diff -Nru python3-sympy-0.7.2/AUTHORS python3-sympy-0.7.3/AUTHORS --- python3-sympy-0.7.2/AUTHORS 2012-10-17 02:30:33.000000000 +0000 +++ python3-sympy-0.7.3/AUTHORS 2013-07-13 17:50:19.000000000 +0000 @@ -77,7 +77,7 @@ Florian Mickler Nicolas Pourcelot Ben Goodrich -Toon Verstraelen +Toon Verstraelen Ronan Lamy James Abbatiello Ryan Krauss @@ -158,7 +158,7 @@ Grzegorz Świrski Matt Habel Nikolay Lazarov -Nichita Utiu +Nichita Utiu Tristan Hume Imran Ahmed Manzoor Steve Anton @@ -173,8 +173,8 @@ Joan Creus Geoffry Song Puneeth Chaganti -Marcin Kostrzewa -Jim Zhang +Marcin Kostrzewa <> +Jim Zhang Natalia Nawara vishal Shruti Mangipudi @@ -190,7 +190,7 @@ Nathan Alison Christian Bühler Carsten Knoll -M R Bharath +Bharath M R Matthias Toews Sergiu Ivanov Jorge E. Cardona @@ -211,6 +211,9 @@ marshall2389 Guru Devanla George Waksman +Angus Griffith <16sn6uv@gmail.com> +Timothy Reluga +Brian Stephanik Ljubiša Moćić <3rdslasher@gmail.com> Piotr Korgul Rom le Clair @@ -218,3 +221,56 @@ Saurabh Jha Tarun Gaba Takafumi Arakaki +Alexander Eberspächer +Sachin Joglekar +Tyler Pirtle +Vasily Povalyaev +Colleen Lee +Niklas Thörne +Huijun Mai +Marek Šuppa +Prasoon Shukla +Sergey B Kirpichev +Stefen Yin +Thomas Hisch +Matthew Hoff +Madeleine Ball +Case Van Horsen +Mary Clark +Rishabh Dixit +Acebulf +Manoj Kumar +Akshit Agarwal +CJ Carey +Patrick Lacasse +Ananya H +Tarang Patel +Christopher Dembia +Benjamin Fishbein +Sean Ge +Ankit Agrawal +Amit Jamadagni +Björn Dahlgren +Christophe Saint-Jean +Demian Wassermann +Khagesh Patel +Stephen Loo +hm +Katja Sophie Hotz +Varun Joshi +Chetna Gupta +Thilina Rathnayake +Shravas K Rao +Max Hutchinson +Matthew Tadd +Alexander Hirzel +Randy Heydon +Ramana Venkata +Oliver Lee +Seshagiri Prabhu +Pradyumna +Erik Welch +Eric Nelson +Roland Puntaier +Chris Conley +Tim Swast diff -Nru python3-sympy-0.7.2/LICENSE python3-sympy-0.7.3/LICENSE --- python3-sympy-0.7.2/LICENSE 2012-10-17 01:53:14.000000000 +0000 +++ python3-sympy-0.7.3/LICENSE 2013-07-13 17:50:18.000000000 +0000 @@ -1,4 +1,4 @@ -Copyright (c) 2006, 2007, 2008, 2009, 2010, 2011, 2012 SymPy Development Team +Copyright (c) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013 SymPy Development Team All rights reserved. diff -Nru python3-sympy-0.7.2/PKG-INFO python3-sympy-0.7.3/PKG-INFO --- python3-sympy-0.7.2/PKG-INFO 2012-10-17 04:46:39.000000000 +0000 +++ python3-sympy-0.7.3/PKG-INFO 2013-07-13 17:53:35.000000000 +0000 @@ -1,6 +1,6 @@ Metadata-Version: 1.1 Name: sympy -Version: 0.7.2 +Version: 0.7.3 Summary: Computer algebra system (CAS) in Python Home-page: http://code.google.com/p/sympy Author: SymPy development team @@ -24,3 +24,4 @@ Classifier: Programming Language :: Python :: 2.7 Classifier: Programming Language :: Python :: 3 Classifier: Programming Language :: Python :: 3.2 +Classifier: Programming Language :: Python :: 3.3 diff -Nru python3-sympy-0.7.2/README.rst python3-sympy-0.7.3/README.rst --- python3-sympy-0.7.2/README.rst 1970-01-01 00:00:00.000000000 +0000 +++ python3-sympy-0.7.3/README.rst 2013-07-13 17:50:18.000000000 +0000 @@ -0,0 +1,222 @@ +SymPy +===== + +A Python library for symbolic mathematics. + +http://sympy.org/ + +See the AUTHORS file for the list of authors. + +And many more people helped on the SymPy mailing list, reported bugs, helped +organize SymPy's participation in the Google Summer of Code, the Google Highly +Open Participation Contest, Google Code-In, wrote and blogged about SymPy... + +License: New BSD License (see the LICENSE file for details) covers all files +in the sympy repository unless stated otherwise. + +Our mailing list is at +https://groups.google.com/forum/?fromgroups#!forum/sympy. We are also on IRC +(`#sympy on Freenode `_, note, this channel is +`logged `_). Feel free to +ask us anything there. We have a very welcoming and helpful community. + +Download +-------- + +Get the latest version of SymPy from +https://pypi.python.org/pypi/sympy/ + +To get the git version do + +:: + + $ git clone git://github.com/sympy/sympy.git + +For other options (tarballs, debs, etc.), see See +http://docs.sympy.org/dev/install.html. + +Documentation and usage +----------------------- + +Everything is at: + +http://docs.sympy.org/ + +You can generate everything at the above site in your local copy of SymPy by:: + + $ cd doc + $ make html + +Then the docs will be in `_build/html`. If you don't want to read that, here +is a short usage: + +From this directory, start python and:: + + >>> from sympy import Symbol, cos + >>> x = Symbol('x') + >>> e = 1/cos(x) + >>> print e.series(x, 0, 10) + 1 + (1/2)*x**2 + (5/24)*x**4 + (61/720)*x**6 + (277/8064)*x**8 + O(x**10) + +SymPy also comes with a console that is a simple wrapper around the +classic python console (or IPython when available) that loads the +sympy namespace and executes some common commands for you. + +To start it, issue:: + + $ bin/isympy + +from this directory if SymPy is not installed or simply:: + + $ isympy + +if SymPy is installed. + +Installation +------------ + +To install SymPy, simply run:: + + $ python setup.py install + +If you install it system-wide, you may need to prefix the previous command with ``sudo``:: + + $ sudo python setup.py install + +See http://docs.sympy.org/dev/install.html for more information. + +Tests +----- + +To execute all tests, run:: + + $./setup.py test + +in the current directory. + +For more fine-grained running of tests or doctest, use ``bin/test`` or +respectively ``bin/doctest``. The master branch is automatically tested by +Travis CI, the results can be seen here: + +.. image:: https://secure.travis-ci.org/sympy/sympy.png?branch=master + :target: http://travis-ci.org/sympy/sympy + +To test pull requests, use `sympy-bot `_. + +Usage in Python 3 +----------------- + +SymPy also supports Python 3. If you want to install the latest version in +Python 3, get the Python 3 tarball from +https://pypi.python.org/pypi/sympy/ + +To build the git version in Python 3, run:: + + $ ./bin/use2to3 + +Note that this command only works if you clone from git. When ran, it will +create a new directory, py3k-sympy, which holds a Python 3 compatible version +of the code. SymPy can then be used normally with Python 3 from that directory +(installation, interactive shell, tests, etc.). If you make any changes to +the Python 2 source, just run that command again to update the Python 3 +source. + +Clean +----- + +To clean everything (thus getting the same tree as in the repository):: + + $ ./setup.py clean + +You can also clean things with git using:: + + $ git clean -Xdf + +which will clear everything ignored by ``.gitignore``, and:: + + $ git clean -df + +to clear all untracked files. You can revert the most recent changes in git +with:: + + $ git reset --hard + +WARNING: The above commands will all clear changes you may have made, and you +will lose them forever. Be sure to check things with ``git status``, ``git +diff``, ``git clean -Xn`` and ``git clean -n`` before doing any of those. + +Bugs +---- + +Our issue tracker is at https://code.google.com/p/sympy/issues/list. Please +report any bugs that you find. Or, even better, fork the repository on GitHub +and create a pull request. We welcome all changes, big or small, and we will +help you make the pull request if you are new to git (just ask on our mailing +list or IRC). + +Brief History +------------- + +SymPy was started by Ondřej Čertík in 2005, he wrote some code during the +summer, then he wrote some more code during the summer 2006. In February 2007, +Fabian Pedregosa joined the project and helped fixed many things, contributed +documentation and made it alive again. 5 students (Mateusz Paprocki, Brian +Jorgensen, Jason Gedge, Robert Schwarz and Chris Wu) improved SymPy incredibly +during the summer 2007 as part of the Google Summer of Code. Pearu Peterson +joined the development during the summer 2007 and he has made SymPy much more +competitive by rewriting the core from scratch, that has made it from 10x to +100x faster. Jurjen N.E. Bos has contributed pretty printing and other patches. +Fredrik Johansson has wrote mpmath and contributed a lot of patches. + +SymPy has participated in every Google Summer of Code since 2007. You can see +https://github.com/sympy/sympy/wiki#google-summer-of-code for full details. +Each year has improved SymPy by bounds. Most of SymPy's development has come +from Google Summer of Code students. + +In 2011, Ondřej Čertík stepped down as lead developer, with Aaron Meurer, who +also started as a Google Summer of Code student, taking his place. Ondřej +Čertík is still active in the community, but is too busy with work and family +to play a lead development role + +Since then, a lot more people have joined the development and some people have +also left. You can see the full list in doc/src/aboutus.rst, or online at: + +http://docs.sympy.org/dev/aboutus.html#sympy-development-team + +The git history goes back to 2007, when development moved from svn to hg. To +see the history before that point, look at http://github.com/sympy/sympy-old. + +You can use git to see the biggest developers. The command:: + + $ git shortlog -ns + +will show each developer, sorted by commits to the project. The command:: + + $ git shortlog -ns --since="1 year" + +will show the top developers from the last year. + +Citation +-------- + +To cite SymPy in publications use:: + + SymPy Development Team (2013). SymPy: Python library for symbolic mathematics + URL http://www.sympy.org. + +A BibTeX entry for LaTeX users is:: + + @Manual{, + title = {SymPy: Python library for symbolic mathematics}, + author = {{SymPy Development Team}}, + year = {2013}, + url = {http://www.sympy.org}, + } + +SymPy is BSD licensed, so you are free to use it whatever you like, be it +academic, commercial, creating forks or derivatives, as long as you copy the +BSD statement if you redistribute it (see the LICENSE file for details). That +said, although not required by the SymPy license, if it is convenient for you, +please cite SymPy when using it in your work and also consider contributing +all your changes back, so that we can incorporate it and all of us will +benefit in the end. diff -Nru python3-sympy-0.7.2/TODO python3-sympy-0.7.3/TODO --- python3-sympy-0.7.2/TODO 2011-10-24 06:15:44.000000000 +0000 +++ python3-sympy-0.7.3/TODO 2013-07-13 17:50:18.000000000 +0000 @@ -1,8 +1,3 @@ Current problems are tracked at: http://code.google.com/p/sympy/issues/list - -for ideas what should be done in the more distant future, see: -http://code.google.com/p/sympy/wiki/Discussion - -but generally ask on the SymPy mailinglist for uptodate future plan. :) diff -Nru python3-sympy-0.7.2/bin/isympy python3-sympy-0.7.3/bin/isympy --- python3-sympy-0.7.2/bin/isympy 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/bin/isympy 2013-07-13 17:53:31.000000000 +0000 @@ -50,17 +50,17 @@ -t TYPES, --types=TYPES Setup the ground types for the polys. By default, gmpy ground types - are used if gmpy is installed, otherwise it falls back to python + are used if gmpy2 or gmpy is installed, otherwise it falls back to python ground types, which are a little bit slower. You can manually choose python ground types even if gmpy is installed (e.g., for testing purposes): $isympy -t python - TYPES must be one of 'gmpy', 'python', or 'sympy' + TYPES must be one of 'gmpy', 'gmpy1' or 'python' - Note that sympy ground types are not supported, and should be used - only for experimental purposes. + Note that the ground type gmpy1 is primarily intended for testing; it + forces the use of gmpy version 1 even if gmpy2 is available. This is the same as setting the environment variable SYMPY_GROUND_TYPES to the given ground type (e.g., @@ -172,19 +172,22 @@ """ -import os, sys, warnings - +import os +import sys +import warnings # hook in-tree SymPy into Python path, if possible isympy_path = os.path.abspath(__file__) -isympy_dir = os.path.dirname(isympy_path) -sympy_top = os.path.split(isympy_dir)[0] -sympy_dir = os.path.join(sympy_top, 'sympy') +isympy_dir = os.path.dirname(isympy_path) +sympy_top = os.path.split(isympy_dir)[0] +sympy_dir = os.path.join(sympy_top, 'sympy') if os.path.isdir(sympy_dir): sys.path.insert(0, sympy_top) +import sympy + def main(): from optparse import OptionParser @@ -193,15 +196,15 @@ # below because optparse line wraps it weird. The argparse module # allows you to disable this, though, but it's only available in # Python 2.7+. - print(__doc__) # the docstring of this module above + print(__doc__) # the docstring of this module above usage = 'usage: isympy [options] -- [ipython options]' parser = OptionParser( usage=usage, - version='0.7.2', + version=sympy.__version__, # XXX: We need a more centralized place to store the version. # It is currently stored in sympy.__version__, but we can't yet # import sympy at this point. - ) + ) parser.add_option( '-c', '--console', @@ -226,10 +229,9 @@ dest='types', action='store', default=None, - choices=['gmpy', 'python', 'sympy'], - help='setup ground types: gmpy | python | sympy; defaults to gmpy if ' - 'gmpy is installed, otherwise python (note that sympy ground types are ' - 'not supported and should be used for experimental purposes only)') + choices=['gmpy', 'gmpy1', 'python'], + help='setup ground types: gmpy | gmpy1 | python; defaults to gmpy if gmpy2 ' + 'or gmpy is installed, otherwise python') parser.add_option( '-o', '--order', @@ -308,14 +310,21 @@ if session is not None: ipython = session == 'ipython' else: - ipython = None + try: + import IPython + ipython = True + except ImportError: + if not options.quiet: + from sympy.interactive.session import no_ipython + print(no_ipython) + ipython = False args = { - 'pretty_print' : True, - 'use_unicode' : None, - 'use_latex' : None, - 'order' : None, - 'argv' : ipy_args, + 'pretty_print': True, + 'use_unicode': None, + 'use_latex': None, + 'order': None, + 'argv': ipy_args, } if options.pretty == 'unicode': @@ -332,7 +341,6 @@ args['auto_symbols'] = options.auto_symbols or options.interactive args['auto_int_to_Integer'] = options.auto_int_to_Integer or options.interactive - from sympy.utilities.exceptions import SymPyDeprecationWarning warnings.simplefilter("always", SymPyDeprecationWarning) diff -Nru python3-sympy-0.7.2/data/TeXmacs/LICENSE python3-sympy-0.7.3/data/TeXmacs/LICENSE --- python3-sympy-0.7.2/data/TeXmacs/LICENSE 2012-10-17 01:53:14.000000000 +0000 +++ python3-sympy-0.7.3/data/TeXmacs/LICENSE 2013-07-13 17:50:18.000000000 +0000 @@ -1,4 +1,4 @@ -Copyright (c) 2006, 2007, 2008, 2009, 2010, 2011, 2012 SymPy developers +Copyright (c) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013 SymPy developers All rights reserved. diff -Nru python3-sympy-0.7.2/debian/changelog python3-sympy-0.7.3/debian/changelog --- python3-sympy-0.7.2/debian/changelog 2013-05-12 22:47:50.000000000 +0000 +++ python3-sympy-0.7.3/debian/changelog 2013-07-20 10:03:59.000000000 +0000 @@ -1,11 +1,17 @@ -python3-sympy (0.7.2-1raring1) raring; urgency=low +python3-sympy (0.7.3-1~ppa1raring1) raring; urgency=low - * Build for raring. + * Rebuild for PPA - -- Thomas Kluyver Sun, 12 May 2013 23:47:33 +0100 + -- Thomas Kluyver Sat, 20 Jul 2013 10:18:13 +0100 -python3-sympy (0.7.2-1) unstable; urgency=low +python3-sympy (0.7.3-1) unstable; urgency=low - * Initial packaging of Python 3 version. + [ Jakub Wilk ] + * Use canonical URIs for Vcs-* fields. + * Remove DM-Upload-Allowed; it's no longer used by the archive + software. - -- Thomas Kluyver Sun, 28 Oct 2012 15:30:18 +0000 + [ Thomas Kluyver ] + * Initial packaging of Python 3 version. Closes: #712924 + + -- Thomas Kluyver Fri, 7 Jun 2013 10:48:09 +0100 diff -Nru python3-sympy-0.7.2/debian/control python3-sympy-0.7.3/debian/control --- python3-sympy-0.7.2/debian/control 2012-11-12 23:56:27.000000000 +0000 +++ python3-sympy-0.7.3/debian/control 2013-06-06 10:09:38.000000000 +0000 @@ -6,11 +6,10 @@ Georges Khaznadar Build-Depends: debhelper (>= 8), python3-all (>=3.2), python3-setuptools X-Python3-Version: >=3.2 -Standards-Version: 3.9.2 +Standards-Version: 3.9.4 Homepage: http://sympy.org/ -Vcs-Svn: svn://svn.debian.org/python-modules/packages/python3-sympy/trunk -Vcs-Browser: http://svn.debian.org/viewsvn/python-modules/packages/python3-sympy/trunk/ -XS-DM-Upload-Allowed: yes +Vcs-Svn: svn://anonscm.debian.org/python-modules/packages/python3-sympy/trunk/ +Vcs-Browser: http://anonscm.debian.org/viewvc/python-modules/packages/python3-sympy/trunk/ Package: python3-sympy Architecture: all diff -Nru python3-sympy-0.7.2/debian/rules python3-sympy-0.7.3/debian/rules --- python3-sympy-0.7.2/debian/rules 2012-11-12 23:58:19.000000000 +0000 +++ python3-sympy-0.7.3/debian/rules 2013-06-06 09:52:10.000000000 +0000 @@ -30,8 +30,14 @@ rm $(PKGDIR)/usr/lib/python3/dist-packages/sympy/mpmath/libmp/exec_py2.py MPMATHDIR = sympy/mpmath -override_dh_clean: - dh_clean +override_dh_auto_clean: + set -ex; for v in $(PYTHON3); do \ + python$$v setup.py clean -a; \ + done; + + # Running setup.py imports sympy, so we need to clear up __pycache__ folders + find . -name "__pycache__" -type d -exec rm -rf '{}' + + for f in torture.py extratest_gamma.py; do \ rm -f $(MPMATHDIR)/tests/$$f; \ done diff -Nru python3-sympy-0.7.2/debian/watch python3-sympy-0.7.3/debian/watch --- python3-sympy-0.7.2/debian/watch 2012-11-12 23:56:27.000000000 +0000 +++ python3-sympy-0.7.3/debian/watch 2013-07-20 09:05:10.000000000 +0000 @@ -1,2 +1,2 @@ version=3 -http://code.google.com/p/sympy/downloads/list?can=1 .*/sympy-(\d[\d.]*)-py3(?:[\d.]*)\.tar\.gz +http://github.com/sympy/sympy/releases .*/sympy-(\d[\d.]*)-py3(?:[\d.]*)\.tar\.gz diff -Nru python3-sympy-0.7.2/doc/Makefile python3-sympy-0.7.3/doc/Makefile --- python3-sympy-0.7.2/doc/Makefile 2012-10-17 01:53:14.000000000 +0000 +++ python3-sympy-0.7.3/doc/Makefile 2013-07-13 17:50:18.000000000 +0000 @@ -6,88 +6,96 @@ # You can set these variables from the command line. SPHINXOPTS = SPHINXVER = 0.5 -#SPHINXBUILDpy = sphinx/Sphinx-$(SPHINXVER)/sphinx-build.py -SPHINXBUILDpy = sphinx-build -SPHINXBUILD = PYTHONPATH=..:$(PYTHONPATH) $(SPHINXBUILDpy) +SPHINXBUILD = PYTHONPATH=..:$(PYTHONPATH) sphinx-build PAPER = SVGFILES = $(wildcard src/modules/physics/mechanics/*.svg) PDFFILES = $(SVGFILES:%.svg=%.pdf) -ALLSPHINXOPTS = -d _build/doctrees -D latex_paper_size=$(PAPER) \ +ALLSPHINXOPTS = -d _build/doctrees $(SPHINXOPTS) src +ALLSPHINXOPTSapi = -d _build/doctrees-api $(SPHINXOPTS) api +ALLSPHINXOPTSlatex = -d _build/doctrees-latex -D latex_paper_size=$(PAPER) \ $(SPHINXOPTS) src -ALLSPHINXOPTSapi = -d _build/doctreesapi -D latex_paper_size=$(PAPER) \ - $(SPHINXOPTS) api +MOFILES = $(foreach l,$(LANGUAGES),$(addprefix _build/i18n/,$(addsuffix /LC_MESSAGES/tutorial.mo,${l}))) +POFILES = $(foreach l,$(LANGUAGES),$(addprefix src/tutorial/tutorial.,$(addsuffix .po,${l}))) -LANGUAGES = bg cs de fr pl ru sr - -.PHONY: help clean html web htmlhelp latex changes linkcheck cheatsheet +.PHONY: changes cheatsheet clean gettext help html html-errors \ + htmlapi htmlhelp htmli18n info latex linkcheck texinfo \ + update-po web .SUFFIXES: .pdf .svg help: @echo "Please use \`make ' where is one of" + @echo " changes to make an overview over all changed/added/deprecated items" + @echo " cheatsheet to make the Cheatsheet" + @echo " clean to remove generated files" + @echo " gettext to make pot files for translation" @echo " html to make standalone HTML files" - @echo " web to make files usable by Sphinx.web" + @echo " html-errors to make the standalone HTML files, stopping on any errors or warnings" + @echo " htmlapi to make HTML API docs" @echo " htmlhelp to make HTML files and a HTML help project" - @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" - @echo " texinfo to make Texinfo files" + @echo " htmli18n to make the i18n versions" @echo " info to make Texinfo files and run them through makeinfo" - @echo " changes to make an overview over all changed/added/deprecated items" + @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" @echo " linkcheck to check all external links for integrity" - @echo " cheatsheet to make the Cheatsheet" - @echo " htmli18n to make the i18n versions" - @echo " html-errors to make the standalone HTML files, stopping on any errors or warnings" + @echo " livehtml to use livereload to view the built html" + @echo " texinfo to make Texinfo files" + @echo " update-po to update po files for translation" + @echo " web to make files usable by Sphinx.web" clean: -rm -rf _build -rm -rf sphinx + -rm -f $(PDFFILES) -$(SPHINXBUILDpy): - rm -rf sphinx -# mkdir sphinx -# cd sphinx; wget http://pypi.python.org/packages/source/S/Sphinx/Sphinx-$(SPHINXVER).tar.gz; -# cd sphinx; tar xzf Sphinx-$(SPHINXVER).tar.gz - -html: $(SPHINXBUILDpy) +html: htmli18n mkdir -p src/.static mkdir -p _build/html mkdir -p _build/doctrees mkdir -p src/modules $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) _build/html cp -r src/pics _build/html/ - cp -r src/figures _build/html/ @echo @echo "Build finished. The HTML pages are in _build/html." html-errors: SPHINXOPTS += -W html-errors: html -htmlapi: $(SPHINXBUILDpy) +htmlapi: mkdir -p api/.static mkdir -p api/modules mkdir -p _build/api _build/doctreesapi rm -f api/modules/sympy*.rst - ./generate_reference.py $(SPHINXBUILD) -b html $(ALLSPHINXOPTSapi) _build/api @echo @echo "Build finished. The API docs pages are in _build/api." gettext: - mkdir -p _build/ - $(SPHINXBUILD) -b gettext src _build/gettext src/tutorial.rst - cp _build/gettext/tutorial.pot src/ + $(SPHINXBUILD) -b gettext -t gettext -D master_doc=tutorial/tutorial \ + -D source_suffix=.en.rst -d _build/doctrees-en src src/tutorial + sed -i "/^\# [0-9a-zA-Z]*$$/d" src/tutorial/tutorial.pot + +update-po: $(POFILES) -htmli18n: +htmli18n: $(MOFILES) mkdir -p _build/i18n/ - mkdir -p _build/html/ - for l in $(LANGUAGES); do \ - mkdir -p src/i18n/$$l/LC_MESSAGES/ ; \ - msgfmt src/tutorial.$$l.po -o src/i18n/$$l/LC_MESSAGES/tutorial.mo ; \ - $(SPHINXBUILD) -b html -D language=$$l $(ALLSPHINXOPTS) _build/i18n/$$l src/tutorial.rst ; \ - cp _build/i18n/$$l/tutorial.html _build/html/tutorial.$$l.html ; \ - done + mkdir -p _build/html/tutorial + $(foreach l,$(LANGUAGES), \ + $(SPHINXBUILD) $(SPHINXOPTS) -b html -D language=$l -D master_doc=tutorial/tutorial \ + -D source_suffix=.en.rst -d _build/doctrees-$l src _build/i18n/$l && \ + cp _build/i18n/$l/tutorial/tutorial.html _build/html/tutorial/tutorial.$l.html && \ + ) true + +$(POFILES): src/tutorial/tutorial.pot + msgmerge -U $@ $< + touch $@ + +$(MOFILES): _build/i18n/%/LC_MESSAGES/tutorial.mo: src/tutorial/tutorial.%.po + mkdir -p $(dir $@) + msgfmt $< -o $@ + rm -rf _build/doctrees-$* web: mkdir -p _build/web _build/doctrees @@ -104,9 +112,9 @@ @echo "Build finished; now you can run HTML Help Workshop with the" \ ".hhp project file in _build/htmlhelp." -latex: $(SPHINXBUILDpy) $(PDFFILES) +latex: $(PDFFILES) mkdir -p _build/latex _build/doctrees - $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) _build/latex + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTSlatex) _build/latex sed -i "s/pdflatex/xelatex/g" _build/latex/Makefile @echo @echo "Build finished; the LaTeX files are in _build/latex." @@ -128,7 +136,12 @@ @echo "Link check complete; look for any errors in the above output " \ "or in _build/linkcheck/output.txt." -cheatsheet: +livehtml: + livereload -b _build/html + +cheatsheet: _build/cheatsheet/cheatsheet.pdf + +_build/cheatsheet/cheatsheet.pdf: cheatsheet/cheatsheet.tex mkdir -p _build/cheatsheet pdflatex -output-directory=_build/cheatsheet cheatsheet/cheatsheet.tex pdflatex -output-directory=_build/cheatsheet cheatsheet/cheatsheet.tex diff -Nru python3-sympy-0.7.2/doc/README.rst python3-sympy-0.7.3/doc/README.rst --- python3-sympy-0.7.2/doc/README.rst 2012-10-17 01:53:14.000000000 +0000 +++ python3-sympy-0.7.3/doc/README.rst 2013-07-13 17:50:18.000000000 +0000 @@ -14,40 +14,47 @@ epiphany _build/html/index.html -How to Build Translated Tutorial -================================ -To build the translated tutorial, build the documentation -using ``make html`` and then just run:: +About the Translated Tutorial +============================= + +Translated versions of the tutorial are generated when building the html +documentation using ``make html``. If you quickly want to check only the +translations and not the whole documentation, just run:: make htmli18n This will create ``tutorial.cs.html``, ``tutorial.ru.html`` (and so on for all languages) in the ``_build/html/`` directory. The input is the English tutorial -``tutorial.rst`` and the .po files ``tutorial.cs.po``, ``tutorial.ru.po``, etc. +``tutorial.en.rst`` and the .po files ``tutorial.cs.po``, ``tutorial.ru.po``, etc. You can freely change the English tutorial -- sentences that are not translated -will remain in English in the translated verions. +will remain in English in the translated versions. -Note: ``make htmli18n`` is currently quite slow, so it is not run by default. -However, this can be trivially implemented by modifying the ``Makefile``. How to Update Translations ========================== -In order to update translations, you first need to generate the -``tutorial.pot`` template by:: +In order to update translations, you first need to make sure that the +``tutorial.pot`` template is up-to-date by running:: make gettext -Then you need to translate it if you are creating a new language -translation. If you are just updating a translation, for example the +If you are creating a translation for a new language, copy the generated +``tutorial.pot`` to a new file ``tutorial.??.po`` where ``??`` is the +two-character language code for your language. Also add the language +code to the LANGUAGES macro in the Makefile. When the translation work +for a new language has reached 90% or more, a link to the new translation +should be added at the bottom of tutorial.en.rst. + +If you are just updating a translation, for example the ``tutorial.cs.po``, just do:: - msgmerge -U tutorial.cs.po tutorial.pot + make update-po This will create a new ``tutorial.cs.po`` by using the template ``tutorial.pot`` and reusing the old translations from old ``tutorial.cs.po`` (if they still work) and leaving the rest untranslated. -Then just build it using ``make htmli18n`` (see the -previous section). +Update your ``tutorial.??.po`` file with your translations, then just build it +using ``make html`` (see the previous section). When you are done, use +``git add`` to add your changes to the repository and submit a pull request. diff -Nru python3-sympy-0.7.2/doc/api/conf.py python3-sympy-0.7.3/doc/api/conf.py --- python3-sympy-0.7.2/doc/api/conf.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/doc/api/conf.py 2013-07-13 17:53:31.000000000 +0000 @@ -12,6 +12,7 @@ # serve to show the default value. import sys +import sympy # If your extensions are in another directory, add it here. #sys.path.append('some/directory') @@ -34,15 +35,15 @@ # General substitutions. project = 'SymPy' -copyright = '2012, SymPy Development Team' +copyright = '2013, SymPy Development Team' # The default replacements for |version| and |release|, also used in various # other places throughout the built documents. # # The short X.Y version. -version = '0.7.2' +version = sympy.__version__ # The full version, including alpha/beta/rc tags. -release = '0.7.2' +release = version # There are two options for replacing |today|: either, you set today to some # non-false value, then it is used: @@ -121,7 +122,7 @@ # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, author, document class [howto/manual]). latex_documents = [('index', 'sympy.tex', 'SymPy Documentation', - 'SymPy Development Team', 'manual')] + 'SymPy Development Team', 'manual')] # Additional stuff for the LaTeX preamble. #latex_preamble = '' diff -Nru python3-sympy-0.7.2/doc/ext/docscrape.py python3-sympy-0.7.3/doc/ext/docscrape.py --- python3-sympy-0.7.2/doc/ext/docscrape.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/doc/ext/docscrape.py 2013-07-13 17:53:31.000000000 +0000 @@ -9,6 +9,7 @@ from io import StringIO import collections + class Reader(object): """ A line-based string reader. @@ -21,10 +22,10 @@ String with lines separated by '\n'. """ - if isinstance(data,list): + if isinstance(data, list): self._str = data else: - self._str = data.split('\n') # store string as list of lines + self._str = data.split('\n') # store string as list of lines self.reset() @@ -32,7 +33,7 @@ return self._str[n] def reset(self): - self._l = 0 # current line nr + self._l = 0 # current line nr def read(self): if not self.eof(): @@ -59,11 +60,12 @@ return self[start:self._l] self._l += 1 if self.eof(): - return self[start:self._l+1] + return self[start:self._l + 1] return [] def read_to_next_empty_line(self): self.seek_next_non_empty_line() + def is_empty(line): return not line.strip() return self.read_to_condition(is_empty) @@ -73,7 +75,7 @@ return (line.strip() and (len(line.lstrip()) == len(line))) return self.read_to_condition(is_unindented) - def peek(self,n=0): + def peek(self, n=0): if self._l + n < len(self._str): return self[self._l + n] else: @@ -105,15 +107,15 @@ 'References': '', 'Examples': '', 'index': {} - } + } self._other_keys = [] self._parse() - def __getitem__(self,key): + def __getitem__(self, key): return self._parsed_data[key] - def __setitem__(self,key,val): + def __setitem__(self, key, val): if key not in self._parsed_data: self._other_keys.append(key) @@ -130,25 +132,27 @@ if l1.startswith('.. index::'): return True - l2 = self._doc.peek(1).strip() # ---------- or ========== + l2 = self._doc.peek(1).strip() # ---------- or ========== return l2.startswith('-'*len(l1)) or l2.startswith('='*len(l1)) - def _strip(self,doc): + def _strip(self, doc): i = 0 j = 0 - for i,line in enumerate(doc): - if line.strip(): break + for i, line in enumerate(doc): + if line.strip(): + break - for j,line in enumerate(doc[::-1]): - if line.strip(): break + for j, line in enumerate(doc[::-1]): + if line.strip(): + break - return doc[i:len(doc)-j] + return doc[i:len(doc) - j] def _read_to_next_section(self): section = self._doc.read_to_next_empty_line() while not self._is_at_section() and not self._doc.eof(): - if not self._doc.peek(-1).strip(): # previous line was empty + if not self._doc.peek(-1).strip(): # previous line was empty section += [''] section += self._doc.read_to_next_empty_line() @@ -160,14 +164,14 @@ data = self._read_to_next_section() name = data[0].strip() - if name.startswith('..'): # index section + if name.startswith('..'): # index section yield name, data[1:] elif len(data) < 2: yield StopIteration else: yield name, self._strip(data[2:]) - def _parse_param_list(self,content): + def _parse_param_list(self, content): r = Reader(content) params = [] while not r.eof(): @@ -180,13 +184,13 @@ desc = r.read_to_next_unindented_line() desc = dedent_lines(desc) - params.append((arg_name,arg_type,desc)) + params.append((arg_name, arg_type, desc)) return params - _name_rgx = re.compile(r"^\s*(:(?P\w+):`(?P[a-zA-Z0-9_.-]+)`|" r" (?P[a-zA-Z0-9_.-]+))\s*", re.X) + def _parse_see_also(self, content): """ func_name : Descriptive text @@ -219,7 +223,8 @@ rest = [] for line in content: - if not line.strip(): continue + if not line.strip(): + continue m = self._name_rgx.match(line) if m and line[m.end():].strip().startswith(':'): @@ -282,7 +287,7 @@ self._doc.reset() self._parse_summary() - for (section,content) in self._read_sections(): + for (section, content) in self._read_sections(): if not section.startswith('..'): section = ' '.join([s.capitalize() for s in section.split(' ')]) if section in ('Parameters', 'Returns', 'Raises', 'Warns', @@ -308,7 +313,7 @@ def _str_signature(self): if self['Signature']: - return [self['Signature'].replace('*','\*')] + [''] + return [self['Signature'].replace('*', '\*')] + [''] else: return [''] @@ -328,7 +333,7 @@ out = [] if self[name]: out += self._str_header(name) - for param,param_type,desc in self[name]: + for param, param_type, desc in self[name]: out += ['%s : %s' % (param, param_type)] out += self._str_indent(desc) out += [''] @@ -343,7 +348,8 @@ return out def _str_see_also(self, func_role): - if not self['See Also']: return [] + if not self['See Also']: + return [] out = [] out += self._str_header("See Also") last_had_desc = True @@ -370,7 +376,7 @@ def _str_index(self): idx = self['index'] out = [] - out += ['.. index:: %s' % idx.get('default','')] + out += ['.. index:: %s' % idx.get('default', '')] for section, references in idx.items(): if section == 'default': continue @@ -387,7 +393,7 @@ out += self._str_param_list(param_list) out += self._str_section('Warnings') out += self._str_see_also(func_role) - for s in ('Notes','References','Examples'): + for s in ('Notes', 'References', 'Examples'): out += self._str_section(s) for param_list in ('Attributes', 'Methods'): out += self._str_param_list(param_list) @@ -395,17 +401,19 @@ return '\n'.join(out) -def indent(str,indent=4): +def indent(str, indent=4): indent_str = ' '*indent if str is None: return indent_str lines = str.split('\n') return '\n'.join(indent_str + l for l in lines) + def dedent_lines(lines): """Deindent a list of lines maximally""" return textwrap.dedent("\n".join(lines)).split("\n") + def header(text, style='-'): return text + '\n' + style*len(text) + '\n' @@ -413,7 +421,7 @@ class FunctionDoc(NumpyDocString): def __init__(self, func, role='func', doc=None, config={}): self._f = func - self._role = role # e.g. "func" or "meth" + self._role = role # e.g. "func" or "meth" if doc is None: if func is None: @@ -427,7 +435,7 @@ # try to read signature argspec = inspect.getargspec(func) argspec = inspect.formatargspec(*argspec) - argspec = argspec.replace('*','\*') + argspec = argspec.replace('*', '\*') signature = '%s%s' % (func_name, argspec) except TypeError as e: signature = '%s()' % func_name @@ -453,7 +461,7 @@ if self._role: if self._role not in roles: print("Warning: invalid role %s" % self._role) - out += '.. %s:: %s\n \n\n' % (roles.get(self._role,''), + out += '.. %s:: %s\n \n\n' % (roles.get(self._role, ''), func_name) out += super(FunctionDoc, self).__str__(func_role=self._role) @@ -493,7 +501,7 @@ def methods(self): if self._cls is None: return [] - return [name for name,func in inspect_getmembers(self._cls) + return [name for name, func in inspect_getmembers(self._cls) if ((not name.startswith('_') or name in self.extra_public_methods) and isinstance(func, collections.Callable))] @@ -502,11 +510,10 @@ def properties(self): if self._cls is None: return [] - return [name for name,func in inspect_getmembers(self._cls) + return [name for name, func in inspect_getmembers(self._cls) if not name.startswith('_') and func is None] - # This function was taken verbatim from Python 2.7 inspect.getmembers() from # the standard library. The difference from Python < 2.7 is that there is the # try/except AttributeError clause added, which catches exceptions like this diff -Nru python3-sympy-0.7.2/doc/ext/docscrape_sphinx.py python3-sympy-0.7.3/doc/ext/docscrape_sphinx.py --- python3-sympy-0.7.2/doc/ext/docscrape_sphinx.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/doc/ext/docscrape_sphinx.py 2013-07-13 17:53:31.000000000 +0000 @@ -1,8 +1,12 @@ -import re, inspect, textwrap, pydoc +import re +import inspect +import textwrap +import pydoc import sphinx from docscrape import NumpyDocString, FunctionDoc, ClassDoc import collections + class SphinxDocString(NumpyDocString): def __init__(self, docstring, config={}): self.use_plots = config.get('use_plots', False) @@ -39,11 +43,11 @@ if self[name]: out += self._str_field_list(name) out += [''] - for param,param_type,desc in self[name]: + for param, param_type, desc in self[name]: out += self._str_indent(['**%s** : %s' % (param.strip(), param_type)]) out += [''] - out += self._str_indent(desc,8) + out += self._str_indent(desc, 8) out += [''] return out @@ -131,7 +135,7 @@ if len(idx) == 0: return out - out += ['.. index:: %s' % idx.get('default','')] + out += ['.. index:: %s' % idx.get('default', '')] for section, references in idx.items(): if section == 'default': continue @@ -152,9 +156,9 @@ # Latex collects all references to a separate bibliography, # so we need to insert links to it if sphinx.__version__ >= "0.6": - out += ['.. only:: latex',''] + out += ['.. only:: latex', ''] else: - out += ['.. latexonly::',''] + out += ['.. latexonly::', ''] items = [] for line in self['References']: m = re.match(r'.. \[([a-z0-9._-]+)\]', line, re.I) @@ -194,24 +198,28 @@ for s in self._other_keys: out += self._str_section(s) out += self._str_member_list('Attributes') - out = self._str_indent(out,indent) + out = self._str_indent(out, indent) return '\n'.join(out) + class SphinxFunctionDoc(SphinxDocString, FunctionDoc): def __init__(self, obj, doc=None, config={}): self.use_plots = config.get('use_plots', False) FunctionDoc.__init__(self, obj, doc=doc, config=config) + class SphinxClassDoc(SphinxDocString, ClassDoc): def __init__(self, obj, doc=None, func_doc=None, config={}): self.use_plots = config.get('use_plots', False) ClassDoc.__init__(self, obj, doc=doc, func_doc=None, config=config) + class SphinxObjDoc(SphinxDocString): def __init__(self, obj, doc=None, config={}): self._f = obj SphinxDocString.__init__(self, doc, config=config) + def get_doc_object(obj, what=None, doc=None, config={}): if inspect.isclass(obj): what = 'class' diff -Nru python3-sympy-0.7.2/doc/ext/numpydoc.py python3-sympy-0.7.3/doc/ext/numpydoc.py --- python3-sympy-0.7.2/doc/ext/numpydoc.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/doc/ext/numpydoc.py 2013-07-13 17:53:31.000000000 +0000 @@ -23,11 +23,14 @@ if sphinx.__version__ < '1.0.1': raise RuntimeError("Sphinx 1.0.1 or newer is required") -import os, re, pydoc +import os +import re +import pydoc from docscrape_sphinx import get_doc_object, SphinxDocString from sphinx.util.compat import Directive import inspect + def mangle_docstrings(app, what, name, obj, options, lines, reference_offset=[0]): @@ -37,14 +40,14 @@ if what == 'module': # Strip top title title_re = re.compile(r'^\s*[#*=]{4,}\n[a-z0-9 -]+\n[#*=]{4,}\s*', - re.I|re.S) + re.I | re.S) lines[:] = title_re.sub('', "\n".join(lines)).split("\n") else: doc = get_doc_object(obj, what, "\n".join(lines), config=cfg) lines[:] = str(doc).split("\n") if app.config.numpydoc_edit_link and hasattr(obj, '__name__') and \ - obj.__name__: + obj.__name__: if hasattr(obj, '__module__'): v = dict(full_name="%s.%s" % (obj.__module__, obj.__name__)) else: @@ -77,21 +80,25 @@ reference_offset[0] += len(references) + def mangle_signature(app, what, name, obj, options, sig, retann): # Do not try to inspect classes that don't define `__init__` if (inspect.isclass(obj) and (not hasattr(obj, '__init__') or - 'initializes x; see ' in pydoc.getdoc(obj.__init__))): + 'initializes x; see ' in pydoc.getdoc(obj.__init__))): return '', '' - if not (isinstance(obj, collections.Callable) or hasattr(obj, '__argspec_is_invalid_')): return - if not hasattr(obj, '__doc__'): return + if not (isinstance(obj, collections.Callable) or hasattr(obj, '__argspec_is_invalid_')): + return + if not hasattr(obj, '__doc__'): + return doc = SphinxDocString(pydoc.getdoc(obj)) if doc['Signature']: sig = re.sub("^[^(]*", "", doc['Signature']) return sig, '' + def setup(app, get_doc_object_=get_doc_object): global get_doc_object get_doc_object = get_doc_object_ @@ -114,6 +121,7 @@ from sphinx.domains.c import CDomain from sphinx.domains.python import PythonDomain + class ManglingDomainBase(object): directive_mangling_map = {} @@ -126,6 +134,7 @@ self.directives[name] = wrap_mangling_directive( self.directives[name], objtype) + class NumpyPythonDomain(ManglingDomainBase, PythonDomain): name = 'np' directive_mangling_map = { @@ -138,6 +147,7 @@ 'attribute': 'attribute', } + class NumpyCDomain(ManglingDomainBase, CDomain): name = 'np-c' directive_mangling_map = { @@ -148,6 +158,7 @@ 'var': 'object', } + def wrap_mangling_directive(base_directive, objtype): class directive(base_directive): def run(self): diff -Nru python3-sympy-0.7.2/doc/ext/sympylive.py python3-sympy-0.7.3/doc/ext/sympylive.py --- python3-sympy-0.7.2/doc/ext/sympylive.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/doc/ext/sympylive.py 2013-07-13 17:53:31.000000000 +0000 @@ -17,8 +17,6 @@ app.add_javascript(app.config.sympylive_url + '/static/utilities.js') app.add_javascript(app.config.sympylive_url + '/static/external/classy.js') - app.add_javascript( - 'http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js') app.add_stylesheet(app.config.sympylive_url + '/static/live-core.css') app.add_stylesheet(app.config.sympylive_url + diff -Nru python3-sympy-0.7.2/doc/man/isympy.xml python3-sympy-0.7.3/doc/man/isympy.xml --- python3-sympy-0.7.2/doc/man/isympy.xml 2012-10-17 01:53:14.000000000 +0000 +++ python3-sympy-0.7.3/doc/man/isympy.xml 2013-07-13 17:50:18.000000000 +0000 @@ -66,7 +66,7 @@ - 2012 + 2013 SymPy Development Team @@ -193,7 +193,7 @@ 'ipython' or 'python' - + @@ -205,18 +205,21 @@ 'ascii' or 'no'. - + Setup the ground types for the polys. By default, gmpy ground types - are used if gmpy is installed, otherwise it falls back to python + are used if gmpy2 or gmpy is installed, otherwise it falls back to python ground types, which are a little bit slower. You can manually choose python ground types even if gmpy is installed (e.g., for testing purposes). Note that sympy ground types are not supported, and should be used only for experimental purposes. + Note that the gmpy1 ground type is primarily intended for testing; it the + use of gmpy even if gmpy2 is available. + This is the same as setting the environment variable SYMPY_GROUND_TYPES to the given ground type (e.g., SYMPY_GROUND_TYPES='gmpy') @@ -227,10 +230,10 @@ Example: isympy -t python TYPE must be one of 'gmpy', - 'python' or 'sympy'. + 'gmpy1' or 'python'. - + @@ -249,7 +252,7 @@ 'rev-grlex', 'grevlex', 'rev-grevlex', 'old', or 'none'. - + @@ -258,7 +261,7 @@ - + @@ -268,7 +271,7 @@ - + @@ -284,7 +287,7 @@ - + @@ -319,7 +322,7 @@ - + @@ -330,7 +333,7 @@ - + -- PYTHONOPTIONS @@ -349,7 +352,7 @@ - + @@ -358,7 +361,7 @@ - + @@ -402,4 +405,3 @@ - diff -Nru python3-sympy-0.7.2/doc/src/_static/default.css_t python3-sympy-0.7.3/doc/src/_static/default.css_t --- python3-sympy-0.7.2/doc/src/_static/default.css_t 1970-01-01 00:00:00.000000000 +0000 +++ python3-sympy-0.7.3/doc/src/_static/default.css_t 2013-07-13 17:50:18.000000000 +0000 @@ -0,0 +1,310 @@ +/* + * default.css_t + * ~~~~~~~~~~~~~ + * + * Sphinx stylesheet -- default theme. + * + * :copyright: Copyright 2007-2013 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ + +@import url("basic.css"); + +/* -- page layout ----------------------------------------------------------- */ + +body { + font-family: {{ theme_bodyfont }}; + font-size: 100%; + background-color: {{ theme_footerbgcolor }}; + color: #000; + margin: 0; + padding: 0; +} + +div.document { + background-color: {{ theme_sidebarbgcolor }}; +} + +div.documentwrapper { + float: left; + width: 100%; +} + +div.bodywrapper { + margin: 0 200px 0 {{ theme_sidebarwidth|toint }}px; +} + +div.body { + background-color: {{ theme_bgcolor }}; + color: {{ theme_textcolor }}; + padding: 0 20px 30px 20px; +} + +{%- if theme_rightsidebar|tobool %} +div.bodywrapper { + margin: 0 {{ theme_sidebarwidth|toint }}px 0 0; +} +{%- endif %} + +div.footer { + color: {{ theme_footertextcolor }}; + width: 100%; + padding: 9px 0 9px 0; + text-align: center; + font-size: 75%; +} + +div.footer a { + color: {{ theme_footertextcolor }}; + text-decoration: underline; +} + +div.related { + background-color: {{ theme_relbarbgcolor }}; + line-height: 30px; + color: {{ theme_relbartextcolor }}; +} + +div.related a { + color: {{ theme_relbarlinkcolor }}; +} + +div.sphinxsidebar { + {%- if theme_stickysidebar|tobool %} + top: 30px; + bottom: 0; + margin: 0; + position: fixed; + overflow: auto; + height: auto; + {%- endif %} + {%- if theme_rightsidebar|tobool %} + float: right; + {%- if theme_stickysidebar|tobool %} + right: 0; + {%- endif %} + {%- endif %} +} + +{%- if theme_stickysidebar|tobool %} +/* this is nice, but it it leads to hidden headings when jumping + to an anchor */ +/* +div.related { + position: fixed; +} + +div.documentwrapper { + margin-top: 30px; +} +*/ +{%- endif %} + +div.sphinxsidebar h3 { + font-family: {{ theme_headfont }}; + color: {{ theme_sidebartextcolor }}; + font-size: 1.4em; + font-weight: normal; + margin: 0; + padding: 0; +} + +div.sphinxsidebar h3 a { + color: {{ theme_sidebartextcolor }}; +} + +div.sphinxsidebar h4 { + font-family: {{ theme_headfont }}; + color: {{ theme_sidebartextcolor }}; + font-size: 1.3em; + font-weight: normal; + margin: 5px 0 0 0; + padding: 0; +} + +div.sphinxsidebar p { + color: {{ theme_sidebartextcolor }}; +} + +div.sphinxsidebar p.topless { + margin: 5px 10px 10px 10px; +} + +div.sphinxsidebar ul { + margin: 10px; + padding: 0; + color: {{ theme_sidebartextcolor }}; +} + +div.sphinxsidebar a { + color: {{ theme_sidebarlinkcolor }}; +} + +div.sphinxsidebar input { + border: 1px solid {{ theme_sidebarlinkcolor }}; + font-family: sans-serif; + font-size: 1em; +} + +{% if theme_collapsiblesidebar|tobool %} +/* for collapsible sidebar */ +div#sidebarbutton { + background-color: {{ theme_sidebarbtncolor }}; +} +{% endif %} + +/* -- hyperlink styles ------------------------------------------------------ */ + +a { + color: {{ theme_linkcolor }}; + text-decoration: none; +} + +a:visited { + color: {{ theme_visitedlinkcolor }}; + text-decoration: none; +} + +a:hover { + text-decoration: underline; +} + +{% if theme_externalrefs|tobool %} +a.external { + text-decoration: none; + border-bottom: 1px dashed {{ theme_linkcolor }}; +} + +a.external:hover { + text-decoration: none; + border-bottom: none; +} + +a.external:visited { + text-decoration: none; + border-bottom: 1px dashed {{ theme_visitedlinkcolor }}; +} +{% endif %} + +/* -- body styles ----------------------------------------------------------- */ + +div.body h1, +div.body h2, +div.body h3, +div.body h4, +div.body h5, +div.body h6 { + font-family: {{ theme_headfont }}; + background-color: {{ theme_headbgcolor }}; + font-weight: normal; + color: {{ theme_headtextcolor }}; + border-bottom: 1px solid #ccc; + margin: 20px -20px 10px -20px; + padding: 3px 0 3px 10px; +} + +div.body h1 { margin-top: 0; font-size: 200%; } +div.body h2 { font-size: 160%; } +div.body h3 { font-size: 140%; } +div.body h4 { font-size: 120%; } +div.body h5 { font-size: 110%; } +div.body h6 { font-size: 100%; } + +a.headerlink { + color: {{ theme_headlinkcolor }}; + font-size: 0.8em; + padding: 0 4px 0 4px; + text-decoration: none; +} + +a.headerlink:hover { + background-color: {{ theme_headlinkcolor }}; + color: white; +} + +div.body p, div.body dd, div.body li { + text-align: left; + line-height: 130%; +} + +div.admonition p.admonition-title + p { + display: inline; +} + +div.admonition p { + margin-bottom: 5px; +} + +div.admonition pre { + margin-bottom: 5px; +} + +div.admonition ul, div.admonition ol { + margin-bottom: 5px; +} + +div.note { + background-color: #eee; + border: 1px solid #ccc; +} + +div.seealso { + background-color: #ffc; + border: 1px solid #ff6; +} + +div.topic { + background-color: #eee; +} + +div.warning { + background-color: #ffe4e4; + border: 1px solid #f66; +} + +p.admonition-title { + display: inline; +} + +p.admonition-title:after { + content: ":"; +} + +pre { + padding: 5px; + background-color: {{ theme_codebgcolor }}; + color: {{ theme_codetextcolor }}; + line-height: 120%; + border: 1px solid #ac9; + border-left: none; + border-right: none; +} + +tt { + background-color: #ecf0f3; + padding: 0 1px 0 1px; + font-size: 0.95em; +} + +th { + background-color: #ede; +} + +.warning tt { + background: #efc2c2; +} + +.note tt { + background: #d6d6d6; +} + +.viewcode-back { + font-family: {{ theme_bodyfont }}; +} + +div.viewcode-block:target { + background-color: #f4debf; + border-top: 1px solid #ac9; + border-bottom: 1px solid #ac9; +} Binary files /tmp/E2vCQhuc_3/python3-sympy-0.7.2/doc/src/_static/sympylogo_big.png and /tmp/E99RNQO9Lx/python3-sympy-0.7.3/doc/src/_static/sympylogo_big.png differ diff -Nru python3-sympy-0.7.2/doc/src/aboutus.rst python3-sympy-0.7.3/doc/src/aboutus.rst --- python3-sympy-0.7.2/doc/src/aboutus.rst 2012-10-17 02:30:33.000000000 +0000 +++ python3-sympy-0.7.3/doc/src/aboutus.rst 2013-07-13 17:50:19.000000000 +0000 @@ -216,6 +216,9 @@ #. marshall2389: Spelling correction #. Guru Devanla: Implemented quantum density operator #. George Waksman: Implemented JavaScript code printer and MathML printer +#. Angus Griffith: Fix bug in rsolve +#. Timothy Reluga: Rewrite trigonometric functions as rationals +#. Brian Stephanik: Test for a bug in fcode #. Ljubiša Moćić: Serbian translation of the tutorial #. Piotr Korgul: Polish translation of the tutorial #. Rom le Clair: French translation of the tutorial @@ -223,6 +226,59 @@ #. Saurabh Jha: Work on Kauers algorithm #. Tarun Gaba: Implemented some trigonometric integrals #. Takafumi Arakaki: Add info target to the doc Makefile +#. Alexander Eberspächer: correct typo in aboutus.rst +#. Sachin Joglekar: Simplification of logic expressions to SOP and POS forms +#. Tyler Pirtle: Fix improperly formatted error message +#. Vasily Povalyaev: Fix latex(Min) +#. Colleen Lee: replace uses of fnan with S.NaN +#. Niklas Thörne: Fix links in the docs +#. Huijun Mai: Chinese translation of the tutorial +#. Marek Šuppa: Improvements to symbols, tests +#. Prasoon Shukla: Bug fixes +#. Sergey B Kirpichev: Bug fixes +#. Stefen Yin: Fixes to the mechanics module +#. Thomas Hisch: Improvements to the printing module +#. Matthew Hoff: Addition to quantum module +#. Madeleine Ball: Bug fix +#. Case Van Horsen: Fixes to gmpy support +#. Mary Clark: Improvements to the group theory module +#. Rishabh Dixit: Bug fixes +#. Acebulf: Typos +#. Manoj Kumar: Bug fix +#. Akshit Agarwal: improvements to range handling in symbols +#. CJ Carey: Fix for limits of factorials +#. Patrick Lacasse: Fix for Piecewise.subs +#. Ananya H: Bug fix +#. Tarang Patel: added test for issue 1640 +#. Christopher Dembia: improvements to mecahanics documentation +#. Benjamin Fishbein: added rank method to Matrix +#. Sean Ge: made KroneckerDelta arguments canonically ordered +#. Ankit Agrawal: Statistical moments +#. Amit Jamadagni: qapply Rotation to spin states +#. Björn Dahlgren: Documentation fix +#. Christophe Saint-Jean: fixed and added metrics to galgebra +#. Demian Wassermann: fix to ccode printer for Piecewise +#. Khagesh Patel: Addition to matrix expressions +#. Stephen Loo: Update minimum gmpy2 version +#. hm: Fixes to printing +#. Katja Sophie Hotz: use expansion in minpoly +#. Varun Joshi: Addition to functions +#. Chetna Gupta: Improvements to the Risch integration algorithm +#. Thilina Rathnayake: Fix to the matrices +#. Shravas K Rao: Implement prev_lexicographic and next_lexicographic +#. Max Hutchinson: Fix to HadamardProduct +#. Matthew Tadd: fix definition in units module +#. Alexander Hirzel: Updates to ODE docs +#. Randy Heydon: improve collinear point detection +#. Ramana Venkata: improvements to special functions +#. Oliver Lee: improvements to mechanics +#. Seshagiri Prabhu: hardcoded 3x3 determinant +#. Pradyumna: Fix to printing +#. Erik Welch: Fix a warning +#. Eric Nelson: Fixes to printing +#. Roland Puntaier: Improve App Engine support +#. Chris Conley: Use warnings instead of prints +#. Tim Swast: Help with pull requests and IPython Up-to-date list in the order of the first contribution is given in the `AUTHORS `_ file. @@ -236,15 +292,16 @@ financial support from Google in various years through the `Google Summer of Code `_ program by providing stipends: - * in 2007 for 5 students (`GSoC 2007 `_) - * in 2008 for 1 student (`GSoC 2008 `_) - * in 2009 for 5 students (`GSoC 2009 `_) - * in 2010 for 5 students (`GSoC 2010 `_) - * in 2011 for 9 studends (`GSoC 2011 `_) + * in 2007 for 5 students (`GSoC 2007 `_) + * in 2008 for 1 student (`GSoC 2008 `_) + * in 2009 for 5 students (`GSoC 2009 `_) + * in 2010 for 5 students (`GSoC 2010 `_) + * in 2011 for 9 students (`GSoC 2011 `_) * in 2012 for 6 students (`GSoC 2012 `_) + * in 2013 for 7 students (`GSoC 2013 `_) * `Python Software Foundation (PSF) `_ has hosted - various GSoC studends over the years: + various GSoC students over the years: * 3 GSoC 2007 students (Brian, Robert and Jason) * 1 GSoC 2008 student (Fredrik) diff -Nru python3-sympy-0.7.2/doc/src/conf.py python3-sympy-0.7.3/doc/src/conf.py --- python3-sympy-0.7.2/doc/src/conf.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/doc/src/conf.py 2013-07-13 17:53:31.000000000 +0000 @@ -12,9 +12,10 @@ # serve to show the default value. import sys +import sympy # If your extensions are in another directory, add it here. -sys.path.extend(['../sympy', 'ext']) +sys.path = ['../sympy', 'ext'] + sys.path # General configuration # --------------------- @@ -22,7 +23,7 @@ # Add any Sphinx extension module names here, as strings. They can be extensions # coming with Sphinx (named 'sphinx.addons.*') or your custom ones. extensions = ['sphinx.ext.autodoc', 'sphinx.ext.viewcode', 'sphinx.ext.mathjax', - 'numpydoc', 'sympylive',] + 'numpydoc', 'sympylive', 'sphinx.ext.graphviz', ] # Use this to use pngmath instead #extensions = ['sphinx.ext.autodoc', 'sphinx.ext.viewcode', 'sphinx.ext.pngmath', ] @@ -41,15 +42,15 @@ # General substitutions. project = 'SymPy' -copyright = '2008, 2009, 2010, 2011, 2012 SymPy Development Team' +copyright = '2013 SymPy Development Team' # The default replacements for |version| and |release|, also used in various # other places throughout the built documents. # # The short X.Y version. -version = '0.7.2' +version = sympy.__version__ # The full version, including alpha/beta/rc tags. -release = '0.7.2' +release = version # There are two options for replacing |today|: either, you set today to some # non-false value, then it is used: @@ -58,7 +59,7 @@ today_fmt = '%B %d, %Y' # Translations: -locale_dirs = ["i18n/"] +locale_dirs = ["../_build/i18n/"] # List of documents that shouldn't be included in the build. #unused_docs = [] @@ -97,7 +98,23 @@ html_logo = '_static/sympylogo.png' html_favicon = '../logo/SymPy-Favicon.ico' -html_theme_options = {'collapsiblesidebar': True} +# See http://sphinx-doc.org/theming.html#builtin-themes. +html_theme_options = { + 'collapsiblesidebar': True, + 'relbarbgcolor': '#2f441e', + 'sidebarbgcolor': '#3b5526', + 'sidebarbtncolor': '#4F663C', + 'sidebarlinkcolor': '#81B953', + 'linkcolor': '#29A329', + 'visitedlinkcolor': '#307748', + 'headtextcolor': '#2f441e', + 'footerbgcolor': '#293b1b', + 'headlinkcolor': '#AAAAAA', + 'sidebartextcolor': '#DDDDDD', + 'footertextcolor': '#DDDDDD', + 'relbartextcolor': '#DDDDDD', + 'relbarlinkcolor': '#81B953', +} # If true, SmartyPants will be used to convert quotes and dashes to # typographically correct entities. @@ -143,8 +160,8 @@ # Additional stuff for the LaTeX preamble. # Tweaked to work with XeTeX. latex_elements = { - 'babel': '', - 'fontenc': r''' + 'babel': '', + 'fontenc': r''' \usepackage{amssymb} \usepackage{fontspec} \defaultfontfeatures{Mapping=tex-text} @@ -152,14 +169,18 @@ \setsansfont{DejaVu Sans} \setmonofont{DejaVu Sans Mono} ''', - 'fontpkg': '', - 'inputenc': '', - 'utf8extra': '', - 'preamble': '' + 'fontpkg': '', + 'inputenc': '', + 'utf8extra': '', + 'preamble': r''' +% redefine \LaTeX to be usable in math mode +\expandafter\def\expandafter\LaTeX\expandafter{\expandafter\text\expandafter{\LaTeX}} +''' } # SymPy logo on title page -latex_logo = '_static/sympylogo.png' +html_logo = '_static/sympylogo.png' +latex_logo = '_static/sympylogo_big.png' # Documents to append as an appendix to all manuals. #latex_appendices = [] @@ -171,18 +192,20 @@ latex_use_modindex = False default_role = 'math' -pngmath_divpng_args = ['-gamma 1.5','-D 110'] +pngmath_divpng_args = ['-gamma 1.5', '-D 110'] # Note, this is ignored by the mathjax extension # Any \newcommand should be defined in the file -pngmath_latex_preamble = '\\usepackage{amsmath}\n'+\ - '\\usepackage{bm}\n'+\ - '\\usepackage{amsfonts}\n'+\ - '\\usepackage{amssymb}\n'+\ - '\\setlength{\\parindent}{0pt}\n' +pngmath_latex_preamble = '\\usepackage{amsmath}\n' \ + '\\usepackage{bm}\n' \ + '\\usepackage{amsfonts}\n' \ + '\\usepackage{amssymb}\n' \ + '\\setlength{\\parindent}{0pt}\n' texinfo_documents = [ - (master_doc, 'sympy', 'SymPy Documentation', - 'SymPy Development Team', - 'SymPy', 'Computer algebra system (CAS) in Python', 'Programming', - 1), + (master_doc, 'sympy', 'SymPy Documentation', 'SymPy Development Team', + 'SymPy', 'Computer algebra system (CAS) in Python', 'Programming', 1), ] + +# Use svg for graphviz + +graphviz_output_format = 'svg' Binary files /tmp/E2vCQhuc_3/python3-sympy-0.7.2/doc/src/figures/admon-note.png and /tmp/E99RNQO9Lx/python3-sympy-0.7.3/doc/src/figures/admon-note.png differ Binary files /tmp/E2vCQhuc_3/python3-sympy-0.7.2/doc/src/figures/featured-downloads.png and /tmp/E99RNQO9Lx/python3-sympy-0.7.3/doc/src/figures/featured-downloads.png differ diff -Nru python3-sympy-0.7.2/doc/src/gotchas.rst python3-sympy-0.7.3/doc/src/gotchas.rst --- python3-sympy-0.7.2/doc/src/gotchas.rst 2012-10-17 03:02:20.000000000 +0000 +++ python3-sympy-0.7.3/doc/src/gotchas.rst 2013-07-13 17:53:31.000000000 +0000 @@ -8,6 +8,7 @@ Introduction ============ + SymPy runs under the `Python Programming Language `_, so there are some things that may behave differently than they do in other, independent computer algebra systems @@ -28,10 +29,12 @@ Equals Signs (=) ================ + Single Equals Sign ------------------ -The equals sign (``=``) is the assignment operator, not an equality. If -you want to do :math:`x=y`, use ``Eq(x,y)`` for equality. + +The equals sign (``=``) is the assignment operator, not equality. If +you want to do :math:`x = y`, use ``Eq(x, y)`` for equality. Alternatively, all expressions are assumed to equal zero, so you can just subtract one side and use ``x - y``. @@ -46,6 +49,7 @@ Double Equals Signs ------------------- + Double equals signs (``==``) are used to test equality. However, this tests expressions exactly, not symbolically. For example: @@ -62,9 +66,10 @@ >>> from sympy import simplify, cos, sin, expand >>> simplify((x + 1)**2 - (x**2 + 2*x + 1)) 0 - >>> simplify(sin(2*x) - 2*sin(x)*cos(x)) - -2*sin(x)*cos(x) + sin(2*x) - >>> expand(sin(2*x) - 2*sin(x)*cos(x), trig=True) + >>> eq = sin(2*x) - 2*sin(x)*cos(x) + >>> simplify(eq) + 0 + >>> expand(eq, trig=True) 0 .. note:: @@ -75,8 +80,10 @@ Variables ========= + Variables Assignment does not Create a Relation Between Expressions ------------------------------------------------------------------- + When you use ``=`` to do assignment, remember that in Python, as in most programming languages, the variable does not change if you change the value you assigned to it. The equations you are typing use the values @@ -85,14 +92,14 @@ Consider the following: >>> from sympy import Symbol - >>> a = Symbol('a') # Create a Symbol named a, that is also stored in the variable "a" - >>> b = a + 1 # Create another object, b, that refers to 'a' + >>> a = Symbol('a') # Symbol, `a`, stored as variable "a" + >>> b = a + 1 # an expression involving `a` stored as variable "b" >>> print(b) a + 1 - >>> a = 4 # a now points to the literal integer 4, not Symbol('a') + >>> a = 4 # "a" now points to literal integer 4, not Symbol('a') >>> print(a) 4 - >>> b # But b is still pointing at Symbol('a') + >>> print(b) # "b" is still pointing at the expression involving `a` a + 1 Changing quantity :obj:`a` does not change :obj:`b`; you are not working @@ -107,11 +114,11 @@ >>> d = r*t >>> print(d) rate*time - >>> r=80 - >>> t=2 + >>> r = 80 + >>> t = 2 >>> print(d) # We haven't changed d, only r and t rate*time - >>> d=r*t + >>> d = r*t >>> print(d) # Now d is using the current values of r and t 160 @@ -173,15 +180,16 @@ Symbols ------- + Symbols are variables, and like all other variables, they need to be assigned before you can use them. For example: >>> import sympy - >>> z**2 # z is not defined yet #doctest: +SKIP + >>> z**2 # z is not defined yet #doctest: +SKIP Traceback (most recent call last): File "", line 1, in NameError: name 'z' is not defined - >>> sympy.var('z') # This is the easiest way to define z as a standard symbol + >>> sympy.var('z') # This is the easiest way to define z as a standard symbol z >>> z**2 z**2 @@ -194,7 +202,7 @@ >>> from sympy import * >>> x, y, z, t = symbols('x y z t') >>> k, m, n = symbols('k m n', integer=True) - >>> f, g, h = list(map(Function, 'fgh')) + >>> f, g, h = symbols('f g h', cls=Function) You can also import common symbol names from :mod:`sympy.abc`. @@ -202,7 +210,7 @@ >>> w w >>> import sympy - >>> dir(sympy.abc) #doctest: +SKIP + >>> dir(sympy.abc) #doctest: +SKIP ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'Symbol', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '__builtins__', '__doc__', '__file__', '__name__', '__package__', '_greek', @@ -231,27 +239,27 @@ not prevent you from overriding default SymPy names or functions, so be careful. - >>> cos(pi) # cos and pi are a built-in sympy names. + >>> cos(pi) # cos and pi are a built-in sympy names. -1 - >>> pi = 3 # Notice that there is no warning for overriding pi. + >>> pi = 3 # Notice that there is no warning for overriding pi. >>> cos(pi) cos(3) - >>> def cos(x): # No warning for overriding built-in functions either. + >>> def cos(x): # No warning for overriding built-in functions either. ... return 5*x ... >>> cos(pi) 15 - >>> from sympy import cos # reimport to restore normal behavior + >>> from sympy import cos # reimport to restore normal behavior To get a full list of all default names in SymPy do: >>> import sympy - >>> dir(sympy) #doctest: +SKIP + >>> dir(sympy) #doctest: +SKIP # A big list of all default sympy names and functions follows. # Ignore everything that starts and ends with __. -If you have `iPython `_ installed and +If you have `iPython `_ installed and use :command:`isympy`, you can also press the TAB key to get a list of all built-in names and to autocomplete. Also, see `this page `_ for a @@ -265,10 +273,12 @@ Symbolic Expressions ==================== + .. _python-vs-sympy-numbers: Python numbers vs. SymPy Numbers -------------------------------- + SymPy uses its own classes for integers, rational numbers, and floating point numbers instead of the default Python :obj:`int` and :obj:`float` types because it allows for more control. But you have to be careful. @@ -276,11 +286,11 @@ to a Python expression. Use the :func:`sympify` function, or just :func:`S`, to ensure that something is a SymPy expression. - >>> 6.2 # Python float. Notice the floating point accuracy problems. #doctest: +SKIP + >>> 6.2 # Python float. Notice the floating point accuracy problems. 6.2000000000000002 - >>> type(6.2) + >>> type(6.2) # in Python 2.x, in Py3k <... 'float'> - >>> S(6.2) # SymPy Float has no such problems because of arbitrary precision. + >>> S(6.2) # SymPy Float has no such problems because of arbitrary precision. 6.20000000000000 >>> type(S(6.2)) @@ -292,11 +302,11 @@ to them. The solution is to :func:`sympify` one of the numbers, or use :mod:`Rational`. - >>> x**(1/2) # evaluates to x**0 or x**0.5 #doctest: +SKIP + >>> x**(1/2) # evaluates to x**0 or x**0.5 x**0.5 - >>> x**(S(1)/2) # sympyify one of the ints + >>> x**(S(1)/2) # sympyify one of the ints sqrt(x) - >>> x**Rational(1, 2) # use the Rational class + >>> x**Rational(1, 2) # use the Rational class sqrt(x) With a power of ``1/2`` you can also use ``sqrt`` shorthand: @@ -319,16 +329,19 @@ Rational. >>> x = Symbol('x') - >>> print(solve(7*x -22,x)) + >>> print(solve(7*x -22, x)) [22/7] - >>> 22/7 # If we just copy and paste we get int 3 or a float #doctest: +SKIP + >>> 22/7 # If we just copy and paste we get int 3 or a float 3.142857142857143 >>> # One solution is to just assign the expression to a variable >>> # if we need to use it again. - >>> a = solve(7*x - 22,x) + >>> a = solve(7*x - 22, x) >>> a [22/7] - >>> # The other solution is to put quotes around the expression and run it through S() (sympify) + + The other solution is to put quotes around the expression + and run it through S() (i.e., sympify it): + >>> S("22/7") 22/7 @@ -337,15 +350,15 @@ `integer division `_. >>> - >>> 1/2 # with division imported it evaluates to a python float #doctest: +SKIP + >>> 1/2 # With division imported it evaluates to a python float 0.5 - >>> 1//2 # You can still achieve integer division with // + >>> 1//2 # You can still achieve integer division with // 0 But be careful: you will now receive floats where you might have desired a Rational: - >>> x**(1/2) #doctest: +SKIP + >>> x**(1/2) x**0.5 :mod:`Rational` only works for number/number and is only meant for @@ -356,39 +369,41 @@ >>> Rational(2, x) Traceback (most recent call last): - File "...", line ..., in ... - compileflags, 1) in test.globs - File "<...>", line 1, in - Rational(2, x) - ... - TypeError: int() argument must be a string or a number, not 'Symbol' + ... + TypeError: invalid input: x >>> 2/x 2/x Evaluating Expressions with Floats and Rationals ------------------------------------------------ -SymPy keeps track of the precision of Floats. The default precision is -15 digits. When expressions involving Floats are evaluated, the result +SymPy keeps track of the precision of ``Float`` objects. The default precision is +15 digits. When an expression involving a ``Float`` is evaluated, the result will be expressed to 15 digits of precision but those digits (depending on the numbers involved with the calculation) may not all be significant. -The first issue to keep in mind is how the Float is created: it is created +The first issue to keep in mind is how the ``Float`` is created: it is created with a value and a precision. The precision indicates how precise of a value -to use when that Float (or an expression it appears in) is evaluated. +to use when that ``Float`` (or an expression it appears in) is evaluated. -The values can be given as strings, integers, or Rationals. We do so below -with a few different values: +The values can be given as strings, integers, floats, or rationals. - - integer input always returns an exact Integer and precision is ignored + - strings and integers are interpreted as exact - >>> Float(1234, 3) - 1234 + >>> Float(100) + 100.000000000000 + >>> Float('100', 5) + 100.00 - - strings are interpreted as exact and always result in a Float + - to have the precision match the number of digits, the null string + can be used for the precision - >>> Float('100', 3) + >>> Float(100, '') 100. + >>> Float('12.34') + 12.3400000000000 + >>> Float('12.34', '') + 12.34 >>> s, r = [Float(j, 3) for j in ('0.25', Rational(1, 7))] >>> for f in [s, r]: @@ -424,7 +439,7 @@ >>> Float('0.1', 10) + Float('0.1', 3) 0.2000061035 -Although the evalf engine tried to maintain 10 digits of precision (since +Although the ``evalf`` engine tried to maintain 10 digits of precision (since that was the highest precision represented) the 3-digit precision used limits the accuracy to about 4 digits -- not all the digits you see are significant. evalf doesn't try to keep track of the number of @@ -442,7 +457,7 @@ >>> abs(big_trig_identity.subs(x, .1).n(2)) > 1000 True -When the cos and sin terms were evaluated to 15 digits of precision and +When the `\cos` and `\sin` terms were evaluated to 15 digits of precision and multiplied by the big number, they gave a large number that was only precise to 15 digits (approximately) and when the 20 digit big number was subtracted the result was not zero. @@ -451,7 +466,7 @@ values for expressions: 1) Pass the desired substitutions with the call to evaluate. By doing - the subs first, the Float values can not be updated as necessary. By + the subs first, the ``Float`` values can not be updated as necessary. By passing the desired substitutions with the call to evalf the ability to re-evaluate as necessary is gained and the results are impressively better: @@ -462,7 +477,7 @@ 2) Use Rationals, not Floats. During the evaluation process, the Rational can be computed to an arbitrary precision while the Float, once created -- at a default of 15 digits -- cannot. Compare the - value of -1.4e+3 above with the nearly zero value obtained when + value of ``-1.4e+3`` above with the nearly zero value obtained when replacing x with a Rational representing 1/10 -- before the call to evaluate: @@ -491,8 +506,8 @@ var('x y a b') expr = 3*x + 4*y print 'original =', expr - expr_modified = expr.subs({x:a, y:b}) - print 'modified = ', expr_modified + expr_modified = expr.subs({x: a, y: b}) + print 'modified =', expr_modified if __name__ == "__main__": main() @@ -501,7 +516,7 @@ :obj:`x` with variable :obj:`a`, and variable :obj:`y` with variable :obj:`b`:: original = 3*x + 4*y - modified = 3*a + 4*b + modified = 3*a + 4*b The :func:`subs` function does not modify the original expression :obj:`expr`. Rather, a modified copy of the expression is returned. This returned object @@ -512,6 +527,7 @@ Mathematical Operators ---------------------- + SymPy uses the same default operators as Python. Most of these, like ``*/+-``, are standard. Aside from integer division discussed in :ref:`Python numbers vs. SymPy Numbers ` above, @@ -529,11 +545,11 @@ SyntaxError: invalid syntax >>> 2*x 2*x - >>> (x+1)^2 # This is not power. Use ** instead. + >>> (x + 1)^2 # This is not power. Use ** instead. Traceback (most recent call last): ... TypeError: unsupported operand type(s) for ^: 'Add' and 'int' - >>> (x+1)**2 + >>> (x + 1)**2 (x + 1)**2 >>> pprint(3 - x**(2*x)/(x + 1)) 2*x @@ -544,6 +560,7 @@ Inverse Trig Functions ---------------------- + SymPy uses different names for some functions than most computer algebra systems. In particular, the inverse trig functions use the python names of :func:`asin`, :func:`acos` and so on instead of the usual ``arcsin`` @@ -552,6 +569,7 @@ Special Symbols =============== + The symbols ``[]``, ``{}``, ``=``, and ``()`` have special meanings in Python, and thus in SymPy. See the Python docs linked to above for additional information. @@ -560,6 +578,7 @@ Lists ----- + Square brackets ``[]`` denote a list. A list is a container that holds any number of different objects. A list can contain anything, including items of different types. Lists are mutable, which means that you can @@ -573,15 +592,15 @@ Example: - >>> a = [x, 1] # A simple list of two items + >>> a = [x, 1] # A simple list of two items >>> a [x, 1] - >>> a[0] # This is the first item + >>> a[0] # This is the first item x - >>> a[0] = 2 # You can change values of lists after they have been created + >>> a[0] = 2 # You can change values of lists after they have been created >>> print(a) [2, 1] - >>> print(solve(x**2+2*x-1,x)) # Some functions return lists + >>> print(solve(x**2 + 2*x - 1, x)) # Some functions return lists [-1 + sqrt(2), -sqrt(2) - 1] @@ -591,21 +610,22 @@ Dictionaries ------------ + Curly brackets ``{}`` denote a dictionary, or a dict for short. A dictionary is an unordered list of non-duplicate keys and values. The -syntax is ``{key:value}``. You can access values of keys using square +syntax is ``{key: value}``. You can access values of keys using square bracket notation. - >>> d = {'a':1, 'b':2} # A dictionary. + >>> d = {'a': 1, 'b': 2} # A dictionary. >>> d {'a': 1, 'b': 2} - >>> d['a'] # How to access items in a dict + >>> d['a'] # How to access items in a dict 1 - >>> roots((x-1)**2*(x-2),x) # some functions return dicts + >>> roots((x - 1)**2*(x - 2), x) # Some functions return dicts {1: 2, 2: 1} >>> # Some SymPy functions return dictionaries. For example, >>> # roots returns a dictionary of root:multiplicity items. - >>> roots((x - 5)**2*(x + 3),x) + >>> roots((x - 5)**2*(x + 3), x) {-3: 1, 5: 2} >>> # This means that the root -3 occurs once and the root 5 occurs twice. @@ -615,6 +635,7 @@ Tuples ------ + Parentheses ``()``, aside from changing operator precedence and their use in function calls, (like ``cos(x)``), are also used for tuples. A ``tuple`` is identical to a :ref:`list `, except that it is not @@ -623,23 +644,32 @@ sometimes it can be more convenient to type parentheses instead of square brackets. - >>> t = (1, 2, x) # Tuples are like lists + >>> t = (1, 2, x) # Tuples are like lists >>> t (1, 2, x) >>> t[0] 1 - >>> t[0] = 4 # Except you can not change them after they have been created + >>> t[0] = 4 # Except you can not change them after they have been created Traceback (most recent call last): File "", line 1, in TypeError: 'tuple' object does not support item assignment - >>> (x,) # Single element tuples, unlike lists, must have a comma in them. + + Single element tuples, unlike lists, must have a comma in them: + + >>> (x,) (x,) - >>> (x) # Not a tuple + + Without the comma, a single expression without a comma is not a tuple: + + >>> (x) x - >>> # integrate takes a tuple as the second argument if you want to integrate with limits. + + integrate takes a sequence as the second argument if you want to integrate + with limits (and a tuple or list will work): + >>> integrate(x**2, (x, 0, 1)) 1/3 - >>> integrate(x**2, [x, 0, 1]) # But a list works too. + >>> integrate(x**2, [x, 0, 1]) 1/3 @@ -651,6 +681,7 @@ Keyword Arguments ----------------- + Aside from the usage described :ref:`above `, equals signs (``=``) are also used to give named arguments to functions. Any function that has ``key=value`` in its parameters list (see below on how @@ -661,25 +692,41 @@ ``**assumptions``) allow you to add any number of ``key=value`` pairs that you want, and they will all be evaluated according to the function. - >>> # sqrt(x**2) doesn't auto simplify to x because x is assumed to be - >>> # complex by default, and, for example, sqrt((-1)**2) == sqrt(1) == 1 != -1. + ``sqrt(x**2)`` doesn't auto simplify to x because x is assumed to be + complex by default, and, for example, ``sqrt((-1)**2) == sqrt(1) == 1 != -1``: + >>> sqrt(x**2) sqrt(x**2) - >>> x = Symbol('x', positive=True) # One example of keyword arguments is assumptions for Symbols - >>> sqrt(x**2) # only == x if x >= 0 + + Giving assumptions to Symbols is an example of using the keyword argument: + + >>> x = Symbol('x', positive=True) + + The square root will now simplify since it knows that ``x >= 0``: + + >>> sqrt(x**2) x - >>> pprint(powsimp(x**n*x**m*y**n*y**m)) # powsimp has a default argument, combine='all' + + powsimp has a default argument of ``combine='all'``: + + >>> pprint(powsimp(x**n*x**m*y**n*y**m)) m + n (x*y) - >>> # Setting combine to the default value is the same as not setting it. + + Setting combine to the default value is the same as not setting it. + >>> pprint(powsimp(x**n*x**m*y**n*y**m, combine='all')) m + n (x*y) - >>> # The non-default options are 'exp', which combines exponents... + + The non-default options are ``'exp'``, which combines exponents... + >>> pprint(powsimp(x**n*x**m*y**n*y**m, combine='exp')) m + n m + n x *y - >>> # ...and 'base', which combines bases. + + ...and 'base', which combines bases. + >>> pprint(powsimp(x**n*x**m*y**n*y**m, combine='base')) m n (x*y) *(x*y) @@ -690,14 +737,16 @@ Getting help from within SymPy ============================== + help() ------ + Although all docs are available at `docs.sympy.org `_ or on the `SymPy Wiki `_, you can also get info on functions from within the Python interpreter that runs SymPy. The easiest way to do this is to do ``help(function)``, or ``function?`` if you are using :command:`ipython`:: - In [1]: help(powsimp) # help() works everywhere + In [1]: help(powsimp) # help() works everywhere In [2]: # But in ipython, you can also use ?, which is better because it In [3]: # it gives you more information @@ -711,12 +760,13 @@ source() -------- + Another useful option is the :func:`source` function. This will print the source code of a function, including any docstring that it may have. You can also do ``function??`` in :command:`ipython`. For example, from SymPy 0.6.5: - >>> source(simplify) # simplify() is actually only 2 lines of code. #doctest: +SKIP + >>> source(simplify) # simplify() is actually only 2 lines of code. #doctest: +SKIP In file: ./sympy/simplify/simplify.py def simplify(expr): """Naively simplifies the given expression. diff -Nru python3-sympy-0.7.2/doc/src/guide.rst python3-sympy-0.7.3/doc/src/guide.rst --- python3-sympy-0.7.2/doc/src/guide.rst 2012-10-17 03:02:20.000000000 +0000 +++ python3-sympy-0.7.3/doc/src/guide.rst 2013-07-13 17:53:31.000000000 +0000 @@ -11,8 +11,8 @@ If you are new to SymPy, start with the :ref:`Tutorial `. If you went through it, now -it's time to learn how SymPy works internally and this is what this guide is -about. Once you grasp the idea behind SymPy, you will be able to use it +it's time to learn how SymPy works internally, which is what this guide is +about. Once you grasp the ideas behind SymPy, you will be able to use it effectively and also know how to extend it and fix it. You may also be just interested in :ref:`SymPy Modules Reference `. @@ -24,15 +24,15 @@ Ondřej's approach ----------------- -Let's say I'd like to understand how ``x+y+x`` works and how it is possible -that it gets simplified to ``2*x+y``. +Let's say I'd like to understand how ``x + y + x`` works and how it is possible +that it gets simplified to ``2*x + y``. I write a simple script, I usually call it ``t.py`` (I don't remember anymore why I call it that way):: from sympy.abc import x, y - e = x + y +x + e = x + y + x print e @@ -64,7 +64,7 @@ to fit in this guide. I see values of all local variables in the left panel, so it's very easy to see -what's happening. You can see, that the ``y+2*x`` is emerging in the ``obj`` +what's happening. You can see, that the ``y + 2*x`` is emerging in the ``obj`` variable. Observing that ``obj`` is constructed from ``c_part`` and ``nc_part`` and seeing what ``c_part`` contains (``y`` and ``2*x``). So looking at the line 28 (the whole line is not visible on the screenshot, so here it is):: @@ -124,22 +124,22 @@ For easier use, there is a syntactic sugar for expressions like: -``cos(x)+1`` is equal to ``cos(x).__add__(1)`` is equal to -``Add(cos(x),Integer(1))`` +``cos(x) + 1`` is equal to ``cos(x).__add__(1)`` is equal to +``Add(cos(x), Integer(1))`` or ``2/cos(x)`` is equal to ``cos(x).__rdiv__(2)`` is equal to -``Mul(Rational(2),Pow(cos(x),Rational(-1)))``. +``Mul(Rational(2), Pow(cos(x), Rational(-1)))``. So, you can write normal expressions using python arithmetics like this:: - a=Symbol("a") - b=Symbol("b") - e=(a+b)**2 + a = Symbol("a") + b = Symbol("b") + e = (a + b)**2 print e -but from the sympy point of view, we just need the classes ``Add``, ``Mul``, +but from the SymPy point of view, we just need the classes ``Add``, ``Mul``, ``Pow``, ``Rational``, ``Integer``. Automatic evaluation to canonical form @@ -155,8 +155,8 @@ the only requirement is that all equivalent expressions must have the same canonical form. We tried the conversion to a canonical (standard) form to be as fast as possible and also in a way so that the result is what you would -write by hand - so for example ``b*a + -4 + b + a*b + 4 + (a+b)**2`` becomes -``2*a*b + b + (a+b)**2``. +write by hand - so for example ``b*a + -4 + b + a*b + 4 + (a + b)**2`` becomes +``2*a*b + b + (a + b)**2``. Whenever you construct an expression, for example ``Add(x, x)``, the ``Add.__new__()`` is called and it determines what to return. In this case:: @@ -179,17 +179,17 @@ Expressions can be compared using a regular python syntax:: >>> from sympy.abc import x, y - >>> x+y == y+x + >>> x + y == y + x True - >>> x+y == y-x + >>> x + y == y - x False -We made the following decision in SymPy: ``a=Symbol("x")`` and another -``b=Symbol("x")`` (with the same string "x") is the same thing, i.e ``a==b`` is -``True``. We chose ``a==b``, because it is more natural - ``exp(x)==exp(x)`` is +We made the following decision in SymPy: ``a = Symbol("x")`` and another +``b = Symbol("x")`` (with the same string "x") is the same thing, i.e ``a == b`` is +``True``. We chose ``a == b``, because it is more natural - ``exp(x) == exp(x)`` is also ``True`` for the same instance of ``x`` but different instances of ``exp``, -so we chose to have ``exp(x)==exp(x)`` even for different instances of ``x``. +so we chose to have ``exp(x) == exp(x)`` even for different instances of ``x``. Sometimes, you need to have a unique symbol, for example as a temporary one in some calculation, which is going to be substituted for something else at the @@ -208,7 +208,7 @@ --------- Starting with 0.6.4, you can turn on/off debug messages with the environment -variable SYMPY_DEBUG, which is expected to have the values True or False. For +variable ``SYMPY_DEBUG``, which is expected to have the values True or False. For example, to turn on debugging, you would issue:: [user@localhost]: SYMPY_DEBUG=True ./bin/isympy @@ -228,8 +228,8 @@ class cos(Function): pass -and use it like ``1+cos(x)``, but if you don't implement the ``fdiff()`` method, -you will not be able to call ``(1+cos(x)).series()``. +and use it like ``1 + cos(x)``, but if you don't implement the ``fdiff()`` method, +you will not be able to call ``(1 + cos(x)).series()``. The symbolic object is characterized (defined) by the things which it can do, so implementing more methods like ``fdiff()``, ``subs()`` etc., you are creating @@ -244,7 +244,7 @@ All objects in sympy are immutable - in the sense that any operation just returns a new instance (it can return the same instance only if it didn't change). This is a common mistake to change the current instance, like -``self.arg=self.arg +1`` (wrong!). Use ``arg=self.arg + 1; return arg`` instead. +``self.arg = self.arg + 1`` (wrong!). Use ``arg = self.arg + 1; return arg`` instead. The object is immutable in the sense of the symbolic expression it represents. It can modify itself to keep track of, for example, its hash. Or it can recalculate anything regarding the @@ -281,7 +281,7 @@ if arg.is_negative: return S.NegativeOne if isinstance(arg, Basic.Mul): - coeff, terms = arg.as_coeff_terms() + coeff, terms = arg.as_coeff_mul() if not isinstance(coeff, Basic.One): return cls(coeff) * cls(Basic.Mul(*terms)) @@ -341,7 +341,7 @@ def eval(cls, n, k): if not 0 <= k < n: raise ValueError("must have 0 <= k < n") - return C.cos(S.Pi*(2*k+1)/(2*n)) + return C.cos(S.Pi*(2*k + 1)/(2*n)) .. note:: the first argument of a @classmethod should be ``cls`` (i.e. not @@ -388,7 +388,7 @@ ... nargs = 1 ... ... def fdiff(self, argindex = 1): - ... return 1-what_am_i(self.args[0])**2 + ... return 1 - what_am_i(self.args[0])**2 ... ... @classmethod ... def eval(cls, arg): @@ -421,7 +421,7 @@ 1 -common tasks +Common tasks ------------ Please use the same way as is shown below all across SymPy. @@ -516,19 +516,14 @@ would like to get fixed and fix it. If you find something odd, please report it into issues_ first before fixing it. Feel free to consult with us on the mailinglist_. Then send your patch either to the issues_ or the mailinglist_. -See the SymPyDevelopment_ wiki, but don't worry about it too much if you find -it too formal - simply get in touch with us on the mailinglist_ and we'll help -you get your patch accepted. - -.. _issues: http://code.google.com/p/sympy/issues/list -.. _mailinglist: http://groups.google.com/group/sympy -.. _SymPyDevelopment: http://code.google.com/p/sympy/wiki/SymPyDevelopment Please read our excellent `SymPy Patches Tutorial `_ at our wiki for a guide on how to write patches to SymPy, how to work with Git, and how to make your life easier as you get started with SymPy. +.. _issues: http://code.google.com/p/sympy/issues/list +.. _mailinglist: http://groups.google.com/group/sympy Improving the docs ------------------ diff -Nru python3-sympy-0.7.2/doc/src/index.rst python3-sympy-0.7.3/doc/src/index.rst --- python3-sympy-0.7.2/doc/src/index.rst 2012-10-17 01:53:14.000000000 +0000 +++ python3-sympy-0.7.3/doc/src/index.rst 2013-07-13 17:50:18.000000000 +0000 @@ -17,7 +17,7 @@ :maxdepth: 2 install.rst - tutorial.rst + tutorial/index.rst gotchas.rst guide.rst modules/index.rst @@ -25,10 +25,3 @@ wiki.rst outreach.rst aboutus.rst - -If something cannot be easily accessed from this page, it's a bug (`please -report it`_). - -This documentation is maintained with docutils, so you might see some comments in the form #doctest:... . You can safely ignore them. - -.. _please report it: http://code.google.com/p/sympy/issues/list diff -Nru python3-sympy-0.7.2/doc/src/install.rst python3-sympy-0.7.3/doc/src/install.rst --- python3-sympy-0.7.2/doc/src/install.rst 2012-10-17 03:02:20.000000000 +0000 +++ python3-sympy-0.7.3/doc/src/install.rst 2013-07-13 17:53:31.000000000 +0000 @@ -1,3 +1,5 @@ +.. _installation: + Installation ------------ @@ -10,6 +12,7 @@ Source ====== + SymPy currently recommends that users install directly from the source files. You will first have to download the source files via the archive. Download the latest release (tar.gz) from the `downloads site`_ and open it with your @@ -43,13 +46,14 @@ Git === + If you are a developer or like to get the latest updates as they come, be sure to install from git. To download the repository, execute the following from the command line:: $ git clone git://github.com/sympy/sympy.git -Then, execute either the setup.py or the bin/isympy scripts as demonstrated +Then, execute either the `setup.py` or the `bin/isympy` scripts as demonstrated above. To update to the latest version, go into your repository and execute:: @@ -59,24 +63,39 @@ If you want to install SymPy, but still want to use the git version, you can run from your repository:: - $ setup.py develop + $ setupegg.py develop This will cause the installed version to always point to the version in the git directory. If you're using the git repository with Python 3, you have to use the ``./bin/use2to3`` script to build the Python 3 version of SymPy. This will put -everything in the py3ksympy directory. +everything in the py3k-sympy directory. + +Anaconda +======== + +Although SymPy does not have any hard dependencies, many nice features are +only enabled when certain libraries are installed. For example, without +Matplotlib, only simple text-based plotting is enabled. With the IPython +notebook or qtconsole, you can get nicer `\LaTeX` printing by running +``%loadext sympy.interactive.ipythonprinting``. An easy way to get all these +libraries in addition to SymPy is to install `Anaconda +`_, which is a free Python distribution +from Continuum Analytics that includes SymPy, Matplotlib, IPython, NumPy, and +many more useful packages for scientific computing. Other Methods ============= -An installation executable is available for Windows users at the -`downloads site`_ (.exe). In addition, various Linux distributions have SymPy + +An installation executable (.exe) is available for Windows users at the +`downloads site`_. In addition, various Linux distributions have SymPy available as a package. Others are strongly encouraged to download from source (details above). Run SymPy ========= + After installation, it is best to verify that your freshly-installed SymPy works. To do this, start up Python and import the SymPy libraries:: @@ -91,7 +110,7 @@ >>> integrate(1/x, x) log(x) -For a starter guide on using SymPy effectively, refer to the :doc:`tutorial`. +For a starter guide on using SymPy effectively, refer to the :ref:`tutorial`. Questions ========= diff -Nru python3-sympy-0.7.2/doc/src/modules/assumptions/index.rst python3-sympy-0.7.3/doc/src/modules/assumptions/index.rst --- python3-sympy-0.7.2/doc/src/modules/assumptions/index.rst 2012-10-17 01:53:14.000000000 +0000 +++ python3-sympy-0.7.3/doc/src/modules/assumptions/index.rst 2013-07-13 17:53:31.000000000 +0000 @@ -37,18 +37,18 @@ See documentation for the logic module for a complete list of valid boolean expressions. -You can also define global assumptions so you don't have to pass that argument -each time to function ask(). This is done by using the global_assumptions -object from module sympy.assumptions. You can then clear global assumptions -with global_assumptions.clear():: +You can also define a context so you don't have to pass that argument +each time to function ask(). This is done by using the assuming context manager +from module sympy.assumptions. :: + >>> >>> from sympy import * >>> x = Symbol('x') - >>> global_assumptions.add(Q.positive(x)) - >>> ask(Q.positive(x)) + >>> y = Symbol('y') + >>> facts = Q.positive(x), Q.positive(y) + >>> with assuming(*facts): + ... print(ask(Q.positive(2*x + y))) True - >>> global_assumptions.clear() - Supported predicates ==================== diff -Nru python3-sympy-0.7.2/doc/src/modules/categories.rst python3-sympy-0.7.3/doc/src/modules/categories.rst --- python3-sympy-0.7.2/doc/src/modules/categories.rst 2012-10-17 02:30:33.000000000 +0000 +++ python3-sympy-0.7.3/doc/src/modules/categories.rst 2013-07-13 17:50:18.000000000 +0000 @@ -1,8 +1,6 @@ Category Theory Module ====================== -.. module:: sympy.categories - Introduction ------------ @@ -25,6 +23,8 @@ Base Class Reference -------------------- +.. module:: sympy.categories + This section lists the classes which implement some of the basic notions in category theory: objects, morphisms, categories, and diagrams. @@ -60,3 +60,12 @@ .. autoclass:: DiagramGrid :members: + +.. autoclass:: ArrowStringDescription + +.. autoclass:: XypicDiagramDrawer + :members: + +.. autofunction:: xypic_draw_diagram + +.. autofunction:: preview_diagram diff -Nru python3-sympy-0.7.2/doc/src/modules/combinatorics/index.rst python3-sympy-0.7.3/doc/src/modules/combinatorics/index.rst --- python3-sympy-0.7.2/doc/src/modules/combinatorics/index.rst 2012-10-17 02:30:33.000000000 +0000 +++ python3-sympy-0.7.3/doc/src/modules/combinatorics/index.rst 2013-07-13 17:50:18.000000000 +0000 @@ -21,3 +21,4 @@ util.rst group_constructs.rst testutil.rst + tensor_can.rst diff -Nru python3-sympy-0.7.2/doc/src/modules/combinatorics/tensor_can.rst python3-sympy-0.7.3/doc/src/modules/combinatorics/tensor_can.rst --- python3-sympy-0.7.2/doc/src/modules/combinatorics/tensor_can.rst 1970-01-01 00:00:00.000000000 +0000 +++ python3-sympy-0.7.3/doc/src/modules/combinatorics/tensor_can.rst 2013-07-13 17:50:18.000000000 +0000 @@ -0,0 +1,14 @@ +.. _combinatorics-tensor_can: + +Tensor Canonicalization +======================= + +.. module:: sympy.combinatorics.tensor_can + +.. autofunction:: canonicalize + +.. autofunction:: double_coset_can_rep + +.. autofunction:: get_symmetric_group_sgs + +.. autofunction:: bsgs_direct_product diff -Nru python3-sympy-0.7.2/doc/src/modules/concrete.rst python3-sympy-0.7.3/doc/src/modules/concrete.rst --- python3-sympy-0.7.2/doc/src/modules/concrete.rst 2012-10-17 01:53:14.000000000 +0000 +++ python3-sympy-0.7.3/doc/src/modules/concrete.rst 2013-07-13 17:50:18.000000000 +0000 @@ -75,9 +75,24 @@ hypergeometric: >>> hypersimp(factorial(2*n), n) - 4*n**2 + 6*n + 2 + 2*(n + 1)*(2*n + 1) >>> hypersimp(factorial(n**2), n) + +Sum and Product manipulation +---------------------------- + +.. autofunction:: sympy.concrete.simplification.index + +.. autofunction:: sympy.concrete.simplification.change_index + +.. autofunction:: sympy.concrete.simplification.reorder_limit + +.. autofunction:: sympy.concrete.simplification.reorder + +.. autofunction:: sympy.concrete.simplification.reverse_order + + Concrete Class Reference ------------------------ .. autoclass:: sympy.concrete.summations.Sum diff -Nru python3-sympy-0.7.2/doc/src/modules/evalf.rst python3-sympy-0.7.3/doc/src/modules/evalf.rst --- python3-sympy-0.7.2/doc/src/modules/evalf.rst 2012-10-17 03:02:20.000000000 +0000 +++ python3-sympy-0.7.3/doc/src/modules/evalf.rst 2013-07-13 17:53:31.000000000 +0000 @@ -46,9 +46,9 @@ You can also use the standard Python functions ``float()``, ``complex()`` to convert SymPy expressions to regular Python numbers: - >>> float(pi) #doctest: +SKIP + >>> float(pi) 3.1415926535... - >>> complex(pi+E*I) #doctest: +SKIP + >>> complex(pi+E*I) (3.1415926535...+2.7182818284...j) @@ -137,10 +137,10 @@ cancellation: >>> a, b = GoldenRatio**1000/sqrt(5), fibonacci(1000) - >>> float(a) #doctest: +SKIP - 4.34665576869...e+208 - >>> float(b) #doctest: +SKIP - 4.34665576869...e+208 + >>> float(a) + 4.34665576869e+208 + >>> float(b) + 4.34665576869e+208 >>> float(a) - float(b) 0.0 @@ -339,7 +339,8 @@ >>> f = factorial >>> n = Symbol('n', integer=True) - >>> R = 9801/sqrt(8)/Sum(f(4*n)*(1103+26390*n)/f(n)**4/396**(4*n), (n, 0, oo)) #doctest: +SKIP + >>> R = 9801/sqrt(8)/Sum(f(4*n)*(1103+26390*n)/f(n)**4/396**(4*n), + ... (n, 0, oo)) #doctest: +SKIP >>> N(R, 10000) #doctest: +SKIP 3.141592653589793238462643383279502884197169399375105820974944592307816406286208 99862803482534211706798214808651328230664709384460955058223172535940812848111745 @@ -409,7 +410,7 @@ 2 \/ 10 4 >>> nsimplify(I**I, [pi]) -pi - --- + ---- 2 e >>> n = Symbol('n') diff -Nru python3-sympy-0.7.2/doc/src/modules/functions/combinatorial.rst python3-sympy-0.7.3/doc/src/modules/functions/combinatorial.rst --- python3-sympy-0.7.2/doc/src/modules/functions/combinatorial.rst 2012-10-17 03:02:20.000000000 +0000 +++ python3-sympy-0.7.3/doc/src/modules/functions/combinatorial.rst 2013-07-13 17:50:18.000000000 +0000 @@ -86,3 +86,70 @@ .. autoclass:: sympy.functions.combinatorial.factorials.RisingFactorial :members: + +stirling +-------- + +.. autofunction:: sympy.functions.combinatorial.numbers.stirling + +Enumeration +=========== + +Three functions are available. Each of them attempts to efficiently compute +a given combinatorial quantity for a given set or multiset which can be +entered as an integer, sequence or multiset (dictionary with +elements as keys and multiplicities as values). The ``k`` parameter indicates +the number of elements to pick (or the number of partitions to make). When +``k`` is None, the sum of the enumeration for all ``k`` (from 0 through the +number of items represented by ``n``) is returned. A ``replacement`` parameter +is recognized for combinations and permutations; this indicates that any item +may appear with multiplicity as high as the number of items in the original +set. + +>>> from sympy.functions.combinatorial.numbers import nC, nP, nT +>>> items = 'baby' + +nC +-- + +Calculate the number of combinations of length ``k``. + +>>> [nC(items, k) for k in range(len(items) + 1)], nC(items) +([1, 3, 4, 3, 1], 12) +>>> nC('aaa', 2) +1 +>>> nC('abc', 2) +3 +>>> nC(3, 2) +3 + +nP +-- + +Calculate the number of permutations of length ``k``. + +>>> [nP(items, k) for k in range(len(items) + 1)], nP(items) +([1, 3, 7, 12, 12], 35) +>>> nC('aaa', 2) +1 +>>> nC('abc', 2) +3 +>>> nC(3, 2) +3 + +nT +-- + +Calculate the number of partitions that have ``k`` parts. + +>>> [nT(items, k) for k in range(len(items) + 1)], nT(items) +([0, 1, 5, 4, 1], 11) +>>> nT('aaa', 2) +1 +>>> nT('abc', 2) +3 +>>> nT(3, 2) +1 + +Note that the integer for ``n`` indicates *identical* items for ``nT`` but +indicates ``n`` *different* items for ``nC`` and ``nP``. diff -Nru python3-sympy-0.7.2/doc/src/modules/functions/elementary.rst python3-sympy-0.7.3/doc/src/modules/functions/elementary.rst --- python3-sympy-0.7.2/doc/src/modules/functions/elementary.rst 2012-10-17 03:02:20.000000000 +0000 +++ python3-sympy-0.7.3/doc/src/modules/functions/elementary.rst 2013-07-13 17:53:31.000000000 +0000 @@ -1,8 +1,8 @@ Elementary ========== -This module implements elementary functions, as well as functions like Abs, -Max, etc. +This module implements elementary functions, as well as functions like ``Abs``, +``Max``, etc. Abs @@ -84,8 +84,8 @@ atan2 ----- -This function is like `atan`, but considers the sign of both arguments in -order to correctly determine the quadrant of its result. +This function is like `\operatorname{atan}`, but considers the sign of both +arguments in order to correctly determine the quadrant of its result. .. autoclass:: sympy.functions.elementary.trigonometric.atan2 :members: @@ -229,7 +229,7 @@ >>> Min(1, x) Min(1, x) -It is named Min and not min to avoid conflicts with the built-in function min. +It is named ``Min`` and not ``min`` to avoid conflicts with the built-in function ``min``. .. autoclass:: sympy.functions.elementary.miscellaneous.Min :members: @@ -240,7 +240,7 @@ Returns the maximum of two (comparable) expressions -It is named Max and not max to avoid conflicts with the built-in function max. +It is named ``Max`` and not ``max`` to avoid conflicts with the built-in function ``max``. .. autoclass:: sympy.functions.elementary.miscellaneous.Max :members: @@ -296,7 +296,7 @@ sqrt ---- -Returns the square root of an expression. It is equivalent to raise to Rational(1,2) +Returns the square root of an expression. It is equivalent to raise to ``Rational(1,2)``. >>> from sympy.functions import sqrt >>> from sympy import Rational diff -Nru python3-sympy-0.7.2/doc/src/modules/functions/index.rst python3-sympy-0.7.3/doc/src/modules/functions/index.rst --- python3-sympy-0.7.2/doc/src/modules/functions/index.rst 2012-10-17 01:53:14.000000000 +0000 +++ python3-sympy-0.7.3/doc/src/modules/functions/index.rst 2013-07-13 17:50:18.000000000 +0000 @@ -1,3 +1,5 @@ +.. _functions: + Functions Module **************** @@ -10,6 +12,8 @@ :noindex: :members: +.. _functions-contents: + Contents ======== diff -Nru python3-sympy-0.7.2/doc/src/modules/functions/special.rst python3-sympy-0.7.3/doc/src/modules/functions/special.rst --- python3-sympy-0.7.2/doc/src/modules/functions/special.rst 2012-10-17 03:02:20.000000000 +0000 +++ python3-sympy-0.7.3/doc/src/modules/functions/special.rst 2013-07-13 17:50:18.000000000 +0000 @@ -16,12 +16,6 @@ .. autofunction:: sympy.functions.special.gamma_functions.beta -erf ---- - -.. autoclass:: sympy.functions.special.error_functions.erf - :members: - Gamma and Related Functions --------------------------- .. autoclass:: sympy.functions.special.gamma_functions.gamma @@ -41,15 +35,33 @@ ----------------------------------------------- .. module:: sympy.functions.special.error_functions -.. autoclass:: erf .. autoclass:: Ei .. autoclass:: expint .. autofunction:: E1 +.. autoclass:: li +.. autoclass:: Li .. autoclass:: Si .. autoclass:: Ci .. autoclass:: Shi .. autoclass:: Chi +.. autoclass:: sympy.functions.special.error_functions.FresnelIntegral + :members: + +.. autoclass:: fresnels +.. autoclass:: fresnelc + +Error Functions +--------------- + +.. autoclass:: sympy.functions.special.error_functions.erf +.. autoclass:: sympy.functions.special.error_functions.erfc +.. autoclass:: sympy.functions.special.error_functions.erfi +.. autoclass:: sympy.functions.special.error_functions.erf2 +.. autoclass:: sympy.functions.special.error_functions.erfinv +.. autoclass:: sympy.functions.special.error_functions.erfcinv +.. autoclass:: sympy.functions.special.error_functions.erf2inv + Bessel Type Functions --------------------- @@ -58,6 +70,7 @@ .. autoclass:: sympy.functions.special.bessel.besselj .. autoclass:: sympy.functions.special.bessel.bessely +.. _besseli: .. autoclass:: sympy.functions.special.bessel.besseli .. autoclass:: sympy.functions.special.bessel.besselk .. autoclass:: sympy.functions.special.bessel.hankel1 @@ -90,6 +103,15 @@ .. autoclass:: sympy.functions.special.hyper.meijerg :members: +Elliptic integrals +------------------ +.. module:: sympy.functions.special.elliptic_integrals + +.. autoclass:: elliptic_k +.. autoclass:: elliptic_f +.. autoclass:: elliptic_e +.. autoclass:: elliptic_pi + Orthogonal Polynomials ---------------------- @@ -101,6 +123,8 @@ .. autoclass:: sympy.functions.special.polynomials.jacobi :members: +.. autofunction:: sympy.functions.special.polynomials.jacobi_normalized + Gegenbauer Polynomials ++++++++++++++++++++++ @@ -148,13 +172,11 @@ Spherical Harmonics ------------------- -.. autofunction:: sympy.functions.special.spherical_harmonics.Plmcos - -.. autofunction:: sympy.functions.special.spherical_harmonics.Ylm +.. autoclass:: sympy.functions.special.spherical_harmonics.Ynm -.. autofunction:: sympy.functions.special.spherical_harmonics.Ylm_c +.. autofunction:: sympy.functions.special.spherical_harmonics.Ynm_c -.. autofunction:: sympy.functions.special.spherical_harmonics.Zlm +.. autoclass:: sympy.functions.special.spherical_harmonics.Znm Tensor Functions ---------------- diff -Nru python3-sympy-0.7.2/doc/src/modules/galgebra/GA/BasicGAtest.py python3-sympy-0.7.3/doc/src/modules/galgebra/GA/BasicGAtest.py --- python3-sympy-0.7.2/doc/src/modules/galgebra/GA/BasicGAtest.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/doc/src/modules/galgebra/GA/BasicGAtest.py 2013-07-13 17:53:31.000000000 +0000 @@ -1,28 +1,28 @@ - a,b,c,d,e = MV.setup('a b c d e') + a, b, c, d, e = MV.setup('a b c d e') MV.set_str_format(1) - print 'e|(a^b) =',e|(a^b) - print 'e|(a^b^c) =',e|(a^b^c) - print 'a*(b^c)-b*(a^c)+c*(a^b) =',a*(b^c)-b*(a^c)+c*(a^b) - print 'e|(a^b^c^d) =',e|(a^b^c^d) - print -d*(a^b^c)+c*(a^b^d)-b*(a^c^d)+a*(b^c^d) + print 'e|(a^b) =', e | (a ^ b) + print 'e|(a^b^c) =', e | (a ^ b ^ c) + print 'a*(b^c)-b*(a^c)+c*(a^b) =', a*(b ^ c) - b*(a ^ c) + c*(a ^ b) + print 'e|(a^b^c^d) =', e | (a ^ b ^ c ^ d) + print -d*(a ^ b ^ c) + c*(a ^ b ^ d) - b*(a ^ c ^ d) + a*(b ^ c ^ d) - print (a^b)|(c^d) + print (a ^ b) | (c ^ d) -e|(a^b) = {-(b.e)}a +e | (a ^ b) = {-(b.e)}a +{(a.e)}b -e|(a^b^c) = {(c.e)}a^b -+{-(b.e)}a^c -+{(a.e)}b^c - -a*(b^c)-b*(a^c)+c*(a^b) = {3}a^b^c - -e|(a^b^c^d) = {-(d.e)}a^b^c -+{(c.e)}a^b^d -+{-(b.e)}a^c^d -+{(a.e)}b^c^d +e | (a ^ b ^ c) = {(c.e)}a ^ b ++{-(b.e)}a ^ c ++{(a.e)}b ^ c + +a*(b ^ c) - b*(a ^ c) + c*(a ^ b) = {3}a ^ b ^ c + +e | (a ^ b ^ c ^ d) = {-(d.e)}a ^ b ^ c ++{(c.e)}a ^ b ^ d ++{-(b.e)}a ^ c ^ d ++{(a.e)}b ^ c ^ d -{4}a^b^c^d +{4}a ^ b ^ c ^ d {(a.d)*(b.c) - (a.c)*(b.d)}1 diff -Nru python3-sympy-0.7.2/doc/src/modules/galgebra/GA/Dirac.py python3-sympy-0.7.3/doc/src/modules/galgebra/GA/Dirac.py --- python3-sympy-0.7.2/doc/src/modules/galgebra/GA/Dirac.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/doc/src/modules/galgebra/GA/Dirac.py 2013-07-13 17:53:31.000000000 +0000 @@ -7,20 +7,20 @@ if __name__ == '__main__': - metric = '1 0 0 0,'+\ - '0 -1 0 0,'+\ - '0 0 -1 0,'+\ + metric = '1 0 0 0,' \ + '0 -1 0 0,' \ + '0 0 -1 0,' \ '0 0 0 -1' vars = symbols('t x y z') - gamma_t,gamma_x,gamma_y,gamma_z = MV.setup('gamma_t gamma_x gamma_y gamma_z',metric,True,vars) + gamma_t, gamma_x, gamma_y, gamma_z = MV.setup('gamma_t gamma_x gamma_y gamma_z', metric, True, vars) - m,e = symbols('m e') + m, e = symbols('m e') Format('1 1 1 1') - I = MV(ONE,'pseudo') + I = MV(ONE, 'pseudo') nvars = len(vars) - psi = MV('psi','spinor',fct=True) - A = MV('A','vector',fct=True) + psi = MV('psi', 'spinor', fct=True) + A = MV('A', 'vector', fct=True) sig_x = gamma_x*gamma_t sig_y = gamma_y*gamma_t sig_z = gamma_z*gamma_t @@ -28,11 +28,11 @@ print(A) print(r'$\bm{\psi}$ is 8-component real spinor (even multi-vector)') print(psi) - dirac_eq = psi.grad()*I*sig_z-e*A*psi-m*psi*gamma_t + dirac_eq = psi.grad()*I*sig_z - e*A*psi - m*psi*gamma_t dirac_eq.simplify() - print('Dirac equation in terms of real geometric algebra/calculus '+\ + print('Dirac equation in terms of real geometric algebra/calculus ' \ r'$\lp\nabla \bm{\psi} I \sigma_{z}-eA\bm{\psi} = m\bm{\psi}\gamma_{t}\rp$') print('Spin measured with respect to $z$ axis') Format('mv=3') - print(r'\nabla \bm{\psi} I \sigma_{z}-eA\bm{\psi}-m\bm{\psi}\gamma_{t} = ',dirac_eq,' = 0') + print(r'\nabla \bm{\psi} I \sigma_{z}-eA\bm{\psi}-m\bm{\psi}\gamma_{t} = ', dirac_eq, ' = 0') xdvi(filename='Dirac.tex') diff -Nru python3-sympy-0.7.2/doc/src/modules/galgebra/GA/GAsympy.rst python3-sympy-0.7.3/doc/src/modules/galgebra/GA/GAsympy.rst --- python3-sympy-0.7.2/doc/src/modules/galgebra/GA/GAsympy.rst 2012-10-17 03:02:20.000000000 +0000 +++ python3-sympy-0.7.3/doc/src/modules/galgebra/GA/GAsympy.rst 2013-07-13 17:53:31.000000000 +0000 @@ -265,7 +265,7 @@ In our symbolic geometric algebra we assume that all multivectors of interest to us can be obtained from the symbolic basis vectors we have input, via the different operations available to geometric algebra. The first problem we have -is representing the general multivector in terms terms of the basis vectors. To +is representing the general multivector in terms of the basis vectors. To do this we form the ordered geometric products of the basis vectors and develop an internal representation of these products in terms of python classes. The ordered geometric products are all multivectors of the form @@ -1354,7 +1354,7 @@ .. function:: S(x) - :func:`S` instanciates a scaler multivector of value ``x``, where ``x`` can be a + :func:`S` instantiates a scaler multivector of value ``x``, where ``x`` can be a :mod:`sympy` variable or integer. This is just a shorthand method for constructing scalar multivectors and can be used when there is any ambiguity in a multivector expression as to whether a symbol or constant should be @@ -1431,7 +1431,7 @@ Calculus -------- -The calculus examples all use the extened LaTeXoutput module, ``latex_ex``, for +The calculus examples all use the extened LaTeX output module, ``latex_ex``, for clarity. diff -Nru python3-sympy-0.7.2/doc/src/modules/galgebra/GA/Maxwell.py python3-sympy-0.7.3/doc/src/modules/galgebra/GA/Maxwell.py --- python3-sympy-0.7.2/doc/src/modules/galgebra/GA/Maxwell.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/doc/src/modules/galgebra/GA/Maxwell.py 2013-07-13 17:53:31.000000000 +0000 @@ -5,42 +5,42 @@ if __name__ == '__main__': - metric = '1 0 0 0,'+\ - '0 -1 0 0,'+\ - '0 0 -1 0,'+\ + metric = '1 0 0 0,' \ + '0 -1 0 0,' \ + '0 0 -1 0,' \ '0 0 0 -1' vars = symbols('t x y z') - gamma_t,gamma_x,gamma_y,gamma_z = MV.setup('gamma_t gamma_x gamma_y gamma_z',metric,True,vars) - LatexPrinter.format(1,1,1,1) - I = MV(1,'pseudo') + gamma_t, gamma_x, gamma_y, gamma_z = MV.setup('gamma_t gamma_x gamma_y gamma_z', metric, True, vars) + LatexPrinter.format(1, 1, 1, 1) + I = MV(1, 'pseudo') print('$I$ Pseudo-Scalar') - print('I =',I) - B = MV('B','vector',fct=True) - E = MV('E','vector',fct=True) - B.set_coef(1,0,0) - E.set_coef(1,0,0) + print('I =', I) + B = MV('B', 'vector', fct=True) + E = MV('E', 'vector', fct=True) + B.set_coef(1, 0, 0) + E.set_coef(1, 0, 0) B *= gamma_t E *= gamma_t - J = MV('J','vector',fct=True) - F = E+I*B + J = MV('J', 'vector', fct=True) + F = E + I*B print(' ') print('$B$ Magnetic Field Bi-Vector') - print('B = Bvec gamma_0 =',B) + print('B = Bvec gamma_0 =', B) print('$F$ Electric Field Bi-Vector') - print('E = Evec gamma_0 =',E) + print('E = Evec gamma_0 =', E) print('$E+IB$ Electo-Magnetic Field Bi-Vector') - print('F = E+IB =',F) + print('F = E+IB =', F) print('$J$ Four Current') - print('J =',J) + print('J =', J) gradF = F.grad() print('Geometric Derivative of Electo-Magnetic Field Bi-Vector') MV_format(3) - print('\\nabla F =',gradF) + print('\\nabla F =', gradF) print('All Maxwell Equations are') print('\\nabla F = J') print('Div $E$ and Curl $H$ Equations') - print('<\\nabla F>_1 -J =',gradF.project(1)-J,' = 0') + print('<\\nabla F>_1 -J =', gradF.project(1) - J, ' = 0') print('Curl $E$ and Div $B$ equations') - print('<\\nabla F>_3 =',gradF.project(3),' = 0') + print('<\\nabla F>_3 =', gradF.project(3), ' = 0') xdvi(filename='Maxwell.tex') diff -Nru python3-sympy-0.7.2/doc/src/modules/galgebra/GA/conformalgeometryGAtest.py python3-sympy-0.7.3/doc/src/modules/galgebra/GA/conformalgeometryGAtest.py --- python3-sympy-0.7.2/doc/src/modules/galgebra/GA/conformalgeometryGAtest.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/doc/src/modules/galgebra/GA/conformalgeometryGAtest.py 2013-07-13 17:53:31.000000000 +0000 @@ -2,45 +2,50 @@ metric = '1 0 0 0 0,0 1 0 0 0,0 0 1 0 0,0 0 0 0 2,0 0 0 2 0' - e0,e1,e2,n,nbar = MV.setup('e0 e1 e2 n nbar',metric,debug=0) + e0, e1, e2, n, nbar = MV.setup('e0 e1 e2 n nbar', metric, debug=0) MV.set_str_format(1) - e = n+nbar + e = n + nbar #conformal representation of points - A = F(e0,n,nbar) # point a = (1,0,0) A = F(a) - B = F(e1,n,nbar) # point b = (0,1,0) B = F(b) - C = F(-1*e0,n,nbar) # point c = (-1,0,0) C = F(c) - D = F(e2,n,nbar) # point d = (0,0,1) D = F(d) - x0,x1,x2 = sympy.symbols('x0 x1 x2') - X = F(MV([x0,x1,x2],'vector'),n,nbar) + A = F(e0, n, nbar) # point a = (1,0,0) A = F(a) + B = F(e1, n, nbar) # point b = (0,1,0) B = F(b) + C = F(-1*e0, n, nbar) # point c = (-1,0,0) C = F(c) + D = F(e2, n, nbar) # point d = (0,0,1) D = F(d) + x0, x1, x2 = sympy.symbols('x0 x1 x2') + X = F(MV([x0, x1, x2], 'vector'), n, nbar) print 'a = e0, b = e1, c = -e0, and d = e2' print 'A = F(a) = 1/2*(a*a*n+2*a-nbar), etc.' print 'Circle through a, b, and c' - print 'Circle: A^B^C^X = 0 =',(A^B^C^X) + print 'Circle: A^B^C^X = 0 =', (A ^ B ^ C ^ X) print 'Line through a and b' - print 'Line : A^B^n^X = 0 =',(A^B^n^X) + print 'Line : A^B^n^X = 0 =', (A ^ B ^ n ^ X) print 'Sphere through a, b, c, and d' - print 'Sphere: A^B^C^D^X = 0 =',(A^B^C^D^X) + print 'Sphere: A^B^C^D^X = 0 =', (A ^ B ^ C ^ D ^ X) print 'Plane through a, b, and d' - print 'Plane : A^B^n^D^X = 0 =',(A^B^n^D^X) + print 'Plane : A^B^n^D^X = 0 =', (A ^ B ^ n ^ D ^ X) -Example: Conformal representations of circles, lines, spheres, and planes +Example: + Conformal representations of circles, lines, spheres, and planes a = e0, b = e1, c = -e0, and d = e2 -A = F(a) = 1/2*(a*a*n+2*a-nbar), etc. +A = F(a) = 1/2*(a*a*n + 2*a - nbar), etc. Circle through a, b, and c -Circle: A^B^C^X = 0 = {-x2}e0^e1^e2^n -+{x2}e0^e1^e2^nbar -+{-1/2 + 1/2*x0**2 + 1/2*x1**2 + 1/2*x2**2}e0^e1^n^nbar +Circle: + A ^ B ^ C ^ X = 0 = {-x2}e0 ^ e1 ^ e2 ^ n ++{x2}e0 ^ e1 ^ e2 ^ nbar ++{-1/2 + 1/2*x0**2 + 1/2*x1**2 + 1/2*x2**2}e0 ^ e1 ^ n ^ nbar Line through a and b -Line : A^B^n^X = 0 = {-x2}e0^e1^e2^n -+{-1/2 + x0/2 + x1/2}e0^e1^n^nbar -+{x2/2}e0^e2^n^nbar -+{-x2/2}e1^e2^n^nbar +Line: + A ^ B ^ n ^ X = 0 = {-x2}e0 ^ e1 ^ e2 ^ n ++{-1/2 + x0/2 + x1/2}e0 ^ e1 ^ n ^ nbar ++{x2/2}e0 ^ e2 ^ n ^ nbar ++{-x2/2}e1 ^ e2 ^ n ^ nbar Sphere through a, b, c, and d -Sphere: A^B^C^D^X = 0 = {1/2 - 1/2*x0**2 - 1/2*x1**2 - 1/2*x2**2}e0^e1^e2^n^nbar +Sphere: + A ^ B ^ C ^ D ^ X = 0 = {1/2 - 1/2*x0**2 - 1/2*x1**2 - 1/2*x2**2}e0 ^ e1 ^ e2 ^ n ^ nbar Plane through a, b, and d -Plane : A^B^n^D^X = 0 = {1/2 - x0/2 - x1/2 - x2/2}e0^e1^e2^n^nbar +Plane: + A ^ B ^ n ^ D ^ X = 0 = {1/2 - x0/2 - x1/2 - x2/2}e0 ^ e1 ^ e2 ^ n ^ nbar diff -Nru python3-sympy-0.7.2/doc/src/modules/galgebra/GA/coords.py python3-sympy-0.7.3/doc/src/modules/galgebra/GA/coords.py --- python3-sympy-0.7.2/doc/src/modules/galgebra/GA/coords.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/doc/src/modules/galgebra/GA/coords.py 2013-07-13 17:53:31.000000000 +0000 @@ -5,42 +5,44 @@ from sympy.galgebra.latex_ex import * from sympy import * -import sympy,numpy,sys +import sympy +import numpy +import sys if __name__ == '__main__': - metric = '1 0 0,'+\ - '0 1 0,'+\ + metric = '1 0 0,' +\ + '0 1 0,' +\ '0 0 1' - gamma_x,gamma_y,gamma_z = MV.setup('gamma_x gamma_y gamma_z',metric,True) + gamma_x, gamma_y, gamma_z = MV.setup('gamma_x gamma_y gamma_z', metric, True) Format('1 1 1 1') - coords = r,theta,phi = symbols('r theta phi') - x = r*(sympy.cos(theta)*gamma_z+sympy.sin(theta)*\ - (sympy.cos(phi)*gamma_x+sympy.sin(phi)*gamma_y)) + coords = r, theta, phi = symbols('r theta phi') + x = r*(sympy.cos(theta)*gamma_z + sympy.sin(theta)* + (sympy.cos(phi)*gamma_x + sympy.sin(phi)*gamma_y)) x.set_name('x') - MV.rebase(x,coords,'e',False) + MV.rebase(x, coords, 'e', False) #psi = MV.scalar_fct('psi') - psi = MV('psi','scalar',fct=True) + psi = MV('psi', 'scalar', fct=True) #psi.name = 'psi' dpsi = psi.grad() print('Gradient of Scalar Function $\\psi$') - print('\\nabla\\psi =',dpsi) + print('\\nabla\\psi =', dpsi) #A = MV.vector_fct('A') - A = MV('A','vector',fct=True) + A = MV('A', 'vector', fct=True) #A.name = 'A' print('Div and Curl of Vector Function $A$') print(A) gradA = A.grad() - I = MV(ONE,'pseudo') + I = MV(ONE, 'pseudo') divA = A.grad_int() curlA = -I*A.grad_ext() - print('\\nabla \\cdot A =',divA) + print('\\nabla \\cdot A =', divA) Format('mv=3') - print('-I\\lp\\nabla \\W A\\rp =',curlA) + print('-I\\lp\\nabla \\W A\\rp =', curlA) xdvi(filename='coords.tex') diff -Nru python3-sympy-0.7.2/doc/src/modules/galgebra/GA/headerGAtest.py python3-sympy-0.7.3/doc/src/modules/galgebra/GA/headerGAtest.py --- python3-sympy-0.7.2/doc/src/modules/galgebra/GA/headerGAtest.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/doc/src/modules/galgebra/GA/headerGAtest.py 2013-07-13 17:53:31.000000000 +0000 @@ -1,12 +1,15 @@ -import os,sys,sympy +import os +import sys +import sympy from sympy.galgebra.GA import MV, ZERO, ONE, HALF from sympy import collect, symbols + def F(x, n, nbar): """ Conformal Mapping Function """ - Fx = HALF*((x*x)*n+2*x-nbar) + Fx = HALF*((x*x)*n + 2*x - nbar) return(Fx) if __name__ == '__main__': diff -Nru python3-sympy-0.7.2/doc/src/modules/galgebra/GA/hyperbolicGAtest.py python3-sympy-0.7.3/doc/src/modules/galgebra/GA/hyperbolicGAtest.py --- python3-sympy-0.7.2/doc/src/modules/galgebra/GA/hyperbolicGAtest.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/doc/src/modules/galgebra/GA/hyperbolicGAtest.py 2013-07-13 17:53:31.000000000 +0000 @@ -1,125 +1,125 @@ - print 'Example: non-euclidian distance calculation' + print 'Example: non-euclidian distance calculation' - metric = '0 # #,# 0 #,# # 1' - X,Y,e = MV.setup('X Y e',metric) - XdotY = sympy.Symbol('(X.Y)') - Xdote = sympy.Symbol('(X.e)') - Ydote = sympy.Symbol('(Y.e)') - MV.set_str_format(1) - L = X^Y^e - B = L*e - Bsq = (B*B)() - print 'L = X^Y^e is a non-euclidian line' - print 'B = L*e =',B - BeBr =B*e*B.rev() - print 'B*e*B.rev() =',BeBr - print 'B^2 =',Bsq - print 'L^2 =',(L*L)() - s,c,Binv,M,S,C,alpha = symbols('s c Binv M S C alpha') - Bhat = Binv*B # Normalize translation generator - R = c+s*Bhat # Rotor R = exp(alpha*Bhat/2) - print 's = sinh(alpha/2) and c = cosh(alpha/2)' - print 'R = exp(alpha*B/(2*|B|)) =',R - Z = R*X*R.rev() - Z.expand() - Z.collect([Binv,s,c,XdotY]) - print 'R*X*R.rev() =',Z - W = Z|Y - W.expand() - W.collect([s*Binv]) - print '(R*X*rev(R)).Y =',W - M = 1/Bsq - W.subs(Binv**2,M) - W.simplify() - Bmag = sympy.sqrt(XdotY**2-2*XdotY*Xdote*Ydote) - W.collect([Binv*c*s,XdotY]) - - W.subs(2*XdotY**2-4*XdotY*Xdote*Ydote,2/(Binv**2)) - W.subs(2*c*s,S) - W.subs(c**2,(C+1)/2) - W.subs(s**2,(C-1)/2) - W.simplify() - W.subs(1/Binv,Bmag) - W = W().expand() - print '(R*X*R.rev()).Y =',W - nl = '\n' - - Wd = collect(W,[C,S],exact=True,evaluate=False) - print 'Wd =',Wd - Wd_1 = Wd[ONE] - Wd_C = Wd[C] - Wd_S = Wd[S] - print '|B| =',Bmag - Wd_1 = Wd_1.subs(Bmag,1/Binv) - Wd_C = Wd_C.subs(Bmag,1/Binv) - Wd_S = Wd_S.subs(Bmag,1/Binv) - print 'Wd[ONE] =',Wd_1 - print 'Wd[C] =',Wd_C - print 'Wd[S] =',Wd_S - - - lhs = Wd_1+Wd_C*C - rhs = -Wd_S*S - lhs = lhs**2 - rhs = rhs**2 - W = (lhs-rhs).expand() - W = (W.subs(1/Binv**2,Bmag**2)).expand() - print 'W =',W - W = (W.subs(S**2,C**2-1)).expand() - print 'W =',W - W = collect(W,[C,C**2],evaluate=False) - print 'W =',W - - a = W[C**2] - b = W[C] - c = W[ONE] - - print 'a =',a - print 'b =',b - print 'c =',c - - D = (b**2-4*a*c).expand() - print 'Setting to 0 and solving for C gives:' - print 'Descriminant D = b^2-4*a*c =',D - C = (-b/(2*a)).expand() - print 'C = cosh(alpha) = -b/(2*a) =',C - -Example: non-euclidian distance calculation -L = X^Y^e is a non-euclidian line -B = L*e = X^Y -+{-(Y.e)}X^e -+{(X.e)}Y^e + metric = '0 # #,# 0 #,# # 1' + X, Y, e = MV.setup('X Y e', metric) + XdotY = sympy.Symbol('(X.Y)') + Xdote = sympy.Symbol('(X.e)') + Ydote = sympy.Symbol('(Y.e)') + MV.set_str_format(1) + L = X ^ Y ^ e + B = L*e + Bsq = (B*B)() + print 'L = X^Y^e is a non-euclidian line' + print 'B = L*e =', B + BeBr = B*e*B.rev() + print 'B*e*B.rev() =', BeBr + print 'B^2 =', Bsq + print 'L^2 =', (L*L)() + s, c, Binv, M, S, C, alpha = symbols('s c Binv M S C alpha') + Bhat = Binv*B # Normalize translation generator + R = c + s*Bhat # Rotor R = exp(alpha*Bhat/2) + print 's = sinh(alpha/2) and c = cosh(alpha/2)' + print 'R = exp(alpha*B/(2*|B|)) =', R + Z = R*X*R.rev() + Z.expand() + Z.collect([Binv, s, c, XdotY]) + print 'R*X*R.rev() =', Z + W = Z | Y + W.expand() + W.collect([s*Binv]) + print '(R*X*rev(R)).Y =', W + M = 1/Bsq + W.subs(Binv**2, M) + W.simplify() + Bmag = sympy.sqrt(XdotY**2 - 2*XdotY*Xdote*Ydote) + W.collect([Binv*c*s, XdotY]) + + W.subs(2*XdotY**2 - 4*XdotY*Xdote*Ydote, 2/(Binv**2)) + W.subs(2*c*s, S) + W.subs(c**2, (C + 1)/2) + W.subs(s**2, (C - 1)/2) + W.simplify() + W.subs(1/Binv, Bmag) + W = W().expand() + print '(R*X*R.rev()).Y =', W + nl = '\n' + + Wd = collect(W, [C, S], exact=True, evaluate=False) + print 'Wd =', Wd + Wd_1 = Wd[ONE] + Wd_C = Wd[C] + Wd_S = Wd[S] + print '|B| =', Bmag + Wd_1 = Wd_1.subs(Bmag, 1/Binv) + Wd_C = Wd_C.subs(Bmag, 1/Binv) + Wd_S = Wd_S.subs(Bmag, 1/Binv) + print 'Wd[ONE] =', Wd_1 + print 'Wd[C] =', Wd_C + print 'Wd[S] =', Wd_S + + lhs = Wd_1 + Wd_C*C + rhs = -Wd_S*S + lhs = lhs**2 + rhs = rhs**2 + W = (lhs - rhs).expand() + W = (W.subs(1/Binv**2, Bmag**2)).expand() + print 'W =', W + W = (W.subs(S**2, C**2 - 1)).expand() + print 'W =', W + W = collect(W, [C, C**2], evaluate=False) + print 'W =', W + + a = W[C**2] + b = W[C] + c = W[ONE] + + print 'a =', a + print 'b =', b + print 'c =', c + + D = (b**2 - 4*a*c).expand() + print 'Setting to 0 and solving for C gives:' + print 'Descriminant D = b^2-4*a*c =', D + C = (-b/(2*a)).expand() + print 'C = cosh(alpha) = -b/(2*a) =', C + +Example: + non - euclidian distance calculation +L = X ^ Y ^ e is a non - euclidian line +B = L*e = X ^ Y ++{-(Y.e)}X ^ e ++{(X.e)}Y ^ e B*e*B.rev() = {2*(X.Y)*(X.e)*(Y.e) - (X.Y)**2}e -B^2 = -2*(X.Y)*(X.e)*(Y.e) + (X.Y)**2 -L^2 = -2*(X.Y)*(X.e)*(Y.e) + (X.Y)**2 +B ^ 2 = -2*(X.Y)*(X.e)*(Y.e) + (X.Y)**2 +L ^ 2 = -2*(X.Y)*(X.e)*(Y.e) + (X.Y)**2 s = sinh(alpha/2) and c = cosh(alpha/2) -R = exp(alpha*B/(2*|B|)) = {c}1 -+{Binv*s}X^Y -+{-(Y.e)*Binv*s}X^e -+{(X.e)*Binv*s}Y^e +R = exp(alpha*B/(2* | B | )) = {c}1 ++{Binv*s}X ^ Y ++{-(Y.e)*Binv*s}X ^ e ++{(X.e)*Binv*s}Y ^ e R*X*R.rev() = {Binv*(2*(X.Y)*c*s - 2*(X.e)*(Y.e)*c*s) + Binv**2*((X.Y)**2*s**2 - 2*(X.Y)*(X.e)*(Y.e)*s**2) + c**2}X - +{2*Binv*c*s*(X.e)**2}Y - +{Binv**2*(-2*(X.e)*(X.Y)**2*s**2 + 4*(X.Y)*(Y.e)*(X.e)**2*s**2) - - 2*(X.Y)*(X.e)*Binv*c*s}e + +{2*Binv*c*s*(X.e)**2}Y + +{Binv**2*(-2*(X.e)*(X.Y)**2*s**2 + 4*(X.Y)*(Y.e)*(X.e)**2*s**2) + - 2*(X.Y)*(X.e)*Binv*c*s}e (R*X*rev(R)).Y = {Binv*s*(-4*(X.Y)*(X.e)*(Y.e)*c + 2*c*(X.Y)**2) + Binv**2*s**2*(-4*(X.e)*(Y.e)*(X.Y)**2 + 4*(X.Y)*(X.e)**2*(Y.e)**2 + (X.Y)**3) + (X.Y)*c**2}1 (R*X*R.rev()).Y = S*(-2*(X.Y)*(X.e)*(Y.e) + (X.Y)**2)**(1/2) - + (X.Y)*Binv*C*(-2*(X.Y)*(X.e)*(Y.e) + - (X.Y)**2)**(1/2) + (X.e)*(Y.e)*Binv*(-2*(X.Y)*(X.e)*(Y.e) - + (X.Y)**2)**(1/2) - - (X.e)*(Y.e)*Binv*C*(-2*(X.Y)*(X.e)*(Y.e) + (X.Y)**2)**(1/2) + + (X.Y)*Binv*C*(-2*(X.Y)*(X.e)*(Y.e) + + (X.Y)**2)**(1/2) + (X.e)*(Y.e)*Binv*(-2*(X.Y)*(X.e)*(Y.e) + + (X.Y)**2)**(1/2) - + (X.e)*(Y.e)*Binv*C*(-2*(X.Y)*(X.e)*(Y.e) + (X.Y)**2)**(1/2) Wd = {1: (X.e)*(Y.e)*Binv*(-2*(X.Y)*(X.e)*(Y.e) + (X.Y)**2)**(1/2), S: (-2*(X.Y)*(X.e)*(Y.e) + (X.Y)**2)**(1/2), C: (X.Y)*Binv*(-2*(X.Y)*(X.e)*(Y.e) + (X.Y)**2)**(1/2) - (X.e)*(Y.e)*Binv*(-2*(X.Y)*(X.e)*(Y.e) + (X.Y)**2)**(1/2)} -|B| = (-2*(X.Y)*(X.e)*(Y.e) + (X.Y)**2)**(1/2) +|B | = (-2*(X.Y)*(X.e)*(Y.e) + (X.Y)**2)**(1/2) Wd[ONE] = (X.e)*(Y.e) Wd[C] = (X.Y) - (X.e)*(Y.e) @@ -130,7 +130,7 @@ - 2*(X.Y)*(X.e)*(Y.e)*C**2 + 2*(X.Y)*(X.e)*(Y.e)*S**2 W = -2*(X.Y)*(X.e)*(Y.e) + 2*(X.Y)*(X.e)*(Y.e)*C + (X.Y)**2 + (X.e)**2*(Y.e)**2 + (X.e)**2*(Y.e)**2*C**2 - - 2*C*(X.e)**2*(Y.e)**2 + 2*C*(X.e)**2*(Y.e)**2 W = {1: -2*(X.Y)*(X.e)*(Y.e) + (X.Y)**2 + (X.e)**2*(Y.e)**2, C**2: (X.e)**2*(Y.e)**2, C: 2*(X.Y)*(X.e)*(Y.e) - 2*(X.e)**2*(Y.e)**2} @@ -140,5 +140,5 @@ c = -2*(X.Y)*(X.e)*(Y.e) + (X.Y)**2 + (X.e)**2*(Y.e)**2 Setting to 0 and solving for C gives: -Descriminant D = b^2-4*a*c = 0 +Descriminant D = b ^ 2 - 4*a*c = 0 C = cosh(alpha) = -b/(2*a) = 1 - (X.Y)/((X.e)*(Y.e)) diff -Nru python3-sympy-0.7.2/doc/src/modules/galgebra/GA/reciprocalframeGAtest.py python3-sympy-0.7.3/doc/src/modules/galgebra/GA/reciprocalframeGAtest.py --- python3-sympy-0.7.2/doc/src/modules/galgebra/GA/reciprocalframeGAtest.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/doc/src/modules/galgebra/GA/reciprocalframeGAtest.py 2013-07-13 17:53:31.000000000 +0000 @@ -1,78 +1,79 @@ - e1,e2,e3 = MV.setup('e1 e2 e3') + e1, e2, e3 = MV.setup('e1 e2 e3') print 'Example: Reciprocal Frames e1, e2, and e3 unit vectors.\n\n' - E = e1^e2^e3 + E = e1 ^ e2 ^ e3 Esq = (E*E)() - print 'E =',E - print 'E^2 =',Esq + print 'E =', E + print 'E^2 =', Esq Esq_inv = 1/Esq - E1 = (e2^e3)*E - E2 = (-1)*(e1^e3)*E - E3 = (e1^e2)*E + E1 = (e2 ^ e3)*E + E2 = (-1)*(e1 ^ e3)*E + E3 = (e1 ^ e2)*E - print 'E1 = (e2^e3)*E =',E1 - print 'E2 =-(e1^e3)*E =',E2 - print 'E3 = (e1^e2)*E =',E3 + print 'E1 = (e2^e3)*E =', E1 + print 'E2 =-(e1^e3)*E =', E2 + print 'E3 = (e1^e2)*E =', E3 - w = (E1|e2) + w = (E1 | e2) w.collect(MV.g) w = w().expand() - print 'E1|e2 =',w + print 'E1|e2 =', w - w = (E1|e3) + w = (E1 | e3) w.collect(MV.g) w = w().expand() - print 'E1|e3 =',w + print 'E1|e3 =', w - w = (E2|e1) + w = (E2 | e1) w.collect(MV.g) w = w().expand() - print 'E2|e1 =',w + print 'E2|e1 =', w - w = (E2|e3) + w = (E2 | e3) w.collect(MV.g) w = w().expand() - print 'E2|e3 =',w + print 'E2|e3 =', w - w = (E3|e1) + w = (E3 | e1) w.collect(MV.g) w = w().expand() - print 'E3|e1 =',w + print 'E3|e1 =', w - w = (E3|e2) + w = (E3 | e2) w.collect(MV.g) w = w().expand() - print 'E3|e2 =',w + print 'E3|e2 =', w - w = (E1|e1) + w = (E1 | e1) w = w().expand() Esq = Esq.expand() - print '(E1|e1)/E^2 =',w/Esq + print '(E1|e1)/E^2 =', w/Esq - w = (E2|e2) + w = (E2 | e2) w = w().expand() - print '(E2|e2)/E^2 =',w/Esq + print '(E2|e2)/E^2 =', w/Esq - w = (E3|e3) + w = (E3 | e3) w = w().expand() - print '(E3|e3)/E^2 =',w/Esq - -Example: Reciprocal Frames e1, e2, and e3 unit vectors. - - -E = e1^e2^e3 -E^2 = -1 - 2*(e1.e2)*(e1.e3)*(e2.e3) + (e1.e2)**2 + (e1.e3)**2 + (e2.e3)**2 -E1 = (e2^e3)*E = {-1 + (e2.e3)**2}e1+{(e1.e2) - (e1.e3)*(e2.e3)}e2+{(e1.e3) - (e1.e2)*(e2.e3)}e3 -E2 =-(e1^e3)*E = {(e1.e2) - (e1.e3)*(e2.e3)}e1+{-1 + (e1.e3)**2}e2+{(e2.e3) - (e1.e2)*(e1.e3)}e3 -E3 = (e1^e2)*E = {(e1.e3) - (e1.e2)*(e2.e3)}e1+{(e2.e3) - (e1.e2)*(e1.e3)}e2+{-1 + (e1.e2)**2}e3 -E1|e2 = 0 -E1|e3 = 0 -E2|e1 = 0 -E2|e3 = 0 -E3|e1 = 0 -E3|e2 = 0 -(E1|e1)/E^2 = 1 -(E2|e2)/E^2 = 1 -(E3|e3)/E^2 = 1 + print '(E3|e3)/E^2 =', w/Esq + +Example: + Reciprocal Frames e1, e2, and e3 unit vectors. + + +E = e1 ^ e2 ^ e3 +E ^ 2 = -1 - 2*(e1.e2)*(e1.e3)*(e2.e3) + (e1.e2)**2 + (e1.e3)**2 + (e2.e3)**2 +E1 = (e2 ^ e3)*E = {-1 + (e2.e3)**2}e1 + {(e1.e2) - (e1.e3)*(e2.e3)}e2 + {(e1.e3) - (e1.e2)*(e2.e3)}e3 +E2 = -(e1 ^ e3)*E = {(e1.e2) - (e1.e3)*(e2.e3)}e1 + {-1 + (e1.e3)**2}e2 + {(e2.e3) - (e1.e2)*(e1.e3)}e3 +E3 = (e1 ^ e2)*E = {(e1.e3) - (e1.e2)*(e2.e3)}e1 + {(e2.e3) - (e1.e2)*(e1.e3)}e2 + {-1 + (e1.e2)**2}e3 +E1 | e2 = 0 +E1 | e3 = 0 +E2 | e1 = 0 +E2 | e3 = 0 +E3 | e1 = 0 +E3 | e2 = 0 +(E1 | e1)/E ^ 2 = 1 +(E2 | e2)/E ^ 2 = 1 +(E3 | e3)/E ^ 2 = 1 diff -Nru python3-sympy-0.7.2/doc/src/modules/galgebra/index.rst python3-sympy-0.7.3/doc/src/modules/galgebra/index.rst --- python3-sympy-0.7.2/doc/src/modules/galgebra/index.rst 2012-10-17 01:53:14.000000000 +0000 +++ python3-sympy-0.7.3/doc/src/modules/galgebra/index.rst 2013-07-13 17:50:18.000000000 +0000 @@ -1,10 +1,10 @@ -================================== -Geometric Algebra Module Docstring -================================== +======================== +Geometric Algebra Module +======================== .. automodule: sympy.galgebra -Documentation for Geometric Algebra module +Documentation for Geometric Algebra module. Contents: diff -Nru python3-sympy-0.7.2/doc/src/modules/galgebra/latex_ex/Maxwell.py python3-sympy-0.7.3/doc/src/modules/galgebra/latex_ex/Maxwell.py --- python3-sympy-0.7.2/doc/src/modules/galgebra/latex_ex/Maxwell.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/doc/src/modules/galgebra/latex_ex/Maxwell.py 2013-07-13 17:53:31.000000000 +0000 @@ -1,48 +1,49 @@ -import sys, sympy +import sys +import sympy import sympy.galgebra.GAsympy as GA import sympy.galgebra.latex_ex as tex if __name__ == '__main__': - metric = '1 0 0 0,'+\ - '0 -1 0 0,'+\ - '0 0 -1 0,'+\ + metric = '1 0 0 0,' \ + '0 -1 0 0,' \ + '0 0 -1 0,' \ '0 0 0 -1' vars = sympy.symbols('t x y z') - gamma_t,gamma_x,gamma_y,gamma_z = GA.MV.setup('gamma_t gamma_x gamma_y gamma_z',metric,True,vars) + gamma_t, gamma_x, gamma_y, gamma_z = GA.MV.setup('gamma_t gamma_x gamma_y gamma_z', metric, True, vars) tex.Format() - I = GA.MV(1,'pseudo') + I = GA.MV(1, 'pseudo') I.convert_to_blades() print('$I$ Pseudo-Scalar') - print('I =',I) - B = GA.MV('B','vector',fct=True) - E = GA.MV('E','vector',fct=True) - B.set_coef(1,0,0) - E.set_coef(1,0,0) + print('I =', I) + B = GA.MV('B', 'vector', fct=True) + E = GA.MV('E', 'vector', fct=True) + B.set_coef(1, 0, 0) + E.set_coef(1, 0, 0) B *= gamma_t E *= gamma_t B.convert_to_blades() E.convert_to_blades() - J = GA.MV('J','vector',fct=True) + J = GA.MV('J', 'vector', fct=True) print('$B$ Magnetic Field Bi-Vector') - print('B = Bvec gamma_0 =',B) + print('B = Bvec gamma_0 =', B) print('$E$ Electric Field Bi-Vector') - print('E = Evec gamma_0 =',E) - F = E+I*B + print('E = Evec gamma_0 =', E) + F = E + I*B print('$E+IB$ Electo-Magnetic Field Bi-Vector') - print('F = E+IB =',F) + print('F = E+IB =', F) print('$J$ Four Current') - print('J =',J) + print('J =', J) gradF = F.grad() gradF.convert_to_blades() print('Geometric Derivative of Electo-Magnetic Field Bi-Vector') tex.MV_format(3) - print('\\nabla F =',gradF) + print('\\nabla F =', gradF) print('All Maxwell Equations are') print('\\nabla F = J') print('Div $E$ and Curl $H$ Equations') - print('<\\nabla F>_1 -J =',gradF.project(1)-J,' = 0') + print('<\\nabla F>_1 -J =', gradF.project(1) - J, ' = 0') print('Curl $E$ and Div $B$ equations') - print('<\\nabla F>_3 =',gradF.project(3),' = 0') + print('<\\nabla F>_3 =', gradF.project(3), ' = 0') tex.xdvi(filename='Maxwell.tex') diff -Nru python3-sympy-0.7.2/doc/src/modules/galgebra/latex_ex/latexdemo.py python3-sympy-0.7.3/doc/src/modules/galgebra/latex_ex/latexdemo.py --- python3-sympy-0.7.2/doc/src/modules/galgebra/latex_ex/latexdemo.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/doc/src/modules/galgebra/latex_ex/latexdemo.py 2013-07-13 17:53:31.000000000 +0000 @@ -1,13 +1,14 @@ -import sys, sympy +import sys +import sympy import sympy.galgebra.latex_ex as tex if __name__ == '__main__': tex.Format() - xbm,alpha_1,delta__nugamma_r = sympy.symbols('xbm alpha_1 delta__nugamma_r') + xbm, alpha_1, delta__nugamma_r = sympy.symbols('xbm alpha_1 delta__nugamma_r') x = alpha_1*xbm/delta__nugamma_r - print('x =',x) + print('x =', x) tex.xdvi() diff -Nru python3-sympy-0.7.2/doc/src/modules/geometry.rst python3-sympy-0.7.3/doc/src/modules/geometry.rst --- python3-sympy-0.7.2/doc/src/modules/geometry.rst 2012-10-17 03:02:17.000000000 +0000 +++ python3-sympy-0.7.3/doc/src/modules/geometry.rst 2013-07-13 17:53:31.000000000 +0000 @@ -7,7 +7,7 @@ ------------ The geometry module for SymPy allows one to create two-dimensional geometrical -entities, such as lines and circles, and query information about these +entities, such as lines and circles, and query for information about these entities. This could include asking the area of an ellipse, checking for collinearity of a set of points, or finding the intersection between two lines. The primary use case of the module involves entities with numerical values, but @@ -18,17 +18,17 @@ The following entities are currently available in the geometry module: -* Point -* Line, Ray, Segment -* Ellipse, Circle -* Polygon, RegularPolygon, Triangle +* ``Point`` +* ``Line``, ``Ray``, ``Segment`` +* ``Ellipse``, ``Circle`` +* ``Polygon``, ``RegularPolygon``, ``Triangle`` Most of the work one will do will be through the properties and methods of -these entities, but several global methods exist for one's usage: +these entities, but several global methods exist: -* intersection(entity1, entity2) -* are_similar(entity1, entity2) -* convex_hull(points) +* ``intersection(entity1, entity2)`` +* ``are_similar(entity1, entity2)`` +* ``convex_hull(points)`` For a full API listing and an explanation of the methods and their return values please see the list of classes at the end of this document. @@ -92,8 +92,15 @@ >>> intersection(t.medians[x], t.medians[y], t.medians[z]) [Point(a, b/3)] -An in-depth example: Pappus' Theorem ------------------------------------- +An in-depth example: Pappus' Hexagon Theorem +-------------------------------------------- + +From Wikipedia ([WikiPappus]_): + + Given one set of collinear points `A`, `B`, `C`, and another set of collinear + points `a`, `b`, `c`, then the intersection points `X`, `Y`, `Z` of line pairs `Ab` and + `aB`, `Ac` and `aC`, `Bc` and `bC` are collinear. + :: >>> from sympy import * @@ -130,19 +137,26 @@ >>> Point.is_collinear(pp1, pp2, pp3) True +References +~~~~~~~~~~ + +.. [WikiPappus] "Pappus's Hexagon Theorem" Wikipedia, the Free Encyclopedia. + Web. 26 Apr. 2013. + + Miscellaneous Notes ------------------- -* The area property of Polygon and Triangle may return a positive or +* The area property of ``Polygon`` and ``Triangle`` may return a positive or negative value, depending on whether or not the points are oriented counter-clockwise or clockwise, respectively. If you always want a positive value be sure to use the ``abs`` function. -* Although Polygon can refer to any type of polygon, the code has been +* Although ``Polygon`` can refer to any type of polygon, the code has been written for simple polygons. Hence, expect potential problems if dealing with complex polygons (overlapping sides). -* Since !SymPy is still in its infancy some things may not simplify - properly and hence some things that should return True (e.g., - Point.is_collinear) may not actually do so. Similarly, attempting to find +* Since SymPy is still in its infancy some things may not simplify + properly and hence some things that should return ``True`` (e.g., + ``Point.is_collinear``) may not actually do so. Similarly, attempting to find the intersection of entities that do intersect may result in an empty result. diff -Nru python3-sympy-0.7.2/doc/src/modules/index.rst python3-sympy-0.7.3/doc/src/modules/index.rst --- python3-sympy-0.7.2/doc/src/modules/index.rst 2012-10-17 02:30:33.000000000 +0000 +++ python3-sympy-0.7.3/doc/src/modules/index.rst 2013-07-13 17:50:18.000000000 +0000 @@ -28,10 +28,8 @@ galgebra/latex_ex/latex_ex.rst integrals/integrals.rst logic.rst - matrices/matrices.rst - matrices/expressions.rst - matrices/immutablematrices.rst - mpmath/index.rst + matrices/index.rst + Mpmath polys/index.rst printing.rst plotting.rst @@ -44,6 +42,7 @@ statistics.rst stats.rst solvers/ode.rst + solvers/pde.rst solvers/solvers.rst tensor/index.rst utilities/index.rst diff -Nru python3-sympy-0.7.2/doc/src/modules/integrals/g-functions.rst python3-sympy-0.7.3/doc/src/modules/integrals/g-functions.rst --- python3-sympy-0.7.2/doc/src/modules/integrals/g-functions.rst 2012-10-17 03:02:20.000000000 +0000 +++ python3-sympy-0.7.3/doc/src/modules/integrals/g-functions.rst 2013-07-13 17:53:31.000000000 +0000 @@ -41,24 +41,24 @@ and a complex structure. This Riemann Surface is usually referred to as the Riemann Surface of the logarithm, for the following reason: We can define maps -`Exp: \mathbb{C} \rightarrow \mathcal{S}, Exp(x + i y) = (exp(x), y)` and -`Log: \mathcal{S} \rightarrow \mathbb{C}, (e^x, y) \mapsto x + iy`. -These can be shown to be both holomorphic, and are indeed mutual inverses. +`\operatorname{Exp}: \mathbb{C} \rightarrow \mathcal{S}, (x + i y) \mapsto (\exp(x), y)` and +`\operatorname{Log}: \mathcal{S} \rightarrow \mathbb{C}, (e^x, y) \mapsto x + iy`. +These can both be shown to be holomorphic, and are indeed mutual inverses. -We also sometimes formally attach a point "zero" to `\mathcal{S}` and denote the +We also sometimes formally attach a point "zero" (`0`) to `\mathcal{S}` and denote the resulting object `\mathcal{S}_0`. Notably there is no complex structure defined near `0`. A fundamental system of neighbourhoods is given by -`\{Exp(z) : Re(z) < k\}`, this at least defines a topology. Elements of +`\{\operatorname{Exp}(z) : \Re(z) < k\}`, which at least defines a topology. Elements of `\mathcal{S}_0` shall be called polar numbers. We further define functions -`Arg: \mathcal{S} \rightarrow \mathbb{R}, (r, \theta) \mapsto \theta` and +`\operatorname{Arg}: \mathcal{S} \rightarrow \mathbb{R}, (r, \theta) \mapsto \theta` and `|.|: \mathcal{S}_0 \rightarrow \mathbb{R}_{>0}, (r, \theta) \mapsto r`. These have evident meaning and are both continuous everywhere. Using these maps many operations can be extended from `\mathbb{C}` to -`\mathcal{S}`. We define `Exp(a) Exp(b) = Exp(a + b)` for `a, b \in \mathbb{C}`, +`\mathcal{S}`. We define `\operatorname{Exp}(a) \operatorname{Exp}(b) = \operatorname{Exp}(a + b)` for `a, b \in \mathbb{C}`, also for `a \in \mathcal{S}` and `b \in \mathbb{C}` we define -`a^b = Exp(b Log(a))`. +`a^b = \operatorname{Exp}(b \operatorname{Log}(a))`. It can be checked easily that using these definitions, many algebraic properties holding for positive reals (e.g. `(ab)^c = a^c b^c`) which hold in `\mathbb{C}` only for some numbers (because of branch cuts) hold indeed for all polar numbers. @@ -74,7 +74,7 @@ .. math:: F(z) = \begin{cases} S(p(z)) &: |z| < 1 \\ - S(p(z)) &: -\pi < Arg(z) + 4\pi n \le \pi \text{ for some } n \in \mathbb{Z} \\ + S(p(z)) &: -\pi < \operatorname{Arg}(z) + 4\pi n \le \pi \text{ for some } n \in \mathbb{Z} \\ -S(p(z)) &: \text{else} \end{cases}. @@ -91,7 +91,7 @@ (which is adhered to in all of SymPy), as follows: Introduce the "cut complex plane" `C = \mathbb{C} \setminus \mathbb{R}_{\le 0}`. Define a function -`l: C \to \mathcal{S}` via `re^{i\theta} \mapsto r Exp(i\theta)`. Here `r > 0` +`l: C \to \mathcal{S}` via `re^{i\theta} \mapsto r \operatorname{Exp}(i\theta)`. Here `r > 0` and `-\pi < \theta \le \pi`. Then `l` is holomorphic, and we define `G = f \circ l`. This called "lifting to the principal branch" throughout the SymPy documentation. @@ -155,7 +155,7 @@ Sometimes this can be remedied by reducing the argument of the G-functions involved. For example it is clear that the G-function representing `e^z` -is satisfies `G(Exp(2 \pi i)z) = G(z)` for all `z \in \mathcal{S}`. The function +is satisfies `G(\operatorname{Exp}(2 \pi i)z) = G(z)` for all `z \in \mathcal{S}`. The function ``meijerg.get_period()`` can be used to discover this, and the function ``principal_branch(z, period)`` in ``functions/elementary/complexes.py`` can be used to exploit the information. This is done transparently by the @@ -452,7 +452,7 @@ the newly obtained gamma function must be separated properly. It is easy to check that the inner integal converges absolutely for -`Re(as) < -1`. Thus the contour `L` has to run left of the line `Re(as) = -1`. +`\Re(as) < -1`. Thus the contour `L` has to run left of the line `\Re(as) = -1`. Under this condition, the poles of the newly-introduced gamma function are separated properly. @@ -483,14 +483,14 @@ multiplicative constant"). Also `z^{x + iy} \sim |\tau|^x e^{i y \log{|\tau|}} e^{\pm x i \frac{\pi}{2}}.` -Set `\omega_{\pm} = b e^{\pm i Re(c) \frac{\pi}{2}}`. We have three cases: +Set `\omega_{\pm} = b e^{\pm i \Re(c) \frac{\pi}{2}}`. We have three cases: -1. `b=0` or `Re(c) \le 0`. - In this case the integral converges if `Re(a) \le -1`. -2. `b \ne 0`, `Im(c) = 0`, `Re(c) > 0`. - In this case the integral converges if `Re(\omega_{\pm}) < 0`. -3. `b \ne 0`, `Im(c) = 0`, `Re(c) > 0`, `Re(\omega_{\pm}) \le 0`, and at least - one of `Re(\omega_{\pm}) = 0`. +1. `b=0` or `\Re(c) \le 0`. + In this case the integral converges if `\Re(a) \le -1`. +2. `b \ne 0`, `\Im(c) = 0`, `\Re(c) > 0`. + In this case the integral converges if `\Re(\omega_{\pm}) < 0`. +3. `b \ne 0`, `\Im(c) = 0`, `\Re(c) > 0`, `\Re(\omega_{\pm}) \le 0`, and at least + one of `\Re(\omega_{\pm}) = 0`. Here the same condition as in (1) applies. Implemented G-Function Formulae diff -Nru python3-sympy-0.7.2/doc/src/modules/integrals/integrals.rst python3-sympy-0.7.3/doc/src/modules/integrals/integrals.rst --- python3-sympy-0.7.2/doc/src/modules/integrals/integrals.rst 2012-10-17 01:53:14.000000000 +0000 +++ python3-sympy-0.7.3/doc/src/modules/integrals/integrals.rst 2013-07-13 17:50:18.000000000 +0000 @@ -1,14 +1,14 @@ -Integrals -========== +Symbolic Integrals +================== .. module:: sympy.integrals -The *integrals* module in SymPy implements methods to calculate definite and indefinite integrals of expressions. +The ``integrals`` module in SymPy implements methods to calculate definite and indefinite integrals of expressions. -Principal method in this module is integrate() +Principal method in this module is :func:`integrate` - - integrate(f, x) returns the indefinite integral :math:`\int f\,dx` - - integrate(f, (x, a, b)) returns the definite integral :math:`\int_{a}^{b} f\,dx` + - ``integrate(f, x)`` returns the indefinite integral :math:`\int f\,dx` + - ``integrate(f, (x, a, b))`` returns the definite integral :math:`\int_{a}^{b} f\,dx` Examples -------- @@ -31,7 +31,7 @@ x + 1 -Exponential-polynomial functions. Multiplicative combinations of polynomials and the functions exp, cos and sin can be integrated by hand using repeated integration by parts, which is an extremely tedious process. Happily, SymPy will deal with these integrals. +Exponential-polynomial functions. These multiplicative combinations of polynomials and the functions ``exp``, ``cos`` and ``sin`` can be integrated by hand using repeated integration by parts, which is an extremely tedious process. Happily, SymPy will deal with these integrals. :: @@ -76,11 +76,11 @@ Internals --------- -There is a general method for calculating antiderivatives of elementary functions, called the Risch algorithm. The Risch algorithm is a decision procedure that can determine whether an elementary solution exists, and in that case calculate it. It can be extended to handle many nonelementary functions in addition to the elementary ones. +There is a general method for calculating antiderivatives of elementary functions, called the *Risch algorithm*. The Risch algorithm is a decision procedure that can determine whether an elementary solution exists, and in that case calculate it. It can be extended to handle many nonelementary functions in addition to the elementary ones. -SymPy currently uses a simplified version of the Risch algorithm, called the Risch-Norman algorithm. This algorithm is much faster, but may fail to find an antiderivative, although it is still very powerful. SymPy also uses pattern matching and heuristics to speed up evaluation of some types of integrals, e.g. polynomials. +SymPy currently uses a simplified version of the Risch algorithm, called the *Risch-Norman algorithm*. This algorithm is much faster, but may fail to find an antiderivative, although it is still very powerful. SymPy also uses pattern matching and heuristics to speed up evaluation of some types of integrals, e.g. polynomials. -For non-elementary definite integrals, sympy uses so-called Meijer G-functions. +For non-elementary definite integrals, SymPy uses so-called Meijer G-functions. Details are described here: .. toctree:: @@ -101,9 +101,13 @@ .. automethod:: sympy.integrals.heurisch +.. automethod:: sympy.integrals.heurisch_wrapper + .. automethod:: sympy.integrals.trigintegrate -Class Integral represents an unevaluated integral and has some methods that help in the integration of an expression. +.. automethod:: sympy.integrals.manualintegrate + +The class `Integral` represents an unevaluated integral and has some methods that help in the integration of an expression. .. autoclass:: sympy.integrals.Integral :members: @@ -114,4 +118,24 @@ TODO and Bugs ------------- -There are still lots of functions that sympy does not know how to integrate. For bugs related to this module, see http://code.google.com/p/sympy/issues/list?q=label:Integration +There are still lots of functions that SymPy does not know how to integrate. For bugs related to this module, see http://code.google.com/p/sympy/issues/list?q=label:Integration + +Numeric Integrals +================= + +SymPy has functions to calculate points and weights for Gaussian quadrature of +any order and any precision: + +.. autofunction:: sympy.integrals.quadrature.gauss_legendre + +.. autofunction:: sympy.integrals.quadrature.gauss_laguerre + +.. autofunction:: sympy.integrals.quadrature.gauss_hermite + +.. autofunction:: sympy.integrals.quadrature.gauss_gen_laguerre + +.. autofunction:: sympy.integrals.quadrature.gauss_chebyshev_t + +.. autofunction:: sympy.integrals.quadrature.gauss_chebyshev_u + +.. autofunction:: sympy.integrals.quadrature.gauss_jacobi diff -Nru python3-sympy-0.7.2/doc/src/modules/logic.rst python3-sympy-0.7.3/doc/src/modules/logic.rst --- python3-sympy-0.7.2/doc/src/modules/logic.rst 2012-10-17 01:53:14.000000000 +0000 +++ python3-sympy-0.7.3/doc/src/modules/logic.rst 2013-07-13 17:50:18.000000000 +0000 @@ -7,12 +7,12 @@ ------------ The logic module for SymPy allows to form and manipulate logic expressions -using symbolic and boolean values. +using symbolic and Boolean values. Forming logical expressions --------------------------- -You can build boolean expressions with the standard python operators ``&`` +You can build Boolean expressions with the standard python operators ``&`` (:class:`And`), ``|`` (:class:`Or`), ``~`` (:class:`Not`):: >>> from sympy import * @@ -68,12 +68,13 @@ This module implements some inference routines in propositional logic. -The function satisfiable will test that a given boolean expression is satisfiable, -that is, you can assign values to the variables to make the sentence True. +The function satisfiable will test that a given Boolean expression is satisfiable, +that is, you can assign values to the variables to make the sentence `True`. -For example, the expression x & ~x is not satisfiable, since there are no values -for x that make this sentence True. On the other hand, (x | y) & (x | ~y) & (~x | y) -is satisfiable with both x and y being True. +For example, the expression ``x & ~x`` is not satisfiable, since there are no +values for ``x`` that make this sentence ``True``. On the other hand, ``(x +| y) & (x | ~y) & (~x | y)`` is satisfiable with both ``x`` and ``y`` being +``True``. >>> from sympy.logic.inference import satisfiable >>> from sympy import Symbol @@ -85,7 +86,7 @@ {x: True, y: True} As you see, when a sentence is satisfiable, it returns a model that makes that -sentence True. If it is not satisfiable it will return False +sentence ``True``. If it is not satisfiable it will return ``False``. .. autofunction:: sympy.logic.inference.satisfiable diff -Nru python3-sympy-0.7.2/doc/src/modules/matrices/dense.rst python3-sympy-0.7.3/doc/src/modules/matrices/dense.rst --- python3-sympy-0.7.2/doc/src/modules/matrices/dense.rst 1970-01-01 00:00:00.000000000 +0000 +++ python3-sympy-0.7.3/doc/src/modules/matrices/dense.rst 2013-07-13 17:50:18.000000000 +0000 @@ -0,0 +1,15 @@ +Dense Matrices +============== + +Matrix Class Reference +---------------------- + +.. autoclass:: sympy.matrices.dense.MutableDenseMatrix + :members: + +ImmutableMatrix Class Reference +------------------------------- + +.. autoclass:: sympy.matrices.immutable.ImmutableMatrix + :members: + :noindex: diff -Nru python3-sympy-0.7.2/doc/src/modules/matrices/expressions.rst python3-sympy-0.7.3/doc/src/modules/matrices/expressions.rst --- python3-sympy-0.7.2/doc/src/modules/matrices/expressions.rst 2012-10-17 03:02:20.000000000 +0000 +++ python3-sympy-0.7.3/doc/src/modules/matrices/expressions.rst 2013-07-13 17:50:18.000000000 +0000 @@ -12,12 +12,13 @@ X^-1*X'^-1*Y >>> Matrix(X) - [X_00, X_01, X_02] - [X_10, X_11, X_12] - [X_20, X_21, X_22] + Matrix([ + [X[0, 0], X[0, 1], X[0, 2]], + [X[1, 0], X[1, 1], X[1, 2]], + [X[2, 0], X[2, 1], X[2, 2]]]) >>> (X*Y)[1, 2] - X_10*Y_02 + X_11*Y_12 + X_12*Y_22 + X[1, 0]*Y[0, 2] + X[1, 1]*Y[1, 2] + X[1, 2]*Y[2, 2] where ``X`` and ``Y`` are :class:`MatrixSymbol`'s rather than scalar symbols. diff -Nru python3-sympy-0.7.2/doc/src/modules/matrices/immutablematrices.rst python3-sympy-0.7.3/doc/src/modules/matrices/immutablematrices.rst --- python3-sympy-0.7.2/doc/src/modules/matrices/immutablematrices.rst 2012-10-17 03:02:20.000000000 +0000 +++ python3-sympy-0.7.3/doc/src/modules/matrices/immutablematrices.rst 2013-07-13 17:50:18.000000000 +0000 @@ -12,6 +12,8 @@ between performance/mutability and safety/immutability. Immutable matrices can do almost everything that normal matrices can do but they inherit from :class:`Basic` and can thus interact more naturally with the rest of SymPy. +:class:`ImmutableMatrix` also inherits from :class:`MatrixExpr`, allowing it to +interact freely with SymPy's Matrix Expression module. You can turn any Matrix-like object into an :class:`ImmutableMatrix` by calling the constructor @@ -21,25 +23,20 @@ >>> M[1, 1] = 0 >>> IM = ImmutableMatrix(M) >>> IM - [1, 2, 3] - [4, 0, 6] - [7, 8, 9] + Matrix([ + [1, 2, 3], + [4, 0, 6], + [7, 8, 9]]) >>> IM[1, 1] = 5 Traceback (most recent call last): ... TypeError: Can not set values in Immutable Matrix. Use Matrix instead. -Matrix Expressions ------------------- - -:class:`ImmutableMatrix` also inherits from :class:`MatrixExpr`, allowing it to -interact freely with SymPy's Matrix Expression module. - -Class Reference ---------------- +ImmutableMatrix Class Reference +------------------------------- -.. module:: sympy.matrices.immutable_matrix +.. module:: sympy.matrices.immutable .. autoclass:: ImmutableMatrix :members: diff -Nru python3-sympy-0.7.2/doc/src/modules/matrices/index.rst python3-sympy-0.7.3/doc/src/modules/matrices/index.rst --- python3-sympy-0.7.2/doc/src/modules/matrices/index.rst 1970-01-01 00:00:00.000000000 +0000 +++ python3-sympy-0.7.3/doc/src/modules/matrices/index.rst 2013-07-13 17:50:18.000000000 +0000 @@ -0,0 +1,18 @@ +.. _matrices-docs: + +======== +Matrices +======== + +.. automodule:: sympy.matrices + +Contents: + +.. toctree:: + :maxdepth: 2 + + matrices.rst + dense.rst + sparse.rst + immutablematrices.rst + expressions.rst diff -Nru python3-sympy-0.7.2/doc/src/modules/matrices/matrices.rst python3-sympy-0.7.3/doc/src/modules/matrices/matrices.rst --- python3-sympy-0.7.2/doc/src/modules/matrices/matrices.rst 2012-10-17 03:02:20.000000000 +0000 +++ python3-sympy-0.7.3/doc/src/modules/matrices/matrices.rst 2013-07-13 17:53:31.000000000 +0000 @@ -7,22 +7,16 @@ ----------------- The linear algebra module is designed to be as simple as possible. First, we -import and declare our first Matrix object: +import and declare our first ``Matrix`` object: >>> from sympy.interactive.printing import init_printing >>> init_printing(use_unicode=False, wrap_line=False, no_global=True) - >>> from sympy.matrices import * - >>> Matrix([[1,0], [0,1]]) - [1 0] - [ ] - [0 1] - >>> Matrix(( - ... Matrix(( - ... (1, 0, 0), - ... (0, 0, 0) - ... )), - ... (0, 0, -1) - ... )) + >>> from sympy.matrices import Matrix, eye, zeros, ones, diag, GramSchmidt + >>> M = Matrix([[1,0,0], [0,0,0]]); M + [1 0 0] + [ ] + [0 0 0] + >>> Matrix([M, (0, 0, -1)]) [1 0 0 ] [ ] [0 0 0 ] @@ -37,25 +31,24 @@ [ ] [3] -This is the standard manner one creates a matrix, i.e. with a list of -appropriately-sizes lists and/or matrices. SymPy also supports more advanced -methods of matrix creation including a single list of values and dimension -inputs: +In addition to creating a matrix from a list of appropriately-sized lists +and/or matrices, SymPy also supports more advanced methods of matrix creation +including a single list of values and dimension inputs: >>> Matrix(2, 3, [1, 2, 3, 4, 5, 6]) [1 2 3] [ ] [4 5 6] -More interestingly (and usefully), we can use a 2-variable function (or lambda) -to make one. Here we create an indicator function which is 1 on the diagonal -and then use it to make the identity matrix: +More interesting (and useful), is the ability to use a 2-variable function +(or ``lambda``) to create a matrix. Here we create an indicator function which +is 1 on the diagonal and then use it to make the identity matrix: >>> def f(i,j): ... if i == j: - ... return 1 + ... return 1 ... else: - ... return 0 + ... return 0 ... >>> Matrix(4, 4, f) [1 0 0 0] @@ -66,7 +59,7 @@ [ ] [0 0 0 1] -Finally let's use lambda to create a 1-line matrix with 1's in the even +Finally let's use ``lambda`` to create a 1-line matrix with 1's in the even permutation entries: >>> Matrix(3, 4, lambda i,j: 1 - (i+j) % 2) @@ -76,9 +69,10 @@ [ ] [1 0 1 0] -There are also a couple of special constructors for quick matrix construction - +There are also a couple of special constructors for quick matrix construction: ``eye`` is the identity matrix, ``zeros`` and ``ones`` for matrices of all -zeros and ones, respectively: +zeros and ones, respectively, and ``diag`` to put matrices or elements along +the diagonal: >>> eye(4) [1 0 0 0] @@ -104,6 +98,12 @@ [1 1 1] >>> ones(1, 3) [1 1 1] + >>> diag(1, Matrix([[1, 2], [3, 4]])) + [1 0 0] + [ ] + [0 1 2] + [ ] + [0 3 4] Basic Manipulation @@ -118,40 +118,64 @@ >>> M[4] 5 -Now, the more standard entry access is a pair of indices: +Now, the more standard entry access is a pair of indices which will always +return the value at the corresponding row and column of the matrix: - >>> M[1,2] + >>> M[1, 2] 6 - >>> M[0,0] + >>> M[0, 0] 1 - >>> M[1,1] + >>> M[1, 1] 5 -Since this is Python we're also able to slice submatrices:: +Since this is Python we're also able to slice submatrices; slices always +give a matrix in return, even if the dimension is 1 x 1:: - >>> M[0:2,0:2] + >>> M[0:2, 0:2] [1 2] [ ] [4 5] - >>> M[1:2,2] - [6] - >>> M[:,2] + >>> M[2:2, 2] + [] + >>> M[:, 2] [3] [ ] [6] + >>> M[:1, 2] + [3] -Remember in the 2nd example above that slicing 2:2 gives an empty range and -that, as in python, a 4 column list is indexed from 0 to 3. In particular, this -mean a quick way to create a copy of the matrix is: +In the second example above notice that the slice 2:2 gives an empty range. Note +also (in keeping with 0-based indexing of Python) the first row/column is 0. - >>> M2 = M[:,:] - >>> M2[0,0] = 100 - >>> M +You cannot access rows or columns that are not present unless they +are in a slice: + + >>> M[:, 10] # the 10-th column (not there) + Traceback (most recent call last): + ... + IndexError: Index out of range: a[[0, 10]] + >>> M[:, 10:11] # the 10-th column (if there) + [] + >>> M[:, :10] # all columns up to the 10-th [1 2 3] [ ] [4 5 6] -See? Changing M2 didn't change M. Since we can slice, we can also assign +Slicing an empty matrix works as long as you use a slice for the coordinate +that has no size: + + >>> Matrix(0, 3, [])[:, 1] + [] + +Slicing gives a copy of what is sliced, so modifications of one object +do not affect the other: + + >>> M2 = M[:, :] + >>> M2[0, 0] = 100 + >>> M[0, 0] == 100 + False + +Notice that changing ``M2`` didn't change ``M``. Since we can slice, we can also assign entries: >>> M = Matrix(([1,2,3,4],[5,6,7,8],[9,10,11,12],[13,14,15,16])) @@ -243,7 +267,7 @@ >>> v1.dot(v3) 0 -Recall that the row_del() and col_del() operations don't return a value - they +Recall that the ``row_del()`` and ``col_del()`` operations don't return a value - they simply change the matrix object. We can also ''glue'' together matrices of the appropriate size: @@ -291,7 +315,7 @@ [ ] [0 0 3] -but we can also apply functions to our matrix entries using applyfunc(). Here we'll declare a function that double any input number. Then we apply it to the 3x3 identity matrix: +but we can also apply functions to our matrix entries using ``applyfunc()``. Here we'll declare a function that double any input number. Then we apply it to the 3x3 identity matrix: >>> f = lambda x: 2*x >>> eye(3).applyfunc(f) @@ -331,8 +355,8 @@ -------------- Now that we have the basics out of the way, let's see what we can do with the -actual matrices. Of course the first things that come to mind are the basics -like the determinant: +actual matrices. Of course, one of the first things that comes to mind is the +determinant: >>> M = Matrix(( [1, 2, 3], [3, 6, 2], [2, 0, 1] )) >>> M.det() @@ -344,8 +368,9 @@ >>> M3.det() 0 -and the inverse. In SymPy the inverse is computed by Gaussian elimination by -default but we can specify it be done by LU decomposition as well: +Another common operation is the inverse: In SymPy, this is computed by Gaussian +elimination by default (for dense matrices) but we can specify it be done by `LU` +decomposition as well: >>> M2.inv() [1 0 0] @@ -353,44 +378,44 @@ [0 1 0] [ ] [0 0 1] - >>> M2.inv("LU") + >>> M2.inv(method="LU") [1 0 0] [ ] [0 1 0] [ ] [0 0 1] - >>> M.inv("LU") + >>> M.inv(method="LU") [-3/14 1/14 1/2 ] [ ] [-1/28 5/28 -1/4] [ ] [ 3/7 -1/7 0 ] - >>> M * M.inv("LU") + >>> M * M.inv(method="LU") [1 0 0] [ ] [0 1 0] [ ] [0 0 1] -We can perform a QR factorization which is handy for solving systems: +We can perform a `QR` factorization which is handy for solving systems: >>> A = Matrix([[1,1,1],[1,1,3],[2,3,4]]) >>> Q, R = A.QRdecomposition() >>> Q - [ ___ ___ ___] - [\/ 6 -\/ 3 -\/ 2 ] - [----- ------ ------] - [ 6 3 2 ] - [ ] - [ ___ ___ ___ ] - [\/ 6 -\/ 3 \/ 2 ] - [----- ------ ----- ] - [ 6 3 2 ] - [ ] - [ ___ ___ ] - [\/ 6 \/ 3 ] - [----- ----- 0 ] - [ 3 3 ] + [ ___ ___ ___ ] + [\/ 6 -\/ 3 -\/ 2 ] + [----- ------- -------] + [ 6 3 2 ] + [ ] + [ ___ ___ ___ ] + [\/ 6 -\/ 3 \/ 2 ] + [----- ------- ----- ] + [ 6 3 2 ] + [ ] + [ ___ ___ ] + [\/ 6 \/ 3 ] + [----- ----- 0 ] + [ 3 3 ] >>> R [ ___ ] [ ___ 4*\/ 6 ___] @@ -412,7 +437,7 @@ [2 3 4] -In addition to the solvers in the solver.py file, we can solve the system Ax=b +In addition to the solvers in the ``solver.py`` file, we can solve the system Ax=b by passing the b vector to the matrix A's LUsolve function. Here we'll cheat a little choose A and x then multiply to get b. Then we can solve for x and check that it's correct: @@ -431,7 +456,7 @@ There's also a nice Gram-Schmidt orthogonalizer which will take a set of vectors and orthogonalize then with respect to another another. There is an optional argument which specifies whether or not the output should also be -normalized, it defaults to False. Let's take some vectors and orthogonalize +normalized, it defaults to ``False``. Let's take some vectors and orthogonalize them - one normalized and one not: >>> L = [Matrix([2,3,5]), Matrix([3,6,2]), Matrix([8,3,6])] @@ -443,27 +468,15 @@ >>> for i in out1: ... print(i) ... - [2] - [3] - [5] - [ 23/19] - [ 63/19] - [-47/19] - [ 1692/353] - [-1551/706] - [ -423/706] + Matrix([[2], [3], [5]]) + Matrix([[23/19], [63/19], [-47/19]]) + Matrix([[1692/353], [-1551/706], [-423/706]]) >>> for i in out2: ... print(i) ... - [ sqrt(38)/19] - [3*sqrt(38)/38] - [5*sqrt(38)/38] - [ 23*sqrt(6707)/6707] - [ 63*sqrt(6707)/6707] - [-47*sqrt(6707)/6707] - [ 12*sqrt(706)/353] - [-11*sqrt(706)/706] - [ -3*sqrt(706)/706] + Matrix([[sqrt(38)/19], [3*sqrt(38)/38], [5*sqrt(38)/38]]) + Matrix([[23*sqrt(6707)/6707], [63*sqrt(6707)/6707], [-47*sqrt(6707)/6707]]) + Matrix([[12*sqrt(706)/353], [-11*sqrt(706)/706], [-3*sqrt(706)/706]]) We can spot-check their orthogonality with dot() and their normality with norm(): @@ -483,18 +496,12 @@ So there is quite a bit that can be done with the module including eigenvalues, eigenvectors, nullspace calculation, cofactor expansion tools, and so on. From -here one might want to look over the matrices.py file for all functionality. +here one might want to look over the ``matrices.py`` file for all functionality. -Matrix Class Reference ----------------------- +MatrixBase Class Reference +-------------------------- .. autoclass:: MatrixBase :members: -.. autoclass:: Matrix - :members: -.. autoclass:: MutableMatrix - :members: -.. autoclass:: SparseMatrix - :members: Matrix Exceptions Reference --------------------------- @@ -509,43 +516,43 @@ Matrix Functions Reference -------------------------- -.. autofunction:: matrix_multiply +.. autofunction:: classof -.. autofunction:: matrix_multiply_elementwise +.. autofunction:: sympy.matrices.dense.matrix_multiply_elementwise -.. autofunction:: matrix_add +.. autofunction:: sympy.matrices.dense.zeros -.. autofunction:: zeros +.. autofunction:: sympy.matrices.dense.ones -.. autofunction:: ones +.. autofunction:: sympy.matrices.dense.eye -.. autofunction:: eye +.. autofunction:: sympy.matrices.dense.diag -.. autofunction:: diag +.. autofunction:: sympy.matrices.dense.jordan_cell -.. autofunction:: randMatrix +.. autofunction:: sympy.matrices.dense.hessian -.. autofunction:: hessian +.. autofunction:: sympy.matrices.dense.GramSchmidt -.. autofunction:: GramSchmidt +.. autofunction:: sympy.matrices.dense.wronskian -.. autofunction:: wronskian +.. autofunction:: sympy.matrices.dense.casoratian -.. autofunction:: casoratian +.. autofunction:: sympy.matrices.dense.randMatrix Numpy Utility Functions Reference --------------------------------- -.. autofunction:: list2numpy +.. autofunction:: sympy.matrices.dense.list2numpy -.. autofunction:: matrix2numpy +.. autofunction:: sympy.matrices.dense.matrix2numpy -.. autofunction:: a2idx +.. autofunction:: sympy.matrices.dense.symarray -.. autofunction:: symarray +.. autofunction:: sympy.matrices.dense.rot_axis1 -.. autofunction:: rot_axis1 +.. autofunction:: sympy.matrices.dense.rot_axis2 -.. autofunction:: rot_axis2 +.. autofunction:: sympy.matrices.dense.rot_axis3 -.. autofunction:: rot_axis3 +.. autofunction:: a2idx diff -Nru python3-sympy-0.7.2/doc/src/modules/matrices/sparse.rst python3-sympy-0.7.3/doc/src/modules/matrices/sparse.rst --- python3-sympy-0.7.2/doc/src/modules/matrices/sparse.rst 1970-01-01 00:00:00.000000000 +0000 +++ python3-sympy-0.7.3/doc/src/modules/matrices/sparse.rst 2013-07-13 17:50:18.000000000 +0000 @@ -0,0 +1,16 @@ +Sparse Matrices +=============== + +.. module:: sympy.matrices.sparse + +SparseMatrix Class Reference +---------------------------- +.. autoclass:: SparseMatrix + :members: +.. autoclass:: MutableSparseMatrix + :members: + +ImmutableSparseMatrix Class Reference +------------------------------------- +.. autoclass:: sympy.matrices.immutable.ImmutableSparseMatrix + :members: diff -Nru python3-sympy-0.7.2/doc/src/modules/mpmath/references.rst python3-sympy-0.7.3/doc/src/modules/mpmath/references.rst --- python3-sympy-0.7.2/doc/src/modules/mpmath/references.rst 2012-10-17 01:53:14.000000000 +0000 +++ python3-sympy-0.7.3/doc/src/modules/mpmath/references.rst 2013-07-13 17:50:18.000000000 +0000 @@ -5,7 +5,7 @@ or cited for examples or mathematical definitions used in this documentation. References not listed here can be found in the source code. -.. [AbramowitzStegun] M Abramowitz & I Stegun. *Handbook of Mathematical Functions, 9th Ed.*, Tenth Printing, December 1972, with corrections (electronic copy: http://www.math.ucla.edu/~cbm/aands/) +.. [AbramowitzStegun] M Abramowitz & I Stegun. *Handbook of Mathematical Functions, 9th Ed.*, Tenth Printing, December 1972, with corrections .. [Bailey] D H Bailey. "Tanh-Sinh High-Precision Quadrature", http://crd.lbl.gov/~dhbailey/dhbpapers/dhb-tanh-sinh.pdf @@ -16,7 +16,7 @@ .. [BorweinBorwein] J Borwein & P B Borwein. *Pi and the AGM: A Study in Analytic Number Theory and Computational Complexity*, Wiley 1987 -.. [BorweinZeta] P Borwein. "An Efficient Algorithm for the Riemann Zeta Function", http://www.cecm.sfu.ca/personal/pborwein/PAPERS/P117.ps +.. [BorweinZeta] P Borwein. "An Efficient Algorithm for the Riemann Zeta Function", http://www.cecm.sfu.ca/personal/pborwein/PAPERS/P115.pdf .. [CabralRosetti] L G Cabral-Rosetti & M A Sanchis-Lozano. "Appell Functions and the Scalar One-Loop Three-point Integrals in Feynman Diagrams". http://arxiv.org/abs/hep-ph/0206081 diff -Nru python3-sympy-0.7.2/doc/src/modules/mpmath/setup.rst python3-sympy-0.7.3/doc/src/modules/mpmath/setup.rst --- python3-sympy-0.7.2/doc/src/modules/mpmath/setup.rst 2012-10-17 01:53:14.000000000 +0000 +++ python3-sympy-0.7.3/doc/src/modules/mpmath/setup.rst 2013-07-13 17:50:18.000000000 +0000 @@ -43,10 +43,10 @@ OpenSUSE ........ -Mpmath is provided in the "Science" repository for all recent versions of `openSUSE `_. To add this repository to the YAST software management tool, see http://en.opensuse.org/Add_Package_Repositories_to_YaST +Mpmath is provided in the "Science" repository for all recent versions of `openSUSE `_. To add this repository to the YAST software management tool, see http://en.opensuse.org/SDB:Add_package_repositories Look up http://download.opensuse.org/repositories/science/ for a list -of supported OpenSUSE versions and use http://download.opensuse.org/repositories/science/openSUSE_11.1/ +of supported OpenSUSE versions and use http://download.opensuse.org/repositories/science/openSUSE_12.2/ (or accordingly for your OpenSUSE version) as the repository URL for YAST. Current development version diff -Nru python3-sympy-0.7.2/doc/src/modules/parsing.rst python3-sympy-0.7.3/doc/src/modules/parsing.rst --- python3-sympy-0.7.2/doc/src/modules/parsing.rst 2012-10-17 01:53:14.000000000 +0000 +++ python3-sympy-0.7.3/doc/src/modules/parsing.rst 2013-07-13 17:50:18.000000000 +0000 @@ -6,6 +6,10 @@ .. autofunction:: sympy.parsing.sympy_parser.parse_expr +.. autofunction:: sympy.parsing.sympy_parser.stringify_expr + +.. autofunction:: sympy.parsing.sympy_parser.eval_expr + .. autofunction:: sympy.parsing.sympy_tokenize.printtoken .. autofunction:: sympy.parsing.sympy_tokenize.tokenize @@ -30,3 +34,39 @@ .. autoclass:: sympy.parsing.sympy_tokenize.TokenError .. autoclass:: sympy.parsing.sympy_tokenize.StopTokenizing + +Parsing Transformations Reference +--------------------------------- + +A transformation is a function that accepts the arguments ``tokens, +local_dict, global_dict`` and returns a list of transformed tokens. They can +be used by passing a list of functions to :py:func:`parse_expr` and are +applied in the order given. + +.. autodata:: sympy.parsing.sympy_parser.standard_transformations + +.. autofunction:: sympy.parsing.sympy_parser.split_symbols + +.. autofunction:: sympy.parsing.sympy_parser.split_symbols_custom + +.. autofunction:: sympy.parsing.sympy_parser.implicit_multiplication + +.. autofunction:: sympy.parsing.sympy_parser.implicit_application + +.. autofunction:: sympy.parsing.sympy_parser.function_exponentiation + +.. autofunction:: sympy.parsing.sympy_parser.implicit_multiplication_application + +.. autofunction:: sympy.parsing.sympy_parser.rationalize + +.. autofunction:: sympy.parsing.sympy_parser.convert_xor + +These are included in +:data:``sympy.parsing.sympy_parser.standard_transformations`` and generally +don't need to be manually added by the user. + +.. autofunction:: sympy.parsing.sympy_parser.factorial_notation + +.. autofunction:: sympy.parsing.sympy_parser.auto_symbol + +.. autofunction:: sympy.parsing.sympy_parser.auto_number diff -Nru python3-sympy-0.7.2/doc/src/modules/physics/mechanics/api/kane.rst python3-sympy-0.7.3/doc/src/modules/physics/mechanics/api/kane.rst --- python3-sympy-0.7.2/doc/src/modules/physics/mechanics/api/kane.rst 2012-10-17 01:53:14.000000000 +0000 +++ python3-sympy-0.7.3/doc/src/modules/physics/mechanics/api/kane.rst 2013-07-13 17:50:18.000000000 +0000 @@ -1,15 +1,22 @@ -================================================= -Kane's Method & Associated Functions (Docstrings) -================================================= +==================================================================== +Kane's Method, Lagrange's Method & Associated Functions (Docstrings) +==================================================================== -KanesMethod -=========== +Kane +==== -.. autoclass:: sympy.physics.mechanics.KanesMethod +.. automodule:: sympy.physics.mechanics.kane :members: + partial_velocity ================ .. automodule:: sympy.physics.mechanics.functions :members: partial_velocity + +LagrangesMethod +=============== + +.. automodule:: sympy.physics.mechanics.lagrange + :members: diff -Nru python3-sympy-0.7.2/doc/src/modules/physics/mechanics/api/part_bod.rst python3-sympy-0.7.3/doc/src/modules/physics/mechanics/api/part_bod.rst --- python3-sympy-0.7.2/doc/src/modules/physics/mechanics/api/part_bod.rst 2012-10-17 01:53:14.000000000 +0000 +++ python3-sympy-0.7.3/doc/src/modules/physics/mechanics/api/part_bod.rst 2013-07-13 17:50:18.000000000 +0000 @@ -38,3 +38,18 @@ ================ .. autofunction:: sympy.physics.mechanics.functions.angular_momentum + +kinetic_energy +============== + +.. autofunction:: sympy.physics.mechanics.functions.kinetic_energy + +potential_energy +================ + +.. autofunction:: sympy.physics.mechanics.functions.potential_energy + +Lagrangian +========== + +.. autofunction:: sympy.physics.mechanics.functions.Lagrangian diff -Nru python3-sympy-0.7.2/doc/src/modules/physics/mechanics/bicycle_example.rst python3-sympy-0.7.3/doc/src/modules/physics/mechanics/bicycle_example.rst --- python3-sympy-0.7.2/doc/src/modules/physics/mechanics/bicycle_example.rst 1970-01-01 00:00:00.000000000 +0000 +++ python3-sympy-0.7.3/doc/src/modules/physics/mechanics/bicycle_example.rst 2013-07-13 17:53:31.000000000 +0000 @@ -0,0 +1,337 @@ +========= +A bicycle +========= + +The bicycle is an interesting system in that it has multiple rigid bodies, +non-holonomic constraints, and a holonomic constraint. The linearized equations +of motion are presented in [Meijaard2007]_. This example will go through +construction of the equations of motion in :mod:`mechanics`. :: + + >>> from sympy import * + >>> from sympy.physics.mechanics import * + >>> print('Calculation of Linearized Bicycle \"A\" Matrix, ' + ... 'with States: Roll, Steer, Roll Rate, Steer Rate') + Calculation of Linearized Bicycle "A" Matrix, with States: Roll, Steer, Roll Rate, Steer Rate + + +Note that this code has been crudely ported from Autolev, which is the reason +for some of the unusual naming conventions. It was purposefully as similar as +possible in order to aid initial porting & debugging. We set Vector.simp to +False (in case it has been set True elsewhere), since it slows down the +computations:: + + >>> Vector.simp = False + >>> mechanics_printing() + +Declaration of Coordinates & Speeds: +A simple definition for qdots, qd = u,is used in this code. Speeds are: yaw +frame ang. rate, roll frame ang. rate, rear wheel frame ang. rate (spinning +motion), frame ang. rate (pitching motion), steering frame ang. rate, and front +wheel ang. rate (spinning motion). Wheel positions are ignorable coordinates, +so they are not introduced. :: + + >>> q1, q2, q3, q4, q5 = dynamicsymbols('q1 q2 q3 q4 q5') + >>> q1d, q2d, q4d, q5d = dynamicsymbols('q1 q2 q4 q5', 1) + >>> u1, u2, u3, u4, u5, u6 = dynamicsymbols('u1 u2 u3 u4 u5 u6') + >>> u1d, u2d, u3d, u4d, u5d, u6d = dynamicsymbols('u1 u2 u3 u4 u5 u6', 1) + +Declaration of System's Parameters: +The below symbols should be fairly self-explanatory. :: + + >>> WFrad, WRrad, htangle, forkoffset = symbols('WFrad WRrad htangle forkoffset') + >>> forklength, framelength, forkcg1 = symbols('forklength framelength forkcg1') + >>> forkcg3, framecg1, framecg3, Iwr11 = symbols('forkcg3 framecg1 framecg3 Iwr11') + >>> Iwr22, Iwf11, Iwf22, Iframe11 = symbols('Iwr22 Iwf11 Iwf22 Iframe11') + >>> Iframe22, Iframe33, Iframe31, Ifork11 = \ + ... symbols('Iframe22 Iframe33 Iframe31 Ifork11') + >>> Ifork22, Ifork33, Ifork31, g = symbols('Ifork22 Ifork33 Ifork31 g') + >>> mframe, mfork, mwf, mwr = symbols('mframe mfork mwf mwr') + +Set up reference frames for the system: +N - inertial +Y - yaw +R - roll +WR - rear wheel, rotation angle is ignorable coordinate so not oriented +Frame - bicycle frame +TempFrame - statically rotated frame for easier reference inertia definition +Fork - bicycle fork +TempFork - statically rotated frame for easier reference inertia definition +WF - front wheel, again posses a ignorable coordinate :: + + >>> N = ReferenceFrame('N') + >>> Y = N.orientnew('Y', 'Axis', [q1, N.z]) + >>> R = Y.orientnew('R', 'Axis', [q2, Y.x]) + >>> Frame = R.orientnew('Frame', 'Axis', [q4 + htangle, R.y]) + >>> WR = ReferenceFrame('WR') + >>> TempFrame = Frame.orientnew('TempFrame', 'Axis', [-htangle, Frame.y]) + >>> Fork = Frame.orientnew('Fork', 'Axis', [q5, Frame.x]) + >>> TempFork = Fork.orientnew('TempFork', 'Axis', [-htangle, Fork.y]) + >>> WF = ReferenceFrame('WF') + + +Kinematics of the Bicycle: +First block of code is forming the positions of the relevant points rear wheel +contact -> rear wheel's center of mass -> frame's center of mass + frame/fork connection +-> fork's center of mass + front wheel's center of mass -> front wheel contact point. :: + + >>> WR_cont = Point('WR_cont') + >>> WR_mc = WR_cont.locatenew('WR_mc', WRrad * R.z) + >>> Steer = WR_mc.locatenew('Steer', framelength * Frame.z) + >>> Frame_mc = WR_mc.locatenew('Frame_mc', -framecg1 * Frame.x + framecg3 * Frame.z) + >>> Fork_mc = Steer.locatenew('Fork_mc', -forkcg1 * Fork.x + forkcg3 * Fork.z) + >>> WF_mc = Steer.locatenew('WF_mc', forklength * Fork.x + forkoffset * Fork.z) + >>> WF_cont = WF_mc.locatenew('WF_cont', WFrad*(dot(Fork.y, Y.z)*Fork.y - \ + ... Y.z).normalize()) + +Set the angular velocity of each frame: +Angular accelerations end up being calculated automatically by differentiating +the angular velocities when first needed. :: +u1 is yaw rate +u2 is roll rate +u3 is rear wheel rate +u4 is frame pitch rate +u5 is fork steer rate +u6 is front wheel rate :: + + >>> Y.set_ang_vel(N, u1 * Y.z) + >>> R.set_ang_vel(Y, u2 * R.x) + >>> WR.set_ang_vel(Frame, u3 * Frame.y) + >>> Frame.set_ang_vel(R, u4 * Frame.y) + >>> Fork.set_ang_vel(Frame, u5 * Fork.x) + >>> WF.set_ang_vel(Fork, u6 * Fork.y) + +Form the velocities of the points, using the 2-point theorem. Accelerations +again are calculated automatically when first needed. :: + + >>> WR_cont.set_vel(N, 0) + >>> WR_mc.v2pt_theory(WR_cont, N, WR) + WRrad*(u1*sin(q2) + u3 + u4)*R.x - WRrad*u2*R.y + >>> Steer.v2pt_theory(WR_mc, N, Frame) + WRrad*(u1*sin(q2) + u3 + u4)*R.x - WRrad*u2*R.y + framelength*(u1*sin(q2) + u4)*Frame.x - framelength*(-u1*sin(htangle + q4)*cos(q2) + u2*cos(htangle + q4))*Frame.y + >>> Frame_mc.v2pt_theory(WR_mc, N, Frame) + WRrad*(u1*sin(q2) + u3 + u4)*R.x - WRrad*u2*R.y + framecg3*(u1*sin(q2) + u4)*Frame.x + (-framecg1*(u1*cos(htangle + q4)*cos(q2) + u2*sin(htangle + q4)) - framecg3*(-u1*sin(htangle + q4)*cos(q2) + u2*cos(htangle + q4)))*Frame.y + framecg1*(u1*sin(q2) + u4)*Frame.z + >>> Fork_mc.v2pt_theory(Steer, N, Fork) + WRrad*(u1*sin(q2) + u3 + u4)*R.x - WRrad*u2*R.y + framelength*(u1*sin(q2) + u4)*Frame.x - framelength*(-u1*sin(htangle + q4)*cos(q2) + u2*cos(htangle + q4))*Frame.y + forkcg3*((sin(q2)*cos(q5) + sin(q5)*cos(htangle + q4)*cos(q2))*u1 + u2*sin(htangle + q4)*sin(q5) + u4*cos(q5))*Fork.x + (-forkcg1*((-sin(q2)*sin(q5) + cos(htangle + q4)*cos(q2)*cos(q5))*u1 + u2*sin(htangle + q4)*cos(q5) - u4*sin(q5)) - forkcg3*(-u1*sin(htangle + q4)*cos(q2) + u2*cos(htangle + q4) + u5))*Fork.y + forkcg1*((sin(q2)*cos(q5) + sin(q5)*cos(htangle + q4)*cos(q2))*u1 + u2*sin(htangle + q4)*sin(q5) + u4*cos(q5))*Fork.z + >>> WF_mc.v2pt_theory(Steer, N, Fork) + WRrad*(u1*sin(q2) + u3 + u4)*R.x - WRrad*u2*R.y + framelength*(u1*sin(q2) + u4)*Frame.x - framelength*(-u1*sin(htangle + q4)*cos(q2) + u2*cos(htangle + q4))*Frame.y + forkoffset*((sin(q2)*cos(q5) + sin(q5)*cos(htangle + q4)*cos(q2))*u1 + u2*sin(htangle + q4)*sin(q5) + u4*cos(q5))*Fork.x + (forklength*((-sin(q2)*sin(q5) + cos(htangle + q4)*cos(q2)*cos(q5))*u1 + u2*sin(htangle + q4)*cos(q5) - u4*sin(q5)) - forkoffset*(-u1*sin(htangle + q4)*cos(q2) + u2*cos(htangle + q4) + u5))*Fork.y - forklength*((sin(q2)*cos(q5) + sin(q5)*cos(htangle + q4)*cos(q2))*u1 + u2*sin(htangle + q4)*sin(q5) + u4*cos(q5))*Fork.z + >>> WF_cont.v2pt_theory(WF_mc, N, WF) + WRrad*(u1*sin(q2) + u3 + u4)*R.x - WRrad*u2*R.y + framelength*(u1*sin(q2) + u4)*Frame.x - framelength*(-u1*sin(htangle + q4)*cos(q2) + u2*cos(htangle + q4))*Frame.y + (-WFrad*(sin(q2)*cos(q5) + sin(q5)*cos(htangle + q4)*cos(q2))*((-sin(q2)*sin(q5) + cos(htangle + q4)*cos(q2)*cos(q5))*u1 + u2*sin(htangle + q4)*cos(q5) - u4*sin(q5))/sqrt((-sin(q2)*cos(q5) - sin(q5)*cos(htangle + q4)*cos(q2))*(sin(q2)*cos(q5) + sin(q5)*cos(htangle + q4)*cos(q2)) + 1) + forkoffset*((sin(q2)*cos(q5) + sin(q5)*cos(htangle + q4)*cos(q2))*u1 + u2*sin(htangle + q4)*sin(q5) + u4*cos(q5)))*Fork.x + (forklength*((-sin(q2)*sin(q5) + cos(htangle + q4)*cos(q2)*cos(q5))*u1 + u2*sin(htangle + q4)*cos(q5) - u4*sin(q5)) - forkoffset*(-u1*sin(htangle + q4)*cos(q2) + u2*cos(htangle + q4) + u5))*Fork.y + (WFrad*(sin(q2)*cos(q5) + sin(q5)*cos(htangle + q4)*cos(q2))*(-u1*sin(htangle + q4)*cos(q2) + u2*cos(htangle + q4) + u5)/sqrt((-sin(q2)*cos(q5) - sin(q5)*cos(htangle + q4)*cos(q2))*(sin(q2)*cos(q5) + sin(q5)*cos(htangle + q4)*cos(q2)) + 1) - forklength*((sin(q2)*cos(q5) + sin(q5)*cos(htangle + q4)*cos(q2))*u1 + u2*sin(htangle + q4)*sin(q5) + u4*cos(q5)))*Fork.z - WFrad*((-sin(q2)*sin(q5)*cos(htangle + q4) + cos(q2)*cos(q5))*u6 + u4*cos(q2) + u5*sin(htangle + q4)*sin(q2))/sqrt((-sin(q2)*cos(q5) - sin(q5)*cos(htangle + q4)*cos(q2))*(sin(q2)*cos(q5) + sin(q5)*cos(htangle + q4)*cos(q2)) + 1)*Y.x + WFrad*(u2 + u5*cos(htangle + q4) + u6*sin(htangle + q4)*sin(q5))/sqrt((-sin(q2)*cos(q5) - sin(q5)*cos(htangle + q4)*cos(q2))*(sin(q2)*cos(q5) + sin(q5)*cos(htangle + q4)*cos(q2)) + 1)*Y.y + + +Sets the inertias of each body. Uses the inertia frame to construct the inertia +dyadics. Wheel inertias are only defined by principal moments of inertia, and +are in fact constant in the frame and fork reference frames; it is for this +reason that the orientations of the wheels does not need to be defined. The +frame and fork inertias are defined in the 'Temp' frames which are fixed to the +appropriate body frames; this is to allow easier input of the reference values +of the benchmark paper. Note that due to slightly different orientations, the +products of inertia need to have their signs flipped; this is done later when +entering the numerical value. :: + + >>> Frame_I = (inertia(TempFrame, Iframe11, Iframe22, Iframe33, 0, 0, + ... Iframe31), Frame_mc) + >>> Fork_I = (inertia(TempFork, Ifork11, Ifork22, Ifork33, 0, 0, Ifork31), Fork_mc) + >>> WR_I = (inertia(Frame, Iwr11, Iwr22, Iwr11), WR_mc) + >>> WF_I = (inertia(Fork, Iwf11, Iwf22, Iwf11), WF_mc) + +Declaration of the RigidBody containers. :: + + >>> BodyFrame = RigidBody('BodyFrame', Frame_mc, Frame, mframe, Frame_I) + >>> BodyFork = RigidBody('BodyFork', Fork_mc, Fork, mfork, Fork_I) + >>> BodyWR = RigidBody('BodyWR', WR_mc, WR, mwr, WR_I) + >>> BodyWF = RigidBody('BodyWF', WF_mc, WF, mwf, WF_I) + + >>> print('Before Forming the List of Nonholonomic Constraints.') + Before Forming the List of Nonholonomic Constraints. + +The kinematic differential equations; they are defined quite simply. Each entry +in this list is equal to zero. :: + + >>> kd = [q1d - u1, q2d - u2, q4d - u4, q5d - u5] + +The nonholonomic constraints are the velocity of the front wheel contact point +dotted into the X, Y, and Z directions; the yaw frame is used as it is "closer" +to the front wheel (1 less DCM connecting them). These constraints force the +velocity of the front wheel contact point to be 0 in the inertial frame; the X +and Y direction constraints enforce a "no-slip" condition, and the Z direction +constraint forces the front wheel contact point to not move away from the +ground frame, essentially replicating the holonomic constraint which does not +allow the frame pitch to change in an invalid fashion. :: + + >>> conlist_speed = [WF_cont.vel(N) & Y.x, + ... WF_cont.vel(N) & Y.y, + ... WF_cont.vel(N) & Y.z] + +The holonomic constraint is that the position from the rear wheel contact point +to the front wheel contact point when dotted into the normal-to-ground plane +direction must be zero; effectively that the front and rear wheel contact +points are always touching the ground plane. This is actually not part of the +dynamic equations, but instead is necessary for the linearization process. :: + + >>> conlist_coord = [WF_cont.pos_from(WR_cont) & Y.z] + +The force list; each body has the appropriate gravitational force applied at +its center of mass. :: + + >>> FL = [(Frame_mc, -mframe * g * Y.z), (Fork_mc, -mfork * g * Y.z), + ... (WF_mc, -mwf * g * Y.z), (WR_mc, -mwr * g * Y.z)] + >>> BL = [BodyFrame, BodyFork, BodyWR, BodyWF] + +The N frame is the inertial frame, coordinates are supplied in the order of +independent, dependent coordinates. The kinematic differential equations are +also entered here. Here the independent speeds are specified, followed by the +dependent speeds, along with the non-holonomic constraints. The dependent +coordinate is also provided, with the holonomic constraint. Again, this is only +comes into play in the linearization process, but is necessary for the +linearization to correctly work. :: + + >>> KM = KanesMethod(N, q_ind=[q1, q2, q3], + ... q_dependent=[q4], configuration_constraints=conlist_coord, + ... u_ind=[u2, u3, u5], + ... u_dependent=[u1, u4, u6], velocity_constraints=conlist_speed, + ... kd_eqs=kd) + >>> print('Before Forming Generalized Active and Inertia Forces, Fr and Fr*') + Before Forming Generalized Active and Inertia Forces, Fr and Fr* + >>> (fr, frstar) = KM.kanes_equations(FL, BL) + >>> print('Base Equations of Motion Computed') + Base Equations of Motion Computed + +This is the start of entering in the numerical values from the benchmark paper +to validate the eigenvalues of the linearized equations from this model to the +reference eigenvalues. Look at the aforementioned paper for more information. +Some of these are intermediate values, used to transform values from the paper +into the coordinate systems used in this model. :: + + >>> PaperRadRear = 0.3 + >>> PaperRadFront = 0.35 + >>> HTA = evalf.N(pi/2-pi/10) + >>> TrailPaper = 0.08 + >>> rake = evalf.N(-(TrailPaper*sin(HTA)-(PaperRadFront*cos(HTA)))) + >>> PaperWb = 1.02 + >>> PaperFrameCgX = 0.3 + >>> PaperFrameCgZ = 0.9 + >>> PaperForkCgX = 0.9 + >>> PaperForkCgZ = 0.7 + >>> FrameLength = evalf.N(PaperWb*sin(HTA) - (rake - \ + ... (PaperRadFront - PaperRadRear)*cos(HTA))) + >>> FrameCGNorm = evalf.N((PaperFrameCgZ - PaperRadRear - \ + ... (PaperFrameCgX/sin(HTA))*cos(HTA))*sin(HTA)) + >>> FrameCGPar = evalf.N((PaperFrameCgX / sin(HTA) + \ + ... (PaperFrameCgZ - PaperRadRear - \ + ... PaperFrameCgX / sin(HTA) * cos(HTA)) * cos(HTA))) + >>> tempa = evalf.N((PaperForkCgZ - PaperRadFront)) + >>> tempb = evalf.N((PaperWb-PaperForkCgX)) + >>> tempc = evalf.N(sqrt(tempa**2 + tempb**2)) + >>> PaperForkL = evalf.N((PaperWb*cos(HTA) - \ + ... (PaperRadFront - PaperRadRear)*sin(HTA))) + >>> ForkCGNorm = evalf.N(rake + (tempc * sin(pi/2 - \ + ... HTA - acos(tempa/tempc)))) + >>> ForkCGPar = evalf.N(tempc * cos((pi/2 - HTA) - \ + ... acos(tempa/tempc)) - PaperForkL) + +Here is the final assembly of the numerical values. The symbol 'v' is the +forward speed of the bicycle (a concept which only makes sense in the upright, +static equilibrium case?). These are in a dictionary which will later be +substituted in. Again the sign on the *product* of inertia values is flipped +here, due to different orientations of coordinate systems. :: + + >>> v = Symbol('v') + >>> val_dict = { + ... WFrad: PaperRadFront, + ... WRrad: PaperRadRear, + ... htangle: HTA, + ... forkoffset: rake, + ... forklength: PaperForkL, + ... framelength: FrameLength, + ... forkcg1: ForkCGPar, + ... forkcg3: ForkCGNorm, + ... framecg1: FrameCGNorm, + ... framecg3: FrameCGPar, + ... Iwr11: 0.0603, + ... Iwr22: 0.12, + ... Iwf11: 0.1405, + ... Iwf22: 0.28, + ... Ifork11: 0.05892, + ... Ifork22: 0.06, + ... Ifork33: 0.00708, + ... Ifork31: 0.00756, + ... Iframe11: 9.2, + ... Iframe22: 11, + ... Iframe33: 2.8, + ... Iframe31: -2.4, + ... mfork: 4, + ... mframe: 85, + ... mwf: 3, + ... mwr: 2, + ... g: 9.81, + ... q1: 0, + ... q2: 0, + ... q4: 0, + ... q5: 0, + ... u1: 0, + ... u2: 0, + ... u3: v/PaperRadRear, + ... u4: 0, + ... u5: 0, + ... u6: v/PaperRadFront} + >>> kdd = KM.kindiffdict() + >>> print('Before Linearization of the \"Forcing\" Term') + Before Linearization of the "Forcing" Term + +Linearizes the forcing vector; the equations are set up as MM udot = forcing, +where MM is the mass matrix, udot is the vector representing the time +derivatives of the generalized speeds, and forcing is a vector which contains +both external forcing terms and internal forcing terms, such as centripetal or +Coriolis forces. This actually returns a matrix with as many rows as *total* +coordinates and speeds, but only as many columns as independent coordinates and +speeds. (Note that below this is commented out, as it takes a few minutes to +run, which is not good when performing the doctests) :: + + >>> # forcing_lin = KM.linearize()[0].subs(sub_dict) + +As mentioned above, the size of the linearized forcing terms is expanded to +include both q's and u's, so the mass matrix must have this done as well. This +will likely be changed to be part of the linearized process, for future +reference. :: + + >>> MM_full = (KM._k_kqdot).row_join(zeros(4, 6)).col_join( + ... (zeros(6, 4)).row_join(KM.mass_matrix)) + >>> print('Before Substitution of Numerical Values') + Before Substitution of Numerical Values + +I think this is pretty self explanatory. It takes a really long time though. +I've experimented with using evalf with substitution, this failed due to +maximum recursion depth being exceeded; I also tried lambdifying this, and it +is also not successful. (again commented out due to speed) :: + + >>> # MM_full = MM_full.subs(val_dict) + >>> # forcing_lin = forcing_lin.subs(val_dict) + >>> # print('Before .evalf() call') + + >>> # MM_full = MM_full.evalf() + >>> # forcing_lin = forcing_lin.evalf() + +Finally, we construct an "A" matrix for the form xdot = A x (x being the state +vector, although in this case, the sizes are a little off). The following line +extracts only the minimum entries required for eigenvalue analysis, which +correspond to rows and columns for lean, steer, lean rate, and steer rate. +(this is all commented out due to being dependent on the above code, which is +also commented out):: + + >>> # Amat = MM_full.inv() * forcing_lin + >>> # A = Amat.extract([1,2,4,6],[1,2,3,5]) + >>> # print(A) + >>> # print('v = 1') + >>> # print(A.subs(v, 1).eigenvals()) + >>> # print('v = 2') + >>> # print(A.subs(v, 2).eigenvals()) + >>> # print('v = 3') + >>> # print(A.subs(v, 3).eigenvals()) + >>> # print('v = 4') + >>> # print(A.subs(v, 4).eigenvals()) + >>> # print('v = 5') + >>> # print(A.subs(v, 5).eigenvals()) + +Upon running the above code yourself, enabling the commented out lines, compare +the computed eigenvalues to those is the referenced paper. This concludes the +bicycle example. diff -Nru python3-sympy-0.7.2/doc/src/modules/physics/mechanics/ex_rd.svg python3-sympy-0.7.3/doc/src/modules/physics/mechanics/ex_rd.svg --- python3-sympy-0.7.2/doc/src/modules/physics/mechanics/ex_rd.svg 2012-10-17 01:53:14.000000000 +0000 +++ python3-sympy-0.7.3/doc/src/modules/physics/mechanics/ex_rd.svg 1970-01-01 00:00:00.000000000 +0000 @@ -1,237 +0,0 @@ - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - R - N - nz - nx - ny - rx - ry - rz - - - - - - - - diff -Nru python3-sympy-0.7.2/doc/src/modules/physics/mechanics/examples.rst python3-sympy-0.7.3/doc/src/modules/physics/mechanics/examples.rst --- python3-sympy-0.7.2/doc/src/modules/physics/mechanics/examples.rst 2012-10-17 03:02:20.000000000 +0000 +++ python3-sympy-0.7.3/doc/src/modules/physics/mechanics/examples.rst 2013-07-13 17:50:18.000000000 +0000 @@ -1,458 +1,15 @@ ============================== -Examples for Physics.Mechanics +Examples for Physics/Mechanics ============================== -This module has been developed to aid in formulation of equations of motion; -here, examples follow to help display how to use this module. +Here are some examples that illustrate how one typically uses this module. We +have ordered the examples roughly according to increasing difficulty. If you +have used this module to do something others might find useful or interesting, +consider adding it here! -The Rolling Disc -================ -The first example is that of a rolling disc. The disc is assumed to be -infinitely thin, in contact with the ground at only 1 point, and it is rolling -without slip on the ground. See the image below. +.. toctree:: + :maxdepth: 1 -.. image:: ex_rd.* - :height: 550 - :width: 550 - :align: center - -Here the definition of the rolling disc's kinematics is formed from the contact -point up, removing the need to introduce generalized speeds. Only 3 -configuration and three speed variables are need to describe this system, along -with the disc's mass and radius, and the local gravity (note that mass will -drop out). :: - - >>> from sympy import symbols, sin, cos, tan - >>> from sympy.physics.mechanics import * - >>> q1, q2, q3, u1, u2, u3 = dynamicsymbols('q1 q2 q3 u1 u2 u3') - >>> q1d, q2d, q3d, u1d, u2d, u3d = dynamicsymbols('q1 q2 q3 u1 u2 u3', 1) - >>> r, m, g = symbols('r m g') - >>> mechanics_printing() - -The kinematics are formed by a series of simple rotations. Each simple rotation -creates a new frame, and the next rotation is defined by the new frame's basis -vectors. This example uses a 3-1-2 series of rotations, or Z, X, Y series of -rotations. Angular velocity for this is defined using the second frame's basis -(the lean frame); it is for this reason that we defined intermediate frames, -rather than using a body-three orientation. :: - - >>> N = ReferenceFrame('N') - >>> Y = N.orientnew('Y', 'Axis', [q1, N.z]) - >>> L = Y.orientnew('L', 'Axis', [q2, Y.x]) - >>> R = L.orientnew('R', 'Axis', [q3, L.y]) - >>> R.set_ang_vel(N, u1 * L.x + u2 * L.y + u3 * L.z) - >>> R.set_ang_acc(N, R.ang_vel_in(N).dt(R) + (R.ang_vel_in(N) ^ R.ang_vel_in(N))) - -This is the translational kinematics. We create a point with no velocity -in N; this is the contact point between the disc and ground. Next we form -the position vector from the contact point to the disc's center of mass. -Finally we form the velocity and acceleration of the disc. :: - - >>> C = Point('C') - >>> C.set_vel(N, 0) - >>> Dmc = C.locatenew('Dmc', r * L.z) - >>> Dmc.v2pt_theory(C, N, R) - r*u2*L.x - r*u1*L.y - >>> Dmc.a2pt_theory(C, N, R) - (r*u1*u3 + r*u2')*L.x + (-r*(-u3*q3' + u1') + r*u2*u3)*L.y + (-r*u1**2 - r*u2**2)*L.z - -This is a simple way to form the inertia dyadic. The inertia of the disc does -not change within the lean frame as the disc rolls; this will make for simpler -equations in the end. :: - - >>> I = inertia(L, m / 4 * r**2, m / 2 * r**2, m / 4 * r**2) - >>> mprint(I) - m*r**2/4*(L.x|L.x) + m*r**2/2*(L.y|L.y) + m*r**2/4*(L.z|L.z) - -Kinematic differential equations; how the generalized coordinate time -derivatives relate to generalized speeds. Here these were computed by hand. :: - - >>> kd = [q1d - u3/cos(q2), q2d - u1, q3d - u2 + u3 * tan(q2)] - -Creation of the force list; it is the gravitational force at the center of mass of -the disc. Then we create the disc by assigning a Point to the center of mass -attribute, a ReferenceFrame to the frame attribute, and mass and inertia. Then -we form the body list. :: - - >>> ForceList = [(Dmc, - m * g * Y.z)] - >>> BodyD = RigidBody('BodyD', Dmc, R, m, (I, Dmc)) - >>> BodyList = [BodyD] - -Finally we form the equations of motion, using the same steps we did before. -Specify inertial frame, supply generalized coordinates and speeds, supply -kinematic differential equation dictionary, compute Fr from the force list and -Fr* from the body list, compute the mass matrix and forcing terms, then solve -for the u dots (time derivatives of the generalized speeds). :: - - >>> KM = KanesMethod(N, q_ind=[q1, q2, q3], u_ind=[u1, u2, u3], kd_eqs=kd) - >>> (fr, frstar) = KM.kanes_equations(ForceList, BodyList) - >>> MM = KM.mass_matrix - >>> forcing = KM.forcing - >>> rhs = MM.inv() * forcing - >>> kdd = KM.kindiffdict() - >>> rhs = rhs.subs(kdd) - >>> rhs.simplify() - >>> mprint(rhs) - [(4*g*sin(q2)/5 + 2*r*u2*u3 - r*u3**2*tan(q2))/r] - [ -2*u1*u3/3] - [ (-2*u2 + u3*tan(q2))*u1] - -This concludes the rolling disc example. - -The Rolling Disc, again -======================= - -We will now revisit the rolling disc example, except this time we are bringing -the non-contributing (constraint) forces into evidence. See [Kane1985]_ for a -more thorough explanation of this. Here, we will turn on the automatic -simplifcation done when doing vector operations. It makes the outputs nicer for -small problems, but can cause larger vector operations to hang. :: - - >>> from sympy.physics.mechanics import * - >>> mechanics_printing() - >>> Vector.simp = True - >>> q1, q2, q3, u1, u2, u3 = dynamicsymbols('q1 q2 q3 u1 u2 u3') - >>> q1d, q2d, q3d, u1d, u2d, u3d = dynamicsymbols('q1 q2 q3 u1 u2 u3', 1) - >>> r, m, g = symbols('r m g') - -These two lines introduce the extra quantities needed to find the constraint -forces. :: - - >>> u4, u5, u6, f1, f2, f3 = dynamicsymbols('u4 u5 u6 f1 f2 f3') - -Most of the main code is the same as before. :: - - >>> N = ReferenceFrame('N') - >>> Y = N.orientnew('Y', 'Axis', [q1, N.z]) - >>> L = Y.orientnew('L', 'Axis', [q2, Y.x]) - >>> R = L.orientnew('R', 'Axis', [q3, L.y]) - >>> R.set_ang_vel(N, u1 * L.x + u2 * L.y + u3 * L.z) - >>> R.set_ang_acc(N, R.ang_vel_in(N).dt(R) + (R.ang_vel_in(N) ^ R.ang_vel_in(N))) - -The definition of rolling without slip necessitates that the velocity of the -contact point is zero; as part of bringing the constraint forces into evidence, -we have to introduce speeds at this point, which will by definition always be -zero. They are normal to the ground, along the path which the disc is rolling, -and along the ground in an perpendicular direction. :: - - >>> C = Point('C') - >>> C.set_vel(N, u4 * L.x + u5 * (Y.z ^ L.x) + u6 * Y.z) - >>> Dmc = C.locatenew('Dmc', r * L.z) - >>> vel = Dmc.v2pt_theory(C, N, R) - >>> acc = Dmc.a2pt_theory(C, N, R) - >>> I = inertia(L, m / 4 * r**2, m / 2 * r**2, m / 4 * r**2) - >>> kd = [q1d - u3/cos(q2), q2d - u1, q3d - u2 + u3 * tan(q2)] - -Just as we previously introduced three speeds as part of this process, we also -introduce three forces; they are in the same direction as the speeds, and -represent the constraint forces in those directions. :: - - >>> ForceList = [(Dmc, - m * g * Y.z), (C, f1 * L.x + f2 * (Y.z ^ L.x) + f3 * Y.z)] - >>> BodyD = RigidBody('BodyD', Dmc, R, m, (I, Dmc)) - >>> BodyList = [BodyD] - - >>> KM = KanesMethod(N, q_ind=[q1, q2, q3], u_ind=[u1, u2, u3], kd_eqs=kd, - ... u_auxiliary=[u4, u5, u6]) - >>> (fr, frstar) = KM.kanes_equations(ForceList, BodyList) - >>> MM = KM.mass_matrix - >>> forcing = KM.forcing - >>> rhs = MM.inv() * forcing - >>> kdd = KM.kindiffdict() - >>> rhs = rhs.subs(kdd) - >>> rhs.simplify() - >>> mprint(rhs) - [(4*g*sin(q2)/5 + 2*r*u2*u3 - r*u3**2*tan(q2))/r] - [ -2*u1*u3/3] - [ (-2*u2 + u3*tan(q2))*u1] - >>> from sympy import signsimp, factor_terms - >>> mprint(KM.auxiliary_eqs.applyfunc(lambda w: factor_terms(signsimp(w)))) - [ m*r*(u1*u3 + u2') - f1] - [ m*r*((u1**2 + u2**2)*sin(q2) + (u2*u3 + u3*q3' - u1')*cos(q2)) - f2] - [g*m - m*r*((u1**2 + u2**2)*cos(q2) - (u2*u3 + u3*q3' - u1')*sin(q2)) - f3] - -The Bicycle -=========== - -The bicycle is an interesting system in that it has multiple rigid bodies, -non-holonomic constraints, and a holonomic constraint. The linearized equations -of motion are presented in [Meijaard2007]_. This example will go through -construction of the equations of motion in :mod:`mechanics`. :: - - >>> from sympy import * - >>> from sympy.physics.mechanics import * - >>> print('Calculation of Linearized Bicycle \"A\" Matrix, with States: Roll, Steer, Roll Rate, Steer Rate') - Calculation of Linearized Bicycle "A" Matrix, with States: Roll, Steer, Roll Rate, Steer Rate - - -Note that this code has been crudely ported from Autolev, which is the reason -for some of the unusual naming conventions. It was purposefully as similar as -possible in order to aid initial porting & debugging. We also turn off -Vector.simp (turned on in the last example) to avoid hangups when doing -computations in this problem. :: - - >>> Vector.simp = False - >>> mechanics_printing() - -Declaration of Coordinates & Speeds: -A Simple definitions for qdots: (qd = u) is used in this code. Speeds are: yaw -frame ang. rate, roll frame ang. rate, rear wheel frame ang. rate (spinning -motion), frame ang. rate (pitching motion), steering frame ang. rate, and front -wheel ang. rate (spinning motion). Wheel positions are ignorable coordinates, -so they are not introduced. :: - - >>> q1, q2, q4, q5 = dynamicsymbols('q1 q2 q4 q5') - >>> q1d, q2d, q4d, q5d = dynamicsymbols('q1 q2 q4 q5', 1) - >>> u1, u2, u3, u4, u5, u6 = dynamicsymbols('u1 u2 u3 u4 u5 u6') - >>> u1d, u2d, u3d, u4d, u5d, u6d = dynamicsymbols('u1 u2 u3 u4 u5 u6', 1) - -Declaration of System's Parameters: -The below symbols should be fairly self-explanatory. :: - - >>> WFrad, WRrad, htangle, forkoffset = symbols('WFrad WRrad htangle forkoffset') - >>> forklength, framelength, forkcg1 = symbols('forklength framelength forkcg1') - >>> forkcg3, framecg1, framecg3, Iwr11 = symbols('forkcg3 framecg1 framecg3 Iwr11') - >>> Iwr22, Iwf11, Iwf22, Iframe11 = symbols('Iwr22 Iwf11 Iwf22 Iframe11') - >>> Iframe22, Iframe33, Iframe31, Ifork11 = symbols('Iframe22 Iframe33 Iframe31 Ifork11') - >>> Ifork22, Ifork33, Ifork31, g = symbols('Ifork22 Ifork33 Ifork31 g') - >>> mframe, mfork, mwf, mwr = symbols('mframe mfork mwf mwr') - -Set up reference frames for the system: -N - inertial -Y - yaw -R - roll -WR - rear wheel, rotation angle is ignorable coordinate so not oriented -Frame - bicycle frame -TempFrame - statically rotated frame for easier reference inertia definition -Fork - bicycle fork -TempFork - statically rotated frame for easier reference inertia definition -WF - front wheel, again posses a ignorable coordinate :: - - >>> N = ReferenceFrame('N') - >>> Y = N.orientnew('Y', 'Axis', [q1, N.z]) - >>> R = Y.orientnew('R', 'Axis', [q2, Y.x]) - >>> Frame = R.orientnew('Frame', 'Axis', [q4 + htangle, R.y]) - >>> WR = ReferenceFrame('WR') - >>> TempFrame = Frame.orientnew('TempFrame', 'Axis', [-htangle, Frame.y]) - >>> Fork = Frame.orientnew('Fork', 'Axis', [q5, Frame.x]) - >>> TempFork = Fork.orientnew('TempFork', 'Axis', [-htangle, Fork.y]) - >>> WF = ReferenceFrame('WF') - - -Kinematics of the Bicycle: -First block of code is forming the positions of the relevant points rear wheel -contact -> rear wheel's center of mass -> frame's center of mass + frame/fork connection --> fork's center of mass + front wheel's center of mass -> front wheel contact point. :: - - >>> WR_cont = Point('WR_cont') - >>> WR_mc = WR_cont.locatenew('WR_mc', WRrad * R.z) - >>> Steer = WR_mc.locatenew('Steer', framelength * Frame.z) - >>> Frame_mc = WR_mc.locatenew('Frame_mc', -framecg1 * Frame.x + framecg3 * Frame.z) - >>> Fork_mc = Steer.locatenew('Fork_mc', -forkcg1 * Fork.x + forkcg3 * Fork.z) - >>> WF_mc = Steer.locatenew('WF_mc', forklength * Fork.x + forkoffset * Fork.z) - >>> WF_cont = WF_mc.locatenew('WF_cont', WFrad*(dot(Fork.y, Y.z)*Fork.y - Y.z).normalize()) - -Set the angular velocity of each frame: -Angular accelerations end up being calculated automatically by differentiating -the angular velocities when first needed. :: -u1 is yaw rate -u2 is roll rate -u3 is rear wheel rate -u4 is frame pitch rate -u5 is fork steer rate -u6 is front wheel rate :: - - >>> Y.set_ang_vel(N, u1 * Y.z) - >>> R.set_ang_vel(Y, u2 * R.x) - >>> WR.set_ang_vel(Frame, u3 * Frame.y) - >>> Frame.set_ang_vel(R, u4 * Frame.y) - >>> Fork.set_ang_vel(Frame, u5 * Fork.x) - >>> WF.set_ang_vel(Fork, u6 * Fork.y) - -Form the velocities of the points, using the 2-point theorem. Accelerations -again are calculated automatically when first needed. :: - - >>> WR_cont.set_vel(N, 0) - >>> WR_mc.v2pt_theory(WR_cont, N, WR) - WRrad*(u1*sin(q2) + u3 + u4)*R.x - WRrad*u2*R.y - >>> Steer.v2pt_theory(WR_mc, N, Frame) - WRrad*(u1*sin(q2) + u3 + u4)*R.x - WRrad*u2*R.y + framelength*(u1*sin(q2) + u4)*Frame.x - framelength*(-u1*sin(htangle + q4)*cos(q2) + u2*cos(htangle + q4))*Frame.y - >>> Frame_mc.v2pt_theory(WR_mc, N, Frame) - WRrad*(u1*sin(q2) + u3 + u4)*R.x - WRrad*u2*R.y + framecg3*(u1*sin(q2) + u4)*Frame.x + (-framecg1*(u1*cos(htangle + q4)*cos(q2) + u2*sin(htangle + q4)) - framecg3*(-u1*sin(htangle + q4)*cos(q2) + u2*cos(htangle + q4)))*Frame.y + framecg1*(u1*sin(q2) + u4)*Frame.z - >>> Fork_mc.v2pt_theory(Steer, N, Fork) - WRrad*(u1*sin(q2) + u3 + u4)*R.x - WRrad*u2*R.y + framelength*(u1*sin(q2) + u4)*Frame.x - framelength*(-u1*sin(htangle + q4)*cos(q2) + u2*cos(htangle + q4))*Frame.y + forkcg3*((sin(q2)*cos(q5) + sin(q5)*cos(htangle + q4)*cos(q2))*u1 + u2*sin(htangle + q4)*sin(q5) + u4*cos(q5))*Fork.x + (-forkcg1*((-sin(q2)*sin(q5) + cos(htangle + q4)*cos(q2)*cos(q5))*u1 + u2*sin(htangle + q4)*cos(q5) - u4*sin(q5)) - forkcg3*(-u1*sin(htangle + q4)*cos(q2) + u2*cos(htangle + q4) + u5))*Fork.y + forkcg1*((sin(q2)*cos(q5) + sin(q5)*cos(htangle + q4)*cos(q2))*u1 + u2*sin(htangle + q4)*sin(q5) + u4*cos(q5))*Fork.z - >>> WF_mc.v2pt_theory(Steer, N, Fork) - WRrad*(u1*sin(q2) + u3 + u4)*R.x - WRrad*u2*R.y + framelength*(u1*sin(q2) + u4)*Frame.x - framelength*(-u1*sin(htangle + q4)*cos(q2) + u2*cos(htangle + q4))*Frame.y + forkoffset*((sin(q2)*cos(q5) + sin(q5)*cos(htangle + q4)*cos(q2))*u1 + u2*sin(htangle + q4)*sin(q5) + u4*cos(q5))*Fork.x + (forklength*((-sin(q2)*sin(q5) + cos(htangle + q4)*cos(q2)*cos(q5))*u1 + u2*sin(htangle + q4)*cos(q5) - u4*sin(q5)) - forkoffset*(-u1*sin(htangle + q4)*cos(q2) + u2*cos(htangle + q4) + u5))*Fork.y - forklength*((sin(q2)*cos(q5) + sin(q5)*cos(htangle + q4)*cos(q2))*u1 + u2*sin(htangle + q4)*sin(q5) + u4*cos(q5))*Fork.z - >>> WF_cont.v2pt_theory(WF_mc, N, WF) - WRrad*(u1*sin(q2) + u3 + u4)*R.x - WRrad*u2*R.y + framelength*(u1*sin(q2) + u4)*Frame.x - framelength*(-u1*sin(htangle + q4)*cos(q2) + u2*cos(htangle + q4))*Frame.y + (-WFrad*(sin(q2)*cos(q5) + sin(q5)*cos(htangle + q4)*cos(q2))*((-sin(q2)*sin(q5) + cos(htangle + q4)*cos(q2)*cos(q5))*u1 + u2*sin(htangle + q4)*cos(q5) - u4*sin(q5))/sqrt((-sin(q2)*cos(q5) - sin(q5)*cos(htangle + q4)*cos(q2))*(sin(q2)*cos(q5) + sin(q5)*cos(htangle + q4)*cos(q2)) + 1) + forkoffset*((sin(q2)*cos(q5) + sin(q5)*cos(htangle + q4)*cos(q2))*u1 + u2*sin(htangle + q4)*sin(q5) + u4*cos(q5)))*Fork.x + (forklength*((-sin(q2)*sin(q5) + cos(htangle + q4)*cos(q2)*cos(q5))*u1 + u2*sin(htangle + q4)*cos(q5) - u4*sin(q5)) - forkoffset*(-u1*sin(htangle + q4)*cos(q2) + u2*cos(htangle + q4) + u5))*Fork.y + (WFrad*(sin(q2)*cos(q5) + sin(q5)*cos(htangle + q4)*cos(q2))*(-u1*sin(htangle + q4)*cos(q2) + u2*cos(htangle + q4) + u5)/sqrt((-sin(q2)*cos(q5) - sin(q5)*cos(htangle + q4)*cos(q2))*(sin(q2)*cos(q5) + sin(q5)*cos(htangle + q4)*cos(q2)) + 1) - forklength*((sin(q2)*cos(q5) + sin(q5)*cos(htangle + q4)*cos(q2))*u1 + u2*sin(htangle + q4)*sin(q5) + u4*cos(q5)))*Fork.z - WFrad*((-sin(q2)*sin(q5)*cos(htangle + q4) + cos(q2)*cos(q5))*u6 + u4*cos(q2) + u5*sin(htangle + q4)*sin(q2))/sqrt((-sin(q2)*cos(q5) - sin(q5)*cos(htangle + q4)*cos(q2))*(sin(q2)*cos(q5) + sin(q5)*cos(htangle + q4)*cos(q2)) + 1)*Y.x + WFrad*(u2 + u5*cos(htangle + q4) + u6*sin(htangle + q4)*sin(q5))/sqrt((-sin(q2)*cos(q5) - sin(q5)*cos(htangle + q4)*cos(q2))*(sin(q2)*cos(q5) + sin(q5)*cos(htangle + q4)*cos(q2)) + 1)*Y.y - - -Sets the inertias of each body. Uses the inertia frame to construct the inertia -dyadics. Wheel inertias are only defined by principal moments of inertia, and -are in fact constant in the frame and fork reference frames; it is for this -reason that the orientations of the wheels does not need to be defined. The -frame and fork inertias are defined in the 'Temp' frames which are fixed to the -appropriate body frames; this is to allow easier input of the reference values -of the benchmark paper. Note that due to slightly different orientations, the -products of inertia need to have their signs flipped; this is done later when -entering the numerical value. :: - - >>> Frame_I = (inertia(TempFrame, Iframe11, Iframe22, Iframe33, 0, 0, Iframe31), Frame_mc) - >>> Fork_I = (inertia(TempFork, Ifork11, Ifork22, Ifork33, 0, 0, Ifork31), Fork_mc) - >>> WR_I = (inertia(Frame, Iwr11, Iwr22, Iwr11), WR_mc) - >>> WF_I = (inertia(Fork, Iwf11, Iwf22, Iwf11), WF_mc) - -Declaration of the RigidBody containers. :: - - >>> BodyFrame = RigidBody('BodyFrame', Frame_mc, Frame, mframe, Frame_I) - >>> BodyFork = RigidBody('BodyFork', Fork_mc, Fork, mfork, Fork_I) - >>> BodyWR = RigidBody('BodyWR', WR_mc, WR, mwr, WR_I) - >>> BodyWF = RigidBody('BodyWF', WF_mc, WF, mwf, WF_I) - - >>> print('Before Forming the List of Nonholonomic Constraints.') - Before Forming the List of Nonholonomic Constraints. - -The kinematic differential equations; they are defined quite simply. Each entry -in this list is equal to zero. :: - - >>> kd = [q1d - u1, q2d - u2, q4d - u4, q5d - u5] - -The nonholonomic constraints are the velocity of the front wheel contact point -dotted into the X, Y, and Z directions; the yaw frame is used as it is "closer" -to the front wheel (1 less DCM connecting them). These constraints force the -velocity of the front wheel contact point to be 0 in the inertial frame; the X -and Y direction constraints enforce a "no-slip" condition, and the Z direction -constraint forces the front wheel contact point to not move away from the -ground frame, essentially replicating the holonomic constraint which does not -allow the frame pitch to change in an invalid fashion. :: - - >>> conlist_speed = [WF_cont.vel(N) & Y.x, WF_cont.vel(N) & Y.y, WF_cont.vel(N) & Y.z] - -The holonomic constraint is that the position from the rear wheel contact point -to the front wheel contact point when dotted into the normal-to-ground plane -direction must be zero; effectively that the front and rear wheel contact -points are always touching the ground plane. This is actually not part of the -dynamic equations, but instead is necessary for the linearization process. :: - - >>> conlist_coord = [WF_cont.pos_from(WR_cont) & Y.z] - -The force list; each body has the appropriate gravitational force applied at -its center of mass. :: - - >>> FL = [(Frame_mc, -mframe * g * Y.z), (Fork_mc, -mfork * g * Y.z), - ... (WF_mc, -mwf * g * Y.z), (WR_mc, -mwr * g * Y.z)] - >>> BL = [BodyFrame, BodyFork, BodyWR, BodyWF] - -The N frame is the inertial frame, coordinates are supplied in the order of -independent, dependent coordinates. The kinematic differential equations are -also entered here. Here the independent speeds are specified, followed by the -dependent speeds, along with the non-holonomic constraints. The dependent -coordinate is also provided, with the holonomic constraint. Again, this is only -comes into play in the linearization process, but is necessary for the -linearization to correctly work. :: - - >>> KM = KanesMethod(N, q_ind=[q1, q2, q3], - ... q_dependent=[q4], configuration_constraints=conlist_coord, - ... u_ind=[u2, u3, u5], - ... u_dependent=[u1, u4, u6], velocity_constraints=conlist_speed, - ... kd_eqs=kd) - >>> print('Before Forming Generalized Active and Inertia Forces, Fr and Fr*') - Before Forming Generalized Active and Inertia Forces, Fr and Fr* - >>> (fr, frstar) = KM.kanes_equations(FL, BL) - >>> print('Base Equations of Motion Computed') - Base Equations of Motion Computed - -This is the start of entering in the numerical values from the benchmark paper -to validate the eigenvalues of the linearized equations from this model to the -reference eigenvalues. Look at the aforementioned paper for more information. -Some of these are intermediate values, used to transform values from the paper -into the coordinate systems used in this model. :: - - >>> PaperRadRear = 0.3 - >>> PaperRadFront = 0.35 - >>> HTA = evalf.N(pi/2-pi/10) - >>> TrailPaper = 0.08 - >>> rake = evalf.N(-(TrailPaper*sin(HTA)-(PaperRadFront*cos(HTA)))) - >>> PaperWb = 1.02 - >>> PaperFrameCgX = 0.3 - >>> PaperFrameCgZ = 0.9 - >>> PaperForkCgX = 0.9 - >>> PaperForkCgZ = 0.7 - >>> FrameLength = evalf.N(PaperWb*sin(HTA)-(rake-(PaperRadFront-PaperRadRear)*cos(HTA))) - >>> FrameCGNorm = evalf.N((PaperFrameCgZ - PaperRadRear-(PaperFrameCgX/sin(HTA))*cos(HTA))*sin(HTA)) - >>> FrameCGPar = evalf.N((PaperFrameCgX / sin(HTA) + (PaperFrameCgZ - PaperRadRear - PaperFrameCgX / sin(HTA) * cos(HTA)) * cos(HTA))) - >>> tempa = evalf.N((PaperForkCgZ - PaperRadFront)) - >>> tempb = evalf.N((PaperWb-PaperForkCgX)) - >>> tempc = evalf.N(sqrt(tempa**2+tempb**2)) - >>> PaperForkL = evalf.N((PaperWb*cos(HTA)-(PaperRadFront-PaperRadRear)*sin(HTA))) - >>> ForkCGNorm = evalf.N(rake+(tempc * sin(pi/2-HTA-acos(tempa/tempc)))) - >>> ForkCGPar = evalf.N(tempc * cos((pi/2-HTA)-acos(tempa/tempc))-PaperForkL) - -Here is the final assembly of the numerical values. The symbol 'v' is the -forward speed of the bicycle (a concept which only makes sense in the upright, -static equilibrium case?). These are in a dictionary which will later be -substituted in. Again the sign on the *product* of inertia values is flipped -here, due to different orientations of coordinate systems. :: - - >>> v = Symbol('v') - >>> val_dict = {WFrad: PaperRadFront, WRrad: PaperRadRear, htangle: HTA, forkoffset: rake, forklength: PaperForkL, framelength: FrameLength, forkcg1: ForkCGPar, forkcg3: ForkCGNorm, framecg1: FrameCGNorm, framecg3: FrameCGPar, Iwr11: 0.0603, Iwr22: 0.12, Iwf11: 0.1405, Iwf22: 0.28, Ifork11: 0.05892, Ifork22: 0.06, Ifork33: 0.00708, Ifork31: 0.00756, Iframe11: 9.2, Iframe22: 11, Iframe33: 2.8, Iframe31: -2.4, mfork: 4, mframe: 85, mwf: 3, mwr: 2, g: 9.81, q1: 0, q2: 0, q4: 0, q5: 0, u1: 0, u2: 0, u3: v/PaperRadRear, u4: 0, u5: 0, u6: v/PaperRadFront} - >>> kdd = KM.kindiffdict() - >>> print('Before Linearization of the \"Forcing\" Term') - Before Linearization of the "Forcing" Term - -Linearizes the forcing vector; the equations are set up as MM udot = forcing, -where MM is the mass matrix, udot is the vector representing the time -derivatives of the generalized speeds, and forcing is a vector which contains -both external forcing terms and internal forcing terms, such as centripetal or -Coriolis forces. This actually returns a matrix with as many rows as *total* -coordinates and speeds, but only as many columns as independent coordinates and -speeds. (Note that below this is commented out, as it takes a few minutes to -run, which is not good when performing the doctests) :: - - >>> # forcing_lin = KM.linearize()[0].subs(sub_dict) - -As mentioned above, the size of the linearized forcing terms is expanded to -include both q's and u's, so the mass matrix must have this done as well. This -will likely be changed to be part of the linearized process, for future -reference. :: - - >>> MM_full = (KM._k_kqdot).row_join(zeros(4, 6)).col_join((zeros(6, 4)).row_join(KM.mass_matrix)) - >>> print('Before Substitution of Numerical Values') - Before Substitution of Numerical Values - -I think this is pretty self explanatory. It takes a really long time though. -I've experimented with using evalf with substitution, this failed due to -maximum recursion depth being exceeded; I also tried lambdifying this, and it -is also not successful. (again commented out due to speed) :: - - >>> # MM_full = MM_full.subs(val_dict) - >>> # forcing_lin = forcing_lin.subs(val_dict) - >>> # print('Before .evalf() call') - - >>> # MM_full = MM_full.evalf() - >>> # forcing_lin = forcing_lin.evalf() - -Finally, we construct an "A" matrix for the form xdot = A x (x being the state -vector, although in this case, the sizes are a little off). The following line -extracts only the minimum entries required for eigenvalue analysis, which -correspond to rows and columns for lean, steer, lean rate, and steer rate. -(this is all commented out due to being dependent on the above code, which is -also commented out):: - - >>> # Amat = MM_full.inv() * forcing_lin - >>> # A = Amat.extract([1,2,4,6],[1,2,3,5]) - >>> # print(A) - >>> # print('v = 1') - >>> # print(A.subs(v, 1).eigenvals()) - >>> # print('v = 2') - >>> # print(A.subs(v, 2).eigenvals()) - >>> # print('v = 3') - >>> # print(A.subs(v, 3).eigenvals()) - >>> # print('v = 4') - >>> # print(A.subs(v, 4).eigenvals()) - >>> # print('v = 5') - >>> # print(A.subs(v, 5).eigenvals()) - -Upon running the above code yourself, enabling the commented out lines, compare -the computed eigenvalues to those is the referenced paper. This concludes the -bicycle example. + rollingdisc_example.rst + bicycle_example.rst diff -Nru python3-sympy-0.7.2/doc/src/modules/physics/mechanics/index.rst python3-sympy-0.7.3/doc/src/modules/physics/mechanics/index.rst --- python3-sympy-0.7.2/doc/src/modules/physics/mechanics/index.rst 2012-10-17 01:53:14.000000000 +0000 +++ python3-sympy-0.7.3/doc/src/modules/physics/mechanics/index.rst 2013-07-13 17:50:18.000000000 +0000 @@ -13,13 +13,52 @@ Mechanics ========= -In physics, mechanics describes conditions of rest or motion; statics or -dynamics. First, an idealized representation of a system is described. Next, we -use physical laws to generate equations that define the system's behaviors. -Then, we solve these equations, in multiple possible ways. Finally, we extract -information from these equations and solutions. Mechanics is currently set up -to create equations of motion, for dynamics. It is also limited to rigid bodies -and particles. +In physics, mechanics describes conditions of rest (statics) or motion +(dynamics). There are a few common steps to all mechanics problems. First, an +idealized representation of a system is described. Next, we use physical laws +to generate equations that define the system's behavior. Then, we solve these +equations, sometimes analytically but usually numerically. Finally, we extract +information from these equations and solutions. The current scope of the module +is multi-body dynamics: the motion of systems of multiple particles and/or +rigid bodies. For example, this module could be used to understand the motion +of a double pendulum, planets, robotic manipulators, bicycles, and any +other system of rigid bodies that may fascinate us. + +Often, the objective in multi-body dynamics is to obtain the trajectory of a +system of rigid bodies through time. The challenge for this task is to first +formulate the equations of motion of the system. Once they are formulated, they +must be solved, that is, integrated forward in time. When digital computers +came around, solving became the easy part of the problem. Now, we can +tackle more complicated problems, which leaves the challenge of formulating the +equations. + +The term "equations of motion" is used to describe the application of Newton's +second law to multi-body systems. The form of the equations of motion depends +on the method used to generate them. This package implements two of these +methods: Kane's method and Lagrange's method. This module facilitates the +formulation of equations of motion, which can then be solved (integrated) using +generic ordinary differential equation (ODE) solvers. + +The approach to a particular class of dynamics problems, that of forward +dynamics, has the following steps: + +1. describing the system's geometry and configuration, +2. specifying the way the system can move, including constraints on its motion +3. describing the external forces and moments on the system, +4. combining the above information according to Newton's second law + (:math:`\mathbf{F}=m\mathbf{a}`), and +5. organizing the resulting equations so that they can be integrated to obtain + the system's trajectory through time. + +Together with the rest of :mod:`SymPy`, this module performs steps 4 and 5, +provided that the user can perform 1 through 3 for the module. That is to say, +the user must provide a complete representation of the free +body diagrams that themselves represent the system, with which this code can +provide equations of motion in a form amenable to numerical integration. Step +5 above amounts to arduous algebra for even fairly simple multi-body systems. +Thus, it is desirable to use a symbolic math package, such as Sympy, to +perform this step. It is for this reason that this module is a part of Sympy. +Step 4 amounts to this specific module, sympy.physics.mechanics. Guide to Mechanics diff -Nru python3-sympy-0.7.2/doc/src/modules/physics/mechanics/kane.rst python3-sympy-0.7.3/doc/src/modules/physics/mechanics/kane.rst --- python3-sympy-0.7.2/doc/src/modules/physics/mechanics/kane.rst 2012-10-17 01:53:14.000000000 +0000 +++ python3-sympy-0.7.3/doc/src/modules/physics/mechanics/kane.rst 2013-07-13 17:50:18.000000000 +0000 @@ -35,7 +35,7 @@ :math:`\mathbf{M}(q, t) \dot{u} = \mathbf{f}(q, \dot{q}, u, t)` -For a non-holonomic system with "o" total speeds and "m" motion constraints, we +For a non-holonomic system with `o` total speeds and `m` motion constraints, we will get o - m equations. The mass-matrix/forcing equations are then augmented in the following fashion: @@ -50,10 +50,10 @@ Kane's Method in Physics/Mechanics ================================== -Formulation of the equations of motion in :mod:`mechanics` starts with creation -of a ``KanesMethod`` object. Upon initialization of the ``KanesMethod`` object, -an inertial reference frame needs to be supplied. along with some basic system -information, suchs as coordinates and speeds :: +The formulation of the equations of motion in :mod:`mechanics` starts with +creation of a ``KanesMethod`` object. Upon initialization of the +``KanesMethod`` object, an inertial reference frame needs to be supplied. along +with some basic system information, suchs as coordinates and speeds :: >>> from sympy.physics.mechanics import * >>> N = ReferenceFrame('N') @@ -133,9 +133,9 @@ >>> KM = KanesMethod(N, [q], [u], [qd - u]) >>> (fr, frstar) = KM.kanes_equations(FL, BL) >>> KM.mass_matrix - [5] + Matrix([[5]]) >>> KM.forcing - [7] + Matrix([[7]]) When there are motion constraints, the mass matrix is augmented by the :math:`k_{dnh}(q, t)` matrix, and the forcing vector by the :math:`f_{dnh}(q, @@ -146,11 +146,13 @@ o) x (n + o), or square and the size of all coordinates and speeds. :: >>> KM.mass_matrix_full - [1, 0] - [0, 5] + Matrix([ + [1, 0], + [0, 5]]) >>> KM.forcing_full - [u] - [7] + Matrix([ + [u], + [7]]) The forcing vector can be linearized as well; its Jacobian is taken only with respect to the independent coordinates and speeds. The linearized forcing @@ -165,8 +167,146 @@ equations, an error with be raised. :: >>> KM.linearize()[0] - [0, 1] - [0, 0] + Matrix([ + [0, 1], + [0, 0]]) Exploration of the provided examples is encouraged in order to gain more understanding of the ``KanesMethod`` object. + +====================================== +Lagrange's Method in Physics/Mechanics +====================================== + +Structure of Equations +====================== + +In :mod:`mechanics` we are assuming there are 3 basic sets of equations needed +to describe a system; the constraint equations, the time differentiated +constraint equations and the dynamic equations. + +.. math:: + \mathbf{m_{c}}(q, t) \dot{q} + \mathbf{f_{c}}(q, t) &= 0\\ + \mathbf{m_{dc}}(\dot{q}, q, t) \ddot{q} + \mathbf{f_{dc}}(\dot{q}, q, t) &= 0\\ + \mathbf{m_d}(\dot{q}, q, t) \ddot{q} + \mathbf{\Lambda_c}(q, t) + \lambda + \mathbf{f_d}(\dot{q}, q, t) &= 0\\ + +In this module, the expressions formed by using Lagrange's equations of the +second kind are rearranged into the following form: + + :math:`\mathbf{M}(q, t) x = \mathbf{f}(q, \dot{q}, t)` + +where in the case of a system without constraints: + + :math:`x = \ddot{q}` + +For a constrained system with `n` generalized speeds and `m` constraints, we +will get n - m equations. The mass-matrix/forcing equations are then augmented +in the following fashion: + +.. math:: + x = \begin{bmatrix} \ddot{q} \\ \lambda \end{bmatrix} \\ + \mathbf{M}(q, t) &= \begin{bmatrix} \mathbf{m_d}(q, t) & + \mathbf{\Lambda_c}(q, t) \end{bmatrix}\\ + \mathbf{F}(\dot{q}, q, t) &= \begin{bmatrix} \mathbf{f_d}(q, \dot{q}, t) + \end{bmatrix}\\ + + +Lagrange's Method in Physics/Mechanics +====================================== + +The formulation of the equations of motion in :mod:`mechanics` using +Lagrange's Method starts with the creation of generalized coordinates and a +Lagrangian. The Lagrangian can either be created with the ``Lagrangian`` +function or can be a user supplied function. In this case we will supply the +Lagrangian. :: + + >>> from sympy.physics.mechanics import * + >>> q1, q2 = dynamicsymbols('q1 q2') + >>> q1d, q2d = dynamicsymbols('q1 q2', 1) + >>> L = q1d**2 + q2d**2 + +To formulate the equations of motion we create a ``LagrangesMethod`` +object. The Lagrangian and generalized coordinates need to be supplied upon +initialization. :: + + >>> LM = LagrangesMethod(L, [q1, q2]) + +With that the equations of motion can be formed. :: + + >>> mechanics_printing() + >>> LM.form_lagranges_equations() + Matrix([ + [2*q1''], + [2*q2'']]) + +It is possible to obtain the mass matrix and the forcing vector. :: + + >>> LM.mass_matrix + Matrix([ + [2, 0], + [0, 2]]) + + >>> LM.forcing + Matrix([ + [0], + [0]]) + +If there are any holonomic or non-holonomic constraints, they must be supplied +as keyword arguments in a list of expressions which are equal to zero. It +should be noted that :mod:`mechanics` requires that the holonomic constraint +equations must be supplied as velocity level constraint equations i.e. the +holonomic constraint equations must be supplied after they have been +differentiated with respect to time. Modifying the example above, the equations +of motion can then be generated: :: + + >>> LM = LagrangesMethod(L, [q1, q2], coneqs = [q1d - q2d]) + +When the equations of motion are generated in this case, the Lagrange +multipliers are introduced; they are represented by ``lam1`` in this case. In +general, there will be as many multipliers as there are constraint equations. :: + + >>> LM.form_lagranges_equations() + Matrix([ + [ lam1 + 2*q1''], + [-lam1 + 2*q2'']]) + +Also in the case of systems with constraints, the 'full' mass matrix is +augmented by the :math:`k_{dc}(q, t)` matrix, and the forcing vector by the +:math:`f_{dc}(q, \dot{q}, t)` vector. The 'full' mass matrix is of size +(2n + o) x (2n + o), i.e. it's a square matrix. :: + + >>> LM.mass_matrix_full + Matrix([ + [1, 0, 0, 0, 0], + [0, 1, 0, 0, 0], + [0, 0, 2, 0, -1], + [0, 0, 0, 2, 1], + [0, 0, 1, -1, 0]]) + >>> LM.forcing_full + Matrix([ + [q1'], + [q2'], + [ 0], + [ 0], + [ 0]]) + +If there are any non-conservative forces or moments acting on the system, +they must also be supplied as keyword arguments in a list of 2-tuples of the +form ``(Point, Vector)`` or ``(ReferenceFrame, Vector)`` where the ``Vector`` +represents the non-conservative forces and torques. Along with this 2-tuple, +the inertial frame must also be specified as a keyword argument. This is shown +below by modifying the example above: :: + + >>> N = ReferenceFrame('N') + >>> P = Point('P') + >>> P.set_vel(N, q1d * N.x) + >>> FL = [(P, 7 * N.x)] + >>> LM = LagrangesMethod(L, [q1, q2], forcelist = FL, frame = N) + >>> LM.form_lagranges_equations() + Matrix([ + [2*q1'' - 7], + [ 2*q2'']]) + +Exploration of the provided examples is encouraged in order to gain more +understanding of the ``LagrangesMethod`` object. diff -Nru python3-sympy-0.7.2/doc/src/modules/physics/mechanics/masses.rst python3-sympy-0.7.3/doc/src/modules/physics/mechanics/masses.rst --- python3-sympy-0.7.2/doc/src/modules/physics/mechanics/masses.rst 2012-10-17 01:53:14.000000000 +0000 +++ python3-sympy-0.7.3/doc/src/modules/physics/mechanics/masses.rst 2013-07-13 17:50:18.000000000 +0000 @@ -43,10 +43,16 @@ >>> from sympy.physics.mechanics import ReferenceFrame, inertia >>> N = ReferenceFrame('N') - >>> # supply a reference frame and the moments of inertia if the object is symmetrical + + Supply a reference frame and the moments of inertia if the object + is symmetrical: + >>> inertia(N, 1, 2, 3) (N.x|N.x) + 2*(N.y|N.y) + 3*(N.z|N.z) - >>> # supply a reference frame along with the products and moments of inertia for a general object + + Supply a reference frame along with the products and moments of inertia + for a general object: + >>> inertia(N, 1, 2, 3, 4, 5, 6) (N.x|N.x) + 4*(N.x|N.y) + 6*(N.x|N.z) + 4*(N.y|N.x) + 2*(N.y|N.y) + 5*(N.y|N.z) + 6*(N.z|N.x) + 5*(N.z|N.y) + 3*(N.z|N.z) @@ -171,3 +177,218 @@ One can also take the time derivative of dyadics or express them in different frames, just like with vectors. + +Linear Momentum +=============== + +The linear momentum of a particle P is defined as: + +.. math:: + L_P = m\mathbf{v} + +where :math:`m` is the mass of the particle P and :math:`\mathbf{v}` is the +velocity of the particle in the inertial frame.[Likins1973]_. + +Similarly the linear momentum of a rigid body is defined as: + +.. math:: + L_B = m\mathbf{v^*} + +where :math:`m` is the mass of the rigid body, B, and :math:`\mathbf{v^*}` is +the velocity of the mass center of B in the inertial frame. + +Angular Momentum +================ + +The angular momentum of a particle P about an arbitrary point O in an inertial +frame N is defined as: + +.. math:: + ^N \mathbf{H} ^ {P/O} = \mathbf{r} \times m\mathbf{v} + +where :math:`\mathbf{r}` is a position vector from point O to the particle of +mass :math:`m` and :math:`\mathbf{v}` is the velocity of the particle in the +inertial frame. + +Similarly the angular momentum of a rigid body B about a point O in an inertial +frame N is defined as: + +.. math:: + ^N \mathbf{H} ^ {B/O} = ^N \mathbf{H} ^ {B/B^*} + ^N \mathbf{H} ^ {B^*/O} + +where the angular momentum of the body about it's mass center is: + +.. math:: + ^N \mathbf{H} ^ {B/B^*} = \mathbf{I^*} \cdot \omega + +and the angular momentum of the mass center about O is: + +.. math:: + ^N \mathbf{H} ^ {B^*/O} = \mathbf{r^*} \times m \mathbf{v^*} + +where :math:`\mathbf{I^*}` is the central inertia dyadic of rigid body B, +:math:`\omega` is the inertial angular velocity of B, :math:`\mathbf{r^*}` is a +position vector from point O to the mass center of B, :math:`m` is the mass of +B and :math:`\mathbf{v^*}` is the velocity of the mass center in the inertial +frame. + +Using momenta functions in Mechanics +==================================== + +The following example shows how to use the momenta functions in +:mod:`mechanics`. + +One begins by creating the requisite symbols to describe the system. Then +the reference frame is created and the kinematics are done. :: + + >> from sympy import symbols + >> from sympy.physics.mechanics import dynamicsymbols, ReferenceFrame + >> from sympy.physics.mechanics import RigidBody, Particle, Point, outer + >> from symp.physics.mechanics import linear_momentum, angular_momentum + >> m, M, l1 = symbols('m M l1') + >> q1d = dynamicsymbols('q1d') + >> N = ReferenceFrame('N') + >> O = Point('O') + >> O.set_vel(N, 0 * N.x) + >> Ac = O.locatenew('Ac', l1 * N.x) + >> P = Ac.locatenew('P', l1 * N.x) + >> a = ReferenceFrame('a') + >> a.set_ang_vel(N, q1d * N.z) + >> Ac.v2pt_theory(O, N, a) + >> P.v2pt_theory(O, N, a) + +Finally, the bodies that make up the system are created. In this case the +system consists of a particle Pa and a RigidBody A. :: + + >> Pa = Particle('Pa', P, m) + >> I = outer(N.z, N.z) + >> A = RigidBody('A', Ac, a, M, (I, Ac)) + +Then one can either choose to evaluate the the momenta of individual components +of the system or of the entire system itself. :: + + >> linear_momentum(N,A) + M*l1*q1d*N.y + >> angular_momentum(O, N, Pa) + 4*l1**2*m*q1d*N.z + >> linear_momentum(N, A, Pa) + (M*l1*q1d + 2*l1*m*q1d)*N.y + >> angular_momentum(O, N, A, Pa) + (4*l1**2*m*q1d + q1d)*N.z + +It should be noted that the user can determine either momenta in any frame +in :mod:`mechanics` as the user is allowed to specify the reference frame when +calling the function. In other words the user is not limited to determining +just inertial linear and angular momenta. Please refer to the docstrings on +each function to learn more about how each function works precisely. + +Kinetic Energy +============== + +The kinetic energy of a particle P is defined as + +.. math:: + T_P = \frac{1}{2} m \mathbf{v^2} + +where :math:`m` is the mass of the particle P and :math:`\mathbf{v}` +is the velocity of the particle in the inertial frame. + +Similarly the kinetic energy of a rigid body B is defined as + +.. math:: + T_B = T_t + T_r + +where the translational kinetic energy is given by: + +.. math:: + T_t = \frac{1}{2} m \mathbf{v^*} \cdot \mathbf{v^*} + +and the rotational kinetic energy is given by: + +.. math:: + T_r = \frac{1}{2} \omega \cdot \mathbf{I^*} \cdot \omega + +where :math:`m` is the mass of the rigid body, :math:`\mathbf{v^*}` is the +velocity of the mass center in the inertial frame, :math:`\omega` is the +inertial angular velocity of the body and :math:`\mathbf{I^*}` is the central +inertia dyadic. + +Potential Energy +================ + +Potential energy is defined as the energy possessed by a body or system by +virtue of its position or arrangement. + +Since there are a variety of definitions for potential energy, this is not +discussed further here. One can learn more about this in any elementary text +book on dynamics. + +Lagrangian +========== + +The Lagrangian of a body or a system of bodies is defined as: + +.. math:: + \mathcal{L} = T - V + +where :math:`T` and :math:`V` are the kinetic and potential energies +respectively. + +Using energy functions in Mechanics +=================================== + +The following example shows how to use the energy functions in +:mod:`mechanics`. + +As was discussed above in the momenta functions, one first creates the system +by going through an identical procedure. :: + + >> from sympy import symbols + >> from sympy.physics.mechanics import dynamicsymbols, ReferenceFrame, outer + >> from sympy.physics.mechanics import RigidBody, Particle, mechanics_printing + >> from symp.physics.mechanics import kinetic_energy, potential_energy, Point + >> mechanics_printing() + >> m, M, l1, g, h, H = symbols('m M l1 g h H') + >> omega = dynamicsymbols('omega') + >> N = ReferenceFrame('N') + >> O = Point('O') + >> O.set_vel(N, 0 * N.x) + >> Ac = O.locatenew('Ac', l1 * N.x) + >> P = Ac.locatenew('P', l1 * N.x) + >> a = ReferenceFrame('a') + >> a.set_ang_vel(N, omega * N.z) + >> Ac.v2pt_theory(O, N, a) + >> P.v2pt_theory(O, N, a) + >> Pa = Particle('Pa', P, m) + >> I = outer(N.z, N.z) + >> A = RigidBody('A', Ac, a, M, (I, Ac)) + +The user can then determine the kinetic energy of any number of entities of the +system: :: + + >> kinetic_energy(N, Pa) + 2*l1**2*m*q1d**2 + >> kinetic_energy(N, Pa, A) + M*l1**2*q1d**2/2 + 2*l1**2*m*q1d**2 + q1d**2/2 + +It should be noted that the user can determine either kinetic energy relative +to any frame in :mod:`mechanics` as the user is allowed to specify the +reference frame when calling the function. In other words the user is not +limited to determining just inertial kinetic energy. + +For potential energies, the user must first specify the potential energy of +every entity of the system using the :mod:`set_potential_energy` method. The +potential energy of any number of entities comprising the system can then be +determined: :: + + >> Pa.set_potential_energy(m * g * h) + >> A.set_potential_energy(M * g * H) + >> potential_energy(A, Pa) + H*M*g + g*h*m + +One can also determine the Lagrangian for this system: :: + + >> Lagrangian(Pa, A) + -H*M*g + M*l1**2*q1d**2/2 - g*h*m + 2*l1**2*m*q1d**2 + q1d**2/2 + +Please refer to the docstrings to learn more about each function. diff -Nru python3-sympy-0.7.2/doc/src/modules/physics/mechanics/reference.rst python3-sympy-0.7.3/doc/src/modules/physics/mechanics/reference.rst --- python3-sympy-0.7.2/doc/src/modules/physics/mechanics/reference.rst 2012-10-17 01:53:14.000000000 +0000 +++ python3-sympy-0.7.3/doc/src/modules/physics/mechanics/reference.rst 2013-07-13 17:50:18.000000000 +0000 @@ -14,3 +14,5 @@ 2011. . .. [WikiDyadicProducts] "Dyadic Product." Wikipedia, the Free Encyclopedia. Web. 05 Aug. 2011. . +.. [Likins1973] Likins, Peter W. Elements of Engineering Mechanics. + McGraw-Hill, Inc. 1973. Print. diff -Nru python3-sympy-0.7.2/doc/src/modules/physics/mechanics/rollingdisc.svg python3-sympy-0.7.3/doc/src/modules/physics/mechanics/rollingdisc.svg --- python3-sympy-0.7.2/doc/src/modules/physics/mechanics/rollingdisc.svg 1970-01-01 00:00:00.000000000 +0000 +++ python3-sympy-0.7.3/doc/src/modules/physics/mechanics/rollingdisc.svg 2013-07-13 17:50:18.000000000 +0000 @@ -0,0 +1,237 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + R + N + nz + nx + ny + rx + ry + rz + + + + + + + + diff -Nru python3-sympy-0.7.2/doc/src/modules/physics/mechanics/rollingdisc_example.rst python3-sympy-0.7.3/doc/src/modules/physics/mechanics/rollingdisc_example.rst --- python3-sympy-0.7.2/doc/src/modules/physics/mechanics/rollingdisc_example.rst 1970-01-01 00:00:00.000000000 +0000 +++ python3-sympy-0.7.3/doc/src/modules/physics/mechanics/rollingdisc_example.rst 2013-07-13 17:50:18.000000000 +0000 @@ -0,0 +1,21 @@ +============== +A rolling disc +============== + +The disc is assumed to be infinitely thin, in contact with the ground at only 1 +point, and it is rolling without slip on the ground. See the image below. + +.. image:: rollingdisc.* + :height: 350 + :width: 350 + :align: center + +We model the rolling disc in three different ways, to show more of the +functionality of this module. + +.. toctree:: + :maxdepth: 1 + + rollingdisc_example_kane.rst + rollingdisc_example_kane_constraints.rst + rollingdisc_example_lagrange.rst diff -Nru python3-sympy-0.7.2/doc/src/modules/physics/mechanics/rollingdisc_example_kane.rst python3-sympy-0.7.3/doc/src/modules/physics/mechanics/rollingdisc_example_kane.rst --- python3-sympy-0.7.2/doc/src/modules/physics/mechanics/rollingdisc_example_kane.rst 1970-01-01 00:00:00.000000000 +0000 +++ python3-sympy-0.7.3/doc/src/modules/physics/mechanics/rollingdisc_example_kane.rst 2013-07-13 17:53:31.000000000 +0000 @@ -0,0 +1,85 @@ +================================== +A rolling disc, with Kane's method +================================== + +Here the definition of the rolling disc's kinematics is formed from the contact +point up, removing the need to introduce generalized speeds. Only 3 +configuration and three speed variables are need to describe this system, along +with the disc's mass and radius, and the local gravity (note that mass will +drop out). :: + + >>> from sympy import symbols, sin, cos, tan + >>> from sympy.physics.mechanics import * + >>> q1, q2, q3, u1, u2, u3 = dynamicsymbols('q1 q2 q3 u1 u2 u3') + >>> q1d, q2d, q3d, u1d, u2d, u3d = dynamicsymbols('q1 q2 q3 u1 u2 u3', 1) + >>> r, m, g = symbols('r m g') + >>> mechanics_printing() + +The kinematics are formed by a series of simple rotations. Each simple rotation +creates a new frame, and the next rotation is defined by the new frame's basis +vectors. This example uses a 3-1-2 series of rotations, or Z, X, Y series of +rotations. Angular velocity for this is defined using the second frame's basis +(the lean frame); it is for this reason that we defined intermediate frames, +rather than using a body-three orientation. :: + + >>> N = ReferenceFrame('N') + >>> Y = N.orientnew('Y', 'Axis', [q1, N.z]) + >>> L = Y.orientnew('L', 'Axis', [q2, Y.x]) + >>> R = L.orientnew('R', 'Axis', [q3, L.y]) + >>> R.set_ang_vel(N, u1 * L.x + u2 * L.y + u3 * L.z) + >>> R.set_ang_acc(N, R.ang_vel_in(N).dt(R) + (R.ang_vel_in(N) ^ R.ang_vel_in(N))) + +This is the translational kinematics. We create a point with no velocity +in N; this is the contact point between the disc and ground. Next we form +the position vector from the contact point to the disc's center of mass. +Finally we form the velocity and acceleration of the disc. :: + + >>> C = Point('C') + >>> C.set_vel(N, 0) + >>> Dmc = C.locatenew('Dmc', r * L.z) + >>> Dmc.v2pt_theory(C, N, R) + r*u2*L.x - r*u1*L.y + >>> Dmc.a2pt_theory(C, N, R) + (r*u1*u3 + r*u2')*L.x + (-r*(-u3*q3' + u1') + r*u2*u3)*L.y + (-r*u1**2 - r*u2**2)*L.z + +This is a simple way to form the inertia dyadic. The inertia of the disc does +not change within the lean frame as the disc rolls; this will make for simpler +equations in the end. :: + + >>> I = inertia(L, m / 4 * r**2, m / 2 * r**2, m / 4 * r**2) + >>> mprint(I) + m*r**2/4*(L.x|L.x) + m*r**2/2*(L.y|L.y) + m*r**2/4*(L.z|L.z) + +Kinematic differential equations; how the generalized coordinate time +derivatives relate to generalized speeds. Here these were computed by hand. :: + + >>> kd = [q1d - u3/cos(q2), q2d - u1, q3d - u2 + u3 * tan(q2)] + +Creation of the force list; it is the gravitational force at the center of mass of +the disc. Then we create the disc by assigning a Point to the center of mass +attribute, a ReferenceFrame to the frame attribute, and mass and inertia. Then +we form the body list. :: + + >>> ForceList = [(Dmc, - m * g * Y.z)] + >>> BodyD = RigidBody('BodyD', Dmc, R, m, (I, Dmc)) + >>> BodyList = [BodyD] + +Finally we form the equations of motion, using the same steps we did before. +Specify inertial frame, supply generalized coordinates and speeds, supply +kinematic differential equation dictionary, compute Fr from the force list and +Fr* from the body list, compute the mass matrix and forcing terms, then solve +for the u dots (time derivatives of the generalized speeds). :: + + >>> KM = KanesMethod(N, q_ind=[q1, q2, q3], u_ind=[u1, u2, u3], kd_eqs=kd) + >>> (fr, frstar) = KM.kanes_equations(ForceList, BodyList) + >>> MM = KM.mass_matrix + >>> forcing = KM.forcing + >>> rhs = MM.inv() * forcing + >>> kdd = KM.kindiffdict() + >>> rhs = rhs.subs(kdd) + >>> rhs.simplify() + >>> mprint(rhs) + Matrix([ + [4*g*sin(q2)/(5*r) + 2*u2*u3 - u3**2*tan(q2)], + [ -2*u1*u3/3], + [ (-2*u2 + u3*tan(q2))*u1]]) diff -Nru python3-sympy-0.7.2/doc/src/modules/physics/mechanics/rollingdisc_example_kane_constraints.rst python3-sympy-0.7.3/doc/src/modules/physics/mechanics/rollingdisc_example_kane_constraints.rst --- python3-sympy-0.7.2/doc/src/modules/physics/mechanics/rollingdisc_example_kane_constraints.rst 1970-01-01 00:00:00.000000000 +0000 +++ python3-sympy-0.7.3/doc/src/modules/physics/mechanics/rollingdisc_example_kane_constraints.rst 2013-07-13 17:53:31.000000000 +0000 @@ -0,0 +1,75 @@ +======================================================== +A rolling disc, with Kane's method and constraint forces +======================================================== + +We will now revisit the rolling disc example, except this time we are bringing +the non-contributing (constraint) forces into evidence. See [Kane1985]_ for a +more thorough explanation of this. Here, we will turn on the automatic +simplifcation done when doing vector operations. It makes the outputs nicer for +small problems, but can cause larger vector operations to hang. :: + + >>> from sympy import symbols, sin, cos, tan + >>> from sympy.physics.mechanics import * + >>> mechanics_printing() + >>> q1, q2, q3, u1, u2, u3 = dynamicsymbols('q1 q2 q3 u1 u2 u3') + >>> q1d, q2d, q3d, u1d, u2d, u3d = dynamicsymbols('q1 q2 q3 u1 u2 u3', 1) + >>> r, m, g = symbols('r m g') + +These two lines introduce the extra quantities needed to find the constraint +forces. :: + + >>> u4, u5, u6, f1, f2, f3 = dynamicsymbols('u4 u5 u6 f1 f2 f3') + +Most of the main code is the same as before. :: + + >>> N = ReferenceFrame('N') + >>> Y = N.orientnew('Y', 'Axis', [q1, N.z]) + >>> L = Y.orientnew('L', 'Axis', [q2, Y.x]) + >>> R = L.orientnew('R', 'Axis', [q3, L.y]) + >>> R.set_ang_vel(N, u1 * L.x + u2 * L.y + u3 * L.z) + >>> R.set_ang_acc(N, R.ang_vel_in(N).dt(R) + (R.ang_vel_in(N) ^ R.ang_vel_in(N))) + +The definition of rolling without slip necessitates that the velocity of the +contact point is zero; as part of bringing the constraint forces into evidence, +we have to introduce speeds at this point, which will by definition always be +zero. They are normal to the ground, along the path which the disc is rolling, +and along the ground in an perpendicular direction. :: + + >>> C = Point('C') + >>> C.set_vel(N, u4 * L.x + u5 * (Y.z ^ L.x) + u6 * Y.z) + >>> Dmc = C.locatenew('Dmc', r * L.z) + >>> vel = Dmc.v2pt_theory(C, N, R) + >>> acc = Dmc.a2pt_theory(C, N, R) + >>> I = inertia(L, m / 4 * r**2, m / 2 * r**2, m / 4 * r**2) + >>> kd = [q1d - u3/cos(q2), q2d - u1, q3d - u2 + u3 * tan(q2)] + +Just as we previously introduced three speeds as part of this process, we also +introduce three forces; they are in the same direction as the speeds, and +represent the constraint forces in those directions. :: + + >>> ForceList = [(Dmc, - m * g * Y.z), (C, f1 * L.x + f2 * (Y.z ^ L.x) + f3 * Y.z)] + >>> BodyD = RigidBody('BodyD', Dmc, R, m, (I, Dmc)) + >>> BodyList = [BodyD] + + >>> KM = KanesMethod(N, q_ind=[q1, q2, q3], u_ind=[u1, u2, u3], kd_eqs=kd, + ... u_auxiliary=[u4, u5, u6]) + >>> (fr, frstar) = KM.kanes_equations(ForceList, BodyList) + >>> MM = KM.mass_matrix + >>> forcing = KM.forcing + >>> rhs = MM.inv() * forcing + >>> kdd = KM.kindiffdict() + >>> rhs = rhs.subs(kdd) + >>> rhs.simplify() + >>> mprint(rhs) + Matrix([ + [4*g*sin(q2)/(5*r) + 2*u2*u3 - u3**2*tan(q2)], + [ -2*u1*u3/3], + [ (-2*u2 + u3*tan(q2))*u1]]) + >>> from sympy import trigsimp, signsimp, collect, factor_terms + >>> def simplify_auxiliary_eqs(w): + ... return signsimp(trigsimp(collect(collect(factor_terms(w), f2), m*r))) + >>> mprint(KM.auxiliary_eqs.applyfunc(simplify_auxiliary_eqs)) + Matrix([ + [ m*r*(u1*u3 + u2') - f1], + [ m*r*((u1**2 + u2**2)*sin(q2) + (u2*u3 + u3*q3' - u1')*cos(q2)) - f2], + [g*m - m*r*((u1**2 + u2**2)*cos(q2) - (u2*u3 + u3*q3' - u1')*sin(q2)) - f3]]) diff -Nru python3-sympy-0.7.2/doc/src/modules/physics/mechanics/rollingdisc_example_lagrange.rst python3-sympy-0.7.3/doc/src/modules/physics/mechanics/rollingdisc_example_lagrange.rst --- python3-sympy-0.7.2/doc/src/modules/physics/mechanics/rollingdisc_example_lagrange.rst 1970-01-01 00:00:00.000000000 +0000 +++ python3-sympy-0.7.3/doc/src/modules/physics/mechanics/rollingdisc_example_lagrange.rst 2013-07-13 17:50:18.000000000 +0000 @@ -0,0 +1,71 @@ +====================================== +A rolling disc using Lagrange's Method +====================================== + +Here the rolling disc is formed from the contact point up, removing the +need to introduce generalized speeds. Only 3 configuration and 3 +speed variables are needed to describe this system, along with the +disc's mass and radius, and the local gravity. :: + + >>> from sympy import symbols, cos, sin + >>> from sympy.physics.mechanics import * + >>> mechanics_printing() + >>> q1, q2, q3 = dynamicsymbols('q1 q2 q3') + >>> q1d, q2d, q3d = dynamicsymbols('q1 q2 q3', 1) + >>> r, m, g = symbols('r m g') + +The kinematics are formed by a series of simple rotations. Each simple +rotation creates a new frame, and the next rotation is defined by the new +frame's basis vectors. This example uses a 3-1-2 series of rotations, or +Z, X, Y series of rotations. Angular velocity for this is defined using +the second frame's basis (the lean frame). :: + + >>> N = ReferenceFrame('N') + >>> Y = N.orientnew('Y', 'Axis', [q1, N.z]) + >>> L = Y.orientnew('L', 'Axis', [q2, Y.x]) + >>> R = L.orientnew('R', 'Axis', [q3, L.y]) + +This is the translational kinematics. We create a point with no velocity +in N; this is the contact point between the disc and ground. Next we form +the position vector from the contact point to the disc's center of mass. +Finally we form the velocity and acceleration of the disc. :: + + >>> C = Point('C') + >>> C.set_vel(N, 0) + >>> Dmc = C.locatenew('Dmc', r * L.z) + >>> Dmc.v2pt_theory(C, N, R) + r*(sin(q2)*q1' + q3')*L.x - r*q2'*L.y + +Forming the inertia dyadic. :: + + >>> I = inertia(L, m / 4 * r**2, m / 2 * r**2, m / 4 * r**2) + >>> mprint(I) + m*r**2/4*(L.x|L.x) + m*r**2/2*(L.y|L.y) + m*r**2/4*(L.z|L.z) + >>> BodyD = RigidBody('BodyD', Dmc, R, m, (I, Dmc)) + +We then set the potential energy and determine the Lagrangian of the rolling +disc. :: + + >>> BodyD.set_potential_energy(- m * g * r * cos(q2)) + >>> Lag = Lagrangian(N, BodyD) + +Then the equations of motion are generated by initializing the +``LagrangesMethod`` object. Finally we solve for the generalized +accelerations(q double dots) with the ``rhs`` method. :: + + >>> q = [q1, q2, q3] + >>> l = LagrangesMethod(Lag, q) + >>> le = l.form_lagranges_equations() + >>> le.simplify(); le + Matrix([ + [m*r**2*(12*sin(q2)*q3'' + 10*sin(2*q2)*q1'*q2' + 12*cos(q2)*q2'*q3' - 5*cos(2*q2)*q1'' + 7*q1'')/8], + [ m*r*(8*g*sin(q2) - 5*r*sin(2*q2)*q1'**2 - 12*r*cos(q2)*q1'*q3' + 10*r*q2'')/8], + [ 3*m*r**2*(sin(q2)*q1'' + cos(q2)*q1'*q2' + q3'')/2]]) + >>> lrhs = l.rhs(); lrhs.simplify(); lrhs + Matrix([ + [ q1'], + [ q2'], + [ q3'], + [ -4*(tan(q2)*q1' + 3*q3'/(2*cos(q2)))*q2'], + [-4*g*sin(q2)/(5*r) + sin(2*q2)*q1'**2/2 + 6*cos(q2)*q1'*q3'/5], + [ (-5*cos(q2)*q1' + 6*tan(q2)*q3' + 4*q1'/cos(q2))*q2']]) diff -Nru python3-sympy-0.7.2/doc/src/modules/physics/mechanics/vectors.rst python3-sympy-0.7.3/doc/src/modules/physics/mechanics/vectors.rst --- python3-sympy-0.7.2/doc/src/modules/physics/mechanics/vectors.rst 2012-10-17 03:02:20.000000000 +0000 +++ python3-sympy-0.7.3/doc/src/modules/physics/mechanics/vectors.rst 2013-07-13 17:50:18.000000000 +0000 @@ -646,14 +646,16 @@ >>> Bp.orient(Bpp,'Axis', [q2, Bpp.y]) >>> B.orient(Bp,'Axis', [q3, Bp.z]) >>> N.dcm(B) - [ cos(q2)*cos(q3), -sin(q3)*cos(q2), sin(q2)] - [sin(q1)*sin(q2)*cos(q3) + sin(q3)*cos(q1), -sin(q1)*sin(q2)*sin(q3) + cos(q1)*cos(q3), -sin(q1)*cos(q2)] - [sin(q1)*sin(q3) - sin(q2)*cos(q1)*cos(q3), sin(q1)*cos(q3) + sin(q2)*sin(q3)*cos(q1), cos(q1)*cos(q2)] + Matrix([ + [ cos(q2)*cos(q3), -sin(q3)*cos(q2), sin(q2)], + [sin(q1)*sin(q2)*cos(q3) + sin(q3)*cos(q1), -sin(q1)*sin(q2)*sin(q3) + cos(q1)*cos(q3), -sin(q1)*cos(q2)], + [sin(q1)*sin(q3) - sin(q2)*cos(q1)*cos(q3), sin(q1)*cos(q3) + sin(q2)*sin(q3)*cos(q1), cos(q1)*cos(q2)]]) >>> B.orient(N,'Body',[q1,q2,q3],'XYZ') >>> N.dcm(B) - [ cos(q2)*cos(q3), -sin(q3)*cos(q2), sin(q2)] - [sin(q1)*sin(q2)*cos(q3) + sin(q3)*cos(q1), -sin(q1)*sin(q2)*sin(q3) + cos(q1)*cos(q3), -sin(q1)*cos(q2)] - [sin(q1)*sin(q3) - sin(q2)*cos(q1)*cos(q3), sin(q1)*cos(q3) + sin(q2)*sin(q3)*cos(q1), cos(q1)*cos(q2)] + Matrix([ + [ cos(q2)*cos(q3), -sin(q3)*cos(q2), sin(q2)], + [sin(q1)*sin(q2)*cos(q3) + sin(q3)*cos(q1), -sin(q1)*sin(q2)*sin(q3) + cos(q1)*cos(q3), -sin(q1)*cos(q2)], + [sin(q1)*sin(q3) - sin(q2)*cos(q1)*cos(q3), sin(q1)*cos(q3) + sin(q2)*sin(q3)*cos(q1), cos(q1)*cos(q2)]]) Space orientations are similar to body orientation, but applied from the frame to body. Body and space rotations can involve either two or three axes: 'XYZ' diff -Nru python3-sympy-0.7.2/doc/src/modules/plotting.rst python3-sympy-0.7.3/doc/src/modules/plotting.rst --- python3-sympy-0.7.2/doc/src/modules/plotting.rst 2012-10-17 01:53:14.000000000 +0000 +++ python3-sympy-0.7.3/doc/src/modules/plotting.rst 2013-07-13 17:50:18.000000000 +0000 @@ -6,10 +6,10 @@ Introduction ------------ -The plotting module allows you to plot 2-dimensional and 3-dimensional plots. -Presently the plots are rendered using ``Matplotlib`` as its backend. It is +The plotting module allows you to make 2-dimensional and 3-dimensional plots. +Presently the plots are rendered using ``matplotlib`` as a backend. It is also possible to plot 2-dimensional plots using a ``TextBackend`` if you don't -have ``Matplotlib``. +have ``matplotlib``. The plotting module has the following functions: @@ -148,14 +148,14 @@ Coordinate Modes ---------------- -Plot supports several curvilinear coordinate modes, and they are independent +``Plot`` supports several curvilinear coordinate modes, and they are independent for each plotted function. You can specify a coordinate mode explicitly with the 'mode' named argument, but it can be automatically determined for cartesian or parametric plots, and therefore must only be specified for polar, cylindrical, and spherical modes. -Specifically, Plot(function arguments) and Plot.__setitem__(i, function -arguments) (accessed using array-index syntax on the Plot instance) will +Specifically, ``Plot(function arguments)`` and ``Plot.__setitem__(i, function +arguments)`` (accessed using array-index syntax on the ``Plot`` instance) will interpret your arguments as a cartesian plot if you provide one function and a parametric plot if you provide two or three functions. Similarly, the arguments will be interpreted as a curve is one variable is used, and a surface if two diff -Nru python3-sympy-0.7.2/doc/src/modules/polys/basics.rst python3-sympy-0.7.3/doc/src/modules/polys/basics.rst --- python3-sympy-0.7.2/doc/src/modules/polys/basics.rst 2012-10-17 02:30:33.000000000 +0000 +++ python3-sympy-0.7.3/doc/src/modules/polys/basics.rst 2013-07-13 17:50:18.000000000 +0000 @@ -109,11 +109,19 @@ When the polynomials have integer coefficients, the contents' gcd is also considered:: - >>> f = 12*(x + 1)*x + >>> f = (12*x + 12)*x >>> g = 16*x**2 >>> gcd(f, g) 4*x +But if the polynomials have rational coefficients, then the returned polynomial is +monic:: + + >>> f = 3*x**2/2 + >>> g = 9*x/4 + >>> gcd(f, g) + x + It also works with multiple variables. In this case, the variables are ordered alphabetically, be default, which has influence on the leading coefficient:: diff -Nru python3-sympy-0.7.2/doc/src/modules/polys/internals.rst python3-sympy-0.7.3/doc/src/modules/polys/internals.rst --- python3-sympy-0.7.2/doc/src/modules/polys/internals.rst 2012-10-17 02:30:33.000000000 +0000 +++ python3-sympy-0.7.3/doc/src/modules/polys/internals.rst 2013-07-13 17:50:19.000000000 +0000 @@ -108,19 +108,14 @@ ********************** .. autoclass:: PythonFiniteField -.. autoclass:: SymPyFiniteField .. autoclass:: GMPYFiniteField .. autoclass:: PythonIntegerRing -.. autoclass:: SymPyIntegerRing .. autoclass:: GMPYIntegerRing .. autoclass:: PythonRationalField -.. autoclass:: SymPyRationalField .. autoclass:: GMPYRationalField -.. autoclass:: PythonRealDomain -.. autoclass:: SymPyRealDomain .. autoclass:: MPmathRealDomain @@ -299,7 +294,6 @@ .. autofunction:: gf_strip .. autofunction:: gf_trunc .. autofunction:: gf_normal -.. autofunction:: gf_convert .. autofunction:: gf_from_dict .. autofunction:: gf_to_dict .. autofunction:: gf_from_int_poly @@ -356,46 +350,9 @@ Dense representations quickly require infeasible amounts of storage and computation time if the number of variables increases. For this reason, -there is code to manipulate polynomials in a *sparse* representation. These -functions carry the ``sdp_`` prefix. As in the ``sdm_`` case, the ground domain -`K` and level `u` often have to be passed explicitly. Furthermore, sparse -representations are relative to a monomial order `O`, which also has to be -passed. - -.. currentmodule:: sympy.polys.distributedpolys -.. autofunction:: sdp_LC -.. autofunction:: sdp_LM -.. autofunction:: sdp_LT -.. autofunction:: sdp_del_LT -.. autofunction:: sdp_monoms -.. autofunction:: sdp_sort -.. autofunction:: sdp_strip -.. autofunction:: sdp_normal -.. autofunction:: sdp_from_dict -.. autofunction:: sdp_to_dict -.. autofunction:: sdp_indep_p -.. autofunction:: sdp_one_p -.. autofunction:: sdp_one -.. autofunction:: sdp_term_p -.. autofunction:: sdp_abs -.. autofunction:: sdp_neg -.. autofunction:: sdp_add_term -.. autofunction:: sdp_sub_term -.. autofunction:: sdp_mul_term -.. autofunction:: sdp_add -.. autofunction:: sdp_sub -.. autofunction:: sdp_mul -.. autofunction:: sdp_sqr -.. autofunction:: sdp_pow -.. autofunction:: sdp_monic -.. autofunction:: sdp_content -.. autofunction:: sdp_primitive -.. autofunction:: sdp_div -.. autofunction:: sdp_rem -.. autofunction:: sdp_quo -.. autofunction:: sdp_exquo -.. autofunction:: sdp_lcm -.. autofunction:: sdp_gcd +there is code to manipulate polynomials in a *sparse* representation. + +.. TODO: write documentation for new sparse polynomials In commutative algebra, one often studies not only polynomials, but also *modules* over polynomial rings. The polynomial manipulation module provides @@ -492,14 +449,15 @@ .. currentmodule:: sympy.polys.groebnertools -.. autofunction:: sdp_groebner -.. autofunction:: buchberger -.. autofunction:: sdp_spoly -.. autofunction:: f5b +.. autofunction:: groebner +.. autofunction:: spoly .. autofunction:: red_groebner .. autofunction:: is_groebner .. autofunction:: is_minimal .. autofunction:: is_reduced + +.. currentmodule:: sympy.polys.fglmtools + .. autofunction:: matrix_fglm Groebner basis algorithms for modules are also provided: diff -Nru python3-sympy-0.7.2/doc/src/modules/polys/reference.rst python3-sympy-0.7.3/doc/src/modules/polys/reference.rst --- python3-sympy-0.7.2/doc/src/modules/polys/reference.rst 2012-10-17 01:53:14.000000000 +0000 +++ python3-sympy-0.7.3/doc/src/modules/polys/reference.rst 2013-07-13 17:50:19.000000000 +0000 @@ -169,3 +169,5 @@ .. currentmodule:: sympy.polys.partfrac .. autofunction:: apart +.. autofunction:: apart_list +.. autofunction:: assemble_partfrac_list diff -Nru python3-sympy-0.7.2/doc/src/modules/printing.rst python3-sympy-0.7.3/doc/src/modules/printing.rst --- python3-sympy-0.7.2/doc/src/modules/printing.rst 2012-10-17 03:02:20.000000000 +0000 +++ python3-sympy-0.7.3/doc/src/modules/printing.rst 2013-07-13 17:53:31.000000000 +0000 @@ -1,7 +1,7 @@ Printing System =============== -See the :ref:`printing-tutorial` section in Tutorial for introduction into +See the :ref:`tutorial-printing` section in Tutorial for introduction into printing. This guide documents the printing system in SymPy and how it works @@ -25,9 +25,9 @@ PrettyPrinter Class ------------------- -Pretty printing subsystem is implemented in ``sympy.printing.pretty.pretty`` +The pretty printing subsystem is implemented in ``sympy.printing.pretty.pretty`` by the ``PrettyPrinter`` class deriving from ``Printer``. It relies on -modules ``sympy.printing.pretty.stringPict``, and +the modules ``sympy.printing.pretty.stringPict``, and ``sympy.printing.pretty.pretty_symbology`` for rendering nice-looking formulas. @@ -84,12 +84,12 @@ Fortran Printing ---------------- -The fcode function translates a sympy expression into Fortran code. The main +The ``fcode`` function translates a sympy expression into Fortran code. The main purpose is to take away the burden of manually translating long mathematical expressions. Therefore the resulting expression should also require no (or very little) manual tweaking to make it compilable. The optional arguments -of fcode can be used to fine-tune the behavior of fcode in such a way that -manual changes in the result are no longer needed. +of ``fcode`` can be used to fine-tune the behavior of ``fcode`` in such a way +that manual changes in the result are no longer needed. .. module:: sympy.printing.fcode .. autofunction:: fcode @@ -113,18 +113,21 @@ >>> expr = sqrt(1-x**2).series(x,n=20).removeO() >>> print(fcode(expr)) - -715*x**18/65536 - 429*x**16/32768 - 33*x**14/2048 - 21*x**12/1024 - @ - 7*x**10/256 - 5*x**8/128 - x**6/16 - x**4/8 - x**2/2 + 1 + -715.0d0/65536.0d0*x**18 - 429.0d0/32768.0d0*x**16 - 33.0d0/ + @ 2048.0d0*x**14 - 21.0d0/1024.0d0*x**12 - 7.0d0/256.0d0*x**10 - + @ 5.0d0/128.0d0*x**8 - 1.0d0/16.0d0*x**6 - 1.0d0/8.0d0*x**4 - 1.0d0 + @ /2.0d0*x**2 + 1 In case of line wrapping, it is handy to include the assignment so that lines are wrapped properly when the assignment part is added. >>> print(fcode(expr, assign_to="var")) - var = -715*x**18/65536 - 429*x**16/32768 - 33*x**14/2048 - 21*x** - @ 12/1024 - 7*x**10/256 - 5*x**8/128 - x**6/16 - x**4/8 - x**2/2 + - @ 1 + var = -715.0d0/65536.0d0*x**18 - 429.0d0/32768.0d0*x**16 - 33.0d0/ + @ 2048.0d0*x**14 - 21.0d0/1024.0d0*x**12 - 7.0d0/256.0d0*x**10 - + @ 5.0d0/128.0d0*x**8 - 1.0d0/16.0d0*x**6 - 1.0d0/8.0d0*x**4 - 1.0d0 + @ /2.0d0*x**2 + 1 -For piecewise functions, the assign_to option is mandatory: +For piecewise functions, the ``assign_to`` option is mandatory: >>> print(fcode(Piecewise((x,x<1),(x**2,True)), assign_to="var")) if (x < 1) then @@ -136,7 +139,7 @@ Note that only top-level piecewise functions are supported due to the lack of a conditional operator in Fortran. Nested piecewise functions would require the introduction of temporary variables, which is a type of expression manipulation -that goes beyond the scope of fcode. +that goes beyond the scope of ``fcode``. Loops are generated if there are Indexed objects in the expression. This also requires use of the assign_to option. @@ -181,7 +184,7 @@ >>> print(fcode(1 - gamma(x)**2, user_functions={gamma: 'mygamma'})) -mygamma(x)**2 + 1 -However, when the user_functions argument is not provided, fcode attempts to +However, when the user_functions argument is not provided, ``fcode`` attempts to use a reasonable default and adds a comment to inform the user of the issue. >>> print(fcode(1 - gamma(x)**2)) @@ -295,7 +298,7 @@ .. module:: sympy.printing.repr This printer generates executable code. This code satisfies the identity -``eval(srepr(expr))=expr``. +``eval(srepr(expr)) == expr``. .. autoclass:: ReprPrinter :members: @@ -442,3 +445,8 @@ .. autoclass:: prettyForm :members: + +dotprint +-------- + +.. autofunction:: sympy.printing.dot.dotprint diff -Nru python3-sympy-0.7.2/doc/src/modules/rewriting.rst python3-sympy-0.7.3/doc/src/modules/rewriting.rst --- python3-sympy-0.7.2/doc/src/modules/rewriting.rst 2012-10-17 01:53:14.000000000 +0000 +++ python3-sympy-0.7.3/doc/src/modules/rewriting.rst 2013-07-13 17:50:18.000000000 +0000 @@ -5,7 +5,7 @@ convert expressions of one type in terms of expressions of different kind. For example expanding, combining and converting expressions apply to term rewriting, and also simplification routines can be included here. Currently -!SymPy has several functions and Basic built-in methods for performing various +SymPy has several functions and basic built-in methods for performing various types of rewriting. Expanding @@ -64,7 +64,8 @@ .. module:: sympy.simplify.cse_main Before evaluating a large expression, it is often useful to identify common -subexpressions, collect them and evaluate them at once. This is implemented in the ``cse`` function. Examples:: +subexpressions, collect them and evaluate them at once. This is implemented +in the ``cse`` function. Examples:: >>> from sympy import cse, sqrt, sin, pprint >>> from sympy.abc import x @@ -77,9 +78,10 @@ ⎛ ⎡ ________ ________⎤⎞ ⎝[(x₀, sin(x))], ⎣╲╱ x₀ + 4 ⋅╲╱ x₀ + 5 ⎦⎠ - >>> pprint(cse(sqrt(sin(x+1) + 5 + cos(y))*sqrt(sin(x+1) + 4 + cos(y))), use_unicode=True) - ⎛ ⎡ ________ ________⎤⎞ - ⎝[(x₀, cos(y)), (x₁, sin(x + 1)), (x₂, x₀ + x₁)], ⎣╲╱ x₂ + 4 ⋅╲╱ x₂ + 5 ⎦⎠ + >>> pprint(cse(sqrt(sin(x+1) + 5 + cos(y))*sqrt(sin(x+1) + 4 + cos(y))), + ... use_unicode=True) + ⎛ ⎡ ________ ________⎤⎞ + ⎝[(x₀, sin(x + 1) + cos(y))], ⎣╲╱ x₀ + 4 ⋅╲╱ x₀ + 5 ⎦⎠ >>> pprint(cse((x-y)*(z-y) + sqrt((x-y)*(z-y))), use_unicode=True) ⎛ ⎡ ____ ⎤⎞ diff -Nru python3-sympy-0.7.2/doc/src/modules/simplify/hyperexpand.rst python3-sympy-0.7.3/doc/src/modules/simplify/hyperexpand.rst --- python3-sympy-0.7.2/doc/src/modules/simplify/hyperexpand.rst 2012-10-17 02:30:33.000000000 +0000 +++ python3-sympy-0.7.3/doc/src/modules/simplify/hyperexpand.rst 2013-07-13 17:50:18.000000000 +0000 @@ -494,9 +494,11 @@ >>> from sympy import Symbol, sqrt, exp, I, pi, fresnelc, root, diff, expand >>> z = Symbol("z") - >>> B0 = sqrt(pi)*exp(-I*pi/4)*fresnelc(2*root(z,4)*exp(I*pi/4)/sqrt(pi))/(2*root(z,4)) + >>> B0 = sqrt(pi)*exp(-I*pi/4)*fresnelc(2*root(z,4)*exp(I*pi/4)/sqrt(pi))/\ + ... (2*root(z,4)) >>> z * diff(B0, z) - z*(cosh(2*sqrt(z))/(4*z) - sqrt(pi)*exp(-I*pi/4)*fresnelc(2*z**(1/4)*exp(I*pi/4)/sqrt(pi))/(8*z**(5/4))) + z*(cosh(2*sqrt(z))/(4*z) - + sqrt(pi)*exp(-I*pi/4)*fresnelc(2*z**(1/4)*exp(I*pi/4)/sqrt(pi))/(8*z**(5/4))) >>> expand(_) cosh(2*sqrt(z))/4 - sqrt(pi)*exp(-I*pi/4)*fresnelc(2*z**(1/4)*exp(I*pi/4)/sqrt(pi))/(8*z**(1/4)) @@ -514,9 +516,11 @@ Computing the second derivative we find - >>> from sympy import Symbol, cosh, sqrt, pi, exp, I, fresnelc, root, diff, expand + >>> from sympy import (Symbol, cosh, sqrt, pi, exp, I, fresnelc, root, + ... diff, expand) >>> z = Symbol("z") - >>> B1prime = cosh(2*sqrt(z))/4 - sqrt(pi)*exp(-I*pi/4)*fresnelc(2*root(z,4)*exp(I*pi/4)/sqrt(pi))/(8*root(z,4)) + >>> B1prime = cosh(2*sqrt(z))/4 - sqrt(pi)*exp(-I*pi/4)*\ + ... fresnelc(2*root(z,4)*exp(I*pi/4)/sqrt(pi))/(8*root(z,4)) >>> z * diff(B1prime, z) z*(-cosh(2*sqrt(z))/(16*z) + sinh(2*sqrt(z))/(4*sqrt(z)) + sqrt(pi)*exp(-I*pi/4)*fresnelc(2*z**(1/4)*exp(I*pi/4)/sqrt(pi))/(32*z**(5/4))) >>> expand(_) diff -Nru python3-sympy-0.7.2/doc/src/modules/simplify/simplify.rst python3-sympy-0.7.3/doc/src/modules/simplify/simplify.rst --- python3-sympy-0.7.2/doc/src/modules/simplify/simplify.rst 2012-10-17 01:53:14.000000000 +0000 +++ python3-sympy-0.7.3/doc/src/modules/simplify/simplify.rst 2013-07-13 17:50:18.000000000 +0000 @@ -22,6 +22,16 @@ .. autofunction:: separatevars +nthroot +------- +.. autofunction:: nthroot + + +rad_rationalize +--------------- +.. autofunction:: rad_rationalize + + radsimp ------- .. autofunction:: radsimp @@ -91,10 +101,6 @@ ^^^^^^^^^^ .. autofunction:: sqrtdenest -subsets -^^^^^^^ -.. autofunction:: subsets - Common Subexpresion Elimination ------------------------------- .. module:: sympy.simplify.cse_main diff -Nru python3-sympy-0.7.2/doc/src/modules/solvers/ode.rst python3-sympy-0.7.3/doc/src/modules/solvers/ode.rst --- python3-sympy-0.7.2/doc/src/modules/solvers/ode.rst 2012-10-17 01:53:14.000000000 +0000 +++ python3-sympy-0.7.3/doc/src/modules/solvers/ode.rst 2013-07-13 17:50:18.000000000 +0000 @@ -7,7 +7,8 @@ User Functions -------------- -These are functions that are imported into the global namespace with ``from sympy import *``. They are intended for user use. +These are functions that are imported into the global namespace with ``from +sympy import *``. They are intended for user use. :func:`dsolve` ^^^^^^^^^^^^^^ @@ -17,10 +18,6 @@ ^^^^^^^^^^^^^^^^^^^^ .. autofunction:: sympy.solvers.ode.classify_ode -:func:`ode_order` -^^^^^^^^^^^^^^^^^^^^ -.. autofunction:: sympy.solvers.ode.ode_order - :func:`checkodesol` ^^^^^^^^^^^^^^^^^^^ .. autofunction:: sympy.solvers.ode.checkodesol @@ -29,13 +26,19 @@ ^^^^^^^^^^^^^^^^^^^^^^^^^ .. autofunction:: sympy.solvers.ode.homogeneous_order -Hint Methods ------------- -These functions are intended for internal use by :func:`dsolve` and others. Nonetheless, they contain useful information in their docstrings on the various ODE solving methods. +:func:`infinitesimals` +^^^^^^^^^^^^^^^^^^^^^^ +.. autofunction:: sympy.solvers.ode.infinitesimals -:obj:`preprocess` -^^^^^^^^^^^^^^^^^ -.. autofunction:: sympy.solvers.ode.preprocess +Hint Functions +-------------- +These functions are intended for internal use by :py:meth:`dsolve` and others. +Nonetheless, they contain useful information in their docstrings on the various +ODE solving methods. + +:obj:`allhints` +^^^^^^^^^^^^^^^ +.. autodata:: sympy.solvers.ode.allhints :obj:`odesimp` ^^^^^^^^^^^^^^ @@ -101,6 +104,18 @@ ^^^^^^^^^^^^^^^^ .. autofunction:: sympy.solvers.ode.ode_separable +:obj:`almost_linear` +^^^^^^^^^^^^^^^^^^^^ +.. autofunction:: sympy.solvers.ode.ode_almost_linear + +:obj:`linear_coefficients` +^^^^^^^^^^^^^^^^^^^^^^^^^^ +.. autofunction:: sympy.solvers.ode.ode_linear_coefficients + +:obj:`separable_reduced` +^^^^^^^^^^^^^^^^^^^^^^^^ +.. autofunction:: sympy.solvers.ode.ode_separable_reduced + Information on the ode module ----------------------------- diff -Nru python3-sympy-0.7.2/doc/src/modules/solvers/pde.rst python3-sympy-0.7.3/doc/src/modules/solvers/pde.rst --- python3-sympy-0.7.2/doc/src/modules/solvers/pde.rst 1970-01-01 00:00:00.000000000 +0000 +++ python3-sympy-0.7.3/doc/src/modules/solvers/pde.rst 2013-07-13 17:50:18.000000000 +0000 @@ -0,0 +1,51 @@ +.. _pde-docs: + +PDE +=== + +.. module::sympy.solvers.pde + +User Functions +-------------- +These are functions that are imported into the global namespace with ``from sympy import *``. They are intended for user use. + +:func:`pde_separate` +^^^^^^^^^^^^^^^^^^^^ +.. autofunction:: sympy.solvers.pde.pde_separate + +:func:`pde_separate_add` +^^^^^^^^^^^^^^^^^^^^^^^^ +.. autofunction:: sympy.solvers.pde.pde_separate_add + +:func:`pde_separate_mul` +^^^^^^^^^^^^^^^^^^^^^^^^ +.. autofunction:: sympy.solvers.pde.pde_separate_mul + +:func:`pdsolve` +^^^^^^^^^^^^^^^ +.. autofunction:: sympy.solvers.pde.pdsolve + +:func:`classify_pde` +^^^^^^^^^^^^^^^^^^^^ +.. autofunction:: sympy.solvers.pde.classify_pde + +:func:`checkpdesol` +^^^^^^^^^^^^^^^^^^^ +.. autofunction:: sympy.solvers.pde.checkpdesol + +Hint Methods +------------ +These funcions are meant for internal use. However they contain useful information on the various solving methods. + +:obj:`pde_1st_linear_constant_coeff_homogeneous` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +.. autofunction:: sympy.solvers.pde.pde_1st_linear_constant_coeff_homogeneous + +:obj:`pde_1st_linear_constant_coeff` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +.. autofunction:: sympy.solvers.pde.pde_1st_linear_constant_coeff + +Information on the pde module +----------------------------- + +.. automodule:: sympy.solvers.pde diff -Nru python3-sympy-0.7.2/doc/src/modules/solvers/solvers.rst python3-sympy-0.7.3/doc/src/modules/solvers/solvers.rst --- python3-sympy-0.7.2/doc/src/modules/solvers/solvers.rst 2012-10-17 03:02:20.000000000 +0000 +++ python3-sympy-0.7.3/doc/src/modules/solvers/solvers.rst 2013-07-13 17:53:31.000000000 +0000 @@ -46,11 +46,12 @@ Partial Differential Equations (PDEs) ------------------------------------- -.. autofunction:: sympy.solvers.pde.pde_separate +See :ref:`pde-docs`. -.. autofunction:: sympy.solvers.pde.pde_separate_add +Deutils (Utilities for solving ODE's and PDE's) +----------------------------------------------- -.. autofunction:: sympy.solvers.pde.pde_separate_mul +.. autofunction:: sympy.solvers.deutils.ode_order Recurrence Equtions ------------------- diff -Nru python3-sympy-0.7.2/doc/src/modules/statistics.rst python3-sympy-0.7.3/doc/src/modules/statistics.rst --- python3-sympy-0.7.2/doc/src/modules/statistics.rst 2012-10-17 03:02:20.000000000 +0000 +++ python3-sympy-0.7.3/doc/src/modules/statistics.rst 2013-07-13 17:53:31.000000000 +0000 @@ -3,9 +3,11 @@ .. module:: sympy.statistics -Note: This module has been deprecated. See the stats module. +.. note :: -The *statistics* module in SymPy implements standard probability distributions + This module has been deprecated. See the :mod:`stats ` module. + +The ``statistics`` module in SymPy implements standard probability distributions and related tools. Its contents can be imported with the following statement:: >>> from sympy import * diff -Nru python3-sympy-0.7.2/doc/src/modules/stats.rst python3-sympy-0.7.3/doc/src/modules/stats.rst --- python3-sympy-0.7.2/doc/src/modules/stats.rst 2012-10-17 01:53:14.000000000 +0000 +++ python3-sympy-0.7.3/doc/src/modules/stats.rst 2013-07-13 17:53:31.000000000 +0000 @@ -25,9 +25,17 @@ .. autofunction:: BetaPrime .. autofunction:: Cauchy .. autofunction:: Chi +.. autofunction:: ChiNoncentral +.. autofunction:: ChiSquared .. autofunction:: Dagum +.. autofunction:: Erlang .. autofunction:: Exponential +.. autofunction:: FDistribution +.. autofunction:: FisherZ +.. autofunction:: Frechet .. autofunction:: Gamma +.. autofunction:: GammaInverse +.. autofunction:: Kumaraswamy .. autofunction:: Laplace .. autofunction:: Logistic .. autofunction:: LogNormal @@ -35,11 +43,14 @@ .. autofunction:: Nakagami .. autofunction:: Normal .. autofunction:: Pareto +.. autofunction:: QuadraticU +.. autofunction:: RaisedCosine .. autofunction:: Rayleigh .. autofunction:: StudentT .. autofunction:: Triangular .. autofunction:: Uniform .. autofunction:: UniformSum +.. autofunction:: VonMises .. autofunction:: Weibull .. autofunction:: WignerSemicircle .. autofunction:: ContinuousRV @@ -63,15 +74,16 @@ SymPy Stats employs a relatively complex class hierarchy. -RandomDomains are a mapping of variables to possible values. For example we -might say that the symbol Symbol('x') can take on the values {1,2,3,4,5,6}. +``RandomDomain``\s are a mapping of variables to possible values. For example we +might say that the symbol ``Symbol('x')`` can take on the values +`\{1,2,3,4,5,6\}`. .. class:: RandomDomain -A PSpace, or Probability Space, combines a RandomDomain with a density to +A ``PSpace``, or Probability Space, combines a ``RandomDomain`` with a density to provide probabilistic information. For example the above domain could be -enhanced by a finite density {1:1/6, 2:1/6, 3:1/6, 4:1/6, 5:1/6, 6:1/6} to -fully define the roll of a fair die named 'x'. +enhanced by a finite density ``{1:1/6, 2:1/6, 3:1/6, 4:1/6, 5:1/6, 6:1/6}`` to +fully define the roll of a fair die named ``x``. .. class:: PSpace diff -Nru python3-sympy-0.7.2/doc/src/modules/tensor/index.rst python3-sympy-0.7.3/doc/src/modules/tensor/index.rst --- python3-sympy-0.7.2/doc/src/modules/tensor/index.rst 2012-10-17 01:53:14.000000000 +0000 +++ python3-sympy-0.7.3/doc/src/modules/tensor/index.rst 2013-07-13 17:50:18.000000000 +0000 @@ -14,3 +14,4 @@ indexed.rst index_methods.rst + tensor.rst diff -Nru python3-sympy-0.7.2/doc/src/modules/tensor/tensor.rst python3-sympy-0.7.3/doc/src/modules/tensor/tensor.rst --- python3-sympy-0.7.2/doc/src/modules/tensor/tensor.rst 1970-01-01 00:00:00.000000000 +0000 +++ python3-sympy-0.7.3/doc/src/modules/tensor/tensor.rst 2013-07-13 17:53:31.000000000 +0000 @@ -0,0 +1,43 @@ +.. _tensor-tensor: + +Tensor +====== + +.. module:: sympy.tensor.tensor + +.. autoclass:: _TensorManager + :members: + +.. autoclass:: TensorIndexType + :members: + +.. autoclass:: TensorIndex + :members: + +.. autofunction:: tensor_indices + +.. autoclass:: TensorSymmetry + :members: + +.. autoclass:: TensorType + :members: + +.. autoclass:: TensorHead + :members: + +.. autoclass:: TensExpr + :members: + +.. autoclass:: TensAdd + :members: + +.. autoclass:: TensMul + :members: + +.. autofunction:: canon_bp + +.. autofunction:: tensor_mul + +.. autofunction:: riemann_cyclic_replace + +.. autofunction:: riemann_cyclic diff -Nru python3-sympy-0.7.2/doc/src/modules/utilities/iterables.rst python3-sympy-0.7.3/doc/src/modules/utilities/iterables.rst --- python3-sympy-0.7.2/doc/src/modules/utilities/iterables.rst 2012-10-17 03:02:20.000000000 +0000 +++ python3-sympy-0.7.3/doc/src/modules/utilities/iterables.rst 2013-07-13 17:53:31.000000000 +0000 @@ -30,6 +30,60 @@ >>> list(variations([1,2,3], 2, True)) [(1, 1), (1, 2), (1, 3), (2, 1), (2, 2), (2, 3), (3, 1), (3, 2), (3, 3)] + +partitions +---------- + +Although the combinatorics module contains Partition and IntegerPartition +classes for investigation and manipulation of partitions, there are a few +functions to generate partitions that can be used as low-level tools for +routines: ``partitions`` and ``multiset_partitions``. The former gives +integer partitions, and the latter gives enumerated partitions of elements. +There is also a routine ``kbins`` that will give a variety of permutations +of partions. + +partitions:: + + >>> from sympy.utilities.iterables import partitions + >>> [p.copy() for s, p in partitions(7, m=2, size=True) if s == 2] + [{1: 1, 6: 1}, {2: 1, 5: 1}, {3: 1, 4: 1}] + +multiset_partitions:: + + >>> from sympy.utilities.iterables import multiset_partitions + >>> [p for p in multiset_partitions(3, 2)] + [[[0, 1], [2]], [[0, 2], [1]], [[0], [1, 2]]] + >>> [p for p in multiset_partitions([1, 1, 1, 2], 2)] + [[[1, 1, 1], [2]], [[1, 1, 2], [1]], [[1, 1], [1, 2]]] + +kbins:: + + >>> from sympy.utilities.iterables import kbins + >>> def show(k): + ... rv = [] + ... for p in k: + ... rv.append(','.join([''.join(j) for j in p])) + ... return sorted(rv) + ... + >>> show(kbins("ABCD", 2)) + ['A,BCD', 'AB,CD', 'ABC,D'] + >>> show(kbins("ABC", 2)) + ['A,BC', 'AB,C'] + >>> show(kbins("ABC", 2, ordered=00)) # same as multiset_partitions + ['A,BC', 'AB,C', 'AC,B'] + >>> show(kbins("ABC", 2, ordered=0o1)) + ['A,BC', 'A,CB', + 'B,AC', 'B,CA', + 'C,AB', 'C,BA'] + >>> show(kbins("ABC", 2, ordered=10)) + ['A,BC', 'AB,C', 'AC,B', + 'B,AC', 'BC,A', + 'C,AB'] + >>> show(kbins("ABC", 2, ordered=11)) + ['A,BC', 'A,CB', 'AB,C', 'AC,B', + 'B,AC', 'B,CA', 'BA,C', 'BC,A', + 'C,AB', 'C,BA', 'CA,B', 'CB,A'] + Docstring ========= Binary files /tmp/E2vCQhuc_3/python3-sympy-0.7.2/doc/src/pics/consoleascii.png and /tmp/E99RNQO9Lx/python3-sympy-0.7.3/doc/src/pics/consoleascii.png differ Binary files /tmp/E2vCQhuc_3/python3-sympy-0.7.2/doc/src/pics/consoleunicode.png and /tmp/E99RNQO9Lx/python3-sympy-0.7.3/doc/src/pics/consoleunicode.png differ Binary files /tmp/E2vCQhuc_3/python3-sympy-0.7.2/doc/src/pics/ipythonnotebook.png and /tmp/E99RNQO9Lx/python3-sympy-0.7.3/doc/src/pics/ipythonnotebook.png differ Binary files /tmp/E2vCQhuc_3/python3-sympy-0.7.2/doc/src/pics/ipythonqtconsole.png and /tmp/E99RNQO9Lx/python3-sympy-0.7.3/doc/src/pics/ipythonqtconsole.png differ diff -Nru python3-sympy-0.7.2/doc/src/python-comparisons.rst python3-sympy-0.7.3/doc/src/python-comparisons.rst --- python3-sympy-0.7.2/doc/src/python-comparisons.rst 2012-10-17 01:53:14.000000000 +0000 +++ python3-sympy-0.7.3/doc/src/python-comparisons.rst 2013-07-13 17:50:19.000000000 +0000 @@ -280,14 +280,14 @@ show("set([a, b])") print "--- x = set([a, b]); y = set([a, b]); ---" - x = set([a,b]) - y = set([a,b]) + x = set([a, b]) + y = set([a, b]) print " x == y :" x == y print "--- x = set([a, b]); y = set([b, d]); ---" - x = set([a,b]) - y = set([b,d]) + x = set([a, b]) + y = set([b, d]) print " x == y :" x == y diff -Nru python3-sympy-0.7.2/doc/src/tutorial/basic_operations.rst python3-sympy-0.7.3/doc/src/tutorial/basic_operations.rst --- python3-sympy-0.7.2/doc/src/tutorial/basic_operations.rst 1970-01-01 00:00:00.000000000 +0000 +++ python3-sympy-0.7.3/doc/src/tutorial/basic_operations.rst 2013-07-13 17:50:18.000000000 +0000 @@ -0,0 +1,190 @@ +.. _tutorial-basic: + +================== + Basic Operations +================== + +Here we discuss some of the most basic operations needed for expression +manipulation in SymPy. Some more advanced operations will be discussed later +in the :ref:`advanced expression manipulation ` section. + + >>> from sympy import * + >>> x, y, z = symbols("x y z") + +Substitution +============ + +One of the most common things you might want to do with a mathematical +expression is substitution. Substitution replaces all instances of something +in an expression with something else. It is done using the ``subs`` method. +For example + + >>> expr = cos(x) + 1 + >>> expr.subs(x, y) + cos(y) + 1 + +Substitution is usually done for one of two reasons: + +1. Evaluating an expression at a point. For example, if our expression is + ``cos(x) + 1`` and we want to evaluate it at the point ``x = 0``, so that + we get ``cos(0) + 1``, which is 2. + + >>> expr.subs(x, 0) + 2 + +2. Replacing a subexpression with another subexpression. There are two + reasons we might want to do this. The first is if we are trying to build + an expression that has some symmetry, such as `x^{x^{x^x}}`. To build + this, we might start with ``x**y``, and replace ``y`` with ``x**y``. We + would then get ``x**(x**y)``. If we replaced ``y`` in this new expression + with ``x**x``, we would get ``x**(x**(x**x))``, the desired expression. + + >>> expr = x**y + >>> expr + x**y + >>> expr = expr.subs(y, x**y) + >>> expr + x**(x**y) + >>> expr = expr.subs(y, x**x) + >>> expr + x**(x**(x**x)) + + The second is if we want to perform a very controlled simplification, or + perhaps a simplification that SymPy is otherwise unable to do. For + example, say we have `\sin(2x) + \cos(2x)`, and we want to replace + `\sin(2x)` with `2\sin(x)\cos(x)`. As we will learn later, the function + ``expand_trig`` does this. However, this function will also expand + `\cos(2x)`, which we may not want. While there are ways to perform such + precise simplification, and we will learn some of them in the + :ref:`advanced expression manipulation ` section, an + easy way is to just replace `\sin(2x)` with `2\sin(x)\cos(x)`. + + >>> expr = sin(2*x) + cos(2*x) + >>> expand_trig(expr) + 2*sin(x)*cos(x) + 2*cos(x)**2 - 1 + >>> expr.subs(sin(2*x), 2*sin(x)*cos(x)) + 2*sin(x)*cos(x) + cos(2*x) + +There are two important things to note about ``subs``. First, it returns a +new expression. SymPy objects are immutable. That means that ``subs`` does +modify it in-place. For example + + >>> expr = cos(x) + >>> expr.subs(x, 0) + 1 + >>> expr + cos(x) + >>> x + x + +.. sidebar:: Quick Tip + + SymPy expressions are immutable. No function will change them in-place. + +Here, we see that performing ``expr.subs(x, 0)`` leaves ``expr`` unchanged. +In fact, since SymPy expressions are immutable, no function will change them +in-place. All functions will return new expressions. + +To perform multiple substitutions at once, pass a list of ``(old, new)`` pairs +to ``subs``. + + >>> expr = x**3 + 4*x*y - z + >>> expr.subs([(x, 2), (y, 4), (z, 0)]) + 40 + +It is often useful to combine this with a list comprehension to do a large set +of similar replacements all at once. For example, say we had `x^4 - 4x^3 + 4x^2 - +2x + 3` and we wanted to replace all instances of `x` that have an even power +with `y`, to get `y^4 - 4x^3 + 4y^2 - 2x + 3`. + + >>> expr = x**4 - 4*x**3 + 4*x**2 - 2*x + 3 + >>> replacements = [(x**i, y**i) for i in range(5) if i % 2 == 0] + >>> expr.subs(replacements) + -4*x**3 - 2*x + y**4 + 4*y**2 + 3 + +Converting Strings to SymPy Expressions +======================================= + +The ``sympify`` function (that's ``sympify``, not to be confused with +``simplify``) can be used to convert strings into SymPy expressions. + +For example + + >>> str_expr = "x**2 + 3*x - 1/2" + >>> expr = sympify(str_expr) + >>> expr + x**2 + 3*x - 1/2 + >>> expr.subs(x, 2) + 19/2 + +.. warning:: ``sympify`` uses ``eval``. Don't use it on unsanitized input. + +``evalf`` +========= + +To evaluate a numerical expression into a floating point number, use +``evalf``. + + >>> expr = sqrt(8) + >>> expr.evalf() + 2.82842712474619 + +SymPy can evaluate floating point expressions to arbitrary precision. By +default, 15 digits of precision are used, but you can pass any number as the +argument to ``evalf``. Let's compute the first 100 digits of `\pi`. + + >>> pi.evalf(100) + 3.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342117068 + +To numerically evaluate an expression with a Symbol at a point, we might use +``subs`` followed by ``evalf``, but it is more efficient and numerically +stable to pass the substitution to ``evalf`` using the ``subs`` flag, which +takes a dictionary of ``Symbol: point`` pairs. + + >>> expr = cos(2*x) + >>> expr.evalf(subs={x: 2.4}) + 0.0874989834394464 + +``lambdify`` +============ + +``subs`` and ``evalf`` are good if you want to do simple evaluation, but if +you intend to evaluate an expression at many points, there are more efficient +ways. For example, if you wanted to evaluate an expression at a thousand +points, using SymPy would be far slower than it needs to be, especially if you +only care about machine precision. Instead, you should use libraries like +`NumPy `_ and `SciPy `_. + +The easiest way to convert a SymPy expression to an expression that can be +numerically evaluated is to use the ``lambdify`` function. ``lambdify`` acts +like a ``lambda`` function, except it converts the SymPy names to the names of +the given numerical library, usually NumPy. For example + + >>> import numpy # doctest:+SKIP + >>> a = numpy.arange(10) # doctest:+SKIP + >>> expr = sin(x) + >>> f = lambdify(x, expr, "numpy") # doctest:+SKIP + >>> f(a) # doctest:+SKIP + [ 0. 0.84147098 0.90929743 0.14112001 -0.7568025 -0.95892427 + -0.2794155 0.6569866 0.98935825 0.41211849] + +You can use other libraries than NumPy. For example, to use the standard +library math module, use ``"math"``. + + >>> f = lambdify(x, expr, "math") + >>> f(0.1) + 0.0998334166468 + +To use lambdify with numerical libraries that it does not know about, pass a +dictionary of ``sympy_name:numerical_function`` pairs. For example + + >>> def mysin(x): + ... """ + ... My sine. Not only accurate for small x. + ... """ + ... return x + >>> f = lambdify(x, expr, {"sin":mysin}) + >>> f(0.1) + 0.1 + +.. TODO: Write an advanced numerics section diff -Nru python3-sympy-0.7.2/doc/src/tutorial/calculus.rst python3-sympy-0.7.3/doc/src/tutorial/calculus.rst --- python3-sympy-0.7.2/doc/src/tutorial/calculus.rst 1970-01-01 00:00:00.000000000 +0000 +++ python3-sympy-0.7.3/doc/src/tutorial/calculus.rst 2013-07-13 17:53:31.000000000 +0000 @@ -0,0 +1,322 @@ +========== + Calculus +========== + +This section covers how to do basic calculus tasks such as derivatives, +integrals, limits, and series expansions in SymPy. If you are not familiar +with the math of any part of this section, you may safely skip it. + + >>> from sympy import * + >>> x, y, z = symbols('x y z') + >>> init_printing(use_unicode=True) + +.. _tutorial-derivatives: + +Derivatives +=========== + +To take derivatives, use the ``diff`` function. + + >>> diff(cos(x), x) + -sin(x) + >>> diff(exp(x**2), x) + ⎛ 2⎞ + ⎝x ⎠ + 2⋅x⋅ℯ + +``diff`` can take multiple derivatives at once. To take multiple derivatives, +pass the variable as many times as you wish to differentiate, or pass a number +after the variable. For example, both of the following find the third +derivative of `x^4`. + + >>> diff(x**4, x, x, x) + 24⋅x + >>> diff(x**4, x, 3) + 24⋅x + +You can also take derivatives with respect to many variables at once. Just +pass each derivative in order, using the same syntax as for single variable +derivatives. For example, each of the following will compute +`\frac{\partial^7}{\partial x\partial y^2\partial z^4} e^{x y z}`. + + >>> expr = exp(x*y*z) + >>> diff(expr, x, y, y, z, z, z, z) + 3 2 ⎛ 3 3 3 2 2 2 ⎞ x⋅y⋅z + x ⋅y ⋅⎝x ⋅y ⋅z + 14⋅x ⋅y ⋅z + 52⋅x⋅y⋅z + 48⎠⋅ℯ + >>> diff(expr, x, y, 2, z, 4) + 3 2 ⎛ 3 3 3 2 2 2 ⎞ x⋅y⋅z + x ⋅y ⋅⎝x ⋅y ⋅z + 14⋅x ⋅y ⋅z + 52⋅x⋅y⋅z + 48⎠⋅ℯ + >>> diff(expr, x, y, y, z, 4) + 3 2 ⎛ 3 3 3 2 2 2 ⎞ x⋅y⋅z + x ⋅y ⋅⎝x ⋅y ⋅z + 14⋅x ⋅y ⋅z + 52⋅x⋅y⋅z + 48⎠⋅ℯ + +``diff`` can also be called as a method. The two ways of calling ``diff`` are +exactly the same, and are provided only for convenience. + + >>> expr.diff(x, y, y, z, 4) + 3 2 ⎛ 3 3 3 2 2 2 ⎞ x⋅y⋅z + x ⋅y ⋅⎝x ⋅y ⋅z + 14⋅x ⋅y ⋅z + 52⋅x⋅y⋅z + 48⎠⋅ℯ + + +To create an unevaluated derivative, use the ``Derivative`` class. It has the +same syntax as ``diff``. + + >>> deriv = Derivative(expr, x, y, y, z, 4) + >>> deriv + 7 + ∂ ⎛ x⋅y⋅z⎞ + ──────────⎝ℯ ⎠ + 4 2 + ∂z ∂y ∂x + +To evaluate an unevaluated derivative, use the ``doit`` method. + + >>> deriv.doit() + 3 2 ⎛ 3 3 3 2 2 2 ⎞ x⋅y⋅z + x ⋅y ⋅⎝x ⋅y ⋅z + 14⋅x ⋅y ⋅z + 52⋅x⋅y⋅z + 48⎠⋅ℯ + +These unevaluated objects are useful for delaying the evaluation of the +derivative, or for printing purposes. They are also used when SymPy does not +know how to compute the derivative of an expression (for example, if it +contains an undefined function, which are described in the :ref:`Solving +Differential Equations ` section). + +Integrals +========= + +To compute an integral, use the ``integrate`` function. There are two kinds +of integrals, definite and indefinite. To compute an indefinite integral, +that is, an antiderivative, or primitive, just pass the variable after the +expression. + + >>> integrate(cos(x), x) + sin(x) + +Note that SymPy does not include the constant of integration. If you want it, +you can add one yourself, or rephrase your problem as a differential equation +and use ``dsolve`` to solve it, which does add the constant (see :ref:`tutorial-dsolve`). + +.. sidebar:: Quick Tip + + `\infty` in SymPy is ``oo`` (that's the lowercase letter "oh" twice). This + is because ``oo`` looks like `\infty`, and is easy to type. + +To compute a definite integral, pass the argument ``(integration_variable, +lower_limit, upper_limit)``. For example, to compute + +.. math:: + + \int_0^\infty e^{-x}\,dx, + +we would do + + >>> integrate(exp(-x), (x, 0, oo)) + 1 + +As with indefinite integrals, you can pass multiple limit tuples to perform a +multiple integral. For example, to compute + +.. math:: + + \int_{-\infty}^{\infty}\int_{-\infty}^{\infty} e^{- x^{2} - y^{2}}\, dx\, dy, + +do + + >>> integrate(exp(-x**2 - y**2), (x, -oo, oo), (y, -oo, oo)) + π + +If ``integrate`` is unable to compute an integral, it returns an unevaluated +``Integral`` object. + + >>> expr = integrate(x**x, x) + >>> print(expr) + Integral(x**x, x) + >>> expr + ⌠ + ⎮ x + ⎮ x dx + ⌡ + +As with ``Derivative``, you can create an unevaluated integral using +``Integral``. To later evaluate this integral, call ``doit``. + + >>> expr = Integral(log(x)**2, x) + >>> expr + ⌠ + ⎮ 2 + ⎮ log (x) dx + ⌡ + >>> expr.doit() + 2 + x⋅log (x) - 2⋅x⋅log(x) + 2⋅x + +``integrate`` uses powerful algorithms that are always improving to compute +both definite and indefinite integrals, including heuristic pattern matching +type algorithms, a partial implementation of the `Risch algorithm +`_, and an algorithm using +`Meijer G-functions `_ that is +useful for computing integrals in terms of special functions, especially +definite integrals. Here is a sampling of some of the power of ``integrate``. + + >>> integ = Integral((x**4 + x**2*exp(x) - x**2 - 2*x*exp(x) - 2*x - + ... exp(x))*exp(x)/((x - 1)**2*(x + 1)**2*(exp(x) + 1)), x) + >>> integ + ⌠ + ⎮ ⎛ 4 2 x 2 x x⎞ x + ⎮ ⎝x + x ⋅ℯ - x - 2⋅x⋅ℯ - 2⋅x - ℯ ⎠⋅ℯ + ⎮ ──────────────────────────────────────── dx + ⎮ 2 2 ⎛ x ⎞ + ⎮ (x - 1) ⋅(x + 1) ⋅⎝ℯ + 1⎠ + ⌡ + >>> integ.doit() + x + ⎛ x ⎞ ℯ + log⎝ℯ + 1⎠ + ────── + 2 + x - 1 + + >>> integ = Integral(sin(x**2), x) + >>> integ + ⌠ + ⎮ ⎛ 2⎞ + ⎮ sin⎝x ⎠ dx + ⌡ + >>> integ.doit() + ⎛ ___ ⎞ + ___ ___ ⎜╲╱ 2 ⋅x⎟ + 3⋅╲╱ 2 ⋅╲╱ π ⋅fresnels⎜───────⎟⋅Γ(3/4) + ⎜ ___ ⎟ + ⎝ ╲╱ π ⎠ + ────────────────────────────────────── + 8⋅Γ(7/4) + + + >>> integ = Integral(x**y*exp(-x), (x, 0, oo)) + >>> integ + ∞ + ⌠ + ⎮ y -x + ⎮ x ⋅ℯ dx + ⌡ + 0 + >>> integ.doit() + ⎧ Γ(y + 1) for -re(y) < 1 + ⎪ + ⎪∞ + ⎪⌠ + ⎨⎮ y -x + ⎪⎮ x ⋅ℯ dx otherwise + ⎪⌡ + ⎪0 + ⎩ + +This last example returned a ``Piecewise`` expression because the integral +does not converge unless `\Re(y) > 1.` + +Limits +====== + +SymPy can compute symbolic limits with the ``limit`` function. The syntax to compute + +.. math:: + + \lim_{x\to x_0} f(x) + +is ``limit(f(x), x, x0)``. + + >>> limit(sin(x)/x, x, 0) + 1 + +``limit`` should be used instead of ``subs`` whenever the point of evaluation +is a singularity. Even though SymPy has objects to represent `\infty`, using +them for evaluation is not reliable because they do not keep track of things +like rate of growth. Also, things like `\infty - \infty` and +`\frac{\infty}{\infty}` return `\mathrm{nan}` (not-a-number). For example + + >>> expr = x**2/exp(x) + >>> expr.subs(x, oo) + nan + >>> limit(expr, x, oo) + 0 + +Like ``Derivative`` and ``Integral``, ``limit`` has an unevaluated +counterpart, ``Limit``. To evaluate it, use ``doit``. + + >>> expr = Limit((cos(x) - 1)/x, x, 0) + >>> expr + cos(x) - 1 + lim ────────── + x->0 x + >>> expr.doit() + 0 + +To evaluate a limit at one side only, pass ``'+'`` or ``'-'`` as a third +argument to ``limit``. For example, to compute + +.. math:: + + \lim_{x\to 0^+}\frac{1}{x}, + +do + + >>> limit(1/x, x, 0, '+') + ∞ + +As opposed to + + >>> limit(1/x, x, 0, '-') + -∞ + +Series Expansion +================ + +SymPy can compute asymptotic series expansions of functions around a point. To +compute the expansion of `f(x)` around the point `x = x_0` terms of order +`x^n`, use ``f(x).series(x, x0, n)``. ``x0`` and ``n`` can be omitted, in +which case the defaults ``x0=0`` and ``n=6`` will be used. + + >>> expr = exp(sin(x)) + >>> expr.series(x, 0, 4) + 2 + x ⎛ 4⎞ + 1 + x + ── + O⎝x ⎠ + 2 + +The `O\left (x^4\right )` term at the end represents the Landau order term at +`x=0` (not to be confused with big O notation used in computer science, which +generally represents the Landau order term at `x=\infty`). It means that all +x terms with power greater than or equal to `x^4` are omitted. Order terms +can be created and manipulated outside of ``series``. They automatically +absorb higher order terms. + + >>> x + x**3 + x**6 + O(x**4) + 3 ⎛ 4⎞ + x + x + O⎝x ⎠ + >>> x*O(1) + O(x) + +If you do not want the order term, use the ``removeO`` method. + + >>> expr.series(x, 0, 4).removeO() + 2 + x + ── + x + 1 + 2 + +Currently, ``O`` only supports orders at 0, so series expansions at points +other than 0 are computed by first shifting to 0 and then shifting back. + + >>> exp(x - 6).series(x, 6) + 2 3 4 5 + x x x x ⎛ 6⎞ + 1 + x + ── + ── + ── + ─── + O⎝x ⎠ + 2 6 24 120 + +This means that if you compute the series expansion at a point other than 0, +the result will be shifted to 0. You can easily shift it back with ``subs``. + + >>> exp(x - 6).series(x, 6).removeO().subs(x, x - 6) + 5 4 3 2 + (x - 6) (x - 6) (x - 6) (x - 6) + x + ──────── + ──────── + ──────── + ──────── - 5 + 120 24 6 2 diff -Nru python3-sympy-0.7.2/doc/src/tutorial/gotchas.rst python3-sympy-0.7.3/doc/src/tutorial/gotchas.rst --- python3-sympy-0.7.2/doc/src/tutorial/gotchas.rst 1970-01-01 00:00:00.000000000 +0000 +++ python3-sympy-0.7.3/doc/src/tutorial/gotchas.rst 2013-07-13 17:53:31.000000000 +0000 @@ -0,0 +1,288 @@ +========= + Gotchas +========= + +To begin, we should make something about SymPy clear. SymPy is nothing more +than a Python library, like ``NumPy``, ``Django``, or even modules in the +Python standard library ``sys`` or ``re``. What this means is that SymPy does +not add anything to the Python language. Limitations that are inherent in the +Python language are also inherent in SymPy. It also means that SymPy tries to +use Python idioms whenever possible, making programming with SymPy easy for +those already familiar with programming with Python. As a simple example, +SymPy uses Python syntax to build expressions. Implicit multiplication (like +``3x`` or ``3 x``) is not allowed in Python, and thus not allowed in SymPy. +To multiply ``3`` and ``x``, you must type ``3*x`` with the ``*``. + +.. _tutorial-gotchas-symbols: + +Symbols +======= + +One consequence of this fact is that SymPy can be used in any environment +where Python is available. We just import it, like we would any other +library: + + >>> from sympy import * + +This imports all the functions and classes from SymPy into our interactive +Python session. Now, suppose we start to do a computation. + + >>> x + 1 + Traceback (most recent call last): + ... + NameError: name 'x' is not defined + +Oops! What happened here? We tried to use the variable ``x``, but it tells us +that ``x`` is not defined. In Python, variables have no meaning until they +are defined. SymPy is no different. Unlike many symbolic manipulation +systems you may have used, in SymPy, variables are not defined automatically. +To define variables, we must use ``symbols``. + + >>> x = symbols('x') + >>> x + 1 + x + 1 + +``symbols`` takes a string of variable names separated by spaces or commas, +and creates Symbols out of them. We can then assign these to variable names. +Later, we will investigate some convenient ways we can work around this issue. +For now, let us just define the most common variable names, ``x``, ``y``, and +``z``, for use through the rest of this section + + >>> x, y, z = symbols('x y z') + +As a final note, we note that the name of a Symbol and the name of the +variable it is assigned to need not have anything to do with one another. + + >>> a, b = symbols('b a') + >>> a + b + >>> b + a + +Here we have done the very confusing thing of assigning a Symbol with the name +``a`` to the variable ``b``, and a Symbol of the name ``b`` to the variable +``a``. Now the Python variable named ``a`` points to the SymPy Symbol named +``b``, and visa versa. How confusing. We could have also done something like + + >>> crazy = symbols('unrelated') + >>> crazy + 1 + unrelated + 1 + +This also shows that Symbols can have names longer than one character if we +want. + +Usually, the best practice is to assign Symbols to Python variables of the +same name, although there are exceptions: Symbol names can contain characters +that are not allowed in Python variable names, or may just want to avoid +typing long names by assigning Symbols with long names to single letter Python +variables. + +To avoid confusion, throughout this tutorial, Symbol names and Python variable +names will always coincide. Furthermore, the word "Symbol" will refer to a +SymPy Symbol and the word "variable" will refer to a Python variable. + +Finally, let us be sure we understand the difference between SymPy Symbols and +Python variables. Consider the following:: + + x = symbols('x') + expr = x + 1 + x = 2 + print expr + +What do you think the output of this code will be? If you thought ``3``, +you're wrong. Let's see what really happens + + >>> x = symbols('x') + >>> expr = x + 1 + >>> x = 2 + >>> print(expr) + x + 1 + +Changing ``x`` to ``2`` had no effect on ``expr``. This is because ``x = 2`` +changes the Python variable ``x`` to ``2``, but has no effect on the SymPy +Symbol ``x``, which was what we used in creating ``expr``. When we created +``expr``, the Python variable ``x`` was a Symbol. After we created, it, we +changed the Python variable ``x`` to 2. But ``expr`` remains the same. This +behavior is not unique to SymPy. All Python programs work this way: if a +variable is changed, expressions that were already created with that variable +do not change automatically. For example + + >>> x = 'abc' + >>> expr = x + 'def' + >>> expr + 'abcdef' + >>> x = 'ABC' + >>> expr + 'abcdef' + + +.. sidebar:: Quick Tip + + To change the value of a Symbol in an expression, use ``subs`` + + >>> x = symbols('x') + >>> expr = x + 1 + >>> expr.subs(x, 2) + 3 + +In this example, if we want to know what ``expr`` is with the new value of +``x``, we need to reevaluate the code that created ``expr``, namely, ``expr = +x + 1``. This can be complicated if several lines created ``expr``. One +advantage of using a symbolic computation system like SymPy is that we can +build a symbolic representation for ``expr``, and then substitute ``x`` with +values. The correct way to do this in SymPy is to use ``subs``, which will be +discussed in more detail later. + + >>> x = symbols('x') + >>> expr = x + 1 + >>> expr.subs(x, 2) + 3 + +.. TODO: Add link to basic operations section + +.. _tutorial_gotchas_equals: + +Equals signs +============ + +Another very important consequence of the fact that SymPy does not extend +Python syntax is that ``=`` does not represent equality in SymPy. Rather it +is Python variable assignment. This is hard-coded into the Python language, +and SymPy makes no attempts to change that. + +You may think, however, that ``==``, which is used for equality testing in +Python, is used for SymPy as equality. This is not quite correct either. Let +us see what happens when we use ``==``. + + >>> x + 1 == 4 + False + +Instead of treating ``x + 1 == 4`` symbolically, we just got ``False``. In +SymPy, ``==`` represents exact structural equality testing. This means that +``a == b`` means that we are *asking* if `a = b`. We always get a ``bool`` as +the result of ``==``. There is a separate object, called ``Eq``, which can be +used to create symbolic equalities + + >>> Eq(x + 1, 4) + x + 1 == 4 + +There is one additional caveat about ``==`` as well. Suppose we want to know +if `(x + 1)^2 = x^2 + 2x + 1`. We might try something like this: + + >>> (x + 1)**2 == x**2 + 2*x + 1 + False + +We got ``False`` again. However, `(x + 1)^2` *does* equal `x^2 + 2x + 1`. What +is going on here? Did we find a bug in SymPy, or is it just not powerful +enough to recognize this basic algebraic fact? + +Recall from above that ``==`` represents *exact* structural equality testing. +"Exact" here means that two expressions will compare equal with ``==`` only if +they are exactly equal structurally. Here, `(x + 1)^2` and `x^2 + 2x + 1` are +not the same symbolically. One is the power of an addition of two terms, and +the other is the addition of three terms. + +It turns out that when using SymPy as a library, having ``==`` test for exact +symbolic equality is far more useful than having it represent symbolic +equality, or having it test for mathematical equality. However, as a new +user, you will probably care more about the latter two. We have already seen +an alternative to representing equalities symbolically, ``Eq``. To test if +two things are equal, it is best to recall the basic fact that if `a = b`, +then `a - b = 0`. Thus, the best way to check if `a = b` is to take `a - b` +and simplify it, and see if it goes to 0. We will learn :ref:`later +` that the function to do this is called ``simplify``. This +method is not infallible---in fact, it can be `theoretically proven +`_ that it is impossible +to determine if two symbolic expressions are identically equal in +general---but for most common expressions, it works quite well. + + >>> a = (x + 1)**2 + >>> b = x**2 + 2*x + 1 + >>> simplify(a - b) + 0 + >>> c = x**2 - 2*x + 1 + >>> simplify(a - c) + 4*x + +There is also a method called ``equals`` that tests if two expressions are +equal by evaluating them numerically at random points. + + >>> a = cos(x)**2 - sin(x)**2 + >>> b = cos(2*x) + >>> a.equals(b) + True + +Two Final Notes: ``^`` and ``/`` +================================ + +You may have noticed that we have been using ``**`` for exponentiation instead +of the standard ``^``. That's because SymPy follows Python's conventions. In +Python, ``^`` represents logical exclusive or. SymPy follows this convention: + + >>> True ^ False + True + >>> True ^ True + False + >>> x^y + Or(And(Not(x), y), And(Not(y), x)) + +Finally, a small technical discussion on how SymPy works is in order. When +you type something like ``x + 1``, the SymPy Symbol ``x`` is added to the +Python int ``1``. Python's operator rules then allow SymPy to tell Python +that SymPy objects know how to be added to Python ints, and so ``1`` is +automatically converted to the SymPy Integer object. + +This sort of operator magic happens automatically behind the scenes, and you +rarely need to even know that it is happening. However, there is one +exception. Whenever you combine a SymPy object and a SymPy object, or a SymPy +object and a Python object, you get a SymPy object, but whenever you combine +two Python objects, SymPy never comes into play, and so you get a Python +object. + + >>> type(Integer(1) + 1) + + >>> type(1 + 1) + <... 'int'> + +This is usually not a big deal. Python ints work much the same as SymPy +Integers, but there is one important exception: division. In SymPy, the +division of two Integers gives a Rational: + + >>> Integer(1)/Integer(3) + 1/3 + >>> type(Integer(1)/Integer(3)) + + +But in Python ``/`` represents either integer division or floating point +division, depending on whether you are in Python 2 or Python 3, and depending +on whether or not you have run ``from __future__ import division``: + + >>> + >>> 1/2 #doctest: +SKIP + 0.5 + +To avoid this, we can construct the rational object explicitly + + >>> Rational(1, 2) + 1/2 + +This problem also comes up whenever we have a larger symbolic expression with +``int/int`` in it. For example: + + >>> x + 1/2 #doctest: +SKIP + x + 0.5 + +This happens because Python first evaluates ``1/2`` into ``0.5``, and then +that is cast into a SymPy type when it is added to ``x``. Again, we can get +around this by explicitly creating a Rational: + + >>> x + Rational(1, 2) + x + 1/2 + +There are several tips on avoiding this situation in the :ref:`gotchas` +document. + +Further Reading +=============== + +For more discussion on the topics covered in this section, see :ref:`gotchas`. diff -Nru python3-sympy-0.7.2/doc/src/tutorial/index.rst python3-sympy-0.7.3/doc/src/tutorial/index.rst --- python3-sympy-0.7.2/doc/src/tutorial/index.rst 1970-01-01 00:00:00.000000000 +0000 +++ python3-sympy-0.7.3/doc/src/tutorial/index.rst 2013-07-13 17:50:18.000000000 +0000 @@ -0,0 +1,19 @@ +.. _tutorial: + +================ + SymPy Tutorial +================ + +.. toctree:: + :maxdepth: 2 + + preliminaries.rst + intro.rst + printing.rst + gotchas.rst + basic_operations.rst + simplification.rst + calculus.rst + solvers.rst + matrices.rst + manipulation.rst diff -Nru python3-sympy-0.7.2/doc/src/tutorial/intro.rst python3-sympy-0.7.3/doc/src/tutorial/intro.rst --- python3-sympy-0.7.2/doc/src/tutorial/intro.rst 1970-01-01 00:00:00.000000000 +0000 +++ python3-sympy-0.7.3/doc/src/tutorial/intro.rst 2013-07-13 17:50:18.000000000 +0000 @@ -0,0 +1,228 @@ +============== + Introduction +============== + +What is Symbolic Computation? +============================= + +Symbolic computation deals with the computation of mathematical objects +symbolically. This means that the mathematical objects are represented +exactly, not approximately, and mathematical expressions with unevaluated +variables are left in symbolic form. + +Let's take an example. Say we wanted to use the built-in Python functions to +compute square roots. We might do something like this + + >>> import math + >>> math.sqrt(9) + 3.0 + +9 is a perfect square, so we got the exact answer, 3. But suppose we computed +the square root of a number that isn't a perfect square + + >>> math.sqrt(8) + 2.82842712475 + +Here we got an approximate result. 2.82842712475 is not the exact square root +of 8 (indeed, the actual square root of 8 cannot be represented by a finite +decimal, since it is an irrational number). If all we cared about was the +decimal form of the square root of 8, we would be done. + +But suppose we want to go further. Recall that `\sqrt{8} = \sqrt{4\cdot 2} = +2\sqrt{2}`. We would have a hard time deducing this from the above result. +This is where symbolic computation comes in. With a symbolic computation +system like SymPy, square roots of numbers that are not perfect squares are +left unevaluated by default + + >>> import sympy + >>> sympy.sqrt(3) + sqrt(3) + +Furthermore---and this is where we start to see the real power of symbolic +computation---symbolic results can be symbolically simplified. + + >>> sympy.sqrt(8) + 2*sqrt(2) + +A More Interesting Example +========================== + +The above example starts to show how we can manipulate irrational numbers +exactly using SymPy. But it is much more powerful than that. Symbolic +computation systems (which by the way, are also often called computer algebra +systems, or just CASs) such as SymPy are capable of computing symbolic +expressions with variables. + +As we will see later, in SymPy, variables are defined using ``symbols``. +Unlike many symbolic manipulation systems, variables in SymPy must be defined +before they are used (the reason for this will be discussed in the :ref:`next +section `). + +Let us define a symbolic expression, representing the mathematical expression +`x + 2y`. + + >>> from sympy import symbols + >>> x, y = symbols('x y') + >>> expr = x + 2*y + >>> expr + x + 2*y + +Note that we wrote ``x + 2*y`` just as we would if ``x`` and ``y`` were +ordinary Python variables. But in this case, instead of evaluating to +something, the expression remains as just ``x + 2*y``. Now let us play around +with it: + + >>> expr + 1 + x + 2*y + 1 + >>> expr - x + 2*y + +Notice something in the above example. When we typed ``expr - x``, we did not +get ``x + 2*y - x``, but rather just ``2*y``. The ``x`` and the ``-x`` +automatically canceled one another. This is similar to how ``sqrt(8)`` +automatically turned into ``2*sqrt(2)`` above. This isn't always the case in +SymPy, however: + + >>> x*expr + x*(x + 2*y) + +Here, we might have expected `x(x + 2y)` to transform into `x^2 + 2xy`, but +instead we see that the expression was left alone. This is a common theme in +SymPy. Aside from obvious simplifications like `x - x = 0` and `\sqrt{8} = +2\sqrt{2}`, most simplifications are not performed automatically. This is +because we might prefer the factored form `x(x + 2y)`, or we might prefer the +expanded form `x^2 + 2xy`. Both forms are useful in different circumstances. +In SymPy, there are functions to go from one form to the other + + >>> from sympy import expand, factor + >>> expanded_expr = expand(x*expr) + >>> expanded_expr + x**2 + 2*x*y + >>> factor(expanded_expr) + x*(x + 2*y) + +The Power of Symbolic Computation +================================= + +The real power of a symbolic computation system such as SymPy is the ability +to do all sorts of computations symbolically. SymPy can compute derivatives, +integrals, and limits, solve equations, work with matrices, and much, much +more, and do it all symbolically. It includes modules for plotting, printing +(like 2D pretty printed output of math formulas, or `\LaTeX`), code +generation, physics, statistics, combinatorics, number theory, geometry, +logic, and more. Here is a small sampling of the sort of symbolic power SymPy +is capable of, to whet your appetite. + + >>> from sympy import * + >>> x, t, z, nu = symbols('x t z nu') + +- This will make all further example pretty print with unicode characters. + + >>> init_printing(use_unicode=True) + +- Take the derivative of `\sin{(x)}e^x`. + + >>> diff(sin(x)*exp(x), x) + x x + ℯ ⋅sin(x) + ℯ ⋅cos(x) + +- Compute `\int(e^x\sin{(x)} + e^x\cos{(x)})\,dx`. + + >>> integrate(exp(x)*sin(x) + exp(x)*cos(x), x) + x + ℯ ⋅sin(x) + +- Compute `\int_{-\infty}^\infty \sin{(x^2)}\,dx`. + + >>> integrate(sin(x**2), (x, -oo, oo)) + ___ ___ + ╲╱ 2 ⋅╲╱ π + ─────────── + 2 + +- Find :math:`\lim_{x\to 0}\frac{\sin{(x)}}{x}`. + + >>> limit(sin(x)/x, x, 0) + 1 + +- Solve `x^2 - 2 = 0`. + + >>> solve(x**2 - 2, x) + ⎡ ___ ___⎤ + ⎣-╲╱ 2 , ╲╱ 2 ⎦ + +- Solve the differential equation `y'' - y = e^t`. + + >>> y = Function('y') + >>> dsolve(Eq(y(t).diff(t, t) - y(t), exp(t)), y(t)) + -t ⎛ t⎞ t + y(t) = C₂⋅ℯ + ⎜C₁ + ─⎟⋅ℯ + ⎝ 2⎠ + +- Find the eigenvalues of `\left[\begin{smallmatrix}1 & 2\\2 & + 2\end{smallmatrix}\right]`. + + >>> Matrix([[1, 2], [2, 2]]).eigenvals() + ⎧ ____ ____ ⎫ + ⎪3 ╲╱ 17 ╲╱ 17 3 ⎪ + ⎨─ + ──────: 1, - ────── + ─: 1⎬ + ⎪2 2 2 2 ⎪ + ⎩ ⎭ + +- Rewrite the Bessel function `J_{\nu}\left(z\right)` in terms of the + spherical Bessel function `j_\nu(z)`. + + >>> besselj(nu, z).rewrite(jn) + ___ ___ + ╲╱ 2 ⋅╲╱ z ⋅jn(ν - 1/2, z) + ────────────────────────── + ___ + ╲╱ π + +- Print `\int_{0}^{\pi} \cos^{2}{\left (x \right )}\, dx` using `\LaTeX`. + + >>> latex(Integral(cos(x)**2, (x, 0, pi))) + \int_{0}^{\pi} \cos^{2}{\left (x \right )}\, dx + +Why SymPy? +========== + +There are many computer algebra systems out there. `This +`_ Wikipedia +article lists many of them. What makes SymPy a better choice than the +alternatives? + +First off, SymPy is completely free. It is open source, and licensed under the +liberal BSD license, so you can even modify the source code and sell if you +want to. This contrasts with popular commercial systems like Maple or +Mathematica that cost hundreds of dollars in licenses. + +Second, SymPy uses Python. Most computer algebra systems invent their own +language. Not SymPy. SymPy is written entirely in Python, and is executed +entirely in Python. This means that if you already know Python, it is much +easier to get started with SymPy, because you already know the syntax (and if +you don't know Python, it is really easy to learn). Plus, we already know +that Python is a well-designed, battle-tested language. The SymPy developers +are confident in their abilities in writing mathematical software, but +inventing a whole new programming language is a completely different thing. +By reusing an existing language, we are able to focus on those things that +matter, the mathematics. + +Another computer algebra system, Sage also uses Python as its language. But +Sage is large, with a download of over a gigabyte. An advantage of SymPy is +that it is lightweight. In addition to being relatively small, it has no +dependencies other than Python, so it can be used almost anywhere easily. +Furthermore, the goals of Sage and the goals of SymPy are different. Sage +aims to be a full featured system for mathematics, and aims to do so by +compiling all the major open source mathematical systems together into +one. When you call some function in Sage, such as ``integrate``, it calls out +to one of the open source packages that it includes. In fact, SymPy is +included in Sage. SymPy on the other hand aims to be an independent system, +with all the features implemented in SymPy itself. + +A final important feature of SymPy is that it can be used as a library. Many +computer algebra systems focus on being usable in interactive environments, but +if you wish to automate or extend them, it is difficult to do. With SymPy, +you can just as easily use it in an interactive Python environment or import +it in your own Python application. SymPy also provides APIs to make it easy +to extend it with your own custom functions. diff -Nru python3-sympy-0.7.2/doc/src/tutorial/manipulation.rst python3-sympy-0.7.3/doc/src/tutorial/manipulation.rst --- python3-sympy-0.7.2/doc/src/tutorial/manipulation.rst 1970-01-01 00:00:00.000000000 +0000 +++ python3-sympy-0.7.3/doc/src/tutorial/manipulation.rst 2013-07-13 17:53:31.000000000 +0000 @@ -0,0 +1,485 @@ +.. _tutorial-manipulation: + +================================== + Advanced Expression Manipulation +================================== + +In this section, we discuss some ways that we can perform advanced +manipulation of expressions. + +Understanding Expression Trees +============================== + +.. sidebar :: Quick Tip + + To play with the ``srepr`` form of expressions in the SymPy Live shell, + change the output format to ``Repr`` in the settings. + +Before we can do this, we need to understand how expressions are represented +in SymPy. A mathematical expression is represented as a tree. Let us take +the expression `x^2 + xy`, i.e., ``x**2 + x*y``. We can see what this +expression looks like internally by using ``srepr`` + + >>> from sympy import * + >>> x, y, z = symbols('x y z') + + >>> expr = x**2 + x*y + >>> srepr(expr) + "Add(Pow(Symbol('x'), Integer(2)), Mul(Symbol('x'), Symbol('y')))" + +The easiest way to tear this apart is to look at a diagram of the expression +tree: + +.. This comes from dotprint(x**2 + x*y, labelfunc=srepr) + +.. graphviz:: + + digraph{ + + # Graph style + "rankdir"="TD" + + ######### + # Nodes # + ######### + + "Symbol(x)_(0, 0)" ["color"="black", "label"="Symbol('x')", "shape"="ellipse"]; + "Integer(2)_(1, 1)" ["color"="black", "label"="Integer(2)", "shape"="ellipse"]; + "Symbol(y)_(0, 1)" ["color"="black", "label"="Symbol('y')", "shape"="ellipse"]; + "Symbol(x)_(1, 0)" ["color"="black", "label"="Symbol('x')", "shape"="ellipse"]; + "Mul(Symbol(x), Symbol(y))_(0,)" ["color"="black", "label"="Mul", "shape"="ellipse"]; + "Pow(Symbol(x), Integer(2))_(1,)" ["color"="black", "label"="Pow", "shape"="ellipse"]; + "Add(Mul(Symbol(x), Symbol(y)), Pow(Symbol(x), Integer(2)))_()" ["color"="black", "label"="Add", "shape"="ellipse"]; + + ######### + # Edges # + ######### + + "Mul(Symbol(x), Symbol(y))_(0,)" -> "Symbol(x)_(0, 0)"; + "Mul(Symbol(x), Symbol(y))_(0,)" -> "Symbol(y)_(0, 1)"; + "Pow(Symbol(x), Integer(2))_(1,)" -> "Symbol(x)_(1, 0)"; + "Pow(Symbol(x), Integer(2))_(1,)" -> "Integer(2)_(1, 1)"; + "Add(Mul(Symbol(x), Symbol(y)), Pow(Symbol(x), Integer(2)))_()" -> "Mul(Symbol(x), Symbol(y))_(0,)"; + "Add(Mul(Symbol(x), Symbol(y)), Pow(Symbol(x), Integer(2)))_()" -> "Pow(Symbol(x), Integer(2))_(1,)"; + } + +.. note:: + + The above diagram was made using `Graphviz `_ and + the :py:meth:`dotprint ` function. + +First, let's look at the leaves of this tree. Symbols are instances of the +class Symbol. While we have been doing + + >>> x = symbols('x') + +we could have also done + + >>> x = Symbol('x') + +Either way, we get a Symbol with the name "x" [#symbols-fn]_. For the number in the +expression, 2, we got ``Integer(2)``. ``Integer`` is the SymPy class for +integers. It is similar to the Python built-in type ``int``, except that +``Integer`` plays nicely with other SymPy types. + +When we write ``x**2``, this creates a ``Pow`` object. ``Pow`` is short for +"power". + + >>> srepr(x**2) + "Pow(Symbol('x'), Integer(2))" + +We could have created the same object by calling ``Pow(x, 2)`` + + >>> Pow(x, 2) + x**2 + +Note that in the ``srepr`` output, we see ``Integer(2)``, the SymPy version of +integers, even though technically, we input ``2``, a Python int. In general, +whenever you combine a SymPy object with a non-SymPy object via some function +or operation, the non-SymPy object will be converted into a SymPy object. The +function that does this is ``sympify`` [#sympify-fn]_. + + >>> type(2) + <... 'int'> + >>> type(sympify(2)) + + +We have seen that ``x**2`` is represented as ``Pow(x, 2)``. What about +``x*y``? As we might expect, this is the multiplication of ``x`` and ``y``. +The SymPy class for multiplication is ``Mul``. + + >>> srepr(x*y) + "Mul(Symbol('x'), Symbol('y'))" + +Thus, we could have created the same object by writing ``Mul(x, y)``. + + >>> Mul(x, y) + x*y + +Now we get to our final expression, ``x**2 + x*y``. This is the addition of +our last two objects, ``Pow(x, 2)``, and ``Mul(x, y)``. The SymPy class for +addition is ``Add``, so, as you might expect, to create this object, we use +``Add(Pow(x, 2), Mul(x, y)``. + + >>> Add(Pow(x, 2), Mul(x, y)) + x**2 + x*y + +SymPy expression trees can have many branches, and can be quite deep or quite +broad. Here is a more complicated example + + >>> expr = sin(x*y)/2 - x**2 + 1/y + >>> srepr(expr) + "Add(Mul(Integer(-1), Pow(Symbol('x'), Integer(2))), Mul(Rational(1, 2), + sin(Mul(Symbol('x'), Symbol('y')))), Pow(Symbol('y'), Integer(-1)))" + +Here is a diagram + +.. dotprint(sin(x*y)/2 - x**2 + 1/y, labelfunc=srepr) + +.. graphviz:: + + digraph{ + + # Graph style + "rankdir"="TD" + + ######### + # Nodes # + ######### + + "Half()_(0, 0)" ["color"="black", "label"="Rational(1, 2)", "shape"="ellipse"]; + "Symbol(y)_(2, 0)" ["color"="black", "label"="Symbol('y')", "shape"="ellipse"]; + "Symbol(x)_(1, 1, 0)" ["color"="black", "label"="Symbol('x')", "shape"="ellipse"]; + "Integer(2)_(1, 1, 1)" ["color"="black", "label"="Integer(2)", "shape"="ellipse"]; + "NegativeOne()_(2, 1)" ["color"="black", "label"="Integer(-1)", "shape"="ellipse"]; + "NegativeOne()_(1, 0)" ["color"="black", "label"="Integer(-1)", "shape"="ellipse"]; + "Symbol(y)_(0, 1, 0, 1)" ["color"="black", "label"="Symbol('y')", "shape"="ellipse"]; + "Symbol(x)_(0, 1, 0, 0)" ["color"="black", "label"="Symbol('x')", "shape"="ellipse"]; + "Pow(Symbol(x), Integer(2))_(1, 1)" ["color"="black", "label"="Pow", "shape"="ellipse"]; + "Pow(Symbol(y), NegativeOne())_(2,)" ["color"="black", "label"="Pow", "shape"="ellipse"]; + "Mul(Symbol(x), Symbol(y))_(0, 1, 0)" ["color"="black", "label"="Mul", "shape"="ellipse"]; + "sin(Mul(Symbol(x), Symbol(y)))_(0, 1)" ["color"="black", "label"="sin", "shape"="ellipse"]; + "Mul(Half(), sin(Mul(Symbol(x), Symbol(y))))_(0,)" ["color"="black", "label"="Mul", "shape"="ellipse"]; + "Mul(NegativeOne(), Pow(Symbol(x), Integer(2)))_(1,)" ["color"="black", "label"="Mul", "shape"="ellipse"]; + "Add(Mul(Half(), sin(Mul(Symbol(x), Symbol(y)))), Mul(NegativeOne(), Pow(Symbol(x), Integer(2))), Pow(Symbol(y), NegativeOne()))_()" ["color"="black", "label"="Add", "shape"="ellipse"]; + + ######### + # Edges # + ######### + + "Pow(Symbol(y), NegativeOne())_(2,)" -> "Symbol(y)_(2, 0)"; + "Pow(Symbol(x), Integer(2))_(1, 1)" -> "Symbol(x)_(1, 1, 0)"; + "Pow(Symbol(x), Integer(2))_(1, 1)" -> "Integer(2)_(1, 1, 1)"; + "Pow(Symbol(y), NegativeOne())_(2,)" -> "NegativeOne()_(2, 1)"; + "Mul(Symbol(x), Symbol(y))_(0, 1, 0)" -> "Symbol(x)_(0, 1, 0, 0)"; + "Mul(Symbol(x), Symbol(y))_(0, 1, 0)" -> "Symbol(y)_(0, 1, 0, 1)"; + "Mul(Half(), sin(Mul(Symbol(x), Symbol(y))))_(0,)" -> "Half()_(0, 0)"; + "Mul(NegativeOne(), Pow(Symbol(x), Integer(2)))_(1,)" -> "NegativeOne()_(1, 0)"; + "sin(Mul(Symbol(x), Symbol(y)))_(0, 1)" -> "Mul(Symbol(x), Symbol(y))_(0, 1, 0)"; + "Mul(NegativeOne(), Pow(Symbol(x), Integer(2)))_(1,)" -> "Pow(Symbol(x), Integer(2))_(1, 1)"; + "Mul(Half(), sin(Mul(Symbol(x), Symbol(y))))_(0,)" -> "sin(Mul(Symbol(x), Symbol(y)))_(0, 1)"; + "Add(Mul(Half(), sin(Mul(Symbol(x), Symbol(y)))), Mul(NegativeOne(), Pow(Symbol(x), Integer(2))), Pow(Symbol(y), NegativeOne()))_()" -> "Pow(Symbol(y), NegativeOne())_(2,)"; + "Add(Mul(Half(), sin(Mul(Symbol(x), Symbol(y)))), Mul(NegativeOne(), Pow(Symbol(x), Integer(2))), Pow(Symbol(y), NegativeOne()))_()" -> "Mul(Half(), sin(Mul(Symbol(x), Symbol(y))))_(0,)"; + "Add(Mul(Half(), sin(Mul(Symbol(x), Symbol(y)))), Mul(NegativeOne(), Pow(Symbol(x), Integer(2))), Pow(Symbol(y), NegativeOne()))_()" -> "Mul(NegativeOne(), Pow(Symbol(x), Integer(2)))_(1,)"; + } + +This expression reveals some interesting things about SymPy expression +trees. Let's go through them one by one. + +Let's first look at the term ``x**2``. As we expected, we see ``Pow(x, 2)``. +One level up, we see we have ``Mul(-1, Pow(x, 2))``. There is no subtraction +class in SymPy. ``x - y`` is represented as ``x + -y``, or, more completely, +``x + -1*y``, i.e., ``Add(x, Mul(-1, y))``. + + >>> expr = x - y + >>> srepr(x - y) + "Add(Symbol('x'), Mul(Integer(-1), Symbol('y')))" + +.. dotprint(x - y, labelfunc=srepr) + +.. graphviz:: + + digraph{ + + # Graph style + "rankdir"="TD" + + ######### + # Nodes # + ######### + + "Symbol(x)_(1,)" ["color"="black", "label"="Symbol('x')", "shape"="ellipse"]; + "Symbol(y)_(0, 1)" ["color"="black", "label"="Symbol('y')", "shape"="ellipse"]; + "NegativeOne()_(0, 0)" ["color"="black", "label"="Integer(-1)", "shape"="ellipse"]; + "Mul(NegativeOne(), Symbol(y))_(0,)" ["color"="black", "label"="Mul", "shape"="ellipse"]; + "Add(Mul(NegativeOne(), Symbol(y)), Symbol(x))_()" ["color"="black", "label"="Add", "shape"="ellipse"]; + + ######### + # Edges # + ######### + + "Mul(NegativeOne(), Symbol(y))_(0,)" -> "Symbol(y)_(0, 1)"; + "Mul(NegativeOne(), Symbol(y))_(0,)" -> "NegativeOne()_(0, 0)"; + "Add(Mul(NegativeOne(), Symbol(y)), Symbol(x))_()" -> "Symbol(x)_(1,)"; + "Add(Mul(NegativeOne(), Symbol(y)), Symbol(x))_()" -> "Mul(NegativeOne(), Symbol(y))_(0,)"; + } + +Next, look at ``1/y``. We might expect to see something like ``Div(1, y)``, +but similar to subtraction, there is no class in SymPy for division. Rather, +division is represented by a power of -1. Hence, we have ``Pow(y, -1)``. +What if we had divided something other than 1 by ``y``, like ``x/y``? Let's +see. + + >>> expr = x/y + >>> srepr(expr) + "Mul(Symbol('x'), Pow(Symbol('y'), Integer(-1)))" + +.. dotprint(x/y, labelfunc=srepr) + +.. graphviz:: + + digraph{ + + # Graph style + "rankdir"="TD" + + ######### + # Nodes # + ######### + + "Symbol(x)_(0,)" ["color"="black", "label"="Symbol('x')", "shape"="ellipse"]; + "Symbol(y)_(1, 0)" ["color"="black", "label"="Symbol('y')", "shape"="ellipse"]; + "NegativeOne()_(1, 1)" ["color"="black", "label"="Integer(-1)", "shape"="ellipse"]; + "Pow(Symbol(y), NegativeOne())_(1,)" ["color"="black", "label"="Pow", "shape"="ellipse"]; + "Mul(Symbol(x), Pow(Symbol(y), NegativeOne()))_()" ["color"="black", "label"="Mul", "shape"="ellipse"]; + + ######### + # Edges # + ######### + + "Pow(Symbol(y), NegativeOne())_(1,)" -> "Symbol(y)_(1, 0)"; + "Pow(Symbol(y), NegativeOne())_(1,)" -> "NegativeOne()_(1, 1)"; + "Mul(Symbol(x), Pow(Symbol(y), NegativeOne()))_()" -> "Symbol(x)_(0,)"; + "Mul(Symbol(x), Pow(Symbol(y), NegativeOne()))_()" -> "Pow(Symbol(y), NegativeOne())_(1,)"; + } + +We see that ``x/y`` is represented as ``x*y**-1``, i.e., ``Mul(x, Pow(y, +-1))``. + +Finally, let's look at the ``sin(x*y)/2`` term. Following the pattern of the +previous example, we might expect to see ``Mul(sin(x*y), Pow(Integer(2), +-1))``. But instead, we have ``Mul(Rational(1, 2), sin(x*y))``. Rational +numbers are always combined into a single term in a multiplication, so that +when we divide by 2, it is represented as multiplying by 1/2. + +Finally, one last note. You may have noticed that the order we entered our +expression and the order that it came out from ``srepr`` or in the graph were +different. You may have also noticed this phenonemon earlier in the +tutorial. For example + + >>> 1 + x + x + 1 + +This because in SymPy, the arguments of the commutative operations ``Add`` and +``Mul`` are stored in an arbitrary (but consistent!) order, which is +independent of the order inputted (if you're worried about noncommutative +multiplication, don't be. In SymPy, you can create noncommutative Symbols +using ``Symbol('A', commutative=False)``, and the order of multiplication for +noncommutative Symbols is kept the same as the input). Furthermore, as we +shall see in the next section, the printing order and the order in which +things are stored internally need not be the same either. + +.. sidebar:: Quick Tip + + The way an expression is represented internally and the way it is printed + are often not the same. + +In general, an important thing to keep in mind when working with SymPy expression +trees is this: the internal representation of an expression and the way it is +printed need not be the same. The same is true for the input form. If some +expression manipulation algorithm is not working in the way you expected it +to, chances are, the internal representation of the object is different from +what you thought it was. + +Recursing through an Expression Tree +==================================== + +Now that you know how expression trees work in SymPy, let's look at how to dig +our way through an expression tree. Every object in SymPy has two very +important attributes, ``func``, and ``args``. + + +func +---- + +``func`` is the head of the object. For example, ``(x*y).func`` is ``Mul``. +Usually it is the same as the class of the object (though there are exceptions +to this rule). + +Two notes about ``func``. First, the class of an object need not be the same +as the one used to create it. For example + + >>> expr = Add(x, x) + >>> expr.func + + +We created ``Add(x, x)``, so we might expect ``expr.func`` to be ``Add``, but +instead we got ``Mul``. Why is that? Let's take a closer look at ``expr``. + + >>> expr + 2*x + +``Add(x, x)``, i.e., ``x + x``, was automatically converted into ``Mul(2, +x)``, i.e., ``2*x``, which is a ``Mul``. SymPy classes make heavy use of the +``__new__`` class constructor, which, unlike ``__init__``, allows a different +class to be returned from the constructor. + +Second, some classes are special-cased, usually for efficiency reasons +[#singleton-fn]_. + + >>> Integer(2).func + + >>> Integer(0).func + + >>> Integer(-1).func + + +For the most part, these issues will not bother us. The special classes +``Zero``, ``One``, ``NegativeOne``, and so on are subclasses of ``Integer``, +so as long as you use ``isinstance``, it will not be an issue. + +args +---- + +``args`` are the top-level arguments of the object. ``(x*y).args`` would be +``(x, y)``. Let's look at some examples + + >>> expr = 3*y**2*x + >>> expr.func + + >>> expr.args + (3, x, y**2) + +From this, we can see that ``expr == Mul(3, y**2, x)``. In fact, we can see +that we can completely reconstruct ``expr`` from its ``func`` and its +``args``. + + >>> expr.func(*expr.args) + 3*x*y**2 + >>> expr == expr.func(*expr.args) + True + +Note that although we entered ``3*y**2*x``, the ``args`` are ``(3, x, y**2)``. +In a ``Mul``, the Rational coefficient will come first in the ``args``, but +other than that, the order of everything else follows no special pattern. To +be sure, though, there is an order. + + >>> expr = y**2*3*x + >>> expr.args + (3, x, y**2) + +Mul's ``args`` are sorted, so that the same ``Mul`` will have the same +``args``. But the sorting is based on some criteria designed to make the +sorting unique and efficient that has no mathematical significance. + +The ``srepr`` form of our ``expr`` is ``Mul(3, x, Pow(y, 2))``. What if we +want to get at the ``args`` of ``Pow(y, 2)``. Notice that the ``y**2`` is in +the third slot of ``expr.args``, i.e., ``expr.args[2]``. + + >>> expr.args[2] + y**2 + +So to get the ``args`` of this, we call ``expr.args[2].args``. + + >>> expr.args[2].args + (y, 2) + +Now what if we try to go deeper. What are the args of ``y``. Or ``2``. +Let's see. + + >>> y.args + () + >>> Integer(2).args + () + +They both have empty ``args``. In SymPy, empty ``args`` signal that we have +hit a leaf of the expression tree. + +So there are two possibilities for a SymPy expression. Either it has empty +``args``, in which case it is a leaf node in any expression tree, or it has +``args``, in which case, it is a branch node of any expression tree. When it +has ``args``, it can be completely rebuilt from its ``func`` and its ``args``. +This is expressed in the key invariant. + +.. topic:: Key Invariant + + Every well-formed SymPy expression must either have empty ``args`` or + satisfy ``expr == expr.func(*expr.args)``. + +(Recall that in Python if ``a`` is a tuple, then ``f(*a)`` means to call ``f`` +with arguments from the elements of ``a``, e.g., ``f(*(1, 2, 3))`` is the same +as ``f(1, 2, 3)``.) + +This key invariant allows us to write simple algorithms that walk expression +trees, change them, and rebuild them into new expressions. + +Walking the Tree +---------------- + +With this knowledge, let's look at how we can recurse through an expression +tree. The nested nature of ``args`` is a perfect fit for recursive functions. +The base case will be empty ``args``. Let's write a simple function that goes +through an expression and prints all the ``args`` at each level. + + >>> def pre(expr): + ... print(expr) + ... for arg in expr.args: + ... pre(arg) + +See how nice it is that ``()`` signals leaves in the expression tree. We +don't even have to write a base case for our recursion; it is handled +automatically by the for loop. + +Let's test our function. + + >>> expr = x*y + 1 + >>> pre(expr) + x*y + 1 + 1 + x*y + x + y + +Can you guess why we called our function ``pre``? We just wrote a pre-order +traversal function for our expression tree. See if you can write a +post-order traversal function. + +Such traversals are so common in SymPy that the generator functions +``preorder_traversal`` and ``postorder_traversal`` are provided to make such +traversals easy. We could have also written our algorithm as + + >>> for arg in preorder_traversal(expr): + ... print(arg) + x*y + 1 + 1 + x*y + x + y + +.. rubric:: Footnotes + +.. [#symbols-fn] We have been using ``symbols`` instead of ``Symbol`` because it + automatically splits apart strings into multiple ``Symbol``\ s. + ``symbols('x y z')`` returns a tuple of three ``Symbol``\ s. ``Symbol('x y + z')`` returns a single ``Symbol`` called ``x y z``. +.. [#sympify-fn] Technically, it is an internal function called ``_sympify``, + which differs from ``sympify`` in that it does not convert strings. ``x + + '2'`` is not allowed. +.. [#singleton-fn] Classes like ``One`` and ``Zero`` are singletonized, meaning + that only one object is ever created, no matter how many times the class is + called. This is done for space efficiency, as these classes are very + common. For example, ``Zero`` might occur very often in a sparse matrix + represented densely. As we have seen, ``NegativeOne`` occurs any time we + have ``-x`` or ``1/x``. It is also done for speed efficiency because + singletonized objects can be compared by ``is``. The unique objects for + each singletonized class can be accessed from the ``S`` object. diff -Nru python3-sympy-0.7.2/doc/src/tutorial/matrices.rst python3-sympy-0.7.3/doc/src/tutorial/matrices.rst --- python3-sympy-0.7.2/doc/src/tutorial/matrices.rst 1970-01-01 00:00:00.000000000 +0000 +++ python3-sympy-0.7.3/doc/src/tutorial/matrices.rst 2013-07-13 17:50:18.000000000 +0000 @@ -0,0 +1,388 @@ +========== + Matrices +========== + + >>> from sympy import * + >>> init_printing(use_unicode=True) + +To make a matrix in SymPy, use the ``Matrix`` object. A matrix is constructed +by providing a list of row vectors that make up the matrix. For example, +to construct the matrix + +.. math:: + + + \left[\begin{array}{cc}1 & -1\\3 & 4\\0 & 2\end{array}\right] + +use + + >>> Matrix([[1, -1], [3, 4], [0, 2]]) + ⎡1 -1⎤ + ⎢ ⎥ + ⎢3 4 ⎥ + ⎢ ⎥ + ⎣0 2 ⎦ + +To make it easy to make column vectors, a list of elements is considered to be +a column vector. + + >>> Matrix([1, 2, 3]) + ⎡1⎤ + ⎢ ⎥ + ⎢2⎥ + ⎢ ⎥ + ⎣3⎦ + +Matrices are manipulated just like any other object in SymPy or Python. + + >>> M = Matrix([[1, 2, 3], [3, 2, 1]]) + >>> N = Matrix([0, 1, 1]) + >>> M*N + ⎡5⎤ + ⎢ ⎥ + ⎣3⎦ + +One important thing to note about SymPy matrices is that, unlike every other +object in SymPy, they are mutable. This means that they can be modified in +place, as we will see below. The downside to this is that ``Matrix`` cannot +be used in places that require immutability, such as inside other SymPy +expressions or as keys to dictionaries. If you need an immutable version of +``Matrix``, use ``ImmutableMatrix``. + +Basic Operations +================ + +Shape +----- + +Here are some basic operations on ``Matrix``. To get the shape of a matrix +use ``shape`` + + >>> M = Matrix([[1, 2, 3], [-2, 0, 4]]) + >>> M + ⎡1 2 3⎤ + ⎢ ⎥ + ⎣-2 0 4⎦ + >>> M.shape + (2, 3) + +Accessing Rows and Columns +-------------------------- + +To get an individual row or column of a matrix, use ``row`` or ``col``. For +example, ``M.row(0)`` will get the first row. ``M.col(-1)`` will get the last +column. + + >>> M.row(0) + [1 2 3] + >>> M.col(-1) + ⎡3⎤ + ⎢ ⎥ + ⎣4⎦ + +Deleting and Inserting Rows and Columns +--------------------------------------- + +To delete a row or column, use ``row_del`` or ``col_del``. These operations +will modify the Matrix **in place**. + + >>> M.col_del(0) + >>> M + ⎡2 3⎤ + ⎢ ⎥ + ⎣0 4⎦ + >>> M.row_del(1) + >>> M + [2 3] + +.. TODO: This is a mess. See issue 3893. + +To insert rows or columns, use ``row_insert`` or ``col_insert``. These +operations **do not** operate in place. + + >>> M + [2 3] + >>> M = M.row_insert(1, Matrix([[0, 4]])) + >>> M + ⎡2 3⎤ + ⎢ ⎥ + ⎣0 4⎦ + >>> M = M.col_insert(0, Matrix([1, -2])) + >>> M + ⎡1 2 3⎤ + ⎢ ⎥ + ⎣-2 0 4⎦ + +Unless explicitly stated, the methods mentioned below do not operate in +place. In general, a method that does not operate in place will return a new +``Matrix`` and a method that does operate in place will return ``None``. + +Basic Methods +============= + +As noted above, simple operations like addition and multiplication are done +just by using ``+``, ``*``, and ``**``. To find the inverse of a matrix, just +raise it to the ``-1`` power. + + >>> M = Matrix([[1, 3], [-2, 3]]) + >>> N = Matrix([[0, 3], [0, 7]]) + >>> M + N + ⎡1 6 ⎤ + ⎢ ⎥ + ⎣-2 10⎦ + >>> M*N + ⎡0 24⎤ + ⎢ ⎥ + ⎣0 15⎦ + >>> 3*M + ⎡3 9⎤ + ⎢ ⎥ + ⎣-6 9⎦ + >>> M**2 + ⎡-5 12⎤ + ⎢ ⎥ + ⎣-8 3 ⎦ + >>> M**-1 + ⎡1/3 -1/3⎤ + ⎢ ⎥ + ⎣2/9 1/9 ⎦ + >>> N**-1 + Traceback (most recent call last): + ... + ValueError: Matrix det == 0; not invertible. + +To take the transpose of a Matrix, use ``T``. + + >>> M = Matrix([[1, 2, 3], [4, 5, 6]]) + >>> M + ⎡1 2 3⎤ + ⎢ ⎥ + ⎣4 5 6⎦ + >>> M.T + ⎡1 4⎤ + ⎢ ⎥ + ⎢2 5⎥ + ⎢ ⎥ + ⎣3 6⎦ + +Matrix Constructors +=================== + +Several constructors exist for creating common matrices. To create an +identity matrix, use ``eye``. ``eye(n)`` will create an `n\times n` identity matrix. + + >>> eye(3) + ⎡1 0 0⎤ + ⎢ ⎥ + ⎢0 1 0⎥ + ⎢ ⎥ + ⎣0 0 1⎦ + >>> eye(4) + ⎡1 0 0 0⎤ + ⎢ ⎥ + ⎢0 1 0 0⎥ + ⎢ ⎥ + ⎢0 0 1 0⎥ + ⎢ ⎥ + ⎣0 0 0 1⎦ + +To create a matrix of all zeros, use ``zeros``. ``zeros(n, m)`` creates an +`n\times m` matrix of `0`\ s. + + >>> zeros(2, 3) + ⎡0 0 0⎤ + ⎢ ⎥ + ⎣0 0 0⎦ + +Similarly, ``ones`` creates a matrix of ones. + + >>> ones(3, 2) + ⎡1 1⎤ + ⎢ ⎥ + ⎢1 1⎥ + ⎢ ⎥ + ⎣1 1⎦ + +To create diagonal matrices, use ``diag``. The arguments to ``diag`` can be +either numbers or matrices. A number is interpreted as a `1\times 1` +matrix. The matrices are stacked diagonally. The remaining elements are +filled with `0`\ s. + + >>> diag(1, 2, 3) + ⎡1 0 0⎤ + ⎢ ⎥ + ⎢0 2 0⎥ + ⎢ ⎥ + ⎣0 0 3⎦ + >>> diag(-1, ones(2, 2), Matrix([5, 7, 5])) + ⎡-1 0 0 0⎤ + ⎢ ⎥ + ⎢0 1 1 0⎥ + ⎢ ⎥ + ⎢0 1 1 0⎥ + ⎢ ⎥ + ⎢0 0 0 5⎥ + ⎢ ⎥ + ⎢0 0 0 7⎥ + ⎢ ⎥ + ⎣0 0 0 5⎦ + +Advanced Methods +================ + +Determinant +----------- + +To compute the determinant of a matrix, use ``det``. + + >>> M = Matrix([[1, 0, 1], [2, -1, 3], [4, 3, 2]]) + >>> M + ⎡1 0 1⎤ + ⎢ ⎥ + ⎢2 -1 3⎥ + ⎢ ⎥ + ⎣4 3 2⎦ + >>> M.det() + -1 + +RREF +---- + +To put a matrix into reduced row echelon form, use ``rref``. ``rref`` returns +a tuple of two elements. The first is the reduced row echelon form, and the +second is a list of indices of the pivot columns. + + >>> M = Matrix([[1, 0, 1, 3], [2, 3, 4, 7], [-1, -3, -3, -4]]) + >>> M + ⎡1 0 1 3 ⎤ + ⎢ ⎥ + ⎢2 3 4 7 ⎥ + ⎢ ⎥ + ⎣-1 -3 -3 -4⎦ + >>> M.rref() + ⎛⎡1 0 1 3 ⎤, [0, 1]⎞ + ⎜⎢ ⎥ ⎟ + ⎜⎢0 1 2/3 1/3⎥ ⎟ + ⎜⎢ ⎥ ⎟ + ⎝⎣0 0 0 0 ⎦ ⎠ + +.. Note:: The first element of the tuple returned by ``rref`` is of type + ``Matrix``. The second is of type ``list``. + +Nullspace +--------- + +To find the nullspace of a matrix, use ``nullspace``. ``nullspace`` returns a +``list`` of column vectors that span the nullspace of the matrix. + + >>> M = Matrix([[1, 2, 3, 0, 0], [4, 10, 0, 0, 1]]) + >>> M + ⎡1 2 3 0 0⎤ + ⎢ ⎥ + ⎣4 10 0 0 1⎦ + >>> M.nullspace() + ⎡⎡-15⎤, ⎡0⎤, ⎡ 1 ⎤⎤ + ⎢⎢ ⎥ ⎢ ⎥ ⎢ ⎥⎥ + ⎢⎢ 6 ⎥ ⎢0⎥ ⎢-1/2⎥⎥ + ⎢⎢ ⎥ ⎢ ⎥ ⎢ ⎥⎥ + ⎢⎢ 1 ⎥ ⎢0⎥ ⎢ 0 ⎥⎥ + ⎢⎢ ⎥ ⎢ ⎥ ⎢ ⎥⎥ + ⎢⎢ 0 ⎥ ⎢1⎥ ⎢ 0 ⎥⎥ + ⎢⎢ ⎥ ⎢ ⎥ ⎢ ⎥⎥ + ⎣⎣ 0 ⎦ ⎣0⎦ ⎣ 1 ⎦⎦ + +Eigenvalues, Eigenvectors, and Diagonalization +---------------------------------------------- + +To find the eigenvalues of a matrix, use ``eigenvals``. ``eigenvals`` +returns a dictionary of ``eigenvalue:algebraic multiplicity`` pairs (similar to the +output of :ref:`roots `). + + >>> M = Matrix([[3, -2, 4, -2], [5, 3, -3, -2], [5, -2, 2, -2], [5, -2, -3, 3]]) + >>> M + ⎡3 -2 4 -2⎤ + ⎢ ⎥ + ⎢5 3 -3 -2⎥ + ⎢ ⎥ + ⎢5 -2 2 -2⎥ + ⎢ ⎥ + ⎣5 -2 -3 3 ⎦ + >>> M.eigenvals() + {-2: 1, 3: 1, 5: 2} + +This means that ``M`` has eigenvalues -2, 3, and 5, and that the +eigenvalues -2 and 3 have algebraic multiplicity 1 and that the eigenvalue 5 +has algebraic multiplicity 2. + +To find the eigenvectors of a matrix, use ``eigenvects``. ``eigenvects`` +returns a list of tuples of the form ``(eigenvalue:algebraic multiplicity, +[eigenvectors])``. + + >>> M.eigenvects() + ⎡⎛-2, 1, ⎡⎡0⎤⎤⎞, ⎛3, 1, ⎡⎡1⎤⎤⎞, ⎛5, 2, ⎡⎡1⎤, ⎡0 ⎤⎤⎞⎤ + ⎢⎜ ⎢⎢ ⎥⎥⎟ ⎜ ⎢⎢ ⎥⎥⎟ ⎜ ⎢⎢ ⎥ ⎢ ⎥⎥⎟⎥ + ⎢⎜ ⎢⎢1⎥⎥⎟ ⎜ ⎢⎢1⎥⎥⎟ ⎜ ⎢⎢1⎥ ⎢-1⎥⎥⎟⎥ + ⎢⎜ ⎢⎢ ⎥⎥⎟ ⎜ ⎢⎢ ⎥⎥⎟ ⎜ ⎢⎢ ⎥ ⎢ ⎥⎥⎟⎥ + ⎢⎜ ⎢⎢1⎥⎥⎟ ⎜ ⎢⎢1⎥⎥⎟ ⎜ ⎢⎢1⎥ ⎢0 ⎥⎥⎟⎥ + ⎢⎜ ⎢⎢ ⎥⎥⎟ ⎜ ⎢⎢ ⎥⎥⎟ ⎜ ⎢⎢ ⎥ ⎢ ⎥⎥⎟⎥ + ⎣⎝ ⎣⎣1⎦⎦⎠ ⎝ ⎣⎣1⎦⎦⎠ ⎝ ⎣⎣0⎦ ⎣1 ⎦⎦⎠⎦ + +This shows us that, for example, the eigenvalue 5 also has geometric +multiplicity 2, because it has two eigenvectors. Because the algebraic and +geometric multiplicities are the same for all the eigenvalues, ``M`` is +diagonalizable. + +To diagonalize a matrix, use ``diagonalize``. ``diagonalize`` returns a tuple +`(P, D)`, where `D` is diagonal and `M = PDP^{-1}`. + + >>> P, D = M.diagonalize() + >>> P + ⎡0 1 1 0 ⎤ + ⎢ ⎥ + ⎢1 1 1 -1⎥ + ⎢ ⎥ + ⎢1 1 1 0 ⎥ + ⎢ ⎥ + ⎣1 1 0 1 ⎦ + >>> D + ⎡-2 0 0 0⎤ + ⎢ ⎥ + ⎢0 3 0 0⎥ + ⎢ ⎥ + ⎢0 0 5 0⎥ + ⎢ ⎥ + ⎣0 0 0 5⎦ + >>> P*D*P**-1 + ⎡3 -2 4 -2⎤ + ⎢ ⎥ + ⎢5 3 -3 -2⎥ + ⎢ ⎥ + ⎢5 -2 2 -2⎥ + ⎢ ⎥ + ⎣5 -2 -3 3 ⎦ + >>> P*D*P**-1 == M + True + +.. sidebar:: Quick Tip + + ``lambda`` is a reserved keyword in Python, so to create a Symbol called + `\lambda`, while using the same names for SymPy Symbols and Python + variables, use ``lamda`` (without the ``b``). It will still pretty print + as `\lambda`. + +Note that since ``eigenvects`` also includes the eigenvalues, you should use +it instead of ``eigenvals`` if you also want the eigenvectors. However, as +computing the eigenvectors may often be costly, ``eigenvals`` should be +preferred if you only wish to find the eigenvalues. + +If all you want is the characteristic polynomial, use ``charpoly``. This is +more efficient than ``eigenvals``, because sometimes symbolic roots can be +expensive to calculate. + + >>> lamda = symbols('lamda') + >>> p = M.charpoly(lamda) + >>> factor(p) + 2 + (λ - 5) ⋅(λ - 3)⋅(λ + 2) + +.. TODO: Add an example for ``jordan_form``, once it is fully implemented. diff -Nru python3-sympy-0.7.2/doc/src/tutorial/preliminaries.rst python3-sympy-0.7.3/doc/src/tutorial/preliminaries.rst --- python3-sympy-0.7.2/doc/src/tutorial/preliminaries.rst 1970-01-01 00:00:00.000000000 +0000 +++ python3-sympy-0.7.3/doc/src/tutorial/preliminaries.rst 2013-07-13 17:50:18.000000000 +0000 @@ -0,0 +1,118 @@ +=============== + Preliminaries +=============== + +This tutorial assumes that the reader already knows the basics of the Python programming +language. If you do not, the `official Python +tutorial `_ is excellent. + +This tutorial assumes a decent mathematical background. Most examples require +knowledge up to calculus level, and some require knowledge at a calculus +level. Some of the advanced features require more than this. If you come +across a section that uses some mathematical function you are not familiar +with, you can probably skip over it, or replace it with a similar one that you +are more familiar with. Or look up the function on Wikipedia and learn +something new. Some important mathematical concepts that are not common +knowledge will be introduced as necessary. + +Installation +============ + +.. sidebar:: Quick Tip + + You do not need to install SymPy to try it. You can use the online shell + at http://live.sympy.org, or the shell at the bottom right of this + documentation page. + +You will need to install SymPy first. See the :ref:`installation guide +`. + +Alternately, you can just use the SymPy Live Sphinx extension to run the code +blocks in the browser. For example, click on the green "Run code block in +SymPy Live" button below + + >>> from sympy import * + >>> x = symbols('x') + >>> a = Integral(cos(x)*exp(x), x) + >>> Eq(a, a.doit()) + Integral(exp(x)*cos(x), x) == exp(x)*sin(x)/2 + exp(x)*cos(x)/2 + +The SymPy Live shell in the bottom corner will pop up and evaluate the code +block. You can also click any individual line to evaluate it one at a time. + +The SymPy Live shell is a fully interactive Python shell. You can type any +expression in the input box to evaluate it. Feel free to use it throughout +the tutorial to experiment. + +To show or hide the SymPy Live shell at any time, just click the green button +on the bottom right of the screen. + +By default, the SymPy Live shell uses `\LaTeX` for output. If you want the +output to look more like the output in the documentation, change the +output format to ``Str`` or ``Unicode``. + +If you wish to modify an example before evaluating it, change the evaluation +mode to "copy" in the SymPy Live settings. This will cause clicking on an +example to copy the example to the SymPy Live shell, but not evaluate it, +allowing you to change it before execution. You can also use the up/down +arrow keys on your keyboard in the input box to move through the shell +history. + +The SymPy Live shell is also available at http://live.sympy.org, with extra +features, like a mobile phone enhanced version and saved history. + +Exercises +========= + +This tutorial was the basis for a tutorial given at the 2013 SciPy conference +in Austin, TX. The website for that tutorial is `here +`_. It has links +to videos, materials, and IPython notebook exercises. The IPython notebook +exercises in particular are recommended to anyone going through this tutorial. + +About This Tutorial +=================== + +This tutorial aims to give an introduction to SymPy for someone who has not +used the library before. Many features of SymPy will be introduced in this +tutorial, but they will not be exhaustive. In fact, virtually every +functionality shown in this tutorial will have more options or capabilities +than what will be shown. The rest of the SymPy documentation serves as API +documentation, which extensively lists every feature and option of each +function. + +These are the goals of this tutorial: + +.. NB: This is mainly here for you, the person who is editing and adding to + this tutorial. Try to keep these principles in mind. + +- To give a guide, suitable for someone who has never used SymPy (but who has + used Python and knows the necessary mathematics). + +- To be written in a narrative format, which is both easy and fun to follow. + It should read like a book. + +- To give insightful examples and exercises, to help the reader learn and to + make it entertaining to work through. + +- To introduce concepts in a logical order. + +.. In other words, don't try to get ahead of yourself. + +- To use good practices and idioms, and avoid antipatterns. Functions or + methodologies that tend to lead to antipatterns are avoided. Features that + are only useful to advanced users are not shown. + +- To be consistent. If there are multiple ways to do it, only the best way is + shown. + +.. For example, there are at least five different ways to create Symbols. + ``symbols`` is the only one that is general and doesn't lead to + antipatterns, so it is the only one used. + +- To avoid unnecessary duplication, it is assumed that previous sections of + the tutorial have already been read. + +Feedback on this tutorial, or on SymPy in general is always welcome. Just +write to our `mailing list +`_. diff -Nru python3-sympy-0.7.2/doc/src/tutorial/printing.rst python3-sympy-0.7.3/doc/src/tutorial/printing.rst --- python3-sympy-0.7.2/doc/src/tutorial/printing.rst 1970-01-01 00:00:00.000000000 +0000 +++ python3-sympy-0.7.3/doc/src/tutorial/printing.rst 2013-07-13 17:53:31.000000000 +0000 @@ -0,0 +1,236 @@ +.. _tutorial-printing: + +========== + Printing +========== + +As we have already seen, SymPy can pretty print its output using Unicode +characters. This is a short introduction to the most common printing options +available in SymPy. + +Printers +======== + +There are several printers available in SymPy. The most common ones are + +- str +- repr +- ASCII pretty printer +- Unicode pretty printer +- LaTeX +- MathML +- Dot + +In addition to these, there are also "printers" that can output SymPy objects +to code, such as C, Fortran, Javascript, Theano, and Python. These are not +discussed in this tutorial. + +Setting up Pretty Printing +========================== + +If all you want is the best pretty printing, use the ``init_printing`` +function. This will automatically enable the best printer available in your +environment. + + >>> from sympy import init_printing + >>> init_printing() # doctest: +SKIP + +.. sidebar:: Quick Tip + + You an also change the printer used in SymPy Live. Just change the "Output + Format" in the settings. + +If you plan to work in an interactive calculator-type session, the +``init_session`` function will automatically import everything in SymPy, +create some common Symbols, setup plotting, and run ``init_printing``. + + >>> from sympy import init_session + >>> init_session() # doctest: +SKIP + + :: + + Python console for SymPy 0.7.3 (Python 2.7.5-64-bit) (ground types: gmpy) + + These commands were executed: + >>> + >>> from sympy import * + >>> x, y, z, t = symbols('x y z t') + >>> k, m, n = symbols('k m n', integer=True) + >>> f, g, h = symbols('f g h', cls=Function) + + Documentation can be found at http://www.sympy.org + + >>> + +In any case, this is what will happen: + +- In the IPython QTConsole, if `\LaTeX` is installed, it will enable a printer + that uses `\LaTeX`. + + .. image:: ../pics/ipythonqtconsole.png + :height: 500 + + If `\LaTeX` is not installed, but Matplotlib is installed, it will use the + Matplotlib rendering engine. If Matplotlib is not installed, it uses the + Unicode pretty printer. + +- In the IPython notebook, it will use MathJax to render `\LaTeX`. + + .. image:: ../pics/ipythonnotebook.png + :height: 250 + +- In an IPython console session, or a regular Python session, it will use the + Unicode pretty printer if the terminal supports Unicode. + + .. image:: ../pics/consoleunicode.png + :width: 700 + +- In a terminal that does not support Unicode, the ASCII pretty printer is + used. + + .. image:: ../pics/consoleascii.png + :width: 700 + +To explicitly not use `\LaTeX`, pass ``use_latex=False`` to ``init_printing`` +or ``init_session``. To explicitly not use Unicode, pass +``use_unicode=False``. + + +Printing Functions +================== + +In addition to automatic printing, you can explicitly use any one of the +printers by calling the appropriate function. + +str +--- + +To get a string form of an expression, use ``str(expr)``. This is also the +form that is produced by ``print expr``. String forms are designed to be easy +to read, but in a form that is correct Python syntax so that it can be copied +and pasted. The ``str`` form of an expression will usually look exactly the +same as the expression as you would enter it. + + >>> from sympy import * + >>> x, y, z = symbols('x y z') + >>> str(Integral(sqrt(1/x), x)) + 'Integral(sqrt(1/x), x)' + >>> print(Integral(sqrt(1/x), x)) + Integral(sqrt(1/x), x) + +repr +---- + +The repr form of an expression is designed to show the exact form of an +expression. It will be discussed more in the :ref:`tutorial-manipulation` +section. To get it, use ``srepr`` [#srepr-fn]_. + + >>> srepr(Integral(sqrt(1/x), x)) + "Integral(Pow(Pow(Symbol('x'), Integer(-1)), Rational(1, 2)), Tuple(Symbol('x')))" + +The repr form is mostly useful for understanding how an expression is built +internally. + + +ASCII Pretty Printer +-------------------- + +The ASCII pretty printer is accessed from ``pprint``. If the terminal does +not support Unicode, the ASCII printer is used by default. Otherwise, you +must pass ``use_unicode=False``. + + >>> pprint(Integral(sqrt(1/x), x), use_unicode=False) + / + | + | ___ + | / 1 + | / - dx + | \/ x + | + / + +``pprint`` prints the output to the screen. If you want the string form, use +``pretty``. + + >>> pretty(Integral(sqrt(1/x), x), use_unicode=False) + ' / \n | \n | ___ \n | / 1 \n | / - dx\n | \\/ x \n | \n/ ' + >>> print(pretty(Integral(sqrt(1/x), x), use_unicode=False)) + / + | + | ___ + | / 1 + | / - dx + | \/ x + | + / + +Unicode Pretty Printer +---------------------- + +The Unicode pretty printer is also accessed from ``print``. It the terminal +supports Unicode, it is used automatically. It ``pprint`` is not able to +detect that the terminal supports unicode, you can pass ``use_unicode=True``. + + >>> pprint(Integral(sqrt(1/x), x), use_unicode=True) + ⌠ + ⎮ ___ + ⎮ ╱ 1 + ⎮ ╱ ─ dx + ⎮ ╲╱ x + ⌡ + +.. _LaTeX: + +`\LaTeX` +-------- + +To get the `\LaTeX` form of an expression, use ``latex``. + + >>> print(latex(Integral(sqrt(1/x), x))) + \int \sqrt{\frac{1}{x}}\, dx + +The ``latex`` function has many options to change the formatting of different +things. See :py:meth:`its documentation ` for +more details. + +MathML +------ + +There is also a printer to MathML, called ``print_mathml``. It must be imported +from ``sympy.printing.mathml``. + + >>> from sympy.printing.mathml import print_mathml + >>> print_mathml(Integral(sqrt(1/x), x)) + + + + x + + + + + + x + -1 + + + + +``print_mathml`` prints the output. If you want the string, use the function +``mathml``. + +Dot +--- + +The ``dotprint`` function in ``sympy.printing.dot`` prints output to dot +format, which can be rendered with Graphviz. See the +:ref:`tutorial-manipulation` section for some examples of the output of this +printer. + +.. rubric:: Footnotes + +.. [#srepr-fn] SymPy does not use the Python builtin ``repr`` function for + repr printing, because in Python ``str(list)`` calls ``repr`` on the + elements of the list, and some SymPy functions return lists (such as + ``solve``). Since ``srepr`` is so verbose, it is unlikely that anyone + would want it called by default on the output of ``solve``. diff -Nru python3-sympy-0.7.2/doc/src/tutorial/simplification.rst python3-sympy-0.7.3/doc/src/tutorial/simplification.rst --- python3-sympy-0.7.2/doc/src/tutorial/simplification.rst 1970-01-01 00:00:00.000000000 +0000 +++ python3-sympy-0.7.3/doc/src/tutorial/simplification.rst 2013-07-13 17:50:18.000000000 +0000 @@ -0,0 +1,863 @@ +.. _tutorial-simplify: + +================ + Simplification +================ + +To make this document easier to read, we are going to enable pretty printing. + + >>> from sympy import * + >>> x, y, z = symbols('x y z') + >>> init_printing(use_unicode=True) + +``simplify`` +============ + +Now let's jump in and do some interesting mathematics. One of the most useful +features of a symbolic manipulation system is the ability to simplify +mathematical expressions. SymPy has dozens of functions to perform various +kinds of simplification. There is also one general function called +``simplify`` that attempts to apply all of these functions in an intelligent +way to arrive at the simplest form of an expression. Here are some examples + + >>> simplify(sin(x)**2 + cos(x)**2) + 1 + >>> simplify((x**3 + x**2 - x - 1)/(x**2 + 2*x + 1)) + x - 1 + >>> simplify(gamma(x)/gamma(x - 2)) + (x - 2)⋅(x - 1) + +Here, ``gamma(x)`` is `\Gamma(x)`, the `gamma function +`_. We see that ``simplify`` is +capable of handling a large class of expressions. + +But ``simplify`` has a pitfall. It just applies all the major simplification +operations in SymPy, and uses heuristics to determine the simplest result. But +"simplest" is not a well-defined term. For example, say we wanted to +"simplify" `x^2 + 2x + 1` into `(x + 1)^2`: + + >>> simplify(x**2 + 2*x + 1) + 2 + x + 2⋅x + 1 + +We did not get what we want. There is a function to perform this +simplification, called ``factor``, which will be discussed below. + +Another pitfall to ``simplify``, which is that it can be unnecessarily slow, +since it tries many kinds of simplifications before picking the best one. If +you already know exactly what kind of simplification you are after, it is +better to apply the specific simplification function(s) that apply those +simplifications. + +Applying specific simplification functions instead of ``simplify`` also has +the advantage that specific functions have certain guarantees about the form +of their output. These will be discussed with each function below. For +example, ``factor``, when called on a polynomial with rational coefficients, +is guaranteed to factor the polynomial into irreducible factors. ``simplify`` +has no guarantees. It is entirely heuristical, and, as we saw above, it may +even miss a possible type of simplification that SymPy is capable of doing. + +``simplify`` is best when used interactively, when you just want to whittle +down an expression to a simpler form. You may then choose to apply specific +functions once you see what ``simplify`` returns, to get a more precise +result. It is also useful when you have no idea what form an expression will +take, and you need a catchall function to simplify it. + +Polynomial/Rational Function Simplification +=========================================== + +``expand`` +---------- + +``expand`` is one of the most common simplification functions in SymPy. +Although it has a lot of scopes, for now, we will consider its function in +expanding polynomial expressions. For example: + + >>> expand((x + 1)**2) + 2 + x + 2⋅x + 1 + >>> expand((x + 2)*(x - 3)) + 2 + x - x - 6 + +Given a polynomial, ``expand`` will put it into a canonical form of a sum of +monomials. + +``expand`` may not sound like a simplification function. After all, by its +very name, it makes expressions bigger, not smaller. Usually this is the +case, but often an expression will become smaller upon calling ``expand`` on +it due to cancellation + + >>> expand((x + 1)*(x - 2) - (x - 1)*x) + -2 + +``factor`` +---------- + +``factor`` takes a polynomial and factors it into irreducible factors over the +rational numbers. For example: + + >>> factor(x**3 - x**2 + x - 1) + ⎛ 2 ⎞ + (x - 1)⋅⎝x + 1⎠ + >>> factor(x**2*z + 4*x*y*z + 4*y**2*z) + 2 + z⋅(x + 2⋅y) + +For polynomials, ``factor`` is the opposite of ``expand``. ``factor`` uses a +complete multivariate factorization algorithm over the rational numbers, which +means that each of the factors returned by ``factor`` is guaranteed to be +irreducible. + +If you are interested in the factors themselves, ``factor_list`` returns a +more structured output. + + >>> factor_list(x**2*z + 4*x*y*z + 4*y**2*z) + (1, [(z, 1), (x + 2⋅y, 2)]) + +Note that the input to ``factor`` and ``expand`` need not be polynomials in +the strict sense. They will intelligently factor or expand any kind of +expression (though note that the factors may not be irreducible if the input +is no longer a polynomial over the rationals). + + >>> expand((cos(x) + sin(x))**2) + 2 2 + sin (x) + 2⋅sin(x)⋅cos(x) + cos (x) + >>> factor(cos(x)**2 + 2*cos(x)*sin(x) + sin(x)**2) + 2 + (sin(x) + cos(x)) + +``collect`` +----------- + +``collect`` collects common powers of a term in an expression. For example + + >>> expr = x*y + x - 3 + 2*x**2 - z*x**2 + x**3 + >>> expr + 3 2 2 + x - x ⋅z + 2⋅x + x⋅y + x - 3 + >>> collected_expr = collect(expr, x) + >>> collected_expr + 3 2 + x + x ⋅(-z + 2) + x⋅(y + 1) - 3 + +``collect`` is particularly useful in conjunction with the ``.coeff`` method. +``expr.coeff(x, n)`` gives the coefficient of ``x**n`` in ``expr``: + + >>> collected_expr.coeff(x, 2) + -z + 2 + +.. TODO: Discuss coeff method in more detail in some other section (maybe + basic expression manipulation tools) + +``cancel`` +---------- + +``cancel`` will take any rational function and put it into the standard +canonical form, `\frac{p}{q}`, where `p` and `q` are expanded polynomials with +no common factors, and the leading coefficients of `p` and `q` do not have +denominators (i.e., are integers). + + >>> cancel((x**2 + 2*x + 1)/(x**2 + x)) + x + 1 + ───── + x + + >>> expr = 1/x + (3*x/2 - 2)/(x - 4) + >>> expr + 3⋅x + ─── - 2 + 2 1 + ─────── + ─ + x - 4 x + >>> cancel(expr) + 2 + 3⋅x - 2⋅x - 8 + ────────────── + 2 + 2⋅x - 8⋅x + + >>> expr = (x*y**2 - 2*x*y*z + x*z**2 + y**2 - 2*y*z + z**2)/(x**2 - 1) + >>> expr + 2 2 2 2 + x⋅y - 2⋅x⋅y⋅z + x⋅z + y - 2⋅y⋅z + z + ─────────────────────────────────────── + 2 + x - 1 + >>> cancel(expr) + 2 2 + y - 2⋅y⋅z + z + ─────────────── + x - 1 + +Note that since ``factor`` will completely factorize both the numerator and +the denominator of an expression, it can also be used to do the same thing: + + >>> factor(expr) + 2 + (y - z) + ──────── + x - 1 + +However, if you are only interested in making sure that the expression is in +canceled form, ``cancel`` is more efficient than ``factor``. + +``apart`` +--------- + +``apart`` performs a `partial fraction decomposition +`_ on a rational +function. + + >>> expr = (4*x**3 + 21*x**2 + 10*x + 12)/(x**4 + 5*x**3 + 5*x**2 + 4*x) + >>> expr + 3 2 + 4⋅x + 21⋅x + 10⋅x + 12 + ──────────────────────── + 4 3 2 + x + 5⋅x + 5⋅x + 4⋅x + >>> apart(expr) + 2⋅x - 1 1 3 + ────────── - ───── + ─ + 2 x + 4 x + x + x + 1 + +Trigonometric Simplification +============================ + +.. note:: + + SymPy follows Python's naming conventions for inverse trigonometric + functions, which is to append an ``a`` to the front of the function's + name. For example, the inverse cosine, or arc cosine, is called ``acos``. + + >>> acos(x) + acos(x) + >>> cos(acos(x)) + x + >>> asin(1) + π + ─ + 2 + +.. TODO: Can we actually do anything with inverse trig functions, + simplification wise? + +``trigsimp`` +------------ + +To simplify expressions using trigonometric identities, use ``trigsimp``. + + >>> trigsimp(sin(x)**2 + cos(x)**2) + 1 + >>> trigsimp(sin(x)**4 - 2*cos(x)**2*sin(x)**2 + cos(x)**4) + cos(4⋅x) 1 + ──────── + ─ + 2 2 + >>> trigsimp(sin(x)*tan(x)/sec(x)) + 2 + sin (x) + +``trigsimp`` also works with hyperbolic trig functions. + + >>> trigsimp(cosh(x)**2 + sinh(x)**2) + cosh(2⋅x) + >>> trigsimp(sinh(x)/tanh(x)) + cosh(x) + +Much like ``simplify``, ``trigsimp`` applies various trigonometric identities to +the input expression, and then uses a heuristic to return the "best" one. + +``expand_trig`` +--------------- + +To expand trigonometric functions, that is, apply the sum or double angle +identities, use ``expand_trig``. + + >>> expand_trig(sin(x + y)) + sin(x)⋅cos(y) + sin(y)⋅cos(x) + >>> expand_trig(tan(2*x)) + 2⋅tan(x) + ───────────── + 2 + - tan (x) + 1 + +Because ``expand_trig`` tends to make trigonometric expressions larger, and +``trigsimp`` tends to make them smaller, these identities can be applied in +reverse using ``trigsimp`` + + >>> trigsimp(sin(x)*cos(y) + sin(y)*cos(x)) + sin(x + y) + +.. TODO: It would be much better to teach individual trig rewriting functions + here, but they don't exist yet. See + https://code.google.com/p/sympy/issues/detail?id=357. + +Powers +====== + +Before we introduce the power simplification functions, a mathematical +discussion on the identities held by powers is in order. There are three +kinds of identities satisfied by exponents + +1. `x^ax^b = x^{a + b}` +2. `x^ay^a = (xy)^a` +3. `(x^a)^b = x^{ab}` + +Identity 1 is always true. + +Identity 2 is not always true. For example, if `x = y = -1` and `a = +\frac{1}{2}`, then `x^ay^a = \sqrt{-1}\sqrt{-1} = i\cdot i = -1`, whereas +`(xy)^a = \sqrt{-1\cdot-1} = \sqrt{1} = 1`. However, identity 2 is true at +least if `x` and `y` are nonnegative and `a` is real (it may also be true +under other conditions as well). A common consequence of the failure of +identity 2 is that `\sqrt{x}\sqrt{y} \neq \sqrt{xy}`. + +Identity 3 is not always true. For example, if `x = -1`, `a = 2`, and `b = +\frac{1}{2}`, then `(x^a)^b = {\left ((-1)^2\right )}^{1/2} = \sqrt{1} = 1` +and `x^{ab} = (-1)^{2\cdot1/2} = (-1)^1 = -1`. However, identity 3 is true at +least if `x` is nonnegative or `b` is an integer (again, it may also hold in +other cases as well). Two common consequences of the failure of identity 3 +are that `\sqrt{x^2}\neq x` and that `\sqrt{\frac{1}{x}} \neq +\frac{1}{\sqrt{x}}`. + +To summarize + ++-----------------------+------------------------------------+----------------------------------------------------+-----------------------------------------------------------------------------+ +|Identity |Sufficient conditions to hold |Counterexample when conditions are not met |Important consequences | ++=======================+====================================+====================================================+=============================================================================+ +|1. `x^ax^b = x^{a + b}`|Always true |None |None | ++-----------------------+------------------------------------+----------------------------------------------------+-----------------------------------------------------------------------------+ +|2. `x^ay^a = (xy)^a` |`x, y \geq 0` and `a \in \mathbb{R}`|`(-1)^{1/2}(-1)^{1/2} \neq (-1\cdot-1)^{1/2}` |`\sqrt{x}\sqrt{y} \neq \sqrt{xy}` in general | ++-----------------------+------------------------------------+----------------------------------------------------+-----------------------------------------------------------------------------+ +|3. `(x^a)^b = x^{ab}` |`x \geq 0` or `b \in \mathbb{Z}` |`{\left((-1)^2\right )}^{1/2} \neq (-1)^{2\cdot1/2}`|`\sqrt{x^2}\neq x` and `\sqrt{\frac{1}{x}}\neq\frac{1}{\sqrt{x}}` in general | ++-----------------------+------------------------------------+----------------------------------------------------+-----------------------------------------------------------------------------+ + +This is important to remember, because by default, SymPy will not perform +simplifications if they are not true in general. + +In order to make SymPy perform simplifications involving identities that are +only true under certain assumptions, we need to put assumptions on our +Symbols. We will undertake a full discussion of the assumptions system later, +but for now, all we need to know are the following. + +- By default, SymPy Symbols are assumed to be complex (elements of + `\mathbb{C}`). That is, a simplification will not be applied to an + expression with a given Symbol unless it holds for all complex numbers. + +- Symbols can be given different assumptions by passing the assumption to + ``symbols``. For the rest of this section, we will be assuming that ``x`` + and ``y`` are positive, and that ``a`` and ``b`` are real. We will leave + ``z``, ``t``, and ``c`` as arbitrary complex Symbols to demonstrate what + happens in that case. + + >>> x, y = symbols('x y', positive=True) + >>> a, b = symbols('a b', real=True) + >>> z, t, c = symbols('z t c') + + .. TODO: Rewrite this using the new assumptions + +.. note:: + + In SymPy, ``sqrt(x)`` is just a shortcut to ``x**Rational(1, 2)``. They + are exactly the same object. + + >>> sqrt(x) == x**Rational(1, 2) + True + +``powsimp`` +----------- + +``powsimp`` applies identities 1 and 2 from above, from left to right. + + + >>> powsimp(x**a*x**b) + a + b + x + >>> powsimp(x**a*y**a) + a + (x⋅y) + +Notice that ``powsimp`` refuses to do the simplification if it is not valid. + + >>> powsimp(t**c*z**c) + c c + t ⋅z + +If you know that you want to apply this simplification, but you don't want to +mess with assumptions, you can pass the ``force=True`` flag. This will force +the simplification to take place, regardless of assumptions. + + >>> powsimp(t**c*z**c, force=True) + c + (t⋅z) + +Note that in some instances, in particular, when the exponents are integers or +rational numbers, and identity 2 holds, it will be applied automatically + + >>> (z*t)**2 + 2 2 + t ⋅z + >>> sqrt(x*y) + ___ ___ + ╲╱ x ⋅╲╱ y + +This means that it will be impossible to undo this identity with ``powsimp``, +because even if ``powsimp`` were to put the bases together, they would be +automatically split apart again. + + >>> powsimp(z**2*t**2) + 2 2 + t ⋅z + >>> powsimp(sqrt(x)*sqrt(y)) + ___ ___ + ╲╱ x ⋅╲╱ y + +``expand_power_exp`` / ``expand_power_base`` +-------------------------------------------- + +``expand_power_exp`` and ``expand_power_base`` apply identities 1 and 2 from +right to left, respectively. + + >>> expand_power_exp(x**(a + b)) + a b + x ⋅x + + >>> expand_power_base((x*y)**a) + a a + x ⋅y + +As with ``powsimp``, identity 2 is not applied if it is not valid. + + >>> expand_power_base((z*t)**c) + c + (t⋅z) + +And as with ``powsimp``, you can force the expansion to happen without +fiddling with assumptions by using ``force=True``. + + >>> expand_power_base((z*t)**c, force=True) + c c + t ⋅z + +As with identity 2, identity 1 is applied automatically if the power is a +number, and hence cannot be undone with ``expand_power_exp``. + + >>> x**2*x**3 + 5 + x + >>> expand_power_exp(x**5) + 5 + x + +``powdenest`` +------------- + +``powdenest`` applies identity 3, from left to right. + + >>> powdenest((x**a)**b) + a⋅b + x + +As before, the identity is not applied if it is not true under the given +assumptions. + + >>> powdenest((z**a)**b) + b + ⎛ a⎞ + ⎝z ⎠ + +And as before, this can be manually overridden with ``force=True``. + + >>> powdenest((z**a)**b, force=True) + a⋅b + z + +Exponentials and logarithms +=========================== + +.. note:: + + In SymPy, as in Python and most programming languages, ``log`` is the + natural logarithm, also known as ``ln``. SymPy automatically provides an + alias ``ln = log`` in case you forget this. + + >>> ln(x) + log(x) + +Logarithms have similar issues as powers. There are two main identities + +1. `\log{(xy)} = \log{(x)} + \log{(y)}` +2. `\log{(x^n)} = n\log{(x)}` + +Neither identity is true for arbitrary complex `x` and `y`, due to the branch +cut in the complex plane for the complex logarithm. However, sufficient +conditions for the identities to hold are if `x` and `y` are positive and `n` +is real. + + >>> x, y = symbols('x y', positive=True) + >>> n = symbols('n', real=True) + +As before, ``z`` and ``t`` will be Symbols with no additional assumptions. + +Note that the identity `\log{\left (\frac{x}{y}\right )} = \log(x) - \log(y)` +is a special case of identities 1 and 2 by `\log{\left (\frac{x}{y}\right )} +=` `\log{\left (x\cdot\frac{1}{y}\right )} =` `\log(x) + \log{\left( +y^{-1}\right )} =` `\log(x) - \log(y)`, and thus it also holds if `x` and `y` +are positive, but may not hold in general. + +We also see that `\log{\left( e^x \right)} = x` comes from `\log{\left ( e^x +\right)} = x\log(e) = x`, and thus holds when `x` is real (and it can be +verified that it does not hold in general for arbitrary complex `x`, for +example, `\log{\left (e^{x + 2\pi i}\right)} = \log{\left (e^x\right )} = x +\neq x + 2\pi i`). + +``expand_log`` +-------------- + +To apply identities 1 and 2 from left to right, use ``expand_log``. As +always, the identities will not be applied unless they are valid. + + >>> expand_log(log(x*y)) + log(x) + log(y) + >>> expand_log(log(x/y)) + log(x) - log(y) + >>> expand_log(log(x**2)) + 2⋅log(x) + >>> expand_log(log(x**n)) + n⋅log(x) + >>> expand_log(log(z*t)) + log(t⋅z) + +As with ``powsimp`` and ``powdenest``, ``expand_log`` has a ``force`` option +that can be used to ignore assumptions. + + >>> expand_log(log(z**2)) + ⎛ 2⎞ + log⎝z ⎠ + >>> expand_log(log(z**2), force=True) + 2⋅log(z) + +``logcombine`` +-------------- + +To apply identities 1 and 2 from right to left, use ``logcombine``. + + >>> logcombine(log(x) + log(y)) + log(x⋅y) + >>> logcombine(n*log(x)) + ⎛ n⎞ + log⎝x ⎠ + >>> logcombine(n*log(z)) + n⋅log(z) + +``logcombine`` also has a ``force`` option that can be used to ignore +assumptions. + + >>> logcombine(n*log(z), force=True) + ⎛ n⎞ + log⎝z ⎠ + +Special Functions +================= + +SymPy implements dozens of special functions, ranging from functions in +combinatorics to mathematical physics. + +An extensive list of the special functions included with SymPy and their +documentation is at the :ref:`Functions Module ` page. + +For the purposes of this tutorial, let's introduce a few special functions in +SymPy. + +Let's define ``x``, ``y``, and ``z`` as regular, complex Symbols, removing any +assumptions we put on them in the previous section. We will also define ``k``, +``m``, and ``n``. + + >>> x, y, z = symbols('x y z') + >>> k, m, n = symbols('k m n') + +The `factorial `_ function is +``factorial``. ``factorial(n)`` represents `n!= 1\cdot2\cdots(n - 1)\cdot +n`. `n!` represents the number of permutations of `n` distinct items. + + >>> factorial(n) + n! + +The `binomial coefficient +`_ function is +``binomial``. ``binomial(n, k)`` represents `\binom{n}{k}`, the number of +ways to choose `k` items from a set of `n` distinct items. It is also often +written as `nCk`, and is pronounced "`n` choose `k`". + + >>> binomial(n, k) + ⎛n⎞ + ⎜ ⎟ + ⎝k⎠ + +The factorial function is closely related to the `gamma function +`_, ``gamma``. ``gamma(z)`` +represents `\Gamma(z) = \int_0^\infty t^{z - 1}e^{-t}\,dt`, which for positive integer +`z` is the same as `(z - 1)!`. + + >>> gamma(z) + Γ(z) + +The `generalized hypergeometric function +`_ is +``hyper``. ``hyper([a_1, ..., a_p], [b_1, ..., b_q], z)`` represents +`{}_pF_q\left(\begin{matrix} a_1, \dots, a_p \\ b_1, \dots, b_q \end{matrix} +\middle| z \right)`. The most common case is `{}_2F_1`, which is often +referred to as the `ordinary hypergeometric function +`_. + + >>> hyper([1, 2], [3], z) + ┌─ ⎛1, 2 │ ⎞ + ├─ ⎜ │ z⎟ + 2╵ 1 ⎝ 3 │ ⎠ + +``rewrite`` +----------- + +A common way to deal with special functions is to rewrite them in terms of one +another. This works for any function in SymPy, not just special functions. +To rewrite an expression in terms of a function, use +``expr.rewrite(function)``. For example, + + >>> tan(x).rewrite(sin) + 2 + 2⋅sin (x) + ───────── + sin(2⋅x) + >>> factorial(x).rewrite(gamma) + Γ(x + 1) + +For some tips on applying more targeted rewriting, see the +:ref:`tutorial-manipulation` section. + +``expand_func`` +--------------- + +To expand special functions in terms of some identities, use ``expand_func``. +For example + + >>> expand_func(gamma(x + 3)) + x⋅(x + 1)⋅(x + 2)⋅Γ(x) + +``hyperexpand`` +--------------- + +To rewrite ``hyper`` in terms of more standard functions, use +``hyperexpand``. + + >>> hyperexpand(hyper([1, 1], [2], z)) + -log(-z + 1) + ───────────── + z + +``hyperexpand`` also works on the more general Meijer G-function (see +:py:meth:`its documentation ` for more information). + + >>> expr = meijerg([[1],[1]], [[1],[]], -z) + >>> expr + ╭─╮1, 1 ⎛1 1 │ ⎞ + │╶┐ ⎜ │ -z⎟ + ╰─╯2, 1 ⎝1 │ ⎠ + >>> hyperexpand(expr) + 1 + ─ + z + ℯ + +``combsimp`` +------------ + +To simplify combinatorial expressions, use ``combsimp``. + + >>> combsimp(factorial(n)/factorial(n - 3)) + n⋅(n - 2)⋅(n - 1) + >>> combsimp(binomial(n+1, k+1)/binomial(n, k)) + n + 1 + ───── + k + 1 + +``combsimp`` also simplifies expressions with ``gamma``. + + >>> combsimp(gamma(x)*gamma(1 - x)) + π + ──────── + sin(π⋅x) + +Example: Continued Fractions +============================ + +Let's use SymPy to explore continued fractions. A `continued fraction +`_ is an expression of the +form + +.. math:: + + a_0 + \cfrac{1}{a_1 + \cfrac{1}{a_2 + \cfrac{1}{ \ddots + \cfrac{1}{a_n} + }}} + +where `a_0, \ldots, a_n` are integers, and `a_1, \ldots, a_n` are positive. A +continued fraction can also be infinite, but infinite objects are more +difficult to represent in computers, so we will only examine the finite case +here. + +A continued fraction of the above form is often represented as a list `[a_0; +a_1, \ldots, a_n]`. Let's write a simple function that converts such a list +to its continued fraction form. The easiest way to construct a continued +fraction from a list is to work backwards. Note that despite the apparent +symmetry of the definition, the first element, `a_0`, must usually be handled +differently from the rest. + + >>> def list_to_frac(l): + ... expr = Integer(0) + ... for i in reversed(l[1:]): + ... expr += i + ... expr = 1/expr + ... return l[0] + expr + >>> list_to_frac([x, y, z]) + 1 + x + ───── + 1 + y + ─ + z + +We use ``Integer(0)`` in ``list_to_frac`` so that the result will always be a +SymPy object, even if we only pass in Python ints. + + >>> list_to_frac([1, 2, 3, 4]) + 43 + ── + 30 + +Every finite continued fraction is a rational number, but we are interested +in symbolics here, so let's create a symbolic continued fraction. The +``symbols`` function that we have been using has a shortcut to create numbered +symbols. ``symbols('a0:5')`` will create the symbols ``a0``, ``a1``, ..., +``a5``. + + >>> syms = symbols('a0:5') + >>> syms + (a₀, a₁, a₂, a₃, a₄) + >>> a0, a1, a2, a3, a4 = syms + >>> frac = list_to_frac(syms) + >>> frac + 1 + a₀ + ───────────────── + 1 + a₁ + ──────────── + 1 + a₂ + ─────── + 1 + a₃ + ── + a₄ + +This form is useful for understanding continued fractions, but lets put it +into standard rational function form using ``cancel``. + + >>> frac = cancel(frac) + >>> frac + a₀⋅a₁⋅a₂⋅a₃⋅a₄ + a₀⋅a₁⋅a₂ + a₀⋅a₁⋅a₄ + a₀⋅a₃⋅a₄ + a₀ + a₂⋅a₃⋅a₄ + a₂ + a₄ + ───────────────────────────────────────────────────────────────────────── + a₁⋅a₂⋅a₃⋅a₄ + a₁⋅a₂ + a₁⋅a₄ + a₃⋅a₄ + 1 + +Now suppose we were given ``frac`` in the above canceled form. In fact, we +might be given the fraction in any form, but we can always put it into the +above canonical form with ``cancel``. Suppose that we knew that it could be +rewritten as a continued fraction. How could we do this with SymPy? A +continued fraction is recursively `c + \frac{1}{f}`, where `c` is an integer +and `f` is a (smaller) continued fraction. If we could write the expression +in this form, we could pull out each `c` recursively and add it to a list. We +could then get a continued fraction with our ``list_to_frac`` function. + +The key observation here is that we can convert an expression to the form `c + +\frac{1}{f}` by doing a partial fraction decomposition with respect to +`c`. This is because `f` does not contain `c`. This means we need to use the +``apart`` function. We use ``apart`` to pull the term out, then subtract it +from the expression, and take the reciprocal to get the `f` part. + + >>> l = [] + >>> frac = apart(frac, a0) + >>> frac + a₂⋅a₃⋅a₄ + a₂ + a₄ + a₀ + ─────────────────────────────────────── + a₁⋅a₂⋅a₃⋅a₄ + a₁⋅a₂ + a₁⋅a₄ + a₃⋅a₄ + 1 + >>> l.append(a0) + >>> frac = 1/(frac - a0) + >>> frac + a₁⋅a₂⋅a₃⋅a₄ + a₁⋅a₂ + a₁⋅a₄ + a₃⋅a₄ + 1 + ─────────────────────────────────────── + a₂⋅a₃⋅a₄ + a₂ + a₄ + +Now we repeat this process + + >>> frac = apart(frac, a1) + >>> frac + a₃⋅a₄ + 1 + a₁ + ────────────────── + a₂⋅a₃⋅a₄ + a₂ + a₄ + >>> l.append(a1) + >>> frac = 1/(frac - a1) + >>> frac = apart(frac, a2) + >>> frac + a₄ + a₂ + ───────── + a₃⋅a₄ + 1 + >>> l.append(a2) + >>> frac = 1/(frac - a2) + >>> frac = apart(frac, a3) + >>> frac + 1 + a₃ + ── + a₄ + >>> l.append(a3) + >>> frac = 1/(frac - a3) + >>> frac = apart(frac, a4) + >>> frac + a₄ + >>> l.append(a4) + >>> list_to_frac(l) + 1 + a₀ + ───────────────── + 1 + a₁ + ──────────── + 1 + a₂ + ─────── + 1 + a₃ + ── + a₄ + + +.. sidebar:: Quick Tip + + You can execute multiple lines at once in SymPy Live. Typing + ``Shift-Enter`` instead of ``Enter`` will enter a newline instead of + executing. + +Of course, this exercise seems pointless, because we already know that our +``frac`` is ``list_to_frac([a0, a1, a2, a3, a4])``. So try the following +exercise. Take a list of symbols and randomize them, and create the canceled +continued fraction, and see if you can reproduce the original list. For +example + + >>> import random + >>> l = list(symbols('a0:5')) + >>> random.shuffle(l) + >>> orig_frac = frac = cancel(list_to_frac(l)) + >>> del l + +Click on "Run code block in SymPy Live" on the definition of ``list_to_frac`` +above, and then on the above example, and try to reproduce ``l`` from +``frac``. I have deleted ``l`` at the end to remove the temptation for +peeking (you can check your answer at the end by calling +``cancel(list_to_frac(l))`` on the list that you generate at the end, and +comparing it to ``orig_frac``. + +See if you can think of a way to figure out what symbol to pass to ``apart`` +at each stage (hint: think of what happens to `a_0` in the formula `a_0 + +\frac{1}{a_1 + \cdots}` when it is canceled). + +.. Answer: a0 is the only symbol that does not appear in the denominator diff -Nru python3-sympy-0.7.2/doc/src/tutorial/solvers.rst python3-sympy-0.7.3/doc/src/tutorial/solvers.rst --- python3-sympy-0.7.2/doc/src/tutorial/solvers.rst 1970-01-01 00:00:00.000000000 +0000 +++ python3-sympy-0.7.3/doc/src/tutorial/solvers.rst 2013-07-13 17:50:18.000000000 +0000 @@ -0,0 +1,165 @@ +========= + Solvers +========= + + >>> from sympy import * + >>> x, y, z = symbols('x y z') + >>> init_printing(use_unicode=True) + +A Note about Equations +====================== + +Recall from the :ref:`gotchas ` section of this +tutorial that symbolic equations in SymPy are not represented by ``=`` or +``==``, but by ``Eq``. + + + >>> Eq(x, y) + x = y + + +However, there is an even easier way. In SymPy, any expression is not in an +``Eq`` is automatically assumed to equal 0 by the solving functions. Since `a += b` if and only if `a - b = 0`, this means that instead of using ``x == y``, +you can just use ``x - y``. For example + + >>> solve(Eq(x**2, 1), x) + [-1, 1] + >>> solve(Eq(x**2 - 1, 0), x) + [-1, 1] + >>> solve(x**2 - 1, x) + [-1, 1] + +This is particularly useful if the equation you wish to solve is already equal +to 0. Instead of typing ``solve(Eq(expr, 0), x)``, you can just use +``solve(expr, x)``. + +Solving Equations Algebraically +=============================== + +The main function for solving algebraic equations, as we saw above, is +``solve``. The syntax is ``solve(equations, variables)``, where, as we saw +above, ``equations`` may be in the form of ``Eq`` instances or expressions +that are assumed to be equal to zero. + +.. TODO: This is a mess, because solve() has such a complicated interface. + +When solving a single equation, the output of ``solve`` is a list of the +solutions. + + >>> solve(x**2 - x, x) + [0, 1] + +If no solutions are found, an empty list is returned, or +``NotImplementedError`` is raised. + + >>> solve(exp(x), x) + [] + +.. note:: + + If ``solve`` returns ``[]`` or raises ``NotImplementedError``, it doesn't + mean that the equation has no solutions. It just means that it couldn't + find any. Often this means that the solutions cannot be represented + symbolically. For example, the equation `x = \cos(x)` has a solution, but + it cannot be represented symbolically using standard functions. + + >>> solve(x - cos(x), x) + Traceback (most recent call last): + ... + NotImplementedError: multiple generators [x, exp(I*x)] + No algorithms are implemented to solve equation exp(I*x) + + In fact, ``solve`` makes *no guarantees whatsoever* about the completeness + of the solutions it finds. Much of ``solve`` is heuristics, which may find + some solutions to an equation or system of equations, but not all of them. + +``solve`` can also solve systems of equations. Pass a list of equations and a +list of variables to solve for. + + >>> solve([x - y + 2, x + y - 3], [x, y]) + {x: 1/2, y: 5/2} + >>> solve([x*y - 7, x + y - 6], [x, y]) + ⎡⎛ ___ ___ ⎞ ⎛ ___ ___ ⎞⎤ + ⎣⎝- ╲╱ 2 + 3, ╲╱ 2 + 3⎠, ⎝╲╱ 2 + 3, - ╲╱ 2 + 3⎠⎦ + +.. note:: + + The type of the output of ``solve`` when solving systems of equations + varies depending on the type of the input. If you want a consistent + interface, pass ``dict=True``. + + >>> solve([x - y + 2, x + y - 3], [x, y], dict=True) + [{x: 1/2, y: 5/2}] + >>> solve([x*y - 7, x + y - 6], [x, y], dict=True) + ⎡⎧ ___ ___ ⎫ ⎧ ___ ___ ⎫⎤ + ⎢⎨x: - ╲╱ 2 + 3, y: ╲╱ 2 + 3⎬, ⎨x: ╲╱ 2 + 3, y: - ╲╱ 2 + 3⎬⎥ + ⎣⎩ ⎭ ⎩ ⎭⎦ + +.. _tutorial-roots: + +``solve`` reports each solution only once. To get the solutions of a +polynomial including multiplicity use ``roots``. + + >>> solve(x**3 - 6*x**2 + 9*x, x) + [0, 3] + >>> roots(x**3 - 6*x**2 + 9*x, x) + {0: 1, 3: 2} + +The output ``{0: 1, 3: 2}`` of ``roots`` means that ``0`` is a root of +multiplicity 1 and ``3`` is a root of multiplicity 2. + +.. _tutorial-dsolve: + +Solving Differential Equations +============================== + +To solve differential equations, use ``dsolve``. First, create an undefined +function by passing ``cls=Function`` to the ``symbols`` function. + + + >>> f, g = symbols('f g', cls=Function) + +``f`` and ``g`` are now undefined functions. We can call ``f(x)``, and it +will represent an unknown function. + + >>> f(x) + f(x) + +Derivatives of ``f(x)`` are unevaluated. + + >>> f(x).diff(x) + d + ──(f(x)) + dx + +(see the :ref:`Derivatives ` section for more on +derivatives). + +To represent the differential equation `f''(x) - 2f'(x) + f(x) = \sin(x)`, we +would thus use + + >>> diffeq = Eq(f(x).diff(x, x) - 2*f(x).diff(x) + f(x), sin(x)) + >>> diffeq + 2 + d d + f(x) - 2⋅──(f(x)) + ───(f(x)) = sin(x) + dx 2 + dx + +To solve the ODE, pass it and the function to solve for to ``dsolve``. + + >>> dsolve(diffeq, f(x)) + x cos(x) + f(x) = (C₁ + C₂⋅x)⋅ℯ + ────── + 2 + +``dsolve`` returns an instance of ``Eq``. This is because in general, +solutions to differential equations cannot be solved explicitly for the +function. + + >>> dsolve(f(x).diff(x)*(1 - sin(f(x))), f(x)) + f(x) + cos(f(x)) = C₁ + +The arbitrary constants in the solutions from dsolve are symbols of the form +``C1``, ``C2``, ``C3``, and so on. diff -Nru python3-sympy-0.7.2/doc/src/tutorial.bg.po python3-sympy-0.7.3/doc/src/tutorial.bg.po --- python3-sympy-0.7.2/doc/src/tutorial.bg.po 2012-10-17 02:30:33.000000000 +0000 +++ python3-sympy-0.7.3/doc/src/tutorial.bg.po 1970-01-01 00:00:00.000000000 +0000 @@ -1,493 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) 2008, 2009, 2010, 2011, 2012 SymPy Development Team -# This file is distributed under the same license as the SymPy package. -# FIRST AUTHOR , YEAR. -# -msgid "" -msgstr "" -"Project-Id-Version: SymPy 0.7.2\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2011-12-17 15:29\n" -"PO-Revision-Date: 2011-12-29 19:03+0530\n" -"Last-Translator: \n" -"Language-Team: LANGUAGE \n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" - -# 3b8d0d99cbd0485d8a0f874d50c2e0ba -#: ../../src/tutorial.rst:5 -msgid "Tutorial" -msgstr "Урок" - -# 261dbc2a93064851bb80b80a8985f0bd -#: ../../src/tutorial.rst:10 -msgid "Introduction" -msgstr "Въведение" - -# d007423f3c5d4407b0ca3221168f4a1e -#: ../../src/tutorial.rst:12 -msgid "SymPy is a Python library for symbolic mathematics. It aims to become a full-featured computer algebra system (CAS) while keeping the code as simple as possible in order to be comprehensible and easily extensible. SymPy is written entirely in Python and does not require any external libraries." -msgstr "SymPy е библиотека на Python за символна математика. Тя цели да стане пълнофункционална алгебрична система (CAS - computer algebra system), като поддържа кода възможно най-опростен с цел да бъде разбираем и лесен за разширяване.SymPy е изцяло написана на Python и не изисква външни библиотеки." - -# 344f5db4e74749c1a76459f6cec09b63 -#: ../../src/tutorial.rst:17 -msgid "This tutorial gives an overview and introduction to SymPy. Read this to have an idea what SymPy can do for you (and how) and if you want to know more, read the :ref:`SymPy User's Guide `, :ref:`SymPy Modules Reference `. or the `sources `_ directly." -msgstr "Този урок е въведение към SymPy. Прочетете го, за да научите какво и как може SymPy, и ако искате да научите повече, прочетете :ref:`SymPy User's Guide `, :ref:`SymPy Modules Reference `. или `сорс код`_ директно." - -# 12619172a6874cb4af84282e3e1bfc39 -#: ../../src/tutorial.rst:26 -msgid "First Steps with SymPy" -msgstr "Първи стъпки със SymPy" - -# 6f67d8997f1a474288d6bd50f5ddbc4f -#: ../../src/tutorial.rst:28 -msgid "The easiest way to download it is to go to http://code.google.com/p/sympy/ and download the latest tarball from the Featured Downloads:" -msgstr "Най-лесният начин да свалите SymPy е да отидете на http://code.google.com/p/sympy/ и да изтеглите последния архив." - -# 65bde5e4aded4818bc11c4b9cfc8a3b7 -#: ../../src/tutorial.rst:34 -msgid "Unpack it:" -msgstr "Разархивирайте го:" - -# 76f6f7d72759408084134e093b5d9aea -#: ../../src/tutorial.rst:40 -msgid "and try it from a Python interpreter:" -msgstr "и го изпробвайте от интерпретатор на Python:" - -# 4ddd39aeea714e9f8495cd77f7e4d7dd -#: ../../src/tutorial.rst:54 -msgid "You can use SymPy as shown above and this is indeed the recommended way if you use it in your program. You can also install it using ``./setup.py install`` as any other Python module, or just install a package in your favourite Linux distribution, e.g.:" -msgstr "Може да използвате SymPy както е показано отгоре, което всъщност е препоръчителният начин, ако го използвате във вашата програма. Също така може да го инсталирате, използвайки ./setup.py install, както който и да е модул на Python,или просто инсталирайте пакет във вашата любима Linux дистрибуция, например:" - -# ce08a431018449c093786fe229ef9736 -#: ../../src/tutorial.rst:80 -msgid "For other means how to install SymPy, consult the Downloads_ tab on the SymPy's webpage." -msgstr "За други начини за инсталация може да погледнете страницата ни за" - -# e81794f1d22c4f47b1f0b5f484ccb789 -#: ../../src/tutorial.rst:87 -msgid "isympy Console" -msgstr "isympy Конзола" - -# 342865b9196045a6a2a11ae9d69bc980 -#: ../../src/tutorial.rst:89 -msgid "For experimenting with new features, or when figuring out how to do things, you can use our special wrapper around IPython called ``isympy`` (located in ``bin/isympy`` if you are running from the source directory) which is just a standard Python shell that has already imported the relevant SymPy modules and defined the symbols x, y, z and some other things:" -msgstr "За да експериментирате с нови функционалности или когато се опитвате да разберете как да направите нещата, може да използвате нашата специална обвивка около IPython, наречена isympy (намираща се в bin/isympy, ако сте компилирали през сорс директорията), която е стандартна конзола на Python и която включва съответните SymPy модули и дефинираните символи x, y, z, както и някои други неща:" - -# 9d9f7e2ea55549268218f99a5b14593a -#: ../../src/tutorial.rst:119 -msgid "Commands entered by you are bold. Thus what we did in 3 lines in a regular Python interpreter can be done in 1 line in isympy." -msgstr "Командите, въведени от вас, са удебелени. Така, това което направихме в 3 линии на обикновен Python, може да се направи с 1 линия на isympy." - -# f53c41b84d8b4d47894877572350325c -#: ../../src/tutorial.rst:124 -msgid "Using SymPy as a calculator" -msgstr "Използване на SymPy като калкулатор" - -# c6a7837a22d44c27a5d35a905779bd84 -#: ../../src/tutorial.rst:126 -msgid "SymPy has three built-in numeric types: Float, Rational and Integer." -msgstr "SymPy има 3 вградени типове числа: Цели, с плаваща запетая и рационални." - -# 68eba98bb6f742d799aba6051f7f3d0f -#: ../../src/tutorial.rst:128 -msgid "The Rational class represents a rational number as a pair of two Integers: the numerator and the denominator. So Rational(1,2) represents 1/2, Rational(5,2) represents 5/2, and so on." -msgstr "Рационалният клас представлява рационална дроб като двойка от цели числа: числителя и знаменателя, така че Rational(1,2) представлява 1/2, Rational(5,2) 5/2 и така нататък." - -# 4178f4aea2b54612a2a0c8f74fe2aa63 -#: ../../src/tutorial.rst:147 -msgid "Proceed with caution while working with Python int's and floating point numbers, especially in division, since you may create a Python number, not a SymPy number. A ratio of two Python ints may create a float -- the \"true division\" standard of Python 3 and the default behavior of ``isympy`` which imports division from __future__::" -msgstr "Бъдете предпазливи, когато работите с цели и с плаваща запетая числа в Python особено когато делите, защото може да създадете Python число, а не SymPy число. От съотношението на 2 цели числа в Python може да се получи число с плаваща запетая -- \"истинското деление\", което е стандарт в Python 3, и подразбиращото се поведение на ``isympy``, което въвежда делението от __future__::" - -# 723ba484cf134b71aaf8e7140c9a3954 -#: ../../src/tutorial.rst:157 -msgid "But in earlier Python versions where division has not been imported, a truncated int will result::" -msgstr "Но в по-ранните версии на Python, където \"истинското делението\" не бе въведено, като резултат ще бъде закръглено число::" - -# 0f88584459994baa87824d3fd4cf34f1 -#: ../../src/tutorial.rst:163 -msgid "In both cases, however, you are not dealing with a SymPy Number because Python created its own number. Most of the time you will probably be working with Rational numbers, so make sure to use Rational to get the SymPy result. One might find it convenient to equate ``R`` and Rational::" -msgstr "Все пак и в двата случая не използваме SymPy числа, защото Python създава свои собствени. През повечето време най-вероятно ще работите с рационални числа, така че се уверете, че използвате Rational, за да получите очаквания резултат. Може да сметнете за удобно да използвате ``R`` като Rational::" - -# bf581140e5ea4f8f98031862c785375e -#: ../../src/tutorial.rst:175 -msgid "We also have some special constants, like e and pi, that are treated as symbols (1+pi won't evaluate to something numeric, rather it will remain as 1+pi), and have arbitrary precision::" -msgstr "Ние също така имаме някои специални константи, като e и pi, които се третират като символи (1+pi няма да се изчисли като някое число, а ще си остане 1+pi) и имат арбитрарна точност::" - -# 366cb3315e5f4371927639cebbf8a726 -#: ../../src/tutorial.rst:189 -msgid "as you see, evalf evaluates the expression to a floating-point number" -msgstr "Както виждате, evalf изчислява израза до число с плаваща запетая." - -# b300cf55ed11465bac6e0991d6f61a15 -#: ../../src/tutorial.rst:191 -msgid "The symbol ``oo`` is used for a class defining mathematical infinity::" -msgstr "Също така има и клас, представляващ математическа безкрайност, наречен ``oo``::" - -# addc7fddfd294a0e8da003463f35b614 -#: ../../src/tutorial.rst:200 -msgid "Symbols" -msgstr "Символи" - -# 8508a3480ca34bd4a8741733e17ccc56 -#: ../../src/tutorial.rst:202 -msgid "In contrast to other Computer Algebra Systems, in SymPy you have to declare symbolic variables explicitly::" -msgstr "За разлика от други компютърни алгебрични системи (CAS), в SymPy вие трябва изрично да декларирате символните променливи::" - -# 19bcc88285724ae99b448a86d7980ce9 -#: ../../src/tutorial.rst:209 -msgid "On the left is the normal Python variable which has been assigned to the SymPy Symbol class. Predefined symbols (including those for symbols with Greek names) are available for import from abc:" -msgstr "Отляво е променливата, на която задаваме като стойност инстанция на SymPy класа Symbol. Инстанциите на този клас могат да се комбинират и да направят израз::" - -# 6b654b5bda774aa0a4b150388bc102dc -#: ../../src/tutorial.rst:215 -msgid "Symbols can also be created with the ``symbols`` or ``var`` functions, the latter automatically adding the created symbols to the namespace, and both accepting a range notation:" -msgstr "" - -# aa93d9743638443ebbae8bc5bee19e56 -#: ../../src/tutorial.rst:227 -msgid "Instances of the Symbol class \"play well together\" and are the building blocks of expresions::" -msgstr "Инстанциите на този клас могат да се комбинират и да направят израз::" - -# c613786cee894688b20cdccfeaac8c9b -#: ../../src/tutorial.rst:239 -msgid "They can be substituted with other numbers, symbols or expressions using ``subs(old, new)``::" -msgstr "И да ги замествате с други символи или числа като използвате ``subs(old, new)``::" - -# 3872add29a8b4a71a5e26a3218130491 -#: ../../src/tutorial.rst:250 -msgid "For the remainder of the tutorial, we assume that we have run::" -msgstr "До края на този урок предполагаме, че сте изпълнили следния код::" - -# d1b280862f04408a98ba048cc9460eaa -#: ../../src/tutorial.rst:255 -msgid "This will make things look better when printed. See the :ref:`printing-tutorial` section below. If you have a unicode font installed, you can pass use_unicode=True for a slightly nicer output." -msgstr "Това ще направи нещата да изглеждат по-добре, когато се принтират (pretty printing). Погледнете секцията за принтиране по-нататък. Ако имате инсталиран някой unicode шрифт, може да подадете use_unicode=True за доста по-красив изход." - -# 17ee30ecb05a410d94cccf0cc229ae5b -#: ../../src/tutorial.rst:260 -msgid "Algebra" -msgstr "Алгебра" - -# 673fbe9f608748128027755ac1b0d7cb -#: ../../src/tutorial.rst:262 -msgid "For partial fraction decomposition, use ``apart(expr, x)``::" -msgstr "За да разложите непълни дроби, използвайте ``apart(expr, x)``::" - -# 723c57a6e36f43eca18771e2ad246955 -#: ../../src/tutorial.rst:287 -msgid "To combine things back together, use ``together(expr, x)``::" -msgstr "За да комбинирате нещата отново заедно, използвайте ``together(expr, x)``::" - -# 607fa824a12d461d9eaf6c83bbc902d0 -#: ../../src/tutorial.rst:309 -msgid "Calculus" -msgstr "Висша математика" - -# 9cbc010ae5b54d2a9222db8a78a2687c -#: ../../src/tutorial.rst:314 -msgid "Limits" -msgstr "Граници" - -# e2cfd8cf367b4f41a2eb8f98045e1f45 -#: ../../src/tutorial.rst:316 -msgid "Limits are easy to use in SymPy, they follow the syntax ``limit(function, variable, point)``, so to compute the limit of f(x) as x -> 0, you would issue ``limit(f, x, 0)``::" -msgstr "Границите са изключително лесни за използване в SymPy. Те имат следния синтаксис limit(function, variable, point), така че за да изчислите границата на f(x), където x -> 0 бихте използвали ``limit(f, x, 0)``::" - -# 7cc96e845d0a4c479199f4a51ed7d665 -#: ../../src/tutorial.rst:325 -msgid "you can also calculate the limit at infinity::" -msgstr "също така може да изчислите граница до безкрайност::" - -# d67693fb8cc04954be3bff6aaa712bfa -#: ../../src/tutorial.rst:336 -msgid "for some non-trivial examples on limits, you can read the test file `test_demidovich.py `_" -msgstr "За някои не толкова тривиални примери, може да прегледате тестовия файл `test_demidovich.py `_" - -# c92009d7b6df4e2d8f9fe9ad14657bbd -#: ../../src/tutorial.rst:343 -msgid "Differentiation" -msgstr "Диференциално смятане" - -# 476aa0220145495a932178c9fc3b305a -#: ../../src/tutorial.rst:345 -msgid "You can differentiate any SymPy expression using ``diff(func, var)``. Examples::" -msgstr "Може да изчислите производните на който и да е израз в SymPy, като използвате ``diff(func, var)``. Примери::" - -# 35850640eccf4071b1b0318a49055f39 -#: ../../src/tutorial.rst:358 -msgid "You can check, that it is correct by::" -msgstr "Можете да проверите, че е правилно, като::" - -# 5ffab586313e4970aa3c933d631bc676 -#: ../../src/tutorial.rst:366 -msgid "Higher derivatives can be calculated using the ``diff(func, var, n)`` method::" -msgstr "Производни от по-висок ред могат да бъдат пресметнати чрез използването на метода ``diff(func, var, n)`` ::" - -# 0624a0af400f4e78a351b056a7ba009c -#: ../../src/tutorial.rst:383 -msgid "Series expansion" -msgstr "Разлагане в ред" - -# b40c746b225d4749a9298ad077c3ce4d -#: ../../src/tutorial.rst:385 -msgid "Use ``.series(var, point, order)``::" -msgstr "Използвайте метода ``.series(var, point, order)``::" - -# f9106b494ab2465bbbd4108736f67a1e -#: ../../src/tutorial.rst:400 -msgid "Another simple example::" -msgstr "Друг прост пример::" - -# d4aa5a4ef31d4327a70c47b42cc0d2d4 -#: ../../src/tutorial.rst:420 -msgid "Integration" -msgstr "Интегриране" - -# 8e985ebba8d5463bb1af3a3220dd21b0 -#: ../../src/tutorial.rst:422 -msgid "SymPy has support for indefinite and definite integration of transcendental elementary and special functions via ``integrate()`` facility, which uses powerful extended Risch-Norman algorithm and some heuristics and pattern matching::" -msgstr "SymPy поддръжа определени и неопределени интеграли на елементарни и специални трансцедентни функции с помощта на integrate(), който използва мощния разширен алгоритъм на Risch-Norman и няколко еврестики и сравнения с шаблони::" - -# 6ff3ff4c189f45078f75a93aa2863ef9 -#: ../../src/tutorial.rst:430 -msgid "You can integrate elementary functions::" -msgstr "Можете да декларирате елементарни функции::" - -# ead91a6c777f47dea8be1a1e50bdf752 -#: ../../src/tutorial.rst:443 -msgid "Also special functions are handled easily::" -msgstr "Лесно можете да се справите и със специалните функции::" - -# 40ad8cd5c7e3460f9cceb59630cf562c -#: ../../src/tutorial.rst:451 -msgid "It is possible to compute definite integrals::" -msgstr "Възможно е да изчислите даден интеграл::" - -# 19602e9ed1b641f993f704eb31111beb -#: ../../src/tutorial.rst:460 -msgid "Also, improper integrals are supported as well::" -msgstr "Също така се поддържат и неопределени интеграли::" - -# b8ef574746f1448ab78da1958f9de616 -#: ../../src/tutorial.rst:472 -msgid "Complex numbers" -msgstr "Комплексни числа" - -# 13fbbe2555b14aefb25e48ac5ed298a0 -#: ../../src/tutorial.rst:474 -msgid "Besides the imaginary unit, I, which is imaginary, symbols can be created with attributes (e.g. real, positive, complex, etc...) and this will affect how they behave::" -msgstr "" - -# d726887f4f0444dba6e4ef6a2bb702d6 -#: ../../src/tutorial.rst:491 -msgid "Functions" -msgstr "Функции" - -# 42585fb828e24af79c0278aa14bcc2c3 -#: ../../src/tutorial.rst:493 -msgid "**trigonometric**::" -msgstr "**тригонометрични**::" - -# be0be9ba76c042b68160f1907d2b0d13 -#: ../../src/tutorial.rst:542 -msgid "**spherical harmonics**::" -msgstr "**сферични хармонични**::" - -# bdc2ad96783444459c3e66c409914143 -#: ../../src/tutorial.rst:568 -msgid "**factorials and gamma function**::" -msgstr "**факториел и гама функции**::" - -# c621f51005504ee9890d34156556de57 -#: ../../src/tutorial.rst:586 -msgid "**zeta function**::" -msgstr "**дзета функции**::" - -# 95ad3014dc9442cc8eb8438b2cc28327 -#: ../../src/tutorial.rst:611 -msgid "**polynomials**::" -msgstr "**полиноми**::" - -# d91cad90caee4aa7b2922a42ebe608b1 -#: ../../src/tutorial.rst:650 -msgid "Differential Equations" -msgstr "Диференциални уравнения" - -# 18467aefa0364cec936571494c1993da -# 65279c1f5c4a448fbb813790d956ac48 -#: ../../src/tutorial.rst:652 -#: ../../src/tutorial.rst:672 -msgid "In ``isympy``::" -msgstr "В ``isympy``::" - -# e036530fce79489cbf1c494a9443568f -#: ../../src/tutorial.rst:670 -msgid "Algebraic equations" -msgstr "Алгебрични уравнения" - -# fd5aedc6ba9f45b4868c10764f9e6797 -#: ../../src/tutorial.rst:685 -msgid "Linear Algebra" -msgstr "Линейна алгебра" - -# 372cf49866874ec1a97d6cb813f8b63b -#: ../../src/tutorial.rst:690 -msgid "Matrices" -msgstr "Матрици" - -# fc4620da22164a3c8f25be8591759f97 -#: ../../src/tutorial.rst:692 -msgid "Matrices are created as instances from the Matrix class::" -msgstr "Матриците се създават като инстанции на Matrix класа::" - -# 0289f9cec4f140c6adc90aa38f84efee -#: ../../src/tutorial.rst:700 -msgid "They can also contain symbols::" -msgstr "също така може да слагате символи в тях::" - -# ced23cc091a34db6be3b5597fd056f32 -#: ../../src/tutorial.rst:715 -msgid "For more about Matrices, see the Linear Algebra tutorial." -msgstr "За повече информация и примери с матрици вижте Linear Algebra tutorial." - -# 71124cfe123649c28c7a61251d0b1cdd -#: ../../src/tutorial.rst:720 -msgid "Pattern matching" -msgstr "Сравняване на шаблони" - -# b9ecf875555748978255bc268bc4123c -#: ../../src/tutorial.rst:722 -msgid "Use the ``.match()`` method, along with the ``Wild`` class, to perform pattern matching on expressions. The method will return a dictionary with the required substitutions, as follows::" -msgstr "Използвайте ``.match()`` метода заедно с класа Wild за да сравнявате изрази с даден шаблон. Методът ще върне речник с изисканите замествания, както следва::" - -# 06d4a8e419854045af79b0076e71616a -#: ../../src/tutorial.rst:736 -msgid "If the match is unsuccessful, it returns ``None``::" -msgstr "Ако съвпадението е неуспешно, методът връща ``None``::" - -# 7219ffc6e8b0486a913297c19b5fce1f -#: ../../src/tutorial.rst:741 -msgid "One can also use the exclude parameter of the ``Wild`` class to ensure that certain things do not show up in the result::" -msgstr "Можете да използвате и втория незадължителен параметър exclude, за да се уверите, че някои неща не се появяват в резултата::" - -# a692f291013a4777a4771188901c6bf2 -#: ../../src/tutorial.rst:755 -msgid "Printing" -msgstr "Принтиране" - -# 8cfe16423a79408c828d270def412899 -#: ../../src/tutorial.rst:757 -msgid "There are many ways to print expressions." -msgstr "Има много начини, по които изразите може да се отпечатат." - -# a9891e6028b644879ce5e3a8489a72a5 -#: ../../src/tutorial.rst:759 -msgid "**Standard**" -msgstr "**Стандартен начин**" - -# 9802b10f6c2d4b7997302f4315e8bf2a -#: ../../src/tutorial.rst:761 -msgid "This is what ``str(expression)`` returns and it looks like this:" -msgstr "Това е резултатът от ``str(expression)`` и изглежда така:" - -# 461df293b09c46b1bf24bc5c335b4401 -#: ../../src/tutorial.rst:772 -msgid "**Pretty printing**" -msgstr "**Красиво отпечатване (pretty printing)**" - -# 29c9e2204a0948db9d8328300f3bdd1a -#: ../../src/tutorial.rst:774 -msgid "Nice ascii-art printing is produced by the ``pprint`` function:" -msgstr "Това е хубаво отпечатване тип ascii-art, направено от ``pprint`` функция:" - -# 5fc9fa809fa04cee8113a669f032b9c3 -#: ../../src/tutorial.rst:793 -msgid "If you have a unicode font installed, the ``pprint`` function will use it by default. You can override this using the ``use_unicode`` option.:" -msgstr "Ако имате инсталиран unicode шрифт, то той би трябвало да бъде използван по подразбиране. Може смените това поведение, като използвате опцията ``use_unicode``.:" - -# dcbf982351c1414bb0c2653039d6f569 -#: ../../src/tutorial.rst:803 -msgid "See also the wiki `Pretty Printing `_ for more examples of a nice unicode printing." -msgstr "Също така вижте уикито `Pretty Printing `_ за повече примери за добро unicode принтиране." - -# af26680251b0437e807a48d7946c3724 -#: ../../src/tutorial.rst:807 -msgid "Tip: To make pretty printing the default in the Python interpreter, use::" -msgstr "Съвет:За да направите красивото отпечатване(pretty printing) по подразбиране в интерпретатора на Python, използвайте::" - -# b34cf35aca67417bbedfd0f9912d3dab -#: ../../src/tutorial.rst:830 -msgid "**Python printing**" -msgstr "**Python отпечатване**" - -# f6300e28499f4c23b1a18aca896340bb -#: ../../src/tutorial.rst:846 -msgid "**LaTeX printing**" -msgstr "**LaTeX отпечатване**" - -# 3b81c7e35c364676a8ec8587b515ac8b -#: ../../src/tutorial.rst:863 -msgid "**MathML**" -msgstr "*MathML**" - -# ee36b86c5d54419fbde01ac89cab213b -#: ../../src/tutorial.rst:875 -msgid "**Pyglet**" -msgstr "**Pyglet**" - -# 8ea61d943b2b4960a879932eba46bc1b -#: ../../src/tutorial.rst:881 -msgid "If pyglet is installed, a pyglet window will open containing the LaTeX rendered expression:" -msgstr "И pyglet прозорец с LaTeX рендиран израз ще се появи:" - -# 8741a66d24b04738a563afc90a41567b -#: ../../src/tutorial.rst:887 -msgid "Notes" -msgstr "Бележки" - -# 51219a05b9a84e79b754d8d03b7fc4fb -#: ../../src/tutorial.rst:889 -msgid "``isympy`` calls ``pprint`` automatically, so that's why you see pretty printing by default." -msgstr "``isympy`` извиква ``pprint`` автоматично, поради тази причина виждате красивото отпечатване (pretty printing) по подразбиране." - -# 7b126ec3363b4c63a6d6b98728a9738a -#: ../../src/tutorial.rst:892 -msgid "Note that there is also a printing module available, ``sympy.printing``. Other printing methods available through this module are:" -msgstr "Забележете, че също така има модул за принтиране, ``sympy.printing``. Други методи за принтиране, налични чрез този модул, са:" - -# 1001063c4e97442dbcb0491eb0641bba -#: ../../src/tutorial.rst:895 -msgid "``pretty(expr)``, ``pretty_print(expr)``, ``pprint(expr)``: Return or print, respectively, a pretty representation of ``expr``. This is the same as the second level of representation described above." -msgstr "``pretty(expr)``, ``pretty_print(expr)``, ``pprint(expr)``: Връща или принтира, съответно, красива репрезентация на ``expr``. Това е еквивалентно на второто ниво на репрезентация показано по-горе." - -# ee0ca8e34ce04b458228cb9d6565ec1a -#: ../../src/tutorial.rst:897 -msgid "``latex(expr)``, ``print_latex(expr)``: Return or print, respectively, a `LaTeX `_ representation of ``expr``" -msgstr "``latex(expr)``, ``print_latex(expr)``: Връща или принтира, съответно, `LaTeX `_ репрезентация на ``expr``" - -# ebfeade491644b0b85f72b00bd3c1bdf -#: ../../src/tutorial.rst:899 -msgid "``mathml(expr)``, ``print_mathml(expr)``: Return or print, respectively, a `MathML `_ representation of ``expr``." -msgstr "``mathml(expr)``, ``print_mathml(expr)``: Връща или принтира, съответно, `MathML `_ репрезентация на ``expr``." - -# bc0334fae2224eb2bfc81a55e7f522dd -#: ../../src/tutorial.rst:901 -msgid "``print_gtk(expr)``: Print ``expr`` to `Gtkmathview `_, a GTK widget that displays MathML code. The `Gtkmathview `_ program is required." -msgstr "``print_gtk(expr)``: Принтира ``expr`` на `Gtkmathview `_, GTK интрумент, който визуализира MathML код. Изисква се `Gtkmathview `_ ." - -# e76c7af419504e458893b76b1b485fd4 -#: ../../src/tutorial.rst:904 -msgid "Further documentation" -msgstr "Допълнителна документация" - -# 2757e954e4c04b01bf9607f2127c3146 -#: ../../src/tutorial.rst:906 -msgid "Now it's time to learn more about SymPy. Go through the :ref:`SymPy User's Guide ` and :ref:`SymPy Modules Reference `." -msgstr "Време е да научите повече за SymPy. Прегледайте :ref:`SymPy User's Guide ` и :ref:`SymPy Modules Reference `." - -# a037027043bd483dab5a52bd8d325980 -#: ../../src/tutorial.rst:910 -msgid "Be sure to also browse our public `wiki.sympy.org `_, that contains a lot of useful examples, tutorials, cookbooks that we and our users contributed, and feel free to edit it." -msgstr "Не пропускайте и да прегледате нашето публично уики – `wiki.sympy.org `_, което съдържа много полезни примери, уроци и наръчници, за които ние и нашите потребители допринасяме и Ви окуражаваме да редактирате и подобрите." diff -Nru python3-sympy-0.7.2/doc/src/tutorial.cs.po python3-sympy-0.7.3/doc/src/tutorial.cs.po --- python3-sympy-0.7.2/doc/src/tutorial.cs.po 2012-10-17 02:30:33.000000000 +0000 +++ python3-sympy-0.7.3/doc/src/tutorial.cs.po 1970-01-01 00:00:00.000000000 +0000 @@ -1,518 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) 2008, 2009, 2010, 2011, 2012 SymPy Development Team -# This file is distributed under the same license as the SymPy package. -# FIRST AUTHOR , YEAR. -# -msgid "" -msgstr "" -"Project-Id-Version: SymPy 0.7.2\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2011-12-27 11:31\n" -"PO-Revision-Date: 2011-12-27 11:52-0800\n" -"Last-Translator: \n" -"Language-Team: LANGUAGE \n" -"Language: \n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" - -# f84d341a1db74f57ba29a7b6c3c2edd9 -#: ../../src/tutorial.rst:5 -msgid "Tutorial" -msgstr "Tutoriál" - -# dae967c0fdb14ea88ac2acf861130402 -#: ../../src/tutorial.rst:10 -msgid "Introduction" -msgstr "Úvod" - -# 946c4116f6b4470c9bd363baa4085f07 -#: ../../src/tutorial.rst:12 -msgid "SymPy is a Python library for symbolic mathematics. It aims to become a full-featured computer algebra system (CAS) while keeping the code as simple as possible in order to be comprehensible and easily extensible. SymPy is written entirely in Python and does not require any external libraries." -msgstr "SymPy je knihovna jazyka Python pro symbolickou matematiku. Má za cíl stát se kompletním počítačovým algebraickým systémem (CAS, Computer algebra system) a zároveň být co nejjednodušší, aby byla pochopitelná a jednoduše rozšiřitelná. SymPy je napsaná kompletně v jazyce Python a nepotřebuje žádné externí knihovny." - -# 7d5e63b794a44e069a63a12902c8c233 -#: ../../src/tutorial.rst:17 -msgid "This tutorial gives an overview and introduction to SymPy. Read this to have an idea what SymPy can do for you (and how) and if you want to know more, read the :ref:`SymPy User's Guide `, :ref:`SymPy Modules Reference `. or the `sources `_ directly." -msgstr "Tento tutoriál je úvodem do SymPy a zároveň ukazuje, co SymPy umí. Přečtěte si ho, aby jste zjistili, jak pro vás může být SymPy užitečná a pokud budete chtít vědět víc, přečtěte si :ref:`Uživatelskou příručku SymPy `, :ref:`Přehled modulů SymPy `. nebo přímo `zdrojové kódy `_" - -# 6b78e0f225174e669fa5ab7877cb6b7f -#: ../../src/tutorial.rst:26 -msgid "First Steps with SymPy" -msgstr "První kroky se SymPy" - -# 09726dfba6634928bc673ade5d89e66b -#: ../../src/tutorial.rst:28 -msgid "The easiest way to download it is to go to http://code.google.com/p/sympy/ and download the latest tarball from the Featured Downloads:" -msgstr "Nejjednodušší způsob, jak stáhnout SymPy je jít na http://code.google.com/p/sympy/ a stáhnout nejnovější verzi z doporučených zdrojů:" - -# 95da13d57e534846abe6d3ae2b3f39d0 -#: ../../src/tutorial.rst:34 -msgid "Unpack it:" -msgstr "Rozbalit ji:" - -# e9b7c89586dc4262a1c0407754dcd7e9 -#: ../../src/tutorial.rst:40 -msgid "and try it from a Python interpreter:" -msgstr "a vyzkoušet jí v interpretru Pythonu:" - -# f6ee1f1e72cd4de781fc5774120042fb -#: ../../src/tutorial.rst:54 -msgid "You can use SymPy as shown above and this is indeed the recommended way if you use it in your program. You can also install it using ``./setup.py install`` as any other Python module, or just install a package in your favourite Linux distribution, e.g.:" -msgstr "Můžete používat SymPy, jak vidíte výše, což je doporučený způsob pokud jí používate ve svém programu. Můžete si jí také nainstalovat pomocí ``./setup.py install`` jako každý modul Pythonu nebo si jednoduše nainstalovat balíček do vaší oblíbené distribuce Linuxu. Například:" - -# cfcc2605ea584cf2af47c450edadccbf -#: ../../src/tutorial.rst:80 -msgid "For other means how to install SymPy, consult the Downloads_ tab on the SymPy's webpage." -msgstr "Pro další způsoby instalace SymPy si prohlédněte záložku Downloads_ na stránkách SymPy." - -# a19913e1d97f4b2b8559d097d92e1851 -#: ../../src/tutorial.rst:87 -msgid "isympy Console" -msgstr "isympy konzole" - -# ff2cbec326eb4f1f98083e84d4dec8db -#: ../../src/tutorial.rst:89 -#, fuzzy -msgid "For experimenting with new features, or when figuring out how to do things, you can use our special wrapper around IPython called ``isympy`` (located in ``bin/isympy`` if you are running from the source directory) which is just a standard Python shell that has already imported the relevant SymPy modules and defined the symbols x, y, z and some other things:" -msgstr "Při zkoušení nových funkcí nebo když se snažíte něčemu přijít na kloub, můžete použít na IPythonu založenou ``isympy`` (umístěnou v ``bin/isympy``, pokud jí spouštíte ze složky se zdrojovým kódem) což je prostě standardní Python shell, který má zapojené související SymPy moduly a definoval symoboly x, y, z a některé další věci:" - -# 4756c54ede09438e885a543ffe5c3c19 -#: ../../src/tutorial.rst:119 -msgid "Commands entered by you are bold. Thus what we did in 3 lines in a regular Python interpreter can be done in 1 line in isympy." -msgstr "Vámi zadané příkazy jsou tučně. Vidíme, že to, co bychom udělali ve 3 řádcích v běžném interpretru Pythonu, lze udělat v isympy v 1 řádku." - -# a50006bf0aed4e2a8a3967edb9ef7afa -#: ../../src/tutorial.rst:124 -msgid "Using SymPy as a calculator" -msgstr "SymPy jako kalkulačka" - -# 88460153b0404c1c80d7d9fef1b9d530 -#: ../../src/tutorial.rst:126 -#, fuzzy -msgid "SymPy has three built-in numeric types: Float, Rational and Integer." -msgstr "SymPy má zabudované tři číselné typy: Float, Rational a Integer." - -# 668a48de987a4bd6bb25e6319aa18ba2 -#: ../../src/tutorial.rst:128 -msgid "The Rational class represents a rational number as a pair of two Integers: the numerator and the denominator. So Rational(1,2) represents 1/2, Rational(5,2) represents 5/2, and so on." -msgstr "Třída Rational reprezentuje racionální čísla jako dvojici Integerů: čitatel a jmenovatel Takže Rational(1,2) reprezentuje 1/2, Ration(5,2) reprezentuje 5/2, a tak dále." - -# e2a928259dea44eaa3cabe0fee4bdd78 -#: ../../src/tutorial.rst:147 -msgid "Proceed with caution while working with Python int's and floating point numbers, especially in division, since you may create a Python number, not a SymPy number. A ratio of two Python ints may create a float -- the \"true division\" standard of Python 3 and the default behavior of ``isympy`` which imports division from __future__::" -msgstr "Postupujte opatrně, když pracujete s Inty a Floaty v Pythonu, obzvlášť při dělení, jelikož můžete vytvořit číslo Pythonu místo SymPy. Podíl dvou Intů v Pythonu může vytvořit Float -- \"pravé dělení\", standard Pythonu 3 a defaultní chování ``isympy``, které vkládá dělení z __future__::" - -# 3f86f4cd341e4872b08b2ae231c0c8c8 -#: ../../src/tutorial.rst:157 -msgid "But in earlier Python versions where division has not been imported, a truncated int will result::" -msgstr "Ale v dřívějších verzích Pythonu, kde nebylo dělení zakomponováno, vyšel oříznutý int::" - -# 9dbc717a5cd64ee7977c80343f7a92d9 -#: ../../src/tutorial.rst:163 -msgid "In both cases, however, you are not dealing with a SymPy Number because Python created its own number. Most of the time you will probably be working with Rational numbers, so make sure to use Rational to get the SymPy result. One might find it convenient to equate ``R`` and Rational::" -msgstr "V obou případech se nejedná o číslo SymPy, protože Python vytvořil své vlastní číslo. Většinu času budete pravděpodobně pracovat s čísly Rational, takže dávejte pozor, abyste používali Rational a dostali tak výsledek SymPy. Někomu může připadat příhodné používat místo dlouhého Rational krátké ``R``::" - -# 3ee8ed81cd7e4bfdadf807a0b9b12e2d -#: ../../src/tutorial.rst:175 -msgid "We also have some special constants, like e and pi, that are treated as symbols (1+pi won't evaluate to something numeric, rather it will remain as 1+pi), and have arbitrary precision::" -msgstr "Také máme k dispozici několik konstant, jak e nebo pí, se kterými se pracuje jako se symboly (1+pi se nevypočítá jako numerická hodnota, ale ponechá se 1+pi) a mají libovolnou přesnost::" - -# a1a7546a35f24edd8c11b1f05ea460e2 -#: ../../src/tutorial.rst:189 -msgid "as you see, evalf evaluates the expression to a floating-point number" -msgstr "jak vidíte, evalf vyhodnotí výraz na číslo s pohyblivou desetinnou čárkou." - -# fac72aa95a124064a2e37da6e411c43a -#: ../../src/tutorial.rst:191 -msgid "The symbol ``oo`` is used for a class defining mathematical infinity::" -msgstr "Symbol ``oo`` se používá pro třídu definující matematické nekonečno::" - -# aa2936b52b8042dead3f4bb1c049edc1 -#: ../../src/tutorial.rst:200 -msgid "Symbols" -msgstr "Symboly" - -# a2cdfc56d552408aacd4e540068fba20 -#: ../../src/tutorial.rst:202 -msgid "In contrast to other Computer Algebra Systems, in SymPy you have to declare symbolic variables explicitly::" -msgstr "Narozdíl od jiných počítačových algebraických systémů, v SymPy je třeba explicitně deklarovat symbolické proměnné::" - -# 18ad6f7b7485464590ced492159ac132 -#: ../../src/tutorial.rst:209 -#, fuzzy -msgid "On the left is the normal Python variable which has been assigned to the SymPy Symbol class. Predefined symbols (including those for symbols with Greek names) are available for import from abc:" -msgstr "Nalevo je běžná proměnná Pythonu, která byla přiřazená SymPy třídě Symbol. Instance třídy Symbol \"si dobře rozumí\" a jsou to stavební kameny výrazů::" - -# 4b6a9120a0484d06b47f8101bdc90f9f -#: ../../src/tutorial.rst:215 -msgid "Symbols can also be created with the ``symbols`` or ``var`` functions, the latter automatically adding the created symbols to the namespace, and both accepting a range notation:" -msgstr "Symboly mohou být vytvořeny pomocí funkcí ``symbols`` nebo ``var``, kde funkce ``var`` automaticky přídá vytvořené symboly do namespace, a jak ``symbols``, tak ``var`` podporují range notaci:" - -# 18ad6f7b7485464590ced492159ac132 -#: ../../src/tutorial.rst:227 -#, fuzzy -msgid "Instances of the Symbol class \"play well together\" and are the building blocks of expresions::" -msgstr "Nalevo je běžná proměnná Pythonu, která byla přiřazená SymPy třídě Symbol. Instance třídy Symbol \"si dobře rozumí\" a jsou to stavební kameny výrazů::" - -# 76d8e041db1c4be7926bb34608f07db0 -#: ../../src/tutorial.rst:239 -msgid "They can be substituted with other numbers, symbols or expressions using ``subs(old, new)``::" -msgstr "Mohou být nahrazeny jinými čísly, symboly nebo výrazy použitím ``subs(stary, novy)``::" - -# 25a498aa5bce46298b6bf5909ae5c45e -#: ../../src/tutorial.rst:250 -msgid "For the remainder of the tutorial, we assume that we have run::" -msgstr "Pro celý zbytek tutoriálu předpokládejme, že jsme zadali::" - -# 94b13605b8b74a32a7780b10b7c94cfa -#: ../../src/tutorial.rst:255 -msgid "This will make things look better when printed. See the :ref:`printing-tutorial` section below. If you have a unicode font installed, you can pass use_unicode=True for a slightly nicer output." -msgstr "To nám zajistí hezčí výstup. Koukněte do sekce níže :ref:`printing-tutorial-cs`. Pokud máte nainstalovaný font unicode, volbou ``use_unicode=True`` dostanete o něco hezčí výstup." - -# 292336f5375a4825bbf4806826fa3f02 -#: ../../src/tutorial.rst:260 -msgid "Algebra" -msgstr "Algebra" - -# 5c2f240042984f8cb50782f5d167085a -#: ../../src/tutorial.rst:262 -msgid "For partial fraction decomposition, use ``apart(expr, x)``::" -msgstr "Pro rozklad na parciální zlomky, použijte ``apart(expr, x)``::" - -# fa0a6c4d37934cb582f9f54330f04797 -#: ../../src/tutorial.rst:287 -msgid "To combine things back together, use ``together(expr, x)``::" -msgstr "Pro zpětné sdružení věcí dohromady, použijte ``together(expr, x)``::" - -# c50715a5f4c24b51a02423023e843c4a -#: ../../src/tutorial.rst:309 -msgid "Calculus" -msgstr "Analýza" - -# bbf0449787ed48dcaceb6997bd1af1d9 -#: ../../src/tutorial.rst:314 -msgid "Limits" -msgstr "Limity" - -# 30fd6e8326d146e1a90ecf4a9d974039 -#: ../../src/tutorial.rst:316 -#, fuzzy -msgid "Limits are easy to use in SymPy, they follow the syntax ``limit(function, variable, point)``, so to compute the limit of f(x) as x -> 0, you would issue ``limit(f, x, 0)``::" -msgstr "Limity se používají v sympy jednoduše, pomocí syntaxe ``limit(function, variable, point)``, takže pro vypočtení limity f(x) pro x -> 0 byste dosadili ``limit(f, x, 0)``::" - -# b61572954db04b9bbadb7b3214bce620 -#: ../../src/tutorial.rst:325 -msgid "you can also calculate the limit at infinity::" -msgstr "také můžete spočítat limitu v nekonečnu::" - -# 3b225244a3534797943e1911bc99109c -#: ../../src/tutorial.rst:336 -msgid "for some non-trivial examples on limits, you can read the test file `test_demidovich.py `_" -msgstr "pro některé netriviální příklady limit si můžete přečíst testovací soubor `test_demidovich.py `_" - -# 839cdd6f6dc246d381cf4ae32fe75973 -#: ../../src/tutorial.rst:343 -msgid "Differentiation" -msgstr "Derivace" - -# 8e81b82b9f6f44e1ab31a0eecf761366 -#: ../../src/tutorial.rst:345 -msgid "You can differentiate any SymPy expression using ``diff(func, var)``. Examples::" -msgstr "Můžete derivovat libovolný výraz v SymPy pomocí ``diff(func, var)``. Například::" - -# 351f72597cd9412b86c05ec2d2ad9dc7 -#: ../../src/tutorial.rst:358 -msgid "You can check, that it is correct by::" -msgstr "Výsledek si můžete zkontrolovat::" - -# cae093b9d4874e55af4aa3e86c9333a8 -#: ../../src/tutorial.rst:366 -msgid "Higher derivatives can be calculated using the ``diff(func, var, n)`` method::" -msgstr "Vyšší derivace můžete spočítat pomocí ``diff(func, var, n)``::" - -# 6798e5997ac849c5bfff0a0f32eb45a0 -#: ../../src/tutorial.rst:383 -msgid "Series expansion" -msgstr "Rozvoj v řady" - -# 6be2148c83b94a408dddc9fb92a20464 -#: ../../src/tutorial.rst:385 -msgid "Use ``.series(var, point, order)``::" -msgstr "Použijte ``.series(var, point, order)``::" - -# a563c2fe1ff84fee9b610aebf5c12392 -#: ../../src/tutorial.rst:400 -msgid "Another simple example::" -msgstr "Další jednoduchý příklad::" - -# 8af7fecfb1ca4c4993be2cce5b8f71cc -#: ../../src/tutorial.rst:420 -msgid "Integration" -msgstr "Integrály" - -# f81cf544a82f45fd9692fd3396982404 -#: ../../src/tutorial.rst:422 -msgid "SymPy has support for indefinite and definite integration of transcendental elementary and special functions via ``integrate()`` facility, which uses powerful extended Risch-Norman algorithm and some heuristics and pattern matching::" -msgstr "SymPy umí počítat neurčité a určité integrály elementárních a speciálních transcendentních funkcí pomocí fuknce ``integrate()``, která využívá silného rozšířeného Risch-Normanova algoritmu, některých heuristik a porovnávání vzorků::" - -# 3a1e02d1dd1c47afbb378ed9627a9a6e -#: ../../src/tutorial.rst:430 -msgid "You can integrate elementary functions::" -msgstr "Můžete integrovat elementární funkce::" - -# 5393cd6b23a1412897e45ad8728e211c -#: ../../src/tutorial.rst:443 -msgid "Also special functions are handled easily::" -msgstr "Také speciální funkce lze jednoduše integrovat::" - -# 6be3be4378614e3883fafdcf154a07e1 -#: ../../src/tutorial.rst:451 -#, fuzzy -msgid "It is possible to compute definite integrals::" -msgstr "Je možné vypočítat určitý integrál::" - -# 06c6ca9048d147f5a7b35ade18b3eb06 -#: ../../src/tutorial.rst:460 -#, fuzzy -msgid "Also, improper integrals are supported as well::" -msgstr "Podporovány jsou i nevlastní integrály::" - -# 06e8b87c46524596870768e0c1b70375 -#: ../../src/tutorial.rst:472 -msgid "Complex numbers" -msgstr "Komplexní čísla" - -# ebb5ccfc3a6a4bc0b815ccb8d1206864 -#: ../../src/tutorial.rst:474 -msgid "Besides the imaginary unit, I, which is imaginary, symbols can be created with attributes (e.g. real, positive, complex, etc...) and this will affect how they behave::" -msgstr "Kromě imaginárního čísla, I, symboly mohou být vytvořeny s atributy (například real, positive, complex, atd...), a to ovlivní jak se budou chovat:" - -# abb5f8441604412088acea01599d35ca -#: ../../src/tutorial.rst:491 -msgid "Functions" -msgstr "Funkce" - -# 45e5a176a38a4d6a817ba27ecbe21fb2 -#: ../../src/tutorial.rst:493 -msgid "**trigonometric**::" -msgstr "**trigonometrické**::" - -# fbfc937ac98f4b24976c97a9d186d8df -#: ../../src/tutorial.rst:542 -msgid "**spherical harmonics**::" -msgstr "**Sférické funkce**::" - -# 589cd74e37ba4bd999e3ad52111ccae0 -#: ../../src/tutorial.rst:568 -msgid "**factorials and gamma function**::" -msgstr "**Faktoriály a gamma funkce**::" - -# 53393f998d7d42148aca75cea7613c2e -#: ../../src/tutorial.rst:586 -msgid "**zeta function**::" -msgstr "**Zeta funkce**::" - -# 6e1ba3c25e1c495b86c474aec7febb89 -#: ../../src/tutorial.rst:611 -msgid "**polynomials**::" -msgstr "**Polynomy**::" - -# 1f1c9e26c1964efc871080bbdcf7ce25 -#: ../../src/tutorial.rst:650 -msgid "Differential Equations" -msgstr "Diferenciální rovnice" - -# 59b93c90e0674876927c83388979f2af -# cd9b7d592e2a4d7495e2fcdfca2396a2 -#: ../../src/tutorial.rst:652 -#: ../../src/tutorial.rst:672 -msgid "In ``isympy``::" -msgstr "V ``isympy``::" - -# 4cffa88d2f5a41ffad3ca85263be5cdc -#: ../../src/tutorial.rst:670 -msgid "Algebraic equations" -msgstr "Algebraické rovnice" - -# 31729299063d4327ba7ca7be58cbe527 -#: ../../src/tutorial.rst:685 -msgid "Linear Algebra" -msgstr "Lineární algebra" - -# cdd55a83a58849d8b269cf4510cca6d1 -#: ../../src/tutorial.rst:690 -msgid "Matrices" -msgstr "Matice" - -# 8257ad14575648b9a440a388e92e358a -#: ../../src/tutorial.rst:692 -msgid "Matrices are created as instances from the Matrix class::" -msgstr "Matice jsou vytvořeny jako instance třídy Matrix::" - -# b1ba9d6bc4dd4f04b169a9dce0c0d99c -#: ../../src/tutorial.rst:700 -#, fuzzy -msgid "They can also contain symbols::" -msgstr "Lze tam také vložit symboly::" - -# bfa056d84c964bdc9ee54b572767409c -#: ../../src/tutorial.rst:715 -#, fuzzy -msgid "For more about Matrices, see the Linear Algebra tutorial." -msgstr "Pro více informací a příkladů s maticemi se podívejte na Linear Algebra tutorial." - -# ce462773103a4863b167e3e262088ae9 -#: ../../src/tutorial.rst:720 -msgid "Pattern matching" -msgstr "Porovnávání vzorků" - -# a5d8f822d44c4096961c41b08cff6e14 -#: ../../src/tutorial.rst:722 -msgid "Use the ``.match()`` method, along with the ``Wild`` class, to perform pattern matching on expressions. The method will return a dictionary with the required substitutions, as follows::" -msgstr "Použijte metodu ``.match()`` spolu s třídou ``Wild`` pro porovnávání výrazů. Metoda vrátí slovník s požadovanými substitucemi, jako vidíme zde::" - -# 5f158aedb06b423db47571b42707a90e -#: ../../src/tutorial.rst:736 -msgid "If the match is unsuccessful, it returns ``None``::" -msgstr "Pokud je porovnání neúspěšné, vrátí ``None``::" - -# 94228299551d420ea0cf91f8fd4771b9 -#: ../../src/tutorial.rst:741 -msgid "One can also use the exclude parameter of the ``Wild`` class to ensure that certain things do not show up in the result::" -msgstr "Lze také použít parametr ``exclude`` třídy ``Wild``, aby se určité věci nezobrazily ve výsledku::" - -# c37af88a913f435981453293ccbb69e5 -#: ../../src/tutorial.rst:755 -msgid "Printing" -msgstr "Výpis" - -# 4a29361607f2475989e5138637b0073a -#: ../../src/tutorial.rst:757 -msgid "There are many ways to print expressions." -msgstr "Je spousta způsobů, jak mohou být výrazy vypisovány." - -# bfb32e3c79d843a2b8cbad8e5e3eb4b8 -#: ../../src/tutorial.rst:759 -msgid "**Standard**" -msgstr "**Standardní**" - -# 56356973c075448783d26e47c6a06064 -#: ../../src/tutorial.rst:761 -msgid "This is what ``str(expression)`` returns and it looks like this:" -msgstr "To je to, co vrátí ``str(expression)`` a vypadá to takto::" - -# f1b2fcd3f3414b6e91cab1f71b6a4e1a -#: ../../src/tutorial.rst:772 -msgid "**Pretty printing**" -msgstr "**Pěkný výpis**" - -# a0d1b3c10c144fa19f684a85fe622493 -#: ../../src/tutorial.rst:774 -#, fuzzy -msgid "Nice ascii-art printing is produced by the ``pprint`` function:" -msgstr "To je pěkný ascii-art výpis vytvořený funkcí ``pprint``::" - -# 9af477bd9adc4d09bf14defba6cdc2bf -#: ../../src/tutorial.rst:793 -#, fuzzy -msgid "If you have a unicode font installed, the ``pprint`` function will use it by default. You can override this using the ``use_unicode`` option.:" -msgstr "Pokud máte nainstalované písmo unicode, měla by ho funkce automaticky využívat. Využívání unicode písma se dá nastavit změnou ``use_unicode``::" - -# 84d8d1e95190474fb633112eaca07332 -#: ../../src/tutorial.rst:803 -msgid "See also the wiki `Pretty Printing `_ for more examples of a nice unicode printing." -msgstr "Pro více příkladů pěkného unicode výstupu koukněte na wiki na `Pretty Printing `_" - -# 919e23979e684267a33d1f30399957ed -#: ../../src/tutorial.rst:807 -#, fuzzy -msgid "Tip: To make pretty printing the default in the Python interpreter, use::" -msgstr "Tip: Pokud chcete v interpretru Pythonu pěkné vypisování používat defaultně, proveďte::" - -# 4e1d49f68b984ff3942a1ad1b4e98100 -#: ../../src/tutorial.rst:830 -msgid "**Python printing**" -msgstr "**Python výstup**::" - -# f8a8af14ba474b2fad3f553da2b898b6 -#: ../../src/tutorial.rst:846 -msgid "**LaTeX printing**" -msgstr "**LaTeX výstup**::" - -# ff5160027cfd45ad87915f270bf6b6cf -#: ../../src/tutorial.rst:863 -msgid "**MathML**" -msgstr "**MathML**::" - -# 43fb7c8304f145748db346289d43e36a -#: ../../src/tutorial.rst:875 -msgid "**Pyglet**" -msgstr "**Pyglet**::" - -# 64d1c80142fd4e29b7d0153b753423c1 -#: ../../src/tutorial.rst:881 -#, fuzzy -msgid "If pyglet is installed, a pyglet window will open containing the LaTeX rendered expression:" -msgstr "A vyskočí pyglet okno s výrazem formátovaným v LaTeXu:" - -# fa6c57fbfbaf42be8755edea03f65b33 -#: ../../src/tutorial.rst:887 -msgid "Notes" -msgstr "Poznámky" - -# abd59a7cd8f942e28c3a44694ab7a6e5 -#: ../../src/tutorial.rst:889 -msgid "``isympy`` calls ``pprint`` automatically, so that's why you see pretty printing by default." -msgstr "``isympy`` volá ``pprint`` automaticky, proto standardně vidíte pěkný výpis." - -# a55e545ba25141af9f6bd2df4b35f02c -#: ../../src/tutorial.rst:892 -msgid "Note that there is also a printing module available, ``sympy.printing``. Other printing methods available through this module are:" -msgstr "Všimněte si, že je přístupný modul pro výpisy, ``sympy.printing``. Další metody dostupné díky tomuto modulu jsou:" - -# e5329a0202044246a97cad451de550a0 -#: ../../src/tutorial.rst:895 -msgid "``pretty(expr)``, ``pretty_print(expr)``, ``pprint(expr)``: Return or print, respectively, a pretty representation of ``expr``. This is the same as the second level of representation described above." -msgstr "* ``pretty(expr)``, ``pretty_print(expr)``, ``pprint(expr)``: Vrací respektive vypisuje, pěknou reprezentaci ``expr``. Je to jako druhá úroveň reprezentace popsané výše." - -# 0bac12dbda6540028b304f4b655ae8e3 -#: ../../src/tutorial.rst:897 -msgid "``latex(expr)``, ``print_latex(expr)``: Return or print, respectively, a `LaTeX `_ representation of ``expr``" -msgstr "``latex(expr)``, ``print_latex(expr)``: Vrací, respektive vypisuje, `LaTeX `_ reprezentaci ``expr``" - -# 7ec29518a7074721824c874431d421b8 -#: ../../src/tutorial.rst:899 -msgid "``mathml(expr)``, ``print_mathml(expr)``: Return or print, respectively, a `MathML `_ representation of ``expr``." -msgstr " ``mathml(expr)``, ``print_mathml(expr)``: Vrací, respektive vypisuje, `MathML `_ reprezentaci ``expr``." - -# db586a15ee234c81a4fc8c2142a7f669 -#: ../../src/tutorial.rst:901 -msgid "``print_gtk(expr)``: Print ``expr`` to `Gtkmathview `_, a GTK widget that displays MathML code. The `Gtkmathview `_ program is required." -msgstr "``print_gtk(expr)``: Vypisuje ``expr`` do `Gtkmathview `_, GTK widgetu, který zobrazuje MathML kód. Je vyžadován program `Gtkmathview `_." - -# 45d07b3cdda546fdbd118b309704bd24 -#: ../../src/tutorial.rst:904 -msgid "Further documentation" -msgstr "Další dokumentace" - -# 0d07680d11e74714a5138cdb1428893d -#: ../../src/tutorial.rst:906 -msgid "Now it's time to learn more about SymPy. Go through the :ref:`SymPy User's Guide ` and :ref:`SymPy Modules Reference `." -msgstr "Nyní je čas dozvědět se více o SymPy. Pročtěte si :ref:`Uživatelskou příručku SymPy ` a :ref:`Přehled modulů SymPy `." - -# 0870c87ad84e4bab908444a6e3552d15 -#: ../../src/tutorial.rst:910 -#, fuzzy -msgid "Be sure to also browse our public `wiki.sympy.org `_, that contains a lot of useful examples, tutorials, cookbooks that we and our users contributed, and feel free to edit it." -msgstr "Také si projděte naší veřejnou `wiki.sympy.org `_, která obsahuje spoustu užitečných příkladů, tutoriálů a kuchařek, které jsme my a naši uživatelé dodali. A nebojte se je upravit." - -# 6c9599bc084b41a580831d5c3c597f64 -#: ../../src/tutorial.rst:915 -msgid "Translations" -msgstr "Překlady" - -# 806c97ff7b32477a876bd5374eb7f773 -#: ../../src/tutorial.rst:917 -msgid "This tutorial is also available in other languages:" -msgstr "Tento tutoriál je také k dispozici v těchto jazycích:" diff -Nru python3-sympy-0.7.2/doc/src/tutorial.de.po python3-sympy-0.7.3/doc/src/tutorial.de.po --- python3-sympy-0.7.2/doc/src/tutorial.de.po 2012-10-17 02:30:33.000000000 +0000 +++ python3-sympy-0.7.3/doc/src/tutorial.de.po 1970-01-01 00:00:00.000000000 +0000 @@ -1,736 +0,0 @@ -# German translation of the SymPy tutorial. -# Copyright (C) 2008, 2009, 2010, 2011, 2012 SymPy Development Team -# This file is distributed under the same license as the SymPy package. -# FIRST AUTHOR , YEAR. -# -#, fuzzy -msgid "" -msgstr "" -"Project-Id-Version: SymPy 0.7.2\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2012-08-14 15:40\n" -"PO-Revision-Date: 2012-08-14 16:34\n" -"Last-Translator: Julien Rioux \n" -"Language-Team: LANGUAGE \n" -"Language: German\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" - -# f413543562494227af1eff43dd1e7c7d -#: ../../src/tutorial.rst:5 -msgid "Tutorial" -msgstr "Tutorial" - -# 5f6658bde5114381abf64a131551f93a -#: ../../src/tutorial.rst:10 -msgid "Introduction" -msgstr "Einführung" - -# 06efddbd4299471c988e3650ad88c342 -#: ../../src/tutorial.rst:12 -msgid "" -"SymPy is a Python library for symbolic mathematics. It aims to become a full-" -"featured computer algebra system (CAS) while keeping the code as simple as " -"possible in order to be comprehensible and easily extensible. SymPy is " -"written entirely in Python and does not require any external libraries." -msgstr "" -"SymPy ist eine Python-Bibliothek für symbolische Mathematik. SymPy soll ein " -"vollständiges Computer-Algebra-System (CAS) bereitstellen und dabei den " -"Programmcode so einfach halten, dass er nachvollziehbar und einfach " -"erweiterbar bleibt. SymPy ist vollständig in Python geschrieben und benötigt " -"keine weiteren Bibliotheken." - -# 4324b1f1974940dfa583777e8dc183e7 -#: ../../src/tutorial.rst:17 -msgid "" -"This tutorial gives an overview and introduction to SymPy. Read this to have " -"an idea what SymPy can do for you (and how) and if you want to know more, " -"read the :ref:`SymPy User's Guide `, :ref:`SymPy Modules Reference " -"`. or the `sources `_ directly." -msgstr "" -"Dieses Tutorial schafft einen Überblick und gibt eine Einführung in SymPy. " -"Wenn du wissen möchtest, was SymPy tun kann (und wie), lies diese Seite, und " -"wenn du mehr erfahren möchtest, lies den :ref:`SymPy User's Guide ` " -"und die :ref:`SymPy Modules Reference ` oder den `Quellcode " -"`_ selbst." - -# e57f318c6c3a484fb70853437be20750 -#: ../../src/tutorial.rst:26 -msgid "First Steps with SymPy" -msgstr "Erste Schritte mit SymPy" - -# 9f3783296da548f2ba6fc7be2e2fc360 -#: ../../src/tutorial.rst:28 -msgid "" -"The easiest way to download it is to go to http://code.google.com/p/sympy/ " -"and download the latest tarball from the Featured Downloads:" -msgstr "" -"Am einfachsten kannst du SymPy mit der aktuellsten .tar-Datei aus den " -"\"Featured Downloads\" von http://code.google.com/p/sympy/ installieren:" - -# 8aaea46c5cab40c2846da068570f89db -#: ../../src/tutorial.rst:34 -msgid "Unpack it:" -msgstr "Dann musst du die Datei auspacken:" - -# 684468dc7ac14299b9cc0948f319244f -#: ../../src/tutorial.rst:40 -msgid "and try it from a Python interpreter:" -msgstr "und kannst sie mit einem Python-Interpreter ausprobieren." - -# 437db7bdc2d24e10af24c9524f711390 -#: ../../src/tutorial.rst:54 -msgid "" -"You can use SymPy as shown above and this is indeed the recommended way if " -"you use it in your program. You can also install it using ``./setup.py " -"install`` as any other Python module, or just install a package in your " -"favourite Linux distribution, e.g.:" -msgstr "" -"SymPy kann wie im Beispiel gezeigt benutzt werden, und dies ist auch der " -"übliche Weg, es von einem anderen Programm aus zu verwenden. Du kannst es " -"ebenfalls wie jedes andere Modul mithilfe von ``./setup.py install`` " -"installieren. Auch ist es natürlich möglich, einfach ein Paket deiner Linux-" -"Distribution zu verwenden, zum Beispiel:" - -# 9b0616ba38144ef9b615c67aaaba823a -#: ../../src/tutorial.rst:80 -msgid "" -"For other means how to install SymPy, consult the Downloads_ tab on the " -"SymPy's webpage." -msgstr "" -"Weitere Installationsmöglichkeiten findest du unter Downloads_ auf der SymPy-" -"Website." - -# 8277e332c6ee40caab7bf4039138683b -#: ../../src/tutorial.rst:87 -msgid "isympy Console" -msgstr "isympy-Konsole" - -# 5fe7056ee7df4023b2133b3fb7f4f61f -#: ../../src/tutorial.rst:89 -msgid "" -"For experimenting with new features, or when figuring out how to do things, " -"you can use our special wrapper around IPython called ``isympy`` (located in " -"``bin/isympy`` if you are running from the source directory) which is just a " -"standard Python shell that has already imported the relevant SymPy modules " -"and defined the symbols x, y, z and some other things:" -msgstr "" -"Für Experimente mit neuen Funktionen und zum Ausprobieren kann die um " -"IPython aufgebaute Umgebung namens ``isympy`` (im Quellverzeichnis unter " -"``bin/isympy``) benutzt werden. Es handelt sich hierbei nur um eine Standard-" -"Python-Konsole, die allerdings bereits die wichtigen sympy-Module importiert " -"hat und unter anderem die Symbole x, y und z bereits definiert hat:" - -# 03438a87fddb4870912813c3708f29c6 -#: ../../src/tutorial.rst:119 -msgid "" -"Commands entered by you are bold. Thus what we did in 3 lines in a regular " -"Python interpreter can be done in 1 line in isympy." -msgstr "" -"Benutzereingaben sind fett dargestellt. Was in einem normalen Python-" -"Interpreter drei Zeilen gebraucht hätte, kann mit isympy in nur einer Zeile " -"ausgedrückt werden." - -# 4b7297a6c1c147978177663678dfcd13 -#: ../../src/tutorial.rst:124 -msgid "Using SymPy as a calculator" -msgstr "Mit SymPy rechnen" - -# 742184bea7ca4c07ac36ddd5300a143c -#: ../../src/tutorial.rst:126 -msgid "SymPy has three built-in numeric types: Float, Rational and Integer." -msgstr "SymPy hat drei eingebaute Zahlentypen: Float, Rational und Integer." - -# ad2dfa5242fe4f408791f5314f73c738 -#: ../../src/tutorial.rst:128 -msgid "" -"The Rational class represents a rational number as a pair of two Integers: " -"the numerator and the denominator. So Rational(1,2) represents 1/2, Rational" -"(5,2) represents 5/2, and so on." -msgstr "" -"Die Klasse Rational stellt eine rationale Zahl als Paar von zwei Ganzzahlen " -"dar: dem Zähler und dem Nenner. Rational(1,2) repräsentiert also 1/2, " -"Rational(5,2) repräsentiert 5/2 und so weiter." - -# ac24030c574349d6b20bf4283e9e79aa -#: ../../src/tutorial.rst:147 -msgid "" -"Proceed with caution while working with Python int's and floating point " -"numbers, especially in division, since you may create a Python number, not a " -"SymPy number. A ratio of two Python ints may create a float -- the \"true " -"division\" standard of Python 3 and the default behavior of ``isympy`` which " -"imports division from __future__::" -msgstr "" -"Beim Arbeiten mit Pythons Ganzzahlen und Fließkommazahlen ist Vorsicht " -"geboten, besonders bei Division, da eine Python-Zahl statt einer SymPy-Zahl " -"das Ergebnis sein kann. Eine Division von zwei Python-Ganzzahlen hat eine " -"Fließkommazahl zum Ergebnis -- die \"echte Divison\" von Python 3 und das " -"Standardverhalten von ``isympy``, welches division aus __future__ " -"importiert::" - -# 98c505d37ae4430e918958b518353cc3 -#: ../../src/tutorial.rst:157 -msgid "" -"But in earlier Python versions where division has not been imported, a " -"truncated int will result::" -msgstr "" -"In älteren Python-Versionen ohne den Import von division ist das Ergebnis " -"hingegen eine abgerundete Ganzzahl::" - -# e0548fd7c4384933b5e5a8a09d371a99 -#: ../../src/tutorial.rst:163 -msgid "" -"In both cases, however, you are not dealing with a SymPy Number because " -"Python created its own number. Most of the time you will probably be working " -"with Rational numbers, so make sure to use Rational to get the SymPy result. " -"One might find it convenient to equate ``R`` and Rational::" -msgstr "" -"In beiden Fällen handelt es sich jedoch nicht um eine SymPy-Zahl, weil " -"Python seine eigenen Zahl zurückgegeben hat. Meistens wirst du aber mit " -"Zahlen des Typs Rational arbeiten wollen, also achte darauf, auch solche zu " -"erhalten. Oft wird zur besseren Lesbarkeit ``R`` mit Rational gleichgesetzt::" - -# 22d7232d350f4daa9526bb1dacf7ab22 -#: ../../src/tutorial.rst:175 -msgid "" -"We also have some special constants, like e and pi, that are treated as " -"symbols (1+pi won't evaluate to something numeric, rather it will remain as " -"1+pi), and have arbitrary precision::" -msgstr "" -"Es gibt auch einige spezielle Konstanten wie e oder pi, die als Symbole " -"behandelt werden (1+pi wird nicht als Zahl ausgerechnet, sondern bleibt " -"1+pi) und in beliebiger Präzision verfügbar sind::" - -# 799352ade72a451783b961d71c28f1b8 -#: ../../src/tutorial.rst:189 -msgid "as you see, evalf evaluates the expression to a floating-point number" -msgstr "Wie man sieht, berechnet evalf aus dem Ausdruck eine Fließkommazahl." - -# b89488f1885644998aa24f202f630219 -#: ../../src/tutorial.rst:191 -msgid "The symbol ``oo`` is used for a class defining mathematical infinity::" -msgstr "" -"Das Symnol ``oo`` wird für eine Klasse benutzt, die mathematische " -"Unendlichkeit darstellt::" - -# f5628260a39641689f6e622d9631086b -#: ../../src/tutorial.rst:200 -msgid "Symbols" -msgstr "Symbole" - -# b7ed502498cd4b33a852e53637ee1de8 -#: ../../src/tutorial.rst:202 -msgid "" -"In contrast to other Computer Algebra Systems, in SymPy you have to declare " -"symbolic variables explicitly::" -msgstr "" -"Im Gegensatz zu anderen Computer-Algebra-Systemen müssen in SymPy " -"symbolische Variablen ausdrücklich deklariert werden::" - -# 1650cf4e732d4a0a8dc12de22825e100 -#: ../../src/tutorial.rst:209 -msgid "" -"On the left is the normal Python variable which has been assigned to the " -"SymPy Symbol class. Predefined symbols (including those for symbols with " -"Greek names) are available for import from abc:" -msgstr "" -"Links steht eine normale Python-Variable, der ein SymPy-Symbol-Objekt " -"zugewiesen wird. Vordefiniert Symbole (inklusiv Symbole mit griechischen " -"Namen) sind von Import von abc verfügbar:" - -# 9e73a43103bd492b8197e5811f6cf2a1 -#: ../../src/tutorial.rst:215 -msgid "" -"Symbols can also be created with the ``symbols`` or ``var`` functions, the " -"latter automatically adding the created symbols to the namespace, and both " -"accepting a range notation:" -msgstr "" -"Symbole können auch mit den ``symbols`` oder ``var`` Funktionen erstellt " -"werden. Die letztere fügt automatisch die Symbole in den Namespace ein, und " -"beide Funktionen akzeptieren eine Reihennotation::" - -# d7906003f80b41d4b2bdc54881522fff -#: ../../src/tutorial.rst:227 -msgid "" -"Instances of the Symbol class \"play well together\" and are the building " -"blocks of expresions::" -msgstr "Aus Symbol-Objekten kann man bequem Ausdrücke zusammensetzen::" - -# 1b12f717d1bd4548a348160aaa4128f6 -#: ../../src/tutorial.rst:239 -msgid "" -"They can be substituted with other numbers, symbols or expressions using " -"``subs(old, new)``::" -msgstr "" -"Sie können mit ``subs(old, new)`` durch Zahlen, andere Symbole oder " -"Ausdrücke ersetzt werden::" - -# d4af7b2be68049f4a6ec9bab6f63bf14 -#: ../../src/tutorial.rst:250 -msgid "For the remainder of the tutorial, we assume that we have run::" -msgstr "" -"Für den Rest des Tutorials gehen wir davon aus, dass folgende Zeile " -"ausgeführt wurde::" - -# 551a3dcd3cc1407b8da6b081ab13224b -#: ../../src/tutorial.rst:255 -msgid "" -"This will make things look better when printed. See the :ref:`printing-" -"tutorial` section below. If you have a unicode font installed, you can pass " -"use_unicode=True for a slightly nicer output." -msgstr "" -"Dies sorgt dafür, dass Ausdrücke bei der Ausgabe besser aussehen (siehe :ref:" -"`printing-tutorial` weiter unten). Wenn eine Unicode-Schrift installiert " -"ist, erreichst du mit use_unicode=True eine noch hübschere Ausgabe." - -# 2931f150f0af4eb591917e425845178b -#: ../../src/tutorial.rst:260 -msgid "Algebra" -msgstr "Algebra" - -# 090610dcc96743a380ba0d56f15ed4fc -#: ../../src/tutorial.rst:262 -msgid "For partial fraction decomposition, use ``apart(expr, x)``::" -msgstr "Für die Partialbruchzerlegung kannst du ``apart(expr, x)`` benutzen::" - -# e08b738c22a94aed923a394dc938a6c7 -#: ../../src/tutorial.rst:287 -msgid "To combine things back together, use ``together(expr, x)``::" -msgstr "Zum Kombinieren gibt es die Funktion ``together(expr, x)``::" - -# 13b889d5d36d4ea48f6385b298891158 -#: ../../src/tutorial.rst:309 -msgid "Calculus" -msgstr "Infinitesimalrechnung" - -# b484a8d9c1ff430b80d943f93b71df6b -#: ../../src/tutorial.rst:314 -msgid "Limits" -msgstr "Limes" - -# 05cec7dcf5154fa085a6c7cf642c6e4f -#: ../../src/tutorial.rst:316 -msgid "" -"Limits are easy to use in SymPy, they follow the syntax ``limit(function, " -"variable, point)``, so to compute the limit of f(x) as x -> 0, you would " -"issue ``limit(f, x, 0)``::" -msgstr "" -"Grenzwerte sind in SymPy einfach zu benutzen, sie folgen der Syntax ``limit" -"(function, variable, point)``, um also den Grenzwert von f(x) bei x -> 0 zu " -"berechnen, kann ``limit(f, x, 0)`` benutzt werden::" - -# fda895b0428240849fd4237ebf0d51e0 -#: ../../src/tutorial.rst:325 -msgid "you can also calculate the limit at infinity::" -msgstr "Analog kann der Limes für x gegen unendlich berechnet werden::" - -# d65187df78b445f28943b5f7282afdee -#: ../../src/tutorial.rst:336 -msgid "" -"for some non-trivial examples on limits, you can read the test file " -"`test_demidovich.py `_" -msgstr "" -"Einige nicht-triviale Beispiele zu Grenzwerten finden sich in der Datei " -"`test_demidovich.py `_" - -# 1e6632c1af2842b1a3dee9e9dd33b5ea -#: ../../src/tutorial.rst:343 -msgid "Differentiation" -msgstr "Differentialrechnung" - -# fb2ece7143a9455c8435eb443f21face -#: ../../src/tutorial.rst:345 -msgid "" -"You can differentiate any SymPy expression using ``diff(func, var)``. " -"Examples::" -msgstr "" -"Mithilfe von ``diff(func, var)`` kann jeder SymPy-Ausdruck differenziert " -"werden. Beispiele::" - -# 25db4dec4f194c00a4601a5587694b96 -#: ../../src/tutorial.rst:358 -msgid "You can check, that it is correct by::" -msgstr "Folgendermaßen kann überprüft werden, ob dies korrekt ist::" - -# 5090dcf5d46e4977b813bff62ae1b963 -#: ../../src/tutorial.rst:366 -msgid "" -"Higher derivatives can be calculated using the ``diff(func, var, n)`` " -"method::" -msgstr "" -"Höhere Ableitungen können mithilfe von ``diff(func, var, n)`` berechnet " -"werden::" - -# 3c1654763acd40cf9eaa510b205cc6e6 -#: ../../src/tutorial.rst:383 -msgid "Series expansion" -msgstr "Reihenentwicklung" - -# 3cf60b99ba92466f8017465afefb2f9a -#: ../../src/tutorial.rst:385 -msgid "Use ``.series(var, point, order)``::" -msgstr "Benutze ``.series(var, point, order)``::" - -# 6083784f687d452080584ad981c166a6 -#: ../../src/tutorial.rst:400 -msgid "Another simple example::" -msgstr "Ein weiteres einfaches Beispiel::" - -# 588350b07e8946c3990190b5e03eeb79 -#: ../../src/tutorial.rst:424 -msgid "Summation" -msgstr "" - -# c8e0a258ce834d868419e0aed64142e9 -#: ../../src/tutorial.rst:426 -msgid "" -"Compute the summation of f with respect to the given summation variable over " -"the given limits." -msgstr "" - -# 8399e19ad841458d9a517e24cd647081 -#: ../../src/tutorial.rst:428 -msgid "" -"summation(f, (i, a, b)) computes the sum of f with respect to i from a to b, " -"i.e., ::" -msgstr "" - -# 2257b464c29d4d7f8fad17e106053f41 -#: ../../src/tutorial.rst:439 -msgid "" -"If it cannot compute the sum, it prints the corresponding summation formula. " -"Repeated sums can be computed by introducing additional limits::" -msgstr "" - -# aaff4f408c9849ee882b4cbf33de4bf8 -#: ../../src/tutorial.rst:473 -msgid "Integration" -msgstr "Integralrechnung" - -# 4e9281ff225c4a11abbb06925642518d -#: ../../src/tutorial.rst:475 -msgid "" -"SymPy has support for indefinite and definite integration of transcendental " -"elementary and special functions via ``integrate()`` facility, which uses " -"powerful extended Risch-Norman algorithm and some heuristics and pattern " -"matching::" -msgstr "" -"SymPy unterstützt unendliche und endliche Integration transzendenter " -"elementarer und spezieller Funktionen durch ``integrate()``, welches den " -"starken Risch-Norman-Algorithmus nutzt, sowie einige Heuristiken und " -"Mustererkennungen::" - -# ca7de1d72bab4e708e93e63312d37d4a -#: ../../src/tutorial.rst:483 -msgid "You can integrate elementary functions::" -msgstr "Es können elementare Funktionen integriert werden::" - -# 783f61d68127448aa8f03645b2ca287f -#: ../../src/tutorial.rst:496 -msgid "Also special functions are handled easily::" -msgstr "Aber auch mit speziellen Funktionen kann einfach umgegangen werden::" - -# 4628465fbda24a84a2a9fe396c917ec6 -#: ../../src/tutorial.rst:504 -msgid "It is possible to compute definite integrals::" -msgstr "Es ist möglich, ein endliches Integral zu berechnen::" - -# a296ca47294e4b2893c5ecb36c4d95a2 -#: ../../src/tutorial.rst:513 -msgid "Also, improper integrals are supported as well::" -msgstr "Auch uneigentliche Integrale werden unterstützt::" - -# 5527da04c3b44ea2bd26ebd8b62e80ff -#: ../../src/tutorial.rst:525 -msgid "Complex numbers" -msgstr "Komplexe Zahlen" - -# e2cad55f8d6d4de4867830a348f8cd3d -#: ../../src/tutorial.rst:527 -msgid "" -"Besides the imaginary unit, I, which is imaginary, symbols can be created " -"with attributes (e.g. real, positive, complex, etc...) and this will affect " -"how they behave::" -msgstr "" -"Mit Ausnahme der imaginären Einheit, I, die rein imaginär ist, können " -"Symbole mit Attributen (z.B. reale, positive, komplex, usw.) erstellt " -"werden, und dies hat Auswirkungen darauf, wie sie sich verhalten::" - -# 2405633b0a3d4f8daeacc7dfd74789c3 -#: ../../src/tutorial.rst:544 -msgid "Functions" -msgstr "Funktionen" - -# a477e26c595743a9bd52779771d88d52 -#: ../../src/tutorial.rst:546 -msgid "**trigonometric**::" -msgstr "**trigonometrische**::" - -# 713271ca436545c38c11e81cc492445a -#: ../../src/tutorial.rst:595 -msgid "**spherical harmonics**::" -msgstr "**Kugelflächen**::" - -# b357f38a95984af8a4a13abbff4193ac -#: ../../src/tutorial.rst:621 -msgid "**factorials and gamma function**::" -msgstr "**Fakultät und Gamma-Funktion**::" - -# 9a927f1633f14851afc8b473085c0691 -#: ../../src/tutorial.rst:639 -msgid "**zeta function**::" -msgstr "**Zeta-Funktion**::" - -# 77a6d46c531f41258b589014b7fefdae -#: ../../src/tutorial.rst:664 -msgid "**polynomials**::" -msgstr "**Polynome**::" - -# 1b26ea47461141dbb9ea27df8afe89b2 -#: ../../src/tutorial.rst:703 -msgid "Differential Equations" -msgstr "Differenzialgleichungen" - -# 3c963d8ae9334bcba385e3d567cbba43 -# 7f9d1d2ba0864e50b4893775f248e848 -#: ../../src/tutorial.rst:705 ../../src/tutorial.rst:725 -msgid "In ``isympy``::" -msgstr "In ``isympy``::" - -# a3b84a6909fd44868fbe615bc40a66b6 -#: ../../src/tutorial.rst:723 -msgid "Algebraic equations" -msgstr "Algebraische Gleichungen" - -# ec163a7bc9f94d50b3bc6dd397d96e3a -#: ../../src/tutorial.rst:738 -msgid "Linear Algebra" -msgstr "Lineare Algebra" - -# e3beeac51dfe44d3bc63b1c391970a10 -#: ../../src/tutorial.rst:743 -msgid "Matrices" -msgstr "Matrizen" - -# 9fea3d6ff5d446b797c77febe52b151d -#: ../../src/tutorial.rst:745 -msgid "Matrices are created as instances from the Matrix class::" -msgstr "Matrizen werden als Instanzen der Matrix-Klasse erzeugt::" - -# f1c6898ba3d94b4a88a1db2de6d13f36 -#: ../../src/tutorial.rst:753 -msgid "They can also contain symbols::" -msgstr "Sie können auch Symbole enthalten::" - -# b4ceb45395554cc883e9200f37658b48 -#: ../../src/tutorial.rst:768 -msgid "For more about Matrices, see the Linear Algebra tutorial." -msgstr "" -"Mehr Informationen und Beispiele zu Matrizen finden sich im " -"LinearAlgebraTutorial." - -# 059567c3bd064380bcda09bda8c5e796 -#: ../../src/tutorial.rst:773 -msgid "Pattern matching" -msgstr "Musterabgleich" - -# 39dff4f6d6074d86abfd69b34cb73e9f -#: ../../src/tutorial.rst:775 -msgid "" -"Use the ``.match()`` method, along with the ``Wild`` class, to perform " -"pattern matching on expressions. The method will return a dictionary with " -"the required substitutions, as follows::" -msgstr "" -"Die Methode ``.match()`` kann gemeinsam mit der Klasse ``Wild`` Ausdrücke " -"auf Muster überprüfen. Die Methode gibt ein dictionary mit den nötigen " -"Ersetzungen zurück, wie im folgenden Beispiel ersichtlich::" - -# 72986769580b4b0494b7ec50975be8f8 -#: ../../src/tutorial.rst:789 -msgid "If the match is unsuccessful, it returns ``None``::" -msgstr "Wenn der Musterabgleich fehlschlägt, wird ``None`` zurückgegeben::" - -# d3234a9c8eaa4ca3a243bcf26bfa49e2 -#: ../../src/tutorial.rst:794 -msgid "" -"One can also use the exclude parameter of the ``Wild`` class to ensure that " -"certain things do not show up in the result::" -msgstr "" -"Über den Parameter ``exclude`` kann man manches aus dem Ergebnis " -"ausschließen:" - -# cb5e1c06b49a479db6cb4c95860737c6 -#: ../../src/tutorial.rst:808 -msgid "Printing" -msgstr "Ausgabe" - -# 931a09a841b64b1eace424825fbd10ea -#: ../../src/tutorial.rst:810 -msgid "There are many ways to print expressions." -msgstr "Es existieren mehrere Wege, Ausdrücke auszugeben:" - -# dee601b28cdd4d5d9d24d3499cca3412 -#: ../../src/tutorial.rst:812 -msgid "**Standard**" -msgstr "**Standard**" - -# e8250adf42ef448784c10eaf643d349a -#: ../../src/tutorial.rst:814 -msgid "This is what ``str(expression)`` returns and it looks like this:" -msgstr "Dies ist die Ausgabe von ``str(expression)`` und sieht so aus:" - -# 70fa277ddedc4a3d89a2f68a03da2e20 -#: ../../src/tutorial.rst:825 -msgid "**Pretty printing**" -msgstr "**ASCII-Art-Ausgabe**" - -# 642cb14321b04ccb9979ce76f9be5e49 -#: ../../src/tutorial.rst:827 -msgid "Nice ascii-art printing is produced by the ``pprint`` function:" -msgstr "Eine ``pprint``-Funktion erzeugt diese hübschere ASCII-Art-Ausgabe." - -# e1cf51783fad4dbaaad3f188d0234c76 -#: ../../src/tutorial.rst:846 -msgid "" -"If you have a unicode font installed, the ``pprint`` function will use it by " -"default. You can override this using the ``use_unicode`` option.:" -msgstr "" -"Wenn eine Unicode-Schriftart installiert ist, sollte die ASCII-Art-Ausgabe " -"standardmäßig die Unicode-Fassung verwenden. Dies kann mit dem Parameter " -"``use_unicode`` erzwungen oder abgeschaltet werden." - -# 3e6640ed96344911b74cc14133039a32 -#: ../../src/tutorial.rst:856 -msgid "" -"See also the wiki `Pretty Printing `_ for more examples of a nice unicode printing." -msgstr "" -"Siehe auch die Wiki-Seite `Pretty Printing `_ für mehr Beispiele von hübschen Unicode-Ausgaben." - -# 3626c95b8c19421b970519910d82a516 -#: ../../src/tutorial.rst:860 -msgid "" -"Tip: To make pretty printing the default in the Python interpreter, use::" -msgstr "" -"Tipp: Die ASCII-Art-Ausgabe kann auch als Standard-Methode gesetzt werden::" - -# 88cd228b579a41a2948c969485db2159 -#: ../../src/tutorial.rst:883 -msgid "**Python printing**" -msgstr "**Python-Ausgabe**" - -# 1507bc52525044a9b77f2030e0d9192a -#: ../../src/tutorial.rst:899 -msgid "**LaTeX printing**" -msgstr "**LaTeX-Ausgabe**" - -# bc262344feb148dfb85d0d9b3b6e2413 -#: ../../src/tutorial.rst:916 -msgid "**MathML**" -msgstr "**MathML**" - -# bc23b29ef4bd421daeacc48cae39dd91 -#: ../../src/tutorial.rst:928 -msgid "**Pyglet**" -msgstr "**Pyglet**" - -# cc8f3cf1777b47c8a068175389731eca -#: ../../src/tutorial.rst:934 -msgid "" -"If pyglet is installed, a pyglet window will open containing the LaTeX " -"rendered expression:" -msgstr "" -"Dies öffnet ein pyglet-Fenster mit dem in LaTeX gerenderten Ausdruck, wenn " -"pyglet installiert ist:" - -# ae6458b8c65e4a139ea61a379b996b25 -#: ../../src/tutorial.rst:940 -msgid "Notes" -msgstr "Hinweise" - -# eb6f6032d7604f9a8f930ddfeaae76f7 -#: ../../src/tutorial.rst:942 -msgid "" -"``isympy`` calls ``pprint`` automatically, so that's why you see pretty " -"printing by default." -msgstr "" -"``isympy`` ruft ``pprint`` automatisch auf -- deswegen sind die Ausgaben " -"standardmäßig hübsch." - -# bdb9bb73185c42efba466c71e1210fe4 -#: ../../src/tutorial.rst:945 -msgid "" -"Note that there is also a printing module available, ``sympy.printing``. " -"Other printing methods available through this module are:" -msgstr "" -"Es ist gibt auch ein Ausgabemodul ``sympy.printing``. Andere " -"Ausgabemethoden, die durch dieses Modul erreichbar sind:" - -# 1ae3f6f86ebe4e8aaf0eab6fdf43c4a1 -#: ../../src/tutorial.rst:948 -msgid "" -"``pretty(expr)``, ``pretty_print(expr)``, ``pprint(expr)``: Return or print, " -"respectively, a pretty representation of ``expr``. This is the same as the " -"second level of representation described above." -msgstr "" - -# fbf4bfb9e8564948a214b22238ce9fea -#: ../../src/tutorial.rst:950 -msgid "" -"``latex(expr)``, ``print_latex(expr)``: Return or print, respectively, a " -"`LaTeX `_ representation of ``expr``" -msgstr "" - -# 31d0fdf12b474cb5951481fc4aa00384 -#: ../../src/tutorial.rst:952 -msgid "" -"``mathml(expr)``, ``print_mathml(expr)``: Return or print, respectively, a " -"`MathML `_ representation of ``expr``." -msgstr "" - -# cd4fb7f145674e4eb598d187f2fc4560 -#: ../../src/tutorial.rst:954 -msgid "" -"``print_gtk(expr)``: Print ``expr`` to `Gtkmathview `_, a GTK widget that displays MathML code. The `Gtkmathview " -"`_ program is required." -msgstr "" - -# 06fd925e5bbd4337b0114cf718495460 -#: ../../src/tutorial.rst:957 -msgid "Further documentation" -msgstr "Weitere Dokumentation" - -# 459fd254b75a44199328f139cc225618 -#: ../../src/tutorial.rst:959 -msgid "" -"Now it's time to learn more about SymPy. Go through the :ref:`SymPy User's " -"Guide ` and :ref:`SymPy Modules Reference `." -msgstr "" -"Nun ist Zeit, mehr über SymPy zu lernen. Lies den :ref:`SymPy User's Guide " -"` und die :ref:`SymPy Modules Reference `." - -# 4ea89c31131649d5b6ccd4c13d3f4b31 -#: ../../src/tutorial.rst:963 -msgid "" -"Be sure to also browse our public `wiki.sympy.org `_, that contains a lot of useful examples, tutorials, cookbooks that we " -"and our users contributed, and feel free to edit it." -msgstr "" -"Unser öffentliches Wiki unter `wiki.sympy.org `_, " -"enthält einen Haufen nützlicher Beispiele und Anleitungen von uns und " -"unseren Nutzern. (Fühle dich frei, dazu beizutragen und Dinge zu verändern!)" - -# 71565efaecaf4a82a0be16754fa44fd9 -#: ../../src/tutorial.rst:968 -msgid "Translations" -msgstr "" - -# 35b1c1d66f4848cea486864587fe383c -#: ../../src/tutorial.rst:970 -msgid "This tutorial is also available in other languages:" -msgstr "" diff -Nru python3-sympy-0.7.2/doc/src/tutorial.fr.po python3-sympy-0.7.3/doc/src/tutorial.fr.po --- python3-sympy-0.7.2/doc/src/tutorial.fr.po 2012-10-17 02:30:33.000000000 +0000 +++ python3-sympy-0.7.3/doc/src/tutorial.fr.po 1970-01-01 00:00:00.000000000 +0000 @@ -1,772 +0,0 @@ -# French translation of the SymPy tutorial -# Copyright (C) 2008, 2009, 2010, 2011, 2012 SymPy Development Team -# This file is distributed under the same license as the SymPy package. -# FIRST AUTHOR , YEAR. -# -#, fuzzy -msgid "" -msgstr "" -"Project-Id-Version: SymPy 0.7.2\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2012-08-14 15:40\n" -"PO-Revision-Date: 2012-08-14 16:13\n" -"Last-Translator: Julien Rioux \n" -"Language-Team: LANGUAGE \n" -"Language: French\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" - -# 352299718af54a5bb6f164a8b88dec0b -#: ../../src/tutorial.rst:5 -msgid "Tutorial" -msgstr "Tutoriel" - -# 8277a71aebfe42c58d1394cd94314a58 -#: ../../src/tutorial.rst:10 -msgid "Introduction" -msgstr "Introduction" - -# d8faf63257d5468d9c8d9dced4206378 -#: ../../src/tutorial.rst:12 -msgid "" -"SymPy is a Python library for symbolic mathematics. It aims to become a full-" -"featured computer algebra system (CAS) while keeping the code as simple as " -"possible in order to be comprehensible and easily extensible. SymPy is " -"written entirely in Python and does not require any external libraries." -msgstr "" -"SymPy est une bibliothèque Python pour les mathématiques symboliques. SymPy " -"prévoit devenir un système complet de calcul formel (\"CAS\" en anglais : " -"\"Computer Algebra System\") tout en gardant le code aussi simple que " -"possible afin qu'il soit compréhensible et facilement extensible. SymPy est " -"entièrement écrit en Python et ne nécessite aucune bibliothèque externe." - -# 45cf39acac1747a49ce17123af564744 -#: ../../src/tutorial.rst:17 -msgid "" -"This tutorial gives an overview and introduction to SymPy. Read this to have " -"an idea what SymPy can do for you (and how) and if you want to know more, " -"read the :ref:`SymPy User's Guide `, :ref:`SymPy Modules Reference " -"`. or the `sources `_ directly." -msgstr "" -"Ce tutoriel donne un aperçu et une introduction à SymPy. Lisez-le pour vous " -"faire une idée de ce que SymPy peut faire pour vous (et comment). Pour en " -"savoir plus, consultez également le :ref:`SymPy User's Guide `, la :" -"ref:`SymPy Modules Reference `, ou le `code source `_ directement." - -# 2c2c93f21b5e4209b7f92cbed2b8a8ba -#: ../../src/tutorial.rst:26 -msgid "First Steps with SymPy" -msgstr "Premiers pas avec SymPy" - -# 8d06c75f00824058ad7889f489ce31b0 -#: ../../src/tutorial.rst:28 -msgid "" -"The easiest way to download it is to go to http://code.google.com/p/sympy/ " -"and download the latest tarball from the Featured Downloads:" -msgstr "" -"La façon la plus simple de télécharger SymPy est de se rendre sur http://" -"code.google.com/p/sympy/ et de télécharger la dernière archive des " -"Téléchargements Recommandés (\"Featured Downloads\" en anglais)." - -# e2c5a69b15464b52b23c0a5bd6862b8a -#: ../../src/tutorial.rst:34 -msgid "Unpack it:" -msgstr "Décompressez-la :" - -# 13fa0617b2654f0fb6e131cf38116f2d -#: ../../src/tutorial.rst:40 -msgid "and try it from a Python interpreter:" -msgstr "et essayez-la dans un interpréteur Python :" - -# c3f5425214764a8694cfce3941b02aa6 -#: ../../src/tutorial.rst:54 -msgid "" -"You can use SymPy as shown above and this is indeed the recommended way if " -"you use it in your program. You can also install it using ``./setup.py " -"install`` as any other Python module, or just install a package in your " -"favourite Linux distribution, e.g.:" -msgstr "" -"Vous pouvez utiliser SymPy comme illustré ci-dessus et c'est en effet la " -"méthode recommandée si vous voulez l'utiliser dans votre programme. Vous " -"pouvez aussi l'installer en utilisant ``./setup.py install`` comme tout " -"autre module Python, ou simplement installer un paquet dans votre " -"distribution Linux préférée, par exemple :" - -# 55b49b81cda049918eed0c4230ddde13 -#: ../../src/tutorial.rst:80 -msgid "" -"For other means how to install SymPy, consult the Downloads_ tab on the " -"SymPy's webpage." -msgstr "" -"Pour d'autres moyens d'installer SymPy, consultez l'onglet Téléchargements_ " -"(\"Downloads\" en anglais) sur la page web de SymPy." - -# 8f7cb3f507ce4fad82e45f0f0b337920 -#: ../../src/tutorial.rst:87 -msgid "isympy Console" -msgstr "La console isympy" - -# 57f6a7bd8cf048dc900ca01ea4a8d9e6 -#: ../../src/tutorial.rst:89 -msgid "" -"For experimenting with new features, or when figuring out how to do things, " -"you can use our special wrapper around IPython called ``isympy`` (located in " -"``bin/isympy`` if you are running from the source directory) which is just a " -"standard Python shell that has already imported the relevant SymPy modules " -"and defined the symbols x, y, z and some other things:" -msgstr "" -"Pour tester de nouvelles fonctionnalités, ou si vous cherchez à savoir " -"comment accomplir certaines choses, vous pouvez utiliser notre emballage " -"(wrapper) spécial enrobant IPython appelé ``isympy`` (situé dans ``bin/" -"isympy`` si vous vous trouvez dans le répertoire source). Cette commande " -"lance un shell Python standard qui importe les modules SymPy les plus " -"courants, les symboles définis x, y, z et d'autres choses à l'avance :" - -# 006ae2e758ee49c4bb04b443406a5af8 -#: ../../src/tutorial.rst:119 -msgid "" -"Commands entered by you are bold. Thus what we did in 3 lines in a regular " -"Python interpreter can be done in 1 line in isympy." -msgstr "" -"Les commandes que vous entrez sont en gras. Ainsi ce que nous avons fait en " -"3 lignes dans un interpréteur Python habituel peut être fait en une ligne " -"avec isympy." - -# f966b702679a4da1bb2ef4adf342630a -#: ../../src/tutorial.rst:124 -msgid "Using SymPy as a calculator" -msgstr "Utiliser SymPy comme une calculatrice" - -# f046236681f34400be4512a01acb4d6f -#: ../../src/tutorial.rst:126 -msgid "SymPy has three built-in numeric types: Float, Rational and Integer." -msgstr "" -"SymPy possède trois types numériques natifs : Float (Flottant), Rational " -"(Rationnel) et Integer (Entier)." - -# 4953a0720c544edc95ca170eecc120e7 -#: ../../src/tutorial.rst:128 -msgid "" -"The Rational class represents a rational number as a pair of two Integers: " -"the numerator and the denominator. So Rational(1,2) represents 1/2, Rational" -"(5,2) represents 5/2, and so on." -msgstr "" -"La classe Rational représente un nombre rationnel en tant que paire de deux " -"Integers : le numérateur et le dénominateur. Donc Rational(1,2) représente " -"1/2, Rational(5,2) représente 5/2, et ainsi de suite." - -# 8215da6dfc7a448d8b1eceb5e49b8195 -#: ../../src/tutorial.rst:147 -msgid "" -"Proceed with caution while working with Python int's and floating point " -"numbers, especially in division, since you may create a Python number, not a " -"SymPy number. A ratio of two Python ints may create a float -- the \"true " -"division\" standard of Python 3 and the default behavior of ``isympy`` which " -"imports division from __future__::" -msgstr "" -"Faites attention lorsque vous travaillez avec les nombres entiers et à " -"virgule flottante de Python, surtout dans des divisions, puisque vous " -"pourriez créer un nombre Python, et non pas un nombre SymPy. Un ratio de " -"deux entiers Python pourrait créer un flottant -- la \"vraie division\", " -"standard sous Python 3 et le comportement par défaut de ``isympy`` qui " -"importe l'opération division du module __future__ ::" - -# 1886bb1d12364256bd21bc136e3b4d6b -#: ../../src/tutorial.rst:157 -msgid "" -"But in earlier Python versions where division has not been imported, a " -"truncated int will result::" -msgstr "" -"Cependant, dans les versions antérieures à Python 3, l'opération division " -"résulte par défaut en une divison euclidienne et entraînera :" - -# ed5860be2f6d4b0a82fa4dd94fdb1c2c -#: ../../src/tutorial.rst:163 -msgid "" -"In both cases, however, you are not dealing with a SymPy Number because " -"Python created its own number. Most of the time you will probably be working " -"with Rational numbers, so make sure to use Rational to get the SymPy result. " -"One might find it convenient to equate ``R`` and Rational::" -msgstr "" -"Dans les deux cas, toutefois, vous n'avez pas affaire à un nombre SymPy " -"parce que Python a créé son propre nombre. La plupart du temps vous " -"travaillerez fort probablement avec des nombres rationels, alors prenez " -"garde à utiliser Rational pour obtenir le résultat en terme d'objets SymPy. " -"On pourrait trouver pratique d'assigner Rational à ``R`` ::" - -# cbc439f62bab451ea83aa0f38cd9334e -#: ../../src/tutorial.rst:175 -msgid "" -"We also have some special constants, like e and pi, that are treated as " -"symbols (1+pi won't evaluate to something numeric, rather it will remain as " -"1+pi), and have arbitrary precision::" -msgstr "" -"SymPy offre également quelques constantes spéciales, comme e et pi, qui sont " -"traitées comme des symboles (1+pi ne sera pas évalué sous forme numérique, " -"mais restera plutôt sous la forme 1+pi), et qui ont une précision " -"arbitraire ::" - -# 23596da160cb43eca427302760dc10e0 -#: ../../src/tutorial.rst:189 -msgid "as you see, evalf evaluates the expression to a floating-point number" -msgstr "" -"Comme vous le voyez, evalf convertit l'expression en un nombre à virgule " -"flottante." - -# 343ffd09916f47e883b534ba9cb25398 -#: ../../src/tutorial.rst:191 -msgid "The symbol ``oo`` is used for a class defining mathematical infinity::" -msgstr "" -"Le symbole ``oo`` est utilisé pour une classe définissant l'infini " -"mathématique ::" - -# 440a7b55bf0246e6a2224a5c27aa2be2 -#: ../../src/tutorial.rst:200 -msgid "Symbols" -msgstr "Symboles" - -# db362eb8a04d4e51895f4fc0d5787127 -#: ../../src/tutorial.rst:202 -msgid "" -"In contrast to other Computer Algebra Systems, in SymPy you have to declare " -"symbolic variables explicitly::" -msgstr "" -"Contrairement à d'autres systèmes de calcul formel, SymPy vous oblige à " -"déclarer les variables symboliques explicitement ::" - -# 04d53da6e24b4acea1709028878facef -#: ../../src/tutorial.rst:209 -msgid "" -"On the left is the normal Python variable which has been assigned to the " -"SymPy Symbol class. Predefined symbols (including those for symbols with " -"Greek names) are available for import from abc:" -msgstr "" -"À gauche se trouve la variable Python normale à laquelle est assignée une " -"instance de la classe Symbol de SymPy. Certains symboles prédefinis (dont " -"les symboles portant un nom grec) sont disponibles après importation :" - -# e5361b48af934938a4649c10bec5f7c9 -#: ../../src/tutorial.rst:215 -msgid "" -"Symbols can also be created with the ``symbols`` or ``var`` functions, the " -"latter automatically adding the created symbols to the namespace, and both " -"accepting a range notation:" -msgstr "" -"Plusieurs symboles peuvent également être déclarés en utilisant une seule " -"commande avec les fonctions ``symbols`` ou ``var``. Ces fonctions acceptent " -"une chaîne de texte contenant une liste ou un interval de symboles à " -"déclarer, la variante ``var`` ajoutant également les symboles à la liste de " -"noms courante (namespace) :" - -# f47705eda25b4870bdd6a48eaa5f4e5a -#: ../../src/tutorial.rst:227 -msgid "" -"Instances of the Symbol class \"play well together\" and are the building " -"blocks of expresions::" -msgstr "" -"Les instances de la classe Symbol travaillent ensemble et sont les " -"fondements nécessaires pour construire des expressions ::" - -# 68e80a5c036a482b8fd057bced16736c -#: ../../src/tutorial.rst:239 -msgid "" -"They can be substituted with other numbers, symbols or expressions using " -"``subs(old, new)``::" -msgstr "" -"Elles peuvent être remplacées par d'autres nombres, symboles ou expressions " -"grâce à l'utilisation de ``subs(old, new)`` ::" - -# 130691e7a3144beba176fc87ae7d23fa -#: ../../src/tutorial.rst:250 -msgid "For the remainder of the tutorial, we assume that we have run::" -msgstr "Pour le reste du tutoriel, il est présumé que nous avons exécuté ::" - -# 240782978b2f437fa50a57307257b26e -#: ../../src/tutorial.rst:255 -msgid "" -"This will make things look better when printed. See the :ref:`printing-" -"tutorial` section below. If you have a unicode font installed, you can pass " -"use_unicode=True for a slightly nicer output." -msgstr "" -"Ceci donnera un meilleur aspect aux résultats affichées. Pour en savoir plus " -"sur l'affichage, consultez la section :ref:`printing-tutorial` ci-dessous. " -"Si vous avez une police unicode installée, vous pouvez passer " -"use_unicode=True pour un affichage un peu plus agréable." - -# aec22b1ce108467ca12dd09a7b669549 -#: ../../src/tutorial.rst:260 -msgid "Algebra" -msgstr "Algèbre" - -# 8afbdc32b6eb483a913f27237d9a1606 -#: ../../src/tutorial.rst:262 -msgid "For partial fraction decomposition, use ``apart(expr, x)``::" -msgstr "" -"Pour la décomposition en éléments simples des fractions, utilisez ``apart" -"(expr, x)`` ::" - -# 5f6cf40996d449a5870e08cd322f83de -#: ../../src/tutorial.rst:287 -msgid "To combine things back together, use ``together(expr, x)``::" -msgstr "Pour remettre tout ensemble, utilisez ``together(expr, x)`` ::" - -# 5dae9592507d4cd88b96cf54f81ddc4c -#: ../../src/tutorial.rst:309 -msgid "Calculus" -msgstr "Calcul" - -# 75af12a54f344350a941850b4274cef0 -#: ../../src/tutorial.rst:314 -msgid "Limits" -msgstr "Limites" - -# 1fd6a572cd2e47b08153c8969aa368f3 -#: ../../src/tutorial.rst:316 -msgid "" -"Limits are easy to use in SymPy, they follow the syntax ``limit(function, " -"variable, point)``, so to compute the limit of f(x) as x -> 0, you would " -"issue ``limit(f, x, 0)``::" -msgstr "" -"Les limites sont simples à utiliser dans SymPy, elles suivent la syntaxe " -"``limit(function, variable, point)``, donc pour calculer la limite de f(x) " -"pour x tendant vers 0, il suffit d'entrer ``limit(f, x, 0)`` ::" - -# 09cd45b9dcc94ea6a9828f5bb038da22 -#: ../../src/tutorial.rst:325 -msgid "you can also calculate the limit at infinity::" -msgstr "Vous pouvez aussi calculer la limite tendant vers l'infini ::" - -# 703b2e3c52bf4c6783a7b12e6b8993be -#: ../../src/tutorial.rst:336 -msgid "" -"for some non-trivial examples on limits, you can read the test file " -"`test_demidovich.py `_" -msgstr "" -"Pour des exemples non-triviaux de limites, vous pouvez lire le fichier de " -"test `test_demidovich.py `_" - -# 0b41a5f8694644c29e47ef223bb42f9b -#: ../../src/tutorial.rst:343 -msgid "Differentiation" -msgstr "Dérivation" - -# 3c642f8923db4cd0a6d8fa48073037b1 -#: ../../src/tutorial.rst:345 -msgid "" -"You can differentiate any SymPy expression using ``diff(func, var)``. " -"Examples::" -msgstr "" -"Vous pouvez dériver n'importe quelle expression SymPy en utilisant ``diff" -"(func, var)``. Exemples ::" - -# f7de7efff45147b084274a45867a5233 -#: ../../src/tutorial.rst:358 -msgid "You can check, that it is correct by::" -msgstr "Vous pouvez vérifier que c'est correct avec ::" - -# 7404220cdfdf46008a31c01a29088a5a -#: ../../src/tutorial.rst:366 -msgid "" -"Higher derivatives can be calculated using the ``diff(func, var, n)`` " -"method::" -msgstr "" -"Des dérivées d'ordre supérieur peuvent être calculées en utilisant la " -"méthode ``diff(func, var, n)`` ::" - -# 1fe4b056ea1044fe96e6bfb997dd38a7 -#: ../../src/tutorial.rst:383 -msgid "Series expansion" -msgstr "Développement en série" - -# f5bc95de25274810824c2b5a62ed6d4a -#: ../../src/tutorial.rst:385 -msgid "Use ``.series(var, point, order)``::" -msgstr "Utilisez ``.series(var, point, order)`` ::" - -# 842dee0260574a2bb2dfdd3adfc65f6c -#: ../../src/tutorial.rst:400 -msgid "Another simple example::" -msgstr "Un autre exemple simple ::" - -# 588350b07e8946c3990190b5e03eeb79 -#: ../../src/tutorial.rst:424 -msgid "Summation" -msgstr "Sommes" - -# c8e0a258ce834d868419e0aed64142e9 -#: ../../src/tutorial.rst:426 -msgid "" -"Compute the summation of f with respect to the given summation variable over " -"the given limits." -msgstr "Calcule la somme de f indexée sur la variable muette donnée entre les " -"limites données." - -# 8399e19ad841458d9a517e24cd647081 -#: ../../src/tutorial.rst:428 -msgid "" -"summation(f, (i, a, b)) computes the sum of f with respect to i from a to b, " -"i.e., ::" -msgstr "" -"summation(f, (i, a, b)) calcule la somme de f sur la variable muette i entre " -"les limites a et b, c'est-à-dire ::" - -# 2257b464c29d4d7f8fad17e106053f41 -#: ../../src/tutorial.rst:439 -msgid "" -"If it cannot compute the sum, it prints the corresponding summation formula. " -"Repeated sums can be computed by introducing additional limits::" -msgstr "" -"Si la somme ne peut pas être résolue, la formule de sommation correspondante " -"est imprimée. Les sommes répétées peuvent être calculées en introduisant " -"des limites additionnelles." - -# 11ab582b28564b3dbc16b671ccfb73b7 -#: ../../src/tutorial.rst:473 -msgid "Integration" -msgstr "Intégration" - -# 5bfb235d51fa432d8c342cf92bfb68b1 -#: ../../src/tutorial.rst:475 -msgid "" -"SymPy has support for indefinite and definite integration of transcendental " -"elementary and special functions via ``integrate()`` facility, which uses " -"powerful extended Risch-Norman algorithm and some heuristics and pattern " -"matching::" -msgstr "" -"SymPy supporte l'intégration définie et indéfinie de fonctions élémentaires " -"et spéciales avec ``integrate()``, qui utilise le puissant algorithme de " -"Risch-Norman étendu et quelques heuristiques ainsi que le filtrage par " -"motif ::" - -# 0ed727b1e0724f7196823484c87dc683 -#: ../../src/tutorial.rst:483 -msgid "You can integrate elementary functions::" -msgstr "Vous pouvez intégrer des fonctions élémentaires ::" - -# f5a4ffc9c9fe4b72b9db2ee3fd2105aa -#: ../../src/tutorial.rst:496 -msgid "Also special functions are handled easily::" -msgstr "Les fonctions spéciales sont aussi facilement gérées ::" - -# ced7d3473a704a5d8bf8acde64aeccc1 -#: ../../src/tutorial.rst:504 -msgid "It is possible to compute definite integrals::" -msgstr "Il est possible de calculer l'intégrale définie ::" - -# 5b1ab2b76c4747ec97af9e6881037ad2 -#: ../../src/tutorial.rst:513 -msgid "Also, improper integrals are supported as well::" -msgstr "Les intégrales impropres sont aussi supportées ::" - -# 456289daa1f44c9ebdf9f991251f2b69 -#: ../../src/tutorial.rst:525 -msgid "Complex numbers" -msgstr "Nombres complexes" - -# a590ff90b89e4ed8ad466e48393db7aa -#: ../../src/tutorial.rst:527 -msgid "" -"Besides the imaginary unit, I, which is imaginary, symbols can be created " -"with attributes (e.g. real, positive, complex, etc...) and this will affect " -"how they behave::" -msgstr "" -"Outre l'unité imaginaire, I, qui est imaginaire, les symboles peuvent être " -"créés avec certains attributs (par exemple réel, positif, complexe, etc.) " -"affectant leur comportement ::" - -# 81c6a63d4e3b4277bc8951b44864a8b3 -#: ../../src/tutorial.rst:544 -msgid "Functions" -msgstr "Fonctions" - -# 7a36bbda19054725a821b8e55babeb07 -#: ../../src/tutorial.rst:546 -msgid "**trigonometric**::" -msgstr "**trigonométrie** ::" - -# afbf58c6f0da41d8b3cfb3d5ebe58355 -#: ../../src/tutorial.rst:595 -msgid "**spherical harmonics**::" -msgstr "**harmoniques sphériques** ::" - -# 1e36c14c2ba24819b1cf01022a823d3f -#: ../../src/tutorial.rst:621 -msgid "**factorials and gamma function**::" -msgstr "**factorielles et fonction gamma** ::" - -# 4be94eceb67b43b9aec82d77eee25c08 -#: ../../src/tutorial.rst:639 -msgid "**zeta function**::" -msgstr "**fonction zeta** ::" - -# da3a1e3a2bb74e44b52660303be0212a -#: ../../src/tutorial.rst:664 -msgid "**polynomials**::" -msgstr "**polynômes** ::" - -# 79b5e10918d44f72af7435df521d8db7 -#: ../../src/tutorial.rst:703 -msgid "Differential Equations" -msgstr "Équations différentielles" - -# 3c5467be56be493a9a7969b711335132 -# 8957dc6e2c6f47619f75f0c71eab8934 -#: ../../src/tutorial.rst:705 ../../src/tutorial.rst:725 -msgid "In ``isympy``::" -msgstr "Dans ``isympy`` ::" - -# 9ba6ed46809f45dda668d509187b1da0 -#: ../../src/tutorial.rst:723 -msgid "Algebraic equations" -msgstr "Équations algébriques" - -# 7ce994b211164a31bf28e153bf36d7ff -#: ../../src/tutorial.rst:738 -msgid "Linear Algebra" -msgstr "Algèbre linéaire" - -# 30289dafef2a4b4f813881457090b1fb -#: ../../src/tutorial.rst:743 -msgid "Matrices" -msgstr "Matrices" - -# 724322e53f59481280cceb0726399c29 -#: ../../src/tutorial.rst:745 -msgid "Matrices are created as instances from the Matrix class::" -msgstr "Les matrices sont créées en instanciant la classe Matrix ::" - -# fcde736a0fa64215b4f6001c5f614c8a -#: ../../src/tutorial.rst:753 -msgid "They can also contain symbols::" -msgstr "Elles peuvent aussi contenir des symboles ::" - -# 9ecaa39c9e3b4bc8a14592228c328636 -#: ../../src/tutorial.rst:768 -msgid "For more about Matrices, see the Linear Algebra tutorial." -msgstr "" -"Pour plus d'informations et d'exemples avec les Matrices, voyez le Tutoriel " -"Algèbre Linéaire." - -# 1ef2e834ca3442009791b78dc8f47868 -#: ../../src/tutorial.rst:773 -msgid "Pattern matching" -msgstr "Filtrage par motif" - -# d9b24fd459c44fca939040de93df5eb4 -#: ../../src/tutorial.rst:775 -msgid "" -"Use the ``.match()`` method, along with the ``Wild`` class, to perform " -"pattern matching on expressions. The method will return a dictionary with " -"the required substitutions, as follows::" -msgstr "" -"Utilisez la méthode ``.match()``, accompagnée de la classe ``Wild``, pour " -"effectuer un filtrage par motif sur des expressions. La méthode renvoit un " -"dictionnaire avec les substitutions requises, comme suit ::" - -# 25432d872c804d25b9f9af409a52b2f3 -#: ../../src/tutorial.rst:789 -msgid "If the match is unsuccessful, it returns ``None``::" -msgstr "Si le filtrage est infructueux, ``None`` est renvoyé ::" - -# a3a96ad7861046a88411b52c80781bb8 -#: ../../src/tutorial.rst:794 -msgid "" -"One can also use the exclude parameter of the ``Wild`` class to ensure that " -"certain things do not show up in the result::" -msgstr "" -"On peut aussi utiliser le paramètre ``exclude`` de la classe ``Wild`` pour " -"s'assurer que certaines choses ne figurent pas dans le résultat ::" - -# 0ff902a7febf4f1cbb3765704e1782ad -#: ../../src/tutorial.rst:808 -msgid "Printing" -msgstr "Affichage" - -# 5550455084ca4f21958dcad809a3b469 -#: ../../src/tutorial.rst:810 -msgid "There are many ways to print expressions." -msgstr "Les expressions peuvent être affichées de plusieures façons." - -# 63e395a41a354834a647400ed129feae -#: ../../src/tutorial.rst:812 -msgid "**Standard**" -msgstr "**Affichage standard**" - -# 9d95b398e5f0434a9f526a996c5e1714 -#: ../../src/tutorial.rst:814 -msgid "This is what ``str(expression)`` returns and it looks like this:" -msgstr "C'est ce que ``str(expression)`` renvoit et ça ressemble à ça :" - -# fa129049989d4c8e81396404c88ff131 -#: ../../src/tutorial.rst:825 -msgid "**Pretty printing**" -msgstr "**Affichage amélioré**" - -# e0ee9f57e30248b19d51cac1645607a0 -#: ../../src/tutorial.rst:827 -msgid "Nice ascii-art printing is produced by the ``pprint`` function:" -msgstr "" -"Ceci est un affichage amélioré en art ASCII produit par la fonction " -"``pprint`` :" - -# c76d8d47f2804755be1b3b53c4785413 -#: ../../src/tutorial.rst:846 -msgid "" -"If you have a unicode font installed, the ``pprint`` function will use it by " -"default. You can override this using the ``use_unicode`` option.:" -msgstr "" -"Si vous avez une police unicode installée, l'affichage amélioré l'utilisera " -"par défaut. Vous pouvez outrepasser ce comportement en utilisant l'option " -"``use_unicode`` :" - -# 4bfe36a39f6f400188893081d61ee01f -#: ../../src/tutorial.rst:856 -msgid "" -"See also the wiki `Pretty Printing `_ for more examples of a nice unicode printing." -msgstr "" -"Voyez aussi la page wiki `Pretty Printing `_ pour plus d'exemples concernant l'affichage amélioré " -"et l'option unicode." - -# c6814f498b1746aea1949750b0748e07 -#: ../../src/tutorial.rst:860 -msgid "" -"Tip: To make pretty printing the default in the Python interpreter, use::" -msgstr "" -"Astuce : pour activer l'affichage amélioré par défaut dans l'interpréteur " -"Python, utilisez ::" - -# e5bc27e2d3ca4106821db25f5d18b781 -#: ../../src/tutorial.rst:883 -msgid "**Python printing**" -msgstr "**Python**" - -# 0a32fac506a2447c88466f2215426108 -#: ../../src/tutorial.rst:899 -msgid "**LaTeX printing**" -msgstr "**LaTeX**" - -# 400fa00c853b452dab4bd2805a9debc1 -#: ../../src/tutorial.rst:916 -msgid "**MathML**" -msgstr "**MathML**" - -# 56a7a86bbd544a879f1ca70c2d2b18ad -#: ../../src/tutorial.rst:928 -msgid "**Pyglet**" -msgstr "**Pyglet**" - -# 577597efafd74929848af620a5d058d4 -#: ../../src/tutorial.rst:934 -msgid "" -"If pyglet is installed, a pyglet window will open containing the LaTeX " -"rendered expression:" -msgstr "" -"Si pyglet est installé, une fenêtre pyglet apparaîtra avec l'expression " -"rendue par LaTeX :" - -# 1b841dfd01e6427cbb50be4b0c11bd37 -#: ../../src/tutorial.rst:940 -msgid "Notes" -msgstr "Notes" - -# 053b683ead2c44fabdbcd3c0ebb9e6dc -#: ../../src/tutorial.rst:942 -msgid "" -"``isympy`` calls ``pprint`` automatically, so that's why you see pretty " -"printing by default." -msgstr "" -"``isympy`` appelle ``pprint`` automatiquement, c'est donc pourquoi vous " -"voyez un affichage amélioré par défaut." - -# 42269d434d4045b9b051f97fbf5e1fb1 -#: ../../src/tutorial.rst:945 -msgid "" -"Note that there is also a printing module available, ``sympy.printing``. " -"Other printing methods available through this module are:" -msgstr "" -"Notez qu'il y a aussi un module d'affichage disponible, ``sympy.printing``. " -"D'autres méthodes d'affichage disponibles dans ce module sont :" - -# ae1ede5523704591b3f85d0196d16be1 -#: ../../src/tutorial.rst:948 -msgid "" -"``pretty(expr)``, ``pretty_print(expr)``, ``pprint(expr)``: Return or print, " -"respectively, a pretty representation of ``expr``. This is the same as the " -"second level of representation described above." -msgstr "" -"``pretty(expr)``, ``pretty_print(expr)``, ``pprint(expr)``: Renvoit ou " -"affiche, respectivement, une représentation améliorée de ``expr``. C'est la " -"même chose que le second niveau de représentation décrit ci-dessus." - -# 9d1e17f8989e430fb6ed6b89bccb416c -#: ../../src/tutorial.rst:950 -msgid "" -"``latex(expr)``, ``print_latex(expr)``: Return or print, respectively, a " -"`LaTeX `_ representation of ``expr``" -msgstr "" -"``latex(expr)``, ``print_latex(expr)``: Renvoit ou affiche, respectivement, " -"une représentation `LaTeX `_ de ``expr``" - -# d248f0d0f36b45b8ac36fcfad7befb0c -#: ../../src/tutorial.rst:952 -msgid "" -"``mathml(expr)``, ``print_mathml(expr)``: Return or print, respectively, a " -"`MathML `_ representation of ``expr``." -msgstr "" -"``mathml(expr)``, ``print_mathml(expr)``: Renvoit ou affiche, " -"respectivement, une représentation `MathML `_ de " -"``expr``." - -# 3ad0e8f5993f47f78b6101252802d569 -#: ../../src/tutorial.rst:954 -msgid "" -"``print_gtk(expr)``: Print ``expr`` to `Gtkmathview `_, a GTK widget that displays MathML code. The `Gtkmathview " -"`_ program is required." -msgstr "" -"``print_gtk(expr)``: Affiche ``expr`` dans `Gtkmathview `_, un widget GTK qui affiche du code MathML. Le " -"programme `Gtkmathview `_ est requis." - -# b2be31fd9b3e482d8d812e12410fa4fc -#: ../../src/tutorial.rst:957 -msgid "Further documentation" -msgstr "Documentation" - -# 8c464db44d054007aba2457b69403054 -#: ../../src/tutorial.rst:959 -msgid "" -"Now it's time to learn more about SymPy. Go through the :ref:`SymPy User's " -"Guide ` and :ref:`SymPy Modules Reference `." -msgstr "" -"Il est maintenant temps d'en apprendre plus sur SymPy. Consultez le :ref:" -"`SymPy User's Guide ` et la :ref:`SymPy Modules Reference `." - -# 530a3ac7c21a43d0a0734b8e2a719742 -#: ../../src/tutorial.rst:963 -msgid "" -"Be sure to also browse our public `wiki.sympy.org `_, that contains a lot of useful examples, tutorials, cookbooks that we " -"and our users contributed, and feel free to edit it." -msgstr "" -"Veillez également à consulter notre `wiki.sympy.org `_ public, qui contient beaucoup d'exemples utiles, des tutoriels, des " -"livres de recettes auxquels nous et nos utilisateurs ont contribué et que " -"nous vous encourageons à modifier." - -# 6f81344d40194b1e9626585ad7d61071 -#: ../../src/tutorial.rst:968 -msgid "Translations" -msgstr "Traductions" - -# d63477b361e444e5ba1312563eb9f3d3 -#: ../../src/tutorial.rst:970 -msgid "This tutorial is also available in other languages:" -msgstr "Ce tutoriel est aussi disponible dans les langues suivantes :" diff -Nru python3-sympy-0.7.2/doc/src/tutorial.pl.po python3-sympy-0.7.3/doc/src/tutorial.pl.po --- python3-sympy-0.7.2/doc/src/tutorial.pl.po 2012-10-17 02:30:33.000000000 +0000 +++ python3-sympy-0.7.3/doc/src/tutorial.pl.po 1970-01-01 00:00:00.000000000 +0000 @@ -1,775 +0,0 @@ -# Polish translation of the SymPy tutorial. -# Copyright (C) 2008, 2009, 2010, 2011, 2012 SymPy Development Team -# This file is distributed under the same license as the SymPy package. -# FIRST AUTHOR , YEAR. -# -#, fuzzy -msgid "" -msgstr "" -"Project-Id-Version: SymPy 0.7.2\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2012-08-14 15:40\n" -"PO-Revision-Date: 2012-08-15 10:51\n" -"Last-Translator: Piotr Korgul \n" -"Language-Team: LANGUAGE \n" -"Language: Polish\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" - -# c3c7762a9db049dfb7222ebc08310009 -#: ../../src/tutorial.rst:5 -msgid "Tutorial" -msgstr "Tutorial" - -# 09c9ce15db7c475b9639ac0c4f7de25d -#: ../../src/tutorial.rst:10 -msgid "Introduction" -msgstr "Wprowadzenie" - -# 52617d18b99647d9b224e94ab4ba4303 -#: ../../src/tutorial.rst:12 -msgid "" -"SymPy is a Python library for symbolic mathematics. It aims to become a full-" -"featured computer algebra system (CAS) while keeping the code as simple as " -"possible in order to be comprehensible and easily extensible. SymPy is " -"written entirely in Python and does not require any external libraries." -msgstr "" -"SymPy jest biblioteką Pythona służącą do wykonywania obliczeń symbolicznych. " -"Za cel stawia sobie stanie się zaawansowanym, w pełni funkcjonalnym systemem " -"algebry komputerowej (ang. Computer Algebra System, w skrócie CAS). Przy tym " -"dąży do zachowania kodu tak prostego, jak to tylko możliwe, by był on " -"zrozumiały i elastyczny. SymPy został napisany całkowicie w Pythonie i nie " -"wymaga żadnych zewnętrznych bibliotek." - -# fcb33c1387364618927d497968780892 -#: ../../src/tutorial.rst:17 -msgid "" -"This tutorial gives an overview and introduction to SymPy. Read this to have " -"an idea what SymPy can do for you (and how) and if you want to know more, " -"read the :ref:`SymPy User's Guide `, :ref:`SymPy Modules Reference " -"`. or the `sources `_ directly." -msgstr "" -"Ten tutorial przedstawia ogólny zarys i przegląd wybranych funkcji SymPy. " -"Dzięki niemu dowiesz się, co SymPy może dla Ciebie zrobić (i jak). Jeśli " -"będziesz chciał dowiedzieć się więcej, przeczytaj :ref:`Przewodnik " -"użytkownika `, :ref:`Opis modułów `. lub też " -"bezpośrednio `źródła `_." - -# fc618fe13ab74b4590a8f551765ecf01 -#: ../../src/tutorial.rst:26 -msgid "First Steps with SymPy" -msgstr "Pierwsze kroki z SymPy" - -# d8f304305c05411fbbc64d0b2eb4254f -#: ../../src/tutorial.rst:28 -msgid "" -"The easiest way to download it is to go to http://code.google.com/p/sympy/ " -"and download the latest tarball from the Featured Downloads:" -msgstr "" -"Żeby ściągnąć SymPy udaj się pod adres http://code.google.com/p/sympy/ i " -"pobierz ostatniego tarballa z sekcji Featured Downloads:" - -# 1c67caa7568f4b1182228149c9e68033 -#: ../../src/tutorial.rst:34 -msgid "Unpack it:" -msgstr "Rozpakuj:" - -# 598cc46f05ce44aaa5a0c50278e35f85 -#: ../../src/tutorial.rst:40 -msgid "and try it from a Python interpreter:" -msgstr "i sprawdź pod interpreterem Pythona:" - -# bb21d7a2c56443d3ad39544da80bfa3e -#: ../../src/tutorial.rst:54 -msgid "" -"You can use SymPy as shown above and this is indeed the recommended way if " -"you use it in your program. You can also install it using ``./setup.py " -"install`` as any other Python module, or just install a package in your " -"favourite Linux distribution, e.g.:" -msgstr "" -"Możesz używać SymPy tak jak pokazano powyżej - ten sposób jest zalecany, " -"jeśli używasz SymPy w swoim własnym programie. Możesz też zainstalować SymPy " -"użwając ``./setup.py install`` (jak w przypadku każdego modułu Pythona), " -"albo po prostu zainstalować odpowiednią paczkę w używanej przez siebie " -"dystrybucji Linuksa, np.:" - -# fa2935dd59924335bad07d2a81f97fea -#: ../../src/tutorial.rst:80 -msgid "" -"For other means how to install SymPy, consult the Downloads_ tab on the " -"SymPy's webpage." -msgstr "" -"Inne sposoby instalacji SymPy znajdziesz w karcie Downloads_ na stronie " -"SymPy." - -# b84bf41fe93244cdaecc6252c5bf40b1 -#: ../../src/tutorial.rst:87 -msgid "isympy Console" -msgstr "isympy" - -# 13fa08b4ecec475680b5dd6948e45e63 -#: ../../src/tutorial.rst:89 -#, fuzzy -msgid "" -"For experimenting with new features, or when figuring out how to do things, " -"you can use our special wrapper around IPython called ``isympy`` (located in " -"``bin/isympy`` if you are running from the source directory) which is just a " -"standard Python shell that has already imported the relevant SymPy modules " -"and defined the symbols x, y, z and some other things:" -msgstr "" -"Żeby poeksperymentować z nowymi funkcjonalnościami, lub żeby sprawdzić, co i " -"jak można zrobić w SymPy, możesz użyć specjalnej nakładki na IPythona " -"nazwanej ``isympy`` (znajduje się ona w ``bin/isympy`` jeśli zaczynasz z " -"katalogu źródłowego). Jest to po prostu standardowa powłoka Pythona, do " -"której zostały już zaimportowane stosowne moduły SymPy, zdefiniowane symbole " -"x, y, z i kilka innych rzeczy:" - -# 494d3d53409b4c959ccba0730a468323 -#: ../../src/tutorial.rst:119 -msgid "" -"Commands entered by you are bold. Thus what we did in 3 lines in a regular " -"Python interpreter can be done in 1 line in isympy." -msgstr "" -"Polecenia wprowadzane przez Ciebie są pogrubione. Tak więc to, co zrobiliśmy " -"w trzech linijkach w zwykłym interpreterze Pythona, może być zrobione w " -"jednej linijce w isympy." - -# 70f81a7568294cbab0fb0230499f1ca8 -#: ../../src/tutorial.rst:124 -msgid "Using SymPy as a calculator" -msgstr "SymPy jako kalkulator" - -# 2f0e19e8e0204f09984f1033cd40e086 -#: ../../src/tutorial.rst:126 -#, fuzzy -msgid "SymPy has three built-in numeric types: Float, Rational and Integer." -msgstr "" -"SymPy posiada trzy wbudowane typy liczbowe: Float (zmiennoprzecinkowy), " -"Rational (wymierny) i Integer (całkowity)." - -# 42324bbd13784561953f6187223f2b45 -#: ../../src/tutorial.rst:128 -msgid "" -"The Rational class represents a rational number as a pair of two Integers: " -"the numerator and the denominator. So Rational(1,2) represents 1/2, Rational" -"(5,2) represents 5/2, and so on." -msgstr "" -"Klasa Rational reprezentuje liczbę wymierną jako parę dwóch liczb " -"całkowitych - licznik i mianownik. Rational(1,2) reprezentuje więc 1/2, " -"Rational(5,2) reprezentuje 5/2 itd." - -# 3a11553e28944951b7378b976614ffa2 -#: ../../src/tutorial.rst:147 -msgid "" -"Proceed with caution while working with Python int's and floating point " -"numbers, especially in division, since you may create a Python number, not a " -"SymPy number. A ratio of two Python ints may create a float -- the \"true " -"division\" standard of Python 3 and the default behavior of ``isympy`` which " -"imports division from __future__::" -msgstr "" -"Należy zachować ostrożność, pracując z liczbami całkowitymi i " -"zmiennoprzecinkowymi w Pythonie, szczególnie podczas dzielenia. Można bowiem " -"przypadkowo utworzyć liczbę obsługiwaną przez samego Pythona, a nie przez " -"SymPy. Dzielenie przez siebie dwóch Pythonowych liczb całkowitych może dać w " -"wyniku liczbę zmiennoprzecinkową -- jest to standard \"prawidłowego dzielenia" -"\" z Pythona 3 i domyślne zachowanie ``isympy``, który importuje dzielenie z " -"__future__::" - -# e444eade59e64fa3a3092c0f8e653d80 -#: ../../src/tutorial.rst:157 -msgid "" -"But in earlier Python versions where division has not been imported, a " -"truncated int will result::" -msgstr "" -"We wcześniejszych wersjach Pythona, gdzie takie dzielenie nie było " -"zaimportowane, wynik był ucinany do liczby całkowitej::" - -# 2d083b1a93bb47268c9e82c196016249 -#: ../../src/tutorial.rst:163 -msgid "" -"In both cases, however, you are not dealing with a SymPy Number because " -"Python created its own number. Most of the time you will probably be working " -"with Rational numbers, so make sure to use Rational to get the SymPy result. " -"One might find it convenient to equate ``R`` and Rational::" -msgstr "" -"Jednakże, w obu przypadkach, nie operowaliśmy na liczbach obsługiwanych " -"przez SymPy, ponieważ Python stworzył swoją własną zmienną. Prawdopodobnie " -"większość czasu będziesz operował na liczbach wymiernych -- dlatego upewnij " -"się, że na pewno używasz klasy Rational, aby uzyskać prawidłowy wynik " -"obsługiwany przez SymPy. Dla wygody możesz na przykład przyrównać ``R`` i " -"Rational::" - -# b6b267bd24dd4e399e0ab89a2951c30b -#: ../../src/tutorial.rst:175 -msgid "" -"We also have some special constants, like e and pi, that are treated as " -"symbols (1+pi won't evaluate to something numeric, rather it will remain as " -"1+pi), and have arbitrary precision::" -msgstr "" -"Możemy skorzystać też z kilku specjalnych stałych, takich jak e czy pi. Są " -"one traktowane jako symbole (np. w przypadku 1+pi nie zostanie obliczona " -"przybliżona wartość tego wyrażenia, lecz pozostanie ono jako 1+pi), i mają " -"arbitralną precyzję::" - -# f763ffaa12654eb49a83a61623d041bf -#: ../../src/tutorial.rst:189 -msgid "as you see, evalf evaluates the expression to a floating-point number" -msgstr "" -"Jak widzisz, evalf wylicza wartość wyrażenia jako liczbę zmiennoprzecinkową." - -# 2d5dadbf852f4d3d9748e9cff200117d -#: ../../src/tutorial.rst:191 -msgid "The symbol ``oo`` is used for a class defining mathematical infinity::" -msgstr "" -"Symbol ``oo`` jest używany jako klasa definiująca matematyczną " -"nieskończoność::" - -# 8c04d0160fcc4c5b9e9f740e466ddaa4 -#: ../../src/tutorial.rst:200 -msgid "Symbols" -msgstr "Symbole" - -# 45d22da3fa694be0acb5afe727e8663b -#: ../../src/tutorial.rst:202 -msgid "" -"In contrast to other Computer Algebra Systems, in SymPy you have to declare " -"symbolic variables explicitly::" -msgstr "" -"W przeciwieństwie do innych systemów algebry komputerowej (CAS), w SymPy sam " -"musisz zadeklarować zmienne symboliczne::" - -# d93a40acb5124f20bddf9eb06ce7d9fb -#: ../../src/tutorial.rst:209 -#, fuzzy -msgid "" -"On the left is the normal Python variable which has been assigned to the " -"SymPy Symbol class. Predefined symbols (including those for symbols with " -"Greek names) are available for import from abc:" -msgstr "" -"Po lewej jest zwykła zmienna z Pythona, która zostaje przypisana do klasy " -"Symbol z SymPy. Obiekty klasy Symbol \"dobrze ze sobą współgrają\" i mogą " -"budować całe bloki wyrażeń::" - -# beba4c07583f424c8077b432b138c274 -#: ../../src/tutorial.rst:215 -msgid "" -"Symbols can also be created with the ``symbols`` or ``var`` functions, the " -"latter automatically adding the created symbols to the namespace, and both " -"accepting a range notation:" -msgstr "" - -# d93a40acb5124f20bddf9eb06ce7d9fb -#: ../../src/tutorial.rst:227 -#, fuzzy -msgid "" -"Instances of the Symbol class \"play well together\" and are the building " -"blocks of expresions::" -msgstr "" -"Po lewej jest zwykła zmienna z Pythona, która zostaje przypisana do klasy " -"Symbol z SymPy. Obiekty klasy Symbol \"dobrze ze sobą współgrają\" i mogą " -"budować całe bloki wyrażeń::" - -# 413e1d34b1e247b59162cd33e3676498 -#: ../../src/tutorial.rst:239 -msgid "" -"They can be substituted with other numbers, symbols or expressions using " -"``subs(old, new)``::" -msgstr "" -"Można podstawiać w ich miejsce inne symbole i liczby używając ``subs(stary, " -"nowy)``::" - -# e80e0d205f06407d88dcc54a3df0c841 -#: ../../src/tutorial.rst:250 -msgid "For the remainder of the tutorial, we assume that we have run::" -msgstr "" -"W pozostałej części tutoriala zakładamy, że wykonaliśmy następujące " -"polecenie::" - -# 827bbf4467c64deeb8a7cac2493c8436 -#: ../../src/tutorial.rst:255 -msgid "" -"This will make things look better when printed. See the :ref:`printing-" -"tutorial` section below. If you have a unicode font installed, you can pass " -"use_unicode=True for a slightly nicer output." -msgstr "" -"Dzięki temu wszystko będzie się ładnie wyświetlało (zobacz sekcję :ref:" -"`printing-tutorial` poniżej). Jeśli masz zainstalowaną czcionkę unicode, " -"możesz zamienić use_unicode=False na use_unicode=True, dzięki czemu uzyskasz " -"nieco ładniejsze wyjście." - -# 066362b1730f425dbabf8d6ab6740bf9 -#: ../../src/tutorial.rst:260 -msgid "Algebra" -msgstr "Algebra" - -# e5a477b974194381bd525bfa4ed0f343 -#: ../../src/tutorial.rst:262 -msgid "For partial fraction decomposition, use ``apart(expr, x)``::" -msgstr "Żeby dokonać rozkładu na ułamki proste, użyj ``apart(wyrażenie, x)``::" - -# f4a49176ecaa40dda1b6074e3838bebb -#: ../../src/tutorial.rst:287 -msgid "To combine things back together, use ``together(expr, x)``::" -msgstr "Aby wszystko znowu ze sobą połączyć, użyj ``together(wyrażenie, x)``::" - -# 41bbfbe984f54e098c7ceb9d15951188 -#: ../../src/tutorial.rst:309 -msgid "Calculus" -msgstr "Rachunek różniczkowy i całkowy" - -# bdd9677d832744c28133a661d70dee94 -#: ../../src/tutorial.rst:314 -msgid "Limits" -msgstr "Granice" - -# 9cf43ca4c0cc48be9d8ca068eb328340 -#: ../../src/tutorial.rst:316 -#, fuzzy -msgid "" -"Limits are easy to use in SymPy, they follow the syntax ``limit(function, " -"variable, point)``, so to compute the limit of f(x) as x -> 0, you would " -"issue ``limit(f, x, 0)``::" -msgstr "" -"Granice są łatwe do obliczenia w SymPy - mają składnię ``limit(funkcja, " -"zmienna, punkt)``. A zatem, żeby wyznaczyć granicę funkcji f(x) przy x -> 0, " -"należy wpisać ``limit(f, x, 0)``::" - -# 5e93a27a89064513b7e380af393b4f9c -#: ../../src/tutorial.rst:325 -msgid "you can also calculate the limit at infinity::" -msgstr "Można również obliczyć granicę w nieskończoności::" - -# 1f400573d2604ef0a0df2cf481babea3 -#: ../../src/tutorial.rst:336 -msgid "" -"for some non-trivial examples on limits, you can read the test file " -"`test_demidovich.py `_" -msgstr "" -"Kilka nietrywialnych przykładów granic znajdziesz w pliku testowym " -"`test_demidovich.py `_" - -# 2c734bd34880493989dd1f35ec88a912 -#: ../../src/tutorial.rst:343 -msgid "Differentiation" -msgstr "Różniczkowanie" - -# 1759c7ac349c4e11a64e2e00de415745 -#: ../../src/tutorial.rst:345 -msgid "" -"You can differentiate any SymPy expression using ``diff(func, var)``. " -"Examples::" -msgstr "" -"Możesz różniczkować dowolne wyrażenie w SymPy używając ``diff(funkcja, " -"zmienna)``. Przykłady::" - -# 48665100e1594e468c31dfda2192e79d -#: ../../src/tutorial.rst:358 -msgid "You can check, that it is correct by::" -msgstr "Możesz też sprawdzić poprawność::" - -# be073287d339491a8be8a2445d953a58 -#: ../../src/tutorial.rst:366 -msgid "" -"Higher derivatives can be calculated using the ``diff(func, var, n)`` " -"method::" -msgstr "" -"Pochodne wyższych rzędów mogą być obliczone przy użyciu ``diff(funkcja, " -"zmienna, n)``::" - -# f8507259d74c42679dfede1adbbb8755 -#: ../../src/tutorial.rst:383 -msgid "Series expansion" -msgstr "Rozwinięcie w szereg" - -# e37dacd98e884378a4c98a35f0cd6a45 -#: ../../src/tutorial.rst:385 -msgid "Use ``.series(var, point, order)``::" -msgstr "Użyj ``.series(var, point, order)``::" - -# e9fce4aa28374d31b510af5561226a2a -#: ../../src/tutorial.rst:400 -msgid "Another simple example::" -msgstr "Inny prosty przykład::" - -# 588350b07e8946c3990190b5e03eeb79 -#: ../../src/tutorial.rst:424 -msgid "Summation" -msgstr "" - -# c8e0a258ce834d868419e0aed64142e9 -#: ../../src/tutorial.rst:426 -msgid "" -"Compute the summation of f with respect to the given summation variable over " -"the given limits." -msgstr "" - -# 8399e19ad841458d9a517e24cd647081 -#: ../../src/tutorial.rst:428 -msgid "" -"summation(f, (i, a, b)) computes the sum of f with respect to i from a to b, " -"i.e., ::" -msgstr "" - -# 2257b464c29d4d7f8fad17e106053f41 -#: ../../src/tutorial.rst:439 -msgid "" -"If it cannot compute the sum, it prints the corresponding summation formula. " -"Repeated sums can be computed by introducing additional limits::" -msgstr "" - -# a512383c4f8249fa99f77a885c6f1a2b -#: ../../src/tutorial.rst:473 -msgid "Integration" -msgstr "Całkowanie" - -# e347ffd4386a4c8183cca2640eb70c76 -#: ../../src/tutorial.rst:475 -msgid "" -"SymPy has support for indefinite and definite integration of transcendental " -"elementary and special functions via ``integrate()`` facility, which uses " -"powerful extended Risch-Norman algorithm and some heuristics and pattern " -"matching::" -msgstr "" -"SymPy potrafi obliczyć całki oznaczone i nieoznaczone dla niektórych funkcji " -"poprzez ``integrate()``. Używany jest do tego rozszerzony algorytm Rischa-" -"Normana, kilka heurystyk i wyszukiwanie wzorca::" - -# e0e05146b9e84ea58749b8040c3834e9 -#: ../../src/tutorial.rst:483 -msgid "You can integrate elementary functions::" -msgstr "Możesz całkować podstawowe funkcje::" - -# 5f3e633871f54c32bd70d7de30d2b90d -#: ../../src/tutorial.rst:496 -msgid "Also special functions are handled easily::" -msgstr "Bardziej skomplikowane funkcje również są obsługiwane::" - -# 4d30d7266b964299945bedd4d95b4898 -#: ../../src/tutorial.rst:504 -#, fuzzy -msgid "It is possible to compute definite integrals::" -msgstr "Można obliczyć całkę oznaczoną::" - -# 7b6882a44eef4c21b5a4321bc50f8372 -#: ../../src/tutorial.rst:513 -#, fuzzy -msgid "Also, improper integrals are supported as well::" -msgstr "Także całki niewłaściwe są obsługiwane::" - -# 815a72a1ffc64afdbeb897bd6d407ba1 -#: ../../src/tutorial.rst:525 -msgid "Complex numbers" -msgstr "Liczby zespolone" - -# a1aeb9f0079544e5bf8b2dd8e56f1115 -#: ../../src/tutorial.rst:527 -msgid "" -"Besides the imaginary unit, I, which is imaginary, symbols can be created " -"with attributes (e.g. real, positive, complex, etc...) and this will affect " -"how they behave::" -msgstr "" - -# f8acd25e28f9422dac12370934685a8a -#: ../../src/tutorial.rst:544 -msgid "Functions" -msgstr "Funkcje" - -# c57ac25e52344fd1a8777c8a161804a8 -#: ../../src/tutorial.rst:546 -msgid "**trigonometric**::" -msgstr "**trygonometria**::" - -# adb5970b193043478bbadc351d9b3c18 -#: ../../src/tutorial.rst:595 -msgid "**spherical harmonics**::" -msgstr "**harmoniki sferyczne**::" - -# d756e1e410ae4d5da8fa2f78eced22b3 -#: ../../src/tutorial.rst:621 -msgid "**factorials and gamma function**::" -msgstr "**silnia i funkcja gamma**::" - -# 5240d684ef814f8baf0d754dddee30aa -#: ../../src/tutorial.rst:639 -msgid "**zeta function**::" -msgstr "**funkcja zeta**::" - -# 3a5d397a982b4600b61213c44ed7c431 -#: ../../src/tutorial.rst:664 -msgid "**polynomials**::" -msgstr "**wielomiany**::" - -# 33f38102397c4eb2bfeb69ab4702a8d4 -#: ../../src/tutorial.rst:703 -msgid "Differential Equations" -msgstr "Równania różniczkowe" - -# d0a3138803fc48a98118d6e6320ee658 -# 1a9fd5b33f574d049686175bfbcdadff -#: ../../src/tutorial.rst:705 ../../src/tutorial.rst:725 -msgid "In ``isympy``::" -msgstr "W ``isympy``::" - -# 265aee4c9ff04d62951c4487e62ec6ea -#: ../../src/tutorial.rst:723 -msgid "Algebraic equations" -msgstr "Równania algebraiczne" - -# d3c97576ded74ee68d30f183c3f67642 -#: ../../src/tutorial.rst:738 -msgid "Linear Algebra" -msgstr "Algebra liniowa" - -# 8f01a7b65c594a318e23e0abd56b8357 -#: ../../src/tutorial.rst:743 -msgid "Matrices" -msgstr "Macierze" - -# a0879dd3c9754bfd803cf5f05238b492 -#: ../../src/tutorial.rst:745 -msgid "Matrices are created as instances from the Matrix class::" -msgstr "Macierze są tworzone jako obiekty klasy Matrix::" - -# b1a0f5459ebf483ab45bb3402f71c631 -#: ../../src/tutorial.rst:753 -#, fuzzy -msgid "They can also contain symbols::" -msgstr "Możesz wpisać w nie także symbole::" - -# ba76268c19984da9b828e4e0777c85aa -#: ../../src/tutorial.rst:768 -#, fuzzy -msgid "For more about Matrices, see the Linear Algebra tutorial." -msgstr "" -"Więcej informacji i przykładów macierzy znajdziesz w LinearAlgebraTutorial." - -# 37f83a52cd0d438daaf88f9840ad436c -#: ../../src/tutorial.rst:773 -msgid "Pattern matching" -msgstr "Wyszukiwanie wzorca" - -# 20a120130a19438ca01e7cdfd8ec0478 -#: ../../src/tutorial.rst:775 -msgid "" -"Use the ``.match()`` method, along with the ``Wild`` class, to perform " -"pattern matching on expressions. The method will return a dictionary with " -"the required substitutions, as follows::" -msgstr "" -"Użyj metody ``.match()`` z klasy ``Wild``, by wyszukać wzorzec w wyrażeniu " -"(porównać wyrażenia). Metoda ta zwróci zbiór odpowiadających sobie " -"współczynników::" - -# 3f9f222845d54b748013d9a64cfdf55b -#: ../../src/tutorial.rst:789 -msgid "If the match is unsuccessful, it returns ``None``::" -msgstr "" -"Jeśli wyszukiwanie zakończyło się niepowodzeniem, zwracane jest ``None``::" - -# d437842fb57143118e6cbd0c9815afbc -#: ../../src/tutorial.rst:794 -msgid "" -"One can also use the exclude parameter of the ``Wild`` class to ensure that " -"certain things do not show up in the result::" -msgstr "" -"Można również użyć parametru wykluczania (exclude) klasy ``Wild``, by " -"zagwarantować, że w wyniku nie zostaną pokazane niektóre rzeczy::" - -# d76bc2d90cc34bb8960519e8b27aa3ca -#: ../../src/tutorial.rst:808 -msgid "Printing" -msgstr "Wyświetlanie" - -# ba56f638f580479ca05b29d8a1a386fe -#: ../../src/tutorial.rst:810 -#, fuzzy -msgid "There are many ways to print expressions." -msgstr "Wyrażenia mogą być wyświetlane na wiele sposobów." - -# f9494b953942407da44d40d938d2bf3f -#: ../../src/tutorial.rst:812 -msgid "**Standard**" -msgstr "**Standardowe**" - -# bcb88e7efa24432a92b57476b97cf180 -#: ../../src/tutorial.rst:814 -msgid "This is what ``str(expression)`` returns and it looks like this:" -msgstr "Jest to to, co zwraca ``str(wyrażenie)`` i wygląda tak:" - -# af7d99f6b926481caba100e4c3eabf81 -#: ../../src/tutorial.rst:825 -msgid "**Pretty printing**" -msgstr "**Ładne wyświetlanie**" - -# 728bc3f692d844458b3a0a3fc3a8c846 -#: ../../src/tutorial.rst:827 -#, fuzzy -msgid "Nice ascii-art printing is produced by the ``pprint`` function:" -msgstr "" -"Jest to wyświetlanie oparte na ascii-arcie. Zapewnia je funkcja ``pprint``:" - -# f207f355dcdd441dbe5764262511046a -#: ../../src/tutorial.rst:846 -#, fuzzy -msgid "" -"If you have a unicode font installed, the ``pprint`` function will use it by " -"default. You can override this using the ``use_unicode`` option.:" -msgstr "" -"Jeśli masz zainstalowaną czcionkę unicode, domyślnie powinno być używane " -"ładne wyświetlanie w unicode. Możesz włączyć lub wyłączyć tę funkcję " -"używając opcji ``use_unicode``:" - -# f808faa1b65b47e69f3ecc0f93442e47 -#: ../../src/tutorial.rst:856 -msgid "" -"See also the wiki `Pretty Printing `_ for more examples of a nice unicode printing." -msgstr "" -"Zobacz również wiki `Pretty Printing `_, gdzie znajdziesz więcej przykładów ładnego wyświetlania " -"w unicode." - -# 94bfede151d644018a32c34ddccf9f83 -#: ../../src/tutorial.rst:860 -#, fuzzy -msgid "" -"Tip: To make pretty printing the default in the Python interpreter, use::" -msgstr "" -"Wskazówka: Aby ustawić ładne wyświetlanie w interpreterze Pythona jako " -"domyśle, skorzystaj z::" - -# 05d75c03895f494aa7f408afae22f63c -#: ../../src/tutorial.rst:883 -msgid "**Python printing**" -msgstr "**Wyświetlanie w Pythonie**" - -# c336c06cddc84625b82021ef70a0ac16 -#: ../../src/tutorial.rst:899 -msgid "**LaTeX printing**" -msgstr "**Wyświetlanie w LaTeX-u**" - -# de4a12f93cb4489d96a6ad4b7f8739e4 -#: ../../src/tutorial.rst:916 -msgid "**MathML**" -msgstr "**MathML**" - -# 117fce629184423cb2a51a77b484ea61 -#: ../../src/tutorial.rst:928 -msgid "**Pyglet**" -msgstr "**Pyglet**" - -# 96f565871b674bf1b3d0e4d3a52f2a8f -#: ../../src/tutorial.rst:934 -#, fuzzy -msgid "" -"If pyglet is installed, a pyglet window will open containing the LaTeX " -"rendered expression:" -msgstr "Pojawi się okienko Pygleta z wyrenderowanym wyrażeniem LaTeX-a:" - -# d2721f4f41694f60962a0c42c2bd4983 -#: ../../src/tutorial.rst:940 -msgid "Notes" -msgstr "Uwagi" - -# e8ad9afd6762437ea704794911463e48 -#: ../../src/tutorial.rst:942 -msgid "" -"``isympy`` calls ``pprint`` automatically, so that's why you see pretty " -"printing by default." -msgstr "" -"``isympy`` wywołuje ``pprint`` automatycznie, dlatego domyślnie jest tam " -"używane ładne wyświetlanie." - -# 0de34c98889b4085b745ba32f9b14757 -#: ../../src/tutorial.rst:945 -msgid "" -"Note that there is also a printing module available, ``sympy.printing``. " -"Other printing methods available through this module are:" -msgstr "" -"Warto zauważyć, że jest dostępny także moduł wyświetlania, ``sympy." -"printing``. Dzięki niemu można skorzystać z innych sposobów wyświetlania:" - -# edbe2baff196446dbb0ff0f4de6871f3 -#: ../../src/tutorial.rst:948 -msgid "" -"``pretty(expr)``, ``pretty_print(expr)``, ``pprint(expr)``: Return or print, " -"respectively, a pretty representation of ``expr``. This is the same as the " -"second level of representation described above." -msgstr "" -"``pretty(expr)``, ``pretty_print(expr)``, ``pprint(expr)``: odpowiednio " -"zwraca lub wyświetla ładną reprezentację wyrażenia ``expr``. Jest to to " -"samo, co drugi sposób wyświetlania opisany powyżej." - -# 4d8ffbde38424598a82ac2aafa525ae4 -#: ../../src/tutorial.rst:950 -msgid "" -"``latex(expr)``, ``print_latex(expr)``: Return or print, respectively, a " -"`LaTeX `_ representation of ``expr``" -msgstr "" -"``latex(expr)``, ``print_latex(expr)``: odpowiednio zwraca lub wyświetla " -"reprezentację wyrażenia ``expr`` w `LaTeX `_-" -"u." - -# 43a55e2b14a04d84b2ac4287a889fb81 -#: ../../src/tutorial.rst:952 -msgid "" -"``mathml(expr)``, ``print_mathml(expr)``: Return or print, respectively, a " -"`MathML `_ representation of ``expr``." -msgstr "" -"``mathml(expr)``, ``print_mathml(expr)``: odpowiednio zwraca lub wyświetla " -"reprezentację wyrażenia ``expr`` w `MathML `_-u." - -# 7f86eed4608f4e34a819dd77a40f4435 -#: ../../src/tutorial.rst:954 -msgid "" -"``print_gtk(expr)``: Print ``expr`` to `Gtkmathview `_, a GTK widget that displays MathML code. The `Gtkmathview " -"`_ program is required." -msgstr "" -"``print_gtk(expr)``: wysyła wyrażenie ``expr`` do `Gtkmathview `_, czyli widgetu GTK, który wyświetla kod MathML. " -"Wymagany jest program `Gtkmathview `_." - -# 31f85b92c0a94cf7b3c6bed30ea313be -#: ../../src/tutorial.rst:957 -msgid "Further documentation" -msgstr "Dalsza dokumentacja" - -# 89862ab0b6cb4d1190f447db5f55974b -#: ../../src/tutorial.rst:959 -msgid "" -"Now it's time to learn more about SymPy. Go through the :ref:`SymPy User's " -"Guide ` and :ref:`SymPy Modules Reference `." -msgstr "" -"Teraz nadszedł czas, by dowiedzieć się więcej na temat SymPy. Przejdź do :" -"ref:`Przewodniku użytkownika ` oraz :ref:`Opisu modułów SymPy `." - -# bea4d9e549134830a8f77a913bac65b1 -#: ../../src/tutorial.rst:963 -#, fuzzy -msgid "" -"Be sure to also browse our public `wiki.sympy.org `_, that contains a lot of useful examples, tutorials, cookbooks that we " -"and our users contributed, and feel free to edit it." -msgstr "" -"Zajrzyj także na nasze publiczne `wiki.sympy.org `_, " -"które zawiera wiele użytecznych przykładów, tutoriali, a także instrukcji " -"krok po kroku. Przygotowaliśmy je my i nasi użytkownicy. Ciebie również " -"zachęcamy do edycji." - -# d6c1908345d1415296e33daaeaa1ee21 -#: ../../src/tutorial.rst:968 -msgid "Translations" -msgstr "" - -# 1c1b1120057c4cd880583fc0d619b4eb -#: ../../src/tutorial.rst:970 -msgid "This tutorial is also available in other languages:" -msgstr "" - -# 157f4fafe0924d50be5801527071ae4c -#~ msgid "That should print the following after the execution::" -#~ msgstr "Po wykonaniu powinno wypisać::" diff -Nru python3-sympy-0.7.2/doc/src/tutorial.pot python3-sympy-0.7.3/doc/src/tutorial.pot --- python3-sympy-0.7.2/doc/src/tutorial.pot 2012-10-17 02:30:33.000000000 +0000 +++ python3-sympy-0.7.3/doc/src/tutorial.pot 1970-01-01 00:00:00.000000000 +0000 @@ -1,524 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) 2008, 2009, 2010, 2011, 2012 SymPy Development Team -# This file is distributed under the same license as the SymPy package. -# FIRST AUTHOR , YEAR. -# -#, fuzzy -msgid "" -msgstr "" -"Project-Id-Version: SymPy 0.7.2\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2012-08-14 15:40\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: FULL NAME \n" -"Language-Team: LANGUAGE \n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" - -#: ../../src/tutorial.rst:5 -# 797a60e1e7a74e14837bbcab15fb757a -msgid "Tutorial" -msgstr "" - -#: ../../src/tutorial.rst:10 -# 694d4f9f41d14cd9bc914f4be25e4baf -msgid "Introduction" -msgstr "" - -#: ../../src/tutorial.rst:12 -# 5f67051f31e3458b8f7de60165d90462 -msgid "SymPy is a Python library for symbolic mathematics. It aims to become a full-featured computer algebra system (CAS) while keeping the code as simple as possible in order to be comprehensible and easily extensible. SymPy is written entirely in Python and does not require any external libraries." -msgstr "" - -#: ../../src/tutorial.rst:17 -# 9f8294eca5ab42c3a808af5ea304398b -msgid "This tutorial gives an overview and introduction to SymPy. Read this to have an idea what SymPy can do for you (and how) and if you want to know more, read the :ref:`SymPy User's Guide `, :ref:`SymPy Modules Reference `. or the `sources `_ directly." -msgstr "" - -#: ../../src/tutorial.rst:26 -# 59d551b4cebb408b9f23419795dae297 -msgid "First Steps with SymPy" -msgstr "" - -#: ../../src/tutorial.rst:28 -# 8bc5afc77b944a71bf65ce2b0fed35e0 -msgid "The easiest way to download it is to go to http://code.google.com/p/sympy/ and download the latest tarball from the Featured Downloads:" -msgstr "" - -#: ../../src/tutorial.rst:34 -# aef81353a2d4449ea6dabf008cf56267 -msgid "Unpack it:" -msgstr "" - -#: ../../src/tutorial.rst:40 -# 83335e43ba4d4f358cbab0cf054fc342 -msgid "and try it from a Python interpreter:" -msgstr "" - -#: ../../src/tutorial.rst:54 -# d7f4d41080d744c6af234c5d263cad57 -msgid "You can use SymPy as shown above and this is indeed the recommended way if you use it in your program. You can also install it using ``./setup.py install`` as any other Python module, or just install a package in your favourite Linux distribution, e.g.:" -msgstr "" - -#: ../../src/tutorial.rst:80 -# df97c2e282e54cb0ab7a3bad8b55c997 -msgid "For other means how to install SymPy, consult the Downloads_ tab on the SymPy's webpage." -msgstr "" - -#: ../../src/tutorial.rst:87 -# fcb4327a07964957b5dc6925404e3dbe -msgid "isympy Console" -msgstr "" - -#: ../../src/tutorial.rst:89 -# 82453b19d3884acba2447546f4b025f8 -msgid "For experimenting with new features, or when figuring out how to do things, you can use our special wrapper around IPython called ``isympy`` (located in ``bin/isympy`` if you are running from the source directory) which is just a standard Python shell that has already imported the relevant SymPy modules and defined the symbols x, y, z and some other things:" -msgstr "" - -#: ../../src/tutorial.rst:119 -# 4c51aca801e2413c87b675b0803a9c89 -msgid "Commands entered by you are bold. Thus what we did in 3 lines in a regular Python interpreter can be done in 1 line in isympy." -msgstr "" - -#: ../../src/tutorial.rst:124 -# c1e8de7a967f412ba7d0a81b6fae15d1 -msgid "Using SymPy as a calculator" -msgstr "" - -#: ../../src/tutorial.rst:126 -# c316d4883e934316ac47807cbcf69185 -msgid "SymPy has three built-in numeric types: Float, Rational and Integer." -msgstr "" - -#: ../../src/tutorial.rst:128 -# a53f23278ac74ff4b4dd529f95328d90 -msgid "The Rational class represents a rational number as a pair of two Integers: the numerator and the denominator. So Rational(1,2) represents 1/2, Rational(5,2) represents 5/2, and so on." -msgstr "" - -#: ../../src/tutorial.rst:147 -# 7c55e3cc4b9140f990a287884d709761 -msgid "Proceed with caution while working with Python int's and floating point numbers, especially in division, since you may create a Python number, not a SymPy number. A ratio of two Python ints may create a float -- the \"true division\" standard of Python 3 and the default behavior of ``isympy`` which imports division from __future__::" -msgstr "" - -#: ../../src/tutorial.rst:157 -# 3606c652f0b84c0b95a6b0ec2b5c8542 -msgid "But in earlier Python versions where division has not been imported, a truncated int will result::" -msgstr "" - -#: ../../src/tutorial.rst:163 -# 97ad890d7ce54755b264190dbf453b68 -msgid "In both cases, however, you are not dealing with a SymPy Number because Python created its own number. Most of the time you will probably be working with Rational numbers, so make sure to use Rational to get the SymPy result. One might find it convenient to equate ``R`` and Rational::" -msgstr "" - -#: ../../src/tutorial.rst:175 -# 0252fb340da849229b7c654aaefd5861 -msgid "We also have some special constants, like e and pi, that are treated as symbols (1+pi won't evaluate to something numeric, rather it will remain as 1+pi), and have arbitrary precision::" -msgstr "" - -#: ../../src/tutorial.rst:189 -# dd561f4e747f462faa1248e10794944e -msgid "as you see, evalf evaluates the expression to a floating-point number" -msgstr "" - -#: ../../src/tutorial.rst:191 -# 0c6d36742fe44f678ce965a85422e237 -msgid "The symbol ``oo`` is used for a class defining mathematical infinity::" -msgstr "" - -#: ../../src/tutorial.rst:200 -# 20b6a777141744dc9875ddbb1e8dfd1a -msgid "Symbols" -msgstr "" - -#: ../../src/tutorial.rst:202 -# c39b3026fd904e4797c99ad8c90aad82 -msgid "In contrast to other Computer Algebra Systems, in SymPy you have to declare symbolic variables explicitly::" -msgstr "" - -#: ../../src/tutorial.rst:209 -# 597af052184b48e8a70829bc8fe0fbe6 -msgid "On the left is the normal Python variable which has been assigned to the SymPy Symbol class. Predefined symbols (including those for symbols with Greek names) are available for import from abc:" -msgstr "" - -#: ../../src/tutorial.rst:215 -# beba4c07583f424c8077b432b138c274 -msgid "Symbols can also be created with the ``symbols`` or ``var`` functions, the latter automatically adding the created symbols to the namespace, and both accepting a range notation:" -msgstr "" - -#: ../../src/tutorial.rst:227 -# ecc96f5a54cb4614a4835865c96c592c -msgid "Instances of the Symbol class \"play well together\" and are the building blocks of expresions::" -msgstr "" - -#: ../../src/tutorial.rst:239 -# 310787af60514a16b2e3f9565335aa92 -msgid "They can be substituted with other numbers, symbols or expressions using ``subs(old, new)``::" -msgstr "" - -#: ../../src/tutorial.rst:250 -# beeef943c0a24619ba138067c013e0d8 -msgid "For the remainder of the tutorial, we assume that we have run::" -msgstr "" - -#: ../../src/tutorial.rst:255 -# 3103676258cb4ea59276c945850cb50c -msgid "This will make things look better when printed. See the :ref:`printing-tutorial` section below. If you have a unicode font installed, you can pass use_unicode=True for a slightly nicer output." -msgstr "" - -#: ../../src/tutorial.rst:260 -# cf97ceae4d7744dd8666d3ac937621bb -msgid "Algebra" -msgstr "" - -#: ../../src/tutorial.rst:262 -# 9f902ba9794d4df1912148e298061810 -msgid "For partial fraction decomposition, use ``apart(expr, x)``::" -msgstr "" - -#: ../../src/tutorial.rst:287 -# 3e07a93ab80c4c5794912ba3ebdf88c2 -msgid "To combine things back together, use ``together(expr, x)``::" -msgstr "" - -#: ../../src/tutorial.rst:309 -# eb560222e88a4d2dbec0a8ba4faced75 -msgid "Calculus" -msgstr "" - -#: ../../src/tutorial.rst:314 -# f091d0a906df495cadd705af0694136f -msgid "Limits" -msgstr "" - -#: ../../src/tutorial.rst:316 -# 3a07a00cf5764ec19f30817f3066c738 -msgid "Limits are easy to use in SymPy, they follow the syntax ``limit(function, variable, point)``, so to compute the limit of f(x) as x -> 0, you would issue ``limit(f, x, 0)``::" -msgstr "" - -#: ../../src/tutorial.rst:325 -# 58d9420a44614acc8b507a18c4537ed1 -msgid "you can also calculate the limit at infinity::" -msgstr "" - -#: ../../src/tutorial.rst:336 -# 1db24bdb84eb4c1e837d5bde0676b148 -msgid "for some non-trivial examples on limits, you can read the test file `test_demidovich.py `_" -msgstr "" - -#: ../../src/tutorial.rst:343 -# 4bd0f3ca175b4255aa12fd8c17f6f98b -msgid "Differentiation" -msgstr "" - -#: ../../src/tutorial.rst:345 -# 4bbffd6d7f0643d188b086951a31ed3d -msgid "You can differentiate any SymPy expression using ``diff(func, var)``. Examples::" -msgstr "" - -#: ../../src/tutorial.rst:358 -# cf8e314365b5421189f9f065e37de271 -msgid "You can check, that it is correct by::" -msgstr "" - -#: ../../src/tutorial.rst:366 -# d3c3002827ab4bf4983ed7f249fe6e6d -msgid "Higher derivatives can be calculated using the ``diff(func, var, n)`` method::" -msgstr "" - -#: ../../src/tutorial.rst:383 -# 7c8fad31977547ad8c5e9a3fd63733af -msgid "Series expansion" -msgstr "" - -#: ../../src/tutorial.rst:385 -# cbe2b6c237a74cccadba92a3e8dc9c50 -msgid "Use ``.series(var, point, order)``::" -msgstr "" - -#: ../../src/tutorial.rst:400 -# 6cd9478c5dd842baa488d1502cea6826 -msgid "Another simple example::" -msgstr "" - -#: ../../src/tutorial.rst:424 -# 588350b07e8946c3990190b5e03eeb79 -msgid "Summation" -msgstr "" - -#: ../../src/tutorial.rst:426 -# c8e0a258ce834d868419e0aed64142e9 -msgid "Compute the summation of f with respect to the given summation variable over the given limits." -msgstr "" - -#: ../../src/tutorial.rst:428 -# 8399e19ad841458d9a517e24cd647081 -msgid "summation(f, (i, a, b)) computes the sum of f with respect to i from a to b, i.e., ::" -msgstr "" - -#: ../../src/tutorial.rst:439 -# 2257b464c29d4d7f8fad17e106053f41 -msgid "If it cannot compute the sum, it prints the corresponding summation formula. Repeated sums can be computed by introducing additional limits::" -msgstr "" - -#: ../../src/tutorial.rst:473 -# de759fd1a1dc44e78202bb06b93c845b -msgid "Integration" -msgstr "" - -#: ../../src/tutorial.rst:475 -# 211e9ff8aff14ac98e2e7871f7d2ddc7 -msgid "SymPy has support for indefinite and definite integration of transcendental elementary and special functions via ``integrate()`` facility, which uses powerful extended Risch-Norman algorithm and some heuristics and pattern matching::" -msgstr "" - -#: ../../src/tutorial.rst:483 -# 2dd4f29b48374377b4097bf742035668 -msgid "You can integrate elementary functions::" -msgstr "" - -#: ../../src/tutorial.rst:496 -# 51af74ff60d54efbbcdfe7d197934621 -msgid "Also special functions are handled easily::" -msgstr "" - -#: ../../src/tutorial.rst:504 -# 4dfa135fdf63484084f0ddc6df45e9bb -msgid "It is possible to compute definite integrals::" -msgstr "" - -#: ../../src/tutorial.rst:513 -# ca7dd42a70a2432a9ea9a23aaff5191e -msgid "Also, improper integrals are supported as well::" -msgstr "" - -#: ../../src/tutorial.rst:525 -# cf11e45361464a658e12b49fcfeb8a00 -msgid "Complex numbers" -msgstr "" - -#: ../../src/tutorial.rst:527 -# a1aeb9f0079544e5bf8b2dd8e56f1115 -msgid "Besides the imaginary unit, I, which is imaginary, symbols can be created with attributes (e.g. real, positive, complex, etc...) and this will affect how they behave::" -msgstr "" - -#: ../../src/tutorial.rst:544 -# 00e2f48d0fbf4eddb9d88cc90c78989c -msgid "Functions" -msgstr "" - -#: ../../src/tutorial.rst:546 -# e727aeeb244b4ac5968e4c2bcd892b9c -msgid "**trigonometric**::" -msgstr "" - -#: ../../src/tutorial.rst:595 -# 978ef55cdcc34d4eb11f4227ff6d2f78 -msgid "**spherical harmonics**::" -msgstr "" - -#: ../../src/tutorial.rst:621 -# 47d63c8636d74819bfdc3ad9ea58d5e6 -msgid "**factorials and gamma function**::" -msgstr "" - -#: ../../src/tutorial.rst:639 -# 0ed99c3baa074d2e8898bfa0b80618d8 -msgid "**zeta function**::" -msgstr "" - -#: ../../src/tutorial.rst:664 -# ac0a6704385f433db0178db4e564002e -msgid "**polynomials**::" -msgstr "" - -#: ../../src/tutorial.rst:703 -# e38b73dcf7664565a8988fb07c8af8e1 -msgid "Differential Equations" -msgstr "" - -#: ../../src/tutorial.rst:705 -#: ../../src/tutorial.rst:725 -# 4016bebf2ad94734b9d4d9de708df62c -# 0cc26ff25a544f7a87155232739231f3 -msgid "In ``isympy``::" -msgstr "" - -#: ../../src/tutorial.rst:723 -# 3c60689f195a470a8e024d31083b4dd1 -msgid "Algebraic equations" -msgstr "" - -#: ../../src/tutorial.rst:738 -# fd9d74fbf8ab4b4590977cd3047a9f62 -msgid "Linear Algebra" -msgstr "" - -#: ../../src/tutorial.rst:743 -# b86acf610fc84e54bfc1631771d43cd1 -msgid "Matrices" -msgstr "" - -#: ../../src/tutorial.rst:745 -# 539e9e2546cd47a39db1b8d78449857e -msgid "Matrices are created as instances from the Matrix class::" -msgstr "" - -#: ../../src/tutorial.rst:753 -# 1542c430b5d944a286654fdda65a8dbf -msgid "They can also contain symbols::" -msgstr "" - -#: ../../src/tutorial.rst:768 -# c3cc5b816c0e44eaa2e603961fd0a5b9 -msgid "For more about Matrices, see the Linear Algebra tutorial." -msgstr "" - -#: ../../src/tutorial.rst:773 -# 9738a09d1b084d7182f0b1c153914b11 -msgid "Pattern matching" -msgstr "" - -#: ../../src/tutorial.rst:775 -# 324e7ca99fc041c190bfa0ac0d699a13 -msgid "Use the ``.match()`` method, along with the ``Wild`` class, to perform pattern matching on expressions. The method will return a dictionary with the required substitutions, as follows::" -msgstr "" - -#: ../../src/tutorial.rst:789 -# 4401ed63901e4fb9a230ce61ade8e4e4 -msgid "If the match is unsuccessful, it returns ``None``::" -msgstr "" - -#: ../../src/tutorial.rst:794 -# 0652a43faa694e43b83b53da80710ff3 -msgid "One can also use the exclude parameter of the ``Wild`` class to ensure that certain things do not show up in the result::" -msgstr "" - -#: ../../src/tutorial.rst:808 -# 9683608b71004bd5a2f0d96aac505ef3 -msgid "Printing" -msgstr "" - -#: ../../src/tutorial.rst:810 -# e48db6ee80b54de8b13bd71b06763d5b -msgid "There are many ways to print expressions." -msgstr "" - -#: ../../src/tutorial.rst:812 -# e76007bea24746d789e06daf17e207de -msgid "**Standard**" -msgstr "" - -#: ../../src/tutorial.rst:814 -# 6eab3292b541486eb55bbc391560e9e2 -msgid "This is what ``str(expression)`` returns and it looks like this:" -msgstr "" - -#: ../../src/tutorial.rst:825 -# d1f80048c60d4eb4a1a34bac3781c93c -msgid "**Pretty printing**" -msgstr "" - -#: ../../src/tutorial.rst:827 -# 489ad0ac51a740069669fcd233e50fe8 -msgid "Nice ascii-art printing is produced by the ``pprint`` function:" -msgstr "" - -#: ../../src/tutorial.rst:846 -# 2ffb727db38348a5adb99f72aebed4b5 -msgid "If you have a unicode font installed, the ``pprint`` function will use it by default. You can override this using the ``use_unicode`` option.:" -msgstr "" - -#: ../../src/tutorial.rst:856 -# 4c1f772a88b54beeb744e7b9909b4f0a -msgid "See also the wiki `Pretty Printing `_ for more examples of a nice unicode printing." -msgstr "" - -#: ../../src/tutorial.rst:860 -# 7f8e233ccbd9463392defe5764b65cbc -msgid "Tip: To make pretty printing the default in the Python interpreter, use::" -msgstr "" - -#: ../../src/tutorial.rst:883 -# 41d709e6b75c4f0c86b66e8e99a57246 -msgid "**Python printing**" -msgstr "" - -#: ../../src/tutorial.rst:899 -# 25ecdc1913ce4ff4afb7fac10c302c85 -msgid "**LaTeX printing**" -msgstr "" - -#: ../../src/tutorial.rst:916 -# ae9a7a5f6f6a43eda9d48afece98c7af -msgid "**MathML**" -msgstr "" - -#: ../../src/tutorial.rst:928 -# 52f39b7c84d94726b7325926ac10c932 -msgid "**Pyglet**" -msgstr "" - -#: ../../src/tutorial.rst:934 -# 50bef9a51cf942738ad7b1dec926b2a0 -msgid "If pyglet is installed, a pyglet window will open containing the LaTeX rendered expression:" -msgstr "" - -#: ../../src/tutorial.rst:940 -# 010b2dd2c3e24eafb511a46133f26b6d -msgid "Notes" -msgstr "" - -#: ../../src/tutorial.rst:942 -# baaa06b2a6cf48eda7f00fa25b524d6a -msgid "``isympy`` calls ``pprint`` automatically, so that's why you see pretty printing by default." -msgstr "" - -#: ../../src/tutorial.rst:945 -# 281aae537d0143c48b36678cdf086918 -msgid "Note that there is also a printing module available, ``sympy.printing``. Other printing methods available through this module are:" -msgstr "" - -#: ../../src/tutorial.rst:948 -# e5a222f58acb434296e162ffd917315f -msgid "``pretty(expr)``, ``pretty_print(expr)``, ``pprint(expr)``: Return or print, respectively, a pretty representation of ``expr``. This is the same as the second level of representation described above." -msgstr "" - -#: ../../src/tutorial.rst:950 -# 8066e9e9e73041cbb9e53611f085a66f -msgid "``latex(expr)``, ``print_latex(expr)``: Return or print, respectively, a `LaTeX `_ representation of ``expr``" -msgstr "" - -#: ../../src/tutorial.rst:952 -# 3684b20c2c8943ae9490a578fa30ed37 -msgid "``mathml(expr)``, ``print_mathml(expr)``: Return or print, respectively, a `MathML `_ representation of ``expr``." -msgstr "" - -#: ../../src/tutorial.rst:954 -# 73701a5e920a451cb1cdb3e5009174eb -msgid "``print_gtk(expr)``: Print ``expr`` to `Gtkmathview `_, a GTK widget that displays MathML code. The `Gtkmathview `_ program is required." -msgstr "" - -#: ../../src/tutorial.rst:957 -# 590fba86b8fe49779d1a210da22564b1 -msgid "Further documentation" -msgstr "" - -#: ../../src/tutorial.rst:959 -# eb31b70391fa4fc186158c0d25085984 -msgid "Now it's time to learn more about SymPy. Go through the :ref:`SymPy User's Guide ` and :ref:`SymPy Modules Reference `." -msgstr "" - -#: ../../src/tutorial.rst:963 -# 566f00c00f584672a5040c5e08679e95 -msgid "Be sure to also browse our public `wiki.sympy.org `_, that contains a lot of useful examples, tutorials, cookbooks that we and our users contributed, and feel free to edit it." -msgstr "" - -#: ../../src/tutorial.rst:968 -# d6c1908345d1415296e33daaeaa1ee21 -msgid "Translations" -msgstr "" - -#: ../../src/tutorial.rst:970 -# 1c1b1120057c4cd880583fc0d619b4eb -msgid "This tutorial is also available in other languages:" -msgstr "" diff -Nru python3-sympy-0.7.2/doc/src/tutorial.rst python3-sympy-0.7.3/doc/src/tutorial.rst --- python3-sympy-0.7.2/doc/src/tutorial.rst 2012-10-17 03:02:20.000000000 +0000 +++ python3-sympy-0.7.3/doc/src/tutorial.rst 1970-01-01 00:00:00.000000000 +0000 @@ -1,973 +0,0 @@ -.. _tutorial: - -======== -Tutorial -======== - -.. role:: input(strong) - -Introduction -============ - -SymPy is a Python library for symbolic mathematics. It aims to become a -full-featured computer algebra system (CAS) while keeping the code as simple as -possible in order to be comprehensible and easily extensible. SymPy is written -entirely in Python and does not require any external libraries. - -This tutorial gives an overview and introduction to SymPy. -Read this to have an idea what SymPy can do for you (and how) and if you want -to know more, read the -:ref:`SymPy User's Guide `, -:ref:`SymPy Modules Reference `. -or the `sources -`_ directly. - -First Steps with SymPy -====================== - -The easiest way to download it is to go to -http://code.google.com/p/sympy/ and -download the latest tarball from the Featured Downloads: - -.. image:: figures/featured-downloads.png - -Unpack it: - -.. parsed-literal:: - - $ :input:`tar xzf sympy-0.5.12.tar.gz` - -and try it from a Python interpreter: - -.. parsed-literal:: - - $ :input:`cd sympy-0.5.12` - $ :input:`python` - Python 2.4.4 (#2, Jan 3 2008, 13:36:28) - [GCC 4.2.3 20071123 (prerelease) (Debian 4.2.2-4)] on linux2 - Type "help", "copyright", "credits" or "license" for more information. - >>> from sympy import Symbol, cos - >>> x = Symbol("x") - >>> (1/cos(x)).series(x, 0, 10) - 1 + x**2/2 + 5*x**4/24 + 61*x**6/720 + 277*x**8/8064 + O(x**10) - -You can use SymPy as shown above and this is indeed the recommended way if you -use it in your program. You can also install it using ``./setup.py install`` as -any other Python module, or just install a package in your favourite Linux -distribution, e.g.: - -.. topic:: Installing SymPy in Debian - - .. parsed-literal:: - - $ :input:`sudo apt-get install python-sympy` - Reading package lists... Done - Building dependency tree - Reading state information... Done - The following NEW packages will be installed: - python-sympy - 0 upgraded, 1 newly installed, 0 to remove and 18 not upgraded. - Need to get 991kB of archives. - After this operation, 5976kB of additional disk space will be used. - Get:1 http://ftp.cz.debian.org unstable/main python-sympy 0.5.12-1 [991kB] - Fetched 991kB in 2s (361kB/s) - Selecting previously deselected package python-sympy. - (Reading database ... 232619 files and directories currently installed.) - Unpacking python-sympy (from .../python-sympy_0.5.12-1_all.deb) ... - Setting up python-sympy (0.5.12-1) ... - - -For other means how to install SymPy, consult the Downloads_ tab on the -SymPy's webpage. - -.. _Downloads: http://code.google.com/p/sympy/wiki/DownloadInstallation?tm=2 - - -isympy Console --------------- - -For experimenting with new features, or when figuring out how to do things, you -can use our special wrapper around IPython called ``isympy`` (located in -``bin/isympy`` if you are running from the source directory) which is just a -standard Python shell that has already imported the relevant SymPy modules and -defined the symbols x, y, z and some other things: - -.. parsed-literal:: - - $ :input:`cd sympy` - $ :input:`./bin/isympy` - IPython console for SymPy 0.7.2 (Python 2.7.1) (ground types: gmpy) - - These commands were executed: - >>> - >>> from sympy import * - >>> x, y, z, t = symbols('x y z t') - >>> k, m, n = symbols('k m n', integer=True) - >>> f, g, h = symbols('f g h', cls=Function) - - Documentation can be found at http://www.sympy.org - - In [1]: :input:`(1/cos(x)).series(x, 0, 10)` - Out[1]: - 2 4 6 8 - x 5*x 61*x 277*x / 10\\ - 1 + -- + ---- + ----- + ------ + O\\x / - 2 24 720 8064 - -.. note:: - - Commands entered by you are bold. Thus what we did in 3 lines in a regular - Python interpreter can be done in 1 line in isympy. - - -Using SymPy as a calculator ---------------------------- - -SymPy has three built-in numeric types: Float, Rational and Integer. - -The Rational class represents a rational number as a pair of two Integers: -the numerator and the denominator. So Rational(1,2) represents 1/2, -Rational(5,2) represents 5/2, and so on. - -:: - - >>> from sympy import Rational - >>> a = Rational(1,2) - - >>> a - 1/2 - - >>> a*2 - 1 - - >>> Rational(2)**50/Rational(10)**50 - 1/88817841970012523233890533447265625 - - -Proceed with caution while working with Python int's and floating -point numbers, especially in division, since you may create a -Python number, not a SymPy number. A ratio of two Python ints may -create a float -- the "true division" standard of Python 3 -and the default behavior of ``isympy`` which imports division -from __future__:: - - >>> 1/2 #doctest: +SKIP - 0.5 - -But in earlier Python versions where division has not been imported, a -truncated int will result:: - - >>> 1/2 #doctest: +SKIP - 0 - -In both cases, however, you are not dealing with a SymPy Number because -Python created its own number. Most of the time you will probably be -working with Rational numbers, so make sure to use Rational to get -the SymPy result. One might find it convenient to equate ``R`` and -Rational:: - - >>> R = Rational - >>> R(1, 2) - 1/2 - >>> R(1)/2 # R(1) is a SymPy Integer and Integer/int gives a Rational - 1/2 - -We also have some special constants, like e and pi, that are treated as symbols -(1+pi won't evaluate to something numeric, rather it will remain as 1+pi), and -have arbitrary precision:: - - >>> from sympy import pi, E - >>> pi**2 - pi**2 - - >>> pi.evalf() - 3.14159265358979 - - >>> (pi + E).evalf() - 5.85987448204884 - -as you see, evalf evaluates the expression to a floating-point number - -The symbol ``oo`` is used for a class defining mathematical infinity:: - - >>> from sympy import oo - >>> oo > 99999 - True - >>> oo + 1 - oo - -Symbols -------- - -In contrast to other Computer Algebra Systems, in SymPy you have to declare -symbolic variables explicitly:: - - >>> from sympy import Symbol - >>> x = Symbol('x') - >>> y = Symbol('y') - -On the left is the normal Python variable which has been assigned to the -SymPy Symbol class. Predefined symbols (including those for symbols with -Greek names) are available for import from abc: - - >>> from sympy.abc import x, theta - -Symbols can also be created with the ``symbols`` or ``var`` functions, the -latter automatically adding the created symbols to the namespace, and both -accepting a range notation: - - >>> from sympy import symbols, var - >>> a, b, c = symbols('a,b,c') - >>> d, e, f = symbols('d:f') - >>> var('g:h') - (g, h) - >>> var('g:2') - (g0, g1) - -Instances of the Symbol class "play well together" and are the building blocks -of expresions:: - - >>> x+y+x-y - 2*x - - >>> (x+y)**2 - (x + y)**2 - - >>> ((x+y)**2).expand() - x**2 + 2*x*y + y**2 - -They can be substituted with other numbers, symbols or expressions using ``subs(old, new)``:: - - >>> ((x+y)**2).subs(x, 1) - (y + 1)**2 - - >>> ((x+y)**2).subs(x, y) - 4*y**2 - - >>> ((x+y)**2).subs(x, 1-y) - 1 - -For the remainder of the tutorial, we assume that we have run:: - - >>> from sympy import init_printing - >>> init_printing(use_unicode=False, wrap_line=False, no_global=True) - -This will make things look better when printed. See the :ref:`printing-tutorial` -section below. If you have a unicode font installed, you can pass -use_unicode=True for a slightly nicer output. - -Algebra -======= - -For partial fraction decomposition, use ``apart(expr, x)``:: - - >>> from sympy import apart - >>> from sympy.abc import x, y, z - - >>> 1/( (x+2)*(x+1) ) - 1 - --------------- - (x + 1)*(x + 2) - - >>> apart(1/( (x+2)*(x+1) ), x) - 1 1 - - ----- + ----- - x + 2 x + 1 - - >>> (x+1)/(x-1) - x + 1 - ----- - x - 1 - - >>> apart((x+1)/(x-1), x) - 2 - 1 + ----- - x - 1 - -To combine things back together, use ``together(expr, x)``:: - - >>> from sympy import together - >>> together(1/x + 1/y + 1/z) - x*y + x*z + y*z - --------------- - x*y*z - - >>> together(apart((x+1)/(x-1), x), x) - x + 1 - ----- - x - 1 - - >>> together(apart(1/( (x+2)*(x+1) ), x), x) - 1 - --------------- - (x + 1)*(x + 2) - - -.. index:: calculus - -Calculus -======== - -.. index:: limits - -Limits ------- - -Limits are easy to use in SymPy, they follow the syntax ``limit(function, -variable, point)``, so to compute the limit of f(x) as x -> 0, you would issue -``limit(f, x, 0)``:: - - >>> from sympy import limit, Symbol, sin, oo - >>> x = Symbol("x") - >>> limit(sin(x)/x, x, 0) - 1 - -you can also calculate the limit at infinity:: - - >>> limit(x, x, oo) - oo - - >>> limit(1/x, x, oo) - 0 - - >>> limit(x**x, x, 0) - 1 - -for some non-trivial examples on limits, you can read the test file -`test_demidovich.py -`_ - -.. index:: differentiation, diff - -Differentiation ---------------- - -You can differentiate any SymPy expression using ``diff(func, var)``. Examples:: - - >>> from sympy import diff, Symbol, sin, tan - >>> x = Symbol('x') - >>> diff(sin(x), x) - cos(x) - >>> diff(sin(2*x), x) - 2*cos(2*x) - - >>> diff(tan(x), x) - 2 - tan (x) + 1 - -You can check, that it is correct by:: - - >>> from sympy import limit - >>> from sympy.abc import delta - >>> limit((tan(x + delta) - tan(x))/delta, delta, 0) - 2 - tan (x) + 1 - -Higher derivatives can be calculated using the ``diff(func, var, n)`` method:: - - >>> diff(sin(2*x), x, 1) - 2*cos(2*x) - - >>> diff(sin(2*x), x, 2) - -4*sin(2*x) - - >>> diff(sin(2*x), x, 3) - -8*cos(2*x) - - -.. index:: - single: series expansion - single: expansion; series - -Series expansion ----------------- - -Use ``.series(var, point, order)``:: - - >>> from sympy import Symbol, cos - >>> x = Symbol('x') - >>> cos(x).series(x, 0, 10) - 2 4 6 8 - x x x x / 10\ - 1 - -- + -- - --- + ----- + O\x / - 2 24 720 40320 - >>> (1/cos(x)).series(x, 0, 10) - 2 4 6 8 - x 5*x 61*x 277*x / 10\ - 1 + -- + ---- + ----- + ------ + O\x / - 2 24 720 8064 - -Another simple example:: - - >>> from sympy import Integral, pprint - - >>> y = Symbol("y") - >>> e = 1/(x + y) - >>> s = e.series(x, 0, 5) - - >>> print(s) - 1/y - x/y**2 + x**2/y**3 - x**3/y**4 + x**4/y**5 + O(x**5) - >>> pprint(s) - 2 3 4 - 1 x x x x / 5\ - - - -- + -- - -- + -- + O\x / - y 2 3 4 5 - y y y y - - - - - -.. index:: summation - -Summation ---------- - -Compute the summation of f with respect to the given summation variable over the given limits. - -summation(f, (i, a, b)) computes the sum of f with respect to i from a to b, -i.e., :: - - b - ____ - \ ` - summation(f, (i, a, b)) = ) f - /___, - i = a - - -If it cannot compute the sum, it prints the corresponding summation formula. -Repeated sums can be computed by introducing additional limits:: - - >>> from sympy import summation, oo, symbols, log - >>> i, n, m = symbols('i n m', integer=True) - - >>> summation(2*i - 1, (i, 1, n)) - 2 - n - >>> summation(1/2**i, (i, 0, oo)) - 2 - >>> summation(1/log(n)**n, (n, 2, oo)) - oo - ___ - \ ` - \ -n - / log (n) - /__, - n = 2 - >>> summation(i, (i, 0, n), (n, 0, m)) - 3 2 - m m m - -- + -- + - - 6 2 3 - >>> from sympy.abc import x - >>> from sympy import factorial - >>> summation(x**n/factorial(n), (n, 0, oo)) - x - e - - -.. index:: integration - -Integration ------------ - -SymPy has support for indefinite and definite integration of transcendental -elementary and special functions via ``integrate()`` facility, which uses -powerful extended Risch-Norman algorithm and some heuristics and pattern -matching:: - - >>> from sympy import integrate, erf, exp, sin, log, oo, pi, sinh, symbols - >>> x, y = symbols('x,y') - -You can integrate elementary functions:: - - >>> integrate(6*x**5, x) - 6 - x - >>> integrate(sin(x), x) - -cos(x) - >>> integrate(log(x), x) - x*log(x) - x - >>> integrate(2*x + sinh(x), x) - 2 - x + cosh(x) - -Also special functions are handled easily:: - - >>> integrate(exp(-x**2)*erf(x), x) - ____ 2 - \/ pi *erf (x) - -------------- - 4 - -It is possible to compute definite integrals:: - - >>> integrate(x**3, (x, -1, 1)) - 0 - >>> integrate(sin(x), (x, 0, pi/2)) - 1 - >>> integrate(cos(x), (x, -pi/2, pi/2)) - 2 - -Also, improper integrals are supported as well:: - - >>> integrate(exp(-x), (x, 0, oo)) - 1 - >>> integrate(log(x), (x, 0, 1)) - -1 - -.. index:: - single: complex numbers - single: expansion; complex - -Complex numbers ---------------- - -Besides the imaginary unit, I, which is imaginary, symbols can be created with -attributes (e.g. real, positive, complex, etc...) and this will affect how -they behave:: - - >>> from sympy import Symbol, exp, I - >>> x = Symbol("x") # a plain x with no attributes - >>> exp(I*x).expand() - I*x - e - >>> exp(I*x).expand(complex=True) - -im(x) -im(x) - I*e *sin(re(x)) + e *cos(re(x)) - >>> x = Symbol("x", real=True) - >>> exp(I*x).expand(complex=True) - I*sin(x) + cos(x) - -Functions ---------- - -**trigonometric**:: - - >>> from sympy import asin, asinh, cos, sin, sinh, symbols, I - >>> x, y = symbols('x,y') - - >>> sin(x+y).expand(trig=True) - sin(x)*cos(y) + sin(y)*cos(x) - - >>> cos(x+y).expand(trig=True) - -sin(x)*sin(y) + cos(x)*cos(y) - - >>> sin(I*x) - I*sinh(x) - - >>> sinh(I*x) - I*sin(x) - - >>> asinh(I) - I*pi - ---- - 2 - - >>> asinh(I*x) - I*asin(x) - - >>> sin(x).series(x, 0, 10) - 3 5 7 9 - x x x x / 10\ - x - -- + --- - ---- + ------ + O\x / - 6 120 5040 362880 - - >>> sinh(x).series(x, 0, 10) - 3 5 7 9 - x x x x / 10\ - x + -- + --- + ---- + ------ + O\x / - 6 120 5040 362880 - - >>> asin(x).series(x, 0, 10) - 3 5 7 9 - x 3*x 5*x 35*x / 10\ - x + -- + ---- + ---- + ----- + O\x / - 6 40 112 1152 - - >>> asinh(x).series(x, 0, 10) - 3 5 7 9 - x 3*x 5*x 35*x / 10\ - x - -- + ---- - ---- + ----- + O\x / - 6 40 112 1152 - -**spherical harmonics**:: - - >>> from sympy import Ylm - >>> from sympy.abc import theta, phi - - >>> Ylm(1, 0, theta, phi) - ___ - \/ 3 *cos(theta) - ---------------- - ____ - 2*\/ pi - - >>> Ylm(1, 1, theta, phi) - ___ I*phi - -\/ 6 *e *sin(theta) - ------------------------ - ____ - 4*\/ pi - - >>> Ylm(2, 1, theta, phi) - ____ I*phi - -\/ 30 *e *sin(theta)*cos(theta) - ------------------------------------ - ____ - 4*\/ pi - -**factorials and gamma function**:: - - >>> from sympy import factorial, gamma, Symbol - >>> x = Symbol("x") - >>> n = Symbol("n", integer=True) - - >>> factorial(x) - x! - - >>> factorial(n) - n! - - >>> gamma(x + 1).series(x, 0, 3) # i.e. factorial(x) - / 2 2\ - 2 |EulerGamma pi | / 3\ - 1 - EulerGamma*x + x *|----------- + ---| + O\x / - \ 2 12/ - -**zeta function**:: - - >>> from sympy import zeta - >>> zeta(4, x) - zeta(4, x) - - >>> zeta(4, 1) - 4 - pi - --- - 90 - - >>> zeta(4, 2) - 4 - pi - -1 + --- - 90 - - >>> zeta(4, 3) - 4 - 17 pi - - -- + --- - 16 90 - - -**polynomials**:: - - >>> from sympy import assoc_legendre, chebyshevt, legendre, hermite - >>> chebyshevt(2, x) - 2 - 2*x - 1 - - >>> chebyshevt(4, x) - 4 2 - 8*x - 8*x + 1 - - >>> legendre(2, x) - 2 - 3*x 1 - ---- - - - 2 2 - - >>> legendre(8, x) - 8 6 4 2 - 6435*x 3003*x 3465*x 315*x 35 - ------- - ------- + ------- - ------ + --- - 128 32 64 32 128 - - >>> assoc_legendre(2, 1, x) - __________ - / 2 - -3*x*\/ - x + 1 - - >>> assoc_legendre(2, 2, x) - 2 - - 3*x + 3 - - >>> hermite(3, x) - 3 - 8*x - 12*x - -.. index:: equations; differential, diff, dsolve - -Differential Equations ----------------------- - -In ``isympy``:: - - >>> from sympy import Function, Symbol, dsolve - >>> f = Function('f') - >>> x = Symbol('x') - >>> f(x).diff(x, x) + f(x) - 2 - d - f(x) + ---(f(x)) - 2 - dx - - >>> dsolve(f(x).diff(x, x) + f(x), f(x)) - f(x) = C1*sin(x) + C2*cos(x) - -.. index:: equations; algebraic, solve - -Algebraic equations -------------------- - -In ``isympy``:: - - >>> from sympy import solve, symbols - >>> x, y = symbols('x,y') - >>> solve(x**4 - 1, x) - [-1, 1, -I, I] - - >>> solve([x + 5*y - 2, -3*x + 6*y - 15], [x, y]) - {x: -3, y: 1} - -.. index:: linear algebra - -Linear Algebra -============== - -.. index:: Matrix - -Matrices --------- - -Matrices are created as instances from the Matrix class:: - - >>> from sympy import Matrix, Symbol - >>> Matrix([[1,0], [0,1]]) - [1 0] - [ ] - [0 1] - -They can also contain symbols:: - - >>> x = Symbol('x') - >>> y = Symbol('y') - >>> A = Matrix([[1,x], [y,1]]) - >>> A - [1 x] - [ ] - [y 1] - - >>> A**2 - [x*y + 1 2*x ] - [ ] - [ 2*y x*y + 1] - -For more about Matrices, see the Linear Algebra tutorial. - -.. index:: pattern matching, match, Wild, WildFunction - -Pattern matching -================ - -Use the ``.match()`` method, along with the ``Wild`` class, to perform pattern -matching on expressions. The method will return a dictionary with the required -substitutions, as follows:: - - >>> from sympy import Symbol, Wild - >>> x = Symbol('x') - >>> p = Wild('p') - >>> (5*x**2).match(p*x**2) - {p: 5} - - >>> q = Wild('q') - >>> (x**2).match(p*x**q) - {p: 1, q: 2} - -If the match is unsuccessful, it returns ``None``:: - - >>> print((x+1).match(p**x)) - None - -One can also use the exclude parameter of the ``Wild`` class to ensure that -certain things do not show up in the result:: - - >>> p = Wild('p', exclude=[1,x]) - >>> print((x+1).match(x+p)) # 1 is excluded - None - >>> print((x+1).match(p+1)) # x is excluded - None - >>> print((x+1).match(x+2+p)) # -1 is not excluded - {p_: -1} - -.. _printing-tutorial: - -Printing -======== - -There are many ways to print expressions. - -**Standard** - -This is what ``str(expression)`` returns and it looks like this: - - >>> from sympy import Integral - >>> from sympy.abc import x - >>> print(x**2) - x**2 - >>> print(1/x) - 1/x - >>> print(Integral(x**2, x)) - Integral(x**2, x) - -**Pretty printing** - -Nice ascii-art printing is produced by the ``pprint`` function: - - >>> from sympy import Integral, pprint - >>> from sympy.abc import x - >>> pprint(x**2) - 2 - x - >>> pprint(1/x) - 1 - - - x - >>> pprint(Integral(x**2, x)) - / - | - | 2 - | x dx - | - / - -If you have a unicode font installed, the ``pprint`` function will use it by -default. You can override this using the ``use_unicode`` option.: - - >>> pprint(Integral(x**2, x), use_unicode=True) - ⌠ - ⎮ 2 - ⎮ x dx - ⌡ - - -See also the wiki `Pretty Printing -`_ for more examples of a nice -unicode printing. - -Tip: To make pretty printing the default in the Python interpreter, use:: - - $ python - Python 2.5.2 (r252:60911, Jun 25 2008, 17:58:32) - [GCC 4.3.1] on linux2 - Type "help", "copyright", "credits" or "license" for more information. - >>> from sympy import init_printing, var, Integral - >>> init_printing(use_unicode=False, wrap_line=False, no_global=True) - >>> var("x") - x - >>> x**3/3 - 3 - x - -- - 3 - >>> Integral(x**2, x) #doctest: +NORMALIZE_WHITESPACE - / - | - | 2 - | x dx - | - / - -**Python printing** - - >>> from sympy.printing.python import python - >>> from sympy import Integral - >>> from sympy.abc import x - >>> print(python(x**2)) - x = Symbol('x') - e = x**2 - >>> print(python(1/x)) - x = Symbol('x') - e = 1/x - >>> print(python(Integral(x**2, x))) - x = Symbol('x') - e = Integral(x**2, x) - - -**LaTeX printing** - - >>> from sympy import Integral, latex - >>> from sympy.abc import x - >>> latex(x**2) - x^{2} - >>> latex(x**2, mode='inline') - $x^{2}$ - >>> latex(x**2, mode='equation') - \begin{equation}x^{2}\end{equation} - >>> latex(x**2, mode='equation*') - \begin{equation*}x^{2}\end{equation*} - >>> latex(1/x) - \frac{1}{x} - >>> latex(Integral(x**2, x)) - \int x^{2}\, dx - -**MathML** - -:: - - >>> from sympy.printing.mathml import mathml - >>> from sympy import Integral, latex - >>> from sympy.abc import x - >>> print(mathml(x**2)) - x2 - >>> print(mathml(1/x)) - x-1 - -**Pyglet** - - >>> from sympy import Integral, preview - >>> from sympy.abc import x - >>> preview(Integral(x**2, x)) #doctest:+SKIP - -If pyglet is installed, a pyglet window will open containing the LaTeX -rendered expression: - -.. image:: pics/pngview1.png - -Notes ------ - -``isympy`` calls ``pprint`` automatically, so that's why you see pretty -printing by default. - -Note that there is also a printing module available, ``sympy.printing``. Other -printing methods available through this module are: - -* ``pretty(expr)``, ``pretty_print(expr)``, ``pprint(expr)``: Return or print, respectively, a pretty representation of ``expr``. This is the same as the second level of representation described above. - -* ``latex(expr)``, ``print_latex(expr)``: Return or print, respectively, a `LaTeX `_ representation of ``expr`` - -* ``mathml(expr)``, ``print_mathml(expr)``: Return or print, respectively, a `MathML `_ representation of ``expr``. - -* ``print_gtk(expr)``: Print ``expr`` to `Gtkmathview `_, a GTK widget that displays MathML code. The `Gtkmathview `_ program is required. - -Further documentation -===================== - -Now it's time to learn more about SymPy. Go through the -:ref:`SymPy User's Guide ` and -:ref:`SymPy Modules Reference `. - -Be sure to also browse our public `wiki.sympy.org `_, -that contains a lot of useful examples, tutorials, cookbooks that we and our -users contributed, and feel free to edit it. - -Translations -============ - -This tutorial is also available in other languages: - -.. toctree:: - :maxdepth: 1 diff -Nru python3-sympy-0.7.2/doc/src/tutorial.ru.po python3-sympy-0.7.3/doc/src/tutorial.ru.po --- python3-sympy-0.7.2/doc/src/tutorial.ru.po 2012-10-17 02:30:33.000000000 +0000 +++ python3-sympy-0.7.3/doc/src/tutorial.ru.po 1970-01-01 00:00:00.000000000 +0000 @@ -1,745 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) 2008, 2009, 2010, 2011, 2012 SymPy Development Team -# This file is distributed under the same license as the SymPy package. -# Alexey Subach , 2011 -# -msgid "" -msgstr "" -"Project-Id-Version: SymPy 0.7.2\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2012-03-19 21:43\n" -"PO-Revision-Date: 2012-03-19 21:40+0400\n" -"Last-Translator: Alexey Gudchenko \n" -"Language-Team: LANGUAGE \n" -"Language: Russian\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" - -# 3b8d0d99cbd0485d8a0f874d50c2e0ba -#: ../../src/tutorial.rst:5 -msgid "Tutorial" -msgstr "Краткое руководство" - -# 261dbc2a93064851bb80b80a8985f0bd -#: ../../src/tutorial.rst:10 -msgid "Introduction" -msgstr "Введение" - -# d007423f3c5d4407b0ca3221168f4a1e -#: ../../src/tutorial.rst:12 -msgid "" -"SymPy is a Python library for symbolic mathematics. It aims to become a full-" -"featured computer algebra system (CAS) while keeping the code as simple as " -"possible in order to be comprehensible and easily extensible. SymPy is " -"written entirely in Python and does not require any external libraries." -msgstr "" -"SymPy представляет собой открытую библиотеку символьных вычислений на языке " -"Python. Цель SymPy - стать полнофункциональной системой компьютерной алгебры " -"(CAS), при этом сохраняя код максимально понятным и легко расширяемым. SymPy " -"полностью написан на Python и не требует сторонних библиотек." - -# 344f5db4e74749c1a76459f6cec09b63 -#: ../../src/tutorial.rst:17 -msgid "" -"This tutorial gives an overview and introduction to SymPy. Read this to have " -"an idea what SymPy can do for you (and how) and if you want to know more, " -"read the :ref:`SymPy User's Guide `, :ref:`SymPy Modules Reference " -"`. or the `sources `_ directly." -msgstr "" -"Данное руководство представляет из себя введение в SymPy. В " -"нем вы узнаете об основных возможностях SymPy и каким образом использовать " -"эту программу. Если же вы желаете прочитать более подробное руководство, то " -"обратитесь к :ref:`Руководству пользователя SymPy `, :ref:`Описанию " -"модулей SymPy `. Можно также обратиться и к `исходному коду " -"`_ библиотеки." - -# 12619172a6874cb4af84282e3e1bfc39 -#: ../../src/tutorial.rst:26 -msgid "First Steps with SymPy" -msgstr "Первые шаги с SymPy" - -# 6f67d8997f1a474288d6bd50f5ddbc4f -#: ../../src/tutorial.rst:28 -msgid "" -"The easiest way to download it is to go to http://code.google.com/p/sympy/ " -"and download the latest tarball from the Featured Downloads:" -msgstr "" -"Скачать SymPy проще всего с http://code.google.com/p/sympy/. В разделе " -"Featured, Downloads нужно найти и загрузить последнюю версию дистрибутива:" - -# 65bde5e4aded4818bc11c4b9cfc8a3b7 -#: ../../src/tutorial.rst:34 -msgid "Unpack it:" -msgstr "" -"Для Windows-систем, нужно скачать и запустить установочный .exe файл. В " -"POSIX-совместимых системах нужно скачать .tar.gz файл и распаковать его:" - -# 76f6f7d72759408084134e093b5d9aea -#: ../../src/tutorial.rst:40 -msgid "and try it from a Python interpreter:" -msgstr "и запустить из интерпретатора Python:" - -# 4ddd39aeea714e9f8495cd77f7e4d7dd -#: ../../src/tutorial.rst:54 -msgid "" -"You can use SymPy as shown above and this is indeed the recommended way if " -"you use it in your program. You can also install it using ``./setup.py " -"install`` as any other Python module, or just install a package in your " -"favourite Linux distribution, e.g.:" -msgstr "" -"Если вы собираетесь использовать SymPy в вашей программе как модуль, " -"рекомендуется обращаться к нему таким же способом, как показано выше. " -"Установить модуль в систему можно или из скаченных исходников, используя " -"команду ./setup.py install. Или, если вы работаете в Linux, можно установить " -"пакет ``python-sympy`` с помощью системы установки программ:" - -# ce08a431018449c093786fe229ef9736 -#: ../../src/tutorial.rst:80 -msgid "" -"For other means how to install SymPy, consult the Downloads_ tab on the " -"SymPy's webpage." -msgstr "" -"Другие способы установки SymPy описаны в разделе Downloads_ на домашней " -"странице SymPy." - -# e81794f1d22c4f47b1f0b5f484ccb789 -#: ../../src/tutorial.rst:87 -msgid "isympy Console" -msgstr "Консоль isympy" - -# 342865b9196045a6a2a11ae9d69bc980 -#: ../../src/tutorial.rst:89 -msgid "" -"For experimenting with new features, or when figuring out how to do things, " -"you can use our special wrapper around IPython called ``isympy`` (located in " -"``bin/isympy`` if you are running from the source directory) which is just a " -"standard Python shell that has already imported the relevant SymPy modules " -"and defined the symbols x, y, z and some other things:" -msgstr "" -"SymPy можно использовать не только как модуль, но и как отдельную программу " -"``isympy``, которая расположена в папке ``bin`` относительно директории с " -"исходным кодом. Программа удобна для экспериментов с новыми функциями или " -"для обучения SymPy. Она использует стандартный терминал IPython, но с уже " -"включенными в нее важными модулями SymPy и определенными переменными x, y, z:" - -# 9d9f7e2ea55549268218f99a5b14593a -#: ../../src/tutorial.rst:119 -msgid "" -"Commands entered by you are bold. Thus what we did in 3 lines in a regular " -"Python interpreter can be done in 1 line in isympy." -msgstr "" -"Команды введенные вами, обозначены жирным шрифтом. То, что мы делали тремя " -"строчками в стандартном терминале Python, мы можем сделать одной строчкой в " -"isympy. Кроме того программа поддерживает различные способы отображения " -"результатов, в том числе графические." - -# f53c41b84d8b4d47894877572350325c -#: ../../src/tutorial.rst:124 -msgid "Using SymPy as a calculator" -msgstr "Использование SymPy в качестве калькулятора" - -# c6a7837a22d44c27a5d35a905779bd84 -# 88460153b0404c1c80d7d9fef1b9d530 -#: ../../src/tutorial.rst:126 -msgid "SymPy has three built-in numeric types: Float, Rational and Integer." -msgstr "" -"SymPy поддерживает три типа численных данных: Float, Rational и Integer." - -# 68eba98bb6f742d799aba6051f7f3d0f -#: ../../src/tutorial.rst:128 -msgid "" -"The Rational class represents a rational number as a pair of two Integers: " -"the numerator and the denominator. So Rational(1,2) represents 1/2, Rational" -"(5,2) represents 5/2, and so on." -msgstr "" -"Rational представляет собой обыкновенную дробь, которая задается с помощью " -"двух целых чисел: числителя и знаменателя. Например, Rational(1,2) " -"представляет дробь 1/2, Rational(5,2) представляет дробь 5/2, и так далее." - -# 4178f4aea2b54612a2a0c8f74fe2aa63 -#: ../../src/tutorial.rst:147 -msgid "" -"Proceed with caution while working with Python int's and floating point " -"numbers, especially in division, since you may create a Python number, not a " -"SymPy number. A ratio of two Python ints may create a float -- the \"true " -"division\" standard of Python 3 and the default behavior of ``isympy`` which " -"imports division from __future__::" -msgstr "" -"Важная особенность Python-интерпретатора, о которой нужно сказать отдельно, " -"связана с делением целых чисел При делении двух питоновских чисел типа int с " -"помощью оператора \"/\" в старых версиях Python в результате получается " -"число питоновского типа int. В Python 3 этот стандарт изменен на \"true " -"division\", и в результате получается питоновский тип float.И этот же " -"стандарт \"true division\" по умолчанию включен и в isympy::" - -# 723ba484cf134b71aaf8e7140c9a3954 -#: ../../src/tutorial.rst:157 -msgid "" -"But in earlier Python versions where division has not been imported, a " -"truncated int will result::" -msgstr "" -"В более ранних версиях Python этого не получится, и результатом будет " -"целочисленное деление::" - -# 0f88584459994baa87824d3fd4cf34f1 -#: ../../src/tutorial.rst:163 -msgid "" -"In both cases, however, you are not dealing with a SymPy Number because " -"Python created its own number. Most of the time you will probably be working " -"with Rational numbers, so make sure to use Rational to get the SymPy result. " -"One might find it convenient to equate ``R`` and Rational::" -msgstr "" -"Обратите внимание, что и в том и в другом случае вы имеете дело не с " -"объектом Number из библиотеки SymPy, который представляет число в SymPy, а с " -"питоновскими числами, которые создаются самим интерпретатором Python. Скорее " -"всего, вам нужно будете работать с дробными числами из библиотеки SymPy, " -"поэтому для того чтобы получать результат в виде объектов SymPy убедитесь, " -"что вы используете класс Rational. Кому-то может показаться удобным " -"обозначать Rational как ``R``::" - -# bf581140e5ea4f8f98031862c785375e -#: ../../src/tutorial.rst:175 -msgid "" -"We also have some special constants, like e and pi, that are treated as " -"symbols (1+pi won't evaluate to something numeric, rather it will remain as " -"1+pi), and have arbitrary precision::" -msgstr "" -"В модуле Sympy имеются особые константы, такие как e и pi, которые ведут " -"себя как переменные (то есть выражение 1+pi не преобразуется сразу в число, " -"а так и останется 1+pi)::" - -# 366cb3315e5f4371927639cebbf8a726 -#: ../../src/tutorial.rst:189 -msgid "as you see, evalf evaluates the expression to a floating-point number" -msgstr "" -"как вы видите, функция evalf переводит исходное выражение в число с " -"плавающей точкой. Вычисления можно проводить с большей точностью. Для этого " -"нужно передать в качестве аргумента этой функции требуемое число десятичных " -"знаков." - -# b300cf55ed11465bac6e0991d6f61a15 -#: ../../src/tutorial.rst:191 -msgid "The symbol ``oo`` is used for a class defining mathematical infinity::" -msgstr "" -"Для работы с математической бесконечностью используется символ ``oo``::" - -# addc7fddfd294a0e8da003463f35b614 -#: ../../src/tutorial.rst:200 -msgid "Symbols" -msgstr "Переменные" - -# 8508a3480ca34bd4a8741733e17ccc56 -#: ../../src/tutorial.rst:202 -msgid "" -"In contrast to other Computer Algebra Systems, in SymPy you have to declare " -"symbolic variables explicitly::" -msgstr "" -"В отличие от многих других систем компьютерной алгебры, вам нужно явно " -"декларировать символьные переменные::" - -# 19bcc88285724ae99b448a86d7980ce9 -#: ../../src/tutorial.rst:209 -msgid "" -"On the left is the normal Python variable which has been assigned to the " -"SymPy Symbol class. Predefined symbols (including those for symbols with " -"Greek names) are available for import from abc:" -msgstr "" -"В левой части этого выражения находится переменная Python, которая " -"питоновским присваиванием соотносится с объектом класса Symbol из SymPy." - -# 6b654b5bda774aa0a4b150388bc102dc -#: ../../src/tutorial.rst:215 -msgid "" -"Symbols can also be created with the ``symbols`` or ``var`` functions, the " -"latter automatically adding the created symbols to the namespace, and both " -"accepting a range notation:" -msgstr "" -"Символьные переменные могут также задаваться и с помощью функций ``symbols`` " -"или ``var``. Они допускают указание диапазона. Их отличие состоит в том, что " -"``var`` добавляет созданные переменные в текущее пространство имен:" - -# aa93d9743638443ebbae8bc5bee19e56 -#: ../../src/tutorial.rst:227 -msgid "" -"Instances of the Symbol class \"play well together\" and are the building " -"blocks of expresions::" -msgstr "" -"Экземпляры класса Symbol взаимодействуют друг с другом. Таким образом, с " -"помощью них конструируются алгебраические выражения::" - -# c613786cee894688b20cdccfeaac8c9b -#: ../../src/tutorial.rst:239 -msgid "" -"They can be substituted with other numbers, symbols or expressions using " -"``subs(old, new)``::" -msgstr "" -"Переменные могут быть заменены на другие переменные, числа или выражения с " -"помощью функции подстановки ``subs(old, new)``::" - -# 3872add29a8b4a71a5e26a3218130491 -#: ../../src/tutorial.rst:250 -msgid "For the remainder of the tutorial, we assume that we have run::" -msgstr "" -"Теперь, с этого момента, для всех написанных ниже примеров мы будем " -"предполагать, что запустили следующую команду по настройке системы " -"отображения результатов::" - -# d1b280862f04408a98ba048cc9460eaa -#: ../../src/tutorial.rst:255 -msgid "" -"This will make things look better when printed. See the :ref:`printing-" -"tutorial` section below. If you have a unicode font installed, you can pass " -"use_unicode=True for a slightly nicer output." -msgstr "" -"Она придаст более качественное отображение выражений. Подробнее по системе " -"отображения и печати написано в разделе :ref:`printing-tutorial-ru`. Если же " -"у вас установлен шрифт с юникодом, вы можете использовать опцию " -"use_unicode=True для еще более красивого вывода." - -# 17ee30ecb05a410d94cccf0cc229ae5b -#: ../../src/tutorial.rst:260 -msgid "Algebra" -msgstr "Алгебра" - -# 673fbe9f608748128027755ac1b0d7cb -#: ../../src/tutorial.rst:262 -msgid "For partial fraction decomposition, use ``apart(expr, x)``::" -msgstr "" -"Чтобы разложить выражение на простейшие дроби используется функция ``apart" -"(expr, x)``::" - -# 723c57a6e36f43eca18771e2ad246955 -#: ../../src/tutorial.rst:287 -msgid "To combine things back together, use ``together(expr, x)``::" -msgstr "" -"Чтобы снова привести дробь к общему знаменателю используется функция " -"``together(expr, x)``::" - -# 607fa824a12d461d9eaf6c83bbc902d0 -#: ../../src/tutorial.rst:309 -msgid "Calculus" -msgstr "Вычисления" - -# 9cbc010ae5b54d2a9222db8a78a2687c -#: ../../src/tutorial.rst:314 -msgid "Limits" -msgstr "Пределы" - -# e2cfd8cf367b4f41a2eb8f98045e1f45 -#: ../../src/tutorial.rst:316 -msgid "" -"Limits are easy to use in SymPy, they follow the syntax ``limit(function, " -"variable, point)``, so to compute the limit of f(x) as x -> 0, you would " -"issue ``limit(f, x, 0)``::" -msgstr "" -"Пределы считаются в SymPy очень легко. Чтобы вычислить предел функции, " -"используйте функцию ``limit(function, variable, point)``. Например, чтобы " -"вычислить предел f(x) при x -> 0, вам нужно ввести ``limit(f, x, 0)``::" - -# 7cc96e845d0a4c479199f4a51ed7d665 -#: ../../src/tutorial.rst:325 -msgid "you can also calculate the limit at infinity::" -msgstr "также вы можете вычислять пределы при x, стремящемся к бесконечности::" - -# d67693fb8cc04954be3bff6aaa712bfa -#: ../../src/tutorial.rst:336 -msgid "" -"for some non-trivial examples on limits, you can read the test file " -"`test_demidovich.py `_" -msgstr "" -"Для более сложных примеров вычисления пределов, вы можете обратится к файлу " -"с тестами `test_demidovich.py `_ " - -# c92009d7b6df4e2d8f9fe9ad14657bbd -#: ../../src/tutorial.rst:343 -msgid "Differentiation" -msgstr "Дифференцирование" - -# 476aa0220145495a932178c9fc3b305a -#: ../../src/tutorial.rst:345 -msgid "" -"You can differentiate any SymPy expression using ``diff(func, var)``. " -"Examples::" -msgstr "" -"Продифференцировать любое выражение SymPy, можно используя ``diff(func, var)" -"``. Примеры::" - -# 35850640eccf4071b1b0318a49055f39 -#: ../../src/tutorial.rst:358 -msgid "You can check, that it is correct by::" -msgstr "" -"Можно, кстати, через пределы проверить правильность вычислений производной::" - -# 5ffab586313e4970aa3c933d631bc676 -#: ../../src/tutorial.rst:366 -msgid "" -"Higher derivatives can be calculated using the ``diff(func, var, n)`` " -"method::" -msgstr "" -"Производные более высших порядков можно вычислить, используя дополнительный " -"параметр этой же функции ``diff(func, var, n)``::" - -# 0624a0af400f4e78a351b056a7ba009c -#: ../../src/tutorial.rst:383 -msgid "Series expansion" -msgstr "Разложение в ряд" - -# b40c746b225d4749a9298ad077c3ce4d -#: ../../src/tutorial.rst:385 -msgid "Use ``.series(var, point, order)``::" -msgstr "" -"Для разложения в ряд используйте метод ``.series(var, point, order)``::" - -# f9106b494ab2465bbbd4108736f67a1e -#: ../../src/tutorial.rst:400 -msgid "Another simple example::" -msgstr "Еще один простой пример::" - -# d4aa5a4ef31d4327a70c47b42cc0d2d4 -#: ../../src/tutorial.rst:420 -msgid "Integration" -msgstr "Интегрирование" - -# 8e985ebba8d5463bb1af3a3220dd21b0 -#: ../../src/tutorial.rst:422 -msgid "" -"SymPy has support for indefinite and definite integration of transcendental " -"elementary and special functions via ``integrate()`` facility, which uses " -"powerful extended Risch-Norman algorithm and some heuristics and pattern " -"matching::" -msgstr "" -"SymPy поддерживает вычисление определенных и неопределенных интегралов с " -"помощью функции ``integrate()``. Она использует расширенный алгоритм Риша-" -"Нормана и некоторые шаблоны и эвристики. Можно вычислять интегралы " -"трансцендентных, простых и специальных функций::" - -# 6ff3ff4c189f45078f75a93aa2863ef9 -#: ../../src/tutorial.rst:430 -msgid "You can integrate elementary functions::" -msgstr "Вы можете интегрировать простейшие функции::" - -# ead91a6c777f47dea8be1a1e50bdf752 -#: ../../src/tutorial.rst:443 -msgid "Also special functions are handled easily::" -msgstr "Примеры интегрирования некоторых специальных функций::" - -# 40ad8cd5c7e3460f9cceb59630cf562c -#: ../../src/tutorial.rst:451 -msgid "It is possible to compute definite integrals::" -msgstr "Возможно также вычислить определенный интеграл::" - -# 19602e9ed1b641f993f704eb31111beb -#: ../../src/tutorial.rst:460 -msgid "Also, improper integrals are supported as well::" -msgstr "Поддерживаются и несобственные интегралы::" - -# b8ef574746f1448ab78da1958f9de616 -#: ../../src/tutorial.rst:472 -msgid "Complex numbers" -msgstr "Комплексные числа" - -# 13fbbe2555b14aefb25e48ac5ed298a0 -#: ../../src/tutorial.rst:474 -msgid "" -"Besides the imaginary unit, I, which is imaginary, symbols can be created " -"with attributes (e.g. real, positive, complex, etc...) and this will affect " -"how they behave::" -msgstr "" -"Помимо мнимой единицы I, которое является мнимым числом, символы тоже могут " -"иметь специальные атрибуты (real, positive, complex и т.д), которые " -"определяют поведение этих символов при вычислении символьных выражений::" - -# d726887f4f0444dba6e4ef6a2bb702d6 -#: ../../src/tutorial.rst:491 -msgid "Functions" -msgstr "Функции" - -# 42585fb828e24af79c0278aa14bcc2c3 -#: ../../src/tutorial.rst:493 -msgid "**trigonometric**::" -msgstr "**тригонометрические**::" - -# be0be9ba76c042b68160f1907d2b0d13 -#: ../../src/tutorial.rst:542 -msgid "**spherical harmonics**::" -msgstr "**сферические**::" - -# bdc2ad96783444459c3e66c409914143 -#: ../../src/tutorial.rst:568 -msgid "**factorials and gamma function**::" -msgstr "**факториалы и гамма-функции**::" - -# c621f51005504ee9890d34156556de57 -#: ../../src/tutorial.rst:586 -msgid "**zeta function**::" -msgstr "**дзета-функции**::" - -# 95ad3014dc9442cc8eb8438b2cc28327 -#: ../../src/tutorial.rst:611 -msgid "**polynomials**::" -msgstr "**многочлены**::" - -# d91cad90caee4aa7b2922a42ebe608b1 -#: ../../src/tutorial.rst:650 -msgid "Differential Equations" -msgstr "Дифференциальные уравнения" - -# 18467aefa0364cec936571494c1993da -# 65279c1f5c4a448fbb813790d956ac48 -#: ../../src/tutorial.rst:652 ../../src/tutorial.rst:672 -msgid "In ``isympy``::" -msgstr "В ``isympy``::" - -# e036530fce79489cbf1c494a9443568f -#: ../../src/tutorial.rst:670 -msgid "Algebraic equations" -msgstr "Алгебраические уравнения" - -# fd5aedc6ba9f45b4868c10764f9e6797 -#: ../../src/tutorial.rst:685 -msgid "Linear Algebra" -msgstr "Линейная алгебра" - -# 372cf49866874ec1a97d6cb813f8b63b -#: ../../src/tutorial.rst:690 -msgid "Matrices" -msgstr "Матрицы" - -# fc4620da22164a3c8f25be8591759f97 -#: ../../src/tutorial.rst:692 -msgid "Matrices are created as instances from the Matrix class::" -msgstr "Матрицы задаются с помощью конструктора Matrix::" - -# 0289f9cec4f140c6adc90aa38f84efee -#: ../../src/tutorial.rst:700 -msgid "They can also contain symbols::" -msgstr "В матрицах вы также можете использовать символьные переменные::" - -# ced23cc091a34db6be3b5597fd056f32 -#: ../../src/tutorial.rst:715 -msgid "For more about Matrices, see the Linear Algebra tutorial." -msgstr "" -"Для того, чтобы узнать о матрицах подробнее, прочитайте, пожалуйста, " -"Руководство по Линейной Алгебре." - -# 71124cfe123649c28c7a61251d0b1cdd -#: ../../src/tutorial.rst:720 -msgid "Pattern matching" -msgstr "Сопоставление с образцом" - -# b9ecf875555748978255bc268bc4123c -#: ../../src/tutorial.rst:722 -msgid "" -"Use the ``.match()`` method, along with the ``Wild`` class, to perform " -"pattern matching on expressions. The method will return a dictionary with " -"the required substitutions, as follows::" -msgstr "" -"Чтобы сопоставить выражения с образцами, используйте функцию ``.match()`` " -"вместе со вспомогательным классом ``Wild``. Эта функция вернет словарь с " -"необходимыми заменами, например::" - -# 06d4a8e419854045af79b0076e71616a -#: ../../src/tutorial.rst:736 -msgid "If the match is unsuccessful, it returns ``None``::" -msgstr "Если же сопоставление не удалось, функция вернет``None``::" - -# 7219ffc6e8b0486a913297c19b5fce1f -#: ../../src/tutorial.rst:741 -msgid "" -"One can also use the exclude parameter of the ``Wild`` class to ensure that " -"certain things do not show up in the result::" -msgstr "" -"Также можно использовать параметр exclude для исключения некоторых значений " -"из результата::" - -# a692f291013a4777a4771188901c6bf2 -#: ../../src/tutorial.rst:755 -msgid "Printing" -msgstr "Печать" - -# 8cfe16423a79408c828d270def412899 -#: ../../src/tutorial.rst:757 -msgid "There are many ways to print expressions." -msgstr "Реализовано несколько способов вывода выражений на экран." - -# a9891e6028b644879ce5e3a8489a72a5 -#: ../../src/tutorial.rst:759 -msgid "**Standard**" -msgstr "**Стандартный**" - -# 9802b10f6c2d4b7997302f4315e8bf2a -#: ../../src/tutorial.rst:761 -msgid "This is what ``str(expression)`` returns and it looks like this:" -msgstr "" -"Стандартный способ представлен функцией ``str(expression)``, которая " -"работает следующим образом:" - -# 461df293b09c46b1bf24bc5c335b4401 -#: ../../src/tutorial.rst:772 -msgid "**Pretty printing**" -msgstr "**Красивая печать**" - -# 29c9e2204a0948db9d8328300f3bdd1a -#: ../../src/tutorial.rst:774 -msgid "Nice ascii-art printing is produced by the ``pprint`` function:" -msgstr "" -"Этот способ печати выражений основан на ascii-графике и реализован через " -"функцию ``pprint``:" - -# 5fc9fa809fa04cee8113a669f032b9c3 -#: ../../src/tutorial.rst:793 -msgid "" -"If you have a unicode font installed, the ``pprint`` function will use it by " -"default. You can override this using the ``use_unicode`` option.:" -msgstr "" -"Если у вас установлен шрифт с юникодом, он будет использовать Pretty-print с " -"юникодом по умолчанию. Эту настройку можно отключить, используя " -"``use_unicode``:" - -# dcbf982351c1414bb0c2653039d6f569 -#: ../../src/tutorial.rst:803 -msgid "" -"See also the wiki `Pretty Printing `_ for more examples of a nice unicode printing." -msgstr "" -"Для изучения подробных примеров работы Pretty-print с юникодом вы можете " -"обратится к статье `Pretty Printing `_ из нашего Вики." - -# af26680251b0437e807a48d7946c3724 -#: ../../src/tutorial.rst:807 -msgid "" -"Tip: To make pretty printing the default in the Python interpreter, use::" -msgstr "" -"Совет: Чтобы активировать Pretty-print по умолчанию в интерпретаторе Python, " -"используйте::" - -# b34cf35aca67417bbedfd0f9912d3dab -#: ../../src/tutorial.rst:830 -msgid "**Python printing**" -msgstr "**Печать объектов Python**" - -# f6300e28499f4c23b1a18aca896340bb -#: ../../src/tutorial.rst:846 -msgid "**LaTeX printing**" -msgstr "**Печать в формате LaTeX**" - -# 3b81c7e35c364676a8ec8587b515ac8b -#: ../../src/tutorial.rst:863 -msgid "**MathML**" -msgstr "**MathML**" - -# ee36b86c5d54419fbde01ac89cab213b -#: ../../src/tutorial.rst:875 -msgid "**Pyglet**" -msgstr "**Pyglet**" - -# 8ea61d943b2b4960a879932eba46bc1b -#: ../../src/tutorial.rst:881 -msgid "" -"If pyglet is installed, a pyglet window will open containing the LaTeX " -"rendered expression:" -msgstr "Появится окно pyglet с отрисованным выражением LaTeX:" - -# 8741a66d24b04738a563afc90a41567b -#: ../../src/tutorial.rst:887 -msgid "Notes" -msgstr "Примечания" - -# 51219a05b9a84e79b754d8d03b7fc4fb -#: ../../src/tutorial.rst:889 -msgid "" -"``isympy`` calls ``pprint`` automatically, so that's why you see pretty " -"printing by default." -msgstr "" -"``isympy`` вызывает ``pprint`` автоматически, по этой причине Pretty-print " -"будет включен в ``isympy`` по умолчанию." - -# 7b126ec3363b4c63a6d6b98728a9738a -#: ../../src/tutorial.rst:892 -msgid "" -"Note that there is also a printing module available, ``sympy.printing``. " -"Other printing methods available through this module are:" -msgstr "" -"Также доступен модуль печати - ``sympy.printing``. Через этот модуль " -"доступны следующий функции печати:" - -# 1001063c4e97442dbcb0491eb0641bba -#: ../../src/tutorial.rst:895 -msgid "" -"``pretty(expr)``, ``pretty_print(expr)``, ``pprint(expr)``: Return or print, " -"respectively, a pretty representation of ``expr``. This is the same as the " -"second level of representation described above." -msgstr "" -"``pretty(expr)``, ``pretty_print(expr)``, ``pprint(expr)``: Возвращает или " -"выводит на экран, соответственно, \"Красивое\" представление выражения " -"``expr``. " - -# ee0ca8e34ce04b458228cb9d6565ec1a -#: ../../src/tutorial.rst:897 -msgid "" -"``latex(expr)``, ``print_latex(expr)``: Return or print, respectively, a " -"`LaTeX `_ representation of ``expr``" -msgstr "" -"``latex(expr)``, ``print_latex(expr)``: Возвращает или выводит на экран, " -"соответственно, `LaTeX `_ -представление " -"``expr``" - -# ebfeade491644b0b85f72b00bd3c1bdf -#: ../../src/tutorial.rst:899 -msgid "" -"``mathml(expr)``, ``print_mathml(expr)``: Return or print, respectively, a " -"`MathML `_ representation of ``expr``." -msgstr "" -"``mathml(expr)``, ``print_mathml(expr)``: Возвращает или выводит на экран, " -"соответственно, `MathML `_ -представление ``expr``." - -# bc0334fae2224eb2bfc81a55e7f522dd -#: ../../src/tutorial.rst:901 -msgid "" -"``print_gtk(expr)``: Print ``expr`` to `Gtkmathview `_, a GTK widget that displays MathML code. The `Gtkmathview " -"`_ program is required." -msgstr "" -"``print_gtk(expr)``: Вывод ``expr`` в `Gtkmathview `_, виджет GTK, который отображает код MathML. Необходимо " -"наличие пакета `Gtkmathview `_ ." - -# e76c7af419504e458893b76b1b485fd4 -#: ../../src/tutorial.rst:904 -msgid "Further documentation" -msgstr "Другие справочники" - -# 2757e954e4c04b01bf9607f2127c3146 -#: ../../src/tutorial.rst:906 -msgid "" -"Now it's time to learn more about SymPy. Go through the :ref:`SymPy User's " -"Guide ` and :ref:`SymPy Modules Reference `." -msgstr "" -"Чтобы узнать о SymPy подробнее, обратитесь :ref:`Руководство пользователя " -"SymPy ` и :ref:`Описание модулей SymPy `." - -# a037027043bd483dab5a52bd8d325980 -#: ../../src/tutorial.rst:910 -msgid "" -"Be sure to also browse our public `wiki.sympy.org `_, that contains a lot of useful examples, tutorials, cookbooks that we " -"and our users contributed, and feel free to edit it." -msgstr "" -"Также можно обратится на `wiki.sympy.org `_ - сайт, " -"который содержит множество полезных примеров, руководств и советов. Они " -"созданны нами и нашим сообществом. Мы будем рады, если и вы внесете в него " -"свой весомый вклад." - -# f6e1f1f3b1214ffc848b88bd85bc8bfd -#: ../../src/tutorial.rst:915 -msgid "Translations" -msgstr "Переводы" - -# cf4fe2ed5e27427cb8d4af80f7e88c3f -#: ../../src/tutorial.rst:917 -msgid "This tutorial is also available in other languages:" -msgstr "Этот текст доступен на других языках:" diff -Nru python3-sympy-0.7.2/doc/src/tutorial.sr.po python3-sympy-0.7.3/doc/src/tutorial.sr.po --- python3-sympy-0.7.2/doc/src/tutorial.sr.po 2012-10-17 02:30:33.000000000 +0000 +++ python3-sympy-0.7.3/doc/src/tutorial.sr.po 1970-01-01 00:00:00.000000000 +0000 @@ -1,751 +0,0 @@ -# Serbian translation of the SymPy tutorial. -# Copyright (C) 2008, 2009, 2010, 2011, 2012 SymPy Development Team -# This file is distributed under the same license as the SymPy package. -# FIRST AUTHOR , YEAR. -# -#, fuzzy -msgid "" -msgstr "" -"Project-Id-Version: SymPy 0.7.2\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2012-08-14 15:40\n" -"PO-Revision-Date: 2012-08-15 11:00\n" -"Last-Translator: Ljubiša Moćić <3rdslasher@gmail.com>\n" -"Language-Team: LANGUAGE \n" -"Language: Serbian\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" - -# ef368fde650b4d37bfab62d3da9a35e8 -#: ../../src/tutorial.rst:5 -msgid "Tutorial" -msgstr "Туторијал" - -# abf8aaaf520c4b8b93deeb2edb6c9be9 -#: ../../src/tutorial.rst:10 -msgid "Introduction" -msgstr "Увод" - -# ed94f47f56be4b81a87025aa073e6979 -#: ../../src/tutorial.rst:12 -msgid "" -"SymPy is a Python library for symbolic mathematics. It aims to become a full-" -"featured computer algebra system (CAS) while keeping the code as simple as " -"possible in order to be comprehensible and easily extensible. SymPy is " -"written entirely in Python and does not require any external libraries." -msgstr "" -"SymPy je Python библиотека за симболичку математику. Циља да постане потпуно " -"садржани алгебарски систем (енглески CAS: \"Computer Algebra System\"), " -"чувајући код једноставнијим колико је могуће да би била разумљива и лакше " -"проширива. SymPy је комплетно написан у програмском језику Python и не " -"захтева никакве екстерне библиотеке." - -# 349f4bf85f73457ba3b5f50386fa738d -#: ../../src/tutorial.rst:17 -msgid "" -"This tutorial gives an overview and introduction to SymPy. Read this to have " -"an idea what SymPy can do for you (and how) and if you want to know more, " -"read the :ref:`SymPy User's Guide `, :ref:`SymPy Modules Reference " -"`. or the `sources `_ directly." -msgstr "" -"Овај туторијал даје вам преглед и увод у SymPy. Прочитајте га да бисте имали " -"идеју шта SymPy можете урадити (и како) а ако хоћете да сазнате више, " -"прочитајте :ref:`SymPy кориснички водич `, :ref:`SymPy референтни " -"модул `. или `изворни код `_ " -"директно." - -# ae4b11d97f904aa58d5d35b5d0645e05 -#: ../../src/tutorial.rst:26 -msgid "First Steps with SymPy" -msgstr "Први кораци" - -# 176f8c58fbec4c2b914e0749d52615d3 -#: ../../src/tutorial.rst:28 -msgid "" -"The easiest way to download it is to go to http://code.google.com/p/sympy/ " -"and download the latest tarball from the Featured Downloads:" -msgstr "" -"Најлакши начин да се преузме је да одете на http://code.google.com/p/sympy/ " -"и преузмeте последњу архиву из истакнутих преузимања:" - -# 2a33709912af465e81983babe696a30c -#: ../../src/tutorial.rst:34 -msgid "Unpack it:" -msgstr "Отпакујте:" - -# 442649bf41ab4420b2a5e64c88d75044 -#: ../../src/tutorial.rst:40 -msgid "and try it from a Python interpreter:" -msgstr "и покушајте из Python интерпретера:" - -# c45e274c1d85470cacc0e0aa68e15690 -#: ../../src/tutorial.rst:54 -msgid "" -"You can use SymPy as shown above and this is indeed the recommended way if " -"you use it in your program. You can also install it using ``./setup.py " -"install`` as any other Python module, or just install a package in your " -"favourite Linux distribution, e.g.:" -msgstr "" -"Можете да користите SymPy како је указано горе и то је препоручен начин ако " -"се користи у вашем програму. Такође га можете инсталирати користећи ``./" -"setup.py install`` као и сваки други Python модул, или само инсталирати " -"пакет ваше Линукс дистрибуције:" - -# e68c77c85d0e44e1836cf9df82297260 -#: ../../src/tutorial.rst:80 -msgid "" -"For other means how to install SymPy, consult the Downloads_ tab on the " -"SymPy's webpage." -msgstr "" -"За остале начине инсталирања SymPy констултујте Downloads_ таб на SymPy " -"страници." - -# c729f14f734c4b0b86fe217c7f5c6b47 -#: ../../src/tutorial.rst:87 -msgid "isympy Console" -msgstr "isympy конзола" - -# 9b778d6328054122a27a53a785f65c38 -#: ../../src/tutorial.rst:89 -#, fuzzy -msgid "" -"For experimenting with new features, or when figuring out how to do things, " -"you can use our special wrapper around IPython called ``isympy`` (located in " -"``bin/isympy`` if you are running from the source directory) which is just a " -"standard Python shell that has already imported the relevant SymPy modules " -"and defined the symbols x, y, z and some other things:" -msgstr "" -"За експериментисање са новим могућностима или када схватате како да радите " -"неке радње, можете користити специјални омот око IPython , звани ``isympy`` " -"(лоциран у ``bin/isympy`` ако покрећете из изворног фолдера) који је само " -"стандардна Python љуска коју су већ увежени SymPy модули, симболи x, y, z и " -"друго:" - -# e8f2cde6e17b484eadbfd07c4826d90f -#: ../../src/tutorial.rst:119 -msgid "" -"Commands entered by you are bold. Thus what we did in 3 lines in a regular " -"Python interpreter can be done in 1 line in isympy." -msgstr "" -"Команде су подебљане. То што смо урадили са 3 линије у регуларном Python " -"интерпретеру може бити урађено у једној линији у isympy." - -# 2570341f10c543189018686201145ef6 -#: ../../src/tutorial.rst:124 -msgid "Using SymPy as a calculator" -msgstr "SymPy као дигитрон" - -# 977c6cd08d0b441198d527f971aed7d4 -#: ../../src/tutorial.rst:126 -#, fuzzy -msgid "SymPy has three built-in numeric types: Float, Rational and Integer." -msgstr "SymPy има три уграђена типа бројева: променљиви, рационални и цели." - -# f537bd938fb149979432e80e9e96d387 -#: ../../src/tutorial.rst:128 -msgid "" -"The Rational class represents a rational number as a pair of two Integers: " -"the numerator and the denominator. So Rational(1,2) represents 1/2, Rational" -"(5,2) represents 5/2, and so on." -msgstr "" -"Класа \"Rational\" представља рацоинални број као пар од два цела, именилац " -"и садржилац, тако да рационални број Rational(1,2) представаља 1/2, Rational" -"(5,2) представља 5/2 и тако даље." - -# 468725a85a9f46929611f57d46ec8e31 -#: ../../src/tutorial.rst:147 -msgid "" -"Proceed with caution while working with Python int's and floating point " -"numbers, especially in division, since you may create a Python number, not a " -"SymPy number. A ratio of two Python ints may create a float -- the \"true " -"division\" standard of Python 3 and the default behavior of ``isympy`` which " -"imports division from __future__::" -msgstr "" -"Наставите са пажњом док радите са целим и променљивим бројевима, посебно у " -"дељењу, јер можете направити Python број, а не SymPy број. Однос два цела " -"броја у Python може направити променљливи -- истинито дељење(true divison) " -"стандардно за Python 3 у подразумевано понашање ``isympy`` који увози дељење " -"из __future__::" - -# 017eabe36b2641ec80ffce69386d44d3 -#: ../../src/tutorial.rst:157 -msgid "" -"But in earlier Python versions where division has not been imported, a " -"truncated int will result::" -msgstr "" -"Али у ранијим Python верзијама где дељење није увежено, скраћени цели број " -"ће бити резултат::" - -# 66bb1bc4b7614abb860cab7b50279651 -#: ../../src/tutorial.rst:163 -msgid "" -"In both cases, however, you are not dealing with a SymPy Number because " -"Python created its own number. Most of the time you will probably be working " -"with Rational numbers, so make sure to use Rational to get the SymPy result. " -"One might find it convenient to equate ``R`` and Rational::" -msgstr "" -"У оба случаја, ипак, не радите са SymPy бројевима јер је Python креирао " -"своје посебне бројеве. Већину времена ћете вероватно радити са рационалним " -"бројевима, тако да будите сигурни да користите рационалне бројеве да бисте " -"добили SymPy резултат. Могло би бити згодно изједначити ``R`` и Rational::" - -# 2d90325df6cd4f7d8e6018724e1babc5 -#: ../../src/tutorial.rst:175 -msgid "" -"We also have some special constants, like e and pi, that are treated as " -"symbols (1+pi won't evaluate to something numeric, rather it will remain as " -"1+pi), and have arbitrary precision::" -msgstr "" -"Такође имамо неке специјалне константе као e и pi, који се третирају као " -"симболи (1+pi неће прерачунати у нумерчку форму, већ ће остати као 1+pi), " -"могу имати произвољну прецизност:" - -# 8312d3db71524eb5b904bed1ef60c1e3 -#: ../../src/tutorial.rst:189 -msgid "as you see, evalf evaluates the expression to a floating-point number" -msgstr "као што видите, evalf рачуна израз у реалан број" - -# 2a8ac4d6b45e474aacae7e2fd30e3da5 -#: ../../src/tutorial.rst:191 -msgid "The symbol ``oo`` is used for a class defining mathematical infinity::" -msgstr "Симбол ``oo`` представља бесконачно::" - -# 4f134a47136245948240fa2f27a68cde -#: ../../src/tutorial.rst:200 -msgid "Symbols" -msgstr "Симболи" - -# b1be7141bb114ff3a795d72f259efc7f -#: ../../src/tutorial.rst:202 -msgid "" -"In contrast to other Computer Algebra Systems, in SymPy you have to declare " -"symbolic variables explicitly::" -msgstr "" -"За разлику од осталих компјутерских алгебарских система, у SymPy ви морате " -"да декларишете симболичке променљиве експлицитно:" - -# 78654a1a0f1a4bfc93cdb3e2d1d89aa0 -#: ../../src/tutorial.rst:209 -#, fuzzy -msgid "" -"On the left is the normal Python variable which has been assigned to the " -"SymPy Symbol class. Predefined symbols (including those for symbols with " -"Greek names) are available for import from abc:" -msgstr "" -"На левој страни је нормална Python променљива која је додељена SymPy Symbol " -"класи. Инстанце класе Symbol се \"добро слажу\" и чине основу израза::" - -# beba4c07583f424c8077b432b138c274 -#: ../../src/tutorial.rst:215 -msgid "" -"Symbols can also be created with the ``symbols`` or ``var`` functions, the " -"latter automatically adding the created symbols to the namespace, and both " -"accepting a range notation:" -msgstr "" - -# 78654a1a0f1a4bfc93cdb3e2d1d89aa0 -#: ../../src/tutorial.rst:227 -#, fuzzy -msgid "" -"Instances of the Symbol class \"play well together\" and are the building " -"blocks of expresions::" -msgstr "" -"На левој страни је нормална Python променљива која је додељена SymPy Symbol " -"класи. Инстанце класе Symbol се \"добро слажу\" и чине основу израза::" - -# aa854af4fdf048408383d25184b199d8 -#: ../../src/tutorial.rst:239 -msgid "" -"They can be substituted with other numbers, symbols or expressions using " -"``subs(old, new)``::" -msgstr "" -"Они могу бити замењени са другим бројевима, симболима или изразима користећи " -"команду ``subs(old, new)``::" - -# bdc4ccb6112f46079db51bcf3b0f2543 -#: ../../src/tutorial.rst:250 -msgid "For the remainder of the tutorial, we assume that we have run::" -msgstr "За остатак овог туторијала, претпостављамо да смо извршили::" - -# 279b65465b8b49c692d7a48a5862a558 -#: ../../src/tutorial.rst:255 -msgid "" -"This will make things look better when printed. See the :ref:`printing-" -"tutorial` section below. If you have a unicode font installed, you can pass " -"use_unicode=True for a slightly nicer output." -msgstr "" -"Ово ће лепше штампати резултате. Погледајте :ref:`printing-tutorial` " -"секцију. Ако имате неки уникод фонт инсталиран, можете користити " -"use_unicode=True за много лепше резултате." - -# aca0bd45e35443bb857b0838a96899fd -#: ../../src/tutorial.rst:260 -msgid "Algebra" -msgstr "Алгебра" - -# d3a8b50893a74c5ebdfc871aa33d0aa2 -#: ../../src/tutorial.rst:262 -msgid "For partial fraction decomposition, use ``apart(expr, x)``::" -msgstr "За делимични разломак, користите ``apart(expr, x)``::" - -# a91644272134460497b718335c6a1512 -#: ../../src/tutorial.rst:287 -msgid "To combine things back together, use ``together(expr, x)``::" -msgstr "Да бисте комбиновали ствари заједно, користите ``together(expr, x)``::" - -# 1e334f50cf2f4d238c9383bfe434377e -#: ../../src/tutorial.rst:309 -msgid "Calculus" -msgstr "Математичка анализа" - -# b67918161aee4eae8b41e423ffdc5cbb -#: ../../src/tutorial.rst:314 -msgid "Limits" -msgstr "Лимити" - -# 20a623fd96054cacb6c0106c4a876074 -#: ../../src/tutorial.rst:316 -#, fuzzy -msgid "" -"Limits are easy to use in SymPy, they follow the syntax ``limit(function, " -"variable, point)``, so to compute the limit of f(x) as x -> 0, you would " -"issue ``limit(f, x, 0)``::" -msgstr "" -"Лимити се лако употребљавају, користе синтаксу ``limit(function,variable, " -"point)``, тако да би израчунали лимит од f(x) када x тежи нули, ви би издали " -"``limit(f, x, 0)``::" - -# 76bae0be9d9946c8b45aea3d51446b8f -#: ../../src/tutorial.rst:325 -msgid "you can also calculate the limit at infinity::" -msgstr "Можете такође израчунати у бесконачности::" - -# fc0a8b34929b4d4397091cfc70c4c086 -#: ../../src/tutorial.rst:336 -msgid "" -"for some non-trivial examples on limits, you can read the test file " -"`test_demidovich.py `_" -msgstr "" -"За неке не-тривијалне примере са лимитима, можете прочитати тест датотеку " -"`test_demidovich.py `_" - -# 61e8d3621dc447718851bb474cccbde0 -#: ../../src/tutorial.rst:343 -msgid "Differentiation" -msgstr "Изводи" - -# ffe2631df29547c58f739f6c6b40f842 -#: ../../src/tutorial.rst:345 -msgid "" -"You can differentiate any SymPy expression using ``diff(func, var)``. " -"Examples::" -msgstr "" -"Можете израчунати извод сваког израза користећи ``diff(func, var)``. " -"Примери::" - -# 31c914e4e1d24d339b2d297e91144d99 -#: ../../src/tutorial.rst:358 -msgid "You can check, that it is correct by::" -msgstr "можете проверити да ли је то тачно са::" - -# 7a41e20394b14882addbc11d398a5152 -#: ../../src/tutorial.rst:366 -msgid "" -"Higher derivatives can be calculated using the ``diff(func, var, n)`` " -"method::" -msgstr "" -"Виши изводи се могу израчунати користећи метод ``diff(func, var, n)``::" - -# 7c36b1afe47e4414bbbf477856b93f2f -#: ../../src/tutorial.rst:383 -msgid "Series expansion" -msgstr "Развој редова" - -# 4f03d2633af941ba8802336c80c2df18 -#: ../../src/tutorial.rst:385 -msgid "Use ``.series(var, point, order)``::" -msgstr "Користите ``.series(var, point, order)``::" - -# 86ce06e6462b41449cc09592dfc434b0 -#: ../../src/tutorial.rst:400 -msgid "Another simple example::" -msgstr "Још један једноставан пример::" - -# 588350b07e8946c3990190b5e03eeb79 -#: ../../src/tutorial.rst:424 -msgid "Summation" -msgstr "" - -# c8e0a258ce834d868419e0aed64142e9 -#: ../../src/tutorial.rst:426 -msgid "" -"Compute the summation of f with respect to the given summation variable over " -"the given limits." -msgstr "" - -# 8399e19ad841458d9a517e24cd647081 -#: ../../src/tutorial.rst:428 -msgid "" -"summation(f, (i, a, b)) computes the sum of f with respect to i from a to b, " -"i.e., ::" -msgstr "" - -# 2257b464c29d4d7f8fad17e106053f41 -#: ../../src/tutorial.rst:439 -msgid "" -"If it cannot compute the sum, it prints the corresponding summation formula. " -"Repeated sums can be computed by introducing additional limits::" -msgstr "" - -# 4542d494b86c4fa99ce66c6290ecae99 -#: ../../src/tutorial.rst:473 -msgid "Integration" -msgstr "Интеграција" - -# d92d3c04d91b4b63983e1d141228f06d -#: ../../src/tutorial.rst:475 -msgid "" -"SymPy has support for indefinite and definite integration of transcendental " -"elementary and special functions via ``integrate()`` facility, which uses " -"powerful extended Risch-Norman algorithm and some heuristics and pattern " -"matching::" -msgstr "" -"SymPy има подршку за одређену и неодређену интеграцију трансцендентних, " -"елементарних и специјалних функција преко методе ``integrate()`` које " -"користи моћни проширени Risch-Norman алгоритам и неке хеуристике и обрасце " -"поклапања::" - -# 0859295f6e274d33bdfa6443f56ab293 -#: ../../src/tutorial.rst:483 -msgid "You can integrate elementary functions::" -msgstr "Можете интегрирати елементарне функције::" - -# d804281ea3a44c55a9cc6cf37ca6777e -#: ../../src/tutorial.rst:496 -msgid "Also special functions are handled easily::" -msgstr "Можете користити и разне специјалне функције::" - -# b403c8bac8634fab984faabd11282d09 -#: ../../src/tutorial.rst:504 -#, fuzzy -msgid "It is possible to compute definite integrals::" -msgstr "Могуће је израчунати одређени интеграл::" - -# 41b911ff4564469aa4801d0a22af54b5 -#: ../../src/tutorial.rst:513 -#, fuzzy -msgid "Also, improper integrals are supported as well::" -msgstr "Такође су подржани неправилни интеграли::" - -# 7fee892c967b41a9851fa0048a40ede7 -#: ../../src/tutorial.rst:525 -msgid "Complex numbers" -msgstr "Комплексни бројеви" - -# a1aeb9f0079544e5bf8b2dd8e56f1115 -#: ../../src/tutorial.rst:527 -msgid "" -"Besides the imaginary unit, I, which is imaginary, symbols can be created " -"with attributes (e.g. real, positive, complex, etc...) and this will affect " -"how they behave::" -msgstr "" - -# 2d2cfa46a8a8437daf67166b7d21e739 -#: ../../src/tutorial.rst:544 -msgid "Functions" -msgstr "Функције" - -# a5c83d7868bd483ebe9da35a50b93295 -#: ../../src/tutorial.rst:546 -msgid "**trigonometric**::" -msgstr "**тригонометријске**::" - -# 7ddac9e1abd9465b8820620d71dddf2c -#: ../../src/tutorial.rst:595 -msgid "**spherical harmonics**::" -msgstr "**сферне хармонике**::" - -# d697dd4f00d3476b97cfbeae88a3b1db -#: ../../src/tutorial.rst:621 -msgid "**factorials and gamma function**::" -msgstr "**Факторијали и гама функције**::" - -# 1aa2da311a3b474daa25ce1ee6451ee9 -#: ../../src/tutorial.rst:639 -msgid "**zeta function**::" -msgstr "**Зета функције**::" - -# 40f77901a1414910ae5fd917371e9029 -#: ../../src/tutorial.rst:664 -msgid "**polynomials**::" -msgstr "**Полиноми**::" - -# a500ab13e2ad48e79e315e64498601fc -#: ../../src/tutorial.rst:703 -msgid "Differential Equations" -msgstr "Диференцијални рачун" - -# 8977e1a0f5a64f869fd9c5940e6eec0b -# 18717d4795ca44fbb4603eb1c65ac069 -#: ../../src/tutorial.rst:705 ../../src/tutorial.rst:725 -msgid "In ``isympy``::" -msgstr "Користећи ``isympy``::" - -# 902a2850cb6849cc832e9ce0af5dfad1 -#: ../../src/tutorial.rst:723 -msgid "Algebraic equations" -msgstr "Алгебарска рачун" - -# 161eae9902d44cacbc715e4f88f9eec1 -#: ../../src/tutorial.rst:738 -msgid "Linear Algebra" -msgstr "Линеарна алгебра" - -# 251181b49ed2424d9a83b481dbbb1192 -#: ../../src/tutorial.rst:743 -msgid "Matrices" -msgstr "Матрице" - -# 2398f781625140588d06c38fe77407b4 -#: ../../src/tutorial.rst:745 -msgid "Matrices are created as instances from the Matrix class::" -msgstr "Матрице се праве као инстанце класе Matrix::" - -# 69fa45ebce294c6386716a0090a48ce4 -#: ../../src/tutorial.rst:753 -#, fuzzy -msgid "They can also contain symbols::" -msgstr "можете такође ставити симболе::" - -# 203197367b344cc3a137d2d8b4e59417 -#: ../../src/tutorial.rst:768 -#, fuzzy -msgid "For more about Matrices, see the Linear Algebra tutorial." -msgstr "" -"За више информација и примера са матрицама, погледајте LinearAlgebraTutorial." - -# dec03cbf93fe4b4f8d3bcb9d55e4b4f3 -#: ../../src/tutorial.rst:773 -msgid "Pattern matching" -msgstr "Поклапање образаца" - -# 507b066dfb884397b1ea2ec88cce6b52 -#: ../../src/tutorial.rst:775 -msgid "" -"Use the ``.match()`` method, along with the ``Wild`` class, to perform " -"pattern matching on expressions. The method will return a dictionary with " -"the required substitutions, as follows::" -msgstr "" -"Користите метод ``.match()`` са класом ``Wild``, да би извршили образац " -"одговарајуће на изразе. Овај метод ће вратити речник (dictionary) са " -"потребним изменама, као::" - -# 78ee6cfe25414349a32f7dd4687c12aa -#: ../../src/tutorial.rst:789 -msgid "If the match is unsuccessful, it returns ``None``::" -msgstr "Ако је претрага неуспешна, метода враћа ``None``::" - -# dd920a1228b0490f980d4bd279ea738b -#: ../../src/tutorial.rst:794 -msgid "" -"One can also use the exclude parameter of the ``Wild`` class to ensure that " -"certain things do not show up in the result::" -msgstr "" -"Можете користити параметар exclude класе ``Wild`` да би били сигурни да се " -"одређене ствари неће приказати у реѕултату::" - -# 0605f8d8c8024f379c2b8e899741fdfa -#: ../../src/tutorial.rst:808 -msgid "Printing" -msgstr "Штампање" - -# 48e9db5b7bf54be585ad546091c74ee4 -#: ../../src/tutorial.rst:810 -#, fuzzy -msgid "There are many ways to print expressions." -msgstr "Постоји више начина како изрази могу бити одштампани." - -# a09097b4e7a74229a371941755140507 -#: ../../src/tutorial.rst:812 -msgid "**Standard**" -msgstr "**Стандардно**" - -# 2ce6dbe6a79947489b06106ba712b796 -#: ../../src/tutorial.rst:814 -msgid "This is what ``str(expression)`` returns and it looks like this:" -msgstr "Ово је резултат методе ``str(expression)`` и изгледа као:" - -# 9f5d40c04bda4b82ac85645b7a24d675 -#: ../../src/tutorial.rst:825 -msgid "**Pretty printing**" -msgstr "**Лепше штампање**" - -# dfa02b1fa94e43fd8a8f2386c4f2b1bf -#: ../../src/tutorial.rst:827 -#, fuzzy -msgid "Nice ascii-art printing is produced by the ``pprint`` function:" -msgstr "Ово је лепше ascii штампање направљено са функцијом ``pprint``:" - -# 41b2c797a817417f9fc14b8229aae679 -#: ../../src/tutorial.rst:846 -#, fuzzy -msgid "" -"If you have a unicode font installed, the ``pprint`` function will use it by " -"default. You can override this using the ``use_unicode`` option.:" -msgstr "" -"Ако имате неки уникод фонт инсталиран, лепше штампање би се требало " -"подразумевано користити. Можете прескочити та подешавања користећи опцију " -"``use_unicode`` :" - -# 79fc29f0c47c4d5fa8a3c2b9012d2037 -#: ../../src/tutorial.rst:856 -msgid "" -"See also the wiki `Pretty Printing `_ for more examples of a nice unicode printing." -msgstr "" -"Погледајте и вики `Pretty Printing `_ за више примера лепог уникодног штампања." - -# 7f872c2470f04fff99a919413b91ca9b -#: ../../src/tutorial.rst:860 -#, fuzzy -msgid "" -"Tip: To make pretty printing the default in the Python interpreter, use::" -msgstr "" -"Савет: Да бисте направили лепо штампање подразумеваним у Python интерпретеру " -"користите::" - -# 69c732f302704f6c9fc8fe1b72671799 -#: ../../src/tutorial.rst:883 -msgid "**Python printing**" -msgstr "**Python штампање**" - -# 4719cc79e4a64895a01f73999d66eb79 -#: ../../src/tutorial.rst:899 -msgid "**LaTeX printing**" -msgstr "**LaTeX штампање**" - -# 5684f424fdca4ab28a1cfddc35d677cd -#: ../../src/tutorial.rst:916 -msgid "**MathML**" -msgstr "**MathML**" - -# 4f6686ebad314fdfb7538e18459d70da -#: ../../src/tutorial.rst:928 -msgid "**Pyglet**" -msgstr "**Pyglet**" - -# 140ace33a61c44098b4e8f45ceebd41c -#: ../../src/tutorial.rst:934 -#, fuzzy -msgid "" -"If pyglet is installed, a pyglet window will open containing the LaTeX " -"rendered expression:" -msgstr "И отвориће се pyglet прозор са даним изразом у формату LaTeX:" - -# 332d3050ee6647b982caffe51722baef -#: ../../src/tutorial.rst:940 -msgid "Notes" -msgstr "Белешке" - -# 0abe6d6f7fc64f8fa5ce10bd16a99c0b -#: ../../src/tutorial.rst:942 -msgid "" -"``isympy`` calls ``pprint`` automatically, so that's why you see pretty " -"printing by default." -msgstr "" -"``isympy`` позива ``pprint`` аутоматски , зато видите лепо штампање као " -"подразумевано." - -# d3af37494c0245ed84c60314c438b827 -#: ../../src/tutorial.rst:945 -msgid "" -"Note that there is also a printing module available, ``sympy.printing``. " -"Other printing methods available through this module are:" -msgstr "" -"Такође постоји модул за штампање, ``sympy.printing``. Остали доступни методи " -"штампања су:" - -# 89f50850bac24c3fa3fe9e68572dc933 -#: ../../src/tutorial.rst:948 -msgid "" -"``pretty(expr)``, ``pretty_print(expr)``, ``pprint(expr)``: Return or print, " -"respectively, a pretty representation of ``expr``. This is the same as the " -"second level of representation described above." -msgstr "" -"``pretty(expr)``, ``pretty_print(expr)``, ``pprint(expr)``: Враћа или " -"штампа, лепо представљање од ``expr``. Ово је исто као и други ново " -"представљања опсаног изнад." - -# 96e4352823004e70b048f9c6a69c9fed -#: ../../src/tutorial.rst:950 -msgid "" -"``latex(expr)``, ``print_latex(expr)``: Return or print, respectively, a " -"`LaTeX `_ representation of ``expr``" -msgstr "" -"``latex(expr)``, ``print_latex(expr)``: Враћа или штампа `LaTeX `_ представљање од ``expr``" - -# 540cdbff4df64170a7af5324afa3c4e8 -#: ../../src/tutorial.rst:952 -msgid "" -"``mathml(expr)``, ``print_mathml(expr)``: Return or print, respectively, a " -"`MathML `_ representation of ``expr``." -msgstr "" -"``mathml(expr)``, ``print_mathml(expr)``: Враћа или штампа `MathML `_ представљање од ``expr``." - -# 33a9a6817dc74e818bffdff09b3199cf -#: ../../src/tutorial.rst:954 -msgid "" -"``print_gtk(expr)``: Print ``expr`` to `Gtkmathview `_, a GTK widget that displays MathML code. The `Gtkmathview " -"`_ program is required." -msgstr "" -"``print_gtk(expr)``: Штампа ``expr`` у `Gtkmathview `_, и GTK додатак који приказује MathML код. `Gtkmathview " -"`_ програм је потребан." - -# 3f91aff42bc7460f87e688120753204d -#: ../../src/tutorial.rst:957 -msgid "Further documentation" -msgstr "Додатна документација" - -# 03c2cab50c5b48088d5952bcc31a3258 -#: ../../src/tutorial.rst:959 -msgid "" -"Now it's time to learn more about SymPy. Go through the :ref:`SymPy User's " -"Guide ` and :ref:`SymPy Modules Reference `." -msgstr "" -"Сада можете учити даље. Погледајте: :ref:`SymPy User's Guide ` и :ref:" -"`SymPy Modules Reference `. Напомена: Остатак документације је " -"доступан само на енглеском језику." - -# fa19b5393f05490bac4274b097994dbc -#: ../../src/tutorial.rst:963 -#, fuzzy -msgid "" -"Be sure to also browse our public `wiki.sympy.org `_, that contains a lot of useful examples, tutorials, cookbooks that we " -"and our users contributed, and feel free to edit it." -msgstr "" -"Претражите и наш јавни `wiki.sympy.org `_, који " -"садрже доста корисних примера, туторијала, који су наши корисници донирали и " -"ми вас охрабрујемо да их уредите." - -# d6c1908345d1415296e33daaeaa1ee21 -#: ../../src/tutorial.rst:968 -msgid "Translations" -msgstr "" - -# 1c1b1120057c4cd880583fc0d619b4eb -#: ../../src/tutorial.rst:970 -msgid "This tutorial is also available in other languages:" -msgstr "" - -# 623cc4a0271f4835adb70ab66b0756a4 -#~ msgid "That should print the following after the execution::" -#~ msgstr "То би требало да одштампа следеће после покретања::" diff -Nru python3-sympy-0.7.2/examples/advanced/autowrap_integrators.py python3-sympy-0.7.3/examples/advanced/autowrap_integrators.py --- python3-sympy-0.7.2/examples/advanced/autowrap_integrators.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/examples/advanced/autowrap_integrators.py 2013-07-13 17:53:31.000000000 +0000 @@ -36,7 +36,7 @@ from sympy.utilities.lambdify import implemented_function from sympy.utilities.autowrap import autowrap, ufuncify from sympy import Idx, IndexedBase, Lambda, pprint, Symbol, oo, Integral,\ - Function + Function from sympy.physics.sho import R_nl from sympy.physics.hydrogen import R_nl as hydro_nl @@ -54,6 +54,7 @@ # *************************************************************************** + def main(): print(__doc__) @@ -78,19 +79,16 @@ expr = expr.evalf(15) print("The h.o. wave function with l = %i and n = %i is" % ( - orbital_momentum_l, n)) + orbital_momentum_l, n)) pprint(expr) # implement, compile and wrap it as a ufunc basis_ho[n] = ufuncify(x, expr) - # now let's see if we can express a hydrogen radial wave in terms of # the ho basis. Here's the solution we will approximate: - H_ufunc = ufuncify(x, hydro_nl(hydrogen_n, orbital_momentum_l, 1, x)) - # The transformation to a different basis can be written like this, # # psi(r) = sum_i c(i) phi_i(r) @@ -110,7 +108,6 @@ # the low-level code. (In fact, summations are very easy to create, and as # we will see it is often necessary to take extra steps in order to avoid # them.) - # we need one integration ufunc for each wave function in the h.o. basis binary_integrator = {} for n in range(basis_dimension): @@ -131,7 +128,6 @@ psi_ho = implemented_function('psi_ho', Lambda(x, R_nl(n, orbital_momentum_l, omega2, x))) - # We represent the hydrogen function by an array which will be an input # argument to the binary routine. This will let the integrators find # h.o. basis coefficients for any wave function we throw at them. @@ -141,7 +137,7 @@ # setup expression for the integration # - step = Symbol('step') # use symbolic stepsize for flexibility + step = Symbol('step') # use symbolic stepsize for flexibility # let i represent an index of the grid array, and let A represent the # grid array. Then we can approximate the integral by a sum over the @@ -150,7 +146,7 @@ expr = A[i]**2*psi_ho(A[i])*psi[i]*step - if n==0: + if n == 0: print("Setting up binary integrators for the integral:") pprint(Integral(x**2*psi_ho(x)*Function('psi')(x), (x, 0, oo))) @@ -165,28 +161,26 @@ binary_integrator[n] = autowrap(expr, args=[A.label, psi.label, step, m]) # Lets see how it converges with the grid dimension - print("Checking convergence of integrator for n = %i" %n) + print("Checking convergence of integrator for n = %i" % n) for g in range(3, 8): grid, step = np.linspace(0, rmax, 2**g, retstep=True) print("grid dimension %5i, integral = %e" % (2**g, binary_integrator[n](grid, H_ufunc(grid), step))) - print("A binary integrator has been set up for each basis state") print("We will now use them to reconstruct a hydrogen solution.") # Note: We didn't need to specify grid or use gridsize before now grid, stepsize = np.linspace(0, rmax, gridsize, retstep=True) - print("Calculating coefficients with gridsize = %i and stepsize %f" %( - len(grid), stepsize)) + print("Calculating coefficients with gridsize = %i and stepsize %f" % ( + len(grid), stepsize)) coeffs = {} for n in range(basis_dimension): coeffs[n] = binary_integrator[n](grid, H_ufunc(grid), stepsize) print("c(%i) = %e" % (n, coeffs[n])) - print("Constructing the approximate hydrogen wave") hydro_approx = 0 all_steps = {} @@ -194,8 +188,7 @@ hydro_approx += basis_ho[n](grid)*coeffs[n] all_steps[n] = hydro_approx.copy() if pylab: - line = pylab.plot(grid, all_steps[n], ':', label='max n = %i'%n) - + line = pylab.plot(grid, all_steps[n], ':', label='max n = %i' % n) # check error numerically diff = np.max(np.abs(hydro_approx - H_ufunc(grid))) @@ -205,7 +198,6 @@ else: print("Ah, that's a pretty good approximation!") - # Check visually if pylab: print("Here's a plot showing the contribution for each n") diff -Nru python3-sympy-0.7.2/examples/advanced/curvilinear_coordinates.py python3-sympy-0.7.3/examples/advanced/curvilinear_coordinates.py --- python3-sympy-0.7.2/examples/advanced/curvilinear_coordinates.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/examples/advanced/curvilinear_coordinates.py 2013-07-13 17:53:31.000000000 +0000 @@ -10,7 +10,8 @@ """ from sympy import var, sin, cos, pprint, Matrix, eye, trigsimp, Eq, \ - Function, simplify, sinh, cosh, expand + Function, simplify, sinh, cosh, expand + def laplace(f, g_inv, g_det, X): """ @@ -27,6 +28,7 @@ f.diff(X[alpha]) / (2*g_det) return r + def transform(name, X, Y, g_correct=None, recursive=False): """ Transforms from cartesian coordinates X to any curvilinear coordinates Y. @@ -62,7 +64,7 @@ print("metric tensor g_{ij} specified by hand:") pprint(g) print("inverse metric tensor g^{ij}:") - g_inv = g.inv("ADJ") + g_inv = g.inv(method="ADJ") g_inv = g_inv.applyfunc(simplify) pprint(g_inv) print("det g_{ij}:") @@ -85,15 +87,15 @@ Matrix([rho*sin(theta)*cos(phi), rho*sin(theta)*sin(phi), rho*cos(theta)]), [rho, theta, phi], - recursive=True - ) + recursive=True + ) transform("rotating disk", - Matrix([t, x*cos(w*t)-y*sin(w*t), x*sin(w*t)+y*cos(w*t), z]), + Matrix([t, x*cos(w*t) - y*sin(w*t), x*sin(w*t) + y*cos(w*t), z]), [t, x, y, z]) transform("parabolic", - Matrix([sigma*tau, (tau**2-sigma**2)/2]), + Matrix([sigma*tau, (tau**2 - sigma**2)/2]), [sigma, tau]) # too complex: @@ -106,7 +108,7 @@ transform("elliptic", Matrix([a*cosh(mu)*cos(nu), a*sinh(mu)*sin(nu)]), [mu, nu] - ) + ) if __name__ == "__main__": main() diff -Nru python3-sympy-0.7.2/examples/advanced/dense_coding_example.py python3-sympy-0.7.3/examples/advanced/dense_coding_example.py --- python3-sympy-0.7.2/examples/advanced/dense_coding_example.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/examples/advanced/dense_coding_example.py 2013-07-13 17:53:31.000000000 +0000 @@ -9,8 +9,10 @@ from sympy.physics.quantum.circuitplot import circuit_plot from sympy.physics.quantum.grover import superposition_basis + def main(): - psi = superposition_basis(2); psi + psi = superposition_basis(2) + psi # Dense coding demo: @@ -25,26 +27,30 @@ # To Send Bob the message |0>|0> print("To Send Bob the message |00>.") - circuit = H(1)*CNOT(1,0) - result = qapply(circuit*psi); result + circuit = H(1)*CNOT(1, 0) + result = qapply(circuit*psi) + result pprint(result) # To send Bob the message |0>|1> print("To Send Bob the message |01>.") - circuit = H(1)*CNOT(1,0)*X(1) - result = qapply(circuit*psi); result + circuit = H(1)*CNOT(1, 0)*X(1) + result = qapply(circuit*psi) + result pprint(result) # To send Bob the message |1>|0> print("To Send Bob the message |10>.") - circuit = H(1)*CNOT(1,0)*Z(1) - result = qapply(circuit*psi); result + circuit = H(1)*CNOT(1, 0)*Z(1) + result = qapply(circuit*psi) + result pprint(result) # To send Bob the message |1>|1> print("To Send Bob the message |11>.") - circuit = H(1)*CNOT(1,0)*Z(1)*X(1) - result = qapply(circuit*psi); result + circuit = H(1)*CNOT(1, 0)*Z(1)*X(1) + result = qapply(circuit*psi) + result pprint(result) if __name__ == "__main__": diff -Nru python3-sympy-0.7.2/examples/advanced/fem.py python3-sympy-0.7.3/examples/advanced/fem.py --- python3-sympy-0.7.2/examples/advanced/fem.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/examples/advanced/fem.py 2013-07-13 17:53:31.000000000 +0000 @@ -16,191 +16,190 @@ """ from sympy import symbols, Symbol, factorial, Rational, zeros, div, eye, \ - integrate, diff, pprint, reduced + integrate, diff, pprint, reduced x, y, z = symbols('x,y,z') + class ReferenceSimplex: - def __init__(self, nsd): - self.nsd = nsd - if nsd <= 3: - coords = symbols('x,y,z')[:nsd] - else: - coords = [Symbol("x_%d" % d) for d in range(nsd)] - self.coords = coords - - def integrate(self,f): - coords = self.coords - nsd = self.nsd - - limit = 1 - for p in coords: - limit -= p - - intf = f - for d in range(0,nsd): - p = coords[d] - limit += p - intf = integrate(intf, (p, 0, limit)) - return intf + def __init__(self, nsd): + self.nsd = nsd + if nsd <= 3: + coords = symbols('x,y,z')[:nsd] + else: + coords = [Symbol("x_%d" % d) for d in range(nsd)] + self.coords = coords + + def integrate(self, f): + coords = self.coords + nsd = self.nsd + + limit = 1 + for p in coords: + limit -= p + + intf = f + for d in range(0, nsd): + p = coords[d] + limit += p + intf = integrate(intf, (p, 0, limit)) + return intf + def bernstein_space(order, nsd): - if nsd > 3: - raise RuntimeError("Bernstein only implemented in 1D, 2D, and 3D") - sum = 0 - basis = [] - coeff = [] - - if nsd == 1: - b1, b2 = x, 1-x - for o1 in range(0,order+1): - for o2 in range(0,order+1): - if o1 + o2 == order: - aij = Symbol("a_%d_%d" % (o1,o2)) - sum += aij*binomial(order,o1)*pow(b1, o1)*pow(b2, o2) - basis.append(binomial(order,o1)*pow(b1, o1)*pow(b2, o2)) - coeff.append(aij) - - - if nsd == 2: - b1, b2, b3 = x, y, 1-x-y - for o1 in range(0,order+1): - for o2 in range(0,order+1): - for o3 in range(0,order+1): - if o1 + o2 + o3 == order: - aij = Symbol("a_%d_%d_%d" % (o1,o2,o3)) - fac = factorial(order) / (factorial(o1)*factorial(o2)*factorial(o3)) - sum += aij*fac*pow(b1, o1)*pow(b2, o2)*pow(b3, o3) - basis.append(fac*pow(b1, o1)*pow(b2, o2)*pow(b3, o3)) - coeff.append(aij) - - if nsd == 3: - b1, b2, b3, b4 = x, y, z, 1-x-y-z - for o1 in range(0,order+1): - for o2 in range(0,order+1): - for o3 in range(0,order+1): - for o4 in range(0,order+1): - if o1 + o2 + o3 + o4 == order: - aij = Symbol("a_%d_%d_%d_%d" % (o1,o2,o3,o4)) - fac = factorial(order)/ (factorial(o1)*factorial(o2)*factorial(o3)*factorial(o4)) - sum += aij*fac*pow(b1, o1)*pow(b2, o2)*pow(b3, o3)*pow(b4, o4) - basis.append(fac*pow(b1, o1)*pow(b2, o2)*pow(b3, o3)*pow(b4, o4)) - coeff.append(aij) + if nsd > 3: + raise RuntimeError("Bernstein only implemented in 1D, 2D, and 3D") + sum = 0 + basis = [] + coeff = [] + + if nsd == 1: + b1, b2 = x, 1 - x + for o1 in range(0, order + 1): + for o2 in range(0, order + 1): + if o1 + o2 == order: + aij = Symbol("a_%d_%d" % (o1, o2)) + sum += aij*binomial(order, o1)*pow(b1, o1)*pow(b2, o2) + basis.append(binomial(order, o1)*pow(b1, o1)*pow(b2, o2)) + coeff.append(aij) + + if nsd == 2: + b1, b2, b3 = x, y, 1 - x - y + for o1 in range(0, order + 1): + for o2 in range(0, order + 1): + for o3 in range(0, order + 1): + if o1 + o2 + o3 == order: + aij = Symbol("a_%d_%d_%d" % (o1, o2, o3)) + fac = factorial(order) / (factorial(o1)*factorial(o2)*factorial(o3)) + sum += aij*fac*pow(b1, o1)*pow(b2, o2)*pow(b3, o3) + basis.append(fac*pow(b1, o1)*pow(b2, o2)*pow(b3, o3)) + coeff.append(aij) + + if nsd == 3: + b1, b2, b3, b4 = x, y, z, 1 - x - y - z + for o1 in range(0, order + 1): + for o2 in range(0, order + 1): + for o3 in range(0, order + 1): + for o4 in range(0, order + 1): + if o1 + o2 + o3 + o4 == order: + aij = Symbol("a_%d_%d_%d_%d" % (o1, o2, o3, o4)) + fac = factorial(order)/ (factorial(o1)*factorial(o2)*factorial(o3)*factorial(o4)) + sum += aij*fac*pow(b1, o1)*pow(b2, o2)*pow(b3, o3)*pow(b4, o4) + basis.append(fac*pow(b1, o1)*pow(b2, o2)*pow(b3, o3)*pow(b4, o4)) + coeff.append(aij) + return sum, coeff, basis - return sum, coeff, basis def create_point_set(order, nsd): - h = Rational(1,order) - set = [] + h = Rational(1, order) + set = [] - if nsd == 1: - for i in range(0, order+1): - x = i*h - if x <= 1: - set.append((x,y)) - - if nsd == 2: - for i in range(0, order+1): - x = i*h - for j in range(0, order+1): - y = j*h - if x + y <= 1: - set.append((x,y)) - - if nsd == 3: - for i in range(0, order+1): - x = i*h - for j in range(0, order+1): - y = j*h - for k in range(0, order+1): - z = j*h - if x + y + z <= 1: - set.append((x,y,z)) - - return set + if nsd == 1: + for i in range(0, order + 1): + x = i*h + if x <= 1: + set.append((x, y)) + + if nsd == 2: + for i in range(0, order + 1): + x = i*h + for j in range(0, order + 1): + y = j*h + if x + y <= 1: + set.append((x, y)) + + if nsd == 3: + for i in range(0, order + 1): + x = i*h + for j in range(0, order + 1): + y = j*h + for k in range(0, order + 1): + z = j*h + if x + y + z <= 1: + set.append((x, y, z)) + return set def create_matrix(equations, coeffs): - A = zeros(len(equations)) - i = 0; j = 0 - for j in range(0, len(coeffs)): - c = coeffs[j] - for i in range(0, len(equations)): - e = equations[i] - d, _ = reduced(e, [c]) - A[i,j] = d[0] - return A - + A = zeros(len(equations)) + i = 0 + j = 0 + for j in range(0, len(coeffs)): + c = coeffs[j] + for i in range(0, len(equations)): + e = equations[i] + d, _ = reduced(e, [c]) + A[i, j] = d[0] + return A class Lagrange: - def __init__(self,nsd, order): - self.nsd = nsd - self.order = order - self.compute_basis() - - def nbf(self): - return len(self.N) - - def compute_basis(self): - order = self.order - nsd = self.nsd - N = [] - pol, coeffs, basis = bernstein_space(order, nsd) - points = create_point_set(order, nsd) - - equations = [] - for p in points: - ex = pol.subs(x, p[0]) - if nsd > 1: - ex = ex.subs(y, p[1]) - if nsd > 2: - ex = ex.subs(z, p[2]) - equations.append(ex ) - - A = create_matrix(equations, coeffs) - Ainv = A.inv() - - b = eye(len(equations)) - - xx = Ainv*b - - for i in range(0,len(equations)): - Ni = pol - for j in range(0,len(coeffs)): - Ni = Ni.subs(coeffs[j], xx[j,i]) - N.append(Ni) + def __init__(self, nsd, order): + self.nsd = nsd + self.order = order + self.compute_basis() + + def nbf(self): + return len(self.N) + + def compute_basis(self): + order = self.order + nsd = self.nsd + N = [] + pol, coeffs, basis = bernstein_space(order, nsd) + points = create_point_set(order, nsd) + + equations = [] + for p in points: + ex = pol.subs(x, p[0]) + if nsd > 1: + ex = ex.subs(y, p[1]) + if nsd > 2: + ex = ex.subs(z, p[2]) + equations.append(ex ) + + A = create_matrix(equations, coeffs) + Ainv = A.inv() + + b = eye(len(equations)) + + xx = Ainv*b + + for i in range(0, len(equations)): + Ni = pol + for j in range(0, len(coeffs)): + Ni = Ni.subs(coeffs[j], xx[j, i]) + N.append(Ni) - self.N = N + self.N = N def main(): - t = ReferenceSimplex(2) - fe = Lagrange(2,2) + t = ReferenceSimplex(2) + fe = Lagrange(2, 2) - u = 0 - #compute u = sum_i u_i N_i - us = [] - for i in range(0, fe.nbf()): - ui = Symbol("u_%d" % i) - us.append(ui) - u += ui*fe.N[i] - - - J = zeros(fe.nbf()) - for i in range(0, fe.nbf()): - Fi = u*fe.N[i] - print(Fi) - for j in range(0, fe.nbf()): - uj = us[j] - integrands = diff(Fi, uj) - print(integrands) - J[j,i] = t.integrate(integrands) + u = 0 + #compute u = sum_i u_i N_i + us = [] + for i in range(0, fe.nbf()): + ui = Symbol("u_%d" % i) + us.append(ui) + u += ui*fe.N[i] + + J = zeros(fe.nbf()) + for i in range(0, fe.nbf()): + Fi = u*fe.N[i] + print(Fi) + for j in range(0, fe.nbf()): + uj = us[j] + integrands = diff(Fi, uj) + print(integrands) + J[j, i] = t.integrate(integrands) - pprint(J) + pprint(J) if __name__ == "__main__": - main() + main() diff -Nru python3-sympy-0.7.2/examples/advanced/gibbs_phenomenon.py python3-sympy-0.7.3/examples/advanced/gibbs_phenomenon.py --- python3-sympy-0.7.2/examples/advanced/gibbs_phenomenon.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/examples/advanced/gibbs_phenomenon.py 2013-07-13 17:53:31.000000000 +0000 @@ -14,12 +14,13 @@ """ from sympy import var, sqrt, integrate, conjugate, seterr, Abs, pprint, I, pi,\ - sin, cos, sign, Plot, lambdify, Integral, S + sin, cos, sign, Plot, lambdify, Integral, S #seterr(True) x = var("x", real=True) + def l2_norm(f, lim): """ Calculates L2 norm of the function "f", over the domain lim=(x, a, b). @@ -40,21 +41,24 @@ """ return sqrt(integrate(Abs(f)**2, lim)) + def l2_inner_product(a, b, lim): """ Calculates the L2 inner product (a, b) over the domain lim. """ return integrate(conjugate(a)*b, lim) + def l2_projection(f, basis, lim): """ L2 projects the function f on the basis over the domain lim. """ r = 0 for b in basis: - r += l2_inner_product(f, b, lim) * b + r += l2_inner_product(f, b, lim) * b return r + def l2_gram_schmidt(list, lim): """ Orthonormalizes the "list" of functions using the Gram-Schmidt process. @@ -81,9 +85,11 @@ r.append(v/v_norm) return r + def integ(f): return integrate(f, (x, -pi, 0)) + integrate(-f, (x, 0, pi)) + def series(L): """ Normalizes the series. @@ -93,6 +99,7 @@ r += integ(b)*b return r + def msolve(f, x): """ Finds the first root of f(x) to the left of 0. @@ -104,20 +111,21 @@ f = lambdify(x, f) x0 = -0.001 dx = 0.001 - while f(x0-dx) * f(x0) > 0: - x0 = x0-dx - x_max = x0-dx + while f(x0 - dx) * f(x0) > 0: + x0 = x0 - dx + x_max = x0 - dx x_min = x0 assert f(x_max) > 0 assert f(x_min) < 0 for n in range(100): - x0 = (x_max+x_min)/2 + x0 = (x_max + x_min)/2 if f(x0) > 0: x_max = x0 else: x_min = x0 return x0 + def main(): #L = l2_gram_schmidt([1, cos(x), sin(x), cos(2*x), sin(2*x)], (x, -pi, pi)) #L = l2_gram_schmidt([1, cos(x), sin(x)], (x, -pi, pi)) diff -Nru python3-sympy-0.7.2/examples/advanced/grover_example.py python3-sympy-0.7.3/examples/advanced/grover_example.py --- python3-sympy-0.7.2/examples/advanced/grover_example.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/examples/advanced/grover_example.py 2013-07-13 17:53:31.000000000 +0000 @@ -8,15 +8,18 @@ from sympy.physics.quantum.grover import (OracleGate, superposition_basis, WGate, grover_iteration) + def demo_vgate_app(v): for i in range(2**v.nqubits): print('qapply(v*IntQubit(%i, %r))' % (i, v.nqubits)) pprint(qapply(v*IntQubit(i, v.nqubits))) qapply(v*IntQubit(i, v.nqubits)) + def black_box(qubits): return True if qubits == IntQubit(1, qubits.nqubits) else False + def main(): print() print('Demonstration of Grover\'s Algorithm') diff -Nru python3-sympy-0.7.2/examples/advanced/hydrogen.py python3-sympy-0.7.3/examples/advanced/hydrogen.py --- python3-sympy-0.7.2/examples/advanced/hydrogen.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/examples/advanced/hydrogen.py 2013-07-13 17:53:31.000000000 +0000 @@ -4,12 +4,13 @@ This example shows how to work with the Hydrogen radial wavefunctions. """ -from sympy import var, pprint, Integral, oo, Eq +from sympy import Eq, Integral, oo, pprint, symbols from sympy.physics.hydrogen import R_nl + def main(): print("Hydrogen radial wavefunctions:") - var("r a") + a, r = symbols("a r") print("R_{21}:") pprint(R_nl(2, 1, a, r)) print("R_{60}:") @@ -18,10 +19,8 @@ print("Normalization:") i = Integral(R_nl(1, 0, 1, r)**2 * r**2, (r, 0, oo)) pprint(Eq(i, i.doit())) - i = Integral(R_nl(2, 0, 1, r)**2 * r**2, (r, 0, oo)) pprint(Eq(i, i.doit())) - i = Integral(R_nl(2, 1, 1, r)**2 * r**2, (r, 0, oo)) pprint(Eq(i, i.doit())) diff -Nru python3-sympy-0.7.2/examples/advanced/pidigits.py python3-sympy-0.7.3/examples/advanced/pidigits.py --- python3-sympy-0.7.2/examples/advanced/pidigits.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/examples/advanced/pidigits.py 2013-07-13 17:53:31.000000000 +0000 @@ -13,27 +13,29 @@ from time import clock import sys + def display_fraction(digits, skip=0, colwidth=10, columns=5): """Pretty printer for first n digits of a fraction""" perline = colwidth * columns printed = 0 - for linecount in range((len(digits)-skip) // (colwidth * columns)): - line = digits[skip+linecount*perline:skip+(linecount+1)*perline] + for linecount in range((len(digits) - skip) // (colwidth * columns)): + line = digits[skip + linecount*perline:skip + (linecount + 1)*perline] for i in range(columns): - print(line[i*colwidth : (i+1)*colwidth], end=' ') - print(":", (linecount+1)*perline) - if (linecount+1) % 10 == 0: + print(line[i*colwidth: (i + 1)*colwidth], end=' ') + print(":", (linecount + 1)*perline) + if (linecount + 1) % 10 == 0: print() printed += colwidth*columns - rem = (len(digits)-skip) % (colwidth * columns) + rem = (len(digits) - skip) % (colwidth * columns) if rem: buf = digits[-rem:] s = "" for i in range(columns): - s += buf[:colwidth].ljust(colwidth+1, " ") + s += buf[:colwidth].ljust(colwidth + 1, " ") buf = buf[colwidth:] print(s + ":", printed + colwidth*columns) + def calculateit(func, base, n, tofile): """Writes first n base-digits of a mpmath function to file""" prec = 100 @@ -43,7 +45,7 @@ else: skip = len(intpart) print("Step 1 of 2: calculating binary value...") - prec = int(n*math.log(base,2))+10 + prec = int(n*math.log(base, 2)) + 10 t = clock() a = func(prec) step1_time = clock() - t @@ -64,6 +66,7 @@ print("\nFinished in %f seconds (%f calc, %f convert)" % \ ((step1_time + step2_time), step1_time, step2_time)) + def interactive(): """Simple function to interact with user""" print("Compute digits of pi with SymPy\n") @@ -74,6 +77,7 @@ tofile = open(tofile, "w") calculateit(pi, base, digits, tofile) + def main(): """A non-interactive runner""" base = 16 diff -Nru python3-sympy-0.7.2/examples/advanced/pyglet_plotting.py python3-sympy-0.7.3/examples/advanced/pyglet_plotting.py --- python3-sympy-0.7.2/examples/advanced/pyglet_plotting.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/examples/advanced/pyglet_plotting.py 2013-07-13 17:53:31.000000000 +0000 @@ -15,8 +15,9 @@ from time import sleep, clock import collections + def main(): - x,y,z = symbols('x,y,z') + x, y, z = symbols('x,y,z') # toggle axes visibility with F5, colors with F6 axes_options = 'visible=false; colored=true; label_ticks=true; label_axes=true; overlay=true; stride=0.5' @@ -25,19 +26,20 @@ p = PygletPlot(width=600, height=500, ortho=False, invert_mouse_zoom=False, axes=axes_options, antialiasing=True) examples = [] + def example_wrapper(f): examples.append(f) return f @example_wrapper def mirrored_saddles(): - p[5] = x**2-y**2, [20], [20] - p[6] = y**2-x**2, [20], [20] + p[5] = x**2 - y**2, [20], [20] + p[6] = y**2 - x**2, [20], [20] @example_wrapper def mirrored_saddles_saveimage(): - p[5] = x**2-y**2, [20], [20] - p[6] = y**2-x**2, [20], [20] + p[5] = x**2 - y**2, [20], [20] + p[6] = y**2 - x**2, [20], [20] p.wait_for_calculations() # although the calculation is complete, # we still need to wait for it to be @@ -47,19 +49,19 @@ @example_wrapper def mirrored_ellipsoids(): - p[2] = x**2+y**2, [40], [40], 'color=zfade' - p[3] = -x**2-y**2, [40], [40], 'color=zfade' + p[2] = x**2 + y**2, [40], [40], 'color=zfade' + p[3] = -x**2 - y**2, [40], [40], 'color=zfade' @example_wrapper def saddle_colored_by_derivative(): - f = x**2-y**2 + f = x**2 - y**2 p[1] = f, 'style=solid' p[1].color = abs(f.diff(x)), abs(f.diff(x) + f.diff(y)), abs(f.diff(y)) @example_wrapper def ding_dong_surface(): - f = sqrt(1.0-y)*y - p[1] = f, [x,0,2*pi,40], [y,-1,4,100], 'mode=cylindrical; style=solid; color=zfade4' + f = sqrt(1.0 - y)*y + p[1] = f, [x, 0, 2*pi, 40], [y, -1, 4, 100], 'mode=cylindrical; style=solid; color=zfade4' @example_wrapper def polar_circle(): @@ -68,7 +70,7 @@ @example_wrapper def polar_flower(): p[8] = 1.5*sin(4*x), [160], 'mode=polar' - p[8].color = z, x, y, (0.5,0.5,0.5), (0.8,0.8,0.8), (x,y,None,z) # z is used for t + p[8].color = z, x, y, (0.5, 0.5, 0.5), (0.8, 0.8, 0.8), (x, y, None, z) # z is used for t @example_wrapper def simple_cylinder(): @@ -77,39 +79,39 @@ @example_wrapper def cylindrical_hyperbola(): ## (note that polar is an alias for cylindrical) - p[10] = 1/y, 'mode=polar', [x], [y,-2,2,20] + p[10] = 1/y, 'mode=polar', [x], [y, -2, 2, 20] @example_wrapper def extruded_hyperbolas(): - p[11] = 1/x, [x,-10,10,100], [1], 'style=solid' - p[12] = -1/x, [x,-10,10,100], [1], 'style=solid' + p[11] = 1/x, [x, -10, 10, 100], [1], 'style=solid' + p[12] = -1/x, [x, -10, 10, 100], [1], 'style=solid' @example_wrapper def torus(): - a,b = 1, 0.5 # radius, thickness - p[13] = (a+b*cos(x))*cos(y), (a+b*cos(x))*sin(y), b*sin(x), [x,0,pi*2,40], [y,0,pi*2,40] + a, b = 1, 0.5 # radius, thickness + p[13] = (a + b*cos(x))*cos(y), (a + b*cos(x))*sin(y), b*sin(x), [x, 0, pi*2, 40], [y, 0, pi*2, 40] @example_wrapper def warped_torus(): - a,b = 2, 1 # radius, thickness - p[13] = (a+b*cos(x))*cos(y), (a+b*cos(x))*sin(y), b*sin(x)+0.5*sin(4*y), [x,0,pi*2,40], [y,0,pi*2,40] + a, b = 2, 1 # radius, thickness + p[13] = (a + b*cos(x))*cos(y), (a + b*cos(x))*sin(y), b*sin(x) + 0.5*sin(4*y), [x, 0, pi*2, 40], [y, 0, pi*2, 40] @example_wrapper def parametric_spiral(): - p[14] = cos(y), sin(y), y/10.0, [y,-4*pi,4*pi,100] - p[14].color = x,(0.1,0.9),y,(0.1,0.9),z,(0.1,0.9) + p[14] = cos(y), sin(y), y/10.0, [y, -4*pi, 4*pi, 100] + p[14].color = x, (0.1, 0.9), y, (0.1, 0.9), z, (0.1, 0.9) @example_wrapper def multistep_gradient(): p[1] = 1, 'mode=spherical', 'style=both' #p[1] = exp(-x**2-y**2+(x*y)/4), [-1.7,1.7,100], [-1.7,1.7,100], 'style=solid' #p[1] = 5*x*y*exp(-x**2-y**2), [-2,2,100], [-2,2,100] - gradient = [ 0.0, (0.3, 0.3, 1.0), + gradient = [ 0.0, (0.3, 0.3, 1.0), 0.30, (0.3, 1.0, 0.3), - 0.55, (0.95,1.0, 0.2), - 0.65, (1.0,0.95, 0.2), + 0.55, (0.95, 1.0, 0.2), + 0.65, (1.0, 0.95, 0.2), 0.85, (1.0, 0.7, 0.2), - 1.0, (1.0, 0.3, 0.2) ] + 1.0, (1.0, 0.3, 0.2) ] p[1].color = z, [None, None, z], gradient #p[1].color = 'zfade' #p[1].color = 'zfade3' @@ -117,14 +119,14 @@ @example_wrapper def lambda_vs_sympy_evaluation(): start = clock() - p[4] = x**2+y**2, [100], [100], 'style=solid' + p[4] = x**2 + y**2, [100], [100], 'style=solid' p.wait_for_calculations() - print("lambda-based calculation took %s seconds." % (clock()-start)) + print("lambda-based calculation took %s seconds." % (clock() - start)) start = clock() - p[4] = x**2+y**2, [100], [100], 'style=solid; use_sympy_eval' + p[4] = x**2 + y**2, [100], [100], 'style=solid; use_sympy_eval' p.wait_for_calculations() - print("sympy substitution-based calculation took %s seconds." % (clock()-start)) + print("sympy substitution-based calculation took %s seconds." % (clock() - start)) @example_wrapper def gradient_vectors(): @@ -140,8 +142,8 @@ representing the gradient of f. """ dx, dy, dz = f.diff(x), f.diff(y), 0 - FF = lambdify( [x,y], [x,y,f] ) - FG = lambdify( [x,y], [dx,dy,dz] ) + FF = lambdify( [x, y], [x, y, f] ) + FG = lambdify( [x, y], [dx, dy, dz] ) iu.v_steps /= 5 iv.v_steps /= 5 Gvl = list(list([FF(u, v), FG(u, v)] @@ -172,7 +174,7 @@ glEnd() return draw - p[i] = f, [-0.5,0.5,25], [-0.5,0.5,25], 'style=solid' + p[i] = f, [-0.5, 0.5, 25], [-0.5, 0.5, 25], 'style=solid' iu = PlotInterval(p[i].intervals[0]) iv = PlotInterval(p[i].intervals[1]) p[i].postdraw.append(draw_gradient_vectors(f, iu, iv)) @@ -181,9 +183,9 @@ gradient_vectors_inner(-x**2 - y**2, 2) def help_str(): - s = ("\nPlot p has been created. Useful commands: \n" - " help(p), p[1] = x**2, print p, p.clear() \n\n" - "Available examples (see source in plotting.py):\n\n") + s = ("\nPlot p has been created. Useful commands: \n" + " help(p), p[1] = x**2, print p, p.clear() \n\n" + "Available examples (see source in plotting.py):\n\n") for i in range(len(examples)): s += "(%i) %s\n" % (i, examples[i].__name__) s += "\n" @@ -198,10 +200,11 @@ elif i >= 0 and i < len(examples): p.clear() examples[i]() - else: print("Not a valid example.\n") + else: + print("Not a valid example.\n") print(p) - example(0) # 0 - 15 are defined above + example(0) # 0 - 15 are defined above print(help_str()) if __name__ == "__main__": diff -Nru python3-sympy-0.7.2/examples/advanced/qft.py python3-sympy-0.7.3/examples/advanced/qft.py --- python3-sympy-0.7.2/examples/advanced/qft.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/examples/advanced/qft.py 2013-07-13 17:53:31.000000000 +0000 @@ -15,114 +15,119 @@ """ -from sympy import Basic,exp,Symbol,sin,Rational,I,Mul, Matrix, \ +from sympy import Basic, exp, Symbol, sin, Rational, I, Mul, Matrix, \ ones, sqrt, pprint, simplify, Eq, sympify from sympy.physics import msigma, mgamma #gamma^mu -gamma0=mgamma(0) -gamma1=mgamma(1) -gamma2=mgamma(2) -gamma3=mgamma(3) -gamma5=mgamma(5) +gamma0 = mgamma(0) +gamma1 = mgamma(1) +gamma2 = mgamma(2) +gamma3 = mgamma(3) +gamma5 = mgamma(5) #sigma_i -sigma1=msigma(1) -sigma2=msigma(2) -sigma3=msigma(3) +sigma1 = msigma(1) +sigma2 = msigma(2) +sigma3 = msigma(3) E = Symbol("E", real=True) m = Symbol("m", real=True) -def u(p,r): + +def u(p, r): """ p = (p1, p2, p3); r = 0,1 """ - assert r in [1,2] - p1,p2,p3 = p + assert r in [1, 2] + p1, p2, p3 = p if r == 1: - ksi = Matrix([[1],[0]]) + ksi = Matrix([[1], [0]]) else: - ksi = Matrix([[0],[1]]) - a = (sigma1*p1 + sigma2*p2 + sigma3*p3) / (E+m) * ksi - if a ==0: + ksi = Matrix([[0], [1]]) + a = (sigma1*p1 + sigma2*p2 + sigma3*p3) / (E + m) * ksi + if a == 0: a = zeros(2, 1) - return sqrt(E+m) * Matrix([[ksi[0,0]], [ksi[1,0]], [a[0,0]], [a[1,0]]]) + return sqrt(E + m) * Matrix([[ksi[0, 0]], [ksi[1, 0]], [a[0, 0]], [a[1, 0]]]) + -def v(p,r): +def v(p, r): """ p = (p1, p2, p3); r = 0,1 """ - assert r in [1,2] - p1,p2,p3 = p + assert r in [1, 2] + p1, p2, p3 = p if r == 1: - ksi = Matrix([[1],[0]]) + ksi = Matrix([[1], [0]]) else: - ksi = -Matrix([[0],[1]]) - a = (sigma1*p1 + sigma2*p2 + sigma3*p3) / (E+m) * ksi - if a ==0: + ksi = -Matrix([[0], [1]]) + a = (sigma1*p1 + sigma2*p2 + sigma3*p3) / (E + m) * ksi + if a == 0: a = zeros(2, 1) - return sqrt(E+m) * Matrix([[a[0,0]], [a[1,0]], [ksi[0,0]], [ksi[1,0]]]) + return sqrt(E + m) * Matrix([[a[0, 0]], [a[1, 0]], [ksi[0, 0]], [ksi[1, 0]]]) + def pslash(p): - p1,p2,p3 = p - p0 = sqrt(m**2+p1**2+p2**2+p3**2) - return gamma0*p0-gamma1*p1-gamma2*p2-gamma3*p3 + p1, p2, p3 = p + p0 = sqrt(m**2 + p1**2 + p2**2 + p3**2) + return gamma0*p0 - gamma1*p1 - gamma2*p2 - gamma3*p3 + def Tr(M): return M.trace() + def xprint(lhs, rhs): pprint( Eq(sympify(lhs), rhs ) ) + def main(): - a=Symbol("a", real=True) - b=Symbol("b", real=True) - c=Symbol("c", real=True) + a = Symbol("a", real=True) + b = Symbol("b", real=True) + c = Symbol("c", real=True) - p = (a,b,c) + p = (a, b, c) assert u(p, 1).D * u(p, 2) == Matrix(1, 1, [0]) assert u(p, 2).D * u(p, 1) == Matrix(1, 1, [0]) - p1,p2,p3 =[Symbol(x, real=True) for x in ["p1","p2","p3"]] - pp1,pp2,pp3 =[Symbol(x, real=True) for x in ["pp1","pp2","pp3"]] - k1,k2,k3 =[Symbol(x, real=True) for x in ["k1","k2","k3"]] - kp1,kp2,kp3 =[Symbol(x, real=True) for x in ["kp1","kp2","kp3"]] + p1, p2, p3 = [Symbol(x, real=True) for x in ["p1", "p2", "p3"]] + pp1, pp2, pp3 = [Symbol(x, real=True) for x in ["pp1", "pp2", "pp3"]] + k1, k2, k3 = [Symbol(x, real=True) for x in ["k1", "k2", "k3"]] + kp1, kp2, kp3 = [Symbol(x, real=True) for x in ["kp1", "kp2", "kp3"]] - p = (p1,p2,p3) - pp = (pp1,pp2,pp3) + p = (p1, p2, p3) + pp = (pp1, pp2, pp3) - k = (k1,k2,k3) - kp = (kp1,kp2,kp3) + k = (k1, k2, k3) + kp = (kp1, kp2, kp3) mu = Symbol("mu") - e = (pslash(p)+m*ones(4))*(pslash(k)-m*ones(4)) - f = pslash(p)+m*ones(4) - g = pslash(p)-m*ones(4) - + e = (pslash(p) + m*ones(4))*(pslash(k) - m*ones(4)) + f = pslash(p) + m*ones(4) + g = pslash(p) - m*ones(4) #pprint(e) xprint( 'Tr(f*g)', Tr(f*g) ) #print Tr(pslash(p) * pslash(k)).expand() - M0 = [ ( v(pp, 1).D * mgamma(mu) * u(p, 1) ) * ( u(k, 1).D * mgamma(mu,True) * \ + M0 = [ ( v(pp, 1).D * mgamma(mu) * u(p, 1) ) * ( u(k, 1).D * mgamma(mu, True) * v(kp, 1) ) for mu in range(4)] - M = M0[0]+M0[1]+M0[2]+M0[3] + M = M0[0] + M0[1] + M0[2] + M0[3] M = M[0] assert isinstance(M, Basic) #print M #print simplify(M) - d=Symbol("d", real=True) #d=E+m + d = Symbol("d", real=True) # d=E+m xprint('M', M) print("-"*40) - M = ((M.subs(E,d-m)).expand() * d**2 ).expand() - xprint('M2', 1/(E+m)**2 * M) + M = ((M.subs(E, d - m)).expand() * d**2 ).expand() + xprint('M2', 1/(E + m)**2 * M) print("-"*40) - x,y= M.as_real_imag() + x, y = M.as_real_imag() xprint('Re(M)', x) xprint('Im(M)', y) - e = x**2+y**2 + e = x**2 + y**2 xprint('abs(M)**2', e) print("-"*40) xprint('Expand(abs(M)**2)', e.expand()) diff -Nru python3-sympy-0.7.2/examples/advanced/relativity.py python3-sympy-0.7.3/examples/advanced/relativity.py --- python3-sympy-0.7.2/examples/advanced/relativity.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/examples/advanced/relativity.py 2013-07-13 17:53:31.000000000 +0000 @@ -16,79 +16,86 @@ from sympy import (exp, Symbol, sin, Rational, Derivative, dsolve, Function, Matrix, Eq, pprint, Pow, classify_ode, solve) -def grad(f,X): - a=[] + +def grad(f, X): + a = [] for x in X: a.append(f.diff(x)) return a -def d(m,x): - return grad(m[0,0],x) + +def d(m, x): + return grad(m[0, 0], x) + class MT(object): - def __init__(self,m): - self.gdd=m - self.guu=m.inv() + def __init__(self, m): + self.gdd = m + self.guu = m.inv() def __str__(self): return "g_dd =\n" + str(self.gdd) - def dd(self,i,j): - return self.gdd[i,j] + def dd(self, i, j): + return self.gdd[i, j] + + def uu(self, i, j): + return self.guu[i, j] - def uu(self,i,j): - return self.guu[i,j] class G(object): - def __init__(self,g,x): + def __init__(self, g, x): self.g = g self.x = x - def udd(self,i,k,l): - g=self.g - x=self.x - r=0 - for m in [0,1,2,3]: - r+=g.uu(i,m)/2 * (g.dd(m,k).diff(x[l])+g.dd(m,l).diff(x[k]) \ - - g.dd(k,l).diff(x[m])) + def udd(self, i, k, l): + g = self.g + x = self.x + r = 0 + for m in [0, 1, 2, 3]: + r += g.uu(i, m)/2 * (g.dd(m, k).diff(x[l]) + g.dd(m, l).diff(x[k]) + - g.dd(k, l).diff(x[m])) return r + class Riemann(object): - def __init__(self,G,x): + def __init__(self, G, x): self.G = G self.x = x - def uddd(self,rho,sigma,mu,nu): - G=self.G - x=self.x - r=G.udd(rho,nu,sigma).diff(x[mu])-G.udd(rho,mu,sigma).diff(x[nu]) - for lam in [0,1,2,3]: - r+=G.udd(rho,mu,lam)*G.udd(lam,nu,sigma) \ - -G.udd(rho,nu,lam)*G.udd(lam,mu,sigma) + def uddd(self, rho, sigma, mu, nu): + G = self.G + x = self.x + r = G.udd(rho, nu, sigma).diff(x[mu]) - G.udd(rho, mu, sigma).diff(x[nu]) + for lam in [0, 1, 2, 3]: + r += G.udd(rho, mu, lam)*G.udd(lam, nu, sigma) \ + - G.udd(rho, nu, lam)*G.udd(lam, mu, sigma) return r + class Ricci(object): - def __init__(self,R,x): + def __init__(self, R, x): self.R = R self.x = x self.g = R.G.g - def dd(self,mu,nu): - R=self.R - x=self.x - r=0 - for lam in [0,1,2,3]: - r+=R.uddd(lam,mu,lam,nu) + def dd(self, mu, nu): + R = self.R + x = self.x + r = 0 + for lam in [0, 1, 2, 3]: + r += R.uddd(lam, mu, lam, nu) return r - def ud(self,mu,nu): - r=0 - for lam in [0,1,2,3]: - r+=self.g.uu(mu,lam)*self.dd(lam,nu) + def ud(self, mu, nu): + r = 0 + for lam in [0, 1, 2, 3]: + r += self.g.uu(mu, lam)*self.dd(lam, nu) return r.expand() + def curvature(Rmn): - return Rmn.ud(0,0)+Rmn.ud(1,1)+Rmn.ud(2,2)+Rmn.ud(3,3) + return Rmn.ud(0, 0) + Rmn.ud(1, 1) + Rmn.ud(2, 2) + Rmn.ud(3, 3) #class nu(Function): # def getname(self): @@ -102,18 +109,18 @@ nu = Function("nu") lam = Function("lambda") -t=Symbol("t") -r=Symbol("r") -theta=Symbol(r"theta") -phi=Symbol(r"phi") +t = Symbol("t") +r = Symbol("r") +theta = Symbol(r"theta") +phi = Symbol(r"phi") #general, spherically symmetric metric -gdd=Matrix(( - (-exp(nu(r)),0,0,0), +gdd = Matrix(( + (-exp(nu(r)), 0, 0, 0), (0, exp(lam(r)), 0, 0), (0, 0, r**2, 0), (0, 0, 0, r**2*sin(theta)**2) - )) +)) #spherical - flat #gdd=Matrix(( # (-1, 0, 0, 0), @@ -135,86 +142,90 @@ # (0, 0, r**2*sin(theta)**2, 0), # (0, 0, 0, r**2) # )) -g=MT(gdd) -X=(t,r,theta,phi) -Gamma=G(g,X) -Rmn=Ricci(Riemann(Gamma,X),X) +g = MT(gdd) +X = (t, r, theta, phi) +Gamma = G(g, X) +Rmn = Ricci(Riemann(Gamma, X), X) -def pprint_Gamma_udd(i,k,l): - pprint(Eq(Symbol('Gamma^%i_%i%i' % (i,k,l)), Gamma.udd(i,k,l))) -def pprint_Rmn_dd(i,j): - pprint(Eq(Symbol('R_%i%i' % (i,j)), Rmn.dd(i,j))) +def pprint_Gamma_udd(i, k, l): + pprint(Eq(Symbol('Gamma^%i_%i%i' % (i, k, l)), Gamma.udd(i, k, l))) + + +def pprint_Rmn_dd(i, j): + pprint(Eq(Symbol('R_%i%i' % (i, j)), Rmn.dd(i, j))) # from Differential Equations example def eq1(): r = Symbol("r") - e = Rmn.dd(0,0) + e = Rmn.dd(0, 0) e = e.subs(nu(r), -lam(r)) pprint(dsolve(e, lam(r))) + def eq2(): r = Symbol("r") - e = Rmn.dd(1,1) + e = Rmn.dd(1, 1) C = Symbol("CC") e = e.subs(nu(r), -lam(r)) pprint(dsolve(e, lam(r))) + def eq3(): r = Symbol("r") - e = Rmn.dd(2,2) + e = Rmn.dd(2, 2) e = e.subs(nu(r), -lam(r)) pprint(dsolve(e, lam(r))) + def eq4(): r = Symbol("r") - e = Rmn.dd(3,3) + e = Rmn.dd(3, 3) e = e.subs(nu(r), -lam(r)) pprint(dsolve(e, lam(r))) pprint(dsolve(e, lam(r), 'best')) - def main(): print("Initial metric:") pprint(gdd) print("-"*40) print("Christoffel symbols:") - pprint_Gamma_udd(0,1,0) - pprint_Gamma_udd(0,0,1) + pprint_Gamma_udd(0, 1, 0) + pprint_Gamma_udd(0, 0, 1) print() - pprint_Gamma_udd(1,0,0) - pprint_Gamma_udd(1,1,1) - pprint_Gamma_udd(1,2,2) - pprint_Gamma_udd(1,3,3) + pprint_Gamma_udd(1, 0, 0) + pprint_Gamma_udd(1, 1, 1) + pprint_Gamma_udd(1, 2, 2) + pprint_Gamma_udd(1, 3, 3) print() - pprint_Gamma_udd(2,2,1) - pprint_Gamma_udd(2,1,2) - pprint_Gamma_udd(2,3,3) + pprint_Gamma_udd(2, 2, 1) + pprint_Gamma_udd(2, 1, 2) + pprint_Gamma_udd(2, 3, 3) print() - pprint_Gamma_udd(3,2,3) - pprint_Gamma_udd(3,3,2) - pprint_Gamma_udd(3,1,3) - pprint_Gamma_udd(3,3,1) + pprint_Gamma_udd(3, 2, 3) + pprint_Gamma_udd(3, 3, 2) + pprint_Gamma_udd(3, 1, 3) + pprint_Gamma_udd(3, 3, 1) print("-"*40) print("Ricci tensor:") - pprint_Rmn_dd(0,0) - e = Rmn.dd(1,1) - pprint_Rmn_dd(1,1) - pprint_Rmn_dd(2,2) - pprint_Rmn_dd(3,3) + pprint_Rmn_dd(0, 0) + e = Rmn.dd(1, 1) + pprint_Rmn_dd(1, 1) + pprint_Rmn_dd(2, 2) + pprint_Rmn_dd(3, 3) #print #print "scalar curvature:" #print curvature(Rmn) print("-"*40) print("Solve Einstein's equations:") e = e.subs(nu(r), -lam(r)).doit() - l = dsolve(e, lam(r)) + l = dsolve(e, lam(r)) pprint(l) lamsol = solve(l, lam(r))[0] - metric = gdd.subs(lam(r), lamsol).subs(nu(r),-lamsol)#.combine() + metric = gdd.subs(lam(r), lamsol).subs(nu(r), -lamsol) # .combine() print("metric:") pprint(metric) diff -Nru python3-sympy-0.7.2/examples/all.py python3-sympy-0.7.3/examples/all.py --- python3-sympy-0.7.2/examples/all.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/examples/all.py 2013-07-13 17:53:31.000000000 +0000 @@ -71,7 +71,7 @@ "advanced.pidigits", "advanced.qft", "advanced.relativity", - ] +] WINDOWED_EXAMPLES = [ "beginner.plotting_nice_plot", @@ -81,10 +81,11 @@ "advanced.autowrap_integrators", "advanced.autowrap_ufuncify", "advanced.pyglet_plotting", - ] +] EXAMPLE_DIR = os.path.dirname(__file__) + def __import__(name, globals=None, locals=None, fromlist=None): """An alternative to the import function so that we can import modules defined as strings. @@ -177,7 +178,8 @@ class DummyFile(object): - def write(self, x): pass + def write(self, x): + pass def suppress_output(fn): diff -Nru python3-sympy-0.7.2/examples/beginner/basic.py python3-sympy-0.7.3/examples/beginner/basic.py --- python3-sympy-0.7.2/examples/beginner/basic.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/examples/beginner/basic.py 2013-07-13 17:53:31.000000000 +0000 @@ -8,6 +8,7 @@ import sympy from sympy import pprint + def main(): a = sympy.Symbol('a') b = sympy.Symbol('b') diff -Nru python3-sympy-0.7.2/examples/beginner/differentiation.py python3-sympy-0.7.3/examples/beginner/differentiation.py --- python3-sympy-0.7.2/examples/beginner/differentiation.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/examples/beginner/differentiation.py 2013-07-13 17:53:31.000000000 +0000 @@ -8,6 +8,7 @@ import sympy from sympy import pprint + def main(): a = sympy.Symbol('a') b = sympy.Symbol('b') diff -Nru python3-sympy-0.7.2/examples/beginner/expansion.py python3-sympy-0.7.3/examples/beginner/expansion.py --- python3-sympy-0.7.2/examples/beginner/expansion.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/examples/beginner/expansion.py 2013-07-13 17:53:31.000000000 +0000 @@ -8,6 +8,7 @@ import sympy from sympy import pprint + def main(): a = sympy.Symbol('a') b = sympy.Symbol('b') diff -Nru python3-sympy-0.7.2/examples/beginner/functions.py python3-sympy-0.7.3/examples/beginner/functions.py --- python3-sympy-0.7.2/examples/beginner/functions.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/examples/beginner/functions.py 2013-07-13 17:53:31.000000000 +0000 @@ -8,6 +8,7 @@ import sympy from sympy import pprint + def main(): a = sympy.Symbol('a') b = sympy.Symbol('b') diff -Nru python3-sympy-0.7.2/examples/beginner/limits_examples.py python3-sympy-0.7.3/examples/beginner/limits_examples.py --- python3-sympy-0.7.2/examples/beginner/limits_examples.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/examples/beginner/limits_examples.py 2013-07-13 17:53:31.000000000 +0000 @@ -7,32 +7,35 @@ from sympy import exp, log, Symbol, Rational, sin, limit, sqrt, oo + def sqrt3(x): return x**Rational(1, 3) + def show(computed, correct): print("computed:", computed, "correct:", correct) + def main(): x = Symbol("x") a = Symbol("a") h = Symbol("h") - show( limit(sqrt(x**2 - 5*x + 6) - x, x, oo) , -Rational(5)/2 ) + show( limit(sqrt(x**2 - 5*x + 6) - x, x, oo), -Rational(5)/2 ) - show( limit(x*(sqrt(x**2 + 1) - x), x, oo) , Rational(1)/2 ) + show( limit(x*(sqrt(x**2 + 1) - x), x, oo), Rational(1)/2 ) - show( limit(x - sqrt3(x**3 - 1), x, oo) , Rational(0) ) + show( limit(x - sqrt3(x**3 - 1), x, oo), Rational(0) ) - show( limit(log(1 + exp(x))/x, x, -oo) , Rational(0) ) + show( limit(log(1 + exp(x))/x, x, -oo), Rational(0) ) - show( limit(log(1 + exp(x))/x, x, oo) , Rational(1) ) + show( limit(log(1 + exp(x))/x, x, oo), Rational(1) ) - show( limit(sin(3*x)/x, x, 0) , Rational(3) ) + show( limit(sin(3*x)/x, x, 0), Rational(3) ) - show( limit(sin(5*x)/sin(2*x), x, 0) , Rational(5)/2 ) + show( limit(sin(5*x)/sin(2*x), x, 0), Rational(5)/2 ) - show( limit(((x - 1)/(x + 1))**x, x, oo) , exp(-2)) + show( limit(((x - 1)/(x + 1))**x, x, oo), exp(-2)) if __name__ == "__main__": main() diff -Nru python3-sympy-0.7.2/examples/beginner/plot_examples.py python3-sympy-0.7.3/examples/beginner/plot_examples.py --- python3-sympy-0.7.2/examples/beginner/plot_examples.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/examples/beginner/plot_examples.py 2013-07-13 17:53:31.000000000 +0000 @@ -3,7 +3,7 @@ from sympy import Symbol, exp, sin, cos from sympy.plotting import (plot, plot_parametric, - plot3d_parametric_surface,plot3d_parametric_line, + plot3d_parametric_surface, plot3d_parametric_line, plot3d) lx = list(range(5)) @@ -15,29 +15,29 @@ v = Symbol('v') expr = x**2 - 1 -b = plot(expr, (x, 2, 4), show=False) # cartesian plot -e = plot(exp(-x),(x, 0, 4), show=False) # cartesian plot (and coloring, see below) +b = plot(expr, (x, 2, 4), show=False) # cartesian plot +e = plot(exp(-x), (x, 0, 4), show=False) # cartesian plot (and coloring, see below) f = plot3d_parametric_line(sin(x), cos(x), x, (x, 0, 10), show=False) # 3d parametric line plot -g = plot3d(sin(x)*cos(y), (x, -5, 5), (y, -10, 10), show=False) # 3d surface cartesian plot -h = plot3d_parametric_surface(cos(u)*v, sin(u)*v, u, (u, 0, 10),(v, -2, 2), show=False) # 3d parametric surface plot +g = plot3d(sin(x)*cos(y), (x, -5, 5), (y, -10, 10), show=False) # 3d surface cartesian plot +h = plot3d_parametric_surface(cos(u)*v, sin(u)*v, u, (u, 0, 10), (v, -2, 2), show=False) # 3d parametric surface plot # Some aesthetics -e[0].line_color = lambda x : x / 4 -f[0].line_color = lambda x, y, z : z / 10 -g[0].surface_color = lambda x, y : sin(x) +e[0].line_color = lambda x: x / 4 +f[0].line_color = lambda x, y, z: z / 10 +g[0].surface_color = lambda x, y: sin(x) # Some more stuff on aesthetics - coloring wrt coordinates or parameters param_line_2d = plot_parametric((x*cos(x), x*sin(x), (x, 0, 15)), (1.1*x*cos(x), 1.1*x*sin(x), (x, 0, 15)), show=False) -param_line_2d[0].line_color = lambda u : sin(u) # parametric -param_line_2d[1].line_color = lambda u, v : u**2 + v**2 # coordinates +param_line_2d[0].line_color = lambda u: sin(u) # parametric +param_line_2d[1].line_color = lambda u, v: u**2 + v**2 # coordinates param_line_2d.title = 'The inner one is colored by parameter and the outher one by coordinates' param_line_3d = plot3d_parametric_line((x*cos(x), x*sin(x), x, (x, 0, 15)), (1.5*x*cos(x), 1.5*x*sin(x), x, (x, 0, 15)), (2*x*cos(x), 2*x*sin(x), x, (x, 0, 15)), show=False) -param_line_3d[0].line_color = lambda u : u #parametric -param_line_3d[1].line_color = lambda u, v : u*v # first and second coordinates -param_line_3d[2].line_color = lambda u, v, w : u*v*w # all coordinates +param_line_3d[0].line_color = lambda u: u # parametric +param_line_3d[1].line_color = lambda u, v: u*v # first and second coordinates +param_line_3d[2].line_color = lambda u, v, w: u*v*w # all coordinates if __name__ == '__main__': diff -Nru python3-sympy-0.7.2/examples/beginner/plotting_nice_plot.py python3-sympy-0.7.3/examples/beginner/plotting_nice_plot.py --- python3-sympy-0.7.2/examples/beginner/plotting_nice_plot.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/examples/beginner/plotting_nice_plot.py 2013-07-13 17:53:31.000000000 +0000 @@ -8,6 +8,7 @@ from sympy import Symbol, cos, sin, Plot, log, tan from sympy.abc import x, y + def main(): fun1 = cos(x)*sin(y) fun2 = sin(x)*sin(y) diff -Nru python3-sympy-0.7.2/examples/beginner/precision.py python3-sympy-0.7.3/examples/beginner/precision.py --- python3-sympy-0.7.2/examples/beginner/precision.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/examples/beginner/precision.py 2013-07-13 17:53:31.000000000 +0000 @@ -8,6 +8,7 @@ import sympy from sympy import Mul, Pow, S + def main(): x = Pow(2, 50, evaluate=False) y = Pow(10, -50, evaluate=False) diff -Nru python3-sympy-0.7.2/examples/beginner/print_pretty.py python3-sympy-0.7.3/examples/beginner/print_pretty.py --- python3-sympy-0.7.2/examples/beginner/print_pretty.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/examples/beginner/print_pretty.py 2013-07-13 17:53:31.000000000 +0000 @@ -7,12 +7,13 @@ from sympy import Symbol, pprint, sin, cos, exp, sqrt + def main(): x = Symbol("x") y = Symbol("y") pprint( x**x ) - print('\n')# separate with two blank likes + print('\n') # separate with two blank likes pprint(x**2 + y + x) print('\n') diff -Nru python3-sympy-0.7.2/examples/beginner/series.py python3-sympy-0.7.3/examples/beginner/series.py --- python3-sympy-0.7.2/examples/beginner/series.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/examples/beginner/series.py 2013-07-13 17:53:31.000000000 +0000 @@ -7,6 +7,7 @@ from sympy import Symbol, cos, sin, pprint + def main(): x = Symbol('x') diff -Nru python3-sympy-0.7.2/examples/beginner/substitution.py python3-sympy-0.7.3/examples/beginner/substitution.py --- python3-sympy-0.7.2/examples/beginner/substitution.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/examples/beginner/substitution.py 2013-07-13 17:53:31.000000000 +0000 @@ -8,6 +8,7 @@ import sympy from sympy import pprint + def main(): x = sympy.Symbol('x') y = sympy.Symbol('y') diff -Nru python3-sympy-0.7.2/examples/intermediate/coupled_cluster.py python3-sympy-0.7.3/examples/intermediate/coupled_cluster.py --- python3-sympy-0.7.2/examples/intermediate/coupled_cluster.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/examples/intermediate/coupled_cluster.py 2013-07-13 17:53:31.000000000 +0000 @@ -14,29 +14,30 @@ symbols, expand, pprint, Rational, latex, Dummy ) -pretty_dummies_dict={ - 'above':'cdefgh', - 'below':'klmno', - 'general':'pqrstu' - } +pretty_dummies_dict = { + 'above': 'cdefgh', + 'below': 'klmno', + 'general': 'pqrstu' +} def get_CC_operators(): """ Returns a tuple (T1,T2) of unique operators. """ - i = symbols('i',below_fermi=True,cls=Dummy) - a = symbols('a',above_fermi=True,cls=Dummy) - t_ai = AntiSymmetricTensor('t',(a,),(i,)) + i = symbols('i', below_fermi=True, cls=Dummy) + a = symbols('a', above_fermi=True, cls=Dummy) + t_ai = AntiSymmetricTensor('t', (a,), (i,)) ai = NO(Fd(a)*F(i)) - i,j = symbols('i,j',below_fermi=True,cls=Dummy) - a,b = symbols('a,b',above_fermi=True,cls=Dummy) - t_abij = AntiSymmetricTensor('t',(a,b),(i,j)) + i, j = symbols('i,j', below_fermi=True, cls=Dummy) + a, b = symbols('a,b', above_fermi=True, cls=Dummy) + t_abij = AntiSymmetricTensor('t', (a, b), (i, j)) abji = NO(Fd(a)*Fd(b)*F(j)*F(i)) T1 = t_ai*ai T2 = Rational(1, 4)*t_abij*abji - return (T1,T2) + return (T1, T2) + def main(): print() @@ -47,10 +48,10 @@ print() # setup hamiltonian - p,q,r,s = symbols('p,q,r,s',cls=Dummy) - f = AntiSymmetricTensor('f',(p,),(q,)) + p, q, r, s = symbols('p,q,r,s', cls=Dummy) + f = AntiSymmetricTensor('f', (p,), (q,)) pr = NO((Fd(p)*F(q))) - v = AntiSymmetricTensor('v',(p,q),(r,s)) + v = AntiSymmetricTensor('v', (p, q), (r, s)) pqsr = NO(Fd(p)*Fd(q)*F(s)*F(r)) H = f*pr + Rational(1, 4)*v*pqsr @@ -59,36 +60,36 @@ print("Calculating 4 nested commutators") C = Commutator - T1,T2 = get_CC_operators() - T = T1+ T2 + T1, T2 = get_CC_operators() + T = T1 + T2 print("commutator 1...") - comm1 = wicks(C(H,T)) + comm1 = wicks(C(H, T)) comm1 = evaluate_deltas(comm1) comm1 = substitute_dummies(comm1) - T1,T2 = get_CC_operators() - T = T1+ T2 + T1, T2 = get_CC_operators() + T = T1 + T2 print("commutator 2...") - comm2 = wicks(C(comm1,T)) + comm2 = wicks(C(comm1, T)) comm2 = evaluate_deltas(comm2) comm2 = substitute_dummies(comm2) - T1,T2 = get_CC_operators() - T = T1+ T2 + T1, T2 = get_CC_operators() + T = T1 + T2 print("commutator 3...") - comm3 = wicks(C(comm2,T)) + comm3 = wicks(C(comm2, T)) comm3 = evaluate_deltas(comm3) comm3 = substitute_dummies(comm3) - T1,T2 = get_CC_operators() - T = T1+ T2 + T1, T2 = get_CC_operators() + T = T1 + T2 print("commutator 4...") - comm4 = wicks(C(comm3,T)) + comm4 = wicks(C(comm3, T)) comm4 = evaluate_deltas(comm4) comm4 = substitute_dummies(comm4) print("construct Hausdoff expansion...") - eq = H + comm1+comm2/2 +comm3/6+comm4/24 + eq = H + comm1 + comm2/2 + comm3/6 + comm4/24 eq = eq.expand() eq = evaluate_deltas(eq) eq = substitute_dummies(eq, new_indices=True, @@ -97,8 +98,8 @@ print() print("extracting CC equations from full Hbar") - i,j,k,l = symbols('i,j,k,l',below_fermi=True) - a,b,c,d = symbols('a,b,c,d',above_fermi=True) + i, j, k, l = symbols('i,j,k,l', below_fermi=True) + a, b, c, d = symbols('a,b,c,d', above_fermi=True) print() print("CC Energy:") print(latex(wicks(eq, simplify_dummies=True, @@ -110,9 +111,9 @@ print(latex(eqT1)) print() print("CC T2:") - eqT2 = wicks(NO(Fd(i)*Fd(j)*F(b)*F(a))*eq,simplify_dummies=True, keep_only_fully_contracted=True, simplify_kronecker_deltas=True) + eqT2 = wicks(NO(Fd(i)*Fd(j)*F(b)*F(a))*eq, simplify_dummies=True, keep_only_fully_contracted=True, simplify_kronecker_deltas=True) P = PermutationOperator - eqT2 = simplify_index_permutations(eqT2,[P(a,b),P(i,j)]) + eqT2 = simplify_index_permutations(eqT2, [P(a, b), P(i, j)]) print(latex(eqT2)) if __name__ == "__main__": diff -Nru python3-sympy-0.7.2/examples/intermediate/differential_equations.py python3-sympy-0.7.3/examples/intermediate/differential_equations.py --- python3-sympy-0.7.2/examples/intermediate/differential_equations.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/examples/intermediate/differential_equations.py 2013-07-13 17:53:31.000000000 +0000 @@ -8,6 +8,7 @@ from sympy import dsolve, Eq, Function, sin, Symbol + def main(): x = Symbol("x") f = Function("f") diff -Nru python3-sympy-0.7.2/examples/intermediate/infinite_1d_box.py python3-sympy-0.7.3/examples/intermediate/infinite_1d_box.py --- python3-sympy-0.7.2/examples/intermediate/infinite_1d_box.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/examples/intermediate/infinite_1d_box.py 2013-07-13 17:53:31.000000000 +0000 @@ -10,6 +10,7 @@ from sympy import Integral, var, S from sympy.functions import sin, sqrt + def X_n(n, a, x): """ Returns the wavefunction X_{n} for an infinite 1D box @@ -41,6 +42,7 @@ """ return ((n * pi / a)**2) / mass + def energy_corrections(perturbation, n, a=10, mass=0.5): """ Calculating first two order corrections due to perturbation theory and @@ -68,8 +70,9 @@ Vnm(n, n, a).evalf(), - (Vnm(n, n-1, a)**2/(E_n(n, a, mass) - E_n(n-1, a, mass)) - + Vnm(n, n+1, a)**2/(E_n(n, a, mass) - E_n(n+1, a, mass))).evalf()) + (Vnm(n, n - 1, a)**2/(E_n(n, a, mass) - E_n(n - 1, a, mass)) + + Vnm(n, n + 1, a)**2/(E_n(n, a, mass) - E_n(n + 1, a, mass))).evalf()) + def main(): print() diff -Nru python3-sympy-0.7.2/examples/intermediate/mplot2d.py python3-sympy-0.7.3/examples/intermediate/mplot2d.py --- python3-sympy-0.7.2/examples/intermediate/mplot2d.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/examples/intermediate/mplot2d.py 2013-07-13 17:53:31.000000000 +0000 @@ -13,6 +13,7 @@ from sympy.core.compatibility import is_sequence from sympy.external import import_module + def mplot2d(f, var, show=True): """ Plot a 2d function using matplotlib/Tk. @@ -26,7 +27,7 @@ sys.exit("Matplotlib is required to use mplot2d.") if not is_sequence(f): - f = [f,] + f = [f, ] for f_i in f: x, y = sample(f_i, var) @@ -36,6 +37,7 @@ if show: p.show() + def main(): x = Symbol('x') diff -Nru python3-sympy-0.7.2/examples/intermediate/mplot3d.py python3-sympy-0.7.3/examples/intermediate/mplot3d.py --- python3-sympy-0.7.2/examples/intermediate/mplot3d.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/examples/intermediate/mplot3d.py 2013-07-13 17:53:31.000000000 +0000 @@ -24,7 +24,7 @@ p = import_module('pylab') # Try newer version first p3 = import_module('mpl_toolkits.mplot3d', - __import__kwargs={'fromlist':['something']}) or import_module('matplotlib.axes3d') + __import__kwargs={'fromlist': ['something']}) or import_module('matplotlib.axes3d') if not p or not p3: sys.exit("Matplotlib is required to use mplot3d.") @@ -34,7 +34,7 @@ ax = p3.Axes3D(fig) #ax.plot_surface(x,y,z) #seems to be a bug in matplotlib - ax.plot_wireframe(x,y,z) + ax.plot_wireframe(x, y, z) ax.set_xlabel('X') ax.set_ylabel('Y') @@ -43,11 +43,12 @@ if show: p.show() + def main(): x = Symbol('x') y = Symbol('y') - mplot3d(x**2-y**2, (x, -10.0, 10.0, 20), (y, -10.0, 10.0, 20)) + mplot3d(x**2 - y**2, (x, -10.0, 10.0, 20), (y, -10.0, 10.0, 20)) #mplot3d(x**2+y**2, (x, -10.0, 10.0, 20), (y, -10.0, 10.0, 20)) #mplot3d(sin(x)+sin(y), (x, -3.14, 3.14, 10), (y, -3.14, 3.14, 10)) diff -Nru python3-sympy-0.7.2/examples/intermediate/partial_differential_eqs.py python3-sympy-0.7.3/examples/intermediate/partial_differential_eqs.py --- python3-sympy-0.7.2/examples/intermediate/partial_differential_eqs.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/examples/intermediate/partial_differential_eqs.py 2013-07-13 17:53:31.000000000 +0000 @@ -8,51 +8,50 @@ from sympy import symbols, Eq, Function, pde_separate, pprint, sin, cos, latex from sympy import Derivative as D + def main(): r, phi, theta = symbols("r,phi,theta") Xi = Function('Xi') R, Phi, Theta, u = list(map(Function, ['R', 'Phi', 'Theta', 'u'])) C1, C2 = symbols('C1,C2') - pprint ("Separation of variables in Laplace equation in spherical coordinates") - pprint ("Laplace equation in spherical coordinates:") - eq = Eq(D(Xi(r, phi, theta), r, 2) + 2/r * D(Xi(r, phi, theta),r) + \ - 1/(r**2 * sin(phi)**2) * D(Xi(r, phi, theta), theta, 2) + \ - cos(phi)/(r**2 * sin(phi)) * D(Xi(r, phi, theta), phi) + \ + pprint("Separation of variables in Laplace equation in spherical coordinates") + pprint("Laplace equation in spherical coordinates:") + eq = Eq(D(Xi(r, phi, theta), r, 2) + 2/r * D(Xi(r, phi, theta), r) + + 1/(r**2 * sin(phi)**2) * D(Xi(r, phi, theta), theta, 2) + + cos(phi)/(r**2 * sin(phi)) * D(Xi(r, phi, theta), phi) + 1/r**2 * D(Xi(r, phi, theta), phi, 2)) - pprint (eq) + pprint(eq) - pprint ("We can either separate this equation in regards with variable r:") + pprint("We can either separate this equation in regards with variable r:") res_r = pde_separate(eq, Xi(r, phi, theta), [R(r), u(phi, theta)]) - pprint (res_r) + pprint(res_r) - pprint ("Or separate it in regards of theta:") + pprint("Or separate it in regards of theta:") res_theta = pde_separate(eq, Xi(r, phi, theta), [Theta(theta), u(r, phi)]) - pprint (res_theta) + pprint(res_theta) res_phi = pde_separate(eq, Xi(r, phi, theta), [Phi(phi), u(r, theta)]) - pprint ("But we cannot separate it in regards of variable phi: ") - pprint ("Result: %s" % res_phi) + pprint("But we cannot separate it in regards of variable phi: ") + pprint("Result: %s" % res_phi) - pprint ("\n\nSo let's make theta dependent part equal with -C1:") + pprint("\n\nSo let's make theta dependent part equal with -C1:") eq_theta = Eq(res_theta[0], -C1) - pprint (eq_theta) - pprint ("\nThis also means that second part is also equal to -C1:") + pprint(eq_theta) + pprint("\nThis also means that second part is also equal to -C1:") eq_left = Eq(res_theta[1], -C1) - pprint (eq_left) + pprint(eq_left) - pprint ("\nLets try to separate phi again :)") + pprint("\nLets try to separate phi again :)") res_theta = pde_separate(eq_left, u(r, phi), [Phi(phi), R(r)]) - pprint ("\nThis time it is successful:") - pprint (res_theta) - - pprint ("\n\nSo our final equations with separated variables are:") - pprint (eq_theta) - pprint (Eq(res_theta[0],C2)) - pprint (Eq(res_theta[1],C2)) - + pprint("\nThis time it is successful:") + pprint(res_theta) + pprint("\n\nSo our final equations with separated variables are:") + pprint(eq_theta) + pprint(Eq(res_theta[0], C2)) + pprint(Eq(res_theta[1], C2)) if __name__ == "__main__": diff -Nru python3-sympy-0.7.2/examples/intermediate/print_gtk.py python3-sympy-0.7.3/examples/intermediate/print_gtk.py --- python3-sympy-0.7.2/examples/intermediate/print_gtk.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/examples/intermediate/print_gtk.py 2013-07-13 17:53:31.000000000 +0000 @@ -7,6 +7,7 @@ from sympy import Integral, Limit, print_gtk, sin, Symbol + def main(): x = Symbol('x') diff -Nru python3-sympy-0.7.2/examples/intermediate/sample.py python3-sympy-0.7.3/examples/intermediate/sample.py --- python3-sympy-0.7.2/examples/intermediate/sample.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/examples/intermediate/sample.py 2013-07-13 17:53:31.000000000 +0000 @@ -5,8 +5,9 @@ graphing functions using matplotlib. """ -from numpy import repeat, arange, empty, ndarray, array -from sympy import Symbol, Basic, Rational, I, sympify +from sympy.core.sympify import sympify, SympifyError +from sympy.external import import_module +np = import_module('numpy') def sample2d(f, x_args): """ @@ -28,9 +29,9 @@ x_l = float(x_max - x_min) x_d = x_l/float(x_n) - X = arange(float(x_min), float(x_max)+x_d, x_d) + X = np.arange(float(x_min), float(x_max) + x_d, x_d) - Y = empty(len(X)) + Y = np.empty(len(X)) for i in range(len(X)): try: Y[i] = float(f.subs(x, X[i])) @@ -38,6 +39,7 @@ Y[i] = None return X, Y + def sample3d(f, x_args, y_args): """ Samples a 3d function f over specified intervals and returns three @@ -61,29 +63,29 @@ x_l = float(x_max - x_min) x_d = x_l/float(x_n) - x_a = arange(float(x_min), float(x_max)+x_d, x_d) + x_a = np.arange(float(x_min), float(x_max) + x_d, x_d) y_l = float(y_max - y_min) y_d = y_l/float(y_n) - y_a = arange(float(y_min), float(y_max)+y_d, y_d) + y_a = np.arange(float(y_min), float(y_max) + y_d, y_d) def meshgrid(x, y): """ Taken from matplotlib.mlab.meshgrid. """ - x = array(x) - y = array(y) + x = np.array(x) + y = np.array(y) numRows, numCols = len(y), len(x) x.shape = 1, numCols - X = repeat(x, numRows, 0) + X = np.repeat(x, numRows, 0) y.shape = numRows, 1 - Y = repeat(y, numCols, 1) + Y = np.repeat(y, numCols, 1) return X, Y - X, Y = meshgrid(x_a, y_a) + X, Y = np.meshgrid(x_a, y_a) - Z = ndarray((len(X), len(X[0]))) + Z = np.ndarray((len(X), len(X[0]))) for j in range(len(X)): for k in range(len(X[0])): try: @@ -92,6 +94,7 @@ Z[j][k] = 0 return X, Y, Z + def sample(f, *var_args): """ Samples a 2d or 3d function over specified intervals and returns diff -Nru python3-sympy-0.7.2/examples/intermediate/trees.py python3-sympy-0.7.3/examples/intermediate/trees.py --- python3-sympy-0.7.2/examples/intermediate/trees.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/examples/intermediate/trees.py 2013-07-13 17:53:31.000000000 +0000 @@ -14,15 +14,18 @@ from sympy import Symbol, Poly + def T(x): - return x+x**2+2*x**3 + 4*x**4 + 9*x**5 + 20*x**6 + 48 * x**7 + \ - 115* x**8 + 286*x**9+719*x**10 + return x + x**2 + 2*x**3 + 4*x**4 + 9*x**5 + 20*x**6 + 48 * x**7 + \ + 115* x**8 + 286*x**9 + 719*x**10 + def A(x): return 1 + T(x) - T(x)**2/2 + T(x**2)/2 + def main(): - x=Symbol("x") + x = Symbol("x") s = Poly(A(x), x) num = list(reversed(s.coeffs()))[:11] diff -Nru python3-sympy-0.7.2/examples/intermediate/vandermonde.py python3-sympy-0.7.3/examples/intermediate/vandermonde.py --- python3-sympy-0.7.2/examples/intermediate/vandermonde.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/examples/intermediate/vandermonde.py 2013-07-13 17:53:31.000000000 +0000 @@ -8,6 +8,7 @@ from sympy import Matrix, pprint, Rational, sqrt, symbols, Symbol, zeros + def symbol_gen(sym_str): """Symbol generator @@ -63,7 +64,7 @@ for i in range(rank): row_syms = [next(g) for g in generators] all_syms.append(row_syms) - for j,term in enumerate(terms): + for j, term in enumerate(terms): v_entry = 1 for k in term: v_entry *= row_syms[k] @@ -82,8 +83,8 @@ V, tmp_syms, terms = vandermonde(order, dim) if num_pts < V.shape[0]: raise ValueError( - "Must provide %d points for order %d, dimension "\ - "%d polynomial, given %d points" % \ + "Must provide %d points for order %d, dimension " + "%d polynomial, given %d points" % (V.shape[0], order, dim, num_pts)) elif num_pts > V.shape[0]: print("gen_poly given %d points but only requires %d, "\ @@ -101,7 +102,7 @@ coeffs = V_inv.multiply(Matrix([points[i][-1] for i in range(num_pts)])) f = 0 - for j,term in enumerate(terms): + for j, term in enumerate(terms): t = 1 for k in term: t *= syms[k] @@ -128,21 +129,21 @@ \sum = %(sum)s = %(sum_expand)s """ % { "det": V.det(), - "sum": det_sum, - "sum_expand": det_sum.expand(), + "sum": det_sum, + "sum_expand": det_sum.expand(), }) print('-'*79) print("Polynomial fitting with a Vandermonde Matrix:") - x,y,z = symbols('x,y,z') + x, y, z = symbols('x,y,z') - points = [(0,3), (1,2), (2,3)] + points = [(0, 3), (1, 2), (2, 3)] print(""" Quadratic function, represented by 3 points: points = %(pts)s f = %(f)s """ % { "pts" : points, - "f" : gen_poly(points, 2, [x]), + "f": gen_poly(points, 2, [x]), }) points = [(0, 1, 1), (1, 0, 0), (1, 1, 0), (Rational(1, 2), 0, 0), @@ -152,7 +153,7 @@ points = %(pts)s f = %(f)s """ % { "pts" : points, - "f" : gen_poly(points, 2, [x, y]), + "f": gen_poly(points, 2, [x, y]), }) points = [(0, 1, 1, 1), (1, 1, 0, 0), (1, 0, 1, 0), (1, 1, 1, 1)] @@ -161,7 +162,7 @@ points = %(pts)s f = %(f)s """ % { "pts" : points, - "f" : gen_poly(points, 1, [x, y, z]), + "f": gen_poly(points, 1, [x, y, z]), }) diff -Nru python3-sympy-0.7.2/setup.py python3-sympy-0.7.3/setup.py --- python3-sympy-0.7.2/setup.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/setup.py 2013-07-13 17:53:31.000000000 +0000 @@ -36,8 +36,8 @@ import sympy # Make sure I have the right Python version. -if sys.version_info[:2] < (2,5): - print(("SymPy requires Python 2.5 or newer. Python %d.%d detected" % \ +if sys.version_info[:2] < (2, 5): + print(("SymPy requires Python 2.5 or newer. Python %d.%d detected" % sys.version_info[:2])) sys.exit(-1) @@ -83,6 +83,8 @@ 'sympy.polys.domains', 'sympy.printing', 'sympy.printing.pretty', + 'sympy.strategies', + 'sympy.strategies.branch', 'sympy.series', 'sympy.sets', 'sympy.simplify', @@ -90,10 +92,12 @@ 'sympy.statistics', 'sympy.stats', 'sympy.tensor', + 'sympy.unify', 'sympy.utilities', 'sympy.utilities.mathml', ] + class audit(Command): """Audits SymPy's source code for following issues: - Names which are used but not defined or used before they are defined. @@ -118,8 +122,8 @@ sys.exit(-1) # We don't want to audit external dependencies ext = ('mpmath',) - dirs = (os.path.join(*d) for d in \ - (m.split('.') for m in modules) if d[1] not in ext) + dirs = (os.path.join(*d) for d in + (m.split('.') for m in modules) if d[1] not in ext) warns = 0 for dir in dirs: for filename in os.listdir(dir): @@ -128,13 +132,14 @@ if warns > 0: print(("Audit finished with total %d warnings" % warns)) + class clean(Command): """Cleans *.pyc and debian trashs, so you should get the same copy as is in the VCS. """ description = "remove build files" - user_options = [("all","a","the same")] + user_options = [("all", "a", "the same")] def initialize_options(self): self.all = None @@ -160,7 +165,7 @@ user_options = [] # distutils complains if this is not here. def __init__(self, *args): - self.args = args[0] # so we can pass it to other classes + self.args = args[0] # so we can pass it to other classes Command.__init__(self, *args) def initialize_options(self): # distutils wants this @@ -172,6 +177,7 @@ def run(self): sympy.utilities.runtests.run_all_tests() + class run_benchmarks(Command): """Runs all SymPy benchmarks""" @@ -179,7 +185,7 @@ user_options = [] # distutils complains if this is not here. def __init__(self, *args): - self.args = args[0] # so we can pass it to other classes + self.args = args[0] # so we can pass it to other classes Command.__init__(self, *args) def initialize_options(self): # distutils wants this @@ -230,6 +236,7 @@ 'sympy.plotting.pygletplot.tests', 'sympy.plotting.tests', 'sympy.polys.agca.tests', + 'sympy.polys.domains.tests', 'sympy.polys.tests', 'sympy.printing.pretty.tests', 'sympy.printing.tests', @@ -239,7 +246,10 @@ 'sympy.solvers.tests', 'sympy.statistics.tests', 'sympy.stats.tests', + 'sympy.strategies.branch.tests', + 'sympy.strategies.tests', 'sympy.tensor.tests', + 'sympy.unify.tests', 'sympy.utilities.tests', ] @@ -256,7 +266,8 @@ 'Programming Language :: Python :: 2.7', 'Programming Language :: Python :: 3', 'Programming Language :: Python :: 3.2', - ] + 'Programming Language :: Python :: 3.3', +] long_description = '''SymPy is a Python library for symbolic mathematics. It aims to become a full-featured computer algebra system (CAS) while keeping the code @@ -264,24 +275,24 @@ SymPy is written entirely in Python and does not require any external libraries.''' setup( - name = 'sympy', - version = sympy.__version__, - description = 'Computer algebra system (CAS) in Python', - long_description = long_description, - author = 'SymPy development team', - author_email = 'sympy@googlegroups.com', - license = 'BSD', - keywords = "Math CAS", - url = 'http://code.google.com/p/sympy', - packages = ['sympy'] + modules + tests, - scripts = ['bin/isympy'], - ext_modules = [], - package_data = { 'sympy.utilities.mathml' : ['data/*.xsl'] }, - data_files = [('share/man/man1', ['doc/man/isympy.1'])], - cmdclass = {'test': test_sympy, - 'bench': run_benchmarks, - 'clean': clean, - 'audit' : audit, + name='sympy', + version=sympy.__version__, + description='Computer algebra system (CAS) in Python', + long_description=long_description, + author='SymPy development team', + author_email='sympy@googlegroups.com', + license='BSD', + keywords="Math CAS", + url='http://code.google.com/p/sympy', + packages=['sympy'] + modules + tests, + scripts=['bin/isympy'], + ext_modules=[], + package_data={ 'sympy.utilities.mathml': ['data/*.xsl'] }, + data_files=[('share/man/man1', ['doc/man/isympy.1'])], + cmdclass={'test': test_sympy, + 'bench': run_benchmarks, + 'clean': clean, + 'audit': audit, }, - classifiers = classifiers, - ) + classifiers=classifiers, +) diff -Nru python3-sympy-0.7.2/sympy/__init__.py python3-sympy-0.7.3/sympy/__init__.py --- python3-sympy-0.7.2/sympy/__init__.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/__init__.py 2013-07-13 17:53:31.000000000 +0000 @@ -9,7 +9,7 @@ http://code.google.com/p/sympy/""" -__version__ = "0.7.2" +__version__ = "0.7.3" # Try to determine if 2to3 has been run. To do this, we look at long.__name__. # If 2to3 has been run, it should convert long to int. @@ -17,19 +17,21 @@ if sys.version_info[0] == 3: try: HAS_2TO3 = int.__name__ == "int" - except NameError: # it tries to see long but long doesn't exist in Python 3 + except NameError: # it tries to see long but long doesn't exist in Python 3 HAS_2TO3 = False else: HAS_2TO3 = int.__name__ == "int" if sys.version_info[0] == 2: if HAS_2TO3: - raise ImportError("It appears 2to3 has been run on the codebase. Use " - "Python 3 or get the original source code.") + raise ImportError("You appear to be using the Python 3 version of " + "SymPy in Python 2. Use Python 3 or get the Python 2 " + "source code from http://sympy.org.") else: if sys.version_info[1] < 5: - raise ImportError("Python Version 2.5 or above is required for SymPy.") -else: # Python 3 + raise ImportError( + "Python Version 2.5 or above is required for SymPy.") +else: # Python 3 if not HAS_2TO3: raise ImportError("This is the Python 2 version of SymPy. To use SymPy " "with Python 3, please obtain a Python 3 version from http://sympy.org, " diff -Nru python3-sympy-0.7.2/sympy/abc.py python3-sympy-0.7.3/sympy/abc.py --- python3-sympy-0.7.2/sympy/abc.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/abc.py 2013-07-13 17:53:31.000000000 +0000 @@ -3,10 +3,56 @@ _latin = list('abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ') # COSINEQ should not be imported as they clash; gamma, pi and zeta clash, too _greek = 'alpha beta gamma delta epsilon zeta eta theta iota kappa lamda '\ - 'mu nu xi omicron pi rho sigma tau upsilon phi chi psi omega'.split(' ') + 'mu nu xi omicron pi rho sigma tau upsilon phi chi psi omega'.split(' ') # Note: We import lamda since lambda is a reserved keyword in Python for _s in _latin + _greek: exec("%s = Symbol('%s')" % (_s, _s)) -del _latin, _greek, _s +def clashing(): + """Return the clashing-symbols dictionaries. + + ``clash1`` defines all the single letter variables that clash with + SymPy objects; ``clash2`` defines the multi-letter clashing symbols; + and ``clash`` is the union of both. These can be passed for ``locals`` + during sympification if one desires Symbols rather than the non-Symbol + objects for those names. + + Examples + ======== + + >>> from sympy import S + >>> from sympy.abc import _clash1, _clash2, _clash + >>> S("Q & C", locals=_clash1) + And(C, Q) + >>> S('pi(x)', locals=_clash2) + pi(x) + >>> S('pi(C, Q)', locals=_clash) + pi(C, Q) + + Note: if changes are made to the docstring examples they can only + be tested after removing "clashing" from the list of deleted items + at the bottom of this file which removes this function from the + namespace. + """ + + ns = {} + exec('from sympy import *', ns) + clash1 = {} + clash2 = {} + while ns: + k, _ = ns.popitem() + if k in _greek: + clash2[k] = Symbol(k) + _greek.remove(k) + elif k in _latin: + clash1[k] = Symbol(k) + _latin.remove(k) + clash = {} + clash.update(clash1) + clash.update(clash2) + return clash1, clash2, clash + +_clash1, _clash2, _clash = clashing() + +del _latin, _greek, _s, clashing, Symbol diff -Nru python3-sympy-0.7.2/sympy/assumptions/__init__.py python3-sympy-0.7.3/sympy/assumptions/__init__.py --- python3-sympy-0.7.2/sympy/assumptions/__init__.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/assumptions/__init__.py 2013-07-13 17:53:31.000000000 +0000 @@ -1,3 +1,3 @@ -from .assume import AppliedPredicate, global_assumptions, Predicate, AssumptionsContext +from .assume import AppliedPredicate, Predicate, AssumptionsContext, assuming from .ask import Q, ask, register_handler, remove_handler from .refine import refine diff -Nru python3-sympy-0.7.2/sympy/assumptions/ask.py python3-sympy-0.7.3/sympy/assumptions/ask.py --- python3-sympy-0.7.2/sympy/assumptions/ask.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/assumptions/ask.py 2013-07-13 17:53:31.000000000 +0000 @@ -1,10 +1,11 @@ """Module for querying SymPy objects about assumptions.""" from sympy.core import sympify -from sympy.logic.boolalg import to_cnf, And, Not, Or, Implies, Equivalent +from sympy.logic.boolalg import to_cnf, And, Not, Or, Implies, Equivalent, BooleanFunction from sympy.logic.inference import satisfiable from sympy.assumptions.assume import (global_assumptions, Predicate, AppliedPredicate) + class Q: """Supported ask keys.""" antihermitian = Predicate('antihermitian') @@ -28,7 +29,23 @@ real = Predicate('real') odd = Predicate('odd') is_true = Predicate('is_true') - + symmetric = Predicate('symmetric') + invertible = Predicate('invertible') + singular = Predicate('singular') + orthogonal = Predicate('orthogonal') + unitary = Predicate('unitary') + normal = Predicate('normal') + positive_definite = Predicate('positive_definite') + upper_triangular = Predicate('upper_triangular') + lower_triangular = Predicate('lower_triangular') + diagonal = Predicate('diagonal') + triangular = Predicate('triangular') + unit_triangular = Predicate('unit_triangular') + fullrank = Predicate('fullrank') + square = Predicate('square') + real_elements = Predicate('real_elements') + complex_elements = Predicate('complex_elements') + integer_elements = Predicate('integer_elements') def _extract_facts(expr, symbol): @@ -41,8 +58,16 @@ if not expr.has(symbol): return None if isinstance(expr, AppliedPredicate): - return expr.func - return expr.func(*[x for x in [_extract_facts(arg, symbol) for arg in expr.args] if x is not None]) + if expr.arg == symbol: + return expr.func + else: + return + args = [_extract_facts(arg, symbol) for arg in expr.args] + if isinstance(expr, And): + return expr.func(*[x for x in args if x is not None]) + if all(arg != None for arg in args): + return expr.func(*args) + def ask(proposition, assumptions=True, context=global_assumptions): """ @@ -77,6 +102,12 @@ It is however a work in progress. """ + if not isinstance(proposition, (BooleanFunction, AppliedPredicate, bool)): + raise TypeError("proposition must be a valid logical expression") + + if not isinstance(assumptions, (BooleanFunction, AppliedPredicate, bool)): + raise TypeError("assumptions must be a valid logical expression") + assumptions = And(assumptions, And(*context)) if isinstance(proposition, AppliedPredicate): key, expr = proposition.func, sympify(proposition.arg) @@ -91,9 +122,6 @@ if assumptions is True: return - if not expr.is_Atom: - return - local_facts = _extract_facts(assumptions, expr) if local_facts is None or local_facts is True: return @@ -122,10 +150,10 @@ return False # Failing all else, we do a full logical inference - return ask_full_inference(key, local_facts) + return ask_full_inference(key, local_facts, known_facts_cnf) -def ask_full_inference(proposition, assumptions): +def ask_full_inference(proposition, assumptions, known_facts_cnf): """ Method for inferring properties about objects. @@ -137,7 +165,6 @@ return None - def register_handler(key, handler): """ Register a handler in the ask system. key must be a string and handler a @@ -163,143 +190,157 @@ except AttributeError: setattr(Q, key, Predicate(key, handlers=[handler])) + def remove_handler(key, handler): """Removes a handler from the ask system. Same syntax as register_handler""" if type(key) is Predicate: key = key.name getattr(Q, key).remove_handler(handler) -def compute_known_facts(): - """Compute the various forms of knowledge compilation used by the - assumptions system. - """ - # Compute the known facts in CNF form for logical inference - fact_string = "# -{ Known facts in CNF }-\n" - cnf = to_cnf(known_facts) - fact_string += "known_facts_cnf = And(\n " - fact_string += ",\n ".join(map(str, cnf.args)) - fact_string += "\n)\n" +def single_fact_lookup(known_facts_keys, known_facts_cnf): # Compute the quick lookup for single facts mapping = {} for key in known_facts_keys: mapping[key] = set([key]) for other_key in known_facts_keys: if other_key != key: - if ask_full_inference(other_key, key): + if ask_full_inference(other_key, key, known_facts_cnf): mapping[key].add(other_key) - fact_string += "\n# -{ Known facts in compressed sets }-\n" - fact_string += "known_facts_dict = {\n " - fact_string += ",\n ".join(["%s: %s" % item for item in list(mapping.items())]) - fact_string += "\n}\n" - return fact_string + return mapping + + +def compute_known_facts(known_facts, known_facts_keys): + """Compute the various forms of knowledge compilation used by the + assumptions system. + + This function is typically applied to the variables + ``known_facts`` and ``known_facts_keys`` defined at the bottom of + this file. + """ + from textwrap import dedent, wrap + + fact_string = dedent('''\ + """ + The contents of this file are the return value of + ``sympy.assumptions.ask.compute_known_facts``. Do NOT manually + edit this file. + """ + + from sympy.logic.boolalg import And, Not, Or + from sympy.assumptions.ask import Q + + # -{ Known facts in CNF }- + known_facts_cnf = And( + %s + ) + + # -{ Known facts in compressed sets }- + known_facts_dict = { + %s + } + ''') + # Compute the known facts in CNF form for logical inference + LINE = ",\n " + HANG = ' '*8 + cnf = to_cnf(known_facts) + c = LINE.join([str(a) for a in cnf.args]) + mapping = single_fact_lookup(known_facts_keys, cnf) + m = LINE.join(['\n'.join( + wrap("%s: %s" % item, + subsequent_indent=HANG, + break_long_words=False)) + for item in list(mapping.items())]) + ',' + return fact_string % (c, m) # handlers_dict tells us what ask handler we should use # for a particular key -_handlers_dict = { - 'antihermitian' : ['sympy.assumptions.handlers.sets.AskAntiHermitianHandler'], - 'bounded' : ['sympy.assumptions.handlers.calculus.AskBoundedHandler'], - 'commutative' : ['sympy.assumptions.handlers.AskCommutativeHandler'], - 'complex' : ['sympy.assumptions.handlers.sets.AskComplexHandler'], - 'composite' : ['sympy.assumptions.handlers.ntheory.AskCompositeHandler'], - 'even' : ['sympy.assumptions.handlers.ntheory.AskEvenHandler'], - 'extended_real' : ['sympy.assumptions.handlers.sets.AskExtendedRealHandler'], - 'hermitian' : ['sympy.assumptions.handlers.sets.AskHermitianHandler'], - 'imaginary' : ['sympy.assumptions.handlers.sets.AskImaginaryHandler'], - 'infinitesimal' : ['sympy.assumptions.handlers.calculus.AskInfinitesimalHandler'], - 'integer' : ['sympy.assumptions.handlers.sets.AskIntegerHandler'], - 'irrational' : ['sympy.assumptions.handlers.sets.AskIrrationalHandler'], - 'rational' : ['sympy.assumptions.handlers.sets.AskRationalHandler'], - 'negative' : ['sympy.assumptions.handlers.order.AskNegativeHandler'], - 'nonzero' : ['sympy.assumptions.handlers.order.AskNonZeroHandler'], - 'positive' : ['sympy.assumptions.handlers.order.AskPositiveHandler'], - 'prime' : ['sympy.assumptions.handlers.ntheory.AskPrimeHandler'], - 'real' : ['sympy.assumptions.handlers.sets.AskRealHandler'], - 'odd' : ['sympy.assumptions.handlers.ntheory.AskOddHandler'], - 'algebraic' : ['sympy.assumptions.handlers.sets.AskAlgebraicHandler'], - 'is_true' : ['sympy.assumptions.handlers.TautologicalHandler'] -} -for name, value in _handlers_dict.items(): - register_handler(name, value[0]) +_val_template = 'sympy.assumptions.handlers.%s' +_handlers = [ + ("antihermitian", "sets.AskAntiHermitianHandler"), + ("bounded", "calculus.AskBoundedHandler"), + ("commutative", "AskCommutativeHandler"), + ("complex", "sets.AskComplexHandler"), + ("composite", "ntheory.AskCompositeHandler"), + ("even", "ntheory.AskEvenHandler"), + ("extended_real", "sets.AskExtendedRealHandler"), + ("hermitian", "sets.AskHermitianHandler"), + ("imaginary", "sets.AskImaginaryHandler"), + ("infinitesimal", "calculus.AskInfinitesimalHandler"), + ("integer", "sets.AskIntegerHandler"), + ("irrational", "sets.AskIrrationalHandler"), + ("rational", "sets.AskRationalHandler"), + ("negative", "order.AskNegativeHandler"), + ("nonzero", "order.AskNonZeroHandler"), + ("positive", "order.AskPositiveHandler"), + ("prime", "ntheory.AskPrimeHandler"), + ("real", "sets.AskRealHandler"), + ("odd", "ntheory.AskOddHandler"), + ("algebraic", "sets.AskAlgebraicHandler"), + ("is_true", "TautologicalHandler"), + ("symmetric", "matrices.AskSymmetricHandler"), + ("invertible", "matrices.AskInvertibleHandler"), + ("orthogonal", "matrices.AskOrthogonalHandler"), + ("unitary", "matrices.AskUnitaryHandler"), + ("positive_definite", "matrices.AskPositiveDefiniteHandler"), + ("upper_triangular", "matrices.AskUpperTriangularHandler"), + ("lower_triangular", "matrices.AskLowerTriangularHandler"), + ("diagonal", "matrices.AskDiagonalHandler"), + ("fullrank", "matrices.AskFullRankHandler"), + ("square", "matrices.AskSquareHandler"), + ("integer_elements", "matrices.AskIntegerElementsHandler"), + ("real_elements", "matrices.AskRealElementsHandler"), + ("complex_elements", "matrices.AskComplexElementsHandler"), +] +for name, value in _handlers: + register_handler(name, _val_template % value) -known_facts_keys = [getattr(Q, attr) for attr in Q.__dict__ \ - if not attr.startswith('__')] +known_facts_keys = [getattr(Q, attr) for attr in Q.__dict__ + if not attr.startswith('__')] known_facts = And( - Implies (Q.real, Q.complex), - Implies (Q.real, Q.hermitian), + Implies(Q.real, Q.complex), + Implies(Q.real, Q.hermitian), Equivalent(Q.even, Q.integer & ~Q.odd), Equivalent(Q.extended_real, Q.real | Q.infinity), Equivalent(Q.odd, Q.integer & ~Q.even), Equivalent(Q.prime, Q.integer & Q.positive & ~Q.composite), - Implies (Q.integer, Q.rational), - Implies (Q.imaginary, Q.complex & ~Q.real), - Implies (Q.imaginary, Q.antihermitian), - Implies (Q.antihermitian, ~Q.hermitian), + Implies(Q.integer, Q.rational), + Implies(Q.rational, Q.algebraic), + Implies(Q.algebraic, Q.complex), + Implies(Q.imaginary, Q.complex & ~Q.real), + Implies(Q.imaginary, Q.antihermitian), + Implies(Q.antihermitian, ~Q.hermitian), Equivalent(Q.negative, Q.nonzero & ~Q.positive), Equivalent(Q.positive, Q.nonzero & ~Q.negative), Equivalent(Q.rational, Q.real & ~Q.irrational), Equivalent(Q.real, Q.rational | Q.irrational), - Implies (Q.nonzero, Q.real), - Equivalent(Q.nonzero, Q.positive | Q.negative) -) + Implies(Q.nonzero, Q.real), + Equivalent(Q.nonzero, Q.positive | Q.negative), -################################################################################ -# Note: The following facts are generated by the compute_known_facts function. # -################################################################################ -# -{ Known facts in CNF }- -known_facts_cnf = And( - Or(Not(Q.integer), Q.even, Q.odd), - Or(Not(Q.extended_real), Q.real, Q.infinity), - Or(Not(Q.real), Q.irrational, Q.rational), - Or(Not(Q.real), Q.complex), - Or(Not(Q.integer), Not(Q.positive), Q.prime, Q.composite), - Or(Not(Q.imaginary), Q.antihermitian), - Or(Not(Q.integer), Q.rational), - Or(Not(Q.real), Q.hermitian), - Or(Not(Q.imaginary), Q.complex), - Or(Not(Q.even), Q.integer), - Or(Not(Q.positive), Q.nonzero), - Or(Not(Q.nonzero), Q.negative, Q.positive), - Or(Not(Q.prime), Q.positive), - Or(Not(Q.rational), Q.real), - Or(Not(Q.real), Not(Q.imaginary)), - Or(Not(Q.odd), Q.integer), - Or(Not(Q.real), Q.extended_real), - Or(Not(Q.composite), Not(Q.prime)), - Or(Not(Q.negative), Q.nonzero), - Or(Not(Q.positive), Not(Q.negative)), - Or(Not(Q.prime), Q.integer), - Or(Not(Q.even), Not(Q.odd)), - Or(Not(Q.nonzero), Q.real), - Or(Not(Q.irrational), Q.real), - Or(Not(Q.rational), Not(Q.irrational)), - Or(Not(Q.infinity), Q.extended_real), - Or(Not(Q.antihermitian), Not(Q.hermitian)) + Implies(Q.orthogonal, Q.positive_definite), + Implies(Q.orthogonal, Q.unitary), + Implies(Q.unitary & Q.real, Q.orthogonal), + Implies(Q.unitary, Q.normal), + Implies(Q.unitary, Q.invertible), + Implies(Q.normal, Q.square), + Implies(Q.diagonal, Q.normal), + Implies(Q.positive_definite, Q.invertible), + Implies(Q.diagonal, Q.upper_triangular), + Implies(Q.diagonal, Q.lower_triangular), + Implies(Q.lower_triangular, Q.triangular), + Implies(Q.upper_triangular, Q.triangular), + Implies(Q.triangular, Q.upper_triangular | Q.lower_triangular), + Implies(Q.upper_triangular & Q.lower_triangular, Q.diagonal), + Implies(Q.diagonal, Q.symmetric), + Implies(Q.unit_triangular, Q.triangular), + Implies(Q.invertible, Q.fullrank), + Implies(Q.invertible, Q.square), + Implies(Q.symmetric, Q.square), + Implies(Q.fullrank & Q.square, Q.invertible), + Equivalent(Q.invertible, ~Q.singular), + Implies(Q.integer_elements, Q.real_elements), + Implies(Q.real_elements, Q.complex_elements), ) -# -{ Known facts in compressed sets }- -known_facts_dict = { - Q.odd: set([Q.complex, Q.odd, Q.hermitian, Q.real, Q.rational, Q.extended_real, Q.integer]), - Q.antihermitian: set([Q.antihermitian]), - Q.infinitesimal: set([Q.infinitesimal]), - Q.hermitian: set([Q.hermitian]), - Q.bounded: set([Q.bounded]), - Q.even: set([Q.complex, Q.real, Q.hermitian, Q.even, Q.rational, Q.extended_real, Q.integer]), - Q.algebraic: set([Q.algebraic]), - Q.is_true: set([Q.is_true]), - Q.real: set([Q.real, Q.complex, Q.extended_real, Q.hermitian]), - Q.rational: set([Q.real, Q.rational, Q.complex, Q.extended_real, Q.hermitian]), - Q.extended_real: set([Q.extended_real]), - Q.integer: set([Q.complex, Q.hermitian, Q.real, Q.rational, Q.extended_real, Q.integer]), - Q.commutative: set([Q.commutative]), - Q.infinity: set([Q.extended_real, Q.infinity]), - Q.complex: set([Q.complex]), - Q.positive: set([Q.complex, Q.positive, Q.nonzero, Q.hermitian, Q.real, Q.extended_real]), - Q.composite: set([Q.composite]), - Q.prime: set([Q.complex, Q.positive, Q.real, Q.hermitian, Q.prime, Q.rational, Q.extended_real, Q.nonzero, Q.integer]), - Q.negative: set([Q.complex, Q.nonzero, Q.hermitian, Q.real, Q.negative, Q.extended_real]), - Q.nonzero: set([Q.nonzero, Q.complex, Q.extended_real, Q.real, Q.hermitian]), - Q.irrational: set([Q.real, Q.irrational, Q.complex, Q.extended_real, Q.hermitian]), - Q.imaginary: set([Q.antihermitian, Q.complex, Q.imaginary]) -} +from sympy.assumptions.ask_generated import known_facts_dict, known_facts_cnf diff -Nru python3-sympy-0.7.2/sympy/assumptions/ask_generated.py python3-sympy-0.7.3/sympy/assumptions/ask_generated.py --- python3-sympy-0.7.2/sympy/assumptions/ask_generated.py 1970-01-01 00:00:00.000000000 +0000 +++ python3-sympy-0.7.3/sympy/assumptions/ask_generated.py 2013-07-13 17:53:31.000000000 +0000 @@ -0,0 +1,123 @@ +""" +The contents of this file are the return value of +``sympy.assumptions.ask.compute_known_facts``. Do NOT manually +edit this file. +""" + +from sympy.logic.boolalg import And, Not, Or +from sympy.assumptions.ask import Q + +# -{ Known facts in CNF }- +known_facts_cnf = And( + Or(Q.invertible, Q.singular), + Or(Not(Q.rational), Q.algebraic), + Or(Not(Q.imaginary), Q.antihermitian), + Or(Not(Q.algebraic), Q.complex), + Or(Not(Q.imaginary), Q.complex), + Or(Not(Q.real), Q.complex), + Or(Not(Q.real_elements), Q.complex_elements), + Or(Not(Q.infinity), Q.extended_real), + Or(Not(Q.real), Q.extended_real), + Or(Not(Q.invertible), Q.fullrank), + Or(Not(Q.real), Q.hermitian), + Or(Not(Q.even), Q.integer), + Or(Not(Q.odd), Q.integer), + Or(Not(Q.prime), Q.integer), + Or(Not(Q.positive_definite), Q.invertible), + Or(Not(Q.unitary), Q.invertible), + Or(Not(Q.diagonal), Q.lower_triangular), + Or(Not(Q.negative), Q.nonzero), + Or(Not(Q.positive), Q.nonzero), + Or(Not(Q.diagonal), Q.normal), + Or(Not(Q.unitary), Q.normal), + Or(Not(Q.prime), Q.positive), + Or(Not(Q.orthogonal), Q.positive_definite), + Or(Not(Q.integer), Q.rational), + Or(Not(Q.irrational), Q.real), + Or(Not(Q.nonzero), Q.real), + Or(Not(Q.rational), Q.real), + Or(Not(Q.integer_elements), Q.real_elements), + Or(Not(Q.invertible), Q.square), + Or(Not(Q.normal), Q.square), + Or(Not(Q.symmetric), Q.square), + Or(Not(Q.diagonal), Q.symmetric), + Or(Not(Q.lower_triangular), Q.triangular), + Or(Not(Q.unit_triangular), Q.triangular), + Or(Not(Q.upper_triangular), Q.triangular), + Or(Not(Q.orthogonal), Q.unitary), + Or(Not(Q.diagonal), Q.upper_triangular), + Or(Not(Q.antihermitian), Not(Q.hermitian)), + Or(Not(Q.composite), Not(Q.prime)), + Or(Not(Q.even), Not(Q.odd)), + Or(Not(Q.imaginary), Not(Q.real)), + Or(Not(Q.invertible), Not(Q.singular)), + Or(Not(Q.irrational), Not(Q.rational)), + Or(Not(Q.negative), Not(Q.positive)), + Or(Not(Q.integer), Q.even, Q.odd), + Or(Not(Q.extended_real), Q.infinity, Q.real), + Or(Not(Q.real), Q.irrational, Q.rational), + Or(Not(Q.triangular), Q.lower_triangular, Q.upper_triangular), + Or(Not(Q.nonzero), Q.negative, Q.positive), + Or(Not(Q.lower_triangular), Not(Q.upper_triangular), Q.diagonal), + Or(Not(Q.fullrank), Not(Q.square), Q.invertible), + Or(Not(Q.real), Not(Q.unitary), Q.orthogonal), + Or(Not(Q.integer), Not(Q.positive), Q.composite, Q.prime) +) + +# -{ Known facts in compressed sets }- +known_facts_dict = { + Q.orthogonal: set([Q.orthogonal, Q.normal, Q.invertible, Q.fullrank, + Q.positive_definite, Q.unitary, Q.square]), + Q.invertible: set([Q.fullrank, Q.invertible, Q.square]), + Q.odd: set([Q.complex, Q.odd, Q.hermitian, Q.real, Q.rational, + Q.extended_real, Q.integer, Q.algebraic]), + Q.symmetric: set([Q.symmetric, Q.square]), + Q.upper_triangular: set([Q.upper_triangular, Q.triangular]), + Q.fullrank: set([Q.fullrank]), + Q.diagonal: set([Q.normal, Q.symmetric, Q.lower_triangular, + Q.upper_triangular, Q.triangular, Q.diagonal, Q.square]), + Q.antihermitian: set([Q.antihermitian]), + Q.singular: set([Q.singular]), + Q.even: set([Q.complex, Q.real, Q.hermitian, Q.even, Q.rational, + Q.extended_real, Q.integer, Q.algebraic]), + Q.hermitian: set([Q.hermitian]), + Q.bounded: set([Q.bounded]), + Q.positive_definite: set([Q.fullrank, Q.invertible, Q.square, + Q.positive_definite]), + Q.nonzero: set([Q.nonzero, Q.complex, Q.extended_real, Q.real, + Q.hermitian]), + Q.complex_elements: set([Q.complex_elements]), + Q.square: set([Q.square]), + Q.real_elements: set([Q.complex_elements, Q.real_elements]), + Q.algebraic: set([Q.complex, Q.algebraic]), + Q.normal: set([Q.normal, Q.square]), + Q.is_true: set([Q.is_true]), + Q.integer_elements: set([Q.complex_elements, Q.real_elements, + Q.integer_elements]), + Q.real: set([Q.real, Q.complex, Q.extended_real, Q.hermitian]), + Q.rational: set([Q.complex, Q.hermitian, Q.real, Q.rational, + Q.extended_real, Q.algebraic]), + Q.extended_real: set([Q.extended_real]), + Q.integer: set([Q.complex, Q.hermitian, Q.real, Q.rational, + Q.extended_real, Q.integer, Q.algebraic]), + Q.infinitesimal: set([Q.infinitesimal]), + Q.commutative: set([Q.commutative]), + Q.infinity: set([Q.extended_real, Q.infinity]), + Q.complex: set([Q.complex]), + Q.lower_triangular: set([Q.triangular, Q.lower_triangular]), + Q.positive: set([Q.complex, Q.positive, Q.nonzero, Q.hermitian, + Q.real, Q.extended_real]), + Q.composite: set([Q.composite]), + Q.triangular: set([Q.triangular]), + Q.prime: set([Q.complex, Q.positive, Q.real, Q.hermitian, Q.prime, + Q.rational, Q.extended_real, Q.nonzero, Q.integer, + Q.algebraic]), + Q.negative: set([Q.complex, Q.nonzero, Q.hermitian, Q.real, + Q.negative, Q.extended_real]), + Q.unitary: set([Q.normal, Q.square, Q.fullrank, Q.invertible, + Q.unitary]), + Q.irrational: set([Q.real, Q.irrational, Q.complex, Q.extended_real, + Q.hermitian]), + Q.unit_triangular: set([Q.triangular, Q.unit_triangular]), + Q.imaginary: set([Q.antihermitian, Q.complex, Q.imaginary]), +} diff -Nru python3-sympy-0.7.2/sympy/assumptions/assume.py python3-sympy-0.7.3/sympy/assumptions/assume.py --- python3-sympy-0.7.2/sympy/assumptions/assume.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/assumptions/assume.py 2013-07-13 17:53:31.000000000 +0000 @@ -3,6 +3,8 @@ from sympy.core.singleton import S from sympy.logic.boolalg import Boolean from sympy.utilities.source import get_class +from contextlib import contextmanager + class AssumptionsContext(set): """Set representing assumptions. @@ -14,7 +16,8 @@ Examples ======== - >>> from sympy import global_assumptions, AppliedPredicate, Q + >>> from sympy import AppliedPredicate, Q + >>> from sympy.assumptions.assume import global_assumptions >>> global_assumptions AssumptionsContext() >>> from sympy.abc import x @@ -35,6 +38,7 @@ global_assumptions = AssumptionsContext() + class AppliedPredicate(Boolean): """The class of expressions resulting from applying a Predicate. @@ -51,7 +55,7 @@ def __new__(cls, predicate, arg): return Boolean.__new__(cls, predicate, arg) - is_Atom = True # do not attempt to decompose this + is_Atom = True # do not attempt to decompose this @property def arg(self): @@ -93,6 +97,7 @@ def _eval_ask(self, assumptions): return self.func.eval(self.arg, assumptions) + class Predicate(Boolean): """A predicate is a function that returns a boolean value. @@ -172,3 +177,26 @@ raise ValueError('incompatible resolutors') break return res + +@contextmanager +def assuming(*assumptions): + """ Context manager for assumptions + + >>> + >>> from sympy.assumptions import assuming, Q, ask + >>> from sympy.abc import x, y + + >>> print(ask(Q.integer(x + y))) + None + + >>> with assuming(Q.integer(x), Q.integer(y)): + ... print(ask(Q.integer(x + y))) + True + """ + old_global_assumptions = global_assumptions.copy() + global_assumptions.update(assumptions) + try: + yield + finally: + global_assumptions.clear() + global_assumptions.update(old_global_assumptions) diff -Nru python3-sympy-0.7.2/sympy/assumptions/handlers/__init__.py python3-sympy-0.7.3/sympy/assumptions/handlers/__init__.py --- python3-sympy-0.7.2/sympy/assumptions/handlers/__init__.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/assumptions/handlers/__init__.py 2013-07-13 17:53:31.000000000 +0000 @@ -1,10 +1,12 @@ from sympy.logic.boolalg import conjuncts from sympy.assumptions import Q, ask + class AskHandler(object): """Base class that all Ask Handlers must inherit""" pass + class CommonHandler(AskHandler): """Defines some useful methods common to most Handlers """ @@ -12,6 +14,15 @@ def NaN(expr, assumptions): return False + @staticmethod + def AlwaysTrue(expr, assumptions): + return True + + @staticmethod + def AlwaysFalse(expr, assumptions): + return False + + class AskCommutativeHandler(CommonHandler): """ Handler for key 'commutative' @@ -42,6 +53,7 @@ def NaN(expr, assumptions): return True + class TautologicalHandler(AskHandler): """Wrapper allowing to query the truth value of a boolean expression.""" @@ -61,15 +73,14 @@ else: return None - @staticmethod def Or(expr, assumptions): result = False for arg in expr.args: p = ask(arg, assumptions=assumptions) - if p == True: + if p is True: return True - if p == None: + if p is None: result = None return result @@ -78,9 +89,9 @@ result = True for arg in expr.args: p = ask(arg, assumptions=assumptions) - if p == False: + if p is False: return False - if p == None: + if p is None: result = None return result @@ -93,9 +104,29 @@ def Equivalent(expr, assumptions): p, q = expr.args pt = ask(p, assumptions=assumptions) - if pt == None: + if pt is None: return None qt = ask(q, assumptions=assumptions) - if qt == None: + if qt is None: return None return pt == qt + + +#### Helper methods +def test_closed_group(expr, assumptions, key): + """ + Test for membership in a group with respect + to the current operation + """ + result = True + for arg in expr.args: + _out = ask(key(arg), assumptions) + if _out is None: + break + elif _out is False: + if result: + result = False + else: + break + else: + return result diff -Nru python3-sympy-0.7.2/sympy/assumptions/handlers/calculus.py python3-sympy-0.7.3/sympy/assumptions/handlers/calculus.py --- python3-sympy-0.7.2/sympy/assumptions/handlers/calculus.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/assumptions/handlers/calculus.py 2013-07-13 17:53:31.000000000 +0000 @@ -6,6 +6,7 @@ from sympy.assumptions import Q, ask from sympy.assumptions.handlers import CommonHandler + class AskInfinitesimalHandler(CommonHandler): """ Handler for key 'infinitesimal' @@ -36,11 +37,12 @@ result = True elif ask(Q.bounded(arg), assumptions): continue - else: break + else: + break else: return result - Add, Pow = Mul, Mul + Add, Pow = [Mul]*2 @staticmethod def Number(expr, assumptions): @@ -48,9 +50,7 @@ NumberSymbol = Number - @staticmethod - def ImaginaryUnit(expr, assumptions): - return False + ImaginaryUnit = staticmethod(CommonHandler.AlwaysFalse) class AskBoundedHandler(CommonHandler): @@ -159,7 +159,7 @@ """ - sign = -1 # sign of unknown or unbounded + sign = -1 # sign of unknown or unbounded result = True for arg in expr.args: _bounded = ask(Q.bounded(arg), assumptions) @@ -170,7 +170,7 @@ # is None and Bounded is None or there was already # an unknown sign, return None if sign != -1 and s != sign or \ - s == None and (s == _bounded or s == sign): + s is None and (s == _bounded or s == sign): return None else: sign = s @@ -246,17 +246,17 @@ """ base_bounded = ask(Q.bounded(expr.base), assumptions) exp_bounded = ask(Q.bounded(expr.exp), assumptions) - if base_bounded==None and exp_bounded==None: # Common Case + if base_bounded is None and exp_bounded is None: # Common Case return None - if base_bounded==False and ask(Q.nonzero(expr.exp), assumptions): + if base_bounded is False and ask(Q.nonzero(expr.exp), assumptions): return False if base_bounded and exp_bounded: return True - if abs(expr.base)<=1 and ask(Q.positive(expr.exp), assumptions): + if abs(expr.base) <= 1 and ask(Q.positive(expr.exp), assumptions): return True - if abs(expr.base)>=1 and ask(Q.negative(expr.exp), assumptions): + if abs(expr.base) >= 1 and ask(Q.negative(expr.exp), assumptions): return True - if abs(expr.base)>=1 and exp_bounded==False: + if abs(expr.base) >= 1 and exp_bounded is False: return False return None @@ -266,36 +266,7 @@ exp = log - @staticmethod - def sin(expr, assumptions): - return True - - cos = sin - - @staticmethod - def Number(expr, assumptions): - return True - - @staticmethod - def Infinity(expr, assumptions): - return False + cos, sin, Number, Pi, Exp1, GoldenRatio, ImaginaryUnit, sign = \ + [staticmethod(CommonHandler.AlwaysTrue)]*8 - @staticmethod - def NegativeInfinity(expr, assumptions): - return False - - @staticmethod - def Pi(expr, assumptions): - return True - - @staticmethod - def Exp1(expr, assumptions): - return True - - @staticmethod - def ImaginaryUnit(expr, assumptions): - return True - - @staticmethod - def sign(expr, assumptions): - return True + Infinity, NegativeInfinity = [staticmethod(CommonHandler.AlwaysFalse)]*2 diff -Nru python3-sympy-0.7.2/sympy/assumptions/handlers/matrices.py python3-sympy-0.7.3/sympy/assumptions/handlers/matrices.py --- python3-sympy-0.7.2/sympy/assumptions/handlers/matrices.py 1970-01-01 00:00:00.000000000 +0000 +++ python3-sympy-0.7.3/sympy/assumptions/handlers/matrices.py 2013-07-13 17:53:31.000000000 +0000 @@ -0,0 +1,454 @@ +""" +This module contains query handlers responsible for calculus queries: +infinitesimal, bounded, etc. +""" +from sympy.logic.boolalg import conjuncts +from sympy.assumptions import Q, ask +from sympy.assumptions.handlers import CommonHandler, test_closed_group +from sympy.matrices.expressions import MatMul, MatrixExpr +from sympy.core.logic import fuzzy_and +from sympy.utilities.iterables import sift +from sympy.core import Basic +from functools import partial + + +def _Factorization(predicate, expr, assumptions): + if predicate in expr.predicates: + return True + +class AskSquareHandler(CommonHandler): + """ + Handler for key 'square' + """ + + @staticmethod + def MatrixExpr(expr, assumptions): + return expr.shape[0] == expr.shape[1] + + +class AskSymmetricHandler(CommonHandler): + """ + Handler for key 'symmetric' + """ + + @staticmethod + def MatMul(expr, assumptions): + factor, mmul = expr.as_coeff_mmul() + if all(ask(Q.symmetric(arg), assumptions) for arg in mmul.args): + return True + if len(mmul.args) >= 2 and mmul.args[0] == mmul.args[-1].T: + return ask(Q.symmetric(MatMul(*mmul.args[1:-1])), assumptions) + + @staticmethod + def MatAdd(expr, assumptions): + return all(ask(Q.symmetric(arg), assumptions) for arg in expr.args) + + @staticmethod + def MatrixSymbol(expr, assumptions): + if not expr.is_square: + return False + if Q.symmetric(expr) in conjuncts(assumptions): + return True + + @staticmethod + def Identity(expr, assumptions): + return True + + @staticmethod + def ZeroMatrix(expr, assumptions): + return ask(Q.square(expr), assumptions) + + @staticmethod + def Transpose(expr, assumptions): + return ask(Q.symmetric(expr.arg), assumptions) + Inverse = Transpose + + @staticmethod + def MatrixSlice(expr, assumptions): + if not expr.on_diag: + return None + else: + return ask(Q.symmetric(expr.parent), assumptions) + + +class AskInvertibleHandler(CommonHandler): + """ + Handler for key 'invertible' + """ + + @staticmethod + def MatMul(expr, assumptions): + factor, mmul = expr.as_coeff_mmul() + if all(ask(Q.invertible(arg), assumptions) for arg in mmul.args): + return True + if any(ask(Q.invertible(arg), assumptions) is False + for arg in mmul.args): + return False + + @staticmethod + def MatAdd(expr, assumptions): + return None + + @staticmethod + def MatrixSymbol(expr, assumptions): + if not expr.is_square: + return False + if Q.invertible(expr) in conjuncts(assumptions): + return True + + Identity, Inverse = [staticmethod(CommonHandler.AlwaysTrue)]*2 + + ZeroMatrix = staticmethod(CommonHandler.AlwaysFalse) + + @staticmethod + def Transpose(expr, assumptions): + return ask(Q.invertible(expr.arg), assumptions) + + @staticmethod + def MatrixSlice(expr, assumptions): + if not expr.on_diag: + return None + else: + return ask(Q.invertible(expr.parent), assumptions) + +class AskOrthogonalHandler(CommonHandler): + """ + Handler for key 'orthogonal' + """ + predicate = Q.orthogonal + @staticmethod + def MatMul(expr, assumptions): + factor, mmul = expr.as_coeff_mmul() + if (all(ask(Q.orthogonal(arg), assumptions) for arg in mmul.args) and + factor == 1): + return True + if any(ask(Q.invertible(arg), assumptions) is False + for arg in mmul.args): + return False + + @staticmethod + def MatAdd(expr, assumptions): + if (len(expr.args) == 1 and + ask(Q.orthogonal(expr.args[0]), assumptions)): + return True + + @staticmethod + def MatrixSymbol(expr, assumptions): + if not expr.is_square: + return False + if Q.orthogonal(expr) in conjuncts(assumptions): + return True + + Identity = staticmethod(CommonHandler.AlwaysTrue) + + ZeroMatrix = staticmethod(CommonHandler.AlwaysFalse) + + @staticmethod + def Transpose(expr, assumptions): + return ask(Q.orthogonal(expr.arg), assumptions) + Inverse = Transpose + + @staticmethod + def MatrixSlice(expr, assumptions): + if not expr.on_diag: + return None + else: + return ask(Q.orthogonal(expr.parent), assumptions) + + Factorization = staticmethod(partial(_Factorization, Q.orthogonal)) + +class AskUnitaryHandler(CommonHandler): + """ + Handler for key 'unitary' + """ + predicate = Q.unitary + + @staticmethod + def MatMul(expr, assumptions): + factor, mmul = expr.as_coeff_mmul() + if (all(ask(Q.unitary(arg), assumptions) for arg in mmul.args) and + abs(factor) == 1): + return True + if any(ask(Q.invertible(arg), assumptions) is False + for arg in mmul.args): + return False + + @staticmethod + def MatrixSymbol(expr, assumptions): + if not expr.is_square: + return False + if Q.unitary(expr) in conjuncts(assumptions): + return True + + @staticmethod + def Identity(expr, assumptions): + return True + + @staticmethod + def ZeroMatrix(expr, assumptions): + return False + + @staticmethod + def Transpose(expr, assumptions): + return ask(Q.unitary(expr.arg), assumptions) + Inverse = Transpose + + @staticmethod + def MatrixSlice(expr, assumptions): + if not expr.on_diag: + return None + else: + return ask(Q.unitary(expr.parent), assumptions) + + @staticmethod + def DFT(expr, assumptions): + return True + + Factorization = staticmethod(partial(_Factorization, Q.unitary)) + +class AskFullRankHandler(CommonHandler): + """ + Handler for key 'fullrank' + """ + @staticmethod + def MatMul(expr, assumptions): + if all(ask(Q.fullrank(arg), assumptions) for arg in expr.args): + return True + + Identity = staticmethod(CommonHandler.AlwaysTrue) + + ZeroMatrix = staticmethod(CommonHandler.AlwaysFalse) + + @staticmethod + def Transpose(expr, assumptions): + return ask(Q.fullrank(expr.arg), assumptions) + Inverse = Transpose + + @staticmethod + def MatrixSlice(expr, assumptions): + if ask(Q.orthogonal(expr.parent), assumptions): + return True + +class AskPositiveDefiniteHandler(CommonHandler): + """ + Handler for key 'positive_definite' + """ + @staticmethod + def MatMul(expr, assumptions): + factor, mmul = expr.as_coeff_mmul() + if (all(ask(Q.positive_definite(arg), assumptions) + for arg in mmul.args) and factor > 0): + return True + if (len(mmul.args) >= 2 + and mmul.args[0] == mmul.args[-1].T + and ask(Q.fullrank(mmul.args[0]), assumptions)): + return ask(Q.positive_definite( + MatMul(*mmul.args[1:-1])), assumptions) + + @staticmethod + def MatAdd(expr, assumptions): + if all(ask(Q.positive_definite(arg), assumptions) + for arg in expr.args): + return True + + @staticmethod + def MatrixSymbol(expr, assumptions): + if not expr.is_square: + return False + if Q.positive_definite(expr) in conjuncts(assumptions): + return True + + Identity = staticmethod(CommonHandler.AlwaysTrue) + + ZeroMatrix = staticmethod(CommonHandler.AlwaysFalse) + + @staticmethod + def Transpose(expr, assumptions): + return ask(Q.positive_definite(expr.arg), assumptions) + Inverse = Transpose + + @staticmethod + def MatrixSlice(expr, assumptions): + if not expr.on_diag: + return None + else: + return ask(Q.positive_definite(expr.parent), assumptions) + +class AskUpperTriangularHandler(CommonHandler): + """ + Handler for key 'upper_triangular' + """ + @staticmethod + def MatMul(expr, assumptions): + factor, matrices = expr.as_coeff_matrices() + if all(ask(Q.upper_triangular(m), assumptions) for m in matrices): + return True + + @staticmethod + def MatAdd(expr, assumptions): + if all(ask(Q.upper_triangular(arg), assumptions) for arg in expr.args): + return True + + @staticmethod + def MatrixSymbol(expr, assumptions): + if Q.upper_triangular(expr) in conjuncts(assumptions): + return True + + Identity, ZeroMatrix = [staticmethod(CommonHandler.AlwaysTrue)]*2 + + @staticmethod + def Transpose(expr, assumptions): + return ask(Q.lower_triangular(expr.arg), assumptions) + + @staticmethod + def Inverse(expr, assumptions): + return ask(Q.upper_triangular(expr.arg), assumptions) + + @staticmethod + def MatrixSlice(expr, assumptions): + if not expr.on_diag: + return None + else: + return ask(Q.upper_triangular(expr.parent), assumptions) + + Factorization = staticmethod(partial(_Factorization, Q.upper_triangular)) + +class AskLowerTriangularHandler(CommonHandler): + """ + Handler for key 'lower_triangular' + """ + @staticmethod + def MatMul(expr, assumptions): + factor, matrices = expr.as_coeff_matrices() + if all(ask(Q.lower_triangular(m), assumptions) for m in matrices): + return True + + @staticmethod + def MatAdd(expr, assumptions): + if all(ask(Q.lower_triangular(arg), assumptions) for arg in expr.args): + return True + + @staticmethod + def MatrixSymbol(expr, assumptions): + if Q.lower_triangular(expr) in conjuncts(assumptions): + return True + + Identity, ZeroMatrix = [staticmethod(CommonHandler.AlwaysTrue)]*2 + + @staticmethod + def Transpose(expr, assumptions): + return ask(Q.upper_triangular(expr.arg), assumptions) + + @staticmethod + def Inverse(expr, assumptions): + return ask(Q.lower_triangular(expr.arg), assumptions) + + @staticmethod + def MatrixSlice(expr, assumptions): + if not expr.on_diag: + return None + else: + return ask(Q.lower_triangular(expr.parent), assumptions) + + Factorization = staticmethod(partial(_Factorization, Q.lower_triangular)) + +class AskDiagonalHandler(CommonHandler): + """ + Handler for key 'diagonal' + """ + @staticmethod + def MatMul(expr, assumptions): + factor, matrices = expr.as_coeff_matrices() + if all(ask(Q.diagonal(m), assumptions) for m in matrices): + return True + + @staticmethod + def MatAdd(expr, assumptions): + if all(ask(Q.diagonal(arg), assumptions) for arg in expr.args): + return True + + @staticmethod + def MatrixSymbol(expr, assumptions): + if Q.diagonal(expr) in conjuncts(assumptions): + return True + + Identity, ZeroMatrix = [staticmethod(CommonHandler.AlwaysTrue)]*2 + + @staticmethod + def Transpose(expr, assumptions): + return ask(Q.diagonal(expr.arg), assumptions) + + @staticmethod + def Inverse(expr, assumptions): + return ask(Q.diagonal(expr.arg), assumptions) + + @staticmethod + def MatrixSlice(expr, assumptions): + if not expr.on_diag: + return None + else: + return ask(Q.diagonal(expr.parent), assumptions) + + @staticmethod + def DiagonalMatrix(expr, assumptions): + return True + + Factorization = staticmethod(partial(_Factorization, Q.diagonal)) + + +def BM_elements(predicate, expr, assumptions): + """ Block Matrix elements """ + return all(ask(predicate(b), assumptions) for b in expr.blocks) + +def MS_elements(predicate, expr, assumptions): + """ Matrix Slice elements """ + return ask(predicate(expr.parent), assumptions) + +def MatMul_elements(matrix_predicate, scalar_predicate, expr, assumptions): + d = sift(expr.args, lambda x: isinstance(x, MatrixExpr)) + factors, matrices = d[False], d[True] + return fuzzy_and( + test_closed_group(Basic(*factors), assumptions, scalar_predicate), + test_closed_group(Basic(*matrices), assumptions, matrix_predicate)) + +class AskIntegerElementsHandler(CommonHandler): + @staticmethod + def MatAdd(expr, assumptions): + return test_closed_group(expr, assumptions, Q.integer_elements) + + HadamardProduct = Determinant = Trace = Transpose = MatAdd + + ZeroMatrix = Identity = staticmethod(CommonHandler.AlwaysTrue) + + MatMul = staticmethod(partial(MatMul_elements, Q.integer_elements, + Q.integer)) + MatrixSlice = staticmethod(partial(MS_elements, Q.integer_elements)) + BlockMatrix = staticmethod(partial(BM_elements, Q.integer_elements)) + +class AskRealElementsHandler(CommonHandler): + @staticmethod + def MatAdd(expr, assumptions): + return test_closed_group(expr, assumptions, Q.real_elements) + + HadamardProduct = Determinant = Trace = Transpose = Inverse = \ + Factorization = MatAdd + + MatMul = staticmethod(partial(MatMul_elements, Q.real_elements, Q.real)) + MatrixSlice = staticmethod(partial(MS_elements, Q.real_elements)) + BlockMatrix = staticmethod(partial(BM_elements, Q.real_elements)) + + +class AskComplexElementsHandler(CommonHandler): + @staticmethod + def MatAdd(expr, assumptions): + return test_closed_group(expr, assumptions, Q.complex_elements) + + HadamardProduct = Determinant = Trace = Transpose = Inverse = \ + Factorization = MatAdd + + MatMul = staticmethod(partial(MatMul_elements, Q.complex_elements, + Q.complex)) + MatrixSlice = staticmethod(partial(MS_elements, Q.complex_elements)) + BlockMatrix = staticmethod(partial(BM_elements, Q.complex_elements)) + + DFT = staticmethod(CommonHandler.AlwaysTrue) diff -Nru python3-sympy-0.7.2/sympy/assumptions/handlers/ntheory.py python3-sympy-0.7.3/sympy/assumptions/handlers/ntheory.py --- python3-sympy-0.7.2/sympy/assumptions/handlers/ntheory.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/assumptions/handlers/ntheory.py 2013-07-13 17:53:31.000000000 +0000 @@ -5,6 +5,7 @@ from sympy.assumptions.handlers import CommonHandler from sympy.ntheory import isprime + class AskPrimeHandler(CommonHandler): """ Handler for key 'prime' @@ -39,7 +40,8 @@ for arg in expr.args: if ask(Q.integer(arg), assumptions): pass - else: break + else: + break else: # a product of integers can't be a prime return False @@ -59,30 +61,17 @@ def Integer(expr, assumptions): return isprime(expr) - @staticmethod - def Rational(expr, assumptions): - return False + Rational, Infinity, NegativeInfinity, ImaginaryUnit = [staticmethod(CommonHandler.AlwaysFalse)]*4 @staticmethod def Float(expr, assumptions): return AskPrimeHandler._number(expr, assumptions) @staticmethod - def Infinity(expr, assumptions): - return False - - @staticmethod - def NegativeInfinity(expr, assumptions): - return False - - @staticmethod - def ImaginaryUnit(expr, assumptions): - return False - - @staticmethod def NumberSymbol(expr, assumptions): return AskPrimeHandler._number(expr, assumptions) + class AskCompositeHandler(CommonHandler): @staticmethod @@ -92,10 +81,14 @@ _integer = ask(Q.integer(expr), assumptions) if _integer: _prime = ask(Q.prime(expr), assumptions) - if _prime is None: return + if _prime is None: + return return not _prime - else: return _integer - else: return _positive + else: + return _integer + else: + return _positive + class AskEvenHandler(CommonHandler): @@ -139,11 +132,15 @@ if irrational: break irrational = True - else: break + else: + break else: - if irrational: return False - if even: return True - if odd == len(expr.args): return False + if irrational: + return False + if even: + return True + if odd == len(expr.args): + return False @staticmethod def Add(expr, assumptions): @@ -161,7 +158,8 @@ pass elif ask(Q.odd(arg), assumptions): _result = not _result - else: break + else: + break else: return _result @@ -169,31 +167,17 @@ def Integer(expr, assumptions): return not bool(expr.p & 1) - @staticmethod - def Rational(expr, assumptions): - return False + Rational, Infinity, NegativeInfinity, ImaginaryUnit = [staticmethod(CommonHandler.AlwaysFalse)]*4 @staticmethod def Float(expr, assumptions): return expr % 2 == 0 @staticmethod - def Infinity(expr, assumptions): - return False - - @staticmethod - def NegativeInfinity(expr, assumptions): - return False - - @staticmethod def NumberSymbol(expr, assumptions): return AskEvenHandler._number(expr, assumptions) @staticmethod - def ImaginaryUnit(expr, assumptions): - return False - - @staticmethod def Abs(expr, assumptions): if ask(Q.real(expr.args[0]), assumptions): return ask(Q.even(expr.args[0]), assumptions) @@ -208,6 +192,7 @@ if ask(Q.real(expr.args[0]), assumptions): return True + class AskOddHandler(CommonHandler): """ Handler for key 'odd' @@ -219,6 +204,7 @@ _integer = ask(Q.integer(expr), assumptions) if _integer: _even = ask(Q.even(expr), assumptions) - if _even is None: return None + if _even is None: + return None return not _even return _integer diff -Nru python3-sympy-0.7.2/sympy/assumptions/handlers/order.py python3-sympy-0.7.3/sympy/assumptions/handlers/order.py --- python3-sympy-0.7.2/sympy/assumptions/handlers/order.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/assumptions/handlers/order.py 2013-07-13 17:53:31.000000000 +0000 @@ -25,7 +25,8 @@ def _number(expr, assumptions): if not expr.as_real_imag()[1]: return expr.evalf() < 0 - else: return False + else: + return False @staticmethod def Basic(expr, assumptions): @@ -53,12 +54,14 @@ return AskNegativeHandler._number(expr, assumptions) result = None for arg in expr.args: - if result is None: result = False + if result is None: + result = False if ask(Q.negative(arg), assumptions): result = not result elif ask(Q.positive(arg), assumptions): pass - else: return + else: + return return result @staticmethod @@ -78,13 +81,13 @@ if ask(Q.odd(expr.exp), assumptions): return ask(Q.negative(expr.base), assumptions) - @staticmethod - def ImaginaryUnit(expr, assumptions): - return False + ImaginaryUnit, Abs = [staticmethod(CommonHandler.AlwaysFalse)]*2 @staticmethod - def Abs(expr, assumptions): - return False + def exp(expr, assumptions): + if ask(Q.real(expr.args[0]), assumptions): + return False + class AskNonZeroHandler(CommonHandler): """ @@ -101,14 +104,15 @@ @staticmethod def Add(expr, assumptions): if all(ask(Q.positive(x), assumptions) for x in expr.args) \ - or all(ask(Q.negative(x), assumptions) for x in expr.args): + or all(ask(Q.negative(x), assumptions) for x in expr.args): return True @staticmethod def Mul(expr, assumptions): for arg in expr.args: result = ask(Q.nonzero(arg), assumptions) - if result: continue + if result: + continue return result return True @@ -116,14 +120,13 @@ def Pow(expr, assumptions): return ask(Q.nonzero(expr.base), assumptions) - @staticmethod - def NaN(expr, assumptions): - return True + NaN = staticmethod(CommonHandler.AlwaysTrue) @staticmethod def Abs(expr, assumptions): return ask(Q.nonzero(expr.args[0]), assumptions) + class AskPositiveHandler(CommonHandler): """ Handler for key 'positive' @@ -134,7 +137,8 @@ def _number(expr, assumptions): if not expr.as_real_imag()[1]: return expr.evalf() > 0 - else: return False + else: + return False @staticmethod def Basic(expr, assumptions): @@ -147,10 +151,12 @@ return AskPositiveHandler._number(expr, assumptions) result = True for arg in expr.args: - if ask(Q.positive(arg), assumptions): continue + if ask(Q.positive(arg), assumptions): + continue elif ask(Q.negative(arg), assumptions): result = result ^ True - else: return + else: + return return result @staticmethod @@ -166,7 +172,8 @@ @staticmethod def Pow(expr, assumptions): - if expr.is_number: return expr.evalf() > 0 + if expr.is_number: + return expr.evalf() > 0 if ask(Q.positive(expr.base), assumptions): return True if ask(Q.negative(expr.base), assumptions): @@ -180,10 +187,24 @@ if ask(Q.real(expr.args[0]), assumptions): return True - @staticmethod - def ImaginaryUnit(expr, assumptions): - return False + ImaginaryUnit = staticmethod(CommonHandler.AlwaysFalse) @staticmethod def Abs(expr, assumptions): return ask(Q.nonzero(expr), assumptions) + + @staticmethod + def Trace(expr, assumptions): + if ask(Q.positive_definite(expr.arg), assumptions): + return True + + @staticmethod + def Determinant(expr, assumptions): + if ask(Q.positive_definite(expr.arg), assumptions): + return True + + @staticmethod + def MatrixElement(expr, assumptions): + if (expr.i == expr.j + and ask(Q.positive_definite(expr.parent), assumptions)): + return True diff -Nru python3-sympy-0.7.2/sympy/assumptions/handlers/sets.py python3-sympy-0.7.3/sympy/assumptions/handlers/sets.py --- python3-sympy-0.7.2/sympy/assumptions/handlers/sets.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/assumptions/handlers/sets.py 2013-07-13 17:53:31.000000000 +0000 @@ -2,7 +2,9 @@ Handlers for predicates related to set membership: integer, rational, etc. """ from sympy.assumptions import Q, ask -from sympy.assumptions.handlers import CommonHandler +from sympy.assumptions.handlers import CommonHandler, test_closed_group +from sympy import I, S + class AskIntegerHandler(CommonHandler): """ @@ -62,13 +64,10 @@ Pow = Add - @staticmethod - def int(expr, assumptions): - return True + int, Integer = [staticmethod(CommonHandler.AlwaysTrue)]*2 - @staticmethod - def Integer(expr, assumptions): - return True + Pi, Exp1, GoldenRatio, Infinity, NegativeInfinity, ImaginaryUnit = \ + [staticmethod(CommonHandler.AlwaysFalse)]*6 @staticmethod def Rational(expr, assumptions): @@ -81,28 +80,15 @@ return int(expr) == expr @staticmethod - def Pi(expr, assumptions): - return False - - @staticmethod - def Exp1(expr, assumptions): - return False - - @staticmethod - def Infinity(expr, assumptions): - return False + def Abs(expr, assumptions): + return ask(Q.integer(expr.args[0]), assumptions) @staticmethod - def NegativeInfinity(expr, assumptions): - return False + def MatrixElement(expr, assumptions): + return ask(Q.integer_elements(expr.args[0]), assumptions) - @staticmethod - def ImaginaryUnit(expr, assumptions): - return False + Determinant = Trace = MatrixElement - @staticmethod - def Abs(expr, assumptions): - return ask(Q.integer(expr.args[0]), assumptions) class AskRationalHandler(CommonHandler): """ @@ -137,34 +123,33 @@ if ask(Q.prime(expr.base), assumptions): return False - @staticmethod - def Rational(expr, assumptions): - return True + Rational, Float = \ + [staticmethod(CommonHandler.AlwaysTrue)]*2 # Float is finite-precision - @staticmethod - def Float(expr, assumptions): - # it's finite-precision - return True + ImaginaryUnit, Infinity, NegativeInfinity, Pi, Exp1, GoldenRatio = \ + [staticmethod(CommonHandler.AlwaysFalse)]*6 @staticmethod - def ImaginaryUnit(expr, assumptions): - return False + def exp(expr, assumptions): + x = expr.args[0] + if ask(Q.rational(x), assumptions): + return ask(~Q.nonzero(x), assumptions) @staticmethod - def Infinity(expr, assumptions): - return False + def cot(expr, assumptions): + x = expr.args[0] + if ask(Q.rational(x), assumptions): + return False @staticmethod - def NegativeInfinity(expr, assumptions): - return False + def log(expr, assumptions): + x = expr.args[0] + if ask(Q.rational(x), assumptions): + return ask(~Q.nonzero(x - 1), assumptions) - @staticmethod - def Pi(expr, assumptions): - return False + sin, cos, tan, asin, atan = [exp]*5 + acos, acot = log, cot - @staticmethod - def Exp1(expr, assumptions): - return False class AskIrrationalHandler(CommonHandler): @@ -173,9 +158,12 @@ _real = ask(Q.real(expr), assumptions) if _real: _rational = ask(Q.rational(expr), assumptions) - if _rational is None: return None + if _rational is None: + return None return not _rational - else: return _real + else: + return _real + class AskRealHandler(CommonHandler): """ @@ -185,7 +173,13 @@ @staticmethod def _number(expr, assumptions): - return not expr.as_real_imag()[1] + # let as_real_imag() work first since the expression may + # be simpler to evaluate + i = expr.as_real_imag()[1].evalf(2) + if i._prec != 1: + return not i + # allow None to be returned if we couldn't show for sure + # that i was 0 @staticmethod def Add(expr, assumptions): @@ -224,65 +218,54 @@ Positive**Real -> Real Real**(Integer/Even) -> Real if base is nonnegative Real**(Integer/Odd) -> Real + Real**Imaginary -> ? + Imaginary**Real -> ? + Real**Real -> ? """ if expr.is_number: return AskRealHandler._number(expr, assumptions) - if ask(Q.real(expr.base), assumptions): - if ask(Q.integer(expr.exp), assumptions): - return True - elif expr.exp.is_Rational: - if (expr.exp.q % 2 == 0): - return ask(Q.real(expr.base), assumptions) and \ - not ask(Q.negative(expr.base), assumptions) - else: return True - elif ask(Q.real(expr.exp), assumptions): - if ask(Q.positive(expr.base), assumptions): + if ask(Q.imaginary(expr.base), assumptions): + if ask(Q.real(expr.exp), assumptions): + if ask(Q.odd(expr.exp), assumptions): + return False + elif ask(Q.even(expr.exp), assumptions): return True + elif ask(Q.real(expr.base), assumptions): + if ask(Q.real(expr.exp), assumptions): + if expr.exp.is_Rational and \ + ask(Q.even(expr.exp.q), assumptions): + return ask(Q.positive(expr.base), assumptions) + elif ask(Q.integer(expr.exp), assumptions): + return True + elif ask(Q.positive(expr.base), assumptions): + return True + elif ask(Q.negative(expr.base), assumptions): + return False - @staticmethod - def Rational(expr, assumptions): - return True - - @staticmethod - def Float(expr, assumptions): - return True - - @staticmethod - def Pi(expr, assumptions): - return True - - @staticmethod - def Exp1(expr, assumptions): - return True + Rational, Float, Pi, Exp1, GoldenRatio, Abs, re, im = \ + [staticmethod(CommonHandler.AlwaysTrue)]*8 - @staticmethod - def Abs(expr, assumptions): - return True + ImaginaryUnit, Infinity, NegativeInfinity = \ + [staticmethod(CommonHandler.AlwaysFalse)]*3 @staticmethod - def re(expr, assumptions): - return True - - im = re + def sin(expr, assumptions): + if ask(Q.real(expr.args[0]), assumptions): + return True - @staticmethod - def ImaginaryUnit(expr, assumptions): - return False + cos, exp = [sin]*2 @staticmethod - def Infinity(expr, assumptions): - return False + def MatrixElement(expr, assumptions): + return ask(Q.real_elements(expr.args[0]), assumptions) - @staticmethod - def NegativeInfinity(expr, assumptions): - return False + Determinant = Trace = MatrixElement @staticmethod - def sin(expr, assumptions): - if ask(Q.real(expr.args[0]), assumptions): + def log(expr, assumptions): + if ask(Q.positive(expr.args[0]), assumptions): return True - cos, exp = sin, sin class AskExtendedRealHandler(AskRealHandler): """ @@ -295,15 +278,10 @@ def Add(expr, assumptions): return test_closed_group(expr, assumptions, Q.extended_real) - Mul, Pow = Add, Add + Mul, Pow = [Add]*2 - @staticmethod - def Infinity(expr, assumptions): - return True + Infinity, NegativeInfinity = [staticmethod(CommonHandler.AlwaysTrue)]*2 - @staticmethod - def NegativeInfinity(expr, assumptions): - return True class AskHermitianHandler(AskRealHandler): """ @@ -361,7 +339,8 @@ if ask(Q.hermitian(expr.args[0]), assumptions): return True - cos, exp = sin, sin + cos, exp = [sin]*2 + class AskComplexHandler(CommonHandler): """ @@ -373,33 +352,19 @@ def Add(expr, assumptions): return test_closed_group(expr, assumptions, Q.complex) - Mul, Pow = Add, Add - - @staticmethod - def Number(expr, assumptions): - return True + Mul = Pow = Add - @staticmethod - def NumberSymbol(expr, assumptions): - return True + Number, sin, cos, exp, re, im, NumberSymbol, Abs, ImaginaryUnit = \ + [staticmethod(CommonHandler.AlwaysTrue)]*9 # they are all complex functions or expressions - @staticmethod - def Abs(expr, assumptions): - return True + Infinity, NegativeInfinity = [staticmethod(CommonHandler.AlwaysFalse)]*2 @staticmethod - def ImaginaryUnit(expr, assumptions): - return True + def MatrixElement(expr, assumptions): + return ask(Q.complex_elements(expr.args[0]), assumptions) - @staticmethod - def Infinity(expr, assumptions): - return False + Determinant = Trace = MatrixElement - @staticmethod - def NegativeInfinity(expr, assumptions): - return False - - sin, cos, exp, re, im = [Abs]*5 # they are all complex functions class AskImaginaryHandler(CommonHandler): """ @@ -411,7 +376,7 @@ @staticmethod def _number(expr, assumptions): # helper method - return not expr.as_real_imag()[0] + return not expr.as_real_imag()[0].evalf() @staticmethod def Add(expr, assumptions): @@ -457,7 +422,33 @@ return False return result - Pow = Add + @staticmethod + def Pow(expr, assumptions): + """ + Imaginary**integer -> Imaginary if integer % 2 == 1 + Imaginary**integer -> real if integer % 2 == 0 + Imaginary**Imaginary -> ? + Imaginary**Real -> ? + """ + if expr.is_number: + return AskImaginaryHandler._number(expr, assumptions) + if ask(Q.imaginary(expr.base), assumptions): + if ask(Q.real(expr.exp), assumptions): + if ask(Q.odd(expr.exp), assumptions): + return True + elif ask(Q.even(expr.exp), assumptions): + return False + elif ask(Q.real(expr.base), assumptions): + if ask(Q.real(expr.exp), assumptions): + if expr.exp.is_Rational and \ + ask(Q.even(expr.exp.q), assumptions): + return ask(Q.negative(expr.base),assumptions) + elif ask(Q.integer(expr.exp), assumptions): + return False + elif ask(Q.positive(expr.base), assumptions): + return False + elif ask(Q.negative(expr.base), assumptions): + return True @staticmethod def Number(expr, assumptions): @@ -465,9 +456,8 @@ NumberSymbol = Number - @staticmethod - def ImaginaryUnit(expr, assumptions): - return True + ImaginaryUnit = staticmethod(CommonHandler.AlwaysTrue) + class AskAntiHermitianHandler(AskImaginaryHandler): """ @@ -528,6 +518,7 @@ elif ask(Q.odd(expr.exp), assumptions): return True + class AskAlgebraicHandler(CommonHandler): """Handler for Q.algebraic key. """ @@ -541,37 +532,36 @@ @staticmethod def Pow(expr, assumptions): - return expr.exp.is_Rational and ask(Q.algebraic(expr.base), assumptions) - - @staticmethod - def Number(expr, assumptions): - return False + return expr.exp.is_Rational and ask( + Q.algebraic(expr.base), assumptions) @staticmethod def Rational(expr, assumptions): return expr.q != 0 + Float, GoldenRatio, ImaginaryUnit, AlgebraicNumber = \ + [staticmethod(CommonHandler.AlwaysTrue)]*4 + + Infinity, NegativeInfinity, ComplexInfinity, Pi, Exp1 = \ + [staticmethod(CommonHandler.AlwaysFalse)]*5 + @staticmethod - def ImaginaryUnit(expr, assumptions): - return True + def exp(expr, assumptions): + x = expr.args[0] + if ask(Q.algebraic(x), assumptions): + return ask(~Q.nonzero(x), assumptions) @staticmethod - def AlgebraicNumber(expr, assumptions): - return True + def cot(expr, assumptions): + x = expr.args[0] + if ask(Q.algebraic(x), assumptions): + return False -#### Helper methods + @staticmethod + def log(expr, assumptions): + x = expr.args[0] + if ask(Q.algebraic(x), assumptions): + return ask(~Q.nonzero(x - 1), assumptions) -def test_closed_group(expr, assumptions, key): - """ - Test for membership in a group with respect - to the current operation - """ - result = True - for arg in expr.args: - _out = ask(key(arg), assumptions) - if _out is None: break - elif _out is False: - if result: result = False - else: break - else: - return result + sin, cos, tan, asin, atan = [exp]*5 + acos, acot = log, cot diff -Nru python3-sympy-0.7.2/sympy/assumptions/refine.py python3-sympy-0.7.3/sympy/assumptions/refine.py --- python3-sympy-0.7.2/sympy/assumptions/refine.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/assumptions/refine.py 2013-07-13 17:53:31.000000000 +0000 @@ -1,6 +1,7 @@ -from sympy.core import S, Add +from sympy.core import S, Add, Expr from sympy.assumptions import Q, ask -from sympy.logic.boolalg import fuzzy_not +from sympy.core.logic import fuzzy_not + def refine(expr, assumptions=True): """ @@ -27,12 +28,16 @@ expr = expr.func(*args) name = expr.__class__.__name__ handler = handlers_dict.get(name, None) - if handler is None: return expr + if handler is None: + return expr new_expr = handler(expr, assumptions) if (new_expr is None) or (expr == new_expr): return expr + if not isinstance(new_expr, Expr): + return new_expr return refine(new_expr, assumptions) + def refine_abs(expr, assumptions): """ Handler for the absolute value. @@ -58,6 +63,7 @@ if ask(Q.negative(arg), assumptions): return -arg + def refine_Pow(expr, assumptions): """ Handler for instances of Pow. @@ -84,7 +90,12 @@ """ from sympy.core import Pow, Rational + from sympy.functions.elementary.complexes import Abs from sympy.functions import sign + if isinstance(expr.base, Abs): + if ask(Q.real(expr.base.args[0]), assumptions) and \ + ask(Q.even(expr.exp), assumptions): + return expr.base.args[0] ** expr.exp if ask(Q.real(expr.base), assumptions): if expr.base.is_number: if ask(Q.even(expr.exp), assumptions): @@ -117,7 +128,7 @@ odd_terms.add(t) terms -= even_terms - if len(odd_terms)%2: + if len(odd_terms) % 2: terms -= odd_terms new_coeff = (coeff + S.One) % 2 else: @@ -155,8 +166,27 @@ elif ask(Q.odd(coeff + S.Half), assumptions): return S.ImaginaryUnit +def refine_Relational(expr, assumptions): + """ + Handler for Relational + + >>> from sympy.assumptions.refine import refine_Relational + >>> from sympy.assumptions.ask import Q + >>> from sympy.abc import x + >>> refine_Relational(x<0, ~Q.is_true(x<0)) + False + """ + return ask(Q.is_true(expr), assumptions) + + handlers_dict = { - 'Abs' : refine_abs, - 'Pow' : refine_Pow, - 'exp' : refine_exp, + 'Abs': refine_abs, + 'Pow': refine_Pow, + 'exp': refine_exp, + 'Equality' : refine_Relational, + 'Unequality' : refine_Relational, + 'GreaterThan' : refine_Relational, + 'LessThan' : refine_Relational, + 'StrictGreaterThan' : refine_Relational, + 'StrictLessThan' : refine_Relational } diff -Nru python3-sympy-0.7.2/sympy/assumptions/tests/test_assumptions_2.py python3-sympy-0.7.3/sympy/assumptions/tests/test_assumptions_2.py --- python3-sympy-0.7.2/sympy/assumptions/tests/test_assumptions_2.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/assumptions/tests/test_assumptions_2.py 2013-07-13 17:53:31.000000000 +0000 @@ -1,30 +1,37 @@ -"""rename this to test_assumptions.py when the old assumptions system is deleted""" +""" +rename this to test_assumptions.py when the old assumptions system is deleted +""" from sympy.abc import x, y -from sympy.assumptions import global_assumptions, Predicate +from sympy.assumptions.assume import global_assumptions, Predicate from sympy.assumptions.ask import _extract_facts, Q from sympy.core import symbols from sympy.logic.boolalg import Or from sympy.printing import pretty + def test_equal(): """Test for equality""" - assert Q.positive(x) == Q.positive(x) - assert Q.positive(x) != ~Q.positive(x) + assert Q.positive(x) == Q.positive(x) + assert Q.positive(x) != ~Q.positive(x) assert ~Q.positive(x) == ~Q.positive(x) + def test_pretty(): assert pretty(Q.positive(x)) == "Q.positive(x)" - assert pretty(set([Q.positive, Q.integer])) == "set([Q.integer, Q.positive])" + assert pretty( + set([Q.positive, Q.integer])) == "set([Q.integer, Q.positive])" + def test_extract_facts(): a, b = symbols('a b', cls=Predicate) - assert _extract_facts(a(x), x) == a - assert _extract_facts(a(x), y) == None + assert _extract_facts(a(x), x) == a + assert _extract_facts(a(x), y) is None assert _extract_facts(~a(x), x) == ~a - assert _extract_facts(~a(x), y) == None + assert _extract_facts(~a(x), y) is None assert _extract_facts(a(x) | b(x), x) == a | b assert _extract_facts(a(x) | ~b(x), x) == a | ~b + def test_global(): """Test for global assumptions""" global_assumptions.add(Q.is_true(x > 0)) @@ -39,6 +46,7 @@ assert not Q.is_true(x > 0) in global_assumptions assert not Q.is_true(y > 0) in global_assumptions + def test_composite_predicates(): pred = Q.integer | ~Q.positive assert type(pred(x)) is Or diff -Nru python3-sympy-0.7.2/sympy/assumptions/tests/test_context.py python3-sympy-0.7.3/sympy/assumptions/tests/test_context.py --- python3-sympy-0.7.2/sympy/assumptions/tests/test_context.py 1970-01-01 00:00:00.000000000 +0000 +++ python3-sympy-0.7.3/sympy/assumptions/tests/test_context.py 2013-07-13 17:53:31.000000000 +0000 @@ -0,0 +1,40 @@ + +from sympy.assumptions import ask, Q +from sympy.assumptions.assume import assuming, global_assumptions +from sympy.abc import x, y + +def test_assuming(): + with assuming(Q.integer(x)): + assert ask(Q.integer(x)) + assert not ask(Q.integer(x)) + +def test_assuming_nested(): + assert not ask(Q.integer(x)) + assert not ask(Q.integer(y)) + with assuming(Q.integer(x)): + assert ask(Q.integer(x)) + assert not ask(Q.integer(y)) + with assuming(Q.integer(y)): + assert ask(Q.integer(x)) + assert ask(Q.integer(y)) + assert ask(Q.integer(x)) + assert not ask(Q.integer(y)) + assert not ask(Q.integer(x)) + assert not ask(Q.integer(y)) + +def test_finally(): + try: + with assuming(Q.integer(x)): + 1/0 + except ZeroDivisionError: + pass + assert not ask(Q.integer(x)) + +def test_remove_safe(): + global_assumptions.add(Q.integer(x)) + with assuming(): + assert ask(Q.integer(x)) + global_assumptions.remove(Q.integer(x)) + assert not ask(Q.integer(x)) + assert ask(Q.integer(x)) + global_assumptions.clear() # for the benefit of other tests diff -Nru python3-sympy-0.7.2/sympy/assumptions/tests/test_matrices.py python3-sympy-0.7.3/sympy/assumptions/tests/test_matrices.py --- python3-sympy-0.7.2/sympy/assumptions/tests/test_matrices.py 1970-01-01 00:00:00.000000000 +0000 +++ python3-sympy-0.7.3/sympy/assumptions/tests/test_matrices.py 2013-07-13 17:53:31.000000000 +0000 @@ -0,0 +1,197 @@ +from sympy import Q, ask, Symbol +from sympy.matrices.expressions import (MatrixSymbol, Identity, ZeroMatrix, + Trace, MatrixSlice, Determinant) +from sympy.matrices.expressions.factorizations import LofLU +from sympy.utilities.pytest import XFAIL +from sympy.assumptions import assuming + +X = MatrixSymbol('X', 2, 2) +Y = MatrixSymbol('Y', 2, 3) +Z = MatrixSymbol('Z', 2, 2) + +def test_square(): + assert ask(Q.square(X)) + assert not ask(Q.square(Y)) + assert ask(Q.square(Y*Y.T)) + +def test_invertible(): + assert ask(Q.invertible(X), Q.invertible(X)) + assert ask(Q.invertible(Y)) is False + assert ask(Q.invertible(X*Y), Q.invertible(X)) is False + assert ask(Q.invertible(X*Z), Q.invertible(X)) is None + assert ask(Q.invertible(X*Z), Q.invertible(X) & Q.invertible(Z)) is True + assert ask(Q.invertible(X.T)) is None + assert ask(Q.invertible(X.T), Q.invertible(X)) is True + assert ask(Q.invertible(X.I)) is True + assert ask(Q.invertible(Identity(3))) is True + assert ask(Q.invertible(ZeroMatrix(3, 3))) is False + assert ask(Q.invertible(X), Q.fullrank(X) & Q.square(X)) + +def test_singular(): + assert ask(Q.singular(X)) is None + assert ask(Q.singular(X), Q.invertible(X)) is False + assert ask(Q.singular(X), ~Q.invertible(X)) is True + +@XFAIL +def test_invertible_fullrank(): + assert ask(Q.invertible(X), Q.fullrank(X)) + + +def test_symmetric(): + assert ask(Q.symmetric(X), Q.symmetric(X)) + assert ask(Q.symmetric(X*Z), Q.symmetric(X)) is None + assert ask(Q.symmetric(X*Z), Q.symmetric(X) & Q.symmetric(Z)) is True + assert ask(Q.symmetric(X + Z), Q.symmetric(X) & Q.symmetric(Z)) is True + assert ask(Q.symmetric(Y)) is False + assert ask(Q.symmetric(Y*Y.T)) is True + assert ask(Q.symmetric(Y.T*X*Y)) is None + assert ask(Q.symmetric(Y.T*X*Y), Q.symmetric(X)) is True + assert ask(Q.symmetric(X*X*X*X*X*X*X*X*X*X), Q.symmetric(X)) is True + + +def _test_orthogonal_unitary(predicate): + assert ask(predicate(X), predicate(X)) + assert ask(predicate(X.T), predicate(X)) is True + assert ask(predicate(X.I), predicate(X)) is True + assert ask(predicate(Y)) is False + assert ask(predicate(X)) is None + assert ask(predicate(X*Z*X), predicate(X) & predicate(Z)) is True + assert ask(predicate(Identity(3))) is True + assert ask(predicate(ZeroMatrix(3, 3))) is False + assert ask(Q.invertible(X), predicate(X)) + assert not ask(predicate(X + Z), predicate(X) & predicate(Z)) + +def test_orthogonal(): + _test_orthogonal_unitary(Q.orthogonal) + +def test_unitary(): + _test_orthogonal_unitary(Q.unitary) + assert ask(Q.unitary(X), Q.orthogonal(X)) + +def test_fullrank(): + assert ask(Q.fullrank(X), Q.fullrank(X)) + assert ask(Q.fullrank(X.T), Q.fullrank(X)) is True + assert ask(Q.fullrank(X)) is None + assert ask(Q.fullrank(Y)) is None + assert ask(Q.fullrank(X*Z), Q.fullrank(X) & Q.fullrank(Z)) is True + assert ask(Q.fullrank(Identity(3))) is True + assert ask(Q.fullrank(ZeroMatrix(3, 3))) is False + assert ask(Q.invertible(X), ~Q.fullrank(X)) == False + + +def test_positive_definite(): + assert ask(Q.positive_definite(X), Q.positive_definite(X)) + assert ask(Q.positive_definite(X.T), Q.positive_definite(X)) is True + assert ask(Q.positive_definite(X.I), Q.positive_definite(X)) is True + assert ask(Q.positive_definite(Y)) is False + assert ask(Q.positive_definite(X)) is None + assert ask(Q.positive_definite(X*Z*X), + Q.positive_definite(X) & Q.positive_definite(Z)) is True + assert ask(Q.positive_definite(X), Q.orthogonal(X)) + assert ask(Q.positive_definite(Y.T*X*Y), + Q.positive_definite(X) & Q.fullrank(Y)) is True + assert not ask(Q.positive_definite(Y.T*X*Y), Q.positive_definite(X)) + assert ask(Q.positive_definite(Identity(3))) is True + assert ask(Q.positive_definite(ZeroMatrix(3, 3))) is False + assert ask(Q.positive_definite(X + Z), Q.positive_definite(X) & + Q.positive_definite(Z)) is True + assert not ask(Q.positive_definite(-X), Q.positive_definite(X)) + assert ask(Q.positive(X[1, 1]), Q.positive_definite(X)) + +def test_triangular(): + assert ask(Q.upper_triangular(X + Z.T + Identity(2)), Q.upper_triangular(X) & + Q.lower_triangular(Z)) is True + assert ask(Q.upper_triangular(X*Z.T), Q.upper_triangular(X) & + Q.lower_triangular(Z)) is True + assert ask(Q.lower_triangular(Identity(3))) is True + assert ask(Q.lower_triangular(ZeroMatrix(3, 3))) is True + assert ask(Q.triangular(X), Q.unit_triangular(X)) + + +def test_diagonal(): + assert ask(Q.diagonal(X + Z.T + Identity(2)), Q.diagonal(X) & + Q.diagonal(Z)) is True + assert ask(Q.diagonal(ZeroMatrix(3, 3))) + assert ask(Q.lower_triangular(X) & Q.upper_triangular(X), Q.diagonal(X)) + assert ask(Q.diagonal(X), Q.lower_triangular(X) & Q.upper_triangular(X)) + assert ask(Q.symmetric(X), Q.diagonal(X)) + assert ask(Q.triangular(X), Q.diagonal(X)) + + +def test_non_atoms(): + assert ask(Q.real(Trace(X)), Q.positive(Trace(X))) + +@XFAIL +def test_non_trivial_implies(): + X = MatrixSymbol('X', 3, 3) + Y = MatrixSymbol('Y', 3, 3) + assert ask(Q.lower_triangular(X+Y), Q.lower_triangular(X) & + Q.lower_triangular(Y)) + assert ask(Q.triangular(X), Q.lower_triangular(X)) + assert ask(Q.triangular(X+Y), Q.lower_triangular(X) & + Q.lower_triangular(Y)) + +def test_MatrixSlice(): + X = MatrixSymbol('X', 4, 4) + B = MatrixSlice(X, (1, 3), (1, 3)) + C = MatrixSlice(X, (0, 3), (1, 3)) + assert ask(Q.symmetric(B), Q.symmetric(X)) + assert ask(Q.invertible(B), Q.invertible(X)) + assert ask(Q.diagonal(B), Q.diagonal(X)) + assert ask(Q.orthogonal(B), Q.orthogonal(X)) + assert ask(Q.upper_triangular(B), Q.upper_triangular(X)) + + assert not ask(Q.symmetric(C), Q.symmetric(X)) + assert not ask(Q.invertible(C), Q.invertible(X)) + assert not ask(Q.diagonal(C), Q.diagonal(X)) + assert not ask(Q.orthogonal(C), Q.orthogonal(X)) + assert not ask(Q.upper_triangular(C), Q.upper_triangular(X)) + +def test_det_trace_positive(): + X = MatrixSymbol('X', 4, 4) + assert ask(Q.positive(Trace(X)), Q.positive_definite(X)) + assert ask(Q.positive(Determinant(X)), Q.positive_definite(X)) + +def test_field_assumptions(): + X = MatrixSymbol('X', 4, 4) + Y = MatrixSymbol('Y', 4, 4) + assert ask(Q.real_elements(X), Q.real_elements(X)) + assert not ask(Q.integer_elements(X), Q.real_elements(X)) + assert ask(Q.complex_elements(X), Q.real_elements(X)) + assert ask(Q.real_elements(X+Y), Q.real_elements(X)) is None + assert ask(Q.real_elements(X+Y), Q.real_elements(X) & Q.real_elements(Y)) + from sympy.matrices.expressions.hadamard import HadamardProduct + assert ask(Q.real_elements(HadamardProduct(X, Y)), + Q.real_elements(X) & Q.real_elements(Y)) + assert ask(Q.complex_elements(X+Y), Q.real_elements(X) & Q.complex_elements(Y)) + + assert ask(Q.real_elements(X.T), Q.real_elements(X)) + assert ask(Q.real_elements(X.I), Q.real_elements(X) & Q.invertible(X)) + assert ask(Q.real_elements(Trace(X)), Q.real_elements(X)) + assert ask(Q.integer_elements(Determinant(X)), Q.integer_elements(X)) + assert not ask(Q.integer_elements(X.I), Q.integer_elements(X)) + alpha = Symbol('alpha') + assert ask(Q.real_elements(alpha*X), Q.real_elements(X) & Q.real(alpha)) + assert ask(Q.real_elements(LofLU(X)), Q.real_elements(X)) + +def test_matrix_element_sets(): + X = MatrixSymbol('X', 4, 4) + assert ask(Q.real(X[1, 2]), Q.real_elements(X)) + assert ask(Q.integer(X[1, 2]), Q.integer_elements(X)) + assert ask(Q.complex(X[1, 2]), Q.complex_elements(X)) + assert ask(Q.integer_elements(Identity(3))) + assert ask(Q.integer_elements(ZeroMatrix(3, 3))) + from sympy.matrices.expressions.fourier import DFT + assert ask(Q.complex_elements(DFT(3))) + + +def test_matrix_element_sets_slices_blocks(): + from sympy.matrices.expressions import BlockMatrix + X = MatrixSymbol('X', 4, 4) + assert ask(Q.integer_elements(X[:, 3]), Q.integer_elements(X)) + assert ask(Q.integer_elements(BlockMatrix([[X], [X]])), + Q.integer_elements(X)) + +def test_matrix_element_sets_determinant_trace(): + assert ask(Q.integer(Determinant(X)), Q.integer_elements(X)) + assert ask(Q.integer(Trace(X)), Q.integer_elements(X)) diff -Nru python3-sympy-0.7.2/sympy/assumptions/tests/test_query.py python3-sympy-0.7.3/sympy/assumptions/tests/test_query.py --- python3-sympy-0.7.2/sympy/assumptions/tests/test_query.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/assumptions/tests/test_query.py 2013-07-13 17:53:31.000000000 +0000 @@ -1,1333 +1,1750 @@ + from sympy.abc import t, w, x, y, z -from sympy.assumptions import (ask, AssumptionsContext, global_assumptions, Q, - register_handler, remove_handler) +from sympy.assumptions import (ask, AssumptionsContext, Q, register_handler, + remove_handler) +from sympy.assumptions.assume import global_assumptions from sympy.assumptions.ask import (compute_known_facts, known_facts_cnf, - known_facts_dict) + known_facts_dict, single_fact_lookup) from sympy.assumptions.handlers import AskHandler from sympy.core import I, Integer, oo, pi, Rational, S, symbols, Add -from sympy.functions import Abs, cos, exp, im, log, re, sign, sin, sqrt -from sympy.logic import Equivalent, Implies, Xor +from sympy.functions import (Abs, cos, exp, im, log, re, sign, sin, sqrt, + tan, atan, acos, asin, cot, acot) +from sympy.logic import Equivalent, Implies, Xor, And, to_cnf, Not from sympy.utilities.pytest import raises, XFAIL, slow +from sympy.assumptions.assume import assuming + def test_int_1(): z = 1 - assert ask(Q.commutative(z)) == True - assert ask(Q.integer(z)) == True - assert ask(Q.rational(z)) == True - assert ask(Q.real(z)) == True - assert ask(Q.complex(z)) == True - assert ask(Q.irrational(z)) == False - assert ask(Q.imaginary(z)) == False - assert ask(Q.positive(z)) == True - assert ask(Q.negative(z)) == False - assert ask(Q.even(z)) == False - assert ask(Q.odd(z)) == True - assert ask(Q.bounded(z)) == True - assert ask(Q.infinitesimal(z)) == False - assert ask(Q.prime(z)) == False - assert ask(Q.composite(z)) == True - assert ask(Q.hermitian(z)) == True - assert ask(Q.antihermitian(z)) == False + assert ask(Q.commutative(z)) is True + assert ask(Q.integer(z)) is True + assert ask(Q.rational(z)) is True + assert ask(Q.real(z)) is True + assert ask(Q.complex(z)) is True + assert ask(Q.irrational(z)) is False + assert ask(Q.imaginary(z)) is False + assert ask(Q.positive(z)) is True + assert ask(Q.negative(z)) is False + assert ask(Q.even(z)) is False + assert ask(Q.odd(z)) is True + assert ask(Q.bounded(z)) is True + assert ask(Q.infinitesimal(z)) is False + assert ask(Q.prime(z)) is False + assert ask(Q.composite(z)) is True + assert ask(Q.hermitian(z)) is True + assert ask(Q.antihermitian(z)) is False + def test_int_11(): z = 11 - assert ask(Q.commutative(z)) == True - assert ask(Q.integer(z)) == True - assert ask(Q.rational(z)) == True - assert ask(Q.real(z)) == True - assert ask(Q.complex(z)) == True - assert ask(Q.irrational(z)) == False - assert ask(Q.imaginary(z)) == False - assert ask(Q.positive(z)) == True - assert ask(Q.negative(z)) == False - assert ask(Q.even(z)) == False - assert ask(Q.odd(z)) == True - assert ask(Q.bounded(z)) == True - assert ask(Q.infinitesimal(z)) == False - assert ask(Q.prime(z)) == True - assert ask(Q.composite(z)) == False - assert ask(Q.hermitian(z)) == True - assert ask(Q.antihermitian(z)) == False + assert ask(Q.commutative(z)) is True + assert ask(Q.integer(z)) is True + assert ask(Q.rational(z)) is True + assert ask(Q.real(z)) is True + assert ask(Q.complex(z)) is True + assert ask(Q.irrational(z)) is False + assert ask(Q.imaginary(z)) is False + assert ask(Q.positive(z)) is True + assert ask(Q.negative(z)) is False + assert ask(Q.even(z)) is False + assert ask(Q.odd(z)) is True + assert ask(Q.bounded(z)) is True + assert ask(Q.infinitesimal(z)) is False + assert ask(Q.prime(z)) is True + assert ask(Q.composite(z)) is False + assert ask(Q.hermitian(z)) is True + assert ask(Q.antihermitian(z)) is False + def test_int_12(): z = 12 - assert ask(Q.commutative(z)) == True - assert ask(Q.integer(z)) == True - assert ask(Q.rational(z)) == True - assert ask(Q.real(z)) == True - assert ask(Q.complex(z)) == True - assert ask(Q.irrational(z)) == False - assert ask(Q.imaginary(z)) == False - assert ask(Q.positive(z)) == True - assert ask(Q.negative(z)) == False - assert ask(Q.even(z)) == True - assert ask(Q.odd(z)) == False - assert ask(Q.bounded(z)) == True - assert ask(Q.infinitesimal(z)) == False - assert ask(Q.prime(z)) == False - assert ask(Q.composite(z)) == True - assert ask(Q.hermitian(z)) == True - assert ask(Q.antihermitian(z)) == False + assert ask(Q.commutative(z)) is True + assert ask(Q.integer(z)) is True + assert ask(Q.rational(z)) is True + assert ask(Q.real(z)) is True + assert ask(Q.complex(z)) is True + assert ask(Q.irrational(z)) is False + assert ask(Q.imaginary(z)) is False + assert ask(Q.positive(z)) is True + assert ask(Q.negative(z)) is False + assert ask(Q.even(z)) is True + assert ask(Q.odd(z)) is False + assert ask(Q.bounded(z)) is True + assert ask(Q.infinitesimal(z)) is False + assert ask(Q.prime(z)) is False + assert ask(Q.composite(z)) is True + assert ask(Q.hermitian(z)) is True + assert ask(Q.antihermitian(z)) is False + def test_float_1(): z = 1.0 - assert ask(Q.commutative(z)) == True - assert ask(Q.integer(z)) == True - assert ask(Q.rational(z)) == True - assert ask(Q.real(z)) == True - assert ask(Q.complex(z)) == True - assert ask(Q.irrational(z)) == False - assert ask(Q.imaginary(z)) == False - assert ask(Q.positive(z)) == True - assert ask(Q.negative(z)) == False - assert ask(Q.even(z)) == False - assert ask(Q.odd(z)) == True - assert ask(Q.bounded(z)) == True - assert ask(Q.infinitesimal(z)) == False - assert ask(Q.prime(z)) == False - assert ask(Q.composite(z)) == True - assert ask(Q.hermitian(z)) == True - assert ask(Q.antihermitian(z)) == False + assert ask(Q.commutative(z)) is True + assert ask(Q.integer(z)) is True + assert ask(Q.rational(z)) is True + assert ask(Q.real(z)) is True + assert ask(Q.complex(z)) is True + assert ask(Q.irrational(z)) is False + assert ask(Q.imaginary(z)) is False + assert ask(Q.positive(z)) is True + assert ask(Q.negative(z)) is False + assert ask(Q.even(z)) is False + assert ask(Q.odd(z)) is True + assert ask(Q.bounded(z)) is True + assert ask(Q.infinitesimal(z)) is False + assert ask(Q.prime(z)) is False + assert ask(Q.composite(z)) is True + assert ask(Q.hermitian(z)) is True + assert ask(Q.antihermitian(z)) is False z = 7.2123 - assert ask(Q.commutative(z)) == True - assert ask(Q.integer(z)) == False - assert ask(Q.rational(z)) == True - assert ask(Q.real(z)) == True - assert ask(Q.complex(z)) == True - assert ask(Q.irrational(z)) == False - assert ask(Q.imaginary(z)) == False - assert ask(Q.positive(z)) == True - assert ask(Q.negative(z)) == False - assert ask(Q.even(z)) == False - assert ask(Q.odd(z)) == False - assert ask(Q.bounded(z)) == True - assert ask(Q.infinitesimal(z)) == False - assert ask(Q.prime(z)) == False - assert ask(Q.composite(z)) == False - assert ask(Q.hermitian(z)) == True - assert ask(Q.antihermitian(z)) == False + assert ask(Q.commutative(z)) is True + assert ask(Q.integer(z)) is False + assert ask(Q.rational(z)) is True + assert ask(Q.real(z)) is True + assert ask(Q.complex(z)) is True + assert ask(Q.irrational(z)) is False + assert ask(Q.imaginary(z)) is False + assert ask(Q.positive(z)) is True + assert ask(Q.negative(z)) is False + assert ask(Q.even(z)) is False + assert ask(Q.odd(z)) is False + assert ask(Q.bounded(z)) is True + assert ask(Q.infinitesimal(z)) is False + assert ask(Q.prime(z)) is False + assert ask(Q.composite(z)) is False + assert ask(Q.hermitian(z)) is True + assert ask(Q.antihermitian(z)) is False + def test_zero_0(): z = Integer(0) - assert ask(Q.nonzero(z)) == False - assert ask(Q.commutative(z)) == True - assert ask(Q.integer(z)) == True - assert ask(Q.rational(z)) == True - assert ask(Q.real(z)) == True - assert ask(Q.complex(z)) == True - assert ask(Q.imaginary(z)) == False - assert ask(Q.positive(z)) == False - assert ask(Q.negative(z)) == False - assert ask(Q.even(z)) == True - assert ask(Q.odd(z)) == False - assert ask(Q.bounded(z)) == True - assert ask(Q.infinitesimal(z)) == True - assert ask(Q.prime(z)) == False - assert ask(Q.composite(z)) == False - assert ask(Q.hermitian(z)) == True - assert ask(Q.antihermitian(z)) == False + assert ask(Q.nonzero(z)) is False + assert ask(Q.commutative(z)) is True + assert ask(Q.integer(z)) is True + assert ask(Q.rational(z)) is True + assert ask(Q.real(z)) is True + assert ask(Q.complex(z)) is True + assert ask(Q.imaginary(z)) is False + assert ask(Q.positive(z)) is False + assert ask(Q.negative(z)) is False + assert ask(Q.even(z)) is True + assert ask(Q.odd(z)) is False + assert ask(Q.bounded(z)) is True + assert ask(Q.infinitesimal(z)) is True + assert ask(Q.prime(z)) is False + assert ask(Q.composite(z)) is False + assert ask(Q.hermitian(z)) is True + assert ask(Q.antihermitian(z)) is False + def test_negativeone(): z = Integer(-1) - assert ask(Q.nonzero(z)) == True - assert ask(Q.commutative(z)) == True - assert ask(Q.integer(z)) == True - assert ask(Q.rational(z)) == True - assert ask(Q.real(z)) == True - assert ask(Q.complex(z)) == True - assert ask(Q.irrational(z)) == False - assert ask(Q.imaginary(z)) == False - assert ask(Q.positive(z)) == False - assert ask(Q.negative(z)) == True - assert ask(Q.even(z)) == False - assert ask(Q.odd(z)) == True - assert ask(Q.bounded(z)) == True - assert ask(Q.infinitesimal(z)) == False - assert ask(Q.prime(z)) == False - assert ask(Q.composite(z)) == False - assert ask(Q.hermitian(z)) == True - assert ask(Q.antihermitian(z)) == False + assert ask(Q.nonzero(z)) is True + assert ask(Q.commutative(z)) is True + assert ask(Q.integer(z)) is True + assert ask(Q.rational(z)) is True + assert ask(Q.real(z)) is True + assert ask(Q.complex(z)) is True + assert ask(Q.irrational(z)) is False + assert ask(Q.imaginary(z)) is False + assert ask(Q.positive(z)) is False + assert ask(Q.negative(z)) is True + assert ask(Q.even(z)) is False + assert ask(Q.odd(z)) is True + assert ask(Q.bounded(z)) is True + assert ask(Q.infinitesimal(z)) is False + assert ask(Q.prime(z)) is False + assert ask(Q.composite(z)) is False + assert ask(Q.hermitian(z)) is True + assert ask(Q.antihermitian(z)) is False + def test_infinity(): - assert ask(Q.commutative(oo)) == True - assert ask(Q.integer(oo)) == False - assert ask(Q.rational(oo)) == False - assert ask(Q.real(oo)) == False - assert ask(Q.extended_real(oo)) == True - assert ask(Q.complex(oo)) == False - assert ask(Q.irrational(oo)) == False - assert ask(Q.imaginary(oo)) == False - assert ask(Q.positive(oo)) == True - assert ask(Q.negative(oo)) == False - assert ask(Q.even(oo)) == False - assert ask(Q.odd(oo)) == False - assert ask(Q.bounded(oo)) == False - assert ask(Q.infinitesimal(oo)) == False - assert ask(Q.prime(oo)) == False - assert ask(Q.composite(oo)) == False - assert ask(Q.hermitian(oo)) == False - assert ask(Q.antihermitian(oo)) == False + assert ask(Q.commutative(oo)) is True + assert ask(Q.integer(oo)) is False + assert ask(Q.rational(oo)) is False + assert ask(Q.algebraic(oo)) is False + assert ask(Q.real(oo)) is False + assert ask(Q.extended_real(oo)) is True + assert ask(Q.complex(oo)) is False + assert ask(Q.irrational(oo)) is False + assert ask(Q.imaginary(oo)) is False + assert ask(Q.positive(oo)) is True + assert ask(Q.negative(oo)) is False + assert ask(Q.even(oo)) is False + assert ask(Q.odd(oo)) is False + assert ask(Q.bounded(oo)) is False + assert ask(Q.infinitesimal(oo)) is False + assert ask(Q.prime(oo)) is False + assert ask(Q.composite(oo)) is False + assert ask(Q.hermitian(oo)) is False + assert ask(Q.antihermitian(oo)) is False + def test_neg_infinity(): mm = S.NegativeInfinity - assert ask(Q.commutative(mm)) == True - assert ask(Q.integer(mm)) == False - assert ask(Q.rational(mm)) == False - assert ask(Q.real(mm)) == False - assert ask(Q.extended_real(mm)) == True - assert ask(Q.complex(mm)) == False - assert ask(Q.irrational(mm)) == False - assert ask(Q.imaginary(mm)) == False - assert ask(Q.positive(mm)) == False - assert ask(Q.negative(mm)) == True - assert ask(Q.even(mm)) == False - assert ask(Q.odd(mm)) == False - assert ask(Q.bounded(mm)) == False - assert ask(Q.infinitesimal(mm)) == False - assert ask(Q.prime(mm)) == False - assert ask(Q.composite(mm)) == False - assert ask(Q.hermitian(mm)) == False - assert ask(Q.antihermitian(mm)) == False + assert ask(Q.commutative(mm)) is True + assert ask(Q.integer(mm)) is False + assert ask(Q.rational(mm)) is False + assert ask(Q.algebraic(mm)) is False + assert ask(Q.real(mm)) is False + assert ask(Q.extended_real(mm)) is True + assert ask(Q.complex(mm)) is False + assert ask(Q.irrational(mm)) is False + assert ask(Q.imaginary(mm)) is False + assert ask(Q.positive(mm)) is False + assert ask(Q.negative(mm)) is True + assert ask(Q.even(mm)) is False + assert ask(Q.odd(mm)) is False + assert ask(Q.bounded(mm)) is False + assert ask(Q.infinitesimal(mm)) is False + assert ask(Q.prime(mm)) is False + assert ask(Q.composite(mm)) is False + assert ask(Q.hermitian(mm)) is False + assert ask(Q.antihermitian(mm)) is False + def test_nan(): nan = S.NaN - assert ask(Q.commutative(nan)) == True - assert ask(Q.integer(nan)) == False - assert ask(Q.rational(nan)) == False - assert ask(Q.real(nan)) == False - assert ask(Q.extended_real(nan)) == False - assert ask(Q.complex(nan)) == False - assert ask(Q.irrational(nan)) == False - assert ask(Q.imaginary(nan)) == False - assert ask(Q.positive(nan)) == False - assert ask(Q.nonzero(nan)) == True - assert ask(Q.even(nan)) == False - assert ask(Q.odd(nan)) == False - assert ask(Q.bounded(nan)) == False - assert ask(Q.infinitesimal(nan)) == False - assert ask(Q.prime(nan)) == False - assert ask(Q.composite(nan)) == False - assert ask(Q.hermitian(nan)) == False - assert ask(Q.antihermitian(nan)) == False + assert ask(Q.commutative(nan)) is True + assert ask(Q.integer(nan)) is False + assert ask(Q.rational(nan)) is False + assert ask(Q.algebraic(nan)) is False + assert ask(Q.real(nan)) is False + assert ask(Q.extended_real(nan)) is False + assert ask(Q.complex(nan)) is False + assert ask(Q.irrational(nan)) is False + assert ask(Q.imaginary(nan)) is False + assert ask(Q.positive(nan)) is False + assert ask(Q.nonzero(nan)) is True + assert ask(Q.even(nan)) is False + assert ask(Q.odd(nan)) is False + assert ask(Q.bounded(nan)) is False + assert ask(Q.infinitesimal(nan)) is False + assert ask(Q.prime(nan)) is False + assert ask(Q.composite(nan)) is False + assert ask(Q.hermitian(nan)) is False + assert ask(Q.antihermitian(nan)) is False + def test_Rational_number(): - r = Rational(3,4) - assert ask(Q.commutative(r)) == True - assert ask(Q.integer(r)) == False - assert ask(Q.rational(r)) == True - assert ask(Q.real(r)) == True - assert ask(Q.complex(r)) == True - assert ask(Q.irrational(r)) == False - assert ask(Q.imaginary(r)) == False - assert ask(Q.positive(r)) == True - assert ask(Q.negative(r)) == False - assert ask(Q.even(r)) == False - assert ask(Q.odd(r)) == False - assert ask(Q.bounded(r)) == True - assert ask(Q.infinitesimal(r)) == False - assert ask(Q.prime(r)) == False - assert ask(Q.composite(r)) == False - assert ask(Q.hermitian(r)) == True - assert ask(Q.antihermitian(r)) == False - - r = Rational(1,4) - assert ask(Q.positive(r)) == True - assert ask(Q.negative(r)) == False - - r = Rational(5,4) - assert ask(Q.negative(r)) == False - assert ask(Q.positive(r)) == True - - r = Rational(5,3) - assert ask(Q.positive(r)) == True - assert ask(Q.negative(r)) == False - - r = Rational(-3,4) - assert ask(Q.positive(r)) == False - assert ask(Q.negative(r)) == True - - r = Rational(-1,4) - assert ask(Q.positive(r)) == False - assert ask(Q.negative(r)) == True - - r = Rational(-5,4) - assert ask(Q.negative(r)) == True - assert ask(Q.positive(r)) == False - - r = Rational(-5,3) - assert ask(Q.positive(r)) == False - assert ask(Q.negative(r)) == True + r = Rational(3, 4) + assert ask(Q.commutative(r)) is True + assert ask(Q.integer(r)) is False + assert ask(Q.rational(r)) is True + assert ask(Q.real(r)) is True + assert ask(Q.complex(r)) is True + assert ask(Q.irrational(r)) is False + assert ask(Q.imaginary(r)) is False + assert ask(Q.positive(r)) is True + assert ask(Q.negative(r)) is False + assert ask(Q.even(r)) is False + assert ask(Q.odd(r)) is False + assert ask(Q.bounded(r)) is True + assert ask(Q.infinitesimal(r)) is False + assert ask(Q.prime(r)) is False + assert ask(Q.composite(r)) is False + assert ask(Q.hermitian(r)) is True + assert ask(Q.antihermitian(r)) is False + + r = Rational(1, 4) + assert ask(Q.positive(r)) is True + assert ask(Q.negative(r)) is False + + r = Rational(5, 4) + assert ask(Q.negative(r)) is False + assert ask(Q.positive(r)) is True + + r = Rational(5, 3) + assert ask(Q.positive(r)) is True + assert ask(Q.negative(r)) is False + + r = Rational(-3, 4) + assert ask(Q.positive(r)) is False + assert ask(Q.negative(r)) is True + + r = Rational(-1, 4) + assert ask(Q.positive(r)) is False + assert ask(Q.negative(r)) is True + + r = Rational(-5, 4) + assert ask(Q.negative(r)) is True + assert ask(Q.positive(r)) is False + + r = Rational(-5, 3) + assert ask(Q.positive(r)) is False + assert ask(Q.negative(r)) is True + def test_sqrt_2(): z = sqrt(2) - assert ask(Q.commutative(z)) == True - assert ask(Q.integer(z)) == False - assert ask(Q.rational(z)) == False - assert ask(Q.real(z)) == True - assert ask(Q.complex(z)) == True - assert ask(Q.irrational(z)) == True - assert ask(Q.imaginary(z)) == False - assert ask(Q.positive(z)) == True - assert ask(Q.negative(z)) == False - assert ask(Q.even(z)) == False - assert ask(Q.odd(z)) == False - assert ask(Q.bounded(z)) == True - assert ask(Q.infinitesimal(z)) == False - assert ask(Q.prime(z)) == False - assert ask(Q.composite(z)) == False - assert ask(Q.hermitian(z)) == True - assert ask(Q.antihermitian(z)) == False + assert ask(Q.commutative(z)) is True + assert ask(Q.integer(z)) is False + assert ask(Q.rational(z)) is False + assert ask(Q.real(z)) is True + assert ask(Q.complex(z)) is True + assert ask(Q.irrational(z)) is True + assert ask(Q.imaginary(z)) is False + assert ask(Q.positive(z)) is True + assert ask(Q.negative(z)) is False + assert ask(Q.even(z)) is False + assert ask(Q.odd(z)) is False + assert ask(Q.bounded(z)) is True + assert ask(Q.infinitesimal(z)) is False + assert ask(Q.prime(z)) is False + assert ask(Q.composite(z)) is False + assert ask(Q.hermitian(z)) is True + assert ask(Q.antihermitian(z)) is False + def test_pi(): z = S.Pi - assert ask(Q.commutative(z)) == True - assert ask(Q.integer(z)) == False - assert ask(Q.rational(z)) == False - assert ask(Q.real(z)) == True - assert ask(Q.complex(z)) == True - assert ask(Q.irrational(z)) == True - assert ask(Q.imaginary(z)) == False - assert ask(Q.positive(z)) == True - assert ask(Q.negative(z)) == False - assert ask(Q.even(z)) == False - assert ask(Q.odd(z)) == False - assert ask(Q.bounded(z)) == True - assert ask(Q.infinitesimal(z)) == False - assert ask(Q.prime(z)) == False - assert ask(Q.composite(z)) == False - assert ask(Q.hermitian(z)) == True - assert ask(Q.antihermitian(z)) == False + assert ask(Q.commutative(z)) is True + assert ask(Q.integer(z)) is False + assert ask(Q.rational(z)) is False + assert ask(Q.algebraic(z)) is False + assert ask(Q.real(z)) is True + assert ask(Q.complex(z)) is True + assert ask(Q.irrational(z)) is True + assert ask(Q.imaginary(z)) is False + assert ask(Q.positive(z)) is True + assert ask(Q.negative(z)) is False + assert ask(Q.even(z)) is False + assert ask(Q.odd(z)) is False + assert ask(Q.bounded(z)) is True + assert ask(Q.infinitesimal(z)) is False + assert ask(Q.prime(z)) is False + assert ask(Q.composite(z)) is False + assert ask(Q.hermitian(z)) is True + assert ask(Q.antihermitian(z)) is False z = S.Pi + 1 - assert ask(Q.commutative(z)) == True - assert ask(Q.integer(z)) == False - assert ask(Q.rational(z)) == False - assert ask(Q.real(z)) == True - assert ask(Q.complex(z)) == True - assert ask(Q.irrational(z)) == True - assert ask(Q.imaginary(z)) == False - assert ask(Q.positive(z)) == True - assert ask(Q.negative(z)) == False - assert ask(Q.even(z)) == False - assert ask(Q.odd(z)) == False - assert ask(Q.bounded(z)) == True - assert ask(Q.infinitesimal(z)) == False - assert ask(Q.prime(z)) == False - assert ask(Q.composite(z)) == False - assert ask(Q.hermitian(z)) == True - assert ask(Q.antihermitian(z)) == False + assert ask(Q.commutative(z)) is True + assert ask(Q.integer(z)) is False + assert ask(Q.rational(z)) is False + assert ask(Q.algebraic(z)) is False + assert ask(Q.real(z)) is True + assert ask(Q.complex(z)) is True + assert ask(Q.irrational(z)) is True + assert ask(Q.imaginary(z)) is False + assert ask(Q.positive(z)) is True + assert ask(Q.negative(z)) is False + assert ask(Q.even(z)) is False + assert ask(Q.odd(z)) is False + assert ask(Q.bounded(z)) is True + assert ask(Q.infinitesimal(z)) is False + assert ask(Q.prime(z)) is False + assert ask(Q.composite(z)) is False + assert ask(Q.hermitian(z)) is True + assert ask(Q.antihermitian(z)) is False z = 2*S.Pi - assert ask(Q.commutative(z)) == True - assert ask(Q.integer(z)) == False - assert ask(Q.rational(z)) == False - assert ask(Q.real(z)) == True - assert ask(Q.complex(z)) == True - assert ask(Q.irrational(z)) == True - assert ask(Q.imaginary(z)) == False - assert ask(Q.positive(z)) == True - assert ask(Q.negative(z)) == False - assert ask(Q.even(z)) == False - assert ask(Q.odd(z)) == False - assert ask(Q.bounded(z)) == True - assert ask(Q.infinitesimal(z)) == False - assert ask(Q.prime(z)) == False - assert ask(Q.composite(z)) == False - assert ask(Q.hermitian(z)) == True - assert ask(Q.antihermitian(z)) == False + assert ask(Q.commutative(z)) is True + assert ask(Q.integer(z)) is False + assert ask(Q.rational(z)) is False + assert ask(Q.algebraic(z)) is False + assert ask(Q.real(z)) is True + assert ask(Q.complex(z)) is True + assert ask(Q.irrational(z)) is True + assert ask(Q.imaginary(z)) is False + assert ask(Q.positive(z)) is True + assert ask(Q.negative(z)) is False + assert ask(Q.even(z)) is False + assert ask(Q.odd(z)) is False + assert ask(Q.bounded(z)) is True + assert ask(Q.infinitesimal(z)) is False + assert ask(Q.prime(z)) is False + assert ask(Q.composite(z)) is False + assert ask(Q.hermitian(z)) is True + assert ask(Q.antihermitian(z)) is False z = S.Pi ** 2 - assert ask(Q.commutative(z)) == True - assert ask(Q.integer(z)) == False - assert ask(Q.rational(z)) == False - assert ask(Q.real(z)) == True - assert ask(Q.complex(z)) == True - assert ask(Q.irrational(z)) == True - assert ask(Q.imaginary(z)) == False - assert ask(Q.positive(z)) == True - assert ask(Q.negative(z)) == False - assert ask(Q.even(z)) == False - assert ask(Q.odd(z)) == False - assert ask(Q.bounded(z)) == True - assert ask(Q.infinitesimal(z)) == False - assert ask(Q.prime(z)) == False - assert ask(Q.composite(z)) == False - assert ask(Q.hermitian(z)) == True - assert ask(Q.antihermitian(z)) == False - - z = (1+S.Pi) ** 2 - assert ask(Q.commutative(z)) == True - assert ask(Q.integer(z)) == False - assert ask(Q.rational(z)) == False - assert ask(Q.real(z)) == True - assert ask(Q.complex(z)) == True - assert ask(Q.irrational(z)) == True - assert ask(Q.imaginary(z)) == False - assert ask(Q.positive(z)) == True - assert ask(Q.negative(z)) == False - assert ask(Q.even(z)) == False - assert ask(Q.odd(z)) == False - assert ask(Q.bounded(z)) == True - assert ask(Q.infinitesimal(z)) == False - assert ask(Q.prime(z)) == False - assert ask(Q.composite(z)) == False - assert ask(Q.hermitian(z)) == True - assert ask(Q.antihermitian(z)) == False + assert ask(Q.commutative(z)) is True + assert ask(Q.integer(z)) is False + assert ask(Q.rational(z)) is False + assert ask(Q.algebraic(z)) is False + assert ask(Q.real(z)) is True + assert ask(Q.complex(z)) is True + assert ask(Q.irrational(z)) is True + assert ask(Q.imaginary(z)) is False + assert ask(Q.positive(z)) is True + assert ask(Q.negative(z)) is False + assert ask(Q.even(z)) is False + assert ask(Q.odd(z)) is False + assert ask(Q.bounded(z)) is True + assert ask(Q.infinitesimal(z)) is False + assert ask(Q.prime(z)) is False + assert ask(Q.composite(z)) is False + assert ask(Q.hermitian(z)) is True + assert ask(Q.antihermitian(z)) is False + + z = (1 + S.Pi) ** 2 + assert ask(Q.commutative(z)) is True + assert ask(Q.integer(z)) is False + assert ask(Q.rational(z)) is False + assert ask(Q.algebraic(z)) is False + assert ask(Q.real(z)) is True + assert ask(Q.complex(z)) is True + assert ask(Q.irrational(z)) is True + assert ask(Q.imaginary(z)) is False + assert ask(Q.positive(z)) is True + assert ask(Q.negative(z)) is False + assert ask(Q.even(z)) is False + assert ask(Q.odd(z)) is False + assert ask(Q.bounded(z)) is True + assert ask(Q.infinitesimal(z)) is False + assert ask(Q.prime(z)) is False + assert ask(Q.composite(z)) is False + assert ask(Q.hermitian(z)) is True + assert ask(Q.antihermitian(z)) is False + def test_E(): z = S.Exp1 - assert ask(Q.commutative(z)) == True - assert ask(Q.integer(z)) == False - assert ask(Q.rational(z)) == False - assert ask(Q.real(z)) == True - assert ask(Q.complex(z)) == True - assert ask(Q.irrational(z)) == True - assert ask(Q.imaginary(z)) == False - assert ask(Q.positive(z)) == True - assert ask(Q.negative(z)) == False - assert ask(Q.even(z)) == False - assert ask(Q.odd(z)) == False - assert ask(Q.bounded(z)) == True - assert ask(Q.infinitesimal(z)) == False - assert ask(Q.prime(z)) == False - assert ask(Q.composite(z)) == False - assert ask(Q.hermitian(z)) == True - assert ask(Q.antihermitian(z)) == False + assert ask(Q.commutative(z)) is True + assert ask(Q.integer(z)) is False + assert ask(Q.rational(z)) is False + assert ask(Q.algebraic(z)) is False + assert ask(Q.real(z)) is True + assert ask(Q.complex(z)) is True + assert ask(Q.irrational(z)) is True + assert ask(Q.imaginary(z)) is False + assert ask(Q.positive(z)) is True + assert ask(Q.negative(z)) is False + assert ask(Q.even(z)) is False + assert ask(Q.odd(z)) is False + assert ask(Q.bounded(z)) is True + assert ask(Q.infinitesimal(z)) is False + assert ask(Q.prime(z)) is False + assert ask(Q.composite(z)) is False + assert ask(Q.hermitian(z)) is True + assert ask(Q.antihermitian(z)) is False + + +def test_GoldenRatio(): + z = S.GoldenRatio + assert ask(Q.commutative(z)) is True + assert ask(Q.integer(z)) is False + assert ask(Q.rational(z)) is False + assert ask(Q.algebraic(z)) is True + assert ask(Q.real(z)) is True + assert ask(Q.complex(z)) is True + assert ask(Q.irrational(z)) is True + assert ask(Q.imaginary(z)) is False + assert ask(Q.positive(z)) is True + assert ask(Q.negative(z)) is False + assert ask(Q.even(z)) is False + assert ask(Q.odd(z)) is False + assert ask(Q.bounded(z)) is True + assert ask(Q.infinitesimal(z)) is False + assert ask(Q.prime(z)) is False + assert ask(Q.composite(z)) is False + assert ask(Q.hermitian(z)) is True + assert ask(Q.antihermitian(z)) is False + def test_I(): z = I - assert ask(Q.commutative(z)) == True - assert ask(Q.integer(z)) == False - assert ask(Q.rational(z)) == False - assert ask(Q.real(z)) == False - assert ask(Q.complex(z)) == True - assert ask(Q.irrational(z)) == False - assert ask(Q.imaginary(z)) == True - assert ask(Q.positive(z)) == False - assert ask(Q.negative(z)) == False - assert ask(Q.even(z)) == False - assert ask(Q.odd(z)) == False - assert ask(Q.bounded(z)) == True - assert ask(Q.infinitesimal(z)) == False - assert ask(Q.prime(z)) == False - assert ask(Q.composite(z)) == False - assert ask(Q.hermitian(z)) == False - assert ask(Q.antihermitian(z)) == True + assert ask(Q.commutative(z)) is True + assert ask(Q.integer(z)) is False + assert ask(Q.rational(z)) is False + assert ask(Q.algebraic(z)) is True + assert ask(Q.real(z)) is False + assert ask(Q.complex(z)) is True + assert ask(Q.irrational(z)) is False + assert ask(Q.imaginary(z)) is True + assert ask(Q.positive(z)) is False + assert ask(Q.negative(z)) is False + assert ask(Q.even(z)) is False + assert ask(Q.odd(z)) is False + assert ask(Q.bounded(z)) is True + assert ask(Q.infinitesimal(z)) is False + assert ask(Q.prime(z)) is False + assert ask(Q.composite(z)) is False + assert ask(Q.hermitian(z)) is False + assert ask(Q.antihermitian(z)) is True z = 1 + I - assert ask(Q.commutative(z)) == True - assert ask(Q.integer(z)) == False - assert ask(Q.rational(z)) == False - assert ask(Q.real(z)) == False - assert ask(Q.complex(z)) == True - assert ask(Q.irrational(z)) == False - assert ask(Q.imaginary(z)) == False - assert ask(Q.positive(z)) == False - assert ask(Q.negative(z)) == False - assert ask(Q.even(z)) == False - assert ask(Q.odd(z)) == False - assert ask(Q.bounded(z)) == True - assert ask(Q.infinitesimal(z)) == False - assert ask(Q.prime(z)) == False - assert ask(Q.composite(z)) == False - assert ask(Q.hermitian(z)) == False - assert ask(Q.antihermitian(z)) == False - - z = I*(1+I) - assert ask(Q.commutative(z)) == True - assert ask(Q.integer(z)) == False - assert ask(Q.rational(z)) == False - assert ask(Q.real(z)) == False - assert ask(Q.complex(z)) == True - assert ask(Q.irrational(z)) == False - assert ask(Q.imaginary(z)) == False - assert ask(Q.positive(z)) == False - assert ask(Q.negative(z)) == False - assert ask(Q.even(z)) == False - assert ask(Q.odd(z)) == False - assert ask(Q.bounded(z)) == True - assert ask(Q.infinitesimal(z)) == False - assert ask(Q.prime(z)) == False - assert ask(Q.composite(z)) == False - assert ask(Q.hermitian(z)) == False - assert ask(Q.antihermitian(z)) == False + assert ask(Q.commutative(z)) is True + assert ask(Q.integer(z)) is False + assert ask(Q.rational(z)) is False + assert ask(Q.algebraic(z)) is True + assert ask(Q.real(z)) is False + assert ask(Q.complex(z)) is True + assert ask(Q.irrational(z)) is False + assert ask(Q.imaginary(z)) is False + assert ask(Q.positive(z)) is False + assert ask(Q.negative(z)) is False + assert ask(Q.even(z)) is False + assert ask(Q.odd(z)) is False + assert ask(Q.bounded(z)) is True + assert ask(Q.infinitesimal(z)) is False + assert ask(Q.prime(z)) is False + assert ask(Q.composite(z)) is False + assert ask(Q.hermitian(z)) is False + assert ask(Q.antihermitian(z)) is False + + z = I*(1 + I) + assert ask(Q.commutative(z)) is True + assert ask(Q.integer(z)) is False + assert ask(Q.rational(z)) is False + assert ask(Q.algebraic(z)) is True + assert ask(Q.real(z)) is False + assert ask(Q.complex(z)) is True + assert ask(Q.irrational(z)) is False + assert ask(Q.imaginary(z)) is False + assert ask(Q.positive(z)) is False + assert ask(Q.negative(z)) is False + assert ask(Q.even(z)) is False + assert ask(Q.odd(z)) is False + assert ask(Q.bounded(z)) is True + assert ask(Q.infinitesimal(z)) is False + assert ask(Q.prime(z)) is False + assert ask(Q.composite(z)) is False + assert ask(Q.hermitian(z)) is False + assert ask(Q.antihermitian(z)) is False + + z = I**(I) + assert ask(Q.imaginary(z)) is False + assert ask(Q.real(z)) is True + + z = (-I)**(I) + assert ask(Q.imaginary(z)) is False + assert ask(Q.real(z)) is True + + z = (3*I)**(I) + assert ask(Q.imaginary(z)) is False + assert ask(Q.real(z)) is False + + z = (1)**(I) + assert ask(Q.imaginary(z)) is False + assert ask(Q.real(z)) is True + + z = (-1)**(I) + assert ask(Q.imaginary(z)) is False + assert ask(Q.real(z)) is True + + z = (1+I)**(I) + assert ask(Q.imaginary(z)) is False + assert ask(Q.real(z)) is False + + z = (I)**(I+3) + assert ask(Q.imaginary(z)) is True + assert ask(Q.real(z)) is False + + z = (I)**(I+2) + assert ask(Q.imaginary(z)) is False + assert ask(Q.real(z)) is True + + z = (I)**(2) + assert ask(Q.imaginary(z)) is False + assert ask(Q.real(z)) is True + + z = (I)**(3) + assert ask(Q.imaginary(z)) is True + assert ask(Q.real(z)) is False + + z = (3)**(I) + assert ask(Q.imaginary(z)) is False + assert ask(Q.real(z)) is False + + z = (I)**(0) + assert ask(Q.imaginary(z)) is False + assert ask(Q.real(z)) is True + @slow def test_bounded(): x, y, z = symbols('x,y,z') - assert ask(Q.bounded(x)) == None - assert ask(Q.bounded(x), Q.bounded(x)) == True - assert ask(Q.bounded(x), Q.bounded(y)) == None - assert ask(Q.bounded(x), Q.complex(x)) == None + assert ask(Q.bounded(x)) is None + assert ask(Q.bounded(x), Q.bounded(x)) is True + assert ask(Q.bounded(x), Q.bounded(y)) is None + assert ask(Q.bounded(x), Q.complex(x)) is None - assert ask(Q.bounded(x+1)) == None - assert ask(Q.bounded(x+1), Q.bounded(x)) == True + assert ask(Q.bounded(x + 1)) is None + assert ask(Q.bounded(x + 1), Q.bounded(x)) is True a = x + y x, y = a.args # B + B - assert ask(Q.bounded(a), Q.bounded(x) & Q.bounded(y)) == True - assert ask(Q.bounded(a), Q.bounded(x) & Q.bounded(y) & Q.positive(x)) == True - assert ask(Q.bounded(a), Q.bounded(x) & Q.bounded(y) & Q.positive(y)) == True - assert ask(Q.bounded(a), Q.bounded(x) & Q.bounded(y) & Q.positive(x) & Q.positive(y)) == True - assert ask(Q.bounded(a), Q.bounded(x) & Q.bounded(y) & Q.positive(x) & ~Q.positive(y)) == True - assert ask(Q.bounded(a), Q.bounded(x) & Q.bounded(y) & ~Q.positive(x) & Q.positive(y)) == True - assert ask(Q.bounded(a), Q.bounded(x) & Q.bounded(y) & ~Q.positive(x) & ~Q.positive(y)) == True + assert ask(Q.bounded(a), Q.bounded(x) & Q.bounded(y)) is True + assert ask( + Q.bounded(a), Q.bounded(x) & Q.bounded(y) & Q.positive(x)) is True + assert ask( + Q.bounded(a), Q.bounded(x) & Q.bounded(y) & Q.positive(y)) is True + assert ask(Q.bounded(a), + Q.bounded(x) & Q.bounded(y) & Q.positive(x) & Q.positive(y)) is True + assert ask(Q.bounded(a), + Q.bounded(x) & Q.bounded(y) & Q.positive(x) & ~Q.positive(y)) is True + assert ask(Q.bounded(a), + Q.bounded(x) & Q.bounded(y) & ~Q.positive(x) & Q.positive(y)) is True + assert ask(Q.bounded(a), + Q.bounded(x) & Q.bounded(y) & ~Q.positive(x) & ~Q.positive(y)) is True # B + U - assert ask(Q.bounded(a), Q.bounded(x) & ~Q.bounded(y)) == False - assert ask(Q.bounded(a), Q.bounded(x) & ~Q.bounded(y) & Q.positive(x)) == False - assert ask(Q.bounded(a), Q.bounded(x) & ~Q.bounded(y) & Q.positive(y)) == False - assert ask(Q.bounded(a), Q.bounded(x) & ~Q.bounded(y) & Q.positive(x) & Q.positive(y)) == False - assert ask(Q.bounded(a), Q.bounded(x) & ~Q.bounded(y) & Q.positive(x) & ~Q.positive(y)) == False - assert ask(Q.bounded(a), Q.bounded(x) & ~Q.bounded(y) & ~Q.positive(x) & Q.positive(y)) == False - assert ask(Q.bounded(a), Q.bounded(x) & ~Q.bounded(y) & ~Q.positive(x) & ~Q.positive(y)) == False + assert ask(Q.bounded(a), Q.bounded(x) & ~Q.bounded(y)) is False + assert ask( + Q.bounded(a), Q.bounded(x) & ~Q.bounded(y) & Q.positive(x)) is False + assert ask( + Q.bounded(a), Q.bounded(x) & ~Q.bounded(y) & Q.positive(y)) is False + assert ask(Q.bounded(a), Q.bounded(x) & ~Q.bounded(y) & Q.positive(x) & + Q.positive(y)) is False + assert ask(Q.bounded(a), Q.bounded(x) & ~Q.bounded(y) & Q.positive(x) & + ~Q.positive(y)) is False + assert ask(Q.bounded(a), Q.bounded(x) & ~Q.bounded(y) & ~Q.positive(x) & + Q.positive(y)) is False + assert ask(Q.bounded(a), Q.bounded(x) & ~Q.bounded(y) & ~Q.positive(x) & + ~Q.positive(y)) is False # B + ? - assert ask(Q.bounded(a), Q.bounded(x)) == None - assert ask(Q.bounded(a), Q.bounded(x) & Q.positive(x)) == None - assert ask(Q.bounded(a), Q.bounded(x) & Q.positive(y)) == None - assert ask(Q.bounded(a), Q.bounded(x) & Q.positive(x) & Q.positive(y)) == None - assert ask(Q.bounded(a), Q.bounded(x) & Q.positive(x) & ~Q.positive(y)) == None - assert ask(Q.bounded(a), Q.bounded(x) & ~Q.positive(x) & Q.positive(y)) == None - assert ask(Q.bounded(a), Q.bounded(x) & ~Q.positive(x) & ~Q.positive(y)) == None + assert ask(Q.bounded(a), Q.bounded(x)) is None + assert ask(Q.bounded(a), Q.bounded(x) & Q.positive(x)) is None + assert ask(Q.bounded(a), Q.bounded(x) & Q.positive(y)) is None + assert ask( + Q.bounded(a), Q.bounded(x) & Q.positive(x) & Q.positive(y)) is None + assert ask( + Q.bounded(a), Q.bounded(x) & Q.positive(x) & ~Q.positive(y)) is None + assert ask( + Q.bounded(a), Q.bounded(x) & ~Q.positive(x) & Q.positive(y)) is None + assert ask( + Q.bounded(a), Q.bounded(x) & ~Q.positive(x) & ~Q.positive(y)) is None # U + U - assert ask(Q.bounded(a), ~Q.bounded(x) & ~Q.bounded(y)) == None - assert ask(Q.bounded(a), ~Q.bounded(x) & ~Q.bounded(y) & Q.positive(x)) == None - assert ask(Q.bounded(a), ~Q.bounded(x) & ~Q.bounded(y) & Q.positive(y)) == None - assert ask(Q.bounded(a), ~Q.bounded(x) & ~Q.bounded(y) & Q.positive(x) & Q.positive(y)) == False - assert ask(Q.bounded(a), ~Q.bounded(x) & ~Q.bounded(y) & Q.positive(x) & ~Q.positive(y)) == None - assert ask(Q.bounded(a), ~Q.bounded(x) & ~Q.bounded(y) & ~Q.positive(x) & Q.positive(y)) == None - assert ask(Q.bounded(a), ~Q.bounded(x) & ~Q.bounded(y) & ~Q.positive(x) & ~Q.positive(y)) == False + assert ask(Q.bounded(a), ~Q.bounded(x) & ~Q.bounded(y)) is None + assert ask( + Q.bounded(a), ~Q.bounded(x) & ~Q.bounded(y) & Q.positive(x)) is None + assert ask( + Q.bounded(a), ~Q.bounded(x) & ~Q.bounded(y) & Q.positive(y)) is None + assert ask(Q.bounded(a), ~Q.bounded(x) & ~Q.bounded(y) & Q.positive(x) & + Q.positive(y)) is False + assert ask(Q.bounded(a), ~Q.bounded(x) & ~Q.bounded(y) & Q.positive(x) & + ~Q.positive(y)) is None + assert ask(Q.bounded(a), ~Q.bounded(x) & ~Q.bounded(y) & ~Q.positive(x) & + Q.positive(y)) is None + assert ask(Q.bounded(a), ~Q.bounded(x) & ~Q.bounded(y) & ~Q.positive(x) & + ~Q.positive(y)) is False # U + ? - assert ask(Q.bounded(a), ~Q.bounded(y)) == None - assert ask(Q.bounded(a), ~Q.bounded(y) & Q.positive(x)) == None - assert ask(Q.bounded(a), ~Q.bounded(y) & Q.positive(y)) == None - assert ask(Q.bounded(a), ~Q.bounded(y) & Q.positive(x) & Q.positive(y)) == False - assert ask(Q.bounded(a), ~Q.bounded(y) & Q.positive(x) & ~Q.positive(y)) == None - assert ask(Q.bounded(a), ~Q.bounded(y) & ~Q.positive(x) & Q.positive(y)) == None - assert ask(Q.bounded(a), ~Q.bounded(y) & ~Q.positive(x) & ~Q.positive(y)) == False + assert ask(Q.bounded(a), ~Q.bounded(y)) is None + assert ask(Q.bounded(a), ~Q.bounded(y) & Q.positive(x)) is None + assert ask(Q.bounded(a), ~Q.bounded(y) & Q.positive(y)) is None + assert ask( + Q.bounded(a), ~Q.bounded(y) & Q.positive(x) & Q.positive(y)) is False + assert ask( + Q.bounded(a), ~Q.bounded(y) & Q.positive(x) & ~Q.positive(y)) is None + assert ask( + Q.bounded(a), ~Q.bounded(y) & ~Q.positive(x) & Q.positive(y)) is None + assert ask( + Q.bounded(a), ~Q.bounded(y) & ~Q.positive(x) & ~Q.positive(y)) is False # ? + ? - assert ask(Q.bounded(a),) == None - assert ask(Q.bounded(a),Q.positive(x)) == None - assert ask(Q.bounded(a),Q.positive(y)) == None - assert ask(Q.bounded(a),Q.positive(x) & Q.positive(y)) == None - assert ask(Q.bounded(a),Q.positive(x) & ~Q.positive(y)) == None - assert ask(Q.bounded(a),~Q.positive(x) & Q.positive(y)) == None - assert ask(Q.bounded(a),~Q.positive(x) & ~Q.positive(y)) == None + assert ask(Q.bounded(a),) is None + assert ask(Q.bounded(a), Q.positive(x)) is None + assert ask(Q.bounded(a), Q.positive(y)) is None + assert ask(Q.bounded(a), Q.positive(x) & Q.positive(y)) is None + assert ask(Q.bounded(a), Q.positive(x) & ~Q.positive(y)) is None + assert ask(Q.bounded(a), ~Q.positive(x) & Q.positive(y)) is None + assert ask(Q.bounded(a), ~Q.positive(x) & ~Q.positive(y)) is None a = x + y + z x, y, z = a.args - assert ask(Q.bounded(a), Q.negative(x) & Q.bounded(x) & Q.negative(y) & Q.bounded(y) & Q.negative(z) & Q.bounded(z)) == True - assert ask(Q.bounded(a), Q.negative(x) & Q.bounded(x) & Q.negative(y) & Q.bounded(y) & Q.bounded(z)) == True - assert ask(Q.bounded(a), Q.negative(x) & Q.bounded(x) & Q.negative(y) & Q.bounded(y) & Q.positive(z) & Q.bounded(z)) == True - assert ask(Q.bounded(a), Q.negative(x) & Q.bounded(x) & Q.negative(y) & Q.bounded(y) & Q.negative(z) & ~Q.bounded(z)) == False - assert ask(Q.bounded(a), Q.negative(x) & Q.bounded(x) & Q.negative(y) & Q.bounded(y) & ~Q.bounded(z)) == False - assert ask(Q.bounded(a), Q.negative(x) & Q.bounded(x) & Q.negative(y) & Q.bounded(y) & Q.positive(z) & ~Q.bounded(z)) == False - assert ask(Q.bounded(a), Q.negative(x) & Q.bounded(x) & Q.negative(y) & Q.bounded(y) & Q.negative(z)) == None - assert ask(Q.bounded(a), Q.negative(x) & Q.bounded(x) & Q.negative(y) & Q.bounded(y)) == None - assert ask(Q.bounded(a), Q.negative(x) & Q.bounded(x) & Q.negative(y) & Q.bounded(y) & Q.positive(z)) == None - assert ask(Q.bounded(a), Q.negative(x) & Q.bounded(x) & Q.bounded(y) & Q.bounded(z)) == True - assert ask(Q.bounded(a), Q.negative(x) & Q.bounded(x) & Q.bounded(y) & Q.positive(z) & Q.bounded(z)) == True - assert ask(Q.bounded(a), Q.negative(x) & Q.bounded(x) & Q.bounded(y) & Q.negative(z) & ~Q.bounded(z)) == False - assert ask(Q.bounded(a), Q.negative(x) & Q.bounded(x) & Q.bounded(y) & ~Q.bounded(z))== False - assert ask(Q.bounded(a), Q.negative(x) & Q.bounded(x) & Q.bounded(y) & Q.positive(z) & ~Q.bounded(z)) == False - assert ask(Q.bounded(a), Q.negative(x) & Q.bounded(x) & Q.bounded(y) & Q.negative(z))== None - assert ask(Q.bounded(a), Q.negative(x) & Q.bounded(x) & Q.bounded(y)) == None - assert ask(Q.bounded(a), Q.negative(x) & Q.bounded(x) & Q.bounded(y) & Q.positive(z)) == None - assert ask(Q.bounded(a), Q.negative(x) & Q.bounded(x) & Q.positive(y) & Q.bounded(y) & Q.positive(z) & Q.bounded(z)) == True - assert ask(Q.bounded(a), Q.negative(x) & Q.bounded(x) & Q.positive(y) & Q.bounded(y) & Q.negative(z) & ~Q.bounded(z)) == False - assert ask(Q.bounded(a), Q.negative(x) & Q.bounded(x) & Q.positive(y) & Q.bounded(y) & ~Q.bounded(z)) == False - assert ask(Q.bounded(a), Q.negative(x) & Q.bounded(x) & Q.positive(y) & Q.bounded(y) & Q.positive(z) & ~Q.bounded(z)) == False - assert ask(Q.bounded(a), Q.negative(x) & Q.bounded(x) & Q.positive(y) & Q.bounded(y) & Q.negative(z)) == None - assert ask(Q.bounded(a), Q.negative(x) & Q.bounded(x) & Q.positive(y) & Q.bounded(y)) == None - assert ask(Q.bounded(a), Q.negative(x) & Q.bounded(x) & Q.positive(y) & Q.bounded(y) & Q.positive(z)) == None - assert ask(Q.bounded(a), Q.negative(x) & Q.bounded(x) & Q.negative(y) & ~Q.bounded(y) & Q.negative(z) & ~Q.bounded(z)) == False - assert ask(Q.bounded(a), Q.negative(x) & Q.bounded(x) & Q.negative(y) & ~Q.bounded(y) & ~Q.bounded(z)) == None - assert ask(Q.bounded(a), Q.negative(x) & Q.bounded(x) & Q.negative(y) & ~Q.bounded(y) & Q.positive(z) & ~Q.bounded(z)) == None - assert ask(Q.bounded(a), Q.negative(x) & Q.bounded(x) & Q.negative(y) & ~Q.bounded(y) & Q.negative(z)) == False - assert ask(Q.bounded(a), Q.negative(x) & Q.bounded(x) & Q.negative(y) & ~Q.bounded(y)) == None - assert ask(Q.bounded(a), Q.negative(x) & Q.bounded(x) & Q.negative(y) & ~Q.bounded(y) & Q.positive(z)) == None - assert ask(Q.bounded(a), Q.negative(x) & Q.bounded(x) & ~Q.bounded(y) & ~Q.bounded(z)) == None - assert ask(Q.bounded(a), Q.negative(x) & Q.bounded(x) & ~Q.bounded(y) & Q.positive(z)& ~Q.bounded(z)) == None - assert ask(Q.bounded(a), Q.negative(x) & Q.bounded(x) & ~Q.bounded(y) & Q.negative(z)) == None - assert ask(Q.bounded(a), Q.negative(x) & Q.bounded(x) & ~Q.bounded(y)) == None - assert ask(Q.bounded(a), Q.negative(x) & Q.bounded(x) & ~Q.bounded(y) & Q.positive(z)) == None - assert ask(Q.bounded(a), Q.negative(x) & Q.bounded(x) & Q.positive(y) & ~Q.bounded(y)& Q.positive(z) & ~Q.bounded(z)) == False - assert ask(Q.bounded(a), Q.negative(x) & Q.bounded(x) & Q.positive(y) & ~Q.bounded(y)& Q.negative(z)) == None - assert ask(Q.bounded(a), Q.negative(x) & Q.bounded(x) & Q.positive(y) & ~Q.bounded(y)) == None - assert ask(Q.bounded(a), Q.negative(x) & Q.bounded(x) & Q.positive(y) & ~Q.bounded(y)& Q.positive(z)) == False - assert ask(Q.bounded(a), Q.negative(x) & Q.bounded(x) & Q.negative(y) & Q.negative(z)) == None - assert ask(Q.bounded(a), Q.negative(x) & Q.bounded(x) & Q.negative(y)) == None - assert ask(Q.bounded(a), Q.negative(x) & Q.bounded(x) & Q.negative(y) & Q.positive(z)) == None - assert ask(Q.bounded(a), Q.negative(x) & Q.bounded(x)) == None - assert ask(Q.bounded(a), Q.negative(x) & Q.bounded(x) & Q.positive(z)) == None - assert ask(Q.bounded(a), Q.negative(x) & Q.bounded(x) & Q.positive(y) & Q.positive(z)) == None - assert ask(Q.bounded(a), Q.bounded(x) & Q.bounded(y) & Q.bounded(z)) == True - assert ask(Q.bounded(a), Q.bounded(x) & Q.bounded(y) & Q.positive(z) & Q.bounded(z))== True - assert ask(Q.bounded(a), Q.bounded(x) & Q.bounded(y) & Q.negative(z) & ~Q.bounded(z))== False - assert ask(Q.bounded(a), Q.bounded(x) & Q.bounded(y) & ~Q.bounded(z)) == False - assert ask(Q.bounded(a), Q.bounded(x) & Q.bounded(y) & Q.positive(z) & ~Q.bounded(z)) == False - assert ask(Q.bounded(a), Q.bounded(x) & Q.bounded(y) & Q.negative(z)) == None - assert ask(Q.bounded(a), Q.bounded(x) & Q.bounded(y)) == None - assert ask(Q.bounded(a), Q.bounded(x) & Q.bounded(y) & Q.positive(z)) == None - assert ask(Q.bounded(a), Q.bounded(x) & Q.positive(y) & Q.bounded(y) & Q.positive(z)& Q.bounded(z)) == True - assert ask(Q.bounded(a), Q.bounded(x) & Q.positive(y) & Q.bounded(y) & Q.negative(z) & ~Q.bounded(z)) == False - assert ask(Q.bounded(a), Q.bounded(x) & Q.positive(y) & Q.bounded(y) & ~Q.bounded(z)) == False - assert ask(Q.bounded(a), Q.bounded(x) & Q.positive(y) & Q.bounded(y) & Q.positive(z)& ~Q.bounded(z)) == False - assert ask(Q.bounded(a), Q.bounded(x) & Q.positive(y) & Q.bounded(y) & Q.negative(z)) == None - assert ask(Q.bounded(a), Q.bounded(x) & Q.positive(y) & Q.bounded(y)) == None - assert ask(Q.bounded(a), Q.bounded(x) & Q.positive(y) & Q.bounded(y) & Q.positive(z)) == None - assert ask(Q.bounded(a), Q.bounded(x) & Q.negative(y) & ~Q.bounded(y) & Q.negative(z) & ~Q.bounded(z)) == False - assert ask(Q.bounded(a), Q.bounded(x) & Q.negative(y) & ~Q.bounded(y) & ~Q.bounded(z)) == None - assert ask(Q.bounded(a), Q.bounded(x) & Q.negative(y) & ~Q.bounded(y) & Q.positive(z)& ~Q.bounded(z)) == None - assert ask(Q.bounded(a), Q.bounded(x) & Q.negative(y) & ~Q.bounded(y) & Q.negative(z)) == False - assert ask(Q.bounded(a), Q.bounded(x) & Q.negative(y) & ~Q.bounded(y)) == None - assert ask(Q.bounded(a), Q.bounded(x) & Q.negative(y) & ~Q.bounded(y) & Q.positive(z)) == None - assert ask(Q.bounded(a), Q.bounded(x) & ~Q.bounded(y) & ~Q.bounded(z)) == None - assert ask(Q.bounded(a), Q.bounded(x) & ~Q.bounded(y) & Q.positive(z) & ~Q.bounded(z)) == None - assert ask(Q.bounded(a), Q.bounded(x) & ~Q.bounded(y) & Q.negative(z)) == None - assert ask(Q.bounded(a), Q.bounded(x) & ~Q.bounded(y)) == None - assert ask(Q.bounded(a), Q.bounded(x) & ~Q.bounded(y) & Q.positive(z)) == None - assert ask(Q.bounded(a), Q.bounded(x) & Q.positive(y) & ~Q.bounded(y) & Q.positive(z) & ~Q.bounded(z)) == False - assert ask(Q.bounded(a), Q.bounded(x) & Q.positive(y) & ~Q.bounded(y) & Q.negative(z)) == None - assert ask(Q.bounded(a), Q.bounded(x) & Q.positive(y) & ~Q.bounded(y)) == None - assert ask(Q.bounded(a), Q.bounded(x) & Q.positive(y) & ~Q.bounded(y) & Q.positive(z)) == False - assert ask(Q.bounded(a), Q.bounded(x) & Q.negative(y) & Q.negative(z)) == None - assert ask(Q.bounded(a), Q.bounded(x) & Q.negative(y)) == None - assert ask(Q.bounded(a), Q.bounded(x) & Q.negative(y) & Q.positive(z)) == None - assert ask(Q.bounded(a), Q.bounded(x)) == None - assert ask(Q.bounded(a), Q.bounded(x) & Q.positive(z)) == None - assert ask(Q.bounded(a), Q.bounded(x) & Q.positive(y) & Q.positive(z)) == None - assert ask(Q.bounded(a), Q.positive(x) & Q.bounded(x) & Q.positive(y) & Q.bounded(y)& Q.positive(z) & Q.bounded(z)) == True - assert ask(Q.bounded(a), Q.positive(x) & Q.bounded(x) & Q.positive(y) & Q.bounded(y)& Q.negative(z) & ~Q.bounded(z)) == False - assert ask(Q.bounded(a), Q.positive(x) & Q.bounded(x) & Q.positive(y) & Q.bounded(y)& ~Q.bounded(z)) == False - assert ask(Q.bounded(a), Q.positive(x) & Q.bounded(x) & Q.positive(y) & Q.bounded(y)& Q.positive(z) & ~Q.bounded(z)) == False - assert ask(Q.bounded(a), Q.positive(x) & Q.bounded(x) & Q.positive(y) & Q.bounded(y)& Q.negative(z)) == None - assert ask(Q.bounded(a), Q.positive(x) & Q.bounded(x) & Q.positive(y) & Q.bounded(y)) == None - assert ask(Q.bounded(a), Q.positive(x) & Q.bounded(x) & Q.positive(y) & Q.bounded(y)& Q.positive(z)) == None - assert ask(Q.bounded(a), Q.positive(x) & Q.bounded(x) & Q.negative(y) & ~Q.bounded(y)& Q.negative(z) & ~Q.bounded(z)) == False - assert ask(Q.bounded(a), Q.positive(x) & Q.bounded(x) & Q.negative(y) & ~Q.bounded(y)& ~Q.bounded(z)) == None - assert ask(Q.bounded(a), Q.positive(x) & Q.bounded(x) & Q.negative(y) & ~Q.bounded(y)& Q.positive(z) & ~Q.bounded(z)) == None - assert ask(Q.bounded(a), Q.positive(x) & Q.bounded(x) & Q.negative(y) & ~Q.bounded(y)& Q.negative(z)) == False - assert ask(Q.bounded(a), Q.positive(x) & Q.bounded(x) & Q.negative(y) & ~Q.bounded(y)) == None - assert ask(Q.bounded(a), Q.positive(x) & Q.bounded(x) & Q.negative(y) & ~Q.bounded(y)& Q.positive(z)) == None - assert ask(Q.bounded(a), Q.positive(x) & Q.bounded(x) & ~Q.bounded(y) & ~Q.bounded(z)) == None - assert ask(Q.bounded(a), Q.positive(x) & Q.bounded(x) & ~Q.bounded(y) & Q.positive(z) & ~Q.bounded(z)) == None - assert ask(Q.bounded(a), Q.positive(x) & Q.bounded(x) & ~Q.bounded(y) & Q.negative(z)) == None - assert ask(Q.bounded(a), Q.positive(x) & Q.bounded(x) & ~Q.bounded(y)) == None - assert ask(Q.bounded(a), Q.positive(x) & Q.bounded(x) & ~Q.bounded(y) & Q.positive(z)) == None - assert ask(Q.bounded(a), Q.positive(x) & Q.bounded(x) & Q.positive(y) & ~Q.bounded(y) & Q.positive(z) & ~Q.bounded(z)) == False - assert ask(Q.bounded(a), Q.positive(x) & Q.bounded(x) & Q.positive(y) & ~Q.bounded(y) & Q.negative(z)) == None - assert ask(Q.bounded(a), Q.positive(x) & Q.bounded(x) & Q.positive(y) & ~Q.bounded(y)) == None - assert ask(Q.bounded(a), Q.positive(x) & Q.bounded(x) & Q.positive(y) & ~Q.bounded(y) & Q.positive(z)) == False - assert ask(Q.bounded(a), Q.positive(x) & Q.bounded(x) & Q.negative(y) & Q.negative(z)) == None - assert ask(Q.bounded(a), Q.positive(x) & Q.bounded(x) & Q.negative(y)) == None - assert ask(Q.bounded(a), Q.positive(x) & Q.bounded(x) & Q.negative(y) & Q.positive(z)) == None - assert ask(Q.bounded(a), Q.positive(x) & Q.bounded(x)) == None - assert ask(Q.bounded(a), Q.positive(x) & Q.bounded(x) & Q.positive(z)) == None - assert ask(Q.bounded(a), Q.positive(x) & Q.bounded(x) & Q.positive(y) & Q.positive(z)) == None - assert ask(Q.bounded(a), Q.negative(x) & ~Q.bounded(x) & Q.negative(y) & ~Q.bounded(y)& Q.negative(z) & ~Q.bounded(z)) == False - assert ask(Q.bounded(a), Q.negative(x) & ~Q.bounded(x) & Q.negative(y) & ~Q.bounded(y)& ~Q.bounded(z)) == None - assert ask(Q.bounded(a), Q.negative(x) & ~Q.bounded(x) & Q.negative(y) & ~Q.bounded(y)& Q.positive(z) & ~Q.bounded(z)) == None - assert ask(Q.bounded(a), Q.negative(x) & ~Q.bounded(x) & Q.negative(y) & ~Q.bounded(y)& Q.negative(z)) == False - assert ask(Q.bounded(a), Q.negative(x) & ~Q.bounded(x) & Q.negative(y) & ~Q.bounded(y)) == None - assert ask(Q.bounded(a), Q.negative(x) & ~Q.bounded(x) & Q.negative(y) & ~Q.bounded(y)& Q.positive(z)) == None - assert ask(Q.bounded(a), Q.negative(x) & ~Q.bounded(x) & ~Q.bounded(y) & ~Q.bounded(z)) == None - assert ask(Q.bounded(a), Q.negative(x) & ~Q.bounded(x) & ~Q.bounded(y) & Q.positive(z) & ~Q.bounded(z)) == None - assert ask(Q.bounded(a), Q.negative(x) & ~Q.bounded(x) & ~Q.bounded(y) & Q.negative(z)) == None - assert ask(Q.bounded(a), Q.negative(x) & ~Q.bounded(x) & ~Q.bounded(y)) == None - assert ask(Q.bounded(a), Q.negative(x) & ~Q.bounded(x) & ~Q.bounded(y) & Q.positive(z)) == None - assert ask(Q.bounded(a), Q.negative(x) & ~Q.bounded(x) & Q.positive(y) & ~Q.bounded(y) & Q.positive(z) & ~Q.bounded(z)) == None - assert ask(Q.bounded(a), Q.negative(x) & ~Q.bounded(x) & Q.positive(y) & ~Q.bounded(y) & Q.negative(z)) == None - assert ask(Q.bounded(a), Q.negative(x) & ~Q.bounded(x) & Q.positive(y) & ~Q.bounded(y)) == None - assert ask(Q.bounded(a), Q.negative(x) & ~Q.bounded(x) & Q.positive(y) & ~Q.bounded(y) & Q.positive(z)) == None - assert ask(Q.bounded(a), Q.negative(x) & ~Q.bounded(x) & Q.negative(y) & Q.negative(z)) == False - assert ask(Q.bounded(a), Q.negative(x) & ~Q.bounded(x) & Q.negative(y)) == None - assert ask(Q.bounded(a), Q.negative(x) & ~Q.bounded(x) & Q.negative(y) & Q.positive(z)) == None - assert ask(Q.bounded(a), Q.negative(x) & ~Q.bounded(x)) == None - assert ask(Q.bounded(a), Q.negative(x) & ~Q.bounded(x) & Q.positive(z)) == None - assert ask(Q.bounded(a), Q.negative(x) & ~Q.bounded(x) & Q.positive(y) & Q.positive(z)) == None - assert ask(Q.bounded(a), ~Q.bounded(x) & ~Q.bounded(y) & ~Q.bounded(z)) == None - assert ask(Q.bounded(a), ~Q.bounded(x) & ~Q.bounded(y) & Q.positive(z) & ~Q.bounded(z)) == None - assert ask(Q.bounded(a), ~Q.bounded(x) & ~Q.bounded(y) & Q.negative(z)) == None - assert ask(Q.bounded(a), ~Q.bounded(x) & ~Q.bounded(y)) == None - assert ask(Q.bounded(a), ~Q.bounded(x) & ~Q.bounded(y) & Q.positive(z)) == None - assert ask(Q.bounded(a), ~Q.bounded(x) & Q.positive(y) & ~Q.bounded(y) & Q.positive(z) & ~Q.bounded(z)) == None - assert ask(Q.bounded(a), ~Q.bounded(x) & Q.positive(y) & ~Q.bounded(y) & Q.negative(z)) == None - assert ask(Q.bounded(a), ~Q.bounded(x) & Q.positive(y) & ~Q.bounded(y)) == None - assert ask(Q.bounded(a), ~Q.bounded(x) & Q.positive(y) & ~Q.bounded(y) & Q.positive(z)) == None - assert ask(Q.bounded(a), ~Q.bounded(x) & Q.negative(y) & Q.negative(z)) == None - assert ask(Q.bounded(a), ~Q.bounded(x) & Q.negative(y)) == None - assert ask(Q.bounded(a), ~Q.bounded(x) & Q.negative(y) & Q.positive(z)) == None - assert ask(Q.bounded(a), ~Q.bounded(x)) == None - assert ask(Q.bounded(a), ~Q.bounded(x) & Q.positive(z)) == None - assert ask(Q.bounded(a), ~Q.bounded(x) & Q.positive(y) & Q.positive(z)) == None - assert ask(Q.bounded(a), Q.positive(x) & ~Q.bounded(x) & Q.positive(y) & ~Q.bounded(y) & Q.positive(z) & ~Q.bounded(z)) == False - assert ask(Q.bounded(a), Q.positive(x) & ~Q.bounded(x) & Q.positive(y) & ~Q.bounded(y) & Q.negative(z)) == None - assert ask(Q.bounded(a), Q.positive(x) & ~Q.bounded(x) & Q.positive(y) & ~Q.bounded(y)) == None - assert ask(Q.bounded(a), Q.positive(x) & ~Q.bounded(x) & Q.positive(y) & ~Q.bounded(y) & Q.positive(z)) == False - assert ask(Q.bounded(a), Q.positive(x) & ~Q.bounded(x) & Q.negative(y) & Q.negative(z)) == None - assert ask(Q.bounded(a), Q.positive(x) & ~Q.bounded(x) & Q.negative(y)) == None - assert ask(Q.bounded(a), Q.positive(x) & ~Q.bounded(x) & Q.negative(y) & Q.positive(z)) == None - assert ask(Q.bounded(a), Q.positive(x) & ~Q.bounded(x)) == None - assert ask(Q.bounded(a), Q.positive(x) & ~Q.bounded(x) & Q.positive(z)) == None - assert ask(Q.bounded(a), Q.positive(x) & ~Q.bounded(x) & Q.positive(y) & Q.positive(z)) == False - assert ask(Q.bounded(a), Q.negative(x) & Q.negative(y) & Q.negative(z)) == None - assert ask(Q.bounded(a), Q.negative(x) & Q.negative(y)) == None - assert ask(Q.bounded(a), Q.negative(x) & Q.negative(y) & Q.positive(z)) == None - assert ask(Q.bounded(a), Q.negative(x)) == None - assert ask(Q.bounded(a), Q.negative(x) & Q.positive(z)) == None - assert ask(Q.bounded(a), Q.negative(x) & Q.positive(y) & Q.positive(z)) == None - assert ask(Q.bounded(a)) == None - assert ask(Q.bounded(a), Q.positive(z)) == None - assert ask(Q.bounded(a), Q.positive(y) & Q.positive(z)) == None - assert ask(Q.bounded(a), Q.positive(x) & Q.positive(y) & Q.positive(z)) == None + assert ask(Q.bounded(a), Q.negative(x) & Q.bounded(x) & Q.negative(y) & + Q.bounded(y) & Q.negative(z) & Q.bounded(z)) is True + assert ask(Q.bounded(a), Q.negative(x) & Q.bounded(x) & + Q.negative(y) & Q.bounded(y) & Q.bounded(z)) is True + assert ask(Q.bounded(a), Q.negative(x) & Q.bounded(x) & Q.negative(y) & + Q.bounded(y) & Q.positive(z) & Q.bounded(z)) is True + assert ask(Q.bounded(a), Q.negative(x) & Q.bounded(x) & Q.negative(y) & + Q.bounded(y) & Q.negative(z) & ~Q.bounded(z)) is False + assert ask(Q.bounded(a), Q.negative(x) & Q.bounded(x) & + Q.negative(y) & Q.bounded(y) & ~Q.bounded(z)) is False + assert ask(Q.bounded(a), Q.negative(x) & Q.bounded(x) & Q.negative(y) & + Q.bounded(y) & Q.positive(z) & ~Q.bounded(z)) is False + assert ask(Q.bounded(a), Q.negative(x) & Q.bounded(x) & + Q.negative(y) & Q.bounded(y) & Q.negative(z)) is None + assert ask(Q.bounded(a), Q.negative(x) & + Q.bounded(x) & Q.negative(y) & Q.bounded(y)) is None + assert ask(Q.bounded(a), Q.negative(x) & Q.bounded(x) & + Q.negative(y) & Q.bounded(y) & Q.positive(z)) is None + assert ask(Q.bounded(a), Q.negative(x) & + Q.bounded(x) & Q.bounded(y) & Q.bounded(z)) is True + assert ask(Q.bounded(a), Q.negative(x) & Q.bounded(x) & + Q.bounded(y) & Q.positive(z) & Q.bounded(z)) is True + assert ask(Q.bounded(a), Q.negative(x) & Q.bounded(x) & + Q.bounded(y) & Q.negative(z) & ~Q.bounded(z)) is False + assert ask(Q.bounded(a), Q.negative(x) & + Q.bounded(x) & Q.bounded(y) & ~Q.bounded(z)) is False + assert ask(Q.bounded(a), Q.negative(x) & Q.bounded(x) & + Q.bounded(y) & Q.positive(z) & ~Q.bounded(z)) is False + assert ask(Q.bounded(a), Q.negative(x) & + Q.bounded(x) & Q.bounded(y) & Q.negative(z)) is None + assert ask( + Q.bounded(a), Q.negative(x) & Q.bounded(x) & Q.bounded(y)) is None + assert ask(Q.bounded(a), Q.negative(x) & + Q.bounded(x) & Q.bounded(y) & Q.positive(z)) is None + assert ask(Q.bounded(a), Q.negative(x) & Q.bounded(x) & Q.positive(y) & + Q.bounded(y) & Q.positive(z) & Q.bounded(z)) is True + assert ask(Q.bounded(a), Q.negative(x) & Q.bounded(x) & Q.positive(y) & + Q.bounded(y) & Q.negative(z) & ~Q.bounded(z)) is False + assert ask(Q.bounded(a), Q.negative(x) & Q.bounded(x) & + Q.positive(y) & Q.bounded(y) & ~Q.bounded(z)) is False + assert ask(Q.bounded(a), Q.negative(x) & Q.bounded(x) & Q.positive(y) & + Q.bounded(y) & Q.positive(z) & ~Q.bounded(z)) is False + assert ask(Q.bounded(a), Q.negative(x) & Q.bounded(x) & + Q.positive(y) & Q.bounded(y) & Q.negative(z)) is None + assert ask(Q.bounded(a), Q.negative(x) & + Q.bounded(x) & Q.positive(y) & Q.bounded(y)) is None + assert ask(Q.bounded(a), Q.negative(x) & Q.bounded(x) & + Q.positive(y) & Q.bounded(y) & Q.positive(z)) is None + assert ask(Q.bounded(a), Q.negative(x) & Q.bounded(x) & Q.negative(y) & + ~Q.bounded(y) & Q.negative(z) & ~Q.bounded(z)) is False + assert ask(Q.bounded(a), Q.negative(x) & Q.bounded(x) & + Q.negative(y) & ~Q.bounded(y) & ~Q.bounded(z)) is None + assert ask(Q.bounded(a), Q.negative(x) & Q.bounded(x) & Q.negative(y) & + ~Q.bounded(y) & Q.positive(z) & ~Q.bounded(z)) is None + assert ask(Q.bounded(a), Q.negative(x) & Q.bounded(x) & + Q.negative(y) & ~Q.bounded(y) & Q.negative(z)) is False + assert ask(Q.bounded(a), Q.negative(x) & + Q.bounded(x) & Q.negative(y) & ~Q.bounded(y)) is None + assert ask(Q.bounded(a), Q.negative(x) & Q.bounded(x) & + Q.negative(y) & ~Q.bounded(y) & Q.positive(z)) is None + assert ask(Q.bounded(a), Q.negative(x) & + Q.bounded(x) & ~Q.bounded(y) & ~Q.bounded(z)) is None + assert ask(Q.bounded(a), Q.negative(x) & Q.bounded(x) & + ~Q.bounded(y) & Q.positive(z) & ~Q.bounded(z)) is None + assert ask(Q.bounded(a), Q.negative(x) & + Q.bounded(x) & ~Q.bounded(y) & Q.negative(z)) is None + assert ask( + Q.bounded(a), Q.negative(x) & Q.bounded(x) & ~Q.bounded(y)) is None + assert ask(Q.bounded(a), Q.negative(x) & + Q.bounded(x) & ~Q.bounded(y) & Q.positive(z)) is None + assert ask(Q.bounded(a), Q.negative(x) & Q.bounded(x) & Q.positive(y) & + ~Q.bounded(y) & Q.positive(z) & ~Q.bounded(z)) is False + assert ask(Q.bounded(a), Q.negative(x) & Q.bounded(x) & + Q.positive(y) & ~Q.bounded(y) & Q.negative(z)) is None + assert ask(Q.bounded(a), Q.negative(x) & + Q.bounded(x) & Q.positive(y) & ~Q.bounded(y)) is None + assert ask(Q.bounded(a), Q.negative(x) & Q.bounded(x) & + Q.positive(y) & ~Q.bounded(y) & Q.positive(z)) is False + assert ask(Q.bounded(a), Q.negative(x) & + Q.bounded(x) & Q.negative(y) & Q.negative(z)) is None + assert ask( + Q.bounded(a), Q.negative(x) & Q.bounded(x) & Q.negative(y)) is None + assert ask(Q.bounded(a), Q.negative(x) & + Q.bounded(x) & Q.negative(y) & Q.positive(z)) is None + assert ask(Q.bounded(a), Q.negative(x) & Q.bounded(x)) is None + assert ask( + Q.bounded(a), Q.negative(x) & Q.bounded(x) & Q.positive(z)) is None + assert ask(Q.bounded(a), Q.negative(x) & + Q.bounded(x) & Q.positive(y) & Q.positive(z)) is None + assert ask( + Q.bounded(a), Q.bounded(x) & Q.bounded(y) & Q.bounded(z)) is True + assert ask(Q.bounded(a), + Q.bounded(x) & Q.bounded(y) & Q.positive(z) & Q.bounded(z)) is True + assert ask(Q.bounded(a), Q.bounded(x) & + Q.bounded(y) & Q.negative(z) & ~Q.bounded(z)) is False + assert ask( + Q.bounded(a), Q.bounded(x) & Q.bounded(y) & ~Q.bounded(z)) is False + assert ask(Q.bounded(a), Q.bounded(x) & + Q.bounded(y) & Q.positive(z) & ~Q.bounded(z)) is False + assert ask( + Q.bounded(a), Q.bounded(x) & Q.bounded(y) & Q.negative(z)) is None + assert ask(Q.bounded(a), Q.bounded(x) & Q.bounded(y)) is None + assert ask( + Q.bounded(a), Q.bounded(x) & Q.bounded(y) & Q.positive(z)) is None + assert ask(Q.bounded(a), Q.bounded(x) & Q.positive(y) & + Q.bounded(y) & Q.positive(z) & Q.bounded(z)) is True + assert ask(Q.bounded(a), Q.bounded(x) & Q.positive(y) & + Q.bounded(y) & Q.negative(z) & ~Q.bounded(z)) is False + assert ask(Q.bounded(a), Q.bounded(x) & + Q.positive(y) & Q.bounded(y) & ~Q.bounded(z)) is False + assert ask(Q.bounded(a), Q.bounded(x) & Q.positive(y) & + Q.bounded(y) & Q.positive(z) & ~Q.bounded(z)) is False + assert ask(Q.bounded(a), Q.bounded(x) & + Q.positive(y) & Q.bounded(y) & Q.negative(z)) is None + assert ask( + Q.bounded(a), Q.bounded(x) & Q.positive(y) & Q.bounded(y)) is None + assert ask(Q.bounded(a), Q.bounded(x) & + Q.positive(y) & Q.bounded(y) & Q.positive(z)) is None + assert ask(Q.bounded(a), Q.bounded(x) & Q.negative(y) & + ~Q.bounded(y) & Q.negative(z) & ~Q.bounded(z)) is False + assert ask(Q.bounded(a), Q.bounded(x) & + Q.negative(y) & ~Q.bounded(y) & ~Q.bounded(z)) is None + assert ask(Q.bounded(a), Q.bounded(x) & Q.negative(y) & + ~Q.bounded(y) & Q.positive(z) & ~Q.bounded(z)) is None + assert ask(Q.bounded(a), Q.bounded(x) & + Q.negative(y) & ~Q.bounded(y) & Q.negative(z)) is False + assert ask( + Q.bounded(a), Q.bounded(x) & Q.negative(y) & ~Q.bounded(y)) is None + assert ask(Q.bounded(a), Q.bounded(x) & + Q.negative(y) & ~Q.bounded(y) & Q.positive(z)) is None + assert ask( + Q.bounded(a), Q.bounded(x) & ~Q.bounded(y) & ~Q.bounded(z)) is None + assert ask(Q.bounded(a), Q.bounded(x) & + ~Q.bounded(y) & Q.positive(z) & ~Q.bounded(z)) is None + assert ask( + Q.bounded(a), Q.bounded(x) & ~Q.bounded(y) & Q.negative(z)) is None + assert ask(Q.bounded(a), Q.bounded(x) & ~Q.bounded(y)) is None + assert ask( + Q.bounded(a), Q.bounded(x) & ~Q.bounded(y) & Q.positive(z)) is None + assert ask(Q.bounded(a), Q.bounded(x) & Q.positive(y) & + ~Q.bounded(y) & Q.positive(z) & ~Q.bounded(z)) is False + assert ask(Q.bounded(a), Q.bounded(x) & + Q.positive(y) & ~Q.bounded(y) & Q.negative(z)) is None + assert ask( + Q.bounded(a), Q.bounded(x) & Q.positive(y) & ~Q.bounded(y)) is None + assert ask(Q.bounded(a), Q.bounded(x) & + Q.positive(y) & ~Q.bounded(y) & Q.positive(z)) is False + assert ask( + Q.bounded(a), Q.bounded(x) & Q.negative(y) & Q.negative(z)) is None + assert ask(Q.bounded(a), Q.bounded(x) & Q.negative(y)) is None + assert ask( + Q.bounded(a), Q.bounded(x) & Q.negative(y) & Q.positive(z)) is None + assert ask(Q.bounded(a), Q.bounded(x)) is None + assert ask(Q.bounded(a), Q.bounded(x) & Q.positive(z)) is None + assert ask( + Q.bounded(a), Q.bounded(x) & Q.positive(y) & Q.positive(z)) is None + assert ask(Q.bounded(a), Q.positive(x) & Q.bounded(x) & Q.positive(y) & + Q.bounded(y) & Q.positive(z) & Q.bounded(z)) is True + assert ask(Q.bounded(a), Q.positive(x) & Q.bounded(x) & Q.positive(y) & + Q.bounded(y) & Q.negative(z) & ~Q.bounded(z)) is False + assert ask(Q.bounded(a), Q.positive(x) & Q.bounded(x) & + Q.positive(y) & Q.bounded(y) & ~Q.bounded(z)) is False + assert ask(Q.bounded(a), Q.positive(x) & Q.bounded(x) & Q.positive(y) & + Q.bounded(y) & Q.positive(z) & ~Q.bounded(z)) is False + assert ask(Q.bounded(a), Q.positive(x) & Q.bounded(x) & + Q.positive(y) & Q.bounded(y) & Q.negative(z)) is None + assert ask(Q.bounded(a), Q.positive(x) & + Q.bounded(x) & Q.positive(y) & Q.bounded(y)) is None + assert ask(Q.bounded(a), Q.positive(x) & Q.bounded(x) & + Q.positive(y) & Q.bounded(y) & Q.positive(z)) is None + assert ask(Q.bounded(a), Q.positive(x) & Q.bounded(x) & Q.negative(y) & + ~Q.bounded(y) & Q.negative(z) & ~Q.bounded(z)) is False + assert ask(Q.bounded(a), Q.positive(x) & Q.bounded(x) & + Q.negative(y) & ~Q.bounded(y) & ~Q.bounded(z)) is None + assert ask(Q.bounded(a), Q.positive(x) & Q.bounded(x) & Q.negative(y) & + ~Q.bounded(y) & Q.positive(z) & ~Q.bounded(z)) is None + assert ask(Q.bounded(a), Q.positive(x) & Q.bounded(x) & + Q.negative(y) & ~Q.bounded(y) & Q.negative(z)) is False + assert ask(Q.bounded(a), Q.positive(x) & + Q.bounded(x) & Q.negative(y) & ~Q.bounded(y)) is None + assert ask(Q.bounded(a), Q.positive(x) & Q.bounded(x) & + Q.negative(y) & ~Q.bounded(y) & Q.positive(z)) is None + assert ask(Q.bounded(a), Q.positive(x) & + Q.bounded(x) & ~Q.bounded(y) & ~Q.bounded(z)) is None + assert ask(Q.bounded(a), Q.positive(x) & Q.bounded(x) & + ~Q.bounded(y) & Q.positive(z) & ~Q.bounded(z)) is None + assert ask(Q.bounded(a), Q.positive(x) & + Q.bounded(x) & ~Q.bounded(y) & Q.negative(z)) is None + assert ask( + Q.bounded(a), Q.positive(x) & Q.bounded(x) & ~Q.bounded(y)) is None + assert ask(Q.bounded(a), Q.positive(x) & + Q.bounded(x) & ~Q.bounded(y) & Q.positive(z)) is None + assert ask(Q.bounded(a), Q.positive(x) & Q.bounded(x) & Q.positive(y) & + ~Q.bounded(y) & Q.positive(z) & ~Q.bounded(z)) is False + assert ask(Q.bounded(a), Q.positive(x) & Q.bounded(x) & + Q.positive(y) & ~Q.bounded(y) & Q.negative(z)) is None + assert ask(Q.bounded(a), Q.positive(x) & + Q.bounded(x) & Q.positive(y) & ~Q.bounded(y)) is None + assert ask(Q.bounded(a), Q.positive(x) & Q.bounded(x) & + Q.positive(y) & ~Q.bounded(y) & Q.positive(z)) is False + assert ask(Q.bounded(a), Q.positive(x) & + Q.bounded(x) & Q.negative(y) & Q.negative(z)) is None + assert ask( + Q.bounded(a), Q.positive(x) & Q.bounded(x) & Q.negative(y)) is None + assert ask(Q.bounded(a), Q.positive(x) & + Q.bounded(x) & Q.negative(y) & Q.positive(z)) is None + assert ask(Q.bounded(a), Q.positive(x) & Q.bounded(x)) is None + assert ask( + Q.bounded(a), Q.positive(x) & Q.bounded(x) & Q.positive(z)) is None + assert ask(Q.bounded(a), Q.positive(x) & + Q.bounded(x) & Q.positive(y) & Q.positive(z)) is None + assert ask(Q.bounded(a), Q.negative(x) & ~Q.bounded(x) & Q.negative(y) & + ~Q.bounded(y) & Q.negative(z) & ~Q.bounded(z)) is False + assert ask(Q.bounded(a), Q.negative(x) & ~Q.bounded(x) & + Q.negative(y) & ~Q.bounded(y) & ~Q.bounded(z)) is None + assert ask(Q.bounded(a), Q.negative(x) & ~Q.bounded(x) & Q.negative(y) & + ~Q.bounded(y) & Q.positive(z) & ~Q.bounded(z)) is None + assert ask(Q.bounded(a), Q.negative(x) & ~Q.bounded(x) & + Q.negative(y) & ~Q.bounded(y) & Q.negative(z)) is False + assert ask(Q.bounded(a), Q.negative(x) & + ~Q.bounded(x) & Q.negative(y) & ~Q.bounded(y)) is None + assert ask(Q.bounded(a), Q.negative(x) & ~Q.bounded(x) & + Q.negative(y) & ~Q.bounded(y) & Q.positive(z)) is None + assert ask(Q.bounded(a), Q.negative(x) & + ~Q.bounded(x) & ~Q.bounded(y) & ~Q.bounded(z)) is None + assert ask(Q.bounded(a), Q.negative(x) & ~Q.bounded(x) & + ~Q.bounded(y) & Q.positive(z) & ~Q.bounded(z)) is None + assert ask(Q.bounded(a), Q.negative(x) & + ~Q.bounded(x) & ~Q.bounded(y) & Q.negative(z)) is None + assert ask( + Q.bounded(a), Q.negative(x) & ~Q.bounded(x) & ~Q.bounded(y)) is None + assert ask(Q.bounded(a), Q.negative(x) & + ~Q.bounded(x) & ~Q.bounded(y) & Q.positive(z)) is None + assert ask(Q.bounded(a), Q.negative(x) & ~Q.bounded(x) & Q.positive(y) & + ~Q.bounded(y) & Q.positive(z) & ~Q.bounded(z)) is None + assert ask(Q.bounded(a), Q.negative(x) & ~Q.bounded(x) & + Q.positive(y) & ~Q.bounded(y) & Q.negative(z)) is None + assert ask(Q.bounded(a), Q.negative(x) & + ~Q.bounded(x) & Q.positive(y) & ~Q.bounded(y)) is None + assert ask(Q.bounded(a), Q.negative(x) & ~Q.bounded(x) & + Q.positive(y) & ~Q.bounded(y) & Q.positive(z)) is None + assert ask(Q.bounded(a), Q.negative(x) & + ~Q.bounded(x) & Q.negative(y) & Q.negative(z)) is False + assert ask( + Q.bounded(a), Q.negative(x) & ~Q.bounded(x) & Q.negative(y)) is None + assert ask(Q.bounded(a), Q.negative(x) & + ~Q.bounded(x) & Q.negative(y) & Q.positive(z)) is None + assert ask(Q.bounded(a), Q.negative(x) & ~Q.bounded(x)) is None + assert ask( + Q.bounded(a), Q.negative(x) & ~Q.bounded(x) & Q.positive(z)) is None + assert ask(Q.bounded(a), Q.negative(x) & + ~Q.bounded(x) & Q.positive(y) & Q.positive(z)) is None + assert ask( + Q.bounded(a), ~Q.bounded(x) & ~Q.bounded(y) & ~Q.bounded(z)) is None + assert ask(Q.bounded(a), ~Q.bounded(x) & + ~Q.bounded(y) & Q.positive(z) & ~Q.bounded(z)) is None + assert ask( + Q.bounded(a), ~Q.bounded(x) & ~Q.bounded(y) & Q.negative(z)) is None + assert ask(Q.bounded(a), ~Q.bounded(x) & ~Q.bounded(y)) is None + assert ask( + Q.bounded(a), ~Q.bounded(x) & ~Q.bounded(y) & Q.positive(z)) is None + assert ask(Q.bounded(a), ~Q.bounded(x) & Q.positive(y) & + ~Q.bounded(y) & Q.positive(z) & ~Q.bounded(z)) is None + assert ask(Q.bounded(a), ~Q.bounded(x) & + Q.positive(y) & ~Q.bounded(y) & Q.negative(z)) is None + assert ask( + Q.bounded(a), ~Q.bounded(x) & Q.positive(y) & ~Q.bounded(y)) is None + assert ask(Q.bounded(a), ~Q.bounded(x) & + Q.positive(y) & ~Q.bounded(y) & Q.positive(z)) is None + assert ask( + Q.bounded(a), ~Q.bounded(x) & Q.negative(y) & Q.negative(z)) is None + assert ask(Q.bounded(a), ~Q.bounded(x) & Q.negative(y)) is None + assert ask( + Q.bounded(a), ~Q.bounded(x) & Q.negative(y) & Q.positive(z)) is None + assert ask(Q.bounded(a), ~Q.bounded(x)) is None + assert ask(Q.bounded(a), ~Q.bounded(x) & Q.positive(z)) is None + assert ask( + Q.bounded(a), ~Q.bounded(x) & Q.positive(y) & Q.positive(z)) is None + assert ask(Q.bounded(a), Q.positive(x) & ~Q.bounded(x) & Q.positive(y) & + ~Q.bounded(y) & Q.positive(z) & ~Q.bounded(z)) is False + assert ask(Q.bounded(a), Q.positive(x) & ~Q.bounded(x) & + Q.positive(y) & ~Q.bounded(y) & Q.negative(z)) is None + assert ask(Q.bounded(a), Q.positive(x) & + ~Q.bounded(x) & Q.positive(y) & ~Q.bounded(y)) is None + assert ask(Q.bounded(a), Q.positive(x) & ~Q.bounded(x) & + Q.positive(y) & ~Q.bounded(y) & Q.positive(z)) is False + assert ask(Q.bounded(a), Q.positive(x) & + ~Q.bounded(x) & Q.negative(y) & Q.negative(z)) is None + assert ask( + Q.bounded(a), Q.positive(x) & ~Q.bounded(x) & Q.negative(y)) is None + assert ask(Q.bounded(a), Q.positive(x) & + ~Q.bounded(x) & Q.negative(y) & Q.positive(z)) is None + assert ask(Q.bounded(a), Q.positive(x) & ~Q.bounded(x)) is None + assert ask( + Q.bounded(a), Q.positive(x) & ~Q.bounded(x) & Q.positive(z)) is None + assert ask(Q.bounded(a), Q.positive(x) & + ~Q.bounded(x) & Q.positive(y) & Q.positive(z)) is False + assert ask( + Q.bounded(a), Q.negative(x) & Q.negative(y) & Q.negative(z)) is None + assert ask(Q.bounded(a), Q.negative(x) & Q.negative(y)) is None + assert ask( + Q.bounded(a), Q.negative(x) & Q.negative(y) & Q.positive(z)) is None + assert ask(Q.bounded(a), Q.negative(x)) is None + assert ask(Q.bounded(a), Q.negative(x) & Q.positive(z)) is None + assert ask( + Q.bounded(a), Q.negative(x) & Q.positive(y) & Q.positive(z)) is None + assert ask(Q.bounded(a)) is None + assert ask(Q.bounded(a), Q.positive(z)) is None + assert ask(Q.bounded(a), Q.positive(y) & Q.positive(z)) is None + assert ask( + Q.bounded(a), Q.positive(x) & Q.positive(y) & Q.positive(z)) is None x, y, z = symbols('x,y,z') - assert ask(Q.bounded(2*x)) == None - assert ask(Q.bounded(2*x), Q.bounded(x)) == True + assert ask(Q.bounded(2*x)) is None + assert ask(Q.bounded(2*x), Q.bounded(x)) is True a = x*y x, y = a.args - assert ask(Q.bounded(a), Q.bounded(x) & Q.bounded(y)) == True - assert ask(Q.bounded(a), Q.bounded(x) & ~Q.bounded(y)) == False - assert ask(Q.bounded(a), Q.bounded(x)) == None - assert ask(Q.bounded(a), ~Q.bounded(x) & Q.bounded(y)) == False - assert ask(Q.bounded(a), ~Q.bounded(x) & ~Q.bounded(y)) == False - assert ask(Q.bounded(a), ~Q.bounded(x)) == None - assert ask(Q.bounded(a), Q.bounded(y)) == None - assert ask(Q.bounded(a), ~Q.bounded(y)) == None - assert ask(Q.bounded(a)) == None + assert ask(Q.bounded(a), Q.bounded(x) & Q.bounded(y)) is True + assert ask(Q.bounded(a), Q.bounded(x) & ~Q.bounded(y)) is False + assert ask(Q.bounded(a), Q.bounded(x)) is None + assert ask(Q.bounded(a), ~Q.bounded(x) & Q.bounded(y)) is False + assert ask(Q.bounded(a), ~Q.bounded(x) & ~Q.bounded(y)) is False + assert ask(Q.bounded(a), ~Q.bounded(x)) is None + assert ask(Q.bounded(a), Q.bounded(y)) is None + assert ask(Q.bounded(a), ~Q.bounded(y)) is None + assert ask(Q.bounded(a)) is None a = x*y*z x, y, z = a.args - assert ask(Q.bounded(a), Q.bounded(x) & Q.bounded(y) & Q.bounded(z)) == True - assert ask(Q.bounded(a), Q.bounded(x) & Q.bounded(y) & ~Q.bounded(z)) == False - assert ask(Q.bounded(a), Q.bounded(x) & Q.bounded(y)) == None - assert ask(Q.bounded(a), Q.bounded(x) & ~Q.bounded(y) & Q.bounded(z)) == False - assert ask(Q.bounded(a), Q.bounded(x) & ~Q.bounded(y) & ~Q.bounded(z)) == False - assert ask(Q.bounded(a), Q.bounded(x) & ~Q.bounded(y)) == None - assert ask(Q.bounded(a), Q.bounded(x) & Q.bounded(z)) == None - assert ask(Q.bounded(a), Q.bounded(x) & ~Q.bounded(z)) == None - assert ask(Q.bounded(a), Q.bounded(x)) == None - assert ask(Q.bounded(a), ~Q.bounded(x) & Q.bounded(y) & Q.bounded(z)) == False - assert ask(Q.bounded(a), ~Q.bounded(x) & Q.bounded(y) & ~Q.bounded(z)) == False - assert ask(Q.bounded(a), ~Q.bounded(x) & Q.bounded(y)) == None - assert ask(Q.bounded(a), ~Q.bounded(x) & ~Q.bounded(y) & Q.bounded(z)) == False - assert ask(Q.bounded(a), ~Q.bounded(x) & ~Q.bounded(y) & ~Q.bounded(z)) == False - assert ask(Q.bounded(a), ~Q.bounded(x) & ~Q.bounded(y)) == None - assert ask(Q.bounded(a), ~Q.bounded(x) & Q.bounded(z)) == None - assert ask(Q.bounded(a), ~Q.bounded(x) & ~Q.bounded(z)) == None - assert ask(Q.bounded(a), ~Q.bounded(x)) == None - assert ask(Q.bounded(a), Q.bounded(y) & Q.bounded(z)) == None - assert ask(Q.bounded(a), Q.bounded(y) & ~Q.bounded(z)) == None - assert ask(Q.bounded(a), Q.bounded(y)) == None - assert ask(Q.bounded(a), ~Q.bounded(y) & Q.bounded(z)) == None - assert ask(Q.bounded(a), ~Q.bounded(y) & ~Q.bounded(z)) == None - assert ask(Q.bounded(a), ~Q.bounded(y)) == None - assert ask(Q.bounded(a), Q.bounded(z)) == None - assert ask(Q.bounded(a), ~Q.bounded(z)) == None - assert ask(Q.bounded(a), ~Q.bounded(z) & Q.nonzero(x) & Q.nonzero(y) & Q.nonzero(z)) == None - assert ask(Q.bounded(a), ~Q.bounded(y) & ~Q.bounded(z) & Q.nonzero(x) & Q.nonzero(y) & Q.nonzero(z)) == False + assert ask( + Q.bounded(a), Q.bounded(x) & Q.bounded(y) & Q.bounded(z)) is True + assert ask( + Q.bounded(a), Q.bounded(x) & Q.bounded(y) & ~Q.bounded(z)) is False + assert ask(Q.bounded(a), Q.bounded(x) & Q.bounded(y)) is None + assert ask( + Q.bounded(a), Q.bounded(x) & ~Q.bounded(y) & Q.bounded(z)) is False + assert ask( + Q.bounded(a), Q.bounded(x) & ~Q.bounded(y) & ~Q.bounded(z)) is False + assert ask(Q.bounded(a), Q.bounded(x) & ~Q.bounded(y)) is None + assert ask(Q.bounded(a), Q.bounded(x) & Q.bounded(z)) is None + assert ask(Q.bounded(a), Q.bounded(x) & ~Q.bounded(z)) is None + assert ask(Q.bounded(a), Q.bounded(x)) is None + assert ask( + Q.bounded(a), ~Q.bounded(x) & Q.bounded(y) & Q.bounded(z)) is False + assert ask( + Q.bounded(a), ~Q.bounded(x) & Q.bounded(y) & ~Q.bounded(z)) is False + assert ask(Q.bounded(a), ~Q.bounded(x) & Q.bounded(y)) is None + assert ask( + Q.bounded(a), ~Q.bounded(x) & ~Q.bounded(y) & Q.bounded(z)) is False + assert ask( + Q.bounded(a), ~Q.bounded(x) & ~Q.bounded(y) & ~Q.bounded(z)) is False + assert ask(Q.bounded(a), ~Q.bounded(x) & ~Q.bounded(y)) is None + assert ask(Q.bounded(a), ~Q.bounded(x) & Q.bounded(z)) is None + assert ask(Q.bounded(a), ~Q.bounded(x) & ~Q.bounded(z)) is None + assert ask(Q.bounded(a), ~Q.bounded(x)) is None + assert ask(Q.bounded(a), Q.bounded(y) & Q.bounded(z)) is None + assert ask(Q.bounded(a), Q.bounded(y) & ~Q.bounded(z)) is None + assert ask(Q.bounded(a), Q.bounded(y)) is None + assert ask(Q.bounded(a), ~Q.bounded(y) & Q.bounded(z)) is None + assert ask(Q.bounded(a), ~Q.bounded(y) & ~Q.bounded(z)) is None + assert ask(Q.bounded(a), ~Q.bounded(y)) is None + assert ask(Q.bounded(a), Q.bounded(z)) is None + assert ask(Q.bounded(a), ~Q.bounded(z)) is None + assert ask(Q.bounded(a), ~Q.bounded(z) & + Q.nonzero(x) & Q.nonzero(y) & Q.nonzero(z)) is None + assert ask(Q.bounded(a), ~Q.bounded(y) & ~Q.bounded(z) & + Q.nonzero(x) & Q.nonzero(y) & Q.nonzero(z)) is False x, y, z = symbols('x,y,z') - assert ask(Q.bounded(x**2)) == None - assert ask(Q.bounded(2**x)) == None - assert ask(Q.bounded(2**x), Q.bounded(x)) == True - assert ask(Q.bounded(x**x)) == None - assert ask(Q.bounded(Rational(1,2) ** x)) == None - assert ask(Q.bounded(Rational(1,2) ** x), Q.positive(x)) == True - assert ask(Q.bounded(Rational(1,2) ** x), Q.negative(x)) == None - assert ask(Q.bounded(S(2) ** x), Q.negative(x)) == True - assert ask(Q.bounded(sqrt(x))) == None - assert ask(Q.bounded(2**x), ~Q.bounded(x))==False - assert ask(Q.bounded(x**2), ~Q.bounded(x))==False + assert ask(Q.bounded(x**2)) is None + assert ask(Q.bounded(2**x)) is None + assert ask(Q.bounded(2**x), Q.bounded(x)) is True + assert ask(Q.bounded(x**x)) is None + assert ask(Q.bounded(Rational(1, 2) ** x)) is None + assert ask(Q.bounded(Rational(1, 2) ** x), Q.positive(x)) is True + assert ask(Q.bounded(Rational(1, 2) ** x), Q.negative(x)) is None + assert ask(Q.bounded(S(2) ** x), Q.negative(x)) is True + assert ask(Q.bounded(sqrt(x))) is None + assert ask(Q.bounded(2**x), ~Q.bounded(x)) is False + assert ask(Q.bounded(x**2), ~Q.bounded(x)) is False # sign function - assert ask(Q.bounded(sign(x))) == True - assert ask(Q.bounded(sign(x)), ~Q.bounded(x)) == True + assert ask(Q.bounded(sign(x))) is True + assert ask(Q.bounded(sign(x)), ~Q.bounded(x)) is True # exponential functions - assert ask(Q.bounded(log(x))) == None - assert ask(Q.bounded(log(x)), Q.bounded(x)) == True - assert ask(Q.bounded(exp(x))) == None - assert ask(Q.bounded(exp(x)), Q.bounded(x)) == True - assert ask(Q.bounded(exp(2))) == True + assert ask(Q.bounded(log(x))) is None + assert ask(Q.bounded(log(x)), Q.bounded(x)) is True + assert ask(Q.bounded(exp(x))) is None + assert ask(Q.bounded(exp(x)), Q.bounded(x)) is True + assert ask(Q.bounded(exp(2))) is True # trigonometric functions - assert ask(Q.bounded(sin(x))) == True - assert ask(Q.bounded(sin(x)), ~Q.bounded(x)) == True - assert ask(Q.bounded(cos(x))) == True - assert ask(Q.bounded(cos(x)), ~Q.bounded(x)) == True - assert ask(Q.bounded(2*sin(x))) == True - assert ask(Q.bounded(sin(x)**2)) == True - assert ask(Q.bounded(cos(x)**2)) == True - assert ask(Q.bounded(cos(x) + sin(x))) == True + assert ask(Q.bounded(sin(x))) is True + assert ask(Q.bounded(sin(x)), ~Q.bounded(x)) is True + assert ask(Q.bounded(cos(x))) is True + assert ask(Q.bounded(cos(x)), ~Q.bounded(x)) is True + assert ask(Q.bounded(2*sin(x))) is True + assert ask(Q.bounded(sin(x)**2)) is True + assert ask(Q.bounded(cos(x)**2)) is True + assert ask(Q.bounded(cos(x) + sin(x))) is True + @XFAIL def test_bounded_xfail(): """We need to support relations in ask for this to work""" - assert ask(Q.bounded(sin(x)**x)) == True - assert ask(Q.bounded(cos(x)**x)) == True - assert ask(Q.bounded(sin(x) ** x)) == True + assert ask(Q.bounded(sin(x)**x)) is True + assert ask(Q.bounded(cos(x)**x)) is True + assert ask(Q.bounded(sin(x) ** x)) is True + +@XFAIL +def test_imaginary_xfail(): + assert ask(Q.imaginary(0**I)) is None + assert ask(Q.imaginary(0**(-I))) is None + +@XFAIL +def test_real_xfail(): + assert ask(Q.real(0**I)) is None + assert ask(Q.real(0**(-I))) is None + def test_commutative(): """By default objects are Q.commutative that is why it returns True for both key=True and key=False""" - assert ask(Q.commutative(x)) == True - assert ask(Q.commutative(x), ~Q.commutative(x)) == False - assert ask(Q.commutative(x), Q.complex(x)) == True - assert ask(Q.commutative(x), Q.imaginary(x)) == True - assert ask(Q.commutative(x), Q.real(x)) == True - assert ask(Q.commutative(x), Q.positive(x)) == True - assert ask(Q.commutative(x), ~Q.commutative(y)) == True - - assert ask(Q.commutative(2*x)) == True - assert ask(Q.commutative(2*x), ~Q.commutative(x)) == False + assert ask(Q.commutative(x)) is True + assert ask(Q.commutative(x), ~Q.commutative(x)) is False + assert ask(Q.commutative(x), Q.complex(x)) is True + assert ask(Q.commutative(x), Q.imaginary(x)) is True + assert ask(Q.commutative(x), Q.real(x)) is True + assert ask(Q.commutative(x), Q.positive(x)) is True + assert ask(Q.commutative(x), ~Q.commutative(y)) is True + + assert ask(Q.commutative(2*x)) is True + assert ask(Q.commutative(2*x), ~Q.commutative(x)) is False + + assert ask(Q.commutative(x + 1)) is True + assert ask(Q.commutative(x + 1), ~Q.commutative(x)) is False - assert ask(Q.commutative(x + 1)) == True - assert ask(Q.commutative(x + 1), ~Q.commutative(x)) == False + assert ask(Q.commutative(x**2)) is True + assert ask(Q.commutative(x**2), ~Q.commutative(x)) is False - assert ask(Q.commutative(x**2)) == True - assert ask(Q.commutative(x**2), ~Q.commutative(x)) == False + assert ask(Q.commutative(log(x))) is True - assert ask(Q.commutative(log(x))) == True def test_complex(): - assert ask(Q.complex(x)) == None - assert ask(Q.complex(x), Q.complex(x)) == True - assert ask(Q.complex(x), Q.complex(y)) == None - assert ask(Q.complex(x), ~Q.complex(x)) == False - assert ask(Q.complex(x), Q.real(x)) == True - assert ask(Q.complex(x), ~Q.real(x)) == None - assert ask(Q.complex(x), Q.rational(x)) == True - assert ask(Q.complex(x), Q.irrational(x)) == True - assert ask(Q.complex(x), Q.positive(x)) == True - assert ask(Q.complex(x), Q.imaginary(x)) == True + assert ask(Q.complex(x)) is None + assert ask(Q.complex(x), Q.complex(x)) is True + assert ask(Q.complex(x), Q.complex(y)) is None + assert ask(Q.complex(x), ~Q.complex(x)) is False + assert ask(Q.complex(x), Q.real(x)) is True + assert ask(Q.complex(x), ~Q.real(x)) is None + assert ask(Q.complex(x), Q.rational(x)) is True + assert ask(Q.complex(x), Q.irrational(x)) is True + assert ask(Q.complex(x), Q.positive(x)) is True + assert ask(Q.complex(x), Q.imaginary(x)) is True + assert ask(Q.complex(x), Q.algebraic(x)) is True # a+b - assert ask(Q.complex(x+1), Q.complex(x)) == True - assert ask(Q.complex(x+1), Q.real(x)) == True - assert ask(Q.complex(x+1), Q.rational(x)) == True - assert ask(Q.complex(x+1), Q.irrational(x)) == True - assert ask(Q.complex(x+1), Q.imaginary(x)) == True - assert ask(Q.complex(x+1), Q.integer(x)) == True - assert ask(Q.complex(x+1), Q.even(x)) == True - assert ask(Q.complex(x+1), Q.odd(x)) == True - assert ask(Q.complex(x+y), Q.complex(x) & Q.complex(y)) == True - assert ask(Q.complex(x+y), Q.real(x) & Q.imaginary(y)) == True + assert ask(Q.complex(x + 1), Q.complex(x)) is True + assert ask(Q.complex(x + 1), Q.real(x)) is True + assert ask(Q.complex(x + 1), Q.rational(x)) is True + assert ask(Q.complex(x + 1), Q.irrational(x)) is True + assert ask(Q.complex(x + 1), Q.imaginary(x)) is True + assert ask(Q.complex(x + 1), Q.integer(x)) is True + assert ask(Q.complex(x + 1), Q.even(x)) is True + assert ask(Q.complex(x + 1), Q.odd(x)) is True + assert ask(Q.complex(x + y), Q.complex(x) & Q.complex(y)) is True + assert ask(Q.complex(x + y), Q.real(x) & Q.imaginary(y)) is True # a*x +b - assert ask(Q.complex(2*x+1), Q.complex(x)) == True - assert ask(Q.complex(2*x+1), Q.real(x)) == True - assert ask(Q.complex(2*x+1), Q.positive(x)) == True - assert ask(Q.complex(2*x+1), Q.rational(x)) == True - assert ask(Q.complex(2*x+1), Q.irrational(x)) == True - assert ask(Q.complex(2*x+1), Q.imaginary(x)) == True - assert ask(Q.complex(2*x+1), Q.integer(x)) == True - assert ask(Q.complex(2*x+1), Q.even(x)) == True - assert ask(Q.complex(2*x+1), Q.odd(x)) == True + assert ask(Q.complex(2*x + 1), Q.complex(x)) is True + assert ask(Q.complex(2*x + 1), Q.real(x)) is True + assert ask(Q.complex(2*x + 1), Q.positive(x)) is True + assert ask(Q.complex(2*x + 1), Q.rational(x)) is True + assert ask(Q.complex(2*x + 1), Q.irrational(x)) is True + assert ask(Q.complex(2*x + 1), Q.imaginary(x)) is True + assert ask(Q.complex(2*x + 1), Q.integer(x)) is True + assert ask(Q.complex(2*x + 1), Q.even(x)) is True + assert ask(Q.complex(2*x + 1), Q.odd(x)) is True # x**2 - assert ask(Q.complex(x**2), Q.complex(x)) == True - assert ask(Q.complex(x**2), Q.real(x)) == True - assert ask(Q.complex(x**2), Q.positive(x)) == True - assert ask(Q.complex(x**2), Q.rational(x)) == True - assert ask(Q.complex(x**2), Q.irrational(x)) == True - assert ask(Q.complex(x**2), Q.imaginary(x)) == True - assert ask(Q.complex(x**2), Q.integer(x)) == True - assert ask(Q.complex(x**2), Q.even(x)) == True - assert ask(Q.complex(x**2), Q.odd(x)) == True + assert ask(Q.complex(x**2), Q.complex(x)) is True + assert ask(Q.complex(x**2), Q.real(x)) is True + assert ask(Q.complex(x**2), Q.positive(x)) is True + assert ask(Q.complex(x**2), Q.rational(x)) is True + assert ask(Q.complex(x**2), Q.irrational(x)) is True + assert ask(Q.complex(x**2), Q.imaginary(x)) is True + assert ask(Q.complex(x**2), Q.integer(x)) is True + assert ask(Q.complex(x**2), Q.even(x)) is True + assert ask(Q.complex(x**2), Q.odd(x)) is True # 2**x - assert ask(Q.complex(2**x), Q.complex(x)) == True - assert ask(Q.complex(2**x), Q.real(x)) == True - assert ask(Q.complex(2**x), Q.positive(x)) == True - assert ask(Q.complex(2**x), Q.rational(x)) == True - assert ask(Q.complex(2**x), Q.irrational(x)) == True - assert ask(Q.complex(2**x), Q.imaginary(x)) == True - assert ask(Q.complex(2**x), Q.integer(x)) == True - assert ask(Q.complex(2**x), Q.even(x)) == True - assert ask(Q.complex(2**x), Q.odd(x)) == True - assert ask(Q.complex(x**y), Q.complex(x) & Q.complex(y)) == True + assert ask(Q.complex(2**x), Q.complex(x)) is True + assert ask(Q.complex(2**x), Q.real(x)) is True + assert ask(Q.complex(2**x), Q.positive(x)) is True + assert ask(Q.complex(2**x), Q.rational(x)) is True + assert ask(Q.complex(2**x), Q.irrational(x)) is True + assert ask(Q.complex(2**x), Q.imaginary(x)) is True + assert ask(Q.complex(2**x), Q.integer(x)) is True + assert ask(Q.complex(2**x), Q.even(x)) is True + assert ask(Q.complex(2**x), Q.odd(x)) is True + assert ask(Q.complex(x**y), Q.complex(x) & Q.complex(y)) is True # trigonometric expressions - assert ask(Q.complex(sin(x))) == True - assert ask(Q.complex(sin(2*x + 1))) == True - assert ask(Q.complex(cos(x))) == True - assert ask(Q.complex(cos(2*x+1))) == True + assert ask(Q.complex(sin(x))) is True + assert ask(Q.complex(sin(2*x + 1))) is True + assert ask(Q.complex(cos(x))) is True + assert ask(Q.complex(cos(2*x + 1))) is True # exponential - assert ask(Q.complex(exp(x))) == True - assert ask(Q.complex(exp(x))) == True + assert ask(Q.complex(exp(x))) is True + assert ask(Q.complex(exp(x))) is True # Q.complexes - assert ask(Q.complex(Abs(x))) == True - assert ask(Q.complex(re(x))) == True - assert ask(Q.complex(im(x))) == True + assert ask(Q.complex(Abs(x))) is True + assert ask(Q.complex(re(x))) is True + assert ask(Q.complex(im(x))) is True + def test_even(): - assert ask(Q.even(x)) == None - assert ask(Q.even(x), Q.integer(x)) == None - assert ask(Q.even(x), ~Q.integer(x)) == False - assert ask(Q.even(x), Q.rational(x)) == None - assert ask(Q.even(x), Q.positive(x)) == None - - assert ask(Q.even(2*x)) == None - assert ask(Q.even(2*x), Q.integer(x)) == True - assert ask(Q.even(2*x), Q.even(x)) == True - assert ask(Q.even(2*x), Q.irrational(x)) == False - assert ask(Q.even(2*x), Q.odd(x)) == True - assert ask(Q.even(2*x), ~Q.integer(x)) == None - assert ask(Q.even(3*x), Q.integer(x)) == None - assert ask(Q.even(3*x), Q.even(x)) == True - assert ask(Q.even(3*x), Q.odd(x)) == False - - assert ask(Q.even(x+1), Q.odd(x)) == True - assert ask(Q.even(x+1), Q.even(x)) == False - assert ask(Q.even(x+2), Q.odd(x)) == False - assert ask(Q.even(x+2), Q.even(x)) == True - assert ask(Q.even(7-x), Q.odd(x)) == True - assert ask(Q.even(7+x), Q.odd(x)) == True - assert ask(Q.even(x+y), Q.odd(x) & Q.odd(y)) == True - assert ask(Q.even(x+y), Q.odd(x) & Q.even(y)) == False - assert ask(Q.even(x+y), Q.even(x) & Q.even(y)) == True - - assert ask(Q.even(2*x + 1), Q.integer(x)) == False - assert ask(Q.even(2*x*y), Q.rational(x) & Q.rational(x)) == None - assert ask(Q.even(2*x*y), Q.irrational(x) & Q.irrational(x)) == None - - assert ask(Q.even(x+y+z), Q.odd(x) & Q.odd(y) & Q.even(z)) == True - assert ask(Q.even(x+y+z+t), Q.odd(x) & Q.odd(y) & Q.even(z) & Q.integer(t)) == None - - assert ask(Q.even(Abs(x)), Q.even(x)) == True - assert ask(Q.even(Abs(x)), ~Q.even(x)) == None - assert ask(Q.even(re(x)), Q.even(x)) == True - assert ask(Q.even(re(x)), ~Q.even(x)) == None - assert ask(Q.even(im(x)), Q.even(x)) == True - assert ask(Q.even(im(x)), Q.real(x)) == True + assert ask(Q.even(x)) is None + assert ask(Q.even(x), Q.integer(x)) is None + assert ask(Q.even(x), ~Q.integer(x)) is False + assert ask(Q.even(x), Q.rational(x)) is None + assert ask(Q.even(x), Q.positive(x)) is None + + assert ask(Q.even(2*x)) is None + assert ask(Q.even(2*x), Q.integer(x)) is True + assert ask(Q.even(2*x), Q.even(x)) is True + assert ask(Q.even(2*x), Q.irrational(x)) is False + assert ask(Q.even(2*x), Q.odd(x)) is True + assert ask(Q.even(2*x), ~Q.integer(x)) is None + assert ask(Q.even(3*x), Q.integer(x)) is None + assert ask(Q.even(3*x), Q.even(x)) is True + assert ask(Q.even(3*x), Q.odd(x)) is False + + assert ask(Q.even(x + 1), Q.odd(x)) is True + assert ask(Q.even(x + 1), Q.even(x)) is False + assert ask(Q.even(x + 2), Q.odd(x)) is False + assert ask(Q.even(x + 2), Q.even(x)) is True + assert ask(Q.even(7 - x), Q.odd(x)) is True + assert ask(Q.even(7 + x), Q.odd(x)) is True + assert ask(Q.even(x + y), Q.odd(x) & Q.odd(y)) is True + assert ask(Q.even(x + y), Q.odd(x) & Q.even(y)) is False + assert ask(Q.even(x + y), Q.even(x) & Q.even(y)) is True + + assert ask(Q.even(2*x + 1), Q.integer(x)) is False + assert ask(Q.even(2*x*y), Q.rational(x) & Q.rational(x)) is None + assert ask(Q.even(2*x*y), Q.irrational(x) & Q.irrational(x)) is None + + assert ask(Q.even(x + y + z), Q.odd(x) & Q.odd(y) & Q.even(z)) is True + assert ask(Q.even(x + y + z + t), + Q.odd(x) & Q.odd(y) & Q.even(z) & Q.integer(t)) is None + + assert ask(Q.even(Abs(x)), Q.even(x)) is True + assert ask(Q.even(Abs(x)), ~Q.even(x)) is None + assert ask(Q.even(re(x)), Q.even(x)) is True + assert ask(Q.even(re(x)), ~Q.even(x)) is None + assert ask(Q.even(im(x)), Q.even(x)) is True + assert ask(Q.even(im(x)), Q.real(x)) is True + def test_extended_real(): - assert ask(Q.extended_real(x), Q.positive(x)) == True - assert ask(Q.extended_real(-x), Q.positive(x)) == True - assert ask(Q.extended_real(-x), Q.negative(x)) == True + assert ask(Q.extended_real(x), Q.positive(x)) is True + assert ask(Q.extended_real(-x), Q.positive(x)) is True + assert ask(Q.extended_real(-x), Q.negative(x)) is True + + assert ask(Q.extended_real(x + S.Infinity), Q.real(x)) is True - assert ask(Q.extended_real(x+S.Infinity), Q.real(x)) == True def test_rational(): - assert ask(Q.rational(x), Q.integer(x)) == True - assert ask(Q.rational(x), Q.irrational(x)) == False - assert ask(Q.rational(x), Q.real(x)) == None - assert ask(Q.rational(x), Q.positive(x)) == None - assert ask(Q.rational(x), Q.negative(x)) == None - assert ask(Q.rational(x), Q.nonzero(x)) == None - - assert ask(Q.rational(2*x), Q.rational(x)) == True - assert ask(Q.rational(2*x), Q.integer(x)) == True - assert ask(Q.rational(2*x), Q.even(x)) == True - assert ask(Q.rational(2*x), Q.odd(x)) == True - assert ask(Q.rational(2*x), Q.irrational(x)) == False - - assert ask(Q.rational(x/2), Q.rational(x)) == True - assert ask(Q.rational(x/2), Q.integer(x)) == True - assert ask(Q.rational(x/2), Q.even(x)) == True - assert ask(Q.rational(x/2), Q.odd(x)) == True - assert ask(Q.rational(x/2), Q.irrational(x)) == False - - assert ask(Q.rational(1/x), Q.rational(x)) == True - assert ask(Q.rational(1/x), Q.integer(x)) == True - assert ask(Q.rational(1/x), Q.even(x)) == True - assert ask(Q.rational(1/x), Q.odd(x)) == True - assert ask(Q.rational(1/x), Q.irrational(x)) == False - - assert ask(Q.rational(2/x), Q.rational(x)) == True - assert ask(Q.rational(2/x), Q.integer(x)) == True - assert ask(Q.rational(2/x), Q.even(x)) == True - assert ask(Q.rational(2/x), Q.odd(x)) == True - assert ask(Q.rational(2/x), Q.irrational(x)) == False + assert ask(Q.rational(x), Q.integer(x)) is True + assert ask(Q.rational(x), Q.irrational(x)) is False + assert ask(Q.rational(x), Q.real(x)) is None + assert ask(Q.rational(x), Q.positive(x)) is None + assert ask(Q.rational(x), Q.negative(x)) is None + assert ask(Q.rational(x), Q.nonzero(x)) is None + assert ask(Q.rational(x), ~Q.algebraic(x)) is False + + assert ask(Q.rational(2*x), Q.rational(x)) is True + assert ask(Q.rational(2*x), Q.integer(x)) is True + assert ask(Q.rational(2*x), Q.even(x)) is True + assert ask(Q.rational(2*x), Q.odd(x)) is True + assert ask(Q.rational(2*x), Q.irrational(x)) is False + + assert ask(Q.rational(x/2), Q.rational(x)) is True + assert ask(Q.rational(x/2), Q.integer(x)) is True + assert ask(Q.rational(x/2), Q.even(x)) is True + assert ask(Q.rational(x/2), Q.odd(x)) is True + assert ask(Q.rational(x/2), Q.irrational(x)) is False + + assert ask(Q.rational(1/x), Q.rational(x)) is True + assert ask(Q.rational(1/x), Q.integer(x)) is True + assert ask(Q.rational(1/x), Q.even(x)) is True + assert ask(Q.rational(1/x), Q.odd(x)) is True + assert ask(Q.rational(1/x), Q.irrational(x)) is False + + assert ask(Q.rational(2/x), Q.rational(x)) is True + assert ask(Q.rational(2/x), Q.integer(x)) is True + assert ask(Q.rational(2/x), Q.even(x)) is True + assert ask(Q.rational(2/x), Q.odd(x)) is True + assert ask(Q.rational(2/x), Q.irrational(x)) is False + + assert ask(Q.rational(x), ~Q.algebraic(x)) is False # with multiple symbols - assert ask(Q.rational(x*y), Q.irrational(x) & Q.irrational(y)) == None - assert ask(Q.rational(y/x), Q.rational(x) & Q.rational(y)) == True - assert ask(Q.rational(y/x), Q.integer(x) & Q.rational(y)) == True - assert ask(Q.rational(y/x), Q.even(x) & Q.rational(y)) == True - assert ask(Q.rational(y/x), Q.odd(x) & Q.rational(y)) == True - assert ask(Q.rational(y/x), Q.irrational(x) & Q.rational(y)) == False + assert ask(Q.rational(x*y), Q.irrational(x) & Q.irrational(y)) is None + assert ask(Q.rational(y/x), Q.rational(x) & Q.rational(y)) is True + assert ask(Q.rational(y/x), Q.integer(x) & Q.rational(y)) is True + assert ask(Q.rational(y/x), Q.even(x) & Q.rational(y)) is True + assert ask(Q.rational(y/x), Q.odd(x) & Q.rational(y)) is True + assert ask(Q.rational(y/x), Q.irrational(x) & Q.rational(y)) is False + + for f in [exp, sin, tan, asin, atan, cos]: + assert ask(Q.rational(f(7))) is False + assert ask(Q.rational(f(7, evaluate=False))) is False + assert ask(Q.rational(f(0, evaluate=False))) is True + assert ask(Q.rational(f(x)), Q.rational(x)) is None + assert ask(Q.rational(f(x)), Q.rational(x) & Q.nonzero(x)) is False + + for g in [log, acos]: + assert ask(Q.rational(g(7))) is False + assert ask(Q.rational(g(7, evaluate=False))) is False + assert ask(Q.rational(g(1, evaluate=False))) is True + assert ask(Q.rational(g(x)), Q.rational(x)) is None + assert ask(Q.rational(g(x)), Q.rational(x) & Q.nonzero(x - 1)) is False + + for h in [cot, acot]: + assert ask(Q.rational(h(7))) is False + assert ask(Q.rational(h(7, evaluate=False))) is False + assert ask(Q.rational(h(x)), Q.rational(x)) is False + def test_hermitian(): - assert ask(Q.hermitian(x)) == None - assert ask(Q.hermitian(x), Q.antihermitian(x)) == False - assert ask(Q.hermitian(x), Q.imaginary(x)) == False - assert ask(Q.hermitian(x), Q.prime(x)) == True - assert ask(Q.hermitian(x), Q.real(x)) == True - - assert ask(Q.hermitian(x+1), Q.antihermitian(x)) == False - assert ask(Q.hermitian(x+1), Q.complex(x)) == None - assert ask(Q.hermitian(x+1), Q.hermitian(x)) == True - assert ask(Q.hermitian(x+1), Q.imaginary(x)) == False - assert ask(Q.hermitian(x+1), Q.real(x)) == True - assert ask(Q.hermitian(x+I), Q.antihermitian(x)) == None - assert ask(Q.hermitian(x+I), Q.complex(x)) == None - assert ask(Q.hermitian(x+I), Q.hermitian(x)) == False - assert ask(Q.hermitian(x+I), Q.imaginary(x)) == None - assert ask(Q.hermitian(x+I), Q.real(x)) == False - assert ask(Q.hermitian(x+y), Q.antihermitian(x) & Q.antihermitian(y)) == None - assert ask(Q.hermitian(x+y), Q.antihermitian(x) & Q.complex(y)) == None - assert ask(Q.hermitian(x+y), Q.antihermitian(x) & Q.hermitian(y)) == False - assert ask(Q.hermitian(x+y), Q.antihermitian(x) & Q.imaginary(y)) == None - assert ask(Q.hermitian(x+y), Q.antihermitian(x) & Q.real(y)) == False - assert ask(Q.hermitian(x+y), Q.hermitian(x) & Q.complex(y)) == None - assert ask(Q.hermitian(x+y), Q.hermitian(x) & Q.hermitian(y)) == True - assert ask(Q.hermitian(x+y), Q.hermitian(x) & Q.imaginary(y)) == False - assert ask(Q.hermitian(x+y), Q.hermitian(x) & Q.real(y)) == True - assert ask(Q.hermitian(x+y), Q.imaginary(x) & Q.complex(y)) == None - assert ask(Q.hermitian(x+y), Q.imaginary(x) & Q.imaginary(y)) == None - assert ask(Q.hermitian(x+y), Q.imaginary(x) & Q.real(y)) == False - assert ask(Q.hermitian(x+y), Q.real(x) & Q.complex(y)) == None - assert ask(Q.hermitian(x+y), Q.real(x) & Q.real(y)) == True - - assert ask(Q.hermitian(I*x), Q.antihermitian(x)) == True - assert ask(Q.hermitian(I*x), Q.complex(x)) == None - assert ask(Q.hermitian(I*x), Q.hermitian(x)) == False - assert ask(Q.hermitian(I*x), Q.imaginary(x)) == True - assert ask(Q.hermitian(I*x), Q.real(x)) == False - assert ask(Q.hermitian(x*y), Q.hermitian(x) & Q.real(y)) == True - - assert ask(Q.hermitian(x+y+z), Q.real(x) & Q.real(y) & Q.real(z)) == True - assert ask(Q.hermitian(x+y+z), Q.real(x) & Q.real(y) & Q.imaginary(z)) == False - assert ask(Q.hermitian(x+y+z), Q.real(x) & Q.imaginary(y) & Q.imaginary(z)) == None - assert ask(Q.hermitian(x+y+z), Q.imaginary(x) & Q.imaginary(y) & Q.imaginary(z)) == None - - assert ask(Q.antihermitian(x)) == None - assert ask(Q.antihermitian(x), Q.real(x)) == False - assert ask(Q.antihermitian(x), Q.prime(x)) == False - - assert ask(Q.antihermitian(x+1), Q.antihermitian(x)) == False - assert ask(Q.antihermitian(x+1), Q.complex(x)) == None - assert ask(Q.antihermitian(x+1), Q.hermitian(x)) == None - assert ask(Q.antihermitian(x+1), Q.imaginary(x)) == False - assert ask(Q.antihermitian(x+1), Q.real(x)) == None - assert ask(Q.antihermitian(x+I), Q.antihermitian(x)) == True - assert ask(Q.antihermitian(x+I), Q.complex(x)) == None - assert ask(Q.antihermitian(x+I), Q.hermitian(x)) == False - assert ask(Q.antihermitian(x+I), Q.imaginary(x)) == True - assert ask(Q.antihermitian(x+I), Q.real(x)) == False - - assert ask(Q.antihermitian(x+y), Q.antihermitian(x) & Q.antihermitian(y)) == True - assert ask(Q.antihermitian(x+y), Q.antihermitian(x) & Q.complex(y)) == None - assert ask(Q.antihermitian(x+y), Q.antihermitian(x) & Q.hermitian(y)) == False - assert ask(Q.antihermitian(x+y), Q.antihermitian(x) & Q.imaginary(y)) == True - assert ask(Q.antihermitian(x+y), Q.antihermitian(x) & Q.real(y)) == False - assert ask(Q.antihermitian(x+y), Q.hermitian(x) & Q.complex(y)) == None - assert ask(Q.antihermitian(x+y), Q.hermitian(x) & Q.hermitian(y)) == None - assert ask(Q.antihermitian(x+y), Q.hermitian(x) & Q.imaginary(y)) == False - assert ask(Q.antihermitian(x+y), Q.hermitian(x) & Q.real(y)) == None - assert ask(Q.antihermitian(x+y), Q.imaginary(x) & Q.complex(y)) == None - assert ask(Q.antihermitian(x+y), Q.imaginary(x) & Q.imaginary(y)) == True - assert ask(Q.antihermitian(x+y), Q.imaginary(x) & Q.real(y)) == False - assert ask(Q.antihermitian(x+y), Q.real(x) & Q.complex(y)) == None - assert ask(Q.antihermitian(x+y), Q.real(x) & Q.real(y)) == None - - assert ask(Q.antihermitian(I*x), Q.real(x)) == True - assert ask(Q.antihermitian(I*x), Q.antihermitian(x)) == False - assert ask(Q.antihermitian(I*x), Q.complex(x)) == None - assert ask(Q.antihermitian(x*y), Q.antihermitian(x) & Q.real(y)) == True - - assert ask(Q.antihermitian(x+y+z), Q.real(x) & Q.real(y) & Q.real(z)) == None - assert ask(Q.antihermitian(x+y+z), Q.real(x) & Q.real(y) & Q.imaginary(z)) == None - assert ask(Q.antihermitian(x+y+z), Q.real(x) & Q.imaginary(y) & Q.imaginary(z)) == False - assert ask(Q.antihermitian(x+y+z), Q.imaginary(x) & Q.imaginary(y) & Q.imaginary(z)) == True + assert ask(Q.hermitian(x)) is None + assert ask(Q.hermitian(x), Q.antihermitian(x)) is False + assert ask(Q.hermitian(x), Q.imaginary(x)) is False + assert ask(Q.hermitian(x), Q.prime(x)) is True + assert ask(Q.hermitian(x), Q.real(x)) is True + + assert ask(Q.hermitian(x + 1), Q.antihermitian(x)) is False + assert ask(Q.hermitian(x + 1), Q.complex(x)) is None + assert ask(Q.hermitian(x + 1), Q.hermitian(x)) is True + assert ask(Q.hermitian(x + 1), Q.imaginary(x)) is False + assert ask(Q.hermitian(x + 1), Q.real(x)) is True + assert ask(Q.hermitian(x + I), Q.antihermitian(x)) is None + assert ask(Q.hermitian(x + I), Q.complex(x)) is None + assert ask(Q.hermitian(x + I), Q.hermitian(x)) is False + assert ask(Q.hermitian(x + I), Q.imaginary(x)) is None + assert ask(Q.hermitian(x + I), Q.real(x)) is False + assert ask( + Q.hermitian(x + y), Q.antihermitian(x) & Q.antihermitian(y)) is None + assert ask(Q.hermitian(x + y), Q.antihermitian(x) & Q.complex(y)) is None + assert ask( + Q.hermitian(x + y), Q.antihermitian(x) & Q.hermitian(y)) is False + assert ask(Q.hermitian(x + y), Q.antihermitian(x) & Q.imaginary(y)) is None + assert ask(Q.hermitian(x + y), Q.antihermitian(x) & Q.real(y)) is False + assert ask(Q.hermitian(x + y), Q.hermitian(x) & Q.complex(y)) is None + assert ask(Q.hermitian(x + y), Q.hermitian(x) & Q.hermitian(y)) is True + assert ask(Q.hermitian(x + y), Q.hermitian(x) & Q.imaginary(y)) is False + assert ask(Q.hermitian(x + y), Q.hermitian(x) & Q.real(y)) is True + assert ask(Q.hermitian(x + y), Q.imaginary(x) & Q.complex(y)) is None + assert ask(Q.hermitian(x + y), Q.imaginary(x) & Q.imaginary(y)) is None + assert ask(Q.hermitian(x + y), Q.imaginary(x) & Q.real(y)) is False + assert ask(Q.hermitian(x + y), Q.real(x) & Q.complex(y)) is None + assert ask(Q.hermitian(x + y), Q.real(x) & Q.real(y)) is True + + assert ask(Q.hermitian(I*x), Q.antihermitian(x)) is True + assert ask(Q.hermitian(I*x), Q.complex(x)) is None + assert ask(Q.hermitian(I*x), Q.hermitian(x)) is False + assert ask(Q.hermitian(I*x), Q.imaginary(x)) is True + assert ask(Q.hermitian(I*x), Q.real(x)) is False + assert ask(Q.hermitian(x*y), Q.hermitian(x) & Q.real(y)) is True + + assert ask( + Q.hermitian(x + y + z), Q.real(x) & Q.real(y) & Q.real(z)) is True + assert ask(Q.hermitian(x + y + z), + Q.real(x) & Q.real(y) & Q.imaginary(z)) is False + assert ask(Q.hermitian(x + y + z), + Q.real(x) & Q.imaginary(y) & Q.imaginary(z)) is None + assert ask(Q.hermitian(x + y + z), + Q.imaginary(x) & Q.imaginary(y) & Q.imaginary(z)) is None + + assert ask(Q.antihermitian(x)) is None + assert ask(Q.antihermitian(x), Q.real(x)) is False + assert ask(Q.antihermitian(x), Q.prime(x)) is False + + assert ask(Q.antihermitian(x + 1), Q.antihermitian(x)) is False + assert ask(Q.antihermitian(x + 1), Q.complex(x)) is None + assert ask(Q.antihermitian(x + 1), Q.hermitian(x)) is None + assert ask(Q.antihermitian(x + 1), Q.imaginary(x)) is False + assert ask(Q.antihermitian(x + 1), Q.real(x)) is None + assert ask(Q.antihermitian(x + I), Q.antihermitian(x)) is True + assert ask(Q.antihermitian(x + I), Q.complex(x)) is None + assert ask(Q.antihermitian(x + I), Q.hermitian(x)) is False + assert ask(Q.antihermitian(x + I), Q.imaginary(x)) is True + assert ask(Q.antihermitian(x + I), Q.real(x)) is False + + assert ask( + Q.antihermitian(x + y), Q.antihermitian(x) & Q.antihermitian(y) + ) is True + assert ask( + Q.antihermitian(x + y), Q.antihermitian(x) & Q.complex(y)) is None + assert ask( + Q.antihermitian(x + y), Q.antihermitian(x) & Q.hermitian(y)) is False + assert ask( + Q.antihermitian(x + y), Q.antihermitian(x) & Q.imaginary(y)) is True + assert ask(Q.antihermitian(x + y), Q.antihermitian(x) & Q.real(y) + ) is False + assert ask(Q.antihermitian(x + y), Q.hermitian(x) & Q.complex(y)) is None + assert ask(Q.antihermitian(x + y), Q.hermitian(x) & Q.hermitian(y) + ) is None + assert ask( + Q.antihermitian(x + y), Q.hermitian(x) & Q.imaginary(y)) is False + assert ask(Q.antihermitian(x + y), Q.hermitian(x) & Q.real(y)) is None + assert ask(Q.antihermitian(x + y), Q.imaginary(x) & Q.complex(y)) is None + assert ask(Q.antihermitian(x + y), Q.imaginary(x) & Q.imaginary(y)) is True + assert ask(Q.antihermitian(x + y), Q.imaginary(x) & Q.real(y)) is False + assert ask(Q.antihermitian(x + y), Q.real(x) & Q.complex(y)) is None + assert ask(Q.antihermitian(x + y), Q.real(x) & Q.real(y)) is None + + assert ask(Q.antihermitian(I*x), Q.real(x)) is True + assert ask(Q.antihermitian(I*x), Q.antihermitian(x)) is False + assert ask(Q.antihermitian(I*x), Q.complex(x)) is None + assert ask(Q.antihermitian(x*y), Q.antihermitian(x) & Q.real(y)) is True + + assert ask(Q.antihermitian(x + y + z), + Q.real(x) & Q.real(y) & Q.real(z)) is None + assert ask(Q.antihermitian(x + y + z), + Q.real(x) & Q.real(y) & Q.imaginary(z)) is None + assert ask(Q.antihermitian(x + y + z), + Q.real(x) & Q.imaginary(y) & Q.imaginary(z)) is False + assert ask(Q.antihermitian(x + y + z), + Q.imaginary(x) & Q.imaginary(y) & Q.imaginary(z)) is True + def test_imaginary(): - assert ask(Q.imaginary(x)) == None - assert ask(Q.imaginary(x), Q.real(x)) == False - assert ask(Q.imaginary(x), Q.prime(x)) == False - - assert ask(Q.imaginary(x+1), Q.real(x)) == False - assert ask(Q.imaginary(x+1), Q.imaginary(x)) == False - assert ask(Q.imaginary(x+I), Q.real(x)) == False - assert ask(Q.imaginary(x+I), Q.imaginary(x)) == True - assert ask(Q.imaginary(x+y), Q.imaginary(x) & Q.imaginary(y)) == True - assert ask(Q.imaginary(x+y), Q.real(x) & Q.real(y)) == False - assert ask(Q.imaginary(x+y), Q.imaginary(x) & Q.real(y)) == False - assert ask(Q.imaginary(x+y), Q.complex(x) & Q.real(y)) == None - - assert ask(Q.imaginary(I*x), Q.real(x)) == True - assert ask(Q.imaginary(I*x), Q.imaginary(x)) == False - assert ask(Q.imaginary(I*x), Q.complex(x)) == None - assert ask(Q.imaginary(x*y), Q.imaginary(x) & Q.real(y)) == True - - assert ask(Q.imaginary(x+y+z), Q.real(x) & Q.real(y) & Q.real(z)) == False - assert ask(Q.imaginary(x+y+z), Q.real(x) & Q.real(y) & Q.imaginary(z)) == None - assert ask(Q.imaginary(x+y+z), Q.real(x) & Q.imaginary(y) & Q.imaginary(z)) == False + assert ask(Q.imaginary(x)) is None + assert ask(Q.imaginary(x), Q.real(x)) is False + assert ask(Q.imaginary(x), Q.prime(x)) is False + + assert ask(Q.imaginary(x + 1), Q.real(x)) is False + assert ask(Q.imaginary(x + 1), Q.imaginary(x)) is False + assert ask(Q.imaginary(x + I), Q.real(x)) is False + assert ask(Q.imaginary(x + I), Q.imaginary(x)) is True + assert ask(Q.imaginary(x + y), Q.imaginary(x) & Q.imaginary(y)) is True + assert ask(Q.imaginary(x + y), Q.real(x) & Q.real(y)) is False + assert ask(Q.imaginary(x + y), Q.imaginary(x) & Q.real(y)) is False + assert ask(Q.imaginary(x + y), Q.complex(x) & Q.real(y)) is None + + assert ask(Q.imaginary(I*x), Q.real(x)) is True + assert ask(Q.imaginary(I*x), Q.imaginary(x)) is False + assert ask(Q.imaginary(I*x), Q.complex(x)) is None + assert ask(Q.imaginary(I**x), Q.negative(x)) is None + assert ask(Q.imaginary(I**x), Q.positive(x)) is None + assert ask(Q.imaginary(I**x), Q.even(x)) is False + assert ask(Q.imaginary(I**y), Q.odd(y)) is True + assert ask(Q.imaginary(x*y), Q.imaginary(x) & Q.real(y)) is True + + assert ask( + Q.imaginary(x + y + z), Q.real(x) & Q.real(y) & Q.real(z)) is False + assert ask(Q.imaginary(x + y + z), + Q.real(x) & Q.real(y) & Q.imaginary(z)) is None + assert ask(Q.imaginary(x + y + z), + Q.real(x) & Q.imaginary(y) & Q.imaginary(z)) is False + assert ask(Q.imaginary(x**0), Q.imaginary(x)) is False + assert ask(Q.imaginary(x**y), Q.imaginary(x) & Q.imaginary(y)) is None + assert ask(Q.imaginary(x**y), Q.imaginary(x) & Q.real(y)) is None + assert ask(Q.imaginary(x**y), Q.real(x) & Q.imaginary(y)) is None + assert ask(Q.imaginary(x**y), Q.real(x) & Q.real(y)) is None + assert ask(Q.imaginary(x**y), Q.imaginary(x) & Q.integer(y)) is None + assert ask(Q.imaginary(x**y), Q.imaginary(y) & Q.integer(x)) is None + assert ask(Q.imaginary(x**y), Q.imaginary(x) & Q.odd(y)) is True + assert ask(Q.imaginary(x**y), Q.imaginary(x) & Q.rational(y)) is None + assert ask(Q.imaginary(x**y), Q.imaginary(x) & Q.even(y)) is False + assert ask(Q.imaginary(x**y), Q.real(x) & Q.integer(y)) is False + assert ask(Q.imaginary(x**y), Q.positive(x) & Q.real(y)) is False + assert ask(Q.imaginary(x**y), Q.negative(x) & Q.real(y)) is True + assert ask(Q.imaginary(x**y), Q.integer(x) & Q.imaginary(y)) is None + assert ask(Q.imaginary(x**(y/z)), Q.real(x) & Q.real(y/z) & Q.rational(y/z) & Q.even(z) & Q.negative(x)) is True + assert ask(Q.imaginary(x**(y/z)), Q.real(x) & Q.rational(y/z) & Q.even(z) & Q.negative(x)) is True + assert ask(Q.imaginary(x**(y/z)), Q.real(x) & Q.integer(y/z)) is False + assert ask(Q.imaginary(x**(y/z)), Q.real(x) & Q.real(y/z) & Q.positive(x)) is False + assert ask(Q.imaginary(x**(y/z)), Q.real(x) & Q.real(y/z) & Q.negative(x)) is True + def test_infinitesimal(): - assert ask(Q.infinitesimal(x)) == None - assert ask(Q.infinitesimal(x), Q.infinitesimal(x)) == True + assert ask(Q.infinitesimal(x)) is None + assert ask(Q.infinitesimal(x), Q.infinitesimal(x)) is True + + assert ask(Q.infinitesimal(2*x), Q.infinitesimal(x)) is True + assert ask(Q.infinitesimal(x*y), Q.infinitesimal(x)) is None + assert ask( + Q.infinitesimal(x*y), Q.infinitesimal(x) & Q.infinitesimal(y)) is True + assert ask(Q.infinitesimal(x*y), Q.infinitesimal(x) & Q.bounded(y)) is True - assert ask(Q.infinitesimal(2*x), Q.infinitesimal(x)) == True - assert ask(Q.infinitesimal(x*y), Q.infinitesimal(x)) == None - assert ask(Q.infinitesimal(x*y), Q.infinitesimal(x) & Q.infinitesimal(y)) == True - assert ask(Q.infinitesimal(x*y), Q.infinitesimal(x) & Q.bounded(y)) == True + assert ask(Q.infinitesimal(x**2), Q.infinitesimal(x)) is True - assert ask(Q.infinitesimal(x**2), Q.infinitesimal(x)) == True def test_integer(): - assert ask(Q.integer(x)) == None - assert ask(Q.integer(x), Q.integer(x)) == True - assert ask(Q.integer(x), ~Q.integer(x)) == False - assert ask(Q.integer(x), ~Q.real(x)) == False - assert ask(Q.integer(x), ~Q.positive(x)) == None - assert ask(Q.integer(x), Q.even(x) | Q.odd(x)) == True - - assert ask(Q.integer(2*x), Q.integer(x)) == True - assert ask(Q.integer(2*x), Q.even(x)) == True - assert ask(Q.integer(2*x), Q.prime(x)) == True - assert ask(Q.integer(2*x), Q.rational(x)) == None - assert ask(Q.integer(2*x), Q.real(x)) == None - assert ask(Q.integer(sqrt(2)*x), Q.integer(x)) == False - - assert ask(Q.integer(x/2), Q.odd(x)) == False - assert ask(Q.integer(x/2), Q.even(x)) == True - assert ask(Q.integer(x/3), Q.odd(x)) == None - assert ask(Q.integer(x/3), Q.even(x)) == None + assert ask(Q.integer(x)) is None + assert ask(Q.integer(x), Q.integer(x)) is True + assert ask(Q.integer(x), ~Q.integer(x)) is False + assert ask(Q.integer(x), ~Q.real(x)) is False + assert ask(Q.integer(x), ~Q.positive(x)) is None + assert ask(Q.integer(x), Q.even(x) | Q.odd(x)) is True + + assert ask(Q.integer(2*x), Q.integer(x)) is True + assert ask(Q.integer(2*x), Q.even(x)) is True + assert ask(Q.integer(2*x), Q.prime(x)) is True + assert ask(Q.integer(2*x), Q.rational(x)) is None + assert ask(Q.integer(2*x), Q.real(x)) is None + assert ask(Q.integer(sqrt(2)*x), Q.integer(x)) is False + + assert ask(Q.integer(x/2), Q.odd(x)) is False + assert ask(Q.integer(x/2), Q.even(x)) is True + assert ask(Q.integer(x/3), Q.odd(x)) is None + assert ask(Q.integer(x/3), Q.even(x)) is None + def test_negative(): - assert ask(Q.negative(x), Q.negative(x)) == True - assert ask(Q.negative(x), Q.positive(x)) == False - assert ask(Q.negative(x), ~Q.real(x)) == False - assert ask(Q.negative(x), Q.prime(x)) == False - assert ask(Q.negative(x), ~Q.prime(x)) == None - - assert ask(Q.negative(-x), Q.positive(x)) == True - assert ask(Q.negative(-x), ~Q.positive(x)) == None - assert ask(Q.negative(-x), Q.negative(x)) == False - assert ask(Q.negative(-x), Q.positive(x)) == True - - assert ask(Q.negative(x-1), Q.negative(x)) == True - assert ask(Q.negative(x+y)) == None - assert ask(Q.negative(x+y), Q.negative(x)) == None - assert ask(Q.negative(x+y), Q.negative(x) & Q.negative(y)) == True - - assert ask(Q.negative(x**2)) == None - assert ask(Q.negative(x**2), Q.real(x)) == False - assert ask(Q.negative(x**1.4), Q.real(x)) == None - - assert ask(Q.negative(x*y)) == None - assert ask(Q.negative(x*y), Q.positive(x) & Q.positive(y)) == False - assert ask(Q.negative(x*y), Q.positive(x) & Q.negative(y)) == True - assert ask(Q.negative(x*y), Q.complex(x) & Q.complex(y)) == None - - assert ask(Q.negative(x**y)) == None - assert ask(Q.negative(x**y), Q.negative(x) & Q.even(y)) == False - assert ask(Q.negative(x**y), Q.negative(x) & Q.odd(y)) == True - assert ask(Q.negative(x**y), Q.positive(x) & Q.integer(y)) == False + assert ask(Q.negative(x), Q.negative(x)) is True + assert ask(Q.negative(x), Q.positive(x)) is False + assert ask(Q.negative(x), ~Q.real(x)) is False + assert ask(Q.negative(x), Q.prime(x)) is False + assert ask(Q.negative(x), ~Q.prime(x)) is None + + assert ask(Q.negative(-x), Q.positive(x)) is True + assert ask(Q.negative(-x), ~Q.positive(x)) is None + assert ask(Q.negative(-x), Q.negative(x)) is False + assert ask(Q.negative(-x), Q.positive(x)) is True + + assert ask(Q.negative(x - 1), Q.negative(x)) is True + assert ask(Q.negative(x + y)) is None + assert ask(Q.negative(x + y), Q.negative(x)) is None + assert ask(Q.negative(x + y), Q.negative(x) & Q.negative(y)) is True + + assert ask(Q.negative(x**2)) is None + assert ask(Q.negative(x**2), Q.real(x)) is False + assert ask(Q.negative(x**1.4), Q.real(x)) is None + + assert ask(Q.negative(x*y)) is None + assert ask(Q.negative(x*y), Q.positive(x) & Q.positive(y)) is False + assert ask(Q.negative(x*y), Q.positive(x) & Q.negative(y)) is True + assert ask(Q.negative(x*y), Q.complex(x) & Q.complex(y)) is None + + assert ask(Q.negative(x**y)) is None + assert ask(Q.negative(x**y), Q.negative(x) & Q.even(y)) is False + assert ask(Q.negative(x**y), Q.negative(x) & Q.odd(y)) is True + assert ask(Q.negative(x**y), Q.positive(x) & Q.integer(y)) is False + + assert ask(Q.negative(Abs(x))) is False - assert ask(Q.negative(Abs(x))) == False def test_nonzero(): - assert ask(Q.nonzero(x)) == None - assert ask(Q.nonzero(x), Q.real(x)) == None - assert ask(Q.nonzero(x), Q.positive(x)) == True - assert ask(Q.nonzero(x), Q.negative(x)) == True - assert ask(Q.nonzero(x), Q.negative(x) | Q.positive(x)) == True - - assert ask(Q.nonzero(x+y)) == None - assert ask(Q.nonzero(x+y), Q.positive(x) & Q.positive(y)) == True - assert ask(Q.nonzero(x+y), Q.positive(x) & Q.negative(y)) == None - assert ask(Q.nonzero(x+y), Q.negative(x) & Q.negative(y)) == True - - assert ask(Q.nonzero(2*x)) == None - assert ask(Q.nonzero(2*x), Q.positive(x)) == True - assert ask(Q.nonzero(2*x), Q.negative(x)) == True - assert ask(Q.nonzero(x*y), Q.nonzero(x)) == None - assert ask(Q.nonzero(x*y), Q.nonzero(x) & Q.nonzero(y)) == True + assert ask(Q.nonzero(x)) is None + assert ask(Q.nonzero(x), Q.real(x)) is None + assert ask(Q.nonzero(x), Q.positive(x)) is True + assert ask(Q.nonzero(x), Q.negative(x)) is True + assert ask(Q.nonzero(x), Q.negative(x) | Q.positive(x)) is True + + assert ask(Q.nonzero(x + y)) is None + assert ask(Q.nonzero(x + y), Q.positive(x) & Q.positive(y)) is True + assert ask(Q.nonzero(x + y), Q.positive(x) & Q.negative(y)) is None + assert ask(Q.nonzero(x + y), Q.negative(x) & Q.negative(y)) is True + + assert ask(Q.nonzero(2*x)) is None + assert ask(Q.nonzero(2*x), Q.positive(x)) is True + assert ask(Q.nonzero(2*x), Q.negative(x)) is True + assert ask(Q.nonzero(x*y), Q.nonzero(x)) is None + assert ask(Q.nonzero(x*y), Q.nonzero(x) & Q.nonzero(y)) is True + + assert ask(Q.nonzero(Abs(x))) is None + assert ask(Q.nonzero(Abs(x)), Q.nonzero(x)) is True - assert ask(Q.nonzero(Abs(x))) == None - assert ask(Q.nonzero(Abs(x)), Q.nonzero(x)) == True def test_odd(): - assert ask(Q.odd(x)) == None - assert ask(Q.odd(x), Q.odd(x)) == True - assert ask(Q.odd(x), Q.integer(x)) == None - assert ask(Q.odd(x), ~Q.integer(x)) == False - assert ask(Q.odd(x), Q.rational(x)) == None - assert ask(Q.odd(x), Q.positive(x)) == None - - assert ask(Q.odd(-x), Q.odd(x)) == True - - assert ask(Q.odd(2*x)) == None - assert ask(Q.odd(2*x), Q.integer(x)) == False - assert ask(Q.odd(2*x), Q.odd(x)) == False - assert ask(Q.odd(2*x), Q.irrational(x)) == False - assert ask(Q.odd(2*x), ~Q.integer(x)) == None - assert ask(Q.odd(3*x), Q.integer(x)) == None - - assert ask(Q.odd(x/3), Q.odd(x)) == None - assert ask(Q.odd(x/3), Q.even(x)) == None - - assert ask(Q.odd(x+1), Q.even(x)) == True - assert ask(Q.odd(x+2), Q.even(x)) == False - assert ask(Q.odd(x+2), Q.odd(x)) == True - assert ask(Q.odd(3-x), Q.odd(x)) == False - assert ask(Q.odd(3-x), Q.even(x)) == True - assert ask(Q.odd(3+x), Q.odd(x)) == False - assert ask(Q.odd(3+x), Q.even(x)) == True - assert ask(Q.odd(x+y), Q.odd(x) & Q.odd(y)) == False - assert ask(Q.odd(x+y), Q.odd(x) & Q.even(y)) == True - assert ask(Q.odd(x-y), Q.even(x) & Q.odd(y)) == True - assert ask(Q.odd(x-y), Q.odd(x) & Q.odd(y)) == False - - assert ask(Q.odd(x+y+z), Q.odd(x) & Q.odd(y) & Q.even(z)) == False - assert ask(Q.odd(x+y+z+t), Q.odd(x) & Q.odd(y) & Q.even(z) & Q.integer(t)) == None - - assert ask(Q.odd(2*x + 1), Q.integer(x)) == True - assert ask(Q.odd(2*x + y), Q.integer(x) & Q.odd(y)) == True - assert ask(Q.odd(2*x + y), Q.integer(x) & Q.even(y)) == False - assert ask(Q.odd(2*x + y), Q.integer(x) & Q.integer(y)) == None - assert ask(Q.odd(x*y), Q.odd(x) & Q.even(y)) == False - assert ask(Q.odd(x*y), Q.odd(x) & Q.odd(y)) == True - assert ask(Q.odd(2*x*y), Q.rational(x) & Q.rational(x)) == None - assert ask(Q.odd(2*x*y), Q.irrational(x) & Q.irrational(x)) == None + assert ask(Q.odd(x)) is None + assert ask(Q.odd(x), Q.odd(x)) is True + assert ask(Q.odd(x), Q.integer(x)) is None + assert ask(Q.odd(x), ~Q.integer(x)) is False + assert ask(Q.odd(x), Q.rational(x)) is None + assert ask(Q.odd(x), Q.positive(x)) is None + + assert ask(Q.odd(-x), Q.odd(x)) is True + + assert ask(Q.odd(2*x)) is None + assert ask(Q.odd(2*x), Q.integer(x)) is False + assert ask(Q.odd(2*x), Q.odd(x)) is False + assert ask(Q.odd(2*x), Q.irrational(x)) is False + assert ask(Q.odd(2*x), ~Q.integer(x)) is None + assert ask(Q.odd(3*x), Q.integer(x)) is None + + assert ask(Q.odd(x/3), Q.odd(x)) is None + assert ask(Q.odd(x/3), Q.even(x)) is None + + assert ask(Q.odd(x + 1), Q.even(x)) is True + assert ask(Q.odd(x + 2), Q.even(x)) is False + assert ask(Q.odd(x + 2), Q.odd(x)) is True + assert ask(Q.odd(3 - x), Q.odd(x)) is False + assert ask(Q.odd(3 - x), Q.even(x)) is True + assert ask(Q.odd(3 + x), Q.odd(x)) is False + assert ask(Q.odd(3 + x), Q.even(x)) is True + assert ask(Q.odd(x + y), Q.odd(x) & Q.odd(y)) is False + assert ask(Q.odd(x + y), Q.odd(x) & Q.even(y)) is True + assert ask(Q.odd(x - y), Q.even(x) & Q.odd(y)) is True + assert ask(Q.odd(x - y), Q.odd(x) & Q.odd(y)) is False + + assert ask(Q.odd(x + y + z), Q.odd(x) & Q.odd(y) & Q.even(z)) is False + assert ask(Q.odd(x + y + z + t), + Q.odd(x) & Q.odd(y) & Q.even(z) & Q.integer(t)) is None + + assert ask(Q.odd(2*x + 1), Q.integer(x)) is True + assert ask(Q.odd(2*x + y), Q.integer(x) & Q.odd(y)) is True + assert ask(Q.odd(2*x + y), Q.integer(x) & Q.even(y)) is False + assert ask(Q.odd(2*x + y), Q.integer(x) & Q.integer(y)) is None + assert ask(Q.odd(x*y), Q.odd(x) & Q.even(y)) is False + assert ask(Q.odd(x*y), Q.odd(x) & Q.odd(y)) is True + assert ask(Q.odd(2*x*y), Q.rational(x) & Q.rational(x)) is None + assert ask(Q.odd(2*x*y), Q.irrational(x) & Q.irrational(x)) is None + + assert ask(Q.odd(Abs(x)), Q.odd(x)) is True - assert ask(Q.odd(Abs(x)), Q.odd(x)) == True def test_prime(): - assert ask(Q.prime(x), Q.prime(x)) == True - assert ask(Q.prime(x), ~Q.prime(x)) == False - assert ask(Q.prime(x), Q.integer(x)) == None - assert ask(Q.prime(x), ~Q.integer(x)) == False - - assert ask(Q.prime(2*x), Q.integer(x)) == False - assert ask(Q.prime(x*y)) == None - assert ask(Q.prime(x*y), Q.prime(x)) == None - assert ask(Q.prime(x*y), Q.integer(x) & Q.integer(y)) == False - - assert ask(Q.prime(x**2), Q.integer(x)) == False - assert ask(Q.prime(x**2), Q.prime(x)) == False - assert ask(Q.prime(x**y), Q.integer(x) & Q.integer(y)) == False + assert ask(Q.prime(x), Q.prime(x)) is True + assert ask(Q.prime(x), ~Q.prime(x)) is False + assert ask(Q.prime(x), Q.integer(x)) is None + assert ask(Q.prime(x), ~Q.integer(x)) is False + + assert ask(Q.prime(2*x), Q.integer(x)) is False + assert ask(Q.prime(x*y)) is None + assert ask(Q.prime(x*y), Q.prime(x)) is None + assert ask(Q.prime(x*y), Q.integer(x) & Q.integer(y)) is False + + assert ask(Q.prime(x**2), Q.integer(x)) is False + assert ask(Q.prime(x**2), Q.prime(x)) is False + assert ask(Q.prime(x**y), Q.integer(x) & Q.integer(y)) is False + def test_positive(): - assert ask(Q.positive(x), Q.positive(x)) == True - assert ask(Q.positive(x), Q.negative(x)) == False - assert ask(Q.positive(x), Q.nonzero(x)) == None - - assert ask(Q.positive(-x), Q.positive(x)) == False - assert ask(Q.positive(-x), Q.negative(x)) == True - - assert ask(Q.positive(x+y), Q.positive(x) & Q.positive(y)) == True - assert ask(Q.positive(x+y), Q.positive(x) & Q.negative(y)) == None - - assert ask(Q.positive(2*x), Q.positive(x)) == True - assumptions = Q.positive(x) & Q.negative(y) & Q.negative(z) & Q.positive(w) - assert ask(Q.positive(x*y*z)) == None - assert ask(Q.positive(x*y*z), assumptions) == True - assert ask(Q.positive(-x*y*z), assumptions) == False + assert ask(Q.positive(x), Q.positive(x)) is True + assert ask(Q.positive(x), Q.negative(x)) is False + assert ask(Q.positive(x), Q.nonzero(x)) is None + + assert ask(Q.positive(-x), Q.positive(x)) is False + assert ask(Q.positive(-x), Q.negative(x)) is True + + assert ask(Q.positive(x + y), Q.positive(x) & Q.positive(y)) is True + assert ask(Q.positive(x + y), Q.positive(x) & Q.negative(y)) is None + + assert ask(Q.positive(2*x), Q.positive(x)) is True + assumptions = Q.positive(x) & Q.negative(y) & Q.negative(z) & Q.positive(w) + assert ask(Q.positive(x*y*z)) is None + assert ask(Q.positive(x*y*z), assumptions) is True + assert ask(Q.positive(-x*y*z), assumptions) is False - assert ask(Q.positive(x**2), Q.positive(x)) == True - assert ask(Q.positive(x**2), Q.negative(x)) == True + assert ask(Q.positive(x**2), Q.positive(x)) is True + assert ask(Q.positive(x**2), Q.negative(x)) is True #exponential - assert ask(Q.positive(exp(x)), Q.real(x)) == True - assert ask(Q.positive(x + exp(x)), Q.real(x)) == None + assert ask(Q.positive(exp(x)), Q.real(x)) is True + assert ask(~Q.negative(exp(x)), Q.real(x)) is True + assert ask(Q.positive(x + exp(x)), Q.real(x)) is None #absolute value - assert ask(Q.positive(Abs(x))) == None # Abs(0) = 0 - assert ask(Q.positive(Abs(x)), Q.positive(x)) == True + assert ask(Q.positive(Abs(x))) is None # Abs(0) = 0 + assert ask(Q.positive(Abs(x)), Q.positive(x)) is True + @XFAIL def test_positive_xfail(): - assert ask(Q.positive(1/(1 + x**2)), Q.real(x)) == True + assert ask(Q.positive(1/(1 + x**2)), Q.real(x)) is True + def test_real(): - assert ask(Q.real(x)) == None - assert ask(Q.real(x), Q.real(x)) == True - assert ask(Q.real(x), Q.nonzero(x)) == True - assert ask(Q.real(x), Q.positive(x)) == True - assert ask(Q.real(x), Q.negative(x)) == True - assert ask(Q.real(x), Q.integer(x)) == True - assert ask(Q.real(x), Q.even(x)) == True - assert ask(Q.real(x), Q.prime(x)) == True - - assert ask(Q.real(x/sqrt(2)), Q.real(x)) == True - assert ask(Q.real(x/sqrt(-2)), Q.real(x)) == False - - assert ask(Q.real(x+1), Q.real(x)) == True - assert ask(Q.real(x+I), Q.real(x)) == False - assert ask(Q.real(x+I), Q.complex(x)) == None - - assert ask(Q.real(2*x), Q.real(x)) == True - assert ask(Q.real(I*x), Q.real(x)) == False - assert ask(Q.real(I*x), Q.imaginary(x)) == True - assert ask(Q.real(I*x), Q.complex(x)) == None - - assert ask(Q.real(x**2), Q.real(x)) == True - assert ask(Q.real(sqrt(x)), Q.negative(x)) == False - assert ask(Q.real(x**y), Q.real(x) & Q.integer(y)) == True - assert ask(Q.real(x**y), Q.real(x) & Q.real(y)) == None - assert ask(Q.real(x**y), Q.positive(x) & Q.real(y)) == True + assert ask(Q.real(x)) is None + assert ask(Q.real(x), Q.real(x)) is True + assert ask(Q.real(x), Q.nonzero(x)) is True + assert ask(Q.real(x), Q.positive(x)) is True + assert ask(Q.real(x), Q.negative(x)) is True + assert ask(Q.real(x), Q.integer(x)) is True + assert ask(Q.real(x), Q.even(x)) is True + assert ask(Q.real(x), Q.prime(x)) is True + + assert ask(Q.real(x/sqrt(2)), Q.real(x)) is True + assert ask(Q.real(x/sqrt(-2)), Q.real(x)) is False + + assert ask(Q.real(x + 1), Q.real(x)) is True + assert ask(Q.real(x + I), Q.real(x)) is False + assert ask(Q.real(x + I), Q.complex(x)) is None + + assert ask(Q.real(2*x), Q.real(x)) is True + assert ask(Q.real(I*x), Q.real(x)) is False + assert ask(Q.real(I*x), Q.imaginary(x)) is True + assert ask(Q.real(I*x), Q.complex(x)) is None + + assert ask(Q.real(x**2), Q.real(x)) is True + assert ask(Q.real(sqrt(x)), Q.negative(x)) is False + assert ask(Q.real(x**y), Q.real(x) & Q.integer(y)) is True + assert ask(Q.real(x**y), Q.real(x) & Q.real(y)) is None + assert ask(Q.real(x**y), Q.positive(x) & Q.real(y)) is True + assert ask(Q.real(x**y), Q.imaginary(x) & Q.imaginary(y)) is None + assert ask(Q.real(x**y), Q.imaginary(x) & Q.real(y)) is None + assert ask(Q.real(x**y), Q.real(x) & Q.imaginary(y)) is None + assert ask(Q.real(x**0), Q.imaginary(x)) is True + assert ask(Q.real(x**y), Q.real(x) & Q.integer(y)) is True + assert ask(Q.real(x**y), Q.positive(x) & Q.real(y)) is True + assert ask(Q.real(x**y), Q.real(x) & Q.rational(y)) is None + assert ask(Q.real(x**y), Q.imaginary(x) & Q.integer(y)) is None + assert ask(Q.real(x**y), Q.imaginary(x) & Q.odd(y)) is False + assert ask(Q.real(x**y), Q.imaginary(x) & Q.even(y)) is True + assert ask(Q.real(x**(y/z)), Q.real(x) & Q.real(y/z) & Q.rational(y/z) & Q.even(z) & Q.positive(x)) is True + assert ask(Q.real(x**(y/z)), Q.real(x) & Q.rational(y/z) & Q.even(z) & Q.negative(x)) is False + assert ask(Q.real(x**(y/z)), Q.real(x) & Q.integer(y/z)) is True + assert ask(Q.real(x**(y/z)), Q.real(x) & Q.real(y/z) & Q.positive(x)) is True + assert ask(Q.real(x**(y/z)), Q.real(x) & Q.real(y/z) & Q.negative(x)) is False # trigonometric functions - assert ask(Q.real(sin(x))) == None - assert ask(Q.real(cos(x))) == None - assert ask(Q.real(sin(x)), Q.real(x)) == True - assert ask(Q.real(cos(x)), Q.real(x)) == True + assert ask(Q.real(sin(x))) is None + assert ask(Q.real(cos(x))) is None + assert ask(Q.real(sin(x)), Q.real(x)) is True + assert ask(Q.real(cos(x)), Q.real(x)) is True # exponential function - assert ask(Q.real(exp(x))) == None - assert ask(Q.real(exp(x)), Q.real(x)) == True - assert ask(Q.real(x + exp(x)), Q.real(x)) == True + assert ask(Q.real(exp(x))) is None + assert ask(Q.real(exp(x)), Q.real(x)) is True + assert ask(Q.real(x + exp(x)), Q.real(x)) is True # Q.complexes - assert ask(Q.real(re(x))) == True - assert ask(Q.real(im(x))) == True - -def test_algebraic(): - assert ask(Q.algebraic(x)) == None + assert ask(Q.real(re(x))) is True + assert ask(Q.real(im(x))) is True - assert ask(Q.algebraic(I)) == True - assert ask(Q.algebraic(2*I)) == True - assert ask(Q.algebraic(I/3)) == True - assert ask(Q.algebraic(sqrt(7))) == True - assert ask(Q.algebraic(2*sqrt(7))) == True - assert ask(Q.algebraic(sqrt(7)/3)) == True - - assert ask(Q.algebraic(I*sqrt(3))) == True - assert ask(Q.algebraic(sqrt(1+I*sqrt(3)))) == True +def test_algebraic(): + assert ask(Q.algebraic(x)) is None - assert ask(Q.algebraic((1+I*sqrt(3)**(S(17)/31)))) == True - assert ask(Q.algebraic((1+I*sqrt(3)**(S(17)/pi)))) == False + assert ask(Q.algebraic(I)) is True + assert ask(Q.algebraic(2*I)) is True + assert ask(Q.algebraic(I/3)) is True + + assert ask(Q.algebraic(sqrt(7))) is True + assert ask(Q.algebraic(2*sqrt(7))) is True + assert ask(Q.algebraic(sqrt(7)/3)) is True + + assert ask(Q.algebraic(I*sqrt(3))) is True + assert ask(Q.algebraic(sqrt(1 + I*sqrt(3)))) is True + + assert ask(Q.algebraic((1 + I*sqrt(3)**(S(17)/31)))) is True + assert ask(Q.algebraic((1 + I*sqrt(3)**(S(17)/pi)))) is False + + for f in [exp, sin, tan, asin, atan, cos]: + assert ask(Q.algebraic(f(7))) is False + assert ask(Q.algebraic(f(7, evaluate=False))) is False + assert ask(Q.algebraic(f(0, evaluate=False))) is True + assert ask(Q.algebraic(f(x)), Q.algebraic(x)) is None + assert ask(Q.algebraic(f(x)), Q.algebraic(x) & Q.nonzero(x)) is False + + for g in [log, acos]: + assert ask(Q.algebraic(g(7))) is False + assert ask(Q.algebraic(g(7, evaluate=False))) is False + assert ask(Q.algebraic(g(1, evaluate=False))) is True + assert ask(Q.algebraic(g(x)), Q.algebraic(x)) is None + assert ask(Q.algebraic(g(x)), Q.algebraic(x) & Q.nonzero(x - 1)) is False + + for h in [cot, acot]: + assert ask(Q.algebraic(h(7))) is False + assert ask(Q.algebraic(h(7, evaluate=False))) is False + assert ask(Q.algebraic(h(x)), Q.algebraic(x)) is False - assert ask(Q.algebraic(sin(7))) == None - assert ask(Q.algebraic(sqrt(sin(7)))) == None - assert ask(Q.algebraic(sqrt(y+I*sqrt(7)))) == None + assert ask(Q.algebraic(sqrt(sin(7)))) is False + assert ask(Q.algebraic(sqrt(y + I*sqrt(7)))) is None - assert ask(Q.algebraic(oo)) == False - assert ask(Q.algebraic(-oo)) == False + assert ask(Q.algebraic(2.47)) is True - assert ask(Q.algebraic(2.47)) == False def test_global(): """Test ask with global assumptions""" - assert ask(Q.integer(x)) == None + assert ask(Q.integer(x)) is None global_assumptions.add(Q.integer(x)) - assert ask(Q.integer(x)) == True + assert ask(Q.integer(x)) is True global_assumptions.clear() - assert ask(Q.integer(x)) == None + assert ask(Q.integer(x)) is None + def test_custom_context(): """Test ask with custom assumptions context""" - assert ask(Q.integer(x)) == None + assert ask(Q.integer(x)) is None local_context = AssumptionsContext() local_context.add(Q.integer(x)) - assert ask(Q.integer(x), context = local_context) == True - assert ask(Q.integer(x)) == None + assert ask(Q.integer(x), context=local_context) is True + assert ask(Q.integer(x)) is None + def test_functions_in_assumptions(): assert ask(Q.negative(x), Q.real(x) >> Q.positive(x)) is False assert ask(Q.negative(x), Equivalent(Q.real(x), Q.positive(x))) is False assert ask(Q.negative(x), Xor(Q.real(x), Q.negative(x))) is False + def test_composite_ask(): assert ask(Q.negative(x) & Q.integer(x), - assumptions=Q.real(x) >> Q.positive(x)) is False + assumptions=Q.real(x) >> Q.positive(x)) is False + def test_composite_proposition(): assert ask(True) is True @@ -1338,11 +1755,19 @@ assert ask(Q.real(x) | Q.integer(x), Q.positive(x)) is True assert ask(Q.real(x) | Q.integer(x)) is None assert ask(Q.real(x) >> Q.positive(x), Q.negative(x)) is False - assert ask(Implies(Q.real(x), Q.positive(x), evaluate=False), Q.negative(x)) is False + assert ask(Implies( + Q.real(x), Q.positive(x), evaluate=False), Q.negative(x)) is False assert ask(Implies(Q.real(x), Q.positive(x), evaluate=False)) is None assert ask(Equivalent(Q.integer(x), Q.even(x)), Q.even(x)) is True assert ask(Equivalent(Q.integer(x), Q.even(x))) is None assert ask(Equivalent(Q.positive(x), Q.integer(x)), Q.integer(x)) is None + assert ask(Q.real(x) | Q.integer(x), Q.real(x) | Q.integer(x)) is True + + +def test_composite_assomption(): + assert ask(Q.positive(x), Q.positive(x) | Q.positive(y)) is None + assert ask(Q.positive(x), Q.real(x) >> Q.positive(y)) is None + def test_incompatible_resolutors(): class Prime2AskHandler(AskHandler): @@ -1358,23 +1783,26 @@ def Number(expr, assumptions): return None register_handler('prime', InconclusiveHandler) - assert ask(Q.prime(3)) == True + assert ask(Q.prime(3)) is True + def test_key_extensibility(): """test that you can add keys to the ask system at runtime""" # make sure the key is not defined raises(AttributeError, lambda: ask(Q.my_key(x))) + class MyAskHandler(AskHandler): @staticmethod def Symbol(expr, assumptions): return True register_handler('my_key', MyAskHandler) - assert ask(Q.my_key(x)) == True - assert ask(Q.my_key(x+1)) == None + assert ask(Q.my_key(x)) is True + assert ask(Q.my_key(x + 1)) is None remove_handler('my_key', MyAskHandler) del Q.my_key raises(AttributeError, lambda: ask(Q.my_key(x))) + def test_type_extensibility(): """test that new types can be added to the ask system at runtime We create a custom type MyType, and override ask Q.prime=True with handler @@ -1394,17 +1822,59 @@ a = MyType() register_handler(Q.prime, MyAskHandler) - assert ask(Q.prime(a)) == True + assert ask(Q.prime(a)) is True + + +def test_single_fact_lookup(): + known_facts = And(Implies(Q.integer, Q.rational), + Implies(Q.rational, Q.real), + Implies(Q.real, Q.complex)) + known_facts_keys = set([Q.integer, Q.rational, Q.real, Q.complex]) + + known_facts_cnf = to_cnf(known_facts) + mapping = single_fact_lookup(known_facts_keys, known_facts_cnf) + + assert mapping[Q.rational] == set([Q.real, Q.rational, Q.complex]) + def test_compute_known_facts(): + known_facts = And(Implies(Q.integer, Q.rational), + Implies(Q.rational, Q.real), + Implies(Q.real, Q.complex)) + known_facts_keys = set([Q.integer, Q.rational, Q.real, Q.complex]) + + s = compute_known_facts(known_facts, known_facts_keys) + + +def test_known_facts_consistent(): + from sympy.assumptions.ask import known_facts, known_facts_keys ns = {} exec('from sympy.logic.boolalg import And, Or, Not', globals(), ns) - exec(compute_known_facts(), globals(), ns) + exec(compute_known_facts(known_facts, known_facts_keys), globals(), ns) assert ns['known_facts_cnf'] == known_facts_cnf assert ns['known_facts_dict'] == known_facts_dict + def test_Add_queries(): assert ask(Q.prime(12345678901234567890 + (cos(1)**2 + sin(1)**2))) is True assert ask(Q.even(Add(S(2), S(2), evaluate=0))) is True assert ask(Q.prime(Add(S(2), S(2), evaluate=0))) is False assert ask(Q.integer(Add(S(2), S(2), evaluate=0))) is True + + +def test_positive(): + with assuming(Q.positive(x + 1)): + assert not ask(Q.positive(x)) + + +def test_issue_2322(): + raises(TypeError, lambda: ask(pi/log(x), Q.real)) + + +def test_issue_3906(): + raises(TypeError, lambda: ask(Q.positive)) + + +def test_issue_2734(): + assert ask(Q.positive(log(x)**2), Q.positive(x)) is None + assert ask(~Q.negative(log(x)**2), Q.positive(x)) is True diff -Nru python3-sympy-0.7.2/sympy/assumptions/tests/test_refine.py python3-sympy-0.7.3/sympy/assumptions/tests/test_refine.py --- python3-sympy-0.7.2/sympy/assumptions/tests/test_refine.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/assumptions/tests/test_refine.py 2013-07-13 17:53:31.000000000 +0000 @@ -1,15 +1,19 @@ from sympy import Abs, exp, Expr, I, pi, Q, Rational, refine, S, sqrt from sympy.abc import x, y, z +from sympy.core.relational import Eq, Ne +from sympy.functions.elementary.piecewise import Piecewise + def test_Abs(): assert refine(Abs(x), Q.positive(x)) == x - assert refine(1+Abs(x), Q.positive(x)) == 1+x + assert refine(1 + Abs(x), Q.positive(x)) == 1 + x assert refine(Abs(x), Q.negative(x)) == -x - assert refine(1+Abs(x), Q.negative(x)) == 1-x + assert refine(1 + Abs(x), Q.negative(x)) == 1 - x assert refine(Abs(x**2)) != x**2 assert refine(Abs(x**2), Q.real(x)) == x**2 + def test_pow(): assert refine((-1)**x, Q.even(x)) == 1 assert refine((-1)**x, Q.odd(x)) == -1 @@ -29,18 +33,65 @@ assert refine(sqrt(1/x), Q.positive(x)) == 1/sqrt(x) # powers of (-1) - assert refine((-1)**(x+y), Q.even(x)) == (-1)**y - assert refine((-1)**(x+y+z), Q.odd(x) & Q.odd(z))==(-1)**y - assert refine((-1)**(x+y+1), Q.odd(x))==(-1)**y - assert refine((-1)**(x+y+2), Q.odd(x))==(-1)**(y+1) - assert refine((-1)**(x+3)) == (-1)**(x+1) + assert refine((-1)**(x + y), Q.even(x)) == (-1)**y + assert refine((-1)**(x + y + z), Q.odd(x) & Q.odd(z)) == (-1)**y + assert refine((-1)**(x + y + 1), Q.odd(x)) == (-1)**y + assert refine((-1)**(x + y + 2), Q.odd(x)) == (-1)**(y + 1) + assert refine((-1)**(x + 3)) == (-1)**(x + 1) + + # powers of Abs + assert refine(Abs(x)**2, Q.real(x)) == x**2 + assert refine(Abs(x)**3, Q.real(x)) == Abs(x)**3 + assert refine(Abs(x)**2) == Abs(x)**2 def test_exp(): assert refine(exp(pi*I*2*x), Q.integer(x)) == 1 - assert refine(exp(pi*I*2*(x+Rational(1,2))), Q.integer(x)) == -1 - assert refine(exp(pi*I*2*(x+Rational(1,4))), Q.integer(x)) == I - assert refine(exp(pi*I*2*(x+Rational(3,4))), Q.integer(x)) == -I + assert refine(exp(pi*I*2*(x + Rational(1, 2))), Q.integer(x)) == -1 + assert refine(exp(pi*I*2*(x + Rational(1, 4))), Q.integer(x)) == I + assert refine(exp(pi*I*2*(x + Rational(3, 4))), Q.integer(x)) == -I + + +def test_Relational(): + assert refine(x < 0, ~Q.is_true(x < 0)) == False + assert refine(x < 0, Q.is_true(x < 0)) == True + assert refine(x < 0, Q.is_true(y < 0)) == (x < 0) + assert refine(x <= 0, ~Q.is_true(x <= 0)) == False + assert refine(x <= 0, Q.is_true(x <= 0)) == True + assert refine(x <= 0, Q.is_true(y <= 0)) == (x <= 0) + assert refine(x > 0, ~Q.is_true(x > 0)) == False + assert refine(x > 0, Q.is_true(x > 0)) == True + assert refine(x > 0, Q.is_true(y > 0)) == (x > 0) + assert refine(x >= 0, ~Q.is_true(x >= 0)) == False + assert refine(x >= 0, Q.is_true(x >= 0)) == True + assert refine(x >= 0, Q.is_true(y >= 0)) == (x >= 0) + assert refine(Eq(x, 0), ~Q.is_true(Eq(x, 0))) == False + assert refine(Eq(x, 0), Q.is_true(Eq(x, 0))) == True + assert refine(Eq(x, 0), Q.is_true(Eq(y, 0))) == Eq(x, 0) + assert refine(Ne(x, 0), ~Q.is_true(Ne(x, 0))) == False + assert refine(Ne(x, 0), Q.is_true(Ne(x, 0))) == True + assert refine(Ne(x, 0), Q.is_true(Ne(y, 0))) == (Ne(x, 0)) + + +def test_Piecewise(): + assert refine(Piecewise((1, x < 0), (3, True)), Q.is_true(x < 0)) == 1 + assert refine(Piecewise((1, x < 0), (3, True)), ~Q.is_true(x < 0)) == 3 + assert refine(Piecewise((1, x < 0), (3, True)), Q.is_true(y < 0)) == Piecewise((1, x < 0), (3, True)) + assert refine(Piecewise((1, x > 0), (3, True)), Q.is_true(x > 0)) == 1 + assert refine(Piecewise((1, x > 0), (3, True)), ~Q.is_true(x > 0)) == 3 + assert refine(Piecewise((1, x > 0), (3, True)), Q.is_true(y > 0)) == Piecewise((1, x > 0), (3, True)) + assert refine(Piecewise((1, x <= 0), (3, True)), Q.is_true(x <= 0)) == 1 + assert refine(Piecewise((1, x <= 0), (3, True)), ~Q.is_true(x <= 0)) == 3 + assert refine(Piecewise((1, x <= 0), (3, True)), Q.is_true(y <= 0)) == Piecewise((1, x <= 0), (3, True)) + assert refine(Piecewise((1, x >= 0), (3, True)), Q.is_true(x >= 0)) == 1 + assert refine(Piecewise((1, x >= 0), (3, True)), ~Q.is_true(x >= 0)) == 3 + assert refine(Piecewise((1, x >= 0), (3, True)), Q.is_true(y >= 0)) == Piecewise((1, x >= 0), (3, True)) + assert refine(Piecewise((1, Eq(x, 0)), (3, True)), Q.is_true(Eq(x, 0))) == 1 + assert refine(Piecewise((1, Eq(x, 0)), (3, True)), ~Q.is_true(Eq(x, 0))) == 3 + assert refine(Piecewise((1, Eq(x, 0)), (3, True)), Q.is_true(Eq(y, 0))) == Piecewise((1, Eq(x, 0)), (3, True)) + assert refine(Piecewise((1, Ne(x, 0)), (3, True)), Q.is_true(Ne(x, 0))) == 1 + assert refine(Piecewise((1, Ne(x, 0)), (3, True)), ~Q.is_true(Ne(x, 0))) == 3 + assert refine(Piecewise((1, Ne(x, 0)), (3, True)), Q.is_true(Ne(y, 0))) == Piecewise((1, Ne(x, 0)), (3, True)) def test_func_args(): diff -Nru python3-sympy-0.7.2/sympy/categories/__init__.py python3-sympy-0.7.3/sympy/categories/__init__.py --- python3-sympy-0.7.2/sympy/categories/__init__.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/categories/__init__.py 2013-07-13 17:53:31.000000000 +0000 @@ -21,4 +21,5 @@ NamedMorphism, CompositeMorphism, Category, Diagram) -from .diagram_drawing import DiagramGrid +from .diagram_drawing import (DiagramGrid, XypicDiagramDrawer, + xypic_draw_diagram, preview_diagram) diff -Nru python3-sympy-0.7.2/sympy/categories/baseclasses.py python3-sympy-0.7.3/sympy/categories/baseclasses.py --- python3-sympy-0.7.2/sympy/categories/baseclasses.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/categories/baseclasses.py 2013-07-13 17:53:31.000000000 +0000 @@ -1,6 +1,7 @@ from sympy.core import (Set, Basic, FiniteSet, EmptySet, Dict, Symbol, Tuple) + class Class(Set): r""" The base class for any kind of class in the set-theoretic sense. @@ -16,6 +17,7 @@ """ is_proper = False + class Object(Symbol): """ The base class for any kind of object in an abstract category. @@ -25,6 +27,7 @@ abstract categories. """ + class Morphism(Basic): """ The base class for any morphism in an abstract category. @@ -127,6 +130,7 @@ """ return self.compose(other) + class IdentityMorphism(Morphism): """ Represents an identity morphism. @@ -156,6 +160,7 @@ def __new__(cls, domain): return Basic.__new__(cls, domain, domain) + class NamedMorphism(Morphism): """ Represents a morphism which has a name. @@ -204,6 +209,7 @@ """ return self.args[2].name + class CompositeMorphism(Morphism): r""" Represents a morphism which is a composition of other morphisms. @@ -268,7 +274,7 @@ following = components[i + 1] if not isinstance(current, Morphism) or \ - not isinstance(following, Morphism): + not isinstance(following, Morphism): raise TypeError("All components must be morphisms.") if current.codomain != following.domain: @@ -385,6 +391,7 @@ """ return NamedMorphism(self.domain, self.codomain, new_name) + class Category(Basic): r""" An (abstract) category. @@ -508,6 +515,7 @@ raise NotImplementedError( "Obtaining the class of morphisms is not implemented in Category.") + class Diagram(Basic): r""" Represents a diagram in a certain category. @@ -717,7 +725,7 @@ conclusions, morphism, empty, add_identities=False, recurse_composites=False) elif isinstance(conclusions_arg, dict) or \ - isinstance(conclusions_arg, Dict): + isinstance(conclusions_arg, Dict): # The user has supplied a dictionary of morphisms and # their properties. for morphism, props in list(conclusions_arg.items()): @@ -862,14 +870,14 @@ >>> d1.is_subdiagram(d) False """ - premises = all([(m in self.premises) and \ - (diagram.premises[m] == self.premises[m]) \ + premises = all([(m in self.premises) and + (diagram.premises[m] == self.premises[m]) for m in diagram.premises]) if not premises: return False - conclusions = all([(m in self.conclusions) and \ - (diagram.conclusions[m] == self.conclusions[m]) \ + conclusions = all([(m in self.conclusions) and + (diagram.conclusions[m] == self.conclusions[m]) for m in diagram.conclusions]) # Premises is surely ``True`` here. @@ -897,7 +905,8 @@ True """ if not self.objects.subset(objects): - raise ValueError("Supplied objects should all belong to the diagram.") + raise ValueError( + "Supplied objects should all belong to the diagram.") new_premises = {} for morphism, props in list(self.premises.items()): diff -Nru python3-sympy-0.7.2/sympy/categories/diagram_drawing.py python3-sympy-0.7.3/sympy/categories/diagram_drawing.py --- python3-sympy-0.7.2/sympy/categories/diagram_drawing.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/categories/diagram_drawing.py 2013-07-13 17:53:31.000000000 +0000 @@ -82,12 +82,15 @@ [Xypic] http://www.tug.org/applications/Xy-pic/ """ -from sympy.core import Basic, FiniteSet, Dict +from sympy.core import Basic, FiniteSet, Dict, Symbol from sympy.categories import (CompositeMorphism, IdentityMorphism, NamedMorphism, Diagram) from sympy.utilities import default_sort_key from itertools import chain from sympy.core.compatibility import iterable +from sympy.printing import latex +from sympy.utilities.decorator import doctest_depends_on + class _GrowableGrid(object): """ @@ -115,7 +118,6 @@ def height(self): return self._height - def __getitem__(self, xxx_todo_changeme): """ Returns the element located at in the i-th line and j-th @@ -162,6 +164,7 @@ for i in range(self._height): self._array[i].insert(0, None) + class DiagramGrid(object): r""" Constructs and holds the fitting of the diagram into a grid. @@ -282,10 +285,12 @@ See Also ======== + Diagram References ========== + [FiveLemma] http://en.wikipedia.org/wiki/Five_lemma """ @staticmethod @@ -368,7 +373,7 @@ # Create edges for morphisms. for morphism in morphisms: DiagramGrid._add_edge_append( - edges, frozenset([morphism.domain,morphism.codomain]), morphism) + edges, frozenset([morphism.domain, morphism.codomain]), morphism) # Create new edges by juxtaposing existing edges. edges1 = dict(edges) @@ -666,7 +671,8 @@ Returns a key for the supplied triangle. It should be the same independently of the hash randomisation. """ - objects = sorted(DiagramGrid._triangle_objects(tri), key=default_sort_key) + objects = sorted( + DiagramGrid._triangle_objects(tri), key=default_sort_key) return (triangle_sizes[tri], default_sort_key(objects)) @staticmethod @@ -716,7 +722,7 @@ def good_triangle(tri): objs = DiagramGrid._triangle_objects(tri) return obj in objs and \ - placed_objects & (objs - set([obj])) == set() + placed_objects & (objs - set([obj])) == set() tris = [tri for tri in triangles if good_triangle(tri)] if not tris: @@ -753,8 +759,8 @@ # Now check for free directions. When checking for # free directions, prefer the horizontal and vertical # directions. - neighbours = [(i-1, j), (i, j+1), (i+1, j), (i, j-1), - (i-1,j-1), (i-1, j+1), (i+1,j-1), (i+1, j+1)] + neighbours = [(i - 1, j), (i, j + 1), (i + 1, j), (i, j - 1), + (i - 1, j - 1), (i - 1, j + 1), (i + 1, j - 1), (i + 1, j + 1)] for pt in neighbours: if DiagramGrid._empty_point(pt, grid): @@ -897,7 +903,8 @@ local_grid = groups_grids[obj] for i in range(local_grid.height): for j in range(local_grid.width): - grid[real_row + i, real_column + j] = local_grid[i, j] + grid[real_row + i, + real_column + j] = local_grid[i, j] else: # This is an object. Just put it there. grid[real_row, real_column] = obj @@ -951,7 +958,8 @@ placed_objects = set(root_edge) while placed_objects != all_objects: - welding = DiagramGrid._find_triangle_to_weld(triangles, fringe, grid) + welding = DiagramGrid._find_triangle_to_weld( + triangles, fringe, grid) if welding: (triangle, welding_edge) = welding @@ -1055,6 +1063,7 @@ grid[0, 0] = root placed_objects = set([root]) + def place_objects(pt, placed_objects): """ Does depth-first search in the underlying graph of the @@ -1340,3 +1349,1234 @@ """ return repr(self._grid._array) + + +class ArrowStringDescription(object): + r""" + Stores the information necessary for producing an Xy-pic + description of an arrow. + + The principal goal of this class is to abstract away the string + representation of an arrow and to also provide the functionality + to produce the actual Xy-pic string. + + ``unit`` sets the unit which will be used to specify the amount of + curving and other distances. ``horizontal_direction`` should be a + string of ``"r"`` or ``"l"`` specifying the horizontal offset of the + target cell of the arrow relatively to the current one. + ``vertical_direction`` should specify the vertical offset using a + series of either ``"d"`` or ``"u"``. ``label_position`` should be + either ``"^"``, ``"_"``, or ``"|"`` to specify that the label should + be positioned above the arrow, below the arrow or just over the arrow, + in a break. Note that the notions "above" and "below" are relative + to arrow direction. ``label`` stores the morphism label. + + This works as follows (disregard the yet unexplained arguments): + + >>> from sympy.categories.diagram_drawing import ArrowStringDescription + >>> astr = ArrowStringDescription( + ... unit="mm", curving=None, curving_amount=None, + ... looping_start=None, looping_end=None, horizontal_direction="d", + ... vertical_direction="r", label_position="_", label="f") + >>> print(str(astr)) + \ar[dr]_{f} + + ``curving`` should be one of ``"^"``, ``"_"`` to specify in which + direction the arrow is going to curve. ``curving_amount`` is a number + describing how many ``unit``'s the morphism is going to curve: + + >>> astr = ArrowStringDescription( + ... unit="mm", curving="^", curving_amount=12, + ... looping_start=None, looping_end=None, horizontal_direction="d", + ... vertical_direction="r", label_position="_", label="f") + >>> print(str(astr)) + \ar@/^12mm/[dr]_{f} + + ``looping_start`` and ``looping_end`` are currently only used for + loop morphisms, those which have the same domain and codomain. + These two attributes should store a valid Xy-pic direction and + specify, correspondingly, the direction the arrow gets out into + and the direction the arrow gets back from: + + >>> astr = ArrowStringDescription( + ... unit="mm", curving=None, curving_amount=None, + ... looping_start="u", looping_end="l", horizontal_direction="", + ... vertical_direction="", label_position="_", label="f") + >>> print(str(astr)) + \ar@(u,l)[]_{f} + + ``label_displacement`` controls how far the arrow label is from + the ends of the arrow. For example, to position the arrow label + near the arrow head, use ">": + + >>> astr = ArrowStringDescription( + ... unit="mm", curving="^", curving_amount=12, + ... looping_start=None, looping_end=None, horizontal_direction="d", + ... vertical_direction="r", label_position="_", label="f") + >>> astr.label_displacement = ">" + >>> print(str(astr)) + \ar@/^12mm/[dr]_>{f} + + Finally, ``arrow_style`` is used to specify the arrow style. To + get a dashed arrow, for example, use "{-->}" as arrow style: + + >>> astr = ArrowStringDescription( + ... unit="mm", curving="^", curving_amount=12, + ... looping_start=None, looping_end=None, horizontal_direction="d", + ... vertical_direction="r", label_position="_", label="f") + >>> astr.arrow_style = "{-->}" + >>> print(str(astr)) + \ar@/^12mm/@{-->}[dr]_{f} + + Notes + ===== + + Instances of :class:`ArrowStringDescription` will be constructed + by :class:`XypicDiagramDrawer` and provided for further use in + formatters. The user is not expected to construct instances of + :class:`ArrowStringDescription` themselves. + + To be able to properly utilise this class, the reader is encouraged + to checkout the Xy-pic user guide, available at [Xypic]. + + See Also + ======== + + XypicDiagramDrawer + + References + ========== + + [Xypic] http://www.tug.org/applications/Xy-pic/ + """ + def __init__(self, unit, curving, curving_amount, looping_start, + looping_end, horizontal_direction, vertical_direction, + label_position, label): + self.unit = unit + self.curving = curving + self.curving_amount = curving_amount + self.looping_start = looping_start + self.looping_end = looping_end + self.horizontal_direction = horizontal_direction + self.vertical_direction = vertical_direction + self.label_position = label_position + self.label = label + + self.label_displacement = "" + self.arrow_style = "" + + # This flag shows that the position of the label of this + # morphism was set while typesetting a curved morphism and + # should not be modified later. + self.forced_label_position = False + + def __str__(self): + if self.curving: + curving_str = "@/%s%d%s/" % (self.curving, self.curving_amount, + self.unit) + else: + curving_str = "" + + if self.looping_start and self.looping_end: + looping_str = "@(%s,%s)" % (self.looping_start, self.looping_end) + else: + looping_str = "" + + if self.arrow_style: + + style_str = "@" + self.arrow_style + else: + style_str = "" + + return "\\ar%s%s%s[%s%s]%s%s{%s}" % \ + (curving_str, looping_str, style_str, self.horizontal_direction, + self.vertical_direction, self.label_position, + self.label_displacement, self.label) + + +class XypicDiagramDrawer(object): + r""" + Given a :class:`Diagram` and the corresponding + :class:`DiagramGrid`, produces the Xy-pic representation of the + diagram. + + The most important method in this class is ``draw``. Consider the + following triangle diagram: + + >>> from sympy.categories import Object, NamedMorphism, Diagram + >>> from sympy.categories import DiagramGrid, XypicDiagramDrawer + >>> A = Object("A") + >>> B = Object("B") + >>> C = Object("C") + >>> f = NamedMorphism(A, B, "f") + >>> g = NamedMorphism(B, C, "g") + >>> diagram = Diagram([f, g], {g * f: "unique"}) + + To draw this diagram, its objects need to be laid out with a + :class:`DiagramGrid`:: + + >>> grid = DiagramGrid(diagram) + + Finally, the drawing: + + >>> drawer = XypicDiagramDrawer() + >>> print(drawer.draw(diagram, grid)) + \xymatrix{ + A \ar[d]_{g\circ f} \ar[r]^{f} & B \ar[ld]^{g} \\ + C & + } + + For further details see the docstring of this method. + + To control the appearance of the arrows, formatters are used. The + dictionary ``arrow_formatters`` maps morphisms to formatter + functions. A formatter is accepts an + :class:`ArrowStringDescription` and is allowed to modify any of + the arrow properties exposed thereby. For example, to have all + morphisms with the property ``unique`` appear as dashed arrows, + and to have their names prepended with `\exists !`, the following + should be done: + + >>> def formatter(astr): + ... astr.label = "\exists !" + astr.label + ... astr.arrow_style = "{-->}" + >>> drawer.arrow_formatters["unique"] = formatter + >>> print(drawer.draw(diagram, grid)) + \xymatrix{ + A \ar@{-->}[d]_{\exists !g\circ f} \ar[r]^{f} & B \ar[ld]^{g} \\ + C & + } + + To modify the appearance of all arrows in the diagram, set + ``default_arrow_formatter``. For example, to place all morphism + labels a little bit farther from the arrow head so that they look + more centred, do as follows: + + >>> def default_formatter(astr): + ... astr.label_displacement = "(0.45)" + >>> drawer.default_arrow_formatter = default_formatter + >>> print(drawer.draw(diagram, grid)) + \xymatrix{ + A \ar@{-->}[d]_(0.45){\exists !g\circ f} \ar[r]^(0.45){f} & B \ar[ld]^(0.45){g} \\ + C & + } + + In some diagrams some morphisms are drawn as curved arrows. + Consider the following diagram: + + >>> D = Object("D") + >>> E = Object("E") + >>> h = NamedMorphism(D, A, "h") + >>> k = NamedMorphism(D, B, "k") + >>> diagram = Diagram([f, g, h, k]) + >>> grid = DiagramGrid(diagram) + >>> drawer = XypicDiagramDrawer() + >>> print(drawer.draw(diagram, grid)) + \xymatrix{ + A \ar[r]_{f} & B \ar[d]^{g} & D \ar[l]^{k} \ar@/_3mm/[ll]_{h} \\ + & C & + } + + To control how far the morphisms are curved by default, one can + use the ``unit`` and ``default_curving_amount`` attributes: + + >>> drawer.unit = "cm" + >>> drawer.default_curving_amount = 1 + >>> print(drawer.draw(diagram, grid)) + \xymatrix{ + A \ar[r]_{f} & B \ar[d]^{g} & D \ar[l]^{k} \ar@/_1cm/[ll]_{h} \\ + & C & + } + + In some diagrams, there are multiple curved morphisms between the + same two objects. To control by how much the curving changes + between two such successive morphisms, use + ``default_curving_step``: + + >>> drawer.default_curving_step = 1 + >>> h1 = NamedMorphism(A, D, "h1") + >>> diagram = Diagram([f, g, h, k, h1]) + >>> grid = DiagramGrid(diagram) + >>> print(drawer.draw(diagram, grid)) + \xymatrix{ + A \ar[r]_{f} \ar@/^1cm/[rr]^{h_{1}} & B \ar[d]^{g} & D \ar[l]^{k} \ar@/_2cm/[ll]_{h} \\ + & C & + } + + The default value of ``default_curving_step`` is 4 units. + + See Also + ======== + + draw, ArrowStringDescription + """ + def __init__(self): + self.unit = "mm" + self.default_curving_amount = 3 + self.default_curving_step = 4 + + # This dictionary maps properties to the corresponding arrow + # formatters. + self.arrow_formatters = {} + + # This is the default arrow formatter which will be applied to + # each arrow independently of its properties. + self.default_arrow_formatter = None + + @staticmethod + def _process_loop_morphism(i, j, grid, morphisms_str_info, object_coords): + """ + Produces the information required for constructing the string + representation of a loop morphism. This function is invoked + from ``_process_morphism``. + + See Also + ======== + + _process_morphism + """ + curving = "" + label_pos = "^" + looping_start = "" + looping_end = "" + + # This is a loop morphism. Count how many morphisms stick + # in each of the four quadrants. Note that straight + # vertical and horizontal morphisms count in two quadrants + # at the same time (i.e., a morphism going up counts both + # in the first and the second quadrants). + + # The usual numbering (counterclockwise) of quadrants + # applies. + quadrant = [0, 0, 0, 0] + + obj = grid[i, j] + + for m, m_str_info in list(morphisms_str_info.items()): + if (m.domain == obj) and (m.codomain == obj): + # That's another loop morphism. Check how it + # loops and mark the corresponding quadrants as + # busy. + (l_s, l_e) = (m_str_info.looping_start, m_str_info.looping_end) + + if (l_s, l_e) == ("r", "u"): + quadrant[0] += 1 + elif (l_s, l_e) == ("u", "l"): + quadrant[1] += 1 + elif (l_s, l_e) == ("l", "d"): + quadrant[2] += 1 + elif (l_s, l_e) == ("d", "r"): + quadrant[3] += 1 + + continue + if m.domain == obj: + (end_i, end_j) = object_coords[m.codomain] + goes_out = True + elif m.codomain == obj: + (end_i, end_j) = object_coords[m.domain] + goes_out = False + else: + continue + + d_i = end_i - i + d_j = end_j - j + m_curving = m_str_info.curving + + if (d_i != 0) and (d_j != 0): + # This is really a diagonal morphism. Detect the + # quadrant. + if (d_i > 0) and (d_j > 0): + quadrant[0] += 1 + elif (d_i > 0) and (d_j < 0): + quadrant[1] += 1 + elif (d_i < 0) and (d_j < 0): + quadrant[2] += 1 + elif (d_i < 0) and (d_j > 0): + quadrant[3] += 1 + elif d_i == 0: + # Knowing where the other end of the morphism is + # and which way it goes, we now have to decide + # which quadrant is now the upper one and which is + # the lower one. + if d_j > 0: + if goes_out: + upper_quadrant = 0 + lower_quadrant = 3 + else: + upper_quadrant = 3 + lower_quadrant = 0 + else: + if goes_out: + upper_quadrant = 2 + lower_quadrant = 1 + else: + upper_quadrant = 1 + lower_quadrant = 2 + + if m_curving: + if m_curving == "^": + quadrant[upper_quadrant] += 1 + elif m_curving == "_": + quadrant[lower_quadrant] += 1 + else: + # This morphism counts in both upper and lower + # quadrants. + quadrant[upper_quadrant] += 1 + quadrant[lower_quadrant] += 1 + elif d_j == 0: + # Knowing where the other end of the morphism is + # and which way it goes, we now have to decide + # which quadrant is now the left one and which is + # the right one. + if d_i < 0: + if goes_out: + left_quadrant = 1 + right_quadrant = 0 + else: + left_quadrant = 0 + right_quadrant = 1 + else: + if goes_out: + left_quadrant = 3 + right_quadrant = 2 + else: + left_quadrant = 2 + right_quadrant = 3 + + if m_curving: + if m_curving == "^": + quadrant[left_quadrant] += 1 + elif m_curving == "_": + quadrant[right_quadrant] += 1 + else: + # This morphism counts in both upper and lower + # quadrants. + quadrant[left_quadrant] += 1 + quadrant[right_quadrant] += 1 + + # Pick the freest quadrant to curve our morphism into. + freest_quadrant = 0 + for i in range(4): + if quadrant[i] < quadrant[freest_quadrant]: + freest_quadrant = i + + # Now set up proper looping. + (looping_start, looping_end) = [("r", "u"), ("u", "l"), ("l", "d"), + ("d", "r")][freest_quadrant] + + return (curving, label_pos, looping_start, looping_end) + + @staticmethod + def _process_horizontal_morphism(i, j, target_j, grid, morphisms_str_info, + object_coords): + """ + Produces the information required for constructing the string + representation of a horizontal morphism. This function is + invoked from ``_process_morphism``. + + See Also + ======== + + _process_morphism + """ + # The arrow is horizontal. Check if it goes from left to + # right (``backwards == False``) or from right to left + # (``backwards == True``). + backwards = False + start = j + end = target_j + if end < start: + (start, end) = (end, start) + backwards = True + + # Let's see which objects are there between ``start`` and + # ``end``, and then count how many morphisms stick out + # upwards, and how many stick out downwards. + # + # For example, consider the situation: + # + # B1 C1 + # | | + # A--B--C--D + # | + # B2 + # + # Between the objects `A` and `D` there are two objects: + # `B` and `C`. Further, there are two morphisms which + # stick out upward (the ones between `B1` and `B` and + # between `C` and `C1`) and one morphism which sticks out + # downward (the one between `B and `B2`). + # + # We need this information to decide how to curve the + # arrow between `A` and `D`. First of all, since there + # are two objects between `A` and `D``, we must curve the + # arrow. Then, we will have it curve downward, because + # there is more space (less morphisms stick out downward + # than upward). + up = [] + down = [] + straight_horizontal = [] + for k in range(start + 1, end): + obj = grid[i, k] + if not obj: + continue + + for m in morphisms_str_info: + if m.domain == obj: + (end_i, end_j) = object_coords[m.codomain] + elif m.codomain == obj: + (end_i, end_j) = object_coords[m.domain] + else: + continue + + if end_i > i: + down.append(m) + elif end_i < i: + up.append(m) + elif not morphisms_str_info[m].curving: + # This is a straight horizontal morphism, + # because it has no curving. + straight_horizontal.append(m) + + if len(up) < len(down): + # More morphisms stick out downward than upward, let's + # curve the morphism up. + if backwards: + curving = "_" + label_pos = "_" + else: + curving = "^" + label_pos = "^" + + # Assure that the straight horizontal morphisms have + # their labels on the lower side of the arrow. + for m in straight_horizontal: + (i1, j1) = object_coords[m.domain] + (i2, j2) = object_coords[m.codomain] + + m_str_info = morphisms_str_info[m] + if j1 < j2: + m_str_info.label_position = "_" + else: + m_str_info.label_position = "^" + + # Don't allow any further modifications of the + # position of this label. + m_str_info.forced_label_position = True + else: + # More morphisms stick out downward than upward, let's + # curve the morphism up. + if backwards: + curving = "^" + label_pos = "^" + else: + curving = "_" + label_pos = "_" + + # Assure that the straight horizontal morphisms have + # their labels on the upper side of the arrow. + for m in straight_horizontal: + (i1, j1) = object_coords[m.domain] + (i2, j2) = object_coords[m.codomain] + + m_str_info = morphisms_str_info[m] + if j1 < j2: + m_str_info.label_position = "^" + else: + m_str_info.label_position = "_" + + # Don't allow any further modifications of the + # position of this label. + m_str_info.forced_label_position = True + + return (curving, label_pos) + + @staticmethod + def _process_vertical_morphism(i, j, target_i, grid, morphisms_str_info, + object_coords): + """ + Produces the information required for constructing the string + representation of a vertical morphism. This function is + invoked from ``_process_morphism``. + + See Also + ======== + + _process_morphism + """ + # This arrow is vertical. Check if it goes from top to + # bottom (``backwards == False``) or from bottom to top + # (``backwards == True``). + backwards = False + start = i + end = target_i + if end < start: + (start, end) = (end, start) + backwards = True + + # Let's see which objects are there between ``start`` and + # ``end``, and then count how many morphisms stick out to + # the left, and how many stick out to the right. + # + # See the corresponding comment in the previous branch of + # this if-statement for more details. + left = [] + right = [] + straight_vertical = [] + for k in range(start + 1, end): + obj = grid[k, j] + if not obj: + continue + + for m in morphisms_str_info: + if m.domain == obj: + (end_i, end_j) = object_coords[m.codomain] + elif m.codomain == obj: + (end_i, end_j) = object_coords[m.domain] + else: + continue + + if end_j > j: + right.append(m) + elif end_j < j: + left.append(m) + elif not morphisms_str_info[m].curving: + # This is a straight vertical morphism, + # because it has no curving. + straight_vertical.append(m) + + if len(left) < len(right): + # More morphisms stick out to the left than to the + # right, let's curve the morphism to the right. + if backwards: + curving = "^" + label_pos = "^" + else: + curving = "_" + label_pos = "_" + + # Assure that the straight vertical morphisms have + # their labels on the left side of the arrow. + for m in straight_vertical: + (i1, j1) = object_coords[m.domain] + (i2, j2) = object_coords[m.codomain] + + m_str_info = morphisms_str_info[m] + if i1 < i2: + m_str_info.label_position = "^" + else: + m_str_info.label_position = "_" + + # Don't allow any further modifications of the + # position of this label. + m_str_info.forced_label_position = True + else: + # More morphisms stick out to the right than to the + # left, let's curve the morphism to the left. + if backwards: + curving = "_" + label_pos = "_" + else: + curving = "^" + label_pos = "^" + + # Assure that the straight vertical morphisms have + # their labels on the right side of the arrow. + for m in straight_vertical: + (i1, j1) = object_coords[m.domain] + (i2, j2) = object_coords[m.codomain] + + m_str_info = morphisms_str_info[m] + if i1 < i2: + m_str_info.label_position = "_" + else: + m_str_info.label_position = "^" + + # Don't allow any further modifications of the + # position of this label. + m_str_info.forced_label_position = True + + return (curving, label_pos) + + def _process_morphism(self, diagram, grid, morphism, object_coords, + morphisms, morphisms_str_info): + """ + Given the required information, produces the string + representation of ``morphism``. + """ + def repeat_string_cond(times, str_gt, str_lt): + """ + If ``times > 0``, repeats ``str_gt`` ``times`` times. + Otherwise, repeats ``str_lt`` ``-times`` times. + """ + if times > 0: + return str_gt * times + else: + return str_lt * (-times) + + def count_morphisms_undirected(A, B): + """ + Counts how many processed morphisms there are between the + two supplied objects. + """ + return len([m for m in morphisms_str_info + if set([m.domain, m.codomain]) == set([A, B])]) + + def count_morphisms_filtered(dom, cod, curving): + """ + Counts the processed morphisms which go out of ``dom`` + into ``cod`` with curving ``curving``. + """ + return len([m for m, m_str_info in list(morphisms_str_info.items()) + if (m.domain, m.codomain) == (dom, cod) and + (m_str_info.curving == curving)]) + + (i, j) = object_coords[morphism.domain] + (target_i, target_j) = object_coords[morphism.codomain] + + # We now need to determine the direction of + # the arrow. + delta_i = target_i - i + delta_j = target_j - j + vertical_direction = repeat_string_cond(delta_i, + "d", "u") + horizontal_direction = repeat_string_cond(delta_j, + "r", "l") + + curving = "" + label_pos = "^" + looping_start = "" + looping_end = "" + + if (delta_i == 0) and (delta_j == 0): + # This is a loop morphism. + (curving, label_pos, looping_start, + looping_end) = XypicDiagramDrawer._process_loop_morphism( + i, j, grid, morphisms_str_info, object_coords) + elif (delta_i == 0) and (abs(j - target_j) > 1): + # This is a horizontal morphism. + (curving, label_pos) = XypicDiagramDrawer._process_horizontal_morphism( + i, j, target_j, grid, morphisms_str_info, object_coords) + elif (delta_j == 0) and (abs(i - target_i) > 1): + # This is a vertical morphism. + (curving, label_pos) = XypicDiagramDrawer._process_vertical_morphism( + i, j, target_i, grid, morphisms_str_info, object_coords) + + count = count_morphisms_undirected(morphism.domain, morphism.codomain) + curving_amount = "" + if curving: + # This morphisms should be curved anyway. + curving_amount = self.default_curving_amount + count * \ + self.default_curving_step + elif count: + # There are no objects between the domain and codomain of + # the current morphism, but this is not there already are + # some morphisms with the same domain and codomain, so we + # have to curve this one. + curving = "^" + filtered_morphisms = count_morphisms_filtered( + morphism.domain, morphism.codomain, curving) + curving_amount = self.default_curving_amount + \ + filtered_morphisms * \ + self.default_curving_step + + # Let's now get the name of the morphism. + morphism_name = "" + if isinstance(morphism, IdentityMorphism): + morphism_name = "id_{%s}" + latex(obj) + elif isinstance(morphism, CompositeMorphism): + component_names = [latex(Symbol(component.name)) for + component in morphism.components] + component_names.reverse() + morphism_name = "\\circ ".join(component_names) + elif isinstance(morphism, NamedMorphism): + morphism_name = latex(Symbol(morphism.name)) + + return ArrowStringDescription( + self.unit, curving, curving_amount, looping_start, + looping_end, horizontal_direction, vertical_direction, + label_pos, morphism_name) + + @staticmethod + def _check_free_space_horizontal(dom_i, dom_j, cod_j, grid): + """ + For a horizontal morphism, checks whether there is free space + (i.e., space not occupied by any objects) above the morphism + or below it. + """ + if dom_j < cod_j: + (start, end) = (dom_j, cod_j) + backwards = False + else: + (start, end) = (cod_j, dom_j) + backwards = True + + # Check for free space above. + if dom_i == 0: + free_up = True + else: + free_up = all([grid[dom_i - 1, j] for j in + range(start, end + 1)]) + + # Check for free space below. + if dom_i == grid.height - 1: + free_down = True + else: + free_down = all([not grid[dom_i + 1, j] for j in + range(start, end + 1)]) + + return (free_up, free_down, backwards) + + @staticmethod + def _check_free_space_vertical(dom_i, cod_i, dom_j, grid): + """ + For a vertical morphism, checks whether there is free space + (i.e., space not occupied by any objects) to the left of the + morphism or to the right of it. + """ + if dom_i < cod_i: + (start, end) = (dom_i, cod_i) + backwards = False + else: + (start, end) = (cod_i, dom_i) + backwards = True + + # Check if there's space to the left. + if dom_j == 0: + free_left = True + else: + free_left = all([not grid[i, dom_j - 1] for i in + range(start, end + 1)]) + + if dom_j == grid.width - 1: + free_right = True + else: + free_right = all([not grid[i, dom_j + 1] for i in + range(start, end + 1)]) + + return (free_left, free_right, backwards) + + @staticmethod + def _check_free_space_diagonal(dom_i, cod_i, dom_j, cod_j, grid): + """ + For a diagonal morphism, checks whether there is free space + (i.e., space not occupied by any objects) above the morphism + or below it. + """ + def abs_xrange(start, end): + if start < end: + return range(start, end + 1) + else: + return range(end, start + 1) + + if dom_i < cod_i and dom_j < cod_j: + # This morphism goes from top-left to + # bottom-right. + (start_i, start_j) = (dom_i, dom_j) + (end_i, end_j) = (cod_i, cod_j) + backwards = False + elif dom_i > cod_i and dom_j > cod_j: + # This morphism goes from bottom-right to + # top-left. + (start_i, start_j) = (cod_i, cod_j) + (end_i, end_j) = (dom_i, dom_j) + backwards = True + if dom_i < cod_i and dom_j > cod_j: + # This morphism goes from top-right to + # bottom-left. + (start_i, start_j) = (dom_i, dom_j) + (end_i, end_j) = (cod_i, cod_j) + backwards = True + elif dom_i > cod_i and dom_j < cod_j: + # This morphism goes from bottom-left to + # top-right. + (start_i, start_j) = (cod_i, cod_j) + (end_i, end_j) = (dom_i, dom_j) + backwards = False + + # This is an attempt at a fast and furious strategy to + # decide where there is free space on the two sides of + # a diagonal morphism. For a diagonal morphism + # starting at ``(start_i, start_j)`` and ending at + # ``(end_i, end_j)`` the rectangle defined by these + # two points is considered. The slope of the diagonal + # ``alpha`` is then computed. Then, for every cell + # ``(i, j)`` within the rectangle, the slope + # ``alpha1`` of the line through ``(start_i, + # start_j)`` and ``(i, j)`` is considered. If + # ``alpha1`` is between 0 and ``alpha``, the point + # ``(i, j)`` is above the diagonal, if ``alpha1`` is + # between ``alpha`` and infinity, the point is below + # the diagonal. Also note that, with some beforehand + # precautions, this trick works for both the main and + # the secondary diagonals of the rectangle. + + # I have considered the possibility to only follow the + # shorter diagonals immediately above and below the + # main (or secondary) diagonal. This, however, + # wouldn't have resulted in much performance gain or + # better detection of outer edges, because of + # relatively small sizes of diagram grids, while the + # code would have become harder to understand. + + alpha = float(end_i - start_i)/(end_j - start_j) + free_up = True + free_down = True + for i in abs_xrange(start_i, end_i): + if not free_up and not free_down: + break + + for j in abs_xrange(start_j, end_j): + if not free_up and not free_down: + break + + if (i, j) == (start_i, start_j): + continue + + if j == start_j: + alpha1 = "inf" + else: + alpha1 = float(i - start_i)/(j - start_j) + + if grid[i, j]: + if (alpha1 == "inf") or (abs(alpha1) > abs(alpha)): + free_down = False + elif abs(alpha1) < abs(alpha): + free_up = False + + return (free_up, free_down, backwards) + + def _push_labels_out(self, morphisms_str_info, grid, object_coords): + """ + For all straight morphisms which form the visual boundary of + the laid out diagram, puts their labels on their outer sides. + """ + def set_label_position(free1, free2, pos1, pos2, backwards, m_str_info): + """ + Given the information about room available to one side and + to the other side of a morphism (``free1`` and ``free2``), + sets the position of the morphism label in such a way that + it is on the freer side. This latter operations involves + choice between ``pos1`` and ``pos2``, taking ``backwards`` + in consideration. + + Thus this function will do nothing if either both ``free1 + == True`` and ``free2 == True`` or both ``free1 == False`` + and ``free2 == False``. In either case, choosing one side + over the other presents no advantage. + """ + if backwards: + (pos1, pos2) = (pos2, pos1) + + if free1 and not free2: + m_str_info.label_position = pos1 + elif free2 and not free1: + m_str_info.label_position = pos2 + + for m, m_str_info in list(morphisms_str_info.items()): + if m_str_info.curving or m_str_info.forced_label_position: + # This is either a curved morphism, and curved + # morphisms have other magic, or the position of this + # label has already been fixed. + continue + + if m.domain == m.codomain: + # This is a loop morphism, their labels, again have a + # different magic. + continue + + (dom_i, dom_j) = object_coords[m.domain] + (cod_i, cod_j) = object_coords[m.codomain] + + if dom_i == cod_i: + # Horizontal morphism. + (free_up, free_down, + backwards) = XypicDiagramDrawer._check_free_space_horizontal( + dom_i, dom_j, cod_j, grid) + + set_label_position(free_up, free_down, "^", "_", + backwards, m_str_info) + elif dom_j == cod_j: + # Vertical morphism. + (free_left, free_right, + backwards) = XypicDiagramDrawer._check_free_space_vertical( + dom_i, cod_i, dom_j, grid) + + set_label_position(free_left, free_right, "_", "^", + backwards, m_str_info) + else: + # A diagonal morphism. + (free_up, free_down, + backwards) = XypicDiagramDrawer._check_free_space_diagonal( + dom_i, cod_i, dom_j, cod_j, grid) + + set_label_position(free_up, free_down, "^", "_", + backwards, m_str_info) + + @staticmethod + def _morphism_sort_key(morphism, object_coords): + """ + Provides a morphism sorting key such that horizontal or + vertical morphisms between neighbouring objects come + first, then horizontal or vertical morphisms between more + far away objects, and finally, all other morphisms. + """ + (i, j) = object_coords[morphism.domain] + (target_i, target_j) = object_coords[morphism.codomain] + + if morphism.domain == morphism.codomain: + # Loop morphisms should get after diagonal morphisms + # so that the proper direction in which to curve the + # loop can be determined. + return (3, 0, default_sort_key(morphism)) + + if target_i == i: + return (1, abs(target_j - j), default_sort_key(morphism)) + + if target_j == j: + return (1, abs(target_i - i), default_sort_key(morphism)) + + # Diagonal morphism. + return (2, 0, default_sort_key(morphism)) + + @staticmethod + def _build_xypic_string(diagram, grid, morphisms, + morphisms_str_info, diagram_format): + """ + Given a collection of :class:`ArrowStringDescription` + describing the morphisms of a diagram and the object layout + information of a diagram, produces the final Xy-pic picture. + """ + # Build the mapping between objects and morphisms which have + # them as domains. + object_morphisms = {} + for obj in diagram.objects: + object_morphisms[obj] = [] + for morphism in morphisms: + object_morphisms[morphism.domain].append(morphism) + + result = "\\xymatrix%s{\n" % diagram_format + + for i in range(grid.height): + for j in range(grid.width): + obj = grid[i, j] + if obj: + result += latex(obj) + " " + + morphisms_to_draw = object_morphisms[obj] + for morphism in morphisms_to_draw: + result += str(morphisms_str_info[morphism]) + " " + + # Don't put the & after the last column. + if j < grid.width - 1: + result += "& " + + # Don't put the line break after the last row. + if i < grid.height - 1: + result += "\\\\" + result += "\n" + + result += "}\n" + + return result + + def draw(self, diagram, grid, masked=None, diagram_format=""): + r""" + Returns the Xy-pic representation of ``diagram`` laid out in + ``grid``. + + Consider the following simple triangle diagram. + + >>> from sympy.categories import Object, NamedMorphism, Diagram + >>> from sympy.categories import DiagramGrid, XypicDiagramDrawer + >>> A = Object("A") + >>> B = Object("B") + >>> C = Object("C") + >>> f = NamedMorphism(A, B, "f") + >>> g = NamedMorphism(B, C, "g") + >>> diagram = Diagram([f, g], {g * f: "unique"}) + + To draw this diagram, its objects need to be laid out with a + :class:`DiagramGrid`:: + + >>> grid = DiagramGrid(diagram) + + Finally, the drawing: + + >>> drawer = XypicDiagramDrawer() + >>> print(drawer.draw(diagram, grid)) + \xymatrix{ + A \ar[d]_{g\circ f} \ar[r]^{f} & B \ar[ld]^{g} \\ + C & + } + + The argument ``masked`` can be used to skip morphisms in the + presentation of the diagram: + + >>> print(drawer.draw(diagram, grid, masked=[g * f])) + \xymatrix{ + A \ar[r]^{f} & B \ar[ld]^{g} \\ + C & + } + + Finally, the ``diagram_format`` argument can be used to + specify the format string of the diagram. For example, to + increase the spacing by 1 cm, proceeding as follows: + + >>> print(drawer.draw(diagram, grid, diagram_format="@+1cm")) + \xymatrix@+1cm{ + A \ar[d]_{g\circ f} \ar[r]^{f} & B \ar[ld]^{g} \\ + C & + } + + """ + # This method works in several steps. It starts by removing + # the masked morphisms, if necessary, and then maps objects to + # their positions in the grid (coordinate tuples). Remember + # that objects are unique in ``Diagram`` and in the layout + # produced by ``DiagramGrid``, so every object is mapped to a + # single coordinate pair. + # + # The next step is the central step and is concerned with + # analysing the morphisms of the diagram and deciding how to + # draw them. For example, how to curve the arrows is decided + # at this step. The bulk of the analysis is implemented in + # ``_process_morphism``, to the result of which the + # appropriate formatters are applied. + # + # The result of the previous step is a list of + # ``ArrowStringDescription``. After the analysis and + # application of formatters, some extra logic tries to assure + # better positioning of morphism labels (for example, an + # attempt is made to avoid the situations when arrows cross + # labels). This functionality constitutes the next step and + # is implemented in ``_push_labels_out``. Note that label + # positions which have been set via a formatter are not + # affected in this step. + # + # Finally, at the closing step, the array of + # ``ArrowStringDescription`` and the layout information + # incorporated in ``DiagramGrid`` are combined to produce the + # resulting Xy-pic picture. This part of code lies in + # ``_build_xypic_string``. + + if not masked: + morphisms_props = grid.morphisms + else: + morphisms_props = {} + for m, props in list(grid.morphisms.items()): + if m in masked: + continue + morphisms_props[m] = props + + # Build the mapping between objects and their position in the + # grid. + object_coords = {} + for i in range(grid.height): + for j in range(grid.width): + if grid[i, j]: + object_coords[grid[i, j]] = (i, j) + + morphisms = sorted(morphisms_props, + key=lambda m: XypicDiagramDrawer._morphism_sort_key( + m, object_coords)) + + # Build the tuples defining the string representations of + # morphisms. + morphisms_str_info = {} + for morphism in morphisms: + string_description = self._process_morphism( + diagram, grid, morphism, object_coords, morphisms, + morphisms_str_info) + + if self.default_arrow_formatter: + self.default_arrow_formatter(string_description) + + for prop in morphisms_props[morphism]: + # prop is a Symbol. TODO: Find out why. + if prop.name in self.arrow_formatters: + formatter = self.arrow_formatters[prop.name] + formatter(string_description) + + morphisms_str_info[morphism] = string_description + + # Reposition the labels a bit. + self._push_labels_out(morphisms_str_info, grid, object_coords) + + return XypicDiagramDrawer._build_xypic_string( + diagram, grid, morphisms, morphisms_str_info, diagram_format) + + +def xypic_draw_diagram(diagram, masked=None, diagram_format="", + groups=None, **hints): + r""" + Provides a shortcut combining :class:`DiagramGrid` and + :class:`XypicDiagramDrawer`. Returns an Xy-pic presentation of + ``diagram``. The argument ``masked`` is a list of morphisms which + will be not be drawn. The argument ``diagram_format`` is the + format string inserted after "\xymatrix". ``groups`` should be a + set of logical groups. The ``hints`` will be passed directly to + the constructor of :class:`DiagramGrid`. + + For more information about the arguments, see the docstrings of + :class:`DiagramGrid` and ``XypicDiagramDrawer.draw``. + + Examples + ======== + + >>> from sympy.categories import Object, NamedMorphism, Diagram + >>> from sympy.categories import xypic_draw_diagram + >>> A = Object("A") + >>> B = Object("B") + >>> C = Object("C") + >>> f = NamedMorphism(A, B, "f") + >>> g = NamedMorphism(B, C, "g") + >>> diagram = Diagram([f, g], {g * f: "unique"}) + >>> print(xypic_draw_diagram(diagram)) + \xymatrix{ + A \ar[d]_{g\circ f} \ar[r]^{f} & B \ar[ld]^{g} \\ + C & + } + + See Also + ======== + + XypicDiagramDrawer, DiagramGrid + """ + grid = DiagramGrid(diagram, groups, **hints) + drawer = XypicDiagramDrawer() + return drawer.draw(diagram, grid, masked, diagram_format) + + +@doctest_depends_on(exe=('latex', 'dvipng'), modules=('pyglet',)) +def preview_diagram(diagram, masked=None, diagram_format="", groups=None, + output='png', viewer=None, euler=True, **hints): + """ + Combines the functionality of ``xypic_draw_diagram`` and + ``sympy.printing.preview``. The arguments ``masked``, + ``diagram_format``, ``groups``, and ``hints`` are passed to + ``xypic_draw_diagram``, while ``output``, ``viewer, and ``euler`` + are passed to ``preview``. + + Examples + ======== + + >>> from sympy.categories import Object, NamedMorphism, Diagram + >>> from sympy.categories import preview_diagram + >>> A = Object("A") + >>> B = Object("B") + >>> C = Object("C") + >>> f = NamedMorphism(A, B, "f") + >>> g = NamedMorphism(B, C, "g") + >>> d = Diagram([f, g], {g * f: "unique"}) + >>> preview_diagram(d) + + See Also + ======== + + xypic_diagram_drawer + """ + from sympy.printing import preview + latex_output = xypic_draw_diagram(diagram, masked, diagram_format, + groups, **hints) + preview(latex_output, output, viewer, euler, ("xypic",)) diff -Nru python3-sympy-0.7.2/sympy/categories/tests/test_baseclasses.py python3-sympy-0.7.3/sympy/categories/tests/test_baseclasses.py --- python3-sympy-0.7.2/sympy/categories/tests/test_baseclasses.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/categories/tests/test_baseclasses.py 2013-07-13 17:53:31.000000000 +0000 @@ -5,6 +5,7 @@ from sympy.utilities.pytest import XFAIL, raises from sympy import FiniteSet, EmptySet, Dict, Tuple + def test_morphisms(): A = Object("A") B = Object("B") @@ -80,6 +81,7 @@ raises(ValueError, lambda: NamedMorphism(A, B, "")) raises(NotImplementedError, lambda: Morphism(A, B)) + def test_diagram(): A = Object("A") B = Object("B") @@ -124,7 +126,7 @@ # Make sure that (re-)adding composites (with new properties) # works as expected. d = Diagram([f, g], {g * f: "unique"}) - assert d.conclusions == Dict({g*f:FiniteSet("unique")}) + assert d.conclusions == Dict({g * f: FiniteSet("unique")}) # Check the hom-sets when there are premises and conclusions. assert d.hom(A, C) == (FiniteSet(g * f), FiniteSet(g * f)) @@ -132,7 +134,7 @@ assert d.hom(A, C) == (FiniteSet(g * f), FiniteSet(g * f)) # Check how the properties of composite morphisms are computed. - d = Diagram({f: ["unique", "isomorphism"], g:"unique"}) + d = Diagram({f: ["unique", "isomorphism"], g: "unique"}) assert d.premises[g * f] == FiniteSet("unique") # Check that conclusion morphisms with new objects are not allowed. @@ -146,7 +148,7 @@ assert d.objects == empty # Check a SymPy Dict object. - d = Diagram(Dict({f: FiniteSet("unique", "isomorphism"), g:"unique"})) + d = Diagram(Dict({f: FiniteSet("unique", "isomorphism"), g: "unique"})) assert d.premises[g * f] == FiniteSet("unique") # Check the addition of components of composite morphisms. @@ -177,10 +179,12 @@ d = Diagram([f, g], {f: "unique", g * f: "veryunique"}) d1 = d.subdiagram_from_objects(FiniteSet(A, B)) assert d1 == Diagram([f], {f: "unique"}) - raises(ValueError, lambda: d.subdiagram_from_objects(FiniteSet(A, Object("D")))) + raises(ValueError, lambda: d.subdiagram_from_objects(FiniteSet(A, + Object("D")))) raises(ValueError, lambda: Diagram({IdentityMorphism(A): "unique"})) + def test_category(): A = Object("A") B = Object("B") diff -Nru python3-sympy-0.7.2/sympy/categories/tests/test_drawing.py python3-sympy-0.7.3/sympy/categories/tests/test_drawing.py --- python3-sympy-0.7.2/sympy/categories/tests/test_drawing.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/categories/tests/test_drawing.py 2013-07-13 17:53:31.000000000 +0000 @@ -1,7 +1,9 @@ -from sympy.categories.diagram_drawing import _GrowableGrid -from sympy.categories import DiagramGrid, Object, NamedMorphism, Diagram +from sympy.categories.diagram_drawing import _GrowableGrid, ArrowStringDescription +from sympy.categories import (DiagramGrid, Object, NamedMorphism, + Diagram, XypicDiagramDrawer, xypic_draw_diagram) from sympy import FiniteSet + def test_GrowableGrid(): grid = _GrowableGrid(1, 2) @@ -10,8 +12,8 @@ assert grid.height == 2 # Check initialisation of elements. - assert grid[0, 0] == None - assert grid[1, 0] == None + assert grid[0, 0] is None + assert grid[1, 0] is None # Check assignment to elements. grid[0, 0] = 1 @@ -28,7 +30,7 @@ assert grid[0, 0] == 1 assert grid[1, 0] == "two" - assert grid[2, 0] == None + assert grid[2, 0] is None # Check appending a column. grid.append_column() @@ -37,11 +39,11 @@ assert grid[0, 0] == 1 assert grid[1, 0] == "two" - assert grid[2, 0] == None + assert grid[2, 0] is None - assert grid[0, 1] == None - assert grid[1, 1] == None - assert grid[2, 1] == None + assert grid[0, 1] is None + assert grid[1, 1] is None + assert grid[2, 1] is None grid = _GrowableGrid(1, 2) grid[0, 0] = 1 @@ -52,7 +54,7 @@ assert grid.width == 1 assert grid.height == 3 - assert grid[0, 0] == None + assert grid[0, 0] is None assert grid[1, 0] == 1 assert grid[2, 0] == "two" @@ -61,14 +63,15 @@ assert grid.width == 2 assert grid.height == 3 - assert grid[0, 0] == None - assert grid[1, 0] == None - assert grid[2, 0] == None + assert grid[0, 0] is None + assert grid[1, 0] is None + assert grid[2, 0] is None - assert grid[0, 1] == None + assert grid[0, 1] is None assert grid[1, 1] == 1 assert grid[2, 1] == "two" + def test_DiagramGrid(): # Set up some objects and morphisms. A = Object("A") @@ -90,10 +93,10 @@ assert grid.height == 1 assert grid[0, 0] == A assert grid[0, 1] == B - assert grid.morphisms == {f:FiniteSet()} + assert grid.morphisms == {f: FiniteSet()} # A triangle. - d = Diagram([f, g], {g * f:"unique"}) + d = Diagram([f, g], {g * f: "unique"}) grid = DiagramGrid(d) assert grid.width == 2 @@ -102,8 +105,8 @@ assert grid[0, 1] == B assert grid[1, 0] == C assert grid[1, 1] is None - assert grid.morphisms == {f:FiniteSet(), g:FiniteSet(), - g * f:FiniteSet("unique")} + assert grid.morphisms == {f: FiniteSet(), g: FiniteSet(), + g * f: FiniteSet("unique")} # A triangle with a "loop" morphism. l_A = NamedMorphism(A, A, "l_A") @@ -116,7 +119,7 @@ assert grid[0, 1] == B assert grid[1, 0] is None assert grid[1, 1] == C - assert grid.morphisms == {f:FiniteSet(), g:FiniteSet(), l_A:FiniteSet()} + assert grid.morphisms == {f: FiniteSet(), g: FiniteSet(), l_A: FiniteSet()} # A simple diagram. d = Diagram([f, g, h, k]) @@ -130,11 +133,11 @@ assert grid[1, 0] is None assert grid[1, 1] == C assert grid[1, 2] is None - assert grid.morphisms == {f:FiniteSet(), g:FiniteSet(), h:FiniteSet(), - k:FiniteSet()} + assert grid.morphisms == {f: FiniteSet(), g: FiniteSet(), h: FiniteSet(), + k: FiniteSet()} assert str(grid) == '[[Object("A"), Object("B"), Object("D")], ' \ - '[None, Object("C"), None]]' + '[None, Object("C"), None]]' # A chain of morphisms. f = NamedMorphism(A, B, "f") @@ -155,8 +158,8 @@ assert grid[2, 0] is None assert grid[2, 1] is None assert grid[2, 2] == E - assert grid.morphisms == {f:FiniteSet(), g:FiniteSet(), h:FiniteSet(), - k:FiniteSet()} + assert grid.morphisms == {f: FiniteSet(), g: FiniteSet(), h: FiniteSet(), + k: FiniteSet()} # A square. f = NamedMorphism(A, B, "f") @@ -172,8 +175,8 @@ assert grid[0, 1] == B assert grid[1, 0] == C assert grid[1, 1] == D - assert grid.morphisms == {f:FiniteSet(), g:FiniteSet(), h:FiniteSet(), - k:FiniteSet()} + assert grid.morphisms == {f: FiniteSet(), g: FiniteSet(), h: FiniteSet(), + k: FiniteSet()} # A strange diagram which resulted from a typo when creating a # test for five lemma, but which allowed to stop one extra problem @@ -301,8 +304,8 @@ assert grid[0, 2] == C assert grid[0, 3] == D assert grid[0, 4] == E - assert grid.morphisms == {f:FiniteSet(), g:FiniteSet(), h:FiniteSet(), - i:FiniteSet()} + assert grid.morphisms == {f: FiniteSet(), g: FiniteSet(), h: FiniteSet(), + i: FiniteSet()} # Test the transposed version. grid = DiagramGrid(d, layout="sequential", transpose=True) @@ -314,8 +317,8 @@ assert grid[2, 0] == C assert grid[3, 0] == D assert grid[4, 0] == E - assert grid.morphisms == {f:FiniteSet(), g:FiniteSet(), h:FiniteSet(), - i:FiniteSet()} + assert grid.morphisms == {f: FiniteSet(), g: FiniteSet(), h: FiniteSet(), + i: FiniteSet()} # A pullback. m1 = NamedMorphism(A, B, "m1") @@ -338,7 +341,7 @@ assert grid[1, 1] == D assert grid[1, 2] is None - morphisms = {g:FiniteSet("unique")} + morphisms = {g: FiniteSet("unique")} for m in [m1, m2, s1, s2, f1, f2]: morphisms[m] = FiniteSet() assert grid.morphisms == morphisms @@ -481,7 +484,7 @@ "transpose": True}, FiniteSet(A_, B_, C_, D_, E_): {"layout": "sequential", "transpose": True}}, - transpose=True) + transpose=True) assert grid.width == 5 assert grid.height == 2 @@ -590,3 +593,314 @@ for f in [f1, f2, f3, f4, f5, f6, f7, f8, f9, f10]: morphisms[f] = FiniteSet() assert grid.morphisms == morphisms + + +def test_ArrowStringDescription(): + astr = ArrowStringDescription("cm", "", None, "", "", "d", "r", "_", "f") + assert str(astr) == "\\ar[dr]_{f}" + + astr = ArrowStringDescription("cm", "", 12, "", "", "d", "r", "_", "f") + assert str(astr) == "\\ar[dr]_{f}" + + astr = ArrowStringDescription("cm", "^", 12, "", "", "d", "r", "_", "f") + assert str(astr) == "\\ar@/^12cm/[dr]_{f}" + + astr = ArrowStringDescription("cm", "", 12, "r", "", "d", "r", "_", "f") + assert str(astr) == "\\ar[dr]_{f}" + + astr = ArrowStringDescription("cm", "", 12, "r", "u", "d", "r", "_", "f") + assert str(astr) == "\\ar@(r,u)[dr]_{f}" + + astr = ArrowStringDescription("cm", "", 12, "r", "u", "d", "r", "_", "f") + assert str(astr) == "\\ar@(r,u)[dr]_{f}" + + astr = ArrowStringDescription("cm", "", 12, "r", "u", "d", "r", "_", "f") + astr.arrow_style = "{-->}" + assert str(astr) == "\\ar@(r,u)@{-->}[dr]_{f}" + + astr = ArrowStringDescription("cm", "_", 12, "", "", "d", "r", "_", "f") + astr.arrow_style = "{-->}" + assert str(astr) == "\\ar@/_12cm/@{-->}[dr]_{f}" + + +def test_XypicDiagramDrawer_line(): + # A linear diagram. + A = Object("A") + B = Object("B") + C = Object("C") + D = Object("D") + E = Object("E") + + f = NamedMorphism(A, B, "f") + g = NamedMorphism(B, C, "g") + h = NamedMorphism(C, D, "h") + i = NamedMorphism(D, E, "i") + d = Diagram([f, g, h, i]) + grid = DiagramGrid(d, layout="sequential") + drawer = XypicDiagramDrawer() + assert drawer.draw(d, grid) == "\\xymatrix{\n" \ + "A \\ar[r]^{f} & B \\ar[r]^{g} & C \\ar[r]^{h} & D \\ar[r]^{i} & E \n" \ + "}\n" + + # The same diagram, transposed. + grid = DiagramGrid(d, layout="sequential", transpose=True) + drawer = XypicDiagramDrawer() + assert drawer.draw(d, grid) == "\\xymatrix{\n" \ + "A \\ar[d]^{f} \\\\\n" \ + "B \\ar[d]^{g} \\\\\n" \ + "C \\ar[d]^{h} \\\\\n" \ + "D \\ar[d]^{i} \\\\\n" \ + "E \n" \ + "}\n" + + +def test_XypicDiagramDrawer_triangle(): + # A triangle diagram. + A = Object("A") + B = Object("B") + C = Object("C") + f = NamedMorphism(A, B, "f") + g = NamedMorphism(B, C, "g") + + d = Diagram([f, g], {g * f: "unique"}) + grid = DiagramGrid(d) + drawer = XypicDiagramDrawer() + assert drawer.draw(d, grid) == "\\xymatrix{\n" \ + "A \\ar[d]_{g\\circ f} \\ar[r]^{f} & B \\ar[ld]^{g} \\\\\n" \ + "C & \n" \ + "}\n" + + # The same diagram, transposed. + grid = DiagramGrid(d, transpose=True) + drawer = XypicDiagramDrawer() + assert drawer.draw(d, grid) == "\\xymatrix{\n" \ + "A \\ar[r]^{g\\circ f} \\ar[d]_{f} & C \\\\\n" \ + "B \\ar[ru]_{g} & \n" \ + "}\n" + + # The same diagram, with a masked morphism. + assert drawer.draw(d, grid, masked=[g]) == "\\xymatrix{\n" \ + "A \\ar[r]^{g\\circ f} \\ar[d]_{f} & C \\\\\n" \ + "B & \n" \ + "}\n" + + # The same diagram with a formatter for "unique". + def formatter(astr): + astr.label = "\\exists !" + astr.label + astr.arrow_style = "{-->}" + + drawer.arrow_formatters["unique"] = formatter + assert drawer.draw(d, grid) == "\\xymatrix{\n" \ + "A \\ar@{-->}[r]^{\\exists !g\\circ f} \\ar[d]_{f} & C \\\\\n" \ + "B \\ar[ru]_{g} & \n" \ + "}\n" + + # The same diagram with a default formatter. + def default_formatter(astr): + astr.label_displacement = "(0.45)" + + drawer.default_arrow_formatter = default_formatter + assert drawer.draw(d, grid) == "\\xymatrix{\n" \ + "A \\ar@{-->}[r]^(0.45){\\exists !g\\circ f} \\ar[d]_(0.45){f} & C \\\\\n" \ + "B \\ar[ru]_(0.45){g} & \n" \ + "}\n" + + # A triangle diagram with a lot of morphisms between the same + # objects. + f1 = NamedMorphism(B, A, "f1") + f2 = NamedMorphism(A, B, "f2") + g1 = NamedMorphism(C, B, "g1") + g2 = NamedMorphism(B, C, "g2") + d = Diagram([f, f1, f2, g, g1, g2], {f1 * g1: "unique", g2 * f2: "unique"}) + + grid = DiagramGrid(d, transpose=True) + drawer = XypicDiagramDrawer() + assert drawer.draw(d, grid, masked=[f1*g1*g2*f2, g2*f2*f1*g1]) == \ + "\\xymatrix{\n" \ + "A \\ar[r]^{g_{2}\\circ f_{2}} \\ar[d]_{f} \\ar@/^3mm/[d]^{f_{2}} " \ + "& C \\ar@/^3mm/[l]^{f_{1}\\circ g_{1}} \\ar@/^3mm/[ld]^{g_{1}} \\\\\n" \ + "B \\ar@/^3mm/[u]^{f_{1}} \\ar[ru]_{g} \\ar@/^3mm/[ru]^{g_{2}} & \n" \ + "}\n" + + +def test_XypicDiagramDrawer_cube(): + # A cube diagram. + A1 = Object("A1") + A2 = Object("A2") + A3 = Object("A3") + A4 = Object("A4") + A5 = Object("A5") + A6 = Object("A6") + A7 = Object("A7") + A8 = Object("A8") + + # The top face of the cube. + f1 = NamedMorphism(A1, A2, "f1") + f2 = NamedMorphism(A1, A3, "f2") + f3 = NamedMorphism(A2, A4, "f3") + f4 = NamedMorphism(A3, A4, "f3") + + # The bottom face of the cube. + f5 = NamedMorphism(A5, A6, "f5") + f6 = NamedMorphism(A5, A7, "f6") + f7 = NamedMorphism(A6, A8, "f7") + f8 = NamedMorphism(A7, A8, "f8") + + # The remaining morphisms. + f9 = NamedMorphism(A1, A5, "f9") + f10 = NamedMorphism(A2, A6, "f10") + f11 = NamedMorphism(A3, A7, "f11") + f12 = NamedMorphism(A4, A8, "f11") + + d = Diagram([f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12]) + grid = DiagramGrid(d) + drawer = XypicDiagramDrawer() + assert drawer.draw(d, grid) == "\\xymatrix{\n" \ + "& A_{5} \\ar[r]^{f_{5}} \\ar[ldd]_{f_{6}} & A_{6} \\ar[rdd]^{f_{7}} " \ + "& \\\\\n" \ + "& A_{1} \\ar[r]^{f_{1}} \\ar[d]^{f_{2}} \\ar[u]^{f_{9}} & A_{2} " \ + "\\ar[d]^{f_{3}} \\ar[u]_{f_{10}} & \\\\\n" \ + "A_{7} \\ar@/_3mm/[rrr]_{f_{8}} & A_{3} \\ar[r]^{f_{3}} \\ar[l]_{f_{11}} " \ + "& A_{4} \\ar[r]^{f_{11}} & A_{8} \n" \ + "}\n" + + # The same diagram, transposed. + grid = DiagramGrid(d, transpose=True) + drawer = XypicDiagramDrawer() + assert drawer.draw(d, grid) == "\\xymatrix{\n" \ + "& & A_{7} \\ar@/^3mm/[ddd]^{f_{8}} \\\\\n" \ + "A_{5} \\ar[d]_{f_{5}} \\ar[rru]^{f_{6}} & A_{1} \\ar[d]^{f_{1}} " \ + "\\ar[r]^{f_{2}} \\ar[l]^{f_{9}} & A_{3} \\ar[d]_{f_{3}} " \ + "\\ar[u]^{f_{11}} \\\\\n" \ + "A_{6} \\ar[rrd]_{f_{7}} & A_{2} \\ar[r]^{f_{3}} \\ar[l]^{f_{10}} " \ + "& A_{4} \\ar[d]_{f_{11}} \\\\\n" \ + "& & A_{8} \n" \ + "}\n" + + +def test_XypicDiagramDrawer_curved_and_loops(): + # A simple diagram, with a curved arrow. + A = Object("A") + B = Object("B") + C = Object("C") + D = Object("D") + + f = NamedMorphism(A, B, "f") + g = NamedMorphism(B, C, "g") + h = NamedMorphism(D, A, "h") + k = NamedMorphism(D, B, "k") + d = Diagram([f, g, h, k]) + grid = DiagramGrid(d) + drawer = XypicDiagramDrawer() + assert drawer.draw(d, grid) == "\\xymatrix{\n" \ + "A \\ar[r]_{f} & B \\ar[d]^{g} & D \\ar[l]^{k} \\ar@/_3mm/[ll]_{h} \\\\\n" \ + "& C & \n" \ + "}\n" + + # The same diagram, transposed. + grid = DiagramGrid(d, transpose=True) + drawer = XypicDiagramDrawer() + assert drawer.draw(d, grid) == "\\xymatrix{\n" \ + "A \\ar[d]^{f} & \\\\\n" \ + "B \\ar[r]^{g} & C \\\\\n" \ + "D \\ar[u]_{k} \\ar@/^3mm/[uu]^{h} & \n" \ + "}\n" + + # The same diagram, larger and rotated. + assert drawer.draw(d, grid, diagram_format="@+1cm@dr") == \ + "\\xymatrix@+1cm@dr{\n" \ + "A \\ar[d]^{f} & \\\\\n" \ + "B \\ar[r]^{g} & C \\\\\n" \ + "D \\ar[u]_{k} \\ar@/^3mm/[uu]^{h} & \n" \ + "}\n" + + # A simple diagram with three curved arrows. + h1 = NamedMorphism(D, A, "h1") + h2 = NamedMorphism(A, D, "h2") + k = NamedMorphism(D, B, "k") + d = Diagram([f, g, h, k, h1, h2]) + grid = DiagramGrid(d) + drawer = XypicDiagramDrawer() + assert drawer.draw(d, grid) == "\\xymatrix{\n" \ + "A \\ar[r]_{f} \\ar@/^3mm/[rr]^{h_{2}} & B \\ar[d]^{g} & D \\ar[l]^{k} " \ + "\\ar@/_7mm/[ll]_{h} \\ar@/_11mm/[ll]_{h_{1}} \\\\\n" \ + "& C & \n" \ + "}\n" + + # The same diagram, transposed. + grid = DiagramGrid(d, transpose=True) + drawer = XypicDiagramDrawer() + assert drawer.draw(d, grid) == "\\xymatrix{\n" \ + "A \\ar[d]^{f} \\ar@/_3mm/[dd]_{h_{2}} & \\\\\n" \ + "B \\ar[r]^{g} & C \\\\\n" \ + "D \\ar[u]_{k} \\ar@/^7mm/[uu]^{h} \\ar@/^11mm/[uu]^{h_{1}} & \n" \ + "}\n" + + # The same diagram, with "loop" morphisms. + l_A = NamedMorphism(A, A, "l_A") + l_D = NamedMorphism(D, D, "l_D") + l_C = NamedMorphism(C, C, "l_C") + d = Diagram([f, g, h, k, h1, h2, l_A, l_D, l_C]) + grid = DiagramGrid(d) + drawer = XypicDiagramDrawer() + assert drawer.draw(d, grid) == "\\xymatrix{\n" \ + "A \\ar[r]_{f} \\ar@/^3mm/[rr]^{h_{2}} \\ar@(u,l)[]^{l_{A}} " \ + "& B \\ar[d]^{g} & D \\ar[l]^{k} \\ar@/_7mm/[ll]_{h} " \ + "\\ar@/_11mm/[ll]_{h_{1}} \\ar@(r,u)[]^{l_{D}} \\\\\n" \ + "& C \\ar@(l,d)[]^{l_{C}} & \n" \ + "}\n" + + # The same diagram with "loop" morphisms, transposed. + grid = DiagramGrid(d, transpose=True) + drawer = XypicDiagramDrawer() + assert drawer.draw(d, grid) == "\\xymatrix{\n" \ + "A \\ar[d]^{f} \\ar@/_3mm/[dd]_{h_{2}} \\ar@(r,u)[]^{l_{A}} & \\\\\n" \ + "B \\ar[r]^{g} & C \\ar@(r,u)[]^{l_{C}} \\\\\n" \ + "D \\ar[u]_{k} \\ar@/^7mm/[uu]^{h} \\ar@/^11mm/[uu]^{h_{1}} " \ + "\\ar@(l,d)[]^{l_{D}} & \n" \ + "}\n" + + # The same diagram with two "loop" morphisms per object. + l_A_ = NamedMorphism(A, A, "n_A") + l_D_ = NamedMorphism(D, D, "n_D") + l_C_ = NamedMorphism(C, C, "n_C") + d = Diagram([f, g, h, k, h1, h2, l_A, l_D, l_C, l_A_, l_D_, l_C_]) + grid = DiagramGrid(d) + drawer = XypicDiagramDrawer() + assert drawer.draw(d, grid) == "\\xymatrix{\n" \ + "A \\ar[r]_{f} \\ar@/^3mm/[rr]^{h_{2}} \\ar@(u,l)[]^{l_{A}} " \ + "\\ar@/^3mm/@(l,d)[]^{n_{A}} & B \\ar[d]^{g} & D \\ar[l]^{k} " \ + "\\ar@/_7mm/[ll]_{h} \\ar@/_11mm/[ll]_{h_{1}} \\ar@(r,u)[]^{l_{D}} " \ + "\\ar@/^3mm/@(d,r)[]^{n_{D}} \\\\\n" \ + "& C \\ar@(l,d)[]^{l_{C}} \\ar@/^3mm/@(d,r)[]^{n_{C}} & \n" \ + "}\n" + + # The same diagram with two "loop" morphisms per object, transposed. + grid = DiagramGrid(d, transpose=True) + drawer = XypicDiagramDrawer() + assert drawer.draw(d, grid) == "\\xymatrix{\n" \ + "A \\ar[d]^{f} \\ar@/_3mm/[dd]_{h_{2}} \\ar@(r,u)[]^{l_{A}} " \ + "\\ar@/^3mm/@(u,l)[]^{n_{A}} & \\\\\n" \ + "B \\ar[r]^{g} & C \\ar@(r,u)[]^{l_{C}} \\ar@/^3mm/@(d,r)[]^{n_{C}} \\\\\n" \ + "D \\ar[u]_{k} \\ar@/^7mm/[uu]^{h} \\ar@/^11mm/[uu]^{h_{1}} " \ + "\\ar@(l,d)[]^{l_{D}} \\ar@/^3mm/@(d,r)[]^{n_{D}} & \n" \ + "}\n" + + +def test_xypic_draw_diagram(): + # A linear diagram. + A = Object("A") + B = Object("B") + C = Object("C") + D = Object("D") + E = Object("E") + + f = NamedMorphism(A, B, "f") + g = NamedMorphism(B, C, "g") + h = NamedMorphism(C, D, "h") + i = NamedMorphism(D, E, "i") + d = Diagram([f, g, h, i]) + + grid = DiagramGrid(d, layout="sequential") + drawer = XypicDiagramDrawer() + assert drawer.draw(d, grid) == xypic_draw_diagram(d, layout="sequential") diff -Nru python3-sympy-0.7.2/sympy/combinatorics/generators.py python3-sympy-0.7.3/sympy/combinatorics/generators.py --- python3-sympy-0.7.2/sympy/combinatorics/generators.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/combinatorics/generators.py 2013-07-13 17:53:31.000000000 +0000 @@ -3,6 +3,7 @@ from sympy.core.symbol import symbols from sympy.matrices import Matrix + def symmetric(n): """ Generates the symmetric group of order n, Sn. @@ -20,6 +21,7 @@ for perm in variations(list(range(n)), n): yield Permutation(perm) + def cyclic(n): """ Generates the cyclic group of order n, Cn. @@ -43,6 +45,7 @@ yield Permutation(gen) gen = rotate_left(gen, 1) + def alternating(n): """ Generates the alternating group of order n, An. @@ -61,6 +64,7 @@ if p.is_even: yield p + def dihedral(n): """ Generates the dihedral group of order 2n, Dn. @@ -76,8 +80,8 @@ >>> Permutation.print_cyclic = True >>> from sympy.combinatorics.generators import dihedral >>> list(dihedral(3)) - [Permutation(2), Permutation(0, 2), Permutation(0, 1, 2), Permutation(1, 2), - Permutation(0, 2, 1), Permutation(2)(0, 1)] + [Permutation(2), Permutation(0, 2), Permutation(0, 1, 2), + Permutation(1, 2), Permutation(0, 2, 1), Permutation(2)(0, 1)] See Also ======== @@ -103,12 +107,20 @@ """Return the permutations of the 3x3 Rubik's cube, see http://www.gap-system.org/Doc/Examples/rubik.html """ - a = [[(1,3,8,6),(2,5,7,4),(9,33,25,17),(10,34,26,18),(11,35,27,19)], - [(9,11,16,14),(10,13,15,12),(1,17,41,40),(4,20,44,37),(6,22,46,35)], - [(17,19,24,22),(18,21,23,20),(6,25,43,16),(7,28,42,13),(8,30,41,11)], - [(25,27,32,30),(26,29,31,28),(3,38,43,19),(5,36,45,21),(8,33,48,24)], - [(33,35,40,38),(34,37,39,36),(3,9,46,32),(2,12,47,29),(1,14,48,27)], - [(41,43,48,46),(42,45,47,44),(14,22,30,38),(15,23,31,39),(16,24,32,40)]] + a = [ + [(1, 3, 8, 6), (2, 5, 7, 4), (9, 33, 25, 17), (10, 34, 26, 18), + (11, 35, 27, 19)], + [(9, 11, 16, 14), (10, 13, 15, 12), (1, 17, 41, 40), (4, 20, 44, 37), + (6, 22, 46, 35)], + [(17, 19, 24, 22), (18, 21, 23, 20), (6, 25, 43, 16), (7, 28, 42, 13), + (8, 30, 41, 11)], + [(25, 27, 32, 30), (26, 29, 31, 28), (3, 38, 43, 19), (5, 36, 45, 21), + (8, 33, 48, 24)], + [(33, 35, 40, 38), (34, 37, 39, 36), (3, 9, 46, 32), (2, 12, 47, 29), + (1, 14, 48, 27)], + [(41, 43, 48, 46), (42, 45, 47, 44), (14, 22, 30, 38), + (15, 23, 31, 39), (16, 24, 32, 40)] + ] return [Permutation([[i - 1 for i in xi] for xi in x], size=48) for x in a] @@ -127,20 +139,27 @@ # 1-based reference to rows and columns in Matrix def getr(f, i): return faces[f].col(n - i) + def getl(f, i): return faces[f].col(i - 1) + def getu(f, i): return faces[f].row(i - 1) + def getd(f, i): return faces[f].row(n - i) + def setr(f, i, s): - faces[f][:,n - i] = Matrix(n, 1, s) + faces[f][:, n - i] = Matrix(n, 1, s) + def setl(f, i, s): - faces[f][:,i - 1] = Matrix(n, 1, s) + faces[f][:, i - 1] = Matrix(n, 1, s) + def setu(f, i, s): - faces[f][i - 1,:] = Matrix(1, n, s) + faces[f][i - 1, :] = Matrix(1, n, s) + def setd(f, i, s): - faces[f][n - i,:] = Matrix(1, n, s) + faces[f][n - i, :] = Matrix(1, n, s) # motion of a single face def cw(F, r=1): @@ -151,6 +170,7 @@ for r in range(n - 1, -1, -1): rv.append(face[r, c]) faces[F] = Matrix(n, n, rv) + def ccw(F): cw(F, 3) @@ -168,6 +188,7 @@ setl(R, i, list((getd(U, i)))) setd(U, i, list(reversed(temp))) i -= 1 + def fccw(i): fcw(i, 3) @@ -185,6 +206,7 @@ cw(R) faces[D] = faces[R] faces[R] = t + def FCCW(): FCW(3) @@ -198,6 +220,7 @@ faces[R] = faces[B] faces[B] = faces[L] faces[L] = t + def UCCW(): UCW(3) @@ -226,24 +249,24 @@ return p g.append(Permutation(p)) - g = [] # container for the group's permutations - I = list(range(6*n**2)) # the identity permutation used for checking + g = [] # container for the group's permutations + I = list(range(6*n**2)) # the identity permutation used for checking # define permutations corresonding to cw rotations of the planes # up TO the last plane from that direction; by not including the # last plane, the orientation of the cube is maintained. # F slices - for i in range(n-1): + for i in range(n - 1): fcw(i) perm() - fccw(i) # restore + fccw(i) # restore assert perm(1) == I # R slices # bring R to front UCW() - for i in range(n-1): + for i in range(n - 1): fcw(i) # put it back in place UCCW() @@ -262,7 +285,7 @@ FCW() UCCW() FCCW() - for i in range(n-1): + for i in range(n - 1): # turn strip fcw(i) # put bottom back on the bottom diff -Nru python3-sympy-0.7.2/sympy/combinatorics/graycode.py python3-sympy-0.7.3/sympy/combinatorics/graycode.py --- python3-sympy-0.7.2/sympy/combinatorics/graycode.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/combinatorics/graycode.py 2013-07-13 17:53:31.000000000 +0000 @@ -4,6 +4,7 @@ import random + class GrayCode(Basic): """ A Gray code is essentially a Hamiltonian walk on @@ -78,17 +79,20 @@ """ if n < 1 or int(n) != n: - raise ValueError('Gray code dimension must be a positive integer, not %i' % n) + raise ValueError( + 'Gray code dimension must be a positive integer, not %i' % n) n = int(n) args = (n,) + args obj = Basic.__new__(cls, *args) if 'start' in kw_args: obj._current = kw_args["start"] if len(obj._current) > n: - raise ValueError('Gray code start has length %i but should not be greater than %i' % (len(obj._current), n)) + raise ValueError('Gray code start has length %i but ' + 'should not be greater than %i' % (len(obj._current), n)) elif 'rank' in kw_args: if int(kw_args["rank"]) != kw_args["rank"]: - raise ValueError('Gray code rank must be a positive integer, not %i' % kw_args["rank"]) + raise ValueError('Gray code rank must be a positive integer, ' + 'not %i' % kw_args["rank"]) obj._rank = int(kw_args["rank"]) % obj.selections obj._current = obj.unrank(n, obj._rank) return obj @@ -170,12 +174,13 @@ start = hints["start"] elif "rank" in hints: start = GrayCode.unrank(self.n, hints["rank"]) - if start != None: + if start is not None: self._current = start current = self.current graycode_bin = gray_to_bin(current) if len(graycode_bin) > self.n: - raise ValueError('Gray code start has length %i but should not be greater than %i' % (len(graycode_bin), bits)) + raise ValueError('Gray code start has length %i but should ' + 'not be greater than %i' % (len(graycode_bin), bits)) self._current = int(current, 2) graycode_int = int(''.join(graycode_bin), 2) for i in range(graycode_int, 1 << bits): @@ -299,6 +304,7 @@ return '1' + _unrank(m - (k % m) - 1, n - 1) return _unrank(rank, n) + def random_bitstring(n): """ Generates a random bitlist of length n. @@ -312,6 +318,7 @@ """ return ''.join([random.choice('01') for i in range(n)]) + def gray_to_bin(bin_list): """ Convert from Gray coding to binary coding. @@ -331,9 +338,10 @@ """ b = [bin_list[0]] for i in range(1, len(bin_list)): - b += str(int(b[i-1] != bin_list[i])) + b += str(int(b[i - 1] != bin_list[i])) return ''.join(b) + def bin_to_gray(bin_list): """ Convert from binary coding to gray coding. @@ -356,6 +364,7 @@ b += str(int(bin_list[i]) ^ int(b[i - 1])) return ''.join(b) + def get_subset_from_bitstring(super_set, bitstring): """ Gets the subset defined by the bitstring. @@ -375,9 +384,10 @@ """ if len(super_set) != len(bitstring): raise ValueError("The sizes of the lists are not equal") - return [super_set[i] for i, j in enumerate(bitstring) \ + return [super_set[i] for i, j in enumerate(bitstring) if bitstring[i] == '1'] + def graycode_subsets(gray_code_set): """ Generates the subsets as enumerated by a Gray code. @@ -398,5 +408,5 @@ ======== get_subset_from_bitstring """ - return [get_subset_from_bitstring(gray_code_set, bitstring) for \ - bitstring in list(GrayCode(len(gray_code_set)).generate_gray())] + for bitstring in list(GrayCode(len(gray_code_set)).generate_gray()): + yield get_subset_from_bitstring(gray_code_set, bitstring) diff -Nru python3-sympy-0.7.2/sympy/combinatorics/group_constructs.py python3-sympy-0.7.3/sympy/combinatorics/group_constructs.py --- python3-sympy-0.7.2/sympy/combinatorics/group_constructs.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/combinatorics/group_constructs.py 2013-07-13 17:53:31.000000000 +0000 @@ -4,6 +4,7 @@ _af_new = Permutation._af_new + def DirectProduct(*groups): """ Returns the direct product of several groups as a permutation group. @@ -48,9 +49,9 @@ for i in range(len(gens_count)): for j in range(current_gen, current_gen + gens_count[i]): gen = ((groups[i].generators)[j - current_gen]).array_form - array_gens[j][current_deg:current_deg + degrees[i]] =\ - [ x + current_deg for x in gen] + array_gens[j][current_deg:current_deg + degrees[i]] = \ + [ x + current_deg for x in gen] current_gen += gens_count[i] current_deg += degrees[i] - perm_gens = uniq([_af_new(list(a)) for a in array_gens]) + perm_gens = list(uniq([_af_new(list(a)) for a in array_gens])) return PermutationGroup(perm_gens, dups=False) diff -Nru python3-sympy-0.7.2/sympy/combinatorics/named_groups.py python3-sympy-0.7.3/sympy/combinatorics/named_groups.py --- python3-sympy-0.7.2/sympy/combinatorics/named_groups.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/combinatorics/named_groups.py 2013-07-13 17:53:31.000000000 +0000 @@ -4,6 +4,7 @@ _af_new = Permutation._af_new + def AbelianGroup(*cyclic_orders): """ Returns the direct product of cyclic groups with the given orders. @@ -11,8 +12,7 @@ According to the structure theorem for finite abelian groups ([1]), every finite abelian group can be written as the direct product of finitely many cyclic groups. - [1] http://groupprops.subwiki.org/wiki/Structure_theorem_for_finitely - _generated_abelian_groups + [1] http://groupprops.subwiki.org/wiki/Structure_theorem_for_finitely_generated_abelian_groups Examples ======== @@ -45,6 +45,7 @@ return G + def AlternatingGroup(n): """ Generates the alternating group on ``n`` elements as a permutation group. @@ -102,13 +103,20 @@ if n < 4: G._is_abelian = True + G._is_nilpotent = True else: G._is_abelian = False + G._is_nilpotent = False + if n < 5: + G._is_solvable = True + else: + G._is_solvable = False G._degree = n G._is_transitive = True G._is_alt = True return G + def CyclicGroup(n): """ Generates the cyclic group of order ``n`` as a permutation group. @@ -142,11 +150,14 @@ G = PermutationGroup([gen]) G._is_abelian = True + G._is_nilpotent = True + G._is_solvable = True G._degree = n G._is_transitive = True G._order = n return G + def DihedralGroup(n): r""" Generates the dihedral group `D_n` as a permutation group. @@ -198,13 +209,19 @@ a.reverse() gen2 = _af_new(a) G = PermutationGroup([gen1, gen2]) - + # if n is a power of 2, group is nilpotent + if n & (n-1) == 0: + G._is_nilpotent = True + else: + G._is_nilpotent = False G._is_abelian = False + G._is_solvable = True G._degree = n G._is_transitive = True G._order = 2*n return G + def SymmetricGroup(n): """ Generates the symmetric group on ``n`` elements as a permutation group. @@ -224,11 +241,11 @@ >>> G.order() 24 >>> list(G.generate_schreier_sims(af=True)) - [[0, 1, 2, 3], [0, 1, 3, 2], [0, 2, 1, 3], [0, 2, 3, 1], [0, 3, 1, 2], - [0, 3, 2, 1], [1, 2, 3, 0], [1, 2, 0, 3], [1, 3, 2, 0], - [1, 3, 0, 2], [1, 0, 2, 3], [1, 0, 3, 2], [2, 3, 0, 1], [2, 3, 1, 0], - [2, 0, 3, 1], [2, 0, 1, 3], [2, 1, 3, 0], [2, 1, 0, 3], [3, 0, 1, 2], - [3, 0, 2, 1], [3, 1, 0, 2], [3, 1, 2, 0], [3, 2, 0, 1], [3, 2, 1, 0]] + [[0, 1, 2, 3], [1, 2, 3, 0], [2, 3, 0, 1], [3, 1, 2, 0], [0, 2, 3, 1], + [1, 3, 0, 2], [2, 0, 1, 3], [3, 2, 0, 1], [0, 3, 1, 2], [1, 0, 2, 3], + [2, 1, 3, 0], [3, 0, 1, 2], [0, 1, 3, 2], [1, 2, 0, 3], [2, 3, 1, 0], + [3, 1, 0, 2], [0, 2, 1, 3], [1, 3, 2, 0], [2, 0, 3, 1], [3, 2, 1, 0], + [0, 3, 2, 1], [1, 0, 3, 2], [2, 1, 0, 3], [3, 0, 2, 1]] See Also ======== @@ -246,23 +263,29 @@ elif n == 2: G = PermutationGroup([Permutation([1, 0])]) else: - a = list(range(1,n)) + a = list(range(1, n)) a.append(0) gen1 = _af_new(a) a = list(range(n)) a[0], a[1] = a[1], a[0] gen2 = _af_new(a) G = PermutationGroup([gen1, gen2]) - - if n<3: + if n < 3: G._is_abelian = True + G._is_nilpotent = True else: G._is_abelian = False + G._is_nilpotent = False + if n < 5: + G._is_solvable = True + else: + G._is_solvable = False G._degree = n G._is_transitive = True G._is_sym = True return G + def RubikGroup(n): """Return a group of Rubik's cube generators. >>> from sympy.combinatorics.named_groups import RubikGroup diff -Nru python3-sympy-0.7.2/sympy/combinatorics/partitions.py python3-sympy-0.7.3/sympy/combinatorics/partitions.py --- python3-sympy-0.7.2/sympy/combinatorics/partitions.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/combinatorics/partitions.py 2013-07-13 17:53:31.000000000 +0000 @@ -1,11 +1,12 @@ from sympy.core import Basic, C, Dict, sympify -from sympy.core.compatibility import as_int +from sympy.core.compatibility import as_int, default_sort_key +from sympy.functions.combinatorial.numbers import bell from sympy.matrices import zeros -from sympy.utilities.misc import default_sort_key from sympy.utilities.iterables import has_dups, flatten, group from collections import defaultdict + class Partition(C.FiniteSet): """ This class represents an abstract partition. @@ -193,7 +194,7 @@ >>> a.rank 13 """ - if self._rank != None: + if self._rank is not None: return self._rank self._rank = RGS_rank(self.RGS) return self._rank @@ -264,6 +265,7 @@ raise ValueError('some blocks of the partition were empty.') return Partition(partition) + class IntegerPartition(Basic): """ This class represents an integer partition. @@ -283,7 +285,7 @@ sympy.utilities.iterables.partitions, sympy.utilities.iterables.multiset_partitions - Reference: http://en.wikipedia.org/wiki/Partition_(number_theory) + Reference: http://en.wikipedia.org/wiki/Partition_%28number_theory%29 """ _dict = None @@ -527,6 +529,7 @@ def __str__(self): return str(list(self.partition)) + def random_integer_partition(n, seed=None): """ Generates a random integer partition summing to ``n`` as a list @@ -565,6 +568,7 @@ partition = flatten([[k]*m for k, m in partition]) return partition + def RGS_generalized(m): """ Computes the m + 1 generalized unrestricted growth strings @@ -575,13 +579,14 @@ >>> from sympy.combinatorics.partitions import RGS_generalized >>> RGS_generalized(6) - [ 1, 1, 1, 1, 1, 1, 1] - [ 1, 2, 3, 4, 5, 6, 0] - [ 2, 5, 10, 17, 26, 0, 0] - [ 5, 15, 37, 77, 0, 0, 0] - [ 15, 52, 151, 0, 0, 0, 0] - [ 52, 203, 0, 0, 0, 0, 0] - [203, 0, 0, 0, 0, 0, 0] + Matrix([ + [ 1, 1, 1, 1, 1, 1, 1], + [ 1, 2, 3, 4, 5, 6, 0], + [ 2, 5, 10, 17, 26, 0, 0], + [ 5, 15, 37, 77, 0, 0, 0], + [ 15, 52, 151, 0, 0, 0, 0], + [ 52, 203, 0, 0, 0, 0, 0], + [203, 0, 0, 0, 0, 0, 0]]) """ d = zeros(m + 1) for i in range(0, m + 1): @@ -590,12 +595,12 @@ for i in range(1, m + 1): for j in range(m): if j <= m - i: - d[i, j] = j * d[i - 1, j] \ - + d[i - 1, j + 1] + d[i, j] = j * d[i - 1, j] + d[i - 1, j + 1] else: d[i, j] = 0 return d + def RGS_enum(m): """ RGS_enum computes the total number of restricted growth strings @@ -623,20 +628,15 @@ ... a += 1 ... >>> assert len(s) == 15 + """ if (m < 1): return 0 elif (m == 1): return 1 else: - m += 1 - b = [1] * (m) - for j in range(1, m): - for i in range(1, j): - b[j] += C.binomial(j - 1, i) * b[i] + return bell(m) - nrgf = b[m - 1] - return nrgf def RGS_unrank(rank, m): """ @@ -660,7 +660,7 @@ L = [1] * (m + 1) j = 1 D = RGS_generalized(m) - for i in range(2, m+1): + for i in range(2, m + 1): v = D[m - i, j] cr = j*v if cr <= rank: @@ -672,6 +672,7 @@ rank %= v return [x - 1 for x in L[1:]] + def RGS_rank(rgs): """ Computes the rank of a restricted growth string. diff -Nru python3-sympy-0.7.2/sympy/combinatorics/perm_groups.py python3-sympy-0.7.3/sympy/combinatorics/perm_groups.py --- python3-sympy-0.7.2/sympy/combinatorics/perm_groups.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/combinatorics/perm_groups.py 2013-07-13 17:53:31.000000000 +0000 @@ -4,334 +4,19 @@ from sympy.core import Basic from sympy.combinatorics import Permutation from sympy.combinatorics.permutations import (_af_commutes_with, _af_invert, - _af_rmul, _af_rmuln, Cycle) + _af_rmul, _af_rmuln, _af_pow, Cycle) from sympy.combinatorics.util import (_check_cycles_alt_sym, _distribute_gens_by_base, _orbits_transversals_from_bsgs, _handle_precomputed_bsgs, _base_ordering, _strong_gens_from_distr, - _strip) + _strip, _strip_af) from sympy.functions.combinatorial.factorials import factorial from sympy.ntheory import sieve from sympy.utilities.iterables import has_variety, is_sequence, uniq from sympy.utilities.randtest import _randrange -rmul = Permutation.rmul +rmul = Permutation.rmul_with_af _af_new = Permutation._af_new -def _smallest_change(h, alpha): - """Return smallest point not fixed by ``h`` else return None.""" - for i in range(alpha, len(h)): - if h[i] != i: - return i - -class _Vertex(object): - """Represents a vertex of JGraph. - - Parameters - ========== - - neighbor - list of neighbor vertices - perm - list of permutations - index_neighbor - list of index position of vertices in neighbor where, - if vertex j is a neighbor of vertex i, then - vertex[i].index_neighbor[ vertex[i].neighbor[j] ] = j, and - if vertex j is not a neighbor of vertex i, - vertex[i].index_neighbor[j] = -1 - n - size of permutation - - """ - def __init__(self, n): - - self.neighbor = [] - self.perm = [] - self.index_neighbor = [-1]*n - -class _JGraph(object): - """Represents a Jerrum graph. - - Parameters - ========== - - vertex - vertices of the Jerrum graph for permutation group G < S(n) - vertex[i] is the i-th vertex (with ``i`` in range(n)) - jg - array of Jerrums generators (edges of the graph) - jgs - number of occupied entries of ``jg`` - freejg - stack of slots of ``jg`` such that ``freejg[i]`` points to the i-th - free position of ``jg``. To a directed edge ``(i, j)`` between vertices - ``i`` and ``j`` it is associated the index of a permutation ``g`` - satisfying ``g[i] = j`` where - ``g = jg[vertex[i].perm[vertex[i].index_neighbor[j]]] - = jg[vertex[j].perm[vertex[j].index_neighbor[i]]]`` - - cycle - list of indices of vertices used to identify cycles - G - Permutation group - n - size of permutation - r - number of generators - """ - def __init__(self, G): - n = G._degree - self.vertex = [_Vertex(n) for i in range(n)] - self.gens = [p.array_form for p in G._generators] - self.jg = [None]*n - self.jgs = 0 - self.freejg = [] - self.cycle = [] - self.G = G - self.n = G._degree - self.r = G._r - - def find_cycle(self, v, v1, v2, prev): - """Test if there is a cycle. - - Parameters - ========== - - v - vertex from which start searching a cycle - v1, v2 - vertices through which the cycle must go - prev - previous vertex - """ - cycle = self.cycle - neighbor = self.vertex[v].neighbor - if v1 in neighbor: - if v1 != prev: - return True - if v2 in neighbor: - if v2 != prev: - cycle.append(v2) - if self.find_cycle(v2, v1, v2, v): - return True - cycle.pop() - for u in neighbor: - if u != prev: - cycle.append(u) - if self.find_cycle(u, v1, v2, v): - return True - cycle.pop() - return False - - def insert(self, g, alpha): - """insert permutation ``g`` in stabilizer chain at point alpha - """ - i = _smallest_change(g, alpha) - if i is None: - return - - vertex = self.vertex - jg = self.jg - gi = g[i] - nn = vertex[i].index_neighbor[gi] - if nn >= 0: # if gi is already neighbor of i - jginn = jg[vertex[i].perm[nn]] - if g != jginn: - # cycle consisting of two edges; - # replace jginn by g and insert h = g**-1*jginn - g1 = _af_invert(g) - h = _af_rmul(g1, jginn) - jg[ vertex[i].perm[nn] ] = g - self.insert(h, alpha) - else: # new edge - self.insert_edge(g, i, gi) - self.cycle = [i] - if self.find_cycle(i, i, gi, -1): - cycle = self.cycle - cycle.append(cycle[0]) - # find the smallest point (vertex) of the cycle - cmin = cycle.index(min(cycle)) - - # now walk around the cycle starting from the smallest - # point, and multiply around the cycle to obtain h - # satisfying h[cmin] = cmin - ap = [] - for c in range(cmin - len(cycle), cmin - 1): - i = cycle[c] - j = cycle[c + 1] - nn = vertex[i].index_neighbor[j] - p = jg[ vertex[i].perm[nn] ] - if i > j: - p = _af_invert(p) - ap.append(p) - ap.reverse() - h = _af_rmuln(*ap) - self.remove_edge(cycle[cmin], cycle[cmin + 1]) - self.insert(h, alpha) - - def insert_edge(self, g, i, gi): - """insert edge (permutation g) moving i to gi (i < gi) - """ - vertex = self.vertex - self.jgs += 1 - jgslot = self.freejg.pop() # the last free generator place - self.jg[jgslot] = g - nn = len(vertex[i].neighbor) - vertex[i].neighbor.append(gi) - vertex[i].perm.append(jgslot) - vertex[i].index_neighbor[gi] = nn - nn = len(vertex[gi].neighbor) - vertex[gi].neighbor.append(i) - vertex[gi].perm.append(jgslot) - vertex[gi].index_neighbor[i] = nn - - def jerrum_filter(self, alpha, cri): - """filter the generators of the stabilizer subgroup G_alpha - - Parameters - ========== - - alpha - point for which the stabilizer is computed - cri[i] - inverse of G._stabilizer_cosets[i] if ``i`` is not None - - Notes - ===== - - Schreier lemma:: - - the stabilizer subgroup G_alpha of G - is generated by the schreier generators - h = cosrep[ p2[i] ]**-1 * g[j] * cosrep[i] - where j=0,..,len(gens)-1 and i=0,..,n-1, where n is the degree. - - Proof that h belongs to G_alpha:: - - cosrep[k][alpha] = k for all k; cosrep[k]**-1[k] = alpha - p1 = cosrep[i]; p2 = g[j] - p3 = cosrep[ p2[i] ]; p3[alpha] = p2[i] - p3**-1[p2[i] = alpha - p3**-1[p2[p1[alpha]] = alpha, so h[alpha] = alpha - - Using Jerrum's filter one can reduce the len(gens)*n generators - of G_alpha produced by the Schreier lemma to at most n-1 - - Jerrum's filter - --------------- - - (see Cameron 'Permutation groups', page 22) - _JGraph has n-1 vertices; the edges (i, j) are labeled by - group elements ``g`` with j = imin(g) = min(i | g[i] != i); - define m(graph) = sum(imin(g) for g in graph) - - At the beginning the graph has no edges, so it is - an acyclic graph. - - Insert a group element ``g`` produced by the Schreier lemma; - introduce in _JGraph an edge (imin(g), g[imin(g)); - if the graph contains a cycle, let ``i0`` be the smallest point - in the cycle, and ``h`` the product of the group elements labeling - the edges in the cycle, starting from ``i0``; h[j] = j for j <= i0; - modify it eliminating the edge (i0, g0[i0]) in the cycle; one obtains - a new acyclic graph with m(graph_new) > m(graph). ``g0`` can be - expressed as a product of ``h`` and the other elements in the cycle. - - Then insert ``h`` in the graph, and so on. - - Since m < n**2, this process ends after a finite number of times, so - in the end one remains with an acyclic graph, with at most n-1 edges - and the same number of generators. - """ - n = self.n - r = self.r - G = self.G - gens = self.gens - cosrep = G._stabilizer_cosets - self.jgs = 0 - for j in range(n): - self.jg[j] = None - self.freejg = list(range(n)) - for i in range(n): - self.vertex[i].neighbor = [] - self.vertex[i].perm = [] - for i in range(n): - for j in range(n): - self.vertex[i].index_neighbor[j] = -1 - - for i in range(n): - if cosrep[i] != None: - p1 = cosrep[i] - for j in range(r): - p2 = gens[j] - p3 = cri[ p2[i] ] - h = [p3[p2[k]] for k in p1] - self.insert(h, alpha) - r = 0 - for j in range(n): - if self.jg[j] != None: - gens[r] = self.jg[j] - r += 1 - self.r = r - - def remove_edge(self, i, gi): - """remove edge from i to gi - """ - vertex = self.vertex - # remove the permutation labeling this edge - self.jgs -= 1 - jgslot = vertex[i].perm[ vertex[i].index_neighbor[gi] ] - self.jg[jgslot] = None - self.freejg.append(jgslot) # now we gained a free place - - for i1, i2 in ((i, gi), (gi, i)): - v = vertex[i1] - j0 = v.index_neighbor[i2] - v.neighbor.pop(j0) - v.perm.pop(j0) - # the index of the vertices >= j0 in vertex[i] has changed - for j in range(j0, len(v.neighbor)): - v.index_neighbor[ v.neighbor[j] ] = j - v.index_neighbor[gi] = -1 - - def schreier_tree(self, alpha, gen): - """traversal of the orbit of alpha - - Compute a traversal of the orbit of alpha, storing the values - in G._stabilizer_cosets; G._stabilizer_cosets[i][alpha] = i if i belongs - to the orbit of alpha. - """ - G = self.G - G._stabilizer_cosets[alpha] = gen - G._stabilizer_cosets_n += 1 - genv = self.gens[:self.r] - h = 0 - r = self.r - stg = [gen] - sta = [alpha] - pos = [0]*self.n - while 1: - # backtrack when finished iterating over generators - if pos[h] >= r: - if h == 0: - return - pos[h] = 0 - h -= 1 - sta.pop() - stg.pop() - continue - g = genv[pos[h]] - pos[h] += 1 - alpha = sta[-1] - ag = g[alpha] - - if G._stabilizer_cosets[ag] is None: - gen1 = _af_rmul(g, stg[-1]) - G._stabilizer_cosets[ag] = gen1 - G._stabilizer_cosets_n += 1 - sta.append(ag) - stg.append(gen1) - h += 1 class PermutationGroup(Basic): """The class defining a Permutation group. @@ -447,7 +132,7 @@ if args[i].size != degree: args[i] = Permutation(args[i], size=degree) if kwargs.pop('dups', True): - args = uniq([Permutation._af_new(list(a)) for a in args]) + args = list(uniq([_af_new(list(a)) for a in args])) obj = Basic.__new__(cls, *args, **kwargs) obj._generators = args obj._order = None @@ -467,9 +152,6 @@ # these attributes are assigned after running schreier_sims obj._base = [] - obj._stabilizer_cosets = [] - obj._stabilizer_cosets_n = [] - obj._stabilizer_gens = [] obj._strong_gens = [] obj._basic_orbits = [] obj._transversals = [] @@ -532,10 +214,10 @@ 25 """ - gens1 = [perm.array_form for perm in self.generators] - gens2 = [perm.array_form for perm in other.generators] - n1 = self.degree - n2 = other.degree + gens1 = [perm._array_form for perm in self.generators] + gens2 = [perm._array_form for perm in other.generators] + n1 = self._degree + n2 = other._degree start = list(range(n1)) end = list(range(n1, n1 + n2)) for i in range(len(gens2)): @@ -586,22 +268,22 @@ """ deg = self.degree - random_gens = self.generators[:] + random_gens = [x._array_form for x in self.generators] k = len(random_gens) if k < r: for i in range(k, r): random_gens.append(random_gens[i - k]) - acc = _af_new(list(range(deg))) + acc = list(range(deg)) random_gens.append(acc) self._random_gens = random_gens # handle randomized input for testing purposes - if _random_prec_n == None: + if _random_prec_n is None: for i in range(n): self.random_pr() else: for i in range(n): - self.random_pr(_random_prec = _random_prec_n[i]) + self.random_pr(_random_prec=_random_prec_n[i]) def _union_find_merge(self, first, second, ranks, parents, not_rep): """Merges two classes in a union-find data structure. @@ -710,10 +392,6 @@ >>> G = PermutationGroup([Permutation(0, 1, 3)(2, 4)]) >>> G.base [0, 2] - >>> I = [Permutation(G.degree - 1)] - >>> c = G.stabilizer_cosets() - >>> [i for i in range(len(c)) if c[i] != I] - [0, 2] See Also ======== @@ -725,7 +403,7 @@ self.schreier_sims() return self._base - def baseswap(self, base, strong_gens, pos, randomized=False,\ + def baseswap(self, base, strong_gens, pos, randomized=False, transversals=None, basic_orbits=None, strong_gens_distr=None): r"""Swap two consecutive base points in base and strong generating set. @@ -765,15 +443,21 @@ >>> from sympy.combinatorics.named_groups import SymmetricGroup >>> from sympy.combinatorics.testutil import _verify_bsgs + >>> from sympy.combinatorics.perm_groups import PermutationGroup >>> S = SymmetricGroup(4) >>> S.schreier_sims() - >>> S.baseswap(S.base, S.strong_gens, 1, randomized=False) - ([0, 2, 1], - [Permutation(0, 1, 2, 3), Permutation(3)(0, 1), Permutation(2, 3), - Permutation(1, 3, 2), Permutation(1, 3)]) >>> S.base [0, 1, 2] - >>> _verify_bsgs(S, S.base, S.strong_gens) + >>> base, gens = S.baseswap(S.base, S.strong_gens, 1, randomized=False) + >>> base, gens + ([0, 2, 1], + [Permutation(0, 1, 2, 3), Permutation(3)(0, 1), Permutation(1, 3, 2), + Permutation(2, 3), Permutation(1, 3)]) + + check that base, gens is a BSGS + + >>> S1 = PermutationGroup(gens) + >>> _verify_bsgs(S1, base, gens) True See Also @@ -796,34 +480,29 @@ """ # construct the basic orbits, generators for the stabilizer chain # and transversal elements from whatever was provided - transversals, basic_orbits, strong_gens_distr =\ - _handle_precomputed_bsgs(base, strong_gens, transversals,\ + transversals, basic_orbits, strong_gens_distr = \ + _handle_precomputed_bsgs(base, strong_gens, transversals, basic_orbits, strong_gens_distr) base_len = len(base) degree = self.degree - stab_pos = PermutationGroup(strong_gens_distr[pos]) # size of orbit of base[pos] under the stabilizer we seek to insert # in the stabilizer chain at position pos + 1 - size = len(basic_orbits[pos])*len(basic_orbits[pos + 1])\ - //len(stab_pos.orbit(base[pos + 1])) + size = len(basic_orbits[pos])*len(basic_orbits[pos + 1]) \ + //len(_orbit(degree, strong_gens_distr[pos], base[pos + 1])) # initialize the wanted stabilizer by a subgroup if pos + 2 > base_len - 1: T = [] else: T = strong_gens_distr[pos + 2][:] - if T == []: - current_group = PermGroup([_af_new(list(range(degree)))]) - else: - current_group = PermGroup(T) # randomized version if randomized is True: + stab_pos = PermutationGroup(strong_gens_distr[pos]) schreier_vector = stab_pos.schreier_vector(base[pos + 1]) # add random elements of the stabilizer until they generate it - while len(current_group.orbit(base[pos])) != size: - new = stab_pos.random_stab(base[pos + 1],\ + while len(_orbit(degree, T, base[pos])) != size: + new = stab_pos.random_stab(base[pos + 1], schreier_vector=schreier_vector) T.append(new) - current_group = PermutationGroup(T) # deterministic version else: Gamma = set(basic_orbits[pos]) @@ -832,20 +511,18 @@ Gamma.remove(base[pos + 1]) # add elements of the stabilizer until they generate it by # ruling out member of the basic orbit of base[pos] along the way - while len(current_group.orbit(base[pos])) != size: + while len(_orbit(degree, T, base[pos])) != size: gamma = next(iter(Gamma)) x = transversals[pos][gamma] - x_inverse = ~x - temp = x_inverse(base[pos + 1]) + temp = x._array_form.index(base[pos + 1]) # (~x)(base[pos + 1]) if temp not in basic_orbits[pos + 1]: - Gamma = Gamma - current_group.orbit(gamma) + Gamma = Gamma - _orbit(degree, T, gamma) else: y = transversals[pos + 1][temp] el = rmul(x, y) - if el(base[pos]) not in current_group.orbit(base[pos]): + if el(base[pos]) not in _orbit(degree, T, base[pos]): T.append(el) - current_group = PermutationGroup(T) - Gamma = Gamma - current_group.orbit(base[pos]) + Gamma = Gamma - _orbit(degree, T, base[pos]) # build the new base and strong generating set strong_gens_new_distr = strong_gens_distr[:] strong_gens_new_distr[pos + 1] = T @@ -906,13 +583,12 @@ [0, 1] >>> for g in A.basic_stabilizers: ... print(g) + ... PermutationGroup([ Permutation(3)(0, 1, 2), - Permutation(1, 2, 3), - Permutation(1, 3, 2)]) + Permutation(1, 2, 3)]) PermutationGroup([ - Permutation(1, 2, 3), - Permutation(1, 3, 2)]) + Permutation(1, 2, 3)]) See Also ======== @@ -921,7 +597,7 @@ """ - if self._stabilizer_cosets == []: + if self._transversals == []: self.schreier_sims() strong_gens = self._strong_gens base = self._base @@ -956,28 +632,13 @@ 2: Permutation(1, 2, 3), 3: Permutation(1, 3, 2)}] - A list of lists of the values of each dictionary can be obtained with - the stabilizer_cosets method. - - >>> A.stabilizer_cosets() - [[Permutation(3), - Permutation(3)(0, 1, 2), - Permutation(3)(0, 2, 1), - Permutation(0, 3, 1)], - [Permutation(3), - Permutation(1, 2, 3), - Permutation(1, 3, 2)]] - >>> A.stabilizer_cosets(af=True) - [[[0, 1, 2, 3], [1, 2, 0, 3], [2, 0, 1, 3], [3, 0, 2, 1]], - [[0, 1, 2, 3], [0, 2, 3, 1], [0, 3, 1, 2]]] - - See Also ======== - strong_gens, base, basic_orbits, basic_stabilizers, stabilizer_cosets + strong_gens, base, basic_orbits, basic_stabilizers """ + if self._transversals == []: self.schreier_sims() return self._transversals @@ -1071,7 +732,7 @@ identity = _af_new(list(range(degree))) orbits = other.orbits() num_orbits = len(orbits) - orbits.sort(key = lambda x: -len(x)) + orbits.sort(key=lambda x: -len(x)) long_base = [] orbit_reps = [None]*num_orbits orbit_reps_indices = [None]*num_orbits @@ -1100,7 +761,7 @@ for j in range(num_rel_orbits): rep = orbit_reps[j] transversals[j] = dict( - other.orbit_transversal(rep, pairs=True)) + other.orbit_transversal(rep, pairs=True)) trivial_test = lambda x: True tests = [None]*base_len for l in range(base_len): @@ -1111,16 +772,18 @@ g = computed_words[l] rep_orb_index = orbit_descr[base[l]] rep = orbit_reps[rep_orb_index] - im = g(base[l]) - im_rep = g(rep) + im = g._array_form[base[l]] + im_rep = g._array_form[rep] tr_el = transversals[rep_orb_index][base[l]] - if im != tr_el(im_rep): - return False - else: - return True + # using the definition of transversal, + # base[l]^g = rep^(tr_el*g); + # if g belongs to the centralizer, then + # base[l]^g = (rep^g)^tr_el + return im == tr_el._array_form[im_rep] tests[l] = test + def prop(g): - return [rmul(g, gen) for gen in other.generators] ==\ + return [rmul(g, gen) for gen in other.generators] == \ [rmul(gen, g) for gen in other.generators] return self.subgroup_search(prop, base=base, strong_gens=strong_gens, tests=tests) @@ -1174,50 +837,29 @@ res = self.normal_closure(commutators) return res - def coset_factor(self, g, af=False): - """Return ``G``'s (self's) coset factorization, ``f``, of ``g`` + def coset_factor(self, g, factor_index=False): + """Return ``G``'s (self's) coset factorization of ``g`` If ``g`` is an element of ``G`` then it can be written as the product of permutations drawn from the Schreier-Sims coset decomposition, - ``u``, of ``G``. The permutations returned in ``f`` are those for which + + The permutations returned in ``f`` are those for which the product gives ``g``: ``g = f[n]*...f[1]*f[0]`` where ``n = len(B)`` - and ``B = G.base``. f[i] is one of the permutations in coset[B[i]]. + and ``B = G.base``. f[i] is one of the permutations in + ``self._basic_orbits[i]``. + + If factor_index==True, + returns a tuple ``[b[0],..,b[n]]``, where ``b[i]`` + belongs to ``self._basic_orbits[i]`` Examples ======== - >>> from sympy.combinatorics import Permutation, Cycle + >>> from sympy.combinatorics import Permutation, PermutationGroup >>> Permutation.print_cyclic = True - >>> from sympy.combinatorics.perm_groups import PermutationGroup - >>> a = Permutation(0, 1, 3, 7, 6, 4)(2, 5) >>> b = Permutation(0, 1, 3, 2)(4, 5, 7, 6) >>> G = PermutationGroup([a, b]) - >>> u = G.stabilizer_cosets() - - The coset decomposition of G has a u of length 3: - - >>> for i, ui in enumerate(u): - ... print('u%s:' % i) - ... for p in ui: - ... print(' ', p) - ... - u0: - Permutation(7) - Permutation(0, 1, 3, 7, 6, 4)(2, 5) - Permutation(0, 2, 6, 4)(1, 3, 7, 5) - Permutation(0, 3, 6)(1, 7, 4) - Permutation(0, 4, 6, 7, 3, 1)(2, 5) - Permutation(0, 5)(2, 7) - Permutation(0, 6, 3)(1, 4, 7) - Permutation(0, 7)(1, 6)(2, 5)(3, 4) - u1: - Permutation(7) - Permutation(7)(1, 2)(5, 6) - Permutation(7)(1, 4, 2)(3, 5, 6) - u2: - Permutation(7) - Permutation(7)(2, 4)(3, 5) Define g: @@ -1232,22 +874,14 @@ 3) drawn from u. See below that a factor from u1 and u2 and the Identity permutation have been used: - >>> f = G.coset_factor(g); f - [Permutation(7), - Permutation(7)(1, 2)(5, 6), - Permutation(7)(2, 4)(3, 5)] - - We confirm that the product of f gives the original g: - + >>> f = G.coset_factor(g) >>> f[2]*f[1]*f[0] == g True - - If g is already in the coset decomposition of G then it (and - Identity permutations) will be returned: - - >>> g = Permutation(u[2][1]) - >>> G.coset_factor(g) - [Permutation(7), Permutation(7), Permutation(7)(2, 4)(3, 5)] + >>> f1 = G.coset_factor(g, True); f1 + [0, 4, 4] + >>> tr = G.basic_transversals + >>> f[0] == tr[0][f1[0]] + True If g is not an element of G then [] is returned: @@ -1255,33 +889,38 @@ >>> G.coset_factor(c) [] + see util._strip """ if isinstance(g, (Cycle, Permutation)): g = g.list() - if len(g) != self.degree: + if len(g) != self._degree: # this could either adjust the size or return [] immediately # but we don't choose between the two and just signal a possible # error raise ValueError('g should be the same size as permutations of G') - I = list(range(self.degree)) - # compute u - u = self.stabilizer_cosets(af=True) - # search for factors - g_now = g - f = [] - for i in range(len(u)): - for h in u[i]: - if h[i] == g_now[i]: - f.append(h) - hinv = _af_invert(h) - g_now = _af_rmul(hinv, g_now) - break - else: + I = list(range(self._degree)) + basic_orbits = self.basic_orbits + transversals = self._transversals + factors = [] + base = self.base + h = g + for i in range(len(base)): + beta = h[base[i]] + if beta == base[i]: + factors.append(beta) + continue + if beta not in basic_orbits[i]: return [] - rv = [f[j] for j in self.base] if g_now == I else [] - if af: - return rv - return [Permutation(i) for i in rv] + u = transversals[i][beta]._array_form + h = _af_rmul(_af_invert(u), h) + factors.append(beta) + if h != I: + return [] + if factor_index: + return factors + tr = self.basic_transversals + factors = [tr[i][factors[i]] for i in range(len(base))] + return factors def coset_rank(self, g): """rank using Schreier-Sims representation @@ -1302,11 +941,11 @@ >>> a = Permutation(0, 1, 3, 7, 6, 4)(2, 5) >>> b = Permutation(0, 1, 3, 2)(4, 5, 7, 6) >>> G = PermutationGroup([a, b]) - >>> c = Permutation(2, 4)(3, 5) + >>> c = Permutation(7)(2, 4)(3, 5) >>> G.coset_rank(c) - 1 - >>> G.coset_unrank(1, af=True) - [0, 1, 4, 5, 2, 3, 6, 7] + 16 + >>> G.coset_unrank(16) + Permutation(7)(2, 4)(3, 5) See Also ======== @@ -1314,42 +953,20 @@ coset_factor """ - u = self.stabilizer_cosets(True) - if isinstance(g, (Cycle, Permutation)): - g = g.list() - # the only error checking is size adjustment; it is assumed that - # elements 0..len(g) - 1 are present - if len(g) != self.degree: - g.extend(list(range(len(g), self.degree))) - g1 = g - m = len(u) - a = [] - - un = self._stabilizer_cosets_n + factors = self.coset_factor(g, True) + if not factors: + return None rank = 0 - base = [1] - for i in un[m:0:-1]: - base.append(base[-1]*i) - base.reverse() - - a1 = [0]*m - i1 = -1 - for i in self._base: - i1 += 1 - x = g1[i] - for j, h in enumerate(u[i]): - if h[i] == x: - a.append(h) - a1[i] = j - rank += j*base[i1] - p2 = _af_invert(h) - g1 = _af_rmul(p2, g1) - break - else: - return None - if g1 == list(range(self.degree)): - return rank - return None + b = 1 + transversals = self._transversals + base = self._base + basic_orbits = self._basic_orbits + for i in range(len(base)): + k = factors[i] + j = basic_orbits[i].index(k) + rank += b*j + b = b*len(transversals[i]) + return rank def coset_unrank(self, rank, af=False): """unrank using Schreier-Sims representation @@ -1358,20 +975,17 @@ if 0 <= rank < order; otherwise it returns None. """ - u = self.stabilizer_cosets(True) if rank < 0 or rank >= self.order(): return None - un = self._stabilizer_cosets_n base = self._base - m = len(u) - nb = len(base) - assert nb == len(un) + transversals = self._transversals + basic_orbits = self._basic_orbits + m = len(base) v = [0]*m - for i in range(nb-1, -1,-1): - j = base[i] - rank, c = divmod(rank, un[i]) - v[j] = c - a = [u[i][v[i]] for i in range(m)] + for i in range(m): + rank, c = divmod(rank, len(transversals[i])) + v[i] = basic_orbits[i][c] + a = [transversals[i][v[i]]._array_form for i in range(m)] h = _af_rmuln(*a) if af: return h @@ -1484,20 +1098,22 @@ """ r = self._r - gens = [p.array_form for p in self.generators] + gens = [p._array_form for p in self.generators] gens_inv = [_af_invert(p) for p in gens] set_commutators = set() + degree = self._degree + rng = list(range(degree)) for i in range(r): for j in range(r): p1 = gens[i] - p1inv = gens_inv[i] p2 = gens[j] - p2inv = gens_inv[j] - c = [p1[p2[p1inv[k]]] for k in p2inv] + c = list(range(degree)) + for k in rng: + c[p2[p1[k]]] = p1[p2[k]] ct = tuple(c) if not ct in set_commutators: set_commutators.add(ct) - cms = [Permutation(p) for p in set_commutators] + cms = [_af_new(p) for p in set_commutators] G2 = self.normal_closure(cms) return G2 @@ -1532,18 +1148,18 @@ >>> H = PermutationGroup(G[0], G[1]) >>> J = PermutationGroup(list(H.generate())); J PermutationGroup([ + Permutation(0, 1)(2, 3), Permutation(3), Permutation(1, 2, 3), Permutation(1, 3, 2), - Permutation(3)(0, 1, 2), - Permutation(0, 1)(2, 3), + Permutation(0, 3, 1), + Permutation(0, 2, 3), + Permutation(0, 3)(1, 2), Permutation(0, 1, 3), - Permutation(0, 2)(1, 3), Permutation(3)(0, 2, 1), - Permutation(0, 2, 3), Permutation(0, 3, 2), - Permutation(0, 3, 1), - Permutation(0, 3)(1, 2)]) + Permutation(3)(0, 1, 2), + Permutation(0, 2)(1, 3)]) >>> _.is_group() True """ @@ -1587,7 +1203,7 @@ yield idn else: yield _af_new(idn) - gens = [p.array_form for p in self.generators] + gens = [p._array_form for p in self.generators] for i in range(len(gens)): # D elements of the subgroup G_i generated by gens[:i] @@ -1597,7 +1213,7 @@ A = N N = [] for a in A: - for g in gens[:i+1]: + for g in gens[:i + 1]: ag = _af_rmul(a, g) if tuple(ag) not in set_element_list: # produce G_i*g @@ -1616,6 +1232,7 @@ def generate_schreier_sims(self, af=False): """Yield group elements using the Schreier-Sims representation + in coset_rank order If af = True it yields the array form of the permutations @@ -1629,45 +1246,60 @@ >>> b = Permutation([0, 2, 3, 1]) >>> g = PermutationGroup([a, b]) >>> list(g.generate_schreier_sims(af=True)) - [[0, 1, 2, 3], [0, 1, 3, 2], [0, 2, 3, 1], - [0, 2, 1, 3], [0, 3, 2, 1], [0, 3, 1, 2]] - + [[0, 1, 2, 3], [0, 2, 1, 3], [0, 3, 2, 1], + [0, 1, 3, 2], [0, 2, 3, 1], [0, 3, 1, 2]] """ - def get1(posmax): - n = len(posmax) - 1 - for i in range(n, -1, -1): - if posmax[i] != 1: - return i + 1 - return 1 - n = self.degree - u = self.stabilizer_cosets(True) + + n = self._degree + u = self.basic_transversals + basic_orbits = self._basic_orbits + if len(u) == 0: + for x in self.generators: + if af: + yield x._array_form + else: + yield x + raise StopIteration + if len(u) == 1: + for i in basic_orbits[0]: + if af: + yield u[0][i]._array_form + else: + yield u[0][i] + raise StopIteration + + u = list(reversed(u)) + basic_orbits = basic_orbits[::-1] # stg stack of group elements stg = [list(range(n))] - # posmax[i] = len(u[i]) posmax = [len(x) for x in u] - n1 = get1(posmax) + n1 = len(posmax) - 1 pos = [0]*n1 - posmax = posmax[:n1] h = 0 while 1: # backtrack when finished iterating over coset if pos[h] >= posmax[h]: + #count_b += 1 if h == 0: raise StopIteration pos[h] = 0 h -= 1 stg.pop() continue - p = _af_rmul(stg[-1], u[h][pos[h]]) + p = _af_rmul(u[h][basic_orbits[h][pos[h]]]._array_form, stg[-1]) pos[h] += 1 stg.append(p) h += 1 if h == n1: if af: - yield p + for i in basic_orbits[-1]: + p = _af_rmul(u[-1][i]._array_form, stg[-1]) + yield p else: - p1 = _af_new(p) - yield p1 + for i in basic_orbits[-1]: + p = _af_rmul(u[-1][i]._array_form, stg[-1]) + p1 = _af_new(p) + yield p1 stg.pop() h -= 1 @@ -1749,7 +1381,7 @@ g = Permutation(g, size=self.degree) if g in self.generators: return True - return bool(self.coset_factor(g.array_form)) + return bool(self.coset_factor(g.array_form, True)) @property def is_abelian(self): @@ -1776,7 +1408,7 @@ return self._is_abelian self._is_abelian = True - gens = [p.array_form for p in self.generators] + gens = [p._array_form for p in self.generators] for x in gens: for y in gens: if y <= x: @@ -1823,7 +1455,7 @@ _check_cycles_alt_sym """ - if _random_prec == None: + if _random_prec is None: n = self.degree if n < 8: return False @@ -1876,7 +1508,7 @@ """ if self._is_nilpotent is None: lcs = self.lower_central_series() - terminator = lcs[len(lcs)-1] + terminator = lcs[len(lcs) - 1] gens = terminator.generators degree = self.degree identity = _af_new(list(range(degree))) @@ -1912,12 +1544,12 @@ True """ - gens2 = [p.array_form for p in self.generators] - gens1 = [p.array_form for p in gr.generators] + gens2 = [p._array_form for p in self.generators] + gens1 = [p._array_form for p in gr.generators] for g1 in gens1: for g2 in gens2: p = _af_rmuln(g1, g2, _af_invert(g1)) - if not self.coset_factor(p): + if not self.coset_factor(p, True): return False return True @@ -1959,7 +1591,7 @@ minimal_block, random_stab """ - if self._is_primitive != None: + if self._is_primitive is not None: return self._is_primitive n = self.degree if randomized: @@ -2065,7 +1697,7 @@ if G.order() % self.order() != 0: return False if self.degree == G.degree or \ - (self.degree < G.degree and not strict): + (self.degree < G.degree and not strict): gens = self.generators else: return False @@ -2101,10 +1733,10 @@ >>> G3.is_transitive() or G3.is_transitive(strict=False) False """ - if self._is_transitive: # strict or not, if True then True + if self._is_transitive: # strict or not, if True then True return self._is_transitive if strict: - if self._is_transitive is not None: # we only store strict=True + if self._is_transitive is not None: # we only store strict=True return self._is_transitive ans = len(self.orbit(0)) == self.degree @@ -2207,7 +1839,7 @@ minimal_block, _union_find_merge """ - if self._max_div != None: + if self._max_div is not None: return self._max_div n = self.degree if n == 1: @@ -2276,12 +1908,12 @@ # the block size must divide the degree of the group if k > self.max_div: return [0]*n - for i in range(k-1): - parents[points[i+1]] = points[0] - not_rep.append(points[i+1]) + for i in range(k - 1): + parents[points[i + 1]] = points[0] + not_rep.append(points[i + 1]) ranks[points[0]] = k i = 0 - len_not_rep = k-1 + len_not_rep = k - 1 while i < len_not_rep: temp = not_rep[i] i += 1 @@ -2291,8 +1923,8 @@ delta = self._union_find_rep(temp, parents) # union has side effects: performs union by rank on the list # of representatives - temp = self._union_find_merge(gen(temp), gen(delta), ranks,\ - parents, not_rep) + temp = self._union_find_merge(gen(temp), gen(delta), ranks, + parents, not_rep) if temp == -1: return [0]*n len_not_rep += temp @@ -2357,8 +1989,8 @@ Z = PermutationGroup(other.generators[:]) base, strong_gens = Z.schreier_sims_incremental() strong_gens_distr = _distribute_gens_by_base(base, strong_gens) - basic_orbits, basic_transversals =\ - _orbits_transversals_from_bsgs(base, strong_gens_distr) + basic_orbits, basic_transversals = \ + _orbits_transversals_from_bsgs(base, strong_gens_distr) self._random_pr_init(r=10, n=20) @@ -2368,26 +2000,26 @@ for i in range(k): g = self.random_pr() h = Z.random_pr() - conj = rmul(~g, h, g) + conj = h^g res = _strip(conj, base, basic_orbits, basic_transversals) if res[0] != identity or res[1] != len(base) + 1: gens = Z.generators gens.append(conj) Z = PermutationGroup(gens) strong_gens.append(conj) - temp_base, temp_strong_gens =\ - Z.schreier_sims_incremental(base, strong_gens) + temp_base, temp_strong_gens = \ + Z.schreier_sims_incremental(base, strong_gens) base, strong_gens = temp_base, temp_strong_gens - strong_gens_distr =\ - _distribute_gens_by_base(base, strong_gens) - basic_orbits, basic_transversals =\ - _orbits_transversals_from_bsgs(base,\ + strong_gens_distr = \ + _distribute_gens_by_base(base, strong_gens) + basic_orbits, basic_transversals = \ + _orbits_transversals_from_bsgs(base, strong_gens_distr) _loop = False for g in self.generators: for h in Z.generators: - conj = rmul(~g, h, g) - res = _strip(conj, base, basic_orbits,\ + conj = h^g + res = _strip(conj, base, basic_orbits, basic_transversals) if res[0] != identity or res[1] != len(base) + 1: _loop = True @@ -2434,44 +2066,7 @@ orbit_transversal """ - if not hasattr(alpha, '__getitem__'): - alpha = [alpha] - - gens = [x.array_form for x in self.generators] - if len(alpha) == 1 or action == 'union': - orb = alpha - used = [False]*self.degree - for el in alpha: - used[el] = True - for b in orb: - for gen in gens: - temp = gen[b] - if used[temp] == False: - orb.append(temp) - used[temp] = True - return set(orb) - elif action == 'tuples': - alpha = tuple(alpha) - orb = [alpha] - used = set([alpha]) - for b in orb: - for gen in gens: - temp = tuple([gen[x] for x in b]) - if temp not in used: - orb.append(temp) - used.add(temp) - return set(orb) - elif action == 'sets': - alpha = frozenset(alpha) - orb = [alpha] - used = set([alpha]) - for b in orb: - for gen in gens: - temp = frozenset([gen[x] for x in b]) - if temp not in used: - orb.append(temp) - used.add(temp) - return set([tuple(x) for x in orb]) + return _orbit(self.degree, self.generators, alpha, action) def orbit_rep(self, alpha, beta, schreier_vector=None): """Return a group element which sends ``alpha`` to ``beta``. @@ -2497,19 +2092,21 @@ schreier_vector """ - if schreier_vector == None: + if schreier_vector is None: schreier_vector = self.schreier_vector(alpha) - if schreier_vector[beta] == None: + if schreier_vector[beta] is None: return False - n = self.degree - u = _af_new(list(range(n))) k = schreier_vector[beta] - gens = self.generators + gens = [x._array_form for x in self.generators] + a = [] while k != -1: - u = rmul(u, gens[k]) - beta = (~gens[k])(beta) + a.append(gens[k]) + beta = gens[k].index(beta) # beta = (~gens[k])(beta) k = schreier_vector[beta] - return u + if a: + return _af_new(_af_rmuln(*a)) + else: + return _af_new(list(range(self._degree))) def orbit_transversal(self, alpha, pairs=False): r"""Computes a transversal for the orbit of ``alpha`` as a set. @@ -2543,21 +2140,7 @@ orbit """ - n = self.degree - tr = [(alpha, list(range(n)))] - used = [False]*n - used[alpha] = True - gens = [x.array_form for x in self.generators] - for pair in tr: - for gen in gens: - temp = gen[pair[0]] - if used[temp] == False: - tr.append((temp, _af_rmul(gen, pair[1]))) - used[temp] = True - if pairs: - tr = [(x, _af_new(y)) for x, y in tr] - return tr - return [_af_new(y) for _, y in tr] + return _orbit_transversal(self._degree, self.generators, alpha, pairs) def orbits(self, rep=False): """Return the orbits of self, ordered according to lowest element @@ -2574,18 +2157,7 @@ >>> G.orbits() [set([0, 2, 3, 4, 6]), set([1, 5])] """ - seen = set() # elements that have already appeared in orbits - orbs = [] - sorted_I = list(range(self._degree)) - I = set(sorted_I) - while I: - i = sorted_I[0] - orb = self.orbit(i) - orbs.append(orb) - # remove all indices that are in this orbit - I -= orb - sorted_I = [i for i in sorted_I if i not in orb] - return orbs + return _orbits(self._degree, self._generators) def order(self): """Return the order of the group: the number of permutations that @@ -2626,20 +2198,22 @@ if self._order != None: return self._order if self._is_sym: - n = self.degree + n = self._degree self._order = factorial(n) return self._order if self._is_alt: - n = self.degree + n = self._degree self._order = factorial(n)/2 return self._order - self.schreier_sims() + + basic_transversals = self.basic_transversals m = 1 - for x in self._stabilizer_cosets_n: - m *= x + for x in basic_transversals: + m *= len(x) + self._order = m return m - def pointwise_stabilizer(self, points, incremental=False): + def pointwise_stabilizer(self, points, incremental=True): r"""Return the pointwise stabilizer for a set of points. For a permutation group ``G`` and a set of points @@ -2679,12 +2253,15 @@ for gen in strong_gens: if [gen(point) for point in points] == points: stab_gens.append(gen) + if not stab_gens: + stab_gens = _af_new(list(range(degree))) return PermutationGroup(stab_gens) else: - H = self + gens = self._generators + degree = self.degree for x in points: - H = H.stabilizer(x) - return H + gens = _stabilizer(degree, gens, x) + return PermutationGroup(gens) def make_perm(self, n, seed=None): """ @@ -2765,7 +2342,7 @@ r = len(random_gens) - 1 # handle randomized input for testing purposes - if _random_prec == None: + if _random_prec is None: s = randrange(r) t = randrange(r - 1) if t == s: @@ -2781,12 +2358,12 @@ e = _random_prec['e'] if x == 1: - random_gens[s] = rmul(random_gens[s], random_gens[t]**e) - random_gens[r] = rmul(random_gens[r], random_gens[s]) + random_gens[s] = _af_rmul(random_gens[s], _af_pow(random_gens[t], e)) + random_gens[r] = _af_rmul(random_gens[r], random_gens[s]) else: - random_gens[s] = rmul(random_gens[t]**e, random_gens[s]) - random_gens[r] = rmul(random_gens[s], random_gens[r]) - return random_gens[r] + random_gens[s] = _af_rmul(_af_pow(random_gens[t], e), random_gens[s]) + random_gens[r] = _af_rmul(random_gens[s], random_gens[r]) + return _af_new(random_gens[r]) def random_stab(self, alpha, schreier_vector=None, _random_prec=None): """Random element from the stabilizer of ``alpha``. @@ -2800,9 +2377,9 @@ random_pr, orbit_rep """ - if schreier_vector == None: + if schreier_vector is None: schreier_vector = self.schreier_vector(alpha) - if _random_prec == None: + if _random_prec is None: rand = self.random_pr() else: rand = _random_prec['rand'] @@ -2820,100 +2397,35 @@ An element of the group can be written as the product h_1*..*h_s. - We use Jerrum's filter in our implementation of the - Schreier-Sims algorithm. It runs in polynomial time. - - This implementation is a translation of the C++ implementation in - http://www.m8j.net + We use the incremental Schreier-Sims algorithm. Examples ======== - >>> from sympy.combinatorics.permutations import Permutation >>> from sympy.combinatorics.perm_groups import PermutationGroup >>> a = Permutation([0, 2, 1]) >>> b = Permutation([1, 0, 2]) >>> G = PermutationGroup([a, b]) >>> G.schreier_sims() - >>> G.stabilizer_gens(af=True) - [[0, 2, 1]] - >>> G.stabilizer_cosets(af=True) - [[[0, 1, 2], [1, 0, 2], [2, 0, 1]], [[0, 1, 2], [0, 2, 1]]] - + >>> G.basic_transversals + [{0: Permutation(2)(0, 1), 1: Permutation(2), 2: Permutation(1, 2)}, + {0: Permutation(2), 2: Permutation(0, 2)}] """ - if self._stabilizer_cosets: + if self._transversals: return - JGr = _JGraph(self) - alpha = 0 - n = JGr.n - self._order = 1 - stabilizer_cosets = [] - num_generators = [] - generators = [] - gen = list(range(n)) - base = [] - scn = [] - JGr.gens += [None]*(n - len(JGr.gens)) - while 1: - self._stabilizer_cosets_n = 0 - self._stabilizer_cosets = [None]*n - JGr.schreier_tree(alpha, gen) - cri = [] - for p in self._stabilizer_cosets: - if not p: - cri.append(p) - else: - cri.append(_af_invert(p)) - JGr.jerrum_filter(alpha, cri) - if self._stabilizer_cosets_n > 1: - base.append(alpha) - scn.append(self._stabilizer_cosets_n) - self._order *= self._stabilizer_cosets_n - stabilizer_cosets.append([p for p in self._stabilizer_cosets if p]) - d = {} - for p in self._stabilizer_cosets: - if p: - d[p[alpha]] = p - num_generators.append(JGr.r) - if JGr.r: - generators.extend(JGr.gens[:JGr.r]) - if JGr.r <= 0: - break - alpha += 1 - self._stabilizer_cosets = stabilizer_cosets - a = [] - for p in generators: - if p not in a: - a.append(p) - self._stabilizer_gens = a - - i = len(JGr.gens) - 1 - while not JGr.gens[i]: - i -= 1 - JGr.gens = JGr.gens[:i+1] + base, strong_gens = self.schreier_sims_incremental() self._base = base - self._stabilizer_cosets_n = scn - strong_gens = self.generators[:] - for gen in self._stabilizer_gens: - gen = Permutation(gen) - if gen not in strong_gens: - strong_gens.append(gen) self._strong_gens = strong_gens - base_len = len(self._base) - transversals = [None]*base_len - basic_orbits = [None]*base_len - for index in range(base_len): - transversals[index] = {} - base_point = self._base[index] - trans = self._stabilizer_cosets[base_point][:] - for el in trans: - el = Permutation(el) - orbit_member = el(base_point) - transversals[index][orbit_member] = el - basic_orbits[index] =\ - list(transversals[index].keys()) + if not base: + self._transversals = [] + self._basic_orbits = [] + return + + strong_gens_distr = _distribute_gens_by_base(base, strong_gens) + basic_orbits, transversals = _orbits_transversals_from_bsgs(base,\ + strong_gens_distr) self._transversals = transversals - self._basic_orbits = basic_orbits + self._basic_orbits = [sorted(x) for x in basic_orbits] def schreier_sims_incremental(self, base=None, gens=None): """Extend a sequence of points and generating set to a base and strong @@ -2975,6 +2487,7 @@ if gens is None: gens = self.generators[:] degree = self.degree + id_af = list(range(degree)) # handle the trivial group if len(gens) == 1 and gens[0].is_Identity: return base, gens @@ -2984,24 +2497,22 @@ _gens = [x for x in _gens if not x.is_Identity] # make sure no generator fixes all base points for gen in _gens: - if all(x == gen(x) for x in _base): - for new in range(gen.size): - if gen(new) != new: + if all(x == gen._array_form[x] for x in _base): + for new in id_af: + if gen._array_form[new] != new: break else: - assert None # can this ever happen? + assert None # can this ever happen? _base.append(new) # distribute generators according to basic stabilizers strong_gens_distr = _distribute_gens_by_base(_base, _gens) # initialize the basic stabilizers, basic orbits and basic transversals - stabs = {} orbs = {} transversals = {} base_len = len(_base) for i in range(base_len): - stabs[i] = PermutationGroup(strong_gens_distr[i]) - transversals[i] = dict(stabs[i].orbit_transversal(_base[i],\ - pairs=True)) + transversals[i] = dict(_orbit_transversal(degree, strong_gens_distr[i], + _base[i], pairs=True, af=True)) orbs[i] = list(transversals[i].keys()) # main loop: amend the stabilizer chain until we have generators # for all stabilizers @@ -3011,47 +2522,52 @@ # a nested loop continue_i = False # test the generators for being a strong generating set - for beta in orbs[i]: - u_beta = transversals[i][beta] + db = {} + for beta, u_beta in list(transversals[i].items()): for gen in strong_gens_distr[i]: - u_beta_gen = transversals[i][gen(beta)] - if rmul(gen, u_beta) != u_beta_gen: + gb = gen._array_form[beta] + u1 = transversals[i][gb] + g1 = _af_rmul(gen._array_form, u_beta) + if g1 != u1: # test if the schreier generator is in the i+1-th # would-be basic stabilizer y = True - schreier_gen = rmul(~u_beta_gen, gen, u_beta) - h, j = _strip(schreier_gen, _base, orbs, transversals) + try: + u1_inv = db[gb] + except KeyError: + u1_inv = db[gb] = _af_invert(u1) + schreier_gen = _af_rmul(u1_inv, g1) + h, j = _strip_af(schreier_gen, _base, orbs, transversals, i) if j <= base_len: # new strong generator h at level j y = False - elif h != _af_new(list(range(degree))): + elif h: # h fixes all base points y = False moved = 0 - while h(moved) == moved: + while h[moved] == moved: moved += 1 _base.append(moved) base_len += 1 strong_gens_distr.append([]) - if y == False: + if y is False: # if a new strong generator is found, update the # data structures and start over + h = _af_new(h) for l in range(i + 1, j): strong_gens_distr[l].append(h) - stabs[l] =\ - PermutationGroup(strong_gens_distr[l]) transversals[l] =\ - dict(stabs[l].orbit_transversal(_base[l],\ - pairs=True)) + dict(_orbit_transversal(degree, strong_gens_distr[l], + _base[l], pairs=True, af=True)) orbs[l] = list(transversals[l].keys()) i = j - 1 # continue main loop using the flag continue_i = True - if continue_i == True: + if continue_i is True: break - if continue_i == True: + if continue_i is True: break - if continue_i == True: + if continue_i is True: continue i -= 1 # build the strong generating set @@ -3062,14 +2578,15 @@ strong_gens.append(gen) return _base, strong_gens - def schreier_sims_random(self, base=None, gens=None, consec_succ=10,\ + def schreier_sims_random(self, base=None, gens=None, consec_succ=10, _random_prec=None): r"""Randomized Schreier-Sims algorithm. The randomized Schreier-Sims algorithm takes the sequence ``base`` and the generating set ``gens``, and extends ``base`` to a base, and ``gens`` to a strong generating set relative to that base with - probability of a wrong answer at most ``1/\text{consec\_succ}``. + probability of a wrong answer at most ``2^{-consec\_succ}``, + provided the random generators are sufficiently random. Parameters ========== @@ -3138,20 +2655,18 @@ for gen in gens: if all(gen(x) == x for x in base): new = 0 - while gen(new) == new: + while gen._array_form[new] == new: new += 1 base.append(new) base_len += 1 # distribute generators according to basic stabilizers strong_gens_distr = _distribute_gens_by_base(base, gens) # initialize the basic stabilizers, basic transversals and basic orbits - stabs = {} transversals = {} orbs = {} for i in range(base_len): - stabs[i] = PermutationGroup(strong_gens_distr[i]) - transversals[i] = dict(stabs[i].orbit_transversal(base[i],\ - pairs=True)) + transversals[i] = dict(_orbit_transversal(n, strong_gens_distr[i], + base[i], pairs=True)) orbs[i] = list(transversals[i].keys()) # initialize the number of consecutive elements sifted c = 0 @@ -3180,9 +2695,8 @@ if y is False: for l in range(1, j): strong_gens_distr[l].append(h) - stabs[l] = PermutationGroup(strong_gens_distr[l]) - transversals[l] = dict(stabs[l].orbit_transversal(base[l],\ - pairs=True)) + transversals[l] = dict(_orbit_transversal(n, + strong_gens_distr[l], base[l], pairs=True)) orbs[l] = list(transversals[l].keys()) c = 0 else: @@ -3234,7 +2748,7 @@ r = len(gens) for b in orb: for i in range(r): - temp = gens[i](b) + temp = gens[i]._array_form[b] if used[temp] is False: orb.append(temp) used[temp] = True @@ -3267,111 +2781,7 @@ orbit """ - n = self.degree - orb = [alpha] - table = {alpha: list(range(n))} - used = [False]*n - used[alpha] = True - gens = [x.array_form for x in self.generators] - stab_gens = [] - for b in orb: - for gen in gens: - temp = gen[b] - if used[temp] is False: - gen_temp = _af_rmul(gen, table[b]) - orb.append(temp) - table[temp] = gen_temp - used[temp] = True - else: - schreier_gen = _af_rmuln(_af_invert(table[temp]), gen, table[b]) - if schreier_gen not in stab_gens: - stab_gens.append(schreier_gen) - return PermutationGroup([_af_new(x) for x in stab_gens]) - - def stabilizer_cosets(self, af=False): - """Return a list of cosets of the stabilizer chain of the group - as computed by the Schreir-Sims algorithm. - - Each coset is a list of permutations in array form. - - Examples - ======== - - >>> from sympy.combinatorics import Permutation - >>> Permutation.print_cyclic = True - - >>> from sympy.combinatorics.polyhedron import tetrahedron - >>> G = tetrahedron.pgroup - - The tetrahedron's pgroup contains a list of permutations corresponding - to different ways of manipulating the tetrahedron. We can look at the - underlying cosets with the stabilizer_cosets method: - - >>> for i, ui in enumerate(G.stabilizer_cosets()): - ... print('coset %i:' % i) - ... for p in ui: - ... print(' ', p) - ... - coset 0: - Permutation(3) - Permutation(3)(0, 1, 2) - Permutation(0, 2)(1, 3) - Permutation(0, 3, 2) - coset 1: - Permutation(3) - Permutation(1, 2, 3) - Permutation(1, 3, 2) - - Any permutation of the tetrahedron can be written as a product of - two permutations, one from each of the cosets. For example, the - first permutation in the tetrahedron pgroup corresponds to the - CW turning of the tetrahedron through the top vertex. This factors - as: - - >>> G.coset_factor(G[0]) - [Permutation(3), Permutation(1, 2, 3)] - - And those two permutations are drawn from the cosets shown above. - - See Also - ======== - coset_factor, basic_transversals - - """ - if not self._stabilizer_cosets: - self.schreier_sims() - if af: - return self._stabilizer_cosets - return [[Permutation(p) for p in c] for c in self._stabilizer_cosets] - - def stabilizer_gens(self, af=False): - """Return the generators of the chain of stabilizers of the - Schreier-Sims representation. - - Examples - ======== - - >>> from sympy.combinatorics.perm_groups import PermutationGroup - >>> from sympy.combinatorics.polyhedron import tetrahedron - >>> from sympy.combinatorics import Permutation - >>> Permutation.print_cyclic = True - >>> G = tetrahedron.pgroup - >>> G.stabilizer_gens() - [Permutation(1, 3, 2), Permutation(1, 2, 3)] - - >>> a = Permutation([0, 2, 1]) - >>> b = Permutation([1, 0, 2]) - >>> G = PermutationGroup([a, b]) - >>> G.stabilizer_gens() - [Permutation(1, 2)] - - """ - - if not self._stabilizer_cosets: - self.schreier_sims() - if af: - return self._stabilizer_gens - return [Permutation(p) for p in self._stabilizer_gens] + return PermGroup(_stabilizer(self._degree, self._generators, alpha)) @property def strong_gens(self): @@ -3406,7 +2816,7 @@ self.schreier_sims() return self._strong_gens - def subgroup_search(self, prop, base=None, strong_gens=None, tests=None,\ + def subgroup_search(self, prop, base=None, strong_gens=None, tests=None, init_subgroup=None): """Find the subgroup of all elements satisfying the property ``prop``. @@ -3429,7 +2839,9 @@ These are used to rule out group elements by partial base images, so that ``tests[l](g)`` returns False if the element ``g`` is known not to satisfy prop base on where g sends the first ``l + 1`` base - points. ``init_subgroup`` - if a subgroup of the saught group is + points. + init_subgroup + if a subgroup of the sought group is known in advance, it can be passed to the function as this parameter. @@ -3480,6 +2892,20 @@ """ # initialize BSGS and basic group properties + def get_reps(orbits): + # get the minimal element in the base ordering + return [min(orbit, key = lambda x: base_ordering[x]) \ + for orbit in orbits] + + def update_nu(l): + temp_index = len(basic_orbits[l]) + 1 -\ + len(res_basic_orbits_init_base[l]) + # this corresponds to the element larger than all points + if temp_index >= len(sorted_orbits[l]): + nu[l] = base_ordering[degree] + else: + nu[l] = sorted_orbits[l][temp_index] + if base is None: base, strong_gens = self.schreier_sims_incremental() base_len = len(base) @@ -3492,7 +2918,7 @@ base_ordering.append(-1) # compute BSGS-related structures strong_gens_distr = _distribute_gens_by_base(base, strong_gens) - basic_orbits, transversals = _orbits_transversals_from_bsgs(base,\ + basic_orbits, transversals = _orbits_transversals_from_bsgs(base, strong_gens_distr) # handle subgroup initialization and tests if init_subgroup is None: @@ -3509,23 +2935,19 @@ # line 2: set the base for K to the base for G res_base = base[:] # line 3: compute BSGS and related structures for K - res_base, res_strong_gens = res.schreier_sims_incremental(base=res_base) - res_strong_gens_distr = _distribute_gens_by_base(res_base,\ + res_base, res_strong_gens = res.schreier_sims_incremental( + base=res_base) + res_strong_gens_distr = _distribute_gens_by_base(res_base, res_strong_gens) - res_basic_orbits_init_base =\ - [PermutationGroup(res_strong_gens_distr[i]).orbit(res_base[i])\ + res_generators = res.generators + res_basic_orbits_init_base = \ + [_orbit(degree, res_strong_gens_distr[i], res_base[i])\ for i in range(base_len)] # initialize orbit representatives orbit_reps = [None]*base_len # line 4: orbit representatives for f-th basic stabilizer of K - stab_f = PermutationGroup(res_strong_gens_distr[f]) - orbits = stab_f.orbits() - reps = [] - for orbit in orbits: - # get the minimal element in the base ordering - rep = min(orbit, key = lambda point: base_ordering[point]) - reps.append(rep) - orbit_reps[f] = reps + orbits = _orbits(degree, res_strong_gens_distr[f]) + orbit_reps[f] = get_reps(orbits) # line 5: remove the base point from the representatives to avoid # getting the identity element as a generator for K orbit_reps[f].remove(base[f]) @@ -3535,49 +2957,39 @@ sorted_orbits = [None]*base_len for i in range(base_len): sorted_orbits[i] = basic_orbits[i][:] - sorted_orbits[i].sort(key = lambda point: base_ordering[point]) + sorted_orbits[i].sort(key=lambda point: base_ordering[point]) # line 7: initializations mu = [None]*base_len nu = [None]*base_len # this corresponds to the element smaller than all points mu[l] = degree + 1 - temp_index = len(basic_orbits[l])+1-len(res_basic_orbits_init_base[l]) - if temp_index >= len(basic_orbits[l]): - # this corresponds to the element larger than all points - nu[l] = base_ordering[degree] - else: - nu[l] = sorted_orbits[l][temp_index] + update_nu(l) # initialize computed words computed_words = [identity]*base_len # line 8: main loop while True: # apply all the tests - while l < base_len - 1 and\ - computed_words[l](base[l]) in orbit_reps[l] and\ - base_ordering[computed_words[l](base[l])] >\ - base_ordering[mu[l]] and\ - base_ordering[computed_words[l](base[l])] <\ - base_ordering[nu[l]] and\ - tests[l](computed_words): + while l < base_len - 1 and \ + computed_words[l](base[l]) in orbit_reps[l] and \ + base_ordering[mu[l]] < \ + base_ordering[computed_words[l](base[l])] < \ + base_ordering[nu[l]] and \ + tests[l](computed_words): # line 11: change the (partial) base of K new_point = computed_words[l](base[l]) res_base[l] = new_point - temp_group = PermutationGroup(res_strong_gens_distr[l]) - new_stab = temp_group.stabilizer(new_point) - res_strong_gens_distr[l + 1] = new_stab.generators + new_stab_gens = _stabilizer(degree, res_strong_gens_distr[l], + new_point) + res_strong_gens_distr[l + 1] = new_stab_gens # line 12: calculate minimal orbit representatives for the # l+1-th basic stabilizer - orbits = new_stab.orbits() - reps = [] - for orbit in orbits: - rep = min(orbit, key = lambda point: base_ordering[point]) - reps.append(rep) - orbit_reps[l + 1] = reps + orbits = _orbits(degree, new_stab_gens) + orbit_reps[l + 1] = get_reps(orbits) # line 13: amend sorted orbits l += 1 - temp_orbit = [computed_words[l-1](point) for point\ + temp_orbit = [computed_words[l - 1](point) for point in basic_orbits[l]] - temp_orbit.sort(key = lambda point: base_ordering[point]) + temp_orbit.sort(key=lambda point: base_ordering[point]) sorted_orbits[l] = temp_orbit # lines 14 and 15: update variables used minimality tests new_mu = degree + 1 @@ -3587,50 +2999,36 @@ if base_ordering[candidate] > base_ordering[new_mu]: new_mu = candidate mu[l] = new_mu - temp_index = len(basic_orbits[l]) + 1 -\ - len(res_basic_orbits_init_base[l]) - if temp_index >= len(sorted_orbits[l]): - nu[l] = base_ordering[degree] - else: - nu[l] = sorted_orbits[l][temp_index] + update_nu(l) # line 16: determine the new transversal element c[l] = 0 temp_point = sorted_orbits[l][c[l]] - temp_element = ~(computed_words[l - 1]) - gamma = temp_element(temp_point) + gamma = computed_words[l - 1]._array_form.index(temp_point) u[l] = transversals[l][gamma] # update computed words - computed_words[l] = rmul(computed_words[l-1], u[l]) + computed_words[l] = rmul(computed_words[l - 1], u[l]) # lines 17 & 18: apply the tests to the group element found g = computed_words[l] temp_point = g(base[l]) - if l == base_len - 1 and\ - base_ordering[temp_point] > base_ordering[mu[l]] and\ - base_ordering[temp_point] < base_ordering[nu[l]] and\ - temp_point in orbit_reps[l] and\ - tests[l](computed_words) and\ - prop(g): + if l == base_len - 1 and \ + base_ordering[mu[l]] < \ + base_ordering[temp_point] < base_ordering[nu[l]] and \ + temp_point in orbit_reps[l] and \ + tests[l](computed_words) and \ + prop(g): # line 19: reset the base of K - gens = res.generators[:] - gens.append(g) - res = PermutationGroup(gens) + res_generators.append(g) res_base = base[:] # line 20: recalculate basic orbits (and transversals) res_strong_gens.append(g) - res_strong_gens_distr = _distribute_gens_by_base(res_base,\ + res_strong_gens_distr = _distribute_gens_by_base(res_base, res_strong_gens) - res_basic_orbits_init_base =\ - [PermutationGroup(res_strong_gens_distr[i]).orbit(res_base[i])\ + res_basic_orbits_init_base = \ + [_orbit(degree, res_strong_gens_distr[i], res_base[i]) \ for i in range(base_len)] # line 21: recalculate orbit representatives - stab_f = PermutationGroup(res_strong_gens_distr[f]) - temp_orbits = stab_f.orbits() - reps = [] - for orbit in orbits: - rep = min(orbit, key = lambda point: base_ordering[point]) - reps.append(rep) - orbit_reps[f] = reps # line 22: reset the search depth + orbit_reps[f] = get_reps(orbits) l = f # line 23: go up the tree until in the first branch not fully # searched @@ -3638,24 +3036,19 @@ l = l - 1 # line 24: if the entire tree is traversed, return K if l == -1: - return res + return PermutationGroup(res_generators) # lines 25-27: update orbit representatives if l < f: # line 26 f = l c[l] = 0 # line 27 - stab_f = PermutationGroup(res_strong_gens_distr[f]) - temp_orbits = stab_f.orbits() - reps = [] - for orbit in orbits: - rep = min(orbit, key = lambda point: base_ordering[point]) - reps.append(rep) - orbit_reps[f] = reps + temp_orbits = _orbits(degree, res_strong_gens_distr[f]) + orbit_reps[f] = get_reps(temp_orbits) # line 28: update variables used for minimality testing mu[l] = degree + 1 - temp_index = len(basic_orbits[l]) + 1 -\ - len(res_basic_orbits_init_base[l]) + temp_index = len(basic_orbits[l]) + 1 - \ + len(res_basic_orbits_init_base[l]) if temp_index >= len(sorted_orbits[l]): nu[l] = base_ordering[degree] else: @@ -3664,10 +3057,10 @@ # accorndingly c[l] += 1 if l == 0: - element = identity + gamma = sorted_orbits[l][c[l]] else: - element = ~(computed_words[l - 1]) - gamma = element(sorted_orbits[l][c[l]]) + gamma = computed_words[l - 1]._array_form.index(sorted_orbits[l][c[l]]) + u[l] = transversals[l][gamma] if l == 0: computed_words[l] = u[l] @@ -3767,35 +3160,35 @@ >>> TableForm(m, headings=[list(range(n)), list(range(n))], wipe_zeros=False) | 0 1 2 3 4 5 6 7 8 9 10 11 ---------------------------------------- - 0 | 0 1 2 3 4 5 6 7 8 9 10 11 - 1 | 1 2 0 4 5 3 7 8 6 10 11 9 - 2 | 2 0 1 5 3 4 8 6 7 11 9 10 - 3 | 3 6 9 7 2 11 10 0 5 4 1 8 - 4 | 4 7 10 8 0 9 11 1 3 5 2 6 - 5 | 5 8 11 6 1 10 9 2 4 3 0 7 - 6 | 6 9 3 2 11 7 0 5 10 1 8 4 - 7 | 7 10 4 0 9 8 1 3 11 2 6 5 - 8 | 8 11 5 1 10 6 2 4 9 0 7 3 - 9 | 9 3 6 11 7 2 5 10 0 8 4 1 - 10 | 10 4 7 9 8 0 3 11 1 6 5 2 - 11 | 11 5 8 10 6 1 4 9 2 7 3 0 - + 0 | 11 0 8 10 6 2 7 4 5 3 9 1 + 1 | 0 1 2 3 4 5 6 7 8 9 10 11 + 2 | 6 2 7 4 5 3 9 1 11 0 8 10 + 3 | 5 3 9 1 11 0 8 10 6 2 7 4 + 4 | 3 4 0 2 10 6 11 8 9 7 1 5 + 5 | 4 5 6 7 8 9 10 11 0 1 2 3 + 6 | 10 6 11 8 9 7 1 5 3 4 0 2 + 7 | 9 7 1 5 3 4 0 2 10 6 11 8 + 8 | 7 8 4 6 2 10 3 0 1 11 5 9 + 9 | 8 9 10 11 0 1 2 3 4 5 6 7 + 10 | 2 10 3 0 1 11 5 9 7 8 4 6 + 11 | 1 11 5 9 7 8 4 6 2 10 3 0 + >>> The entries in the table give the element in the group corresponding to the product of a given column element and row element: - >>> g[3]*g[1] == g[6] + >>> g[3]*g[2] == g[9] True The inverse of every element is also in the group: >>> TableForm([[g.index(~gi) for gi in g]], headings=[[], list(range(n))], ... wipe_zeros=False) - 0 1 2 3 4 5 6 7 8 9 10 11 - -------------------------- - 0 2 1 7 4 10 6 3 9 8 5 11 + 0 1 2 3 4 5 6 7 8 9 10 11 + --------------------------- + 11 1 7 3 10 9 6 2 8 5 4 0 - So we see that g[6] and g[4] are equivalent to their inverse while - g[1] == ~g[2]. + So we see that g[1] and g[3] are equivalent to their inverse while + g[7] == ~g[2]. """ # identity present I = Permutation(size=self.degree) @@ -3818,4 +3211,206 @@ return False return True +def _orbit(degree, generators, alpha, action='tuples'): + r"""Compute the orbit of alpha ``\{g(\alpha) | g \in G\}`` as a set. + + The time complexity of the algorithm used here is ``O(|Orb|*r)`` where + ``|Orb|`` is the size of the orbit and ``r`` is the number of generators of + the group. For a more detailed analysis, see [1], p.78, [2], pp. 19-21. + Here alpha can be a single point, or a list of points. + + If alpha is a single point, the ordinary orbit is computed. + if alpha is a list of points, there are three available options: + + 'union' - computes the union of the orbits of the points in the list + 'tuples' - computes the orbit of the list interpreted as an ordered + tuple under the group action ( i.e., g((1,2,3)) = (g(1), g(2), g(3)) ) + 'sets' - computes the orbit of the list interpreted as a sets + + Examples + ======== + + >>> from sympy.combinatorics import Permutation + >>> from sympy.combinatorics.perm_groups import PermutationGroup, _orbit + >>> a = Permutation([1,2,0,4,5,6,3]) + >>> G = PermutationGroup([a]) + >>> _orbit(G.degree, G.generators, 0) + set([0, 1, 2]) + >>> _orbit(G.degree, G.generators, [0, 4], 'union') + set([0, 1, 2, 3, 4, 5, 6]) + + See Also + ======== + + orbit, orbit_transversal + + """ + if not hasattr(alpha, '__getitem__'): + alpha = [alpha] + + gens = [x._array_form for x in generators] + if len(alpha) == 1 or action == 'union': + orb = alpha + used = [False]*degree + for el in alpha: + used[el] = True + for b in orb: + for gen in gens: + temp = gen[b] + if used[temp] == False: + orb.append(temp) + used[temp] = True + return set(orb) + elif action == 'tuples': + alpha = tuple(alpha) + orb = [alpha] + used = set([alpha]) + for b in orb: + for gen in gens: + temp = tuple([gen[x] for x in b]) + if temp not in used: + orb.append(temp) + used.add(temp) + return set(orb) + elif action == 'sets': + alpha = frozenset(alpha) + orb = [alpha] + used = set([alpha]) + for b in orb: + for gen in gens: + temp = frozenset([gen[x] for x in b]) + if temp not in used: + orb.append(temp) + used.add(temp) + return set([tuple(x) for x in orb]) + +def _orbits(degree, generators): + """Compute the orbits of G. + + If rep=False it returns a list of sets else it returns a list of + representatives of the orbits + + Examples + ======== + >>> from sympy.combinatorics.permutations import Permutation + >>> from sympy.combinatorics.perm_groups import PermutationGroup, _orbits + >>> a = Permutation([0, 2, 1]) + >>> b = Permutation([1, 0, 2]) + >>> _orbits(a.size, [a, b]) + [set([0, 1, 2])] + """ + + seen = set() # elements that have already appeared in orbits + orbs = [] + sorted_I = list(range(degree)) + I = set(sorted_I) + while I: + i = sorted_I[0] + orb = _orbit(degree, generators, i) + orbs.append(orb) + # remove all indices that are in this orbit + I -= orb + sorted_I = [i for i in sorted_I if i not in orb] + return orbs + +def _orbit_transversal(degree, generators, alpha, pairs, af=False): + r"""Computes a transversal for the orbit of ``alpha`` as a set. + + generators generators of the group ``G`` + + For a permutation group ``G``, a transversal for the orbit + ``Orb = \{g(\alpha) | g \in G\}`` is a set + ``\{g_\beta | g_\beta(\alpha) = \beta\}`` for ``\beta \in Orb``. + Note that there may be more than one possible transversal. + If ``pairs`` is set to ``True``, it returns the list of pairs + ``(\beta, g_\beta)``. For a proof of correctness, see [1], p.79 + + if af is True, the transversal elements are given in array form + + Examples + ======== + + >>> from sympy.combinatorics import Permutation + >>> Permutation.print_cyclic = True + >>> from sympy.combinatorics.named_groups import DihedralGroup + >>> from sympy.combinatorics.perm_groups import _orbit_transversal + >>> G = DihedralGroup(6) + >>> _orbit_transversal(G.degree, G.generators, 0, False) + [Permutation(5), + Permutation(0, 1, 2, 3, 4, 5), + Permutation(0, 5)(1, 4)(2, 3), + Permutation(0, 2, 4)(1, 3, 5), + Permutation(5)(0, 4)(1, 3), + Permutation(0, 3)(1, 4)(2, 5)] + """ + + tr = [(alpha, list(range(degree)))] + used = [False]*degree + used[alpha] = True + gens = [x._array_form for x in generators] + for x, px in tr: + for gen in gens: + temp = gen[x] + if used[temp] == False: + tr.append((temp, _af_rmul(gen, px))) + used[temp] = True + if pairs: + if not af: + tr = [(x, _af_new(y)) for x, y in tr] + return tr + + if af: + return [y for _, y in tr] + + return [_af_new(y) for _, y in tr] + +def _stabilizer(degree, generators, alpha): + r"""Return the stabilizer subgroup of ``alpha``. + + The stabilizer of ``\alpha`` is the group ``G_\alpha = + \{g \in G | g(\alpha) = \alpha\}``. + For a proof of correctness, see [1], p.79. + + degree degree of G + generators generators of G + + Examples + ======== + + >>> from sympy.combinatorics import Permutation + >>> Permutation.print_cyclic = True + >>> from sympy.combinatorics.perm_groups import _stabilizer + >>> from sympy.combinatorics.named_groups import DihedralGroup + >>> G = DihedralGroup(6) + >>> _stabilizer(G.degree, G.generators, 5) + [Permutation(5)(0, 4)(1, 3), Permutation(5)] + + See Also + ======== + + orbit + + """ + orb = [alpha] + table = {alpha: list(range(degree))} + table_inv = {alpha: list(range(degree))} + used = [False]*degree + used[alpha] = True + gens = [x._array_form for x in generators] + stab_gens = [] + for b in orb: + for gen in gens: + temp = gen[b] + if used[temp] is False: + gen_temp = _af_rmul(gen, table[b]) + orb.append(temp) + table[temp] = gen_temp + table_inv[temp] = _af_invert(gen_temp) + used[temp] = True + else: + schreier_gen = _af_rmuln(table_inv[temp], gen, table[b]) + if schreier_gen not in stab_gens: + stab_gens.append(schreier_gen) + return [_af_new(x) for x in stab_gens] + PermGroup = PermutationGroup diff -Nru python3-sympy-0.7.2/sympy/combinatorics/permutations.py python3-sympy-0.7.3/sympy/combinatorics/permutations.py --- python3-sympy-0.7.2/sympy/combinatorics/permutations.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/combinatorics/permutations.py 2013-07-13 17:53:31.000000000 +0000 @@ -10,6 +10,7 @@ from sympy.mpmath.libmp.libintmath import ifac from functools import reduce + def _af_rmul(a, b): """ Return the product b*a; input and output are array forms. The ith value @@ -41,6 +42,7 @@ """ return [a[i] for i in b] + def _af_rmuln(*abc): """ Given [a, b, c, ...] return the product of ...*c*b*a using array forms. @@ -100,6 +102,7 @@ p1 = _af_rmuln(*a[m//2:]) return [p0[i] for i in p1] + def _af_parity(pi): """ Computes the parity of a permutation in array form. @@ -135,6 +138,7 @@ a[i] = 1 return (n - c) % 2 + def _af_invert(a): """ Finds the inverse, ~A, of a permutation, A, given in array form. @@ -159,6 +163,50 @@ inv_form[ai] = i return inv_form +def _af_pow(a, n): + """ + Routine for finding powers of a permutation. + + Examples + ======== + + >>> from sympy.combinatorics.permutations import Permutation, _af_pow + >>> Permutation.print_cyclic = False + >>> p = Permutation([2,0,3,1]) + >>> p.order() + 4 + >>> _af_pow(p._array_form, 4) + [0, 1, 2, 3] + """ + if n == 0: + return list(range(len(a))) + if n < 0: + return _af_pow(_af_invert(a), -n) + if n == 1: + return a[:] + elif n == 2: + b = [a[i] for i in a] + elif n == 3: + b = [a[a[i]] for i in a] + elif n == 4: + b = [a[a[a[i]]] for i in a] + else: + # use binary multiplication + b = list(range(len(a))) + while 1: + if n & 1: + b = [b[i] for i in a] + n -= 1 + if not n: + break + if n % 4 == 0: + a = [a[a[a[i]]] for i in a] + n = n // 4 + elif n % 2 == 0: + a = [a[i] for i in a] + n = n // 2 + return b + def _af_commutes_with(a, b): """ Checks if the two permutations with array forms @@ -178,6 +226,7 @@ """ return not any(a[b[i]] != b[a[i]] for i in range(len(a) - 1)) + class Cycle(dict): """ Wrapper around dict which provides the functionality of a disjoint cycle. @@ -773,37 +822,37 @@ #f) (Cycle) = conversion to permutation #g) (Permutation) = adjust size or return copy ok = True - if not args: # a - return Perm._af_new(list(range(size or 0))) - elif len(args) > 1: # c - return Perm._af_new(Cycle(*args).list(size)) + if not args: # a + return _af_new(list(range(size or 0))) + elif len(args) > 1: # c + return _af_new(Cycle(*args).list(size)) if len(args) == 1: a = args[0] - if isinstance(a, Perm): # g + if isinstance(a, Perm): # g if size is None or size == a.size: return a return Perm(a.array_form, size=size) - if isinstance(a, Cycle): # f - return Perm._af_new(a.list(size)) - if not is_sequence(a): # b - return Perm._af_new(list(range(a + 1))) + if isinstance(a, Cycle): # f + return _af_new(a.list(size)) + if not is_sequence(a): # b + return _af_new(list(range(a + 1))) if has_variety(is_sequence(ai) for ai in a): ok = False else: ok = False if not ok: - raise ValueError("Permutation argument must be a list of ints, " - "a list of lists, Permutation or Cycle.") + raise ValueError("Permutation argument must be a list of ints, " + "a list of lists, Permutation or Cycle.") # safe to assume args are valid; this also makes a copy # of the args args = list(args[0]) - is_cycle = args and is_sequence(args[0]) - if is_cycle: # e + is_cycle = args and is_sequence(args[0]) + if is_cycle: # e args = [[int(i) for i in c] for c in args] - else: # d + else: # d args = [int(i) for i in args] # if there are n elements present, 0, 1, ..., n-1 should be present @@ -821,7 +870,7 @@ temp = set(temp) if not is_cycle and \ - any(i not in temp for i in range(len(temp))): + any(i not in temp for i in range(len(temp))): raise ValueError("Integers 0 through %s must be present." % max(temp)) @@ -878,9 +927,7 @@ @property def array_form(self): """ - This is used to convert from cyclic notation to the - canonical notation. - + Return a copy of the attribute _array_form Examples ======== @@ -895,24 +942,8 @@ [2, 0, 3, 1] >>> Permutation([[1, 2], [4, 5]]).array_form [0, 2, 1, 3, 5, 4] - - See Also - ======== - - cyclic_form """ - # watch that given list doesn't shadow the argument: - # store a copy; return a copy - if self._array_form is not None: - return list(self._array_form) - cycles = self.args[0] - perm = list(range(self.size)) - for c in cycles: - for i in range(len(c) - 1): - perm[c[i]] = c[i + 1] - perm[c[-1]] = c[0] - self._array_form = perm[:] - return self.array_form + return self._array_form[:] def list(self, size=None): """Return the permutation as an explicit list, possibly @@ -993,7 +1024,7 @@ unchecked[j] = False if len(cycle) > 1: cyclic_form.append(cycle) - assert cycle == list(minlex(cycle)) + assert cycle == list(minlex(cycle, is_set=True)) cyclic_form.sort() self._cyclic_form = cyclic_form[:] return cyclic_form @@ -1048,7 +1079,7 @@ [0, 1, 2, 3] """ a = self.array_form - return [i for i, e in enumerate(self.array_form) if a[i] != i] + return [i for i, e in enumerate(a) if a[i] != i] def __add__(self, other): """Return permutation that is other higher in rank than self. @@ -1093,6 +1124,8 @@ Return product of Permutations [a, b, c, ...] as the Permutation whose ith value is a(b(c(i))). + a, b, c, ... can be Permutation objects or tuples. + Examples ======== @@ -1131,6 +1164,24 @@ rv = args[i]*rv return rv + @staticmethod + def rmul_with_af(*args): + """ + same as rmul, but the elements of args are Permutation objects + which have _array_form + """ + a = [x._array_form for x in args] + rv = _af_new(_af_rmuln(*a)) + return rv + + def mul_inv(self, other): + """ + other*~self, self and other have _array_form + """ + a = _af_invert(self._array_form) + b = other._array_form + return _af_new(_af_rmul(a, b)) + def __rmul__(self, other): """This is needed to coerse other to Permutation in rmul.""" return Perm(other)*self @@ -1194,7 +1245,7 @@ else: b.extend(list(range(len(b), len(a)))) perm = [b[i] for i in a] + b[len(a):] - return Perm._af_new(perm) + return _af_new(perm) def commutes_with(self, other): """ @@ -1233,37 +1284,9 @@ """ if type(n) == Perm: raise NotImplementedError( - 'p**p is not defined; do you mean p^p (conjugate)?') + 'p**p is not defined; do you mean p^p (conjugate)?') n = int(n) - if n == 0: - return Perm._af_new(list(range(self.size))) - if n < 0: - return pow(~self, -n) - a = self.array_form - if n == 1: - return Perm._af_new(a) # XXX is `return self` ok? - elif n == 2: - b = [a[i] for i in a] - elif n == 3: - b = [a[a[i]] for i in a] - elif n == 4: - b = [a[a[a[i]]] for i in a] - else: - # use binary multiplication - b = list(range(len(a))) - while 1: - if n & 1: - b = [b[i] for i in a] - n -= 1 - if not n: - break - if n % 4 == 0: - a = [a[a[a[i]]] for i in a] - n = n // 4 - elif n % 2 == 0: - a = [a[i] for i in a] - n = n // 2 - return Perm._af_new(b) + return _af_new(_af_pow(self.array_form, n)) def __rxor__(self, i): """Return self(i) when ``i`` is an int. @@ -1352,12 +1375,12 @@ if self.size != h.size: raise ValueError("The permutations must be of equal size.") - invh = [None]*self.size - h = h.array_form - p = self.array_form + a = [None]*self.size + h = h._array_form + p = self._array_form for i in range(self.size): - invh[h[i]] = i - return Perm._af_new([h[p[i]] for i in invh]) + a[h[i]] = h[p[i]] + return _af_new(a) def transpositions(self): """ @@ -1393,8 +1416,8 @@ res.append(tuple(x)) elif nx > 2: first = x[0] - for y in x[nx-1:0:-1]: - res.append((first,y)) + for y in x[nx - 1:0:-1]: + res.append((first, y)) return res @classmethod @@ -1440,7 +1463,7 @@ >>> p*~p == ~p*p == Permutation([0, 1, 2, 3]) True """ - return Perm._af_new(_af_invert(self.array_form)) + return _af_new(_af_invert(self._array_form)) def __iter__(self): """Yield elements from array form. @@ -1483,22 +1506,13 @@ i = i[0] try: # P(1) - return self.array_form[i] + return self._array_form[i] except TypeError: try: # P([a, b, c]) - return [i[j] for j in self.array_form] - except TypeError: - try: - if isinstance(i, Cycle): - i = Permutation(i.list(), size=self.size) - else: - i = Permutation( - i.array_form, size=self.size) - i = i.array_form - return [i[j] for j in self.array_form] - except: - raise TypeError('unrecognized argument') + return [i[j] for j in self._array_form] + except: + raise TypeError('unrecognized argument') else: # P(1, 2, 3) return self*Permutation(Cycle(*i), size=self.size) @@ -1544,7 +1558,7 @@ perm = self.array_form[:] n = len(perm) i = n - 2 - while perm[i+1] < perm[i]: + while perm[i + 1] < perm[i]: i -= 1 if i == -1: return None @@ -1559,7 +1573,7 @@ perm[j], perm[i] = perm[i], perm[j] i += 1 j -= 1 - return Perm._af_new(perm) + return _af_new(perm) @classmethod def unrank_nonlex(self, n, r): @@ -1591,9 +1605,9 @@ n = int(n) r = r % ifac(n) _unrank1(n, r, id_perm) - return Perm._af_new(id_perm) + return _af_new(id_perm) - def rank_nonlex(self, inv_perm = None): + def rank_nonlex(self, inv_perm=None): """ This is a linear time ranking algorithm that does not enforce lexicographic order [3]. @@ -1654,22 +1668,19 @@ r = self.rank_nonlex() if r == ifac(self.size) - 1: return None - return Perm.unrank_nonlex(self.size, r+1) + return Perm.unrank_nonlex(self.size, r + 1) - def rank(self, i=None): + def rank(self): """ - Returns the lexicographic rank of the permutation (default) or - the ith ranked permutation of self. + Returns the lexicographic rank of the permutation. Examples ======== >>> from sympy.combinatorics.permutations import Permutation - >>> p = Permutation([0,1,2,3]) + >>> p = Permutation([0, 1, 2, 3]) >>> p.rank() 0 - >>> p.rank(23) == Permutation([3, 2, 1, 0]) - True >>> p = Permutation([3, 2, 1, 0]) >>> p.rank() 23 @@ -1679,8 +1690,6 @@ next_lex, unrank_lex, cardinality, length, order, size """ - if i is not None: - return self.unrank_lex(self.size, i) if not self._rank is None: return self._rank rank = 0 @@ -1884,7 +1893,7 @@ descents, inversions, min, max """ a = self.array_form - pos = [i for i in range(len(a)-1) if a[i] < a[i+1]] + pos = [i for i in range(len(a) - 1) if a[i] < a[i + 1]] return pos def descents(self): @@ -1906,7 +1915,7 @@ ascents, inversions, min, max """ a = self.array_form - pos = [i for i in range(len(a)-1) if a[i] > a[i+1]] + pos = [i for i in range(len(a) - 1) if a[i] > a[i + 1]] return pos def max(self): @@ -2007,9 +2016,9 @@ while i + k < n: right = i + k * 2 - 1 if right >= n: - right = n -1 - inversions += _merge(arr, temp, i, i+k, right) - i = i + k * 2; + right = n - 1 + inversions += _merge(arr, temp, i, i + k, right) + i = i + k * 2 k = k * 2 return inversions @@ -2059,7 +2068,7 @@ invb = [None]*n for i in range(n): invb[b[i]] = i - return Perm._af_new([a[b[inva[i]]] for i in invb]) + return _af_new([a[b[inva[i]]] for i in invb]) def signature(self): """ @@ -2165,7 +2174,7 @@ if singletons: rv[1] = singletons self._cycle_structure = rv - return dict(rv) # make a copy + return dict(rv) # make a copy @property def cycles(self): @@ -2183,6 +2192,10 @@ [[0], [1], [2]] >>> Permutation(0, 1)(2, 3).cycles 2 + + See Also + ======== + sympy.functions.combinatorial.numbers.stirling """ return len(self.full_cyclic_form) @@ -2203,7 +2216,7 @@ """ a = self.array_form - return sum([j for j in range(len(a) - 1) if a[j] > a[j+1]]) + return sum([j for j in range(len(a) - 1) if a[j] > a[j + 1]]) def runs(self): """ @@ -2271,7 +2284,7 @@ for i in range(n - 1): val = 0 - for j in range(i+1, n): + for j in range(i + 1, n): if self_array_form[j] < self_array_form[i]: val += 1 inversion_vector[i] = val @@ -2340,20 +2353,20 @@ r2 = 0 n = ifac(size) pj = 1 - for j in range(2, size+1): + for j in range(2, size + 1): pj *= j r1 = (rank * pj) // n k = r1 - j*r2 if r2 % 2 == 0: - for i in range(j-1, j-k-1, -1): - perm[i] = perm[i-1] - perm[j-k-1] = j-1 + for i in range(j - 1, j - k - 1, -1): + perm[i] = perm[i - 1] + perm[j - k - 1] = j - 1 else: - for i in range(j-1, k, -1): - perm[i] = perm[i-1] - perm[k] = j-1 + for i in range(j - 1, k, -1): + perm[i] = perm[i - 1] + perm[k] = j - 1 r2 = r1 - return Perm._af_new(perm) + return _af_new(perm) def next_trotterjohnson(self): """ @@ -2388,24 +2401,24 @@ while m > 0 and not done: d = rho.index(m) for i in range(d, m): - rho[i] = rho[i+1] + rho[i] = rho[i + 1] par = _af_parity(rho[:m]) if par == 1: if d == m: m -= 1 else: - pi[st+d], pi[st+d+1] = pi[st+d+1], pi[st+d] + pi[st + d], pi[st + d + 1] = pi[st + d + 1], pi[st + d] done = True else: if d == 0: m -= 1 st += 1 else: - pi[st+d], pi[st+d-1] = pi[st+d-1], pi[st+d] + pi[st + d], pi[st + d - 1] = pi[st + d - 1], pi[st + d] done = True if m == 0: return None - return Perm._af_new(pi) + return _af_new(pi) def get_precedence_matrix(self): """ @@ -2420,12 +2433,13 @@ >>> p Permutation([2, 5, 3, 1, 4, 0]) >>> p.get_precedence_matrix() - [0, 0, 0, 0, 0, 0] - [1, 0, 0, 0, 1, 0] - [1, 1, 0, 1, 1, 1] - [1, 1, 0, 0, 1, 0] - [1, 0, 0, 0, 0, 0] - [1, 1, 0, 1, 1, 0] + Matrix([ + [0, 0, 0, 0, 0, 0], + [1, 0, 0, 0, 1, 0], + [1, 1, 0, 1, 1, 1], + [1, 1, 0, 0, 1, 0], + [1, 0, 0, 0, 0, 0], + [1, 1, 0, 1, 1, 0]]) See Also ======== @@ -2491,19 +2505,20 @@ >>> from sympy.combinatorics.permutations import Permutation >>> p = Permutation.josephus(3,6,1) >>> p.get_adjacency_matrix() - [0, 0, 0, 0, 0, 0] - [0, 0, 0, 0, 1, 0] - [0, 0, 0, 0, 0, 1] - [0, 1, 0, 0, 0, 0] - [1, 0, 0, 0, 0, 0] - [0, 0, 0, 1, 0, 0] - + Matrix([ + [0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 1, 0], + [0, 0, 0, 0, 0, 1], + [0, 1, 0, 0, 0, 0], + [1, 0, 0, 0, 0, 0], + [0, 0, 0, 1, 0, 0]]) >>> q = Permutation([0, 1, 2, 3]) >>> q.get_adjacency_matrix() - [0, 1, 0, 0] - [0, 0, 1, 0] - [0, 0, 0, 1] - [0, 0, 0, 0] + Matrix([ + [0, 1, 0, 0], + [0, 0, 1, 0], + [0, 0, 0, 1], + [0, 0, 0, 0]]) See Also ======== @@ -2587,7 +2602,7 @@ return sum([abs(a[i] - b[i]) for i in range(len(a))]) @classmethod - def josephus(self, m, n, s = 1): + def josephus(self, m, n, s=1): """Return as a permutation the shuffling of range(n) using the Josephus scheme in which every m-th item is selected until all have been chosen. The returned permutation has elements listed by the order in which they @@ -2660,7 +2675,7 @@ except IndexError: raise ValueError("The inversion vector is not valid.") perm.extend(N) - return Perm._af_new(perm) + return _af_new(perm) @classmethod def random(self, n): @@ -2679,7 +2694,7 @@ """ perm_array = list(range(n)) random.shuffle(perm_array) - return Perm._af_new(perm_array) + return _af_new(perm_array) @classmethod def unrank_lex(self, size, rank): @@ -2710,16 +2725,17 @@ rank -= d*psize perm_array[size - i - 1] = d for j in range(size - i, size): - if perm_array[j] > d-1: + if perm_array[j] > d - 1: perm_array[j] += 1 psize = new_psize - return Perm._af_new(perm_array) + return _af_new(perm_array) # global flag to control how permutations are printed # when True, Permutation([0, 2, 1, 3]) -> Cycle(1, 2) # when False, Permutation([0, 2, 1, 3]) -> Permutation([0, 2, 1]) print_cyclic = True + def _merge(arr, temp, left, mid, right): """ Merges two sorted arrays and calculates the inversion count. @@ -2753,3 +2769,4 @@ return inv_count Perm = Permutation +_af_new = Perm._af_new diff -Nru python3-sympy-0.7.2/sympy/combinatorics/polyhedron.py python3-sympy-0.7.3/sympy/combinatorics/polyhedron.py --- python3-sympy-0.7.2/sympy/combinatorics/polyhedron.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/combinatorics/polyhedron.py 2013-07-13 17:53:31.000000000 +0000 @@ -6,6 +6,7 @@ rmul = Perm.rmul + class Polyhedron(Basic): """ Represents the polyhedral symmetry group (PSG). @@ -74,12 +75,12 @@ permutation, Permutation(range(4)), is not included since it does not change the orientation of the vertices.) - >>> pgroup = [Permutation([[0,1,2], [3]]),\ - Permutation([[0,1,3], [2]]),\ - Permutation([[0,2,3], [1]]),\ - Permutation([[1,2,3], [0]]),\ - Permutation([[0,1], [2,3]]),\ - Permutation([[0,2], [1,3]]),\ + >>> pgroup = [Permutation([[0,1,2], [3]]), \ + Permutation([[0,1,3], [2]]), \ + Permutation([[0,2,3], [1]]), \ + Permutation([[1,2,3], [0]]), \ + Permutation([[0,1], [2,3]]), \ + Permutation([[0,2], [1,3]]), \ Permutation([[0,3], [1,2]])] The Polyhedron is now constructed and demonstrated: @@ -104,17 +105,17 @@ Here is a demonstration that applying p and p**2 for every p in pgroup generates all the orientations of a tetrahedron and no others: - >>> all = ( (w, x, y, z) ,\ - (x, y, w, z) ,\ - (y, w, x, z) ,\ - (w, z, x, y) ,\ - (z, w, y, x) ,\ - (w, y, z, x) ,\ - (y, z, w, x) ,\ - (x, z, y, w) ,\ - (z, y, x, w) ,\ - (y, x, z, w) ,\ - (x, w, z, y) ,\ + >>> all = ( (w, x, y, z), \ + (x, y, w, z), \ + (y, w, x, z), \ + (w, z, x, y), \ + (z, w, y, x), \ + (w, y, z, x), \ + (y, z, w, x), \ + (x, z, y, w), \ + (z, y, x, w), \ + (y, x, z, w), \ + (x, w, z, y), \ (z, x, w, y) ) >>> got = [] @@ -334,7 +335,8 @@ (0,1,2,3,4) (0,1,6,10,5) (1,2,7,11,6) (2,3,8,12,7) (3,4,9,13,8) (0,4,9,14,5) - (5,10,16,15,14) (6,10,16,17,11) (7,11,17,18,12) (8,12,18,19,13) (9,13,19,15,14) + (5,10,16,15,14) ( + 6,10,16,17,11) (7,11,17,18,12) (8,12,18,19,13) (9,13,19,15,14) (15,16,17,18,19) icosahedron, icosahedron_faces @@ -371,11 +373,11 @@ [1] www.ocf.berkeley.edu/~wwu/articles/platonicsolids.pdf """ - faces = [minlex(f, directed=False) for f in faces] + faces = [minlex(f, directed=False, is_set=True) for f in faces] corners, faces, pgroup = args = \ [Tuple(*a) for a in (corners, faces, pgroup)] obj = Basic.__new__(cls, *args) - obj._corners = tuple(corners) # in order given + obj._corners = tuple(corners) # in order given obj._faces = FiniteSet(faces) if pgroup and pgroup[0].size != len(corners): raise ValueError("Permutation size unequal to number of corners.") @@ -580,6 +582,7 @@ """ self._corners = self.args[0] + def _pgroup_calcs(): """Return the permutation groups for each of the polyhedra and the face definitions: tetrahedron, cube, octahedron, dodecahedron, icosahedron, @@ -663,7 +666,7 @@ # A map between face and the vertex of the double is made so that # after rotation the position of the vertices can be located fmap = dict(list(zip(ordered_faces, - list(range(len(ordered_faces)))))) + list(range(len(ordered_faces)))))) flat_faces = flatten(ordered_faces) new_pgroup = [] for i, p in enumerate(pgroup): @@ -674,29 +677,30 @@ # enumerating the faces reorder = unflatten([c[j] for j in flat_faces], n) # make them canonical - reorder = [tuple(map(as_int, minlex(f, directed=False))) - for f in reorder] + reorder = [tuple(map(as_int, + minlex(f, directed=False, is_set=True))) + for f in reorder] # map face to vertex: the resulting list of vertices are the # permutation that we seek for the double new_pgroup.append(Perm([fmap[f] for f in reorder])) return new_pgroup tetrahedron_faces = [ - (0, 1, 2), (0, 2, 3), (0, 3, 1), # upper 3 - (1, 2, 3), # bottom - ] + (0, 1, 2), (0, 2, 3), (0, 3, 1), # upper 3 + (1, 2, 3), # bottom + ] # cw from top # _t_pgroup = [ - Perm([[1,2,3], [0]]), # cw from top - Perm([[0,1,2], [3]]), # cw from front face - Perm([[0,3,2], [1]]), # cw from back right face - Perm([[0,3,1], [2]]), # cw from back left face - Perm([[0,1], [2,3]]), # through front left edge - Perm([[0,2], [1,3]]), # through front right edge - Perm([[0,3], [1,2]]), # through back edge - ] + Perm([[1, 2, 3], [0]]), # cw from top + Perm([[0, 1, 2], [3]]), # cw from front face + Perm([[0, 3, 2], [1]]), # cw from back right face + Perm([[0, 3, 1], [2]]), # cw from back left face + Perm([[0, 1], [2, 3]]), # through front left edge + Perm([[0, 2], [1, 3]]), # through front right edge + Perm([[0, 3], [1, 2]]), # through back edge + ] tetrahedron = Polyhedron( list(range(4)), @@ -704,29 +708,29 @@ _t_pgroup) cube_faces = [ - (0, 1, 2, 3), # upper - (0, 1, 5, 4), (1, 2, 6, 5), (2, 3, 7, 6), (0, 3, 7, 4), # middle 4 - (4, 5, 6, 7), # lower + (0, 1, 2, 3), # upper + (0, 1, 5, 4), (1, 2, 6, 5), (2, 3, 7, 6), (0, 3, 7, 4), # middle 4 + (4, 5, 6, 7), # lower ] # U, D, F, B, L, R = up, down, front, back, left, right _c_pgroup = [Perm(p) for p in [ - [1,2,3,0,5,6,7,4], # cw from top, U - [4,0,3,7,5,1,2,6], # cw from F face - [4,5,1,0,7,6,2,3], # cw from R face - - [1,0,4,5,2,3,7,6], # cw through UF edge - [6,2,1,5,7,3,0,4], # cw through UR edge - [6,7,3,2,5,4,0,1], # cw through UB edge - [3,7,4,0,2,6,5,1], # cw through UL edge - [4,7,6,5,0,3,2,1], # cw through FL edge - [6,5,4,7,2,1,0,3], # cw through FR edge - - [0,3,7,4,1,2,6,5], # cw through UFL vertex - [5,1,0,4,6,2,3,7], # cw through UFR vertex - [5,6,2,1,4,7,3,0], # cw through UBR vertex - [7,4,0,3,6,5,1,2], # cw through UBL + [1, 2, 3, 0, 5, 6, 7, 4], # cw from top, U + [4, 0, 3, 7, 5, 1, 2, 6], # cw from F face + [4, 5, 1, 0, 7, 6, 2, 3], # cw from R face + + [1, 0, 4, 5, 2, 3, 7, 6], # cw through UF edge + [6, 2, 1, 5, 7, 3, 0, 4], # cw through UR edge + [6, 7, 3, 2, 5, 4, 0, 1], # cw through UB edge + [3, 7, 4, 0, 2, 6, 5, 1], # cw through UL edge + [4, 7, 6, 5, 0, 3, 2, 1], # cw through FL edge + [6, 5, 4, 7, 2, 1, 0, 3], # cw through FR edge + + [0, 3, 7, 4, 1, 2, 6, 5], # cw through UFL vertex + [5, 1, 0, 4, 6, 2, 3, 7], # cw through UFR vertex + [5, 6, 2, 1, 4, 7, 3, 0], # cw through UBR vertex + [7, 4, 0, 3, 6, 5, 1, 2], # cw through UBL ]] cube = Polyhedron( @@ -735,9 +739,9 @@ _c_pgroup) octahedron_faces = [ - (0, 1, 2), (0, 2, 3), (0, 3, 4), (0, 1, 4), # top 4 - (1, 2, 5), (2, 3, 5), (3, 4, 5), (1, 4, 5), # bottom 4 - ] + (0, 1, 2), (0, 2, 3), (0, 3, 4), (0, 1, 4), # top 4 + (1, 2, 5), (2, 3, 5), (3, 4, 5), (1, 4, 5), # bottom 4 + ] octahedron = Polyhedron( list(range(6)), @@ -745,13 +749,14 @@ _pgroup_of_double(cube, cube_faces, _c_pgroup)) dodecahedron_faces = [ - (0,1,2,3,4), # top - (0,1,6,10,5), (1,2,7,11,6), (2,3,8,12,7), # upper 5 - (3,4,9,13,8), (0,4,9,14,5), - (5,10,16,15,14), (6,10,16,17,11), (7,11,17,18,12), # lower 5 - (8,12,18,19,13), (9,13,19,15,14), - (15,16,17,18,19) # bottom - ] + (0, 1, 2, 3, 4), # top + (0, 1, 6, 10, 5), (1, 2, 7, 11, 6), (2, 3, 8, 12, 7), # upper 5 + (3, 4, 9, 13, 8), (0, 4, 9, 14, 5), + (5, 10, 16, 15, 14), (6, 10, 16, 17, 11), (7, 11, 17, 18, + 12), # lower 5 + (8, 12, 18, 19, 13), (9, 13, 19, 15, 14), + (15, 16, 17, 18, 19) # bottom + ] def _string_to_perm(s): rv = [Perm(list(range(20)))] @@ -794,14 +799,14 @@ icosahedron_faces = [ [0, 1, 2], [0, 2, 3], [0, 3, 4], [0, 4, 5], [0, 1, 5], [1, 6, 7], [1, 2, 7], [2, 7, 8], [2, 3, 8], [3, 8, 9 ], - [3, 4, 9], [4,9,10 ], [4, 5,10], [5, 6, 10], [1, 5, 6 ], + [3, 4, 9], [4, 9, 10 ], [4, 5, 10], [5, 6, 10], [1, 5, 6 ], [6, 7, 11], [7, 8, 11], [8, 9, 11], [9, 10, 11], [6, 10, 11]] icosahedron = Polyhedron( list(range(12)), icosahedron_faces, _pgroup_of_double( - dodecahedron, dodecahedron_faces, _dodeca_pgroup)) + dodecahedron, dodecahedron_faces, _dodeca_pgroup)) return (tetrahedron, cube, octahedron, dodecahedron, icosahedron, tetrahedron_faces, cube_faces, octahedron_faces, diff -Nru python3-sympy-0.7.2/sympy/combinatorics/prufer.py python3-sympy-0.7.3/sympy/combinatorics/prufer.py --- python3-sympy-0.7.2/sympy/combinatorics/prufer.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/combinatorics/prufer.py 2013-07-13 17:53:31.000000000 +0000 @@ -4,6 +4,7 @@ from collections import defaultdict + class Prufer(Basic): """ The Prufer correspondence is an algorithm that describes the @@ -248,18 +249,18 @@ >>> from sympy.combinatorics.prufer import Prufer >>> Prufer.edges([1, 2, 3], [2, 4, 5]) # a T - ([[0, 1], [3, 4], [1, 2], [1, 3]], 5) + ([[0, 1], [1, 2], [1, 3], [3, 4]], 5) Duplicate edges are removed: >>> Prufer.edges([0, 1, 2, 3], [1, 4, 5], [1, 4, 6]) # a K - ([[0, 1], [1, 2], [4, 6], [4, 5], [1, 4], [2, 3]], 7) + ([[0, 1], [1, 2], [1, 4], [2, 3], [4, 5], [4, 6]], 7) """ e = set() nmin = runs[0][0] for r in runs: - for i in range(len(r)-1): + for i in range(len(r) - 1): a, b = r[i: i + 2] if b < a: a, b = b, a @@ -267,12 +268,11 @@ rv = [] got = set() nmin = nmax = None - while e: - ei = e.pop() + for ei in e: for i in ei: got.add(i) - nmin = min(ei[0], nmin) if nmin != None else ei[0] - nmax = max(ei[1], nmax) if nmax != None else ei[1] + nmin = min(ei[0], nmin) if nmin is not None else ei[0] + nmax = max(ei[1], nmax) if nmax is not None else ei[1] rv.append(list(ei)) missing = set(range(nmin, nmax + 1)) - got if missing: @@ -286,7 +286,7 @@ for i, ei in enumerate(rv): rv[i] = [n - nmin for n in ei] nmax -= nmin - return rv, nmax + 1 + return sorted(rv), nmax + 1 def prufer_rank(self): """Computes the rank of a Prufer sequence. @@ -363,7 +363,8 @@ args = [list(args[0])] if args[0] and iterable(args[0][0]): if not args[0][0]: - raise ValueError('Prufer expects at least one edge in the tree.') + raise ValueError( + 'Prufer expects at least one edge in the tree.') if len(args) > 1: nnodes = args[1] else: @@ -427,4 +428,4 @@ prufer_rank, rank, next, size """ - return Prufer.unrank(self.rank - delta, self.nodes) + return Prufer.unrank(self.rank -delta, self.nodes) diff -Nru python3-sympy-0.7.2/sympy/combinatorics/subsets.py python3-sympy-0.7.3/sympy/combinatorics/subsets.py --- python3-sympy-0.7.2/sympy/combinatorics/subsets.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/combinatorics/subsets.py 2013-07-13 17:53:31.000000000 +0000 @@ -2,7 +2,7 @@ from sympy.combinatorics.graycode import GrayCode from sympy.core.compatibility import bin, combinations -from functools import reduce + class Subset(Basic): """ @@ -81,13 +81,9 @@ next_binary, prev_binary """ bin_list = Subset.bitlist_from_subset(self.subset, self.superset) - next_bin_list = list(bin((int(reduce(lambda x, y: - x + y, bin_list), 2) + k) - % 2**self.superset_size))[2:] - next_bin_list = [0] * (self.superset_size - len(next_bin_list)) + \ - next_bin_list - return Subset.subset_from_bitlist(self.superset, next_bin_list) - + n = (int(''.join(bin_list), 2) + k) % 2**self.superset_size + bits = bin(n)[2:].rjust(self.superset_size, '0') + return Subset.subset_from_bitlist(self.superset, bits) def next_binary(self): """ @@ -135,17 +131,84 @@ """ Generates the next lexicographically ordered subset. - NOT IMPLEMENTED + Examples + ======== + + >>> from sympy.combinatorics.subsets import Subset + >>> a = Subset(['c','d'], ['a','b','c','d']) + >>> a.next_lexicographic().subset + ['d'] + >>> a = Subset(['d'], ['a','b','c','d']) + >>> a.next_lexicographic().subset + [] + + See Also + ======== + prev_lexicographic """ - raise NotImplementedError() + i = self.superset_size - 1 + indices = Subset.subset_indices(self.subset, self.superset) + + if i in indices: + if i - 1 in indices: + indices.remove(i - 1) + else: + indices.remove(i) + i = i - 1 + while not i in indices and i >= 0: + i = i - 1 + if i >= 0: + indices.remove(i) + indices.append(i+1) + else: + while i not in indices and i >= 0: + i = i - 1 + indices.append(i + 1) + + ret_set = [] + super_set = self.superset + for i in indices: + ret_set.append(super_set[i]) + return Subset(ret_set, super_set) def prev_lexicographic(self): """ Generates the previous lexicographically ordered subset. - NOT YET IMPLEMENTED + Examples + ======== + + >>> from sympy.combinatorics.subsets import Subset + >>> a = Subset([], ['a','b','c','d']) + >>> a.prev_lexicographic().subset + ['d'] + >>> a = Subset(['c','d'], ['a','b','c','d']) + >>> a.prev_lexicographic().subset + ['c'] + + See Also + ======== + next_lexicographic """ - raise NotImplementedError() + i = self.superset_size - 1 + indices = Subset.subset_indices(self.subset, self.superset) + + while i not in indices and i >= 0: + i = i - 1 + + if i - 1 in indices or i == 0: + indices.remove(i) + else: + if i >= 0: + indices.remove(i) + indices.append(i - 1) + indices.append(self.superset_size - 1) + + ret_set = [] + super_set = self.superset + for i in indices: + ret_set.append(super_set[i]) + return Subset(ret_set, super_set) def iterate_graycode(self, k): """ @@ -227,7 +290,7 @@ ======== iterate_binary, unrank_binary """ - if self._rank_binary == None: + if self._rank_binary is None: self._rank_binary = int("".join( Subset.bitlist_from_subset(self.subset, self.superset)), 2) @@ -249,7 +312,7 @@ >>> a.rank_lexicographic 43 """ - if self._rank_lex == None: + if self._rank_lex is None: def _ranklex(self, subset_index, i, n): if subset_index == [] or i > n: return 0 @@ -281,7 +344,7 @@ ======== iterate_graycode, unrank_gray """ - if self._rank_graycode == None: + if self._rank_graycode is None: bits = Subset.bitlist_from_subset(self.subset, self.superset) self._rank_graycode = GrayCode(len(bits), start=bits).rank return self._rank_graycode @@ -444,9 +507,8 @@ ======== iterate_binary, rank_binary """ - bin_list = list(bin(rank))[2:] - bin_list = [0] * (len(superset) - len(bin_list)) + bin_list - return Subset.subset_from_bitlist(superset, bin_list) + bits = bin(rank)[2:].rjust(len(superset), '0') + return Subset.subset_from_bitlist(superset, bits) @classmethod def unrank_gray(self, rank, superset): @@ -499,6 +561,7 @@ return list() return [d[bi] for bi in b] + def ksubsets(superset, k): """ Finds the subsets of size k in lexicographic order. diff -Nru python3-sympy-0.7.2/sympy/combinatorics/tensor_can.py python3-sympy-0.7.3/sympy/combinatorics/tensor_can.py --- python3-sympy-0.7.2/sympy/combinatorics/tensor_can.py 1970-01-01 00:00:00.000000000 +0000 +++ python3-sympy-0.7.3/sympy/combinatorics/tensor_can.py 2013-07-13 17:53:31.000000000 +0000 @@ -0,0 +1,1179 @@ +from sympy.combinatorics.permutations import Permutation, _af_rmul, _af_rmuln,\ + _af_invert, _af_new +from sympy.combinatorics.perm_groups import PermutationGroup, _orbit, \ + _orbit_transversal +from sympy.combinatorics.util import _distribute_gens_by_base, \ + _orbits_transversals_from_bsgs + +""" + References for tensor canonicalization: + + [1] R. Portugal "Algorithmic simplification of tensor expressions", + J. Phys. A 32 (1999) 7779-7789 + + [2] R. Portugal, B.F. Svaiter "Group-theoretic Approach for Symbolic + Tensor Manipulation: I. Free Indices" + arXiv:math-ph/0107031v1 + + [3] L.R.U. Manssur, R. Portugal "Group-theoretic Approach for Symbolic + Tensor Manipulation: II. Dummy Indices" + arXiv:math-ph/0107032v1 + + [4] xperm.c part of XPerm written by J. M. Martin-Garcia + http://www.xact.es/index.html +""" + + +def dummy_sgs(dummies, sym, n): + """ + Return the strong generators for dummy indices + + Parameters + ========== + + dummies : list of dummy indices + `dummies[2k], dummies[2k+1]` are paired indices + sym : symmetry under interchange of contracted dummies:: + * None no symmetry + * 0 commuting + * 1 anticommuting + + n : number of indices + + in base form the dummy indices are always in consecutive positions + + Examples + ======== + + >>> from sympy.combinatorics.tensor_can import dummy_sgs + >>> dummy_sgs(list(range(2, 8)), 0, 8) + [[0, 1, 3, 2, 4, 5, 6, 7, 8, 9], [0, 1, 2, 3, 5, 4, 6, 7, 8, 9], + [0, 1, 2, 3, 4, 5, 7, 6, 8, 9], [0, 1, 4, 5, 2, 3, 6, 7, 8, 9], + [0, 1, 2, 3, 6, 7, 4, 5, 8, 9]] + """ + assert len(dummies) <= n + res = [] + # exchange of contravariant and covariant indices + if sym is not None: + for j in dummies[::2]: + a = list(range(n + 2)) + if sym == 1: + a[n] = n + 1 + a[n + 1] = n + a[j], a[j + 1] = a[j + 1], a[j] + res.append(a) + # rename dummy indices + for j in dummies[:-3:2]: + a = list(range(n + 2)) + a[j:j + 4] = a[j + 2], a[j + 3], a[j], a[j + 1] + res.append(a) + return res + + +def _min_dummies(dummies, sym, indices): + """ + Return list of minima of the orbits of indices in group of dummies + see `double_coset_can_rep` for the description of `dummies` and `sym` + indices is the initial list of dummy indices + + Examples + ======== + + >>> from sympy.combinatorics.tensor_can import _min_dummies + >>> _min_dummies([list(range(2, 8))], [0], list(range(10))) + [0, 1, 2, 2, 2, 2, 2, 2, 8, 9] + """ + num_types = len(sym) + m = [] + for dx in dummies: + if dx: + m.append(min(dx)) + else: + m.append(None) + res = indices[:] + for i in range(num_types): + for c, i in enumerate(indices): + for j in range(num_types): + if i in dummies[j]: + res[c] = m[j] + break + return res + + +def _trace_S(s, j, b, S_cosets): + """ + Return the representative h satisfying s[h[b]] == j + + If there is not such a representative return None + """ + for h in S_cosets[b]: + if s[h[b]] == j: + return h + return None + + +def _trace_D(gj, p_i, Dxtrav): + """ + Return the representative h satisfying h[gj] == p_i + + If there is not such a representative return None + """ + for h in Dxtrav: + if h[gj] == p_i: + return h + return None + + +def _dumx_remove(dumx, dumx_flat, p0): + """ + remove p0 from dumx + """ + res = [] + for dx in dumx: + if p0 not in dx: + res.append(dx) + continue + k = dx.index(p0) + if k % 2 == 0: + p0_paired = dx[k + 1] + else: + p0_paired = dx[k - 1] + dx.remove(p0) + dx.remove(p0_paired) + dumx_flat.remove(p0) + dumx_flat.remove(p0_paired) + res.append(dx) + + +def transversal2coset(size, base, transversal): + a = [] + j = 0 + for i in range(size): + if i in base: + a.append(sorted(transversal[j].values())) + j += 1 + else: + a.append([list(range(size))]) + j = len(a) - 1 + while a[j] == [list(range(size))]: + j -= 1 + return a[:j + 1] + + +def double_coset_can_rep(dummies, sym, b_S, sgens, S_transversals, g): + """ + Butler-Portugal algorithm for tensor canonicalization with dummy indices + + dummies + list of lists of dummy indices, + one list for each type of index; + the dummy indices are put in order contravariant, covariant + [d0, -d0, d1, -d1, ...]. + + sym + list of the symmetries of the index metric for each type. + + possible symmetries of the metrics + * 0 symmetric + * 1 antisymmetric + * None no symmetry + + b_S + base of a minimal slot symmetry BSGS. + + sgens + generators of the slot symmetry BSGS. + + S_transversals + transversals for the slot BSGS. + + g + permutation representing the tensor. + + Return 0 if the tensor is zero, else return the array form of + the permutation representing the canonical form of the tensor. + + + A tensor with dummy indices can be represented in a number + of equivalent ways which typically grows exponentially with + the number of indices. To be able to establish if two tensors + with many indices are equal becomes computationally very slow + in absence of an efficient algorithm. + + The Butler-Portugal algorithm [3] is an efficient algorithm to + put tensors in canonical form, solving the above problem. + + Portugal observed that a tensor can be represented by a permutation, + and that the class of tensors equivalent to it under slot and dummy + symmetries is equivalent to the double coset `D*g*S` + (Note: in this documentation we use the conventions for multiplication + of permutations p, q with (p*q)(i) = p[q[i]] which is opposite + to the one used in the Permutation class) + + Using the algorithm by Butler to find a representative of the + double coset one can find a canonical form for the tensor. + + To see this correspondence, + let `g` be a permutation in array form; a tensor with indices `ind` + (the indices including both the contravariant and the covariant ones) + can be written as + + `t = T(ind[g[0],..., ind[g[n-1]])`, + + where `n= len(ind)`; + `g` has size `n + 2`, the last two indices for the sign of the tensor + (trick introduced in [4]). + + A slot symmetry transformation `s` is a permutation acting on the slots + `t -> T(ind[(g*s)[0]],..., ind[(g*s)[n-1]])` + + A dummy symmetry transformation acts on `ind` + `t -> T(ind[(d*g)[0]],..., ind[(d*g)[n-1]])` + + Being interested only in the transformations of the tensor under + these symmetries, one can represent the tensor by `g`, which transforms + as + + `g -> d*g*s`, so it belongs to the coset `D*g*S`. + + Let us explain the conventions by an example. + + Given a tensor `T^{d3 d2 d1}{}_{d1 d2 d3}` with the slot symmetries + `T^{a0 a1 a2 a3 a4 a5} = -T^{a2 a1 a0 a3 a4 a5}` + + `T^{a0 a1 a2 a3 a4 a5} = -T^{a4 a1 a2 a3 a0 a5}` + + and symmetric metric, find the tensor equivalent to it which + is the lowest under the ordering of indices: + lexicographic ordering `d1, d2, d3` then and contravariant index + before covariant index; that is the canonical form of the tensor. + + The canonical form is `-T^{d1 d2 d3}{}_{d1 d2 d3}` + obtained using `T^{a0 a1 a2 a3 a4 a5} = -T^{a2 a1 a0 a3 a4 a5}`. + + To convert this problem in the input for this function, + use the following labelling of the index names + (- for covariant for short) `d1, -d1, d2, -d2, d3, -d3` + + `T^{d3 d2 d1}{}_{d1 d2 d3}` corresponds to `g = [4,2,0,1,3,5,6,7]` + where the last two indices are for the sign + + `sgens = [Permutation(0,2)(6,7), Permutation(0,4)(6,7)]` + + sgens[0] is the slot symmetry `-(0,2)` + `T^{a0 a1 a2 a3 a4 a5} = -T^{a2 a1 a0 a3 a4 a5}` + + sgens[1] is the slot symmetry `-(0,4)` + `T^{a0 a1 a2 a3 a4 a5} = -T^{a4 a1 a2 a3 a0 a5}` + + The dummy symmetry group D is generated by the strong base generators + `[(0,1),(2,3),(4,5),(0,1)(2,3),(2,3)(4,5)]` + + The dummy symmetry acts from the left + `d = [1,0,2,3,4,5,6,7]` exchange `d1 -> -d1` + `T^{d3 d2 d1}{}_{d1 d2 d3} == T^{d3 d2}{}_{d1}{}^{d1}{}_{d2 d3}` + + `g=[4,2,0,1,3,5,6,7] -> [4,2,1,0,3,5,6,7] = _af_rmul(d, g)` + which differs from `_af_rmul(g, d)`. + + The slot symmetry acts from the right + `s = [2,1,0,3,4,5,7,6]` exchanges slots 0 and 2 and changes sign + `T^{d3 d2 d1}{}_{d1 d2 d3} == -T^{d1 d2 d3}{}_{d1 d2 d3}` + + `g=[4,2,0,1,3,5,6,7] -> [0,2,4,1,3,5,7,6] = _af_rmul(g, s)` + + Example in which the tensor is zero, same slot symmetries as above: + `T^{d3}{}_{d1,d2}{}^{d1}{}_{d3}{}^{d2}` + + `= -T^{d3}{}_{d1,d3}{}^{d1}{}_{d2}{}^{d2}` under slot symmetry `-(2,4)`; + + `= T_{d3 d1}{}^{d3}{}^{d1}{}_{d2}{}^{d2}` under slot symmetry `-(0,2)`; + + `= T^{d3}{}_{d1 d3}{}^{d1}{}_{d2}{}^{d2}` symmetric metric; + + `= 0` since two of these lines have tensors differ only for the sign. + + The double coset D*g*S consists of permutations `h = d*g*s` corresponding + to equivalent tensors; if there are two `h` which are the same apart + from the sign, return zero; otherwise + choose as representative the tensor with indices + ordered lexicographically according to `[d1, -d1, d2, -d2, d3, -d3]` + that is `rep = min(D*g*S) = min([d*g*s for d in D for s in S])` + + The indices are fixed one by one; first choose the lowest index + for slot 0, then the lowest remaining index for slot 1, etc. + Doing this one obtains a chain of stabilizers + + `S -> S_{b0} -> S_{b0,b1} -> ...` and + `D -> D_{p0} -> D_{p0,p1} -> ...` + + where `[b0, b1, ...] = range(b)` is a base of the symmetric group; + the strong base `b_S` of S is an ordered sublist of it; + therefore it is sufficient to compute once the + strong base generators of S using the Schreier-Sims algorithm; + the stabilizers of the strong base generators are the + strong base generators of the stabilizer subgroup. + + `dbase = [p0,p1,...]` is not in general in lexicographic order, + so that one must recompute the strong base generators each time; + however this is trivial, there is no need to use the Schreier-Sims + algorithm for D. + + The algorithm keeps a TAB of elements `(s_i, d_i, h_i)` + where `h_i = d_i*g*s_i` satisfying `h_i[j] = p_j` for `0 <= j < i` + starting from `s_0 = id, d_0 = id, h_0 = g`. + + The equations `h_0[0] = p_0, h_1[1] = p_1,...` are solved in this order, + choosing each time the lowest possible value of p_i + + For `j < i` + `d_i*g*s_i*S_{b_0,...,b_{i-1}}*b_j = D_{p_0,...,p_{i-1}}*p_j` + so that for dx in `D_{p_0,...,p_{i-1}}` and sx in + `S_{base[0],...,base[i-1]}` one has `dx*d_i*g*s_i*sx*b_j = p_j` + + Search for dx, sx such that this equation holds for `j = i`; + it can be written as `s_i*sx*b_j = J, dx*d_i*g*J = p_j` + `sx*b_j = s_i**-1*J; sx = trace(s_i**-1, S_{b_0,...,b_{i-1}})` + `dx**-1*p_j = d_i*g*J; dx = trace(d_i*g*J, D_{p_0,...,p_{i-1}})` + + `s_{i+1} = s_i*trace(s_i**-1*J, S_{b_0,...,b_{i-1}})` + `d_{i+1} = trace(d_i*g*J, D_{p_0,...,p_{i-1}})**-1*d_i` + `h_{i+1}*b_i = d_{i+1}*g*s_{i+1}*b_i = p_i` + + `h_n*b_j = p_j` for all j, so that `h_n` is the solution. + + Add the found `(s, d, h)` to TAB1. + + At the end of the iteration sort TAB1 with respect to the `h`; + if there are two consecutive `h` in TAB1 which differ only for the + sign, the tensor is zero, so return 0; + if there are two consecutive `h` which are equal, keep only one. + + Then stabilize the slot generators under `i` and the dummy generators + under `p_i`. + + Assign `TAB = TAB1` at the end of the iteration step. + + At the end `TAB` contains a unique `(s, d, h)`, since all the slots + of the tensor `h` have been fixed to have the minimum value according + to the symmetries. The algorithm returns `h`. + + It is important that the slot BSGS has lexicographic minimal base, + otherwise there is an `i` which does not belong to the slot base + for which `p_i` is fixed by the dummy symmetry only, while `i` + is not invariant from the slot stabilizer, so `p_i` is not in + general the minimal value. + + This algorithm differs slightly from the original algorithm [3]: + the canonical form is minimal lexicographically, and + the BSGS has minimal base under lexicographic order. + Equal tensors `h` are eliminated from TAB. + + + Examples + ======== + + >>> from sympy.combinatorics.permutations import Permutation + >>> from sympy.combinatorics.perm_groups import PermutationGroup + >>> from sympy.combinatorics.tensor_can import double_coset_can_rep, get_transversals + >>> gens = [Permutation(x) for x in [[2,1,0,3,4,5,7,6], [4,1,2,3,0,5,7,6]]] + >>> base = [0, 2] + >>> g = Permutation([4,2,0,1,3,5,6,7]) + >>> transversals = get_transversals(base, gens) + >>> double_coset_can_rep([list(range(6))], [0], base, gens, transversals, g) + [0, 1, 2, 3, 4, 5, 7, 6] + + >>> g = Permutation([4,1,3,0,5,2,6,7]) + >>> double_coset_can_rep([list(range(6))], [0], base, gens, transversals, g) + 0 + """ + size = g.size + g = g.array_form + num_dummies = size - 2 + indices = list(range(num_dummies)) + all_metrics_with_sym = all([_ is not None for _ in sym]) + num_types = len(sym) + dumx = dummies[:] + dumx_flat = [] + for dx in dumx: + dumx_flat.extend(dx) + b_S = b_S[:] + sgensx = [h._array_form for h in sgens] + if b_S: + S_transversals = transversal2coset(size, b_S, S_transversals) + # strong generating set for D + dsgsx = [] + for i in range(num_types): + dsgsx.extend(dummy_sgs(dumx[i], sym[i], num_dummies)) + ginv = _af_invert(g) + idn = list(range(size)) + # TAB = list of entries (s, d, h) where h = _af_rmuln(d,g,s) + # for short, in the following d*g*s means _af_rmuln(d,g,s) + TAB = [(idn, idn, g)] + for i in range(size - 2): + b = i + testb = b in b_S and sgensx + if testb: + sgensx1 = [_af_new(_) for _ in sgensx] + deltab = _orbit(size, sgensx1, b) + else: + deltab = set([b]) + # p1 = min(IMAGES) = min(Union D_p*h*deltab for h in TAB) + if all_metrics_with_sym: + md = _min_dummies(dumx, sym, indices) + else: + md = [min(_orbit(size, [_af_new( + ddx) for ddx in dsgsx], ii)) for ii in range(size - 2)] + + p_i = min([min([md[h[x]] for x in deltab]) for s, d, h in TAB]) + dsgsx1 = [_af_new(_) for _ in dsgsx] + Dxtrav = _orbit_transversal(size, dsgsx1, p_i, False, af=True) \ + if dsgsx else None + if Dxtrav: + Dxtrav = [_af_invert(x) for x in Dxtrav] + # compute the orbit of p_i + for ii in range(num_types): + if p_i in dumx[ii]: + # the orbit is made by all the indices in dum[ii] + if sym[ii] is not None: + deltap = dumx[ii] + else: + # the orbit is made by all the even indices if p_i + # is even, by all the odd indices if p_i is odd + p_i_index = dumx[ii].index(p_i) % 2 + deltap = dumx[ii][p_i_index::2] + break + else: + deltap = [p_i] + TAB1 = [] + nTAB = len(TAB) + while TAB: + s, d, h = TAB.pop() + if min([md[h[x]] for x in deltab]) != p_i: + continue + deltab1 = [x for x in deltab if md[h[x]] == p_i] + # NEXT = s*deltab1 intersection (d*g)**-1*deltap + dg = _af_rmul(d, g) + dginv = _af_invert(dg) + sdeltab = [s[x] for x in deltab1] + gdeltap = [dginv[x] for x in deltap] + NEXT = [x for x in sdeltab if x in gdeltap] + # d, s satisfy + # d*g*s*base[i-1] = p_{i-1}; using the stabilizers + # d*g*s*S_{base[0],...,base[i-1]}*base[i-1] = + # D_{p_0,...,p_{i-1}}*p_{i-1} + # so that to find d1, s1 satisfying d1*g*s1*b = p_i + # one can look for dx in D_{p_0,...,p_{i-1}} and + # sx in S_{base[0],...,base[i-1]} + # d1 = dx*d; s1 = s*sx + # d1*g*s1*b = dx*d*g*s*sx*b = p_i + for j in NEXT: + if testb: + # solve s1*b = j with s1 = s*sx for some element sx + # of the stabilizer of ..., base[i-1] + # sx*b = s**-1*j; sx = _trace_S(s, j,...) + # s1 = s*trace_S(s**-1*j,...) + s1 = _trace_S(s, j, b, S_transversals) + if not s1: + continue + else: + s1 = [s[ix] for ix in s1] + else: + s1 = s + #assert s1[b] == j # invariant + # solve d1*g*j = p_i with d1 = dx*d for some element dg + # of the stabilizer of ..., p_{i-1} + # dx**-1*p_i = d*g*j; dx**-1 = trace_D(d*g*j,...) + # d1 = trace_D(d*g*j,...)**-1*d + # to save an inversion in the inner loop; notice we did + # Dxtrav = [perm_af_invert(x) for x in Dxtrav] out of the loop + if Dxtrav: + d1 = _trace_D(dg[j], p_i, Dxtrav) + if not d1: + continue + else: + if p_i != dg[j]: + continue + d1 = idn + assert d1[dg[j]] == p_i # invariant + d1 = [d1[ix] for ix in d] + h1 = [d1[g[ix]] for ix in s1] + #assert h1[b] == p_i # invariant + TAB1.append((s1, d1, h1)) + + # if TAB contains equal permutations, keep only one of them; + # if TAB contains equal permutations up to the sign, return 0 + TAB1.sort(key=lambda x: x[-1]) + nTAB1 = len(TAB1) + prev = [0] * size + while TAB1: + s, d, h = TAB1.pop() + if h[:-2] == prev[:-2]: + if h[-1] != prev[-1]: + return 0 + else: + TAB.append((s, d, h)) + prev = h + + # stabilize the SGS + sgensx = [h for h in sgensx if h[b] == b] + if b in b_S: + b_S.remove(b) + _dumx_remove(dumx, dumx_flat, p_i) + dsgsx = [] + for i in range(num_types): + dsgsx.extend(dummy_sgs(dumx[i], sym[i], num_dummies)) + return TAB[0][-1] + + +def canonical_free(base, gens, g, num_free): + """ + canonicalization of a tensor with respect to free indices + choosing the minimum with respect to lexicographical ordering + in the free indices + + ``base``, ``gens`` BSGS for slot permutation group + ``g`` permutation representing the tensor + ``num_free`` number of free indices + The indices must be ordered with first the free indices + + see explanation in double_coset_can_rep + The algorithm is a variation of the one given in [2]. + + Examples + ======== + + >>> from sympy.combinatorics import Permutation + >>> from sympy.combinatorics.tensor_can import canonical_free + >>> gens = [[1,0,2,3,5,4], [2,3,0,1,4,5],[0,1,3,2,5,4]] + >>> gens = [Permutation(h) for h in gens] + >>> base = [0, 2] + >>> g = Permutation([2, 1, 0, 3, 4, 5]) + >>> canonical_free(base, gens, g, 4) + [0, 3, 1, 2, 5, 4] + + Consider the product of Riemann tensors + ``T = R^{a}_{d0}^{d1,d2}*R_{d2,d1}^{d0,b}`` + The order of the indices is ``[a,b,d0,-d0,d1,-d1,d2,-d2]`` + The permutation corresponding to the tensor is + ``g = [0,3,4,6,7,5,2,1,8,9]`` + + In particular ``a`` is position ``0``, ``b`` is in position ``9``. + Use the slot symmetries to get `T` is a form which is the minimal + in lexicographic order in the free indices ``a`` and ``b``, e.g. + ``-R^{a}_{d0}^{d1,d2}*R^{b,d0}_{d2,d1}`` corresponding to + ``[0, 3, 4, 6, 1, 2, 7, 5, 9, 8]`` + + >>> from sympy.combinatorics.tensor_can import riemann_bsgs, tensor_gens + >>> base, gens = riemann_bsgs + >>> size, sbase, sgens = tensor_gens(base, gens, [[],[]], 0) + >>> g = Permutation([0,3,4,6,7,5,2,1,8,9]) + >>> canonical_free(sbase, [Permutation(h) for h in sgens], g, 2) + [0, 3, 4, 6, 1, 2, 7, 5, 9, 8] + """ + g = g.array_form + size = len(g) + if not base: + return g[:] + + transversals = get_transversals(base, gens) + m = len(base) + for x in sorted(g[:-2]): + if x not in base: + base.append(x) + h = g + for i, transv in enumerate(transversals): + b = base[i] + h_i = [size]*num_free + # find the element s in transversals[i] such that + # _af_rmul(h, s) has its free elements with the lowest position in h + s = None + for sk in list(transv.values()): + h1 = _af_rmul(h, sk) + hi = [h1.index(ix) for ix in range(num_free)] + if hi < h_i: + h_i = hi + s = sk + if s: + h = _af_rmul(h, s) + return h + + +def _get_map_slots(size, fixed_slots): + res = list(range(size)) + pos = 0 + for i in range(size): + if i in fixed_slots: + continue + res[i] = pos + pos += 1 + return res + + +def _lift_sgens(size, fixed_slots, free, s): + a = [] + j = k = 0 + fd = list(zip(fixed_slots, free)) + fd = [y for x, y in sorted(fd)] + num_free = len(free) + for i in range(size): + if i in fixed_slots: + a.append(fd[k]) + k += 1 + else: + a.append(s[j] + num_free) + j += 1 + return a + + +def canonicalize(g, dummies, msym, *v): + """ + canonicalize tensor formed by tensors + + Parameters + ========== + + g : permutation representing the tensor + + dummies : list representing the dummy indices + it can be a list of dummy indices of the same type + or a list of lists of dummy indices, one list for each + type of index; + the dummy indices must come after the free indices, + and put in order contravariant, covariant + [d0, -d0, d1,-d1,...] + msym : symmetry of the metric(s) + it can be an integer or a list; + in the first case it is the symmetry of the dummy index metric; + in the second case it is the list of the symmetries of the + index metric for each type + v : list, (base_i, gens_i, n_i, sym_i) for tensors of type `i` + + base_i, gens_i : BSGS for tensors of this type. + The BSGS should have minimal base under lexicographic ordering; + if not, an attempt is made do get the minimal BSGS; + in case of failure, + canonicalize_naive is used, which is much slower. + + n_i : number of tensors of type `i`. + + sym_i : symmetry under exchange of component tensors of type `i`. + + Both for msym and sym_i the cases are + * None no symmetry + * 0 commuting + * 1 anticommuting + + Returns + ======= + + 0 if the tensor is zero, else return the array form of + the permutation representing the canonical form of the tensor. + + Algorithm + ========= + + First one uses canonical_free to get the minimum tensor under + lexicographic order, using only the slot symmetries. + If the component tensors have not minimal BSGS, it is attempted + to find it; if the attempt fails canonicalize_naive + is used instead. + + Compute the residual slot symmetry keeping fixed the free indices + using tensor_gens(base, gens, list_free_indices, sym). + + Reduce the problem eliminating the free indices. + + Then use double_coset_can_rep and lift back the result reintroducing + the free indices. + + Examples + ======== + + one type of index with commuting metric; + + `A_{a b}` and `B_{a b}` antisymmetric and commuting + + `T = A_{d0 d1} * B^{d0}{}_{d2} * B^{d2 d1}` + + `ord = [d0,-d0,d1,-d1,d2,-d2]` order of the indices + + g = [1,3,0,5,4,2,6,7] + + `T_c = 0` + + >>> from sympy.combinatorics.tensor_can import get_symmetric_group_sgs, canonicalize, bsgs_direct_product + >>> from sympy.combinatorics import Permutation + >>> base2a, gens2a = get_symmetric_group_sgs(2, 1) + >>> t0 = (base2a, gens2a, 1, 0) + >>> t1 = (base2a, gens2a, 2, 0) + >>> g = Permutation([1,3,0,5,4,2,6,7]) + >>> canonicalize(g, list(range(6)), 0, t0, t1) + 0 + + same as above, but with `B_{a b}` anticommuting + + `T_c = -A^{d0 d1} * B_{d0}{}^{d2} * B_{d1 d2}` + + can = [0,2,1,4,3,5,7,6] + + >>> t1 = (base2a, gens2a, 2, 1) + >>> canonicalize(g, list(range(6)), 0, t0, t1) + [0, 2, 1, 4, 3, 5, 7, 6] + + two types of indices `[a,b,c,d,e,f]` and `[m,n]`, in this order, + both with commuting metric + + `f^{a b c}` antisymmetric, commuting + + `A_{m a}` no symmetry, commuting + + `T = f^c{}_{d a} * f^f{}_{e b} * A_m{}^d * A^{m b} * A_n{}^a * A^{n e}` + + ord = [c,f,a,-a,b,-b,d,-d,e,-e,m,-m,n,-n] + + g = [0,7,3, 1,9,5, 11,6, 10,4, 13,2, 12,8, 14,15] + + The canonical tensor is + `T_c = -f^{c a b} * f^{f d e} * A^m{}_a * A_{m d} * A^n{}_b * A_{n e}` + + can = [0,2,4, 1,6,8, 10,3, 11,7, 12,5, 13,9, 15,14] + + >>> base_f, gens_f = get_symmetric_group_sgs(3, 1) + >>> base1, gens1 = get_symmetric_group_sgs(1) + >>> base_A, gens_A = bsgs_direct_product(base1, gens1, base1, gens1) + >>> t0 = (base_f, gens_f, 2, 0) + >>> t1 = (base_A, gens_A, 4, 0) + >>> dummies = [list(range(2, 10)), list(range(10, 14))] + >>> g = Permutation([0,7,3,1,9,5,11,6,10,4,13,2,12,8,14,15]) + >>> canonicalize(g, dummies, [0, 0], t0, t1) + [0, 2, 4, 1, 6, 8, 10, 3, 11, 7, 12, 5, 13, 9, 15, 14] + """ + from sympy.combinatorics.testutil import canonicalize_naive + if not isinstance(msym, list): + if not msym in [0, 1, None]: + raise ValueError('msym must be 0, 1 or None') + num_types = 1 + else: + num_types = len(msym) + if not all(msymx in [0, 1, None] for msymx in msym): + raise ValueError('msym entries must be 0, 1 or None') + if len(dummies) != num_types: + raise ValueError( + 'dummies and msym must have the same number of elements') + size = g.size + num_tensors = 0 + v1 = [] + for i in range(len(v)): + base_i, gens_i, n_i, sym_i = v[i] + # check that the BSGS is minimal; + # this property is used in double_coset_can_rep; + # if it is not minimal use canonicalize_naive + if not _is_minimal_bsgs(base_i, gens_i): + mbsgs = get_minimal_bsgs(base_i, gens_i) + if not mbsgs: + can = canonicalize_naive(g, dummies, msym, *v) + return can + base_i, gens_i = mbsgs + v1.append((base_i, gens_i, [[]] * n_i, sym_i)) + num_tensors += n_i + + if num_types == 1 and not isinstance(msym, list): + dummies = [dummies] + msym = [msym] + flat_dummies = [] + for dumx in dummies: + flat_dummies.extend(dumx) + + if flat_dummies and flat_dummies != list(range(flat_dummies[0], flat_dummies[-1] + 1)): + raise ValueError('dummies is not valid') + + # slot symmetry of the tensor + size1, sbase, sgens = gens_products(*v1) + if size != size1: + raise ValueError( + 'g has size %d, generators have size %d' % (size, size1)) + free = [i for i in range(size - 2) if i not in flat_dummies] + num_free = len(free) + + # g1 minimal tensor under slot symmetry + g1 = canonical_free(sbase, sgens, g, num_free) + if not flat_dummies: + return g1 + # save the sign of g1 + sign = 0 if g1[-1] == size - 1 else 1 + + # the free indices are kept fixed. + # Determine free_i, the list of slots of tensors which are fixed + # since they are occupied by free indices, which are fixed. + start = 0 + for i in range(len(v)): + free_i = [] + base_i, gens_i, n_i, sym_i = v[i] + len_tens = gens_i[0].size - 2 + # for each component tensor get a list od fixed islots + for j in range(n_i): + # get the elements corresponding to the component tensor + h = g1[start:(start + len_tens)] + fr = [] + # get the positions of the fixed elements in h + for k in free: + if k in h: + fr.append(h.index(k)) + free_i.append(fr) + start += len_tens + v1[i] = (base_i, gens_i, free_i, sym_i) + # BSGS of the tensor with fixed free indices + # if tensor_gens fails in gens_product, use canonicalize_naive + size, sbase, sgens = gens_products(*v1) + + # reduce the permutations getting rid of the free indices + pos_dummies = [g1.index(x) for x in flat_dummies] + pos_free = [g1.index(x) for x in range(num_free)] + size_red = size - num_free + g1_red = [x - num_free for x in g1 if x in flat_dummies] + if sign: + g1_red.extend([size_red - 1, size_red - 2]) + else: + g1_red.extend([size_red - 2, size_red - 1]) + map_slots = _get_map_slots(size, pos_free) + sbase_red = [map_slots[i] for i in sbase if i not in pos_free] + sgens_red = [_af_new([map_slots[i] for i in y._array_form if i not in pos_free]) for y in sgens] + dummies_red = [[x - num_free for x in y] for y in dummies] + transv_red = get_transversals(sbase_red, sgens_red) + g1_red = _af_new(g1_red) + g2 = double_coset_can_rep( + dummies_red, msym, sbase_red, sgens_red, transv_red, g1_red) + if g2 == 0: + return 0 + # lift to the case with the free indices + g3 = _lift_sgens(size, pos_free, free, g2) + return g3 + + +def perm_af_direct_product(gens1, gens2, signed=True): + """ + direct products of the generators gens1 and gens2 + + Examples + ======== + + >>> from sympy.combinatorics.tensor_can import perm_af_direct_product + >>> gens1 = [[1,0,2,3], [0,1,3,2]] + >>> gens2 = [[1,0]] + >>> perm_af_direct_product(gens1, gens2, False) + [[1, 0, 2, 3, 4, 5], [0, 1, 3, 2, 4, 5], [0, 1, 2, 3, 5, 4]] + >>> gens1 = [[1,0,2,3,5,4], [0,1,3,2,4,5]] + >>> gens2 = [[1,0,2,3]] + >>> perm_af_direct_product(gens1, gens2, True) + [[1, 0, 2, 3, 4, 5, 7, 6], [0, 1, 3, 2, 4, 5, 6, 7], [0, 1, 2, 3, 5, 4, 6, 7]] + """ + gens1 = [list(x) for x in gens1] + gens2 = [list(x) for x in gens2] + s = 2 if signed else 0 + n1 = len(gens1[0]) - s + n2 = len(gens2[0]) - s + start = list(range(n1)) + end = list(range(n1, n1 + n2)) + if signed: + gens1 = [gen[:-2] + end + [gen[-2] + n2, gen[-1] + n2] + for gen in gens1] + gens2 = [start + [x + n1 for x in gen] for gen in gens2] + else: + gens1 = [gen + end for gen in gens1] + gens2 = [start + [x + n1 for x in gen] for gen in gens2] + + res = gens1 + gens2 + + return res + + +def bsgs_direct_product(base1, gens1, base2, gens2, signed=True): + """ + direct product of two BSGS + + base1 base of the first BSGS. + + gens1 strong generating sequence of the first BSGS. + + base2, gens2 similarly for the second BSGS. + + signed flag for signed permutations. + + Examples + ======== + + >>> from sympy.combinatorics import Permutation + >>> from sympy.combinatorics.tensor_can import (get_symmetric_group_sgs, bsgs_direct_product) + >>> Permutation.print_cyclic = True + >>> base1, gens1 = get_symmetric_group_sgs(1) + >>> base2, gens2 = get_symmetric_group_sgs(2) + >>> bsgs_direct_product(base1, gens1, base2, gens2) + ([1], [Permutation(4)(1, 2)]) + """ + s = 2 if signed else 0 + n1 = gens1[0].size - s + base = base1[:] + base += [x + n1 for x in base2] + gens1 = [h._array_form for h in gens1] + gens2 = [h._array_form for h in gens2] + gens = perm_af_direct_product(gens1, gens2, signed) + size = len(gens[0]) + id_af = list(range(size)) + gens = [h for h in gens if h != id_af] + if not gens: + gens = [id_af] + return base, [_af_new(h) for h in gens] + + +def get_symmetric_group_sgs(n, antisym=False): + """ + Return base, gens of the minimal BSGS for (anti)symmetric tensor + + ``n`` rank of the tensor + + ``antisym = False`` symmetric tensor + ``antisym = True`` antisymmetric tensor + + Examples + ======== + + >>> from sympy.combinatorics import Permutation + >>> from sympy.combinatorics.tensor_can import get_symmetric_group_sgs + >>> Permutation.print_cyclic = True + >>> get_symmetric_group_sgs(3) + ([0, 1], [Permutation(4)(0, 1), Permutation(4)(1, 2)]) + """ + if n == 1: + return [], [_af_new(list(range(3)))] + gens = [Permutation(n - 1)(i, i + 1)._array_form for i in range(n - 1)] + if antisym == 0: + gens = [x + [n, n + 1] for x in gens] + else: + gens = [x + [n + 1, n] for x in gens] + base = list(range(n - 1)) + return base, [_af_new(h) for h in gens] + +riemann_bsgs = [0, 2], [Permutation(0, 1)(4, 5), Permutation(2, 3)(4, 5), + Permutation(5)(0, 2)(1, 3)] + + +def get_transversals(base, gens): + """ + Return transversals for the group with BSGS base, gens + """ + if not base: + return [] + stabs = _distribute_gens_by_base(base, gens) + orbits, transversals = _orbits_transversals_from_bsgs(base, stabs) + transversals = [dict((x, h._array_form) for x, h in list(y.items())) for y in + transversals] + return transversals + + +def _is_minimal_bsgs(base, gens): + """ + Check if the BSGS has minimal base under lexigographic order. + + base, gens BSGS + + Examples + ======== + + >>> from sympy.combinatorics import Permutation + >>> from sympy.combinatorics.tensor_can import riemann_bsgs, _is_minimal_bsgs + >>> _is_minimal_bsgs(*riemann_bsgs) + True + >>> riemann_bsgs1 = ([2, 0], ([Permutation(5)(0,1)(4,5), Permutation(5)(0,2)(1,3)])) + >>> _is_minimal_bsgs(*riemann_bsgs1) + False + """ + base1 = [] + sgs1 = gens[:] + size = gens[0].size + for i in range(size): + if not all(h._array_form[i] == i for h in sgs1): + base1.append(i) + sgs1 = [h for h in sgs1 if h._array_form[i] == i] + return base1 == base + + +def get_minimal_bsgs(base, gens): + """ + Compute a minimal GSGS + + base, gens BSGS + + If base, gens is a minimal BSGS return it; else return a minimal BSGS + if it fails in finding one, it returns None + + TODO: use baseswap in the case in which if it fails in finding a + minimal BSGS + + Examples + ======== + + >>> from sympy.combinatorics import Permutation + >>> from sympy.combinatorics.tensor_can import get_minimal_bsgs + >>> Permutation.print_cyclic = True + >>> riemann_bsgs1 = ([2, 0], ([Permutation(5)(0,1)(4,5), Permutation(5)(0,2)(1,3)])) + >>> get_minimal_bsgs(*riemann_bsgs1) + ([0, 2], [Permutation(0, 1)(4, 5), Permutation(5)(0, 2)(1, 3), Permutation(2, 3)(4, 5)]) + """ + G = PermutationGroup(gens) + base, gens = G.schreier_sims_incremental() + if not _is_minimal_bsgs(base, gens): + return None + return base, gens + + +def tensor_gens(base, gens, list_free_indices, sym=0): + """ + Returns size, res_base, res_gens BSGS for n tensors of the same type + + base, gens BSGS for tensors of this type + list_free_indices list of the slots occupied by fixed indices + for each of the tensors + + sym symmetry under commutation of two tensors + sym None no symmetry + sym 0 commuting + sym 1 anticommuting + + Examples + ======== + + >>> from sympy.combinatorics import Permutation + >>> from sympy.combinatorics.tensor_can import tensor_gens, get_symmetric_group_sgs + >>> Permutation.print_cyclic = True + + two symmetric tensors with 3 indices without free indices + >>> base, gens = get_symmetric_group_sgs(3) + >>> tensor_gens(base, gens, [[], []]) + (8, [0, 1, 3, 4], [Permutation(7)(0, 1), Permutation(7)(1, 2), Permutation(7)(3, 4), Permutation(7)(4, 5), Permutation(7)(0, 3)(1, 4)(2, 5)]) + + two symmetric tensors with 3 indices with free indices in slot 1 and 0 + >>> tensor_gens(base, gens, [[1],[0]]) + (8, [0, 4], [Permutation(7)(0, 2), Permutation(7)(4, 5)]) + + four symmetric tensors with 3 indices, two of which with free indices + + """ + def _get_bsgs(G, base, gens, free_indices): + """ + return the BSGS for G.pointwise_stabilizer(free_indices) + """ + if not free_indices: + return base[:], gens[:] + else: + H = G.pointwise_stabilizer(free_indices) + base, sgs = H.schreier_sims_incremental() + return base, sgs + + # if not base there is no slot symmetry for the component tensors + # if list_free_indices.count([]) < 2 there is no commutation symmetry + # so there is no resulting slot symmetry + if not base and list_free_indices.count([]) < 2: + n = len(list_free_indices) + size = gens[0].size + size = n * (gens[0].size - 2) + 2 + return size, [], [_af_new(list(range(size)))] + + # if any(list_free_indices) one needs to compute the pointwise + # stabilizer, so G is needed + if any(list_free_indices): + G = PermutationGroup(gens) + else: + G = None + + # no_free list of lists of indices for component tensors without fixed + # indices + no_free = [] + size = gens[0].size + id_af = list(range(size)) + num_indices = size - 2 + if not list_free_indices[0]: + no_free.append(list(range(num_indices))) + res_base, res_gens = _get_bsgs(G, base, gens, list_free_indices[0]) + for i in range(1, len(list_free_indices)): + base1, gens1 = _get_bsgs(G, base, gens, list_free_indices[i]) + res_base, res_gens = bsgs_direct_product(res_base, res_gens, + base1, gens1, 1) + if not list_free_indices[i]: + no_free.append(list(range(size - 2, size - 2 + num_indices))) + size += num_indices + nr = size - 2 + res_gens = [h for h in res_gens if h._array_form != id_af] + # if sym there are no commuting tensors stop here + if sym is None or not no_free: + if not res_gens: + res_gens = [_af_new(id_af)] + return size, res_base, res_gens + + # if the component tensors have moinimal BSGS, so is their direct + # product P; the slot symmetry group is S = P*C, where C is the group + # to (anti)commute the component tensors with no free indices + # a stabilizer has the property S_i = P_i*C_i; + # the BSGS of P*C has SGS_P + SGS_C and the base is + # the ordered union of the bases of P and C. + # If P has minimal BSGS, so has S with this base. + base_comm = [] + for i in range(len(no_free) - 1): + ind1 = no_free[i] + ind2 = no_free[i + 1] + a = list(range(ind1[0])) + a.extend(ind2) + a.extend(ind1) + base_comm.append(ind1[0]) + a.extend(list(range(ind2[-1] + 1, nr))) + if sym == 0: + a.extend([nr, nr + 1]) + else: + a.extend([nr + 1, nr]) + res_gens.append(_af_new(a)) + # each base is ordered; order the union of the two bases + for i in base_comm: + if i not in res_base: + res_base.append(i) + res_base.sort() + if not res_gens: + res_gens = [_af_new(id_af)] + + return size, res_base, res_gens + + +def gens_products(*v): + """ + Returns size, res_base, res_gens BSGS for n tensors of different types + + v is a sequence of (base_i, gens_i, free_i, sym_i) + where + base_i, gens_i BSGS of tensor of type `i` + free_i list of the fixed slots for each of the tensors + of type `i`; if there are `n_i` tensors of type `i` + and none of them have fixed slots, `free = [[]]*n_i` + sym 0 (1) if the tensors of type `i` (anti)commute among themselves + + Examples + ======== + + >>> from sympy.combinatorics import Permutation + >>> from sympy.combinatorics.tensor_can import get_symmetric_group_sgs, gens_products + >>> Permutation.print_cyclic = True + >>> base, gens = get_symmetric_group_sgs(2) + >>> gens_products((base,gens,[[],[]],0)) + (6, [0, 2], [Permutation(5)(0, 1), Permutation(5)(2, 3), Permutation(5)(0, 2)(1, 3)]) + >>> gens_products((base,gens,[[1],[]],0)) + (6, [2], [Permutation(5)(2, 3)]) + """ + res_size, res_base, res_gens = tensor_gens(*v[0]) + for i in range(1, len(v)): + size, base, gens = tensor_gens(*v[i]) + res_base, res_gens = bsgs_direct_product(res_base, res_gens, base, + gens, 1) + res_size = res_gens[0].size + id_af = list(range(res_size)) + res_gens = [h for h in res_gens if h != id_af] + if not res_gens: + res_gens = [id_af] + return res_size, res_base, res_gens diff -Nru python3-sympy-0.7.2/sympy/combinatorics/tests/test_generators.py python3-sympy-0.7.3/sympy/combinatorics/tests/test_generators.py --- python3-sympy-0.7.2/sympy/combinatorics/tests/test_generators.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/combinatorics/tests/test_generators.py 2013-07-13 17:53:31.000000000 +0000 @@ -1,101 +1,102 @@ from sympy.combinatorics.generators import symmetric, cyclic, alternating, dihedral from sympy.combinatorics.permutations import Permutation + def test_generators(): assert list(cyclic(6)) == [ - Permutation([0, 1, 2, 3, 4, 5]), - Permutation([1, 2, 3, 4, 5, 0]), - Permutation([2, 3, 4, 5, 0, 1]), - Permutation([3, 4, 5, 0, 1, 2]), - Permutation([4, 5, 0, 1, 2, 3]), - Permutation([5, 0, 1, 2, 3, 4])] + Permutation([0, 1, 2, 3, 4, 5]), + Permutation([1, 2, 3, 4, 5, 0]), + Permutation([2, 3, 4, 5, 0, 1]), + Permutation([3, 4, 5, 0, 1, 2]), + Permutation([4, 5, 0, 1, 2, 3]), + Permutation([5, 0, 1, 2, 3, 4])] assert list(cyclic(10)) == [ - Permutation([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]), - Permutation([1, 2, 3, 4, 5, 6, 7, 8, 9, 0]), - Permutation([2, 3, 4, 5, 6, 7, 8, 9, 0, 1]), - Permutation([3, 4, 5, 6, 7, 8, 9, 0, 1, 2]), - Permutation([4, 5, 6, 7, 8, 9, 0, 1, 2, 3]), - Permutation([5, 6, 7, 8, 9, 0, 1, 2, 3, 4]), - Permutation([6, 7, 8, 9, 0, 1, 2, 3, 4, 5]), - Permutation([7, 8, 9, 0, 1, 2, 3, 4, 5, 6]), - Permutation([8, 9, 0, 1, 2, 3, 4, 5, 6, 7]), - Permutation([9, 0, 1, 2, 3, 4, 5, 6, 7, 8])] + Permutation([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]), + Permutation([1, 2, 3, 4, 5, 6, 7, 8, 9, 0]), + Permutation([2, 3, 4, 5, 6, 7, 8, 9, 0, 1]), + Permutation([3, 4, 5, 6, 7, 8, 9, 0, 1, 2]), + Permutation([4, 5, 6, 7, 8, 9, 0, 1, 2, 3]), + Permutation([5, 6, 7, 8, 9, 0, 1, 2, 3, 4]), + Permutation([6, 7, 8, 9, 0, 1, 2, 3, 4, 5]), + Permutation([7, 8, 9, 0, 1, 2, 3, 4, 5, 6]), + Permutation([8, 9, 0, 1, 2, 3, 4, 5, 6, 7]), + Permutation([9, 0, 1, 2, 3, 4, 5, 6, 7, 8])] assert list(alternating(4)) == [ - Permutation([0, 1, 2, 3]), - Permutation([0, 2, 3, 1]), - Permutation([0, 3, 1, 2]), - Permutation([1, 0, 3, 2]), - Permutation([1, 2, 0, 3]), - Permutation([1, 3, 2, 0]), - Permutation([2, 0, 1, 3]), - Permutation([2, 1, 3, 0]), - Permutation([2, 3, 0, 1]), - Permutation([3, 0, 2, 1]), - Permutation([3, 1, 0, 2]), - Permutation([3, 2, 1, 0])] + Permutation([0, 1, 2, 3]), + Permutation([0, 2, 3, 1]), + Permutation([0, 3, 1, 2]), + Permutation([1, 0, 3, 2]), + Permutation([1, 2, 0, 3]), + Permutation([1, 3, 2, 0]), + Permutation([2, 0, 1, 3]), + Permutation([2, 1, 3, 0]), + Permutation([2, 3, 0, 1]), + Permutation([3, 0, 2, 1]), + Permutation([3, 1, 0, 2]), + Permutation([3, 2, 1, 0])] assert list(symmetric(3)) == [ - Permutation([0, 1, 2]), - Permutation([0, 2, 1]), - Permutation([1, 0, 2]), - Permutation([1, 2, 0]), - Permutation([2, 0, 1]), - Permutation([2, 1, 0])] + Permutation([0, 1, 2]), + Permutation([0, 2, 1]), + Permutation([1, 0, 2]), + Permutation([1, 2, 0]), + Permutation([2, 0, 1]), + Permutation([2, 1, 0])] assert list(symmetric(4)) == [ - Permutation([0, 1, 2, 3]), - Permutation([0, 1, 3, 2]), - Permutation([0, 2, 1, 3]), - Permutation([0, 2, 3, 1]), - Permutation([0, 3, 1, 2]), - Permutation([0, 3, 2, 1]), - Permutation([1, 0, 2, 3]), - Permutation([1, 0, 3, 2]), - Permutation([1, 2, 0, 3]), - Permutation([1, 2, 3, 0]), - Permutation([1, 3, 0, 2]), - Permutation([1, 3, 2, 0]), - Permutation([2, 0, 1, 3]), - Permutation([2, 0, 3, 1]), - Permutation([2, 1, 0, 3]), - Permutation([2, 1, 3, 0]), - Permutation([2, 3, 0, 1]), - Permutation([2, 3, 1, 0]), - Permutation([3, 0, 1, 2]), - Permutation([3, 0, 2, 1]), - Permutation([3, 1, 0, 2]), - Permutation([3, 1, 2, 0]), - Permutation([3, 2, 0, 1]), - Permutation([3, 2, 1, 0])] + Permutation([0, 1, 2, 3]), + Permutation([0, 1, 3, 2]), + Permutation([0, 2, 1, 3]), + Permutation([0, 2, 3, 1]), + Permutation([0, 3, 1, 2]), + Permutation([0, 3, 2, 1]), + Permutation([1, 0, 2, 3]), + Permutation([1, 0, 3, 2]), + Permutation([1, 2, 0, 3]), + Permutation([1, 2, 3, 0]), + Permutation([1, 3, 0, 2]), + Permutation([1, 3, 2, 0]), + Permutation([2, 0, 1, 3]), + Permutation([2, 0, 3, 1]), + Permutation([2, 1, 0, 3]), + Permutation([2, 1, 3, 0]), + Permutation([2, 3, 0, 1]), + Permutation([2, 3, 1, 0]), + Permutation([3, 0, 1, 2]), + Permutation([3, 0, 2, 1]), + Permutation([3, 1, 0, 2]), + Permutation([3, 1, 2, 0]), + Permutation([3, 2, 0, 1]), + Permutation([3, 2, 1, 0])] assert list(dihedral(1)) == [ - Permutation([0, 1]), Permutation([1, 0])] + Permutation([0, 1]), Permutation([1, 0])] assert list(dihedral(2)) == [ - Permutation([0, 1, 2, 3]), - Permutation([1, 0, 3, 2]), - Permutation([2, 3, 0, 1]), - Permutation([3, 2, 1, 0])] + Permutation([0, 1, 2, 3]), + Permutation([1, 0, 3, 2]), + Permutation([2, 3, 0, 1]), + Permutation([3, 2, 1, 0])] assert list(dihedral(3)) == [ - Permutation([0, 1, 2]), - Permutation([2, 1, 0]), - Permutation([1, 2, 0]), - Permutation([0, 2, 1]), - Permutation([2, 0, 1]), - Permutation([1, 0, 2])] + Permutation([0, 1, 2]), + Permutation([2, 1, 0]), + Permutation([1, 2, 0]), + Permutation([0, 2, 1]), + Permutation([2, 0, 1]), + Permutation([1, 0, 2])] assert list(dihedral(5)) == [ - Permutation([0, 1, 2, 3, 4]), - Permutation([4, 3, 2, 1, 0]), - Permutation([1, 2, 3, 4, 0]), - Permutation([0, 4, 3, 2, 1]), - Permutation([2, 3, 4, 0, 1]), - Permutation([1, 0, 4, 3, 2]), - Permutation([3, 4, 0, 1, 2]), - Permutation([2, 1, 0, 4, 3]), - Permutation([4, 0, 1, 2, 3]), - Permutation([3, 2, 1, 0, 4])] + Permutation([0, 1, 2, 3, 4]), + Permutation([4, 3, 2, 1, 0]), + Permutation([1, 2, 3, 4, 0]), + Permutation([0, 4, 3, 2, 1]), + Permutation([2, 3, 4, 0, 1]), + Permutation([1, 0, 4, 3, 2]), + Permutation([3, 4, 0, 1, 2]), + Permutation([2, 1, 0, 4, 3]), + Permutation([4, 0, 1, 2, 3]), + Permutation([3, 2, 1, 0, 4])] diff -Nru python3-sympy-0.7.2/sympy/combinatorics/tests/test_graycode.py python3-sympy-0.7.3/sympy/combinatorics/tests/test_graycode.py --- python3-sympy-0.7.2/sympy/combinatorics/tests/test_graycode.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/combinatorics/tests/test_graycode.py 2013-07-13 17:53:31.000000000 +0000 @@ -1,8 +1,9 @@ from sympy.combinatorics.graycode import (GrayCode, bin_to_gray, random_bitstring, get_subset_from_bitstring, graycode_subsets) + def test_graycode(): - g=GrayCode(2) + g = GrayCode(2) got = [] for i in g.generate_gray(): if i.startswith('0'): @@ -22,7 +23,8 @@ '101100', '100100', '100101', '100111', '100110', '100010', '100011', '100001', '100000'] assert list(a.generate_gray(start='011001')) == codes - assert list(a.generate_gray(rank=GrayCode(6, start='011001').rank)) == codes + assert list( + a.generate_gray(rank=GrayCode(6, start='011001').rank)) == codes assert a.next().current == '000001' assert a.next(2).current == '000011' assert a.next(-1).current == '100000' @@ -34,8 +36,8 @@ assert GrayCode(6, rank=4).current == '000110' assert GrayCode(6, rank=4).rank == 4 - assert [GrayCode(4, start=s).rank for s in \ - GrayCode(4).generate_gray()] == [0, 1, 2, 3, 4, 5, 6, 7, 8, \ + assert [GrayCode(4, start=s).rank for s in + GrayCode(4).generate_gray()] == [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15] a = GrayCode(15, rank=15) assert a.current == '000000000001000' @@ -47,8 +49,9 @@ assert len(a) == 5 assert all(i in ['0', '1'] for i in a) - assert get_subset_from_bitstring(['a','b','c','d'], '0011') == ['c', 'd'] - assert get_subset_from_bitstring('abcd','1001') == ['a', 'd'] - assert list(graycode_subsets(['a','b','c'])) == \ - [[], ['c'], ['b', 'c'], ['b'], ['a', 'b'], ['a', 'b', 'c'], \ + assert get_subset_from_bitstring( + ['a', 'b', 'c', 'd'], '0011') == ['c', 'd'] + assert get_subset_from_bitstring('abcd', '1001') == ['a', 'd'] + assert list(graycode_subsets(['a', 'b', 'c'])) == \ + [[], ['c'], ['b', 'c'], ['b'], ['a', 'b'], ['a', 'b', 'c'], ['a', 'c'], ['a']] diff -Nru python3-sympy-0.7.2/sympy/combinatorics/tests/test_group_constructs.py python3-sympy-0.7.3/sympy/combinatorics/tests/test_group_constructs.py --- python3-sympy-0.7.2/sympy/combinatorics/tests/test_group_constructs.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/combinatorics/tests/test_group_constructs.py 2013-07-13 17:53:31.000000000 +0000 @@ -1,6 +1,7 @@ from sympy.combinatorics.group_constructs import DirectProduct from sympy.combinatorics.named_groups import CyclicGroup, DihedralGroup + def test_direct_product_n(): C = CyclicGroup(4) D = DihedralGroup(4) @@ -8,7 +9,7 @@ assert G.order() == 64 assert G.degree == 12 assert len(G.orbits()) == 3 - assert G.is_abelian == True + assert G.is_abelian is True H = DirectProduct(D, C) assert H.order() == 32 - assert H.is_abelian == False + assert H.is_abelian is False diff -Nru python3-sympy-0.7.2/sympy/combinatorics/tests/test_named_groups.py python3-sympy-0.7.3/sympy/combinatorics/tests/test_named_groups.py --- python3-sympy-0.7.2/sympy/combinatorics/tests/test_named_groups.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/combinatorics/tests/test_named_groups.py 2013-07-13 17:53:31.000000000 +0000 @@ -1,41 +1,51 @@ from sympy.combinatorics.named_groups import (SymmetricGroup, CyclicGroup, DihedralGroup, AlternatingGroup, AbelianGroup) + def test_SymmetricGroup(): G = SymmetricGroup(5) elements = list(G.generate()) assert (G.generators[0]).size == 5 assert len(elements) == 120 - assert G.is_solvable == False - assert G.is_abelian == False - assert G.is_transitive() == True + assert G.is_solvable is False + assert G.is_abelian is False + assert G.is_nilpotent is False + assert G.is_transitive() is True H = SymmetricGroup(1) assert H.order() == 1 L = SymmetricGroup(2) assert L.order() == 2 + def test_CyclicGroup(): G = CyclicGroup(10) elements = list(G.generate()) assert len(elements) == 10 assert (G.derived_subgroup()).order() == 1 - assert G.is_abelian == True + assert G.is_abelian is True + assert G.is_solvable is True + assert G.is_nilpotent is True H = CyclicGroup(1) assert H.order() == 1 L = CyclicGroup(2) assert L.order() == 2 + def test_DihedralGroup(): G = DihedralGroup(6) elements = list(G.generate()) assert len(elements) == 12 - assert G.is_transitive() == True - assert G.is_abelian == False + assert G.is_transitive() is True + assert G.is_abelian is False + assert G.is_solvable is True + assert G.is_nilpotent is False H = DihedralGroup(1) assert H.order() == 2 L = DihedralGroup(2) assert L.order() == 4 - assert L.is_abelian == True + assert L.is_abelian is True + assert L.is_nilpotent is True + def test_AlternatingGroup(): G = AlternatingGroup(5) @@ -47,7 +57,8 @@ L = AlternatingGroup(2) assert L.order() == 1 + def test_AbelianGroup(): A = AbelianGroup(3, 3, 3) assert A.order() == 27 - assert A.is_abelian == True + assert A.is_abelian is True diff -Nru python3-sympy-0.7.2/sympy/combinatorics/tests/test_partitions.py python3-sympy-0.7.3/sympy/combinatorics/tests/test_partitions.py --- python3-sympy-0.7.2/sympy/combinatorics/tests/test_partitions.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/combinatorics/tests/test_partitions.py 2013-07-13 17:53:31.000000000 +0000 @@ -4,14 +4,15 @@ from sympy.utilities.pytest import raises from sympy.utilities.iterables import default_sort_key, partitions + def test_partition(): from sympy.abc import x raises(ValueError, lambda: Partition(list(range(3)))) raises(ValueError, lambda: Partition([[1, 1, 2]])) - a = Partition([[1,2,3], [4]]) - b = Partition([[1,2], [3,4]]) + a = Partition([[1, 2, 3], [4]]) + b = Partition([[1, 2], [3, 4]]) c = Partition([[x]]) l = [a, b, c] l.sort(key=default_sort_key) @@ -19,9 +20,9 @@ l.sort(key=lambda w: default_sort_key(w, order='rev-lex')) assert l == [c, a, b] - assert (a == b) == False + assert (a == b) is False assert a <= b - assert (a > b) == False + assert (a > b) is False assert a != b assert (a + 2).partition == [[1, 2], [3, 4]] @@ -43,16 +44,16 @@ raises(ValueError, lambda: IntegerPartition(list(range(3)))) # check fails since 1 + 2 != 100 raises(ValueError, lambda: IntegerPartition(100, list(range(1, 3)))) - a = IntegerPartition(8, [1,3,4]) + a = IntegerPartition(8, [1, 3, 4]) b = a.next_lex() - c = IntegerPartition([1,3,4]) - d = IntegerPartition(8, {1:3, 3:1, 2:1}) + c = IntegerPartition([1, 3, 4]) + d = IntegerPartition(8, {1: 3, 3: 1, 2: 1}) assert a == c assert a.integer == d.integer assert a.conjugate == [3, 2, 2, 1] - assert (a == b) == False + assert (a == b) is False assert a <= b - assert (a > b) == False + assert (a > b) is False assert a != b for i in range(1, 11): @@ -64,11 +65,11 @@ for j in range(n): next.add(a) a = a.next_lex() - IntegerPartition(i, a.partition) # check it by giving i + IntegerPartition(i, a.partition) # check it by giving i for j in range(n): prev.add(a) a = a.prev_lex() - IntegerPartition(i, a.partition) # check it by giving i + IntegerPartition(i, a.partition) # check it by giving i assert next == ans assert prev == ans @@ -79,9 +80,10 @@ raises(ValueError, lambda: random_integer_partition(-1)) assert random_integer_partition(1) == [1] - assert random_integer_partition(10, seed=[1,3,2,1,5,1] + assert random_integer_partition(10, seed=[1, 3, 2, 1, 5, 1] ) == [5, 2, 1, 1, 1] + def test_rgs(): raises(ValueError, lambda: RGS_unrank(-1, 3)) raises(ValueError, lambda: RGS_unrank(3, 0)) diff -Nru python3-sympy-0.7.2/sympy/combinatorics/tests/test_perm_groups.py python3-sympy-0.7.3/sympy/combinatorics/tests/test_perm_groups.py --- python3-sympy-0.7.2/sympy/combinatorics/tests/test_perm_groups.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/combinatorics/tests/test_perm_groups.py 2013-07-13 17:53:31.000000000 +0000 @@ -6,21 +6,22 @@ from sympy.combinatorics.generators import rubik_cube_generators from sympy.combinatorics.polyhedron import tetrahedron as Tetra, cube from sympy.combinatorics.testutil import _verify_bsgs, _verify_centralizer,\ - _verify_normal_closure + _verify_normal_closure rmul = Permutation.rmul + def test_has(): # return p in self.generators a = Permutation([1, 0]) - G = PermutationGroup([a]) + G = PermutationGroup([a]) assert G.is_abelian a = Permutation([2, 0, 1]) b = Permutation([2, 1, 0]) - G = PermutationGroup([a, b]) + G = PermutationGroup([a, b]) assert not G.is_abelian - G = PermutationGroup([a]) + G = PermutationGroup([a]) assert G.has(a) assert not G.has(b) @@ -29,11 +30,12 @@ assert PermutationGroup(a, b).degree == \ PermutationGroup(a, b).degree == 6 + def test_generate(): a = Permutation([1, 0]) g = list(PermutationGroup([a]).generate()) assert g == [Permutation([0, 1]), Permutation([1, 0])] - assert len(list(PermutationGroup(Permutation((0,1))).generate())) == 1 + assert len(list(PermutationGroup(Permutation((0, 1))).generate())) == 1 g = PermutationGroup([a]).generate(method='dimino') assert list(g) == [Permutation([0, 1]), Permutation([1, 0])] a = Permutation([2, 0, 1]) @@ -42,7 +44,8 @@ g = G.generate() v1 = [p.array_form for p in list(g)] v1.sort() - assert v1 == [[0,1,2], [0,2,1], [1,0,2], [1,2,0], [2,0,1], [2,1,0]] + assert v1 == [[0, 1, 2], [0, 2, 1], [1, 0, 2], [1, 2, 0], [2, 0, + 1], [2, 1, 0]] v2 = list(G.generate(method='dimino', af=True)) assert v1 == sorted(v2) a = Permutation([2, 0, 1, 3, 4, 5]) @@ -50,16 +53,21 @@ g = PermutationGroup([a, b]).generate(af=True) assert len(list(g)) == 360 + def test_order(): - a = Permutation([2,0,1,3,4,5,6,7,8,9]) - b = Permutation([2,1,3,4,5,6,7,8,9,0]) + a = Permutation([2, 0, 1, 3, 4, 5, 6, 7, 8, 9]) + b = Permutation([2, 1, 3, 4, 5, 6, 7, 8, 9, 0]) g = PermutationGroup([a, b]) assert g.order() == 1814400 + def test_stabilizer(): - a = Permutation([2,0,1,3,4,5]) - b = Permutation([2,1,3,4,5,0]) - G = PermutationGroup([a,b]) + S = SymmetricGroup(2) + H = S.stabilizer(0) + assert H.generators == [Permutation(1)] + a = Permutation([2, 0, 1, 3, 4, 5]) + b = Permutation([2, 1, 3, 4, 5, 0]) + G = PermutationGroup([a, b]) G0 = G.stabilizer(0) assert G0.order() == 60 @@ -72,13 +80,18 @@ v = list(G2_1.generate(af=True)) assert v == [[0, 1, 2, 3, 4, 5, 6, 7], [3, 1, 2, 0, 7, 5, 6, 4]] - gens = ((1,2,0,4,5,3,6,7,8,9,10,11,12,13,14,15,16,17,18,19), - (0,1,2,3,4,5,19,6,8,9,10,11,12,13,14,15,16,7,17,18), - (0,1,2,3,4,5,6,7,9,18,16,11,12,13,14,15,8,17,10,19)) + gens = ( + (1, 2, 0, 4, 5, 3, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19), + (0, 1, 2, 3, 4, 5, 19, 6, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 7, 17, 18), + (0, 1, 2, 3, 4, 5, 6, 7, 9, 18, 16, 11, 12, 13, 14, 15, 8, 17, 10, 19)) gens = [Permutation(p) for p in gens] G = PermutationGroup(gens) G2 = G.stabilizer(2) assert G2.order() == 181440 + S = SymmetricGroup(3) + assert [G.order() for G in S.basic_stabilizers] == [6, 2] + def test_center(): # the center of the dihedral group D_n is of order 2 for even n @@ -106,6 +119,7 @@ G.is_subgroup(D*A*C) assert _verify_centralizer(G, G) + def test_centralizer(): # the centralizer of the trivial group is the entire group S = SymmetricGroup(2) @@ -113,7 +127,7 @@ A = AlternatingGroup(5) assert A.centralizer(Permutation(list(range(5)))).is_subgroup(A) # a centralizer in the trivial group is the trivial group itself - triv = PermutationGroup([Permutation([0,1,2,3])]) + triv = PermutationGroup([Permutation([0, 1, 2, 3])]) D = DihedralGroup(4) assert triv.centralizer(D).is_subgroup(triv) # brute-force verifications for centralizers of groups @@ -151,14 +165,6 @@ if gp.degree == gp2.degree: assert _verify_centralizer(gp, gp2) -def test_stabilizer_cosets(): - a = Permutation([0, 2, 1]) - b = Permutation([1, 0, 2]) - G = PermutationGroup([a, b]) - assert G.stabilizer_cosets(af=True) == \ - [[[0,1,2], [1,0,2], [2,0,1]], [[0,1,2], [0,2,1]]] - assert G.stabilizer_gens(af=True) == [[0, 2, 1]] - def test_coset_rank(): gens_cube = [[1, 3, 5, 7, 0, 2, 4, 6], [1, 3, 0, 2, 5, 7, 4, 6]] gens = [Permutation(p) for p in gens_cube] @@ -171,10 +177,15 @@ assert h == h1 i += 1 assert G.coset_unrank(48) == None - assert G.coset_rank(gens[0]) == 6 - assert G.coset_unrank(6) == gens[0] + assert G.coset_unrank(G.coset_rank(gens[0])) == gens[0] def test_coset_factor(): + a = Permutation([0, 2, 1]) + G = PermutationGroup([a]) + c = Permutation([2, 1, 0]) + assert not G.coset_factor(c) + assert G.coset_rank(c) is None + a = Permutation([2,0,1,3,4,5]) b = Permutation([2,1,3,4,5,0]) g = PermutationGroup([a, b]) @@ -183,15 +194,17 @@ assert not g.coset_factor(d.array_form) assert not g.contains(d) c = Permutation([1,0,2,3,5,4]) - v = g.coset_factor(c, af=True) - assert _af_rmuln(*v) == [1,0,2,3,5,4] + v = g.coset_factor(c, True) + tr = g.basic_transversals + p = Permutation.rmul(*[tr[i][v[i]] for i in range(len(g.base))]) + assert p == c + v = g.coset_factor(c) + p = Permutation.rmul(*v) + assert p == c assert g.contains(c) - - a = Permutation([0,2,1]) - g = PermutationGroup([a]) - c = Permutation([2,1,0]) - assert not g.coset_factor(c) - assert g.coset_rank(c) == None + G = PermutationGroup([Permutation([2,1,0])]) + p = Permutation([1,0,2]) + assert G.coset_factor(p) == [] def test_orbits(): a = Permutation([2, 0, 1]) @@ -201,9 +214,10 @@ assert g.orbits() == [set([0, 1, 2])] assert g.is_transitive() and g.is_transitive(strict=False) assert g.orbit_transversal(0) == \ - [Permutation([0, 1, 2]), Permutation([2, 0, 1]), Permutation([1, 2, 0])] + [Permutation( + [0, 1, 2]), Permutation([2, 0, 1]), Permutation([1, 2, 0])] assert g.orbit_transversal(0, True) == \ - [(0, Permutation([0, 1, 2])), (2, Permutation([2, 0, 1])), \ + [(0, Permutation([0, 1, 2])), (2, Permutation([2, 0, 1])), (1, Permutation([1, 2, 0]))] a = Permutation(list(range(1, 100)) + [0]) @@ -214,23 +228,25 @@ assert not G.is_transitive() and not G.is_transitive(strict=False) G = PermutationGroup([Permutation(0, 1, 3), Permutation(3)(0, 1)]) assert not G.is_transitive() and G.is_transitive(strict=False) - assert PermutationGroup(Permutation(3)).is_transitive(strict=False) is False + assert PermutationGroup( + Permutation(3)).is_transitive(strict=False) is False + def test_is_normal(): - gens_s5 = [Permutation(p) for p in [[1,2,3,4,0], [2,1,4,0,3]]] + gens_s5 = [Permutation(p) for p in [[1, 2, 3, 4, 0], [2, 1, 4, 0, 3]]] G1 = PermutationGroup(gens_s5) assert G1.order() == 120 - gens_a5 = [Permutation(p) for p in [[1,0,3,2,4], [2,1,4,3,0]]] + gens_a5 = [Permutation(p) for p in [[1, 0, 3, 2, 4], [2, 1, 4, 3, 0]]] G2 = PermutationGroup(gens_a5) assert G2.order() == 60 assert G2.is_normal(G1) - gens3 = [Permutation(p) for p in [[2,1,3,0,4], [1,2,0,3,4]]] + gens3 = [Permutation(p) for p in [[2, 1, 3, 0, 4], [1, 2, 0, 3, 4]]] G3 = PermutationGroup(gens3) assert not G3.is_normal(G1) assert G3.order() == 12 G4 = G1.normal_closure(G3.generators) assert G4.order() == 60 - gens5 = [Permutation(p) for p in [[1,2,3,0,4], [1,2,0,3,4]]] + gens5 = [Permutation(p) for p in [[1, 2, 3, 0, 4], [1, 2, 0, 3, 4]]] G5 = PermutationGroup(gens5) assert G5.order() == 24 G6 = G1.normal_closure(G5.generators) @@ -239,15 +255,17 @@ assert not G1.is_subgroup(G4) assert G2.is_subgroup(G4) + def test_eq(): - a = [[1,2,0,3,4,5], [1,0,2,3,4,5], [2,1,0,3,4,5], [1,2,0,3,4,5]] - a = [Permutation(p) for p in a + [[1,2,3,4,5,0]]] - g = Permutation([1,2,3,4,5,0]) - G1, G2, G3 = [PermutationGroup(x) for x in [a[:2],a[2:4],[g, g**2]]] + a = [[1, 2, 0, 3, 4, 5], [1, 0, 2, 3, 4, 5], [2, 1, 0, 3, 4, 5], [ + 1, 2, 0, 3, 4, 5]] + a = [Permutation(p) for p in a + [[1, 2, 3, 4, 5, 0]]] + g = Permutation([1, 2, 3, 4, 5, 0]) + G1, G2, G3 = [PermutationGroup(x) for x in [a[:2], a[2:4], [g, g**2]]] assert G1.order() == G2.order() == G3.order() == 6 assert G1.is_subgroup(G2) assert not G1.is_subgroup(G3) - G4 = PermutationGroup([Permutation([0,1])]) + G4 = PermutationGroup([Permutation([0, 1])]) assert not G1.is_subgroup(G4) assert G4.is_subgroup(G1, 0) assert PermutationGroup(g, g).is_subgroup(PermutationGroup(g)) @@ -256,10 +274,11 @@ assert not CyclicGroup(5).is_subgroup(SymmetricGroup(3)*CyclicGroup(5), 0) assert CyclicGroup(3).is_subgroup(SymmetricGroup(3)*CyclicGroup(5), 0) + def test_derived_subgroup(): a = Permutation([1, 0, 2, 4, 3]) b = Permutation([0, 1, 3, 2, 4]) - G = PermutationGroup([a,b]) + G = PermutationGroup([a, b]) C = G.derived_subgroup() assert C.order() == 3 assert C.is_normal(G) @@ -271,16 +290,18 @@ C = G.derived_subgroup() assert C.order() == 12 + def test_is_solvable(): - a = Permutation([1,2,0]) - b = Permutation([1,0,2]) + a = Permutation([1, 2, 0]) + b = Permutation([1, 0, 2]) G = PermutationGroup([a, b]) assert G.is_solvable - a = Permutation([1,2,3,4,0]) - b = Permutation([1,0,2,3,4]) + a = Permutation([1, 2, 3, 4, 0]) + b = Permutation([1, 0, 2, 3, 4]) G = PermutationGroup([a, b]) assert not G.is_solvable + def test_rubik1(): gens = rubik_cube_generators() gens1 = [gens[-1]] + [p**2 for p in gens[1:]] @@ -309,6 +330,7 @@ G2 = G.normal_closure(G1.generators) assert G2.is_subgroup(G) + def test_direct_product(): C = CyclicGroup(4) D = DihedralGroup(4) @@ -316,17 +338,19 @@ assert G.order() == 64 assert G.degree == 12 assert len(G.orbits()) == 3 - assert G.is_abelian == True + assert G.is_abelian is True H = D*C assert H.order() == 32 - assert H.is_abelian == False + assert H.is_abelian is False + def test_orbit_rep(): G = DihedralGroup(6) - assert G.orbit_rep(1,3) in [Permutation([2, 3, 4, 5, 0, 1]),\ + assert G.orbit_rep(1, 3) in [Permutation([2, 3, 4, 5, 0, 1]), Permutation([4, 3, 2, 1, 0, 5])] H = CyclicGroup(4)*G - assert H.orbit_rep(1, 5) == False + assert H.orbit_rep(1, 5) is False + def test_schreier_vector(): G = CyclicGroup(50) @@ -338,6 +362,7 @@ L = SymmetricGroup(4) assert L.schreier_vector(1) == [1, -1, 0, 0] + def test_random_pr(): D = DihedralGroup(6) r = 11 @@ -346,46 +371,48 @@ _random_prec_n[0] = {'s': 7, 't': 3, 'x': 2, 'e': -1} _random_prec_n[1] = {'s': 5, 't': 5, 'x': 1, 'e': -1} _random_prec_n[2] = {'s': 3, 't': 4, 'x': 2, 'e': 1} - D._random_pr_init(r, n, _random_prec_n = _random_prec_n) - assert D._random_gens[11] == Permutation([0, 1, 2, 3, 4, 5]) + D._random_pr_init(r, n, _random_prec_n=_random_prec_n) + assert D._random_gens[11] == [0, 1, 2, 3, 4, 5] _random_prec = {'s': 2, 't': 9, 'x': 1, 'e': -1} - assert D.random_pr(_random_prec = _random_prec) == \ - Permutation([0, 5, 4, 3, 2, 1]) + assert D.random_pr(_random_prec=_random_prec) == \ + Permutation([0, 5, 4, 3, 2, 1]) + def test_is_alt_sym(): G = DihedralGroup(10) - assert G.is_alt_sym() == False + assert G.is_alt_sym() is False S = SymmetricGroup(10) N_eps = 10 _random_prec = {'N_eps': N_eps, - 0: Permutation([[2], [1, 4], [0, 6, 7, 8, 9, 3, 5]]), - 1: Permutation([[1, 8, 7, 6, 3, 5, 2, 9], [0, 4]]), - 2: Permutation([[5, 8], [4, 7], [0, 1, 2, 3, 6, 9]]), - 3: Permutation([[3], [0, 8, 2, 7, 4, 1, 6, 9, 5]]), - 4: Permutation([[8], [4, 7, 9], [3, 6], [0, 5, 1, 2]]), - 5: Permutation([[6], [0, 2, 4, 5, 1, 8, 3, 9, 7]]), - 6: Permutation([[6, 9, 8], [4, 5], [1, 3, 7], [0, 2]]), - 7: Permutation([[4], [0, 2, 9, 1, 3, 8, 6, 5, 7]]), - 8: Permutation([[1, 5, 6, 3], [0, 2, 7, 8, 4, 9]]), - 9: Permutation([[8], [6, 7], [2, 3, 4, 5], [0, 1, 9]])} - assert S.is_alt_sym(_random_prec = _random_prec) == True + 0: Permutation([[2], [1, 4], [0, 6, 7, 8, 9, 3, 5]]), + 1: Permutation([[1, 8, 7, 6, 3, 5, 2, 9], [0, 4]]), + 2: Permutation([[5, 8], [4, 7], [0, 1, 2, 3, 6, 9]]), + 3: Permutation([[3], [0, 8, 2, 7, 4, 1, 6, 9, 5]]), + 4: Permutation([[8], [4, 7, 9], [3, 6], [0, 5, 1, 2]]), + 5: Permutation([[6], [0, 2, 4, 5, 1, 8, 3, 9, 7]]), + 6: Permutation([[6, 9, 8], [4, 5], [1, 3, 7], [0, 2]]), + 7: Permutation([[4], [0, 2, 9, 1, 3, 8, 6, 5, 7]]), + 8: Permutation([[1, 5, 6, 3], [0, 2, 7, 8, 4, 9]]), + 9: Permutation([[8], [6, 7], [2, 3, 4, 5], [0, 1, 9]])} + assert S.is_alt_sym(_random_prec=_random_prec) is True A = AlternatingGroup(10) _random_prec = {'N_eps': N_eps, - 0: Permutation([[1, 6, 4, 2, 7, 8, 5, 9, 3], [0]]), - 1: Permutation([[1], [0, 5, 8, 4, 9, 2, 3, 6, 7]]), - 2: Permutation([[1, 9, 8, 3, 2, 5], [0, 6, 7, 4]]), - 3: Permutation([[6, 8, 9], [4, 5], [1, 3, 7, 2], [0]]), - 4: Permutation([[8], [5], [4], [2, 6, 9, 3], [1], [0, 7]]), - 5: Permutation([[3, 6], [0, 8, 1, 7, 5, 9, 4, 2]]), - 6: Permutation([[5], [2, 9], [1, 8, 3], [0, 4, 7, 6]]), - 7: Permutation([[1, 8, 4, 7, 2, 3], [0, 6, 9, 5]]), - 8: Permutation([[5, 8, 7], [3], [1, 4, 2, 6], [0, 9]]), - 9: Permutation([[4, 9, 6], [3, 8], [1, 2], [0, 5, 7]])} - assert A.is_alt_sym(_random_prec = _random_prec) == False + 0: Permutation([[1, 6, 4, 2, 7, 8, 5, 9, 3], [0]]), + 1: Permutation([[1], [0, 5, 8, 4, 9, 2, 3, 6, 7]]), + 2: Permutation([[1, 9, 8, 3, 2, 5], [0, 6, 7, 4]]), + 3: Permutation([[6, 8, 9], [4, 5], [1, 3, 7, 2], [0]]), + 4: Permutation([[8], [5], [4], [2, 6, 9, 3], [1], [0, 7]]), + 5: Permutation([[3, 6], [0, 8, 1, 7, 5, 9, 4, 2]]), + 6: Permutation([[5], [2, 9], [1, 8, 3], [0, 4, 7, 6]]), + 7: Permutation([[1, 8, 4, 7, 2, 3], [0, 6, 9, 5]]), + 8: Permutation([[5, 8, 7], [3], [1, 4, 2, 6], [0, 9]]), + 9: Permutation([[4, 9, 6], [3, 8], [1, 2], [0, 5, 7]])} + assert A.is_alt_sym(_random_prec=_random_prec) is False + def test_minimal_block(): D = DihedralGroup(6) - block_system = D.minimal_block([0,3]) + block_system = D.minimal_block([0, 3]) for i in range(3): assert block_system[i] == block_system[i + 3] S = SymmetricGroup(6) @@ -393,25 +420,29 @@ assert Tetra.pgroup.minimal_block([0, 1]) == [0, 0, 0, 0] + def test_max_div(): S = SymmetricGroup(10) assert S.max_div == 5 + def test_is_primitive(): S = SymmetricGroup(5) - assert S.is_primitive() == True + assert S.is_primitive() is True C = CyclicGroup(7) - assert C.is_primitive() == True + assert C.is_primitive() is True + def test_random_stab(): S = SymmetricGroup(5) _random_el = Permutation([1, 3, 2, 0, 4]) _random_prec = {'rand': _random_el} - g = S.random_stab(2, _random_prec = _random_prec) + g = S.random_stab(2, _random_prec=_random_prec) assert g == Permutation([1, 3, 2, 0, 4]) h = S.random_stab(1) assert h(1) == 1 + def test_transitivity_degree(): perm = Permutation([1, 2, 0]) C = PermutationGroup([perm]) @@ -422,21 +453,22 @@ Alt = PermutationGroup([gen1, gen2]) assert Alt.transitivity_degree == 3 + def test_schreier_sims_random(): - assert Tetra.pgroup.base == [0, 1] + assert sorted(Tetra.pgroup.base) == [0, 1] S = SymmetricGroup(3) base = [0, 1] - strong_gens = [Permutation([1, 2, 0]), Permutation([1, 0, 2]),\ + strong_gens = [Permutation([1, 2, 0]), Permutation([1, 0, 2]), Permutation([0, 2, 1])] assert S.schreier_sims_random(base, strong_gens, 5) == (base, strong_gens) D = DihedralGroup(3) - _random_prec = {'g': [Permutation([2, 0, 1]), Permutation([1, 2, 0]),\ + _random_prec = {'g': [Permutation([2, 0, 1]), Permutation([1, 2, 0]), Permutation([1, 0, 2])]} base = [0, 1] - strong_gens = [Permutation([1, 2, 0]), Permutation([2, 1, 0]),\ + strong_gens = [Permutation([1, 2, 0]), Permutation([2, 1, 0]), Permutation([0, 2, 1])] - assert D.schreier_sims_random([], D.generators, 2,\ + assert D.schreier_sims_random([], D.generators, 2, _random_prec=_random_prec) == (base, strong_gens) def test_baseswap(): @@ -448,21 +480,22 @@ deterministic = S.baseswap(base, strong_gens, 1, randomized=False) randomized = S.baseswap(base, strong_gens, 1) assert deterministic[0] == [0, 2, 1] - assert _verify_bsgs(S, deterministic[0], deterministic[1]) == True + assert _verify_bsgs(S, deterministic[0], deterministic[1]) is True assert randomized[0] == [0, 2, 1] - assert _verify_bsgs(S, randomized[0], randomized[1]) == True + assert _verify_bsgs(S, randomized[0], randomized[1]) is True + def test_schreier_sims_incremental(): identity = Permutation([0, 1, 2, 3, 4]) TrivialGroup = PermutationGroup([identity]) base, strong_gens = TrivialGroup.schreier_sims_incremental(base=[0, 1, 2]) - assert _verify_bsgs(TrivialGroup, base, strong_gens) == True + assert _verify_bsgs(TrivialGroup, base, strong_gens) is True S = SymmetricGroup(5) - base, strong_gens = S.schreier_sims_incremental(base=[0,1,2]) - assert _verify_bsgs(S, base, strong_gens) == True + base, strong_gens = S.schreier_sims_incremental(base=[0, 1, 2]) + assert _verify_bsgs(S, base, strong_gens) is True D = DihedralGroup(2) base, strong_gens = D.schreier_sims_incremental(base=[1]) - assert _verify_bsgs(D, base, strong_gens) == True + assert _verify_bsgs(D, base, strong_gens) is True A = AlternatingGroup(7) gens = A.generators[:] gen0 = gens[0] @@ -470,12 +503,13 @@ gen1 = rmul(gen1, ~gen0) gen0 = rmul(gen0, gen1) gen1 = rmul(gen0, gen1) - base, strong_gens = A.schreier_sims_incremental(base=[0,1], gens=gens) - assert _verify_bsgs(A, base, strong_gens) == True + base, strong_gens = A.schreier_sims_incremental(base=[0, 1], gens=gens) + assert _verify_bsgs(A, base, strong_gens) is True C = CyclicGroup(11) gen = C.generators[0] base, strong_gens = C.schreier_sims_incremental(gens=[gen**3]) - assert _verify_bsgs(C, base, strong_gens) == True + assert _verify_bsgs(C, base, strong_gens) is True + def _subgroup_search(i, j, k): prop_true = lambda x: True @@ -496,7 +530,7 @@ assert S.stabilizer(7).is_subgroup(S.subgroup_search(prop_fix_points)) points = [3, 4] assert S.stabilizer(3).stabilizer(4).is_subgroup( - S.subgroup_search(prop_fix_points)) + S.subgroup_search(prop_fix_points)) points = [3, 5] fix35 = A.subgroup_search(prop_fix_points) points = [5] @@ -505,19 +539,22 @@ ).is_subgroup(fix5) base, strong_gens = A.schreier_sims_incremental() g = A.generators[0] - comm_g =\ - A.subgroup_search(prop_comm_g, base=base, strong_gens=strong_gens) - assert _verify_bsgs(comm_g, base, comm_g.generators) == True - assert [prop_comm_g(gen) == True for gen in comm_g.generators] + comm_g = \ + A.subgroup_search(prop_comm_g, base=base, strong_gens=strong_gens) + assert _verify_bsgs(comm_g, base, comm_g.generators) is True + assert [prop_comm_g(gen) is True for gen in comm_g.generators] + def test_subgroup_search(): _subgroup_search(10, 15, 2) + @XFAIL def test_subgroup_search2(): skip('takes too much time') _subgroup_search(16, 17, 1) + def test_normal_closure(): # the normal closure of the trivial group is trivial S = SymmetricGroup(3) @@ -552,6 +589,7 @@ if gp2.is_subgroup(gp, 0) and gp2.degree == gp.degree: assert _verify_normal_closure(gp, gp2) + def test_derived_series(): # the derived series of the trivial group consists only of the trivial group triv = PermutationGroup([Permutation([0, 1, 2])]) @@ -567,6 +605,7 @@ assert series[2].is_subgroup(DihedralGroup(2)) assert series[3].is_trivial + def test_lower_central_series(): # the lower central series of the trivial group consists of the trivial # group @@ -582,6 +621,7 @@ assert len(series) == 2 assert series[1].is_subgroup(AlternatingGroup(6)) + def test_commutator(): # the commutator of the trivial group and the trivial group is trivial S = SymmetricGroup(3) @@ -608,6 +648,7 @@ A = AlternatingGroup(3) assert S.commutator(A, S).is_subgroup(A) + def test_is_nilpotent(): # every abelian group is nilpotent for i in (1, 2, 3): @@ -618,14 +659,19 @@ Ab = AbelianGroup(5, 7, 10) assert Ab.is_nilpotent # A_5 is not solvable and thus not nilpotent - assert AlternatingGroup(5).is_nilpotent == False + assert AlternatingGroup(5).is_nilpotent is False + def test_is_trivial(): for i in range(5): triv = PermutationGroup([Permutation(list(range(i)))]) assert triv.is_trivial + def test_pointwise_stabilizer(): + S = SymmetricGroup(2) + stab = S.pointwise_stabilizer([0]) + assert stab.generators == [Permutation(1)] S = SymmetricGroup(5) points = [] stab = S @@ -634,6 +680,7 @@ points.append(point) assert S.pointwise_stabilizer(points).is_subgroup(stab) + def test_make_perm(): assert cube.pgroup.make_perm(5, seed=list((list(range(5))))) == \ Permutation([4, 7, 6, 5, 0, 3, 2, 1]) diff -Nru python3-sympy-0.7.2/sympy/combinatorics/tests/test_permutations.py python3-sympy-0.7.3/sympy/combinatorics/tests/test_permutations.py --- python3-sympy-0.7.2/sympy/combinatorics/tests/test_permutations.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/combinatorics/tests/test_permutations.py 2013-07-13 17:53:31.000000000 +0000 @@ -6,6 +6,7 @@ rmul = Permutation.rmul + def test_Permutation(): # don't auto fill 0 raises(ValueError, lambda: Permutation([1])) @@ -18,6 +19,8 @@ assert list(p(1, 2)) == [0, 2, 1, 3] # conversion to list assert list(p) == list(range(4)) + assert Permutation(size=4) == Permutation(3) + assert Permutation(Permutation(3), size=5) == Permutation(4) # cycle form with size assert Permutation([[1, 2]], size=4) == Permutation([[1, 2], [0], [3]]) # random generation @@ -26,13 +29,14 @@ p = Permutation([2, 5, 1, 6, 3, 0, 4]) q = Permutation([[1], [0, 3, 5, 6, 2, 4]]) assert len(set([p, p])) == 1 - r = Permutation([1,3,2,0,4,6,5]) + r = Permutation([1, 3, 2, 0, 4, 6, 5]) ans = Permutation(_af_rmuln(*[w.array_form for w in (p, q, r)])).array_form assert rmul(p, q, r).array_form == ans # make sure no other permutation of p, q, r could have given # that answer for a, b, c in permutations((p, q, r)): - if (a, b, c) == (p, q, r): continue + if (a, b, c) == (p, q, r): + continue assert rmul(a, b, c).array_form != ans assert p.support() == list(range(7)) @@ -46,8 +50,8 @@ assert _af_rmul(p.array_form, q.array_form) == \ [6, 5, 3, 0, 2, 4, 1] - assert rmul(Permutation([[1,2,3],[0,4]]), - Permutation([[1,2,4],[0],[3]])).cyclic_form == \ + assert rmul(Permutation([[1, 2, 3], [0, 4]]), + Permutation([[1, 2, 4], [0], [3]])).cyclic_form == \ [[0, 4, 2], [1, 3]] assert q.array_form == [3, 1, 4, 5, 0, 6, 2] assert q.cyclic_form == [[0, 3, 5, 6, 2, 4]] @@ -79,7 +83,7 @@ raises(TypeError, lambda: p + Permutation(list(range(10)))) assert (p - q.rank()).rank() == Permutation(0, 6, 3, 1, 2, 5, 4).rank() - assert p.rank() - q.rank() < 0 # for coverage: make sure mod is used + assert p.rank() - q.rank() < 0 # for coverage: make sure mod is used assert (q - p.rank()).rank() == Permutation(1, 4, 6, 2)(3, 5).rank() assert p*q == Permutation(_af_rmuln(*[list(w) for w in (q, p)])) @@ -88,13 +92,13 @@ assert p*Permutation([[0, 1]]) == Permutation([2, 5, 0, 6, 3, 1, 4]) assert Permutation([[0, 1]])*p == Permutation([5, 2, 1, 6, 3, 0, 4]) - pq = p^q + pq = p ^ q assert pq == Permutation([5, 6, 0, 4, 1, 2, 3]) assert pq == rmul(q, p, ~q) - qp = q^p + qp = q ^ p assert qp == Permutation([4, 3, 6, 2, 1, 5, 0]) assert qp == rmul(p, q, ~p) - raises(ValueError, lambda: p^Permutation([])) + raises(ValueError, lambda: p ^ Permutation([])) assert p.commutator(q) == Permutation(0, 1, 3, 4, 6, 5, 2) assert q.commutator(p) == Permutation(0, 2, 5, 6, 4, 3, 1) @@ -109,13 +113,13 @@ assert Permutation.from_inversion_vector(p.inversion_vector()) == p assert Permutation.from_inversion_vector(q.inversion_vector()).array_form\ - == q.array_form + == q.array_form raises(ValueError, lambda: Permutation.from_inversion_vector([0, 2])) - assert Permutation([i for i in range(500,-1,-1)]).inversions() == 125250 + assert Permutation([i for i in range(500, -1, -1)]).inversions() == 125250 s = Permutation([0, 4, 1, 3, 2]) assert s.parity() == 0 - _ = s.cyclic_form # needed to create a value for _cyclic_form + _ = s.cyclic_form # needed to create a value for _cyclic_form assert len(s._cyclic_form) != s.size and s.parity() == 0 assert not s.is_odd assert s.is_even @@ -189,7 +193,7 @@ assert p.get_positional_distance(q) == 8 p = Permutation([0, 3, 1, 2, 4]) q = Permutation.josephus(4, 5, 2) - assert p.get_adjacency_distance(q) == 3 + assert p.get_adjacency_distance(q) == 3 raises(ValueError, lambda: p.get_adjacency_distance(Permutation([]))) raises(ValueError, lambda: p.get_positional_distance(Permutation([]))) raises(ValueError, lambda: p.get_precedence_distance(Permutation([]))) @@ -197,9 +201,9 @@ a = [Permutation.unrank_nonlex(4, i) for i in range(5)] iden = Permutation([0, 1, 2, 3]) for i in range(5): - for j in range(i+1, 5): + for j in range(i + 1, 5): assert a[i].commutes_with(a[j]) == \ - (rmul(a[i], a[j]) == rmul(a[j], a[i])) + (rmul(a[i], a[j]) == rmul(a[j], a[i])) if a[i].commutes_with(a[j]): assert a[i].commutator(a[j]) == iden assert a[j].commutator(a[i]) == iden @@ -209,10 +213,12 @@ assert a.cycle_structure == {1: 4} assert b.cycle_structure == {2: 1, 3: 1, 1: 2} + def test_josephus(): assert Permutation.josephus(4, 6, 1) == Permutation([3, 1, 0, 2, 5, 4]) assert Permutation.josephus(1, 5, 1).is_Identity + def test_ranking(): assert Permutation.unrank_lex(5, 10).rank() == 10 p = Permutation.unrank_lex(15, 225) @@ -224,15 +230,16 @@ p = Permutation.unrank_lex(4, 23) assert p.rank() == 23 assert p.array_form == [3, 2, 1, 0] - assert p.next_lex() == None + assert p.next_lex() is None p = Permutation([1, 5, 2, 0, 3, 6, 4]) q = Permutation([[1, 2, 3, 5, 6], [0, 4]]) a = [Permutation.unrank_trotterjohnson(4, i).array_form for i in range(5)] - assert a == [[0,1,2,3], [0,1,3,2], [0,3,1,2], [3,0,1,2], [3,0,2,1] ] + assert a == [[0, 1, 2, 3], [0, 1, 3, 2], [0, 3, 1, 2], [3, 0, 1, + 2], [3, 0, 2, 1] ] assert [Permutation(pa).rank_trotterjohnson() for pa in a] == list(range(5)) - assert Permutation([0,1,2,3]).next_trotterjohnson() == \ - Permutation([0,1,3,2]) + assert Permutation([0, 1, 2, 3]).next_trotterjohnson() == \ + Permutation([0, 1, 3, 2]) assert q.rank_trotterjohnson() == 2283 assert p.rank_trotterjohnson() == 3389 @@ -242,11 +249,11 @@ l = [] tj = [] for i in range(6): - l.append(a) - tj.append(b) - a=a.next_lex() - b=b.next_trotterjohnson() - assert a == b == None + l.append(a) + tj.append(b) + a = a.next_lex() + b = b.next_trotterjohnson() + assert a == b is None assert set([tuple(a) for a in l]) == set([tuple(a) for a in tj]) p = Permutation([2, 5, 1, 6, 3, 0, 4]) @@ -262,12 +269,19 @@ assert Permutation.unrank_nonlex(7, 41) == Permutation(q.array_form) a = [Permutation.unrank_nonlex(4, i).array_form for i in range(24)] - assert a == \ - [[1, 2, 3, 0], [3, 2, 0, 1], [1, 3, 0, 2], [1, 2, 0, 3], [2, 3, 1, 0], \ - [2, 0, 3, 1], [3, 0, 1, 2], [2, 0, 1, 3], [1, 3, 2, 0], [3, 0, 2, 1], \ - [1, 0, 3, 2], [1, 0, 2, 3], [2, 1, 3, 0], [2, 3, 0, 1], [3, 1, 0, 2], \ - [2, 1, 0, 3], [3, 2, 1, 0], [0, 2, 3, 1], [0, 3, 1, 2], [0, 2, 1, 3], \ - [3, 1, 2, 0], [0, 3, 2, 1], [0, 1, 3, 2], [0, 1, 2, 3]] + assert a == [ + [1, 2, 3, 0], [3, 2, 0, 1], [1, 3, 0, 2], [1, 2, 0, 3], [2, 3, 1, 0], + [2, 0, 3, 1], [3, 0, 1, 2], [2, 0, 1, 3], [1, 3, 2, 0], [3, 0, 2, 1], + [1, 0, 3, 2], [1, 0, 2, 3], [2, 1, 3, 0], [2, 3, 0, 1], [3, 1, 0, 2], + [2, 1, 0, 3], [3, 2, 1, 0], [0, 2, 3, 1], [0, 3, 1, 2], [0, 2, 1, 3], + [3, 1, 2, 0], [0, 3, 2, 1], [0, 1, 3, 2], [0, 1, 2, 3]] + + N = 10 + p1 = Permutation(a[0]) + for i in range(1, N+1): + p1 = p1*Permutation(a[i]) + p2 = Permutation.rmul_with_af(*[Permutation(h) for h in a[N::-1]]) + assert p1 == p2 ok = [] p = Permutation([1, 0]) @@ -281,8 +295,9 @@ assert Permutation([3, 2, 0, 1]).next_nonlex() == Permutation([1, 3, 0, 2]) assert [Permutation(pa).rank_nonlex() for pa in a] == list(range(24)) + def test_mul(): - a, b = [0,2,1,3], [0,1,3,2] + a, b = [0, 2, 1, 3], [0, 1, 3, 2] assert _af_rmul(a, b) == [0, 2, 3, 1] assert _af_rmuln(a, b, list(range(4))) == [0, 2, 3, 1] assert rmul(Permutation(a), Permutation(b)).array_form == [0, 2, 3, 1] @@ -292,7 +307,7 @@ c = (3, 1, 2, 0) assert Permutation.rmul(a, b, c) == Permutation([1, 2, 3, 0]) assert Permutation.rmul(a, c) == Permutation([3, 2, 1, 0]) - raises (TypeError, lambda: Permutation.rmul(b, c)) + raises(TypeError, lambda: Permutation.rmul(b, c)) n = 6 m = 8 @@ -300,9 +315,10 @@ h = list(range(n)) for i in range(m): h = _af_rmul(h, a[i]) - h2 = _af_rmuln(*a[:i+1]) + h2 = _af_rmuln(*a[:i + 1]) assert h == h2 + def test_args(): p = Permutation([(0, 3, 1, 2), (4, 5)]) assert p._cyclic_form is None @@ -315,45 +331,54 @@ assert Permutation([0]) == Permutation((0, )) assert Permutation([[0], [1]]) == Permutation(((0, ), (1, ))) == \ Permutation(((0, ), [1])) - assert Permutation([[1,2]]) == Permutation([0, 2, 1]) - assert Permutation([[1], [4,2]]) == Permutation([0, 1, 4, 3, 2]) - assert Permutation([[1], [4,2]], size=1) == Permutation([0, 1, 4, 3, 2]) - assert Permutation([[1], [4,2]], size=6) == Permutation([0, 1, 4, 3, 2, 5]) + assert Permutation([[1, 2]]) == Permutation([0, 2, 1]) + assert Permutation([[1], [4, 2]]) == Permutation([0, 1, 4, 3, 2]) + assert Permutation([[1], [4, 2]], size=1) == Permutation([0, 1, 4, 3, 2]) + assert Permutation( + [[1], [4, 2]], size=6) == Permutation([0, 1, 4, 3, 2, 5]) assert Permutation([], size=3) == Permutation([0, 1, 2]) assert Permutation(3).list(5) == [0, 1, 2, 3, 4] assert Permutation(3).list(-1) == [] assert Permutation(5)(1, 2).list(-1) == [0, 2, 1] assert Permutation(5)(1, 2).list() == [0, 2, 1, 3, 4, 5] - raises(TypeError, lambda: Permutation([1, 2], [0])) # enclosing brackets needed - raises(ValueError, lambda: Permutation([[1, 2], 0])) # enclosing brackets needed on 0 - raises(ValueError, lambda: Permutation([1,1,0])) + raises(TypeError, lambda: Permutation([1, 2], [0])) + # enclosing brackets needed + raises(ValueError, lambda: Permutation([[1, 2], 0])) + # enclosing brackets needed on 0 + raises(ValueError, lambda: Permutation([1, 1, 0])) raises(ValueError, lambda: Permutation([[1], [1, 2]])) - raises(ValueError, lambda: Permutation([4, 5], size=10)) # where are 0-3? + raises(ValueError, lambda: Permutation([4, 5], size=10)) # where are 0-3? # but this is ok because cycles imply that only those listed moved assert Permutation(4, 5) == Permutation([0, 1, 2, 3, 5, 4]) + def test_Cycle(): - assert Cycle(1, 2)(2,3) == Cycle(1, 3, 2) + assert str(Cycle()) == 'Cycle()' + assert Cycle(Cycle(1,2)) == Cycle(1, 2) + assert Cycle(1,2).copy() == Cycle(1,2) + assert list(Cycle(1, 3, 2)) == [0, 3, 1, 2] + assert Cycle(1, 2)(2, 3) == Cycle(1, 3, 2) assert Cycle(1, 2)(2, 3)(4, 5) == Cycle(1, 3, 2)(4, 5) - assert Permutation(Cycle(1, 2)(2, 1, 0, 3)).cyclic_form , Cycle(0, 2, 1) + assert Permutation(Cycle(1, 2)(2, 1, 0, 3)).cyclic_form, Cycle(0, 2, 1) raises(ValueError, lambda: Cycle().list()) - assert Cycle(1,2).list() == [0, 2, 1] - assert Cycle(1,2).list(4) == [0, 2, 1, 3] + assert Cycle(1, 2).list() == [0, 2, 1] + assert Cycle(1, 2).list(4) == [0, 2, 1, 3] assert Permutation(Cycle(1, 2), size=4) == \ Permutation([0, 2, 1, 3]) - assert str(Cycle(1,2)(4,5)) == 'Cycle(1, 2)(4, 5)' - assert str(Cycle(1,2)) == 'Cycle(1, 2)' + assert str(Cycle(1, 2)(4, 5)) == 'Cycle(1, 2)(4, 5)' + assert str(Cycle(1, 2)) == 'Cycle(1, 2)' assert Cycle(Permutation(list(range(3)))) == Cycle() - assert Cycle(1,2).list() == [0, 2, 1] - assert Cycle(1,2).list(4) == [0, 2, 1, 3] + assert Cycle(1, 2).list() == [0, 2, 1] + assert Cycle(1, 2).list(4) == [0, 2, 1, 3] raises(TypeError, lambda: Cycle((1, 2))) raises(ValueError, lambda: Cycle(1, 2, 1)) raises(TypeError, lambda: Cycle(1, 2)*{}) # check round-trip - p = Permutation([[1,2], [4,3]], size=5) + p = Permutation([[1, 2], [4, 3]], size=5) assert Permutation(Cycle(p)) == p + def test_from_sequence(): assert Permutation.from_sequence('SymPy') == Permutation(4)(0, 1, 3) assert Permutation.from_sequence('SymPy', key=lambda x: x.lower()) == \ diff -Nru python3-sympy-0.7.2/sympy/combinatorics/tests/test_polyhedron.py python3-sympy-0.7.3/sympy/combinatorics/tests/test_polyhedron.py --- python3-sympy-0.7.2/sympy/combinatorics/tests/test_polyhedron.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/combinatorics/tests/test_polyhedron.py 2013-07-13 17:53:31.000000000 +0000 @@ -8,23 +8,24 @@ rmul = Permutation.rmul + def test_polyhedron(): raises(ValueError, lambda: Polyhedron(list('ab'), pgroup=[Permutation([0])])) - pgroup = [Permutation([[0,7,2,5],[6,1,4,3]]),\ - Permutation([[0,7,1,6],[5,2,4,3]]),\ - Permutation([[3,6,0,5],[4,1,7,2]]),\ - Permutation([[7,4,5],[1,3,0],[2],[6]]),\ - Permutation([[1,3,2],[7,6,5],[4],[0]]),\ - Permutation([[4,7,6],[2,0,3],[1],[5]]),\ - Permutation([[1,2,0],[4,5,6],[3],[7]]),\ - Permutation([[4,2],[0,6],[3,7],[1,5]]),\ - Permutation([[3,5],[7,1],[2,6],[0,4]]),\ - Permutation([[2,5],[1,6],[0,4],[3,7]]),\ - Permutation([[4,3],[7,0],[5,1],[6,2]]),\ - Permutation([[4,1],[0,5],[6,2],[7,3]]),\ - Permutation([[7,2],[3,6],[0,4],[1,5]]),\ - Permutation([0,1,2,3,4,5,6,7])] + pgroup = [Permutation([[0, 7, 2, 5], [6, 1, 4, 3]]), + Permutation([[0, 7, 1, 6], [5, 2, 4, 3]]), + Permutation([[3, 6, 0, 5], [4, 1, 7, 2]]), + Permutation([[7, 4, 5], [1, 3, 0], [2], [6]]), + Permutation([[1, 3, 2], [7, 6, 5], [4], [0]]), + Permutation([[4, 7, 6], [2, 0, 3], [1], [5]]), + Permutation([[1, 2, 0], [4, 5, 6], [3], [7]]), + Permutation([[4, 2], [0, 6], [3, 7], [1, 5]]), + Permutation([[3, 5], [7, 1], [2, 6], [0, 4]]), + Permutation([[2, 5], [1, 6], [0, 4], [3, 7]]), + Permutation([[4, 3], [7, 0], [5, 1], [6, 2]]), + Permutation([[4, 1], [0, 5], [6, 2], [7, 3]]), + Permutation([[7, 2], [3, 6], [0, 4], [1, 5]]), + Permutation([0, 1, 2, 3, 4, 5, 6, 7])] corners = tuple(symbols('A:H')) faces = cube_faces cube = Polyhedron(corners, faces, pgroup) @@ -33,12 +34,12 @@ (0, 1), (6, 7), (1, 2), (5, 6), (0, 3), (2, 3), (4, 7), (4, 5), (3, 7), (1, 5), (0, 4), (2, 6))) - for i in range(3): # add 180 degree face rotations + for i in range(3): # add 180 degree face rotations cube.rotate(cube.pgroup[i]**2) assert cube.corners == corners - for i in range(3,7): # add 240 degree axial corner rotations + for i in range(3, 7): # add 240 degree axial corner rotations cube.rotate(cube.pgroup[i]**2) assert cube.corners == corners @@ -77,7 +78,7 @@ for h, size, rpt, target in zip( (tetrahedron, square, octahedron, dodecahedron, icosahedron), - (4, 8, 6, 20, 12), - (3, 4, 4, 5, 5), - (12, 24, 24, 60, 60)): + (4, 8, 6, 20, 12), + (3, 4, 4, 5, 5), + (12, 24, 24, 60, 60)): check(h, size, rpt, target) diff -Nru python3-sympy-0.7.2/sympy/combinatorics/tests/test_prufer.py python3-sympy-0.7.3/sympy/combinatorics/tests/test_prufer.py --- python3-sympy-0.7.2/sympy/combinatorics/tests/test_prufer.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/combinatorics/tests/test_prufer.py 2013-07-13 17:53:31.000000000 +0000 @@ -1,6 +1,7 @@ from sympy.combinatorics.prufer import Prufer from sympy.utilities.pytest import raises + def test_prufer(): # number of nodes is optional assert Prufer([[0, 1], [0, 2], [0, 3], [0, 4]], 5).nodes == 5 @@ -18,7 +19,7 @@ assert a.prufer_repr == [4, 1, 4, 0] assert Prufer.edges([0, 1, 2, 3], [1, 4, 5], [1, 4, 6]) == \ - ([[0, 1], [1, 2], [4, 6], [4, 5], [1, 4], [2, 3]], 7) + ([[0, 1], [1, 2], [1, 4], [2, 3], [4, 5], [4, 6]], 7) assert Prufer([0]*4).size == Prufer([6]*4).size == 1296 # accept iterables but convert to list of lists @@ -26,13 +27,15 @@ Prufer(tree).tree_repr == tree Prufer(set(tree)).tree_repr == tree - raises(ValueError, lambda: Prufer([[1, 2], [3, 4]])) # 0 is missing + raises(ValueError, lambda: Prufer([[1, 2], [3, 4]])) # 0 is missing assert Prufer(*Prufer.edges([1, 2], [3, 4])).prufer_repr == [1, 3] - raises(ValueError, lambda: Prufer.edges([1, 3], [3, 4])) # a broken tree but edges doesn't care + raises(ValueError, lambda: Prufer.edges( + [1, 3], [3, 4])) # a broken tree but edges doesn't care raises(ValueError, lambda: Prufer.edges([1, 2], [5, 6])) + def test_round_trip(): - def doit(t,b): + def doit(t, b): e, n = Prufer.edges(*t) t = Prufer(e, n) a = sorted(t.tree_repr) diff -Nru python3-sympy-0.7.2/sympy/combinatorics/tests/test_subsets.py python3-sympy-0.7.3/sympy/combinatorics/tests/test_subsets.py --- python3-sympy-0.7.2/sympy/combinatorics/tests/test_subsets.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/combinatorics/tests/test_subsets.py 2013-07-13 17:53:31.000000000 +0000 @@ -1,30 +1,48 @@ from sympy.combinatorics import Subset + def test_subset(): - a = Subset(['c','d'],['a','b','c','d']) - assert a.next_binary() == Subset(['b'], ['a','b','c','d']) - assert a.prev_binary() == Subset(['c'], ['a','b','c','d']) - assert a.next_gray() == Subset(['c'], ['a','b','c','d']) - assert a.prev_gray() == Subset(['d'], ['a','b','c','d']) + a = Subset(['c', 'd'], ['a', 'b', 'c', 'd']) + assert a.next_binary() == Subset(['b'], ['a', 'b', 'c', 'd']) + assert a.prev_binary() == Subset(['c'], ['a', 'b', 'c', 'd']) + assert a.next_lexicographic() == Subset(['d'], ['a', 'b', 'c', 'd']) + assert a.prev_lexicographic() == Subset(['c'], ['a', 'b', 'c', 'd']) + assert a.next_gray() == Subset(['c'], ['a', 'b', 'c', 'd']) + assert a.prev_gray() == Subset(['d'], ['a', 'b', 'c', 'd']) assert a.rank_binary == 3 assert a.rank_lexicographic == 14 assert a.rank_gray == 2 assert a.cardinality == 16 - a = Subset([2,5,7],[1,2,3,4,5,6,7]) - assert a.next_binary() == Subset([2, 5, 6],[1,2,3,4,5,6,7]) - assert a.prev_binary() == Subset([2, 5],[1,2,3,4,5,6,7]) - assert a.next_gray() == Subset([2, 5, 6, 7],[1,2,3,4,5,6,7]) - assert a.prev_gray() == Subset([2, 5],[1,2,3,4,5,6,7]) + a = Subset([2, 5, 7], [1, 2, 3, 4, 5, 6, 7]) + assert a.next_binary() == Subset([2, 5, 6], [1, 2, 3, 4, 5, 6, 7]) + assert a.prev_binary() == Subset([2, 5], [1, 2, 3, 4, 5, 6, 7]) + assert a.next_lexicographic() == Subset([2, 6], [1, 2, 3, 4, 5, 6, 7]) + assert a.prev_lexicographic() == Subset([2, 5, 6, 7], [1, 2, 3, 4, 5, 6, 7]) + assert a.next_gray() == Subset([2, 5, 6, 7], [1, 2, 3, 4, 5, 6, 7]) + assert a.prev_gray() == Subset([2, 5], [1, 2, 3, 4, 5, 6, 7]) assert a.rank_binary == 37 assert a.rank_lexicographic == 93 assert a.rank_gray == 57 assert a.cardinality == 128 - superset = ['a','b','c','d'] - assert Subset.unrank_binary(4,superset).rank_binary == 4 - assert Subset.unrank_gray(10,superset).rank_gray == 10 - - superset = [1,2,3,4,5,6,7,8,9] - assert Subset.unrank_binary(33,superset).rank_binary == 33 - assert Subset.unrank_gray(25,superset).rank_gray == 25 + superset = ['a', 'b', 'c', 'd'] + assert Subset.unrank_binary(4, superset).rank_binary == 4 + assert Subset.unrank_gray(10, superset).rank_gray == 10 + + superset = [1, 2, 3, 4, 5, 6, 7, 8, 9] + assert Subset.unrank_binary(33, superset).rank_binary == 33 + assert Subset.unrank_gray(25, superset).rank_gray == 25 + + a = Subset([], ['a', 'b', 'c', 'd']) + i = 1 + while a.subset != Subset(['d'], ['a', 'b', 'c', 'd']).subset: + a = a.next_lexicographic() + i = i + 1 + assert i == 16 + + i = 1 + while a.subset != Subset([], ['a', 'b', 'c', 'd']).subset: + a = a.prev_lexicographic() + i = i + 1 + assert i == 16 diff -Nru python3-sympy-0.7.2/sympy/combinatorics/tests/test_tensor_can.py python3-sympy-0.7.3/sympy/combinatorics/tests/test_tensor_can.py --- python3-sympy-0.7.2/sympy/combinatorics/tests/test_tensor_can.py 1970-01-01 00:00:00.000000000 +0000 +++ python3-sympy-0.7.3/sympy/combinatorics/tests/test_tensor_can.py 2013-07-13 17:53:31.000000000 +0000 @@ -0,0 +1,565 @@ +from sympy.combinatorics.perm_groups import PermutationGroup +from sympy.combinatorics.permutations import Permutation, Perm +from sympy.combinatorics.tensor_can import (perm_af_direct_product, dummy_sgs, + riemann_bsgs, get_symmetric_group_sgs, gens_products, canonicalize, + bsgs_direct_product) +from sympy.combinatorics.testutil import canonicalize_naive, graph_certificate +from sympy.utilities.pytest import skip, XFAIL + +def test_perm_af_direct_product(): + gens1 = [[1,0,2,3], [0,1,3,2]] + gens2 = [[1,0]] + assert perm_af_direct_product(gens1, gens2, 0) == [[1, 0, 2, 3, 4, 5], [0, 1, 3, 2, 4, 5], [0, 1, 2, 3, 5, 4]] + gens1 = [[1,0,2,3,5,4], [0,1,3,2,4,5]] + gens2 = [[1,0,2,3]] + assert [[1, 0, 2, 3, 4, 5, 7, 6], [0, 1, 3, 2, 4, 5, 6, 7], [0, 1, 2, 3, 5, 4, 6, 7]] + +def test_dummy_sgs(): + a = dummy_sgs([1,2], 0, 4) + assert a == [[0,2,1,3,4,5]] + a = dummy_sgs([2,3,4,5], 0, 8) + assert a == [x._array_form for x in [Perm(9)(2,3), Perm(9)(4,5), + Perm(9)(2,4)(3,5)]] + + a = dummy_sgs([2,3,4,5], 1, 8) + assert a == [x._array_form for x in [Perm(2,3)(8,9), Perm(4,5)(8,9), + Perm(9)(2,4)(3,5)]] + +def test_get_symmetric_group_sgs(): + assert get_symmetric_group_sgs(2) == ([0], [Permutation(3)(0,1)]) + assert get_symmetric_group_sgs(2, 1) == ([0], [Permutation(0,1)(2,3)]) + assert get_symmetric_group_sgs(3) == ([0,1], [Permutation(4)(0,1), Permutation(4)(1,2)]) + assert get_symmetric_group_sgs(3, 1) == ([0,1], [Permutation(0,1)(3,4), Permutation(1,2)(3,4)]) + assert get_symmetric_group_sgs(4) == ([0,1,2], [Permutation(5)(0,1), Permutation(5)(1,2), Permutation(5)(2,3)]) + assert get_symmetric_group_sgs(4, 1) == ([0,1,2], [Permutation(0,1)(4,5), Permutation(1,2)(4,5), Permutation(2,3)(4,5)]) + + +def test_canonicalize_no_slot_sym(): + # cases in which there is no slot symmetry after fixing the + # free indices; here and in the following if the symmetry of the + # metric is not specified, it is assumed to be symmetric. + # If it is not specified, tensors are commuting. + + # A_d0 * B^d0; g = [1,0, 2,3]; T_c = A^d0*B_d0; can = [0,1,2,3] + base1, gens1 = get_symmetric_group_sgs(1) + dummies = [0, 1] + g = Permutation([1,0,2,3]) + can = canonicalize(g, dummies, 0, (base1,gens1,1,0), (base1,gens1,1,0)) + assert can == [0,1,2,3] + # equivalently + can = canonicalize(g, dummies, 0, (base1, gens1, 2, None)) + assert can == [0,1,2,3] + + # with antisymmetric metric; T_c = -A^d0*B_d0; can = [0,1,3,2] + can = canonicalize(g, dummies, 1, (base1,gens1,1,0), (base1,gens1,1,0)) + assert can == [0,1,3,2] + + # A^a * B^b; ord = [a,b]; g = [0,1,2,3]; can = g + g = Permutation([0,1,2,3]) + dummies = [] + t0 = t1 = (base1, gens1, 1, 0) + can = canonicalize(g, dummies, 0, t0, t1) + assert can == [0,1,2,3] + # B^b * A^a + g = Permutation([1,0,2,3]) + can = canonicalize(g, dummies, 0, t0, t1) + assert can == [1,0,2,3] + + # A symmetric + # A^{b}_{d0}*A^{d0, a} order a,b,d0,-d0; T_c = A^{a d0}*A{b}_{d0} + # g = [1,3,2,0,4,5]; can = [0,2,1,3,4,5] + base2, gens2 = get_symmetric_group_sgs(2) + dummies = [2,3] + g = Permutation([1,3,2,0,4,5]) + can = canonicalize(g, dummies, 0, (base2, gens2, 2, 0)) + assert can == [0, 2, 1, 3, 4, 5] + # with antisymmetric metric + can = canonicalize(g, dummies, 1, (base2, gens2, 2, 0)) + assert can == [0, 2, 1, 3, 4, 5] + # A^{a}_{d0}*A^{d0, b} + g = Permutation([0,3,2,1,4,5]) + can = canonicalize(g, dummies, 1, (base2, gens2, 2, 0)) + assert can == [0, 2, 1, 3, 5, 4] + + # A, B symmetric + # A^b_d0*B^{d0,a}; g=[1,3,2,0,4,5] + # T_c = A^{b,d0}*B_{a,d0}; can = [1,2,0,3,4,5] + dummies = [2,3] + g = Permutation([1,3,2,0,4,5]) + can = canonicalize(g, dummies, 0, (base2,gens2,1,0), (base2,gens2,1,0)) + assert can == [1,2,0,3,4,5] + # same with antisymmetric metric + can = canonicalize(g, dummies, 1, (base2,gens2,1,0), (base2,gens2,1,0)) + assert can == [1,2,0,3,5,4] + + # A^{d1}_{d0}*B^d0*C_d1 ord=[d0,-d0,d1,-d1]; g = [2,1,0,3,4,5] + # T_c = A^{d0 d1}*B_d0*C_d1; can = [0,2,1,3,4,5] + base1, gens1 = get_symmetric_group_sgs(1) + base2, gens2 = get_symmetric_group_sgs(2) + g = Permutation([2,1,0,3,4,5]) + dummies = [0,1,2,3] + t0 = (base2, gens2, 1, 0) + t1 = t2 = (base1, gens1, 1, 0) + can = canonicalize(g, dummies, 0, t0, t1, t2) + assert can == [0, 2, 1, 3, 4, 5] + + # A without symmetry + # A^{d1}_{d0}*B^d0*C_d1 ord=[d0,-d0,d1,-d1]; g = [2,1,0,3,4,5] + # T_c = A^{d0 d1}*B_d1*C_d0; can = [0,2,3,1,4,5] + g = Permutation([2,1,0,3,4,5]) + dummies = [0,1,2,3] + t0 = ([], [Permutation(list(range(4)))], 1, 0) + can = canonicalize(g, dummies, 0, t0, t1, t2) + assert can == [0,2,3,1,4,5] + # A, B without symmetry + # A^{d1}_{d0}*B_{d1}^{d0}; g = [2,1,3,0,4,5] + # T_c = A^{d0 d1}*B_{d0 d1}; can = [0,2,1,3,4,5] + t0 = t1 = ([], [Permutation(list(range(4)))], 1, 0) + dummies = [0,1,2,3] + g = Permutation([2,1,3,0,4,5]) + can = canonicalize(g, dummies, 0, t0, t1) + assert can == [0, 2, 1, 3, 4, 5] + # A_{d0}^{d1}*B_{d1}^{d0}; g = [1,2,3,0,4,5] + # T_c = A^{d0 d1}*B_{d1 d0}; can = [0,2,3,1,4,5] + g = Permutation([1,2,3,0,4,5]) + can = canonicalize(g, dummies, 0, t0, t1) + assert can == [0,2,3,1,4,5] + + # A, B, C without symmetry + # A^{d1 d0}*B_{a d0}*C_{d1 b} ord=[a,b,d0,-d0,d1,-d1] + # g=[4,2,0,3,5,1,6,7] + # T_c=A^{d0 d1}*B_{a d1}*C_{d0 b}; can = [2,4,0,5,3,1,6,7] + t0 = t1 = t2 = ([], [Permutation(list(range(4)))], 1, 0) + dummies = [2,3,4,5] + g = Permutation([4,2,0,3,5,1,6,7]) + can = canonicalize(g, dummies, 0, t0, t1, t2) + assert can == [2,4,0,5,3,1,6,7] + + # A symmetric, B and C without symmetry + # A^{d1 d0}*B_{a d0}*C_{d1 b} ord=[a,b,d0,-d0,d1,-d1] + # g=[4,2,0,3,5,1,6,7] + # T_c = A^{d0 d1}*B_{a d0}*C_{d1 b}; can = [2,4,0,3,5,1,6,7] + t0 = (base2,gens2,1,0) + t1 = t2 = ([], [Permutation(list(range(4)))], 1, 0) + dummies = [2,3,4,5] + g = Permutation([4,2,0,3,5,1,6,7]) + can = canonicalize(g, dummies, 0, t0, t1, t2) + assert can == [2,4,0,3,5,1,6,7] + + # A and C symmetric, B without symmetry + # A^{d1 d0}*B_{a d0}*C_{d1 b} ord=[a,b,d0,-d0,d1,-d1] + # g=[4,2,0,3,5,1,6,7] + # T_c = A^{d0 d1}*B_{a d0}*C_{b d1}; can = [2,4,0,3,1,5,6,7] + t0 = t2 = (base2,gens2,1,0) + t1 = ([], [Permutation(list(range(4)))], 1, 0) + dummies = [2,3,4,5] + g = Permutation([4,2,0,3,5,1,6,7]) + can = canonicalize(g, dummies, 0, t0, t1, t2) + assert can == [2,4,0,3,1,5,6,7] + + # A symmetric, B without symmetry, C antisymmetric + # A^{d1 d0}*B_{a d0}*C_{d1 b} ord=[a,b,d0,-d0,d1,-d1] + # g=[4,2,0,3,5,1,6,7] + # T_c = -A^{d0 d1}*B_{a d0}*C_{b d1}; can = [2,4,0,3,1,5,7,6] + t0 = (base2,gens2, 1, 0) + t1 = ([], [Permutation(list(range(4)))], 1, 0) + base2a, gens2a = get_symmetric_group_sgs(2, 1) + t2 = (base2a, gens2a, 1, 0) + dummies = [2,3,4,5] + g = Permutation([4,2,0,3,5,1,6,7]) + can = canonicalize(g, dummies, 0, t0, t1, t2) + assert can == [2,4,0,3,1,5,7,6] + + +def test_canonicalize_no_dummies(): + base1, gens1 = get_symmetric_group_sgs(1) + base2, gens2 = get_symmetric_group_sgs(2) + base2a, gens2a = get_symmetric_group_sgs(2, 1) + + # A commuting + # A^c A^b A^a; ord = [a,b,c]; g = [2,1,0,3,4] + # T_c = A^a A^b A^c; can = range(5) + g = Permutation([2,1,0,3,4]) + can = canonicalize(g, [], 0, (base1, gens1, 3, 0)) + assert can == list(range(5)) + + # A anticommuting + # A^c A^b A^a; ord = [a,b,c]; g = [2,1,0,3,4] + # T_c = -A^a A^b A^c; can = [0,1,2,4,3] + g = Permutation([2,1,0,3,4]) + can = canonicalize(g, [], 0, (base1, gens1, 3, 1)) + assert can == [0,1,2,4,3] + + # A commuting and symmetric + # A^{b,d}*A^{c,a}; ord = [a,b,c,d]; g = [1,3,2,0,4,5] + # T_c = A^{a c}*A^{b d}; can = [0,2,1,3,4,5] + g = Permutation([1,3,2,0,4,5]) + can = canonicalize(g, [], 0, (base2, gens2, 2, 0)) + assert can == [0,2,1,3,4,5] + + # A anticommuting and symmetric + # A^{b,d}*A^{c,a}; ord = [a,b,c,d]; g = [1,3,2,0,4,5] + # T_c = -A^{a c}*A^{b d}; can = [0,2,1,3,5,4] + g = Permutation([1,3,2,0,4,5]) + can = canonicalize(g, [], 0, (base2, gens2, 2, 1)) + assert can == [0,2,1,3,5,4] + # A^{c,a}*A^{b,d} ; g = [2,0,1,3,4,5] + # T_c = A^{a c}*A^{b d}; can = [0,2,1,3,4,5] + g = Permutation([2,0,1,3,4,5]) + can = canonicalize(g, [], 0, (base2, gens2, 2, 1)) + assert can == [0,2,1,3,4,5] + +def test_no_metric_symmetry(): + # no metric symmetry + # A^d1_d0 * A^d0_d1; ord = [d0,-d0,d1,-d1]; g= [2,1,0,3,4,5] + # T_c = A^d0_d1 * A^d1_d0; can = [0,3,2,1,4,5] + g = Permutation([2,1,0,3,4,5]) + can = canonicalize(g, list(range(4)), None, [[], [Permutation(list(range(4)))], 2, 0]) + assert can == [0,3,2,1,4,5] + + # A^d1_d2 * A^d0_d3 * A^d2_d1 * A^d3_d0 + # ord = [d0,-d0,d1,-d1,d2,-d2,d3,-d3] + # 0 1 2 3 4 5 6 7 + # g = [2,5,0,7,4,3,6,1,8,9] + # T_c = A^d0_d1 * A^d1_d0 * A^d2_d3 * A^d3_d2 + # can = [0,3,2,1,4,7,6,5,8,9] + g = Permutation([2,5,0,7,4,3,6,1,8,9]) + #can = canonicalize(g, range(8), 0, [[], [range(4)], 4, 0]) + #assert can == [0, 2, 3, 1, 4, 6, 7, 5, 8, 9] + can = canonicalize(g, list(range(8)), None, [[], [Permutation(list(range(4)))], 4, 0]) + assert can == [0, 3, 2, 1, 4, 7, 6, 5, 8, 9] + + # A^d0_d2 * A^d1_d3 * A^d3_d0 * A^d2_d1 + # g = [0,5,2,7,6,1,4,3,8,9] + # T_c = A^d0_d1 * A^d1_d2 * A^d2_d3 * A^d3_d0 + # can = [0,3,2,5,4,7,6,1,8,9] + g = Permutation([0,5,2,7,6,1,4,3,8,9]) + can = canonicalize(g, list(range(8)), None, [[], [Permutation(list(range(4)))], 4, 0]) + assert can == [0,3,2,5,4,7,6,1,8,9] + + g = Permutation([12,7,10,3,14,13,4,11,6,1,2,9,0,15,8,5,16,17]) + can = canonicalize(g, list(range(16)), None, [[], [Permutation(list(range(4)))], 8, 0]) + assert can == [0,3,2,5,4,7,6,1,8,11,10,13,12,15,14,9,16,17] + +def test_canonical_free(): + # t = A^{d0 a1}*A_d0^a0 + # ord = [a0,a1,d0,-d0]; g = [2,1,3,0,4,5]; dummies = [[2,3]] + # t_c = A_d0^a0*A^{d0 a1} + # can = [3,0, 2,1, 4,5] + base = [0] + gens = [Permutation(5)(0,2)(1,3)] + g = Permutation([2,1,3,0,4,5]) + num_free = 2 + dummies = [[2,3]] + can = canonicalize(g, dummies, [None], ([], [Permutation(3)], 2, 0)) + assert can == [3,0, 2,1, 4,5] + +def test_canonicalize1(): + base1, gens1 = get_symmetric_group_sgs(1) + base1a, gens1a = get_symmetric_group_sgs(1, 1) + base2, gens2 = get_symmetric_group_sgs(2) + base3, gens3 = get_symmetric_group_sgs(3) + base2a, gens2a = get_symmetric_group_sgs(2, 1) + base3a, gens3a = get_symmetric_group_sgs(3, 1) + + # A_d0*A^d0; ord = [d0,-d0]; g = [1,0,2,3] + # T_c = A^d0*A_d0; can = [0,1,2,3] + g = Permutation([1,0,2,3]) + can = canonicalize(g, [0, 1], 0, (base1, gens1, 2, 0)) + assert can == list(range(4)) + + # A commuting + # A_d0*A_d1*A_d2*A^d2*A^d1*A^d0; ord=[d0,-d0,d1,-d1,d2,-d2] + # g = [1,3,5,4,2,0,6,7] + # T_c = A^d0*A_d0*A^d1*A_d1*A^d2*A_d2; can = range(8) + g = Permutation([1,3,5,4,2,0,6,7]) + can = canonicalize(g, list(range(6)), 0, (base1, gens1, 6, 0)) + assert can == list(range(8)) + + # A anticommuting + # A_d0*A_d1*A_d2*A^d2*A^d1*A^d0; ord=[d0,-d0,d1,-d1,d2,-d2] + # g = [1,3,5,4,2,0,6,7] + # T_c 0; can = 0 + g = Permutation([1,3,5,4,2,0,6,7]) + can = canonicalize(g, list(range(6)), 0, (base1, gens1, 6, 1)) + assert can == 0 + can1 = canonicalize_naive(g, list(range(6)), 0, (base1, gens1, 6, 1)) + assert can1 == 0 + + # A commuting symmetric + # A^{d0 b}*A^a_d1*A^d1_d0; ord=[a,b,d0,-d0,d1,-d1] + # g = [2,1,0,5,4,3,6,7] + # T_c = A^{a d0}*A^{b d1}*A_{d0 d1}; can = [0,2,1,4,3,5,6,7] + g = Permutation([2,1,0,5,4,3,6,7]) + can = canonicalize(g, list(range(2,6)), 0, (base2, gens2, 3, 0)) + assert can == [0,2,1,4,3,5,6,7] + + # A, B commuting symmetric + # A^{d0 b}*A^d1_d0*B^a_d1; ord=[a,b,d0,-d0,d1,-d1] + # g = [2,1,4,3,0,5,6,7] + # T_c = A^{b d0}*A_d0^d1*B^a_d1; can = [1,2,3,4,0,5,6,7] + g = Permutation([2,1,4,3,0,5,6,7]) + can = canonicalize(g, list(range(2,6)), 0, (base2,gens2,2,0), (base2,gens2,1,0)) + assert can == [1,2,3,4,0,5,6,7] + + # A commuting symmetric + # A^{d1 d0 b}*A^{a}_{d1 d0}; ord=[a,b, d0,-d0,d1,-d1] + # g = [4,2,1,0,5,3,6,7] + # T_c = A^{a d0 d1}*A^{b}_{d0 d1}; can = [0,2,4,1,3,5,6,7] + g = Permutation([4,2,1,0,5,3,6,7]) + can = canonicalize(g, list(range(2,6)), 0, (base3, gens3, 2, 0)) + assert can == [0,2,4,1,3,5,6,7] + + + # A^{d3 d0 d2}*A^a0_{d1 d2}*A^d1_d3^a1*A^{a2 a3}_d0 + # ord = [a0,a1,a2,a3,d0,-d0,d1,-d1,d2,-d2,d3,-d3] + # 0 1 2 3 4 5 6 7 8 9 10 11 + # g = [10,4,8, 0,7,9, 6,11,1, 2,3,5, 12,13] + # T_c = A^{a0 d0 d1}*A^a1_d0^d2*A^{a2 a3 d3}*A_{d1 d2 d3} + # can = [0,4,6, 1,5,8, 2,3,10, 7,9,11, 12,13] + g = Permutation([10,4,8, 0,7,9, 6,11,1, 2,3,5, 12,13]) + can = canonicalize(g, list(range(4,12)), 0, (base3, gens3, 4, 0)) + assert can == [0,4,6, 1,5,8, 2,3,10, 7,9,11, 12,13] + + # A commuting symmetric, B antisymmetric + # A^{d0 d1 d2} * A_{d2 d3 d1} * B_d0^d3 + # ord = [d0,-d0,d1,-d1,d2,-d2,d3,-d3] + # g = [0,2,4,5,7,3,1,6,8,9] + # in this esxample and in the next three, + # renaming dummy indices and using symmetry of A, + # T = A^{d0 d1 d2} * A_{d0 d1 d3} * B_d2^d3 + # can = 0 + g = Permutation([0,2,4,5,7,3,1,6,8,9]) + can = canonicalize(g, list(range(8)), 0, (base3, gens3,2,0), (base2a,gens2a,1,0)) + assert can == 0 + # A anticommuting symmetric, B anticommuting + # A^{d0 d1 d2} * A_{d2 d3 d1} * B_d0^d3 + # T_c = A^{d0 d1 d2} * A_{d0 d1}^d3 * B_{d2 d3} + # can = [0,2,4, 1,3,6, 5,7, 8,9] + can = canonicalize(g, list(range(8)), 0, (base3, gens3,2,1), (base2a,gens2a,1,0)) + assert can == [0,2,4, 1,3,6, 5,7, 8,9] + # A anticommuting symmetric, B antisymmetric commuting, antisymmetric metric + # A^{d0 d1 d2} * A_{d2 d3 d1} * B_d0^d3 + # T_c = -A^{d0 d1 d2} * A_{d0 d1}^d3 * B_{d2 d3} + # can = [0,2,4, 1,3,6, 5,7, 9,8] + can = canonicalize(g, list(range(8)), 1, (base3, gens3,2,1), (base2a,gens2a,1,0)) + assert can == [0,2,4, 1,3,6, 5,7, 9,8] + + # A anticommuting symmetric, B anticommuting anticommuting, + # no metric symmetry + # A^{d0 d1 d2} * A_{d2 d3 d1} * B_d0^d3 + # T_c = A^{d0 d1 d2} * A_{d0 d1 d3} * B_d2^d3 + # can = [0,2,4, 1,3,7, 5,6, 8,9] + can = canonicalize(g, list(range(8)), None, (base3, gens3,2,1), (base2a,gens2a,1,0)) + assert can == [0,2,4,1,3,7,5,6,8,9] + + # Gamma anticommuting + # Gamma_{mu nu} * gamma^rho * Gamma^{nu mu alpha} + # ord = [alpha, rho, mu,-mu,nu,-nu] + # g = [3,5,1,4,2,0,6,7] + # T_c = -Gamma^{mu nu} * gamma^rho * Gamma_{alpha mu nu} + # can = [2,4,1,0,3,5,7,6]] + g = Permutation([3,5,1,4,2,0,6,7]) + t0 = (base2a, gens2a, 1, None) + t1 = (base1, gens1, 1, None) + t2 = (base3a, gens3a, 1, None) + can = canonicalize(g, list(range(2, 6)), 0, t0, t1, t2) + assert can == [2,4,1,0,3,5,7,6] + + # Gamma_{mu nu} * Gamma^{gamma beta} * gamma_rho * Gamma^{nu mu alpha} + # ord = [alpha, beta, gamma, -rho, mu,-mu,nu,-nu] + # 0 1 2 3 4 5 6 7 + # g = [5,7,2,1,3,6,4,0,8,9] + # T_c = Gamma^{mu nu} * Gamma^{beta gamma} * gamma_rho * Gamma^alpha_{mu nu} # can = [4,6,1,2,3,0,5,7,8,9] + t0 = (base2a, gens2a, 2, None) + g = Permutation([5,7,2,1,3,6,4,0,8,9]) + can = canonicalize(g, list(range(4, 8)), 0, t0, t1, t2) + assert can == [4,6,1,2,3,0,5,7,8,9] + + # f^a_{b,c} antisymmetric in b,c; A_mu^a no symmetry + # f^c_{d a} * f_{c e b} * A_mu^d * A_nu^a * A^{nu e} * A^{mu b} + # ord = [mu,-mu,nu,-nu,a,-a,b,-b,c,-c,d,-d, e, -e] + # 0 1 2 3 4 5 6 7 8 9 10 11 12 13 + # g = [8,11,5, 9,13,7, 1,10, 3,4, 2,12, 0,6, 14,15] + # T_c = -f^{a b c} * f_a^{d e} * A^mu_b * A_{mu d} * A^nu_c * A_{nu e} + # can = [4,6,8, 5,10,12, 0,7, 1,11, 2,9, 3,13, 15,14] + g = Permutation([8,11,5, 9,13,7, 1,10, 3,4, 2,12, 0,6, 14,15]) + base_f, gens_f = bsgs_direct_product(base1, gens1, base2a, gens2a) + base_A, gens_A = bsgs_direct_product(base1, gens1, base1, gens1) + t0 = (base_f, gens_f, 2, 0) + t1 = (base_A, gens_A, 4, 0) + can = canonicalize(g, [list(range(4)), list(range(4, 14))], [0, 0], t0, t1) + assert can == [4,6,8, 5,10,12, 0,7, 1,11, 2,9, 3,13, 15,14] + + +def test_riemann_invariants(): + baser, gensr = riemann_bsgs + # R^{d0 d1}_{d1 d0}; ord = [d0,-d0,d1,-d1]; g = [0,2,3,1,4,5] + # T_c = -R^{d0 d1}_{d0 d1}; can = [0,2,1,3,5,4] + g = Permutation([0,2,3,1,4,5]) + can = canonicalize(g, list(range(2, 4)), 0, (baser, gensr, 1, 0)) + assert can == [0,2,1,3,5,4] + # use a non minimal BSGS + can = canonicalize(g, list(range(2, 4)), 0, ([2, 0], [Permutation([1,0,2,3,5,4]), Permutation([2,3,0,1,4,5])], 1, 0)) + assert can == [0,2,1,3,5,4] + + """ + The following tests in test_riemann_invariants and in + test_riemann_invariants1 have been checked using xperm.c from XPerm in + in [1] and with an older version contained in [2] + + [1] xperm.c part of xPerm written by J. M. Martin-Garcia + http://www.xact.es/index.html + [2] test_xperm.cc in cadabra by Kasper Peeters, http://cadabra.phi-sci.com/ + """ + # R_d11^d1_d0^d5 * R^{d6 d4 d0}_d5 * R_{d7 d2 d8 d9} * + # R_{d10 d3 d6 d4} * R^{d2 d7 d11}_d1 * R^{d8 d9 d3 d10} + # ord: contravariant d_k ->2*k, covariant d_k -> 2*k+1 + # T_c = R^{d0 d1 d2 d3} * R_{d0 d1}^{d4 d5} * R_{d2 d3}^{d6 d7} * + # R_{d4 d5}^{d8 d9} * R_{d6 d7}^{d10 d11} * R_{d8 d9 d10 d11} + g = Permutation([23,2,1,10,12,8,0,11,15,5,17,19,21,7,13,9,4,14,22,3,16,18,6,20,24,25]) + can = canonicalize(g, list(range(24)), 0, (baser, gensr, 6, 0)) + assert can == [0,2,4,6,1,3,8,10,5,7,12,14,9,11,16,18,13,15,20,22,17,19,21,23,24,25] + + # use a non minimal BSGS + can = canonicalize(g, list(range(24)), 0, ([2, 0], [Permutation([1,0,2,3,5,4]), Permutation([2,3,0,1,4,5])], 6, 0)) + assert can == [0,2,4,6,1,3,8,10,5,7,12,14,9,11,16,18,13,15,20,22,17,19,21,23,24,25] + + g = Permutation([0,2,5,7,4,6,9,11,8,10,13,15,12,14,17,19,16,18,21,23,20,22,25,27,24,26,29,31,28,30,33,35,32,34,37,39,36,38,1,3,40,41]) + can = canonicalize(g, list(range(40)), 0, (baser, gensr, 10, 0)) + assert can == [0,2,4,6,1,3,8,10,5,7,12,14,9,11,16,18,13,15,20,22,17,19,24,26,21,23,28,30,25,27,32,34,29,31,36,38,33,35,37,39,40,41] + + +@XFAIL +def test_riemann_invariants1(): + skip('takes too much time') + baser, gensr = riemann_bsgs + g = Permutation([17, 44, 11, 3, 0, 19, 23, 15, 38, 4, 25, 27, 43, 36, 22, 14, 8, 30, 41, 20, 2, 10, 12, 28, 18, 1, 29, 13, 37, 42, 33, 7, 9, 31, 24, 26, 39, 5, 34, 47, 32, 6, 21, 40, 35, 46, 45, 16, 48, 49]) + can = canonicalize(g, list(range(48)), 0, (baser, gensr, 12, 0)) + assert can == [0, 2, 4, 6, 1, 3, 8, 10, 5, 7, 12, 14, 9, 11, 16, 18, 13, 15, 20, 22, 17, 19, 24, 26, 21, 23, 28, 30, 25, 27, 32, 34, 29, 31, 36, 38, 33, 35, 40, 42, 37, 39, 44, 46, 41, 43, 45, 47, 48, 49] + + g = Permutation([0,2,4,6, 7,8,10,12, 14,16,18,20, 19,22,24,26, 5,21,28,30, 32,34,36,38, 40,42,44,46, 13,48,50,52, 15,49,54,56, 17,33,41,58, 9,23,60,62, 29,35,63,64, 3,45,66,68, 25,37,47,57, 11,31,69,70, 27,39,53,72, 1,59,73,74, 55,61,67,76, 43,65,75,78, 51,71,77,79, 80,81]) + can = canonicalize(g, list(range(80)), 0, (baser, gensr, 20, 0)) + assert can == [0,2,4,6, 1,8,10,12, 3,14,16,18, 5,20,22,24, 7,26,28,30, 9,15,32,34, 11,36,23,38, 13,40,42,44, 17,39,29,46, 19,48,43,50, 21,45,52,54, 25,56,33,58, 27,60,53,62, 31,51,64,66, 35,65,47,68, 37,70,49,72, 41,74,57,76, 55,67,59,78, 61,69,71,75, 63,79,73,77, 80,81] + + +def test_riemann_products(): + baser, gensr = riemann_bsgs + base1, gens1 = get_symmetric_group_sgs(1) + base2, gens2 = get_symmetric_group_sgs(2) + base2a, gens2a = get_symmetric_group_sgs(2, 1) + + # R^{a b d0}_d0 = 0 + g = Permutation([0,1,2,3,4,5]) + can = canonicalize(g, list(range(2,4)), 0, (baser, gensr, 1, 0)) + assert can == 0 + + # R^{d0 b a}_d0 ; ord = [a,b,d0,-d0}; g = [2,1,0,3,4,5] + # T_c = -R^{a d0 b}_d0; can = [0,2,1,3,5,4] + g = Permutation([2,1,0,3,4,5]) + can = canonicalize(g, list(range(2, 4)), 0, (baser, gensr, 1, 0)) + assert can == [0,2,1,3,5,4] + + # R^d1_d2^b_d0 * R^{d0 a}_d1^d2; ord=[a,b,d0,-d0,d1,-d1,d2,-d2] + # g = [4,7,1,3,2,0,5,6,8,9] + # T_c = -R^{a d0 d1 d2}* R^b_{d0 d1 d2} + # can = [0,2,4,6,1,3,5,7,9,8] + g = Permutation([4,7,1,3,2,0,5,6,8,9]) + can = canonicalize(g, list(range(2,8)), 0, (baser, gensr, 2, 0)) + assert can == [0,2,4,6,1,3,5,7,9,8] + can1 = canonicalize_naive(g, list(range(2,8)), 0, (baser, gensr, 2, 0)) + assert can == can1 + + # A symmetric commuting + # R^{d6 d5}_d2^d1 * R^{d4 d0 d2 d3} * A_{d6 d0} A_{d3 d1} * A_{d4 d5} + # g = [12,10,5,2, 8,0,4,6, 13,1, 7,3, 9,11,14,15] + # T_c = -R^{d0 d1 d2 d3} * R_d0^{d4 d5 d6} * A_{d1 d4}*A_{d2 d5}*A_{d3 d6} + + g = Permutation([12,10,5,2,8,0,4,6,13,1,7,3,9,11,14,15]) + can = canonicalize(g, list(range(14)), 0, ((baser,gensr,2,0)), (base2,gens2,3,0)) + assert can == [0, 2, 4, 6, 1, 8, 10, 12, 3, 9, 5, 11, 7, 13, 15, 14] + + # R^{d2 a0 a2 d0} * R^d1_d2^{a1 a3} * R^{a4 a5}_{d0 d1} + # ord = [a0,a1,a2,a3,a4,a5,d0,-d0,d1,-d1,d2,-d2] + # 0 1 2 3 4 5 6 7 8 9 10 11 + # can = [0, 6, 2, 8, 1, 3, 7, 10, 4, 5, 9, 11, 12, 13] + # T_c = R^{a0 d0 a2 d1}*R^{a1 a3}_d0^d2*R^{a4 a5}_{d1 d2} + g = Permutation([10,0,2,6,8,11,1,3,4,5,7,9,12,13]) + can = canonicalize(g, list(range(6,12)), 0, (baser, gensr, 3, 0)) + assert can == [0, 6, 2, 8, 1, 3, 7, 10, 4, 5, 9, 11, 12, 13] + #can1 = canonicalize_naive(g, range(6,12), 0, (baser, gensr, 3, 0)) + #assert can == can1 + + # A^n_{i, j} antisymmetric in i,j + # A_m0^d0_a1 * A_m1^a0_d0; ord = [m0,m1,a0,a1,d0,-d0] + # g = [0,4,3,1,2,5,6,7] + # T_c = -A_{m a1}^d0 * A_m1^a0_d0 + # can = [0,3,4,1,2,5,7,6] + base, gens = bsgs_direct_product(base1, gens1, base2a, gens2a) + dummies = list(range(4, 6)) + g = Permutation([0,4,3,1,2,5,6,7]) + can = canonicalize(g, dummies, 0, (base, gens, 2, 0)) + assert can == [0, 3, 4, 1, 2, 5, 7, 6] + + + # A^n_{i, j} symmetric in i,j + # A^m0_a0^d2 * A^n0_d2^d1 * A^n1_d1^d0 * A_{m0 d0}^a1 + # ordering: first the free indices; then first n, then d + # ord=[n0,n1,a0,a1, m0,-m0,d0,-d0,d1,-d1,d2,-d2] + # 0 1 2 3 4 5 6 7 8 9 10 11] + # g = [4,2,10, 0,11,8, 1,9,6, 5,7,3, 12,13] + # if the dummy indices m_i and d_i were separated, + # one gets + # T_c = A^{n0 d0 d1} * A^n1_d0^d2 * A^m0^a0_d1 * A_m0^a1_d2 + # can = [0, 6, 8, 1, 7, 10, 4, 2, 9, 5, 3, 11, 12, 13] + # If they are not, so can is + # T_c = A^{n0 m0 d0} A^n1_m0^d1 A^{d2 a0}_d0 A_d2^a1_d1 + # can = [0, 4, 6, 1, 5, 8, 10, 2, 7, 11, 3, 9, 12, 13] + # case with single type of indices + + base, gens = bsgs_direct_product(base1, gens1, base2, gens2) + dummies = list(range(4, 12)) + g = Permutation([4,2,10, 0,11,8, 1,9,6, 5,7,3, 12,13]) + can = canonicalize(g, dummies, 0, (base, gens, 4, 0)) + assert can == [0, 4, 6, 1, 5, 8, 10, 2, 7, 11, 3, 9, 12, 13] + # case with separated indices + dummies = [list(range(4, 6)), list(range(6,12))] + sym = [0, 0] + can = canonicalize(g, dummies, sym, (base, gens, 4, 0)) + assert can == [0, 6, 8, 1, 7, 10, 4, 2, 9, 5, 3, 11, 12, 13] + # case with separated indices with the second type of index + # with antisymmetric metric: there is a sign change + sym = [0, 1] + can = canonicalize(g, dummies, sym, (base, gens, 4, 0)) + assert can == [0, 6, 8, 1, 7, 10, 4, 2, 9, 5, 3, 11, 13, 12] + +def test_graph_certificate(): + # test tensor invariants constructed from random regular graphs; + # checked graph isomorphism with networkx + import random + def randomize_graph(size, g): + p = list(range(size)) + random.shuffle(p) + g1a = {} + for k, v in list(g1.items()): + g1a[p[k]] = [p[i] for i in v] + return g1a + + g1 = {0: [2, 3, 7], 1: [4, 5, 7], 2: [0, 4, 6], 3: [0, 6, 7], 4: [1, 2, 5], 5: [1, 4, 6], 6: [2, 3, 5], 7: [0, 1, 3]} + g2 = {0: [2, 3, 7], 1: [2, 4, 5], 2: [0, 1, 5], 3: [0, 6, 7], 4: [1, 5, 6], 5: [1, 2, 4], 6: [3, 4, 7], 7: [0, 3, 6]} + + c1 = graph_certificate(g1) + c2 = graph_certificate(g2) + assert c1 != c2 + g1a = randomize_graph(8, g1) + c1a = graph_certificate(g1a) + assert c1 == c1a + + g1 = {0: [8, 1, 9, 7], 1: [0, 9, 3, 4], 2: [3, 4, 6, 7], 3: [1, 2, 5, 6], 4: [8, 1, 2, 5], 5: [9, 3, 4, 7], 6: [8, 2, 3, 7], 7: [0, 2, 5, 6], 8: [0, 9, 4, 6], 9: [8, 0, 5, 1]} + g2 = {0: [1, 2, 5, 6], 1: [0, 9, 5, 7], 2: [0, 4, 6, 7], 3: [8, 9, 6, 7], 4: [8, 2, 6, 7], 5: [0, 9, 8, 1], 6: [0, 2, 3, 4], 7: [1, 2, 3, 4], 8: [9, 3, 4, 5], 9: [8, 1, 3, 5]} + c1 = graph_certificate(g1) + c2 = graph_certificate(g2) + assert c1 != c2 + g1a = randomize_graph(10, g1) + c1a = graph_certificate(g1a) + assert c1 == c1a diff -Nru python3-sympy-0.7.2/sympy/combinatorics/tests/test_testutil.py python3-sympy-0.7.3/sympy/combinatorics/tests/test_testutil.py --- python3-sympy-0.7.2/sympy/combinatorics/tests/test_testutil.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/combinatorics/tests/test_testutil.py 2013-07-13 17:53:31.000000000 +0000 @@ -1,8 +1,8 @@ from sympy.combinatorics.named_groups import SymmetricGroup, AlternatingGroup,\ -CyclicGroup + CyclicGroup from sympy.combinatorics.testutil import _verify_bsgs, _cmp_perm_lists,\ -_naive_list_centralizer, _verify_centralizer,\ -_verify_normal_closure + _naive_list_centralizer, _verify_centralizer,\ + _verify_normal_closure from sympy.combinatorics.permutations import Permutation from sympy.combinatorics.perm_groups import PermutationGroup from random import shuffle @@ -13,7 +13,8 @@ els = list(S.generate_dimino()) other = els[:] shuffle(other) - assert _cmp_perm_lists(els, other) == True + assert _cmp_perm_lists(els, other) is True + def test_naive_list_centralizer(): # verified by GAP @@ -22,14 +23,16 @@ assert _naive_list_centralizer(S, S) == [Permutation([0, 1, 2])] assert PermutationGroup(_naive_list_centralizer(S, A)).is_subgroup(A) + def test_verify_bsgs(): S = SymmetricGroup(5) S.schreier_sims() base = S.base strong_gens = S.strong_gens - assert _verify_bsgs(S, base, strong_gens) == True - assert _verify_bsgs(S, base[:-1], strong_gens) == False - assert _verify_bsgs(S, base, S.generators) == False + assert _verify_bsgs(S, base, strong_gens) is True + assert _verify_bsgs(S, base[:-1], strong_gens) is False + assert _verify_bsgs(S, base, S.generators) is False + def test_verify_centralizer(): # verified by GAP @@ -39,6 +42,7 @@ assert _verify_centralizer(S, S, centr=triv) assert _verify_centralizer(S, A, centr=A) + def test_verify_normal_closure(): # verified by GAP S = SymmetricGroup(3) diff -Nru python3-sympy-0.7.2/sympy/combinatorics/tests/test_util.py python3-sympy-0.7.3/sympy/combinatorics/tests/test_util.py --- python3-sympy-0.7.2/sympy/combinatorics/tests/test_util.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/combinatorics/tests/test_util.py 2013-07-13 17:53:31.000000000 +0000 @@ -1,19 +1,21 @@ from sympy.combinatorics.named_groups import SymmetricGroup, DihedralGroup,\ -AlternatingGroup + AlternatingGroup from sympy.combinatorics.permutations import Permutation from sympy.combinatorics.util import _check_cycles_alt_sym, _strip,\ -_distribute_gens_by_base, _strong_gens_from_distr,\ -_orbits_transversals_from_bsgs, _handle_precomputed_bsgs, _base_ordering,\ -_remove_gens + _distribute_gens_by_base, _strong_gens_from_distr,\ + _orbits_transversals_from_bsgs, _handle_precomputed_bsgs, _base_ordering,\ + _remove_gens from sympy.combinatorics.testutil import _verify_bsgs + def test_check_cycles_alt_sym(): perm1 = Permutation([[0, 1, 2, 3, 4, 5, 6], [7], [8], [9]]) perm2 = Permutation([[0, 1, 2, 3, 4, 5], [6, 7, 8, 9]]) perm3 = Permutation([[0, 1, 2, 3, 4], [5, 6, 7, 8, 9]]) - assert _check_cycles_alt_sym(perm1) == True - assert _check_cycles_alt_sym(perm2) == False - assert _check_cycles_alt_sym(perm3) == False + assert _check_cycles_alt_sym(perm1) is True + assert _check_cycles_alt_sym(perm2) is False + assert _check_cycles_alt_sym(perm3) is False + def test_strip(): D = DihedralGroup(5) @@ -32,24 +34,27 @@ assert res3[0] != identity assert res3[1] == 2 + def test_distribute_gens_by_base(): base = [0, 1, 2] - gens = [Permutation([0, 1, 2, 3]), Permutation([0, 1, 3, 2]),\ + gens = [Permutation([0, 1, 2, 3]), Permutation([0, 1, 3, 2]), Permutation([0, 2, 3, 1]), Permutation([3, 2, 1, 0])] - assert _distribute_gens_by_base(base, gens) == [gens,\ - [Permutation([0, 1, 2, 3]),\ - Permutation([0, 1, 3, 2]),\ - Permutation([0, 2, 3, 1])],\ - [Permutation([0, 1, 2, 3]),\ + assert _distribute_gens_by_base(base, gens) == [gens, + [Permutation([0, 1, 2, 3]), + Permutation([0, 1, 3, 2]), + Permutation([0, 2, 3, 1])], + [Permutation([0, 1, 2, 3]), Permutation([0, 1, 3, 2])]] + def test_strong_gens_from_distr(): - strong_gens_distr = [[Permutation([0, 2, 1]), Permutation([1, 2, 0]),\ + strong_gens_distr = [[Permutation([0, 2, 1]), Permutation([1, 2, 0]), Permutation([1, 0, 2])], [Permutation([0, 2, 1])]] - assert _strong_gens_from_distr(strong_gens_distr) ==\ - [Permutation([0, 2, 1]),\ - Permutation([1, 2, 0]),\ - Permutation([1, 0, 2])] + assert _strong_gens_from_distr(strong_gens_distr) == \ + [Permutation([0, 2, 1]), + Permutation([1, 2, 0]), + Permutation([1, 0, 2])] + def test_orbits_transversals_from_bsgs(): S = SymmetricGroup(4) @@ -71,6 +76,7 @@ order *= len(orbits[i]) assert S.order() == order + def test_handle_precomputed_bsgs(): A = AlternatingGroup(5) A.schreier_sims() @@ -92,21 +98,23 @@ order *= len(orbits[i]) assert A.order() == order + def test_base_ordering(): base = [2, 4, 5] degree = 7 assert _base_ordering(base, degree) == [3, 4, 0, 5, 1, 2, 6] + def test_remove_gens(): S = SymmetricGroup(10) base, strong_gens = S.schreier_sims_incremental() new_gens = _remove_gens(base, strong_gens) - assert _verify_bsgs(S, base, new_gens) == True + assert _verify_bsgs(S, base, new_gens) is True A = AlternatingGroup(7) base, strong_gens = A.schreier_sims_incremental() new_gens = _remove_gens(base, strong_gens) - assert _verify_bsgs(A, base, new_gens) == True + assert _verify_bsgs(A, base, new_gens) is True D = DihedralGroup(2) base, strong_gens = D.schreier_sims_incremental() new_gens = _remove_gens(base, strong_gens) - assert _verify_bsgs(D, base, new_gens) == True + assert _verify_bsgs(D, base, new_gens) is True diff -Nru python3-sympy-0.7.2/sympy/combinatorics/testutil.py python3-sympy-0.7.3/sympy/combinatorics/testutil.py --- python3-sympy-0.7.2/sympy/combinatorics/testutil.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/combinatorics/testutil.py 2013-07-13 17:53:31.000000000 +0000 @@ -3,6 +3,7 @@ rmul = Permutation.rmul + def _cmp_perm_lists(first, second): """ Compare two lists of permutations as sets. @@ -26,9 +27,10 @@ """ return set([tuple(a) for a in first]) == \ - set([tuple(a) for a in second]) + set([tuple(a) for a in second]) + -def _naive_list_centralizer(self, other): +def _naive_list_centralizer(self, other, af=False): from sympy.combinatorics.perm_groups import PermutationGroup """ Return a list of elements for the centralizer of a subgroup/set/element. @@ -51,20 +53,25 @@ sympy.combinatorics.perm_groups.centralizer """ + from sympy.combinatorics.permutations import _af_commutes_with if hasattr(other, 'generators'): - elements = list(self.generate_dimino()) - gens = other.generators - commutes_with_gens = lambda x: [rmul(x, gen) for gen in gens] ==\ - [rmul(gen, x) for gen in gens] + elements = list(self.generate_dimino(af=True)) + gens = [x._array_form for x in other.generators] + commutes_with_gens = lambda x: all(_af_commutes_with(x, gen) for gen in gens) centralizer_list = [] - for element in elements: - if commutes_with_gens(element): - centralizer_list.append(element) + if not af: + for element in elements: + if commutes_with_gens(element): + centralizer_list.append(Permutation._af_new(element)) + else: + for element in elements: + if commutes_with_gens(element): + centralizer_list.append(element) return centralizer_list elif hasattr(other, 'getitem'): - return _naive_list_centralizer(self, PermutationGroup(other)) + return _naive_list_centralizer(self, PermutationGroup(other), af) elif hasattr(other, 'array_form'): - return _naive_list_centralizer(self, PermutationGroup([other])) + return _naive_list_centralizer(self, PermutationGroup([other]), af) def _verify_bsgs(group, base, gens): """ @@ -103,6 +110,7 @@ return False return True + def _verify_centralizer(group, arg, centr=None): """ Verify the centralizer of a group/set/element inside another group. @@ -127,17 +135,18 @@ See Also ======== - _naive_list_centralizer,\ - sympy.combinatorics.perm_groups.PermutationGroup.centralizer,\ + _naive_list_centralizer, + sympy.combinatorics.perm_groups.PermutationGroup.centralizer, _cmp_perm_lists """ if centr is None: centr = group.centralizer(arg) - centr_list = list(centr.generate_dimino()) - centr_list_naive = _naive_list_centralizer(group, arg) + centr_list = list(centr.generate_dimino(af=True)) + centr_list_naive = _naive_list_centralizer(group, arg, af=True) return _cmp_perm_lists(centr_list, centr_list_naive) + def _verify_normal_closure(group, arg, closure=None): from sympy.combinatorics.perm_groups import PermutationGroup """ @@ -149,7 +158,7 @@ Examples ======== - >>> from sympy.combinatorics.named_groups import (SymmetricGroup,\ + >>> from sympy.combinatorics.named_groups import (SymmetricGroup, ... AlternatingGroup) >>> from sympy.combinatorics.testutil import _verify_normal_closure >>> S = SymmetricGroup(3) @@ -165,18 +174,157 @@ """ if closure is None: closure = group.normal_closure(arg) - conjugates = [] - group_els = list(group.generate_dimino()) + conjugates = set() if hasattr(arg, 'generators'): subgr_gens = arg.generators elif hasattr(arg, '__getitem__'): subgr_gens = arg elif hasattr(arg, 'array_form'): subgr_gens = [arg] - for el in group_els: + for el in group.generate_dimino(): for gen in subgr_gens: - conjugate = rmul(~el, gen, el) - if conjugate not in conjugates: - conjugates.append(conjugate) - naive_closure = PermutationGroup(conjugates) + conjugates.add(gen^el) + naive_closure = PermutationGroup(list(conjugates)) return closure.is_subgroup(naive_closure) + +def canonicalize_naive(g, dummies, sym, *v): + """ + canonicalize tensor formed by tensors of the different types + + g permutation representing the tensor + dummies list of dummy indices + msym symmetry of the metric + + v is a list of (base_i, gens_i, n_i, sym_i) for tensors of type `i` + base_i, gens_i BSGS for tensors of this type + n_i number ot tensors of type `i` + + sym_i symmetry under exchange of two component tensors of type `i` + None no symmetry + 0 commuting + 1 anticommuting + + Return 0 if the tensor is zero, else return the array form of + the permutation representing the canonical form of the tensor. + + Examples + ======== + >>> from sympy.combinatorics.testutil import canonicalize_naive + >>> from sympy.combinatorics.tensor_can import get_symmetric_group_sgs + >>> from sympy.combinatorics import Permutation, PermutationGroup + >>> g = Permutation([1,3,2,0,4,5]) + >>> base2, gens2 = get_symmetric_group_sgs(2) + >>> canonicalize_naive(g, [2, 3], 0, (base2, gens2, 2, 0)) + [0, 2, 1, 3, 4, 5] + """ + from sympy.combinatorics.perm_groups import PermutationGroup + from sympy.combinatorics.tensor_can import gens_products, dummy_sgs + from sympy.combinatorics.permutations import Permutation, _af_rmul + v1 = [] + for i in range(len(v)): + base_i, gens_i, n_i, sym_i = v[i] + v1.append((base_i, gens_i, [[]]*n_i, sym_i)) + size, sbase, sgens = gens_products(*v1) + dgens = dummy_sgs(dummies, sym, size-2) + if isinstance(sym, int): + num_types = 1 + dummies = [dummies] + sym = [sym] + else: + num_types = len(sym) + dgens = [] + for i in range(num_types): + dgens.extend(dummy_sgs(dummies[i], sym[i], size - 2)) + S = PermutationGroup(sgens) + D = PermutationGroup([Permutation(x) for x in dgens]) + dlist = list(D.generate(af=True)) + g = g.array_form + st = set() + for s in S.generate(af=True): + h = _af_rmul(g, s) + for d in dlist: + q = tuple(_af_rmul(d, h)) + st.add(q) + a = list(st) + a.sort() + prev = (0,)*size + for h in a: + if h[:-2] == prev[:-2]: + if h[-1] != prev[-1]: + return 0 + prev = h + return list(a[0]) + +def graph_certificate(gr): + """ + Return a certificate for the graph + + gr adjacency list + + The graph is assumed to be unoriented and without + external lines. + + Associate to each vertex of the graph a symmetric tensor with + number of indices equal to the degree of the vertex; indices + are contracted when they correspond to the same line of the graph. + The canonical form of the tensor gives a certificate for the graph. + + This is not an efficient algorithm to get the certificate of a graph. + + Examples + ======== + + >>> from sympy.combinatorics.testutil import graph_certificate + >>> gr1 = {0:[1,2,3,5], 1:[0,2,4], 2:[0,1,3,4], 3:[0,2,4], 4:[1,2,3,5], 5:[0,4]} + >>> gr2 = {0:[1,5], 1:[0,2,3,4], 2:[1,3,5], 3:[1,2,4,5], 4:[1,3,5], 5:[0,2,3,4]} + >>> c1 = graph_certificate(gr1) + >>> c2 = graph_certificate(gr2) + >>> c1 + [0, 2, 4, 6, 1, 8, 10, 12, 3, 14, 16, 18, 5, 9, 15, 7, 11, 17, 13, 19, 20, 21] + >>> c1 == c2 + True + """ + from sympy.combinatorics.permutations import _af_invert + from sympy.combinatorics.tensor_can import get_symmetric_group_sgs, canonicalize + items = list(gr.items()) + items.sort(key=lambda x: len(x[1]), reverse=True) + pvert = [x[0] for x in items] + pvert = _af_invert(pvert) + + # the indices of the tensor are twice the number of lines of the graph + num_indices = 0 + for v, neigh in items: + num_indices += len(neigh) + # associate to each vertex its indices; for each line + # between two vertices assign the + # even index to the vertex which comes first in items, + # the odd index to the other vertex + vertices = [[] for i in items] + i = 0 + for v, neigh in items: + for v2 in neigh: + if pvert[v] < pvert[v2]: + vertices[pvert[v]].append(i) + vertices[pvert[v2]].append(i+1) + i += 2 + g = [] + for v in vertices: + g.extend(v) + assert len(g) == num_indices + g += [num_indices, num_indices + 1] + size = num_indices + 2 + assert sorted(g) == list(range(size)) + g = Permutation(g) + vlen = [0]*(len(vertices[0])+1) + for neigh in vertices: + vlen[len(neigh)] += 1 + v = [] + for i in range(len(vlen)): + n = vlen[i] + if n: + base, gens = get_symmetric_group_sgs(i) + v.append((base, gens, n, 0)) + v.reverse() + dummies = list(range(num_indices)) + can = canonicalize(g, dummies, 0, *v) + return can diff -Nru python3-sympy-0.7.2/sympy/combinatorics/util.py python3-sympy-0.7.3/sympy/combinatorics/util.py --- python3-sympy-0.7.2/sympy/combinatorics/util.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/combinatorics/util.py 2013-07-13 17:53:32.000000000 +0000 @@ -65,6 +65,7 @@ current += 1 return ordering + def _check_cycles_alt_sym(perm): """ Checks for cycles of prime length p with n/2 < p < n-2. @@ -105,10 +106,11 @@ j = af[j] used.add(j) total_len += current_len - if current_len > n//2 and current_len < n-2 and isprime(current_len): + if current_len > n//2 and current_len < n - 2 and isprime(current_len): return True return False + def _distribute_gens_by_base(base, gens): """ Distribute the group elements ``gens`` by membership in basic stabilizers. @@ -158,25 +160,22 @@ """ base_len = len(base) - stabs = [] degree = gens[0].size - for i in range(base_len): - stabs.append([]) - num_gens = len(gens) + stabs = [[] for _ in range(base_len)] max_stab_index = 0 - for i in range(num_gens): + for gen in gens: j = 0 - while j < base_len - 1 and gens[i](base[j]) == base[j]: + while j < base_len - 1 and gen._array_form[base[j]] == base[j]: j += 1 if j > max_stab_index: max_stab_index = j for k in range(j + 1): - stabs[k].append(gens[i]) + stabs[k].append(gen) for i in range(max_stab_index + 1, base_len): stabs[i].append(_af_new(list(range(degree)))) return stabs -def _handle_precomputed_bsgs(base, strong_gens, transversals=None,\ +def _handle_precomputed_bsgs(base, strong_gens, transversals=None, basic_orbits=None, strong_gens_distr=None): """ Calculate BSGS-related structures from those present. @@ -216,8 +215,10 @@ ... basic_orbits=D.basic_orbits) ([{0: Permutation(2), 1: Permutation(0, 1, 2), 2: Permutation(0, 2)}, {1: Permutation(2), 2: Permutation(1, 2)}], - [[0, 1, 2], [1, 2]], [[Permutation(0, 1, 2), Permutation(0, 2), Permutation(1, 2)], - [Permutation(1, 2)]]) + [[0, 1, 2], [1, 2]], [[Permutation(0, 1, 2), + Permutation(0, 2), + Permutation(1, 2)], + [Permutation(1, 2)]]) See Also ======== @@ -229,11 +230,11 @@ strong_gens_distr = _distribute_gens_by_base(base, strong_gens) if transversals is None: if basic_orbits is None: - basic_orbits, transversals =\ - _orbits_transversals_from_bsgs(base, strong_gens_distr) + basic_orbits, transversals = \ + _orbits_transversals_from_bsgs(base, strong_gens_distr) else: - transversals =\ - _orbits_transversals_from_bsgs(base, strong_gens_distr, + transversals = \ + _orbits_transversals_from_bsgs(base, strong_gens_distr, transversals_only=True) else: if basic_orbits is None: @@ -243,7 +244,8 @@ basic_orbits[i] = list(transversals[i].keys()) return transversals, basic_orbits, strong_gens_distr -def _orbits_transversals_from_bsgs(base, strong_gens_distr,\ + +def _orbits_transversals_from_bsgs(base, strong_gens_distr, transversals_only=False): """ Compute basic orbits and transversals from a base and strong generating set. @@ -284,14 +286,15 @@ _distribute_gens_by_base, _handle_precomputed_bsgs """ - from sympy.combinatorics.perm_groups import PermutationGroup + from sympy.combinatorics.perm_groups import _orbit_transversal base_len = len(base) + degree = strong_gens_distr[0][0].size transversals = [None]*base_len if transversals_only is False: basic_orbits = [None]*base_len for i in range(base_len): - group = PermutationGroup(strong_gens_distr[i]) - transversals[i] = dict(group.orbit_transversal(base[i], pairs=True)) + transversals[i] = dict(_orbit_transversal(degree, strong_gens_distr[i], + base[i], pairs=True)) if transversals_only is False: basic_orbits[i] = list(transversals[i].keys()) if transversals_only: @@ -299,6 +302,7 @@ else: return basic_orbits, transversals + def _remove_gens(base, strong_gens, basic_orbits=None, strong_gens_distr=None): """ Remove redundant generators from a strong generating set. @@ -347,15 +351,16 @@ "Handbook of computational group theory" """ - from sympy.combinatorics.perm_groups import PermutationGroup + from sympy.combinatorics.perm_groups import PermutationGroup, _orbit base_len = len(base) + degree = strong_gens[0].size if strong_gens_distr is None: strong_gens_distr = _distribute_gens_by_base(base, strong_gens) + temp = strong_gens_distr[:] if basic_orbits is None: basic_orbits = [] for i in range(base_len): - stab = PermutationGroup(strong_gens_distr[i]) - basic_orbit = stab.orbit(base[i]) + basic_orbit = _orbit(degree, strong_gens_distr[i], base[i]) basic_orbits.append(basic_orbit) strong_gens_distr.append([]) res = strong_gens[:] @@ -367,8 +372,7 @@ temp_gens.remove(gen) if temp_gens == []: continue - temp_group = PermutationGroup(temp_gens) - temp_orbit = temp_group.orbit(base[i]) + temp_orbit = _orbit(degree, temp_gens, base[i]) if temp_orbit == basic_orbits[i]: gens_copy.remove(gen) res.remove(gen) @@ -439,7 +443,7 @@ sympy.combinatorics.perm_groups.PermutationGroup.schreier_sims_random """ - h = g.array_form + h = g._array_form base_len = len(base) for i in range(base_len): beta = h[base[i]] @@ -447,10 +451,30 @@ continue if beta not in orbits[i]: return _af_new(h), i + 1 - u = transversals[i][beta].array_form + u = transversals[i][beta]._array_form h = _af_rmul(_af_invert(u), h) return _af_new(h), base_len + 1 +def _strip_af(h, base, orbits, transversals, j): + """ + optimized _strip, with h, transversals and result in array form + if the stripped elements is the identity, it returns False, base_len + 1 + + j h[base[i]] == base[i] for i <= j + """ + base_len = len(base) + for i in range(j+1, base_len): + beta = h[base[i]] + if beta == base[i]: + continue + if beta not in orbits[i]: + return h, i + 1 + u = transversals[i][beta] + if h == u: + return False, base_len + 1 + h = _af_rmul(_af_invert(u), h) + return h, base_len + 1 + def _strong_gens_from_distr(strong_gens_distr): """ Retrieve strong generating set from generators of basic stabilizers. diff -Nru python3-sympy-0.7.2/sympy/concrete/delta.py python3-sympy-0.7.3/sympy/concrete/delta.py --- python3-sympy-0.7.2/sympy/concrete/delta.py 1970-01-01 00:00:00.000000000 +0000 +++ python3-sympy-0.7.3/sympy/concrete/delta.py 2013-07-13 17:53:32.000000000 +0000 @@ -0,0 +1,301 @@ +from sympy.core import Add, Interval, Mul, S, Dummy, symbols +from sympy.core.compatibility import default_sort_key +from sympy.functions import KroneckerDelta, Piecewise, piecewise_fold + + +def _expand_delta(expr, index): + """ + Expand the first Add containing a simple KroneckerDelta. + """ + if not expr.is_Mul: + return expr + delta = None + terms = [S(1)] + for h in expr.args: + if delta is None and h.is_Add and _has_simple_delta(h, index): + delta = True + terms = [terms[0]*t for t in h.args] + else: + terms = [t*h for t in terms] + return Add(*terms) + + +def _extract_delta(expr, index): + """ + Extract a simple KroneckerDelta from the expression. + + Returns the tuple ``(delta, newexpr)`` where: + + - ``delta`` is a simple KroneckerDelta expression if one was found, + or ``None`` if no simple KroneckerDelta expression was found. + + - ``newexpr`` is a Mul containing the remaining terms; ``expr`` is + returned unchanged if no simple KroneckerDelta expression was found. + + Examples + ======== + + >>> from sympy import KroneckerDelta + >>> from sympy.concrete.delta import _extract_delta + >>> from sympy.abc import x, y, i, j, k + >>> _extract_delta(4*x*y*KroneckerDelta(i, j), i) + (KroneckerDelta(i, j), 4*x*y) + >>> _extract_delta(4*x*y*KroneckerDelta(i, j), k) + (None, 4*x*y*KroneckerDelta(i, j)) + + See Also + ======== + + sympy.functions.special.tensor_functions.KroneckerDelta + deltaproduct + deltasummation + """ + if not _has_simple_delta(expr, index): + return (None, expr) + if isinstance(expr, KroneckerDelta): + return (expr, S(1)) + assert expr.is_Mul + + delta = None + terms = [] + + for arg in expr.args: + if delta is None and _is_simple_delta(arg, index): + delta = arg + else: + terms.append(arg) + return (delta, expr.func(*terms)) + + +def _has_simple_delta(expr, index): + """ + Returns True if ``expr`` is an expression that contains a KroneckerDelta + that is simple in the index ``index``, meaning that this KroneckerDelta + is nonzero for a single value of the index ``index``. + """ + if expr.has(KroneckerDelta): + if _is_simple_delta(expr, index): + return True + for arg in expr.args: + if _has_simple_delta(arg, index): + return True + return False + + +def _is_simple_delta(delta, index): + """ + Returns True if ``delta`` is a KroneckerDelta and is nonzero for a single + value of the index ``index``. + """ + if isinstance(delta, KroneckerDelta) and delta.has(index): + p = (delta.args[0] - delta.args[1]).as_poly(index) + if p: + return p.degree() == 1 + return False + + +def _remove_multiple_delta(expr): + """ + Evaluate products of KroneckerDelta's. + """ + from sympy.solvers import solve + if expr.is_Add: + return expr.func(*list(map(_remove_multiple_delta, expr.args))) + if not expr.is_Mul: + return expr + eqs = [] + newargs = [] + for arg in expr.args: + if isinstance(arg, KroneckerDelta): + eqs.append(arg.args[0] - arg.args[1]) + else: + newargs.append(arg) + if not eqs: + return expr + solns = solve(eqs, dict=True) + if len(solns) == 0: + return S.Zero + elif len(solns) == 1: + for key in list(solns[0].keys()): + newargs.append(KroneckerDelta(key, solns[0][key])) + expr2 = expr.func(*newargs) + if expr != expr2: + return _remove_multiple_delta(expr2) + return expr + + +def _simplify_delta(expr): + """ + Rewrite a KroneckerDelta's indices in its simplest form. + """ + from sympy.solvers import solve + if isinstance(expr, KroneckerDelta): + try: + slns = solve(expr.args[0] - expr.args[1], dict=True) + if slns and len(slns) == 1: + return Mul(*[KroneckerDelta(*(key, value)) + for key, value in slns[0].items()]) + except NotImplementedError: + pass + return expr + + +def deltaproduct(f, limit): + """ + Handle products containing a KroneckerDelta. + + See Also + ======== + + deltasummation + sympy.functions.special.tensor_functions.KroneckerDelta + sympy.concrete.products.product + """ + from sympy.concrete.products import product + + if ((limit[2] - limit[1]) < 0) is True: + return S.One + + if not f.has(KroneckerDelta): + return product(f, limit) + + if f.is_Add: + # Identify the term in the Add that has a simple KroneckerDelta + delta = None + terms = [] + for arg in sorted(f.args, key=default_sort_key): + if delta is None and _has_simple_delta(arg, limit[0]): + delta = arg + else: + terms.append(arg) + newexpr = f.func(*terms) + k = Dummy("kprime", integer=True) + if isinstance(limit[1], int) and isinstance(limit[2], int): + result = deltaproduct(newexpr, limit) + sum([ + deltaproduct(newexpr, (limit[0], limit[1], ik - 1)) * + delta.subs(limit[0], ik) * + deltaproduct(newexpr, (limit[0], ik + 1, limit[2])) for ik in range(int(limit[1]), int(limit[2] + 1))] + ) + else: + result = deltaproduct(newexpr, limit) + deltasummation( + deltaproduct(newexpr, (limit[0], limit[1], k - 1)) * + delta.subs(limit[0], k) * + deltaproduct(newexpr, (limit[0], k + 1, limit[2])), (k, limit[1], limit[2]), no_piecewise=True + ) + return _remove_multiple_delta(result) + + delta, _ = _extract_delta(f, limit[0]) + + if not delta: + g = _expand_delta(f, limit[0]) + if f != g: + from sympy import factor + try: + return factor(deltaproduct(g, limit)) + except AssertionError: + return deltaproduct(g, limit) + return product(f, limit) + + from sympy import Eq + c = Eq(limit[2], limit[1] - 1) + return _remove_multiple_delta(f.subs(limit[0], limit[1])*KroneckerDelta(limit[2], limit[1])) + \ + S.One*_simplify_delta(KroneckerDelta(limit[2], limit[1] - 1)) + + +def deltasummation(f, limit, no_piecewise=False): + """ + Handle summations containing a KroneckerDelta. + + The idea for summation is the following: + + - If we are dealing with a KroneckerDelta expression, i.e. KroneckerDelta(g(x), j), + we try to simplify it. + + If we could simplify it, then we sum the resulting expression. + We already know we can sum a simplified expression, because only + simple KroneckerDelta expressions are involved. + + If we couldn't simplify it, there are two cases: + + 1) The expression is a simple expression: we return the summation, + taking care if we are dealing with a Derivative or with a proper + KroneckerDelta. + + 2) The expression is not simple (i.e. KroneckerDelta(cos(x))): we can do + nothing at all. + + - If the expr is a multiplication expr having a KroneckerDelta term: + + First we expand it. + + If the expansion did work, then we try to sum the expansion. + + If not, we try to extract a simple KroneckerDelta term, then we have two + cases: + + 1) We have a simple KroneckerDelta term, so we return the summation. + + 2) We didn't have a simple term, but we do have an expression with + simplified KroneckerDelta terms, so we sum this expression. + + Examples + ======== + + >>> from sympy import oo + >>> from sympy.abc import i, j, k + >>> from sympy.concrete.delta import deltasummation + >>> from sympy import KroneckerDelta, Piecewise + >>> deltasummation(KroneckerDelta(i, k), (k, -oo, oo)) + 1 + >>> deltasummation(KroneckerDelta(i, k), (k, 0, oo)) + Piecewise((1, i >= 0), (0, True)) + >>> deltasummation(KroneckerDelta(i, k), (k, 1, 3)) + Piecewise((1, And(1 <= i, i <= 3)), (0, True)) + >>> deltasummation(k*KroneckerDelta(i, j)*KroneckerDelta(j, k), (k, -oo, oo)) + j*KroneckerDelta(i, j) + >>> deltasummation(j*KroneckerDelta(i, j), (j, -oo, oo)) + i + >>> deltasummation(i*KroneckerDelta(i, j), (i, -oo, oo)) + j + + See Also + ======== + + deltaproduct + sympy.functions.special.tensor_functions.KroneckerDelta + sympy.concrete.sums.summation + """ + from sympy.concrete.summations import summation + from sympy.solvers import solve + + if ((limit[2] - limit[1]) < 0) is True: + return S.Zero + + if not f.has(KroneckerDelta): + return summation(f, limit) + + x = limit[0] + + g = _expand_delta(f, x) + if g.is_Add: + return piecewise_fold( + Add(*[deltasummation(h, limit, no_piecewise) for h in g.args])) + + # try to extract a simple KroneckerDelta term + delta, expr = _extract_delta(g, x) + + if not delta: + return summation(f, limit) + + solns = solve(delta.args[0] - delta.args[1], x) + if len(solns) == 0: + return S.Zero + elif len(solns) != 1: + return Sum(f, limit) + value = solns[0] + if no_piecewise: + return expr.subs(x, value) + return Piecewise( + (expr.subs(x, value), Interval(*limit[1:3]).as_relational(value)), + (S.Zero, True) + ) diff -Nru python3-sympy-0.7.2/sympy/concrete/gosper.py python3-sympy-0.7.3/sympy/concrete/gosper.py --- python3-sympy-0.7.2/sympy/concrete/gosper.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/concrete/gosper.py 2013-07-13 17:53:32.000000000 +0000 @@ -6,6 +6,7 @@ from sympy.solvers import solve from sympy.simplify import hypersimp + def gosper_normal(f, g, n, polys=True): r""" Compute the Gosper's normal form of ``f`` and ``g``. @@ -41,7 +42,8 @@ (1/4, n + 3/2, n + 1/4) """ - (p, q), opt = parallel_poly_from_expr((f, g), n, field=True, extension=True) + (p, q), opt = parallel_poly_from_expr( + (f, g), n, field=True, extension=True) a, A = p.LC(), p.monic() b, B = q.LC(), q.monic() @@ -64,7 +66,7 @@ A = A.quo(d) B = B.quo(d.shift(-i)) - for j in range(1, i+1): + for j in range(1, i + 1): C *= d.shift(-j) A = A.mul_ground(Z) @@ -76,6 +78,7 @@ return A, B, C + def gosper_term(f, n): r""" Compute Gosper's hypergeometric term for ``f``. @@ -151,6 +154,7 @@ else: return B.as_expr()*x/C.as_expr() + def gosper_sum(f, k): r""" Gosper's hypergeometric summation algorithm. @@ -173,11 +177,11 @@ >>> f = (4*k + 1)*factorial(k)/factorial(2*k + 1) >>> gosper_sum(f, (k, 0, n)) - (-n! + 2*(2*n + 1)!)/(2*n + 1)! + (-factorial(n) + 2*factorial(2*n + 1))/factorial(2*n + 1) >>> _.subs(n, 2) == sum(f.subs(k, i) for i in [0, 1, 2]) True >>> gosper_sum(f, (k, 3, n)) - (-60*n! + (2*n + 1)!)/(60*(2*n + 1)!) + (-60*factorial(n) + factorial(2*n + 1))/(60*factorial(2*n + 1)) >>> _.subs(n, 5) == sum(f.subs(k, i) for i in [3, 4, 5]) True @@ -203,6 +207,12 @@ if indefinite: result = f*g else: - result = (f*(g+1)).subs(k, b) - (f*g).subs(k, a) + result = (f*(g + 1)).subs(k, b) - (f*g).subs(k, a) + + if result is S.NaN: + try: + result = (f*(g + 1)).limit(k, b) - (f*g).limit(k, a) + except NotImplementedError: + result = None return factor(result) diff -Nru python3-sympy-0.7.2/sympy/concrete/products.py python3-sympy-0.7.3/sympy/concrete/products.py --- python3-sympy-0.7.2/sympy/concrete/products.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/concrete/products.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,11 +1,187 @@ -from sympy.core import C, Expr, Mul, S, sympify +from sympy.core.containers import Tuple +from sympy.core.core import C +from sympy.core.expr import Expr +from sympy.core.mul import Mul +from sympy.core.singleton import S +from sympy.core.sympify import sympify from sympy.functions.elementary.piecewise import piecewise_fold from sympy.polys import quo, roots from sympy.simplify import powsimp + class Product(Expr): - """Represents unevaluated product. + r"""Represents unevaluated products. + ``Product`` represents a finite or infinite product, with the first + argument being the general form of terms in the series, and the second + argument being ``(dummy_variable, start, end)``, with ``dummy_variable`` + taking all integer values from ``start`` through ``end``. In accordance + with long-standing mathematical convention, the end term is included in + the product. + + Finite products + =============== + + For finite products (and products with symbolic limits assumed to be finite) + we follow the analogue of the summation convention described by Karr [1], + especially definition 3 of section 1.4. The product: + + .. math:: + + \prod_{m \leq i < n} f(i) + + has *the obvious meaning* for `m < n`, namely: + + .. math:: + + \prod_{m \leq i < n} f(i) = f(m) f(m+1) \cdot \ldots \cdot f(n-2) f(n-1) + + with the upper limit value `f(n)` excluded. The product over an empty set is + one if and only if `m = n`: + + .. math:: + + \prod_{m \leq i < n} f(i) = 1 \quad \mathrm{for} \quad m = n + + Finally, for all other products over empty sets we assume the following + definition: + + .. math:: + + \prod_{m \leq i < n} f(i) = \frac{1}{\prod_{n \leq i < m} f(i)} \quad \mathrm{for} \quad m > n + + It is important to note that above we define all products with the upper + limit being exclusive. This is in contrast to the usual mathematical notation, + but does not affect the product convention. Indeed we have: + + .. math:: + + \prod_{m \leq i < n} f(i) = \prod_{i = m}^{n - 1} f(i) + + where the difference in notation is intentional to emphasize the meaning, + with limits typeset on the top being inclusive. + + Examples + ======== + + >>> from sympy.abc import a, b, i, k, m, n, x + >>> from sympy import Product, factorial, oo + >>> Product(k,(k,1,m)) + Product(k, (k, 1, m)) + >>> Product(k,(k,1,m)).doit() + factorial(m) + >>> Product(k**2,(k,1,m)) + Product(k**2, (k, 1, m)) + >>> Product(k**2,(k,1,m)).doit() + (factorial(m))**2 + + Wallis' product for pi: + + >>> W = Product(2*i/(2*i-1) * 2*i/(2*i+1), (i, 1, oo)) + >>> W + Product(4*i**2/((2*i - 1)*(2*i + 1)), (i, 1, oo)) + + Direct computation currently fails: + + >>> W.doit() + nan + + But we can approach the infinite product by a limit of finite products: + + >>> from sympy import limit + >>> W2 = Product(2*i/(2*i-1)*2*i/(2*i+1), (i, 1, n)) + >>> W2 + Product(4*i**2/((2*i - 1)*(2*i + 1)), (i, 1, n)) + >>> W2e = W2.doit() + >>> W2e + 2**(-2*n)*4**n*(factorial(n))**2/(RisingFactorial(1/2, n)*RisingFactorial(3/2, n)) + >>> limit(W2e, n, oo) + pi/2 + + By the same formula we can compute sin(pi/2): + + >>> from sympy import pi, gamma, simplify + >>> P = pi * x * Product(1 - x**2/k**2,(k,1,n)) + >>> P = P.subs(x, pi/2) + >>> P + pi**2*Product(1 - pi**2/(4*k**2), (k, 1, n))/2 + >>> Pe = P.doit() + >>> Pe + pi**2*RisingFactorial(1 + pi/2, n)*RisingFactorial(-pi/2 + 1, n)/(2*(factorial(n))**2) + >>> Pe = Pe.rewrite(gamma) + >>> Pe + pi**2*gamma(n + 1 + pi/2)*gamma(n - pi/2 + 1)/(2*gamma(1 + pi/2)*gamma(-pi/2 + 1)*gamma(n + 1)**2) + >>> Pe = simplify(Pe) + >>> Pe + sin(pi**2/2)*gamma(n + 1 + pi/2)*gamma(n - pi/2 + 1)/gamma(n + 1)**2 + >>> limit(Pe, n, oo) + sin(pi**2/2) + + Products with the lower limit being larger than the upper one: + + >>> Product(1/i, (i, 6, 1)).doit() + 120 + >>> Product(i, (i, 2, 5)).doit() + 120 + + The empty product: + + >>> Product(i, (i, n, n-1)).doit() + 1 + + An example showing that the symbolic result of a product is still + valid for seemingly nonsensical values of the limits. Then the Karr + convention allows us to give a perfectly valid interpretation to + those products by interchanging the limits according to the above rules: + + >>> P = Product(2, (i, 10, n)).doit() + >>> P + 2**(n - 9) + >>> P.subs(n, 5) + 1/16 + >>> Product(2, (i, 10, 5)).doit() + 1/16 + >>> 1/Product(2, (i, 6, 9)).doit() + 1/16 + + An explicit example of the Karr summation convention applied to products: + + >>> P1 = Product(x, (i, a, b)).doit() + >>> P1 + x**(-a + b + 1) + >>> P2 = Product(x, (i, b+1, a-1)).doit() + >>> P2 + x**(a - b - 1) + >>> simplify(P1 * P2) + 1 + + And another one: + + >>> P1 = Product(i, (i, b, a)).doit() + >>> P1 + RisingFactorial(b, a - b + 1) + >>> P2 = Product(i, (i, a+1, b-1)).doit() + >>> P2 + RisingFactorial(a + 1, -a + b - 1) + >>> P1 * P2 + RisingFactorial(b, a - b + 1)*RisingFactorial(a + 1, -a + b - 1) + >>> simplify(P1 * P2) + 1 + + See Also + ======== + + Sum, summation + product + + References + ========== + + .. [1] Michael Karr, "Summation in Finite Terms", Journal of the ACM, + Volume 28 Issue 2, April 1981, Pages 305-350 + http://dl.acm.org/citation.cfm?doid=322248.322255 + .. [2] http://en.wikipedia.org/wiki/Multiplication#Capital_Pi_notation + .. [3] http://en.wikipedia.org/wiki/Empty_product """ __slots__ = ['is_commutative'] @@ -29,13 +205,14 @@ # Only limits with lower and upper bounds are supported; the indefinite # Product is not supported if any(len(l) != 3 or None in l for l in limits): - raise ValueError('Product requires values for lower and upper bounds.') + raise ValueError( + 'Product requires values for lower and upper bounds.') obj = Expr.__new__(cls, **assumptions) arglist = [sign*function] arglist.extend(limits) obj._args = tuple(arglist) - obj.is_commutative = function.is_commutative # limits already checked + obj.is_commutative = function.is_commutative # limits already checked return obj @@ -71,11 +248,10 @@ >>> Product(x, (x, y, 1)).free_symbols set([y]) """ - from sympy.concrete.summations import _free_symbols - + from sympy.integrals.integrals import _free_symbols if self.function.is_zero or self.function == 1: return set() - return _free_symbols(self.function, self.limits) + return _free_symbols(self) @property def is_zero(self): @@ -88,8 +264,8 @@ """ Return True if the Product will result in a number, else False. - sympy considers anything that will result in a number to have - is_number == True. + Examples + ======== >>> from sympy import log, Product >>> from sympy.abc import x, y, z @@ -107,13 +283,19 @@ return self.function.is_zero or self.function == 1 or not self.free_symbols + def as_dummy(self): + from sympy.integrals.integrals import _as_dummy + return _as_dummy(self) + def doit(self, **hints): - f = g = self.function + f = self.function + for index, limit in enumerate(self.limits): i, a, b = limit dif = b - a if dif.is_Integer and dif < 0: - a, b = b, a + a, b = b + 1, a - 1 + f = 1 / f g = self._eval_product(f, (i, a, b)) if g is None: @@ -126,8 +308,18 @@ else: return powsimp(f) + def _eval_adjoint(self): + if self.is_commutative: + return Product(self.function.adjoint(), *self.limits) + return None + + def _eval_conjugate(self): + return Product(self.function.conjugate(), *self.limits) + def _eval_product(self, term, limits): - from sympy import summation + from sympy.concrete.delta import deltaproduct, _has_simple_delta + from sympy.concrete.summations import summation + from sympy.functions import KroneckerDelta (k, a, n) = limits @@ -137,9 +329,12 @@ if a == n: return term.subs(k, a) + if term.has(KroneckerDelta) and _has_simple_delta(term, limits[0]): + return deltaproduct(term, limits) + dif = n - a if dif.is_Integer: - return Mul(*[term.subs(k, a + i) for i in range(dif + 1)]) + return Mul(*[term.subs(k, a + i) for i in range(dif + 1)]) elif term.is_polynomial(k): poly = term.as_poly(k) @@ -149,14 +344,14 @@ all_roots = roots(poly, multiple=True) for r in all_roots: - A *= C.RisingFactorial(a-r, n-a+1) + A *= C.RisingFactorial(a - r, n - a + 1) Q *= n - r if len(all_roots) < poly.degree(): arg = quo(poly, Q.as_poly(k)) B = Product(arg, (k, a, n)).doit() - return poly.LC()**(n-a+1) * A * B + return poly.LC()**(n - a + 1) * A * B elif term.is_Add: p, q = term.as_numer_denom() @@ -204,6 +399,17 @@ else: return f + def _eval_transpose(self): + if self.is_commutative: + return Product(self.function.transpose(), *self.limits) + return None + + + def _eval_subs(self, old, new): + from sympy.integrals.integrals import _eval_subs + return _eval_subs(self, old, new) + + def product(*args, **kwargs): r""" Compute the product. @@ -227,11 +433,11 @@ >>> i, n, m, k = symbols('i n m k', integer=True) >>> product(i, (i, 1, k)) - k! + factorial(k) >>> product(m, (i, 1, k)) m**k >>> product(i, (i, 1, k), (k, 1, n)) - Product(k!, (k, 1, n)) + Product(factorial(k), (k, 1, n)) """ diff -Nru python3-sympy-0.7.2/sympy/concrete/simplification.py python3-sympy-0.7.3/sympy/concrete/simplification.py --- python3-sympy-0.7.2/sympy/concrete/simplification.py 1970-01-01 00:00:00.000000000 +0000 +++ python3-sympy-0.7.3/sympy/concrete/simplification.py 2013-07-13 17:53:32.000000000 +0000 @@ -0,0 +1,416 @@ +""" Change index / Reorder / Reverse order of limits of Sums and Products""" +from sympy.concrete import Product, Sum +from sympy import S + + +class ReorderError(NotImplementedError): + """ + Exception raised when trying to reorder dependent limits. + """ + def __init__(self, expr, msg): + super(ReorderError, self).__init__( + "%s could not be reordered: %s." % (expr, msg)) + + +def index(expr, x): + """ + Return the index of a limit variable. + + Usage + ===== + + ``index(expr, x)`` returns the index of the limit variable ``x`` in the + limits of ``expr``. Note that we start counting with 0 at the inner-most + limits tuple. + + Examples + ======== + + >>> from sympy.concrete.simplification import index + >>> from sympy.abc import x, y, a, b, c, d + >>> from sympy import Sum, Product + >>> index(Sum(x*y, (x, a, b), (y, c, d)), x) + 0 + >>> index(Sum(x*y, (x, a, b), (y, c, d)), y) + 1 + >>> index(Product(x*y, (x, a, b), (y, c, d)), x) + 0 + >>> index(Product(x*y, (x, a, b), (y, c, d)), y) + 1 + + See Also + ======== + + sympy.concrete.simplification.change_index, + sympy.concrete.simplification.reorder_limit, + sympy.concrete.simplification.reorder, + sympy.concrete.simplification.reverse_order + """ + if isinstance(expr, Sum) or isinstance(expr, Product): + variables = [limit[0] for limit in expr.limits] + + if variables.count(x) != 1: + raise ValueError(expr, "Number of instances of variable not equal to one") + else: + return variables.index(x) + + +def change_index(expr, var, trafo, newvar=None): + """ + Change index of a Sum or Product. + + Perform a linear transformation `x \mapsto a x + b` on the index variable + `x`. For `a` the only values allowed are `\pm 1`. A new variable to be used + after the change of index can also be specified. + + Usage + ===== + + ``change_index(expr, var, trafo, newvar=None)`` where ``var`` specifies the + index variable `x` to transform. The transformation ``trafo`` must be linear + and given in terms of ``var``. If the optional argument ``newvar`` is + provided then ``var`` gets replaced by ``newvar`` in the final expression. + + Examples + ======== + + >>> from sympy.concrete.simplification import change_index + >>> from sympy import Sum, Product, simplify + >>> from sympy.abc import x, y, a, b, c, d, u, v, i, j, k, l + + >>> S = Sum(x, (x, a, b)) + >>> S.doit() + -a**2/2 + a/2 + b**2/2 + b/2 + + >>> Sn = change_index(S, x, x + 1, y) + >>> Sn + Sum(y - 1, (y, a + 1, b + 1)) + >>> Sn.doit() + -a**2/2 + a/2 + b**2/2 + b/2 + + >>> Sn = change_index(S, x, -x, y) + >>> Sn + Sum(-y, (y, -b, -a)) + >>> Sn.doit() + -a**2/2 + a/2 + b**2/2 + b/2 + + >>> Sn = change_index(S, x, x+u) + >>> Sn + Sum(-u + x, (x, a + u, b + u)) + >>> Sn.doit() + -a**2/2 - a*u + a/2 + b**2/2 + b*u + b/2 - u*(-a + b + 1) + u + >>> simplify(Sn.doit()) + -a**2/2 + a/2 + b**2/2 + b/2 + + >>> Sn = change_index(S, x, -x - u, y) + >>> Sn + Sum(-u - y, (y, -b - u, -a - u)) + >>> Sn.doit() + -a**2/2 - a*u + a/2 + b**2/2 + b*u + b/2 - u*(-a + b + 1) + u + >>> simplify(Sn.doit()) + -a**2/2 + a/2 + b**2/2 + b/2 + + >>> P = Product(i*j**2, (i, a, b), (j, c, d)) + >>> P + Product(i*j**2, (i, a, b), (j, c, d)) + >>> P2 = change_index(P, i, i+3, k) + >>> P2 + Product(j**2*(k - 3), (k, a + 3, b + 3), (j, c, d)) + >>> P3 = change_index(P2, j, -j, l) + >>> P3 + Product(l**2*(k - 3), (k, a + 3, b + 3), (l, -d, -c)) + + When dealing with symbols only, we can make a + general linear transformation: + + >>> Sn = change_index(S, x, u*x+v, y) + >>> Sn + Sum((-v + y)/u, (y, b*u + v, a*u + v)) + >>> Sn.doit() + -v*(a*u - b*u + 1)/u + (a**2*u**2/2 + a*u*v + a*u/2 - b**2*u**2/2 - b*u*v + b*u/2 + v)/u + >>> simplify(Sn.doit()) + a**2*u/2 + a/2 - b**2*u/2 + b/2 + + However, the last result can be inconsistent with usual + summation where the index increment is always 1. This is + obvious as we get back the original value only for ``u`` + equal +1 or -1. + + See Also + ======== + + sympy.concrete.simplification.index, + sympy.concrete.simplification.reorder_limit, + sympy.concrete.simplification.reorder, + sympy.concrete.simplification.reverse_order + """ + if newvar is None: + newvar = var + + limits = [] + for limit in expr.limits: + if limit[0] == var: + p = trafo.as_poly(var) + if p.degree() != 1: + raise ValueError("Index transformation is not linear") + alpha = p.coeff_monomial(var) + beta = p.coeff_monomial(S.One) + if alpha.is_number: + if alpha == S.One: + limits.append((newvar, alpha*limit[1] + beta, alpha*limit[2] + beta)) + elif alpha == S.NegativeOne: + limits.append((newvar, alpha*limit[2] + beta, alpha*limit[1] + beta)) + else: + raise ValueError("Linear transformation results in non-linear summation stepsize") + else: + # Note that the case of alpha being symbolic can give issues if alpha < 0. + limits.append((newvar, alpha*limit[2] + beta, alpha*limit[1] + beta)) + else: + limits.append(limit) + + function = expr.function.subs(var, (var - beta)/alpha) + function = function.subs(var, newvar) + + if isinstance(expr, Sum): + return Sum(function, *tuple(limits)) + elif isinstance(expr, Product): + return Product(function, *tuple(limits)) + else: + raise NotImplementedError(expr, "change_index only implemented for Sum and Product") + + +def reorder(expr, *arg): + """ + Reorder limits in a expression containing a Sum or a Product. + + Usage + ===== + + ``reorder(expr, *arg)`` reorders the limits in the expression ``expr`` + according to the list of tuples given by ``arg``. These tuples can + contain numerical indices or index variable names or involve both. + + Examples + ======== + + >>> from sympy.concrete.simplification import reorder + >>> from sympy import Sum, Product + >>> from sympy.abc import x, y, z, a, b, c, d, e, f + + >>> reorder(Sum(x*y, (x, a, b), (y, c, d)), (x, y)) + Sum(x*y, (y, c, d), (x, a, b)) + + >>> reorder(Sum(x*y*z, (x, a, b), (y, c, d), (z, e, f)), (x, y), (x, z), (y, z)) + Sum(x*y*z, (z, e, f), (y, c, d), (x, a, b)) + + >>> P = Product(x*y*z, (x, a, b), (y, c, d), (z, e, f)) + >>> reorder(P, (x, y), (x, z), (y, z)) + Product(x*y*z, (z, e, f), (y, c, d), (x, a, b)) + + We can also select the index variables by counting them, starting + with the inner-most one: + + >>> reorder(Sum(x**2, (x, a, b), (x, c, d)), (0, 1)) + Sum(x**2, (x, c, d), (x, a, b)) + + And of course we can mix both schemes: + + >>> reorder(Sum(x*y, (x, a, b), (y, c, d)), (y, x)) + Sum(x*y, (y, c, d), (x, a, b)) + >>> reorder(Sum(x*y, (x, a, b), (y, c, d)), (y, 0)) + Sum(x*y, (y, c, d), (x, a, b)) + + See Also + ======== + + sympy.concrete.simplification.index, + sympy.concrete.simplification.change_index, + sympy.concrete.simplification.reorder_limit, + sympy.concrete.simplification.reverse_order + """ + new_expr = expr + + for r in arg: + if len(r) != 2: + raise ValueError(r, "Invalid number of arguments") + + index1 = r[0] + index2 = r[1] + + if not isinstance(r[0], int): + index1 = index(expr, r[0]) + if not isinstance(r[1], int): + index2 = index(expr, r[1]) + + new_expr = reorder_limit(new_expr, index1, index2) + + return new_expr + + +def reorder_limit(expr, x, y): + """ + Interchange two limit tuples of a Sum or Product expression. + + Usage + ===== + + ``reorder_limit(expr, x, y)`` interchanges two limit tuples. The + arguments ``x`` and ``y`` are integers corresponding to the index + variables of the two limits which are to be interchanged. The + expression ``expr`` has to be either a Sum or a Product. + + Examples + ======== + + >>> from sympy.concrete.simplification import reorder_limit + >>> from sympy.abc import x, y, z, a, b, c, d, e, f + >>> from sympy import Sum, Product + + >>> reorder_limit(Sum(x*y*z, (x, a, b), (y, c, d), (z, e, f)), 0, 2) + Sum(x*y*z, (z, e, f), (y, c, d), (x, a, b)) + >>> reorder_limit(Sum(x**2, (x, a, b), (x, c, d)), 1, 0) + Sum(x**2, (x, c, d), (x, a, b)) + + >>> reorder_limit(Product(x*y*z, (x, a, b), (y, c, d), (z, e, f)), 0, 2) + Product(x*y*z, (z, e, f), (y, c, d), (x, a, b)) + + See Also + ======== + + sympy.concrete.simplification.index, + sympy.concrete.simplification.change_index, + sympy.concrete.simplification.reorder, + sympy.concrete.simplification.reverse_order + """ + var = set([limit[0] for limit in expr.limits]) + limit_x = expr.limits[x] + limit_y = expr.limits[y] + + if (len(set(limit_x[1].free_symbols).intersection(var)) == 0 and + len(set(limit_x[2].free_symbols).intersection(var)) == 0 and + len(set(limit_y[1].free_symbols).intersection(var)) == 0 and + len(set(limit_y[2].free_symbols).intersection(var)) == 0): + + limits = [] + for i, limit in enumerate(expr.limits): + if i == x: + limits.append(limit_y) + elif i == y: + limits.append(limit_x) + else: + limits.append(limit) + + if isinstance(expr, Sum): + return Sum(expr.function, *limits) + elif isinstance(expr, Product): + return Product(expr.function, *limits) + else: + raise NotImplementedError(expr, "reorder only implemented for Sum and Product") + + else: + raise ReorderError(expr, "could not interchange the two limits specified") + + +def reverse_order(expr, *indices): + """ + Reverse the order of a limit in a Sum or Product. + + Usage + ===== + + ``reverse_order(expr, *indices)`` reverses some limits in the expression + ``expr`` which can be either a ``Sum`` or a ``Product``. The selectors in + the argument ``indices`` specify some indices whose limits get reversed. + These selectors are either variable names or numerical indices counted + starting from the inner-most limit tuple. + + Examples + ======== + + >>> from sympy.concrete.simplification import reverse_order + >>> from sympy import Sum + >>> from sympy.abc import x, y, a, b, c, d + + >>> reverse_order(Sum(x, (x, 0, 3)), x) + Sum(-x, (x, 4, -1)) + >>> reverse_order(Sum(x*y, (x, 1, 5), (y, 0, 6)), x, y) + Sum(x*y, (x, 6, 0), (y, 7, -1)) + >>> reverse_order(Sum(x, (x, a, b)), x) + Sum(-x, (x, b + 1, a - 1)) + >>> reverse_order(Sum(x, (x, a, b)), 0) + Sum(-x, (x, b + 1, a - 1)) + + >>> from sympy import Product, simplify, RisingFactorial, gamma + >>> P = Product(x, (x, a, b)) + >>> Pr = reverse_order(P, x) + >>> Pr + Product(1/x, (x, b + 1, a - 1)) + >>> Pr = Pr.doit() + >>> Pr + 1/RisingFactorial(b + 1, a - b - 1) + >>> simplify(Pr) + gamma(b + 1)/gamma(a) + >>> P = P.doit() + >>> P + RisingFactorial(a, -a + b + 1) + >>> simplify(P) + gamma(b + 1)/gamma(a) + + While one should prefer variable names when specifying which limits + to reverse, the index counting notation comes in handy in case there + are several symbols with the same name. + + >>> S = Sum(x**2, (x, a, b), (x, c, d)) + >>> S + Sum(x**2, (x, a, b), (x, c, d)) + >>> S0 = reverse_order(S, 0) + >>> S0 + Sum(-x**2, (x, b + 1, a - 1), (x, c, d)) + >>> S1 = reverse_order(S0, 1) + >>> S1 + Sum(x**2, (x, b + 1, a - 1), (x, d + 1, c - 1)) + + Of course we can mix both notations: + + >>> reverse_order(Sum(x*y, (x, a, b), (y, 2, 5)), x, 1) + Sum(x*y, (x, b + 1, a - 1), (y, 6, 1)) + >>> reverse_order(Sum(x*y, (x, a, b), (y, 2, 5)), y, x) + Sum(x*y, (x, b + 1, a - 1), (y, 6, 1)) + + See Also + ======== + + sympy.concrete.simplification.index, + sympy.concrete.simplification.change_index, + sympy.concrete.simplification.reorder_limit, + sympy.concrete.simplification.reorder + + References + ========== + + .. [1] Michael Karr, "Summation in Finite Terms", Journal of the ACM, + Volume 28 Issue 2, April 1981, Pages 305-350 + http://dl.acm.org/citation.cfm?doid=322248.322255 + """ + l_indices = list(indices) + + for i, indx in enumerate(l_indices): + if not isinstance(indx, int): + l_indices[i] = index(expr, indx) + + if isinstance(expr, Sum) or isinstance(expr, Product): + e = 1 + limits = [] + for i, limit in enumerate(expr.limits): + l = limit + if i in l_indices: + e = -e + l = (limit[0], limit[2] + 1 , limit[1] - 1) + limits.append(l) + + if isinstance(expr, Sum): + return Sum(e * expr.function, *limits) + elif isinstance(expr, Product): + return Product(expr.function ** e, *limits) + else: + return expr diff -Nru python3-sympy-0.7.2/sympy/concrete/summations.py python3-sympy-0.7.3/sympy/concrete/summations.py --- python3-sympy-0.7.2/sympy/concrete/summations.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/concrete/summations.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,25 +1,134 @@ -from sympy.core import Add, C, Derivative, Dummy, Expr, S, sympify, Wild +from sympy.core.add import Add +from sympy.core.basic import C +from sympy.core.containers import Tuple +from sympy.core.expr import Expr +from sympy.core.function import Derivative +from sympy.core.relational import Eq +from sympy.core.singleton import S +from sympy.core.symbol import (Dummy, Wild) +from sympy.core.sympify import sympify from sympy.concrete.gosper import gosper_sum -from sympy.functions.elementary.piecewise import piecewise_fold +from sympy.functions.elementary.piecewise import piecewise_fold, Piecewise from sympy.polys import apart, PolynomialError from sympy.solvers import solve -def _free_symbols(function, limits): - """Helper function to return the symbols that appear in a sum-like object - once it is evaluated. - """ - isyms = function.free_symbols - for xab in limits: - # take out the target symbol - if xab[0] in isyms: - isyms.remove(xab[0]) - # add in the new symbols - for i in xab[1:]: - isyms.update(i.free_symbols) - return isyms class Sum(Expr): - """Represents unevaluated summation.""" + """Represents unevaluated summation. + + ``Sum`` represents a finite or infinite series, with the first argument + being the general form of terms in the series, and the second argument + being ``(dummy_variable, start, end)``, with ``dummy_variable`` taking + all integer values from ``start`` through ``end``. In accordance with + long-standing mathematical convention, the end term is included in the + summation. + + Finite sums + =========== + + For finite sums (and sums with symbolic limits assumed to be finite) we + follow the summation convention described by Karr [1], especially + definition 3 of section 1.4. The sum: + + .. math:: + + \sum_{m \leq i < n} f(i) + + has *the obvious meaning* for `m < n`, namely: + + .. math:: + + \sum_{m \leq i < n} f(i) = f(m) + f(m+1) + \ldots + f(n-2) + f(n-1) + + with the upper limit value `f(n)` excluded. The sum over an empty set is + zero if and only if `m = n`: + + .. math:: + + \sum_{m \leq i < n} f(i) = 0 \quad \mathrm{for} \quad m = n + + Finally, for all other sums over empty sets we assume the following + definition: + + .. math:: + + \sum_{m \leq i < n} f(i) = - \sum_{n \leq i < m} f(i) \quad \mathrm{for} \quad m > n + + It is important to note that Karr defines all sums with the upper + limit being exclusive. This is in contrast to the usual mathematical notation, + but does not affect the summation convention. Indeed we have: + + .. math:: + + \sum_{m \leq i < n} f(i) = \sum_{i = m}^{n - 1} f(i) + + where the difference in notation is intentional to emphasize the meaning, + with limits typeset on the top being inclusive. + + Examples + ======== + + >>> from sympy.abc import i, k, m, n, x + >>> from sympy import Sum, factorial, oo + >>> Sum(k,(k,1,m)) + Sum(k, (k, 1, m)) + >>> Sum(k,(k,1,m)).doit() + m**2/2 + m/2 + >>> Sum(k**2,(k,1,m)) + Sum(k**2, (k, 1, m)) + >>> Sum(k**2,(k,1,m)).doit() + m**3/3 + m**2/2 + m/6 + >>> Sum(x**k,(k,0,oo)) + Sum(x**k, (k, 0, oo)) + >>> Sum(x**k,(k,0,oo)).doit() + Piecewise((1/(-x + 1), Abs(x) < 1), (Sum(x**k, (k, 0, oo)), True)) + >>> Sum(x**k/factorial(k),(k,0,oo)).doit() + exp(x) + + An example showing that the symbolic result of a summation is still + valid for seemingly nonsensical values of the limits. Then the Karr + convention allows us to give a perfectly valid interpretation to + those sums by interchanging the limits according to the above rules: + + >>> S = Sum(i, (i,1,n)).doit() + >>> S + n**2/2 + n/2 + >>> S.subs(n, -4) + 6 + >>> Sum(i, (i, 1, -4)).doit() + 6 + >>> Sum(-i, (i, -3, 0)).doit() + 6 + + An explicit example of the Karr summation convention: + + >>> S1 = Sum(i**2, (i, m, m+n-1)).doit() + >>> S1 + m**2*n + m*n**2 - m*n + n**3/3 - n**2/2 + n/6 + >>> S2 = Sum(i**2, (i, m+n, m-1)).doit() + >>> S2 + -m**2*n - m*n**2 + m*n - n**3/3 + n**2/2 - n/6 + >>> S1 + S2 + 0 + >>> S3 = Sum(i, (i, m, m-1)).doit() + >>> S3 + 0 + + See Also + ======== + + summation + Product, product + + References + ========== + + .. [1] Michael Karr, "Summation in Finite Terms", Journal of the ACM, + Volume 28 Issue 2, April 1981, Pages 305-350 + http://dl.acm.org/citation.cfm?doid=322248.322255 + .. [2] http://en.wikipedia.org/wiki/Summation#Capital-sigma_notation + .. [3] http://en.wikipedia.org/wiki/Empty_sum + """ __slots__ = ['is_commutative'] @@ -48,7 +157,7 @@ arglist = [sign*function] arglist.extend(limits) obj._args = tuple(arglist) - obj.is_commutative = function.is_commutative # limits already checked + obj.is_commutative = function.is_commutative # limits already checked return obj @@ -73,19 +182,10 @@ @property def free_symbols(self): - """ - This method returns the symbols that will exist when the - summation is evaluated. This is useful if one is trying to - determine whether a sum depends on a certain symbol or not. - - >>> from sympy import Sum - >>> from sympy.abc import x, y - >>> Sum(x, (x, y, 1)).free_symbols - set([y]) - """ + from sympy.integrals.integrals import _free_symbols if self.function.is_zero: return set() - return _free_symbols(self.function, self.limits) + return _free_symbols(self) @property def is_zero(self): @@ -99,18 +199,14 @@ """ Return True if the Sum will result in a number, else False. - sympy considers anything that will result in a number to have - is_number == True. - - >>> from sympy import log - >>> log(2).is_number - True - Sums are a special case since they contain symbols that can be replaced with numbers. Whether the integral can be done or not is another issue. But answering whether the final result is a number is not difficult. + Examples + ======== + >>> from sympy import Sum >>> from sympy.abc import x, y >>> Sum(x, (y, 1, x)).is_number @@ -131,27 +227,41 @@ return self.function.is_zero or not self.free_symbols + def as_dummy(self): + from sympy.integrals.integrals import _as_dummy + return _as_dummy(self) + def doit(self, **hints): - #if not hints.get('sums', True): - # return self - f = self.function + if hints.get('deep', True): + f = self.function.doit(**hints) + else: + f = self.function + for limit in self.limits: i, a, b = limit dif = b - a if dif.is_Integer and dif < 0: - a, b = b, a + a, b = b + 1, a - 1 + f = -f f = eval_sum(f, (i, a, b)) if f is None: return self if hints.get('deep', True): - return f.doit(**hints) - else: - return f + # eval_sum could return partially unevaluated + # result with Piecewise. In this case we won't + # doit() recursively. + if not isinstance(f, Piecewise): + return f.doit(**hints) - def _eval_summation(self, f, x): - return + return f + + def _eval_adjoint(self): + return Sum(self.function.adjoint(), *self.limits) + + def _eval_conjugate(self): + return Sum(self.function.conjugate(), *self.limits) def _eval_derivative(self, x): """ @@ -175,7 +285,7 @@ limit = limits.pop(-1) - if limits: # f is the argument to a Sum + if limits: # f is the argument to a Sum f = Sum(f, *limits) if len(limit) == 3: @@ -190,6 +300,12 @@ else: return NotImplementedError('Lower and upper bound expected.') + def _eval_summation(self, f, x): + return None + + def _eval_transpose(self): + return Sum(self.function.transpose(), *self.limits) + def euler_maclaurin(self, m=0, n=0, eps=0, eval_integral=True): """ Return an Euler-Maclaurin approximation of self, where m is the @@ -238,10 +354,13 @@ f = self.function assert len(self.limits) == 1 i, a, b = self.limits[0] + if a > b: + a, b = b + 1, a - 1 + f = -f s = S.Zero if m: for k in range(m): - term = f.subs(i, a+k) + term = f.subs(i, a + k) if (eps and term and abs(term.evalf(3)) < eps): return s, abs(term) s += term @@ -251,6 +370,7 @@ if eval_integral: I = I.doit() s += I + def fpoint(expr): if b is S.Infinity: return expr.subs(i, a), 0 @@ -258,18 +378,19 @@ fa, fb = fpoint(f) iterm = (fa + fb)/2 g = f.diff(i) - for k in range(1, n+2): + for k in range(1, n + 2): ga, gb = fpoint(g) - term = C.bernoulli(2*k)/C.factorial(2*k)*(gb-ga) + term = C.bernoulli(2*k)/C.factorial(2*k)*(gb - ga) if (eps and term and abs(term.evalf(3)) < eps) or (k > n): break s += term - g = g.diff(i, 2) + g = g.diff(i, 2, simplify=False) return s + iterm, abs(term) - def _eval_subs(self, old, new): # XXX this should be the same as Integral's - if any(old == v for v in self.variables): - return self + def _eval_subs(self, old, new): + from sympy.integrals.integrals import _eval_subs + return _eval_subs(self, old, new) + def summation(f, *symbols, **kwargs): r""" @@ -308,9 +429,16 @@ >>> summation(x**n/factorial(n), (n, 0, oo)) exp(x) + See Also + ======== + + Sum + Product, product + """ return Sum(f, *symbols, **kwargs).doit(deep=False) + def telescopic_direct(L, R, n, limits): """Returns the direct summation of the terms of a telescopic sum @@ -329,9 +457,10 @@ (i, a, b) = limits s = 0 for m in range(n): - s += L.subs(i,a+m) + R.subs(i,b-m) + s += L.subs(i, a + m) + R.subs(i, b - m) return s + def telescopic(L, R, limits): '''Tries to perform the summation using the telescopic property @@ -350,7 +479,7 @@ s = None if sol and k in sol: s = sol[k] - if not (s.is_Integer and L.subs(i,i + s) == -R): + if not (s.is_Integer and L.subs(i, i + s) == -R): #sometimes match fail(f(x+2).match(-f(x+k))->{k: -2 - 2x})) s = None @@ -364,7 +493,7 @@ except NotImplementedError: return None sol = [si for si in sol if si.is_Integer and - (L.subs(i,i + si) + R).expand().is_zero] + (L.subs(i, i + si) + R).expand().is_zero] if len(sol) != 1: return None s = sol[0] @@ -374,7 +503,11 @@ elif s > 0: return telescopic_direct(L, R, s, (i, a, b)) + def eval_sum(f, limits): + from sympy.concrete.delta import deltasummation, _has_simple_delta + from sympy.functions import KroneckerDelta + (i, a, b) = limits if f is S.Zero: return S.Zero @@ -383,6 +516,9 @@ if a == b: return f.subs(i, a) + if f.has(KroneckerDelta) and _has_simple_delta(f, limits[0]): + return deltasummation(f, limits) + dif = b - a definite = dif.is_Integer # Doing it directly may be faster if there are very few terms. @@ -398,16 +534,18 @@ if definite: return eval_sum_direct(f, (i, a, b)) + def eval_sum_direct(expr, limits): (i, a, b) = limits dif = b - a return Add(*[expr.subs(i, a + j) for j in range(dif + 1)]) + def eval_sum_symbolic(f, limits): (i, a, b) = limits if not f.has(i): - return f*(b-a+1) + return f*(b - a + 1) # Linearity if f.is_Mul: @@ -415,14 +553,16 @@ if not L.has(i): sR = eval_sum_symbolic(R, (i, a, b)) - if sR: return L*sR + if sR: + return L*sR if not R.has(i): sL = eval_sum_symbolic(L, (i, a, b)) - if sL: return R*sL + if sL: + return R*sL try: - f = apart(f, i) # see if it becomes an Add + f = apart(f, i) # see if it becomes an Add except PolynomialError: pass @@ -448,30 +588,31 @@ if n.is_Integer: if n >= 0: - return ((C.bernoulli(n+1, b+1) - C.bernoulli(n+1, a))/(n+1)).expand() + return ((C.bernoulli(n + 1, b + 1) - C.bernoulli(n + 1, a))/(n + 1)).expand() elif a.is_Integer and a >= 1: if n == -1: return C.harmonic(b) - C.harmonic(a - 1) else: return C.harmonic(b, abs(n)) - C.harmonic(a - 1, abs(n)) - # Geometric terms - c1 = C.Wild('c1', exclude=[i]) - c2 = C.Wild('c2', exclude=[i]) - c3 = C.Wild('c3', exclude=[i]) - - e = f.match(c1**(c2*i+c3)) - - if e is not None: - c1 = c1.subs(e) - c2 = c2.subs(e) - c3 = c3.subs(e) + if not (a.has(S.Infinity, S.NegativeInfinity) or + b.has(S.Infinity, S.NegativeInfinity)): + # Geometric terms + c1 = C.Wild('c1', exclude=[i]) + c2 = C.Wild('c2', exclude=[i]) + c3 = C.Wild('c3', exclude=[i]) - # TODO: more general limit handling - return c1**c3 * (c1**(a*c2) - c1**(c2+b*c2)) / (1 - c1**c2) + e = f.match(c1**(c2*i + c3)) + + if e is not None: + p = (c1**c3).subs(e) + q = (c1**c2).subs(e) + + r = p*(q**a - q**(b + 1))/(1 - q) + l = p*(b - a + 1) + + return Piecewise((l, Eq(q, S.One)), (r, True)) - if not (a.has(S.Infinity, S.NegativeInfinity) or \ - b.has(S.Infinity, S.NegativeInfinity)): r = gosper_sum(f, (i, a, b)) if not r in (None, S.NaN): @@ -479,6 +620,7 @@ return eval_sum_hyper(f, (i, a, b)) + def _eval_sum_hyper(f, i, a): """ Returns (res, cond). Sums from a to oo. """ from sympy.functions import hyper @@ -522,14 +664,14 @@ # hypergeometric series. ap = params[0] + [1] bq = params[1] - x = ab[0]/ab[1] + x = ab[0]/ab[1] h = hyper(ap, bq, x) return f.subs(i, 0)*hyperexpand(h), h.convergence_statement + def eval_sum_hyper(f, xxx_todo_changeme): (i, a, b) = xxx_todo_changeme - from sympy.functions import Piecewise from sympy import oo, And if b != oo: @@ -563,4 +705,12 @@ # Now b == oo, a != -oo res = _eval_sum_hyper(f, i, a) if res is not None: + r, c = res + if c is False: + if r.is_number: + if f.is_positive or f.is_zero: + return S.Infinity + elif f.is_negative: + return S.NegativeInfinity + return None return Piecewise(res, (Sum(f, (i, a, b)), True)) diff -Nru python3-sympy-0.7.2/sympy/concrete/tests/test_delta.py python3-sympy-0.7.3/sympy/concrete/tests/test_delta.py --- python3-sympy-0.7.2/sympy/concrete/tests/test_delta.py 1970-01-01 00:00:00.000000000 +0000 +++ python3-sympy-0.7.3/sympy/concrete/tests/test_delta.py 2013-07-13 17:53:32.000000000 +0000 @@ -0,0 +1,412 @@ +from sympy.concrete import Sum +from sympy.concrete.delta import deltaproduct, deltasummation +from sympy.core import Eq, S, symbols, oo +from sympy.functions import KroneckerDelta, Piecewise, piecewise_fold +from sympy.logic import And + +i, j, k, l, m = symbols("i j k l m", integer=True) +x, y = symbols("x y", commutative=False) + +KD = KroneckerDelta + + +def test_deltaproduct(): + dp = deltaproduct + assert dp(x, (j, 1, 0)) == 1 + assert dp(x, (j, 1, 3)) == x**3 + assert dp(x + y, (j, 1, 3)) == (x + y)**3 + assert dp(x*y, (j, 1, 3)) == (x*y)**3 + assert dp(KD(i, j), (k, 1, 3)) == KD(i, j) + assert dp(x*KD(i, j), (k, 1, 3)) == x**3*KD(i, j) + assert dp(x*y*KD(i, j), (k, 1, 3)) == (x*y)**3*KD(i, j) + + assert dp(KD(i, j), (j, 1, 3)) == 0 + assert dp(KD(i, j), (j, 1, 1)) == KD(i, 1) + assert dp(KD(i, j), (j, 2, 2)) == KD(i, 2) + assert dp(KD(i, j), (j, 3, 3)) == KD(i, 3) + assert dp(KD(i, j), (j, 1, k)) == KD(i, 1)*KD(k, 1) + KD(k, 0) + assert dp(KD(i, j), (j, k, 3)) == KD(i, 3)*KD(k, 3) + KD(k, 4) + assert dp(KD(i, j), (j, k, l)) == KD(i, l)*KD(k, l) + KD(k, l + 1) + + assert dp(x*KD(i, j), (j, 1, 3)) == 0 + assert dp(x*KD(i, j), (j, 1, 1)) == x*KD(i, 1) + assert dp(x*KD(i, j), (j, 2, 2)) == x*KD(i, 2) + assert dp(x*KD(i, j), (j, 3, 3)) == x*KD(i, 3) + assert dp(x*KD(i, j), (j, 1, k)) == x*KD(i, 1)*KD(k, 1) + KD(k, 0) + assert dp(x*KD(i, j), (j, k, 3)) == x*KD(i, 3)*KD(k, 3) + KD(k, 4) + assert dp(x*KD(i, j), (j, k, l)) == x*KD(i, l)*KD(k, l) + KD(k, l + 1) + + assert dp((x + y)*KD(i, j), (j, 1, 3)) == 0 + assert dp((x + y)*KD(i, j), (j, 1, 1)) == (x + y)*KD(i, 1) + assert dp((x + y)*KD(i, j), (j, 2, 2)) == (x + y)*KD(i, 2) + assert dp((x + y)*KD(i, j), (j, 3, 3)) == (x + y)*KD(i, 3) + assert dp((x + y)*KD(i, j), (j, 1, k)) == \ + (x + y)*KD(i, 1)*KD(k, 1) + KD(k, 0) + assert dp((x + y)*KD(i, j), (j, k, 3)) == \ + (x + y)*KD(i, 3)*KD(k, 3) + KD(k, 4) + assert dp((x + y)*KD(i, j), (j, k, l)) == \ + (x + y)*KD(i, l)*KD(k, l) + KD(k, l + 1) + + assert dp(KD(i, k) + KD(j, k), (k, 1, 3)) == 0 + assert dp(KD(i, k) + KD(j, k), (k, 1, 1)) == KD(i, 1) + KD(j, 1) + assert dp(KD(i, k) + KD(j, k), (k, 2, 2)) == KD(i, 2) + KD(j, 2) + assert dp(KD(i, k) + KD(j, k), (k, 3, 3)) == KD(i, 3) + KD(j, 3) + assert dp(KD(i, k) + KD(j, k), (k, 1, l)) == KD(l, 0) + \ + KD(i, 1)*KD(l, 1) + KD(j, 1)*KD(l, 1) + \ + KD(i, 1)*KD(j, 2)*KD(l, 2) + KD(j, 1)*KD(i, 2)*KD(l, 2) + assert dp(KD(i, k) + KD(j, k), (k, l, 3)) == KD(l, 4) + \ + KD(i, 3)*KD(l, 3) + KD(j, 3)*KD(l, 3) + \ + KD(i, 2)*KD(j, 3)*KD(l, 2) + KD(i, 3)*KD(j, 2)*KD(l, 2) + assert dp(KD(i, k) + KD(j, k), (k, l, m)) == KD(l, m + 1) + \ + KD(i, m)*KD(l, m) + KD(j, m)*KD(l, m) + \ + KD(i, m)*KD(j, m - 1)*KD(l, m - 1) + KD(i, m - 1)*KD(j, m)*KD(l, m - 1) + + assert dp(x*(KD(i, k) + KD(j, k)), (k, 1, 3)) == 0 + assert dp(x*(KD(i, k) + KD(j, k)), (k, 1, 1)) == x*(KD(i, 1) + KD(j, 1)) + assert dp(x*(KD(i, k) + KD(j, k)), (k, 2, 2)) == x*(KD(i, 2) + KD(j, 2)) + assert dp(x*(KD(i, k) + KD(j, k)), (k, 3, 3)) == x*(KD(i, 3) + KD(j, 3)) + assert dp(x*(KD(i, k) + KD(j, k)), (k, 1, l)) == KD(l, 0) + \ + x*KD(i, 1)*KD(l, 1) + x*KD(j, 1)*KD(l, 1) + \ + x**2*KD(i, 1)*KD(j, 2)*KD(l, 2) + x**2*KD(j, 1)*KD(i, 2)*KD(l, 2) + assert dp(x*(KD(i, k) + KD(j, k)), (k, l, 3)) == KD(l, 4) + \ + x*KD(i, 3)*KD(l, 3) + x*KD(j, 3)*KD(l, 3) + \ + x**2*KD(i, 2)*KD(j, 3)*KD(l, 2) + x**2*KD(i, 3)*KD(j, 2)*KD(l, 2) + assert dp(x*(KD(i, k) + KD(j, k)), (k, l, m)) == KD(l, m + 1) + \ + x*KD(i, m)*KD(l, m) + x*KD(j, m)*KD(l, m) + \ + x**2*KD(i, m - 1)*KD(j, m)*KD(l, m - 1) + \ + x**2*KD(i, m)*KD(j, m - 1)*KD(l, m - 1) + + assert dp((x + y)*(KD(i, k) + KD(j, k)), (k, 1, 3)) == 0 + assert dp((x + y)*(KD(i, k) + KD(j, k)), (k, 1, 1)) == \ + (x + y)*(KD(i, 1) + KD(j, 1)) + assert dp((x + y)*(KD(i, k) + KD(j, k)), (k, 2, 2)) == \ + (x + y)*(KD(i, 2) + KD(j, 2)) + assert dp((x + y)*(KD(i, k) + KD(j, k)), (k, 3, 3)) == \ + (x + y)*(KD(i, 3) + KD(j, 3)) + assert dp((x + y)*(KD(i, k) + KD(j, k)), (k, 1, l)) == KD(l, 0) + \ + (x + y)*KD(i, 1)*KD(l, 1) + (x + y)*KD(j, 1)*KD(l, 1) + \ + (x + y)**2*KD(i, 1)*KD(j, 2)*KD(l, 2) + \ + (x + y)**2*KD(j, 1)*KD(i, 2)*KD(l, 2) + assert dp((x + y)*(KD(i, k) + KD(j, k)), (k, l, 3)) == KD(l, 4) + \ + (x + y)*KD(i, 3)*KD(l, 3) + (x + y)*KD(j, 3)*KD(l, 3) + \ + (x + y)**2*KD(i, 2)*KD(j, 3)*KD(l, 2) + \ + (x + y)**2*KD(i, 3)*KD(j, 2)*KD(l, 2) + assert dp((x + y)*(KD(i, k) + KD(j, k)), (k, l, m)) == KD(l, m + 1) + \ + (x + y)*KD(i, m)*KD(l, m) + (x + y)*KD(j, m)*KD(l, m) + \ + (x + y)**2*KD(i, m - 1)*KD(j, m)*KD(l, m - 1) + \ + (x + y)**2*KD(i, m)*KD(j, m - 1)*KD(l, m - 1) + + assert dp(x*y + x*KD(i, j), (j, 1, 3)) == (x*y)**3 + \ + x*(x*y)**2*KD(i, 1) + (x*y)*x*(x*y)*KD(i, 2) + (x*y)**2*x*KD(i, 3) + assert dp(x*y + x*KD(i, j), (j, 1, 1)) == x*y + x*KD(i, 1) + assert dp(x*y + x*KD(i, j), (j, 2, 2)) == x*y + x*KD(i, 2) + assert dp(x*y + x*KD(i, j), (j, 3, 3)) == x*y + x*KD(i, 3) + assert dp(x*y + x*KD(i, j), (j, 1, k)) == \ + (x*y)**k + (x*y)**(i - 1)*x*(x*y)**(k - i) + assert dp(x*y + x*KD(i, j), (j, k, 3)) == \ + (x*y)**(-k + 4) + (x*y)**(i - k)*x*(x*y)**(3 - i) + assert dp(x*y + x*KD(i, j), (j, k, l)) == \ + (x*y)**(-k + l + 1) + (x*y)**(i - k)*x*(x*y)**(l - i) + + assert dp(x*(y + KD(i, j)), (j, 1, 3)) == (x*y)**3 + \ + x*(x*y)**2*KD(i, 1) + (x*y)*x*(x*y)*KD(i, 2) + (x*y)**2*x*KD(i, 3) + assert dp(x*(y + KD(i, j)), (j, 1, 1)) == x*(y + KD(i, 1)) + assert dp(x*(y + KD(i, j)), (j, 2, 2)) == x*(y + KD(i, 2)) + assert dp(x*(y + KD(i, j)), (j, 3, 3)) == x*(y + KD(i, 3)) + assert dp(x*(y + KD(i, j)), (j, 1, k)) == \ + (x*y)**k + (x*y)**(i - 1)*x*(x*y)**(k - i) + assert dp(x*(y + KD(i, j)), (j, k, 3)) == \ + (x*y)**(-k + 4) + (x*y)**(i - k)*x*(x*y)**(3 - i) + assert dp(x*(y + KD(i, j)), (j, k, l)) == \ + (x*y)**(-k + l + 1) + (x*y)**(i - k)*x*(x*y)**(l - i) + + assert dp(x*(y + 2*KD(i, j)), (j, 1, 3)) == (x*y)**3 + \ + 2*x*(x*y)**2*KD(i, 1) + 2*x*y*x*x*y*KD(i, 2) + 2*(x*y)**2*x*KD(i, 3) + assert dp(x*(y + 2*KD(i, j)), (j, 1, 1)) == x*(y + 2*KD(i, 1)) + assert dp(x*(y + 2*KD(i, j)), (j, 2, 2)) == x*(y + 2*KD(i, 2)) + assert dp(x*(y + 2*KD(i, j)), (j, 3, 3)) == x*(y + 2*KD(i, 3)) + assert dp(x*(y + 2*KD(i, j)), (j, 1, k)) == \ + (x*y)**k + 2*(x*y)**(i - 1)*x*(x*y)**(k - i) + assert dp(x*(y + 2*KD(i, j)), (j, k, 3)) == \ + (x*y)**(-k + 4) + 2*(x*y)**(i - k)*x*(x*y)**(3 - i) + assert dp(x*(y + 2*KD(i, j)), (j, k, l)) == \ + (x*y)**(-k + l + 1) + 2*(x*y)**(i - k)*x*(x*y)**(l - i) + + assert dp((x + y)*(y + KD(i, j)), (j, 1, 3)) == ((x + y)*y)**3 + \ + (x + y)*((x + y)*y)**2*KD(i, 1) + \ + (x + y)*y*(x + y)**2*y*KD(i, 2) + \ + ((x + y)*y)**2*(x + y)*KD(i, 3) + assert dp((x + y)*(y + KD(i, j)), (j, 1, 1)) == (x + y)*(y + KD(i, 1)) + assert dp((x + y)*(y + KD(i, j)), (j, 2, 2)) == (x + y)*(y + KD(i, 2)) + assert dp((x + y)*(y + KD(i, j)), (j, 3, 3)) == (x + y)*(y + KD(i, 3)) + assert dp((x + y)*(y + KD(i, j)), (j, 1, k)) == ((x + y)*y)**k + \ + ((x + y)*y)**(i - 1)*(x + y)*((x + y)*y)**(k - i) + assert dp((x + y)*(y + KD(i, j)), (j, k, 3)) == ((x + y)*y)**(-k + 4) + \ + ((x + y)*y)**(i - k)*(x + y)*((x + y)*y)**(3 - i) + assert dp((x + y)*(y + KD(i, j)), (j, k, l)) == \ + ((x + y)*y)**(-k + l + 1) + \ + ((x + y)*y)**(i - k)*(x + y)*((x + y)*y)**(l - i) + + assert dp((x + KD(i, k))*(y + KD(i, j)), (j, 1, 3)) == \ + KD(i, 1)*(KD(i, k) + x)*((KD(i, k) + x)*y)**2 + \ + KD(i, 2)*(KD(i, k) + x)*y*(KD(i, k) + x)**2*y + \ + KD(i, 3)*((KD(i, k) + x)*y)**2*(KD(i, k) + x) + \ + ((KD(i, k) + x)*y)**3 + assert dp((x + KD(i, k))*(y + KD(i, j)), (j, 1, 1)) == \ + (x + KD(i, k))*(y + KD(i, 1)) + assert dp((x + KD(i, k))*(y + KD(i, j)), (j, 2, 2)) == \ + (x + KD(i, k))*(y + KD(i, 2)) + assert dp((x + KD(i, k))*(y + KD(i, j)), (j, 3, 3)) == \ + (x + KD(i, k))*(y + KD(i, 3)) + assert dp((x + KD(i, k))*(y + KD(i, j)), (j, 1, k)) == \ + ((x + KD(i, k))*y)**k + \ + ((x + KD(i, k))*y)**(i - 1)*(x + KD(i, k))*((x + KD(i, k))*y)**(-i + k) + assert dp((x + KD(i, k))*(y + KD(i, j)), (j, k, 3)) == \ + ((x + KD(i, k))*y)**(4 - k) + \ + ((x + KD(i, k))*y)**(i - k)*(x + KD(i, k))*((x + KD(i, k))*y)**(-i + 3) + assert dp((x + KD(i, k))*(y + KD(i, j)), (j, k, l)) == \ + ((x + KD(i, k))*y)**(-k + l + 1) + \ + ((x + KD(i, k))*y)**(i - k)*(x + KD(i, k))*((x + KD(i, k))*y)**(-i + l) + + +def test_deltasummation(): + ds = deltasummation + assert ds(x, (j, 1, 0)) == 0 + assert ds(x, (j, 1, 3)) == 3*x + assert ds(x + y, (j, 1, 3)) == 3*(x + y) + assert ds(x*y, (j, 1, 3)) == 3*x*y + assert ds(KD(i, j), (k, 1, 3)) == 3*KD(i, j) + assert ds(x*KD(i, j), (k, 1, 3)) == 3*x*KD(i, j) + assert ds(x*y*KD(i, j), (k, 1, 3)) == 3*x*y*KD(i, j) + + n = symbols('n', integer=True, nonzero=True) + assert ds(KD(n, 0), (n, 1, 3)) == 0 + + # return unevaluated, until it gets implemented + assert ds(KD(i**2, j**2), (j, -oo, oo)) == \ + Sum(KD(i**2, j**2), (j, -oo, oo)) + + assert Piecewise((KD(i, k), And(S(1) <= i, i <= 3)), (0, True)) == \ + ds(KD(i, j)*KD(j, k), (j, 1, 3)) == \ + ds(KD(j, k)*KD(i, j), (j, 1, 3)) + + assert ds(KD(i, k), (k, -oo, oo)) == 1 + assert ds(KD(i, k), (k, 0, oo)) == Piecewise((1, i >= 0), (0, True)) + assert ds(KD(i, k), (k, 1, 3)) == \ + Piecewise((1, And(S(1) <= i, i <= 3)), (0, True)) + assert ds(k*KD(i, j)*KD(j, k), (k, -oo, oo)) == j*KD(i, j) + assert ds(j*KD(i, j), (j, -oo, oo)) == i + assert ds(i*KD(i, j), (i, -oo, oo)) == j + assert ds(x, (i, 1, 3)) == 3*x + assert ds((i + j)*KD(i, j), (j, -oo, oo)) == 2*i + + assert ds(KD(i, j), (j, 1, 3)) == \ + Piecewise((1, And(S(1) <= i, i <= 3)), (0, True)) + assert ds(KD(i, j), (j, 1, 1)) == Piecewise((1, Eq(i, 1)), (0, True)) + assert ds(KD(i, j), (j, 2, 2)) == Piecewise((1, Eq(i, 2)), (0, True)) + assert ds(KD(i, j), (j, 3, 3)) == Piecewise((1, Eq(i, 3)), (0, True)) + assert ds(KD(i, j), (j, 1, k)) == \ + Piecewise((1, And(S(1) <= i, i <= k)), (0, True)) + assert ds(KD(i, j), (j, k, 3)) == \ + Piecewise((1, And(k <= i, i <= 3)), (0, True)) + assert ds(KD(i, j), (j, k, l)) == \ + Piecewise((1, And(k <= i, i <= l)), (0, True)) + + assert ds(x*KD(i, j), (j, 1, 3)) == \ + Piecewise((x, And(S(1) <= i, i <= 3)), (0, True)) + assert ds(x*KD(i, j), (j, 1, 1)) == Piecewise((x, Eq(i, 1)), (0, True)) + assert ds(x*KD(i, j), (j, 2, 2)) == Piecewise((x, Eq(i, 2)), (0, True)) + assert ds(x*KD(i, j), (j, 3, 3)) == Piecewise((x, Eq(i, 3)), (0, True)) + assert ds(x*KD(i, j), (j, 1, k)) == \ + Piecewise((x, And(S(1) <= i, i <= k)), (0, True)) + assert ds(x*KD(i, j), (j, k, 3)) == \ + Piecewise((x, And(k <= i, i <= 3)), (0, True)) + assert ds(x*KD(i, j), (j, k, l)) == \ + Piecewise((x, And(k <= i, i <= l)), (0, True)) + + assert ds((x + y)*KD(i, j), (j, 1, 3)) == \ + Piecewise((x + y, And(S(1) <= i, i <= 3)), (0, True)) + assert ds((x + y)*KD(i, j), (j, 1, 1)) == \ + Piecewise((x + y, Eq(i, 1)), (0, True)) + assert ds((x + y)*KD(i, j), (j, 2, 2)) == \ + Piecewise((x + y, Eq(i, 2)), (0, True)) + assert ds((x + y)*KD(i, j), (j, 3, 3)) == \ + Piecewise((x + y, Eq(i, 3)), (0, True)) + assert ds((x + y)*KD(i, j), (j, 1, k)) == \ + Piecewise((x + y, And(S(1) <= i, i <= k)), (0, True)) + assert ds((x + y)*KD(i, j), (j, k, 3)) == \ + Piecewise((x + y, And(k <= i, i <= 3)), (0, True)) + assert ds((x + y)*KD(i, j), (j, k, l)) == \ + Piecewise((x + y, And(k <= i, i <= l)), (0, True)) + + assert ds(KD(i, k) + KD(j, k), (k, 1, 3)) == piecewise_fold( + Piecewise((1, And(S(1) <= i, i <= 3)), (0, True)) + + Piecewise((1, And(S(1) <= j, j <= 3)), (0, True))) + assert ds(KD(i, k) + KD(j, k), (k, 1, 1)) == piecewise_fold( + Piecewise((1, Eq(i, 1)), (0, True)) + + Piecewise((1, Eq(j, 1)), (0, True))) + assert ds(KD(i, k) + KD(j, k), (k, 2, 2)) == piecewise_fold( + Piecewise((1, Eq(i, 2)), (0, True)) + + Piecewise((1, Eq(j, 2)), (0, True))) + assert ds(KD(i, k) + KD(j, k), (k, 3, 3)) == piecewise_fold( + Piecewise((1, Eq(i, 3)), (0, True)) + + Piecewise((1, Eq(j, 3)), (0, True))) + assert ds(KD(i, k) + KD(j, k), (k, 1, l)) == piecewise_fold( + Piecewise((1, And(S(1) <= i, i <= l)), (0, True)) + + Piecewise((1, And(S(1) <= j, j <= l)), (0, True))) + assert ds(KD(i, k) + KD(j, k), (k, l, 3)) == piecewise_fold( + Piecewise((1, And(l <= i, i <= 3)), (0, True)) + + Piecewise((1, And(l <= j, j <= 3)), (0, True))) + assert ds(KD(i, k) + KD(j, k), (k, l, m)) == piecewise_fold( + Piecewise((1, And(l <= i, i <= m)), (0, True)) + + Piecewise((1, And(l <= j, j <= m)), (0, True))) + + assert ds(x*KD(i, k) + KD(j, k), (k, 1, 3)) == piecewise_fold( + Piecewise((x, And(S(1) <= i, i <= 3)), (0, True)) + + Piecewise((1, And(S(1) <= j, j <= 3)), (0, True))) + assert ds(x*KD(i, k) + KD(j, k), (k, 1, 1)) == piecewise_fold( + Piecewise((x, Eq(i, 1)), (0, True)) + + Piecewise((1, Eq(j, 1)), (0, True))) + assert ds(x*KD(i, k) + KD(j, k), (k, 2, 2)) == piecewise_fold( + Piecewise((x, Eq(i, 2)), (0, True)) + + Piecewise((1, Eq(j, 2)), (0, True))) + assert ds(x*KD(i, k) + KD(j, k), (k, 3, 3)) == piecewise_fold( + Piecewise((x, Eq(i, 3)), (0, True)) + + Piecewise((1, Eq(j, 3)), (0, True))) + assert ds(x*KD(i, k) + KD(j, k), (k, 1, l)) == piecewise_fold( + Piecewise((x, And(S(1) <= i, i <= l)), (0, True)) + + Piecewise((1, And(S(1) <= j, j <= l)), (0, True))) + assert ds(x*KD(i, k) + KD(j, k), (k, l, 3)) == piecewise_fold( + Piecewise((x, And(l <= i, i <= 3)), (0, True)) + + Piecewise((1, And(l <= j, j <= 3)), (0, True))) + assert ds(x*KD(i, k) + KD(j, k), (k, l, m)) == piecewise_fold( + Piecewise((x, And(l <= i, i <= m)), (0, True)) + + Piecewise((1, And(l <= j, j <= m)), (0, True))) + + assert ds(x*(KD(i, k) + KD(j, k)), (k, 1, 3)) == piecewise_fold( + Piecewise((x, And(S(1) <= i, i <= 3)), (0, True)) + + Piecewise((x, And(S(1) <= j, j <= 3)), (0, True))) + assert ds(x*(KD(i, k) + KD(j, k)), (k, 1, 1)) == piecewise_fold( + Piecewise((x, Eq(i, 1)), (0, True)) + + Piecewise((x, Eq(j, 1)), (0, True))) + assert ds(x*(KD(i, k) + KD(j, k)), (k, 2, 2)) == piecewise_fold( + Piecewise((x, Eq(i, 2)), (0, True)) + + Piecewise((x, Eq(j, 2)), (0, True))) + assert ds(x*(KD(i, k) + KD(j, k)), (k, 3, 3)) == piecewise_fold( + Piecewise((x, Eq(i, 3)), (0, True)) + + Piecewise((x, Eq(j, 3)), (0, True))) + assert ds(x*(KD(i, k) + KD(j, k)), (k, 1, l)) == piecewise_fold( + Piecewise((x, And(S(1) <= i, i <= l)), (0, True)) + + Piecewise((x, And(S(1) <= j, j <= l)), (0, True))) + assert ds(x*(KD(i, k) + KD(j, k)), (k, l, 3)) == piecewise_fold( + Piecewise((x, And(l <= i, i <= 3)), (0, True)) + + Piecewise((x, And(l <= j, j <= 3)), (0, True))) + assert ds(x*(KD(i, k) + KD(j, k)), (k, l, m)) == piecewise_fold( + Piecewise((x, And(l <= i, i <= m)), (0, True)) + + Piecewise((x, And(l <= j, j <= m)), (0, True))) + + assert ds((x + y)*(KD(i, k) + KD(j, k)), (k, 1, 3)) == piecewise_fold( + Piecewise((x + y, And(S(1) <= i, i <= 3)), (0, True)) + + Piecewise((x + y, And(S(1) <= j, j <= 3)), (0, True))) + assert ds((x + y)*(KD(i, k) + KD(j, k)), (k, 1, 1)) == piecewise_fold( + Piecewise((x + y, Eq(i, 1)), (0, True)) + + Piecewise((x + y, Eq(j, 1)), (0, True))) + assert ds((x + y)*(KD(i, k) + KD(j, k)), (k, 2, 2)) == piecewise_fold( + Piecewise((x + y, Eq(i, 2)), (0, True)) + + Piecewise((x + y, Eq(j, 2)), (0, True))) + assert ds((x + y)*(KD(i, k) + KD(j, k)), (k, 3, 3)) == piecewise_fold( + Piecewise((x + y, Eq(i, 3)), (0, True)) + + Piecewise((x + y, Eq(j, 3)), (0, True))) + assert ds((x + y)*(KD(i, k) + KD(j, k)), (k, 1, l)) == piecewise_fold( + Piecewise((x + y, And(S(1) <= i, i <= l)), (0, True)) + + Piecewise((x + y, And(S(1) <= j, j <= l)), (0, True))) + assert ds((x + y)*(KD(i, k) + KD(j, k)), (k, l, 3)) == piecewise_fold( + Piecewise((x + y, And(l <= i, i <= 3)), (0, True)) + + Piecewise((x + y, And(l <= j, j <= 3)), (0, True))) + assert ds((x + y)*(KD(i, k) + KD(j, k)), (k, l, m)) == piecewise_fold( + Piecewise((x + y, And(l <= i, i <= m)), (0, True)) + + Piecewise((x + y, And(l <= j, j <= m)), (0, True))) + + assert ds(x*y + x*KD(i, j), (j, 1, 3)) == \ + Piecewise((3*x*y + x, And(S(1) <= i, i <= 3)), (3*x*y, True)) + assert ds(x*y + x*KD(i, j), (j, 1, 1)) == \ + Piecewise((x*y + x, Eq(i, 1)), (x*y, True)) + assert ds(x*y + x*KD(i, j), (j, 2, 2)) == \ + Piecewise((x*y + x, Eq(i, 2)), (x*y, True)) + assert ds(x*y + x*KD(i, j), (j, 3, 3)) == \ + Piecewise((x*y + x, Eq(i, 3)), (x*y, True)) + assert ds(x*y + x*KD(i, j), (j, 1, k)) == \ + Piecewise((k*x*y + x, And(S(1) <= i, i <= k)), (k*x*y, True)) + assert ds(x*y + x*KD(i, j), (j, k, 3)) == \ + Piecewise(((4 - k)*x*y + x, And(k <= i, i <= 3)), ((4 - k)*x*y, True)) + assert ds(x*y + x*KD(i, j), (j, k, l)) == Piecewise( + ((l - k + 1)*x*y + x, And(k <= i, i <= l)), ((l - k + 1)*x*y, True)) + + assert ds(x*(y + KD(i, j)), (j, 1, 3)) == \ + Piecewise((3*x*y + x, And(S(1) <= i, i <= 3)), (3*x*y, True)) + assert ds(x*(y + KD(i, j)), (j, 1, 1)) == \ + Piecewise((x*y + x, Eq(i, 1)), (x*y, True)) + assert ds(x*(y + KD(i, j)), (j, 2, 2)) == \ + Piecewise((x*y + x, Eq(i, 2)), (x*y, True)) + assert ds(x*(y + KD(i, j)), (j, 3, 3)) == \ + Piecewise((x*y + x, Eq(i, 3)), (x*y, True)) + assert ds(x*(y + KD(i, j)), (j, 1, k)) == \ + Piecewise((k*x*y + x, And(S(1) <= i, i <= k)), (k*x*y, True)) + assert ds(x*(y + KD(i, j)), (j, k, 3)) == \ + Piecewise(((4 - k)*x*y + x, And(k <= i, i <= 3)), ((4 - k)*x*y, True)) + assert ds(x*(y + KD(i, j)), (j, k, l)) == Piecewise( + ((l - k + 1)*x*y + x, And(k <= i, i <= l)), ((l - k + 1)*x*y, True)) + + assert ds(x*(y + 2*KD(i, j)), (j, 1, 3)) == \ + Piecewise((3*x*y + 2*x, And(S(1) <= i, i <= 3)), (3*x*y, True)) + assert ds(x*(y + 2*KD(i, j)), (j, 1, 1)) == \ + Piecewise((x*y + 2*x, Eq(i, 1)), (x*y, True)) + assert ds(x*(y + 2*KD(i, j)), (j, 2, 2)) == \ + Piecewise((x*y + 2*x, Eq(i, 2)), (x*y, True)) + assert ds(x*(y + 2*KD(i, j)), (j, 3, 3)) == \ + Piecewise((x*y + 2*x, Eq(i, 3)), (x*y, True)) + assert ds(x*(y + 2*KD(i, j)), (j, 1, k)) == \ + Piecewise((k*x*y + 2*x, And(S(1) <= i, i <= k)), (k*x*y, True)) + assert ds(x*(y + 2*KD(i, j)), (j, k, 3)) == Piecewise( + ((4 - k)*x*y + 2*x, And(k <= i, i <= 3)), ((4 - k)*x*y, True)) + assert ds(x*(y + 2*KD(i, j)), (j, k, l)) == Piecewise( + ((l - k + 1)*x*y + 2*x, And(k <= i, i <= l)), ((l - k + 1)*x*y, True)) + + assert ds((x + y)*(y + KD(i, j)), (j, 1, 3)) == Piecewise( + (3*(x + y)*y + x + y, And(S(1) <= i, i <= 3)), (3*(x + y)*y, True)) + assert ds((x + y)*(y + KD(i, j)), (j, 1, 1)) == \ + Piecewise(((x + y)*y + x + y, Eq(i, 1)), ((x + y)*y, True)) + assert ds((x + y)*(y + KD(i, j)), (j, 2, 2)) == \ + Piecewise(((x + y)*y + x + y, Eq(i, 2)), ((x + y)*y, True)) + assert ds((x + y)*(y + KD(i, j)), (j, 3, 3)) == \ + Piecewise(((x + y)*y + x + y, Eq(i, 3)), ((x + y)*y, True)) + assert ds((x + y)*(y + KD(i, j)), (j, 1, k)) == Piecewise( + (k*(x + y)*y + x + y, And(S(1) <= i, i <= k)), (k*(x + y)*y, True)) + assert ds((x + y)*(y + KD(i, j)), (j, k, 3)) == Piecewise( + ((4 - k)*(x + y)*y + x + y, And(k <= i, i <= 3)), + ((4 - k)*(x + y)*y, True)) + assert ds((x + y)*(y + KD(i, j)), (j, k, l)) == Piecewise( + ((l - k + 1)*(x + y)*y + x + y, And(k <= i, i <= l)), + ((l - k + 1)*(x + y)*y, True)) + + assert ds((x + KD(i, k))*(y + KD(i, j)), (j, 1, 3)) == piecewise_fold( + Piecewise((KD(i, k) + x, And(S(1) <= i, i <= 3)), (0, True)) + + 3*(KD(i, k) + x)*y) + assert ds((x + KD(i, k))*(y + KD(i, j)), (j, 1, 1)) == piecewise_fold( + Piecewise((KD(i, k) + x, Eq(i, 1)), (0, True)) + + (KD(i, k) + x)*y) + assert ds((x + KD(i, k))*(y + KD(i, j)), (j, 2, 2)) == piecewise_fold( + Piecewise((KD(i, k) + x, Eq(i, 2)), (0, True)) + + (KD(i, k) + x)*y) + assert ds((x + KD(i, k))*(y + KD(i, j)), (j, 3, 3)) == piecewise_fold( + Piecewise((KD(i, k) + x, Eq(i, 3)), (0, True)) + + (KD(i, k) + x)*y) + assert ds((x + KD(i, k))*(y + KD(i, j)), (j, 1, k)) == piecewise_fold( + Piecewise((KD(i, k) + x, And(S(1) <= i, i <= k)), (0, True)) + + k*(KD(i, k) + x)*y) + assert ds((x + KD(i, k))*(y + KD(i, j)), (j, k, 3)) == piecewise_fold( + Piecewise((KD(i, k) + x, And(k <= i, i <= 3)), (0, True)) + + (4 - k)*(KD(i, k) + x)*y) + assert ds((x + KD(i, k))*(y + KD(i, j)), (j, k, l)) == piecewise_fold( + Piecewise((KD(i, k) + x, And(k <= i, i <= l)), (0, True)) + + (l - k + 1)*(KD(i, k) + x)*y) diff -Nru python3-sympy-0.7.2/sympy/concrete/tests/test_gosper.py python3-sympy-0.7.3/sympy/concrete/tests/test_gosper.py --- python3-sympy-0.7.2/sympy/concrete/tests/test_gosper.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/concrete/tests/test_gosper.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,16 +1,20 @@ """Tests for Gosper's algorithm for hypergeometric summation. """ -from sympy import binomial, factorial, gamma, Poly, S, simplify, sqrt +from sympy import binomial, factorial, gamma, Poly, S, simplify, sqrt, exp, log from sympy.abc import a, b, j, k, m, n, r, x from sympy.concrete.gosper import gosper_normal, gosper_sum, gosper_term from sympy.utilities.pytest import XFAIL + def test_gosper_normal(): assert gosper_normal(4*n + 5, 2*(4*n + 1)*(2*n + 3), n) == \ (Poly(S(1)/4, n), Poly(n + S(3)/2), Poly(n + S(1)/4)) + def test_gosper_term(): - assert gosper_term((4*k + 1)*factorial(k)/factorial(2*k + 1), k) == (-k - S(1)/2)/(k + S(1)/4) + assert gosper_term((4*k + 1)*factorial( + k)/factorial(2*k + 1), k) == (-k - S(1)/2)/(k + S(1)/4) + def test_gosper_sum(): assert gosper_sum(1, (k, 0, n)) == 1 + n @@ -27,14 +31,24 @@ assert gosper_sum((k - 3)*factorial(k), (k, 0, n)) is None assert gosper_sum(k*factorial(k), k) == factorial(k) - assert gosper_sum(k*factorial(k), (k, 0, n)) == n*factorial(n) + factorial(n) - 1 + assert gosper_sum( + k*factorial(k), (k, 0, n)) == n*factorial(n) + factorial(n) - 1 assert gosper_sum((-1)**k*binomial(n, k), (k, 0, n)) == 0 - assert gosper_sum((-1)**k*binomial(n, k), (k, 0, m)) == -(-1)**m*(m - n)*binomial(n, m)/n + assert gosper_sum(( + -1)**k*binomial(n, k), (k, 0, m)) == -(-1)**m*(m - n)*binomial(n, m)/n assert gosper_sum((4*k + 1)*factorial(k)/factorial(2*k + 1), (k, 0, n)) == \ (2*factorial(2*n + 1) - factorial(n))/factorial(2*n + 1) + # issue 2934: + assert gosper_sum( + n*(n + a + b)*a**n*b**n/(factorial(n + a)*factorial(n + b)), \ + (n, 0, m)) == -a*b*(exp(m*log(a))*exp(m*log(b))*factorial(a)* \ + factorial(b) - factorial(a + m)*factorial(b + m))/(factorial(a)* \ + factorial(b)*factorial(a + m)*factorial(b + m)) + + def test_gosper_sum_indefinite(): assert gosper_sum(k, k) == k*(k - 1)/2 assert gosper_sum(k**2, k) == k*(k - 1)*(2*k - 1)/6 @@ -43,12 +57,17 @@ assert gosper_sum(-(27*k**4 + 158*k**3 + 430*k**2 + 678*k + 445)*gamma(2*k + 4)/(3*(3*k + 7)*gamma(3*k + 6)), k) == \ (3*k + 5)*(k**2 + 2*k + 5)*gamma(2*k + 4)/gamma(3*k + 6) + def test_gosper_sum_parametric(): assert gosper_sum(binomial(S(1)/2, m - j + 1)*binomial(S(1)/2, m + j), (j, 1, n)) == \ - n*(1 + m - n)*(-1 + 2*m + 2*n)*binomial(S(1)/2, 1 + m - n)*binomial(S(1)/2, m + n)/(m*(1 + 2*m)) + n*(1 + m - n)*(-1 + 2*m + 2*n)*binomial(S(1)/2, 1 + m - n)* \ + binomial(S(1)/2, m + n)/(m*(1 + 2*m)) + def test_gosper_sum_algebraic(): - assert gosper_sum(n**2 + sqrt(2), (n, 0, m)) == (m + 1)*(2*m**2 + m + 6*sqrt(2))/6 + assert gosper_sum( + n**2 + sqrt(2), (n, 0, m)) == (m + 1)*(2*m**2 + m + 6*sqrt(2))/6 + def test_gosper_sum_iterated(): f1 = binomial(2*k, k)/4**k @@ -64,6 +83,8 @@ # the AeqB tests test expressions given in # www.math.upenn.edu/~wilf/AeqB.pdf + + def test_gosper_sum_AeqB_part1(): f1a = n**4 f1b = n**3*2**n @@ -76,9 +97,12 @@ g1a = m*(m + 1)*(2*m + 1)*(3*m**2 + 3*m - 1)/30 g1b = 26 + 2**(m + 1)*(m**3 - 3*m**2 + 9*m - 13) - g1c = (m + 1)*(m*(m**2 - 7*m + 3)*sqrt(5) - (3*m**3 - 7*m**2 + 19*m - 6))/(2*m**3*sqrt(5) + m**4 + 5*m**2 - 1)/6 - g1d = -S(2)/231 + 2*4**m*(m + 1)*(63*m**4 + 112*m**3 + 18*m**2 - 22*m + 3)/(693*binomial(2*m, m)) - g1e = -S(9)/2 + (81*m**2 + 261*m + 200)*factorial(3*m + 2)/(40*27**m*factorial(m)*factorial(m + 1)*factorial(m + 2)) + g1c = (m + 1)*(m*(m**2 - 7*m + 3)*sqrt(5) - ( + 3*m**3 - 7*m**2 + 19*m - 6))/(2*m**3*sqrt(5) + m**4 + 5*m**2 - 1)/6 + g1d = -S(2)/231 + 2*4**m*(m + 1)*(63*m**4 + 112*m**3 + 18*m**2 - + 22*m + 3)/(693*binomial(2*m, m)) + g1e = -S(9)/2 + (81*m**2 + 261*m + 200)*factorial( + 3*m + 2)/(40*27**m*factorial(m)*factorial(m + 1)*factorial(m + 2)) g1f = (2*m + 1)**2*binomial(2*m, m)**2/(4**(2*m)*(m + 1)) g1g = -binomial(2*m, m)**2/4**(2*m) g1h = -(2*m + 1)**2*(3*m + 4)*factorial(m - S(1)/2)**2/factorial(m + 1)**2 @@ -100,35 +124,43 @@ g = gosper_sum(f1h, (n, 0, m)) assert g is not None and simplify(g - g1h) == 0 + def test_gosper_sum_AeqB_part2(): f2a = n**2*a**n f2b = (n - r/2)*binomial(r, n) f2c = factorial(n - 1)**2/(factorial(n - x)*factorial(n + x)) - g2a = -a*(a + 1)/(a - 1)**3 + a**(m + 1)*(a**2*m**2 - 2*a*m**2 + m**2 - 2*a*m + 2*m + a + 1)/(a - 1)**3 + g2a = -a*(a + 1)/(a - 1)**3 + a**( + m + 1)*(a**2*m**2 - 2*a*m**2 + m**2 - 2*a*m + 2*m + a + 1)/(a - 1)**3 g2b = (m - r)*binomial(r, m)/2 ff = factorial(1 - x)*factorial(1 + x) - g2c = 1/ff*(1 - 1/x**2) + factorial(m)**2/(x**2*factorial(m - x)*factorial(m + x)) + g2c = 1/ff*( + 1 - 1/x**2) + factorial(m)**2/(x**2*factorial(m - x)*factorial(m + x)) g = gosper_sum(f2a, (n, 0, m)) - assert g is not None and simplify(g - g2a) == 0 + assert g is not None and simplify(g - g2a) == 0 g = gosper_sum(f2b, (n, 0, m)) - assert g is not None and simplify(g - g2b) == 0 + assert g is not None and simplify(g - g2b) == 0 g = gosper_sum(f2c, (n, 1, m)) assert g is not None and simplify(g - g2c) == 0 # delete these lines and unXFAIL the nan test below when it passes f2d = n*(n + a + b)*a**n*b**n/(factorial(n + a)*factorial(n + b)) - g2d = 1/(factorial(a - 1)*factorial(b - 1)) - a**(m + 1)*b**(m + 1)/(factorial(a + m)*factorial(b + m)) - assert simplify(sum(f2d.subs(n,i) for i in range(3)) - g2d.subs(m, 2)) == 0 + g2d = 1/(factorial(a - 1)*factorial( + b - 1)) - a**(m + 1)*b**(m + 1)/(factorial(a + m)*factorial(b + m)) + assert simplify( + sum(f2d.subs(n, i) for i in range(3)) - g2d.subs(m, 2)) == 0 + @XFAIL def test_gosper_nan(): f2d = n*(n + a + b)*a**n*b**n/(factorial(n + a)*factorial(n + b)) - g2d = 1/(factorial(a - 1)*factorial(b - 1)) - a**(m + 1)*b**(m + 1)/(factorial(a + m)*factorial(b + m)) + g2d = 1/(factorial(a - 1)*factorial( + b - 1)) - a**(m + 1)*b**(m + 1)/(factorial(a + m)*factorial(b + m)) g = gosper_sum(f2d, (n, 0, m)) assert g is not S.NaN and simplify(g - g2d) == 0 + def test_gosper_sum_AeqB_part3(): f3a = 1/n**4 f3b = (6*n + 3)/(4*n**4 + 8*n**3 + 8*n**2 + 4*n + 3) @@ -136,27 +168,28 @@ f3d = n**2*4**n/((n + 1)*(n + 2)) f3e = 2**n/(n + 1) f3f = 4*(n - 1)*(n**2 - 2*n - 1)/(n**2*(n + 1)**2*(n - 2)**2*(n - 3)**2) - f3g = (n**4 - 14*n**2 - 24*n - 9)*2**n/(n**2*(n + 1)**2*(n + 2)**2*(n + 3)**2) + f3g = (n**4 - 14*n**2 - 24*n - 9)*2**n/(n**2*(n + 1)**2*(n + 2)**2* + (n + 3)**2) # g3a -> no closed form g3b = m*(m + 2)/(2*m**2 + 4*m + 3) g3c = 2**m/m**2 - 2 g3d = S(2)/3 + 4**(m + 1)*(m - 1)/(m + 2)/3 # g3e -> no closed form - g3f = -(-S(1)/16 + 1/((m - 2)**2*(m + 1)**2)) # the AeqB key is wrong + g3f = -(-S(1)/16 + 1/((m - 2)**2*(m + 1)**2)) # the AeqB key is wrong g3g = -S(2)/9 + 2**(m + 1)/((m + 1)**2*(m + 3)**2) g = gosper_sum(f3a, (n, 1, m)) assert g is None g = gosper_sum(f3b, (n, 1, m)) - assert g is not None and simplify(g - g3b) == 0 - g = gosper_sum(f3c, (n, 1, m-1)) - assert g is not None and simplify(g - g3c) == 0 + assert g is not None and simplify(g - g3b) == 0 + g = gosper_sum(f3c, (n, 1, m - 1)) + assert g is not None and simplify(g - g3c) == 0 g = gosper_sum(f3d, (n, 1, m)) - assert g is not None and simplify(g - g3d) == 0 - g = gosper_sum(f3e, (n, 0, m-1)) + assert g is not None and simplify(g - g3d) == 0 + g = gosper_sum(f3e, (n, 0, m - 1)) assert g is None g = gosper_sum(f3f, (n, 4, m)) assert g is not None and simplify(g - g3f) == 0 g = gosper_sum(f3g, (n, 1, m)) - assert g is not None and simplify(g - g3g) == 0 + assert g is not None and simplify(g - g3g) == 0 diff -Nru python3-sympy-0.7.2/sympy/concrete/tests/test_products.py python3-sympy-0.7.3/sympy/concrete/tests/test_products.py --- python3-sympy-0.7.2/sympy/concrete/tests/test_products.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/concrete/tests/test_products.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,17 +1,183 @@ -from sympy import (symbols, product, factorial, rf, sqrt, cos, +from sympy import (symbols, Symbol, product, factorial, rf, sqrt, cos, Function, Product, Rational, Sum, oo) from sympy.utilities.pytest import raises +from sympy import simplify +from sympy.concrete.simplification import change_index, reorder, reverse_order a, k, n, m, x = symbols('a,k,n,m,x', integer=True) f = Function('f') +def test_karr_convention(): + # Test the Karr product convention that we want to hold. + # See his paper "Summation in Finite Terms" for a detailed + # reasoning why we really want exactly this definition. + # The convention is described for sums on page 309 and + # essentially in section 1.4, definition 3. For products + # we can find in analogy: + # + # \prod_{m <= i < n} f(i) 'has the obvious meaning' for m < n + # \prod_{m <= i < n} f(i) = 0 for m = n + # \prod_{m <= i < n} f(i) = 1 / \prod_{n <= i < m} f(i) for m > n + # + # It is important to note that he defines all products with + # the upper limit being *exclusive*. + # In contrast, sympy and the usual mathematical notation has: + # + # prod_{i = a}^b f(i) = f(a) * f(a+1) * ... * f(b-1) * f(b) + # + # with the upper limit *inclusive*. So translating between + # the two we find that: + # + # \prod_{m <= i < n} f(i) = \prod_{i = m}^{n-1} f(i) + # + # where we intentionally used two different ways to typeset the + # products and its limits. + + i = Symbol("i", integer=True) + k = Symbol("k", integer=True) + j = Symbol("j", integer=True) + + # A simple example with a concrete factors and symbolic limits. + + # The normal product: m = k and n = k + j and therefore m < n: + m = k + n = k + j + + a = m + b = n - 1 + S1 = Product(i**2, (i, a, b)).doit() + + # The reversed product: m = k + j and n = k and therefore m > n: + m = k + j + n = k + + a = m + b = n - 1 + S2 = Product(i**2, (i, a, b)).doit() + + assert simplify(S1 * S2) == 1 + + # Test the empty product: m = k and n = k and therefore m = n: + m = k + n = k + + a = m + b = n - 1 + Sz = Product(i**2, (i, a, b)).doit() + + assert Sz == 1 + + # Another example this time with an unspecified factor and + # numeric limits. (We can not do both tests in the same example.) + f = Function("f") + + # The normal product with m < n: + m = 2 + n = 11 + + a = m + b = n - 1 + S1 = Product(f(i), (i, a, b)).doit() + + # The reversed product with m > n: + m = 11 + n = 2 + + a = m + b = n - 1 + S2 = Product(f(i), (i, a, b)).doit() + + assert simplify(S1 * S2) == 1 + + # Test the empty product with m = n: + m = 5 + n = 5 + + a = m + b = n - 1 + Sz = Product(f(i), (i, a, b)).doit() + + assert Sz == 1 + + +def test_karr_proposition_2a(): + # Test Karr, page 309, proposition 2, part a + i = Symbol("i", integer=True) + u = Symbol("u", integer=True) + v = Symbol("v", integer=True) + + def test_the_product(m, n): + # g + g = i**3 + 2*i**2 - 3*i + # f = Delta g + f = simplify(g.subs(i, i+1) / g) + # The product + a = m + b = n - 1 + P = Product(f, (i, a, b)).doit() + # Test if Product_{m <= i < n} f(i) = g(n) / g(m) + assert simplify(P / (g.subs(i, n) / g.subs(i, m))) == 1 + + # m < n + test_the_product(u, u+v) + # m = n + test_the_product(u, u ) + # m > n + test_the_product(u+v, u ) + + +def test_karr_proposition_2b(): + # Test Karr, page 309, proposition 2, part b + i = Symbol("i", integer=True) + u = Symbol("u", integer=True) + v = Symbol("v", integer=True) + w = Symbol("w", integer=True) + + def test_the_product(l, n, m): + # Productmand + s = i**3 + # First product + a = l + b = n - 1 + S1 = Product(s, (i, a, b)).doit() + # Second product + a = l + b = m - 1 + S2 = Product(s, (i, a, b)).doit() + # Third product + a = m + b = n - 1 + S3 = Product(s, (i, a, b)).doit() + # Test if S1 = S2 * S3 as required + assert simplify(S1 / (S2 * S3)) == 1 + + # l < m < n + test_the_product(u, u+v, u+v+w) + # l < m = n + test_the_product(u, u+v, u+v ) + # l < m > n + test_the_product(u, u+v+w, v ) + # l = m < n + test_the_product(u, u, u+v ) + # l = m = n + test_the_product(u, u, u ) + # l = m > n + test_the_product(u+v, u+v, u ) + # l > m < n + test_the_product(u+v, u, u+w ) + # l > m = n + test_the_product(u+v, u, u ) + # l > m > n + test_the_product(u+v+w, u+v, u ) + + def test_simple_products(): - assert product(2, (k, a, n)) == 2**(n-a+1) + assert product(2, (k, a, n)) == 2**(n - a + 1) assert product(k, (k, 1, n)) == factorial(n) assert product(k**3, (k, 1, n)) == factorial(n)**3 - assert product(k+1, (k, 0, n-1)) == factorial(n) - assert product(k+1, (k, a, n-1)) == rf(1+a, n-a) + assert product(k + 1, (k, 0, n - 1)) == factorial(n) + assert product(k + 1, (k, a, n - 1)) == rf(1 + a, n - a) assert product(cos(k), (k, 0, 5)) == cos(1)*cos(2)*cos(3)*cos(4)*cos(5) assert product(cos(k), (k, 3, 5)) == cos(3)*cos(4)*cos(5) @@ -19,34 +185,44 @@ assert isinstance(product(k**k, (k, 1, n)), Product) + assert Product(x**k, (k, 1, n)).variables == [k] + raises(ValueError, lambda: Product(n)) raises(ValueError, lambda: Product(n, k)) raises(ValueError, lambda: Product(n, k, 1)) raises(ValueError, lambda: Product(n, k, 1, 10)) raises(ValueError, lambda: Product(n, (k, 1))) + def test_multiple_products(): assert product(x, (n, 1, k), (k, 1, m)) == x**(m**2/2 + m/2) - assert product(f(n), (n, 1, m), (m, 1, k)) == Product(f(n), (n, 1, m), (m, 1, k)).doit() + assert product(f(n), ( + n, 1, m), (m, 1, k)) == Product(f(n), (n, 1, m), (m, 1, k)).doit() assert Product(f(n), (m, 1, k), (n, 1, k)).doit() == \ Product(Product(f(n), (m, 1, k)), (n, 1, k)).doit() == \ product(f(n), (m, 1, k), (n, 1, k)) == \ product(product(f(n), (m, 1, k)), (n, 1, k)) == \ Product(f(n)**k, (n, 1, k)) - assert Product(x, (x, 1, k), (k, 1, n)).doit() == Product(factorial(k), (k, 1, n)) + assert Product( + x, (x, 1, k), (k, 1, n)).doit() == Product(factorial(k), (k, 1, n)) + + assert Product(x**k, (n, 1, k), (k, 1, m)).variables == [n, k] + def test_rational_products(): - assert product(1+1/k, (k, 1, n)) == rf(2, n)/factorial(n) + assert product(1 + 1/k, (k, 1, n)) == rf(2, n)/factorial(n) + def test_special_products(): # Wallis product - assert product((4*k)**2 / (4*k**2-1), (k, 1, n)) == \ + assert product((4*k)**2 / (4*k**2 - 1), (k, 1, n)) == \ 4**n*factorial(n)**2/rf(Rational(1, 2), n)/rf(Rational(3, 2), n) # Euler's product formula for sin assert product(1 + a/k**2, (k, 1, n)) == \ rf(1 - sqrt(-a), n)*rf(1 + sqrt(-a), n)/factorial(n)**2 + def test__eval_product(): from sympy.abc import i, n # 1710 @@ -55,11 +231,106 @@ # 1711 assert product(2**i, (i, 1, n)) == 2**(n/2 + n**2/2) + def test_product_pow(): # Issue 1718 assert product(2**f(k), (k, 1, n)) == 2**Sum(f(k), (k, 1, n)) assert product(2**(2*f(k)), (k, 1, n)) == 2**Sum(2*f(k), (k, 1, n)) + def test_infinite_product(): # Issue 2638 assert isinstance(Product(2**(1/factorial(n)), (n, 0, oo)), Product) + + +def test_conjugate_transpose(): + p = Product(x**k, (k, 1, 3)) + assert p.adjoint().doit() == p.doit().adjoint() + assert p.conjugate().doit() == p.doit().conjugate() + assert p.transpose().doit() == p.doit().transpose() + + A, B = symbols("A B", commutative=False) + p = Product(A*B**k, (k, 1, 3)) + assert p.adjoint().doit() == p.doit().adjoint() + assert p.conjugate().doit() == p.doit().conjugate() + assert p.transpose().doit() == p.doit().transpose() + + +def test_simplify(): + y, t, b, c = symbols('y, t, b, c', integer = True) + + assert simplify(Product(x*y, (x, n, m), (y, a, k)) * \ + Product(y, (x, n, m), (y, a, k))) == \ + Product(x*y**2, (x, n, m), (y, a, k)) + assert simplify(3 * y* Product(x, (x, n, m)) * Product(x, (x, m + 1, a))) \ + == 3 * y * Product(x, (x, n, a)) + assert simplify(Product(x, (x, k + 1, a)) * Product(x, (x, n, k))) == \ + Product(x, (x, n, a)) + assert simplify(Product(x, (x, k + 1, a)) * Product(x + 1, (x, n, k))) == \ + Product(x, (x, k + 1, a)) * Product(x + 1, (x, n, k)) + assert simplify(Product(x, (t, a, b)) * Product(y, (t, a, b)) * \ + Product(x, (t, b+1, c))) == Product(x*y, (t, a, b)) * \ + Product(x, (t, b+1, c)) + assert simplify(Product(x, (t, a, b)) * Product(x, (t, b+1, c)) * \ + Product(y, (t, a, b))) == Product(x*y, (t, a, b)) * \ + Product(x, (t, b+1, c)) + + +def test_change_index(): + b, y, c, d, z = symbols('b, y, c, d, z', integer = True) + + assert change_index(Product(x, (x, a, b)), x, x + 1, y) == \ + Product(y - 1, (y, a + 1, b + 1)) + assert change_index(Product(x**2, (x, a, b)), x, x - 1) == \ + Product((x + 1)**2, (x, a - 1, b - 1)) + assert change_index(Product(x**2, (x, a, b)), x, -x, y) == \ + Product((-y)**2, (y, -b, -a)) + assert change_index(Product(x, (x, a, b)), x, -x - 1) == \ + Product(-x - 1, (x, - b - 1, -a - 1)) + assert change_index(Product(x*y, (x, a, b), (y, c, d)), x, x - 1, z) == \ + Product((z + 1)*y, (z, a - 1, b - 1), (y, c, d)) + + +def test_reorder(): + b, y, c, d, z = symbols('b, y, c, d, z', integer = True) + + assert reorder(Product(x*y, (x, a, b), (y, c, d)), (0, 1)) == \ + Product(x*y, (y, c, d), (x, a, b)) + assert reorder(Product(x, (x, a, b), (x, c, d)), (0, 1)) == \ + Product(x, (x, c, d), (x, a, b)) + assert reorder(Product(x*y + z, (x, a, b), (z, m, n), (y, c, d)), \ + (2, 0), (0, 1)) == Product(x*y + z, (z, m, n), (y, c, d), (x, a, b)) + assert reorder(Product(x*y*z, (x, a, b), (y, c, d), (z, m, n)), \ + (0, 1), (1, 2), (0, 2)) == \ + Product(x*y*z, (x, a, b), (z, m, n), (y, c, d)) + assert reorder(Product(x*y*z, (x, a, b), (y, c, d), (z, m, n)), \ + (x, y), (y, z), (x, z)) == \ + Product(x*y*z, (x, a, b), (z, m, n), (y, c, d)) + assert reorder(Product(x*y, (x, a, b), (y, c, d)), (x, 1)) == \ + Product(x*y, (y, c, d), (x, a, b)) + assert reorder(Product(x*y, (x, a, b), (y, c, d)), (y, x)) == \ + Product(x*y, (y, c, d), (x, a, b)) + + +def test_reverse_order(): + x, y, a, b, c, d= symbols('x, y, a, b, c, d', integer = True) + + assert reverse_order(Product(x, (x, 0, 3)), 0) == Product(1/x, (x, 4, -1)) + assert reverse_order(Product(x*y, (x, 1, 5), (y, 0, 6)), 0, 1) == \ + Product(x*y, (x, 6, 0), (y, 7, -1)) + assert reverse_order(Product(x, (x, 1, 2)), 0) == Product(1/x, (x, 3, 0)) + assert reverse_order(Product(x, (x, 1, 3)), 0) == Product(1/x, (x, 4, 0)) + assert reverse_order(Product(x, (x, 1, a)), 0) == Product(1/x, (x, a + 1, 0)) + assert reverse_order(Product(x, (x, a, 5)), 0) == Product(1/x, (x, 6, a - 1)) + assert reverse_order(Product(x, (x, a + 1, a + 5)), 0) == \ + Product(1/x, (x, a + 6, a)) + assert reverse_order(Product(x, (x, a + 1, a + 2)), 0) == \ + Product(1/x, (x, a + 3, a)) + assert reverse_order(Product(x, (x, a + 1, a + 1)), 0) == \ + Product(1/x, (x, a + 2, a)) + assert reverse_order(Product(x, (x, a, b)), 0) == Product(1/x, (x, b + 1, a - 1)) + assert reverse_order(Product(x, (x, a, b)), x) == Product(1/x, (x, b + 1, a - 1)) + assert reverse_order(Product(x*y, (x, a, b), (y, 2, 5)), x, 1) == \ + Product(x*y, (x, b + 1, a - 1), (y, 6, 1)) + assert reverse_order(Product(x*y, (x, a, b), (y, 2, 5)), y, x) == \ + Product(x*y, (x, b + 1, a - 1), (y, 6, 1)) diff -Nru python3-sympy-0.7.2/sympy/concrete/tests/test_sums_products.py python3-sympy-0.7.3/sympy/concrete/tests/test_sums_products.py --- python3-sympy-0.7.2/sympy/concrete/tests/test_sums_products.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/concrete/tests/test_sums_products.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,15 +1,180 @@ from sympy import (binomial, Catalan, cos, Derivative, E, exp, EulerGamma, factorial, Function, harmonic, Integral, log, nan, oo, pi, Product, product, Rational, S, sqrt, Sum, summation, Symbol, - sympify, zeta, oo) + symbols, sympify, zeta, oo, I, Abs, Piecewise, Eq, simplify) from sympy.abc import a, b, c, d, k, m, n, x, y, z from sympy.concrete.summations import telescopic from sympy.utilities.pytest import XFAIL, raises +from sympy import simplify +from sympy.concrete.simplification import change_index, reorder, reverse_order n = Symbol('n', integer=True) +def test_karr_convention(): + # Test the Karr summation convention that we want to hold. + # See his paper "Summation in Finite Terms" for a detailed + # reasoning why we really want exactly this definition. + # The convention is described on page 309 and essentially + # in section 1.4, definition 3: + # + # \sum_{m <= i < n} f(i) 'has the obvious meaning' for m < n + # \sum_{m <= i < n} f(i) = 0 for m = n + # \sum_{m <= i < n} f(i) = - \sum_{n <= i < m} f(i) for m > n + # + # It is important to note that he defines all sums with + # the upper limit being *exclusive*. + # In contrast, sympy and the usual mathematical notation has: + # + # sum_{i = a}^b f(i) = f(a) + f(a+1) + ... + f(b-1) + f(b) + # + # with the upper limit *inclusive*. So translating between + # the two we find that: + # + # \sum_{m <= i < n} f(i) = \sum_{i = m}^{n-1} f(i) + # + # where we intentionally used two different ways to typeset the + # sum and its limits. + + i = Symbol("i", integer=True) + k = Symbol("k", integer=True) + j = Symbol("j", integer=True) + + # A simple example with a concrete summand and symbolic limits. + + # The normal sum: m = k and n = k + j and therefore m < n: + m = k + n = k + j + + a = m + b = n - 1 + S1 = Sum(i**2, (i, a, b)).doit() + + # The reversed sum: m = k + j and n = k and therefore m > n: + m = k + j + n = k + + a = m + b = n - 1 + S2 = Sum(i**2, (i, a, b)).doit() + + assert simplify(S1 + S2) == 0 + + # Test the empty sum: m = k and n = k and therefore m = n: + m = k + n = k + + a = m + b = n - 1 + Sz = Sum(i**2, (i, a, b)).doit() + + assert Sz == 0 + + # Another example this time with an unspecified summand and + # numeric limits. (We can not do both tests in the same example.) + f = Function("f") + + # The normal sum with m < n: + m = 2 + n = 11 + + a = m + b = n - 1 + S1 = Sum(f(i), (i, a, b)).doit() + + # The reversed sum with m > n: + m = 11 + n = 2 + + a = m + b = n - 1 + S2 = Sum(f(i), (i, a, b)).doit() + + assert simplify(S1 + S2) == 0 + + # Test the empty sum with m = n: + m = 5 + n = 5 + + a = m + b = n - 1 + Sz = Sum(f(i), (i, a, b)).doit() + + assert Sz == 0 + + +def test_karr_proposition_2a(): + # Test Karr, page 309, proposition 2, part a + i = Symbol("i", integer=True) + u = Symbol("u", integer=True) + v = Symbol("v", integer=True) + + def test_the_sum(m, n): + # g + g = i**3 + 2*i**2 - 3*i + # f = Delta g + f = simplify(g.subs(i, i+1) - g) + # The sum + a = m + b = n - 1 + S = Sum(f, (i, a, b)).doit() + # Test if Sum_{m <= i < n} f(i) = g(n) - g(m) + assert simplify(S - (g.subs(i, n) - g.subs(i, m))) == 0 + + # m < n + test_the_sum(u, u+v) + # m = n + test_the_sum(u, u ) + # m > n + test_the_sum(u+v, u ) + + +def test_karr_proposition_2b(): + # Test Karr, page 309, proposition 2, part b + i = Symbol("i", integer=True) + u = Symbol("u", integer=True) + v = Symbol("v", integer=True) + w = Symbol("w", integer=True) + + def test_the_sum(l, n, m): + # Summand + s = i**3 + # First sum + a = l + b = n - 1 + S1 = Sum(s, (i, a, b)).doit() + # Second sum + a = l + b = m - 1 + S2 = Sum(s, (i, a, b)).doit() + # Third sum + a = m + b = n - 1 + S3 = Sum(s, (i, a, b)).doit() + # Test if S1 = S2 + S3 as required + assert S1 - (S2 + S3) == 0 + + # l < m < n + test_the_sum(u, u+v, u+v+w) + # l < m = n + test_the_sum(u, u+v, u+v ) + # l < m > n + test_the_sum(u, u+v+w, v ) + # l = m < n + test_the_sum(u, u, u+v ) + # l = m = n + test_the_sum(u, u, u ) + # l = m > n + test_the_sum(u+v, u+v, u ) + # l > m < n + test_the_sum(u+v, u, u+w ) + # l > m = n + test_the_sum(u+v, u, u ) + # l > m > n + test_the_sum(u+v+w, u+v, u ) + + def test_arithmetic_sums(): - assert summation(1, (n, a, b)) == b-a+1 + assert summation(1, (n, a, b)) == b - a + 1 assert Sum(S.NaN, (n, a, b)) is S.NaN assert Sum(x, (n, a, a)).doit() == x assert Sum(x, (x, a, a)).doit() == a @@ -18,12 +183,12 @@ s1 = Sum(n, (n, lo, hi)) s2 = Sum(n, (n, hi, lo)) assert s1 != s2 - assert s1.doit() == s2.doit() == 3 + assert s1.doit() == 3 and s2.doit() == 0 lo, hi = x, x + 1 s1 = Sum(n, (n, lo, hi)) s2 = Sum(n, (n, hi, lo)) assert s1 != s2 - assert s1.doit() == s2.doit() == 2*x + 1 + assert s1.doit() == 2*x + 1 and s2.doit() == 0 assert Sum(Integral(x, (x, 1, y)) + x, (x, 1, 2)).doit() == \ y**2 + 2 assert summation(1, (n, 1, 10)) == 10 @@ -34,27 +199,47 @@ assert summation(cos(n), (n, x, x + 2)) == cos(x) + cos(x + 1) + cos(x + 2) assert isinstance(summation(cos(n), (n, x, x + S.Half)), Sum) + def test_polynomial_sums(): assert summation(n**2, (n, 3, 8)) == 199 assert summation(n, (n, a, b)) == \ - ((a+b)*(b-a+1)/2).expand() + ((a + b)*(b - a + 1)/2).expand() assert summation(n**2, (n, 1, b)) == \ - ((2*b**3+3*b**2+b)/6).expand() + ((2*b**3 + 3*b**2 + b)/6).expand() assert summation(n**3, (n, 1, b)) == \ - ((b**4+2*b**3+b**2)/4).expand() + ((b**4 + 2*b**3 + b**2)/4).expand() assert summation(n**6, (n, 1, b)) == \ - ((6*b**7+21*b**6+21*b**5-7*b**3+b)/42).expand() + ((6*b**7 + 21*b**6 + 21*b**5 - 7*b**3 + b)/42).expand() + def test_geometric_sums(): - assert summation(pi**n, (n, 0, b)) == (1-pi**(b+1)) / (1-pi) - assert summation(2 * 3**n, (n, 0, b)) == 3**(b+1) - 1 - assert summation(Rational(1,2)**n, (n, 1, oo)) == 1 - assert summation(2**n, (n, 0, b)) == 2**(b+1) - 1 + assert summation(pi**n, (n, 0, b)) == (1 - pi**(b + 1)) / (1 - pi) + assert summation(2 * 3**n, (n, 0, b)) == 3**(b + 1) - 1 + assert summation(Rational(1, 2)**n, (n, 1, oo)) == 1 + assert summation(2**n, (n, 0, b)) == 2**(b + 1) - 1 assert summation(2**n, (n, 1, oo)) == oo assert summation(2**(-n), (n, 1, oo)) == 1 - assert summation(3**(-n), (n, 4, oo)) == Rational(1,54) - assert summation(2**(-4*n+3), (n, 1, oo)) == Rational(8,15) - assert summation(2**(n+1), (n, 1, b)).expand() == 4*(2**b-1) + assert summation(3**(-n), (n, 4, oo)) == Rational(1, 54) + assert summation(2**(-4*n + 3), (n, 1, oo)) == Rational(8, 15) + assert summation(2**(n + 1), (n, 1, b)).expand() == 4*(2**b - 1) + + # issue 3565: + assert summation(x**n, (n, 0, oo)) == \ + Piecewise((1/(-x + 1), Abs(x) < 1), (Sum(x**n, (n, 0, oo)), True)) + + assert summation(-2**n, (n, 0, oo)) == -oo + assert summation(I**n, (n, 0, oo)) == Sum(I**n, (n, 0, oo)) + + # issue 3703: + assert summation((-1)**(2*x + 2), (x, 0, n)) == n + 1 + assert summation((-2)**(2*x + 2), (x, 0, n)) == 4*4**(n + 1)/S(3) - S(4)/3 + assert summation((-1)**x, (x, 0, n)) == -(-1)**(n + 1)/S(2) + S(1)/2 + assert summation(y**x, (x, a, b)) == \ + Piecewise((-a + b + 1, Eq(y, 1)), ((y**a - y**(b + 1))/(-y + 1), True)) + assert summation((-2)**(y*x + 2), (x, 0, n)) == \ + 4*Piecewise((n + 1, Eq((-2)**y, 1)), + ((-(-2)**(y*(n + 1)) + 1)/(-(-2)**y + 1), True)) + def test_harmonic_sums(): assert summation(1/k, (k, 0, n)) == Sum(1/k, (k, 0, n)) @@ -62,18 +247,22 @@ assert summation(n/k, (k, 1, n)) == n*harmonic(n) assert summation(1/k, (k, 5, n)) == harmonic(n) - harmonic(4) + def test_composite_sums(): - f = Rational(1,2)*(7 - 6*n + Rational(1,7)*n**3) + f = Rational(1, 2)*(7 - 6*n + Rational(1, 7)*n**3) s = summation(f, (n, a, b)) assert not isinstance(s, Sum) A = 0 for i in range(-3, 5): A += f.subs(n, i) - B = s.subs(a,-3).subs(b,4) + B = s.subs(a, -3).subs(b, 4) assert A == B + def test_hypergeometric_sums(): - assert summation(binomial(2*k, k)/4**k, (k, 0, n)) == (1 + 2*n)*binomial(2*n, n)/4**n + assert summation( + binomial(2*k, k)/4**k, (k, 0, n)) == (1 + 2*n)*binomial(2*n, n)/4**n + def test_other_sums(): f = m**2 + m*exp(m) @@ -84,42 +273,54 @@ fac = factorial + def NS(e, n=15, **options): return str(sympify(e).evalf(n, **options)) + def test_evalf_fast_series(): # Euler transformed series for sqrt(1+x) - assert NS(Sum(fac(2*n+1)/fac(n)**2/2**(3*n+1), (n, 0, oo)), 100) == NS(sqrt(2), 100) + assert NS(Sum( + fac(2*n + 1)/fac(n)**2/2**(3*n + 1), (n, 0, oo)), 100) == NS(sqrt(2), 100) # Some series for exp(1) estr = NS(E, 100) assert NS(Sum(1/fac(n), (n, 0, oo)), 100) == estr - assert NS(1/Sum((1-2*n)/fac(2*n), (n, 0, oo)), 100) == estr - assert NS(Sum((2*n+1)/fac(2*n), (n, 0, oo)), 100) == estr - assert NS(Sum((4*n+3)/2**(2*n+1)/fac(2*n+1), (n, 0, oo))**2, 100) == estr + assert NS(1/Sum((1 - 2*n)/fac(2*n), (n, 0, oo)), 100) == estr + assert NS(Sum((2*n + 1)/fac(2*n), (n, 0, oo)), 100) == estr + assert NS(Sum((4*n + 3)/2**(2*n + 1)/fac(2*n + 1), (n, 0, oo))**2, 100) == estr pistr = NS(pi, 100) # Ramanujan series for pi - assert NS(9801/sqrt(8)/Sum(fac(4*n)*(1103+26390*n)/fac(n)**4/396**(4*n), (n, 0, oo)), 100) == pistr - assert NS(1/Sum(binomial(2*n,n)**3 * (42*n+5)/2**(12*n+4), (n, 0, oo)), 100) == pistr + assert NS(9801/sqrt(8)/Sum(fac( + 4*n)*(1103 + 26390*n)/fac(n)**4/396**(4*n), (n, 0, oo)), 100) == pistr + assert NS(1/Sum( + binomial(2*n, n)**3 * (42*n + 5)/2**(12*n + 4), (n, 0, oo)), 100) == pistr # Machin's formula for pi - assert NS(16*Sum((-1)**n/(2*n+1)/5**(2*n+1), (n, 0, oo)) - \ - 4*Sum((-1)**n/(2*n+1)/239**(2*n+1), (n, 0, oo)), 100) == pistr + assert NS(16*Sum((-1)**n/(2*n + 1)/5**(2*n + 1), (n, 0, oo)) - + 4*Sum((-1)**n/(2*n + 1)/239**(2*n + 1), (n, 0, oo)), 100) == pistr # Apery's constant astr = NS(zeta(3), 100) - P = 126392*n**5 + 412708*n**4 + 531578*n**3 + 336367*n**2 + 104000*n + 12463 - assert NS(Sum((-1)**n * P / 24 * (fac(2*n+1)*fac(2*n)*fac(n))**3 / fac(3*n+2) / fac(4*n+3)**3, (n, 0, oo)), 100) == astr - assert NS(Sum((-1)**n * (205*n**2 + 250*n + 77)/64 * fac(n)**10 / fac(2*n+1)**5, (n, 0, oo)), 100) == astr + P = 126392*n**5 + 412708*n**4 + 531578*n**3 + 336367*n**2 + 104000* \ + n + 12463 + assert NS(Sum((-1)**n * P / 24 * (fac(2*n + 1)*fac(2*n)*fac( + n))**3 / fac(3*n + 2) / fac(4*n + 3)**3, (n, 0, oo)), 100) == astr + assert NS(Sum((-1)**n * (205*n**2 + 250*n + 77)/64 * fac(n)**10 / + fac(2*n + 1)**5, (n, 0, oo)), 100) == astr + def test_evalf_fast_series_issue998(): # Catalan's constant - assert NS(Sum((-1)**(n-1)*2**(8*n)*(40*n**2-24*n+3)*fac(2*n)**3*\ - fac(n)**2/n**3/(2*n-1)/fac(4*n)**2, (n, 1, oo))/64, 100) == \ + assert NS(Sum((-1)**(n - 1)*2**(8*n)*(40*n**2 - 24*n + 3)*fac(2*n)**3* + fac(n)**2/n**3/(2*n - 1)/fac(4*n)**2, (n, 1, oo))/64, 100) == \ NS(Catalan, 100) astr = NS(zeta(3), 100) - assert NS(5*Sum((-1)**(n-1)*fac(n)**2 / n**3 / fac(2*n), (n, 1, oo))/2, 100) == astr - assert NS(Sum((-1)**(n-1)*(56*n**2-32*n+5) / (2*n-1)**2 * fac(n-1)**3 / fac(3*n), (n, 1, oo))/4, 100) == astr + assert NS(5*Sum( + (-1)**(n - 1)*fac(n)**2 / n**3 / fac(2*n), (n, 1, oo))/2, 100) == astr + assert NS(Sum((-1)**(n - 1)*(56*n**2 - 32*n + 5) / (2*n - 1)**2 * fac(n - 1) + **3 / fac(3*n), (n, 1, oo))/4, 100) == astr + def test_evalf_slow_series(): assert NS(Sum((-1)**n / n, (n, 1, oo)), 15) == NS(-log(2), 15) @@ -127,8 +328,9 @@ assert NS(Sum(1/n**2, (n, 1, oo)), 15) == NS(pi**2/6, 15) assert NS(Sum(1/n**2, (n, 1, oo)), 100) == NS(pi**2/6, 100) assert NS(Sum(1/n**2, (n, 1, oo)), 500) == NS(pi**2/6, 500) - assert NS(Sum((-1)**n / (2*n+1)**3, (n, 0, oo)), 15) == NS(pi**3/32, 15) - assert NS(Sum((-1)**n / (2*n+1)**3, (n, 0, oo)), 50) == NS(pi**3/32, 50) + assert NS(Sum((-1)**n / (2*n + 1)**3, (n, 0, oo)), 15) == NS(pi**3/32, 15) + assert NS(Sum((-1)**n / (2*n + 1)**3, (n, 0, oo)), 50) == NS(pi**3/32, 50) + def test_euler_maclaurin(): # Exact polynomial sums with E-M @@ -147,17 +349,22 @@ for m, n in [(2, 4), (2, 20), (10, 20), (18, 20)]: A = Sum(1/k**3, (k, 1, oo)) s, e = A.euler_maclaurin(m, n) - assert abs((s-zeta(3)).evalf()) < e.evalf() + assert abs((s - zeta(3)).evalf()) < e.evalf() + def test_evalf_euler_maclaurin(): assert NS(Sum(1/k**k, (k, 1, oo)), 15) == '1.29128599706266' - assert NS(Sum(1/k**k, (k, 1, oo)), 50) == '1.2912859970626635404072825905956005414986193682745' - assert NS(Sum(1/k-log(1+1/k), (k, 1, oo)), 15) == NS(EulerGamma, 15) - assert NS(Sum(1/k-log(1+1/k), (k, 1, oo)), 50) == NS(EulerGamma, 50) + assert NS(Sum(1/k**k, (k, 1, oo)), + 50) == '1.2912859970626635404072825905956005414986193682745' + assert NS(Sum(1/k - log(1 + 1/k), (k, 1, oo)), 15) == NS(EulerGamma, 15) + assert NS(Sum(1/k - log(1 + 1/k), (k, 1, oo)), 50) == NS(EulerGamma, 50) assert NS(Sum(log(k)/k**2, (k, 1, oo)), 15) == '0.937548254315844' - assert NS(Sum(log(k)/k**2, (k, 1, oo)), 50) == '0.93754825431584375370257409456786497789786028861483' + assert NS(Sum(log(k)/k**2, (k, 1, oo)), + 50) == '0.93754825431584375370257409456786497789786028861483' assert NS(Sum(1/k, (k, 1000000, 2000000)), 15) == '0.693147930560008' - assert NS(Sum(1/k, (k, 1000000, 2000000)), 50) == '0.69314793056000780941723211364567656807940638436025' + assert NS(Sum(1/k, (k, 1000000, 2000000)), + 50) == '0.69314793056000780941723211364567656807940638436025' + def test_simple_products(): assert Product(S.NaN, (x, 1, 3)) is S.NaN @@ -165,93 +372,135 @@ assert Product(x, (n, a, a)).doit() == x assert Product(x, (x, a, a)).doit() == a assert Product(x, (y, 1, a)).doit() == x**a + lo, hi = 1, 2 s1 = Product(n, (n, lo, hi)) s2 = Product(n, (n, hi, lo)) assert s1 != s2 - assert s1.doit() == s2.doit() == 2 + # This IS correct according to Karr product convention + assert s1.doit() == 2 + assert s2.doit() == 1 + lo, hi = x, x + 1 s1 = Product(n, (n, lo, hi)) s2 = Product(n, (n, hi, lo)) + s3 = 1 / Product(n, (n, hi + 1, lo - 1)) assert s1 != s2 - assert s1.doit() == s2.doit() == x*(x + 1) - assert Product(Integral(2*x, (x,1,y)) + 2*x, (x,1,2)).doit() == \ + # This IS correct according to Karr product convention + assert s1.doit() == x*(x + 1) + assert s2.doit() == 1 + assert s3.doit() == x*(x + 1) + + assert Product(Integral(2*x, (x, 1, y)) + 2*x, (x, 1, 2)).doit() == \ (y**2 + 1)*(y**2 + 3) - assert product(2, (n, a, b)) == 2**(b-a+1) + assert product(2, (n, a, b)) == 2**(b - a + 1) assert product(n, (n, 1, b)) == factorial(b) assert product(n**3, (n, 1, b)) == factorial(b)**3 - assert product(3**(2+n), (n, a, b)) \ - == 3**(2*(1-a+b)+b/2+(b**2)/2+a/2-(a**2)/2) + assert product(3**(2 + n), (n, a, b)) \ + == 3**(2*(1 - a + b) + b/2 + (b**2)/2 + a/2 - (a**2)/2) assert product(cos(n), (n, 3, 5)) == cos(3)*cos(4)*cos(5) assert product(cos(n), (n, x, x + 2)) == cos(x)*cos(x + 1)*cos(x + 2) assert isinstance(product(cos(n), (n, x, x + S.Half)), Product) # If Product managed to evaluate this one, it most likely got it wrong! assert isinstance(Product(n**n, (n, 1, b)), Product) + @XFAIL def test_rational_products(): - assert Product(1+1/n, (n, a, b)) == (1+b)/a - assert Product(n+1, (n, a, b)) == factorial(1+b)/factorial(a) - assert Product((n+1)/(n-1), (n, a, b)) == b*(1+b)/(a*(a-1)) - assert Product(n/(n+1)/(n+2), (n, a, b)) \ - == a*factorial(a+1)/(b+1)/factorial(b+2) - assert Product(n*(n+1)/(n-1)/(n-2), (n, a, b)) \ - == b**2*(b-1)*(1+b)/(a-1)**2/(a*(a-2)) + assert Product(1 + 1/n, (n, a, b)) == (1 + b)/a + assert Product(n + 1, (n, a, b)) == factorial(1 + b)/factorial(a) + assert Product((n + 1)/(n - 1), (n, a, b)) == b*(1 + b)/(a*(a - 1)) + assert Product(n/(n + 1)/(n + 2), (n, a, b)) \ + == a*factorial(a + 1)/(b + 1)/factorial(b + 2) + assert Product(n*(n + 1)/(n - 1)/(n - 2), (n, a, b)) \ + == b**2*(b - 1)*(1 + b)/(a - 1)**2/(a*(a - 2)) + @XFAIL def test_wallis_product(): # Wallis product, given in two different forms to ensure that Product # can factor simple rational expressions - A = Product(4*n**2 / (4*n**2-1), (n, 1, b)) - B = Product((2*n)*(2*n)/(2*n-1)/(2*n+1), (n, 1, b)) - half = Rational(1,2) - R = pi/2 * factorial(b)**2 / factorial(b-half) / factorial(b+half) + A = Product(4*n**2 / (4*n**2 - 1), (n, 1, b)) + B = Product((2*n)*(2*n)/(2*n - 1)/(2*n + 1), (n, 1, b)) + half = Rational(1, 2) + R = pi/2 * factorial(b)**2 / factorial(b - half) / factorial(b + half) assert A == R assert B == R # This one should eventually also be doable (Euler's product formula for sin) # assert Product(1+x/n**2, (n, 1, b)) == ... + def test_telescopic_sums(): #checks also input 2 of comment 1 issue 1028 - assert Sum(1/k - 1/(k+1),(k,1,n)).doit() == 1 - 1/(1 + n) + assert Sum(1/k - 1/(k + 1), (k, 1, n)).doit() == 1 - 1/(1 + n) f = Function("f") - assert Sum(f(k)-f(k+2),(k,m,n)).doit() == -f(1+n) - f(2+n) + f(m) + f(1+m) - assert Sum(cos(k)-cos(k+3),(k,1,n)).doit() == -cos(1 + n) - cos(2 + n) - \ - cos(3 + n) + cos(1) + cos(2) + cos(3) + assert Sum( + f(k) - f(k + 2), (k, m, n)).doit() == -f(1 + n) - f(2 + n) + f(m) + f(1 + m) + assert Sum(cos(k) - cos(k + 3), (k, 1, n)).doit() == -cos(1 + n) - \ + cos(2 + n) - cos(3 + n) + cos(1) + cos(2) + cos(3) # dummy variable shouldn't matter - assert telescopic(1/m, -m/(1+m),(m, n-1, n)) == \ - telescopic(1/k, -k/(1+k),(k, n-1, n)) + assert telescopic(1/m, -m/(1 + m), (m, n - 1, n)) == \ + telescopic(1/k, -k/(1 + k), (k, n - 1, n)) assert Sum(1/x/(x - 1), (x, a, b)).doit() == -((a - b - 1)/(b*(a - 1))) + def test_sum_reconstruct(): s = Sum(n**2, (n, -1, 1)) assert s == Sum(*s.args) raises(ValueError, lambda: Sum(x, x)) raises(ValueError, lambda: Sum(x, (x, 1))) -def test_Sum_limit_subs(): - assert Sum(a*exp(a), (a, -2, 2)) == Sum(a*exp(a), (a, -b, b)).subs(b, 2) - assert Sum(a, (a, Sum(b, (b, 1, 2)), 4)).subs(Sum(b, (b, 1, 2)), c) == \ - Sum(a, (a, c, 4)) -@XFAIL -def test_issue2166(): +def test_limit_subs(): + for F in (Sum, Product, Integral): + assert F(a*exp(a), (a, -2, 2)) == F(a*exp(a), (a, -b, b)).subs(b, 2) + assert F(a, (a, F(b, (b, 1, 2)), 4)).subs(F(b, (b, 1, 2)), c) == \ + F(a, (a, c, 4)) + assert F(x, (x, 1, x + y)).subs(x, 1) == F(x, (x, 1, y + 1)) + + +def test_equality(): + # if this fails remove special handling below + raises(ValueError, lambda: Sum(x, x)) + r = symbols('x', real=True) + for F in (Sum, Product, Integral): + try: + assert F(x, x) != F(y, y) + assert F(x, (x, 1, 2)) != F(x, x) + assert F(x, (x, x)) != F(x, x) # or else they print the same + assert F(1, x) != F(1, y) + except ValueError: + pass + assert F(a, (x, 1, 2)) != F(a, (x, 1, 3)) + assert F(a, (x, 1, 2)) != F(b, (x, 1, 2)) + assert F(x, (x, 1, 2)) != F(r, (r, 1, 2)) + assert F(1, (x, 1, x)) != F(1, (y, 1, x)) + assert F(1, (x, 1, x)) != F(1, (y, 1, y)) + + # issue 2166 assert Sum(x, (x, 1, x)).subs(x, a) == Sum(x, (x, 1, a)) + def test_Sum_doit(): assert Sum(n*Integral(a**2), (n, 0, 2)).doit() == a**3 - assert Sum(n*Integral(a**2), (n, 0, 2)).doit(deep = False) == \ + assert Sum(n*Integral(a**2), (n, 0, 2)).doit(deep=False) == \ 3*Integral(a**2) assert summation(n*Integral(a**2), (n, 0, 2)) == 3*Integral(a**2) + # test nested sum evaluation + S = Sum( Sum( Sum(2,(z,1,n+1)), (y,x+1,n)), (x,1,n)) + assert 0 == (S.doit() - n*(n+1)*(n-1)).factor() + + def test_Product_doit(): assert Product(n*Integral(a**2), (n, 1, 3)).doit() == 2 * a**9 / 9 - assert Product(n*Integral(a**2), (n, 1, 3)).doit(deep = False) == \ + assert Product(n*Integral(a**2), (n, 1, 3)).doit(deep=False) == \ 6*Integral(a**2)**3 assert product(n*Integral(a**2), (n, 1, 3)) == 6*Integral(a**2)**3 + def test_Sum_interface(): assert isinstance(Sum(0, (n, 0, 2)), Sum) assert Sum(nan, (n, 0, 2)) is nan @@ -262,6 +511,7 @@ raises(ValueError, lambda: Sum(1)) raises(ValueError, lambda: summation(1)) + def test_eval_diff(): assert Sum(x, (x, 1, 2)).diff(x) == 0 assert Sum(x*y, (x, 1, 2)).diff(x) == 0 @@ -269,19 +519,17 @@ e = Sum(x*y, (x, 1, a)) assert e.diff(a) == Derivative(e, a) assert Sum(x*y, (x, 1, 3), (a, 2, 5)).diff(y) == \ - Sum(x*y, (x, 1, 3), (a, 2, 5)).doit().diff(y) == \ - 24 + Sum(x*y, (x, 1, 3), (a, 2, 5)).doit().diff(y) == 24 + def test_hypersum(): from sympy import simplify, sin, hyper assert simplify(summation(x**n/fac(n), (n, 1, oo))) == -1 + exp(x) assert summation((-1)**n * x**(2*n) / fac(2*n), (n, 0, oo)) == cos(x) - assert simplify(summation((-1)**n*x**(2*n+1)/factorial(2*n+1), - (n, 3, oo))) \ - == -x + sin(x) + x**3/6 - x**5/120 + assert simplify(summation((-1)**n*x**(2*n + 1) / + factorial(2*n + 1), (n, 3, oo))) == -x + sin(x) + x**3/6 - x**5/120 - assert summation(1/(n+2)**3, (n, 1, oo)) == \ - -S(9)/8 + zeta(3) + assert summation(1/(n + 2)**3, (n, 1, oo)) == -S(9)/8 + zeta(3) assert summation(1/n**4, (n, 1, oo)) == pi**4/90 s = summation(x**n*n, (n, -oo, 0)) @@ -292,14 +540,17 @@ m = Symbol('n', integer=True, positive=True) assert summation(binomial(m, k), (k, 0, m)) == 2**m + def test_issue_1071(): assert summation(1/factorial(k), (k, 0, oo)) == E + def test_is_zero(): for func in [Sum, Product]: assert func(0, (x, 1, 1)).is_zero is True assert func(x, (x, 1, 1)).is_zero is None + def test_is_commutative(): from sympy.physics.secondquant import NO, F, Fd m = Symbol('m', commutative=False) @@ -310,6 +561,7 @@ assert f(NO(Fd(x)*F(y))*z, (z, 1, 2)).is_commutative is False + def test_is_number(): assert Sum(1, (x, 1, 1)).is_number is True assert Sum(1, (x, 1, x)).is_number is False @@ -328,6 +580,7 @@ assert Product(x, (y, 1, 1)).is_number is False assert Product(x, (x, 1, 2)).is_number is True + def test_free_symbols(): for func in [Sum, Product]: assert func(1, (x, 1, 2)).free_symbols == set() @@ -346,17 +599,119 @@ assert Sum(1, (x, 1, y)).free_symbols == set([y]) assert Product(1, (x, 1, y)).free_symbols == set() + +def test_conjugate_transpose(): + A, B = symbols("A B", commutative=False) + p = Sum(A*B**n, (n, 1, 3)) + assert p.adjoint().doit() == p.doit().adjoint() + assert p.conjugate().doit() == p.doit().conjugate() + assert p.transpose().doit() == p.doit().transpose() + + @XFAIL -def test_issue_1072() : +def test_issue_1072(): k = Symbol("k") assert summation(factorial(2*k + 1)/factorial(2*k), (k, 0, oo)) == oo + @XFAIL def test_issue_3174(): # when this passes, the doctests involving Sum in # is_constant can be unskipped assert Sum(x, (x, 1, n)).n(2, subs={n: 0}) == 1 -@XFAIL + def test_issue_3175(): assert Sum(x, (x, 1, 0)).doit() == 0 + assert NS(Sum(x, (x, 1, 0))) == '0.e-122' + assert Sum(n, (n, 10, 5)).doit() == -30 + assert NS(Sum(n, (n, 10, 5))) == '-30.0000000000000' + + +def test_simplify(): + y, t = symbols('y, t') + + assert simplify(Sum(x*y, (x, n, m), (y, a, k)) + \ + Sum(y, (x, n, m), (y, a, k))) == Sum(x*y + y, (x, n, m), (y, a, k)) + assert simplify(Sum(x, (x, n, m)) + Sum(x, (x, m + 1, a))) == \ + Sum(x, (x, n, a)) + assert simplify(Sum(x, (x, k + 1, a)) + Sum(x, (x, n, k))) == \ + Sum(x, (x, n, a)) + assert simplify(Sum(x, (x, k + 1, a)) + Sum(x + 1, (x, n, k))) == \ + Sum(x, (x, k + 1, a)) + Sum(x + 1, (x, n, k)) + assert simplify(Sum(x, (x, 0, 3)) * 3 + 3 * Sum(x, (x, 4, 6)) + \ + 4 * Sum(z, (z, 0, 1))) == Sum(4*z, (z, 0, 1)) + Sum(3*x, (x, 0, 6)) + assert simplify(3*Sum(x**2, (x, a, b)) + Sum(x, (x, a, b))) == \ + Sum(3*x**2 + x, (x, a, b)) + assert simplify(Sum(x**3, (x, n, k)) * 3 + 3 * Sum(x, (x, n, k)) + \ + 4 * y * Sum(z, (z, n, k))) + 1 == \ + y*Sum(4*z, (z, n, k)) + Sum(3*x**3 + 3*x, (x, n, k)) + 1 + assert simplify(Sum(x, (x, a, b)) + 1 + Sum(x, (x, b + 1, c))) == \ + 1 + Sum(x, (x, a, c)) + assert simplify(Sum(x, (t, a, b)) + Sum(y, (t, a, b)) + \ + Sum(x, (t, b+1, c))) == Sum(x + y, (t, a, b)) + Sum(x, (t, b+1, c)) + assert simplify(Sum(x, (t, a, b)) + Sum(x, (t, b+1, c)) + \ + Sum(y, (t, a, b))) == Sum(x + y, (t, a, b)) + Sum(x, (t, b+1, c)) + assert simplify(Sum(x, (t, a, b)) + 2 * Sum(x, (t, b+1, c))) == \ + simplify(Sum(x, (t, a, b)) + Sum(x, (t, b+1, c)) + Sum(x, (t, b+1, c))) + assert simplify(Sum(x, (x, a, b))*Sum(x**2, (x, a, b))) == \ + Sum(x, (x, a, b)) * Sum(x**2, (x, a, b)) + +def test_change_index(): + b, v = symbols('b, v', integer = True) + + assert change_index(Sum(x, (x, a, b)), x, x + 1, y) == \ + Sum(y - 1, (y, a + 1, b + 1)) + assert change_index(Sum(x**2, (x, a, b)), x, x - 1) == \ + Sum((x+1)**2, (x, a - 1, b - 1)) + assert change_index(Sum(x**2, (x, a, b)), x, -x, y) == \ + Sum((-y)**2, (y, -b, -a)) + assert change_index(Sum(x, (x, a, b)), x, -x - 1) == \ + Sum(-x - 1, (x, -b - 1, -a - 1)) + assert change_index(Sum(x*y, (x, a, b), (y, c, d)), x, x - 1, z) == \ + Sum((z + 1)*y, (z, a - 1, b - 1), (y, c, d)) + assert change_index(Sum(x, (x, a, b)), x, x + v) == \ + Sum(-v + x, (x, a + v, b + v)) + assert change_index(Sum(x, (x, a, b)), x, -x - v) == \ + Sum(-v - x, (x, -b - v, -a - v)) + + +def test_reorder(): + b, y, c, d, z = symbols('b, y, c, d, z', integer = True) + + assert reorder(Sum(x*y, (x, a, b), (y, c, d)), (0, 1)) == \ + Sum(x*y, (y, c, d), (x, a, b)) + assert reorder(Sum(x, (x, a, b), (x, c, d)), (0, 1)) == \ + Sum(x, (x, c, d), (x, a, b)) + assert reorder(Sum(x*y + z, (x, a, b), (z, m, n), (y, c, d)), \ + (2, 0), (0, 1)) == Sum(x*y + z, (z, m, n), (y, c, d), (x, a, b)) + assert reorder(Sum(x*y*z, (x, a, b), (y, c, d), (z, m, n)), \ + (0, 1), (1, 2), (0, 2)) == Sum(x*y*z, (x, a, b), (z, m, n), (y, c, d)) + assert reorder(Sum(x*y*z, (x, a, b), (y, c, d), (z, m, n)), \ + (x, y), (y, z), (x, z)) == Sum(x*y*z, (x, a, b), (z, m, n), (y, c, d)) + assert reorder(Sum(x*y, (x, a, b), (y, c, d)), (x, 1)) == \ + Sum(x*y, (y, c, d), (x, a, b)) + assert reorder(Sum(x*y, (x, a, b), (y, c, d)), (y, x)) == \ + Sum(x*y, (y, c, d), (x, a, b)) + + +def test_reverse_order(): + assert reverse_order(Sum(x, (x, 0, 3)), 0) == Sum(-x, (x, 4, -1)) + assert reverse_order(Sum(x*y, (x, 1, 5), (y, 0, 6)), 0, 1) == \ + Sum(x*y, (x, 6, 0), (y, 7, -1)) + assert reverse_order(Sum(x, (x, 1, 2)), 0) == Sum(-x, (x, 3, 0)) + assert reverse_order(Sum(x, (x, 1, 3)), 0) == Sum(-x, (x, 4, 0)) + assert reverse_order(Sum(x, (x, 1, a)), 0) == Sum(-x, (x, a + 1, 0)) + assert reverse_order(Sum(x, (x, a, 5)), 0) == Sum(-x, (x, 6, a - 1)) + assert reverse_order(Sum(x, (x, a + 1, a + 5)), 0) == \ + Sum(-x, (x, a + 6, a)) + assert reverse_order(Sum(x, (x, a + 1, a + 2)), 0) == \ + Sum(-x, (x, a + 3, a)) + assert reverse_order(Sum(x, (x, a + 1, a + 1)), 0) == \ + Sum(-x, (x, a + 2, a)) + assert reverse_order(Sum(x, (x, a, b)), 0) == Sum(-x, (x, b + 1, a - 1)) + assert reverse_order(Sum(x, (x, a, b)), x) == Sum(-x, (x, b + 1, a - 1)) + assert reverse_order(Sum(x*y, (x, a, b), (y, 2, 5)), x, 1) == \ + Sum(x*y, (x, b + 1, a - 1), (y, 6, 1)) + assert reverse_order(Sum(x*y, (x, a, b), (y, 2, 5)), y, x) == \ + Sum(x*y, (x, b + 1, a - 1), (y, 6, 1)) diff -Nru python3-sympy-0.7.2/sympy/conftest.py python3-sympy-0.7.3/sympy/conftest.py --- python3-sympy-0.7.2/sympy/conftest.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/conftest.py 2013-07-13 17:53:32.000000000 +0000 @@ -4,23 +4,34 @@ import pytest from sympy.core.cache import clear_cache + def pytest_report_header(config): from sympy.utilities.misc import ARCH s = "architecture: %s\n" % ARCH from sympy.core.cache import USE_CACHE s += "cache: %s\n" % USE_CACHE - from sympy.polys.domains import GROUND_TYPES - s += "ground types: %s\n" % GROUND_TYPES + from sympy.core.compatibility import GROUND_TYPES, HAS_GMPY + version = '' + if GROUND_TYPES =='gmpy': + if HAS_GMPY == 1: + import gmpy + elif HAS_GMPY == 2: + import gmpy2 as gmpy + version = gmpy.version() + s += "ground types: %s %s\n" % (GROUND_TYPES, version) return s + def pytest_addoption(parser): parser.addoption("--slow", dest="runslow", action="store_true", help="allow slow tests to run") + def pytest_configure(config): # register an additional marker config.addinivalue_line("markers", "slow: slow test") + def pytest_runtest_setup(item): if not isinstance(item, pytest.Function): return @@ -31,7 +42,9 @@ def pytest_terminal_summary(terminalreporter): if (terminalreporter.stats.get('error', None) or terminalreporter.stats.get('failed', None)): - terminalreporter.write_sep(' ', 'DO *NOT* COMMIT!', red=True, bold=True) + terminalreporter.write_sep( + ' ', 'DO *NOT* COMMIT!', red=True, bold=True) + def pytest_runtest_teardown(): clear_cache() diff -Nru python3-sympy-0.7.2/sympy/core/__init__.py python3-sympy-0.7.3/sympy/core/__init__.py --- python3-sympy-0.7.2/sympy/core/__init__.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/core/__init__.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,14 +1,14 @@ """Core module. Provides the basic operations needed in sympy. """ -from .sympify import sympify +from .sympify import sympify, SympifyError from .cache import cacheit from .basic import Basic, Atom, C, preorder_traversal from .singleton import S from .expr import Expr, AtomicExpr from .symbol import Symbol, Wild, Dummy, symbols, var -from .numbers import Number, Float, Rational, Integer, NumberSymbol,\ - RealNumber, Real, igcd, ilcm, seterr, E, I, nan, oo, pi, zoo +from .numbers import Number, Float, Rational, Integer, NumberSymbol, \ + RealNumber, Real, igcd, ilcm, seterr, E, I, nan, oo, pi, zoo from .power import Pow, integer_nthroot from .mul import Mul, prod from .add import Add @@ -19,7 +19,7 @@ from .multidimensional import vectorize from .function import Lambda, WildFunction, Derivative, diff, FunctionClass, \ Function, Subs, expand, PoleError, count_ops, \ - expand_mul, expand_log, expand_func,\ + expand_mul, expand_log, expand_func, \ expand_trig, expand_complex, expand_multinomial, nfloat, \ expand_power_base, expand_power_exp from .sets import (Set, Interval, Union, EmptySet, FiniteSet, ProductSet, diff -Nru python3-sympy-0.7.2/sympy/core/add.py python3-sympy-0.7.3/sympy/core/add.py --- python3-sympy-0.7.2/sympy/core/add.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/core/add.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,13 +1,71 @@ -from .core import C -from .singleton import S -from .operations import AssocOp -from .cache import cacheit -from .numbers import ilcm, igcd - from collections import defaultdict + +from sympy.core.core import C +from sympy.core.singleton import S +from sympy.core.operations import AssocOp +from sympy.core.cache import cacheit +from sympy.core.numbers import ilcm, igcd +from sympy.core.expr import Expr from functools import reduce -class Add(AssocOp): + +def _addsort(args): + # in-place sorting of args + + # Currently we sort things using hashes, as it is quite fast. A better + # solution is not to sort things at all - but this needs some more + # fixing. + args.sort(key=hash) + + +def _unevaluated_Add(*args): + """Return a well-formed unevaluated Add: Numbers are collected and + put in slot 0 and args are sorted. Use this when args have changed + but you still want to return an unevaluated Add. + + Examples + ======== + + >>> from sympy.core.add import _unevaluated_Add as uAdd + >>> from sympy import S, Add + >>> from sympy.abc import x, y + >>> a = uAdd(*[S(1.0), x, S(2)]) + >>> a.args[0] + 3.00000000000000 + >>> a.args[1] + x + + Beyond the Number being in slot 0, there is no other assurance of + order for the arguments since they are hash sorted. So, for testing + purposes, output produced by this in some other function can only + be tested against the output of this function or as one of several + options: + + >>> opts = (Add(x, y, evaluated=False), Add(y, x, evaluated=False)) + >>> a = uAdd(x, y) + >>> assert a in opts and a == uAdd(x, y) + + """ + args = list(args) + newargs = [] + co = S.Zero + while args: + a = args.pop() + if a.is_Add: + # this will keep nesting from building up + # so that x + (x + 1) -> x + x + 1 (3 args) + args.extend(a.args) + elif a.is_Number: + co += a + else: + newargs.append(a) + _addsort(newargs) + if co: + newargs.insert(0, co) + return Add._from_args(newargs) + + +class Add(Expr, AssocOp): __slots__ = [] @@ -39,29 +97,8 @@ a, b = seq if b.is_Rational: a, b = b, a - assert a if a.is_Rational: if b.is_Mul: - # if it's an unevaluated 2-arg, expand it - c, t = b.as_coeff_Mul() - if t.is_Add: - h, t = t.as_coeff_Add() - bargs = [c*ti for ti in Add.make_args(t)] - bargs.sort(key=hash) - ch = c*h - if ch: - bargs.insert(0, ch) - b = Add._from_args(bargs) - if b.is_Add: - bargs = list(b.args) - if bargs[0].is_Number: - bargs[0] += a - if not bargs[0]: - bargs.pop(0) - else: - bargs.insert(0, a) - rv = bargs, [], None - elif b.is_Mul: rv = [a, b], [], None if rv: if all(s.is_commutative for s in rv[0]): @@ -71,7 +108,7 @@ terms = {} # term -> coeff # e.g. x**2 -> 5 for ... + 5*x**2 + ... - coeff = S.Zero # standalone term (Number or zoo will always be in slot 0) + coeff = S.Zero # coefficient (Number or zoo) to always be in slot 0 # e.g. 3 + ... order_factors = [] @@ -85,12 +122,14 @@ break if o is None: continue - order_factors = [o]+[o1 for o1 in order_factors if not o.contains(o1)] + order_factors = [o] + [ + o1 for o1 in order_factors if not o.contains(o1)] continue # 3 or NaN elif o.is_Number: - if o is S.NaN or coeff is S.ComplexInfinity and o.is_bounded is False: + if (o is S.NaN or coeff is S.ComplexInfinity and + o.is_bounded is False): # we know for sure the result will be nan return [S.NaN], [], None if coeff.is_Number: @@ -117,18 +156,11 @@ elif o.is_Mul: c, s = o.as_coeff_Mul() - # 3*... - # unevaluated 2-arg Mul, but we always unfold it so - # it can combine with other terms (just like is done - # with the Pow below) - if c.is_Number and s.is_Add: - seq.extend([c*a for a in s.args]) - continue - # check for unevaluated Pow, e.g. 2**3 or 2**(-1/2) elif o.is_Pow: b, e = o.as_base_exp() - if b.is_Number and (e.is_Integer or (e.is_Rational and e.is_negative)): + if b.is_Number and (e.is_Integer or + (e.is_Rational and e.is_negative)): seq.append(b**e) continue c, s = S.One, o @@ -138,13 +170,11 @@ c = S.One s = o - # now we have: # o = c*s, where # # c is a Number # s is an expression with number factor extracted - # let's collect terms with the same s, so e.g. # 2*x**2 + 3*x**2 -> 5*x**2 if s in terms: @@ -152,12 +182,11 @@ else: terms[s] = c - # now let's construct new args: # [2*x**2, x**3, 7*x**4, pi, ...] newseq = [] noncommutative = False - for s,c in list(terms.items()): + for s, c in list(terms.items()): # 0*s if c is S.Zero: continue @@ -171,33 +200,35 @@ # so we can simply put c in slot0 and go the fast way. cs = s._new_rawargs(*((c,) + s.args)) newseq.append(cs) - + elif s.is_Add: + # we just re-create the unevaluated Mul + newseq.append(Mul(c, s, evaluate=False)) else: # alternatively we have to call all Mul's machinery (slow) - newseq.append(Mul(c,s)) + newseq.append(Mul(c, s)) noncommutative = noncommutative or not s.is_commutative # oo, -oo if coeff is S.Infinity: - newseq = [f for f in newseq if not (f.is_nonnegative or f.is_real and - (f.is_bounded or - f.is_finite or - f.is_infinitesimal))] + newseq = [f for f in newseq if not + (f.is_nonnegative or f.is_real and + (f.is_bounded or f.is_infinitesimal))] + elif coeff is S.NegativeInfinity: - newseq = [f for f in newseq if not (f.is_nonpositive or f.is_real and - (f.is_bounded or - f.is_finite or - f.is_infinitesimal))] + newseq = [f for f in newseq if not + (f.is_nonpositive or f.is_real and + (f.is_bounded or f.is_infinitesimal))] + if coeff is S.ComplexInfinity: # zoo might be # unbounded_real + bounded_im # bounded_real + unbounded_im # unbounded_real + unbounded_im # addition of a bounded real or imaginary number won't be able to - # change the zoo nature; if unbounded a NaN condition could result if - # the unbounded symbol had sign opposite of the unbounded portion of zoo, - # e.g. unbounded_real - unbounded_real + # change the zoo nature; if unbounded a NaN condition could result + # if the unbounded symbol had sign opposite of the unbounded + # portion of zoo, e.g., unbounded_real - unbounded_real. newseq = [c for c in newseq if not (c.is_bounded and c.is_real is not None)] @@ -220,13 +251,8 @@ coeff = S.Zero break - # order args canonically - # Currently we sort things using hashes, as it is quite fast. A better - # solution is not to sort things at all - but this needs some more - # fixing. NOTE: this is used in primitive and Mul.flattten, too, so if - # it changes here it should be changed there. - newseq.sort(key=hash) + _addsort(newseq) # current code expects coeff to be first if coeff is not S.Zero: @@ -283,7 +309,7 @@ Examples ======== - >>> from sympy.abc import x, y + >>> from sympy.abc import x >>> (7 + 3*x).as_coeff_add() (7, (3*x,)) >>> (7*x).as_coeff_add() @@ -329,11 +355,12 @@ def _matches_simple(self, expr, repl_dict): # handle (w+3).matches('x+5') -> {w: x+2} coeff, terms = self.as_coeff_add() - if len(terms)==1: + if len(terms) == 1: return terms[0].matches(expr - coeff, repl_dict) return - matches = AssocOp._matches_commutative + def matches(self, expr, repl_dict={}, old=False): + return AssocOp._matches_commutative(self, expr, repl_dict, old) @staticmethod def _combine_inverse(lhs, rhs): @@ -389,7 +416,8 @@ # check for quick exit if len(nd) == 1: d, n = nd.popitem() - return Add(*[_keep_coeff(ncon, ni) for ni in n]), _keep_coeff(dcon, d) + return Add( + *[_keep_coeff(ncon, ni) for ni in n]), _keep_coeff(dcon, d) # sum up the terms having a common denominator for d, n in nd.items(): @@ -400,7 +428,7 @@ # assemble single numerator and denominator denoms, numers = [list(i) for i in zip(*iter(nd.items()))] - n, d = Add(*[Mul(*(denoms[:i]+[numers[i]]+denoms[i+1:])) + n, d = Add(*[Mul(*(denoms[:i] + [numers[i]] + denoms[i + 1:])) for i in range(len(numers))]), Mul(*denoms) return _keep_coeff(ncon, n), _keep_coeff(dcon, d) @@ -411,17 +439,27 @@ def _eval_is_rational_function(self, syms): return all(term._eval_is_rational_function(syms) for term in self.args) + def _eval_is_algebraic_expr(self, syms): + return all(term._eval_is_algebraic_expr(syms) for term in self.args) + # assumption methods - _eval_is_real = lambda self: self._eval_template_is_attr('is_real', when_multiple=None) - _eval_is_antihermitian = lambda self: self._eval_template_is_attr('is_antihermitian', when_multiple=None) - _eval_is_bounded = lambda self: self._eval_template_is_attr('is_bounded', when_multiple=None) - _eval_is_hermitian = lambda self: self._eval_template_is_attr('is_hermitian', when_multiple=None) - _eval_is_imaginary = lambda self: self._eval_template_is_attr('is_imaginary', when_multiple=None) - _eval_is_integer = lambda self: self._eval_template_is_attr('is_integer', when_multiple=None) - _eval_is_commutative = lambda self: self._eval_template_is_attr('is_commutative') + _eval_is_real = lambda self: self._eval_template_is_attr( + 'is_real', when_multiple=None) + _eval_is_antihermitian = lambda self: self._eval_template_is_attr( + 'is_antihermitian', when_multiple=None) + _eval_is_bounded = lambda self: self._eval_template_is_attr( + 'is_bounded', when_multiple=None) + _eval_is_hermitian = lambda self: self._eval_template_is_attr( + 'is_hermitian', when_multiple=None) + _eval_is_imaginary = lambda self: self._eval_template_is_attr( + 'is_imaginary', when_multiple=None) + _eval_is_integer = lambda self: self._eval_template_is_attr( + 'is_integer', when_multiple=None) + _eval_is_commutative = lambda self: self._eval_template_is_attr( + 'is_commutative') def _eval_is_odd(self): - l = [f for f in self.args if not (f.is_even==True)] + l = [f for f in self.args if not (f.is_even is True)] if not l: return False if l[0].is_odd: @@ -548,13 +586,16 @@ coeff_old, terms_old = old.as_coeff_Add() if coeff_self.is_Rational and coeff_old.is_Rational: - if terms_self == terms_old: # (2 + a).subs( 3 + a, y) -> -1 + y - return Add( new, coeff_self, -coeff_old) - if terms_self == -terms_old: # (2 + a).subs(-3 - a, y) -> -1 - y - return Add(-new, coeff_self, coeff_old) - - args_old, args_self = Add.make_args(terms_old), Add.make_args(terms_self) - if len(args_old) < len(args_self): # (a+b+c+d).subs(b+c,x) -> a+x+d + if terms_self == terms_old: # (2 + a).subs( 3 + a, y) -> -1 + y + return Add(new, coeff_self, -coeff_old) + if terms_self == -terms_old: # (2 + a).subs(-3 - a, y) -> -1 - y + return Add(-new, coeff_self, coeff_old) + + if coeff_self.is_Rational and coeff_old.is_Rational \ + or coeff_self == coeff_old: + args_old, args_self = Add.make_args( + terms_old), Add.make_args(terms_self) + if len(args_old) < len(args_self): # (a+b+c).subs(b+c,x) -> a+x self_set = set(args_self) old_set = set(args_old) @@ -563,7 +604,8 @@ return Add(new, coeff_self, -coeff_old, *[s._subs(old, new) for s in ret_set]) - args_old = Add.make_args(-terms_old) # (a+b+c+d).subs(-b-c,x) -> a-x+d + args_old = Add.make_args( + -terms_old) # (a+b+c+d).subs(-b-c,x) -> a-x+d old_set = set(args_old) if old_set < self_set: ret_set = self_set - old_set @@ -755,7 +797,7 @@ c = terms.pop(0) else: c = None - terms.sort(key=hash) + _addsort(terms) if c: terms.insert(0, c) return Rational(ngcd, dlcm), self._new_rawargs(*terms) @@ -780,7 +822,8 @@ See docstring of Expr.as_content_primitive for more examples. """ - con, prim = Add(*[_keep_coeff(*a.as_content_primitive(radical=radical)) for a in self.args]).primitive() + con, prim = Add(*[_keep_coeff(*a.as_content_primitive( + radical=radical)) for a in self.args]).primitive() if radical and prim.is_Add: # look for common radicals that can be removed args = prim.args @@ -791,8 +834,8 @@ for ai in Mul.make_args(m): if ai.is_Pow: b, e = ai.as_base_exp() - if e.is_Rational and b.is_Integer and b > 0: - term_rads[e.q].append(int(b)**e.p) + if e.is_Rational and b.is_Integer: + term_rads[e.q].append(abs(int(b))**e.p) if not term_rads: break if common_q is None: @@ -826,7 +869,7 @@ @property def _sorted_args(self): - from sympy.utilities.misc import default_sort_key + from sympy.core.compatibility import default_sort_key return sorted(self.args, key=lambda w: default_sort_key(w)) from .mul import Mul, _keep_coeff, prod diff -Nru python3-sympy-0.7.2/sympy/core/assumptions.py python3-sympy-0.7.3/sympy/core/assumptions.py --- python3-sympy-0.7.2/sympy/core/assumptions.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/core/assumptions.py 2013-07-13 17:53:32.000000000 +0000 @@ -78,8 +78,9 @@ 'real == negative | zero | positive', - 'positive -> real & !negative & !zero', - 'negative -> real & !positive & !zero', + 'negative == nonpositive & nonzero', + 'positive == nonnegative & nonzero', + 'zero == nonnegative & nonpositive', 'nonpositive == real & !positive', 'nonnegative == real & !negative', @@ -108,6 +109,7 @@ _assume_defined.add('polar') _assume_defined = frozenset(_assume_defined) + class StdFactKB(FactKB): """A FactKB specialised for the built-in rules @@ -127,6 +129,7 @@ """Convert a fact name to the name of the corresponding property""" return 'is_%s' % fact + def make_property(fact): """Create the automagic property corresponding to a fact.""" @@ -141,6 +144,7 @@ getit.__name__ = as_property(fact) return property(getit) + def _ask(fact, obj): """ Find the truth value for a property of an object. @@ -198,6 +202,7 @@ # Note: the result has already been cached return None + class ManagedProperties(BasicMeta, metaclass=BasicMeta): """Metaclass for classes with old-style assumptions""" @@ -241,7 +246,7 @@ try: derived_from_bases |= set(base.default_assumptions) except AttributeError: - continue #not an assumption-aware class + continue # not an assumption-aware class for fact in derived_from_bases - set(cls.default_assumptions): pname = as_property(fact) if pname not in cls.__dict__: diff -Nru python3-sympy-0.7.2/sympy/core/basic.py python3-sympy-0.7.3/sympy/core/basic.py --- python3-sympy-0.7.2/sympy/core/basic.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/core/basic.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,24 +1,25 @@ """Base class for all the objects in SymPy""" -from copy import copy from sympy.core.assumptions import ManagedProperties from sympy.core.cache import cacheit from sympy.core.core import BasicType, C from sympy.core.sympify import _sympify, sympify, SympifyError -from sympy.core.compatibility import callable, reduce, cmp, iterable +from sympy.core.compatibility import (callable, reduce, cmp, iterable, + ordered) from sympy.core.decorators import deprecated from sympy.core.singleton import S import collections from functools import reduce + class Basic(object, metaclass=ManagedProperties): """ - Base class for all objects in sympy. + Base class for all objects in SymPy. Conventions: 1) Always use ``.args``, when accessing parameters of some instance: - >>> from sympy import symbols, cot + >>> from sympy import cot >>> from sympy.abc import x, y >>> cot(x).args @@ -80,8 +81,8 @@ def __new__(cls, *args): obj = object.__new__(cls) - obj._assumptions = cls.default_assumptions - obj._mhash = None # will be set by __hash__ method. + obj._assumptions = cls.default_assumptions + obj._mhash = None # will be set by __hash__ method. obj._args = args # all items in args must be Basic objects return obj @@ -219,7 +220,7 @@ if c != 0: return c - return Basic.compare(a,b) + return Basic.compare(a, b) @staticmethod @deprecated(useinstead="default_sort_key", issue=1491, deprecated_since_version="0.7.2") @@ -272,7 +273,7 @@ # both objects are non-SymPy if (not isinstance(a, Basic)) and (not isinstance(b, Basic)): - return cmp(a,b) + return cmp(a, b) if not isinstance(a, Basic): return -1 # other < sympy @@ -314,8 +315,7 @@ Examples ======== - >>> from sympy.core import Basic, S, I - >>> from sympy.abc import x + >>> from sympy.core import S, I >>> sorted([S(1)/2, I, -I], key=lambda x: x.sort_key()) [1/2, -I, I] @@ -376,7 +376,6 @@ return self._hashable_content() == other._hashable_content() - def __ne__(self, other): """a != b -> Compare two symbolic trees and see whether they are different @@ -428,7 +427,8 @@ elif len(dummy_symbols) == 1: dummy = dummy_symbols.pop() else: - raise ValueError("only one dummy symbol allowed on the left-hand side") + raise ValueError( + "only one dummy symbol allowed on the left-hand side") if symbol is None: symbols = other.free_symbols @@ -527,7 +527,8 @@ """ if types: - types = tuple([t if isinstance(t, type) else type(t) for t in types]) + types = tuple( + [t if isinstance(t, type) else type(t) for t in types]) else: types = (Atom,) result = set() @@ -552,27 +553,44 @@ union = set.union return reduce(union, [arg.free_symbols for arg in self.args], set()) + @property + def canonical_variables(self): + """Return a dictionary mapping any variable defined in + ``self.variables`` as underscore-suffixed numbers + corresponding to their position in ``self.variables``. Enough + underscores are added to ensure that there will be no clash with + existing free symbols. + + Examples + ======== + + >>> from sympy import Lambda + >>> from sympy.abc import x + >>> Lambda(x, 2*x).canonical_variables + {x: 0_} + """ + if not hasattr(self, 'variables'): + return {} + u = "_" + while any(s.name.endswith(u) for s in self.free_symbols): + u += "_" + name = '%%i%s' % u + V = self.variables + return dict(list(zip(V, [C.Symbol(name % i, **v.assumptions0) + for i, v in enumerate(V)]))) + def is_hypergeometric(self, k): from sympy.simplify import hypersimp return hypersimp(self, k) is not None @property def is_number(self): - """Returns ``True`` if 'self' is a number. + """Returns ``True`` if 'self' contains no free symbols. - >>> from sympy import log, Integral - >>> from sympy.abc import x, y - - >>> x.is_number - False - >>> (2*x).is_number - False - >>> (2 + log(2)).is_number - True - >>> (2 + Integral(2, x)).is_number - False - >>> (2 + Integral(2, (x, 1, 2))).is_number - True + See Also + ======== + is_comparable + sympy.core.expr.is_number """ # should be overriden by subclasses @@ -580,6 +598,18 @@ @property def is_comparable(self): + """Return True if self can be computed to a real number + with precision, else False. + + Examples + ======== + + >>> from sympy import exp_polar, pi, I + >>> (I*exp_polar(I*pi/2)).is_comparable + True + >>> (I*exp_polar(I*pi*2)).is_comparable + False + """ is_real = self.is_real if is_real is False: return False @@ -588,13 +618,15 @@ return False if is_real and is_number: return True - n, i = self.evalf(2).as_real_imag() + n, i = [p.evalf(2) for p in self.as_real_imag()] if not i.is_Number or not n.is_Number: return False if i: - if i._prec != 1: - return False - return n._prec != 1 + # if _prec = 1 we can't decide and if not, + # the answer is False so return False + return False + else: + return n._prec != 1 @property def func(self): @@ -629,7 +661,7 @@ Examples ======== - >>> from sympy import symbols, cot + >>> from sympy import cot >>> from sympy.abc import x, y >>> cot(x).args @@ -683,7 +715,7 @@ def as_poly(self, *gens, **args): """Converts ``self`` to a polynomial or returns ``None``. - >>> from sympy import Poly, sin + >>> from sympy import sin >>> from sympy.abc import x, y >>> print((x**2 + x*y).as_poly()) @@ -781,7 +813,7 @@ default_sort_key to break any ties. All other iterables are left unsorted. - >>> from sympy import sqrt, sin, cos, exp + >>> from sympy import sqrt, sin, cos >>> from sympy.abc import a, b, c, d, e >>> A = (sqrt(sin(2*x)), a) @@ -850,19 +882,20 @@ d.setdefault(ops, []).append((o, n)) newseq = [] for k in sorted(list(d.keys()), reverse=True): - newseq.extend(sorted([v[0] for v in d[k]], key=default_sort_key)) + newseq.extend( + sorted([v[0] for v in d[k]], key=default_sort_key)) sequence = [(k, sequence[k]) for k in newseq] del newseq, d else: sequence = sorted([(k, v) for (k, v) in sequence.items()], key=default_sort_key) - if kwargs.pop('simultaneous', False): # XXX should this be the default for dict subs? + if kwargs.pop('simultaneous', False): # XXX should this be the default for dict subs? reps = {} rv = self for old, new in sequence: d = C.Dummy() - rv = rv._subs(old, d) + rv = rv._subs(old, d, **kwargs) reps[d] = new if not isinstance(rv, Basic): break @@ -870,7 +903,7 @@ else: rv = self for old, new in sequence: - rv = rv._subs(old, new) + rv = rv._subs(old, new, **kwargs) if not isinstance(rv, Basic): break return rv @@ -885,7 +918,7 @@ should be applied wherein a search for replacements is made amongst the arguments of self. - >>> from sympy import Basic, Add, Mul + >>> from sympy import Add >>> from sympy.abc import x, y, z Examples @@ -961,7 +994,22 @@ hit = True args[i] = arg if hit: - return self.func(*args) + rv = self.func(*args) + hack2 = hints.get('hack2', False) + if hack2 and self.is_Mul and not rv.is_Mul: # 2-arg hack + coeff = S.One + nonnumber = [] + for i in args: + if i.is_Number: + coeff *= i + else: + nonnumber.append(i) + nonnumber = self.func(*nonnumber) + if coeff is S.One: + return nonnumber + else: + return self.func(coeff, nonnumber, evaluate=False) + return rv return self if _aresame(self, old): @@ -1042,8 +1090,14 @@ if self in rule: return rule[self] elif rule: - args = tuple([arg.xreplace(rule) for arg in self.args]) - if args != self.args: + args = [] + for a in self.args: + try: + args.append(a.xreplace(rule)) + except AttributeError: + args.append(a) + args = tuple(args) + if not _aresame(args, self.args): return self.func(*args) return self @@ -1068,7 +1122,7 @@ Examples ======== - >>> from sympy import sin, S + >>> from sympy import sin >>> from sympy.abc import x, y, z >>> (x**2 + sin(x*y)).has(z) False @@ -1105,70 +1159,125 @@ except AttributeError: return any(arg == pattern for arg in preorder_traversal(self)) - def _has_matcher(self): """Helper for .has()""" return self.__eq__ - - def replace(self, query, value, map=False): + def replace(self, query, value, map=False, simultaneous=True, exact=False): """ Replace matching subexpressions of ``self`` with ``value``. If ``map = True`` then also return the mapping {old: new} where ``old`` was a sub-expression found with query and ``new`` is the replacement - value for it. + value for it. If the expression itself doesn't match the query, then + the returned value will be ``self.xreplace(map)`` otherwise it should + be ``self.subs(ordered(map.items()))``. Traverses an expression tree and performs replacement of matching - subexpressions from the bottom to the top of the tree. The list of - possible combinations of queries and replacement values is listed - below: + subexpressions from the bottom to the top of the tree. The default + approach is to do the replacement in a simultaneous fashion so + changes made are targeted only once. If this is not desired or causes + problems, ``simultaneous`` can be set to False. In addition, if an + expression containing more than one Wild symbol is being used to match + subexpressions and the ``exact`` flag is True, then the match will only + succeed if non-zero values are received for each Wild that appears in + the match pattern. + + The list of possible combinations of queries and replacement values + is listed below: Examples ======== Initial setup - >>> from sympy import log, sin, cos, tan, Wild + >>> from sympy import log, sin, cos, tan, Wild, Mul, Add >>> from sympy.abc import x, y >>> f = log(sin(x)) + tan(sin(x**2)) 1.1. type -> type - obj.replace(sin, tan) + obj.replace(type, newtype) + + When object of type ``type`` is found, replace it with the + result of passing its argument(s) to ``newtype``. >>> f.replace(sin, cos) log(cos(x)) + tan(cos(x**2)) >>> sin(x).replace(sin, cos, map=True) (cos(x), {sin(x): cos(x)}) + >>> (x*y).replace(Mul, Add) + x + y 1.2. type -> func - obj.replace(sin, lambda arg: ...) + obj.replace(type, func) + + When object of type ``type`` is found, apply ``func`` to its + argument(s). ``func`` must be written to handle the number + of arguments of ``type``. >>> f.replace(sin, lambda arg: sin(2*arg)) log(sin(2*x)) + tan(sin(2*x**2)) + >>> (x*y).replace(Mul, lambda *args: sin(2*Mul(*args))) + sin(2*x*y) - 2.1. expr -> expr - obj.replace(sin(a), tan(a)) + 2.1. pattern -> expr + obj.replace(pattern(wild), expr(wild)) + + Replace subexpressions matching ``pattern`` with the expression + written in terms of the Wild symbols in ``pattern``. >>> a = Wild('a') >>> f.replace(sin(a), tan(a)) log(tan(x)) + tan(tan(x**2)) + >>> f.replace(sin(a), tan(a/2)) + log(tan(x/2)) + tan(tan(x**2/2)) + >>> f.replace(sin(a), a) + log(x) + tan(x**2) + >>> (x*y).replace(a*x, a) + y + + When the default value of False is used with patterns that have + more than one Wild symbol, non-intuitive results may be obtained: + + >>> b = Wild('b') + >>> (2*x).replace(a*x + b, b - a) + 2/x + + For this reason, the ``exact`` option can be used to make the + replacement only when the match gives non-zero values for all + Wild symbols: + + >>> (2*x + y).replace(a*x + b, b - a, exact=True) + y - 2 + >>> (2*x).replace(a*x + b, b - a, exact=True) + 2*x - 2.2. expr -> func - obj.replace(sin(a), lambda a: ...) + 2.2. pattern -> func + obj.replace(pattern(wild), lambda wild: expr(wild)) + + All behavior is the same as in 2.1 but now a function in terms of + pattern variables is used rather than an expression: - >>> f.replace(sin(a), cos(a)) - log(cos(x)) + tan(cos(x**2)) >>> f.replace(sin(a), lambda a: sin(2*a)) log(sin(2*x)) + tan(sin(2*x**2)) 3.1. func -> func - obj.replace(lambda expr: ..., lambda expr: ...) + obj.replace(filter, func) + + Replace subexpression ``e`` with ``func(e)`` if ``filter(e)`` + is True. >>> g = 2*sin(x**3) >>> g.replace(lambda expr: expr.is_Number, lambda expr: expr**2) 4*sin(x**9) + The expression itself is also targeted by the query but is done in + such a fashion that changes are not made twice. + + >>> e = x*(x*y + 1) + >>> e.replace(lambda x: x.is_Mul, lambda x: 2*x) + 2*x*(2*x*y + 1) + See Also ======== subs: substitution of subexpressions as defined by the objects @@ -1177,6 +1286,17 @@ using matching rules """ + from sympy.core.symbol import Dummy + from sympy.simplify.simplify import bottom_up + + try: + query = sympify(query) + except SympifyError: + pass + try: + value = sympify(value) + except SympifyError: + pass if isinstance(query, type): _query = lambda expr: isinstance(expr, query) @@ -1185,65 +1305,91 @@ elif isinstance(value, collections.Callable): _value = lambda expr, result: value(*expr.args) else: - raise TypeError("given a type, replace() expects another type or a callable") + raise TypeError( + "given a type, replace() expects another " + "type or a callable") elif isinstance(query, Basic): _query = lambda expr: expr.match(query) + # XXX remove the exact flag and make multi-symbol + # patterns use exact=True semantics; to do this the query must + # be tested to find out how many Wild symbols are present. + # See https://groups.google.com/forum/ + # ?fromgroups=#!topic/sympy/zPzo5FtRiqI + # for a method of inspecting a function to know how many + # parameters it has. if isinstance(value, Basic): - _value = lambda expr, result: value.subs(result) + if exact: + _value = lambda expr, result: (value.subs(result) + if all(val for val in list(result.values())) else expr) + else: + _value = lambda expr, result: value.subs(result) elif isinstance(value, collections.Callable): - _value = lambda expr, result: value(**dict([ (str(key)[:-1], val) for key, val in result.items() ])) + # match dictionary keys get the trailing underscore stripped + # from them and are then passed as keywords to the callable; + # if ``exact`` is True, only accept match if there are no null + # values amongst those matched. + if exact: + _value = lambda expr, result: (value(**dict([ ( + str(key)[:-1], val) for key, val in result.items()])) + if all(val for val in list(result.values())) else expr) + else: + _value = lambda expr, result: value(**dict([ ( + str(key)[:-1], val) for key, val in result.items()])) else: - raise TypeError("given an expression, replace() expects another expression or a callable") + raise TypeError( + "given an expression, replace() expects " + "another expression or a callable") elif isinstance(query, collections.Callable): _query = query if isinstance(value, collections.Callable): _value = lambda expr, result: value(expr) else: - raise TypeError("given a callable, replace() expects another callable") + raise TypeError( + "given a callable, replace() expects " + "another callable") else: - raise TypeError("first argument to replace() must be a type, an expression or a callable") - - mapping = {} + raise TypeError( + "first argument to replace() must be a " + "type, an expression or a callable") + mapping = {} # changes that took place + mask = [] # the dummies that were used as change placeholders def rec_replace(expr): - args, construct = [], False - - for arg in expr.args: - result = rec_replace(arg) - - if result is not None: - construct = True - else: - result = arg - - args.append(result) - - if construct: - return expr.__class__(*args) - else: - result = _query(expr) - - if result: - value = _value(expr, result) - - if map: - mapping[expr] = value - - return value - else: - return None - - result = rec_replace(self) - - if result is None: - result = self + result = _query(expr) + if result or result == {}: + new = _value(expr, result) + if new is not None and new != expr: + mapping[expr] = new + if simultaneous: + # don't let this expression be changed during rebuilding + d = Dummy() + mask.append((d, new)) + expr = d + else: + expr = new + return expr + + rv = bottom_up(self, rec_replace, atoms=True) + + # restore original expressions for Dummy symbols + if simultaneous: + mask = list(reversed(mask)) + for o, n in mask: + r = {o: n} + rv = rv.xreplace(r) if not map: - return result + return rv else: - return result, mapping + if simultaneous: + # restore subexpressions in mapping + for o, n in mask: + r = {o: n} + mapping = dict([(k.xreplace(r), v.xreplace(r)) + for k, v in mapping.items()]) + return rv, mapping def find(self, query, group=False): """Find all subexpressions matching a query. """ @@ -1268,18 +1414,21 @@ query = _make_find_query(query) return sum(bool(query(sub)) for sub in preorder_traversal(self)) - def matches(self, expr, repl_dict={}): + def matches(self, expr, repl_dict={}, old=False): """ - Helper method for match() - switches the pattern and expr. + Helper method for match() that looks for a match between Wild symbols + in self and expressions in expr. - Can be used to solve linear equations: + Examples + ======== - >>> from sympy import Symbol, Wild, Integer - >>> a,b = list(map(Symbol, 'ab')) + >>> from sympy import symbols, Wild, Basic + >>> a, b, c = symbols('a b c') >>> x = Wild('x') - >>> (a+b*x).matches(Integer(0)) - {x_: -a/b} - + >>> Basic(a + x, x).matches(Basic(a + b, c)) is None + True + >>> Basic(a + x, x).matches(Basic(a + b + c, b + c)) + {x_: b + c} """ expr = sympify(expr) if not isinstance(expr, self.__class__): @@ -1295,12 +1444,12 @@ for arg, other_arg in zip(self.args, expr.args): if arg == other_arg: continue - d = arg.xreplace(d).matches(other_arg, d) + d = arg.xreplace(d).matches(other_arg, d, old=old) if d is None: return None return d - def match(self, pattern): + def match(self, pattern, old=False): """ Pattern matching. @@ -1314,7 +1463,7 @@ Examples ======== - >>> from sympy import symbols, Wild + >>> from sympy import Wild >>> from sympy.abc import x, y >>> p = Wild("p") >>> q = Wild("q") @@ -1330,15 +1479,32 @@ >>> (p*q**r).xreplace(e.match(p*q**r)) 4*x**2 + The ``old`` flag will give the old-style pattern matching where + expressions and patterns are essentially solved to give the + match. Both of the following give None unless ``old=True``: + + >>> (x - 2).match(p - x, old=True) + {p_: 2*x - 2} + >>> (2/x).match(p*x, old=True) + {p_: 2/x**2} + """ + from sympy import signsimp pattern = sympify(pattern) - return pattern.matches(self) + s = signsimp(self) + p = signsimp(pattern) + # if we still have the same relationship between the types of + # input, then use the sign simplified forms + if (pattern.func == self.func) and (s.func == p.func): + rv = p.matches(s, old=old) + else: + rv = pattern.matches(self, old=old) + return rv def count_ops(self, visual=None): """wrapper for count_ops that returns the operation count.""" from sympy import count_ops return count_ops(self, visual) - return sum(a.count_ops(visual) for a in self.args) def doit(self, **hints): """Evaluate objects that are not evaluated by default like limits, @@ -1347,7 +1513,7 @@ or unless the 'deep' hint was set to 'False'. >>> from sympy import Integral - >>> from sympy.abc import x, y + >>> from sympy.abc import x >>> 2*Integral(x, x) 2*Integral(x, x) @@ -1360,42 +1526,61 @@ """ if hints.get('deep', True): - terms = [ term.doit(**hints) for term in self.args ] + terms = [ term.doit(**hints) if isinstance(term, Basic) else term + for term in self.args ] return self.func(*terms) else: return self def _eval_rewrite(self, pattern, rule, **hints): if self.is_Atom: + if hasattr(self, rule): + return getattr(self, rule)() return self sargs = self.args - terms = [ t._eval_rewrite(pattern, rule, **hints) for t in sargs ] + terms = [ t._eval_rewrite(pattern, rule, **hints) + if isinstance(t, Basic) else t + for t in sargs ] return self.func(*terms) def rewrite(self, *args, **hints): - """Rewrites expression containing applications of functions - of one kind in terms of functions of different kind. For - example you can rewrite trigonometric functions as complex - exponentials or combinatorial functions as gamma function. - - As a pattern this function accepts a list of functions to - to rewrite (instances of DefinedFunction class). As rule - you can use string or a destination function instance (in - this case rewrite() will use the str() function). - - There is also possibility to pass hints on how to rewrite - the given expressions. For now there is only one such hint - defined called 'deep'. When 'deep' is set to False it will - forbid functions to rewrite their contents. + """ Rewrite functions in terms of other functions. - >>> from sympy import sin, exp, I - >>> from sympy.abc import x, y + Rewrites expression containing applications of functions + of one kind in terms of functions of different kind. For + example you can rewrite trigonometric functions as complex + exponentials or combinatorial functions as gamma function. + + As a pattern this function accepts a list of functions to + to rewrite (instances of DefinedFunction class). As rule + you can use string or a destination function instance (in + this case rewrite() will use the str() function). + + There is also possibility to pass hints on how to rewrite + the given expressions. For now there is only one such hint + defined called 'deep'. When 'deep' is set to False it will + forbid functions to rewrite their contents. + + Examples + ======== + + >>> from sympy import sin, exp + >>> from sympy.abc import x + + Unspecified pattern: + >>> sin(x).rewrite(exp) + -I*(exp(I*x) - exp(-I*x))/2 + + Pattern as a single function: + >>> sin(x).rewrite(sin, exp) + -I*(exp(I*x) - exp(-I*x))/2 - >>> sin(x).rewrite(sin, exp) - -I*(exp(I*x) - exp(-I*x))/2 + Pattern as a list of functions: + >>> sin(x).rewrite([sin, ], exp) + -I*(exp(I*x) - exp(-I*x))/2 """ - if self.is_Atom or not args: + if not args: return self else: pattern = args[:-1] @@ -1417,6 +1602,7 @@ else: return self + class Atom(Basic): """ A parent class for atomic things. An atom is an expression with no subexpressions. @@ -1432,11 +1618,11 @@ __slots__ = [] - def matches(self, expr, repl_dict={}): + def matches(self, expr, repl_dict={}, old=False): if self == expr: return repl_dict - def xreplace(self, rule): + def xreplace(self, rule, hack2=False): return rule.get(self, self) def doit(self, **hints): @@ -1451,6 +1637,9 @@ from sympy.core import S return self.class_key(), (1, (str(self),)), S.One.sort_key(), S.One + def _eval_simplify(self, ratio, measure): + return self + @property def _sorted_args(self): # this is here as a safeguard against accidentally using _sorted_args @@ -1460,6 +1649,7 @@ raise AttributeError('Atoms have no args. It might be necessary' ' to make a check for Atoms in the calling code.') + def _aresame(a, b): """Return True if a and b are structurally the same, else False. @@ -1468,7 +1658,7 @@ To SymPy, 2.0 == 2: - >>> from sympy import S, Symbol, cos, sin + >>> from sympy import S >>> 2.0 == S(2) True @@ -1488,6 +1678,7 @@ else: return True + def _atomic(e): """Return atom-like quantities as far as substitution is concerned: Derivatives, Functions and Symbols. Don't @@ -1528,6 +1719,7 @@ atoms.add(p) return atoms + class preorder_traversal(object): """ Do a pre-order traversal of a tree. @@ -1545,9 +1737,12 @@ ========== node : sympy expression The expression to traverse. - key : (default None) sort key - The key used to sort args of Basic objects. When None, args of Basic - objects are processed in arbitrary order. + keys : (default None) sort key(s) + The key(s) used to sort args of Basic objects. When None, args of Basic + objects are processed in arbitrary order. If key is defined, it will + be passed along to ordered() as the only key(s) to use to sort the + arguments; if ``key`` is simply True then the default keys of ordered + will be used. Yields ====== @@ -1556,43 +1751,45 @@ Examples ======== + >>> from sympy import symbols - >>> from sympy import symbols, default_sort_key >>> from sympy.core.basic import preorder_traversal >>> x, y, z = symbols('x y z') The nodes are returned in the order that they are encountered unless key - is given. + is given; simply passing key=True will guarantee that the traversal is + unique. - >>> list(preorder_traversal((x + y)*z, key=None)) # doctest: +SKIP + >>> list(preorder_traversal((x + y)*z, keys=None)) # doctest: +SKIP [z*(x + y), z, x + y, y, x] - >>> list(preorder_traversal((x + y)*z, key=default_sort_key)) + >>> list(preorder_traversal((x + y)*z, keys=True)) [z*(x + y), z, x + y, x, y] """ - def __init__(self, node, key=None): + def __init__(self, node, keys=None): self._skip_flag = False - self._pt = self._preorder_traversal(node, key) + self._pt = self._preorder_traversal(node, keys) - def _preorder_traversal(self, node, key): + def _preorder_traversal(self, node, keys): yield node if self._skip_flag: self._skip_flag = False return if isinstance(node, Basic): args = node.args - if key: - args = list(args) - args.sort(key=key) + if keys: + if keys != True: + args = ordered(args, keys, default=False) + else: + args = ordered(args) for arg in args: - for subtree in self._preorder_traversal(arg, key): + for subtree in self._preorder_traversal(arg, keys): yield subtree elif iterable(node): for item in node: - for subtree in self._preorder_traversal(item, key): + for subtree in self._preorder_traversal(item, keys): yield subtree - def skip(self): """ Skip yielding current node's (last yielded node's) subtrees. @@ -1619,6 +1816,7 @@ def __iter__(self): return self + def _make_find_query(query): """Convert the argument of Basic.find() into a callable""" try: diff -Nru python3-sympy-0.7.2/sympy/core/cache.py python3-sympy-0.7.3/sympy/core/cache.py --- python3-sympy-0.7.2/sympy/core/cache.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/core/cache.py 2013-07-13 17:53:32.000000000 +0000 @@ -8,6 +8,7 @@ from sympy.core.decorators import wraps + def print_cache(): """print cache content""" @@ -32,6 +33,7 @@ for k, v in kv.items(): print(' %s :\t%s' % (k, v)) + def clear_cache(): """clear cache content""" for item, cache in CACHE: @@ -43,9 +45,11 @@ ######################################## + def __cacheit_nocache(func): return func + def __cacheit(func): """caching decorator. @@ -89,6 +93,7 @@ return r return wrapper + def __cacheit_debug(func): """cacheit + code to check cache consistency""" cfunc = __cacheit(func) @@ -96,7 +101,7 @@ @wraps(func) def wrapper(*args, **kw_args): # always call function itself and compare it with cached version - r1 = func (*args, **kw_args) + r1 = func(*args, **kw_args) r2 = cfunc(*args, **kw_args) # try to see if the result is immutable @@ -116,6 +121,7 @@ return r1 return wrapper + def _getenv(key, default=None): from os import getenv return getenv(key, default) @@ -124,10 +130,11 @@ USE_CACHE = _getenv('SYMPY_USE_CACHE', 'yes').lower() if USE_CACHE == 'no': - cacheit = __cacheit_nocache + cacheit = __cacheit_nocache elif USE_CACHE == 'yes': - cacheit = __cacheit + cacheit = __cacheit elif USE_CACHE == 'debug': - cacheit = __cacheit_debug # a lot slower + cacheit = __cacheit_debug # a lot slower else: - raise RuntimeError('unrecognized value for SYMPY_USE_CACHE: %s' % USE_CACHE) + raise RuntimeError( + 'unrecognized value for SYMPY_USE_CACHE: %s' % USE_CACHE) diff -Nru python3-sympy-0.7.2/sympy/core/compatibility.py python3-sympy-0.7.3/sympy/core/compatibility.py --- python3-sympy-0.7.2/sympy/core/compatibility.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/core/compatibility.py 2013-07-13 17:53:32.000000000 +0000 @@ -4,20 +4,25 @@ here for easy import. """ + + from collections import defaultdict +from sympy.external import import_module + # These are in here because telling if something is an iterable just by calling # hasattr(obj, "__iter__") behaves differently in Python 2 and Python 3. In # particular, hasattr(str, "__iter__") is False in Python 2 and True in Python 3. # I think putting them here also makes it easier to use them in the core. + def iterable(i, exclude=(str, dict)): """ - Return a boolean indicating whether i is an iterable in the sympy sense. + Return a boolean indicating whether ``i`` is SymPy iterable. - When sympy is working with iterables, it is almost always assuming + When SymPy is working with iterables, it is almost always assuming that the iterable is not a string or a mapping, so those are excluded - by default. If you want a pure python definition, make exclude=None. To + by default. If you want a pure Python definition, make exclude=None. To exclude multiple items, pass them as a tuple. See also: is_sequence @@ -55,9 +60,10 @@ return not isinstance(i, exclude) return True + def is_sequence(i, include=None): """ - Return a boolean indicating whether i is a sequence in the sympy + Return a boolean indicating whether ``i`` is a sequence in the SymPy sense. If anything that fails the test below should be included as being a sequence for your application, set 'include' to that object's type; multiple types should be passed as a tuple of types. @@ -103,6 +109,7 @@ callable = callable except NameError: import collections + def callable(obj): return isinstance(obj, collections.Callable) @@ -111,6 +118,7 @@ except ImportError: reduce = reduce + def cmp_to_key(mycmp): """ Convert a cmp= function into a key= function @@ -120,16 +128,22 @@ class K(object): def __init__(self, obj, *args): self.obj = obj + def __lt__(self, other): return mycmp(self.obj, other.obj) < 0 + def __gt__(self, other): return mycmp(self.obj, other.obj) > 0 + def __eq__(self, other): return mycmp(self.obj, other.obj) == 0 + def __le__(self, other): return mycmp(self.obj, other.obj) <= 0 + def __ge__(self, other): return mycmp(self.obj, other.obj) >= 0 + def __ne__(self, other): return mycmp(self.obj, other.obj) != 0 return K @@ -138,18 +152,18 @@ import builtins cmp = builtins.cmp except AttributeError: - def cmp(a,b): + def cmp(a, b): return (a > b) - (a < b) try: from itertools import product -except ImportError: # Python 2.5 - def product(*args, **kwds): +except ImportError: # Python 2.5 + def product(*args, **kwargs): """ Cartesian product of input iterables. Equivalent to nested for-loops in a generator expression. For example, - product(A, B) returns the same as ((x,y) for x in A for y in B). + cartes(A, B) returns the same as ((x,y) for x in A for y in B). The nested loops cycle like an odometer with the rightmost element advancing on every iteration. This pattern creates a lexicographic @@ -163,22 +177,26 @@ Examples ======== - >>> from sympy.core.compatibility import product - >>> [''.join(p) for p in list(product('ABC', 'xy'))] + >>> from sympy.utilities.iterables import cartes + >>> [''.join(p) for p in list(cartes('ABC', 'xy'))] ['Ax', 'Ay', 'Bx', 'By', 'Cx', 'Cy'] - >>> list(product(list(range(2)), repeat=2)) + >>> list(cartes(list(range(2)), repeat=2)) [(0, 0), (0, 1), (1, 0), (1, 1)] + + See Also + ======== + variations """ - pools = list(map(tuple, args)) * kwds.get('repeat', 1) + pools = list(map(tuple, args)) * kwargs.get('repeat', 1) result = [[]] for pool in pools: - result = [x+[y] for x in result for y in pool] + result = [x + [y] for x in result for y in pool] for prod in result: yield tuple(prod) try: from itertools import permutations -except ImportError: # Python 2.5 +except ImportError: # Python 2.5 def permutations(iterable, r=None): """ Return successive r length permutations of elements in the iterable. @@ -208,13 +226,13 @@ if r > n: return indices = list(range(n)) - cycles = list(range(n, n-r, -1)) + cycles = list(range(n, n - r, -1)) yield tuple(pool[i] for i in indices[:r]) while n: for i in reversed(list(range(r))): cycles[i] -= 1 if cycles[i] == 0: - indices[i:] = indices[i+1:] + indices[i:i+1] + indices[i:] = indices[i + 1:] + indices[i:i + 1] cycles[i] = n - i else: j = cycles[i] @@ -226,7 +244,7 @@ try: from itertools import combinations, combinations_with_replacement -except ImportError: # < python 2.6 +except ImportError: # < python 2.6 def combinations(iterable, r): """ Return r length subsequences of elements from the input iterable. @@ -263,8 +281,8 @@ else: return indices[i] += 1 - for j in range(i+1, r): - indices[j] = indices[j-1] + 1 + for j in range(i + 1, r): + indices[j] = indices[j - 1] + 1 yield tuple(pool[i] for i in indices) def combinations_with_replacement(iterable, r): @@ -303,6 +321,7 @@ indices[i:] = [indices[i] + 1] * (r - i) yield tuple(pool[i] for i in indices) + def set_intersection(*sets): """Return the intersection of all the given sets. @@ -324,6 +343,7 @@ rv &= s return rv + def set_union(*sets): """Return the union of all the given sets. @@ -340,18 +360,124 @@ rv |= s return rv + + +try: + from collections import namedtuple +except ImportError: + # code from http://code.activestate.com/recipes/500261-named-tuples/ + # PSF license + # code is Copyright 2007-2013 Raymond Hettinger + from operator import itemgetter as _itemgetter + from keyword import iskeyword as _iskeyword + import sys as _sys + + # For some reason, doctest will test namedtuple's docstring if we simply + # have a def namedtuple() here + def _namedtuple(typename, field_names, verbose=False, rename=False): + if isinstance(field_names, str): + field_names = field_names.replace(',', ' ').split() + field_names = tuple(map(str, field_names)) + if rename: + names = list(field_names) + seen = set() + for i, name in enumerate(names): + if (not min(c.isalnum() or c=='_' for c in name) or _iskeyword(name) + or not name or name[0].isdigit() or name.startswith('_') + or name in seen): + names[i] = '_%d' % i + seen.add(name) + field_names = tuple(names) + for name in (typename,) + field_names: + if not min(c.isalnum() or c=='_' for c in name): + raise ValueError('Type names and field names can only contain' + ' alphanumeric characters and underscores: %r' % name) + if _iskeyword(name): + raise ValueError('Type names and field names cannot be a' + ' keyword: %r' % name) + if name[0].isdigit(): + raise ValueError('Type names and field names cannot start' + ' with a number: %r' % name) + seen_names = set() + for name in field_names: + if name.startswith('_') and not rename: + raise ValueError('Field names cannot start with an' + ' underscore: %r' % name) + if name in seen_names: + raise ValueError('Encountered duplicate field name: %r' % name) + seen_names.add(name) + + # Create and fill-in the class template + numfields = len(field_names) + argtxt = repr(field_names).replace("'", "")[1:-1] + reprtxt = ', '.join('%s=%%r' % name for name in field_names) + template = '''class %(typename)s(tuple): + '%(typename)s(%(argtxt)s)' \n + __slots__ = () \n + _fields = %(field_names)r \n + def __new__(_cls, %(argtxt)s): + return _tuple.__new__(_cls, (%(argtxt)s)) \n + @classmethod + def _make(cls, iterable, new=tuple.__new__, len=len): + 'Make a new %(typename)s object from a sequence or iterable' + result = new(cls, iterable) + if len(result) != %(numfields)d: + raise TypeError('Expected %(numfields)d arguments, got %%d' %% len(result)) + return result \n + def __repr__(self): + return '%(typename)s(%(reprtxt)s)' %% self \n + def _asdict(self): + 'Return a new dict which maps field names to their values' + return dict(zip(self._fields, self)) \n + def _replace(_self, **kwds): + 'Return a new %(typename)s object replacing specified fields with new values' + result = _self._make(map(kwds.pop, %(field_names)r, _self)) + if kwds: + raise ValueError('Got unexpected field names: %%r' %% kwds.keys()) + return result \n + def __getnewargs__(self): + return tuple(self) \n\n''' % locals() + for i, name in enumerate(field_names): + template += ' %s = _property(_itemgetter(%d))\n' % (name, i) + if verbose: + print(template) + + # Execute the template string in a temporary namespace + namespace = dict(_itemgetter=_itemgetter, __name__='namedtuple_%s' % typename, + _property=property, _tuple=tuple) + try: + exec(template, namespace) + except SyntaxError as e: + raise SyntaxError(e.message + ':\n' + template) + result = namespace[typename] + + # For pickling to work, the __module__ variable needs to be set to the frame + # where the named tuple is created. Bypass this step in enviroments where + # sys._getframe is not defined (Jython for example) or sys._getframe is not + # defined for arguments greater than 0 (IronPython). + try: + result.__module__ = _sys._getframe(1).f_globals.get('__name__', '__main__') + except (AttributeError, ValueError): + pass + + return result + + namedtuple = _namedtuple + try: bin = bin -except NameError: # Python 2.5 +except NameError: # Python 2.5 def bin(x): """ bin(number) -> string Stringifies an int or long in base 2. """ - if x < 0: return '-' + bin(-x) + if x < 0: + return '-' + bin(-x) out = [] - if x == 0: out.append('0') + if x == 0: + out.append('0') while x > 0: out.append('01'[x & 1]) x >>= 1 @@ -360,7 +486,7 @@ try: next = next -except NameError: # Python 2.5 +except NameError: # Python 2.5 def next(*args): """ next(iterator[, default]) @@ -378,6 +504,42 @@ else: raise TypeError('Expected 1 or 2 arguments, got %s' % len(args)) +try: + from builtins import bin +except ImportError: # Python 2.5 + _hexDict = { + '0': '0000', '1': '0001', '2': '0010', '3': '0011', '4': '0100', '5': '0101', + '6': '0110', '7': '0111', '8': '1000', '9': '1001', 'a': '1010', 'b': '1011', + 'c': '1100', 'd': '1101', 'e': '1110', 'f': '1111', 'L': ''} + + def bin(n): + """Return the equivalent to Python 2.6's bin function. + + Examples + ======== + + >>> from sympy.core.compatibility import bin + >>> bin(-123) + '-0b1111011' + >>> bin(0) # this is the only time a 0 will be to the right of 'b' + '0b0' + + See Also + ======== + sympy.physics.quantum.shor.arr + + Modified from http://code.activestate.com/recipes/576847/ + """ + # ========================================================= + # create hex of int, remove '0x'. now for each hex char, + # look up binary string, append in list and join at the end. + # ========================================================= + if n < 0: + return '-%s' % bin(-n) + return '0b%s' % (''.join([_hexDict[hstr] for hstr in hex(n)[2:].lower() + ]).lstrip('0') or '0') + + def as_int(n): """ Convert the argument to a builtin integer. @@ -402,41 +564,373 @@ ValueError: ... is not an integer """ - result = int(n) - if result != n: + try: + result = int(n) + if result != n: + raise TypeError + except TypeError: raise ValueError('%s is not an integer' % n) return result -def quick_sort(seq, quick=True): - """Sort by hash and break ties with default_sort_key (default) - or entirely by default_sort_key if ``quick`` is False. - - When sorting for consistency between systems, ``quick`` should be - False; if sorting is just needed to give consistent orderings during - a given session ``quick`` can be True. - >>> from sympy.core.compatibility import quick_sort +def default_sort_key(item, order=None): + """Return a key that can be used for sorting. + + The key has the structure: + + (class_key, (len(args), args), exponent.sort_key(), coefficient) + + This key is supplied by the sort_key routine of Basic objects when + ``item`` is a Basic object or an object (other than a string) that + sympifies to a Basic object. Otherwise, this function produces the + key. + + The ``order`` argument is passed along to the sort_key routine and is + used to determine how the terms *within* an expression are ordered. + (See examples below) ``order`` options are: 'lex', 'grlex', 'grevlex', + and reversed values of the same (e.g. 'rev-lex'). The default order + value is None (which translates to 'lex'). + + Examples + ======== + + >>> from sympy import S, I, default_sort_key + >>> from sympy.core.function import UndefinedFunction >>> from sympy.abc import x - For PYTHONHASHSEED=3923375334 the x came first; for - PYTHONHASHSEED=158315900 the x came last (on a 32-bit system). + The following are eqivalent ways of getting the key for an object: - >>> quick_sort([x, 1, 3]) in [(1, 3, x), (x, 1, 3)] + >>> x.sort_key() == default_sort_key(x) True + + Here are some examples of the key that is produced: + + >>> default_sort_key(UndefinedFunction('f')) + ((0, 0, 'UndefinedFunction'), (1, ('f',)), ((1, 0, 'Number'), + (0, ()), (), 1), 1) + >>> default_sort_key('1') + ((0, 0, 'str'), (1, ('1',)), ((1, 0, 'Number'), (0, ()), (), 1), 1) + >>> default_sort_key(S.One) + ((1, 0, 'Number'), (0, ()), (), 1) + >>> default_sort_key(2) + ((1, 0, 'Number'), (0, ()), (), 2) + + + While sort_key is a method only defined for SymPy objects, + default_sort_key will accept anything as an argument so it is + more robust as a sorting key. For the following, using key= + lambda i: i.sort_key() would fail because 2 doesn't have a sort_key + method; that's why default_sort_key is used. Note, that it also + handles sympification of non-string items likes ints: + + >>> a = [2, I, -I] + >>> sorted(a, key=default_sort_key) + [2, -I, I] + + The returned key can be used anywhere that a key can be specified for + a function, e.g. sort, min, max, etc...: + + >>> a.sort(key=default_sort_key); a[0] + 2 + >>> min(a, key=default_sort_key) + 2 + + Note + ---- + + The key returned is useful for getting items into a canonical order + that will be the same across platforms. It is not directly useful for + sorting lists of expressions: + + >>> a, b = x, 1/x + + Since ``a`` has only 1 term, its value of sort_key is unaffected by + ``order``: + + >>> a.sort_key() == a.sort_key('rev-lex') + True + + If ``a`` and ``b`` are combined then the key will differ because there + are terms that can be ordered: + + >>> eq = a + b + >>> eq.sort_key() == eq.sort_key('rev-lex') + False + >>> eq.as_ordered_terms() + [x, 1/x] + >>> eq.as_ordered_terms('rev-lex') + [1/x, x] + + But since the keys for each of these terms are independent of ``order``'s + value, they don't sort differently when they appear separately in a list: + + >>> sorted(eq.args, key=default_sort_key) + [1/x, x] + >>> sorted(eq.args, key=lambda i: default_sort_key(i, order='rev-lex')) + [1/x, x] + + The order of terms obtained when using these keys is the order that would + be obtained if those terms were *factors* in a product. + + See Also + ======== + + sympy.core.expr.as_ordered_factors, sympy.core.expr.as_ordered_terms + """ - from sympy.utilities.iterables import default_sort_key - if not quick: - seq = list(seq) - seq.sort(key=default_sort_key) + from sympy.core import S, Basic + from sympy.core.sympify import sympify, SympifyError + from sympy.core.compatibility import iterable + + if isinstance(item, Basic): + return item.sort_key(order=order) + + if iterable(item, exclude=str): + if isinstance(item, dict): + args = list(item.items()) + unordered = True + elif isinstance(item, set): + args = item + unordered = True + else: + # e.g. tuple, list + args = list(item) + unordered = False + + args = [default_sort_key(arg, order=order) for arg in args] + + if unordered: + # e.g. dict, set + args = sorted(args) + + cls_index, args = 10, (len(args), tuple(args)) + else: + if not isinstance(item, str): + try: + item = sympify(item) + except SympifyError: + # e.g. lambda x: x + pass + else: + if isinstance(item, Basic): + # e.g int -> Integer + return default_sort_key(item) + # e.g. UndefinedFunction + + # e.g. str + cls_index, args = 0, (1, (str(item),)) + + return (cls_index, 0, item.__class__.__name__ + ), args, S.One.sort_key(), S.One + + +def _nodes(e): + """ + A helper for ordered() which returns the node count of ``e`` which + for Basic object is the number of Basic nodes in the expression tree + but for other object is 1 (unless the object is an iterable or dict + for which the sum of nodes is returned). + """ + from .basic import Basic + + if isinstance(e, Basic): + return e.count(Basic) + elif iterable(e): + return 1 + sum(_nodes(ei) for ei in e) + elif isinstance(e, dict): + return 1 + sum(_nodes(k) + _nodes(v) for k, v in e.items()) else: - d = defaultdict(list) + return 1 + + +def ordered(seq, keys=None, default=True, warn=False): + """Return an iterator of the seq where keys are used to break ties. + Two default keys will be applied after and provided unless ``default`` + is False. The two keys are _nodes and default_sort_key which will + place smaller expressions before larger ones (in terms of Basic nodes) + and where there are ties, they will be broken by the default_sort_key. + + If ``warn`` is True then an error will be raised if there were no + keys remaining to break ties. This can be used if it was expected that + there should be no ties. + + Examples + ======== + + >>> from sympy.utilities.iterables import ordered + >>> from sympy import count_ops + >>> from sympy.abc import x, y + + The count_ops is not sufficient to break ties in this list and the first + two items appear in their original order (i.e. the sorting is stable): + + >>> list(ordered([y + 2, x + 2, x**2 + y + 3], + ... count_ops, default=False, warn=False)) + ... + [y + 2, x + 2, x**2 + y + 3] + + The default_sort_key allows the tie to be broken: + + >>> list(ordered([y + 2, x + 2, x**2 + y + 3])) + ... + [x + 2, y + 2, x**2 + y + 3] + + Here, sequences are sorted by length, then sum: + + >>> seq, keys = [[[1, 2, 1], [0, 3, 1], [1, 1, 3], [2], [1]], [ + ... lambda x: len(x), + ... lambda x: sum(x)]] + ... + >>> list(ordered(seq, keys, default=False, warn=False)) + [[1], [2], [1, 2, 1], [0, 3, 1], [1, 1, 3]] + + If ``warn`` is True, an error will be raised if there were not + enough keys to break ties: + + >>> list(ordered(seq, keys, default=False, warn=True)) + Traceback (most recent call last): + ... + ValueError: not enough keys to break ties + + + Notes + ===== + + The decorated sort is one of the fastest ways to sort a sequence for + which special item comparison is desired: the sequence is decorated, + sorted on the basis of the decoration (e.g. making all letters lower + case) and then undecorated. If one wants to break ties for items that + have the same decorated value, a second key can be used. But if the + second key is expensive to compute then it is inefficient to decorate + all items with both keys: only those items having identical first key + values need to be decorated. This function applies keys successively + only when needed to break ties. By yielding an iterator, use of the + tie-breaker is delayed as long as possible. + + This function is best used in cases when use of the first key is + expected to be a good hashing function; if there are no unique hashes + from application of a key then that key should not have been used. The + exception, however, is that even if there are many collisions, if the + first group is small and one does not need to process all items in the + list then time will not be wasted sorting what one was not interested + in. For example, if one were looking for the minimum in a list and + there were several criteria used to define the sort order, then this + function would be good at returning that quickly if the first group + of candidates is small relative to the number of items being processed. + + """ + d = defaultdict(list) + if keys: + if not isinstance(keys, (list, tuple)): + keys = [keys] + keys = list(keys) + + f = keys.pop(0) for a in seq: - d[hash(a)].append(a) - seq = [] - for k in sorted(d.keys()): - if len(d[k]) > 1: - seq.extend(sorted(d[k], key=default_sort_key)) - else: - seq.extend(d[k]) - return tuple(seq) + d[f(a)].append(a) + else: + if not default: + raise ValueError('if default=False then keys must be provided') + d[None].extend(seq) + + for k in sorted(d.keys()): + if len(d[k]) > 1: + if keys: + d[k] = ordered(d[k], keys, default, warn) + elif default: + d[k] = ordered(d[k], (_nodes, default_sort_key,), + default=False, warn=warn) + elif warn: + raise ValueError('not enough keys to break ties') + for v in d[k]: + yield v + d.pop(k) + +try: + next = next +except NameError: + def next(x): + return x.__next__() + +# If HAS_GMPY is 0, no supported version of gmpy is available. Otherwise, +# HAS_GMPY contains the major version number of gmpy; i.e. 1 for gmpy, and +# 2 for gmpy2. + +# Versions of gmpy prior to 1.03 do not work correctly with int(largempz) +# For example, int(gmpy.mpz(2**256)) would raise OverflowError. +# See issue 1881. + +# Minimum version of gmpy changed to 1.13 to allow a single code base to also +# work with gmpy2. + +def _getenv(key, default=None): + from os import getenv + return getenv(key, default) + +GROUND_TYPES = _getenv('SYMPY_GROUND_TYPES', 'auto').lower() + +HAS_GMPY = 0 + +if GROUND_TYPES != 'python': + + # Don't try to import gmpy2 if ground types is set to gmpy1. This is + # primarily intended for testing. + + if GROUND_TYPES != 'gmpy1': + gmpy = import_module('gmpy2', min_module_version='2.0.0', + module_version_attr='version', module_version_attr_call_args=()) + if gmpy: + HAS_GMPY = 2 + else: + GROUND_TYPES = 'gmpy' + + if not HAS_GMPY: + gmpy = import_module('gmpy', min_module_version='1.13', + module_version_attr='version', module_version_attr_call_args=()) + if gmpy: + HAS_GMPY = 1 + +if GROUND_TYPES == 'auto': + if HAS_GMPY: + GROUND_TYPES = 'gmpy' + else: + GROUND_TYPES = 'python' + +if GROUND_TYPES == 'gmpy' and not HAS_GMPY: + from warnings import warn + warn("gmpy library is not installed, switching to 'python' ground types") + GROUND_TYPES = 'python' + +# SYMPY_INTS is a tuple containing the base types for valid integer types. + +import sys + +if sys.version_info[0] == 2: + SYMPY_INTS = (int, int) +else: + SYMPY_INTS = (int,) + +if GROUND_TYPES == 'gmpy': + SYMPY_INTS += (type(gmpy.mpz(0)),) + +# check_output() is new in python 2.7 +import os +try: + from subprocess import CalledProcessError + try: + from subprocess import check_output + except ImportError: + from subprocess import check_call + def check_output(*args, **kwargs): + with open(os.devnull, 'w') as fh: + kwargs['stdout'] = fh + try: + return check_call(*args, **kwargs) + except CalledProcessError as e: + e.output = ("program output is not available for " + "python 2.5.x and 2.6.x") + raise e +except ImportError: + # running on platform like App Engine, no subprocess at all + pass diff -Nru python3-sympy-0.7.2/sympy/core/containers.py python3-sympy-0.7.3/sympy/core/containers.py --- python3-sympy-0.7.2/sympy/core/containers.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/core/containers.py 2013-07-13 17:53:32.000000000 +0000 @@ -10,6 +10,7 @@ from sympy.core.sympify import sympify, converter from sympy.utilities.iterables import iterable + class Tuple(Basic): """ Wrapper around the builtin tuple object @@ -33,10 +34,10 @@ obj = Basic.__new__(cls, *args, **assumptions) return obj - def __getitem__(self,i): - if isinstance(i,slice): + def __getitem__(self, i): + if isinstance(i, slice): indices = i.indices(len(self)) - return Tuple(*[self.args[i] for i in range(*indices)]) + return Tuple(*[self.args[j] for j in range(*indices)]) return self.args[i] def __len__(self): @@ -88,6 +89,7 @@ converter[tuple] = lambda tup: Tuple(*tup) + def tuple_wrapper(method): """ Decorator that converts any tuple in the function arguments into a Tuple. @@ -96,7 +98,7 @@ call a function with regular tuples in the argument, and the wrapper will convert them to Tuples before handing them to the function. - >>> from sympy.core.containers import tuple_wrapper, Tuple + >>> from sympy.core.containers import tuple_wrapper >>> def f(*args): ... return args >>> g = tuple_wrapper(f) @@ -108,7 +110,7 @@ """ def wrap_tuples(*args, **kw_args): - newargs=[] + newargs = [] for arg in args: if type(arg) is tuple: newargs.append(Tuple(*arg)) @@ -117,6 +119,7 @@ return method(*newargs, **kw_args) return wrap_tuples + class Dict(Basic): """ Wrapper around the builtin dict object @@ -127,7 +130,6 @@ cannot be changed afterwards. Otherwise it behaves identically to the Python dict. - >>> from sympy import S >>> from sympy.core.containers import Dict >>> D = Dict({1: 'one', 2: 'two'}) @@ -151,7 +153,7 @@ """ def __new__(cls, *args): - if len(args)==1 and ((args[0].__class__ is dict) or + if len(args) == 1 and ((args[0].__class__ is dict) or (args[0].__class__ is Dict)): items = [Tuple(k, v) for k, v in list(args[0].items())] elif iterable(args) and all(len(arg) == 2 for arg in args): @@ -161,7 +163,7 @@ elements = frozenset(items) obj = Basic.__new__(cls, elements) obj.elements = elements - obj._dict = dict(items) # In case Tuple decides it wants to sympify + obj._dict = dict(items) # In case Tuple decides it wants to sympify return obj def __getitem__(self, key): diff -Nru python3-sympy-0.7.2/sympy/core/core.py python3-sympy-0.7.3/sympy/core/core.py --- python3-sympy-0.7.2/sympy/core/core.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/core/core.py 2013-07-13 17:53:32.000000000 +0000 @@ -6,33 +6,33 @@ # FIXME this is *so* irrelevant and outdated! ordering_of_classes = [ # singleton numbers - 'Zero', 'One','Half','Infinity','NaN','NegativeOne','NegativeInfinity', + 'Zero', 'One', 'Half', 'Infinity', 'NaN', 'NegativeOne', 'NegativeInfinity', # numbers - 'Integer','Rational','Float', + 'Integer', 'Rational', 'Float', # singleton symbols - 'Exp1','Pi','ImaginaryUnit', + 'Exp1', 'Pi', 'ImaginaryUnit', # symbols - 'Symbol','Wild','Temporary', + 'Symbol', 'Wild', 'Temporary', # arithmetic operations 'Pow', 'Mul', 'Add', # function values - 'Derivative','Integral', + 'Derivative', 'Integral', # defined singleton functions - 'Abs','Sign','Sqrt', + 'Abs', 'Sign', 'Sqrt', 'Floor', 'Ceiling', 'Re', 'Im', 'Arg', 'Conjugate', - 'Exp','Log', - 'Sin','Cos','Tan','Cot','ASin','ACos','ATan','ACot', - 'Sinh','Cosh','Tanh','Coth','ASinh','ACosh','ATanh','ACoth', - 'RisingFactorial','FallingFactorial', - 'factorial','binomial', - 'Gamma','LowerGamma','UpperGamma','PolyGamma', + 'Exp', 'Log', + 'Sin', 'Cos', 'Tan', 'Cot', 'ASin', 'ACos', 'ATan', 'ACot', + 'Sinh', 'Cosh', 'Tanh', 'Coth', 'ASinh', 'ACosh', 'ATanh', 'ACoth', + 'RisingFactorial', 'FallingFactorial', + 'factorial', 'binomial', + 'Gamma', 'LowerGamma', 'UpperGamma', 'PolyGamma', 'Erf', # special polynomials - 'Chebyshev','Chebyshev2', + 'Chebyshev', 'Chebyshev2', # undefined functions - 'Function','WildFunction', + 'Function', 'WildFunction', # anonymous functions 'Lambda', # Landau O symbol @@ -40,7 +40,7 @@ # relational operations 'Equality', 'Unequality', 'StrictGreaterThan', 'StrictLessThan', 'GreaterThan', 'LessThan', - ] +] class BasicType(type): @@ -68,6 +68,7 @@ #A set containing all sympy class objects, kept in sync with C all_classes = set() + class ClassRegistry(Registry): """ Namespace for SymPy classes @@ -94,6 +95,7 @@ C = ClassRegistry() + class BasicMeta(BasicType): def __init__(cls, *args, **kws): diff -Nru python3-sympy-0.7.2/sympy/core/coreerrors.py python3-sympy-0.7.3/sympy/core/coreerrors.py --- python3-sympy-0.7.2/sympy/core/coreerrors.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/core/coreerrors.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,7 +1,9 @@ """Definitions of common exceptions for :mod:`sympy.core` module. """ + class BaseCoreError(Exception): """Base class for core related exceptions. """ + class NonCommutativeExpression(BaseCoreError): """Raised when expression didn't have commutative property. """ diff -Nru python3-sympy-0.7.2/sympy/core/decorators.py python3-sympy-0.7.3/sympy/core/decorators.py --- python3-sympy-0.7.2/sympy/core/decorators.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/core/decorators.py 2013-07-13 17:53:32.000000000 +0000 @@ -8,6 +8,7 @@ from functools import wraps from .sympify import SympifyError, sympify + def deprecated(**decorator_kwargs): """This is a decorator which can be used to mark functions as deprecated. It will result in a warning being emitted @@ -23,6 +24,7 @@ return new_func return deprecated_decorator + def _sympifyit(arg, retval=None): """decorator to smartly _sympify function arguments @@ -44,6 +46,7 @@ return deco + def __sympifyit(func, arg, retval=None): """decorator to _sympify `arg` argument for function `func` @@ -64,7 +67,11 @@ @wraps(func) def __sympifyit_wrapper(a, b): try: - return func(a, sympify(b, strict=True)) + # If an external class has _op_priority, it knows how to deal + # with sympy objects. Otherwise, it must be converted. + if not hasattr(b, '_op_priority'): + b = sympify(b, strict=True) + return func(a, b) except SympifyError: return retval diff -Nru python3-sympy-0.7.2/sympy/core/evalf.py python3-sympy-0.7.3/sympy/core/evalf.py --- python3-sympy-0.7.2/sympy/core/evalf.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/core/evalf.py 2013-07-13 17:53:32.000000000 +0000 @@ -2,22 +2,23 @@ Adaptive numerical evaluation of SymPy expressions, using mpmath for mathematical functions. """ +import math + import sympy.mpmath.libmp as libmp from sympy.mpmath import make_mpc, make_mpf, mp, mpc, mpf, nsum, quadts, quadosc from sympy.mpmath import inf as mpmath_inf -from sympy.mpmath.libmp import (bitcount, from_int, from_man_exp, - from_rational, fhalf, fnone, fone, fzero, mpf_abs, mpf_add, mpf_atan, - mpf_atan2, mpf_cmp, mpf_cos, mpf_e, mpf_exp, mpf_log, mpf_lt, mpf_mul, - mpf_neg, mpf_pi, mpf_pow, mpf_pow_int, mpf_shift, mpf_sin, mpf_sqrt, - normalize, round_nearest, to_int, to_str) +from sympy.mpmath.libmp import (from_int, from_man_exp, from_rational, fhalf, + fnan, fnone, fone, fzero, mpf_abs, mpf_add, + mpf_atan, mpf_atan2, mpf_cmp, mpf_cos, mpf_e, mpf_exp, mpf_log, mpf_lt, + mpf_mul, mpf_neg, mpf_pi, mpf_pow, mpf_pow_int, mpf_shift, mpf_sin, + mpf_sqrt, normalize, round_nearest, to_int, to_str) +from sympy.mpmath.libmp import bitcount as mpmath_bitcount from sympy.mpmath.libmp.backend import MPZ from sympy.mpmath.libmp.libmpc import _infs_nan from sympy.mpmath.libmp.libmpf import dps_to_prec - from sympy.mpmath.libmp.gammazeta import mpf_bernoulli -import math - +from sympy.core.compatibility import SYMPY_INTS from .sympify import sympify from .core import C from .singleton import S @@ -26,6 +27,9 @@ LG10 = math.log(10, 2) rnd = round_nearest +def bitcount(n): + return mpmath_bitcount(int(n)) + # Used in a few places as placeholder values to denote exponents and # precision levels, e.g. of exact numbers. Must be careful to avoid # passing these to mpmath functions or returning them in final results. @@ -35,6 +39,7 @@ # ~= 100 digits. Real men set this to INF. DEFAULT_MAXPREC = 333 + class PrecisionExhausted(ArithmeticError): pass @@ -66,6 +71,7 @@ """ + def fastlog(x): """Fast approximation of log2(x) for an mpf value tuple x. @@ -98,6 +104,7 @@ return MINUS_INF return x[2] + x[3] + def pure_complex(v): """Return a and b if v matches a + I*b where b is not zero and a and b are Numbers, else None. @@ -116,6 +123,7 @@ if i is S.ImaginaryUnit: return h, c + def scaled_zero(mag, sign=1): """Return an mpf representing a power of two with magnitude ``mag`` and -1 for precision. Or, if ``mag`` is a scaled_zero tuple, then just @@ -143,7 +151,7 @@ """ if type(mag) is tuple and len(mag) == 4 and iszero(mag, scaled=True): return (mag[0][0],) + mag[1:] - elif type(mag) is int: + elif isinstance(mag, SYMPY_INTS): if sign not in [-1, 1]: raise ValueError('sign must be +/-1') rv, p = mpf_shift(fone, mag), -1 @@ -153,11 +161,13 @@ else: raise ValueError('scaled zero expects int or scaled_zero tuple.') + def iszero(mpf, scaled=False): if not scaled: return not mpf or not mpf[1] and not mpf[-1] return mpf and type(mpf[0]) is list and mpf[1] == mpf[-1] == 1 + def complex_accuracy(result): """ Returns relative accuracy of a complex number with given accuracies @@ -180,12 +190,13 @@ return im_acc re_size = fastlog(re) im_size = fastlog(im) - absolute_error = max(re_size-re_acc, im_size-im_acc) + absolute_error = max(re_size - re_acc, im_size - im_acc) relative_error = absolute_error - max(re_size, im_size) return -relative_error + def get_abs(expr, prec, options): - re, im, re_acc, im_acc = evalf(expr, prec+2, options) + re, im, re_acc, im_acc = evalf(expr, prec + 2, options) if not re: re, re_acc, im, im_acc = im, im_acc, re, re_acc if im: @@ -195,6 +206,7 @@ else: return None, None, None, None + def get_complex_part(expr, no, prec, options): """no = 0 for real part, no = 1 for imaginary part""" workprec = prec @@ -208,15 +220,19 @@ workprec += max(30, 2**i) i += 1 + def evalf_abs(expr, prec, options): return get_abs(expr.args[0], prec, options) + def evalf_re(expr, prec, options): return get_complex_part(expr.args[0], 0, prec, options) + def evalf_im(expr, prec, options): return get_complex_part(expr.args[0], 1, prec, options) + def finalize_complex(re, im, prec): if re == fzero and im == fzero: raise ValueError("got complex zero with unknown accuracy") @@ -235,25 +251,27 @@ re_acc = prec + min(-(size_im - size_re), 0) return re, im, re_acc, im_acc + def chop_parts(value, prec): """ Chop off tiny real or complex parts. """ re, im, re_acc, im_acc = value # Method 1: chop based on absolute value - if re and re not in _infs_nan and (fastlog(re) < -prec+4): + if re and re not in _infs_nan and (fastlog(re) < -prec + 4): re, re_acc = None, None - if im and im not in _infs_nan and (fastlog(im) < -prec+4): + if im and im not in _infs_nan and (fastlog(im) < -prec + 4): im, im_acc = None, None # Method 2: chop if inaccurate and relatively small if re and im: delta = fastlog(re) - fastlog(im) - if re_acc < 2 and (delta - re_acc <= -prec+4): + if re_acc < 2 and (delta - re_acc <= -prec + 4): re, re_acc = None, None - if im_acc < 2 and (delta - im_acc >= prec-4): + if im_acc < 2 and (delta - im_acc >= prec - 4): im, im_acc = None, None return re, im, re_acc, im_acc + def check_target(expr, result, prec): a = complex_accuracy(result) if a < prec: @@ -261,6 +279,7 @@ "from zero. Try simplifying the input, using chop=True, or providing " "a higher maxn for evalf" % (expr)) + def get_integer_part(expr, no, options, return_ints=False): """ With no = 1, computes ceiling(expr) @@ -276,11 +295,11 @@ # We now know the size, so we can calculate how much extra precision # (if any) is needed to get within the nearest integer if ire and iim: - gap = max(fastlog(ire)-ire_acc, fastlog(iim)-iim_acc) + gap = max(fastlog(ire) - ire_acc, fastlog(iim) - iim_acc) elif ire: - gap = fastlog(ire)-ire_acc + gap = fastlog(ire) - ire_acc elif iim: - gap = fastlog(iim)-iim_acc + gap = fastlog(iim) - iim_acc else: # ... or maybe the expression was exactly zero return None, None, None, None @@ -289,7 +308,7 @@ if gap >= -margin: ire, iim, ire_acc, iim_acc = \ - evalf(expr, margin+assumed_size+gap, options) + evalf(expr, margin + assumed_size + gap, options) # We can now easily find the nearest integer, but to find floor/ceil, we # must also calculate whether the difference to the nearest integer is @@ -319,9 +338,11 @@ return int(to_int(re or fzero)), int(to_int(im or fzero)) return re, im, re_acc, im_acc + def evalf_ceiling(expr, prec, options): return get_integer_part(expr.args[0], 1, options) + def evalf_floor(expr, prec, options): return get_integer_part(expr.args[0], -1, options) @@ -331,6 +352,7 @@ # # #----------------------------------------------------------------------------# + def add_terms(terms, prec, target_prec): """ Helper for evalf_add. Adds a list of (mpfval, accuracy) terms. @@ -353,13 +375,28 @@ XXX explain why this is needed and why one can't just loop using mpf_add """ + from sympy.core.core import C + terms = [t for t in terms if not iszero(t)] if not terms: return None, None elif len(terms) == 1: return terms[0] + + # see if any argument is NaN or oo and thus warrants a special return + special = [] + for t in terms: + arg = C.Float._new(t[0], 1) + if arg is S.NaN or arg.is_unbounded: + special.append(arg) + if special: + from sympy.core.add import Add + rv = evalf(Add(*special), prec + 4, {}) + return rv[0], rv[2] + working_prec = 2*prec sum_man, sum_exp, absolute_error = 0, 0, MINUS_INF + for x, accuracy in terms: sign, man, exp, bc = x if sign: @@ -399,6 +436,7 @@ #print "returning", to_str(r[0],50), r[1] return r + def evalf_add(v, prec, options): res = pure_complex(v) if res: @@ -407,7 +445,6 @@ im, _, im_acc, _ = evalf(c, prec, options) return re, im, re_acc, im_acc - oldmaxprec = options.get('maxprec', DEFAULT_MAXPREC) i = 0 @@ -416,8 +453,10 @@ options['maxprec'] = min(oldmaxprec, 2*prec) terms = [evalf(arg, prec + 10, options) for arg in v.args] - re, re_acc = add_terms([a[0::2] for a in terms if a[0]], prec, target_prec) - im, im_acc = add_terms([a[1::2] for a in terms if a[1]], prec, target_prec) + re, re_acc = add_terms( + [a[0::2] for a in terms if a[0]], prec, target_prec) + im, im_acc = add_terms( + [a[1::2] for a in terms if a[1]], prec, target_prec) acc = complex_accuracy((re, im, re_acc, im_acc)) if acc >= target_prec: if options.get('verbose'): @@ -439,7 +478,10 @@ im = scaled_zero(im) return re, im, re_acc, im_acc + def evalf_mul(v, prec, options): + from sympy.core.core import C + res = pure_complex(v) if res: # the only pure complex that is a mul is h*I @@ -448,6 +490,20 @@ return None, im, None, im_acc args = list(v.args) + # see if any argument is NaN or oo and thus warrants a special return + special = [] + for arg in args: + arg = evalf(arg, prec, options) + if arg[0] is None: + continue + arg = C.Float._new(arg[0], 1) + if arg is S.NaN or arg.is_unbounded: + special.append(arg) + if special: + from sympy.core.mul import Mul + special = Mul(*special) + return evalf(special, prec + 4, {}) + # With guard digits, multiplication in the real case does not destroy # accuracy. This is also true in the complex case when considering the # total accuracy; however accuracy for the real or imaginary parts @@ -468,6 +524,7 @@ direction = 0 args.append(S.One) complex_factors = [] + for i, arg in enumerate(args): if i != last and pure_complex(arg): args[-1] = (args[-1]*arg).expand() @@ -536,6 +593,7 @@ re, im = mpf_neg(im), re return re, im, acc, acc + def evalf_pow(v, prec, options): target_prec = prec @@ -551,8 +609,8 @@ return fone, None, prec, None # Exponentiation by p magnifies relative error by |p|, so the # base must be evaluated with increased precision if p is large - prec += int(math.log(abs(p),2)) - re, im, re_acc, im_acc = evalf(base, prec+5, options) + prec += int(math.log(abs(p), 2)) + re, im, re_acc, im_acc = evalf(base, prec + 5, options) # Real to integer power if re and not im: return mpf_pow_int(re, p, target_prec), None, target_prec, None @@ -560,10 +618,14 @@ if im and not re: z = mpf_pow_int(im, p, target_prec) case = p % 4 - if case == 0: return z, None, target_prec, None - if case == 1: return None, z, None, target_prec - if case == 2: return mpf_neg(z), None, target_prec, None - if case == 3: return None, mpf_neg(z), None, target_prec + if case == 0: + return z, None, target_prec, None + if case == 1: + return None, z, None, target_prec + if case == 2: + return mpf_neg(z), None, target_prec, None + if case == 3: + return None, mpf_neg(z), None, target_prec # Zero raised to an integer power if not re: return None, None, None, None @@ -574,7 +636,7 @@ # Pure square root if exp is S.Half: - xre, xim, _, _ = evalf(base, prec+5, options) + xre, xim, _, _ = evalf(base, prec + 5, options) # General complex square root if xim: re, im = libmp.mpc_sqrt((xre or fzero, xim), prec) @@ -609,14 +671,15 @@ return finalize_complex(re, im, target_prec) return mpf_exp(yre, target_prec), None, target_prec, None - xre, xim, _, _= evalf(base, prec+5, options) + xre, xim, _, _ = evalf(base, prec + 5, options) # 0**y if not (xre or xim): return None, None, None, None # (real ** complex) or (complex ** complex) if yim: - re, im = libmp.mpc_pow((xre or fzero, xim or fzero), (yre or fzero, yim), + re, im = libmp.mpc_pow( + (xre or fzero, xim or fzero), (yre or fzero, yim), target_prec) return finalize_complex(re, im, target_prec) # complex ** real @@ -632,19 +695,16 @@ return mpf_pow(xre, yre, target_prec), None, target_prec, None - - #----------------------------------------------------------------------------# # # # Special functions # # # #----------------------------------------------------------------------------# - def evalf_trig(v, prec, options): """ - This function handles sin and cos of real arguments. + This function handles sin and cos of complex arguments. - TODO: should also handle tan and complex arguments. + TODO: should also handle tan of complex arguments. """ if v.func is C.cos: func = mpf_cos @@ -658,7 +718,9 @@ xprec = prec + 20 re, im, re_acc, im_acc = evalf(arg, xprec, options) if im: - raise NotImplementedError + if 'subs' in options: + v = v.subs(options['subs']) + return evalf(v._eval_evalf(prec), prec, options) if not re: if v.func is C.cos: return fone, None, prec, None @@ -688,7 +750,7 @@ if accuracy < prec: if options.get('verbose'): print("SIN/COS", accuracy, "wanted", prec, "gap", gap) - print(to_str(y,10)) + print(to_str(y, 10)) if xprec > options.get('maxprec', DEFAULT_MAXPREC): return y, None, accuracy, None xprec += gap @@ -697,14 +759,16 @@ else: return y, None, prec, None + def evalf_log(expr, prec, options): arg = expr.args[0] - workprec = prec+10 + workprec = prec + 10 xre, xim, xacc, _ = evalf(arg, workprec, options) if xim: # XXX: use get_abs etc instead - re = evalf_log(C.log(C.Abs(arg, evaluate=False), evaluate=False), prec, options) + re = evalf_log( + C.log(C.Abs(arg, evaluate=False), evaluate=False), prec, options) im = mpf_atan2(xim, xre or fzero, prec) return re[0], im, re[2], prec @@ -726,15 +790,17 @@ else: return re, None, re_acc, None + def evalf_atan(v, prec, options): arg = v.args[0] - xre, xim, reacc, imacc = evalf(arg, prec+5, options) + xre, xim, reacc, imacc = evalf(arg, prec + 5, options) if xre is xim is None: return (None,)*4 if xim: raise NotImplementedError return mpf_atan(xre, prec, rnd), None, prec, None + def evalf_subs(prec, subs): """ Change all Float entries in `subs` to have precision prec. """ newsubs = {} @@ -745,12 +811,13 @@ newsubs[a] = b return newsubs + def evalf_piecewise(expr, prec, options): if 'subs' in options: expr = expr.subs(evalf_subs(prec, options['subs'])) newopts = options.copy() del newopts['subs'] - if hasattr(expr,'func'): + if hasattr(expr, 'func'): return evalf(expr, prec, newopts) if type(expr) == float: return evalf(C.Float(expr), prec, newopts) @@ -760,6 +827,7 @@ # We still have undefined symbols raise NotImplementedError + def evalf_bernoulli(expr, prec, options): arg = expr.args[0] if not arg.is_Integer: @@ -776,6 +844,7 @@ # # #----------------------------------------------------------------------------# + def as_mpmath(x, prec, options): x = sympify(x) if isinstance(x, C.Zero): @@ -790,6 +859,7 @@ return mpc(re or fzero, im) return mpf(re) + def do_integral(expr, prec, options): func = expr.args[0] x, xlow, xhigh = expr.args[1] @@ -799,9 +869,9 @@ options['maxprec'] = min(oldmaxprec, 2*prec) try: - mp.prec = prec+5 - xlow = as_mpmath(xlow, prec+15, options) - xhigh = as_mpmath(xhigh, prec+15, options) + mp.prec = prec + 5 + xlow = as_mpmath(xlow, prec + 15, options) + xhigh = as_mpmath(xhigh, prec + 15, options) # Integration is like summation, and we can phone home from # the integrand function to update accuracy summation style @@ -814,7 +884,7 @@ max_imag_term = [MINUS_INF] def f(t): - re, im, re_acc, im_acc = evalf(func, mp.prec, {'subs':{x:t}}) + re, im, re_acc, im_acc = evalf(func, mp.prec, {'subs': {x: t}}) have_part[0] = re or have_part[0] have_part[1] = im or have_part[1] @@ -830,13 +900,13 @@ A = C.Wild('A', exclude=[x]) B = C.Wild('B', exclude=[x]) D = C.Wild('D') - m = func.match(C.cos(A*x+B)*D) + m = func.match(C.cos(A*x + B)*D) if not m: - m = func.match(C.sin(A*x+B)*D) + m = func.match(C.sin(A*x + B)*D) if not m: raise ValueError("An integrand of the form sin(A*x+B)*f(x) " "or cos(A*x+B)*f(x) is required for oscillatory quadrature") - period = as_mpmath(2*S.Pi/m[A], prec+15, options) + period = as_mpmath(2*S.Pi/m[A], prec + 15, options) result = quadosc(f, [xlow, xhigh], period=period) # XXX: quadosc does not do error detection yet quadrature_error = MINUS_INF @@ -851,27 +921,35 @@ if have_part[0]: re = result.real._mpf_ if re == fzero: - re, re_acc = scaled_zero(min(-prec, -max_real_term[0], -quadrature_error)) - re = scaled_zero(re) # handled ok in evalf_integral + re, re_acc = scaled_zero( + min(-prec, -max_real_term[0], -quadrature_error)) + re = scaled_zero(re) # handled ok in evalf_integral else: - re_acc = -max(max_real_term[0] - fastlog(re) - prec, quadrature_error) + re_acc = -max(max_real_term[0] - fastlog(re) - + prec, quadrature_error) else: re, re_acc = None, None if have_part[1]: im = result.imag._mpf_ if im == fzero: - im, im_acc = scaled_zero(min(-prec, -max_imag_term[0], -quadrature_error)) - im = scaled_zero(im) # handled ok in evalf_integral + im, im_acc = scaled_zero( + min(-prec, -max_imag_term[0], -quadrature_error)) + im = scaled_zero(im) # handled ok in evalf_integral else: - im_acc = -max(max_imag_term[0] - fastlog(im) - prec, quadrature_error) + im_acc = -max(max_imag_term[0] - fastlog(im) - + prec, quadrature_error) else: im, im_acc = None, None result = re, im, re_acc, im_acc return result + def evalf_integral(expr, prec, options): + limits = expr.limits + if len(limits) != 1 or len(limits[0]) != 3: + raise NotImplementedError workprec = prec i = 0 maxprec = options.get('maxprec', INF) @@ -885,6 +963,7 @@ workprec += prec - max(-2**i, accuracy) i += 1 + def check_convergence(numer, denom, n): """ Returns (h, g, p) where @@ -919,7 +998,8 @@ return rate, constant, 0 pc = npol.all_coeffs()[1] qc = dpol.all_coeffs()[1] - return rate, constant, (qc-pc)/dpol.LC() + return rate, constant, (qc - pc)/dpol.LC() + def hypsum(expr, n, start, prec): """ @@ -931,7 +1011,7 @@ from sympy import hypersimp, lambdify if start: - expr = expr.subs(n, n+start) + expr = expr.subs(n, n + start) hs = hypersimp(expr, n) if hs is None: raise NotImplementedError("a hypergeometric series is required") @@ -952,8 +1032,8 @@ s = term k = 1 while abs(term) > 5: - term *= MPZ(func1(k-1)) - term //= MPZ(func2(k-1)) + term *= MPZ(func1(k - 1)) + term //= MPZ(func2(k - 1)) s += term k += 1 return from_man_exp(s, -prec) @@ -973,8 +1053,8 @@ def summand(k, _term=[term]): if k: k = int(k) - _term[0] *= MPZ(func1(k-1)) - _term[0] //= MPZ(func2(k-1)) + _term[0] *= MPZ(func1(k - 1)) + _term[0] //= MPZ(func2(k - 1)) return make_mpf(from_man_exp(_term[0], -prec2)) orig = mp.prec @@ -985,13 +1065,13 @@ mp.prec = orig return v._mpf_ + def evalf_sum(expr, prec, options): func = expr.function limits = expr.limits - if len(limits) != 1 or not isinstance(limits[0], Tuple) or \ - len(limits[0]) != 3: + if len(limits) != 1 or len(limits[0]) != 3: raise NotImplementedError - prec2 = prec+10 + prec2 = prec + 10 try: n, a, b = limits[0] if b != S.Infinity or a != int(a): @@ -1007,7 +1087,7 @@ eps = C.Float(2.0)**(-prec) for i in range(1, 5): m = n = 2**i * prec - s, err = expr.euler_maclaurin(m=m, n=n, eps=eps, \ + s, err = expr.euler_maclaurin(m=m, n=n, eps=eps, eval_integral=False) err = err.evalf() if err <= eps: @@ -1015,7 +1095,7 @@ err = fastlog(evalf(abs(err), 20, options)[0]) try: re, im, re_acc, im_acc = evalf(s, prec2, options) - except TypeError: # issue 3174 + except TypeError: # issue 3174 # when should it try subs if they are in options? raise NotImplementedError if re_acc is None: @@ -1050,48 +1130,51 @@ evalf_table = None + def _create_evalf_table(): global evalf_table evalf_table = { - C.Symbol : evalf_symbol, - C.Dummy : evalf_symbol, - C.Float : lambda x, prec, options: (x._mpf_, None, prec, None), - C.Rational : lambda x, prec, options: (from_rational(x.p, x.q, prec), None, prec, None), - C.Integer : lambda x, prec, options: (from_int(x.p, prec), None, prec, None), - C.Zero : lambda x, prec, options: (None, None, prec, None), - C.One : lambda x, prec, options: (fone, None, prec, None), - C.Half : lambda x, prec, options: (fhalf, None, prec, None), - C.Pi : lambda x, prec, options: (mpf_pi(prec), None, prec, None), - C.Exp1 : lambda x, prec, options: (mpf_e(prec), None, prec, None), - C.ImaginaryUnit : lambda x, prec, options: (None, fone, None, prec), - C.NegativeOne : lambda x, prec, options: (fnone, None, prec, None), + C.Symbol: evalf_symbol, + C.Dummy: evalf_symbol, + C.Float: lambda x, prec, options: (x._mpf_, None, prec, None), + C.Rational: lambda x, prec, options: (from_rational(x.p, x.q, prec), None, prec, None), + C.Integer: lambda x, prec, options: (from_int(x.p, prec), None, prec, None), + C.Zero: lambda x, prec, options: (None, None, prec, None), + C.One: lambda x, prec, options: (fone, None, prec, None), + C.Half: lambda x, prec, options: (fhalf, None, prec, None), + C.Pi: lambda x, prec, options: (mpf_pi(prec), None, prec, None), + C.Exp1: lambda x, prec, options: (mpf_e(prec), None, prec, None), + C.ImaginaryUnit: lambda x, prec, options: (None, fone, None, prec), + C.NegativeOne: lambda x, prec, options: (fnone, None, prec, None), + C.NaN : lambda x, prec, options: (fnan, None, prec, None), - C.exp : lambda x, prec, options: evalf_pow(C.Pow(S.Exp1, x.args[0], + C.exp: lambda x, prec, options: evalf_pow(C.Pow(S.Exp1, x.args[0], evaluate=False), prec, options), - C.cos : evalf_trig, - C.sin : evalf_trig, + C.cos: evalf_trig, + C.sin: evalf_trig, - C.Add : evalf_add, - C.Mul : evalf_mul, - C.Pow : evalf_pow, - - C.log : evalf_log, - C.atan : evalf_atan, - C.Abs : evalf_abs, - - C.re : evalf_re, - C.im : evalf_im, - C.floor : evalf_floor, - C.ceiling : evalf_ceiling, - - C.Integral : evalf_integral, - C.Sum : evalf_sum, - C.Piecewise : evalf_piecewise, + C.Add: evalf_add, + C.Mul: evalf_mul, + C.Pow: evalf_pow, + + C.log: evalf_log, + C.atan: evalf_atan, + C.Abs: evalf_abs, + + C.re: evalf_re, + C.im: evalf_im, + C.floor: evalf_floor, + C.ceiling: evalf_ceiling, + + C.Integral: evalf_integral, + C.Sum: evalf_sum, + C.Piecewise: evalf_piecewise, - C.bernoulli : evalf_bernoulli, + C.bernoulli: evalf_bernoulli, } + def evalf(x, prec, options): from sympy import re as re_, im as im_ try: @@ -1123,7 +1206,7 @@ if options.get("verbose"): print("### input", x) print("### output", to_str(r[0] or fzero, 50)) - print("### raw", r)#r[0], r[2] + print("### raw", r) # r[0], r[2] print() chop = options.get('chop', False) if chop: @@ -1189,14 +1272,14 @@ if not evalf_table: _create_evalf_table() prec = dps_to_prec(n) - options = {'maxprec': max(prec,int(maxn*LG10)), 'chop': chop, + options = {'maxprec': max(prec, int(maxn*LG10)), 'chop': chop, 'strict': strict, 'verbose': verbose} if subs is not None: options['subs'] = subs if quad is not None: options['quad'] = quad try: - result = evalf(self, prec+4, options) + result = evalf(self, prec + 4, options) except NotImplementedError: # Fall back to the ordinary evalf v = self._eval_evalf(prec) @@ -1240,6 +1323,8 @@ errmsg = "cannot convert to mpmath number" if allow_ints and self.is_Integer: return self.p + if hasattr(self, '_as_mpf_val'): + return make_mpf(self._as_mpf_val(prec)) try: re, im, _, _ = evalf(self, prec, {}) if im: @@ -1283,7 +1368,7 @@ Examples ======== - >>> from sympy import Sum, Symbol, oo, N + >>> from sympy import Sum, oo, N >>> from sympy.abc import k >>> Sum(1/k**k, (k, 1, oo)) Sum(k**(-k), (k, 1, oo)) diff -Nru python3-sympy-0.7.2/sympy/core/expr.py python3-sympy-0.7.3/sympy/core/expr.py --- python3-sympy-0.7.2/sympy/core/expr.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/core/expr.py 2013-07-13 17:53:32.000000000 +0000 @@ -5,16 +5,15 @@ from .evalf import EvalfMixin, pure_complex from .decorators import _sympifyit, call_highest_priority from .cache import cacheit -from .compatibility import reduce, as_int +from .compatibility import reduce, as_int, default_sort_key from sympy.mpmath.libmp import mpf_log, prec_to_dps -from sympy.utilities.misc import default_sort_key from collections import defaultdict -from math import log10, ceil from inspect import getmro import collections from functools import reduce + class Expr(Basic, EvalfMixin): __slots__ = [] @@ -69,15 +68,29 @@ else: args = expr.args - args = tuple([ default_sort_key(arg, order=order) for arg in args ]) + args = tuple( + [ default_sort_key(arg, order=order) for arg in args ]) args = (len(args), tuple(args)) exp = exp.sort_key(order=order) return expr.class_key(), args, exp, coeff - def __call__(self, *args): - # (x+Lambda(y, 2*y))(z) -> x+2*z + def rcall(self, *args): + """Apply on the argument recursively through the expression tree. + + This method is used to simulate a common abuse of notation for + operators. For instance in SymPy the the following will not work: + + ``(x+Lambda(y, 2*y))(z) == x+2*z``, + + however you can use + + >>> from sympy import Lambda + >>> from sympy.abc import x,y,z + >>> (x + Lambda(y, 2*y)).rcall(z) + x + 2*z + """ return Expr._recursive_call(self, args) @staticmethod @@ -88,21 +101,20 @@ return cls != Expr if isinstance(expr_to_call, collections.Callable) and the_call_method_is_overridden(expr_to_call): - if isinstance(expr_to_call, C.Symbol):# XXX When you call a Symbol it is + if isinstance(expr_to_call, C.Symbol): # XXX When you call a Symbol it is return expr_to_call # transformed into an UndefFunction else: return expr_to_call(*on_args) elif expr_to_call.args: - args = [Expr._recursive_call(sub, on_args) for sub in expr_to_call.args] + args = [Expr._recursive_call( + sub, on_args) for sub in expr_to_call.args] return type(expr_to_call)(*args) else: return expr_to_call - # *************** # * Arithmetics * # *************** - # Expr and its sublcasses use _op_priority to determine which object # passed to a binary special method (__mul__, etc.) will handle the # operation. In general, the 'call_highest_priority' decorator will choose @@ -117,8 +129,10 @@ def __pos__(self): return self + def __neg__(self): return Mul(S.NegativeOne, self) + def __abs__(self): return C.Abs(self) @@ -126,6 +140,7 @@ @call_highest_priority('__radd__') def __add__(self, other): return Add(self, other) + @_sympifyit('other', NotImplemented) @call_highest_priority('__add__') def __radd__(self, other): @@ -135,6 +150,7 @@ @call_highest_priority('__rsub__') def __sub__(self, other): return Add(self, -other) + @_sympifyit('other', NotImplemented) @call_highest_priority('__sub__') def __rsub__(self, other): @@ -144,6 +160,7 @@ @call_highest_priority('__rmul__') def __mul__(self, other): return Mul(self, other) + @_sympifyit('other', NotImplemented) @call_highest_priority('__mul__') def __rmul__(self, other): @@ -153,6 +170,7 @@ @call_highest_priority('__rpow__') def __pow__(self, other): return Pow(self, other) + @_sympifyit('other', NotImplemented) @call_highest_priority('__pow__') def __rpow__(self, other): @@ -162,6 +180,7 @@ @call_highest_priority('__rdiv__') def __div__(self, other): return Mul(self, Pow(other, S.NegativeOne)) + @_sympifyit('other', NotImplemented) @call_highest_priority('__div__') def __rdiv__(self, other): @@ -174,6 +193,7 @@ @call_highest_priority('__rmod__') def __mod__(self, other): return Mod(self, other) + @_sympifyit('other', NotImplemented) @call_highest_priority('__mod__') def __rmod__(self, other): @@ -210,6 +230,7 @@ if diff_sign != isign: i -= isign return i + __long__ = __int__ def __float__(self): # Don't bother testing if it's a number; if it's not this is going @@ -230,28 +251,32 @@ @_sympifyit('other', False) # sympy > other def __ge__(self, other): dif = self - other - if dif.is_nonnegative != dif.is_negative: + if dif.is_nonnegative is not None and \ + dif.is_nonnegative is not dif.is_negative: return dif.is_nonnegative return C.GreaterThan(self, other) - @_sympifyit('other', False) # sympy > other + @_sympifyit('other', False) # sympy > other def __le__(self, other): dif = self - other - if dif.is_nonpositive != dif.is_positive: + if dif.is_nonpositive is not None and \ + dif.is_nonpositive is not dif.is_positive: return dif.is_nonpositive return C.LessThan(self, other) @_sympifyit('other', False) # sympy > other def __gt__(self, other): dif = self - other - if dif.is_positive != dif.is_nonpositive: + if dif.is_positive is not None and \ + dif.is_positive is not dif.is_nonpositive: return dif.is_positive return C.StrictGreaterThan(self, other) - @_sympifyit('other', False) # sympy > other + @_sympifyit('other', False) # sympy > other def __lt__(self, other): dif = self - other - if dif.is_negative != dif.is_nonnegative: + if dif.is_negative is not None and \ + dif.is_negative is not dif.is_nonnegative: return dif.is_negative return C.StrictLessThan(self, other) @@ -263,27 +288,32 @@ re, im = x._mpc_ re = C.Float._new(re, prec) im = C.Float._new(im, prec)*S.ImaginaryUnit - return re+im + return re + im else: raise TypeError("expected mpmath number (mpf or mpc)") @property def is_number(self): - """Returns True if 'self' is a number. + """Returns True if 'self' has no free symbols. + It will be faster than `if not self.free_symbols`, however, since + `is_number` will fail as soon as it hits a free symbol. - >>> from sympy import log, Integral - >>> from sympy.abc import x, y + Examples + ======== - >>> x.is_number - False - >>> (2*x).is_number - False - >>> (2 + log(2)).is_number - True - >>> (2 + Integral(2, x)).is_number - False - >>> (2 + Integral(2, (x, 1, 2))).is_number - True + >>> from sympy import log, Integral + >>> from sympy.abc import x + + >>> x.is_number + False + >>> (2*x).is_number + False + >>> (2 + log(2)).is_number + True + >>> (2 + Integral(2, x)).is_number + False + >>> (2 + Integral(2, (x, 1, 2))).is_number + True """ if not self.args: @@ -347,7 +377,6 @@ # e.g. exp_polar(2*I*pi) doesn't evaluate but is_number is True return None - if nmag._prec == 1: # increase the precision up to the default maximum # precision to see if we can get any significance @@ -445,8 +474,8 @@ >>> one = cos(x)**2 + sin(x)**2 >>> one.is_constant() True - >>> ((one - 1)**(x + 1)).is_constant() # could be 0 or 1 - False + >>> ((one - 1)**(x + 1)).is_constant() in (True, False) # could be 0 or 1 + True """ simplify = flags.get('simplify', True) @@ -539,6 +568,10 @@ used to return True or False. """ + from sympy.simplify.simplify import nsimplify, simplify + from sympy.solvers.solvers import solve + from sympy.polys.polyerrors import NotAlgebraic + from sympy.polys.numberfields import minimal_polynomial other = sympify(other) if self == other: @@ -548,27 +581,76 @@ # don't worry about doing simplification steps one at a time # because if the expression ever goes to 0 then the subsequent # simplification steps that are done will be very fast. - diff = (self - other).as_content_primitive()[1] - diff = factor_terms(diff.simplify(), radical=True) + diff = factor_terms((self - other).simplify(), radical=True) if not diff: return True - if all(f.is_Atom for m in Add.make_args(diff) - for f in Mul.make_args(m)): + if not diff.has(Add): # if there is no expanding to be done after simplifying # then this can't be a zero return False constant = diff.is_constant(simplify=False, failing_number=True) - if constant is False or \ - not diff.free_symbols and not diff.is_number: + + if constant is False: return False - elif constant is True: + + if constant is None and (diff.free_symbols or not diff.is_number): + # e.g. unless the right simplification is done, a symbolic + # zero is possible (see expression of issue 3730: without + # simplification constant will be None). + return + + if constant is True: ndiff = diff._random() if ndiff: return False + # sometimes we can use a simplified result to give a clue as to + # what the expression should be; if the expression is *not* zero + # then we should have been able to compute that and so now + # we can just consider the cases where the approximation appears + # to be zero -- we try to prove it via minimal_polynomial. + if diff.is_number: + approx = diff.nsimplify() + if not approx: + # try to prove via self-consistency + surds = [s for s in diff.atoms(Pow) if s.args[0].is_Integer] + # it seems to work better to try big ones first + surds.sort(key=lambda x: -x.args[0]) + for s in surds: + try: + # simplify is False here -- this expression has already + # been identified as being hard to identify as zero; + # we will handle the checking ourselves using nsimplify + # to see if we are in the right ballpark or not and if so + # *then* the simplification will be attempted. + sol = solve(diff, s, check=False, simplify=False) + if sol: + if s in sol: + return True + if any(nsimplify(si, [s]) == s and simplify(si) == s + for si in sol): + return True + except NotImplementedError: + pass + + # try to prove with minimal_polynomial but know when + # *not* to use this or else it can take a long time. + # Pernici noted the following: + # >>> q = -73*sqrt(3) + 1 + 128*sqrt(5) + 1315*sqrt(2) + # >>> p = expand(q**3)**Rational(1, 3) + # >>> minimal_polynomial(p - q) # hangs for at least 15 minutes + if False: # change False to condition that assures non-hang + try: + mp = minimal_polynomial(diff) + if mp.is_Symbol: + return True + return False + except NotAlgebraic: + pass + # diff has not simplified to zero; constant is either None, True # or the number with significance (prec != 1) that was randomly # calculated twice as the same value. @@ -586,9 +668,11 @@ try: # check to see that we can get a value n2 = self._eval_evalf(2) + if n2 is None: + raise AttributeError + if n2._prec == 1: # no significance + raise AttributeError except AttributeError: - n2 = None - if n2 is None: return None n, i = self.evalf(2).as_real_imag() if not i.is_Number or not n.is_Number: @@ -608,9 +692,11 @@ try: # check to see that we can get a value n2 = self._eval_evalf(2) + if n2 is None: + raise AttributeError + if n2._prec == 1: # no significance + raise AttributeError except AttributeError: - n2 = None - if n2 is None: return None n, i = self.evalf(2).as_real_imag() if not i.is_Number or not n.is_Number: @@ -643,7 +729,7 @@ A = 0 else: A = self.subs(x, a) - if A is S.NaN: + if A.has(S.NaN): A = limit(self, x, a) if A is S.NaN: return A @@ -652,7 +738,7 @@ B = 0 else: B = self.subs(x, b) - if B is S.NaN: + if B.has(S.NaN): B = limit(self, x, b) return B - A @@ -751,7 +837,7 @@ ======== >>> from sympy import sin, cos - >>> from sympy.abc import x, y + >>> from sympy.abc import x >>> (sin(x)**2*cos(x) + sin(x)**2 + 1).as_ordered_terms() [sin(x)**2*cos(x), sin(x)**2, 1] @@ -772,7 +858,7 @@ _order.append((term, repr)) ordered = sorted(_terms, key=key, reverse=True) \ - + sorted(_order, key=key, reverse=True) + + sorted(_order, key=key, reverse=True) if data: return ordered, gens @@ -834,7 +920,6 @@ return result, gens - def removeO(self): """Removes the additive O(..) symbol if there is one""" return self @@ -871,7 +956,7 @@ return S.One if o.is_Pow: return o.args[1] - if o.is_Mul: # x**n*log(x)**n or x**n/log(x)**n + if o.is_Mul: # x**n*log(x)**n or x**n/log(x)**n for oi in o.args: if oi.is_Symbol: return S.One @@ -887,10 +972,10 @@ def count_ops(self, visual=None): """wrapper for count_ops that returns the operation count.""" - from sympy import count_ops + from .function import count_ops return count_ops(self, visual) - def args_cnc(self, cset=False, warn=True): + def args_cnc(self, cset=False, warn=True, split_1=True): """Return [commutative factors, non-commutative factors] of self. self is treated as a Mul and the ordering of the factors is maintained. @@ -899,7 +984,7 @@ then an error will be raised unless it is explicitly supressed by setting ``warn`` to False. - Note: -1 is always separated from a Number. + Note: -1 is always separated from a Number unless split_1 is False. >>> from sympy import symbols, oo >>> A, B = symbols('A B', commutative=0) @@ -910,6 +995,8 @@ [[-1, 2.5, x], []] >>> (-2*x*A*B*y).args_cnc() [[-1, 2, x, y], [A, B]] + >>> (-2*x*A*B*y).args_cnc(split_1=False) + [[-2, x, y], [A, B]] >>> (-2*x*y).args_cnc(cset=True) [set([-1, 2, x, y]), []] @@ -934,10 +1021,10 @@ c = args nc = [] - if c and ( + if c and split_1 and ( c[0].is_Number and c[0].is_negative and - c[0] != S.NegativeOne): + c[0] is not S.NegativeOne): c[:1] = [S.NegativeOne, -c[0]] if cset: @@ -950,9 +1037,8 @@ def coeff(self, x, n=1, right=False): """ - Returns the coefficient from the term containing "x**n" or None if - there is no such term. If ``n`` is zero then all terms independent of - x will be returned. + Returns the coefficient from the term(s) containing ``x**n`` or None. If ``n`` + is zero then all terms independent of ``x`` will be returned. When x is noncommutative, the coeff to the left (default) or right of x can be returned. The keyword 'right' is ignored when x is commutative. @@ -960,7 +1046,12 @@ See Also ======== - as_coefficient + as_coefficient: separate the expression into a coefficient and factor + as_coeff_Add: separate the additive constant from an expression + as_coeff_Mul: separate the multiplicative constant from an expression + as_independent: separate x-dependent terms/factors from others + sympy.polys.polytools.coeff_monomial: efficiently find the single coefficient of a monomial in Poly + sympy.polys.polytools.nth: like coeff_monomial but powers of monomial terms are used Examples ======== @@ -1052,13 +1143,6 @@ >>> (n*m + x*m*n).coeff(m*n, right=1) 1 - See Also - ======== - - as_coeff_Add: a method to separate the additive constant from an expression - as_coeff_Mul: a method to separate the multiplicative constant from an expression - as_independent: a method to separate x dependent terms/factors from others - """ x = sympify(x) if not isinstance(x, Basic): @@ -1168,7 +1252,7 @@ return S.Zero elif co: return Add(*co) - else: # both nc + else: # both nc xargs, nx = x.args_cnc(cset=True) # find the parts that pass the commutative terms for a in args: @@ -1187,7 +1271,7 @@ if not right: return Mul(Add(*[Mul(*r) for r, c in co]), Mul(*co[0][1][:ii])) else: - return Mul(*co[0][1][ii+len(nx):]) + return Mul(*co[0][1][ii + len(nx):]) beg = reduce(incommon, (n[1] for n in co)) if beg: ii = find(beg, nx, right) @@ -1202,14 +1286,15 @@ else: m = ii + len(nx) return Add(*[Mul(*(list(r) + n[m:])) for r, n in co]) - end = list(reversed(reduce(incommon, (list(reversed(n[1])) for n in co)))) + end = list(reversed( + reduce(incommon, (list(reversed(n[1])) for n in co)))) if end: ii = find(end, nx, right) if ii is not None: if not right: - return Add(*[Mul(*(list(r) + n[:-len(end)+ii])) for r, n in co]) + return Add(*[Mul(*(list(r) + n[:-len(end) + ii])) for r, n in co]) else: - return Mul(*end[ii+len(nx):]) + return Mul(*end[ii + len(nx):]) # look for single match hit = None for i, (r, n) in enumerate(co): @@ -1225,7 +1310,7 @@ if not right: return Mul(*(list(r) + n[:ii])) else: - return Mul(*n[ii+len(nx):]) + return Mul(*n[ii + len(nx):]) return S.Zero @@ -1256,16 +1341,11 @@ of 'expr' and 'expr'-free coefficient. If such separation is not possible it will return None. - See Also - ======== - - coeff - Examples ======== - >>> from sympy import E, pi, sin, I, symbols - >>> from sympy.abc import x, y + >>> from sympy import E, pi, sin, I, Poly + >>> from sympy.abc import x >>> E.as_coefficient(E) 1 @@ -1273,9 +1353,31 @@ 2 >>> (2*sin(E)*E).as_coefficient(E) + Two terms have E in them so a sum is returned. (If one were + desiring the coefficient of the term exactly matching E then + the constant from the returned expression could be selected. + Or, for greater precision, a method of Poly can be used to + indicate the desired term from which the coefficient is + desired.) + >>> (2*E + x*E).as_coefficient(E) x + 2 + >>> _.args[0] # just want the exact match + 2 + >>> p = Poly(2*E + x*E); p + Poly(x*E + 2*E, x, E, domain='ZZ') + >>> p.coeff_monomial(E) + 2 + >>> p.nth(0,1) + 2 + + Since the following cannot be written as a product containing + E as a factor, None is returned. (If the coefficient ``2*x`` is + desired then the ``coeff`` method should be used.) + >>> (2*E*x + x).as_coefficient(E) + >>> (2*E*x + x).coeff(E) + 2*x >>> (E*(x + 1) + x).as_coefficient(E) @@ -1283,6 +1385,17 @@ 2 >>> (2*I).as_coefficient(pi*I) + See Also + ======== + + coeff: return sum of terms have a given factor + as_coeff_Add: separate the additive constant from an expression + as_coeff_Mul: separate the multiplicative constant from an expression + as_independent: separate x-dependent terms/factors from others + sympy.polys.polytools.coeff_monomial: efficiently find the single coefficient of a monomial in Poly + sympy.polys.polytools.nth: like coeff_monomial but powers of monomial terms are used + + """ r = self.extract_multiplicatively(expr) @@ -1423,10 +1536,11 @@ sym = set() other = [] for d in deps: - if isinstance(d, C.Symbol): # Symbol.is_Symbol is True + if isinstance(d, C.Symbol): # Symbol.is_Symbol is True sym.add(d) else: other.append(d) + def has(e): """return the standard has() if there are no literal symbols, else check to see that symbol-deps are in the free symbols.""" @@ -1440,7 +1554,7 @@ else: want = Mul if (want is not func or - func is not Add and func is not Mul): + func is not Add and func is not Mul): if has(self): return (want.identity, self) else: @@ -1454,10 +1568,10 @@ d = sift(args, lambda x: has(x)) depend = d[True] indep = d[False] - if func is Add: # all terms were treated as commutative + if func is Add: # all terms were treated as commutative return (Add(*indep), Add(*depend)) - else: # handle noncommutative by stopping at first dependent term + else: # handle noncommutative by stopping at first dependent term for i, n in enumerate(nc): if has(n): depend.extend(nc[i:]) @@ -1534,26 +1648,6 @@ # a -> b ** e return self, S.One - def as_coeff_terms(self, *deps): - """ - This method is deprecated. Use .as_coeff_mul() instead. - """ - from sympy.utilities.exceptions import SymPyDeprecationWarning - SymPyDeprecationWarning(feature="as_coeff_terms()", - useinstead="as_coeff_mul()", issue=3377, - deprecated_since_version="0.7.0").warn() - return self.as_coeff_mul(*deps) - - def as_coeff_factors(self, *deps): - """ - This method is deprecated. Use .as_coeff_add() instead. - """ - from sympy.utilities.exceptions import SymPyDeprecationWarning - SymPyDeprecationWarning(feature="as_coeff_factors()", - useinstead="as_coeff_add()", issue=3377, - deprecated_since_version="0.7.0").warn() - return self.as_coeff_add(*deps) - def as_coeff_mul(self, *deps): """Return the tuple (c, args) where self is written as a Mul, ``m``. @@ -1754,7 +1848,7 @@ if c.is_Mul: a, b = c.as_two_terms() x = self.extract_multiplicatively(a) - if x != None: + if x is not None: return x.extract_multiplicatively(b) quotient = self / c if self.is_Number: @@ -1805,7 +1899,7 @@ newargs = [] for arg in self.args: newarg = arg.extract_multiplicatively(c) - if newarg != None: + if newarg is not None: newargs.append(newarg) else: return None @@ -1820,11 +1914,11 @@ elif self.is_Pow: if c.is_Pow and c.base == self.base: new_exp = self.exp.extract_additively(c.exp) - if new_exp != None: + if new_exp is not None: return self.base ** (new_exp) elif c == self.base: new_exp = self.exp.extract_additively(1) - if new_exp != None: + if new_exp is not None: return self.base ** (new_exp) def extract_additively(self, c): @@ -1833,7 +1927,6 @@ Examples ======== - >>> from sympy import S >>> from sympy.abc import x, y >>> e = 2*x + 3 >>> e.extract_additively(x + 1) @@ -1876,7 +1969,7 @@ diff = co - c # XXX should we match types? i.e should 3 - .1 succeed? if (co > 0 and diff > 0 and diff < co or - co < 0 and diff < 0 and diff > co): + co < 0 and diff < 0 and diff > co): return diff return None @@ -1945,8 +2038,9 @@ """ negative_self = -self - self_has_minus = (self.extract_multiplicatively(-1) != None) - negative_self_has_minus = ((negative_self).extract_multiplicatively(-1) != None) + self_has_minus = (self.extract_multiplicatively(-1) is not None) + negative_self_has_minus = ( + (negative_self).extract_multiplicatively(-1) is not None) if self_has_minus != negative_self_has_minus: return self_has_minus else: @@ -2056,7 +2150,7 @@ returns False for expressions that are "polynomials" with symbolic exponents. Thus, you should be able to apply polynomial algorithms to expressions for which this returns True, and Poly(expr, \*syms) should - work only if and only if expr.is_polynomial(\*syms) returns True. The + work if and only if expr.is_polynomial(\*syms) returns True. The polynomial does not have to be in expanded form. If no symbols are given, all free symbols in the expression will be used. @@ -2159,7 +2253,7 @@ result in an expression that does not appear to be a rational function to become one. - >>> from sympy import sqrt, factor, cancel + >>> from sympy import sqrt, factor >>> y = Symbol('y', positive=True) >>> a = sqrt(y**2 + 2*y + 1)/y >>> a.is_rational_function(y) @@ -2169,7 +2263,7 @@ >>> factor(a).is_rational_function(y) True - See also is_rational_function(). + See also is_algebraic_expr(). """ if syms: @@ -2183,6 +2277,64 @@ else: return self._eval_is_rational_function(syms) + def _eval_is_algebraic_expr(self, syms): + if self.free_symbols.intersection(syms) == set([]): + return True + return False + + def is_algebraic_expr(self, *syms): + ''' + This tests whether a given expression is algebraic or not, in the + given symbols, syms. When syms is not given, all free symbols + will be used. The rational function does not have to be in expanded + or in any kind of canonical form. + + This function returns False for expressions that are "algebraic + expressions" with symbolic exponents. This is a simple extension to the + is_rational_function, including rational exponentiation. + + Examples + ======== + + >>> from sympy import Symbol, sqrt + >>> x = Symbol('x') + >>> sqrt(1 + x).is_rational_function() + False + >>> sqrt(1 + x).is_algebraic_expr() + True + + This function does not attempt any nontrivial simplifications that may + result in an expression that does not appear to be an algebraic + expression to become one. + + >>> from sympy import sin, factor + >>> a = sqrt(sin(x)**2 + 2*sin(x) + 1)/(sin(x) + 1) + >>> a.is_algebraic_expr(x) + False + >>> factor(a).is_algebraic_expr() + True + + See Also + ======== + is_rational_function() + + References + ========== + + - http://en.wikipedia.org/wiki/Algebraic_expression + + ''' + if syms: + syms = set(map(sympify, syms)) + else: + syms = self.free_symbols + + if syms.intersection(self.free_symbols) == set([]): + # constant algebraic expression + return True + else: + return self._eval_is_algebraic_expr(syms) + ################################################################################### ##################### SERIES, LEADING TERM, LIMIT, ORDER METHODS ################## ################################################################################### @@ -2246,7 +2398,7 @@ >>> e.series(x, n=2) cos(exp(y)) - x*sin(exp(y)) + O(x**2) - If ``n=None`` then an iterator of the series terms will be returned. + If ``n=None`` then a generator of the series terms will be returned. >>> term=cos(x).series(n=None) >>> [next(term) for i in range(2)] @@ -2309,18 +2461,18 @@ rep2 = x rep2b = -x0 s = self.subs(x, rep).series(x, x0=0, n=n, dir='+') - if n is None: # lseries... + if n is None: # lseries... return (si.subs(x, rep2 + rep2b) for si in s) # nseries... o = s.getO() or S.Zero s = s.removeO() if o and x0: - rep2b = 0 # when O() can handle x0 != 0 this can be removed + rep2b = 0 # when O() can handle x0 != 0 this can be removed return s.subs(x, rep2 + rep2b) + o # from here on it's x0=0 and dir='+' handling - if n != None: # nseries handling + if n is not None: # nseries handling s1 = self._eval_nseries(x, n=n, logx=None) o = s1.getO() or S.Zero if o: @@ -2356,11 +2508,11 @@ o = S.Zero try: - return collect(s1,x) + o + return collect(s1, x) + o except NotImplementedError: return s1 + o - else: # lseries handling + else: # lseries handling def yield_lseries(s): """Return terms of lseries one at a time.""" for si in s: @@ -2461,10 +2613,10 @@ See also lseries(). """ - if x and not self.has(x): + if x and not x in self.free_symbols: return self - if x is None or x0 or dir != '+':#{see XPOS above} or (x.is_positive == x.is_negative == None): - assert logx == None + if x is None or x0 or dir != '+': # {see XPOS above} or (x.is_positive == x.is_negative == None): + assert logx is None return self.series(x, x0, n, dir) else: return self._eval_nseries(x, n=n, logx=logx) @@ -2603,7 +2755,7 @@ ################################################################################### def diff(self, *symbols, **assumptions): - new_symbols = list(map(sympify, symbols)) # e.g. x, 2, y, z + new_symbols = list(map(sympify, symbols)) # e.g. x, 2, y, z assumptions.setdefault("evaluate", True) return Derivative(self, *new_symbols, **assumptions) @@ -2628,6 +2780,7 @@ ``False`` otherwise. """ hit = False + cls = expr.__class__ # XXX: Hack to support non-Basic args # | # V @@ -2639,16 +2792,17 @@ sargs.append(arg) if hit: - expr = expr.func(*sargs) + expr = cls(*sargs) - if hasattr(expr, '_eval_expand_' + hint): - newexpr = getattr(expr, '_eval_expand_' + hint)(**hints) + if hasattr(expr, hint): + newexpr = getattr(expr, hint)(**hints) if newexpr != expr: return (newexpr, True) + return (expr, hit) @cacheit - def expand(self, deep=True, modulus=None, power_base=True, power_exp=True, \ + def expand(self, deep=True, modulus=None, power_base=True, power_exp=True, mul=True, log=True, multinomial=True, basic=True, **hints): """ Expand an expression using hints. @@ -2659,7 +2813,7 @@ """ from sympy.simplify.simplify import fraction - hints.update(power_base=power_base, power_exp=power_exp, mul=mul, \ + hints.update(power_base=power_base, power_exp=power_exp, mul=mul, log=log, multinomial=multinomial, basic=basic) expr = self @@ -2673,6 +2827,7 @@ elif hints.pop('numer', False): n, d = fraction(self) return n.expand(deep=deep, modulus=modulus, **hints)/d + # Although the hints are sorted here, an earlier hint may get applied # at a given node in the expression tree before another because of how # the hints are applied. e.g. expand(log(x*(y + z))) -> log(x*y + @@ -2698,13 +2853,29 @@ for hint in sorted(list(hints.keys()), key=_expand_hint_key): use_hint = hints[hint] if use_hint: + hint = '_eval_expand_' + hint expr, hit = Expr._expand_hint(expr, hint, deep=deep, **hints) + while True: + was = expr + if hints.get('multinomial', False): + expr, _ = Expr._expand_hint( + expr, '_eval_expand_multinomial', deep=deep, **hints) + if hints.get('mul', False): + expr, _ = Expr._expand_hint( + expr, '_eval_expand_mul', deep=deep, **hints) + if hints.get('log', False): + expr, _ = Expr._expand_hint( + expr, '_eval_expand_log', deep=deep, **hints) + if expr == was: + break + if modulus is not None: modulus = sympify(modulus) if not modulus.is_Integer or modulus <= 0: - raise ValueError("modulus must be a positive integer, got %s" % modulus) + raise ValueError( + "modulus must be a positive integer, got %s" % modulus) terms = [] @@ -2729,10 +2900,12 @@ from sympy.integrals import integrate return integrate(self, *args, **kwargs) - def simplify(self): + def simplify(self, ratio=1.7, measure=None): """See the simplify function in sympy.simplify""" from sympy.simplify import simplify - return simplify(self) + from sympy.core.function import count_ops + measure = measure or count_ops + return simplify(self, ratio, measure) def nsimplify(self, constants=[], tolerance=None, full=False): """See the nsimplify function in sympy.simplify""" @@ -2764,10 +2937,10 @@ from sympy.simplify import ratsimp return ratsimp(self) - def trigsimp(self, deep=False, recursive=False): + def trigsimp(self, **args): """See the trigsimp function in sympy.simplify""" from sympy.simplify import trigsimp - return trigsimp(self, deep, recursive) + return trigsimp(self, **args) def radsimp(self): """See the radsimp function in sympy.simplify""" @@ -2819,14 +2992,14 @@ 3. >>> pi.round(2) 3.14 - >>> (2*pi + E*I).round() #doctest: +SKIP + >>> (2*pi + E*I).round() 6. + 3.*I The round method has a chopping effect: >>> (2*pi + I/10).round() 6. - >>> (pi/10 + 2*I).round() #doctest: +SKIP + >>> (pi/10 + 2*I).round() 2.*I >>> (pi/10 + E*I).round(2) 0.31 + 2.72*I @@ -2849,8 +3022,6 @@ True """ - from sympy.functions.elementary.exponential import log - x = self if not x.is_number: raise TypeError('%s is not a number' % x) @@ -2868,8 +3039,8 @@ allow = digits_needed = mag_first_dig + p if dps is not None and allow > dps: allow = dps - mag = Pow(10, p) # magnitude needed to bring digit p to units place - x += 1/(2*mag) # add the half for rounding + mag = Pow(10, p) # magnitude needed to bring digit p to units place + x += 1/(2*mag) # add the half for rounding i10 = 10*mag*x.n((dps if dps is not None else digits_needed) + 1) rv = Integer(i10)//10 q = 1 @@ -2884,6 +3055,7 @@ else: return C.Float(rv, allow) + class AtomicExpr(Atom, Expr): """ A parent class for object which are both atoms and Exprs. @@ -2907,9 +3079,13 @@ def _eval_is_rational_function(self, syms): return True + def _eval_is_algebraic_expr(self, syms): + return True + def _eval_nseries(self, x, n, logx): return self + def _mag(x): """Return integer ``i`` such that .1 <= x/10**i < 1 diff -Nru python3-sympy-0.7.2/sympy/core/exprtools.py python3-sympy-0.7.3/sympy/core/exprtools.py --- python3-sympy-0.7.2/sympy/core/exprtools.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/core/exprtools.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,23 +1,28 @@ """Tools for manipulating of large commutative expressions. """ from sympy.core.add import Add -from sympy.core.compatibility import iterable, is_sequence +from sympy.core.compatibility import iterable, is_sequence, SYMPY_INTS from sympy.core.mul import Mul, _keep_coeff from sympy.core.power import Pow from sympy.core.basic import Basic, preorder_traversal from sympy.core.expr import Expr from sympy.core.sympify import sympify -from sympy.core.numbers import Rational, Integer +from sympy.core.numbers import Rational, Integer, Number, I from sympy.core.singleton import S from sympy.core.symbol import Dummy from sympy.core.coreerrors import NonCommutativeExpression from sympy.core.containers import Tuple, Dict from sympy.utilities import default_sort_key from sympy.utilities.iterables import (common_prefix, common_suffix, - variations) + variations, ordered) from collections import defaultdict + +def _isnumber(i): + return isinstance(i, (SYMPY_INTS, float)) or i.is_Number + + def decompose_power(expr): """ Decompose power into symbolic base and integer exponent. @@ -66,36 +71,228 @@ return base, exp + class Factors(object): - """Efficient representation of ``f_1*f_2*...*f_n``. """ + """Efficient representation of ``f_1*f_2*...*f_n``.""" __slots__ = ['factors', 'gens'] - def __init__(self, factors=None): # Factors - if factors is None: + def __init__(self, factors=None): # Factors + """Initialize Factors from dict or expr. + + Examples + ======== + + >>> from sympy.core.exprtools import Factors + >>> from sympy.abc import x + >>> from sympy import I + >>> e = 2*x**3 + >>> Factors(e) + Factors({2: 1, x: 3}) + >>> Factors(e.as_powers_dict()) + Factors({2: 1, x: 3}) + >>> f = _ + >>> f.factors # underlying dictionary + {2: 1, x: 3} + >>> f.gens # base of each factor + frozenset([2, x]) + >>> Factors(0) + Factors({0: 1}) + >>> Factors(I) + Factors({I: 1}) + + Notes + ===== + + Although a dictionary can be passed, only minimal checking is + performed: powers of -1 and I are made canonical. + + """ + if isinstance(factors, (SYMPY_INTS, float)): + factors = S(factors) + + if isinstance(factors, Factors): + factors = factors.factors.copy() + elif factors is None or factors is S.One: + factors = {} + elif factors is S.Zero or factors == 0: + factors = {S.Zero: S.One} + elif isinstance(factors, Number): + n = factors factors = {} + if n < 0: + factors[S.NegativeOne] = S.One + n = -n + if n is not S.One: + if n.is_Float or n.is_Integer or n is S.Infinity: + factors[n] = S.One + elif n.is_Rational: + # since we're processing Numbers, the denominator is + # stored with a negative exponent; all other factors + # are left . + if n.p != 1: + factors[Integer(n.p)] = S.One + factors[Integer(n.q)] = S.NegativeOne + else: + raise ValueError('Expected Float|Rational|Integer, not %s' % n) + elif isinstance(factors, Basic) and not factors.args: + factors = {factors: S.One} + elif isinstance(factors, Expr): + c, nc = factors.args_cnc() + i = c.count(I) + for _ in range(i): + c.remove(I) + factors = dict(Mul._from_args(c).as_powers_dict()) + if i: + factors[I] = S.One*i + if nc: + factors[Mul(*nc, **dict(evaluate=False))] = S.One + else: + factors = factors.copy() # /!\ should be dict-like - self.factors = factors - self.gens = frozenset(list(factors.keys())) + # tidy up -/+1 and I exponents if Rational - def __hash__(self): # Factors - return hash((tuple(self.factors), self.gens)) + handle = [] + for k in factors: + if k is I or k in (-1, 1): + handle.append(k) + if handle: + i1 = S.One + for k in handle: + if not _isnumber(factors[k]): + continue + i1 *= k**factors.pop(k) + if i1 is not S.One: + for a in i1.args if i1.is_Mul else [i1]: # at worst, -1.0*I*(-1)**e + if a is S.NegativeOne: + factors[a] = S.One + elif a is I: + factors[I] = S.One + elif a.is_Pow: + if S.NegativeOne not in factors: + factors[S.NegativeOne] = S.Zero + factors[S.NegativeOne] += a.exp + elif a == 1: + factors[a] = S.One + elif a == -1: + factors[-a] = S.One + factors[S.NegativeOne] = S.One + else: + raise ValueError('unexpected factor in i1: %s' % a) + + self.factors = factors + try: + self.gens = frozenset(list(factors.keys())) + except AttributeError: + raise TypeError('expecting Expr or dictionary') + + def __hash__(self): # Factors + keys = tuple(ordered(list(self.factors.keys()))) + values = [self.factors[k] for k in keys] + return hash((keys, values)) + + def __repr__(self): # Factors + return "Factors({%s})" % ', '.join( + ['%s: %s' % (k, v) for k, v in ordered(list(self.factors.items()))]) + + @property + def is_zero(self): # Factors + """ + >>> from sympy.core.exprtools import Factors + >>> Factors(0).is_zero + True + """ + f = self.factors + return len(f) == 1 and S.Zero in f + + @property + def is_one(self): # Factors + """ + >>> from sympy.core.exprtools import Factors + >>> Factors(1).is_one + True + """ + return not self.factors + + def as_expr(self): # Factors + """Return the underlying expression. + + Examples + ======== + + >>> from sympy.core.exprtools import Factors + >>> from sympy.abc import x, y + >>> Factors((x*y**2).as_powers_dict()).as_expr() + x*y**2 - def __repr__(self): # Factors - return "Factors(%s)" % self.factors + """ - def as_expr(self): # Factors args = [] for factor, exp in self.factors.items(): if exp != 1: b, e = factor.as_base_exp() - e = _keep_coeff(Integer(exp), e) + if isinstance(exp, int): + e = _keep_coeff(Integer(exp), e) + elif isinstance(exp, Rational): + e = _keep_coeff(exp, e) + else: + e *= exp args.append(b**e) else: args.append(factor) return Mul(*args) - def normal(self, other): # Factors + def mul(self, other): # Factors + """Return Factors of ``self * other``. + + Examples + ======== + + >>> from sympy.core.exprtools import Factors + >>> from sympy.abc import x, y, z + >>> a = Factors((x*y**2).as_powers_dict()) + >>> b = Factors((x*y/z).as_powers_dict()) + >>> a.mul(b) + Factors({x: 2, y: 3, z: -1}) + >>> a*b + Factors({x: 2, y: 3, z: -1}) + """ + if not isinstance(other, Factors): + other = Factors(other) + if any(f.is_zero for f in (self, other)): + return Factors(S.Zero) + factors = dict(self.factors) + + for factor, exp in other.factors.items(): + if factor in factors: + exp = factors[factor] + exp + + if not exp: + del factors[factor] + continue + + factors[factor] = exp + + return Factors(factors) + + def normal(self, other): + """Return ``self`` and ``other`` with ``gcd`` removed from each. + The only differences between this and method ``div`` is that this + is 1) optimized for the case when there are few factors in common and + 2) this does not raise an error if ``other`` is zero. + + See Also + ======== + div + + """ + if not isinstance(other, Factors): + other = Factors(other) + if other.is_zero: + return (Factors(), Factors(S.Zero)) + if self.is_zero: + return (Factors(S.Zero), Factors()) + self_factors = dict(self.factors) other_factors = dict(other.factors) @@ -110,61 +307,196 @@ if not exp: del self_factors[factor] del other_factors[factor] - else: + elif _isnumber(exp): if exp > 0: self_factors[factor] = exp del other_factors[factor] else: del self_factors[factor] other_factors[factor] = -exp + else: + r = self_exp.extract_additively(other_exp) + if r is not None: + if r: + self_factors[factor] = r + del other_factors[factor] + else: # should be handled already + del self_factors[factor] + del other_factors[factor] + else: + sc, sa = self_exp.as_coeff_Add() + if sc: + oc, oa = other_exp.as_coeff_Add() + diff = sc - oc + if diff > 0: + self_factors[factor] -= oc + other_exp = oa + elif diff < 0: + self_factors[factor] -= sc + other_factors[factor] -= sc + other_exp = oa - diff + else: + self_factors[factor] = sa + other_exp = oa + if other_exp: + other_factors[factor] = other_exp + else: + del other_factors[factor] return Factors(self_factors), Factors(other_factors) - def mul(self, other): # Factors - factors = dict(self.factors) + def div(self, other): # Factors + """Return ``self`` and ``other`` with ``gcd`` removed from each. + This is optimized for the case when there are many factors in common. - for factor, exp in other.factors.items(): - if factor in factors: - exp = factors[factor] + exp + Examples + ======== - if not exp: - del factors[factor] - continue + >>> from sympy.core.exprtools import Factors + >>> from sympy.abc import x, y, z + >>> from sympy import S - factors[factor] = exp + >>> a = Factors((x*y**2).as_powers_dict()) + >>> a.div(a) + (Factors({}), Factors({})) + >>> a.div(x*z) + (Factors({y: 2}), Factors({z: 1})) - return Factors(factors) + The ``/`` operator only gives ``quo``: + + >>> a/x + Factors({y: 2}) + + Factors treats its factors as though they are all in the numerator, so + if you violate this assumption the results will be correct but will + not strictly correspond to the numerator and denominator of the ratio: - def div(self, other): # Factors + >>> a.div(x/z) + (Factors({y: 2}), Factors({z: -1})) + + Factors is also naive about bases: it does not attempt any denesting + of Rational-base terms, for example the following does not become + 2**(2*x)/2. + + >>> Factors(2**(2*x + 2)).div(S(8)) + (Factors({2: 2*x + 2}), Factors({8: 1})) + + factor_terms can clean up such Rational-bases powers: + + >>> from sympy.core.exprtools import factor_terms + >>> n, d = Factors(2**(2*x + 2)).div(S(8)) + >>> n.as_expr()/d.as_expr() + 2**(2*x + 2)/8 + >>> factor_terms(_) + 2**(2*x)/2 + + """ quo, rem = dict(self.factors), {} + if not isinstance(other, Factors): + other = Factors(other) + if other.is_zero: + raise ZeroDivisionError + if self.is_zero: + return (Factors(S.Zero), Factors()) + for factor, exp in other.factors.items(): if factor in quo: - exp = quo[factor] - exp + d = quo[factor] - exp + if _isnumber(d): + if d <= 0: + del quo[factor] + + if d >= 0: + if d: + quo[factor] = d - if exp <= 0: - del quo[factor] + continue - if exp >= 0: - if exp: - quo[factor] = exp + exp = -d + else: + r = quo[factor].extract_additively(exp) + if r is not None: + if r: + quo[factor] = r + else: # should be handled already + del quo[factor] + else: + other_exp = exp + sc, sa = quo[factor].as_coeff_Add() + if sc: + oc, oa = other_exp.as_coeff_Add() + diff = sc - oc + if diff > 0: + quo[factor] -= oc + other_exp = oa + elif diff < 0: + quo[factor] -= sc + other_exp = oa - diff + else: + quo[factor] = sa + other_exp = oa + if other_exp: + rem[factor] = other_exp + else: + assert factor not in rem continue - exp = -exp - rem[factor] = exp return Factors(quo), Factors(rem) - def quo(self, other): # Factors + def quo(self, other): # Factors + """Return numerator Factor of ``self / other``. + + Examples + ======== + + >>> from sympy.core.exprtools import Factors + >>> from sympy.abc import x, y, z + >>> a = Factors((x*y**2).as_powers_dict()) + >>> b = Factors((x*y/z).as_powers_dict()) + >>> a.quo(b) # same as a/b + Factors({y: 1}) + """ return self.div(other)[0] - def rem(self, other): # Factors + def rem(self, other): # Factors + """Return denominator Factors of ``self / other``. + + Examples + ======== + + >>> from sympy.core.exprtools import Factors + >>> from sympy.abc import x, y, z + >>> a = Factors((x*y**2).as_powers_dict()) + >>> b = Factors((x*y/z).as_powers_dict()) + >>> a.rem(b) + Factors({z: -1}) + >>> a.rem(a) + Factors({}) + """ return self.div(other)[1] - def pow(self, other): # Factors - if type(other) is int and other >= 0: + def pow(self, other): # Factors + """Return self raised to a non-negative integer power. + + Examples + ======== + + >>> from sympy.core.exprtools import Factors + >>> from sympy.abc import x, y + >>> a = Factors((x*y**2).as_powers_dict()) + >>> a**2 + Factors({x: 2, y: 4}) + + """ + if isinstance(other, Factors): + other = other.as_expr() + if other.is_Integer: + other = int(other) + if isinstance(other, SYMPY_INTS) and other >= 0: factors = {} if other: @@ -175,7 +507,26 @@ else: raise ValueError("expected non-negative integer, got %s" % other) - def gcd(self, other): # Factors + def gcd(self, other): # Factors + """Return Factors of ``gcd(self, other)``. The keys are + the intersection of factors with the minimum exponent for + each factor. + + Examples + ======== + + >>> from sympy.core.exprtools import Factors + >>> from sympy.abc import x, y, z + >>> a = Factors((x*y**2).as_powers_dict()) + >>> b = Factors((x*y/z).as_powers_dict()) + >>> a.gcd(b) + Factors({x: 1, y: 1}) + """ + if not isinstance(other, Factors): + other = Factors(other) + if other.is_zero: + return Factors(self.factors) + factors = {} for factor, exp in self.factors.items(): @@ -185,7 +536,26 @@ return Factors(factors) - def lcm(self, other): # Factors + def lcm(self, other): # Factors + """Return Factors of ``lcm(self, other)`` which are + the union of factors with the maximum exponent for + each factor. + + Examples + ======== + + >>> from sympy.core.exprtools import Factors + >>> from sympy.abc import x, y, z + >>> a = Factors((x*y**2).as_powers_dict()) + >>> b = Factors((x*y/z).as_powers_dict()) + >>> a.lcm(b) + Factors({x: 1, y: 2, z: -1}) + """ + if not isinstance(other, Factors): + other = Factors(other) + if any(f.is_zero for f in (self, other)): + return Factors(S.Zero) + factors = dict(self.factors) for factor, exp in other.factors.items(): @@ -196,53 +566,42 @@ return Factors(factors) - def __mul__(self, other): # Factors - if isinstance(other, Factors): - return self.mul(other) - else: - return NotImplemented + def __mul__(self, other): # Factors + return self.mul(other) - def __divmod__(self, other): # Factors - if isinstance(other, Factors): - return self.div(other) - else: - return NotImplemented + def __divmod__(self, other): # Factors + return self.div(other) - def __div__(self, other): # Factors - if isinstance(other, Factors): - return self.quo(other) - else: - return NotImplemented + def __div__(self, other): # Factors + return self.quo(other) __truediv__ = __div__ - def __mod__(self, other): # Factors - if isinstance(other, Factors): - return self.rem(other) - else: - return NotImplemented + def __mod__(self, other): # Factors + return self.rem(other) - def __pow__(self, other): # Factors - if type(other) is int: - return self.pow(other) - else: - return NotImplemented + def __pow__(self, other): # Factors + return self.pow(other) - def __eq__(self, other): # Factors + def __eq__(self, other): # Factors + if not isinstance(other, Factors): + other = Factors(other) return self.factors == other.factors - def __ne__(self, other): # Factors + def __ne__(self, other): # Factors return not self.__eq__(other) + class Term(object): """Efficient representation of ``coeff*(numer/denom)``. """ __slots__ = ['coeff', 'numer', 'denom'] - def __init__(self, term, numer=None, denom=None): # Term + def __init__(self, term, numer=None, denom=None): # Term if numer is None and denom is None: if not term.is_commutative: - raise NonCommutativeExpression('commutative expression expected') + raise NonCommutativeExpression( + 'commutative expression expected') coeff, factors = term.as_coeff_mul() numer, denom = defaultdict(int), defaultdict(int) @@ -274,16 +633,16 @@ self.numer = numer self.denom = denom - def __hash__(self): # Term + def __hash__(self): # Term return hash((self.coeff, self.numer, self.denom)) - def __repr__(self): # Term + def __repr__(self): # Term return "Term(%s, %s, %s)" % (self.coeff, self.numer, self.denom) - def as_expr(self): # Term + def as_expr(self): # Term return self.coeff*(self.numer.as_expr()/self.denom.as_expr()) - def mul(self, other): # Term + def mul(self, other): # Term coeff = self.coeff*other.coeff numer = self.numer.mul(other.numer) denom = self.denom.mul(other.denom) @@ -292,37 +651,37 @@ return Term(coeff, numer, denom) - def inv(self): # Term + def inv(self): # Term return Term(1/self.coeff, self.denom, self.numer) - def quo(self, other): # Term + def quo(self, other): # Term return self.mul(other.inv()) - def pow(self, other): # Term + def pow(self, other): # Term if other < 0: return self.inv().pow(-other) else: - return Term(self.coeff ** other, + return Term(self.coeff ** other, self.numer.pow(other), self.denom.pow(other)) - def gcd(self, other): # Term + def gcd(self, other): # Term return Term(self.coeff.gcd(other.coeff), self.numer.gcd(other.numer), self.denom.gcd(other.denom)) - def lcm(self, other): # Term + def lcm(self, other): # Term return Term(self.coeff.lcm(other.coeff), self.numer.lcm(other.numer), self.denom.lcm(other.denom)) - def __mul__(self, other): # Term + def __mul__(self, other): # Term if isinstance(other, Term): return self.mul(other) else: return NotImplemented - def __div__(self, other): # Term + def __div__(self, other): # Term if isinstance(other, Term): return self.quo(other) else: @@ -330,20 +689,21 @@ __truediv__ = __div__ - def __pow__(self, other): # Term - if type(other) is int: + def __pow__(self, other): # Term + if isinstance(other, SYMPY_INTS): return self.pow(other) else: return NotImplemented - def __eq__(self, other): # Term + def __eq__(self, other): # Term return (self.coeff == other.coeff and self.numer == other.numer and self.denom == other.denom) - def __ne__(self, other): # Term + def __ne__(self, other): # Term return not self.__eq__(other) + def _gcd_terms(terms, isprimitive=False, fraction=True): """Helper function for :func:`gcd_terms`. @@ -366,7 +726,6 @@ if len(terms) == 0: return S.Zero, S.Zero, S.One - if len(terms) == 1: cont = terms[0].coeff numer = terms[0].numer.as_expr() @@ -404,6 +763,7 @@ return cont, numer, denom + def gcd_terms(terms, isprimitive=False, clear=True, fraction=True): """Compute the GCD of ``terms`` and put them together. @@ -447,6 +807,9 @@ >>> gcd_terms(x/2/y + 1/x/y, fraction=False, clear=False) (x + 2/x)/(2*y) + The ``clear`` flag was ignored in this case because the returned + expression was a rational expression, not a simple sum. + See Also ======== factor_terms, sympy.polys.polytools.terms_gcd @@ -470,11 +833,11 @@ isadd = isinstance(terms, Add) addlike = isadd or not isinstance(terms, Basic) and \ - is_sequence(terms, include=set) and \ - not isinstance(terms, Dict) + is_sequence(terms, include=set) and \ + not isinstance(terms, Dict) if addlike: - if isadd: # i.e. an Add + if isadd: # i.e. an Add terms = list(terms.args) else: terms = sympify(terms) @@ -508,7 +871,7 @@ return terms.func(*[handle(i) for i in terms.args]) -def factor_terms(expr, radical=False, clear=False, fraction=False): +def factor_terms(expr, radical=False, clear=False, fraction=False, sign=True): """Remove common factors from terms in all arguments without changing the underlying structure of the expr. No expansion or simplification (and no processing of non-commutatives) is performed. @@ -523,10 +886,13 @@ If fraction=True (default is False) then a common denominator will be constructed for the expression. + If sign=True (default) then even if the only factor in common is a -1, + it will be factored out of the expression. + Examples ======== - >>> from sympy import factor_terms, Symbol, Mul, primitive + >>> from sympy import factor_terms, Symbol >>> from sympy.abc import x, y >>> factor_terms(x + x*(2 + 4*y)**3) x*(8*(2*y + 1)**3 + 1) @@ -551,55 +917,79 @@ >>> factor_terms(x*y/2 + y, clear=False) == _ True + If a -1 is all that can be factored out, to *not* factor it out, the + flag ``sign`` must be False: + + >>> factor_terms(-x - y) + -(x + y) + >>> factor_terms(-x - y, sign=False) + -x - y + >>> factor_terms(-2*x - 2*y, sign=False) + -2*(x + y) + See Also ======== gcd_terms, sympy.polys.polytools.terms_gcd """ + from sympy.simplify.simplify import bottom_up - expr = sympify(expr) - is_iterable = iterable(expr) - - if not isinstance(expr, Basic) or expr.is_Atom: - if is_iterable: - return type(expr)([factor_terms(i, - radical=radical, - clear=clear, - fraction=fraction) for i in expr]) - return expr + def do(expr): + is_iterable = iterable(expr) - if expr.is_Pow or expr.is_Function or is_iterable or not hasattr(expr, 'args_cnc'): - args = expr.args - newargs = tuple([factor_terms(i, - radical=radical, - clear=clear, - fraction=fraction) for i in args]) - if newargs == args: + if not isinstance(expr, Basic) or expr.is_Atom: + if is_iterable: + return type(expr)([do(i) for i in expr]) return expr - return expr.func(*newargs) - cont, p = expr.as_content_primitive(radical=radical) - if p.is_Add: - list_args = [gcd_terms(a, - isprimitive=True, - clear=clear, - fraction=fraction) for a in Add.make_args(p)] - p = Add._from_args(list_args) # gcd_terms will fix up ordering - elif p.args: - p = p.func(*[factor_terms(a, radical, clear, fraction) for a in p.args]) - p = gcd_terms(p, - isprimitive=True, - clear=clear, - fraction=fraction) - return _keep_coeff(cont, p, clear=clear) + if expr.is_Pow or expr.is_Function or \ + is_iterable or not hasattr(expr, 'args_cnc'): + args = expr.args + newargs = tuple([do(i) for i in args]) + if newargs == args: + return expr + return expr.func(*newargs) + + cont, p = expr.as_content_primitive(radical=radical) + if p.is_Add: + list_args = [do(a) for a in Add.make_args(p)] + # get a common negative (if there) which gcd_terms does not remove + if all(a.as_coeff_Mul()[0] < 0 for a in list_args): + cont = -cont + list_args = [-a for a in list_args] + # watch out for exp(-(x+2)) which gcd_terms will change to exp(-x-2) + special = {} + for i, a in enumerate(list_args): + b, e = a.as_base_exp() + if e.is_Mul and e != Mul(*e.args): + list_args[i] = Dummy() + special[list_args[i]] = a + # rebuild p not worrying about the order which gcd_terms will fix + p = Add._from_args(list_args) + p = gcd_terms(p, + isprimitive=True, + clear=clear, + fraction=fraction).xreplace(special) + elif p.args: + p = p.func( + *[do(a) for a in p.args]) + rv = _keep_coeff(cont, p, clear=clear, sign=sign) + return rv + expr = sympify(expr) + return do(expr) + -def _mask_nc(eq): - """Return ``eq`` with non-commutative objects replaced with dummy +def _mask_nc(eq, name=None): + """ + Return ``eq`` with non-commutative objects replaced with Dummy symbols. A dictionary that can be used to restore the original - values is returned: if it is None, the expression is - noncommutative and cannot be made commutative. The third value - returned is a list of any non-commutative symbols that appear - in the returned equation. + values is returned: if it is None, the expression is noncommutative + and cannot be made commutative. The third value returned is a list + of any non-commutative symbols that appear in the returned equation. + + ``name``, if given, is the name that will be used with numered Dummy + variables that will replace the non-commutative objects and is mainly + used for doctesting purposes. Notes ===== @@ -616,40 +1006,39 @@ Examples ======== >>> from sympy.physics.secondquant import Commutator, NO, F, Fd - >>> from sympy import Dummy, symbols, Sum, Mul, Basic - >>> from sympy.abc import x, y + >>> from sympy import symbols, Mul >>> from sympy.core.exprtools import _mask_nc + >>> from sympy.abc import x, y >>> A, B, C = symbols('A,B,C', commutative=False) - >>> Dummy._count = 0 # reset for doctest purposes One nc-symbol: - >>> _mask_nc(A**2 - x**2) - (_0**2 - x**2, {_0: A}, []) + >>> _mask_nc(A**2 - x**2, 'd') + (_d0**2 - x**2, {_d0: A}, []) Multiple nc-symbols: - >>> _mask_nc(A**2 - B**2) + >>> _mask_nc(A**2 - B**2, 'd') (A**2 - B**2, None, [A, B]) An nc-object with nc-symbols but no others outside of it: - >>> _mask_nc(1 + x*Commutator(A, B)) - (_1*x + 1, {_1: Commutator(A, B)}, []) - >>> _mask_nc(NO(Fd(x)*F(y))) - (_2, {_2: NO(CreateFermion(x)*AnnihilateFermion(y))}, []) + >>> _mask_nc(1 + x*Commutator(A, B), 'd') + (_d0*x + 1, {_d0: Commutator(A, B)}, []) + >>> _mask_nc(NO(Fd(x)*F(y)), 'd') + (_d0, {_d0: NO(CreateFermion(x)*AnnihilateFermion(y))}, []) Multiple nc-objects: >>> eq = x*Commutator(A, B) + x*Commutator(A, C)*Commutator(A, B) - >>> _mask_nc(eq) - (x*_3 + x*_4*_3, {_3: Commutator(A, B), _4: Commutator(A, C)}, [_3, _4]) + >>> _mask_nc(eq, 'd') + (x*_d0 + x*_d1*_d0, {_d0: Commutator(A, B), _d1: Commutator(A, C)}, [_d0, _d1]) Multiple nc-objects and nc-symbols: >>> eq = A*Commutator(A, B) + B*Commutator(A, C) - >>> _mask_nc(eq) - (A*_5 + B*_6, {_5: Commutator(A, B), _6: Commutator(A, C)}, [_5, _6, A, B]) + >>> _mask_nc(eq, 'd') + (A*_d0 + B*_d1, {_d0: Commutator(A, B), _d1: Commutator(A, C)}, [_d0, _d1, A, B]) If there is an object that: @@ -660,14 +1049,26 @@ then it will give False (or None?) for the is_commutative test. Such objects are also removed by this routine: - >>> from sympy import Basic, Mul + >>> from sympy import Basic >>> eq = (1 + Mul(Basic(), Basic(), evaluate=False)) >>> eq.is_commutative False - >>> _mask_nc(eq) - (_7**2 + 1, {_7: Basic()}, []) + >>> _mask_nc(eq, 'd') + (_d0**2 + 1, {_d0: Basic()}, []) """ + name = name or 'mask' + # Make Dummy() append sequential numbers to the name + def numbered_names(): + i = 0 + while True: + yield name + str(i) + i += 1 + names = numbered_names() + def Dummy(*args, **kwargs): + from sympy import Dummy + return Dummy(next(names), *args, **kwargs) + expr = eq if expr.is_commutative: return eq, {}, [] @@ -676,7 +1077,7 @@ rep = [] nc_obj = set() nc_syms = set() - pot = preorder_traversal(expr, key=default_sort_key) + pot = preorder_traversal(expr, keys=default_sort_key) for i, a in enumerate(pot): if any(a == r[0] for r in rep): pot.skip() @@ -710,6 +1111,7 @@ nc_syms.sort(key=default_sort_key) return expr, dict([(v, k) for k, v in rep]) or None, nc_syms + def factor_nc(expr): """Return the factored form of ``expr`` while handling non-commutative expressions. @@ -725,9 +1127,14 @@ >>> factor_nc(((x + A)*(x + B)).expand()) (x + A)*(x + B) """ - from sympy.simplify.simplify import _mexpand + from sympy.simplify.simplify import powsimp from sympy.polys import gcd, factor + def _pemexpand(expr): + "Expand with the minimal set of hints necessary to check the result." + return expr.expand(deep=True, mul=True, power_exp=True, + power_base=False, basic=False, multinomial=True, log=False) + expr = sympify(expr) if not isinstance(expr, Expr) or not expr.args: return expr @@ -752,8 +1159,12 @@ if c is not S.One: hit = True c, g = c.as_coeff_Mul() + if g is not S.One: + for i, (cc, _) in enumerate(args): + cc = list(Mul.make_args(Mul._from_args(list(cc))/g)) + args[i][0] = cc for i, (cc, _) in enumerate(args): - cc = list(Mul.make_args(Mul._from_args(list(cc))/g)) + cc[0] = cc[0]/c args[i][0] = cc # find any noncommutative common prefix for i, a in enumerate(args): @@ -841,7 +1252,7 @@ unrep1 = [(v, k) for k, v in rep1] unrep1.reverse() new_mid, r2, _ = _mask_nc(mid.subs(rep1)) - new_mid = factor(new_mid) + new_mid = powsimp(factor(new_mid)) new_mid = new_mid.subs(r2).subs(unrep1) @@ -859,13 +1270,15 @@ cfac.append(f) else: b, e = f.as_base_exp() - assert e.is_Integer - ncfac.extend([b]*e) + if e.is_Integer: + ncfac.extend([b]*e) + else: + ncfac.append(f) pre_mid = g*Mul(*cfac)*l - target = _mexpand(expr/c) + target = _pemexpand(expr/c) for s in variations(ncfac, len(ncfac)): ok = pre_mid*Mul(*s)*r - if _mexpand(ok) == target: + if _pemexpand(ok) == target: return _keep_coeff(c, ok) # mid was an Add that didn't factor successfully diff -Nru python3-sympy-0.7.2/sympy/core/facts.py python3-sympy-0.7.3/sympy/core/facts.py --- python3-sympy-0.7.2/sympy/core/facts.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/core/facts.py 2013-07-13 17:53:32.000000000 +0000 @@ -51,6 +51,7 @@ from .logic import Logic, And, Or, Not + def _base_fact(atom): """Return the literal fact of an atom. @@ -61,6 +62,7 @@ else: return atom + def _as_pair(atom): if isinstance(atom, Not): return (atom.arg, False) @@ -68,6 +70,8 @@ return (atom, True) # XXX this prepares forward-chaining rules for alpha-network + + def deduce_alpha_implications(implications): """deduce all implications @@ -110,7 +114,8 @@ impl.discard(a) na = Not(a) if na in impl: - raise ValueError('implications are inconsistent: %s -> %s %s' % (a, na, impl)) + raise ValueError( + 'implications are inconsistent: %s -> %s %s' % (a, na, impl)) return res @@ -171,10 +176,10 @@ bimpl_impl = x_impl.get(bimpl) if bimpl_impl is not None: ximpls |= bimpl_impl[0] - seen_static_extension=True + seen_static_extension = True # attach beta-nodes which can be possibly triggered by an alpha-chain - for bidx, (bcond,bimpl) in enumerate(beta_rules): + for bidx, (bcond, bimpl) in enumerate(beta_rules): bargs = set(bcond.args) for x, (ximpls, bb) in x_impl.items(): x_all = ximpls | set([x]) @@ -225,6 +230,7 @@ # RULES PROVER # ################ + class TautologyDetected(Exception): """(internal) Prover uses it for reporting detected tautology""" pass @@ -261,17 +267,17 @@ def __init__(self): self.proved_rules = [] - self._rules_seen = set() + self._rules_seen = set() def split_alpha_beta(self): """split proved rules into alpha and beta chains""" rules_alpha = [] # a -> b - rules_beta = [] # &(...) -> b - for a,b in self.proved_rules: + rules_beta = [] # &(...) -> b + for a, b in self.proved_rules: if isinstance(a, And): - rules_beta.append((a,b)) + rules_beta.append((a, b)) else: - rules_alpha.append((a,b) ) + rules_alpha.append((a, b) ) return rules_alpha, rules_beta @property @@ -288,10 +294,10 @@ return if isinstance(a, bool): return - if (a,b) in self._rules_seen: + if (a, b) in self._rules_seen: return else: - self._rules_seen.add((a,b)) + self._rules_seen.add((a, b)) # this is the core of processing try: @@ -316,12 +322,12 @@ if not isinstance(a, Logic): # Atom # tautology: a -> a|c|... if a in b.args: - raise TautologyDetected(a,b, 'a -> a|c|...') + raise TautologyDetected(a, b, 'a -> a|c|...') self.process_rule(And(*[Not(barg) for barg in b.args]), Not(a)) for bidx in range(len(b.args)): barg = b.args[bidx] - brest= b.args[:bidx] + b.args[bidx+1:] + brest = b.args[:bidx] + b.args[bidx + 1:] self.process_rule(And(a, Not(barg)), Or(*brest)) # left part @@ -330,23 +336,24 @@ # (this will be the basis of beta-network) elif isinstance(a, And): if b in a.args: - raise TautologyDetected(a,b, 'a & b -> a') - self.proved_rules.append((a,b)) + raise TautologyDetected(a, b, 'a & b -> a') + self.proved_rules.append((a, b)) # XXX NOTE at present we ignore !c -> !a | !b elif isinstance(a, Or): if b in a.args: - raise TautologyDetected(a,b, 'a | b -> a') + raise TautologyDetected(a, b, 'a | b -> a') for aarg in a.args: self.process_rule(aarg, b) else: # both `a` and `b` are atoms - self.proved_rules.append((a,b)) # a -> b + self.proved_rules.append((a, b)) # a -> b self.proved_rules.append((Not(b), Not(a))) # !b -> !a ######################################## + class FactRules(object): """Rules that describe how to deduce facts in logic space @@ -406,7 +413,7 @@ self.beta_rules = [] for bcond, bimpl in P.rules_beta: self.beta_rules.append( - (set(_as_pair(a) for a in bcond.args), _as_pair(bimpl))) + (set(_as_pair(a) for a in bcond.args), _as_pair(bimpl))) # deduce alpha implications impl_a = deduce_alpha_implications(P.rules_alpha) @@ -436,11 +443,13 @@ prereq[k] |= pitems self.prereq = prereq + class InconsistentAssumptions(ValueError): def __str__(self): kb, fact, value = self.args return "%s, %s=%s" % (kb, fact, value) + class FactKB(dict): """ A simple propositional knowledge base relying on compiled inference rules. diff -Nru python3-sympy-0.7.2/sympy/core/function.py python3-sympy-0.7.3/sympy/core/function.py --- python3-sympy-0.7.2/sympy/core/function.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/core/function.py 2013-07-13 17:53:32.000000000 +0000 @@ -12,9 +12,7 @@ creation: f = Lambda(x, exp(x)*x) f = Lambda(exp(x)*x) # free symbols of expr define the number of args - f = Lambda(exp(x)*x) # free symbols in the expression define the number - # of arguments - f = exp * Lambda(x,x) + f = exp * Lambda(x, x) 4) isn't implemented yet: composition of functions, like (sin+cos)(x), this works in sympy core, but needs to be ported back to SymPy. @@ -32,17 +30,18 @@ (x,) """ -from .core import BasicMeta, C +from .add import Add from .assumptions import ManagedProperties from .basic import Basic -from .singleton import S -from .sympify import sympify -from .expr import Expr, AtomicExpr -from .decorators import _sympifyit -from .compatibility import iterable,is_sequence from .cache import cacheit +from .compatibility import iterable, is_sequence +from .core import BasicMeta, C +from .decorators import _sympifyit +from .expr import Expr, AtomicExpr from .numbers import Rational, Float -from .add import Add +from .rules import Transform +from .singleton import S +from .sympify import sympify from sympy.core.containers import Tuple, Dict from sympy.core.logic import fuzzy_and @@ -52,6 +51,7 @@ from sympy import mpmath import sympy.mpmath.libmp as mlib + def _coeff_isneg(a): """Return True if the leading Number is negative. @@ -75,13 +75,16 @@ a = a.args[0] return a.is_Number and a.is_negative + class PoleError(Exception): pass + class ArgumentIndexError(ValueError): def __str__(self): return ("Invalid operation with argument number %s for Function %s" % - (self.args[1], self.args[0])) + (self.args[1], self.args[0])) + class FunctionClass(ManagedProperties, metaclass=BasicMeta): """ @@ -96,6 +99,7 @@ def __repr__(cls): return cls.__name__ + class Application(Basic, metaclass=FunctionClass): """ Base class for applied functions. @@ -162,7 +166,6 @@ return new(*self.args) - class Function(Application, Expr): """Base class for applied mathematical functions. @@ -265,8 +268,7 @@ # and change NumPy to take advantage of this. temp = ('%(name)s takes exactly %(args)s ' 'argument%(plural)s (%(given)s given)') - raise TypeError(temp % - { + raise TypeError(temp % { 'name': cls, 'args': cls.nargs, 'plural': 's'*(n != 1), @@ -330,7 +332,6 @@ return 4, i, name - @property def is_commutative(self): """ @@ -362,6 +363,26 @@ # we be more intelligent about it? try: args = [arg._to_mpmath(prec + 5) for arg in self.args] + def bad(m): + from sympy.mpmath import mpf, mpc + # the precision of an mpf value is the last element + # if that is 1 (and m[1] is not 1 which would indicate a + # power of 2), then the eval failed; so check that none of + # the arguments failed to compute to a finite precision. + # Note: An mpc value has two parts, the re and imag tuple; + # check each of those parts, too. Anything else is allowed to + # pass + if isinstance(m, mpf): + m = m._mpf_ + return m[1] !=1 and m[-1] == 1 + elif isinstance(m, mpc): + m, n = m._mpc_ + return m[1] !=1 and m[-1] == 1 and \ + n[1] !=1 and n[-1] == 1 + else: + return False + if any(bad(a) for a in args): + raise ValueError # one or more args failed to compute with significance except ValueError: return @@ -420,7 +441,7 @@ Examples ======== - >>> from sympy import atan2, O + >>> from sympy import atan2 >>> from sympy.abc import x, y >>> atan2(x, y).series(x, n=2) atan2(0, y) + x/y + O(x**2) @@ -435,20 +456,15 @@ -1/x - log(x)/x + log(x)/2 + O(1) """ - if self.func.nargs is None: - from sympy.utilities.misc import filldedent - raise NotImplementedError(filldedent(''' - series for user-defined functions are not - supported.''')) args = self.args args0 = [t.limit(x, 0) for t in args] - if any(t.is_bounded == False for t in args0): + if any(t.is_bounded is False for t in args0): from sympy import oo, zoo, nan # XXX could use t.as_leading_term(x) here but it's a little # slower a = [t.compute_leading_term(x, logx=logx) for t in args] a0 = [t.limit(x, 0) for t in a] - if any ([t.has(oo, -oo, zoo, nan) for t in a0]): + if any([t.has(oo, -oo, zoo, nan) for t in a0]): return self._eval_aseries(n, args0, x, logx )._eval_nseries(x, n, logx) # Careful: the argument goes to oo, but only logarithmically so. We @@ -478,7 +494,10 @@ s = s.removeO() s = s.subs(v, zi).expand() + C.Order(o.expr.subs(v, zi), x) return s - if (self.func.nargs == 1 and args0[0]) or self.func.nargs > 1: + if (self.func.nargs is None + or (self.func.nargs == 1 and args0[0]) + or isinstance(self.func.nargs, tuple) + or self.func.nargs > 1): e = self e1 = e.expand() if e == e1: @@ -489,7 +508,7 @@ raise PoleError("Cannot expand %s around 0" % (self)) series = term fact = S.One - for i in range(n-1): + for i in range(n - 1): i += 1 fact *= Rational(i) e = e.diff(x) @@ -507,7 +526,12 @@ arg = self.args[0] l = [] g = None - for i in range(n+2): + # try to predict a number of terms needed + nterms = n + 2 + cf = C.Order(arg.as_leading_term(x), x).getn() + if cf != 0: + nterms = int(nterms / cf) + for i in range(nterms): g = self.taylor_term(i, arg, g) g = g.nseries(x, n=n, logx=logx) l.append(g) @@ -537,15 +561,15 @@ nargs = self.nargs[-1] else: nargs = self.nargs - if not (1<=argindex<=nargs): + if not (1 <= argindex <= nargs): raise ArgumentIndexError(self, argindex) - if not self.args[argindex-1].is_Symbol: + if not self.args[argindex - 1].is_Symbol: # See issue 1525 and issue 1620 and issue 2501 arg_dummy = C.Dummy('xi_%i' % argindex) return Subs(Derivative( - self.subs(self.args[argindex-1], arg_dummy), - arg_dummy), arg_dummy, self.args[argindex-1]) - return Derivative(self,self.args[argindex-1],evaluate=False) + self.subs(self.args[argindex - 1], arg_dummy), + arg_dummy), arg_dummy, self.args[argindex - 1]) + return Derivative(self, self.args[argindex - 1], evaluate=False) def _eval_as_leading_term(self, x): """Stub that should be overridden by new Functions to return @@ -582,7 +606,8 @@ redefine it to make it faster by using the "previous_terms". """ x = sympify(x) - return cls(x).diff(x, n).subs(x, 0) * x**n / C.factorial(n) + _x = Dummy('x') + return cls(_x).diff(_x, n).subs(_x, x).subs(x, 0) * x**n / C.factorial(n) class AppliedUndef(Function): @@ -596,31 +621,59 @@ result.nargs = len(args) return result + class UndefinedFunction(FunctionClass): """ The (meta)class of undefined functions. """ def __new__(mcl, name): - return BasicMeta.__new__(mcl, name, (AppliedUndef,), {}) + ret = BasicMeta.__new__(mcl, name, (AppliedUndef,), {}) + ret.__module__ = None + return ret class WildFunction(Function, AtomicExpr): """ - WildFunction() matches any expression but another WildFunction() - XXX is this as intended, does it work ? + A WildFunction function matches any function (with its arguments). + + Examples + ======== + + >>> from sympy import WildFunction, Function, cos + >>> from sympy.abc import x, y + >>> F = WildFunction('F') + >>> f = Function('f') + >>> x.match(F) + >>> F.match(F) + {F_: F_} + >>> f(x).match(F) + {F_: f(x)} + >>> cos(x).match(F) + {F_: cos(x)} + >>> f(x, y).match(F) + + To match functions with more than 1 arguments, set ``nargs`` to the + desired value: + + >>> F.nargs = 2 + >>> f(x, y).match(F) + {F_: f(x, y)} + """ nargs = 1 + include = set() def __new__(cls, name, **assumptions): obj = Function.__new__(cls, name, **assumptions) obj.name = name return obj - def matches(self, expr, repl_dict={}): + def matches(self, expr, repl_dict={}, old=False): if self.nargs is not None: - if not hasattr(expr,'nargs') or self.nargs != expr.nargs: + if not hasattr(expr, 'nargs') or self.nargs != expr.nargs: return None + repl_dict = repl_dict.copy() repl_dict[self] = expr return repl_dict @@ -629,6 +682,7 @@ def is_number(self): return False + class Derivative(Expr): """ Carries out differentiation of the given expression with respect to symbols. @@ -639,6 +693,21 @@ method internally (not _eval_derivative); Derivative should be the only one to call _eval_derivative. + Simplification of high-order derivatives: + + Because there can be a significant amount of simplification that can be + done when multiple differentiations are performed, results will be + automatically simplified in a fairly conservative fashion unless the + keyword ``simplify`` is set to False. + + >>> from sympy import sqrt, diff + >>> from sympy.abc import x + >>> e = sqrt((x + 1)**2 + x) + >>> diff(e, x, 5, simplify=False).count_ops() + 136 + >>> diff(e, x, 5).count_ops() + 30 + Ordering of variables: If evaluate is set to True and the expression can not be evaluated, the @@ -712,7 +781,7 @@ u = f(t) and v = f'(t), and F(t, f(t), f'(t)).diff(f(t)) simply means F(t, u, v).diff(u) at u = f(t). - We do not allow to take derivative with respect to expressions where this + We do not allow derivatives to be taken with respect to expressions where this is not so well defined. For example, we do not allow expr.diff(x*y) because there are multiple ways of structurally defining where x*y appears in an expression, some of which may surprise the reader (for example, a @@ -731,9 +800,11 @@ >>> from sympy import symbols, Function >>> f, g = symbols('f g', cls=Function) >>> f(2*g(x)).diff(x) - 2*Derivative(g(x), x)*Subs(Derivative(f(_xi_1), _xi_1), (_xi_1,), (2*g(x),)) + 2*Derivative(g(x), x)*Subs(Derivative(f(_xi_1), _xi_1), + (_xi_1,), (2*g(x),)) >>> f(g(x)).diff(x) - Derivative(g(x), x)*Subs(Derivative(f(_xi_1), _xi_1), (_xi_1,), (g(x),)) + Derivative(g(x), x)*Subs(Derivative(f(_xi_1), _xi_1), + (_xi_1,), (g(x),)) Finally, note that, to be consistent with variational calculus, and to ensure that the definition of substituting a Function for a Symbol in an @@ -779,10 +850,11 @@ >>> Derivative(f(x)**2, f(x), evaluate=True) 2*f(x) >>> Derivative(f(g(x)), x, evaluate=True) - Derivative(g(x), x)*Subs(Derivative(f(_xi_1), _xi_1), (_xi_1,), (g(x),)) + Derivative(g(x), x)*Subs(Derivative(f(_xi_1), _xi_1), + (_xi_1,), (g(x),)) """ - is_Derivative = True + is_Derivative = True @property def _diff_wrt(self): @@ -805,6 +877,7 @@ return False def __new__(cls, expr, *variables, **assumptions): + expr = sympify(expr) # There are no variables, we differentiate wrt all of the free symbols @@ -831,8 +904,8 @@ variable_count = [] all_zero = True i = 0 - while i < len(variables) - 1: # process up to final Integer - v, count = variables[i: i+2] + while i < len(variables) - 1: # process up to final Integer + v, count = variables[i: i + 2] iwas = i if v._diff_wrt: # We need to test the more specific case of count being an @@ -844,7 +917,7 @@ count = 1 i += 1 - if i == iwas: # didn't get an update because of bad input + if i == iwas: # didn't get an update because of bad input from sympy.utilities.misc import filldedent raise ValueError(filldedent(''' Can\'t differentiate wrt the variable: %s, %s''' % (v, count))) @@ -861,7 +934,7 @@ return expr # Pop evaluate because it is not really an assumption and we will need - # to track use it carefully below. + # to track it carefully below. evaluate = assumptions.pop('evaluate', False) # Look for a quick exit if there are symbols that don't appear in @@ -885,7 +958,7 @@ (not isinstance(expr, Derivative))): variables = list(variablegen) # If we wanted to evaluate, we sort the variables into standard - # order for later comparisons. This is too agressive if evaluate + # order for later comparisons. This is too aggressive if evaluate # is False, so we don't do it in that case. if evaluate: #TODO: check if assumption of discontinuous derivatives exist @@ -907,6 +980,7 @@ # don't commute with derivatives wrt symbols and we can't safely # continue. unhandled_non_symbol = False + nderivs = 0 # how many derivatives were performed for v in variablegen: is_symbol = v.is_Symbol @@ -919,6 +993,7 @@ old_v = v v = new_v obj = expr._eval_derivative(v) + nderivs += 1 if not is_symbol: if obj is not None: obj = obj.subs(v, old_v) @@ -944,6 +1019,10 @@ expr.args[0], *cls._sort_variables(expr.args[1:]) ) + if nderivs > 1 and assumptions.get('simplify', True): + from sympy.core.exprtools import factor_terms + from sympy.simplify.simplify import signsimp + expr = factor_terms(signsimp(expr)) return expr @classmethod @@ -1054,6 +1133,7 @@ if len(self.free_symbols) != 1 or len(self.variables) != 1: raise NotImplementedError('partials and higher order derivatives') z = list(self.free_symbols)[0] + def eval(x): f0 = self.expr.subs(z, Expr._from_mpmath(x, prec=mpmath.mp.prec)) f0 = f0.evalf(mlib.libmpf.prec_to_dps(mpmath.mp.prec)) @@ -1097,6 +1177,7 @@ def _eval_as_leading_term(self, x): return self.args[0].as_leading_term(x) + class Lambda(Expr): """ Lambda(x, expr) represents a lambda function similar to Python's @@ -1131,17 +1212,18 @@ def __new__(cls, variables, expr): try: + for v in variables if iterable(variables) else [variables]: + assert v.is_Symbol + except (AssertionError, AttributeError): + raise ValueError('variable is not a Symbol: %s' % v) + try: variables = Tuple(*variables) except TypeError: variables = Tuple(variables) if len(variables) == 1 and variables[0] == expr: return S.IdentityFunction - #use dummy variables internally, just to be sure - new_variables = [C.Dummy(arg.name) for arg in variables] - expr = sympify(expr).xreplace(dict(list(zip(variables, new_variables)))) - - obj = Expr.__new__(cls, Tuple(*new_variables), expr) + obj = Expr.__new__(cls, Tuple(*variables), S(expr)) return obj @property @@ -1165,10 +1247,8 @@ def __call__(self, *args): if len(args) != self.nargs: - from sympy.utilities.misc import filldedent - raise TypeError(filldedent(''' - %s takes %d arguments (%d given) - ''' % (self, self.nargs, len(args)))) + raise TypeError('%s takes %d arguments (%d given)' % + (self, self.nargs, len(args))) return self.expr.xreplace(dict(list(zip(self.variables, args)))) def __eq__(self, other): @@ -1189,7 +1269,7 @@ return super(Lambda, self).__hash__() def _hashable_content(self): - return (self.nargs, ) + tuple(sorted(self.free_symbols)) + return (self.expr.xreplace(self.canonical_variables),) @property def is_identity(self): @@ -1199,6 +1279,7 @@ else: return None + class Subs(Expr): """ Represents unevaluated substitutions of an expression. @@ -1248,9 +1329,9 @@ variables = [variables] variables = list(sympify(variables)) - if uniq(variables) != variables: + if list(uniq(variables)) != variables: repeated = [ v for v in set(variables) - if list(variables).count(v) > 1 ] + if list(variables).count(v) > 1 ] raise ValueError('cannot substitute expressions %s more than ' 'once.' % repeated) @@ -1334,7 +1415,7 @@ return super(Subs, self).__hash__() def _hashable_content(self): - return (self._expr, ) + return (self._expr.xreplace(self.canonical_variables),) def _eval_subs(self, old, new): if old in self.variables: @@ -1346,7 +1427,7 @@ if s not in self.free_symbols: return S.Zero return Subs(self.expr.diff(s), self.variables, self.point).doit() \ - + Add(*[ Subs(point.diff(s) * self.expr.diff(arg), + + Add(*[ Subs(point.diff(s) * self.expr.diff(arg), self.variables, self.point).doit() for arg, point in zip(self.variables, self.point) ]) @@ -1403,8 +1484,7 @@ References ========== - http://documents.wolfram.com/v5/Built-inFunctions/AlgebraicComputation/ - Calculus/D.html + http://reference.wolfram.com/legacy/v5_2/Built-inFunctions/AlgebraicComputation/Calculus/D.html See Also ======== @@ -1415,7 +1495,8 @@ kwargs.setdefault('evaluate', True) return Derivative(f, *symbols, **kwargs) -def expand(e, deep=True, modulus=None, power_base=True, power_exp=True, \ + +def expand(e, deep=True, modulus=None, power_base=True, power_exp=True, mul=True, log=True, multinomial=True, basic=True, **hints): """ Expand an expression using methods given as hints. @@ -1508,7 +1589,7 @@ proper assumptions--the arguments must be positive and the exponents must be real--or else the ``force`` hint must be True: - >>> from sympy import log, symbols, oo + >>> from sympy import log, symbols >>> log(x**2*y).expand(log=True) log(x**2*y) >>> log(x**2*y).expand(log=True, force=True) @@ -1596,19 +1677,19 @@ functions or to use ``hint=False`` to this function to finely control which hints are applied. Here are some examples:: - >>> from sympy import expand_log, expand, expand_mul, expand_power_base + >>> from sympy import expand, expand_mul, expand_power_base >>> x, y, z = symbols('x,y,z', positive=True) >>> expand(log(x*(y + z))) log(x) + log(y + z) - Here, we see that ``log`` was applied before ``mul``. To get the log + Here, we see that ``log`` was applied before ``mul``. To get the mul expanded form, either of the following will work:: - >>> expand_log(log(x*(y + z))) - log(x) + log(y + z) - >>> expand(log(x*(y + z)), mul=False) - log(x) + log(y + z) + >>> expand_mul(log(x*(y + z))) + log(x*y + x*z) + >>> expand(log(x*(y + z)), log=False) + log(x*y + x*z) A similar thing can happen with the ``power_base`` hint:: @@ -1745,6 +1826,8 @@ return sympify(e).expand(deep=deep, modulus=modulus, **hints) # These are simple wrappers around single hints. + + def expand_mul(expr, deep=True): """ Wrapper around expand that only uses the mul hint. See the expand @@ -1759,9 +1842,10 @@ x*exp(x + y)*log(x*y**2) + y*exp(x + y)*log(x*y**2) """ - return sympify(expr).expand(deep=deep, mul=True, power_exp=False,\ + return sympify(expr).expand(deep=deep, mul=True, power_exp=False, power_base=False, basic=False, multinomial=False, log=False) + def expand_multinomial(expr, deep=True): """ Wrapper around expand that only uses the multinomial hint. See the expand @@ -1776,9 +1860,10 @@ x**2 + 2*x*exp(x + 1) + exp(2*x + 2) """ - return sympify(expr).expand(deep=deep, mul=False, power_exp=False,\ + return sympify(expr).expand(deep=deep, mul=False, power_exp=False, power_base=False, basic=False, multinomial=True, log=False) + def expand_log(expr, deep=True, force=False): """ Wrapper around expand that only uses the log hint. See the expand @@ -1797,6 +1882,7 @@ power_exp=False, power_base=False, multinomial=False, basic=False, force=force) + def expand_func(expr, deep=True): """ Wrapper around expand that only uses the func hint. See the expand @@ -1811,9 +1897,10 @@ x*(x + 1)*gamma(x) """ - return sympify(expr).expand(deep=deep, func=True, basic=False,\ + return sympify(expr).expand(deep=deep, func=True, basic=False, log=False, mul=False, power_exp=False, power_base=False, multinomial=False) + def expand_trig(expr, deep=True): """ Wrapper around expand that only uses the trig hint. See the expand @@ -1822,15 +1909,16 @@ Examples ======== - >>> from sympy import expand_trig, sin, cos + >>> from sympy import expand_trig, sin >>> from sympy.abc import x, y >>> expand_trig(sin(x+y)*(x+y)) (x + y)*(sin(x)*cos(y) + sin(y)*cos(x)) """ - return sympify(expr).expand(deep=deep, trig=True, basic=False,\ + return sympify(expr).expand(deep=deep, trig=True, basic=False, log=False, mul=False, power_exp=False, power_base=False, multinomial=False) + def expand_complex(expr, deep=True): """ Wrapper around expand that only uses the complex hint. See the expand @@ -1850,9 +1938,10 @@ ======== Expr.as_real_imag """ - return sympify(expr).expand(deep=deep, complex=True, basic=False,\ + return sympify(expr).expand(deep=deep, complex=True, basic=False, log=False, mul=False, power_exp=False, power_base=False, multinomial=False) + def expand_power_base(expr, deep=True, force=False): """ Wrapper around expand that only uses the power_base hint. @@ -1917,6 +2006,7 @@ power_exp=False, power_base=True, multinomial=False, basic=False, force=force) + def expand_power_exp(expr, deep=True): """ Wrapper around expand that only uses the power_exp hint. @@ -1931,9 +2021,10 @@ >>> expand_power_exp(x**(y + 2)) x**2*x**y """ - return sympify(expr).expand(deep=deep, complex=False, basic=False,\ + return sympify(expr).expand(deep=deep, complex=False, basic=False, log=False, mul=False, power_exp=True, power_base=False, multinomial=False) + def count_ops(expr, visual=False): """ Return a representation (integer or expression) of the operations in expr. @@ -2036,13 +2127,13 @@ if n < 0: ops.append(NEG) args.append(d) - continue # won't be -Mul but could be Add + continue # won't be -Mul but could be Add elif d is not S.One: if not d.is_Integer: args.append(d) ops.append(DIV) args.append(n) - continue # could be -Mul + continue # could be -Mul elif a.is_Add: aargs = list(a.args) negs = 0 @@ -2056,20 +2147,20 @@ args.append(ai) if i > 0: ops.append(ADD) - if negs == len(aargs): # -x - y = NEG + SUB + if negs == len(aargs): # -x - y = NEG + SUB ops.append(NEG) - elif _coeff_isneg(aargs[0]): # -x + y = SUB, but already recorded ADD + elif _coeff_isneg(aargs[0]): # -x + y = SUB, but already recorded ADD ops.append(SUB - ADD) continue if a.is_Pow and a.exp is S.NegativeOne: ops.append(DIV) - args.append(a.base) # won't be -Mul but could be Add + args.append(a.base) # won't be -Mul but could be Add continue if (a.is_Mul or a.is_Pow or a.is_Function or isinstance(a, Derivative) or - isinstance(a, C.Integral)): + isinstance(a, C.Integral)): o = C.Symbol(a.func.__name__.upper()) # count the args @@ -2087,7 +2178,7 @@ ops = [count_ops(i, visual=visual) for i in expr] elif not isinstance(expr, Basic): ops = [] - else: # it's Basic not isinstance(expr, Expr): + else: # it's Basic not isinstance(expr, Expr): assert isinstance(expr, Basic) ops = [count_ops(a, visual=visual) for a in expr.args] @@ -2106,6 +2197,7 @@ return sum(int((a.args or [1])[0]) for a in Add.make_args(ops)) + def nfloat(expr, n=15, exponent=False): """Make all Rationals in expr Floats except those in exponents (unless the exponents flag is set to True). @@ -2115,7 +2207,7 @@ >>> from sympy.core.function import nfloat >>> from sympy.abc import x, y - >>> from sympy import cos, pi, S, sqrt + >>> from sympy import cos, pi, sqrt >>> nfloat(x**4 + x/2 + cos(pi/3) + 1 + sqrt(y)) x**4 + 0.5*x + sqrt(y) + 1.5 >>> nfloat(x**4 + sqrt(y), exponent=True) @@ -2123,42 +2215,41 @@ """ from sympy.core import Pow + if iterable(expr, exclude=str): if isinstance(expr, (dict, Dict)): return type(expr)([(k, nfloat(v, n, exponent)) for k, v in expr.items()]) return type(expr)([nfloat(a, n, exponent) for a in expr]) - elif not isinstance(expr, Expr): - return Float(expr, '') - elif expr.is_Float: - return expr.n(n) - elif expr.is_Integer: - return Float(float(expr)).n(n) - elif expr.is_Rational: - return Float(expr).n(n) + rv = sympify(expr) + + if rv.is_Number: + return Float(rv, n) + elif rv.is_number: + # evalf doesn't always set the precision + rv = rv.n(n) + if rv.is_Number: + rv = Float(rv.n(n), n) + else: + pass # pure_complex(rv) is likely True + return rv if not exponent: - bases = {} - expos = {} - reps = {} - for p in expr.atoms(Pow): - b, e = p.as_base_exp() - b = bases.setdefault(p.base, nfloat(p.base, n, exponent)) - e = expos.setdefault(e, Dummy()) - reps[p] = Pow(b, e, evaluate=False) - rv = expr.xreplace(dict(reps)).n(n).xreplace( - dict([(v, k) for k, v in expos.items()])) + reps = [(p, Pow(p.base, Dummy())) for p in rv.atoms(Pow)] + rv = rv.xreplace(dict(reps)) + rv = rv.n(n) + if not exponent: + rv = rv.xreplace(dict([(d.exp, p.exp) for p, d in reps])) else: - intex = lambda x: x.is_Pow and x.exp.is_Integer - floex = lambda x: Pow(x.base, Float(x.exp, ''), evaluate=False) - rv = expr.n(n).replace(intex, floex) - - - funcs = [f for f in rv.atoms(Function)] - funcs.sort(key=count_ops) - funcs.reverse() - return rv.subs([(f, f.func(*[nfloat(a, n, exponent) - for a in f.args])) for f in funcs]) + # Pow._eval_evalf special cases Integer exponents so if + # exponent is suppose to be handled we have to do so here + rv = rv.xreplace(Transform( + lambda x: Pow(x.base, Float(x.exp, n)), + lambda x: x.is_Pow and x.exp.is_Integer)) + + return rv.xreplace(Transform( + lambda x: x.func(*nfloat(x.args, n, exponent)), + lambda x: isinstance(x, Function))) from sympy.core.symbol import Dummy diff -Nru python3-sympy-0.7.2/sympy/core/logic.py python3-sympy-0.7.3/sympy/core/logic.py --- python3-sympy-0.7.2/sympy/core/logic.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/core/logic.py 2013-07-13 17:53:32.000000000 +0000 @@ -8,6 +8,7 @@ """ from sympy.core.compatibility import iterable, cmp + def fuzzy_bool(x): """Return True, False or None according to x. @@ -18,6 +19,7 @@ return None return bool(x) + def fuzzy_and(*args): """Return True (all True), False (any False) or None. @@ -50,8 +52,7 @@ return True elif a is False or b is False: return False - elif (len(args) == 1 and iterable(args[0]) or - len(args) > 2): + elif (len(args) == 1 and iterable(args[0]) or len(args) > 2): if len(args) == 1: args = args[0] if args: @@ -60,7 +61,7 @@ ai = fuzzy_bool(ai) if ai is False: return False - if rv: # this will stop updating if a None is ever trapped + if rv: # this will stop updating if a None is ever trapped rv = ai return rv if not args: @@ -68,13 +69,30 @@ elif len(args) == 1: return fuzzy_bool(args[0]) + def fuzzy_not(v): - """'not' in fuzzy logic""" + """ + Not in fuzzy logic + + Will return Not if arg is a boolean value, and None if argument + is None. + + Examples: + + >>> from sympy.core.logic import fuzzy_not + >>> fuzzy_not(True) + False + >>> fuzzy_not(None) + >>> fuzzy_not(False) + True + + """ if v is None: return v else: return not v + class Logic(object): """Logical expression""" # {} 'op' -> LogicClass @@ -91,7 +109,6 @@ def __hash__(self): return hash( (type(self).__name__,) + tuple(self.args) ) - def __eq__(a, b): if not isinstance(b, type(a)): return False @@ -109,7 +126,6 @@ return True return False - def __cmp__(a, b): if type(a) is not type(b): return cmp( str(type(a)), str(type(b)) ) @@ -130,15 +146,17 @@ !a & !b | c """ - lexpr = None # current logical expression + lexpr = None # current logical expression schedop = None # scheduled operation for term in text.split(): # operation symbol if term in '&|': if schedop is not None: - raise ValueError('double op forbidden: "%s %s"' % (term, schedop)) + raise ValueError( + 'double op forbidden: "%s %s"' % (term, schedop)) if lexpr is None: - raise ValueError('%s cannot be in the beginning of expression' % term) + raise ValueError( + '%s cannot be in the beginning of expression' % term) schedop = term continue if term[0] == '!': @@ -152,7 +170,8 @@ # this should be atom if lexpr is not None: - raise ValueError('missing op between "%s" and "%s"' % (lexpr, term)) + raise ValueError( + 'missing op between "%s" and "%s"' % (lexpr, term)) lexpr = term @@ -191,7 +210,6 @@ return Logic.__new__(cls, *sorted(args, key=hash)) - @classmethod def flatten(cls, args): # quick-n-dirty flattening for And and Or @@ -220,7 +238,6 @@ # !(a&b&c ...) == !a | !b | !c ... return Or( *[Not(a) for a in self.args] ) - # (a|b|...) & c == (a&c) | (b&c) | ... def expand(self): @@ -228,7 +245,7 @@ for i in range(len(self.args)): arg = self.args[i] if isinstance(arg, Or): - arest = self.args[:i] + self.args[i+1:] + arest = self.args[:i] + self.args[i + 1:] orterms = [And( *(arest + (a,)) ) for a in arg.args] for j in range(len(orterms)): @@ -249,6 +266,7 @@ # !(a|b|c ...) == !a & !b & !c ... return And( *[Not(a) for a in self.args] ) + class Not(Logic): def __new__(cls, arg): diff -Nru python3-sympy-0.7.2/sympy/core/mod.py python3-sympy-0.7.3/sympy/core/mod.py --- python3-sympy-0.7.2/sympy/core/mod.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/core/mod.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,13 +1,12 @@ from .function import Function -from sympy.core.numbers import Float -from sympy.core.function import expand_mul + class Mod(Function): """Represents a modulo operation on symbolic expressions. Receives two arguments, dividend p and divisor q. - The convention used is the same as python's: the remainder always has the + The convention used is the same as Python's: the remainder always has the same sign as the divisor. Examples @@ -24,16 +23,107 @@ @classmethod def eval(cls, p, q): - from sympy.simplify.simplify import nsimplify - if q.is_Number: - float = not q.is_Rational - pnew = expand_mul(p) - if pnew.is_Number: - float = float or not pnew.is_Rational - if not float: - return pnew % q - return Float(nsimplify(pnew) % nsimplify(q)) - elif pnew.is_Add and pnew.args[0].is_Number: - r, p = pnew.as_two_terms() - p += Mod(r, q) - return Mod(p, q, evaluate=False) + from sympy.core.add import Add + from sympy.core.mul import Mul + from sympy.core.singleton import S + from sympy.core.exprtools import gcd_terms + from sympy.polys.polytools import gcd + + def doit(p, q): + """Try to return p % q if both are numbers or +/-p is known + to be less than q. + """ + + if p == q or p == -q or p.is_Pow and p.exp.is_Integer and p.base == q: + return S.Zero + + if p.is_Number and q.is_Number: + return (p % q) + + # by ratio + r = p/q + try: + d = int(r) + except TypeError: + pass + else: + if type(d) is int: + rv = p - d*q + if rv*q < 0: + rv += q + return rv + + # by differencec + d = p - q + if (d < 0) is True: + if (q < 0) is True: + return d + elif (q > 0) is True: + return p + + rv = doit(p, q) + if rv is not None: + return rv + + # denest + if p.func is cls: + # easy + qinner = p.args[1] + if qinner == q: + return p + # XXX other possibilities? + + # extract gcd; any further simplification should be done by the user + G = gcd(p, q) + if G is not S.One: + p, q = [ + gcd_terms(i/G, clear=False, fraction=False) for i in (p, q)] + pwas, qwas = p, q + + # simplify terms + # (x + y + 2) % x -> Mod(y + 2, x) + if p.is_Add: + args = [] + for i in p.args: + a = cls(i, q) + if a.count(cls) > i.count(cls): + args.append(i) + else: + args.append(a) + if args != list(p.args): + p = Add(*args) + + else: + # handle coefficients if they are not Rational + # since those are not handled by factor_terms + # e.g. Mod(.6*x, .3*y) -> 0.3*Mod(2*x, y) + cp, p = p.as_coeff_Mul() + cq, q = q.as_coeff_Mul() + ok = False + if not cp.is_Rational or not cq.is_Rational: + r = cp % cq + if r == 0: + G *= cq + p *= int(cp/cq) + ok = True + if not ok: + p = cp*p + q = cq*q + + # simple -1 extraction + if p.could_extract_minus_sign() and q.could_extract_minus_sign(): + G, p, q = [-i for i in (G, p, q)] + + # check again to see if p and q can now be handled as numbers + rv = doit(p, q) + if rv is not None: + return rv*G + + # put 1.0 from G on inside + if G.is_Float and G == 1: + p *= G + return cls(p, q, evaluate=False) + elif G.is_Mul and G.args[0].is_Float and G.args[0] == 1: + p = G.args[0]*p + G = Mul._from_args(G.args[1:]) + return G*cls(p, q, evaluate=(p, q) != (pwas, qwas)) diff -Nru python3-sympy-0.7.2/sympy/core/mul.py python3-sympy-0.7.3/sympy/core/mul.py --- python3-sympy-0.7.2/sympy/core/mul.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/core/mul.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,27 +1,88 @@ from collections import defaultdict import operator -from .sympify import sympify -from .basic import Basic, C -from .singleton import S -from .operations import AssocOp -from .cache import cacheit -from .logic import fuzzy_not -from .compatibility import cmp_to_key +from sympy.core.sympify import sympify +from sympy.core.basic import Basic, C +from sympy.core.singleton import S +from sympy.core.operations import AssocOp +from sympy.core.cache import cacheit +from sympy.core.logic import fuzzy_not +from sympy.core.compatibility import cmp_to_key +from sympy.core.expr import Expr from functools import reduce # internal marker to indicate: # "there are still non-commutative objects -- don't forget to process them" + + class NC_Marker: - is_Order = False - is_Mul = False - is_Number = False - is_Poly = False + is_Order = False + is_Mul = False + is_Number = False + is_Poly = False is_commutative = False -class Mul(AssocOp): +# Key for sorting commutative args in canonical order +_args_sortkey = cmp_to_key(Basic.compare) +def _mulsort(args): + # in-place sorting of args + args.sort(key=_args_sortkey) + + +def _unevaluated_Mul(*args): + """Return a well-formed unevaluated Mul: Numbers are collected and + put in slot 0 and args are sorted. Use this when args have changed + but you still want to return an unevaluated Mul. + + Examples + ======== + + >>> from sympy.core.mul import _unevaluated_Mul as uMul + >>> from sympy import S, sqrt, Mul + >>> from sympy.abc import x + >>> a = uMul(*[S(3.0), x, S(2)]) + >>> a.args[0] + 6.00000000000000 + >>> a.args[1] + x + + Beyond the Number being in slot 0, there is no other flattening of + arguments, but two unevaluated Muls with the same arguments will + always compare as equal during testing: + + >>> m = uMul(sqrt(2), sqrt(3)) + >>> m == uMul(sqrt(3), sqrt(2)) + True + >>> m == Mul(*m.args) + False + + """ + args = list(args) + newargs = [] + ncargs = [] + co = S.One + while args: + a = args.pop() + if a.is_Mul: + c, nc = a.args_cnc() + args.extend(c) + if nc: + ncargs.append(Mul._from_args(nc)) + elif a.is_Number: + co *= a + else: + newargs.append(a) + _mulsort(newargs) + if co is not S.One: + newargs.insert(0, co) + if ncargs: + newargs.append(Mul._from_args(ncargs)) + return Mul._from_args(newargs) + + +class Mul(Expr, AssocOp): __slots__ = [] @@ -30,9 +91,6 @@ #identity = S.One # cyclic import, so defined in numbers.py - # Key for sorting commutative args in canonical order - _args_sortkey = cmp_to_key(Basic.compare) - @classmethod def flatten(cls, seq): """Return commutative, noncommutative and order arguments by @@ -111,6 +169,7 @@ Removal of 1 from the sequence is already handled by AssocOp.__new__. """ + rv = None if len(seq) == 2: a, b = seq @@ -119,25 +178,22 @@ assert not a is S.One if a and a.is_Rational: r, b = b.as_coeff_Mul() - a *= r - if b.is_Mul: - bargs, nc = b.args_cnc() - rv = bargs, nc, None - if a is not S.One: - bargs.insert(0, a) - - elif b.is_Add and b.is_commutative: - if a is S.One: - rv = [b], [], None - else: - r, b = b.as_coeff_Add() - bargs = [_keep_coeff(a, bi) for bi in Add.make_args(b)] - bargs.sort(key=hash) - ar = a*r - if ar: - bargs.insert(0, ar) - bargs = [Add._from_args(bargs)] - rv = bargs, [], None + if b.is_Add: + if r is not S.One: # 2-arg hack + # leave the Mul as a Mul + rv = [Mul(a*r, b, evaluate=False)], [], None + elif b.is_commutative: + if a is S.One: + rv = [b], [], None + else: + r, b = b.as_coeff_Add() + bargs = [_keep_coeff(a, bi) for bi in Add.make_args(b)] + _addsort(bargs) + ar = a*r + if ar: + bargs.insert(0, ar) + bargs = [Add._from_args(bargs)] + rv = bargs, [], None if rv: return rv @@ -150,23 +206,19 @@ coeff = S.One # standalone term # e.g. 3 * ... - iu = [] # ImaginaryUnits, I - c_powers = [] # (base,exp) n # e.g. (x,n) for x num_exp = [] # (num-base, exp) y # e.g. (3, y) for ... * 3 * ... - neg1e = 0 # exponent on -1 extracted from Number-based Pow + neg1e = S.Zero # exponent on -1 extracted from Number-based Pow and I pnum_rat = {} # (num-base, Rat-exp) 1/2 # e.g. (3, 1/2) for ... * 3 * ... order_symbols = None - - # --- PART 1 --- # # "collect powers and coeff": @@ -178,7 +230,6 @@ # o pnum_rat # # NOTE: this is optimized for all-objects-are-commutative case - for o in seq: # O(x) if o.is_Order: @@ -208,7 +259,7 @@ if o is S.NaN or coeff is S.ComplexInfinity and o is S.Zero: # we know for sure the result will be nan return [S.NaN], [], None - elif coeff.is_Number: # it could be zoo + elif coeff.is_Number: # it could be zoo coeff *= o if coeff is S.NaN: # we know for sure the result will be nan @@ -226,7 +277,7 @@ continue elif o is S.ImaginaryUnit: - iu.append(o) + neg1e += S.Half continue elif o.is_commutative: @@ -236,27 +287,33 @@ # y # 3 - if o.is_Pow and b.is_Number: + if o.is_Pow: + if b.is_Number: - # get all the factors with numeric base so they can be - # combined below, but don't combine negatives unless - # the exponent is an integer - if e.is_Rational: - if e.is_Integer: - coeff *= Pow(b, e) # it is an unevaluated power + # get all the factors with numeric base so they can be + # combined below, but don't combine negatives unless + # the exponent is an integer + if e.is_Rational: + if e.is_Integer: + coeff *= Pow(b, e) # it is an unevaluated power + continue + elif e.is_negative: # also a sign of an unevaluated power + seq.append(Pow(b, e)) + continue + elif b.is_negative: + neg1e += e + b = -b + if b is not S.One: + pnum_rat.setdefault(b, []).append(e) continue - elif e.is_negative: # also a sign of an unevaluated power - seq.append(Pow(b, e)) + elif b.is_positive or e.is_integer: + num_exp.append((b, e)) continue - elif b.is_negative: - neg1e += e - b = -b - if b is not S.One: - pnum_rat.setdefault(b, []).append(e) - continue - elif b.is_positive or e.is_integer: - num_exp.append((b, e)) + + elif b is S.ImaginaryUnit and e.is_Rational: + neg1e += e/2 continue + c_powers.append((b, e)) # NON-COMMUTATIVE @@ -275,14 +332,14 @@ # b c b+c # try to combine last terms: a * a -> a o1 = nc_part.pop() - b1,e1 = o1.as_base_exp() - b2,e2 = o.as_base_exp() + b1, e1 = o1.as_base_exp() + b2, e2 = o.as_base_exp() new_exp = e1 + e2 # Only allow powers to combine if the new exponent is # not an Add. This allow things like a**2*b**3 == a**5 # if a.is_commutative == False, but prohibits # a**x*a**y and x**a*x**b from combining (x,y commute). - if b1==b2 and (not new_exp.is_Add): + if b1 == b2 and (not new_exp.is_Add): o12 = b1 ** new_exp # now o12 could be a commutative object @@ -296,21 +353,6 @@ nc_part.append(o1) nc_part.append(o) - # handle the ImaginaryUnits - if iu: - if len(iu) == 1: - c_powers.append((iu[0], S.One)) - else: - # a product of I's has one of 4 values; select that value - # based on the length of iu: - # len(iu) % 4 of (0, 1, 2, 3) has a corresponding value of - # (1, I,-1,-I) - niu = len(iu) % 4 - if niu % 2: - c_powers.append((S.ImaginaryUnit, S.One)) - if niu in (2, 3): - coeff = -coeff - # We do want a combined exponent if it would not be an Add, such as # y 2y 3y # x * x -> x @@ -326,7 +368,7 @@ # gather exponents of common bases... def _gather(c_powers): new_c_powers = [] - common_b = {} # b:e + common_b = {} # b:e for b, e in c_powers: co = e.as_coeff_Mul() common_b.setdefault(b, {}).setdefault(co[1], []).append(co[0]) @@ -402,15 +444,15 @@ # extract gcd of bases in num_rat # 2**(1/3)*6**(1/4) -> 2**(1/3+1/4)*3**(1/4) - pnew = {} - i = 0 # steps through num_rat which may grow + pnew = defaultdict(list) + i = 0 # steps through num_rat which may grow while i < len(num_rat): bi, ei = num_rat[i] grow = [] for j in range(i + 1, len(num_rat)): bj, ej = num_rat[j] - g = igcd(bi, bj) - if g != 1: + g = bi.gcd(bj) + if g is not S.One: # 4**r1*6**r2 -> 2**(r1+r2) * 2**r1 * 3**r2 # this might have a gcd with something else e = ei + ej @@ -418,14 +460,14 @@ coeff *= Pow(g, e) else: if e.p > e.q: - e_i, ep = divmod(e.p, e.q) # change e in place + e_i, ep = divmod(e.p, e.q) # change e in place coeff *= Pow(g, e_i) e = Rational(ep, e.q) grow.append((g, e)) # update the jth item - num_rat[j] = (bj//g, ej) + num_rat[j] = (bj/g, ej) # update bi that we are checking with - bi = bi//g + bi = bi/g if bi is S.One: break if bi is not S.One: @@ -433,12 +475,14 @@ if obj.is_Number: coeff *= obj else: - if obj.is_Mul: # sqrt(12) -> 2*sqrt(3) - c, obj = obj.args # expecting only 2 args - coeff *= c - assert obj.is_Pow - bi, ei = obj.args - pnew.setdefault(ei, []).append(bi) + # changes like sqrt(12) -> 2*sqrt(3) + for obj in Mul.make_args(obj): + if obj.is_Number: + coeff *= obj + else: + assert obj.is_Pow + bi, ei = obj.args + pnew[ei].append(bi) num_rat.extend(grow) i += 1 @@ -447,23 +491,29 @@ for e, b in pnew.items(): pnew[e] = Mul(*b) - # see if there is a base with matching coefficient - # that the -1 can be joined with + # handle -1 and I if neg1e: - p = Pow(S.NegativeOne, neg1e) - if p.is_Number: - coeff *= p - else: - c, p = p.as_coeff_Mul() - coeff *= c - if p.is_Pow and p.base is S.NegativeOne: - neg1e = p.exp + # treat I as (-1)**(1/2) and compute -1's total exponent + p, q = neg1e.as_numer_denom() + # if the integer part is odd, extract -1 + n, p = divmod(p, q) + if n % 2: + coeff = -coeff + # if it's a multiple of 1/2 extract I + if q == 2: + c_part.append(S.ImaginaryUnit) + elif p: + # see if there is any positive base this power of + # -1 can join + neg1e = Rational(p, q) for e, b in pnew.items(): if e == neg1e and b.is_positive: pnew[e] = -b break else: - c_part.append(p) + # keep it separate; we've already evaluated it as + # much as possible so evaluate=False + c_part.append(Pow(S.NegativeOne, neg1e, evaluate=False)) # add all the pnew powers c_part.extend([Pow(b, e) for e, b in pnew.items()]) @@ -502,109 +552,41 @@ return [coeff], [], order_symbols # order commutative part canonically - c_part.sort(key=cls._args_sortkey) + _mulsort(c_part) # current code expects coeff to be always in slot-0 if coeff is not S.One: c_part.insert(0, coeff) - # we are done - if len(c_part)==2 and c_part[0].is_Number and c_part[1].is_Add: + if (not nc_part and len(c_part) == 2 and c_part[0].is_Number and + c_part[1].is_Add): # 2*(1+a) -> 2 + 2 * a coeff = c_part[0] c_part = [Add(*[coeff*f for f in c_part[1].args])] return c_part, nc_part, order_symbols - def _eval_power(b, e): # don't break up NC terms: (A*B)**3 != A**3*B**3, it is A*B*A*B*A*B - coeff, b = b.as_coeff_Mul() - bc, bnc = b.args_cnc() + cargs, nc = b.args_cnc(split_1=False) - done = [Pow(Mul._from_args(bnc), e, evaluate=False) if bnc else S.One] + if e.is_Integer: + return Mul(*[Pow(b, e, evaluate=False) for b in cargs]) * \ + Pow(Mul._from_args(nc), e, evaluate=False) - if e.is_Number: - if e.is_Integer: - # (a*b)**2 -> a**2 * b**2 - return Mul(*([s**e for s in [coeff] + bc] + done)) - - if e.is_Rational or e.is_Float: - unk = [] - nonneg = [] - neg = [] - iu = [] - for bi in bc: - if bi.is_polar: - nonneg.append(bi) - elif bi.is_negative is not None: - if bi.is_negative: - neg.append(bi) - elif bi.is_nonnegative: - nonneg.append(bi) - elif bi is S.ImaginaryUnit: - iu.append(bi) - else: - unk.append(bi) - else: - unk.append(bi) - - if iu: - niu = len(iu) % 4 - i = S.ImaginaryUnit if niu % 2 else S.One - if niu in (2, 3): - coeff = -coeff - if i is S.ImaginaryUnit: - if unk or e.is_Float: - unk.append(i) - else: - if coeff.is_negative and e.is_Rational: - coeff = -coeff - ie = Rational(4*e.q - e.p, 2*e.q) - done.append(Pow(-1, ie)) - else: - done.append(i**e) - - if len(unk) == len(bc) or len(neg) == len(bc) == 1: - # if all terms were unknown there is nothing to pull - # out except maybe the coeff; if there is a single - # negative term, this is the base case which cannot - # be processed further - if coeff.is_negative: - coeff *= -1 - bc[0] = -bc[0] - if coeff is S.One: - return None - return Mul(*([Pow(coeff, e), Pow(Mul(*bc), e)] + done)) - - # otherwise return the new expression expanding out the known - # terms; those that are not known can be expanded out with - # expand_power_base() but this will introduce a lot of - # "garbage" that is needed to keep one on the same branch as - # the unexpanded expression. The negatives are brought out - # with a negative sign added and a negative left behind in the - # unexpanded terms if there were an odd number of negatives. - if coeff.is_negative: - coeff = -coeff - neg.append(S.NegativeOne) - if neg: - neg = [-w for w in neg] - if len(neg) % 2: - unk.append(S.NegativeOne) + p = Pow(b, e, evaluate=False) - done.extend([Pow(s, e) for s in nonneg + neg + [coeff, Mul(*unk)]]) - return Mul(*done) + if e.is_Rational or e.is_Float: + return p._eval_expand_power_base() - if e.is_even and coeff.is_negative: - return Pow(-coeff, e)*Pow(b, e) + return p @classmethod def class_key(cls): return 3, 0, cls.__name__ - def _eval_evalf(self, prec): c, m = self.as_coeff_Mul() if c is S.NegativeOne: @@ -681,17 +663,29 @@ def as_real_imag(self, deep=True, **hints): other = [] - coeff = S(1) + coeff = S.One for a in self.args: - if a.is_real: + if a.is_real or a.is_imaginary: coeff *= a + elif a.is_commutative: + # search for complex conjugate pairs: + for i, x in enumerate(other): + if x == a.conjugate(): + coeff *= C.Abs(x)**2 + del other[i] + break + else: + other.append(a) else: other.append(a) m = Mul(*other) if hints.get('ignore') == m: return None else: - return (coeff*C.re(m), coeff*C.im(m)) + if coeff.is_real: + return (coeff*C.re(m), coeff*C.im(m)) + else: + return (-C.im(coeff)*C.im(m), C.im(coeff)*C.re(m)) @staticmethod def _expandsums(sums): @@ -710,19 +704,21 @@ terms = [Mul(a, b) for a in left for b in right] added = Add(*terms) - return Add.make_args(added) #it may have collapsed down to one term + return Add.make_args(added) # it may have collapsed down to one term def _eval_expand_mul(self, **hints): - from sympy import fraction, expand_mul + from sympy import fraction # Handle things like 1/(x*(x + 1)), which are automatically converted # to 1/x*1/(x + 1) expr = self n, d = fraction(expr) if d.is_Mul: - expr = n/d._eval_expand_mul(**hints) + n, d = [i._eval_expand_mul(**hints) if i.is_Mul else i + for i in (n, d)] + expr = n/d if not expr.is_Mul: - return expand_mul(expr, deep=False) + return expr plain, sums, rewrite = [], [], False for factor in expr.args: @@ -733,7 +729,7 @@ if factor.is_commutative: plain.append(factor) else: - sums.append(Basic(factor)) # Wrapper + sums.append(Basic(factor)) # Wrapper if not rewrite: return expr @@ -758,7 +754,7 @@ t = terms[i].diff(s) if t is S.Zero: continue - factors.append(Mul(*(terms[:i]+[t]+terms[i+1:]))) + factors.append(Mul(*(terms[:i] + [t] + terms[i + 1:]))) return Add(*factors) def _matches_simple(self, expr, repl_dict): @@ -770,12 +766,30 @@ return terms[0].matches(newexpr, repl_dict) return - def matches(self, expr, repl_dict={}): + def matches(self, expr, repl_dict={}, old=False): expr = sympify(expr) if self.is_commutative and expr.is_commutative: - return AssocOp._matches_commutative(self, expr, repl_dict) - # todo for commutative parts, until then use the default matches method for non-commutative products - return self._matches(expr, repl_dict) + return AssocOp._matches_commutative(self, expr, repl_dict, old) + elif self.is_commutative is not expr.is_commutative: + return None + c1, nc1 = self.args_cnc() + c2, nc2 = expr.args_cnc() + repl_dict = repl_dict.copy() + if c1: + if not c2: + c2 = [1] + a = Mul(*c1) + if isinstance(a, AssocOp): + repl_dict = a._matches_commutative(Mul(*c2), repl_dict, old) + else: + repl_dict = a.matches(Mul(*c2), repl_dict) + if repl_dict: + a = Mul(*nc1) + if isinstance(a, Mul): + repl_dict = a._matches(Mul(*nc2), repl_dict) + else: + repl_dict = a.matches(Mul(*nc2), repl_dict) + return repl_dict or None def _matches(self, expr, repl_dict={}): # weed out negative one prefixes @@ -789,7 +803,8 @@ return b.matches(-expr, repl_dict) expr = sympify(expr) if expr.is_Mul and expr.args[0] is S.NegativeOne: - expr = -expr; sign = -sign + expr = -expr + sign = -sign if not expr.is_Mul: # expr can only match if it matches b and a matches +/- 1 @@ -799,7 +814,7 @@ return a.matches(Rational(sign), repl_dict) # do more expensive match dd = b.matches(expr, repl_dict) - if dd == None: + if dd is None: return None dd = a.matches(Rational(sign), dd) return dd @@ -832,7 +847,6 @@ return None return d - @staticmethod def _combine_inverse(lhs, rhs): """ @@ -841,6 +855,7 @@ """ if lhs == rhs: return S.One + def check(l, r): if l.is_Float and r.is_comparable: # if both objects are added to 0 they will share the same "normalization" @@ -856,22 +871,19 @@ for x in rhs.args: if x in a: a.remove(x) + elif -x in a: + a.remove(-x) + b.append(-1) else: b.append(x) return Mul(*a)/Mul(*b) return lhs/rhs def as_powers_dict(self): - d = defaultdict(list) + d = defaultdict(int) for term in self.args: b, e = term.as_base_exp() - d[b].append(e) - for b, e in d.items(): - if len(e) == 1: - e = e[0] - else: - e = Add(*e) - d[b] = e + d[b] += e return d def as_numer_denom(self): @@ -902,14 +914,31 @@ def _eval_is_rational_function(self, syms): return all(term._eval_is_rational_function(syms) for term in self.args) + def _eval_is_algebraic_expr(self, syms): + return all(term._eval_is_algebraic_expr(syms) for term in self.args) + _eval_is_bounded = lambda self: self._eval_template_is_attr('is_bounded') - _eval_is_integer = lambda self: self._eval_template_is_attr('is_integer', when_multiple=None) - _eval_is_commutative = lambda self: self._eval_template_is_attr('is_commutative') + _eval_is_commutative = lambda self: self._eval_template_is_attr( + 'is_commutative') + _eval_is_rational = lambda self: self._eval_template_is_attr('is_rational', + when_multiple=None) + + def _eval_is_integer(self): + is_rational = self.is_rational + + if is_rational: + n, d = self.as_numer_denom() + if d is S.One: + return True + elif d is S(2): + return n.is_even + elif is_rational is False: + return False def _eval_is_polar(self): has_polar = any(arg.is_polar for arg in self.args) return has_polar and \ - all(arg.is_polar or arg.is_positive for arg in self.args) + all(arg.is_polar or arg.is_positive for arg in self.args) # I*I -> R, I*I*I -> -I def _eval_is_real(self): @@ -956,7 +985,6 @@ return (im_count % 2 == 1) - def _eval_is_hermitian(self): nc_count = 0 im_count = 0 @@ -1011,7 +1039,6 @@ return (im_count % 2 == 1) - def _eval_is_irrational(self): for t in self.args: a = t.is_irrational @@ -1113,14 +1140,19 @@ if is_integer: r = True for t in self.args: - if t.is_even: - return False - if t.is_odd is None: - r = None + if not t.is_integer: + return None + elif t.is_even: + r = False + elif t.is_integer: + if r is False: + pass + elif t.is_odd is None: + r = None return r # !integer -> !odd - elif is_integer == False: + elif is_integer is False: return False def _eval_is_even(self): @@ -1129,16 +1161,24 @@ if is_integer: return fuzzy_not(self._eval_is_odd()) - elif is_integer == False: + elif is_integer is False: return False def _eval_subs(self, old, new): - from sympy import sign, Dummy, multiplicity + from sympy.functions.elementary.complexes import sign + from sympy.ntheory.factor_ import multiplicity from sympy.simplify.simplify import powdenest, fraction if not old.is_Mul: return None + # try keep replacement literal so -2*x doesn't replace 4*x + if old.args[0].is_Number and old.args[0] < 0: + if self.args[0].is_Number: + if self.args[0] < 0: + return self._subs(-old, -new) + return None + def base_exp(a): # if I and -1 are in a Mul, they get both end up with # a -1 base (see issue 3322); all we want here are the @@ -1183,7 +1223,6 @@ but not vice versa, and 2/5 does not divide 1/3) then return the integer number of times it divides, else return 0. """ - if not b.q % a.q or not a.q % b.q: return int(a/b) return 0 @@ -1226,18 +1265,13 @@ # then co_self in c is replaced by (3/5)**2 and co_residual # is 2*(1/7)**2 - if co_xmul and co_xmul.is_Rational: - n_old, d_old = co_old.as_numer_denom() - n_self, d_self = co_self.as_numer_denom() - def _multiplicity(p, n): - p = abs(p) - if p is S.One: - return S.Infinity - return multiplicity(p, abs(n)) - mult = S(min(_multiplicity(n_old, n_self), - _multiplicity(d_old, d_self))) + if co_xmul and co_xmul.is_Rational and abs(co_old) != 1: + mult = S(multiplicity(abs(co_old), co_self)) c.pop(co_self) - c[co_old] = mult + if co_old in c: + c[co_old] += mult + else: + c[co_old] = mult co_residual = co_self/co_old**mult else: co_residual = 1 @@ -1245,25 +1279,20 @@ # do quick tests to see if we can't succeed ok = True - if ( + if len(old_nc) > len(nc): # more non-commutative terms - len(old_nc) > len(nc)): ok = False - elif ( + elif len(old_c) > len(c): # more commutative terms - len(old_c) > len(c)): ok = False - elif ( + elif set(i[0] for i in old_nc).difference(set(i[0] for i in nc)): # unmatched non-commutative bases - set(_[0] for _ in old_nc).difference(set(_[0] for _ in nc))): ok = False - elif ( + elif set(old_c).difference(set(c)): # unmatched commutative terms - set(old_c).difference(set(c))): ok = False - elif ( + elif any(sign(c[b]) != sign(old_c[b]) for b in old_c): # differences in sign - any(sign(c[b]) != sign(old_c[b]) for b in old_c)): ok = False if not ok: return rv @@ -1286,7 +1315,7 @@ else: ncdid = 0 # number of nc replacements we did take = len(old_nc) # how much to look at each time - limit = cdid or S.Infinity # max number that we can take + limit = cdid or S.Infinity # max number that we can take failed = [] # failed terms will need subs if other terms pass i = 0 while limit and i + take <= len(nc): @@ -1401,7 +1430,6 @@ terms = [t.nseries(x, n=n, logx=logx) for t in self.args] return powsimp(Mul(*terms).expand(), combine='exp', deep=True) - def _eval_as_leading_term(self, x): return Mul(*[t.as_leading_term(x) for t in self.args]) @@ -1467,6 +1495,7 @@ def _sorted_args(self): return self.as_ordered_factors() + def prod(a, start=1): """Return product of elements of a. Start with int 1 so if only ints are included then an int result is returned. @@ -1491,13 +1520,16 @@ """ return reduce(operator.mul, a, start) -def _keep_coeff(coeff, factors, clear=True): + +def _keep_coeff(coeff, factors, clear=True, sign=False): """Return ``coeff*factors`` unevaluated if necessary. - If clear is False, do not keep the coefficient as a factor + If ``clear`` is False, do not keep the coefficient as a factor if it can be distributed on a single factor such that one or more terms will still have integer coefficients. + If ``sign`` is True, allow a coefficient of -1 to remain factored out. + Examples ======== @@ -1511,6 +1543,10 @@ x/2 + 1 >>> _keep_coeff(S.Half, (x + 2)*y, clear=False) y*(x + 2)/2 + >>> _keep_coeff(S(-1), x + y) + -x - y + >>> _keep_coeff(S(-1), x + y, sign=True) + -(x + y) """ if not coeff.is_Number: @@ -1518,9 +1554,9 @@ factors, coeff = coeff, factors else: return coeff*factors - if coeff == 1: + if coeff is S.One: return factors - elif coeff == -1: # don't keep sign? + elif coeff is S.NegativeOne and not sign: return -factors elif factors.is_Add: if not clear and coeff.is_Rational and coeff.q != 1: @@ -1543,6 +1579,18 @@ else: return coeff*factors -from .numbers import Rational, igcd + +def expand_2arg(e): + from sympy.simplify.simplify import bottom_up + def do(e): + if e.is_Mul: + c, r = e.as_coeff_Mul() + if c.is_Number and r.is_Add: + return _unevaluated_Add(*[c*ri for ri in r.args]) + return e + return bottom_up(e, do) + + +from .numbers import Rational from .power import Pow -from .add import Add +from .add import Add, _addsort, _unevaluated_Add diff -Nru python3-sympy-0.7.2/sympy/core/multidimensional.py python3-sympy-0.7.3/sympy/core/multidimensional.py --- python3-sympy-0.7.2/sympy/core/multidimensional.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/core/multidimensional.py 2013-07-13 17:53:32.000000000 +0000 @@ -5,6 +5,7 @@ """ from sympy.core.decorators import wraps + def apply_on_element(f, args, kwargs, n): """ Returns a structure with the same dimension as the specified argument, @@ -34,6 +35,7 @@ # all basic elements. return list(map(f_reduced, structure)) + def iter_copy(structure): """ Returns a copy of an iterable object (also copying all embedded iterables). @@ -46,6 +48,7 @@ l.append(i) return l + def structure_copy(structure): """ Returns a copy of the given structure (numpy-array, list, iterable, ..). @@ -54,25 +57,31 @@ return structure.copy() return iter_copy(structure) + class vectorize: """ Generalizes a function taking scalars to accept multidimensional arguments. - For example:: - - (1) @vectorize(0) - def sin(x): - .... - - sin([1, x, y]) - --> [sin(1), sin(x), sin(y)] + For example - (2) @vectorize(0,1) - def diff(f(y), y) - .... + >>> from sympy import diff, sin, symbols, Function + >>> from sympy.core.multidimensional import vectorize + >>> x, y, z = symbols('x y z') + >>> f, g, h = list(map(Function, 'fgh')) + + >>> @vectorize(0) + ... def vsin(x): + ... return sin(x) + + >>> vsin([1, x, y]) + [sin(1), sin(x), sin(y)] + + >>> @vectorize(0, 1) + ... def vdiff(f, y): + ... return diff(f, y) - diff([f(x,y,z),g(x,y,z),h(x,y,z)], [x,y,z]) - --> [[d/dx f, d/dy f, d/dz f], [d/dx g, d/dy g, d/dz g], [d/dx h, d/dy h, d/dz h]] + >>> vdiff([f(x, y, z), g(x, y, z), h(x, y, z)], [x, y, z]) + [[Derivative(f(x, y, z), x), Derivative(f(x, y, z), y), Derivative(f(x, y, z), z)], [Derivative(g(x, y, z), x), Derivative(g(x, y, z), y), Derivative(g(x, y, z), z)], [Derivative(h(x, y, z), x), Derivative(h(x, y, z), y), Derivative(h(x, y, z), z)]] """ def __init__(self, *mdargs): """ @@ -82,7 +91,7 @@ If no argument is given, everything is treated multidimensional. """ for a in mdargs: - assert isinstance(a, (int,str)) + assert isinstance(a, (int, str)) self.mdargs = mdargs def __call__(self, f): @@ -102,7 +111,7 @@ for n in mdargs: if isinstance(n, int): - if n>=arglength: + if n >= arglength: continue entry = args[n] is_arg = True diff -Nru python3-sympy-0.7.2/sympy/core/numbers.py python3-sympy-0.7.3/sympy/core/numbers.py --- python3-sympy-0.7.2/sympy/core/numbers.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/core/numbers.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,40 +1,48 @@ +import decimal +import math +import re as regex +from collections import defaultdict + from .core import C from .sympify import converter, sympify, _sympify, SympifyError -from .basic import Basic from .singleton import S, Singleton from .expr import Expr, AtomicExpr from .decorators import _sympifyit, deprecated from .cache import cacheit, clear_cache -from sympy.core.compatibility import as_int +from sympy.core.compatibility import as_int, HAS_GMPY, SYMPY_INTS import sympy.mpmath as mpmath import sympy.mpmath.libmp as mlib from sympy.mpmath.libmp import mpf_pow, mpf_pi, mpf_e, phi_fixed from sympy.mpmath.ctx_mp import mpnumeric -from sympy.mpmath.libmp.libmpf import fnan, _normalize as mpf_normalize - -import decimal -import math -import re as regex -from collections import defaultdict +from sympy.mpmath.libmp.libmpf import ( + finf as _mpf_inf, fninf as _mpf_ninf, + fnan as _mpf_nan, fzero as _mpf_zero, _normalize as mpf_normalize, + prec_to_dps) rnd = mlib.round_nearest _LOG2 = math.log(2) + def mpf_norm(mpf, prec): """Return the mpf tuple normalized appropriately for the indicated - precision. - - This also contains a portion of code to not return zero if - the mantissa is 0 since it is zero for mpf's +inf, -inf and - nan, too. + precision after doing a check to see if zero should be returned or + not when the mantissa is 0. ``mpf_normlize`` always assumes that this + is zero, but it may not be since the mantissa for mpf's values "+inf", + "-inf" and "nan" have a mantissa of zero, too. + + Note: this is not intended to validate a given mpf tuple, so sending + mpf tuples that were not created by mpmath may produce bad results. This + is only a wrapper to ``mpf_normalize`` which provides the check for non- + zero mpfs that have a 0 for the mantissa. """ sign, man, expt, bc = mpf if not man: # hack for mpf_normalize which does not do this; # it assumes that if man is zero the result is 0 + # (see issue 3540) if not bc: - return mlib.fzero + return _mpf_zero else: # don't change anything; this should already # be a well formed mpf tuple @@ -44,6 +52,8 @@ # TODO: we should use the warnings module _errdict = {"divide": False} + + def seterr(divide=False): """ Should sympy raise an exception on 0/0 or return a nan? @@ -55,25 +65,39 @@ clear_cache() _errdict["divide"] = divide + +def _as_integer_ratio(p): + """compatibility implementation for python < 2.6""" + neg_pow, man, expt, bc = getattr(p, '_mpf_', mpmath.mpf(p)._mpf_) + p = [1, -1][neg_pow % 2]*man + if expt < 0: + q = 2**-expt + else: + q = 1 + p *= 2**expt + return int(p), int(q) + + def _decimal_to_Rational_prec(dec): """Convert an ordinary decimal instance to a Rational.""" # _is_special is needed for Python 2.5 support; is_finite for Python 3.3 # support nonfinite = getattr(dec, '_is_special', None) if nonfinite is None: - nonfinite = not dec.is_finite() + nonfinite = not dec.is_finite() # Note, this is_finite is not SymPy's if nonfinite: raise TypeError("dec must be finite, got %s." % dec) s, d, e = dec.as_tuple() prec = len(d) - if int(dec) == dec: - rv = Rational(int(dec)) + if e >= 0: # it's an integer + rv = Integer(int(dec)) else: s = (-1)**s d = sum([di*10**i for i, di in enumerate(reversed(d))]) rv = Rational(s*d, 10**-e) return rv, prec + def _literal_float(f): """Return True if n can be interpreted as a floating point number.""" pat = r"[-+]?((\d*\.\d+)|(\d+\.?))(eE[-+]?\d+)?" @@ -83,6 +107,8 @@ _gcdcache = {} # TODO caching with decorator, but not to degrade performance + + def igcd(a, b): """Computes positive, integer greatest common divisor of two numbers. @@ -90,7 +116,7 @@ improve speed, igcd() has its own caching mechanism implemented. """ try: - return _gcdcache[(a,b)] + return _gcdcache[(a, b)] except KeyError: a, b = as_int(a), as_int(b) @@ -103,9 +129,10 @@ else: a = abs(a or b) - _gcdcache[(a,b)] = a + _gcdcache[(a, b)] = a return a + def ilcm(a, b): """Computes integer least common multiple of two numbers. """ if a == 0 and b == 0: @@ -113,6 +140,7 @@ else: return a*b // igcd(a, b) + def igcdex(a, b): """Returns x, y, g such that g = x*a + y*b = gcd(a, b). @@ -151,10 +179,11 @@ while b: (c, q) = (a % b, a // b) - (a, b, r, s, x, y) = (b, c, x-q*r, y-q*s, r, s) + (a, b, r, s, x, y) = (b, c, x - q*r, y - q*s, r, s) return (x*x_sign, y*y_sign, a) + class Number(AtomicExpr): """ Represents any kind of number in sympy. @@ -168,8 +197,6 @@ Rational(1) + sqrt(Rational(2)) """ is_commutative = True - is_bounded = True - is_finite = True is_number = True __slots__ = [] @@ -181,11 +208,11 @@ def __new__(cls, *obj): if len(obj) == 1: - obj=obj[0] + obj = obj[0] if isinstance(obj, Number): return obj - if isinstance(obj, int): + if isinstance(obj, SYMPY_INTS): return Integer(obj) if isinstance(obj, tuple) and len(obj) == 2: return Rational(*obj) @@ -196,7 +223,7 @@ if isinstance(val, Number): return val else: - raise ValueError('String "%s" does not denote a Number'%obj) + raise ValueError('String "%s" does not denote a Number' % obj) if isinstance(obj, Number): return obj msg = "expected str|int|long|float|Decimal|Number object but got %r" @@ -217,7 +244,7 @@ return Tuple(*divmod(self.p, other.p)) else: rat = self/other - w = sign(rat)*int(abs(rat)) # = rat.floor() + w = sign(rat)*int(abs(rat)) # = rat.floor() r = self - other*w #w*other + r == self return Tuple(w, r) @@ -235,7 +262,7 @@ def _as_mpf_val(self, prec): """Evaluation of mpf tuple accurate to at least prec bits.""" - raise NotImplementedError('%s needs ._as_mpf_val() method' % \ + raise NotImplementedError('%s needs ._as_mpf_val() method' % (self.__class__.__name__)) def _eval_evalf(self, prec): @@ -258,7 +285,13 @@ def _eval_subs(self, old, new): if old == -self: return -new - return self # there is no other possibility + return self # there is no other possibility + + def _eval_is_bounded(self): + return True + + def _eval_is_finite(self): + return True @classmethod def class_key(cls): @@ -296,16 +329,16 @@ if other is S.NaN: return S.NaN elif other is S.Infinity: - if self == 0: + if self.is_zero: return S.NaN - elif self > 0: + elif self.is_positive: return S.Infinity else: return S.NegativeInfinity elif other is S.NegativeInfinity: - if self == 0: + if self.is_zero: return S.NaN - elif self > 0: + elif self.is_positive: return S.NegativeInfinity else: return S.Infinity @@ -322,7 +355,6 @@ __truediv__ = __div__ - def __eq__(self, other): raise NotImplementedError('%s needs .__eq__() method' % (self.__class__.__name__)) @@ -351,10 +383,6 @@ def is_constant(self, *wrt, **flags): return True - @property - def is_number(self): - return True - def as_coeff_mul(self, *deps): # a -> c*t if self.is_Rational: @@ -369,20 +397,6 @@ return self, tuple() return S.Zero, (self,) - def gcd(self, other): - """Compute greatest common divisor of input arguments. """ - return S.One - - def lcm(self, other): - """Compute least common multiple of input arguments. """ - other = _sympify(other) - return self*other - - def cofactors(self, other): - """Compute GCD and cofactors of input arguments. """ - other = _sympify(other) - return S.One, self, other - def as_coeff_Mul(self, rational=False): """Efficiently extract the coefficient of a product. """ if rational and not self.is_Rational: @@ -393,6 +407,22 @@ """Efficiently extract the coefficient of a summation. """ return self, S.Zero + def gcd(self, other): + """Compute GCD of `self` and `other`. """ + from sympy.polys import gcd + return gcd(self, other) + + def lcm(self, other): + """Compute LCM of `self` and `other`. """ + from sympy.polys import lcm + return lcm(self, other) + + def cofactors(self, other): + """Compute GCD and cofactors of `self` and `other`. """ + from sympy.polys import cofactors + return cofactors(self, other) + + class Float(Number): """ Represents a floating point number. It is capable of representing @@ -402,12 +432,10 @@ ======== >>> from sympy import Float - >>> Float(3.5) # convert from Python float or int + >>> Float(3.5) 3.50000000000000 - >>> Float(3) # reverts to Integer - 3 - >>> Float(3, '') # forced to Float - 3. + >>> Float(3) + 3.00000000000000 Floats can be created from a string representations of Python floats to force ints to Float or to enter high-precision (> 15 significant @@ -428,6 +456,19 @@ 123456789.123456 >>> Float('12e-3', '') 0.012 + >>> Float(3, '') + 3. + + If a number is written in scientific notation, only the digits before the + exponent are considered significant if a decimal appears, otherwise the + "e" signifies only how to move the decimal: + + >>> Float('60.e2', '') # 2 digits significant + 6.0e+3 + >>> Float('60e2', '') # 4 digits significant + 6000. + >>> Float('600e-2', '') # 3 digits significant + 6.00 Notes ===== @@ -479,7 +520,7 @@ >>> def show(f): # binary rep of Float ... from sympy import Mul, Pow ... s, m, e, b = f._mpf_ - ... v = Mul(m, Pow(2, e, evaluate=False), evaluate=False) + ... v = Mul(int(m), Pow(2, int(e), evaluate=False), evaluate=False) ... print('%s at prec=%s' % (v, f._prec)) ... >>> t = Float('0.3', 3) @@ -507,17 +548,20 @@ -5.00000000000000 An actual mpf tuple also contains the number of bits in c as the last - element of the tuple, but this is not needed for instantiation: + element of the tuple: + + >>> _._mpf_ + (1, 5, 0, 3) - >>> _._mpf_ - (1, 5, 0, 3) + This is not needed for instantiation and is not the same thing as the + precision. The mpf tuple and the precision are two separate quantities + that Float tracks. """ __slots__ = ['_mpf_', '_prec'] + is_rational = True is_real = True - is_irrational = False - is_integer = False is_Float = True @@ -528,20 +572,17 @@ num = '0' + num elif num.startswith('-.') and len(num) > 2: num = '-0.' + num[2:] - elif not num: - return C.Zero() + elif isinstance(num, float) and num == 0: + num = '0' + elif isinstance(num, (SYMPY_INTS, Integer)): + num = str(num) # faster than mlib.from_int + elif isinstance(num, mpmath.mpf): + num = num._mpf_ + if prec == '': - if isinstance(num, (int, Integer)): - # an int is unambiguous, but if someone enters - # .99999999999999999, Python automatically converts - # this to 1.0 and although 1.0 == 1, this is not - # really what the user typed, so we avoid guessing -- - # even if num == int(num) -- because we don't know how - # it became that exact float. - num = str(num) - elif not isinstance(num, str): + if not isinstance(num, str): raise ValueError('The null string can only be used when ' - 'the number to Float is passed as a string.') + 'the number to Float is passed as a string or an integer.') ok = None if _literal_float(num): try: @@ -549,23 +590,22 @@ except decimal.InvalidOperation: pass else: + isint = '.' not in num num, dps = _decimal_to_Rational_prec(Num) + if num.is_Integer and isint: + dps = max(dps, len(str(num).lstrip('-'))) ok = True - if num.is_Integer: - dps = len(str(num)) if ok is None: raise ValueError('string-float not recognized: %s' % num) else: dps = prec - if prec != '' and isinstance(num, (int, Integer)): - # if this is changed here it has to be changed in _new, too - return Integer(num) - prec = mlib.libmpf.dps_to_prec(dps) if isinstance(num, float): _mpf_ = mlib.from_float(num, prec, rnd) - elif isinstance(num, (str, decimal.Decimal, Integer)): + elif isinstance(num, str): + _mpf_ = mlib.from_str(num, prec, rnd) + elif isinstance(num, decimal.Decimal): _mpf_ = mlib.from_str(str(num), prec, rnd) elif isinstance(num, Rational): _mpf_ = mlib.from_rational(num.p, num.q, prec, rnd) @@ -582,7 +622,7 @@ return Float._new(num, prec) else: _mpf_ = mpmath.mpf( - S.NegativeOne**num[0]*num[1]*2**num[2])._mpf_ + S.NegativeOne**num[0]*num[1]*2**num[2])._mpf_ elif isinstance(num, Float): _mpf_ = num._mpf_ if prec < num._prec: @@ -590,8 +630,11 @@ else: _mpf_ = mpmath.mpf(num)._mpf_ - if not num: - return C.Zero() + # special cases + if _mpf_ == _mpf_zero: + pass # we want a Float + elif _mpf_ == _mpf_nan: + return S.NaN obj = Expr.__new__(cls) obj._mpf_ = _mpf_ @@ -600,30 +643,14 @@ @classmethod def _new(cls, _mpf_, _prec): - if _mpf_ == mlib.fzero: - return S.Zero - - # the new Float should be normalized unless it is - # an integer because Float doesn't return Floats - # for Integers. If Integers can become Floats then - # all the following (up to the first 'obj =' line - # can be replaced with ok = mpf_norm(_mpf_, _prec) - - sign, man, expt, bc = _mpf_ - if not man: - # hack for mpf_normalize which does not do this - if not bc: - ok = mlib.fzero - else: - ok = (sign % 2, int(man), expt, bc) - elif expt < 0: - # this is the non-hack normalization - ok = mpf_normalize(sign, man, expt, bc, _prec, rnd) - else: - ok = _mpf_ + # special cases + if _mpf_ == _mpf_zero: + return S.Zero # XXX this is different from Float which gives 0.0 + elif _mpf_ == _mpf_nan: + return S.NaN obj = Expr.__new__(cls) - obj._mpf_ = ok + obj._mpf_ = mpf_norm(_mpf_, _prec) obj._prec = _prec return obj @@ -652,19 +679,46 @@ def _as_mpf_val(self, prec): rv = mpf_norm(self._mpf_, prec) # uncomment to see failures - #if rv != was._mpf_ and self._prec == prec: - # print was._mpf_, rv + #if rv != self._mpf_ and self._prec == prec: + # print self._mpf_, rv return rv def _as_mpf_op(self, prec): return self._mpf_, max(prec, self._prec) - def _eval_is_positive(self): - return self.num > 0 + def _eval_is_bounded(self): + if self._mpf_ in (_mpf_inf, _mpf_ninf): + return False + return True + + def _eval_is_finite(self): + if self._mpf_ in (_mpf_inf, _mpf_ninf, _mpf_zero): + return False + return True + + def _eval_is_integer(self): + return self._mpf_ == _mpf_zero def _eval_is_negative(self): + if self._mpf_ == _mpf_ninf: + return True + if self._mpf_ == _mpf_inf: + return False return self.num < 0 + def _eval_is_positive(self): + if self._mpf_ == _mpf_inf: + return True + if self._mpf_ == _mpf_ninf: + return False + return self.num > 0 + + def _eval_is_zero(self): + return self._mpf_ == _mpf_zero + + def __bool__(self): + return self._mpf_ != _mpf_zero + def __neg__(self): return Float._new(mlib.mpf_neg(self._mpf_), self._prec) @@ -691,7 +745,7 @@ @_sympifyit('other', NotImplemented) def __div__(self, other): - if isinstance(other, Number): + if isinstance(other, Number) and other != 0: rhs, prec = other._as_mpf_op(self._prec) return Float._new(mlib.mpf_div(self._mpf_, rhs, prec, rnd), prec) return Number.__div__(self, other) @@ -700,6 +754,16 @@ @_sympifyit('other', NotImplemented) def __mod__(self, other): + if isinstance(other, Rational) and other.q != 1: + # calculate mod with Rationals, *then* round the result + return Float(Rational.__mod__(Rational(self), other), + prec_to_dps(self._prec)) + if isinstance(other, Float): + r = self/other + if r == int(r): + prec = max([prec_to_dps(i) + for i in (self._prec, other._prec)]) + return Float(0, prec) if isinstance(other, Number): rhs, prec = other._as_mpf_op(self._prec) return Float._new(mlib.mpf_mod(self._mpf_, rhs, prec, rnd), prec) @@ -707,6 +771,8 @@ @_sympifyit('other', NotImplemented) def __rmod__(self, other): + if isinstance(other, Float): + return other.__mod__(self) if isinstance(other, Number): rhs, prec = other._as_mpf_op(self._prec) return Float._new(mlib.mpf_mod(rhs, self._mpf_, prec, rnd), prec) @@ -719,6 +785,11 @@ (-p)**r -> exp(r*log(-p)) -> exp(r*(log(p) + I*Pi)) -> -> p**r*(sin(Pi*r) + cos(Pi*r)*I) """ + if self == 0: + if expt.is_positive: + return S.Zero + if expt.is_negative: + return Float('inf') if isinstance(expt, Number): if isinstance(expt, Integer): prec = self._prec @@ -731,15 +802,19 @@ return Float._new(y, prec) except mlib.ComplexResult: re, im = mlib.mpc_pow( - (self, mlib.fzero), (expt, mlib.fzero), prec, rnd) + (self, _mpf_zero), (expt, _mpf_zero), prec, rnd) return Float._new(re, prec) + \ - Float._new(im, prec)*S.ImaginaryUnit + Float._new(im, prec)*S.ImaginaryUnit def __abs__(self): return Float._new(mlib.mpf_abs(self._mpf_), self._prec) def __int__(self): - return int(mlib.to_int(self._mpf_)) # uses round_fast = round_down + if self._mpf_ == _mpf_zero: + return 0 + return int(mlib.to_int(self._mpf_)) # uses round_fast = round_down + + __long__ = __int__ def __eq__(self, other): if isinstance(other, float): @@ -759,10 +834,6 @@ return False return other.__eq__(self) if isinstance(other, Float): - # hack for the nan == nan case which, to mpf_eq is not equal - # but to SymPy should be equal - if other._mpf_ == self._mpf_ == fnan: - return True return bool(mlib.mpf_eq(self._mpf_, other._mpf_)) if isinstance(other, Number): # numbers should compare at the same precision; @@ -832,7 +903,7 @@ def __hash__(self): return super(Float, self).__hash__() - def epsilon_eq(self, other, epsilon="10e-16"): + def epsilon_eq(self, other, epsilon="1e-15"): return abs(self - other) < Float(epsilon) def _sage_(self): @@ -845,27 +916,45 @@ # this is here to work nicely in Sage RealNumber = Float + @deprecated(useinstead="Float", issue=1721, deprecated_since_version="0.7.0") def Real(*args, **kwargs): # pragma: no cover """Deprecated alias for the Float constructor.""" return Float(*args, **kwargs) + class Rational(Number): """Represents integers and rational numbers (p/q) of any size. Examples ======== - >>> from sympy import Rational - >>> from sympy.abc import x, y + >>> from sympy import Rational, nsimplify, S, pi >>> Rational(3) 3 - >>> Rational(1,2) + >>> Rational(1, 2) + 1/2 + + Rational is unprejudiced in accepting input. If a float is passed, the + underlying value of the binary representation will be returned: + + >>> Rational(.5) 1/2 - >>> Rational(1.5) - 1 + >>> Rational(.2) + 3602879701896397/18014398509481984 + + If the simpler representation of the float is desired then consider + limiting the denominator to the desired value or convert the float to + a string (which is roughly equivalent to limiting the denominator to + 10**12): + + >>> Rational(str(.2)) + 1/5 + >>> Rational(.2).limit_denominator(10**12) + 1/5 - Rational can also accept strings that are valid literals for reals: + An arbitrarily precise Rational is obtained when a string literal is + passed: >>> Rational("1.23") 123/100 @@ -873,16 +962,35 @@ 1/100 >>> Rational(".1") 1/10 + >>> Rational('1e-2/3.2') + 1/320 - Parsing needs for any other type of string for which a Rational is desired - can be handled with the rational=True option in sympify() which produces - rationals from strings like '.[3]' (=1/3) and '3/10' (=3/10). + The conversion of other types of strings can be handled by + the sympify() function, and conversion of floats to expressions + or simple fractions can be handled with nsimplify: + + >>> S('.[3]') # repeating digits in brackets + 1/3 + >>> S('3**2/10') # general expressions + 9/10 + >>> nsimplify(.3) # numbers that have a simple form + 3/10 - **Low-level** + But if the input does not reduce to a literal Rational, an error will + be raised: + + >>> Rational(pi) + Traceback (most recent call last): + ... + TypeError: invalid input: pi + + + Low-level + --------- Access numerator and denominator as .p and .q: - >>> r = Rational(3,4) + >>> r = Rational(3, 4) >>> r 3/4 >>> r.p @@ -890,12 +998,15 @@ >>> r.q 4 - Note that p and q return integers (not sympy Integers) so some care + Note that p and q return integers (not SymPy Integers) so some care is needed when using them in expressions: >>> r.p//r.q 0 + See Also + ======== + sympify, sympy.simplify.simplify.nsimplify """ is_real = True is_integer = False @@ -910,6 +1021,7 @@ if q is None: if isinstance(p, Rational): return p + if isinstance(p, str): p = p.replace(' ', '') try: @@ -925,18 +1037,36 @@ if f: n, d = f.groups() return Rational(int(n), int(d)) - raise ValueError('invalid literal: %s' % p) - elif not isinstance(p, Basic): - return Rational(S(p)) + elif p.count('/') == 1: + p, q = p.split('/') + return Rational(Rational(p), Rational(q)) + else: + pass # error will raise below + else: + try: + if isinstance(p, fractions.Fraction): + return Rational(p.numerator, p.denominator) + except NameError: + pass # error will raise below + + if isinstance(p, (float, Float)): + return Rational(*_as_integer_ratio(p)) + + if not isinstance(p, SYMPY_INTS + (Rational,)): + raise TypeError('invalid input: %s' % p) q = S.One + else: + p = Rational(p) + q = Rational(q) + if isinstance(q, Rational): p *= q.q q = q.p if isinstance(p, Rational): q *= p.q p = p.p - p = int(p) - q = int(q) + + # p and q are now integers if q == 0: if p == 0: if _errdict["divide"]: @@ -1003,16 +1133,16 @@ n, d = self.p, self.q while True: a = n//d - q2 = q0+a*q1 + q2 = q0 + a*q1 if q2 > max_denominator: break - p0, q0, p1, q1 = p1, q1, p0+a*p1, q2 - n, d = d, n-a*d + p0, q0, p1, q1 = p1, q1, p0 + a*p1, q2 + n, d = d, n - a*d - k = (max_denominator-q0)//q1 - bound1 = Rational(p0+k*p1, q0+k*q1) + k = (max_denominator - q0)//q1 + bound1 = Rational(p0 + k*p1, q0 + k*q1) bound2 = Rational(p1, q1) - if abs(bound2 - self) <= abs(bound1-self): + if abs(bound2 - self) <= abs(bound1 - self): return bound2 else: return bound1 @@ -1076,15 +1206,15 @@ n = (self.p*other.q) // (other.p*self.q) return Rational(self.p*other.q - n*other.p*self.q, self.q*other.q) if isinstance(other, Float): - return self.evalf() % other + # calculate mod with Rationals, *then* round the answer + return Float(self.__mod__(Rational(other)), + prec_to_dps(other._prec)) return Number.__mod__(self, other) @_sympifyit('other', NotImplemented) def __rmod__(self, other): if isinstance(other, Rational): return Rational.__mod__(other, self) - if isinstance(other, Float): - return other % self.evalf() return Number.__rmod__(self, other) def _eval_power(self, expt): @@ -1096,15 +1226,15 @@ ne = -expt if (ne is S.One): return Rational(self.q, self.p) - if self < 0: + if self.is_negative: if expt.q != 1: - return -(S.NegativeOne)**((expt.p % expt.q) / \ + return -(S.NegativeOne)**((expt.p % expt.q) / S(expt.q))*Rational(self.q, -self.p)**ne else: return S.NegativeOne**ne*Rational(self.q, -self.p)**ne else: return Rational(self.q, self.p)**ne - if expt is S.Infinity: # -oo already caught by test for negative + if expt is S.Infinity: # -oo already caught by test for negative if self.p > self.q: # (3/2)**oo -> oo return S.Infinity @@ -1120,8 +1250,9 @@ # (4/3)**(5/6) -> 4**(5/6)*3**(-5/6) return Integer(self.p)**expt*Integer(self.q)**(-expt) # as the above caught negative self.p, now self is positive - return Integer(self.q)**Rational(expt.p*(expt.q-1), expt.q) / \ - Integer(self.q)**Integer(expt.p) + return Integer(self.q)**Rational( + expt.p*(expt.q - 1), expt.q) / \ + Integer(self.q)**Integer(expt.p) if self.is_negative and expt.is_even: return (-self)**expt @@ -1143,6 +1274,8 @@ return -(-p//q) return p//q + __long__ = __int__ + def __eq__(self, other): try: other = _sympify(other) @@ -1194,7 +1327,6 @@ return bool(self.p*other.q >= self.q*other.p) return Expr.__ge__(self, other) - def __lt__(self, other): try: other = _sympify(other) @@ -1221,6 +1353,8 @@ if other.is_real and other.is_number and not isinstance(other, Rational): other = other.evalf() if isinstance(other, Number): + if other is S.NaN: + return None if isinstance(other, Float): return bool(mlib.mpf_le( self._as_mpf_val(other._prec), other._mpf_)) @@ -1230,22 +1364,17 @@ def __hash__(self): return super(Rational, self).__hash__() - def factors(self, limit=None, use_trial=True, - use_rho=False, - use_pm1=False, - verbose=False, - visual=False): + def factors(self, limit=None, use_trial=True, use_rho=False, + use_pm1=False, verbose=False, visual=False): """A wrapper to factorint which return factors of self that are smaller than limit (or cheap to compute). Special methods of factoring are disabled by default so that only trial division is used. """ from sympy.ntheory import factorint - f = factorint(self.p, limit=limit, - use_trial=use_trial, - use_rho=use_rho, - use_pm1=use_pm1, - verbose=verbose).copy() + f = factorint(self.p, limit=limit, use_trial=use_trial, + use_rho=use_rho, use_pm1=use_pm1, + verbose=verbose).copy() f = defaultdict(int, f) for p, e in list(factorint(self.q, limit=limit, use_trial=use_trial, @@ -1268,66 +1397,25 @@ args = [] args.extend([Pow(*i, **{'evaluate':False}) for i in sorted(f.items())]) - return Mul(*args, **{'evaluate':False}) + return Mul(*args, **{'evaluate': False}) + @_sympifyit('other', NotImplemented) def gcd(self, other): - """Compute greatest common divisor of input arguments. """ - if type(other) in (int, int): - p = igcd(self.p, other) - - if self.is_Integer: - return Integer(p) - else: - return Rational(p, self.q) - else: - other = _sympify(other) - - if other.is_Rational: - p = igcd(self.p, other.p) - - if other.is_Integer: - if self.is_Integer: - return Integer(p) - else: - return Rational(p, self.q) - else: - if self.is_Integer: - return Rational(p, other.q) - else: - return Rational(p, ilcm(self.q, other.q)) - elif other.is_Number: - return S.One - else: - raise TypeError("expected integer or rational, got %s" % other) + if isinstance(other, Rational): + if other is S.Zero: + return other + return Rational( + Integer(igcd(self.p, other.p)), + Integer(ilcm(self.q, other.q))) + return Number.gcd(self, other) + @_sympifyit('other', NotImplemented) def lcm(self, other): - """Compute least common multiple of input arguments. """ - if type(other) in (int, int): - return Integer(ilcm(self.p, other)) - else: - other = _sympify(other) - - if other.is_Rational: - p = ilcm(self.p, other.p) - - if self.is_Integer or other.is_Integer: - return Integer(p) - else: - return Rational(p, igcd(self.q, other.q)) - elif other.is_Number: - return self*other - else: - raise TypeError("expected integer or rational, got %s" % other) - - def cofactors(self, other): - """Compute GCD and cofactors of input arguments. """ - other = _sympify(other) - gcd = self.gcd(other) - - if gcd is S.One: - return gcd, self, other - else: - return gcd, self/gcd, other/gcd + if isinstance(other, Rational): + return Rational( + self.p*other.p//igcd(self.p, other.p), + igcd(self.q, other.q)) + return Number.lcm(self, other) def as_numer_denom(self): return Integer(self.p), Integer(self.q) @@ -1356,6 +1444,7 @@ return -self, S.NegativeOne return S.One, self + # int -> Integer _intcache = {} @@ -1364,14 +1453,14 @@ def _intcache_printinfo(): ints = sorted(_intcache.keys()) nhit = _intcache_hits - nmiss= _intcache_misses + nmiss = _intcache_misses if nhit == 0 and nmiss == 0: print() print('Integer cache statistic was not collected') return - miss_ratio = float(nmiss) / (nhit+nmiss) + miss_ratio = float(nmiss) / (nhit + nmiss) print() print('Integer cache statistic') @@ -1381,13 +1470,15 @@ print() print(' #hit #miss #total') print() - print('%5i %5i (%7.5f %%) %5i' % (nhit, nmiss, miss_ratio*100, nhit + nmiss)) + print('%5i %5i (%7.5f %%) %5i' % ( + nhit, nmiss, miss_ratio*100, nhit + nmiss)) print() print(ints) _intcache_hits = 0 _intcache_misses = 0 + def int_trace(f): import os if os.getenv('SYMPY_TRACE_INT', 'no').lower() != 'yes': @@ -1405,7 +1496,6 @@ return f(cls, i) - # also we want to hook our _intcache_printinfo into sys.atexit import atexit atexit.register(_intcache_printinfo) @@ -1413,8 +1503,6 @@ return Integer_tracer - - class Integer(Rational): q = 1 @@ -1441,7 +1529,11 @@ # an integer). So we proceed by taking int() of the input and # let the int routines determine whether the expression can # be made into an int or whether an error should be raised. - ival = int(i) + try: + ival = int(i) + except TypeError: + raise TypeError( + 'Integer can only work with integer expressions.') try: return _intcache[ival] except KeyError: @@ -1460,6 +1552,8 @@ def __int__(self): return self.p + __long__ = __int__ + def __neg__(self): return Integer(-self.p) @@ -1553,16 +1647,16 @@ def __gt__(self, other): if isinstance(other, int): - return (self.p > other) + return (self.p > other) elif isinstance(other, Integer): - return (self.p > other.p) + return (self.p > other.p) return Rational.__gt__(self, other) def __lt__(self, other): if isinstance(other, int): - return (self.p < other) + return (self.p < other) elif isinstance(other, Integer): - return (self.p < other.p) + return (self.p < other.p) return Rational.__lt__(self, other) def __ge__(self, other): @@ -1624,15 +1718,15 @@ return (-self)**expt if not isinstance(expt, Rational): return - if expt is S.Half and self < 0: + if expt is S.Half and self.is_negative: # we extract I for this special case since everyone is doing so return S.ImaginaryUnit*Pow(-self, expt) - if expt < 0: + if expt.is_negative: # invert base and change sign on exponent ne = -expt - if self < 0: + if self.is_negative: if expt.q != 1: - return -(S.NegativeOne)**((expt.p % expt.q) / \ + return -(S.NegativeOne)**((expt.p % expt.q) / S(expt.q))*Rational(1, -self)**ne else: return (S.NegativeOne)**ne*Rational(1, -self)**ne @@ -1643,8 +1737,8 @@ if xexact: # if it's a perfect root we've finished result = Integer(x**abs(expt.p)) - if self < 0: - result*= (-1)**expt + if self.is_negative: + result *= S.NegativeOne**expt return result # The following is an algorithm where we collect perfect roots @@ -1661,8 +1755,8 @@ # now process the dict of factors if self.is_negative: dict[-1] = 1 - out_int = 1 # integer part - out_rad = 1 # extracted radicals + out_int = 1 # integer part + out_rad = 1 # extracted radicals sqr_int = 1 sqr_gcd = 0 sqr_dict = {} @@ -1710,52 +1804,10 @@ def __rfloordiv__(self, other): return Integer(Integer(other).p // self.p) - def factorial(self): - """Compute factorial of `self`. """ - from sympy.functions.combinatorial.factorials import factorial - return Integer(factorial(int(self))) - - def isqrt(self): - """Compute integer square root of `self`. """ - return Integer(mlib.isqrt(int(self))) - - def half_gcdex(self, other): - """Half Extended Euclidean Algorithm. """ - s, _, h = self.gcdex(other) - return s, h - - def gcdex(self, other): - """Extended Euclidean Algorithm. """ - if isinstance(other, int): - return tuple(map(Integer, igcdex(int(self), other))) - b = _sympify(other) - if b.is_Integer: - return tuple(map(Integer, igcdex(int(self), int(b)))) - else: - raise ValueError("expected an integer, got %s" % b) - - def invert(self, other): - """Invert `self` modulo `other`, if possible. """ - if isinstance(other, int): - a, b = int(self), other - else: - b = _sympify(other) - - if b.is_Integer: - a, b = int(self), int(b) - else: - raise ValueError("expected an integer, got %s" % b) - - s, _, h = igcdex(a, b) - - if h == 1: - return Integer(s % b) - else: - raise ZeroDivisionError("zero divisor") - # Add sympify converters converter[int] = converter[int] = Integer + class RationalConstant(Rational): """ Abstract base class for rationals with specific behaviors @@ -1768,6 +1820,7 @@ def __new__(cls): return AtomicExpr.__new__(cls) + class IntegerConstant(Integer): __slots__ = [] @@ -1794,14 +1847,6 @@ def __neg__(): return S.Zero - @_sympifyit('other', NotImplemented) - def __mul__(self, other): - if other is S.NaN or \ - other is S.NegativeInfinity or \ - other is S.Infinity or \ - other is S.ComplexInfinity: - return S.NaN - return S.Zero def _eval_power(self, expt): if expt.is_positive: @@ -1816,7 +1861,7 @@ coeff, terms = expt.as_coeff_Mul() if coeff.is_negative: return S.Infinity**terms - if coeff is not S.One: # there is a Number to discard + if coeff is not S.One: # there is a Number to discard return self**terms def _eval_order(self, *symbols): @@ -1826,6 +1871,7 @@ def __bool__(self): return False + class One(IntegerConstant, metaclass=Singleton): p = 1 q = 1 @@ -1847,15 +1893,13 @@ return @staticmethod - def factors(limit=None, use_trial=True, - use_rho=False, - use_pm1=False, - verbose=False, - visual=False): + def factors(limit=None, use_trial=True, use_rho=False, use_pm1=False, + verbose=False, visual=False): if visual: return S.One return {1: 1} + class NegativeOne(IntegerConstant, metaclass=Singleton): p = -1 q = 1 @@ -1892,6 +1936,7 @@ return self**i*self**Rational(r, expt.q) return + class Half(RationalConstant, metaclass=Singleton): p = 1 q = 2 @@ -1904,14 +1949,14 @@ class Infinity(Number, metaclass=Singleton): - is_commutative = True - is_positive = True - is_bounded = False - is_finite = False + is_commutative = True + is_positive = True + is_bounded = False + is_finite = False is_infinitesimal = False - is_integer = None - is_rational = None - is_odd = None + is_integer = None + is_rational = None + is_odd = None __slots__ = [] @@ -1924,9 +1969,8 @@ if other is S.NegativeInfinity or other is S.NaN: return S.NaN elif other.is_Float: - if other == Float('-inf') or other._mpf_ == fnan: - #Used workaround because Float('nan') == Float('nan') return False - return Float('nan') + if other == Float('-inf'): + return S.NaN else: return Float('inf') else: @@ -1940,9 +1984,8 @@ if other is S.Infinity or other is S.NaN: return S.NaN elif other.is_Float: - if other == Float('inf') or other._mpf_ == fnan: - #Used workaround because Float('nan') == Float('nan') return False - return Float('nan') + if other == Float('inf'): + return S.NaN else: return Float('inf') else: @@ -1955,9 +1998,8 @@ if other is S.Zero or other is S.NaN: return S.NaN elif other.is_Float: - if other._mpf_ == fnan or other == 0: - #Used workaround because Float('nan') == Float('nan') return False - return Float('nan') + if other == 0: + return S.NaN if other > 0: return Float('inf') else: @@ -1974,16 +2016,14 @@ def __div__(self, other): if isinstance(other, Number): if other is S.Infinity or \ - other is S.NegativeInfinity or \ - other is S.NaN: + other is S.NegativeInfinity or \ + other is S.NaN: return S.NaN elif other.is_Float: if other == Float('-inf') or \ - other == Float('inf') or \ - other._mpf_ == fnan: - #Used workaround because Float('nan') == Float('nan') return False - return Float('nan') - elif other >= 0: + other == Float('inf'): + return S.NaN + elif other.is_nonnegative: return Float('inf') else: return Float('-inf') @@ -2059,15 +2099,16 @@ oo = S.Infinity + class NegativeInfinity(Number, metaclass=Singleton): - is_commutative = True - is_real = True - is_positive = False - is_bounded = False - is_finite = False + is_commutative = True + is_real = True + is_positive = False + is_bounded = False + is_finite = False is_infinitesimal = False - is_integer = None - is_rational = None + is_integer = None + is_rational = None __slots__ = [] @@ -2080,8 +2121,7 @@ if other is S.Infinity or other is S.NaN: return S.NaN elif other.is_Float: - if other == Float('inf') or other._mpf_ == fnan: - #Used workaround because Float('nan') == Float('nan') return False + if other == Float('inf'): return Float('nan') else: return Float('-inf') @@ -2096,8 +2136,7 @@ if other is S.NegativeInfinity or other is S.NaN: return S.NaN elif other.is_Float: - if other == Float('-inf') or other._mpf_ == fnan: - #Used workaround because Float('nan') == Float('nan') return False + if other == Float('-inf'): return Float('nan') else: return Float('-inf') @@ -2111,15 +2150,14 @@ if other is S.Zero or other is S.NaN: return S.NaN elif other.is_Float: - if other._mpf_ == fnan or other == 0: - #Used workaround because Float('nan') == Float('nan') return False - return Float('nan') - elif other > 0: + if other is S.NaN or other.is_zero: + return S.NaN + elif other.is_positive: return Float('-inf') else: return Float('inf') else: - if other > 0: + if other.is_positive: return S.NegativeInfinity else: return S.Infinity @@ -2130,17 +2168,15 @@ def __div__(self, other): if isinstance(other, Number): if other is S.Infinity or \ - other is S.NegativeInfinity or \ - other is S.NaN: + other is S.NegativeInfinity or \ + other is S.NaN: return S.NaN elif other.is_Float: if other == Float('-inf') or \ - other == Float('inf') or \ - other == Float('nan') or \ - other._mpf_ == fnan: - #Used workaround because Float('nan') == Float('nan') return False - return Float('nan') - elif other >= 0: + other == Float('inf') or \ + other is S.NaN: + return S.NaN + elif other.is_nonnegative: return Float('-inf') else: return Float('inf') @@ -2176,8 +2212,8 @@ """ if isinstance(expt, Number): if expt is S.NaN or \ - expt is S.Infinity or \ - expt is S.NegativeInfinity: + expt is S.Infinity or \ + expt is S.NegativeInfinity: return S.NaN if isinstance(expt, Integer) and expt.is_positive: @@ -2216,6 +2252,7 @@ def __ge__(self, other): return other is S.NegativeInfinity + class NaN(Number, metaclass=Singleton): """ Not a Number. @@ -2287,7 +2324,7 @@ __truediv__ = __div__ def _as_mpf_val(self, prec): - return mlib.fnan + return _mpf_nan def _sage_(self): import sage.all as sage @@ -2316,6 +2353,7 @@ nan = S.NaN + class ComplexInfinity(AtomicExpr, metaclass=Singleton): is_commutative = True is_bounded = False @@ -2350,7 +2388,9 @@ zoo = S.ComplexInfinity -class NumberSymbol(AtomicExpr, metaclass=Singleton): + +class NumberSymbol(AtomicExpr): + is_commutative = True is_bounded = True is_finite = True @@ -2397,7 +2437,7 @@ if isinstance(other, Number): approx = self.approximation_interval(other.__class__) if approx is not None: - l,u = approx + l, u = approx if other < l: return False if other > u: @@ -2431,6 +2471,9 @@ # subclass with appropriate return value raise NotImplementedError + def __long__(self): + return self.__int__() + def __hash__(self): return super(NumberSymbol, self).__hash__() @@ -2438,7 +2481,7 @@ class Exp1(NumberSymbol, metaclass=Singleton): is_real = True is_positive = True - is_negative = False # XXX Forces is_negative/is_nonnegative + is_negative = False # XXX Forces is_negative/is_nonnegative is_irrational = True __slots__ = [] @@ -2454,19 +2497,28 @@ return mpf_e(prec) def approximation_interval(self, number_cls): - if issubclass(number_cls,Integer): - return (Integer(2),Integer(3)) - elif issubclass(number_cls,Rational): + if issubclass(number_cls, Integer): + return (Integer(2), Integer(3)) + elif issubclass(number_cls, Rational): pass def _eval_power(self, expt): return C.exp(expt) + def _eval_rewrite_as_sin(self): + I = S.ImaginaryUnit + return C.sin(I + S.Pi/2) - I*C.sin(I) + + def _eval_rewrite_as_cos(self): + I = S.ImaginaryUnit + return C.cos(I) + I*C.cos(I + S.Pi/2) + def _sage_(self): import sage.all as sage return sage.e E = S.Exp1 + class Pi(NumberSymbol, metaclass=Singleton): is_real = True is_positive = True @@ -2489,13 +2541,14 @@ if issubclass(number_cls, Integer): return (Integer(3), Integer(4)) elif issubclass(number_cls, Rational): - return (Rational(223,71), Rational(22,7)) + return (Rational(223, 71), Rational(22, 7)) def _sage_(self): import sage.all as sage return sage.pi pi = S.Pi + class GoldenRatio(NumberSymbol, metaclass=Singleton): is_real = True is_positive = True @@ -2509,7 +2562,7 @@ def _as_mpf_val(self, prec): # XXX track down why this has to be increased - rv = mlib.from_man_exp(phi_fixed(prec+10), -prec-10) + rv = mlib.from_man_exp(phi_fixed(prec + 10), -prec - 10) return mpf_norm(rv, prec) def _eval_expand_func(self, **hints): @@ -2526,6 +2579,7 @@ import sage.all as sage return sage.golden_ratio + class EulerGamma(NumberSymbol, metaclass=Singleton): is_real = True is_positive = True @@ -2539,8 +2593,8 @@ def _as_mpf_val(self, prec): # XXX track down why this has to be increased - v = mlib.libhyper.euler_fixed(prec+10) - rv = mlib.from_man_exp(v, -prec-10) + v = mlib.libhyper.euler_fixed(prec + 10) + rv = mlib.from_man_exp(v, -prec - 10) return mpf_norm(rv, prec) def approximation_interval(self, number_cls): @@ -2553,6 +2607,7 @@ import sage.all as sage return sage.euler_gamma + class Catalan(NumberSymbol, metaclass=Singleton): is_real = True is_positive = True @@ -2566,8 +2621,8 @@ def _as_mpf_val(self, prec): # XXX track down why this has to be increased - v = mlib.catalan_fixed(prec+10) - rv = mlib.from_man_exp(v, -prec-10) + v = mlib.catalan_fixed(prec + 10) + rv = mlib.from_man_exp(v, -prec - 10) return mpf_norm(rv, prec) def approximation_interval(self, number_cls): @@ -2580,6 +2635,7 @@ import sage.all as sage return sage.catalan + class ImaginaryUnit(AtomicExpr, metaclass=Singleton): is_commutative = True is_imaginary = True @@ -2611,7 +2667,6 @@ I**3 mod 4 -> -I """ - if isinstance(expt, Number): if isinstance(expt, Integer): expt = expt.p % 4 @@ -2646,24 +2701,31 @@ pass try: - import gmpy + if HAS_GMPY == 2: + import gmpy2 as gmpy + elif HAS_GMPY == 1: + import gmpy + else: + raise ImportError def sympify_mpz(x): return Integer(int(x)) def sympify_mpq(x): - return Rational(int(x.numer()), int(x.denom())) + return Rational(int(x.numerator), int(x.denominator)) converter[type(gmpy.mpz(1))] = sympify_mpz converter[type(gmpy.mpq(1, 2))] = sympify_mpq except ImportError: pass + def sympify_mpmath(x): return Expr._from_mpmath(x, x.context.prec) converter[mpnumeric] = sympify_mpmath + def sympify_complex(a): real, imag = list(map(sympify, (a.real, a.imag))) return real + S.ImaginaryUnit*imag @@ -2672,7 +2734,7 @@ _intcache[0] = S.Zero _intcache[1] = S.One -_intcache[-1]= S.NegativeOne +_intcache[-1] = S.NegativeOne from .power import Pow, integer_nthroot from .mul import Mul diff -Nru python3-sympy-0.7.2/sympy/core/operations.py python3-sympy-0.7.3/sympy/core/operations.py --- python3-sympy-0.7.2/sympy/core/operations.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/core/operations.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,16 +1,12 @@ from sympy.core.core import C -from sympy.core.expr import Expr from sympy.core.sympify import _sympify, sympify -from sympy.core.basic import Basic +from sympy.core.basic import Basic, _aresame from sympy.core.cache import cacheit -from sympy.core.compatibility import cmp, quick_sort +from sympy.core.compatibility import cmp, ordered from sympy.core.logic import fuzzy_and -# from add import Add /cyclic/ -# from mul import Mul /cyclic/ -# from function import Lambda, WildFunction /cyclic/ -class AssocOp(Expr): +class AssocOp(Basic): """ Associative operations, can separate noncommutative and commutative parts. @@ -55,7 +51,7 @@ elif len(args) == 1: return args[0] - obj = Expr.__new__(cls, *args) + obj = super(AssocOp, cls).__new__(cls, *args) if is_commutative is None: is_commutative = fuzzy_and(a.is_commutative for a in args) obj.is_commutative = is_commutative @@ -67,7 +63,7 @@ This is handy when we want to optimize things, e.g. - >>> from sympy import Mul, symbols, S + >>> from sympy import Mul, S >>> from sympy.abc import x, y >>> e = Mul(3, x, y) >>> e.args @@ -118,14 +114,14 @@ new_seq = [] while seq: o = seq.pop() - if o.__class__ is cls: # classes must match exactly + if o.__class__ is cls: # classes must match exactly seq.extend(o.args) else: new_seq.append(o) # c_part, nc_part, order_symbols return [], new_seq, None - def _matches_commutative(self, expr, repl_dict={}): + def _matches_commutative(self, expr, repl_dict={}, old=False): """ Matches Add/Mul "pattern" to an expression "expr". @@ -172,11 +168,11 @@ return d # eliminate exact part from pattern: (2+a+w1+w2).matches(expr) -> (w1+w2).matches(expr-a-2) - wild_part = [] - exact_part = [] from .function import WildFunction from .symbol import Wild - for p in self.args: + wild_part = [] + exact_part = [] + for p in ordered(self.args): if p.has(Wild, WildFunction) and (not expr.has(p)): # not all Wild should stay Wilds, for example: # (w2+w3).matches(w1) -> (w1+w3).matches(w1) -> w3.matches(0) @@ -185,23 +181,77 @@ exact_part.append(p) if exact_part: + exact = self.func(*exact_part) + free = expr.free_symbols + if free and (exact.free_symbols - free): + # there are symbols in the exact part that are not + # in the expr; but if there are no free symbols, let + # the matching continue + return None newpattern = self.func(*wild_part) - newexpr = self._combine_inverse(expr, self.func(*exact_part)) + newexpr = self._combine_inverse(expr, exact) + if not old and (expr.is_Add or expr.is_Mul): + if newexpr.count_ops() > expr.count_ops(): + return None return newpattern.matches(newexpr, repl_dict) # now to real work ;) - if expr.is_Add: - i, d = expr.as_independent(C.Symbol) - expr_list = (i,) + self.make_args(expr) - else: - expr_list = self.make_args(expr) - for last_op in reversed(expr_list): - for w in reversed(wild_part): - d1 = w.matches(last_op, repl_dict) - if d1 is not None: - d2 = self.xreplace(d1).matches(expr, d1) - if d2 is not None: - return d2 + i = 0 + saw = set() + while expr not in saw: + saw.add(expr) + expr_list = (self.identity,) + tuple(ordered(self.make_args(expr))) + for last_op in reversed(expr_list): + for w in reversed(wild_part): + d1 = w.matches(last_op, repl_dict) + if d1 is not None: + d2 = self.xreplace(d1).matches(expr, d1) + if d2 is not None: + return d2 + + if i == 0: + if self.is_Mul: + # make e**i look like Mul + if expr.is_Pow and expr.exp.is_Integer: + if expr.exp > 0: + expr = C.Mul(* + [expr.base, expr.base**(expr.exp - 1)], + **{'evaluate': False}) + else: + expr = C.Mul(* + [1/expr.base, expr.base**(expr.exp + 1)], + **{'evaluate': False}) + i += 1 + continue + + elif self.is_Add: + # make i*e look like Add + c, e = expr.as_coeff_Mul() + if abs(c) > 1: + if c > 0: + expr = C.Add(*[e, (c - 1)*e], + **{'evaluate': False}) + else: + expr = C.Add(*[-e, (c + 1)*e], + **{'evaluate': False}) + i += 1 + continue + + # try collection on non-Wild symbols + from sympy.simplify.simplify import collect + was = expr + did = set() + for w in reversed(wild_part): + c, w = w.as_coeff_mul(Wild) + free = c.free_symbols - did + if free: + did.update(free) + expr = collect(expr, free) + if expr != was: + i += 0 + continue + + break # if we didn't continue, there is nothing more to do return @@ -221,6 +271,7 @@ c, nc = _ncsplit(self) cls = self.__class__ + def is_in(expr): if expr == self: return True @@ -233,7 +284,7 @@ return True elif len(nc) <= len(_nc): for i in range(len(_nc) - len(nc)): - if _nc[i:i+len(nc)] == nc: + if _nc[i:i + len(nc)] == nc: return True return False return is_in @@ -258,7 +309,51 @@ return not multi def _eval_evalf(self, prec): - return self.func(*[s._evalf(prec) for s in self.args]) + """ + Evaluate the parts of self that are numbers; if the whole thing + was a number with no functions it would have been evaluated, but + it wasn't so we must judiciously extract the numbers and reconstruct + the object. This is *not* simply replacing numbers with evaluated + numbers. Nunmbers should be handled in the largest pure-number + expression as possible. So the code below separates ``self`` into + number and non-number parts and evaluates the number parts and + walks the args of the non-number part recursively (doing the same + thing). + """ + x, tail = self.as_independent(C.Symbol) + + if tail is not self.identity: + # here, we have a number so we just call to _evalf with prec; + # prec is not the same as n, it is the binary precision so + # that's why we don't call to evalf. + x = x._evalf(prec) if x is not self.identity else self.identity + args = [] + for a in self.func.make_args(tail): + # here we call to _eval_evalf since we don't know what we + # are dealing with and all other _eval_evalf routines should + # be doing the same thing (i.e. taking binary prec and + # finding the evalf-able args) + newa = a._eval_evalf(prec) + if newa is None: + args.append(a) + else: + args.append(newa) + if not _aresame(tuple(args), self.func.make_args(tail)): + tail = self.func(*args) + return self.func(x, tail) + + # this is the same as above, but there were no pure-number args to + # deal with + args = [] + for a in self.args: + newa = a._eval_evalf(prec) + if newa is None: + args.append(a) + else: + args.append(newa) + if not _aresame(tuple(args), self.args): + return self.func(*args) + return self @classmethod def make_args(cls, expr): @@ -281,9 +376,11 @@ else: return (expr,) + class ShortCircuit(Exception): pass + class LatticeOp(AssocOp): """ Join/meet operations of an algebraic lattice[1]. @@ -313,7 +410,7 @@ References: - [1] - http://en.wikipedia.org/wiki/Lattice_(order) + [1] - http://en.wikipedia.org/wiki/Lattice_%28order%29 """ is_commutative = True @@ -329,13 +426,16 @@ elif len(_args) == 1: return set(_args).pop() else: - obj = Expr.__new__(cls, _args) + # XXX in almost every other case for __new__, *_args is + # passed along, but the expectation here is for _args + obj = super(AssocOp, cls).__new__(cls, _args) obj._argset = _args return obj @classmethod - def _new_args_filter(cls, arg_sequence): + def _new_args_filter(cls, arg_sequence, call_cls=None): """Generator filtering args""" + cls = call_cls or cls for arg in arg_sequence: if arg == cls.zero: raise ShortCircuit(arg) @@ -371,7 +471,7 @@ @property @cacheit def args(self): - return quick_sort(self._argset) + return tuple(ordered(self._argset)) @staticmethod def _compare_pretty(a, b): diff -Nru python3-sympy-0.7.2/sympy/core/power.py python3-sympy-0.7.3/sympy/core/power.py --- python3-sympy-0.7.2/sympy/core/power.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/core/power.py 2013-07-13 17:53:32.000000000 +0000 @@ -3,14 +3,18 @@ from .sympify import _sympify from .cache import cacheit from .core import C -from sympy.core.function import (_coeff_isneg, expand_complex, - expand_multinomial, expand_mul) from .singleton import S from .expr import Expr -from sympy import mpmath +from sympy.core.function import (_coeff_isneg, expand_complex, + expand_multinomial, expand_mul) +from sympy.core.logic import fuzzy_bool +from sympy.core.compatibility import as_int + +from sympy.mpmath.libmp import sqrtrem as mpmath_sqrtrem from sympy.utilities.iterables import sift + def integer_nthroot(y, n): """ Return a tuple containing x = floor(y**(1/n)) @@ -25,14 +29,19 @@ """ y, n = int(y), int(n) - if y < 0: raise ValueError("y must be nonnegative") - if n < 1: raise ValueError("n must be positive") - if y in (0, 1): return y, True - if n == 1: return y, True + if y < 0: + raise ValueError("y must be nonnegative") + if n < 1: + raise ValueError("n must be positive") + if y in (0, 1): + return y, True + if n == 1: + return y, True if n == 2: - x, rem = mpmath.libmp.sqrtrem(y) + x, rem = mpmath_sqrtrem(y) return int(x), not rem - if n > y: return 1, False + if n > y: + return 1, False # Get initial estimate for Newton's method. Care must be taken to # avoid overflow try: @@ -49,9 +58,9 @@ # Newton iteration xprev, x = -1, guess while 1: - t = x**(n-1) + t = x**(n - 1) #xprev, x = x, x - (t*x-y)//(n*t) - xprev, x = x, ((n-1)*x + y//t)//n + xprev, x = x, ((n - 1)*x + y//t)//n #print n, x-xprev, abs(x-xprev) < 2 if abs(x - xprev) < 2: break @@ -67,6 +76,7 @@ t = x**n return x, t == y + class Pow(Expr): is_Pow = True @@ -75,6 +85,8 @@ @cacheit def __new__(cls, b, e, evaluate=True): + from sympy.functions.elementary.exponential import exp_polar + # don't optimize "if e==0; return 1" here; it's better to handle that # in the calling routine so this doesn't get called b = _sympify(b) @@ -85,10 +97,23 @@ elif e is S.One: return b elif S.NaN in (b, e): - if b is S.One: # already handled e == 0 above + if b is S.One: # already handled e == 0 above return S.One return S.NaN else: + # recognize base as E + if not e.is_Atom and b is not S.Exp1 and b.func is not exp_polar: + from sympy import numer, denom, log, sign, im, factor_terms + c, ex = factor_terms(e, sign=False).as_coeff_Mul() + den = denom(ex) + if den.func is log and den.args[0] == b: + return S.Exp1**(c*numer(ex)) + elif den.is_Add: + s = sign(im(b)) + if s.is_Number and s and den == \ + log(-factor_terms(b, sign=False)) + s*S.ImaginaryUnit*S.Pi: + return S.Exp1**(c*numer(ex)) + obj = b._eval_power(e) if obj is not None: return obj @@ -116,14 +141,19 @@ if b.is_real and not b_nneg and e.is_even: b = abs(b) b_nneg = True - smallarg = (abs(e) <= abs(S.Pi/log(b))) + + # Special case for when b is nan. See pull req 1714 for details + if b is S.NaN: + smallarg = (abs(e) <= S.Zero) + else: + smallarg = (abs(e) <= abs(S.Pi/log(b))) if (other.is_Rational and other.q == 2 and - e.is_real is False and smallarg is False): + e.is_real is False and smallarg is False): return -Pow(b, e*other) if (other.is_integer or e.is_real and (b_nneg or abs(e) < 1) or e.is_real is False and smallarg is True or - b.is_polar): + b.is_polar): return Pow(b, e*other) def _eval_is_even(self): @@ -168,14 +198,14 @@ c2 = e.is_integer if c1 is None or c2 is None: return None - if not c1 and e.is_nonnegative: #rat**nonneg + if not c1 and e.is_nonnegative: # rat**nonneg return False - if c1 and c2: # int**int + if c1 and c2: # int**int if e.is_nonnegative or e.is_positive: return True if self.exp.is_negative: return False - if c1 and e.is_negative and e.is_bounded: #int**neg + if c1 and e.is_negative and e.is_bounded: # int**neg return False if b.is_Number and e.is_Number: # int**nonneg or rat**? @@ -184,9 +214,11 @@ def _eval_is_real(self): real_b = self.base.is_real - if real_b is None: return + if real_b is None: + return real_e = self.exp.is_real - if real_e is None: return + if real_e is None: + return if real_b and real_e: if self.base.is_positive: return True @@ -207,7 +239,14 @@ elif (self.exp in [S.ImaginaryUnit, -S.ImaginaryUnit] and self.base in [S.ImaginaryUnit, -S.ImaginaryUnit]): return True + elif self.exp.is_Add: + c, a = self.exp.as_coeff_Add() + if c and c.is_Integer: + return C.Mul( + self.base**c, self.base**a, evaluate=False).is_real if real_b and im_e: + if self.base is S.NegativeOne: + return True c = self.exp.coeff(S.ImaginaryUnit) if c: ok = (c*C.log(self.base)/S.Pi).is_Integer @@ -228,9 +267,11 @@ if self.base.is_unbounded: return True c1 = self.base.is_bounded - if c1 is None: return + if c1 is None: + return c2 = self.exp.is_bounded - if c2 is None: return + if c2 is None: + return if c1 and c2: if self.exp.is_nonnegative or self.base.is_nonzero: return True @@ -240,28 +281,47 @@ def _eval_subs(self, old, new): if old.func is self.func and self.base == old.base: - coeff1, terms1 = self.exp.as_coeff_Mul() - coeff2, terms2 = old.exp.as_coeff_Mul() + coeff1, terms1 = self.exp.as_independent(C.Symbol, as_Add=False) + coeff2, terms2 = old.exp.as_independent(C.Symbol, as_Add=False) if terms1 == terms2: pow = coeff1/coeff2 - if pow == int(pow) or self.base.is_positive: + ok = False # True if int(pow) == pow OR self.base.is_positive + try: + pow = as_int(pow) + ok = True + except ValueError: + ok = self.base.is_positive + if ok: # issue 2081 - return Pow(new, pow) # (x**(6*y)).subs(x**(3*y),z)->z**2 + return Pow(new, pow) # (x**(6*y)).subs(x**(3*y),z)->z**2 if old.func is C.exp and self.exp.is_real and self.base.is_positive: - coeff1, terms1 = old.args[0].as_coeff_Mul() + coeff1, terms1 = old.args[0].as_independent(C.Symbol, as_Add=False) # we can only do this when the base is positive AND the exponent # is real - coeff2, terms2 = (self.exp*C.log(self.base)).as_coeff_Mul() + coeff2, terms2 = (self.exp*C.log(self.base)).as_independent( + C.Symbol, as_Add=False) if terms1 == terms2: pow = coeff1/coeff2 if pow == int(pow) or self.base.is_positive: - return Pow(new, pow) # (2**x).subs(exp(x*log(2)), z) -> z + return Pow(new, pow) # (2**x).subs(exp(x*log(2)), z) -> z def as_base_exp(self): - """Return base and exp of self unless base is 1/Integer, then return Integer, -exp. + """Return base and exp of self. + + If base is 1/Integer, then return Integer, -exp. If this extra + processing is not needed, the base and exp properties will + give the raw arguments + + Examples + ======== + + >>> from sympy import Pow, S + >>> p = Pow(S.Half, 2, evaluate=False) + >>> p.as_base_exp() + (2, -2) + >>> p.args + (1/2, 2) - If this extra processing is not needed, the base and exp properties will - give the raw arguments, e.g. (1/2, 2) for (1/2)**2 rather than (2, -2). """ b, e = self.args @@ -319,103 +379,138 @@ def _eval_expand_power_base(self, **hints): """(a*b)**n -> a**n * b**n""" force = hints.get('force', False) - b, ewas = self.args + + b = self.base e = self.exp - if b.is_Mul: - bargs = b.args - if force or e.is_integer: - nonneg = bargs - other = [] - elif ewas.is_Rational or len(bargs) == 2 and bargs[0] is S.NegativeOne: - # the Rational exponent was already expanded automatically - # if there is a negative Number * foo, foo must be unknown - # or else it, too, would have automatically expanded; - # sqrt(-Number*foo) -> sqrt(Number)*sqrt(-foo); then - # sqrt(-foo) -> unchanged if foo is not positive else - # -> I*sqrt(foo) - # So...if we have a 2 arg Mul and the first is a Number - # that number is -1 and there is nothing more than can - # be done without the force=True hint - nonneg= [] - else: - # this is just like what is happening automatically, except - # that now we are doing it for an arbitrary exponent for which - # no automatic expansion is done - def pred(x): - if x.is_polar is None: - return x.is_nonnegative - return x.is_polar - sifted = sift(b.args, pred) - nonneg = sifted[True] - other = sifted[None] - neg = sifted[False] + if not b.is_Mul: + return self - # make sure the Number gets pulled out - if neg and neg[0].is_Number and neg[0] is not S.NegativeOne: - nonneg.append(-neg[0]) - neg[0] = S.NegativeOne + cargs, nc = b.args_cnc(split_1=False) - # leave behind a negative sign - oddneg = len(neg) % 2 - if oddneg: + # expand each term - this is top-level-only + # expansion but we have to watch out for things + # that don't have an _eval_expand method + if nc: + nc = [i._eval_expand_power_base(**hints) + if hasattr(i, '_eval_expand_power_base') else i + for i in nc] + + if e.is_Integer: + if e.is_positive: + rv = Mul(*nc*e) + else: + rv = 1/Mul(*nc*-e) + if cargs: + rv *= Mul(*cargs)**e + return rv + + if not cargs: + return Pow(Mul(*nc), e, evaluate=False) + + nc = [Mul(*nc)] + + # sift the commutative bases + def pred(x): + if x is S.ImaginaryUnit: + return S.ImaginaryUnit + polar = x.is_polar + if polar: + return True + if polar is None: + return fuzzy_bool(x.is_nonnegative) + sifted = sift(cargs, pred) + nonneg = sifted[True] + other = sifted[None] + neg = sifted[False] + imag = sifted[S.ImaginaryUnit] + if imag: + I = S.ImaginaryUnit + i = len(imag) % 4 + if i == 0: + pass + elif i == 1: + other.append(I) + elif i == 2: + if neg: + nonn = -neg.pop() + if nonn is not S.One: + nonneg.append(nonn) + else: + neg.append(S.NegativeOne) + else: + if neg: + nonn = -neg.pop() + if nonn is not S.One: + nonneg.append(nonn) + else: + neg.append(S.NegativeOne) + other.append(I) + del imag + + # bring out the bases that can be separated from the base + + if force or e.is_integer: + # treat all commutatives the same and put nc in other + cargs = nonneg + neg + other + other = nc + else: + # this is just like what is happening automatically, except + # that now we are doing it for an arbitrary exponent for which + # no automatic expansion is done + + assert not e.is_Integer + + # handle negatives by making them all positive and putting + # the residual -1 in other + if len(neg) > 1: + o = S.One + if not other and neg[0].is_Number: + o *= neg.pop(0) + if len(neg) % 2: + o = -o + for n in neg: + nonneg.append(-n) + if o is not S.One: + other.append(o) + elif neg and other: + if neg[0].is_Number and neg[0] is not S.NegativeOne: other.append(S.NegativeOne) + nonneg.append(-neg[0]) + else: + other.extend(neg) + else: + other.extend(neg) + del neg - # negate all negatives and append to nonneg - nonneg += [-n for n in neg] + cargs = nonneg + other += nc - if nonneg: # then there's a new expression to return - d = sift(nonneg, lambda x: x.is_commutative is True) - c = d[True] - nc = d[False] - if not e.is_Integer: - other.extend(nc) - nc = [] - elif len(nc) == 1: - c.extend(nc) - nc = [] - else: - nc = [Mul._from_args(nc)]*e - other = [Pow(Mul(*other), e)] + nc - return Mul(*([Pow(b, e) for b in c] + other)) - return Pow(b, e) + rv = S.One + if cargs: + rv *= Mul(*[Pow(b, e, evaluate=False) for b in cargs]) + if other: + rv *= Pow(Mul(*other), e, evaluate=False) + return rv def _eval_expand_multinomial(self, **hints): """(a+b+..) ** n -> a**n + n*a**(n-1)*b + .., n is nonzero integer""" - b = self.base - e = self.exp - - if b is None: - base = self.base - else: - base = b - if e is None: - exp = self.exp - else: - exp = e - - if e is not None or b is not None: - result = Pow(base, exp) - - if result.is_Pow: - base, exp = result.base, result.exp - else: - return result - else: - result = None + base, exp = self.args + result = self if exp.is_Rational and exp.p > 0 and base.is_Add: if not exp.is_Integer: n = Integer(exp.p // exp.q) if not n: - return Pow(base, exp) + return result else: radical, result = Pow(base, exp - n), [] expanded_base_n = Pow(base, n) if expanded_base_n.is_Pow: - expanded_base_n = expanded_base_n._eval_expand_multinomial() + expanded_base_n = \ + expanded_base_n._eval_expand_multinomial() for term in Add.make_args(expanded_base_n): result.append(term*radical) @@ -426,21 +521,22 @@ if base.is_commutative: order_terms, other_terms = [], [] - for order in base.args: - if order.is_Order: - order_terms.append(order) + for b in base.args: + if b.is_Order: + order_terms.append(b) else: - other_terms.append(order) + other_terms.append(b) if order_terms: # (f(x) + O(x^n))^m -> f(x)^m + m*f(x)^{m-1} *O(x^n) f = Add(*other_terms) + o = Add(*order_terms) if n == 2: - return expand_multinomial(f**n, deep=False) + n*f*Add(*order_terms) + return expand_multinomial(f**n, deep=False) + n*f*o else: g = expand_multinomial(f**(n - 1), deep=False) - return expand_mul(f*g, deep=False) + n*g*Add(*order_terms) + return expand_mul(f*g, deep=False) + n*g*o if base.is_number: # Efficiently expand expressions of the form (a + b*I)**n @@ -465,9 +561,9 @@ while n: if n & 1: - c, d = a*c-b*d, b*c+a*d + c, d = a*c - b*d, b*c + a*d n -= 1 - a, b = a*a-b*b, 2*a*b + a, b = a*a - b*b, 2*a*b n //= 2 I = S.ImaginaryUnit @@ -484,37 +580,30 @@ # so now it's easy to get the correct result -- we get the # coefficients first: from sympy import multinomial_coefficients + from sympy.polys.polyutils import basic_from_dict expansion_dict = multinomial_coefficients(len(p), n) # in our example: {(3, 0): 1, (1, 2): 3, (0, 3): 1, (2, 1): 3} # and now construct the expression. - - # An elegant way would be to use Poly, but unfortunately it is - # slower than the direct method below, so it is commented out: - #b = {} - #for k in expansion_dict: - # b[k] = Integer(expansion_dict[k]) - #return Poly(b, *p).as_expr() - - from sympy.polys.polyutils import basic_from_dict - result = basic_from_dict(expansion_dict, *p) - return result + return basic_from_dict(expansion_dict, *p) else: if n == 2: return Add(*[f*g for f in base.args for g in base.args]) else: - multi = (base**(n-1))._eval_expand_multinomial() + multi = (base**(n - 1))._eval_expand_multinomial() if multi.is_Add: - return Add(*[f*g for f in base.args for g in multi.args]) + return Add(*[f*g for f in base.args + for g in multi.args]) else: + # XXX can this ever happen if base was an Add? return Add(*[f*multi for f in base.args]) - elif exp.is_Rational and exp.p < 0 and base.is_Add and abs(exp.p) > exp.q: + elif (exp.is_Rational and exp.p < 0 and base.is_Add and + abs(exp.p) > exp.q): return 1 / Pow(base, -exp)._eval_expand_multinomial() elif exp.is_Add and base.is_Number: # a + b a b # n --> n n , where n, a, b are Numbers coeff, tail = S.One, S.Zero - for term in exp.args: if term.is_Number: coeff *= Pow(base, term) @@ -526,13 +615,12 @@ return result def as_real_imag(self, deep=True, **hints): - from sympy.core.symbol import symbols from sympy.polys.polytools import poly if self.exp.is_Integer: exp = self.exp re, im = self.base.as_real_imag(deep=deep) - if re.func == C.re or im.func == C.im or not im: + if not im: return self, S.Zero a, b = symbols('a b', cls=Dummy) if exp >= 0: @@ -541,7 +629,8 @@ expr = expand_multinomial(self.base**exp) return expr.as_real_imag() - expr = poly((a + b)**exp) # a = re, b = im; expr = (a + b*I)**exp + expr = poly( + (a + b)**exp) # a = re, b = im; expr = (a + b*I)**exp else: mag = re**2 + im**2 re, im = re/mag, -im/mag @@ -610,13 +699,13 @@ if self.base.has(*syms): return self.base._eval_is_polynomial(syms) and \ - self.exp.is_Integer and \ - self.exp >= 0 + self.exp.is_Integer and \ + self.exp >= 0 else: return True def _eval_is_rational(self): - p = self.func(*self.as_base_exp()) # in case it's unevaluated + p = self.func(*self.as_base_exp()) # in case it's unevaluated if not p.is_Pow: return p.is_rational b, e = p.as_base_exp() @@ -633,7 +722,17 @@ if self.base.has(*syms): return self.base._eval_is_rational_function(syms) and \ - self.exp.is_Integer + self.exp.is_Integer + else: + return True + + def _eval_is_algebraic_expr(self, syms): + if self.exp.has(*syms): + return False + + if self.base.has(*syms): + return self.base._eval_is_algebraic_expr(syms) and \ + self.exp.is_Rational else: return True @@ -645,9 +744,9 @@ # this should be the same as ExpBase.as_numer_denom wrt # exponent handling neg_exp = exp.is_negative - int_exp = exp.is_integer - if not neg_exp and not exp.is_real: + if not neg_exp and not (-exp).is_negative: neg_exp = _coeff_isneg(exp) + int_exp = exp.is_integer # the denominator cannot be separated from the numerator if # its sign is unknown unless the exponent is an integer, e.g. # sqrt(a/b) != sqrt(a)/sqrt(b) when a=1 and b=-1. But if the @@ -667,9 +766,8 @@ exp = -exp return Pow(n, exp), Pow(d, exp) - def matches(self, expr, repl_dict={}): + def matches(self, expr, repl_dict={}, old=False): expr = _sympify(expr) - b, e = expr.as_base_exp() # special case, pattern = 1 and expr.exp can match to 0 if expr is S.One: @@ -678,6 +776,15 @@ if d is not None: return d + b, e = expr.as_base_exp() + + # special case number + sb, se = self.as_base_exp() + if sb.is_Symbol and se.is_Integer and expr: + if e.is_rational: + return sb.matches(b**(e/se), repl_dict) + return sb.matches(expr**(1/se), repl_dict) + d = repl_dict.copy() d = self.base.matches(b, d) if d is None: @@ -690,12 +797,12 @@ def _eval_nseries(self, x, n, logx): # NOTE! This function is an important part of the gruntz algorithm - # for computing limits. It has to return a generalized power series - # with coefficients in C(log, log(x)). In more detail: + # for computing limits. It has to return a generalized power + # series with coefficients in C(log, log(x)). In more detail: # It has to return an expression # c_0*x**e_0 + c_1*x**e_1 + ... (finitely many terms) - # where e_i are numbers (not necessarily integers) and c_i are expression - # involving only numbers, the log function, and log(x). + # where e_i are numbers (not necessarily integers) and c_i are + # expressions involving only numbers, the log function, and log(x). from sympy import powsimp, collect, exp, log, O, ceiling b, e = self.args if e.is_Integer: @@ -738,7 +845,8 @@ for m in range(1, ceiling(n/l)): new_term = terms[-1]*(-rest) if new_term.is_Pow: - new_term = new_term._eval_expand_multinomial(deep=False) + new_term = new_term._eval_expand_multinomial( + deep=False) else: new_term = expand_mul(new_term, deep=False) terms.append(new_term) @@ -748,7 +856,8 @@ terms.append(O(x**n)) return powsimp(Add(*terms), deep=True, combine='exp') else: - # negative powers are rewritten to the cases above, for example: + # negative powers are rewritten to the cases above, for + # example: # sin(x)**(-4) = 1/( sin(x)**4) = ... # and expand the denominator: denominator = (b**(-e))._eval_nseries(x, n=n, logx=logx) @@ -783,9 +892,9 @@ except TypeError: #well, the n is something more complicated (like 1+log(2)) try: - n = int(n.evalf()) + 1 # XXX why is 1 being added? + n = int(n.evalf()) + 1 # XXX why is 1 being added? except TypeError: - pass # hope that base allows this to be resolved + pass # hope that base allows this to be resolved n = _sympify(n) return n, unbounded @@ -804,15 +913,29 @@ return b0**ei - if (b0 is S.Zero or b0.is_unbounded): if unbounded is not False: - return b0**e # XXX what order + return b0**e # XXX what order - if not ei.is_number: # if not, how will we proceed? - raise ValueError('expecting numerical exponent but got %s' % ei) + if not ei.is_number: # if not, how will we proceed? + raise ValueError( + 'expecting numerical exponent but got %s' % ei) nuse = n - ei + + if e.is_real and e.is_positive: + lt = b.as_leading_term(x) + + # Try to correct nuse (= m) guess from: + # (lt + rest + O(x**m))**e = + # lt**e*(1 + rest/lt + O(x**m)/lt)**e = + # lt**e + ... + O(x**m)*lt**(e - 1) = ... + O(x**n) + try: + cf = C.Order(lt, x).getn() + nuse = ceiling(n - cf*(e - 1)) + except NotImplementedError: + pass + bs = b._eval_nseries(x, n=nuse, logx=logx) terms = bs.removeO() if terms.is_Add: @@ -820,10 +943,22 @@ lt = terms.as_leading_term(x) # bs -> lt + rest -> lt*(1 + (bs/lt - 1)) - return ((Pow(lt, e)* - Pow((bs/lt).expand(), e). - nseries(x, n=nuse, logx=logx)).expand() + - order) + return ((Pow(lt, e) * Pow((bs/lt).expand(), e).nseries( + x, n=nuse, logx=logx)).expand() + order) + + if bs.is_Add: + from sympy import O + # So, bs + O() == terms + c = Dummy('c') + res = [] + for arg in bs.args: + if arg.is_Order: + arg = c*arg.expr + res.append(arg) + bs = Add(*res) + rv = (bs**e).series(x).subs(c, O(1)) + rv += order + return rv rv = bs**e if terms != bs: @@ -864,8 +999,9 @@ return C.exp(self.exp * C.log(self.base)).as_leading_term(x) @cacheit - def taylor_term(self, n, x, *previous_terms): # of (1+x)**e - if n<0: return S.Zero + def taylor_term(self, n, x, *previous_terms): # of (1+x)**e + if n < 0: + return S.Zero x = _sympify(x) return C.binomial(self.exp, n) * Pow(x, n) @@ -902,7 +1038,7 @@ >>> eq.as_content_primitive() (9, 3**(2*x)) >>> powsimp(Mul(*_)) - 9**(x + 1) + 3**(2*x + 2) >>> eq = (2 + 2*x)**y >>> s = expand_power_base(eq); s.is_Mul, s @@ -941,10 +1077,10 @@ e = _keep_coeff(ce, pe) # b**e = (h*t)**e = h**e*t**e = c*m*t**e if e.is_Rational and b.is_Mul: - h, t = b.as_content_primitive(radical=radical) # h is positive - c, m = Pow(h, e).as_coeff_Mul() # so c is positive + h, t = b.as_content_primitive(radical=radical) # h is positive + c, m = Pow(h, e).as_coeff_Mul() # so c is positive m, me = m.as_base_exp() - if m is S.One or me == e: # probably always true + if m is S.One or me == e: # probably always true # return the following, not return c, m*Pow(t, e) # which would change Pow into Mul; we let sympy # decide what to do by using the unevaluated Mul, e.g @@ -958,7 +1094,7 @@ self = self.simplify() b, e = self.as_base_exp() bz = b.equals(0) - if bz: # recalculate with assumptions in case it's unevaluated + if bz: # recalculate with assumptions in case it's unevaluated new = b**e if new != self: return new.is_constant() @@ -978,4 +1114,4 @@ from .add import Add from .numbers import Integer from .mul import Mul, _keep_coeff -from .symbol import Symbol, Dummy +from .symbol import Symbol, Dummy, symbols diff -Nru python3-sympy-0.7.2/sympy/core/relational.py python3-sympy-0.7.3/sympy/core/relational.py --- python3-sympy-0.7.2/sympy/core/relational.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/core/relational.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,14 +1,15 @@ from .basic import S from .expr import Expr from .evalf import EvalfMixin +from .symbol import Symbol from .sympify import _sympify from sympy.logic.boolalg import Boolean __all__ = ( - 'Rel', 'Eq', 'Ne', 'Lt', 'Le', 'Gt', 'Ge', - 'Relational', 'Equality', 'Unequality', 'StrictLessThan', 'LessThan', - 'StrictGreaterThan', 'GreaterThan', + 'Rel', 'Eq', 'Ne', 'Lt', 'Le', 'Gt', 'Ge', + 'Relational', 'Equality', 'Unequality', 'StrictLessThan', 'LessThan', + 'StrictGreaterThan', 'GreaterThan', ) @@ -26,7 +27,8 @@ y == x**2 + x """ - return Relational(a,b,op) + return Relational(a, b, op) + def Eq(a, b=0): """ @@ -42,7 +44,8 @@ y == x**2 + x """ - return Relational(a,b,'==') + return Relational(a, b, '==') + def Ne(a, b): """ @@ -58,7 +61,8 @@ y != x**2 + x """ - return Relational(a,b,'!=') + return Relational(a, b, '!=') + def Lt(a, b): """ @@ -74,7 +78,8 @@ y < x**2 + x """ - return Relational(a,b,'<') + return Relational(a, b, '<') + def Le(a, b): """ @@ -90,7 +95,8 @@ y <= x**2 + x """ - return Relational(a,b,'<=') + return Relational(a, b, '<=') + def Gt(a, b): """ @@ -106,7 +112,8 @@ y > x**2 + x """ - return Relational(a,b,'>') + return Relational(a, b, '>') + def Ge(a, b): """ @@ -122,10 +129,12 @@ y >= x**2 + x """ - return Relational(a,b,'>=') + return Relational(a, b, '>=') # Note, see issue 1887. Ideally, we wouldn't want to subclass both Boolean # and Expr. + + class Relational(Boolean, Expr, EvalfMixin): __slots__ = [] @@ -146,22 +155,40 @@ except KeyError: msg = "Invalid relational operator symbol: '%r'" raise ValueError(msg % repr(rop)) - if (lhs.is_number and rhs.is_number and - (rop_cls in (Equality, Unequality) or - lhs.is_real and rhs.is_real)): + + diff = S.NaN + if isinstance(lhs, Expr) and isinstance(rhs, Expr): diff = lhs - rhs + if not (diff is S.NaN or diff.has(Symbol)): know = diff.equals(0, failing_expression=True) - if know is True: # exclude failing expression case - Nlhs = S.Zero + if know is True: # exclude failing expression case + diff = S.Zero elif know is False: - from sympy import sign - Nlhs = sign(diff.n(2)) - else: - Nlhs = None - lhs = know - rhs = S.Zero - if Nlhs is not None: - return rop_cls._eval_relation(Nlhs, S.Zero) + diff = diff.n() + if rop_cls is Equality: + if (lhs == rhs) is True or (diff == S.Zero) is True: + return True + elif diff is S.NaN: + pass + elif diff.is_Number or diff.is_Float: + return False + elif lhs.is_real is not rhs.is_real and \ + lhs.is_real is not None and \ + rhs.is_real is not None: + return False + elif rop_cls is Unequality: + if (lhs == rhs) is True or (diff == S.Zero) is True: + return False + elif diff is S.NaN: + pass + elif diff.is_Number or diff.is_Float: + return True + elif lhs.is_real is not rhs.is_real and \ + lhs.is_real is not None and \ + rhs.is_real is not None: + return True + elif diff.is_Number and diff.is_real: + return rop_cls._eval_relation(diff, S.Zero) obj = Expr.__new__(rop_cls, lhs, rhs, **assumptions) return obj @@ -189,6 +216,11 @@ def _eval_relation_doit(cls, lhs, rhs): return cls._eval_relation(lhs, rhs) + def _eval_simplify(self, ratio, measure): + return self.__class__(self.lhs.simplify(ratio=ratio), + self.rhs.simplify(ratio=ratio)) + + class Equality(Relational): rel_op = '==' @@ -206,7 +238,8 @@ return Eq(lhs, rhs) def __bool__(self): - return self.lhs.compare(self.rhs)==0 + return self.lhs.compare(self.rhs) == 0 + class Unequality(Relational): @@ -223,7 +256,8 @@ return Ne(lhs, rhs) def __bool__(self): - return self.lhs.compare(self.rhs)!=0 + return self.lhs.compare(self.rhs) != 0 + class _Greater(Relational): """Not intended for general use @@ -242,6 +276,7 @@ def lts(self): return self._args[1] + class _Less(Relational): """Not intended for general use. @@ -259,6 +294,7 @@ def lts(self): return self._args[0] + class GreaterThan(_Greater): """Class representations of inequalities. @@ -511,6 +547,7 @@ def __bool__(self): return self.lhs.compare( self.rhs ) >= 0 + class LessThan(_Less): __doc__ = GreaterThan.__doc__ __slots__ = () @@ -524,6 +561,7 @@ def __bool__(self): return self.lhs.compare( self.rhs ) <= 0 + class StrictGreaterThan(_Greater): __doc__ = GreaterThan.__doc__ __slots__ = () @@ -537,6 +575,7 @@ def __bool__(self): return self.lhs.compare( self.rhs ) > 0 + class StrictLessThan(_Less): __doc__ = GreaterThan.__doc__ __slots__ = () @@ -554,18 +593,18 @@ # is defined here, rather than directly in the class, because the classes that # it references have not been defined until now (e.g. StrictLessThan). Relational.ValidRelationOperator = { - None : Equality, - '==' : Equality, - 'eq' : Equality, - '!=' : Unequality, - '<>' : Unequality, - 'ne' : Unequality, - '>=' : GreaterThan, - 'ge' : GreaterThan, - '<=' : LessThan, - 'le' : LessThan, - '>' : StrictGreaterThan, - 'gt' : StrictGreaterThan, - '<' : StrictLessThan, - 'lt' : StrictLessThan, + None: Equality, + '==': Equality, + 'eq': Equality, + '!=': Unequality, + '<>': Unequality, + 'ne': Unequality, + '>=': GreaterThan, + 'ge': GreaterThan, + '<=': LessThan, + 'le': LessThan, + '>': StrictGreaterThan, + 'gt': StrictGreaterThan, + '<': StrictLessThan, + 'lt': StrictLessThan, } diff -Nru python3-sympy-0.7.2/sympy/core/rules.py python3-sympy-0.7.3/sympy/core/rules.py --- python3-sympy-0.7.2/sympy/core/rules.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/core/rules.py 2013-07-13 17:53:32.000000000 +0000 @@ -2,6 +2,7 @@ Replacement rules. """ + class Transform(object): """ Immutable mapping that can be used as a generic transformation rule. diff -Nru python3-sympy-0.7.2/sympy/core/sets.py python3-sympy-0.7.3/sympy/core/sets.py --- python3-sympy-0.7.2/sympy/core/sets.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/core/sets.py 2013-07-13 17:53:32.000000000 +0000 @@ -4,7 +4,6 @@ from sympy.core.evalf import EvalfMixin from sympy.core.numbers import Float from sympy.core.compatibility import iterable -from sympy.core.decorators import deprecated from sympy.mpmath import mpi, mpf from sympy.assumptions import ask @@ -12,6 +11,7 @@ from sympy.utilities import default_sort_key + class Set(Basic): """ The base class for any kind of set. @@ -241,8 +241,8 @@ return ProductSet(self, other) def __pow__(self, exp): - if not sympify(exp).is_Integer and exp>=0: - raise ValueError("%s: Exponent must be a positive Integer"%exp) + if not sympify(exp).is_Integer and exp >= 0: + raise ValueError("%s: Exponent must be a positive Integer" % exp) return ProductSet([self]*exp) def __sub__(self, other): @@ -265,6 +265,7 @@ def is_real(self): return None + class ProductSet(Set): """ Represents a Cartesian Product of Sets. @@ -317,7 +318,7 @@ raise TypeError("Input must be Sets or iterables of Sets") sets = flatten(list(sets)) - if EmptySet() in sets or len(sets)==0: + if EmptySet() in sets or len(sets) == 0: return EmptySet() return Basic.__new__(cls, *sets, **assumptions) @@ -339,7 +340,7 @@ try: if len(element) != len(self.args): return False - except TypeError: # maybe element isn't an iterable + except TypeError: # maybe element isn't an iterable return False return And(*[set.contains(item) for set, item in zip(self.sets, element)]) @@ -393,6 +394,7 @@ measure *= set.measure return measure + class Interval(Set, EvalfMixin): """ Represents a real interval as a Set. @@ -407,7 +409,7 @@ Examples ======== - >>> from sympy import Symbol, Interval, sets + >>> from sympy import Symbol, Interval >>> Interval(0, 1) [0, 1] @@ -580,28 +582,28 @@ if other.is_Interval and self._is_comparable(other): from sympy.functions.elementary.miscellaneous import Min, Max # Non-overlapping intervals - end = Min(self.end, other.end) + end = Min(self.end, other.end) start = Max(self.start, other.start) if (end < start or - (end==start and (end not in self and end not in other))): + (end == start and (end not in self and end not in other))): return None else: start = Min(self.start, other.start) - end = Max(self.end, other.end) + end = Max(self.end, other.end) - left_open = ((self.start != start or self.left_open) and - (other.start != start or other.left_open)) - right_open = ((self.end != end or self.right_open) and - (other.end != end or other.right_open)) + left_open = ((self.start != start or self.left_open) and + (other.start != start or other.left_open)) + right_open = ((self.end != end or self.right_open) and + (other.end != end or other.right_open)) return Interval(start, end, left_open, right_open) # If I have open end points and these endpoints are contained in other - if ((self.left_open and other.contains(self.start) is True) or - (self.right_open and other.contains(self.end) is True)): + if ((self.left_open and other.contains(self.start) is True) or + (self.right_open and other.contains(self.end) is True)): # Fill in my end points and return - open_left = self.left_open and self.start not in other - open_right = self.right_open and self.end not in other + open_left = self.left_open and self.start not in other + open_right = self.right_open and self.end not in other new_self = Interval(self.start, self.end, open_left, open_right) return set((new_self, other)) @@ -657,27 +659,25 @@ def as_relational(self, symbol): """Rewrite an interval in terms of inequalities and logic operators. """ - from sympy.core.relational import Lt, Le - - if not self.is_left_unbounded: + other = sympify(symbol) + if self.right_open: + right = other < self.end + else: + right = other <= self.end + if right is True: if self.left_open: - left = Lt(self.start, symbol) + return other > self.start else: - left = Le(self.start, symbol) - - if not self.is_right_unbounded: - if self.right_open: - right = Lt(symbol, self.right) - else: - right = Le(symbol, self.right) - if self.is_left_unbounded and self.is_right_unbounded: - return True # XXX: Contained(symbol, Floats) - elif self.is_left_unbounded: - return right - elif self.is_right_unbounded: - return left + return other >= self.start + if self.left_open: + left = self.start < other else: - return And(left, right) + left = self.start <= other + return And(left, right) + + @property + def free_symbols(self): + return self.start.free_symbols | self.end.free_symbols class Union(Set, EvalfMixin): """ @@ -712,19 +712,20 @@ # flatten inputs to merge intersections and iterables args = list(args) + def flatten(arg): if isinstance(arg, Set): if arg.is_Union: return sum(list(map(flatten, arg.args)), []) else: return [arg] - if iterable(arg): # and not isinstance(arg, Set) (implicit) + if iterable(arg): # and not isinstance(arg, Set) (implicit) return sum(list(map(flatten, arg)), []) raise TypeError("Input must be Sets or iterables of Sets") args = flatten(args) # Union of no sets is EmptySet - if len(args)==0: + if len(args) == 0: return S.EmptySet args = sorted(args, key=default_sort_key) @@ -774,7 +775,7 @@ args = new_args break - if len(args)==1: + if len(args) == 1: return args.pop() else: return Union(args, evaluate=False) @@ -874,6 +875,7 @@ def is_real(self): return all(set.is_real for set in self.args) + class Intersection(Set): """ Represents an intersection of sets as a Set. @@ -906,19 +908,20 @@ # flatten inputs to merge intersections and iterables args = list(args) + def flatten(arg): if isinstance(arg, Set): if arg.is_Intersection: return sum(list(map(flatten, arg.args)), []) else: return [arg] - if iterable(arg): # and not isinstance(arg, Set) (implicit) + if iterable(arg): # and not isinstance(arg, Set) (implicit) return sum(list(map(flatten, arg)), []) raise TypeError("Input must be Sets or iterables of Sets") args = flatten(args) # Intersection of no sets is everything - if len(args)==0: + if len(args) == 0: return S.UniversalSet args = sorted(args, key=default_sort_key) @@ -1010,7 +1013,7 @@ args = new_args break - if len(args)==1: + if len(args) == 1: return args.pop() else: return Intersection(args, evaluate=False) @@ -1019,6 +1022,7 @@ """Rewrite an Intersection in terms of equalities and logic operators""" return And(*[set.as_relational(symbol) for set in self.args]) + class EmptySet(Set, metaclass=Singleton): """ Represents the empty set. The empty set is available as a singleton @@ -1071,6 +1075,7 @@ def __iter__(self): return iter([]) + class UniversalSet(Set, metaclass=Singleton): """ Represents the set of all things. @@ -1117,6 +1122,7 @@ def _union(self, other): return self + class FiniteSet(Set, EvalfMixin): """ Represents a finite set of discrete numbers @@ -1124,7 +1130,7 @@ Examples ======== - >>> from sympy import Symbol, FiniteSet, sets + >>> from sympy import FiniteSet >>> FiniteSet(1, 2, 3, 4) {1, 2, 3, 4} @@ -1138,16 +1144,19 @@ is_FiniteSet = True is_iterable = True - def __new__(cls, *args): - if len(args)==1 and iterable(args[0]): - args = args[0] + def __new__(cls, *args, **kwargs): + evaluate = kwargs.get('evaluate', True) + if evaluate: + if len(args) == 1 and iterable(args[0]): + args = args[0] - args = list(map(sympify, args)) + args = list(map(sympify, args)) + + if len(args) == 0: + return EmptySet() - if len(args) == 0: - return EmptySet() - args = frozenset(args) # remove duplicates + args = frozenset(args) # remove duplicates obj = Basic.__new__(cls, *args) obj._elements = args return obj @@ -1213,16 +1222,16 @@ """ if not all(elem.is_number for elem in self): raise ValueError("%s: Complement not defined for symbolic inputs" - %self) + % self) # as there are only numbers involved, a straight sort is sufficient; # default_sort_key is not needed args = sorted(self.args) - intervals = [] # Build up a list of intervals between the elements + intervals = [] # Build up a list of intervals between the elements intervals += [Interval(S.NegativeInfinity, args[0], True, True)] for a, b in zip(args[:-1], args[1:]): - intervals.append(Interval(a, b, True, True)) # open intervals + intervals.append(Interval(a, b, True, True)) # open intervals intervals.append(Interval(args[-1], S.Infinity, True, True)) return Union(intervals, evaluate=False) diff -Nru python3-sympy-0.7.2/sympy/core/singleton.py python3-sympy-0.7.3/sympy/core/singleton.py --- python3-sympy-0.7.2/sympy/core/singleton.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/core/singleton.py 2013-07-13 17:53:32.000000000 +0000 @@ -4,6 +4,7 @@ from .assumptions import ManagedProperties from .sympify import sympify + class SingletonRegistry(Registry): """ A map between singleton classes and the corresponding instances. @@ -42,7 +43,7 @@ True ** Developer notes ** - The class is instanciated immediately at the point where it is defined + The class is instantiated immediately at the point where it is defined by calling cls.__new__(cls). This instance is cached and cls.__new__ is rebound to return it directly. diff -Nru python3-sympy-0.7.2/sympy/core/symbol.py python3-sympy-0.7.3/sympy/core/symbol.py --- python3-sympy-0.7.2/sympy/core/symbol.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/core/symbol.py 2013-07-13 17:53:32.000000000 +0000 @@ -8,9 +8,12 @@ from .function import FunctionClass from sympy.core.logic import fuzzy_bool from sympy.logic.boolalg import Boolean +from sympy.utilities.iterables import cartes from sympy.utilities.exceptions import SymPyDeprecationWarning -import re +import string +import re as _re + class Symbol(AtomicExpr, Boolean): """ @@ -59,14 +62,6 @@ """ - if 'dummy' in assumptions: - SymPyDeprecationWarning( - feature="Symbol('x', dummy=True)", - useinstead="Dummy() or symbols(..., cls=Dummy)", - issue=3378, deprecated_since_version="0.7.0", - ).warn() - if assumptions.pop('dummy'): - return Dummy(name, **assumptions) if assumptions.get('zero', False): return S.Zero is_commutative = fuzzy_bool(assumptions.get('commutative', True)) @@ -77,14 +72,17 @@ return Symbol.__xnew_cached_(cls, name, **assumptions) def __new_stage2__(cls, name, **assumptions): - assert isinstance(name, str),repr(type(name)) + if not isinstance(name, str): + raise TypeError("name should be a string, not %s" % repr(type(name))) obj = Expr.__new__(cls) obj.name = name obj._assumptions = StdFactKB(assumptions) return obj - __xnew__ = staticmethod(__new_stage2__) # never cached (e.g. dummy) - __xnew_cached_ = staticmethod(cacheit(__new_stage2__)) # symbols are always cached + __xnew__ = staticmethod( + __new_stage2__) # never cached (e.g. dummy) + __xnew_cached_ = staticmethod( + cacheit(__new_stage2__)) # symbols are always cached def __getnewargs__(self): return (self.name,) @@ -92,7 +90,6 @@ def __getstate__(self): return {'_assumptions': self._assumptions} - def _hashable_content(self): return (self.name,) + tuple(sorted(self.assumptions0.items())) @@ -135,6 +132,7 @@ def free_symbols(self): return set([self]) + class Dummy(Symbol): """Dummy symbols are each unique, identified by an internal count index: @@ -146,9 +144,8 @@ used. This is useful when a temporary variable is needed and the name of the variable used in the expression is not important. - >>> Dummy._count = 0 # /!\ this should generally not be changed; it is being - >>> Dummy() # used here to make sure that the doctest passes. - _0 + >>> Dummy() #doctest: +SKIP + _Dummy_10 """ @@ -160,7 +157,7 @@ def __new__(cls, name=None, **assumptions): if name is None: - name = str(Dummy._count) + name = "Dummy_" + str(Dummy._count) is_commutative = fuzzy_bool(assumptions.get('commutative', True)) if is_commutative is None: @@ -179,9 +176,31 @@ def _hashable_content(self): return Symbol._hashable_content(self) + (self.dummy_index,) + class Wild(Symbol): """ - Wild() matches any expression but another Wild(). + A Wild symbol matches anything. + + Examples + ======== + + >>> from sympy import Wild, WildFunction, cos, pi + >>> from sympy.abc import x + >>> a = Wild('a') + >>> b = Wild('b') + >>> b.match(a) + {a_: b_} + >>> x.match(a) + {a_: x} + >>> pi.match(a) + {a_: pi} + >>> (x**2).match(a) + {a_: x**2} + >>> cos(x).match(a) + {a_: cos(x)} + >>> A = WildFunction('A') + >>> A.match(a) + {a_: A_} """ __slots__ = ['exclude', 'properties'] @@ -212,7 +231,7 @@ return super(Wild, self)._hashable_content() + (self.exclude, self.properties) # TODO add check against another Wild - def matches(self, expr, repl_dict={}): + def matches(self, expr, repl_dict={}, old=False): if any(expr.has(x) for x in self.exclude): return None if any(not f(expr) for f in self.properties): @@ -224,9 +243,8 @@ def __call__(self, *args, **kwargs): raise TypeError("'%s' object is not callable" % type(self).__name__) -_re_var_range = re.compile(r"^(.*?)(\d*):(\d+)$") -_re_var_scope = re.compile(r"^(.):(.)$") -_re_var_split = re.compile(r"\s*,\s*|\s+") + +_range = _re.compile('([0-9]*:[0-9]+|[a-zA-Z]?:[a-zA-Z])') def symbols(names, **args): """ @@ -262,13 +280,21 @@ >>> symbols('x', seq=True) (x,) - To reduce typing, range syntax is supported to create indexed symbols:: + To reduce typing, range syntax is supported to create indexed symbols. + Ranges are indicated by a colon and the type of range is determined by + the character to the right of the colon. If the character is a digit + then all continguous digits to the left are taken as the nonnegative + starting value (or 0 if there are no digit of the colon) and all + contiguous digits to the right are taken as 1 greater than the ending + value:: >>> symbols('x:10') (x0, x1, x2, x3, x4, x5, x6, x7, x8, x9) >>> symbols('x5:10') (x5, x6, x7, x8, x9) + >>> symbols('x5(:2)') + (x50, x51) >>> symbols('x5:10,y:5') (x5, x6, x7, x8, x9, y0, y1, y2, y3, y4) @@ -276,18 +302,46 @@ >>> symbols(('x5:10', 'y:5')) ((x5, x6, x7, x8, x9), (y0, y1, y2, y3, y4)) - To reduce typing even more, lexicographic range syntax is supported:: + If the character to the right of the colon is a letter, then the single + letter to the left (or 'a' if there is none) is taken as the start + and all characters in the lexicographic range *through* the letter to + the right are used as the range:: >>> symbols('x:z') (x, y, z) + >>> symbols('x:c') # null range + () + >>> symbols('x(:c)') + (xa, xb, xc) - >>> symbols('a:d,x:z') + >>> symbols(':c') + (a, b, c) + + >>> symbols('a:d, x:z') (a, b, c, d, x, y, z) >>> symbols(('a:d', 'x:z')) ((a, b, c, d), (x, y, z)) - All newly created symbols have assumptions set accordingly to ``args``:: + Multiple ranges are supported; contiguous numerical ranges should be + separated by parentheses to disambiguate the ending number of one + range from the starting number of the next:: + + >>> symbols('x:2(1:3)') + (x01, x02, x11, x12) + >>> symbols(':3:2') # parsing is from left to right + (00, 01, 10, 11, 20, 21) + + Only one pair of parentheses surrounding ranges are removed, so to + include parentheses around ranges, double them. And to include spaces, + commas, or colons, escape them with a backslash:: + + >>> symbols('x((a:b))') + (x(a), x(b)) + >>> symbols('x(:1\,:2)') # or 'x((:1)\,(:2))' + (x(0,0), x(0,1)) + + All newly created symbols have assumptions set according to ``args``:: >>> a = symbols('a', integer=True) >>> a.is_integer @@ -297,9 +351,9 @@ >>> x.is_real and y.is_real and z.is_real True - Despite its name, :func:`symbols` can create symbol--like objects of - other type, for example instances of Function or Wild classes. To - achieve this, set ``cls`` keyword argument to the desired type:: + Despite its name, :func:`symbols` can create symbol-like objects like + instances of Function or Wild classes. To achieve this, set ``cls`` + keyword argument to the desired type:: >>> symbols('f,g,h', cls=Function) (f, g, h) @@ -318,17 +372,41 @@ feature="each_char in the options to symbols() and var()", useinstead="spaces or commas between symbol names", issue=1919, deprecated_since_version="0.7.0", value=value - ).warn() + ).warn() if isinstance(names, str): + marker = 0 + literals = ['\,', '\:', '\ '] + for i in range(len(literals)): + lit = literals.pop(0) + if lit in names: + while chr(marker) in names: + marker += 1 + lit_char = chr(marker) + marker += 1 + names = names.replace(lit, lit_char) + literals.append((lit_char, lit[1:])) + def literal(s): + if literals: + for c, l in literals: + s = s.replace(c, l) + return s + names = names.strip() - as_seq= names.endswith(',') + as_seq = names.endswith(',') if as_seq: names = names[:-1].rstrip() if not names: raise ValueError('no symbols given') - names = _re_var_split.split(names) + # split on commas + names = [n.strip() for n in names.split(',')] + if not all(n for n in names): + raise ValueError('missing symbol between commas') + # split on spaces + for i in range(len(names) - 1, -1, -1): + names[i: i + 1] = names[i].split() + if args.pop('each_char', False) and not as_seq and len(names) == 1: return symbols(tuple(names[0]), **args) @@ -340,44 +418,50 @@ raise ValueError('missing symbol') if ':' not in name: - symbol = cls(name, **args) + symbol = cls(literal(name), **args) result.append(symbol) continue - match = _re_var_range.match(name) - - if match is not None: - name, start, end = match.groups() - - if not start: - start = 0 + split = _range.split(name) + # remove 1 layer of bounding parentheses around ranges + for i in range(len(split) - 1): + if i and ':' in split[i] and split[i] != ':' and \ + split[i - 1].endswith('(') and \ + split[i + 1].startswith(')'): + split[i - 1] = split[i - 1][:-1] + split[i + 1] = split[i + 1][1:] + for i, s in enumerate(split): + if ':' in s: + if s[-1].endswith(':'): + raise ValueError('missing end range') + a, b = s.split(':') + if b[-1] in string.digits: + a = 0 if not a else int(a) + b = int(b) + split[i] = [str(c) for c in range(a, b)] + else: + a = a or 'a' + split[i] = [string.ascii_letters[c] for c in range( + string.ascii_letters.index(a), + string.ascii_letters.index(b) + 1)] # inclusive + if not split[i]: + break else: - start = int(start) - - for i in range(start, int(end)): - symbol = cls("%s%i" % (name, i), **args) - result.append(symbol) - - seq = True - continue - - match = _re_var_scope.match(name) - - if match is not None: - start, end = match.groups() - - for name in range(ord(start), ord(end)+1): - symbol = cls(chr(name), **args) - result.append(symbol) - + split[i] = [s] + else: seq = True - continue - - raise ValueError("'%s' is not a valid symbol range specification" % name) + if len(split) == 1: + names = split[0] + else: + names = [''.join(s) for s in cartes(*split)] + if literals: + result.extend([cls(literal(s), **args) for s in names]) + else: + result.extend([cls(s, **args) for s in names]) if not seq and len(result) <= 1: if not result: - raise ValueError('missing symbol') # should never happen + return () return result[0] return tuple(result) @@ -387,6 +471,7 @@ return type(names)(result) + def var(names, **args): """ Create symbols and inject them into the global namespace. @@ -440,6 +525,6 @@ else: traverse(syms, frame) finally: - del frame # break cyclic dependencies as stated in inspect docs + del frame # break cyclic dependencies as stated in inspect docs return syms diff -Nru python3-sympy-0.7.2/sympy/core/sympify.py python3-sympy-0.7.3/sympy/core/sympify.py --- python3-sympy-0.7.2/sympy/core/sympify.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/core/sympify.py 2013-07-13 17:53:32.000000000 +0000 @@ -10,6 +10,7 @@ def __init__(self, expr, base_exc=None): self.expr = expr self.base_exc = base_exc + def __str__(self): if self.base_exc is None: return "SympifyError: %r" % (self.expr,) @@ -18,25 +19,51 @@ "raised:\n%s: %s" % (self.expr, self.base_exc.__class__.__name__, str(self.base_exc))) -converter = {} #See sympify docstring. +converter = {} # See sympify docstring. + +class CantSympify(object): + """ + Mix in this trait to a class to disallow sympification of its instances. + + Example + ======= + + >>> from sympy.core.sympify import sympify, CantSympify + + >>> class Something(dict): + ... pass + ... + >>> sympify(Something()) + {} + + >>> class Something(dict, CantSympify): + ... pass + ... + >>> sympify(Something()) + Traceback (most recent call last): + ... + SympifyError: SympifyError: {} + + """ + pass def sympify(a, locals=None, convert_xor=True, strict=False, rational=False): """ - Converts an arbitrary expression to a type that can be used inside sympy. + Converts an arbitrary expression to a type that can be used inside SymPy. - For example, it will convert python ints into instance of sympy.Rational, + For example, it will convert Python ints into instance of sympy.Rational, floats into instances of sympy.Float, etc. It is also able to coerce symbolic expressions which inherit from Basic. This can be useful in cooperation with SAGE. It currently accepts as arguments: - - any object defined in sympy (except matrices [TODO]) + - any object defined in sympy - standard numeric python types: int, long, float, Decimal - strings (like "0.09" or "2e-19") - booleans, including ``None`` (will leave them unchanged) - lists, sets or tuples containing any of the above - If the argument is already a type that sympy understands, it will do + If the argument is already a type that SymPy understands, it will do nothing but return that value. This can be used at the beginning of a function to ensure you are working with the correct type. @@ -61,6 +88,59 @@ ... SympifyError: SympifyError: "could not parse u'x***2'" + Locals + ------ + + The sympification happens with access to everything that is loaded + by ``from sympy import *``; anything used in a string that is not + defined by that import will be converted to a symbol. In the following, + the ``bitcout`` function is treated as a symbol and the ``O`` is + interpreted as the Order object (used with series) and it raises + an error when used improperly: + + >>> s = 'bitcount(42)' + >>> sympify(s) + bitcount(42) + >>> sympify("O(x)") + O(x) + >>> sympify("O + 1") + Traceback (most recent call last): + ... + TypeError: unbound method... + + In order to have ``bitcount`` be recognized it can be imported into a + namespace dictionary and passed as locals: + + >>> ns = {} + >>> exec('from sympy.core.evalf import bitcount', ns) + >>> sympify(s, locals=ns) + 6 + + In order to have the ``O`` interpreted as a Symbol, identify it as such + in the namespace dictionary. This can be done in a variety of ways; all + three of the following are possibilities: + + >>> from sympy import Symbol + >>> ns["O"] = Symbol("O") # method 1 + >>> exec('from sympy.abc import O', ns) # method 2 + >>> ns.update(dict(O=Symbol("O"))) # method 3 + >>> sympify("O + 1", locals=ns) + O + 1 + + If you want *all* single-letter and Greek-letter variables to be symbols + then you can use the clashing-symbols dictionaries that have been defined + there as private variables: _clash1 (single-letter variables), _clash2 + (the multi-letter Greek names) or _clash (both single and multi-letter + names that are defined in abc). + + >>> from sympy.abc import _clash1 + >>> _clash1 + {'C': C, 'E': E, 'I': I, 'N': N, 'O': O, 'Q': Q, 'S': S} + >>> sympify('C & Q', _clash1) + And(C, Q) + + Strict + ------ If the option ``strict`` is set to ``True``, only the types for which an explicit conversion has been defined are converted. In the other @@ -73,6 +153,9 @@ ... SympifyError: SympifyError: True + Extending + --------- + To extend ``sympify`` to convert custom objects (not derived from ``Basic``), just define a ``_sympy_`` method to your class. You can do that even to classes that you do not own by subclassing or adding the method at runtime. @@ -86,8 +169,9 @@ ... def __getitem__(self, i): return list(self)[i] ... def _sympy_(self): return Matrix(self) >>> sympify(MyList1()) - [1] - [2] + Matrix([ + [1], + [2]]) If you do not have control over the class definition you could also use the ``converter`` global dictionary. The key is the class and the value is a @@ -103,13 +187,33 @@ >>> from sympy.core.sympify import converter >>> converter[MyList2] = lambda x: Matrix(x) >>> sympify(MyList2()) - [1] - [2] + Matrix([ + [1], + [2]]) + + Notes + ===== + + Sometimes autosimplification during sympification results in expressions + that are very different in structure than what was entered. Until such + autosimplification is no longer done, the ``kernS`` function might be of + some use. In the example below you can see how an expression reduces to + -1 by autosimplification, but does not do so when ``kernS`` is used. + + >>> from sympy.core.sympify import kernS + >>> from sympy.abc import x + >>> -2*(-(-x + 1/x)/(x*(x - 1/x)**2) - 1/(x*(x - 1/x))) - 1 + -1 + >>> s = '-2*(-(-x + 1/x)/(x*(x - 1/x)**2) - 1/(x*(x - 1/x))) - 1' + >>> sympify(s) + -1 + >>> kernS(s) + -2*(-(-x + 1/x)/(x*(x - 1/x)**2) - 1/(x*(x - 1/x))) - 1 """ try: cls = a.__class__ - except AttributeError: #a is probably an old-style class object + except AttributeError: # a is probably an old-style class object cls = type(a) if cls in sympy_classes: return a @@ -128,6 +232,9 @@ except KeyError: continue + if isinstance(a, CantSympify): + raise SympifyError(a) + try: return a._sympy_() except AttributeError: @@ -171,39 +278,145 @@ except Exception as exc: raise SympifyError(a, exc) - from sympy.parsing.sympy_parser import parse_expr, TokenError + from sympy.parsing.sympy_parser import (parse_expr, TokenError, + standard_transformations) + from sympy.parsing.sympy_parser import convert_xor as t_convert_xor + from sympy.parsing.sympy_parser import rationalize as t_rationalize + + transformations = standard_transformations + + if rational: + transformations += (t_rationalize,) + if convert_xor: + transformations += (t_convert_xor,) try: a = a.replace('\n', '') - expr = parse_expr(a, locals or {}, rational, convert_xor) - except (TokenError, SyntaxError): - raise SympifyError('could not parse %r' % a) + expr = parse_expr(a, local_dict=locals, transformations=transformations) + except (TokenError, SyntaxError) as exc: + raise SympifyError('could not parse %r' % a, exc) return expr + def _sympify(a): - """Short version of sympify for internal usage for __add__ and __eq__ - methods where it is ok to allow some things (like Python integers - and floats) in the expression. This excludes things (like strings) - that are unwise to allow into such an expression. - - >>> from sympy import Integer - >>> Integer(1) == 1 - True - - >>> Integer(1) == '1' - False - - >>> from sympy import Symbol - >>> from sympy.abc import x - >>> x + 1 - x + 1 - - >>> x + '1' - Traceback (most recent call last): - ... - TypeError: unsupported operand type(s) for +: 'Symbol' and 'str' + """ + Short version of sympify for internal usage for __add__ and __eq__ methods + where it is ok to allow some things (like Python integers and floats) in + the expression. This excludes things (like strings) that are unwise to + allow into such an expression. + + >>> from sympy import Integer + >>> Integer(1) == 1 + True + + >>> Integer(1) == '1' + False + + >>> from sympy.abc import x + >>> x + 1 + x + 1 + + >>> x + '1' + Traceback (most recent call last): + ... + TypeError: unsupported operand type(s) for +: 'Symbol' and 'str' + + see: sympify - see: sympify """ return sympify(a, strict=True) + + +def kernS(s): + """Use a hack to try keep autosimplification from joining Integer or + minus sign into an Add of a Mul; this modification doesn't + prevent the 2-arg Mul from becoming an Add, however. + + Examples + ======== + + >>> from sympy.core.sympify import kernS + >>> from sympy.abc import x, y, z + + The 2-arg Mul allows a leading Integer to be distributed but kernS will + prevent that: + + >>> 2*(x + y) + 2*x + 2*y + >>> kernS('2*(x + y)') + 2*(x + y) + + If use of the hack fails, the un-hacked string will be passed to sympify... + and you get what you get. + + XXX This hack should not be necessary once issue 1497 has been resolved. + """ + import re + from sympy.core.symbol import Symbol + + hit = False + if '(' in s: + if s.count('(') != s.count(")"): + raise SympifyError('unmatched left parenthesis') + + kern = '_kern' + while kern in s: + kern += "_" + olds = s + # digits*( -> digits*kern*( + s = re.sub(r'(\d+)( *\* *)\(', r'\1*%s\2(' % kern, s) + # negated parenthetical + kern2 = kern + "2" + while kern2 in s: + kern2 += "_" + # step 1: -(...) --> kern-kern*(...) + target = r'%s-%s*(' % (kern, kern) + s = re.sub(r'- *\(', target, s) + # step 2: double the matching closing parenthesis + # kern-kern*(...) --> kern-kern*(...)kern2 + i = nest = 0 + while True: + j = s.find(target, i) + if j == -1: + break + j = s.find('(') + for j in range(j, len(s)): + if s[j] == "(": + nest += 1 + elif s[j] == ")": + nest -= 1 + if nest == 0: + break + s = s[:j] + kern2 + s[j:] + i = j + # step 3: put in the parentheses + # kern-kern*(...)kern2 --> (-kern*(...)) + s = s.replace(target, target.replace(kern, "(", 1)) + s = s.replace(kern2, ')') + hit = kern in s + + for i in range(2): + try: + expr = sympify(s) + break + except: # the kern might cause unknown errors, so use bare except + if hit: + s = olds # maybe it didn't like the kern; use un-kerned s + hit = False + continue + expr = sympify(s) # let original error raise + + if not hit: + return expr + + rep = {Symbol(kern): 1} + def _clear(expr): + if isinstance(expr, (list, tuple, set)): + return type(expr)([_clear(e) for e in expr]) + if hasattr(expr, 'subs'): + return expr.subs(rep, hack2=True) + return expr + expr = _clear(expr) + # hope that kern is not there anymore + return expr diff -Nru python3-sympy-0.7.2/sympy/core/tests/test_args.py python3-sympy-0.7.3/sympy/core/tests/test_args.py --- python3-sympy-0.7.2/sympy/core/tests/test_args.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/core/tests/test_args.py 2013-07-13 17:53:32.000000000 +0000 @@ -10,13 +10,13 @@ import re import warnings -from sympy import Basic, S, symbols, sqrt, sin -from sympy import Basic, S, symbols, sqrt, sin, oo, Interval +from sympy import Basic, S, symbols, sqrt, sin, oo, Interval, exp from sympy.utilities.pytest import XFAIL, SKIP from sympy.utilities.exceptions import SymPyDeprecationWarning x, y, z = symbols('x,y,z') + def test_all_classes_are_tested(): this = os.path.split(__file__)[0] path = os.path.join(this, os.pardir, os.pardir) @@ -78,18 +78,22 @@ assert not failed, "Missing classes: %s. Please add tests for these to sympy/core/tests/test_args.py." % ", ".join(failed) + def _test_args(obj): return all(isinstance(arg, Basic) for arg in obj.args) + @XFAIL def test_sympy__assumptions__assume__AppliedPredicate(): from sympy.assumptions.assume import AppliedPredicate, Predicate assert _test_args(AppliedPredicate(Predicate("test"), 2)) + def test_sympy__assumptions__assume__Predicate(): from sympy.assumptions.assume import Predicate assert _test_args(Predicate("test")) + @XFAIL def test_sympy__combinatorics__graycode__GrayCode(): from sympy.combinatorics.graycode import GrayCode @@ -97,1185 +101,1640 @@ assert _test_args(GrayCode(3, start='100')) assert _test_args(GrayCode(3, rank=1)) + def test_sympy__combinatorics__subsets__Subset(): from sympy.combinatorics.subsets import Subset assert _test_args(Subset([0, 1], [0, 1, 2, 3])) - assert _test_args(Subset(['c','d'], ['a','b','c','d'])) + assert _test_args(Subset(['c', 'd'], ['a', 'b', 'c', 'd'])) + @XFAIL def test_sympy__combinatorics__permutations__Permutation(): from sympy.combinatorics.permutations import Permutation assert _test_args(Permutation([0, 1, 2, 3])) + @XFAIL def test_sympy__combinatorics__perm_groups__PermutationGroup(): from sympy.combinatorics.permutations import Permutation from sympy.combinatorics.perm_groups import PermutationGroup assert _test_args(PermutationGroup([Permutation([0, 1])])) + def test_sympy__combinatorics__polyhedron__Polyhedron(): from sympy.combinatorics.permutations import Permutation from sympy.combinatorics.polyhedron import Polyhedron from sympy.abc import w, x, y, z - pgroup = [Permutation([[0,1,2], [3]]),\ - Permutation([[0,1,3], [2]]),\ - Permutation([[0,2,3], [1]]),\ - Permutation([[1,2,3], [0]]),\ - Permutation([[0,1], [2,3]]),\ - Permutation([[0,2], [1,3]]),\ - Permutation([[0,3], [1,2]]),\ + pgroup = [Permutation([[0, 1, 2], [3]]), + Permutation([[0, 1, 3], [2]]), + Permutation([[0, 2, 3], [1]]), + Permutation([[1, 2, 3], [0]]), + Permutation([[0, 1], [2, 3]]), + Permutation([[0, 2], [1, 3]]), + Permutation([[0, 3], [1, 2]]), Permutation([[0, 1, 2, 3]])] corners = [w, x, y, z] - faces = [(w,x,y),(w,y,z),(w,z,x),(x,y,z)] + faces = [(w, x, y), (w, y, z), (w, z, x), (x, y, z)] assert _test_args(Polyhedron(corners, faces, pgroup)) + @XFAIL def test_sympy__combinatorics__prufer__Prufer(): from sympy.combinatorics.prufer import Prufer assert _test_args(Prufer([[0, 1], [0, 2], [0, 3]], 4)) + def test_sympy__combinatorics__partitions__Partition(): from sympy.combinatorics.partitions import Partition assert _test_args(Partition([[1]])) + @XFAIL def test_sympy__combinatorics__partitions__IntegerPartition(): from sympy.combinatorics.partitions import IntegerPartition assert _test_args(IntegerPartition([1])) + def test_sympy__concrete__products__Product(): from sympy.concrete.products import Product assert _test_args(Product(x, (x, 0, 10))) assert _test_args(Product(x, (x, 0, y), (y, 0, 10))) + def test_sympy__concrete__summations__Sum(): from sympy.concrete.summations import Sum assert _test_args(Sum(x, (x, 0, 10))) assert _test_args(Sum(x, (x, 0, y), (y, 0, 10))) + def test_sympy__core__add__Add(): from sympy.core.add import Add assert _test_args(Add(x, y, z, 2)) + def test_sympy__core__basic__Atom(): from sympy.core.basic import Atom assert _test_args(Atom()) + def test_sympy__core__basic__Basic(): from sympy.core.basic import Basic assert _test_args(Basic()) + def test_sympy__core__containers__Dict(): from sympy.core.containers import Dict assert _test_args(Dict({x: y, y: z})) + def test_sympy__core__containers__Tuple(): from sympy.core.containers import Tuple assert _test_args(Tuple(x, y, z, 2)) + def test_sympy__core__expr__AtomicExpr(): from sympy.core.expr import AtomicExpr assert _test_args(AtomicExpr()) + def test_sympy__core__expr__Expr(): from sympy.core.expr import Expr assert _test_args(Expr()) + def test_sympy__core__function__Application(): from sympy.core.function import Application assert _test_args(Application(1, 2, 3)) + def test_sympy__core__function__AppliedUndef(): from sympy.core.function import AppliedUndef assert _test_args(AppliedUndef(1, 2, 3)) + def test_sympy__core__function__Derivative(): from sympy.core.function import Derivative assert _test_args(Derivative(2, x, y, 3)) + @SKIP("abstract class") def test_sympy__core__function__Function(): pass + def test_sympy__core__function__Lambda(): from sympy.core.function import Lambda assert _test_args(Lambda((x, y), x + y + z)) + def test_sympy__core__function__Subs(): from sympy.core.function import Subs assert _test_args(Subs(x + y, x, 2)) + def test_sympy__core__function__WildFunction(): from sympy.core.function import WildFunction assert _test_args(WildFunction('f')) + def test_sympy__core__mod__Mod(): from sympy.core.mod import Mod assert _test_args(Mod(x, 2)) + def test_sympy__core__mul__Mul(): from sympy.core.mul import Mul assert _test_args(Mul(2, x, y, z)) + def test_sympy__core__numbers__Catalan(): from sympy.core.numbers import Catalan assert _test_args(Catalan()) + def test_sympy__core__numbers__ComplexInfinity(): from sympy.core.numbers import ComplexInfinity assert _test_args(ComplexInfinity()) + def test_sympy__core__numbers__EulerGamma(): from sympy.core.numbers import EulerGamma assert _test_args(EulerGamma()) + def test_sympy__core__numbers__Exp1(): from sympy.core.numbers import Exp1 assert _test_args(Exp1()) + def test_sympy__core__numbers__Float(): from sympy.core.numbers import Float assert _test_args(Float(1.23)) + def test_sympy__core__numbers__GoldenRatio(): from sympy.core.numbers import GoldenRatio assert _test_args(GoldenRatio()) + def test_sympy__core__numbers__Half(): from sympy.core.numbers import Half assert _test_args(Half()) + def test_sympy__core__numbers__ImaginaryUnit(): from sympy.core.numbers import ImaginaryUnit assert _test_args(ImaginaryUnit()) + def test_sympy__core__numbers__Infinity(): from sympy.core.numbers import Infinity assert _test_args(Infinity()) + def test_sympy__core__numbers__Integer(): from sympy.core.numbers import Integer assert _test_args(Integer(7)) + @SKIP("abstract class") def test_sympy__core__numbers__IntegerConstant(): pass + def test_sympy__core__numbers__NaN(): from sympy.core.numbers import NaN assert _test_args(NaN()) + def test_sympy__core__numbers__NegativeInfinity(): from sympy.core.numbers import NegativeInfinity assert _test_args(NegativeInfinity()) + def test_sympy__core__numbers__NegativeOne(): from sympy.core.numbers import NegativeOne assert _test_args(NegativeOne()) + def test_sympy__core__numbers__Number(): from sympy.core.numbers import Number assert _test_args(Number(1, 7)) + def test_sympy__core__numbers__NumberSymbol(): from sympy.core.numbers import NumberSymbol assert _test_args(NumberSymbol()) + def test_sympy__core__numbers__One(): from sympy.core.numbers import One assert _test_args(One()) + def test_sympy__core__numbers__Pi(): from sympy.core.numbers import Pi assert _test_args(Pi()) + def test_sympy__core__numbers__Rational(): from sympy.core.numbers import Rational assert _test_args(Rational(1, 7)) + def test_sympy__core__numbers__RationalConstant(): from sympy.core.numbers import RationalConstant assert _test_args(RationalConstant()) + def test_sympy__core__numbers__Zero(): from sympy.core.numbers import Zero assert _test_args(Zero()) + @SKIP("abstract class") def test_sympy__core__operations__AssocOp(): pass + @SKIP("abstract class") def test_sympy__core__operations__LatticeOp(): pass + def test_sympy__core__power__Pow(): from sympy.core.power import Pow assert _test_args(Pow(x, 2)) + def test_sympy__core__relational__Equality(): from sympy.core.relational import Equality assert _test_args(Equality(x, 2)) + def test_sympy__core__relational__GreaterThan(): from sympy.core.relational import GreaterThan assert _test_args(GreaterThan(x, 2)) + def test_sympy__core__relational__LessThan(): from sympy.core.relational import LessThan assert _test_args(LessThan(x, 2)) + @SKIP("abstract class") def test_sympy__core__relational__Relational(): pass + def test_sympy__core__relational__StrictGreaterThan(): from sympy.core.relational import StrictGreaterThan assert _test_args(StrictGreaterThan(x, 2)) + def test_sympy__core__relational__StrictLessThan(): from sympy.core.relational import StrictLessThan assert _test_args(StrictLessThan(x, 2)) + def test_sympy__core__relational__Unequality(): from sympy.core.relational import Unequality assert _test_args(Unequality(x, 2)) + def test_sympy__core__sets__EmptySet(): from sympy.core.sets import EmptySet assert _test_args(EmptySet()) + def test_sympy__core__sets__UniversalSet(): from sympy.core.sets import UniversalSet assert _test_args(UniversalSet()) + def test_sympy__core__sets__FiniteSet(): from sympy.core.sets import FiniteSet assert _test_args(FiniteSet(x, y, z)) + @XFAIL def test_sympy__core__sets__Interval(): from sympy.core.sets import Interval assert _test_args(Interval(0, 1)) + def test_sympy__core__sets__ProductSet(): from sympy.core.sets import ProductSet, Interval assert _test_args(ProductSet(Interval(0, 1), Interval(0, 1))) + @SKIP("does it make sense to test this?") def test_sympy__core__sets__Set(): from sympy.core.sets import Set assert _test_args(Set()) + def test_sympy__core__sets__Intersection(): from sympy.core.sets import Intersection, Interval assert _test_args(Intersection(Interval(0, 3), Interval(2, 4), evaluate=False)) + def test_sympy__core__sets__Union(): from sympy.core.sets import Union, Interval assert _test_args(Union(Interval(0, 1), Interval(2, 3))) + def test_sympy__core__trace__Tr(): from sympy.core.trace import Tr - a,b = symbols('a b') - assert _test_args(Tr(a+b)) + a, b = symbols('a b') + assert _test_args(Tr(a + b)) + def test_sympy__sets__fancysets__Naturals(): from sympy.sets.fancysets import Naturals assert _test_args(Naturals()) +def test_sympy__sets__fancysets__Naturals0(): + from sympy.sets.fancysets import Naturals0 + assert _test_args(Naturals0()) + def test_sympy__sets__fancysets__Integers(): from sympy.sets.fancysets import Integers assert _test_args(Integers()) -@XFAIL # This fails for the same reason Interval fails. Not all args are Basic + +@XFAIL # This fails for the same reason Interval fails. Not all args are Basic def test_sympy__sets__fancysets__Reals(): from sympy.sets.fancysets import Reals assert _test_args(Reals()) + def test_sympy__sets__fancysets__TransformationSet(): from sympy.sets.fancysets import TransformationSet from sympy import S, Lambda, Symbol x = Symbol('x') assert _test_args(TransformationSet(Lambda(x, x**2), S.Naturals)) + def test_sympy__sets__fancysets__Range(): from sympy.sets.fancysets import Range assert _test_args(Range(1, 5, 1)) # STATS -def normal_pdf(x): - from sympy import pi, exp, sqrt - pdf = sqrt(2)*exp(-x**2/2)/(2*sqrt(pi)) - return pdf + + +from sympy.stats.crv_types import NormalDistribution +nd = NormalDistribution(0, 1) +from sympy.stats.frv_types import DieDistribution +die = DieDistribution(6) + def test_sympy__stats__crv__ContinuousDomain(): from sympy.stats.crv import ContinuousDomain - assert _test_args(ContinuousDomain(set([x]), Interval(-oo,oo))) + assert _test_args(ContinuousDomain(set([x]), Interval(-oo, oo))) + def test_sympy__stats__crv__SingleContinuousDomain(): from sympy.stats.crv import SingleContinuousDomain - assert _test_args(SingleContinuousDomain(x, Interval(-oo,oo))) + assert _test_args(SingleContinuousDomain(x, Interval(-oo, oo))) + def test_sympy__stats__crv__ProductContinuousDomain(): from sympy.stats.crv import SingleContinuousDomain, ProductContinuousDomain - D = SingleContinuousDomain(x, Interval(-oo,oo)) - E = SingleContinuousDomain(y, Interval(0,oo)) + D = SingleContinuousDomain(x, Interval(-oo, oo)) + E = SingleContinuousDomain(y, Interval(0, oo)) assert _test_args(ProductContinuousDomain(D, E)) + def test_sympy__stats__crv__ConditionalContinuousDomain(): from sympy.stats.crv import (SingleContinuousDomain, ConditionalContinuousDomain) - D = SingleContinuousDomain(x, Interval(-oo,oo)) - assert _test_args(ConditionalContinuousDomain(D, x>0)) + D = SingleContinuousDomain(x, Interval(-oo, oo)) + assert _test_args(ConditionalContinuousDomain(D, x > 0)) + def test_sympy__stats__crv__ContinuousPSpace(): from sympy.stats.crv import ContinuousPSpace, SingleContinuousDomain - pdf = normal_pdf(x) - D = SingleContinuousDomain(x, Interval(-oo,oo)) - assert _test_args(ContinuousPSpace(D, pdf)) + D = SingleContinuousDomain(x, Interval(-oo, oo)) + assert _test_args(ContinuousPSpace(D, nd)) + def test_sympy__stats__crv__SingleContinuousPSpace(): from sympy.stats.crv import SingleContinuousPSpace - pdf = normal_pdf(x) - assert _test_args(SingleContinuousPSpace(x, pdf, Interval(-oo,oo))) + assert _test_args(SingleContinuousPSpace(x, nd)) + def test_sympy__stats__crv__ProductContinuousPSpace(): from sympy.stats.crv import ProductContinuousPSpace, SingleContinuousPSpace - pdf1 = normal_pdf(x) - A = SingleContinuousPSpace(x, pdf1, Interval(-oo,oo)) - pdf2 = normal_pdf(y) - B = SingleContinuousPSpace(y, pdf2, Interval(-oo,oo)) - assert _test_args(ProductContinuousPSpace(A,B)) + A = SingleContinuousPSpace(x, nd) + B = SingleContinuousPSpace(y, nd) + assert _test_args(ProductContinuousPSpace(A, B)) + +@SKIP("abstract class") +def test_sympy__stats__crv__SingleContinuousDistribution(): + pass + +def test_sympy__stats__drv__SingleDiscretePSpace(): + from sympy.stats.drv import SingleDiscretePSpace + from sympy.stats.drv_types import PoissonDistribution + assert _test_args(SingleDiscretePSpace(x, PoissonDistribution(1))) + +@SKIP("abstract class") +def test_sympy__stats__drv__SingleDiscreteDistribution(): + pass def test_sympy__stats__rv__RandomDomain(): from sympy.stats.rv import RandomDomain from sympy.core.sets import FiniteSet - assert _test_args(RandomDomain(FiniteSet(x), FiniteSet(1,2,3))) + assert _test_args(RandomDomain(FiniteSet(x), FiniteSet(1, 2, 3))) + def test_sympy__stats__rv__SingleDomain(): from sympy.stats.rv import SingleDomain from sympy.core.sets import FiniteSet - assert _test_args(SingleDomain(x, FiniteSet(1,2,3))) + assert _test_args(SingleDomain(x, FiniteSet(1, 2, 3))) + def test_sympy__stats__rv__ConditionalDomain(): from sympy.stats.rv import ConditionalDomain, RandomDomain from sympy.core.sets import FiniteSet - D = RandomDomain(FiniteSet(x), FiniteSet(1,2)) - assert _test_args(ConditionalDomain(D, x>1)) + D = RandomDomain(FiniteSet(x), FiniteSet(1, 2)) + assert _test_args(ConditionalDomain(D, x > 1)) + def test_sympy__stats__rv__PSpace(): from sympy.stats.rv import PSpace, RandomDomain from sympy import Dict, FiniteSet - D = RandomDomain(FiniteSet(x), FiniteSet(1,2)) - assert _test_args(PSpace(D, Dict({(x,1):S.Half, (x,2):S.Half}))) + D = RandomDomain(FiniteSet(x), FiniteSet(1, 2, 3, 4, 5, 6)) + assert _test_args(PSpace(D, die)) + +@SKIP("abstract Class") def test_sympy__stats__rv__SinglePSpace(): - from sympy.stats.rv import SinglePSpace, RandomDomain - from sympy import Dict, FiniteSet - D = RandomDomain(FiniteSet(x), FiniteSet(1,2)) - assert _test_args(SinglePSpace(D, Dict({(x,1):S.Half, (x,2):S.Half}))) + pass + def test_sympy__stats__rv__RandomSymbol(): from sympy.stats.rv import RandomSymbol from sympy.stats.crv import SingleContinuousPSpace - pdf = normal_pdf(x) - A = SingleContinuousPSpace(x, pdf, Interval(-oo,oo)) + A = SingleContinuousPSpace(x, nd) assert _test_args(RandomSymbol(A, x)) + def test_sympy__stats__rv__ProductPSpace(): from sympy.stats.rv import ProductPSpace from sympy.stats.crv import SingleContinuousPSpace - pdf1 = normal_pdf(x) - A = SingleContinuousPSpace(x, pdf1, Interval(-oo,oo)) - pdf2 = normal_pdf(y) - B = SingleContinuousPSpace(y, pdf2, Interval(-oo,oo)) - assert _test_args(ProductPSpace(A,B)) + A = SingleContinuousPSpace(x, nd) + B = SingleContinuousPSpace(y, nd) + assert _test_args(ProductPSpace(A, B)) + def test_sympy__stats__rv__ProductDomain(): from sympy.stats.rv import ProductDomain, SingleDomain - D = SingleDomain(x, Interval(-oo,oo)) - E = SingleDomain(y, Interval(0,oo)) + D = SingleDomain(x, Interval(-oo, oo)) + E = SingleDomain(y, Interval(0, oo)) assert _test_args(ProductDomain(D, E)) -def test_sympy__stats__frv_types__DiscreteUniformPSpace(): - from sympy.stats.frv_types import DiscreteUniformPSpace - assert _test_args(DiscreteUniformPSpace('X', list(range(6)))) - -def test_sympy__stats__frv_types__DiePSpace(): - from sympy.stats.frv_types import DiePSpace - assert _test_args(DiePSpace('X', 6)) - -def test_sympy__stats__frv_types__BernoulliPSpace(): - from sympy.stats.frv_types import BernoulliPSpace - assert _test_args(BernoulliPSpace('X', S.Half, 0, 1)) - -def test_sympy__stats__frv_types__CoinPSpace(): - from sympy.stats.frv_types import CoinPSpace - assert _test_args(CoinPSpace('X', S.Half)) - -def test_sympy__stats__frv_types__BinomialPSpace(): - from sympy.stats.frv_types import BinomialPSpace - assert _test_args(BinomialPSpace('X', 5, S.Half, 1, 0)) - -def test_sympy__stats__frv_types__HypergeometricPSpace(): - from sympy.stats.frv_types import HypergeometricPSpace - assert _test_args(HypergeometricPSpace('X', 10, 5, 3)) + +def test_sympy__stats__frv_types__DiscreteUniformDistribution(): + from sympy.stats.frv_types import DiscreteUniformDistribution + from sympy.core.containers import Tuple + assert _test_args(DiscreteUniformDistribution(Tuple(list(range(6))))) + + +def test_sympy__stats__frv_types__DieDistribution(): + from sympy.stats.frv_types import DieDistribution + assert _test_args(DieDistribution(6)) + + +def test_sympy__stats__frv_types__BernoulliDistribution(): + from sympy.stats.frv_types import BernoulliDistribution + assert _test_args(BernoulliDistribution(S.Half, 0, 1)) + + +def test_sympy__stats__frv_types__BinomialDistribution(): + from sympy.stats.frv_types import BinomialDistribution + assert _test_args(BinomialDistribution(5, S.Half, 1, 0)) + + +def test_sympy__stats__frv_types__HypergeometricDistribution(): + from sympy.stats.frv_types import HypergeometricDistribution + assert _test_args(HypergeometricDistribution(10, 5, 3)) + def test_sympy__stats__frv__FiniteDomain(): from sympy.stats.frv import FiniteDomain - assert _test_args(FiniteDomain(set([(x,1), (x,2)]))) # x can be 1 or 2 + assert _test_args(FiniteDomain(set([(x, 1), (x, 2)]))) # x can be 1 or 2 + def test_sympy__stats__frv__SingleFiniteDomain(): from sympy.stats.frv import SingleFiniteDomain - assert _test_args(SingleFiniteDomain(x, set([1,2]))) # x can be 1 or 2 + assert _test_args(SingleFiniteDomain(x, set([1, 2]))) # x can be 1 or 2 + def test_sympy__stats__frv__ProductFiniteDomain(): from sympy.stats.frv import SingleFiniteDomain, ProductFiniteDomain - xd = SingleFiniteDomain(x, set([1,2])) - yd = SingleFiniteDomain(y, set([1,2])) + xd = SingleFiniteDomain(x, set([1, 2])) + yd = SingleFiniteDomain(y, set([1, 2])) assert _test_args(ProductFiniteDomain(xd, yd)) + def test_sympy__stats__frv__ConditionalFiniteDomain(): from sympy.stats.frv import SingleFiniteDomain, ConditionalFiniteDomain - xd = SingleFiniteDomain(x, set([1,2])) - assert _test_args(ConditionalFiniteDomain(xd, x>1)) + xd = SingleFiniteDomain(x, set([1, 2])) + assert _test_args(ConditionalFiniteDomain(xd, x > 1)) + def test_sympy__stats__frv__FinitePSpace(): from sympy.stats.frv import FinitePSpace, SingleFiniteDomain - xd = SingleFiniteDomain(x, set([1,2])) - assert _test_args(FinitePSpace(xd, {(x,1):S.Half, (x,2):S.Half})) + xd = SingleFiniteDomain(x, set([1, 2, 3, 4, 5, 6])) + p = 1.0/6 + xd = SingleFiniteDomain(x, set([1, 2])) + assert _test_args(FinitePSpace(xd, {(x, 1): S.Half, (x, 2): S.Half})) + def test_sympy__stats__frv__SingleFinitePSpace(): from sympy.stats.frv import SingleFinitePSpace, SingleFiniteDomain - xd = SingleFiniteDomain(x, set([1,2])) - assert _test_args(SingleFinitePSpace(xd, {(x,1):S.Half, (x,2):S.Half})) + from sympy import Symbol + + assert _test_args(SingleFinitePSpace(Symbol('x'), die)) + def test_sympy__stats__frv__ProductFinitePSpace(): from sympy.stats.frv import (SingleFiniteDomain, SingleFinitePSpace, ProductFinitePSpace) - xd = SingleFiniteDomain(x, set([1,2])) - xp = SingleFinitePSpace(xd, {(x,1):S.Half, (x,2):S.Half}) - yd = SingleFiniteDomain(y, set([1,2])) - yp = SingleFinitePSpace(yd, {(y,1):S.Half, (y,2):S.Half}) + from sympy import Symbol + xp = SingleFinitePSpace(Symbol('x'), die) + yp = SingleFinitePSpace(Symbol('y'), die) assert _test_args(ProductFinitePSpace(xp, yp)) -def test_sympy__stats__crv_types__ArcsinPSpace(): - from sympy.stats.crv_types import ArcsinPSpace - assert _test_args(ArcsinPSpace('X', 0,1)) - -def test_sympy__stats__crv_types__BeniniPSpace(): - from sympy.stats.crv_types import BeniniPSpace - assert _test_args(BeniniPSpace('X', 1,1,1)) - -def test_sympy__stats__crv_types__BetaPSpace(): - from sympy.stats.crv_types import BetaPSpace - assert _test_args(BetaPSpace('X', 1,1)) - -def test_sympy__stats__crv_types__BetaPrimePSpace(): - from sympy.stats.crv_types import BetaPrimePSpace - assert _test_args(BetaPrimePSpace('X', 1,1)) - -def test_sympy__stats__crv_types__CauchyPSpace(): - from sympy.stats.crv_types import CauchyPSpace - assert _test_args(CauchyPSpace('X', 0,1)) - -def test_sympy__stats__crv_types__ChiPSpace(): - from sympy.stats.crv_types import ChiPSpace - assert _test_args(ChiPSpace('X', 1)) - -def test_sympy__stats__crv_types__DagumPSpace(): - from sympy.stats.crv_types import DagumPSpace - assert _test_args(DagumPSpace('X', 1,1,1)) - -def test_sympy__stats__crv_types__ExponentialPSpace(): - from sympy.stats.crv_types import ExponentialPSpace - assert _test_args(ExponentialPSpace('X', 1)) - -def test_sympy__stats__crv_types__GammaPSpace(): - from sympy.stats.crv_types import GammaPSpace - assert _test_args(GammaPSpace('X', 1,1)) - -def test_sympy__stats__crv_types__LaplacePSpace(): - from sympy.stats.crv_types import LaplacePSpace - assert _test_args(LaplacePSpace('X', 0,1)) - -def test_sympy__stats__crv_types__LogisticPSpace(): - from sympy.stats.crv_types import LogisticPSpace - assert _test_args(LogisticPSpace('X', 0,1)) - -def test_sympy__stats__crv_types__LogNormalPSpace(): - from sympy.stats.crv_types import LogNormalPSpace - assert _test_args(LogNormalPSpace('X', 0,1)) - -def test_sympy__stats__crv_types__MaxwellPSpace(): - from sympy.stats.crv_types import MaxwellPSpace - assert _test_args(MaxwellPSpace('X', 1)) - -def test_sympy__stats__crv_types__NakagamiPSpace(): - from sympy.stats.crv_types import NakagamiPSpace - assert _test_args(NakagamiPSpace('X', 1,1)) - -def test_sympy__stats__crv_types__NormalPSpace(): - from sympy.stats.crv_types import NormalPSpace - assert _test_args(NormalPSpace('X', 0,1)) - -def test_sympy__stats__crv_types__ParetoPSpace(): - from sympy.stats.crv_types import ParetoPSpace - assert _test_args(ParetoPSpace('X', 1,1)) - -def test_sympy__stats__crv_types__RayleighPSpace(): - from sympy.stats.crv_types import RayleighPSpace - assert _test_args(RayleighPSpace('X', 1)) - -def test_sympy__stats__crv_types__StudentTPSpace(): - from sympy.stats.crv_types import StudentTPSpace - assert _test_args(StudentTPSpace('X', 1)) - -def test_sympy__stats__crv_types__TriangularPSpace(): - from sympy.stats.crv_types import TriangularPSpace - assert _test_args(TriangularPSpace('X', -1,0,1)) - -def test_sympy__stats__crv_types__UniformPSpace(): - from sympy.stats.crv_types import UniformPSpace - assert _test_args(UniformPSpace('X', 0,1)) - -def test_sympy__stats__crv_types__UniformSumPSpace(): - from sympy.stats.crv_types import UniformSumPSpace - assert _test_args(UniformSumPSpace('X', 1)) - -def test_sympy__stats__crv_types__WeibullPSpace(): - from sympy.stats.crv_types import WeibullPSpace - assert _test_args(WeibullPSpace('X', 1,1)) - -def test_sympy__stats__crv_types__WignerSemicirclePSpace(): - from sympy.stats.crv_types import WignerSemicirclePSpace - assert _test_args(WignerSemicirclePSpace('X', 1)) +@SKIP("abstract class") +def test_sympy__stats__frv__SingleFiniteDistribution(): + pass + +@SKIP("abstract class") +def test_sympy__stats__crv__ContinuousDistribution(): + pass + + +def test_sympy__stats__frv_types__FiniteDistributionHandmade(): + from sympy.stats.frv_types import FiniteDistributionHandmade + assert _test_args(FiniteDistributionHandmade({1: 1})) + + +def test_sympy__stats__crv__ContinuousDistributionHandmade(): + from sympy.stats.crv import ContinuousDistributionHandmade + from sympy import Symbol, Interval + assert _test_args(ContinuousDistributionHandmade(Symbol('x'), + Interval(0, 2))) + +def test_sympy__stats__rv__Density(): + from sympy.stats.rv import Density + from sympy.stats.crv_types import Normal + assert _test_args(Density(Normal('x', 0, 1))) + + +def test_sympy__stats__crv_types__ArcsinDistribution(): + from sympy.stats.crv_types import ArcsinDistribution + assert _test_args(ArcsinDistribution(0, 1)) + + +def test_sympy__stats__crv_types__BeniniDistribution(): + from sympy.stats.crv_types import BeniniDistribution + assert _test_args(BeniniDistribution(1, 1, 1)) + + +def test_sympy__stats__crv_types__BetaDistribution(): + from sympy.stats.crv_types import BetaDistribution + assert _test_args(BetaDistribution(1, 1)) + + +def test_sympy__stats__crv_types__BetaPrimeDistribution(): + from sympy.stats.crv_types import BetaPrimeDistribution + assert _test_args(BetaPrimeDistribution(1, 1)) + + +def test_sympy__stats__crv_types__CauchyDistribution(): + from sympy.stats.crv_types import CauchyDistribution + assert _test_args(CauchyDistribution(0, 1)) + + +def test_sympy__stats__crv_types__ChiDistribution(): + from sympy.stats.crv_types import ChiDistribution + assert _test_args(ChiDistribution(1)) + + +def test_sympy__stats__crv_types__ChiNoncentralDistribution(): + from sympy.stats.crv_types import ChiNoncentralDistribution + assert _test_args(ChiNoncentralDistribution(1,1)) + + +def test_sympy__stats__crv_types__ChiSquaredDistribution(): + from sympy.stats.crv_types import ChiSquaredDistribution + assert _test_args(ChiSquaredDistribution(1)) + + +def test_sympy__stats__crv_types__DagumDistribution(): + from sympy.stats.crv_types import DagumDistribution + assert _test_args(DagumDistribution(1, 1, 1)) + + +def test_sympy__stats__crv_types__ExponentialDistribution(): + from sympy.stats.crv_types import ExponentialDistribution + assert _test_args(ExponentialDistribution(1)) + + +def test_sympy__stats__crv_types__FDistributionDistribution(): + from sympy.stats.crv_types import FDistributionDistribution + assert _test_args(FDistributionDistribution(1, 1)) + + +def test_sympy__stats__crv_types__FisherZDistribution(): + from sympy.stats.crv_types import FisherZDistribution + assert _test_args(FisherZDistribution(1, 1)) + + +def test_sympy__stats__crv_types__FrechetDistribution(): + from sympy.stats.crv_types import FrechetDistribution + assert _test_args(FrechetDistribution(1, 1, 1)) + + +def test_sympy__stats__crv_types__GammaInverseDistribution(): + from sympy.stats.crv_types import GammaInverseDistribution + assert _test_args(GammaInverseDistribution(1, 1)) + + +def test_sympy__stats__crv_types__GammaDistribution(): + from sympy.stats.crv_types import GammaDistribution + assert _test_args(GammaDistribution(1, 1)) + + +def test_sympy__stats__crv_types__KumaraswamyDistribution(): + from sympy.stats.crv_types import KumaraswamyDistribution + assert _test_args(KumaraswamyDistribution(1, 1)) + +def test_sympy__stats__crv_types__LaplaceDistribution(): + from sympy.stats.crv_types import LaplaceDistribution + assert _test_args(LaplaceDistribution(0, 1)) + + +def test_sympy__stats__crv_types__LogisticDistribution(): + from sympy.stats.crv_types import LogisticDistribution + assert _test_args(LogisticDistribution(0, 1)) + + +def test_sympy__stats__crv_types__LogNormalDistribution(): + from sympy.stats.crv_types import LogNormalDistribution + assert _test_args(LogNormalDistribution(0, 1)) + + +def test_sympy__stats__crv_types__MaxwellDistribution(): + from sympy.stats.crv_types import MaxwellDistribution + assert _test_args(MaxwellDistribution(1)) + + +def test_sympy__stats__crv_types__NakagamiDistribution(): + from sympy.stats.crv_types import NakagamiDistribution + assert _test_args(NakagamiDistribution(1, 1)) + + +def test_sympy__stats__crv_types__NormalDistribution(): + from sympy.stats.crv_types import NormalDistribution + assert _test_args(NormalDistribution(0, 1)) + + +def test_sympy__stats__crv_types__ParetoDistribution(): + from sympy.stats.crv_types import ParetoDistribution + assert _test_args(ParetoDistribution(1, 1)) + + +def test_sympy__stats__crv_types__QuadraticUDistribution(): + from sympy.stats.crv_types import QuadraticUDistribution + assert _test_args(QuadraticUDistribution(1, 2)) + +def test_sympy__stats__crv_types__RaisedCosineDistribution(): + from sympy.stats.crv_types import RaisedCosineDistribution + assert _test_args(RaisedCosineDistribution(1, 1)) + +def test_sympy__stats__crv_types__RayleighDistribution(): + from sympy.stats.crv_types import RayleighDistribution + assert _test_args(RayleighDistribution(1)) + + +def test_sympy__stats__crv_types__StudentTDistribution(): + from sympy.stats.crv_types import StudentTDistribution + assert _test_args(StudentTDistribution(1)) + + +def test_sympy__stats__crv_types__TriangularDistribution(): + from sympy.stats.crv_types import TriangularDistribution + assert _test_args(TriangularDistribution(-1, 0, 1)) + + +def test_sympy__stats__crv_types__UniformDistribution(): + from sympy.stats.crv_types import UniformDistribution + assert _test_args(UniformDistribution(0, 1)) + + +def test_sympy__stats__crv_types__UniformSumDistribution(): + from sympy.stats.crv_types import UniformSumDistribution + assert _test_args(UniformSumDistribution(1)) + + +def test_sympy__stats__crv_types__VonMisesDistribution(): + from sympy.stats.crv_types import VonMisesDistribution + assert _test_args(VonMisesDistribution(1, 1)) + + +def test_sympy__stats__crv_types__WeibullDistribution(): + from sympy.stats.crv_types import WeibullDistribution + assert _test_args(WeibullDistribution(1, 1)) + + +def test_sympy__stats__crv_types__WignerSemicircleDistribution(): + from sympy.stats.crv_types import WignerSemicircleDistribution + assert _test_args(WignerSemicircleDistribution(1)) + +def test_sympy__stats__drv_types__PoissonDistribution(): + from sympy.stats.drv_types import PoissonDistribution + assert _test_args(PoissonDistribution(1)) + +def test_sympy__stats__drv_types__GeometricDistribution(): + from sympy.stats.drv_types import GeometricDistribution + assert _test_args(GeometricDistribution(.5)) def test_sympy__core__symbol__Dummy(): from sympy.core.symbol import Dummy assert _test_args(Dummy('t')) + def test_sympy__core__symbol__Symbol(): from sympy.core.symbol import Symbol assert _test_args(Symbol('t')) + def test_sympy__core__symbol__Wild(): from sympy.core.symbol import Wild assert _test_args(Wild('x', exclude=[x])) + @SKIP("abstract class") def test_sympy__functions__combinatorial__factorials__CombinatorialFunction(): pass + def test_sympy__functions__combinatorial__factorials__FallingFactorial(): from sympy.functions.combinatorial.factorials import FallingFactorial assert _test_args(FallingFactorial(2, x)) + def test_sympy__functions__combinatorial__factorials__MultiFactorial(): from sympy.functions.combinatorial.factorials import MultiFactorial assert _test_args(MultiFactorial(x)) + def test_sympy__functions__combinatorial__factorials__RisingFactorial(): from sympy.functions.combinatorial.factorials import RisingFactorial assert _test_args(RisingFactorial(2, x)) + def test_sympy__functions__combinatorial__factorials__binomial(): from sympy.functions.combinatorial.factorials import binomial assert _test_args(binomial(2, x)) + +def test_sympy__functions__combinatorial__factorials__subfactorial(): + from sympy.functions.combinatorial.factorials import subfactorial + assert _test_args(subfactorial(1)) + + def test_sympy__functions__combinatorial__factorials__factorial(): from sympy.functions.combinatorial.factorials import factorial assert _test_args(factorial(x)) + def test_sympy__functions__combinatorial__factorials__factorial2(): from sympy.functions.combinatorial.factorials import factorial2 assert _test_args(factorial2(x)) + def test_sympy__functions__combinatorial__numbers__bell(): from sympy.functions.combinatorial.numbers import bell assert _test_args(bell(x, y)) + def test_sympy__functions__combinatorial__numbers__bernoulli(): from sympy.functions.combinatorial.numbers import bernoulli assert _test_args(bernoulli(x)) + def test_sympy__functions__combinatorial__numbers__catalan(): from sympy.functions.combinatorial.numbers import catalan assert _test_args(catalan(x)) + def test_sympy__functions__combinatorial__numbers__euler(): from sympy.functions.combinatorial.numbers import euler assert _test_args(euler(x)) + def test_sympy__functions__combinatorial__numbers__fibonacci(): from sympy.functions.combinatorial.numbers import fibonacci assert _test_args(fibonacci(x)) + def test_sympy__functions__combinatorial__numbers__harmonic(): from sympy.functions.combinatorial.numbers import harmonic assert _test_args(harmonic(x, 2)) + def test_sympy__functions__combinatorial__numbers__lucas(): from sympy.functions.combinatorial.numbers import lucas assert _test_args(lucas(x)) + def test_sympy__functions__elementary__complexes__Abs(): from sympy.functions.elementary.complexes import Abs assert _test_args(Abs(x)) + def test_sympy__functions__elementary__complexes__adjoint(): from sympy.functions.elementary.complexes import adjoint assert _test_args(adjoint(x)) + def test_sympy__functions__elementary__complexes__arg(): from sympy.functions.elementary.complexes import arg assert _test_args(arg(x)) + def test_sympy__functions__elementary__complexes__conjugate(): from sympy.functions.elementary.complexes import conjugate assert _test_args(conjugate(x)) + def test_sympy__functions__elementary__complexes__im(): from sympy.functions.elementary.complexes import im assert _test_args(im(x)) + def test_sympy__functions__elementary__complexes__re(): from sympy.functions.elementary.complexes import re assert _test_args(re(x)) + def test_sympy__functions__elementary__complexes__sign(): from sympy.functions.elementary.complexes import sign assert _test_args(sign(x)) + def test_sympy__functions__elementary__complexes__polar_lift(): from sympy.functions.elementary.complexes import polar_lift assert _test_args(polar_lift(x)) + def test_sympy__functions__elementary__complexes__periodic_argument(): from sympy.functions.elementary.complexes import periodic_argument assert _test_args(periodic_argument(x, y)) + def test_sympy__functions__elementary__complexes__principal_branch(): from sympy.functions.elementary.complexes import principal_branch assert _test_args(principal_branch(x, y)) + def test_sympy__functions__elementary__complexes__transpose(): from sympy.functions.elementary.complexes import transpose assert _test_args(transpose(x)) + def test_sympy__functions__elementary__exponential__LambertW(): from sympy.functions.elementary.exponential import LambertW assert _test_args(LambertW(2)) + @SKIP("abstract class") def test_sympy__functions__elementary__exponential__ExpBase(): pass + def test_sympy__functions__elementary__exponential__exp(): from sympy.functions.elementary.exponential import exp assert _test_args(exp(2)) + def test_sympy__functions__elementary__exponential__exp_polar(): from sympy.functions.elementary.exponential import exp_polar assert _test_args(exp_polar(2)) + def test_sympy__functions__elementary__exponential__log(): from sympy.functions.elementary.exponential import log assert _test_args(log(2)) + @SKIP("abstract class") def test_sympy__functions__elementary__hyperbolic__HyperbolicFunction(): pass + def test_sympy__functions__elementary__hyperbolic__acosh(): from sympy.functions.elementary.hyperbolic import acosh assert _test_args(acosh(2)) + def test_sympy__functions__elementary__hyperbolic__acoth(): from sympy.functions.elementary.hyperbolic import acoth assert _test_args(acoth(2)) + def test_sympy__functions__elementary__hyperbolic__asinh(): from sympy.functions.elementary.hyperbolic import asinh assert _test_args(asinh(2)) + def test_sympy__functions__elementary__hyperbolic__atanh(): from sympy.functions.elementary.hyperbolic import atanh assert _test_args(atanh(2)) + def test_sympy__functions__elementary__hyperbolic__cosh(): from sympy.functions.elementary.hyperbolic import cosh assert _test_args(cosh(2)) + def test_sympy__functions__elementary__hyperbolic__coth(): from sympy.functions.elementary.hyperbolic import coth assert _test_args(coth(2)) + def test_sympy__functions__elementary__hyperbolic__sinh(): from sympy.functions.elementary.hyperbolic import sinh assert _test_args(sinh(2)) + def test_sympy__functions__elementary__hyperbolic__tanh(): from sympy.functions.elementary.hyperbolic import tanh assert _test_args(tanh(2)) + @SKIP("does this work at all?") def test_sympy__functions__elementary__integers__RoundFunction(): from sympy.functions.elementary.integers import RoundFunction assert _test_args(RoundFunction()) + def test_sympy__functions__elementary__integers__ceiling(): from sympy.functions.elementary.integers import ceiling assert _test_args(ceiling(x)) + def test_sympy__functions__elementary__integers__floor(): from sympy.functions.elementary.integers import floor assert _test_args(floor(x)) + def test_sympy__functions__elementary__miscellaneous__IdentityFunction(): from sympy.functions.elementary.miscellaneous import IdentityFunction assert _test_args(IdentityFunction()) + def test_sympy__functions__elementary__miscellaneous__Max(): from sympy.functions.elementary.miscellaneous import Max assert _test_args(Max(x, 2)) + def test_sympy__functions__elementary__miscellaneous__Min(): from sympy.functions.elementary.miscellaneous import Min assert _test_args(Min(x, 2)) + @SKIP("abstract class") def test_sympy__functions__elementary__miscellaneous__MinMaxBase(): pass + def test_sympy__functions__elementary__piecewise__ExprCondPair(): from sympy.functions.elementary.piecewise import ExprCondPair assert _test_args(ExprCondPair(1, True)) + def test_sympy__functions__elementary__piecewise__Piecewise(): from sympy.functions.elementary.piecewise import Piecewise assert _test_args(Piecewise((1, x >= 0), (0, True))) + @SKIP("abstract class") def test_sympy__functions__elementary__trigonometric__TrigonometricFunction(): pass + def test_sympy__functions__elementary__trigonometric__acos(): from sympy.functions.elementary.trigonometric import acos assert _test_args(acos(2)) + def test_sympy__functions__elementary__trigonometric__acot(): from sympy.functions.elementary.trigonometric import acot assert _test_args(acot(2)) + def test_sympy__functions__elementary__trigonometric__asin(): from sympy.functions.elementary.trigonometric import asin assert _test_args(asin(2)) + def test_sympy__functions__elementary__trigonometric__atan(): from sympy.functions.elementary.trigonometric import atan assert _test_args(atan(2)) + def test_sympy__functions__elementary__trigonometric__atan2(): from sympy.functions.elementary.trigonometric import atan2 assert _test_args(atan2(2, 3)) + def test_sympy__functions__elementary__trigonometric__cos(): from sympy.functions.elementary.trigonometric import cos assert _test_args(cos(2)) + def test_sympy__functions__elementary__trigonometric__csc(): from sympy.functions.elementary.trigonometric import csc assert _test_args(csc(2)) + def test_sympy__functions__elementary__trigonometric__cot(): from sympy.functions.elementary.trigonometric import cot assert _test_args(cot(2)) + def test_sympy__functions__elementary__trigonometric__sin(): assert _test_args(sin(2)) + def test_sympy__functions__elementary__trigonometric__sec(): from sympy.functions.elementary.trigonometric import sec assert _test_args(sec(2)) + def test_sympy__functions__elementary__trigonometric__tan(): from sympy.functions.elementary.trigonometric import tan assert _test_args(tan(2)) + @SKIP("abstract class") def test_sympy__functions__special__bessel__BesselBase(): pass + @SKIP("abstract class") def test_sympy__functions__special__bessel__SphericalBesselBase(): pass + def test_sympy__functions__special__bessel__besseli(): from sympy.functions.special.bessel import besseli assert _test_args(besseli(x, 1)) + def test_sympy__functions__special__bessel__besselj(): from sympy.functions.special.bessel import besselj assert _test_args(besselj(x, 1)) + def test_sympy__functions__special__bessel__besselk(): from sympy.functions.special.bessel import besselk assert _test_args(besselk(x, 1)) + def test_sympy__functions__special__bessel__bessely(): from sympy.functions.special.bessel import bessely assert _test_args(bessely(x, 1)) + def test_sympy__functions__special__bessel__hankel1(): from sympy.functions.special.bessel import hankel1 assert _test_args(hankel1(x, 1)) + def test_sympy__functions__special__bessel__hankel2(): from sympy.functions.special.bessel import hankel2 assert _test_args(hankel2(x, 1)) + def test_sympy__functions__special__bessel__jn(): from sympy.functions.special.bessel import jn assert _test_args(jn(0, x)) + def test_sympy__functions__special__bessel__yn(): from sympy.functions.special.bessel import yn assert _test_args(yn(0, x)) + +def test_sympy__functions__special__elliptic_integrals__elliptic_k(): + from sympy.functions.special.elliptic_integrals import elliptic_k as K + assert _test_args(K(x)) + + +def test_sympy__functions__special__elliptic_integrals__elliptic_f(): + from sympy.functions.special.elliptic_integrals import elliptic_f as F + assert _test_args(F(x, y)) + + +def test_sympy__functions__special__elliptic_integrals__elliptic_e(): + from sympy.functions.special.elliptic_integrals import elliptic_e as E + assert _test_args(E(x)) + assert _test_args(E(x, y)) + + +def test_sympy__functions__special__elliptic_integrals__elliptic_pi(): + from sympy.functions.special.elliptic_integrals import elliptic_pi as P + assert _test_args(P(x, y)) + assert _test_args(P(x, y, z)) + + def test_sympy__functions__special__delta_functions__DiracDelta(): from sympy.functions.special.delta_functions import DiracDelta assert _test_args(DiracDelta(x, 1)) + def test_sympy__functions__special__delta_functions__Heaviside(): from sympy.functions.special.delta_functions import Heaviside assert _test_args(Heaviside(x)) + def test_sympy__functions__special__error_functions__erf(): from sympy.functions.special.error_functions import erf assert _test_args(erf(2)) +def test_sympy__functions__special__error_functions__erfc(): + from sympy.functions.special.error_functions import erfc + assert _test_args(erfc(2)) + +def test_sympy__functions__special__error_functions__erfi(): + from sympy.functions.special.error_functions import erfi + assert _test_args(erfi(2)) + +def test_sympy__functions__special__error_functions__erf2(): + from sympy.functions.special.error_functions import erf2 + assert _test_args(erf2(2, 3)) + +def test_sympy__functions__special__error_functions__erfinv(): + from sympy.functions.special.error_functions import erfinv + assert _test_args(erfinv(2)) + +def test_sympy__functions__special__error_functions__erfcinv(): + from sympy.functions.special.error_functions import erfcinv + assert _test_args(erfcinv(2)) + +def test_sympy__functions__special__error_functions__erf2inv(): + from sympy.functions.special.error_functions import erf2inv + assert _test_args(erf2inv(2, 3)) + @SKIP("abstract class") def test_sympy__functions__special__error_functions__FresnelIntegral(): pass + def test_sympy__functions__special__error_functions__fresnels(): from sympy.functions.special.error_functions import fresnels assert _test_args(fresnels(2)) + def test_sympy__functions__special__error_functions__fresnelc(): from sympy.functions.special.error_functions import fresnelc assert _test_args(fresnelc(2)) + def test_sympy__functions__special__error_functions__erfs(): from sympy.functions.special.error_functions import _erfs assert _test_args(_erfs(2)) + def test_sympy__functions__special__error_functions__Ei(): from sympy.functions.special.error_functions import Ei assert _test_args(Ei(2)) + +def test_sympy__functions__special__error_functions__li(): + from sympy.functions.special.error_functions import li + assert _test_args(li(2)) + + +def test_sympy__functions__special__error_functions__Li(): + from sympy.functions.special.error_functions import Li + assert _test_args(Li(2)) + + @SKIP("abstract class") def test_sympy__functions__special__error_functions__TrigonometricIntegral(): pass + def test_sympy__functions__special__error_functions__Si(): from sympy.functions.special.error_functions import Si assert _test_args(Si(2)) + def test_sympy__functions__special__error_functions__Ci(): from sympy.functions.special.error_functions import Ci assert _test_args(Ci(2)) + def test_sympy__functions__special__error_functions__Shi(): from sympy.functions.special.error_functions import Shi assert _test_args(Shi(2)) + def test_sympy__functions__special__error_functions__Chi(): from sympy.functions.special.error_functions import Chi assert _test_args(Chi(2)) + def test_sympy__functions__special__error_functions__expint(): from sympy.functions.special.error_functions import expint assert _test_args(expint(y, x)) + def test_sympy__functions__special__gamma_functions__gamma(): from sympy.functions.special.gamma_functions import gamma assert _test_args(gamma(x)) + def test_sympy__functions__special__gamma_functions__loggamma(): from sympy.functions.special.gamma_functions import loggamma assert _test_args(loggamma(2)) + def test_sympy__functions__special__gamma_functions__lowergamma(): from sympy.functions.special.gamma_functions import lowergamma assert _test_args(lowergamma(x, 2)) + def test_sympy__functions__special__gamma_functions__polygamma(): from sympy.functions.special.gamma_functions import polygamma assert _test_args(polygamma(x, 2)) + def test_sympy__functions__special__gamma_functions__uppergamma(): from sympy.functions.special.gamma_functions import uppergamma assert _test_args(uppergamma(x, 2)) + @SKIP("abstract class") def test_sympy__functions__special__hyper__TupleParametersBase(): pass + +@SKIP("abstract class") +def test_sympy__functions__special__hyper__TupleArg(): + pass + + def test_sympy__functions__special__hyper__hyper(): from sympy.functions.special.hyper import hyper assert _test_args(hyper([1, 2, 3], [4, 5], x)) + def test_sympy__functions__special__hyper__meijerg(): from sympy.functions.special.hyper import meijerg assert _test_args(meijerg([1, 2, 3], [4, 5], [6], [], x)) + @SKIP("abstract class") def test_sympy__functions__special__hyper__HyperRep(): pass + def test_sympy__functions__special__hyper__HyperRep_power1(): from sympy.functions.special.hyper import HyperRep_power1 assert _test_args(HyperRep_power1(x, y)) + def test_sympy__functions__special__hyper__HyperRep_power2(): from sympy.functions.special.hyper import HyperRep_power2 assert _test_args(HyperRep_power2(x, y)) + def test_sympy__functions__special__hyper__HyperRep_log1(): from sympy.functions.special.hyper import HyperRep_log1 assert _test_args(HyperRep_log1(x)) + def test_sympy__functions__special__hyper__HyperRep_atanh(): from sympy.functions.special.hyper import HyperRep_atanh assert _test_args(HyperRep_atanh(x)) + def test_sympy__functions__special__hyper__HyperRep_asin1(): from sympy.functions.special.hyper import HyperRep_asin1 assert _test_args(HyperRep_asin1(x)) + def test_sympy__functions__special__hyper__HyperRep_asin2(): from sympy.functions.special.hyper import HyperRep_asin2 assert _test_args(HyperRep_asin2(x)) + def test_sympy__functions__special__hyper__HyperRep_sqrts1(): from sympy.functions.special.hyper import HyperRep_sqrts1 assert _test_args(HyperRep_sqrts1(x, y)) + def test_sympy__functions__special__hyper__HyperRep_sqrts2(): from sympy.functions.special.hyper import HyperRep_sqrts2 assert _test_args(HyperRep_sqrts2(x, y)) + def test_sympy__functions__special__hyper__HyperRep_log2(): from sympy.functions.special.hyper import HyperRep_log2 assert _test_args(HyperRep_log2(x)) + def test_sympy__functions__special__hyper__HyperRep_cosasin(): from sympy.functions.special.hyper import HyperRep_cosasin assert _test_args(HyperRep_cosasin(x, y)) + def test_sympy__functions__special__hyper__HyperRep_sinasin(): from sympy.functions.special.hyper import HyperRep_sinasin assert _test_args(HyperRep_sinasin(x, y)) + @SKIP("abstract class") def test_sympy__functions__special__polynomials__OrthogonalPolynomial(): pass + def test_sympy__functions__special__polynomials__jacobi(): from sympy.functions.special.polynomials import jacobi assert _test_args(jacobi(x, 2, 2, 2)) + def test_sympy__functions__special__polynomials__gegenbauer(): from sympy.functions.special.polynomials import gegenbauer assert _test_args(gegenbauer(x, 2, 2)) + def test_sympy__functions__special__polynomials__chebyshevt(): from sympy.functions.special.polynomials import chebyshevt assert _test_args(chebyshevt(x, 2)) + def test_sympy__functions__special__polynomials__chebyshevt_root(): from sympy.functions.special.polynomials import chebyshevt_root assert _test_args(chebyshevt_root(x, 2)) + def test_sympy__functions__special__polynomials__chebyshevu(): from sympy.functions.special.polynomials import chebyshevu assert _test_args(chebyshevu(x, 2)) + def test_sympy__functions__special__polynomials__chebyshevu_root(): from sympy.functions.special.polynomials import chebyshevu_root assert _test_args(chebyshevu_root(x, 2)) + def test_sympy__functions__special__polynomials__hermite(): from sympy.functions.special.polynomials import hermite assert _test_args(hermite(x, 2)) + def test_sympy__functions__special__polynomials__legendre(): from sympy.functions.special.polynomials import legendre assert _test_args(legendre(x, 2)) + def test_sympy__functions__special__polynomials__assoc_legendre(): from sympy.functions.special.polynomials import assoc_legendre assert _test_args(assoc_legendre(x, 0, y)) + def test_sympy__functions__special__polynomials__laguerre(): from sympy.functions.special.polynomials import laguerre assert _test_args(laguerre(x, 2)) + def test_sympy__functions__special__polynomials__assoc_laguerre(): from sympy.functions.special.polynomials import assoc_laguerre assert _test_args(assoc_laguerre(x, 0, y)) + +def test_sympy__functions__special__spherical_harmonics__Ynm(): + from sympy.functions.special.spherical_harmonics import Ynm + assert _test_args(Ynm(1, 1, x, y)) + + +def test_sympy__functions__special__spherical_harmonics__Znm(): + from sympy.functions.special.spherical_harmonics import Znm + assert _test_args(Znm(1, 1, x, y)) + + def test_sympy__functions__special__tensor_functions__LeviCivita(): from sympy.functions.special.tensor_functions import LeviCivita assert _test_args(LeviCivita(x, y, 2)) + def test_sympy__functions__special__tensor_functions__KroneckerDelta(): from sympy.functions.special.tensor_functions import KroneckerDelta assert _test_args(KroneckerDelta(x, y)) + def test_sympy__functions__special__zeta_functions__dirichlet_eta(): from sympy.functions.special.zeta_functions import dirichlet_eta assert _test_args(dirichlet_eta(x)) + def test_sympy__functions__special__zeta_functions__zeta(): from sympy.functions.special.zeta_functions import zeta assert _test_args(zeta(101)) + def test_sympy__functions__special__zeta_functions__lerchphi(): from sympy.functions.special.zeta_functions import lerchphi assert _test_args(lerchphi(x, y, z)) + def test_sympy__functions__special__zeta_functions__polylog(): from sympy.functions.special.zeta_functions import polylog assert _test_args(polylog(x, y)) + def test_sympy__integrals__integrals__Integral(): from sympy.integrals.integrals import Integral assert _test_args(Integral(2, (x, 0, 1))) + +def test_sympy__integrals__risch__NonElementaryIntegral(): + from sympy.integrals.risch import NonElementaryIntegral + assert _test_args(NonElementaryIntegral(exp(-x**2), x)) + + @SKIP("abstract class") def test_sympy__integrals__transforms__IntegralTransform(): pass + def test_sympy__integrals__transforms__MellinTransform(): from sympy.integrals.transforms import MellinTransform assert _test_args(MellinTransform(2, x, y)) + def test_sympy__integrals__transforms__InverseMellinTransform(): from sympy.integrals.transforms import InverseMellinTransform assert _test_args(InverseMellinTransform(2, x, y, 0, 1)) + def test_sympy__integrals__transforms__LaplaceTransform(): from sympy.integrals.transforms import LaplaceTransform assert _test_args(LaplaceTransform(2, x, y)) + def test_sympy__integrals__transforms__InverseLaplaceTransform(): from sympy.integrals.transforms import InverseLaplaceTransform assert _test_args(InverseLaplaceTransform(2, x, y, 0)) + @SKIP("abstract class") def test_sympy__integrals__transforms__FourierTypeTransform(): pass + def test_sympy__integrals__transforms__InverseFourierTransform(): from sympy.integrals.transforms import InverseFourierTransform assert _test_args(InverseFourierTransform(2, x, y)) + def test_sympy__integrals__transforms__FourierTransform(): from sympy.integrals.transforms import FourierTransform assert _test_args(FourierTransform(2, x, y)) + @SKIP("abstract class") def test_sympy__integrals__transforms__SineCosineTypeTransform(): pass + def test_sympy__integrals__transforms__InverseSineTransform(): from sympy.integrals.transforms import InverseSineTransform assert _test_args(InverseSineTransform(2, x, y)) + def test_sympy__integrals__transforms__SineTransform(): from sympy.integrals.transforms import SineTransform assert _test_args(SineTransform(2, x, y)) + def test_sympy__integrals__transforms__InverseCosineTransform(): from sympy.integrals.transforms import InverseCosineTransform assert _test_args(InverseCosineTransform(2, x, y)) + def test_sympy__integrals__transforms__CosineTransform(): from sympy.integrals.transforms import CosineTransform assert _test_args(CosineTransform(2, x, y)) + @SKIP("abstract class") def test_sympy__integrals__transforms__HankelTypeTransform(): pass + def test_sympy__integrals__transforms__InverseHankelTransform(): from sympy.integrals.transforms import InverseHankelTransform assert _test_args(InverseHankelTransform(2, x, y, 0)) + def test_sympy__integrals__transforms__HankelTransform(): from sympy.integrals.transforms import HankelTransform assert _test_args(HankelTransform(2, x, y, 0)) + def test_sympy__logic__boolalg__And(): from sympy.logic.boolalg import And assert _test_args(And(x, y, 2)) + @SKIP("abstract class") def test_sympy__logic__boolalg__Boolean(): pass + def test_sympy__logic__boolalg__BooleanFunction(): from sympy.logic.boolalg import BooleanFunction assert _test_args(BooleanFunction(1, 2, 3)) + def test_sympy__logic__boolalg__Equivalent(): from sympy.logic.boolalg import Equivalent assert _test_args(Equivalent(x, 2)) + def test_sympy__logic__boolalg__ITE(): from sympy.logic.boolalg import ITE assert _test_args(ITE(x, y, 2)) + def test_sympy__logic__boolalg__Implies(): from sympy.logic.boolalg import Implies - assert _test_args(Implies(x, 2)) + assert _test_args(Implies(x, y)) + def test_sympy__logic__boolalg__Nand(): from sympy.logic.boolalg import Nand assert _test_args(Nand(x, y, 2)) + def test_sympy__logic__boolalg__Nor(): from sympy.logic.boolalg import Nor - assert _test_args(Nor(x, y, 2)) + assert _test_args(Nor(x, y)) + def test_sympy__logic__boolalg__Not(): from sympy.logic.boolalg import Not - assert _test_args(Not(2)) + assert _test_args(Not(x)) + def test_sympy__logic__boolalg__Or(): from sympy.logic.boolalg import Or - assert _test_args(Or(x, y, 2)) + assert _test_args(Or(x, y)) + def test_sympy__logic__boolalg__Xor(): from sympy.logic.boolalg import Xor assert _test_args(Xor(x, y, 2)) + def test_sympy__matrices__matrices__DeferredVector(): from sympy.matrices.matrices import DeferredVector assert _test_args(DeferredVector("X")) + @SKIP("abstract class") def test_sympy__matrices__expressions__matexpr__MatrixBase(): pass -def test_sympy__matrices__immutable_matrix__ImmutableMatrix(): - from sympy.matrices.immutable_matrix import ImmutableMatrix - assert _test_args(ImmutableMatrix([[1,2],[3,4]])) + +def test_sympy__matrices__immutable__ImmutableMatrix(): + from sympy.matrices.immutable import ImmutableMatrix + assert _test_args(ImmutableMatrix([[1, 2], [3, 4]])) + + +def test_sympy__matrices__immutable__ImmutableSparseMatrix(): + from sympy.matrices.immutable import ImmutableSparseMatrix + assert _test_args(ImmutableSparseMatrix([[1, 2], [3, 4]])) + + +def test_sympy__matrices__expressions__slice__MatrixSlice(): + from sympy.matrices.expressions.slice import MatrixSlice + from sympy.matrices.expressions import MatrixSymbol + X = MatrixSymbol('X', 4, 4) + assert _test_args(MatrixSlice(X, (0, 2), (0, 2))) + def test_sympy__matrices__expressions__blockmatrix__BlockDiagMatrix(): from sympy.matrices.expressions.blockmatrix import BlockDiagMatrix @@ -1284,6 +1743,7 @@ Y = MatrixSymbol('Y', y, y) assert _test_args(BlockDiagMatrix(X, Y)) + def test_sympy__matrices__expressions__blockmatrix__BlockMatrix(): from sympy.matrices.expressions.blockmatrix import BlockMatrix from sympy.matrices.expressions import MatrixSymbol, ZeroMatrix @@ -1293,11 +1753,13 @@ O = ZeroMatrix(y, x) assert _test_args(BlockMatrix([[X, Z], [O, Y]])) + def test_sympy__matrices__expressions__inverse__Inverse(): from sympy.matrices.expressions.inverse import Inverse from sympy.matrices.expressions import MatrixSymbol assert _test_args(Inverse(MatrixSymbol('A', 3, 3))) + def test_sympy__matrices__expressions__matadd__MatAdd(): from sympy.matrices.expressions.matadd import MatAdd from sympy.matrices.expressions import MatrixSymbol @@ -1305,25 +1767,34 @@ Y = MatrixSymbol('Y', x, y) assert _test_args(MatAdd(X, Y)) + @XFAIL def test_sympy__matrices__expressions__matexpr__Identity(): from sympy.matrices.expressions.matexpr import Identity assert _test_args(Identity(3)) + @SKIP("abstract class") def test_sympy__matrices__expressions__matexpr__MatrixExpr(): pass +def test_sympy__matrices__expressions__matexpr__MatrixElement(): + from sympy.matrices.expressions.matexpr import MatrixSymbol, MatrixElement + from sympy import S + assert _test_args(MatrixElement(MatrixSymbol('A', 3, 5), S(2), S(3))) + @XFAIL def test_sympy__matrices__expressions__matexpr__MatrixSymbol(): from sympy.matrices.expressions.matexpr import MatrixSymbol assert _test_args(MatrixSymbol('A', 3, 5)) + @XFAIL def test_sympy__matrices__expressions__matexpr__ZeroMatrix(): from sympy.matrices.expressions.matexpr import ZeroMatrix assert _test_args(ZeroMatrix(3, 5)) + def test_sympy__matrices__expressions__matmul__MatMul(): from sympy.matrices.expressions.matmul import MatMul from sympy.matrices.expressions import MatrixSymbol @@ -1331,236 +1802,380 @@ Y = MatrixSymbol('Y', y, x) assert _test_args(MatMul(X, Y)) +def test_sympy__matrices__expressions__diagonal__DiagonalMatrix(): + from sympy.matrices.expressions.diagonal import DiagonalMatrix + from sympy.matrices.expressions import MatrixSymbol + x = MatrixSymbol('x', 10, 1) + assert _test_args(DiagonalMatrix(x)) + +def test_sympy__matrices__expressions__diagonal__DiagonalOf(): + from sympy.matrices.expressions.diagonal import DiagonalOf + from sympy.matrices.expressions import MatrixSymbol + X = MatrixSymbol('x', 10, 10) + assert _test_args(DiagonalOf(X)) + +def test_sympy__matrices__expressions__hadamard__HadamardProduct(): + from sympy.matrices.expressions.hadamard import HadamardProduct + from sympy.matrices.expressions import MatrixSymbol + X = MatrixSymbol('X', x, y) + Y = MatrixSymbol('Y', x, y) + assert _test_args(HadamardProduct(X, Y)) + + def test_sympy__matrices__expressions__matpow__MatPow(): from sympy.matrices.expressions.matpow import MatPow from sympy.matrices.expressions import MatrixSymbol X = MatrixSymbol('X', x, x) assert _test_args(MatPow(X, 2)) + def test_sympy__matrices__expressions__transpose__Transpose(): from sympy.matrices.expressions.transpose import Transpose from sympy.matrices.expressions import MatrixSymbol assert _test_args(Transpose(MatrixSymbol('A', 3, 5))) + +def test_sympy__matrices__expressions__adjoint__Adjoint(): + from sympy.matrices.expressions.adjoint import Adjoint + from sympy.matrices.expressions import MatrixSymbol + assert _test_args(Adjoint(MatrixSymbol('A', 3, 5))) + + def test_sympy__matrices__expressions__trace__Trace(): from sympy.matrices.expressions.trace import Trace from sympy.matrices.expressions import MatrixSymbol assert _test_args(Trace(MatrixSymbol('A', 3, 3))) +def test_sympy__matrices__expressions__determinant__Determinant(): + from sympy.matrices.expressions.determinant import Determinant + from sympy.matrices.expressions import MatrixSymbol + assert _test_args(Determinant(MatrixSymbol('A', 3, 3))) + + def test_sympy__matrices__expressions__funcmatrix__FunctionMatrix(): from sympy.matrices.expressions.funcmatrix import FunctionMatrix from sympy import Lambda, symbols i, j = symbols('i,j') - assert _test_args(FunctionMatrix(3,3, Lambda((i,j), i-j) )) + assert _test_args(FunctionMatrix(3, 3, Lambda((i, j), i - j) )) + +def test_sympy__matrices__expressions__fourier__DFT(): + from sympy.matrices.expressions.fourier import DFT + from sympy import S + assert _test_args(DFT(S(2))) + +def test_sympy__matrices__expressions__fourier__IDFT(): + from sympy.matrices.expressions.fourier import IDFT + from sympy import S + assert _test_args(IDFT(S(2))) + +from sympy.matrices.expressions import MatrixSymbol +X = MatrixSymbol('X', 10, 10) + +def test_sympy__matrices__expressions__factorizations__LofLU(): + from sympy.matrices.expressions.factorizations import LofLU + assert _test_args(LofLU(X)) + +def test_sympy__matrices__expressions__factorizations__UofLU(): + from sympy.matrices.expressions.factorizations import UofLU + assert _test_args(UofLU(X)) + +def test_sympy__matrices__expressions__factorizations__QofQR(): + from sympy.matrices.expressions.factorizations import QofQR + assert _test_args(QofQR(X)) + +def test_sympy__matrices__expressions__factorizations__RofQR(): + from sympy.matrices.expressions.factorizations import RofQR + assert _test_args(RofQR(X)) + +def test_sympy__matrices__expressions__factorizations__LofCholesky(): + from sympy.matrices.expressions.factorizations import LofCholesky + assert _test_args(LofCholesky(X)) + +def test_sympy__matrices__expressions__factorizations__UofCholesky(): + from sympy.matrices.expressions.factorizations import UofCholesky + assert _test_args(UofCholesky(X)) + +def test_sympy__matrices__expressions__factorizations__EigenVectors(): + from sympy.matrices.expressions.factorizations import EigenVectors + assert _test_args(EigenVectors(X)) + +def test_sympy__matrices__expressions__factorizations__EigenValues(): + from sympy.matrices.expressions.factorizations import EigenValues + assert _test_args(EigenValues(X)) + +def test_sympy__matrices__expressions__factorizations__UofSVD(): + from sympy.matrices.expressions.factorizations import UofSVD + assert _test_args(UofSVD(X)) + +def test_sympy__matrices__expressions__factorizations__VofSVD(): + from sympy.matrices.expressions.factorizations import VofSVD + assert _test_args(VofSVD(X)) + +def test_sympy__matrices__expressions__factorizations__SofSVD(): + from sympy.matrices.expressions.factorizations import SofSVD + assert _test_args(SofSVD(X)) + +@SKIP("abstract class") +def test_sympy__matrices__expressions__factorizations__Factorization(): + pass def test_sympy__physics__gaussopt__BeamParameter(): from sympy.physics.gaussopt import BeamParameter assert _test_args(BeamParameter(530e-9, 1, w=1e-3)) + def test_sympy__physics__paulialgebra__Pauli(): from sympy.physics.paulialgebra import Pauli assert _test_args(Pauli(1)) + def test_sympy__physics__quantum__anticommutator__AntiCommutator(): from sympy.physics.quantum.anticommutator import AntiCommutator assert _test_args(AntiCommutator(x, y)) + def test_sympy__physics__quantum__cartesian__PositionBra3D(): from sympy.physics.quantum.cartesian import PositionBra3D assert _test_args(PositionBra3D(x, y, z)) + def test_sympy__physics__quantum__cartesian__PositionKet3D(): from sympy.physics.quantum.cartesian import PositionKet3D assert _test_args(PositionKet3D(x, y, z)) + def test_sympy__physics__quantum__cartesian__PositionState3D(): from sympy.physics.quantum.cartesian import PositionState3D assert _test_args(PositionState3D(x, y, z)) + def test_sympy__physics__quantum__cartesian__PxBra(): from sympy.physics.quantum.cartesian import PxBra assert _test_args(PxBra(x, y, z)) + def test_sympy__physics__quantum__cartesian__PxKet(): from sympy.physics.quantum.cartesian import PxKet assert _test_args(PxKet(x, y, z)) + def test_sympy__physics__quantum__cartesian__PxOp(): from sympy.physics.quantum.cartesian import PxOp assert _test_args(PxOp(x, y, z)) + def test_sympy__physics__quantum__cartesian__XBra(): from sympy.physics.quantum.cartesian import XBra assert _test_args(XBra(x)) + def test_sympy__physics__quantum__cartesian__XKet(): from sympy.physics.quantum.cartesian import XKet assert _test_args(XKet(x)) + def test_sympy__physics__quantum__cartesian__XOp(): from sympy.physics.quantum.cartesian import XOp assert _test_args(XOp(x)) + def test_sympy__physics__quantum__cartesian__YOp(): from sympy.physics.quantum.cartesian import YOp assert _test_args(YOp(x)) + def test_sympy__physics__quantum__cartesian__ZOp(): from sympy.physics.quantum.cartesian import ZOp assert _test_args(ZOp(x)) + def test_sympy__physics__quantum__cg__CG(): from sympy.physics.quantum.cg import CG from sympy import S assert _test_args(CG(S(3)/2, S(3)/2, S(1)/2, -S(1)/2, 1, 1)) + def test_sympy__physics__quantum__cg__Wigner3j(): from sympy.physics.quantum.cg import Wigner3j - assert _test_args(Wigner3j(6,0,4,0,2,0)) + assert _test_args(Wigner3j(6, 0, 4, 0, 2, 0)) + def test_sympy__physics__quantum__cg__Wigner6j(): from sympy.physics.quantum.cg import Wigner6j - assert _test_args(Wigner6j(1,2,3,2,1,2)) + assert _test_args(Wigner6j(1, 2, 3, 2, 1, 2)) + def test_sympy__physics__quantum__cg__Wigner9j(): from sympy.physics.quantum.cg import Wigner9j - assert _test_args(Wigner9j(2,1,1,S(3)/2,S(1)/2,1,S(1)/2,S(1)/2,0)) + assert _test_args(Wigner9j(2, 1, 1, S(3)/2, S(1)/2, 1, S(1)/2, S(1)/2, 0)) + def test_sympy__physics__quantum__commutator__Commutator(): from sympy.physics.quantum.commutator import Commutator A, B = symbols('A,B', commutative=False) assert _test_args(Commutator(A, B)) + def test_sympy__physics__quantum__constants__HBar(): from sympy.physics.quantum.constants import HBar assert _test_args(HBar()) + def test_sympy__physics__quantum__dagger__Dagger(): from sympy.physics.quantum.dagger import Dagger from sympy.physics.quantum.state import Ket assert _test_args(Dagger(Dagger(Ket('psi')))) + def test_sympy__physics__quantum__gate__CGate(): from sympy.physics.quantum.gate import CGate, Gate - assert _test_args(CGate((0,1), Gate(2))) + assert _test_args(CGate((0, 1), Gate(2))) + def test_sympy__physics__quantum__gate__CNotGate(): from sympy.physics.quantum.gate import CNotGate assert _test_args(CNotGate(0, 1)) + def test_sympy__physics__quantum__gate__Gate(): from sympy.physics.quantum.gate import Gate assert _test_args(Gate(0)) + def test_sympy__physics__quantum__gate__HadamardGate(): from sympy.physics.quantum.gate import HadamardGate assert _test_args(HadamardGate(0)) + def test_sympy__physics__quantum__gate__IdentityGate(): from sympy.physics.quantum.gate import IdentityGate assert _test_args(IdentityGate(0)) + def test_sympy__physics__quantum__gate__OneQubitGate(): from sympy.physics.quantum.gate import OneQubitGate assert _test_args(OneQubitGate(0)) + def test_sympy__physics__quantum__gate__PhaseGate(): from sympy.physics.quantum.gate import PhaseGate assert _test_args(PhaseGate(0)) + def test_sympy__physics__quantum__gate__SwapGate(): from sympy.physics.quantum.gate import SwapGate assert _test_args(SwapGate(0, 1)) + def test_sympy__physics__quantum__gate__TGate(): from sympy.physics.quantum.gate import TGate assert _test_args(TGate(0)) + def test_sympy__physics__quantum__gate__TwoQubitGate(): from sympy.physics.quantum.gate import TwoQubitGate assert _test_args(TwoQubitGate(0)) + def test_sympy__physics__quantum__gate__UGate(): from sympy.physics.quantum.gate import UGate - from sympy.matrices.immutable_matrix import ImmutableMatrix + from sympy.matrices.immutable import ImmutableMatrix from sympy import Integer, Tuple - assert _test_args(UGate(Tuple(Integer(1)), ImmutableMatrix([[1,0],[0,2]]))) + assert _test_args( + UGate(Tuple(Integer(1)), ImmutableMatrix([[1, 0], [0, 2]]))) + def test_sympy__physics__quantum__gate__XGate(): from sympy.physics.quantum.gate import XGate assert _test_args(XGate(0)) + def test_sympy__physics__quantum__gate__YGate(): from sympy.physics.quantum.gate import YGate assert _test_args(YGate(0)) + def test_sympy__physics__quantum__gate__ZGate(): from sympy.physics.quantum.gate import ZGate assert _test_args(ZGate(0)) + @SKIP("TODO: sympy.physics") def test_sympy__physics__quantum__grover__OracleGate(): from sympy.physics.quantum.grover import OracleGate assert _test_args(OracleGate()) + def test_sympy__physics__quantum__grover__WGate(): from sympy.physics.quantum.grover import WGate assert _test_args(WGate(1)) + def test_sympy__physics__quantum__hilbert__ComplexSpace(): from sympy.physics.quantum.hilbert import ComplexSpace assert _test_args(ComplexSpace(x)) + def test_sympy__physics__quantum__hilbert__DirectSumHilbertSpace(): from sympy.physics.quantum.hilbert import DirectSumHilbertSpace, ComplexSpace, FockSpace c = ComplexSpace(2) f = FockSpace() assert _test_args(DirectSumHilbertSpace(c, f)) + def test_sympy__physics__quantum__hilbert__FockSpace(): from sympy.physics.quantum.hilbert import FockSpace assert _test_args(FockSpace()) + def test_sympy__physics__quantum__hilbert__HilbertSpace(): from sympy.physics.quantum.hilbert import HilbertSpace assert _test_args(HilbertSpace()) + def test_sympy__physics__quantum__hilbert__L2(): from sympy.physics.quantum.hilbert import L2 from sympy import oo, Interval assert _test_args(L2(Interval(0, oo))) + def test_sympy__physics__quantum__hilbert__TensorPowerHilbertSpace(): from sympy.physics.quantum.hilbert import TensorPowerHilbertSpace, FockSpace f = FockSpace() assert _test_args(TensorPowerHilbertSpace(f, 2)) + def test_sympy__physics__quantum__hilbert__TensorProductHilbertSpace(): from sympy.physics.quantum.hilbert import TensorProductHilbertSpace, FockSpace, ComplexSpace c = ComplexSpace(2) f = FockSpace() assert _test_args(TensorProductHilbertSpace(f, c)) + def test_sympy__physics__quantum__innerproduct__InnerProduct(): from sympy.physics.quantum import Bra, Ket, InnerProduct b = Bra('b') k = Ket('k') assert _test_args(InnerProduct(b, k)) + def test_sympy__physics__quantum__operator__DifferentialOperator(): from sympy.physics.quantum.operator import DifferentialOperator from sympy import Derivative, Function f = Function('f') assert _test_args(DifferentialOperator(1/x*Derivative(f(x), x), f(x))) + def test_sympy__physics__quantum__operator__HermitianOperator(): from sympy.physics.quantum.operator import HermitianOperator assert _test_args(HermitianOperator('H')) + def test_sympy__physics__quantum__operator__Operator(): from sympy.physics.quantum.operator import Operator assert _test_args(Operator('A')) + def test_sympy__physics__quantum__operator__OuterProduct(): from sympy.physics.quantum.operator import OuterProduct from sympy.physics.quantum import Ket, Bra @@ -1568,207 +2183,258 @@ k = Ket('k') assert _test_args(OuterProduct(k, b)) + def test_sympy__physics__quantum__operator__UnitaryOperator(): from sympy.physics.quantum.operator import UnitaryOperator assert _test_args(UnitaryOperator('U')) + def test_sympy__physics__quantum__piab__PIABBra(): from sympy.physics.quantum.piab import PIABBra assert _test_args(PIABBra('B')) + def test_sympy__physics__quantum__piab__PIABHamiltonian(): from sympy.physics.quantum.piab import PIABHamiltonian assert _test_args(PIABHamiltonian('P')) + def test_sympy__physics__quantum__piab__PIABKet(): from sympy.physics.quantum.piab import PIABKet assert _test_args(PIABKet('K')) + def test_sympy__physics__quantum__qexpr__QExpr(): from sympy.physics.quantum.qexpr import QExpr assert _test_args(QExpr(0)) + def test_sympy__physics__quantum__qft__Fourier(): from sympy.physics.quantum.qft import Fourier assert _test_args(Fourier(0, 1)) + def test_sympy__physics__quantum__qft__IQFT(): from sympy.physics.quantum.qft import IQFT assert _test_args(IQFT(0, 1)) + def test_sympy__physics__quantum__qft__QFT(): from sympy.physics.quantum.qft import QFT assert _test_args(QFT(0, 1)) + def test_sympy__physics__quantum__qft__RkGate(): from sympy.physics.quantum.qft import RkGate assert _test_args(RkGate(0, 1)) + def test_sympy__physics__quantum__qubit__IntQubit(): from sympy.physics.quantum.qubit import IntQubit assert _test_args(IntQubit(0)) + def test_sympy__physics__quantum__qubit__IntQubitBra(): from sympy.physics.quantum.qubit import IntQubitBra assert _test_args(IntQubitBra(0)) + def test_sympy__physics__quantum__qubit__IntQubitState(): from sympy.physics.quantum.qubit import IntQubitState, QubitState assert _test_args(IntQubitState(QubitState(0, 1))) + def test_sympy__physics__quantum__qubit__Qubit(): from sympy.physics.quantum.qubit import Qubit assert _test_args(Qubit(0, 0, 0)) + def test_sympy__physics__quantum__qubit__QubitBra(): from sympy.physics.quantum.qubit import QubitBra assert _test_args(QubitBra('1', 0)) + def test_sympy__physics__quantum__qubit__QubitState(): from sympy.physics.quantum.qubit import QubitState assert _test_args(QubitState(0, 1)) + def test_sympy__physics__quantum__density__Density(): from sympy.physics.quantum.density import Density from sympy.physics.quantum.state import Ket - assert _test_args(Density([Ket(0),0.5], [Ket(1),0.5])) + assert _test_args(Density([Ket(0), 0.5], [Ket(1), 0.5])) + @SKIP("TODO: sympy.physics.quantum.shor: Cmod Not Implemented") def test_sympy__physics__quantum__shor__CMod(): from sympy.physics.quantum.shor import CMod assert _test_args(CMod()) + def test_sympy__physics__quantum__spin__CoupledSpinState(): from sympy.physics.quantum.spin import CoupledSpinState assert _test_args(CoupledSpinState(1, 0, (1, 1))) assert _test_args(CoupledSpinState(1, 0, (1, S(1)/2, S(1)/2))) - assert _test_args(CoupledSpinState(1, 0, (1, S(1)/2, S(1)/2), ((2,3,S(1)/2),(1,2,1)) )) - j,m,j1,j2,j3,j12,x = symbols('j m j1:4 j12 x') - assert CoupledSpinState(j, m, (j1,j2,j3)).subs(j2,x) == CoupledSpinState(j, m, (j1,x,j3)) - assert CoupledSpinState(j, m, (j1,j2,j3),((1,3,j12),(1,2,j)) ).subs(j12,x) == \ - CoupledSpinState(j, m, (j1,j2,j3), ((1,3,x),(1,2,j)) ) + assert _test_args(CoupledSpinState( + 1, 0, (1, S(1)/2, S(1)/2), ((2, 3, S(1)/2), (1, 2, 1)) )) + j, m, j1, j2, j3, j12, x = symbols('j m j1:4 j12 x') + assert CoupledSpinState( + j, m, (j1, j2, j3)).subs(j2, x) == CoupledSpinState(j, m, (j1, x, j3)) + assert CoupledSpinState(j, m, (j1, j2, j3), ((1, 3, j12), (1, 2, j)) ).subs(j12, x) == \ + CoupledSpinState(j, m, (j1, j2, j3), ((1, 3, x), (1, 2, j)) ) + def test_sympy__physics__quantum__spin__J2Op(): from sympy.physics.quantum.spin import J2Op assert _test_args(J2Op('J')) + def test_sympy__physics__quantum__spin__JminusOp(): from sympy.physics.quantum.spin import JminusOp assert _test_args(JminusOp('J')) + def test_sympy__physics__quantum__spin__JplusOp(): from sympy.physics.quantum.spin import JplusOp assert _test_args(JplusOp('J')) + def test_sympy__physics__quantum__spin__JxBra(): from sympy.physics.quantum.spin import JxBra assert _test_args(JxBra(1, 0)) + def test_sympy__physics__quantum__spin__JxBraCoupled(): from sympy.physics.quantum.spin import JxBraCoupled assert _test_args(JxBraCoupled(1, 0, (1, 1))) + def test_sympy__physics__quantum__spin__JxKet(): from sympy.physics.quantum.spin import JxKet assert _test_args(JxKet(1, 0)) + def test_sympy__physics__quantum__spin__JxKetCoupled(): from sympy.physics.quantum.spin import JxKetCoupled assert _test_args(JxKetCoupled(1, 0, (1, 1))) + def test_sympy__physics__quantum__spin__JxOp(): from sympy.physics.quantum.spin import JxOp assert _test_args(JxOp('J')) + def test_sympy__physics__quantum__spin__JyBra(): from sympy.physics.quantum.spin import JyBra assert _test_args(JyBra(1, 0)) + def test_sympy__physics__quantum__spin__JyBraCoupled(): from sympy.physics.quantum.spin import JyBraCoupled assert _test_args(JyBraCoupled(1, 0, (1, 1))) + def test_sympy__physics__quantum__spin__JyKet(): from sympy.physics.quantum.spin import JyKet assert _test_args(JyKet(1, 0)) + def test_sympy__physics__quantum__spin__JyKetCoupled(): from sympy.physics.quantum.spin import JyKetCoupled assert _test_args(JyKetCoupled(1, 0, (1, 1))) + def test_sympy__physics__quantum__spin__JyOp(): from sympy.physics.quantum.spin import JyOp assert _test_args(JyOp('J')) + def test_sympy__physics__quantum__spin__JzBra(): from sympy.physics.quantum.spin import JzBra assert _test_args(JzBra(1, 0)) + def test_sympy__physics__quantum__spin__JzBraCoupled(): from sympy.physics.quantum.spin import JzBraCoupled assert _test_args(JzBraCoupled(1, 0, (1, 1))) + def test_sympy__physics__quantum__spin__JzKet(): from sympy.physics.quantum.spin import JzKet assert _test_args(JzKet(1, 0)) + def test_sympy__physics__quantum__spin__JzKetCoupled(): from sympy.physics.quantum.spin import JzKetCoupled assert _test_args(JzKetCoupled(1, 0, (1, 1))) + def test_sympy__physics__quantum__spin__JzOp(): from sympy.physics.quantum.spin import JzOp assert _test_args(JzOp('J')) + def test_sympy__physics__quantum__spin__Rotation(): from sympy.physics.quantum.spin import Rotation from sympy import pi assert _test_args(Rotation(pi, 0, pi/2)) + def test_sympy__physics__quantum__spin__SpinState(): from sympy.physics.quantum.spin import SpinState assert _test_args(SpinState(1, 0)) + def test_sympy__physics__quantum__spin__WignerD(): from sympy.physics.quantum.spin import WignerD assert _test_args(WignerD(0, 1, 2, 3, 4, 5)) + def test_sympy__physics__quantum__state__Bra(): from sympy.physics.quantum.state import Bra assert _test_args(Bra(0)) + def test_sympy__physics__quantum__state__BraBase(): from sympy.physics.quantum.state import BraBase assert _test_args(BraBase(0)) + def test_sympy__physics__quantum__state__Ket(): from sympy.physics.quantum.state import Ket assert _test_args(Ket(0)) + def test_sympy__physics__quantum__state__KetBase(): from sympy.physics.quantum.state import KetBase assert _test_args(KetBase(0)) + def test_sympy__physics__quantum__state__State(): from sympy.physics.quantum.state import State assert _test_args(State(0)) + def test_sympy__physics__quantum__state__StateBase(): from sympy.physics.quantum.state import StateBase assert _test_args(StateBase(0)) + def test_sympy__physics__quantum__state__TimeDepBra(): from sympy.physics.quantum.state import TimeDepBra assert _test_args(TimeDepBra('psi', 't')) + def test_sympy__physics__quantum__state__TimeDepKet(): from sympy.physics.quantum.state import TimeDepKet assert _test_args(TimeDepKet('psi', 't')) + def test_sympy__physics__quantum__state__TimeDepState(): from sympy.physics.quantum.state import TimeDepState assert _test_args(TimeDepState('psi', 't')) + def test_sympy__physics__quantum__state__Wavefunction(): from sympy.physics.quantum.state import Wavefunction from sympy.functions import sin @@ -1778,245 +2444,412 @@ g = Piecewise((0, x < 0), (0, x > L), (sqrt(2//L)*sin(n*pi*x/L), True)) assert _test_args(Wavefunction(g, x)) + def test_sympy__physics__quantum__tensorproduct__TensorProduct(): from sympy.physics.quantum.tensorproduct import TensorProduct assert _test_args(TensorProduct(x, y)) + def test_sympy__physics__quantum__identitysearch__GateIdentity(): from sympy.physics.quantum.gate import X from sympy.physics.quantum.identitysearch import GateIdentity assert _test_args(GateIdentity(X(0), X(0))) + +def test_sympy__physics__quantum__sho1d__SHOOp(): + from sympy.physics.quantum.sho1d import SHOOp + assert _test_args(SHOOp('a')) + + +def test_sympy__physics__quantum__sho1d__RaisingOp(): + from sympy.physics.quantum.sho1d import RaisingOp + assert _test_args(RaisingOp('a')) + + +def test_sympy__physics__quantum__sho1d__LoweringOp(): + from sympy.physics.quantum.sho1d import LoweringOp + assert _test_args(LoweringOp('a')) + + +def test_sympy__physics__quantum__sho1d__NumberOp(): + from sympy.physics.quantum.sho1d import NumberOp + assert _test_args(NumberOp('N')) + + +def test_sympy__physics__quantum__sho1d__Hamiltonian(): + from sympy.physics.quantum.sho1d import Hamiltonian + assert _test_args(Hamiltonian('H')) + + +def test_sympy__physics__quantum__sho1d__SHOState(): + from sympy.physics.quantum.sho1d import SHOState + assert _test_args(SHOState(0)) + + +def test_sympy__physics__quantum__sho1d__SHOKet(): + from sympy.physics.quantum.sho1d import SHOKet + assert _test_args(SHOKet(0)) + + +def test_sympy__physics__quantum__sho1d__SHOBra(): + from sympy.physics.quantum.sho1d import SHOBra + assert _test_args(SHOBra(0)) + + def test_sympy__physics__secondquant__AnnihilateBoson(): from sympy.physics.secondquant import AnnihilateBoson assert _test_args(AnnihilateBoson(0)) + def test_sympy__physics__secondquant__AnnihilateFermion(): from sympy.physics.secondquant import AnnihilateFermion assert _test_args(AnnihilateFermion(0)) + @SKIP("abstract class") def test_sympy__physics__secondquant__Annihilator(): pass + def test_sympy__physics__secondquant__AntiSymmetricTensor(): from sympy.physics.secondquant import AntiSymmetricTensor i, j = symbols('i j', below_fermi=True) a, b = symbols('a b', above_fermi=True) assert _test_args(AntiSymmetricTensor('v', (a, i), (b, j))) + def test_sympy__physics__secondquant__BosonState(): from sympy.physics.secondquant import BosonState assert _test_args(BosonState((0, 1))) + @SKIP("abstract class") def test_sympy__physics__secondquant__BosonicOperator(): pass + def test_sympy__physics__secondquant__Commutator(): from sympy.physics.secondquant import Commutator assert _test_args(Commutator(x, y)) + def test_sympy__physics__secondquant__CreateBoson(): from sympy.physics.secondquant import CreateBoson assert _test_args(CreateBoson(0)) + def test_sympy__physics__secondquant__CreateFermion(): from sympy.physics.secondquant import CreateFermion assert _test_args(CreateFermion(0)) + @SKIP("abstract class") def test_sympy__physics__secondquant__Creator(): pass + def test_sympy__physics__secondquant__Dagger(): from sympy.physics.secondquant import Dagger from sympy import I assert _test_args(Dagger(2*I)) + def test_sympy__physics__secondquant__FermionState(): from sympy.physics.secondquant import FermionState assert _test_args(FermionState((0, 1))) + def test_sympy__physics__secondquant__FermionicOperator(): from sympy.physics.secondquant import FermionicOperator assert _test_args(FermionicOperator(0)) + def test_sympy__physics__secondquant__FockState(): from sympy.physics.secondquant import FockState assert _test_args(FockState((0, 1))) + def test_sympy__physics__secondquant__FockStateBosonBra(): from sympy.physics.secondquant import FockStateBosonBra assert _test_args(FockStateBosonBra((0, 1))) + def test_sympy__physics__secondquant__FockStateBosonKet(): from sympy.physics.secondquant import FockStateBosonKet assert _test_args(FockStateBosonKet((0, 1))) + def test_sympy__physics__secondquant__FockStateBra(): from sympy.physics.secondquant import FockStateBra assert _test_args(FockStateBra((0, 1))) + def test_sympy__physics__secondquant__FockStateFermionBra(): from sympy.physics.secondquant import FockStateFermionBra assert _test_args(FockStateFermionBra((0, 1))) + def test_sympy__physics__secondquant__FockStateFermionKet(): from sympy.physics.secondquant import FockStateFermionKet assert _test_args(FockStateFermionKet((0, 1))) + def test_sympy__physics__secondquant__FockStateKet(): from sympy.physics.secondquant import FockStateKet assert _test_args(FockStateKet((0, 1))) + def test_sympy__physics__secondquant__InnerProduct(): from sympy.physics.secondquant import InnerProduct from sympy.physics.secondquant import FockStateKet, FockStateBra assert _test_args(InnerProduct(FockStateBra((0, 1)), FockStateKet((0, 1)))) + def test_sympy__physics__secondquant__NO(): from sympy.physics.secondquant import NO, F, Fd assert _test_args(NO(Fd(x)*F(y))) + def test_sympy__physics__secondquant__PermutationOperator(): from sympy.physics.secondquant import PermutationOperator assert _test_args(PermutationOperator(0, 1)) + def test_sympy__physics__secondquant__SqOperator(): from sympy.physics.secondquant import SqOperator assert _test_args(SqOperator(0)) + def test_sympy__physics__secondquant__TensorSymbol(): from sympy.physics.secondquant import TensorSymbol assert _test_args(TensorSymbol(x)) + def test_sympy__physics__units__Unit(): from sympy.physics.units import Unit assert _test_args(Unit("meter", "m")) + def test_sympy__polys__numberfields__AlgebraicNumber(): from sympy.polys.numberfields import AlgebraicNumber assert _test_args(AlgebraicNumber(sqrt(2), [1, 2, 3])) + def test_sympy__polys__polytools__GroebnerBasis(): from sympy.polys.polytools import GroebnerBasis assert _test_args(GroebnerBasis([x, y, z], x, y, z)) + def test_sympy__polys__polytools__Poly(): from sympy.polys.polytools import Poly assert _test_args(Poly(2, x, y)) + def test_sympy__polys__polytools__PurePoly(): from sympy.polys.polytools import PurePoly assert _test_args(PurePoly(2, x, y)) + def test_sympy__polys__rootoftools__RootOf(): from sympy.polys.rootoftools import RootOf assert _test_args(RootOf(x**3 + x + 1, 0)) + def test_sympy__polys__rootoftools__RootSum(): from sympy.polys.rootoftools import RootSum assert _test_args(RootSum(x**3 + x + 1, sin)) + def test_sympy__series__limits__Limit(): from sympy.series.limits import Limit assert _test_args(Limit(x, x, 0, dir='-')) + def test_sympy__series__order__Order(): from sympy.series.order import Order assert _test_args(Order(1, x, y)) -def test_sympy__simplify__cse_opts__Neg(): - from sympy.simplify.cse_opts import Neg - assert _test_args(Neg()) + +def test_sympy__simplify__hyperexpand__Hyper_Function(): + from sympy.simplify.hyperexpand import Hyper_Function + assert _test_args(Hyper_Function([2], [1])) + + +def test_sympy__simplify__hyperexpand__G_Function(): + from sympy.simplify.hyperexpand import G_Function + assert _test_args(G_Function([2], [1], [], [])) + def test_sympy__tensor__indexed__Idx(): from sympy.tensor.indexed import Idx assert _test_args(Idx('test')) assert _test_args(Idx(1, (0, 10))) + def test_sympy__tensor__indexed__Indexed(): from sympy.tensor.indexed import Indexed, Idx assert _test_args(Indexed('A', Idx('i'), Idx('j'))) + def test_sympy__tensor__indexed__IndexedBase(): from sympy.tensor.indexed import IndexedBase assert _test_args(IndexedBase('A', shape=(x, y))) + assert _test_args(IndexedBase('A', 1)) + assert _test_args(IndexedBase('A')[0, 1]) + +@XFAIL +def test_sympy__tensor__tensor__TensorIndexType(): + from sympy.tensor.tensor import TensorIndexType + from sympy import Symbol + assert _test_args(TensorIndexType('Lorentz', metric=False)) + +@XFAIL +def test_sympy__tensor__tensor__TensorSymmetry(): + from sympy.tensor.tensor import TensorIndexType, tensor_indices, TensorSymmetry, TensorType, get_symmetric_group_sgs + assert _test_args(TensorSymmetry(get_symmetric_group_sgs(2))) + + +@XFAIL +def test_sympy__tensor__tensor__TensorType(): + from sympy.tensor.tensor import TensorIndexType, TensorSymmetry, get_symmetric_group_sgs, TensorType + Lorentz = TensorIndexType('Lorentz', dummy_fmt='L') + sym = TensorSymmetry(get_symmetric_group_sgs(1)) + assert _test_args(TensorType([Lorentz], sym)) + +@XFAIL +def test_sympy__tensor__tensor__TensorHead(): + from sympy.tensor.tensor import TensorIndexType, TensorSymmetry, TensorType, get_symmetric_group_sgs, TensorHead + Lorentz = TensorIndexType('Lorentz', dummy_fmt='L') + sym = TensorSymmetry(get_symmetric_group_sgs(1)) + S1 = TensorType([Lorentz], sym) + assert _test_args(TensorHead('p', S1, 0)) + +@XFAIL +def test_sympy__tensor__tensor__TensorIndex(): + from sympy.tensor.tensor import TensorIndexType, TensorIndex, TensorSymmetry, TensorType, get_symmetric_group_sgs + Lorentz = TensorIndexType('Lorentz', dummy_fmt='L') + assert _test_args(TensorIndex('i', Lorentz)) + +@SKIP("abstract class") +def test_sympy__tensor__tensor__TensExpr(): + pass + +def test_sympy__tensor__tensor__TensAdd(): + from sympy.tensor.tensor import TensorIndexType, TensorSymmetry, TensorType, get_symmetric_group_sgs, tensor_indices, TensAdd + Lorentz = TensorIndexType('Lorentz', dummy_fmt='L') + a, b = tensor_indices('a,b', Lorentz) + sym = TensorSymmetry(get_symmetric_group_sgs(1)) + S1 = TensorType([Lorentz], sym) + p, q = S1('p,q') + t1 = p(a) + t2 = q(a) + assert _test_args(TensAdd(t1, t2)) + + +def test_sympy__tensor__tensor__TensMul(): + from sympy.core import S + from sympy.tensor.tensor import TensorIndexType, TensorSymmetry, TensorType, get_symmetric_group_sgs, tensor_indices, TensMul + Lorentz = TensorIndexType('Lorentz', dummy_fmt='L') + a, b = tensor_indices('a,b', Lorentz) + sym = TensorSymmetry(get_symmetric_group_sgs(1)) + S1 = TensorType([Lorentz], sym) + p = S1('p') + free, dum = TensMul.from_indices(a) + assert _test_args(TensMul(S.One, [p], free, dum)) + + @XFAIL def test_as_coeff_add(): # the ordering of terms in (3*x, 4*x**2) is system-dependent assert (7, (3*x, 4*x**2)) == (7 + 3*x + 4*x**2).as_coeff_add() + def test_sympy__geometry__curve__Curve(): from sympy.geometry.curve import Curve assert _test_args(Curve((x, 1), (x, 0, 1))) + def test_sympy__geometry__point__Point(): from sympy.geometry.point import Point assert _test_args(Point(0, 1)) + def test_sympy__geometry__ellipse__Ellipse(): from sympy.geometry.ellipse import Ellipse assert _test_args(Ellipse((0, 1), 2, 3)) + def test_sympy__geometry__ellipse__Circle(): from sympy.geometry.ellipse import Circle assert _test_args(Circle((0, 1), 2)) + def test_sympy__geometry__line__LinearEntity(): from sympy.geometry.line import LinearEntity assert _test_args(LinearEntity((0, 1), (2, 3))) + def test_sympy__geometry__line__Line(): from sympy.geometry.line import Line assert _test_args(Line((0, 1), (2, 3))) + def test_sympy__geometry__line__Ray(): from sympy.geometry.line import Ray assert _test_args(Ray((0, 1), (2, 3))) + def test_sympy__geometry__line__Segment(): from sympy.geometry.line import Segment assert _test_args(Segment((0, 1), (2, 3))) + def test_sympy__geometry__polygon__Polygon(): from sympy.geometry.polygon import Polygon assert _test_args(Polygon((0, 1), (2, 3), (4, 5), (6, 7))) + def test_sympy__geometry__polygon__RegularPolygon(): from sympy.geometry.polygon import RegularPolygon assert _test_args(RegularPolygon((0, 1), 2, 3, 4)) + def test_sympy__geometry__polygon__Triangle(): from sympy.geometry.polygon import Triangle assert _test_args(Triangle((0, 1), (2, 3), (4, 5))) + def test_sympy__geometry__entity__GeometryEntity(): from sympy.geometry.entity import GeometryEntity from sympy.geometry.point import Point assert _test_args(GeometryEntity(Point(1, 0), 1)) + @XFAIL def test_sympy__diffgeom__diffgeom__Manifold(): from sympy.diffgeom import Manifold assert _test_args(Manifold('name', 3)) + @XFAIL def test_sympy__diffgeom__diffgeom__Patch(): from sympy.diffgeom import Manifold, Patch assert _test_args(Patch('name', Manifold('name', 3))) + @XFAIL def test_sympy__diffgeom__diffgeom__CoordSystem(): from sympy.diffgeom import Manifold, Patch, CoordSystem assert _test_args(CoordSystem('name', Patch('name', Manifold('name', 3)))) + @XFAIL def test_sympy__diffgeom__diffgeom__Point(): from sympy.diffgeom import Manifold, Patch, CoordSystem, Point - assert _test_args(Point(CoordSystem('name', Patch('name', Manifold('name', 3))), [x, y])) + assert _test_args(Point( + CoordSystem('name', Patch('name', Manifold('name', 3))), [x, y])) + @XFAIL def test_sympy__diffgeom__diffgeom__BaseScalarField(): @@ -2024,17 +2857,20 @@ cs = CoordSystem('name', Patch('name', Manifold('name', 3))) assert _test_args(BaseScalarField(cs, 0)) + @XFAIL def test_sympy__diffgeom__diffgeom__BaseVectorField(): from sympy.diffgeom import Manifold, Patch, CoordSystem, BaseVectorField cs = CoordSystem('name', Patch('name', Manifold('name', 3))) assert _test_args(BaseVectorField(cs, 0)) + def test_sympy__diffgeom__diffgeom__Differential(): from sympy.diffgeom import Manifold, Patch, CoordSystem, BaseScalarField, Differential cs = CoordSystem('name', Patch('name', Manifold('name', 3))) assert _test_args(Differential(BaseScalarField(cs, 0))) + def test_sympy__diffgeom__diffgeom__Commutator(): from sympy.diffgeom import Manifold, Patch, CoordSystem, BaseScalarField, BaseVectorField, Commutator cs = CoordSystem('name', Patch('name', Manifold('name', 3))) @@ -2043,12 +2879,14 @@ v1 = BaseVectorField(cs1, 0) assert _test_args(Commutator(v, v1)) + def test_sympy__diffgeom__diffgeom__TensorProduct(): from sympy.diffgeom import Manifold, Patch, CoordSystem, BaseScalarField, Differential, TensorProduct cs = CoordSystem('name', Patch('name', Manifold('name', 3))) d = Differential(BaseScalarField(cs, 0)) assert _test_args(TensorProduct(d, d)) + def test_sympy__diffgeom__diffgeom__WedgeProduct(): from sympy.diffgeom import Manifold, Patch, CoordSystem, BaseScalarField, Differential, WedgeProduct cs = CoordSystem('name', Patch('name', Manifold('name', 3))) @@ -2056,6 +2894,7 @@ d1 = Differential(BaseScalarField(cs, 1)) assert _test_args(WedgeProduct(d, d1)) + def test_sympy__diffgeom__diffgeom__LieDerivative(): from sympy.diffgeom import Manifold, Patch, CoordSystem, BaseScalarField, Differential, BaseVectorField, LieDerivative cs = CoordSystem('name', Patch('name', Manifold('name', 3))) @@ -2063,39 +2902,47 @@ v = BaseVectorField(cs, 0) assert _test_args(LieDerivative(v, d)) + @XFAIL def test_sympy__diffgeom__diffgeom__BaseCovarDerivativeOp(): from sympy.diffgeom import Manifold, Patch, CoordSystem, BaseCovarDerivativeOp cs = CoordSystem('name', Patch('name', Manifold('name', 3))) - assert _test_args(BaseCovarDerivativeOp(cs, 0, [[[0,]*3,]*3,]*3)) + assert _test_args(BaseCovarDerivativeOp(cs, 0, [[[0, ]*3, ]*3, ]*3)) + def test_sympy__diffgeom__diffgeom__CovarDerivativeOp(): from sympy.diffgeom import Manifold, Patch, CoordSystem, BaseVectorField, CovarDerivativeOp cs = CoordSystem('name', Patch('name', Manifold('name', 3))) v = BaseVectorField(cs, 0) - _test_args(CovarDerivativeOp(v, [[[0,]*3,]*3,]*3)) + _test_args(CovarDerivativeOp(v, [[[0, ]*3, ]*3, ]*3)) + def test_sympy__categories__baseclasses__Class(): from sympy.categories.baseclasses import Class assert _test_args(Class()) + def test_sympy__categories__baseclasses__Object(): from sympy.categories import Object assert _test_args(Object("A")) + @XFAIL def test_sympy__categories__baseclasses__Morphism(): from sympy.categories import Object, Morphism assert _test_args(Morphism(Object("A"), Object("B"))) + def test_sympy__categories__baseclasses__IdentityMorphism(): from sympy.categories import Object, IdentityMorphism assert _test_args(IdentityMorphism(Object("A"))) + def test_sympy__categories__baseclasses__NamedMorphism(): from sympy.categories import Object, NamedMorphism assert _test_args(NamedMorphism(Object("A"), Object("B"), "f")) + def test_sympy__categories__baseclasses__CompositeMorphism(): from sympy.categories import Object, NamedMorphism, CompositeMorphism A = Object("A") @@ -2105,6 +2952,7 @@ g = NamedMorphism(B, C, "g") assert _test_args(CompositeMorphism(f, g)) + def test_sympy__categories__baseclasses__Diagram(): from sympy.categories import Object, NamedMorphism, Diagram, Category A = Object("A") @@ -2114,6 +2962,7 @@ d = Diagram([f]) assert _test_args(d) + def test_sympy__categories__baseclasses__Category(): from sympy.categories import Object, NamedMorphism, Diagram, Category A = Object("A") @@ -2125,3 +2974,9 @@ d2 = Diagram([f]) K = Category("K", commutative_diagrams=[d1, d2]) assert _test_args(K) + +def test_sympy__ntheory__factor___totient(): + from sympy.ntheory.factor_ import totient + k = symbols('k', integer=True) + t = totient(k) + assert _test_args(t) diff -Nru python3-sympy-0.7.2/sympy/core/tests/test_arit.py python3-sympy-0.7.3/sympy/core/tests/test_arit.py --- python3-sympy-0.7.2/sympy/core/tests/test_arit.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/core/tests/test_arit.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,130 +1,138 @@ -from sympy import (Symbol, sin, cos, exp, O, sqrt, Rational, Float, re, pi, +from sympy import (Symbol, sin, cos, exp, sqrt, Rational, Float, re, pi, sympify, Add, Mul, Pow, Mod, I, log, S, Max, Or, symbols, oo, Integer, - Tuple) + sign, im +) from sympy.utilities.pytest import XFAIL, raises +from sympy.utilities.randtest import test_numerically + x = Symbol('x') y = Symbol('y') z = Symbol('z') + def test_bug1(): assert re(x) != x - x.series(x,0,1) + x.series(x, 0, 1) assert re(x) != x a = Symbol("a") b = Symbol("b", positive=True) c = Symbol("c") + def test_Symbol(): - e=a*b - assert e==a*b - assert a*b*b==a*b**2 - assert a*b*b+c==c+a*b**2 - assert a*b*b-c==-c+a*b**2 + e = a*b + assert e == a*b + assert a*b*b == a*b**2 + assert a*b*b + c == c + a*b**2 + assert a*b*b - c == -c + a*b**2 + def test_arit0(): p = Rational(5) - e=a*b + e = a*b assert e == a*b - e=a*b+b*a + e = a*b + b*a assert e == 2*a*b - e=a*b+b*a+a*b+p*b*a + e = a*b + b*a + a*b + p*b*a assert e == 8*a*b - e=a*b+b*a+a*b+p*b*a+a - assert e == a+8*a*b - e=a+a + e = a*b + b*a + a*b + p*b*a + a + assert e == a + 8*a*b + e = a + a assert e == 2*a - e=a+b+a - assert e == b+2*a - e=a+b*b+a+b*b - assert e == 2*a+2*b**2 - e=a+Rational(2)+b*b+a+b*b+p - assert e == 7+2*a+2*b**2 - e=(a+b*b+a+b*b)*p - assert e == 5*(2*a+2*b**2) - e=(a*b*c+c*b*a+b*a*c)*p + e = a + b + a + assert e == b + 2*a + e = a + b*b + a + b*b + assert e == 2*a + 2*b**2 + e = a + Rational(2) + b*b + a + b*b + p + assert e == 7 + 2*a + 2*b**2 + e = (a + b*b + a + b*b)*p + assert e == 5*(2*a + 2*b**2) + e = (a*b*c + c*b*a + b*a*c)*p assert e == 15*a*b*c - e=(a*b*c+c*b*a+b*a*c)*p-Rational(15)*a*b*c + e = (a*b*c + c*b*a + b*a*c)*p - Rational(15)*a*b*c assert e == Rational(0) - e = Rational(50)*(a-a) + e = Rational(50)*(a - a) assert e == Rational(0) - e=b*a-b-a*b+b + e = b*a - b - a*b + b assert e == Rational(0) - e=a*b+c**p - assert e == a*b+c**5 - e=a/b + e = a*b + c**p + assert e == a*b + c**5 + e = a/b assert e == a*b**(-1) - e=a*2*2 + e = a*2*2 assert e == 4*a - e=2+a*2/2 - assert e == 2+a - e=2-a-2 + e = 2 + a*2/2 + assert e == 2 + a + e = 2 - a - 2 assert e == -a - e=2*a*2 + e = 2*a*2 assert e == 4*a - e=2/a/2 + e = 2/a/2 assert e == a**(-1) - e=2**a**2 + e = 2**a**2 assert e == 2**(a**2) - e = -(1+a) - assert e == -1 -a - e = Rational(1,2)*(1+a) - assert e == Rational(1,2) + a/2 + e = -(1 + a) + assert e == -1 - a + e = Rational(1, 2)*(1 + a) + assert e == Rational(1, 2) + a/2 + def test_div(): - e=a/b + e = a/b assert e == a*b**(-1) - e=a/b+c/2 - assert e == a*b**(-1)+Rational(1)/2*c - e=(1-b)/(b-1) - assert e == (1+-b)*((-1)+b)**(-1) + e = a/b + c/2 + assert e == a*b**(-1) + Rational(1)/2*c + e = (1 - b)/(b - 1) + assert e == (1 + -b)*((-1) + b)**(-1) + def test_pow(): n1 = Rational(1) n2 = Rational(2) n5 = Rational(5) - e=a*a + e = a*a assert e == a**2 - e=a*a*a + e = a*a*a assert e == a**3 - e=a*a*a*a**Rational(6) + e = a*a*a*a**Rational(6) assert e == a**9 - e=a*a*a*a**Rational(6)-a**Rational(9) + e = a*a*a*a**Rational(6) - a**Rational(9) assert e == Rational(0) - e=a**(b-b) + e = a**(b - b) assert e == Rational(1) - e=(a-a)**b + e = (a - a)**b assert e == Rational(0) - e=(a+Rational(1)-a)**b + e = (a + Rational(1) - a)**b assert e == Rational(1) - e=(a+b+c)**n2 - assert e == (a+b+c)**2 - assert e.expand() == 2*b*c+2*a*c+2*a*b+a**2+c**2+b**2 - - e=(a+b)**n2 - assert e == (a+b)**2 - assert e.expand() == 2*a*b+a**2+b**2 - - e=(a+b)**(n1/n2) - assert e == sqrt(a+b) - assert e.expand() == sqrt(a+b) + e = (a + b + c)**n2 + assert e == (a + b + c)**2 + assert e.expand() == 2*b*c + 2*a*c + 2*a*b + a**2 + c**2 + b**2 + + e = (a + b)**n2 + assert e == (a + b)**2 + assert e.expand() == 2*a*b + a**2 + b**2 + + e = (a + b)**(n1/n2) + assert e == sqrt(a + b) + assert e.expand() == sqrt(a + b) - n=n5**(n1/n2) + n = n5**(n1/n2) assert n == sqrt(5) - e=n*a*b-n*b*a + e = n*a*b - n*b*a assert e == Rational(0) - e=n*a*b+n*b*a + e = n*a*b + n*b*a assert e == 2*a*b*sqrt(5) assert e.diff(a) == 2*b*sqrt(5) assert e.diff(a) == 2*b*sqrt(5) - e=a/b**2 + e = a/b**2 assert e == a*b**(-2) - assert sqrt(2*(1+sqrt(2))) == (2*(1+2**Rational(1,2)))**Rational(1,2) + assert sqrt(2*(1 + sqrt(2))) == (2*(1 + 2**Rational(1, 2)))**Rational(1, 2) x = Symbol('x') y = Symbol('y') @@ -134,12 +142,14 @@ assert (x**5*(3*x)**(3)).expand() == 27 * x**8 assert (x**5*(-3*x)**(3)).expand() == -27 * x**8 - assert (x**5*(3*x)**(-3)).expand() == Rational(1,27) * x**2 - assert (x**5*(-3*x)**(-3)).expand() == -Rational(1,27) * x**2 + assert (x**5*(3*x)**(-3)).expand() == Rational(1, 27) * x**2 + assert (x**5*(-3*x)**(-3)).expand() == -Rational(1, 27) * x**2 # expand_power_exp - assert (x**(y**(x+exp(x+y))+z)).expand(deep=False) == x**z*x**(y**(x + exp(x + y))) - assert (x**(y**(x+exp(x+y))+z)).expand() == x**z*x**(y**x*y**(exp(x)*exp(y))) + assert (x**(y**(x + exp(x + y)) + z)).expand(deep=False) == \ + x**z*x**(y**(x + exp(x + y))) + assert (x**(y**(x + exp(x + y)) + z)).expand() == \ + x**z*x**(y**x*y**(exp(x)*exp(y))) n = Symbol('k', even=False) k = Symbol('k', even=True) @@ -147,24 +157,46 @@ assert (-1)**x == (-1)**x assert (-1)**n == (-1)**n assert (-2)**k == 2**k - assert (-2*x)**k == 2**k*x**k + assert (-2*x)**k == (-2*x)**k # we choose not to auto expand this assert (-1)**k == 1 + def test_pow2(): # x**(2*y) is always (x**y)**2 but is only (x**2)**y if # x.is_positive or y.is_integer # let x = 1 to see why the following are not true. - assert ((-x)**2)**Rational(1,3) != ((-x)**Rational(1,3))**2 - assert (-x)**Rational(2,3) != x**Rational(2,3) - assert (-x)**Rational(5,7) != -x**Rational(5,7) + assert ((-x)**2)**Rational(1, 3) != ((-x)**Rational(1, 3))**2 + assert (-x)**Rational(2, 3) != x**Rational(2, 3) + assert (-x)**Rational(5, 7) != -x**Rational(5, 7) + def test_pow3(): assert sqrt(2)**3 == 2 * sqrt(2) assert sqrt(2)**3 == sqrt(8) + +def test_pow_E(): + assert 2**(y/log(2)) == S.Exp1**y + assert 2**(y/log(2)/3) == S.Exp1**(y/3) + assert 3**(1/log(-3)) != S.Exp1 + assert (3 + 2*I)**(1/(log(-3 - 2*I) + I*pi)) == S.Exp1 + assert (4 + 2*I)**(1/(log(-4 - 2*I) + I*pi)) == S.Exp1 + assert (3 + 2*I)**(1/(log(-3 - 2*I, 3)/2 + I*pi/log(3)/2)) == 9 + assert (3 + 2*I)**(1/(log(3 + 2*I, 3)/2)) == 9 + # every time tests are run they will affirm with a different random + # value that this identity holds + while 1: + b = x._random() + r, i = b.as_real_imag() + if i: + break + assert test_numerically(b**(1/(log(-b) + sign(i)*I*pi).n()), S.Exp1) + + def test_pow_issue417(): assert 4**Rational(1, 4) == sqrt(2) + def test_pow_im(): for m in (-2, -1, 2): for d in (3, 4, 5): @@ -174,7 +206,7 @@ assert (b**e - b.n()**e.n()).n(2, chop=1e-10) == 0 e = Rational(7, 3) - assert (2*x*I)**e == 4*2**Rational(1, 3)*(I*x)**e # same as Wolfram Alpha + assert (2*x*I)**e == 4*2**Rational(1, 3)*(I*x)**e # same as Wolfram Alpha im = symbols('im', imaginary=True) assert (2*im*I)**e == 4*2**Rational(1, 3)*(I*im)**e @@ -185,95 +217,39 @@ assert Mul(*args)**e == ans args = [I, I, I, 2] e = Rational(1, 3) - ans = -(-1)**Rational(5, 6)*2**e + ans = 2**e*(-I)**e assert Mul(*args, **dict(evaluate=False))**e == ans assert Mul(*args)**e == ans + args.append(-3) + ans = (6*I)**e + assert Mul(*args, **dict(evaluate=False))**e == ans + assert Mul(*args)**e == ans + args.append(-1) + ans = (-6*I)**e + assert Mul(*args, **dict(evaluate=False))**e == ans + assert Mul(*args)**e == ans + args = [I, I, 2] e = Rational(1, 3) ans = (-2)**e assert Mul(*args, **dict(evaluate=False))**e == ans assert Mul(*args)**e == ans + args.append(-3) + ans = (6)**e + assert Mul(*args, **dict(evaluate=False))**e == ans + assert Mul(*args)**e == ans + args.append(-1) + ans = (-6)**e + assert Mul(*args, **dict(evaluate=False))**e == ans + assert Mul(*args)**e == ans + assert Mul(Pow(-1, Rational(3, 2), evaluate=False), I, I) == I + assert Mul(I*Pow(I, S.Half, evaluate=False)) == (-1)**Rational(3, 4) -def test_expand(): - p = Rational(5) - e = (a+b)*c - assert e == c*(a+b) - assert (e.expand()-a*c-b*c) == Rational(0) - e=(a+b)*(a+b) - assert e == (a+b)**2 - assert e.expand() == 2*a*b+a**2+b**2 - e=(a+b)*(a+b)**Rational(2) - assert e == (a+b)**3 - assert e.expand() == 3*b*a**2+3*a*b**2+a**3+b**3 - assert e.expand() == 3*b*a**2+3*a*b**2+a**3+b**3 - e=(a+b)*(a+c)*(b+c) - assert e == (a+c)*(a+b)*(b+c) - assert e.expand() == 2*a*b*c+b*a**2+c*a**2+b*c**2+a*c**2+c*b**2+a*b**2 - e=(a+Rational(1))**p - assert e == (1+a)**5 - assert e.expand() == 1+5*a+10*a**2+10*a**3+5*a**4+a**5 - e=(a+b+c)*(a+c+p) - assert e == (5+a+c)*(a+b+c) - assert e.expand() == 5*a+5*b+5*c+2*a*c+b*c+a*b+a**2+c**2 - x=Symbol("x") - s=exp(x*x)-1 - e=s.nseries(x,0,3)/x**2 - assert e.expand() == 1+x**2/2+O(x**4) - - e = (x*(y+z))**(x*(y+z))*(x+y) - assert e.expand(power_exp=False, power_base=False) == x*(x*y + x*z)**(x*y + x*z) + y*(x*y + x*z)**(x*y + x*z) - assert e.expand(power_exp=False, power_base=False, deep=False) == x*(x*(y + z))**(x*(y + z)) + y*(x*(y + z))**(x*(y + z)) - e = (x*(y+z))**z - assert e.expand(power_base=True, mul=True, deep=True) in [x**z*(y + z)**z, (x*y + x*z)**z] - assert ((2*y)**z).expand() == 2**z*y**z - p=Symbol('p', positive=True) - assert sqrt(-x).expand().is_Pow - assert sqrt(-x).expand(force=True) == I*sqrt(x) - assert ((2*y*p)**z).expand() == 2**z*p**z*y**z - assert ((2*y*p*x)**z).expand() == 2**z*p**z*(x*y)**z - assert ((2*y*p*x)**z).expand(force=True) == 2**z*p**z*x**z*y**z - assert ((2*y*p*-pi)**z).expand() == 2**z*pi**z*p**z*(-y)**z - assert ((2*y*p*-pi*x)**z).expand() == 2**z*pi**z*p**z*(-x*y)**z - n=Symbol('n', negative=True) - m=Symbol('m', negative=True) - assert ((-2*x*y*n)**z).expand() == 2**z*(-n)**z*(x*y)**z - assert ((-2*x*y*n*m)**z).expand() == 2**z*(-m)**z*(-n)**z*(-x*y)**z - # issue 2383 - assert sqrt(-2*x*n) == sqrt(2)*sqrt(-n)*sqrt(x) - # issue 2506 (2) - assert (cos(x+y)**2).expand(trig=True) in [(-sin(x)*sin(y) + cos(x)*cos(y))**2, - sin(x)**2*sin(y)**2 - 2*sin(x)*sin(y)*cos(x)*cos(y) + cos(x)**2*cos(y)**2] - - # Check that this isn't too slow - x = Symbol('x') - W = 1 - for i in range(1, 21): - W = W * (x-i) - W = W.expand() - assert W.has(-1672280820*x**15) - -def test_power_expand(): - """Test for Pow.expand()""" - a = Symbol('a') - b = Symbol('b') - p = (a+b)**2 - assert p.expand() == a**2 + b**2 + 2*a*b - - p = (1+2*(1+a))**2 - assert p.expand() == 9 + 4*(a**2) + 12*a - - p = 2**(a+b) - assert p.expand() == 2**a*2**b - - A = Symbol('A', commutative=False) - B = Symbol('B', commutative=False) - assert (2**(A+B)).expand() == 2**(A+B) - assert (A**(a+b)).expand() != A**(a+b) def test_real_mul(): assert Float(0) * pi * x == Float(0) - assert Float(1) * pi * x == pi * x - assert len((Float(2) * pi * x).args) == 3 + assert set((Float(1) * pi * x).args) == set([Float(1), pi, x]) + def test_ncmul(): A = Symbol("A", commutative=False) @@ -285,25 +261,23 @@ assert A*b*B*3*C != 3*b*B*A*C assert A*b*B*3*C == 3*A*B*C*b - assert A+B == B+A - assert (A+B)*C != C*(A+B) - - assert C*(A+B)*C != C*C*(A+B) + assert A + B == B + A + assert (A + B)*C != C*(A + B) - assert (C*(A+B)).expand() == C*A+C*B - assert (C*(A+B)).expand() != A*C+B*C + assert C*(A + B)*C != C*C*(A + B) assert A*A == A**2 - assert (A+B)*(A+B) == (A+B)**2 - assert ((A+B)**2).expand() == A**2 + A*B + B*A +B**2 + assert (A + B)*(A + B) == (A + B)**2 - assert A**-1 * A == 1 + assert A**-1 * A == 1 assert A/A == 1 assert A/(A**2) == 1/A - assert A/(1+A) == A/(1+A) + assert A/(1 + A) == A/(1 + A) + + assert set((A + B + 2*(A + B)).args) == \ + set([A, B, 2*(A + B)]) - assert (A+B + 2*(A+B)) == 3*A + 3*B def test_ncpow(): x = Symbol('x', commutative=False) @@ -315,22 +289,23 @@ assert (x**2)*(y**2) != (y**2)*(x**2) assert (x**-2)*y != y*(x**2) - assert 2**x*2**y != 2**(x+y) - assert 2**x*2**y*2**z != 2**(x+y+z) + assert 2**x*2**y != 2**(x + y) + assert 2**x*2**y*2**z != 2**(x + y + z) assert 2**x*2**(2*x) == 2**(3*x) assert 2**x*2**(2*x)*2**x == 2**(4*x) assert exp(x)*exp(y) != exp(y)*exp(x) assert exp(x)*exp(y)*exp(z) != exp(y)*exp(x)*exp(z) - assert exp(x)*exp(y)*exp(z) != exp(x+y+z) - assert x**a*x**b != x**(a+b) - assert x**a*x**b*x**c != x**(a+b+c) + assert exp(x)*exp(y)*exp(z) != exp(x + y + z) + assert x**a*x**b != x**(a + b) + assert x**a*x**b*x**c != x**(a + b + c) assert x**3*x**4 == x**7 assert x**3*x**4*x**2 == x**9 assert x**a*x**(4*a) == x**(5*a) assert x**a*x**(4*a)*x**a == x**(6*a) + def test_powerbug(): - x=Symbol("x") + x = Symbol("x") assert x**1 != (-x)**1 assert x**2 == (-x)**2 assert x**3 != (-x)**3 @@ -343,6 +318,7 @@ assert (2*x)**2 == (-2*x)**2 + def test_Mul_doesnt_expand_exp(): x = Symbol('x') y = Symbol('y') @@ -353,45 +329,48 @@ assert x**(y)*x**(2*y) == x**(3*y) assert sqrt(2)*sqrt(2) == 2 assert 2**x*2**(2*x) == 2**(3*x) - assert sqrt(2)*2**Rational(1,4)*5**Rational(3,4) == 10**Rational(3,4) + assert sqrt(2)*2**Rational(1, 4)*5**Rational(3, 4) == 10**Rational(3, 4) assert (x**(-log(5)/log(3))*x)/(x*x**( - log(5)/log(3))) == sympify(1) + def test_Add_Mul_is_integer(): x = Symbol('x') k = Symbol('k', integer=True) n = Symbol('n', integer=True) - assert (2*k).is_integer == True - assert (-k).is_integer == True - assert (k/3).is_integer == False - assert (x*k*n).is_integer == None - - assert (k+n).is_integer == True - assert (k+x).is_integer == None - assert (k+n*x).is_integer == None - assert (k+n/3).is_integer == False + assert (2*k).is_integer is True + assert (-k).is_integer is True + assert (k/3).is_integer is None + assert (x*k*n).is_integer is None + + assert (k + n).is_integer is True + assert (k + x).is_integer is None + assert (k + n*x).is_integer is None + assert (k + n/3).is_integer is None + + assert ((1 + sqrt(3))*(-sqrt(3) + 1)).is_integer is not False + assert (1 + (1 + sqrt(3))*(-sqrt(3) + 1)).is_integer is not False - assert ((1 + sqrt(3))*(-sqrt(3) + 1)).is_integer != False - assert (1 + (1 + sqrt(3))*(-sqrt(3) + 1)).is_integer != False def test_Add_Mul_is_bounded(): x = Symbol('x', real=True, bounded=False) - assert sin(x).is_bounded == True - assert (x*sin(x)).is_bounded == False - assert (1024*sin(x)).is_bounded == True + assert sin(x).is_bounded is True + assert (x*sin(x)).is_bounded is False + assert (1024*sin(x)).is_bounded is True assert (sin(x)*exp(x)).is_bounded is not True - assert (sin(x)*cos(x)).is_bounded == True + assert (sin(x)*cos(x)).is_bounded is True assert (x*sin(x)*exp(x)).is_bounded is not True - assert (sin(x)-67).is_bounded == True - assert (sin(x)+exp(x)).is_bounded is not True + assert (sin(x) - 67).is_bounded is True + assert (sin(x) + exp(x)).is_bounded is not True assert (1 + x).is_bounded is False assert (1 + x**2 + (1 + x)*(1 - x)).is_bounded is None assert (sqrt(2)*(1 + x)).is_bounded is False assert (sqrt(2)*(1 + x)*(1 - x)).is_bounded is False + def test_Mul_is_even_odd(): x = Symbol('x', integer=True) @@ -399,36 +378,53 @@ n = Symbol('n', odd=True) m = Symbol('m', even=True) - assert (2*x).is_even == True - assert (2*x).is_odd == False + assert (2*x).is_even is True + assert (2*x).is_odd is False + + assert (3*x).is_even is None + assert (3*x).is_odd is None + + assert (k/3).is_integer is None + assert (k/3).is_even is None + assert (k/3).is_odd is None + + assert (2*n).is_even is True + assert (2*n).is_odd is False - assert (3*x).is_even == None - assert (3*x).is_odd == None + assert (2*m).is_even is True + assert (2*m).is_odd is False - assert (k/3).is_integer == False - assert (k/3).is_even == False - assert (k/3).is_odd == False + assert (-n).is_even is False + assert (-n).is_odd is True - assert (2*n).is_even == True - assert (2*n).is_odd == False + assert (k*n).is_even is False + assert (k*n).is_odd is True - assert (2*m).is_even == True - assert (2*m).is_odd == False + assert (k*m).is_even is True + assert (k*m).is_odd is False - assert (-n).is_even == False - assert (-n).is_odd == True + assert (k*n*m).is_even is True + assert (k*n*m).is_odd is False - assert (k*n).is_even == False - assert (k*n).is_odd == True + assert (k*m*x).is_even is True + assert (k*m*x).is_odd is False - assert (k*m).is_even == True - assert (k*m).is_odd == False + # issue 3692: + assert (x/2).is_integer is None + assert (k/2).is_integer is False + assert (m/2).is_integer is True - assert (k*n*m).is_even == True - assert (k*n*m).is_odd == False - assert (k*m*x).is_even == True - assert (k*m*x).is_odd == False +def test_Mul_is_rational(): + x = Symbol('x') + n = Symbol('n', integer=True) + m = Symbol('m', integer=True) + + assert (n/m).is_rational is True + assert (x/pi).is_rational is None + assert (x/n).is_rational is None + assert (n/pi).is_rational is False + def test_Add_is_even_odd(): x = Symbol('x', integer=True) @@ -437,29 +433,30 @@ n = Symbol('n', odd=True) m = Symbol('m', even=True) - assert (k+7).is_even == True - assert (k+7).is_odd == False + assert (k + 7).is_even is True + assert (k + 7).is_odd is False + + assert (-k + 7).is_even is True + assert (-k + 7).is_odd is False - assert (-k+7).is_even == True - assert (-k+7).is_odd == False + assert (k - 12).is_even is False + assert (k - 12).is_odd is True - assert (k-12).is_even == False - assert (k-12).is_odd == True + assert (-k - 12).is_even is False + assert (-k - 12).is_odd is True - assert (-k-12).is_even == False - assert (-k-12).is_odd == True + assert (k + n).is_even is True + assert (k + n).is_odd is False - assert (k+n).is_even == True - assert (k+n).is_odd == False + assert (k + m).is_even is False + assert (k + m).is_odd is True - assert (k+m).is_even == False - assert (k+m).is_odd == True + assert (k + n + m).is_even is True + assert (k + n + m).is_odd is False - assert (k+n+m).is_even == True - assert (k+n+m).is_odd == False + assert (k + n + x + m).is_even is None + assert (k + n + x + m).is_odd is None - assert (k+n+x+m).is_even == None - assert (k+n+x+m).is_odd == None def test_Mul_is_negative_positive(): x = Symbol('x', real=True) @@ -470,94 +467,95 @@ nneg = Symbol('nneg', nonnegative=True) npos = Symbol('npos', nonpositive=True) - assert neg.is_negative == True - assert (-neg).is_negative == False - assert (2*neg).is_negative == True + assert neg.is_negative is True + assert (-neg).is_negative is False + assert (2*neg).is_negative is True + + assert (2*pos)._eval_is_negative() is False + assert (2*pos).is_negative is False - assert (2*pos)._eval_is_negative() == False - assert (2*pos).is_negative == False + assert pos.is_negative is False + assert (-pos).is_negative is True + assert (2*pos).is_negative is False - assert pos.is_negative == False - assert (-pos).is_negative == True - assert (2*pos).is_negative == False + assert (pos*neg).is_negative is True + assert (2*pos*neg).is_negative is True + assert (-pos*neg).is_negative is False + assert (pos*neg*y).is_negative is False # y.is_real=F; !real -> !neg - assert (pos*neg).is_negative == True - assert (2*pos*neg).is_negative == True - assert (-pos*neg).is_negative == False - assert (pos*neg*y).is_negative == False # y.is_real=F; !real -> !neg + assert nneg.is_negative is False + assert (-nneg).is_negative is None + assert (2*nneg).is_negative is False - assert nneg.is_negative == False - assert (-nneg).is_negative == None - assert (2*nneg).is_negative == False + assert npos.is_negative is None + assert (-npos).is_negative is False + assert (2*npos).is_negative is None - assert npos.is_negative == None - assert (-npos).is_negative == False - assert (2*npos).is_negative == None + assert (nneg*npos).is_negative is None - assert (nneg*npos).is_negative == None + assert (neg*nneg).is_negative is None + assert (neg*npos).is_negative is False - assert (neg*nneg).is_negative == None - assert (neg*npos).is_negative == False + assert (pos*nneg).is_negative is False + assert (pos*npos).is_negative is None - assert (pos*nneg).is_negative == False - assert (pos*npos).is_negative == None + assert (npos*neg*nneg).is_negative is False + assert (npos*pos*nneg).is_negative is None - assert (npos*neg*nneg).is_negative == False - assert (npos*pos*nneg).is_negative == None + assert (-npos*neg*nneg).is_negative is None + assert (-npos*pos*nneg).is_negative is False - assert (-npos*neg*nneg).is_negative == None - assert (-npos*pos*nneg).is_negative == False + assert (17*npos*neg*nneg).is_negative is False + assert (17*npos*pos*nneg).is_negative is None - assert (17*npos*neg*nneg).is_negative == False - assert (17*npos*pos*nneg).is_negative == None + assert (neg*npos*pos*nneg).is_negative is False - assert (neg*npos*pos*nneg).is_negative == False + assert (x*neg).is_negative is None + assert (nneg*npos*pos*x*neg).is_negative is None - assert (x*neg).is_negative == None - assert (nneg*npos*pos*x*neg).is_negative == None + assert neg.is_positive is False + assert (-neg).is_positive is True + assert (2*neg).is_positive is False - assert neg.is_positive == False - assert (-neg).is_positive == True - assert (2*neg).is_positive == False + assert pos.is_positive is True + assert (-pos).is_positive is False + assert (2*pos).is_positive is True - assert pos.is_positive == True - assert (-pos).is_positive == False - assert (2*pos).is_positive == True + assert (pos*neg).is_positive is False + assert (2*pos*neg).is_positive is False + assert (-pos*neg).is_positive is True + assert (-pos*neg*y).is_positive is False # y.is_real=F; !real -> !neg - assert (pos*neg).is_positive == False - assert (2*pos*neg).is_positive == False - assert (-pos*neg).is_positive == True - assert (-pos*neg*y).is_positive == False # y.is_real=F; !real -> !neg + assert nneg.is_positive is None + assert (-nneg).is_positive is False + assert (2*nneg).is_positive is None - assert nneg.is_positive == None - assert (-nneg).is_positive == False - assert (2*nneg).is_positive == None + assert npos.is_positive is False + assert (-npos).is_positive is None + assert (2*npos).is_positive is False - assert npos.is_positive == False - assert (-npos).is_positive == None - assert (2*npos).is_positive == False + assert (nneg*npos).is_positive is False - assert (nneg*npos).is_positive == False + assert (neg*nneg).is_positive is False + assert (neg*npos).is_positive is None - assert (neg*nneg).is_positive == False - assert (neg*npos).is_positive == None + assert (pos*nneg).is_positive is None + assert (pos*npos).is_positive is False - assert (pos*nneg).is_positive == None - assert (pos*npos).is_positive == False + assert (npos*neg*nneg).is_positive is None + assert (npos*pos*nneg).is_positive is False - assert (npos*neg*nneg).is_positive == None - assert (npos*pos*nneg).is_positive == False + assert (-npos*neg*nneg).is_positive is False + assert (-npos*pos*nneg).is_positive is None - assert (-npos*neg*nneg).is_positive == False - assert (-npos*pos*nneg).is_positive == None + assert (17*npos*neg*nneg).is_positive is None + assert (17*npos*pos*nneg).is_positive is False - assert (17*npos*neg*nneg).is_positive == None - assert (17*npos*pos*nneg).is_positive == False + assert (neg*npos*pos*nneg).is_positive is None - assert (neg*npos*pos*nneg).is_positive == None + assert (x*neg).is_positive is None + assert (nneg*npos*pos*x*neg).is_positive is None - assert (x*neg).is_positive == None - assert (nneg*npos*pos*x*neg).is_positive == None def test_Mul_is_negative_positive_2(): a = Symbol('a', nonnegative=True) @@ -565,20 +563,20 @@ c = Symbol('c', nonpositive=True) d = Symbol('d', nonpositive=True) - assert (a*b).is_nonnegative == True - assert (a*b).is_negative == False - assert (a*b).is_zero == None - assert (a*b).is_positive == None - - assert (c*d).is_nonnegative == True - assert (c*d).is_negative == False - assert (c*d).is_zero == None - assert (c*d).is_positive == None - - assert (a*c).is_nonpositive == True - assert (a*c).is_positive == False - assert (a*c).is_zero == None - assert (a*c).is_negative == None + assert (a*b).is_nonnegative is True + assert (a*b).is_negative is False + assert (a*b).is_zero is None + assert (a*b).is_positive is None + + assert (c*d).is_nonnegative is True + assert (c*d).is_negative is False + assert (c*d).is_zero is None + assert (c*d).is_positive is None + + assert (a*c).is_nonpositive is True + assert (a*c).is_positive is False + assert (a*c).is_zero is None + assert (a*c).is_negative is None def test_Mul_is_nonpositive_nonnegative(): @@ -589,89 +587,90 @@ u = Symbol('u', nonnegative=True) v = Symbol('v', nonpositive=True) - assert k.is_nonpositive == True - assert (-k).is_nonpositive == False - assert (2*k).is_nonpositive == True + assert k.is_nonpositive is True + assert (-k).is_nonpositive is False + assert (2*k).is_nonpositive is True - assert n.is_nonpositive == False - assert (-n).is_nonpositive == True - assert (2*n).is_nonpositive == False + assert n.is_nonpositive is False + assert (-n).is_nonpositive is True + assert (2*n).is_nonpositive is False - assert (n*k).is_nonpositive == True - assert (2*n*k).is_nonpositive == True - assert (-n*k).is_nonpositive == False + assert (n*k).is_nonpositive is True + assert (2*n*k).is_nonpositive is True + assert (-n*k).is_nonpositive is False - assert u.is_nonpositive == None - assert (-u).is_nonpositive == True - assert (2*u).is_nonpositive == None + assert u.is_nonpositive is None + assert (-u).is_nonpositive is True + assert (2*u).is_nonpositive is None - assert v.is_nonpositive == True - assert (-v).is_nonpositive == None - assert (2*v).is_nonpositive == True + assert v.is_nonpositive is True + assert (-v).is_nonpositive is None + assert (2*v).is_nonpositive is True - assert (u*v).is_nonpositive == True + assert (u*v).is_nonpositive is True - assert (k*u).is_nonpositive == True - assert (k*v).is_nonpositive == None + assert (k*u).is_nonpositive is True + assert (k*v).is_nonpositive is None - assert (n*u).is_nonpositive == None - assert (n*v).is_nonpositive == True + assert (n*u).is_nonpositive is None + assert (n*v).is_nonpositive is True - assert (v*k*u).is_nonpositive == None - assert (v*n*u).is_nonpositive == True + assert (v*k*u).is_nonpositive is None + assert (v*n*u).is_nonpositive is True - assert (-v*k*u).is_nonpositive == True - assert (-v*n*u).is_nonpositive == None + assert (-v*k*u).is_nonpositive is True + assert (-v*n*u).is_nonpositive is None - assert (17*v*k*u).is_nonpositive == None - assert (17*v*n*u).is_nonpositive == True + assert (17*v*k*u).is_nonpositive is None + assert (17*v*n*u).is_nonpositive is True - assert (k*v*n*u).is_nonpositive == None + assert (k*v*n*u).is_nonpositive is None - assert (x*k).is_nonpositive == None - assert (u*v*n*x*k).is_nonpositive == None + assert (x*k).is_nonpositive is None + assert (u*v*n*x*k).is_nonpositive is None - assert k.is_nonnegative == False - assert (-k).is_nonnegative == True - assert (2*k).is_nonnegative == False + assert k.is_nonnegative is False + assert (-k).is_nonnegative is True + assert (2*k).is_nonnegative is False - assert n.is_nonnegative == True - assert (-n).is_nonnegative == False - assert (2*n).is_nonnegative == True + assert n.is_nonnegative is True + assert (-n).is_nonnegative is False + assert (2*n).is_nonnegative is True - assert (n*k).is_nonnegative == False - assert (2*n*k).is_nonnegative == False - assert (-n*k).is_nonnegative == True + assert (n*k).is_nonnegative is False + assert (2*n*k).is_nonnegative is False + assert (-n*k).is_nonnegative is True - assert u.is_nonnegative == True - assert (-u).is_nonnegative == None - assert (2*u).is_nonnegative == True + assert u.is_nonnegative is True + assert (-u).is_nonnegative is None + assert (2*u).is_nonnegative is True - assert v.is_nonnegative == None - assert (-v).is_nonnegative == True - assert (2*v).is_nonnegative == None + assert v.is_nonnegative is None + assert (-v).is_nonnegative is True + assert (2*v).is_nonnegative is None - assert (u*v).is_nonnegative == None + assert (u*v).is_nonnegative is None - assert (k*u).is_nonnegative == None - assert (k*v).is_nonnegative == True + assert (k*u).is_nonnegative is None + assert (k*v).is_nonnegative is True - assert (n*u).is_nonnegative == True - assert (n*v).is_nonnegative == None + assert (n*u).is_nonnegative is True + assert (n*v).is_nonnegative is None - assert (v*k*u).is_nonnegative == True - assert (v*n*u).is_nonnegative == None + assert (v*k*u).is_nonnegative is True + assert (v*n*u).is_nonnegative is None - assert (-v*k*u).is_nonnegative == None - assert (-v*n*u).is_nonnegative == True + assert (-v*k*u).is_nonnegative is None + assert (-v*n*u).is_nonnegative is True - assert (17*v*k*u).is_nonnegative == True - assert (17*v*n*u).is_nonnegative == None + assert (17*v*k*u).is_nonnegative is True + assert (17*v*n*u).is_nonnegative is None - assert (k*v*n*u).is_nonnegative == True + assert (k*v*n*u).is_nonnegative is True + + assert (x*k).is_nonnegative is None + assert (u*v*n*x*k).is_nonnegative is None - assert (x*k).is_nonnegative == None - assert (u*v*n*x*k).is_nonnegative == None def test_Add_is_negative_positive(): x = Symbol('x', real=True) @@ -681,77 +680,78 @@ u = Symbol('u', nonnegative=True) v = Symbol('v', nonpositive=True) - assert (k-2).is_negative == True - assert (k+17).is_negative == None - assert (-k-5).is_negative == None - assert (-k+123).is_negative == False - - assert (k-n).is_negative == True - assert (k+n).is_negative == None - assert (-k-n).is_negative == None - assert (-k+n).is_negative == False - - assert (k-n-2).is_negative == True - assert (k+n+17).is_negative == None - assert (-k-n-5).is_negative == None - assert (-k+n+123).is_negative == False - - assert (-2*k+123*n+17).is_negative == False - - assert (k+u).is_negative == None - assert (k+v).is_negative == True - assert (n+u).is_negative == False - assert (n+v).is_negative == None - - assert (u-v).is_negative == False - assert (u+v).is_negative == None - assert (-u-v).is_negative == None - assert (-u+v).is_negative == None - - assert (u-v+n+2).is_negative == False - assert (u+v+n+2).is_negative == None - assert (-u-v+n+2).is_negative == None - assert (-u+v+n+2).is_negative == None - - assert (k+x).is_negative == None - assert (k+x-n).is_negative == None - - assert (k-2).is_positive == False - assert (k+17).is_positive == None - assert (-k-5).is_positive == None - assert (-k+123).is_positive == True - - assert (k-n).is_positive == False - assert (k+n).is_positive == None - assert (-k-n).is_positive == None - assert (-k+n).is_positive == True - - assert (k-n-2).is_positive == False - assert (k+n+17).is_positive == None - assert (-k-n-5).is_positive == None - assert (-k+n+123).is_positive == True - - assert (-2*k+123*n+17).is_positive == True - - assert (k+u).is_positive == None - assert (k+v).is_positive == False - assert (n+u).is_positive == True - assert (n+v).is_positive == None - - assert (u-v).is_positive == None - assert (u+v).is_positive == None - assert (-u-v).is_positive == None - assert (-u+v).is_positive == False - - assert (u-v-n-2).is_positive == None - assert (u+v-n-2).is_positive == None - assert (-u-v-n-2).is_positive == None - assert (-u+v-n-2).is_positive == False + assert (k - 2).is_negative is True + assert (k + 17).is_negative is None + assert (-k - 5).is_negative is None + assert (-k + 123).is_negative is False + + assert (k - n).is_negative is True + assert (k + n).is_negative is None + assert (-k - n).is_negative is None + assert (-k + n).is_negative is False + + assert (k - n - 2).is_negative is True + assert (k + n + 17).is_negative is None + assert (-k - n - 5).is_negative is None + assert (-k + n + 123).is_negative is False + + assert (-2*k + 123*n + 17).is_negative is False + + assert (k + u).is_negative is None + assert (k + v).is_negative is True + assert (n + u).is_negative is False + assert (n + v).is_negative is None + + assert (u - v).is_negative is False + assert (u + v).is_negative is None + assert (-u - v).is_negative is None + assert (-u + v).is_negative is None + + assert (u - v + n + 2).is_negative is False + assert (u + v + n + 2).is_negative is None + assert (-u - v + n + 2).is_negative is None + assert (-u + v + n + 2).is_negative is None + + assert (k + x).is_negative is None + assert (k + x - n).is_negative is None + + assert (k - 2).is_positive is False + assert (k + 17).is_positive is None + assert (-k - 5).is_positive is None + assert (-k + 123).is_positive is True + + assert (k - n).is_positive is False + assert (k + n).is_positive is None + assert (-k - n).is_positive is None + assert (-k + n).is_positive is True + + assert (k - n - 2).is_positive is False + assert (k + n + 17).is_positive is None + assert (-k - n - 5).is_positive is None + assert (-k + n + 123).is_positive is True + + assert (-2*k + 123*n + 17).is_positive is True + + assert (k + u).is_positive is None + assert (k + v).is_positive is False + assert (n + u).is_positive is True + assert (n + v).is_positive is None + + assert (u - v).is_positive is None + assert (u + v).is_positive is None + assert (-u - v).is_positive is None + assert (-u + v).is_positive is False + + assert (u - v - n - 2).is_positive is None + assert (u + v - n - 2).is_positive is None + assert (-u - v - n - 2).is_positive is None + assert (-u + v - n - 2).is_positive is False + + assert (n + x).is_positive is None + assert (n + x - k).is_positive is None - assert (n+x).is_positive == None - assert (n+x-k).is_positive == None + assert (-3 - sqrt(5) + (-sqrt(10)/2 - sqrt(2)/2)**2).is_zero is not False - assert (-3 - sqrt(5) + (-sqrt(10)/2 - sqrt(2)/2)**2).is_zero != False def test_Add_is_nonpositive_nonnegative(): x = Symbol('x', real=True) @@ -761,75 +761,76 @@ u = Symbol('u', nonnegative=True) v = Symbol('v', nonpositive=True) - assert (u-2).is_nonpositive == None - assert (u+17).is_nonpositive == False - assert (-u-5).is_nonpositive == True - assert (-u+123).is_nonpositive == None - - assert (u-v).is_nonpositive == None - assert (u+v).is_nonpositive == None - assert (-u-v).is_nonpositive == None - assert (-u+v).is_nonpositive == True - - assert (u-v-2).is_nonpositive == None - assert (u+v+17).is_nonpositive == None - assert (-u-v-5).is_nonpositive == None - assert (-u+v-123).is_nonpositive == True - - assert (-2*u+123*v-17).is_nonpositive == True - - assert (k+u).is_nonpositive == None - assert (k+v).is_nonpositive == True - assert (n+u).is_nonpositive == False - assert (n+v).is_nonpositive == None - - assert (k-n).is_nonpositive == True - assert (k+n).is_nonpositive == None - assert (-k-n).is_nonpositive == None - assert (-k+n).is_nonpositive == False - - assert (k-n+u+2).is_nonpositive == None - assert (k+n+u+2).is_nonpositive == None - assert (-k-n+u+2).is_nonpositive == None - assert (-k+n+u+2).is_nonpositive == False - - assert (u+x).is_nonpositive == None - assert (v-x-n).is_nonpositive == None - - assert (u-2).is_nonnegative == None - assert (u+17).is_nonnegative == True - assert (-u-5).is_nonnegative == False - assert (-u+123).is_nonnegative == None - - assert (u-v).is_nonnegative == True - assert (u+v).is_nonnegative == None - assert (-u-v).is_nonnegative == None - assert (-u+v).is_nonnegative == None - - assert (u-v+2).is_nonnegative == True - assert (u+v+17).is_nonnegative == None - assert (-u-v-5).is_nonnegative == None - assert (-u+v-123).is_nonnegative == False - - assert (2*u-123*v+17).is_nonnegative == True - - assert (k+u).is_nonnegative == None - assert (k+v).is_nonnegative == False - assert (n+u).is_nonnegative == True - assert (n+v).is_nonnegative == None - - assert (k-n).is_nonnegative == False - assert (k+n).is_nonnegative == None - assert (-k-n).is_nonnegative == None - assert (-k+n).is_nonnegative == True - - assert (k-n-u-2).is_nonnegative == False - assert (k+n-u-2).is_nonnegative == None - assert (-k-n-u-2).is_nonnegative == None - assert (-k+n-u-2).is_nonnegative == None + assert (u - 2).is_nonpositive is None + assert (u + 17).is_nonpositive is False + assert (-u - 5).is_nonpositive is True + assert (-u + 123).is_nonpositive is None + + assert (u - v).is_nonpositive is None + assert (u + v).is_nonpositive is None + assert (-u - v).is_nonpositive is None + assert (-u + v).is_nonpositive is True + + assert (u - v - 2).is_nonpositive is None + assert (u + v + 17).is_nonpositive is None + assert (-u - v - 5).is_nonpositive is None + assert (-u + v - 123).is_nonpositive is True + + assert (-2*u + 123*v - 17).is_nonpositive is True + + assert (k + u).is_nonpositive is None + assert (k + v).is_nonpositive is True + assert (n + u).is_nonpositive is False + assert (n + v).is_nonpositive is None + + assert (k - n).is_nonpositive is True + assert (k + n).is_nonpositive is None + assert (-k - n).is_nonpositive is None + assert (-k + n).is_nonpositive is False + + assert (k - n + u + 2).is_nonpositive is None + assert (k + n + u + 2).is_nonpositive is None + assert (-k - n + u + 2).is_nonpositive is None + assert (-k + n + u + 2).is_nonpositive is False + + assert (u + x).is_nonpositive is None + assert (v - x - n).is_nonpositive is None + + assert (u - 2).is_nonnegative is None + assert (u + 17).is_nonnegative is True + assert (-u - 5).is_nonnegative is False + assert (-u + 123).is_nonnegative is None + + assert (u - v).is_nonnegative is True + assert (u + v).is_nonnegative is None + assert (-u - v).is_nonnegative is None + assert (-u + v).is_nonnegative is None + + assert (u - v + 2).is_nonnegative is True + assert (u + v + 17).is_nonnegative is None + assert (-u - v - 5).is_nonnegative is None + assert (-u + v - 123).is_nonnegative is False + + assert (2*u - 123*v + 17).is_nonnegative is True + + assert (k + u).is_nonnegative is None + assert (k + v).is_nonnegative is False + assert (n + u).is_nonnegative is True + assert (n + v).is_nonnegative is None + + assert (k - n).is_nonnegative is False + assert (k + n).is_nonnegative is None + assert (-k - n).is_nonnegative is None + assert (-k + n).is_nonnegative is True + + assert (k - n - u - 2).is_nonnegative is False + assert (k + n - u - 2).is_nonnegative is None + assert (-k - n - u - 2).is_nonnegative is None + assert (-k + n - u - 2).is_nonnegative is None + + assert (u - x).is_nonnegative is None + assert (v + x + n).is_nonnegative is None - assert (u-x).is_nonnegative == None - assert (v+x+n).is_nonnegative == None def test_Pow_is_integer(): x = Symbol('x') @@ -838,29 +839,29 @@ n = Symbol('n', integer=True, nonnegative=True) m = Symbol('m', integer=True, positive=True) - assert (k**2).is_integer == True - assert (k**(-2)).is_integer == False + assert (k**2).is_integer is True + assert (k**(-2)).is_integer is False - assert (2**k).is_integer == None - assert (2**(-k)).is_integer == None + assert (2**k).is_integer is None + assert (2**(-k)).is_integer is None - assert (2**n).is_integer == True - assert (2**(-n)).is_integer == None + assert (2**n).is_integer is True + assert (2**(-n)).is_integer is None - assert (2**m).is_integer == True - assert (2**(-m)).is_integer == False + assert (2**m).is_integer is True + assert (2**(-m)).is_integer is False - assert (x**2).is_integer == None - assert (2**x).is_integer == None + assert (x**2).is_integer is None + assert (2**x).is_integer is None - assert (k**n).is_integer == True - assert (k**(-n)).is_integer == None + assert (k**n).is_integer is True + assert (k**(-n)).is_integer is None - assert (k**x).is_integer == None - assert (x**k).is_integer == None + assert (k**x).is_integer is None + assert (x**k).is_integer is None - assert (k**(n*m)).is_integer == True - assert (k**(-n*m)).is_integer == None + assert (k**(n*m)).is_integer is True + assert (k**(-n*m)).is_integer is None assert sqrt(3).is_integer is False assert sqrt(.3).is_integer is False @@ -874,30 +875,31 @@ assert Pow(4, S.Half, evaluate=False).is_integer is True assert Pow(S.Half, -2, evaluate=False).is_integer is True + def test_Pow_is_real(): x = Symbol('x', real=True) y = Symbol('y', real=True, positive=True) - assert (x**2).is_real == True - assert (x**3).is_real == True - assert (x**x).is_real == None - assert (y**x).is_real == True + assert (x**2).is_real is True + assert (x**3).is_real is True + assert (x**x).is_real is None + assert (y**x).is_real is True - assert (x**Rational(1,3)).is_real == None - assert (y**Rational(1,3)).is_real == True + assert (x**Rational(1, 3)).is_real is None + assert (y**Rational(1, 3)).is_real is True - assert sqrt(-1 - sqrt(2)).is_real == False + assert sqrt(-1 - sqrt(2)).is_real is False i = Symbol('i', imaginary=True) assert (i**i).is_real is None assert (I**i).is_real is None assert ((-I)**i).is_real is None - assert (2**i).is_real is None # (2**(pi/log(2) * I)) is real, 2**I is not + assert (2**i).is_real is None # (2**(pi/log(2) * I)) is real, 2**I is not assert (2**I).is_real is False assert (2**-I).is_real is False assert (i**2).is_real assert (i**3).is_real is False - assert (i**x).is_real is None # could be (-I)**(2/3) + assert (i**x).is_real is None # could be (-I)**(2/3) e = Symbol('e', even=True) o = Symbol('o', odd=True) k = Symbol('k', integer=True) @@ -905,6 +907,7 @@ assert (i**o).is_real is False assert (i**k).is_real is None + @XFAIL def test_real_Pow(): """ @@ -914,21 +917,23 @@ k = Symbol('k', integer=True, nonzero=True) assert (k**(I*pi/log(k))).is_real + def test_Pow_is_bounded(): x = Symbol('x', real=True) p = Symbol('p', positive=True) n = Symbol('n', negative=True) - assert (x**2).is_bounded == None # x could be oo - assert (x**x).is_bounded == None # ditto - assert (p**x).is_bounded == None # ditto - assert (n**x).is_bounded == None # ditto + assert (x**2).is_bounded is None # x could be oo + assert (x**x).is_bounded is None # ditto + assert (p**x).is_bounded is None # ditto + assert (n**x).is_bounded is None # ditto assert (1/S.Pi).is_bounded - assert (sin(x)**2).is_bounded == True - assert (sin(x)**x).is_bounded == None - assert (sin(x)**exp(x)).is_bounded == None - assert (1/sin(x)).is_bounded == None # if zero, no, otherwise yes - assert (1/exp(x)).is_bounded == None # x could be -oo + assert (sin(x)**2).is_bounded is True + assert (sin(x)**x).is_bounded is None + assert (sin(x)**exp(x)).is_bounded is None + assert (1/sin(x)).is_bounded is None # if zero, no, otherwise yes + assert (1/exp(x)).is_bounded is None # x could be -oo + def test_Pow_is_even_odd(): x = Symbol('x') @@ -938,44 +943,45 @@ m = Symbol('m', integer=True, nonnegative=True) p = Symbol('p', integer=True, positive=True) - assert (k**2).is_even == True - assert (n**2).is_even == False - assert (2**k).is_even == None - assert (x**2).is_even == None + assert (k**2).is_even is True + assert (n**2).is_even is False + assert (2**k).is_even is None + assert (x**2).is_even is None + + assert (k**m).is_even is None + assert (n**m).is_even is False - assert (k**m).is_even == None - assert (n**m).is_even == False + assert (k**p).is_even is True + assert (n**p).is_even is False - assert (k**p).is_even == True - assert (n**p).is_even == False + assert (m**k).is_even is None + assert (p**k).is_even is None - assert (m**k).is_even == None - assert (p**k).is_even == None + assert (m**n).is_even is None + assert (p**n).is_even is None - assert (m**n).is_even == None - assert (p**n).is_even == None + assert (k**x).is_even is None + assert (n**x).is_even is None - assert (k**x).is_even == None - assert (n**x).is_even == None + assert (k**2).is_odd is False + assert (n**2).is_odd is True + assert (3**k).is_odd is None - assert (k**2).is_odd == False - assert (n**2).is_odd == True - assert (3**k).is_odd == None + assert (k**m).is_odd is None + assert (n**m).is_odd is True - assert (k**m).is_odd == None - assert (n**m).is_odd == True + assert (k**p).is_odd is False + assert (n**p).is_odd is True - assert (k**p).is_odd == False - assert (n**p).is_odd == True + assert (m**k).is_odd is None + assert (p**k).is_odd is None - assert (m**k).is_odd == None - assert (p**k).is_odd == None + assert (m**n).is_odd is None + assert (p**n).is_odd is None - assert (m**n).is_odd == None - assert (p**n).is_odd == None + assert (k**x).is_odd is None + assert (n**x).is_odd is None - assert (k**x).is_odd == None - assert (n**x).is_odd == None def test_Pow_is_negative_positive(): x = Symbol('x', real=True) @@ -986,34 +992,35 @@ z = Symbol('z') - assert (2**x).is_positive == True - assert ((-2)**x).is_positive == None - assert ((-2)**n).is_positive == True - assert ((-2)**m).is_positive == False - - assert (k**2).is_positive == True - assert (k**(-2)).is_positive == True - - assert (k**x).is_positive == True - assert ((-k)**x).is_positive == None - assert ((-k)**n).is_positive == True - assert ((-k)**m).is_positive == False - - assert (2**x).is_negative == False - assert ((-2)**x).is_negative == None - assert ((-2)**n).is_negative == False - assert ((-2)**m).is_negative == True - - assert (k**2).is_negative == False - assert (k**(-2)).is_negative == False - - assert (k**x).is_negative == False - assert ((-k)**x).is_negative == None - assert ((-k)**n).is_negative == False - assert ((-k)**m).is_negative == True + assert (2**x).is_positive is True + assert ((-2)**x).is_positive is None + assert ((-2)**n).is_positive is True + assert ((-2)**m).is_positive is False + + assert (k**2).is_positive is True + assert (k**(-2)).is_positive is True + + assert (k**x).is_positive is True + assert ((-k)**x).is_positive is None + assert ((-k)**n).is_positive is True + assert ((-k)**m).is_positive is False + + assert (2**x).is_negative is False + assert ((-2)**x).is_negative is None + assert ((-2)**n).is_negative is False + assert ((-2)**m).is_negative is True + + assert (k**2).is_negative is False + assert (k**(-2)).is_negative is False + + assert (k**x).is_negative is False + assert ((-k)**x).is_negative is None + assert ((-k)**n).is_negative is False + assert ((-k)**m).is_negative is True + + assert (2**z).is_positive is None + assert (2**z).is_negative is None - assert (2**z).is_positive == None - assert (2**z).is_negative == None def test_Pow_is_nonpositive_nonnegative(): x = Symbol('x', real=True) @@ -1023,99 +1030,100 @@ n = Symbol('n', even=True) m = Symbol('m', odd=True) - assert (2**x).is_nonnegative == True - assert ((-2)**x).is_nonnegative == None - assert ((-2)**n).is_nonnegative == True - assert ((-2)**m).is_nonnegative == False - - assert (k**2).is_nonnegative == True - assert (k**(-2)).is_nonnegative == True - - assert (k**x).is_nonnegative == None # NOTE (0**x).is_real = U - assert (l**x).is_nonnegative == True - assert (l**x).is_positive == True - assert ((-k)**x).is_nonnegative == None - assert ((-k)**n).is_nonnegative == True - assert ((-k)**m).is_nonnegative == None - - assert (2**x).is_nonpositive == False - assert ((-2)**x).is_nonpositive == None - assert ((-2)**n).is_nonpositive == False - assert ((-2)**m).is_nonpositive == True - - assert (k**2).is_nonpositive == None - assert (k**(-2)).is_nonpositive == None - - assert (k**x).is_nonpositive == None - assert ((-k)**x).is_nonpositive == None - assert ((-k)**n).is_nonpositive == None - assert ((-k)**m).is_nonpositive == True + assert (2**x).is_nonnegative is True + assert ((-2)**x).is_nonnegative is None + assert ((-2)**n).is_nonnegative is True + assert ((-2)**m).is_nonnegative is False + + assert (k**2).is_nonnegative is True + assert (k**(-2)).is_nonnegative is True + + assert (k**x).is_nonnegative is None # NOTE (0**x).is_real = U + assert (l**x).is_nonnegative is True + assert (l**x).is_positive is True + assert ((-k)**x).is_nonnegative is None + assert ((-k)**n).is_nonnegative is True + assert ((-k)**m).is_nonnegative is None + + assert (2**x).is_nonpositive is False + assert ((-2)**x).is_nonpositive is None + assert ((-2)**n).is_nonpositive is False + assert ((-2)**m).is_nonpositive is True + + assert (k**2).is_nonpositive is None + assert (k**(-2)).is_nonpositive is None + + assert (k**x).is_nonpositive is None + assert ((-k)**x).is_nonpositive is None + assert ((-k)**n).is_nonpositive is None + assert ((-k)**m).is_nonpositive is True def test_Mul_is_imaginary_real(): r = Symbol('r', real=True) i = Symbol('i', imaginary=True) - ii= Symbol('ii',imaginary=True) + ii = Symbol('ii', imaginary=True) x = Symbol('x') - assert I .is_imaginary == True - assert I .is_real == False - assert (-I) .is_imaginary == True - assert (-I) .is_real == False - assert (3*I) .is_imaginary == True - assert (3*I) .is_real == False - assert (I*I) .is_imaginary == False - assert (I*I) .is_real == True - - assert (r*i) .is_imaginary == True - assert (r*i) .is_real == False + assert I.is_imaginary is True + assert I.is_real is False + assert (-I).is_imaginary is True + assert (-I).is_real is False + assert (3*I).is_imaginary is True + assert (3*I).is_real is False + assert (I*I).is_imaginary is False + assert (I*I).is_real is True + + assert (r*i).is_imaginary is True + assert (r*i).is_real is False - assert (x*i) .is_imaginary == None - assert (x*i) .is_real == None + assert (x*i).is_imaginary is None + assert (x*i).is_real is None - assert (i*ii).is_imaginary == False - assert (i*ii).is_real == True - - assert (r*i*ii).is_imaginary == False - assert (r*i*ii).is_real == True + assert (i*ii).is_imaginary is False + assert (i*ii).is_real is True + assert (r*i*ii).is_imaginary is False + assert (r*i*ii).is_real is True def test_Add_is_comparable(): - assert (x+y).is_comparable == False - assert (x+1).is_comparable == False - assert (Rational(1,3) - sqrt(8)).is_comparable == True + assert (x + y).is_comparable is False + assert (x + 1).is_comparable is False + assert (Rational(1, 3) - sqrt(8)).is_comparable is True + def test_Mul_is_comparable(): - assert (x*y).is_comparable == False - assert (x*2).is_comparable == False - assert (sqrt(2)*Rational(1,3)).is_comparable == True + assert (x*y).is_comparable is False + assert (x*2).is_comparable is False + assert (sqrt(2)*Rational(1, 3)).is_comparable is True def test_Pow_is_comparable(): - assert (x**y).is_comparable == False - assert (x**2).is_comparable == False - assert (sqrt(Rational(1,3))).is_comparable == True + assert (x**y).is_comparable is False + assert (x**2).is_comparable is False + assert (sqrt(Rational(1, 3))).is_comparable is True def test_Add_is_positive_2(): - e = Rational(1,3) - sqrt(8) - assert e.is_positive == False - assert e.is_negative == True + e = Rational(1, 3) - sqrt(8) + assert e.is_positive is False + assert e.is_negative is True e = pi - 1 - assert e.is_positive == True - assert e.is_negative == False + assert e.is_positive is True + assert e.is_negative is False def test_Add_is_irrational(): i = Symbol('i', irrational=True) - assert i.is_irrational == True - assert i.is_rational == False + assert i.is_irrational is True + assert i.is_rational is False + + assert (i + 1).is_irrational is True + assert (i + 1).is_rational is False - assert (i+1).is_irrational == True - assert (i+1).is_rational == False @XFAIL def test_issue432(): @@ -1125,20 +1133,24 @@ def __rtruediv__(self, other): return "something" - assert sympify(1)/MightyNumeric((1,2)) == "something" + assert sympify(1)/MightyNumeric((1, 2)) == "something" + def test_issue432b(): class Foo: def __init__(self): self.field = 1.0 + def __mul__(self, other): self.field = self.field * other + def __rmul__(self, other): self.field = other * self.field f = Foo() x = Symbol("x") assert f*x == x*f + def test_bug3(): a = Symbol("a") b = Symbol("b", positive=True) @@ -1146,50 +1158,54 @@ f = b + 2*a assert e == f + def test_suppressed_evaluation(): - a = Add(0,3,2,evaluate=False) - b = Mul(1,3,2,evaluate=False) - c = Pow(3,2,evaluate=False) + a = Add(0, 3, 2, evaluate=False) + b = Mul(1, 3, 2, evaluate=False) + c = Pow(3, 2, evaluate=False) assert a != 6 assert a.func is Add - assert a.args == (3,2) + assert a.args == (3, 2) assert b != 6 assert b.func is Mul - assert b.args == (3,2) + assert b.args == (3, 2) assert c != 9 assert c.func is Pow - assert c.args == (3,2) + assert c.args == (3, 2) def test_Add_as_coeff_mul(): # Issue 2425. These should all be (1, self) - assert (x + 1).as_coeff_mul() == (1, (x + 1,) ) - assert (x + 2).as_coeff_mul() == (1, (x + 2,) ) - assert (x + 3).as_coeff_mul() == (1, (x + 3,) ) - - assert (x - 1).as_coeff_mul() == (1, (x - 1,) ) - assert (x - 2).as_coeff_mul() == (1, (x - 2,) ) - assert (x - 3).as_coeff_mul() == (1, (x - 3,) ) + assert (x + 1).as_coeff_mul() == (1, (x + 1,)) + assert (x + 2).as_coeff_mul() == (1, (x + 2,)) + assert (x + 3).as_coeff_mul() == (1, (x + 3,)) + + assert (x - 1).as_coeff_mul() == (1, (x - 1,)) + assert (x - 2).as_coeff_mul() == (1, (x - 2,)) + assert (x - 3).as_coeff_mul() == (1, (x - 3,)) n = Symbol('n', integer=True) - assert (n + 1).as_coeff_mul() == (1, (n + 1,) ) - assert (n + 2).as_coeff_mul() == (1, (n + 2,) ) - assert (n + 3).as_coeff_mul() == (1, (n + 3,) ) - - assert (n - 1).as_coeff_mul() == (1, (n - 1,) ) - assert (n - 2).as_coeff_mul() == (1, (n - 2,) ) - assert (n - 3).as_coeff_mul() == (1, (n - 3,) ) + assert (n + 1).as_coeff_mul() == (1, (n + 1,)) + assert (n + 2).as_coeff_mul() == (1, (n + 2,)) + assert (n + 3).as_coeff_mul() == (1, (n + 3,)) + + assert (n - 1).as_coeff_mul() == (1, (n - 1,)) + assert (n - 2).as_coeff_mul() == (1, (n - 2,)) + assert (n - 3).as_coeff_mul() == (1, (n - 3,)) + def test_Pow_as_coeff_mul_doesnt_expand(): assert exp(x + y).as_coeff_mul() == (1, (exp(x + y),)) assert exp(x + exp(x + y)) != exp(x + exp(x)*exp(y)) + def test_issue415(): assert sqrt(S.Half) * sqrt(6) == 2 * sqrt(3)/2 assert S(1)/2*sqrt(6)*sqrt(2) == sqrt(3) assert sqrt(6)/2*sqrt(2) == sqrt(3) assert sqrt(6)*sqrt(2)/2 == sqrt(3) + def test_make_args(): assert Add.make_args(x) == (x,) assert Mul.make_args(x) == (x,) @@ -1197,23 +1213,26 @@ assert Add.make_args(x*y*z) == (x*y*z,) assert Mul.make_args(x*y*z) == (x*y*z).args - assert Add.make_args(x+y+z) == (x+y+z).args - assert Mul.make_args(x+y+z) == (x+y+z,) + assert Add.make_args(x + y + z) == (x + y + z).args + assert Mul.make_args(x + y + z) == (x + y + z,) + + assert Add.make_args((x + y)**z) == ((x + y)**z,) + assert Mul.make_args((x + y)**z) == ((x + y)**z,) - assert Add.make_args((x+y)**z) == ((x+y)**z,) - assert Mul.make_args((x+y)**z) == ((x+y)**z,) def test_issue2027(): assert (-2)**x*(-3)**x != 6**x i = Symbol('i', integer=1) assert (-2)**i*(-3)**i == 6**i + def test_Rational_as_content_primitive(): c, p = S(1), S(0) assert (c*p).as_content_primitive() == (c, p) c, p = S(1)/2, S(1) assert (c*p).as_content_primitive() == (c, p) + def test_Add_as_content_primitive(): assert (x + 2).as_content_primitive() == (1, x + 2) @@ -1229,8 +1248,10 @@ assert (3/x + 3*x*y*z**2).as_content_primitive() == (3, 1/x + x*y*z**2) assert (3/x + 6*x*y*z**2).as_content_primitive() == (3, 1/x + 2*x*y*z**2) - assert (2*x/3 + 4*y/9).as_content_primitive() == (Rational(2, 9), 3*x + 2*y) - assert (2*x/3 + 2.5*y).as_content_primitive() == (Rational(1, 3), 2*x + 7.5*y) + assert (2*x/3 + 4*y/9).as_content_primitive() == \ + (Rational(2, 9), 3*x + 2*y) + assert (2*x/3 + 2.5*y).as_content_primitive() == \ + (Rational(1, 3), 2*x + 7.5*y) # the coefficient may sort to a position other than 0 p = 3 + x + y @@ -1239,25 +1260,27 @@ p *= -1 assert (2*p).expand().as_content_primitive() == (2, p) + def test_Mul_as_content_primitive(): assert (2*x).as_content_primitive() == (2, x) - assert (x*(2+2*x)).as_content_primitive() == (2, x*(1 + x)) - assert (x*(2 + 2*y)*(3*x + 3)**2).as_content_primitive() == (18, x*(1 + y)*(x + 1)**2) - assert ((2+2*x)**2*(3+6*x)+S.Half).as_content_primitive() == (S.Half, 24*(x + 1)**2*(2*x + 1) + 1) + assert (x*(2 + 2*x)).as_content_primitive() == (2, x*(1 + x)) + assert (x*(2 + 2*y)*(3*x + 3)**2).as_content_primitive() == \ + (18, x*(1 + y)*(x + 1)**2) + assert ((2 + 2*x)**2*(3 + 6*x) + S.Half).as_content_primitive() == \ + (S.Half, 24*(x + 1)**2*(2*x + 1) + 1) + def test_Pow_as_content_primitive(): assert (x**y).as_content_primitive() == (1, x**y) - assert ((2*x + 2)**y).as_content_primitive() == (1, (Mul(2,(x + 1), evaluate=False))**y) + assert ((2*x + 2)**y).as_content_primitive() == \ + (1, (Mul(2, (x + 1), evaluate=False))**y) assert ((2*x + 2)**3).as_content_primitive() == (8, (x + 1)**3) + def test_issue2361(): u = Mul(2, (1 + x), evaluate=False) - assert 2 + u == 4 + 2*x - # the Number is only suppose to distribute on a commutative Add - n = Symbol('n', commutative=False) - u = 2*(1 + n) - assert u.is_Mul - assert 2 + u == 4 + 2*n + assert (2 + u).args == (2, u) + def test_product_irrational(): from sympy import I, pi @@ -1265,10 +1288,14 @@ # The following used to be deduced from the above bug: assert (I*pi).is_positive is False + def test_issue_2820(): assert (x/(y*(1 + y))).expand() == x/(y**2 + y) + def test_Mod(): + assert Mod(x, 1).func is Mod + assert pi % pi == S.Zero assert Mod(5, 3) == 2 assert Mod(-5, 3) == 1 assert Mod(5, -3) == -1 @@ -1278,22 +1305,84 @@ assert x % 5 == Mod(x, 5) assert x % y == Mod(x, y) assert (x % y).subs({x: 5, y: 3}) == 2 - assert (x + 3) % 1 == Mod(x, 1) - assert (x + 3.0) % 1 == Mod(x, 1) - assert (x - S(33)/10) % 1 == Mod(x + S(7)/10, 1) - assert (x - 3.3) % 1 == Mod(x + 0.7, 1) - assert Mod(-3.3, 1) == Mod(0.7, 1) == Float(0.7) + + # Float handling + point3 = Float(3.3) % 1 + assert (x - 3.3) % 1 == Mod(1.*x + 1 - point3, 1) + assert Mod(-3.3, 1) == 1 - point3 + assert Mod(0.7, 1) == Float(0.7) e = Mod(1.3, 1) - assert e == .3 and e.is_Float + point3 = Float._new(Float(.3)._mpf_, 51) + assert e == point3 and e.is_Float e = Mod(1.3, .7) - assert e == .6 and e.is_Float + point6 = Float._new(Float(.6)._mpf_, 51) + assert e == point6 and e.is_Float e = Mod(1.3, Rational(7, 10)) - assert e == .6 and e.is_Float + assert e == point6 and e.is_Float e = Mod(Rational(13, 10), 0.7) - assert e == .6 and e.is_Float + assert e == point6 and e.is_Float e = Mod(Rational(13, 10), Rational(7, 10)) assert e == .6 and e.is_Rational + # check that sign is right + r2 = sqrt(2) + r3 = sqrt(3) + for i in [-r3, -r2, r2, r3]: + for j in [-r3, -r2, r2, r3]: + assert test_numerically(i % j, i.n() % j.n()) + for _x in range(4): + for _y in range(9): + reps = [(x, _x), (y, _y)] + assert Mod(3*x + y, 9).subs(reps) == (3*_x + _y) % 9 + + # denesting + # easy case + assert Mod(Mod(x, y), y) == Mod(x, y) + # in case someone attempts more denesting + for i in [-3, -2, 2, 3]: + for j in [-3, -2, 2, 3]: + for k in range(3): + # print i, j, k + assert Mod(Mod(k, i), j) == (k % i) % j + + # known difference + assert Mod(5*sqrt(2), sqrt(5)) == 5*sqrt(2) - 3*sqrt(5) + p = symbols('p', positive=True) + assert Mod(p + 1, p + 3) == p + 1 + n = symbols('n', negative=True) + assert Mod(n - 3, n - 1) == -2 + assert Mod(n - 2*p, n - p) == -p + assert Mod(p - 2*n, p - n) == -n + + # handling sums + assert (x + 3) % 1 == Mod(x, 1) + assert (x + 3.0) % 1 == Mod(1.*x, 1) + assert (x - S(33)/10) % 1 == Mod(x + S(7)/10, 1) + assert str(Mod(.6*x + y, .3*y)) == str(Mod(0.1*y + 0.6*x, 0.3*y)) + assert (x + 1) % x == 1 % x + assert (x + y) % x == y % x + assert (x + y + 2) % x == (y + 2) % x + assert (a + 3*x + 1) % (2*x) == Mod(a + x + 1, 2*x) + assert (12*x + 18*y) % (3*x) == 3*Mod(6*y, x) + + # gcd extraction + assert (-3*x) % (-2*y) == -Mod(3*x, 2*y) + assert (.6*pi) % (.3*x*pi) == 0.3*pi*Mod(2, x) + assert (.6*pi) % (.31*x*pi) == pi*Mod(0.6, 0.31*x) + assert (6*pi) % (.3*x*pi) == pi*Mod(6, 0.3*x) + assert (6*pi) % (.31*x*pi) == pi*Mod(6, 0.31*x) + assert (6*pi) % (.42*x*pi) == pi*Mod(6, 0.42*x) + assert (12*x) % (2*y) == 2*Mod(6*x, y) + assert (12*x) % (3*5*y) == 3*Mod(4*x, 5*y) + assert (12*x) % (15*x*y) == 3*x*Mod(4, 5*y) + assert (-2*pi) % (3*pi) == pi + assert (2*x + 2) % (x + 1) == 0 + assert (x*(x + 1)) % (x + 1) == (x + 1)*Mod(x, 1) + assert Mod(5.0*x, 0.1*y) == 0.1*Mod(50*x, y) + i = Symbol('i', integer=True) + assert (3*i*x) % (2*i*y) == i*Mod(3*x, 2*y) + + def test_issue_2902(): A = Symbol("A", commutative=False) eq = A + A**2 @@ -1311,6 +1400,7 @@ assert (sqrt(2)*A).is_commutative is False assert (sqrt(2)*A*B).is_commutative is False + def test_polar(): from sympy import polar_lift p = Symbol('p', polar=True) @@ -1330,6 +1420,7 @@ assert (2*q)**2 == 4 * q**2 assert ((p*q)**x).expand() == p**x * q**x + def test_issue_2941(): a, b = Pow(1, 2, evaluate=False), S.One assert a != b @@ -1337,9 +1428,10 @@ assert not (a == b) assert not (b == a) + def test_issue_2983(): assert Max(x, 1) * Max(x, 2) == Max(x, 1) * Max(x, 2) - assert Or(x, z) * Or(x, z) == Or(x, z) * Or(x, z) + def test_issue_2978(): assert x**2.0/x == x**1.0 @@ -1352,6 +1444,7 @@ assert 2**x*2**(2.0*x) == 2**(3.0*x) assert 2**(1.5*x)*2**(2.5*x) == 2**(4.0*x) + def test_mul_flatten_oo(): p = symbols('p', positive=True) n, m = symbols('n,m', negative=True) @@ -1359,7 +1452,8 @@ assert n*oo == -oo assert n*m*oo == oo assert p*oo == oo - assert x_im*oo != I*oo # i could be +/- 3*I -> +/-oo + assert x_im*oo != I*oo # i could be +/- 3*I -> +/-oo + def test_issue_2061_2988_2990_2991(): #2988 @@ -1371,24 +1465,35 @@ assert (-2*B*C)**2 == 4*(B*C)**2 #2061 assert sqrt(-1.0*x) == 1.0*sqrt(-x) + assert sqrt(1.0*x) == 1.0*sqrt(x) #2991 assert (-2*x*y*A*B)**2 == 4*x**2*y**2*(A*B)**2 + def test_float_int(): assert int(float(sqrt(10))) == int(sqrt(10)) assert int(pi**1000) % 10 == 2 - assert int(Float('1.123456789012345678901234567890e20','')) == \ + assert int(Float('1.123456789012345678901234567890e20', '')) == \ 112345678901234567890 - assert int(Float('1.123456789012345678901234567890e25','')) == \ + assert int(Float('1.123456789012345678901234567890e25', '')) == \ 11234567890123456789012345 - assert int(Float('1.123456789012345678901234567890e35','')) == \ - 112345678901234567890123456789000000 - assert Integer(Float('1.123456789012345678901234567890e20','')) == \ + # decimal forces float so it's not an exact integer ending in 000000 + assert int(Float('1.123456789012345678901234567890e35', '')) == \ + 112345678901234567890123456789000192 + assert int(Float('123456789012345678901234567890e5', '')) == \ + 12345678901234567890123456789000000 + assert Integer(Float('1.123456789012345678901234567890e20', '')) == \ 112345678901234567890 - assert Integer(Float('1.123456789012345678901234567890e25','')) == \ + assert Integer(Float('1.123456789012345678901234567890e25', '')) == \ 11234567890123456789012345 - assert Integer(Float('1.123456789012345678901234567890e35','')) == \ - 112345678901234567890123456789000000 + # decimal forces float so it's not an exact integer ending in 000000 + assert Integer(Float('1.123456789012345678901234567890e35', '')) == \ + 112345678901234567890123456789000192 + assert Integer(Float('123456789012345678901234567890e5', '')) == \ + 12345678901234567890123456789000000 + assert Float('123000e-2','') == Float('1230.00', '') + assert Float('123000e2','') == Float('12300000', '') + assert int(1 + Rational('.9999999999999999999999999')) == 1 assert int(pi/1e20) == 0 assert int(1 + pi/1e20) == 1 @@ -1398,4 +1503,26 @@ raises(TypeError, lambda: float(x)) raises(TypeError, lambda: float(sqrt(-1))) - assert int(12345678901234567890 + cos(1)**2 + sin(1)**2) == 12345678901234567891 + assert int(12345678901234567890 + cos(1)**2 + sin(1)**2) == \ + 12345678901234567891 + +def test_issue_3512a(): + assert Mul.flatten([3**Rational(1, 3), + Pow(-Rational(1, 9), Rational(2, 3), evaluate=False)]) == \ + ([Rational(1, 3), (-1)**Rational(2, 3)], [], None) + + +def test_denest_add_mul(): + # when working with evaluated expressions make sure they denest + eq = x + 1 + eq = Add(eq, 2, evaluate=False) + eq = Add(eq, 2, evaluate=False) + assert Add(*eq.args) == x + 5 + eq = x*2 + eq = Mul(eq, 2, evaluate=False) + eq = Mul(eq, 2, evaluate=False) + assert Mul(*eq.args) == 8*x + # but don't let them denest unecessarily + eq = Mul(-2, x - 2, evaluate=False) + assert 2*eq == Mul(-4, x - 2, evaluate=False) + assert -eq == Mul(2, x - 2, evaluate=False) diff -Nru python3-sympy-0.7.2/sympy/core/tests/test_assumptions.py python3-sympy-0.7.3/sympy/core/tests/test_assumptions.py --- python3-sympy-0.7.2/sympy/core/tests/test_assumptions.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/core/tests/test_assumptions.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,283 +1,296 @@ + from sympy.core import Symbol, S, Rational, Integer from sympy.utilities.pytest import raises, XFAIL -from sympy import I, sqrt, log, exp +from sympy import I, sqrt, log, exp, sin, asin from sympy.core.facts import InconsistentAssumptions + def test_symbol_unset(): - x = Symbol('x',real=True, integer=True) - assert x.is_real == True - assert x.is_integer == True - assert x.is_imaginary == False - assert x.is_noninteger == False + x = Symbol('x', real=True, integer=True) + assert x.is_real is True + assert x.is_integer is True + assert x.is_imaginary is False + assert x.is_noninteger is False assert x.is_number is False + def test_zero(): z = Integer(0) - assert z.is_commutative == True - assert z.is_integer == True - assert z.is_rational == True - assert z.is_real == True - assert z.is_complex == True - assert z.is_noninteger == False - assert z.is_irrational == False - assert z.is_imaginary == False - assert z.is_positive == False - assert z.is_negative == False - assert z.is_nonpositive == True - assert z.is_nonnegative == True - assert z.is_even == True - assert z.is_odd == False - assert z.is_bounded == True - assert z.is_unbounded == False - assert z.is_finite == False - assert z.is_infinitesimal == True - assert z.is_comparable == True - assert z.is_prime == False - assert z.is_composite == False + assert z.is_commutative is True + assert z.is_integer is True + assert z.is_rational is True + assert z.is_real is True + assert z.is_complex is True + assert z.is_noninteger is False + assert z.is_irrational is False + assert z.is_imaginary is False + assert z.is_positive is False + assert z.is_negative is False + assert z.is_nonpositive is True + assert z.is_nonnegative is True + assert z.is_even is True + assert z.is_odd is False + assert z.is_bounded is True + assert z.is_unbounded is False + assert z.is_finite is False + assert z.is_infinitesimal is True + assert z.is_comparable is True + assert z.is_prime is False + assert z.is_composite is False assert z.is_number is True + def test_one(): z = Integer(1) - assert z.is_commutative == True - assert z.is_integer == True - assert z.is_rational == True - assert z.is_real == True - assert z.is_complex == True - assert z.is_noninteger == False - assert z.is_irrational == False - assert z.is_imaginary == False - assert z.is_positive == True - assert z.is_negative == False - assert z.is_nonpositive == False - assert z.is_nonnegative == True - assert z.is_even == False - assert z.is_odd == True - assert z.is_bounded == True - assert z.is_unbounded == False - assert z.is_finite == True - assert z.is_infinitesimal == False - assert z.is_comparable == True - assert z.is_prime == False + assert z.is_commutative is True + assert z.is_integer is True + assert z.is_rational is True + assert z.is_real is True + assert z.is_complex is True + assert z.is_noninteger is False + assert z.is_irrational is False + assert z.is_imaginary is False + assert z.is_positive is True + assert z.is_negative is False + assert z.is_nonpositive is False + assert z.is_nonnegative is True + assert z.is_even is False + assert z.is_odd is True + assert z.is_bounded is True + assert z.is_unbounded is False + assert z.is_finite is True + assert z.is_infinitesimal is False + assert z.is_comparable is True + assert z.is_prime is False assert z.is_number is True + @XFAIL def test_one_is_composite(): assert S(1).is_composite is False + def test_negativeone(): z = Integer(-1) - assert z.is_commutative == True - assert z.is_integer == True - assert z.is_rational == True - assert z.is_real == True - assert z.is_complex == True - assert z.is_noninteger == False - assert z.is_irrational == False - assert z.is_imaginary == False - assert z.is_positive == False - assert z.is_negative == True - assert z.is_nonpositive == True - assert z.is_nonnegative == False - assert z.is_even == False - assert z.is_odd == True - assert z.is_bounded == True - assert z.is_unbounded == False - assert z.is_finite == True - assert z.is_infinitesimal == False - assert z.is_comparable == True - assert z.is_prime == False - assert z.is_composite == False + assert z.is_commutative is True + assert z.is_integer is True + assert z.is_rational is True + assert z.is_real is True + assert z.is_complex is True + assert z.is_noninteger is False + assert z.is_irrational is False + assert z.is_imaginary is False + assert z.is_positive is False + assert z.is_negative is True + assert z.is_nonpositive is True + assert z.is_nonnegative is False + assert z.is_even is False + assert z.is_odd is True + assert z.is_bounded is True + assert z.is_unbounded is False + assert z.is_finite is True + assert z.is_infinitesimal is False + assert z.is_comparable is True + assert z.is_prime is False + assert z.is_composite is False assert z.is_number is True + def test_infinity(): oo = S.Infinity - assert oo.is_commutative == True - assert oo.is_integer == None - assert oo.is_rational == None - assert oo.is_real == True - assert oo.is_complex == True - assert oo.is_noninteger == None - assert oo.is_irrational == None - assert oo.is_imaginary == False - assert oo.is_positive == True - assert oo.is_negative == False - assert oo.is_nonpositive == False - assert oo.is_nonnegative == True - assert oo.is_even == None - assert oo.is_odd == None - assert oo.is_bounded == False - assert oo.is_unbounded == True - assert oo.is_finite == False - assert oo.is_infinitesimal == False - assert oo.is_comparable == True - assert oo.is_prime == None - assert oo.is_composite == None + assert oo.is_commutative is True + assert oo.is_integer is None + assert oo.is_rational is None + assert oo.is_real is True + assert oo.is_complex is True + assert oo.is_noninteger is None + assert oo.is_irrational is None + assert oo.is_imaginary is False + assert oo.is_positive is True + assert oo.is_negative is False + assert oo.is_nonpositive is False + assert oo.is_nonnegative is True + assert oo.is_even is None + assert oo.is_odd is None + assert oo.is_bounded is False + assert oo.is_unbounded is True + assert oo.is_finite is False + assert oo.is_infinitesimal is False + assert oo.is_comparable is True + assert oo.is_prime is None + assert oo.is_composite is None assert oo.is_number is True + def test_neg_infinity(): mm = S.NegativeInfinity - assert mm.is_commutative == True - assert mm.is_integer == None - assert mm.is_rational == None - assert mm.is_real == True - assert mm.is_complex == True - assert mm.is_noninteger == None - assert mm.is_irrational == None - assert mm.is_imaginary == False - assert mm.is_positive == False - assert mm.is_negative == True - assert mm.is_nonpositive == True - assert mm.is_nonnegative == False - assert mm.is_even == None - assert mm.is_odd == None - assert mm.is_bounded == False - assert mm.is_unbounded == True - assert mm.is_finite == False - assert mm.is_infinitesimal == False - assert mm.is_comparable == True - assert mm.is_prime == False - assert mm.is_composite == False + assert mm.is_commutative is True + assert mm.is_integer is None + assert mm.is_rational is None + assert mm.is_real is True + assert mm.is_complex is True + assert mm.is_noninteger is None + assert mm.is_irrational is None + assert mm.is_imaginary is False + assert mm.is_positive is False + assert mm.is_negative is True + assert mm.is_nonpositive is True + assert mm.is_nonnegative is False + assert mm.is_even is None + assert mm.is_odd is None + assert mm.is_bounded is False + assert mm.is_unbounded is True + assert mm.is_finite is False + assert mm.is_infinitesimal is False + assert mm.is_comparable is True + assert mm.is_prime is False + assert mm.is_composite is False assert mm.is_number is True def test_nan(): nan = S.NaN - assert nan.is_commutative == True - assert nan.is_integer == None - assert nan.is_rational == None - assert nan.is_real == None - assert nan.is_complex == None - assert nan.is_noninteger == None - assert nan.is_irrational == None - assert nan.is_imaginary == None - assert nan.is_positive == None - assert nan.is_negative == None - assert nan.is_nonpositive == None - assert nan.is_nonnegative == None - assert nan.is_even == None - assert nan.is_odd == None - assert nan.is_bounded == None - assert nan.is_unbounded == None - assert nan.is_finite == None - assert nan.is_infinitesimal == None - assert nan.is_comparable == False - assert nan.is_prime == None - assert nan.is_composite == None + assert nan.is_commutative is True + assert nan.is_integer is None + assert nan.is_rational is None + assert nan.is_real is None + assert nan.is_complex is None + assert nan.is_noninteger is None + assert nan.is_irrational is None + assert nan.is_imaginary is None + assert nan.is_positive is None + assert nan.is_negative is None + assert nan.is_nonpositive is None + assert nan.is_nonnegative is None + assert nan.is_even is None + assert nan.is_odd is None + assert nan.is_bounded is None + assert nan.is_unbounded is None + assert nan.is_finite is None + assert nan.is_infinitesimal is None + assert nan.is_comparable is False + assert nan.is_prime is None + assert nan.is_composite is None assert nan.is_number is True + def test_pos_rational(): - r = Rational(3,4) - assert r.is_commutative == True - assert r.is_integer == False - assert r.is_rational == True - assert r.is_real == True - assert r.is_complex == True - assert r.is_noninteger == True - assert r.is_irrational == False - assert r.is_imaginary == False - assert r.is_positive == True - assert r.is_negative == False - assert r.is_nonpositive == False - assert r.is_nonnegative == True - assert r.is_even == False - assert r.is_odd == False - assert r.is_bounded == True - assert r.is_unbounded == False - assert r.is_finite == True - assert r.is_infinitesimal == False - assert r.is_comparable == True - assert r.is_prime == False - assert r.is_composite == False - - r = Rational(1,4) - assert r.is_nonpositive == False - assert r.is_positive == True - assert r.is_negative == False - assert r.is_nonnegative == True - r = Rational(5,4) - assert r.is_negative == False - assert r.is_positive == True - assert r.is_nonpositive == False - assert r.is_nonnegative == True - r = Rational(5,3) - assert r.is_nonnegative == True - assert r.is_positive == True - assert r.is_negative == False - assert r.is_nonpositive == False + r = Rational(3, 4) + assert r.is_commutative is True + assert r.is_integer is False + assert r.is_rational is True + assert r.is_real is True + assert r.is_complex is True + assert r.is_noninteger is True + assert r.is_irrational is False + assert r.is_imaginary is False + assert r.is_positive is True + assert r.is_negative is False + assert r.is_nonpositive is False + assert r.is_nonnegative is True + assert r.is_even is False + assert r.is_odd is False + assert r.is_bounded is True + assert r.is_unbounded is False + assert r.is_finite is True + assert r.is_infinitesimal is False + assert r.is_comparable is True + assert r.is_prime is False + assert r.is_composite is False + + r = Rational(1, 4) + assert r.is_nonpositive is False + assert r.is_positive is True + assert r.is_negative is False + assert r.is_nonnegative is True + r = Rational(5, 4) + assert r.is_negative is False + assert r.is_positive is True + assert r.is_nonpositive is False + assert r.is_nonnegative is True + r = Rational(5, 3) + assert r.is_nonnegative is True + assert r.is_positive is True + assert r.is_negative is False + assert r.is_nonpositive is False + def test_neg_rational(): - r = Rational(-3,4) - assert r.is_positive == False - assert r.is_nonpositive == True - assert r.is_negative == True - assert r.is_nonnegative == False - r = Rational(-1,4) - assert r.is_nonpositive == True - assert r.is_positive == False - assert r.is_negative == True - assert r.is_nonnegative == False - r = Rational(-5,4) - assert r.is_negative == True - assert r.is_positive == False - assert r.is_nonpositive == True - assert r.is_nonnegative == False - r = Rational(-5,3) - assert r.is_nonnegative == False - assert r.is_positive == False - assert r.is_negative == True - assert r.is_nonpositive == True + r = Rational(-3, 4) + assert r.is_positive is False + assert r.is_nonpositive is True + assert r.is_negative is True + assert r.is_nonnegative is False + r = Rational(-1, 4) + assert r.is_nonpositive is True + assert r.is_positive is False + assert r.is_negative is True + assert r.is_nonnegative is False + r = Rational(-5, 4) + assert r.is_negative is True + assert r.is_positive is False + assert r.is_nonpositive is True + assert r.is_nonnegative is False + r = Rational(-5, 3) + assert r.is_nonnegative is False + assert r.is_positive is False + assert r.is_negative is True + assert r.is_nonpositive is True + def test_pi(): z = S.Pi - assert z.is_commutative == True - assert z.is_integer == False - assert z.is_rational == False - assert z.is_real == True - assert z.is_complex == True - assert z.is_noninteger == True - assert z.is_irrational == True - assert z.is_imaginary == False - assert z.is_positive == True - assert z.is_negative == False - assert z.is_nonpositive == False - assert z.is_nonnegative == True - assert z.is_even == False - assert z.is_odd == False - assert z.is_bounded == True - assert z.is_unbounded == False - assert z.is_finite == True - assert z.is_infinitesimal == False - assert z.is_comparable == True - assert z.is_prime == False - assert z.is_composite == False + assert z.is_commutative is True + assert z.is_integer is False + assert z.is_rational is False + assert z.is_real is True + assert z.is_complex is True + assert z.is_noninteger is True + assert z.is_irrational is True + assert z.is_imaginary is False + assert z.is_positive is True + assert z.is_negative is False + assert z.is_nonpositive is False + assert z.is_nonnegative is True + assert z.is_even is False + assert z.is_odd is False + assert z.is_bounded is True + assert z.is_unbounded is False + assert z.is_finite is True + assert z.is_infinitesimal is False + assert z.is_comparable is True + assert z.is_prime is False + assert z.is_composite is False + def test_E(): z = S.Exp1 - assert z.is_commutative == True - assert z.is_integer == False - assert z.is_rational == False - assert z.is_real == True - assert z.is_complex == True - assert z.is_noninteger == True - assert z.is_irrational == True - assert z.is_imaginary == False - assert z.is_positive == True - assert z.is_negative == False - assert z.is_nonpositive == False - assert z.is_nonnegative == True - assert z.is_even == False - assert z.is_odd == False - assert z.is_bounded == True - assert z.is_unbounded == False - assert z.is_finite == True - assert z.is_infinitesimal == False - assert z.is_comparable == True - assert z.is_prime == False - assert z.is_composite == False + assert z.is_commutative is True + assert z.is_integer is False + assert z.is_rational is False + assert z.is_real is True + assert z.is_complex is True + assert z.is_noninteger is True + assert z.is_irrational is True + assert z.is_imaginary is False + assert z.is_positive is True + assert z.is_negative is False + assert z.is_nonpositive is False + assert z.is_nonnegative is True + assert z.is_even is False + assert z.is_odd is False + assert z.is_bounded is True + assert z.is_unbounded is False + assert z.is_finite is True + assert z.is_infinitesimal is False + assert z.is_comparable is True + assert z.is_prime is False + assert z.is_composite is False + def test_I(): z = S.ImaginaryUnit @@ -303,65 +316,151 @@ assert z.is_prime is False assert z.is_composite is False + def test_symbol_real(): # issue 749 a = Symbol('a', real=False) - assert a.is_real == False - assert a.is_integer == False - assert a.is_negative == False - assert a.is_positive == False - assert a.is_nonnegative == False - assert a.is_nonpositive == False - assert a.is_zero == False + assert a.is_real is False + assert a.is_integer is False + assert a.is_negative is False + assert a.is_positive is False + assert a.is_nonnegative is False + assert a.is_nonpositive is False + assert a.is_zero is False + def test_symbol_zero(): - x = Symbol('x',zero=True) - assert x.is_positive == False - assert x.is_nonpositive == True - assert x.is_negative == False - assert x.is_nonnegative == True - assert x.is_zero == True - assert x.is_nonzero == False + x = Symbol('x', zero=True) + assert x.is_positive is False + assert x.is_nonpositive is True + assert x.is_negative is False + assert x.is_nonnegative is True + assert x.is_zero is True + assert x.is_nonzero is False + def test_symbol_positive(): - x = Symbol('x',positive=True) - assert x.is_positive == True - assert x.is_nonpositive == False - assert x.is_negative == False - assert x.is_nonnegative == True - assert x.is_zero == False - assert x.is_nonzero == True + x = Symbol('x', positive=True) + assert x.is_positive is True + assert x.is_nonpositive is False + assert x.is_negative is False + assert x.is_nonnegative is True + assert x.is_zero is False + assert x.is_nonzero is True + def test_neg_symbol_positive(): - x = -Symbol('x',positive=True) - assert x.is_positive == False - assert x.is_nonpositive == True - assert x.is_negative == True - assert x.is_nonnegative == False - -def test_neg_symbol_positive2(): - x = -Symbol('x',positive=True) - assert x.is_zero == False - assert x.is_nonzero == True + x = -Symbol('x', positive=True) + assert x.is_positive is False + assert x.is_nonpositive is True + assert x.is_negative is True + assert x.is_nonnegative is False + assert x.is_zero is False + assert x.is_nonzero is True + def test_symbol_nonpositive(): - x = Symbol('x',nonpositive=True) - assert x.is_positive == False - assert x.is_nonpositive == True - assert x.is_negative == None - assert x.is_nonnegative == None - assert x.is_zero == None - assert x.is_nonzero == None + x = Symbol('x', nonpositive=True) + assert x.is_positive is False + assert x.is_nonpositive is True + assert x.is_negative is None + assert x.is_nonnegative is None + assert x.is_zero is None + assert x.is_nonzero is None + def test_neg_symbol_nonpositive(): - x = -Symbol('x',nonpositive=True) - assert x.is_positive == None - assert x.is_nonpositive == None - assert x.is_negative == False - assert x.is_nonnegative == True - assert x.is_zero == None - assert x.is_nonzero == None + x = -Symbol('x', nonpositive=True) + assert x.is_positive is None + assert x.is_nonpositive is None + assert x.is_negative is False + assert x.is_nonnegative is True + assert x.is_zero is None + assert x.is_nonzero is None + + +def test_symbol_falsepositive(): + x = Symbol('x', positive=False) + assert x.is_positive is False + assert x.is_nonpositive is None + assert x.is_negative is None + assert x.is_nonnegative is None + assert x.is_zero is None + assert x.is_nonzero is None + + +@XFAIL +def test_neg_symbol_falsepositive(): + x = -Symbol('x', positive=False) + assert x.is_positive is None + assert x.is_nonpositive is None + assert x.is_negative is False # this currently returns None + assert x.is_nonnegative is None + assert x.is_zero is None + assert x.is_nonzero is None + + +def test_symbol_falsepositive_real(): + x = Symbol('x', positive=False, real=True) + assert x.is_positive is False + assert x.is_nonpositive is True + assert x.is_negative is None + assert x.is_nonnegative is None + assert x.is_zero is None + assert x.is_nonzero is None + + +def test_neg_symbol_falsepositive_real(): + x = -Symbol('x', positive=False, real=True) + assert x.is_positive is None + assert x.is_nonpositive is None + assert x.is_negative is False + assert x.is_nonnegative is True + assert x.is_zero is None + assert x.is_nonzero is None + + +def test_symbol_falsenonnegative(): + x = Symbol('x', nonnegative=False) + assert x.is_positive is False + assert x.is_nonpositive is None + assert x.is_negative is None + assert x.is_nonnegative is False + assert x.is_zero is False + assert x.is_nonzero is True + + +@XFAIL +def test_neg_symbol_falsenonnegative(): + x = -Symbol('x', nonnegative=False) + assert x.is_positive is None + assert x.is_nonpositive is False # this currently returns None + assert x.is_negative is False # this currently returns None + assert x.is_nonnegative is None + assert x.is_zero is False # this currently returns None + assert x.is_nonzero is True # this currently returns None + + +def test_symbol_falsenonnegative_real(): + x = Symbol('x', nonnegative=False, real=True) + assert x.is_positive is False + assert x.is_nonpositive is True + assert x.is_negative is True + assert x.is_nonnegative is False + assert x.is_zero is False + assert x.is_nonzero is True + + +def test_neg_symbol_falsenonnegative_real(): + x = -Symbol('x', nonnegative=False, real=True) + assert x.is_positive is True + assert x.is_nonpositive is False + assert x.is_negative is False + assert x.is_nonnegative is True + assert x.is_zero is False + assert x.is_nonzero is True + def test_prime(): assert S(-1).is_prime is False @@ -373,6 +472,7 @@ assert S(17).is_prime is True assert S(4).is_prime is False + def test_composite(): assert S(-1).is_composite is False assert S(-2).is_composite is False @@ -382,22 +482,24 @@ assert S(17).is_composite is False assert S(4).is_composite is True + def test_prime_symbol(): x = Symbol('x', prime=True) - assert x.is_prime == True - assert x.is_integer == True - assert x.is_positive == True - assert x.is_negative == False - assert x.is_nonpositive == False - assert x.is_nonnegative == True + assert x.is_prime is True + assert x.is_integer is True + assert x.is_positive is True + assert x.is_negative is False + assert x.is_nonpositive is False + assert x.is_nonnegative is True x = Symbol('x', prime=False) - assert x.is_prime == False - assert x.is_integer == None - assert x.is_positive == None - assert x.is_negative == None - assert x.is_nonpositive == None - assert x.is_nonnegative == None + assert x.is_prime is False + assert x.is_integer is None + assert x.is_positive is None + assert x.is_negative is None + assert x.is_nonpositive is None + assert x.is_nonnegative is None + def test_symbol_noncommutative(): x = Symbol('x', commutative=True) @@ -410,106 +512,113 @@ assert x.is_real is False assert x.is_complex is False + def test_other_symbol(): x = Symbol('x', integer=True) - assert x.is_integer == True - assert x.is_real == True + assert x.is_integer is True + assert x.is_real is True x = Symbol('x', integer=True, nonnegative=True) - assert x.is_integer == True - assert x.is_nonnegative == True - assert x.is_negative == False - assert x.is_positive == None + assert x.is_integer is True + assert x.is_nonnegative is True + assert x.is_negative is False + assert x.is_positive is None x = Symbol('x', integer=True, nonpositive=True) - assert x.is_integer == True - assert x.is_nonpositive == True - assert x.is_positive == False - assert x.is_negative == None + assert x.is_integer is True + assert x.is_nonpositive is True + assert x.is_positive is False + assert x.is_negative is None x = Symbol('x', odd=True) - assert x.is_odd == True - assert x.is_even == False - assert x.is_integer == True + assert x.is_odd is True + assert x.is_even is False + assert x.is_integer is True x = Symbol('x', odd=False) - assert x.is_odd == False - assert x.is_even == None - assert x.is_integer == None + assert x.is_odd is False + assert x.is_even is None + assert x.is_integer is None x = Symbol('x', even=True) - assert x.is_even == True - assert x.is_odd == False - assert x.is_integer == True + assert x.is_even is True + assert x.is_odd is False + assert x.is_integer is True x = Symbol('x', even=False) - assert x.is_even == False - assert x.is_odd == None - assert x.is_integer == None + assert x.is_even is False + assert x.is_odd is None + assert x.is_integer is None x = Symbol('x', integer=True, nonnegative=True) - assert x.is_integer == True - assert x.is_nonnegative == True + assert x.is_integer is True + assert x.is_nonnegative is True x = Symbol('x', integer=True, nonpositive=True) - assert x.is_integer == True - assert x.is_nonpositive == True + assert x.is_integer is True + assert x.is_nonpositive is True with raises(AttributeError): x.is_real = False + def test_issue726(): """catch: hash instability""" x = Symbol("x") y = Symbol("y") - a1 = x+y - a2 = y+x + a1 = x + y + a2 = y + x a2.is_comparable h1 = hash(a1) h2 = hash(a2) assert h1 == h2 + def test_issue1723(): - z = (-1)**Rational(1,3)*(1-I*sqrt(3)) + z = (-1)**Rational(1, 3)*(1 - I*sqrt(3)) assert z.is_real in [True, None] + def test_hash_vs_typeinfo(): """seemingly different typeinfo, but in fact equal""" # the following two are semantically equal - x1= Symbol('x', even=True) - x2= Symbol('x', integer=True, odd=False) + x1 = Symbol('x', even=True) + x2 = Symbol('x', integer=True, odd=False) assert hash(x1) == hash(x2) assert x1 == x2 + def test_hash_vs_typeinfo_2(): """different typeinfo should mean !eq""" # the following two are semantically different x = Symbol('x') - x1= Symbol('x', even=True) + x1 = Symbol('x', even=True) assert x != x1 - assert hash(x) != hash(x1) # This might fail with very low probability + assert hash(x) != hash(x1) # This might fail with very low probability + def test_hash_vs_eq(): """catch: different hash for equal objects""" a = 1 + S.Pi # important: do not fold it into a Number instance - ha= hash(a) # it should be Add/Mul/... to trigger the bug + ha = hash(a) # it should be Add/Mul/... to trigger the bug a.is_positive # this uses .evalf() and deduces it is positive - assert a.is_positive == True + assert a.is_positive is True # be sure that hash stayed the same assert ha == hash(a) # now b should be the same expression b = a.expand(trig=True) - hb= hash(b) + hb = hash(b) assert a == b - assert ha== hb + assert ha == hb + def test_Add_is_pos_neg(): # these cover lines not covered by the rest of tests in core @@ -523,12 +632,13 @@ assert (n + x).is_negative is True assert (p + x).is_negative is False + def test_special_is_rational(): i = Symbol('i', integer=True) r = Symbol('r', rational=True) x = Symbol('x') assert sqrt(3).is_rational is False - assert (3+sqrt(3)).is_rational is False + assert (3 + sqrt(3)).is_rational is False assert (3*sqrt(3)).is_rational is False assert exp(3).is_rational is False assert exp(i).is_rational is False @@ -547,17 +657,25 @@ assert (r**i).is_rational is True assert (r**r).is_rational is None assert (r**x).is_rational is None + assert sin(1).is_rational is False + assert sin(i).is_rational is False + assert sin(r).is_rational is False + assert sin(x).is_rational is None + assert asin(r).is_rational is False + assert sin(asin(3), evaluate=False).is_rational is True + @XFAIL def test_issue_3176(): x = Symbol('x') # both zero or both Muls...but neither "change would be very appreciated. # This is similar to x/x => 1 even though if x = 0, it is really nan. - assert type(x*0) == type(0*S.Infinity) + assert isinstance(x*0, type(0*S.Infinity)) if 0*S.Infinity is S.NaN: b = Symbol('b', bounded=None) assert (b*0).is_zero is None + def test_special_assumptions(): x = Symbol('x') z2 = z = Symbol('z', zero=True) @@ -572,9 +690,19 @@ e = -3 - sqrt(5) + (-sqrt(10)/2 - sqrt(2)/2)**2 assert (e < 0) is False assert (e > 0) is False - assert (e == 0) is False # it's not a literal 0 + assert (e == 0) is False # it's not a literal 0 assert e.equals(0) is True + def test_inconsistent(): # cf. issues 2696 and 2446 - raises(InconsistentAssumptions, lambda: Symbol('x', real=True, commutative=False)) + raises(InconsistentAssumptions, lambda: Symbol('x', real=True, + commutative=False)) + + +def test_issue_3532(): + assert ((-1)**(I)).is_real is True + assert ((-1)**(I*2)).is_real is True + assert ((-1)**(I/2)).is_real is True + assert ((-1)**(I*S.Pi)).is_real is True + assert (I**(I + 2)).is_real is True diff -Nru python3-sympy-0.7.2/sympy/core/tests/test_basic.py python3-sympy-0.7.3/sympy/core/tests/test_basic.py --- python3-sympy-0.7.2/sympy/core/tests/test_basic.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/core/tests/test_basic.py 2013-07-13 17:53:32.000000000 +0000 @@ -4,22 +4,26 @@ from sympy.core.basic import Basic, Atom, preorder_traversal from sympy.core.singleton import S, Singleton from sympy.core.symbol import symbols -from sympy.utilities.misc import default_sort_key +from sympy.core.compatibility import default_sort_key from sympy.utilities.pytest import raises -b1 = Basic(); b2 = Basic(b1); b3 = Basic(b2) +b1 = Basic() +b2 = Basic(b1) +b3 = Basic(b2) b21 = Basic(b2, b1) + def test_structure(): assert b21.args == (b2, b1) assert tuple(b21.iter_basic_args()) == b21.args assert b21.func(*b21.args) == b21 assert bool(b1) + def test_equality(): - instances = [b1, b2, b3, b21, Basic(b1,b1,b1), Basic] + instances = [b1, b2, b3, b21, Basic(b1, b1, b1), Basic] for i, b_i in enumerate(instances): for j, b_j in enumerate(instances): assert (b_i == b_j) == (i == j) @@ -30,17 +34,19 @@ assert Basic() != 0 assert not(Basic() == 0) + def test_matches_basic(): - instances = [Basic(b1,b1,b2), Basic(b1,b2,b1), Basic(b2, b1, b1), - Basic(b1, b2), Basic(b2, b1), b2, b1] + instances = [Basic(b1, b1, b2), Basic(b1, b2, b1), Basic(b2, b1, b1), + Basic(b1, b2), Basic(b2, b1), b2, b1] for i, b_i in enumerate(instances): for j, b_j in enumerate(instances): - if i ==j: + if i == j: assert b_i.matches(b_j) == {} else: assert b_i.matches(b_j) is None assert b1.match(b1) == {} + def test_has(): assert b21.has(b1) assert b21.has(b3, b1) @@ -48,6 +54,7 @@ assert not b1.has(b21, b3) assert not b21.has() + def test_subs(): assert b21.subs(b2, b1) == Basic(b1, b1) assert b21.subs(b2, b21) == Basic(b21, b1) @@ -60,19 +67,24 @@ raises(ValueError, lambda: b21.subs('bad arg')) raises(ValueError, lambda: b21.subs(b1, b2, b3)) + def test_atoms(): assert b21.atoms() == set() + def test_free_symbols_empty(): assert b21.free_symbols == set() + def test_doit(): assert b21.doit() == b21 assert b21.doit(deep=False) == b21 + def test_S(): assert repr(S) == 'S' + def test_xreplace(): assert b21.xreplace({b2: b1}) == Basic(b1, b1) assert b21.xreplace({b2: b21}) == Basic(b21, b1) @@ -81,32 +93,36 @@ assert Atom(b1).xreplace({b1: b2}) == Atom(b1) assert Atom(b1).xreplace({Atom(b1): b2}) == b2 raises(TypeError, lambda: b1.xreplace()) - raises(TypeError, lambda: b1.xreplace([b1,b2])) + raises(TypeError, lambda: b1.xreplace([b1, b2])) + def test_Singleton(): - global instanciated - instanciated = 0 + global instantiated + instantiated = 0 + class MySingleton(Basic, metaclass=Singleton): def __new__(cls): - global instanciated - instanciated += 1 + global instantiated + instantiated += 1 return Basic.__new__(cls) - assert instanciated == 1 + assert instantiated == 1 assert MySingleton() is not Basic() assert MySingleton() is MySingleton() assert S.MySingleton is MySingleton() - assert instanciated == 1 + assert instantiated == 1 class MySingleton_sub(MySingleton): pass - assert instanciated == 2 + assert instantiated == 2 assert MySingleton_sub() is not MySingleton() assert MySingleton_sub() is MySingleton_sub() + def test_preorder_traversal(): expr = Basic(b21, b3) - assert list(preorder_traversal(expr)) == [expr, b21, b2, b1, b1, b3, b2, b1] + assert list( + preorder_traversal(expr)) == [expr, b21, b2, b1, b1, b3, b2, b1] assert list(preorder_traversal(('abc', ('d', 'ef')))) == [ ('abc', ('d', 'ef')), 'abc', ('d', 'ef'), 'd', 'ef'] @@ -119,9 +135,12 @@ assert result == [expr, b21, b2, b1, b3, b2] w, x, y, z = symbols('w:z') - expr = z + w*(x+y) - assert list(preorder_traversal([expr], key=default_sort_key)) == \ + expr = z + w*(x + y) + assert list(preorder_traversal([expr], keys=default_sort_key)) == \ [[w*(x + y) + z], w*(x + y) + z, z, w*(x + y), w, x + y, x, y] + assert list(preorder_traversal((x + y)*z, keys=True)) == \ + [z*(x + y), z, x + y, x, y] + def test_sorted_args(): x = symbols('x') diff -Nru python3-sympy-0.7.2/sympy/core/tests/test_cache.py python3-sympy-0.7.3/sympy/core/tests/test_cache.py --- python3-sympy-0.7.2/sympy/core/tests/test_cache.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/core/tests/test_cache.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,5 +1,6 @@ from sympy.core.cache import cacheit + def test_cacheit_doc(): @cacheit def testfn(): diff -Nru python3-sympy-0.7.2/sympy/core/tests/test_compatibility.py python3-sympy-0.7.3/sympy/core/tests/test_compatibility.py --- python3-sympy-0.7.2/sympy/core/tests/test_compatibility.py 1970-01-01 00:00:00.000000000 +0000 +++ python3-sympy-0.7.3/sympy/core/tests/test_compatibility.py 2013-07-13 17:53:32.000000000 +0000 @@ -0,0 +1,15 @@ +from sympy.core.compatibility import default_sort_key, as_int +from sympy.core.singleton import S +from sympy.utilities.pytest import raises + +from sympy.abc import x + + +def test_default_sort_key(): + func = lambda x: x + assert sorted([func, x, func], key=default_sort_key) == [func, func, x] + + +def test_as_int(): + raises(ValueError, lambda : as_int(1.1)) + raises(ValueError, lambda : as_int([])) diff -Nru python3-sympy-0.7.2/sympy/core/tests/test_complex.py python3-sympy-0.7.3/sympy/core/tests/test_complex.py --- python3-sympy-0.7.2/sympy/core/tests/test_complex.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/core/tests/test_complex.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,14 +1,16 @@ -from sympy import (S, Symbol, sqrt, I, Integer, Rational, cos, sin, im, re, - exp, sinh, cosh, tan, tanh, conjugate, sign, cot, coth, pi, +from sympy import (S, Symbol, sqrt, I, Integer, Rational, cos, sin, im, re, Abs, + exp, sinh, cosh, tan, tanh, conjugate, sign, cot, coth, pi, symbols, expand_complex) from sympy.utilities.pytest import XFAIL + def test_complex(): a = Symbol("a", real=True) b = Symbol("b", real=True) - e = (a+I*b)*(a-I*b) - assert e.expand() == a**2+b**2 - assert sqrt(I) == (-1)**Rational(1,4) + e = (a + I*b)*(a - I*b) + assert e.expand() == a**2 + b**2 + assert sqrt(I) == (-1)**Rational(1, 4) + def test_conjugate(): a = Symbol("a", real=True) @@ -33,56 +35,63 @@ assert conjugate(tanh(z)) == tanh(zc) assert conjugate(coth(z)) == coth(zc) + def test_abs1(): - a=Symbol("a", real=True) - b=Symbol("b", real=True) + a = Symbol("a", real=True) + b = Symbol("b", real=True) assert abs(a) == abs(a) assert abs(-a) == abs(a) - assert abs(a+I*b) == sqrt(a**2+b**2) + assert abs(a + I*b) == sqrt(a**2 + b**2) + def test_abs2(): - a=Symbol("a", real=False) - b=Symbol("b", real=False) + a = Symbol("a", real=False) + b = Symbol("b", real=False) assert abs(a) != a assert abs(-a) != a - assert abs(a+I*b) != sqrt(a**2+b**2) + assert abs(a + I*b) != sqrt(a**2 + b**2) + def test_evalc(): x = Symbol("x", real=True) y = Symbol("y", real=True) z = Symbol("z") - assert ((x+I*y)**2).expand(complex=True) == x**2+2*I*x*y - y**2 + assert ((x + I*y)**2).expand(complex=True) == x**2 + 2*I*x*y - y**2 assert expand_complex(z**(2*I)) == (re((re(z) + I*im(z))**(2*I)) + I*im((re(z) + I*im(z))**(2*I))) - assert expand_complex(z**(2*I), deep=False) == I*im(z**(2*I)) + re(z**(2*I)) + assert expand_complex( + z**(2*I), deep=False) == I*im(z**(2*I)) + re(z**(2*I)) - assert exp(I*x) != cos(x)+I*sin(x) - assert exp(I*x).expand(complex=True) == cos(x)+I*sin(x) - assert exp(I*x+y).expand(complex=True) == exp(y)*cos(x)+I*sin(x)*exp(y) + assert exp(I*x) != cos(x) + I*sin(x) + assert exp(I*x).expand(complex=True) == cos(x) + I*sin(x) + assert exp(I*x + y).expand(complex=True) == exp(y)*cos(x) + I*sin(x)*exp(y) assert sin(I*x).expand(complex=True) == I * sinh(x) - assert sin(x+I*y).expand(complex=True) == sin(x)*cosh(y) + \ - I * sinh(y) * cos(x) + assert sin(x + I*y).expand(complex=True) == sin(x)*cosh(y) + \ + I * sinh(y) * cos(x) assert cos(I*x).expand(complex=True) == cosh(x) - assert cos(x+I*y).expand(complex=True) == cos(x)*cosh(y) - \ - I * sinh(y) * sin(x) + assert cos(x + I*y).expand(complex=True) == cos(x)*cosh(y) - \ + I * sinh(y) * sin(x) assert tan(I*x).expand(complex=True) == tanh(x) * I - assert tan(x+I*y).expand(complex=True) == \ - ((sin(x)*cos(x) + I*cosh(y)*sinh(y)) / (cos(x)**2 + sinh(y)**2)).expand() + assert tan(x + I*y).expand(complex=True) == ( + (sin(x)*cos(x) + I*cosh(y)*sinh(y)) / + (cos(x)**2 + sinh(y)**2)).expand() assert sinh(I*x).expand(complex=True) == I * sin(x) - assert sinh(x+I*y).expand(complex=True) == sinh(x)*cos(y) + \ - I * sin(y) * cosh(x) + assert sinh(x + I*y).expand(complex=True) == sinh(x)*cos(y) + \ + I * sin(y) * cosh(x) assert cosh(I*x).expand(complex=True) == cos(x) - assert cosh(x+I*y).expand(complex=True) == cosh(x)*cos(y) + \ - I * sin(y) * sinh(x) + assert cosh(x + I*y).expand(complex=True) == cosh(x)*cos(y) + \ + I * sin(y) * sinh(x) assert tanh(I*x).expand(complex=True) == tan(x) * I - assert tanh(x+I*y).expand(complex=True) == \ - ((sinh(x)*cosh(x) + I*cos(y)*sin(y)) / (sinh(x)**2 + cos(y)**2)).expand() + assert tanh(x + I*y).expand(complex=True) == ( + (sinh(x)*cosh(x) + I*cos(y)*sin(y)) / + (sinh(x)**2 + cos(y)**2)).expand() + def test_pythoncomplex(): x = Symbol("x") @@ -90,37 +99,43 @@ assert 4j*x == 4.0*x*I assert 4.1j*x != 4*x*I + def test_rootcomplex(): R = Rational - assert ((+1+I)**R(1,2)).expand(complex=True) == 2**R(1,4)*cos( pi/8) + 2**R(1,4)*sin( pi/8)*I - assert ((-1-I)**R(1,2)).expand(complex=True) == 2**R(1,4)*cos(3*pi/8) - 2**R(1,4)*sin(3*pi/8)*I + assert ((+1 + I)**R(1, 2)).expand( + complex=True) == 2**R(1, 4)*cos( pi/8) + 2**R(1, 4)*sin( pi/8)*I + assert ((-1 - I)**R(1, 2)).expand( + complex=True) == 2**R(1, 4)*cos(3*pi/8) - 2**R(1, 4)*sin(3*pi/8)*I assert (sqrt(-10)*I).as_real_imag() == (-sqrt(10), 0) + def test_expand_inverse(): - assert (1/(1+I)).expand(complex=True) == (1-I)/2 - assert ((1+2*I)**(-2)).expand(complex=True) == (-3-4*I)/25 - assert ((1+I)**(-8)).expand(complex=True) == Rational(1,16) + assert (1/(1 + I)).expand(complex=True) == (1 - I)/2 + assert ((1 + 2*I)**(-2)).expand(complex=True) == (-3 - 4*I)/25 + assert ((1 + I)**(-8)).expand(complex=True) == Rational(1, 16) + def test_expand_complex(): - assert ((2+3*I)**10).expand(complex=True) == -341525 - 145668*I + assert ((2 + 3*I)**10).expand(complex=True) == -341525 - 145668*I # the following two tests are to ensure the SymPy uses an efficient # algorithm for calculating powers of complex numbers. They should execute # in something like 0.01s. - assert ((2+3*I)**1000).expand(complex=True) == \ + assert ((2 + 3*I)**1000).expand(complex=True) == \ -81079464736246615951519029367296227340216902563389546989376269312984127074385455204551402940331021387412262494620336565547972162814110386834027871072723273110439771695255662375718498785908345629702081336606863762777939617745464755635193139022811989314881997210583159045854968310911252660312523907616129080027594310008539817935736331124833163907518549408018652090650537035647520296539436440394920287688149200763245475036722326561143851304795139005599209239350981457301460233967137708519975586996623552182807311159141501424576682074392689622074945519232029999 + \ 46938745946789557590804551905243206242164799136976022474337918748798900569942573265747576032611189047943842446167719177749107138603040963603119861476016947257034472364028585381714774667326478071264878108114128915685688115488744955550920239128462489496563930809677159214598114273887061533057125164518549173898349061972857446844052995037423459472376202251620778517659247970283904820245958198842631651569984310559418135975795868314764489884749573052997832686979294085577689571149679540256349988338406458116270429842222666345146926395233040564229555893248370000*I - assert ((2+3*I/4)**1000).expand(complex=True) == \ + assert ((2 + 3*I/4)**1000).expand(complex=True) == \ Integer(1)*37079892761199059751745775382463070250205990218394308874593455293485167797989691280095867197640410033222367257278387021789651672598831503296531725827158233077451476545928116965316544607115843772405184272449644892857783761260737279675075819921259597776770965829089907990486964515784097181964312256560561065607846661496055417619388874421218472707497847700629822858068783288579581649321248495739224020822198695759609598745114438265083593711851665996586461937988748911532242908776883696631067311443171682974330675406616373422505939887984366289623091300746049101284856530270685577940283077888955692921951247230006346681086274961362500646889925803654263491848309446197554307105991537357310209426736453173441104334496173618419659521888945605315751089087820455852582920963561495787655250624781448951403353654348109893478206364632640344111022531861683064175862889459084900614967785405977231549003280842218501570429860550379522498497412180001/114813069527425452423283320117768198402231770208869520047764273682576626139237031385665948631650626991844596463898746277344711896086305533142593135616665318539129989145312280000688779148240044871428926990063486244781615463646388363947317026040466353970904996558162398808944629605623311649536164221970332681344168908984458505602379484807914058900934776500429002716706625830522008132236281291761267883317206598995396418127021779858404042159853183251540889433902091920554957783589672039160081957216630582755380425583726015528348786419432054508915275783882625175435528800822842770817965453762184851149029376 + \ I*421638390580169706973991429333213477486930178424989246669892530737775352519112934278994501272111385966211392610029433824534634841747911783746811994443436271013377059560245191441549885048056920190833693041257216263519792201852046825443439142932464031501882145407459174948712992271510309541474392303461939389368955986650538525895866713074543004916049550090364398070215427272240155060576252568700906004691224321432509053286859100920489253598392100207663785243368195857086816912514025693453058403158416856847185079684216151337200057494966741268925263085619240941610301610538225414050394612058339070756009433535451561664522479191267503989904464718368605684297071150902631208673621618217106272361061676184840810762902463998065947687814692402219182668782278472952758690939877465065070481351343206840649517150634973307937551168752642148704904383991876969408056379195860410677814566225456558230131911142229028179902418223009651437985670625/1793954211366022694113801876840128100034871409513586250746316776290259783425578615401030447369541046747571819748417910583511123376348523955353017744010395602173906080395504375010762174191250701116076984219741972574712741619474818186676828531882286780795390571221287481389759837587864244524002565968286448146002639202882164150037179450123657170327105882819203167448541028601906377066191895183769810676831353109303069033234715310287563158747705988305326397404720186258671215368588625611876280581509852855552819149745718992630449787803625851701801184123166018366180137512856918294030710215034138299203584 - assert ((2+3*I)**-1000).expand(complex=True) == \ + assert ((2 + 3*I)**-1000).expand(complex=True) == \ Integer(1)*-81079464736246615951519029367296227340216902563389546989376269312984127074385455204551402940331021387412262494620336565547972162814110386834027871072723273110439771695255662375718498785908345629702081336606863762777939617745464755635193139022811989314881997210583159045854968310911252660312523907616129080027594310008539817935736331124833163907518549408018652090650537035647520296539436440394920287688149200763245475036722326561143851304795139005599209239350981457301460233967137708519975586996623552182807311159141501424576682074392689622074945519232029999/8777125472973511649630750050295188683351430110097915876250894978429797369155961290321829625004920141758416719066805645579710744290541337680113772670040386863849283653078324415471816788604945889094925784900885812724984087843737442111926413818245854362613018058774368703971604921858023116665586358870612944209398056562604561248859926344335598822815885851096698226775053153403320782439987679978321289537645645163767251396759519805603090332694449553371530571613352311006350058217982509738362083094920649452123351717366337410243853659113315547584871655479914439219520157174729130746351059075207407866012574386726064196992865627149566238044625779078186624347183905913357718850537058578084932880569701242598663149911276357125355850792073635533676541250531086757377369962506979378337216411188347761901006460813413505861461267545723590468627854202034450569581626648934062198718362303420281555886394558137408159453103395918783625713213314350531051312551733021627153081075080140680608080529736975658786227362251632725009435866547613598753584705455955419696609282059191031962604169242974038517575645939316377801594539335940001 - Integer(1)*46938745946789557590804551905243206242164799136976022474337918748798900569942573265747576032611189047943842446167719177749107138603040963603119861476016947257034472364028585381714774667326478071264878108114128915685688115488744955550920239128462489496563930809677159214598114273887061533057125164518549173898349061972857446844052995037423459472376202251620778517659247970283904820245958198842631651569984310559418135975795868314764489884749573052997832686979294085577689571149679540256349988338406458116270429842222666345146926395233040564229555893248370000*I/8777125472973511649630750050295188683351430110097915876250894978429797369155961290321829625004920141758416719066805645579710744290541337680113772670040386863849283653078324415471816788604945889094925784900885812724984087843737442111926413818245854362613018058774368703971604921858023116665586358870612944209398056562604561248859926344335598822815885851096698226775053153403320782439987679978321289537645645163767251396759519805603090332694449553371530571613352311006350058217982509738362083094920649452123351717366337410243853659113315547584871655479914439219520157174729130746351059075207407866012574386726064196992865627149566238044625779078186624347183905913357718850537058578084932880569701242598663149911276357125355850792073635533676541250531086757377369962506979378337216411188347761901006460813413505861461267545723590468627854202034450569581626648934062198718362303420281555886394558137408159453103395918783625713213314350531051312551733021627153081075080140680608080529736975658786227362251632725009435866547613598753584705455955419696609282059191031962604169242974038517575645939316377801594539335940001 - assert ((2+3*I/4)**-1000).expand(complex=True) == \ + assert ((2 + 3*I/4)**-1000).expand(complex=True) == \ Integer(1)*4257256305661027385394552848555894604806501409793288342610746813288539790051927148781268212212078237301273165351052934681382567968787279534591114913777456610214738290619922068269909423637926549603264174216950025398244509039145410016404821694746262142525173737175066432954496592560621330313807235750500564940782099283410261748370262433487444897446779072067625787246390824312580440138770014838135245148574339248259670887549732495841810961088930810608893772914812838358159009303794863047635845688453859317690488124382253918725010358589723156019888846606295866740117645571396817375322724096486161308083462637370825829567578309445855481578518239186117686659177284332344643124760453112513611749309168470605289172320376911472635805822082051716625171429727162039621902266619821870482519063133136820085579315127038372190224739238686708451840610064871885616258831386810233957438253532027049148030157164346719204500373766157143311767338973363806106967439378604898250533766359989107510507493549529158818602327525235240510049484816090584478644771183158342479140194633579061295740839490629457435283873180259847394582069479062820225159699506175855369539201399183443253793905149785994830358114153241481884290274629611529758663543080724574566578220908907477622643689220814376054314972190402285121776593824615083669045183404206291739005554569305329760211752815718335731118664756831942466773261465213581616104242113894521054475516019456867271362053692785300826523328020796670205463390909136593859765912483565093461468865534470710132881677639651348709376/2103100954337624833663208713697737151593634525061637972297915388685604042449504336765884978184588688426595940401280828953096857809292320006227881797146858511436638446932833617514351442216409828605662238790280753075176269765767010004889778647709740770757817960711900340755635772183674511158570690702969774966791073165467918123298694584729211212414462628433370481195120564586361368504153395406845170075275051749019600057116719726628746724489572189061061036426955163696859127711110719502594479795200686212257570291758725259007379710596548777812659422174199194837355646482046783616494013289495563083118517507178847555801163089723056310287760875135196081975602765511153122381201303871673391366630940702817360340900568748719988954847590748960761446218262344767250783946365392689256634180417145926390656439421745644011831124277463643383712803287985472471755648426749842410972650924240795946699346613614779460399530274263580007672855851663196114585312432954432654691485867618908420370875753749297487803461900447407917655296784879220450937110470920633595689721819488638484547259978337741496090602390463594556401615298457456112485536498177883358587125449801777718900375736758266215245325999241624148841915093787519330809347240990363802360596034171167818310322276373120180985148650099673289383722502488957717848531612020897298448601714154586319660314294591620415272119454982220034319689607295960162971300417552364254983071768070124456169427638371140064235083443242844616326538396503937972586505546495649094344512270582463639152160238137952390380581401171977159154009407415523525096743009110916334144716516647041176989758534635251844947906038080852185583742296318878233394998111078843229681030277039104786225656992262073797524057992347971177720807155842376332851559276430280477639539393920006008737472164850104411971830120295750221200029811143140323763349636629725073624360001 - Integer(1)*3098214262599218784594285246258841485430681674561917573155883806818465520660668045042109232930382494608383663464454841313154390741655282039877410154577448327874989496074260116195788919037407420625081798124301494353693248757853222257918294662198297114746822817460991242508743651430439120439020484502408313310689912381846149597061657483084652685283853595100434135149479564507015504022249330340259111426799121454516345905101620532787348293877485702600390665276070250119465888154331218827342488849948540687659846652377277250614246402784754153678374932540789808703029043827352976139228402417432199779415751301480406673762521987999573209628597459357964214510139892316208670927074795773830798600837815329291912002136924506221066071242281626618211060464126372574400100990746934953437169840312584285942093951405864225230033279614235191326102697164613004299868695519642598882914862568516635347204441042798206770888274175592401790040170576311989738272102077819127459014286741435419468254146418098278519775722104890854275995510700298782146199325790002255362719776098816136732897323406228294203133323296591166026338391813696715894870956511298793595675308998014158717167429941371979636895553724830981754579086664608880698350866487717403917070872269853194118364230971216854931998642990452908852258008095741042117326241406479532880476938937997238098399302185675832474590293188864060116934035867037219176916416481757918864533515526389079998129329045569609325290897577497835388451456680707076072624629697883854217331728051953671643278797380171857920000*I/2103100954337624833663208713697737151593634525061637972297915388685604042449504336765884978184588688426595940401280828953096857809292320006227881797146858511436638446932833617514351442216409828605662238790280753075176269765767010004889778647709740770757817960711900340755635772183674511158570690702969774966791073165467918123298694584729211212414462628433370481195120564586361368504153395406845170075275051749019600057116719726628746724489572189061061036426955163696859127711110719502594479795200686212257570291758725259007379710596548777812659422174199194837355646482046783616494013289495563083118517507178847555801163089723056310287760875135196081975602765511153122381201303871673391366630940702817360340900568748719988954847590748960761446218262344767250783946365392689256634180417145926390656439421745644011831124277463643383712803287985472471755648426749842410972650924240795946699346613614779460399530274263580007672855851663196114585312432954432654691485867618908420370875753749297487803461900447407917655296784879220450937110470920633595689721819488638484547259978337741496090602390463594556401615298457456112485536498177883358587125449801777718900375736758266215245325999241624148841915093787519330809347240990363802360596034171167818310322276373120180985148650099673289383722502488957717848531612020897298448601714154586319660314294591620415272119454982220034319689607295960162971300417552364254983071768070124456169427638371140064235083443242844616326538396503937972586505546495649094344512270582463639152160238137952390380581401171977159154009407415523525096743009110916334144716516647041176989758534635251844947906038080852185583742296318878233394998111078843229681030277039104786225656992262073797524057992347971177720807155842376332851559276430280477639539393920006008737472164850104411971830120295750221200029811143140323763349636629725073624360001 a = Symbol('a', real=True) b = Symbol('b', real=True) assert exp(a*(2 + I*b)).expand(complex=True) == \ - I*exp(2*a)*sin(a*b) + exp(2*a)*cos(a*b) + I*exp(2*a)*sin(a*b) + exp(2*a)*cos(a*b) + def test_expand(): f = (16 - 2*sqrt(29))**2 @@ -130,25 +145,50 @@ f = (Integer(1)/2 + I)**10 assert f.expand() == Integer(237)/1024 - 779*I/256 + def test_re_im1652(): x = Symbol('x') assert re(x) == re(conjugate(x)) assert im(x) == - im(conjugate(x)) assert im(x)*re(conjugate(x)) + im(conjugate(x)) * re(x) == 0 + def test_issue_1985(): x = Symbol('x') - assert ((x + x*I)/(1 + I)).as_real_imag() == (re((x + I*x)/(1 + I)), im((x + I*x)/(1 + I))) + assert ((x + x*I)/(1 + I)).as_real_imag() == (re((x + I*x)/(1 + I) + ), im((x + I*x)/(1 + I))) + def test_issue_2137(): - assert (cos(1+I)**3).as_real_imag() == (-3*sin(1)**2*sinh(1)**2*cos(1)*cosh(1) + + assert (cos(1 + I)**3).as_real_imag() == (-3*sin(1)**2*sinh(1)**2*cos(1)*cosh(1) + cos(1)**3*cosh(1)**3, -3*cos(1)**2*cosh(1)**2*sin(1)*sinh(1) + sin(1)**3*sinh(1)**3) + def test_real_imag(): - x = Symbol('x') + x, y, z = symbols('x, y, z') + X, Y, Z = symbols('X, Y, Z', commutative=False) a = Symbol('a', real=True) assert (2*a*x).as_real_imag() == (2*a*re(x), 2*a*im(x)) + # issue 2296: + assert (x*x.conjugate()).as_real_imag() == (Abs(x)**2, 0) + assert im(x*x.conjugate()) == 0 + assert im(x*y.conjugate()*z*y) == im(x*z)*Abs(y)**2 + assert im(x*y.conjugate()*x*y) == im(x**2)*Abs(y)**2 + assert im(Z*y.conjugate()*X*y) == im(Z*X)*Abs(y)**2 + assert im(X*X.conjugate()) == im(X*X.conjugate(), evaluate=False) + assert (sin(x)*sin(x).conjugate()).as_real_imag() == \ + (Abs(sin(x))**2, 0) + + # issue 3474: + assert (x**2).as_real_imag() == (re(x)**2 - im(x)**2, 2*re(x)*im(x)) + + # issue 3329: + r = Symbol('r', real=True) + i = Symbol('i', imaginary=True) + assert (i*r*x).as_real_imag() == (I*i*r*im(x), -I*i*r*re(x)) + + def test_pow_issue_1724(): e = ((-1)**(S(1)/3)) assert e.conjugate().n() == e.n().conjugate() @@ -157,5 +197,6 @@ e = 2**I assert e.conjugate().n() == e.n().conjugate() + def test_issue_2330(): assert sqrt(I).conjugate() != sqrt(I) diff -Nru python3-sympy-0.7.2/sympy/core/tests/test_containers.py python3-sympy-0.7.3/sympy/core/tests/test_containers.py --- python3-sympy-0.7.2/sympy/core/tests/test_containers.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/core/tests/test_containers.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,11 +1,13 @@ + from sympy import Matrix, Tuple, symbols, sympify, Basic, Dict, S, FiniteSet from sympy.core.containers import tuple_wrapper -from sympy.utilities.pytest import raises +from sympy.utilities.pytest import raises, XFAIL from sympy.core.compatibility import is_sequence, iterable + def test_Tuple(): t = (1, 2, 3, 4) - st = Tuple(*t) + st = Tuple(*t) assert set(sympify(t)) == set(st) assert len(t) == len(st) assert set(sympify(t[:2])) == set(st[:2]) @@ -16,7 +18,7 @@ t2 = (p, q, r, s) st2 = Tuple(*t2) assert st2.atoms() == set(t2) - assert st == st2.subs({p:1, q:2, r:3, s:4}) + assert st == st2.subs({p: 1, q: 2, r: 3, s: 4}) # issue 2406 assert all(isinstance(arg, Basic) for arg in st.args) assert Tuple(p, 1).subs(p, 0) == Tuple(0, 1) @@ -27,11 +29,13 @@ assert Tuple.fromiter(x for x in range(4)) == Tuple(0, 1, 2, 3) assert st2.fromiter(st2.args) == st2 + def test_Tuple_contains(): t1, t2 = Tuple(1), Tuple(2) assert t1 in Tuple(1, 2, 3, t1, Tuple(t2)) assert t2 not in Tuple(1, 2, 3, t1, Tuple(t2)) + def test_Tuple_concatenation(): assert Tuple(1, 2) + Tuple(3, 4) == Tuple(1, 2, 3, 4) assert (1, 2) + Tuple(3, 4) == Tuple(1, 2, 3, 4) @@ -46,6 +50,7 @@ assert Tuple(1, 2) + Tuple2(3, 4) == Tuple(1, 2, 1, 2, 3, 4) assert Tuple2(1, 2) + Tuple(3, 4) == Tuple(1, 2, 3, 4) + def test_Tuple_equality(): assert Tuple(1, 2) is not (1, 2) assert (Tuple(1, 2) == (1, 2)) is True @@ -57,12 +62,14 @@ assert (Tuple(1, 2) == Tuple(1, 3)) is False assert (Tuple(1, 2) != Tuple(1, 3)) is True + def test_Tuple_comparision(): assert (Tuple(1, 3) >= Tuple(-10, 30)) is True assert (Tuple(1, 3) <= Tuple(-10, 30)) is False assert (Tuple(1, 3) >= Tuple(1, 3)) is True assert (Tuple(1, 3) <= Tuple(1, 3)) is True + def test_tuple_wrapper(): @tuple_wrapper @@ -74,6 +81,7 @@ assert wrap_tuples_and_return((p, 1)) == (Tuple(p, 1),) assert wrap_tuples_and_return(1, (p, 2), 3) == (1, Tuple(p, 2), 3) + def test_iterable_is_sequence(): ordered = [list(), tuple(), Tuple(), Matrix([[]])] unordered = [set()] @@ -84,31 +92,33 @@ assert all(not iterable(i) for i in not_sympy_iterable) assert all(iterable(i, exclude=None) for i in not_sympy_iterable) + def test_Dict(): - x,y,z = symbols('x y z') - d = Dict({x:1, y:2, z:3}) + x, y, z = symbols('x y z') + d = Dict({x: 1, y: 2, z: 3}) assert d[x] == 1 assert d[y] == 2 raises(KeyError, lambda: d[2]) assert len(d) == 3 - assert set(d.keys()) == set((x,y,z)) - assert set(d.values()) == set((S(1),S(2),S(3))) - assert d.get(5,'default') == 'default' + assert set(d.keys()) == set((x, y, z)) + assert set(d.values()) == set((S(1), S(2), S(3))) + assert d.get(5, 'default') == 'default' assert x in d and z in d and not 5 in d - assert d.has(x) and d.has(1) # SymPy Basic .has method + assert d.has(x) and d.has(1) # SymPy Basic .has method # Test input types # input - a python dict # input - items as args - SymPy style - assert (Dict({x:1, y:2, z:3}) == - Dict((x,1), (y,2), (z,3))) + assert (Dict({x: 1, y: 2, z: 3}) == + Dict((x, 1), (y, 2), (z, 3))) - raises(TypeError, lambda: Dict(((x,1), (y,2), (z,3)))) + raises(TypeError, lambda: Dict(((x, 1), (y, 2), (z, 3)))) with raises(NotImplementedError): - d[5] = 6 # assert immutability + d[5] = 6 # assert immutability - assert set(d.items()) == set((Tuple(x,S(1)), Tuple(y,S(2)), Tuple(z,S(3)))) - assert set(d) == set([x,y,z]) + assert set( + d.items()) == set((Tuple(x, S(1)), Tuple(y, S(2)), Tuple(z, S(3)))) + assert set(d) == set([x, y, z]) assert str(d) == '{x: 1, y: 2, z: 3}' assert d.__repr__() == '{x: 1, y: 2, z: 3}' @@ -116,12 +126,25 @@ d = Dict({x: 1, y: 2, z: 3}) assert d == Dict(d) -def issue_2689(): - args = [(1,2),(2,1)] - for o in [Dict, Tuple, FiniteSet]: + +def test_issue_2689(): + args = [(1, 2), (2, 1)] + for o in [Dict, Tuple]: + # __eq__ and arg handling + if o != Tuple: + assert o(*args) == o(*reversed(args)) + pair = [o(*args), o(*reversed(args))] + assert sorted(pair) == sorted(reversed(pair)) + assert set(o(*args)) # doesn't fail + + +@XFAIL +def test_issue_2689b(): + args = [(1, 2), (2, 1)] + for o in [FiniteSet]: # __eq__ and arg handling if o != Tuple: assert o(*args) == o(*reversed(args)) pair = [o(*args), o(*reversed(args))] assert sorted(pair) == sorted(reversed(pair)) - assert set(o(*args)) # doesn't fail + assert set(o(*args)) # doesn't fail diff -Nru python3-sympy-0.7.2/sympy/core/tests/test_count_ops.py python3-sympy-0.7.3/sympy/core/tests/test_count_ops.py --- python3-sympy-0.7.2/sympy/core/tests/test_count_ops.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/core/tests/test_count_ops.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,8 +1,9 @@ from sympy import symbols, sin, exp, cos, Derivative, Integral, Basic, \ - count_ops, S, And, I, pi, Eq + count_ops, S, And, I, pi, Eq x, y, z = symbols('x,y,z') + def test_count_ops_non_visual(): def count(val): return count_ops(val, visual=False) @@ -14,9 +15,12 @@ assert count({x + y: x}) == 1 assert count({x + y: S(2) + x}) is not S.One + def test_count_ops_visual(): - ADD, MUL, POW, SIN, COS, EXP, AND, D, G = symbols('Add Mul Pow sin cos exp And Derivative Integral'.upper()) + ADD, MUL, POW, SIN, COS, EXP, AND, D, G = symbols( + 'Add Mul Pow sin cos exp And Derivative Integral'.upper()) DIV, SUB, NEG = symbols('DIV SUB NEG') + def count(val): return count_ops(val, visual=True) @@ -60,7 +64,8 @@ assert count(2*z + y**17 + x + 1) == 3*ADD + MUL + POW assert count(2*z + y**17 + x + sin(x)) == 3*ADD + POW + MUL + SIN assert count(2*z + y**17 + x + sin(x**2)) == 3*ADD + MUL + 2*POW + SIN - assert count(2*z + y**17 + x + sin(x**2) + exp(cos(x))) == 4*ADD + MUL + 2*POW + EXP + COS + SIN + assert count(2*z + y**17 + x + sin( + x**2) + exp(cos(x))) == 4*ADD + MUL + 2*POW + EXP + COS + SIN assert count(Derivative(x, x)) == D assert count(Integral(x, x) + 2*x/(1 + x)) == G + DIV + MUL + 2*ADD @@ -72,7 +77,8 @@ assert count({}) is S.Zero assert count([x + 1, sin(x)*y, None]) == SIN + ADD + MUL assert count([]) is S.Zero - assert count(And(x, y, z)) == 2*AND + + # XXX: These are a bit surprising, only Expr-compatible ops are counted. + assert count(And(x, y, z)) == 0 assert count(Basic(x, x + y)) == ADD - # is this right or should we count the Eq, too...like an Add? assert count(Eq(x + y, S(2))) == ADD diff -Nru python3-sympy-0.7.2/sympy/core/tests/test_diff.py python3-sympy-0.7.3/sympy/core/tests/test_diff.py --- python3-sympy-0.7.2/sympy/core/tests/test_diff.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/core/tests/test_diff.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,7 +1,8 @@ from sympy import Symbol, Rational, cos, sin, tan, cot, exp, log, Function, \ - Derivative, Expr, symbols, pi, I, S + Derivative, Expr, symbols, pi, I, S from sympy.utilities.pytest import raises + def test_diff(): x, y = symbols('x, y') assert Rational(1, 3).diff(x) is S.Zero @@ -33,11 +34,12 @@ e = a*b*c assert e.diff(c) == a*b + def test_diff2(): n3 = Rational(3) n2 = Rational(2) n6 = Rational(6) - x,c = list(map(Symbol, 'xc')) + x, c = list(map(Symbol, 'xc')) e = n3*(-n2 + x**n2)*cos(x) + x*(-n6 + x**n2)*sin(x) assert e == 3*(-2 + x**2)*cos(x) + x*(-6 + x**2)*sin(x) @@ -50,18 +52,19 @@ e = 2*exp(x*x)*x assert e.diff(x) == 2*exp(x**2) + 4*x**2*exp(x**2) + def test_diff3(): - a,b,c = list(map(Symbol, 'abc')) + a, b, c = list(map(Symbol, 'abc')) p = Rational(5) e = a*b + sin(b**p) assert e == a*b + sin(b**5) assert e.diff(a) == b - assert e.diff(b) == a+5*b**4*cos(b**5) + assert e.diff(b) == a + 5*b**4*cos(b**5) e = tan(c) assert e == tan(c) assert e.diff(c) in [cos(c)**(-2), 1 + sin(c)**2/cos(c)**2, 1 + tan(c)**2] - e = c*log(c)-c - assert e == -c+c*log(c) + e = c*log(c) - c + assert e == -c + c*log(c) assert e.diff(c) == log(c) e = log(sin(c)) assert e == log(sin(c)) @@ -70,6 +73,7 @@ assert e == 2**a*log(Rational(2))**(-1) assert e.diff(a) == 2**a + def test_diff_no_eval_derivative(): class My(Expr): def __new__(cls, x): @@ -81,11 +85,13 @@ # it doesn't have y so it shouldn't need a method for this case assert My(x).diff(y) == 0 + def test_speed(): # this should return in 0.0s. If it takes forever, it's wrong. x = Symbol("x") assert x.diff(x, 10**8) == 0 + def test_deriv_noncommutative(): A = Symbol("A", commutative=False) f = Function("f") diff -Nru python3-sympy-0.7.2/sympy/core/tests/test_equal.py python3-sympy-0.7.3/sympy/core/tests/test_equal.py --- python3-sympy-0.7.2/sympy/core/tests/test_equal.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/core/tests/test_equal.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,12 +1,13 @@ from sympy import Symbol, Dummy, Rational, exp + def test_equal(): b = Symbol("b") a = Symbol("a") - e1 = a+b + e1 = a + b e2 = 2*a*b e3 = a**3*b**2 - e4 = a*b+b*a + e4 = a*b + b*a assert not e1 == e2 assert not e1 == e2 assert e1 != e2 @@ -15,23 +16,24 @@ assert not e2 == e3 x = Symbol("x") - e1 = exp(x+1/x) + e1 = exp(x + 1/x) y = Symbol("x") - e2 = exp(y+1/y) + e2 = exp(y + 1/y) assert e1 == e2 assert not e1 != e2 y = Symbol("y") - e2 = exp(y+1/y) + e2 = exp(y + 1/y) assert not e1 == e2 assert e1 != e2 - e5 = Rational(3)+2*x-x-x + e5 = Rational(3) + 2*x - x - x assert e5 == 3 assert 3 == e5 assert e5 != 4 assert 4 != e5 - assert e5 != 3+x - assert 3+x != e5 + assert e5 != 3 + x + assert 3 + x != e5 + def test_expevalbug(): x = Symbol("x") @@ -39,6 +41,7 @@ e3 = exp(x) assert e1 == e3 + def test_cmp_bug1(): class T(object): pass @@ -49,6 +52,7 @@ assert not (x == t) assert (x != t) + def test_cmp_bug2(): class T(object): pass @@ -58,6 +62,7 @@ assert not (Symbol == t) assert (Symbol != t) + def test_cmp_bug1258(): """ Check that Basic subclasses can be compared with sympifiable objects. @@ -68,14 +73,15 @@ assert not (Symbol == 'x') assert (Symbol != 'x') + def test_dummy_eq(): x = Symbol('x') y = Symbol('y') u = Dummy('u') - assert (u**2 + 1).dummy_eq(x**2 + 1) == True - assert ((u**2 + 1) == (x**2 + 1)) == False + assert (u**2 + 1).dummy_eq(x**2 + 1) is True + assert ((u**2 + 1) == (x**2 + 1)) is False - assert (u**2 + y).dummy_eq(x**2 + y, x) == True - assert (u**2 + y).dummy_eq(x**2 + y, y) == False + assert (u**2 + y).dummy_eq(x**2 + y, x) is True + assert (u**2 + y).dummy_eq(x**2 + y, y) is False diff -Nru python3-sympy-0.7.2/sympy/core/tests/test_eval.py python3-sympy-0.7.3/sympy/core/tests/test_eval.py --- python3-sympy-0.7.2/sympy/core/tests/test_eval.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/core/tests/test_eval.py 2013-07-13 17:53:32.000000000 +0000 @@ -7,23 +7,25 @@ b = Symbol("b") c = Rational(1) p = Rational(5) - assert a*b+c+p == a*b+6 - assert c+a+p == a+6 - assert c+a-p == a+(-4) - assert a+a == 2*a - assert a+p+a == 2*a+5 - assert c+p == Rational(6) - assert b+a-b == a + assert a*b + c + p == a*b + 6 + assert c + a + p == a + 6 + assert c + a - p == a + (-4) + assert a + a == 2*a + assert a + p + a == 2*a + 5 + assert c + p == Rational(6) + assert b + a - b == a + def test_addmul_eval(): a = Symbol("a") b = Symbol("b") c = Rational(1) p = Rational(5) - assert c+a+b*c+a-p == 2*a+b+(-4) - assert a*2+p+a == a*2+5+a - assert a*2+p+a == 3*a+5 - assert a*2+a == 3*a + assert c + a + b*c + a - p == 2*a + b + (-4) + assert a*2 + p + a == a*2 + 5 + a + assert a*2 + p + a == 3*a + 5 + assert a*2 + a == 3*a + def test_pow_eval(): # XXX Pow does not fully support conversion of negative numbers @@ -33,35 +35,39 @@ assert sqrt(-4) == 2*I assert sqrt( 4) == 2 - assert (8)**Rational(1,3) == 2 - assert (-8)**Rational(1,3) == 2*((-1)**Rational(1,3)) + assert (8)**Rational(1, 3) == 2 + assert (-8)**Rational(1, 3) == 2*((-1)**Rational(1, 3)) assert sqrt(-2) == I*sqrt(2) - assert (-1)**Rational(1,3) != I - assert (-10)**Rational(1,3) != I*((10)**Rational(1,3)) - assert (-2)**Rational(1,4) != (2)**Rational(1,4) + assert (-1)**Rational(1, 3) != I + assert (-10)**Rational(1, 3) != I*((10)**Rational(1, 3)) + assert (-2)**Rational(1, 4) != (2)**Rational(1, 4) - assert 64**Rational(1,3) == 4 - assert 64**Rational(2,3) == 16 + assert 64**Rational(1, 3) == 4 + assert 64**Rational(2, 3) == 16 assert 24/sqrt(64) == 3 - assert (-27)**Rational(1,3) == 3*(-1)**Rational(1,3) + assert (-27)**Rational(1, 3) == 3*(-1)**Rational(1, 3) assert (cos(2) / tan(2))**2 == (cos(2) / tan(2))**2 + @XFAIL def test_pow_eval_X1(): - assert (-1)**Rational(1,3) == Rational(1,2)+Rational(1,2)*I*sqrt(3) + assert (-1)**Rational(1, 3) == Rational(1, 2) + Rational(1, 2)*I*sqrt(3) + def test_mulpow_eval(): x = Symbol('x') assert sqrt(50)/(sqrt(2)*x) == 5/x assert sqrt(27)/sqrt(3) == 3 + def test_evalpow_bug(): x = Symbol("x") assert 1/(1/x) == x assert 1/(-1/x) == -x + def test_symbol_expand(): x = Symbol('x') y = Symbol('y') @@ -75,8 +81,9 @@ assert g.expand() == f assert g.expand() == g.expand().expand() + def test_function(): f = Function('f') - l,x = list(map(Symbol, 'lx')) + l, x = list(map(Symbol, 'lx')) assert exp(l(x))*l(x)/exp(l(x)) == l(x) assert exp(f(x))*f(x)/exp(f(x)) == f(x) diff -Nru python3-sympy-0.7.2/sympy/core/tests/test_eval_power.py python3-sympy-0.7.3/sympy/core/tests/test_eval_power.py --- python3-sympy-0.7.2/sympy/core/tests/test_eval_power.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/core/tests/test_eval_power.py 2013-07-13 17:53:32.000000000 +0000 @@ -4,9 +4,6 @@ from sympy.functions.elementary.exponential import exp from sympy.utilities.pytest import XFAIL -def test_issue153(): - #test that is runs: - a = sqrt(2*(1+sqrt(2))) def test_rational(): a = Rational(1, 5) @@ -23,58 +20,66 @@ assert a**Rational(17, 3) == r assert 2 * a**Rational(17, 3) == 2*r + def test_large_rational(): - e = (Rational(123712**12-1,7)+Rational(1,7))**Rational(1,3) - assert e == 234232585392159195136 * (Rational(1,7)**Rational(1,3)) + e = (Rational(123712**12 - 1, 7) + Rational(1, 7))**Rational(1, 3) + assert e == 234232585392159195136 * (Rational(1, 7)**Rational(1, 3)) + def test_negative_real(): - def feq(a,b): + def feq(a, b): return abs(a - b) < 1E-10 assert feq(S.One / Float(-0.5), -Integer(2)) + def test_expand(): x = Symbol('x') - assert (2**(-1-x)).expand() == Rational(1,2)*2**(-x) + assert (2**(-1 - x)).expand() == Rational(1, 2)*2**(-x) + def test_issue350(): #test if powers are simplified correctly #see also issue 896 x = Symbol('x') - assert ((x**Rational(1,3))**Rational(2)) == x**Rational(2,3) - assert ((x**Rational(3))**Rational(2,5)) == (x**Rational(3))**Rational(2,5) + assert ((x**Rational(1, 3))**Rational(2)) == x**Rational(2, 3) + assert ( + (x**Rational(3))**Rational(2, 5)) == (x**Rational(3))**Rational(2, 5) a = Symbol('a', real=True) b = Symbol('b', real=True) assert (a**2)**b == (abs(a)**b)**2 - assert sqrt(1/a) != 1/sqrt(a) # e.g. for a = -1 - assert (a**3)**Rational(1,3) != a - assert (x**a)**b != x**(a*b) # e.g. x = -1, a=2, b=1/2 + assert sqrt(1/a) != 1/sqrt(a) # e.g. for a = -1 + assert (a**3)**Rational(1, 3) != a + assert (x**a)**b != x**(a*b) # e.g. x = -1, a=2, b=1/2 assert (x**.5)**b == x**(.5*b) assert (x**.5)**.5 == x**.25 - assert (x**2.5)**.5 != x**1.25 # e.g. for x = 5*I + assert (x**2.5)**.5 != x**1.25 # e.g. for x = 5*I - k = Symbol('k',integer=True) - m = Symbol('m',integer=True) + k = Symbol('k', integer=True) + m = Symbol('m', integer=True) assert (x**k)**m == x**(k*m) - assert Number(5)**Rational(2,3)==Number(25)**Rational(1,3) + assert Number(5)**Rational(2, 3) == Number(25)**Rational(1, 3) assert (x**.5)**2 == x**1.0 assert (x**2)**k == (x**k)**2 == x**(2*k) a = Symbol('a', positive=True) - assert (a**3)**Rational(2,5) == a**Rational(6,5) + assert (a**3)**Rational(2, 5) == a**Rational(6, 5) assert (a**2)**b == (a**b)**2 assert (a**Rational(2, 3))**x == (a**(2*x/3)) != (a**x)**Rational(2, 3) + def test_issue767(): - assert --sqrt(sqrt(5)-1)==sqrt(sqrt(5)-1) + assert --sqrt(sqrt(5) - 1) == sqrt(sqrt(5) - 1) + def test_negative_one(): x = Symbol('x', complex=True) y = Symbol('y', complex=True) assert 1/x**y == x**(-y) + def test_issue1263(): neg = Symbol('neg', negative=True) nonneg = Symbol('nonneg', nonnegative=True) @@ -91,58 +96,75 @@ def eqn(num, den, pow): return (num/den)**pow - npos=1 - nneg=-1 - dpos=2-sqrt(3) - dneg=1-sqrt(3) + npos = 1 + nneg = -1 + dpos = 2 - sqrt(3) + dneg = 1 - sqrt(3) assert dpos > 0 and dneg < 0 and npos > 0 and nneg < 0 # pos or neg integer - eq=eqn(npos, dpos, 2);assert eq.is_Pow and eq.as_numer_denom() == (1, dpos**2) - eq=eqn(npos, dneg, 2);assert eq.is_Pow and eq.as_numer_denom() == (1, dneg**2) - eq=eqn(nneg, dpos, 2);assert eq.is_Pow and eq.as_numer_denom() == (1, dpos**2) - eq=eqn(nneg, dneg, 2);assert eq.is_Pow and eq.as_numer_denom() == (1, dneg**2) - eq=eqn(npos, dpos, -2);assert eq.is_Pow and eq.as_numer_denom() == (dpos**2, 1) - eq=eqn(npos, dneg, -2);assert eq.is_Pow and eq.as_numer_denom() == (dneg**2, 1) - eq=eqn(nneg, dpos, -2);assert eq.is_Pow and eq.as_numer_denom() == (dpos**2, 1) - eq=eqn(nneg, dneg, -2);assert eq.is_Pow and eq.as_numer_denom() == (dneg**2, 1) + eq = eqn(npos, dpos, 2) + assert eq.is_Pow and eq.as_numer_denom() == (1, dpos**2) + eq = eqn(npos, dneg, 2) + assert eq.is_Pow and eq.as_numer_denom() == (1, dneg**2) + eq = eqn(nneg, dpos, 2) + assert eq.is_Pow and eq.as_numer_denom() == (1, dpos**2) + eq = eqn(nneg, dneg, 2) + assert eq.is_Pow and eq.as_numer_denom() == (1, dneg**2) + eq = eqn(npos, dpos, -2) + assert eq.is_Pow and eq.as_numer_denom() == (dpos**2, 1) + eq = eqn(npos, dneg, -2) + assert eq.is_Pow and eq.as_numer_denom() == (dneg**2, 1) + eq = eqn(nneg, dpos, -2) + assert eq.is_Pow and eq.as_numer_denom() == (dpos**2, 1) + eq = eqn(nneg, dneg, -2) + assert eq.is_Pow and eq.as_numer_denom() == (dneg**2, 1) # pos or neg rational pow = S.Half - eq=eqn(npos, dpos, pow);assert eq.is_Pow and eq.as_numer_denom() == (npos**pow, dpos**pow) - eq=eqn(npos, dneg, pow);assert eq.is_Pow and eq.as_numer_denom() == ((-npos)**pow, (-dneg)**pow) - eq=eqn(nneg, dpos, pow);assert not eq.is_Pow or eq.as_numer_denom() == (nneg**pow, dpos**pow) - eq=eqn(nneg, dneg, pow);assert eq.is_Pow and eq.as_numer_denom() == ((-nneg)**pow, (-dneg)**pow) - eq=eqn(npos, dpos, -pow);assert eq.is_Pow and eq.as_numer_denom() == (dpos**pow, npos**pow) - eq=eqn(npos, dneg, -pow);assert eq.is_Pow and eq.as_numer_denom() == ((-dneg)**pow, (-npos)**pow) - eq=eqn(nneg, dpos, -pow);assert not eq.is_Pow or eq.as_numer_denom() == (dpos**pow, nneg**pow) - eq=eqn(nneg, dneg, -pow);assert eq.is_Pow and eq.as_numer_denom() == ((-dneg)**pow, (-nneg)**pow) + eq = eqn(npos, dpos, pow) + assert eq.is_Pow and eq.as_numer_denom() == (npos**pow, dpos**pow) + eq = eqn(npos, dneg, pow) + assert eq.is_Pow and eq.as_numer_denom() == ((-npos)**pow, (-dneg)**pow) + eq = eqn(nneg, dpos, pow) + assert not eq.is_Pow or eq.as_numer_denom() == (nneg**pow, dpos**pow) + eq = eqn(nneg, dneg, pow) + assert eq.is_Pow and eq.as_numer_denom() == ((-nneg)**pow, (-dneg)**pow) + eq = eqn(npos, dpos, -pow) + assert eq.is_Pow and eq.as_numer_denom() == (dpos**pow, npos**pow) + eq = eqn(npos, dneg, -pow) + assert eq.is_Pow and eq.as_numer_denom() == ((-dneg)**pow, (-npos)**pow) + eq = eqn(nneg, dpos, -pow) + assert not eq.is_Pow or eq.as_numer_denom() == (dpos**pow, nneg**pow) + eq = eqn(nneg, dneg, -pow) + assert eq.is_Pow and eq.as_numer_denom() == ((-dneg)**pow, (-nneg)**pow) # unknown exponent pow = 2*any - eq=eqn(npos, dpos, pow) + eq = eqn(npos, dpos, pow) assert eq.is_Pow and eq.as_numer_denom() == (npos**pow, dpos**pow) - eq=eqn(npos, dneg, pow) + eq = eqn(npos, dneg, pow) assert eq.is_Pow and eq.as_numer_denom() == ((-npos)**pow, (-dneg)**pow) - eq=eqn(nneg, dpos, pow) + eq = eqn(nneg, dpos, pow) assert eq.is_Pow and eq.as_numer_denom() == (nneg**pow, dpos**pow) - eq=eqn(nneg, dneg, pow) + eq = eqn(nneg, dneg, pow) assert eq.is_Pow and eq.as_numer_denom() == ((-nneg)**pow, (-dneg)**pow) - eq=eqn(npos, dpos, -pow) + eq = eqn(npos, dpos, -pow) assert eq.as_numer_denom() == (dpos**pow, npos**pow) - eq=eqn(npos, dneg, -pow) + eq = eqn(npos, dneg, -pow) assert eq.is_Pow and eq.as_numer_denom() == ((-dneg)**pow, (-npos)**pow) - eq=eqn(nneg, dpos, -pow) + eq = eqn(nneg, dpos, -pow) assert eq.is_Pow and eq.as_numer_denom() == (dpos**pow, nneg**pow) - eq=eqn(nneg, dneg, -pow) + eq = eqn(nneg, dneg, -pow) assert eq.is_Pow and eq.as_numer_denom() == ((-dneg)**pow, (-nneg)**pow) x = Symbol('x') y = Symbol('y') assert ((1/(1 + x/3))**(-S.One)).as_numer_denom() == (3 + x, 3) - notp = Symbol('notp', positive=False) # not positive does not imply real + notp = Symbol('notp', positive=False) # not positive does not imply real b = ((1 + x/notp)**-2) assert (b**(-y)).as_numer_denom() == (1, b**y) assert (b**(-S.One)).as_numer_denom() == ((notp + x)**2, notp**2) nonp = Symbol('nonp', nonpositive=True) - assert (((1 + x/nonp)**-2)**(-S.One)).as_numer_denom() == ((-nonp - x)**2, nonp**2) + assert (((1 + x/nonp)**-2)**(-S.One)).as_numer_denom() == ((-nonp - + x)**2, nonp**2) n = Symbol('n', negative=True) assert (x**n).as_numer_denom() == (1, x**-n) @@ -160,15 +182,17 @@ i = Symbol('i', integer=True) assert (((1 + x/y)**i)).as_numer_denom() == ((x + y)**i, y**i) + def test_Pow_signs(): """Cf. issues 1496 and 2151""" x = Symbol('x') y = Symbol('y') n = Symbol('n', even=True) - assert (3-y)**2 != (y-3)**2 - assert (3-y)**n != (y-3)**n - assert (-3+y-x)**2 != (3-y+x)**2 - assert (y-3)**3 != -(3-y)**3 + assert (3 - y)**2 != (y - 3)**2 + assert (3 - y)**n != (y - 3)**n + assert (-3 + y - x)**2 != (3 - y + x)**2 + assert (y - 3)**3 != -(3 - y)**3 + def test_power_with_noncommutative_mul_as_base(): x = Symbol('x', commutative=False) @@ -176,6 +200,7 @@ assert not (x*y)**3 == x**3*y**3 assert (2*x*y)**3 == 8*(x*y)**3 + def test_zero(): x = Symbol('x') y = Symbol('y') @@ -191,6 +216,7 @@ i = Symbol('i', imaginary=True) assert 0**i == nan + def test_pow_as_base_exp(): x = Symbol('x') assert (S.Infinity**(2 - x)).as_base_exp() == (S.Infinity, 2 - x) @@ -198,14 +224,15 @@ p = S.Half**x assert p.base, p.exp == p.as_base_exp() == (S(2), -x) + def test_issue_3001(): x = Symbol('x') y = Symbol('y') assert x**1.0 == x assert x == x**1.0 assert True != x**1.0 - assert x**1.0 != True - assert x != True + assert x**1.0 is not True + assert x is not True assert x*y == (x*y)**1.0 assert (x**1.0)**1.0 == x assert (x**1.0)**2.0 == x**2 @@ -216,18 +243,34 @@ # power-of-1.0 case. assert ((x*y)**1.0).func is Pow + def test_issue_3109(): from sympy import root, Rational I = S.ImaginaryUnit assert sqrt(33**(9*I/10)) == -33**(9*I/20) - assert root((6*I)**(2*I), 3).as_base_exp()[1] == Rational(1, 3) # != 2*I/3 + assert root((6*I)**(2*I), 3).as_base_exp()[1] == Rational(1, 3) # != 2*I/3 assert root((6*I)**(I/3), 3).as_base_exp()[1] == I/9 assert sqrt(exp(3*I)) == exp(3*I/2) assert sqrt(-sqrt(3)*(1 + 2*I)) == sqrt(sqrt(3))*sqrt(-1 - 2*I) - -@XFAIL -def test_issue_3109_fail(): - from sympy import root, Rational - I = S.ImaginaryUnit assert sqrt(exp(5*I)) == -exp(5*I/2) assert root(exp(5*I), 3).exp == Rational(1, 3) + +def test_issue_2969(): + from sympy import sin, O + x = Symbol('x') + assert sqrt(sin(x)).series(x, 0, 7) == \ + sqrt(x) - x**(S(5)/2)/12 + x**(S(9)/2)/1440 - \ + x**(S(13)/2)/24192 + O(x**7) + assert sqrt(sin(x)).series(x, 0, 9) == \ + sqrt(x) - x**(S(5)/2)/12 + x**(S(9)/2)/1440 - \ + x**(S(13)/2)/24192 - 67*x**(S(17)/2)/29030400 + O(x**9) + assert sqrt(sin(x**3)).series(x, 0, 19) == \ + sqrt(x**3) - x**6*sqrt(x**3)/12 + x**12*sqrt(x**3)/1440 + O(x**19) + assert sqrt(sin(x**3)).series(x, 0, 20) == \ + sqrt(x**3) - x**6*sqrt(x**3)/12 + x**12*sqrt(x**3)/1440 - \ + x**18*sqrt(x**3)/24192 + O(x**20) + +@XFAIL +def test_issue_3683(): + assert sqrt(sin(x**3)).series(x, 0, 7) == sqrt(x**3) + O(x**7) + assert sqrt(sin(x**4)).series(x, 0, 3) == sqrt(x**4) + O(x**4) diff -Nru python3-sympy-0.7.2/sympy/core/tests/test_evalf.py python3-sympy-0.7.3/sympy/core/tests/test_evalf.py --- python3-sympy-0.7.2/sympy/core/tests/test_evalf.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/core/tests/test_evalf.py 2013-07-13 17:53:32.000000000 +0000 @@ -7,48 +7,62 @@ from sympy.mpmath.libmp.libmpf import from_float from sympy.utilities.pytest import raises, XFAIL + def NS(e, n=15, **options): return sstr(sympify(e).evalf(n, **options), full_prec=True) + def test_evalf_helpers(): - assert complex_accuracy((from_float(2.0),None,35,None)) == 35 - assert complex_accuracy((from_float(2.0),from_float(10.0),35,100)) == 37 - assert complex_accuracy((from_float(2.0),from_float(1000.0),35,100)) == 43 - assert complex_accuracy((from_float(2.0),from_float(10.0),100,35)) == 35 - assert complex_accuracy((from_float(2.0),from_float(1000.0),100,35)) == 35 + assert complex_accuracy((from_float(2.0), None, 35, None)) == 35 + assert complex_accuracy((from_float(2.0), from_float(10.0), 35, 100)) == 37 + assert complex_accuracy( + (from_float(2.0), from_float(1000.0), 35, 100)) == 43 + assert complex_accuracy((from_float(2.0), from_float(10.0), 100, 35)) == 35 + assert complex_accuracy( + (from_float(2.0), from_float(1000.0), 100, 35)) == 35 + def test_evalf_basic(): - assert NS('pi',15) == '3.14159265358979' - assert NS('2/3',10) == '0.6666666667' - assert NS('355/113-pi',6) == '2.66764e-7' + assert NS('pi', 15) == '3.14159265358979' + assert NS('2/3', 10) == '0.6666666667' + assert NS('355/113-pi', 6) == '2.66764e-7' assert NS('16*atan(1/5)-4*atan(1/239)', 15) == '3.14159265358979' + def test_cancellation(): - assert NS(Add(pi,Rational(1,10**1000),-pi,evaluate=False),15,maxn=1200) == '1.00000000000000e-1000' + assert NS(Add(pi, Rational(1, 10**1000), -pi, evaluate=False), 15, + maxn=1200) == '1.00000000000000e-1000' + def test_evalf_powers(): - assert NS('pi**(10**20)',10) == '1.339148777e+49714987269413385435' - assert NS(pi**(10**100),10) == ('4.946362032e+4971498726941338543512682882' + assert NS('pi**(10**20)', 10) == '1.339148777e+49714987269413385435' + assert NS(pi**(10**100), 10) == ('4.946362032e+4971498726941338543512682882' '9089887365167832438044244613405349992494711208' '95526746555473864642912223') - assert NS('2**(1/10**50)',15) == '1.00000000000000' - assert NS('2**(1/10**50)-1',15) == '6.93147180559945e-51' + assert NS('2**(1/10**50)', 15) == '1.00000000000000' + assert NS('2**(1/10**50)-1', 15) == '6.93147180559945e-51' # Evaluation of Rump's ill-conditioned polynomial + + def test_evalf_rump(): - a = 1335*y**6/4+x**2*(11*x**2*y**2-y**6-121*y**4-2)+11*y**8/2+x/(2*y) - assert NS(a, 15, subs={x:77617, y:33096}) == '-0.827396059946821' + a = 1335*y**6/4 + x**2*(11*x**2*y**2 - y**6 - 121*y**4 - 2) + 11*y**8/2 + x/(2*y) + assert NS(a, 15, subs={x: 77617, y: 33096}) == '-0.827396059946821' + def test_evalf_complex(): - assert NS('2*sqrt(pi)*I',10) == '3.544907702*I' - assert NS('3+3*I',15) == '3.00000000000000 + 3.00000000000000*I' - assert NS('E+pi*I',15) == '2.71828182845905 + 3.14159265358979*I' - assert NS('pi * (3+4*I)',15) == '9.42477796076938 + 12.5663706143592*I' - assert NS('I*(2+I)',15) == '-1.00000000000000 + 2.00000000000000*I' + assert NS('2*sqrt(pi)*I', 10) == '3.544907702*I' + assert NS('3+3*I', 15) == '3.00000000000000 + 3.00000000000000*I' + assert NS('E+pi*I', 15) == '2.71828182845905 + 3.14159265358979*I' + assert NS('pi * (3+4*I)', 15) == '9.42477796076938 + 12.5663706143592*I' + assert NS('I*(2+I)', 15) == '-1.00000000000000 + 2.00000000000000*I' + @XFAIL def test_evalf_complex_bug(): - assert NS('(pi+E*I)*(E+pi*I)',15) in ('0.e-15 + 17.25866050002*I', '0.e-17 + 17.25866050002*I', '-0.e-17 + 17.25866050002*I') + assert NS('(pi+E*I)*(E+pi*I)', 15) in ('0.e-15 + 17.25866050002*I', + '0.e-17 + 17.25866050002*I', '-0.e-17 + 17.25866050002*I') + def test_evalf_complex_powers(): assert NS('(E+pi*I)**100000000000000000') == \ @@ -56,30 +70,38 @@ # XXX: rewrite if a+a*I simplification introduced in sympy #assert NS('(pi + pi*I)**2') in ('0.e-15 + 19.7392088021787*I', '0.e-16 + 19.7392088021787*I') assert NS('(pi + pi*I)**2', chop=True) == '19.7392088021787*I' - assert NS('(pi + 1/10**8 + pi*I)**2') == '6.2831853e-8 + 19.7392088650106*I' + assert NS( + '(pi + 1/10**8 + pi*I)**2') == '6.2831853e-8 + 19.7392088650106*I' assert NS('(pi + 1/10**12 + pi*I)**2') == '6.283e-12 + 19.7392088021850*I' assert NS('(pi + pi*I)**4', chop=True) == '-389.636364136010' - assert NS('(pi + 1/10**8 + pi*I)**4') == '-389.636366616512 + 2.4805021e-6*I' + assert NS( + '(pi + 1/10**8 + pi*I)**4') == '-389.636366616512 + 2.4805021e-6*I' assert NS('(pi + 1/10**12 + pi*I)**4') == '-389.636364136258 + 2.481e-10*I' - assert NS('(10000*pi + 10000*pi*I)**4', chop=True) == '-3.89636364136010e+18' + assert NS( + '(10000*pi + 10000*pi*I)**4', chop=True) == '-3.89636364136010e+18' + @XFAIL def test_evalf_complex_powers_bug(): assert NS('(pi + pi*I)**4') == '-389.63636413601 + 0.e-14*I' + def test_evalf_exponentiation(): assert NS(sqrt(-pi)) == '1.77245385090552*I' - assert NS(Pow(pi*I, Rational(1,2), evaluate=False)) == '1.25331413731550 + 1.25331413731550*I' + assert NS(Pow(pi*I, Rational( + 1, 2), evaluate=False)) == '1.25331413731550 + 1.25331413731550*I' assert NS(pi**I) == '0.413292116101594 + 0.910598499212615*I' - assert NS(pi**(E+I/3)) == '20.8438653991931 + 8.36343473930031*I' - assert NS((pi+I/3)**(E+I/3)) == '17.2442906093590 + 13.6839376767037*I' + assert NS(pi**(E + I/3)) == '20.8438653991931 + 8.36343473930031*I' + assert NS((pi + I/3)**(E + I/3)) == '17.2442906093590 + 13.6839376767037*I' assert NS(exp(pi)) == '23.1406926327793' - assert NS(exp(pi+E*I)) == '-21.0981542849657 + 9.50576358282422*I' + assert NS(exp(pi + E*I)) == '-21.0981542849657 + 9.50576358282422*I' assert NS(pi**pi) == '36.4621596072079' assert NS((-pi)**pi) == '-32.9138577418939 - 15.6897116534332*I' assert NS((-pi)**(-pi)) == '-0.0247567717232697 + 0.0118013091280262*I' # An example from Smith, "Multiple Precision Complex Arithmetic and Functions" + + def test_evalf_complex_cancellation(): A = Rational('63287/100000') B = Rational('52498/100000') @@ -93,73 +115,113 @@ # 64471/10000000000 + 2231321613*I/2500000000 # >>> 2231321613*4 # 8925286452L - assert NS((A+B*I)*(C+D*I), 6) == '6.44710e-6 + 0.892529*I' - assert NS((A+B*I)*(C+D*I), 10) == '6.447100000e-6 + 0.8925286452*I' - assert NS((A+B*I)*(C+D*I) - F*I, 5) in ('6.4471e-6 + 0.e-14*I', '6.4471e-6 - 0.e-14*I') + assert NS((A + B*I)*(C + D*I), 6) == '6.44710e-6 + 0.892529*I' + assert NS((A + B*I)*(C + D*I), 10) == '6.447100000e-6 + 0.8925286452*I' + assert NS((A + B*I)*( + C + D*I) - F*I, 5) in ('6.4471e-6 + 0.e-14*I', '6.4471e-6 - 0.e-14*I') + def test_evalf_logs(): assert NS("log(3+pi*I)", 15) == '1.46877619736226 + 0.808448792630022*I' assert NS("log(pi*I)", 15) == '1.14472988584940 + 1.57079632679490*I' + def test_evalf_trig(): - assert NS('sin(1)',15) == '0.841470984807897' - assert NS('cos(1)',15) == '0.540302305868140' - assert NS('sin(10**-6)',15) == '9.99999999999833e-7' - assert NS('cos(10**-6)',15) == '0.999999999999500' - assert NS('sin(E*10**100)',15) == '0.409160531722613' + assert NS('sin(1)', 15) == '0.841470984807897' + assert NS('cos(1)', 15) == '0.540302305868140' + assert NS('sin(10**-6)', 15) == '9.99999999999833e-7' + assert NS('cos(10**-6)', 15) == '0.999999999999500' + assert NS('sin(E*10**100)', 15) == '0.409160531722613' # Some input near roots assert NS(sin(exp(pi*sqrt(163))*pi), 15) == '-2.35596641936785e-12' - assert NS(sin(pi*10**100 + Rational(7,10**5), evaluate=False), 15, maxn=120) == \ + assert NS(sin(pi*10**100 + Rational(7, 10**5), evaluate=False), 15, maxn=120) == \ '6.99999999428333e-5' - assert NS(sin(Rational(7,10**5), evaluate=False), 15) == \ + assert NS(sin(Rational(7, 10**5), evaluate=False), 15) == \ '6.99999999428333e-5' # Check detection of various false identities + + def test_evalf_near_integers(): # Binet's formula - f = lambda n: ((1+sqrt(5))**n)/(2**n * sqrt(5)) + f = lambda n: ((1 + sqrt(5))**n)/(2**n * sqrt(5)) assert NS(f(5000) - fibonacci(5000), 10, maxn=1500) == '5.156009964e-1046' # Some near-integer identities from # http://mathworld.wolfram.com/AlmostInteger.html - assert NS('sin(2017*2**(1/5))',15) == '-1.00000000000000' - assert NS('sin(2017*2**(1/5))',20) == '-0.99999999999999997857' - assert NS('1+sin(2017*2**(1/5))',15) == '2.14322287389390e-17' + assert NS('sin(2017*2**(1/5))', 15) == '-1.00000000000000' + assert NS('sin(2017*2**(1/5))', 20) == '-0.99999999999999997857' + assert NS('1+sin(2017*2**(1/5))', 15) == '2.14322287389390e-17' assert NS('45 - 613*E/37 + 35/991', 15) == '6.03764498766326e-11' + def test_evalf_ramanujan(): assert NS(exp(pi*sqrt(163)) - 640320**3 - 744, 10) == '-7.499274028e-13' # A related identity A = 262537412640768744*exp(-pi*sqrt(163)) B = 196884*exp(-2*pi*sqrt(163)) C = 103378831900730205293632*exp(-3*pi*sqrt(163)) - assert NS(1-A-B+C,10) == '1.613679005e-59' + assert NS(1 - A - B + C, 10) == '1.613679005e-59' # Input that for various reasons have failed at some point + + def test_evalf_bugs(): - assert NS(sin(1)+exp(-10**10),10) == NS(sin(1),10) - assert NS(exp(10**10)+sin(1),10) == NS(exp(10**10),10) - assert NS('log(1+1/10**50)',20) == '1.0000000000000000000e-50' - assert NS('log(10**100,10)',10) == '100.0000000' - assert NS('log(2)',10) == '0.6931471806' - assert NS('(sin(x)-x)/x**3', 15, subs={x:'1/10**50'}) == '-0.166666666666667' - assert NS(sin(1)+Rational(1,10**100)*I,15) == '0.841470984807897 + 1.00000000000000e-100*I' + assert NS(sin(1) + exp(-10**10), 10) == NS(sin(1), 10) + assert NS(exp(10**10) + sin(1), 10) == NS(exp(10**10), 10) + assert NS('log(1+1/10**50)', 20) == '1.0000000000000000000e-50' + assert NS('log(10**100,10)', 10) == '100.0000000' + assert NS('log(2)', 10) == '0.6931471806' + assert NS( + '(sin(x)-x)/x**3', 15, subs={x: '1/10**50'}) == '-0.166666666666667' + assert NS(sin(1) + Rational( + 1, 10**100)*I, 15) == '0.841470984807897 + 1.00000000000000e-100*I' assert x.evalf() == x - assert NS((1+I)**2*I, 6) == '-2.00000' - d={n: (-1)**Rational(6,7), y: (-1)**Rational(4,7), x: (-1)**Rational(2,7)} - assert NS((x*(1+y*(1 + n))).subs(d).evalf(),6) == '0.346011 + 0.433884*I' - assert NS(((-I-sqrt(2)*I)**2).evalf()) == '-5.82842712474619' - assert NS((1+I)**2*I,15) == '-2.00000000000000' + assert NS((1 + I)**2*I, 6) == '-2.00000' + d = {n: ( + -1)**Rational(6, 7), y: (-1)**Rational(4, 7), x: (-1)**Rational(2, 7)} + assert NS((x*(1 + y*(1 + n))).subs(d).evalf(), 6) == '0.346011 + 0.433884*I' + assert NS(((-I - sqrt(2)*I)**2).evalf()) == '-5.82842712474619' + assert NS((1 + I)**2*I, 15) == '-2.00000000000000' #1659 (1/2): assert NS(pi.evalf(69) - pi) == '-4.43863937855894e-71' #1659 (2/2): With the bug present, this still only fails if the # terms are in the order given here. This is not generally the case, # because the order depends on the hashes of the terms. assert NS(20 - 5008329267844*n**25 - 477638700*n**37 - 19*n, - subs={n:.01}) == '19.8100000000000' - assert NS(((x - 1)*((1 - x))**1000).n()) == '(-x + 1.00000000000000)**1000*(x - 1.00000000000000)' + subs={n: .01}) == '19.8100000000000' + assert NS(((x - 1)*((1 - x))**1000).n() + ) == '(-x + 1.00000000000000)**1000*(x - 1.00000000000000)' assert NS((-x).n()) == '-x' assert NS((-2*x).n()) == '-2.00000000000000*x' assert NS((-2*x*y).n()) == '-2.00000000000000*x*y' + assert cos(x).n(subs={x: 1+I}) == cos(x).subs(x, 1+I).n() + #3561. Also NaN != mpmath.nan + # In this order: + # 0*nan, 0/nan, 0*inf, 0/inf + # 0+nan, 0-nan, 0+inf, 0-inf + # >>> n = Some Number + # n*nan, n/nan, n*inf, n/inf + # n+nan, n-nan, n+inf, n-inf + assert (0*sin(oo)).n() == S.Zero + assert (0/sin(oo)).n() == S.Zero + assert (0*E**(oo)).n() == S.NaN + assert (0/E**(oo)).n() == S.Zero + + assert (0+sin(oo)).n() == S.NaN + assert (0-sin(oo)).n() == S.NaN + assert (0+E**(oo)).n() == S.Infinity + assert (0-E**(oo)).n() == S.NegativeInfinity + + assert (5*sin(oo)).n() == S.NaN + assert (5/sin(oo)).n() == S.NaN + assert (5*E**(oo)).n() == S.Infinity + assert (5/E**(oo)).n() == S.Zero + + assert (5+sin(oo)).n() == S.NaN + assert (5-sin(oo)).n() == S.NaN + assert (5+E**(oo)).n() == S.Infinity + assert (5-E**(oo)).n() == S.NegativeInfinity + def test_evalf_integer_parts(): a = floor(log(8)/log(2) - exp(-1000), evaluate=False) @@ -171,12 +233,15 @@ # equals, as a fallback, can still fail but it might succeed as here assert ceiling(10*(sin(1)**2 + cos(1)**2)) == 10 - assert int(floor(factorial(50)/E,evaluate=False).evalf()) == \ + assert int(floor(factorial(50)/E, evaluate=False).evalf(70)) == \ 11188719610782480504630258070757734324011354208865721592720336800 - assert int(ceiling(factorial(50)/E,evaluate=False).evalf()) == \ + assert int(ceiling(factorial(50)/E, evaluate=False).evalf(70)) == \ 11188719610782480504630258070757734324011354208865721592720336801 - assert int(floor((GoldenRatio**999 / sqrt(5) + Rational(1,2))).evalf(1000)) == fibonacci(999) - assert int(floor((GoldenRatio**1000 / sqrt(5) + Rational(1,2))).evalf(1000)) == fibonacci(1000) + assert int(floor((GoldenRatio**999 / sqrt(5) + Rational(1, 2))) + .evalf(1000)) == fibonacci(999) + assert int(floor((GoldenRatio**1000 / sqrt(5) + Rational(1, 2))) + .evalf(1000)) == fibonacci(1000) + def test_evalf_trig_zero_detection(): a = sin(160*pi, evaluate=False) @@ -186,36 +251,42 @@ assert a.evalf(chop=True) == 0 raises(PrecisionExhausted, lambda: a.evalf(strict=True)) + def test_evalf_divergent_series(): raises(ValueError, lambda: Sum(1/n, (n, 1, oo)).evalf()) - raises(ValueError, lambda: Sum(n/(n**2+1), (n, 1, oo)).evalf()) + raises(ValueError, lambda: Sum(n/(n**2 + 1), (n, 1, oo)).evalf()) raises(ValueError, lambda: Sum((-1)**n, (n, 1, oo)).evalf()) raises(ValueError, lambda: Sum((-1)**n, (n, 1, oo)).evalf()) raises(ValueError, lambda: Sum(n**2, (n, 1, oo)).evalf()) raises(ValueError, lambda: Sum(2**n, (n, 1, oo)).evalf()) raises(ValueError, lambda: Sum((-2)**n, (n, 1, oo)).evalf()) - raises(ValueError, lambda: Sum((2*n+3)/(3*n**2+4), (n,0, oo)).evalf()) - raises(ValueError, lambda: Sum((0.5*n**3)/(n**4+1),(n,0,oo)).evalf()) + raises(ValueError, lambda: Sum((2*n + 3)/(3*n**2 + 4), (n, 0, oo)).evalf()) + raises(ValueError, lambda: Sum((0.5*n**3)/(n**4 + 1), (n, 0, oo)).evalf()) + def test_evalf_py_methods(): - assert abs(float(pi+1) - 4.1415926535897932) < 1e-10 - assert abs(complex(pi+1) - 4.1415926535897932) < 1e-10 - assert abs(complex(pi+E*I) - (3.1415926535897931+2.7182818284590451j)) < 1e-10 - raises(TypeError, lambda: float(pi+x)) + assert abs(float(pi + 1) - 4.1415926535897932) < 1e-10 + assert abs(complex(pi + 1) - 4.1415926535897932) < 1e-10 + assert abs( + complex(pi + E*I) - (3.1415926535897931 + 2.7182818284590451j)) < 1e-10 + raises(TypeError, lambda: float(pi + x)) + def test_evalf_power_subs_bugs(): - assert (x**2).evalf(subs={x:0}) == 0 - assert sqrt(x).evalf(subs={x:0}) == 0 - assert (x**Rational(2,3)).evalf(subs={x:0}) == 0 - assert (x**x).evalf(subs={x:0}) == 1 - assert (3**x).evalf(subs={x:0}) == 1 - assert exp(x).evalf(subs={x:0}) == 1 - assert ((2+I)**x).evalf(subs={x:0}) == 1 - assert (0**x).evalf(subs={x:0}) == 1 + assert (x**2).evalf(subs={x: 0}) == 0 + assert sqrt(x).evalf(subs={x: 0}) == 0 + assert (x**Rational(2, 3)).evalf(subs={x: 0}) == 0 + assert (x**x).evalf(subs={x: 0}) == 1 + assert (3**x).evalf(subs={x: 0}) == 1 + assert exp(x).evalf(subs={x: 0}) == 1 + assert ((2 + I)**x).evalf(subs={x: 0}) == 1 + assert (0**x).evalf(subs={x: 0}) == 1 + def test_evalf_arguments(): raises(TypeError, lambda: pi.evalf(method="garbage")) + def test_implemented_function_evalf(): from sympy.utilities.lambdify import implemented_function f = Function('f') @@ -226,6 +297,7 @@ assert f(x).evalf() == f(x) del f._imp_ # XXX: due to caching _imp_ would influence all other tests + def test_evaluate_false(): for no in [0, False, None]: assert Add(3, 2, evaluate=no).is_Add @@ -233,30 +305,36 @@ assert Pow(3, 2, evaluate=no).is_Pow assert Pow(y, 2, evaluate=True) - Pow(y, 2, evaluate=True) == 0 + def test_evalf_relational(): assert Eq(x/5, y/10).evalf() == Eq(0.2*x, 0.1*y) + def test_issue_2387(): assert not cos(sqrt(0.5 + I)).n().is_Function + def test_issue_2387_bug(): from sympy import I, Expr assert abs(Expr._from_mpmath(I._to_mpmath(15), 15) - I) < 1.0e-15 + def test_bugs(): from sympy import polar_lift, re - assert abs(re((1+I)**2)) < 1e-15 + assert abs(re((1 + I)**2)) < 1e-15 # anything that evalf's to 0 will do in place of polar_lift assert abs(polar_lift(0)).n() == 0 + def test_subs_bugs(): from sympy import besseli - assert NS('besseli(-x, y) - besseli(x, y)', subs={x:3.5, y:20.0}) == \ - '-4.92535585957223e-10' - assert NS('Piecewise((x, x>0)) + Piecewise((1-x, x>0))', subs={x:0.1}) == \ - '1.00000000000000' + assert NS('besseli(-x, y) - besseli(x, y)', subs={x: 3.5, y: 20.0}) == \ + '-4.92535585957223e-10' + assert NS('Piecewise((x, x>0)) + Piecewise((1-x, x>0))', subs={x: 0.1}) == \ + '1.00000000000000' + def test_issue_1857_2105(): # 1857 @@ -281,20 +359,24 @@ assert NS(v, 5) == '0.077284 + 1.1104*I' assert NS(v, 1) == '0.08 + 1.*I' + def test_old_docstring(): a = (E + pi*I)*(E - pi*I) assert NS(a) == '17.2586605000200' assert a.n() == 17.25866050002001 + def test_issue_1707(): assert integrate(atan(x)**2, (x, -1, 1)).evalf().round(1) == 0.5 assert atan(0, evaluate=False).n() == 0 + def test_evalf_mul(): # sympy should not try to expand this; it should be handled term-wise # in evalf through mpmath assert NS(product(1 + sqrt(n)*I, (n, 1, 500)), 1) == '5.e+567 + 2.e+568*I' + def test_scaled_zero(): a, b = (([0], 1, 100, 1), -1) assert scaled_zero(100) == (a, b) @@ -307,11 +389,23 @@ raises(ValueError, lambda: scaled_zero(100, 0)) raises(ValueError, lambda: scaled_zero((1, 5, 1, 3))) + def test_chop_value(): for i in range(-27, 28): assert (Pow(10, i)*2).n(chop=10**i) and not (Pow(10, i)).n(chop=10**i) + def test_infinities(): assert oo.evalf(chop=True) == inf assert (-oo).evalf(chop=True) == ninf - assert S.NaN.evalf(chop=True) == nan + + +def test_to_mpmath(): + assert sqrt(3)._to_mpmath(20)._mpf_ == (0, 908093, -19, 20) + assert S(3.2)._to_mpmath(20)._mpf_ == (0, 838861, -18, 20) + + +def test_issue_3533_evalf(): + add = (-100000*sqrt(2500000001) + 5000000001) + assert add.n() == 9.999999998e-11 + assert (add*add).n() == 9.999999996e-21 diff -Nru python3-sympy-0.7.2/sympy/core/tests/test_expand.py python3-sympy-0.7.3/sympy/core/tests/test_expand.py --- python3-sympy-0.7.2/sympy/core/tests/test_expand.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/core/tests/test_expand.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,51 +1,91 @@ -from sympy import (log, sqrt, Rational as R, Symbol, I, exp, pi, S, re, im, - Tuple, sin) - +from sympy import (log, sqrt, Rational as R, Symbol, I, exp, pi, S, + cos, sin, Mul, Pow, cse, O) from sympy.simplify.simplify import expand_numer, expand +from sympy.core.function import ( + expand_power_base, expand_multinomial) + from sympy.utilities.pytest import raises -from sympy.core.function import (expand_mul, expand_multinomial, expand_log, - expand_func, expand_trig, expand_complex, expand_power_base, - expand_power_exp) +from sympy.core.function import expand_power_base +from sympy.utilities.randtest import test_numerically from sympy.abc import x, y, z + def test_expand_no_log(): - assert ((1+log(x**4))**2).expand(log=False) == 1 + 2*log(x**4) + log(x**4)**2 - assert ((1+log(x**4))*(1+log(x**3))).expand(log=False) == 1 + log(x**4) + log(x**3) + log(x**4)*log(x**3) + assert ( + (1 + log(x**4))**2).expand(log=False) == 1 + 2*log(x**4) + log(x**4)**2 + assert ((1 + log(x**4))*(1 + log(x**3))).expand( + log=False) == 1 + log(x**4) + log(x**3) + log(x**4)*log(x**3) + def test_expand_no_multinomial(): - assert ((1+x)*(1+(1+x)**4)).expand(multinomial=False) == 1 + x + (1+x)**4 + x*(1+x)**4 + assert ((1 + x)*(1 + (1 + x)**4)).expand(multinomial=False) == \ + 1 + x + (1 + x)**4 + x*(1 + x)**4 + def test_expand_negative_integer_powers(): - expr = (x+y)**(-2) + expr = (x + y)**(-2) assert expr.expand() == 1 / (2*x*y + x**2 + y**2) - assert expr.expand(multinomial=False) == (x+y)**(-2) - expr = (x+y)**(-3) + assert expr.expand(multinomial=False) == (x + y)**(-2) + expr = (x + y)**(-3) assert expr.expand() == 1 / (3*x*x*y + 3*x*y*y + x**3 + y**3) - assert expr.expand(multinomial=False) == (x+y)**(-3) - expr = (x+y)**(2) * (x+y)**(-4) + assert expr.expand(multinomial=False) == (x + y)**(-3) + expr = (x + y)**(2) * (x + y)**(-4) assert expr.expand() == 1 / (2*x*y + x**2 + y**2) - assert expr.expand(multinomial=False) == (x+y)**(-2) + assert expr.expand(multinomial=False) == (x + y)**(-2) + def test_expand_non_commutative(): - A = x = Symbol('x', commutative=False) - B = y = Symbol('y', commutative=False) + A = Symbol('A', commutative=False) + B = Symbol('B', commutative=False) + C = Symbol('C', commutative=False) a = Symbol('a') + b = Symbol('b') i = Symbol('i', integer=True) - assert ((x + y)**2).expand() == x*y + y*x + x**2 + y**2 - assert ((x + y)**3).expand() == (x**2*y + y**2*x + x*y**2 + y*x**2 + - x**3 + y**3 + x*y*x + y*x*y) + n = Symbol('n', negative=True) + m = Symbol('m', negative=True) + p = Symbol('p', polar=True) + np = Symbol('p', polar=False) + + assert (C*(A + B)).expand() == C*A + C*B + assert (C*(A + B)).expand() != A*C + B*C + assert ((A + B)**2).expand() == A**2 + A*B + B*A + B**2 + assert ((A + B)**3).expand() == (A**2*B + B**2*A + A*B**2 + B*A**2 + + A**3 + B**3 + A*B*A + B*A*B) # 3120 - assert ((a*A*B*A**-1)**2).expand() == a**2*A*B**2*A**(-1) + assert ((a*A*B*A**-1)**2).expand() == a**2*A*B**2/A # Note that (a*A*B*A**-1)**2 is automatically converted to a**2*(A*B*A**-1)**2 assert ((a*A*B*A**-1)**2).expand(deep=False) == a**2*(A*B*A**-1)**2 + assert ((a*A*B*A**-1)**2).expand() == a**2*(A*B**2*A**-1) assert ((a*A*B*A**-1)**2).expand(force=True) == a**2*A*B**2*A**(-1) assert ((a*A*B)**2).expand() == a**2*A*B*A*B assert ((a*A)**2).expand() == a**2*A**2 assert ((a*A*B)**i).expand() == a**i*(A*B)**i + assert ((a*A*(B*(A*B/A)**2))**i).expand() == a**i*(A*B*A*B**2/A)**i + # 3459 + assert (A*B*(A*B)**-1).expand() == A*B*(A*B)**-1 + assert ((a*A)**i).expand() == a**i*A**i + assert ((a*A*B*A**-1)**3).expand() == a**3*A*B**3/A + assert ((a*A*B*A*B/A)**3).expand() == \ + a**3*A*B*(A*B**2)*(A*B**2)*A*B*A**(-1) + assert ((a*A*B*A*B/A)**-3).expand() == \ + a**-3*(A*B*(A*B**2)*(A*B**2)*A*B*A**(-1))**-1 + assert ((a*b*A*B*A**-1)**i).expand() == a**i*b**i*(A*B/A)**i + assert ((a*(a*b)**i)**i).expand() == a**i*a**(i**2)*b**(i**2) + e = Pow(Mul(a, 1/a, A, B, evaluate=False), S(2), evaluate=False) + assert e.expand() == A*B*A*B + assert sqrt(a*(A*b)**i).expand() == sqrt(a*b**i*A**i) + assert (sqrt(-a)**a).expand() == sqrt(-a)**a + assert expand((-2*n)**(i/3)) == 2**(i/3)*(-n)**(i/3) + assert expand((-2*n*m)**(i/a)) == (-2)**(i/a)*(-n)**(i/a)*(-m)**(i/a) + assert expand((-2*a*p)**b) == 2**b*p**b*(-a)**b + assert expand((-2*a*np)**b) == 2**b*(-a*np)**b + assert expand(sqrt(A*B)) == sqrt(A*B) + assert expand(sqrt(-2*a*b)) == sqrt(2)*sqrt(-a*b) + def test_expand_radicals(): - a = (x + y)**R(1,2) + a = (x + y)**R(1, 2) assert (a**1).expand() == a assert (a**3).expand() == x*a + y*a @@ -55,7 +95,7 @@ assert (1/a**3).expand() == 1/(x*a + y*a) assert (1/a**5).expand() == 1/(x**2*a + 2*x*y*a + y**2*a) - a = (x + y)**R(1,3) + a = (x + y)**R(1, 3) assert (a**1).expand() == a assert (a**2).expand() == a**2 @@ -63,6 +103,7 @@ assert (a**5).expand() == x*a**2 + y*a**2 assert (a**7).expand() == x**2*a + 2*x*y*a + y**2*a + def test_expand_modulus(): assert ((x + y)**11).expand(modulus=11) == x**11 + y**11 assert ((x + sqrt(2)*y)**11).expand(modulus=11) == x**11 + 10*sqrt(2)*y**11 @@ -71,9 +112,13 @@ raises(ValueError, lambda: ((x + y)**11).expand(modulus=0)) raises(ValueError, lambda: ((x + y)**11).expand(modulus=x)) + def test_issue_2644(): - assert (x*sqrt(x + y)*(1 + sqrt(x + y))).expand() == x**2 + x*y + x*sqrt(x + y) - assert (x*sqrt(x + y)*(1 + x*sqrt(x + y))).expand() == x**3 + x**2*y + x*sqrt(x + y) + assert (x*sqrt( + x + y)*(1 + sqrt(x + y))).expand() == x**2 + x*y + x*sqrt(x + y) + assert (x*sqrt( + x + y)*(1 + x*sqrt(x + y))).expand() == x**3 + x**2*y + x*sqrt(x + y) + def test_expand_frac(): assert expand((x + y)*y/x/(x + 1), frac=True) == \ @@ -82,29 +127,19 @@ (x*y + y**2)/(x*(x + 1)) assert expand((x + y)*y/x/(x + 1), denom=True) == \ y*(x + y)/(x**2 + x) - eq = (x+1)**2/y + eq = (x + 1)**2/y assert expand_numer(eq, multinomial=False) == eq + def test_issue_3022(): - from sympy import cse - ans = S('''([ - (x0, im(x)), - (x1, re(x)), - (x2, atan2(x0, x1)/2), - (x3, sin(x2)), (x4, cos(x2)), - (x5, x0**2 + x1**2), - (x6, atan2(0, x5)/4), - (x7, cos(x6)), - (x8, sin(x6)), - (x9, x4*x7), - (x10, x4*x8), - (x11, x3*x8), - (x12, x3*x7)], - [sqrt(2)*(x10 + I*x10 + x11 - I*x11 + x12 + I*x12 - x9 + I*x9)/ - (8*pi**(3/2)*x5**(1/4))])''') eq = -I*exp(-3*I*pi/4)/(4*pi**(S(3)/2)*sqrt(x)) - r, e = cse((eq).expand(complex=True)) - assert abs((eq - e[0].subs(reversed(r))).subs(x, 1 + 3*I)) < 1e-9 + assert cse((eq).expand(complex=True)) == S(''' + ([(x0, re(x)), (x1, im(x)), (x2, sin(atan2(x1, x0)/2)), (x3, + cos(atan2(x1, x0)/2)), (x4, x0**2 + x1**2), (x5, sin(atan2(0, x4)/4)), + (x6, cos(atan2(0, x4)/4)), (x7, x2*x5), (x8, x3*x5), (x9, x2*x6), + (x10, x3*x6)], [sqrt(2)*(-x10 + I*x10 + x7 - I*x7 + x8 + I*x8 + x9 + + I*x9)/(8*pi**(3/2)*x4**(1/4))])''') + def test_expand_power_base(): # was test_separate() @@ -115,14 +150,163 @@ assert expand_power_base((x*(y*z)**2)**3) == x**3*y**6*z**6 assert expand_power_base((sin((x*y)**2)*y)**z).is_Pow - assert expand_power_base((sin((x*y)**2)*y)**z, force=True) == sin((x*y)**2)**z*y**z - assert expand_power_base((sin((x*y)**2)*y)**z, deep=True) == (sin(x**2*y**2)*y)**z + assert expand_power_base( + (sin((x*y)**2)*y)**z, force=True) == sin((x*y)**2)**z*y**z + assert expand_power_base( + (sin((x*y)**2)*y)**z, deep=True) == (sin(x**2*y**2)*y)**z assert expand_power_base(exp(x)**2) == exp(2*x) assert expand_power_base((exp(x)*exp(y))**2) == exp(2*x)*exp(2*y) - assert expand_power_base((exp((x*y)**z)*exp(y))**2) == exp(2*(x*y)**z)*exp(2*y) - assert expand_power_base((exp((x*y)**z)*exp(y))**2, deep=True, force=True) == exp(2*x**z*y**z)*exp(2*y) + assert expand_power_base( + (exp((x*y)**z)*exp(y))**2) == exp(2*(x*y)**z)*exp(2*y) + assert expand_power_base((exp((x*y)**z)*exp( + y))**2, deep=True, force=True) == exp(2*x**z*y**z)*exp(2*y) assert expand_power_base((exp(x)*exp(y))**z).is_Pow - assert expand_power_base((exp(x)*exp(y))**z, force=True) == exp(x)**z*exp(y)**z + assert expand_power_base( + (exp(x)*exp(y))**z, force=True) == exp(x)**z*exp(y)**z + + +def test_expand_arit(): + a = Symbol("a") + b = Symbol("b", positive=True) + c = Symbol("c") + + p = R(5) + e = (a + b)*c + assert e == c*(a + b) + assert (e.expand() - a*c - b*c) == R(0) + e = (a + b)*(a + b) + assert e == (a + b)**2 + assert e.expand() == 2*a*b + a**2 + b**2 + e = (a + b)*(a + b)**R(2) + assert e == (a + b)**3 + assert e.expand() == 3*b*a**2 + 3*a*b**2 + a**3 + b**3 + assert e.expand() == 3*b*a**2 + 3*a*b**2 + a**3 + b**3 + e = (a + b)*(a + c)*(b + c) + assert e == (a + c)*(a + b)*(b + c) + assert e.expand() == 2*a*b*c + b*a**2 + c*a**2 + b*c**2 + a*c**2 + c*b**2 + a*b**2 + e = (a + R(1))**p + assert e == (1 + a)**5 + assert e.expand() == 1 + 5*a + 10*a**2 + 10*a**3 + 5*a**4 + a**5 + e = (a + b + c)*(a + c + p) + assert e == (5 + a + c)*(a + b + c) + assert e.expand() == 5*a + 5*b + 5*c + 2*a*c + b*c + a*b + a**2 + c**2 + x = Symbol("x") + s = exp(x*x) - 1 + e = s.nseries(x, 0, 3)/x**2 + assert e.expand() == 1 + x**2/2 + O(x**4) + + e = (x*(y + z))**(x*(y + z))*(x + y) + assert e.expand(power_exp=False, power_base=False) == x*(x*y + x* + z)**(x*y + x*z) + y*(x*y + x*z)**(x*y + x*z) + assert e.expand(power_exp=False, power_base=False, deep=False) == x* \ + (x*(y + z))**(x*(y + z)) + y*(x*(y + z))**(x*(y + z)) + e = (x*(y + z))**z + assert e.expand(power_base=True, mul=True, deep=True) in [x**z*(y + + z)**z, (x*y + x*z)**z] + assert ((2*y)**z).expand() == 2**z*y**z + p = Symbol('p', positive=True) + assert sqrt(-x).expand().is_Pow + assert sqrt(-x).expand(force=True) == I*sqrt(x) + assert ((2*y*p)**z).expand() == 2**z*p**z*y**z + assert ((2*y*p*x)**z).expand() == 2**z*p**z*(x*y)**z + assert ((2*y*p*x)**z).expand(force=True) == 2**z*p**z*x**z*y**z + assert ((2*y*p*-pi)**z).expand() == 2**z*pi**z*p**z*(-y)**z + assert ((2*y*p*-pi*x)**z).expand() == 2**z*pi**z*p**z*(-x*y)**z + n = Symbol('n', negative=True) + m = Symbol('m', negative=True) + assert ((-2*x*y*n)**z).expand() == 2**z*(-n)**z*(x*y)**z + assert ((-2*x*y*n*m)**z).expand() == 2**z*(-m)**z*(-n)**z*(-x*y)**z + # issue 2383 + assert sqrt(-2*x*n) == sqrt(2)*sqrt(-n)*sqrt(x) + # issue 2506 (2) + assert (cos(x + y)**2).expand(trig=True) in [ + (-sin(x)*sin(y) + cos(x)*cos(y))**2, + sin(x)**2*sin(y)**2 - 2*sin(x)*sin(y)*cos(x)*cos(y) + cos(x)**2*cos(y)**2 + ] + + # Check that this isn't too slow + x = Symbol('x') + W = 1 + for i in range(1, 21): + W = W * (x - i) + W = W.expand() + assert W.has(-1672280820*x**15) + + +def test_power_expand(): + """Test for Pow.expand()""" + a = Symbol('a') + b = Symbol('b') + p = (a + b)**2 + assert p.expand() == a**2 + b**2 + 2*a*b + + p = (1 + 2*(1 + a))**2 + assert p.expand() == 9 + 4*(a**2) + 12*a + + p = 2**(a + b) + assert p.expand() == 2**a*2**b + + A = Symbol('A', commutative=False) + B = Symbol('B', commutative=False) + assert (2**(A + B)).expand() == 2**(A + B) + assert (A**(a + b)).expand() != A**(a + b) + + +def test_issues_2820_3731(): + # 2820 + n = -1 + 1/x + z = n/x/(-n)**2 - 1/n/x + assert expand(z) == 1/(x**2 - 2*x + 1) - 1/(x - 2 + 1/x) - 1/(-x + 1) + + # 3731 + p = (1 + x)**2 + assert expand_multinomial((1 + x*p)**2) == ( + x**2*(x**4 + 4*x**3 + 6*x**2 + 4*x + 1) + 2*x*(x**2 + 2*x + 1) + 1) + assert expand_multinomial((1 + (y + x)*p)**2) == ( + 2*((x + y)*(x**2 + 2*x + 1)) + (x**2 + 2*x*y + y**2)* + (x**4 + 4*x**3 + 6*x**2 + 4*x + 1) + 1) + A = Symbol('A', commutative=False) + p = (1 + A)**2 + assert expand_multinomial((1 + x*p)**2) == ( + x**2*(1 + 4*A + 6*A**2 + 4*A**3 + A**4) + 2*x*(1 + 2*A + A**2) + 1) + assert expand_multinomial((1 + (y + x)*p)**2) == ( + (x + y)*(1 + 2*A + A**2)*2 + (x**2 + 2*x*y + y**2)* + (1 + 4*A + 6*A**2 + 4*A**3 + A**4) + 1) + assert expand_multinomial((1 + (y + x)*p)**3) == ( + (x + y)*(1 + 2*A + A**2)*3 + (x**2 + 2*x*y + y**2)*(1 + 4*A + + 6*A**2 + 4*A**3 + A**4)*3 + (x**3 + 3*x**2*y + 3*x*y**2 + y**3)*(1 + 6*A + + 15*A**2 + 20*A**3 + 15*A**4 + 6*A**5 + A**6) + 1) + # unevaluate powers + eq = (Pow((x + 1)*((A + 1)**2), 2, evaluate=False)) + # - in this case the base is not an Add so no further + # expansion is done + assert expand_multinomial(eq) == \ + (x**2 + 2*x + 1)*(1 + 4*A + 6*A**2 + 4*A**3 + A**4) + # - but here, the expanded base *is* an Add so it gets expanded + eq = (Pow(((A + 1)**2), 2, evaluate=False)) + assert expand_multinomial(eq) == 1 + 4*A + 6*A**2 + 4*A**3 + A**4 + + # coverage + def ok(a, b, n): + e = (a + I*b)**n + return test_numerically(e, expand_multinomial(e)) + + for a in [2, S.Half]: + for b in [3, S(1)/3]: + for n in range(2, 6): + assert ok(a, b, n) + + assert expand_multinomial((x + 1 + O(z))**2) == \ + 1 + 2*x + x**2 + O(z) + assert expand_multinomial((x + 1 + O(z))**3) == \ + 1 + 3*x + 3*x**2 + x**3 + O(z) + + assert expand_multinomial(3**(x + y + 3)) == 27*3**(x + y) + +def test_expand_log(): + t = Symbol('t', positive=True) + # after first expansion, -2*log(2) + log(4); then 0 after second + assert expand(log(t**2) - log(t**2/4) - 2*log(2)) == 0 diff -Nru python3-sympy-0.7.2/sympy/core/tests/test_expr.py python3-sympy-0.7.3/sympy/core/tests/test_expr.py --- python3-sympy-0.7.2/sympy/core/tests/test_expr.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/core/tests/test_expr.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,19 +1,21 @@ -from sympy import (Add, Basic, S, Symbol, Wild, Float, Integer, Rational, I, +from sympy import (Add, Basic, S, Symbol, Wild, Float, Integer, Rational, I, sin, cos, tan, exp, log, nan, oo, sqrt, symbols, Integral, sympify, WildFunction, Poly, Function, Derivative, Number, pi, NumberSymbol, zoo, - Piecewise, Mul, Pow, nsimplify, ratsimp, trigsimp, radsimp, powsimp, - simplify, together, collect, factorial, apart, combsimp, factor, refine, - cancel, Tuple, default_sort_key, DiracDelta, gamma, Dummy, Sum, E, - exp_polar, Lambda) + Piecewise, Mul, Pow, nsimplify, ratsimp, trigsimp, radsimp, powsimp, + simplify, together, collect, factorial, apart, combsimp, factor, refine, + cancel, Tuple, default_sort_key, DiracDelta, gamma, Dummy, Sum, E, + exp_polar, Lambda, expand, diff, O) from sympy.core.function import AppliedUndef -from sympy.abc import a, b, c, d, e, n, t, u, x, y, z from sympy.physics.secondquant import FockState from sympy.physics.units import meter from sympy.utilities.pytest import raises, XFAIL +from sympy.abc import a, b, c, n, t, u, x, y, z + + class DummyNumber(object): """ Minimal implementation of a number that works with SymPy. @@ -89,13 +91,17 @@ def __neg__(self): return - self.number + class I5(DummyNumber): number = 5 + def __int__(self): return self.number + class F1_1(DummyNumber): number = 1.1 + def __float__(self): return self.number @@ -108,7 +114,7 @@ Float("1.3"), x, y, - pow(x,y)*y, + pow(x, y)*y, ] # all supported objects @@ -119,25 +125,29 @@ f1_1 ] + def dotest(s): for x in all_objs: for y in all_objs: - s(x,y) + s(x, y) + return True + def test_basic(): - def j(a,b): + def j(a, b): x = a x = +a x = -a - x = a+b - x = a-b + x = a + b + x = a - b x = a*b x = a/b x = a**b - dotest(j) + assert dotest(j) + def test_ibasic(): - def s(a,b): + def s(a, b): x = a x += b x = a @@ -146,75 +156,121 @@ x *= b x = a x /= b - dotest(s) + assert dotest(s) + def test_relational(): - assert (pi < 3) == False - assert (pi <= 3) == False - assert (pi > 3) == True - assert (pi >= 3) == True - assert (-pi < 3) == True - assert (-pi <= 3) == True - assert (-pi > 3) == False - assert (-pi >= 3) == False - assert (x - 2 < x - 3) == False + assert (pi < 3) is False + assert (pi <= 3) is False + assert (pi > 3) is True + assert (pi >= 3) is True + assert (-pi < 3) is True + assert (-pi <= 3) is True + assert (-pi > 3) is False + assert (-pi >= 3) is False + assert (x - 2 < x - 3) is False + + +def test_relational_assumptions(): + from sympy import Lt, Gt, Le, Ge + m1 = Symbol("m1", nonnegative=False) + m2 = Symbol("m2", positive=False) + m3 = Symbol("m3", nonpositive=False) + m4 = Symbol("m4", negative=False) + assert (m1 < 0) == Lt(m1, 0) + assert (m2 <= 0) == Le(m2, 0) + assert (m3 > 0) == Gt(m3, 0) + assert (m4 >= 0) == Ge(m4, 0) + m1 = Symbol("m1", nonnegative=False, real=True) + m2 = Symbol("m2", positive=False, real=True) + m3 = Symbol("m3", nonpositive=False, real=True) + m4 = Symbol("m4", negative=False, real=True) + assert (m1 < 0) is True + assert (m2 <= 0) is True + assert (m3 > 0) is True + assert (m4 >= 0) is True + m1 = Symbol("m1", negative=True) + m2 = Symbol("m2", nonpositive=True) + m3 = Symbol("m3", positive=True) + m4 = Symbol("m4", nonnegative=True) + assert (m1 < 0) is True + assert (m2 <= 0) is True + assert (m3 > 0) is True + assert (m4 >= 0) is True + m1 = Symbol("m1", negative=False) + m2 = Symbol("m2", nonpositive=False) + m3 = Symbol("m3", positive=False) + m4 = Symbol("m4", nonnegative=False) + assert (m1 < 0) is False + assert (m2 <= 0) is False + assert (m3 > 0) is False + assert (m4 >= 0) is False + def test_relational_noncommutative(): from sympy import Lt, Gt, Le, Ge A, B = symbols('A,B', commutative=False) - assert (A < B) == Lt(A, B) + assert (A < B) == Lt(A, B) assert (A <= B) == Le(A, B) - assert (A > B) == Gt(A, B) + assert (A > B) == Gt(A, B) assert (A >= B) == Ge(A, B) + def test_basic_nostr(): for obj in basic_objs: raises(TypeError, lambda: obj + '1') raises(TypeError, lambda: obj - '1') if obj == 2: - if hasattr(int, '__index__'): # Python 2.5+ (PEP 357) + if hasattr(int, '__index__'): # Python 2.5+ (PEP 357) assert obj * '1' == '11' else: raises(TypeError, lambda: obj * '1') raises(TypeError, lambda: obj / '1') raises(TypeError, lambda: obj ** '1') + def test_leadterm(): - assert (3+2*x**(log(3)/log(2)-1)).leadterm(x) == (3,0) + assert (3 + 2*x**(log(3)/log(2) - 1)).leadterm(x) == (3, 0) - assert (1/x**2+1+x+x**2).leadterm(x)[1] == -2 - assert (1/x+1+x+x**2).leadterm(x)[1] == -1 - assert (x**2+1/x).leadterm(x)[1] == -1 - assert (1+x**2).leadterm(x)[1] == 0 - assert (x+1).leadterm(x)[1] == 0 - assert (x+x**2).leadterm(x)[1] == 1 + assert (1/x**2 + 1 + x + x**2).leadterm(x)[1] == -2 + assert (1/x + 1 + x + x**2).leadterm(x)[1] == -1 + assert (x**2 + 1/x).leadterm(x)[1] == -1 + assert (1 + x**2).leadterm(x)[1] == 0 + assert (x + 1).leadterm(x)[1] == 0 + assert (x + x**2).leadterm(x)[1] == 1 assert (x**2).leadterm(x)[1] == 2 + def test_as_leading_term(): - assert (3+2*x**(log(3)/log(2)-1)).as_leading_term(x) == 3 - assert (1/x**2+1+x+x**2).as_leading_term(x) == 1/x**2 - assert (1/x+1+x+x**2).as_leading_term(x) == 1/x - assert (x**2+1/x).as_leading_term(x) == 1/x - assert (1+x**2).as_leading_term(x) == 1 - assert (x+1).as_leading_term(x) == 1 - assert (x+x**2).as_leading_term(x) == x + assert (3 + 2*x**(log(3)/log(2) - 1)).as_leading_term(x) == 3 + assert (1/x**2 + 1 + x + x**2).as_leading_term(x) == 1/x**2 + assert (1/x + 1 + x + x**2).as_leading_term(x) == 1/x + assert (x**2 + 1/x).as_leading_term(x) == 1/x + assert (1 + x**2).as_leading_term(x) == 1 + assert (x + 1).as_leading_term(x) == 1 + assert (x + x**2).as_leading_term(x) == x assert (x**2).as_leading_term(x) == x**2 assert (x + oo).as_leading_term(x) == oo + def test_leadterm2(): assert (x*cos(1)*cos(1 + sin(1)) + sin(1 + sin(1))).leadterm(x) == \ - (sin(1 + sin(1)), 0) + (sin(1 + sin(1)), 0) + def test_leadterm3(): - assert (y+z+x).leadterm(x) == (y+z, 0) + assert (y + z + x).leadterm(x) == (y + z, 0) + def test_as_leading_term2(): assert (x*cos(1)*cos(1 + sin(1)) + sin(1 + sin(1))).as_leading_term(x) == \ - sin(1 + sin(1)) + sin(1 + sin(1)) + def test_as_leading_term3(): - assert (2+pi+x).as_leading_term(x) == 2 + pi - assert (2*x+pi*x+x**2).as_leading_term(x) == (2+pi)*x + assert (2 + pi + x).as_leading_term(x) == 2 + pi + assert (2*x + pi*x + x**2).as_leading_term(x) == (2 + pi)*x + def test_as_leading_term_stub(): class foo(Function): @@ -223,17 +279,19 @@ assert foo(1).as_leading_term(x) == foo(1) raises(NotImplementedError, lambda: foo(x).as_leading_term(x)) + def test_atoms(): assert sorted(list(x.atoms())) == [x] - assert sorted(list((1+x).atoms())) == sorted([1, x]) + assert sorted(list((1 + x).atoms())) == sorted([1, x]) - assert sorted(list((1+2*cos(x)).atoms(Symbol))) == [x] - assert sorted(list((1+2*cos(x)).atoms(Symbol,Number))) == sorted([1, 2, x]) + assert sorted(list((1 + 2*cos(x)).atoms(Symbol))) == [x] + assert sorted( + list((1 + 2*cos(x)).atoms(Symbol, Number))) == sorted([1, 2, x]) assert sorted(list((2*(x**(y**x))).atoms())) == sorted([2, x, y]) - assert sorted(list(Rational(1,2).atoms())) == [S.Half] - assert sorted(list(Rational(1,2).atoms(Symbol))) == [] + assert sorted(list(Rational(1, 2).atoms())) == [S.Half] + assert sorted(list(Rational(1, 2).atoms(Symbol))) == [] assert sorted(list(sin(oo).atoms(oo))) == [oo] @@ -248,14 +306,11 @@ assert list((I*pi).atoms(NumberSymbol)) == [pi] assert sorted((I*pi).atoms(NumberSymbol, I)) == \ - sorted((I*pi).atoms(I,NumberSymbol)) == [pi, I] - + sorted((I*pi).atoms(I, NumberSymbol)) == [pi, I] assert exp(exp(x)).atoms(exp) == set([exp(exp(x)), exp(x)]) - assert (1 + x*(2 + y)+exp(3 + z)).atoms(Add) == set( - [1 + x*(2 + y)+exp(3 + z), - 2 + y, - 3 + z]) + assert (1 + x*(2 + y) + exp(3 + z)).atoms(Add) == \ + set([1 + x*(2 + y) + exp(3 + z), 2 + y, 3 + z]) # issue 3033 f = Function('f') @@ -271,72 +326,94 @@ assert e.atoms(Function, Number) == \ set([S(2), sin(x), f(x)]) + def test_is_polynomial(): k = Symbol('k', nonnegative=True, integer=True) - assert Rational(2).is_polynomial(x, y, z) == True - assert (S.Pi).is_polynomial(x, y, z) == True + assert Rational(2).is_polynomial(x, y, z) is True + assert (S.Pi).is_polynomial(x, y, z) is True + + assert x.is_polynomial(x) is True + assert x.is_polynomial(y) is True - assert x.is_polynomial(x) == True - assert x.is_polynomial(y) == True + assert (x**2).is_polynomial(x) is True + assert (x**2).is_polynomial(y) is True - assert (x**2).is_polynomial(x) == True - assert (x**2).is_polynomial(y) == True + assert (x**(-2)).is_polynomial(x) is False + assert (x**(-2)).is_polynomial(y) is True - assert (x**(-2)).is_polynomial(x) == False - assert (x**(-2)).is_polynomial(y) == True + assert (2**x).is_polynomial(x) is False + assert (2**x).is_polynomial(y) is True - assert (2**x).is_polynomial(x) == False - assert (2**x).is_polynomial(y) == True + assert (x**k).is_polynomial(x) is False + assert (x**k).is_polynomial(k) is False + assert (x**x).is_polynomial(x) is False + assert (k**k).is_polynomial(k) is False + assert (k**x).is_polynomial(k) is False - assert (x**k).is_polynomial(x) == False - assert (x**k).is_polynomial(k) == False - assert (x**x).is_polynomial(x) == False - assert (k**k).is_polynomial(k) == False - assert (k**x).is_polynomial(k) == False + assert (x**(-k)).is_polynomial(x) is False + assert ((2*x)**k).is_polynomial(x) is False - assert (x**(-k)).is_polynomial(x) == False - assert ((2*x)**k).is_polynomial(x) == False + assert (x**2 + 3*x - 8).is_polynomial(x) is True + assert (x**2 + 3*x - 8).is_polynomial(y) is True - assert (x**2 + 3*x - 8).is_polynomial(x) == True - assert (x**2 + 3*x - 8).is_polynomial(y) == True + assert (x**2 + 3*x - 8).is_polynomial() is True - assert (x**2 + 3*x - 8).is_polynomial() == True + assert sqrt(x).is_polynomial(x) is False + assert (sqrt(x)**3).is_polynomial(x) is False - assert sqrt(x).is_polynomial(x) == False - assert (sqrt(x)**3).is_polynomial(x) == False + assert (x**2 + 3*x*sqrt(y) - 8).is_polynomial(x) is True + assert (x**2 + 3*x*sqrt(y) - 8).is_polynomial(y) is False - assert (x**2 + 3*x*sqrt(y) - 8).is_polynomial(x) == True - assert (x**2 + 3*x*sqrt(y) - 8).is_polynomial(y) == False + assert ((x**2)*(y**2) + x*(y**2) + y*x + exp(2)).is_polynomial() is True + assert ((x**2)*(y**2) + x*(y**2) + y*x + exp(x)).is_polynomial() is False - assert ((x**2)*(y**2) + x*(y**2) + y*x + exp(2)).is_polynomial() == True - assert ((x**2)*(y**2) + x*(y**2) + y*x + exp(x)).is_polynomial() == False + assert ( + (x**2)*(y**2) + x*(y**2) + y*x + exp(2)).is_polynomial(x, y) is True + assert ( + (x**2)*(y**2) + x*(y**2) + y*x + exp(x)).is_polynomial(x, y) is False - assert ((x**2)*(y**2) + x*(y**2) + y*x + exp(2)).is_polynomial(x, y) == True - assert ((x**2)*(y**2) + x*(y**2) + y*x + exp(x)).is_polynomial(x, y) == False def test_is_rational_function(): - assert Integer(1).is_rational_function() == True - assert Integer(1).is_rational_function(x) == True + assert Integer(1).is_rational_function() is True + assert Integer(1).is_rational_function(x) is True - assert Rational(17,54).is_rational_function() == True - assert Rational(17,54).is_rational_function(x) == True + assert Rational(17, 54).is_rational_function() is True + assert Rational(17, 54).is_rational_function(x) is True - assert (12/x).is_rational_function() == True - assert (12/x).is_rational_function(x) == True + assert (12/x).is_rational_function() is True + assert (12/x).is_rational_function(x) is True - assert (x/y).is_rational_function() == True - assert (x/y).is_rational_function(x) == True - assert (x/y).is_rational_function(x, y) == True - - assert (x**2+1/x/y).is_rational_function() == True - assert (x**2+1/x/y).is_rational_function(x) == True - assert (x**2+1/x/y).is_rational_function(x, y) == True - - assert (sin(y)/x).is_rational_function() == False - assert (sin(y)/x).is_rational_function(y) == False - assert (sin(y)/x).is_rational_function(x) == True - assert (sin(y)/x).is_rational_function(x, y) == False + assert (x/y).is_rational_function() is True + assert (x/y).is_rational_function(x) is True + assert (x/y).is_rational_function(x, y) is True + + assert (x**2 + 1/x/y).is_rational_function() is True + assert (x**2 + 1/x/y).is_rational_function(x) is True + assert (x**2 + 1/x/y).is_rational_function(x, y) is True + + assert (sin(y)/x).is_rational_function() is False + assert (sin(y)/x).is_rational_function(y) is False + assert (sin(y)/x).is_rational_function(x) is True + assert (sin(y)/x).is_rational_function(x, y) is False + + +def test_is_algebraic_expr(): + assert sqrt(3).is_algebraic_expr(x) is True + assert sqrt(3).is_algebraic_expr() is True + + eq = ((1 + x**2)/(1 - y**2))**(S(1)/3) + assert eq.is_algebraic_expr(x) is True + assert eq.is_algebraic_expr(y) is True + + assert (sqrt(x) + y**(S(2)/3)).is_algebraic_expr(x) is True + assert (sqrt(x) + y**(S(2)/3)).is_algebraic_expr(y) is True + assert (sqrt(x) + y**(S(2)/3)).is_algebraic_expr() is True + + assert (cos(y)/sqrt(x)).is_algebraic_expr() is False + assert (cos(y)/sqrt(x)).is_algebraic_expr(x) is True + assert (cos(y)/sqrt(x)).is_algebraic_expr(y) is False + assert (cos(y)/sqrt(x)).is_algebraic_expr(x, y) is False def test_SAGE1(): #see http://code.google.com/p/sympy/issues/detail?id=247 @@ -349,6 +426,7 @@ raises(TypeError, lambda: Rational(2)*MyInt) + def test_SAGE2(): class MyInt(object): def __int__(self): @@ -359,6 +437,7 @@ raises(TypeError, lambda: Rational(2)*MyInt) + def test_SAGE3(): class MySymbol: def __rmul__(self, other): @@ -369,46 +448,53 @@ assert e == ('mys', x, o) + def test_len(): e = x*y assert len(e.args) == 2 - e = x+y+z + e = x + y + z assert len(e.args) == 3 + def test_doit(): a = Integral(x**2, x) - assert isinstance(a.doit(), Integral) == False + assert isinstance(a.doit(), Integral) is False - assert isinstance(a.doit(integrals=True), Integral) == False - assert isinstance(a.doit(integrals=False), Integral) == True + assert isinstance(a.doit(integrals=True), Integral) is False + assert isinstance(a.doit(integrals=False), Integral) is True assert (2*Integral(x, x)).doit() == x**2 + def test_attribute_error(): raises(AttributeError, lambda: x.cos()) raises(AttributeError, lambda: x.sin()) raises(AttributeError, lambda: x.exp()) + def test_args(): assert (x*y).args in ((x, y), (y, x)) - assert (x+y).args in ((x, y), (y, x)) - assert (x*y+1).args in ((x*y, 1), (1, x*y)) + assert (x + y).args in ((x, y), (y, x)) + assert (x*y + 1).args in ((x*y, 1), (1, x*y)) assert sin(x*y).args == (x*y,) assert sin(x*y).args[0] == x*y - assert (x**y).args == (x,y) + assert (x**y).args == (x, y) assert (x**y).args[0] == x assert (x**y).args[1] == y + def test_iter_basic_args(): assert list(sin(x*y).iter_basic_args()) == [x*y] assert list((x**y).iter_basic_args()) == [x, y] + def test_noncommutative_expand_issue658(): A, B, C = symbols('A,B,C', commutative=False) assert A*B - B*A != 0 - assert (A*(A+B)*B).expand() == A**2*B + A*B**2 - assert (A*(A+B+C)*B).expand() == A**2*B + A*B**2 + A*C*B + assert (A*(A + B)*B).expand() == A**2*B + A*B**2 + assert (A*(A + B + C)*B).expand() == A**2*B + A*B**2 + A*C*B + def test_as_numer_denom(): a, b, c = symbols('a, b, c') @@ -428,15 +514,15 @@ assert Rational(1, 2).as_numer_denom() == (1, 2) assert (1/y**2).as_numer_denom() == (1, y**2) assert (x/y**2).as_numer_denom() == (x, y**2) - assert ((x**2+1)/y).as_numer_denom() == (x**2+1, y) - assert (x*(y+1)/y**7).as_numer_denom() == (x*(y+1), y**7) + assert ((x**2 + 1)/y).as_numer_denom() == (x**2 + 1, y) + assert (x*(y + 1)/y**7).as_numer_denom() == (x*(y + 1), y**7) assert (x**-2).as_numer_denom() == (1, x**2) assert (a/x + b/2/x + c/3/x).as_numer_denom() == \ - (6*a + 3*b + 2*c, 6*x) + (6*a + 3*b + 2*c, 6*x) assert (a/x + b/2/x + c/3/y).as_numer_denom() == \ - (2*c*x + y*(6*a + 3*b), 6*x*y) + (2*c*x + y*(6*a + 3*b), 6*x*y) assert (a/x + b/2/x + c/.5/x).as_numer_denom() == \ - (2*a + b + 4.0*c, 2*x) + (2*a + b + 4.0*c, 2*x) # this should take no more than a few seconds assert int(log(Add(*[Dummy()/i/x for i in range(1, 705)] ).as_numer_denom()[1]/x).n(4)) == 705 @@ -457,11 +543,12 @@ assert ((A*B*C)**-1).as_numer_denom() == ((A*B*C)**-1, 1) assert ((A*B*C)**-1/x).as_numer_denom() == ((A*B*C)**-1, x) + def test_as_independent(): - assert (2*x*sin(x)+y+x).as_independent(x) == (y, x + 2*x*sin(x)) - assert (2*x*sin(x)+y+x).as_independent(y) == (x + 2*x*sin(x), y) + assert (2*x*sin(x) + y + x).as_independent(x) == (y, x + 2*x*sin(x)) + assert (2*x*sin(x) + y + x).as_independent(y) == (x + 2*x*sin(x), y) - assert (2*x*sin(x)+y+x).as_independent(x, y) == (0, y + x + 2*x*sin(x)) + assert (2*x*sin(x) + y + x).as_independent(x, y) == (0, y + x + 2*x*sin(x)) assert (x*sin(x)*cos(y)).as_independent(x) == (cos(y), x*sin(x)) assert (x*sin(x)*cos(y)).as_independent(y) == (x*sin(x), cos(y)) @@ -483,8 +570,8 @@ assert (3*x).as_independent(x, as_Add=True) == (0, 3*x) assert (3*x).as_independent(x, as_Add=False) == (3, x) - assert (3+x).as_independent(x, as_Add=True) == (3, x) - assert (3+x).as_independent(x, as_Add=False) == (1, 3 + x) + assert (3 + x).as_independent(x, as_Add=True) == (3, x) + assert (3 + x).as_independent(x, as_Add=False) == (1, 3 + x) # issue 2380 assert (3*x).as_independent(Symbol) == (3, x) @@ -493,51 +580,87 @@ assert (n1*x*y).as_independent(x) == (n1*y, x) assert ((x + n1)*(x - y)).as_independent(x) == (1, (x + n1)*(x - y)) assert ((x + n1)*(x - y)).as_independent(y) == (x + n1, x - y) - assert (DiracDelta(x - n1)*DiracDelta(x - y)).as_independent(x) == (1, DiracDelta(x - n1)*DiracDelta(x - y)) + assert (DiracDelta(x - n1)*DiracDelta(x - y)).as_independent(x) \ + == (1, DiracDelta(x - n1)*DiracDelta(x - y)) assert (x*y*n1*n2*n3).as_independent(n2) == (x*y*n1, n2*n3) assert (x*y*n1*n2*n3).as_independent(n1) == (x*y, n1*n2*n3) assert (x*y*n1*n2*n3).as_independent(n3) == (x*y*n1*n2, n3) assert (DiracDelta(x - n1)*DiracDelta(y - n1)*DiracDelta(x - n2)).as_independent(y) == \ - (DiracDelta(x - n1), DiracDelta(y - n1)*DiracDelta(x - n2)) + (DiracDelta(x - n1)*DiracDelta(x - n2), DiracDelta(y - n1)) # issue 2685 assert (x + Integral(x, (x, 1, 2))).as_independent(x, strict=True) == \ (Integral(x, (x, 1, 2)), x) + def test_call(): # See the long history of this in issues 1927 and 2006. + raises(TypeError, lambda: sin(x)({ x : 1, sin(x) : 2})) + raises(TypeError, lambda: sin(x)(1)) + # No effect as there are no callables - assert sin(x)(1) == sin(x) - assert (1+sin(x))(1) == 1+sin(x) + assert sin(x).rcall(1) == sin(x) + assert (1 + sin(x)).rcall(1) == 1 + sin(x) # Effect in the pressence of callables l = Lambda(x, 2*x) - assert (l+x)(y) == 2*y+x - assert (x**l)(2) == x**4 + assert (l + x).rcall(y) == 2*y + x + assert (x**l).rcall(2) == x**4 # TODO UndefinedFunction does not subclass Expr #f = Function('f') #assert (2*f)(x) == 2*f(x) + def test_replace(): f = log(sin(x)) + tan(sin(x**2)) assert f.replace(sin, cos) == log(cos(x)) + tan(cos(x**2)) - assert f.replace(sin, lambda a: sin(2*a)) == log(sin(2*x)) + tan(sin(2*x**2)) + assert f.replace( + sin, lambda a: sin(2*a)) == log(sin(2*x)) + tan(sin(2*x**2)) a = Wild('a') + b = Wild('b') assert f.replace(sin(a), cos(a)) == log(cos(x)) + tan(cos(x**2)) - assert f.replace(sin(a), lambda a: sin(2*a)) == log(sin(2*x)) + tan(sin(2*x**2)) + assert f.replace( + sin(a), lambda a: sin(2*a)) == log(sin(2*x)) + tan(sin(2*x**2)) + # test exact + assert (2*x).replace(a*x + b, b - a, exact=True) == 2*x + assert (2*x).replace(a*x + b, b - a) == 2/x + assert (2*x).replace(a*x + b, lambda a, b: b - a, exact=True) == 2*x + assert (2*x).replace(a*x + b, lambda a, b: b - a) == 2/x g = 2*sin(x**3) - assert g.replace(lambda expr: expr.is_Number, lambda expr: expr**2) == 4*sin(x**9) + assert g.replace( + lambda expr: expr.is_Number, lambda expr: expr**2) == 4*sin(x**9) assert cos(x).replace(cos, sin, map=True) == (sin(x), {cos(x): sin(x)}) assert sin(x).replace(cos, sin) == sin(x) - assert (y*sin(x)).replace(sin, lambda expr: sin(expr)/y) == sin(x) + cond, func = lambda x: x.is_Mul, lambda x: 2*x + assert (x*y).replace(cond, func, map=True) == (2*x*y, {x*y: 2*x*y}) + assert (x*(1 + x*y)).replace(cond, func, map=True) == \ + (2*x*(2*x*y + 1), {x*(2*x*y + 1): 2*x*(2*x*y + 1), x*y: 2*x*y}) + assert (y*sin(x)).replace(sin, lambda expr: sin(expr)/y, map=True) == \ + (sin(x), {sin(x): sin(x)/y}) + # if not simultaneous then y*sin(x) -> y*sin(x)/y = sin(x) -> sin(x)/y + assert (y*sin(x)).replace(sin, lambda expr: sin(expr)/y, + simultaneous=False) == sin(x)/y + assert (x**2 + O(x**3)).replace(Pow, lambda b, e: b**e/e) == O(1, x) + assert (x**2 + O(x**3)).replace(Pow, lambda b, e: b**e/e, + simultaneous=False) == x**2/2 + O(x**3) + assert (x*(x*y + 3)).replace(lambda x: x.is_Mul, lambda x: 2 + x) == \ + x*(x*y + 5) + 2 + e = (x*y + 1)*(2*x*y + 1) + 1 + assert e.replace(cond, func, map=True) == ( + 2*((2*x*y + 1)*(4*x*y + 1)) + 1, + {2*x*y: 4*x*y, x*y: 2*x*y, (2*x*y + 1)*(4*x*y + 1): + 2*((2*x*y + 1)*(4*x*y + 1))}) + assert x.replace(x, y) == y + assert (x + 1).replace(1, 2) == x + 2 + def test_find(): expr = (x + y + 2 + sin(3*x)) @@ -559,7 +682,8 @@ expr = sin(sin(x)) + sin(x) + cos(x) + x assert expr.find(lambda u: type(u) is sin) == set([sin(x), sin(sin(x))]) - assert expr.find(lambda u: type(u) is sin, group=True) == {sin(x): 2, sin(sin(x)): 1} + assert expr.find( + lambda u: type(u) is sin, group=True) == {sin(x): 2, sin(sin(x)): 1} assert expr.find(sin(a)) == set([sin(x), sin(sin(x))]) assert expr.find(sin(a), group=True) == {sin(x): 2, sin(sin(x)): 1} @@ -567,6 +691,7 @@ assert expr.find(sin) == set([sin(x), sin(sin(x))]) assert expr.find(sin, group=True) == {sin(x): 2, sin(sin(x)): 1} + def test_count(): expr = (x + y + 2 + sin(3*x)) @@ -583,6 +708,7 @@ assert expr.count(sin(a)) == 1 assert expr.count(lambda u: type(u) is sin) == 1 + def test_has_basics(): f = Function('f') g = Function('g') @@ -610,6 +736,7 @@ assert not x.has() + def test_has_multiple(): f = x**2*y + sin(2**t + log(z)) @@ -632,6 +759,7 @@ assert (i*y**i).has(x, y) assert not (i*y**i).has(x, z) + def test_has_piecewise(): f = (x*y + 3/y)**(3 + 2) g = Function('g') @@ -648,6 +776,7 @@ assert p.has(g) assert not p.has(h) + def test_has_iterative(): A, B, C = symbols('A,B,C', commutative=False) f = x*gamma(x)*sin(x)*exp(x*y)*A*B*C*cos(x*A*B) @@ -684,6 +813,7 @@ assert not f.has(2*x + y) assert not f.has(2*x*y) + def test_has_tuple(): f = Function('f') g = Function('g') @@ -698,7 +828,8 @@ assert not Tuple(f, g).has(x) assert Tuple(f, g).has(f) assert not Tuple(f, g).has(h) - assert Tuple(True).has(True) is True # .has(1) will also be True + assert Tuple(True).has(True) is True # .has(1) will also be True + def test_has_units(): from sympy.physics.units import m, s @@ -706,6 +837,7 @@ assert (x*m/s).has(x) assert (x*m/s).has(y, z) is False + def test_has_polys(): poly = Poly(x**2 + x*y*sin(z), x, y, t) @@ -713,9 +845,11 @@ assert poly.has(x, y, z) assert poly.has(x, y, z, t) + def test_has_physics(): assert FockState((x, y)).has(x) + def test_as_poly_as_expr(): f = x**2 + 2*x*y @@ -728,67 +862,71 @@ assert p.as_poly() == p + def test_nonzero(): - assert bool(S.Zero) == False - assert bool(S.One) == True - assert bool(x) == True - assert bool(x+y) == True - assert bool(x-x) == False - assert bool(x*y) == True - assert bool(x*1) == True - assert bool(x*0) == False + assert bool(S.Zero) is False + assert bool(S.One) is True + assert bool(x) is True + assert bool(x + y) is True + assert bool(x - x) is False + assert bool(x*y) is True + assert bool(x*1) is True + assert bool(x*0) is False + def test_is_number(): - assert Float(3.14).is_number == True - assert Integer(737).is_number == True - assert Rational(3, 2).is_number == True - assert Rational(8).is_number == True - assert x.is_number == False - assert (2*x).is_number == False - assert (x + y).is_number == False - assert log(2).is_number == True - assert log(x).is_number == False - assert (2 + log(2)).is_number == True - assert (8+log(2)).is_number == True - assert (2 + log(x)).is_number == False - assert (8+log(2)+x).is_number == False - assert (1+x**2/x-x).is_number == True - assert Tuple(Integer(1)).is_number == False - assert Add(2, x).is_number == False - assert Mul(3, 4).is_number == True - assert Pow(log(2), 2).is_number == True - assert oo.is_number == True + assert Float(3.14).is_number is True + assert Integer(737).is_number is True + assert Rational(3, 2).is_number is True + assert Rational(8).is_number is True + assert x.is_number is False + assert (2*x).is_number is False + assert (x + y).is_number is False + assert log(2).is_number is True + assert log(x).is_number is False + assert (2 + log(2)).is_number is True + assert (8 + log(2)).is_number is True + assert (2 + log(x)).is_number is False + assert (8 + log(2) + x).is_number is False + assert (1 + x**2/x - x).is_number is True + assert Tuple(Integer(1)).is_number is False + assert Add(2, x).is_number is False + assert Mul(3, 4).is_number is True + assert Pow(log(2), 2).is_number is True + assert oo.is_number is True g = WildFunction('g') - assert g.is_number == False - assert (2*g).is_number == False - assert (x**2).subs(x, 3).is_number == True + assert g.is_number is False + assert (2*g).is_number is False + assert (x**2).subs(x, 3).is_number is True # test extensibility of .is_number # on subinstances of Basic class A(Basic): pass a = A() - assert a.is_number == False + assert a.is_number is False + def test_as_coeff_add(): assert S(2).as_coeff_add() == (2, ()) assert S(3.0).as_coeff_add() == (0, (S(3.0),)) assert S(-3.0).as_coeff_add() == (0, (S(-3.0),)) - assert x .as_coeff_add() == ( 0, (x,)) - assert (-1+x).as_coeff_add() == (-1, (x,)) - assert ( 2+x).as_coeff_add() == ( 2, (x,)) - assert ( 1+x).as_coeff_add() == ( 1, (x,)) + assert x.as_coeff_add() == (0, (x,)) + assert (x - 1).as_coeff_add() == (-1, (x,)) + assert (x + 1).as_coeff_add() == (1, (x,)) + assert (x + 2).as_coeff_add() == (2, (x,)) assert (x + y).as_coeff_add(y) == (x, (y,)) assert (3*x).as_coeff_add(y) == (3*x, ()) # don't do expansion e = (x + y)**2 assert e.as_coeff_add(y) == (0, (e,)) + def test_as_coeff_mul(): assert S(2).as_coeff_mul() == (2, ()) assert S(3.0).as_coeff_mul() == (1, (S(3.0),)) assert S(-3.0).as_coeff_mul() == (-1, (S(3.0),)) - assert x .as_coeff_mul() == ( 1, (x,)) + assert x.as_coeff_mul() == (1, (x,)) assert (-x).as_coeff_mul() == (-1, (x,)) assert (2*x).as_coeff_mul() == (2, (x,)) assert (x*y).as_coeff_mul(y) == (x, (y,)) @@ -799,6 +937,7 @@ e = 2**(x + y) assert e.as_coeff_mul(y) == (1, (e,)) + def test_as_coeff_exponent(): assert (3*x**4).as_coeff_exponent(x) == (3, 4) assert (2*x**3).as_coeff_exponent(x) == (2, 3) @@ -810,35 +949,36 @@ assert (0*x**0).as_coeff_exponent(x) == (0, 0) assert (-1*x**0).as_coeff_exponent(x) == (-1, 0) assert (-2*x**0).as_coeff_exponent(x) == (-2, 0) - assert (2*x**3+pi*x**3).as_coeff_exponent(x) == (2+pi, 3) + assert (2*x**3 + pi*x**3).as_coeff_exponent(x) == (2 + pi, 3) assert (x*log(2)/(2*x + pi*x)).as_coeff_exponent(x) == \ - (log(2)/(2+pi), 0) + (log(2)/(2 + pi), 0) # 1685 D = Derivative f = Function('f') - fx = D(f(x), x) - assert fx.as_coeff_exponent(f(x)) == (fx ,0) + fx = D(f(x), x) + assert fx.as_coeff_exponent(f(x)) == (fx, 0) + def test_extractions(): assert ((x*y)**3).extract_multiplicatively(x**2 * y) == x*y**2 - assert ((x*y)**3).extract_multiplicatively(x**4 * y) == None + assert ((x*y)**3).extract_multiplicatively(x**4 * y) is None assert (2*x).extract_multiplicatively(2) == x - assert (2*x).extract_multiplicatively(3) == None - assert (2*x).extract_multiplicatively(-1) == None + assert (2*x).extract_multiplicatively(3) is None + assert (2*x).extract_multiplicatively(-1) is None assert (Rational(1, 2)*x).extract_multiplicatively(3) == x/6 - assert (sqrt(x)).extract_multiplicatively(x) == None - assert (sqrt(x)).extract_multiplicatively(1/x) == None + assert (sqrt(x)).extract_multiplicatively(x) is None + assert (sqrt(x)).extract_multiplicatively(1/x) is None - assert ((x*y)**3).extract_additively(1) == None + assert ((x*y)**3).extract_additively(1) is None assert (x + 1).extract_additively(x) == 1 - assert (x + 1).extract_additively(2*x) == None - assert (x + 1).extract_additively(-x) == None - assert (-x + 1).extract_additively(2*x) == None + assert (x + 1).extract_additively(2*x) is None + assert (x + 1).extract_additively(-x) is None + assert (-x + 1).extract_additively(2*x) is None assert (2*x + 3).extract_additively(x) == x + 3 assert (2*x + 3).extract_additively(2) == 2*x + 1 assert (2*x + 3).extract_additively(3) == 2*x - assert (2*x + 3).extract_additively(-2) == None - assert (2*x + 3).extract_additively(3*x) == None + assert (2*x + 3).extract_additively(-2) is None + assert (2*x + 3).extract_additively(3*x) is None assert (2*x + 3).extract_additively(2*x) == 3 assert x.extract_additively(0) == x assert S(2).extract_additively(x) is None @@ -862,36 +1002,39 @@ (x + 2*y)*(y + 1) + 3 n = Symbol("n", integer=True) - assert (Integer(-3)).could_extract_minus_sign() == True - assert (-n*x+x).could_extract_minus_sign() != (n*x-x).could_extract_minus_sign() - assert (x-y).could_extract_minus_sign() != (-x+y).could_extract_minus_sign() - assert (1-x-y).could_extract_minus_sign() == True - assert (1-x+y).could_extract_minus_sign() == False - assert ((-x-x*y)/y).could_extract_minus_sign() == True - assert (-(x+x*y)/y).could_extract_minus_sign() == True - assert ((x+x*y)/(-y)).could_extract_minus_sign() == True - assert ((x+x*y)/y).could_extract_minus_sign() == False - assert (x*(-x-x**3)).could_extract_minus_sign() == True # used to give inf recurs - assert ((-x-y)/(x+y)).could_extract_minus_sign() == True # is_Mul odd case + assert (Integer(-3)).could_extract_minus_sign() is True + assert (-n*x + x).could_extract_minus_sign() != \ + (n*x - x).could_extract_minus_sign() + assert (x - y).could_extract_minus_sign() != \ + (-x + y).could_extract_minus_sign() + assert (1 - x - y).could_extract_minus_sign() is True + assert (1 - x + y).could_extract_minus_sign() is False + assert ((-x - x*y)/y).could_extract_minus_sign() is True + assert (-(x + x*y)/y).could_extract_minus_sign() is True + assert ((x + x*y)/(-y)).could_extract_minus_sign() is True + assert ((x + x*y)/y).could_extract_minus_sign() is False + assert (x*(-x - x**3)).could_extract_minus_sign() is True + assert ((-x - y)/(x + y)).could_extract_minus_sign() is True # The results of each of these will vary on different machines, e.g. # the first one might be False and the other (then) is true or vice versa, # so both are included. - assert ((-x-y)/(x-y)).could_extract_minus_sign() == False or\ - ((-x-y)/(y-x)).could_extract_minus_sign() == False # is_Mul even case - assert ( x - y).could_extract_minus_sign() == False - assert (-x + y).could_extract_minus_sign() == True + assert ((-x - y)/(x - y)).could_extract_minus_sign() is False or \ + ((-x - y)/(y - x)).could_extract_minus_sign() is False + assert (x - y).could_extract_minus_sign() is False + assert (-x + y).could_extract_minus_sign() is True + def test_coeff(): - assert (x+1).coeff(x+1) == 1 + assert (x + 1).coeff(x + 1) == 1 assert (3*x).coeff(0) == 0 - assert (z*(1+x)*x**2).coeff(1+x) == z*x**2 - assert (1+2*x*x**(1+x)).coeff(x*x**(1+x)) == 2 - assert (1+2*x**(y+z)).coeff(x**(y+z)) == 2 - assert (3+2*x+4*x**2).coeff(1) == 0 - assert (3+2*x+4*x**2).coeff(-1) == 0 - assert (3+2*x+4*x**2).coeff(x) == 2 - assert (3+2*x+4*x**2).coeff(x**2) == 4 - assert (3+2*x+4*x**2).coeff(x**3) == 0 + assert (z*(1 + x)*x**2).coeff(1 + x) == z*x**2 + assert (1 + 2*x*x**(1 + x)).coeff(x*x**(1 + x)) == 2 + assert (1 + 2*x**(y + z)).coeff(x**(y + z)) == 2 + assert (3 + 2*x + 4*x**2).coeff(1) == 0 + assert (3 + 2*x + 4*x**2).coeff(-1) == 0 + assert (3 + 2*x + 4*x**2).coeff(x) == 2 + assert (3 + 2*x + 4*x**2).coeff(x**2) == 4 + assert (3 + 2*x + 4*x**2).coeff(x**3) == 0 assert (-x/8 + x*y).coeff(x) == -S(1)/8 + y assert (-x/8 + x*y).coeff(-x) == S(1)/8 @@ -902,22 +1045,22 @@ n1, n2 = symbols('n1 n2', commutative=False) assert (n1*n2).coeff(n1) == 1 assert (n1*n2).coeff(n2) == n1 - assert (n1*n2 + x*n1).coeff(n1) == 1 # 1*n1*(n2+x) + assert (n1*n2 + x*n1).coeff(n1) == 1 # 1*n1*(n2+x) assert (n2*n1 + x*n1).coeff(n1) == n2 + x assert (n2*n1 + x*n1**2).coeff(n1) == n2 assert (n1**x).coeff(n1) == 0 assert (n1*n2 + n2*n1).coeff(n1) == 0 - assert (2*(n1+n2)*n2).coeff(n1+n2, right=1) == n2 - assert (2*(n1+n2)*n2).coeff(n1+n2, right=0) == 2 + assert (2*(n1 + n2)*n2).coeff(n1 + n2, right=1) == n2 + assert (2*(n1 + n2)*n2).coeff(n1 + n2, right=0) == 2 f = Function('f') assert (2*f(x) + 3*f(x).diff(x)).coeff(f(x)) == 2 - expr = z*(x+y)**2 - expr2 = z*(x+y)**2 + z*(2*x + 2*y)**2 - assert expr.coeff(z) == (x+y)**2 - assert expr.coeff(x+y) == 0 - assert expr2.coeff(z) == (x+y)**2 + (2*x + 2*y)**2 + expr = z*(x + y)**2 + expr2 = z*(x + y)**2 + z*(2*x + 2*y)**2 + assert expr.coeff(z) == (x + y)**2 + assert expr.coeff(x + y) == 0 + assert expr2.coeff(z) == (x + y)**2 + (2*x + 2*y)**2 assert (x + y + 3*z).coeff(1) == x + y assert (-x + 2*y).coeff(-1) == x @@ -925,7 +1068,7 @@ assert (3 + 2*x + 4*x**2).coeff(1) == 0 assert (-x - 2*y).coeff(2) == -y assert (x + sqrt(2)*x).coeff(sqrt(2)) == x - assert (3 + 2*x + 4*x**2).coeff(x) == 2 + assert (3 + 2*x + 4*x**2).coeff(x) == 2 assert (3 + 2*x + 4*x**2).coeff(x**2) == 4 assert (3 + 2*x + 4*x**2).coeff(x**3) == 0 assert (z*(x + y)**2).coeff((x + y)**2) == z @@ -939,7 +1082,7 @@ assert x.coeff(x, 0) == 0 n, m, o, l = symbols('n m o l', commutative=False) - assert n.coeff(n) == 1 + assert n.coeff(n) == 1 assert y.coeff(n) == 0 assert (3*n).coeff(n) == 3 assert (2 + n).coeff(x*m) == 0 @@ -947,11 +1090,12 @@ assert (2 + n).coeff(x*m*n + y) == 0 assert (2*x*n*m).coeff(3*n) == 0 assert (n*m + m*n*m).coeff(n) == 1 + m - assert (n*m + m*n*m).coeff(n, right=True) == m # = (1 + m)*n*m + assert (n*m + m*n*m).coeff(n, right=True) == m # = (1 + m)*n*m assert (n*m + m*n).coeff(n) == 0 assert (n*m + o*m*n).coeff(m*n) == o assert (n*m + o*m*n).coeff(m*n, right=1) == 1 - assert (n*m + n*m*n).coeff(n*m, right=1) == 1 + n # = n*m*(n + 1) + assert (n*m + n*m*n).coeff(n*m, right=1) == 1 + n # = n*m*(n + 1) + def test_coeff2(): r, kappa = symbols('r, kappa') @@ -960,6 +1104,7 @@ g = g.expand() assert g.coeff((psi(r).diff(r))) == 2/r + def test_coeff2_0(): r, kappa = symbols('r, kappa') psi = Function("psi") @@ -968,21 +1113,25 @@ assert g.coeff(psi(r).diff(r, 2)) == 1 + def test_coeff_expand(): - expr = z*(x+y)**2 - expr2 = z*(x+y)**2 + z*(2*x + 2*y)**2 - assert expr.coeff(z) == (x+y)**2 - assert expr2.coeff(z) == (x+y)**2 + (2*x + 2*y)**2 + expr = z*(x + y)**2 + expr2 = z*(x + y)**2 + z*(2*x + 2*y)**2 + assert expr.coeff(z) == (x + y)**2 + assert expr2.coeff(z) == (x + y)**2 + (2*x + 2*y)**2 + def test_integrate(): assert x.integrate(x) == x**2/2 assert x.integrate((x, 0, 1)) == S(1)/2 + def test_as_base_exp(): assert x.as_base_exp() == (x, S.One) assert (x*y*z).as_base_exp() == (x*y*z, S.One) - assert (x+y+z).as_base_exp() == (x+y+z, S.One) - assert ((x+y)**z).as_base_exp() == (x+y, z) + assert (x + y + z).as_base_exp() == (x + y + z, S.One) + assert ((x + y)**z).as_base_exp() == (x + y, z) + def test_issue1864(): assert hasattr(Mul(x, y), "is_commutative") @@ -992,45 +1141,54 @@ expr = Mul(Pow(2, 2, evaluate=False), 3, evaluate=False) + 1 assert hasattr(expr, "is_commutative") + def test_action_verbs(): - assert nsimplify((1/(exp(3*pi*x/5)+1))) == (1/(exp(3*pi*x/5)+1)).nsimplify() + assert nsimplify((1/(exp(3*pi*x/5) + 1))) == \ + (1/(exp(3*pi*x/5) + 1)).nsimplify() assert ratsimp(1/x + 1/y) == (1/x + 1/y).ratsimp() - assert trigsimp(log(x), deep=True) == (log(x)).trigsimp(deep = True) - assert radsimp(1/(2+sqrt(2))) == (1/(2+sqrt(2))).radsimp() - assert powsimp(x**y*x**z*y**z, combine='all') == (x**y*x**z*y**z).powsimp(combine='all') + assert trigsimp(log(x), deep=True) == (log(x)).trigsimp(deep=True) + assert radsimp(1/(2 + sqrt(2))) == (1/(2 + sqrt(2))).radsimp() + assert powsimp(x**y*x**z*y**z, combine='all') == \ + (x**y*x**z*y**z).powsimp(combine='all') assert simplify(x**y*x**z*y**z) == (x**y*x**z*y**z).simplify() assert together(1/x + 1/y) == (1/x + 1/y).together() # Not tested because it's deprecated #assert separate((x*(y*z)**3)**2) == ((x*(y*z)**3)**2).separate() - assert collect(a*x**2 + b*x**2 + a*x - b*x + c, x) == (a*x**2 + b*x**2 + a*x - b*x + c).collect(x) - assert apart(y/(y+2)/(y+1), y) == (y/(y+2)/(y+1)).apart(y) - assert combsimp(y/(x+2)/(x+1)) == (y/(x+2)/(x+1)).combsimp() - assert factor(x**2+5*x+6) == (x**2+5*x+6).factor() + assert collect(a*x**2 + b*x**2 + a*x - b*x + c, x) == \ + (a*x**2 + b*x**2 + a*x - b*x + c).collect(x) + assert apart(y/(y + 2)/(y + 1), y) == (y/(y + 2)/(y + 1)).apart(y) + assert combsimp(y/(x + 2)/(x + 1)) == (y/(x + 2)/(x + 1)).combsimp() + assert factor(x**2 + 5*x + 6) == (x**2 + 5*x + 6).factor() assert refine(sqrt(x**2)) == sqrt(x**2).refine() - assert cancel((x**2+5*x+6)/(x+2)) == ((x**2+5*x+6)/(x+2)).cancel() + assert cancel((x**2 + 5*x + 6)/(x + 2)) == ((x**2 + 5*x + 6)/(x + 2)).cancel() + def test_as_powers_dict(): assert x.as_powers_dict() == {x: 1} assert (x**y*z).as_powers_dict() == {x: y, z: 1} assert Mul(2, 2, **dict(evaluate=False)).as_powers_dict() == {S(2): S(2)} + assert (x*y).as_powers_dict()[z] == 0 + assert (x + y).as_powers_dict()[z] == 0 + def test_as_coefficients_dict(): check = [S(1), x, y, x*y, 1] assert [Add(3*x, 2*x, y, 3).as_coefficients_dict()[i] for i in check] == \ - [3, 5, 1, 0, 0] + [3, 5, 1, 0, 0] assert [(3*x*y).as_coefficients_dict()[i] for i in check] == \ - [0, 0, 0, 3, 0] + [0, 0, 0, 3, 0] assert (3.0*x*y).as_coefficients_dict()[3.0*x*y] == 1 + def test_args_cnc(): A = symbols('A', commutative=False) - assert (x+A).args_cnc() == \ + assert (x + A).args_cnc() == \ [[], [x + A]] - assert (x+a).args_cnc() == \ + assert (x + a).args_cnc() == \ [[a + x], []] assert (x*a).args_cnc() == \ [[a, x], []] - assert (x*y*A*(A+1)).args_cnc(cset=True) == \ + assert (x*y*A*(A + 1)).args_cnc(cset=True) == \ [set([x, y]), [A, 1 + A]] assert Mul(x, x, evaluate=False).args_cnc(cset=True, warn=False) == \ [set([x]), []] @@ -1039,6 +1197,9 @@ raises(ValueError, lambda: Mul(x, x, evaluate=False).args_cnc(cset=True)) assert Mul(x, y, x, evaluate=False).args_cnc() == \ [[x, y, x], []] + # always split -1 from leading number + assert (-1.*x).args_cnc() == [[-1, 1.0, x], []] + def test_new_rawargs(): n = Symbol('n', commutative=False) @@ -1059,10 +1220,12 @@ assert m._new_rawargs(x, n, reeval=False).is_commutative is False assert m._new_rawargs(S.One) is S.One + def test_2127(): assert Add(evaluate=False) == 0 assert Mul(evaluate=False) == 1 - assert Mul(x+y, evaluate=False).is_Add + assert Mul(x + y, evaluate=False).is_Add + def test_free_symbols(): # free_symbols should return the free symbols of an object @@ -1073,13 +1236,11 @@ assert meter.free_symbols == set() assert (meter**x).free_symbols == set([x]) + def test_issue2201(): x = Symbol('x', commutative=False) assert x*sqrt(2)/sqrt(6) == x*sqrt(3)/3 -def test_issue_2061(): - assert sqrt(-1.0*x) == 1.0*sqrt(-x) - assert sqrt(1.0*x) == 1.0*sqrt(x) def test_as_coeff_Mul(): assert Integer(3).as_coeff_Mul() == (Integer(3), Integer(1)) @@ -1097,6 +1258,7 @@ assert (x).as_coeff_Mul() == (S.One, x) assert (x*y).as_coeff_Mul() == (S.One, x*y) + def test_as_coeff_Add(): assert Integer(3).as_coeff_Add() == (Integer(3), Integer(0)) assert Rational(3, 4).as_coeff_Add() == (Rational(3, 4), Integer(0)) @@ -1113,13 +1275,15 @@ assert (x).as_coeff_Add() == (S.Zero, x) assert (x*y).as_coeff_Add() == (S.Zero, x*y) + def test_expr_sorting(): f, g = symbols('f,g', cls=Function) exprs = [1/x**2, 1/x, sqrt(sqrt(x)), sqrt(x), x, sqrt(x)**3, x**2] assert sorted(exprs, key=default_sort_key) == exprs - exprs = [x, 2*x, 2*x**2, 2*x**3, x**n, 2*x**n, sin(x), sin(x)**n, sin(x**2), cos(x), cos(x**2), tan(x)] + exprs = [x, 2*x, 2*x**2, 2*x**3, x**n, 2*x**n, sin(x), sin(x)**n, + sin(x**2), cos(x), cos(x**2), tan(x)] assert sorted(exprs, key=default_sort_key) == exprs exprs = [x + 1, x**2 + x + 1, x**3 + x**2 + x + 1] @@ -1152,11 +1316,13 @@ exprs = [set([1]), set([1, 2])] assert sorted(exprs, key=default_sort_key) == exprs + def test_as_ordered_factors(): f, g = symbols('f,g', cls=Function) assert x.as_ordered_factors() == [x] - assert (2*x*x**n*sin(x)*cos(x)).as_ordered_factors() == [Integer(2), x, x**n, sin(x), cos(x)] + assert (2*x*x**n*sin(x)*cos(x)).as_ordered_factors() \ + == [Integer(2), x, x**n, sin(x), cos(x)] args = [f(1), f(2), f(3), f(1, 2, 3), g(1), g(2), g(3), g(1, 2, 3)] expr = Mul(*args) @@ -1168,11 +1334,13 @@ assert (A*B).as_ordered_factors() == [A, B] assert (B*A).as_ordered_factors() == [B, A] + def test_as_ordered_terms(): f, g = symbols('f,g', cls=Function) assert x.as_ordered_terms() == [x] - assert (sin(x)**2*cos(x) + sin(x)*cos(x)**2 + 1).as_ordered_terms() == [sin(x)**2*cos(x), sin(x)*cos(x)**2, 1] + assert (sin(x)**2*cos(x) + sin(x)*cos(x)**2 + 1).as_ordered_terms() \ + == [sin(x)**2*cos(x), sin(x)*cos(x)**2, 1] args = [f(1), f(2), f(3), f(1, 2, 3), g(1), g(2), g(3), g(1, 2, 3)] expr = Add(*args) @@ -1181,14 +1349,14 @@ assert (1 + 4*sqrt(3)*pi*x).as_ordered_terms() == [4*pi*x*sqrt(3), 1] - assert ( 2 + 3*I).as_ordered_terms() == [ 2, 3*I] - assert (-2 + 3*I).as_ordered_terms() == [-2, 3*I] - assert ( 2 - 3*I).as_ordered_terms() == [ 2, -3*I] + assert ( 2 + 3*I).as_ordered_terms() == [2, 3*I] + assert (-2 + 3*I).as_ordered_terms() == [-2, 3*I] + assert ( 2 - 3*I).as_ordered_terms() == [2, -3*I] assert (-2 - 3*I).as_ordered_terms() == [-2, -3*I] - assert ( 4 + 3*I).as_ordered_terms() == [ 4, 3*I] - assert (-4 + 3*I).as_ordered_terms() == [-4, 3*I] - assert ( 4 - 3*I).as_ordered_terms() == [ 4, -3*I] + assert ( 4 + 3*I).as_ordered_terms() == [4, 3*I] + assert (-4 + 3*I).as_ordered_terms() == [-4, 3*I] + assert ( 4 - 3*I).as_ordered_terms() == [4, -3*I] assert (-4 - 3*I).as_ordered_terms() == [-4, -3*I] f = x**2*y**2 + x*y**4 + y + 2 @@ -1198,10 +1366,12 @@ assert f.as_ordered_terms(order="rev-lex") == [2, y, x*y**4, x**2*y**2] assert f.as_ordered_terms(order="rev-grlex") == [2, y, x**2*y**2, x*y**4] + def test_sort_key_atomic_expr(): from sympy.physics.units import m, s assert sorted([-m, s], key=lambda arg: arg.sort_key()) == [-m, s] + def test_issue_1100(): # first subs and limit gives NaN a = x/y @@ -1213,6 +1383,7 @@ assert a._eval_interval(x, 1, oo)._eval_interval(y, oo, 1) is S.NaN raises(ValueError, lambda: x._eval_interval(x, None, None)) + def test_primitive(): assert (3*(x + 1)**2).primitive() == (3, (x + 1)**2) assert (6*x + 2).primitive() == (2, 3*x + 1) @@ -1233,36 +1404,38 @@ (S(1)/21, 14*x + 12*y + oo) assert S.Zero.primitive() == (S.One, S.Zero) + def test_issue_2744(): a = 1 + x assert (2*a).extract_multiplicatively(a) == 2 assert (4*a).extract_multiplicatively(2*a) == 2 assert ((3*a)*(2*a)).extract_multiplicatively(a) == 6*a + def test_is_constant(): from sympy.solvers.solvers import checksol - Sum(x, (x, 1, 10)).is_constant() == True - Sum(x, (x, 1, n)).is_constant() == False - Sum(x, (x, 1, n)).is_constant(y) == True - Sum(x, (x, 1, n)).is_constant(n) == False - Sum(x, (x, 1, n)).is_constant(x) == True + Sum(x, (x, 1, 10)).is_constant() is True + Sum(x, (x, 1, n)).is_constant() is False + Sum(x, (x, 1, n)).is_constant(y) is True + Sum(x, (x, 1, n)).is_constant(n) is False + Sum(x, (x, 1, n)).is_constant(x) is True eq = a*cos(x)**2 + a*sin(x)**2 - a - eq.is_constant() == True - assert eq.subs({x:pi, a:2}) == eq.subs({x:pi, a:3}) == 0 + eq.is_constant() is True + assert eq.subs({x: pi, a: 2}) == eq.subs({x: pi, a: 3}) == 0 assert x.is_constant() is False assert x.is_constant(y) is True - assert checksol(x, x, Sum(x, (x, 1, n))) == False - assert checksol(x, x, Sum(x, (x, 1, n))) == False + assert checksol(x, x, Sum(x, (x, 1, n))) is False + assert checksol(x, x, Sum(x, (x, 1, n))) is False f = Function('f') - assert checksol(x, x, f(x)) == False + assert checksol(x, x, f(x)) is False p = symbols('p', positive=True) - assert Pow(x, S(0), evaluate=False).is_constant() == True # == 1 - assert Pow(S(0), x, evaluate=False).is_constant() == False # == 0 or 1 - assert Pow(S(0), p, evaluate=False).is_constant() == True # == 1 - assert (2**x).is_constant() == False - assert Pow(S(2), S(3), evaluate=False).is_constant() == True + assert Pow(x, S(0), evaluate=False).is_constant() is True # == 1 + assert Pow(S(0), x, evaluate=False).is_constant() is False # == 0 or 1 + assert Pow(S(0), p, evaluate=False).is_constant() is True # == 1 + assert (2**x).is_constant() is False + assert Pow(S(2), S(3), evaluate=False).is_constant() is True z1, z2 = symbols('z1 z2', zero=True) assert (z1 + 2*z2).is_constant() is True @@ -1271,6 +1444,7 @@ assert (3*meter).is_constant() is True assert (x*meter).is_constant() is False + def test_equals(): assert (-3 - sqrt(5) + (-sqrt(10)/2 - sqrt(2)/2)**2).equals(0) assert (x**2 - 1).equals((x + 1)*(x - 1)) @@ -1285,6 +1459,10 @@ assert (sqrt(5) + pi).equals(0) is False assert meter.equals(0) is False assert (3*meter**2).equals(0) is False + eq = -(-1)**(S(3)/4)*6**(S(1)/4) + (-6)**(S(1)/4)*I + if eq != 0: # if canonicalization makes this zero, skip the test + assert eq.equals(0) + assert sqrt(x).equals(0) is False # from integrate(x*sqrt(1+2*x), x); # diff is zero only when assumptions allow @@ -1300,10 +1478,41 @@ assert diff.subs(x, p).equals(0) is True assert diff.subs(x, -1).equals(0) is True + # prove via minimal_polynomial or self-consistency + eq = sqrt(1 + sqrt(3)) + sqrt(3 + 3*sqrt(3)) - sqrt(10 + 6*sqrt(3)) + assert eq.equals(0) + q = 3**Rational(1, 3) + 3 + p = expand(q**3)**Rational(1, 3) + assert (p - q).equals(0) + + # issue 3730 + # eq = q*x + q/4 + x**4 + x**3 + 2*x**2 - S(1)/3 + # z = eq.subs(x, solve(eq, x)[0]) + q = symbols('q') + z = (q*(-sqrt(-2*(-(q - S(7)/8)**S(2)/8 - S(2197)/13824)**(S(1)/3) - + S(13)/12)/2 - sqrt((2*q - S(7)/4)/sqrt(-2*(-(q - S(7)/8)**S(2)/8 - + S(2197)/13824)**(S(1)/3) - S(13)/12) + 2*(-(q - S(7)/8)**S(2)/8 - + S(2197)/13824)**(S(1)/3) - S(13)/6)/2 - S(1)/4) + q/4 + (-sqrt(-2*(-(q + - S(7)/8)**S(2)/8 - S(2197)/13824)**(S(1)/3) - S(13)/12)/2 - sqrt((2*q + - S(7)/4)/sqrt(-2*(-(q - S(7)/8)**S(2)/8 - S(2197)/13824)**(S(1)/3) - + S(13)/12) + 2*(-(q - S(7)/8)**S(2)/8 - S(2197)/13824)**(S(1)/3) - + S(13)/6)/2 - S(1)/4)**4 + (-sqrt(-2*(-(q - S(7)/8)**S(2)/8 - + S(2197)/13824)**(S(1)/3) - S(13)/12)/2 - sqrt((2*q - + S(7)/4)/sqrt(-2*(-(q - S(7)/8)**S(2)/8 - S(2197)/13824)**(S(1)/3) - + S(13)/12) + 2*(-(q - S(7)/8)**S(2)/8 - S(2197)/13824)**(S(1)/3) - + S(13)/6)/2 - S(1)/4)**3 + 2*(-sqrt(-2*(-(q - S(7)/8)**S(2)/8 - + S(2197)/13824)**(S(1)/3) - S(13)/12)/2 - sqrt((2*q - + S(7)/4)/sqrt(-2*(-(q - S(7)/8)**S(2)/8 - S(2197)/13824)**(S(1)/3) - + S(13)/12) + 2*(-(q - S(7)/8)**S(2)/8 - S(2197)/13824)**(S(1)/3) - + S(13)/6)/2 - S(1)/4)**2 - S(1)/3) + assert z.equals(0) + + def test_random(): - from sympy import posify + from sympy import posify, lucas assert posify(x)[0]._random() is not None - assert S('-pi*Abs(1/log(n!)) + 1')._random(2, -2, 0, -1, 0) is None + assert lucas(n)._random(2, -2, 0, -1, 1) is None + def test_round(): from sympy.abc import x @@ -1353,12 +1562,12 @@ assert S.Zero.round() == 0 - a = (Add(1, Float('1.'+'9'*27, ''), evaluate=0)) - assert a.round(10) == Float('3.0000000000','') - assert a.round(25) == Float('3.0000000000000000000000000','') - assert a.round(26) == Float('3.00000000000000000000000000','') - assert a.round(27) == Float('2.999999999999999999999999999','') - assert a.round(30) == Float('2.999999999999999999999999999','') + a = (Add(1, Float('1.' + '9'*27, ''), evaluate=0)) + assert a.round(10) == Float('3.0000000000', '') + assert a.round(25) == Float('3.0000000000000000000000000', '') + assert a.round(26) == Float('3.00000000000000000000000000', '') + assert a.round(27) == Float('2.999999999999999999999999999', '') + assert a.round(30) == Float('2.999999999999999999999999999', '') raises(TypeError, lambda: x.round()) @@ -1377,10 +1586,35 @@ # the floats assert str((pi/10 + E*I).round(2)) == '0.31 + 2.72*I' assert (pi/10 + E*I).round(2).as_real_imag() == (0.31, 2.72) - assert (pi/10 + E*I).round(2) == Float(0.31, 2) + I*Float(2.72, 3) + assert (pi/10 + E*I).round(2) == Float(0.31, 2) + I*Float(2.72, 3) # issue 3815 - assert (I**(I+3)).round(3) == Float('-0.208','')*I + assert (I**(I + 3)).round(3) == Float('-0.208', '')*I + def test_extract_branch_factor(): assert exp_polar(2.0*I*pi).extract_branch_factor() == (1, 1) + + +def test_identity_removal(): + assert Add.make_args(x + 0) == (x,) + assert Mul.make_args(x*1) == (x,) + + +def test_float_0(): + assert Float(0.0) + 1 == Float(1.0) + + +@XFAIL +def test_float_0_fail(): + assert Float(0.0)*x == Float(0.0) + assert (x + Float(0.0)).is_Add + + +def test_issue_3226(): + ans = (b**2 + z**2 - (b*(a + b*t) + z*(c + t*z))**2/( + (a + b*t)**2 + (c + t*z)**2))/sqrt((a + b*t)**2 + (c + t*z)**2) + e = sqrt((a + b*t)**2 + (c + z*t)**2) + assert diff(e, t, 2) == ans + e.diff(t, 2) == ans + assert diff(e, t, 2, simplify=False) != ans diff -Nru python3-sympy-0.7.2/sympy/core/tests/test_exprtools.py python3-sympy-0.7.3/sympy/core/tests/test_exprtools.py --- python3-sympy-0.7.2/sympy/core/tests/test_exprtools.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/core/tests/test_exprtools.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,33 +1,40 @@ """Tests for tools for manipulating of large commutative expressions. """ -from sympy import (S, Add, sin, Mul, Symbol, oo, Integral, sqrt, Tuple, - Interval, O, symbols, simplify, collect, Sum, Basic, Dict) +from sympy import (S, Add, sin, Mul, Symbol, oo, Integral, sqrt, Tuple, I, + Interval, O, symbols, simplify, collect, Sum, Basic, Dict, + root, exp) from sympy.abc import a, b, t, x, y, z from sympy.core.exprtools import (decompose_power, Factors, Term, _gcd_terms, gcd_terms, factor_terms, factor_nc) from sympy.core.mul import _keep_coeff as _keep_coeff from sympy.simplify.cse_opts import sub_pre +from sympy.utilities.pytest import raises + + def test_decompose_power(): assert decompose_power(x) == (x, 1) assert decompose_power(x**2) == (x, 2) assert decompose_power(x**(2*y)) == (x**y, 2) assert decompose_power(x**(2*y/3)) == (x**(y/3), 2) -def test_Factors(): - assert Factors() == Factors({}) +def test_Factors(): + assert Factors() == Factors({}) == Factors(S(1)) assert Factors().as_expr() == S.One assert Factors({x: 2, y: 3, sin(x): 4}).as_expr() == x**2*y**3*sin(x)**4 + assert Factors(S.Infinity) == Factors({oo: 1}) + assert Factors(S.NegativeInfinity) == Factors({oo: 1, -1: 1}) a = Factors({x: 5, y: 3, z: 7}) - b = Factors({y: 4, z: 3, t: 10}) + b = Factors({ y: 4, z: 3, t: 10}) assert a.mul(b) == a*b == Factors({x: 5, y: 7, z: 10, t: 10}) - assert a.div(b) == divmod(a, b) == (Factors({x: 5, z: 4}), Factors({y: 1, t: 10})) + assert a.div(b) == divmod(a, b) == \ + (Factors({x: 5, z: 4}), Factors({y: 1, t: 10})) assert a.quo(b) == a/b == Factors({x: 5, z: 4}) - assert a.rem(b) == a%b == Factors({y: 1, t: 10}) + assert a.rem(b) == a % b == Factors({y: 1, t: 10}) assert a.pow(3) == a**3 == Factors({x: 15, y: 9, z: 21}) assert b.pow(3) == b**3 == Factors({y: 12, z: 9, t: 30}) @@ -40,6 +47,82 @@ assert a.normal(b) == (Factors({x: 4, y: 7, t: 4}), Factors({z: 1})) + assert Factors(sqrt(2)*x).as_expr() == sqrt(2)*x + + assert Factors(-I)*I == Factors() + assert Factors({S(-1): S(3)})*Factors({S(-1): S(1), I: S(5)}) == \ + Factors(I) + + assert Factors(S(2)**x).div(S(3)**x) == \ + (Factors({S(2): x}), Factors({S(3): x})) + assert Factors(2**(2*x + 2)).div(S(8)) == \ + (Factors({S(2): 2*x + 2}), Factors({S(8): S(1)})) + + # coverage + # /!\ things break if this is not True + assert Factors({S(-1): S(3)/2}) == Factors({I: S.One, S(-1): S.One}) + assert Factors({I: S(1), S(-1): S(1)/3}).as_expr() == I*(-1)**(S(1)/3) + + assert Factors(-1.) == Factors({S(-1): S(1), S(1.): 1}) + assert Factors(-2.) == Factors({S(-1): S(1), S(2.): 1}) + assert Factors((-2.)**x) == Factors({S(-2.): x}) + assert Factors(S(-2)) == Factors({S(-1): S(1), S(2): 1}) + assert Factors(S.Half) == Factors({S(2): -S.One}) + assert Factors(S(3)/2) == Factors({S(3): S.One, S(2): S(-1)}) + assert Factors({I: S(1)}) == Factors(I) + assert Factors({-1.0: 2, I: 1}) == Factors({S(1.0): 1, I: 1}) + assert Factors({S.NegativeOne: -S(3)/2}).as_expr() == I + A = symbols('A', commutative=False) + assert Factors(2*A**2) == Factors({S(2): 1, A**2: 1}) + assert Factors(I) == Factors({I: S.One}) + assert Factors(x).normal(S(2)) == (Factors(x), Factors(S(2))) + assert Factors(x).normal(S(0)) == (Factors(), Factors(S(0))) + raises(ZeroDivisionError, lambda: Factors(x).div(S(0))) + assert Factors(x).mul(S(2)) == Factors(2*x) + assert Factors(x).mul(S(0)).is_zero + assert Factors(x).mul(1/x).is_one + assert Factors(x**sqrt(2)**3).as_expr() == x**(2*sqrt(2)) + assert Factors(x)**Factors(S(2)) == Factors(x**2) + assert Factors(x).gcd(S(0)) == Factors(x) + assert Factors(x).lcm(S(0)).is_zero + assert Factors(S(0)).div(x) == (Factors(S(0)), Factors()) + assert Factors(x).div(x) == (Factors(), Factors()) + assert Factors({x: .2})/Factors({x: .2}) == Factors() + assert Factors(x) != Factors() + assert Factors(S(0)).normal(x) == (Factors(S(0)), Factors()) + n, d = x**(2 + y), x**2 + f = Factors(n) + assert f.div(d) == f.normal(d) == (Factors(x**y), Factors()) + d = x**y + assert f.div(d) == f.normal(d) == (Factors(x**2), Factors()) + n = d = 2**x + f = Factors(n) + assert f.div(d) == f.normal(d) == (Factors(), Factors()) + n, d = 2**x, 2**y + f = Factors(n) + assert f.div(d) == f.normal(d) == (Factors({S(2): x}), Factors({S(2): y})) + + # extraction of constant only + n = x**(x + 3) + assert Factors(n).normal(x**-3) == (Factors({x: x + 6}), Factors({})) + assert Factors(n).normal(x**3) == (Factors({x: x}), Factors({})) + assert Factors(n).normal(x**4) == (Factors({x: x}), Factors({x: 1})) + assert Factors(n).normal(x**(y - 3)) == \ + (Factors({x: x + 6}), Factors({x: y})) + assert Factors(n).normal(x**(y + 3)) == (Factors({x: x}), Factors({x: y})) + assert Factors(n).normal(x**(y + 4)) == \ + (Factors({x: x}), Factors({x: y + 1})) + + assert Factors(n).div(x**-3) == (Factors({x: x + 6}), Factors({})) + assert Factors(n).div(x**3) == (Factors({x: x}), Factors({})) + assert Factors(n).div(x**4) == (Factors({x: x}), Factors({x: 1})) + assert Factors(n).div(x**(y - 3)) == \ + (Factors({x: x + 6}), Factors({x: y})) + assert Factors(n).div(x**(y + 3)) == (Factors({x: x}), Factors({x: y})) + assert Factors(n).div(x**(y + 4)) == \ + (Factors({x: x}), Factors({x: y + 1})) + + def test_Term(): a = Term(4*x*y**2/z/t**3) b = Term(2*x**3*y**5/t**3) @@ -50,17 +133,22 @@ assert a.as_expr() == 4*x*y**2/z/t**3 assert b.as_expr() == 2*x**3*y**5/t**3 - assert a.inv() == Term(S(1)/4, Factors({z: 1, t: 3}), Factors({x: 1, y: 2})) + assert a.inv() == \ + Term(S(1)/4, Factors({z: 1, t: 3}), Factors({x: 1, y: 2})) assert b.inv() == Term(S(1)/2, Factors({t: 3}), Factors({x: 3, y: 5})) - assert a.mul(b) == a*b == Term(8, Factors({x: 4, y: 7}), Factors({z: 1, t: 6})) + assert a.mul(b) == a*b == \ + Term(8, Factors({x: 4, y: 7}), Factors({z: 1, t: 6})) assert a.quo(b) == a/b == Term(2, Factors({}), Factors({x: 2, y: 3, z: 1})) - assert a.pow(3) == a**3 == Term(64, Factors({x: 3, y: 6}), Factors({z: 3, t: 9})) + assert a.pow(3) == a**3 == \ + Term(64, Factors({x: 3, y: 6}), Factors({z: 3, t: 9})) assert b.pow(3) == b**3 == Term(8, Factors({x: 9, y: 15}), Factors({t: 9})) - assert a.pow(-3) == a**(-3) == Term(S(1)/64, Factors({z: 3, t: 9}), Factors({x: 3, y: 6})) - assert b.pow(-3) == b**(-3) == Term(S(1)/8, Factors({t: 9}), Factors({x: 9, y: 15})) + assert a.pow(-3) == a**(-3) == \ + Term(S(1)/64, Factors({z: 3, t: 9}), Factors({x: 3, y: 6})) + assert b.pow(-3) == b**(-3) == \ + Term(S(1)/8, Factors({t: 9}), Factors({x: 9, y: 15})) assert a.gcd(b) == Term(2, Factors({x: 1, y: 2}), Factors({t: 3})) assert a.lcm(b) == Term(4, Factors({x: 3, y: 5}), Factors({z: 1, t: 3})) @@ -71,13 +159,17 @@ assert a.mul(b) == Term(8, Factors({x: 4, y: 7, t: 4}), Factors({z: 1})) assert Term((2*x + 2)**3) == Term(8, Factors({x + 1: 3}), Factors({})) - assert Term((2*x + 2)*(3*x + 6)**2) == Term(18, Factors({x + 1: 1, x + 2: 2}), Factors({})) + assert Term((2*x + 2)*(3*x + 6)**2) == \ + Term(18, Factors({x + 1: 1, x + 2: 2}), Factors({})) + def test_gcd_terms(): - f = 2*(x + 1)*(x + 4)/(5*x**2 + 5) + (2*x + 2)*(x + 5)/(x**2 + 1)/5 + (2*x + 2)*(x + 6)/(5*x**2 + 5) + f = 2*(x + 1)*(x + 4)/(5*x**2 + 5) + (2*x + 2)*(x + 5)/(x**2 + 1)/5 + \ + (2*x + 2)*(x + 6)/(5*x**2 + 5) assert _gcd_terms(f) == ((S(6)/5)*((1 + x)/(1 + x**2)), 5 + x, 1) - assert _gcd_terms(Add.make_args(f)) == ((S(6)/5)*((1 + x)/(1 + x**2)), 5 + x, 1) + assert _gcd_terms(Add.make_args(f)) == \ + ((S(6)/5)*((1 + x)/(1 + x**2)), 5 + x, 1) newf = (S(6)/5)*((1 + x)*(5 + x)/(1 + x**2)) assert gcd_terms(f) == newf @@ -88,11 +180,11 @@ assert gcd_terms(set(args)) == newf # but a Basic sequence is treated as a container assert gcd_terms(Tuple(*args)) != newf - assert gcd_terms(Basic(Tuple(1,3*y + 3*x*y), Tuple(1, 3))) == \ + assert gcd_terms(Basic(Tuple(1, 3*y + 3*x*y), Tuple(1, 3))) == \ Basic((1, 3*y*(x + 1)), (1, 3)) # but we shouldn't change keys of a dictionary or some may be lost - assert gcd_terms(Dict((x*(1 + y), 2),(x + x*y, y + x*y))) == \ - Dict({x*(y + 1): 2, x + x*y: y*(1 + x)}) + assert gcd_terms(Dict((x*(1 + y), 2), (x + x*y, y + x*y))) == \ + Dict({x*(y + 1): 2, x + x*y: y*(1 + x)}) assert gcd_terms((2*x + 2)**3 + (2*x + 2)**2) == 4*(x + 1)**2*(2*x + 3) @@ -119,6 +211,7 @@ eq = x/(x + 1/x) assert gcd_terms(eq, fraction=False) == eq + def test_factor_terms(): A = Symbol('A', commutative=False) assert factor_terms(9*(x + x*y + 1) + (3*x + 3)**(2 + 2*x)) == \ @@ -139,9 +232,14 @@ x*(a + 2*b)*(y + 1) i = Integral(x, (x, 0, oo)) assert factor_terms(i) == i + + # check radical extraction eq = sqrt(2) + sqrt(10) assert factor_terms(eq) == eq assert factor_terms(eq, radical=True) == sqrt(2)*(1 + sqrt(5)) + eq = root(-6, 3) + root(6, 3) + assert factor_terms(eq, radical=True) == 6**(S(1)/3)*(1 + (-1)**(S(1)/3)) + eq = [x + x*y] ans = [x*(y + 1)] for c in [list, tuple, set]: @@ -159,13 +257,27 @@ assert factor_terms((1/(x**3 + x**2) + 2/x**2)*y) == \ y*(2 + 1/(x + 1))/x**2 + # if not True, then processesing for this in factor_terms is not necessary + assert gcd_terms(-x - y) == -x - y + assert factor_terms(-x - y) == Mul(-1, x + y, evaluate=False) + + # if not True, then "special" processesing in factor_terms is not necessary + assert gcd_terms(exp(Mul(-1, x + 1))) == exp(-x - 1) + e = exp(-x - 2) + x + assert factor_terms(e) == exp(Mul(-1, x + 2, evaluate=False)) + x + assert factor_terms(e, sign=False) == e + assert factor_terms(exp(-4*x - 2) - x) == -x + exp(Mul(-2, 2*x + 1, evaluate=False)) + + def test_xreplace(): e = Mul(2, 1 + x, evaluate=False) assert e.xreplace({}) == e assert e.xreplace({y: x}) == e + def test_factor_nc(): x, y = symbols('x,y') + k = symbols('k', integer=True) n, m, o = symbols('n,m,o', commutative=False) # mul and multinomial expansion is needed @@ -190,7 +302,7 @@ factor_nc_test(x*(1 + sin(s))) factor_nc_test((1 + n)**2) - factor_nc_test((x + n)*(x + m)*(x+y)) + factor_nc_test((x + n)*(x + m)*(x + y)) factor_nc_test(x*(n*m + 1)) factor_nc_test(x*(n*m + x)) factor_nc_test(x*(x*n*m + 1)) @@ -216,6 +328,17 @@ eq = x*Commutator(m, n) + x*Commutator(m, o)*Commutator(m, n) assert factor(eq) == x*(1 + Commutator(m, o))*Commutator(m, n) + # issue 3435 + assert (2*n + 2*m).factor() == 2*(n + m) + + # issue 3602 + assert factor_nc(n**k + n**(k + 1)) == n**k*(1 + n) + assert factor_nc((m*n)**k + (m*n)**(k + 1)) == (1 + m*n)*(m*n)**k + + # issue 3819 + assert factor_nc(-n*(2*x**2 + 2*x)) == -2*n*x*(x + 1) + + def test_issue_3261(): a, b = symbols("a b") apb = a + b diff -Nru python3-sympy-0.7.2/sympy/core/tests/test_facts.py python3-sympy-0.7.3/sympy/core/tests/test_facts.py --- python3-sympy-0.7.2/sympy/core/tests/test_facts.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/core/tests/test_facts.py 2013-07-13 17:53:32.000000000 +0000 @@ -7,36 +7,40 @@ F = False U = None + def test_deduce_alpha_implications(): def D(i): I = deduce_alpha_implications(i) - P = rules_2prereq(dict(((k, True), set([(v, True) for v in S])) for k, S in list(I.items()))) - return I,P + P = rules_2prereq(dict( + ((k, True), set([(v, True) for v in S])) for k, S in list(I.items()))) + return I, P # transitivity - I,P = D([('a','b'), ('b','c')]) - assert I == {'a': set(['b','c']), 'b': set(['c'])} + I, P = D([('a', 'b'), ('b', 'c')]) + assert I == {'a': set(['b', 'c']), 'b': set(['c'])} assert P == {'b': set(['a']), 'c': set(['a', 'b'])} # see if the output does not contain repeated implications - I,P = D([('a','b'), ('b','c'), ('b','c')]) - assert I == {'a': set(['b','c']), 'b': set(['c'])} + I, P = D([('a', 'b'), ('b', 'c'), ('b', 'c')]) + assert I == {'a': set(['b', 'c']), 'b': set(['c'])} assert P == {'b': set(['a']), 'c': set(['a', 'b'])} # see if it is tolerant to cycles - assert D([('a','a'), ('a','a')]) == ({}, {}) - assert D([('a','b'), ('b','a')]) == ({'a': set(['b']), 'b': set(['a'])}, {'a': set(['b']), 'b': set(['a'])}) + assert D([('a', 'a'), ('a', 'a')]) == ({}, {}) + assert D([('a', 'b'), ('b', 'a')]) == ( + {'a': set(['b']), 'b': set(['a'])}, + {'a': set(['b']), 'b': set(['a'])}) # see if it catches inconsistency - raises(ValueError, lambda: D([('a',Not('a'))])) - raises(ValueError, lambda: D([('a','b'), ('b',Not('a'))])) - raises(ValueError, lambda: D([('a','b'), ('b','c'), ('b','na'), ('na',Not('a'))])) - + raises(ValueError, lambda: D([('a', Not('a'))])) + raises(ValueError, lambda: D([('a', 'b'), ('b', Not('a'))])) + raises(ValueError, lambda: D([('a', 'b'), ('b', 'c'), ('b', 'na'), + ('na', Not('a'))])) # something related to real-world - I,P = D([('rat','real'), ('int','rat')]) + I, P = D([('rat', 'real'), ('int', 'rat')]) - assert I == {'int': set(['rat', 'real']), 'rat': set(['real'])} + assert I == {'int': set(['rat', 'real']), 'rat': set(['real'])} assert P == {'rat': set(['int']), 'real': set(['int', 'rat'])} @@ -49,156 +53,172 @@ return (set(), [bidx]) # x -> a &(a,b) -> x -- x -> a - A = {'x': set(['a'])}; B = [ (And('a','b'), 'x') ] - assert APPLY(A, B) == {'x': (set(['a']), []), 'a':Q(0), 'b':Q(0)} + A = {'x': set(['a'])} + B = [(And('a', 'b'), 'x')] + assert APPLY(A, B) == {'x': (set(['a']), []), 'a': Q(0), 'b': Q(0)} # x -> a &(a,!x) -> b -- x -> a - A = {'x': set(['a'])}; B = [ (And('a',Not('x')), 'b') ] - assert APPLY(A, B) == {'x': (set(['a']), []), Not('x'):Q(0), 'a':Q(0)} + A = {'x': set(['a'])} + B = [(And('a', Not('x')), 'b')] + assert APPLY(A, B) == {'x': (set(['a']), []), Not('x'): Q(0), 'a': Q(0)} # x -> a b &(a,b) -> c -- x -> a b c - A = {'x': set(['a','b'])}; B = [ (And('a','b'), 'c') ] - assert APPLY(A, B) == {'x': (set(['a','b','c']), []), 'a':Q(0), 'b':Q(0)} + A = {'x': set(['a', 'b'])} + B = [(And('a', 'b'), 'c')] + assert APPLY(A, B) == \ + {'x': (set(['a', 'b', 'c']), []), 'a': Q(0), 'b': Q(0)} # x -> a &(a,b) -> y -- x -> a [#0] - A = {'x': set(['a'])}; B = [ (And('a','b'), 'y') ] - assert APPLY(A, B) == {'x': (set(['a']), [0]), 'a':Q(0), 'b':Q(0)} + A = {'x': set(['a'])} + B = [(And('a', 'b'), 'y')] + assert APPLY(A, B) == {'x': (set(['a']), [0]), 'a': Q(0), 'b': Q(0)} # x -> a b c &(a,b) -> c -- x -> a b c - A = {'x': set(['a','b','c'])} - B = [ (And('a','b'), 'c') ] - assert APPLY(A, B) == {'x': (set(['a','b','c']), []), 'a':Q(0), 'b':Q(0)} + A = {'x': set(['a', 'b', 'c'])} + B = [(And('a', 'b'), 'c')] + assert APPLY(A, B) == \ + {'x': (set(['a', 'b', 'c']), []), 'a': Q(0), 'b': Q(0)} # x -> a b &(a,b,c) -> y -- x -> a b [#0] - A = {'x': set(['a','b'])}; B = [ (And('a','b','c'), 'y') ] - assert APPLY(A, B) == {'x': (set(['a','b']), [0]), 'a':Q(0), 'b':Q(0), 'c':Q(0)} + A = {'x': set(['a', 'b'])} + B = [(And('a', 'b', 'c'), 'y')] + assert APPLY(A, B) == \ + {'x': (set(['a', 'b']), [0]), 'a': Q(0), 'b': Q(0), 'c': Q(0)} # x -> a b &(a,b) -> c -- x -> a b c d # c -> d c -> d - A = {'x': set(['a','b']), 'c': set(['d'])} - B = [ (And('a','b'), 'c') ] - assert APPLY(A, B) == {'x': (set(['a','b','c','d']), []), 'c': (set(['d']), []), 'a':Q(0), 'b':Q(0)} + A = {'x': set(['a', 'b']), 'c': set(['d'])} + B = [(And('a', 'b'), 'c')] + assert APPLY(A, B) == {'x': (set(['a', 'b', 'c', 'd']), []), + 'c': (set(['d']), []), 'a': Q(0), 'b': Q(0)} # x -> a b &(a,b) -> c -- x -> a b c d e # c -> d &(c,d) -> e c -> d e - A = {'x': set(['a','b']), 'c': set(['d'])} - B = [ (And('a','b'), 'c'), (And('c','d'), 'e') ] - assert APPLY(A, B) == {'x': (set(['a','b','c','d','e']), []), 'c': (set(['d','e']), []), 'a':Q(0), 'b':Q(0), 'd':Q(1)} + A = {'x': set(['a', 'b']), 'c': set(['d'])} + B = [(And('a', 'b'), 'c'), (And('c', 'd'), 'e')] + assert APPLY(A, B) == {'x': (set(['a', 'b', 'c', 'd', 'e']), []), + 'c': (set(['d', 'e']), []), 'a': Q(0), 'b': Q(0), 'd': Q(1)} # x -> a b &(a,y) -> z -- x -> a b y z # &(a,b) -> y - A = {'x': set(['a','b'])} - B = [ (And('a','y'), 'z'), - (And('a','b'), 'y') ] - assert APPLY(A,B) == {'x': (set(['a','b','y','z']), []), 'a':(set(), [0,1]), 'y':Q(0), 'b':Q(1)} + A = {'x': set(['a', 'b'])} + B = [(And('a', 'y'), 'z'), (And('a', 'b'), 'y')] + assert APPLY(A, B) == {'x': (set(['a', 'b', 'y', 'z']), []), + 'a': (set(), [0, 1]), 'y': Q(0), 'b': Q(1)} # x -> a b &(a,!b) -> c -- x -> a b A = {'x': set(['a', 'b'])} - B = [ (And('a', Not('b')), 'c') ] - assert APPLY(A,B) == {'x': (set(['a', 'b']), []), 'a':Q(0), Not('b'):Q(0)} + B = [(And('a', Not('b')), 'c')] + assert APPLY(A, B) == \ + {'x': (set(['a', 'b']), []), 'a': Q(0), Not('b'): Q(0)} # !x -> !a !b &(!a,b) -> c -- !x -> !a !b A = {Not('x'): set([Not('a'), Not('b')])} - B = [ (And(Not('a'),'b'), 'c') ] - assert APPLY(A,B) == {Not('x'): (set([Not('a'), Not('b')]), []), Not('a'):Q(0), 'b':Q(0)} + B = [(And(Not('a'), 'b'), 'c')] + assert APPLY(A, B) == \ + {Not('x'): (set([Not('a'), Not('b')]), []), Not('a'): Q(0), 'b': Q(0)} # x -> a b &(b,c) -> !a -- x -> a b - A = {'x': set(['a','b'])} - B = [ (And('b','c'), Not('a')) ] - assert APPLY(A,B) == {'x': (set(['a','b']), []), 'b':Q(0), 'c':Q(0)} + A = {'x': set(['a', 'b'])} + B = [(And('b', 'c'), Not('a'))] + assert APPLY(A, B) == {'x': (set(['a', 'b']), []), 'b': Q(0), 'c': Q(0)} # x -> a b &(a, b) -> c -- x -> a b c p # c -> p a - A = {'x': set(['a','b']), 'c': set(['p','a'])} - B = [ (And('a','b'), 'c') ] - assert APPLY(A,B) == {'x': (set(['a','b','c','p']), []), - 'c': (set(['p','a']), []), 'a':Q(0), 'b':Q(0)} + A = {'x': set(['a', 'b']), 'c': set(['p', 'a'])} + B = [(And('a', 'b'), 'c')] + assert APPLY(A, B) == {'x': (set(['a', 'b', 'c', 'p']), []), + 'c': (set(['p', 'a']), []), 'a': Q(0), 'b': Q(0)} def test_FactRules_parse(): f = FactRules('a -> b') - assert f.prereq == {'b': set(['a']), 'a': set(['b'])} + assert f.prereq == {'b': set(['a']), 'a': set(['b'])} f = FactRules('a -> !b') - assert f.prereq == {'b': set(['a']), 'a': set(['b'])} + assert f.prereq == {'b': set(['a']), 'a': set(['b'])} f = FactRules('!a -> b') - assert f.prereq == {'b': set(['a']), 'a': set(['b'])} + assert f.prereq == {'b': set(['a']), 'a': set(['b'])} f = FactRules('!a -> !b') - assert f.prereq == {'b': set(['a']), 'a': set(['b'])} + assert f.prereq == {'b': set(['a']), 'a': set(['b'])} f = FactRules('!z == nz') - assert f.prereq == {'z': set(['nz']), 'nz': set(['z'])} + assert f.prereq == {'z': set(['nz']), 'nz': set(['z'])} def test_FactRules_parse2(): raises(ValueError, lambda: FactRules('a -> !a')) + def test_FactRules_deduce(): f = FactRules(['a -> b', 'b -> c', 'b -> d', 'c -> e']) + def D(facts): kb = FactKB(f) kb.deduce_all_facts(facts) return kb - assert D({'a': T}) == {'a': T, 'b': T, 'c': T, 'd': T, 'e': T} - assert D({'b': T}) == { 'b': T, 'c': T, 'd': T, 'e': T} - assert D({'c': T}) == { 'c': T, 'e': T} - assert D({'d': T}) == { 'd': T } - assert D({'e': T}) == { 'e': T} - - assert D({'a': F}) == {'a': F } - assert D({'b': F}) == {'a': F, 'b': F } - assert D({'c': F}) == {'a': F, 'b': F, 'c': F } - assert D({'d': F}) == {'a': F, 'b': F, 'd': F } + assert D({'a': T}) == {'a': T, 'b': T, 'c': T, 'd': T, 'e': T} + assert D({'b': T}) == { 'b': T, 'c': T, 'd': T, 'e': T} + assert D({'c': T}) == { 'c': T, 'e': T} + assert D({'d': T}) == { 'd': T } + assert D({'e': T}) == { 'e': T} + + assert D({'a': F}) == {'a': F } + assert D({'b': F}) == {'a': F, 'b': F } + assert D({'c': F}) == {'a': F, 'b': F, 'c': F } + assert D({'d': F}) == {'a': F, 'b': F, 'd': F } - assert D({'a': U}) == {'a': U} # XXX ok? + assert D({'a': U}) == {'a': U} # XXX ok? def test_FactRules_deduce2(): # pos/neg/zero, but the rules are not sufficient to derive all relations f = FactRules(['pos -> !neg', 'pos -> !z']) + def D(facts): kb = FactKB(f) kb.deduce_all_facts(facts) return kb - assert D({'pos':T}) == {'pos': T, 'neg': F, 'z': F} - assert D({'pos':F}) == {'pos': F } - assert D({'neg':T}) == {'pos': F, 'neg': T } - assert D({'neg':F}) == { 'neg': F } - assert D({'z': T}) == {'pos': F, 'z': T} - assert D({'z': F}) == { 'z': F} + assert D({'pos': T}) == {'pos': T, 'neg': F, 'z': F} + assert D({'pos': F}) == {'pos': F } + assert D({'neg': T}) == {'pos': F, 'neg': T } + assert D({'neg': F}) == { 'neg': F } + assert D({'z': T}) == {'pos': F, 'z': T} + assert D({'z': F}) == { 'z': F} # pos/neg/zero. rules are sufficient to derive all relations f = FactRules(['pos -> !neg', 'neg -> !pos', 'pos -> !z', 'neg -> !z']) - assert D({'pos':T}) == {'pos': T, 'neg': F, 'z': F} - assert D({'pos':F}) == {'pos': F } - assert D({'neg':T}) == {'pos': F, 'neg': T, 'z': F} - assert D({'neg':F}) == { 'neg': F } - assert D({'z': T}) == {'pos': F, 'neg': F, 'z': T} - assert D({'z': F}) == { 'z': F} + assert D({'pos': T}) == {'pos': T, 'neg': F, 'z': F} + assert D({'pos': F}) == {'pos': F } + assert D({'neg': T}) == {'pos': F, 'neg': T, 'z': F} + assert D({'neg': F}) == { 'neg': F } + assert D({'z': T}) == {'pos': F, 'neg': F, 'z': T} + assert D({'z': F}) == { 'z': F} def test_FactRules_deduce_multiple(): # deduction that involves _several_ starting points f = FactRules(['real == pos | npos']) + def D(facts): kb = FactKB(f) kb.deduce_all_facts(facts) return kb - assert D({'real': T}) == {'real': T} - assert D({'real': F}) == {'real': F, 'pos': F, 'npos': F} - assert D({'pos' : T}) == {'real': T, 'pos': T} - assert D({'npos': T}) == {'real': T, 'npos': T} + assert D({'real': T}) == {'real': T} + assert D({'real': F}) == {'real': F, 'pos': F, 'npos': F} + assert D({'pos': T}) == {'real': T, 'pos': T} + assert D({'npos': T}) == {'real': T, 'npos': T} # --- key tests below --- assert D({'pos': F, 'npos': F}) == {'real': F, 'pos': F, 'npos': F} assert D({'real': T, 'pos': F}) == {'real': T, 'pos': F, 'npos': T} - assert D({'real': T, 'npos':F}) == {'real': T, 'pos': T, 'npos': F} + assert D({'real': T, 'npos': F}) == {'real': T, 'pos': T, 'npos': F} assert D({'pos': T, 'npos': F}) == {'real': T, 'pos': T, 'npos': F} assert D({'pos': F, 'npos': T}) == {'real': T, 'pos': F, 'npos': T} @@ -206,31 +226,38 @@ def test_FactRules_deduce_multiple2(): f = FactRules(['real == neg | zero | pos']) + def D(facts): kb = FactKB(f) kb.deduce_all_facts(facts) return kb - assert D({'real': T}) == {'real': T} - assert D({'real': F}) == {'real': F, 'neg': F, 'zero': F, 'pos': F} - assert D({'neg' : T}) == {'real': T, 'neg': T} - assert D({'zero': T}) == {'real': T, 'zero': T} - assert D({'pos' : T}) == {'real': T, 'pos': T} + assert D({'real': T}) == {'real': T} + assert D({'real': F}) == {'real': F, 'neg': F, 'zero': F, 'pos': F} + assert D({'neg': T}) == {'real': T, 'neg': T} + assert D({'zero': T}) == {'real': T, 'zero': T} + assert D({'pos': T}) == {'real': T, 'pos': T} # --- key tests below --- - assert D({'neg': F, 'zero': F, 'pos': F}) == {'real': F, 'neg': F, 'zero': F, 'pos': F} - assert D({'real':T, 'neg': F}) == {'real': T, 'neg': F} - assert D({'real':T, 'zero':F}) == {'real': T, 'zero':F} - assert D({'real':T, 'pos': F}) == {'real': T, 'pos': F} - - assert D({'real':T, 'zero': F, 'pos': F}) == {'real': T, 'neg': T, 'zero': F, 'pos': F} - assert D({'real':T, 'neg': F, 'pos': F}) == {'real': T, 'neg': F, 'zero': T, 'pos': F} - assert D({'real':T, 'neg': F, 'zero': F }) == {'real': T, 'neg': F, 'zero': F, 'pos': T} - - - assert D({'neg': T, 'zero': F, 'pos': F}) == {'real': T, 'neg': T, 'zero': F, 'pos': F} - assert D({'neg': F, 'zero': T, 'pos': F}) == {'real': T, 'neg': F, 'zero': T, 'pos': F} - assert D({'neg': F, 'zero': F, 'pos': T}) == {'real': T, 'neg': F, 'zero': F, 'pos': T} + assert D({'neg': F, 'zero': F, 'pos': F}) == {'real': F, 'neg': F, + 'zero': F, 'pos': F} + assert D({'real': T, 'neg': F}) == {'real': T, 'neg': F} + assert D({'real': T, 'zero': F}) == {'real': T, 'zero': F} + assert D({'real': T, 'pos': F}) == {'real': T, 'pos': F} + + assert D({'real': T, 'zero': F, 'pos': F}) == {'real': T, + 'neg': T, 'zero': F, 'pos': F} + assert D({'real': T, 'neg': F, 'pos': F}) == {'real': T, + 'neg': F, 'zero': T, 'pos': F} + assert D({'real': T, 'neg': F, 'zero': F }) == {'real': T, + 'neg': F, 'zero': F, 'pos': T} + + assert D({'neg': T, 'zero': F, 'pos': F}) == {'real': T, 'neg': T, + 'zero': F, 'pos': F} + assert D({'neg': F, 'zero': T, 'pos': F}) == {'real': T, 'neg': F, + 'zero': T, 'pos': F} + assert D({'neg': F, 'zero': F, 'pos': T}) == {'real': T, 'neg': F, + 'zero': F, 'pos': T} def test_FactRules_deduce_base(): diff -Nru python3-sympy-0.7.2/sympy/core/tests/test_function.py python3-sympy-0.7.3/sympy/core/tests/test_function.py --- python3-sympy-0.7.2/sympy/core/tests/test_function.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/core/tests/test_function.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,6 +1,6 @@ from sympy import (Lambda, Symbol, Function, Derivative, Subs, sqrt, log, exp, Rational, Float, sin, cos, acos, diff, I, re, im, - E, expand, pi, O, Sum, S, polygamma, loggamma, + E, expand, pi, O, Sum, S, polygamma, loggamma, expint, Tuple, Dummy, Eq, Expr, symbols, nfloat) from sympy.utilities.pytest import XFAIL, raises from sympy.abc import t, w, x, y, z @@ -10,21 +10,24 @@ f, g, h = symbols('f g h', cls=Function) + def test_f_expand_complex(): x = Symbol('x', real=True) - assert f(x).expand(complex=True) == I*im(f(x)) + re(f(x)) - assert exp(x).expand(complex=True) == exp(x) - assert exp(I*x).expand(complex=True) == cos(x) + I*sin(x) - assert exp(z).expand(complex=True) == cos(im(z))*exp(re(z)) + \ - I*sin(im(z))*exp(re(z)) + assert f(x).expand(complex=True) == I*im(f(x)) + re(f(x)) + assert exp(x).expand(complex=True) == exp(x) + assert exp(I*x).expand(complex=True) == cos(x) + I*sin(x) + assert exp(z).expand(complex=True) == cos(im(z))*exp(re(z)) + \ + I*sin(im(z))*exp(re(z)) + def test_bug1(): e = sqrt(-log(w)) - assert e.subs(log(w),-x) == sqrt(x) + assert e.subs(log(w), -x) == sqrt(x) e = sqrt(-5*log(w)) - assert e.subs(log(w),-x) == sqrt(5*x) + assert e.subs(log(w), -x) == sqrt(5*x) + def test_general_function(): nu = Function('nu') @@ -41,6 +44,7 @@ assert edxdx == diff(diff(nu(x), x), x) assert edxdy == 0 + def test_derivative_subs_bug(): e = diff(g(x), x) assert e.subs(g(x), f(x)) != e @@ -49,6 +53,7 @@ assert e.subs(x, y) == Derivative(g(y), y) + def test_derivative_subs_self_bug(): d = diff(f(x), x) @@ -62,6 +67,7 @@ assert diff(8*f(x)*x, x) == 8*f(x) + 8*x*diff(f(x), x) assert diff(8*f(x)*y*x, x) == 8*y*f(x) + 8*y*x*diff(f(x), x) + def test_derivative_evaluate(): assert Derivative(sin(x), x) != diff(sin(x), x) assert Derivative(sin(x), x).doit() == diff(sin(x), x) @@ -69,6 +75,7 @@ assert Derivative(Derivative(f(x), x), x) == diff(f(x), x, x) assert Derivative(sin(x), x, 0) == sin(x) + def test_diff_symbols(): assert diff(f(x, y, z), x, y, z) == Derivative(f(x, y, z), x, y, z) assert diff(f(x, y, z), x, x, x) == Derivative(f(x, y, z), x, x, x) @@ -84,6 +91,7 @@ assert Derivative(Derivative(f(x, y, z), x), y)._eval_derivative(z) == \ Derivative(f(x, y, z), x, y, z) + def test_Lambda(): e = Lambda(x, x**2) assert e(4) == 16 @@ -92,7 +100,7 @@ assert Lambda(x, x**2) == Lambda(x, x**2) assert Lambda(x, x**2) == Lambda(y, y**2) - assert Lambda(x, x**2) != Lambda(y, y**2+1) + assert Lambda(x, x**2) != Lambda(y, y**2 + 1) assert Lambda((x, y), x**y) == Lambda((y, x), y**x) assert Lambda((x, y), x**y) != Lambda((x, y), y**x) @@ -104,46 +112,54 @@ assert Lambda(x, x**2)(e(x)) == x**4 assert e(e(x)) == x**4 - assert Lambda((x, y), x+y).nargs == 2 + assert Lambda((x, y), x + y).nargs == 2 p = x, y, z, t - assert Lambda(p, t*(x+y+z))(*p) == t * (x + y + z) + assert Lambda(p, t*(x + y + z))(*p) == t * (x + y + z) assert Lambda(x, 2*x) + Lambda(y, 2*y) == 2*Lambda(x, 2*x) assert Lambda(x, 2*x) not in [ Lambda(x, x) ] + raises(ValueError, lambda: Lambda(1, x)) + assert Lambda(x, 1)(1) is S.One + def test_IdentityFunction(): assert Lambda(x, x) is Lambda(y, y) is S.IdentityFunction assert Lambda(x, 2*x) is not S.IdentityFunction assert Lambda((x, y), x) is not S.IdentityFunction + def test_Lambda_symbols(): assert Lambda(x, 2*x).free_symbols == set() assert Lambda(x, x*y).free_symbols == set([y]) + def test_Lambda_arguments(): raises(TypeError, lambda: Lambda(x, 2*x)(x, y)) - raises(TypeError, lambda: Lambda((x, y), x+y)(x)) + raises(TypeError, lambda: Lambda((x, y), x + y)(x)) + def test_Lambda_equality(): - assert Lambda(x, 2*x) != Lambda((x,y), 2*x) - assert (Lambda(x, 2*x) == Lambda((x,y), 2*x)) is False + assert Lambda(x, 2*x) == Lambda(y, 2*y) + # although variables are casts as Dummies, the expressions + # should still compare equal assert Lambda((x, y), 2*x) == Lambda((x, y), 2*x) - assert (Lambda((x, y), 2*x) != Lambda((x, y), 2*x)) is False + assert Lambda(x, 2*x) != Lambda((x, y), 2*x) assert Lambda(x, 2*x) != 2*x - assert (Lambda(x, 2*x) == 2*x) is False + def test_Subs(): + assert Subs(x, x, 0) == Subs(y, y, 0) assert Subs(x, x, 0).subs(x, 1) == Subs(x, x, 1) assert Subs(y, x, 0).subs(y, 1) == Subs(1, x, 0) assert Subs(f(x), x, 0).doit() == f(0) assert Subs(f(x**2), x**2, 0).doit() == f(0) assert Subs(f(x, y, z), (x, y, z), (0, 1, 1)) != \ - Subs(f(x, y, z), (x, y, z), (0, 0, 1)) + Subs(f(x, y, z), (x, y, z), (0, 0, 1)) assert Subs(f(x, y), (x, y, z), (0, 1, 1)) == \ - Subs(f(x, y), (x, y, z), (0, 1, 2)) + Subs(f(x, y), (x, y, z), (0, 1, 2)) assert Subs(f(x, y), (x, y, z), (0, 1, 1)) != \ - Subs(f(x, y) + z, (x, y, z), (0, 1, 0)) + Subs(f(x, y) + z, (x, y, z), (0, 1, 0)) assert Subs(f(x, y), (x, y), (0, 1)).doit() == f(0, 1) assert Subs(Subs(f(x, y), x, 0), y, 1).doit() == f(0, 1) raises(ValueError, lambda: Subs(f(x, y), (x, y), (0, 0, 1))) @@ -165,10 +181,10 @@ assert Subs(f(x), x, 0).free_symbols == set([]) assert Subs(f(x, y), x, z).free_symbols == set([y, z]) - assert Subs(f(x).diff(x), x, 0).doit() , Subs(f(x).diff(x), x, 0) - assert Subs(1 + f(x).diff(x), x, 0).doit() , 1 + Subs(f(x).diff(x), x, 0) + assert Subs(f(x).diff(x), x, 0).doit(), Subs(f(x).diff(x), x, 0) + assert Subs(1 + f(x).diff(x), x, 0).doit(), 1 + Subs(f(x).diff(x), x, 0) assert Subs(y*f(x, y).diff(x), (x, y), (0, 2)).doit() == \ - 2*Subs(Derivative(f(x, 2), x), x, 0) + 2*Subs(Derivative(f(x, 2), x), x, 0) assert Subs(y**2*f(x), x, 0).diff(y) == 2*y*f(0) e = Subs(y**2*f(x), x, y) @@ -179,12 +195,14 @@ e2 = Subs(z*f(y), y, 1) assert e1 + e2 == 2*e1 assert e1.__hash__() == e2.__hash__() - assert Subs(z*f(x+1), x, 1) not in [ e1, e2 ] - assert Derivative(f(x),x).subs(x,g(x)) == Subs(Derivative(f(x),x), (x,), (g(x),)) + assert Subs(z*f(x + 1), x, 1) not in [ e1, e2 ] + assert Derivative( + f(x), x).subs(x, g(x)) == Subs(Derivative(f(x), x), (x,), (g(x),)) assert Subs(f(x)*cos(y) + z, (x, y), (0, pi/3)).n(2) == \ Subs(f(x)*cos(y) + z, (x, y), (0, pi/3)).evalf(2) == \ z + Rational('1/2').n(2)*f(0) + @XFAIL def test_Subs2(): # this reflects a limitation of subs(), probably won't fix @@ -192,44 +210,49 @@ def test_expand_function(): - assert expand(x+y) == x + y - assert expand(x+y, complex=True) == I*im(x) + I*im(y) + re(x) + re(y) + assert expand(x + y) == x + y + assert expand(x + y, complex=True) == I*im(x) + I*im(y) + re(x) + re(y) assert expand((x + y)**11, modulus=11) == x**11 + y**11 + def test_function_comparable(): - assert sin(x).is_comparable == False - assert cos(x).is_comparable == False + assert sin(x).is_comparable is False + assert cos(x).is_comparable is False - assert sin(Float('0.1')).is_comparable == True - assert cos(Float('0.1')).is_comparable == True + assert sin(Float('0.1')).is_comparable is True + assert cos(Float('0.1')).is_comparable is True - assert sin(E).is_comparable == True - assert cos(E).is_comparable == True + assert sin(E).is_comparable is True + assert cos(E).is_comparable is True + + assert sin(Rational(1, 3)).is_comparable is True + assert cos(Rational(1, 3)).is_comparable is True - assert sin(Rational(1,3)).is_comparable == True - assert cos(Rational(1,3)).is_comparable == True @XFAIL def test_function_comparable_infinities(): - assert sin(oo).is_comparable == False - assert sin(-oo).is_comparable == False - assert sin(zoo).is_comparable == False - assert sin(nan).is_comparable == False + assert sin(oo).is_comparable is False + assert sin(-oo).is_comparable is False + assert sin(zoo).is_comparable is False + assert sin(nan).is_comparable is False + def test_deriv1(): # These all requre derivatives evaluated at a point (issue 1620) to work. # See issue 1525 assert f(2*x).diff(x) == 2*Subs(Derivative(f(x), x), Tuple(x), Tuple(2*x)) assert (f(x)**3).diff(x) == 3*f(x)**2*f(x).diff(x) - assert (f(2*x)**3).diff(x) == 6*f(2*x)**2*Subs(Derivative(f(x), x), Tuple(x), + assert ( + f(2*x)**3).diff(x) == 6*f(2*x)**2*Subs(Derivative(f(x), x), Tuple(x), Tuple(2*x)) - assert f(2+x).diff(x) == Subs(Derivative(f(x), x), Tuple(x), Tuple(x + 2)) - assert f(2+3*x).diff(x) == 3*Subs(Derivative(f(x), x), Tuple(x), + assert f(2 + x).diff(x) == Subs(Derivative(f(x), x), Tuple(x), Tuple(x + 2)) + assert f(2 + 3*x).diff(x) == 3*Subs(Derivative(f(x), x), Tuple(x), Tuple(3*x + 2)) assert f(3*sin(x)).diff(x) == 3*cos(x)*Subs(Derivative(f(x), x), Tuple(x), Tuple(3*sin(x))) + def test_deriv2(): assert (x**3).diff(x) == 3*x**2 assert (x**3).diff(x, evaluate=False) != 3*x**2 @@ -239,6 +262,7 @@ assert diff(x**3, x, evaluate=False) != 3*x**2 assert diff(x**3, x, evaluate=False) == Derivative(x**3, x) + def test_func_deriv(): assert f(x).diff(x) == Derivative(f(x), x) # issue 1435 @@ -247,59 +271,77 @@ assert Derivative(f(x, y), y, x).args[1:] == (y, x) assert (Derivative(f(x, y), x, y) - Derivative(f(x, y), y, x)).doit() == 0 + def test_suppressed_evaluation(): a = sin(0, evaluate=False) assert a != 0 assert a.func is sin assert a.args == (0,) + def test_function_evalf(): - def eq(a,b,eps): - return abs(a-b) < eps + def eq(a, b, eps): + return abs(a - b) < eps assert eq(sin(1).evalf(15), Float("0.841470984807897"), 1e-13) - assert eq(sin(2).evalf(25), Float("0.9092974268256816953960199",25), 1e-23) - assert eq(sin(1+I).evalf(15), Float("1.29845758141598") + Float("0.634963914784736")*I, 1e-13) - assert eq(exp(1+I).evalf(15), Float("1.46869393991588") + Float("2.28735528717884239")*I, 1e-13) - assert eq(exp(-0.5+1.5*I).evalf(15), Float("0.0429042815937374") + Float("0.605011292285002")*I, 1e-13) - assert eq(log(pi+sqrt(2)*I).evalf(15), Float("1.23699044022052") + Float("0.422985442737893")*I, 1e-13) + assert eq( + sin(2).evalf(25), Float("0.9092974268256816953960199", 25), 1e-23) + assert eq(sin(1 + I).evalf( + 15), Float("1.29845758141598") + Float("0.634963914784736")*I, 1e-13) + assert eq(exp(1 + I).evalf(15), Float( + "1.46869393991588") + Float("2.28735528717884239")*I, 1e-13) + assert eq(exp(-0.5 + 1.5*I).evalf(15), Float( + "0.0429042815937374") + Float("0.605011292285002")*I, 1e-13) + assert eq(log(pi + sqrt(2)*I).evalf( + 15), Float("1.23699044022052") + Float("0.422985442737893")*I, 1e-13) assert eq(cos(100).evalf(15), Float("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) + return (0, 0, 0) + assert MyFunc(0) == (0, 0, 0) + def test_function_non_commutative(): x = Symbol('x', commutative=False) - assert f(x).is_commutative == False - assert sin(x).is_commutative == False - assert exp(x).is_commutative == False - assert log(x).is_commutative == False + assert f(x).is_commutative is False + assert sin(x).is_commutative is False + assert exp(x).is_commutative is False + assert log(x).is_commutative is False + def test_function__eval_nseries(): n = Symbol('n') - assert sin(x)._eval_nseries(x,2,None) == x + O(x**2) - assert sin(x+1)._eval_nseries(x,2,None) == x*cos(1) + sin(1) + O(x**2) - assert sin(pi*(1-x))._eval_nseries(x,2,None) == pi*x + O(x**2) - assert acos(1-x**2)._eval_nseries(x,2,None) == sqrt(2)*x + O(x**2) - assert polygamma(n,x+1)._eval_nseries(x,2,None) == \ - polygamma(n,1) + polygamma(n+1,1)*x + O(x**2) - raises(PoleError, lambda: sin(1/x)._eval_nseries(x,2,None)) - raises(PoleError, lambda: acos(1-x)._eval_nseries(x,2,None)) - raises(PoleError, lambda: acos(1+x)._eval_nseries(x,2,None)) - assert loggamma(1/x)._eval_nseries(x,0,None) \ - == log(x)/2 - log(x)/x - 1/x + O(1, x) - assert loggamma(log(1/x)).nseries(x,n=1,logx=y) == loggamma(-y) + assert sin(x)._eval_nseries(x, 2, None) == x + O(x**2) + assert sin(x + 1)._eval_nseries(x, 2, None) == x*cos(1) + sin(1) + O(x**2) + assert sin(pi*(1 - x))._eval_nseries(x, 2, None) == pi*x + O(x**2) + assert acos(1 - x**2)._eval_nseries(x, 2, None) == sqrt(2)*x + O(x**2) + assert polygamma(n, x + 1)._eval_nseries(x, 2, None) == \ + polygamma(n, 1) + polygamma(n + 1, 1)*x + O(x**2) + raises(PoleError, lambda: sin(1/x)._eval_nseries(x, 2, None)) + raises(PoleError, lambda: acos(1 - x)._eval_nseries(x, 2, None)) + raises(PoleError, lambda: acos(1 + x)._eval_nseries(x, 2, None)) + assert loggamma(1/x)._eval_nseries(x, 0, None) == \ + log(x)/2 - log(x)/x - 1/x + O(1, x) + assert loggamma(log(1/x)).nseries(x, n=1, logx=y) == loggamma(-y) + + # issue 3626: + assert expint(S(3)/2, -x)._eval_nseries(x, 5, None) == \ + 2 - 2*sqrt(pi)*sqrt(-x) - 2*x - x**2/3 - x**3/15 - x**4/84 + O(x**5) + assert sin(sqrt(x))._eval_nseries(x, 3, None) == \ + sqrt(x) - x**(S(3)/2)/6 + x**(S(5)/2)/120 + O(x**3) + def test_doit(): n = Symbol('n', integer=True) f = Sum(2 * n * x, (n, 1, 3)) d = Derivative(f, x) assert d.doit() == 12 - assert d.doit(deep = False) == Sum(2*n, (n, 1, 3)) + assert d.doit(deep=False) == Sum(2*n, (n, 1, 3)) + def test_evalf_default(): from sympy.functions.special.gamma_functions import polygamma @@ -307,23 +349,27 @@ assert type(re(sin(I + 1.0))) == Float assert type(im(sin(I + 1.0))) == Float assert type(sin(4)) == sin - assert type(polygamma(2.0,4.0)) == Float - assert type(sin(Rational(1,4))) == sin + assert type(polygamma(2.0, 4.0)) == Float + assert type(sin(Rational(1, 4))) == sin + def test_issue2300(): args = [x, y, S(2), S.Half] + def ok(a): """Return True if the input args for diff are ok""" - if not a: return False - if a[0].is_Symbol is False: return False + if not a: + return False + if a[0].is_Symbol is False: + return False s_at = [i for i in range(len(a)) if a[i].is_Symbol] n_at = [i for i in range(len(a)) if not a[i].is_Symbol] # every symbol is followed by symbol or int # every number is followed by a symbol - return (all(a[i+1].is_Symbol or a[i+1].is_Integer - for i in s_at if i+1>> solve(x**r-y**2,y) + # [-x**(r/2), x**(r/2)] + + r = Symbol('r', rational=True) + assert (x**r).match(y**2) == {y: x**(r/2)} + assert (x**e).match(y**2) == {y: sqrt(x**e)} + + # since (x**i = y) -> x = y**(1/i) where i is an integer + # the following should also be valid as long as y is not + # zero when i is negative. + + a = Wild('a') + + e = S(0) + assert e.match(a) == {a: e} + assert e.match(1/a) is None + assert e.match(a**.3) is None + + e = S(3) + assert e.match(1/a) == {a: 1/e} + assert e.match(1/a**2) == {a: 1/sqrt(e)} + e = pi + assert e.match(1/a) == {a: 1/e} + assert e.match(1/a**2) == {a: 1/sqrt(e)} + assert (-e).match(sqrt(a)) is None + assert (-e).match(a**2) == {a: I*sqrt(pi)} + + +def test_issue_1784(): + a = Wild('a') + x = Symbol('x') + + e = [i**2 for i in (x - 2, 2 - x)] + p = [i**2 for i in (x - a, a- x)] + for eq in e: + for pat in p: + assert eq.match(pat) == {a: 2} + + +def test_issue_1220(): + x, y = symbols('x y') + + p = -x*(S(1)/8 - y) + ans = set([S.Zero, y - S(1)/8]) + + def ok(pat): + assert set(p.match(pat).values()) == ans + + ok(Wild("coeff", exclude=[x])*x + Wild("rest")) + ok(Wild("w", exclude=[x])*x + Wild("rest")) + ok(Wild("coeff", exclude=[x])*x + Wild("rest")) + ok(Wild("w", exclude=[x])*x + Wild("rest")) + ok(Wild("e", exclude=[x])*x + Wild("rest")) + ok(Wild("ress", exclude=[x])*x + Wild("rest")) + ok(Wild("resu", exclude=[x])*x + Wild("rest")) + + +def test_issue_679(): + p, c, q = symbols('p c q', cls=Wild) + x = Symbol('x') + + assert (sin(x)**2).match(sin(p)*sin(q)*c) == {q: x, c: 1, p: x} + assert (2*sin(x)).match(sin(p) + sin(q) + c) == {q: x, c: 0, p: x} + + +def test_issue_784(): + mu, gamma, x = symbols('mu gamma x') + f = (- gamma * (x-mu)**2 - log(gamma) + log(2*pi)) / 2 + g1 = Wild('g1', exclude=[gamma]) + g2 = Wild('g2', exclude=[gamma]) + g3 = Wild('g3', exclude=[gamma]) + assert f.expand().match(g1 * log(gamma) + g2 * gamma + g3) == \ + {g3: log(2)/2 + log(pi)/2, g1: -S(1)/2, g2: -mu**2/2 + mu*x - x**2/2} + + +def test_issue_3004(): + x = Symbol('x') + a = Wild('a') + assert (-I*x*oo).match(I*a*oo) == {a: -x} + + +def test_issue_3539(): + a = Wild('a') + x = Symbol('x') + assert (x - 2).match(a - x) is None + assert (6/x).match(a*x) is None + assert (6/x**2).match(a/x) == {a: 6/x} diff -Nru python3-sympy-0.7.2/sympy/core/tests/test_noncommutative.py python3-sympy-0.7.3/sympy/core/tests/test_noncommutative.py --- python3-sympy-0.7.2/sympy/core/tests/test_noncommutative.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/core/tests/test_noncommutative.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,18 +1,22 @@ """Tests for noncommutative symbols and expressions.""" from sympy import ( + adjoint, cancel, collect, combsimp, conjugate, + cos, expand, factor, posify, radsimp, ratsimp, rcollect, + sin, simplify, symbols, + transpose, trigsimp, I, ) @@ -20,29 +24,57 @@ from sympy.utilities.pytest import XFAIL A, B, C = symbols("A B C", commutative=False) +X = symbols("X", commutative=False, hermitian=True) +Y = symbols("Y", commutative=False, antihermitian=True) + + +def test_adjoint(): + assert adjoint(A).is_commutative is False + assert adjoint(A*A) == adjoint(A)**2 + assert adjoint(A*B) == adjoint(B)*adjoint(A) + assert adjoint(A*B**2) == adjoint(B)**2*adjoint(A) + assert adjoint(A*B - B*A) == adjoint(B)*adjoint(A) - adjoint(A)*adjoint(B) + assert adjoint(A + I*B) == adjoint(A) - I*adjoint(B) + + assert adjoint(X) == X + assert adjoint(-I*X) == I*X + assert adjoint(Y) == -Y + assert adjoint(-I*Y) == -I*Y + + assert adjoint(X) == conjugate(transpose(X)) + assert adjoint(Y) == conjugate(transpose(Y)) + assert adjoint(X) == transpose(conjugate(X)) + assert adjoint(Y) == transpose(conjugate(Y)) + @XFAIL def test_cancel(): assert cancel(A*B - B*A) == A*B - B*A + @XFAIL def test_collect(): assert collect(A*B - B*A, A) == A*B - B*A assert collect(A*B - B*A, B) == A*B - B*A assert collect(A*B - B*A, x) == A*B - B*A + def test_combsimp(): assert combsimp(A*B - B*A) == A*B - B*A + def test_conjugate(): - assert conjugate(A).is_commutative == False + assert conjugate(A).is_commutative is False assert (A*A).conjugate() == conjugate(A)**2 assert (A*B).conjugate() == conjugate(A)*conjugate(B) assert (A*B**2).conjugate() == conjugate(A)*conjugate(B)**2 - assert (A*B - B*A).conjugate() == conjugate(A)*conjugate(B) - conjugate(B)*conjugate(A) - assert (A*B).conjugate() - (B*A).conjugate() == conjugate(A)*conjugate(B) - conjugate(B)*conjugate(A) + assert (A*B - B*A).conjugate() == \ + conjugate(A)*conjugate(B) - conjugate(B)*conjugate(A) + assert (A*B).conjugate() - (B*A).conjugate() == \ + conjugate(A)*conjugate(B) - conjugate(B)*conjugate(A) assert (A + I*B).conjugate() == conjugate(A) - I*conjugate(B) + def test_expand(): assert expand((A*B)**2) == A*B*A*B assert expand(A*B - B*A) == A*B - B*A @@ -50,31 +82,38 @@ assert expand(B*A*(A + B)*B) == B*A**2*B + B*A*B**2 assert expand(B*A*(A + C)*B) == B*A**2*B + B*A*C*B + def test_factor(): assert factor(A*B - B*A) == A*B - B*A + def test_posify(): - assert posify(A)[0].is_commutative == False + assert posify(A)[0].is_commutative is False for q in (A*B/A, (A*B/A)**2, (A*B)**2, A*B - B*A): p = posify(q) assert p[0].subs(p[1]) == q + def test_radsimp(): assert radsimp(A*B - B*A) == A*B - B*A + @XFAIL def test_ratsimp(): assert ratsimp(A*B - B*A) == A*B - B*A + @XFAIL def test_rcollect(): assert rcollect(A*B - B*A, A) == A*B - B*A assert rcollect(A*B - B*A, B) == A*B - B*A assert rcollect(A*B - B*A, x) == A*B - B*A + def test_simplify(): assert simplify(A*B - B*A) == A*B - B*A + def test_subs(): assert (x*y*A).subs(x*y, z) == A*z assert (x*A*B).subs(x*A, C) == C*B @@ -83,6 +122,21 @@ assert (A**2*B**2).subs(A*B**2, C) == A*C assert (A*A*A + A*B*A).subs(A*A*A, C) == C + A*B*A -@XFAIL + +def test_transpose(): + assert transpose(A).is_commutative is False + assert transpose(A*A) == transpose(A)**2 + assert transpose(A*B) == transpose(B)*transpose(A) + assert transpose(A*B**2) == transpose(B)**2*transpose(A) + assert transpose(A*B - B*A) == \ + transpose(B)*transpose(A) - transpose(A)*transpose(B) + assert transpose(A + I*B) == transpose(A) + I*transpose(B) + + assert transpose(X) == conjugate(X) + assert transpose(-I*X) == -I*conjugate(X) + assert transpose(Y) == -conjugate(Y) + assert transpose(-I*Y) == I*conjugate(Y) + + def test_trigsimp(): assert trigsimp(A*sin(x)**2 + A*cos(x)**2) == A diff -Nru python3-sympy-0.7.2/sympy/core/tests/test_numbers.py python3-sympy-0.7.3/sympy/core/tests/test_numbers.py --- python3-sympy-0.7.2/sympy/core/tests/test_numbers.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/core/tests/test_numbers.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,14 +1,16 @@ + +import decimal from sympy import (Rational, Symbol, Float, I, sqrt, oo, nan, pi, E, Integer, S, factorial, Catalan, EulerGamma, GoldenRatio, cos, exp, Number, zoo, log, Mul, Pow, Tuple) from sympy.core.basic import _aresame from sympy.core.power import integer_nthroot -from sympy.utilities.pytest import XFAIL, slow - -from sympy.core.numbers import igcd, ilcm, igcdex, seterr, _intcache -from sympy.utilities.pytest import raises +from sympy.core.numbers import igcd, ilcm, igcdex, seterr, _intcache, mpf_norm +from sympy.mpmath import mpf +from sympy.utilities.pytest import XFAIL, slow, raises from sympy import mpmath + def test_integers_cache(): python_int = 2**65 + 3175259 @@ -33,12 +35,14 @@ assert hash(python_int) in _intcache assert sympy_hash_int not in _intcache + def test_seterr(): - seterr(divide = True) + seterr(divide=True) raises(ValueError, lambda: S.Zero/S.Zero) - seterr(divide = False) + seterr(divide=False) assert S.Zero / S.Zero == S.NaN + def test_mod(): x = Rational(1, 2) y = Rational(3, 4) @@ -56,15 +60,33 @@ a = Float(2.6) - assert (a % .2).round(15) == 0.2 + assert (a % .2) == 0 assert (a % 2).round(15) == 0.6 assert (a % 0.5).round(15) == 0.1 + # In these two tests, if the precision of m does + # not match the precision of the ans, then it is + # likely that the change made now gives an answer + # with degraded accuracy. + r = Rational(500, 41) + f = Float('.36', 3) + m = r % f + ans = Float(r % Rational(f), 3) + assert m == ans and m._prec == ans._prec + f = Float('8.36', 3) + m = f % r + ans = Float(Rational(f) % r, 3) + assert m == ans and m._prec == ans._prec + + s = S.Zero + + assert s % float(1) == S.Zero + # No rounding required since these numbers can be represented # exactly. - assert Rational(3,4) % Float(1.1) == 0.75 + assert Rational(3, 4) % Float(1.1) == 0.75 assert Float(1.5) % Rational(5, 4) == 0.25 - assert Rational(5,4).__rmod__(Float('1.5')) == 0.25 + assert Rational(5, 4).__rmod__(Float('1.5')) == 0.25 assert Float('1.5').__rmod__(Float('2.75')) == Float('1.25') assert 2.75 % Float('1.5') == Float('1.25') @@ -74,13 +96,14 @@ assert type(a % b) == Integer assert a % b == Integer(3) assert Integer(1) % Rational(2, 3) == Rational(1, 3) - assert Rational(7,5) % Integer(1) == Rational(2,5) + assert Rational(7, 5) % Integer(1) == Rational(2, 5) assert Integer(2) % 1.5 == 0.5 assert Integer(3).__rmod__(Integer(10)) == Integer(1) assert Integer(10) % 4 == Integer(2) assert 15 % Integer(4) == Integer(3) + def test_divmod(): assert divmod(S(12), S(8)) == Tuple(1, 4) assert divmod(-S(12), S(8)) == Tuple(-2, 4) @@ -146,6 +169,7 @@ assert divmod(S(-3), S(2)) == (-2, 1) assert divmod(S(-3), 2) == (-2, 1) + def test_igcd(): assert igcd(0, 0) == 0 assert igcd(0, 1) == 1 @@ -168,6 +192,7 @@ raises(ValueError, lambda: igcd(45.1, 30)) raises(ValueError, lambda: igcd(45, 30.1)) + def test_ilcm(): assert ilcm(0, 0) == 0 assert ilcm(1, 0) == 0 @@ -180,15 +205,18 @@ raises(ValueError, lambda: ilcm(8.1, 7)) raises(ValueError, lambda: ilcm(8, 7.1)) + def test_igcdex(): assert igcdex(2, 3) == (-1, 1, 1) assert igcdex(10, 12) == (-1, 1, 2) assert igcdex(100, 2004) == (-20, 1, 4) + def _strictly_equal(a, b): return (a.p, a.q, type(a.p), type(a.q)) == \ (b.p, b.q, type(b.p), type(b.q)) + def _test_rational_new(cls): """ Tests that are common between Integer and Rational. @@ -197,7 +225,6 @@ assert cls(1) is S.One assert cls(-1) is S.NegativeOne # These look odd, but are similar to int(): - assert cls(0.9) is S.Zero assert cls('1') is S.One assert cls('-1') is S.NegativeOne @@ -205,19 +232,22 @@ assert _strictly_equal(i, cls('10')) assert _strictly_equal(i, cls('10')) assert _strictly_equal(i, cls(10)) - assert _strictly_equal(i, cls(10.5)) assert _strictly_equal(i, cls(i)) raises(TypeError, lambda: cls(Symbol('x'))) + def test_Integer_new(): """ Test for Integer constructor """ _test_rational_new(Integer) + assert _strictly_equal(Integer(0.9), S.Zero) + assert _strictly_equal(Integer(10.5), Integer(10)) raises(ValueError, lambda: Integer("10.5")) - assert Integer(Rational('1.'+'9'*20)) == 1 + assert Integer(Rational('1.' + '9'*20)) == 1 + def test_Rational_new(): """" @@ -230,18 +260,23 @@ assert n1 == Rational(Integer(1), Integer(2)) assert n1 == Rational(1, Integer(2)) assert n1 == Rational(Rational(1, 2)) - assert n1 == Rational(1.2, 2) - assert n1 == Rational('.5') assert 1 == Rational(n1, n1) - assert Rational(3, 2) == Rational(Rational(1,2),Rational(1,3)) - assert Rational(3, 1) == Rational(1,Rational(1,3)) + assert Rational(3, 2) == Rational(Rational(1, 2), Rational(1, 3)) + assert Rational(3, 1) == Rational(1, Rational(1, 3)) n3_4 = Rational(3, 4) assert Rational('3/4') == n3_4 assert -Rational('-3/4') == n3_4 assert Rational('.76').limit_denominator(4) == n3_4 assert Rational(19, 25).limit_denominator(4) == n3_4 assert Rational('19/25').limit_denominator(4) == n3_4 - raises(ValueError, lambda: Rational('1/2 + 2/3')) + assert Rational(1.0, 3) == Rational(1, 3) + assert Rational(1, 3.0) == Rational(1, 3) + assert Rational(Float(0.5)) == Rational(1, 2) + assert Rational('1e2/1e-2') == Rational(10000) + assert Rational(-1, 0) == S.NegativeInfinity + assert Rational(1, 0) == S.Infinity + raises(TypeError, lambda: Rational('3**3')) + raises(TypeError, lambda: Rational('1/2 + 2/3')) # handle fractions.Fraction instances try: @@ -250,6 +285,7 @@ except ImportError: pass + def test_Number_new(): """" Test for Number constructor @@ -258,7 +294,7 @@ assert Number(1) is S.One assert Number(2).__class__ is Integer assert Number(-622).__class__ is Integer - assert Number(5,3).__class__ is Rational + assert Number(5, 3).__class__ is Rational assert Number(5.3).__class__ is Float assert Number('1') is S.One assert Number('2').__class__ is Integer @@ -267,32 +303,33 @@ assert Number('5.3').__class__ is Float raises(ValueError, lambda: Number('cos')) raises(TypeError, lambda: Number(cos)) - a = Rational(3,5) - assert Number(a) is a # Check idempotence on Numbers + a = Rational(3, 5) + assert Number(a) is a # Check idempotence on Numbers + def test_Rational_cmp(): - n1 = Rational(1,4) - n2 = Rational(1,3) - n3 = Rational(2,4) - n4 = Rational(2,-4) + n1 = Rational(1, 4) + n2 = Rational(1, 3) + n3 = Rational(2, 4) + n4 = Rational(2, -4) n5 = Rational(0) n6 = Rational(1) n7 = Rational(3) n8 = Rational(-3) - assert n8n8 - assert (n1+1)**n2 < 2 - assert ((n1+n6)/n7) < 1 - - assert n4n1 - assert not n3 n8 + assert (n1 + 1)**n2 < 2 + assert ((n1 + n6)/n7) < 1 + + assert n4 < n3 + assert n2 < n3 + assert n1 < n2 + assert n3 > n1 + assert not n3 < n1 assert not (Rational(-1) > 0) assert Rational(-1) < 0 @@ -300,7 +337,7 @@ def test_Float(): def eq(a, b): t = Float("1.0E-15") - return (-t < a-b < t) + return (-t < a - b < t) a = Float(2) ** Float(3) assert eq(a.evalf(), Float(8)) @@ -324,10 +361,33 @@ assert Float((0, 0, -456, -2)) == Float('inf') == Float('+inf') assert Float((1, 0, -789, -3)) == Float('-inf') + raises(ValueError, lambda: Float((0, 7, 1, 3), '')) + + assert Float('+inf').is_bounded is False + assert Float('+inf').is_finite is False + assert Float('+inf').is_negative is False + assert Float('+inf').is_positive is True + assert Float('+inf').is_unbounded is True + assert Float('+inf').is_zero is False + + assert Float('-inf').is_bounded is False + assert Float('-inf').is_finite is False + assert Float('-inf').is_negative is True + assert Float('-inf').is_positive is False + assert Float('-inf').is_unbounded is True + assert Float('-inf').is_zero is False + + assert Float('0.0').is_bounded is True + assert Float('0.0').is_finite is False + assert Float('0.0').is_negative is False + assert Float('0.0').is_positive is False + assert Float('0.0').is_unbounded is False + assert Float('0.0').is_zero is True + # do not automatically evalf def teq(a): - assert (a.evalf () == a) is False - assert (a.evalf () != a) is True + assert (a.evalf() == a) is False + assert (a.evalf() != a) is True assert (a == a.evalf()) is False assert (a != a.evalf()) is True @@ -335,16 +395,8 @@ teq(2*pi) teq(cos(0.1, evaluate=False)) - assert Float(0) is S.Zero - assert Float(1) is S.One - - assert Float(S.Zero) is S.Zero - assert Float(S.One) is S.One - i = 12345678901234567890 - assert _aresame(Float(12), Integer(12)) assert _aresame(Float(12, ''), Float('12', '')) - assert _aresame(Float(i), Integer(i)) assert _aresame(Float(Integer(i), ''), Float(i, '')) assert _aresame(Float(i, ''), Float(str(i), 20)) assert not _aresame(Float(str(i)), Float(i, '')) @@ -360,6 +412,7 @@ Float('123 456.123 456') == Float('123456.123456') Integer('123 456') == Integer('123456') Rational('123 456.123 456') == Rational('123456.123456') + assert Float(' .3e2') == Float('0.3e2') # allow auto precision detection assert Float('.1', '') == Float(.1, 1) @@ -368,18 +421,29 @@ assert Float('2.0', '') == Float('2', 2) raises(ValueError, lambda: Float("12.3d-4", "")) - raises(ValueError, lambda:Float(12.3, "")) - raises(ValueError, lambda:Float('.')) - raises(ValueError, lambda:Float('-.')) - assert Float('-0') == Float('0.0') - assert Float('.0') == Float('0.0') - assert Float('-.0') == Float('-0.0') - assert Float(' .3e2') == Float('0.3e2') + raises(ValueError, lambda: Float(12.3, "")) + raises(ValueError, lambda: Float('.')) + raises(ValueError, lambda: Float('-.')) + + zero = Float('0.0') + assert Float('-0') == zero + assert Float('.0') == zero + assert Float('-.0') == zero + assert Float('-0.0') == zero + assert Float(0.0) == zero + assert Float(0) == zero + assert Float(0, '') == Float('0', '') + assert Float(1) == Float(1.0) + assert Float(S.Zero) == zero + assert Float(S.One) == Float(1.0) + + assert Float(decimal.Decimal('0.1'), 3) == Float('.1', 3) def test_Float_eval(): a = Float(3.2) assert (a**2).is_Float + def test_Float_issue_2107(): a = Float(0.1, 10) b = Float("0.1", 10) @@ -394,6 +458,7 @@ assert S.Zero + b - b == 0 assert S.Zero + b + (-b) == 0 + def test_Infinity(): assert oo != 1 assert 1*oo == oo @@ -408,9 +473,9 @@ assert -oo*3 == -oo assert oo + oo == oo assert -oo + oo*(-5) == -oo - assert 1/oo == 0 - assert 1/(-oo) == 0 - assert 8/oo == 0 + assert 1/oo == 0 + assert 1/(-oo) == 0 + assert 8/oo == 0 assert oo % 2 == nan assert 2 % oo == nan assert oo/oo == nan @@ -482,10 +547,10 @@ assert -oo*float(-1) == Float('inf') and (-oo*float(-1)).is_Float assert oo/float(-1) == Float('-inf') and (oo/float(-1)).is_Float assert -oo/float(-1) == Float('inf') and (-oo/float(-1)).is_Float - assert oo + float(1) == Float('inf') and (oo+float(1)).is_Float - assert -oo + float(1) == Float('-inf') and (-oo+float(1)).is_Float - assert oo - float(1) == Float('inf') and (oo-float(1)).is_Float - assert -oo - float(1) == Float('-inf') and (-oo-float(1)).is_Float + assert oo + float(1) == Float('inf') and (oo + float(1)).is_Float + assert -oo + float(1) == Float('-inf') and (-oo + float(1)).is_Float + assert oo - float(1) == Float('inf') and (oo - float(1)).is_Float + assert -oo - float(1) == Float('-inf') and (-oo - float(1)).is_Float assert float(1)*oo == Float('inf') and (float(1)*oo).is_Float assert float(1)*-oo == Float('-inf') and (float(1)*-oo).is_Float assert float(1)/oo == 0 @@ -499,15 +564,18 @@ assert float(1) - oo == Float('-inf') assert float(1) - -oo == Float('inf') - from sympy.mpmath.libmp.libmpf import fnan - assert (oo*Float('nan'))._mpf_ == fnan - assert (-oo*Float('nan'))._mpf_ == fnan - assert (oo/Float('nan'))._mpf_ == fnan - assert (-oo/Float('nan'))._mpf_ == fnan - assert (oo + Float('nan'))._mpf_ == fnan - assert (-oo + Float('nan'))._mpf_ == fnan - assert (oo - Float('nan'))._mpf_ == fnan - assert (-oo - Float('nan'))._mpf_ == fnan + assert Float('nan') == nan + assert nan*1.0 == nan + assert -1.0*nan == nan + assert nan*oo == nan + assert nan*-oo == nan + assert nan/oo == nan + assert nan/-oo == nan + assert nan + oo == nan + assert nan + -oo == nan + assert nan - oo == nan + assert nan - -oo == nan + assert -oo * S.Zero == nan assert oo*nan == nan assert -oo*nan == nan @@ -518,8 +586,8 @@ assert oo - nan == nan assert -oo - nan == nan assert S.Zero * oo == nan - assert oo.is_Rational == False - assert isinstance(oo, Rational) == False + assert oo.is_Rational is False + assert isinstance(oo, Rational) is False assert S.One/oo == 0 assert -S.One/oo == 0 @@ -537,21 +605,78 @@ assert nan/S.One == nan assert -oo - S.One == -oo + def test_Infinity_2(): x = Symbol('x') assert oo*x != oo - assert oo*(pi-1) == oo - assert oo*(1-pi) == -oo + assert oo*(pi - 1) == oo + assert oo*(1 - pi) == -oo assert (-oo)*x != -oo - assert (-oo)*(pi-1) == -oo - assert (-oo)*(1-pi) == oo + assert (-oo)*(pi - 1) == -oo + assert (-oo)*(1 - pi) == oo + + assert (-1)**S.NaN is S.NaN + assert oo - Float('inf') is S.NaN + assert oo + Float('-inf') is S.NaN + assert oo*0 is S.NaN + assert oo/Float('inf') is S.NaN + assert oo/Float('-inf') is S.NaN + assert oo**S.NaN is S.NaN + assert -oo + Float('inf') is S.NaN + assert -oo - Float('-inf') is S.NaN + assert -oo*S.NaN is S.NaN + assert -oo*0 is S.NaN + assert -oo/Float('inf') is S.NaN + assert -oo/Float('-inf') is S.NaN + assert -oo/S.NaN is S.NaN + assert abs(-oo) == oo + assert all((-oo)**i is S.NaN for i in (oo, -oo, S.NaN)) + assert (-oo)**3 == -oo + assert (-oo)**2 == oo + assert abs(S.ComplexInfinity) == oo + + +def test_Mul_Infinity_Zero(): + assert 0*Float('inf') == nan + assert 0*Float('-inf') == nan + assert 0*Float('inf') == nan + assert 0*Float('-inf') == nan + assert Float('inf')*0 == nan + assert Float('-inf')*0 == nan + assert Float('inf')*0 == nan + assert Float('-inf')*0 == nan + assert Float(0)*Float('inf') == nan + assert Float(0)*Float('-inf') == nan + assert Float(0)*Float('inf') == nan + assert Float(0)*Float('-inf') == nan + assert Float('inf')*Float(0) == nan + assert Float('-inf')*Float(0) == nan + assert Float('inf')*Float(0) == nan + assert Float('-inf')*Float(0) == nan + + +def test_Div_By_Zero(): + assert 1/S(0) == oo + assert 1/Float(0) == Float('inf') + assert 0/S(0) == nan + assert 0/Float(0) == nan + assert S(0)/0 == nan + assert Float(0)/0 == nan + assert -1/S(0) == -oo + assert -1/Float(0) == Float('-inf') + def test_Infinity_inequations(): assert oo > pi assert not (oo < pi) assert exp(-3) < oo + assert Float('+inf') > pi + assert not (Float('+inf') < pi) + assert exp(-3) < Float('+inf') + + def test_NaN(): assert nan == nan assert nan != 1 @@ -565,9 +690,9 @@ assert -nan*3 == nan assert nan + nan == nan assert -nan + nan*(-5) == nan - assert 1/nan == nan - assert 1/(-nan) == nan - assert 8/nan == nan + assert 1/nan == nan + assert 1/(-nan) == nan + assert 8/nan == nan assert not nan > 0 assert not nan < 0 assert not nan >= 0 @@ -584,25 +709,27 @@ assert nan*S.One == nan assert nan + S.One == nan assert nan/S.One == nan - assert nan**0 == 1 # as per IEEE 754 - assert 1**nan == 1 # as per IEEE 754 + assert nan**0 == 1 # as per IEEE 754 + assert 1**nan == 1 # as per IEEE 754 + def test_special_numbers(): - assert isinstance(S.NaN, Number) == True - assert isinstance(S.Infinity, Number) == True - assert isinstance(S.NegativeInfinity, Number) == True - - assert S.NaN.is_number == True - assert S.Infinity.is_number == True - assert S.NegativeInfinity.is_number == True - - assert isinstance(S.NaN, Rational) == False - assert isinstance(S.Infinity, Rational) == False - assert isinstance(S.NegativeInfinity, Rational) == False - - assert S.NaN.is_rational != True - assert S.Infinity.is_rational != True - assert S.NegativeInfinity.is_rational != True + assert isinstance(S.NaN, Number) is True + assert isinstance(S.Infinity, Number) is True + assert isinstance(S.NegativeInfinity, Number) is True + + assert S.NaN.is_number is True + assert S.Infinity.is_number is True + assert S.NegativeInfinity.is_number is True + + assert isinstance(S.NaN, Rational) is False + assert isinstance(S.Infinity, Rational) is False + assert isinstance(S.NegativeInfinity, Rational) is False + + assert S.NaN.is_rational is not True + assert S.Infinity.is_rational is not True + assert S.NegativeInfinity.is_rational is not True + def test_powers(): assert integer_nthroot(1, 2) == (1, True) @@ -612,40 +739,42 @@ assert integer_nthroot(2, 5) == (1, False) assert integer_nthroot(4, 2) == (2, True) assert integer_nthroot(123**25, 25) == (123, True) - assert integer_nthroot(123**25+1, 25) == (123, False) - assert integer_nthroot(123**25-1, 25) == (122, False) - assert integer_nthroot(1,1) == (1, True) - assert integer_nthroot(0,1) == (0, True) - assert integer_nthroot(0,3) == (0, True) + assert integer_nthroot(123**25 + 1, 25) == (123, False) + assert integer_nthroot(123**25 - 1, 25) == (122, False) + assert integer_nthroot(1, 1) == (1, True) + assert integer_nthroot(0, 1) == (0, True) + assert integer_nthroot(0, 3) == (0, True) assert integer_nthroot(10000, 1) == (10000, True) - assert integer_nthroot(4,2) == (2, True) - assert integer_nthroot(16,2) == (4, True) - assert integer_nthroot(26,2) == (5, False) + assert integer_nthroot(4, 2) == (2, True) + assert integer_nthroot(16, 2) == (4, True) + assert integer_nthroot(26, 2) == (5, False) assert integer_nthroot(1234567**7, 7) == (1234567, True) - assert integer_nthroot(1234567**7+1, 7) == (1234567, False) - assert integer_nthroot(1234567**7-1, 7) == (1234566, False) + assert integer_nthroot(1234567**7 + 1, 7) == (1234567, False) + assert integer_nthroot(1234567**7 - 1, 7) == (1234566, False) b = 25**1000 assert integer_nthroot(b, 1000) == (25, True) - assert integer_nthroot(b+1, 1000) == (25, False) - assert integer_nthroot(b-1, 1000) == (24, False) + assert integer_nthroot(b + 1, 1000) == (25, False) + assert integer_nthroot(b - 1, 1000) == (24, False) c = 10**400 c2 = c**2 assert integer_nthroot(c2, 2) == (c, True) - assert integer_nthroot(c2+1, 2) == (c, False) - assert integer_nthroot(c2-1, 2) == (c-1, False) - assert integer_nthroot(2,10**10) == (1, False) + assert integer_nthroot(c2 + 1, 2) == (c, False) + assert integer_nthroot(c2 - 1, 2) == (c - 1, False) + assert integer_nthroot(2, 10**10) == (1, False) p, r = integer_nthroot(int(factorial(10000)), 100) assert p % (10**10) == 5322420655 assert not r # Test that this is fast - assert integer_nthroot(2,10**10) == (1, False) + assert integer_nthroot(2, 10**10) == (1, False) + def test_integer_nthroot_overflow(): assert integer_nthroot(10**(50*50), 50) == (10**50, True) assert integer_nthroot(10**100000, 10000) == (10**10, True) + def test_powers_Integer(): """Test Integer._eval_power""" # check infinity @@ -656,37 +785,39 @@ assert S(0) ** S.Infinity == 0 # check Nan - assert S(1) ** S.NaN == S.One + assert S(1) ** S.NaN == S.One assert S(-1) ** S.NaN == S.NaN # check for exact roots - assert S(-1) ** Rational(6, 5) == - (-1)**(S(1)/5) + assert S(-1) ** Rational(6, 5) == - (-1)**(S(1)/5) assert sqrt(S(4)) == 2 assert sqrt(S(-4)) == I * 2 - assert S(16) ** Rational(1, 4) == 2 - assert S(-16) ** Rational(1, 4) == 2 * (-1)**Rational(1,4) - assert S(9) ** Rational(3, 2) == 27 - assert S(-9) ** Rational(3, 2) == -27*I - assert S(27) ** Rational(2, 3) == 9 + assert S(16) ** Rational(1, 4) == 2 + assert S(-16) ** Rational(1, 4) == 2 * (-1)**Rational(1, 4) + assert S(9) ** Rational(3, 2) == 27 + assert S(-9) ** Rational(3, 2) == -27*I + assert S(27) ** Rational(2, 3) == 9 assert S(-27) ** Rational(2, 3) == 9 * (S(-1) ** Rational(2, 3)) assert (-2) ** Rational(-2, 1) == Rational(1, 4) # not exact roots - assert sqrt(-3) == I*sqrt(3) - assert (3) ** (S(3)/2) == 3 * sqrt(3) - assert (-3) ** (S(3)/2) == - 3 * sqrt(-3) - assert (-3) ** (S(5)/2) == 9 * I * sqrt(3) - assert (-3) ** (S(7)/2) == - I * 27 * sqrt(3) - assert (2) ** (S(3)/2) == 2 * sqrt(2) - assert (2) ** (S(-3)/2) == sqrt(2) / 4 - assert (81) ** (S(2)/3) == 9 * (S(3) ** (S(2)/3)) - assert (-81) ** (S(2)/3) == 9 * (S(-3) ** (S(2)/3)) - assert (-3) ** Rational(-7, 3) == -(-1)**Rational(2, 3)*3**Rational(2, 3)/27 - assert (-3) ** Rational(-2, 3) == -(-1)**Rational(1, 3)*3**Rational(1, 3)/3 + assert sqrt(-3) == I*sqrt(3) + assert (3) ** (S(3)/2) == 3 * sqrt(3) + assert (-3) ** (S(3)/2) == - 3 * sqrt(-3) + assert (-3) ** (S(5)/2) == 9 * I * sqrt(3) + assert (-3) ** (S(7)/2) == - I * 27 * sqrt(3) + assert (2) ** (S(3)/2) == 2 * sqrt(2) + assert (2) ** (S(-3)/2) == sqrt(2) / 4 + assert (81) ** (S(2)/3) == 9 * (S(3) ** (S(2)/3)) + assert (-81) ** (S(2)/3) == 9 * (S(-3) ** (S(2)/3)) + assert (-3) ** Rational(-7, 3) == \ + -(-1)**Rational(2, 3)*3**Rational(2, 3)/27 + assert (-3) ** Rational(-2, 3) == \ + -(-1)**Rational(1, 3)*3**Rational(1, 3)/3 # join roots assert sqrt(6) + sqrt(24) == 3*sqrt(6) - assert sqrt(2) * sqrt(3) == sqrt(6) + assert sqrt(2) * sqrt(3) == sqrt(6) # separate symbols & constansts x = Symbol("x") @@ -694,19 +825,22 @@ assert sqrt((3 - sqrt(pi)) ** 2) == 3 - sqrt(pi) # check that it is fast for big numbers - assert (2**64+1) ** Rational(4, 3) - assert (2**64+1) ** Rational(17,25) + assert (2**64 + 1) ** Rational(4, 3) + assert (2**64 + 1) ** Rational(17, 25) # negative rational power and negative base - assert (-3) ** Rational(-7, 3) == -(-1)**Rational(2, 3)*3**Rational(2, 3)/27 - assert (-3) ** Rational(-2, 3) == -(-1)**Rational(1, 3)*3**Rational(1, 3)/3 + assert (-3) ** Rational(-7, 3) == \ + -(-1)**Rational(2, 3)*3**Rational(2, 3)/27 + assert (-3) ** Rational(-2, 3) == \ + -(-1)**Rational(1, 3)*3**Rational(1, 3)/3 assert S(1234).factors() == {617: 1, 2: 1} assert Rational(2*3, 3*5*7).factors() == {2: 1, 5: -1, 7: -1} - # test that eval_power factors numbers bigger than limit (2**15) + # test that eval_power factors numbers bigger than + # the current limit in factor_trial_division (2**15) from sympy import nextprime - n = nextprime(2**15) # bigger than the current limit in factor_trial_division + n = nextprime(2**15) assert sqrt(n**2) == n assert sqrt(n**3) == n*sqrt(n) assert sqrt(4*n) == 2*sqrt(n) @@ -717,79 +851,90 @@ # check that bases sharing a gcd are exptracted assert 2**Rational(1, 3)*3**Rational(1, 4)*6**Rational(1, 5) == \ - 2**Rational(8, 15)*3**Rational(9, 20) + 2**Rational(8, 15)*3**Rational(9, 20) assert sqrt(8)*24**Rational(1, 3)*6**Rational(1, 5) == \ - 4*2**Rational(7, 10)*3**Rational(8, 15) + 4*2**Rational(7, 10)*3**Rational(8, 15) assert sqrt(8)*(-24)**Rational(1, 3)*(-6)**Rational(1, 5) == \ - 4*(-3)**Rational(8, 15)*2**Rational(7, 10) + 4*(-3)**Rational(8, 15)*2**Rational(7, 10) assert 2**Rational(1, 3)*2**Rational(8, 9) == 2*2**Rational(2, 9) assert 2**Rational(2, 3)*6**Rational(1, 3) == 2*3**Rational(1, 3) - assert 2**Rational(2, 3)*6**Rational(8, 9) == 2*2**Rational(5, 9)*3**Rational(8, 9) + assert 2**Rational(2, 3)*6**Rational(8, 9) == \ + 2*2**Rational(5, 9)*3**Rational(8, 9) assert (-2)**Rational(2, S(3))*(-4)**Rational(1, S(3)) == -2*2**Rational(1, 3) assert 3*Pow(3, 2, evaluate=False) == 3**3 assert 3*Pow(3, -1/S(3), evaluate=False) == 3**(2/S(3)) assert (-2)**(1/S(3))*(-3)**(1/S(4))*(-5)**(5/S(6)) == \ - -(-1)**Rational(5, 12)*2**Rational(1, 3)*3**Rational(1, 4)*5**Rational(5, 6) + -(-1)**Rational(5, 12)*2**Rational(1, 3)*3**Rational(1, 4) * \ + 5**Rational(5, 6) - assert Integer(-2)**Symbol('', even=True) == Integer(2)**Symbol('', even=True) + assert Integer(-2)**Symbol('', even=True) == \ + Integer(2)**Symbol('', even=True) assert (-1)**Float(.5) == 1.0*I + def test_powers_Rational(): """Test Rational._eval_power""" # check infinity - assert Rational(1,2) ** S.Infinity == 0 - assert Rational(3,2) ** S.Infinity == S.Infinity - assert Rational(-1,2) ** S.Infinity == 0 - assert Rational(-3,2)** S.Infinity == S.Infinity + S.Infinity * S.ImaginaryUnit + assert Rational(1, 2) ** S.Infinity == 0 + assert Rational(3, 2) ** S.Infinity == S.Infinity + assert Rational(-1, 2) ** S.Infinity == 0 + assert Rational(-3, 2) ** S.Infinity == \ + S.Infinity + S.Infinity * S.ImaginaryUnit # check Nan - assert Rational(3,4) ** S.NaN == S.NaN - assert Rational(-2,3) ** S.NaN == S.NaN + assert Rational(3, 4) ** S.NaN == S.NaN + assert Rational(-2, 3) ** S.NaN == S.NaN # exact roots on numerator - assert sqrt(Rational(4,3)) == 2 * sqrt(3) / 3 - assert Rational(4,3) ** Rational(3,2) == 8 * sqrt(3) / 9 - assert sqrt(Rational(-4,3)) == I * 2 * sqrt(3) / 3 - assert Rational(-4,3) ** Rational(3,2) == - I * 8 * sqrt(3) / 9 - assert Rational(27,2) ** Rational(1,3) == 3 * (2 ** Rational(2,3)) / 2 - assert Rational(5**3, 8**3) ** Rational(4,3) == Rational(5**4, 8**4) + assert sqrt(Rational(4, 3)) == 2 * sqrt(3) / 3 + assert Rational(4, 3) ** Rational(3, 2) == 8 * sqrt(3) / 9 + assert sqrt(Rational(-4, 3)) == I * 2 * sqrt(3) / 3 + assert Rational(-4, 3) ** Rational(3, 2) == - I * 8 * sqrt(3) / 9 + assert Rational(27, 2) ** Rational(1, 3) == 3 * (2 ** Rational(2, 3)) / 2 + assert Rational(5**3, 8**3) ** Rational(4, 3) == Rational(5**4, 8**4) # exact root on denominator - assert sqrt(Rational(1,4)) == Rational(1,2) - assert sqrt(Rational(1,-4)) == I * Rational(1,2) - assert sqrt(Rational(3,4)) == sqrt(3) / 2 - assert sqrt(Rational(3,-4)) == I * sqrt(3) / 2 - assert Rational(5,27) ** Rational(1,3) == (5 ** Rational(1,3)) / 3 + assert sqrt(Rational(1, 4)) == Rational(1, 2) + assert sqrt(Rational(1, -4)) == I * Rational(1, 2) + assert sqrt(Rational(3, 4)) == sqrt(3) / 2 + assert sqrt(Rational(3, -4)) == I * sqrt(3) / 2 + assert Rational(5, 27) ** Rational(1, 3) == (5 ** Rational(1, 3)) / 3 # not exact roots - assert sqrt(Rational(1,2)) == sqrt(2) / 2 - assert sqrt(Rational(-4,7)) == I * sqrt(Rational(4,7)) + assert sqrt(Rational(1, 2)) == sqrt(2) / 2 + assert sqrt(Rational(-4, 7)) == I * sqrt(Rational(4, 7)) assert Rational(-3, 2)**Rational(-7, 3) == \ - -4*(-1)**Rational(2, 3)*2**Rational(1, 3)*3**Rational(2, 3)/27 + -4*(-1)**Rational(2, 3)*2**Rational(1, 3)*3**Rational(2, 3)/27 assert Rational(-3, 2)**Rational(-2, 3) == \ - -(-1)**Rational(1, 3)*2**Rational(2, 3)*3**Rational(1, 3)/3 + -(-1)**Rational(1, 3)*2**Rational(2, 3)*3**Rational(1, 3)/3 # negative integer power and negative rational base assert Rational(-2, 3) ** Rational(-2, 1) == Rational(9, 4) a = Rational(1, 10) assert a**Float(a, 2) == Float(a, 2)**Float(a, 2) - assert Rational(-2, 3)**Symbol('', even=True) == Rational(2, 3)**Symbol('', even=True) + assert Rational(-2, 3)**Symbol('', even=True) == \ + Rational(2, 3)**Symbol('', even=True) + def test_powers_Float(): assert str((S('-1/10')**S('3/10')).n()) == str(Float(-.1)**(.3)) + def test_abs1(): - assert Rational(1,6) != Rational(-1,6) - assert abs(Rational(1,6)) == abs(Rational(-1,6)) + assert Rational(1, 6) != Rational(-1, 6) + assert abs(Rational(1, 6)) == abs(Rational(-1, 6)) + def test_accept_int(): assert Float(4) == 4 + def test_dont_accept_str(): - assert Float("0.2") != "0.2" + assert Float("0.2") != "0.2" assert not (Float("0.2") == "0.2") + def test_int(): a = Rational(5) assert int(a) == 5 @@ -800,13 +945,26 @@ assert int(E) == 2 assert int(GoldenRatio) == 1 +def test_long(): + a = Rational(5) + assert int(a) == 5 + a = Rational(9, 10) + assert int(a) == int(-a) == 0 + a = Integer(2**100) + assert int(a) == a + assert int(pi) == 3 + assert int(E) == 2 + assert int(GoldenRatio) == 1 + def test_real_bug(): x = Symbol("x") - assert str(2.0*x*x) in ["(2.0*x)*x","2.0*x**2","2.00000000000000*x**2"] - assert str(2.1*x*x)!="(2.0*x)*x" + assert str(2.0*x*x) in ["(2.0*x)*x", "2.0*x**2", "2.00000000000000*x**2"] + assert str(2.1*x*x) != "(2.0*x)*x" + def test_bug_sqrt(): - assert ((sqrt(Rational(2))+1)*(sqrt(Rational(2))-1)).expand() == 1 + assert ((sqrt(Rational(2)) + 1)*(sqrt(Rational(2)) - 1)).expand() == 1 + def test_pi_Pi(): "Test, that pi (instance) is imported, but Pi (class) is not" @@ -814,143 +972,127 @@ with raises(ImportError): from sympy import Pi + def test_no_len(): # there should be no len for numbers raises(TypeError, lambda: len(Rational(2))) - raises(TypeError, lambda: len(Rational(2,3))) + raises(TypeError, lambda: len(Rational(2, 3))) raises(TypeError, lambda: len(Integer(2))) + def test_issue222(): assert sqrt(Rational(1, 5)) == sqrt(Rational(1, 5)) - assert 5 * sqrt(Rational(1,5)) == sqrt(5) + assert 5 * sqrt(Rational(1, 5)) == sqrt(5) + def test_issue593(): - assert ((-1)**Rational(1,6)).expand(complex=True) == I/2 + sqrt(3)/2 - assert ((-5)**Rational(1,6)).expand(complex=True) == \ - 5**Rational(1,6)*I/2 + 5**Rational(1,6)*sqrt(3)/2 - assert ((-64)**Rational(1,6)).expand(complex=True) == I + sqrt(3) + assert ((-1)**Rational(1, 6)).expand(complex=True) == I/2 + sqrt(3)/2 + assert ((-5)**Rational(1, 6)).expand(complex=True) == \ + 5**Rational(1, 6)*I/2 + 5**Rational(1, 6)*sqrt(3)/2 + assert ((-64)**Rational(1, 6)).expand(complex=True) == I + sqrt(3) + def test_issue324(): x = Symbol("x") - assert sqrt(x-1).as_base_exp() == (x - 1, S.Half) - assert sqrt(x-1) != I*sqrt(1-x) + assert sqrt(x - 1).as_base_exp() == (x - 1, S.Half) + assert sqrt(x - 1) != I*sqrt(1 - x) + def test_issue350(): x = Symbol("x", real=True) assert sqrt(x**2) == abs(x) - assert sqrt(x-1).subs(x,5) == 2 + assert sqrt(x - 1).subs(x, 5) == 2 def test_Integer_factors(): def F(i): return Integer(i).factors() - assert F(1) == { 1:1} - assert F(2) == { 2:1} - assert F(3) == { 3:1} - assert F(4) == { 2:2} - assert F(5) == { 5:1} - assert F(6) == { 2:1, 3:1} - assert F(7) == { 7:1} - assert F(8) == { 2:3} - assert F(9) == { 3:2} - assert F(10) == { 2:1, 5:1} - assert F(11) == {11:1} - assert F(12) == { 2:2, 3:1} - assert F(13) == {13:1} - assert F(14) == { 2:1, 7:1} - assert F(15) == { 3:1, 5:1} - assert F(16) == { 2:4} - assert F(17) == {17:1} - assert F(18) == { 2:1, 3:2} - assert F(19) == {19:1} - assert F(20) == { 2:2, 5:1} - assert F(21) == { 3:1, 7:1} - assert F(22) == { 2:1, 11:1} - assert F(23) == {23:1} - assert F(24) == { 2:3, 3:1} - assert F(25) == { 5:2} - assert F(26) == { 2:1, 13:1} - assert F(27) == { 3:3} - assert F(28) == { 2:2, 7:1} - assert F(29) == {29:1} - assert F(30) == { 2:1, 3:1, 5:1} - assert F(31) == {31:1} - assert F(32) == { 2:5} - assert F(33) == { 3:1, 11:1} - assert F(34) == { 2:1, 17:1} - assert F(35) == { 5:1, 7:1} - assert F(36) == { 2:2, 3:2} - assert F(37) == {37:1} - assert F(38) == { 2:1, 19:1} - assert F(39) == { 3:1, 13:1} - assert F(40) == { 2:3, 5:1} - assert F(41) == {41:1} - assert F(42) == { 2:1, 3:1, 7:1} - assert F(43) == {43:1} - assert F(44) == { 2:2, 11:1} - assert F(45) == { 3:2, 5:1} - assert F(46) == { 2:1, 23:1} - assert F(47) == {47:1} - assert F(48) == { 2:4, 3:1} - assert F(49) == { 7:2} - assert F(50) == { 2:1, 5:2} - assert F(51) == { 3:1, 17:1} + assert F(1) == {1: 1} + assert F(2) == {2: 1} + assert F(3) == {3: 1} + assert F(4) == {2: 2} + assert F(5) == {5: 1} + assert F(6) == {2: 1, 3: 1} + assert F(7) == {7: 1} + assert F(8) == {2: 3} + assert F(9) == {3: 2} + assert F(10) == {2: 1, 5: 1} + assert F(11) == {11: 1} + assert F(12) == {2: 2, 3: 1} + assert F(13) == {13: 1} + assert F(14) == {2: 1, 7: 1} + assert F(15) == {3: 1, 5: 1} + assert F(16) == {2: 4} + assert F(17) == {17: 1} + assert F(18) == {2: 1, 3: 2} + assert F(19) == {19: 1} + assert F(20) == {2: 2, 5: 1} + assert F(21) == {3: 1, 7: 1} + assert F(22) == {2: 1, 11: 1} + assert F(23) == {23: 1} + assert F(24) == {2: 3, 3: 1} + assert F(25) == {5: 2} + assert F(26) == {2: 1, 13: 1} + assert F(27) == {3: 3} + assert F(28) == {2: 2, 7: 1} + assert F(29) == {29: 1} + assert F(30) == {2: 1, 3: 1, 5: 1} + assert F(31) == {31: 1} + assert F(32) == {2: 5} + assert F(33) == {3: 1, 11: 1} + assert F(34) == {2: 1, 17: 1} + assert F(35) == {5: 1, 7: 1} + assert F(36) == {2: 2, 3: 2} + assert F(37) == {37: 1} + assert F(38) == {2: 1, 19: 1} + assert F(39) == {3: 1, 13: 1} + assert F(40) == {2: 3, 5: 1} + assert F(41) == {41: 1} + assert F(42) == {2: 1, 3: 1, 7: 1} + assert F(43) == {43: 1} + assert F(44) == {2: 2, 11: 1} + assert F(45) == {3: 2, 5: 1} + assert F(46) == {2: 1, 23: 1} + assert F(47) == {47: 1} + assert F(48) == {2: 4, 3: 1} + assert F(49) == {7: 2} + assert F(50) == {2: 1, 5: 2} + assert F(51) == {3: 1, 17: 1} def test_Rational_factors(): - def F(p,q,visual=None): - return Rational(p,q).factors(visual=visual) + def F(p, q, visual=None): + return Rational(p, q).factors(visual=visual) - assert F(2,3) == { 2:1, 3:-1} - assert F(2,9) == { 2:1, 3:-2} - assert F(2,15) == { 2:1, 3:-1, 5:-1} - assert F(6,10) == { 3:1, 5:-1} - assert str(F(12,1, visual=True)) == '2**2*3**1' - assert str(F(1,1, visual=True)) == '1' + assert F(2, 3) == {2: 1, 3: -1} + assert F(2, 9) == {2: 1, 3: -2} + assert F(2, 15) == {2: 1, 3: -1, 5: -1} + assert F(6, 10) == {3: 1, 5: -1} + assert str(F(12, 1, visual=True)) == '2**2*3**1' + assert str(F(1, 1, visual=True)) == '1' assert str(F(25, 14, visual=True)) == '5**2/(2*7)' assert str(F(-25, 14*9, visual=True)) == '-5**2/(2*3**2*7)' + def test_issue1008(): - assert pi*(E + 10) + pi*(-E - 10) != 0 + assert pi*(E + 10) + pi*(-E - 10) != 0 assert pi*(E + 10**10) + pi*(-E - 10**10) != 0 assert pi*(E + 10**20) + pi*(-E - 10**20) != 0 assert pi*(E + 10**80) + pi*(-E - 10**80) != 0 - assert (pi*(E + 10) + pi*(-E - 10)).expand() == 0 + assert (pi*(E + 10) + pi*(-E - 10)).expand() == 0 assert (pi*(E + 10**10) + pi*(-E - 10**10)).expand() == 0 assert (pi*(E + 10**20) + pi*(-E - 10**20)).expand() == 0 assert (pi*(E + 10**80) + pi*(-E - 10**80)).expand() == 0 + def test_IntegerInteger(): a = Integer(4) b = Integer(a) assert a == b -def test_Integer_methods(): - assert Integer(0).factorial() == Integer(1) - assert Integer(1).factorial() == Integer(1) - assert Integer(10).factorial() == Integer(3628800) - - assert Integer(100).isqrt() == Integer(10) - assert Integer(110).isqrt() == Integer(10) - assert Integer(121).isqrt() == Integer(11) - - assert Integer(100).half_gcdex(2004) == \ - (Integer(-20), Integer(4)) - assert Integer(100).half_gcdex(Integer(2004)) == \ - (Integer(-20), Integer(4)) - assert Integer(100).gcdex(2004) == \ - (Integer(-20), Integer(1), Integer(4)) - assert Integer(100).gcdex(Integer(2004)) == \ - (Integer(-20), Integer(1), Integer(4)) - - raises(ValueError, lambda: Integer(3).half_gcdex(Rational(1,2))) - raises(ValueError, lambda: Integer(3).gcdex(Rational(1,2))) - - assert Integer(3).invert(7) == Integer(5) - assert Integer(3).invert(Integer(7)) == Integer(5) def test_Rational_gcd_lcm_cofactors(): assert Integer(4).gcd(2) == Integer(2) @@ -963,38 +1105,43 @@ assert Integer(4).gcd(Integer(3)) == Integer(1) assert Integer(4).lcm(Integer(3)) == Integer(12) - assert Rational(4,3).gcd(2) == Rational(2,3) - assert Rational(4,3).lcm(2) == Integer(4) - assert Rational(4,3).gcd(Integer(2)) == Rational(2,3) - assert Rational(4,3).lcm(Integer(2)) == Integer(4) - - assert Integer(4).gcd(Rational(2,9)) == Rational(2,9) - assert Integer(4).lcm(Rational(2,9)) == Integer(4) - - assert Rational(4,3).gcd(Rational(2,9)) == Rational(2,9) - assert Rational(4,3).lcm(Rational(2,9)) == Rational(4,3) - assert Rational(4,5).gcd(Rational(2,9)) == Rational(2,45) - assert Rational(4,5).lcm(Rational(2,9)) == Integer(4) + assert Rational(4, 3).gcd(2) == Rational(2, 3) + assert Rational(4, 3).lcm(2) == Integer(4) + assert Rational(4, 3).gcd(Integer(2)) == Rational(2, 3) + assert Rational(4, 3).lcm(Integer(2)) == Integer(4) + + assert Integer(4).gcd(Rational(2, 9)) == Rational(2, 9) + assert Integer(4).lcm(Rational(2, 9)) == Integer(4) + + assert Rational(4, 3).gcd(Rational(2, 9)) == Rational(2, 9) + assert Rational(4, 3).lcm(Rational(2, 9)) == Rational(4, 3) + assert Rational(4, 5).gcd(Rational(2, 9)) == Rational(2, 45) + assert Rational(4, 5).lcm(Rational(2, 9)) == Integer(4) assert Integer(4).cofactors(2) == (Integer(2), Integer(2), Integer(1)) - assert Integer(4).cofactors(Integer(2)) == (Integer(2), Integer(2), Integer(1)) + assert Integer(4).cofactors(Integer(2)) == \ + (Integer(2), Integer(2), Integer(1)) assert Integer(4).gcd(Float(2.0)) == S.One assert Integer(4).lcm(Float(2.0)) == Float(8.0) assert Integer(4).cofactors(Float(2.0)) == (S.One, Integer(4), Float(2.0)) - assert Rational(1,2).gcd(Float(2.0)) == S.One - assert Rational(1,2).lcm(Float(2.0)) == Float(1.0) - assert Rational(1,2).cofactors(Float(2.0)) == (S.One, Rational(1,2), Float(2.0)) + assert Rational(1, 2).gcd(Float(2.0)) == S.One + assert Rational(1, 2).lcm(Float(2.0)) == Float(1.0) + assert Rational(1, 2).cofactors(Float(2.0)) == \ + (S.One, Rational(1, 2), Float(2.0)) + def test_Float_gcd_lcm_cofactors(): assert Float(2.0).gcd(Integer(4)) == S.One assert Float(2.0).lcm(Integer(4)) == Float(8.0) assert Float(2.0).cofactors(Integer(4)) == (S.One, Float(2.0), Integer(4)) - assert Float(2.0).gcd(Rational(1,2)) == S.One - assert Float(2.0).lcm(Rational(1,2)) == Float(1.0) - assert Float(2.0).cofactors(Rational(1,2)) == (S.One, Float(2.0), Rational(1,2)) + assert Float(2.0).gcd(Rational(1, 2)) == S.One + assert Float(2.0).lcm(Rational(1, 2)) == Float(1.0) + assert Float(2.0).cofactors(Rational(1, 2)) == \ + (S.One, Float(2.0), Rational(1, 2)) + def test_issue1512(): assert abs(pi._evalf(50) - 3.14159265358979) < 1e-10 @@ -1003,17 +1150,19 @@ assert abs(EulerGamma._evalf(50) - 0.577215664901533) < 1e-10 assert abs(GoldenRatio._evalf(50) - 1.61803398874989) < 1e-10 x = Symbol("x") - assert (pi+x).evalf() == pi.evalf()+x - assert (E+x).evalf() == E.evalf()+x - assert (Catalan+x).evalf() == Catalan.evalf()+x - assert (EulerGamma+x).evalf() == EulerGamma.evalf()+x - assert (GoldenRatio+x).evalf() == GoldenRatio.evalf()+x + assert (pi + x).evalf() == pi.evalf() + x + assert (E + x).evalf() == E.evalf() + x + assert (Catalan + x).evalf() == Catalan.evalf() + x + assert (EulerGamma + x).evalf() == EulerGamma.evalf() + x + assert (GoldenRatio + x).evalf() == GoldenRatio.evalf() + x + def test_conversion_to_mpmath(): assert mpmath.mpmathify(Integer(1)) == mpmath.mpf(1) assert mpmath.mpmathify(Rational(1, 2)) == mpmath.mpf(0.5) assert mpmath.mpmathify(Float('1.23', 15)) == mpmath.mpf('1.23') + def test_relational(): # real x = S(.1) @@ -1021,7 +1170,7 @@ assert (x == cos) is False # rational - x = Rational(1,3) + x = Rational(1, 3) assert (x != cos) is True assert (x == cos) is False @@ -1032,16 +1181,19 @@ assert (x != cos) is True assert (x == cos) is False + def test_Integer_as_index(): - if hasattr(int, '__index__'): # Python 2.5+ (PEP 357) + if hasattr(int, '__index__'): # Python 2.5+ (PEP 357) assert 'hello'[Integer(2):] == 'llo' + def test_Rational_int(): - assert int( Rational(7, 5)) == 1 - assert int( Rational(1, 2)) == 0 - assert int(-Rational(1, 2)) == 0 + assert int( Rational(7, 5)) == 1 + assert int( Rational(1, 2)) == 0 + assert int(-Rational(1, 2)) == 0 assert int(-Rational(7, 5)) == -1 + def test_zoo(): b = Symbol('b', bounded=True) nz = Symbol('nz', nonzero=True) @@ -1087,7 +1239,7 @@ else: assert (zoo/i).is_Mul - assert (I*oo).is_Mul # allow directed infinity + assert (I*oo).is_Mul # allow directed infinity assert zoo + zoo is S.NaN assert zoo * zoo is zoo assert zoo - zoo is S.NaN @@ -1099,15 +1251,16 @@ assert Mul.flatten([S(-1), oo, S(0)]) == ([S.NaN], [], None) + def test_issue_1023(): x = Symbol('x', nonpositive=True) assert (oo + x).is_Add x = Symbol('x', bounded=True) - assert (oo + x).is_Add # x could be imaginary + assert (oo + x).is_Add # x could be imaginary x = Symbol('x', finite=True) - assert (oo + x).is_Add # x could be imaginary + assert (oo + x).is_Add # x could be imaginary x = Symbol('x', infinitesimal=True) - assert (oo + x).is_Add # x could be imaginary + assert (oo + x).is_Add # x could be imaginary x = Symbol('x', nonnegative=True) assert oo + x == oo x = Symbol('x', bounded=True, real=True) @@ -1135,9 +1288,11 @@ x = Symbol('x', infinitesimal=True, real=True) assert -oo + x == -oo + def test_GoldenRatio_expand(): assert GoldenRatio.expand(func=True) == S.Half + sqrt(5)/2 + def test_as_content_primitive(): assert S.Zero.as_content_primitive() == (1, 0) assert S.Half.as_content_primitive() == (S.Half, 1) @@ -1145,6 +1300,7 @@ assert S(3).as_content_primitive() == (3, 1) assert S(3.1).as_content_primitive() == (1, 3.1) + @XFAIL def test_hashing_sympy_integers(): # Test for issue #1973 @@ -1152,26 +1308,32 @@ assert hash(S(4)) == 4 assert hash(S(4)) == hash(int(4)) + def test_issue_1073(): - assert int((E**100).round()) == 26881171418161354484126255515800135873611119 - assert int((pi**100).round()) == 51878483143196131920862615246303013562686760680406 - assert int((Rational(1)/EulerGamma**100).round()) == 734833795660954410469466 + assert int((E**100).round()) == \ + 26881171418161354484126255515800135873611119 + assert int((pi**100).round()) == \ + 51878483143196131920862615246303013562686760680406 + assert int((Rational(1)/EulerGamma**100).round()) == \ + 734833795660954410469466 + @XFAIL def test_mpmath_issues(): from sympy.mpmath.libmp.libmpf import _normalize import sympy.mpmath.libmp as mlib rnd = mlib.round_nearest - mpf = (0, 0, -123, -1, 53, rnd) # nan + mpf = (0, 0, -123, -1, 53, rnd) # nan assert _normalize(mpf, 53) != (0, 0, 0, 0) - mpf = (0, 0, -456, -2, 53, rnd) # +inf + mpf = (0, 0, -456, -2, 53, rnd) # +inf assert _normalize(mpf, 53) != (0, 0, 0, 0) - mpf = (1, 0, -789, -3, 53, rnd) # -inf + mpf = (1, 0, -789, -3, 53, rnd) # -inf assert _normalize(mpf, 53) != (0, 0, 0, 0) from sympy.mpmath.libmp.libmpf import fnan assert mlib.mpf_eq(fnan, fnan) + def test_Catalan_EulerGamma_prec(): n = GoldenRatio f = Float(n.n(), 5) @@ -1185,12 +1347,35 @@ assert f._prec == 20 assert n._as_mpf_val(20) == f._mpf_ + def test_Float_eq(): assert Float(.12, 3) != Float(.12, 4) assert Float(.12, 3) == .12 assert 0.12 == Float(.12, 3) assert Float('.12', 22) != .12 + def test_int_NumberSymbols(): assert [int(i) for i in [pi, EulerGamma, E, GoldenRatio, Catalan]] == \ [3, 0, 2, 1, 0] + + +def test_3541(): + from sympy.mpmath.libmp.libmpf import ( + _normalize as mpf_normalize, finf, fninf, fzero) + # fnan is not included because Float no longer returns fnan, + # but otherwise, the same sort of test could apply + assert Float(finf).is_zero is False + assert Float(fninf).is_zero is False + assert bool(Float(0)) is False + + +def test_3250(): + assert Float('23.e3', '')._prec == 10 + assert Float('23e3', '')._prec == 20 + assert Float('23000', '')._prec == 20 + assert Float('-23000', '')._prec == 20 + +def test_mpf_norm(): + assert mpf_norm((1, 0, 1, 0), 10) == mpf('0')._mpf_ + assert Float._new((1, 0, 1, 0), 10)._mpf_ == mpf('0')._mpf_ diff -Nru python3-sympy-0.7.2/sympy/core/tests/test_operations.py python3-sympy-0.7.3/sympy/core/tests/test_operations.py --- python3-sympy-0.7.2/sympy/core/tests/test_operations.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/core/tests/test_operations.py 2013-07-13 17:53:32.000000000 +0000 @@ -4,10 +4,13 @@ from sympy.core.sympify import SympifyError # create the simplest possible Lattice class + + class join(LatticeOp): zero = Integer(0) identity = Integer(1) + def test_lattice_simple(): assert join(join(2, 3), 4) == join(2, join(3, 4)) assert join(2, 3) == join(3, 2) @@ -20,13 +23,16 @@ assert join(4) == 4 assert join(1, 4, 2, 3, 1, 3, 2) == join(2, 3, 4) + def test_lattice_shortcircuit(): raises(SympifyError, lambda: join(object)) assert join(0, object) == 0 + def test_lattice_print(): assert str(join(5, 4, 3, 2)) == 'join(2, 3, 4, 5)' + def test_lattice_make_args(): assert join.make_args(0) == set([0]) assert join.make_args(1) == set([1]) diff -Nru python3-sympy-0.7.2/sympy/core/tests/test_priority.py python3-sympy-0.7.3/sympy/core/tests/test_priority.py --- python3-sympy-0.7.2/sympy/core/tests/test_priority.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/core/tests/test_priority.py 2013-07-13 17:53:32.000000000 +0000 @@ -10,6 +10,7 @@ @call_highest_priority('__rmul__') def __mul__(self, other): return self.result + @call_highest_priority('__mul__') def __rmul__(self, other): return self.result @@ -17,6 +18,7 @@ @call_highest_priority('__radd__') def __add__(self, other): return self.result + @call_highest_priority('__add__') def __radd__(self, other): return self.result @@ -24,6 +26,7 @@ @call_highest_priority('__rsub__') def __sub__(self, other): return self.result + @call_highest_priority('__sub__') def __rsub__(self, other): return self.result @@ -31,6 +34,7 @@ @call_highest_priority('__rpow__') def __pow__(self, other): return self.result + @call_highest_priority('__pow__') def __rpow__(self, other): return self.result @@ -38,6 +42,7 @@ @call_highest_priority('__rdiv__') def __div__(self, other): return self.result + @call_highest_priority('__div__') def __rdiv__(self, other): return self.result @@ -45,11 +50,13 @@ __truediv__ = __div__ __rtruediv__ = __rdiv__ + class Lower(Higher): _op_priority = 5.0 result = 'low' + def test_mul(): x = Symbol('x') h = Higher() @@ -58,21 +65,24 @@ assert x*h == h*x == 'high' assert l*x == x*l != 'low' + def test_add(): x = Symbol('x') h = Higher() l = Lower() - assert l+h == h+l == 'high' - assert x+h == h+x == 'high' - assert l+x == x+l != 'low' + assert l + h == h + l == 'high' + assert x + h == h + x == 'high' + assert l + x == x + l != 'low' + def test_sub(): x = Symbol('x') h = Higher() l = Lower() - assert l-h == h-l == 'high' - assert x-h == h-x == 'high' - assert l-x == -(x-l) != 'low' + assert l - h == h - l == 'high' + assert x - h == h - x == 'high' + assert l - x == -(x - l) != 'low' + def test_pow(): x = Symbol('x') @@ -83,6 +93,7 @@ assert l**x != 'low' assert x**l != 'low' + def test_div(): x = Symbol('x') h = Higher() diff -Nru python3-sympy-0.7.2/sympy/core/tests/test_relational.py python3-sympy-0.7.3/sympy/core/tests/test_relational.py --- python3-sympy-0.7.2/sympy/core/tests/test_relational.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/core/tests/test_relational.py 2013-07-13 17:53:32.000000000 +0000 @@ -8,77 +8,79 @@ def test_rel_ne(): - Relational(x, y, '!=') # this used to raise + assert Relational(x, y, '!=') == Ne(x, y) def test_rel_subs(): e = Relational(x, y, '==') - e = e.subs(x,z) + e = e.subs(x, z) assert isinstance(e, Equality) assert e.lhs == z assert e.rhs == y e = Relational(x, y, '>=') - e = e.subs(x,z) + e = e.subs(x, z) assert isinstance(e, GreaterThan) assert e.lhs == z assert e.rhs == y e = Relational(x, y, '<=') - e = e.subs(x,z) + e = e.subs(x, z) assert isinstance(e, LessThan) assert e.lhs == z assert e.rhs == y e = Relational(x, y, '>') - e = e.subs(x,z) + e = e.subs(x, z) assert isinstance(e, StrictGreaterThan) assert e.lhs == z assert e.rhs == y e = Relational(x, y, '<') - e = e.subs(x,z) + e = e.subs(x, z) assert isinstance(e, StrictLessThan) assert e.lhs == z assert e.rhs == y - e = Eq(x,0) - assert e.subs(x,0) == True - assert e.subs(x,1) == False + e = Eq(x, 0) + assert e.subs(x, 0) is True + assert e.subs(x, 1) is False def test_wrappers(): - e = x+x**2 + e = x + x**2 res = Relational(y, e, '==') - assert Rel(y, x+x**2, '==') == res - assert Eq(y, x+x**2) == res + assert Rel(y, x + x**2, '==') == res + assert Eq(y, x + x**2) == res res = Relational(y, e, '<') - assert Lt(y, x+x**2) == res + assert Lt(y, x + x**2) == res res = Relational(y, e, '<=') - assert Le(y, x+x**2) == res + assert Le(y, x + x**2) == res res = Relational(y, e, '>') - assert Gt(y, x+x**2) == res + assert Gt(y, x + x**2) == res res = Relational(y, e, '>=') - assert Ge(y, x+x**2) == res + assert Ge(y, x + x**2) == res res = Relational(y, e, '!=') - assert Ne(y, x+x**2) == res + assert Ne(y, x + x**2) == res + def test_Eq(): assert Eq(x**2) == Eq(x**2, 0) assert Eq(x**2) != Eq(x**2, 1) + def test_rel_Infinity(): assert (oo > oo) is False assert (oo > -oo) is True @@ -105,21 +107,22 @@ assert (-oo <= -oo) is True assert (-oo <= 1) is True + def test_bool(): - assert Eq(0,0) is True - assert Eq(1,0) is False - assert Ne(0,0) is False - assert Ne(1,0) is True - assert Lt(0,1) is True - assert Lt(1,0) is False - assert Le(0,1) is True - assert Le(1,0) is False - assert Le(0,0) is True - assert Gt(1,0) is True - assert Gt(0,1) is False - assert Ge(1,0) is True - assert Ge(0,1) is False - assert Ge(1,1) is True + assert Eq(0, 0) is True + assert Eq(1, 0) is False + assert Ne(0, 0) is False + assert Ne(1, 0) is True + assert Lt(0, 1) is True + assert Lt(1, 0) is False + assert Le(0, 1) is True + assert Le(1, 0) is False + assert Le(0, 0) is True + assert Gt(1, 0) is True + assert Gt(0, 1) is False + assert Ge(1, 0) is True + assert Ge(0, 1) is False + assert Ge(1, 1) is True assert Eq(I, 2) is False assert Ne(I, 2) is True assert Gt(I, 2) not in [True, False] @@ -130,11 +133,13 @@ b = Float('.0000000000000000000001', '') assert Eq(pi + a, pi + b) is False + def test_rich_cmp(): - assert (xy) == Gt(x,y) - assert (x>=y) == Ge(x,y) + assert (x < y) == Lt(x, y) + assert (x <= y) == Le(x, y) + assert (x > y) == Gt(x, y) + assert (x >= y) == Ge(x, y) + def test_doit(): from sympy import Symbol @@ -154,21 +159,22 @@ assert Eq(x, 0).doit() == Eq(x, 0) + def test_new_relational(): x = Symbol('x') - assert Eq(x) == Relational(x, 0) # None ==> Equality - assert Eq(x) == Relational(x, 0, '==') - assert Eq(x) == Relational(x, 0, 'eq') - assert Eq(x) == Equality(x, 0) + assert Eq(x) == Relational(x, 0) # None ==> Equality + assert Eq(x) == Relational(x, 0, '==') + assert Eq(x) == Relational(x, 0, 'eq') + assert Eq(x) == Equality(x, 0) assert Eq(x, -1) == Relational(x, -1) # None ==> Equality assert Eq(x, -1) == Relational(x, -1, '==') assert Eq(x, -1) == Relational(x, -1, 'eq') assert Eq(x, -1) == Equality(x, -1) - assert Eq(x) != Relational(x, 1) # None ==> Equality - assert Eq(x) != Relational(x, 1, '==') - assert Eq(x) != Relational(x, 1, 'eq') - assert Eq(x) != Equality(x, 1) + assert Eq(x) != Relational(x, 1) # None ==> Equality + assert Eq(x) != Relational(x, 1, '==') + assert Eq(x) != Relational(x, 1, 'eq') + assert Eq(x) != Equality(x, 1) assert Eq(x, -1) != Relational(x, 1) # None ==> Equality assert Eq(x, -1) != Relational(x, 1, '==') assert Eq(x, -1) != Relational(x, 1, 'eq') @@ -228,13 +234,12 @@ assert Lt(x, 1) != Relational(x, 0, '<') assert Lt(x, 1) != Relational(x, 0, 'lt') assert Lt(x, 1) != StrictLessThan(x, 0) - assert (x < 1) == Relational(x, 1, '<') - assert (x < 1) == Relational(x, 1, 'lt') - assert (x < 1) == StrictLessThan(x, 1) - assert (x < 0) != Relational(x, 1, '<') - assert (x < 0) != Relational(x, 1, 'lt') - assert (x < 0) != StrictLessThan(x, 1) - + assert (x < 1) == Relational(x, 1, '<') + assert (x < 1) == Relational(x, 1, 'lt') + assert (x < 1) == StrictLessThan(x, 1) + assert (x < 0) != Relational(x, 1, '<') + assert (x < 0) != Relational(x, 1, 'lt') + assert (x < 0) != StrictLessThan(x, 1) # finally, some fuzz testing from random import randint @@ -250,12 +255,14 @@ raises(ValueError, lambda: Relational(x, 1, relation_type)) + @XFAIL def test_relational_bool_output(): # XFail test for issue: # http://code.google.com/p/sympy/issues/detail?id=2832 raises(ValueError, lambda: bool(x > 3)) + def test_relational_logic_symbols(): # See issue 3105 assert (x < y) & (z < t) == And(x < y, z < t) diff -Nru python3-sympy-0.7.2/sympy/core/tests/test_rules.py python3-sympy-0.7.3/sympy/core/tests/test_rules.py --- python3-sympy-0.7.2/sympy/core/tests/test_rules.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/core/tests/test_rules.py 2013-07-13 17:53:32.000000000 +0000 @@ -2,8 +2,9 @@ from sympy.utilities.pytest import raises + def test_Transform(): - add1 = Transform(lambda x: x+1, lambda x: x % 2 == 1) + add1 = Transform(lambda x: x + 1, lambda x: x % 2 == 1) assert add1[1] == 2 assert (1 in add1) is True assert add1.get(1) == 2 diff -Nru python3-sympy-0.7.2/sympy/core/tests/test_sets.py python3-sympy-0.7.3/sympy/core/tests/test_sets.py --- python3-sympy-0.7.2/sympy/core/tests/test_sets.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/core/tests/test_sets.py 2013-07-13 17:53:32.000000000 +0000 @@ -8,11 +8,12 @@ from sympy.utilities.pytest import raises from sympy.utilities.pytest import raises, XFAIL + def test_interval_arguments(): assert Interval(0, oo) == Interval(0, oo, False, True) - assert Interval(0, oo).right_open == True + assert Interval(0, oo).right_open is True assert Interval(-oo, 0) == Interval(-oo, 0, True, False) - assert Interval(-oo, 0).left_open == True + assert Interval(-oo, 0).left_open is True assert isinstance(Interval(1, 1), FiniteSet) @@ -28,6 +29,7 @@ assert isinstance(Interval(1, Symbol('a', real=True)), Interval) + def test_interval_symbolic_end_points(): a = Symbol('a', real=True) @@ -36,6 +38,7 @@ assert Interval(0, a).contains(1) == LessThan(1, a) + def test_union(): assert Union(Interval(1, 2), Interval(2, 3)) == Interval(1, 3) assert Union(Interval(1, 2), Interval(2, 3, True)) == Interval(1, 3) @@ -43,83 +46,88 @@ assert Union(Interval(1, 2), Interval(1, 3)) == Interval(1, 3) assert Union(Interval(1, 3), Interval(1, 2)) == Interval(1, 3) assert Union(Interval(1, 3, False, True), Interval(1, 2)) == \ - Interval(1, 3, False, True) + Interval(1, 3, False, True) assert Union(Interval(1, 3), Interval(1, 2, False, True)) == Interval(1, 3) assert Union(Interval(1, 2, True), Interval(1, 3)) == Interval(1, 3) - assert Union(Interval(1, 2, True), Interval(1, 3, True)) == Interval(1, 3, True) + assert Union(Interval(1, 2, True), Interval(1, 3, True)) == \ + Interval(1, 3, True) assert Union(Interval(1, 2, True), Interval(1, 3, True, True)) == \ - Interval(1, 3, True, True) + Interval(1, 3, True, True) assert Union(Interval(1, 2, True, True), Interval(1, 3, True)) == \ - Interval(1, 3, True) + Interval(1, 3, True) assert Union(Interval(1, 3), Interval(2, 3)) == Interval(1, 3) assert Union(Interval(1, 3, False, True), Interval(2, 3)) == \ - Interval(1, 3) + Interval(1, 3) assert Union(Interval(1, 2, False, True), Interval(2, 3, True)) != \ - Interval(1, 3) + Interval(1, 3) assert Union(Interval(1, 2), S.EmptySet) == Interval(1, 2) assert Union(S.EmptySet) == S.EmptySet - assert Union(Interval(0,1), [FiniteSet(1.0/n) for n in range(1,10)]) == \ - Interval(0,1) + assert Union(Interval(0, 1), [FiniteSet(1.0/n) for n in range(1, 10)]) == \ + Interval(0, 1) assert Interval(1, 2).union(Interval(2, 3)) == \ - Interval(1, 2) + Interval(2, 3) + Interval(1, 2) + Interval(2, 3) assert Interval(1, 2).union(Interval(2, 3)) == Interval(1, 3) assert Union(Set()) == Set() - assert FiniteSet(1) + FiniteSet(2) + FiniteSet(3) == FiniteSet(1,2,3) + assert FiniteSet(1) + FiniteSet(2) + FiniteSet(3) == FiniteSet(1, 2, 3) assert FiniteSet(['ham']) + FiniteSet(['eggs']) == FiniteSet('ham', 'eggs') - assert FiniteSet(1,2,3) + S.EmptySet == FiniteSet(1,2,3) + assert FiniteSet(1, 2, 3) + S.EmptySet == FiniteSet(1, 2, 3) - assert FiniteSet(1,2,3) & FiniteSet(2,3,4) == FiniteSet(2,3) - assert FiniteSet(1,2,3) | FiniteSet(2,3,4) == FiniteSet(1,2,3,4) + assert FiniteSet(1, 2, 3) & FiniteSet(2, 3, 4) == FiniteSet(2, 3) + assert FiniteSet(1, 2, 3) | FiniteSet(2, 3, 4) == FiniteSet(1, 2, 3, 4) x = Symbol("x") y = Symbol("y") z = Symbol("z") assert S.EmptySet | FiniteSet(x, FiniteSet(y, z)) == \ - FiniteSet(x, FiniteSet(y, z)) + FiniteSet(x, FiniteSet(y, z)) # Test that Intervals and FiniteSets play nicely - assert Interval(1,3) + FiniteSet(2) == Interval(1,3) - assert Interval(1,3, True,True) + FiniteSet(3) == Interval(1,3, True,False) - X = Interval(1,3)+FiniteSet(5) - Y = Interval(1,2)+FiniteSet(3) + assert Interval(1, 3) + FiniteSet(2) == Interval(1, 3) + assert Interval(1, 3, True, True) + FiniteSet(3) == \ + Interval(1, 3, True, False) + X = Interval(1, 3) + FiniteSet(5) + Y = Interval(1, 2) + FiniteSet(3) XandY = X.intersect(Y) assert 2 in X and 3 in X and 3 in XandY assert X.subset(XandY) and Y.subset(XandY) raises(TypeError, lambda: Union(1, 2, 3)) - assert X.is_iterable == False + assert X.is_iterable is False + def test_difference(): assert Interval(1, 3) - Interval(1, 2) == Interval(2, 3, True) assert Interval(1, 3) - Interval(2, 3) == Interval(1, 2, False, True) assert Interval(1, 3, True) - Interval(2, 3) == Interval(1, 2, True, True) assert Interval(1, 3, True) - Interval(2, 3, True) == \ - Interval(1, 2, True, False) - assert Interval(0,2) - FiniteSet(1) == \ - Union(Interval(0,1,False, True), Interval(1,2, True, False)) + Interval(1, 2, True, False) + assert Interval(0, 2) - FiniteSet(1) == \ + Union(Interval(0, 1, False, True), Interval(1, 2, True, False)) - assert FiniteSet(1,2,3) - FiniteSet(2) == FiniteSet(1,3) + assert FiniteSet(1, 2, 3) - FiniteSet(2) == FiniteSet(1, 3) assert FiniteSet('ham', 'eggs') - FiniteSet(['eggs']) == FiniteSet(['ham']) - assert FiniteSet(1,2,3,4) - Interval(2,10, True, False) == FiniteSet(1,2) - assert FiniteSet(1,2,3,4) - S.EmptySet == FiniteSet(1,2,3,4) - assert Union(Interval(0,2), FiniteSet(2,3,4)) - Interval(1,3) == \ - Union(Interval(0,1,False, True), FiniteSet(4)) + assert FiniteSet(1, 2, 3, 4) - Interval(2, 10, True, False) == \ + FiniteSet(1, 2) + assert FiniteSet(1, 2, 3, 4) - S.EmptySet == FiniteSet(1, 2, 3, 4) + assert Union(Interval(0, 2), FiniteSet(2, 3, 4)) - Interval(1, 3) == \ + Union(Interval(0, 1, False, True), FiniteSet(4)) + def test_complement(): assert Interval(0, 1).complement == \ - Union(Interval(-oo, 0, True, True), Interval(1, oo, True, True)) + Union(Interval(-oo, 0, True, True), Interval(1, oo, True, True)) assert Interval(0, 1, True, False).complement == \ - Union(Interval(-oo, 0, True, False), Interval(1, oo, True, True)) + Union(Interval(-oo, 0, True, False), Interval(1, oo, True, True)) assert Interval(0, 1, False, True).complement == \ - Union(Interval(-oo, 0, True, True), Interval(1, oo, False, True)) + Union(Interval(-oo, 0, True, True), Interval(1, oo, False, True)) assert Interval(0, 1, True, True).complement == \ - Union(Interval(-oo, 0, True, False), Interval(1, oo, False, True)) + Union(Interval(-oo, 0, True, False), Interval(1, oo, False, True)) assert -S.EmptySet == S.EmptySet.complement assert ~S.EmptySet == S.EmptySet.complement @@ -128,69 +136,74 @@ assert S.UniversalSet.complement == S.EmptySet assert Union(Interval(0, 1), Interval(2, 3)).complement == \ - Union(Interval(-oo, 0, True, True), Interval(1, 2, True, True), - Interval(3, oo, True, True)) + Union(Interval(-oo, 0, True, True), Interval(1, 2, True, True), + Interval(3, oo, True, True)) - assert FiniteSet(0).complement == Union(Interval(-oo,0, True,True) , - Interval(0,oo, True, True)) + assert FiniteSet(0).complement == Union(Interval(-oo, 0, True, True), + Interval(0, oo, True, True)) assert (FiniteSet(5) + Interval(S.NegativeInfinity, 0)).complement == \ - Interval(0, 5, True, True) + Interval(5, S.Infinity, True,True) + Interval(0, 5, True, True) + Interval(5, S.Infinity, True, True) - assert FiniteSet(1,2,3).complement == Interval(S.NegativeInfinity,1, True,True) + Interval(1,2, True,True) + Interval(2,3, True,True) + Interval(3,S.Infinity, True,True) + assert FiniteSet(1, 2, 3).complement == \ + Interval(S.NegativeInfinity, 1, True, True) + Interval(1, 2, True, True) + \ + Interval(2, 3, True, True) + Interval(3, S.Infinity, True, True) - X = Interval(1,3)+FiniteSet(5) + X = Interval(1, 3) + FiniteSet(5) assert X.intersect(X.complement) == S.EmptySet - square = Interval(0,1) * Interval(0,1) + square = Interval(0, 1) * Interval(0, 1) notsquare = square.complement - assert all(pt in square for pt in [(0,0), (.5,.5), (1,0), (1,1)]) - assert not any(pt in notsquare for pt in [(0,0), (.5,.5), (1,0), (1,1)]) - assert not any(pt in square for pt in [(-1,0), (1.5,.5), (10,10)]) - assert all(pt in notsquare for pt in [(-1,0), (1.5,.5), (10,10)]) + assert all(pt in square for pt in [(0, 0), (.5, .5), (1, 0), (1, 1)]) + assert not any( + pt in notsquare for pt in [(0, 0), (.5, .5), (1, 0), (1, 1)]) + assert not any(pt in square for pt in [(-1, 0), (1.5, .5), (10, 10)]) + assert all(pt in notsquare for pt in [(-1, 0), (1.5, .5), (10, 10)]) + def test_intersect(): x = Symbol('x') assert Interval(0, 2).intersect(Interval(1, 2)) == Interval(1, 2) assert Interval(0, 2).intersect(Interval(1, 2, True)) == \ - Interval(1, 2, True) + Interval(1, 2, True) assert Interval(0, 2, True).intersect(Interval(1, 2)) == \ - Interval(1, 2, False, False) + Interval(1, 2, False, False) assert Interval(0, 2, True, True).intersect(Interval(1, 2)) == \ - Interval(1, 2, False, True) + Interval(1, 2, False, True) assert Interval(0, 2).intersect(Union(Interval(0, 1), Interval(2, 3))) == \ - Union(Interval(0, 1), Interval(2, 2)) + Union(Interval(0, 1), Interval(2, 2)) - assert FiniteSet(1,2,x).intersect(FiniteSet(x)) == FiniteSet(x) + assert FiniteSet(1, 2, x).intersect(FiniteSet(x)) == FiniteSet(x) assert FiniteSet('ham', 'eggs').intersect(FiniteSet(['ham'])) == \ - FiniteSet(['ham']) - assert FiniteSet(1,2,3,4,5).intersect(S.EmptySet) == S.EmptySet + FiniteSet(['ham']) + assert FiniteSet(1, 2, 3, 4, 5).intersect(S.EmptySet) == S.EmptySet - assert Interval(0,5).intersect(FiniteSet(1,3)) == FiniteSet(1,3) - assert Interval(0,1, True, True).intersect(FiniteSet(1)) == S.EmptySet + assert Interval(0, 5).intersect(FiniteSet(1, 3)) == FiniteSet(1, 3) + assert Interval(0, 1, True, True).intersect(FiniteSet(1)) == S.EmptySet assert Union(Interval(0, 1), Interval(2, 3)).intersect(Interval(1, 2)) == \ - Union(Interval(1, 1), Interval(2, 2)) + Union(Interval(1, 1), Interval(2, 2)) assert Union(Interval(0, 1), Interval(2, 3)).intersect(Interval(0, 2)) == \ - Union(Interval(0, 1), Interval(2, 2)) + Union(Interval(0, 1), Interval(2, 2)) assert Union(Interval(0, 1), Interval(2, 3)).intersect(Interval(1, 2, True, True)) == \ - S.EmptySet + S.EmptySet assert Union(Interval(0, 1), Interval(2, 3)).intersect(S.EmptySet) == \ - S.EmptySet - assert Union(Interval(0,5), FiniteSet(['Ham'])).intersect(FiniteSet(2,3,4,5,6)) == \ - FiniteSet(2,3,4,5) + S.EmptySet + assert Union(Interval(0, 5), FiniteSet(['Ham'])).intersect(FiniteSet(2, 3, 4, 5, 6)) == \ + FiniteSet(2, 3, 4, 5) + def test_intersection(): # iterable - i = Intersection(FiniteSet(1,2,3), Interval(2, 5), evaluate=False) + i = Intersection(FiniteSet(1, 2, 3), Interval(2, 5), evaluate=False) assert i.is_iterable assert set(i) == set([S(2), S(3)]) # challenging intervals x = Symbol('x', real=True) i = Intersection(Interval(0, 3), Interval(x, 6)) - assert (5 in i) == False + assert (5 in i) is False raises(TypeError, lambda: 2 in i) # Singleton special cases @@ -200,20 +213,23 @@ # Products line = Interval(0, 5) i = Intersection(line**2, line**3, evaluate=False) - assert (2,2) not in i - assert (2,2,2) not in i + assert (2, 2) not in i + assert (2, 2, 2) not in i raises(ValueError, lambda: list(i)) + def test_interval_subs(): a = Symbol('a', real=True) assert Interval(0, a).subs(a, 2) == Interval(0, 2) assert Interval(a, 0).subs(a, 2) == S.EmptySet + def test_interval_to_mpi(): assert Interval(0, 1).to_mpi() == mpi(0, 1) assert Interval(0, 1, True, False).to_mpi() == mpi(0, 1) - assert type(Interval(0,1).to_mpi()) == type(mpi(0,1)) + assert type(Interval(0, 1).to_mpi()) == type(mpi(0, 1)) + def test_measure(): a = Symbol('a', real=True) @@ -223,77 +239,82 @@ assert Interval(1, a).measure == a - 1 assert Union(Interval(1, 2), Interval(3, 4)).measure == 2 - assert Union(Interval(1, 2), Interval(3, 4), FiniteSet(5,6,7)).measure == 2 + assert Union(Interval(1, 2), Interval(3, 4), FiniteSet(5, 6, 7)).measure \ + == 2 - assert FiniteSet(1,2,oo,a,-oo,-5).measure == 0 + assert FiniteSet(1, 2, oo, a, -oo, -5).measure == 0 assert S.EmptySet.measure == 0 - square = Interval(0,10) * Interval(0,10) - offsetsquare = Interval(5,15) * Interval(5,15) - band = Interval(-oo,oo) * Interval(2,4) + square = Interval(0, 10) * Interval(0, 10) + offsetsquare = Interval(5, 15) * Interval(5, 15) + band = Interval(-oo, oo) * Interval(2, 4) assert square.measure == offsetsquare.measure == 100 - assert (square + offsetsquare).measure == 175 # there is some overlap + assert (square + offsetsquare).measure == 175 # there is some overlap assert (square - offsetsquare).measure == 75 - assert (square * FiniteSet(1,2,3)).measure == 0 + assert (square * FiniteSet(1, 2, 3)).measure == 0 assert (square.intersect(band)).measure == 20 assert (square + band).measure == oo - assert (band * FiniteSet(1,2,3)).measure == nan + assert (band * FiniteSet(1, 2, 3)).measure == nan + def test_subset(): - assert Interval(0, 2).subset(Interval(0, 1)) == True - assert Interval(0, 2).subset(Interval(0, 3)) == False + assert Interval(0, 2).subset(Interval(0, 1)) is True + assert Interval(0, 2).subset(Interval(0, 3)) is False - assert FiniteSet(1,2,3,4).subset(FiniteSet(1,2)) - assert FiniteSet(1,2,3,4).subset(FiniteSet(4,5)) == False - assert Interval(0,2).subset(FiniteSet(1)) - assert Interval(0,2,True,True).subset(FiniteSet(1,2)) == False - assert (Interval(0,2,False,True)+FiniteSet(2,3)).subset( - Interval(1,2)+FiniteSet(3)) + assert FiniteSet(1, 2, 3, 4).subset(FiniteSet(1, 2)) + assert FiniteSet(1, 2, 3, 4).subset(FiniteSet(4, 5)) is False + assert Interval(0, 2).subset(FiniteSet(1)) + assert Interval(0, 2, True, True).subset(FiniteSet(1, 2)) is False + assert (Interval(0, 2, False, True) + FiniteSet(2, 3)).subset( + Interval(1, 2) + FiniteSet(3)) - assert Union(Interval(0, 1), Interval(2, 5)).subset(Interval(3, 4)) == True - assert Union(Interval(0, 1), Interval(2, 5)).subset(Interval(3, 6)) == False + assert Union(Interval(0, 1), Interval(2, 5)).subset(Interval(3, 4)) is True + assert Union(Interval(0, 1), Interval(2, 5)).subset(Interval(3, 6)) is False - assert Interval(0,5).subset(FiniteSet(1,2,3,4)) == True - assert FiniteSet(1,2,3).subset(S.EmptySet) == True + assert Interval(0, 5).subset(FiniteSet(1, 2, 3, 4)) is True + assert FiniteSet(1, 2, 3).subset(S.EmptySet) is True - assert S.EmptySet.subset(Interval(0, 1)) == False - assert S.EmptySet.subset(S.EmptySet) == True + assert S.EmptySet.subset(Interval(0, 1)) is False + assert S.EmptySet.subset(S.EmptySet) is True raises(ValueError, lambda: S.EmptySet.subset(1)) + def test_contains(): - assert Interval(0, 2).contains(1) == True - assert Interval(0, 2).contains(3) == False - assert Interval(0, 2, True, False).contains(0) == False - assert Interval(0, 2, True, False).contains(2) == True - assert Interval(0, 2, False, True).contains(0) == True - assert Interval(0, 2, False, True).contains(2) == False - assert Interval(0, 2, True, True).contains(0) == False - assert Interval(0, 2, True, True).contains(2) == False + assert Interval(0, 2).contains(1) is True + assert Interval(0, 2).contains(3) is False + assert Interval(0, 2, True, False).contains(0) is False + assert Interval(0, 2, True, False).contains(2) is True + assert Interval(0, 2, False, True).contains(0) is True + assert Interval(0, 2, False, True).contains(2) is False + assert Interval(0, 2, True, True).contains(0) is False + assert Interval(0, 2, True, True).contains(2) is False - assert FiniteSet(1,2,3).contains(2) - assert FiniteSet(1,2,Symbol('x')).contains(Symbol('x')) + assert FiniteSet(1, 2, 3).contains(2) + assert FiniteSet(1, 2, Symbol('x')).contains(Symbol('x')) items = [1, 2, S.Infinity, S('ham'), -1.1] fset = FiniteSet(*items) assert all(item in fset for item in items) assert all(fset.contains(item) is True for item in items) - assert Union(Interval(0, 1), Interval(2, 5)).contains(3) == True - assert Union(Interval(0, 1), Interval(2, 5)).contains(6) == False - assert Union(Interval(0, 1), FiniteSet(2, 5)).contains(3) == False + assert Union(Interval(0, 1), Interval(2, 5)).contains(3) is True + assert Union(Interval(0, 1), Interval(2, 5)).contains(6) is False + assert Union(Interval(0, 1), FiniteSet(2, 5)).contains(3) is False + + assert S.EmptySet.contains(1) is False - assert S.EmptySet.contains(1) == False def test_interval_symbolic(): x = Symbol('x') e = Interval(0, 1) - assert e.contains(x) == And(0<=x, x<=1) + assert e.contains(x) == And(0 <= x, x <= 1) raises(TypeError, lambda: x in e) e = Interval(0, 1, True, True) - assert e.contains(x) == And(0= y) == GreaterThan(x, y) - assert (x >= 0) == GreaterThan(x, 0) - assert (x <= y) == LessThan(x, y) - assert (x <= 0) == LessThan(x, 0) + assert (x >= y) == GreaterThan(x, y) + assert (x >= 0) == GreaterThan(x, 0) + assert (x <= y) == LessThan(x, y) + assert (x <= 0) == LessThan(x, 0) - assert (0 <= x) == GreaterThan(x, 0) - assert (0 >= x) == LessThan(x, 0) + assert (0 <= x) == GreaterThan(x, 0) + assert (0 >= x) == LessThan(x, 0) assert (S(0) >= x) == GreaterThan(0, x) assert (S(0) <= x) == LessThan(0, x) - assert (x > y) == StrictGreaterThan(x, y) - assert (x > 0) == StrictGreaterThan(x, 0) - assert (x < y) == StrictLessThan(x, y) - assert (x < 0) == StrictLessThan(x, 0) + assert (x > y) == StrictGreaterThan(x, y) + assert (x > 0) == StrictGreaterThan(x, 0) + assert (x < y) == StrictLessThan(x, y) + assert (x < 0) == StrictLessThan(x, 0) - assert (0 < x) == StrictGreaterThan(x, 0) - assert (0 > x) == StrictLessThan(x, 0) + assert (0 < x) == StrictGreaterThan(x, 0) + assert (0 > x) == StrictLessThan(x, 0) assert (S(0) > x) == StrictGreaterThan(0, x) assert (S(0) < x) == StrictLessThan(0, x) e = x**2 + 4*x + 1 assert (e >= 0) == GreaterThan(e, 0) assert (0 <= e) == GreaterThan(e, 0) - assert (e > 0) == StrictGreaterThan(e, 0) - assert (0 < e) == StrictGreaterThan(e, 0) + assert (e > 0) == StrictGreaterThan(e, 0) + assert (0 < e) == StrictGreaterThan(e, 0) assert (e <= 0) == LessThan(e, 0) assert (0 >= e) == LessThan(e, 0) - assert (e < 0) == StrictLessThan(e, 0) - assert (0 > e) == StrictLessThan(e, 0) + assert (e < 0) == StrictLessThan(e, 0) + assert (0 > e) == StrictLessThan(e, 0) assert (S(0) >= e) == GreaterThan(0, e) assert (S(0) <= e) == LessThan(0, e) - assert (S(0) < e) == StrictLessThan(0, e) - assert (S(0) > e) == StrictGreaterThan(0, e) + assert (S(0) < e) == StrictLessThan(0, e) + assert (S(0) > e) == StrictGreaterThan(0, e) + def test_no_len(): # there should be no len for numbers x = Symbol('x') raises(TypeError, lambda: len(x)) + def test_ineq_unequal(): S = sympify x, y, z = symbols('x,y,z') e = ( - S(-1) >= x, S(-1) >= y, S(-1) >= z, - S(-1) > x, S(-1) > y, S(-1) > z, - S(-1) <= x, S(-1) <= y, S(-1) <= z, - S(-1) < x, S(-1) < y, S(-1) < z, - S(0) >= x, S(0) >= y, S(0) >= z, - S(0) > x, S(0) > y, S(0) > z, - S(0) <= x, S(0) <= y, S(0) <= z, - S(0) < x, S(0) < y, S(0) < z, - S('3/7') >= x, S('3/7') >= y, S('3/7') >= z, - S('3/7') > x, S('3/7') > y, S('3/7') > z, - S('3/7') <= x, S('3/7') <= y, S('3/7') <= z, - S('3/7') < x, S('3/7') < y, S('3/7') < z, - S(1.5) >= x, S(1.5) >= y, S(1.5) >= z, - S(1.5) > x, S(1.5) > y, S(1.5) > z, - S(1.5) <= x, S(1.5) <= y, S(1.5) <= z, - S(1.5) < x, S(1.5) < y, S(1.5) < z, - S(2) >= x, S(2) >= y, S(2) >= z, - S(2) > x, S(2) > y, S(2) > z, - S(2) <= x, S(2) <= y, S(2) <= z, - S(2) < x, S(2) < y, S(2) < z, - x >= -1, y >= -1, z >= -1, - x > -1, y > -1, z > -1, - x <= -1, y <= -1, z <= -1, - x < -1, y < -1, z < -1, - x >= 0, y >= 0, z >= 0, - x > 0, y > 0, z > 0, - x <= 0, y <= 0, z <= 0, - x < 0, y < 0, z < 0, - x >= 1.5, y >= 1.5, z >= 1.5, - x > 1.5, y > 1.5, z > 1.5, - x <= 1.5, y <= 1.5, z <= 1.5, - x < 1.5, y < 1.5, z < 1.5, - x >= 2, y >= 2, z >= 2, - x > 2, y > 2, z > 2, - x <= 2, y <= 2, z <= 2, - x < 2, y < 2, z < 2, - - x >= y, x >= z, y >= x, y >= z, z >= x, z >= y, - x > y, x > z, y > x, y > z, z > x, z > y, - x <= y, x <= z, y <= x, y <= z, z <= x, z <= y, - x < y, x < z, y < x, y < z, z < x, z < y, - - x - pi >= y + z, y - pi >= x + z, z - pi >= x + y, - x - pi > y + z, y - pi > x + z, z - pi > x + y, - x - pi <= y + z, y - pi <= x + z, z - pi <= x + y, - x - pi < y + z, y - pi < x + z, z - pi < x + y, - True, False + S(-1) >= x, S(-1) >= y, S(-1) >= z, + S(-1) > x, S(-1) > y, S(-1) > z, + S(-1) <= x, S(-1) <= y, S(-1) <= z, + S(-1) < x, S(-1) < y, S(-1) < z, + S(0) >= x, S(0) >= y, S(0) >= z, + S(0) > x, S(0) > y, S(0) > z, + S(0) <= x, S(0) <= y, S(0) <= z, + S(0) < x, S(0) < y, S(0) < z, + S('3/7') >= x, S('3/7') >= y, S('3/7') >= z, + S('3/7') > x, S('3/7') > y, S('3/7') > z, + S('3/7') <= x, S('3/7') <= y, S('3/7') <= z, + S('3/7') < x, S('3/7') < y, S('3/7') < z, + S(1.5) >= x, S(1.5) >= y, S(1.5) >= z, + S(1.5) > x, S(1.5) > y, S(1.5) > z, + S(1.5) <= x, S(1.5) <= y, S(1.5) <= z, + S(1.5) < x, S(1.5) < y, S(1.5) < z, + S(2) >= x, S(2) >= y, S(2) >= z, + S(2) > x, S(2) > y, S(2) > z, + S(2) <= x, S(2) <= y, S(2) <= z, + S(2) < x, S(2) < y, S(2) < z, + x >= -1, y >= -1, z >= -1, + x > -1, y > -1, z > -1, + x <= -1, y <= -1, z <= -1, + x < -1, y < -1, z < -1, + x >= 0, y >= 0, z >= 0, + x > 0, y > 0, z > 0, + x <= 0, y <= 0, z <= 0, + x < 0, y < 0, z < 0, + x >= 1.5, y >= 1.5, z >= 1.5, + x > 1.5, y > 1.5, z > 1.5, + x <= 1.5, y <= 1.5, z <= 1.5, + x < 1.5, y < 1.5, z < 1.5, + x >= 2, y >= 2, z >= 2, + x > 2, y > 2, z > 2, + x <= 2, y <= 2, z <= 2, + x < 2, y < 2, z < 2, + + x >= y, x >= z, y >= x, y >= z, z >= x, z >= y, + x > y, x > z, y > x, y > z, z > x, z > y, + x <= y, x <= z, y <= x, y <= z, z <= x, z <= y, + x < y, x < z, y < x, y < z, z < x, z < y, + + x - pi >= y + z, y - pi >= x + z, z - pi >= x + y, + x - pi > y + z, y - pi > x + z, z - pi > x + y, + x - pi <= y + z, y - pi <= x + z, z - pi <= x + y, + x - pi < y + z, y - pi < x + z, z - pi < x + y, + True, False ) left_e = e[:-1] for i, e1 in enumerate( left_e ): - for e2 in e[i +1:]: + for e2 in e[i + 1:]: assert e1 != e2 + def test_Wild_properties(): # these tests only include Atoms - x = Symbol("x") - y = Symbol("y") - p = Symbol("p", positive=True) - k = Symbol("k", integer=True) - n = Symbol("n", integer=True, positive=True) + x = Symbol("x") + y = Symbol("y") + p = Symbol("p", positive=True) + k = Symbol("k", integer=True) + n = Symbol("n", integer=True, positive=True) - given_patterns = [ x, y, p, k, -k, n, -n, sympify(-3), sympify(3), pi, Rational(3,2), I ] + given_patterns = [ x, y, p, k, -k, n, -n, sympify(-3), sympify(3), + pi, Rational(3, 2), I ] integerp = lambda k: k.is_integer positivep = lambda k: k.is_positive @@ -167,7 +175,7 @@ S = Wild("S", properties=[symbolp]) R = Wild("R", properties=[realp]) - Y = Wild("Y", exclude=[x,p,k,n]) + Y = Wild("Y", exclude=[x, p, k, n]) P = Wild("P", properties=[positivep]) K = Wild("K", properties=[integerp]) N = Wild("N", properties=[positivep, integerp]) @@ -175,12 +183,12 @@ given_wildcards = [ S, R, Y, P, K, N ] goodmatch = { - S : (x,y,p,k,n), - R : (p,k,-k,n,-n,-3,3,pi,Rational(3,2)), - Y : (y,-3,3,pi,Rational(3,2),I ), - P : (p, n,3,pi, Rational(3,2)), - K : (k,-k,n,-n,-3,3), - N : (n,3)} + S: (x, y, p, k, n), + R: (p, k, -k, n, -n, -3, 3, pi, Rational(3, 2)), + Y: (y, -3, 3, pi, Rational(3, 2), I ), + P: (p, n, 3, pi, Rational(3, 2)), + K: (k, -k, n, -n, -3, 3), + N: (n, 3)} for A in given_wildcards: for pat in given_patterns: @@ -188,7 +196,8 @@ if pat in goodmatch[A]: assert d[A] in goodmatch[A] else: - assert d == None + assert d is None + @XFAIL def test_symbols_each_char(): @@ -209,10 +218,12 @@ # now test the actual output warnings.filterwarnings("ignore") assert symbols(['wx', 'yz'], each_char=True) == [(w, x), (y, z)] - assert all(w.is_Function for w in flatten(symbols(['wx', 'yz'], each_char=True, cls=Function))) + assert all(w.is_Function for w in flatten( + symbols(['wx', 'yz'], each_char=True, cls=Function))) assert symbols('xyz', each_char=True) == (x, y, z) assert symbols('x,', each_char=True) == (x,) - assert symbols('x y z', each_char=True) == symbols('x,y,z', each_char=True) == (x, y, z) + assert symbols('x y z', each_char=True) == symbols( + 'x,y,z', each_char=True) == (x, y, z) assert symbols('xyz', each_char=False) == Symbol('xyz') a, b = symbols('x y', each_char=False, real=True) assert a.is_real and b.is_real @@ -220,10 +231,12 @@ assert symbols('x0:0', each_char=False) == () assert symbols('x0:1', each_char=False) == (Symbol('x0'),) - assert symbols('x0:3', each_char=False) == (Symbol('x0'), Symbol('x1'), Symbol('x2')) + assert symbols( + 'x0:3', each_char=False) == (Symbol('x0'), Symbol('x1'), Symbol('x2')) assert symbols('x:0', each_char=False) == () assert symbols('x:1', each_char=False) == (Symbol('x0'),) - assert symbols('x:3', each_char=False) == (Symbol('x0'), Symbol('x1'), Symbol('x2')) + assert symbols( + 'x:3', each_char=False) == (Symbol('x0'), Symbol('x1'), Symbol('x2')) assert symbols('x1:1', each_char=False) == () assert symbols('x1:2', each_char=False) == (Symbol('x1'),) assert symbols('x1:3', each_char=False) == (Symbol('x1'), Symbol('x2')) @@ -235,6 +248,7 @@ # warnings.catch_warnings context manager. # See http://docs.python.org/library/warnings#testing-warnings. + def test_symbols(): x = Symbol('x') y = Symbol('y') @@ -316,7 +330,56 @@ assert symbols('a:d,x:z') == (a, b, c, d, x, y, z) assert symbols(('a:d', 'x:z')) == ((a, b, c, d), (x, y, z)) + aa = Symbol('aa') + ab = Symbol('ab') + ac = Symbol('ac') + ad = Symbol('ad') + + assert symbols('aa:d') == (aa, ab, ac, ad) + assert symbols('aa:d,x:z') == (aa, ab, ac, ad, x, y, z) + assert symbols(('aa:d','x:z')) == ((aa, ab, ac, ad), (x, y, z)) + + + # issue 3576 + def sym(s): + return str(symbols(s)) + assert sym('a0:4') == '(a0, a1, a2, a3)' + assert sym('a2:4,b1:3') == '(a2, a3, b1, b2)' + assert sym('a1(2:4)') == '(a12, a13)' + assert sym(('a0:2.0:2')) == '(a0.0, a0.1, a1.0, a1.1)' + assert sym(('aa:cz')) == '(aaz, abz, acz)' + assert sym('aa:c0:2') == '(aa0, aa1, ab0, ab1, ac0, ac1)' + assert sym('aa:ba:b') == '(aaa, aab, aba, abb)' + assert sym('a:3b') == '(a0b, a1b, a2b)' + assert sym('a-1:3b') == '(a-1b, a-2b)' + assert sym('a:2\,:2' + chr(0)) == '(a0,0%s, a0,1%s, a1,0%s, a1,1%s)' % ( + (chr(0),)*4) + assert sym('x(:a:3)') == '(x(a0), x(a1), x(a2))' + assert sym('x(:c):1') == '(xa0, xb0, xc0)' + assert sym('x((:a)):3') == '(x(a)0, x(a)1, x(a)2)' + assert sym('x(:a:3') == '(x(a0, x(a1, x(a2)' + assert sym(':2') == '(0, 1)' + assert sym(':b') == '(a, b)' + assert sym(':b:2') == '(a0, a1, b0, b1)' + assert sym(':2:2') == '(00, 01, 10, 11)' + assert sym(':b:b') == '(aa, ab, ba, bb)' + + raises(ValueError, lambda: symbols(':')) + raises(ValueError, lambda: symbols('a:')) + raises(ValueError, lambda: symbols('::')) + raises(ValueError, lambda: symbols('a::')) + raises(ValueError, lambda: symbols(':a:')) + raises(ValueError, lambda: symbols('::a')) + + def test_call(): f = Symbol('f') assert f(2) raises(TypeError, lambda: Wild('x')(1)) + +def test_unicode(): + xu = Symbol('x') + x = Symbol('x') + assert x == xu + + raises(TypeError, lambda: Symbol(1)) diff -Nru python3-sympy-0.7.2/sympy/core/tests/test_sympify.py python3-sympy-0.7.3/sympy/core/tests/test_sympify.py --- python3-sympy-0.7.2/sympy/core/tests/test_sympify.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/core/tests/test_sympify.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,22 +1,26 @@ from sympy import Symbol, exp, Integer, Float, sin, cos, log, Poly, Lambda, \ - Function, I, S, sqrt, srepr, Rational, Tuple + Function, I, S, sqrt, srepr, Rational, Tuple, Matrix, Interval from sympy.abc import x, y -from sympy.core.sympify import sympify, _sympify, SympifyError +from sympy.core.sympify import sympify, _sympify, SympifyError, kernS from sympy.core.decorators import _sympifyit from sympy.utilities.pytest import XFAIL, raises from sympy.utilities.decorator import conserve_mpmath_dps from sympy.geometry import Point, Line from sympy.functions.combinatorial.factorials import factorial, factorial2 +from sympy.abc import _clash, _clash1, _clash2 +from sympy.core.compatibility import HAS_GMPY from sympy import mpmath + def test_439(): v = sympify("exp(x)") assert v == exp(x) assert type(v) == type(exp(x)) assert str(type(v)) == str(type(exp(x))) + def test_sympify1(): assert sympify("x") == Symbol("x") assert sympify(" x") == Symbol("x") @@ -34,26 +38,33 @@ assert sympify('.0[526315789473684210]') == Rational(1, 19) assert sympify('.034[56]') == Rational(1711, 49500) # options to make reals into rationals - assert sympify('1.22[345]', rational=1) == \ - 1 + Rational(22, 100) + Rational(345, 99900) - assert sympify('2/2.6', rational=1) == Rational(10, 13) - assert sympify('2.6/2', rational=1) == Rational(13, 10) - assert sympify('2.6e2/17', rational=1) == Rational(260, 17) - assert sympify('2.6e+2/17', rational=1) == Rational(260, 17) - assert sympify('2.6e-2/17', rational=1) == Rational(26, 17000) - assert sympify('2.1+3/4', rational=1) == Rational(21, 10) + Rational(3, 4) - assert sympify('2.234456', rational=1) == Rational(279307, 125000) - assert sympify('2.234456e23', rational=1) == 223445600000000000000000 - assert sympify('2.234456e-23', rational=1) == Rational(279307, 12500000000000000000000000000) - assert sympify('-2.234456e-23', rational=1) == Rational(-279307, 12500000000000000000000000000) - assert sympify('12345678901/17', rational=1) == Rational(12345678901, 17) - assert sympify('1/.3 + x', rational=1) == Rational(10, 3) + x + assert sympify('1.22[345]', rational=True) == \ + 1 + Rational(22, 100) + Rational(345, 99900) + assert sympify('2/2.6', rational=True) == Rational(10, 13) + assert sympify('2.6/2', rational=True) == Rational(13, 10) + assert sympify('2.6e2/17', rational=True) == Rational(260, 17) + assert sympify('2.6e+2/17', rational=True) == Rational(260, 17) + assert sympify('2.6e-2/17', rational=True) == Rational(26, 17000) + assert sympify('2.1+3/4', rational=True) == \ + Rational(21, 10) + Rational(3, 4) + assert sympify('2.234456', rational=True) == Rational(279307, 125000) + assert sympify('2.234456e23', rational=True) == 223445600000000000000000 + assert sympify('2.234456e-23', rational=True) == \ + Rational(279307, 12500000000000000000000000000) + assert sympify('-2.234456e-23', rational=True) == \ + Rational(-279307, 12500000000000000000000000000) + assert sympify('12345678901/17', rational=True) == \ + Rational(12345678901, 17) + assert sympify('1/.3 + x', rational=True) == Rational(10, 3) + x # make sure longs in fractions work - assert sympify('222222222222/11111111111') == Rational(222222222222, 11111111111) + assert sympify('222222222222/11111111111') == \ + Rational(222222222222, 11111111111) # ... even if they come from repetend notation assert sympify('1/.2[123456789012]') == Rational(333333333333, 70781892967) # ... or from high precision reals - assert sympify('.1234567890123456', rational=1) == Rational(19290123283179, 156250000000000) + assert sympify('.1234567890123456', rational=True) == \ + Rational(19290123283179, 156250000000000) + def test_sympify_Fraction(): try: @@ -64,33 +75,41 @@ value = sympify(fractions.Fraction(101, 127)) assert value == Rational(101, 127) and type(value) is Rational + def test_sympify_gmpy(): - try: - import gmpy - except ImportError: - pass - else: + if HAS_GMPY: + if HAS_GMPY == 2: + import gmpy2 as gmpy + elif HAS_GMPY == 1: + import gmpy + value = sympify(gmpy.mpz(1000001)) assert value == Integer(1000001) and type(value) is Integer value = sympify(gmpy.mpq(101, 127)) assert value == Rational(101, 127) and type(value) is Rational + @conserve_mpmath_dps def test_sympify_mpmath(): value = sympify(mpmath.mpf(1.0)) assert value == Float(1.0) and type(value) is Float mpmath.mp.dps = 12 - assert sympify(mpmath.pi).epsilon_eq(Float("3.14159265359"), Float("1e-12")) is True - assert sympify(mpmath.pi).epsilon_eq(Float("3.14159265359"), Float("1e-13")) is False + assert sympify( + mpmath.pi).epsilon_eq(Float("3.14159265359"), Float("1e-12")) is True + assert sympify( + mpmath.pi).epsilon_eq(Float("3.14159265359"), Float("1e-13")) is False mpmath.mp.dps = 6 - assert sympify(mpmath.pi).epsilon_eq(Float("3.14159"), Float("1e-5")) is True - assert sympify(mpmath.pi).epsilon_eq(Float("3.14159"), Float("1e-6")) is False + assert sympify( + mpmath.pi).epsilon_eq(Float("3.14159"), Float("1e-5")) is True + assert sympify( + mpmath.pi).epsilon_eq(Float("3.14159"), Float("1e-6")) is False assert sympify(mpmath.mpc(1.0 + 2.0j)) == Float(1.0) + Float(2.0)*I + def test_sympify2(): class A: def _sympy_(self): @@ -98,10 +117,11 @@ a = A() - assert _sympify(a)== x**3 + assert _sympify(a) == x**3 assert sympify(a) == x**3 assert a == x**3 + def test_sympify3(): assert sympify("x**3") == x**3 assert sympify("x^3") == x**3 @@ -110,30 +130,35 @@ raises(SympifyError, lambda: _sympify('x**3')) raises(SympifyError, lambda: _sympify('1/2')) + def test_sympify_keywords(): raises(SympifyError, lambda: sympify('if')) raises(SympifyError, lambda: sympify('for')) raises(SympifyError, lambda: sympify('while')) raises(SympifyError, lambda: sympify('lambda')) + def test_sympify_float(): assert sympify("1e-64") != 0 assert sympify("1e-20000") != 0 + def test_sympify_bool(): """Test that sympify accepts boolean values and that output leaves them unchanged""" - assert sympify(True) == True - assert sympify(False)== False + assert sympify(True) is True + assert sympify(False) is False + def test_sympyify_iterables(): ans = [Rational(3, 10), Rational(1, 5)] - assert sympify(['.3', '.2'], rational=1) == ans - assert sympify(set(['.3', '.2']), rational=1) == set(ans) - assert sympify(tuple(['.3', '.2']), rational=1) == Tuple(*ans) + assert sympify(['.3', '.2'], rational=True) == ans + assert sympify(set(['.3', '.2']), rational=True) == set(ans) + assert sympify(tuple(['.3', '.2']), rational=True) == Tuple(*ans) assert sympify(dict(x=0, y=1)) == {x: 0, y: 1} assert sympify(['1', '2', ['3', '4']]) == [S(1), S(2), [S(3), S(4)]] + def test_sympify4(): class A: def _sympy_(self): @@ -141,38 +166,42 @@ a = A() - assert _sympify(a)**3== x**3 + assert _sympify(a)**3 == x**3 assert sympify(a)**3 == x**3 assert a == x + def test_sympify_text(): assert sympify('some') == Symbol('some') assert sympify('core') == Symbol('core') - assert sympify('True') == True - assert sympify('False') == False + assert sympify('True') is True + assert sympify('False') is False assert sympify('Poly') == Poly assert sympify('sin') == sin + def test_sympify_function(): - assert sympify('factor(x**2-1, x)') == -(1-x)*(x+1) + assert sympify('factor(x**2-1, x)') == -(1 - x)*(x + 1) assert sympify('sin(pi/2)*cos(pi)') == -Integer(1) + def test_sympify_poly(): - p = Poly(x**2+x+1, x) + p = Poly(x**2 + x + 1, x) assert _sympify(p) is p assert sympify(p) is p + def test_sympify_factorial(): assert sympify('x!') == factorial(x) - assert sympify('(x+1)!') == factorial(x+1) + assert sympify('(x+1)!') == factorial(x + 1) assert sympify('(1 + y*(x + 1))!') == factorial(1 + y*(x + 1)) assert sympify('(1 + y*(x + 1)!)^2') == (1 + y*factorial(x + 1))**2 assert sympify('y*x!') == y*factorial(x) assert sympify('x!!') == factorial2(x) - assert sympify('(x+1)!!') == factorial2(x+1) + assert sympify('(x+1)!!') == factorial2(x + 1) assert sympify('(1 + y*(x + 1))!!') == factorial2(1 + y*(x + 1)) assert sympify('(1 + y*(x + 1)!!)^2') == (1 + y*factorial2(x + 1))**2 assert sympify('y*x!!') == y*factorial2(x) @@ -184,6 +213,7 @@ raises(SympifyError, lambda: sympify("(!)")) raises(SympifyError, lambda: sympify("x!!!")) + def test_sage(): # how to effectivelly test for the _sage_() method without having SAGE # installed? @@ -192,49 +222,54 @@ assert hasattr(sin(x), "_sage_") assert hasattr(cos(x), "_sage_") assert hasattr(x**2, "_sage_") - assert hasattr(x+y, "_sage_") + assert hasattr(x + y, "_sage_") assert hasattr(exp(x), "_sage_") assert hasattr(log(x), "_sage_") + def test_bug496(): - a_ = sympify("a_") - _a = sympify("_a") + assert sympify("a_") == Symbol("a_") + assert sympify("_a") == Symbol("_a") + @XFAIL def test_lambda(): x = Symbol('x') assert sympify('lambda: 1') == Lambda((), 1) assert sympify('lambda x: 2*x') == Lambda(x, 2*x) - assert sympify('lambda x, y: 2*x+y') == Lambda([x, y], 2*x+y) + assert sympify('lambda x, y: 2*x+y') == Lambda([x, y], 2*x + y) + def test_lambda_raises(): with raises(SympifyError): _sympify('lambda: 1') + def test_sympify_raises(): raises(SympifyError, lambda: sympify("fx)")) + def test__sympify(): x = Symbol('x') f = Function('f') # positive _sympify - assert _sympify(x) is x - assert _sympify(f) is f - assert _sympify(1) == Integer(1) - assert _sympify(0.5) == Float("0.5") - assert _sympify(1+1j) == 1.0 + I*1.0 + assert _sympify(x) is x + assert _sympify(f) is f + assert _sympify(1) == Integer(1) + assert _sympify(0.5) == Float("0.5") + assert _sympify(1 + 1j) == 1.0 + I*1.0 class A: def _sympy_(self): return Integer(5) a = A() - assert _sympify(a) == Integer(5) + assert _sympify(a) == Integer(5) # negative _sympify raises(SympifyError, lambda: _sympify('1')) - raises(SympifyError, lambda: _sympify([1,2,3])) + raises(SympifyError, lambda: _sympify([1, 2, 3])) def test_sympifyit(): @@ -243,7 +278,7 @@ @_sympifyit('b', NotImplemented) def add(a, b): - return a+b + return a + b assert add(x, 1) == x + 1 assert add(x, 0.5) == x + Float('0.5') @@ -251,10 +286,9 @@ assert add(x, '1') == NotImplemented - @_sympifyit('b') def add_raises(a, b): - return a+b + return a + b assert add_raises(x, 1) == x + 1 assert add_raises(x, 0.5) == x + Float('0.5') @@ -262,6 +296,7 @@ raises(SympifyError, lambda: add_raises(x, '1')) + def test_int_float(): class F1_1(object): def __float__(self): @@ -349,41 +384,48 @@ assert abs(_sympify(f1_1b) - 1.1) < 1e-5 assert abs(_sympify(f1_1c) - 1.1) < 1e-5 + def test_issue1034(): a = sympify('Integer(4)') assert a == Integer(4) assert a.is_Integer + def test_issue883(): a = [3, 2.0] assert sympify(a) == [Integer(3), Float(2.0)] assert sympify(tuple(a)) == Tuple(Integer(3), Float(2.0)) assert sympify(set(a)) == set([Integer(3), Float(2.0)]) + def test_S_sympify(): assert S(1)/2 == sympify(1)/2 assert (-2)**(S(1)/2) == sqrt(2)*I + def test_issue1689(): - assert srepr(S(1.0+0J)) == srepr(S(1.0)) == srepr(Float(1.0)) - assert srepr(Float(1)) != srepr(Float(1.0)) + assert srepr(S(1.0 + 0J)) == srepr(S(1.0)) == srepr(Float(1.0)) + def test_issue1699_None(): assert S(None) is None + def test_issue3218(): assert sympify("x+\ny") == x + y + def test_issue1889_builtins(): C = Symbol('C') vars = {} vars['C'] = C exp1 = sympify('C') - assert exp1 == C # Make sure it did not get mixed up with sympy.C + assert exp1 == C # Make sure it did not get mixed up with sympy.C exp2 = sympify('C', vars) - assert exp2 == C # Make sure it did not get mixed up with sympy.C + assert exp2 == C # Make sure it did not get mixed up with sympy.C + def test_geometry(): p = sympify(Point(0, 1)) @@ -391,15 +433,40 @@ L = sympify(Line(p, (1, 0))) assert L == Line((0, 1), (1, 0)) and type(L) == Line -def test_no_autosimplify_into_Mul(): - s = '-1 - 2*(-(-x + 1/x)/(x*(x - 1/x)**2) - 1/(x*(x - 1/x)))' - def clean(s): - return ''.join(str(s).split()) + +def test_kernS(): + s = '-1 - 2*(-(-x + 1/x)/(x*(x - 1/x)**2) - 1/(x*(x - 1/x)))' + # when 1497 is fixed, this no longer should pass: the expression + # should be unchanged assert -1 - 2*(-(-x + 1/x)/(x*(x - 1/x)**2) - 1/(x*(x - 1/x))) == -1 # sympification should not allow the constant to enter a Mul # or else the structure can change dramatically - ss = S(s) - assert ss != 1 and ss.simplify() == -1 - s = '-1 - 2*(-(-x + 1/x)/(x*(x - 1/x)**2) - 1/(x*(x - 1/x)))'.replace('x', '_kern') - ss = S(s) - assert ss != 1 and ss.simplify() == -1 + ss = kernS(s) + assert ss != -1 and ss.simplify() == -1 + s = '-1 - 2*(-(-x + 1/x)/(x*(x - 1/x)**2) - 1/(x*(x - 1/x)))'.replace( + 'x', '_kern') + ss = kernS(s) + assert ss != -1 and ss.simplify() == -1 + # issue 3588 + assert kernS('Interval(-1,-2 - 4*(-3))') == Interval(-1, 10) + assert kernS('_kern') == Symbol('_kern') + assert kernS('E**-(x)') == exp(-x) + e = 2*(x + y)*y + assert kernS(['2*(x + y)*y', ('2*(x + y)*y',)]) == [e, (e,)] + assert kernS('-(2*sin(x)**2 + 2*sin(x)*cos(x))*y/2') == \ + -y*(2*sin(x)**2 + 2*sin(x)*cos(x))/2 + + +def test_issue_3441_3453(): + assert S('[[1/3,2], (2/5,)]') == [[Rational(1, 3), 2], (Rational(2, 5),)] + assert S('[[2/6,2], (2/4,)]') == [[Rational(1, 3), 2], (Rational(1, 2),)] + assert S('[[[2*(1)]]]') == [[[2]]] + assert S('Matrix([2*(1)])') == Matrix([2]) + +def test_issue_2497(): + assert str(S("Q & C", locals=_clash1)) == 'And(C, Q)' + assert str(S('pi(x)', locals=_clash2)) == 'pi(x)' + assert str(S('pi(C, Q)', locals=_clash)) == 'pi(C, Q)' + locals = {} + exec("from sympy.abc import Q, C", locals) + assert str(S('C&Q', locals)) == 'And(C, Q)' diff -Nru python3-sympy-0.7.2/sympy/core/tests/test_trace.py python3-sympy-0.7.3/sympy/core/tests/test_trace.py --- python3-sympy-0.7.2/sympy/core/tests/test_trace.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/core/tests/test_trace.py 2013-07-13 17:53:32.000000000 +0000 @@ -2,12 +2,13 @@ from sympy.core.trace import Tr from sympy.utilities.pytest import raises + def test_trace_new(): a, b, c, d, Y = symbols('a b c d Y') A, B, C, D = symbols('A B C D', commutative=False) - assert Tr(a+b) == a + b - assert Tr(A+B) == Tr(A) + Tr(B) + assert Tr(a + b) == a + b + assert Tr(A + B) == Tr(A) + Tr(B) #check trace args not implicitly permuted assert Tr(C*D*A*B).args[0].args == (C, D, A, B) @@ -26,7 +27,7 @@ assert isinstance(Tr(pow(A, a)), Tr) #Matrix - M = Matrix([[1,1], [2,2]]) + M = Matrix([[1, 1], [2, 2]]) assert Tr(M) == 3 ##test indices in different forms @@ -53,11 +54,11 @@ assert t.args[1] == Tuple(1, 2) #trace indices test - t = Tr((A+B), [2]) + t = Tr((A + B), [2]) assert t.args[0].args[1] == Tuple(2) and t.args[1].args[1] == Tuple(2) - t = Tr(a*A, [2,3]) - assert t.args[1].args[1] == Tuple(2,3) + t = Tr(a*A, [2, 3]) + assert t.args[1].args[1] == Tuple(2, 3) #class with trace method defined #to simulate numpy objects @@ -71,12 +72,14 @@ raises(ValueError, lambda: Tr()) raises(ValueError, lambda: Tr(A, 1, 2)) + def test_trace_doit(): a, b, c, d = symbols('a b c d') A, B, C, D = symbols('A B C D', commutative=False) #TODO: needed while testing reduced density operations, etc. + def test_permute(): A, B, C, D, E, F, G = symbols('A B C D E F G', commutative=False) t = Tr(A*B*C*D*E*F*G) @@ -92,8 +95,8 @@ assert t.permute(-5).args[0].args == (F, G, A, B, C, D, E) assert t.permute(-8).args[0].args == t.permute(-1).args[0].args - t = Tr((A+B)*(B*B)*C*D) - assert t.permute(2).args[0].args == (C, D, (A+B), (B**2)) + t = Tr((A + B)*(B*B)*C*D) + assert t.permute(2).args[0].args == (C, D, (A + B), (B**2)) t1 = Tr(A*B) t2 = t1.permute(1) diff -Nru python3-sympy-0.7.2/sympy/core/tests/test_truediv.py python3-sympy-0.7.3/sympy/core/tests/test_truediv.py --- python3-sympy-0.7.2/sympy/core/tests/test_truediv.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/core/tests/test_truediv.py 2013-07-13 17:53:32.000000000 +0000 @@ -4,40 +4,45 @@ from sympy import Rational, Symbol, Float + def test_truediv(): assert 1/2 != 0 assert Rational(1)/2 != 0 + def dotest(s): x = Symbol("x") y = Symbol("y") l = [ - Rational(2), - Float("1.3"), - x, - y, - pow(x,y)*y, - 5, - 5.5 + Rational(2), + Float("1.3"), + x, + y, + pow(x, y)*y, + 5, + 5.5 ] for x in l: for y in l: - s(x,y) + s(x, y) + return True + def test_basic(): - def s(a,b): + def s(a, b): x = a x = +a x = -a - x = a+b - x = a-b + x = a + b + x = a - b x = a*b x = a/b x = a**b - dotest(s) + assert dotest(s) + def test_ibasic(): - def s(a,b): + def s(a, b): x = a x += b x = a @@ -46,4 +51,4 @@ x *= b x = a x /= b - dotest(s) + assert dotest(s) diff -Nru python3-sympy-0.7.2/sympy/core/tests/test_var.py python3-sympy-0.7.3/sympy/core/tests/test_var.py --- python3-sympy-0.7.2/sympy/core/tests/test_var.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/core/tests/test_var.py 2013-07-13 17:53:32.000000000 +0000 @@ -4,45 +4,51 @@ from sympy.utilities.pytest import raises # make z1 with call-depth = 1 -def make_z1(): + + +def _make_z1(): var("z1") # make z2 with call-depth = 2 + + def __make_z2(): var("z2") -def make_z2(): + +def _make_z2(): __make_z2() def test_var(): var("a") - assert a == Symbol("a") + assert a == Symbol("a") var("b bb cc zz _x") - assert b == Symbol("b") + assert b == Symbol("b") assert bb == Symbol("bb") assert cc == Symbol("cc") assert zz == Symbol("zz") assert _x == Symbol("_x") - v = var(['d','e','fg']) - assert d == Symbol('d') - assert e == Symbol('e') + v = var(['d', 'e', 'fg']) + assert d == Symbol('d') + assert e == Symbol('e') assert fg == Symbol('fg') # check return value - assert v == [d, e, fg] + assert v == [d, e, fg] # see if var() really injects into global namespace raises(NameError, lambda: z1) - make_z1() + _make_z1() assert z1 == Symbol("z1") raises(NameError, lambda: z2) - make_z2() + _make_z2() assert z2 == Symbol("z2") + def test_var_return(): raises(ValueError, lambda: var('')) v2 = var('q') @@ -51,6 +57,7 @@ assert v2 == Symbol('q') assert v3 == (Symbol('q'), Symbol('p')) + def test_var_accepts_comma(): v1 = var('x y z') v2 = var('x,y,z') @@ -59,10 +66,12 @@ assert v1 == v2 assert v1 == v3 + def test_var_keywords(): var('x y', real=True) assert x.is_real and y.is_real + def test_var_cls(): f = var('f', cls=Function) diff -Nru python3-sympy-0.7.2/sympy/core/tests/test_wester.py python3-sympy-0.7.3/sympy/core/tests/test_wester.py --- python3-sympy-0.7.2/sympy/core/tests/test_wester.py 1970-01-01 00:00:00.000000000 +0000 +++ python3-sympy-0.7.3/sympy/core/tests/test_wester.py 2013-07-13 17:53:32.000000000 +0000 @@ -0,0 +1,863 @@ +""" Tests from Michael Wester's 1999 paper "Review of CAS mathematical +capabilities". + +http://www.math.unm.edu/~wester/cas/book/Wester.pdf +See also http://math.unm.edu/~wester/cas_review.html for detailed output of each +tested system. +""" + +from sympy import (Rational, symbols, factorial, sqrt, log, exp, oo, product, + binomial, rf, pi, gamma, igcd, factorint, nsimplify, radsimp, combsimp, + npartitions, totient, primerange, factor, simplify, gcd, resultant, expand, + I, trigsimp, tan, sin, cos, diff, nan, limit, EulerGamma, polygamma, + bernoulli, assoc_legendre, Function, re, im, DiracDelta, chebyshevt, atan, + sinh, cosh, floor, ceiling, solve, asinh, LambertW, N, apart, sqrtdenest, + factorial2, powdenest, Mul, S, mpmath, ZZ, Poly, expand_func) + +from sympy.functions.combinatorial.numbers import stirling +from sympy.integrals.deltafunctions import deltaintegrate +from sympy.utilities.pytest import XFAIL, slow +from sympy.utilities.iterables import partitions +from sympy.mpmath import mpi, mpc +from sympy.physics.quantum import Commutator + +R = Rational +x, y, z = symbols('x y z') +i, j, k, l, m, n = symbols('i j k l m n', integer=True) +f = Function('f') +g = Function('g') + +# A. Boolean Logic and Quantifier Elimination +# Not implemented. + +# B. Set Theory +# Not implemented. + +# C. Numbers + + +def test_C1(): + assert (factorial(50) == + 30414093201713378043612608166064768844377641568960512000000000000) + + +def test_C2(): + assert (factorint(factorial(50)) == {2: 47, 3: 22, 5: 12, 7: 8, + 11: 4, 13: 3, 17: 2, 19: 2, 23: 2, 29: 1, 31: 1, 37: 1, + 41: 1, 43: 1, 47: 1}) + + +def test_C3(): + assert (factorial2(10), factorial2(9)) == (3840, 945) + + +# Base conversions; not really implemented by sympy +# Whatever. Take credit! +def test_C4(): + assert 0xABC == 2748 + + +def test_C5(): + assert 123 == int('234', 7) + + +def test_C6(): + assert int('677', 8) == int('1BF', 16) == 447 + + +def test_C7(): + assert log(32768, 8) == 5 + + +def test_C8(): + # Modular multiplicative inverse. Would be nice if divmod could do this. + assert ZZ.invert(5, 7) == 3 + assert ZZ.invert(5, 6) == 5 + + +def test_C9(): + assert igcd(igcd(1776, 1554), 5698) == 74 + + +def test_C10(): + x = 0 + for n in range(2, 11): + x += R(1, n) + assert x == R(4861, 2520) + + +def test_C11(): + assert R(1, 7) == S('0.[142857]') + + +def test_C12(): + assert R(7, 11) * R(22, 7) == 2 + + +def test_C13(): + test = R(10, 7) * (1 + R(29, 1000)) ** R(1, 3) + good = 3 ** R(1, 3) + assert test == good + + +def test_C14(): + assert nsimplify(sqrt(2*sqrt(3) + 4)) == 1 + sqrt(3) + + +def test_C15(): + test = nsimplify(sqrt(14 + 3*sqrt(3 + 2*sqrt(5 - 12*sqrt(3 - 2*sqrt(2)))))) + good = sqrt(2) + 3 + assert test == good + + +def test_C16(): + test = sqrtdenest(sqrt(10 + 2*sqrt(6) + 2*sqrt(10) + 2*sqrt(15))) + good = sqrt(2) + sqrt(3) + sqrt(5) + assert test == good + + +def test_C17(): + test = nsimplify((sqrt(3) + sqrt(2)) / (sqrt(3) - sqrt(2))) + good = 5 + 2*sqrt(6) + assert test == good + + +def test_C18(): + assert nsimplify(sqrt(-2 + sqrt(-5)) * sqrt(-2 - sqrt(-5))) == 3 + + +@XFAIL +def test_C19(): + assert radsimp(nsimplify((90 + 35*sqrt(7)) ** R(1, 3))) == 3 + sqrt(7) + + +def test_C20(): + inside = (135 + 78*sqrt(3)) + test = nsimplify((inside**R(2, 3) + 3) * sqrt(3) / inside**R(1, 3)) + assert test == 12 + + +def test_C21(): + assert nsimplify((41 + 29*sqrt(2)) ** R(1, 5)) == 1 + sqrt(2) + + +@XFAIL +def test_C22(): + test = nsimplify(((6 - 4*sqrt(2))*log(3 - 2*sqrt(2)) + (3 - 2*sqrt(2))*log(17 + - 12*sqrt(2)) + 32 - 24*sqrt(2)) / (48*sqrt(2) - 72)) + good = sqrt(2)/3 - log(sqrt(2) - 1)/3 + assert test == good + + +def test_C23(): + assert 2 * oo - 3 == oo + + +@XFAIL +def test_C24(): + raise NotImplementedError("2**aleph_null == aleph_1") + +# D. Numerical Analysis + + +def test_D1(): + assert 0.0 / sqrt(2) == 0.0 + + +def test_D2(): + assert str(exp(-1000000).evalf()) == '3.29683147808856e-434295' + + +def test_D3(): + assert exp(pi*sqrt(163)).evalf(50).num.ae(262537412640768744) + + +def test_D4(): + assert floor(R(-5, 3)) == -2 + assert ceiling(R(-5, 3)) == -1 + + +@XFAIL +def test_D5(): + raise NotImplementedError("cubic_spline([1, 2, 4, 5], [1, 4, 2, 3], x)(3) == 27/8") + + +@XFAIL +def test_D6(): + raise NotImplementedError("translate sum(a[i]*x**i, (i,1,n)) to FORTRAN") + + +@XFAIL +def test_D7(): + raise NotImplementedError("translate sum(a[i]*x**i, (i,1,n)) to C") + + +@XFAIL +def test_D8(): + # One way is to cheat by converting the sum to a string, + # and replacing the '[' and ']' with ''. + # E.g., horner(S(str(_).replace('[','').replace(']',''))) + raise NotImplementedError("apply Horner's rule to sum(a[i]*x**i, (i,1,5))") + + +@XFAIL +def test_D9(): + raise NotImplementedError("translate D8 to FORTRAN") + + +@XFAIL +def test_D10(): + raise NotImplementedError("translate D8 to C") + + +@XFAIL +def test_D11(): + #Is there a way to use count_ops? + raise NotImplementedError("flops(sum(product(f[i][k], (i,1,k)), (k,1,n)))") + + +@XFAIL +def test_D12(): + assert (mpi(-4, 2) * x + mpi(1, 3)) ** 2 == mpi(-8, 16)*x**2 + mpi(-24, 12)*x + mpi(1, 9) + + +@XFAIL +def test_D13(): + raise NotImplementedError("discretize a PDE: diff(f(x,t),t) == diff(diff(f(x,t),x),x)") + +# E. Statistics +# See scipy; all of this is numerical. + +# F. Combinatorial Theory. + + +def test_F1(): + assert rf(x, 3) == x*(1 + x)*(2 + x) + + +def test_F2(): + assert expand_func(binomial(n, 3)) == n*(n - 1)*(n - 2)/6 + + +@XFAIL +def test_F3(): + assert combsimp(2**n * factorial(n) * factorial2(2*n - 1)) == factorial(2*n) + + +@XFAIL +def test_F4(): + assert combsimp((2**n * factorial(n) * product(2*k - 1, (k, 1, n)))) == factorial(2*n) + + +@XFAIL +def test_F5(): + assert gamma(n + R(1, 2)) / sqrt(pi) / factorial(n) == factorial(2*n)/2**(2*n)/factorial(n)**2 + + +def test_F6(): + partTest = [p.copy() for p in partitions(4)] + partDesired = [{4: 1}, {1: 1, 3: 1}, {2: 2}, {1: 2, 2:1}, {1: 4}] + assert partTest == partDesired + + +def test_F7(): + assert npartitions(4) == 5 + + +def test_F8(): + assert stirling(5, 2, signed=True) == -50 # if signed, then kind=1 + + +def test_F9(): + assert totient(1776) == 576 + +# G. Number Theory + + +def test_G1(): + assert list(primerange(999983, 1000004)) == [999983, 1000003] + + +@XFAIL +def test_G2(): + raise NotImplementedError("find the primitive root of 191 == 19") + + +@XFAIL +def test_G3(): + raise NotImplementedError("(a+b)**p mod p == a**p + b**p mod p; p prime") + +# ... G20 Modular equations and continued fractions are not implemented. + +# H. Algebra + + +def test_H1(): + assert simplify(2*2**n) == simplify(2**(n + 1)) + assert powdenest(2*2**n) == simplify(2**(n + 1)) + + +@XFAIL +def test_H2(): + assert 4 * 2**n == 2 ** (n + 2) + + +@XFAIL +def test_H3(): + assert (-1)**(n*(n + 1)) == 1 + + +def test_H4(): + expr = factor(6*x - 10) + assert type(expr) is Mul + assert expr.args[0] == 2 + assert expr.args[1] == 3*x - 5 + +p1 = 64*x**34 - 21*x**47 - 126*x**8 - 46*x**5 - 16*x**60 - 81 +p2 = 72*x**60 - 25*x**25 - 19*x**23 - 22*x**39 - 83*x**52 + 54*x**10 + 81 +q = 34*x**19 - 25*x**16 + 70*x**7 + 20*x**3 - 91*x - 86 + + +def test_H5(): + assert gcd(p1, p2, x) == 1 + + +def test_H6(): + assert gcd(expand(p1 * q), expand(p2 * q)) == q + + +def test_H7(): + p1 = 24*x*y**19*z**8 - 47*x**17*y**5*z**8 + 6*x**15*y**9*z**2 - 3*x**22 + 5 + p2 = 34*x**5*y**8*z**13 + 20*x**7*y**7*z**7 + 12*x**9*y**16*z**4 + 80*y**14*z + assert gcd(p1, p2, x, y, z) == 1 + + +def test_H8(): + p1 = 24*x*y**19*z**8 - 47*x**17*y**5*z**8 + 6*x**15*y**9*z**2 - 3*x**22 + 5 + p2 = 34*x**5*y**8*z**13 + 20*x**7*y**7*z**7 + 12*x**9*y**16*z**4 + 80*y**14*z + q = 11*x**12*y**7*z**13 - 23*x**2*y**8*z**10 + 47*x**17*y**5*z**8 + assert gcd(p1 * q, p2 * q, x, y, z) == q + + +def test_H9(): + p1 = 2*x**(n + 4) - x**(n + 2) + p2 = 4*x**(n + 1) + 3*x**n + assert gcd(p1, p2) == x**n + + +def test_H10(): + p1 = 3*x**4 + 3*x**3 + x**2 - x - 2 + p2 = x**3 - 3*x**2 + x + 5 + assert resultant(p1, p2, x) == 0 + + +def test_H11(): + assert resultant(p1 * q, p2 * q, x) == 0 + + +def test_H12(): + num = x**2 - 4 + den = x**2 + 4*x + 4 + assert simplify(num/den) == (x - 2)/(x + 2) + + +@XFAIL +def test_H13(): + assert simplify((exp(x) - 1) / (exp(x/2) + 1)) == exp(x/2) - 1 + + +def test_H14(): + p = (x + 1) ** 20 + ep = expand(p) + assert ep == (1 + 20*x + 190*x**2 + 1140*x**3 + 4845*x**4 + 15504*x**5 + + 38760*x**6 + 77520*x**7 + 125970*x**8 + 167960*x**9 + 184756*x**10 + + 167960*x**11 + 125970*x**12 + 77520*x**13 + 38760*x**14 + 15504*x**15 + + 4845*x**16 + 1140*x**17 + 190*x**18 + 20*x**19 + x**20) + dep = diff(ep, x) + assert dep == (20 + 380*x + 3420*x**2 + 19380*x**3 + 77520*x**4 + + 232560*x**5 + 542640*x**6 + 1007760*x**7 + 1511640*x**8 + 1847560*x**9 + + 1847560*x**10 + 1511640*x**11 + 1007760*x**12 + 542640*x**13 + + 232560*x**14 + 77520*x**15 + 19380*x**16 + 3420*x**17 + 380*x**18 + + 20*x**19) + assert factor(dep) == 20*(1 + x)**19 + + +def test_H15(): + assert simplify((Mul(*[x - r for r in solve(x**3 + x**2 - 7)]))) == x**3 + x**2 - 7 + + +def test_H16(): + assert factor(x**100 - 1) == ((x - 1)*(x + 1)*(x**2 + 1)*(x**4 - x**3 + + x**2 - x + 1)*(x**4 + x**3 + x**2 + x + 1)*(x**8 - x**6 + x**4 + - x**2 + 1)*(x**20 - x**15 + x**10 - x**5 + 1)*(x**20 + x**15 + x**10 + + x**5 + 1)*(x**40 - x**30 + x**20 - x**10 + 1)) + + +@slow +def test_H17(): + assert simplify(factor(expand(p1 * p2)) - p1*p2) == 0 + + +@XFAIL +def test_H18(): + # Factor over complex rationals. + test = factor(4*x**4 + 8*x**3 + 77*x**2 + 18*x + 53) + good = (2*x + 3*I)*(2*x - 3*I)*(x + 1 - 4*I)(x + 1 + 4*I) + assert test == good + + +def test_H19(): + a = symbols('a') + # The idea is to let a**2 == 2, then solve 1/(a-1). Answer is a+1") + assert Poly(a - 1).invert(Poly(a**2 - 2)) == a + 1 + + +@XFAIL +def test_H20(): + raise NotImplementedError("let a**2==2; (x**3 + (a-2)*x**2 - " + + "(2*a+3)*x - 3*a) / (x**2-2) = (x**2 - 2*x - 3) / (x-a)") + + +@XFAIL +def test_H21(): + raise NotImplementedError("evaluate (b+c)**4 assuming b**3==2, c**2==3. \ + Answer is 2*b + 8*c + 18*b**2 + 12*b*c + 9") + + +def test_H22(): + assert factor(x**4 - 3*x**2 + 1, modulus=5) == (x - 2)**2 * (x + 2)**2 + + +def test_H23(): + f = x**11 + x + 1 + g = (x**2 + x + 1) * (x**9 - x**8 + x**6 - x**5 + x**3 - x**2 + 1) + assert factor(f, modulus=65537) == g + + +@XFAIL +def test_H24(): + raise NotImplementedError("factor x**4 - 3*x**2 + 1, GoldenRatio") + + +@slow +def test_H25(): + e = (x - 2*y**2 + 3*z**3) ** 20 + assert factor(expand(e)) == e + + +@slow +def test_H26(): + g = expand((sin(x) - 2*cos(y)**2 + 3*tan(z)**3)**20) + assert factor(g, expand=False) == (-sin(x) + 2*cos(y)**2 - 3*tan(z)**3)**20 + + +@slow +def test_H27(): + f = 24*x*y**19*z**8 - 47*x**17*y**5*z**8 + 6*x**15*y**9*z**2 - 3*x**22 + 5 + g = 34*x**5*y**8*z**13 + 20*x**7*y**7*z**7 + 12*x**9*y**16*z**4 + 80*y**14*z + h = -2*z*y**7 \ + *(6*x**9*y**9*z**3 + 10*x**7*z**6 + 17*y*x**5*z**12 + 40*y**7) \ + *(3*x**22 + 47*x**17*y**5*z**8 - 6*x**15*y**9*z**2 - 24*x*y**19*z**8 - 5) + assert factor(expand(f*g)) == h + + +@XFAIL +def test_H28(): + raise NotImplementedError("expand ((1 - c**2)**5 * (1 - s**2)**5 * " + + "(c**2 + s**2)**10) with c**2 + s**2 = 1. Answer is c**10*s**10.") + + +@XFAIL +def test_H29(): + assert factor(4*x**2 - 21*x*y + 20*y**2, modulus=3) == (x + y)*(x - y) + + +def test_H30(): + test = factor(x**3 + y**3, extension=sqrt(-3)) + answer = (x + y)*(x + y*(-R(1, 2) - sqrt(3)/2*I))*(x + y*(-R(1, 2) + sqrt(3)/2*I)) + assert answer == test + + +def test_H31(): + f = (x**2 + 2*x + 3)/(x**3 + 4*x**2 + 5*x + 2) + g = 2 / (x + 1)**2 - 2 / (x + 1) + 3 / (x + 2) + assert apart(f) == g + + +@XFAIL +def test_H32(): # issue 3459 + raise NotImplementedError("[A*B*C - (A*B*C)**(-1)]*A*C*B (product \ + of a non-commuting product and its inverse)") + + +def test_H33(): + A, B, C = symbols('A, B, C', commutatative=False) + assert (Commutator(A, Commutator(B, C)) + + Commutator(B, Commutator(C, A)) + + Commutator(C, Commutator(A, B))).doit().expand() == 0 + + +# I. Trigonometry + +@XFAIL +def test_I1(): + assert tan(7*pi/10) == -sqrt(1 + 2/sqrt(5)) + + +@XFAIL +def test_I2(): + assert sqrt((1 + cos(6))/2) == -cos(3) + + +@XFAIL +def test_I3(): + assert cos(n*pi) + sin((4*n - 1)*pi/2) == (-1)**n - 1 + + +@XFAIL +def test_I4(): + assert cos(pi*cos(n*pi)) + sin(pi/2*cos(n*pi)) == (-1)**n - 1 + + +@XFAIL +def test_I5(): + assert sin((n**5/5 + n**4/2 + n**3/3 - n/30) * pi) == 0 + + +@XFAIL +def test_I6(): + raise NotImplementedError("assuming -3*pi0 else obj + return Mul(*c_part)*obj if len(c_part) > 0 else obj elif isinstance(expr, Pow): if (_is_scalar(expr.args[0]) and - _is_scalar(expr.args[1])): + _is_scalar(expr.args[1])): return expr else: return Expr.__new__(cls, expr, indices) @@ -148,7 +150,7 @@ return Expr.__new__(cls, expr, indices) - def doit(self,**kwargs): + def doit(self, **kwargs): """ Perform the trace operation. #TODO: Current version ignores the indices set for partial trace. @@ -172,7 +174,6 @@ # and implementation improved. return True - #TODO: Review if the permute method is needed # and if it needs to return a new instance def permute(self, pos): @@ -210,4 +211,4 @@ else: args = [self.args[0]] - return tuple(args) + (self.args[1], ) + return tuple(args) + (self.args[1], ) diff -Nru python3-sympy-0.7.2/sympy/diffgeom/__init__.py python3-sympy-0.7.3/sympy/diffgeom/__init__.py --- python3-sympy-0.7.2/sympy/diffgeom/__init__.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/diffgeom/__init__.py 2013-07-13 17:53:32.000000000 +0000 @@ -1 +1,9 @@ -from .diffgeom import * +from .diffgeom import ( + BaseCovarDerivativeOp, BaseScalarField, BaseVectorField, Commutator, + contravariant_order, CoordSystem, CovarDerivativeOp, covariant_order, + Differential, intcurve_diffequ, intcurve_series, LieDerivative, + Manifold, metric_to_Christoffel_1st, metric_to_Christoffel_2nd, + metric_to_Ricci_components, metric_to_Riemann_components, Patch, + Point, TensorProduct, twoform_to_matrix, vectors_in_basis, + WedgeProduct, +) diff -Nru python3-sympy-0.7.2/sympy/diffgeom/diffgeom.py python3-sympy-0.7.3/sympy/diffgeom/diffgeom.py --- python3-sympy-0.7.2/sympy/diffgeom/diffgeom.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/diffgeom/diffgeom.py 2013-07-13 17:53:32.000000000 +0000 @@ -13,6 +13,7 @@ # TODO too often one needs to call doit or simplify on the output, check the # tests and find out why + class Manifold(Basic): """Object representing a mathematical manifold. @@ -30,7 +31,7 @@ # other Patch instance on the same manifold. def _latex(self, printer, *args): - return r'\mathbb{%s}' % self.name + return r'\mathrm{%s}' % self.name class Patch(Basic): @@ -48,6 +49,7 @@ ========= Define a Manifold and a Patch on that Manifold: + >>> from sympy.diffgeom import Manifold, Patch >>> m = Manifold('M', 3) >>> p = Patch('P', m) @@ -98,27 +100,32 @@ >>> polar.connect_to(rect, [r, theta], [r*cos(theta), r*sin(theta)]) >>> polar.coord_tuple_transform_to(rect, [0, 2]) - [0] - [0] + Matrix([ + [0], + [0]]) >>> polar.coord_tuple_transform_to(rect, [2, pi/2]) - [0] - [2] + Matrix([ + [0], + [2]]) >>> rect.coord_tuple_transform_to(polar, [1, 1]) - [sqrt(2)] - [ pi/4] + Matrix([ + [sqrt(2)], + [ pi/4]]) Calculate the jacobian of the polar to cartesian transformation: >>> polar.jacobian(rect, [r, theta]) - [cos(theta), -r*sin(theta)] - [sin(theta), r*cos(theta)] + Matrix([ + [cos(theta), -r*sin(theta)], + [sin(theta), r*cos(theta)]]) Define a point using coordinates in one of the coordinate systems: >>> p = polar.point([1, 3*pi/4]) >>> rect.point_to_coords(p) - [-sqrt(2)/2] - [ sqrt(2)/2] + Matrix([ + [-sqrt(2)/2], + [ sqrt(2)/2]]) Define a basis scalar field (i.e. a coordinate function), that takes a point and returns its coordinates. It is an instance of ``BaseScalarField``. @@ -134,15 +141,15 @@ >>> v_x = rect.base_vector(0) >>> x = rect.coord_function(0) - >>> v_x(x)(p) + >>> v_x(x) 1 - >>> v_x(v_x(x))(p) + >>> v_x(v_x(x)) 0 Define a basis oneform field: >>> dx = rect.base_oneform(0) - >>> dx(v_x)(p) + >>> dx(v_x) 1 If you provide a list of names the fields will print nicely: @@ -164,7 +171,7 @@ super(CoordSystem, self).__init__() self.name = name if not names: - names = ['%s_%d'%(name, i) for i in range(patch.dim)] + names = ['%s_%d' % (name, i) for i in range(patch.dim)] self._names = names self.patch = patch self._args = self.name, self.patch @@ -225,7 +232,8 @@ # format instead of wondering dict/tuple/whatever. # As it is at the moment this is an ugly hack for changing the format inv_from = [i.as_dummy() for i in from_coords] - inv_to = solve([t[0]-t[1] for t in zip(inv_from, to_exprs)], list(from_coords)) + inv_to = solve( + [t[0] - t[1] for t in zip(inv_from, to_exprs)], list(from_coords)) if isinstance(inv_to, dict): inv_to = [inv_to[fc] for fc in from_coords] else: @@ -249,7 +257,8 @@ def jacobian(self, to_sys, coords): """Return the jacobian matrix of a transformation.""" - with_dummies = self.coord_tuple_transform_to(to_sys, self._dummies).jacobian(self._dummies) + with_dummies = self.coord_tuple_transform_to( + to_sys, self._dummies).jacobian(self._dummies) return with_dummies.subs(list(zip(self._dummies, coords))) ########################################################################## @@ -322,7 +331,7 @@ def _latex(self, printer, *args): return r'\mathrm{%s}^{\mathrm{%s}}_{%s}' % ( - self.name, self.patch.name, self.patch.manifold._latex(printer, *args)) + self.name, self.patch.name, self.patch.manifold._latex(printer, *args)) class Point(Basic): @@ -354,11 +363,13 @@ >>> p = Point(polar, [r, 3*pi/4]) >>> p.coords() - [ r] - [3*pi/4] + Matrix([ + [ r], + [3*pi/4]]) >>> p.coords(rect) - [-sqrt(2)*r/2] - [ sqrt(2)*r/2] + Matrix([ + [-sqrt(2)*r/2], + [ sqrt(2)*r/2]]) """ def __init__(self, coord_sys, coords): @@ -425,13 +436,13 @@ >>> fx = BaseScalarField(rect, 0) >>> fy = BaseScalarField(rect, 1) - >>> (fx**2+fy**2)(point) + >>> (fx**2+fy**2).rcall(point) r0**2 >>> g = Function('g') >>> ftheta = BaseScalarField(polar, 1) >>> fg = g(ftheta-pi) - >>> fg(point) + >>> fg.rcall(point) g(-pi) """ @@ -458,7 +469,8 @@ return simplify(coords[self._index]).doit() # XXX Workaround for limitations on the content of args - free_symbols=set() + free_symbols = set() + def doit(self): return self @@ -500,9 +512,9 @@ >>> g = Function('g') >>> s_field = g(R2.x, R2.y) - >>> s_field(point_r) + >>> s_field.rcall(point_r) g(x0, y0) - >>> s_field(point_p) + >>> s_field.rcall(point_p) g(r0*cos(theta0), r0*sin(theta0)) Vector field: @@ -512,11 +524,11 @@ / d \| |-----(g(x, xi_2))|| \dxi_2 /|xi_2=y - >>> pprint(v(s_field)(point_r).doit()) + >>> pprint(v(s_field).rcall(point_r).doit()) d ---(g(x0, y0)) dy0 - >>> pprint(v(s_field)(point_p).doit()) + >>> pprint(v(s_field).rcall(point_p).doit()) / d \| |-----(g(r0*cos(theta0), xi_2))|| \dxi_2 /|xi_2=r0*sin(theta0) @@ -544,7 +556,8 @@ # First step: e_x(x+r**2) -> e_x(x) + 2*r*e_x(r) d_var = self._coord_sys._dummy # TODO: you need a real dummy function for the next line - d_funcs = [Function('_#_%s' % i)(d_var) for i, b in enumerate(base_scalars)] + d_funcs = [Function('_#_%s' % i)(d_var) for i, + b in enumerate(base_scalars)] d_result = scalar_field.subs(list(zip(base_scalars, d_funcs))) d_result = d_result.diff(d_var) @@ -560,7 +573,7 @@ # Remove the dummies result = d_result.subs(list(zip(d_funcs, base_scalars))) result = result.subs(list(zip(coords, self._coord_sys.coord_functions()))) - return result.doit() # XXX doit for the Subs instances + return result.doit() # XXX doit for the Subs instances class Commutator(Expr): @@ -599,8 +612,9 @@ #""" def __new__(cls, v1, v2): if (covariant_order(v1) or contravariant_order(v1) != 1 - or covariant_order(v2) or contravariant_order(v2) != 1): - raise ValueError('Only commutators of vector fields are supported.') + or covariant_order(v2) or contravariant_order(v2) != 1): + raise ValueError( + 'Only commutators of vector fields are supported.') if v1 == v2: return Zero() coord_sys = set.union(*[v.atoms(CoordSystem) for v in (v1, v2)]) @@ -609,7 +623,8 @@ # actually evaluate the commutator. if all(isinstance(v, BaseVectorField) for v in (v1, v2)): return Zero() - bases_1, bases_2 = [list(v.atoms(BaseVectorField)) for v in (v1, v2)] + bases_1, bases_2 = [list(v.atoms(BaseVectorField)) + for v in (v1, v2)] coeffs_1 = [v1.expand().coeff(b) for b in bases_1] coeffs_2 = [v2.expand().coeff(b) for b in bases_2] res = 0 @@ -684,7 +699,8 @@ """ def __new__(cls, form_field): if contravariant_order(form_field): - raise ValueError('A vector field was supplied as an argument to Differential.') + raise ValueError( + 'A vector field was supplied as an argument to Differential.') if isinstance(form_field, Differential): return Zero() else: @@ -718,9 +734,9 @@ for a in vector_fields): raise ValueError('The arguments supplied to Differential should be vector fields or Nones.') k = len(vector_fields) - if k==1: + if k == 1: if vector_fields[0]: - return vector_fields[0](self._form_field) + return vector_fields[0].rcall(self._form_field) return self else: # For higher form it is more complicated: @@ -732,14 +748,14 @@ v = vector_fields ret = 0 for i in range(k): - t = v[i](f(*v[:i]+v[i+1:])) + t = v[i].rcall(f.rcall(*v[:i] + v[i + 1:])) ret += (-1)**i*t - for j in range(i+1,k): + for j in range(i + 1, k): c = Commutator(v[i], v[j]) - if c: # TODO this is ugly - the Commutator can be Zero and + if c: # TODO this is ugly - the Commutator can be Zero and # this causes the next line to fail - t = f(*(c,)+v[:i]+v[i+1:j]+v[j+1:]) - ret += (-1)**(i+j)*t + t = f.rcall(*(c,) + v[:i] + v[i + 1:j] + v[j + 1:]) + ret += (-1)**(i + j)*t return ret @@ -779,19 +795,19 @@ >>> TP = TensorProduct >>> metric = TP(R2.dx, R2.dx) + 3*TP(R2.dy, R2.dy) - >>> metric(R2.e_y, None) + >>> metric.rcall(R2.e_y, None) 3*dy Or automatically pad the args with ``None``s. - >>> metric(R2.e_y) + >>> metric.rcall(R2.e_y) 3*dy """ def __new__(cls, *args): if any(contravariant_order(a) for a in args): raise ValueError('A vector field was supplied as an argument to TensorProduct.') - scalar = Mul(*[m for m in args if covariant_order(m)==0]) + scalar = Mul(*[m for m in args if covariant_order(m) == 0]) forms = [m for m in args if covariant_order(m)] if forms: if len(forms) == 1: @@ -818,11 +834,11 @@ tot_order = covariant_order(self) tot_args = len(v_fields) if tot_args != tot_order: - v_fields = list(v_fields) + [None]*(tot_order-tot_args) + v_fields = list(v_fields) + [None]*(tot_order - tot_args) orders = [covariant_order(f) for f in self._args] - indices = [sum(orders[:i+1]) for i in range(len(orders)-1)] - v_fields = [v_fields[i:j] for i, j in zip([0]+indices, indices+[None])] - multipliers = [t[0](*t[1]) for t in zip(self._args, v_fields)] + indices = [sum(orders[:i + 1]) for i in range(len(orders) - 1)] + v_fields = [v_fields[i:j] for i, j in zip([0] + indices, indices + [None])] + multipliers = [t[0].rcall(*t[1]) for t in zip(self._args, v_fields)] return TensorProduct(*multipliers) def _latex(self, printer, *args): @@ -860,7 +876,7 @@ 0 """ - # TODO the caclulation of signatures is slow + # TODO the calculation of signatures is slow # TODO you do not need all these permutations (neither the prefactor) def __call__(self, *vector_fields): """Apply on a list of vector_fields. @@ -869,7 +885,8 @@ orders = (covariant_order(e) for e in self.args) mul = 1/Mul(*(factorial(o) for o in orders)) perms = permutations(vector_fields) - perms_par = (Permutation(p).signature() for p in permutations(list(range(len(vector_fields))))) + perms_par = (Permutation( + p).signature() for p in permutations(list(range(len(vector_fields))))) tensor_prod = TensorProduct(*self.args) return mul*Add(*[tensor_prod(*p[0])*p[1] for p in zip(perms, perms_par)]) @@ -891,12 +908,12 @@ if contravariant_order(v_field) != 1 or covariant_order(v_field): raise ValueError('Lie derivatives are defined only wrt vector fields.' ' The supplied argument was not a vector field.') - if expr_form_ord>0: + if expr_form_ord > 0: return super(LieDerivative, cls).__new__(cls, v_field, expr) if expr.atoms(BaseVectorField): return Commutator(v_field, expr) else: - return v_field(expr) + return v_field.rcall(expr) def __init__(self, v_field, expr): super(LieDerivative, self).__init__() @@ -908,7 +925,7 @@ v = self._v_field expr = self._expr lead_term = v(expr(*args)) - rest = Add(*[Mul(*args[:i] + (Commutator(v, args[i]),) + args[i+1:]) + rest = Add(*[Mul(*args[:i] + (Commutator(v, args[i]),) + args[i + 1:]) for i in range(len(args))]) return lead_term - rest @@ -959,7 +976,8 @@ # First step: replace all vectors with something susceptible to # derivation and do the derivation # TODO: you need a real dummy function for the next line - d_funcs = [Function('_#_%s' % i)(wrt_scalar) for i, b in enumerate(vectors)] + d_funcs = [Function('_#_%s' % i)(wrt_scalar) for i, + b in enumerate(vectors)] d_result = field.subs(list(zip(vectors, d_funcs))) d_result = wrt_vector(d_result) @@ -971,12 +989,12 @@ for v in vectors: d = Add(*[(self._christoffel[k][wrt_vector._index][v._index] *v._coord_sys.base_vector(k)) - for k in range(v._coord_sys.dim)]) + for k in range(v._coord_sys.dim)]) derivs.append(d) to_subs = [wrt_vector(d) for d in d_funcs] result = d_result.subs(list(zip(to_subs, derivs))) - return result #TODO .doit() # XXX doit for the Subs instances + return result # TODO .doit() # XXX doit for the Subs instances class CovarDerivativeOp(Expr): @@ -1013,8 +1031,8 @@ def __call__(self, field): vectors = list(self._wrt.atoms(BaseVectorField)) base_ops = [BaseCovarDerivativeOp(v._coord_sys, v._index, self._christoffel) - for v in vectors] - return self._wrt.subs(list(zip(vectors, base_ops)))(field) + for v in vectors] + return self._wrt.subs(list(zip(vectors, base_ops))).rcall(field) def _latex(self, printer, *args): return r'\mathbb{\nabla}_{%s}' % printer._print(self._wrt) @@ -1073,44 +1091,54 @@ Calculate the series: >>> intcurve_series(vector_field, t, start_point, n=3) - [t + x] - [ y] + Matrix([ + [t + x], + [ y]]) Or get the elements of the expansion in a list: >>> series = intcurve_series(vector_field, t, start_point, n=3, coeffs=True) >>> series[0] - [x] - [y] + Matrix([ + [x], + [y]]) >>> series[1] - [t] - [0] + Matrix([ + [t], + [0]]) >>> series[2] - [0] - [0] + Matrix([ + [0], + [0]]) The series in the polar coordinate system: - >>> series = intcurve_series(vector_field, t, start_point, n=3, coord_sys=R2_p, coeffs=True) + >>> series = intcurve_series(vector_field, t, start_point, + ... n=3, coord_sys=R2_p, coeffs=True) >>> series[0] - [sqrt(x**2 + y**2)] - [ atan2(y, x)] + Matrix([ + [sqrt(x**2 + y**2)], + [ atan2(y, x)]]) >>> series[1] - [t*x/sqrt(x**2 + y**2)] - [ -t*y/(x**2 + y**2)] + Matrix([ + [t*x/sqrt(x**2 + y**2)], + [ -t*y/(x**2 + y**2)]]) >>> series[2] - [t**2*(-x**2/(x**2 + y**2)**(3/2) + 1/sqrt(x**2 + y**2))/2] - [ t**2*x*y/(x**2 + y**2)**2] + Matrix([ + [t**2*(-x**2/(x**2 + y**2)**(3/2) + 1/sqrt(x**2 + y**2))/2], + [ t**2*x*y/(x**2 + y**2)**2]]) """ if contravariant_order(vector_field) != 1 or covariant_order(vector_field): raise ValueError('The supplied field was not a vector field.') + def iter_vfield(scalar_field, i): """Return `vector_field` called `i` times on `scalar_field`.""" - return reduce(lambda s, v: v(s), [vector_field,]*i, scalar_field) + return reduce(lambda s, v: v.rcall(s), [vector_field, ]*i, scalar_field) + def taylor_terms_per_coord(coord_function): """Return the series for one of the coordinates.""" - return [param**i*iter_vfield(coord_function, i)(start_point)/factorial(i) + return [param**i*iter_vfield(coord_function, i).rcall(start_point)/factorial(i) for i in range(n)] coord_sys = coord_sys if coord_sys else start_point._coord_sys coord_functions = coord_sys.coord_functions() @@ -1189,12 +1217,13 @@ if contravariant_order(vector_field) != 1 or covariant_order(vector_field): raise ValueError('The supplied field was not a vector field.') coord_sys = coord_sys if coord_sys else start_point._coord_sys - gammas = [Function('f_%d'%i)(param) for i in range(start_point._coord_sys.dim)] + gammas = [Function('f_%d' % i)(param) for i in range( + start_point._coord_sys.dim)] arbitrary_p = Point(coord_sys, gammas) coord_functions = coord_sys.coord_functions() - equations = [simplify(diff(cf(arbitrary_p), param) - vector_field(cf)(arbitrary_p)) + equations = [simplify(diff(cf.rcall(arbitrary_p), param) - vector_field.rcall(cf).rcall(arbitrary_p)) for cf in coord_functions] - init_cond = [simplify(cf(arbitrary_p).subs(param,0) - cf(start_point)) + init_cond = [simplify(cf.rcall(arbitrary_p).subs(param, 0) - cf.rcall(start_point)) for cf in coord_functions] return equations, init_cond @@ -1251,13 +1280,14 @@ return 0 if not not_zero else not_zero[0] elif isinstance(expr, Pow): if covariant_order(expr.base) or covariant_order(expr.exp): - raise ValueError('Misformed expression containing a power of a vector.') + raise ValueError( + 'Misformed expression containing a power of a vector.') return 0 elif isinstance(expr, BaseVectorField): return 1 elif not _strict or expr.atoms(BaseScalarField): return 0 - else: # If it does not contain anything related to the diffgeom module and it is _strict + else: # If it does not contain anything related to the diffgeom module and it is _strict return -1 @@ -1293,7 +1323,8 @@ return 0 if not not_zero else not_zero[0] elif isinstance(expr, Pow): if covariant_order(expr.base) or covariant_order(expr.exp): - raise ValueError('Misformed expression containing a power of a form.') + raise ValueError( + 'Misformed expression containing a power of a form.') return 0 elif isinstance(expr, Differential): return covariant_order(*expr.args) + 1 @@ -1301,7 +1332,7 @@ return sum(covariant_order(a) for a in expr.args) elif not _strict or expr.atoms(BaseScalarField): return 0 - else: # If it does not contain anything related to the diffgeom module and it is _strict + else: # If it does not contain anything related to the diffgeom module and it is _strict return -1 @@ -1351,14 +1382,17 @@ >>> from sympy.diffgeom import twoform_to_matrix, TensorProduct >>> TP = TensorProduct >>> twoform_to_matrix(TP(R2.dx, R2.dx) + TP(R2.dy, R2.dy)) - [1, 0] - [0, 1] + Matrix([ + [1, 0], + [0, 1]]) >>> twoform_to_matrix(R2.x*TP(R2.dx, R2.dx) + TP(R2.dy, R2.dy)) - [x, 0] - [0, 1] + Matrix([ + [x, 0], + [0, 1]]) >>> twoform_to_matrix(TP(R2.dx, R2.dx) + TP(R2.dy, R2.dy) - TP(R2.dx, R2.dy)/2) - [ 1, 0] - [-1/2, 1] + Matrix([ + [ 1, 0], + [-1/2, 1]]) """ if covariant_order(expr) != 2 or contravariant_order(expr): @@ -1371,8 +1405,8 @@ coord_sys = coord_sys.pop() vectors = coord_sys.base_vectors() expr = expr.expand() - matrix_content = [[expr(v1, v2) for v1 in vectors] - for v2 in vectors] + matrix_content = [[expr.rcall(v1, v2) for v1 in vectors] + for v2 in vectors] return Matrix(matrix_content) @@ -1396,14 +1430,16 @@ """ matrix = twoform_to_matrix(expr) if not matrix.is_symmetric(): - raise ValueError('The two-form representing the metric is not symmetric.') + raise ValueError( + 'The two-form representing the metric is not symmetric.') coord_sys = expr.atoms(CoordSystem).pop() - deriv_matrices = [matrix.applyfunc(lambda a: d(a)) for d in coord_sys.base_vectors()] + deriv_matrices = [matrix.applyfunc(lambda a: d(a)) + for d in coord_sys.base_vectors()] indices = list(range(coord_sys.dim)) - christoffel = [[[(deriv_matrices[k][i,j] + deriv_matrices[j][i,k] - deriv_matrices[i][j,k])/2 + christoffel = [[[(deriv_matrices[k][i, j] + deriv_matrices[j][i, k] - deriv_matrices[i][j, k])/2 for k in indices] - for j in indices] - for i in indices] + for j in indices] + for i in indices] return list_to_tuple_rec(christoffel) @@ -1439,10 +1475,10 @@ dums = coord_sys._dummies matrix = matrix.subs(list(zip(s_fields, dums))).inv().subs(list(zip(dums, s_fields))) # XXX end of workaround - christoffel = [[[Add(*[matrix[i,l]*ch_1st[l][j][k] for l in indices]) + christoffel = [[[Add(*[matrix[i, l]*ch_1st[l][j][k] for l in indices]) for k in indices] - for j in indices] - for i in indices] + for j in indices] + for i in indices] return list_to_tuple_rec(christoffel) @@ -1461,14 +1497,17 @@ >>> from sympy.diffgeom import metric_to_Riemann_components, TensorProduct >>> TP = TensorProduct >>> metric_to_Riemann_components(TP(R2.dx, R2.dx) + TP(R2.dy, R2.dy)) - ((((0, 0), (0, 0)), ((0, 0), (0, 0))), (((0, 0), (0, 0)), ((0, 0), (0, 0)))) + ((((0, 0), (0, 0)), ((0, 0), (0, 0))), (((0, 0), (0, 0)), ((0, 0), + (0, 0)))) - >>> non_trivial_metric = exp(2*R2.r)*TP(R2.dr, R2.dr) + R2.r**2*TP(R2.dtheta, R2.dtheta) + >>> non_trivial_metric = exp(2*R2.r)*TP(R2.dr, R2.dr) + \ + R2.r**2*TP(R2.dtheta, R2.dtheta) >>> non_trivial_metric exp(2*r)*TensorProduct(dr, dr) + r**2*TensorProduct(dtheta, dtheta) >>> riemann = metric_to_Riemann_components(non_trivial_metric) >>> riemann[0] - (((0, 0), (0, 0)), ((0, -exp(-2*r)*r + 2*r*exp(-2*r)), (exp(-2*r)*r - 2*r*exp(-2*r), 0))) + (((0, 0), (0, 0)), ((0, -exp(-2*r)*r + 2*r*exp(-2*r)), + (exp(-2*r)*r - 2*r*exp(-2*r), 0))) >>> riemann[1] (((0, -r**(-1)), (r**(-1), 0)), ((0, 0), (0, 0))) @@ -1477,25 +1516,25 @@ coord_sys = expr.atoms(CoordSystem).pop() indices = list(range(coord_sys.dim)) deriv_ch = [[[[d(ch_2nd[i][j][k]) - for d in coord_sys.base_vectors()] - for k in indices] - for j in indices] - for i in indices] + for d in coord_sys.base_vectors()] + for k in indices] + for j in indices] + for i in indices] riemann_a = [[[[deriv_ch[rho][sig][nu][mu] - deriv_ch[rho][sig][mu][nu] - for nu in indices] - for mu in indices] - for sig in indices] + for nu in indices] + for mu in indices] + for sig in indices] for rho in indices] riemann_b = [[[[Add(*[ch_2nd[rho][l][mu]*ch_2nd[l][sig][nu] - ch_2nd[rho][l][nu]*ch_2nd[l][sig][mu] for l in indices]) - for nu in indices] - for mu in indices] - for sig in indices] - for rho in indices] + for nu in indices] + for mu in indices] + for sig in indices] + for rho in indices] riemann = [[[[riemann_a[rho][sig][mu][nu] + riemann_b[rho][sig][mu][nu] - for nu in indices] + for nu in indices] for mu in indices] - for sig in indices] - for rho in indices] + for sig in indices] + for rho in indices] return list_to_tuple_rec(riemann) @@ -1516,7 +1555,8 @@ >>> metric_to_Ricci_components(TP(R2.dx, R2.dx) + TP(R2.dy, R2.dy)) ((0, 0), (0, 0)) - >>> non_trivial_metric = exp(2*R2.r)*TP(R2.dr, R2.dr) + R2.r**2*TP(R2.dtheta, R2.dtheta) + >>> non_trivial_metric = exp(2*R2.r)*TP(R2.dr, R2.dr) + \ + R2.r**2*TP(R2.dtheta, R2.dtheta) >>> non_trivial_metric exp(2*r)*TensorProduct(dr, dr) + r**2*TensorProduct(dtheta, dtheta) >>> metric_to_Ricci_components(non_trivial_metric) #TODO why is this not simpler @@ -1527,6 +1567,6 @@ coord_sys = expr.atoms(CoordSystem).pop() indices = list(range(coord_sys.dim)) ricci = [[Add(*[riemann[k][i][k][j] for k in indices]) - for j in indices] - for i in indices] + for j in indices] + for i in indices] return list_to_tuple_rec(ricci) diff -Nru python3-sympy-0.7.2/sympy/diffgeom/rn.py python3-sympy-0.7.3/sympy/diffgeom/rn.py --- python3-sympy-0.7.2/sympy/diffgeom/rn.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/diffgeom/rn.py 2013-07-13 17:53:32.000000000 +0000 @@ -56,7 +56,8 @@ R3_s = CoordSystem('spherical', R3_origin, ['r', 'theta', 'phi']) # Connecting the coordinate charts. -x, y, z, rho, psi, r, theta, phi = [Dummy(s) for s in ['x', 'y', 'z', 'rho', 'psi', 'r', 'theta', 'phi']] +x, y, z, rho, psi, r, theta, phi = [Dummy(s) for s in ['x', 'y', 'z', + 'rho', 'psi', 'r', 'theta', 'phi']] ## rectangular <-> cylindrical R3_r.connect_to(R3_c, [x, y, z], [sqrt(x**2 + y**2), atan2(y, x), z], @@ -66,14 +67,16 @@ inverse=False, fill_in_gaps=False) ## rectangular <-> spherical R3_r.connect_to(R3_s, [x, y, z], - [sqrt(x**2+y**2+z**2), acos(z/sqrt(x**2+y**2+z**2)), atan2(y, x)], + [sqrt(x**2 + y**2 + z**2), acos(z/ + sqrt(x**2 + y**2 + z**2)), atan2(y, x)], inverse=False, fill_in_gaps=False) R3_s.connect_to(R3_r, [r, theta, phi], - [r*sin(theta)*cos(phi), r*sin(theta)*sin(phi), r*cos(theta)], + [r*sin(theta)*cos(phi), r*sin( + theta)*sin(phi), r*cos(theta)], inverse=False, fill_in_gaps=False) ## cylindrical <-> spherical R3_c.connect_to(R3_s, [rho, psi, z], - [sqrt(rho**2+z**2), acos(z/sqrt(rho**2+z**2)), psi], + [sqrt(rho**2 + z**2), acos(z/sqrt(rho**2 + z**2)), psi], inverse=False, fill_in_gaps=False) R3_s.connect_to(R3_c, [r, theta, phi], [r*sin(theta), phi, r*cos(theta)], diff -Nru python3-sympy-0.7.2/sympy/diffgeom/tests/test_class_structure.py python3-sympy-0.7.3/sympy/diffgeom/tests/test_class_structure.py --- python3-sympy-0.7.2/sympy/diffgeom/tests/test_class_structure.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/diffgeom/tests/test_class_structure.py 2013-07-13 17:53:32.000000000 +0000 @@ -11,6 +11,7 @@ v1, v2 = cs.base_vectors() f1, f2 = cs.base_oneforms() + def test_point(): point = Point(cs, [x, y]) assert point == point.func(*point.args) @@ -18,6 +19,7 @@ #TODO assert point.subs(x, 2) == Point(cs, [2, y]) #TODO assert point.free_symbols == set([x, y]) + def test_rebuild(): assert m == m.func(*m.args) assert p == p.func(*p.args) @@ -27,10 +29,11 @@ assert v1 == v1.func(*v1.args) assert f1 == f1.func(*f1.args) + def test_subs(): - assert s1.subs(s1,s2) == s2 - assert v1.subs(v1,v2) == v2 - assert f1.subs(f1,f2) == f2 - assert (x*f(s1)+y).subs(s1,s2) == x*f(s2)+y - assert (f(s1)*v1).subs(v1,v2) == f(s1)*v2 - assert (y*f(s1)*f1).subs(f1,f2) == y*f(s1)*f2 + assert s1.subs(s1, s2) == s2 + assert v1.subs(v1, v2) == v2 + assert f1.subs(f1, f2) == f2 + assert (x*f(s1) + y).subs(s1, s2) == x*f(s2) + y + assert (f(s1)*v1).subs(v1, v2) == f(s1)*v2 + assert (y*f(s1)*f1).subs(f1, f2) == y*f(s1)*f2 diff -Nru python3-sympy-0.7.2/sympy/diffgeom/tests/test_diffgeom.py python3-sympy-0.7.3/sympy/diffgeom/tests/test_diffgeom.py --- python3-sympy-0.7.2/sympy/diffgeom/tests/test_diffgeom.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/diffgeom/tests/test_diffgeom.py 2013-07-13 17:53:32.000000000 +0000 @@ -13,31 +13,36 @@ TP = TensorProduct + def test_R2(): x0, y0, r0, theta0 = symbols('x0, y0, r0, theta0', real=True) point_r = R2_r.point([x0, y0]) point_p = R2_p.point([r0, theta0]) # r**2 = x**2 + y**2 - assert (R2.r**2 - R2.x**2 - R2.y**2)(point_r) == 0 - assert trigsimp( (R2.r**2 - R2.x**2 - R2.y**2)(point_p) ) == 0 - assert trigsimp(R2.e_r(R2.x**2+R2.y**2)(point_p).doit()) == 2*r0 + assert (R2.r**2 - R2.x**2 - R2.y**2).rcall(point_r) == 0 + assert trigsimp( (R2.r**2 - R2.x**2 - R2.y**2).rcall(point_p) ) == 0 + assert trigsimp(R2.e_r(R2.x**2 + R2.y**2).rcall(point_p).doit()) == 2*r0 # polar->rect->polar == Id a, b = symbols('a b', positive=True) m = Matrix([[a], [b]]) #TODO assert m == R2_r.coord_tuple_transform_to(R2_p, R2_p.coord_tuple_transform_to(R2_r, [a, b])).applyfunc(simplify) - assert m == R2_p.coord_tuple_transform_to(R2_r, R2_r.coord_tuple_transform_to(R2_p, m)).applyfunc(simplify) + assert m == R2_p.coord_tuple_transform_to( + R2_r, R2_r.coord_tuple_transform_to(R2_p, m)).applyfunc(simplify) def test_R3(): a, b, c = symbols('a b c', positive=True) m = Matrix([[a], [b], [c]]) - assert m == R3_c.coord_tuple_transform_to(R3_r, R3_r.coord_tuple_transform_to(R3_c, m)).applyfunc(simplify) + assert m == R3_c.coord_tuple_transform_to( + R3_r, R3_r.coord_tuple_transform_to(R3_c, m)).applyfunc(simplify) #TODO assert m == R3_r.coord_tuple_transform_to(R3_c, R3_c.coord_tuple_transform_to(R3_r, m)).applyfunc(simplify) - assert m == R3_s.coord_tuple_transform_to(R3_r, R3_r.coord_tuple_transform_to(R3_s, m)).applyfunc(simplify) + assert m == R3_s.coord_tuple_transform_to( + R3_r, R3_r.coord_tuple_transform_to(R3_s, m)).applyfunc(simplify) #TODO assert m == R3_r.coord_tuple_transform_to(R3_s, R3_s.coord_tuple_transform_to(R3_r, m)).applyfunc(simplify) - assert m == R3_s.coord_tuple_transform_to(R3_c, R3_c.coord_tuple_transform_to(R3_s, m)).applyfunc(simplify) + assert m == R3_s.coord_tuple_transform_to( + R3_c, R3_c.coord_tuple_transform_to(R3_s, m)).applyfunc(simplify) #TODO assert m == R3_c.coord_tuple_transform_to(R3_s, R3_s.coord_tuple_transform_to(R3_c, m)).applyfunc(simplify) @@ -46,7 +51,7 @@ p = R2_r.point([x, y]) #TODO assert p.free_symbols() == set([x, y]) assert p.coords(R2_r) == p.coords() == Matrix([x, y]) - assert p.coords(R2_p) == Matrix([sqrt(x**2+y**2), atan2(y,x)]) + assert p.coords(R2_p) == Matrix([sqrt(x**2 + y**2), atan2(y, x)]) def test_commutator(): @@ -60,14 +65,15 @@ def test_differential(): xdy = R2.x*R2.dy dxdy = Differential(xdy) - assert xdy(None) == xdy + assert xdy.rcall(None) == xdy assert dxdy(R2.e_x, R2.e_y) == 1 assert dxdy(R2.e_x, R2.x*R2.e_y) == R2.x assert Differential(dxdy) == 0 def test_products(): - assert TensorProduct(R2.dx, R2.dy)(R2.e_x, R2.e_y) == R2.dx(R2.e_x)*R2.dy(R2.e_y) == 1 + assert TensorProduct( + R2.dx, R2.dy)(R2.e_x, R2.e_y) == R2.dx(R2.e_x)*R2.dy(R2.e_y) == 1 assert WedgeProduct(R2.dx, R2.dy)(R2.e_x, R2.e_y) == 1 assert TensorProduct(R2.dx, R2.dy)(None, R2.e_y) == R2.dx assert TensorProduct(R2.dx, R2.dy)(R2.e_x, None) == R2.dy @@ -80,8 +86,9 @@ assert LieDerivative(R2.e_x, R2.x) == R2.e_x(R2.x) == 1 assert LieDerivative(R2.e_x, R2.e_x) == Commutator(R2.e_x, R2.e_x) == 0 assert LieDerivative(R2.e_x, R2.e_r) == Commutator(R2.e_x, R2.e_r) - assert LieDerivative(R2.e_x+R2.e_y, R2.x) == 1 - assert LieDerivative(R2.e_x, TensorProduct(R2.dx, R2.dy))(R2.e_x, R2.e_y) == 0 + assert LieDerivative(R2.e_x + R2.e_y, R2.x) == 1 + assert LieDerivative( + R2.e_x, TensorProduct(R2.dx, R2.dy))(R2.e_x, R2.e_y) == 0 def test_covar_deriv(): @@ -102,14 +109,16 @@ assert str(equations) == '[f_1(t) + Derivative(f_0(t), t), -f_0(t) + Derivative(f_1(t), t)]' assert str(init_cond) == '[f_0(0) - 1, f_1(0)]' equations, init_cond = intcurve_diffequ(vector_field, t, start_point, R2_p) - assert str(equations) == '[Derivative(f_0(t), t), Derivative(f_1(t), t) - 1]' + assert str( + equations) == '[Derivative(f_0(t), t), Derivative(f_1(t), t) - 1]' assert str(init_cond) == '[f_0(0) - 1, f_1(0)]' def test_helpers_and_coordinate_dependent(): one_form = R2.dr + R2.dx two_form = Differential(R2.x*R2.dr + R2.r*R2.dx) - three_form = Differential(R2.y*two_form) + Differential(R2.x*Differential(R2.r*R2.dr)) + three_form = Differential( + R2.y*two_form) + Differential(R2.x*Differential(R2.r*R2.dr)) metric = TensorProduct(R2.dx, R2.dx) + TensorProduct(R2.dy, R2.dy) metric_ambig = TensorProduct(R2.dx, R2.dx) + TensorProduct(R2.dr, R2.dr) misform_a = TensorProduct(R2.dr, R2.dr) + R2.dr @@ -126,52 +135,52 @@ assert covariant_order(two_form + twoform_not_sym) == 2 assert covariant_order(two_form + twoform_not_TP) == 2 - raises(ValueError, lambda : covariant_order(misform_a)) - raises(ValueError, lambda : covariant_order(misform_b)) - raises(ValueError, lambda : covariant_order(misform_c)) - - assert twoform_to_matrix(metric) == Matrix([[1,0],[0,1]]) - assert twoform_to_matrix(twoform_not_sym) == Matrix([[1,0],[1,0]]) - assert twoform_to_matrix(twoform_not_TP) == Matrix([[0,-1],[1,0]]) - - raises(ValueError, lambda : twoform_to_matrix(one_form)) - raises(ValueError, lambda : twoform_to_matrix(three_form)) - raises(ValueError, lambda : twoform_to_matrix(metric_ambig)) - - raises(ValueError, lambda : metric_to_Christoffel_1st(twoform_not_sym)) - raises(ValueError, lambda : metric_to_Christoffel_2nd(twoform_not_sym)) - raises(ValueError, lambda : metric_to_Riemann_components(twoform_not_sym)) - raises(ValueError, lambda : metric_to_Ricci_components(twoform_not_sym)) + raises(ValueError, lambda: covariant_order(misform_a)) + raises(ValueError, lambda: covariant_order(misform_b)) + raises(ValueError, lambda: covariant_order(misform_c)) + + assert twoform_to_matrix(metric) == Matrix([[1, 0], [0, 1]]) + assert twoform_to_matrix(twoform_not_sym) == Matrix([[1, 0], [1, 0]]) + assert twoform_to_matrix(twoform_not_TP) == Matrix([[0, -1], [1, 0]]) + + raises(ValueError, lambda: twoform_to_matrix(one_form)) + raises(ValueError, lambda: twoform_to_matrix(three_form)) + raises(ValueError, lambda: twoform_to_matrix(metric_ambig)) + + raises(ValueError, lambda: metric_to_Christoffel_1st(twoform_not_sym)) + raises(ValueError, lambda: metric_to_Christoffel_2nd(twoform_not_sym)) + raises(ValueError, lambda: metric_to_Riemann_components(twoform_not_sym)) + raises(ValueError, lambda: metric_to_Ricci_components(twoform_not_sym)) def test_correct_arguments(): - raises(ValueError, lambda : R2.e_x(R2.e_x)) - raises(ValueError, lambda : R2.e_x(R2.dx)) + raises(ValueError, lambda: R2.e_x(R2.e_x)) + raises(ValueError, lambda: R2.e_x(R2.dx)) - raises(ValueError, lambda : Commutator(R2.e_x, R2.x)) - raises(ValueError, lambda : Commutator(R2.dx, R2.e_x)) + raises(ValueError, lambda: Commutator(R2.e_x, R2.x)) + raises(ValueError, lambda: Commutator(R2.dx, R2.e_x)) - raises(ValueError, lambda : Differential(Differential(R2.e_x))) + raises(ValueError, lambda: Differential(Differential(R2.e_x))) - raises(ValueError, lambda : R2.dx(R2.x)) + raises(ValueError, lambda: R2.dx(R2.x)) - raises(ValueError, lambda : TensorProduct(R2.e_x, R2.dx)) + raises(ValueError, lambda: TensorProduct(R2.e_x, R2.dx)) - raises(ValueError, lambda : LieDerivative(R2.dx, R2.dx)) - raises(ValueError, lambda : LieDerivative(R2.x, R2.dx)) + raises(ValueError, lambda: LieDerivative(R2.dx, R2.dx)) + raises(ValueError, lambda: LieDerivative(R2.x, R2.dx)) - raises(ValueError, lambda : CovarDerivativeOp(R2.dx, [])) - raises(ValueError, lambda : CovarDerivativeOp(R2.x, [])) + raises(ValueError, lambda: CovarDerivativeOp(R2.dx, [])) + raises(ValueError, lambda: CovarDerivativeOp(R2.x, [])) a = Symbol('a') - raises(ValueError, lambda : intcurve_series(R2.dx, a, R2_r.point([1,2]))) - raises(ValueError, lambda : intcurve_series(R2.x, a, R2_r.point([1,2]))) + raises(ValueError, lambda: intcurve_series(R2.dx, a, R2_r.point([1, 2]))) + raises(ValueError, lambda: intcurve_series(R2.x, a, R2_r.point([1, 2]))) - raises(ValueError, lambda : intcurve_diffequ(R2.dx, a, R2_r.point([1,2]))) - raises(ValueError, lambda : intcurve_diffequ(R2.x, a, R2_r.point([1,2]))) + raises(ValueError, lambda: intcurve_diffequ(R2.dx, a, R2_r.point([1, 2]))) + raises(ValueError, lambda: intcurve_diffequ(R2.x, a, R2_r.point([1, 2]))) - raises(ValueError, lambda : contravariant_order(R2.e_x + R2.dx)) - raises(ValueError, lambda : covariant_order(R2.e_x + R2.dx)) + raises(ValueError, lambda: contravariant_order(R2.e_x + R2.dx)) + raises(ValueError, lambda: covariant_order(R2.e_x + R2.dx)) - raises(ValueError, lambda : contravariant_order(R2.e_x*R2.e_y)) - raises(ValueError, lambda : covariant_order(R2.dx*R2.dy)) + raises(ValueError, lambda: contravariant_order(R2.e_x*R2.e_y)) + raises(ValueError, lambda: covariant_order(R2.dx*R2.dy)) diff -Nru python3-sympy-0.7.2/sympy/diffgeom/tests/test_function_diffgeom_book.py python3-sympy-0.7.3/sympy/diffgeom/tests/test_function_diffgeom_book.py --- python3-sympy-0.7.2/sympy/diffgeom/tests/test_function_diffgeom_book.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/diffgeom/tests/test_function_diffgeom_book.py 2013-07-13 17:53:32.000000000 +0000 @@ -15,23 +15,25 @@ # From "Functional Differential Geometry" as of 2011 # by Sussman and Wisdom. + def test_functional_diffgeom_ch2(): x0, y0, r0, theta0 = symbols('x0, y0, r0, theta0', real=True) x, y = symbols('x, y', real=True) f = Function('f') assert (R2_p.point_to_coords(R2_r.point([x0, y0])) == - Matrix([sqrt(x0**2+y0**2), atan2(y0, x0)])) + Matrix([sqrt(x0**2 + y0**2), atan2(y0, x0)])) assert (R2_r.point_to_coords(R2_p.point([r0, theta0])) == - Matrix([r0*cos(theta0), r0*sin(theta0)])) + Matrix([r0*cos(theta0), r0*sin(theta0)])) - assert R2_p.jacobian(R2_r, [r0, theta0]) == Matrix([[cos(theta0), -r0*sin(theta0)], [sin(theta0), r0*cos(theta0)]]) + assert R2_p.jacobian(R2_r, [r0, theta0]) == Matrix( + [[cos(theta0), -r0*sin(theta0)], [sin(theta0), r0*cos(theta0)]]) field = f(R2.x, R2.y) p1_in_rect = R2_r.point([x0, y0]) - p1_in_polar = R2_p.point([sqrt(x0**2 + y0**2), atan2(y0,x0)]) - assert field(p1_in_rect) == f(x0, y0) - assert field(p1_in_polar) == f(x0, y0) + p1_in_polar = R2_p.point([sqrt(x0**2 + y0**2), atan2(y0, x0)]) + assert field.rcall(p1_in_rect) == f(x0, y0) + assert field.rcall(p1_in_polar) == f(x0, y0) p_r = R2_r.point([x0, y0]) p_p = R2_p.point([r0, theta0]) @@ -42,8 +44,8 @@ assert R2.theta(p_r) == atan2(y0, x0) h = R2.x*R2.r**2 + R2.y**3 - assert h(p_r) == x0*(x0**2 + y0**2) + y0**3 - assert h(p_p) == r0**3*sin(theta0)**3 + r0**3*cos(theta0) + assert h.rcall(p_r) == x0*(x0**2 + y0**2) + y0**3 + assert h.rcall(p_p) == r0**3*sin(theta0)**3 + r0**3*cos(theta0) def test_functional_diffgeom_ch3(): @@ -54,20 +56,23 @@ b2 = Function('b2') p_r = R2_r.point([x0, y0]) - s_field = f(R2.x,R2.y) + s_field = f(R2.x, R2.y) v_field = b1(R2.x)*R2.e_x + b2(R2.y)*R2.e_y - assert v_field(s_field)(p_r).doit() == b1(x0)*Derivative(f(x0, y0), x0) + b2(y0)*Derivative(f(x0, y0), y0) + assert v_field.rcall(s_field).rcall(p_r).doit() == b1( + x0)*Derivative(f(x0, y0), x0) + b2(y0)*Derivative(f(x0, y0), y0) - assert R2.e_x(R2.r**2)(p_r) == 2*x0 + assert R2.e_x(R2.r**2).rcall(p_r) == 2*x0 v = R2.e_x + 2*R2.e_y s = R2.r**2 + 3*R2.x - assert v(s)(p_r).doit() == 2*x0 + 4*y0 + 3 + assert v.rcall(s).rcall(p_r).doit() == 2*x0 + 4*y0 + 3 circ = -R2.y*R2.e_x + R2.x*R2.e_y series = intcurve_series(circ, t, R2_r.point([1, 0]), coeffs=True) series_x, series_y = list(zip(*series)) - assert all([term == cos(t).taylor_term(i,t) for i, term in enumerate(series_x)]) - assert all([term == sin(t).taylor_term(i,t) for i, term in enumerate(series_y)]) + assert all( + [term == cos(t).taylor_term(i, t) for i, term in enumerate(series_x)]) + assert all( + [term == sin(t).taylor_term(i, t) for i, term in enumerate(series_y)]) def test_functional_diffgeom_ch4(): @@ -80,30 +85,36 @@ p_r = R2_r.point([x0, y0]) p_p = R2_p.point([r0, theta0]) - f_field = b1(R2.x,R2.y)*R2.dx + b2(R2.x,R2.y)*R2.dy - assert f_field(R2.e_x)(p_r) == b1(x0, y0) - assert f_field(R2.e_y)(p_r) == b2(x0, y0) + f_field = b1(R2.x, R2.y)*R2.dx + b2(R2.x, R2.y)*R2.dy + assert f_field.rcall(R2.e_x).rcall(p_r) == b1(x0, y0) + assert f_field.rcall(R2.e_y).rcall(p_r) == b2(x0, y0) - s_field_r = f(R2.x,R2.y) + s_field_r = f(R2.x, R2.y) df = Differential(s_field_r) - assert df(R2.e_x)(p_r).doit() == Derivative(f(x0, y0), x0) - assert df(R2.e_y)(p_r).doit() == Derivative(f(x0, y0), y0) + assert df(R2.e_x).rcall(p_r).doit() == Derivative(f(x0, y0), x0) + assert df(R2.e_y).rcall(p_r).doit() == Derivative(f(x0, y0), y0) - s_field_p = f(R2.r,R2.theta) + s_field_p = f(R2.r, R2.theta) df = Differential(s_field_p) - assert trigsimp(df(R2.e_x)(p_p).doit()) == cos(theta0)*Derivative(f(r0, theta0), r0) - sin(theta0)*Derivative(f(r0, theta0), theta0)/r0 - assert trigsimp(df(R2.e_y)(p_p).doit()) == sin(theta0)*Derivative(f(r0, theta0), r0) + cos(theta0)*Derivative(f(r0, theta0), theta0)/r0 - - assert R2.dx(R2.e_x)(p_r) == 1 - assert R2.dx(R2.e_y)(p_r) == 0 + assert trigsimp(df(R2.e_x).rcall(p_p).doit()) == ( + cos(theta0)*Derivative(f(r0, theta0), r0) - + sin(theta0)*Derivative(f(r0, theta0), theta0)/r0) + assert trigsimp(df(R2.e_y).rcall(p_p).doit()) == ( + sin(theta0)*Derivative(f(r0, theta0), r0) + + cos(theta0)*Derivative(f(r0, theta0), theta0)/r0) + + assert R2.dx(R2.e_x).rcall(p_r) == 1 + assert R2.dx(R2.e_x) == 1 + assert R2.dx(R2.e_y).rcall(p_r) == 0 + assert R2.dx(R2.e_y) == 0 circ = -R2.y*R2.e_x + R2.x*R2.e_y - assert R2.dx(circ)(p_r).doit() == -y0 - assert R2.dy(circ)(p_r) == x0 - assert R2.dr(circ)(p_r) == 0 - assert simplify(R2.dtheta(circ)(p_r)) == 1 + assert R2.dx(circ).rcall(p_r).doit() == -y0 + assert R2.dy(circ).rcall(p_r) == x0 + assert R2.dr(circ).rcall(p_r) == 0 + assert simplify(R2.dtheta(circ).rcall(p_r)) == 1 - assert (circ - R2.e_theta)(s_field_r)(p_r) == 0 + assert (circ - R2.e_theta).rcall(s_field_r).rcall(p_r) == 0 def test_functional_diffgeom_ch6(): @@ -118,16 +129,18 @@ v = v0*R3_r.e_x + v1*R3_r.e_y + v2*R3_r.e_z w = w0*R3_r.e_x + w1*R3_r.e_y + w2*R3_r.e_z wp = WedgeProduct(R3_r.dx, R3_r.dy, R3_r.dz) - assert wp(u, v, w) == Matrix(3, 3, [u0, u1, u2, v0, v1, v2, w0, w1, w2]).det() + assert wp( + u, v, w) == Matrix(3, 3, [u0, u1, u2, v0, v1, v2, w0, w1, w2]).det() a, b, c = symbols('a, b, c', cls=Function) - a_f = a(R3_r.x,R3_r.y,R3_r.z) - b_f = b(R3_r.x,R3_r.y,R3_r.z) - c_f = c(R3_r.x,R3_r.y,R3_r.z) + a_f = a(R3_r.x, R3_r.y, R3_r.z) + b_f = b(R3_r.x, R3_r.y, R3_r.z) + c_f = c(R3_r.x, R3_r.y, R3_r.z) theta = a_f*R3_r.dx + b_f*R3_r.dy + c_f*R3_r.dz dtheta = Differential(theta) da = Differential(a_f) db = Differential(b_f) dc = Differential(c_f) - expr = dtheta - WedgeProduct(da, R3_r.dx) - WedgeProduct(db, R3_r.dy) - WedgeProduct(dc, R3_r.dz) - assert expr(R3_r.e_x, R3_r.e_y) == 0 + expr = dtheta - WedgeProduct( + da, R3_r.dx) - WedgeProduct(db, R3_r.dy) - WedgeProduct(dc, R3_r.dz) + assert expr.rcall(R3_r.e_x, R3_r.e_y) == 0 diff -Nru python3-sympy-0.7.2/sympy/diffgeom/tests/test_hyperbolic_space.py python3-sympy-0.7.3/sympy/diffgeom/tests/test_hyperbolic_space.py --- python3-sympy-0.7.2/sympy/diffgeom/tests/test_hyperbolic_space.py 1970-01-01 00:00:00.000000000 +0000 +++ python3-sympy-0.7.3/sympy/diffgeom/tests/test_hyperbolic_space.py 2013-07-13 17:53:32.000000000 +0000 @@ -0,0 +1,87 @@ +''' +unit test describing the hyperbolic half-plane with the Poincare metric. This +is a basic model of hyperbolic geometry on the (positive) half-space + +{(x,y) \in R^2 | y > 0} + +with the Riemannian metric + +ds^2 = (dx^2 + dy^2)/y^2 + +It has constant negative scalar curvature = -2 + +https://en.wikipedia.org/wiki/Poincare_half-plane_model +''' +from sympy import diag +from sympy.diffgeom import (twoform_to_matrix, + metric_to_Christoffel_1st, metric_to_Christoffel_2nd, + metric_to_Riemann_components, metric_to_Ricci_components) +import sympy.diffgeom.rn + +def test_H2(): + TP = sympy.diffgeom.TensorProduct + R2 = sympy.diffgeom.rn.R2 + y = R2.y + dy = R2.dy + dx = R2.dx + g = (TP(dx, dx) + TP(dy, dy))*y**(-2) + automat = twoform_to_matrix(g) + mat = diag(y**(-2), y**(-2)) + assert mat == automat + + gamma1 = metric_to_Christoffel_1st(g) + assert gamma1[0][0][0] == 0 + assert gamma1[0][0][1] == -y**(-3) + assert gamma1[0][1][0] == -y**(-3) + assert gamma1[0][1][1] == 0 + + assert gamma1[1][1][1] == -y**(-3) + assert gamma1[1][1][0] == 0 + assert gamma1[1][0][1] == 0 + assert gamma1[1][0][0] == y**(-3) + + gamma2 = metric_to_Christoffel_2nd(g) + assert gamma2[0][0][0] == 0 + assert gamma2[0][0][1] == -y**(-1) + assert gamma2[0][1][0] == -y**(-1) + assert gamma2[0][1][1] == 0 + + assert gamma2[1][1][1] == -y**(-1) + assert gamma2[1][1][0] == 0 + assert gamma2[1][0][1] == 0 + assert gamma2[1][0][0] == y**(-1) + + Rm = metric_to_Riemann_components(g) + assert Rm[0][0][0][0] == 0 + assert Rm[0][0][0][1] == 0 + assert Rm[0][0][1][0] == 0 + assert Rm[0][0][1][1] == 0 + + assert Rm[0][1][0][0] == 0 + assert Rm[0][1][0][1] == -y**(-2) + assert Rm[0][1][1][0] == y**(-2) + assert Rm[0][1][1][1] == 0 + + assert Rm[1][0][0][0] == 0 + assert Rm[1][0][0][1] == y**(-2) + assert Rm[1][0][1][0] == -y**(-2) + assert Rm[1][0][1][1] == 0 + + assert Rm[1][1][0][0] == 0 + assert Rm[1][1][0][1] == 0 + assert Rm[1][1][1][0] == 0 + assert Rm[1][1][1][1] == 0 + + Ric = metric_to_Ricci_components(g) + assert Ric[0][0] == -y**(-2) + assert Ric[0][1] == 0 + assert Ric[1][0] == 0 + assert Ric[0][0] == -y**(-2) + + ## scalar curvature is -2 + #TODO - it would be nice to have index contraction built-in + R = (Ric[0][0] + Ric[1][1])*y**2 + assert R == -2 + + ## Gauss curvature is -1 + assert R/2 == -1 diff -Nru python3-sympy-0.7.2/sympy/external/importtools.py python3-sympy-0.7.3/sympy/external/importtools.py --- python3-sympy-0.7.2/sympy/external/importtools.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/external/importtools.py 2013-07-13 17:53:32.000000000 +0000 @@ -6,8 +6,9 @@ # For example, you might set both to False before running the tests so that # warnings are not printed to the console, or set both to True for debugging. -WARN_NOT_INSTALLED = None # Default is False -WARN_OLD_VERSION = None # Default is True +WARN_NOT_INSTALLED = None # Default is False +WARN_OLD_VERSION = None # Default is True + def __sympy_debug(): # helper function from sympy/__init__.py @@ -20,6 +21,7 @@ WARN_OLD_VERSION = True WARN_NOT_INSTALLED = True + def import_module(module, min_module_version=None, min_python_version=None, warn_not_installed=None, warn_old_version=None, module_version_attr='__version__', module_version_attr_call_args=None, @@ -111,7 +113,8 @@ if sys.version_info < min_python_version: if warn_old_version: warnings.warn("Python version is too old to use %s " - "(%s or newer required)" % (module, '.'.join(map(str, min_python_version))), + "(%s or newer required)" % ( + module, '.'.join(map(str, min_python_version))), UserWarning) return @@ -121,6 +124,15 @@ try: mod = __import__(module, **__import__kwargs) + + ## there's something funny about imports with matplotlib and py3k. doing + ## from matplotlib import collections + ## gives python's stdlib collections module. explicitly re-importing + ## the module fixes this. + from_list = __import__kwargs.get('fromlist', tuple()) + for submod in from_list: + if submod == 'collections' and mod.__name__ == 'matplotlib': + __import__(module + '.' + submod) except ImportError: if warn_not_installed: warnings.warn("%s module is not installed" % module, UserWarning) @@ -129,7 +141,8 @@ #except catch as e: except catch as e: if warn_not_installed: - warnings.warn("%s module could not be used (%s)" % (module, repr(e))) + warnings.warn( + "%s module could not be used (%s)" % (module, repr(e))) return if min_module_version: diff -Nru python3-sympy-0.7.2/sympy/external/tests/test_autowrap.py python3-sympy-0.7.3/sympy/external/tests/test_autowrap.py --- python3-sympy-0.7.2/sympy/external/tests/test_autowrap.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/external/tests/test_autowrap.py 2013-07-13 17:53:32.000000000 +0000 @@ -6,17 +6,25 @@ numpy = import_module('numpy') Cython = import_module('Cython') -f2py = import_module('numpy.f2py', __import__kwargs={'fromlist':['f2py']}) +f2py = import_module('numpy.f2py', __import__kwargs={'fromlist': ['f2py']}) f2pyworks = False if f2py: try: autowrap(symbols('x'), 'f95', 'f2py') - except (CodeWrapError, ImportError): + except (CodeWrapError, ImportError, OSError): f2pyworks = False else: f2pyworks = True +a, b, c = symbols('a b c') +n, m, d = symbols('n m d', integer=True) +A, B, C = symbols('A B C', cls=IndexedBase) +i = Idx('i', m) +j = Idx('j', n) +k = Idx('k', d) + + def has_module(module): """ Return True if module exists, otherwise run skip(). @@ -26,7 +34,7 @@ # To give a string of the module name to skip(), this function takes a # string. So we don't waste time running import_module() more than once, # just map the three modules tested here in this dict. - modnames = {'numpy':numpy, 'Cython':Cython, 'f2py':f2py} + modnames = {'numpy': numpy, 'Cython': Cython, 'f2py': f2py} if modnames[module]: if module == 'f2py' and not f2pyworks: @@ -38,29 +46,25 @@ # test runners used by several language-backend combinations # + def runtest_autowrap_twice(language, backend): - a, b, c = symbols('a b c') f = autowrap((((a + b)/c)**5).expand(), language, backend) g = autowrap((((a + b)/c)**4).expand(), language, backend) # check that autowrap updates the module name. Else, g gives the same as f assert f(1, -2, 1) == -1.0 - assert g(1, -2, 1) == 1.0 + assert g(1, -2, 1) == 1.0 + def runtest_autowrap_trace(language, backend): has_module('numpy') - A = IndexedBase('A') - n = symbols('n', integer=True) - i = Idx('i', n) trace = autowrap(A[i, i], language, backend) assert trace(numpy.eye(100)) == 100 + def runtest_autowrap_matrix_vector(language, backend): has_module('numpy') - A, x, y = list(map(IndexedBase, ['A', 'x', 'y'])) - n, m = symbols('n m', integer=True) - i = Idx('i', m) - j = Idx('j', n) + x, y = symbols('x y', cls=IndexedBase) expr = Eq(y[i], A[i, j]*x[j]) mv = autowrap(expr, language, backend) @@ -70,13 +74,9 @@ y = numpy.dot(M, x) assert numpy.sum(numpy.abs(y - mv(M, x))) < 1e-13 + def runtest_autowrap_matrix_matrix(language, backend): has_module('numpy') - A, B, C = list(map(IndexedBase, ['A', 'B', 'C'])) - n, m, d = symbols('n m d', integer=True) - i = Idx('i', m) - j = Idx('j', n) - k = Idx('k', d) expr = Eq(C[i, j], A[i, k]*B[k, j]) matmat = autowrap(expr, language, backend) @@ -86,6 +86,7 @@ M3 = numpy.dot(M1, M2) assert numpy.sum(numpy.abs(M3 - matmat(M1, M2))) < 1e-13 + def runtest_ufuncify(language, backend): has_module('numpy') a, b, c = symbols('a b c') @@ -102,22 +103,27 @@ # f2py + def test_wrap_twice_f95_f2py(): has_module('f2py') runtest_autowrap_twice('f95', 'f2py') + def test_autowrap_trace_f95_f2py(): has_module('f2py') runtest_autowrap_trace('f95', 'f2py') + def test_autowrap_matrix_vector_f95_f2py(): has_module('f2py') runtest_autowrap_matrix_vector('f95', 'f2py') + def test_autowrap_matrix_matrix_f95_f2py(): has_module('f2py') runtest_autowrap_matrix_matrix('f95', 'f2py') + def test_ufuncify_f95_f2py(): has_module('f2py') runtest_ufuncify('f95', 'f2py') @@ -132,21 +138,25 @@ has_module('Cython') runtest_autowrap_twice('C', 'cython') + @XFAIL def test_autowrap_trace_C_Cython(): has_module('Cython') runtest_autowrap_trace('C', 'cython') + @XFAIL def test_autowrap_matrix_vector_C_cython(): has_module('Cython') runtest_autowrap_matrix_vector('C', 'cython') + @XFAIL def test_autowrap_matrix_matrix_C_cython(): has_module('Cython') runtest_autowrap_matrix_matrix('C', 'cython') + @XFAIL def test_ufuncify_C_Cython(): has_module('Cython') diff -Nru python3-sympy-0.7.2/sympy/external/tests/test_codegen.py python3-sympy-0.7.3/sympy/external/tests/test_codegen.py --- python3-sympy-0.7.2/sympy/external/tests/test_codegen.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/external/tests/test_codegen.py 2013-07-13 17:53:32.000000000 +0000 @@ -24,11 +24,11 @@ -from sympy import symbols +from sympy.abc import x, y, z from sympy.utilities.pytest import skip from sympy.utilities.codegen import( - codegen, Routine, InputArgument, Result, get_code_generator - ) + codegen, Routine, InputArgument, Result, get_code_generator +) import sys import os import tempfile @@ -85,35 +85,36 @@ compile_commands = {} compile_commands['cc'] = [ - "cc -c codegen.c -o codegen.o", - "cc -c main.c -o main.o", - "cc main.o codegen.o -lm -o test.exe" - ] + "cc -c codegen.c -o codegen.o", + "cc -c main.c -o main.o", + "cc main.o codegen.o -lm -o test.exe" +] compile_commands['gfortran'] = [ - "gfortran -c codegen.f90 -o codegen.o", - "gfortran -ffree-line-length-none -c main.f90 -o main.o", - "gfortran main.o codegen.o -o test.exe" - ] + "gfortran -c codegen.f90 -o codegen.o", + "gfortran -ffree-line-length-none -c main.f90 -o main.o", + "gfortran main.o codegen.o -o test.exe" +] compile_commands['g95'] = [ - "g95 -c codegen.f90 -o codegen.o", - "g95 -ffree-line-length-huge -c main.f90 -o main.o", - "g95 main.o codegen.o -o test.exe" - ] + "g95 -c codegen.f90 -o codegen.o", + "g95 -ffree-line-length-huge -c main.f90 -o main.o", + "g95 main.o codegen.o -o test.exe" +] compile_commands['ifort'] = [ - "ifort -c codegen.f90 -o codegen.o", - "ifort -c main.f90 -o main.o", - "ifort main.o codegen.o -o test.exe" - ] + "ifort -c codegen.f90 -o codegen.o", + "ifort -c main.f90 -o main.o", + "ifort main.o codegen.o -o test.exe" +] combinations_lang_compiler = [ - ('C', 'cc'), - ('F95', 'ifort'), - ('F95', 'gfortran'), - ('F95', 'g95') - ] + ('C', 'cc'), + ('F95', 'ifort'), + ('F95', 'gfortran'), + ('F95', 'g95') +] + def try_run(commands): """Run a series of commands and only return True if all ran fine.""" @@ -165,7 +166,8 @@ # includes the numerical tests test_strings = [] for fn_name, args, expected, threshold in numerical_tests: - call_string = "%s(%s)-(%s)" % (fn_name, ",".join(str(arg) for arg in args), expected) + call_string = "%s(%s)-(%s)" % ( + fn_name, ",".join(str(arg) for arg in args), expected) if language == "F95": call_string = fortranize_double_constants(call_string) threshold = fortranize_double_constants(str(threshold)) @@ -180,10 +182,11 @@ f_name = "main.c" else: raise NotImplemented( - "FIXME: filename extension unknown for language: %s"%language) + "FIXME: filename extension unknown for language: %s" % language) with open(f_name, "w") as f: - f.write(main_template[language] % {'statements': "".join(test_strings)}) + f.write( + main_template[language] % {'statements': "".join(test_strings)}) # 4) Compile and link compiled = try_run(commands) @@ -214,8 +217,11 @@ os.chdir(oldwork) # 7) Do the assertions in the end - assert compiled, "failed to compile %s code with:\n%s" %(language, "\n".join(commands)) - assert executed, "failed to execute %s code from:\n%s" %(language, "\n".join(commands)) + assert compiled, "failed to compile %s code with:\n%s" % ( + language, "\n".join(commands)) + assert executed, "failed to execute %s code from:\n%s" % ( + language, "\n".join(commands)) + def fortranize_double_constants(code_string): """ @@ -226,7 +232,7 @@ pattern_float = re.compile('\d+\.\d*(?!\d*d)') def subs_exp(matchobj): - return re.sub('[eE]','d',matchobj.group(0)) + return re.sub('[eE]', 'd', matchobj.group(0)) def subs_float(matchobj): return "%sd0" % matchobj.group(0) @@ -237,13 +243,11 @@ return code_string - def is_feasible(language, commands): # This test should always work, otherwise the compiler is not present. - x = symbols('x') routine = Routine("test", x) numerical_tests = [ - ("test", ( 1.0,), 1.0, 1e-15), + ("test", ( 1.0,), 1.0, 1e-15), ("test", (-1.0,), -1.0, 1e-15), ] try: @@ -264,39 +268,43 @@ # We test all language-compiler combinations, just to report what is skipped + def test_C_cc(): if ("C", 'cc') in invalid_lang_compilers: skip("`cc' command didn't work as expected") + def test_F95_ifort(): if ("F95", 'ifort') in invalid_lang_compilers: skip("`ifort' command didn't work as expected") + def test_F95_gfortran(): if ("F95", 'gfortran') in invalid_lang_compilers: skip("`gfortran' command didn't work as expected") + def test_F95_g95(): if ("F95", 'g95') in invalid_lang_compilers: skip("`g95' command didn't work as expected") # Here comes the actual tests + def test_basic_codegen(): - x,y,z = symbols('x,y,z') numerical_tests = [ ("test", (1.0, 6.0, 3.0), 21.0, 1e-15), ("test", (-1.0, 2.0, -2.5), -2.5, 1e-15), ] - name_expr = [("test", (x+y)*z)] + name_expr = [("test", (x + y)*z)] for lang, commands in valid_lang_commands: run_test("basic_codegen", name_expr, numerical_tests, lang, commands) + def test_intrinsic_math1_codegen(): # not included: log10 from sympy import acos, asin, atan, ceiling, cos, cosh, floor, log, ln, \ sin, sinh, sqrt, tan, tanh, N - x = symbols('x') name_expr = [ ("test_fabs", abs(x)), ("test_acos", acos(x)), @@ -322,35 +330,37 @@ name_expr_C = [("test_floor", floor(x)), ("test_ceil", ceiling(x))] else: name_expr_C = [] - run_test("intrinsic_math1", name_expr + name_expr_C, numerical_tests, lang, commands) + run_test("intrinsic_math1", name_expr + name_expr_C, + numerical_tests, lang, commands) + def test_instrinsic_math2_codegen(): # not included: frexp, ldexp, modf, fmod from sympy import atan2, N - x, y = symbols('x,y') name_expr = [ - ("test_atan2", atan2(x,y)), + ("test_atan2", atan2(x, y)), ("test_pow", x**y), ] numerical_tests = [] for name, expr in name_expr: - for xval,yval in (0.2, 1.3), (0.5, -0.2), (0.8, 0.8): + for xval, yval in (0.2, 1.3), (0.5, -0.2), (0.8, 0.8): expected = N(expr.subs(x, xval).subs(y, yval)) - numerical_tests.append((name, (xval,yval), expected, 1e-14)) + numerical_tests.append((name, (xval, yval), expected, 1e-14)) for lang, commands in valid_lang_commands: run_test("intrinsic_math2", name_expr, numerical_tests, lang, commands) + def test_complicated_codegen(): from sympy import sin, cos, tan, N - x,y,z = symbols('x,y,z') name_expr = [ - ("test1", ((sin(x)+cos(y)+tan(z))**7).expand()), - ("test2", cos(cos(cos(cos(cos(cos(cos(cos(x+y+z))))))))), + ("test1", ((sin(x) + cos(y) + tan(z))**7).expand()), + ("test2", cos(cos(cos(cos(cos(cos(cos(cos(x + y + z))))))))), ] numerical_tests = [] for name, expr in name_expr: - for xval,yval,zval in (0.2, 1.3, -0.3), (0.5, -0.2, 0.0), (0.8, 2.1, 0.8): + for xval, yval, zval in (0.2, 1.3, -0.3), (0.5, -0.2, 0.0), (0.8, 2.1, 0.8): expected = N(expr.subs(x, xval).subs(y, yval).subs(z, zval)) - numerical_tests.append((name, (xval,yval,zval), expected, 1e-12)) + numerical_tests.append((name, (xval, yval, zval), expected, 1e-12)) for lang, commands in valid_lang_commands: - run_test("complicated_codegen", name_expr, numerical_tests, lang, commands) + run_test( + "complicated_codegen", name_expr, numerical_tests, lang, commands) diff -Nru python3-sympy-0.7.2/sympy/external/tests/test_importtools.py python3-sympy-0.7.3/sympy/external/tests/test_importtools.py --- python3-sympy-0.7.2/sympy/external/tests/test_importtools.py 1970-01-01 00:00:00.000000000 +0000 +++ python3-sympy-0.7.3/sympy/external/tests/test_importtools.py 2013-07-13 17:53:32.000000000 +0000 @@ -0,0 +1,35 @@ +from sympy.external import import_module + +# fixes issue that arose in addressing issue 3434 +def test_no_stdlib_collections(): + ''' + make sure we get the right collections when it is not part of a + larger list + ''' + import collections + matplotlib = import_module('matplotlib', + __import__kwargs={'fromlist': ['cm', 'collections']}, + min_module_version='1.1.0', catch=(RuntimeError,)) + if matplotlib: + assert collections != matplotlib.collections + +def test_no_stdlib_collections2(): + ''' + make sure we get the right collections when it is not part of a + larger list + ''' + import collections + matplotlib = import_module('matplotlib', + __import__kwargs={'fromlist': ['collections']}, + min_module_version='1.1.0', catch=(RuntimeError,)) + if matplotlib: + assert collections != matplotlib.collections + +def test_no_stdlib_collections3(): + '''make sure we get the right collections with no catch''' + import collections + matplotlib = import_module('matplotlib', + __import__kwargs={'fromlist': ['cm', 'collections']}, + min_module_version='1.1.0') + if matplotlib: + assert collections != matplotlib.collections diff -Nru python3-sympy-0.7.2/sympy/external/tests/test_numpy.py python3-sympy-0.7.3/sympy/external/tests/test_numpy.py --- python3-sympy-0.7.2/sympy/external/tests/test_numpy.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/external/tests/test_numpy.py 2013-07-13 17:53:32.000000000 +0000 @@ -16,6 +16,7 @@ #bin/test will not execute any tests now disabled = True + def setup_module(module): """py.test support""" if getattr(module, 'disabled', False): @@ -27,10 +28,12 @@ import sympy from sympy import mpmath +from sympy.abc import x, y, z from sympy.utilities.decorator import conserve_mpmath_dps # first, systematically check, that all operations are implemented and don't -# raise and exception +# raise an exception + def test_systematic_basic(): def s(sympy_object, numpy_array): @@ -47,23 +50,23 @@ x = Symbol("x") y = Symbol("y") sympy_objs = [ - Rational(2, 3), - Float("1.3"), - x, - y, - pow(x,y)*y, - Integer(5), - Float(5.5), - ] + Rational(2, 3), + Float("1.3"), + x, + y, + pow(x, y)*y, + Integer(5), + Float(5.5), + ] numpy_objs = [ - array([1]), - array([3, 8, -1]), - array([x, x**2, Rational(5)]), - array([x/y*sin(y), 5, Rational(5)]), - ] + array([1]), + array([3, 8, -1]), + array([x, x**2, Rational(5)]), + array([x/y*sin(y), 5, Rational(5)]), + ] for x in sympy_objs: for y in numpy_objs: - s(x,y) + s(x, y) # now some random tests, that test particular problems and that also @@ -72,32 +75,32 @@ def test_basics(): one = Rational(1) zero = Rational(0) - x = Symbol("x") assert array(1) == array(one) assert array([one]) == array([one]) assert array([x]) == array([x]) assert array(x) == array(Symbol("x")) - assert array(one+x) == array(1+x) + assert array(one + x) == array(1 + x) X = array([one, zero, zero]) assert (X == array([one, zero, zero])).all() assert (X == array([one, 0, 0])).all() + def test_arrays(): one = Rational(1) zero = Rational(0) X = array([one, zero, zero]) Y = one*X - X = array([Symbol("a")+Rational(1,2)]) - Y = X+X - assert Y == array([1+2*Symbol("a")]) + X = array([Symbol("a") + Rational(1, 2)]) + Y = X + X + assert Y == array([1 + 2*Symbol("a")]) Y = Y + 1 - assert Y == array([2+2*Symbol("a")]) - Y = X-X + assert Y == array([2 + 2*Symbol("a")]) + Y = X - X assert Y == array([0]) + def test_conversion1(): - x = Symbol("x") a = list2numpy([x**2, x]) #looks like an array? assert isinstance(a, ndarray) @@ -106,8 +109,8 @@ assert len(a) == 2 #yes, it's the array + def test_conversion2(): - x = Symbol("x") a = 2*list2numpy([x**2, x]) b = list2numpy([2*x**2, 2*x]) assert (a == b).all() @@ -116,129 +119,134 @@ zero = Rational(0) X = list2numpy([one, zero, zero]) Y = one*X - X = list2numpy([Symbol("a")+Rational(1,2)]) - Y = X+X - assert Y == array([1+2*Symbol("a")]) + X = list2numpy([Symbol("a") + Rational(1, 2)]) + Y = X + X + assert Y == array([1 + 2*Symbol("a")]) Y = Y + 1 - assert Y == array([2+2*Symbol("a")]) - Y = X-X + assert Y == array([2 + 2*Symbol("a")]) + Y = X - X assert Y == array([0]) + def test_list2numpy(): - x = Symbol("x") assert (array([x**2, x]) == list2numpy([x**2, x])).all() + def test_Matrix1(): - x = Symbol("x") m = Matrix([[x, x**2], [5, 2/x]]) - assert (array(m.subs(x, 2)) == array([[2, 4],[5, 1]])).all() + assert (array(m.subs(x, 2)) == array([[2, 4], [5, 1]])).all() m = Matrix([[sin(x), x**2], [5, 2/x]]) - assert (array(m.subs(x, 2)) == array([[sin(2), 4],[5, 1]])).all() + assert (array(m.subs(x, 2)) == array([[sin(2), 4], [5, 1]])).all() + def test_Matrix2(): - x = Symbol("x") m = Matrix([[x, x**2], [5, 2/x]]) - assert (matrix(m.subs(x, 2)) == matrix([[2, 4],[5, 1]])).all() + assert (matrix(m.subs(x, 2)) == matrix([[2, 4], [5, 1]])).all() m = Matrix([[sin(x), x**2], [5, 2/x]]) - assert (matrix(m.subs(x, 2)) == matrix([[sin(2), 4],[5, 1]])).all() + assert (matrix(m.subs(x, 2)) == matrix([[sin(2), 4], [5, 1]])).all() + def test_Matrix3(): - x = Symbol("x") - a = array([[2, 4],[5, 1]]) + a = array([[2, 4], [5, 1]]) assert Matrix(a) == Matrix([[2, 4], [5, 1]]) assert Matrix(a) != Matrix([[2, 4], [5, 2]]) a = array([[sin(2), 4], [5, 1]]) - assert Matrix(a) == Matrix([[sin(2), 4],[5, 1]]) - assert Matrix(a) != Matrix([[sin(0), 4],[5, 1]]) + assert Matrix(a) == Matrix([[sin(2), 4], [5, 1]]) + assert Matrix(a) != Matrix([[sin(0), 4], [5, 1]]) + def test_Matrix4(): - x = Symbol("x") - a = matrix([[2, 4],[5, 1]]) + a = matrix([[2, 4], [5, 1]]) assert Matrix(a) == Matrix([[2, 4], [5, 1]]) assert Matrix(a) != Matrix([[2, 4], [5, 2]]) a = matrix([[sin(2), 4], [5, 1]]) - assert Matrix(a) == Matrix([[sin(2), 4],[5, 1]]) - assert Matrix(a) != Matrix([[sin(0), 4],[5, 1]]) + assert Matrix(a) == Matrix([[sin(2), 4], [5, 1]]) + assert Matrix(a) != Matrix([[sin(0), 4], [5, 1]]) + def test_Matrix_sum(): - x, y, z = Symbol('x'), Symbol('y'), Symbol('z') - M = Matrix([[1,2,3],[x,y,x],[2*y,-50,z*x]]) - m = matrix([[2,3,4],[x,5,6],[x,y,z**2]]) - assert M+m == Matrix([[3,5,7],[2*x,y+5,x+6],[2*y+x,y-50,z*x+z**2]]) - assert m+M == Matrix([[3,5,7],[2*x,y+5,x+6],[2*y+x,y-50,z*x+z**2]]) - assert M+m == M.add(m) + M = Matrix([[1, 2, 3], [x, y, x], [2*y, -50, z*x]]) + m = matrix([[2, 3, 4], [x, 5, 6], [x, y, z**2]]) + assert M + m == Matrix([[3, 5, 7], [2*x, y + 5, x + 6], [2*y + x, y - 50, z*x + z**2]]) + assert m + M == Matrix([[3, 5, 7], [2*x, y + 5, x + 6], [2*y + x, y - 50, z*x + z**2]]) + assert M + m == M.add(m) + def test_Matrix_mul(): - x, y, z = Symbol('x'), Symbol('y'), Symbol('z') - M = Matrix([[1,2,3],[x,y,x]]) - m = matrix([[2,4],[x,6],[x,z**2]]) + M = Matrix([[1, 2, 3], [x, y, x]]) + m = matrix([[2, 4], [x, 6], [x, z**2]]) assert M*m == Matrix([ - [ 2 + 5*x, 16 + 3*z**2], - [2*x + x*y + x**2, 4*x + 6*y + x*z**2], - ]) + [ 2 + 5*x, 16 + 3*z**2], + [2*x + x*y + x**2, 4*x + 6*y + x*z**2], + ]) assert m*M == Matrix([ - [ 2 + 4*x, 4 + 4*y, 6 + 4*x], - [ 7*x, 2*x + 6*y, 9*x], - [x + x*z**2, 2*x + y*z**2, 3*x + x*z**2], - ]) + [ 2 + 4*x, 4 + 4*y, 6 + 4*x], + [ 7*x, 2*x + 6*y, 9*x], + [x + x*z**2, 2*x + y*z**2, 3*x + x*z**2], + ]) a = array([2]) assert a[0] * M == 2 * M assert M * a[0] == 2 * M + def test_Matrix_array(): class matarray(object): def __array__(self): from numpy import array - return array([[1,2,3],[4,5,6],[7,8,9]]) + return array([[1, 2, 3], [4, 5, 6], [7, 8, 9]]) matarr = matarray() - assert Matrix(matarr) == Matrix([[1,2,3],[4,5,6],[7,8,9]]) + assert Matrix(matarr) == Matrix([[1, 2, 3], [4, 5, 6], [7, 8, 9]]) + def test_issue629(): - x = Symbol("x") - assert (Rational(1,2)*array([2*x, 0]) == array([x, 0])).all() - assert (Rational(1,2) + array([2*x, 0]) == array([2*x + Rational(1,2), Rational(1,2)])).all() + assert (Rational(1, 2)*array([2*x, 0]) == array([x, 0])).all() + assert (Rational(1, 2) + array( + [2*x, 0]) == array([2*x + Rational(1, 2), Rational(1, 2)])).all() assert (Float("0.5")*array([2*x, 0]) == array([Float("1.0")*x, 0])).all() - assert (Float("0.5") + array([2*x, 0]) == array([2*x + Float("0.5"), Float("0.5")])).all() + assert (Float("0.5") + array( + [2*x, 0]) == array([2*x + Float("0.5"), Float("0.5")])).all() + @conserve_mpmath_dps def test_lambdify(): mpmath.mp.dps = 16 sin02 = mpmath.mpf("0.198669330795061215459412627") - x = Symbol("x") f = lambdify(x, sin(x), "numpy") prec = 1e-15 assert -prec < f(0.2) - sin02 < prec try: - f(x) # if this succeeds, it can't be a numpy function + f(x) # if this succeeds, it can't be a numpy function assert False except AttributeError: pass + def test_lambdify_matrix(): - x = Symbol("x") - f = lambdify(x, Matrix([[x, 2*x],[1, 2]]), "numpy") - assert (f(1) == matrix([[1,2],[1,2]])).all() + f = lambdify(x, Matrix([[x, 2*x], [1, 2]]), "numpy") + assert (f(1) == matrix([[1, 2], [1, 2]])).all() + def test_lambdify_matrix_multi_input(): - x,y,z = symbols('x,y,z') - M=sympy.Matrix([[x**2, x*y, x*z], - [y*x, y**2, y*z], - [z*x, z*y, z**2]]) - f = lambdify((x,y,z), M, "numpy") + M = sympy.Matrix([[x**2, x*y, x*z], + [y*x, y**2, y*z], + [z*x, z*y, z**2]]) + f = lambdify((x, y, z), M, "numpy") - xh,yh,zh = 1.0, 2.0, 3.0 + xh, yh, zh = 1.0, 2.0, 3.0 expected = matrix([[xh**2, xh*yh, xh*zh], [yh*xh, yh**2, yh*zh], [zh*xh, zh*yh, zh**2]]) - actual = f(xh,yh,zh) - assert numpy.allclose(actual,expected) + actual = f(xh, yh, zh) + assert numpy.allclose(actual, expected) + def test_lambdify_matrix_vec_input(): - X=sympy.DeferredVector('X') - M=Matrix([[X[0]**2, X[0]*X[1], X[0]*X[2]], - [X[1]*X[0], X[1]**2, X[1]*X[2]], - [X[2]*X[0], X[2]*X[1], X[2]**2]]) + X = sympy.DeferredVector('X') + M = Matrix([ + [X[0]**2, X[0]*X[1], X[0]*X[2]], + [X[1]*X[0], X[1]**2, X[1]*X[2]], + [X[2]*X[0], X[2]*X[1], X[2]**2]]) f = lambdify(X, M, "numpy") Xh = array([1.0, 2.0, 3.0]) @@ -246,7 +254,8 @@ [Xh[1]*Xh[0], Xh[1]**2, Xh[1]*Xh[2]], [Xh[2]*Xh[0], Xh[2]*Xh[1], Xh[2]**2]]) actual = f(Xh) - assert numpy.allclose(actual,expected) + assert numpy.allclose(actual, expected) + def test_lambdify_transl(): from sympy.utilities.lambdify import NUMPY_TRANSLATIONS @@ -254,6 +263,7 @@ assert sym in sympy.__dict__ assert mat in numpy.__dict__ + def test_symarray(): """Test creation of numpy arrays of sympy symbols.""" @@ -263,7 +273,7 @@ syms = symbols('_0,_1,_2') s1 = symarray("", 3) s2 = symarray("", 3) - npt.assert_array_equal (s1, np.array(syms, dtype=object)) + npt.assert_array_equal(s1, np.array(syms, dtype=object)) assert s1[0] is s2[0] a = symarray('a', 3) @@ -271,21 +281,23 @@ assert not(a[0] is b[0]) asyms = symbols('a_0,a_1,a_2') - npt.assert_array_equal (a, np.array(asyms, dtype=object)) + npt.assert_array_equal(a, np.array(asyms, dtype=object)) # Multidimensional checks - a2d = symarray('a', (2,3)) - assert a2d.shape == (2,3) + a2d = symarray('a', (2, 3)) + assert a2d.shape == (2, 3) a00, a12 = symbols('a_0_0,a_1_2') - assert a2d[0,0] is a00 - assert a2d[1,2] is a12 + assert a2d[0, 0] is a00 + assert a2d[1, 2] is a12 - a3d = symarray('a', (2,3,2)) - assert a3d.shape == (2,3,2) + a3d = symarray('a', (2, 3, 2)) + assert a3d.shape == (2, 3, 2) a000, a120, a121 = symbols('a_0_0_0,a_1_2_0,a_1_2_1') - assert a3d[0,0,0] is a000 - assert a3d[1,2,0] is a120 - assert a3d[1,2,1] is a121 + assert a3d[0, 0, 0] is a000 + assert a3d[1, 2, 0] is a120 + assert a3d[1, 2, 1] is a121 + def test_vectorize(): - assert (numpy.vectorize(sin)([1, 2, 3]) == numpy.array([sin(1), sin(2), sin(3)])).all() + assert (numpy.vectorize( + sin)([1, 2, 3]) == numpy.array([sin(1), sin(2), sin(3)])).all() diff -Nru python3-sympy-0.7.2/sympy/external/tests/test_sage.py python3-sympy-0.7.3/sympy/external/tests/test_sage.py --- python3-sympy-0.7.2/sympy/external/tests/test_sage.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/external/tests/test_sage.py 2013-07-13 17:53:32.000000000 +0000 @@ -21,7 +21,7 @@ from sympy.external import import_module -sage = import_module('sage.all', __import__kwargs={'fromlist':['all']}) +sage = import_module('sage.all', __import__kwargs={'fromlist': ['all']}) if not sage: #bin/test will not execute any tests now disabled = True @@ -30,6 +30,7 @@ # Sage does not support Python 3 currently disabled = True + def setup_module(module): """py.test support""" if getattr(module, 'disabled', False): @@ -40,6 +41,7 @@ from sympy.utilities.pytest import XFAIL + def check_expression(expr, var_symbols): """Does eval(expr) both in Sage and SymPy and does other checks.""" @@ -70,61 +72,72 @@ assert e_sage == sage.SR(e_sympy) - def test_basics(): check_expression("x", "x") check_expression("x**2", "x") check_expression("x**2+y**3", "x y") check_expression("1/(x+y)**2-x**3/4", "x y") + def test_complex(): check_expression("I", "") check_expression("23+I*4", "x") + @XFAIL def test_complex_fail(): # Sage doesn't properly implement _sympy_ on I check_expression("I*y", "y") check_expression("x+I*y", "x y") + def test_integer(): check_expression("4*x", "x") check_expression("-4*x", "x") + def test_real(): check_expression("1.123*x", "x") check_expression("-18.22*x", "x") + def test_E(): assert sympy.sympify(sage.e) == sympy.E assert sage.e == sage.SR(sympy.E) + def test_pi(): assert sympy.sympify(sage.pi) == sympy.pi assert sage.pi == sage.SR(sympy.pi) + def test_euler_gamma(): assert sympy.sympify(sage.euler_gamma) == sympy.EulerGamma assert sage.euler_gamma == sage.SR(sympy.EulerGamma) + def test_oo(): assert sympy.sympify(sage.oo) == sympy.oo assert sage.oo == sage.SR(sympy.oo) assert sympy.sympify(-sage.oo) == -sympy.oo assert -sage.oo == sage.SR(-sympy.oo) + def test_NaN(): assert sympy.sympify(sage.NaN) == sympy.nan assert sage.NaN == sage.SR(sympy.nan) + def test_Catalan(): assert sympy.sympify(sage.catalan) == sympy.Catalan assert sage.catalan == sage.SR(sympy.Catalan) + def test_GoldenRation(): assert sympy.sympify(sage.golden_ratio) == sympy.GoldenRatio assert sage.golden_ratio == sage.SR(sympy.GoldenRatio) + def test_functions(): check_expression("sin(x)", "x") check_expression("cos(x)", "x") @@ -146,13 +159,14 @@ check_expression("exp(x)", "x") check_expression("log(x)", "x") + def test_issue924(): sage.var("a x") log = sage.log - i = sympy.integrate(log(x)/a, (x, a, a+1)) + i = sympy.integrate(log(x)/a, (x, a, a + 1)) i2 = sympy.simplify(i) s = sage.SR(i2) - assert s == (a*log(1+a) - a*log(a) + log(1+a) - 1)/a + assert s == (a*log(1 + a) - a*log(a) + log(1 + a) - 1)/a # This string contains Sage doctests, that execute all the functions above. # When you add a new function, please add it here as well. diff -Nru python3-sympy-0.7.2/sympy/external/tests/test_scipy.py python3-sympy-0.7.3/sympy/external/tests/test_scipy.py --- python3-sympy-0.7.2/sympy/external/tests/test_scipy.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/external/tests/test_scipy.py 2013-07-13 17:53:32.000000000 +0000 @@ -12,6 +12,7 @@ #bin/test will not execute any tests now disabled = True + def setup_module(module): """py.test support""" if getattr(module, 'disabled', False): @@ -20,12 +21,14 @@ from sympy import jn_zeros + def eq(a, b, tol=1e-6): for x, y in zip(a, b): - if not (abs(x-y) < tol): + if not (abs(x - y) < tol): return False return True + def test_jn_zeros(): assert eq(jn_zeros(0, 4, method="scipy"), [3.141592, 6.283185, 9.424777, 12.566370]) diff -Nru python3-sympy-0.7.2/sympy/functions/__init__.py python3-sympy-0.7.3/sympy/functions/__init__.py --- python3-sympy-0.7.2/sympy/functions/__init__.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/functions/__init__.py 2013-07-13 17:53:32.000000000 +0000 @@ -6,7 +6,7 @@ """ from sympy.functions.combinatorial.factorials import (factorial, factorial2, - rf, ff, binomial, RisingFactorial, FallingFactorial) + rf, ff, binomial, RisingFactorial, FallingFactorial, subfactorial) from sympy.functions.combinatorial.numbers import (fibonacci, lucas, harmonic, bernoulli, bell, euler, catalan) from sympy.functions.elementary.miscellaneous import (sqrt, root, Min, Max, @@ -22,8 +22,9 @@ asinh, acosh, atanh, acoth) from sympy.functions.elementary.integers import floor, ceiling from sympy.functions.elementary.piecewise import Piecewise, piecewise_fold -from sympy.functions.special.error_functions import (erf, Ei, expint, - E1, Si, Ci, Shi, Chi, fresnels, fresnelc) +from sympy.functions.special.error_functions import (erf, erfc, erfi, erf2, + erfinv, erfcinv, erf2inv, Ei, expint, E1, li, Li, Si, Ci, Shi, Chi, + fresnels, fresnelc) from sympy.functions.special.gamma_functions import (gamma, lowergamma, uppergamma, polygamma, loggamma, digamma, trigamma, beta) from sympy.functions.special.zeta_functions import (dirichlet_eta, zeta, @@ -37,7 +38,9 @@ from sympy.functions.special.hyper import hyper, meijerg from sympy.functions.special.polynomials import (legendre, assoc_legendre, hermite, chebyshevt, chebyshevu, chebyshevu_root, chebyshevt_root, - laguerre, assoc_laguerre, gegenbauer, jacobi) -from sympy.functions.special.spherical_harmonics import Ylm, Zlm + laguerre, assoc_laguerre, gegenbauer, jacobi, jacobi_normalized) +from sympy.functions.special.spherical_harmonics import Ynm, Ynm_c, Znm +from sympy.functions.special.elliptic_integrals import (elliptic_k, + elliptic_f, elliptic_e, elliptic_pi) ln = log diff -Nru python3-sympy-0.7.2/sympy/functions/combinatorial/factorials.py python3-sympy-0.7.3/sympy/functions/combinatorial/factorials.py --- python3-sympy-0.7.2/sympy/functions/combinatorial/factorials.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/functions/combinatorial/factorials.py 2013-07-13 17:53:32.000000000 +0000 @@ -3,9 +3,12 @@ from sympy.ntheory import sieve from math import sqrt as _sqrt -from sympy.core.compatibility import reduce +from sympy.core.compatibility import reduce, as_int +from sympy.core.cache import cacheit from functools import reduce + + class CombinatorialFunction(Function): """Base class for combinatorial functions. """ @@ -13,6 +16,7 @@ ######################## FACTORIAL and MULTI-FACTORIAL ######################## ############################################################################### + class factorial(CombinatorialFunction): """Implementation of factorial function over nonnegative integers. For the sake of convenience and simplicity of procedures using @@ -49,10 +53,10 @@ 5040 >>> factorial(n) - n! + factorial(n) >>> factorial(2*n) - (2*n)! + factorial(2*n) See Also ======== @@ -69,9 +73,9 @@ raise ArgumentIndexError(self, argindex) _small_swing = [ - 1,1,1,3,3,15,5,35,35,315,63,693,231,3003,429,6435,6435,109395, - 12155,230945,46189,969969,88179,2028117,676039,16900975,1300075, - 35102025,5014575,145422675,9694845,300540195,300540195 + 1, 1, 1, 3, 3, 15, 5, 35, 35, 315, 63, 693, 231, 3003, 429, 6435, 6435, 109395, + 12155, 230945, 46189, 969969, 88179, 2028117, 676039, 16900975, 1300075, + 35102025, 5014575, 145422675, 9694845, 300540195, 300540195 ] @classmethod @@ -81,7 +85,7 @@ else: N, primes = int(_sqrt(n)), [] - for prime in sieve.primerange(3, N+1): + for prime in sieve.primerange(3, N + 1): p, q = 1, n while True: @@ -96,13 +100,13 @@ if p > 1: primes.append(p) - for prime in sieve.primerange(N+1, n//3 + 1): + for prime in sieve.primerange(N + 1, n//3 + 1): if (n // prime) & 1 == 1: primes.append(prime) L_product = R_product = 1 - for prime in sieve.primerange(n//2 + 1, n+1): + for prime in sieve.primerange(n//2 + 1, n + 1): L_product *= prime for prime in primes: @@ -131,7 +135,7 @@ n, result = n.p, 1 if n < 20: - for i in range(2, n+1): + for i in range(2, n + 1): result *= i else: N, bits = n, 0 @@ -142,7 +146,7 @@ N = N >> 1 - result = cls._recursive(n)*2**(n-bits) + result = cls._recursive(n)*2**(n - bits) return C.Integer(result) @@ -155,19 +159,75 @@ def _eval_is_integer(self): return self.args[0].is_integer + class MultiFactorial(CombinatorialFunction): pass + +class subfactorial(CombinatorialFunction): + """The subfactorial counts the derangements of n items and is + defined for non-negative integers as:: + + , + | 1 for n = 0 + !n = { 0 for n = 1 + | (n - 1)*(!(n - 1) + !(n - 2)) for n > 1 + ` + + It can also be written as int(round(n!/exp(1))) but the recursive + definition with caching is implemented for this function. + + References + ========== + .. [1] http://en.wikipedia.org/wiki/Subfactorial + + Examples + ======== + + >>> from sympy import subfactorial + >>> from sympy.abc import n + >>> subfactorial(n + 1) + subfactorial(n + 1) + >>> subfactorial(5) + 44 + + See Also + ======== + factorial, sympy.utilities.iterables.generate_derangements + """ + nargs = 1 + + @classmethod + @cacheit + def _eval(self, n): + if not n: + return 1 + elif n == 1: + return 0 + return (n - 1)*(self._eval(n - 1) + self._eval(n - 2)) + + @classmethod + def eval(cls, arg): + try: + arg = as_int(arg) + if arg < 0: + raise ValueError + return C.Integer(cls._eval(arg)) + except ValueError: + if sympify(arg).is_Number: + raise ValueError("argument must be a nonnegative integer") + + class factorial2(CombinatorialFunction): """The double factorial n!!, not to be confused with (n!)! The double factorial is defined for integers >= -1 as:: - , - | n*(n - 2)*(n - 4)* ... * 1 for n odd - n!! = -| n*(n - 2)*(n - 4)* ... * 2 for n even - | 1 for n = 0, -1 - ' + , + | n*(n - 2)*(n - 4)* ... * 1 for n odd + n!! = { n*(n - 2)*(n - 4)* ... * 2 for n even + | 1 for n = 0, -1 + ` Examples ======== @@ -176,7 +236,7 @@ >>> var('n') n >>> factorial2(n + 1) - (n + 1)!! + factorial2(n + 1) >>> factorial2(5) 15 >>> factorial2(-1) @@ -196,16 +256,12 @@ return S.One return factorial2(arg - 2)*arg - def _sympystr(self, p): - if self.args[0].is_Atom: - return "%s!!" % p.doprint(self.args[0]) - else: - return "(%s)!!" % p.doprint(self.args[0]) ############################################################################### ######################## RISING and FALLING FACTORIALS ######################## ############################################################################### + class RisingFactorial(CombinatorialFunction): """Rising factorial (also called Pochhammer symbol) is a double valued function arising in concrete mathematics, hypergeometric functions @@ -264,18 +320,19 @@ else: return S.Infinity else: - return reduce(lambda r, i: r*(x+i), range(0, int(k)), 1) + return reduce(lambda r, i: r*(x + i), range(0, int(k)), 1) else: if x is S.Infinity: return S.Infinity elif x is S.NegativeInfinity: return S.Infinity else: - return 1/reduce(lambda r, i: r*(x-i), range(1, abs(int(k))+1), 1) + return 1/reduce(lambda r, i: r*(x - i), range(1, abs(int(k)) + 1), 1) def _eval_rewrite_as_gamma(self, x, k): return C.gamma(x + k) / C.gamma(x) + class FallingFactorial(CombinatorialFunction): """Falling factorial (related to rising factorial) is a double valued function arising in concrete mathematics, hypergeometric functions @@ -329,15 +386,14 @@ else: return S.Infinity else: - return reduce(lambda r, i: r*(x-i), range(0, int(k)), 1) + return reduce(lambda r, i: r*(x - i), range(0, int(k)), 1) else: if x is S.Infinity: return S.Infinity elif x is S.NegativeInfinity: return S.Infinity else: - return 1/reduce(lambda r, i: r*(x+i), range(1, abs(int(k))+1), 1) - + return 1/reduce(lambda r, i: r*(x + i), range(1, abs(int(k)) + 1), 1) def _eval_rewrite_as_gamma(self, x, k): return (-1)**k * C.gamma(-x + k) / C.gamma(-x) @@ -349,6 +405,7 @@ ########################### BINOMIAL COEFFICIENTS ############################# ############################################################################### + class binomial(CombinatorialFunction): """Implementation of the binomial coefficient. It can be defined in two ways depending on its desired interpretation: @@ -368,10 +425,15 @@ For the sake of convenience for negative 'k' this function will return zero no matter what valued is the other argument. + To expand the binomial when n is a symbol, use either + expand_func() or expand(func=True). The former will keep the + polynomial in factored form while the latter will expand the + polynomial itself. See examples for details. + Examples ======== - >>> from sympy import Symbol, Rational, binomial + >>> from sympy import Symbol, Rational, binomial, expand_func >>> n = Symbol('n', integer=True) >>> binomial(15, 8) @@ -395,6 +457,12 @@ -5/128 >>> binomial(n, 3) + binomial(n, 3) + + >>> binomial(n, 3).expand(func=True) + n**3/6 - n**2/2 + n/3 + + >>> expand_func(binomial(n, 3)) n*(n - 2)*(n - 1)/6 """ @@ -433,7 +501,7 @@ M, result = int(_sqrt(n)), 1 - for prime in sieve.primerange(2, n+1): + for prime in sieve.primerange(2, n + 1): if prime > n - k: result *= prime elif prime > n // 2: @@ -454,14 +522,13 @@ result *= prime**exp return C.Integer(result) - else: + elif n.is_Number: result = n - k + 1 - - for i in range(2, k+1): - result *= n-k+i + for i in range(2, k + 1): + result *= n - k + i result /= i - return result + elif k.is_negative: return S.Zero elif (n - k).simplify().is_negative: @@ -472,6 +539,35 @@ if d.is_Integer: return cls.eval(n, d) + def _eval_expand_func(self, **hints): + """ + Function to expand binomial(n,k) when m is positive integer + Also, + n is self.args[0] and k is self.args[1] while using binomial(n, k) + """ + n = self.args[0] + if n.is_Number: + return binomial(*self.args) + + k = self.args[1] + if k.is_Add and n in k.args: + k = n - k + + if k.is_Integer: + if k == S.Zero: + return S.One + elif k < 0: + return S.Zero + else: + n = self.args[0] + result = n - k + 1 + for i in range(2, k + 1): + result *= n - k + i + result /= i + return result + else: + return binomial(*self.args) + def _eval_rewrite_as_factorial(self, n, k): return C.factorial(n)/(C.factorial(k)*C.factorial(n - k)) diff -Nru python3-sympy-0.7.2/sympy/functions/combinatorial/numbers.py python3-sympy-0.7.3/sympy/functions/combinatorial/numbers.py --- python3-sympy-0.7.2/sympy/functions/combinatorial/numbers.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/functions/combinatorial/numbers.py 2013-07-13 17:53:32.000000000 +0000 @@ -7,14 +7,19 @@ the separate 'factorials' module. """ -from sympy import Function, S, Symbol, Rational, oo, Integer, C, Add, expand_mul +from sympy.core.function import Function, expand_mul +from sympy.core import S, Symbol, Rational, oo, Integer, C, Add, Dummy +from sympy.core.compatibility import as_int, SYMPY_INTS +from sympy.core.cache import cacheit +from sympy.functions.combinatorial.factorials import factorial from sympy.mpmath import bernfrac from sympy.mpmath.libmp import ifib as _ifib + def _product(a, b): p = 1 - for k in range(a, b+1): + for k in range(a, b + 1): p *= k return p @@ -60,13 +65,13 @@ References ========== - * http://en.wikipedia.org/wiki/Fibonacci_number - * http://mathworld.wolfram.com/FibonacciNumber.html + .. [1] http://en.wikipedia.org/wiki/Fibonacci_number + .. [2] http://mathworld.wolfram.com/FibonacciNumber.html See Also ======== - lucas + bell, bernoulli, catalan, euler, harmonic, lucas """ @staticmethod @@ -83,7 +88,7 @@ if n.is_Integer: n = int(n) if n < 0: - return S.NegativeOne**(n+1) * fibonacci(-n) + return S.NegativeOne**(n + 1) * fibonacci(-n) if sym is None: return Integer(cls._fib(n)) else: @@ -92,6 +97,7 @@ "only for positive integer indices.") return cls._fibpoly(n).subs(_sym, sym) + class lucas(Function): """ Lucas numbers @@ -114,18 +120,19 @@ References ========== - * http://en.wikipedia.org/wiki/Lucas_number + .. [1] http://en.wikipedia.org/wiki/Lucas_number + .. [2] http://mathworld.wolfram.com/LucasNumber.html See Also ======== - fibonacci + bell, bernoulli, catalan, euler, fibonacci, harmonic """ @classmethod def eval(cls, n): if n.is_Integer: - return fibonacci(n+1) + fibonacci(n-1) + return fibonacci(n + 1) + fibonacci(n - 1) #----------------------------------------------------------------------------# @@ -200,35 +207,37 @@ References ========== - * http://en.wikipedia.org/wiki/Bernoulli_number - * http://en.wikipedia.org/wiki/Bernoulli_polynomial + .. [1] http://en.wikipedia.org/wiki/Bernoulli_number + .. [2] http://en.wikipedia.org/wiki/Bernoulli_polynomial + .. [3] http://mathworld.wolfram.com/BernoulliNumber.html + .. [4] http://mathworld.wolfram.com/BernoulliPolynomial.html See Also ======== - euler, bell + bell, catalan, euler, fibonacci, harmonic, lucas """ # Calculates B_n for positive even n @staticmethod def _calc_bernoulli(n): s = 0 - a = int(C.binomial(n+3, n-6)) - for j in range(1, n//6+1): + a = int(C.binomial(n + 3, n - 6)) + for j in range(1, n//6 + 1): s += a * bernoulli(n - 6*j) # Avoid computing each binomial coefficient from scratch - a *= _product(n-6 - 6*j + 1, n-6*j) - a //= _product(6*j+4, 6*j+9) + a *= _product(n - 6 - 6*j + 1, n - 6*j) + a //= _product(6*j + 4, 6*j + 9) if n % 6 == 4: - s = -Rational(n+3, 6) - s + s = -Rational(n + 3, 6) - s else: - s = Rational(n+3, 3) - s - return s / C.binomial(n+3, n) + s = Rational(n + 3, 3) - s + return s / C.binomial(n + 3, n) # We implement a specialized memoization scheme to handle each # case modulo 6 separately - _cache = {0: S.One, 2:Rational(1,6), 4:Rational(-1,30)} - _highest = {0:0, 2:2, 4:4} + _cache = {0: S.One, 2: Rational(1, 6), 4: Rational(-1, 30)} + _highest = {0: 0, 2: 2, 4: 4} @classmethod def eval(cls, n, sym=None): @@ -237,8 +246,10 @@ if n is S.Zero: return S.One elif n is S.One: - if sym is None: return -S.Half - else: return sym - S.Half + if sym is None: + return -S.Half + else: + return sym - S.Half # Bernoulli numbers elif sym is None: if n.is_odd: @@ -255,7 +266,7 @@ # To avoid excessive recursion when, say, bernoulli(1000) is # requested, calculate and cache the entire sequence ... B_988, # B_994, B_1000 in increasing order - for i in range(highest_cached+6, n+6, 6): + for i in range(highest_cached + 6, n + 6, 6): b = cls._calc_bernoulli(i) cls._cache[i] = b cls._highest[case] = i @@ -264,7 +275,7 @@ else: n, result = int(n), [] for k in range(n + 1): - result.append(C.binomial(n, k)*cls(k)*sym**(n-k)) + result.append(C.binomial(n, k)*cls(k)*sym**(n - k)) return Add(*result) else: raise ValueError("Bernoulli numbers are defined only" @@ -331,14 +342,14 @@ References ========== - * http://en.wikipedia.org/wiki/Bell_number - * http://mathworld.wolfram.com/BellNumber.html - * http://mathworld.wolfram.com/BellPolynomial.html + .. [1] http://en.wikipedia.org/wiki/Bell_number + .. [2] http://mathworld.wolfram.com/BellNumber.html + .. [3] http://mathworld.wolfram.com/BellPolynomial.html See Also ======== - euler, bernoulli + bernoulli, catalan, euler, fibonacci, harmonic, lucas """ @staticmethod @@ -347,7 +358,7 @@ s = 1 a = 1 for k in range(1, n): - a = a * (n-k) // k + a = a * (n - k) // k s += a * prev[k] return s @@ -356,9 +367,9 @@ def _bell_poly(n, prev): s = 1 a = 1 - for k in range(2, n+1): - a = a * (n-k+1) // (k-1) - s += a * prev[k-1] + for k in range(2, n + 1): + a = a * (n - k + 1) // (k - 1) + s += a * prev[k - 1] return expand_mul(_sym * s) @staticmethod @@ -378,15 +389,16 @@ B_{0,k} = 0; for k>=1 """ - if (n==0) and (k==0): + if (n == 0) and (k == 0): return S.One - elif (n==0) or (k==0): + elif (n == 0) or (k == 0): return S.Zero s = S.Zero a = S.One - for m in range(1, n-k+2): - s += a*bell._bell_incomplete_poly(n-m, k-1, symbols)*symbols[m-1] - a = a*(n-m)/m + for m in range(1, n - k + 2): + s += a * bell._bell_incomplete_poly( + n - m, k - 1, symbols) * symbols[m - 1] + a = a * (n - m) / m return expand_mul(s) @classmethod @@ -406,27 +418,26 @@ # # #----------------------------------------------------------------------------# + class harmonic(Function): r""" Harmonic numbers - The nth harmonic number is given by 1 + 1/2 + 1/3 + ... + 1/n. + The nth harmonic number is given by `\operatorname{H}_{n} = + 1 + \frac{1}{2} + \frac{1}{3} + \ldots + \frac{1}{n}`. - More generally:: + More generally: - n - ___ - \ -m - H = ) k . - n,m /___ - k = 1 + .. math:: \operatorname{H}_{n,m} = \sum_{k=1}^{n} \frac{1}{k^m} - As n -> oo, H_{n,m} -> zeta(m) (the Riemann zeta function) + As `n \rightarrow \infty`, `\operatorname{H}_{n,m} \rightarrow \zeta(m)`, + the Riemann zeta function. - * harmonic(n) gives the nth harmonic number, H_n + * ``harmonic(n)`` gives the nth harmonic number, `\operatorname{H}_n` - * harmonic(n, m) gives the nth generalized harmonic number - of order m, H_{n,m}, where harmonic(n) == harmonic(n, 1) + * ``harmonic(n, m)`` gives the nth generalized harmonic number + of order `m`, `\operatorname{H}_{n,m}`, where + ``harmonic(n) == harmonic(n, 1)`` Examples ======== @@ -440,11 +451,66 @@ >>> harmonic(oo, 2) pi**2/6 + >>> from sympy import Symbol, Sum + >>> n = Symbol("n") + + >>> harmonic(n).rewrite(Sum) + Sum(1/_k, (_k, 1, n)) + + We can rewrite harmonic numbers in terms of polygamma functions: + + >>> from sympy import digamma, polygamma + >>> m = Symbol("m") + + >>> harmonic(n).rewrite(digamma) + polygamma(0, n + 1) + EulerGamma + + >>> harmonic(n).rewrite(polygamma) + polygamma(0, n + 1) + EulerGamma + + >>> harmonic(n,3).rewrite(polygamma) + polygamma(2, n + 1)/2 - polygamma(2, 1)/2 + + >>> harmonic(n,m).rewrite(polygamma) + (-1)**m*(polygamma(m - 1, 1) - polygamma(m - 1, n + 1))/factorial(m - 1) + + Integer offsets in the argument can be pulled out: + + >>> from sympy import expand_func + + >>> expand_func(harmonic(n+4)) + harmonic(n) + 1/(n + 4) + 1/(n + 3) + 1/(n + 2) + 1/(n + 1) + + >>> expand_func(harmonic(n-4)) + harmonic(n) - 1/(n - 1) - 1/(n - 2) - 1/(n - 3) - 1/n + + Some limits can be computed as well: + + >>> from sympy import limit, oo + + >>> limit(harmonic(n), n, oo) + oo + + >>> limit(harmonic(n, 2), n, oo) + pi**2/6 + + >>> limit(harmonic(n, 3), n, oo) + -polygamma(2, 1)/2 + + >>> limit(harmonic(m, n), m, oo) + zeta(n) + References ========== - * http://en.wikipedia.org/wiki/Harmonic_number + .. [1] http://en.wikipedia.org/wiki/Harmonic_number + .. [2] http://functions.wolfram.com/GammaBetaErf/HarmonicNumber/ + .. [3] http://functions.wolfram.com/GammaBetaErf/HarmonicNumber2/ + + See Also + ======== + bell, bernoulli, catalan, euler, fibonacci, lucas """ # Generate one memoized Harmonic number-generating function for each @@ -469,12 +535,53 @@ cls._functions[m] = f return cls._functions[m](int(n)) + def _eval_rewrite_as_polygamma(self, n, m=1): + from sympy.functions.special.gamma_functions import polygamma + return S.NegativeOne**m/factorial(m - 1) * (polygamma(m - 1, 1) - polygamma(m - 1, n + 1)) + + def _eval_rewrite_as_digamma(self, n, m=1): + from sympy.functions.special.gamma_functions import polygamma + return self.rewrite(polygamma) + + def _eval_rewrite_as_trigamma(self, n, m=1): + from sympy.functions.special.gamma_functions import polygamma + return self.rewrite(polygamma) + + def _eval_rewrite_as_Sum(self, n, m=None): + k = C.Dummy("k", integer=True) + if m is None: + m = S.One + return C.Sum(k**(-m), (k, 1, n)) + + def _eval_expand_func(self, **hints): + n = self.args[0] + m = self.args[1] if len(self.args) == 2 else 1 + + if m == S.One: + if n.is_Add: + off = n.args[0] + nnew = n - off + if off.is_Integer and off.is_positive: + result = [S.One/(nnew + i) for i in range(off, 0, -1)] + [harmonic(nnew)] + return Add(*result) + elif off.is_Integer and off.is_negative: + result = [-S.One/(nnew + i) for i in range(0, off, -1)] + [harmonic(nnew)] + return Add(*result) + + return self + + def _eval_rewrite_as_tractable(self, n, m=1): + from sympy.functions.special.gamma_functions import polygamma + return self.rewrite(polygamma).rewrite("tractable", deep=True) + + #----------------------------------------------------------------------------# # # # Euler numbers # # # #----------------------------------------------------------------------------# + class euler(Function): r""" Euler numbers @@ -506,15 +613,15 @@ References ========== - * http://en.wikipedia.org/wiki/Euler_numbers - * http://mathworld.wolfram.com/EulerNumber.html - * http://en.wikipedia.org/wiki/Alternating_permutation - * http://mathworld.wolfram.com/AlternatingPermutation.html + .. [1] http://en.wikipedia.org/wiki/Euler_numbers + .. [2] http://mathworld.wolfram.com/EulerNumber.html + .. [3] http://en.wikipedia.org/wiki/Alternating_permutation + .. [4] http://mathworld.wolfram.com/AlternatingPermutation.html See Also ======== - bernoulli, bell + bell, bernoulli, catalan, fibonacci, harmonic, lucas """ nargs = 1 @@ -531,18 +638,16 @@ res = mp.eulernum(m, exact=True) return Integer(res) - def _eval_rewrite_as_Sum(self, arg): if arg.is_even: k = C.Dummy("k", integer=True) j = C.Dummy("j", integer=True) n = self.args[0] / 2 - Em = (S.ImaginaryUnit * C.Sum( C.Sum( C.binomial(k,j) * ((-1)**j * (k-2*j)**(2*n+1)) / - (2**k*S.ImaginaryUnit**k * k), (j,0,k)), (k, 1, 2*n+1))) + Em = (S.ImaginaryUnit * C.Sum( C.Sum( C.binomial(k, j) * ((-1)**j * (k - 2*j)**(2*n + 1)) / + (2**k*S.ImaginaryUnit**k * k), (j, 0, k)), (k, 1, 2*n + 1))) return Em - def _eval_evalf(self, prec): m = self.args[0] @@ -562,6 +667,7 @@ # # #----------------------------------------------------------------------------# + class catalan(Function): r""" Catalan numbers @@ -610,7 +716,7 @@ continuous real funtion in n: >>> diff(catalan(n), n) - (polygamma(0, n + 1/2) - polygamma(0, n + 2) + 2*log(2))*catalan(n) + (polygamma(0, n + 1/2) - polygamma(0, n + 2) + log(4))*catalan(n) As a more advanced example consider the following ratio between consecutive numbers: @@ -631,34 +737,605 @@ References ========== - * http://en.wikipedia.org/wiki/Catalan_number - * http://mathworld.wolfram.com/CatalanNumber.html - * http://geometer.org/mathcircles/catalan.pdf + .. [1] http://en.wikipedia.org/wiki/Catalan_number + .. [2] http://mathworld.wolfram.com/CatalanNumber.html + .. [3] http://functions.wolfram.com/GammaBetaErf/CatalanNumber/ + .. [4] http://geometer.org/mathcircles/catalan.pdf See Also ======== + bell, bernoulli, euler, fibonacci, harmonic, lucas sympy.functions.combinatorial.factorials.binomial """ @classmethod def eval(cls, n, evaluate=True): if n.is_Integer and n.is_nonnegative: - return 4**n*C.gamma(n + S.Half)/(C.gamma(S.Half)*C.gamma(n+2)) + return 4**n*C.gamma(n + S.Half)/(C.gamma(S.Half)*C.gamma(n + 2)) def fdiff(self, argindex=1): n = self.args[0] - return catalan(n)*(C.polygamma(0,n+Rational(1,2))-C.polygamma(0,n+2)+C.log(4)) + return catalan(n)*(C.polygamma(0, n + Rational(1, 2)) - C.polygamma(0, n + 2) + C.log(4)) - def _eval_rewrite_as_binomial(self,n): - return C.binomial(2*n,n)/(n + 1) + def _eval_rewrite_as_binomial(self, n): + return C.binomial(2*n, n)/(n + 1) - def _eval_rewrite_as_gamma(self,n): + def _eval_rewrite_as_gamma(self, n): # The gamma function allows to generalize Catalan numbers to complex n - return 4**n*C.gamma(n + S.Half)/(C.gamma(S.Half)*C.gamma(n+2)) + return 4**n*C.gamma(n + S.Half)/(C.gamma(S.Half)*C.gamma(n + 2)) - def _eval_rewrite_as_hyper(self,n): - return C.hyper([1-n,-n],[2],1) + def _eval_rewrite_as_hyper(self, n): + return C.hyper([1 - n, -n], [2], 1) def _eval_evalf(self, prec): return self.rewrite(C.gamma).evalf(prec) + +####################################################################### +### +### Functions for enumerating partitions, permutations and combinations +### +####################################################################### + + +class _MultisetHistogram(tuple): + pass + + +_N = -1 +_ITEMS = -2 +_M = slice(None, _ITEMS) + + +def _multiset_histogram(n): + """Return tuple used in permutation and combination counting. Input + is a dictionary giving items with counts as values or a sequence of + items (which need not be sorted). + + The data is stored in a class deriving from tuple so it is easily + recognized and so it can be converted easily to a list. + """ + if type(n) is dict: # item: count + if not all(isinstance(v, int) and v >= 0 for v in list(n.values())): + raise ValueError + tot = sum(n.values()) + items = sum(1 for k in n if n[k] > 0) + return _MultisetHistogram([n[k] for k in n if n[k] > 0] + [items, tot]) + else: + n = list(n) + s = set(n) + if len(s) == len(n): + n = [1]*len(n) + n.extend([len(n), len(n)]) + return _MultisetHistogram(n) + m = dict(list(zip(s, list(range(len(s)))))) + d = dict(list(zip(list(range(len(s))), [0]*len(s)))) + for i in n: + d[m[i]] += 1 + return _multiset_histogram(d) + + +def nP(n, k=None, replacement=False): + """Return the number of permutations of ``n`` items taken ``k`` at a time. + + Possible values for ``n``:: + integer - set of length ``n`` + sequence - converted to a multiset internally + multiset - {element: multiplicity} + + If ``k`` is None then the total of all permutations of length 0 + through the number of items represented by ``n`` will be returned. + + If ``replacement`` is True then a given item can appear more than once + in the ``k`` items. (For example, for 'ab' permutations of 2 would + include 'aa', 'ab', 'ba' and 'bb'.) The multiplicity of elements in + ``n`` is ignored when ``replacement`` is True but the total number + of elements is considered since no element can appear more times than + the number of elements in ``n``. + + Examples + ======== + + >>> from sympy.functions.combinatorial.numbers import nP + >>> from sympy.utilities.iterables import multiset_permutations, multiset + >>> nP(3, 2) + 6 + >>> nP('abc', 2) == nP(multiset('abc'), 2) == 6 + True + >>> nP('aab', 2) + 3 + >>> nP([1, 2, 2], 2) + 3 + >>> [nP(3, i) for i in range(4)] + [1, 3, 6, 6] + >>> nP(3) == sum(_) + True + + When ``replacement`` is True, each item can have multiplicity + equal to the length represented by ``n``: + + >>> nP('aabc', replacement=True) + 121 + >>> [len(list(multiset_permutations('aaaabbbbcccc', i))) for i in range(5)] + [1, 3, 9, 27, 81] + >>> sum(_) + 121 + + References + ========== + + .. [1] http://en.wikipedia.org/wiki/Permutation + + See Also + ======== + sympy.utilities.iterables.multiset_permutations + + """ + try: + n = as_int(n) + except ValueError: + return Integer(_nP(_multiset_histogram(n), k, replacement)) + return Integer(_nP(n, k, replacement)) + + +@cacheit +def _nP(n, k=None, replacement=False): + from sympy.functions.combinatorial.factorials import factorial + from sympy.core.mul import prod + + if k == 0: + return 1 + if isinstance(n, SYMPY_INTS): # n different items + # assert n >= 0 + if k is None: + return sum(_nP(n, i, replacement) for i in range(n + 1)) + elif replacement: + return n**k + elif k > n: + return 0 + elif k == n: + return factorial(k) + elif k == 1: + return n + else: + # assert k >= 0 + return _product(n - k + 1, n) + elif isinstance(n, _MultisetHistogram): + if k is None: + return sum(_nP(n, i, replacement) for i in range(n[_N] + 1)) + elif replacement: + return n[_ITEMS]**k + elif k == n[_N]: + return factorial(k)/prod([factorial(i) for i in n[_M] if i > 1]) + elif k > n[_N]: + return 0 + elif k == 1: + return n[_ITEMS] + else: + # assert k >= 0 + tot = 0 + n = list(n) + for i in range(len(n[_M])): + if not n[i]: + continue + n[_N] -= 1 + if n[i] == 1: + n[i] = 0 + n[_ITEMS] -= 1 + tot += _nP(_MultisetHistogram(n), k - 1) + n[_ITEMS] += 1 + n[i] = 1 + else: + n[i] -= 1 + tot += _nP(_MultisetHistogram(n), k - 1) + n[i] += 1 + n[_N] += 1 + return tot + + +@cacheit +def _AOP_product(n): + """for n = (m1, m2, .., mk) return the coefficients of the polynomial, + prod(sum(x**i for i in range(nj + 1)) for nj in n); i.e. the coefficients + of the product of AOPs (all-one polynomials) or order given in n. The + resulting coefficient corresponding to x**r is the number of r-length + combinations of sum(n) elements with multiplicities given in n. + The coefficients are given as a default dictionary (so if a query is made + for a key that is not present, 0 will be returned). + + Examples + ======== + + >>> from sympy.functions.combinatorial.numbers import _AOP_product + >>> from sympy.abc import x + >>> n = (2, 2, 3) # e.g. aabbccc + >>> prod = ((x**2 + x + 1)*(x**2 + x + 1)*(x**3 + x**2 + x + 1)).expand() + >>> c = _AOP_product(n); dict(c) + {0: 1, 1: 3, 2: 6, 3: 8, 4: 8, 5: 6, 6: 3, 7: 1} + >>> [c[i] for i in range(8)] == [prod.coeff(x, i) for i in range(8)] + True + + The generating poly used here is the same as that listed in + http://tinyurl.com/cep849r, but in a refactored form. + + """ + from collections import defaultdict + + n = list(n) + ord = sum(n) + need = (ord + 2)//2 + rv = [1]*(n.pop() + 1) + rv.extend([0]*(need - len(rv))) + rv = rv[:need] + while n: + ni = n.pop() + N = ni + 1 + was = rv[:] + for i in range(1, min(N, len(rv))): + rv[i] += rv[i - 1] + for i in range(N, need): + rv[i] += rv[i - 1] - was[i - N] + rev = list(reversed(rv)) + if ord % 2: + rv = rv + rev + else: + rv[-1:] = rev + d = defaultdict(int) + for i in range(len(rv)): + d[i] = rv[i] + return d + + +def nC(n, k=None, replacement=False): + """Return the number of combinations of ``n`` items taken ``k`` at a time. + + Possible values for ``n``:: + integer - set of length ``n`` + sequence - converted to a multiset internally + multiset - {element: multiplicity} + + If ``k`` is None then the total of all combinations of length 0 + through the number of items represented in ``n`` will be returned. + + If ``replacement`` is True then a given item can appear more than once + in the ``k`` items. (For example, for 'ab' sets of 2 would include 'aa', + 'ab', and 'bb'.) The multiplicity of elements in ``n`` is ignored when + ``replacement`` is True but the total number of elements is considered + since no element can appear more times than the number of elements in + ``n``. + + Examples + ======== + + >>> from sympy.functions.combinatorial.numbers import nC + >>> from sympy.utilities.iterables import multiset_combinations + >>> nC(3, 2) + 3 + >>> nC('abc', 2) + 3 + >>> nC('aab', 2) + 2 + + When ``replacement`` is True, each item can have multiplicity + equal to the length represented by ``n``: + + >>> nC('aabc', replacement=True) + 35 + >>> [len(list(multiset_combinations('aaaabbbbcccc', i))) for i in range(5)] + [1, 3, 6, 10, 15] + >>> sum(_) + 35 + + If there are ``k`` items with multiplicities ``m_1, m_2, ..., m_k`` + then the total of all combinations of length 0 hrough ``k`` is the + product, ``(m_1 + 1)*(m_2 + 1)*...*(m_k + 1)``. When the multiplicity + of each item is 1 (i.e., k unique items) then there are 2**k + combinations. For example, if there are 4 unique items, the total number + of combinations is 16: + + >>> sum(nC(4, i) for i in range(5)) + 16 + + References + ========== + + .. [1] http://en.wikipedia.org/wiki/Combination + .. [2] http://tinyurl.com/cep849r + + See Also + ======== + sympy.utilities.iterables.multiset_combinations + """ + from sympy.functions.combinatorial.factorials import binomial + from sympy.core.mul import prod + + if isinstance(n, SYMPY_INTS): + if k is None: + if not replacement: + return 2**n + return sum(nC(n, i, replacement) for i in range(n + 1)) + assert k >= 0 + if replacement: + return binomial(n + k - 1, k) + return binomial(n, k) + if isinstance(n, _MultisetHistogram): + N = n[_N] + if k is None: + if not replacement: + return prod(m + 1 for m in n[_M]) + return sum(nC(n, i, replacement) for i in range(N + 1)) + elif replacement: + return nC(n[_ITEMS], k, replacement) + # assert k >= 0 + elif k in (1, N - 1): + return n[_ITEMS] + elif k in (0, N): + return 1 + return _AOP_product(tuple(n[_M]))[k] + else: + return nC(_multiset_histogram(n), k, replacement) + + +@cacheit +def _stirling1(n, k): + if n == k == 0: + return S.One + if 0 in (n, k): + return S.Zero + n1 = n - 1 + + # some special values + if n == k: + return S.One + elif k == 1: + return factorial(n1) + elif k == n1: + return C.binomial(n, 2) + elif k == n - 2: + return (3*n - 1)*C.binomial(n, 3)/4 + elif k == n - 3: + return C.binomial(n, 2)*C.binomial(n, 4) + + # general recurrence + return n1*_stirling1(n1, k) + _stirling1(n1, k - 1) + + +@cacheit +def _stirling2(n, k): + if n == k == 0: + return S.One + if 0 in (n, k): + return S.Zero + n1 = n - 1 + + # some special values + if k == n1: + return C.binomial(n, 2) + elif k == 2: + return 2**n1 - 1 + + # general recurrence + return k*_stirling2(n1, k) + _stirling2(n1, k - 1) + + +def stirling(n, k, d=None, kind=2, signed=False): + """Return Stirling number S(n, k) of the first or second (default) kind. + + The sum of all Stirling numbers of the second kind for k = 1 + through n is bell(n). The recurrence relationship for these numbers + is:: + + {0} {n} {0} {n + 1} {n} { n } + { } = 1; { } = { } = 0; { } = j*{ } + { } + {0} {0} {k} { k } {k} {k - 1} + + where ``j`` is:: + ``n`` for Stirling numbers of the first kind + ``-n`` for signed Stirling numbers of the first kind + ``k`` for Stirling numbers of the second kind + + The first kind of Stirling number counts the number of permutations of + ``n`` distinct items that have ``k`` cycles; the second kind counts the + ways in which ``n`` distinct items can be partitioned into ``k`` parts. + If ``d`` is given, the "reduced Stirling number of the second kind" is + returned: ``S^{d}(n, k) = S(n - d + 1, k - d + 1)`` with ``n >= k >= d``. + (This counts the ways to partition ``n`` consecutive integers into + ``k`` groups with no pairwise difference less than ``d``. See example + below.) + + To obtain the signed Stirling numbers of the first kind, use keyword + ``signed=True``. Using this keyword automatically sets ``kind`` to 1. + + Examples + ======== + + >>> from sympy.functions.combinatorial.numbers import stirling, bell + >>> from sympy.combinatorics import Permutation + >>> from sympy.utilities.iterables import multiset_partitions, permutations + + First kind (unsigned by default): + + >>> [stirling(6, i, kind=1) for i in range(7)] + [0, 120, 274, 225, 85, 15, 1] + >>> perms = list(permutations(list(range(4)))) + >>> [sum(Permutation(p).cycles == i for p in perms) for i in range(5)] + [0, 6, 11, 6, 1] + >>> [stirling(4, i, kind=1) for i in range(5)] + [0, 6, 11, 6, 1] + + First kind (signed): + + >>> [stirling(4, i, signed=True) for i in range(5)] + [0, -6, 11, -6, 1] + + Second kind: + + >>> [stirling(10, i) for i in range(12)] + [0, 1, 511, 9330, 34105, 42525, 22827, 5880, 750, 45, 1, 0] + >>> sum(_) == bell(10) + True + >>> len(list(multiset_partitions(list(range(4)), 2))) == stirling(4, 2) + True + + Reduced second kind: + + >>> from sympy import subsets, oo + >>> def delta(p): + ... if len(p) == 1: + ... return oo + ... return min(abs(i[0] - i[1]) for i in subsets(p, 2)) + >>> parts = multiset_partitions(list(range(5)), 3) + >>> d = 2 + >>> sum(1 for p in parts if all(delta(i) >= d for i in p)) + 7 + >>> stirling(5, 3, 2) + 7 + + References + ========== + + .. [1] http://en.wikipedia.org/wiki/Stirling_numbers_of_the_first_kind + .. [2] http://en.wikipedia.org/wiki/Stirling_numbers_of_the_second_kind + + See Also + ======== + sympy.utilities.iterables.multiset_partitions + + """ + # TODO: make this a class like bell() + + n = as_int(n) + k = as_int(k) + if n < 0: + raise ValueError('n must be nonnegative') + if k > n: + return S.Zero + if d: + # assert k >= d + # kind is ignored -- only kind=2 is supported + return _stirling2(n - d + 1, k - d + 1) + elif signed: + # kind is ignored -- only kind=1 is supported + return (-1)**(n - k)*_stirling1(n, k) + + if kind == 1: + return _stirling1(n, k) + elif kind == 2: + return _stirling2(n, k) + else: + raise ValueError('kind must be 1 or 2, not %s' % k) + + +@cacheit +def _nT(n, k): + """Return the partitions of ``n`` items into ``k`` parts. This + is used by ``nT`` for the case when ``n`` is an integer.""" + if k == 0: + return 1 if k == n else 0 + return sum(_nT(n - k, j) for j in range(min(k, n - k) + 1)) + + +def nT(n, k=None): + """Return the number of ``k``-sized partitions of ``n`` items. + + Possible values for ``n``:: + integer - ``n`` identical items + sequence - converted to a multiset internally + multiset - {element: multiplicity} + + Note: the convention for ``nT`` is different than that of ``nC`` and``nP`` in that + here an integer indicates ``n`` *identical* items instead of a set of + length ``n``; this is in keepng with the ``partitions`` function which + treats its integer-``n`` input like a list of ``n`` 1s. One can use + ``range(n)`` for ``n`` to indicate ``n`` distinct items. + + If ``k`` is None then the total number of ways to partition the elements + represented in ``n`` will be returned. + + Examples + ======== + + >>> from sympy.functions.combinatorial.numbers import nT + + Partitions of the given multiset: + + >>> [nT('aabbc', i) for i in range(1, 7)] + [1, 8, 11, 5, 1, 0] + >>> nT('aabbc') == sum(_) + True + + (TODO The following can be activated with >>> when + taocp_multiset_permutation is in place.) + >> [nT("mississippi", i) for i in range(1, 12)] + [1, 74, 609, 1521, 1768, 1224, 579, 197, 50, 9, 1] + + Partitions when all items are identical: + + >>> [nT(5, i) for i in range(1, 6)] + [1, 2, 2, 1, 1] + >>> nT('1'*5) == sum(_) + True + + When all items are different: + + >>> [nT(list(range(5)), i) for i in range(1, 6)] + [1, 15, 25, 10, 1] + >>> nT(list(range(5))) == sum(_) + True + + References + ========== + + .. [1] http://undergraduate.csse.uwa.edu.au/units/CITS7209/partition.pdf + + See Also + ======== + sympy.utilities.iterables.partitions + sympy.utilities.iterables.multiset_partitions + + """ + from sympy.utilities.iterables import multiset_partitions + + if isinstance(n, SYMPY_INTS): + # assert n >= 0 + # all the same + if k is None: + return sum(_nT(n, k) for k in range(1, n + 1)) + return _nT(n, k) + if not isinstance(n, _MultisetHistogram): + try: + # if n contains hashable items there is some + # quick handling that can be done + u = len(set(n)) + if u == 1: + return nT(len(n), k) + elif u == len(n): + n = list(range(u)) + raise TypeError + except TypeError: + n = _multiset_histogram(n) + N = n[_N] + if k is None and N == 1: + return 1 + if k in (1, N): + return 1 + if k == 2 or N == 2 and k is None: + m, r = divmod(N, 2) + rv = sum(nC(n, i) for i in range(1, m + 1)) + if not r: + rv -= nC(n, m)//2 + if k is None: + rv += 1 # for k == 1 + return rv + if N == n[_ITEMS]: + # all distinct + if k is None: + return bell(N) + return stirling(N, k) + if k is None: + return sum(nT(n, k) for k in range(1, N + 1)) + tot = 0 + for p in multiset_partitions( + [i for i, j in enumerate(n[_M]) for ii in range(j)]): + tot += len(p) == k + return tot diff -Nru python3-sympy-0.7.2/sympy/functions/combinatorial/tests/test_comb_factorials.py python3-sympy-0.7.3/sympy/functions/combinatorial/tests/test_comb_factorials.py --- python3-sympy-0.7.2/sympy/functions/combinatorial/tests/test_comb_factorials.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/functions/combinatorial/tests/test_comb_factorials.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,6 +1,9 @@ from sympy import (Symbol, symbols, factorial, factorial2, binomial, - rf, ff, gamma, polygamma, EulerGamma, O, pi, nan, oo, simplify) -from sympy.utilities.pytest import XFAIL + rf, ff, gamma, polygamma, EulerGamma, O, pi, nan, + oo, simplify, expand_func) +from sympy.functions.combinatorial.factorials import subfactorial +from sympy.utilities.pytest import XFAIL, raises + def test_rf_eval_apply(): x, y = symbols('x,y') @@ -20,16 +23,17 @@ assert rf(x, 0) == 1 assert rf(x, 1) == x - assert rf(x, 2) == x*(x+1) - assert rf(x, 3) == x*(x+1)*(x+2) - assert rf(x, 5) == x*(x+1)*(x+2)*(x+3)*(x+4) - - assert rf(x, -1) == 1/(x-1) - assert rf(x, -2) == 1/((x-1)*(x-2)) - assert rf(x, -3) == 1/((x-1)*(x-2)*(x-3)) + assert rf(x, 2) == x*(x + 1) + assert rf(x, 3) == x*(x + 1)*(x + 2) + assert rf(x, 5) == x*(x + 1)*(x + 2)*(x + 3)*(x + 4) + + assert rf(x, -1) == 1/(x - 1) + assert rf(x, -2) == 1/((x - 1)*(x - 2)) + assert rf(x, -3) == 1/((x - 1)*(x - 2)*(x - 3)) assert rf(1, 100) == factorial(100) + def test_ff_eval_apply(): x, y = symbols('x,y') @@ -48,16 +52,17 @@ assert ff(x, 0) == 1 assert ff(x, 1) == x - assert ff(x, 2) == x*(x-1) - assert ff(x, 3) == x*(x-1)*(x-2) - assert ff(x, 5) == x*(x-1)*(x-2)*(x-3)*(x-4) - - assert ff(x, -1) == 1/(x+1) - assert ff(x, -2) == 1/((x+1)*(x+2)) - assert ff(x, -3) == 1/((x+1)*(x+2)*(x+3)) + assert ff(x, 2) == x*(x - 1) + assert ff(x, 3) == x*(x - 1)*(x - 2) + assert ff(x, 5) == x*(x - 1)*(x - 2)*(x - 3)*(x - 4) + + assert ff(x, -1) == 1/(x + 1) + assert ff(x, -2) == 1/((x + 1)*(x + 2)) + assert ff(x, -3) == 1/((x + 1)*(x + 2)*(x + 3)) assert ff(100, 100) == factorial(100) + def test_factorial(): n = Symbol('n', integer=True) @@ -67,6 +72,7 @@ assert factorial(n).func == factorial assert factorial(2*n).func == factorial + def test_factorial_diff(): n = Symbol('n', integer=True) @@ -75,17 +81,20 @@ assert factorial(n**2).diff(n) == \ 2*n*gamma(1 + n**2)*polygamma(0, 1 + n**2) + def test_factorial_series(): n = Symbol('n', integer=True) assert factorial(n).series(n, 0, 3) == \ 1 - n*EulerGamma + n**2*(EulerGamma**2/2 + pi**2/12) + O(n**3) + def test_factorial_rewrite(): n = Symbol('n', integer=True) assert factorial(n).rewrite(gamma) == gamma(n + 1) + def test_factorial2(): n = Symbol('n', integer=True) @@ -95,6 +104,7 @@ assert factorial2(8) == 384 assert factorial2(n).func == factorial2 + def test_binomial(): n = Symbol('n', integer=True) k = Symbol('k', integer=True) @@ -111,17 +121,23 @@ assert binomial(-10, 7) == -11440 assert binomial(n, -1) == 0 assert binomial(n, 0) == 1 - assert binomial(n, 1) == n - assert binomial(n, 2) == n*(n - 1)/2 - assert binomial(n, n-2) == n*(n - 1)/2 - assert binomial(n, n-1) == n + assert expand_func(binomial(n, 1)) == n + assert expand_func(binomial(n, 2)) == n*(n - 1)/2 + assert expand_func(binomial(n, n - 2)) == n*(n - 1)/2 + assert expand_func(binomial(n, n - 1)) == n + assert binomial(n, 3).func == binomial + assert binomial(n, 3).expand(func=True) == n**3/6 - n**2/2 + n/3 + assert expand_func(binomial(n, 3)) == n*(n - 2)*(n - 1)/6 assert binomial(n, n) == 1 - assert binomial(n, n+1) == 0 + assert binomial(n, n + 1) == 0 assert binomial(n, u) == 0 assert binomial(n, v).func == binomial assert binomial(n, k).func == binomial assert binomial(n, n + v) == 0 + assert expand_func(binomial(n, n-3)) == n*(n - 2)*(n - 1)/6 + + def test_binomial_diff(): n = Symbol('n', integer=True) k = Symbol('k', integer=True) @@ -129,19 +145,25 @@ assert binomial(n, k).diff(n) == \ (-polygamma(0, 1 + n - k) + polygamma(0, 1 + n))*binomial(n, k) assert binomial(n**2, k**3).diff(n) == \ - 2*n*(-polygamma(0, 1 + n**2 - k**3) + polygamma(0, 1 + n**2))*binomial(n**2, k**3) + 2*n*(-polygamma( + 0, 1 + n**2 - k**3) + polygamma(0, 1 + n**2))*binomial(n**2, k**3) assert binomial(n, k).diff(k) == \ (-polygamma(0, 1 + k) + polygamma(0, 1 + n - k))*binomial(n, k) assert binomial(n**2, k**3).diff(k) == \ - 3*k**2*(-polygamma(0, 1 + k**3) + polygamma(0, 1 + n**2 - k**3))*binomial(n**2, k**3) + 3*k**2*(-polygamma( + 0, 1 + k**3) + polygamma(0, 1 + n**2 - k**3))*binomial(n**2, k**3) + def test_binomial_rewrite(): n = Symbol('n', integer=True) k = Symbol('k', integer=True) - assert binomial(n, k).rewrite(factorial) == factorial(n)/(factorial(k)*factorial(n - k)) - assert binomial(n, k).rewrite(gamma) == gamma(n + 1)/(gamma(k + 1)*gamma(n - k + 1)) + assert binomial(n, k).rewrite( + factorial) == factorial(n)/(factorial(k)*factorial(n - k)) + assert binomial( + n, k).rewrite(gamma) == gamma(n + 1)/(gamma(k + 1)*gamma(n - k + 1)) + @XFAIL def test_factorial_simplify_fail(): @@ -149,3 +171,10 @@ from sympy.abc import x assert simplify(x*polygamma(0, x + 1) - x*polygamma(0, x + 2) + polygamma(0, x + 1) - polygamma(0, x + 2) + 1) == 0 + + +def test_subfactorial(): + assert all(subfactorial(i) == ans for i, ans in enumerate( + [1, 0, 1, 2, 9, 44, 265, 1854, 14833, 133496])) + raises(ValueError, lambda: subfactorial(0.1)) + raises(ValueError, lambda: subfactorial(-2)) diff -Nru python3-sympy-0.7.2/sympy/functions/combinatorial/tests/test_comb_numbers.py python3-sympy-0.7.3/sympy/functions/combinatorial/tests/test_comb_numbers.py --- python3-sympy-0.7.2/sympy/functions/combinatorial/tests/test_comb_numbers.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/functions/combinatorial/tests/test_comb_numbers.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,33 +1,34 @@ -from sympy import bernoulli, Symbol, symbols, Sum, harmonic, Rational, oo, \ - zoo, pi, I, bell, fibonacci, lucas, euler, catalan, \ - binomial, gamma, sqrt, hyper, log, polygamma, diff, \ - Expr, sympify +from sympy import (bernoulli, Symbol, symbols, Dummy, Sum, harmonic, Rational, oo, + zoo, pi, I, bell, fibonacci, lucas, euler, catalan, binomial, gamma, sqrt, + hyper, log, digamma, trigamma, polygamma, diff, Expr, sympify, expand_func, + EulerGamma, factorial) -from sympy.utilities.pytest import XFAIL +from sympy.utilities.pytest import XFAIL, raises x = Symbol('x') + def test_bernoulli(): assert bernoulli(0) == 1 - assert bernoulli(1) == Rational(-1,2) - assert bernoulli(2) == Rational(1,6) + assert bernoulli(1) == Rational(-1, 2) + assert bernoulli(2) == Rational(1, 6) assert bernoulli(3) == 0 - assert bernoulli(4) == Rational(-1,30) + assert bernoulli(4) == Rational(-1, 30) assert bernoulli(5) == 0 - assert bernoulli(6) == Rational(1,42) + assert bernoulli(6) == Rational(1, 42) assert bernoulli(7) == 0 - assert bernoulli(8) == Rational(-1,30) - assert bernoulli(10) == Rational(5,66) + assert bernoulli(8) == Rational(-1, 30) + assert bernoulli(10) == Rational(5, 66) assert bernoulli(1000001) == 0 assert bernoulli(0, x) == 1 - assert bernoulli(1, x) == x-Rational(1,2) - assert bernoulli(2, x) == x**2-x+Rational(1,6) + assert bernoulli(1, x) == x - Rational(1, 2) + assert bernoulli(2, x) == x**2 - x + Rational(1, 6) assert bernoulli(3, x) == x**3 - (3*x**2)/2 + x/2 # Should be fast; computed with mpmath b = bernoulli(1000) - assert b.p % 10**10 == 7950421099 + assert b.p % 10**10 == 7950421099 assert b.q == 342999030 b = bernoulli(10**6, evaluate=False).evalf() @@ -45,6 +46,7 @@ assert fibonacci(3, x) == x**2 + 1 assert fibonacci(4, x) == x**3 + 2*x + def test_bell(): assert [bell(n) for n in range(8)] == [1, 1, 2, 5, 15, 52, 203, 877] @@ -59,7 +61,8 @@ # but we must supply zero-based indexed object X[1:] = (x1, .. x5) assert bell(6, 2, X[1:]) == 6*X[5]*X[1] + 15*X[4]*X[2] + 10*X[3]**2 - assert bell(6, 3, X[1:]) == 15*X[4]*X[1]**2 + 60*X[3]*X[2]*X[1] + 15*X[2]**3 + assert bell( + 6, 3, X[1:]) == 15*X[4]*X[1]**2 + 60*X[3]*X[2]*X[1] + 15*X[2]**3 X = (1, 10, 100, 1000, 10000) assert bell(6, 2, X) == (6 + 15 + 10)*10000 @@ -70,16 +73,57 @@ X = (1, 2, 3, 5) assert bell(6, 3, X) == 15*5 + 60*3*2 + 15*2**3 + def test_harmonic(): - assert harmonic(1,1) == 1 - assert harmonic(2,1) == Rational(3,2) - assert harmonic(3,1) == Rational(11,6) - assert harmonic(4,1) == Rational(25,12) - assert harmonic(3,1) == harmonic(3) - assert harmonic(3,5) == 1 + Rational(1,2**5) + Rational(1,3**5) - assert harmonic(10,0) == 10 - assert harmonic(oo,1) == zoo - assert harmonic(oo,2) == (pi**2)/6 + assert harmonic(1, 1) == 1 + assert harmonic(2, 1) == Rational(3, 2) + assert harmonic(3, 1) == Rational(11, 6) + assert harmonic(4, 1) == Rational(25, 12) + assert harmonic(3, 1) == harmonic(3) + assert harmonic(3, 5) == 1 + Rational(1, 2**5) + Rational(1, 3**5) + assert harmonic(10, 0) == 10 + assert harmonic(oo, 1) == zoo + assert harmonic(oo, 2) == (pi**2)/6 + + +def replace_dummy(expr, sym): + dum = expr.atoms(Dummy) + if not dum: + return expr + assert len(dum) == 1 + return expr.xreplace({dum.pop(): sym}) + + +def test_harmonic_rewrite_sum(): + n = Symbol("n") + m = Symbol("m") + + _k = Dummy("k") + assert replace_dummy(harmonic(n).rewrite(Sum), _k) == Sum(1/_k, (_k, 1, n)) + assert replace_dummy(harmonic(n, m).rewrite(Sum), _k) == Sum(_k**(-m), (_k, 1, n)) + + +@XFAIL +def test_harmonic_rewrite_sum(): + n = Symbol("n") + m = Symbol("m") + + assert harmonic(n).rewrite(digamma) == polygamma(0, n + 1) + EulerGamma + assert harmonic(n).rewrite(trigamma) == polygamma(0, n + 1) + EulerGamma + assert harmonic(n).rewrite(polygamma) == polygamma(0, n + 1) + EulerGamma + + assert harmonic(n,3).rewrite(polygamma) == polygamma(2, n + 1)/2 - polygamma(2, 1)/2 + assert harmonic(n,m).rewrite(polygamma) == (-1)**m*(polygamma(m - 1, 1) - polygamma(m - 1, n + 1))/factorial(m - 1) + + assert expand_func(harmonic(n+4)) == harmonic(n) + 1/(n + 4) + 1/(n + 3) + 1/(n + 2) + 1/(n + 1) + assert expand_func(harmonic(n-4)) == harmonic(n) - 1/(n - 1) - 1/(n - 2) - 1/(n - 3) - 1/n + + assert harmonic(n, m).rewrite("tractable") == harmonic(n, m).rewrite(polygamma) + + _k = Dummy("k") + assert harmonic(n).rewrite(Sum) == Sum(1/_k, (_k, 1, n)) + assert harmonic(n, m).rewrite(Sum) == Sum(_k**(-m), (_k, 1, n)) + def test_euler(): assert euler(0) == 1 @@ -101,12 +145,14 @@ assert euler(n).rewrite(Sum) == euler(n) # XXX: Not sure what the guy who wrote this test was trying to do with the _j and _k stuff - assert euler(2*n+1).rewrite(Sum) == 0 + assert euler(2*n + 1).rewrite(Sum) == 0 + @XFAIL def test_euler_failing(): # depends on dummy variables being implemented http://code.google.com/p/sympy/issues/detail?id=2566 - assert euler(2*n).rewrite(Sum) == I*Sum(Sum((-1)**_j*2**(-_k)*I**(-_k)*(-2*_j + _k)**(2*n + 1)*binomial(_k, _j)/_k, (_j, 0, _k)), (_k, 1, 2*n + 1)) + assert euler(2*n).rewrite(Sum) == I*Sum(Sum((-1)**_j*2**(-_k)*I**(-_k)*(-2*_j + _k)**(2*n + 1)*binomial(_k, _j)/_k, (_j, 0, _k)), (_k, 1, 2*n + 1)) + def test_catalan(): assert catalan(1) == 1 @@ -116,11 +162,170 @@ assert catalan(x) == catalan(x) assert catalan(2*x).rewrite(binomial) == binomial(4*x, 2*x)/(2*x + 1) - assert catalan(Rational(1,2)).rewrite(gamma) == 8/(3*pi) - assert catalan(3*x).rewrite(gamma) == 4**(3*x)*gamma(3*x + Rational(1,2))/(sqrt(pi)*gamma(3*x + 2)) + assert catalan(Rational(1, 2)).rewrite(gamma) == 8/(3*pi) + assert catalan(3*x).rewrite(gamma) == 4**( + 3*x)*gamma(3*x + Rational(1, 2))/(sqrt(pi)*gamma(3*x + 2)) assert catalan(x).rewrite(hyper) == hyper((-x + 1, -x), (2,), 1) - assert diff(catalan(x),x) == (polygamma(0, x + Rational(1,2)) - polygamma(0, x + 2) + 2*log(2))*catalan(x) + assert diff(catalan(x), x) == (polygamma( + 0, x + Rational(1, 2)) - polygamma(0, x + 2) + log(4))*catalan(x) c = catalan(0.5).evalf() assert str(c) == '0.848826363156775' + + +def test_nC_nP_nT(): + from sympy.utilities.iterables import ( + multiset_permutations, multiset_combinations, multiset_partitions, + partitions, subsets, permutations) + from sympy.functions.combinatorial.numbers import ( + nP, nC, nT, stirling, _multiset_histogram, _AOP_product) + from sympy.combinatorics.permutations import Permutation + from sympy.core.numbers import oo + from random import choice + + c = 'abcdefghijklmnopqrstuvwxyz' + for i in range(100): + s = ''.join(choice(c) for i in range(7)) + u = len(s) == len(set(s)) + try: + tot = 0 + for i in range(8): + check = nP(s, i) + tot += check + assert len(list(multiset_permutations(s, i))) == check + if u: + assert nP(len(s), i) == check + assert nP(s) == tot + except AssertionError: + print(s, i, 'failed perm test') + raise ValueError() + + for i in range(100): + s = ''.join(choice(c) for i in range(7)) + u = len(s) == len(set(s)) + try: + tot = 0 + for i in range(8): + check = nC(s, i) + tot += check + assert len(list(multiset_combinations(s, i))) == check + if u: + assert nC(len(s), i) == check + assert nC(s) == tot + if u: + assert nC(len(s)) == tot + except AssertionError: + print(s, i, 'failed combo test') + raise ValueError() + + for i in range(1, 10): + tot = 0 + for j in range(1, i + 2): + check = nT(i, j) + tot += check + assert sum(1 for p in partitions(i, j, size=True) if p[0] == j) == check + assert nT(i) == tot + + for i in range(1, 10): + tot = 0 + for j in range(1, i + 2): + check = nT(list(range(i)), j) + tot += check + assert len(list(multiset_partitions(list(range(i)), j))) == check + assert nT(list(range(i))) == tot + + for i in range(100): + s = ''.join(choice(c) for i in range(7)) + u = len(s) == len(set(s)) + try: + tot = 0 + for i in range(1, 8): + check = nT(s, i) + tot += check + assert len(list(multiset_partitions(s, i))) == check + if u: + assert nT(list(range(len(s))), i) == check + if u: + assert nT(list(range(len(s)))) == tot + assert nT(s) == tot + except AssertionError: + print(s, i, 'failed partition test') + raise ValueError() + + # tests for Stirling numbers of the first kind that are not tested in the + # above + assert [stirling(9, i, kind=1) for i in range(11)] == [ + 0, 40320, 109584, 118124, 67284, 22449, 4536, 546, 36, 1, 0] + perms = list(permutations(list(range(4)))) + assert [sum(1 for p in perms if Permutation(p).cycles == i) + for i in range(5)] == [0, 6, 11, 6, 1] == [ + stirling(4, i, kind=1) for i in range(5)] + # http://oeis.org/A008275 + assert [stirling(n, k, signed=1) + for n in range(10) for k in range(1, n + 1)] == [ + 1, -1, + 1, 2, -3, + 1, -6, 11, -6, + 1, 24, -50, 35, -10, + 1, -120, 274, -225, 85, -15, + 1, 720, -1764, 1624, -735, 175, -21, + 1, -5040, 13068, -13132, 6769, -1960, 322, -28, + 1, 40320, -109584, 118124, -67284, 22449, -4536, 546, -36, 1] + # http://en.wikipedia.org/wiki/Stirling_numbers_of_the_first_kind + assert [stirling(n, k, kind=1) + for n in range(10) for k in range(n+1)] == [ + 1, + 0, 1, + 0, 1, 1, + 0, 2, 3, 1, + 0, 6, 11, 6, 1, + 0, 24, 50, 35, 10, 1, + 0, 120, 274, 225, 85, 15, 1, + 0, 720, 1764, 1624, 735, 175, 21, 1, + 0, 5040, 13068, 13132, 6769, 1960, 322, 28, 1, + 0, 40320, 109584, 118124, 67284, 22449, 4536, 546, 36, 1] + # http://en.wikipedia.org/wiki/Stirling_numbers_of_the_second_kind + assert [stirling(n, k, kind=2) + for n in range(10) for k in range(n+1)] == [ + 1, + 0, 1, + 0, 1, 1, + 0, 1, 3, 1, + 0, 1, 7, 6, 1, + 0, 1, 15, 25, 10, 1, + 0, 1, 31, 90, 65, 15, 1, + 0, 1, 63, 301, 350, 140, 21, 1, + 0, 1, 127, 966, 1701, 1050, 266, 28, 1, + 0, 1, 255, 3025, 7770, 6951, 2646, 462, 36, 1] + assert stirling(3, 4, kind=1) == stirling(3, 4, kind=1) == 0 + raises(ValueError, lambda: stirling(-2, 2)) + + def delta(p): + if len(p) == 1: + return oo + return min(abs(i[0] - i[1]) for i in subsets(p, 2)) + parts = multiset_partitions(list(range(5)), 3) + d = 2 + assert (sum(1 for p in parts if all(delta(i) >= d for i in p)) == + stirling(5, 3, d=d) == 7) + + # other coverage tests + assert nC('abb', 2) == nC('aab', 2) == 2 + assert nP(3, 3, replacement=True) == nP('aabc', 3, replacement=True) == 27 + assert nP(3, 4) == 0 + assert nP('aabc', 5) == 0 + assert nC(4, 2, replacement=True) == nC('abcdd', 2, replacement=True) == \ + len(list(multiset_combinations('aabbccdd', 2))) == 10 + assert nC('abcdd') == sum(nC('abcdd', i) for i in range(6)) == 24 + assert nC(list('abcdd'), 4) == 4 + assert nT('aaaa') == nT(4) == len(list(partitions(4))) == 5 + assert nT('aaab') == len(list(multiset_partitions('aaab'))) == 7 + assert nC('aabb'*3, 3) == 4 # aaa, bbb, abb, baa + assert dict(_AOP_product((4,1,1,1))) == { + 0: 1, 1: 4, 2: 7, 3: 8, 4: 8, 5: 7, 6: 4, 7: 1} + # the following was the first t that showed a problem in a previous form of + # the function, so it's not as random as it may appear + t = (3, 9, 4, 6, 6, 5, 5, 2, 10, 4) + assert sum(_AOP_product(t)[i] for i in range(55)) == 58212000 + raises(ValueError, lambda: _multiset_histogram({1:'a'})) diff -Nru python3-sympy-0.7.2/sympy/functions/elementary/complexes.py python3-sympy-0.7.3/sympy/functions/elementary/complexes.py --- python3-sympy-0.7.2/sympy/functions/elementary/complexes.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/functions/elementary/complexes.py 2013-07-13 17:53:32.000000000 +0000 @@ -4,11 +4,13 @@ from sympy.functions.elementary.piecewise import Piecewise from sympy.core import Add, Mul from sympy.core.relational import Eq +from sympy.functions.elementary.trigonometric import atan, atan2 ############################################################################### ######################### REAL and IMAGINARY PARTS ############################ ############################################################################### + class re(Function): """Returns real part of expression. This function performs only elementary analysis and so it will fail to decompose properly @@ -39,7 +41,7 @@ nargs = 1 is_real = True - unbranched = True # implicitely works on the projection to C + unbranched = True # implicitely works on the projection to C @classmethod def eval(cls, arg): @@ -127,7 +129,7 @@ nargs = 1 is_real = True - unbranched = True # implicitely works on the projection to C + unbranched = True # implicitely works on the projection to C @classmethod def eval(cls, arg): @@ -216,6 +218,9 @@ nargs = 1 + is_bounded = True + is_complex = True + def doit(self): if self.args[0].is_nonzero: return self.args[0] / Abs(self.args[0]) @@ -223,9 +228,33 @@ @classmethod def eval(cls, arg): + # handle what we can + if arg.is_Mul: + c, args = arg.as_coeff_mul() + unk = [] + is_imag = c.is_imaginary + is_neg = c.is_negative + for a in args: + if a.is_negative: + is_neg = not is_neg + elif a.is_positive: + pass + else: + ai = im(a) + if a.is_imaginary and ai.is_comparable: # i.e. a = I*real + is_imag = not is_imag + if ai.is_negative: + is_neg = not is_neg + else: + unk.append(a) + if c is S.One and len(unk) == len(args): + return None + return (S.NegativeOne if is_neg else S.One) \ + * (S.ImaginaryUnit if is_imag else S.One) \ + * cls(arg._new_rawargs(*unk)) if arg is S.NaN: return S.NaN - if arg is S.Zero: + if arg.is_zero: # it may be an Expr that is zero return S.Zero if arg.is_positive: return S.One @@ -240,27 +269,6 @@ return S.ImaginaryUnit if arg2.is_negative: return -S.ImaginaryUnit - if arg.is_Mul: - c, args = arg.as_coeff_mul() - unk = [] - is_imag = c.is_imaginary - is_neg = c.is_negative - for ai in args: - ai2 = -S.ImaginaryUnit * ai - if ai.is_negative: - is_neg = not is_neg - elif ai.is_imaginary and ai2.is_positive: - is_imag = not is_imag - elif ai.is_negative is None or \ - (ai.is_imaginary is None or ai2.is_positive is None): - unk.append(ai) - if c is S.One and len(unk) == len(args): - return None - return (S.NegativeOne if is_neg else S.One) \ - * (S.ImaginaryUnit if is_imag else S.One) \ - * cls(arg._new_rawargs(*unk)) - - is_bounded = True def _eval_Abs(self): if self.args[0].is_nonzero: @@ -279,6 +287,12 @@ return 2 * Derivative(self.args[0], x, **{'evaluate': True}) \ * DiracDelta(-S.ImaginaryUnit * self.args[0]) + def _eval_is_imaginary(self): + return self.args[0].is_imaginary + + def _eval_is_integer(self): + return self.args[0].is_real + def _eval_is_zero(self): return self.args[0].is_zero @@ -288,13 +302,18 @@ self.args[0].is_nonzero and other.is_integer and other.is_even - ): + ): return S.One def _sage_(self): import sage.all as sage return sage.sgn(self.args[0]._sage_()) + def _eval_rewrite_as_Piecewise(self, arg): + if arg.is_real: + return Piecewise((1, arg > 0), (-1, arg < 0), (0, True)) + + class Abs(Function): """ Return the absolute value of the argument. @@ -362,6 +381,7 @@ obj = arg._eval_Abs() if obj is not None: return obj + # handle what we can if arg.is_Mul: known = [] unk = [] @@ -376,6 +396,8 @@ return known*unk if arg is S.NaN: return S.NaN + if arg.is_zero: # it may be an Expr that is zero + return S.Zero if arg.is_nonnegative: return arg if arg.is_nonpositive: @@ -412,9 +434,9 @@ s = self.args[0]._eval_nseries(x, n=n, logx=logx) when = Eq(direction, 0) return Piecewise( - ((s.subs(direction, 0)), when), - (sign(direction)*s, True), - ) + ((s.subs(direction, 0)), when), + (sign(direction)*s, True), + ) def _sage_(self): import sage.all as sage @@ -433,8 +455,11 @@ # for complex arguments). if arg.is_real: return arg*(C.Heaviside(arg) - C.Heaviside(-arg)) - else: - return self + + def _eval_rewrite_as_Piecewise(self, arg): + if arg.is_real: + return Piecewise((arg, arg >= 0), (-arg, True)) + class arg(Function): """Returns the argument (in radians) of a complex number""" @@ -456,6 +481,10 @@ return (x * Derivative(y, t, **{'evaluate': True}) - y * Derivative(x, t, **{'evaluate': True})) / (x**2 + y**2) + def _eval_rewrite_as_atan2(self, arg): + x, y = re(self.args[0]), im(self.args[0]) + return atan2(y, x) + class conjugate(Function): """ Changes the sign of the imaginary part of a complex number. @@ -498,7 +527,8 @@ return -conjugate(Derivative(self.args[0], x, **{'evaluate': True})) def _eval_transpose(self): - return conjugate(transpose(self.args[0])) + return adjoint(self.args[0]) + class transpose(Function): """ @@ -516,12 +546,13 @@ def _eval_adjoint(self): return conjugate(self.args[0]) - def _eval_derivative(self, x): - return transpose(Derivative(self.args[0], x, **{'evaluate': True})) + def _eval_conjugate(self): + return adjoint(self.args[0]) def _eval_transpose(self): return self.args[0] + class adjoint(Function): """ Conjugate transpose or Hermite conjugation. @@ -544,9 +575,6 @@ def _eval_conjugate(self): return transpose(self.args[0]) - def _eval_derivative(self, x): - return adjoint(Derivative(self.args[0], x, **{'evaluate': True})) - def _eval_transpose(self): return conjugate(self.args[0]) @@ -570,6 +598,7 @@ ############### HANDLING OF POLAR NUMBERS ##################################### ############################################################################### + class polar_lift(Function): """ Lift argument to the riemann surface of the logarithm, using the @@ -602,7 +631,7 @@ nargs = 1 is_polar = True - is_comparable = False # Cannot be evalf'd. + is_comparable = False # Cannot be evalf'd. @classmethod def eval(cls, arg): @@ -639,6 +668,7 @@ """ Careful! any evalf of polar numbers is flaky """ return self.args[0]._eval_evalf(prec) + class periodic_argument(Function): """ Represent the argument on a quotient of the riemann surface of the @@ -683,7 +713,8 @@ unbranched += a.exp.as_real_imag()[1] elif a.is_Pow: re, im = a.exp.as_real_imag() - unbranched += re*unbranched_argument(a.base) + im*log(abs(a.base)) + unbranched += re*unbranched_argument( + a.base) + im*log(abs(a.base)) elif a.func is polar_lift: unbranched += arg(a.args[0]) else: @@ -730,10 +761,12 @@ ub = periodic_argument(z, oo)._eval_evalf(prec) return (ub - ceiling(ub/period - S(1)/2)*period)._eval_evalf(prec) + def unbranched_argument(arg): from sympy import oo return periodic_argument(arg, oo) + class principal_branch(Function): """ Represent a polar number reduced to its principal branch on a quotient @@ -762,7 +795,7 @@ nargs = 2 is_polar = True - is_comparable = False # cannot always be evalf'd + is_comparable = False # cannot always be evalf'd @classmethod def eval(self, x, period): @@ -774,8 +807,9 @@ ub = periodic_argument(x, oo) barg = periodic_argument(x, period) if ub != barg and not ub.has(periodic_argument) \ - and not barg.has(periodic_argument): + and not barg.has(periodic_argument): pl = polar_lift(x) + def mr(expr): if not isinstance(expr, Symbol): return polar_lift(expr) @@ -801,13 +835,13 @@ arg = periodic_argument(c, period) if arg.has(periodic_argument): return None - if arg.is_number and (unbranched_argument(c) != arg or \ + if arg.is_number and (unbranched_argument(c) != arg or (arg == 0 and m != () and c != 1)): if arg == 0: return abs(c)*principal_branch(Mul(*m), period) return principal_branch(exp_polar(I*arg)*Mul(*m), period)*abs(c) if arg.is_number and ((abs(arg) < period/2) is True or arg == period/2) \ - and m == (): + and m == (): return exp_polar(arg*I)*abs(c) def _eval_evalf(self, prec): @@ -815,7 +849,7 @@ z, period = self.args p = periodic_argument(z, period)._eval_evalf(prec) if abs(p) > pi or p == -pi: - return self # Cannot evalf for this argument. + return self # Cannot evalf for this argument. return (abs(z)*exp(I*p))._eval_evalf(prec) # /cyclic/ diff -Nru python3-sympy-0.7.2/sympy/functions/elementary/exponential.py python3-sympy-0.7.3/sympy/functions/elementary/exponential.py --- python3-sympy-0.7.2/sympy/functions/elementary/exponential.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/functions/elementary/exponential.py 2013-07-13 17:53:32.000000000 +0000 @@ -20,6 +20,7 @@ # log(x(1+p)), this *has* to be expanded to log(x)+log(1+p) if x.is_positive and # p.is_positive.] + class ExpBase(Function): nargs = 1 @@ -49,7 +50,7 @@ # exponent handling exp = self.exp neg_exp = exp.is_negative - if not neg_exp and not exp.is_real: + if not neg_exp and not (-exp).is_negative: neg_exp = _coeff_isneg(exp) if neg_exp: return S.One, self.func(-exp) @@ -124,6 +125,7 @@ return expr return self.func(arg) + class exp_polar(ExpBase): r""" Represent a 'polar number' (see g-function Sphinx documentation). @@ -157,7 +159,7 @@ """ is_polar = True - is_comparable = False # cannot be evalf'd + is_comparable = False # cannot be evalf'd def _eval_Abs(self): from sympy import expand_mul @@ -168,7 +170,7 @@ from sympy import im, pi, re i = im(self.args[0]) if i <= -pi or i > pi: - return self # cannot evalf for this argument + return self # cannot evalf for this argument res = exp(self.args[0])._eval_evalf(prec) if i > 0 and im(res) < 0: # i ~ pi, but exp(I*i) evaluated to argument slightly bigger than pi @@ -185,6 +187,7 @@ return self, S(1) return ExpBase.as_base_exp(self) + class exp(ExpBase): """ The exponential function, :math:`e^x`. @@ -236,6 +239,9 @@ elif (coeff + S.Half).is_odd: return S.ImaginaryUnit + # Warning: code in risch.py will be very sensitive to changes + # in this (see DifferentialExtension). + # look for a single log factor coeff, terms = arg.as_coeff_Mul() @@ -332,18 +338,19 @@ def _eval_subs(self, old, new): arg = self.args[0] o = old - if old.is_Pow: # handle (exp(3*log(x))).subs(x**2, z) -> z**(3/2) + if old.is_Pow: # handle (exp(3*log(x))).subs(x**2, z) -> z**(3/2) o = exp(o.exp*log(o.base)) if o.func is exp: # exp(a*expr) .subs( exp(b*expr), y ) -> y ** (a/b) - a, expr_terms = self.args[0].as_coeff_mul() - b, expr_terms_= o.args[0].as_coeff_mul() + a, expr_terms = self.args[0].as_independent( + C.Symbol, as_Add=False) + b, expr_terms_ = o.args[0].as_independent( + C.Symbol, as_Add=False) if expr_terms == expr_terms_: return new**(a/b) - - if arg.is_Add: # exp(2*x+a).subs(exp(3*x),y) -> y**(2/3) * exp(a) + if arg.is_Add: # exp(2*x+a).subs(exp(3*x),y) -> y**(2/3) * exp(a) # exp(exp(x) + exp(x**2)).subs(exp(exp(x)), w) -> w * exp(exp(x**2)) oarg = o.args[0] new_l = [] @@ -362,8 +369,8 @@ return r if o is S.Exp1: # treat this however Pow is being treated - u = C.Dummy('u') - return (u**self.args[0]).subs(u, new) + u = C.Dummy('u', positive=True) + return (u**self.args[0]).xreplace({u: new}) return Function._eval_subs(self, o, new) @@ -424,25 +431,29 @@ if arg.is_Add: return Mul(*[exp(f).as_leading_term(x) for f in arg.args]) arg = self.args[0].as_leading_term(x) - if C.Order(1,x).contains(arg): + if C.Order(1, x).contains(arg): return S.One return exp(arg) def _eval_rewrite_as_sin(self, arg): I = S.ImaginaryUnit - return C.sin(I*arg+S.Pi/2) - I*C.sin(I*arg) + return C.sin(I*arg + S.Pi/2) - I*C.sin(I*arg) def _eval_rewrite_as_cos(self, arg): I = S.ImaginaryUnit - return C.cos(I*arg) + I*C.cos(I*arg+S.Pi/2) + return C.cos(I*arg) + I*C.cos(I*arg + S.Pi/2) def _sage_(self): import sage.all as sage return sage.exp(self.args[0]._sage_()) + class log(Function): """ - The logarithmic function :math:`ln(x)` or :math:`log(x)`. + The natural logarithm function `\ln(x)` or `\log(x)`. + Logarithms are taken with the natural base, `e`. To get + a logarithm of a different base ``b``, use ``log(x, b)``, + which is essentially short-hand for ``log(x)/log(b)``. See Also ======== @@ -450,7 +461,7 @@ exp """ - nargs = (1,2) + nargs = (1, 2) def fdiff(self, argindex=1): """ @@ -465,7 +476,7 @@ def inverse(self, argindex=1): """ - Returns the inverse function, log(x) (or ln(x)). + Returns `e^x`, the inverse function of `\log(x)`. """ return exp @@ -482,10 +493,17 @@ else: return S.ComplexInfinity try: - if not (base.is_positive and arg.is_positive): - raise ValueError + # handle extraction of powers of the base now + # or else expand_log in Mul would have to handle this n = multiplicity(base, arg) - return n + log(arg // base ** n) / log(base) + if n: + den = base**n + if den.is_Integer: + return n + log(arg // den) / log(base) + else: + return n + log(arg / den) / log(base) + else: + return log(arg)/log(base) except ValueError: pass if base is not S.Exp1: @@ -509,10 +527,6 @@ elif arg.is_Rational: if arg.q != 1: return cls(arg.p) - cls(arg.q) - # remove perfect powers automatically - p = perfect_power(int(arg)) - if p is not False: - return p[1]*cls(p[0]) elif arg is S.ComplexInfinity: return S.ComplexInfinity elif arg is S.Exp1: @@ -544,9 +558,9 @@ @staticmethod @cacheit - def taylor_term(n, x, *previous_terms): # of log(1+x) + def taylor_term(n, x, *previous_terms): # of log(1+x) """ - Returns the next term in the Taylor series expansion of log(1+x). + Returns the next term in the Taylor series expansion of `\log(1+x)`. """ from sympy import powsimp if n < 0: @@ -557,14 +571,20 @@ if previous_terms: p = previous_terms[-1] if p is not None: - return powsimp((-n) * p * x / (n+1), deep=True, combine='exp') - return (1-2*(n%2)) * x**(n+1)/(n+1) + return powsimp((-n) * p * x / (n + 1), deep=True, combine='exp') + return (1 - 2*(n % 2)) * x**(n + 1)/(n + 1) def _eval_expand_log(self, deep=True, **hints): from sympy import unpolarify + from sympy.concrete import Sum, Product force = hints.get('force', False) arg = self.args[0] - if arg.is_Mul: + if arg.is_Integer: + # remove perfect powers + p = perfect_power(int(arg)) + if p is not False: + return p[1]*self.func(p[0]) + elif arg.is_Mul: expr = [] nonpos = [] for x in arg.args: @@ -579,10 +599,17 @@ return Add(*expr) + log(Mul(*nonpos)) elif arg.is_Pow: if force or (arg.exp.is_real and arg.base.is_positive) or \ - arg.base.is_polar: + arg.base.is_polar: b = arg.base e = arg.exp - return unpolarify(e) * self.func(b)._eval_expand_log(**hints) + a = self.func(b) + if isinstance(a, log): + return unpolarify(e) * a._eval_expand_log(**hints) + else: + return unpolarify(e) * a + elif isinstance(arg, Product): + if arg.function.is_positive: + return Sum(log(arg.function), *arg.limits) return self.func(arg) @@ -612,7 +639,7 @@ else: abs = C.Abs(self.args[0]) arg = C.arg(self.args[0]) - if hints.get('log', False): # Expand the log + if hints.get('log', False): # Expand the log hints['complex'] = False return (log(abs).expand(deep, **hints), arg) else: @@ -671,7 +698,7 @@ #l = r.get(l, S.Zero) k, l = r[k], r[l] if l != 0 and not l.has(x) and not k.has(x): - r = log(k) + l*logx # XXX true regardless of assumptions? + r = log(k) + l*logx # XXX true regardless of assumptions? return r # TODO new and probably slow @@ -689,7 +716,6 @@ l.append(g) return log(a) + b*logx + Add(*l) + C.Order(p**n, x) - def _eval_as_leading_term(self, x): arg = self.args[0].as_leading_term(x) if arg is S.One: @@ -700,6 +726,7 @@ import sage.all as sage return sage.log(self.args[0]._sage_()) + class LambertW(Function): """Lambert W function, defined as the inverse function of x*exp(x). This function represents the principal branch @@ -730,7 +757,7 @@ """ if argindex == 1: x = self.args[0] - return LambertW(x)/(x*(1+LambertW(x))) + return LambertW(x)/(x*(1 + LambertW(x))) else: raise ArgumentIndexError(self, argindex) diff -Nru python3-sympy-0.7.2/sympy/functions/elementary/hyperbolic.py python3-sympy-0.7.3/sympy/functions/elementary/hyperbolic.py --- python3-sympy-0.7.2/sympy/functions/elementary/hyperbolic.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/functions/elementary/hyperbolic.py 2013-07-13 17:53:32.000000000 +0000 @@ -7,14 +7,23 @@ ########################### HYPERBOLIC FUNCTIONS ############################## ############################################################################### + class HyperbolicFunction(Function): - """Base class for hyperbolic functions. """ + """ + Base class for hyperbolic functions. + + See Also + ======== + + sinh, cosh, tanh, coth + """ unbranched = True + class sinh(HyperbolicFunction): - """ - The hyperbolic sine function, :math:`\\frac{exp(x) - exp(-x)}{2}`. + r""" + The hyperbolic sine function, `\frac{e^x - e^{-x}}{2}`. * sinh(x) -> Returns the hyperbolic sine of x @@ -72,15 +81,15 @@ if arg.func == acosh: x = arg.args[0] - return sqrt(x-1) * sqrt(x+1) + return sqrt(x - 1) * sqrt(x + 1) if arg.func == atanh: x = arg.args[0] - return x/sqrt(1-x**2) + return x/sqrt(1 - x**2) if arg.func == acoth: x = arg.args[0] - return 1/(sqrt(x-1) * sqrt(x+1)) + return 1/(sqrt(x - 1) * sqrt(x + 1)) @staticmethod @cacheit @@ -95,7 +104,7 @@ if len(previous_terms) > 2: p = previous_terms[-2] - return p * x**2 / (n*(n-1)) + return p * x**2 / (n*(n - 1)) else: return x**(n) / C.factorial(n) @@ -118,6 +127,27 @@ re, im = self.args[0].as_real_imag() return (sinh(re)*C.cos(im), cosh(re)*C.sin(im)) + def _eval_expand_complex(self, deep=True, **hints): + re_part, im_part = self.as_real_imag(deep=deep, **hints) + return re_part + im_part*S.ImaginaryUnit + + def _eval_expand_trig(self, deep=True, **hints): + if deep: + arg = self.args[0].expand(deep, **hints) + else: + arg = self.args[0] + x = None + if arg.is_Add: # TODO, implement more if deep stuff here + x, y = arg.as_two_terms() + else: + coeff, terms = arg.as_coeff_Mul(rational=True) + if coeff is not S.One and coeff.is_Integer and terms is not S.One: + x = terms + y = (coeff - 1)*x + if x is not None: + return (sinh(x)*cosh(y) + sinh(y)*cosh(x)).expand(trig=True) + return sinh(arg) + def _eval_rewrite_as_exp(self, arg): return (C.exp(arg) - C.exp(-arg)) / 2 @@ -152,9 +182,10 @@ import sage.all as sage return sage.sinh(self.args[0]._sage_()) + class cosh(HyperbolicFunction): - """ - The hyperbolic cosine function, :math:`\\frac{exp(x) + exp(-x)}{2}`. + r""" + The hyperbolic cosine function, `\frac{e^x + e^{-x}}{2}`. * cosh(x) -> Returns the hyperbolic cosine of x @@ -171,12 +202,6 @@ else: raise ArgumentIndexError(self, argindex) - def inverse(self, argindex=1): - """ - Returns the inverse of this function. - """ - return acosh - @classmethod def eval(cls, arg): arg = sympify(arg) @@ -205,17 +230,17 @@ return cls(-arg) if arg.func == asinh: - return sqrt(1+arg.args[0]**2) + return sqrt(1 + arg.args[0]**2) if arg.func == acosh: return arg.args[0] if arg.func == atanh: - return 1/sqrt(1-arg.args[0]**2) + return 1/sqrt(1 - arg.args[0]**2) if arg.func == acoth: x = arg.args[0] - return x/(sqrt(x-1) * sqrt(x+1)) + return x/(sqrt(x - 1) * sqrt(x + 1)) @staticmethod @cacheit @@ -227,7 +252,7 @@ if len(previous_terms) > 2: p = previous_terms[-2] - return p * x**2 / (n*(n-1)) + return p * x**2 / (n*(n - 1)) else: return x**(n)/C.factorial(n) @@ -248,6 +273,27 @@ return (cosh(re)*C.cos(im), sinh(re)*C.sin(im)) + def _eval_expand_complex(self, deep=True, **hints): + re_part, im_part = self.as_real_imag(deep=deep, **hints) + return re_part + im_part*S.ImaginaryUnit + + def _eval_expand_trig(self, deep=True, **hints): + if deep: + arg = self.args[0].expand(deep, **hints) + else: + arg = self.args[0] + x = None + if arg.is_Add: # TODO, implement more if deep stuff here + x, y = arg.as_two_terms() + else: + coeff, terms = arg.as_coeff_Mul(rational=True) + if coeff is not S.One and coeff.is_Integer and terms is not S.One: + x = terms + y = (coeff - 1)*x + if x is not None: + return (cosh(x)*cosh(y) + sinh(x)*sinh(y)).expand(trig=True) + return cosh(arg) + def _eval_rewrite_as_exp(self, arg): return (C.exp(arg) + C.exp(-arg)) / 2 @@ -256,11 +302,11 @@ def _eval_rewrite_as_tanh(self, arg): tanh_half = tanh(S.Half*arg)**2 - return (1+tanh_half)/(1-tanh_half) + return (1 + tanh_half)/(1 - tanh_half) def _eval_rewrite_as_coth(self, arg): coth_half = coth(S.Half*arg)**2 - return (coth_half+1)/(coth_half-1) + return (coth_half + 1)/(coth_half - 1) def _eval_as_leading_term(self, x): arg = self.args[0].as_leading_term(x) @@ -282,9 +328,10 @@ import sage.all as sage return sage.cosh(self.args[0]._sage_()) + class tanh(HyperbolicFunction): - """ - The hyperbolic tangent function, :math:`\\frac{sinh(x)}{cosh(x)}`. + r""" + The hyperbolic tangent function, `\frac{\sinh(x)}{\cosh(x)}`. * tanh(x) -> Returns the hyperbolic tangent of x @@ -338,11 +385,11 @@ if arg.func == asinh: x = arg.args[0] - return x/sqrt(1+x**2) + return x/sqrt(1 + x**2) if arg.func == acosh: x = arg.args[0] - return sqrt(x-1) * sqrt(x+1) / x + return sqrt(x - 1) * sqrt(x + 1) / x if arg.func == atanh: return arg.args[0] @@ -358,12 +405,12 @@ else: x = sympify(x) - a = 2**(n+1) + a = 2**(n + 1) - B = C.bernoulli(n+1) - F = C.factorial(n+1) + B = C.bernoulli(n + 1) + F = C.factorial(n + 1) - return a*(a-1) * B/F * x**n + return a*(a - 1) * B/F * x**n def _eval_conjugate(self): return self.func(self.args[0].conjugate()) @@ -384,7 +431,7 @@ def _eval_rewrite_as_exp(self, arg): neg_exp, pos_exp = C.exp(-arg), C.exp(arg) - return (pos_exp-neg_exp)/(pos_exp+neg_exp) + return (pos_exp - neg_exp)/(pos_exp + neg_exp) def _eval_rewrite_as_sinh(self, arg): return S.ImaginaryUnit*sinh(arg)/sinh(S.Pi*S.ImaginaryUnit/2 - arg) @@ -415,9 +462,10 @@ import sage.all as sage return sage.tanh(self.args[0]._sage_()) + class coth(HyperbolicFunction): - """ - The hyperbolic tangent function, :math:`\\frac{cosh(x)}{sinh(x)}`. + r""" + The hyperbolic cotangent function, `\frac{\cosh(x)}{\sinh(x)}`. * coth(x) -> Returns the hyperbolic cotangent of x """ @@ -466,11 +514,11 @@ if arg.func == asinh: x = arg.args[0] - return sqrt(1+x**2)/x + return sqrt(1 + x**2)/x if arg.func == acosh: x = arg.args[0] - return x/(sqrt(x-1) * sqrt(x+1)) + return x/(sqrt(x - 1) * sqrt(x + 1)) if arg.func == atanh: return 1/arg.args[0] @@ -488,10 +536,10 @@ else: x = sympify(x) - B = C.bernoulli(n+1) - F = C.factorial(n+1) + B = C.bernoulli(n + 1) + F = C.factorial(n + 1) - return 2**(n+1) * B/F * x**n + return 2**(n + 1) * B/F * x**n def _eval_conjugate(self): return self.func(self.args[0].conjugate()) @@ -512,7 +560,7 @@ def _eval_rewrite_as_exp(self, arg): neg_exp, pos_exp = C.exp(-arg), C.exp(arg) - return (pos_exp+neg_exp)/(pos_exp-neg_exp) + return (pos_exp + neg_exp)/(pos_exp - neg_exp) def _eval_rewrite_as_sinh(self, arg): return -S.ImaginaryUnit*sinh(S.Pi*S.ImaginaryUnit/2 - arg)/sinh(arg) @@ -599,7 +647,7 @@ x = sympify(x) if len(previous_terms) >= 2 and n > 2: p = previous_terms[-2] - return -p * (n-2)**2/(n*(n-1)) * x**2 + return -p * (n - 2)**2/(n*(n - 1)) * x**2 else: k = (n - 1) // 2 R = C.RisingFactorial(S.Half, k) @@ -614,10 +662,17 @@ else: return self.func(arg) + def inverse(self, argindex=1): + """ + Returns the inverse of this function. + """ + return sinh + def _sage_(self): import sage.all as sage return sage.asinh(self.args[0]._sage_()) + class acosh(Function): """ The inverse hyperbolic cosine function. @@ -657,26 +712,26 @@ if arg.is_number: cst_table = { - S.ImaginaryUnit : C.log(S.ImaginaryUnit*(1+sqrt(2))), - -S.ImaginaryUnit : C.log(-S.ImaginaryUnit*(1+sqrt(2))), - S.Half : S.Pi/3, - -S.Half : 2*S.Pi/3, - sqrt(2)/2 : S.Pi/4, - -sqrt(2)/2 : 3*S.Pi/4, - 1/sqrt(2) : S.Pi/4, - -1/sqrt(2) : 3*S.Pi/4, - sqrt(3)/2 : S.Pi/6, - -sqrt(3)/2 : 5*S.Pi/6, - (sqrt(3)-1)/sqrt(2**3) : 5*S.Pi/12, - -(sqrt(3)-1)/sqrt(2**3) : 7*S.Pi/12, - sqrt(2+sqrt(2))/2 : S.Pi/8, - -sqrt(2+sqrt(2))/2 : 7*S.Pi/8, - sqrt(2-sqrt(2))/2 : 3*S.Pi/8, - -sqrt(2-sqrt(2))/2 : 5*S.Pi/8, - (1+sqrt(3))/(2*sqrt(2)) : S.Pi/12, - -(1+sqrt(3))/(2*sqrt(2)) : 11*S.Pi/12, - (sqrt(5)+1)/4 : S.Pi/5, - -(sqrt(5)+1)/4 : 4*S.Pi/5 + S.ImaginaryUnit: C.log(S.ImaginaryUnit*(1 + sqrt(2))), + -S.ImaginaryUnit: C.log(-S.ImaginaryUnit*(1 + sqrt(2))), + S.Half: S.Pi/3, + -S.Half: 2*S.Pi/3, + sqrt(2)/2: S.Pi/4, + -sqrt(2)/2: 3*S.Pi/4, + 1/sqrt(2): S.Pi/4, + -1/sqrt(2): 3*S.Pi/4, + sqrt(3)/2: S.Pi/6, + -sqrt(3)/2: 5*S.Pi/6, + (sqrt(3) - 1)/sqrt(2**3): 5*S.Pi/12, + -(sqrt(3) - 1)/sqrt(2**3): 7*S.Pi/12, + sqrt(2 + sqrt(2))/2: S.Pi/8, + -sqrt(2 + sqrt(2))/2: 7*S.Pi/8, + sqrt(2 - sqrt(2))/2: 3*S.Pi/8, + -sqrt(2 - sqrt(2))/2: 5*S.Pi/8, + (1 + sqrt(3))/(2*sqrt(2)): S.Pi/12, + -(1 + sqrt(3))/(2*sqrt(2)): 11*S.Pi/12, + (sqrt(5) + 1)/4: S.Pi/5, + -(sqrt(5) + 1)/4: 4*S.Pi/5 } if arg in cst_table: @@ -708,7 +763,7 @@ x = sympify(x) if len(previous_terms) >= 2 and n > 2: p = previous_terms[-2] - return p * (n-2)**2/(n*(n-1)) * x**2 + return p * (n - 2)**2/(n*(n - 1)) * x**2 else: k = (n - 1) // 2 R = C.RisingFactorial(S.Half, k) @@ -723,10 +778,17 @@ else: return self.func(arg) + def inverse(self, argindex=1): + """ + Returns the inverse of this function. + """ + return cosh + def _sage_(self): import sage.all as sage return sage.acosh(self.args[0]._sage_()) + class atanh(Function): """ The inverse hyperbolic tangent function. @@ -742,7 +804,7 @@ def fdiff(self, argindex=1): if argindex == 1: - return 1/(1-self.args[0]**2) + return 1/(1 - self.args[0]**2) else: raise ArgumentIndexError(self, argindex) @@ -794,10 +856,17 @@ else: return self.func(arg) + def inverse(self, argindex=1): + """ + Returns the inverse of this function. + """ + return tanh + def _sage_(self): import sage.all as sage return sage.atanh(self.args[0]._sage_()) + class acoth(Function): """ The inverse hyperbolic cotangent function. @@ -808,7 +877,7 @@ def fdiff(self, argindex=1): if argindex == 1: - return 1/(1-self.args[0]**2) + return 1/(1 - self.args[0]**2) else: raise ArgumentIndexError(self, argindex) @@ -862,6 +931,12 @@ else: return self.func(arg) + def inverse(self, argindex=1): + """ + Returns the inverse of this function. + """ + return coth + def _sage_(self): import sage.all as sage return sage.acoth(self.args[0]._sage_()) diff -Nru python3-sympy-0.7.2/sympy/functions/elementary/integers.py python3-sympy-0.7.3/sympy/functions/elementary/integers.py --- python3-sympy-0.7.2/sympy/functions/elementary/integers.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/functions/elementary/integers.py 2013-07-13 17:53:32.000000000 +0000 @@ -8,6 +8,7 @@ ######################### FLOOR and CEILING FUNCTIONS ######################### ############################################################################### + class RoundFunction(Function): """The base class for rounding functions.""" @@ -45,9 +46,10 @@ if npart and ( not spart or npart.is_real and spart.is_imaginary or - npart.is_imaginary and spart.is_real): + npart.is_imaginary and spart.is_real): try: - re, im = get_integer_part(npart, cls._dir, {}, return_ints=True) + re, im = get_integer_part( + npart, cls._dir, {}, return_ints=True) ipart += C.Integer(re) + C.Integer(im)*S.ImaginaryUnit npart = S.Zero except (PrecisionExhausted, NotImplementedError): @@ -70,6 +72,7 @@ def _eval_is_integer(self): return self.args[0].is_real + class floor(RoundFunction): """ Floor is a univariate function which returns the largest integer @@ -119,10 +122,11 @@ if direction.is_positive: return r else: - return r-1 + return r - 1 else: return r + class ceiling(RoundFunction): """ Ceiling is a univariate function which returns the smallest integer diff -Nru python3-sympy-0.7.2/sympy/functions/elementary/miscellaneous.py python3-sympy-0.7.3/sympy/functions/elementary/miscellaneous.py --- python3-sympy-0.7.2/sympy/functions/elementary/miscellaneous.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/functions/elementary/miscellaneous.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,14 +1,16 @@ from sympy.core import S, C, sympify +from sympy.core.add import Add from sympy.core.basic import Basic from sympy.core.containers import Tuple from sympy.core.numbers import Rational from sympy.core.operations import LatticeOp, ShortCircuit -from sympy.core.function import Application, Lambda +from sympy.core.function import Application, Lambda, ArgumentIndexError from sympy.core.expr import Expr from sympy.core.singleton import Singleton from sympy.core.rules import Transform from sympy.core.compatibility import as_int + class IdentityFunction(Lambda, metaclass=Singleton): """ The identity function @@ -24,6 +26,7 @@ """ __slots__ = [] nargs = 1 + def __new__(cls): x = C.Dummy('x') #construct "by hand" to avoid infinite loop @@ -34,6 +37,7 @@ ############################# ROOT and SQUARE ROOT FUNCTION ################### ############################################################################### + def sqrt(arg): """The square root function @@ -105,7 +109,7 @@ def root(arg, n): - """The n-th root function (a shortcut for arg**(1/n)) + """The n-th root function (a shortcut for ``arg**(1/n)``) root(x, n) -> Returns the principal n-th root of x. @@ -182,6 +186,7 @@ n = sympify(n) return C.Pow(arg, 1/n) + def real_root(arg, n=None): """Return the real nth-root of arg if possible. If n is omitted then all instances of -1**(1/odd) will be changed to -1. @@ -225,7 +230,8 @@ ############################# MINIMUM and MAXIMUM ############################# ############################################################################### -class MinMaxBase(LatticeOp): + +class MinMaxBase(Expr, LatticeOp): def __new__(cls, *args, **assumptions): if not args: raise ValueError("The Max/Min functions must have arguments.") @@ -270,7 +276,7 @@ for arg in arg_sequence: # pre-filter, checking comparability of arguments - if (arg.is_real == False) or (arg is S.ComplexInfinity): + if (arg.is_real is False) or (arg is S.ComplexInfinity): raise ValueError("The argument '%s' is not comparable." % arg) if arg == cls.zero: @@ -341,11 +347,27 @@ yx = cls._rel_inversed(x, y) if isinstance(yx, bool): if yx: - return False # never occurs? + return False # never occurs? return True return False -class Max(MinMaxBase, Application, Basic): + def _eval_derivative(self, s): + # f(x).diff(s) -> x.diff(s) * f.fdiff(1)(s) + i = 0 + l = [] + for a in self.args: + i += 1 + da = a.diff(s) + if da is S.Zero: + continue + try: + df = self.fdiff(i) + except ArgumentIndexError: + df = Function.fdiff(self, i) + l.append(df * da) + return Add(*l) + +class Max(MinMaxBase, Application): """ Return, if possible, the maximum value of the list. @@ -426,7 +448,7 @@ ========== .. [1] http://en.wikipedia.org/wiki/Directed_complete_partial_order - .. [2] http://en.wikipedia.org/wiki/Lattice_(order) + .. [2] http://en.wikipedia.org/wiki/Lattice_%28order%29 See Also ======== @@ -450,8 +472,20 @@ """ return (x < y) + def fdiff( self, argindex ): + from sympy.functions.special.delta_functions import Heaviside + n = len(self.args) + if 0 < argindex and argindex <= n: + argindex -= 1 + if n == 2: + return Heaviside( self.args[argindex] - self.args[1-argindex] ) + newargs = tuple([self.args[i] for i in range(n) if i != argindex]) + return Heaviside( self.args[argindex] - Max(*newargs) ) + else: + raise ArgumentIndexError(self, argindex) + -class Min(MinMaxBase, Application, Basic): +class Min(MinMaxBase, Application): """ Return, if possible, the minimum value of the list. @@ -499,3 +533,15 @@ Check if x > y. """ return (x > y) + + def fdiff( self, argindex ): + from sympy.functions.special.delta_functions import Heaviside + n = len(self.args) + if 0 < argindex and argindex <= n: + argindex -= 1 + if n == 2: + return Heaviside( self.args[1-argindex] - self.args[argindex] ) + newargs = tuple([ self.args[i] for i in range(n) if i != argindex]) + return Heaviside( Min(*newargs) - self.args[argindex] ) + else: + raise ArgumentIndexError(self, argindex) diff -Nru python3-sympy-0.7.2/sympy/functions/elementary/piecewise.py python3-sympy-0.7.3/sympy/functions/elementary/piecewise.py --- python3-sympy-0.7.2/sympy/functions/elementary/piecewise.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/functions/elementary/piecewise.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,9 +1,10 @@ -from sympy.core import Basic, S, Function, diff, Tuple +from sympy.core import Basic, S, Function, diff, Tuple, Expr from sympy.core.relational import Equality, Relational from sympy.core.symbol import Dummy from sympy.functions.elementary.miscellaneous import Max, Min -from sympy.logic.boolalg import And, Boolean, Or -from sympy.utilities.misc import default_sort_key +from sympy.logic.boolalg import And, Boolean, distribute_and_over_or, Not, Or +from sympy.core.compatibility import default_sort_key + class ExprCondPair(Tuple): """Represents an expression, condition pair.""" @@ -50,6 +51,7 @@ yield self.expr yield self.cond + class Piecewise(Function): """ Represents a piecewise function. @@ -97,7 +99,7 @@ continue if not isinstance(cond, (bool, Relational, Boolean)): raise TypeError( - "Cond %s is of type %s, but must be a Relational," \ + "Cond %s is of type %s, but must be a Relational," " Boolean, or a built-in bool." % (cond, type(cond))) newargs.append(pair) if cond is True: @@ -146,10 +148,16 @@ elif cond_eval: if all_conds_evaled: return expr - if len(non_false_ecpairs) != 0 and non_false_ecpairs[-1].expr == expr: - non_false_ecpairs[-1] = ExprCondPair(expr, Or(cond, non_false_ecpairs[-1].cond)) - else: - non_false_ecpairs.append( ExprCondPair(expr, cond) ) + if len(non_false_ecpairs) != 0: + if non_false_ecpairs[-1].cond == cond: + continue + elif non_false_ecpairs[-1].expr == expr: + newcond = Or(cond, non_false_ecpairs[-1].cond) + if isinstance(newcond, (And, Or)): + newcond = distribute_and_over_or(newcond) + non_false_ecpairs[-1] = ExprCondPair(expr, newcond) + continue + non_false_ecpairs.append(ExprCondPair(expr, cond)) if len(non_false_ecpairs) != len(args) or piecewise_again: return Piecewise(*non_false_ecpairs) @@ -174,9 +182,11 @@ if c is True or c.subs(x, 0) is True: return e.as_leading_term(x) + def _eval_adjoint(self): + return Piecewise(*[(e.adjoint(), c) for e, c in self.args]) + def _eval_conjugate(self): - from sympy.functions.elementary.complexes import conjugate - return Piecewise(*[(conjugate(e), c) for e, c in self.args]) + return Piecewise(*[(e.conjugate(), c) for e, c in self.args]) def _eval_derivative(self, x): return Piecewise(*[(diff(e, x), c) for e, c in self.args]) @@ -195,6 +205,11 @@ # following papers; # http://portal.acm.org/citation.cfm?id=281649 # http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.70.4127&rep=rep1&type=pdf + + if a is None or b is None: + # In this case, it is just simple substitution + return super(Piecewise, self)._eval_interval(sym, a, b) + mul = 1 if (a == b) is True: return S.Zero @@ -203,7 +218,8 @@ elif (a <= b) is not True: newargs = [] for e, c in self.args: - intervals = self._sort_expr_cond(sym, S.NegativeInfinity, S.Infinity, c) + intervals = self._sort_expr_cond( + sym, S.NegativeInfinity, S.Infinity, c) values = [] for lower, upper in intervals: if (a < lower) is True: @@ -237,7 +253,7 @@ """The evaluation of a Piecewise interval when both the lower and the upper limit are symbolic is not yet implemented.""") values.append(val) - if len(set(values)) == 1 : + if len(set(values)) == 1: try: c = c.subs(sym, rep) except AttributeError: @@ -256,10 +272,17 @@ # Finally run through the intervals and sum the evaluation. ret_fun = 0 for int_a, int_b, expr in int_expr: - ret_fun += expr._eval_interval(sym, Max(a, int_a), Min(b, int_b)) + if isinstance(expr, Piecewise): + # If we still have a Piecewise by now, _sort_expr_cond would + # already have determined that its conditions are independent + # of the integration variable, thus we just use substitution. + ret_fun += piecewise_fold( + expr.subs(sym, Min(b, int_b)) - expr.subs(sym, Max(a, int_a))) + else: + ret_fun += expr._eval_interval(sym, Max(a, int_a), Min(b, int_b)) return mul * ret_fun - def _sort_expr_cond(self, sym, a, b, targetcond = None): + def _sort_expr_cond(self, sym, a, b, targetcond=None): """Determine what intervals the expr, cond pairs affect. 1) If cond is True, then log it as default @@ -278,6 +301,7 @@ expr_cond = [] or_cond = False or_intervals = [] + independent_expr_cond = [] for expr, cond in self.args: if isinstance(cond, Or): for cond2 in sorted(cond.args, key=default_sort_key): @@ -288,8 +312,12 @@ break for expr, cond in expr_cond: if cond is True: - default = expr + independent_expr_cond.append((expr, cond)) + default = Piecewise(*independent_expr_cond) break + if sym not in cond.free_symbols: + independent_expr_cond.append((expr, cond)) + continue elif isinstance(cond, Equality): continue elif isinstance(cond, And): @@ -301,7 +329,7 @@ elif cond2.gts.has(sym): lower = Max(cond2.lts, lower) else: - lower, upper = cond.lts, cond.gts # part 1: initialize with givens + lower, upper = cond.lts, cond.gts # part 1: initialize with givens if cond.lts.has(sym): # part 1a: expand the side ... lower = S.NegativeInfinity # e.g. x <= 0 ---> -oo <= 0 elif cond.gts.has(sym): # part 1a: ... that can be expanded @@ -344,23 +372,25 @@ or_cond = Or(or_cond, cond) or_intervals.append((lower, upper)) if or_cond == targetcond: - or_intervals.sort(key=lambda x:x[0]) + or_intervals.sort(key=lambda x: x[0]) return or_intervals - int_expr.sort(key=lambda x: x[1].sort_key() if x[1].is_number else S.NegativeInfinity.sort_key()) - int_expr.sort(key=lambda x: x[0].sort_key() if x[0].is_number else S.Infinity.sort_key()) + int_expr.sort(key=lambda x: x[1].sort_key( + ) if x[1].is_number else S.NegativeInfinity.sort_key()) + int_expr.sort(key=lambda x: x[0].sort_key( + ) if x[0].is_number else S.Infinity.sort_key()) from sympy.functions.elementary.miscellaneous import MinMaxBase for n in range(len(int_expr)): if len(int_expr[n][0].free_symbols) or len(int_expr[n][1].free_symbols): if isinstance(int_expr[n][1], Min) or int_expr[n][1] == b: newval = Min(*int_expr[n][:-1]) - if n > 0 and int_expr[n][0] == int_expr[n-1][1]: - int_expr[n-1][1] = newval + if n > 0 and int_expr[n][0] == int_expr[n - 1][1]: + int_expr[n - 1][1] = newval int_expr[n][0] = newval else: newval = Max(*int_expr[n][:-1]) - if n < len(int_expr) - 1 and int_expr[n][1] == int_expr[n+1][0]: - int_expr[n+1][0] = newval + if n < len(int_expr) - 1 and int_expr[n][1] == int_expr[n + 1][0]: + int_expr[n + 1][0] = newval int_expr[n][1] = newval # Add holes to list of intervals if there is a default value, @@ -382,13 +412,17 @@ int_expr.extend(holes) if targetcond is True: return [(h[0], h[1]) for h in holes] - elif holes and default == None: - raise ValueError("Called interval evaluation over piecewise " \ - "function on undefined intervals %s" % \ + elif holes and default is None: + raise ValueError("Called interval evaluation over piecewise " + "function on undefined intervals %s" % ", ".join([str((h[0], h[1])) for h in holes])) return int_expr + def _eval_nseries(self, x, n, logx): + args = [(ec.expr._eval_nseries(x, n, logx), ec.cond) for ec in self.args] + return self.func(*args) + def _eval_power(self, s): return Piecewise(*[(e**s, c) for e, c in self.args]) @@ -398,20 +432,20 @@ """ args = list(self.args) for i, (e, c) in enumerate(args): - e = e._subs(old, new) - if isinstance(c, bool): pass elif isinstance(c, Basic): c = c._subs(old, new) - + if not c is False: + e = e._subs(old, new) args[i] = e, c + if c is True: + return Piecewise(*args) return Piecewise(*args) - def _eval_nseries(self, x, n, logx): - args = [(ec.expr._eval_nseries(x, n, logx), ec.cond) for ec in self.args] - return self.func(*args) + def _eval_transpose(self): + return Piecewise(*[(e.transpose(), c) for e, c in self.args]) def _eval_template_is_attr(self, is_attr, when_multiple=None): b = None @@ -425,29 +459,45 @@ return when_multiple return b - _eval_is_bounded = lambda self: self._eval_template_is_attr('is_bounded', when_multiple=False) + _eval_is_bounded = lambda self: self._eval_template_is_attr( + 'is_bounded', when_multiple=False) _eval_is_complex = lambda self: self._eval_template_is_attr('is_complex') _eval_is_even = lambda self: self._eval_template_is_attr('is_even') - _eval_is_imaginary = lambda self: self._eval_template_is_attr('is_imaginary') + _eval_is_imaginary = lambda self: self._eval_template_is_attr( + 'is_imaginary') _eval_is_integer = lambda self: self._eval_template_is_attr('is_integer') - _eval_is_irrational = lambda self: self._eval_template_is_attr('is_irrational') + _eval_is_irrational = lambda self: self._eval_template_is_attr( + 'is_irrational') _eval_is_negative = lambda self: self._eval_template_is_attr('is_negative') - _eval_is_nonnegative = lambda self: self._eval_template_is_attr('is_nonnegative') - _eval_is_nonpositive = lambda self: self._eval_template_is_attr('is_nonpositive') - _eval_is_nonzero = lambda self: self._eval_template_is_attr('is_nonzero', when_multiple=True) + _eval_is_nonnegative = lambda self: self._eval_template_is_attr( + 'is_nonnegative') + _eval_is_nonpositive = lambda self: self._eval_template_is_attr( + 'is_nonpositive') + _eval_is_nonzero = lambda self: self._eval_template_is_attr( + 'is_nonzero', when_multiple=True) _eval_is_odd = lambda self: self._eval_template_is_attr('is_odd') _eval_is_polar = lambda self: self._eval_template_is_attr('is_polar') _eval_is_positive = lambda self: self._eval_template_is_attr('is_positive') _eval_is_real = lambda self: self._eval_template_is_attr('is_real') - _eval_is_zero = lambda self: self._eval_template_is_attr('is_zero', when_multiple=False) + _eval_is_zero = lambda self: self._eval_template_is_attr( + 'is_zero', when_multiple=False) @classmethod def __eval_cond(cls, cond): """Return the truth value of the condition.""" + from sympy.solvers.solvers import checksol if cond is True: return True + if isinstance(cond, Equality): + if checksol(cond, {}, minimal=True): + # the equality is trivially solved + return True + diff = cond.lhs - cond.rhs + if diff.is_commutative: + return diff.is_zero return None + def piecewise_fold(expr): """ Takes an expression containing a piecewise function and returns the @@ -474,12 +524,28 @@ return ExprCondPair(*new_args) piecewise_args = [] for n, arg in enumerate(new_args): - if arg.func is Piecewise: + if isinstance(arg, Piecewise): piecewise_args.append(n) if len(piecewise_args) > 0: n = piecewise_args[0] - new_args = [(expr.func(*(new_args[:n] + [e] + new_args[n+1:])), c) \ - for e, c in new_args[n].args] + new_args = [(expr.func(*(new_args[:n] + [e] + new_args[n + 1:])), c) + for e, c in new_args[n].args] + if isinstance(expr, Boolean): + # If expr is Boolean, we must return some kind of PiecewiseBoolean. + # This is constructed by means of Or, And and Not. + # piecewise_fold(0 < Piecewise( (sin(x), x<0), (cos(x), True))) + # can't return Piecewise((0 < sin(x), x < 0), (0 < cos(x), True)) + # but instead Or(And(x < 0, 0 < sin(x)), And(0 < cos(x), Not(x<0))) + other = True + rtn = False + for e, c in new_args: + rtn = Or(rtn, And(other, c, e)) + other = And(other, Not(c)) + if len(piecewise_args) > 1: + return piecewise_fold(rtn) + return rtn if len(piecewise_args) > 1: return piecewise_fold(Piecewise(*new_args)) - return Piecewise(*new_args) + return Piecewise(*new_args) + else: + return expr.func(*new_args) diff -Nru python3-sympy-0.7.2/sympy/functions/elementary/tests/test_complexes.py python3-sympy-0.7.3/sympy/functions/elementary/tests/test_complexes.py --- python3-sympy-0.7.2/sympy/functions/elementary/tests/test_complexes.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/functions/elementary/tests/test_complexes.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,13 +1,18 @@ -from sympy import (symbols, Symbol, sqrt, oo, re, nan, im, sign, I, E, log, - pi, arg, conjugate, expand, exp, sin, cos, Function, Abs, zoo, atan2, - S, DiracDelta, Rational, Heaviside) +from sympy import ( + Abs, adjoint, arg, atan2, conjugate, cos, DiracDelta, E, exp, expand, + Expr, Function, Heaviside, I, im, log, nan, oo, pi, Rational, re, S, + sign, sin, sqrt, Symbol, symbols, transpose, zoo, exp_polar, Piecewise +) from sympy.utilities.pytest import XFAIL from sympy.utilities.randtest import comp + + def N_equals(a, b): """Check whether two complex numbers are numerically close""" return comp(a.n(), b.n(), 1.e-6) + def test_re(): x, y = symbols('x,y') a, b = symbols('a,b', real=True) @@ -48,7 +53,7 @@ assert re(log(2*I)) == log(2) - assert re((2+I)**2).expand(complex=True) == 3 + assert re((2 + I)**2).expand(complex=True) == 3 assert re(conjugate(x)) == re(x) assert conjugate(re(x)) == re(x) @@ -56,13 +61,15 @@ assert re(x).as_real_imag() == (re(x), 0) assert re(i*r*x).diff(r) == re(i*x) - assert re(i*r*x).diff(i) == -I * im(r*x) + assert re(i*r*x).diff(i) == I*r*im(x) - assert re(sqrt(a + b*I)) == (a**2 + b**2)**Rational(1,4)*cos(atan2(b, a)/2) + assert re( + sqrt(a + b*I)) == (a**2 + b**2)**Rational(1, 4)*cos(atan2(b, a)/2) assert re(a * (2 + b*I)) == 2*a assert re((1 + sqrt(a + b*I))/2) == \ - (a**2 + b**2)**Rational(1,4)*cos(atan2(b, a)/2)/2 + Rational(1,2) + (a**2 + b**2)**Rational(1, 4)*cos(atan2(b, a)/2)/2 + Rational(1, 2) + def test_im(): x, y = symbols('x,y') @@ -105,7 +112,7 @@ assert im(log(2*I)) == pi/2 - assert im((2+I)**2).expand(complex=True) == 4 + assert im((2 + I)**2).expand(complex=True) == 4 assert im(conjugate(x)) == -im(x) assert conjugate(im(x)) == im(x) @@ -115,11 +122,13 @@ assert im(i*r*x).diff(r) == im(i*x) assert im(i*r*x).diff(i) == -I * re(r*x) - assert im(sqrt(a + b*I)) == (a**2 + b**2)**Rational(1,4)*sin(atan2(b, a)/2) + assert im( + sqrt(a + b*I)) == (a**2 + b**2)**Rational(1, 4)*sin(atan2(b, a)/2) assert im(a * (2 + b*I)) == a*b assert im((1 + sqrt(a + b*I))/2) == \ - (a**2 + b**2)**Rational(1,4)*sin(atan2(b, a)/2)/2 + (a**2 + b**2)**Rational(1, 4)*sin(atan2(b, a)/2)/2 + def test_sign(): assert sign(1.2) == 1 @@ -128,9 +137,17 @@ assert sign(-3*I) == -I assert sign(0) == 0 assert sign(nan) == nan + assert sign(2 + 2*I).doit() == sqrt(2)*(2 + 2*I)/4 + assert sign(2 + 3*I).simplify() == sign(2 + 3*I) + assert sign(2 + 2*I).simplify() == sign(1 + I) x = Symbol('x') - assert sign(x).is_zero == None + assert sign(x).is_bounded is True + assert sign(x).is_complex is True + assert sign(x).is_imaginary is None + assert sign(x).is_integer is None + assert sign(x).is_real is None + assert sign(x).is_zero is None assert sign(x).doit() == sign(x) assert sign(1.2*x) == sign(x) assert sign(2*x) == sign(x) @@ -138,47 +155,86 @@ assert sign(-2*I*x) == -I*sign(x) assert sign(conjugate(x)) == conjugate(sign(x)) - p = Symbol('p', positive = True) - n = Symbol('n', negative = True) - m = Symbol('m', negative = True) + p = Symbol('p', positive=True) + n = Symbol('n', negative=True) + m = Symbol('m', negative=True) assert sign(2*p*x) == sign(x) assert sign(n*x) == -sign(x) assert sign(n*m*x) == sign(x) x = Symbol('x', imaginary=True) - assert sign(x).is_zero == False + assert sign(x).is_imaginary is True + assert sign(x).is_integer is False + assert sign(x).is_real is False + assert sign(x).is_zero is False assert sign(x).diff(x) == 2*DiracDelta(-I*x) assert sign(x).doit() == x / Abs(x) assert conjugate(sign(x)) == -sign(x) x = Symbol('x', real=True) - assert sign(x).is_zero == None + assert sign(x).is_imaginary is False + assert sign(x).is_integer is True + assert sign(x).is_real is True + assert sign(x).is_zero is None assert sign(x).diff(x) == 2*DiracDelta(x) assert sign(x).doit() == sign(x) assert conjugate(sign(x)) == sign(x) x = Symbol('x', nonzero=True) - assert sign(x).is_zero == False + assert sign(x).is_imaginary is None + assert sign(x).is_integer is None + assert sign(x).is_real is None + assert sign(x).is_zero is False assert sign(x).doit() == x / Abs(x) assert sign(Abs(x)) == 1 assert Abs(sign(x)) == 1 x = Symbol('x', positive=True) - assert sign(x).is_zero == False + assert sign(x).is_imaginary is False + assert sign(x).is_integer is True + assert sign(x).is_real is True + assert sign(x).is_zero is False assert sign(x).doit() == x / Abs(x) assert sign(Abs(x)) == 1 assert Abs(sign(x)) == 1 x = 0 - assert sign(x).is_zero == True + assert sign(x).is_imaginary is False + assert sign(x).is_integer is True + assert sign(x).is_real is True + assert sign(x).is_zero is True assert sign(x).doit() == 0 assert sign(Abs(x)) == 0 assert Abs(sign(x)) == 0 nz = Symbol('nz', nonzero=True, integer=True) + assert sign(nz).is_imaginary is False + assert sign(nz).is_integer is True + assert sign(nz).is_real is True + assert sign(nz).is_zero is False assert sign(nz)**2 == 1 assert (sign(nz)**3).args == (sign(nz), 3) + x, y = Symbol('x', real=True), Symbol('y') + assert sign(x).rewrite(Piecewise) == \ + Piecewise((1, x > 0), (-1, x < 0), (0, True)) + assert sign(y).rewrite(Piecewise) == sign(y) + + # evaluate what can be evaluated + assert sign(exp_polar(I*pi)*pi) is S.NegativeOne + + eq = -sqrt(10 + 6*sqrt(3)) + sqrt(1 + sqrt(3)) + sqrt(3 + 3*sqrt(3)) + # if there is a fast way to know when and when you cannot prove an + # expression like this is zero then the equality to zero is ok + assert sign(eq).func is sign or sign(eq) == 0 + # but sometimes it's hard to do this so it's better not to load + # abs down with tests that will be very slow + q = 1 + sqrt(2) - 2*sqrt(3) + 1331*sqrt(6) + p = expand(q**3)**Rational(1, 3) + d = p - q + assert sign(d).func is sign or sign(d) == 0 + + def test_as_real_imag(): n = pi**1000 # the special code for working out the real @@ -190,20 +246,23 @@ # issue 3162 x = Symbol('x') assert sqrt(x).as_real_imag() == \ - ((re(x)**2 + im(x)**2)**(S(1)/4)*cos(atan2(im(x), re(x))/2), \ + ((re(x)**2 + im(x)**2)**(S(1)/4)*cos(atan2(im(x), re(x))/2), (re(x)**2 + im(x)**2)**(S(1)/4)*sin(atan2(im(x), re(x))/2)) # issue 754 a, b = symbols('a,b', real=True) assert ((1 + sqrt(a + b*I))/2).as_real_imag() == \ - ((a**2 + b**2)**Rational(1,4)*cos(atan2(b, a)/2)/2 + Rational(1,2), \ - (a**2 + b**2)**Rational(1,4)*sin(atan2(b, a)/2)/2) + ( + (a**2 + b**2)**Rational( + 1, 4)*cos(atan2(b, a)/2)/2 + Rational(1, 2), + (a**2 + b**2)**Rational(1, 4)*sin(atan2(b, a)/2)/2) + @XFAIL def test_sign_issue_3068(): n = pi**1000 i = int(n) - assert (n - i).round() == 1 # doesn't hang + assert (n - i).round() == 1 # doesn't hang assert sign(n - i) == 1 # perhaps it's not possible to get the sign right when # only 1 digit is being requested for this situtation; @@ -211,6 +270,7 @@ assert (n - x).n(1, subs={x: i}) > 0 assert (n - x).n(2, subs={x: i}) > 0 + def test_Abs(): x, y = symbols('x,y') assert sign(sign(x)) == sign(x) @@ -239,16 +299,28 @@ n = Symbol('n', integer=True) assert x**(2*n) == Abs(x)**(2*n) assert Abs(x).diff(x) == sign(x) - assert abs(x) == Abs(x) # Python built-in + assert abs(x) == Abs(x) # Python built-in assert Abs(x)**3 == x**2*Abs(x) assert Abs(x)**4 == x**4 - assert (Abs(x)**(3*n)).args == (Abs(x), 3*n) # leave symbolic odd unchanged + assert ( + Abs(x)**(3*n)).args == (Abs(x), 3*n) # leave symbolic odd unchanged assert (1/Abs(x)).args == (Abs(x), -1) assert 1/Abs(x)**3 == 1/(x**2*Abs(x)) x = Symbol('x', imaginary=True) assert Abs(x).diff(x) == -sign(x) + eq = -sqrt(10 + 6*sqrt(3)) + sqrt(1 + sqrt(3)) + sqrt(3 + 3*sqrt(3)) + # if there is a fast way to know when and when you cannot prove an + # expression like this is zero then the equality to zero is ok + assert abs(eq).func is Abs or abs(eq) == 0 + # but sometimes it's hard to do this so it's better not to load + # abs down with tests that will be very slow + q = 1 + sqrt(2) - 2*sqrt(3) + 1331*sqrt(6) + p = expand(q**3)**Rational(1, 3) + d = p - q + assert abs(d).func is Abs or abs(d) == 0 + def test_Abs_rewrite(): x = Symbol('x', real=True) a = Abs(x).rewrite(Heaviside).expand() @@ -258,6 +330,11 @@ y = Symbol('y') assert Abs(y).rewrite(Heaviside) == Abs(y) + x, y = Symbol('x', real=True), Symbol('y') + assert Abs(x).rewrite(Piecewise) == Piecewise((x, x >= 0), (-x, True)) + assert Abs(y).rewrite(Piecewise) == Abs(y) + + def test_Abs_real(): # test some properties of abs that only apply # to real numbers @@ -275,21 +352,23 @@ assert Abs(nn) == nn assert Abs(np) == -np + def test_Abs_properties(): x = Symbol('x') - assert Abs(x).is_real == True - assert Abs(x).is_positive == None - assert Abs(x).is_nonnegative == True + assert Abs(x).is_real is True + assert Abs(x).is_positive is None + assert Abs(x).is_nonnegative is True w = Symbol('w', complex=True, zero=False) - assert Abs(w).is_real == True - assert Abs(w).is_positive == True - assert Abs(w).is_zero == False + assert Abs(w).is_real is True + assert Abs(w).is_positive is True + assert Abs(w).is_zero is False q = Symbol('q', positive=True) - assert Abs(q).is_real == True - assert Abs(q).is_positive == True - assert Abs(q).is_zero == False + assert Abs(q).is_real is True + assert Abs(q).is_positive is True + assert Abs(q).is_zero is False + def test_abs(): # this tests that abs calls Abs; don't rename to @@ -297,15 +376,16 @@ a = Symbol('a', positive=True) assert abs(I*(1 + a)**2) == (1 + a)**2 + def test_arg(): assert arg(0) == nan assert arg(1) == 0 assert arg(-1) == pi assert arg(I) == pi/2 assert arg(-I) == -pi/2 - assert arg(1+I) == pi/4 - assert arg(-1+I) == 3*pi/4 - assert arg(1-I) == -pi/4 + assert arg(1 + I) == pi/4 + assert arg(-1 + I) == 3*pi/4 + assert arg(1 - I) == -pi/4 p = Symbol('p', positive=True) assert arg(p) == 0 @@ -316,12 +396,51 @@ x = Symbol('x') assert conjugate(arg(x)) == arg(x) +def test_arg_rewrite(): + assert arg(1 + I) == atan2(1, 1) + + x = Symbol('x', real=True) + y = Symbol('y', real=True) + assert arg(x + I*y).rewrite(atan2) == atan2(y, x) + +def test_adjoint(): + a = Symbol('a', antihermitian=True) + b = Symbol('b', hermitian=True) + assert adjoint(a) == -a + assert adjoint(I*a) == I*a + assert adjoint(b) == b + assert adjoint(I*b) == -I*b + assert adjoint(a*b) == -b*a + assert adjoint(I*a*b) == I*b*a + + x, y = symbols('x y') + assert adjoint(adjoint(x)) == x + assert adjoint(x + y) == adjoint(x) + adjoint(y) + assert adjoint(x - y) == adjoint(x) - adjoint(y) + assert adjoint(x * y) == adjoint(x) * adjoint(y) + assert adjoint(x / y) == adjoint(x) / adjoint(y) + assert adjoint(-x) == -adjoint(x) + + x, y = symbols('x y', commutative=False) + assert adjoint(adjoint(x)) == x + assert adjoint(x + y) == adjoint(x) + adjoint(y) + assert adjoint(x - y) == adjoint(x) - adjoint(y) + assert adjoint(x * y) == adjoint(y) * adjoint(x) + assert adjoint(x / y) == 1 / adjoint(y) * adjoint(x) + assert adjoint(-x) == -adjoint(x) + + def test_conjugate(): a = Symbol('a', real=True) + b = Symbol('b', imaginary=True) assert conjugate(a) == a assert conjugate(I*a) == -I*a + assert conjugate(b) == -b + assert conjugate(I*b) == I*b + assert conjugate(a*b) == -a*b + assert conjugate(I*a*b) == I*a*b - x, y = symbols('x,y') + x, y = symbols('x y') assert conjugate(conjugate(x)) == x assert conjugate(x + y) == conjugate(x) + conjugate(y) assert conjugate(x - y) == conjugate(x) - conjugate(y) @@ -329,16 +448,64 @@ assert conjugate(x / y) == conjugate(x) / conjugate(y) assert conjugate(-x) == -conjugate(x) + +def test_conjugate_transpose(): + x = Symbol('x') + assert conjugate(transpose(x)) == adjoint(x) + assert transpose(conjugate(x)) == adjoint(x) + assert adjoint(transpose(x)) == conjugate(x) + assert transpose(adjoint(x)) == conjugate(x) + assert adjoint(conjugate(x)) == transpose(x) + assert conjugate(adjoint(x)) == transpose(x) + + class Symmetric(Expr): + def _eval_adjoint(self): + return None + + def _eval_conjugate(self): + return None + + def _eval_transpose(self): + return self + x = Symmetric() + assert conjugate(x) == adjoint(x) + assert transpose(x) == x + + +def test_transpose(): + a = Symbol('a', complex=True) + assert transpose(a) == a + assert transpose(I*a) == I*a + + x, y = symbols('x y') + assert transpose(transpose(x)) == x + assert transpose(x + y) == transpose(x) + transpose(y) + assert transpose(x - y) == transpose(x) - transpose(y) + assert transpose(x * y) == transpose(x) * transpose(y) + assert transpose(x / y) == transpose(x) / transpose(y) + assert transpose(-x) == -transpose(x) + + x, y = symbols('x y', commutative=False) + assert transpose(transpose(x)) == x + assert transpose(x + y) == transpose(x) + transpose(y) + assert transpose(x - y) == transpose(x) - transpose(y) + assert transpose(x * y) == transpose(y) * transpose(x) + assert transpose(x / y) == 1 / transpose(y) * transpose(x) + assert transpose(-x) == -transpose(x) + + def test_issue936(): x = Symbol('x') - assert Abs(x).expand(trig=True) == Abs(x) - assert sign(x).expand(trig=True) == sign(x) - assert arg(x).expand(trig=True) == arg(x) + assert Abs(x).expand(trig=True) == Abs(x) + assert sign(x).expand(trig=True) == sign(x) + assert arg(x).expand(trig=True) == arg(x) + def test_issue3206(): x = Symbol('x') assert Abs(Abs(x)) == Abs(x) + def test_issue1655_derivative_conjugate(): x = Symbol('x', real=True) y = Symbol('y', imaginary=True) @@ -346,6 +513,7 @@ assert (f(x).conjugate()).diff(x) == (f(x).diff(x)).conjugate() assert (f(y).conjugate()).diff(y) == -(f(y).diff(y)).conjugate() + def test_derivatives_issue1658(): x = Symbol('x', real=True) y = Symbol('y', imaginary=True) @@ -354,44 +522,47 @@ assert im(f(x)).diff(x) == im(f(x).diff(x)) assert re(f(y)).diff(y) == -I*im(f(y).diff(y)) assert im(f(y)).diff(y) == -I*re(f(y).diff(y)) - assert Abs(f(x)).diff(x).subs(f(x), 1+I*x).doit() == x/sqrt(1 + x**2) - assert arg(f(x)).diff(x).subs(f(x), 1+I*x**2).doit() == 2*x/(1+x**4) - assert Abs(f(y)).diff(y).subs(f(y), 1+y).doit() == -y/sqrt(1 - y**2) - assert arg(f(y)).diff(y).subs(f(y), I+y**2).doit() == 2*y/(1 + y**4) + assert Abs(f(x)).diff(x).subs(f(x), 1 + I*x).doit() == x/sqrt(1 + x**2) + assert arg(f(x)).diff(x).subs(f(x), 1 + I*x**2).doit() == 2*x/(1 + x**4) + assert Abs(f(y)).diff(y).subs(f(y), 1 + y).doit() == -y/sqrt(1 - y**2) + assert arg(f(y)).diff(y).subs(f(y), I + y**2).doit() == 2*y/(1 + y**4) + def test_periodic_argument(): from sympy import (periodic_argument, unbranched_argument, oo, principal_branch, polar_lift, pi) x = Symbol('x') - p = Symbol('p', positive = True) + p = Symbol('p', positive=True) assert unbranched_argument(2 + I) == periodic_argument(2 + I, oo) assert unbranched_argument(1 + x) == periodic_argument(1 + x, oo) - assert N_equals(unbranched_argument((1+I)**2), pi/2) - assert N_equals(unbranched_argument((1-I)**2), -pi/2) - assert N_equals(periodic_argument((1+I)**2, 3*pi), pi/2) - assert N_equals(periodic_argument((1-I)**2, 3*pi), -pi/2) + assert N_equals(unbranched_argument((1 + I)**2), pi/2) + assert N_equals(unbranched_argument((1 - I)**2), -pi/2) + assert N_equals(periodic_argument((1 + I)**2, 3*pi), pi/2) + assert N_equals(periodic_argument((1 - I)**2, 3*pi), -pi/2) - assert unbranched_argument(principal_branch(x, pi)) \ - == periodic_argument(x, pi) + assert unbranched_argument(principal_branch(x, pi)) == \ + periodic_argument(x, pi) assert unbranched_argument(polar_lift(2 + I)) == unbranched_argument(2 + I) - assert periodic_argument(polar_lift(2 + I), 2*pi) \ - == periodic_argument(2 + I, 2*pi) - assert periodic_argument(polar_lift(2 + I), 3*pi) \ - == periodic_argument(2 + I, 3*pi) - assert periodic_argument(polar_lift(2 + I), pi) \ - == periodic_argument(polar_lift(2 + I), pi) + assert periodic_argument(polar_lift(2 + I), 2*pi) == \ + periodic_argument(2 + I, 2*pi) + assert periodic_argument(polar_lift(2 + I), 3*pi) == \ + periodic_argument(2 + I, 3*pi) + assert periodic_argument(polar_lift(2 + I), pi) == \ + periodic_argument(polar_lift(2 + I), pi) assert unbranched_argument(polar_lift(1 + I)) == pi/4 assert periodic_argument(2*p, p) == periodic_argument(p, p) assert periodic_argument(pi*p, p) == periodic_argument(p, p) + @XFAIL def test_principal_branch_fail(): # TODO XXX why does abs(x)._eval_evalf() not fall back to global evalf? assert N_equals(principal_branch((1 + I)**2, pi/2), 0) + def test_principal_branch(): from sympy import principal_branch, polar_lift, exp_polar p = Symbol('p', positive=True) @@ -405,7 +576,7 @@ assert principal_branch(-1, 2*pi) == exp_polar(I*pi) assert principal_branch(-1, pi) == exp_polar(0) assert principal_branch(exp_polar(3*pi*I)*x, 2*pi) == \ - principal_branch(exp_polar(I*pi)*x, 2*pi) + principal_branch(exp_polar(I*pi)*x, 2*pi) assert principal_branch(neg*exp_polar(pi*I), 2*pi) == neg*exp_polar(-I*pi) assert N_equals(principal_branch((1 + I)**2, 2*pi), 2*I) @@ -417,3 +588,18 @@ assert principal_branch(x, -4).func is principal_branch assert principal_branch(x, -oo).func is principal_branch assert principal_branch(x, zoo).func is principal_branch + + +@XFAIL +def test_issue_3068_3052(): + n = pi**1000 + i = int(n) + assert sign(n - i) == 1 + assert abs(n - i) == n - i + eps = pi**-1500 + big = pi**1000 + one = cos(x)**2 + sin(x)**2 + e = big*one - big + eps + assert sign(simplify(e)) == 1 + for xi in (111, 11, 1, S(1)/10): + assert sign(e.subs(x, xi)) == 1 diff -Nru python3-sympy-0.7.2/sympy/functions/elementary/tests/test_exponential.py python3-sympy-0.7.3/sympy/functions/elementary/tests/test_exponential.py --- python3-sympy-0.7.2/sympy/functions/elementary/tests/test_exponential.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/functions/elementary/tests/test_exponential.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,6 +1,7 @@ from sympy import (symbols, log, Float, nan, oo, zoo, I, pi, E, exp, Symbol, LambertW, sqrt, Rational, expand_log, S, sign, nextprime, conjugate, - sin, cos, sinh, cosh, exp_polar, re) + sin, cos, sinh, cosh, exp_polar, re, Function, simplify, Eq) + def test_exp_values(): @@ -24,9 +25,9 @@ assert exp(2*pi*I) == 1 assert exp(pi*I*2*k) == 1 - assert exp(pi*I*2*(k+Rational(1,2))) == -1 - assert exp(pi*I*2*(k+Rational(1,4))) == I - assert exp(pi*I*2*(k+Rational(3,4))) == -I + assert exp(pi*I*2*(k + Rational(1, 2))) == -1 + assert exp(pi*I*2*(k + Rational(1, 4))) == I + assert exp(pi*I*2*(k + Rational(3, 4))) == -I assert exp(log(x)) == x assert exp(2*log(x)) == x**2 @@ -37,8 +38,9 @@ assert exp(x*log(x)) != x**x assert exp(sin(x)*log(x)) != x - assert exp(3*log(x)+oo*x) == exp(oo*x) * x**3 - assert exp(4*log(x)*log(y)+3*log(x)) == x**3 * exp(4*log(x)*log(y)) + assert exp(3*log(x) + oo*x) == exp(oo*x) * x**3 + assert exp(4*log(x)*log(y) + 3*log(x)) == x**3 * exp(4*log(x)*log(y)) + def test_exp_log(): x = Symbol("x", real=True) @@ -52,17 +54,19 @@ assert log(exp_polar(z)) == z assert exp(log(y)) == y + def test_exp_expand(): x = Symbol("x") y = Symbol("y") - e = exp(log(Rational(2))*(1+x)-log(Rational(2))*x) + e = exp(log(Rational(2))*(1 + x) - log(Rational(2))*x) assert e.expand() == 2 - assert exp(x+y) != exp(x)*exp(y) - assert exp(x+y).expand() == exp(x)*exp(y) + assert exp(x + y) != exp(x)*exp(y) + assert exp(x + y).expand() == exp(x)*exp(y) + def test_exp__as_base_exp(): - x,y = symbols('x,y') + x, y = symbols('x,y') assert exp(x).as_base_exp() == (E, x) assert exp(2*x).as_base_exp() == (E, 2*x) @@ -70,13 +74,14 @@ assert exp(-x).as_base_exp() == (E, -x) # Pow( *expr.as_base_exp() ) == expr invariant should hold - assert E**x == exp(x) + assert E**x == exp(x) assert E**(2*x) == exp(2*x) assert E**(x*y) == exp(x*y) assert exp(x).base is S.Exp1 assert exp(x).exp == x + def test_exp_infinity(): y = Symbol('y') assert exp(I*y) != nan @@ -84,33 +89,40 @@ assert exp(-I*oo) == nan assert exp(y*I*oo) != nan + def test_exp_subs(): x, y = symbols('x,y') e = (exp(3*log(x), evaluate=False)) assert e.subs(x**3, y**3) == e assert e.subs(x**2, 5) == e assert exp(3*log(x)).subs(x**2, y) == x**3 - assert exp(5*x).subs(exp(7*x),y) == y**Rational(5,7) - assert exp(2*x + 7).subs(exp(3*x),y) == y**Rational(2,3) * exp(7) + assert exp(5*x).subs(exp(7*x), y) == y**Rational(5, 7) + assert exp(2*x + 7).subs(exp(3*x), y) == y**Rational(2, 3) * exp(7) assert exp(exp(x) + exp(x**2)).subs(exp(exp(x)), y) == y * exp(exp(x**2)) - assert exp(x).subs(E,y) == y**x + assert exp(x).subs(E, y) == y**x x = symbols('x', positive=True) - assert exp(3*log(x)).subs(x**2, y) == y**Rational(3,2) + assert exp(3*log(x)).subs(x**2, y) == y**Rational(3, 2) + def test_exp_conjugate(): x = Symbol('x') assert conjugate(exp(x)) == exp(conjugate(x)) + def test_exp_rewrite(): x = symbols('x') assert exp(x).rewrite(sin) == sinh(x) + cosh(x) assert exp(x*I).rewrite(cos) == cos(x) + I*sin(x) + assert exp(1).rewrite(cos) == sinh(1) + cosh(1) + assert exp(1).rewrite(sin) == sinh(1) + cosh(1) + def test_exp_leading_term(): x = symbols('x') assert exp(x).as_leading_term(x) == 1 assert exp(1/x).as_leading_term(x) == exp(1/x) - assert exp(2+x).as_leading_term(x) == exp(2) + assert exp(2 + x).as_leading_term(x) == exp(2) + def test_log_values(): assert log(nan) == nan @@ -150,6 +162,7 @@ assert log(2*3).func is log assert log(2*3**2).func is log + def test_log_base(): assert log(1, 2) == 0 assert log(2, 2) == 1 @@ -160,6 +173,11 @@ assert log(3**3, 3) == 3 assert log(5, 1) == zoo assert log(1, 1) == nan + assert log(Rational(2, 3), 10) == (-log(3) + log(2))/log(10) + assert log(Rational(2, 3), Rational(1, 3)) == -log(2)/log(3) + 1 + assert log(Rational(2, 3), Rational(2, 5)) == \ + (-log(3) + log(2))/(-log(5) + log(2)) + def test_log_symbolic(): x, y = symbols('x,y') @@ -177,7 +195,6 @@ assert log(x, 2) == log(x)/log(2) assert log(E, 2) == 1/log(2) - p, q = symbols('p,q', positive=True) r = Symbol('r', real=True) @@ -200,6 +217,7 @@ assert log(-x).func is log and log(-x).args[0] == -x assert log(-p).func is log and log(-p).args[0] == -p + def test_exp_assumptions(): x = Symbol('x') r = Symbol('r', real=True) @@ -214,15 +232,17 @@ assert e(re(x)).is_real is True assert e(re(x)).is_imaginary is False + def test_log_assumptions(): p = symbols('p', positive=True) n = symbols('n', negative=True) assert log(2) > 0 assert log(1).is_zero - assert log(2-pi-pi*(1/pi-1)).is_zero + assert log(2 - pi - pi*(1/pi - 1)).is_zero assert log(p).is_zero is None assert log(n).is_zero is False - assert log(0.5).is_negative == True + assert log(0.5).is_negative is True + def test_log_hashing(): x = Symbol("y") @@ -230,9 +250,9 @@ assert hash(x) != hash(log(log(x))) assert log(x) != log(log(log(x))) - e = 1/log(log(x)+log(log(x))) + e = 1/log(log(x) + log(log(x))) assert e.base.func is log - e = 1/log(log(x)+log(log(log(x)))) + e = 1/log(log(x) + log(log(log(x)))) assert e.base.func is log x = Symbol("x") @@ -242,29 +262,34 @@ assert hash(log(log(x))) != hash(x) assert e != x + def test_log_sign(): assert sign(log(2)) == 1 + def test_log_expand_complex(): - assert log(1+I).expand(complex=True) == log(2)/2 + I*pi/4 - assert log(1 - sqrt(2)).expand(complex=True) == log(sqrt(2)-1) + I*pi + assert log(1 + I).expand(complex=True) == log(2)/2 + I*pi/4 + assert log(1 - sqrt(2)).expand(complex=True) == log(sqrt(2) - 1) + I*pi + def test_log_apply_evalf(): - value = (log(3)/log(2)-1).evalf() + value = (log(3)/log(2) - 1).evalf() assert value.epsilon_eq(Float("0.58496250072115618145373")) + def test_log_expand(): w = Symbol("w", positive=True) e = log(w**(log(5)/log(3))) assert e.expand() == log(5)/log(3) * log(w) x, y, z = symbols('x,y,z', positive=True) - assert log(x*(y+z)).expand(mul=False) == log(x)+log(y+z) + assert log(x*(y + z)).expand(mul=False) == log(x) + log(y + z) assert log(log(x**2)*log(y*z)).expand() in [log(2*log(x)*log(y) + 2*log(x)*log(z)), log(log(x)*log(z) + log(y)*log(x)) + log(2), log((log(y) + log(z))*log(x)) + log(2)] assert log(x**log(x**2)).expand(deep=False) == log(x)*log(x**2) assert log(x**log(x**2)).expand() == 2*log(x)**2 - assert (log(x*(y+z))*(x+y)),expand(mul=True, log=True) == y*log(x) + y*log(y + z) + z*log(x) + z*log(y + z) + assert (log(x*(y + z))*(x + y)), expand(mul=True, log=True) == y*log( + x) + y*log(y + z) + z*log(x) + z*log(y + z) x, y = symbols('x,y') assert log(x*y).expand(force=True) == log(x) + log(y) assert log(x**y).expand(force=True) == y*log(x) @@ -274,10 +299,12 @@ # logs together than it is to take them apart. assert log(2*3**2).expand() != 2*log(3) + log(2) + def test_log_simplify(): x = Symbol("x", positive=True) assert log(x**2).expand() == 2*log(x) - assert expand_log(log(x**(2+log(2)))) == (2+log(2))*log(x) + assert expand_log(log(x**(2 + log(2)))) == (2 + log(2))*log(x) + def test_lambertw(): x = Symbol('x') @@ -287,18 +314,20 @@ assert LambertW(-1/E) == -1 assert LambertW(-log(2)/2) == -log(2) assert LambertW(oo) == oo - assert LambertW(x**2).diff(x) == 2*LambertW(x**2)/x/(1+LambertW(x**2)) + assert LambertW(x**2).diff(x) == 2*LambertW(x**2)/x/(1 + LambertW(x**2)) assert LambertW(sqrt(2)).evalf(30).epsilon_eq( - Float("0.701338383413663009202120278965",30),1e-29) + Float("0.701338383413663009202120278965", 30), 1e-29) + def test_exp_expand(): - A,B,C = symbols('A,B,C', commutative=False) - x,y,z = symbols('x,y,z') + A, B, C = symbols('A,B,C', commutative=False) + x, y, z = symbols('x,y,z') + + assert exp(A + B).expand() == exp(A + B) + assert exp(A + B + C).expand() == exp(A + B + C) + assert exp(x + y).expand() == exp(x)*exp(y) + assert exp(x + y + z).expand() == exp(x)*exp(y)*exp(z) - assert exp(A+B).expand() == exp(A+B) - assert exp(A+B+C).expand() == exp(A+B+C) - assert exp(x+y).expand() == exp(x)*exp(y) - assert exp(x+y+z).expand() == exp(x)*exp(y)*exp(z) def test_as_numer_denom(): from sympy.abc import x @@ -329,3 +358,16 @@ # Compare exp(1.0*pi*I). assert (exp_polar(1.0*pi*I).n(n=5)).as_real_imag()[1] >= 0 + +def test_log_product(): + from sympy.abc import n, m + i, j = symbols('i,j', positive=True, integer=True) + x, y = symbols('x,y', positive=True) + from sympy.concrete import Product, Sum + f, g = Function('f'), Function('g') + assert simplify(log(Product(x**i, (i, 1, n)))) == Sum(i*log(x), (i, 1, n)) + assert simplify(log(Product(x**i*y**j, (i, 1, n), (j, 1, m)))) == \ + log(Product(x**i*y**j, (i, 1, n), (j, 1, m))) + + expr = log(Product(-2, (n, 0, 4))) + assert Eq(simplify(expr), expr) diff -Nru python3-sympy-0.7.2/sympy/functions/elementary/tests/test_hyperbolic.py python3-sympy-0.7.3/sympy/functions/elementary/tests/test_hyperbolic.py --- python3-sympy-0.7.2/sympy/functions/elementary/tests/test_hyperbolic.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/functions/elementary/tests/test_hyperbolic.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,8 +1,9 @@ from sympy import symbols, Symbol, sinh, nan, oo, zoo, pi, asinh, acosh, log, sqrt, \ - coth, I, cot, E, tanh, tan, cosh, cos, S, sin, Rational, atanh, acoth, \ - Integer, O, exp + coth, I, cot, E, tanh, tan, cosh, cos, S, sin, Rational, atanh, acoth, \ + Integer, O, exp + +from sympy.utilities.pytest import XFAIL, raises -from sympy.utilities.pytest import XFAIL def test_sinh(): x, y = symbols('x,y') @@ -66,12 +67,12 @@ assert sinh(k*pi*I/2) == sin(k*pi/2)*I - assert sinh(x).inverse() == asinh def test_sinh_series(): x = Symbol('x') assert sinh(x).series(x, 0, 10) == \ - x + x**3/6 + x**5/120 + x**7/5040 + x**9/362880 + O(x**10) + x + x**3/6 + x**5/120 + x**7/5040 + x**9/362880 + O(x**10) + def test_cosh(): x, y = symbols('x,y') @@ -102,8 +103,8 @@ assert cosh(-pi*I/2) == 0 assert cosh(pi*I/2) == 0 assert cosh(-pi*I/2) == 0 - assert cosh((-3*10**73+1)*pi*I/2) == 0 - assert cosh((7*10**103+1)*pi*I/2) == 0 + assert cosh((-3*10**73 + 1)*pi*I/2) == 0 + assert cosh((7*10**103 + 1)*pi*I/2) == 0 assert cosh(pi*I) == -1 assert cosh(-pi*I) == -1 @@ -135,12 +136,12 @@ assert cosh(k*pi) == cosh(k*pi) - assert cosh(x).inverse() == acosh def test_cosh_series(): x = Symbol('x') assert cosh(x).series(x, 0, 10) == \ - 1 + x**2/2 + x**4/24 + x**6/720 + x**8/40320 + O(x**10) + 1 + x**2/2 + x**4/24 + x**6/720 + x**8/40320 + O(x**10) + def test_tanh(): x, y = symbols('x,y') @@ -204,12 +205,12 @@ assert tanh(k*pi*I/2) == tan(k*pi/2)*I - assert tanh(x).inverse() == atanh def test_tanh_series(): x = Symbol('x') assert tanh(x).series(x, 0, 10) == \ - x - x**3/3 + 2*x**5/15 - 17*x**7/315 + 62*x**9/2835 + O(x**10) + x - x**3/3 + 2*x**5/15 - 17*x**7/315 + 62*x**9/2835 + O(x**10) + def test_coth(): x, y = symbols('x,y') @@ -273,12 +274,12 @@ assert coth(k*pi*I) == -cot(k*pi)*I - assert coth(x).inverse() == acoth def test_coth_series(): x = Symbol('x') assert coth(x).series(x, 0, 8) == \ - 1/x + x/3 - x**3/45 + 2*x**5/945 - x**7/4725 + O(x**8) + 1/x + x/3 - x**3/45 + 2*x**5/945 - x**7/4725 + O(x**8) + def test_asinh(): x, y = symbols('x,y') @@ -286,9 +287,9 @@ assert asinh(-x) == -asinh(x) assert asinh(nan) == nan assert asinh( 0) == 0 - assert asinh(+1) == log(sqrt(2)+1) + assert asinh(+1) == log(sqrt(2) + 1) - assert asinh(-1) == log(sqrt(2)-1) + assert asinh(-1) == log(sqrt(2) - 1) assert asinh(I) == pi*I/2 assert asinh(-I) == -pi*I/2 assert asinh(I/2) == pi*I/6 @@ -305,20 +306,22 @@ assert asinh(I *(sqrt(3) - 1)/(2**(S(3)/2))) == pi*I/12 assert asinh(-I *(sqrt(3) - 1)/(2**(S(3)/2))) == -pi*I/12 - assert asinh(I*(sqrt(5)-1)/4) == pi*I/10 - assert asinh(-I*(sqrt(5)-1)/4) == -pi*I/10 + assert asinh(I*(sqrt(5) - 1)/4) == pi*I/10 + assert asinh(-I*(sqrt(5) - 1)/4) == -pi*I/10 + + assert asinh(I*(sqrt(5) + 1)/4) == 3*pi*I/10 + assert asinh(-I*(sqrt(5) + 1)/4) == -3*pi*I/10 - assert asinh(I*(sqrt(5)+1)/4) == 3*pi*I/10 - assert asinh(-I*(sqrt(5)+1)/4) == -3*pi*I/10 def test_asinh_series(): x = Symbol('x') assert asinh(x).series(x, 0, 8) == \ - x - x**3/6 + 3*x**5/40 - 5*x**7/112 + O(x**8) + x - x**3/6 + 3*x**5/40 - 5*x**7/112 + O(x**8) t5 = asinh(x).taylor_term(5, x) assert t5 == 3*x**5/40 assert asinh(x).taylor_term(7, x, t5, 0) == -5*x**7/112 + def test_acosh(): # TODO please write more tests -- see #652 # From http://functions.wolfram.com/ElementaryFunctions/ArcCosh/03/01/ @@ -326,27 +329,27 @@ assert acosh(1) == 0 assert acosh(-1) == pi*I assert acosh(0) == I*pi/2 - assert acosh(Rational(1,2)) == I*pi/3 - assert acosh(Rational(-1,2)) == 2*pi*I/3 + assert acosh(Rational(1, 2)) == I*pi/3 + assert acosh(Rational(-1, 2)) == 2*pi*I/3 assert acosh(zoo) == oo - assert acosh(I) == log(I*(1+sqrt(2))) - assert acosh(-I) == log(-I*(1+sqrt(2))) - assert acosh((sqrt(3)-1)/(2*sqrt(2))) == 5*pi*I/12 - assert acosh(-(sqrt(3)-1)/(2*sqrt(2))) == 7*pi*I/12 + assert acosh(I) == log(I*(1 + sqrt(2))) + assert acosh(-I) == log(-I*(1 + sqrt(2))) + assert acosh((sqrt(3) - 1)/(2*sqrt(2))) == 5*pi*I/12 + assert acosh(-(sqrt(3) - 1)/(2*sqrt(2))) == 7*pi*I/12 assert acosh(sqrt(2)/2) == I*pi/4 assert acosh(-sqrt(2)/2) == 3*I*pi/4 assert acosh(sqrt(3)/2) == I*pi/6 assert acosh(-sqrt(3)/2) == 5*I*pi/6 - assert acosh(sqrt(2+sqrt(2))/2) == I*pi/8 - assert acosh(-sqrt(2+sqrt(2))/2) == 7*I*pi/8 - assert acosh(sqrt(2-sqrt(2))/2) == 3*I*pi/8 - assert acosh(-sqrt(2-sqrt(2))/2) == 5*I*pi/8 - assert acosh((1+sqrt(3))/(2*sqrt(2))) == I*pi/12 - assert acosh(-(1+sqrt(3))/(2*sqrt(2))) == 11*I*pi/12 - assert acosh((sqrt(5)+1)/4) == I*pi/5 - assert acosh(-(sqrt(5)+1)/4) == 4*I*pi/5 + assert acosh(sqrt(2 + sqrt(2))/2) == I*pi/8 + assert acosh(-sqrt(2 + sqrt(2))/2) == 7*I*pi/8 + assert acosh(sqrt(2 - sqrt(2))/2) == 3*I*pi/8 + assert acosh(-sqrt(2 - sqrt(2))/2) == 5*I*pi/8 + assert acosh((1 + sqrt(3))/(2*sqrt(2))) == I*pi/12 + assert acosh(-(1 + sqrt(3))/(2*sqrt(2))) == 11*I*pi/12 + assert acosh((sqrt(5) + 1)/4) == I*pi/5 + assert acosh(-(sqrt(5) + 1)/4) == 4*I*pi/5 def test_acosh_infinities(): @@ -355,10 +358,11 @@ assert acosh(I*oo) == oo assert acosh(-I*oo) == oo + def test_acosh_series(): x = Symbol('x') assert acosh(x).series(x, 0, 8) == \ - -I*x + pi*I/2 - I*x**3/6 - 3*I*x**5/40 - 5*I*x**7/112 + O(x**8) + -I*x + pi*I/2 - I*x**3/6 - 3*I*x**5/40 - 5*I*x**7/112 + O(x**8) t5 = acosh(x).taylor_term(5, x) assert t5 == - 3*I*x**5/40 assert acosh(x).taylor_term(7, x, t5, 0) == - 5*I*x**7/112 @@ -391,26 +395,30 @@ assert atanh(-I/sqrt(3)) == -I*pi/6 assert atanh(I*sqrt(3)) == I*pi/3 assert atanh(-I*sqrt(3)) == -I*pi/3 - assert atanh(I*(1+sqrt(2))) == 3*pi*I/8 - assert atanh(I*(sqrt(2)-1)) == pi*I/8 - assert atanh(I*(1-sqrt(2))) == -pi*I/8 - assert atanh(-I*(1+sqrt(2))) == -3*pi*I/8 - assert atanh(I*sqrt(5+2*sqrt(5))) == 2*I*pi/5 - assert atanh(-I*sqrt(5+2*sqrt(5))) == -2*I*pi/5 - assert atanh(I*(2-sqrt(3))) == pi*I/12 - assert atanh(I*(sqrt(3)-2)) == -pi*I/12 + assert atanh(I*(1 + sqrt(2))) == 3*pi*I/8 + assert atanh(I*(sqrt(2) - 1)) == pi*I/8 + assert atanh(I*(1 - sqrt(2))) == -pi*I/8 + assert atanh(-I*(1 + sqrt(2))) == -3*pi*I/8 + assert atanh(I*sqrt(5 + 2*sqrt(5))) == 2*I*pi/5 + assert atanh(-I*sqrt(5 + 2*sqrt(5))) == -2*I*pi/5 + assert atanh(I*(2 - sqrt(3))) == pi*I/12 + assert atanh(I*(sqrt(3) - 2)) == -pi*I/12 assert atanh(oo) == -I*pi/2 + def test_atanh_series(): x = Symbol('x') assert atanh(x).series(x, 0, 10) == \ - x + x**3/3 + x**5/5 + x**7/7 + x**9/9 + O(x**10) + x + x**3/3 + x**5/5 + x**7/7 + x**9/9 + O(x**10) + def test_atanh_infinities(): assert atanh(oo) == -I*pi/2 assert atanh(-oo) == I*pi/2 # TODO please write more tests -- see #652 + + def test_acoth(): # TODO please write more tests -- see #652 # From http://functions.wolfram.com/ElementaryFunctions/ArcCoth/03/01/ @@ -438,21 +446,35 @@ assert acoth(-I/sqrt(3)) == I*pi/3 assert acoth(I*sqrt(3)) == -I*pi/6 assert acoth(-I*sqrt(3)) == I*pi/6 - assert acoth(I*(1+sqrt(2))) == -pi*I/8 - assert acoth(-I*(sqrt(2)+1)) == pi*I/8 - assert acoth(I*(1-sqrt(2))) == 3*pi*I/8 - assert acoth(I*(sqrt(2)-1)) == -3*pi*I/8 - assert acoth(I*sqrt(5+2*sqrt(5))) == -I*pi/10 - assert acoth(-I*sqrt(5+2*sqrt(5))) == I*pi/10 - assert acoth(I*(2+sqrt(3))) == -pi*I/12 - assert acoth(-I*(2+sqrt(3))) == pi*I/12 - assert acoth(I*(2-sqrt(3))) == -5*pi*I/12 - assert acoth(I*(sqrt(3)-2)) == 5*pi*I/12 + assert acoth(I*(1 + sqrt(2))) == -pi*I/8 + assert acoth(-I*(sqrt(2) + 1)) == pi*I/8 + assert acoth(I*(1 - sqrt(2))) == 3*pi*I/8 + assert acoth(I*(sqrt(2) - 1)) == -3*pi*I/8 + assert acoth(I*sqrt(5 + 2*sqrt(5))) == -I*pi/10 + assert acoth(-I*sqrt(5 + 2*sqrt(5))) == I*pi/10 + assert acoth(I*(2 + sqrt(3))) == -pi*I/12 + assert acoth(-I*(2 + sqrt(3))) == pi*I/12 + assert acoth(I*(2 - sqrt(3))) == -5*pi*I/12 + assert acoth(I*(sqrt(3) - 2)) == 5*pi*I/12 + def test_acoth_series(): x = Symbol('x') assert acoth(x).series(x, 0, 10) == \ - I*pi/2 + x + x**3/3 + x**5/5 + x**7/7 + x**9/9 + O(x**10) + I*pi/2 + x + x**3/3 + x**5/5 + x**7/7 + x**9/9 + O(x**10) + + +def test_inverses(): + x = Symbol('x') + assert sinh(x).inverse() == asinh + raises(AttributeError, lambda: cosh(x).inverse()) + assert tanh(x).inverse() == atanh + assert coth(x).inverse() == acoth + assert asinh(x).inverse() == sinh + assert acosh(x).inverse() == cosh + assert atanh(x).inverse() == tanh + assert acoth(x).inverse() == coth + def test_leading_term(): x = Symbol('x') @@ -465,80 +487,93 @@ eq = func(arg) assert eq.as_leading_term(x) == eq + def test_complex(): - a,b = symbols('a,b', real=True) + a, b = symbols('a,b', real=True) z = a + b*I for func in [sinh, cosh, tanh, coth]: assert func(z).conjugate() == func(a - b*I) - for deep in [True,False]: - assert sinh(z).expand(complex=True,deep=deep) == sinh(a)*cos(b) + I*cosh(a)*sin(b) - assert cosh(z).expand(complex=True,deep=deep) == cosh(a)*cos(b) + I*sinh(a)*sin(b) - assert tanh(z).expand(complex=True,deep=deep) == sinh(a)*cosh(a)/(cos(b)**2+sinh(a)**2) + I*sin(b)*cos(b)/(cos(b)**2+sinh(a)**2) - assert coth(z).expand(complex=True,deep=deep) == sinh(a)*cosh(a)/(sin(b)**2+sinh(a)**2) - I*sin(b)*cos(b)/(sin(b)**2+sinh(a)**2) + for deep in [True, False]: + assert sinh(z).expand( + complex=True, deep=deep) == sinh(a)*cos(b) + I*cosh(a)*sin(b) + assert cosh(z).expand( + complex=True, deep=deep) == cosh(a)*cos(b) + I*sinh(a)*sin(b) + assert tanh(z).expand(complex=True, deep=deep) == sinh(a)*cosh( + a)/(cos(b)**2 + sinh(a)**2) + I*sin(b)*cos(b)/(cos(b)**2 + sinh(a)**2) + assert coth(z).expand(complex=True, deep=deep) == sinh(a)*cosh( + a)/(sin(b)**2 + sinh(a)**2) - I*sin(b)*cos(b)/(sin(b)**2 + sinh(a)**2) + def test_complex_2899(): - a,b = symbols('a,b', real=True) - for deep in [True,False]: + a, b = symbols('a,b', real=True) + for deep in [True, False]: for func in [sinh, cosh, tanh, coth]: - assert func(a).expand(complex=True,deep=deep) == func(a) + assert func(a).expand(complex=True, deep=deep) == func(a) + def test_simplifications(): x = Symbol('x') assert sinh(asinh(x)) == x - assert sinh(acosh(x)) == sqrt(x-1) * sqrt(x+1) - assert sinh(atanh(x)) == x/sqrt(1-x**2) - assert sinh(acoth(x)) == 1/(sqrt(x-1) * sqrt(x+1)) + assert sinh(acosh(x)) == sqrt(x - 1) * sqrt(x + 1) + assert sinh(atanh(x)) == x/sqrt(1 - x**2) + assert sinh(acoth(x)) == 1/(sqrt(x - 1) * sqrt(x + 1)) - assert cosh(asinh(x)) == sqrt(1+x**2) + assert cosh(asinh(x)) == sqrt(1 + x**2) assert cosh(acosh(x)) == x - assert cosh(atanh(x)) == 1/sqrt(1-x**2) - assert cosh(acoth(x)) == x/(sqrt(x-1) * sqrt(x+1)) + assert cosh(atanh(x)) == 1/sqrt(1 - x**2) + assert cosh(acoth(x)) == x/(sqrt(x - 1) * sqrt(x + 1)) - assert tanh(asinh(x)) == x/sqrt(1+x**2) - assert tanh(acosh(x)) == sqrt(x-1) * sqrt(x+1) / x + assert tanh(asinh(x)) == x/sqrt(1 + x**2) + assert tanh(acosh(x)) == sqrt(x - 1) * sqrt(x + 1) / x assert tanh(atanh(x)) == x assert tanh(acoth(x)) == 1/x - assert coth(asinh(x)) == sqrt(1+x**2)/x - assert coth(acosh(x)) == x/(sqrt(x-1) * sqrt(x+1)) + assert coth(asinh(x)) == sqrt(1 + x**2)/x + assert coth(acosh(x)) == x/(sqrt(x - 1) * sqrt(x + 1)) assert coth(atanh(x)) == 1/x assert coth(acoth(x)) == x + def test_issue1037(): assert cosh(asinh(Integer(3)/2)) == sqrt(Integer(13)/4) + def test_sinh_rewrite(): x = Symbol('x') - assert sinh(x).rewrite(exp) == (exp(x)-exp(-x))/2 - assert sinh(x).rewrite(cosh) == -I*cosh(x+I*pi/2) + assert sinh(x).rewrite(exp) == (exp(x) - exp(-x))/2 + assert sinh(x).rewrite(cosh) == -I*cosh(x + I*pi/2) tanh_half = tanh(S.Half*x) - assert sinh(x).rewrite(tanh) == 2*tanh_half/(1-tanh_half**2) + assert sinh(x).rewrite(tanh) == 2*tanh_half/(1 - tanh_half**2) coth_half = coth(S.Half*x) - assert sinh(x).rewrite(coth) == 2*coth_half/(coth_half**2-1) + assert sinh(x).rewrite(coth) == 2*coth_half/(coth_half**2 - 1) + def test_cosh_rewrite(): x = Symbol('x') - assert cosh(x).rewrite(exp) == (exp(x)+exp(-x))/2 - assert cosh(x).rewrite(sinh) == -I*sinh(x+I*pi/2) + assert cosh(x).rewrite(exp) == (exp(x) + exp(-x))/2 + assert cosh(x).rewrite(sinh) == -I*sinh(x + I*pi/2) tanh_half = tanh(S.Half*x)**2 - assert cosh(x).rewrite(tanh) == (1+tanh_half)/(1-tanh_half) + assert cosh(x).rewrite(tanh) == (1 + tanh_half)/(1 - tanh_half) coth_half = coth(S.Half*x)**2 - assert cosh(x).rewrite(coth) == (coth_half+1)/(coth_half-1) + assert cosh(x).rewrite(coth) == (coth_half + 1)/(coth_half - 1) + def test_tanh_rewrite(): x = Symbol('x') - assert tanh(x).rewrite(exp) == (exp(x)-exp(-x))/(exp(x)+exp(-x)) - assert tanh(x).rewrite(sinh) == I*sinh(x)/sinh(I*pi/2-x) - assert tanh(x).rewrite(cosh) == I*cosh(I*pi/2-x)/cosh(x) + assert tanh(x).rewrite(exp) == (exp(x) - exp(-x))/(exp(x) + exp(-x)) + assert tanh(x).rewrite(sinh) == I*sinh(x)/sinh(I*pi/2 - x) + assert tanh(x).rewrite(cosh) == I*cosh(I*pi/2 - x)/cosh(x) assert tanh(x).rewrite(coth) == 1/coth(x) + def test_coth_rewrite(): x = Symbol('x') - assert coth(x).rewrite(exp) == (exp(x)+exp(-x))/(exp(x)-exp(-x)) - assert coth(x).rewrite(sinh) == -I*sinh(I*pi/2-x)/sinh(x) - assert coth(x).rewrite(cosh) == -I*cosh(x)/cosh(I*pi/2-x) + assert coth(x).rewrite(exp) == (exp(x) + exp(-x))/(exp(x) - exp(-x)) + assert coth(x).rewrite(sinh) == -I*sinh(I*pi/2 - x)/sinh(x) + assert coth(x).rewrite(cosh) == -I*cosh(x)/cosh(I*pi/2 - x) assert coth(x).rewrite(tanh) == 1/tanh(x) + def test_derivs(): x = Symbol('x') assert coth(x).diff(x) == -sinh(x)**(-2) @@ -549,3 +584,17 @@ assert asinh(x).diff(x) == 1/sqrt(x**2 + 1) assert acosh(x).diff(x) == 1/sqrt(x**2 - 1) assert atanh(x).diff(x) == 1/(-x**2 + 1) + +def test_sinh_expansion(): + x,y = symbols('x,y') + assert sinh(x+y).expand(trig=True) == sinh(x)*cosh(y) + cosh(x)*sinh(y) + assert sinh(2*x).expand(trig=True) == 2*sinh(x)*cosh(x) + assert sinh(3*x).expand(trig=True).expand() == \ + sinh(x)**3 + 3*sinh(x)*cosh(x)**2 + +def test_cosh_expansion(): + x,y = symbols('x,y') + assert cosh(x+y).expand(trig=True) == cosh(x)*cosh(y) + sinh(x)*sinh(y) + assert cosh(2*x).expand(trig=True) == cosh(x)**2 + sinh(x)**2 + assert cosh(3*x).expand(trig=True).expand() == \ + 3*sinh(x)**2*cosh(x) + cosh(x)**3 diff -Nru python3-sympy-0.7.2/sympy/functions/elementary/tests/test_integers.py python3-sympy-0.7.3/sympy/functions/elementary/tests/test_integers.py --- python3-sympy-0.7.2/sympy/functions/elementary/tests/test_integers.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/functions/elementary/tests/test_integers.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,8 +1,9 @@ from sympy import Symbol, floor, nan, oo, E, symbols, ceiling, pi, Rational, \ - Float, I, sin, exp, log, factorial + Float, I, sin, exp, log, factorial from sympy.utilities.pytest import XFAIL + def test_floor(): x = Symbol('x') @@ -198,8 +199,9 @@ assert ceiling(factorial(50)/exp(1)) == \ 11188719610782480504630258070757734324011354208865721592720336801 + def test_series(): - x,y = symbols('x,y') + x, y = symbols('x,y') assert floor(x).nseries(x, y, 100) == floor(y) assert ceiling(x).nseries(x, y, 100) == ceiling(y) assert floor(x).nseries(x, pi, 100) == 3 @@ -209,8 +211,9 @@ assert floor(-x).nseries(x, 0, 100) == -1 assert ceiling(-x).nseries(x, 0, 100) == 0 + @XFAIL def test_issue_1050(): - assert floor(3 + pi*I + y*I) == 3 + floor(pi+y)*I - assert floor(3*I + pi*I + y*I) == floor(3+pi+y)*I - assert floor(3 + E + pi*I + y*I) == 5 + floor(pi+y)*I + assert floor(3 + pi*I + y*I) == 3 + floor(pi + y)*I + assert floor(3*I + pi*I + y*I) == floor(3 + pi + y)*I + assert floor(3 + E + pi*I + y*I) == 5 + floor(pi + y)*I diff -Nru python3-sympy-0.7.2/sympy/functions/elementary/tests/test_interface.py python3-sympy-0.7.3/sympy/functions/elementary/tests/test_interface.py --- python3-sympy-0.7.2/sympy/functions/elementary/tests/test_interface.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/functions/elementary/tests/test_interface.py 2013-07-13 17:53:32.000000000 +0000 @@ -3,13 +3,14 @@ from sympy import Function, sympify, sin, cos, limit, tanh from sympy.abc import x + def test_function_series1(): """Create our new "sin" function.""" class my_function(Function): nargs = 1 - def fdiff(self, argindex = 1): + def fdiff(self, argindex=1): return cos(self.args[0]) @classmethod @@ -22,13 +23,14 @@ assert my_function(x).series(x, 0, 10) == sin(x).series(x, 0, 10) assert limit(my_function(x)/x, x, 0) == 1 + def test_function_series2(): """Create our new "cos" function.""" class my_function2(Function): nargs = 1 - def fdiff(self, argindex = 1): + def fdiff(self, argindex=1): return -sin(self.args[0]) @classmethod @@ -40,6 +42,7 @@ #Test that the taylor series is correct assert my_function2(x).series(x, 0, 10) == cos(x).series(x, 0, 10) + def test_function_series3(): """ Test our easy "tanh" function. @@ -54,8 +57,8 @@ class mytanh(Function): nargs = 1 - def fdiff(self, argindex = 1): - return 1-mytanh(self.args[0])**2 + def fdiff(self, argindex=1): + return 1 - mytanh(self.args[0])**2 @classmethod def eval(cls, arg): diff -Nru python3-sympy-0.7.2/sympy/functions/elementary/tests/test_miscellaneous.py python3-sympy-0.7.3/sympy/functions/elementary/tests/test_miscellaneous.py --- python3-sympy-0.7.2/sympy/functions/elementary/tests/test_miscellaneous.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/functions/elementary/tests/test_miscellaneous.py 2013-07-13 17:53:32.000000000 +0000 @@ -4,6 +4,7 @@ from sympy.functions.elementary.miscellaneous import sqrt, root, Min, Max, real_root from sympy import S, Float, I, cos, sin, oo, pi, Add + def test_Min(): from sympy.abc import x, y, z n = Symbol('n', negative=True) @@ -77,10 +78,10 @@ assert Min(x, y, z) == Min(z, y, x) assert Min(x, Min(y, z)) == Min(z, y, x) assert Min(x, Max(y, -oo)) == Min(x, y) - assert Min(p, oo, n, p, p, p_) == n + assert Min(p, oo, n, p, p, p_) == n assert Min(p_, n_, p) == n_ - assert Min(n, oo, -7, p, p, 2) == Min(n, -7) - assert Min(2, x, p, n, oo, n_, p, 2, -2, -2) == Min(-2, x, n, n_) + assert Min(n, oo, -7, p, p, 2) == Min(n, -7) + assert Min(2, x, p, n, oo, n_, p, 2, -2, -2) == Min(-2, x, n, n_) assert Min(0, x, 1, y) == Min(0, x, y) assert Min(1000, 100, -100, x, p, n) == Min(n, x, -100) assert Min(cos(x), sin(x)) == Min(cos(x), sin(x)) @@ -91,6 +92,12 @@ raises(ValueError, lambda: Min(I, x)) raises(ValueError, lambda: Min(S.ComplexInfinity, x)) + from sympy.functions.special.delta_functions import Heaviside + assert Min(1,x).diff(x) == Heaviside(1-x) + assert Min(x,1).diff(x) == Heaviside(1-x) + assert Min(0,-x,1-2*x).diff(x) == -Heaviside(x + Min(0, -2*x + 1)) \ + - 2*Heaviside(2*x + Min(0, -x) - 1) + def test_Max(): from sympy.abc import x, y, z @@ -112,9 +119,9 @@ assert Max(x, y, z) == Max(z, y, x) assert Max(x, Max(y, z)) == Max(z, y, x) assert Max(x, Min(y, oo)) == Max(x, y) - assert Max(n, -oo, n_, p, 2) == Max(p, 2) - assert Max(n, -oo, n_, p) == p - assert Max(2, x, p, n, -oo, S.NegativeInfinity, n_, p, 2) == Max(2, x, p) + assert Max(n, -oo, n_, p, 2) == Max(p, 2) + assert Max(n, -oo, n_, p) == p + assert Max(2, x, p, n, -oo, S.NegativeInfinity, n_, p, 2) == Max(2, x, p) assert Max(0, x, 1, y) == Max(1, x, y) assert Max(x, x + 1, x - 1) == 1 + x assert Max(1000, 100, -100, x, p, n) == Max(p, x, 1000) @@ -131,6 +138,12 @@ # Max(n, -oo, n_, p, 1000) == Max(p, 1000) # False + from sympy.functions.special.delta_functions import Heaviside + assert Max(1,x).diff(x) == Heaviside(x-1) + assert Max(x,1).diff(x) == Heaviside(x-1) + assert Max(x**2, 1+x, 1).diff(x) == 2*x*Heaviside(x**2 - Max(1,x+1)) \ + + Heaviside(x - Max(1,x**2) + 1) + def test_root(): from sympy.abc import x, y, z @@ -138,8 +151,8 @@ assert root(2, 2) == sqrt(2) assert root(2, 1) == 2 - assert root(2, 3) == 2**Rational(1,3) - assert root(2, -5) == 2**Rational(4,5)/2 + assert root(2, 3) == 2**Rational(1, 3) + assert root(2, -5) == 2**Rational(4, 5)/2 assert root(-2, 1) == -2 @@ -148,12 +161,13 @@ assert root(x, 2) == sqrt(x) assert root(x, 1) == x - assert root(x, 3) == x**Rational(1,3) - assert root(x, -5) == x**Rational(-1,5) + assert root(x, 3) == x**Rational(1, 3) + assert root(x, -5) == x**Rational(-1, 5) assert root(x, n) == x**(1/n) assert root(x, -n) == x**(-1/n) + def test_nthroot(): assert real_root(-8, 3) == -2 assert real_root(-16, 4) == root(-16, 4) diff -Nru python3-sympy-0.7.2/sympy/functions/elementary/tests/test_piecewise.py python3-sympy-0.7.3/sympy/functions/elementary/tests/test_piecewise.py --- python3-sympy-0.7.2/sympy/functions/elementary/tests/test_piecewise.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/functions/elementary/tests/test_piecewise.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,51 +1,78 @@ -from sympy import (diff, expand, Eq, Integral, integrate, Interval, lambdify, - log, oo, Piecewise, piecewise_fold, symbols, pi, solve, - Rational, Basic, Function, I, conjugate, re, im, And, Or, - Max, Min) +from sympy import ( + adjoint, And, Basic, conjugate, diff, expand, Eq, Function, I, im, + Integral, integrate, Interval, lambdify, log, Max, Min, oo, Or, pi, + Piecewise, piecewise_fold, Rational, re, solve, symbols, transpose, + cos, exp, Abs, Not +) from sympy.utilities.pytest import XFAIL, raises -x,y = symbols('x,y') +x, y = symbols('x y') +z = symbols('z', nonzero=True) + def test_piecewise(): # Test canonization assert Piecewise((x, x < 1), (0, True)) == Piecewise((x, x < 1), (0, True)) - assert Piecewise((x, x < 1), (0, True), (1, True)) == Piecewise((x, x < 1), (0, True)) - assert Piecewise((x, x < 1), (0, False), (-1, 1 > 2)) == Piecewise((x, x < 1)) - assert Piecewise((x, x < 1), (0, x < 2), (0, True)) == Piecewise((x, x < 1), (0, True)) - assert Piecewise((x, x < 1), (x, x < 2), (0, True)) == Piecewise((x, Or(x < 1, x < 2)), (0, True)) + assert Piecewise((x, x < 1), (0, True), (1, True)) == \ + Piecewise((x, x < 1), (0, True)) + assert Piecewise((x, x < 1), (0, False), (-1, 1 > 2)) == \ + Piecewise((x, x < 1)) + assert Piecewise((x, x < 1), (0, x < 1), (0, True)) == \ + Piecewise((x, x < 1), (0, True)) + assert Piecewise((x, x < 1), (0, x < 2), (0, True)) == \ + Piecewise((x, x < 1), (0, True)) + assert Piecewise((x, x < 1), (x, x < 2), (0, True)) == \ + Piecewise((x, Or(x < 1, x < 2)), (0, True)) assert Piecewise((x, x < 1), (x, x < 2), (x, True)) == x assert Piecewise((x, True)) == x + assert Piecewise((1, Eq(x + 1/x, (x**2 + 1)/x)), (2, True)) == 1 raises(TypeError, lambda: Piecewise(x)) - raises(TypeError, lambda: Piecewise((x,x**2))) + raises(TypeError, lambda: Piecewise((x, x**2))) # Test subs - p = Piecewise((-1, x < -1), (x**2, x < 0), (log(x), x >=0)) - p_x2 = Piecewise((-1, x**2 < -1), (x**4, x**2 < 0), (log(x**2), x**2 >=0)) - assert p.subs(x,x**2) == p_x2 - assert p.subs(x,-5) == -1 - assert p.subs(x,-1) == 1 - assert p.subs(x,1) == log(1) + p = Piecewise((-1, x < -1), (x**2, x < 0), (log(x), x >= 0)) + p_x2 = Piecewise((-1, x**2 < -1), (x**4, x**2 < 0), (log(x**2), x**2 >= 0)) + assert p.subs(x, x**2) == p_x2 + assert p.subs(x, -5) == -1 + assert p.subs(x, -1) == 1 + assert p.subs(x, 1) == log(1) # More subs tests p2 = Piecewise((1, x < pi), (-1, x < 2*pi), (0, x > 2*pi)) + p3 = Piecewise((1, Eq(x, 0)), (1/x, True)) + p4 = Piecewise((1, Eq(x, 0)), (2, 1/x>2)) assert p2.subs(x, 2) == 1 - assert p2.subs(x,4) == -1 - assert p2.subs(x,10) == 0 + assert p2.subs(x, 4) == -1 + assert p2.subs(x, 10) == 0 + assert p3.subs(x, 0.0) == 1 + assert p4.subs(x, 0.0) == 1 + f, g, h = symbols('f,g,h', cls=Function) pf = Piecewise((f(x), x < -1), (f(x) + h(x) + 2, x <= 1)) pg = Piecewise((g(x), x < -1), (g(x) + h(x) + 2, x <= 1)) assert pg.subs(g, f) == pf + assert Piecewise((1, Eq(x, 0)), (0, True)).subs(x, 0) == 1 + assert Piecewise((1, Eq(x, 0)), (0, True)).subs(x, 1) == 0 + assert Piecewise((1, Eq(x, y)), (0, True)).subs(x, y) == 1 + assert Piecewise((1, Eq(x, z)), (0, True)).subs(x, z) == 1 + assert Piecewise((1, Eq(exp(x), cos(z))), (0, True)).subs(x, z) == \ + Piecewise((1, Eq(exp(z), cos(z))), (0, True)) + assert Piecewise((1, Eq(x, y*(y + 1))), (0, True)).subs(x, y**2 + y) == 1 + + p5 = Piecewise( (0, Eq(cos(x) + y, 0)), (1, True)) + assert p5.subs(y, 0) == Piecewise( (0, Eq(cos(x), 0)), (1, True)) + # Test evalf assert p.evalf() == p - assert p.evalf(subs={x:-2}) == -1 - assert p.evalf(subs={x:-1}) == 1 - assert p.evalf(subs={x:1}) == log(1) + assert p.evalf(subs={x: -2}) == -1 + assert p.evalf(subs={x: -1}) == 1 + assert p.evalf(subs={x: 1}) == log(1) # Test doit - f_int = Piecewise((Integral(x,(x,0,1)), x < 1)) + f_int = Piecewise((Integral(x, (x, 0, 1)), x < 1)) assert f_int.doit() == Piecewise( (1.0/2.0, x < 1) ) # Test differentiation @@ -53,8 +80,8 @@ fp = x*p dp = Piecewise((0, x < -1), (2*x, x < 0), (1/x, x >= 0)) fp_dx = x*dp + p - assert diff(p,x) == dp - assert diff(f*p,x) == fp_dx + assert diff(p, x) == dp + assert diff(f*p, x) == fp_dx # Test simple arithmetic assert x*p == fp @@ -70,8 +97,9 @@ # Test _eval_interval f1 = x*y + 2 f2 = x*y**2 + 3 - peval = Piecewise( (f1, x<0), (f2, x>0)) - peval_interval = f1.subs(x,0) - f1.subs(x,-1) + f2.subs(x,1) - f2.subs(x,0) + peval = Piecewise( (f1, x < 0), (f2, x > 0)) + peval_interval = f1.subs( + x, 0) - f1.subs(x, -1) + f2.subs(x, 1) - f2.subs(x, 0) assert peval._eval_interval(x, 0, 0) == 0 assert peval._eval_interval(x, -1, 1) == peval_interval peval2 = Piecewise((f1, x < 0), (f2, True)) @@ -79,26 +107,30 @@ assert peval2._eval_interval(x, 1, -1) == -peval_interval assert peval2._eval_interval(x, -1, -2) == f1.subs(x, -2) - f1.subs(x, -1) assert peval2._eval_interval(x, -1, 1) == peval_interval + assert peval2._eval_interval(x, None, 0) == peval2.subs(x, 0) + assert peval2._eval_interval(x, -1, None) == -peval2.subs(x, -1) # Test integration - p_int = Piecewise((-x,x < -1), (x**3/3.0, x < 0), (-x + x*log(x), x >= 0)) - assert integrate(p,x) == p_int - p = Piecewise((x, x < 1),(x**2, -1 <= x),(x,3= 0)) + assert integrate(p, x) == p_int + p = Piecewise((x, x < 1), (x**2, -1 <= x), (x, 3 < x)) + assert integrate(p, (x, -2, 2)) == 5.0/6.0 + assert integrate(p, (x, 2, -2)) == -5.0/6.0 + p = Piecewise((0, x < 0), (1, x < 1), (0, x < 2), (1, x < 3), (0, True)) + assert integrate(p, (x, -oo, oo)) == 2 + p = Piecewise((x, x < -10), (x**2, x <= -1), (x, 1 < x)) + raises(ValueError, lambda: integrate(p, (x, -2, 2))) # Test commutativity assert p.is_commutative is True + def test_piecewise_free_symbols(): a = symbols('a') - f = Piecewise((x , a<0), (y, True)) + f = Piecewise((x, a < 0), (y, True)) assert f.free_symbols == set([x, y, a]) + def test_piecewise_integrate(): # XXX Use '<=' here! '>=' is not yet implemented .. f = Piecewise(((x - 2)**2, 0 <= x), (1, True)) @@ -132,11 +164,11 @@ g = Piecewise((0, x < 0), (x, x <= 1), (1, True)) assert integrate(g, (x, -5, 1)) == Rational(1, 2) - assert integrate(g, (x, -5, y)).subs(y, 1) == Rational(1,2) - assert integrate(g, (x, y, 1)).subs(y, -5) == Rational(1,2) + assert integrate(g, (x, -5, y)).subs(y, 1) == Rational(1, 2) + assert integrate(g, (x, y, 1)).subs(y, -5) == Rational(1, 2) assert integrate(g, (x, 1, -5)) == -Rational(1, 2) - assert integrate(g, (x, 1, y)).subs(y, -5) == -Rational(1,2) - assert integrate(g, (x, y, -5)).subs(y, 1) == -Rational(1,2) + assert integrate(g, (x, 1, y)).subs(y, -5) == -Rational(1, 2) + assert integrate(g, (x, y, -5)).subs(y, 1) == -Rational(1, 2) assert integrate(g, (x, -5, y)) == Piecewise((0, y < 0), (y**2/2, y <= 1), (y - 0.5, True)) assert integrate(g, (x, y, 1)) == Piecewise((0.5, y < 0), @@ -171,6 +203,7 @@ assert integrate(g, (x, y, 1)) == Piecewise((1, y <= -1), (0, y >= 1), (y**2/2 - y + 0.5, y > 0), (-y**2/2 - y + 0.5, True)) + def test_piecewise_integrate_symbolic_conditions(): from sympy.abc import a, b, x, y p0 = Piecewise((0, Or(x < a, x > b)), (1, True)) @@ -207,11 +240,18 @@ assert integrate(p4, (x, -oo, y)) == 0.5*y + 0.5*Min(b, y) - Min(a, b, y) assert integrate(p5, (x, -oo, y)) == 0.5*y + 0.5*Min(b, y) - Min(a, b, y) + +def test_piecewise_integrate_independent_conditions(): + p = Piecewise((0, Eq(y, 0)), (x*y, True)) + assert integrate(p, (x, 1, 3)) == \ + Piecewise((0, Eq(y, 0)), (4*y, True)) + + def test_piecewise_solve(): abs2 = Piecewise((-x, x <= 0), (x, x > 0)) f = abs2.subs(x, x - 2) assert solve(f, x) == [2] - assert solve(f - 1,x) == [1, 3] + assert solve(f - 1, x) == [1, 3] f = Piecewise(((x - 2)**2, x >= 0), (1, True)) assert solve(f, x) == [2] @@ -231,62 +271,107 @@ g = Piecewise(((x - 5)**5, x >= 2), (f, True), (10, False)) assert solve(g, x) == [5] + g = Piecewise(((x - 5)**5, x >= 2), + (-x + 2, x - 2 <= 0), (x - 2, x - 2 > 0)) + assert solve(g, x) == [5] + # See issue 1253 (enhance the solver to handle inequalities). + + @XFAIL def test_piecewise_solve2(): f = Piecewise(((x - 2)**2, x >= 0), (0, True)) assert solve(f, x) == [2, Interval(0, oo, True, True)] + def test_piecewise_fold(): p = Piecewise((x, x < 1), (1, 1 <= x)) assert piecewise_fold(x*p) == Piecewise((x**2, x < 1), (x, 1 <= x)) - assert piecewise_fold(p+p) == Piecewise((2*x, x < 1), (2, 1 <= x)) - assert piecewise_fold(Piecewise((1, x < 0), (2, True)) \ + assert piecewise_fold(p + p) == Piecewise((2*x, x < 1), (2, 1 <= x)) + assert piecewise_fold(Piecewise((1, x < 0), (2, True)) + Piecewise((10, x < 0), (-10, True))) == \ - Piecewise((11, x < 0), (-8, True)) + Piecewise((11, x < 0), (-8, True)) p1 = Piecewise((0, x < 0), (x, x <= 1), (0, True)) - p2 = Piecewise((0, x < 0), (1 - x, x <=1), (0, True)) + p2 = Piecewise((0, x < 0), (1 - x, x <= 1), (0, True)) p = 4*p1 + 2*p2 - assert integrate(piecewise_fold(p),(x,-oo,oo)) == integrate(2*x + 2, (x, 0, 1)) + assert integrate( + piecewise_fold(p), (x, -oo, oo)) == integrate(2*x + 2, (x, 0, 1)) + + +def test_piecewise_fold_piecewise_in_cond(): + p1 = Piecewise((cos(x), x < 0), (0, True)) + p2 = Piecewise((0, Eq(p1, 0)), (p1 / Abs(p1), True)) + p3 = piecewise_fold(p2) + assert(p2.subs(x, -pi/2) == 0.0) + assert(p2.subs(x, 1) == 0.0) + assert(p2.subs(x, -pi/4) == 1.0) + p4 = Piecewise((0, Eq(p1, 0)), (1,True)) + assert(piecewise_fold(p4) == Piecewise( + (0, Or(And(Eq(cos(x), 0), x < 0), Not(x < 0))), (1, True))) + + r1 = 1 < Piecewise((1, x < 1), (3, True)) + assert(piecewise_fold(r1) == Not(x < 1)) + + p5 = Piecewise((1, x < 0), (3, True)) + p6 = Piecewise((1, x < 1), (3, True)) + p7 = piecewise_fold(Piecewise((1, p5 < p6), (0, True))) + assert(Piecewise((1, And(Not(x < 1), x < 0)), (0, True))) + + +@XFAIL +def test_piecewise_fold_piecewise_in_cond_2(): + p1 = Piecewise((cos(x), x < 0), (0, True)) + p2 = Piecewise((0, Eq(p1, 0)), (1 / p1, True)) + p3 = Piecewise((0, Or(And(Eq(cos(x), 0), x < 0), Not(x < 0))), + (1 / cos(x), True)) + assert(piecewise_fold(p2) == p3) + def test_piecewise_fold_expand(): p1 = Piecewise((1, Interval(0, 1, False, True).contains(x)), (0, True)) - p2 = piecewise_fold(expand((1-x)*p1)) - assert p2 == Piecewise((1 - x, Interval(0, 1, False, True).contains(x)), \ + p2 = piecewise_fold(expand((1 - x)*p1)) + assert p2 == Piecewise((1 - x, Interval(0, 1, False, True).contains(x)), (Piecewise((-x, Interval(0, 1, False, True).contains(x)), (0, True)), True)) - p2 = expand(piecewise_fold((1-x)*p1)) - assert p2 == Piecewise((1 - x, Interval(0, 1, False, True).contains(x)), (0, True)) + p2 = expand(piecewise_fold((1 - x)*p1)) + assert p2 == Piecewise( + (1 - x, Interval(0, 1, False, True).contains(x)), (0, True)) + def test_piecewise_duplicate(): - p = Piecewise((x, x < -10),(x**2, x <= -1),(x, 1 < x)) + p = Piecewise((x, x < -10), (x**2, x <= -1), (x, 1 < x)) assert p == Piecewise(*p.args) + def test_doit(): p1 = Piecewise((x, x < 1), (x**2, -1 <= x), (x, 3 < x)) p2 = Piecewise((x, x < 1), (Integral(2 * x), -1 <= x), (x, 3 < x)) assert p2.doit() == p1 - assert p2.doit(deep = False) == p2 + assert p2.doit(deep=False) == p2 + def test_piecewise_interval(): - p1 = Piecewise((x, Interval(0,1).contains(x)), (0, True)) + p1 = Piecewise((x, Interval(0, 1).contains(x)), (0, True)) assert p1.subs(x, -0.5) == 0 assert p1.subs(x, 0.5) == 0.5 assert p1.diff(x) == Piecewise((1, Interval(0, 1).contains(x)), (0, True)) - assert integrate(p1, x) == Piecewise((x**2/2, Interval(0, 1).contains(x)), (0, True)) + assert integrate( + p1, x) == Piecewise((x**2/2, Interval(0, 1).contains(x)), (0, True)) + def test_piecewise_collapse(): - p1 = Piecewise((x, x<0),(x**2,x>1)) - p2 = Piecewise((p1,x<0),(p1,x>1)) + p1 = Piecewise((x, x < 0), (x**2, x > 1)) + p2 = Piecewise((p1, x < 0), (p1, x > 1)) assert p2 == Piecewise((x, x < 0), (x**2, 1 < x)) - p1 = Piecewise((Piecewise((x,x<0),(1,True)),True)) - assert p1 == Piecewise((Piecewise((x,x<0),(1,True)),True)) + p1 = Piecewise((Piecewise((x, x < 0), (1, True)), True)) + assert p1 == Piecewise((Piecewise((x, x < 0), (1, True)), True)) + def test_piecewise_lambdify(): p = Piecewise( @@ -302,11 +387,13 @@ assert f(0.5) == 0.5 assert f(2.0) == 0.0 + def test_piecewise_series(): from sympy import sin, cos, O - p1 = Piecewise((sin(x), x<0),(cos(x),x>0)) - p2 = Piecewise((x+O(x**2), x<0),(1+O(x**2),x>0)) - assert p1.nseries(x,n=2) == p2 + p1 = Piecewise((sin(x), x < 0), (cos(x), x > 0)) + p2 = Piecewise((x + O(x**2), x < 0), (1 + O(x**2), x > 0)) + assert p1.nseries(x, n=2) == p2 + def test_piecewise_as_leading_term(): p1 = Piecewise((1/x, x > 1), (0, True)) @@ -326,6 +413,7 @@ assert p7.as_leading_term(x) == x assert p8.as_leading_term(x) == 1/x + def test_piecewise_complex(): p1 = Piecewise((2, x < 0), (1, 0 <= x)) p2 = Piecewise((2*I, x < 0), (I, 0 <= x)) @@ -336,16 +424,28 @@ assert conjugate(p2) == piecewise_fold(-p2) assert conjugate(p3) == p4 - assert p1.is_imaginary == False - assert p1.is_real == True - assert p2.is_imaginary == True - assert p2.is_real == False - assert p3.is_imaginary == None - assert p3.is_real == None + assert p1.is_imaginary is False + assert p1.is_real is True + assert p2.is_imaginary is True + assert p2.is_real is False + assert p3.is_imaginary is None + assert p3.is_real is None assert p1.as_real_imag() == (p1, 0) assert p2.as_real_imag() == (0, -I*p2) + +def test_conjugate_transpose(): + A, B = symbols("A B", commutative=False) + p = Piecewise((A*B**2, x > 0), (A**2*B, True)) + assert p.adjoint() == \ + Piecewise((adjoint(A*B**2), x > 0), (adjoint(A**2*B), True)) + assert p.conjugate() == \ + Piecewise((conjugate(A*B**2), x > 0), (conjugate(A**2*B), True)) + assert p.transpose() == \ + Piecewise((transpose(A*B**2), x > 0), (transpose(A**2*B), True)) + + def test_piecewise_evaluate(): assert Piecewise((x, True)) == x assert Piecewise((x, True), evaluate=True) == x diff -Nru python3-sympy-0.7.2/sympy/functions/elementary/tests/test_trigonometric.py python3-sympy-0.7.3/sympy/functions/elementary/tests/test_trigonometric.py --- python3-sympy-0.7.2/sympy/functions/elementary/tests/test_trigonometric.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/functions/elementary/tests/test_trigonometric.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,16 +1,17 @@ from sympy import (symbols, Symbol, nan, oo, zoo, I, sinh, sin, acot, pi, atan, acos, Rational, sqrt, asin, acot, cot, coth, E, S, tan, tanh, cos, cosh, atan2, exp, log, asinh, acoth, atanh, O, cancel, Matrix, re, im, - Float,Pow) + Float, Pow, gcd, sec, csc, cot) -from sympy.utilities.pytest import XFAIL +from sympy.utilities.pytest import XFAIL, slow, raises -def test_sin(): - x, y = symbols('x,y') +x, y, z = symbols('x y z') +r = Symbol('r', real=True) +k = Symbol('k', integer=True) - r = Symbol('r', real=True) - k = Symbol('k', integer=True) +def test_sin(): + x, y = symbols('x y') assert sin(nan) == nan @@ -64,6 +65,8 @@ assert sin(-1273*pi/5) == -sin(2*pi/5) + assert sin(pi/8) == sqrt((2 - sqrt(2))/4) + assert sin(104*pi/105) == sin(pi/105) assert sin(106*pi/105) == -sin(pi/105) @@ -77,35 +80,59 @@ assert sin(k*pi*I) == sinh(k*pi)*I - assert sin(r).is_real == True + assert sin(r).is_real is True + + assert isinstance(sin( re(x) - im(y)), sin) is True + assert isinstance(sin(-re(x) + im(y)), sin) is False + + for d in list(range(1, 22)) + [60, 85]: + for n in range(0, d*2 + 1): + x = n*pi/d + e = abs( float(sin(x)) - sin(float(x)) ) + assert e < 1e-12 + + +def test_sin_cos(): + for d in [1, 2, 3, 4, 5, 6, 10, 12]: # list is not exhaustive... + for n in range(-2*d, d*2): + x = n*pi/d + assert sin(x + pi/2) == cos(x), "fails for %d*pi/%d" % (n, d) + assert sin(x - pi/2) == -cos(x), "fails for %d*pi/%d" % (n, d) + assert sin(x) == cos(x - pi/2), "fails for %d*pi/%d" % (n, d) + assert -sin(x) == cos(x + pi/2), "fails for %d*pi/%d" % (n, d) - assert isinstance(sin( re(x) - im(y)), sin) == True - assert isinstance(sin(-re(x) + im(y)), sin) == False def test_sin_series(): - x = Symbol('x') assert sin(x).series(x, 0, 9) == \ - x - x**3/6 + x**5/120 - x**7/5040 + O(x**9) + x - x**3/6 + x**5/120 - x**7/5040 + O(x**9) + def test_sin_rewrite(): - x = Symbol('x') assert sin(x).rewrite(exp) == -I*(exp(I*x) - exp(-I*x))/2 assert sin(x).rewrite(tan) == 2*tan(x/2)/(1 + tan(x/2)**2) assert sin(x).rewrite(cot) == 2*cot(x/2)/(1 + cot(x/2)**2) - assert sin(sinh(x)).rewrite(exp).subs(x, 3).n() == sin(x).rewrite(exp).subs(x, sinh(3)).n() - assert sin(cosh(x)).rewrite(exp).subs(x, 3).n() == sin(x).rewrite(exp).subs(x, cosh(3)).n() - assert sin(tanh(x)).rewrite(exp).subs(x, 3).n() == sin(x).rewrite(exp).subs(x, tanh(3)).n() - assert sin(coth(x)).rewrite(exp).subs(x, 3).n() == sin(x).rewrite(exp).subs(x, coth(3)).n() - assert sin(sin(x)).rewrite(exp).subs(x, 3).n() == sin(x).rewrite(exp).subs(x, sin(3)).n() - assert sin(cos(x)).rewrite(exp).subs(x, 3).n() == sin(x).rewrite(exp).subs(x, cos(3)).n() - assert sin(tan(x)).rewrite(exp).subs(x, 3).n() == sin(x).rewrite(exp).subs(x, tan(3)).n() - assert sin(cot(x)).rewrite(exp).subs(x, 3).n() == sin(x).rewrite(exp).subs(x, cot(3)).n() - assert sin(log(x)).rewrite(Pow) == I*x**-I / 2 - I*x**I /2 + assert sin(sinh(x)).rewrite( + exp).subs(x, 3).n() == sin(x).rewrite(exp).subs(x, sinh(3)).n() + assert sin(cosh(x)).rewrite( + exp).subs(x, 3).n() == sin(x).rewrite(exp).subs(x, cosh(3)).n() + assert sin(tanh(x)).rewrite( + exp).subs(x, 3).n() == sin(x).rewrite(exp).subs(x, tanh(3)).n() + assert sin(coth(x)).rewrite( + exp).subs(x, 3).n() == sin(x).rewrite(exp).subs(x, coth(3)).n() + assert sin(sin(x)).rewrite( + exp).subs(x, 3).n() == sin(x).rewrite(exp).subs(x, sin(3)).n() + assert sin(cos(x)).rewrite( + exp).subs(x, 3).n() == sin(x).rewrite(exp).subs(x, cos(3)).n() + assert sin(tan(x)).rewrite( + exp).subs(x, 3).n() == sin(x).rewrite(exp).subs(x, tan(3)).n() + assert sin(cot(x)).rewrite( + exp).subs(x, 3).n() == sin(x).rewrite(exp).subs(x, cot(3)).n() + assert sin(log(x)).rewrite(Pow) == I*x**-I / 2 - I*x**I /2 + def test_sin_expansion(): # Note: these formulas are not unique. The ones here come from the # Chebyshev formulas. - x, y = symbols('x y') assert sin(x + y).expand(trig=True) == sin(x)*cos(y) + cos(x)*sin(y) assert sin(x - y).expand(trig=True) == sin(x)*cos(y) - cos(x)*sin(y) assert sin(y - x).expand(trig=True) == cos(x)*sin(y) - sin(x)*cos(y) @@ -115,52 +142,46 @@ assert sin(2).expand(trig=True) == 2*sin(1)*cos(1) assert sin(3).expand(trig=True) == -4*sin(1)**3 + 3*sin(1) -def test_trig_symmetry(): - x = Symbol('x') - y = Symbol('y') - k = Symbol('k', integer=True) +def test_trig_symmetry(): assert sin(-x) == -sin(x) assert cos(-x) == cos(x) assert tan(-x) == -tan(x) assert cot(-x) == -cot(x) - assert sin(x+pi) == -sin(x) - assert sin(x+2*pi) == sin(x) - assert sin(x+3*pi) == -sin(x) - assert sin(x+4*pi) == sin(x) - assert sin(x-5*pi) == -sin(x) - assert cos(x+pi) == -cos(x) - assert cos(x+2*pi) == cos(x) - assert cos(x+3*pi) == -cos(x) - assert cos(x+4*pi) == cos(x) - assert cos(x-5*pi) == -cos(x) - assert tan(x+pi) == tan(x) - assert tan(x-3*pi) == tan(x) - assert cot(x+pi) == cot(x) - assert cot(x-3*pi) == cot(x) - assert sin(pi/2-x) == cos(x) - assert sin(3*pi/2-x) == -cos(x) - assert sin(5*pi/2-x) == cos(x) - assert cos(pi/2-x) == sin(x) - assert cos(3*pi/2-x) == -sin(x) - assert cos(5*pi/2-x) == sin(x) - assert tan(pi/2-x) == cot(x) - assert tan(3*pi/2-x) == cot(x) - assert tan(5*pi/2-x) == cot(x) - assert cot(pi/2-x) == tan(x) - assert cot(3*pi/2-x) == tan(x) - assert cot(5*pi/2-x) == tan(x) - assert sin(pi/2+x) == cos(x) - assert cos(pi/2+x) == -sin(x) - assert tan(pi/2+x) == -cot(x) - assert cot(pi/2+x) == -tan(x) - -def test_cos(): - x, y = symbols('x,y') + assert sin(x + pi) == -sin(x) + assert sin(x + 2*pi) == sin(x) + assert sin(x + 3*pi) == -sin(x) + assert sin(x + 4*pi) == sin(x) + assert sin(x - 5*pi) == -sin(x) + assert cos(x + pi) == -cos(x) + assert cos(x + 2*pi) == cos(x) + assert cos(x + 3*pi) == -cos(x) + assert cos(x + 4*pi) == cos(x) + assert cos(x - 5*pi) == -cos(x) + assert tan(x + pi) == tan(x) + assert tan(x - 3*pi) == tan(x) + assert cot(x + pi) == cot(x) + assert cot(x - 3*pi) == cot(x) + assert sin(pi/2 - x) == cos(x) + assert sin(3*pi/2 - x) == -cos(x) + assert sin(5*pi/2 - x) == cos(x) + assert cos(pi/2 - x) == sin(x) + assert cos(3*pi/2 - x) == -sin(x) + assert cos(5*pi/2 - x) == sin(x) + assert tan(pi/2 - x) == cot(x) + assert tan(3*pi/2 - x) == cot(x) + assert tan(5*pi/2 - x) == cot(x) + assert cot(pi/2 - x) == tan(x) + assert cot(3*pi/2 - x) == tan(x) + assert cot(5*pi/2 - x) == tan(x) + assert sin(pi/2 + x) == cos(x) + assert cos(pi/2 + x) == -sin(x) + assert tan(pi/2 + x) == -cot(x) + assert cot(pi/2 + x) == -tan(x) - r = Symbol('r', real=True) - k = Symbol('k', integer=True) +def test_cos(): + x, y = symbols('x y') assert cos(nan) == nan @@ -183,12 +204,12 @@ assert cos(-pi/2) == 0 assert cos(pi/2) == 0 assert cos(-pi/2) == 0 - assert cos((-3*10**73+1)*pi/2) == 0 - assert cos((7*10**103+1)*pi/2) == 0 + assert cos((-3*10**73 + 1)*pi/2) == 0 + assert cos((7*10**103 + 1)*pi/2) == 0 assert cos(pi) == -1 assert cos(-pi) == -1 - assert cos(2*pi)==1 + assert cos(2*pi) == 1 assert cos(5*pi) == -1 assert cos(8*pi) == 1 @@ -214,6 +235,8 @@ assert cos(-1273*pi/5) == -cos(2*pi/5) + assert cos(pi/8) == sqrt((2 + sqrt(2))/4) + assert cos(104*pi/105) == -cos(pi/105) assert cos(106*pi/105) == -cos(pi/105) @@ -223,11 +246,18 @@ assert cos(x*I) == cosh(x) assert cos(k*pi*I) == cosh(k*pi) - assert cos(r).is_real == True + assert cos(r).is_real is True assert cos(k*pi) == (-1)**k assert cos(2*k*pi) == 1 + for d in list(range(1, 22)) + [60, 85]: + for n in range(0, 2*d + 1): + x = n*pi/d + e = abs( float(cos(x)) - cos(float(x)) ) + assert e < 1e-12 + + def test_issue_3091(): c = Float('123456789012345678901234567890.25', '') for cls in [sin, cos, tan, cot]: @@ -235,28 +265,36 @@ assert cls(4.125*pi) == cls(pi/8) assert cls(4.7*pi) == cls((4.7 % 2)*pi) + def test_cos_series(): - x = Symbol('x') assert cos(x).series(x, 0, 9) == \ - 1 - x**2/2 + x**4/24 - x**6/720 + x**8/40320 + O(x**9) + 1 - x**2/2 + x**4/24 - x**6/720 + x**8/40320 + O(x**9) + def test_cos_rewrite(): - x = Symbol('x') assert cos(x).rewrite(exp) == exp(I*x)/2 + exp(-I*x)/2 assert cos(x).rewrite(tan) == (1 - tan(x/2)**2)/(1 + tan(x/2)**2) assert cos(x).rewrite(cot) == -(1 - cot(x/2)**2)/(1 + cot(x/2)**2) - assert cos(sinh(x)).rewrite(exp).subs(x, 3).n() == cos(x).rewrite(exp).subs(x, sinh(3)).n() - assert cos(cosh(x)).rewrite(exp).subs(x, 3).n() == cos(x).rewrite(exp).subs(x, cosh(3)).n() - assert cos(tanh(x)).rewrite(exp).subs(x, 3).n() == cos(x).rewrite(exp).subs(x, tanh(3)).n() - assert cos(coth(x)).rewrite(exp).subs(x, 3).n() == cos(x).rewrite(exp).subs(x, coth(3)).n() - assert cos(sin(x)).rewrite(exp).subs(x, 3).n() == cos(x).rewrite(exp).subs(x, sin(3)).n() - assert cos(cos(x)).rewrite(exp).subs(x, 3).n() == cos(x).rewrite(exp).subs(x, cos(3)).n() - assert cos(tan(x)).rewrite(exp).subs(x, 3).n() == cos(x).rewrite(exp).subs(x, tan(3)).n() - assert cos(cot(x)).rewrite(exp).subs(x, 3).n() == cos(x).rewrite(exp).subs(x, cot(3)).n() + assert cos(sinh(x)).rewrite( + exp).subs(x, 3).n() == cos(x).rewrite(exp).subs(x, sinh(3)).n() + assert cos(cosh(x)).rewrite( + exp).subs(x, 3).n() == cos(x).rewrite(exp).subs(x, cosh(3)).n() + assert cos(tanh(x)).rewrite( + exp).subs(x, 3).n() == cos(x).rewrite(exp).subs(x, tanh(3)).n() + assert cos(coth(x)).rewrite( + exp).subs(x, 3).n() == cos(x).rewrite(exp).subs(x, coth(3)).n() + assert cos(sin(x)).rewrite( + exp).subs(x, 3).n() == cos(x).rewrite(exp).subs(x, sin(3)).n() + assert cos(cos(x)).rewrite( + exp).subs(x, 3).n() == cos(x).rewrite(exp).subs(x, cos(3)).n() + assert cos(tan(x)).rewrite( + exp).subs(x, 3).n() == cos(x).rewrite(exp).subs(x, tan(3)).n() + assert cos(cot(x)).rewrite( + exp).subs(x, 3).n() == cos(x).rewrite(exp).subs(x, cot(3)).n() assert cos(log(x)).rewrite(Pow) == x**I/2 + x**-I/2 + def test_cos_expansion(): - x, y = symbols('x y') assert cos(x + y).expand(trig=True) == cos(x)*cos(y) - sin(x)*sin(y) assert cos(x - y).expand(trig=True) == cos(x)*cos(y) + sin(x)*sin(y) assert cos(y - x).expand(trig=True) == cos(x)*cos(y) + sin(x)*sin(y) @@ -266,13 +304,8 @@ assert cos(2).expand(trig=True) == 2*cos(1)**2 - 1 assert cos(3).expand(trig=True) == 4*cos(1)**3 - 3*cos(1) -def test_tan(): - x, y = symbols('x,y') - - r = Symbol('r', real=True) - - k = Symbol('k', integer=True) +def test_tan(): assert tan(nan) == nan assert tan(oo*I) == I @@ -319,48 +352,65 @@ assert tan(k*pi*I) == tanh(k*pi)*I - assert tan(r).is_real == True + assert tan(r).is_real is True assert tan(10*pi/7) == tan(3*pi/7) assert tan(11*pi/7) == -tan(3*pi/7) assert tan(-11*pi/7) == tan(3*pi/7) + def test_tan_series(): - x = Symbol('x') assert tan(x).series(x, 0, 9) == \ - x + x**3/3 + 2*x**5/15 + 17*x**7/315 + O(x**9) + x + x**3/3 + 2*x**5/15 + 17*x**7/315 + O(x**9) + def test_tan_rewrite(): - x = Symbol('x') neg_exp, pos_exp = exp(-x*I), exp(x*I) - assert tan(x).rewrite(exp) == I*(neg_exp-pos_exp)/(neg_exp+pos_exp) + assert tan(x).rewrite(exp) == I*(neg_exp - pos_exp)/(neg_exp + pos_exp) assert tan(x).rewrite(sin) == 2*sin(x)**2/sin(2*x) assert tan(x).rewrite(cos) == -cos(x + S.Pi/2)/cos(x) assert tan(x).rewrite(cot) == 1/cot(x) - assert tan(sinh(x)).rewrite(exp).subs(x, 3).n() == tan(x).rewrite(exp).subs(x, sinh(3)).n() - assert tan(cosh(x)).rewrite(exp).subs(x, 3).n() == tan(x).rewrite(exp).subs(x, cosh(3)).n() - assert tan(tanh(x)).rewrite(exp).subs(x, 3).n() == tan(x).rewrite(exp).subs(x, tanh(3)).n() - assert tan(coth(x)).rewrite(exp).subs(x, 3).n() == tan(x).rewrite(exp).subs(x, coth(3)).n() - assert tan(sin(x)).rewrite(exp).subs(x, 3).n() == tan(x).rewrite(exp).subs(x, sin(3)).n() - assert tan(cos(x)).rewrite(exp).subs(x, 3).n() == tan(x).rewrite(exp).subs(x, cos(3)).n() - assert tan(tan(x)).rewrite(exp).subs(x, 3).n() == tan(x).rewrite(exp).subs(x, tan(3)).n() - assert tan(cot(x)).rewrite(exp).subs(x, 3).n() == tan(x).rewrite(exp).subs(x, cot(3)).n() + assert tan(sinh(x)).rewrite( + exp).subs(x, 3).n() == tan(x).rewrite(exp).subs(x, sinh(3)).n() + assert tan(cosh(x)).rewrite( + exp).subs(x, 3).n() == tan(x).rewrite(exp).subs(x, cosh(3)).n() + assert tan(tanh(x)).rewrite( + exp).subs(x, 3).n() == tan(x).rewrite(exp).subs(x, tanh(3)).n() + assert tan(coth(x)).rewrite( + exp).subs(x, 3).n() == tan(x).rewrite(exp).subs(x, coth(3)).n() + assert tan(sin(x)).rewrite( + exp).subs(x, 3).n() == tan(x).rewrite(exp).subs(x, sin(3)).n() + assert tan(cos(x)).rewrite( + exp).subs(x, 3).n() == tan(x).rewrite(exp).subs(x, cos(3)).n() + assert tan(tan(x)).rewrite( + exp).subs(x, 3).n() == tan(x).rewrite(exp).subs(x, tan(3)).n() + assert tan(cot(x)).rewrite( + exp).subs(x, 3).n() == tan(x).rewrite(exp).subs(x, cot(3)).n() assert tan(log(x)).rewrite(Pow) == I*(x**-I - x**I)/(x**-I + x**I) + assert 0 == (cos(pi/15)*tan(pi/15) - sin(pi/15)).rewrite(pow) + assert tan(pi/19).rewrite(pow) == tan(pi/19) + assert tan(8*pi/19).rewrite(sqrt) == tan(8*pi/19) + def test_tan_subs(): - x,y = symbols('x,y') assert tan(x).subs(tan(x), y) == y assert tan(x).subs(x, y) == tan(y) assert tan(x).subs(x, S.Pi/2) == zoo assert tan(x).subs(x, 3*S.Pi/2) == zoo -def test_cot(): - x, y = symbols('x,y') - r = Symbol('r', real=True) +def test_tan_expansion(): + assert tan(x + y).expand(trig=True) == ((tan(x) + tan(y))/(1 - tan(x)*tan(y))).expand() + assert tan(x - y).expand(trig=True) == ((tan(x) - tan(y))/(1 + tan(x)*tan(y))).expand() + assert tan(x + y + z).expand(trig=True) == ( + (tan(x) + tan(y) + tan(z) - tan(x)*tan(y)*tan(z))/ + (1 - tan(x)*tan(y) - tan(x)*tan(z) - tan(y)*tan(z))).expand() + assert 0 == tan(2*x).expand(trig=True).rewrite(tan).subs([(tan(x), Rational(1, 7))])*24 - 7 + assert 0 == tan(3*x).expand(trig=True).rewrite(tan).subs([(tan(x), Rational(1, 5))])*55 - 37 + assert 0 == tan(4*x - pi/4).expand(trig=True).rewrite(tan).subs([(tan(x), Rational(1, 5))])*239 - 1 - k = Symbol('k', integer=True) +def test_cot(): assert cot(nan) == nan assert cot(oo*I) == -I @@ -373,7 +423,7 @@ assert cot(atan(x)) == 1 / x assert cot(asin(x)) == sqrt(1 - x**2) / x assert cot(acos(x)) == x / sqrt(1 - x**2) - assert cot(atan2(y,x)) == x/y + assert cot(atan2(y, x)) == x/y assert cot(pi*I) == -coth(pi)*I assert cot(-pi*I) == coth(pi)*I @@ -403,149 +453,167 @@ assert cot(x*I) == -coth(x)*I assert cot(k*pi*I) == -coth(k*pi)*I - assert cot(r).is_real == True + assert cot(r).is_real is True assert cot(10*pi/7) == cot(3*pi/7) assert cot(11*pi/7) == -cot(3*pi/7) assert cot(-11*pi/7) == cot(3*pi/7) + def test_cot_series(): - x = Symbol('x') assert cot(x).series(x, 0, 9) == \ - 1/x - x/3 - x**3/45 - 2*x**5/945 - x**7/4725 + O(x**9) + 1/x - x/3 - x**3/45 - 2*x**5/945 - x**7/4725 + O(x**9) + def test_cot_rewrite(): - x = Symbol('x') neg_exp, pos_exp = exp(-x*I), exp(x*I) - assert cot(x).rewrite(exp) == I*(pos_exp+neg_exp)/(pos_exp-neg_exp) + assert cot(x).rewrite(exp) == I*(pos_exp + neg_exp)/(pos_exp - neg_exp) assert cot(x).rewrite(sin) == 2*sin(2*x)/sin(x)**2 assert cot(x).rewrite(cos) == -cos(x)/cos(x + S.Pi/2) assert cot(x).rewrite(tan) == 1/tan(x) - assert cot(sinh(x)).rewrite(exp).subs(x, 3).n() == cot(x).rewrite(exp).subs(x, sinh(3)).n() - assert cot(cosh(x)).rewrite(exp).subs(x, 3).n() == cot(x).rewrite(exp).subs(x, cosh(3)).n() - assert cot(tanh(x)).rewrite(exp).subs(x, 3).n() == cot(x).rewrite(exp).subs(x, tanh(3)).n() - assert cot(coth(x)).rewrite(exp).subs(x, 3).n() == cot(x).rewrite(exp).subs(x, coth(3)).n() - assert cot(sin(x)).rewrite(exp).subs(x, 3).n() == cot(x).rewrite(exp).subs(x, sin(3)).n() - assert cot(tan(x)).rewrite(exp).subs(x, 3).n() == cot(x).rewrite(exp).subs(x, tan(3)).n() + assert cot(sinh(x)).rewrite( + exp).subs(x, 3).n() == cot(x).rewrite(exp).subs(x, sinh(3)).n() + assert cot(cosh(x)).rewrite( + exp).subs(x, 3).n() == cot(x).rewrite(exp).subs(x, cosh(3)).n() + assert cot(tanh(x)).rewrite( + exp).subs(x, 3).n() == cot(x).rewrite(exp).subs(x, tanh(3)).n() + assert cot(coth(x)).rewrite( + exp).subs(x, 3).n() == cot(x).rewrite(exp).subs(x, coth(3)).n() + assert cot(sin(x)).rewrite( + exp).subs(x, 3).n() == cot(x).rewrite(exp).subs(x, sin(3)).n() + assert cot(tan(x)).rewrite( + exp).subs(x, 3).n() == cot(x).rewrite(exp).subs(x, tan(3)).n() assert cot(log(x)).rewrite(Pow) == -I*(x**-I + x**I)/(x**-I - x**I) + assert cot(4*pi/15).rewrite(pow) == (cos(4*pi/15)/sin(4*pi/15)).rewrite(pow) + assert cot(pi/19).rewrite(pow) == cot(pi/19) + assert cot(pi/19).rewrite(sqrt) == cot(pi/19) + def test_cot_subs(): - x,y = symbols('x,y') assert cot(x).subs(cot(x), y) == y assert cot(x).subs(x, y) == cot(y) assert cot(x).subs(x, 0) == zoo assert cot(x).subs(x, S.Pi) == zoo -def test_asin(): - x = Symbol('x') +def test_cot_expansion(): + assert cot(x + y).expand(trig=True) == ((cot(x)*cot(y) - 1)/(cot(x) + cot(y))).expand() + assert cot(x - y).expand(trig=True) == (-(cot(x)*cot(y) + 1)/(cot(x) - cot(y))).expand() + assert cot(x + y + z).expand(trig=True) == ( + (cot(x)*cot(y)*cot(z) - cot(x) - cot(y) - cot(z))/ + (-1 + cot(x)*cot(y) + cot(x)*cot(z) + cot(y)*cot(z))).expand() + assert cot(3*x).expand(trig=True) == ((cot(x)**3 - 3*cot(x))/(3*cot(x)**2 - 1)).expand() + assert 0 == cot(2*x).expand(trig=True).rewrite(cot).subs([(cot(x), Rational(1, 3))])*3 + 4 + assert 0 == cot(3*x).expand(trig=True).rewrite(cot).subs([(cot(x), Rational(1, 5))])*55 - 37 + assert 0 == cot(4*x - pi/4).expand(trig=True).rewrite(cot).subs([(cot(x), Rational(1, 7))])*863 + 191 + + +def test_asin(): assert asin(nan) == nan assert asin(oo) == -I*oo assert asin(-oo) == I*oo # Note: asin(-x) = - asin(x) - assert asin(0) == 0 - assert asin(1) == pi/2 - assert asin(-1) == -pi/2 + assert asin(0) == 0 + assert asin(1) == pi/2 + assert asin(-1) == -pi/2 assert asin(sqrt(3)/2) == pi/3 assert asin(-sqrt(3)/2) == -pi/3 assert asin(sqrt(2)/2) == pi/4 assert asin(-sqrt(2)/2) == -pi/4 - assert asin(sqrt((5-sqrt(5))/8)) == pi/5 - assert asin(-sqrt((5-sqrt(5))/8)) == -pi/5 - assert asin(Rational(1,2)) == pi/6 - assert asin(-Rational(1,2)) == -pi/6 - assert asin((sqrt(2-sqrt(2)))/2) == pi/8 - assert asin(-(sqrt(2-sqrt(2)))/2) == -pi/8 - assert asin((sqrt(5)-1)/4) == pi/10 - assert asin(-(sqrt(5)-1)/4) == -pi/10 - assert asin((sqrt(3)-1)/sqrt(2**3)) == pi/12 - assert asin(-(sqrt(3)-1)/sqrt(2**3)) == -pi/12 + assert asin(sqrt((5 - sqrt(5))/8)) == pi/5 + assert asin(-sqrt((5 - sqrt(5))/8)) == -pi/5 + assert asin(Rational(1, 2)) == pi/6 + assert asin(-Rational(1, 2)) == -pi/6 + assert asin((sqrt(2 - sqrt(2)))/2) == pi/8 + assert asin(-(sqrt(2 - sqrt(2)))/2) == -pi/8 + assert asin((sqrt(5) - 1)/4) == pi/10 + assert asin(-(sqrt(5) - 1)/4) == -pi/10 + assert asin((sqrt(3) - 1)/sqrt(2**3)) == pi/12 + assert asin(-(sqrt(3) - 1)/sqrt(2**3)) == -pi/12 - assert asin(x).diff(x) == 1/sqrt(1-x**2) + assert asin(x).diff(x) == 1/sqrt(1 - x**2) - assert asin(0.2).is_real == True - assert asin(-2).is_real == False + assert asin(0.2).is_real is True + assert asin(-2).is_real is False assert asin(-2*I) == -I*asinh(2) + def test_asin_series(): - x = Symbol('x') assert asin(x).series(x, 0, 9) == \ - x + x**3/6 + 3*x**5/40 + 5*x**7/112 + O(x**9) + x + x**3/6 + 3*x**5/40 + 5*x**7/112 + O(x**9) t5 = asin(x).taylor_term(5, x) assert t5 == 3*x**5/40 assert asin(x).taylor_term(7, x, t5, 0) == 5*x**7/112 + def test_asin_rewrite(): - x = Symbol('x') assert asin(x).rewrite(log) == -I*log(I*x + sqrt(1 - x**2)) assert asin(x).rewrite(atan) == 2*atan(x/(1 + sqrt(1 - x**2))) assert asin(x).rewrite(acos) == S.Pi/2 - acos(x) -def test_acos(): - x = Symbol('x') - r = Symbol('r', real=True) +def test_acos(): assert acos(nan) == nan assert acos(oo) == I*oo assert acos(-oo) == -I*oo # Note: acos(-x) = pi - acos(x) - assert acos(0) == pi/2 - assert acos(Rational(1,2)) == pi/3 - assert acos(-Rational(1,2)) == (2*pi)/3 - assert acos(1) == 0 + assert acos(0) == pi/2 + assert acos(Rational(1, 2)) == pi/3 + assert acos(-Rational(1, 2)) == (2*pi)/3 + assert acos(1) == 0 assert acos(-1) == pi assert acos(sqrt(2)/2) == pi/4 assert acos(-sqrt(2)/2) == (3*pi)/4 - assert acos(x).diff(x) == -1/sqrt(1-x**2) + assert acos(x).diff(x) == -1/sqrt(1 - x**2) + + assert acos(0.2).is_real is True + assert acos(-2).is_real is False - assert acos(0.2).is_real == True - assert acos(-2).is_real == False def test_acos_series(): - x = Symbol('x') assert acos(x).series(x, 0, 8) == \ - pi/2 - x - x**3/6 - 3*x**5/40 - 5*x**7/112 + O(x**8) + pi/2 - x - x**3/6 - 3*x**5/40 - 5*x**7/112 + O(x**8) assert acos(x).series(x, 0, 8) == pi/2 - asin(x).series(x, 0, 8) t5 = acos(x).taylor_term(5, x) assert t5 == -3*x**5/40 assert acos(x).taylor_term(7, x, t5, 0) == -5*x**7/112 + def test_acos_rewrite(): - x = Symbol('x') assert acos(x).rewrite(log) == pi/2 + I*log(I*x + sqrt(1 - x**2)) + assert acos(x).rewrite(atan) == \ + atan(sqrt(1 - x**2)/x) + (pi/2)*(1 - x*sqrt(1/x**2)) assert acos(0).rewrite(atan) == S.Pi/2 assert acos(0.5).rewrite(atan) == acos(0.5).rewrite(log) assert acos(x).rewrite(asin) == S.Pi/2 - asin(x) -def test_atan(): - x = Symbol('x') - - r = Symbol('r', real=True) +def test_atan(): assert atan(nan) == nan assert atan(oo) == pi/2 assert atan(-oo) == -pi/2 - assert atan(0) == 0 - assert atan(1) == pi/4 + assert atan(0) == 0 + assert atan(1) == pi/4 assert atan(sqrt(3)) == pi/3 assert atan(oo) == pi/2 - assert atan(x).diff(x) == 1/(1+x**2) + assert atan(x).diff(x) == 1/(1 + x**2) - assert atan(r).is_real == True + assert atan(r).is_real is True assert atan(-2*I) == -I*atanh(2) + def test_atan_rewrite(): - x = Symbol('x') assert atan(x).rewrite(log) == I*log((1 - I*x)/(1 + I*x))/2 + def test_atan2(): assert atan2(0, 0) == S.NaN assert atan2(0, 1) == 0 @@ -554,42 +622,39 @@ assert atan2(-1, 1) == -pi/4 assert atan2(0, -1) == pi -def test_acot(): - x = Symbol('x') - - r = Symbol('r', real=True) +def test_acot(): assert acot(nan) == nan assert acot(-oo) == 0 assert acot(oo) == 0 - assert acot(1) == pi/4 - assert acot(0) == pi/2 + assert acot(1) == pi/4 + assert acot(0) == pi/2 assert acot(sqrt(3)/3) == pi/3 assert acot(1/sqrt(3)) == pi/3 assert acot(-1/sqrt(3)) == -pi/3 - assert acot(x).diff(x) == -1/(1+x**2) + assert acot(x).diff(x) == -1/(1 + x**2) - assert acot(r).is_real == True + assert acot(r).is_real is True assert acot(I*pi) == -I*acoth(pi) assert acot(-2*I) == I*acoth(2) + def test_acot_rewrite(): - x = Symbol('x') assert acot(x).rewrite(log) == I*log((x - I)/(x + I))/2 + def test_attributes(): - x = Symbol('x') assert sin(x).args == (x,) + def test_sincos_rewrite(): - x = Symbol("x") - y = Symbol("y") - assert sin(pi/2-x) == cos(x) - assert sin(pi-x) == sin(x) - assert cos(pi/2-x) == sin(x) - assert cos(pi-x) == -cos(x) + assert sin(pi/2 - x) == cos(x) + assert sin(pi - x) == sin(x) + assert cos(pi/2 - x) == sin(x) + assert cos(pi - x) == -cos(x) + def _check_even_rewrite(func, arg): """Checks that the expr has been rewritten using f(-x) -> f(x) @@ -597,44 +662,47 @@ """ return func(arg).args[0] == -arg + def _check_odd_rewrite(func, arg): """Checks that the expr has been rewritten using f(-x) -> -f(x) arg : -x """ return func(arg).func.is_Mul + def _check_no_rewrite(func, arg): """Checks that the expr is not rewritten""" return func(arg).args[0] == arg + def test_evenodd_rewrite(): - x, y = symbols('x,y') - a = cos(2) #negative - b = sin(1) #positive + a = cos(2) # negative + b = sin(1) # positive even = [cos] odd = [sin, tan, cot, asin, atan, acot] - with_minus = [-1, -2**1024 * E, -pi/105, -x*y, -x-y] + with_minus = [-1, -2**1024 * E, -pi/105, -x*y, -x - y] for func in even: for expr in with_minus: assert _check_even_rewrite(func, expr) assert _check_no_rewrite(func, a*b) - assert func(x-y) == func(y-x) #it doesn't matter which form is canonical + assert func( + x - y) == func(y - x) # it doesn't matter which form is canonical for func in odd: for expr in with_minus: assert _check_odd_rewrite(func, expr) assert _check_no_rewrite(func, a*b) - assert func(x-y) == -func(y-x) #it doesn't matter which form is canonical + assert func( + x - y) == -func(y - x) # it doesn't matter which form is canonical + def test_issue1448(): - x = Symbol('x') - assert cot(x).inverse() == acot assert sin(x).rewrite(cot) == 2*cot(x/2)/(1 + cot(x/2)**2) assert cos(x).rewrite(cot) == -(1 - cot(x/2)**2)/(1 + cot(x/2)**2) assert tan(x).rewrite(cot) == 1/cot(x) assert cot(x).fdiff() == -1 - cot(x)**2 + def test_as_leading_term_issue2173(): - x = Symbol('x') assert sin(x).as_leading_term(x) == x assert cos(x).as_leading_term(x) == 1 assert tan(x).as_leading_term(x) == x @@ -644,39 +712,40 @@ assert atan(x).as_leading_term(x) == x assert acot(x).as_leading_term(x) == x + def test_leading_terms(): - x = Symbol('x') for func in [sin, cos, tan, cot, asin, acos, atan, acot]: for arg in (1/x, S.Half): eq = func(arg) assert eq.as_leading_term(x) == eq + def test_atan2_expansion(): - x, y = symbols("x,y") - assert cancel(atan2(x+1,x**2).diff(x) - atan((x+1)/x**2).diff(x)) == 0 - assert cancel(atan(x/y).series(x, 0, 5) - atan2(x, y).series(x, 0, 5) \ + assert cancel(atan2(x + 1, x**2).diff(x) - atan((x + 1)/x**2).diff(x)) == 0 + assert cancel(atan(x/y).series(x, 0, 5) - atan2(x, y).series(x, 0, 5) + atan2(0, y) - atan(0)) == O(x**5) - assert cancel(atan(x/y).series(y, 1, 4) - atan2(x, y).series(y, 1, 4) \ + assert cancel(atan(x/y).series(y, 1, 4) - atan2(x, y).series(y, 1, 4) + atan2(x, 1) - atan(x)) == O(y**4) - assert cancel(atan((x+y)/y).series(y, 1, 3) - atan2(x+y, y).series(y, 1, 3) \ - + atan2(1+x, 1) - atan(1+x)) == O(y**3) - assert Matrix([atan2(x, y)]).jacobian([x, y]) \ - == Matrix([[y/(x**2+y**2), -x/(x**2+y**2)]]) + assert cancel(atan((x + y)/y).series(y, 1, 3) - atan2(x + y, y).series(y, 1, 3) + + atan2(1 + x, 1) - atan(1 + x)) == O(y**3) + assert Matrix([atan2(x, y)]).jacobian([x, y]) == \ + Matrix([[y/(x**2 + y**2), -x/(x**2 + y**2)]]) + def test_aseries(): - x = Symbol('x') def t(n, v, d, e): - assert abs(n(1/v).evalf() - n(1/x).series(x, dir=d).removeO().subs(x, v)) < e + assert abs( + n(1/v).evalf() - n(1/x).series(x, dir=d).removeO().subs(x, v)) < e t(atan, 0.1, '+', 1e-5) t(atan, -0.1, '-', 1e-5) t(acot, 0.1, '+', 1e-5) t(acot, -0.1, '-', 1e-5) + def test_issue_1321(): i = Symbol('i', integer=True) e = Symbol('e', even=True) o = Symbol('o', odd=True) - x = Symbol('x') # unknown parity for variable assert cos(4*i*pi) == 1 @@ -684,7 +753,7 @@ assert tan(4*i*pi) == 0 assert cot(4*i*pi) == zoo - assert cos(3*i*pi) == cos(pi*i) # +/-1 + assert cos(3*i*pi) == cos(pi*i) # +/-1 assert sin(3*i*pi) == 0 assert tan(3*i*pi) == 0 assert cot(3*i*pi) == zoo @@ -694,7 +763,7 @@ assert tan(4.0*i*pi) == 0 assert cot(4.0*i*pi) == zoo - assert cos(3.0*i*pi) == cos(pi*i) # +/-1 + assert cos(3.0*i*pi) == cos(pi*i) # +/-1 assert sin(3.0*i*pi) == 0 assert tan(3.0*i*pi) == 0 assert cot(3.0*i*pi) == zoo @@ -781,27 +850,84 @@ assert tan(4.5*x*pi) == tan(4.5*pi*x) assert cot(4.5*x*pi) == cot(4.5*pi*x) + def test_inverses(): - x = Symbol('x') - for pair in [[sin, asin], [cos, acos], [tan, atan], [cot, acot]]: - assert pair[0](x).inverse() == pair[1] + raises(AttributeError, lambda: sin(x).inverse()) + raises(AttributeError, lambda: cos(x).inverse()) + assert tan(x).inverse() == atan + assert cot(x).inverse() == acot + raises(AttributeError, lambda: csc(x).inverse()) + raises(AttributeError, lambda: sec(x).inverse()) + assert asin(x).inverse() == sin + assert acos(x).inverse() == cos + assert atan(x).inverse() == tan + assert acot(x).inverse() == cot + + def test_real_imag(): - a,b = symbols('a,b', real=True) - z = a+b*I + a, b = symbols('a b', real=True) + z = a + b*I for deep in [True, False]: - assert sin(z).as_real_imag(deep=deep) == (sin(a)*cosh(b), cos(a)*sinh(b)) - assert cos(z).as_real_imag(deep=deep) == (cos(a)*cosh(b), -sin(a)*sinh(b)) - assert tan(z).as_real_imag(deep=deep) == (sin(a)*cos(a)/(cos(a)**2+sinh(b)**2), sinh(b)*cosh(b)/(cos(a)**2+sinh(b)**2)) - assert cot(z).as_real_imag(deep=deep) == (sin(a)*cos(a)/(sin(a)**2+sinh(b)**2), -sinh(b)*cosh(b)/(sin(a)**2+sinh(b)**2)) + assert sin( + z).as_real_imag(deep=deep) == (sin(a)*cosh(b), cos(a)*sinh(b)) + assert cos( + z).as_real_imag(deep=deep) == (cos(a)*cosh(b), -sin(a)*sinh(b)) + assert tan(z).as_real_imag(deep=deep) == (sin(a)*cos( + a)/(cos(a)**2 + sinh(b)**2), sinh(b)*cosh(b)/(cos(a)**2 + sinh(b)**2)) + assert cot(z).as_real_imag(deep=deep) == (sin(a)*cos(a)/( + sin(a)**2 + sinh(b)**2), -sinh(b)*cosh(b)/(sin(a)**2 + sinh(b)**2)) assert sin(a).as_real_imag(deep=deep) == (sin(a), 0) assert cos(a).as_real_imag(deep=deep) == (cos(a), 0) assert tan(a).as_real_imag(deep=deep) == (tan(a), 0) assert cot(a).as_real_imag(deep=deep) == (cot(a), 0) + @XFAIL def test_sin_cos_with_infinity(): # Test for issue 2097 # http://code.google.com/p/sympy/issues/detail?id=2097 assert sin(oo) == S.NaN assert cos(oo) == S.NaN + + +@slow +def test_sincos_rewrite_sqrt(): + # equivalent to testing rewrite(pow) + for p in [1, 3, 5, 17, 3*5*17]: + for t in [1, 8]: + n = t*p + for i in range(1, (n + 1)//2 + 1): + if 1 == gcd(i, n): + x = i*pi/n + s1 = sin(x).rewrite(sqrt) + c1 = cos(x).rewrite(sqrt) + assert not s1.has(cos, sin), "fails for %d*pi/%d" % (i, n) + assert not c1.has(cos, sin), "fails for %d*pi/%d" % (i, n) + assert 1e-10 > abs( sin(float(x)) - float(s1) ) + assert 1e-10 > abs( cos(float(x)) - float(c1) ) + + +@slow +def test_tancot_rewrite_sqrt(): + # equivalent to testing rewrite(pow) + for p in [1, 3, 5, 17, 3*5*17]: + for t in [1, 8]: + n = t*p + for i in range(1, (n + 1)//2 + 1): + if 1 == gcd(i, n): + x = i*pi/n + if 2*i != n and 3*i != 2*n: + t1 = tan(x).rewrite(sqrt) + assert not t1.has(cot, tan), "fails for %d*pi/%d" % (i, n) + assert 1e-10 > abs( tan(float(x)) - float(t1) ) + if i != 0 and i != n: + c1 = cot(x).rewrite(sqrt) + assert not c1.has(cot, tan), "fails for %d*pi/%d" % (i, n) + assert 1e-10 > abs( cot(float(x)) - float(c1) ) + +def test_sec(): + assert sec(x).diff(x) == tan(x)*sec(x) + +def test_csc(): + assert csc(x).diff(x) == -cot(x)*csc(x) diff -Nru python3-sympy-0.7.2/sympy/functions/elementary/trigonometric.py python3-sympy-0.7.3/sympy/functions/elementary/trigonometric.py --- python3-sympy-0.7.2/sympy/functions/elementary/trigonometric.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/functions/elementary/trigonometric.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,21 +1,32 @@ from sympy.core.add import Add -from sympy.core.numbers import Rational from sympy.core.basic import C, sympify, cacheit from sympy.core.singleton import S +from sympy.core.numbers import igcdex from sympy.core.function import Function, ArgumentIndexError from sympy.functions.elementary.miscellaneous import sqrt from sympy.functions.elementary.exponential import log from sympy.functions.elementary.hyperbolic import HyperbolicFunction +from sympy.utilities.iterables import numbered_symbols ############################################################################### ########################## TRIGONOMETRIC FUNCTIONS ############################ ############################################################################### + class TrigonometricFunction(Function): """Base class for trigonometric functions. """ unbranched = True + def _eval_is_rational(self): + s = self.func(*self.args) + if s.func == self.func: + if s.args[0].is_rational: + return False + else: + return s.is_rational + + def _peeloff_pi(arg): """ Split ARG into two parts, a "rest" and a multiple of pi/2. @@ -46,6 +57,7 @@ m2 = K*S.Pi - m1 return arg - m2, m2 + def _pi_coeff(arg, cycles=1): """ When arg is a Number times pi (e.g. 3*pi/2) then return the Number @@ -55,7 +67,9 @@ something with known parity then the multiple is returned as 0 otherwise as 2. - Examples: + Examples + ======== + >>> from sympy.functions.elementary.trigonometric import _pi_coeff as coeff >>> from sympy import pi >>> from sympy.abc import x, y @@ -84,33 +98,34 @@ elif arg.is_Mul: cx = arg.coeff(S.Pi) if cx: - c, x = cx.as_coeff_Mul() # pi is not included as coeff + c, x = cx.as_coeff_Mul() # pi is not included as coeff if c.is_Float: # recast exact binary fractions to Rationals f = abs(c) % 1 if f != 0: - p = -round(log(f, 2).evalf()) + p = -int(round(log(f, 2).evalf())) m = 2**p cm = c*m i = int(cm) if i == cm: - c = Rational(i, m) + c = C.Rational(i, m) cx = c*x else: - c = Rational(int(c)) + c = C.Rational(int(c)) cx = c*x if x.is_integer: c2 = c % 2 if c2 == 1: return x elif not c2: - if x.is_even is not None: # known parity + if x.is_even is not None: # known parity return S.Zero return 2*x else: return c2*x return cx + class sin(TrigonometricFunction): """ The sine function. @@ -147,7 +162,7 @@ References ========== - U{Definitions in trigonometry} + .. [1] http://planetmath.org/encyclopedia/DefinitionsInTrigonometry.html """ @@ -159,12 +174,6 @@ else: raise ArgumentIndexError(self, argindex) - def inverse(self, argindex=1): - """ - Returns the inverse of this function. - """ - return asin - @classmethod def eval(cls, arg): if arg.is_Number: @@ -172,7 +181,7 @@ return S.NaN elif arg is S.Zero: return S.Zero - elif arg is S.Infinity: + elif arg is S.Infinity or arg is S.NegativeInfinity: return if arg.could_extract_minus_sign(): @@ -193,49 +202,26 @@ return cls(narg) return None - cst_table_some = { - 2 : S.One, - 3 : S.Half*sqrt(3), - 4 : S.Half*sqrt(2), - 6 : S.Half, - } - - cst_table_more = { - (1, 5) : sqrt((5 - sqrt(5)) / 8), - (2, 5) : sqrt((5 + sqrt(5)) / 8) - } - - p = pi_coeff.p - q = pi_coeff.q - - Q, P = p // q, p % q - - try: - result = cst_table_some[q] - except KeyError: - if abs(P) > q // 2: - P = q - P - - try: - result = cst_table_more[(P, q)] - except KeyError: - if P != p: - result = cls(C.Rational(P, q)*S.Pi) - else: - newarg = pi_coeff*S.Pi - if newarg != arg: - return cls(newarg) - return None - - if Q % 2 == 1: - return -result - else: - return result + # http://code.google.com/p/sympy/issues/detail?id=2949 + # transform a sine to a cosine, to avoid redundant code + if pi_coeff.is_Rational: + x = pi_coeff % 2 + if x > 1: + return -cls((x % 1)*S.Pi) + if 2*x > 1: + return cls((1 - x)*S.Pi) + narg = ((pi_coeff + C.Rational(3, 2)) % 2)*S.Pi + result = cos(narg) + if not isinstance(result, cos): + return result + if pi_coeff*S.Pi != arg: + return cls(pi_coeff*S.Pi) + return None if arg.is_Add: x, m = _peeloff_pi(arg) if m: - return sin(m)*cos(x)+cos(m)*sin(x) + return sin(m)*cos(x) + cos(m)*sin(x) if arg.func is asin: return arg.args[0] @@ -266,13 +252,13 @@ if len(previous_terms) > 2: p = previous_terms[-2] - return -p * x**2 / (n*(n-1)) + return -p * x**2 / (n*(n - 1)) else: return (-1)**(n//2) * x**(n)/C.factorial(n) def _eval_rewrite_as_exp(self, arg): exp, I = C.exp, S.ImaginaryUnit - if isinstance(arg, TrigonometricFunction) or isinstance(arg, HyperbolicFunction) : + if isinstance(arg, TrigonometricFunction) or isinstance(arg, HyperbolicFunction): arg = arg.func(arg.args[0]).rewrite(exp) return (exp(arg*I) - exp(-arg*I)) / (2*I) @@ -296,6 +282,12 @@ cot_half = cot(S.Half*arg) return 2*cot_half/(1 + cot_half**2) + def _eval_rewrite_as_pow(self, arg): + return self.rewrite(cos).rewrite(pow) + + def _eval_rewrite_as_sqrt(self, arg): + return self.rewrite(cos).rewrite(sqrt) + def _eval_conjugate(self): return self.func(self.args[0].conjugate()) @@ -316,7 +308,7 @@ from sympy import expand_mul arg = self.args[0] x = None - if arg.is_Add: # TODO, implement more if deep stuff here + if arg.is_Add: # TODO, implement more if deep stuff here # TODO: Do this more efficiently for more than two terms x, y = arg.as_two_terms() sx = sin(x, evaluate=False)._eval_expand_trig() @@ -326,7 +318,7 @@ return sx*cy + sy*cx else: n, x = arg.as_coeff_Mul(rational=True) - if n.is_Integer: # n will be positive because of .eval + if n.is_Integer: # n will be positive because of .eval # canonicalization # See http://mathworld.wolfram.com/Multiple-AngleFormulas.html @@ -335,6 +327,10 @@ else: return expand_mul((-1)**(n/2 - 1)*cos(x)*C.chebyshevu(n - 1, sin(x)), deep=False) + pi_coeff = _pi_coeff(arg) + if pi_coeff is not None: + if pi_coeff.is_Rational: + return self.rewrite(sqrt) return sin(arg) def _eval_as_leading_term(self, x): @@ -357,6 +353,7 @@ import sage.all as sage return sage.sin(self.args[0]._sage_()) + class cos(TrigonometricFunction): """ The cosine function. @@ -393,7 +390,7 @@ References ========== - U{Definitions in trigonometry} + .. [1] http://planetmath.org/encyclopedia/DefinitionsInTrigonometry.html """ @@ -405,9 +402,6 @@ else: raise ArgumentIndexError(self, argindex) - def inverse(self, argindex=1): - return acos - @classmethod def eval(cls, arg): if arg.is_Number: @@ -415,7 +409,15 @@ return S.NaN elif arg is S.Zero: return S.One - elif arg is S.Infinity: + elif arg is S.Infinity or arg is S.NegativeInfinity: + # In this cases, it is unclear if we should + # return S.NaN or leave un-evaluated. One + # useful test case is how "limit(sin(x)/x,x,oo)" + # is handled. + # See test_sin_cos_with_infinity() an + # Test for issue 209 + # http://code.google.com/p/sympy/issues/detail?id=2097 + # For now, we return un-evaluated. return if arg.could_extract_minus_sign(): @@ -427,58 +429,59 @@ pi_coeff = _pi_coeff(arg) if pi_coeff is not None: + if pi_coeff.is_integer: + return (S.NegativeOne)**pi_coeff if not pi_coeff.is_Rational: - if pi_coeff.is_integer: - return (S.NegativeOne)**pi_coeff narg = pi_coeff*S.Pi if narg != arg: return cls(narg) return None + # cosine formula ##################### + # http://code.google.com/p/sympy/issues/detail?id=2949 + # explicit calculations are preformed for + # cos(k pi / 8), cos(k pi /10), and cos(k pi / 12) + # Some other exact values like cos(k pi/15) can be + # calculated using a partial-fraction decomposition + # by calling cos( X ).rewrite(sqrt) cst_table_some = { - 1 : S.One, - 2 : S.Zero, - 3 : S.Half, - 4 : S.Half*sqrt(2), - 6 : S.Half*sqrt(3), + 3: S.Half, + 5: (sqrt(5) + 1)/4, } + if pi_coeff.is_Rational: + q = pi_coeff.q + p = pi_coeff.p % (2*q) + if p > q: + narg = (pi_coeff - 1)*S.Pi + return -cls(narg) + if 2*p > q: + narg = (1 - pi_coeff)*S.Pi + return -cls(narg) + + # If nested sqrt's are worse than un-evaluation + # you can require q in (1, 2, 3, 4, 6) + # q <= 12 returns expressions with 2 or fewer nestings. + if q > 12: + return None - cst_table_more = { - (1, 5) : (sqrt(5) + 1)/4, - (2, 5) : (sqrt(5) - 1)/4 - } - - p = pi_coeff.p - q = pi_coeff.q - - Q, P = 2*p // q, p % q - - try: - result = cst_table_some[q] - except KeyError: - if abs(P) > q // 2: - P = q - P - - try: - result = cst_table_more[(P, q)] - except KeyError: - if P != p: - result = cls(C.Rational(P, q)*S.Pi) - else: - newarg = pi_coeff*S.Pi - if newarg != arg: - return cls(newarg) + if q in cst_table_some: + cts = cst_table_some[pi_coeff.q] + return C.chebyshevt(pi_coeff.p, cts).expand() + + if 0 == q % 2: + narg = (pi_coeff*2)*S.Pi + nval = cls(narg) + if None == nval: return None - - if Q % 4 in (1, 2): - return -result - else: - return result + x = (2*pi_coeff + 1)/2 + sign_cos = (-1)**((-1 if x < 0 else 1)*int(abs(x))) + return sign_cos*sqrt( (1 + nval)/2 ) + return None if arg.is_Add: x, m = _peeloff_pi(arg) if m: - return cos(m)*cos(x)-sin(m)*sin(x) + return cos(m)*cos(x) - sin(m)*sin(x) if arg.func is acos: return arg.args[0] @@ -509,13 +512,13 @@ if len(previous_terms) > 2: p = previous_terms[-2] - return -p * x**2 / (n*(n-1)) + return -p * x**2 / (n*(n - 1)) else: return (-1)**(n//2)*x**(n)/C.factorial(n) def _eval_rewrite_as_exp(self, arg): exp, I = C.exp, S.ImaginaryUnit - if isinstance(arg, TrigonometricFunction) or isinstance(arg, HyperbolicFunction) : + if isinstance(arg, TrigonometricFunction) or isinstance(arg, HyperbolicFunction): arg = arg.func(arg.args[0]).rewrite(exp) return (exp(arg*I) + exp(-arg*I)) / 2 @@ -530,14 +533,118 @@ def _eval_rewrite_as_tan(self, arg): tan_half = tan(S.Half*arg)**2 - return (1-tan_half)/(1+tan_half) + return (1 - tan_half)/(1 + tan_half) def _eval_rewrite_as_sincos(self, arg): return sin(arg)*cos(arg)/sin(arg) def _eval_rewrite_as_cot(self, arg): cot_half = cot(S.Half*arg)**2 - return (cot_half-1)/(cot_half+1) + return (cot_half - 1)/(cot_half + 1) + + def _eval_rewrite_as_pow(self, arg): + return self._eval_rewrite_as_sqrt(arg) + + def _eval_rewrite_as_sqrt(self, arg): + _EXPAND_INTS = False + + def migcdex(x): + # recursive calcuation of gcd and linear combination + # for a sequence of integers. + # Given (x1, x2, x3) + # Returns (y1, y1, y3, g) + # such that g is the gcd and x1*y1+x2*y2+x3*y3 - g = 0 + # Note, that this is only one such linear combination. + if len(x) == 1: + return (1, x[0]) + if len(x) == 2: + return igcdex(x[0], x[-1]) + g = migcdex(x[1:]) + u, v, h = igcdex(x[0], g[-1]) + return tuple([u] + [v*i for i in g[0:-1] ] + [h]) + + def ipartfrac(r, factors=None): + if isinstance(r, int): + return r + assert isinstance(r, C.Rational) + n = r.q + if 2 > r.q*r.q: + return r.q + + if None == factors: + a = [n//x**y for x, y in factorint(r.q).items()] + else: + a = [n//x for x in factors] + if len(a) == 1: + return [ r ] + h = migcdex(a) + ans = [ r.p*C.Rational(i*j, r.q) for i, j in zip(h[:-1], a) ] + assert r == sum(ans) + return ans + pi_coeff = _pi_coeff(arg) + if pi_coeff is None: + return None + + assert not pi_coeff.is_integer, "should have been simplified already" + + if not pi_coeff.is_Rational: + return None + + cst_table_some = { + 3: S.Half, + 5: (sqrt(5) + 1)/4, + 17: sqrt((15 + sqrt(17))/32 + sqrt(2)*(sqrt(17 - sqrt(17)) + + sqrt(sqrt(2)*(-8*sqrt(17 + sqrt(17)) - (1 - sqrt(17)) + *sqrt(17 - sqrt(17))) + 6*sqrt(17) + 34))/32) + # 65537 and 257 are the only other known Fermat primes + # Please add if you would like them + } + + def fermatCoords(n): + assert isinstance(n, int) + assert n > 0 + if n == 1 or 0 == n % 2: + return False + primes = dict( [(p, 0) for p in cst_table_some ] ) + assert 1 not in primes + for p_i in primes: + while 0 == n % p_i: + n = n/p_i + primes[p_i] += 1 + if 1 != n: + return False + if max(primes.values()) > 1: + return False + return tuple([ p for p in primes if primes[p] == 1]) + + if pi_coeff.q in cst_table_some: + return C.chebyshevt(pi_coeff.p, cst_table_some[pi_coeff.q]).expand() + + if 0 == pi_coeff.q % 2: # recursively remove powers of 2 + narg = (pi_coeff*2)*S.Pi + nval = cos(narg) + if None == nval: + return None + nval = nval.rewrite(sqrt) + if not _EXPAND_INTS: + if (isinstance(nval, cos) or isinstance(-nval, cos)): + return None + x = (2*pi_coeff + 1)/2 + sign_cos = (-1)**((-1 if x < 0 else 1)*int(abs(x))) + return sign_cos*sqrt( (1 + nval)/2 ) + + FC = fermatCoords(pi_coeff.q) + if FC: + decomp = ipartfrac(pi_coeff, FC) + X = [(x[1], x[0]*S.Pi) for x in zip(decomp, numbered_symbols('z'))] + pcls = cos(sum([x[0] for x in X]))._eval_expand_trig().subs(X) + return pcls.rewrite(sqrt) + if _EXPAND_INTS: + decomp = ipartfrac(pi_coeff) + X = [(x[1], x[0]*S.Pi) for x in zip(decomp, numbered_symbols('z'))] + pcls = cos(sum([x[0] for x in X]))._eval_expand_trig().subs(X) + return pcls + return None def _eval_conjugate(self): return self.func(self.args[0].conjugate()) @@ -558,7 +665,7 @@ def _eval_expand_trig(self, **hints): arg = self.args[0] x = None - if arg.is_Add: # TODO: Do this more efficiently for more than two terms + if arg.is_Add: # TODO: Do this more efficiently for more than two terms x, y = arg.as_two_terms() sx = sin(x, evaluate=False)._eval_expand_trig() sy = sin(y, evaluate=False)._eval_expand_trig() @@ -569,6 +676,10 @@ coeff, terms = arg.as_coeff_Mul(rational=True) if coeff.is_Integer: return C.chebyshevt(coeff, cos(terms)) + pi_coeff = _pi_coeff(arg) + if pi_coeff is not None: + if pi_coeff.is_Rational: + return self.rewrite(sqrt) return cos(arg) def _eval_as_leading_term(self, x): @@ -592,22 +703,37 @@ import sage.all as sage return sage.cos(self.args[0]._sage_()) -class sec(TrigonometricFunction): #TODO implement rest all functions for sec. see cos, sin, tan. - def _eval_rewrite_as_cos(self,arg): +class sec(TrigonometricFunction): # TODO implement rest all functions for sec. see cos, sin, tan. + + def _eval_rewrite_as_cos(self, arg): return (1/cos(arg)) def _eval_rewrite_as_sincos(self, arg): return sin(arg)/(cos(arg)*sin(arg)) -class csc(TrigonometricFunction): #TODO implement rest all functions for csc. see cos, sin, tan. + def fdiff(self, argindex=1): + if argindex == 1: + return tan(self.args[0])*sec(self.args[0]) + else: + raise ArgumentIndexError(self, argindex) - def _eval_rewrite_as_sin(self,arg): + +class csc(TrigonometricFunction): # TODO implement other functions for csc as in cos, sin, tan. + + def _eval_rewrite_as_sin(self, arg): return (1/sin(arg)) def _eval_rewrite_as_sincos(self, arg): return cos(arg)/(sin(arg)*cos(arg)) + def fdiff(self, argindex=1): + if argindex == 1: + return -cot(self.args[0])*csc(self.args[0]) + else: + raise ArgumentIndexError(self, argindex) + + class tan(TrigonometricFunction): """ tan(x) -> Returns the tangent of x (measured in radians) @@ -636,14 +762,14 @@ References ========== - U{Definitions in trigonometry} + .. [1] http://planetmath.org/encyclopedia/DefinitionsInTrigonometry.html """ nargs = 1 def fdiff(self, argindex=1): - if argindex==1: + if argindex == 1: return S.One + self**2 else: raise ArgumentIndexError(self, argindex) @@ -680,39 +806,27 @@ return cls(narg) return None - cst_table = { - 2 : S.ComplexInfinity, - 3 : sqrt(3), - 4 : S.One, - 6 : 1 / sqrt(3), - } - - try: - result = cst_table[pi_coeff.q] - - if (2*pi_coeff.p // pi_coeff.q) % 4 in (1, 3): - return -result - else: - return result - except KeyError: - if pi_coeff.p > pi_coeff.q: - p, q = pi_coeff.p % pi_coeff.q, pi_coeff.q - if 2 * p > q: - return -cls(Rational(q - p, q)*S.Pi) - return cls(Rational(p, q)*S.Pi) - else: - newarg = pi_coeff*S.Pi - if newarg != arg: - return cls(newarg) - return None + if pi_coeff.is_Rational: + narg = ((pi_coeff + S.Half) % 1 - S.Half)*S.Pi + # see cos() to specify which expressions should be + # expanded automatically in terms of radicals + cresult, sresult = cos(narg), cos(narg - S.Pi/2) + if not isinstance(cresult, cos) \ + and not isinstance(sresult, cos): + if cresult == 0: + return S.ComplexInfinity + return (sresult/cresult) + if narg != arg: + return cls(narg) if arg.is_Add: x, m = _peeloff_pi(arg) if m: - if (m*2/S.Pi) % 2 == 0: - return tan(x) - else: + tanm = tan(m) + tanx = tan(x) + if tanm is S.ComplexInfinity: return -cot(x) + return (tanm + tanx)/(1 - tanm*tanx) if arg.func is atan: return arg.args[0] @@ -741,12 +855,12 @@ else: x = sympify(x) - a, b = ((n-1)//2), 2**(n+1) + a, b = ((n - 1)//2), 2**(n + 1) - B = C.bernoulli(n+1) - F = C.factorial(n+1) + B = C.bernoulli(n + 1) + F = C.factorial(n + 1) - return (-1)**a * b*(b-1) * B/F * x**n + return (-1)**a * b*(b - 1) * B/F * x**n def _eval_nseries(self, x, n, logx): i = self.args[0].limit(x, 0)*2/S.Pi @@ -777,14 +891,40 @@ denom = cos(re)**2 + C.sinh(im)**2 return (sin(re)*cos(re)/denom, C.sinh(im)*C.cosh(im)/denom) - # TODO: Implement _eval_expand_trig + def _eval_expand_trig(self, **hints): + arg = self.args[0] + x = None + if arg.is_Add: + from sympy import symmetric_poly + n = len(arg.args) + TX = [] + for x in arg.args: + tx = tan(x, evaluate=False)._eval_expand_trig() + TX.append(tx) + + Yg = numbered_symbols('Y') + Y = [ next(Yg) for i in range(n) ] + + p = [0, 0] + for i in range(n + 1): + p[1 - i % 2] += symmetric_poly(i, Y)*(-1)**((i % 4)//2) + return (p[0]/p[1]).subs(list(zip(Y, TX))) + + else: + coeff, terms = arg.as_coeff_Mul(rational=True) + if coeff.is_Integer and coeff > 1: + I = S.ImaginaryUnit + z = C.Symbol('dummy', real=True) + P = ((1 + I*z)**coeff).expand() + return (C.im(P)/C.re(P)).subs([(z, tan(terms))]) + return tan(arg) def _eval_rewrite_as_exp(self, arg): exp, I = C.exp, S.ImaginaryUnit - if isinstance(arg, TrigonometricFunction) or isinstance(arg, HyperbolicFunction) : + if isinstance(arg, TrigonometricFunction) or isinstance(arg, HyperbolicFunction): arg = arg.func(arg.args[0]).rewrite(exp) neg_exp, pos_exp = exp(-arg*I), exp(arg*I) - return I*(neg_exp-pos_exp)/(neg_exp+pos_exp) + return I*(neg_exp - pos_exp)/(neg_exp + pos_exp) def _eval_rewrite_as_sin(self, x): return 2*sin(x)**2/sin(2*x) @@ -798,6 +938,18 @@ def _eval_rewrite_as_cot(self, arg): return 1/cot(arg) + def _eval_rewrite_as_pow(self, arg): + y = self.rewrite(cos).rewrite(pow) + if y.has(cos): + return None + return y + + def _eval_rewrite_as_sqrt(self, arg): + y = self.rewrite(cos).rewrite(sqrt) + if y.has(cos): + return None + return y + def _eval_as_leading_term(self, x): arg = self.args[0].as_leading_term(x) @@ -819,6 +971,7 @@ import sage.all as sage return sage.tan(self.args[0]._sage_()) + class cot(TrigonometricFunction): """ cot(x) -> Returns the cotangent of x (measured in radians) @@ -834,7 +987,7 @@ def inverse(self, argindex=1): """ - Return the inverse of this function. + Returns the inverse of this function. """ return acot @@ -864,39 +1017,31 @@ return cls(narg) return None - cst_table = { - 2 : S.Zero, - 3 : 1 / sqrt(3), - 4 : S.One, - 6 : sqrt(3) - } - - try: - result = cst_table[pi_coeff.q] - - if (2*pi_coeff.p // pi_coeff.q) % 4 in (1, 3): - return -result - else: - return result - except KeyError: - if pi_coeff.p > pi_coeff.q: - p, q = pi_coeff.p % pi_coeff.q, pi_coeff.q - if 2 * p > q: - return -cls(Rational(q - p, q)*S.Pi) - return cls(Rational(p, q)*S.Pi) - else: - newarg = pi_coeff*S.Pi - if newarg != arg: - return cls(newarg) - return None + if pi_coeff.is_Rational: + narg = (((pi_coeff + S.Half) % 1) - S.Half)*S.Pi + # see cos() to specify which expressions should be + # expanded automatically in terms of radicals + cresult, sresult = cos(narg), cos(narg - S.Pi/2) + if not isinstance(cresult, cos) \ + and not isinstance(sresult, cos): + if sresult == 0: + return S.ComplexInfinity + return cresult / sresult + if narg != arg: + return cls(narg) if arg.is_Add: x, m = _peeloff_pi(arg) if m: - if (m*2/S.Pi) % 2 == 0: - return cot(x) - else: + cotm = cot(m) + if cotm == 0: return -tan(x) + cotx = cot(x) + if cotm is S.ComplexInfinity: + return cotx + if cotm.is_Rational: + return (cotm*cotx - 1) / (cotm + cotx) + return None if arg.func is acot: return arg.args[0] @@ -927,10 +1072,10 @@ else: x = sympify(x) - B = C.bernoulli(n+1) - F = C.factorial(n+1) + B = C.bernoulli(n + 1) + F = C.factorial(n + 1) - return (-1)**((n+1)//2) * 2**(n+1) * B/F * x**n + return (-1)**((n + 1)//2) * 2**(n + 1) * B/F * x**n def _eval_nseries(self, x, n, logx): i = self.args[0].limit(x, 0)/S.Pi @@ -958,10 +1103,10 @@ def _eval_rewrite_as_exp(self, arg): exp, I = C.exp, S.ImaginaryUnit - if isinstance(arg, TrigonometricFunction) or isinstance(arg, HyperbolicFunction) : + if isinstance(arg, TrigonometricFunction) or isinstance(arg, HyperbolicFunction): arg = arg.func(arg.args[0]).rewrite(exp) neg_exp, pos_exp = exp(-arg*I), exp(arg*I) - return I*(pos_exp+neg_exp)/(pos_exp-neg_exp) + return I*(pos_exp + neg_exp)/(pos_exp - neg_exp) def _eval_rewrite_as_Pow(self, arg): if arg.func is log: @@ -981,6 +1126,18 @@ def _eval_rewrite_as_tan(self, arg): return 1/tan(arg) + def _eval_rewrite_as_pow(self, arg): + y = self.rewrite(cos).rewrite(pow) + if y.has(cos): + return None + return y + + def _eval_rewrite_as_sqrt(self, arg): + y = self.rewrite(cos).rewrite(sqrt) + if y.has(cos): + return None + return y + def _eval_as_leading_term(self, x): arg = self.args[0].as_leading_term(x) @@ -992,6 +1149,33 @@ def _eval_is_real(self): return self.args[0].is_real + def _eval_expand_trig(self, **hints): + arg = self.args[0] + x = None + if arg.is_Add: + from sympy import symmetric_poly + n = len(arg.args) + CX = [] + for x in arg.args: + cx = cot(x, evaluate=False)._eval_expand_trig() + CX.append(cx) + + Yg = numbered_symbols('Y') + Y = [ next(Yg) for i in range(n) ] + + p = [0, 0] + for i in range(n, -1, -1): + p[(n - i) % 2] += symmetric_poly(i, Y)*(-1)**(((n - i) % 4)//2) + return (p[0]/p[1]).subs(list(zip(Y, CX))) + else: + coeff, terms = arg.as_coeff_Mul(rational=True) + if coeff.is_Integer and coeff > 1: + I = S.ImaginaryUnit + z = C.Symbol('dummy', real=True) + P = ((z + I)**coeff).expand() + return (C.re(P)/C.im(P)).subs([(z, cot(terms))]) + return cot(arg) + def _sage_(self): import sage.all as sage return sage.cot(self.args[0]._sage_()) @@ -1000,6 +1184,7 @@ ########################### TRIGONOMETRIC INVERSES ############################ ############################################################################### + class asin(Function): """ asin(x) -> Returns the arc sine of x (measured in radians) @@ -1033,6 +1218,14 @@ else: raise ArgumentIndexError(self, argindex) + def _eval_is_rational(self): + s = self.func(*self.args) + if s.func == self.func: + if s.args[0].is_rational: + return False + else: + return s.is_rational + @classmethod def eval(cls, arg): if arg.is_Number: @@ -1054,25 +1247,25 @@ if arg.is_number: cst_table = { - sqrt(3)/2 : 3, - -sqrt(3)/2 : -3, - sqrt(2)/2 : 4, - -sqrt(2)/2 : -4, - 1/sqrt(2) : 4, - -1/sqrt(2) : -4, - sqrt((5-sqrt(5))/8) : 5, - -sqrt((5-sqrt(5))/8) : -5, - S.Half : 6, - -S.Half : -6, - sqrt(2-sqrt(2))/2 : 8, - -sqrt(2-sqrt(2))/2 : -8, - (sqrt(5)-1)/4 : 10, - (1-sqrt(5))/4 : -10, - (sqrt(3)-1)/sqrt(2**3) : 12, - (1-sqrt(3))/sqrt(2**3) : -12, - (sqrt(5)+1)/4 : S(10)/3, - -(sqrt(5)+1)/4 : -S(10)/3 - } + sqrt(3)/2: 3, + -sqrt(3)/2: -3, + sqrt(2)/2: 4, + -sqrt(2)/2: -4, + 1/sqrt(2): 4, + -1/sqrt(2): -4, + sqrt((5 - sqrt(5))/8): 5, + -sqrt((5 - sqrt(5))/8): -5, + S.Half: 6, + -S.Half: -6, + sqrt(2 - sqrt(2))/2: 8, + -sqrt(2 - sqrt(2))/2: -8, + (sqrt(5) - 1)/4: 10, + (1 - sqrt(5))/4: -10, + (sqrt(3) - 1)/sqrt(2**3): 12, + (1 - sqrt(3))/sqrt(2**3): -12, + (sqrt(5) + 1)/4: S(10)/3, + -(sqrt(5) + 1)/4: -S(10)/3 + } if arg in cst_table: return S.Pi / cst_table[arg] @@ -1090,7 +1283,7 @@ x = sympify(x) if len(previous_terms) >= 2 and n > 2: p = previous_terms[-2] - return p * (n-2)**2/(n*(n-1)) * x**2 + return p * (n - 2)**2/(n*(n - 1)) * x**2 else: k = (n - 1) // 2 R = C.RisingFactorial(S.Half, k) @@ -1112,15 +1305,22 @@ return 2*atan(x/(1 + sqrt(1 - x**2))) def _eval_rewrite_as_log(self, x): - return -S.ImaginaryUnit*C.log(S.ImaginaryUnit*x + sqrt(1-x**2)) + return -S.ImaginaryUnit*C.log(S.ImaginaryUnit*x + sqrt(1 - x**2)) def _eval_is_real(self): - return self.args[0].is_real and (self.args[0]>=-1 and self.args[0]<=1) + return self.args[0].is_real and (self.args[0] >= -1 and self.args[0] <= 1) + + def inverse(self, argindex=1): + """ + Returns the inverse of this function. + """ + return sin def _sage_(self): import sage.all as sage return sage.asin(self.args[0]._sage_()) + class acos(Function): """ acos(x) -> Returns the arc cosine of x (measured in radians) @@ -1156,6 +1356,14 @@ else: raise ArgumentIndexError(self, argindex) + def _eval_is_rational(self): + s = self.func(*self.args) + if s.func == self.func: + if s.args[0].is_rational: + return False + else: + return s.is_rational + @classmethod def eval(cls, arg): if arg.is_Number: @@ -1174,20 +1382,19 @@ if arg.is_number: cst_table = { - S.Half : S.Pi/3, - -S.Half : 2*S.Pi/3, - sqrt(2)/2 : S.Pi/4, - -sqrt(2)/2 : 3*S.Pi/4, - 1/sqrt(2) : S.Pi/4, - -1/sqrt(2) : 3*S.Pi/4, - sqrt(3)/2 : S.Pi/6, - -sqrt(3)/2 : 5*S.Pi/6, - } + S.Half: S.Pi/3, + -S.Half: 2*S.Pi/3, + sqrt(2)/2: S.Pi/4, + -sqrt(2)/2: 3*S.Pi/4, + 1/sqrt(2): S.Pi/4, + -1/sqrt(2): 3*S.Pi/4, + sqrt(3)/2: S.Pi/6, + -sqrt(3)/2: 5*S.Pi/6, + } if arg in cst_table: return cst_table[arg] - @staticmethod @cacheit def taylor_term(n, x, *previous_terms): @@ -1199,7 +1406,7 @@ x = sympify(x) if len(previous_terms) >= 2 and n > 2: p = previous_terms[-2] - return p * (n-2)**2/(n*(n-1)) * x**2 + return p * (n - 2)**2/(n*(n - 1)) * x**2 else: k = (n - 1) // 2 R = C.RisingFactorial(S.Half, k) @@ -1215,7 +1422,7 @@ return self.func(arg) def _eval_is_real(self): - return self.args[0].is_real and (self.args[0]>=-1 and self.args[0]<=1) + return self.args[0].is_real and (self.args[0] >= -1 and self.args[0] <= 1) def _eval_rewrite_as_log(self, x): return S.Pi/2 + S.ImaginaryUnit * C.log(S.ImaginaryUnit * x + sqrt(1 - x**2)) @@ -1224,15 +1431,19 @@ return S.Pi/2 - asin(x) def _eval_rewrite_as_atan(self, x): - if x > -1 and x <= 1: - return 2 * atan(sqrt(1 - x**2)/(1 + x)) - else: - raise ValueError("The argument must be bounded in the interval (-1,1]") + return atan(sqrt(1 - x**2)/x) + (S.Pi/2)*(1 - x*sqrt(1/x**2)) + + def inverse(self, argindex=1): + """ + Returns the inverse of this function. + """ + return cos def _sage_(self): import sage.all as sage return sage.acos(self.args[0]._sage_()) + class atan(Function): """ atan(x) -> Returns the arc tangent of x (measured in radians) @@ -1264,10 +1475,18 @@ def fdiff(self, argindex=1): if argindex == 1: - return 1/(1+self.args[0]**2) + return 1/(1 + self.args[0]**2) else: raise ArgumentIndexError(self, argindex) + def _eval_is_rational(self): + s = self.func(*self.args) + if s.func == self.func: + if s.args[0].is_rational: + return False + else: + return s.is_rational + @classmethod def eval(cls, arg): if arg.is_Number: @@ -1288,21 +1507,21 @@ if arg.is_number: cst_table = { - sqrt(3)/3 : 6, - -sqrt(3)/3 : -6, - 1/sqrt(3) : 6, - -1/sqrt(3) : -6, - sqrt(3) : 3, - -sqrt(3) : -3, - (1+sqrt(2)) : S(8)/3, - -(1+sqrt(2)) : S(8)/3, - (sqrt(2)-1) : 8, - (1-sqrt(2)) : -8, - sqrt((5+2*sqrt(5))) : S(5)/2, - -sqrt((5+2*sqrt(5))) : -S(5)/2, - (2-sqrt(3)) : 12, - -(2-sqrt(3)) : -12 - } + sqrt(3)/3: 6, + -sqrt(3)/3: -6, + 1/sqrt(3): 6, + -1/sqrt(3): -6, + sqrt(3): 3, + -sqrt(3): -3, + (1 + sqrt(2)): S(8)/3, + -(1 + sqrt(2)): S(8)/3, + (sqrt(2) - 1): 8, + (1 - sqrt(2)): -8, + sqrt((5 + 2*sqrt(5))): S(5)/2, + -sqrt((5 + 2*sqrt(5))): -S(5)/2, + (2 - sqrt(3)): 12, + -(2 - sqrt(3)): -12 + } if arg in cst_table: return S.Pi / cst_table[arg] @@ -1311,8 +1530,6 @@ if i_coeff is not None: return S.ImaginaryUnit * C.atanh(i_coeff) - - @staticmethod @cacheit def taylor_term(n, x, *previous_terms): @@ -1320,7 +1537,7 @@ return S.Zero else: x = sympify(x) - return (-1)**((n-1)//2) * x**n / n + return (-1)**((n - 1)//2) * x**n / n def _eval_as_leading_term(self, x): arg = self.args[0].as_leading_term(x) @@ -1334,8 +1551,8 @@ return self.args[0].is_real def _eval_rewrite_as_log(self, x): - return S.ImaginaryUnit/2 * \ - (C.log((S(1) - S.ImaginaryUnit * x)/(S(1) + S.ImaginaryUnit * x))) + return S.ImaginaryUnit/2 * (C.log( + (S(1) - S.ImaginaryUnit * x)/(S(1) + S.ImaginaryUnit * x))) def _eval_aseries(self, n, args0, x, logx): if args0[0] == S.Infinity: @@ -1345,10 +1562,17 @@ else: return super(atan, self)._eval_aseries(n, args0, x, logx) + def inverse(self, argindex=1): + """ + Returns the inverse of this function. + """ + return tan + def _sage_(self): import sage.all as sage return sage.atan(self.args[0]._sage_()) + class acot(Function): """ acot(x) -> Returns the arc cotangent of x (measured in radians) @@ -1358,10 +1582,18 @@ def fdiff(self, argindex=1): if argindex == 1: - return -1 / (1+self.args[0]**2) + return -1 / (1 + self.args[0]**2) else: raise ArgumentIndexError(self, argindex) + def _eval_is_rational(self): + s = self.func(*self.args) + if s.func == self.func: + if s.args[0].is_rational: + return False + else: + return s.is_rational + @classmethod def eval(cls, arg): if arg.is_Number: @@ -1383,23 +1615,23 @@ if arg.is_number: cst_table = { - sqrt(3)/3 : 3, - -sqrt(3)/3 : -3, - 1/sqrt(3) : 3, - -1/sqrt(3) : -3, - sqrt(3) : 6, - -sqrt(3) : -6, - (1+sqrt(2)) : 8, - -(1+sqrt(2)) : -8, - (1-sqrt(2)) : -S(8)/3, - (sqrt(2)-1) : S(8)/3, - sqrt(5+2*sqrt(5)) : 10, - -sqrt(5+2*sqrt(5)) : -10, - (2+sqrt(3)) : 12, - -(2+sqrt(3)) : -12, - (2-sqrt(3)) : S(12)/5, - -(2-sqrt(3)) : -S(12)/5, - } + sqrt(3)/3: 3, + -sqrt(3)/3: -3, + 1/sqrt(3): 3, + -1/sqrt(3): -3, + sqrt(3): 6, + -sqrt(3): -6, + (1 + sqrt(2)): 8, + -(1 + sqrt(2)): -8, + (1 - sqrt(2)): -S(8)/3, + (sqrt(2) - 1): S(8)/3, + sqrt(5 + 2*sqrt(5)): 10, + -sqrt(5 + 2*sqrt(5)): -10, + (2 + sqrt(3)): 12, + -(2 + sqrt(3)): -12, + (2 - sqrt(3)): S(12)/5, + -(2 - sqrt(3)): -S(12)/5, + } if arg in cst_table: return S.Pi / cst_table[arg] @@ -1412,12 +1644,12 @@ @cacheit def taylor_term(n, x, *previous_terms): if n == 0: - return S.Pi / 2 # FIX THIS + return S.Pi / 2 # FIX THIS elif n < 0 or n % 2 == 0: return S.Zero else: x = sympify(x) - return (-1)**((n+1)//2) * x**n / n + return (-1)**((n + 1)//2) * x**n / n def _eval_as_leading_term(self, x): arg = self.args[0].as_leading_term(x) @@ -1438,19 +1670,27 @@ else: return super(atan, self)._eval_aseries(n, args0, x, logx) + def _eval_rewrite_as_log(self, x): + return S.ImaginaryUnit/2 * \ + (C.log((x - S.ImaginaryUnit)/(x + S.ImaginaryUnit))) + + def inverse(self, argindex=1): + """ + Returns the inverse of this function. + """ + return cot + def _sage_(self): import sage.all as sage return sage.acot(self.args[0]._sage_()) - def _eval_rewrite_as_log(self, x): - return S.ImaginaryUnit/2 * \ - (C.log((x - S.ImaginaryUnit)/(x + S.ImaginaryUnit))) class atan2(Function): - """ - atan2(y,x) -> Returns the atan(y/x) taking two arguments y and x. - Signs of both y and x are considered to determine the appropriate - quadrant of atan(y/x). The range is (-pi, pi]. + r""" + atan2(y,x) -> Returns `\operatorname{atan}(y/x)` taking two + arguments y and x. Signs of both y and x are considered to + determine the appropriate quadrant of `\operatorname{atan}(y/x)`. + The range is `(-\pi, \pi]`. """ nargs = 2 diff -Nru python3-sympy-0.7.2/sympy/functions/special/__init__.py python3-sympy-0.7.3/sympy/functions/special/__init__.py --- python3-sympy-0.7.2/sympy/functions/special/__init__.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/functions/special/__init__.py 2013-07-13 17:53:32.000000000 +0000 @@ -3,5 +3,6 @@ from . import zeta_functions from . import tensor_functions from . import delta_functions +from . import elliptic_integrals from . import polynomials diff -Nru python3-sympy-0.7.2/sympy/functions/special/bessel.py python3-sympy-0.7.3/sympy/functions/special/bessel.py --- python3-sympy-0.7.2/sympy/functions/special/bessel.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/functions/special/bessel.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,9 +1,10 @@ """Bessel type functions""" from sympy import S, pi, I -from sympy.core.function import Function, ArgumentIndexError -from sympy.functions.elementary.trigonometric import sin, cos +from sympy.core.function import Function, ArgumentIndexError, expand_func +from sympy.functions.elementary.trigonometric import sin, cos, csc, cot from sympy.functions.elementary.miscellaneous import sqrt +from sympy.functions.elementary.complexes import re, im # TODO # o Airy Ai and Bi functions @@ -17,12 +18,13 @@ # o More rewriting. # o Add solvers to ode.py (or rather add solvers for the hypergeometric equation). + class BesselBase(Function): """ Abstract base class for bessel-type functions. This class is meant to reduce code duplication. - All bessel type functions can 1) be differentiated, and the derivatives + All Bessel type functions can 1) be differentiated, and the derivatives expressed in terms of similar functions and 2) be rewritten in terms of other bessel-type functions. @@ -48,13 +50,31 @@ if argindex != 2: raise ArgumentIndexError(self, argindex) return self._b/2 * self.__class__(self.order - 1, self.argument) \ - - self._a/2 * self.__class__(self.order + 1, self.argument) \ + - self._a/2 * self.__class__(self.order + 1, self.argument) \ + + def _eval_conjugate(self): + z = self.argument + if (z.is_real and z.is_negative) is False: + return self.__class__(self.order.conjugate(), z.conjugate()) + + def _eval_expand_func(self, **hints): + nu, z, f = self.order, self.argument, self.__class__ + if nu.is_real: + if (nu - 1).is_positive: + return (-self._a*self._b*f(nu - 2, z)._eval_expand_func() + + 2*self._a*(nu - 1)*f(nu - 1, z)._eval_expand_func()/z) + elif (nu + 1).is_negative: + return (2*self._b*(nu + 1)*f(nu + 1, z)._eval_expand_func()/z - + self._a*self._b*f(nu + 2, z)._eval_expand_func()) + return self + + class besselj(BesselBase): r""" Bessel function of the first kind. - The Bessel J function of order :math:`\nu` is defined to be the function + The Bessel `J` function of order `\nu` is defined to be the function satisfying Bessel's differential equation .. math :: @@ -75,7 +95,7 @@ Examples ======== - Create a bessel function object: + Create a Bessel function object: >>> from sympy import besselj, jn >>> from sympy.abc import z, n @@ -86,7 +106,7 @@ >>> b.diff(z) besselj(n - 1, z)/2 - besselj(n + 1, z)/2 - Rewrite in terms of spherical bessel functions: + Rewrite in terms of spherical Bessel functions: >>> b.rewrite(jn) sqrt(2)*sqrt(z)*jn(n - 1/2, z)/sqrt(pi) @@ -103,36 +123,42 @@ bessely, besseli, besselk - References ========== - - Abramowitz, Milton; Stegun, Irene A., eds. (1965), "Chapter 9", - Handbook of Mathematical Functions with Formulas, Graphs, and Mathematical - Tables - - Luke, Y. L. (1969), The Special Functions and Their Approximations, - Volume 1 - - http://en.wikipedia.org/wiki/Bessel_function + .. [1] Abramowitz, Milton; Stegun, Irene A., eds. (1965), "Chapter 9", + Handbook of Mathematical Functions with Formulas, Graphs, and + Mathematical Tables + .. [2] Luke, Y. L. (1969), The Special Functions and Their + Approximations, Volume 1 + .. [3] http://en.wikipedia.org/wiki/Bessel_function + .. [4] http://functions.wolfram.com/Bessel-TypeFunctions/BesselJ/ """ _a = S.One _b = S.One - def _eval_rewrite_as_jn(self, nu, z, expand=False): - jn_part = jn(nu - S('1/2'), self.argument) - if expand: - jn_part = jn_part._eval_expand_func() - return sqrt(2*z/pi) * jn_part - @classmethod def eval(cls, nu, z): - if nu.is_Integer: - if nu < 0: - return S(-1)**nu*besselj(-nu, z) - if z.could_extract_minus_sign(): - return S(-1)**nu*besselj(nu, -z) + if z.is_zero: + if nu.is_zero: + return S.One + elif (nu.is_integer and nu.is_zero is False) or re(nu).is_positive: + return S.Zero + elif re(nu).is_negative and not (nu.is_integer is True): + return S.ComplexInfinity + elif nu.is_imaginary: + return S.NaN + if z is S.Infinity or (z is S.NegativeInfinity): + return S.Zero + + if z.could_extract_minus_sign(): + return (z)**nu*(-z)**(-nu)*besselj(nu, -z) + if nu.is_integer: + if nu.could_extract_minus_sign(): + return S(-1)**(-nu)*besselj(-nu, z) newz = z.extract_multiplicatively(I) - if newz: # NOTE we don't want to change the function if z==0 + if newz: # NOTE we don't want to change the function if z==0 return I**(nu)*besseli(nu, newz) # branch handling: @@ -149,20 +175,23 @@ if nu != nnu: return besselj(nnu, z) - def _eval_expand_func(self, **hints): - if self.order.is_Rational and self.order.q == 2: - return self._eval_rewrite_as_jn(*self.args, **{'expand':True}) - return self - def _eval_rewrite_as_besseli(self, nu, z): from sympy import polar_lift, exp return exp(I*pi*nu/2)*besseli(nu, polar_lift(-I)*z) + def _eval_rewrite_as_bessely(self, nu, z): + if nu.is_integer is False: + return csc(pi*nu)*bessely(-nu, z) - cot(pi*nu)*bessely(nu, z) + + def _eval_rewrite_as_jn(self, nu, z): + return sqrt(2*z/pi)*jn(nu - S.Half, self.argument) + + class bessely(BesselBase): r""" Bessel function of the second kind. - The Bessel Y function of order :math:`\nu` is defined as + The Bessel `Y` function of order `\nu` is defined as .. math :: Y_\nu(z) = \lim_{\mu \to \nu} \frac{J_\mu(z) \cos(\pi \mu) @@ -189,27 +218,44 @@ besselj, besseli, besselk + References + ========== + + .. [1] http://functions.wolfram.com/Bessel-TypeFunctions/BesselY/ + """ _a = S.One _b = S.One - def _eval_rewrite_as_yn(self, nu, z, expand=False): - yn_part = yn(nu - S('1/2'), self.argument) - if expand: - yn_part = yn_part._eval_expand_func() - return sqrt(2*z/pi) * yn_part - @classmethod def eval(cls, nu, z): - if nu.is_Integer: - if nu < 0: - return S(-1)**nu*bessely(-nu, z) + if z.is_zero: + if nu.is_zero: + return S.NegativeInfinity + elif re(nu).is_zero is False: + return S.ComplexInfinity + elif re(nu).is_zero: + return S.NaN + if z is S.Infinity or z is S.NegativeInfinity: + return S.Zero + + if nu.is_integer: + if nu.could_extract_minus_sign(): + return S(-1)**(-nu)*bessely(-nu, z) + + def _eval_rewrite_as_besselj(self, nu, z): + if nu.is_integer is False: + return csc(pi*nu)*(cos(pi*nu)*besselj(nu, z) - besselj(-nu, z)) + + def _eval_rewrite_as_besseli(self, nu, z): + aj = self._eval_rewrite_as_besselj(*self.args) + if aj: + return aj.rewrite(besseli) + + def _eval_rewrite_as_yn(self, nu, z): + return sqrt(2*z/pi) * yn(nu - S.Half, self.argument) - def _eval_expand_func(self, **hints): - if self.order.is_Rational and self.order.q == 2: - return self._eval_rewrite_as_yn(*self.args, **{'expand':True}) - return self class besseli(BesselBase): r""" @@ -226,7 +272,7 @@ .. math :: I_\nu(z) = i^{-\nu} J_\nu(iz), - where :math:`J_\mu(z)` is the Bessel function of the first kind. + where :math:`J_\nu(z)` is the Bessel function of the first kind. Examples ======== @@ -241,6 +287,11 @@ besselj, bessely, besselk + References + ========== + + .. [1] http://functions.wolfram.com/Bessel-TypeFunctions/BesselI/ + """ _a = -S.One @@ -248,9 +299,26 @@ @classmethod def eval(cls, nu, z): - if nu.is_Integer: + if z.is_zero: + if nu.is_zero: + return S.One + elif (nu.is_integer and nu.is_zero is False) or re(nu).is_positive: + return S.Zero + elif re(nu).is_negative and not (nu.is_integer is True): + return S.ComplexInfinity + elif nu.is_imaginary: + return S.NaN + if z.is_imaginary: + if im(z) is S.Infinity or im(z) is S.NegativeInfinity: + return S.Zero + + if z.could_extract_minus_sign(): + return (z)**nu*(-z)**(-nu)*besseli(nu, -z) + if nu.is_integer: + if nu.could_extract_minus_sign(): + return besseli(-nu, z) newz = z.extract_multiplicatively(I) - if newz: # NOTE we don't want to change the function if z==0 + if newz: # NOTE we don't want to change the function if z==0 return I**(-nu)*besselj(nu, -newz) # branch handling: @@ -271,6 +339,15 @@ from sympy import polar_lift, exp return exp(-I*pi*nu/2)*besselj(nu, polar_lift(I)*z) + def _eval_rewrite_as_bessely(self, nu, z): + aj = self._eval_rewrite_as_besselj(*self.args) + if aj: + return aj.rewrite(bessely) + + def _eval_rewrite_as_jn(self, nu, z): + return self._eval_rewrite_as_besselj(*self.args).rewrite(jn) + + class besselk(BesselBase): r""" Modified Bessel function of the second kind. @@ -299,11 +376,53 @@ besselj, besseli, bessely + References + ========== + + .. [1] http://functions.wolfram.com/Bessel-TypeFunctions/BesselK/ + """ _a = S.One _b = -S.One + @classmethod + def eval(cls, nu, z): + if z.is_zero: + if nu.is_zero: + return S.Infinity + elif re(nu).is_zero is False: + return S.ComplexInfinity + elif re(nu).is_zero: + return S.NaN + if z.is_imaginary: + if im(z) is S.Infinity or im(z) is S.NegativeInfinity: + return S.Zero + + if nu.is_integer: + if nu.could_extract_minus_sign(): + return besselk(-nu, z) + + def _eval_rewrite_as_besseli(self, nu, z): + if nu.is_integer is False: + return pi*csc(pi*nu)*(besseli(-nu, z) - besseli(nu, z))/2 + + def _eval_rewrite_as_besselj(self, nu, z): + ai = self._eval_rewrite_as_besseli(*self.args) + if ai: + return ai.rewrite(besselj) + + def _eval_rewrite_as_bessely(self, nu, z): + aj = self._eval_rewrite_as_besselj(*self.args) + if aj: + return aj.rewrite(bessely) + + def _eval_rewrite_as_yn(self, nu, z): + ay = self._eval_rewrite_as_bessely(*self.args) + if ay: + return ay.rewrite(yn) + + class hankel1(BesselBase): r""" Hankel function of the first kind. @@ -331,11 +450,22 @@ hankel2, besselj, bessely + References + ========== + + .. [1] http://functions.wolfram.com/Bessel-TypeFunctions/HankelH1/ + """ _a = S.One _b = S.One + def _eval_conjugate(self): + z = self.argument + if (z.is_real and z.is_negative) is False: + return hankel2(self.order.conjugate(), z.conjugate()) + + class hankel2(BesselBase): r""" Hankel function of the second kind. @@ -364,22 +494,33 @@ hankel1, besselj, bessely + References + ========== + + .. [1] http://functions.wolfram.com/Bessel-TypeFunctions/HankelH2/ + """ _a = S.One _b = S.One + def _eval_conjugate(self): + z = self.argument + if (z.is_real and z.is_negative) is False: + return hankel1(self.order.conjugate(), z.conjugate()) + from sympy.polys.orthopolys import spherical_bessel_fn as fn + class SphericalBesselBase(BesselBase): """ - Base class for spherical bessel functions. + Base class for spherical Bessel functions. - These are thin wrappers around ordinary bessel functions, - since spherical bessel functions differ from the ordinary + These are thin wrappers around ordinary Bessel functions, + since spherical Bessel functions differ from the ordinary ones just by a slight change in order. - To use this class, define the _rewrite and _expand methods. + To use this class, define the ``_rewrite`` and ``_expand`` methods. """ def _expand(self, **hints): @@ -387,7 +528,7 @@ raise NotImplementedError('expansion') def _rewrite(self): - """ Rewrite self in terms of ordinary bessel functions. """ + """ Rewrite self in terms of ordinary Bessel functions. """ raise NotImplementedError('rewriting') def _eval_expand_func(self, **hints): @@ -403,14 +544,14 @@ if argindex != 2: raise ArgumentIndexError(self, argindex) return self.__class__(self.order - 1, self.argument) - \ - self * (self.order + 1)/self.argument + self * (self.order + 1)/self.argument class jn(SphericalBesselBase): r""" Spherical Bessel function of the first kind. - This function is a solution to the spherical bessel equation + This function is a solution to the spherical Bessel equation .. math :: z^2 \frac{\mathrm{d}^2 w}{\mathrm{d}z^2} @@ -459,13 +600,14 @@ def _expand(self, **hints): n = self.order z = self.argument - return fn(n, z) * sin(z) + (-1)**(n+1) * fn(-n-1, z) * cos(z) + return fn(n, z) * sin(z) + (-1)**(n + 1) * fn(-n - 1, z) * cos(z) + class yn(SphericalBesselBase): r""" Spherical Bessel function of the second kind. - This function is another solution to the spherical bessel equation, and + This function is another solution to the spherical Bessel equation, and linearly independent from :math:`j_n`. It can be defined as .. math :: @@ -503,8 +645,8 @@ def _expand(self, **hints): n = self.order z = self.argument - return (-1)**(n+1) * \ - (fn(-n-1, z) * sin(z) + (-1)**(-n) * fn(n, z) * cos(z)) + return (-1)**(n + 1) * \ + (fn(-n - 1, z) * sin(z) + (-1)**(-n) * fn(n, z) * cos(z)) def jn_zeros(n, k, method="sympy", dps=15): @@ -513,13 +655,17 @@ This returns an array of zeros of jn up to the k-th zero. - * method = "sympy": uses mpmath besseljzero - * method = "scipy": uses the SciPy's sph_jn and newton to find all + * method = "sympy": uses :func:`mpmath.besseljzero` + * method = "scipy": uses the + `SciPy's sph_jn `_ + and + `newton `_ + to find all roots, which is faster than computing the zeros using a general numerical solver, but it requires SciPy and only works with low - precision floating point numbers. [the function used with + precision floating point numbers. [The function used with method="sympy" is a recent addition to mpmath, before that a general - solver was used] + solver was used.] Examples ======== @@ -541,14 +687,15 @@ from sympy import Expr prec = dps_to_prec(dps) return [Expr._from_mpmath(besseljzero(S(n + 0.5)._to_mpmath(prec), - int(k)), prec) \ + int(k)), prec) for k in range(1, k + 1)] elif method == "scipy": from scipy.special import sph_jn from scipy.optimize import newton - f = lambda x: sph_jn(n, x)[0][-1] + f = lambda x: sph_jn(n, x)[0][-1] else: raise NotImplementedError("Unknown method.") + def solver(f, x): if method == "scipy": root = newton(f, x) @@ -557,12 +704,12 @@ return root # we need to approximate the position of the first root: - root = n+pi + root = n + pi # determine the first root exactly: root = solver(f, root) roots = [root] - for i in range(k-1): + for i in range(k - 1): # estimate the position of the next root using the last root + pi: - root = solver(f, root+pi) + root = solver(f, root + pi) roots.append(root) return roots diff -Nru python3-sympy-0.7.2/sympy/functions/special/bsplines.py python3-sympy-0.7.3/sympy/functions/special/bsplines.py --- python3-sympy-0.7.2/sympy/functions/special/bsplines.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/functions/special/bsplines.py 2013-07-13 17:53:32.000000000 +0000 @@ -7,26 +7,30 @@ def _add_splines(c, b1, d, b2): """Construct c*b1 + d*b2.""" if b1 == S.Zero or c == S.Zero: - return expand(piecewise_fold(d*b2)) - if b2 == S.Zero or d == S.Zero: - return expand(piecewise_fold(c*b1)) - new_args = [] - n_intervals = len(b1.args) - assert(n_intervals==len(b2.args)) - new_args.append((expand(c*b1.args[0].expr), b1.args[0].cond)) - for i in range(1, n_intervals-1): - new_args.append(( - expand(c*b1.args[i].expr+d*b2.args[i-1].expr), - b1.args[i].cond - )) - new_args.append((expand(d*b2.args[-2].expr), b2.args[-2].cond)) - new_args.append(b2.args[-1]) - return Piecewise(*new_args) + rv = piecewise_fold(d*b2) + elif b2 == S.Zero or d == S.Zero: + rv = piecewise_fold(c*b1) + else: + new_args = [] + n_intervals = len(b1.args) + assert(n_intervals == len(b2.args)) + new_args.append((c*b1.args[0].expr, b1.args[0].cond)) + for i in range(1, n_intervals - 1): + new_args.append(( + c*b1.args[i].expr + d*b2.args[i - 1].expr, + b1.args[i].cond + )) + new_args.append((d*b2.args[-2].expr, b2.args[-2].cond)) + new_args.append(b2.args[-1]) + rv = Piecewise(*new_args) + + return rv.expand() + def bspline_basis(d, knots, n, x, close=True): - """The n-th B-spline at x of degree d with knots. + """The `n`-th B-spline at `x` of degree `d` with knots. - B-Splines are piecewise polynomials of degree d [1]. They are defined on + B-Splines are piecewise polynomials of degree `d` [1]_. They are defined on a set of knots, which is a sequence of integers or floats. The 0th degree splines have a value of one on a single interval: @@ -38,8 +42,8 @@ >>> bspline_basis(d, knots, 0, x) Piecewise((1, And(x <= 1, x >= 0)), (0, True)) - For a given (d, knots) there are len(knots)-d-1 B-splines defined, that - are indexed by n (starting at 0). + For a given ``(d, knots)`` there are ``len(knots)-d-1`` B-splines defined, that + are indexed by ``n`` (starting at 0). Here is an example of a cubic B-spline: @@ -77,33 +81,35 @@ References ========== - [1] http://en.wikipedia.org/wiki/B-spline + .. [1] http://en.wikipedia.org/wiki/B-spline """ knots = [sympify(k) for k in knots] d = int(d) n = int(n) n_knots = len(knots) - n_intervals = n_knots-1 - if n+d+1 > n_intervals: - raise ValueError('n+d+1 must not exceed len(knots)-1') - if d==0: + n_intervals = n_knots - 1 + if n + d + 1 > n_intervals: + raise ValueError('n + d + 1 must not exceed len(knots) - 1') + if d == 0: result = Piecewise( - (S.One, Interval(knots[n], knots[n+1], False, not close).contains(x)), + (S.One, Interval(knots[n], knots[n + 1], False, + not close).contains(x)), (0, True) ) elif d > 0: - denom = knots[n+d+1] - knots[n+1] + denom = knots[n + d + 1] - knots[n + 1] if denom != S.Zero: - B = (knots[n+d+1] - x)/denom - b2 = bspline_basis(d-1, knots, n+1, x, close) + B = (knots[n + d + 1] - x)/denom + b2 = bspline_basis(d - 1, knots, n + 1, x, close) else: b2 = B = S.Zero - denom = knots[n+d] - knots[n] + denom = knots[n + d] - knots[n] if denom != S.Zero: A = (x - knots[n])/denom - b1 = bspline_basis(d-1, knots, n, x, close and (B == S.Zero or b2 == S.Zero)) + b1 = bspline_basis( + d - 1, knots, n, x, close and (B == S.Zero or b2 == S.Zero)) else: b1 = A = S.Zero @@ -112,12 +118,13 @@ raise ValueError('degree must be non-negative: %r' % n) return result + def bspline_basis_set(d, knots, x): - """Return the len(knots)-d-1 B-splines at x of degree d with knots. + """Return the ``len(knots)-d-1`` B-splines at ``x`` of degree ``d`` with ``knots``. This function returns a list of Piecewise polynomials that are the - len(knots)-d-1 B-splines of degree d for the given knots. This function - calls bspline_basis(d, knots, n, x) for different values of n. + ``len(knots)-d-1`` B-splines of degree ``d`` for the given knots. This function + calls ``bspline_basis(d, knots, n, x)`` for different values of ``n``. Examples ======== @@ -142,5 +149,5 @@ bsplines_basis """ - n_splines = len(knots)-d-1 + n_splines = len(knots) - d - 1 return [bspline_basis(d, knots, i, x) for i in range(n_splines)] diff -Nru python3-sympy-0.7.2/sympy/functions/special/delta_functions.py python3-sympy-0.7.3/sympy/functions/special/delta_functions.py --- python3-sympy-0.7.2/sympy/functions/special/delta_functions.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/functions/special/delta_functions.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,11 +1,15 @@ from sympy.core import S, sympify, diff from sympy.core.function import Function, ArgumentIndexError +from sympy.core.relational import Eq from sympy.polys.polyerrors import PolynomialError from sympy.functions.elementary.complexes import im +from sympy.functions.elementary.piecewise import Piecewise ############################################################################### ################################ DELTA FUNCTION ############################### ############################################################################### + + class DiracDelta(Function): """ The DiracDelta function and its derivatives. @@ -33,12 +37,14 @@ References ========== - http://mathworld.wolfram.com/DeltaFunction.html + .. [1] http://mathworld.wolfram.com/DeltaFunction.html """ nargs = (1, 2) - def fdiff(self, argindex = 1): + is_real = True + + def fdiff(self, argindex=1): if argindex == 1: #I didn't know if there is a better way to handle default arguments k = 0 @@ -53,14 +59,12 @@ k = sympify(k) if not k.is_Integer or k.is_negative: raise ValueError("Error: the second argument of DiracDelta must be \ - a non-negative integer, %s given instead." %(k,)) + a non-negative integer, %s given instead." % (k,)) arg = sympify(arg) if arg is S.NaN: return S.NaN if arg.is_positive or arg.is_negative: return S.Zero - elif arg.is_zero: - return S.Infinity def simplify(self, x): """simplify(self, x) @@ -94,18 +98,17 @@ """ from sympy.polys.polyroots import roots - if not self.args[0].has(x) or (len(self.args)>1 and self.args[1] != 0 ): + if not self.args[0].has(x) or (len(self.args) > 1 and self.args[1] != 0 ): return self try: - argroots = roots(self.args[0], x, \ - multiple=True) + argroots = roots(self.args[0], x, multiple=True) result = 0 valid = True darg = diff(self.args[0], x) for r in argroots: #should I care about multiplicities of roots? - if r.is_real and not darg.subs(x,r).is_zero: - result = result + DiracDelta(x - r)/abs(darg.subs(x,r)) + if r.is_real is not False and not darg.subs(x, r).is_zero: + result += DiracDelta(x - r)/abs(darg.subs(x, r)) else: valid = False break @@ -115,7 +118,7 @@ pass return self - def is_simple(self,x): + def is_simple(self, x): """is_simple(self, x) Tells whether the argument(args[0]) of DiracDelta is a linear @@ -153,13 +156,11 @@ return p.degree() == 1 return False - def _eval_conjugate(self): - return self - ############################################################################### ############################## HEAVISIDE FUNCTION ############################# ############################################################################### + class Heaviside(Function): """Heaviside Piecewise function @@ -202,12 +203,14 @@ References ========== - http://mathworld.wolfram.com/HeavisideStepFunction.html + .. [1] http://mathworld.wolfram.com/HeavisideStepFunction.html """ nargs = 1 - def fdiff(self, argindex = 1): + is_real = True + + def fdiff(self, argindex=1): if argindex == 1: # property number 1 return DiracDelta(self.args[0]) @@ -227,3 +230,7 @@ return S.Half elif arg.is_positive: return S.One + + def _eval_rewrite_as_Piecewise(self, arg): + if arg.is_real: + return Piecewise((1, arg > 0), (S(1)/2, Eq(arg, 0)), (0, True)) diff -Nru python3-sympy-0.7.2/sympy/functions/special/elliptic_integrals.py python3-sympy-0.7.3/sympy/functions/special/elliptic_integrals.py --- python3-sympy-0.7.2/sympy/functions/special/elliptic_integrals.py 1970-01-01 00:00:00.000000000 +0000 +++ python3-sympy-0.7.3/sympy/functions/special/elliptic_integrals.py 2013-07-13 17:53:32.000000000 +0000 @@ -0,0 +1,350 @@ +""" Elliptic integrals. """ + +from sympy.core import S, pi, I +from sympy.core.function import Function, ArgumentIndexError +from sympy.functions.elementary.hyperbolic import atanh +from sympy.functions.elementary.trigonometric import sin, tan +from sympy.functions.elementary.miscellaneous import sqrt +from sympy.functions.elementary.complexes import sign +from sympy.functions.special.hyper import hyper, meijerg +from sympy.functions.special.gamma_functions import gamma + +class elliptic_k(Function): + r""" + The complete elliptic integral of the first kind, defined by + + .. math:: K(z) = F\left(\tfrac{\pi}{2}\middle| z\right) + + where `F\left(z\middle| m\right)` is the Legendre incomplete + elliptic integral of the first kind. + + The function `K(z)` is a single-valued function on the complex + plane with branch cut along the interval `(1, \infty)`. + + Examples + ======== + + >>> from sympy import elliptic_k, I, pi + >>> from sympy.abc import z + >>> elliptic_k(0) + pi/2 + >>> elliptic_k(1.0 + I) + 1.50923695405127 + 0.625146415202697*I + + References + ========== + + .. [1] http://en.wikipedia.org/wiki/Elliptic_integrals + .. [2] http://functions.wolfram.com/EllipticIntegrals/EllipticK + + See Also + ======== + + elliptic_f + """ + + nargs = 1 + + @classmethod + def eval(cls, z): + if z is S.Zero: + return pi/2 + elif z is S.Half: + return 8*pi**(S(3)/2)/gamma(-S(1)/4)**2 + elif z is S.One: + return S.ComplexInfinity + elif z is S.NegativeOne: + return gamma(S(1)/4)**2/(4*sqrt(2*pi)) + elif z in (S.Infinity, S.NegativeInfinity, I*S.Infinity, + I*S.NegativeInfinity, S.ComplexInfinity): + return S.Zero + + def fdiff(self, argindex=1): + z = self.args[0] + return (elliptic_e(z) - (1 - z)*elliptic_k(z))/(2*z*(1 - z)) + + def _eval_conjugate(self): + z = self.args[0] + if (z.is_real and (z - 1).is_positive) is False: + return self.func(z.conjugate()) + + def _eval_rewrite_as_hyper(self, z): + return (pi/2)*hyper((S.Half, S.Half), (S.One,), z) + + def _eval_rewrite_as_meijerg(self, z): + return meijerg(((S.Half, S.Half), []), ((S.Zero,), (S.Zero,)), -z)/2 + + +class elliptic_f(Function): + r""" + The Legendre incomplete elliptic integral of the first + kind, defined by + + .. math:: F\left(z\middle| m\right) = + \int_0^z \frac{dt}{\sqrt{1 - m \sin^2 t}} + + This function reduces to a complete elliptic integral of + the first kind, `K(m)`, when `z = \pi/2`. + + Examples + ======== + + >>> from sympy import elliptic_f, I, O + >>> from sympy.abc import z, m + >>> elliptic_f(z, m).series(z) + z + z**5*(3*m**2/40 - m/30) + m*z**3/6 + O(z**6) + >>> elliptic_f(3.0 + I/2, 1.0 + I) + 2.909449841483 + 1.74720545502474*I + + References + ========== + + .. [1] http://en.wikipedia.org/wiki/Elliptic_integrals + .. [2] http://functions.wolfram.com/EllipticIntegrals/EllipticF + + See Also + ======== + + elliptic_k + """ + + nargs = 2 + + @classmethod + def eval(cls, z, m): + k = 2*z/pi + if m.is_zero: + return z + elif z.is_zero: + return S.Zero + elif k.is_integer: + return k*elliptic_k(m) + elif m in (S.Infinity, S.NegativeInfinity): + return S.Zero + elif z.could_extract_minus_sign(): + return -elliptic_f(-z, m) + + def fdiff(self, argindex=1): + z, m = self.args + fm = sqrt(1 - m*sin(z)**2) + if argindex == 1: + return 1/fm + elif argindex == 2: + return (elliptic_e(z, m)/(2*m*(1 - m)) - elliptic_f(z, m)/(2*m) - + sin(2*z)/(4*(1 - m)*fm)) + raise ArgumentIndexError(self, argindex) + + def _eval_conjugate(self): + z, m = self.args + if (m.is_real and (m - 1).is_positive) is False: + return self.func(z.conjugate(), m.conjugate()) + + +class elliptic_e(Function): + r""" + Called with two arguments `z` and `m`, evaluates the + incomplete elliptic integral of the second kind, defined by + + .. math:: E\left(z\middle| m\right) = \int_0^z \sqrt{1 - m \sin^2 t} dt + + Called with a single argument `z`, evaluates the Legendre complete + elliptic integral of the second kind + + .. math:: E(z) = E\left(\tfrac{\pi}{2}\middle| z\right) + + The function `E(z)` is a single-valued function on the complex + plane with branch cut along the interval `(1, \infty)`. + + Examples + ======== + + >>> from sympy import elliptic_e, I, pi, O + >>> from sympy.abc import z, m + >>> elliptic_e(z, m).series(z) + z + z**5*(-m**2/40 + m/30) - m*z**3/6 + O(z**6) + >>> elliptic_e(1 + I, 2 - I/2).n() + 1.55203744279187 + 0.290764986058437*I + >>> elliptic_e(0) + pi/2 + >>> elliptic_e(2.0 - I) + 0.991052601328069 + 0.81879421395609*I + + References + ========== + + .. [1] http://en.wikipedia.org/wiki/Elliptic_integrals + .. [2] http://functions.wolfram.com/EllipticIntegrals/EllipticE2 + .. [3] http://functions.wolfram.com/EllipticIntegrals/EllipticE + """ + + nargs = (1, 2) + + @classmethod + def eval(cls, *args): + if len(args) == 2: + z, m = args + k = 2*z/pi + if m.is_zero: + return z + if z.is_zero: + return S.Zero + elif k.is_integer: + return k*elliptic_e(m) + elif m in (S.Infinity, S.NegativeInfinity): + return S.ComplexInfinity + elif z.could_extract_minus_sign(): + return -elliptic_e(-z, m) + else: + z = args[0] + if z.is_zero: + return pi/2 + elif z is S.One: + return S.One + elif z is S.Infinity: + return I*S.Infinity + elif z is S.NegativeInfinity: + return S.Infinity + elif z is S.ComplexInfinity: + return S.ComplexInfinity + + def fdiff(self, argindex=1): + if len(self.args) == 2: + z, m = self.args + if argindex == 1: + return sqrt(1 - m*sin(z)**2) + elif argindex == 2: + return (elliptic_e(z, m) - elliptic_f(z, m))/(2*m) + else: + z = self.args[0] + if argindex == 1: + return (elliptic_e(z) - elliptic_k(z))/(2*z) + raise ArgumentIndexError(self, argindex) + + def _eval_conjugate(self): + z, m = self.args + if (m.is_real and (m - 1).is_positive) is False: + return self.func(z.conjugate(), m.conjugate()) + + def _eval_rewrite_as_hyper(self, *args): + if len(args) == 1: + z = args[0] + return (pi/2)*hyper((-S.Half, S.Half), (S.One,), z) + + def _eval_rewrite_as_meijerg(self, *args): + if len(args) == 1: + z = args[0] + return -meijerg(((S.Half, S(3)/2), []), \ + ((S.Zero,), (S.Zero,)), -z)/4 + + +class elliptic_pi(Function): + r""" + Called with three arguments `n`, `z` and `m`, evaluates the + Legendre incomplete elliptic integral of the third kind, defined by + + .. math:: \Pi\left(n; z\middle| m\right) = \int_0^z \frac{dt} + {\left(1 - n \sin^2 t\right) \sqrt{1 - m \sin^2 t}} + + Called with two arguments `n` and `m`, evaluates the complete + elliptic integral of the third kind: + + .. math:: \Pi\left(n\middle| m\right) = + \Pi\left(n; \tfrac{\pi}{2}\middle| m\right) + + Examples + ======== + + >>> from sympy import elliptic_pi, I, pi, O, S + >>> from sympy.abc import z, n, m + >>> elliptic_pi(n, z, m).series(z) + z + z**3*(m/6 + n/3) + z**5*(3*m**2/40 + m*n/10 - m/30 + n**2/5 - n/15) + O(z**6) + >>> elliptic_pi(0.5 + I, 1.0 - I, 1.2) + 2.50232379629182 - 0.760939574180767*I + >>> elliptic_pi(0, 0) + pi/2 + >>> elliptic_pi(1.0 - I/3, 2.0 + I) + 3.29136443417283 + 0.32555634906645*I + + References + ========== + + .. [1] http://en.wikipedia.org/wiki/Elliptic_integrals + .. [2] http://functions.wolfram.com/EllipticIntegrals/EllipticPi3 + .. [3] http://functions.wolfram.com/EllipticIntegrals/EllipticPi + """ + + nargs = (2, 3) + + @classmethod + def eval(cls, *args): + if len(args) == 3: + n, z, m = args + k = 2*z/pi + if n == S.Zero: + return elliptic_f(z, m) + elif n == S.One: + return (elliptic_f(z, m) + + (sqrt(1 - m*sin(z)**2)*tan(z) - + elliptic_e(z, m))/(1 - m)) + elif k.is_integer: + return k*elliptic_pi(n, m) + elif m == S.Zero: + return atanh(sqrt(n - 1)*tan(z))/sqrt(n - 1) + elif n == m: + return (elliptic_f(z, n) - elliptic_pi(1, z, n) + + tan(z)/sqrt(1 - n*sin(z)**2)) + elif n in (S.Infinity, S.NegativeInfinity): + return S.Zero + elif m in (S.Infinity, S.NegativeInfinity): + return S.Zero + elif z.could_extract_minus_sign(): + return -elliptic_pi(n, -z, m) + else: + n, m = args + if n == S.Zero: + return elliptic_k(m) + elif n == S.One: + return S.ComplexInfinity + elif m == S.Zero: + return pi/(2*sqrt(1 - n)) + elif m == S.One: + return -S.Infinity/sign(n - 1) + elif n == m: + return elliptic_e(n)/(1 - n) + elif n in (S.Infinity, S.NegativeInfinity): + return S.Zero + elif m in (S.Infinity, S.NegativeInfinity): + return S.Zero + + def _eval_conjugate(self): + if len(self.args) == 3: + n, z, m = self.args + if (n.is_real and (n - 1).is_positive) is False and \ + (m.is_real and (m - 1).is_positive) is False: + return self.func(n.conjugate(), z.conjugate(), m.conjugate()) + else: + n, m = self.args + return self.func(n.conjugate(), m.conjugate()) + + def fdiff(self, argindex=1): + if len(self.args) == 3: + n, z, m = self.args + fm, fn = sqrt(1 - m*sin(z)**2), 1 - n*sin(z)**2 + if argindex == 1: + return (elliptic_e(z, m) + (m - n)*elliptic_f(z, m)/n + + (n**2 - m)*elliptic_pi(n, z, m)/n - + n*fm*sin(2*z)/(2*fn))/(2*(m - n)*(n - 1)) + elif argindex == 2: + return 1/(fm*fn) + elif argindex == 3: + return (elliptic_e(z, m)/(m - 1) + + elliptic_pi(n, z, m) - + m*sin(2*z)/(2*(m - 1)*fm))/(2*(n - m)) + else: + n, m = self.args + if argindex == 1: + return (elliptic_e(m) + (m - n)*elliptic_k(m)/n + + (n**2 - m)*elliptic_pi(n, m)/n)/(2*(m - n)*(n - 1)) + elif argindex == 2: + return (elliptic_e(m)/(m - 1) + elliptic_pi(n, m))/(2*(n - m)) + raise ArgumentIndexError(self, argindex) diff -Nru python3-sympy-0.7.2/sympy/functions/special/error_functions.py python3-sympy-0.7.3/sympy/functions/special/error_functions.py --- python3-sympy-0.7.2/sympy/functions/special/error_functions.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/functions/special/error_functions.py 2013-07-13 17:53:32.000000000 +0000 @@ -4,6 +4,7 @@ from sympy.core import Add, S, C, sympify, cacheit, pi, I from sympy.core.function import Function, ArgumentIndexError from sympy.functions.elementary.miscellaneous import sqrt, root +from sympy.functions.elementary.exponential import exp, log from sympy.functions.elementary.complexes import polar_lift from sympy.functions.special.hyper import hyper, meijerg @@ -14,13 +15,15 @@ ################################ ERROR FUNCTION ############################### ############################################################################### + class erf(Function): - """ + r""" The Gauss error function. This function is defined as: - :math:`\\mathrm{erf}(x)=\\frac{2}{\\sqrt{\\pi}} \\int_0^x e^{-t^2} \\, \\mathrm{d}x` + .. math :: + \operatorname{erf}(x)=\frac{2}{\sqrt{\pi}} \int_0^x e^{-t^2} \, \mathrm{d}x. Or, in ASCII:: @@ -82,6 +85,16 @@ >>> erf(-4*I).evalf(30) -1296959.73071763923152794095062*I + See Also + ======== + + erfc: Complementary error function. + erfi: Imaginary error function. + erf2: Two-argument error function. + erfinv: Inverse error function. + erfcinv: Inverse Complementary error function. + erf2inv: Inverse two-argument error function. + References ========== @@ -92,65 +105,816 @@ """ nargs = 1 - unbranched = True + unbranched = True + + def fdiff(self, argindex=1): + if argindex == 1: + return 2*C.exp(-self.args[0]**2)/sqrt(S.Pi) + else: + raise ArgumentIndexError(self, argindex) + + @classmethod + def eval(cls, arg): + if arg.is_Number: + if arg is S.NaN: + return S.NaN + elif arg is S.Infinity: + return S.One + elif arg is S.NegativeInfinity: + return S.NegativeOne + elif arg is S.Zero: + return S.Zero + + if arg.func is erfinv: + return arg.args[0] + + if arg.func is erfcinv: + return S.One - arg.args[0] + + if arg.func is erf2inv and arg.args[0] is S.Zero: + return arg.args[1] + + # Try to pull out factors of I + t = arg.extract_multiplicatively(S.ImaginaryUnit) + if t is S.Infinity or t is S.NegativeInfinity: + return arg + + # Try to pull out factors of -1 + if arg.could_extract_minus_sign(): + return -cls(-arg) + + @staticmethod + @cacheit + def taylor_term(n, x, *previous_terms): + if n < 0 or n % 2 == 0: + return S.Zero + else: + x = sympify(x) + k = C.floor((n - 1)/S(2)) + if len(previous_terms) > 2: + return -previous_terms[-2] * x**2 * (n - 2)/(n*k) + else: + return 2*(-1)**k * x**n/(n*C.factorial(k)*sqrt(S.Pi)) + + def _eval_conjugate(self): + return self.func(self.args[0].conjugate()) + + def _eval_is_real(self): + return self.args[0].is_real + + def _eval_rewrite_as_uppergamma(self, z): + return sqrt(z**2)/z*(S.One - C.uppergamma(S.Half, z**2)/sqrt(S.Pi)) + + def _eval_rewrite_as_fresnels(self, z): + arg = (S.One - S.ImaginaryUnit)*z/sqrt(pi) + return (S.One + S.ImaginaryUnit)*(fresnelc(arg) - I*fresnels(arg)) + + def _eval_rewrite_as_fresnelc(self, z): + arg = (S.One - S.ImaginaryUnit)*z/sqrt(pi) + return (S.One + S.ImaginaryUnit)*(fresnelc(arg) - I*fresnels(arg)) + + def _eval_rewrite_as_meijerg(self, z): + return z/sqrt(pi)*meijerg([S.Half], [], [0], [-S.Half], z**2) + + def _eval_rewrite_as_hyper(self, z): + return 2*z/sqrt(pi)*hyper([S.Half], [3*S.Half], -z**2) + + def _eval_rewrite_as_expint(self, z): + return sqrt(z**2)/z - z*expint(S.Half, z**2)/sqrt(S.Pi) + + def _eval_rewrite_as_tractable(self, z): + return S.One - _erfs(z)*C.exp(-z**2) + + def _eval_rewrite_as_erfc(self, z): + return S.One - erfc(z) + + def _eval_rewrite_as_erfi(self, z): + return -I*erfi(I*z) + + def _eval_as_leading_term(self, x): + arg = self.args[0].as_leading_term(x) + + if x in arg.free_symbols and C.Order(1, x).contains(arg): + return 2*x/sqrt(pi) + else: + return self.func(arg) + + def as_real_imag(self, deep=True, **hints): + if self.args[0].is_real: + if deep: + hints['complex'] = False + return (self.expand(deep, **hints), S.Zero) + else: + return (self, S.Zero) + if deep: + x, y = self.args[0].expand(deep, **hints).as_real_imag() + else: + x, y = self.args[0].as_real_imag() + + sq = -y**2/x**2 + re = S.Half*(self.func(x + x*sqrt(sq)) + self.func(x - x*sqrt(sq))) + im = x/(2*y) * sqrt(sq) * (self.func(x - x*sqrt(sq)) - + self.func(x + x*sqrt(sq))) + return (re, im) + +class erfc(Function): + r""" + Complementary Error Function. The function is defined as: + + :math:`\mathrm{erfc}(x) = \frac{2}{\sqrt{\pi}} \int_x^\infty e^{-t^2} \mathrm{d}t` + + Examples + ======== + + >>> from sympy import I, oo, erfc + >>> from sympy.abc import z + + Several special values are known: + + >>> erfc(0) + 1 + >>> erfc(oo) + 0 + >>> erfc(-oo) + 2 + >>> erfc(I*oo) + -oo*I + >>> erfc(-I*oo) + oo*I + + The error function obeys the mirror symmetry: + + >>> from sympy import conjugate + >>> conjugate(erfc(z)) + erfc(conjugate(z)) + + Differentiation with respect to z is supported: + + >>> from sympy import diff + >>> diff(erfc(z), z) + -2*exp(-z**2)/sqrt(pi) + + It also follows + + >>> erfc(-z) + -erfc(z) + 2 + + We can numerically evaluate the complementary error function to arbitrary precision + on the whole complex plane: + + >>> erfc(4).evalf(30) + 0.0000000154172579002800188521596734869 + + >>> erfc(4*I).evalf(30) + 1.0 - 1296959.73071763923152794095062*I + + See Also + ======== + + erf: Gaussian error function. + erfi: Imaginary error function. + erf2: Two-argument error function. + erfinv: Inverse error function. + erfcinv: Inverse Complementary error function. + erf2inv: Inverse two-argument error function. + + References + ========== + + .. [1] http://en.wikipedia.org/wiki/Error_function + .. [2] http://dlmf.nist.gov/7 + .. [3] http://mathworld.wolfram.com/Erfc.html + .. [4] http://functions.wolfram.com/GammaBetaErf/Erfc + """ + + nargs = 1 + unbranched = True + + def fdiff(self, argindex=1): + if argindex == 1: + return -2*C.exp(-self.args[0]**2)/sqrt(S.Pi) + else: + raise ArgumentIndexError(self, argindex) + + @classmethod + def eval(cls, arg): + if arg.is_Number: + if arg is S.NaN: + return S.NaN + elif arg is S.Infinity: + return S.Zero + elif arg is S.Zero: + return S.One + + if arg.func is erfinv: + return S.One - arg.args[0] + + if arg.func is erfcinv: + return arg.args[0] + + # Try to pull out factors of I + t = arg.extract_multiplicatively(S.ImaginaryUnit) + if t is S.Infinity or t is S.NegativeInfinity: + return -arg + + # Try to pull out factors of -1 + if arg.could_extract_minus_sign(): + return S(2) - cls(-arg) + + @staticmethod + @cacheit + def taylor_term(n, x, *previous_terms): + if n == 0: + return S.One + elif n < 0 or n % 2 == 0: + return S.Zero + else: + x = sympify(x) + k = C.floor((n - 1)/S(2)) + if len(previous_terms) > 2: + return -previous_terms[-2] * x**2 * (n - 2)/(n*k) + else: + return -2*(-1)**k * x**n/(n*C.factorial(k)*sqrt(S.Pi)) + + def _eval_conjugate(self): + return self.func(self.args[0].conjugate()) + + def _eval_is_real(self): + return self.args[0].is_real + + def _eval_rewrite_as_tractable(self, z): + return self.rewrite(erf).rewrite("tractable", deep=True) + + def _eval_rewrite_as_erf(self, z): + return S.One - erf(z) + + def _eval_rewrite_as_erfi(self, z): + return S.One + I*erfi(I*z) + + def _eval_rewrite_as_fresnels(self, z): + arg = (S.One - S.ImaginaryUnit)*z/sqrt(pi) + return S.One - (S.One + S.ImaginaryUnit)*(fresnelc(arg) - I*fresnels(arg)) + + def _eval_rewrite_as_fresnelc(self, z): + arg = (S.One-S.ImaginaryUnit)*z/sqrt(pi) + return S.One - (S.One + S.ImaginaryUnit)*(fresnelc(arg) - I*fresnels(arg)) + + def _eval_rewrite_as_meijerg(self, z): + return S.One - z/sqrt(pi)*meijerg([S.Half], [], [0], [-S.Half], z**2) + + def _eval_rewrite_as_hyper(self, z): + return S.One - 2*z/sqrt(pi)*hyper([S.Half], [3*S.Half], -z**2) + + def _eval_rewrite_as_uppergamma(self, z): + return S.One - sqrt(z**2)/z*(S.One - C.uppergamma(S.Half, z**2)/sqrt(S.Pi)) + + def _eval_rewrite_as_expint(self, z): + return S.One - sqrt(z**2)/z + z*expint(S.Half, z**2)/sqrt(S.Pi) + + def _eval_as_leading_term(self, x): + arg = self.args[0].as_leading_term(x) + + if x in arg.free_symbols and C.Order(1, x).contains(arg): + return S.One + else: + return self.func(arg) + + def as_real_imag(self, deep=True, **hints): + if self.args[0].is_real: + if deep: + hints['complex'] = False + return (self.expand(deep, **hints), S.Zero) + else: + return (self, S.Zero) + if deep: + x, y = self.args[0].expand(deep, **hints).as_real_imag() + else: + x, y = self.args[0].as_real_imag() + + sq = -y**2/x**2 + re = S.Half*(self.func(x + x*sqrt(sq)) + self.func(x - x*sqrt(sq))) + im = x/(2*y) * sqrt(sq) * (self.func(x - x*sqrt(sq)) - + self.func(x + x*sqrt(sq))) + return (re, im) + +class erfi(Function): + r""" + Imaginary error function. The function erfi is defined as: + + :math:`\mathrm{erfi}(x) = \frac{2}{\sqrt{\pi}} \int_0^x e^{t^2} \mathrm{d}t` + + Examples + ======== + + >>> from sympy import I, oo, erfi + >>> from sympy.abc import z + + Several special values are known: + + >>> erfi(0) + 0 + >>> erfi(oo) + oo + >>> erfi(-oo) + -oo + >>> erfi(I*oo) + I + >>> erfi(-I*oo) + -I + + In general one can pull out factors of -1 and I from the argument: + + >>> erfi(-z) + -erfi(z) + + >>> from sympy import conjugate + >>> conjugate(erfi(z)) + erfi(conjugate(z)) + + Differentiation with respect to z is supported: + + >>> from sympy import diff + >>> diff(erfi(z), z) + 2*exp(z**2)/sqrt(pi) + + We can numerically evaluate the imaginary error function to arbitrary precision + on the whole complex plane: + + >>> erfi(2).evalf(30) + 18.5648024145755525987042919132 + + >>> erfi(-2*I).evalf(30) + -0.995322265018952734162069256367*I + + See Also + ======== + + erf: Gaussian error function. + erfc: Complementary error function. + erf2: Two-argument error function. + erfinv: Inverse error function. + erfcinv: Inverse Complementary error function. + erf2inv: Inverse two-argument error function. + + References + ========== + + .. [1] http://en.wikipedia.org/wiki/Error_function + .. [2] http://mathworld.wolfram.com/Erfi.html + .. [3] http://functions.wolfram.com/GammaBetaErf/Erfi + """ + + nargs = 1 + unbranched = True + + def fdiff(self, argindex=1): + if argindex == 1: + return 2*C.exp(self.args[0]**2)/sqrt(S.Pi) + else: + raise ArgumentIndexError(self, argindex) + + @classmethod + def eval(cls, z): + if z.is_Number: + if z is S.NaN: + return S.NaN + elif z is S.Zero: + return S.Zero + elif z is S.Infinity: + return S.Infinity + + # Try to pull out factors of -1 + if z.could_extract_minus_sign(): + return -cls(-z) + + # Try to pull out factors of I + nz = z.extract_multiplicatively(I) + if nz is not None: + if nz is S.Infinity: + return I + if nz.func is erfinv: + return I*nz.args[0] + if nz.func is erfcinv: + return I*(S.One - nz.args[0]) + if nz.func is erf2inv and nz.args[0] is S.Zero: + return I*nz.args[1] + + @staticmethod + @cacheit + def taylor_term(n, x, *previous_terms): + if n < 0 or n % 2 == 0: + return S.Zero + else: + x = sympify(x) + k = C.floor((n - 1)/S(2)) + if len(previous_terms) > 2: + return previous_terms[-2] * x**2 * (n - 2)/(n*k) + else: + return 2 * x**n/(n*C.factorial(k)*sqrt(S.Pi)) + + def _eval_conjugate(self): + return self.func(self.args[0].conjugate()) + + def _eval_is_real(self): + return self.args[0].is_real + + def _eval_rewrite_as_tractable(self, z): + return self.rewrite(erf).rewrite("tractable", deep=True) + + def _eval_rewrite_as_erf(self, z): + return -I*erf(I*z) + + def _eval_rewrite_as_erfc(self, z): + return I*erfc(I*z) - I + + def _eval_rewrite_as_fresnels(self, z): + arg = (S.One + S.ImaginaryUnit)*z/sqrt(pi) + return (S.One - S.ImaginaryUnit)*(fresnelc(arg) - I*fresnels(arg)) + + def _eval_rewrite_as_fresnelc(self, z): + arg = (S.One + S.ImaginaryUnit)*z/sqrt(pi) + return (S.One - S.ImaginaryUnit)*(fresnelc(arg) - I*fresnels(arg)) + + def _eval_rewrite_as_meijerg(self, z): + return z/sqrt(pi)*meijerg([S.Half], [], [0], [-S.Half], -z**2) + + def _eval_rewrite_as_hyper(self, z): + return 2*z/sqrt(pi)*hyper([S.Half], [3*S.Half], z**2) + + def _eval_rewrite_as_uppergamma(self, z): + return sqrt(-z**2)/z*(C.uppergamma(S.Half, -z**2)/sqrt(S.Pi) - S.One) + + def _eval_rewrite_as_expint(self, z): + return sqrt(-z**2)/z - z*expint(S.Half, -z**2)/sqrt(S.Pi) + + def as_real_imag(self, deep=True, **hints): + if self.args[0].is_real: + if deep: + hints['complex'] = False + return (self.expand(deep, **hints), S.Zero) + else: + return (self, S.Zero) + if deep: + x, y = self.args[0].expand(deep, **hints).as_real_imag() + else: + x, y = self.args[0].as_real_imag() + + sq = -y**2/x**2 + re = S.Half*(self.func(x + x*sqrt(sq)) + self.func(x - x*sqrt(sq))) + im = x/(2*y) * sqrt(sq) * (self.func(x - x*sqrt(sq)) - + self.func(x + x*sqrt(sq))) + return (re, im) + +class erf2(Function): + r""" + Two-argument error function. This function is defined as: + + :math:`\mathrm{erf2}(x, y) = \frac{2}{\sqrt{\pi}} \int_x^y e^{-t^2} \mathrm{d}t` + + Examples + ======== + + >>> from sympy import I, oo, erf2 + >>> from sympy.abc import x, y + + Several special values are known: + + >>> erf2(0, 0) + 0 + >>> erf2(x, x) + 0 + >>> erf2(x, oo) + -erf(x) + 1 + >>> erf2(x, -oo) + -erf(x) - 1 + >>> erf2(oo, y) + erf(y) - 1 + >>> erf2(-oo, y) + erf(y) + 1 + + In general one can pull out factors of -1: + + >>> erf2(-x, -y) + -erf2(x, y) + + The error function obeys the mirror symmetry: + + >>> from sympy import conjugate + >>> conjugate(erf2(x, y)) + erf2(conjugate(x), conjugate(y)) + + Differentiation with respect to x, y is supported: + + >>> from sympy import diff + >>> diff(erf2(x, y), x) + -2*exp(-x**2)/sqrt(pi) + >>> diff(erf2(x, y), y) + 2*exp(-y**2)/sqrt(pi) + + See Also + ======== + + erf: Gaussian error function. + erfc: Complementary error function. + erfi: Imaginary error function. + erfinv: Inverse error function. + erfcinv: Inverse Complementary error function. + erf2inv: Inverse two-argument error function. + + References + ========== + + .. [1] http://functions.wolfram.com/GammaBetaErf/Erf2/ + """ + + nargs = 2 + + def fdiff(self, argindex): + x, y = self.args + if argindex == 1: + return -2*C.exp(-x**2)/sqrt(S.Pi) + elif argindex == 2: + return 2*C.exp(-y**2)/sqrt(S.Pi) + else: + raise ArgumentIndexError(self, argindex) + + @classmethod + def eval(cls, x, y): + I = S.Infinity + N = S.NegativeInfinity + O = S.Zero + if x is S.NaN or y is S.NaN: + return S.NaN + elif x == y: + return S.Zero + elif (x is I or x is N or x is O) or (y is I or y is N or y is O): + return erf(y) - erf(x) + + if y.func is erf2inv and y.args[0] == x: + return y.args[1] + + #Try to pull out -1 factor + sign_x = x.could_extract_minus_sign() + sign_y = y.could_extract_minus_sign() + if (sign_x and sign_y): + return -cls(-x, -y) + elif (sign_x or sign_y): + return erf(y)-erf(x) + + def _eval_conjugate(self): + return self.func(self.args[0].conjugate(), self.args[1].conjugate()) + + def _eval_is_real(self): + return self.args[0].is_real and self.args[1].is_real + + def _eval_rewrite_as_erf(self, x, y): + return erf(y) - erf(x) + + def _eval_rewrite_as_erfc(self, x, y): + return erfc(x) - erfc(y) + + def _eval_rewrite_as_erfi(self, x, y): + return I*(erfi(I*x)-erfi(I*y)) + + def _eval_rewrite_as_fresnels(self, x, y): + return erf(y).rewrite(fresnels) - erf(x).rewrite(fresnels) + + def _eval_rewrite_as_fresnelc(self, x, y): + return erf(y).rewrite(fresnelc) - erf(x).rewrite(fresnelc) + + def _eval_rewrite_as_meijerg(self, x, y): + return erf(y).rewrite(meijerg) - erf(x).rewrite(meijerg) + + def _eval_rewrite_as_hyper(self, x, y): + return erf(y).rewrite(hyper) - erf(x).rewrite(hyper) + + def _eval_rewrite_as_uppergamma(self, x, y): + return (sqrt(y**2)/y*(S.One - C.uppergamma(S.Half, y**2)/sqrt(S.Pi)) - + sqrt(x**2)/x*(S.One - C.uppergamma(S.Half, x**2)/sqrt(S.Pi))) + + def _eval_rewrite_as_expint(self, x, y): + return erf(y).rewrite(expint) - erf(x).rewrite(expint) + +class erfinv(Function): + r""" + Inverse Error Function. The erfinv function is defined as: + + :math:`\mathrm{erf}(x) = y \quad \Rightarrow \quad \mathrm{erfinv}(y) = x` + + Examples + ======== + + >>> from sympy import I, oo, erfinv + >>> from sympy.abc import x + + Several special values are known: + + >>> erfinv(0) + 0 + >>> erfinv(1) + oo + + Differentiation with respect to x is supported: + + >>> from sympy import diff + >>> diff(erfinv(x), x) + sqrt(pi)*exp(erfinv(x)**2)/2 + + We can numerically evaluate the inverse error function to arbitrary precision + on [-1, 1]: + + >>> erfinv(0.2).evalf(30) + 0.179143454621291692285822705344 + + See Also + ======== + + erf: Gaussian error function. + erfc: Complementary error function. + erfi: Imaginary error function. + erf2: Two-argument error function. + erfcinv: Inverse Complementary error function. + erf2inv: Inverse two-argument error function. + + References + ========== + + .. [1] http://en.wikipedia.org/wiki/Error_function#Inverse_functions + .. [2] http://functions.wolfram.com/GammaBetaErf/InverseErf/ + """ + + nargs = 1 + + def fdiff(self, argindex =1): + if argindex == 1: + return sqrt(S.Pi)*C.exp(self.func(self.args[0])**2)*S.Half + else : + raise ArgumentIndexError(self, argindex) + + @classmethod + def eval(cls, z): + if z is S.NaN: + return S.NaN + elif z is S.NegativeOne: + return S.NegativeInfinity + elif z is S.Zero: + return S.Zero + elif z is S.One: + return S.Infinity + + if (z.func is erf) and z.args[0].is_real: + return z.args[0] + + # Try to pull out factors of -1 + nz = z.extract_multiplicatively(-1) + if nz is not None and ((nz.func is erf) and (nz.args[0]).is_real): + return -nz.args[0] + + def _eval_rewrite_as_erfcinv(self, z): + return erfcinv(1-z) + +class erfcinv (Function): + r""" + Inverse Complementary Error Function. The erfcinv function is defined as: + + :math:`\mathrm{erfc}(x) = y \quad \Rightarrow \quad \mathrm{erfcinv}(y) = x` + + Examples + ======== + + >>> from sympy import I, oo, erfcinv + >>> from sympy.abc import x + + Several special values are known: + + >>> erfcinv(1) + 0 + >>> erfcinv(0) + oo + + Differentiation with respect to x is supported: + + >>> from sympy import diff + >>> diff(erfcinv(x), x) + -sqrt(pi)*exp(erfcinv(x)**2)/2 + + See Also + ======== + + erf: Gaussian error function. + erfc: Complementary error function. + erfi: Imaginary error function. + erf2: Two-argument error function. + erfinv: Inverse error function. + erf2inv: Inverse two-argument error function. + + References + ========== + + .. [1] http://en.wikipedia.org/wiki/Error_function#Inverse_functions + .. [2] http://functions.wolfram.com/GammaBetaErf/InverseErfc/ + """ + + nargs = 1 - def fdiff(self, argindex=1): + def fdiff(self, argindex =1): if argindex == 1: - return 2*C.exp(-self.args[0]**2)/sqrt(S.Pi) + return -sqrt(S.Pi)*C.exp(self.func(self.args[0])**2)*S.Half else: raise ArgumentIndexError(self, argindex) @classmethod - def eval(cls, arg): - if arg.is_Number: - if arg is S.NaN: - return S.NaN - elif arg is S.Infinity: - return S.One - elif arg is S.NegativeInfinity: - return S.NegativeOne - elif arg is S.Zero: - return S.Zero + def eval(cls, z): + if z is S.NaN: + return S.NaN + elif z is S.Zero: + return S.Infinity + elif z is S.One: + return S.Zero + elif z == 2: + return S.NegativeInfinity - t = arg.extract_multiplicatively(S.ImaginaryUnit) - if t == S.Infinity or t == S.NegativeInfinity: - return arg + def _eval_rewrite_as_erfinv(self, z): + return erfinv(1-z) - if arg.could_extract_minus_sign(): - return -cls(-arg) +class erf2inv(Function): + r""" + Two-argument Inverse error function. The erf2inv function is defined as: - @staticmethod - @cacheit - def taylor_term(n, x, *previous_terms): - if n < 0 or n % 2 == 0: - return S.Zero - else: - x = sympify(x) - k = C.floor((n - 1)/S(2)) - if len(previous_terms) > 2: - return -previous_terms[-2] * x**2 * (n-2)/(n*k) - else: - return 2*(-1)**k * x**n/(n*C.factorial(k)*sqrt(S.Pi)) + :math:`\mathrm{erf2}(x, w) = y \quad \Rightarrow \quad \mathrm{erf2inv}(x, y) = w` - def _eval_conjugate(self): - return self.func(self.args[0].conjugate()) + Examples + ======== - def _eval_is_real(self): - return self.args[0].is_real + >>> from sympy import I, oo, erf2inv, erfinv, erfcinv + >>> from sympy.abc import x, y - def _eval_rewrite_as_uppergamma(self, z): - return sqrt(z**2)/z*(S.One - C.uppergamma(S.Half, z**2)/sqrt(S.Pi)) + Several special values are known: - def _eval_rewrite_as_tractable(self, z): - return S.One - _erfs(z)*C.exp(-z**2) + >>> erf2inv(0, 0) + 0 + >>> erf2inv(1, 0) + 1 + >>> erf2inv(0, 1) + oo + >>> erf2inv(0, y) + erfinv(y) + >>> erf2inv(oo, y) + erfcinv(-y) - def _eval_as_leading_term(self, x): - arg = self.args[0].as_leading_term(x) + Differentiation with respect to x and y is supported: - if x in arg.free_symbols and C.Order(1, x).contains(arg): - return 2*x/sqrt(pi) + >>> from sympy import diff + >>> diff(erf2inv(x, y), x) + exp(-x**2 + erf2inv(x, y)**2) + >>> diff(erf2inv(x, y), y) + sqrt(pi)*exp(erf2inv(x, y)**2)/2 + + See Also + ======== + + erf: Gaussian error function. + erfc: Complementary error function. + erfi: Imaginary error function. + erf2: Two-argument error function. + erfinv: Inverse error function. + erfcinv: Inverse complementary error function. + + References + ========== + + .. [1] http://functions.wolfram.com/GammaBetaErf/InverseErf2/ + """ + + nargs = 2 + + def fdiff(self, argindex): + x, y = self.args + if argindex == 1: + return C.exp(self.func(x,y)**2-x**2) + elif argindex == 2: + return sqrt(S.Pi)*S.Half*C.exp(self.func(x,y)**2) else: - return self.func(arg) + raise ArgumentIndexError(self, argindex) + + @classmethod + def eval(cls, x, y): + if x is S.NaN or y is S.NaN: + return S.NaN + elif x is S.Zero and y is S.Zero: + return S.Zero + elif x is S.Zero and y is S.One: + return S.Infinity + elif x is S.One and y is S.Zero: + return S.One + elif x is S.Zero: + return erfinv(y) + elif x is S.Infinity: + return erfcinv(-y) + elif y is S.Zero: + return x + elif y is S.Infinity: + return erfinv(x) ############################################################################### @@ -161,51 +925,60 @@ r""" The classical exponential integral. - For the use in SymPy, this function is defined as + For use in SymPy, this function is defined as .. math:: \operatorname{Ei}(x) = \sum_{n=1}^\infty \frac{x^n}{n\, n!} + \log(x) + \gamma, - where :math:`\gamma` is the Euler-Mascheroni constant. + where `\gamma` is the Euler-Mascheroni constant. - If :math:`x` is a polar number, this defines an analytic function on the + If `x` is a polar number, this defines an analytic function on the riemann surface of the logarithm. Otherwise this defines an analytic - function in the cut plane :math:`\mathbb{C} \setminus (-\infty, 0]`. + function in the cut plane `\mathbb{C} \setminus (-\infty, 0]`. **Background** - The name 'exponential integral' comes from the following statement: + The name *exponential integral* comes from the following statement: .. math:: \operatorname{Ei}(x) = \int_{-\infty}^x \frac{e^t}{t} \mathrm{d}t If the integral is interpreted as a Cauchy principal value, this statement - holds for :math:`x > 0` and :math:`\operatorname{Ei}(x)` as defined above. + holds for `x > 0` and `\operatorname{Ei}(x)` as defined above. - Note that we carefully avoided defining :math:`\operatorname{Ei}(x)` for - negative real x. This is because above integral formula does not hold for - any polar lift of such :math:`x`, indeed all branches of - :math:`\operatorname{Ei}(x)` above the negative reals are imaginary. + Note that we carefully avoided defining `\operatorname{Ei}(x)` for + negative real `x`. This is because above integral formula does not hold for + any polar lift of such `x`, indeed all branches of + `\operatorname{Ei}(x)` above the negative reals are imaginary. - However, the following statement holds for all :math:`x \in \mathbb{R}^*`: + However, the following statement holds for all `x \in \mathbb{R}^*`: .. math:: \int_{-\infty}^x \frac{e^t}{t} \mathrm{d}t = \frac{\operatorname{Ei}\left(|x|e^{i \arg(x)}\right) + \operatorname{Ei}\left(|x|e^{- i \arg(x)}\right)}{2}, where the integral is again understood to be a principal value if - :math:`x > 0`, and :math:`|x|e^{i \arg(x)}`, - :math:`|x|e^{- i \arg(x)}` denote two conjugate polar lifts of :math:`x`. + `x > 0`, and `|x|e^{i \arg(x)}`, + `|x|e^{- i \arg(x)}` denote two conjugate polar lifts of `x`. See Also ======== - expint, sympy.functions.special.gamma_functions.uppergamma + expint: Generalised exponential integral. + E1: Special case of the generalised exponential integral. + li: Logarithmic integral. + Li: Offset logarithmic integral. + Si: Sine integral. + Ci: Cosine integral. + Shi: Hyperbolic sine integral. + Chi: Hyperbolic cosine integral. + sympy.functions.special.gamma_functions.uppergamma References ========== - - Abramowitz & Stegun, section 5: http://www.math.sfu.ca/~cbm/aands/page_228.htm - - http://en.wikipedia.org/wiki/Exponential_integral + .. [1] http://dlmf.nist.gov/6.6 + .. [2] http://en.wikipedia.org/wiki/Exponential_integral + .. [3] Abramowitz & Stegun, section 5: http://www.math.sfu.ca/~cbm/aands/page_228.htm Examples ======== @@ -285,12 +1058,24 @@ def _eval_rewrite_as_expint(self, z): return -expint(1, polar_lift(-1)*z) - I*pi + def _eval_rewrite_as_li(self, z): + if isinstance(z, log): + return li(z.args[0]) + # TODO: + # Actually it only holds that: + # Ei(z) = li(exp(z)) + # for -pi < imag(z) <= pi + return li(exp(z)) + def _eval_rewrite_as_Si(self, z): return Shi(z) + Chi(z) _eval_rewrite_as_Ci = _eval_rewrite_as_Si _eval_rewrite_as_Chi = _eval_rewrite_as_Si _eval_rewrite_as_Shi = _eval_rewrite_as_Si + def _eval_rewrite_as_tractable(self, z): + return C.exp(z) * _eis(z) + class expint(Function): r""" Generalized exponential integral. @@ -319,16 +1104,22 @@ See Also ======== - E1: The classical case, returns expint(1, z). Ei: Another related function called exponential integral. + E1: The classical case, returns expint(1, z). + li: Logarithmic integral. + Li: Offset logarithmic integral. + Si: Sine integral. + Ci: Cosine integral. + Shi: Hyperbolic sine integral. + Chi: Hyperbolic cosine integral. sympy.functions.special.gamma_functions.uppergamma References ========== - - http://dlmf.nist.gov/8.19 - - http://functions.wolfram.com/GammaBetaErf/ExpIntegralE/ - - http://en.wikipedia.org/wiki/Exponential_integral + .. [1] http://dlmf.nist.gov/8.19 + .. [2] http://functions.wolfram.com/GammaBetaErf/ExpIntegralE/ + .. [3] http://en.wikipedia.org/wiki/Exponential_integral Examples ======== @@ -406,9 +1197,9 @@ if (nu > 0) is not True: return return expint(nu, z) \ - - 2*pi*I*n*(-1)**(nu-1)/factorial(nu-1)*unpolarify(z)**(nu - 1) + - 2*pi*I*n*(-1)**(nu - 1)/factorial(nu - 1)*unpolarify(z)**(nu - 1) else: - return (exp(2*I*pi*nu*n) - 1)*z**(nu-1)*gamma(1 - nu) + expint(nu, z) + return (exp(2*I*pi*nu*n) - 1)*z**(nu - 1)*gamma(1 - nu) + expint(nu, z) def fdiff(self, argindex): from sympy import meijerg @@ -431,9 +1222,9 @@ elif nu.is_Integer and nu > 1: # DLMF, 8.19.7 x = -unpolarify(z) - return x**(nu-1)/factorial(nu - 1)*E1(z).rewrite(Ei) + \ - exp(x)/factorial(nu - 1) * \ - Add(*[factorial(nu - k - 2)*x**k for k in range(nu - 1)]) + return x**(nu - 1)/factorial(nu - 1)*E1(z).rewrite(Ei) + \ + exp(x)/factorial(nu - 1) * \ + Add(*[factorial(nu - k - 2)*x**k for k in range(nu - 1)]) else: return self @@ -448,16 +1239,260 @@ _eval_rewrite_as_Chi = _eval_rewrite_as_Si _eval_rewrite_as_Shi = _eval_rewrite_as_Si + def E1(z): """ Classical case of the generalized exponential integral. This is equivalent to ``expint(1, z)``. + See Also + ======== + + Ei: Exponential integral. + expint: Generalised exponential integral. + li: Logarithmic integral. + Li: Offset logarithmic integral. + Si: Sine integral. + Ci: Cosine integral. + Shi: Hyperbolic sine integral. + Chi: Hyperbolic cosine integral. """ return expint(1, z) +class li(Function): + r""" + The classical logarithmic integral. + + For the use in SymPy, this function is defined as + + .. math:: \operatorname{li}(x) = \int_0^x \frac{1}{\log(t)} \mathrm{d}t \,. + + Examples + ======== + + >>> from sympy import I, oo, li + >>> from sympy.abc import z + + Several special values are known: + + >>> li(0) + 0 + >>> li(1) + -oo + >>> li(oo) + oo + + Differentiation with respect to z is supported: + + >>> from sympy import diff + >>> diff(li(z), z) + 1/log(z) + + Defining the `li` function via an integral: + + + The logarithmic integral can also be defined in terms of Ei: + + >>> from sympy import Ei + >>> li(z).rewrite(Ei) + Ei(log(z)) + >>> diff(li(z).rewrite(Ei), z) + 1/log(z) + + We can numerically evaluate the logarithmic integral to arbitrary precision + on the whole complex plane (except the singular points): + + >>> li(2).evalf(30) + 1.04516378011749278484458888919 + + >>> li(2*I).evalf(30) + 1.0652795784357498247001125598 + 3.08346052231061726610939702133*I + + We can even compute Soldner's constant by the help of mpmath: + + >>> from sympy.mpmath import findroot + >>> findroot(li, 2) + 1.45136923488338 + + Further transformations include rewriting `li` in terms of + the trigonometric integrals `Si`, `Ci`, `Shi` and `Chi`: + + >>> from sympy import Si, Ci, Shi, Chi + >>> li(z).rewrite(Si) + -log(I*log(z)) - log(1/log(z))/2 + log(log(z))/2 + Ci(I*log(z)) + Shi(log(z)) + >>> li(z).rewrite(Ci) + -log(I*log(z)) - log(1/log(z))/2 + log(log(z))/2 + Ci(I*log(z)) + Shi(log(z)) + >>> li(z).rewrite(Shi) + -log(1/log(z))/2 + log(log(z))/2 + Chi(log(z)) - Shi(log(z)) + >>> li(z).rewrite(Chi) + -log(1/log(z))/2 + log(log(z))/2 + Chi(log(z)) - Shi(log(z)) + + See Also + ======== + + Li: Offset logarithmic integral. + Ei: Exponential integral. + expint: Generalised exponential integral. + E1: Special case of the generalised exponential integral. + Si: Sine integral. + Ci: Cosine integral. + Shi: Hyperbolic sine integral. + Chi: Hyperbolic cosine integral. + + References + ========== + + .. [1] http://en.wikipedia.org/wiki/Logarithmic_integral + .. [2] http://mathworld.wolfram.com/LogarithmicIntegral.html + .. [3] http://dlmf.nist.gov/6 + .. [4] http://mathworld.wolfram.com/SoldnersConstant.html + """ + + nargs = 1 + + @classmethod + def eval(cls, z): + if z is S.Zero: + return S.Zero + elif z is S.One: + return S.NegativeInfinity + elif z is S.Infinity: + return S.Infinity + + def fdiff(self, argindex=1): + arg = self.args[0] + if argindex == 1: + return S.One / C.log(arg) + else: + raise ArgumentIndexError(self, argindex) + + def _eval_conjugate(self): + z = self.args[0] + # Exclude values on the branch cut (-oo, 0) + if not (z.is_real and z.is_negative): + return self.func(z.conjugate()) + + def _eval_rewrite_as_Li(self, z): + return Li(z) + li(2) + + def _eval_rewrite_as_Ei(self, z): + return Ei(C.log(z)) + + def _eval_rewrite_as_uppergamma(self, z): + from sympy import uppergamma + return (-uppergamma(0, -C.log(z)) + + S.Half*(C.log(C.log(z)) - C.log(S.One/C.log(z))) - C.log(-C.log(z))) + + def _eval_rewrite_as_Si(self, z): + return (Ci(I*C.log(z)) - I*Si(I*C.log(z)) - + S.Half*(C.log(S.One/C.log(z)) - C.log(C.log(z))) - C.log(I*C.log(z))) + + _eval_rewrite_as_Ci = _eval_rewrite_as_Si + + def _eval_rewrite_as_Shi(self, z): + return (Chi(C.log(z)) - Shi(C.log(z)) - S.Half*(C.log(S.One/C.log(z)) - C.log(C.log(z)))) + + _eval_rewrite_as_Chi = _eval_rewrite_as_Shi + + def _eval_rewrite_as_hyper(self, z): + return (C.log(z)*hyper((1, 1), (2, 2), C.log(z)) + + S.Half*(C.log(C.log(z)) - C.log(S.One/C.log(z))) + S.EulerGamma) + + def _eval_rewrite_as_meijerg(self, z): + return (-C.log(-C.log(z)) - S.Half*(C.log(S.One/C.log(z)) - C.log(C.log(z))) + - meijerg(((), (1,)), ((0, 0), ()), -C.log(z))) + + def _eval_rewrite_as_tractable(self, z): + return z * _eis(C.log(z)) + + +class Li(Function): + r""" + The offset logarithmic integral. + + For the use in SymPy, this function is defined as + + .. math:: \operatorname{Li}(x) = \operatorname{li}(x) - \operatorname{li}(2) + + Examples + ======== + + >>> from sympy import I, oo, Li + >>> from sympy.abc import z + + The following special value is known: + + >>> Li(2) + 0 + + Differentiation with respect to z is supported: + + >>> from sympy import diff + >>> diff(Li(z), z) + 1/log(z) + + The shifted logarithmic integral can be written in terms of `li(z)`: + + >>> from sympy import li + >>> Li(z).rewrite(li) + li(z) - li(2) + + We can numerically evaluate the logarithmic integral to arbitrary precision + on the whole complex plane (except the singular points): + + >>> Li(2).evalf(30) + 0 + + >>> Li(4).evalf(30) + 1.92242131492155809316615998938 + + See Also + ======== + + li: Logarithmic integral. + Ei: Exponential integral. + expint: Generalised exponential integral. + E1: Special case of the generalised exponential integral. + Si: Sine integral. + Ci: Cosine integral. + Shi: Hyperbolic sine integral. + Chi: Hyperbolic cosine integral. + + References + ========== + + .. [1] http://en.wikipedia.org/wiki/Logarithmic_integral + .. [2] http://mathworld.wolfram.com/LogarithmicIntegral.html + .. [3] http://dlmf.nist.gov/6 + """ + + nargs = 1 + + @classmethod + def eval(cls, z): + if z is S.Infinity: + return S.Infinity + elif z is 2*S.One: + return S.Zero + + def fdiff(self, argindex=1): + arg = self.args[0] + if argindex == 1: + return S.One / C.log(arg) + else: + raise ArgumentIndexError(self, argindex) + + def _eval_evalf(self, prec): + return self.rewrite(li).evalf(prec) + + def _eval_rewrite_as_li(self, z): + return li(z) - li(2) + + def _eval_rewrite_as_tractable(self, z): + return self.rewrite(li).rewrite("tractable", deep=True) + ############################################################################### #################### TRIGONOMETRIC INTEGRALS ################################## ############################################################################### @@ -471,6 +1506,11 @@ def eval(cls, z): if z == 0: return cls._atzero + elif z is S.Infinity: + return cls._atinf + elif z is S.NegativeInfinity: + return cls._atneginf + nz = z.extract_multiplicatively(polar_lift(I)) if nz is None and cls._trigfunc(0) == 0: nz = z.extract_multiplicatively(I) @@ -513,11 +1553,12 @@ baseseries = self._trigfunc(x)._eval_nseries(x, n, logx) if self._trigfunc(0) != 0: baseseries -= 1 - baseseries = baseseries.replace(Pow, lambda t, n: t**n/n) + baseseries = baseseries.replace(Pow, lambda t, n: t**n/n, simultaneous=False) if self._trigfunc(0) != 0: baseseries += EulerGamma + log(x) return baseseries.subs(x, self.args[0])._eval_nseries(x, n, logx) + class Si(TrigonometricIntegral): r""" Sine integral. @@ -532,14 +1573,18 @@ ======== Ci: Cosine integral. - Shi: Sinh integral. - Chi: Cosh integral. - expint: The generalised exponential integral. + Shi: Hyperbolic sine integral. + Chi: Hyperbolic cosine integral. + Ei: Exponential integral. + expint: Generalised exponential integral. + E1: Special case of the generalised exponential integral. + li: Logarithmic integral. + Li: Offset logarithmic integral. References ========== - - http://en.wikipedia.org/wiki/Trigonometric_integral + .. [1] http://en.wikipedia.org/wiki/Trigonometric_integral Examples ======== @@ -558,7 +1603,7 @@ >>> Si(z*exp_polar(2*I*pi)) Si(z) - Sine integral behaves much like ordinary sine under multiplication by I: + Sine integral behaves much like ordinary sine under multiplication by ``I``: >>> Si(I*z) I*Shi(z) @@ -570,12 +1615,15 @@ >>> from sympy import expint >>> Si(z).rewrite(expint) - -I*(-expint(1, z*exp_polar(-I*pi/2))/2 + expint(1, z*exp_polar(I*pi/2))/2) + pi/2 + -I*(-expint(1, z*exp_polar(-I*pi/2))/2 + + expint(1, z*exp_polar(I*pi/2))/2) + pi/2 """ _trigfunc = C.sin _atzero = S(0) + _atinf = pi*S.Half + _atneginf = -pi*S.Half @classmethod def _minusfactor(cls, z): @@ -589,17 +1637,18 @@ # XXX should we polarify z? return pi/2 + (E1(polar_lift(I)*z) - E1(polar_lift(-I)*z))/2/I + class Ci(TrigonometricIntegral): r""" Cosine integral. - This function is defined for positive :math:`x` by + This function is defined for positive `x` by .. math:: \operatorname{Ci}(x) = \gamma + \log{x} + \int_0^x \frac{\cos{t} - 1}{t} \mathrm{d}t = -\int_x^\infty \frac{\cos{t}}{t} \mathrm{d}t, - where :math:`\gamma` is the Euler-Mascheroni constant. + where `\gamma` is the Euler-Mascheroni constant. We have @@ -607,11 +1656,11 @@ -\frac{\operatorname{E}_1\left(e^{i\pi/2} z\right) + \operatorname{E}_1\left(e^{-i \pi/2} z\right)}{2} - which holds for all polar :math:`z` and thus provides an analytic + which holds for all polar `z` and thus provides an analytic continuation to the Riemann surface of the logarithm. The formula also holds as stated - for :math:`z \in \mathbb{C}` with :math:`Re(z) > 0`. + for `z \in \mathbb{C}` with `\Re(z) > 0`. By lifting to the principal branch we obtain an analytic function on the cut complex plane. @@ -619,14 +1668,18 @@ ======== Si: Sine integral. - Shi: Sinh integral. - Chi: Cosh integral. - expint: The generalised exponential integral. + Shi: Hyperbolic sine integral. + Chi: Hyperbolic cosine integral. + Ei: Exponential integral. + expint: Generalised exponential integral. + E1: Special case of the generalised exponential integral. + li: Logarithmic integral. + Li: Offset logarithmic integral. References ========== - - http://en.wikipedia.org/wiki/Trigonometric_integral + .. [1] http://en.wikipedia.org/wiki/Trigonometric_integral Examples ======== @@ -634,7 +1687,7 @@ >>> from sympy import Ci >>> from sympy.abc import z - The cosine integral is a primitive of cos(z)/z: + The cosine integral is a primitive of `\cos(z)/z`: >>> Ci(z).diff(z) cos(z)/z @@ -645,7 +1698,7 @@ >>> Ci(z*exp_polar(2*I*pi)) Ci(z) + 2*I*pi - Cosine integral behaves somewhat like ordinary cos under multiplication by I: + The cosine integral behaves somewhat like ordinary `\cos` under multiplication by `i`: >>> from sympy import polar_lift >>> Ci(polar_lift(I)*z) @@ -663,6 +1716,8 @@ _trigfunc = C.cos _atzero = S.ComplexInfinity + _atinf = S.Zero + _atneginf = I*pi @classmethod def _minusfactor(cls, z): @@ -675,6 +1730,7 @@ def _eval_rewrite_as_expint(self, z): return -(E1(polar_lift(I)*z) + E1(polar_lift(-I)*z))/2 + class Shi(TrigonometricIntegral): r""" Sinh integral. @@ -690,13 +1746,17 @@ Si: Sine integral. Ci: Cosine integral. - Chi: Cosh integral. - expint: The generalised exponential integral. + Chi: Hyperbolic cosine integral. + Ei: Exponential integral. + expint: Generalised exponential integral. + E1: Special case of the generalised exponential integral. + li: Logarithmic integral. + Li: Offset logarithmic integral. References ========== - - http://en.wikipedia.org/wiki/Trigonometric_integral + .. [1] http://en.wikipedia.org/wiki/Trigonometric_integral Examples ======== @@ -704,7 +1764,7 @@ >>> from sympy import Shi >>> from sympy.abc import z - The Sinh integral is a primitive of sinh(z)/z: + The Sinh integral is a primitive of `\sinh(z)/z`: >>> Shi(z).diff(z) sinh(z)/z @@ -715,7 +1775,7 @@ >>> Shi(z*exp_polar(2*I*pi)) Shi(z) - Sinh integral behaves much like ordinary sinh under multiplication by I: + The `\sinh` integral behaves much like ordinary `\sinh` under multiplication by `i`: >>> Shi(I*z) I*Si(z) @@ -733,6 +1793,8 @@ _trigfunc = C.sinh _atzero = S(0) + _atinf = S.Infinity + _atneginf = S.NegativeInfinity @classmethod def _minusfactor(cls, z): @@ -745,7 +1807,8 @@ def _eval_rewrite_as_expint(self, z): from sympy import exp_polar # XXX should we polarify z? - return (E1(z)-E1(exp_polar(I*pi)*z))/2 - I*pi/2 + return (E1(z) - E1(exp_polar(I*pi)*z))/2 - I*pi/2 + class Chi(TrigonometricIntegral): r""" @@ -773,13 +1836,17 @@ Si: Sine integral. Ci: Cosine integral. - Shi: Sinh integral. - expint: The generalised exponential integral. + Shi: Hyperbolic sine integral. + Ei: Exponential integral. + expint: Generalised exponential integral. + E1: Special case of the generalised exponential integral. + li: Logarithmic integral. + Li: Offset logarithmic integral. References ========== - - http://en.wikipedia.org/wiki/Trigonometric_integral + .. [1] http://en.wikipedia.org/wiki/Trigonometric_integral Examples ======== @@ -787,7 +1854,7 @@ >>> from sympy import Chi >>> from sympy.abc import z - The cosh integral is a primitive of cosh(z)/z: + The `\cosh` integral is a primitive of `\cosh(z)/z`: >>> Chi(z).diff(z) cosh(z)/z @@ -798,7 +1865,7 @@ >>> Chi(z*exp_polar(2*I*pi)) Chi(z) + 2*I*pi - Cosh integral behaves somewhat like ordinary cosh under multiplication by I: + The `\cosh` integral behaves somewhat like ordinary `\cosh` under multiplication by `i`: >>> from sympy import polar_lift >>> Chi(polar_lift(I)*z) @@ -816,6 +1883,8 @@ _trigfunc = C.cosh _atzero = S.ComplexInfinity + _atinf = S.Infinity + _atneginf = S.Infinity @classmethod def _minusfactor(cls, z): @@ -829,6 +1898,15 @@ from sympy import exp_polar return -I*pi/2 - (E1(z) + E1(exp_polar(I*pi)*z))/2 + def _latex(self, printer, exp=None): + assert len(self.args) == 1 + if exp: + return r'\operatorname{Chi}^{%s}{\left (%s \right )}' \ + % (printer._print(exp), printer._print(self.args[0])) + else: + return r'\operatorname{Chi}{\left (%s \right )}' \ + % printer._print(self.args[0]) + ############################################################################### #################### FRESNEL INTEGRALS ######################################## @@ -907,8 +1985,9 @@ # http://functions.wolfram.com/06.33.19.0006.01 x, y = self._as_real_imag(deep=deep, **hints) sq = -y**2/x**2 - re = S.Half*(self.func(x+x*sqrt(sq))+self.func(x-x*sqrt(sq))) - im = x/(2*y) * sqrt(sq) * (self.func(x-x*sqrt(sq)) - self.func(x+x*sqrt(sq))) + re = S.Half*(self.func(x + x*sqrt(sq)) + self.func(x - x*sqrt(sq))) + im = x/(2*y) * sqrt(sq) * (self.func(x - x*sqrt(sq)) - + self.func(x + x*sqrt(sq))) return (re, im) @@ -941,20 +2020,21 @@ >>> fresnels(-I*oo) I/2 - In general one can pull out factors of -1 and I from the argument: + In general one can pull out factors of -1 and `i` from the argument: + >>> fresnels(-z) -fresnels(z) - >>> fresnels(I*z) -I*fresnels(z) - The Fresnel S integral obeys the mirror symmetry: + The Fresnel S integral obeys the mirror symmetry + `\overline{S(z)} = S(\bar{z})`: >>> from sympy import conjugate >>> conjugate(fresnels(z)) fresnels(conjugate(z)) - Differentiation with respect to z is supported: + Differentiation with respect to `z` is supported: >>> from sympy import diff >>> diff(fresnels(z), z) @@ -1015,7 +2095,8 @@ def _eval_rewrite_as_meijerg(self, z): return (pi*z**(S(9)/4) / (sqrt(2)*(z**2)**(S(3)/4)*(-z)**(S(3)/4)) - * meijerg([],[1],[S(3)/4],[S(1)/4,0],-pi**2*z**4/16)) + * meijerg([], [1], [S(3)/4], [S(1)/4, 0], -pi**2*z**4/16)) + class fresnelc(FresnelIntegral): r""" @@ -1046,20 +2127,21 @@ >>> fresnelc(-I*oo) -I/2 - In general one can pull out factors of -1 and I from the argument: + In general one can pull out factors of -1 and `i` from the argument: + >>> fresnelc(-z) -fresnelc(z) - >>> fresnelc(I*z) I*fresnelc(z) - The Fresnel C integral obeys the mirror symmetry: + The Fresnel C integral obeys the mirror symmetry + `\overline{C(z)} = C(\bar{z})`: >>> from sympy import conjugate >>> conjugate(fresnelc(z)) fresnelc(conjugate(z)) - Differentiation with respect to z is supported: + Differentiation with respect to `z` is supported: >>> from sympy import diff >>> diff(fresnelc(z), z) @@ -1119,16 +2201,62 @@ return z * hyper([S.One/4], [S.One/2, S(5)/4], -pi**2*z**4/16) def _eval_rewrite_as_meijerg(self, z): - return (pi*z**(S(3)/4) / (sqrt(2)*root(z**2,4)*root(-z,4)) - * meijerg([],[1],[S(1)/4],[S(3)/4,0],-pi**2*z**4/16)) + return (pi*z**(S(3)/4) / (sqrt(2)*root(z**2, 4)*root(-z, 4)) + * meijerg([], [1], [S(1)/4], [S(3)/4, 0], -pi**2*z**4/16)) ############################################################################### #################### HELPER FUNCTIONS ######################################### ############################################################################### + class _erfs(Function): """ - Helper function to make the :math:`erf(z)` function + Helper function to make the `\\mathrm{erf}(z)` function + tractable for the Gruntz algorithm. + """ + + nargs = 1 + + def _eval_aseries(self, n, args0, x, logx): + point = args0[0] + + # Expansion at oo + if point is S.Infinity: + z = self.args[0] + l = [ 1/sqrt(S.Pi) * C.factorial(2*k)*(-S( + 4))**(-k)/C.factorial(k) * (1/z)**(2*k + 1) for k in range(0, n) ] + o = C.Order(1/z**(2*n + 1), x) + # It is very inefficient to first add the order and then do the nseries + return (Add(*l))._eval_nseries(x, n, logx) + o + + # Expansion at I*oo + t = point.extract_multiplicatively(S.ImaginaryUnit) + if t is S.Infinity: + z = self.args[0] + # TODO: is the series really correct? + l = [ 1/sqrt(S.Pi) * C.factorial(2*k)*(-S( + 4))**(-k)/C.factorial(k) * (1/z)**(2*k + 1) for k in range(0, n) ] + o = C.Order(1/z**(2*n + 1), x) + # It is very inefficient to first add the order and then do the nseries + return (Add(*l))._eval_nseries(x, n, logx) + o + + # All other points are not handled + return super(_erfs, self)._eval_aseries(n, args0, x, logx) + + def fdiff(self, argindex=1): + if argindex == 1: + z = self.args[0] + return -2/sqrt(S.Pi) + 2*z*_erfs(z) + else: + raise ArgumentIndexError(self, argindex) + + def _eval_rewrite_as_intractable(self, z): + return (S.One - erf(z))*C.exp(z**2) + + +class _eis(Function): + """ + Helper function to make the `\\mathrm{Ei}(z)` and `\\mathrm{li}(z)` functions tractable for the Gruntz algorithm. """ @@ -1139,17 +2267,18 @@ return super(_erfs, self)._eval_aseries(n, args0, x, logx) z = self.args[0] - l = [ 1/sqrt(S.Pi) * C.factorial(2*k)*(-S(4))**(-k)/C.factorial(k) * (1/z)**(2*k+1) for k in range(0,n) ] - o = C.Order(1/z**(2*n+1), x) + l = [ C.factorial(k) * (1/z)**(k + 1) for k in range(0, n) ] + o = C.Order(1/z**(n + 1), x) # It is very inefficient to first add the order and then do the nseries return (Add(*l))._eval_nseries(x, n, logx) + o + def fdiff(self, argindex=1): if argindex == 1: z = self.args[0] - return -2/sqrt(S.Pi)+2*z*_erfs(z) + return S.One / z - _eis(z) else: raise ArgumentIndexError(self, argindex) def _eval_rewrite_as_intractable(self, z): - return (S.One-erf(z))*C.exp(z**2) + return C.exp(-z)*Ei(z) diff -Nru python3-sympy-0.7.2/sympy/functions/special/gamma_functions.py python3-sympy-0.7.3/sympy/functions/special/gamma_functions.py --- python3-sympy-0.7.2/sympy/functions/special/gamma_functions.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/functions/special/gamma_functions.py 2013-07-13 17:53:32.000000000 +0000 @@ -2,24 +2,28 @@ from sympy.core.function import Function, ArgumentIndexError from .zeta_functions import zeta from .error_functions import erf -from sympy.core import Dummy,Rational +from sympy.core import Dummy, Rational from sympy.functions.elementary.exponential import log from sympy.functions.elementary.integers import floor from sympy.functions.elementary.miscellaneous import sqrt from sympy.functions.combinatorial.numbers import bernoulli from sympy.functions.combinatorial.factorials import rf +from sympy.functions.combinatorial.numbers import harmonic ############################################################################### ############################ COMPLETE GAMMA FUNCTION ########################## ############################################################################### + class gamma(Function): """The gamma function returns a function which passes through the integral values of the factorial function, i.e. though defined in the complex plane, - when n is an integer, `gamma(n) = (n - 1)!` + when n is an integer, `\Gamma(n) = (n - 1)!` + + References + ========== - Reference: - http://en.wikipedia.org/wiki/Gamma_function + .. [1] http://en.wikipedia.org/wiki/Gamma_function """ nargs = 1 @@ -40,7 +44,7 @@ return S.Infinity elif arg.is_Integer: if arg.is_positive: - return C.factorial(arg-1) + return C.factorial(arg - 1) else: return S.ComplexInfinity elif arg.is_Rational: @@ -65,7 +69,6 @@ else: return 2**n*sqrt(S.Pi) / coeff - def _eval_expand_func(self, **hints): arg = self.args[0] if arg.is_Rational: @@ -141,10 +144,10 @@ References ========== - - Abramowitz, Milton; Stegun, Irene A., eds. (1965), Chapter 6, Section 5, - Handbook of Mathematical Functions with Formulas, Graphs, and Mathematical - Tables - - http://en.wikipedia.org/wiki/Incomplete_gamma_function + .. [1] Abramowitz, Milton; Stegun, Irene A., eds. (1965), Chapter 6, + Section 5, Handbook of Mathematical Functions with Formulas, Graphs, + and Mathematical Tables + .. [2] http://en.wikipedia.org/wiki/Incomplete_gamma_function """ @@ -154,11 +157,11 @@ from sympy import meijerg, unpolarify if argindex == 2: a, z = self.args - return C.exp(-unpolarify(z))*z**(a-1) + return C.exp(-unpolarify(z))*z**(a - 1) elif argindex == 1: a, z = self.args return gamma(a)*digamma(a) - log(z)*uppergamma(a, z) \ - + meijerg([], [1, 1], [0, 0, a], [], z) + + meijerg([], [1, 1], [0, 0, a], [], z) else: raise ArgumentIndexError(self, argindex) @@ -182,11 +185,11 @@ # lowergamma(s, exp(2*I*pi*n)*x) = exp(2*pi*I*n*a)*lowergamma(a, x) from sympy import unpolarify, I, factorial, exp nx, n = x.extract_branch_factor() - if a.is_integer and a > 0: + if a.is_integer and a.is_positive: nx = unpolarify(x) if nx != x: return lowergamma(a, nx) - elif a.is_integer and a <= 0: + elif a.is_integer and a.is_nonpositive: if n != 0: return 2*pi*I*n*(-1)**(-a)/factorial(-a) + lowergamma(a, nx) elif n != 0: @@ -227,6 +230,7 @@ return self return self.rewrite(uppergamma).rewrite(expint) + class uppergamma(Function): r""" Upper incomplete gamma function @@ -237,7 +241,8 @@ \Gamma(s, x) = \int_x^\infty t^{s-1} e^{-t} \mathrm{d}t = \Gamma(s) - \gamma(s, x). - This can be shown to be the same as + where `\gamma(s, x)` is the lower incomplete gamma function, + :class:`lowergamma`. This can be shown to be the same as .. math :: \Gamma(s, x) = \Gamma(s) @@ -246,7 +251,10 @@ where :math:`{}_1F_1` is the (confluent) hypergeometric function. The upper incomplete gamma function is also essentially equivalent to the - generalized exponential integral. + generalized exponential integral: + + .. math :: + \operatorname{E}_{n}(x) = \int_{1}^{\infty}{\frac{e^{-xt}}{t^n} \, dt} = x^{n-1}\Gamma(1-n,x). Examples ======== @@ -271,11 +279,11 @@ References ========== - - Abramowitz, Milton; Stegun, Irene A., eds. (1965), Chapter 6, Section 5, - Handbook of Mathematical Functions with Formulas, Graphs, and Mathematical - Tables - - http://en.wikipedia.org/wiki/Incomplete_gamma_function - + .. [1] Abramowitz, Milton; Stegun, Irene A., eds. (1965), Chapter 6, + Section 5, Handbook of Mathematical Functions with Formulas, Graphs, + and Mathematical Tables + .. [2] http://en.wikipedia.org/wiki/Incomplete_gamma_function + .. [3] http://en.wikipedia.org/wiki/Exponential_integral#Relation_with_other_functions """ nargs = 2 @@ -284,7 +292,7 @@ from sympy import meijerg, unpolarify if argindex == 2: a, z = self.args - return -C.exp(-unpolarify(z))*z**(a-1) + return -C.exp(-unpolarify(z))*z**(a - 1) elif argindex == 1: a, z = self.args return uppergamma(a, z)*log(z) + meijerg([], [1, 1], [0, 0, a], [], z) @@ -331,7 +339,7 @@ if a is S.One: return C.exp(-z) elif a is S.Half: - return sqrt(pi)*(1 - erf(sqrt(z))) # TODO could use erfc... + return sqrt(pi)*(1 - erf(sqrt(z))) # TODO could use erfc... elif a.is_Integer or (2*a).is_Integer: b = a - 1 if b.is_positive: @@ -342,7 +350,6 @@ if not a.is_Integer: return (cls(a + 1, z) - z**a * C.exp(-z))/a - def _eval_rewrite_as_lowergamma(self, s, x): return gamma(s) - lowergamma(s, x) @@ -351,21 +358,44 @@ return expint(1 - s, x)*x**s - ############################################################################### ########################### GAMMA RELATED FUNCTIONS ########################### ############################################################################### - class polygamma(Function): - """The function `polygamma(n, z)` returns `log(gamma(z)).diff(n + 1)` + r"""The function ``polygamma(n, z)`` returns ``log(gamma(z)).diff(n + 1)`` + + .. math :: + \psi^{(n)}(z) = \frac{d^n}{d x^n} \log \Gamma(z) + + Examples + ======== + + We can rewrite polygamma functions in terms of harmonic numbers: - See Also - ======== + >>> from sympy import polygamma, harmonic, Symbol + >>> x = Symbol("x") - gamma, digamma, trigamma + >>> polygamma(0, x).rewrite(harmonic) + harmonic(x - 1) - EulerGamma - Reference: - http://en.wikipedia.org/wiki/Polygamma_function + >>> polygamma(2, x).rewrite(harmonic) + 2*harmonic(x - 1, 3) - 2*zeta(3) + + >>> ni = Symbol("n", integer=True) + >>> polygamma(ni, x).rewrite(harmonic) + (-1)**(n + 1)*(-harmonic(x - 1, n + 1) + zeta(n + 1))*factorial(n) + + See Also + ======== + + gamma, digamma, trigamma + + References + ========== + + .. [1] http://en.wikipedia.org/wiki/Polygamma_function + .. [2] http://functions.wolfram.com/GammaBetaErf/PolyGamma/ + .. [3] http://functions.wolfram.com/GammaBetaErf/PolyGamma2/ """ nargs = 2 @@ -373,7 +403,7 @@ def fdiff(self, argindex=2): if argindex == 2: n, z = self.args[:2] - return polygamma(n+1, z) + return polygamma(n + 1, z) else: raise ArgumentIndexError(self, argindex) @@ -390,7 +420,7 @@ def _eval_aseries(self, n, args0, x, logx): if args0[1] != oo or not \ - (self.args[0].is_Integer and self.args[0].is_nonnegative): + (self.args[0].is_Integer and self.args[0].is_nonnegative): return super(polygamma, self)._eval_aseries(n, args0, x, logx) z = self.args[1] N = self.args[0] @@ -403,7 +433,7 @@ if n < 2: o = C.Order(1/z, x) else: - m = C.ceiling((n+1)//2) + m = C.ceiling((n + 1)//2) l = [bernoulli(2*k) / (2*k*z**(2*k)) for k in range(1, m)] r -= Add(*l) o = C.Order(1/z**(2*m), x) @@ -416,9 +446,9 @@ # quite a long time! fac = gamma(N) e0 = fac + N*fac/(2*z) - m = C.ceiling((n+1)//2) + m = C.ceiling((n + 1)//2) for k in range(1, m): - fac = fac*(2*k+N-1)*(2*k+N-2) / ((2*k)*(2*k-1)) + fac = fac*(2*k + N - 1)*(2*k + N - 2) / ((2*k)*(2*k - 1)) e0 += bernoulli(2*k)*fac/z**(2*k) o = C.Order(1/z**(2*m), x) if n == 0: @@ -456,9 +486,9 @@ return S.ComplexInfinity else: if n is S.Zero: - return -S.EulerGamma + C.harmonic(z-1, 1) + return -S.EulerGamma + C.harmonic(z - 1, 1) elif n.is_odd: - return (-1)**(n+1)*C.factorial(n)*zeta(n+1, z) + return (-1)**(n + 1)*C.factorial(n)*zeta(n + 1, z) if n == 0 and z.is_Rational: # TODO actually *any* n/m can be done, but that is messy @@ -480,7 +510,6 @@ # TODO n == 1 also can do some rational z - def _eval_expand_func(self, **hints): n, z = self.args @@ -490,34 +519,56 @@ if coeff.is_Integer: e = -(n + 1) if coeff > 0: - tail = Add(*[C.Pow(z - i, e) for i in range(1, int(coeff) + 1)]) + tail = Add(*[C.Pow( + z - i, e) for i in range(1, int(coeff) + 1)]) else: - tail = -Add(*[C.Pow(z + i, e) for i in range(0, int(-coeff))]) + tail = -Add(*[C.Pow( + z + i, e) for i in range(0, int(-coeff))]) return polygamma(n, z - coeff) + (-1)**n*C.factorial(n)*tail elif z.is_Mul: coeff, z = z.as_two_terms() if coeff.is_Integer and coeff.is_positive: - tail = [ polygamma(n, z + C.Rational(i, coeff)) for i in range(0, int(coeff)) ] + tail = [ polygamma(n, z + C.Rational( + i, coeff)) for i in range(0, int(coeff)) ] if n == 0: return Add(*tail)/coeff + log(coeff) else: - return Add(*tail)/coeff**(n+1) + return Add(*tail)/coeff**(n + 1) z *= coeff return polygamma(n, z) def _eval_rewrite_as_zeta(self, n, z): - return (-1)**(n+1)*C.factorial(n)*zeta(n+1, z-1) + if n >= S.One: + return (-1)**(n + 1)*C.factorial(n)*zeta(n + 1, z) + else: + return self + + def _eval_rewrite_as_harmonic(self, n, z): + if n.is_integer: + if n == S.Zero: + return harmonic(z - 1) - S.EulerGamma + else: + return S.NegativeOne**(n+1) * C.factorial(n) * (C.zeta(n+1) - harmonic(z-1, n+1)) + + def _eval_as_leading_term(self, x): + n, z = [a.as_leading_term(x) for a in self.args] + o = C.Order(z, x) + if n == 0 and o.contains(1/x): + return o.getn() * log(x) + else: + return self.func(n, z) + class loggamma(Function): """ - The loggamma function is `ln(gamma(x))`. + The loggamma function is `\log(\Gamma(x))`. References ========== - http://mathworld.wolfram.com/LogGammaFunction.html + .. [1] http://mathworld.wolfram.com/LogGammaFunction.html """ @@ -527,14 +578,14 @@ if args0[0] != oo: return super(loggamma, self)._eval_aseries(n, args0, x, logx) z = self.args[0] - m = min(n, C.ceiling((n+S(1))/2)) - r = log(z)*(z-S(1)/2) - z + log(2*pi)/2 - l = [bernoulli(2*k) / (2*k*(2*k-1)*z**(2*k-1)) for k in range(1, m)] + m = min(n, C.ceiling((n + S(1))/2)) + r = log(z)*(z - S(1)/2) - z + log(2*pi)/2 + l = [bernoulli(2*k) / (2*k*(2*k - 1)*z**(2*k - 1)) for k in range(1, m)] o = None if m == 0: o = C.Order(1, x) else: - o = C.Order(1/z**(2*m-1), x) + o = C.Order(1/z**(2*m - 1), x) # It is very inefficient to first add the order and then do the nseries return (r + Add(*l))._eval_nseries(x, n, logx) + o @@ -550,12 +601,13 @@ else: raise ArgumentIndexError(self, argindex) + def digamma(x): """ The digamma function is the logarithmic derivative of the gamma function. - In this case, `digamma(x) = polygamma(0, x)`. + In this case, ``digamma(x) = polygamma(0, x)``. See Also ======== @@ -565,11 +617,12 @@ """ return polygamma(0, x) + def trigamma(x): """ The trigamma function is the second of the polygamma functions. - In this case, `trigamma(x) = polygamma(1, x)`. + In this case, ``trigamma(x) = polygamma(1, x)``. See Also ======== @@ -579,6 +632,7 @@ """ return polygamma(1, x) + def beta(x, y): """ Euler Beta function @@ -586,4 +640,4 @@ ``beta(x, y) == gamma(x)*gamma(y) / gamma(x+y)`` """ - return gamma(x)*gamma(y) / gamma(x+y) + return gamma(x)*gamma(y) / gamma(x + y) diff -Nru python3-sympy-0.7.2/sympy/functions/special/hyper.py python3-sympy-0.7.3/sympy/functions/special/hyper.py --- python3-sympy-0.7.2/sympy/functions/special/hyper.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/functions/special/hyper.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,6 +1,6 @@ """Hypergeometric and Meijer G-functions""" -from sympy.core import S, I, pi, oo, ilcm, Mod +from sympy.core import S, I, pi, oo, ilcm, Mod, C from sympy.core.function import Function, Derivative, ArgumentIndexError from sympy.core.containers import Tuple from sympy.core.mul import Mul @@ -9,9 +9,18 @@ sinh, cosh, asinh, acosh, atanh, acoth) from functools import reduce +class TupleArg(Tuple): + def limit(self, x, xlim, dir='+'): + """ Compute limit x->xlim. + """ + from sympy.series.limits import limit + return TupleArg(*[limit(f, x, xlim, dir) for f in self.args]) + + # TODO should __new__ accept **options? # TODO should constructors should check if parameters are sensible? + def _prep_tuple(v): """ Turn an iterable argument V into a Tuple and unpolarify, since both @@ -27,7 +36,8 @@ (7, 8, 9) """ from sympy.simplify.simplify import unpolarify - return Tuple(*[unpolarify(x) for x in v]) + return TupleArg(*[unpolarify(x) for x in v]) + class TupleParametersBase(Function): """ Base class that takes care of differentiation, when some of @@ -47,6 +57,7 @@ except (ArgumentIndexError, NotImplementedError): return Derivative(self, s) + class hyper(TupleParametersBase): r""" The (generalized) hypergeometric function is defined by a series where @@ -155,9 +166,9 @@ References ========== - - Luke, Y. L. (1969), The Special Functions and Their Approximations, - Volume 1 - - http://en.wikipedia.org/wiki/Generalized_hypergeometric_function + .. [1] Luke, Y. L. (1969), The Special Functions and Their Approximations, + Volume 1 + .. [2] http://en.wikipedia.org/wiki/Generalized_hypergeometric_function """ nargs = 3 @@ -190,6 +201,15 @@ return gamma(c)*gamma(c - a - b)/gamma(c - a)/gamma(c - b) return hyperexpand(self) + def _eval_rewrite_as_Sum(self, ap, bq, z): + from sympy.functions import factorial, RisingFactorial, Piecewise + n = C.Dummy("n", integer=True) + rfap = Tuple(*[RisingFactorial(a, n) for a in ap]) + rfbq = Tuple(*[RisingFactorial(b, n) for b in bq]) + coeff = Mul(*rfap) / Mul(*rfbq) + return Piecewise((C.Sum(coeff * z**n / factorial(n), (n, 0, oo)), + self.convergence_statement), (self, True)) + @property def argument(self): """ Argument of the hypergeometric function. """ @@ -198,12 +218,12 @@ @property def ap(self): """ Numerator parameters of the hypergeometric function. """ - return self.args[0] + return Tuple(*self.args[0]) @property def bq(self): """ Denominator parameters of the hypergeometric function. """ - return self.args[1] + return Tuple(*self.args[1]) @property def _diffargs(self): @@ -276,6 +296,7 @@ c3 = And(re(e) >= 1, abs(z) < 1) return Or(c1, c2, c3) + class meijerg(TupleParametersBase): r""" The Meijer G-function is defined by a Mellin-Barnes type integral that @@ -376,7 +397,8 @@ >>> from sympy import hyperexpand >>> from sympy.abc import a, b, c >>> hyperexpand(meijerg([a], [], [c], [b], x), allow_hyper=True) - x**c*gamma(-a + c + 1)*hyper((-a + c + 1,), (-b + c + 1,), -x)/gamma(-b + c + 1) + x**c*gamma(-a + c + 1)*hyper((-a + c + 1,), + (-b + c + 1,), -x)/gamma(-b + c + 1) Thus the Meijer G-function also subsumes many named functions as special cases. You can use expand_func or hyperexpand to (try to) rewrite a @@ -397,9 +419,9 @@ References ========== - - Luke, Y. L. (1969), The Special Functions and Their Approximations, - Volume 1 - - http://en.wikipedia.org/wiki/Meijer_G-function + .. [1] Luke, Y. L. (1969), The Special Functions and Their Approximations, + Volume 1 + .. [2] http://en.wikipedia.org/wiki/Meijer_G-function """ @@ -409,12 +431,13 @@ if len(args) == 5: args = [(args[0], args[1]), (args[2], args[3]), args[4]] if len(args) != 3: - raise TypeError("args must eiter be as, as', bs, bs', z or " \ + raise TypeError("args must eiter be as, as', bs, bs', z or " "as, bs, z") + def tr(p): if len(p) != 2: raise TypeError("wrong argument") - return Tuple(_prep_tuple(p[0]), _prep_tuple(p[1])) + return TupleArg(_prep_tuple(p[0]), _prep_tuple(p[1])) # TODO should we check convergence conditions? return Function.__new__(cls, tr(args[0]), tr(args[1]), args[2]) @@ -426,7 +449,7 @@ a = list(self.an) a[0] -= 1 G = meijerg(a, self.aother, self.bm, self.bother, self.argument) - return 1/self.argument * ((self.an[0]-1)*self + G) + return 1/self.argument * ((self.an[0] - 1)*self + G) elif len(self.bm) >= 1: b = list(self.bm) b[0] += 1 @@ -484,7 +507,7 @@ found = i break if found is None: - raise NotImplementedError('Derivative not expressible ' \ + raise NotImplementedError('Derivative not expressible ' 'as G-function?') y = l2[i] l2.pop(i) @@ -610,10 +633,10 @@ """ Get the defining integrand D(s). """ from sympy import gamma return self.argument**s \ - * Mul(*(gamma(b - s) for b in self.bm)) \ - * Mul(*(gamma(1 - a + s) for a in self.an)) \ - / Mul(*(gamma(1 - b + s) for b in self.bother)) \ - / Mul(*(gamma(a - s) for a in self.aother)) + * Mul(*(gamma(b - s) for b in self.bm)) \ + * Mul(*(gamma(1 - a + s) for a in self.an)) \ + / Mul(*(gamma(1 - b + s) for b in self.bother)) \ + / Mul(*(gamma(a - s) for a in self.aother)) @property def argument(self): @@ -623,32 +646,32 @@ @property def an(self): """ First set of numerator parameters. """ - return self.args[0][0] + return Tuple(*self.args[0][0]) @property def ap(self): """ Combined numerator parameters. """ - return self.args[0][0] + self.args[0][1] + return Tuple(*(self.args[0][0] + self.args[0][1])) @property def aother(self): """ Second set of numerator parameters. """ - return self.args[0][1] + return Tuple(*self.args[0][1]) @property def bm(self): """ First set of denominator parameters. """ - return self.args[1][0] + return Tuple(*self.args[1][0]) @property def bq(self): """ Combined denominator parameters. """ - return self.args[1][0] + self.args[1][1] + return Tuple(*(self.args[1][0] + self.args[1][1])) @property def bother(self): """ Second set of denominator parameters. """ - return self.args[1][1] + return Tuple(*self.args[1][1]) @property def _diffargs(self): @@ -666,6 +689,7 @@ c.f. references. """ return len(self.bm) + len(self.an) - S(len(self.ap) + len(self.bq))/2 + class HyperRep(Function): """ A base class for "hyper representation functions". @@ -737,6 +761,7 @@ return self._expr_small_minus(*args) return self._expr_small(*args) + class HyperRep_power1(HyperRep): """ Return a representative for hyper([-a], [], z) == (1 - z)**a. """ nargs = 2 @@ -761,6 +786,7 @@ return cls._expr_small_minus(a, x) return (1 + x)**a*exp(2*n*pi*I*a) + class HyperRep_power2(HyperRep): """ Return a representative for hyper([a, a - 1/2], [2*a], z). """ nargs = 2 @@ -780,7 +806,7 @@ sgn = 1 n -= 1 return 2**(2*a - 1)*(1 + sgn*I*sqrt(x - 1))**(1 - 2*a) \ - *exp(-2*n*pi*I*a) + *exp(-2*n*pi*I*a) @classmethod def _expr_big_minus(cls, a, x, n): @@ -789,6 +815,7 @@ sgn = -1 return sgn*2**(2*a - 1)*(sqrt(1 + x) + sgn)**(1 - 2*a)*exp(-2*pi*I*a*n) + class HyperRep_log1(HyperRep): """ Represent -z*hyper([1, 1], [2], z) == log(1 - z). """ @classmethod @@ -801,12 +828,13 @@ @classmethod def _expr_big(cls, x, n): - return log(x - 1) + (2*n-1)*pi*I + return log(x - 1) + (2*n - 1)*pi*I @classmethod def _expr_big_minus(cls, x, n): return log(1 + x) + 2*n*pi*I + class HyperRep_atanh(HyperRep): """ Represent hyper([1/2, 1], [3/2], z) == atanh(sqrt(z))/sqrt(z). """ @classmethod @@ -828,6 +856,7 @@ else: return (atan(sqrt(x)) - pi)/sqrt(x) + class HyperRep_asin1(HyperRep): """ Represent hyper([1/2, 1/2], [3/2], z) == asin(sqrt(z))/sqrt(z). """ @classmethod @@ -844,7 +873,8 @@ @classmethod def _expr_big_minus(cls, z, n): - return S(-1)**n*(asinh(sqrt(z))/sqrt(z)+n*pi*I/sqrt(z)) + return S(-1)**n*(asinh(sqrt(z))/sqrt(z) + n*pi*I/sqrt(z)) + class HyperRep_asin2(HyperRep): """ Represent hyper([1, 1], [3/2], z) == asin(sqrt(z))/sqrt(z)/sqrt(1-z). """ @@ -852,22 +882,22 @@ @classmethod def _expr_small(cls, z): return HyperRep_asin1._expr_small(z) \ - /HyperRep_power1._expr_small(S(1)/2, z) + /HyperRep_power1._expr_small(S(1)/2, z) @classmethod def _expr_small_minus(cls, z): return HyperRep_asin1._expr_small_minus(z) \ - /HyperRep_power1._expr_small_minus(S(1)/2, z) + /HyperRep_power1._expr_small_minus(S(1)/2, z) @classmethod def _expr_big(cls, z, n): return HyperRep_asin1._expr_big(z, n) \ - /HyperRep_power1._expr_big(S(1)/2, z, n) + /HyperRep_power1._expr_big(S(1)/2, z, n) @classmethod def _expr_big_minus(cls, z, n): return HyperRep_asin1._expr_big_minus(z, n) \ - /HyperRep_power1._expr_big_minus(S(1)/2, z, n) + /HyperRep_power1._expr_big_minus(S(1)/2, z, n) class HyperRep_sqrts1(HyperRep): @@ -929,7 +959,8 @@ return (1 + z)**a*exp(2*pi*I*n*a)*sqrt(z)*sin(2*a*atan(sqrt(z))) else: return (1 + z)**a*exp(2*pi*I*n*a)*sqrt(z) \ - *sin(2*a*atan(sqrt(z)) - 2*pi*a) + *sin(2*a*atan(sqrt(z)) - 2*pi*a) + class HyperRep_log2(HyperRep): """ Represent log(1/2 + sqrt(1 - z)/2) == -z/4*hyper([3/2, 1, 1], [2, 2], z) """ diff -Nru python3-sympy-0.7.2/sympy/functions/special/polynomials.py python3-sympy-0.7.3/sympy/functions/special/polynomials.py --- python3-sympy-0.7.2/sympy/functions/special/polynomials.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/functions/special/polynomials.py 2013-07-13 17:53:32.000000000 +0000 @@ -11,6 +11,8 @@ from sympy.core import Rational from sympy.core.function import Function, ArgumentIndexError from sympy.functions.elementary.miscellaneous import sqrt +from sympy.functions.special.gamma_functions import gamma +from sympy.functions.combinatorial.factorials import factorial from sympy.polys.orthopolys import ( jacobi_poly, @@ -42,6 +44,7 @@ # Jacobi polynomials # + class jacobi(OrthogonalPolynomial): r""" Jacobi polynomial :math:`P_n^{\left(\alpha, \beta\right)}(x)` @@ -70,24 +73,25 @@ jacobi(n, a, b, x) >>> jacobi(n, a, a, x) - RisingFactorial(a + 1, n)*gegenbauer(n, a + 1/2, x)/RisingFactorial(2*a + 1, n) + RisingFactorial(a + 1, n)*gegenbauer(n, + a + 1/2, x)/RisingFactorial(2*a + 1, n) >>> jacobi(n, 0, 0, x) legendre(n, x) >>> jacobi(n, S(1)/2, S(1)/2, x) - RisingFactorial(3/2, n)*chebyshevu(n, x)/(n + 1)! + RisingFactorial(3/2, n)*chebyshevu(n, x)/factorial(n + 1) >>> jacobi(n, -S(1)/2, -S(1)/2, x) - RisingFactorial(1/2, n)*chebyshevt(n, x)/n! + RisingFactorial(1/2, n)*chebyshevt(n, x)/factorial(n) >>> jacobi(n, a, b, -x) (-1)**n*jacobi(n, b, a, x) >>> jacobi(n, a, b, 0) - 2**(-n)*gamma(a + n + 1)*hyper((-b - n, -n), (a + 1,), -1)/(n!*gamma(a + 1)) + 2**(-n)*gamma(a + n + 1)*hyper((-b - n, -n), (a + 1,), -1)/(factorial(n)*gamma(a + 1)) >>> jacobi(n, a, b, 1) - RisingFactorial(a + 1, n)/n! + RisingFactorial(a + 1, n)/factorial(n) >>> conjugate(jacobi(n, a, b, x)) jacobi(n, conjugate(a), conjugate(b), conjugate(x)) @@ -131,15 +135,15 @@ elif a == S.Zero: return legendre(n, x) elif a == S.Half: - return C.RisingFactorial(3*S.Half, n) / C.factorial(n+1) * chebyshevu(n, x) + return C.RisingFactorial(3*S.Half, n) / C.factorial(n + 1) * chebyshevu(n, x) else: - return C.RisingFactorial(a+1, n) / C.RisingFactorial(2*a+1, n) * gegenbauer(n, a+S.Half, x) + return C.RisingFactorial(a + 1, n) / C.RisingFactorial(2*a + 1, n) * gegenbauer(n, a + S.Half, x) elif b == -a: # P^{a, -a}_n(x) - return C.gamma(n+a+1) / C.gamma(n+1) * (1+x)**(a/2) / (1-x)**(a/2) * assoc_legendre(n, -a, x) + return C.gamma(n + a + 1) / C.gamma(n + 1) * (1 + x)**(a/2) / (1 - x)**(a/2) * assoc_legendre(n, -a, x) elif a == -b: # P^{-b, b}_n(x) - return C.gamma(n-b+1) / C.gamma(n+1) * (1-x)**(b/2) / (1+x)**(b/2) * assoc_legendre(n, b, x) + return C.gamma(n - b + 1) / C.gamma(n + 1) * (1 - x)**(b/2) / (1 + x)**(b/2) * assoc_legendre(n, b, x) if not n.is_Number: # Symbolic result P^{a,b}_n(x) @@ -148,14 +152,14 @@ return S.NegativeOne**n * jacobi(n, b, a, -x) # We can evaluate for some special values of x if x == S.Zero: - return (2**(-n) * C.gamma(a+n+1) / (C.gamma(a+1) * C.factorial(n)) * - C.hyper([-b-n, -n], [a+1], -1)) + return (2**(-n) * C.gamma(a + n + 1) / (C.gamma(a + 1) * C.factorial(n)) * + C.hyper([-b - n, -n], [a + 1], -1)) if x == S.One: - return C.RisingFactorial(a+1, n) / C.factorial(n) + return C.RisingFactorial(a + 1, n) / C.factorial(n) elif x == S.Infinity: if n.is_positive: # TODO: Make sure a+b+2*n \notin Z - return C.RisingFactorial(a+b+n+1, n) * S.Infinity + return C.RisingFactorial(a + b + n + 1, n) * S.Infinity else: # n is a given fixed integer, evaluate into polynomial return jacobi_poly(n, a, b, x) @@ -169,39 +173,99 @@ n, a, b, x = self.args k = C.Dummy("k") f1 = 1 / (a + b + n + k + 1) - f2 = ((a + b + 2*k + 1) * C.RisingFactorial(b + k + 1, n-k) / - ((n - k) * C.RisingFactorial(a + b + k + 1, n-k))) - return C.Sum(f1 * (jacobi(n,a,b,x) + f2*jacobi(k,a,b,x)) , (k,0,n-1)) + f2 = ((a + b + 2*k + 1) * C.RisingFactorial(b + k + 1, n - k) / + ((n - k) * C.RisingFactorial(a + b + k + 1, n - k))) + return C.Sum(f1 * (jacobi(n, a, b, x) + f2*jacobi(k, a, b, x)), (k, 0, n - 1)) elif argindex == 3: # Diff wrt b n, a, b, x = self.args k = C.Dummy("k") f1 = 1 / (a + b + n + k + 1) - f2 = (-1)**(n-k) * ((a + b + 2*k + 1) * C.RisingFactorial(a + k + 1, n-k) / - ((n - k) * C.RisingFactorial(a + b + k + 1, n-k))) - return C.Sum(f1 * (jacobi(n,a,b,x) + f2*jacobi(k,a,b,x)) , (k,0,n-1)) + f2 = (-1)**(n - k) * ((a + b + 2*k + 1) * C.RisingFactorial(a + k + 1, n - k) / + ((n - k) * C.RisingFactorial(a + b + k + 1, n - k))) + return C.Sum(f1 * (jacobi(n, a, b, x) + f2*jacobi(k, a, b, x)), (k, 0, n - 1)) elif argindex == 4: # Diff wrt x n, a, b, x = self.args - return S.Half * (a + b + n + 1) * jacobi(n-1, a+1, b+1, x) + return S.Half * (a + b + n + 1) * jacobi(n - 1, a + 1, b + 1, x) else: raise ArgumentIndexError(self, argindex) def _eval_rewrite_as_polynomial(self, n, a, b, x): # TODO: Make sure n \in N k = C.Dummy("k") - kern = (C.RisingFactorial(-n, k) * C.RisingFactorial(a+b+n+1, k) * C.RisingFactorial(a+k+1, n-k) / - C.factorial(k) * ((1-x)/2)**k) + kern = (C.RisingFactorial(-n, k) * C.RisingFactorial(a + b + n + 1, k) * C.RisingFactorial(a + k + 1, n - k) / + C.factorial(k) * ((1 - x)/2)**k) return 1 / C.factorial(n) * C.Sum(kern, (k, 0, n)) def _eval_conjugate(self): n, a, b, x = self.args return self.func(n, a.conjugate(), b.conjugate(), x.conjugate()) + +def jacobi_normalized(n, a, b, x): + r""" + Jacobi polynomial :math:`P_n^{\left(\alpha, \beta\right)}(x)` + + jacobi_normalized(n, alpha, beta, x) gives the nth Jacobi polynomial + in x, :math:`P_n^{\left(\alpha, \beta\right)}(x)`. + + The Jacobi polynomials are orthogonal on :math:`[-1, 1]` with respect + to the weight :math:`\left(1-x\right)^\alpha \left(1+x\right)^\beta`. + + This functions returns the polynomials normilzed: + + .. math:: + + \int_{-1}^{1} + P_m^{\left(\alpha, \beta\right)}(x) + P_n^{\left(\alpha, \beta\right)}(x) + (1-x)^{\alpha} (1+x)^{\beta} \mathrm{d}x + = \delta_{m,n} + + Examples + ======== + + >>> from sympy import jacobi_normalized + >>> from sympy.abc import n,a,b,x + + >>> jacobi_normalized(n, a, b, x) + jacobi(n, a, b, x)/sqrt(2**(a + b + 1)*gamma(a + n + 1)*gamma(b + n + 1)/((a + b + 2*n + 1)*factorial(n)*gamma(a + b + n + 1))) + + See Also + ======== + + gegenbauer, + chebyshevt_root, chebyshevu, chebyshevu_root, + legendre, assoc_legendre, + hermite, + laguerre, assoc_laguerre, + sympy.polys.orthopolys.jacobi_poly, + sympy.polys.orthopolys.gegenbauer_poly + sympy.polys.orthopolys.chebyshevt_poly + sympy.polys.orthopolys.chebyshevu_poly + sympy.polys.orthopolys.hermite_poly + sympy.polys.orthopolys.legendre_poly + sympy.polys.orthopolys.laguerre_poly + + References + ========== + + .. [1] http://en.wikipedia.org/wiki/Jacobi_polynomials + .. [2] http://mathworld.wolfram.com/JacobiPolynomial.html + .. [3] http://functions.wolfram.com/Polynomials/JacobiP/ + """ + nfactor = (S(2)**(a + b + 1) * (gamma(n + a + 1) * gamma(n + b + 1)) + / (2*n + a + b + 1) / (factorial(n) * gamma(n + a + b + 1))) + + return jacobi(n, a, b, x) / sqrt(nfactor) + + #---------------------------------------------------------------------------- # Gegenbauer polynomials # + class gegenbauer(OrthogonalPolynomial): r""" Gegenbauer polynomial :math:`C_n^{\left(\alpha\right)}(x)` @@ -301,12 +365,12 @@ # We can evaluate for some special values of x if x == S.Zero: return (2**n * sqrt(S.Pi) * C.gamma(a + S.Half*n) / - (C.gamma((1-n)/2) * C.gamma(n+1) * C.gamma(a)) ) + (C.gamma((1 - n)/2) * C.gamma(n + 1) * C.gamma(a)) ) if x == S.One: - return C.gamma(2*a+n) / (C.gamma(2*a) * C.gamma(n+1)) + return C.gamma(2*a + n) / (C.gamma(2*a) * C.gamma(n + 1)) elif x == S.Infinity: if n.is_positive: - return C.RisingFactorial(a,n) * S.Infinity + return C.RisingFactorial(a, n) * S.Infinity else: # n is a given fixed integer, evaluate into polynomial return gegenbauer_poly(n, a, x) @@ -319,21 +383,23 @@ # Diff wrt a n, a, x = self.args k = C.Dummy("k") - factor1 = 2 * (1 + (-1)**(n-k)) * (k + a) / ((k + n + 2*a) * (n - k)) - factor2 = 2*(k+1) / ((k + 2*a) * (2*k + 2*a + 1)) + 2 / (k + n + 2*a) + factor1 = 2 * (1 + (-1)**(n - k)) * (k + a) / ((k + + n + 2*a) * (n - k)) + factor2 = 2*(k + 1) / ((k + 2*a) * (2*k + 2*a + 1)) + \ + 2 / (k + n + 2*a) kern = factor1*gegenbauer(k, a, x) + factor2*gegenbauer(n, a, x) - return C.Sum(kern, (k, 0, n-1)) + return C.Sum(kern, (k, 0, n - 1)) elif argindex == 3: # Diff wrt x n, a, x = self.args - return 2*a*gegenbauer(n-1, a+1, x) + return 2*a*gegenbauer(n - 1, a + 1, x) else: raise ArgumentIndexError(self, argindex) def _eval_rewrite_as_polynomial(self, n, a, x): k = C.Dummy("k") - kern = ((-1)**k * C.RisingFactorial(a, n-k) * (2*x)**(n-2*k) / - (C.factorial(k) * C.factorial(n-2*k))) + kern = ((-1)**k * C.RisingFactorial(a, n - k) * (2*x)**(n - 2*k) / + (C.factorial(k) * C.factorial(n - 2*k))) return C.Sum(kern, (k, 0, C.floor(n/2))) def _eval_conjugate(self): @@ -344,6 +410,7 @@ # Chebyshev polynomials of first and second kind # + class chebyshevt(OrthogonalPolynomial): r""" Chebyshev polynomial of the first kind, :math:`T_n(x)` @@ -415,10 +482,10 @@ # Symbolic result T_n(x) # T_n(-x) ---> (-1)**n * T_n(x) if x.could_extract_minus_sign(): - return S.NegativeOne**n * chebyshevt(n,-x) + return S.NegativeOne**n * chebyshevt(n, -x) # T_{-n}(x) ---> T_n(x) if n.could_extract_minus_sign(): - return chebyshevt(-n,x) + return chebyshevt(-n, x) # We can evaluate for some special values of x if x == S.Zero: return C.cos(S.Half * S.Pi * n) @@ -441,15 +508,16 @@ elif argindex == 2: # Diff wrt x n, x = self.args - return n * chebyshevu(n-1, x) + return n * chebyshevu(n - 1, x) else: raise ArgumentIndexError(self, argindex) def _eval_rewrite_as_polynomial(self, n, x): k = C.Dummy("k") - kern = C.binomial(n, 2*k) * (x**2 - 1)**k * x**(n-2*k) + kern = C.binomial(n, 2*k) * (x**2 - 1)**k * x**(n - 2*k) return C.Sum(kern, (k, 0, C.floor(n/2))) + class chebyshevu(OrthogonalPolynomial): r""" Chebyshev polynomial of the second kind, :math:`U_n(x)` @@ -521,13 +589,13 @@ # Symbolic result U_n(x) # U_n(-x) ---> (-1)**n * U_n(x) if x.could_extract_minus_sign(): - return S.NegativeOne**n * chebyshevu(n,-x) + return S.NegativeOne**n * chebyshevu(n, -x) # U_{-n}(x) ---> -U_{n-2}(x) if n.could_extract_minus_sign(): if n == S.NegativeOne: return S.Zero else: - return -chebyshevu(-n-2,x) + return -chebyshevu(-n - 2, x) # We can evaluate for some special values of x if x == S.Zero: return C.cos(S.Half * S.Pi * n) @@ -542,7 +610,7 @@ if n == S.NegativeOne: return S.Zero else: - return -cls._eval_at_order(-n-2, x) + return -cls._eval_at_order(-n - 2, x) else: return cls._eval_at_order(n, x) @@ -553,15 +621,17 @@ elif argindex == 2: # Diff wrt x n, x = self.args - return ((n+1) * chebyshevt(n+1, x) - x * chebyshevu(n,x)) / (x**2 - 1) + return ((n + 1) * chebyshevt(n + 1, x) - x * chebyshevu(n, x)) / (x**2 - 1) else: raise ArgumentIndexError(self, argindex) def _eval_rewrite_as_polynomial(self, n, x): k = C.Dummy("k") - kern = S.NegativeOne**k * C.factorial(n-k) * (2*x)**(n-2*k) / (C.factorial(k) * C.factorial(n-2*k)) + kern = S.NegativeOne**k * C.factorial( + n - k) * (2*x)**(n - 2*k) / (C.factorial(k) * C.factorial(n - 2*k)) return C.Sum(kern, (k, 0, C.floor(n/2))) + class chebyshevt_root(Function): r""" chebyshev_root(n, k) returns the kth root (indexed from zero) of @@ -600,7 +670,8 @@ def eval(cls, n, k): if not 0 <= k < n: raise ValueError("must have 0 <= k < n") - return C.cos(S.Pi*(2*k+1)/(2*n)) + return C.cos(S.Pi*(2*k + 1)/(2*n)) + class chebyshevu_root(Function): r""" @@ -639,12 +710,13 @@ def eval(cls, n, k): if not 0 <= k < n: raise ValueError("must have 0 <= k < n") - return C.cos(S.Pi*(k+1)/(n+1)) + return C.cos(S.Pi*(k + 1)/(n + 1)) #---------------------------------------------------------------------------- # Legendre polynomials and Associated Legendre polynomials # + class legendre(OrthogonalPolynomial): r""" legendre(n, x) gives the nth Legendre polynomial of x, :math:`P_n(x)` @@ -702,10 +774,10 @@ # Symbolic result L_n(x) # L_n(-x) ---> (-1)**n * L_n(x) if x.could_extract_minus_sign(): - return S.NegativeOne**n * legendre(n,-x) + return S.NegativeOne**n * legendre(n, -x) # L_{-n}(x) ---> L_{n-1}(x) if n.could_extract_minus_sign(): - return legendre(-n - S.One,x) + return legendre(-n - S.One, x) # We can evaluate for some special values of x if x == S.Zero: return sqrt(S.Pi)/(C.gamma(S.Half - n/2)*C.gamma(S.One + n/2)) @@ -716,7 +788,8 @@ else: # n is a given fixed integer, evaluate into polynomial if n.is_negative: - raise ValueError("The index n must be nonnegative integer (got %r)" % n) + raise ValueError( + "The index n must be nonnegative integer (got %r)" % n) else: return cls._eval_at_order(n, x) @@ -737,6 +810,7 @@ kern = (-1)**k*C.binomial(n, k)**2*((1 + x)/2)**(n - k)*((1 - x)/2)**k return C.Sum(kern, (k, 0, n)) + class assoc_legendre(Function): r""" assoc_legendre(n,m, x) gives :math:`P_n^m(x)`, where n and m are @@ -826,19 +900,21 @@ # Diff wrt x # Find better formula, this is unsuitable for x = 1 n, m, x = self.args - return 1/(x**2 - 1)*(x*n*assoc_legendre(n,m,x) - (m + n)*assoc_legendre(n - 1,m,x)) + return 1/(x**2 - 1)*(x*n*assoc_legendre(n, m, x) - (m + n)*assoc_legendre(n - 1, m, x)) else: raise ArgumentIndexError(self, argindex) def _eval_rewrite_as_polynomial(self, n, m, x): k = C.Dummy("k") - kern = C.factorial(2*n - 2*k)/(2**n*C.factorial(n - k)*C.factorial(k)*C.factorial(n - 2*k - m))*(-1)**k*x**(n - m - 2*k) + kern = C.factorial(2*n - 2*k)/(2**n*C.factorial(n - k)*C.factorial( + k)*C.factorial(n - 2*k - m))*(-1)**k*x**(n - m - 2*k) return (1 - x**2)**(m/2) * C.Sum(kern, (k, 0, C.floor((n - m)*S.Half))) #---------------------------------------------------------------------------- # Hermite polynomials # + class hermite(OrthogonalPolynomial): r""" hermite(n, x) gives the nth Hermite polynomial in x, :math:`H_n(x)` @@ -897,7 +973,7 @@ # Symbolic result H_n(x) # H_n(-x) ---> (-1)**n * H_n(x) if x.could_extract_minus_sign(): - return S.NegativeOne**n * hermite(n,-x) + return S.NegativeOne**n * hermite(n, -x) # We can evaluate for some special values of x if x == S.Zero: return 2**n * sqrt(S.Pi) / C.gamma((S.One - n)/2) @@ -906,7 +982,8 @@ else: # n is a given fixed integer, evaluate into polynomial if n.is_negative: - raise ValueError("The index n must be nonnegative integer (got %r)" % n) + raise ValueError( + "The index n must be nonnegative integer (got %r)" % n) else: return cls._eval_at_order(n, x) @@ -917,19 +994,20 @@ elif argindex == 2: # Diff wrt x n, x = self.args - return 2*n*hermite(n-1, x) + return 2*n*hermite(n - 1, x) else: raise ArgumentIndexError(self, argindex) def _eval_rewrite_as_polynomial(self, n, x): k = C.Dummy("k") - kern = (-1)**k / (C.factorial(k)*C.factorial(n-2*k)) * (2*x)**(n-2*k) + kern = (-1)**k / (C.factorial(k)*C.factorial(n - 2*k)) * (2*x)**(n - 2*k) return C.factorial(n)*C.Sum(kern, (k, 0, C.floor(n/2))) #---------------------------------------------------------------------------- # Laguerre polynomials # + class laguerre(OrthogonalPolynomial): r""" Returns the nth Laguerre polynomial in x, :math:`L_n(x)`. @@ -992,7 +1070,7 @@ # L_{n}(-x) ---> exp(-x) * L_{-n-1}(x) # L_{-n}(x) ---> exp(x) * L_{n-1}(-x) if n.could_extract_minus_sign(): - return C.exp(x) * laguerre(n-1, -x) + return C.exp(x) * laguerre(n - 1, -x) # We can evaluate for some special values of x if x == S.Zero: return S.One @@ -1003,7 +1081,8 @@ else: # n is a given fixed integer, evaluate into polynomial if n.is_negative: - raise ValueError("The index n must be nonnegative integer (got %r)" % n) + raise ValueError( + "The index n must be nonnegative integer (got %r)" % n) else: return laguerre_poly(n, x, 0) @@ -1014,14 +1093,14 @@ elif argindex == 2: # Diff wrt x n, x = self.args - return -assoc_laguerre(n-1, 1, x) + return -assoc_laguerre(n - 1, 1, x) else: raise ArgumentIndexError(self, argindex) def _eval_rewrite_as_polynomial(self, n, x): # TODO: Should make sure n is in N_0 k = C.Dummy("k") - kern = C.RisingFactorial(-n,k) / C.factorial(k)**2 * x**k + kern = C.RisingFactorial(-n, k) / C.factorial(k)**2 * x**k return C.Sum(kern, (k, 0, n)) @@ -1051,7 +1130,8 @@ >>> assoc_laguerre(2, a, x) a**2/2 + 3*a/2 + x**2/2 + x*(-a - 2) + 1 >>> assoc_laguerre(3, a, x) - a**3/6 + a**2 + 11*a/6 - x**3/6 + x**2*(a/2 + 3/2) + x*(-a**2/2 - 5*a/2 - 3) + 1 + a**3/6 + a**2 + 11*a/6 - x**3/6 + x**2*(a/2 + 3/2) + + x*(-a**2/2 - 5*a/2 - 3) + 1 >>> assoc_laguerre(n, a, 0) binomial(a + n, a) @@ -1104,7 +1184,7 @@ if not n.is_Number: # We can evaluate for some special values of x if x == S.Zero: - return C.binomial(n+alpha, alpha) + return C.binomial(n + alpha, alpha) elif x == S.Infinity and n > S.Zero: return S.NegativeOne**n * S.Infinity elif x == S.NegativeInfinity and n > S.Zero: @@ -1112,7 +1192,8 @@ else: # n is a given fixed integer, evaluate into polynomial if n.is_negative: - raise ValueError("The index n must be nonnegative integer (got %r)" % n) + raise ValueError( + "The index n must be nonnegative integer (got %r)" % n) else: return laguerre_poly(n, x, alpha) @@ -1124,16 +1205,17 @@ # Diff wrt alpha n, alpha, x = self.args k = C.Dummy("k") - return C.Sum(assoc_laguerre(k, alpha, x) / (n-alpha), (k, 0, n-1)) + return C.Sum(assoc_laguerre(k, alpha, x) / (n - alpha), (k, 0, n - 1)) elif argindex == 3: # Diff wrt x n, alpha, x = self.args - return -assoc_laguerre(n-1, alpha+1, x) + return -assoc_laguerre(n - 1, alpha + 1, x) else: raise ArgumentIndexError(self, argindex) def _eval_rewrite_as_polynomial(self, n, x): # TODO: Should make sure n is in N_0 k = C.Dummy("k") - kern = C.RisingFactorial(-n,k) / (C.gamma(k + alpha + 1) * C.factorial(k)) * x**k + kern = C.RisingFactorial( + -n, k) / (C.gamma(k + alpha + 1) * C.factorial(k)) * x**k return C.gamma(n + alpha + 1) / C.factorial(n) * C.Sum(kern, (k, 0, n)) diff -Nru python3-sympy-0.7.2/sympy/functions/special/spherical_harmonics.py python3-sympy-0.7.3/sympy/functions/special/spherical_harmonics.py --- python3-sympy-0.7.2/sympy/functions/special/spherical_harmonics.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/functions/special/spherical_harmonics.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,65 +1,309 @@ -from sympy import C, pi, I +from sympy import pi, I +from sympy.core.basic import C +from sympy.core.singleton import S from sympy.core import Dummy, sympify -from sympy.functions import legendre, assoc_legendre +from sympy.core.function import Function, ArgumentIndexError +from sympy.functions import assoc_legendre +from sympy.functions.elementary.trigonometric import sin, cos +from sympy.functions.elementary.complexes import Abs from sympy.functions.elementary.miscellaneous import sqrt -Pl = legendre -Plm= assoc_legendre - _x = Dummy("x") -def Plmcos(l, m, th): - """ - Plm(cos(th)). - """ - l = sympify(l) - m = sympify(m) - sin = C.sin - cos = C.cos - P = Plm(l, m, _x).subs(_x, cos(th)) - # assume th in (0,pi) => sin(th) is nonnegative - _sinth = Dummy("_sinth", nonnegative=True) - P = P.subs(1-cos(th)**2, _sinth**2).subs(_sinth, sin(th)) - return P +class Ynm(Function): + r""" + Spherical harmonics defined as -def Ylm(l, m, theta, phi): - """ - Spherical harmonics Ylm. + .. math:: + Y_n^m(\theta, \varphi) := \sqrt{\frac{(2n+1)(n-m)!}{4\pi(n+m)!}} + \exp(i m \varphi) + \mathrm{P}_n^m\left(\cos(\theta)\right) + + Ynm() gives the spherical harmonic function of order `n` and `m` + in `\theta` and `\varphi`, `Y_n^m(\theta, \varphi)`. The four + parameters are as follows: `n \geq 0` an integer and `m` an integer + such that `-n \leq m \leq n` holds. The two angles are real-valued + with `\theta \in [0, \pi]` and `\varphi \in [0, 2\pi]`. Examples ======== - >>> from sympy import symbols, Ylm - >>> theta, phi = symbols("theta phi") - >>> Ylm(0, 0, theta, phi) + >>> from sympy import Ynm, Symbol + >>> from sympy.abc import n,m + >>> theta = Symbol("theta") + >>> phi = Symbol("phi") + + >>> Ynm(n, m, theta, phi) + Ynm(n, m, theta, phi) + + Several symmetries are known, for the order + + >>> from sympy import Ynm, Symbol + >>> from sympy.abc import n,m + >>> theta = Symbol("theta") + >>> phi = Symbol("phi") + + >>> Ynm(n, -m, theta, phi) + (-1)**m*exp(-2*I*m*phi)*Ynm(n, m, theta, phi) + + as well as for the angles + + >>> from sympy import Ynm, Symbol, simplify + >>> from sympy.abc import n,m + >>> theta = Symbol("theta") + >>> phi = Symbol("phi") + + >>> Ynm(n, m, -theta, phi) + Ynm(n, m, theta, phi) + + >>> Ynm(n, m, theta, -phi) + exp(-2*I*m*phi)*Ynm(n, m, theta, phi) + + For specific integers n and m we can evalute the harmonics + to more useful expressions + + >>> simplify(Ynm(0, 0, theta, phi).expand(func=True)) 1/(2*sqrt(pi)) - >>> Ylm(1, -1, theta, phi) + + >>> simplify(Ynm(1, -1, theta, phi).expand(func=True)) sqrt(6)*exp(-I*phi)*sin(theta)/(4*sqrt(pi)) - >>> Ylm(1, 0, theta, phi) + + >>> simplify(Ynm(1, 0, theta, phi).expand(func=True)) sqrt(3)*cos(theta)/(2*sqrt(pi)) + >>> simplify(Ynm(1, 1, theta, phi).expand(func=True)) + -sqrt(6)*exp(I*phi)*sin(theta)/(4*sqrt(pi)) + + >>> simplify(Ynm(2, -2, theta, phi).expand(func=True)) + sqrt(30)*exp(-2*I*phi)*sin(theta)**2/(8*sqrt(pi)) + + >>> simplify(Ynm(2, -1, theta, phi).expand(func=True)) + sqrt(30)*exp(-I*phi)*sin(2*theta)/(8*sqrt(pi)) + + >>> simplify(Ynm(2, 0, theta, phi).expand(func=True)) + sqrt(5)*(3*cos(theta)**2 - 1)/(4*sqrt(pi)) + + >>> simplify(Ynm(2, 1, theta, phi).expand(func=True)) + -sqrt(30)*exp(I*phi)*sin(2*theta)/(8*sqrt(pi)) + + >>> simplify(Ynm(2, 2, theta, phi).expand(func=True)) + sqrt(30)*exp(2*I*phi)*sin(theta)**2/(8*sqrt(pi)) + + We can differentiate the functions with respect + to both angles + + >>> from sympy import Ynm, Symbol, diff + >>> from sympy.abc import n,m + >>> theta = Symbol("theta") + >>> phi = Symbol("phi") + + >>> diff(Ynm(n, m, theta, phi), theta) + m*cot(theta)*Ynm(n, m, theta, phi) + sqrt((-m + n)*(m + n + 1))*exp(-I*phi)*Ynm(n, m + 1, theta, phi) + + >>> diff(Ynm(n, m, theta, phi), phi) + I*m*Ynm(n, m, theta, phi) + + Further we can compute the complex conjugation + + >>> from sympy import Ynm, Symbol, conjugate + >>> from sympy.abc import n,m + >>> theta = Symbol("theta") + >>> phi = Symbol("phi") + + >>> conjugate(Ynm(n, m, theta, phi)) + (-1)**(2*m)*exp(-2*I*m*phi)*Ynm(n, m, theta, phi) + + To get back the well known expressions in spherical + coordinates we use full expansion + + >>> from sympy import Ynm, Symbol, expand_func + >>> from sympy.abc import n,m + >>> theta = Symbol("theta") + >>> phi = Symbol("phi") + + >>> expand_func(Ynm(n, m, theta, phi)) + sqrt((2*n + 1)*factorial(-m + n)/factorial(m + n))*exp(I*m*phi)*assoc_legendre(n, m, cos(theta))/(2*sqrt(pi)) + + See Also + ======== + + Ynm_c, Znm + + References + ========== + + .. [1] http://en.wikipedia.org/wiki/Spherical_harmonics + .. [2] http://mathworld.wolfram.com/SphericalHarmonic.html + .. [3] http://functions.wolfram.com/Polynomials/SphericalHarmonicY/ + .. [4] http://dlmf.nist.gov/14.30 """ - l, m, theta, phi = [sympify(x) for x in (l, m, theta, phi)] - factorial = C.factorial - return sqrt((2*l+1)/(4*pi) * factorial(l-m)/factorial(l+m)) * \ - Plmcos(l, m, theta) * C.exp(I*m*phi) - -def Ylm_c(l, m, theta, phi): - """Conjugate spherical harmonics.""" - return (-1)**m * Ylm(l, -m, theta, phi) -def Zlm(l, m, th, ph): + nargs = 4 + + @classmethod + def eval(cls, n, m, theta, phi): + n, m, theta, phi = [sympify(x) for x in (n, m, theta, phi)] + + # Handle negative index m and arguments theta, phi + if m.could_extract_minus_sign(): + m = -m + return S.NegativeOne**m * C.exp(-2*I*m*phi) * Ynm(n, m, theta, phi) + if theta.could_extract_minus_sign(): + theta = -theta + return Ynm(n, m, theta, phi) + if phi.could_extract_minus_sign(): + phi = -phi + return C.exp(-2*I*m*phi) * Ynm(n, m, theta, phi) + + # TODO Add more simplififcation here + + def _eval_expand_func(self, **hints): + n, m, theta, phi = self.args + return (sqrt((2*n + 1)/(4*pi) * C.factorial(n - m)/C.factorial(n + m)) * + C.exp(I*m*phi) * assoc_legendre(n, m, C.cos(theta))) + + def fdiff(self, argindex=4): + if argindex == 1: + # Diff wrt n + raise ArgumentIndexError(self, argindex) + elif argindex == 2: + # Diff wrt m + raise ArgumentIndexError(self, argindex) + elif argindex == 3: + # Diff wrt theta + n, m, theta, phi = self.args + return (m * C.cot(theta) * Ynm(n, m, theta, phi) + + sqrt((n - m)*(n + m + 1)) * C.exp(-I*phi) * Ynm(n, m + 1, theta, phi)) + elif argindex == 4: + # Diff wrt phi + n, m, theta, phi = self.args + return I * m * Ynm(n, m, theta, phi) + else: + raise ArgumentIndexError(self, argindex) + + def _eval_rewrite_as_polynomial(self, n, m, theta, phi): + # TODO: Make sure n \in N + # TODO: Assert |m| <= n ortherwise we should return 0 + return self.expand(func=True) + + def _eval_rewrite_as_sin(self, n, m, theta, phi): + return self.rewrite(cos) + + def _eval_rewrite_as_cos(self, n, m, theta, phi): + # This method can be expensive due to extensive use of simplification! + from sympy.simplify import simplify, trigsimp + # TODO: Make sure n \in N + # TODO: Assert |m| <= n ortherwise we should return 0 + term = simplify(self.expand(func=True)) + # We can do this because of the range of theta + term = term.xreplace({Abs(sin(theta)):sin(theta)}) + return simplify(trigsimp(term)) + + def _eval_conjugate(self): + # TODO: Make sure theta \in R and phi \in R + n, m, theta, phi = self.args + return S.NegativeOne**m * self.func(n, -m, theta, phi) + + def as_real_imag(self, deep=True, **hints): + # TODO: Handle deep and hints + n, m, theta, phi = self.args + re = (sqrt((2*n + 1)/(4*pi) * C.factorial(n - m)/C.factorial(n + m)) * + C.cos(m*phi) * assoc_legendre(n, m, C.cos(theta))) + im = (sqrt((2*n + 1)/(4*pi) * C.factorial(n - m)/C.factorial(n + m)) * + C.sin(m*phi) * assoc_legendre(n, m, C.cos(theta))) + return (re, im) + + def _eval_evalf(self, prec): + # Note: works without this function by just calling + # mpmath for Legendre polynomials. But using + # the dedicated function directly is cleaner. + from sympy.mpmath import mp + from sympy import Expr + n = self.args[0]._to_mpmath(prec) + m = self.args[1]._to_mpmath(prec) + theta = self.args[2]._to_mpmath(prec) + phi = self.args[3]._to_mpmath(prec) + oprec = mp.prec + mp.prec = prec + res = mp.spherharm(n, m, theta, phi) + mp.prec = oprec + return Expr._from_mpmath(res, prec) + + +def Ynm_c(n, m, theta, phi): + r"""Conjugate spherical harmonics defined as + + .. math:: + \overline{Y_n^m(\theta, \varphi)} := (-1)^m Y_n^{-m}(\theta, \varphi) + + See Also + ======== + + Ynm, Znm + + References + ========== + + .. [1] http://en.wikipedia.org/wiki/Spherical_harmonics + .. [2] http://mathworld.wolfram.com/SphericalHarmonic.html + .. [3] http://functions.wolfram.com/Polynomials/SphericalHarmonicY/ """ - Real spherical harmonics. + from sympy import conjugate + return conjugate(Ynm(n, m, theta, phi)) + + +class Znm(Function): + r""" + Real spherical harmonics defined as + + .. math:: + + Z_n^m(\theta, \varphi) := + \begin{cases} + \frac{Y_n^m(\theta, \varphi) + \overline{Y_n^m(\theta, \varphi)}}{\sqrt{2}} &\quad m > 0 \\ + Y_n^m(\theta, \varphi) &\quad m = 0 \\ + \frac{Y_n^m(\theta, \varphi) - \overline{Y_n^m(\theta, \varphi)}}{i \sqrt{2}} &\quad m < 0 \\ + \end{cases} + + which gives in simplified form + + .. math:: + + Z_n^m(\theta, \varphi) = + \begin{cases} + \frac{Y_n^m(\theta, \varphi) + (-1)^m Y_n^{-m}(\theta, \varphi)}{\sqrt{2}} &\quad m > 0 \\ + Y_n^m(\theta, \varphi) &\quad m = 0 \\ + \frac{Y_n^m(\theta, \varphi) - (-1)^m Y_n^{-m}(\theta, \varphi)}{i \sqrt{2}} &\quad m < 0 \\ + \end{cases} + + See Also + ======== + + Ynm, Ynm_c + + References + ========== + + .. [1] http://en.wikipedia.org/wiki/Spherical_harmonics + .. [2] http://mathworld.wolfram.com/SphericalHarmonic.html + .. [3] http://functions.wolfram.com/Polynomials/SphericalHarmonicY/ """ - from sympy import simplify - if m > 0: - zz = C.NegativeOne()**m*(Ylm(l, m, th, ph) + Ylm_c(l, m, th, ph))/sqrt(2) - elif m == 0: - return Ylm(l, m, th, ph) - else: - zz = C.NegativeOne()**m*(Ylm(l, -m, th, ph) - Ylm_c(l, -m, th, ph))/(I*sqrt(2)) - - zz = zz.expand(complex=True) - zz = simplify(zz) - return zz + + nargs = 4 + + @classmethod + def eval(cls, n, m, theta, phi): + n, m, th, ph = [sympify(x) for x in (n, m, theta, phi)] + + if m.is_positive: + zz = (Ynm(n, m, th, ph) + Ynm_c(n, m, th, ph)) / sqrt(2) + #zz = zz.expand(complex=True) + #zz = simplify(zz) + return zz + elif m.is_zero: + return Ynm(n, m, th, ph) + elif m.is_negative: + zz = (Ynm(n, m, th, ph) - Ynm_c(n, m, th, ph)) / (sqrt(2)*I) + #zz = zz.expand(complex=True) + #zz = simplify(zz) + return zz diff -Nru python3-sympy-0.7.2/sympy/functions/special/tensor_functions.py python3-sympy-0.7.3/sympy/functions/special/tensor_functions.py --- python3-sympy-0.7.2/sympy/functions/special/tensor_functions.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/functions/special/tensor_functions.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,17 +1,18 @@ from sympy.core.function import Function, C from sympy.core import S, Integer from sympy.core.mul import prod -from sympy.utilities.iterables import has_dups +from sympy.utilities.iterables import (has_dups, default_sort_key) ############################################################################### ###################### Kronecker Delta, Levi-Civita etc. ###################### ############################################################################### + def Eijk(*args, **kwargs): """ Represent the Levi-Civita symbol. - This is just compatibility wrapper to LeviCivita(). + This is just compatibility wrapper to ``LeviCivita()``. See Also ======== @@ -21,6 +22,7 @@ """ return LeviCivita(*args, **kwargs) + def eval_levicivita(*args): """Evaluate Levi-Civita symbol.""" from sympy import factorial @@ -30,6 +32,7 @@ / factorial(i) for i in range(n)) # converting factorial(i) to int is slightly faster + class LeviCivita(Function): """Represent the Levi-Civita symbol. @@ -60,6 +63,9 @@ Eijk """ + + is_integer = True + @classmethod def eval(cls, *args): if all(isinstance(a, (int, Integer)) for a in args): @@ -70,11 +76,12 @@ def doit(self): return eval_levicivita(*self.args) + class KroneckerDelta(Function): """The discrete, or Kronecker, delta function. - A function that takes in two integers i and j. It returns 0 if i and j are - not equal or it returns 1 if i and j are equal. + A function that takes in two integers `i` and `j`. It returns `0` if `i` and `j` are + not equal or it returns `1` if `i` and `j` are equal. Parameters ========== @@ -116,11 +123,11 @@ References ========== - http://en.wikipedia.org/wiki/Kronecker_delta + .. [1] http://en.wikipedia.org/wiki/Kronecker_delta """ nargs = 2 - is_commutative=True + is_integer = True @classmethod @@ -158,12 +165,22 @@ return KroneckerDelta(0, diff.args[0]) if i.assumptions0.get("below_fermi") and \ - j.assumptions0.get("above_fermi"): + j.assumptions0.get("above_fermi"): return S.Zero if j.assumptions0.get("below_fermi") and \ - i.assumptions0.get("above_fermi"): + i.assumptions0.get("above_fermi"): return S.Zero + # to make KroneckerDelta canonical + # following lines will check if inputs are in order + # if not, will return KroneckerDelta with correct order + if i is not min(i, j, key=default_sort_key): + return cls(j, i) + def _eval_power(self, expt): + if expt.is_positive: + return self + if expt.is_negative and not -expt is S.One: + return 1/self @property def is_above_fermi(self): @@ -330,7 +347,6 @@ # if both indices are general we are True, else false return self.is_below_fermi and self.is_above_fermi - @property def preferred_index(self): """ @@ -423,12 +439,3 @@ return 1 else: return 0 - - def _sympyrepr(self, printer, *args): - return "%s(%s, %s)"% (self.__class__.__name__, self.args[0], \ - self.args[1]) - - def _latex(self, printer, *args): - i = printer._print(self.args[0], *args) - j = printer._print(self.args[1], *args) - return '\\delta_{%s %s}' % (i, j) diff -Nru python3-sympy-0.7.2/sympy/functions/special/tests/test_bessel.py python3-sympy-0.7.3/sympy/functions/special/tests/test_bessel.py --- python3-sympy-0.7.2/sympy/functions/special/tests/test_bessel.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/functions/special/tests/test_bessel.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,47 +1,143 @@ from sympy import jn, yn, symbols, sin, cos, pi, S, jn_zeros, besselj, \ - bessely, besseli, besselk, hankel1, hankel2, expand_func, \ - latex, sqrt + bessely, besseli, besselk, hankel1, hankel2, expand_func, \ + latex, sqrt, sinh, cosh from sympy.functions.special.bessel import fn from sympy.utilities.pytest import raises, skip from sympy.utilities.randtest import \ - random_complex_number as randcplx, \ - test_numerically as tn, \ - test_derivative_numerically as td + random_complex_number as randcplx, \ + test_numerically as tn, \ + test_derivative_numerically as td, \ + _randint + from sympy.abc import z, n, k, x +randint = _randint() + def test_bessel_rand(): - assert td(besselj(randcplx(), z), z) - assert td(bessely(randcplx(), z), z) - assert td(besseli(randcplx(), z), z) - assert td(besselk(randcplx(), z), z) - assert td(hankel1(randcplx(), z), z) - assert td(hankel2(randcplx(), z), z) - assert td(jn(randcplx(), z), z) - assert td(yn(randcplx(), z), z) + for f in [besselj, bessely, besseli, besselk, hankel1, hankel2, jn, yn]: + assert td(f(randcplx(), z), z) + def test_diff(): - assert besselj(n, z).diff(z) == besselj(n-1, z)/2 - besselj(n+1, z)/2 - assert bessely(n, z).diff(z) == bessely(n-1, z)/2 - bessely(n+1, z)/2 - assert besseli(n, z).diff(z) == besseli(n-1, z)/2 + besseli(n+1, z)/2 - assert besselk(n, z).diff(z) == -besselk(n-1, z)/2 - besselk(n+1, z)/2 - assert hankel1(n, z).diff(z) == hankel1(n-1, z)/2 - hankel1(n+1, z)/2 - assert hankel2(n, z).diff(z) == hankel2(n-1, z)/2 - hankel2(n+1, z)/2 + assert besselj(n, z).diff(z) == besselj(n - 1, z)/2 - besselj(n + 1, z)/2 + assert bessely(n, z).diff(z) == bessely(n - 1, z)/2 - bessely(n + 1, z)/2 + assert besseli(n, z).diff(z) == besseli(n - 1, z)/2 + besseli(n + 1, z)/2 + assert besselk(n, z).diff(z) == -besselk(n - 1, z)/2 - besselk(n + 1, z)/2 + assert hankel1(n, z).diff(z) == hankel1(n - 1, z)/2 - hankel1(n + 1, z)/2 + assert hankel2(n, z).diff(z) == hankel2(n - 1, z)/2 - hankel2(n + 1, z)/2 + def test_rewrite(): from sympy import polar_lift, exp, I + assert besselj(n, z).rewrite(jn) == sqrt(2*z/pi)*jn(n - S(1)/2, z) assert bessely(n, z).rewrite(yn) == sqrt(2*z/pi)*yn(n - S(1)/2, z) assert besseli(n, z).rewrite(besselj) == \ - exp(-I*n*pi/2)*besselj(n, polar_lift(I)*z) + exp(-I*n*pi/2)*besselj(n, polar_lift(I)*z) assert besselj(n, z).rewrite(besseli) == \ - exp(I*n*pi/2)*besseli(n, polar_lift(-I)*z) + exp(I*n*pi/2)*besseli(n, polar_lift(-I)*z) + nu = randcplx() + assert tn(besselj(nu, z), besselj(nu, z).rewrite(besseli), z) + assert tn(besselj(nu, z), besselj(nu, z).rewrite(bessely), z) + assert tn(besseli(nu, z), besseli(nu, z).rewrite(besselj), z) + assert tn(besseli(nu, z), besseli(nu, z).rewrite(bessely), z) + + assert tn(bessely(nu, z), bessely(nu, z).rewrite(besselj), z) + assert tn(bessely(nu, z), bessely(nu, z).rewrite(besseli), z) + + assert tn(besselk(nu, z), besselk(nu, z).rewrite(besselj), z) + assert tn(besselk(nu, z), besselk(nu, z).rewrite(besseli), z) + assert tn(besselk(nu, z), besselk(nu, z).rewrite(bessely), z) + def test_expand(): - assert expand_func(besselj(S(1)/2, z)) == sqrt(2)*sin(z)/(sqrt(pi)*sqrt(z)) - assert expand_func(bessely(S(1)/2, z)) == -sqrt(2)*cos(z)/(sqrt(pi)*sqrt(z)) + from sympy import besselsimp, Symbol, exp, exp_polar, I + + assert expand_func(besselj(S(1)/2, z).rewrite(jn)) == \ + sqrt(2)*sin(z)/(sqrt(pi)*sqrt(z)) + assert expand_func(bessely(S(1)/2, z).rewrite(yn)) == \ + -sqrt(2)*cos(z)/(sqrt(pi)*sqrt(z)) + + # XXX: teach sin/cos to work around arguments like + # x*exp_polar(I*pi*n/2). Then change besselsimp -> expand_func + assert besselsimp(besselj(S(1)/2, z)) == sqrt(2)*sin(z)/(sqrt(pi)*sqrt(z)) + assert besselsimp(besselj(S(-1)/2, z)) == sqrt(2)*cos(z)/(sqrt(pi)*sqrt(z)) + assert besselsimp(besselj(S(5)/2, z)) == \ + -sqrt(2)*(z**2*sin(z) + 3*z*cos(z) - 3*sin(z))/(sqrt(pi)*z**(S(5)/2)) + assert besselsimp(besselj(-S(5)/2, z)) == \ + -sqrt(2)*(z**2*cos(z) - 3*z*sin(z) - 3*cos(z))/(sqrt(pi)*z**(S(5)/2)) + + assert besselsimp(bessely(S(1)/2, z)) == \ + -(sqrt(2)*cos(z))/(sqrt(pi)*sqrt(z)) + assert besselsimp(bessely(S(-1)/2, z)) == sqrt(2)*sin(z)/(sqrt(pi)*sqrt(z)) + assert besselsimp(bessely(S(5)/2, z)) == \ + sqrt(2)*(z**2*cos(z) - 3*z*sin(z) - 3*cos(z))/(sqrt(pi)*z**(S(5)/2)) + assert besselsimp(bessely(S(-5)/2, z)) == \ + -sqrt(2)*(z**2*sin(z) + 3*z*cos(z) - 3*sin(z))/(sqrt(pi)*z**(S(5)/2)) + + assert besselsimp(besseli(S(1)/2, z)) == sqrt(2)*sinh(z)/(sqrt(pi)*sqrt(z)) + assert besselsimp(besseli(S(-1)/2, z)) == \ + sqrt(2)*cosh(z)/(sqrt(pi)*sqrt(z)) + assert besselsimp(besseli(S(5)/2, z)) == \ + sqrt(2)*(z**2*sinh(z) - 3*z*cosh(z) + 3*sinh(z))/(sqrt(pi)*z**(S(5)/2)) + assert besselsimp(besseli(S(-5)/2, z)) == \ + sqrt(2)*(z**2*cosh(z) - 3*z*sinh(z) + 3*cosh(z))/(sqrt(pi)*z**(S(5)/2)) + + assert besselsimp(besselk(S(1)/2, z)) == \ + besselsimp(besselk(S(-1)/2, z)) == sqrt(pi)*exp(-z)/(sqrt(2)*sqrt(z)) + assert besselsimp(besselk(S(5)/2, z)) == \ + besselsimp(besselk(S(-5)/2, z)) == \ + sqrt(2)*sqrt(pi)*(z**2 + 3*z + 3)*exp(-z)/(2*z**(S(5)/2)) + + def check(eq, ans): + return tn(eq, ans) and eq == ans + + rn = randcplx(a=1, b=0, d=0, c=2) + + for besselx in [besselj, bessely, besseli, besselk]: + ri = S(2*randint(-11, 10) + 1) / 2 # half integer in [-21/2, 21/2] + assert tn(besselsimp(besselx(ri, z)), besselx(ri, z)) + + assert check(expand_func(besseli(rn, x)), \ + besseli(rn - 2, x) - 2*(rn - 1)*besseli(rn - 1, x)/x) + assert check(expand_func(besseli(-rn, x)), \ + besseli(-rn + 2, x) + 2*(-rn + 1)*besseli(-rn + 1, x)/x) + + assert check(expand_func(besselj(rn, x)), \ + -besselj(rn - 2, x) + 2*(rn - 1)*besselj(rn - 1, x)/x) + assert check(expand_func(besselj(-rn, x)), \ + -besselj(-rn + 2, x) + 2*(-rn + 1)*besselj(-rn + 1, x)/x) + + assert check(expand_func(besselk(rn, x)), \ + besselk(rn - 2, x) + 2*(rn - 1)*besselk(rn - 1, x)/x) + assert check(expand_func(besselk(-rn, x)), \ + besselk(-rn + 2, x) - 2*(-rn + 1)*besselk(-rn + 1, x)/x) + + assert check(expand_func(bessely(rn, x)), \ + -bessely(rn - 2, x) + 2*(rn - 1)*bessely(rn - 1, x)/x) + assert check(expand_func(bessely(-rn, x)), \ + -bessely(-rn + 2, x) + 2*(-rn + 1)*bessely(-rn + 1, x)/x) + + n = Symbol('n', integer=True, positive=True) + + assert expand_func(besseli(n + 2, z)) == \ + besseli(n, z) + (-2*n - 2)*(-2*n*besseli(n, z)/z + besseli(n - 1, z))/z + assert expand_func(besselj(n + 2, z)) == \ + -besselj(n, z) + (2*n + 2)*(2*n*besselj(n, z)/z - besselj(n - 1, z))/z + assert expand_func(besselk(n + 2, z)) == \ + besselk(n, z) + (2*n + 2)*(2*n*besselk(n, z)/z + besselk(n - 1, z))/z + assert expand_func(bessely(n + 2, z)) == \ + -bessely(n, z) + (2*n + 2)*(2*n*bessely(n, z)/z - bessely(n - 1, z))/z + + assert expand_func(besseli(n + S(1)/2, z).rewrite(jn)) == \ + sqrt(2)*sqrt(z)*exp(-I*pi*(n + S(1)/2)/2)* \ + exp_polar(I*pi/4)*jn(n, z*exp_polar(I*pi/2))/sqrt(pi) + assert expand_func(besselj(n + S(1)/2, z).rewrite(jn)) == \ + sqrt(2)*sqrt(z)*jn(n, z)/sqrt(pi) + def test_fn(): x, z = symbols("x z") @@ -50,41 +146,51 @@ assert fn(3, z) == -6/z**2 + 15/z**4 assert fn(4, z) == 1/z - 45/z**3 + 105/z**5 -def mjn(n, z): return expand_func(jn(n,z)) -def myn(n, z): return expand_func(yn(n,z)) + +def mjn(n, z): + return expand_func(jn(n, z)) + + +def myn(n, z): + return expand_func(yn(n, z)) + def test_jn(): z = symbols("z") assert mjn(0, z) == sin(z)/z assert mjn(1, z) == sin(z)/z**2 - cos(z)/z - assert mjn(2, z) == (3/z**3-1/z)*sin(z) - (3/z**2) * cos(z) + assert mjn(2, z) == (3/z**3 - 1/z)*sin(z) - (3/z**2) * cos(z) assert mjn(3, z) == (15/z**4 - 6/z**2)*sin(z) + (1/z - 15/z**3)*cos(z) assert mjn(4, z) == (1/z + 105/z**5 - 45/z**3)*sin(z) + \ - (-105/z**4 + 10/z**2)*cos(z) + (-105/z**4 + 10/z**2)*cos(z) assert mjn(5, z) == (945/z**6 - 420/z**4 + 15/z**2)*sin(z) + \ - (-1/z - 945/z**5 + 105/z**3)*cos(z) + (-1/z - 945/z**5 + 105/z**3)*cos(z) assert mjn(6, z) == (-1/z + 10395/z**7 - 4725/z**5 + 210/z**3)*sin(z) + \ - (-10395/z**6 + 1260/z**4 - 21/z**2)*cos(z) + (-10395/z**6 + 1260/z**4 - 21/z**2)*cos(z) assert expand_func(jn(n, z)) == jn(n, z) + def test_yn(): z = symbols("z") assert myn(0, z) == -cos(z)/z - assert myn(1, z) == -cos(z)/z**2-sin(z)/z - assert myn(2, z) == -((3/z**3-1/z)*cos(z)+(3/z**2)*sin(z)) + assert myn(1, z) == -cos(z)/z**2 - sin(z)/z + assert myn(2, z) == -((3/z**3 - 1/z)*cos(z) + (3/z**2)*sin(z)) assert expand_func(yn(n, z)) == yn(n, z) + def test_sympify_yn(): assert S(15) in myn(3, pi).atoms() assert myn(3, pi) == 15/pi**4 - 6/pi**2 + def eq(a, b, tol=1e-6): for x, y in zip(a, b): - if not (abs(x-y) < tol): + if not (abs(x - y) < tol): return False return True + def test_jn_zeros(): assert eq(jn_zeros(0, 4), [3.141592, 6.283185, 9.424777, 12.566370]) assert eq(jn_zeros(1, 4), [4.493409, 7.725251, 10.904121, 14.066193]) @@ -92,13 +198,54 @@ assert eq(jn_zeros(3, 4), [6.987932, 10.417118, 13.698023, 16.923621]) assert eq(jn_zeros(4, 4), [8.182561, 11.704907, 15.039664, 18.301255]) + def test_bessel_eval(): - from sympy import I - assert besselj(-4, z) == besselj(4, z) - assert besselj(-3, z) == -besselj(3, z) + from sympy import I, Symbol + n, m, k = Symbol('n', integer=True), Symbol('m'), Symbol('k', integer=True, zero=False) + + for f in [besselj, besseli]: + assert f(0, 0) == S.One + assert f(2.1, 0) == S.Zero + assert f(-3, 0) == S.Zero + assert f(-10.2, 0) == S.ComplexInfinity + assert f(1 + 3*I, 0) == S.Zero + assert f(-3 + I, 0) == S.ComplexInfinity + assert f(-2*I, 0) == S.NaN + assert f(n, 0) != S.One and f(n, 0) != S.Zero + assert f(m, 0) != S.One and f(m, 0) != S.Zero + assert f(k, 0) == S.Zero + + assert bessely(0, 0) == S.NegativeInfinity + assert besselk(0, 0) == S.Infinity + for f in [bessely, besselk]: + assert f(1 + I, 0) == S.ComplexInfinity + assert f(I, 0) == S.NaN + + for f in [besselj, bessely]: + assert f(m, S.Infinity) == S.Zero + assert f(m, S.NegativeInfinity) == S.Zero + + for f in [besseli, besselk]: + assert f(m, I*S.Infinity) == S.Zero + assert f(m, I*S.NegativeInfinity) == S.Zero + + for f in [besseli, besselk]: + assert f(-4, z) == f(4, z) + assert f(-3, z) == f(3, z) + assert f(-n, z) == f(n, z) + assert f(-m, z) != f(m, z) + + for f in [besselj, bessely]: + assert f(-4, z) == f(4, z) + assert f(-3, z) == -f(3, z) + assert f(-n, z) == (-1)**n*f(n, z) + assert f(-m, z) != (-1)**m*f(m, z) + + for f in [besselj, besseli]: + assert f(m, -z) == (-z)**m*z**(-m)*f(m, z) - assert bessely(-2, z) == bessely(2, z) - assert bessely(-1, z) == -bessely(1, z) + assert besseli(2, -z) == besseli(2, z) + assert besseli(3, -z) == -besseli(3, z) assert besselj(0, -z) == besselj(0, z) assert besselj(1, -z) == -besselj(1, z) @@ -107,6 +254,42 @@ assert besseli(1, I*z) == I*besselj(1, z) assert besselj(3, I*z) == -I*besseli(3, z) + +def test_conjugate(): + from sympy import conjugate, I, Symbol + n, z, x = Symbol('n'), Symbol('z', real=False), Symbol('x', real=True) + y, t = Symbol('y', real=True, positive=True), Symbol('t', negative=True) + + for f in [besseli, besselj, besselk, bessely, jn, yn, hankel1, hankel2]: + assert f(n, -1).conjugate() != f(conjugate(n), -1) + assert f(n, x).conjugate() != f(conjugate(n), x) + assert f(n, t).conjugate() != f(conjugate(n), t) + + rz = randcplx(b=0.5) + + for f in [besseli, besselj, besselk, bessely, jn, yn]: + assert f(n, 1 + I).conjugate() == f(conjugate(n), 1 - I) + assert f(n, 0).conjugate() == f(conjugate(n), 0) + assert f(n, 1).conjugate() == f(conjugate(n), 1) + assert f(n, z).conjugate() == f(conjugate(n), conjugate(z)) + assert f(n, y).conjugate() == f(conjugate(n), y) + assert tn(f(n, rz).conjugate(), f(conjugate(n), conjugate(rz))) + + assert hankel1(n, 1 + I).conjugate() == hankel2(conjugate(n), 1 - I) + assert hankel1(n, 0).conjugate() == hankel2(conjugate(n), 0) + assert hankel1(n, 1).conjugate() == hankel2(conjugate(n), 1) + assert hankel1(n, y).conjugate() == hankel2(conjugate(n), y) + assert hankel1(n, z).conjugate() == hankel2(conjugate(n), conjugate(z)) + assert tn(hankel1(n, rz).conjugate(), hankel2(conjugate(n), conjugate(rz))) + + assert hankel2(n, 1 + I).conjugate() == hankel1(conjugate(n), 1 - I) + assert hankel2(n, 0).conjugate() == hankel1(conjugate(n), 0) + assert hankel2(n, 1).conjugate() == hankel1(conjugate(n), 1) + assert hankel2(n, y).conjugate() == hankel1(conjugate(n), y) + assert hankel2(n, z).conjugate() == hankel1(conjugate(n), conjugate(z)) + assert tn(hankel2(n, rz).conjugate(), hankel1(conjugate(n), conjugate(rz))) + + def test_branching(): from sympy import exp_polar, polar_lift, Symbol, I, exp assert besselj(polar_lift(k), x) == besselj(k, x) diff -Nru python3-sympy-0.7.2/sympy/functions/special/tests/test_bsplines.py python3-sympy-0.7.3/sympy/functions/special/tests/test_bsplines.py --- python3-sympy-0.7.2/sympy/functions/special/tests/test_bsplines.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/functions/special/tests/test_bsplines.py 2013-07-13 17:53:32.000000000 +0000 @@ -4,59 +4,79 @@ x, y = symbols('x,y') + def test_basic_degree_0(): d = 0 knots = list(range(5)) splines = bspline_basis_set(d, knots, x) for i in range(len(splines)): - assert splines[i] == Piecewise((1, Interval(i, i+1).contains(x)), (0, True)) + assert splines[i] == Piecewise((1, Interval(i, i + 1) + .contains(x)), (0, True)) + def test_basic_degree_1(): d = 1 knots = list(range(5)) splines = bspline_basis_set(d, knots, x) - assert splines[0] == Piecewise((x, Interval(0, 1, False, True).contains(x)), + assert splines[0] == Piecewise( + (x, Interval(0, 1, False, True).contains(x)), (2 - x, Interval(1, 2).contains(x)), (0, True)) - assert splines[1] == Piecewise((-1 + x, Interval(1, 2, False, True).contains(x)), + assert splines[1] == Piecewise( + (-1 + x, Interval(1, 2, False, True).contains(x)), (3 - x, Interval(2, 3).contains(x)), (0, True)) - assert splines[2] == Piecewise((-2 + x, Interval(2, 3, False, True).contains(x)), + assert splines[2] == Piecewise( + (-2 + x, Interval(2, 3, False, True).contains(x)), (4 - x, Interval(3, 4).contains(x)), (0, True)) + def test_basic_degree_2(): d = 2 knots = list(range(5)) splines = bspline_basis_set(d, knots, x) b0 = Piecewise((x**2/2, Interval(0, 1, False, True).contains(x)), - (Rational(-3, 2) + 3*x - x**2, Interval(1, 2, False, True).contains(x)), + (Rational( + -3, 2) + 3*x - x**2, Interval(1, 2, False, True).contains(x)), (Rational(9, 2) - 3*x + x**2/2, Interval(2, 3).contains(x)), (0, True)) - b1 = Piecewise((Rational(1, 2) - x + x**2/2, Interval(1, 2, False, True).contains(x)), - (Rational(-11, 2) + 5*x - x**2, Interval(2, 3, False, True).contains(x)), + b1 = Piecewise( + (Rational(1, 2) - x + x**2/2, Interval(1, 2, False, True).contains(x)), + (Rational( + -11, 2) + 5*x - x**2, Interval(2, 3, False, True).contains(x)), (8 - 4*x + x**2/2, Interval(3, 4).contains(x)), (0, True)) assert splines[0] == b0 assert splines[1] == b1 + def test_basic_degree_3(): d = 3 knots = list(range(5)) splines = bspline_basis_set(d, knots, x) b0 = Piecewise( (x**3/6, Interval(0, 1, False, True).contains(x)), - (Rational(2, 3) - 2*x + 2*x**2 - x**3/2, Interval(1, 2, False, True).contains(x)), - (Rational(-22, 3) + 10*x - 4*x**2 + x**3/2, Interval(2, 3, False, True).contains(x)), + (Rational(2, 3) - 2*x + 2*x**2 - x**3/2, Interval(1, 2, + False, True).contains(x)), + (Rational(-22, 3) + 10*x - 4*x**2 + x**3/2, Interval(2, 3, + False, True).contains(x)), (Rational(32, 3) - 8*x + 2*x**2 - x**3/6, Interval(3, 4).contains(x)), (0, True) ) assert splines[0] == b0 + def test_repeated_degree_1(): d = 1 - knots = [0,0,1,2,2,3,4,4] + knots = [0, 0, 1, 2, 2, 3, 4, 4] splines = bspline_basis_set(d, knots, x) - assert splines[0] == Piecewise((1 - x, Interval(0, 1).contains(x)), (0, True)) - assert splines[1] == Piecewise((x, Interval(0, 1, False, True).contains(x)), + assert splines[0] == Piecewise((1 - x, Interval(0, 1).contains(x)), + (0, True)) + assert splines[1] == Piecewise( + (x, Interval(0, 1, False, True).contains(x)), (2 - x, Interval(1, 2).contains(x)), (0, True)) - assert splines[2] == Piecewise((-1 + x, Interval(1, 2).contains(x)), (0, True)) - assert splines[3] == Piecewise((3 - x, Interval(2, 3).contains(x)), (0, True)) - assert splines[4] == Piecewise((-2 + x, Interval(2, 3, False, True).contains(x)), + assert splines[2] == Piecewise((-1 + x, Interval(1, 2).contains(x) + ), (0, True)) + assert splines[3] == Piecewise((3 - x, Interval(2, 3).contains(x)), + (0, True)) + assert splines[4] == Piecewise( + (-2 + x, Interval(2, 3, False, True).contains(x)), (4 - x, Interval(3, 4).contains(x)), (0, True)) - assert splines[5] == Piecewise((-3 + x, Interval(3, 4).contains(x)), (0, True)) + assert splines[5] == Piecewise((-3 + x, Interval(3, 4).contains(x) + ), (0, True)) diff -Nru python3-sympy-0.7.2/sympy/functions/special/tests/test_delta_functions.py python3-sympy-0.7.3/sympy/functions/special/tests/test_delta_functions.py --- python3-sympy-0.7.2/sympy/functions/special/tests/test_delta_functions.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/functions/special/tests/test_delta_functions.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,33 +1,39 @@ -from sympy import symbols, DiracDelta, Heaviside, nan, oo, sqrt, pi, conjugate +from sympy import ( + adjoint, conjugate, DiracDelta, Heaviside, nan, oo, pi, sqrt, symbols, + transpose, Symbol, Piecewise, I, S, Eq +) from sympy.utilities.pytest import raises from sympy.core.function import ArgumentIndexError -from sympy.core import I +x, y = symbols('x y') -x,y = symbols('x y') def test_DiracDelta(): assert DiracDelta(1) == 0 assert DiracDelta(5.1) == 0 assert DiracDelta(-pi) == 0 - assert DiracDelta(5,7) == 0 - assert DiracDelta(0) == oo - assert DiracDelta(0,5) == oo + assert DiracDelta(5, 7) == 0 assert DiracDelta(nan) == nan - assert DiracDelta(x).func == DiracDelta + assert DiracDelta(0).func is DiracDelta + assert DiracDelta(x).func is DiracDelta + + assert adjoint(DiracDelta(x)) == DiracDelta(x) + assert adjoint(DiracDelta(x - y)) == DiracDelta(x - y) assert conjugate(DiracDelta(x)) == DiracDelta(x) assert conjugate(DiracDelta(x - y)) == DiracDelta(x - y) + assert transpose(DiracDelta(x)) == DiracDelta(x) + assert transpose(DiracDelta(x - y)) == DiracDelta(x - y) - assert DiracDelta(x).diff(x) == DiracDelta(x,1) - assert DiracDelta(x,1).diff(x) == DiracDelta(x,2) + assert DiracDelta(x).diff(x) == DiracDelta(x, 1) + assert DiracDelta(x, 1).diff(x) == DiracDelta(x, 2) - assert DiracDelta(x).is_simple(x) == True - assert DiracDelta(3*x).is_simple(x) == True - assert DiracDelta(x**2).is_simple(x) == False - assert DiracDelta(sqrt(x)).is_simple(x) == False - assert DiracDelta(x).is_simple(y) == False + assert DiracDelta(x).is_simple(x) is True + assert DiracDelta(3*x).is_simple(x) is True + assert DiracDelta(x**2).is_simple(x) is False + assert DiracDelta(sqrt(x)).is_simple(x) is False + assert DiracDelta(x).is_simple(y) is False assert DiracDelta(x*y).simplify(x) == DiracDelta(x)/abs(y) assert DiracDelta(x*y).simplify(y) == DiracDelta(y)/abs(x) @@ -35,7 +41,8 @@ assert DiracDelta(y).simplify(x) == DiracDelta(y) raises(ArgumentIndexError, lambda: DiracDelta(x).fdiff(2)) - raises(ValueError, lambda: DiracDelta(x,-1)) + raises(ValueError, lambda: DiracDelta(x, -1)) + def test_heaviside(): assert Heaviside(0) == 0.5 @@ -43,10 +50,24 @@ assert Heaviside(1) == 1 assert Heaviside(nan) == nan + assert adjoint(Heaviside(x)) == Heaviside(x) + assert adjoint(Heaviside(x - y)) == Heaviside(x - y) + assert conjugate(Heaviside(x)) == Heaviside(x) + assert conjugate(Heaviside(x - y)) == Heaviside(x - y) + assert transpose(Heaviside(x)) == Heaviside(x) + assert transpose(Heaviside(x - y)) == Heaviside(x - y) + assert Heaviside(x).diff(x) == DiracDelta(x) - assert Heaviside(x+I).is_Function - assert Heaviside(I*x).is_Function + assert Heaviside(x + I).is_Function is True + assert Heaviside(I*x).is_Function is True raises(ArgumentIndexError, lambda: Heaviside(x).fdiff(2)) raises(ValueError, lambda: Heaviside(I)) - raises(ValueError, lambda: Heaviside(2+3*I)) + raises(ValueError, lambda: Heaviside(2 + 3*I)) + + +def test_rewrite(): + x, y = Symbol('x', real=True), Symbol('y') + assert Heaviside(x).rewrite(Piecewise) == \ + Piecewise((1, x > 0), (S(1)/2, Eq(x, 0)), (0, True)) + assert Heaviside(y).rewrite(Piecewise) == Heaviside(y) diff -Nru python3-sympy-0.7.2/sympy/functions/special/tests/test_elliptic_integrals.py python3-sympy-0.7.3/sympy/functions/special/tests/test_elliptic_integrals.py --- python3-sympy-0.7.2/sympy/functions/special/tests/test_elliptic_integrals.py 1970-01-01 00:00:00.000000000 +0000 +++ python3-sympy-0.7.3/sympy/functions/special/tests/test_elliptic_integrals.py 2013-07-13 17:53:32.000000000 +0000 @@ -0,0 +1,136 @@ +from sympy import (S, Symbol, pi, I, oo, zoo, sin, sqrt, tan, atan, gamma, + atanh, hyper, meijerg) +from sympy.functions.special.elliptic_integrals import (elliptic_k as K, + elliptic_f as F, elliptic_e as E, elliptic_pi as P) +from sympy.utilities.randtest import (test_derivative_numerically as td, + random_complex_number as randcplx, + test_numerically as tn) +from sympy.abc import x, y, z, m, n + +i = Symbol('i', integer=True) +j = Symbol('k', integer=True, positive=True) + +def test_K(): + assert K(0) == pi/2 + assert K(S(1)/2) == 8*pi**(S(3)/2)/gamma(-S(1)/4)**2 + assert K(1) == zoo + assert K(-1) == gamma(S(1)/4)**2/(4*sqrt(2*pi)) + assert K(oo) == 0 + assert K(-oo) == 0 + assert K(I*oo) == 0 + assert K(-I*oo) == 0 + assert K(zoo) == 0 + + assert K(z).diff(z) == (E(z) - (1 - z)*K(z))/(2*z*(1 - z)) + assert td(K(z), z) + + zi = Symbol('z', real=False) + assert K(zi).conjugate() == K(zi.conjugate()) + zr = Symbol('z', real=True, negative=True) + assert K(zr).conjugate() == K(zr) + + assert K(z).rewrite(hyper) == \ + (pi/2)*hyper((S.Half, S.Half), (S.One,), z) + assert tn(K(z), (pi/2)*hyper((S.Half, S.Half), (S.One,), z)) + assert K(z).rewrite(meijerg) == \ + meijerg(((S.Half, S.Half), []), ((S.Zero,), (S.Zero,)), -z)/2 + assert tn(K(z), meijerg(((S.Half, S.Half), []), ((S.Zero,), (S.Zero,)), -z)/2) + + +def test_F(): + assert F(z, 0) == z + assert F(0, m) == 0 + assert F(pi*i/2, m) == i*K(m) + assert F(z, oo) == 0 + assert F(z, -oo) == 0 + + assert F(-z, m) == -F(z, m) + + assert F(z, m).diff(z) == 1/sqrt(1 - m*sin(z)**2) + assert F(z, m).diff(m) == E(z, m)/(2*m*(1 - m)) - F(z, m)/(2*m) - \ + sin(2*z)/(4*(1 - m)*sqrt(1 - m*sin(z)**2)) + r = randcplx() + assert td(F(z, r), z) + assert td(F(r, m), m) + + mi = Symbol('m', real=False) + assert F(z, mi).conjugate() == F(z.conjugate(), mi.conjugate()) + mr = Symbol('m', real=True, negative=True) + assert F(z, mr).conjugate() == F(z.conjugate(), mr) + + +def test_E(): + assert E(z, 0) == z + assert E(0, m) == 0 + assert E(i*pi/2, m) == i*E(m) + assert E(z, oo) == zoo + assert E(z, -oo) == zoo + assert E(0) == pi/2 + assert E(1) == 1 + assert E(oo) == I*oo + assert E(-oo) == oo + assert E(zoo) == zoo + + assert E(-z, m) == -E(z, m) + + assert E(z, m).diff(z) == sqrt(1 - m*sin(z)**2) + assert E(z, m).diff(m) == (E(z, m) - F(z, m))/(2*m) + assert E(z).diff(z) == (E(z) - K(z))/(2*z) + r = randcplx() + assert td(E(r, m), m) + assert td(E(z, r), z) + assert td(E(z), z) + + mi = Symbol('m', real=False) + assert E(z, mi).conjugate() == E(z.conjugate(), mi.conjugate()) + mr = Symbol('m', real=True, negative=True) + assert E(z, mr).conjugate() == E(z.conjugate(), mr) + + assert E(z).rewrite(hyper) == (pi/2)*hyper((-S.Half, S.Half), (S.One,), z) + assert tn(E(z), (pi/2)*hyper((-S.Half, S.Half), (S.One,), z)) + assert E(z).rewrite(meijerg) == \ + -meijerg(((S.Half, S(3)/2), []), ((S.Zero,), (S.Zero,)), -z)/4 + assert tn(E(z), -meijerg(((S.Half, S(3)/2), []), ((S.Zero,), (S.Zero,)), -z)/4) + + +def test_P(): + assert P(0, z, m) == F(z, m) + assert P(1, z, m) == F(z, m) + \ + (sqrt(1 - m*sin(z)**2)*tan(z) - E(z, m))/(1 - m) + assert P(n, i*pi/2, m) == i*P(n, m) + assert P(n, z, 0) == atanh(sqrt(n - 1)*tan(z))/sqrt(n - 1) + assert P(n, z, n) == F(z, n) - P(1, z, n) + tan(z)/sqrt(1 - n*sin(z)**2) + assert P(oo, z, m) == 0 + assert P(-oo, z, m) == 0 + assert P(n, z, oo) == 0 + assert P(n, z, -oo) == 0 + assert P(0, m) == K(m) + assert P(1, m) == zoo + assert P(n, 0) == pi/(2*sqrt(1 - n)) + assert P(2, 1) == -oo + assert P(-1, 1) == oo + assert P(n, n) == E(n)/(1 - n) + + assert P(n, -z, m) == -P(n, z, m) + + ni, mi = Symbol('n', real=False), Symbol('m', real=False) + assert P(ni, z, mi).conjugate() == \ + P(ni.conjugate(), z.conjugate(), mi.conjugate()) + nr, mr = Symbol('n', real=True, negative=True), \ + Symbol('m', real=True, negative=True) + assert P(nr, z, mr).conjugate() == P(nr, z.conjugate(), mr) + assert P(n, m).conjugate() == P(n.conjugate(), m.conjugate()) + + assert P(n, z, m).diff(n) == (E(z, m) + (m - n)*F(z, m)/n + + (n**2 - m)*P(n, z, m)/n - n*sqrt(1 - + m*sin(z)**2)*sin(2*z)/(2*(1 - n*sin(z)**2)))/(2*(m - n)*(n - 1)) + assert P(n, z, m).diff(z) == 1/(sqrt(1 - m*sin(z)**2)*(1 - n*sin(z)**2)) + assert P(n, z, m).diff(m) == (E(z, m)/(m - 1) + P(n, z, m) - + m*sin(2*z)/(2*(m - 1)*sqrt(1 - m*sin(z)**2)))/(2*(n - m)) + assert P(n, m).diff(n) == (E(m) + (m - n)*K(m)/n + + (n**2 - m)*P(n, m)/n)/(2*(m - n)*(n - 1)) + assert P(n, m).diff(m) == (E(m)/(m - 1) + P(n, m))/(2*(n - m)) + rx, ry = randcplx(), randcplx() + assert td(P(n, rx, ry), n) + assert td(P(rx, z, ry), z) + assert td(P(rx, ry, m), m) diff -Nru python3-sympy-0.7.2/sympy/functions/special/tests/test_error_functions.py python3-sympy-0.7.3/sympy/functions/special/tests/test_error_functions.py --- python3-sympy-0.7.2/sympy/functions/special/tests/test_error_functions.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/functions/special/tests/test_error_functions.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,10 +1,15 @@ -from sympy import (symbols, expand, expand_func, erf, nan, oo, Float, conjugate, - sqrt, sin, cos, pi, re, im, Abs, O, factorial, exp_polar, - polar_lift, Symbol, I, integrate, exp, uppergamma, expint, - log, loggamma, limit, hyper, meijerg, gamma, S, Shi, Chi, - Si, Ci, E1, Ei, sin, cos, sinh, cosh, fresnels, fresnelc) +from sympy import ( + symbols, expand, expand_func, nan, oo, Float, conjugate, diff, + re, im, Abs, O, factorial, exp_polar, polar_lift, gruntz, limit, + Symbol, I, integrate, S, + sqrt, sin, cos, sinh, cosh, exp, log, pi, EulerGamma, + erf, erfc, erfi, erf2, erfinv, erfcinv, erf2inv, + gamma, uppergamma, loggamma, + Ei, expint, E1, li, Li, Si, Ci, Shi, Chi, + fresnels, fresnelc, + hyper, meijerg) -from sympy.functions.special.error_functions import _erfs +from sympy.functions.special.error_functions import _erfs, _eis from sympy.core.function import ArgumentIndexError @@ -14,6 +19,7 @@ w = Symbol("w", real=True) n = Symbol("n", integer=True) + def test_erf(): assert erf(nan) == nan @@ -29,8 +35,13 @@ assert erf(-x*y) == -erf(x*y) assert erf(-x - y) == -erf(x + y) - assert erf(I).is_real == False - assert erf(0).is_real == True + assert erf(erfinv(x)) == x + assert erf(erfcinv(x)) == 1 - x + assert erf(erf2inv(0, x)) == x + assert erf(erf2inv(0, erf(erfcinv(1 - erf(erfinv(x)))))) == x + + assert erf(I).is_real is False + assert erf(0).is_real is True assert conjugate(erf(z)) == erf(conjugate(z)) @@ -38,31 +49,233 @@ assert erf(1/x).as_leading_term(x) == erf(1/x) assert erf(z).rewrite('uppergamma') == sqrt(z**2)*erf(sqrt(z**2))/z - - assert limit(exp(x)*exp(x**2)*(erf(x+1/exp(x))-erf(x)), x, oo) == 2/sqrt(pi) - assert limit((1-erf(z))*exp(z**2)*z, z, oo) == 1/sqrt(pi) - assert limit((1-erf(x))*exp(x**2)*sqrt(pi)*x, x, oo) == 1 - assert limit(((1-erf(x))*exp(x**2)*sqrt(pi)*x-1)*2*x**2, x, oo) == -1 + assert erf(z).rewrite('erfc') == S.One - erfc(z) + assert erf(z).rewrite('erfi') == -I*erfi(I*z) + assert erf(z).rewrite('fresnels') == (1 + I)*(fresnelc(z*(1 - I)/sqrt(pi)) - + I*fresnels(z*(1 - I)/sqrt(pi))) + assert erf(z).rewrite('fresnelc') == (1 + I)*(fresnelc(z*(1 - I)/sqrt(pi)) - + I*fresnels(z*(1 - I)/sqrt(pi))) + assert erf(z).rewrite('hyper') == 2*z*hyper([S.Half], [3*S.Half], -z**2)/sqrt(pi) + assert erf(z).rewrite('meijerg') == z*meijerg([S.Half], [], [0], [-S.Half], z**2)/sqrt(pi) + assert erf(z).rewrite('expint') == sqrt(z**2)/z - z*expint(S.Half, z**2)/sqrt(S.Pi) + + assert limit(exp(x)*exp(x**2)*(erf(x + 1/exp(x)) - erf(x)), x, oo) == \ + 2/sqrt(pi) + assert limit((1 - erf(z))*exp(z**2)*z, z, oo) == 1/sqrt(pi) + assert limit((1 - erf(x))*exp(x**2)*sqrt(pi)*x, x, oo) == 1 + assert limit(((1 - erf(x))*exp(x**2)*sqrt(pi)*x - 1)*2*x**2, x, oo) == -1 + + assert erf(x).as_real_imag() == \ + ((erf(re(x) - I*re(x)*Abs(im(x))/Abs(re(x)))/2 + + erf(re(x) + I*re(x)*Abs(im(x))/Abs(re(x)))/2, + I*(erf(re(x) - I*re(x)*Abs(im(x))/Abs(re(x))) - + erf(re(x) + I*re(x)*Abs(im(x))/Abs(re(x)))) * + re(x)*Abs(im(x))/(2*im(x)*Abs(re(x))))) raises(ArgumentIndexError, lambda: erf(x).fdiff(2)) + def test_erf_series(): assert erf(x).series(x, 0, 7) == 2*x/sqrt(pi) - \ 2*x**3/3/sqrt(pi) + x**5/5/sqrt(pi) + O(x**7) + def test_erf_evalf(): - assert abs( erf(Float(2.0)) - 0.995322265 ) < 1E-8 # XXX + assert abs( erf(Float(2.0)) - 0.995322265 ) < 1E-8 # XXX + def test__erfs(): - assert _erfs(z).diff(z) == -2/sqrt(S.Pi)+2*z*_erfs(z) + assert _erfs(z).diff(z) == -2/sqrt(S.Pi) + 2*z*_erfs(z) - assert _erfs(1/z).series(z) == z/sqrt(pi) - z**3/(2*sqrt(pi)) + 3*z**5/(4*sqrt(pi)) + O(z**6) + assert _erfs(1/z).series(z) == \ + z/sqrt(pi) - z**3/(2*sqrt(pi)) + 3*z**5/(4*sqrt(pi)) + O(z**6) - assert expand(erf(z).rewrite('tractable').diff(z).rewrite('intractable')) == erf(z).diff(z) + assert expand(erf(z).rewrite('tractable').diff(z).rewrite('intractable')) \ + == erf(z).diff(z) assert _erfs(z).rewrite("intractable") == (-erf(z) + 1)*exp(z**2) + +def test_erfc(): + assert erfc(nan) == nan + + assert erfc(oo) == 0 + assert erfc(-oo) == 2 + + assert erfc(0) == 1 + + assert erfc(I*oo) == -oo*I + assert erfc(-I*oo) == oo*I + + assert erfc(-x) == S(2) - erfc(x) + assert erfc(erfcinv(x)) == x + + assert erfc(I).is_real is False + assert erfc(0).is_real is True + + assert conjugate(erfc(z)) == erfc(conjugate(z)) + + assert erfc(x).as_leading_term(x) == S.One + assert erfc(1/x).as_leading_term(x) == erfc(1/x) + + assert erfc(z).rewrite('erf') == 1 - erf(z) + assert erfc(z).rewrite('erfi') == 1 + I*erfi(I*z) + assert erfc(z).rewrite('fresnels') == 1 - (1 + I)*(fresnelc(z*(1 - I)/sqrt(pi)) - + I*fresnels(z*(1 - I)/sqrt(pi))) + assert erfc(z).rewrite('fresnelc') == 1 - (1 + I)*(fresnelc(z*(1 - I)/sqrt(pi)) - + I*fresnels(z*(1 - I)/sqrt(pi))) + assert erfc(z).rewrite('hyper') == 1 - 2*z*hyper([S.Half], [3*S.Half], -z**2)/sqrt(pi) + assert erfc(z).rewrite('meijerg') == 1 - z*meijerg([S.Half], [], [0], [-S.Half], z**2)/sqrt(pi) + assert erfc(z).rewrite('uppergamma') == 1 - sqrt(z**2)*erf(sqrt(z**2))/z + assert erfc(z).rewrite('expint') == S.One - sqrt(z**2)/z + z*expint(S.Half, z**2)/sqrt(S.Pi) + + assert erfc(x).as_real_imag() == \ + ((erfc(re(x) - I*re(x)*Abs(im(x))/Abs(re(x)))/2 + + erfc(re(x) + I*re(x)*Abs(im(x))/Abs(re(x)))/2, + I*(erfc(re(x) - I*re(x)*Abs(im(x))/Abs(re(x))) - + erfc(re(x) + I*re(x)*Abs(im(x))/Abs(re(x)))) * + re(x)*Abs(im(x))/(2*im(x)*Abs(re(x))))) + + raises(ArgumentIndexError, lambda: erfc(x).fdiff(2)) + + +def test_erfc_series(): + assert erfc(x).series(x, 0, 7) == 1 - 2*x/sqrt(pi) + \ + 2*x**3/3/sqrt(pi) - x**5/5/sqrt(pi) + O(x**7) + + +def test_erfc_evalf(): + assert abs( erfc(Float(2.0)) - 0.00467773 ) < 1E-8 # XXX + + +def test_erfi(): + assert erfi(nan) == nan + + assert erfi(oo) == S.Infinity + assert erfi(-oo) == S.NegativeInfinity + + assert erfi(0) == S.Zero + + assert erfi(I*oo) == I + assert erfi(-I*oo) == -I + + assert erfi(-x) == -erfi(x) + + assert erfi(I*erfinv(x)) == I*x + assert erfi(I*erfcinv(x)) == I*(1 - x) + assert erfi(I*erf2inv(0, x)) == I*x + + assert erfi(I).is_real is False + assert erfi(0).is_real is True + + assert conjugate(erfi(z)) == erfi(conjugate(z)) + + assert erfi(z).rewrite('erf') == -I*erf(I*z) + assert erfi(z).rewrite('erfc') == I*erfc(I*z) - I + assert erfi(z).rewrite('fresnels') == (1 - I)*(fresnelc(z*(1 + I)/sqrt(pi)) - + I*fresnels(z*(1 + I)/sqrt(pi))) + assert erfi(z).rewrite('fresnelc') == (1 - I)*(fresnelc(z*(1 + I)/sqrt(pi)) - + I*fresnels(z*(1 + I)/sqrt(pi))) + assert erfi(z).rewrite('hyper') == 2*z*hyper([S.Half], [3*S.Half], z**2)/sqrt(pi) + assert erfi(z).rewrite('meijerg') == z*meijerg([S.Half], [], [0], [-S.Half], -z**2)/sqrt(pi) + assert erfi(z).rewrite('uppergamma') == (sqrt(-z**2)/z*(uppergamma(S.Half, + -z**2)/sqrt(S.Pi) - S.One)) + assert erfi(z).rewrite('expint') == sqrt(-z**2)/z - z*expint(S.Half, -z**2)/sqrt(S.Pi) + + assert erfi(x).as_real_imag() == \ + ((erfi(re(x) - I*re(x)*Abs(im(x))/Abs(re(x)))/2 + + erfi(re(x) + I*re(x)*Abs(im(x))/Abs(re(x)))/2, + I*(erfi(re(x) - I*re(x)*Abs(im(x))/Abs(re(x))) - + erfi(re(x) + I*re(x)*Abs(im(x))/Abs(re(x)))) * + re(x)*Abs(im(x))/(2*im(x)*Abs(re(x))))) + + raises(ArgumentIndexError, lambda: erfi(x).fdiff(2)) + + +def test_erfi_series(): + assert erfi(x).series(x, 0, 7) == 2*x/sqrt(pi) + \ + 2*x**3/3/sqrt(pi) + x**5/5/sqrt(pi) + O(x**7) + + +def test_erfi_evalf(): + assert abs( erfi(Float(2.0)) - 18.5648024145756 ) < 1E-13 # XXX + + +def test_erf2(): + + assert erf2(0, 0) == S.Zero + assert erf2(x, x) == S.Zero + assert erf2(nan, 0) == nan + + assert erf2(-oo, y) == erf(y) + 1 + assert erf2( oo, y) == erf(y) - 1 + assert erf2( x, oo) == 1 - erf(x) + assert erf2( x,-oo) == -1 - erf(x) + assert erf2(x, erf2inv(x, y)) == y + + assert erf2(-x, -y) == -erf2(x,y) + assert erf2(-x, y) == erf(y) + erf(x) + assert erf2( x, -y) == -erf(y) - erf(x) + assert erf2(x, y).rewrite('fresnels') == erf(y).rewrite(fresnels)-erf(x).rewrite(fresnels) + assert erf2(x, y).rewrite('fresnelc') == erf(y).rewrite(fresnelc)-erf(x).rewrite(fresnelc) + assert erf2(x, y).rewrite('hyper') == erf(y).rewrite(hyper)-erf(x).rewrite(hyper) + assert erf2(x, y).rewrite('meijerg') == erf(y).rewrite(meijerg)-erf(x).rewrite(meijerg) + assert erf2(x, y).rewrite('uppergamma') == erf(y).rewrite(uppergamma) - erf(x).rewrite(uppergamma) + assert erf2(x, y).rewrite('expint') == erf(y).rewrite(expint)-erf(x).rewrite(expint) + + assert erf2(I, 0).is_real is False + assert erf2(0, 0).is_real is True + + #assert conjugate(erf2(x, y)) == erf2(conjugate(x), conjugate(y)) + + assert erf2(x, y).rewrite('erf') == erf(y) - erf(x) + assert erf2(x, y).rewrite('erfc') == erfc(x) - erfc(y) + assert erf2(x, y).rewrite('erfi') == I*(erfi(I*x) - erfi(I*y)) + + raises(ArgumentIndexError, lambda: erfi(x).fdiff(3)) + + +def test_erfinv(): + assert erfinv(0) == 0 + assert erfinv(1) == S.Infinity + assert erfinv(nan) == S.NaN + + assert erfinv(erf(w)) == w + assert erfinv(erf(-w)) == -w + + assert erfinv(x).diff() == sqrt(pi)*exp(erfinv(x)**2)/2 + + assert erfinv(z).rewrite('erfcinv') == erfcinv(1-z) + + +def test_erfinv_evalf(): + assert abs( erfinv(Float(0.2)) - 0.179143454621292 ) < 1E-13 + + +def test_erfcinv(): + assert erfcinv(1) == 0 + assert erfcinv(0) == S.Infinity + assert erfcinv(nan) == S.NaN + + assert erfcinv(x).diff() == -sqrt(pi)*exp(erfcinv(x)**2)/2 + + assert erfcinv(z).rewrite('erfinv') == erfinv(1-z) + + +def test_erf2inv(): + assert erf2inv(0, 0) == S.Zero + assert erf2inv(0, 1) == S.Infinity + assert erf2inv(1, 0) == S.One + assert erf2inv(0, y) == erfinv(y) + assert erf2inv(oo,y) == erfcinv(-y) + + assert erf2inv(x, y).diff(x) == exp(-x**2 + erf2inv(x, y)**2) + assert erf2inv(x, y).diff(y) == sqrt(pi)*exp(erf2inv(x, y)**2)/2 + + # NOTE we multiply by exp_polar(I*pi) and need this to be on the principal -# branch, hence take x in the lower half plane (d=0). +# branch, hence take x in the lower half plane (d=0). + + def mytn(expr1, expr2, expr3, x, d=0): from sympy.utilities.randtest import test_numerically, random_complex_number subs = {} @@ -72,18 +285,21 @@ return expr2 == expr3 and test_numerically(expr1.subs(subs), expr2.subs(subs), x, d=d) + def mytd(expr1, expr2, x): from sympy.utilities.randtest import test_derivative_numerically, \ - random_complex_number + random_complex_number subs = {} for a in expr1.free_symbols: if a != x: subs[a] = random_complex_number() return expr1.diff(x) == expr2 and test_derivative_numerically(expr1.subs(subs), x) + def tn_branch(func, s=None): from sympy import I, pi, exp_polar from random import uniform + def fn(x): if s is None: return func(x) @@ -94,6 +310,7 @@ expr2 = fn(-c + eps*I) - fn(-c - eps*I) return abs(expr.n() - expr2.n()).n() < 1e-10 + def test_ei(): pos = Symbol('p', positive=True) neg = Symbol('n', negative=True) @@ -113,19 +330,26 @@ assert mytn(Ei(x*polar_lift(I)), Ei(x*polar_lift(I)).rewrite(Si), Ci(x) + I*Si(x) + I*pi/2, x) + assert Ei(log(x)).rewrite(li) == li(x) + assert Ei(2*log(x)).rewrite(li) == li(x**2) + + assert gruntz(Ei(x+exp(-x))*exp(-x)*x, x, oo) == 1 + + def test_expint(): assert mytn(expint(x, y), expint(x, y).rewrite(uppergamma), - y**(x-1)*uppergamma(1 - x, y), x) - assert mytd(expint(x, y), -y**(x - 1)*meijerg([], [1, 1], [0, 0, 1-x], [], y), x) + y**(x - 1)*uppergamma(1 - x, y), x) + assert mytd( + expint(x, y), -y**(x - 1)*meijerg([], [1, 1], [0, 0, 1 - x], [], y), x) assert mytd(expint(x, y), -expint(x - 1, y), y) assert mytn(expint(1, x), expint(1, x).rewrite(Ei), -Ei(x*polar_lift(-1)) + I*pi, x) assert expint(-4, x) == exp(-x)/x + 4*exp(-x)/x**2 + 12*exp(-x)/x**3 \ - + 24*exp(-x)/x**4 + 24*exp(-x)/x**5 + + 24*exp(-x)/x**4 + 24*exp(-x)/x**5 assert expint(-S(3)/2, x) == \ - exp(-x)/x + 3*exp(-x)/(2*x**2) - 3*sqrt(pi)*erf(sqrt(x))/(4*x**S('5/2')) \ - + 3*sqrt(pi)/(4*x**S('5/2')) + exp(-x)/x + 3*exp(-x)/(2*x**2) - 3*sqrt(pi)*erf(sqrt(x))/(4*x**S('5/2')) \ + + 3*sqrt(pi)/(4*x**S('5/2')) assert tn_branch(expint, 1) assert tn_branch(expint, 2) @@ -133,13 +357,13 @@ assert tn_branch(expint, 1.7) assert tn_branch(expint, pi) - assert expint(y, x*exp_polar(2*I*pi)) \ - == x**(y - 1)*(exp(2*I*pi*y) - 1)*gamma(-y + 1) + expint(y, x) - assert expint(y, x*exp_polar(-2*I*pi)) \ - == x**(y - 1)*(exp(-2*I*pi*y) - 1)*gamma(-y + 1) + expint(y, x) + assert expint(y, x*exp_polar(2*I*pi)) == \ + x**(y - 1)*(exp(2*I*pi*y) - 1)*gamma(-y + 1) + expint(y, x) + assert expint(y, x*exp_polar(-2*I*pi)) == \ + x**(y - 1)*(exp(-2*I*pi*y) - 1)*gamma(-y + 1) + expint(y, x) assert expint(2, x*exp_polar(2*I*pi)) == 2*I*pi*x + expint(2, x) assert expint(2, x*exp_polar(-2*I*pi)) == -2*I*pi*x + expint(2, x) - assert expint(1,x).rewrite(Ei).rewrite(expint) == expint(1, x) + assert expint(1, x).rewrite(Ei).rewrite(expint) == expint(1, x) assert mytn(E1(x), E1(x).rewrite(Shi), Shi(x) - Chi(x), x) assert mytn(E1(polar_lift(I)*x), E1(polar_lift(I)*x).rewrite(Si), @@ -148,7 +372,26 @@ assert mytn(expint(2, x), expint(2, x).rewrite(Ei).rewrite(expint), -x*E1(x) + exp(-x), x) assert mytn(expint(3, x), expint(3, x).rewrite(Ei).rewrite(expint), - x**2*E1(x)/2 + (1-x)*exp(-x)/2, x) + x**2*E1(x)/2 + (1 - x)*exp(-x)/2, x) + + +def test__eis(): + assert _eis(z).diff(z) == -_eis(z) + 1/z + + assert _eis(1/z).series(z) == \ + z + z**2 + 2*z**3 + 6*z**4 + 24*z**5 + O(z**6) + + assert Ei(z).rewrite('tractable') == exp(z)*_eis(z) + assert li(z).rewrite('tractable') == z*_eis(log(z)) + + assert _eis(z).rewrite('intractable') == exp(-z)*Ei(z) + + assert expand(li(z).rewrite('tractable').diff(z).rewrite('intractable')) \ + == li(z).diff(z) + + assert expand(Ei(z).rewrite('tractable').diff(z).rewrite('intractable')) \ + == Ei(z).diff(z) + def tn_arg(func): def test(arg, e1, e2): @@ -158,9 +401,61 @@ v2 = func(e1*v + e2*1e-15).n() return abs(v1 - v2).n() < 1e-10 return test(exp_polar(I*pi/2), I, 1) and \ - test(exp_polar(-I*pi/2), -I, 1) and \ - test(exp_polar(I*pi), -1, I) and \ - test(exp_polar(-I*pi), -1, -I) + test(exp_polar(-I*pi/2), -I, 1) and \ + test(exp_polar(I*pi), -1, I) and \ + test(exp_polar(-I*pi), -1, -I) + + +def test_li(): + z = Symbol("z") + zr = Symbol("z", real=True) + zp = Symbol("z", positive=True) + zn = Symbol("z", negative=True) + + assert li(0) == 0 + assert li(1) == -oo + assert li(oo) == oo + + assert isinstance(li(z), li) + + assert diff(li(z), z) == 1/log(z) + + assert conjugate(li(z)) == li(conjugate(z)) + assert conjugate(li(-zr)) == li(-zr) + assert conjugate(li(-zp)) == conjugate(li(-zp)) + assert conjugate(li(zn)) == conjugate(li(zn)) + + assert li(z).rewrite(Li) == Li(z) + li(2) + assert li(z).rewrite(Ei) == Ei(log(z)) + assert li(z).rewrite(uppergamma) == (-log(1/log(z))/2 - log(-log(z)) + + log(log(z))/2 - expint(1, -log(z))) + assert li(z).rewrite(Si) == (-log(I*log(z)) - log(1/log(z))/2 + + log(log(z))/2 + Ci(I*log(z)) + Shi(log(z))) + assert li(z).rewrite(Ci) == (-log(I*log(z)) - log(1/log(z))/2 + + log(log(z))/2 + Ci(I*log(z)) + Shi(log(z))) + assert li(z).rewrite(Shi) == (-log(1/log(z))/2 + log(log(z))/2 + + Chi(log(z)) - Shi(log(z))) + assert li(z).rewrite(Chi) == (-log(1/log(z))/2 + log(log(z))/2 + + Chi(log(z)) - Shi(log(z))) + assert li(z).rewrite(hyper) ==(log(z)*hyper((1, 1), (2, 2), log(z)) - + log(1/log(z))/2 + log(log(z))/2 + EulerGamma) + assert li(z).rewrite(meijerg) == (-log(1/log(z))/2 - log(-log(z)) + log(log(z))/2 - + meijerg(((), (1,)), ((0, 0), ()), -log(z))) + + assert gruntz(1/li(z), z, oo) == 0 + + +def test_Li(): + assert Li(2) == 0 + assert Li(oo) == oo + + assert isinstance(Li(z), Li) + + assert diff(Li(z), z) == 1/log(z) + + assert gruntz(1/Li(z), z, oo) == 0 + assert Li(z).rewrite(li) == li(z) - li(2) + def test_si(): assert Si(I*x) == I*Shi(x) @@ -174,14 +469,19 @@ assert Shi(exp_polar(2*pi*I)*x) == Shi(x) assert Shi(exp_polar(-2*pi*I)*x) == Shi(x) + assert Si(oo) == pi/2 + assert Si(-oo) == -pi/2 + assert Shi(oo) == oo + assert Shi(-oo) == -oo + assert mytd(Si(x), sin(x)/x, x) assert mytd(Shi(x), sinh(x)/x, x) assert mytn(Si(x), Si(x).rewrite(Ei), - -I*(-Ei(x*exp_polar(-I*pi/2))/2 \ - + Ei(x*exp_polar(I*pi/2))/2 - I*pi) + pi/2, x) + -I*(-Ei(x*exp_polar(-I*pi/2))/2 + + Ei(x*exp_polar(I*pi/2))/2 - I*pi) + pi/2, x) assert mytn(Si(x), Si(x).rewrite(expint), - -I*(-expint(1, x*exp_polar(-I*pi/2))/2 + \ + -I*(-expint(1, x*exp_polar(-I*pi/2))/2 + expint(1, x*exp_polar(I*pi/2))/2) + pi/2, x) assert mytn(Shi(x), Shi(x).rewrite(Ei), Ei(x)/2 - Ei(x*exp_polar(I*pi))/2 + I*pi/2, x) @@ -191,11 +491,14 @@ assert tn_arg(Si) assert tn_arg(Shi) - from sympy import O - assert Si(x).nseries(x, n=8) == x - x**3/18 + x**5/600 - x**7/35280 + O(x**9) - assert Shi(x).nseries(x, n=8) == x + x**3/18 + x**5/600 + x**7/35280 + O(x**9) + assert Si(x).nseries(x, n=8) == \ + x - x**3/18 + x**5/600 - x**7/35280 + O(x**9) + assert Shi(x).nseries(x, n=8) == \ + x + x**3/18 + x**5/600 + x**7/35280 + O(x**9) assert Si(sin(x)).nseries(x, n=5) == x - 2*x**3/9 + 17*x**5/450 + O(x**6) - assert Si(x).nseries(x, 1, n=3) == Si(1) + x*sin(1) + x**2*(-sin(1)/2 + cos(1)/2) + O(x**3) + assert Si(x).nseries(x, 1, n=3) == \ + Si(1) + x*sin(1) + x**2*(-sin(1)/2 + cos(1)/2) + O(x**3) + def test_ci(): m1 = exp_polar(I*pi) @@ -216,6 +519,11 @@ assert Chi(exp_polar(2*I*pi)*x) == Chi(x) + 2*I*pi assert Ci(exp_polar(-2*I*pi)*x) == Ci(x) - 2*I*pi + assert Ci(oo) == 0 + assert Ci(-oo) == I*pi + assert Chi(oo) == oo + assert Chi(-oo) == oo + assert mytd(Ci(x), cos(x)/x, x) assert mytd(Chi(x), cosh(x)/x, x) @@ -228,10 +536,13 @@ assert tn_arg(Chi) from sympy import O, EulerGamma, log, limit - assert Ci(x).nseries(x, n=4) == EulerGamma + log(x) - x**2/4 + x**4/96 + O(x**5) - assert Chi(x).nseries(x, n=4) == EulerGamma + log(x) + x**2/4 + x**4/96 + O(x**5) + assert Ci(x).nseries(x, n=4) == \ + EulerGamma + log(x) - x**2/4 + x**4/96 + O(x**5) + assert Chi(x).nseries(x, n=4) == \ + EulerGamma + log(x) + x**2/4 + x**4/96 + O(x**5) assert limit(log(x) - Ci(2*x), x, 0) == -log(2) - EulerGamma + def test_fresnel(): assert fresnels(0) == 0 assert fresnels(oo) == S.Half @@ -246,24 +557,35 @@ assert fresnels(z).diff(z) == sin(pi*z**2/2) - assert fresnels(z).rewrite(erf) == (S.One+I)/4 * (erf((S.One+I)/2*sqrt(pi)*z) - I*erf((S.One-I)/2*sqrt(pi)*z)) + assert fresnels(z).rewrite(erf) == (S.One + I)/4 * ( + erf((S.One + I)/2*sqrt(pi)*z) - I*erf((S.One - I)/2*sqrt(pi)*z)) - assert fresnels(z).rewrite(hyper) == pi*z**3/6 * hyper([S(3)/4], [S(3)/2, S(7)/4], -pi**2*z**4/16) + assert fresnels(z).rewrite(hyper) == \ + pi*z**3/6 * hyper([S(3)/4], [S(3)/2, S(7)/4], -pi**2*z**4/16) - assert fresnels(z).series(z, n=15) == pi*z**3/6 - pi**3*z**7/336 + pi**5*z**11/42240 + O(z**15) + assert fresnels(z).series(z, n=15) == \ + pi*z**3/6 - pi**3*z**7/336 + pi**5*z**11/42240 + O(z**15) assert fresnels(w).is_real is True - assert fresnels(z).as_real_imag() == ((fresnels(re(z) - I*re(z)*Abs(im(z))/Abs(re(z)))/2 + fresnels(re(z) + I*re(z)*Abs(im(z))/Abs(re(z)))/2, - I*(fresnels(re(z) - I*re(z)*Abs(im(z))/Abs(re(z))) - fresnels(re(z) + I*re(z)*Abs(im(z))/Abs(re(z))))* - re(z)*Abs(im(z))/(2*im(z)*Abs(re(z))))) - - assert fresnels(2+3*I).as_real_imag() == (fresnels(2 + 3*I)/2 + fresnels(2 - 3*I)/2, I*(fresnels(2 - 3*I) - fresnels(2 + 3*I))/2) - - assert expand_func(integrate(fresnels(z), z)) == z*fresnels(z) + cos(pi*z**2/2)/pi - - assert fresnels(z).rewrite(meijerg) == sqrt(2)*pi*z**(S(9)/4)* \ - meijerg(((), (1,)), ((S(3)/4,), (S(1)/4, 0)), -pi**2*z**4/16)/(2*(-z)**(S(3)/4)*(z**2)**(S(3)/4)) + assert fresnels(z).as_real_imag() == \ + ((fresnels(re(z) - I*re(z)*Abs(im(z))/Abs(re(z)))/2 + + fresnels(re(z) + I*re(z)*Abs(im(z))/Abs(re(z)))/2, + I*(fresnels(re(z) - I*re(z)*Abs(im(z))/Abs(re(z))) - + fresnels(re(z) + I*re(z)*Abs(im(z))/Abs(re(z)))) * + re(z)*Abs(im(z))/(2*im(z)*Abs(re(z))))) + + assert fresnels(2 + 3*I).as_real_imag() == ( + fresnels(2 + 3*I)/2 + fresnels(2 - 3*I)/2, + I*(fresnels(2 - 3*I) - fresnels(2 + 3*I))/2 + ) + + assert expand_func(integrate(fresnels(z), z)) == \ + z*fresnels(z) + cos(pi*z**2/2)/pi + + assert fresnels(z).rewrite(meijerg) == sqrt(2)*pi*z**(S(9)/4) * \ + meijerg(((), (1,)), ((S(3)/4,), + (S(1)/4, 0)), -pi**2*z**4/16)/(2*(-z)**(S(3)/4)*(z**2)**(S(3)/4)) assert fresnelc(0) == 0 assert fresnelc(oo) == S.Half @@ -278,25 +600,35 @@ assert fresnelc(z).diff(z) == cos(pi*z**2/2) - assert fresnelc(z).rewrite(erf) == (S.One - I)/4 * (erf((S.One + I)/2*sqrt(pi)*z) + I*erf((S.One - I)/2*sqrt(pi)*z)) + assert fresnelc(z).rewrite(erf) == (S.One - I)/4 * ( + erf((S.One + I)/2*sqrt(pi)*z) + I*erf((S.One - I)/2*sqrt(pi)*z)) - assert fresnelc(z).rewrite(hyper) == z * hyper([S.One/4], [S.One/2, S(5)/4], -pi**2*z**4/16) + assert fresnelc(z).rewrite(hyper) == \ + z * hyper([S.One/4], [S.One/2, S(5)/4], -pi**2*z**4/16) - assert fresnelc(z).series(z, n=15) == z - pi**2*z**5/40 + pi**4*z**9/3456 - pi**6*z**13/599040 + O(z**15) + assert fresnelc(z).series(z, n=15) == \ + z - pi**2*z**5/40 + pi**4*z**9/3456 - pi**6*z**13/599040 + O(z**15) assert fresnelc(w).is_real is True - assert fresnelc(z).as_real_imag() == ((fresnelc(re(z) - I*re(z)*Abs(im(z))/Abs(re(z)))/2 + fresnelc(re(z) + I*re(z)*Abs(im(z))/Abs(re(z)))/2, - I*(fresnelc(re(z) - I*re(z)*Abs(im(z))/Abs(re(z))) - fresnelc(re(z) + I*re(z)*Abs(im(z))/Abs(re(z))))* - re(z)*Abs(im(z))/(2*im(z)*Abs(re(z))))) - - assert fresnelc(2+3*I).as_real_imag() == (fresnelc(2 - 3*I)/2 + fresnelc(2 + 3*I)/2, I*(fresnelc(2 - 3*I) - fresnelc(2 + 3*I))/2) - - assert expand_func(integrate(fresnelc(z), z)) == z*fresnelc(z) - sin(pi*z**2/2)/pi - - assert fresnelc(z).rewrite(meijerg) == sqrt(2)*pi*z**(S(3)/4)* \ - meijerg(((), (1,)), ((S(1)/4,), (S(3)/4, 0)), -pi**2*z**4/16)/(2*(-z)**(S(1)/4)*(z**2)**(S(1)/4)) - + assert fresnelc(z).as_real_imag() == \ + ((fresnelc(re(z) - I*re(z)*Abs(im(z))/Abs(re(z)))/2 + + fresnelc(re(z) + I*re(z)*Abs(im(z))/Abs(re(z)))/2, + I*(fresnelc(re(z) - I*re(z)*Abs(im(z))/Abs(re(z))) - + fresnelc(re(z) + I*re(z)*Abs(im(z))/Abs(re(z)))) * + re(z)*Abs(im(z))/(2*im(z)*Abs(re(z))))) + + assert fresnelc(2 + 3*I).as_real_imag() == ( + fresnelc(2 - 3*I)/2 + fresnelc(2 + 3*I)/2, + I*(fresnelc(2 - 3*I) - fresnelc(2 + 3*I))/2 + ) + + assert expand_func(integrate(fresnelc(z), z)) == \ + z*fresnelc(z) - sin(pi*z**2/2)/pi + + assert fresnelc(z).rewrite(meijerg) == sqrt(2)*pi*z**(S(3)/4) * \ + meijerg(((), (1,)), ((S(1)/4,), + (S(3)/4, 0)), -pi**2*z**4/16)/(2*(-z)**(S(1)/4)*(z**2)**(S(1)/4)) from sympy.utilities.randtest import test_numerically diff -Nru python3-sympy-0.7.2/sympy/functions/special/tests/test_gamma_functions.py python3-sympy-0.7.3/sympy/functions/special/tests/test_gamma_functions.py --- python3-sympy-0.7.2/sympy/functions/special/tests/test_gamma_functions.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/functions/special/tests/test_gamma_functions.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,14 +1,19 @@ -from sympy import (Symbol, gamma, I, oo, nan, zoo, factorial, sqrt, Rational, log, - polygamma, EulerGamma, pi, uppergamma, S, expand_func, loggamma, sin, - cos, O, cancel, lowergamma, exp, erf, beta, exp_polar) +from sympy import ( + Symbol, gamma, I, oo, nan, zoo, factorial, sqrt, Rational, log, + polygamma, EulerGamma, pi, uppergamma, S, expand_func, loggamma, sin, + cos, O, cancel, lowergamma, exp, erf, beta, exp_polar, harmonic, zeta, + factorial) +from sympy.core.function import ArgumentIndexError from sympy.utilities.randtest import (test_derivative_numerically as td, random_complex_number as randcplx, test_numerically as tn) +from sympy.utilities.pytest import raises x = Symbol('x') y = Symbol('y') n = Symbol('n', integer=True) + def test_gamma(): assert gamma(nan) == nan assert gamma(oo) == oo @@ -22,7 +27,7 @@ assert gamma(102) == factorial(101) - assert gamma(Rational(1,2)) == sqrt(pi) + assert gamma(Rational(1, 2)) == sqrt(pi) assert gamma(Rational(3, 2)) == Rational(1, 2)*sqrt(pi) assert gamma(Rational(5, 2)) == Rational(3, 4)*sqrt(pi) @@ -34,16 +39,21 @@ assert gamma(Rational(-15, 2)) == Rational(256, 2027025)*sqrt(pi) - assert gamma(Rational(-11, 8)).expand(func=True) == Rational(64, 33)*gamma(Rational(5, 8)) - assert gamma(Rational(-10, 3)).expand(func=True) == Rational(81, 280)*gamma(Rational(2, 3)) - assert gamma(Rational(14, 3)).expand(func=True) == Rational(880, 81)*gamma(Rational(2, 3)) - assert gamma(Rational(17, 7)).expand(func=True) == Rational(30, 49)*gamma(Rational(3, 7)) - assert gamma(Rational(19, 8)).expand(func=True) == Rational(33, 64)*gamma(Rational(3, 8)) + assert gamma(Rational( + -11, 8)).expand(func=True) == Rational(64, 33)*gamma(Rational(5, 8)) + assert gamma(Rational( + -10, 3)).expand(func=True) == Rational(81, 280)*gamma(Rational(2, 3)) + assert gamma(Rational( + 14, 3)).expand(func=True) == Rational(880, 81)*gamma(Rational(2, 3)) + assert gamma(Rational( + 17, 7)).expand(func=True) == Rational(30, 49)*gamma(Rational(3, 7)) + assert gamma(Rational( + 19, 8)).expand(func=True) == Rational(33, 64)*gamma(Rational(3, 8)) assert gamma(x).diff(x) == gamma(x)*polygamma(0, x) - assert gamma(x - 1).expand(func=True) == gamma(x)/(x-1) - assert gamma(x + 2).expand(func=True, mul=False) == x*(x+1)*gamma(x) + assert gamma(x - 1).expand(func=True) == gamma(x)/(x - 1) + assert gamma(x + 2).expand(func=True, mul=False) == x*(x + 1)*gamma(x) assert expand_func(gamma(x + Rational(3, 2))) == \ (x + Rational(1, 2))*gamma(x + Rational(1, 2)) @@ -54,8 +64,8 @@ # Test a bug: assert expand_func(gamma(x + Rational(3, 4))) == gamma(x + Rational(3, 4)) - assert gamma(3*exp_polar(I*pi)/4).is_nonnegative == False - assert gamma(3*exp_polar(I*pi)/4).is_nonpositive == True + assert gamma(3*exp_polar(I*pi)/4).is_nonnegative is False + assert gamma(3*exp_polar(I*pi)/4).is_nonpositive is True def test_gamma_series(): @@ -63,9 +73,10 @@ 1 - EulerGamma*x + x**2*(EulerGamma**2/2 + pi**2/12) + O(x**3) assert gamma(x).series(x, -1, 3) == \ -1/x + EulerGamma - 1 + x*(-1 - pi**2/12 - EulerGamma**2/2 + EulerGamma) \ - + x**2*(-1 - pi**2/12 - EulerGamma**2/2 + EulerGamma**3/6 - \ + + x**2*(-1 - pi**2/12 - EulerGamma**2/2 + EulerGamma**3/6 - polygamma(2, 1)/6 + EulerGamma*pi**2/12 + EulerGamma) + O(x**3) + def tn_branch(s, func): from sympy import I, pi, exp_polar from random import uniform @@ -75,13 +86,14 @@ expr2 = func(s + eps, -c + eps*I) - func(s + eps, -c - eps*I) return abs(expr.n() - expr2.n()).n() < 1e-10 + def test_lowergamma(): from sympy import meijerg, exp_polar, I, expint - assert lowergamma(x, y).diff(y) == y**(x-1)*exp(-y) + assert lowergamma(x, y).diff(y) == y**(x - 1)*exp(-y) assert td(lowergamma(randcplx(), y), y) assert lowergamma(x, y).diff(x) == \ - gamma(x)*polygamma(0, x) - uppergamma(x, y)*log(y) \ - + meijerg([], [1, 1], [0, 0, x], [], y) + gamma(x)*polygamma(0, x) - uppergamma(x, y)*log(y) \ + + meijerg([], [1, 1], [0, 0, x], [], y) assert lowergamma(S.Half, x) == sqrt(pi)*erf(sqrt(x)) assert not lowergamma(S.Half - 3, x).has(lowergamma) @@ -100,23 +112,26 @@ assert tn_branch(pi, lowergamma) assert lowergamma(3, exp_polar(4*pi*I)*x) == lowergamma(3, x) assert lowergamma(y, exp_polar(5*pi*I)*x) == \ - exp(4*I*pi*y)*lowergamma(y, x*exp_polar(pi*I)) + exp(4*I*pi*y)*lowergamma(y, x*exp_polar(pi*I)) assert lowergamma(-2, exp_polar(5*pi*I)*x) == \ - lowergamma(-2, x*exp_polar(I*pi)) + 2*pi*I + lowergamma(-2, x*exp_polar(I*pi)) + 2*pi*I - assert lowergamma(x, y).rewrite(expint) == -y**x*expint(-x + 1, y) + gamma(x) + assert lowergamma( + x, y).rewrite(expint) == -y**x*expint(-x + 1, y) + gamma(x) k = Symbol('k', integer=True) - assert lowergamma(k, y).rewrite(expint) == -y**k*expint(-k + 1, y) + gamma(k) + assert lowergamma( + k, y).rewrite(expint) == -y**k*expint(-k + 1, y) + gamma(k) k = Symbol('k', integer=True, positive=False) assert lowergamma(k, y).rewrite(expint) == lowergamma(k, y) + def test_uppergamma(): from sympy import meijerg, exp_polar, I, expint assert uppergamma(4, 0) == 6 - assert uppergamma(x, y).diff(y) == -y**(x-1)*exp(-y) + assert uppergamma(x, y).diff(y) == -y**(x - 1)*exp(-y) assert td(uppergamma(randcplx(), y), y) assert uppergamma(x, y).diff(x) == \ - uppergamma(x, y)*log(y) + meijerg([], [1, 1], [0, 0, x], [], y) + uppergamma(x, y)*log(y) + meijerg([], [1, 1], [0, 0, x], [], y) assert td(uppergamma(x, randcplx()), x) assert uppergamma(S.Half, x) == sqrt(pi)*(1 - erf(sqrt(x))) @@ -136,13 +151,15 @@ assert tn_branch(pi, uppergamma) assert uppergamma(3, exp_polar(4*pi*I)*x) == uppergamma(3, x) assert uppergamma(y, exp_polar(5*pi*I)*x) == \ - exp(4*I*pi*y)*uppergamma(y, x*exp_polar(pi*I)) + gamma(y)*(1-exp(4*pi*I*y)) + exp(4*I*pi*y)*uppergamma(y, x*exp_polar(pi*I)) + \ + gamma(y)*(1 - exp(4*pi*I*y)) assert uppergamma(-2, exp_polar(5*pi*I)*x) == \ - uppergamma(-2, x*exp_polar(I*pi)) - 2*pi*I + uppergamma(-2, x*exp_polar(I*pi)) - 2*pi*I assert uppergamma(-2, x) == expint(3, x)/x**2 assert uppergamma(x, y).rewrite(expint) == y**x*expint(-x + 1, y) + def test_polygamma(): from sympy import I @@ -166,7 +183,7 @@ assert polygamma(1, 2) == pi**2/6 - 1 assert polygamma(1, 3) == pi**2/6 - Rational(5, 4) assert polygamma(3, 1) == pi**4 / 15 - assert polygamma(3, 5) == 6*(Rational(-22369,20736) + pi**4/90) + assert polygamma(3, 5) == 6*(Rational(-22369, 20736) + pi**4/90) assert polygamma(5, 1) == 8 * pi**6 / 63 def t(m, n): @@ -185,8 +202,18 @@ assert t(3, 4) assert t(2, 3) + assert polygamma(0, x).rewrite(zeta) == polygamma(0, x) + assert polygamma(1, x).rewrite(zeta) == zeta(2, x) + assert polygamma(2, x).rewrite(zeta) == -2*zeta(3, x) + assert polygamma(3, 7*x).diff(x) == 7*polygamma(4, 7*x) + assert polygamma(0, x).rewrite(harmonic) == harmonic(x - 1) - EulerGamma + assert polygamma(2, x).rewrite(harmonic) == 2*harmonic(x - 1, 3) - 2*zeta(3) + ni = Symbol("n", integer=True) + assert polygamma(ni, x).rewrite(harmonic) == (-1)**(ni + 1)*(-harmonic(x - 1, ni + 1) + + zeta(ni + 1))*factorial(ni) + # Polygamma of non-negative integer order is unbranched: from sympy import exp_polar k = Symbol('n', integer=True, nonnegative=True) @@ -205,61 +232,73 @@ # Test a bug assert polygamma(0, -x).expand(func=True) == polygamma(0, -x) + def test_polygamma_expand_func(): assert polygamma(0, x).expand(func=True) == polygamma(0, x) assert polygamma(0, 2*x).expand(func=True) == \ - polygamma(0, x)/2 + polygamma(0, Rational(1, 2) + x)/2 + log(2) + polygamma(0, x)/2 + polygamma(0, Rational(1, 2) + x)/2 + log(2) assert polygamma(1, 2*x).expand(func=True) == \ - polygamma(1, x)/4 + polygamma(1, Rational(1, 2) + x)/4 + polygamma(1, x)/4 + polygamma(1, Rational(1, 2) + x)/4 assert polygamma(2, x).expand(func=True) == \ - polygamma(2, x) + polygamma(2, x) assert polygamma(0, -1 + x).expand(func=True) == \ - polygamma(0, x) - 1/(x - 1) + polygamma(0, x) - 1/(x - 1) assert polygamma(0, 1 + x).expand(func=True) == \ - 1/x + polygamma(0, x ) + 1/x + polygamma(0, x ) assert polygamma(0, 2 + x).expand(func=True) == \ - 1/x + 1/(1 + x) + polygamma(0, x) + 1/x + 1/(1 + x) + polygamma(0, x) assert polygamma(0, 3 + x).expand(func=True) == \ - polygamma(0, x) + 1/x + 1/(1 + x) + 1/(2 + x) + polygamma(0, x) + 1/x + 1/(1 + x) + 1/(2 + x) assert polygamma(0, 4 + x).expand(func=True) == \ - polygamma(0, x) + 1/x + 1/(1 + x) + 1/(2 + x) + 1/(3 + x) + polygamma(0, x) + 1/x + 1/(1 + x) + 1/(2 + x) + 1/(3 + x) assert polygamma(1, 1 + x).expand(func=True) == \ - polygamma(1, x) - 1/x**2 + polygamma(1, x) - 1/x**2 assert polygamma(1, 2 + x).expand(func=True, multinomial=False) == \ - polygamma(1, x) - 1/x**2 - 1/(1 + x)**2 + polygamma(1, x) - 1/x**2 - 1/(1 + x)**2 assert polygamma(1, 3 + x).expand(func=True, multinomial=False) == \ - polygamma(1, x) - 1/x**2 - 1/(1 + x)**2 - 1/(2 + x)**2 + polygamma(1, x) - 1/x**2 - 1/(1 + x)**2 - 1/(2 + x)**2 assert polygamma(1, 4 + x).expand(func=True, multinomial=False) == \ - polygamma(1, x) - 1/x**2 - 1/(1 + x)**2 - \ - 1/(2 + x)**2 - 1/(3 + x)**2 + polygamma(1, x) - 1/x**2 - 1/(1 + x)**2 - \ + 1/(2 + x)**2 - 1/(3 + x)**2 assert polygamma(0, x + y).expand(func=True) == \ - polygamma(0, x + y) + polygamma(0, x + y) assert polygamma(1, x + y).expand(func=True) == \ - polygamma(1, x + y) + polygamma(1, x + y) assert polygamma(1, 3 + 4*x + y).expand(func=True, multinomial=False) == \ - polygamma(1, y + 4*x) - 1/(y + 4*x)**2 - \ - 1/(1 + y + 4*x)**2 - 1/(2 + y + 4*x)**2 + polygamma(1, y + 4*x) - 1/(y + 4*x)**2 - \ + 1/(1 + y + 4*x)**2 - 1/(2 + y + 4*x)**2 assert polygamma(3, 3 + 4*x + y).expand(func=True, multinomial=False) == \ - polygamma(3, y + 4*x) - 6/(y + 4*x)**4 - \ - 6/(1 + y + 4*x)**4 - 6/(2 + y + 4*x)**4 + polygamma(3, y + 4*x) - 6/(y + 4*x)**4 - \ + 6/(1 + y + 4*x)**4 - 6/(2 + y + 4*x)**4 assert polygamma(3, 4*x + y + 1).expand(func=True, multinomial=False) == \ - polygamma(3, y + 4*x) - 6/(y + 4*x)**4 + polygamma(3, y + 4*x) - 6/(y + 4*x)**4 e = polygamma(3, 4*x + y + S(3)/2) assert e.expand(func=True) == e e = polygamma(3, x + y + S(3)/4) - assert e.expand(func = True, basic = False) == e + assert e.expand(func=True, basic=False) == e + def test_loggamma(): - s1 = loggamma(1/(x+sin(x))+cos(x)).nseries(x,n=4) - s2 = (-log(2*x)-1)/(2*x) - log(x/pi)/2 + (4-log(2*x))*x/24 + O(x**2) + raises(TypeError, lambda: loggamma(2, 3)) + raises(ArgumentIndexError, lambda: loggamma(x).fdiff(2)) + assert loggamma(x).diff(x) == polygamma(0, x) + s1 = loggamma(1/(x + sin(x)) + cos(x)).nseries(x, n=4) + s2 = (-log(2*x) - 1)/(2*x) - log(x/pi)/2 + (4 - log(2*x))*x/24 + O(x**2) assert (s1 - s2).expand(force=True).removeO() == 0 s1 = loggamma(1/x).series(x) - s2 = (1/x-S(1)/2)*log(1/x) - 1/x + log(2*pi)/2 + \ - x/12 - x**3/360 + x**5/1260 + O(x**7) + s2 = (1/x - S(1)/2)*log(1/x) - 1/x + log(2*pi)/2 + \ + x/12 - x**3/360 + x**5/1260 + O(x**7) assert ((s1 - s2).expand(force=True)).removeO() == 0 + assert loggamma(x).rewrite('intractable') == log(gamma(x)) + + assert loggamma(x).is_real is None + y, z = Symbol('y', real=True), Symbol('z', imaginary=True) + assert loggamma(y).is_real + assert loggamma(z).is_real is False + def tN(N, M): - assert loggamma(1/x)._eval_nseries(x,n=N,logx=None).getn() == M + assert loggamma(1/x)._eval_nseries(x, n=N, logx=None).getn() == M tN(0, 0) tN(1, 1) tN(2, 3) @@ -267,16 +306,18 @@ tN(4, 5) tN(5, 5) + def test_polygamma_expansion(): # A. & S., pa. 259 and 260 - assert polygamma(0, 1/x).nseries(x, n=3) \ - == -log(x) - x/2 - x**2/12 + O(x**4) - assert polygamma(1, 1/x).series(x, n=5) \ - == x + x**2/2 + x**3/6 + O(x**5) - assert polygamma(3, 1/x).nseries(x, n=8) \ - == 2*x**3 + 3*x**4 + 2*x**5 - x**7 + 4*x**9/3 + O(x**11) + assert polygamma(0, 1/x).nseries(x, n=3) == \ + -log(x) - x/2 - x**2/12 + O(x**4) + assert polygamma(1, 1/x).series(x, n=5) == \ + x + x**2/2 + x**3/6 + O(x**5) + assert polygamma(3, 1/x).nseries(x, n=8) == \ + 2*x**3 + 3*x**4 + 2*x**5 - x**7 + 4*x**9/3 + O(x**11) + def test_beta_function(): x, y = Symbol('x'), Symbol('y') - assert beta(x,y) == gamma(x)*gamma(y)/gamma(x+y) - assert beta(x,y) == beta(y,x) # Symmetric + assert beta(x, y) == gamma(x)*gamma(y)/gamma(x + y) + assert beta(x, y) == beta(y, x) # Symmetric diff -Nru python3-sympy-0.7.2/sympy/functions/special/tests/test_hyper.py python3-sympy-0.7.3/sympy/functions/special/tests/test_hyper.py --- python3-sympy-0.7.2/sympy/functions/special/tests/test_hyper.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/functions/special/tests/test_hyper.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,21 +1,24 @@ from sympy import (hyper, meijerg, S, Tuple, pi, I, exp, log, - cos, sqrt, symbols, oo, Derivative, gamma) + cos, sqrt, symbols, oo, Derivative, gamma, O) +from sympy.series.limits import limit from sympy.abc import x, z, k from sympy.utilities.pytest import raises from sympy.utilities.randtest import ( - random_complex_number as randcplx, - test_numerically as tn, - test_derivative_numerically as td) + random_complex_number as randcplx, + test_numerically as tn, + test_derivative_numerically as td) + def test_TupleParametersBase(): # test that our implementation of the chain rule works p = hyper((), (), z**2) assert p.diff(z) == p*2*z + def test_hyper(): raises(TypeError, lambda: hyper(1, 2, z)) - assert hyper((1, 2),(1,), z) == hyper(Tuple(1, 2), Tuple(1), z) + assert hyper((1, 2), (1,), z) == hyper(Tuple(1, 2), Tuple(1), z) h = hyper((1, 2), (3, 4, 5), z) assert h.ap == Tuple(1, 2) @@ -28,12 +31,13 @@ assert tn(z*hyper((1, 1), Tuple(2), -z), log(1 + z), z) # differentiation - h = hyper((randcplx(), randcplx(), randcplx()), (randcplx(), randcplx()), z) + h = hyper( + (randcplx(), randcplx(), randcplx()), (randcplx(), randcplx()), z) assert td(h, z) a1, a2, b1, b2, b3 = symbols('a1:3, b1:4') assert hyper((a1, a2), (b1, b2, b3), z).diff(z) == \ - a1*a2/(b1*b2*b3) * hyper((a1+1, a2+1), (b1+1, b2+1, b3+1), z) + a1*a2/(b1*b2*b3) * hyper((a1 + 1, a2 + 1), (b1 + 1, b2 + 1, b3 + 1), z) # differentiation wrt parameters is not supported assert hyper([z], [], z).diff(z) == Derivative(hyper([z], [], z), z) @@ -41,7 +45,8 @@ # hyper is unbranched wrt parameters from sympy import polar_lift assert hyper([polar_lift(z)], [polar_lift(k)], polar_lift(x)) == \ - hyper([z], [k], polar_lift(x)) + hyper([z], [k], polar_lift(x)) + def test_expand_func(): # evaluation at 1 of Gauss' hypergeometric function: @@ -49,16 +54,37 @@ from sympy import gamma, expand_func a1, b1, c1 = randcplx(), randcplx(), randcplx() + 5 assert expand_func(hyper([a, b], [c], 1)) == \ - gamma(c)*gamma(-a - b + c)/(gamma(-a + c)*gamma(-b + c)) + gamma(c)*gamma(-a - b + c)/(gamma(-a + c)*gamma(-b + c)) assert abs(expand_func(hyper([a1, b1], [c1], 1)).n() - hyper([a1, b1], [c1], 1).n()) < 1e-10 # hyperexpand wrapper for hyper: assert expand_func(hyper([], [], z)) == exp(z) assert expand_func(hyper([1, 2, 3], [], z)) == hyper([1, 2, 3], [], z) - assert expand_func(meijerg([[1,1],[]], [[1],[0]], z)) == log(z + 1) - assert expand_func(meijerg([[1,1],[]], [[],[]], z)) \ - == meijerg([[1,1],[]], [[],[]], z) + assert expand_func(meijerg([[1, 1], []], [[1], [0]], z)) == log(z + 1) + assert expand_func(meijerg([[1, 1], []], [[], []], z)) == \ + meijerg([[1, 1], []], [[], []], z) + + +def replace_dummy(expr, sym): + from sympy import Dummy + dum = expr.atoms(Dummy) + if not dum: + return expr + assert len(dum) == 1 + return expr.xreplace({dum.pop(): sym}) + + +def test_hyper_rewrite_sum(): + from sympy import RisingFactorial, factorial, Dummy, Sum + _k = Dummy("k") + assert replace_dummy(hyper((1, 2), (1, 3), x).rewrite(Sum), _k) == \ + Sum(x**_k / factorial(_k) * RisingFactorial(2, _k) / + RisingFactorial(3, _k), (_k, 0, oo)) + + assert hyper((1, 2, 3), (-1, 3), z).rewrite(Sum) == \ + hyper((1, 2, 3), (-1, 3), z) + def test_radius_of_convergence(): assert hyper((1, 2), [3], z).radius_of_convergence == 1 @@ -84,7 +110,7 @@ raises(TypeError, lambda: meijerg(((1,), (2,)), (3,), (4,), z)) assert meijerg(((1, 2), (3,)), ((4,), (5,)), z) == \ - meijerg(Tuple(1, 2), Tuple(3), Tuple(4), Tuple(5), z) + meijerg(Tuple(1, 2), Tuple(3), Tuple(4), Tuple(5), z) g = meijerg((1, 2), (3, 4, 5), (6, 7, 8, 9), (10, 11, 12, 13, 14), z) assert g.an == Tuple(1, 2) @@ -104,7 +130,7 @@ assert tn(meijerg(Tuple(), Tuple(), Tuple(0), Tuple(), -z), exp(z), z) assert tn(sqrt(pi)*meijerg(Tuple(), Tuple(), Tuple(0), Tuple(S(1)/2), z**2/4), cos(z), z) - assert tn(meijerg(Tuple(1, 1),Tuple(), Tuple(1), Tuple(0), z), + assert tn(meijerg(Tuple(1, 1), Tuple(), Tuple(1), Tuple(0), z), log(1 + z), z) # differentiation @@ -122,29 +148,30 @@ a1, a2, b1, b2, c1, c2, d1, d2 = symbols('a1:3, b1:3, c1:3, d1:3') assert meijerg((a1, a2), (b1, b2), (c1, c2), (d1, d2), z).diff(z) == \ - (meijerg((a1-1, a2), (b1, b2), (c1, c2), (d1, d2), z) \ + (meijerg((a1 - 1, a2), (b1, b2), (c1, c2), (d1, d2), z) + (a1 - 1)*meijerg((a1, a2), (b1, b2), (c1, c2), (d1, d2), z))/z assert meijerg([z, z], [], [], [], z).diff(z) == \ - Derivative(meijerg([z, z], [], [], [], z), z) + Derivative(meijerg([z, z], [], [], [], z), z) # meijerg is unbranched wrt parameters from sympy import polar_lift as pl assert meijerg([pl(a1)], [pl(a2)], [pl(b1)], [pl(b2)], pl(z)) == \ - meijerg([a1], [a2], [b1], [b2], pl(z)) + meijerg([a1], [a2], [b1], [b2], pl(z)) # integrand from sympy.abc import a, b, c, d, s assert meijerg([a], [b], [c], [d], z).integrand(s) == \ - z**s*gamma(c - s)*gamma(-a + s + 1)/(gamma(b - s)*gamma(-d + s + 1)) + z**s*gamma(c - s)*gamma(-a + s + 1)/(gamma(b - s)*gamma(-d + s + 1)) + def test_meijerg_derivative(): assert meijerg([], [1, 1], [0, 0, x], [], z).diff(x) == \ - log(z)*meijerg([], [1, 1], [0, 0, x], [], z) \ - + 2*meijerg([], [1, 1, 1], [0, 0, x, 0], [], z) + log(z)*meijerg([], [1, 1], [0, 0, x], [], z) \ + + 2*meijerg([], [1, 1, 1], [0, 0, x, 0], [], z) y = randcplx() - a = 5 # mpmath chokes with non-real numbers, and Mod1 with floats + a = 5 # mpmath chokes with non-real numbers, and Mod1 with floats assert td(meijerg([x], [], [], [], y), x) assert td(meijerg([x**2], [], [], [], y), x) assert td(meijerg([], [x], [], [], y), x) @@ -157,13 +184,17 @@ b = S(3)/2 assert td(meijerg([a + 2], [b], [b - 3, x], [a], y), x) + def test_meijerg_period(): assert meijerg([], [1], [0], [], x).get_period() == 2*pi assert meijerg([1], [], [], [0], x).get_period() == 2*pi - assert meijerg([], [], [0], [], x).get_period() == 2*pi # exp(x) - assert meijerg([], [], [0], [S(1)/2], x).get_period() == 2*pi # cos(sqrt(x)) - assert meijerg([], [], [S(1)/2], [0], x).get_period() == 4*pi # sin(sqrt(x)) - assert meijerg([1, 1], [], [1], [0], x).get_period() == oo # log(1 + x) + assert meijerg([], [], [0], [], x).get_period() == 2*pi # exp(x) + assert meijerg( + [], [], [0], [S(1)/2], x).get_period() == 2*pi # cos(sqrt(x)) + assert meijerg( + [], [], [S(1)/2], [0], x).get_period() == 4*pi # sin(sqrt(x)) + assert meijerg([1, 1], [], [1], [0], x).get_period() == oo # log(1 + x) + def test_hyper_unpolarify(): from sympy import exp_polar @@ -174,6 +205,7 @@ assert hyper([0], [0], a).argument == b assert hyper([0, 1], [0], a).argument == a + def test_hyperrep(): from sympy.functions.special.hyper import (HyperRep, HyperRep_atanh, HyperRep_power1, HyperRep_power2, HyperRep_log1, HyperRep_asin1, @@ -182,26 +214,34 @@ # First test the base class works. from sympy import Piecewise, exp_polar a, b, c, d, z = symbols('a b c d z') + class myrep(HyperRep): @classmethod - def _expr_small(cls, x): return a + def _expr_small(cls, x): + return a + @classmethod - def _expr_small_minus(cls, x): return b + def _expr_small_minus(cls, x): + return b + @classmethod - def _expr_big(cls, x, n): return c*n + def _expr_big(cls, x, n): + return c*n + @classmethod - def _expr_big_minus(cls, x, n): return d*n + def _expr_big_minus(cls, x, n): + return d*n assert myrep(z).rewrite('nonrep') == Piecewise((0, abs(z) > 1), (a, True)) assert myrep(exp_polar(I*pi)*z).rewrite('nonrep') == \ - Piecewise((0, abs(z) > 1), (b, True)) + Piecewise((0, abs(z) > 1), (b, True)) assert myrep(exp_polar(2*I*pi)*z).rewrite('nonrep') == \ - Piecewise((c, abs(z) > 1), (a, True)) + Piecewise((c, abs(z) > 1), (a, True)) assert myrep(exp_polar(3*I*pi)*z).rewrite('nonrep') == \ - Piecewise((d, abs(z) > 1), (b, True)) + Piecewise((d, abs(z) > 1), (b, True)) assert myrep(exp_polar(4*I*pi)*z).rewrite('nonrep') == \ - Piecewise((2*c, abs(z) > 1), (a, True)) + Piecewise((2*c, abs(z) > 1), (a, True)) assert myrep(exp_polar(5*I*pi)*z).rewrite('nonrep') == \ - Piecewise((2*d, abs(z) > 1), (b, True)) + Piecewise((2*d, abs(z) > 1), (b, True)) assert myrep(z).rewrite('nonrepsmall') == a assert myrep(exp_polar(I*pi)*z).rewrite('nonrepsmall') == b @@ -212,15 +252,18 @@ a=S(-1)/2, b=S(-1)/2, c=S(1)/2, d=S(1)/2): return False # Next check that the two small representations agree. - if not tn(func.rewrite('nonrepsmall').subs(z, exp_polar(I*pi)*z).replace(exp_polar, exp), - func.subs(z, exp_polar(I*pi)*z).rewrite('nonrepsmall'), - z, a=S(-1)/2, b=S(-1)/2, c=S(1)/2, d=S(1)/2): + if not tn( + func.rewrite('nonrepsmall').subs( + z, exp_polar(I*pi)*z).replace(exp_polar, exp), + func.subs(z, exp_polar(I*pi)*z).rewrite('nonrepsmall'), + z, a=S(-1)/2, b=S(-1)/2, c=S(1)/2, d=S(1)/2): return False # Next check continuity along exp_polar(I*pi)*t expr = func.subs(z, exp_polar(I*pi)*z).rewrite('nonrep') if abs(expr.subs(z, 1 + 1e-15).n() - expr.subs(z, 1 - 1e-15).n()) > 1e-10: return False # Finally check continuity of the big reps. + def dosubs(func, a, b): rv = func.subs(z, exp_polar(a)*z).rewrite('nonrep') return rv.subs(z, exp_polar(b)*z).replace(exp_polar, exp) @@ -248,14 +291,15 @@ -2*z/(2*a + 1)*hyper([-a - S(1)/2, -a], [S(1)/2], z).diff(z), z) assert t(HyperRep_log2(z), -z/4*hyper([S(3)/2, 1, 1], [2, 2], z), z) assert t(HyperRep_cosasin(a, z), hyper([-a, a], [S(1)/2], z), z) - assert t(HyperRep_sinasin(a, z), 2*a*z*hyper([1-a, 1+a], [S(3)/2], z), z) + assert t(HyperRep_sinasin(a, z), 2*a*z*hyper([1 - a, 1 + a], [S(3)/2], z), z) + def test_meijerg_eval(): from sympy import besseli, exp_polar from sympy.abc import l a = randcplx() arg = x*exp_polar(k*pi*I) - expr1 = pi*meijerg([[], [(a+1)/2]], [[a/2], [-a/2, (a+ 1)/2]], arg**2/4) + expr1 = pi*meijerg([[], [(a + 1)/2]], [[a/2], [-a/2, (a + 1)/2]], arg**2/4) expr2 = besseli(a, arg) # Test that the two expressions agree for all arguments. @@ -270,11 +314,22 @@ for x_ in [0.5, 1.5]: for k_ in [0.5, S(1)/3, 0.25, 0.75, S(2)/3, 1.0, 1.5]: assert abs((expr1 - expr2).n( - subs={x: x_, k: k_ + eps, l: k_ - eps})) < 1e-10 + subs={x: x_, k: k_ + eps, l: k_ - eps})) < 1e-10 assert abs((expr1 - expr2).n( - subs={x: x_, k: -k_ + eps, l: -k_ - eps})) < 1e-10 + subs={x: x_, k: -k_ + eps, l: -k_ - eps})) < 1e-10 expr = (meijerg(((0.5,), ()), ((0.5, 0, 0.5), ()), exp_polar(-I*pi)/4) + meijerg(((0.5,), ()), ((0.5, 0, 0.5), ()), exp_polar(I*pi)/4)) \ - /(2*sqrt(pi)) + /(2*sqrt(pi)) assert (expr - pi/exp(1)).n(chop=True) == 0 + + +def test_limits(): + k, x = symbols('k, x') + assert hyper((1,), (S(4)/3, S(5)/3), k**2).series(k) == \ + hyper((1,), (S(4)/3, S(5)/3), 0) + \ + 9*k**2*hyper((2,), (S(7)/3, S(8)/3), 0)/20 + \ + 81*k**4*hyper((3,), (S(10)/3, S(11)/3), 0)/1120 + \ + O(k**6) # issue 3251 + assert limit(meijerg((), (), (1,), (0,), -x), x, 0) == \ + meijerg(((), ()), ((1,), (0,)), 0) # issue 2953 diff -Nru python3-sympy-0.7.2/sympy/functions/special/tests/test_spec_polynomials.py python3-sympy-0.7.3/sympy/functions/special/tests/test_spec_polynomials.py --- python3-sympy-0.7.2/sympy/functions/special/tests/test_spec_polynomials.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/functions/special/tests/test_spec_polynomials.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,12 +1,14 @@ -from sympy import (Symbol, Dummy, diff, Derivative, Rational, roots, sympify, S, sqrt, hyper, - cos, gamma, conjugate, factorial, pi, oo, zoo, binomial, Sum, RisingFactorial, - legendre, assoc_legendre, chebyshevu, chebyshevt, chebyshevt_root, chebyshevu_root, - laguerre, assoc_laguerre, laguerre_poly, hermite, gegenbauer, jacobi) +from sympy import ( + Symbol, Dummy, diff, Derivative, Rational, roots, sympify, S, sqrt, hyper, + cos, gamma, conjugate, factorial, pi, oo, zoo, binomial, Sum, RisingFactorial, + legendre, assoc_legendre, chebyshevu, chebyshevt, chebyshevt_root, chebyshevu_root, + laguerre, assoc_laguerre, laguerre_poly, hermite, gegenbauer, jacobi, jacobi_normalized) from sympy.utilities.pytest import raises x = Symbol('x') + def test_jacobi(): n = Symbol("n") a = Symbol("a") @@ -15,29 +17,40 @@ assert jacobi(0, a, b, x) == 1 assert jacobi(1, a, b, x) == a/2 - b/2 + x*(a/2 + b/2 + 1) - assert jacobi(n, a, a, x) == RisingFactorial(a + 1, n)*gegenbauer(n, a + S(1)/2, x)/RisingFactorial(2*a + 1, n) + assert jacobi(n, a, a, x) == RisingFactorial( + a + 1, n)*gegenbauer(n, a + S(1)/2, x)/RisingFactorial(2*a + 1, n) assert jacobi(n, a, -a, x) == ((-1)**a*(-x + 1)**(-a/2)*(x + 1)**(a/2)*assoc_legendre(n, a, x)* factorial(-a + n)*gamma(a + n + 1)/(factorial(a + n)*gamma(n + 1))) assert jacobi(n, -b, b, x) == ((-x + 1)**(b/2)*(x + 1)**(-b/2)*assoc_legendre(n, b, x)* gamma(-b + n + 1)/gamma(n + 1)) assert jacobi(n, 0, 0, x) == legendre(n, x) - assert jacobi(n, S.Half, S.Half, x) == RisingFactorial(S(3)/2, n)*chebyshevu(n, x)/factorial(n + 1) - assert jacobi(n, -S.Half, -S.Half, x) == RisingFactorial(S(1)/2, n)*chebyshevt(n, x)/factorial(n) + assert jacobi(n, S.Half, S.Half, x) == RisingFactorial( + S(3)/2, n)*chebyshevu(n, x)/factorial(n + 1) + assert jacobi(n, -S.Half, -S.Half, x) == RisingFactorial( + S(1)/2, n)*chebyshevt(n, x)/factorial(n) X = jacobi(n, a, b, x) assert isinstance(X, jacobi) assert jacobi(n, a, b, -x) == (-1)**n*jacobi(n, b, a, x) - assert jacobi(n, a, b, 0) == 2**(-n)*gamma(a + n + 1)*hyper((-b - n, -n), (a + 1,), -1)/(factorial(n)*gamma(a + 1)) + assert jacobi(n, a, b, 0) == 2**(-n)*gamma(a + n + 1)*hyper( + (-b - n, -n), (a + 1,), -1)/(factorial(n)*gamma(a + 1)) assert jacobi(n, a, b, 1) == RisingFactorial(a + 1, n)/factorial(n) m = Symbol("m", positive=True) assert jacobi(m, a, b, oo) == oo*RisingFactorial(a + b + m + 1, m) - assert conjugate(jacobi(m, a, b, x)) == jacobi(m, conjugate(a), conjugate(b), conjugate(x)) + assert conjugate(jacobi(m, a, b, x)) == \ + jacobi(m, conjugate(a), conjugate(b), conjugate(x)) + + assert diff(jacobi(n, a, b, x), n) == Derivative(jacobi(n, a, b, x), n) + assert diff(jacobi(n, a, b, x), x) == \ + (a/2 + b/2 + n/2 + S(1)/2)*jacobi(n - 1, a + 1, b + 1, x) + + assert jacobi_normalized(n, a, b, x) == \ + (jacobi(n, a, b, x)/sqrt(2**(a + b + 1)*gamma(a + n + 1)*gamma(b + n + 1) + /((a + b + 2*n + 1)*factorial(n)*gamma(a + b + n + 1)))) - assert diff(jacobi(n,a,b,x), n) == Derivative(jacobi(n, a, b, x), n) - assert diff(jacobi(n,a,b,x), x) == (a/2 + b/2 + n/2 + S(1)/2)*jacobi(n - 1, a + 1, b + 1, x) def test_gegenbauer(): n = Symbol("n") @@ -46,8 +59,8 @@ assert gegenbauer(0, a, x) == 1 assert gegenbauer(1, a, x) == 2*a*x assert gegenbauer(2, a, x) == -a + x**2*(2*a**2 + 2*a) - assert gegenbauer(3, a, x) == x**3*(4*a**3/3 + 4*a**2 + 8*a/3) + x*(-2*a**2 - 2*a) - + assert gegenbauer(3, a, x) == \ + x**3*(4*a**3/3 + 4*a**2 + 8*a/3) + x*(-2*a**2 - 2*a) assert gegenbauer(-1, a, x) == 0 assert gegenbauer(n, S(1)/2, x) == legendre(n, x) @@ -58,7 +71,8 @@ assert isinstance(X, gegenbauer) assert gegenbauer(n, a, -x) == (-1)**n*gegenbauer(n, a, x) - assert gegenbauer(n, a, 0) == 2**n*sqrt(pi)*gamma(a + n/2)/(gamma(a)*gamma(-n/2 + S(1)/2)*gamma(n + 1)) + assert gegenbauer(n, a, 0) == 2**n*sqrt(pi) * \ + gamma(a + n/2)/(gamma(a)*gamma(-n/2 + S(1)/2)*gamma(n + 1)) assert gegenbauer(n, a, 1) == gamma(2*a + n)/(gamma(2*a)*gamma(n + 1)) assert gegenbauer(n, a, -1) == zoo @@ -66,20 +80,22 @@ m = Symbol("m", positive=True) assert gegenbauer(m, a, oo) == oo*RisingFactorial(a, m) - assert conjugate(gegenbauer(n, a, x)) == gegenbauer(n, conjugate(a), conjugate(x)) + assert conjugate(gegenbauer(n, a, x)) == \ + gegenbauer(n, conjugate(a), conjugate(x)) assert diff(gegenbauer(n, a, x), n) == Derivative(gegenbauer(n, a, x), n) assert diff(gegenbauer(n, a, x), x) == 2*a*gegenbauer(n - 1, a + 1, x) + def test_legendre(): raises(ValueError, lambda: legendre(-1, x)) assert legendre(0, x) == 1 assert legendre(1, x) == x - assert legendre(2, x) == ((3*x**2-1)/2).expand() - assert legendre(3, x) == ((5*x**3-3*x)/2).expand() - assert legendre(4, x) == ((35*x**4-30*x**2+3)/8).expand() - assert legendre(5, x) == ((63*x**5-70*x**3+15*x)/8).expand() - assert legendre(6, x) == ((231*x**6-315*x**4+105*x**2-5)/16).expand() + assert legendre(2, x) == ((3*x**2 - 1)/2).expand() + assert legendre(3, x) == ((5*x**3 - 3*x)/2).expand() + assert legendre(4, x) == ((35*x**4 - 30*x**2 + 3)/8).expand() + assert legendre(5, x) == ((63*x**5 - 70*x**3 + 15*x)/8).expand() + assert legendre(6, x) == ((231*x**6 - 315*x**4 + 105*x**2 - 5)/16).expand() assert legendre(10, -1) == 1 assert legendre(11, -1) == -1 @@ -88,63 +104,66 @@ assert legendre(10, 0) != 0 assert legendre(11, 0) == 0 - assert roots(legendre(4,x), x) == { - sqrt(Rational(3, 7) - Rational(2, 35)*sqrt(30)): 1, + assert roots(legendre(4, x), x) == { + sqrt(Rational(3, 7) - Rational(2, 35)*sqrt(30)): 1, -sqrt(Rational(3, 7) - Rational(2, 35)*sqrt(30)): 1, - sqrt(Rational(3, 7) + Rational(2, 35)*sqrt(30)): 1, + sqrt(Rational(3, 7) + Rational(2, 35)*sqrt(30)): 1, -sqrt(Rational(3, 7) + Rational(2, 35)*sqrt(30)): 1, } n = Symbol("n") - X = legendre(n,x) + X = legendre(n, x) assert isinstance(X, legendre) - assert legendre(-n,x) == legendre(n-1, x) - assert legendre(n,-x) == (-1)**n*legendre(n, x) - assert diff(legendre(n,x), x) == n*(x*legendre(n, x) - legendre(n - 1, x))/(x**2 - 1) - assert diff(legendre(n,x), n) == Derivative(legendre(n, x), n) + assert legendre(-n, x) == legendre(n - 1, x) + assert legendre(n, -x) == (-1)**n*legendre(n, x) + assert diff(legendre(n, x), x) == \ + n*(x*legendre(n, x) - legendre(n - 1, x))/(x**2 - 1) + assert diff(legendre(n, x), n) == Derivative(legendre(n, x), n) + def test_assoc_legendre(): - Plm=assoc_legendre - Q=sqrt(1-x**2) + Plm = assoc_legendre + Q = sqrt(1 - x**2) - assert Plm(0, 0, x) == 1 - assert Plm(1, 0, x) == x + assert Plm(0, 0, x) == 1 + assert Plm(1, 0, x) == x assert Plm(1, 1, x) == -Q - assert Plm(2, 0, x) == (3*x**2-1)/2 + assert Plm(2, 0, x) == (3*x**2 - 1)/2 assert Plm(2, 1, x) == -3*x*Q - assert Plm(2, 2, x) == 3*Q**2 - assert Plm(3, 0, x) == (5*x**3-3*x)/2 - assert Plm(3, 1, x).expand() == (( 3*(1-5*x**2)/2 ).expand() * Q).expand() - assert Plm(3, 2, x) == 15*x * Q**2 + assert Plm(2, 2, x) == 3*Q**2 + assert Plm(3, 0, x) == (5*x**3 - 3*x)/2 + assert Plm(3, 1, x).expand() == (( 3*(1 - 5*x**2)/2 ).expand() * Q).expand() + assert Plm(3, 2, x) == 15*x * Q**2 assert Plm(3, 3, x) == -15 * Q**3 # negative m - assert Plm(1,-1, x) == -Plm(1, 1, x)/2 - assert Plm(2,-2, x) == Plm(2, 2, x)/24 - assert Plm(2,-1, x) == -Plm(2, 1, x)/6 - assert Plm(3,-3, x) == -Plm(3, 3, x)/720 - assert Plm(3,-2, x) == Plm(3, 2, x)/120 - assert Plm(3,-1, x) == -Plm(3, 1, x)/12 + assert Plm(1, -1, x) == -Plm(1, 1, x)/2 + assert Plm(2, -2, x) == Plm(2, 2, x)/24 + assert Plm(2, -1, x) == -Plm(2, 1, x)/6 + assert Plm(3, -3, x) == -Plm(3, 3, x)/720 + assert Plm(3, -2, x) == Plm(3, 2, x)/120 + assert Plm(3, -1, x) == -Plm(3, 1, x)/12 n = Symbol("n") m = Symbol("m") - X = Plm(n,m, x) + X = Plm(n, m, x) assert isinstance(X, assoc_legendre) - assert Plm(n,0, x) == legendre(n, x) + assert Plm(n, 0, x) == legendre(n, x) raises(ValueError, lambda: Plm(-1, 0, x)) raises(ValueError, lambda: Plm(0, 1, x)) + def test_chebyshev(): assert chebyshevt(0, x) == 1 assert chebyshevt(1, x) == x - assert chebyshevt(2, x) == 2*x**2-1 - assert chebyshevt(3, x) == 4*x**3-3*x + assert chebyshevt(2, x) == 2*x**2 - 1 + assert chebyshevt(3, x) == 4*x**3 - 3*x for n in range(1, 4): for k in range(n): @@ -178,7 +197,9 @@ assert chebyshevu(n, 0) == cos(pi*n/2) assert chebyshevu(n, 1) == n + 1 - assert diff(chebyshevu(n, x), x) == (-x*chebyshevu(n, x) + (n + 1)*chebyshevt(n + 1, x))/(x**2 - 1) + assert diff(chebyshevu(n, x), x) == \ + (-x*chebyshevu(n, x) + (n + 1)*chebyshevt(n + 1, x))/(x**2 - 1) + def test_hermite(): assert hermite(0, x) == 1 @@ -194,7 +215,8 @@ assert hermite(-n, x) == hermite(-n, x) assert diff(hermite(n, x), x) == 2*n*hermite(n - 1, x) - assert diff(hermite(n, x), n) == Derivative(hermite(n, x), n) + assert diff(hermite(n, x), n) == Derivative(hermite(n, x), n) + def test_laguerre(): alpha = Symbol("alpha") @@ -202,8 +224,11 @@ # generalized Laguerre polynomials: assert assoc_laguerre(0, alpha, x) == 1 assert assoc_laguerre(1, alpha, x) == -x + alpha + 1 - assert assoc_laguerre(2, alpha, x).expand() == (x**2/2 - (alpha+2)*x + (alpha+2)*(alpha+1)/2).expand() - assert assoc_laguerre(3, alpha, x).expand() == (-x**3/6 + (alpha+3)*x**2/2 - (alpha+2)*(alpha+3)*x/2 + (alpha+1)*(alpha+2)*(alpha+3)/6).expand() + assert assoc_laguerre(2, alpha, x).expand() == \ + (x**2/2 - (alpha + 2)*x + (alpha + 2)*(alpha + 1)/2).expand() + assert assoc_laguerre(3, alpha, x).expand() == \ + (-x**3/6 + (alpha + 3)*x**2/2 - (alpha + 2)*(alpha + 3)*x/2 + + (alpha + 1)*(alpha + 2)*(alpha + 3)/6).expand() # Laguerre polynomials: assert assoc_laguerre(0, 0, x) == 1 @@ -231,6 +256,7 @@ assert assoc_laguerre(n, 0, x) == laguerre(n, x) assert assoc_laguerre(n, alpha, 0) == binomial(alpha + n, alpha) - assert diff(assoc_laguerre(n, alpha, x), x) == -assoc_laguerre(n - 1, alpha + 1, x) + assert diff(assoc_laguerre(n, alpha, x), x) == \ + -assoc_laguerre(n - 1, alpha + 1, x) #k = Dummy("k") #assert diff(assoc_laguerre(n, alpha, x), alpha) == Sum(assoc_laguerre(k, alpha, x)/(-alpha + n), (k, 0, n - 1)) diff -Nru python3-sympy-0.7.2/sympy/functions/special/tests/test_spherical_harmonics.py python3-sympy-0.7.3/sympy/functions/special/tests/test_spherical_harmonics.py --- python3-sympy-0.7.2/sympy/functions/special/tests/test_spherical_harmonics.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/functions/special/tests/test_spherical_harmonics.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,81 +1,63 @@ -from sympy import Ylm, Zlm, Symbol, sympify, sqrt, pi, sin, cos, exp, I, S -from sympy.functions.special.spherical_harmonics import Pl, Plm, Plmcos +from sympy import Symbol, sqrt, pi, sin, cos, cot, exp, I, S, diff, conjugate +from sympy.functions.special.spherical_harmonics import Ynm, Znm, Ynm_c from sympy.utilities.pytest import XFAIL -def test_Pl(): - x = Symbol("x") - assert Pl(0, x) == 1 - assert Pl(1, x) == x - assert Pl(2, x) == ((3*x**2 - 1)/2).expand() - assert Pl(3, x) == ((5*x**3 - 3*x)/2).expand() - assert Pl(4, x) == ((35*x**4-30*x**2+3)/8).expand() - assert Pl(5, x) == ((63*x**5-70*x**3+15*x)/8).expand() - assert Pl(6, x) == ((231*x**6-315*x**4+105*x**2-5)/16).expand() - -def test_Plm(): - #http://en.wikipedia.org/wiki/Legendre_function - x = Symbol("x") - assert Plm(0, 0, x) == 1 - assert Plm(1, -1, x) == -Plm(1, 1, x)/2 - assert Plm(1, 0, x) == x - assert Plm(1, 1, x) == -(1-x**2)**(sympify(1)/2) - assert Plm(2, -2, x) == Plm(2, 2, x)/24 - assert Plm(2, -1, x) == -Plm(2, 1, x)/6 - assert Plm(2, 0, x) == (3*x**2-1)/2 - assert Plm(2, 1, x) == -3*x*(1-x**2)**(sympify(1)/2) - assert Plm(2, 2, x) == 3*(1-x**2) - assert Plm(3, -3, x) == -Plm(3, 3, x)/720 - assert Plm(3, -2, x) == Plm(3, 2, x)/120 - assert Plm(3, -1, x) == -Plm(3, 1, x)/12 - assert Plm(3, 0, x) == (5*x**3-3*x)/2 - assert Plm(3, 1, x).expand() == (( 3*(1-5*x**2)/2 ).expand() \ - *(1-x**2)**(sympify(1)/2)).expand() - assert Plm(3, 2, x) == 15*x*(1-x**2) - assert Plm(3, 3, x) == -15*(1-x**2)**(sympify(3)/2) - -def test_Plmcos(): - #http://en.wikipedia.org/wiki/Legendre_function - th = Symbol("th", real = True) - assert Plmcos(0, 0, th) == 1 - assert Plmcos(1, -1, th) == sin(th)/2 - assert Plmcos(1, 0, th) == cos(th) - assert Plmcos(1, 1, th) == -sin(th) - assert Plmcos(2, 0, th) == (3*cos(th)**2-1)/2 - assert Plmcos(2, 1, th) == -3*cos(th)*sin(th) - assert Plmcos(2, 2, th) in [3*sin(th)**2, 3*(1-cos(th)**2)] - assert Plmcos(3, 0, th) == (5*cos(th)**3-3*cos(th))/2 - assert Plmcos(3, 1, th) == -sin(th)*(15*cos(th)**2/2-S(3)/2) - assert Plmcos(3, 2, th) == 15*cos(th)*sin(th)**2 - assert Plmcos(3, 3, th) == -15*sin(th)**3 - -def test_Ylm(): - #http://en.wikipedia.org/wiki/Spherical_harmonics - th, ph = Symbol("theta", real = True), Symbol("phi", real = True) - assert Ylm(0, 0, th, ph) == sympify(1)/(2*sqrt(pi)) - assert Ylm(1, -1, th, ph) == sympify(1)/2 * sqrt(3/(2*pi)) * sin(th) * \ - exp(-I*ph) - assert Ylm(1, 0, th, ph) == sympify(1)/2 * sqrt(3/pi) * cos(th) - assert Ylm(1, 1, th, ph) == -sympify(1)/2 * sqrt(3/(2*pi)) * sin(th) * \ - exp(I*ph) - assert Ylm(2, 0, th, ph).expand() == (sympify(1)/4 * sqrt(5/pi) * \ - (3*cos(th)**2-1)).expand() - assert Ylm(2, 1, th, ph).expand() == (-sympify(1)/2 * \ - sqrt(3)*sqrt(5/(2*pi)) * (sin(th)*cos(th)) * exp(I*ph)).expand() - - # These last 2 return the correct answer, but the answer can be simplified - assert Ylm(2, -2, th, ph).expand() == -sqrt(30)*exp(-2*I*ph)*cos(th)**S(2)/(8*sqrt(pi)) + \ - S(sqrt(30)*exp(-2*I*ph))/(8*sqrt(pi)) - assert Ylm(2, 2, th, ph).expand() == S(-sqrt(30)*exp(2*I*ph)*cos(th)**2)/(8*sqrt(pi)) + S(sqrt(30)*exp(2*I*ph))/(8*sqrt(pi)) - -def test_Zlm(): - #http://en.wikipedia.org/wiki/Solid_harmonics#List_of_lowest_functions - th, ph = Symbol("theta", real = True), Symbol("phi", real = True) - assert Zlm(0, 0, th, ph) == sqrt(1/(4*pi)) - assert Zlm(1, -1, th, ph) == sqrt(3/(4*pi))*sin(th)*sin(ph) - assert Zlm(1, 0, th, ph) == sqrt(3/(4*pi))*cos(th) - assert Zlm(1, 1, th, ph) == sqrt(3/(4*pi))*sin(th)*cos(ph) - - assert Zlm(2, -1, th, ph) == sqrt(15/(4*pi))*sin(th)*cos(th)*sin(ph) - assert Zlm(2, 0, th, ph).expand() == (sympify(1)/4 * sqrt(5/pi) * \ - (3*cos(th)**2-1)).expand() - assert Zlm(2, 1, th, ph) == sqrt(15/(4*pi))*sin(th)*cos(th)*cos(ph) + +def test_Ynm(): + # http://en.wikipedia.org/wiki/Spherical_harmonics + th, ph = Symbol("theta", real=True), Symbol("phi", real=True) + from sympy.abc import n,m + + assert Ynm(0, 0, th, ph).expand(func=True) == 1/(2*sqrt(pi)) + assert Ynm(1, -1, th, ph) == -exp(-2*I*ph)*Ynm(1, 1, th, ph) + assert Ynm(1, -1, th, ph).expand(func=True) == sqrt(6)*sqrt(-cos(th)**2 + 1)*exp(-I*ph)/(4*sqrt(pi)) + assert Ynm(1, -1, th, ph).expand(func=True) == sqrt(6)*sqrt(-cos(th)**2 + 1)*exp(-I*ph)/(4*sqrt(pi)) + assert Ynm(1, 0, th, ph).expand(func=True) == sqrt(3)*cos(th)/(2*sqrt(pi)) + assert Ynm(1, 1, th, ph).expand(func=True) == -sqrt(6)*sqrt(-cos(th)**2 + 1)*exp(I*ph)/(4*sqrt(pi)) + assert Ynm(2, 0, th, ph).expand(func=True) == 3*sqrt(5)*cos(th)**2/(4*sqrt(pi)) - sqrt(5)/(4*sqrt(pi)) + assert Ynm(2, 1, th, ph).expand(func=True) == -sqrt(30)*sqrt(-cos(th)**2 + 1)*exp(I*ph)*cos(th)/(4*sqrt(pi)) + assert Ynm(2, -2, th, ph).expand(func=True) == (-sqrt(30)*exp(-2*I*ph)*cos(th)**2/(8*sqrt(pi)) + + sqrt(30)*exp(-2*I*ph)/(8*sqrt(pi))) + assert Ynm(2, 2, th, ph).expand(func=True) == (-sqrt(30)*exp(2*I*ph)*cos(th)**2/(8*sqrt(pi)) + + sqrt(30)*exp(2*I*ph)/(8*sqrt(pi))) + + assert diff(Ynm(n, m, th, ph), th) == (m*cot(th)*Ynm(n, m, th, ph) + + sqrt((-m + n)*(m + n + 1))*exp(-I*ph)*Ynm(n, m + 1, th, ph)) + assert diff(Ynm(n, m, th, ph), ph) == I*m*Ynm(n, m, th, ph) + + assert conjugate(Ynm(n, m, th, ph)) == (-1)**(2*m)*exp(-2*I*m*ph)*Ynm(n, m, th, ph) + + assert Ynm(n, m, -th, ph) == Ynm(n, m, th, ph) + assert Ynm(n, m, th, -ph) == exp(-2*I*m*ph)*Ynm(n, m, th, ph) + assert Ynm(n, -m, th, ph) == (-1)**m*exp(-2*I*m*ph)*Ynm(n, m, th, ph) + + +def test_Ynm_c(): + th, ph = Symbol("theta", real=True), Symbol("phi", real=True) + from sympy.abc import n,m + + assert Ynm_c(n, m, th, ph) == (-1)**(2*m)*exp(-2*I*m*ph)*Ynm(n, m, th, ph) + + +def test_Znm(): + # http://en.wikipedia.org/wiki/Solid_harmonics#List_of_lowest_functions + th, ph = Symbol("theta", real=True), Symbol("phi", real=True) + from sympy.abc import n,m + + assert Znm(0, 0, th, ph) == Ynm(0, 0, th, ph) + assert Znm(1, -1, th, ph) == (-sqrt(2)*I*(Ynm(1, 1, th, ph) + - exp(-2*I*ph)*Ynm(1, 1, th, ph))/2) + assert Znm(1, 0, th, ph) == Ynm(1, 0, th, ph) + assert Znm(1, 1, th, ph) == (sqrt(2)*(Ynm(1, 1, th, ph) + + exp(-2*I*ph)*Ynm(1, 1, th, ph))/2) + assert Znm(0, 0, th, ph).expand(func=True) == 1/(2*sqrt(pi)) + assert Znm(1, -1, th, ph).expand(func=True) == (sqrt(3)*I*sqrt(-cos(th)**2 + 1)*exp(I*ph)/(4*sqrt(pi)) + - sqrt(3)*I*sqrt(-cos(th)**2 + 1)*exp(-I*ph)/(4*sqrt(pi))) + assert Znm(1, 0, th, ph).expand(func=True) == sqrt(3)*cos(th)/(2*sqrt(pi)) + assert Znm(1, 1, th, ph).expand(func=True) == (-sqrt(3)*sqrt(-cos(th)**2 + 1)*exp(I*ph)/(4*sqrt(pi)) + - sqrt(3)*sqrt(-cos(th)**2 + 1)*exp(-I*ph)/(4*sqrt(pi))) + assert Znm(2, -1, th, ph).expand(func=True) == (sqrt(15)*I*sqrt(-cos(th)**2 + 1)*exp(I*ph)*cos(th)/(4*sqrt(pi)) + - sqrt(15)*I*sqrt(-cos(th)**2 + 1)*exp(-I*ph)*cos(th)/(4*sqrt(pi))) + assert Znm(2, 0, th, ph).expand(func=True) == 3*sqrt(5)*cos(th)**2/(4*sqrt(pi)) - sqrt(5)/(4*sqrt(pi)) + assert Znm(2, 1, th, ph).expand(func=True) == (-sqrt(15)*sqrt(-cos(th)**2 + 1)*exp(I*ph)*cos(th)/(4*sqrt(pi)) + - sqrt(15)*sqrt(-cos(th)**2 + 1)*exp(-I*ph)*cos(th)/(4*sqrt(pi))) diff -Nru python3-sympy-0.7.2/sympy/functions/special/tests/test_tensor_functions.py python3-sympy-0.7.3/sympy/functions/special/tests/test_tensor_functions.py --- python3-sympy-0.7.2/sympy/functions/special/tests/test_tensor_functions.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/functions/special/tests/test_tensor_functions.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,16 +1,20 @@ -from sympy import symbols, Symbol, Eijk, LeviCivita, KroneckerDelta, Dummy +from sympy import ( + adjoint, conjugate, Dummy, Eijk, KroneckerDelta, LeviCivita, Symbol, + symbols, transpose, +) from sympy.physics.secondquant import evaluate_deltas, F from sympy.utilities.pytest import XFAIL -x, y = symbols('x,y') +x, y = symbols('x y') + def test_levicivita(): assert Eijk(1, 2, 3) == LeviCivita(1, 2, 3) assert LeviCivita(1, 2, 3) == 1 assert LeviCivita(1, 3, 2) == -1 assert LeviCivita(1, 2, 2) == 0 - i,j,k = symbols('i j k') - assert LeviCivita(i, j, k) == LeviCivita(i,j,k, evaluate=False) + i, j, k = symbols('i j k') + assert LeviCivita(i, j, k) == LeviCivita(i, j, k, evaluate=False) assert LeviCivita(i, j, i) == 0 assert LeviCivita(1, i, i) == 0 assert LeviCivita(i, j, k).doit() == (j - i)*(k - i)*(k - j)/2 @@ -18,93 +22,108 @@ assert LeviCivita(4, 5, 1, 2, 3) == 1 assert LeviCivita(4, 5, 2, 1, 3) == -1 + assert LeviCivita(i, j, k).is_integer is True + + assert adjoint(LeviCivita(i, j, k)) == LeviCivita(i, j, k) + assert conjugate(LeviCivita(i, j, k)) == LeviCivita(i, j, k) + assert transpose(LeviCivita(i, j, k)) == LeviCivita(i, j, k) + + def test_kronecker_delta(): - i, j = symbols('i,j') + i, j = symbols('i j') k = Symbol('k', nonzero=True) assert KroneckerDelta(1, 1) == 1 assert KroneckerDelta(1, 2) == 0 assert KroneckerDelta(x, x) == 1 - assert KroneckerDelta(x**2-y**2, x**2-y**2) == 1 + assert KroneckerDelta(x**2 - y**2, x**2 - y**2) == 1 assert KroneckerDelta(i, i) == 1 assert KroneckerDelta(i, i + 1) == 0 assert KroneckerDelta(0, 0) == 1 assert KroneckerDelta(0, 1) == 0 + assert KroneckerDelta(i + k, i) == KroneckerDelta(0, k) assert KroneckerDelta(i + k, i + k) == 1 assert KroneckerDelta(i + k, i + 1 + k) == 0 assert KroneckerDelta(i, j).subs(dict(i=1, j=0)) == 0 assert KroneckerDelta(i, j).subs(dict(i=3, j=3)) == 1 + assert KroneckerDelta(i, j)**0 == 1 + for n in range(1, 10): + assert KroneckerDelta(i, j)**n == KroneckerDelta(i, j) + assert KroneckerDelta(i, j)**-n == 1/KroneckerDelta(i, j) + + assert KroneckerDelta(i, j).is_integer is True + + assert adjoint(KroneckerDelta(i, j)) == KroneckerDelta(i, j) + assert conjugate(KroneckerDelta(i, j)) == KroneckerDelta(i, j) + assert transpose(KroneckerDelta(i, j)) == KroneckerDelta(i, j) + # to test if canonical + assert (KroneckerDelta(i, j) == KroneckerDelta(j, i)) == True def test_kronecker_delta_secondquant(): """secondquant-specific methods""" D = KroneckerDelta - i,j,v,w = symbols('i j v w',below_fermi=True,cls=Dummy) - a,b,t,u = symbols('a b t u',above_fermi=True, cls=Dummy) - p,q,r,s = symbols('p q r s',cls=Dummy) - - assert D(i,a) == 0 - assert D(i,t) == 0 - - assert D(i,j).is_above_fermi == False - assert D(a,b).is_above_fermi == True - assert D(p,q).is_above_fermi == True - assert D(i,q).is_above_fermi == False - assert D(q,i).is_above_fermi == False - assert D(q,v).is_above_fermi == False - assert D(a,q).is_above_fermi == True - - assert D(i,j).is_below_fermi == True - assert D(a,b).is_below_fermi == False - assert D(p,q).is_below_fermi == True - assert D(p,j).is_below_fermi == True - assert D(q,b).is_below_fermi == False - - assert D(i,j).is_only_above_fermi == False - assert D(a,b).is_only_above_fermi == True - assert D(p,q).is_only_above_fermi == False - assert D(i,q).is_only_above_fermi == False - assert D(q,i).is_only_above_fermi == False - assert D(a,q).is_only_above_fermi == True - - assert D(i,j).is_only_below_fermi == True - assert D(a,b).is_only_below_fermi == False - assert D(p,q).is_only_below_fermi == False - assert D(p,j).is_only_below_fermi == True - assert D(q,b).is_only_below_fermi == False - - assert not D(i,q).indices_contain_equal_information - assert not D(a,q).indices_contain_equal_information - assert D(p,q).indices_contain_equal_information - assert D(a,b).indices_contain_equal_information - assert D(i,j).indices_contain_equal_information - - assert D(q,b).preferred_index == b - assert D(q,b).killable_index == q - assert D(q,t).preferred_index == t - assert D(q,t).killable_index == q - assert D(q,i).preferred_index == i - assert D(q,i).killable_index == q - assert D(q,v).preferred_index == v - assert D(q,v).killable_index == q - assert D(q, p).preferred_index == q - assert D(q, p).killable_index == p - + i, j, v, w = symbols('i j v w', below_fermi=True, cls=Dummy) + a, b, t, u = symbols('a b t u', above_fermi=True, cls=Dummy) + p, q, r, s = symbols('p q r s', cls=Dummy) + + assert D(i, a) == 0 + assert D(i, t) == 0 + + assert D(i, j).is_above_fermi is False + assert D(a, b).is_above_fermi is True + assert D(p, q).is_above_fermi is True + assert D(i, q).is_above_fermi is False + assert D(q, i).is_above_fermi is False + assert D(q, v).is_above_fermi is False + assert D(a, q).is_above_fermi is True + + assert D(i, j).is_below_fermi is True + assert D(a, b).is_below_fermi is False + assert D(p, q).is_below_fermi is True + assert D(p, j).is_below_fermi is True + assert D(q, b).is_below_fermi is False + + assert D(i, j).is_only_above_fermi is False + assert D(a, b).is_only_above_fermi is True + assert D(p, q).is_only_above_fermi is False + assert D(i, q).is_only_above_fermi is False + assert D(q, i).is_only_above_fermi is False + assert D(a, q).is_only_above_fermi is True + + assert D(i, j).is_only_below_fermi is True + assert D(a, b).is_only_below_fermi is False + assert D(p, q).is_only_below_fermi is False + assert D(p, j).is_only_below_fermi is True + assert D(q, b).is_only_below_fermi is False + + assert not D(i, q).indices_contain_equal_information + assert not D(a, q).indices_contain_equal_information + assert D(p, q).indices_contain_equal_information + assert D(a, b).indices_contain_equal_information + assert D(i, j).indices_contain_equal_information + + assert D(q, b).preferred_index == b + assert D(q, b).killable_index == q + assert D(q, t).preferred_index == t + assert D(q, t).killable_index == q + assert D(q, i).preferred_index == i + assert D(q, i).killable_index == q + assert D(q, v).preferred_index == v + assert D(q, v).killable_index == q + assert D(q, p).preferred_index == p + assert D(q, p).killable_index == q EV = evaluate_deltas - assert EV(D(a,q)*F(q)) == F(a) - assert EV(D(i,q)*F(q)) == F(i) - assert EV(D(a,q)*F(a)) == D(a,q)*F(a) - assert EV(D(i,q)*F(i)) == D(i,q)*F(i) - assert EV(D(a,b)*F(a)) == F(b) - assert EV(D(a,b)*F(b)) == F(a) - assert EV(D(i,j)*F(i)) == F(j) - assert EV(D(i,j)*F(j)) == F(i) - assert EV(D(p,q)*F(q)) == F(p) - assert EV(D(p,q)*F(p)) == F(q) - assert EV(D(p,j)*D(p,i)*F(i)) == F(j) - assert EV(D(p,j)*D(p,i)*F(j)) == F(i) - assert EV(D(p,q)*D(p,i))*F(i) == D(q,i)*F(i) - -@XFAIL -def test_kronecker_delta_failing(): - assert D(i, i + k) == D(0, k) + assert EV(D(a, q)*F(q)) == F(a) + assert EV(D(i, q)*F(q)) == F(i) + assert EV(D(a, q)*F(a)) == D(a, q)*F(a) + assert EV(D(i, q)*F(i)) == D(i, q)*F(i) + assert EV(D(a, b)*F(a)) == F(b) + assert EV(D(a, b)*F(b)) == F(a) + assert EV(D(i, j)*F(i)) == F(j) + assert EV(D(i, j)*F(j)) == F(i) + assert EV(D(p, q)*F(q)) == F(p) + assert EV(D(p, q)*F(p)) == F(q) + assert EV(D(p, j)*D(p, i)*F(i)) == F(j) + assert EV(D(p, j)*D(p, i)*F(j)) == F(i) + assert EV(D(p, q)*D(p, i))*F(i) == D(q, i)*F(i) diff -Nru python3-sympy-0.7.2/sympy/functions/special/tests/test_zeta_functions.py python3-sympy-0.7.3/sympy/functions/special/tests/test_zeta_functions.py --- python3-sympy-0.7.2/sympy/functions/special/tests/test_zeta_functions.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/functions/special/tests/test_zeta_functions.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,6 +1,6 @@ from sympy import (Symbol, zeta, nan, Rational, Float, pi, dirichlet_eta, log, - zoo, expand_func, polylog, lerchphi, S, exp, sqrt, I, exp_polar, - polar_lift) + zoo, expand_func, polylog, lerchphi, S, exp, sqrt, I, + exp_polar, polar_lift, O) from sympy.utilities.randtest import (test_derivative_numerically as td, random_complex_number as randcplx, test_numerically as tn) from sympy.utilities.pytest import XFAIL @@ -10,13 +10,14 @@ z = Symbol('z') s = Symbol('s') + def test_zeta_eval(): assert zeta(nan) == nan assert zeta(x, nan) == nan - assert zeta(0) == Rational(-1,2) - assert zeta(0, x) == Rational(1,2) - x + assert zeta(0) == Rational(-1, 2) + assert zeta(0, x) == Rational(1, 2) - x assert zeta(1) == zoo assert zeta(1, 2) == zoo @@ -57,15 +58,23 @@ assert zeta(0, 2) == -Rational(3, 2) assert zeta(0, -2) == Rational(3, 2) - assert zeta(3).evalf(20).epsilon_eq(Float("1.2020569031595942854",20), 1e-19) + assert zeta( + 3).evalf(20).epsilon_eq(Float("1.2020569031595942854", 20), 1e-19) + + +def test_zeta_series(): + assert zeta(x, a).series(a, 0, 2) == \ + zeta(x, 0) - x*a*zeta(x + 1, 0) + O(a**2) + def test_dirichlet_eta_eval(): - assert dirichlet_eta(0) == Rational(1,2) - assert dirichlet_eta(-1) == Rational(1,4) + assert dirichlet_eta(0) == Rational(1, 2) + assert dirichlet_eta(-1) == Rational(1, 4) assert dirichlet_eta(1) == log(2) assert dirichlet_eta(2) == pi**2/12 - assert dirichlet_eta(4) == pi**4*Rational(7,720) + assert dirichlet_eta(4) == pi**4*Rational(7, 720) + def test_rewriting(): assert dirichlet_eta(x).rewrite(zeta) == (1 - 2**(1 - x))*zeta(x) @@ -79,12 +88,14 @@ assert lerchphi(1, x, a).rewrite(zeta) == zeta(x, a) assert z*lerchphi(z, s, 1).rewrite(polylog) == polylog(s, z) + def test_derivatives(): from sympy import Derivative assert zeta(x, a).diff(x) == Derivative(zeta(x, a), x) assert zeta(x, a).diff(a) == -x*zeta(x + 1, a) - assert lerchphi(z, s, a).diff(z) == (lerchphi(z, s-1, a) - a*lerchphi(z, s, a))/z - assert lerchphi(z, s, a).diff(a) == -s*lerchphi(z, s+1, a) + assert lerchphi( + z, s, a).diff(z) == (lerchphi(z, s - 1, a) - a*lerchphi(z, s, a))/z + assert lerchphi(z, s, a).diff(a) == -s*lerchphi(z, s + 1, a) assert polylog(s, z).diff(z) == polylog(s - 1, z)/z b = randcplx() @@ -94,11 +105,12 @@ assert td(lerchphi(c, b, x), x) assert td(lerchphi(x, b, c), x) + def myexpand(func, target): expanded = expand_func(func) if target is not None: return expanded == target - if expanded == func: # it didn't expand + if expanded == func: # it didn't expand return False # check to see that the expanded and original evaluate to the same value @@ -108,6 +120,7 @@ return abs(func.subs(subs).n() - expanded.replace(exp_polar, exp).subs(subs).n()) < 1e-10 + def test_polylog_expansion(): from sympy import factor, log assert polylog(s, 0) == 0 @@ -130,7 +143,7 @@ # polylog reduction assert myexpand(lerchphi(z, s, S(1)/2), - 2**(s-1)*(polylog(s, sqrt(z))/sqrt(z) \ + 2**(s - 1)*(polylog(s, sqrt(z))/sqrt(z) - polylog(s, polar_lift(-1)*sqrt(z))/sqrt(z))) assert myexpand(lerchphi(z, s, 2), -1/z + polylog(s, z)/z**2) assert myexpand(lerchphi(z, s, S(3)/2), None) @@ -140,7 +153,7 @@ # hurwitz zeta reduction assert myexpand(lerchphi(-1, s, a), - 2**(-s)*zeta(s, a/2) - 2**(-s)*zeta(s, (a+1)/2)) + 2**(-s)*zeta(s, a/2) - 2**(-s)*zeta(s, (a + 1)/2)) assert myexpand(lerchphi(I, s, a), None) assert myexpand(lerchphi(-I, s, a), None) assert myexpand(lerchphi(exp(2*I*pi/5), s, a), None) diff -Nru python3-sympy-0.7.2/sympy/functions/special/zeta_functions.py python3-sympy-0.7.3/sympy/functions/special/zeta_functions.py --- python3-sympy-0.7.2/sympy/functions/special/zeta_functions.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/functions/special/zeta_functions.py 2013-07-13 17:53:32.000000000 +0000 @@ -6,11 +6,12 @@ ###################### LERCH TRANSCENDENT ##################################### ############################################################################### + class lerchphi(Function): r""" Lerch transcendent (Lerch phi function). - For :math:`Re(a) > 0`, :math:`|z| < 1` and :math:`s \in \mathbb{C}`, the + For :math:`\operatorname{Re}(a) > 0`, `|z| < 1` and `s \in \mathbb{C}`, the Lerch transcendent is defined as .. math :: \Phi(z, s, a) = \sum_{n=0}^\infty \frac{z^n}{(n + a)^s}, @@ -28,9 +29,9 @@ .. math:: \Phi(z, s, a) = z\Phi(z, s, a+1) + a^{-s}. - This provides the analytic continuation to :math:`Re(a) \le 0`. + This provides the analytic continuation to `\operatorname{Re}(a) \le 0`. - Assume now :math:`Re(a) > 0`. The integral representation + Assume now `\operatorname{Re}(a) > 0`. The integral representation .. math:: \Phi_0(z, s, a) = \int_0^\infty \frac{t^{s-1} e^{-at}}{1 - ze^{-t}} \frac{\mathrm{d}t}{\Gamma(s)} @@ -58,10 +59,10 @@ References ========== - - Bateman, H.; Erdelyi, A. (1953), Higher Transcendental Functions, - Vol. I, New York: McGraw-Hill. Section 1.11. - - http://dlmf.nist.gov/25.14 - - http://en.wikipedia.org/wiki/Lerch_transcendent + .. [1] Bateman, H.; Erdelyi, A. (1953), Higher Transcendental Functions, + Vol. I, New York: McGraw-Hill. Section 1.11. + .. [2] http://dlmf.nist.gov/25.14 + .. [3] http://en.wikipedia.org/wiki/Lerch_transcendent Examples ======== @@ -93,9 +94,11 @@ >>> from sympy import S >>> expand_func(lerchphi(z, s, S(1)/2)) - 2**(s - 1)*(polylog(s, sqrt(z))/sqrt(z) - polylog(s, sqrt(z)*exp_polar(I*pi))/sqrt(z)) + 2**(s - 1)*(polylog(s, sqrt(z))/sqrt(z) - + polylog(s, sqrt(z)*exp_polar(I*pi))/sqrt(z)) >>> expand_func(lerchphi(z, s, S(3)/2)) - -2**s/z + 2**(s - 1)*(polylog(s, sqrt(z))/sqrt(z) - polylog(s, sqrt(z)*exp_polar(I*pi))/sqrt(z))/z + -2**s/z + 2**(s - 1)*(polylog(s, sqrt(z))/sqrt(z) - + polylog(s, sqrt(z)*exp_polar(I*pi))/sqrt(z))/z The derivatives with respect to :math:`z` and :math:`a` can be computed in closed form: @@ -148,9 +151,9 @@ m, n = S([a.p, a.q]) zet = exp_polar(2*pi*I/n) root = z**(1/n) - return add + mul*n**(s-1)*Add( - *[polylog(s, zet**k*root)._eval_expand_func(**hints) \ - / (unpolarify(zet)**k*root)**m for k in range(n)]) + return add + mul*n**(s - 1)*Add( + *[polylog(s, zet**k*root)._eval_expand_func(**hints) + / (unpolarify(zet)**k*root)**m for k in range(n)]) # TODO use minpoly instead of ad-hoc methods when issue 2789 is fixed if z.func is exp and (z.args[0]/(pi*I)).is_Rational or z in [-1, I, -I]: @@ -164,7 +167,7 @@ else: arg = z.args[0]/(2*pi*I) p, q = S([arg.p, arg.q]) - return Add(*[exp(2*pi*I*k*p/q)/q**s*zeta(s, (k + a)/q) \ + return Add(*[exp(2*pi*I*k*p/q)/q**s*zeta(s, (k + a)/q) for k in range(q)]) return lerchphi(z, s, a) @@ -172,9 +175,9 @@ def fdiff(self, argindex=1): z, s, a = self.args if argindex == 3: - return -s*lerchphi(z, s+1, a) + return -s*lerchphi(z, s + 1, a) elif argindex == 1: - return (lerchphi(z, s-1, a) - a*lerchphi(z, s, a))/z + return (lerchphi(z, s - 1, a) - a*lerchphi(z, s, a))/z else: raise ArgumentIndexError @@ -184,8 +187,10 @@ return res else: return self + def _eval_rewrite_as_zeta(self, z, s, a): return self._eval_rewrite_helper(z, s, a, zeta) + def _eval_rewrite_as_polylog(self, z, s, a): return self._eval_rewrite_helper(z, s, a, polylog) @@ -193,6 +198,7 @@ ###################### POLYLOGARITHM ########################################## ############################################################################### + class polylog(Function): r""" Polylogarithm function. @@ -273,7 +279,7 @@ def fdiff(self, argindex=1): s, z = self.args if argindex == 2: - return polylog(s-1, z)/z + return polylog(s - 1, z)/z raise ArgumentIndexError def _eval_rewrite_as_lerchphi(self, s, z): @@ -296,16 +302,17 @@ ###################### HURWITZ GENERALIZED ZETA FUNCTION ###################### ############################################################################### + class zeta(Function): r""" Hurwitz zeta function (or Riemann zeta function). - For :math:`Re(a) > 0` and :math:`Re(s) > 1`, this function is defined as + For `\operatorname{Re}(a) > 0` and `\operatorname{Re}(s) > 1`, this function is defined as .. math:: \zeta(s, a) = \sum_{n=0}^\infty \frac{1}{(n + a)^s}, where the standard choice of argument for :math:`n + a` is used. For fixed - :math:`a` with :math:`Re(a) > 0` the Hurwitz zeta function admits a + :math:`a` with `\operatorname{Re}(a) > 0` the Hurwitz zeta function admits a meromorphic continuation to all of :math:`\mathbb{C}`, it is an unbranched function with a simple pole at :math:`s = 1`. @@ -317,7 +324,7 @@ .. math:: \zeta(s, a) = \Phi(1, s, a). This formula defines an analytic continuation for all possible values of - :math:`s` and :math:`a` (also :math:`Re(a) < 0`), see the documentation of + :math:`s` and :math:`a` (also `\operatorname{Re}(a) < 0`), see the documentation of :class:`lerchphi` for a description of the branching behavior. If no value is passed for :math:`a`, by this function assumes a default value @@ -331,8 +338,8 @@ References ========== - - http://dlmf.nist.gov/25.11 - - http://en.wikipedia.org/wiki/Hurwitz_zeta_function + .. [1] http://dlmf.nist.gov/25.11 + .. [2] http://en.wikipedia.org/wiki/Hurwitz_zeta_function Examples ======== @@ -346,6 +353,8 @@ >>> from sympy.abc import s >>> zeta(s, 1) zeta(s) + >>> zeta(s) + zeta(s) The Riemann zeta function can also be expressed using the Dirichlet eta function: @@ -433,17 +442,17 @@ elif z.is_Integer: if a.is_Integer: if z.is_negative: - zeta = (-1)**z * C.bernoulli(-z+1)/(-z+1) + zeta = (-1)**z * C.bernoulli(-z + 1)/(-z + 1) elif z.is_even: B, F = C.bernoulli(z), C.factorial(z) - zeta = 2**(z-1) * abs(B) * pi**z / F + zeta = 2**(z - 1) * abs(B) * pi**z / F else: return if a.is_negative: return zeta + C.harmonic(abs(a), z) else: - return zeta - C.harmonic(a-1, z) + return zeta - C.harmonic(a - 1, z) def _eval_rewrite_as_dirichlet_eta(self, s, a=1): if a != 1: @@ -464,11 +473,12 @@ else: raise ArgumentIndexError + class dirichlet_eta(Function): r""" Dirichlet eta function. - For :math:`Re(s) > 0`, this function is defined as + For `\operatorname{Re}(s) > 0`, this function is defined as .. math:: \eta(s) = \sum_{n=1}^\infty \frac{(-1)^n}{n^s}. @@ -483,7 +493,7 @@ References ========== - - http://en.wikipedia.org/wiki/Dirichlet_eta_function + .. [1] http://en.wikipedia.org/wiki/Dirichlet_eta_function Examples ======== @@ -504,7 +514,7 @@ return C.log(2) z = zeta(s) if not z.has(zeta): - return (1-2**(1-s))*z + return (1 - 2**(1 - s))*z def _eval_rewrite_as_zeta(self, s): - return (1-2**(1-s)) * zeta(s) + return (1 - 2**(1 - s)) * zeta(s) diff -Nru python3-sympy-0.7.2/sympy/galgebra/GA.py python3-sympy-0.7.3/sympy/galgebra/GA.py --- python3-sympy-0.7.2/sympy/galgebra/GA.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/galgebra/GA.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,7 +1,7 @@ #!/usr/bin/python """ -The module symbolicGA implements symbolic Geometric Algebra in python. +The module GA implements symbolic Geometric Algebra in python. The relevant references for this module are: 1. "Geometric Algebra for Physicists" by C. Doran and A. Lazenby, @@ -9,11 +9,10 @@ 2. "Geometric Algebra for Computer Science" by Leo Dorst, Daniel Fontijne, and Stephen Mann, Morgan Kaufmann Publishers, 2007. - - 3. SymPy Tutorial, http://docs.sympy.org/ """ import sys -import numpy, sympy +import numpy +import sympy import re as regrep import sympy.galgebra.latex_ex from sympy.core.decorators import deprecated @@ -22,19 +21,21 @@ """Re pattern for rational number""" ZERO = sympy.Rational(0) -ONE = sympy.Rational(1) -TWO = sympy.Rational(2) -HALF = sympy.Rational(1,2) +ONE = sympy.Rational(1) +TWO = sympy.Rational(2) +HALF = sympy.Rational(1, 2) from sympy.core import Pow as pow_type from sympy import Abs as abs_type from sympy.core import Mul as mul_type from sympy.core import Add as add_type + @sympy.vectorize(0) -def substitute_array(array,*args): +def substitute_array(array, *args): return(array.subs(*args)) + def is_quasi_unit_numpy_array(array): """ Determine if a array is square and diagonal with @@ -57,19 +58,22 @@ else: return(False) + @deprecated(value="This function is no longer needed.", issue=3379, deprecated_since_version="0.7.2") def set_main(main_program): pass + def plist(lst): if type(lst) == list: for x in lst: plist(x) else: - sys.stderr.write(lst+'\n') + sys.stderr.write(lst + '\n') return + def numeric(num_str): """ Returns rational numbers compatible with symbols. @@ -87,24 +91,28 @@ else: a = int(tmp[0]) b = int(tmp[1]) - return(sympy.Rational(a,b)) + return(sympy.Rational(a, b)) -def collect(expr,lst): + +def collect(expr, lst): """ Wrapper for sympy.collect. """ lst = MV.scalar_to_symbol(lst) - return(sympy.collect(expr,lst)) + return(sympy.collect(expr, lst)) + def sqrt(expr): return(sympy.sqrt(expr)) + def isint(a): """ Test for integer. """ return(type(a) == int) + def make_null_array(n): """ Return list of n empty lists. @@ -114,6 +122,7 @@ a.append([]) return(a) + def test_int_flgs(lst): """ Test if all elements in list are 0. @@ -123,45 +132,55 @@ return(1) return(0) -def comb(N,P): + +def comb(N, P): """ Calculates the combinations of the integers [0,N-1] taken P at a time. The output is a list of lists of integers where the inner lists are the different combinations. Each combination is sorted in ascending order. """ - def rloop(n,p,combs,comb): + def rloop(n, p, combs, comb): if p: for i in range(n): - newcomb = comb+[i] - np = p-1 - rloop(i,np,combs,newcomb) + newcomb = comb + [i] + np = p - 1 + rloop(i, np, combs, newcomb) else: combs.append(comb) combs = [] - rloop(N,P,combs,[]) + rloop(N, P, combs, []) for comb in combs: comb.sort() return(combs) + def diagpq(p, q=0): """ - Return string equivalent metric tensor for signature (p, q). + Returns string equivalent metric tensor for signature (p, q). """ n = p + q D = [] - rn = list(range(n)) - for i in rn: - for j in rn: - if i ==j: - if i < p: - D.append('1 ') - else: - D.append('-1 ') - else: - D.append('0 ') + for i in range(p): + D.append((i*'0 ' +'1 '+ (n-i-1)*'0 ')[:-1]) + for i in range(p,n): + D.append((i*'0 ' +'-1 '+ (n-i-1)*'0 ')[:-1]) return ','.join(D) +def arbitrary_metric(n): + """ + Returns string equivalent metric tensor for arbitrary signature. + """ + return ','.join(n*[(n*'# ')[:-1]]) + +def arbitrary_metric_conformal(n): + """ + Returns string equivalent metric tensor for arbitrary signature (n+1,1). + """ + str1 = ','.join(n*[n*'# '+'0 0']) + return ','.join([str1, n*'0 '+'1 0', n*'0 '+'0 -1']) + + def make_scalars(symnamelst): """ make_scalars takes a string of symbol names separated by @@ -171,15 +190,17 @@ symlst = sympy.symbols(symnamelst) scalar_lst = [] for s in symlst: - tmp = MV(s,'scalar') + tmp = MV(s, 'scalar') scalar_lst.append(tmp) return(scalar_lst) + @deprecated(useinstead="sympy.symbols()", issue=3379, deprecated_since_version="0.7.2") def make_symbols(symnamelst): return sympy.symbols(symnamelst) + def israt(numstr): """ Test if string represents a rational number. @@ -189,6 +210,7 @@ return(1) return(0) + def dualsort(lst1, lst2): """ Inplace dual sort of lst1 and lst2 keyed on sorted lst1. @@ -199,14 +221,16 @@ lst2[:] = list(map(lst2.__getitem__, _indices)) return -def cp(A,B): + +def cp(A, B): """ Calculates the commutator product (A*B-B*A)/2 for the objects A and B. """ - return(HALF*(A*B-B*A)) + return(HALF*(A*B - B*A)) + -def reduce_base(k,base): +def reduce_base(k, base): """ If base is a list of sorted integers [i_1,...,i_R] then reduce_base sorts the list [k,i_1,...,i_R] and calculates whether an odd or even @@ -214,39 +238,40 @@ is returned and +1 for even permutations or -1 for odd permutations. """ if k in base: - return(0,base) + return(0, base) grade = len(base) if grade == 1: if k < base[0]: - return(1,[k,base[0]]) + return(1, [k, base[0]]) else: - return(-1,[base[0],k]) + return(-1, [base[0], k]) ilo = 0 - ihi = grade-1 + ihi = grade - 1 if k < base[0]: - return(1,[k]+base) + return(1, [k] + base) if k > base[ihi]: - if grade%2 == 0: - return(1,base+[k]) + if grade % 2 == 0: + return(1, base + [k]) else: - return(-1,base+[k]) - imid = ihi+ilo + return(-1, base + [k]) + imid = ihi + ilo if grade == 2: - return(-1,[base[0],k,base[1]]) + return(-1, [base[0], k, base[1]]) while True: - if ihi-ilo == 1: + if ihi - ilo == 1: break if base[imid] > k: ihi = imid else: ilo = imid - imid = (ilo+ihi)/2 - if ilo%2 == 1: - return(1,base[:ihi]+[k]+base[ihi:]) + imid = (ilo + ihi)/2 + if ilo % 2 == 1: + return(1, base[:ihi] + [k] + base[ihi:]) else: - return(-1,base[:ihi]+[k]+base[ihi:]) + return(-1, base[:ihi] + [k] + base[ihi:]) -def sub_base(k,base): + +def sub_base(k, base): """ If base is a list of sorted integers [i_1,...,i_R] then sub_base returns a list with the k^th element removed. Note that k=0 removes the first @@ -260,7 +285,8 @@ return([base[1]]) else: return([base[0]]) - return(base[:k]+base[k+1:]) + return(base[:k] + base[k + 1:]) + def magnitude(vector): """ @@ -269,8 +295,8 @@ magsq is determined and because of the way that absolute values are removed. """ - magsq = sympy.expand((vector|vector)()) - magsq = sympy.trigsimp(magsq,deep=True,recursive=True) + magsq = sympy.expand((vector | vector)()) + magsq = sympy.trigsimp(magsq, deep=True, recursive=True) #print magsq magsq_str = sympy.galgebra.latex_ex.LatexPrinter()._print(magsq) if magsq_str[0] == '-': @@ -279,7 +305,8 @@ #print mag return(mag) -def LaTeX_lst(lst,title=''): + +def LaTeX_lst(lst, title=''): """ Output a list in LaTeX format. """ @@ -289,6 +316,7 @@ sympy.galgebra.latex_ex.LaTeX(x) return + def unabs(x): """ Remove absolute values from expressions so a = sqrt(a**2). @@ -310,15 +338,17 @@ return(x.args[0]) return(x) -def function_lst(fstr,xtuple): - sys.stderr.write(fstr+'\n') + +def function_lst(fstr, xtuple): + sys.stderr.write(fstr + '\n') fct_lst = [] for xstr in fstr.split(): f = sympy.Function(xstr)(*xtuple) fct_lst.append(f) return(fct_lst) -def vector_fct(Fstr,x): + +def vector_fct(Fstr, x): """ Create a list of functions of arguments x. One function is created for each variable in x. Fstr is a string that is @@ -330,16 +360,18 @@ nx = len(x) Fvec = [] for ix in range(nx): - ftmp = sympy.Function(Fstr+'__'+sympy.galgebra.latex_ex.LatexPrinter.str_basic(x[ix]))(*tuple(x)) + ftmp = sympy.Function(Fstr + '__' + sympy.galgebra.latex_ex.LatexPrinter.str_basic(x[ix]))(*tuple(x)) Fvec.append(ftmp) return(Fvec) + def print_lst(lst): for x in lst: print(x) return -def normalize(elst,nname_lst): + +def normalize(elst, nname_lst): """ Normalize a list of vectors and rename the normalized vectors. 'elist' is the list (or array) of vectors to be normalized and nname_lst is a list of the names for the @@ -347,9 +379,9 @@ the normalized vectors (enlst) and the magnitudes of the original vectors (mags). """ i = 0 - mags = numpy.array(MV.n*[ZERO],dtype=numpy.object) - enlst= numpy.array(MV.n*[ZERO],dtype=numpy.object) - for (e,nname) in zip(elst,nname_lst): + mags = numpy.array(MV.n*[ZERO], dtype=numpy.object) + enlst = numpy.array(MV.n*[ZERO], dtype=numpy.object) + for (e, nname) in zip(elst, nname_lst): emag = magnitude(e) emaginv = 1/emag mags[i] = emag @@ -357,17 +389,19 @@ enorm.name = nname enlst[i] = enorm i += 1 - return(enlst,mags) + return(enlst, mags) -def build_base(base_index,base_vectors,reverse=False): + +def build_base(base_index, base_vectors, reverse=False): base = base_vectors[base_index[0]] if len(base_index) > 1: for i in base_index[1:]: - base = base^base_vectors[i] + base = base ^ base_vectors[i] if reverse: base = base.rev() return(base) + class MV(object): is_setup = False @@ -376,14 +410,14 @@ coords = None @staticmethod - def pad_zeros(value,n): + def pad_zeros(value, n): """ Pad list with zeros to length n. If length is > n truncate list. Return padded list. """ nvalue = len(value) if nvalue < n: - value = value+(n-nvalue)*[ZERO] + value = value + (n - nvalue)*[ZERO] if nvalue > n: value = value[:n] return(value) @@ -394,23 +428,23 @@ Calculates all the MV static variables needed for basis operations. See reference 5 section 2. """ - MV.vbasis = basis - MV.vsyms = sympy.symbols(MV.vbasis) - MV.n = len(MV.vbasis) - MV.nrg = list(range(MV.n)) - MV.n1 = MV.n+1 - MV.n1rg = list(range(MV.n1)) - MV.npow = 2**MV.n - MV.index = list(range(MV.n)) - MV.gabasis = [[]] - MV.basis = (MV.n+1)*[0] - MV.basislabel = (MV.n+1)*[0] - MV.basis[0] = [] + MV.vbasis = basis + MV.vsyms = sympy.symbols(MV.vbasis) + MV.n = len(MV.vbasis) + MV.nrg = list(range(MV.n)) + MV.n1 = MV.n + 1 + MV.n1rg = list(range(MV.n1)) + MV.npow = 2**MV.n + MV.index = list(range(MV.n)) + MV.gabasis = [[]] + MV.basis = (MV.n + 1)*[0] + MV.basislabel = (MV.n + 1)*[0] + MV.basis[0] = [] MV.basislabel[0] = '1' MV.basislabel_lst = [['1']] - MV.nbasis = numpy.array((MV.n+1)*[1],dtype=numpy.object) - for igrade in range(1,MV.n+1): - tmp = comb(MV.n,igrade) + MV.nbasis = numpy.array((MV.n + 1)*[1], dtype=numpy.object) + for igrade in range(1, MV.n + 1): + tmp = comb(MV.n, igrade) MV.gabasis += [tmp] ntmp = len(tmp) MV.nbasis[igrade] = ntmp @@ -440,12 +474,12 @@ igrade += 1 if MV.debug: - print('basis strings =',MV.vbasis) - print('basis symbols =',MV.vsyms) - print('basis labels =',MV.basislabel) - print('basis =',MV.basis) - print('grades =',MV.nbasis) - print('index =',MV.index) + print('basis strings =', MV.vbasis) + print('basis symbols =', MV.vsyms) + print('basis labels =', MV.basislabel) + print('basis =', MV.basis) + print('grades =', MV.nbasis) + print('index =', MV.index) return @staticmethod @@ -456,9 +490,9 @@ """ if MV.metric_str: MV.g = [] - MV.metric = numpy.array(MV.n*[MV.n*[ZERO]],dtype=numpy.object) + MV.metric = numpy.array(MV.n*[MV.n*[ZERO]], dtype=numpy.object) if metric == '': - metric = numpy.array(MV.n*[MV.n*['#']],dtype=numpy.object) + metric = numpy.array(MV.n*[MV.n*['#']], dtype=numpy.object) for i in MV.index: for j in MV.index: gij = metric[i][j] @@ -467,9 +501,10 @@ else: if gij == '#': if i == j: - gij = '('+MV.vbasis[j]+'**2)' + gij = '(' + MV.vbasis[j] + '**2)' else: - gij = '('+MV.vbasis[min(i,j)]+'.'+MV.vbasis[max(i,j)]+')' + gij = '(' + MV.vbasis[min( + i, j)] + '.' + MV.vbasis[max(i, j)] + ')' tmp = sympy.Symbol(gij) MV.metric[i][j] = tmp if i <= j: @@ -483,7 +518,7 @@ g_row.append(col) MV.g.append(g_row) if MV.debug: - print('metric =',MV.metric) + print('metric =', MV.metric) return @staticmethod @@ -497,15 +532,15 @@ if MV.tables_flg: MV.E = MV.bvec[0] MV.brecp = [] - for i in range(1,MV.n): - MV.E = MV.E^MV.bvec[i] + for i in range(1, MV.n): + MV.E = MV.E ^ MV.bvec[i] for i in range(MV.n): tmp = ONE - if i%2 != 0: + if i % 2 != 0: tmp = -ONE for j in range(MV.n): if i != j: - tmp = tmp^MV.bvec[j] + tmp = tmp ^ MV.bvec[j] tmp = tmp*MV.E MV.brecp.append(tmp) MV.Esq = (MV.E*MV.E)() @@ -525,29 +560,29 @@ if nblst <= 1: return(1) jstep = 1 - while jstep 2: - blst = blst[:istep]+blst[jstep+1:] + if len(blst) > 2: + blst = blst[:istep] + blst[jstep + 1:] else: blst = [] - if len(blst) <= 1 or jstep == nblst-1: + if len(blst) <= 1 or jstep == nblst - 1: blst_flg = 0 else: blst_flg = 1 - return(MV.metric[i][i],blst,blst_flg) + return(MV.metric[i][i], blst, blst_flg) if blst[istep] > blst[jstep]: - blst1 = blst[:istep]+blst[jstep+1:] + blst1 = blst[:istep] + blst[jstep + 1:] a1 = TWO*MV.metric[blst[jstep]][blst[istep]] - blst = blst[:istep]+[blst[jstep]]+[blst[istep]]+blst[jstep+1:] + blst = blst[:istep] + [blst[jstep]] + [blst[istep]] + blst[jstep + 1:] if len(blst1) <= 1: blst1_flg = 0 else: blst1_flg = 1 - return(a1,blst1,blst1_flg,blst) - jstep +=1 + return(a1, blst1, blst1_flg, blst) + jstep += 1 return(1) @staticmethod @@ -558,22 +593,22 @@ realized. See reference 5 section 3. """ if blst == []: - blst_coef = [] + blst_coef = [] blst_expand = [] for i in MV.n1rg: blst_coef.append([]) blst_expand.append([]) blst_expand[0].append([]) blst_coef[0].append(ONE) - return(blst_coef,blst_expand) + return(blst_coef, blst_expand) blst_expand = [blst] - blst_coef = [ONE] - blst_flg = [1] + blst_coef = [ONE] + blst_flg = [1] while test_int_flgs(blst_flg): for i in range(len(blst_flg)): if blst_flg[i]: tmp = MV.reduce_basis_loop(blst_expand[i]) - if tmp ==1: + if tmp == 1: blst_flg[i] = 0 else: if len(tmp) == 3: @@ -581,17 +616,18 @@ blst_expand[i] = tmp[1] blst_flg[i] = tmp[2] else: - blst_coef[i] = -blst_coef[i] - blst_flg[i] = 1 + blst_coef[i] = -blst_coef[i] + blst_flg[i] = 1 blst_expand[i] = tmp[3] blst_coef.append(-blst_coef[i]*tmp[0]) blst_expand.append(tmp[1]) blst_flg.append(tmp[2]) - (blst_coef,blst_expand) = MV.combine_common_factors(blst_coef,blst_expand) - return(blst_coef,blst_expand) + (blst_coef, blst_expand) = MV.combine_common_factors( + blst_coef, blst_expand) + return(blst_coef, blst_expand) @staticmethod - def combine_common_factors(blst_coef,blst_expand): + def combine_common_factors(blst_coef, blst_expand): new_blst_coef = [] new_blst_expand = [] for i in range(MV.n1): @@ -604,16 +640,16 @@ new_blst_expand[blen].append(blst_expand[ifac]) for i in range(MV.n1): if len(new_blst_coef[i]) > 1: - MV.contract(new_blst_coef[i],new_blst_expand[i]) - return(new_blst_coef,new_blst_expand) + MV.contract(new_blst_coef[i], new_blst_expand[i]) + return(new_blst_coef, new_blst_expand) @staticmethod - def contract(coefs,bases): - dualsort(coefs,bases) - n = len(bases)-1 + def contract(coefs, bases): + dualsort(coefs, bases) + n = len(bases) - 1 i = 0 while i < n: - j = i+1 + j = i + 1 if bases[i] == bases[j]: coefs[i] += coefs[j] bases.pop(j) @@ -629,11 +665,11 @@ bases.pop(i) n -= 1 else: - i +=1 + i += 1 return @staticmethod - def convert(coefs,bases): + def convert(coefs, bases): mv = MV() mv.bladeflg = 0 for igrade in MV.n1rg: @@ -641,14 +677,15 @@ base = bases[igrade] if len(coef) > 0: nbases = MV.nbasis[igrade] - mv.mv[igrade] = numpy.array(nbases*[ZERO],dtype=numpy.object) + mv.mv[igrade] = numpy.array(nbases*[ZERO], dtype=numpy.object) nbaserg = list(range(len(base))) for ibase in nbaserg: if igrade > 0: k = MV.basis[igrade].index(base[ibase]) mv.mv[igrade][k] = coef[ibase] else: - mv.mv[igrade] = numpy.array([coef[0]],dtype=numpy.object) + mv.mv[igrade] = numpy.array( + [coef[0]], dtype=numpy.object) return(mv) @staticmethod @@ -679,25 +716,26 @@ else: labels = MV.bladelabel mv.compact() - if isinstance(mv.mv[0],int): + if isinstance(mv.mv[0], int): value = '' else: value = (mv.mv[0][0]).__str__() - value = value.replace(' ','') + value = value.replace(' ', '') dummy = sympy.Dummy('dummy') for igrade in MV.n1rg[1:]: - if isinstance(mv.mv[igrade],numpy.ndarray): + if isinstance(mv.mv[igrade], numpy.ndarray): j = 0 for x in mv.mv[igrade]: if x != ZERO: xstr = (x*dummy).__str__() - xstr = xstr.replace(' ','') + xstr = xstr.replace(' ', '') if xstr[0] != '-' and len(value) > 0: - xstr = '+'+xstr + xstr = '+' + xstr if xstr.find('_dummy') < 2 and xstr[-5:] != '_dummy': - xstr = xstr.replace('_dummy*','')+'*'+labels[igrade][j] + xstr = xstr.replace( + '_dummy*', '') + '*' + labels[igrade][j] else: - xstr = xstr.replace('_dummy',labels[igrade][j]) + xstr = xstr.replace('_dummy', labels[igrade][j]) if MV.str_mode == 2: xstr += '\n' value += xstr @@ -707,11 +745,11 @@ if value == '': value = '0' #value = value.replace(' ','') - value = value.replace('dummy','1') + value = value.replace('dummy', '1') return(value) @staticmethod - def xstr_rep(mv,lst_mode=0): + def xstr_rep(mv, lst_mode=0): """ Converts internal representation of a multivector to a string for outputing. If lst_mode = 1, str_rep outputs a list of @@ -731,7 +769,7 @@ value = '' for igrade in MV.n1rg: tmp = [] - if isinstance(mv.mv[igrade],numpy.ndarray): + if isinstance(mv.mv[igrade], numpy.ndarray): j = 0 for x in mv.mv[igrade]: if x != ZERO: @@ -743,12 +781,12 @@ xstr = '-' else: if xstr[0] != '+': - xstr = '+('+xstr+')' + xstr = '+(' + xstr + ')' else: - xstr = '+('+xstr[1:]+')' - value += xstr+labels[igrade][j] + xstr = '+(' + xstr[1:] + ')' + value += xstr + labels[igrade][j] if MV.str_mode and not lst_mode: - value += value+'\n' + value += value + '\n' if lst_mode: tmp.append(value) j += 1 @@ -766,7 +804,7 @@ return(value) @staticmethod - def setup(basis,metric='',rframe=False,coords=None,debug=False,offset=0): + def setup(basis, metric='', rframe=False, coords=None, debug=False, offset=0): """ MV.setup initializes the MV class by calculating the static multivector tables required for geometric algebra operations @@ -778,21 +816,21 @@ MV.debug = debug MV.bladeprint = 0 MV.tables_flg = 0 - MV.str_mode = 0 + MV.str_mode = 0 MV.basisroot = '' MV.index_offset = offset - if coords == None: + if coords is None: MV.coords = None else: MV.coords = tuple(coords) - rframe= True + rframe = True if type(basis) == str: basislst = basis.split() if len(basislst) == 1: MV.basisroot = basislst[0] basislst = [] for coord in coords: - basislst.append(MV.basisroot+'_'+str(coord)) + basislst.append(MV.basisroot + '_' + str(coord)) MV.define_basis(basislst) if type(metric) == str: MV.metric_str = True @@ -825,13 +863,13 @@ isym = 0 MV.bvec = [] for name in MV.vbasis: - bvar = MV(value=isym,mvtype='basisvector',mvname=name) + bvar = MV(value=isym, mvtype='basisvector', mvname=name) bvar.bladeflg = 1 MV.bvec.append(bvar) isym += 1 if rframe: MV.define_reciprocal_frame() - MV.I = MV(ONE,'pseudo','I') + MV.I = MV(ONE, 'pseudo', 'I') MV.ZERO = MV() Isq = (MV.I*MV.I)() MV.Iinv = (1/Isq)*MV.I @@ -850,35 +888,35 @@ those associated with each dimension of vector space. """ phi = sympy.Function(fct_name)(*MV.coords) - Phi = MV(phi,'scalar') + Phi = MV(phi, 'scalar') Phi.name = fct_name return(Phi) @staticmethod - def vector_fct(fct_name,vars=''): + def vector_fct(fct_name, vars=''): """ Create multivector vector function with name fct_name (string) and independent variables coords (list of variable). Default variables are those associated with each dimension of vector space. """ - if isinstance(vars,str): - Acoefs = vector_fct(fct_name,MV.coords) + if isinstance(vars, str): + Acoefs = vector_fct(fct_name, MV.coords) else: - Acoefs =numpy.array(MV.n*[ZERO],dtype=numpy.object) + Acoefs = numpy.array(MV.n*[ZERO], dtype=numpy.object) x = MV.coords - if isinstance(vars,sympy.core.symbol.Symbol): + if isinstance(vars, sympy.core.symbol.Symbol): for icoef in MV.nrg: - Acoefs[icoef] = sympy.Function(fct_name+'__'+\ + Acoefs[icoef] = sympy.Function(fct_name + '__' + sympy.galgebra.latex_ex.LatexPrinter.str_basic(x[icoef]))(vars) else: for icoef in MV.nrg: - Acoefs[icoef] = sympy.Function(fct_name+'__'+\ + Acoefs[icoef] = sympy.Function(fct_name + '__' + sympy.galgebra.latex_ex.LatexPrinter.str_basic(x[icoef]))(*tuple(vars)) - A = MV(Acoefs,'vector',fct_name) + A = MV(Acoefs, 'vector', fct_name) return(A) @staticmethod - def rebase(x,coords,base_name='',debug=False,debug_level=0): + def rebase(x, coords, base_name='', debug=False, debug_level=0): """ Define curvilinear coordinates for previously defined vector (multivector) space (MV.setup has been run) with position vector, x, that is a vector function of the independent coordinates, coords (list of @@ -907,41 +945,42 @@ #Form root names for basis, reciprocal basis, normalized basis, and normalized reciprocal basis if base_name == '': - base_name = MV.basisroot+'prm' + base_name = MV.basisroot + 'prm' - LaTeX_base = sympy.galgebra.latex_ex.LatexPrinter.extended_symbol(base_name) - bm = '\\bm{'+LaTeX_base+'}' - bmhat = '\\hat{'+bm+'}' - bstr = bmhat+'_{[i_{1},\dots, i_{R}]}' + LaTeX_base = sympy.galgebra.latex_ex.LatexPrinter.extended_symbol( + base_name) + bm = '\\bm{' + LaTeX_base + '}' + bmhat = '\\hat{' + bm + '}' + bstr = bmhat + '_{[i_{1},\dots, i_{R}]}' base_name += 'bm' - base_name_hat = base_name+'hat' + base_name_hat = base_name + 'hat' - base_name_lst = [] - nbase_name_lst = [] - rbase_name_lst = [] + base_name_lst = [] + nbase_name_lst = [] + rbase_name_lst = [] rnbase_name_lst = [] coords_lst = [] for coord in coords: coord_str = sympy.galgebra.latex_ex.LatexPrinter.str_basic(coord) coords_lst.append(coord_str) - base_name_lst.append(base_name+'_'+coord_str) - rbase_name_lst.append(base_name+'__'+coord_str) - nbase_name_lst.append(base_name_hat+'_'+coord_str) - rnbase_name_lst.append(base_name_hat+'__'+coord_str) + base_name_lst.append(base_name + '_' + coord_str) + rbase_name_lst.append(base_name + '__' + coord_str) + nbase_name_lst.append(base_name_hat + '_' + coord_str) + rnbase_name_lst.append(base_name_hat + '__' + coord_str) if not (MV.n == len(coords) == len(base_name_lst)): print('rebaseMV inputs not congruent:') - print('MV.n =',MV.n) - print('coords =',coords) - print('bases =',base_name) + print('MV.n =', MV.n) + print('coords =', coords) + print('bases =', base_name) sys.exit(1) - if isinstance(x,MV): + if isinstance(x, MV): #Calculate basis vectors from derivatives of position vector x - bases = numpy.array(MV.n*[ZERO],dtype=numpy.object) + bases = numpy.array(MV.n*[ZERO], dtype=numpy.object) i = 0 for coord in coords: ei = x.diff(coords[i]) @@ -964,7 +1003,7 @@ bases = x - for (base,name) in zip(bases,base_name_lst): + for (base, name) in zip(bases, base_name_lst): base.set_name(name) if debug: @@ -980,26 +1019,27 @@ #Calculate normalized basis vectors and magnitudes of #unormalized basis vectors - (nbases,mags) = normalize(bases,nbase_name_lst) + (nbases, mags) = normalize(bases, nbase_name_lst) if debug: print('Magnitudes') - print('\\abs{'+LaTeX_base+'_{i}} = ',mags) + print('\\abs{' + LaTeX_base + '_{i}} = ', mags) print('Normalized Basis Vectors') for nbase in nbases: print(nbase) - g = numpy.array(MV.n*[MV.n*[ZERO]],dtype=numpy.object) + g = numpy.array(MV.n*[MV.n*[ZERO]], dtype=numpy.object) for irow in MV.nrg: for icol in MV.nrg: - magsq = sympy.expand((nbases[irow]|nbases[icol])()) - g[irow][icol] = sympy.simplify(sympy.trigsimp(magsq,deep=True,recursive=True)) + magsq = sympy.expand((nbases[irow] | nbases[icol])()) + g[irow][icol] = sympy.simplify( + sympy.trigsimp(magsq, deep=True, recursive=True)) if debug: - print('Metric $\\hat{g}_{ij} = \\hat{'+LaTeX_base+'}_{i}\\cdot \\hat{'+\ - LaTeX_base+'}_{j}$') - print(r'\hat{g}_{ij} =',sympy.galgebra.latex_ex.LaTeX(g)) + print('Metric $\\hat{g}_{ij} = \\hat{' + LaTeX_base + \ + '}_{i}\\cdot \\hat{' + LaTeX_base + '}_{j}$') + print(r'\hat{g}_{ij} =', sympy.galgebra.latex_ex.LaTeX(g)) if debug_level == 2: return @@ -1018,7 +1058,7 @@ rnbases.append(base) ibasis += 1 else: - rnbases = reciprocal_frame(nbases,rnbase_name_lst) + rnbases = reciprocal_frame(nbases, rnbase_name_lst) ibase = 0 for base in rnbases: base.simplify() @@ -1041,24 +1081,25 @@ Acoef = [] for ibasis in MV.nrg: - evec = numpy.array(MV.n*[ZERO],dtype=numpy.object) + evec = numpy.array(MV.n*[ZERO], dtype=numpy.object) for jbasis in MV.nrg: - evec[jbasis] = (MV.bvec[ibasis]|rnbases[jbasis])() + evec[jbasis] = (MV.bvec[ibasis] | rnbases[jbasis])() Acoef.append(evec) #Calculat metric tensors - gr = numpy.array(MV.n*[MV.n*[ZERO]],dtype=numpy.object) + gr = numpy.array(MV.n*[MV.n*[ZERO]], dtype=numpy.object) for irow in MV.nrg: for icol in MV.nrg: - magsq = sympy.expand((rnbases[irow]|rnbases[icol])()) - gr[irow][icol] = sympy.simplify(sympy.trigsimp(magsq,deep=True,recursive=True)) + magsq = sympy.expand((rnbases[irow] | rnbases[icol])()) + gr[irow][icol] = sympy.simplify( + sympy.trigsimp(magsq, deep=True, recursive=True)) if debug: - print('Metric $\\hat{g}^{ij} = \\hat{'+LaTeX_base+'}^{i}\\cdot \\hat{'+\ - LaTeX_base+'}^{j}$') - print(r'\hat{g}^{ij} =',sympy.galgebra.latex_ex.LaTeX(gr)) + print('Metric $\\hat{g}^{ij} = \\hat{' + LaTeX_base + \ + '}^{i}\\cdot \\hat{' + LaTeX_base + '}^{j}$') + print(r'\hat{g}^{ij} =', sympy.galgebra.latex_ex.LaTeX(gr)) if debug_level == 4: return @@ -1073,10 +1114,10 @@ grade_bases = [] rgrade_bases = [] for index in base_index: - base = build_base(index,nbases) + base = build_base(index, nbases) base.simplify() base.trigsimp() - rbase = build_base(index,rnbases,True) + rbase = build_base(index, rnbases, True) rbase.simplify() rbase.trigsimp() grade_bases.append(base) @@ -1095,7 +1136,7 @@ for base in MV_bases[igrade]: sum = MV() itheta = 0 - for (theta,etheta) in zip(coords,rnbases): + for (theta, etheta) in zip(coords, rnbases): psum = (1/mags[itheta])*etheta*base.diff(theta) psum.trigsimp() sum += psum @@ -1108,7 +1149,8 @@ igrade += 1 if debug: - print('Curvilinear Bases: $'+bstr+' = '+bmhat+'_{i_{1}}\\W\\dots\\W'+bmhat+'_{i_{R}}$') + print('Curvilinear Bases: $' + bstr + ' = ' + bmhat + \ + '_{i_{1}}\\W\\dots\\W' + bmhat + '_{i_{R}}$') igrade = 1 for grade in MV_bases[1:]: ibase = 0 @@ -1117,8 +1159,8 @@ sub_str = '' for i in index: sub_str += sympy.galgebra.latex_ex.LatexPrinter.extended_symbol(coords_lst[i]) - base_str = bmhat+'_{['+sub_str+']} = ' - print(base_str,base) + base_str = bmhat + '_{[' + sub_str + ']} = ' + print(base_str, base) ibase += 1 igrade += 1 @@ -1136,11 +1178,11 @@ if igrade < MV.n: ibase = 0 - p1base = len(MV_bases[igrade+1]) - m1base = len(MV_bases[igrade-1]) + p1base = len(MV_bases[igrade + 1]) + m1base = len(MV_bases[igrade - 1]) while ibase < nbase: - Cm1 = numpy.array(m1base*[ZERO],dtype=numpy.object) - Cp1 = numpy.array(p1base*[ZERO],dtype=numpy.object) + Cm1 = numpy.array(m1base*[ZERO], dtype=numpy.object) + Cp1 = numpy.array(p1base*[ZERO], dtype=numpy.object) C = MV_connect[igrade][ibase] if igrade == 1: X = C(0) @@ -1148,29 +1190,30 @@ X = MV() jbase = 0 while jbase < m1base: - Cm1[jbase] = sympy.trigsimp((MV.inner_product(MV_rbases[igrade-1][jbase],C))(),deep=True,recursive=True) + Cm1[jbase] = sympy.trigsimp((MV.inner_product(MV_rbases[igrade - 1][jbase], C))(), deep=True, recursive=True) jbase += 1 jbase = 0 while jbase < p1base: - Cp1[jbase] = sympy.trigsimp((MV.inner_product(MV_rbases[igrade+1][jbase],C))(),deep=True,recursive=True) + Cp1[jbase] = sympy.trigsimp((MV.inner_product(MV_rbases[igrade + 1][jbase], C))(), deep=True, recursive=True) jbase += 1 - X += MV((igrade-1,Cm1),'grade')+MV((igrade+1,Cp1),'grade') + X += MV( + (igrade - 1, Cm1), 'grade') + MV((igrade + 1, Cp1), 'grade') X.simplify() X.trigsimp() grade_connect.append(X) ibase += 1 else: ibase = 0 - m1base = len(MV_bases[igrade-1]) + m1base = len(MV_bases[igrade - 1]) while ibase < nbase: - Cm1 = numpy.array(m1base*[ZERO],dtype=numpy.object) + Cm1 = numpy.array(m1base*[ZERO], dtype=numpy.object) C = MV_connect[igrade][ibase] jbase = 0 while jbase < m1base: - Cm1[jbase] = sympy.trigsimp((MV.inner_product(MV_rbases[igrade-1][jbase],C))(),deep=True,recursive=True) + Cm1[jbase] = sympy.trigsimp((MV.inner_product(MV_rbases[igrade - 1][jbase], C))(), deep=True, recursive=True) jbase += 1 X = MV() - X.mv[MV.n-1] = Cm1 + X.mv[MV.n - 1] = Cm1 X.simplify() X.trigsimp() grade_connect.append(X) @@ -1181,17 +1224,18 @@ base_str = '' for coord in coords: - base_str += base_name+'_'+sympy.galgebra.latex_ex.LatexPrinter.str_basic(coord)+' ' + base_str += base_name + '_' + \ + sympy.galgebra.latex_ex.LatexPrinter.str_basic(coord) + ' ' base_str = base_str[:-1] old_names = MV.vbasis - MV.setup(base_str,g,True,coords) + MV.setup(base_str, g, True, coords) MV.curvilinear_flg = True MV.Connect = MV_Connect sympy.galgebra.latex_ex.LatexPrinter.latex_bases() - MV.Rframe = numpy.array(MV.n*[ZERO],dtype=numpy.object) + MV.Rframe = numpy.array(MV.n*[ZERO], dtype=numpy.object) ibasis = 0 while ibasis < MV.n: base = MV() @@ -1205,7 +1249,7 @@ MV.org_basis = [] for ibasis in MV.nrg: - evec = MV(Acoef[ibasis],'vector',old_names[ibasis]) + evec = MV(Acoef[ibasis], 'vector', old_names[ibasis]) MV.org_basis.append(evec) if MV.coords[0] == sympy.Symbol('t'): @@ -1213,7 +1257,7 @@ # I can't fix this no name error because I have no clue what the # original writer was trying to do. for coef in dedt_coef: - MV.dedt.append(MV(coef,'vector')) + MV.dedt.append(MV(coef, 'vector')) else: MV.dedt = None @@ -1222,20 +1266,21 @@ for evec in MV.org_basis: print(evec) - print('Renormalized Reciprocal Vectors '+\ - '$\\bfrac{'+bmhat+'^{k}}{\\abs{\\bm{'+LaTeX_base+'}_{k}}}$') + print('Renormalized Reciprocal Vectors ' + '$\\bfrac{' + bmhat + \ + '^{k}}{\\abs{\\bm{' + LaTeX_base + '}_{k}}}$') ibasis = 0 while ibasis < MV.n: - c_str = sympy.galgebra.latex_ex.LatexPrinter.extended_symbol(coords_lst[ibasis]) - print('\\bfrac{\\bm{\\hat{'+LaTeX_base+\ - '}}^{'+c_str+'}}{\\abs{\\bm{'+LaTeX_base+\ - '}_{'+c_str+'}}} =',MV.Rframe[ibasis]) + c_str = sympy.galgebra.latex_ex.LatexPrinter.extended_symbol( + coords_lst[ibasis]) + print('\\bfrac{\\bm{\\hat{' + LaTeX_base + '}}^{' + c_str + \ + '}}{\\abs{\\bm{' + LaTeX_base + '}_{' + c_str + '}}} =', \ + MV.Rframe[ibasis]) ibasis += 1 - title_str = 'Connection Multivectors: $C\\lbrc'+bstr+'\\rbrc = '+\ - '\\bfrac{'+bmhat+'^{k}}{\\abs{'+bmhat+\ - '_{k}}}\\pdiff{'+bstr+'}{\\theta^{k}}$' + title_str = 'Connection Multivectors: $C\\lbrc' + bstr + \ + '\\rbrc = ' + '\\bfrac{' + bmhat + '^{k}}{\\abs{' + bmhat + \ + '_{k}}}\\pdiff{' + bstr + '}{\\theta^{k}}$' print(title_str) igrade = 1 @@ -1247,8 +1292,9 @@ for i in index: sub_str += sympy.galgebra.latex_ex.LatexPrinter.extended_symbol(coords_lst[i]) - base_str = 'C\\lbrc\\hat{'+LaTeX_base+'}_{['+sub_str+']}\\rbrc = ' - print(base_str,base) + base_str = 'C\\lbrc\\hat{' + \ + LaTeX_base + '}_{[' + sub_str + ']}\\rbrc = ' + print(base_str, base) ibase += 1 igrade += 1 return @@ -1291,11 +1337,11 @@ base2 = [] else: base2 = MV.basis[jgrade][jbase] - base = base1+base2 - (coefs,bases) = MV.reduce_basis(base) - product = MV.convert(coefs,bases) - product.name = '('+MV.basislabel[igrade][ibase]+')('+\ - MV.basislabel[jgrade][jbase]+')' + base = base1 + base2 + (coefs, bases) = MV.reduce_basis(base) + product = MV.convert(coefs, bases) + product.name = '(' + MV.basislabel[igrade][ibase] + \ + ')(' + MV.basislabel[jgrade][jbase] + ')' MV.mtable[igrade][ibase][jgrade].append(product) if MV.debug: print('Multiplication Table:') @@ -1307,14 +1353,14 @@ return @staticmethod - def geometric_product(mv1,mv2): + def geometric_product(mv1, mv2): """ MV.geometric_product(mv1,mv2) calculates the geometric product the multivectors mv1 and mv2 (mv1*mv2). See reference 5 section 3. """ product = MV() - if isinstance(mv1,MV) and isinstance(mv2,MV): + if isinstance(mv1, MV) and isinstance(mv2, MV): bladeflg1 = mv1.bladeflg bladeflg2 = mv2.bladeflg if bladeflg1: @@ -1323,13 +1369,13 @@ mv2.convert_from_blades() for igrade in MV.n1rg: gradei = mv1.mv[igrade] - if isinstance(gradei,numpy.ndarray): + if isinstance(gradei, numpy.ndarray): for ibase in range(MV.nbasis[igrade]): xi = gradei[ibase] if xi != ZERO: for jgrade in MV.n1rg: gradej = mv2.mv[jgrade] - if isinstance(gradej,numpy.ndarray): + if isinstance(gradej, numpy.ndarray): for jbase in range(MV.nbasis[jgrade]): xj = gradej[jbase] if xj != ZERO: @@ -1343,24 +1389,24 @@ if bladeflg1 and bladeflg2: product.convert_to_blades() else: - if isinstance(mv1,MV): + if isinstance(mv1, MV): product = mv1.scalar_mul(mv2) else: product = mv2.scalar_mul(mv1) return(product) @staticmethod - def wedge(igrade1,blade1,vector2,name=''): + def wedge(igrade1, blade1, vector2, name=''): """ Calculate the outer product of a multivector blade and a vector. See reference 5 section 5 for details. """ w12 = blade1*vector2 w21 = vector2*blade1 - if igrade1%2 != 0: - w = w12-w21 + if igrade1 % 2 != 0: + w = w12 - w21 else: - w = w12+w21 + w = w12 + w21 w.name = name return(w*HALF) @@ -1378,27 +1424,28 @@ MV.bladelabel.append([]) if igrade == 0: MV.bladelabel[0].append('1') - tmp = [MV(value=ONE,mvtype='scalar',mvname='1')] + tmp = [MV(value=ONE, mvtype='scalar', mvname='1')] if igrade == 1: tmp = [] for ibase in range(MV.nbasis[1]): MV.bladelabel[1].append(basis_str[ibase]) - tmp.append(MV(value=ibase,mvtype='basisvector',mvname=basis_str[ibase])) + tmp.append(MV(value=ibase, + mvtype='basisvector', mvname=basis_str[ibase])) if igrade >= 2: tmp = [] basis = MV.basis[igrade] for blade in basis: name = '' for i in blade: - name += basis_str[i]+'^' + name += basis_str[i] + '^' name = name[:-1] MV.bladelabel[igrade].append(name) - lblade = MV.basis[igrade-1].index(blade[:-1]) + lblade = MV.basis[igrade - 1].index(blade[:-1]) rblade = blade[-1] - igrade1 = igrade-1 - blade1 = MV.btable[igrade1][lblade] + igrade1 = igrade - 1 + blade1 = MV.btable[igrade1][lblade] vector2 = MV.btable[1][rblade] - b1Wv2 = MV.wedge(igrade1,blade1,vector2,name) + b1Wv2 = MV.wedge(igrade1, blade1, vector2, name) tmp.append(b1Wv2) MV.btable.append(tmp) if MV.debug: @@ -1420,25 +1467,26 @@ MV.ibtable = [] for igrade in MV.n1rg: if igrade == 0: - tmp = [MV(value=ONE,mvtype='scalar',mvname='1')] + tmp = [MV(value=ONE, mvtype='scalar', mvname='1')] if igrade == 1: tmp = [] for ibase in range(MV.nbasis[1]): - tmp.append(MV(value=ibase,mvtype='basisvector')) + tmp.append(MV(value=ibase, mvtype='basisvector')) if igrade >= 2: tmp = [] iblade = 0 for blade in MV.btable[igrade]: invblade = MV() - for i in range(igrade-1): + for i in range(igrade - 1): invblade.mv[i] = -blade.mv[i] invblade.mv[igrade] = +blade.mv[igrade] invblade.bladeflg = 1 if igrade >= 4: - jgrade = igrade-2 + jgrade = igrade - 2 while jgrade > 1: for ibase in range(MV.nbasis[jgrade]): - invblade.substitute_base(jgrade,ibase,MV.ibtable[jgrade][ibase]) + invblade.substitute_base( + jgrade, ibase, MV.ibtable[jgrade][ibase]) jgrade -= 2 invblade.name = MV.basislabel[igrade][iblade] iblade += 1 @@ -1452,7 +1500,7 @@ return @staticmethod - def outer_product(mv1,mv2): + def outer_product(mv1, mv2): """ MV.outer_product(mv1,mv2) calculates the outer (exterior,wedge) product of the multivectors mv1 and mv2 (mv1^mv2). See @@ -1462,30 +1510,30 @@ if mv1.is_scalar() and mv2.is_scalar(): return(mv1*mv2) - if isinstance(mv1,MV) and isinstance(mv2,MV): + if isinstance(mv1, MV) and isinstance(mv2, MV): product = MV() product.bladeflg = 1 mv1.convert_to_blades() mv2.convert_to_blades() for igrade1 in MV.n1rg: - if isinstance(mv1.mv[igrade1],numpy.ndarray): + if isinstance(mv1.mv[igrade1], numpy.ndarray): pg1 = mv1.project(igrade1) for igrade2 in MV.n1rg: - igrade = igrade1+igrade2 + igrade = igrade1 + igrade2 if igrade <= MV.n: - if isinstance(mv2.mv[igrade2],numpy.ndarray): + if isinstance(mv2.mv[igrade2], numpy.ndarray): pg2 = mv2.project(igrade2) pg1pg2 = pg1*pg2 product.add_in_place(pg1pg2.project(igrade)) else: - if isinstance(mv1,MV): + if isinstance(mv1, MV): product = mv1.scalar_mul(mv2) - if isinstance(mv2,MV): + if isinstance(mv2, MV): product = mv2.scalar_mul(mv1) return(product) @staticmethod - def inner_product(mv1,mv2,mode='s'): + def inner_product(mv1, mv2, mode='s'): """ MV.inner_product(mv1,mv2) calculates the inner @@ -1497,106 +1545,105 @@ if mv1.is_scalar() and mv2.is_scalar(): return(mv1*mv2) - if isinstance(mv1,MV) and isinstance(mv2,MV): + if isinstance(mv1, MV) and isinstance(mv2, MV): product = MV() product.bladeflg = 1 mv1.convert_to_blades() mv2.convert_to_blades() for igrade1 in range(MV.n1): - if isinstance(mv1.mv[igrade1],numpy.ndarray): + if isinstance(mv1.mv[igrade1], numpy.ndarray): pg1 = mv1.project(igrade1) for igrade2 in range(MV.n1): - igrade = igrade1-igrade2 + igrade = igrade1 - igrade2 if mode == 's': igrade = igrade.__abs__() else: if mode == 'l': igrade = -igrade if igrade >= 0: - if isinstance(mv2.mv[igrade2],numpy.ndarray): + if isinstance(mv2.mv[igrade2], numpy.ndarray): pg2 = mv2.project(igrade2) pg1pg2 = pg1*pg2 product.add_in_place(pg1pg2.project(igrade)) return(product) else: if mode == 's': - if isinstance(mv1,MV): + if isinstance(mv1, MV): product = mv1.scalar_mul(mv2) - if isinstance(mv2,MV): + if isinstance(mv2, MV): product = mv2.scalar_mul(mv1) else: product = None return(product) - @staticmethod - def addition(mv1,mv2): + def addition(mv1, mv2): """ MV.addition(mv1,mv2) calculates the sum of the multivectors mv1 and mv2 (mv1+mv2). """ sum = MV() - if isinstance(mv1,MV) and isinstance(mv2,MV): + if isinstance(mv1, MV) and isinstance(mv2, MV): if mv1.bladeflg or mv2.bladeflg: mv1.convert_to_blades() mv2.convert_to_blades() sum.bladeflg = 1 for i in MV.n1rg: - if isinstance(mv1.mv[i],numpy.ndarray) and isinstance(mv2.mv[i],numpy.ndarray): - sum.mv[i] = mv1.mv[i]+mv2.mv[i] + if isinstance(mv1.mv[i], numpy.ndarray) and isinstance(mv2.mv[i], numpy.ndarray): + sum.mv[i] = mv1.mv[i] + mv2.mv[i] else: - if isinstance(mv1.mv[i],numpy.ndarray) and not isinstance(mv2.mv[i],numpy.ndarray): + if isinstance(mv1.mv[i], numpy.ndarray) and not isinstance(mv2.mv[i], numpy.ndarray): sum.mv[i] = +mv1.mv[i] else: - if isinstance(mv2.mv[i],numpy.ndarray) and not isinstance(mv1.mv[i],numpy.ndarray): + if isinstance(mv2.mv[i], numpy.ndarray) and not isinstance(mv1.mv[i], numpy.ndarray): sum.mv[i] = +mv2.mv[i] return(sum) else: - if isinstance(mv1,MV): - return(mv1+MV(mv2,'scalar')) + if isinstance(mv1, MV): + return(mv1 + MV(mv2, 'scalar')) else: - return(MV(mv1,'scalar')+mv2) + return(MV(mv1, 'scalar') + mv2) @staticmethod - def subtraction(mv1,mv2): + def subtraction(mv1, mv2): """ MV.subtraction(mv1,mv2) calculates the difference of the multivectors mv1 and mv2 (mv1-mv2). """ diff = MV() - if isinstance(mv1,MV) and isinstance(mv2,MV): + if isinstance(mv1, MV) and isinstance(mv2, MV): if mv1.bladeflg or mv2.bladeflg: mv1.convert_to_blades() mv2.convert_to_blades() diff.bladeflg = 1 for i in MV.n1rg: - if isinstance(mv1.mv[i],numpy.ndarray) and isinstance(mv2.mv[i],numpy.ndarray): - diff.mv[i] = mv1.mv[i]-mv2.mv[i] + if isinstance(mv1.mv[i], numpy.ndarray) and isinstance(mv2.mv[i], numpy.ndarray): + diff.mv[i] = mv1.mv[i] - mv2.mv[i] else: - if isinstance(mv1.mv[i],numpy.ndarray) and not isinstance(mv2.mv[i],numpy.ndarray): + if isinstance(mv1.mv[i], numpy.ndarray) and not isinstance(mv2.mv[i], numpy.ndarray): diff.mv[i] = +mv1.mv[i] else: - if not isinstance(mv1.mv[i],numpy.ndarray) and isinstance(mv2.mv[i],numpy.ndarray): + if not isinstance(mv1.mv[i], numpy.ndarray) and isinstance(mv2.mv[i], numpy.ndarray): diff.mv[i] = -mv2.mv[i] return(diff) else: - if isinstance(mv1,MV): - return(mv1-MV(mv2,'scalar')) + if isinstance(mv1, MV): + return(mv1 - MV(mv2, 'scalar')) else: - return(MV(mv1,'scalar')-mv2) + return(MV(mv1, 'scalar') - mv2) @staticmethod - def vdiff(vec,x): + def vdiff(vec, x): dvec = numpy.array(len(vec)*[ZERO]) ivec = 0 for veci in vec: - dvec[ivec] = sympy.diff(veci,x) + dvec[ivec] = sympy.diff(veci, x) ivec += 1 return(dvec) @staticmethod def scalar_to_symbol(scalar): - if isinstance(scalar,MV): + if isinstance(scalar, MV): return(scalar.mv[0][0]) if type(scalar) == list: sym = [] @@ -1605,7 +1652,7 @@ return(sym) return(scalar) - def __init__(self,value='',mvtype='',mvname='',fct=False,vars=None): + def __init__(self, value='', mvtype='', mvname='', fct=False, vars=None): """ Initialization of multivector X. Inputs are as follows @@ -1632,134 +1679,147 @@ multivector field of MV.coords is instantiated. """ - self.name = mvname - self.mv = MV.n1*[0] - self.bladeflg = 0 #1 for blade expansion + self.name = mvname + self.mv = MV.n1*[0] + self.bladeflg = 0 # 1 for blade expansion self.puregrade = 1 if mvtype == 'basisvector': - self.mv[1] = numpy.array(MV.nbasis[1]*[ZERO],dtype=numpy.object) + self.mv[1] = numpy.array(MV.nbasis[1]*[ZERO], dtype=numpy.object) self.mv[1][value] = ONE if mvtype == 'basisbivector': - self.mv[2] = numpy.array(MV.nbasis[2]*[ZERO],dtype=numpy.object) + self.mv[2] = numpy.array(MV.nbasis[2]*[ZERO], dtype=numpy.object) self.mv[2][value] = ONE if mvtype == 'scalar': - if isinstance(value,str): + if isinstance(value, str): value = sympy.Symbol(value) - if isinstance(value,int): + if isinstance(value, int): value = sympy.Rational(value) - self.mv[0] = numpy.array([value],dtype=numpy.object) + self.mv[0] = numpy.array([value], dtype=numpy.object) if mvtype == 'pseudo': - if isinstance(value,str): + if isinstance(value, str): value = sympy.Symbol(value) - self.mv[MV.n] = numpy.array([value],dtype=numpy.object) + self.mv[MV.n] = numpy.array([value], dtype=numpy.object) if mvtype == 'vector': - if isinstance(value,str): #Most general vector + if isinstance(value, str): # Most general vector symbol_str = '' for ibase in MV.nrg: - if MV.coords == None: - symbol = value+'__'+str(ibase+MV.index_offset) - symbol_str += symbol+' ' + if MV.coords is None: + symbol = value + '__' + str(ibase + MV.index_offset) + symbol_str += symbol + ' ' else: - symbol = value+'__'+(MV.coords[ibase]).name - symbol_str += symbol+' ' + symbol = value + '__' + (MV.coords[ibase]).name + symbol_str += symbol + ' ' symbol_lst = sympy.symbols(symbol_str) - self.mv[1] = numpy.array(symbol_lst,dtype=numpy.object) + self.mv[1] = numpy.array(symbol_lst, dtype=numpy.object) self.name = value else: - value = MV.pad_zeros(value,MV.nbasis[1]) - self.mv[1] = numpy.array(value,dtype=numpy.object) + value = MV.pad_zeros(value, MV.nbasis[1]) + self.mv[1] = numpy.array(value, dtype=numpy.object) if mvtype == 'grade2': - if isinstance(value,str): #Most general grade-2 multivector + if isinstance(value, str): # Most general grade-2 multivector if value != '': symbol_str = '' for base in MV.basis[2]: - symbol = value+MV.construct_index(base) - symbol_str += symbol+' ' + symbol = value + MV.construct_index(base) + symbol_str += symbol + ' ' symbol_lst = sympy.symbols(symbol_str) - self.mv[2] = numpy.array(symbol_lst,dtype=numpy.object) + self.mv[2] = numpy.array(symbol_lst, dtype=numpy.object) else: - value = MV.pad_zeros(value,MV.nbasis[2]) - self.mv[2] = numpy.array(value,dtype=numpy.object) + value = MV.pad_zeros(value, MV.nbasis[2]) + self.mv[2] = numpy.array(value, dtype=numpy.object) if mvtype == 'grade': igrade = value[0] - coefs = value[1] - if isinstance(coefs,str): #Most general pure grade multivector + coefs = value[1] + if isinstance(coefs, str): # Most general pure grade multivector base_symbol = coefs coefs = [] bases = MV.basis[igrade] if igrade == 0: - self.mv[0] = numpy.array([sympy.Symbol(base_symbol)],dtype=numpy.object) + self.mv[0] = numpy.array( + [sympy.Symbol(base_symbol)], dtype=numpy.object) else: for base in bases: - coef = base_symbol+MV.construct_index(base) + coef = base_symbol + MV.construct_index(base) coef = sympy.Symbol(coef) coefs.append(coef) - self.mv[igrade] = numpy.array(coefs,dtype=numpy.object) + self.mv[igrade] = numpy.array(coefs, dtype=numpy.object) else: self.mv[igrade] = coefs if mvtype == 'base': - self.mv[value[0]] = numpy.array(MV.nbasis[value[0]]*[ZERO],dtype=numpy.object) + self.mv[value[0]] = numpy.array( + MV.nbasis[value[0]]*[ZERO], dtype=numpy.object) self.mv[value[0]][value[1]] = ONE if mvtype == 'spinor': - if isinstance(value,str): #Most general spinor + if isinstance(value, str): # Most general spinor for grade in MV.n1rg: - if grade%2 == 0: + if grade % 2 == 0: symbol_str = '' if grade != 0: symbol_lst = [] for base in MV.basis[grade]: - symbol = sympy.Symbol(value+MV.construct_index(base)) + symbol = sympy.Symbol( + value + MV.construct_index(base)) symbol_lst.append(symbol) - self.mv[grade] = numpy.array(symbol_lst,dtype=numpy.object) + self.mv[grade] = numpy.array( + symbol_lst, dtype=numpy.object) else: - self.mv[0] = numpy.array([sympy.Symbol(value)],dtype=numpy.object) - self.name = value+'bm' - if isinstance(value,str) and mvtype == '': #Most general multivector + self.mv[0] = numpy.array( + [sympy.Symbol(value)], dtype=numpy.object) + self.name = value + 'bm' + if isinstance(value, str) and mvtype == '': # Most general multivector if value != '': for grade in MV.n1rg: symbol_str = '' if grade != 0: symbol_lst = [] for base in MV.basis[grade]: - symbol = sympy.Symbol(value+MV.construct_index(base)) + symbol = sympy.Symbol( + value + MV.construct_index(base)) symbol_lst.append(symbol) - self.mv[grade] = numpy.array(symbol_lst,dtype=numpy.object) + self.mv[grade] = numpy.array( + symbol_lst, dtype=numpy.object) else: - self.mv[0] = numpy.array([sympy.Symbol(value)],dtype=numpy.object) - self.name = value+'bm' + self.mv[0] = numpy.array( + [sympy.Symbol(value)], dtype=numpy.object) + self.name = value + 'bm' if fct: if vars is not None: vars = tuple(vars) for grade in MV.n1rg: - if not isinstance(self.mv[grade],int): + if not isinstance(self.mv[grade], int): if grade == 0: - coef = sympy.galgebra.latex_ex.LatexPrinter.str_basic(self.mv[0][0]) - if vars == None and MV.coords is not None: - self.mv[0]= numpy.array([sympy.Function(coef)(*MV.coords)],dtype=numpy.object) + coef = sympy.galgebra.latex_ex.LatexPrinter.str_basic( + self.mv[0][0]) + if vars is None and MV.coords is not None: + self.mv[0] = numpy.array([sympy.Function( + coef)(*MV.coords)], dtype=numpy.object) else: - self.mv[0]= numpy.array([sympy.Function(coef)(*vars)],dtype=numpy.object) + self.mv[0] = numpy.array([sympy.Function( + coef)(*vars)], dtype=numpy.object) else: for base in range(MV.nbasis[grade]): coef = sympy.galgebra.latex_ex.LatexPrinter.str_basic(self.mv[grade][base]) - if vars == None and MV.coords is not None: - self.mv[grade][base] = sympy.Function(coef)(*MV.coords) + if vars is None and MV.coords is not None: + self.mv[grade][ + base] = sympy.Function(coef)(*MV.coords) else: - self.mv[grade][base] = sympy.Function(coef)(*vars) + self.mv[ + grade][base] = sympy.Function(coef)(*vars) @staticmethod def construct_index(base): index_str = '' if len(base) == 0: return('') - if MV.coords == None: + if MV.coords is None: for ix in base: - index_str += str(ix+MV.index_offset) + index_str += str(ix + MV.index_offset) else: for ix in base: index_str += (MV.coords[ix]).name - return('__'+index_str) + return('__' + index_str) - def set_name(self,namestr): + def set_name(self, namestr): self.name = namestr return @@ -1767,66 +1827,68 @@ """ X.max_grade() is maximum grade of non-zero grades of X. """ - for i in range(MV.n,-1,-1): - if isinstance(self.mv[i],numpy.ndarray): + for i in range(MV.n, -1, -1): + if isinstance(self.mv[i], numpy.ndarray): return(i) return(-1) @staticmethod - def coord(xname,offset=0): + def coord(xname, offset=0): xi_str = '' for i in MV.nrg: - xi_str += xname+str(i+offset)+' ' + xi_str += xname + str(i + offset) + ' ' xi = sympy.symbols(xi_str) - x = MV(xi,'vector') + x = MV(xi, 'vector') return(x) - def x(self,i): + def x(self, i): if isint(self.mv[1]): return(ZERO) return(self.mv[1][i]) - def set_coef(self,grade,base,value): - if isinstance(self.mv[grade],int): - self.mv[grade] = numpy.array(MV.nbasis[grade]*[ZERO],dtype=numpy.object) + def set_coef(self, grade, base, value): + if isinstance(self.mv[grade], int): + self.mv[grade] = numpy.array( + MV.nbasis[grade]*[ZERO], dtype=numpy.object) self.mv[grade][base] = value return @staticmethod - def named(mvname,value='',mvtype=''): + def named(mvname, value='', mvtype=''): name = mvname - tmp = MV(value=value,mvtype=mvtype,mvname=name) - setattr(sys.modules[__name__],name,tmp) + tmp = MV(value=value, mvtype=mvtype, mvname=name) + setattr(sys.modules[__name__], name, tmp) return @staticmethod def printnm(tpl): for a in tpl: - print(a.name,' =',a.mv) + print(a.name, ' =', a.mv) return def __str__(self): return(MV.str_rep(self)) - def printmv(self,name=''): + def printmv(self, name=''): title = '' if name: - title += name+' = ' + title += name + ' = ' else: if self.name: - title += self.name+' = ' - print(title+MV.str_rep(self)) + title += self.name + ' = ' + print(title + MV.str_rep(self)) return - def set_value(self,igrade,ibase,value): - if isinstance(self.mv[igrade],numpy.ndarray): + def set_value(self, igrade, ibase, value): + if isinstance(self.mv[igrade], numpy.ndarray): self.mv[igrade][ibase] = value else: - self.mv[igrade] = numpy.array(MV.nbasis[igrade]*[ZERO],dtype=numpy.object) + self.mv[igrade] = numpy.array( + MV.nbasis[igrade]*[ZERO], dtype=numpy.object) self.mv[igrade][ibase] = value return - def add_in_place(self,mv): + def add_in_place(self, mv): """ X.add_in_place(mv) increments multivector X by multivector mv. @@ -1835,14 +1897,14 @@ self.convert_to_blades() mv.convert_to_blades() for i in MV.n1rg: - if isinstance(self.mv[i],numpy.ndarray) and isinstance(mv.mv[i],numpy.ndarray): + if isinstance(self.mv[i], numpy.ndarray) and isinstance(mv.mv[i], numpy.ndarray): self.mv[i] += mv.mv[i] else: - if not isinstance(self.mv[i],numpy.ndarray) and isinstance(mv.mv[i],numpy.ndarray): + if not isinstance(self.mv[i], numpy.ndarray) and isinstance(mv.mv[i], numpy.ndarray): self.mv[i] = +mv.mv[i] return - def sub_in_place(self,mv): + def sub_in_place(self, mv): """ X.sub_in_place(mv) decrements multivector X by multivector mv. @@ -1851,10 +1913,10 @@ self.convert_to_blades() mv.convert_to_blades() for i in MV.n1rg: - if isinstance(self.mv[i],numpy.ndarray) and isinstance(mv.mv[i],numpy.ndarray): + if isinstance(self.mv[i], numpy.ndarray) and isinstance(mv.mv[i], numpy.ndarray): self.mv[i] -= mv.mv[i] else: - if not isinstance(self.mv[i],numpy.ndarray) and isinstance(mv.mv[i],numpy.ndarray): + if not isinstance(self.mv[i], numpy.ndarray) and isinstance(mv.mv[i], numpy.ndarray): self.mv[i] = +mv.mv[i] return @@ -1862,7 +1924,7 @@ p = MV() p.bladeflg = self.bladeflg for i in MV.n1rg: - if isinstance(self.mv[i],numpy.ndarray): + if isinstance(self.mv[i], numpy.ndarray): p.mv[i] = +self.mv[i] return(p) @@ -1870,85 +1932,85 @@ n = MV() n.bladeflg = self.bladeflg for i in MV.n1rg: - if isinstance(self.mv[i],numpy.ndarray): + if isinstance(self.mv[i], numpy.ndarray): n.mv[i] = -self.mv[i] return(n) - def __add_ab__(self,mv): + def __add_ab__(self, mv): self.add_in_place(mv) return - def __sub_ab__(self,mv): + def __sub_ab__(self, mv): self.sub_in_place(mv) return - def __add__(self,mv): + def __add__(self, mv): """See MV.addition(self,mv)""" - return(MV.addition(self,mv)) + return(MV.addition(self, mv)) - def __radd__(self,mv): + def __radd__(self, mv): """See MV.addition(mv,self)""" - return(MV.addition(mv,self)) + return(MV.addition(mv, self)) - def __sub__(self,mv): + def __sub__(self, mv): """See MV.subtraction(self,mv)""" - return(MV.subtraction(self,mv)) + return(MV.subtraction(self, mv)) - def __rsub__(self,mv): + def __rsub__(self, mv): """See MV.subtraction(mv,self)""" - return(MV.subtraction(mv,self)) + return(MV.subtraction(mv, self)) - def __xor__(self,mv): + def __xor__(self, mv): """See MV.outer_product(self,mv)""" - return(MV.outer_product(self,mv)) + return(MV.outer_product(self, mv)) - def __pow__(self,mv): + def __pow__(self, mv): """See MV.outer_product(self,mv)""" - return(MV.outer_product(self,mv)) + return(MV.outer_product(self, mv)) - def __rxor__(self,mv): + def __rxor__(self, mv): """See MV.outer_product(mv,self)""" - return(MV.outer_product(mv,self)) + return(MV.outer_product(mv, self)) - def __or__(self,mv): + def __or__(self, mv): """See MV.inner_product(self,mv)""" - return(MV.inner_product(self,mv)) + return(MV.inner_product(self, mv)) - def __ror__(self,mv): + def __ror__(self, mv): """See MV.inner_product(mv,self)""" - return(MV.inner_product(mv,self)) + return(MV.inner_product(mv, self)) - def __lt__(self,mv): + def __lt__(self, mv): """See MV.inner_product(self,mv)""" - return(MV.inner_product(self,mv,'l')) + return(MV.inner_product(self, mv, 'l')) - def __lshift__(self,mv): + def __lshift__(self, mv): """See MV.inner_product(self,mv)""" - return(MV.inner_product(self,mv,'l')) + return(MV.inner_product(self, mv, 'l')) - def __rlshift__(self,mv): + def __rlshift__(self, mv): """See MV.inner_product(self,mv)""" - return(MV.inner_product(mv,self,'l')) + return(MV.inner_product(mv, self, 'l')) - def lc(self,mv): - return(MV.inner_product(self,mv,'l')) + def lc(self, mv): + return(MV.inner_product(self, mv, 'l')) - def __gt__(self,mv): + def __gt__(self, mv): """See MV.inner_product(self,mv)""" - return(MV.inner_product(self,mv,'r')) + return(MV.inner_product(self, mv, 'r')) - def __rshift__(self,mv): + def __rshift__(self, mv): """See MV.inner_product(self,mv)""" - return(MV.inner_product(self,mv,'r')) + return(MV.inner_product(self, mv, 'r')) - def __rrshift__(self,mv): + def __rrshift__(self, mv): """See MV.inner_product(self,mv)""" - return(MV.inner_product(mv,self,'r')) + return(MV.inner_product(mv, self, 'r')) - def rc(self,mv): - return(MV.inner_product(self,mv,'r')) + def rc(self, mv): + return(MV.inner_product(self, mv, 'r')) - def scalar_mul(self,c): + def scalar_mul(self, c): """ Y = X.scalar_mul(c), multiply multivector X by scalar c and return result. @@ -1957,100 +2019,100 @@ mv.bladeflg = self.bladeflg mv.puregrade = self.puregrade for i in MV.n1rg: - if isinstance(self.mv[i],numpy.ndarray): + if isinstance(self.mv[i], numpy.ndarray): #print self.mv[i] #print c,type(c) mv.mv[i] = self.mv[i]*c return(mv) - def scalar_mul_inplace(self,c): + def scalar_mul_inplace(self, c): """ X.scalar_mul_inplace(c), multiply multivector X by scalar c and save result in X. """ for i in MV.n1rg: - if isinstance(self.mv[i],numpy.ndarray): + if isinstance(self.mv[i], numpy.ndarray): self.mv[i] = self.mv[i]*c return - def __mul__(self,mv): + def __mul__(self, mv): """See MV.geometric_product(self,mv)""" - return(MV.geometric_product(self,mv)) + return(MV.geometric_product(self, mv)) - def __rmul__(self,mv): + def __rmul__(self, mv): """See MV.geometric_product(mv,self)""" - return(MV.geometric_product(mv,self)) + return(MV.geometric_product(mv, self)) - def __div__(self,scalar): + def __div__(self, scalar): div = MV() div.bladeflg = self.bladeflg for i in MV.n1rg: - if isinstance(self.mv[i],numpy.ndarray): + if isinstance(self.mv[i], numpy.ndarray): div.mv[i] = self.mv[i]/scalar return(div) - def __div_ab__(self,scalar): + def __div_ab__(self, scalar): for i in MV.n1rg: - if isinstance(self.mv[i],numpy.ndarray): + if isinstance(self.mv[i], numpy.ndarray): self.mv[i] /= scalar return - def __call__(self,igrade=0,ibase=0): + def __call__(self, igrade=0, ibase=0): """ X(i,j) returns symbol in ith grade and jth base or blade of multivector X. """ - if not isinstance(self.mv[igrade],numpy.ndarray): + if not isinstance(self.mv[igrade], numpy.ndarray): return(ZERO) return(self.mv[igrade][ibase]) @staticmethod - def equal(mv1,mv2): + def equal(mv1, mv2): mv1.compact() - if isinstance(mv2,MV): + if isinstance(mv2, MV): mv2.compact() pure_grade = mv1.is_pure() - if not isinstance(mv2,MV) and pure_grade != 0: + if not isinstance(mv2, MV) and pure_grade != 0: return(False) - if not isinstance(mv2,MV) and pure_grade == 0: - if isinstance(mv1.mv[0],int): + if not isinstance(mv2, MV) and pure_grade == 0: + if isinstance(mv1.mv[0], int): return(mv2 == 0) else: return(mv1.mv[0][0] == mv2) - for (mvi,mvj) in zip(mv1.mv,mv2.mv): + for (mvi, mvj) in zip(mv1.mv, mv2.mv): if isint(mvi) ^ isint(mvj): return(False) - if isinstance(mvi,numpy.ndarray) and isinstance(mvj,numpy.ndarray): - for (x,y) in zip(mvi,mvj): + if isinstance(mvi, numpy.ndarray) and isinstance(mvj, numpy.ndarray): + for (x, y) in zip(mvi, mvj): if x != y: return(False) return(True) - def __eq__(self,mv): - return(MV.equal(self,mv)) + def __eq__(self, mv): + return(MV.equal(self, mv)) - def copy(self,sub=0): + def copy(self, sub=0): """ Y = X.copy(), make a deep copy of multivector X in multivector Y so that Y can be modified without affecting X. """ cpy = MV() - cpy.name = self.name - cpy.bladeflg = self.bladeflg + cpy.name = self.name + cpy.bladeflg = self.bladeflg cpy.puregrade = self.puregrade for i in MV.n1rg: if sub: - if isinstance(self.mv[i],numpy.ndarray): + if isinstance(self.mv[i], numpy.ndarray): cpy.mv[i] = -self.mv[i] else: - if isinstance(self.mv[i],numpy.ndarray): + if isinstance(self.mv[i], numpy.ndarray): cpy.mv[i] = +self.mv[i] return(cpy) - def substitute_base(self,igrade,base,mv): - if not isinstance(self.mv[igrade],numpy.ndarray): + def substitute_base(self, igrade, base, mv): + if not isinstance(self.mv[igrade], numpy.ndarray): return - if isinstance(base,numpy.ndarray): + if isinstance(base, numpy.ndarray): ibase = MV.basis[igrade].index(base) else: ibase = base @@ -2069,8 +2131,8 @@ if self.bladeflg: return self.bladeflg = 1 - for igrade in range(2,MV.n1): - if isinstance(self.mv[igrade],numpy.ndarray): + for igrade in range(2, MV.n1): + if isinstance(self.mv[igrade], numpy.ndarray): for ibase in range(MV.nbasis[igrade]): coef = self.mv[igrade][ibase] if (not coef == ZERO): @@ -2086,8 +2148,8 @@ if not self.bladeflg: return self.bladeflg = 0 - for igrade in range(2,MV.n1): - if isinstance(self.mv[igrade],numpy.ndarray): + for igrade in range(2, MV.n1): + if isinstance(self.mv[igrade], numpy.ndarray): for ibase in range(MV.nbasis[igrade]): coef = self.mv[igrade][ibase] if (not coef == ZERO): @@ -2095,7 +2157,7 @@ self.add_in_place(MV.btable[igrade][ibase]*coef) return - def project(self,r): + def project(self, r): """ Grade projection operator. For multivector X, X.project(r) returns multivector of grade r components of X if r is an @@ -2105,23 +2167,23 @@ r is a general spinor then X.project(r) will return the even grades of X. """ - if isinstance(r,int): + if isinstance(r, int): grade_r = MV() if r > MV.n: return(grade_r) self.convert_to_blades() - if not isinstance(self.mv[r],numpy.ndarray): + if not isinstance(self.mv[r], numpy.ndarray): return(grade_r) grade_r.bladeflg = 1 grade_r.puregrade = 1 grade_r.mv[r] = +self.mv[r] return(grade_r) - if isinstance(r,MV): + if isinstance(r, MV): self.convert_to_blades() r.convert_to_blades() proj = MV() for i in MV.n1rg: - if not isinstance(r.mv[i],int): + if not isinstance(r.mv[i], int): proj.mv[i] = self.mv[i] proj.bladeflg = self.bladeflg return(proj) @@ -2134,9 +2196,9 @@ """ egrades = MV() self.convert_to_blades() - egrades.bladeflg = self.bladeflg + egrades.bladeflg = self.bladeflg egrades.puregrade = self.puregrade - for igrade in range(0,MV.n1,2): + for igrade in range(0, MV.n1, 2): egrades.mv[igrade] = +self.mv[igrade] return(egrades) @@ -2147,9 +2209,9 @@ """ ogrades = MV() self.convert_to_blades() - ogrades.bladeflg = self.bladeflg + ogrades.bladeflg = self.bladeflg ogrades.puregrade = self.puregrade - for igrade in range(1,MV.n1,2): + for igrade in range(1, MV.n1, 2): ogrades.mv[igrade] = +self.mv[igrade] return(ogrades) @@ -2160,30 +2222,31 @@ """ revmv = MV() self.convert_to_blades() - revmv.bladeflg = self.bladeflg + revmv.bladeflg = self.bladeflg revmv.puregrade = self.puregrade for igrade in MV.n1rg: - if isinstance(self.mv[igrade],numpy.ndarray): - if igrade < 2 or (not (((igrade*(igrade-1))/2)%2)): + if isinstance(self.mv[igrade], numpy.ndarray): + if igrade < 2 or (not (((igrade*(igrade - 1))/2) % 2)): revmv.mv[igrade] = +self.mv[igrade] else: revmv.mv[igrade] = -self.mv[igrade] return(revmv) - def cse(self,grade): + def cse(self, grade): cse_lst = [] - if isinstance(self.mv[grade],numpy.ndarray): + if isinstance(self.mv[grade], numpy.ndarray): for ibase in range(MV.nbasis[grade]): if self.mv[grade][ibase] != ZERO: cse_lst.append(sympy.cse(self.mv[grade][ibase])) return(cse_lst) - def div(self,grade,divisor): + def div(self, grade, divisor): div_lst = [] - if isinstance(self.mv[grade],numpy.ndarray): + if isinstance(self.mv[grade], numpy.ndarray): for ibase in range(MV.nbasis[grade]): if self.mv[grade][ibase] != ZERO: - div_lst.append(self.mv[grade][ibase].as_coefficient(divisor)) + div_lst.append( + self.mv[grade][ibase].as_coefficient(divisor)) return(div_lst) # don't know which one is correctly named @@ -2191,68 +2254,70 @@ def div(self): return self.grad_int() - def collect(self,lst): + def collect(self, lst): """ Applies sympy collect function to each component of multivector. """ for igrade in MV.n1rg: - if isinstance(self.mv[igrade],numpy.ndarray): + if isinstance(self.mv[igrade], numpy.ndarray): for ibase in range(MV.nbasis[igrade]): if self.mv[igrade][ibase] != ZERO: self.mv[igrade][ibase] = \ - sympy.collect(self.mv[igrade][ibase],lst) + sympy.collect(self.mv[igrade][ibase], lst) return - def sqrfree(self,lst): + def sqrfree(self, lst): """ Applies sympy sqrfree function to each component of multivector. """ for igrade in MV.n1rg: - if isinstance(self.mv[igrade],numpy.ndarray): + if isinstance(self.mv[igrade], numpy.ndarray): for ibase in range(MV.nbasis[igrade]): if self.mv[igrade][ibase] != ZERO: self.mv[igrade][ibase] = \ - sympy.sqrfree(self.mv[igrade][ibase],lst) + sympy.sqrfree(self.mv[igrade][ibase], lst) return def flatten(self): flst = [] for igrade in MV.n1rg: - if isinstance(self.mv[igrade],int): + if isinstance(self.mv[igrade], int): flst += MV.nbasis[igrade]*[ZERO] else: for coef in self.mv[igrade]: flst.append(coef) return(flst) - def subs(self,*args): + def subs(self, *args): X = MV() - X.bladeflg = self.bladeflg + X.bladeflg = self.bladeflg X.puregrade = self.puregrade for igrade in MV.n1rg: - if isinstance(self.mv[igrade],numpy.ndarray): - X.mv[igrade] = numpy.array(substitute_array(self.mv[igrade],*args)) + if isinstance(self.mv[igrade], numpy.ndarray): + X.mv[igrade] = numpy.array( + substitute_array(self.mv[igrade], *args)) return(X) - def sub_mv(self,mv1,mv2): + def sub_mv(self, mv1, mv2): mv1_flat = mv1.flatten() mv2_flat = mv2.flatten() - self.sub_scalar(mv1_flat,mv2_flat) + self.sub_scalar(mv1_flat, mv2_flat) return - def sub_scalar(self,expr1,expr2): - if (isinstance(expr1,list) and isinstance(expr2,list)) or \ - (isinstance(expr1,tuple) and isinstance(expr2,tuple)): - for (var1,var2) in zip(expr1,expr2): - self.sub_scalar(var1,var2) + def sub_scalar(self, expr1, expr2): + if (isinstance(expr1, list) and isinstance(expr2, list)) or \ + (isinstance(expr1, tuple) and isinstance(expr2, tuple)): + for (var1, var2) in zip(expr1, expr2): + self.sub_scalar(var1, var2) else: for igrade in MV.n1rg: - if not isinstance(self.mv[igrade],int): + if not isinstance(self.mv[igrade], int): for ibase in range(MV.nbasis[igrade]): if expr1 != ZERO: - self.mv[igrade][ibase] = self.mv[igrade][ibase].subs(expr1,expr2) + self.mv[igrade][ibase] = self.mv[ + igrade][ibase].subs(expr1, expr2) return def simplify(self): @@ -2261,11 +2326,11 @@ to each component of multivector. """ for igrade in MV.n1rg: - if isinstance(self.mv[igrade],numpy.ndarray): + if isinstance(self.mv[igrade], numpy.ndarray): for ibase in range(MV.nbasis[igrade]): if self.mv[igrade][ibase] != ZERO: self.mv[igrade][ibase] = \ - sympy.simplify(self.mv[igrade][ibase]) + sympy.simplify(self.mv[igrade][ibase]) return def trigsimp(self): @@ -2275,11 +2340,12 @@ using the recursive option. """ for igrade in MV.n1rg: - if isinstance(self.mv[igrade],numpy.ndarray): + if isinstance(self.mv[igrade], numpy.ndarray): for ibase in range(MV.nbasis[igrade]): if self.mv[igrade][ibase] != ZERO: self.mv[igrade][ibase] = \ - sympy.trigsimp(self.mv[igrade][ibase],deep=True, recursive=True) + sympy.trigsimp(self.mv[igrade] + [ibase], deep=True, recursive=True) return def cancel(self): @@ -2288,11 +2354,11 @@ to each component of multivector. """ for igrade in MV.n1rg: - if isinstance(self.mv[igrade],numpy.ndarray): + if isinstance(self.mv[igrade], numpy.ndarray): for ibase in range(MV.nbasis[igrade]): if self.mv[igrade][ibase] != ZERO: self.mv[igrade][ibase] = \ - sympy.cancel(self.mv[igrade][ibase]) + sympy.cancel(self.mv[igrade][ibase]) return def expand(self): @@ -2301,11 +2367,11 @@ of multivector. """ for igrade in MV.n1rg: - if isinstance(self.mv[igrade],numpy.ndarray): + if isinstance(self.mv[igrade], numpy.ndarray): for ibase in range(MV.nbasis[igrade]): if self.mv[igrade][ibase] != ZERO: self.mv[igrade][ibase] = \ - self.mv[igrade][ibase].expand() + self.mv[igrade][ibase].expand() return def is_pure(self): @@ -2313,7 +2379,7 @@ ngrade = 0 self.compact() for i in MV.n1rg: - if isinstance(self.mv[i],numpy.ndarray): + if isinstance(self.mv[i], numpy.ndarray): for base in self.mv[i]: if base != 0: igrade = i @@ -2348,7 +2414,7 @@ self.mv[i] = 0 return - def diff(self,x): + def diff(self, x): """ Calculate partial derivative of multivector with respect to argument x. @@ -2356,8 +2422,8 @@ D = MV() igrade = 0 for grade in self.mv: - if not isinstance(grade,int): - D.mv[igrade] = MV.vdiff(grade,x) + if not isinstance(grade, int): + D.mv[igrade] = MV.vdiff(grade, x) igrade += 1 return(D) @@ -2383,14 +2449,14 @@ recp = MV.Rframe else: recp = MV.brecp - for (rbase,iD) in zip(recp,D): + for (rbase, iD) in zip(recp, D): dD.add_in_place(rbase*iD) - if MV.curvilinear_flg: #Add Connection + if MV.curvilinear_flg: # Add Connection igrade = 1 while igrade <= MV.n: coefs = self.mv[igrade] if type(coefs) != int: - for (coef,connect) in zip(coefs,MV.Connect[igrade]): + for (coef, connect) in zip(coefs, MV.Connect[igrade]): dD.add_in_place(coef*connect) igrade += 1 return(dD) @@ -2407,16 +2473,16 @@ recp = MV.Rframe else: recp = MV.brecp - for (irbase,iD) in zip(recp,D): - dD.add_in_place(irbase^iD) - if MV.curvilinear_flg: #Add Connection + for (irbase, iD) in zip(recp, D): + dD.add_in_place(irbase ^ iD) + if MV.curvilinear_flg: # Add Connection igrade = 1 while igrade <= MV.n: coefs = self.mv[igrade] if type(coefs) != int: - for (coef,connect) in zip(coefs,MV.Connect[igrade]): + for (coef, connect) in zip(coefs, MV.Connect[igrade]): if igrade < MV.n: - dD.add_in_place(coef*connect.project(igrade+1)) + dD.add_in_place(coef*connect.project(igrade + 1)) igrade += 1 return(dD) @@ -2435,15 +2501,15 @@ recp = MV.Rframe else: recp = MV.brecp - for (irbase,iD) in zip(recp,D): - dD.add_in_place(irbase|iD) - if MV.curvilinear_flg: #Add Connection + for (irbase, iD) in zip(recp, D): + dD.add_in_place(irbase | iD) + if MV.curvilinear_flg: # Add Connection igrade = 1 while igrade <= MV.n: coefs = self.mv[igrade] if type(coefs) != int: - for (coef,connect) in zip(coefs,MV.Connect[igrade]): - dD.add_in_place(coef*connect.project(igrade-1)) + for (coef, connect) in zip(coefs, MV.Connect[igrade]): + dD.add_in_place(coef*connect.project(igrade - 1)) igrade += 1 return(dD) @@ -2451,7 +2517,7 @@ """ Calculate scalar component of square of multivector. """ - return((self|self)()) + return((self | self)()) def Name(self): """ @@ -2459,21 +2525,23 @@ """ return(sympy.galgebra.latex_ex.LatexPrinter.extended_symbol(self.name)) -def set_names(var_lst,var_str): + +def set_names(var_lst, var_str): """ Set the names of a list of multivectors (var_lst) for a space delimited string (var_str) containing the names. """ var_str_lst = var_str.split() if len(var_lst) == len(var_str_lst): - for (var,var_name) in zip(var_lst,var_str_lst): + for (var, var_name) in zip(var_lst, var_str_lst): var.set_name(var_name) return sys.stderr.write('Error in set_names. Lists incongruent!\n') sys.exit() return -def reciprocal_frame(vlst,names=''): + +def reciprocal_frame(vlst, names=''): """ Calculate reciprocal frame of list (vlst) of vectors. If desired name each vector in list of reciprocal vectors with names in space delimited string @@ -2486,18 +2554,18 @@ else: if names != '': name_lst = names.split() - for i in range(1,MV.n): - E = E^vlst[i] + for i in range(1, MV.n): + E = E ^ vlst[i] for i in range(MV.n): tmp = ONE - if i%2 != 0: + if i % 2 != 0: tmp = -ONE for j in range(MV.n): if i != j: - tmp = tmp^vlst[j] + tmp = tmp ^ vlst[j] tmp = tmp*E recp.append(tmp) - Esq = sympy.trigsimp(E.mag2(),deep=True,recursive=True) + Esq = sympy.trigsimp(E.mag2(), deep=True, recursive=True) print(Esq) print(sympy.simplify(Esq)) Esq_inv = ONE/Esq @@ -2510,5 +2578,6 @@ i += 1 return(recp) + def S(value): - return(MV(value,'scalar')) + return(MV(value, 'scalar')) diff -Nru python3-sympy-0.7.2/sympy/galgebra/latex_ex.py python3-sympy-0.7.3/sympy/galgebra/latex_ex.py --- python3-sympy-0.7.2/sympy/galgebra/latex_ex.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/galgebra/latex_ex.py 2013-07-13 17:53:32.000000000 +0000 @@ -6,7 +6,8 @@ #if sys.version.find('Stackless') >= 0: # sys.path.append('/usr/lib/python2.5/site-packages') -import os,types,io +import types +import io from sympy.core import S, C, Basic, Symbol from sympy.core.function import _coeff_isneg @@ -22,55 +23,27 @@ from sympy.utilities import default_sort_key from sympy.printing.latex import accepted_latex_functions +from sympy.printing.preview import preview + def debug(txt): - sys.stderr.write(txt+'\n') + sys.stderr.write(txt + '\n') return -def find_executable(executable, path=None): - """Try to find 'executable' in the directories listed in 'path' (a - string listing directories separated by 'os.pathsep'; defaults to - os.environ['PATH']). Returns the complete filename or None if not - found - """ - if path is None: - path = os.environ['PATH'] - paths = path.split(os.pathsep) - extlist = [''] - if os.name == 'os2': - (base, ext) = os.path.splitext(executable) - # executable files on OS/2 can have an arbitrary extension, but - # .exe is automatically appended if no dot is present in the name - if not ext: - executable = executable + ".exe" - elif sys.platform == 'win32': - pathext = os.environ['PATHEXT'].lower().split(os.pathsep) - (base, ext) = os.path.splitext(executable) - if ext.lower() not in pathext: - extlist = pathext - for ext in extlist: - execname = executable + ext - if os.path.isfile(execname): - return execname - else: - for p in paths: - f = os.path.join(p, execname) - if os.path.isfile(f): - return f - else: - return None -def len_cmp(str1,str2): - return(len(str2)-len(str1)) +def len_cmp(str1, str2): + return(len(str2) - len(str1)) + def process_equals(xstr): eq1 = xstr.find('=') eq2 = xstr.rfind('=') if eq1 == eq2: return(xstr) - xstr = xstr[:eq1]+xstr[eq2:] + xstr = xstr[:eq1] + xstr[eq2:] return(xstr) + class LatexPrinter(Printer): r""" A printer class which converts an expression into its LaTeX equivalent. @@ -140,68 +113,70 @@ str_fmt = 1 LaTeX_flg = False - mode = ('_','^') + mode = ('_', '^') - fmt_dict = {'sym':0,'fct':0,'pdiff':0,'mv':0,'str':1} + fmt_dict = {'sym': 0, 'fct': 0, 'pdiff': 0, 'mv': 0, 'str': 1} - fct_dict = {'sin':'sin','cos':'cos','tan':'tan','cot':'cot',\ - 'asin':'Sin^{-1}','acos':'Cos^{-1}',\ - 'atan':'Tan^{-1}','acot':'Cot^{-1}',\ - 'sinh':'sinh','cosh':'cosh','tanh':'tanh','coth':'coth',\ - 'asinh':'Sinh^{-1}','acosh':'Cosh^{-1}', - 'atanh':'Tanh^{-1}','acoth':'Coth^{-1}',\ - 'sqrt':'sqrt','exp':'exp','log':'ln'} + fct_dict = {'sin': 'sin', 'cos': 'cos', 'tan': 'tan', 'cot': 'cot', + 'asin': 'Sin^{-1}', 'acos': 'Cos^{-1}', + 'atan': 'Tan^{-1}', 'acot': 'Cot^{-1}', + 'sinh': 'sinh', 'cosh': 'cosh', 'tanh': 'tanh', 'coth': 'coth', + 'asinh': 'Sinh^{-1}', 'acosh': 'Cosh^{-1}', + 'atanh': 'Tanh^{-1}', 'acoth': 'Coth^{-1}', + 'sqrt': 'sqrt', 'exp': 'exp', 'log': 'ln'} fct_dict_keys = list(fct_dict.keys()) - greek_keys = sorted(('alpha','beta','gamma','delta','varepsilon','epsilon','zeta',\ - 'vartheta','theta','iota','kappa','lambda','mu','nu','xi',\ - 'varpi','pi','rho','varrho','varsigma','sigma','tau','upsilon',\ - 'varphi','phi','chi','psi','omega','Gamma','Delta','Theta',\ - 'Lambda','Xi','Pi','Sigma','Upsilon','Phi','Psi','Omega','partial',\ - 'nabla','eta'),key=cmp_to_key(len_cmp)) - - accent_keys = sorted(('hat','check','dot','breve','acute','ddot','grave','tilde',\ - 'mathring','bar','vec','bm','prm','abs'),key=cmp_to_key(len_cmp)) + greek_keys = sorted( + ('alpha', 'beta', 'gamma', 'delta', 'varepsilon', 'epsilon', 'zeta', + 'vartheta', 'theta', 'iota', 'kappa', 'lambda', 'mu', 'nu', 'xi', + 'varpi', 'pi', 'rho', 'varrho', 'varsigma', 'sigma', 'tau', 'upsilon', + 'varphi', 'phi', 'chi', 'psi', 'omega', 'Gamma', 'Delta', 'Theta', + 'Lambda', 'Xi', 'Pi', 'Sigma', 'Upsilon', 'Phi', 'Psi', 'Omega', 'partial', + 'nabla', 'eta'), key=cmp_to_key(len_cmp)) + + accent_keys = sorted( + ('hat', 'check', 'dot', 'breve', 'acute', 'ddot', 'grave', 'tilde', + 'mathring', 'bar', 'vec', 'bm', 'prm', 'abs'), key=cmp_to_key(len_cmp)) greek_cnt = 0 greek_dict = {} accent_cnt = 0 accent_dict = {} - preamble = '\\documentclass[10pt,letter,fleqn]{report}\n'+\ - '\\pagestyle{empty}\n'+\ - '\\usepackage[latin1]{inputenc}\n'+\ - '\\usepackage[dvips,landscape,top=1cm,nohead,nofoot]{geometry}\n'+\ - '\\usepackage{amsmath}\n'+\ - '\\usepackage{bm}\n'+\ - '\\usepackage{amsfonts}\n'+\ - '\\usepackage{amssymb}\n'+\ - '\\setlength{\\parindent}{0pt}\n'+\ - '\\newcommand{\\bfrac}[2]{\\displaystyle\\frac{#1}{#2}}\n'+\ - '\\newcommand{\\lp}{\\left (}\n'+\ - '\\newcommand{\\rp}{\\right )}\n'+\ - '\\newcommand{\\half}{\\frac{1}{2}}\n'+\ - '\\newcommand{\\llt}{\\left <}\n'+\ - '\\newcommand{\\rgt}{\\right >}\n'+\ - '\\newcommand{\\abs}[1]{\\left |{#1}\\right | }\n'+\ - '\\newcommand{\\pdiff}[2]{\\bfrac{\\partial {#1}}{\\partial {#2}}}\n'+\ - '\\newcommand{\\lbrc}{\\left \\{}\n'+\ - '\\newcommand{\\rbrc}{\\right \\}}\n'+\ - '\\newcommand{\\W}{\\wedge}\n'+\ - "\\newcommand{\\prm}[1]{{#1}'}\n"+\ - '\\newcommand{\\ddt}[1]{\\bfrac{d{#1}}{dt}}\n'+\ - '\\newcommand{\\R}{\\dagger}\n'+\ + preamble = '\\documentclass[10pt,letter,fleqn]{report}\n' \ + '\\pagestyle{empty}\n' \ + '\\usepackage[latin1]{inputenc}\n' \ + '\\usepackage[dvips,landscape,top=1cm,nohead,nofoot]{geometry}\n' \ + '\\usepackage{amsmath}\n' \ + '\\usepackage{bm}\n' \ + '\\usepackage{amsfonts}\n' \ + '\\usepackage{amssymb}\n' \ + '\\setlength{\\parindent}{0pt}\n' \ + '\\newcommand{\\bfrac}[2]{\\displaystyle\\frac{#1}{#2}}\n' \ + '\\newcommand{\\lp}{\\left (}\n' \ + '\\newcommand{\\rp}{\\right )}\n' \ + '\\newcommand{\\half}{\\frac{1}{2}}\n' \ + '\\newcommand{\\llt}{\\left <}\n' \ + '\\newcommand{\\rgt}{\\right >}\n' \ + '\\newcommand{\\abs}[1]{\\left |{#1}\\right | }\n' \ + '\\newcommand{\\pdiff}[2]{\\bfrac{\\partial {#1}}{\\partial {#2}}}\n' \ + '\\newcommand{\\lbrc}{\\left \\{}\n' \ + '\\newcommand{\\rbrc}{\\right \\}}\n' \ + '\\newcommand{\\W}{\\wedge}\n' \ + "\\newcommand{\\prm}[1]{{#1}'}\n" \ + '\\newcommand{\\ddt}[1]{\\bfrac{d{#1}}{dt}}\n' \ + '\\newcommand{\\R}{\\dagger}\n' \ '\\begin{document}\n' - postscript = '\\end{document}\n' @staticmethod def latex_bases(): """ Generate LaTeX strings for multivector bases """ - if type(sympy.galgebra.GA.MV.basislabel_lst) == int: - sys.stderr.write('MV.setup() must be executed before LatexPrinter.format()!\n') + if isinstance(sympy.galgebra.GA.MV.basislabel_lst, int): + sys.stderr.write( + 'MV.setup() must be executed before LatexPrinter.format()!\n') sys.exit(1) LatexPrinter.latexbasis_lst = [['']] for grades in sympy.galgebra.GA.MV.basislabel_lst[1:]: @@ -216,7 +191,7 @@ return @staticmethod - def build_base(igrade,iblade,bld_flg): + def build_base(igrade, iblade, bld_flg): if igrade == 0: return('') base_lst = LatexPrinter.latexbasis_lst[igrade][iblade] @@ -225,19 +200,19 @@ base_str = '' for base in base_lst[:-1]: if bld_flg: - base_str += base+'\\W ' + base_str += base + '\\W ' else: base_str += base base_str += base_lst[-1] return(base_str) @staticmethod - def format(sym=0,fct=0,pdiff=0,mv=0): + def format(sym=0, fct=0, pdiff=0, mv=0): LatexPrinter.LaTeX_flg = True - LatexPrinter.fmt_dict['sym'] = sym - LatexPrinter.fmt_dict['fct'] = fct + LatexPrinter.fmt_dict['sym'] = sym + LatexPrinter.fmt_dict['fct'] = fct LatexPrinter.fmt_dict['pdiff'] = pdiff - LatexPrinter.fmt_dict['mv'] = mv + LatexPrinter.fmt_dict['mv'] = mv LatexPrinter.fmt_dict['str'] = 1 if sympy.galgebra.GA.MV.is_setup: LatexPrinter.latex_bases() @@ -256,7 +231,7 @@ @staticmethod def redirect(): LatexPrinter.Basic__str__ = Basic.__str__ - LatexPrinter.MV__str__ = sympy.galgebra.GA.MV.__str__ + LatexPrinter.MV__str__ = sympy.galgebra.GA.MV.__str__ LatexPrinter.stdout = sys.stdout sys.stdout = io.StringIO() Basic.__str__ = LaTeX @@ -282,16 +257,16 @@ def format_str(fmt='0 0 0 0'): fmt_lst = fmt.split() if '=' not in fmt: - LatexPrinter.fmt_dict['sym'] = int(fmt_lst[0]) - LatexPrinter.fmt_dict['fct'] = int(fmt_lst[1]) + LatexPrinter.fmt_dict['sym'] = int(fmt_lst[0]) + LatexPrinter.fmt_dict['fct'] = int(fmt_lst[1]) LatexPrinter.fmt_dict['pdiff'] = int(fmt_lst[2]) - LatexPrinter.fmt_dict['mv'] = int(fmt_lst[3]) + LatexPrinter.fmt_dict['mv'] = int(fmt_lst[3]) else: for fmt in fmt_lst: x = fmt.split('=') LatexPrinter.fmt_dict[x[0]] = int(x[1]) - if LatexPrinter.LaTeX_flg == False: + if LatexPrinter.LaTeX_flg is False: if sympy.galgebra.GA.MV.is_setup: LatexPrinter.latex_bases() LatexPrinter.redirect() @@ -311,20 +286,20 @@ for sym in LatexPrinter.greek_keys: isym = name_str.find(sym) if isym > -1: - keystr = '@'+str(LatexPrinter.greek_cnt) + keystr = '@' + str(LatexPrinter.greek_cnt) LatexPrinter.greek_cnt += 1 LatexPrinter.greek_dict[keystr] = sym - name_str = name_str.replace(sym,keystr) + name_str = name_str.replace(sym, keystr) return(name_str) @staticmethod def tokenize_accents(name_str): for sym in LatexPrinter.accent_keys: if name_str.find(sym) > -1: - keystr = '#'+str(LatexPrinter.accent_cnt)+'#' + keystr = '#' + str(LatexPrinter.accent_cnt) + '#' LatexPrinter.accent_cnt += 1 - LatexPrinter.accent_dict[keystr] = '\\'+sym - name_str = name_str.replace(sym,keystr) + LatexPrinter.accent_dict[keystr] = '\\' + sym + name_str = name_str.replace(sym, keystr) return(name_str) @staticmethod @@ -332,8 +307,9 @@ if name_str.find('@') == -1: return(name_str) for token in list(LatexPrinter.greek_dict.keys()): - name_str = name_str.replace(token,'{\\'+LatexPrinter.greek_dict[token]+'}') - LatexPrinter.greek_cnt = 0 + name_str = name_str.replace( + token, '{\\' + LatexPrinter.greek_dict[token] + '}') + LatexPrinter.greek_cnt = 0 LatexPrinter.greek_dict = {} return(name_str) @@ -345,8 +321,9 @@ return(name_str) for x in tmp_lst[1:]: if x != '': - name_str = '{}'+LatexPrinter.accent_dict['#'+x+'#']+'{'+name_str+'}' - LatexPrinter.accent_cnt = 0 + name_str = '{}' + LatexPrinter.accent_dict[ + '#' + x + '#'] + '{' + name_str + '}' + LatexPrinter.accent_cnt = 0 LatexPrinter.accent_dict = {} return(name_str) @@ -362,18 +339,18 @@ imode = 0 for x in tmp_lst[1:]: if x == '': - imode = (imode+1)%2 + imode = (imode + 1) % 2 else: - subsup_str += LatexPrinter.mode[imode]+'{'+x+'}' + subsup_str += LatexPrinter.mode[imode] + '{' + x + '}' #subsup_str += LatexPrinter.mode[imode]+x+' ' - imode = (imode+1)%2 - name_str = sym_str+subsup_str + imode = (imode + 1) % 2 + name_str = sym_str + subsup_str name_str = LatexPrinter.replace_greek_tokens(name_str) return(name_str) - def coefficient(self,coef,first_flg): + def coefficient(self, coef, first_flg): if isinstance(coef, C.AssocOp) and isinstance(-coef, C.AssocOp): - coef_str = r"\lp %s\rp " % self._print(coef) + coef_str = r"\lp %s\rp " % self._print(coef) else: coef_str = self._print(coef) if first_flg: @@ -383,15 +360,15 @@ else: if coef_str[0] != '-': if coef_str[0] != '+': - coef_str = '+'+coef_str - if coef_str in ('1','+1','-1'): + coef_str = '+' + coef_str + if coef_str in ('1', '+1', '-1'): if coef_str == '1': coef_str = '' else: coef_str = coef_str[0] - return(coef_str,first_flg) + return(coef_str, first_flg) - def __init__(self,inline=True): + def __init__(self, inline=True): Printer.__init__(self) self._inline = inline @@ -527,7 +504,8 @@ if LatexPrinter.fmt_dict['pdiff'] == 1: tex = r'\partial_{%s}' % self._print(expr.variables[0]) else: - tex = r"\frac{\partial}{\partial %s}" % self._print(expr.variables[0]) + tex = r"\frac{\partial}{\partial %s}" % self._print( + expr.variables[0]) else: multiplicity, i, tex = [], 1, "" current = expr.variables[0] @@ -599,9 +577,11 @@ if func in LatexPrinter.fct_dict_keys: if exp is not None: if func in accepted_latex_functions: - name = r"\%s^{%s}" % (LatexPrinter.fct_dict[func], exp) + name = r"\%s^{%s}" % ( + LatexPrinter.fct_dict[func], exp) else: - name = r"\operatorname{%s}^{%s}" % (LatexPrinter.fct_dict[func], exp) + name = r"\operatorname{%s}^{%s}" % ( + LatexPrinter.fct_dict[func], exp) else: if LatexPrinter.fct_dict[func] in accepted_latex_functions: name = r"\%s" % LatexPrinter.fct_dict[func] @@ -701,6 +681,18 @@ else: return tex + def _print_factorial(self, expr, exp=None): + x = expr.args[0] + if self._needs_brackets(x): + tex = r"!\left(%s\right)" % self._print(x) + else: + tex = "!" + self._print(x) + + if exp is not None: + return r"%s^{%s}" % (tex, exp) + else: + return tex + def _print_binomial(self, expr, exp=None): tex = r"{{%s}\choose{%s}}" % (self._print(expr[0]), self._print(expr[1])) @@ -771,19 +763,20 @@ return(name_str) #convert trailing digits to subscript - m = regrep.match('(^[a-zA-Z]+)([0-9]+)$',name_str) + m = regrep.match('(^[a-zA-Z]+)([0-9]+)$', name_str) if m is not None: - name, sub=m.groups() - tex=self._print_Symbol(Symbol(name)) - tex="%s_{%s}" %(tex, sub) + name, sub = m.groups() + tex = self._print_Symbol(Symbol(name)) + tex = "%s_{%s}" % (tex, sub) return tex # insert braces to expresions containing '_' or '^' - m = regrep.match('(^[a-zA-Z0-9]+)([_\^]{1})([a-zA-Z0-9]+)$',name_str) + m = regrep.match( + '(^[a-zA-Z0-9]+)([_\^]{1})([a-zA-Z0-9]+)$', name_str) if m is not None: - name, sep, rest=m.groups() - tex=self._print_Symbol(Symbol(name)) - tex="%s%s{%s}" %(tex, sep, rest) + name, sep, rest = m.groups() + tex = self._print_Symbol(Symbol(name)) + tex = "%s%s{%s}" % (tex, sep, rest) return tex greek = set([ 'alpha', 'beta', 'gamma', 'delta', 'epsilon', 'zeta', @@ -804,71 +797,70 @@ def _print_Symbol(self, expr): return LatexPrinter.print_Symbol_name(expr.name) - def _print_str(self,expr): + def _print_str(self, expr): if LatexPrinter.fmt_dict['str'] > 0: - expr = expr.replace('^','{\\wedge}') - expr = expr.replace('|','{\\cdot}') - expr = expr.replace('__','^') + expr = expr.replace('^', '{\\wedge}') + expr = expr.replace('|', '{\\cdot}') + expr = expr.replace('__', '^') return(expr) - def _print_ndarray(self,expr): + def _print_ndarray(self, expr): shape = numpy.shape(expr) ndim = len(shape) expr_str = '' if ndim == 1: - expr_str += '#\\left [ \\begin{array}{'+shape[0]*'c'+'} \n' + expr_str += '#\\left [ \\begin{array}{' + shape[0]*'c' + '} \n' for col in expr: - expr_str += self._print(col)+' & ' - expr_str = expr_str[:-2]+'\n\\end{array}\\right ]#\n' + expr_str += self._print(col) + ' & ' + expr_str = expr_str[:-2] + '\n\\end{array}\\right ]#\n' return(expr_str) if ndim == 2: - expr_str += '#\\left [ \\begin{array}{'+shape[1]*'c'+'} \n' + expr_str += '#\\left [ \\begin{array}{' + shape[1]*'c' + '} \n' for row in expr[:-1]: for xij in row[:-1]: expr_str += self._print(xij) + ' & ' expr_str += self._print(row[-1]) + ' \\\\ \n' for xij in expr[-1][:-1]: expr_str += self._print(xij) + ' & ' - expr_str += self._print(expr[-1][-1]) + '\n \\end{array} \\right ] #\n' + expr_str += self._print( + expr[-1][-1]) + '\n \\end{array} \\right ] #\n' return(expr_str) if ndim == 3: - expr_str = '#\\left \\{ \\begin{array}{'+shape[0]*'c'+'} \n' + expr_str = '#\\left \\{ \\begin{array}{' + shape[0]*'c' + '} \n' for x in expr[:-1]: - xstr = self._print(x).replace('#','') + xstr = self._print(x).replace('#', '') expr_str += xstr + ' , & ' - xstr = self._print(expr[-1]).replace('#','') - expr_str += xstr+'\n\\end{array} \\right \\}#\n' + xstr = self._print(expr[-1]).replace('#', '') + expr_str += xstr + '\n\\end{array} \\right \\}#\n' return(expr_str) - def _print_MV(self,expr): + def _print_MV(self, expr): igrade = 0 MV_str = '' line_lst = [] - first_flg = True for grade in expr.mv: - if type(grade) != int: - if type(grade) != int: - ibase = 0 - for base in grade: - if base != 0: - tmp = Symbol('XYZW') - base_str = str(base*tmp) - if base_str[0] != '-': - base_str = '+'+base_str - base_str = base_str.replace('- ','-') - if base_str[1:5] == 'XYZW': - base_str = base_str.replace('XYZW','') - else: - base_str = base_str.replace('XYZW','1') - MV_str += base_str+\ - LatexPrinter.build_base(igrade,ibase,expr.bladeflg) - if LatexPrinter.fmt_dict['mv'] == 3: - line_lst.append(MV_str) - MV_str = '' - ibase += 1 + if not isinstance(grade, int): + ibase = 0 + for base in grade: + if base != 0: + tmp = Symbol('XYZW') + base_str = str(base*tmp) + if base_str[0] != '-': + base_str = '+' + base_str + base_str = base_str.replace('- ', '-') + if base_str[1:5] == 'XYZW': + base_str = base_str.replace('XYZW', '') + else: + base_str = base_str.replace('XYZW', '1') + MV_str += base_str + LatexPrinter.build_base( + igrade, ibase, expr.bladeflg) + if LatexPrinter.fmt_dict['mv'] == 3: + line_lst.append(MV_str) + MV_str = '' + ibase += 1 if LatexPrinter.fmt_dict['mv'] == 2: if MV_str != '': line_lst.append(MV_str) @@ -885,42 +877,40 @@ MV_str = line_lst[0] n_lines = 0 if LatexPrinter.fmt_dict['mv'] >= 2: - MV_str = '@'+line_lst[0]+' \\\\ \n' + MV_str = '@' + line_lst[0] + ' \\\\ \n' for line in line_lst[1:-1]: - MV_str += '& '+line+' \\\\ \n' - MV_str += '& '+line_lst[-1]+'@\n' + MV_str += '& ' + line + ' \\\\ \n' + MV_str += '& ' + line_lst[-1] + '@\n' if MV_str == '': MV_str = '0' if expr.name != '': - MV_str = LatexPrinter.extended_symbol(expr.name)+' = '+MV_str + MV_str = LatexPrinter.extended_symbol(expr.name) + ' = ' + MV_str return(MV_str) - def _print_OMV(self,expr): + def _print_OMV(self, expr): igrade = 0 MV_str = '' line_lst = [] - first_flg = True for grade in expr.mv: - if type(grade) is not None: - if type(grade) is not None: - ibase = 0 - for base in grade: - if base != 0: - tmp = Symbol('XYZW') - base_str = str(base*tmp) - if base_str[0] != '-': - base_str = '+'+base_str - base_str = base_str.replace('- ','-') - if base_str[1:5] == 'XYZW': - base_str = base_str.replace('XYZW','') - else: - base_str = base_str.replace('XYZW','1') - MV_str += base_str+\ - LatexPrinter.build_base(igrade,ibase,expr.bladeflg) - if LatexPrinter.fmt_dict['mv'] == 3: - line_lst.append(MV_str) - MV_str = '' - ibase += 1 + if not isinstance(grade, None): + ibase = 0 + for base in grade: + if base != 0: + tmp = Symbol('XYZW') + base_str = str(base*tmp) + if base_str[0] != '-': + base_str = '+' + base_str + base_str = base_str.replace('- ', '-') + if base_str[1:5] == 'XYZW': + base_str = base_str.replace('XYZW', '') + else: + base_str = base_str.replace('XYZW', '1') + MV_str += base_str + LatexPrinter.build_base( + igrade, ibase, expr.bladeflg) + if LatexPrinter.fmt_dict['mv'] == 3: + line_lst.append(MV_str) + MV_str = '' + ibase += 1 if LatexPrinter.fmt_dict['mv'] == 2: if MV_str != '': line_lst.append(MV_str) @@ -937,22 +927,22 @@ MV_str = line_lst[0] n_lines = 0 if LatexPrinter.fmt_dict['mv'] >= 2: - MV_str = '@'+line_lst[0]+' \\\\ \n' + MV_str = '@' + line_lst[0] + ' \\\\ \n' for line in line_lst[1:-1]: - MV_str += '& '+line+' \\\\ \n' - MV_str += '& '+line_lst[-1]+'@\n' + MV_str += '& ' + line + ' \\\\ \n' + MV_str += '& ' + line_lst[-1] + '@\n' if MV_str == '': MV_str = '0' if expr.name != '': - MV_str = LatexPrinter.extended_symbol(expr.name)+' = '+MV_str + MV_str = LatexPrinter.extended_symbol(expr.name) + ' = ' + MV_str return(MV_str) def _print_Relational(self, expr): charmap = { - "==" : "=", - "<" : "<", - "<=" : r"\leq", - "!=" : r"\neq", + "==": "=", + "<": "<", + "<=": r"\leq", + "!=": r"\neq", } return "%s %s %s" % (self._print(expr.lhs), @@ -961,8 +951,8 @@ def _print_Matrix(self, expr): lines = [] - for line in range(expr.lines): # horrible, should be 'rows' - lines.append(" & ".join([ self._print(i) for i in expr[line,:] ])) + for line in range(expr.lines): # horrible, should be 'rows' + lines.append(" & ".join([ self._print(i) for i in expr[line, :] ])) if self._inline: tex = r"\left(\begin{smallmatrix}%s\end{smallmatrix}\right)" @@ -994,10 +984,11 @@ if len(expr.args) == 1 or expr.args[1] == 0: tex = r"\delta\left(%s\right)" % self._print(expr.args[0]) else: - tex = r"\delta^{\left( %s \right)}\left( %s \right)" % (\ - self._print(expr.args[1]), self._print(expr.args[0])) + tex = r"\delta^{\left( %s \right)}\left( %s \right)" % ( + self._print(expr.args[1]), self._print(expr.args[0])) return tex + def LaTeX(expr, inline=True): """ Convert the given expression to LaTeX representation. @@ -1008,19 +999,20 @@ 'equation*' environment (remember to import 'amsmath'). >>> from sympy import Rational - >>> from sympy.abc import tau, mu + >>> from sympy.abc import tau, mu, x, y + >>> from sympy.galgebra.latex_ex import LaTeX - >>> latex((2*tau)**Rational(7,2)) + >>> LaTeX((2*tau)**Rational(7,2)) '$8 \\\\sqrt{2} \\\\sqrt[7]{\\\\tau}$' - >>> latex((2*mu)**Rational(7,2), inline=False) + >>> LaTeX((2*mu)**Rational(7,2), inline=False) '\\\\begin{equation*}8 \\\\sqrt{2} \\\\sqrt[7]{\\\\mu}\\\\end{equation*}' Besides all Basic based expressions, you can recursively convert Python containers (lists, tuples and dicts) and also SymPy matrices: - >>> latex([2/x, y]) + >>> LaTeX([2/x, y]) '$\\\\begin{bmatrix}\\\\frac{2}{x}, & y\\\\end{bmatrix}$' The extended latex printer will also append the output to a @@ -1030,15 +1022,18 @@ xstr = LatexPrinter(inline).doprint(expr) return (xstr) + def print_LaTeX(expr): """Prints LaTeX representation of the given expression.""" print(LaTeX(expr)) + def Format(fmt='1 1 1 1'): LatexPrinter.format_str(fmt) return -def xdvi(filename='tmplatex.tex',debug=False): + +def xdvi(filename='tmplatex.tex', debug=False): """ Post processes LaTeX output (see comments below), adds preamble and postscript, generates tex file, inputs file to latex, displays resulting @@ -1054,13 +1049,11 @@ array_flg = False eqnarray_flg = False raw_flg = False - nline = len(body_lst) - iline = 0 i = iter(body_lst) line = next(i) while True: - if '$' in line: #Inline math expression(s) + if '$' in line: # Inline math expression(s) if len(line) > 0: line += '\\newline \n' body += line @@ -1069,12 +1062,12 @@ except StopIteration: break - elif '%' in line: #Raw LaTeX input + elif '%' in line: # Raw LaTeX input """ If % in line assume line is beginning of raw LaTeX input and stop post processing """ - line = line.replace('%','') + line = line.replace('%', '') raw_flg = True while raw_flg: if '%' in line: @@ -1083,7 +1076,7 @@ post processing """ raw_flg = False - line = line.replace('%','')+'\n' + line = line.replace('%', '') + '\n' else: line += '\n' line = process_equals(line) @@ -1093,14 +1086,14 @@ except StopIteration: break - elif '#' in line: #Array input + elif '#' in line: # Array input """ If # in line assume line is beginning of array input and contains \begin{array} statement """ - line = line.replace('#','') + line = line.replace('#', '') array_flg = True - line = '\\begin{equation*}\n'+line + line = '\\begin{equation*}\n' + line while array_flg: if '#' in line: """ @@ -1108,7 +1101,7 @@ \end{array} statement """ array_flg = False - line = line.replace('#','') + line = line.replace('#', '') line += '\\end{equation*}\n' else: line += '\n' @@ -1119,14 +1112,14 @@ except StopIteration: break - elif '@' in line: #Align input + elif '@' in line: # Align input """ If @ in line assume line is beginning of align input """ - line = line.replace('@','') - line = line.replace('=','& = ') + line = line.replace('@', '') + line = line.replace('=', '& = ') eqnarray_flg = True - line = '\\begin{align*}\n'+line + line = '\\begin{align*}\n' + line line = process_equals(line) body += line try: @@ -1139,10 +1132,10 @@ If @ in line assume line is end of align input """ eqnarray_flg = False - line = line.replace('@','') + line = line.replace('@', '') line += '\\end{align*}\n' else: - line+'\n' + line + '\n' line = process_equals(line) body += line try: @@ -1151,11 +1144,11 @@ break else: - if '=' in line: #Single line equation - line = '\\begin{equation*}\n'+line+'\n\\end{equation*}' - else: #Text with no math expression(s)unless \ or _ in line + if '=' in line: # Single line equation + line = '\\begin{equation*}\n' + line + '\n\\end{equation*}' + else: # Text with no math expression(s)unless \ or _ in line if '\\' in line or '_' in line or '^' in line: - line = '\\begin{equation*}\n'+line+'\n\\end{equation*}' + line = '\\begin{equation*}\n' + line + '\n\\end{equation*}' else: if len(line) > 0: line += '\\newline \n' @@ -1165,35 +1158,12 @@ line = next(i) except StopIteration: break - body = LatexPrinter.preamble+body+LatexPrinter.postscript - - with open(filename,'w') as latex_file: - latex_file.write(body) - - latex_str = None - xdvi_str = None - - if find_executable('latex') is not None: - latex_str = 'latex' - - if find_executable('xdvi') is not None: - xdvi_str = 'xdvi' - - if find_executable('yap') is not None: - xdvi_str = 'yap' - - if latex_str is not None and xdvi_str is not None: - if debug: #Display latex excution output for debugging purposes - os.system(latex_str+' '+filename[:-4]) - else: #Works for Linux don't know about Windows - if sys.platform.startswith('linux'): - os.system(latex_str+' '+filename[:-4]+' > /dev/null') - else: - os.system(latex_str+' '+filename[:-4]+' > NUL') - os.system(xdvi_str+' '+filename[:-4]+' &') + preview(body, output='dvi', outputTexFile=filename, + preamble=LatexPrinter.preamble) LatexPrinter.LaTeX_flg = False return + def MV_format(mv_fmt): """ 0 or 1 - Print multivector on one line @@ -1206,6 +1176,7 @@ LatexPrinter.fmt_dict['mv'] = mv_fmt return + def fct_format(fct_fmt): """ 0 - Default sympy latex format @@ -1220,6 +1191,7 @@ LatexPrinter.fct = fct_fmt return + def pdiff_format(pdiff_fmt): """ 0 - Use default sympy partial derivative format @@ -1230,6 +1202,7 @@ LatexPrinter.fmt_dict['pdiff'] = pdiff_fmt return + def sym_format(sym_fmt): """ 0 - Use default sympy format @@ -1243,6 +1216,7 @@ LatexPrinter.fmt_dict['sym'] = sym_fmt return + def str_format(str_fmt): """ 0 - Use default sympy format @@ -1256,5 +1230,6 @@ LatexPrinter.fmt_dict['str'] = str_fmt return + def ext_str(xstr): return(LatexPrinter.extended_symbol(xstr)) diff -Nru python3-sympy-0.7.2/sympy/galgebra/tests/test_GA.py python3-sympy-0.7.3/sympy/galgebra/tests/test_GA.py --- python3-sympy-0.7.2/sympy/galgebra/tests/test_GA.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/galgebra/tests/test_GA.py 2013-07-13 17:53:32.000000000 +0000 @@ -16,70 +16,74 @@ from sympy.galgebra.GA import MV, ZERO, HALF, S import sympy + def F(x, n, nbar): """ Conformal Mapping Function from 3D Euclidean space to 5D conformal space where the images of all maps are null vectors. """ - Fx = HALF*((x*x)*n+2*x-nbar) + Fx = HALF*((x*x)*n + 2*x - nbar) #print 'F(x) =',Fx return(Fx) + def test_rmul(): """ Test for commutative scalar multiplication. Leftover from when sympy and numpy were not working together and __mul__ and __rmul__ would not give the same answer. """ - x,y,z = MV.setup('x y z') - a,b,c = sympy.symbols('a b c') + x, y, z = MV.setup('x y z') + a, b, c = sympy.symbols('a b c') assert 5*x == x*5 assert HALF*x == x*HALF assert a*x == x*a + def test_contraction(): """ Test for inner product and left and right contraction """ - e_1,e_2,e_3 = MV.setup('e_1 e_2 e_3','1 0 0, 0 1 0, 0 0 1',offset=1) + e_1, e_2, e_3 = MV.setup('e_1 e_2 e_3', '1 0 0, 0 1 0, 0 0 1', offset=1) + + assert ((e_1 ^ e_3) | e_1) == -e_3 + assert ((e_1 ^ e_3) > e_1) == -e_3 + assert (e_1 | (e_1 ^ e_3)) == e_3 + assert (e_1 < (e_1 ^ e_3)) == e_3 + assert ((e_1 ^ e_3) < e_1) == 0 + assert (e_1 > (e_1 ^ e_3)) == 0 - assert ((e_1^e_3)|e_1) == -e_3 - assert ((e_1^e_3)>e_1) == -e_3 - assert (e_1|(e_1^e_3)) == e_3 - assert (e_1<(e_1^e_3)) == e_3 - assert ((e_1^e_3)(e_1^e_3)) == 0 def test_substitution(): - e_x,e_y,e_z = MV.setup('e_x e_y e_z','1 0 0, 0 1 0, 0 0 1',offset=1) - x,y,z = sympy.symbols('x y z') + e_x, e_y, e_z = MV.setup('e_x e_y e_z', '1 0 0, 0 1 0, 0 0 1', offset=1) + x, y, z = sympy.symbols('x y z') - X = x*e_x+y*e_y+z*e_z - Y = X.subs([(x,2),(y,3),(z,4)]) - assert Y == 2*e_x+3*e_y+4*e_z + X = x*e_x + y*e_y + z*e_z + Y = X.subs([(x, 2), (y, 3), (z, 4)]) + assert Y == 2*e_x + 3*e_y + 4*e_z def test_vector_extraction(): """ Show that conformal bivector encodes two points. See D&L Section 10.4.1 """ - metric = ' 0 -1 #,'+ \ - '-1 0 #,'+ \ + metric = ' 0 -1 #,' + \ + '-1 0 #,' + \ ' # # #,' - P1,P2,a = MV.setup('P1 P2 a',metric) + P1, P2, a = MV.setup('P1 P2 a', metric) """ P1 and P2 are null vectors and hence encode points in conformal space. Show that P1 and P2 can be extracted from the bivector B = P1^P2. a is a third vector in the conformal space with a.B not 0. """ - B = P1^P2 + B = P1 ^ P2 Bsq = B*B - ap = a-(a^B)*B - Ap = ap+ap*B - Am = ap-ap*B + ap = a - (a ^ B)*B + Ap = ap + ap*B + Am = ap - ap*B P1dota = sympy.Symbol('(P1.a)') P2dota = sympy.Symbol('(P2.a)') Ap_test = (-2*P2dota)*P1 @@ -97,91 +101,132 @@ assert Ap2 == ZERO assert Am2 == ZERO +def test_metrics(): + """ + Test specific metrics (diagpq, arbitrary_metric, arbitrary_metric_conformal) + """ + from sympy.galgebra.GA import diagpq, arbitrary_metric, arbitrary_metric_conformal + metric = diagpq(3) + p1, p2, p3 = MV.setup('p1 p2 p3', metric, debug=0) + MV.set_str_format(1) + x1, y1, z1 = sympy.symbols('x1 y1 z1') + x2, y2, z2 = sympy.symbols('x2 y2 z2') + v1 = x1*p1 + y1*p2 + z1*p3 + v2 = x2*p1 + y2*p2 + z2*p3 + prod1 = v1*v2 + prod2 = (v1|v2) + (v1^v2) + diff = prod1 - prod2 + diff.compact() + assert diff == ZERO + metric = arbitrary_metric(3) + p1, p2, p3 = MV.setup('p1 p2 p3', metric, debug=0) + v1 = x1*p1 + y1*p2 + z1*p3 + v2 = x2*p1 + y2*p2 + z2*p3 + prod1 = v1*v2 + prod2 = (v1|v2) + (v1^v2) + diff = prod1 - prod2 + diff.compact() + assert diff == ZERO + metric = arbitrary_metric_conformal(3) + p1, p2, p3 = MV.setup('p1 p2 p3', metric, debug=0) + v1 = x1*p1 + y1*p2 + z1*p3 + v2 = x2*p1 + y2*p2 + z2*p3 + prod1 = v1*v2 + prod2 = (v1|v2) + (v1^v2) + diff = prod1 - prod2 + diff.compact() + assert diff == ZERO + def test_geometry(): """ Test conformal geometric description of circles, lines, spheres, and planes. """ - metric = '1 0 0 0 0,'+ \ - '0 1 0 0 0,'+ \ - '0 0 1 0 0,'+ \ - '0 0 0 0 2,'+ \ + metric = '1 0 0 0 0,' + \ + '0 1 0 0 0,' + \ + '0 0 1 0 0,' + \ + '0 0 0 0 2,' + \ '0 0 0 2 0' - e0,e1,e2,n,nbar = MV.setup('e0 e1 e2 n nbar',metric,debug=0) - e = n+nbar + e0, e1, e2, n, nbar = MV.setup('e0 e1 e2 n nbar', metric, debug=0) + e = n + nbar #conformal representation of points - A = F(e0,n,nbar) # point a = (1,0,0) A = F(a) - B = F(e1,n,nbar) # point b = (0,1,0) B = F(b) - C = F(-1*e0,n,nbar) # point c = (-1,0,0) C = F(c) - D = F(e2,n,nbar) # point d = (0,0,1) D = F(d) - x0,x1,x2 = sympy.symbols('x0 x1 x2') - X = F(MV([x0,x1,x2],'vector'),n,nbar) - - Circle = A^B^C^X - Line = A^B^n^X - Sphere = A^B^C^D^X - Plane = A^B^n^D^X + A = F(e0, n, nbar) # point a = (1,0,0) A = F(a) + B = F(e1, n, nbar) # point b = (0,1,0) B = F(b) + C = F(-1*e0, n, nbar) # point c = (-1,0,0) C = F(c) + D = F(e2, n, nbar) # point d = (0,0,1) D = F(d) + x0, x1, x2 = sympy.symbols('x0 x1 x2') + X = F(MV([x0, x1, x2], 'vector'), n, nbar) + + Circle = A ^ B ^ C ^ X + Line = A ^ B ^ n ^ X + Sphere = A ^ B ^ C ^ D ^ X + Plane = A ^ B ^ n ^ D ^ X #Circle through a, b, and c - Circle_test = -x2*(e0^e1^e2^n)+x2*(e0^e1^e2^nbar)+HALF*(-1+x0**2+x1**2+x2**2)*(e0^e1^n^nbar) - diff = Circle-Circle_test + Circle_test = -x2*(e0 ^ e1 ^ e2 ^ n) + x2*( + e0 ^ e1 ^ e2 ^ nbar) + HALF*(-1 + x0**2 + x1**2 + x2**2)*(e0 ^ e1 ^ n ^ nbar) + diff = Circle - Circle_test diff.compact() assert diff == ZERO #Line through a and b - Line_test = -x2*(e0^e1^e2^n)+HALF*(-1+x0+x1)*(e0^e1^n^nbar)+(HALF*x2)*(e0^e2^n^nbar)+\ - (-HALF*x2)*(e1^e2^n^nbar) - diff = Line-Line_test + Line_test = -x2*(e0 ^ e1 ^ e2 ^ n) + \ + HALF*(-1 + x0 + x1)*(e0 ^ e1 ^ n ^ nbar) + \ + (HALF*x2)*(e0 ^ e2 ^ n ^ nbar) + \ + (-HALF*x2)*(e1 ^ e2 ^ n ^ nbar) + diff = Line - Line_test diff.compact() assert diff == ZERO #Sphere through a, b, c, and d - Sphere_test = HALF*(1-x0**2-x1**2-x2**2)*(e0^e1^e2^n^nbar) - diff = Sphere-Sphere_test + Sphere_test = HALF*(1 - x0**2 - x1**2 - x2**2)*(e0 ^ e1 ^ e2 ^ n ^ nbar) + diff = Sphere - Sphere_test diff.compact() assert diff == ZERO #Plane through a, b, and d - Plane_test = HALF*(1-x0-x1-x2)*(e0^e1^e2^n^nbar) - diff = Plane-Plane_test + Plane_test = HALF*(1 - x0 - x1 - x2)*(e0 ^ e1 ^ e2 ^ n ^ nbar) + diff = Plane - Plane_test diff.compact() assert diff == ZERO + def test_extract_plane_and_line(): """ Show that conformal trivector encodes planes and lines. See D&L section 10.4.2 """ - metric = '# # # 0 0,'+ \ - '# # # 0 0,'+ \ - '# # # 0 0,'+ \ - '0 0 0 0 2,'+ \ + metric = '# # # 0 0,' + \ + '# # # 0 0,' + \ + '# # # 0 0,' + \ + '0 0 0 0 2,' + \ '0 0 0 2 0' - p1,p2,p3,n,nbar = MV.setup('p1 p2 p3 n nbar',metric,debug=0) + p1, p2, p3, n, nbar = MV.setup('p1 p2 p3 n nbar', metric, debug=0) MV.set_str_format(1) - P1 = F(p1,n,nbar) - P2 = F(p2,n,nbar) - P3 = F(p3,n,nbar) + P1 = F(p1, n, nbar) + P2 = F(p2, n, nbar) + P3 = F(p3, n, nbar) #Line through p1 and p2 - L = P1^P2^n - delta = (L|n)|nbar - delta_test = 2*p1-2*p2 - diff = delta-delta_test + L = P1 ^ P2 ^ n + delta = (L | n) | nbar + delta_test = 2*p1 - 2*p2 + diff = delta - delta_test diff.compact() assert diff == ZERO #Plane through p1, p2, and p3 - C = P1^P2^P3 - delta = ((C^n)|n)|nbar - delta_test = 2*(p1^p2)-2*(p1^p3)+2*(p2^p3) - diff = delta-delta_test + C = P1 ^ P2 ^ P3 + delta = ((C ^ n) | n) | nbar + delta_test = 2*(p1 ^ p2) - 2*(p1 ^ p3) + 2*(p2 ^ p3) + diff = delta - delta_test diff.compact() assert diff == ZERO + def test_reciprocal_frame(): """ Test of formula for general reciprocal frame of three vectors. @@ -190,92 +235,98 @@ e_i.E_j = delta_ij*(e1^e2^e3)**2 """ - metric = '1 # #,'+ \ - '# 1 #,'+ \ + metric = '1 # #,' + \ + '# 1 #,' + \ '# # 1,' - e1,e2,e3 = MV.setup('e1 e2 e3',metric) - E = e1^e2^e3 + e1, e2, e3 = MV.setup('e1 e2 e3', metric) + E = e1 ^ e2 ^ e3 Esq = (E*E)() Esq_inv = 1/Esq - E1 = (e2^e3)*E - E2 = (-1)*(e1^e3)*E - E3 = (e1^e2)*E - w = (E1|e2) + E1 = (e2 ^ e3)*E + E2 = (-1)*(e1 ^ e3)*E + E3 = (e1 ^ e2)*E + w = (E1 | e2) w.collect(MV.g) w = w().expand() - w = (E1|e3) + w = (E1 | e3) w.collect(MV.g) w = w().expand() assert w == 0 - w = (E2|e1) + w = (E2 | e1) w.collect(MV.g) w = w().expand() assert w == 0 - w = (E2|e3) + w = (E2 | e3) w.collect(MV.g) w = w().expand() assert w == 0 - w = (E3|e1) + w = (E3 | e1) w.collect(MV.g) w = w().expand() assert w == 0 - w = (E3|e2) + w = (E3 | e2) w.collect(MV.g) w = w().expand() assert w == 0 - w = (E1|e1) + w = (E1 | e1) w = w().expand() Esq = Esq.expand() assert w/Esq == 1 - w = (E2|e2) + w = (E2 | e2) w = w().expand() assert w/Esq == 1 - w = (E3|e3) + w = (E3 | e3) w = w().expand() assert w/Esq == 1 + def test_derivative(): - coords = x,y,z = sympy.symbols('x y z') - e_x,e_y,e_z = MV.setup('e','1 0 0, 0 1 0, 0 0 1',coords=coords) - X = x*e_x+y*e_y+z*e_z - a = MV('a','vector') + coords = x, y, z = sympy.symbols('x y z') + e_x, e_y, e_z = MV.setup('e', '1 0 0, 0 1 0, 0 0 1', coords=coords) + X = x*e_x + y*e_y + z*e_z + a = MV('a', 'vector') - assert ((X|a).grad()) == a + assert ((X | a).grad()) == a assert ((X*X).grad()) == 2*X assert (X*X*X).grad() == 5*X*X assert X.grad_int() == 3 + def test_str(): - e_1,e_2,e_3 = MV.setup('e_1 e_2 e_3','1 0 0, 0 1 0, 0 0 1') + e_1, e_2, e_3 = MV.setup('e_1 e_2 e_3', '1 0 0, 0 1 0, 0 0 1') X = MV('x') assert str(X) == 'x+x__0*e_1+x__1*e_2+x__2*e_3+x__01*e_1e_2+x__02*e_1e_3+x__12*e_2e_3+x__012*e_1e_2e_3' - Y = MV('y','spinor') + Y = MV('y', 'spinor') assert str(Y) == 'y+y__01*e_1e_2+y__02*e_1e_3+y__12*e_2e_3' - Z = X+Y + Z = X + Y assert str(Z) == 'x+y+x__0*e_1+x__1*e_2+x__2*e_3+(x__01+y__01)*e_1e_2+(x__02+y__02)*e_1e_3+(x__12+y__12)*e_2e_3+x__012*e_1e_2e_3' - assert str(e_1|e_1) == '1' + assert str(e_1 | e_1) == '1' + def test_metric(): - MV.setup('e_1 e_2 e_3','[1,1,1]') + MV.setup('e_1 e_2 e_3', '[1,1,1]') assert str(MV.metric) == '[[1 0 0]\n [0 1 0]\n [0 0 1]]' + def test_constructor(): """ Test various multivector constructors """ - e_1,e_2,e_3 = MV.setup('e_1 e_2 e_3','[1,1,1]') + e_1, e_2, e_3 = MV.setup('e_1 e_2 e_3', '[1,1,1]') x = sympy.symbols('x') assert str(S(1)) == '1' assert str(S(x)) == 'x' - assert str(MV('a','scalar')) == 'a' - assert str(MV('a','vector')) == 'a__0*e_1+a__1*e_2+a__2*e_3' - assert str(MV('a','pseudo')) == 'a*e_1e_2e_3' - assert str(MV('a','spinor')) == 'a+a__01*e_1e_2+a__02*e_1e_3+a__12*e_2e_3' + assert str(MV('a', 'scalar')) == 'a' + assert str(MV('a', 'vector')) == 'a__0*e_1+a__1*e_2+a__2*e_3' + assert str(MV('a', 'pseudo')) == 'a*e_1e_2e_3' + assert str(MV('a', 'spinor')) == 'a+a__01*e_1e_2+a__02*e_1e_3+a__12*e_2e_3' assert str(MV('a')) == 'a+a__0*e_1+a__1*e_2+a__2*e_3+a__01*e_1e_2+a__02*e_1e_3+a__12*e_2e_3+a__012*e_1e_2e_3' - assert str(MV([2,'a'],'grade')) == 'a__01*e_1e_2+a__02*e_1e_3+a__12*e_2e_3' - assert str(MV('a','grade2')) == 'a__01*e_1e_2+a__02*e_1e_3+a__12*e_2e_3' + assert str( + MV([2, 'a'], 'grade')) == 'a__01*e_1e_2+a__02*e_1e_3+a__12*e_2e_3' + assert str(MV('a', 'grade2')) == 'a__01*e_1e_2+a__02*e_1e_3+a__12*e_2e_3' + def test__print_Mul_Add(): from sympy.galgebra.latex_ex import LatexPrinter diff -Nru python3-sympy-0.7.2/sympy/geometry/__init__.py python3-sympy-0.7.3/sympy/geometry/__init__.py --- python3-sympy-0.7.2/sympy/geometry/__init__.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/geometry/__init__.py 2013-07-13 17:53:32.000000000 +0000 @@ -20,6 +20,7 @@ from sympy.geometry.line import Line, Ray, Segment from sympy.geometry.ellipse import Ellipse, Circle from sympy.geometry.polygon import Polygon, RegularPolygon, Triangle, rad, deg -from sympy.geometry.util import * -from sympy.geometry.exceptions import * +from sympy.geometry.util import are_similar, centroid, convex_hull, idiff, \ + intersection +from sympy.geometry.exceptions import GeometryError from sympy.geometry.curve import Curve diff -Nru python3-sympy-0.7.2/sympy/geometry/curve.py python3-sympy-0.7.3/sympy/geometry/curve.py --- python3-sympy-0.7.2/sympy/geometry/curve.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/geometry/curve.py 2013-07-13 17:53:32.000000000 +0000 @@ -45,12 +45,13 @@ ======== sympy.core.function.Function + sympy.polys.polyfuncs.interpolate Examples ======== - >>> from sympy import sin, cos, Symbol - >>> from sympy.abc import t + >>> from sympy import sin, cos, Symbol, interpolate + >>> from sympy.abc import t, a >>> from sympy.geometry import Curve >>> C = Curve((sin(t), cos(t)), (t, 0, 2)) >>> C.functions @@ -59,15 +60,23 @@ (t, 0, 2) >>> C.parameter t - + >>> C = Curve((t, interpolate([1, 4, 9, 16], t)), (t, 0, 1)); C + Curve((t, t**2), (t, 0, 1)) + >>> C.subs(t, 4) + Point(4, 16) + >>> C.arbitrary_point(a) + Point(a, a**2) """ def __new__(cls, function, limits): fun = sympify(function) if not is_sequence(fun) or len(fun) != 2: - raise ValueError("Function argument should be (x(t), y(t)) but got %s" % str(function)) + raise ValueError("Function argument should be (x(t), y(t)) " + "but got %s" % str(function)) if not is_sequence(limits) or len(limits) != 3: - raise ValueError("Limit argument should be (t, tmin, tmax) but got %s" % str(limits)) + raise ValueError("Limit argument should be (t, tmin, tmax) " + "but got %s" % str(limits)) + return GeometryEntity.__new__(cls, Tuple(*fun), Tuple(*limits)) def _eval_subs(self, old, new): @@ -77,7 +86,8 @@ @property def free_symbols(self): """ - Return a set of symbols other than the bound symbols used to parametrically define the Curve. + Return a set of symbols other than the bound symbols used to + parametrically define the Curve. Examples ======== @@ -187,7 +197,7 @@ >>> Curve((x, x), (x, 0, 1)).rotate(pi/2) Curve((-x, x), (x, 0, 1)) """ - from sympy.matrices.matrices import Matrix, rot_axis3 + from sympy.matrices import Matrix, rot_axis3 pt = -Point(pt or (0, 0)) rv = self.translate(*pt.args) f = list(rv.functions) @@ -281,8 +291,10 @@ tnew = _symbol(parameter, self.parameter) t = self.parameter - if tnew.name != t.name and tnew.name in (f.name for f in self.free_symbols): - raise ValueError('Symbol %s already appears in object and cannot be used as a parameter.' % tnew.name) + if (tnew.name != t.name and + tnew.name in (f.name for f in self.free_symbols)): + raise ValueError('Symbol %s already appears in object ' + 'and cannot be used as a parameter.' % tnew.name) return Point(*[w.subs(t, tnew) for w in self.functions]) def plot_interval(self, parameter='t'): diff -Nru python3-sympy-0.7.2/sympy/geometry/ellipse.py python3-sympy-0.7.3/sympy/geometry/ellipse.py --- python3-sympy-0.7.2/sympy/geometry/ellipse.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/geometry/ellipse.py 2013-07-13 17:53:32.000000000 +0000 @@ -8,6 +8,7 @@ from sympy.core import S, C, sympify, pi, Dummy from sympy.core.logic import fuzzy_bool +from sympy.core.numbers import oo from sympy.simplify import simplify, trigsimp from sympy.functions.elementary.miscellaneous import sqrt, Max, Min from sympy.functions.elementary.complexes import im @@ -20,6 +21,9 @@ import random +from sympy.utilities.decorator import doctest_depends_on, no_attrs_in_subclass + + class Ellipse(GeometryEntity): """An elliptical GeometryEntity. @@ -86,13 +90,14 @@ Plotting: - >>> from sympy import Circle, Plot, Segment + >>> from sympy.plotting.pygletplot import PygletPlot as Plot + >>> from sympy import Circle, Segment >>> c1 = Circle(Point(0,0), 1) >>> Plot(c1) # doctest: +SKIP [0]: cos(t), sin(t), 'mode=parametric' >>> p = Plot() # doctest: +SKIP >>> p[0] = c1 # doctest: +SKIP - >>> radius = Segment(c1.center, c1.random_point()) # doctest: +SKIP + >>> radius = Segment(c1.center, c1.random_point()) >>> p[1] = radius # doctest: +SKIP >>> p # doctest: +SKIP [0]: cos(t), sin(t), 'mode=parametric' @@ -100,9 +105,11 @@ t*sin(1.546086215036205357975518382), 'mode=parametric' """ + _doctest_depends_on = {'modules': ('numpy', 'matplotlib')} - def __new__(cls, center=None, hradius=None, vradius=None, eccentricity=None, - **kwargs): + def __new__( + cls, center=None, hradius=None, vradius=None, eccentricity=None, + **kwargs): hradius = sympify(hradius) vradius = sympify(vradius) @@ -114,7 +121,7 @@ center = Point(center) if len([_f for _f in (hradius, vradius, eccentricity) if _f]) != 2: - raise ValueError('Exactly two arguments of "hradius", '\ + raise ValueError('Exactly two arguments of "hradius", ' '"vradius", and "eccentricity" must not be None."') if eccentricity is not None: @@ -288,7 +295,6 @@ return self.hradius return rv - @property def area(self): """The area of the ellipse. @@ -328,9 +334,8 @@ return 2*pi*self.hradius else: x = C.Dummy('x', real=True) - return 4*self.major*\ - C.Integral(sqrt((1 - (self.eccentricity*x)**2)/(1 - x**2)), - (x, 0, 1)) + return 4*self.major*C.Integral( + sqrt((1 - (self.eccentricity*x)**2)/(1 - x**2)), (x, 0, 1)) @property def eccentricity(self): @@ -518,6 +523,23 @@ v = self.vradius return self.func(c.scale(x, y), hradius=h*x, vradius=v*y) + def reflect(self, line): + """Override GeometryEntity.reflect since the radius + is not a GeometryEntity. + + Examples + ======== + + >>> from sympy import Circle, Line + >>> Circle((0, 1), 1).reflect(Line((0, 0), (1, 1))) + Circle(Point(1, 0), -1) + """ + if line.slope in (0, oo): + c = self.center + c = c.reflect(line) + return self.func(c, -self.hradius, self.vradius) + raise NotImplementedError('reflection line not horizontal | vertical.') + def encloses_point(self, p): """ Return True if p is enclosed by (is inside of) self. @@ -571,6 +593,7 @@ return fuzzy_bool(test.is_positive) + @doctest_depends_on(modules=('pyglet',)) def tangent_lines(self, p): """Tangent lines between `p` and the ellipse. @@ -608,10 +631,11 @@ [Line(Point(3, 0), Point(3, -12))] >>> # This will plot an ellipse together with a tangent line. - >>> from sympy import Point, Ellipse, Plot + >>> from sympy.plotting.pygletplot import PygletPlot as Plot + >>> from sympy import Point, Ellipse >>> e = Ellipse(Point(0,0), 3, 2) - >>> t = e.tangent_lines(e.random_point()) # doctest: +SKIP - >>> p = Plot() # doctest: +SKIP + >>> t = e.tangent_lines(e.random_point()) + >>> p = Plot() >>> p[0] = e # doctest: +SKIP >>> p[1] = t # doctest: +SKIP @@ -648,7 +672,8 @@ # handle horizontal and vertical tangent lines if len(tangent_points) == 1: - assert tangent_points[0][0] == p.x or tangent_points[0][1] == p.y + assert tangent_points[0][ + 0] == p.x or tangent_points[0][1] == p.y return [Line(p, p + Point(1, 0)), Line(p, p + Point(0, 1))] # others @@ -841,7 +866,7 @@ valid point is obtained. """ - from sympy import nsimplify, sin, cos + from sympy import sin, cos, Rational t = _symbol('t') x, y = self.arbitrary_point(t).args # get a random value in [-1, 1) corresponding to cos(t) @@ -850,13 +875,15 @@ rng = random.Random(seed) else: rng = random - for i in range(10): # should be enough? - c = nsimplify(2*rng.random() - 1) + for i in range(10): # should be enough? + # simplify this now or else the Float will turn s into a Float + c = 2*Rational(rng.random()) - 1 s = sqrt(1 - c**2) p1 = Point(x.subs(cos(t), c), y.subs(sin(t), s)) if p1 in self: return p1 - raise GeometryError('Having problems generating a point in the ellipse.') + raise GeometryError( + 'Having problems generating a point in the ellipse.') def equation(self, x='x', y='y'): """The equation of the ellipse. @@ -915,7 +942,7 @@ a = ldir.dot(mdir) b = ldir.dot(mdiff) c = diff.dot(mdiff) - 1 - det = simplify(b*b - a*c); + det = simplify(b*b - a*c) result = [] if det == 0: @@ -925,7 +952,7 @@ is_good = True try: is_good = (det > 0) - except NotImplementedError: #symbolic, allow + except NotImplementedError: # symbolic, allow is_good = True if is_good: @@ -1069,6 +1096,9 @@ elif isinstance(o, Ellipse): return self == o return False +# once py2.5 support gets dropped replace this with a class decorator +Ellipse._doctest_depends_on = no_attrs_in_subclass( + Ellipse, Ellipse._doctest_depends_on) class Circle(Ellipse): @@ -1118,12 +1148,14 @@ (sqrt(2)/2, sqrt(2)/2, sqrt(2)/2, Point(1/2, 1/2)) """ + def __new__(cls, *args, **kwargs): c, r = None, None if len(args) == 3: args = [Point(a) for a in args] if Point.is_collinear(*args): - raise GeometryError("Cannot construct a circle from three collinear points") + raise GeometryError( + "Cannot construct a circle from three collinear points") from .polygon import Triangle t = Triangle(*args) c = t.circumcenter @@ -1169,7 +1201,10 @@ This Ellipse property is an alias for the Circle's radius. Whereas hradius, major and minor can use Ellipse's conventions, - the vradius does not exist for a circle. + the vradius does not exist for a circle. It is always a positive + value in order that the Circle, like Polygons, will have an + area that can be positive or negative as determined by the sign + of the hradius. Examples ======== @@ -1179,7 +1214,7 @@ >>> c1.vradius 6 """ - return self.radius + return abs(self.radius) @property def circumference(self): @@ -1312,10 +1347,26 @@ pt = Point(pt) return self.translate(*(-pt).args).scale(x, y).translate(*pt.args) c = c.scale(x, y) + x, y = [abs(i) for i in (x, y)] if x == y: return self.func(c, x*self.radius) h = v = self.radius return Ellipse(c, hradius=h*x, vradius=v*y) + def reflect(self, line): + """Override GeometryEntity.reflect since the radius + is not a GeometryEntity. + + Examples + ======== + + >>> from sympy import Circle, Line + >>> Circle((0, 1), 1).reflect(Line((0, 0), (1, 1))) + Circle(Point(1, 0), -1) + """ + c = self.center + c = c.reflect(line) + return self.func(c, -self.radius) + from .polygon import Polygon diff -Nru python3-sympy-0.7.2/sympy/geometry/entity.py python3-sympy-0.7.3/sympy/geometry/entity.py --- python3-sympy-0.7.2/sympy/geometry/entity.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/geometry/entity.py 2013-07-13 17:53:32.000000000 +0000 @@ -11,7 +11,7 @@ from sympy.core.basic import Basic from sympy.core.sympify import sympify from sympy.functions import cos, sin -from sympy.matrices.matrices import eye +from sympy.matrices import eye # How entities are ordered; used by __cmp__ in GeometryEntity ordering_of_classes = [ @@ -27,6 +27,7 @@ "Curve" ] + class GeometryEntity(Basic): """The base class for all geometrical entities. @@ -36,7 +37,8 @@ """ def __new__(cls, *args, **kwargs): - return Basic.__new__(cls, *sympify(args)) + args = list(map(sympify, args)) + return Basic.__new__(cls, *args) def _sympy_(self): return self @@ -122,7 +124,7 @@ if pt: pt = Point(pt) return self.translate(*(-pt).args).scale(x, y).translate(*pt.args) - return type(self)(*[a.scale(x, y) for a in self.args]) # if this fails, override this class + return type(self)(*[a.scale(x, y) for a in self.args]) # if this fails, override this class def translate(self, x=0, y=0): """Shift the object by adding to the x,y-coordinates the values x and y. @@ -142,7 +144,8 @@ >>> t.translate(2) Triangle(Point(3, 0), Point(3/2, sqrt(3)/2), Point(3/2, -sqrt(3)/2)) >>> t.translate(2, 2) - Triangle(Point(3, 2), Point(3/2, sqrt(3)/2 + 2), Point(3/2, -sqrt(3)/2 + 2)) + Triangle(Point(3, 2), Point(3/2, sqrt(3)/2 + 2), + Point(3/2, -sqrt(3)/2 + 2)) """ newargs = [] @@ -151,7 +154,40 @@ newargs.append(a.translate(x, y)) else: newargs.append(a) - return type(self)(*newargs) + return self.func(*newargs) + + def reflect(self, line): + from sympy import atan, Line, Point, Dummy, oo + + g = self + l = line + o = Point(0, 0) + if l.slope == 0: + y = l.args[0].y + if not y: # x-axis + return g.scale(y=-1) + reps = [(p, p.translate(y=2*(y - p.y))) for p in g.atoms(Point)] + elif l.slope == oo: + x = l.args[0].x + if not x: # y-axis + return g.scale(x=-1) + reps = [(p, p.translate(x=2*(x - p.x))) for p in g.atoms(Point)] + else: + if not hasattr(g, 'reflect') and not all( + isinstance(arg, Point) for arg in g.args): + raise NotImplementedError( + 'reflect undefined or non-Point args in %s' % g) + a = atan(l.slope) + c = l.coefficients + d = -c[-1]/c[1] # y-intercept + # apply the transform to a single point + x, y = Dummy(), Dummy() + xf = Point(x, y) + xf = xf.translate(y=-d).rotate(-a, o).scale(y=-1 + ).rotate(a, o).translate(y=d) + # replace every point using that transform + reps = [(p, xf.xreplace({x: p.x, y: p.y})) for p in g.atoms(Point)] + return g.xreplace(dict(reps)) def encloses(self, o): """ @@ -289,6 +325,7 @@ new = Point(new) return self._subs(old, new) + def translate(x, y): """Return the matrix to translate a 2-D point by x and y.""" rv = eye(3) @@ -296,6 +333,7 @@ rv[2, 1] = y return rv + def scale(x, y, pt=None): """Return the matrix to multiply a 2-D point's coordinates by x and y. @@ -311,6 +349,7 @@ return tr1*rv*tr2 return rv + def rotate(th): """Return the matrix to rotate a 2-D point about the origin by ``angle``. diff -Nru python3-sympy-0.7.2/sympy/geometry/exceptions.py python3-sympy-0.7.3/sympy/geometry/exceptions.py --- python3-sympy-0.7.2/sympy/geometry/exceptions.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/geometry/exceptions.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,5 +1,6 @@ """Geometry Errors.""" + class GeometryError(ValueError): """An exception raised by classes in the geometry module.""" pass diff -Nru python3-sympy-0.7.2/sympy/geometry/line.py python3-sympy-0.7.3/sympy/geometry/line.py --- python3-sympy-0.7.2/sympy/geometry/line.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/geometry/line.py 2013-07-13 17:53:32.000000000 +0000 @@ -11,7 +11,7 @@ from sympy.core import S, C, sympify, Dummy from sympy.functions.elementary.trigonometric import _pi_coeff as pi_coeff from sympy.core.logic import fuzzy_and -from sympy.simplify import simplify +from sympy.simplify.simplify import simplify from sympy.solvers import solve from sympy.geometry.exceptions import GeometryError from .entity import GeometryEntity @@ -19,9 +19,12 @@ from .util import _symbol # TODO: this should be placed elsewhere and reused in other modules + + class Undecidable(ValueError): pass + class LinearEntity(GeometryEntity): """An abstract base class for all linear entities (line, ray and segment) in a 2-dimensional Euclidean space. @@ -56,7 +59,7 @@ p2 = Point(p2) if p1 == p2: # Rolygon returns lower priority classes...should LinearEntity, too? - return p1 # raise ValueError("%s.__new__ requires two unique Points." % cls.__name__) + return p1 # raise ValueError("%s.__new__ requires two unique Points." % cls.__name__) return GeometryEntity.__new__(cls, p1, p2, **kwargs) @@ -401,8 +404,8 @@ """ d1, d2 = (self.p1 - self.p2).args - if d2 == 0: # If a horizontal line - if p.y == self.p1.y: # if p is on this linear entity + if d2 == 0: # If a horizontal line + if p.y == self.p1.y: # if p is on this linear entity return Line(p, p + Point(0, 1)) else: p2 = Point(p.x, self.p1.y) @@ -611,7 +614,8 @@ if projected is None: n1 = self.__class__.__name__ n2 = o.__class__.__name__ - raise GeometryError("Do not know how to project %s onto %s" % (n2, n1)) + raise GeometryError( + "Do not know how to project %s onto %s" % (n2, n1)) return self.intersection(projected)[0] @@ -662,7 +666,7 @@ a1, b1, c1 = self.coefficients a2, b2, c2 = o.coefficients t = simplify(a1*b2 - a2*b1) - if t.equals(0) is not False: # assume they are parallel + if t.equals(0) is not False: # assume they are parallel if isinstance(self, Line): if o.p1 in self: return [o] @@ -737,16 +741,18 @@ # because that requires an equality test that is fragile; # instead we employ some diagnostics to see if the intersection # is valid + def inseg(self): def _between(a, b, c): return c >= a and c <= b or c <= a and c >= b if _between(self.p1.x, self.p2.x, inter.x) and \ - _between(self.p1.y, self.p2.y, inter.y): + _between(self.p1.y, self.p2.y, inter.y): return True + def inray(self): sray = Ray(self.p1, inter) if sray.xdirection == self.xdirection and \ - sray.ydirection == self.ydirection: + sray.ydirection == self.ydirection: return True for i in range(2): if isinstance(self, Line): @@ -769,6 +775,52 @@ return o.intersection(self) + def arbitrary_point(self, parameter='t'): + """A parameterized point on the Line. + + Parameters + ========== + + parameter : str, optional + The name of the parameter which will be used for the parametric + point. The default value is 't'. When this parameter is 0, the + first point used to define the line will be returned, and when + it is 1 the second point will be returned. + + Returns + ======= + + point : Point + + Raises + ====== + + ValueError + When ``parameter`` already appears in the Line's definition. + + See Also + ======== + + sympy.geometry.point.Point + + Examples + ======== + + >>> from sympy import Point, Line + >>> p1, p2 = Point(1, 0), Point(5, 3) + >>> l1 = Line(p1, p2) + >>> l1.arbitrary_point() + Point(4*t + 1, 3*t) + + """ + t = _symbol(parameter) + if t.name in (f.name for f in self.free_symbols): + raise ValueError('Symbol %s already appears in object ' + 'and cannot be used as a parameter.' % t.name) + x = simplify(self.p1.x + t*(self.p2.x - self.p1.x)) + y = simplify(self.p1.y + t*(self.p2.y - self.p1.y)) + return Point(x, y) + def random_point(self): """A random point on a LinearEntity. @@ -826,7 +878,7 @@ a, b, c = self.coefficients x = randint(lower, upper) - y = simplify((-c - a*x) / b) + y = (-c - a*x) / b return Point(x, y) def is_similar(self, other): @@ -860,7 +912,8 @@ if result is not None: return result else: - raise Undecidable("can't decide whether '%s' contains '%s'" % (self, other)) + raise Undecidable( + "can't decide whether '%s' contains '%s'" % (self, other)) def contains(self, other): """Subclasses should implement this method and should return @@ -939,7 +992,8 @@ try: p2 = Point(pt) except NotImplementedError: - raise ValueError('The 2nd argument was not a valid Point; if it was meant to be a slope it should be given with keyword "slope".') + raise ValueError('The 2nd argument was not a valid Point. ' + 'If it was a slope, enter it with keyword "slope".') if p1 == p2: raise ValueError('A line requires two distinct points.') elif slope is not None and pt is None: @@ -955,51 +1009,10 @@ return LinearEntity.__new__(cls, p1, p2, **kwargs) - def arbitrary_point(self, parameter='t'): - """A parameterized point on the Line. - - Parameters - ========== - - parameter : str, optional - The name of the parameter which will be used for the parametric - point. The default value is 't'. - - Returns - ======= - - point : Point - - Raises - ====== - - ValueError - When ``parameter`` already appears in the Line's definition. - - See Also - ======== - - sympy.geometry.point.Point - - Examples - ======== - - >>> from sympy import Point, Line - >>> p1, p2 = Point(1, 0), Point(5, 3) - >>> l1 = Line(p1, p2) - >>> l1.arbitrary_point() - Point(4*t + 1, 3*t) - - """ - t = _symbol(parameter) - if t.name in (f.name for f in self.free_symbols): - raise ValueError('Symbol %s already appears in object and cannot be used as a parameter.' % t.name) - x = simplify(self.p1.x + t*(self.p2.x - self.p1.x)) - y = simplify(self.p1.y + t*(self.p2.y - self.p1.y)) - return Point(x, y) - def plot_interval(self, parameter='t'): - """The plot interval for the default geometric plot of line. + """The plot interval for the default geometric plot of line. Gives + values that will produce a line that is +/- 5 units long (where a + unit is the distance between the two points that define the line). Parameters ========== @@ -1160,7 +1173,10 @@ try: p2 = Point(pt) except NotImplementedError: - raise ValueError('The 2nd argument was not a valid Point;\nif it was meant to be an angle it should be given with keyword "angle".') + raise ValueError( + 'The 2nd argument was not a valid Point;\nif ' + 'it was meant to be an angle it should be ' + 'given with keyword "angle".') if p1 == p2: raise ValueError('A Ray requires two distinct points.') elif angle is not None and pt is None: @@ -1275,89 +1291,10 @@ else: return S.NegativeInfinity - def arbitrary_point(self, parameter='t'): - """A parameterized point on the Ray. - - Parameters - ========== - - parameter : str, optional - The name of the parameter which will be used for the parametric - point. The default value is 't'. - - Returns - ======= - - point : Point - - Raises - ====== - - ValueError - When ``parameter`` already appears in the Ray's definition. - - See Also - ======== - - sympy.geometry.point.Point - - Examples - ======== - - >>> from sympy import Ray, Point, Segment, S, simplify, solve - >>> from sympy.abc import t - >>> r = Ray(Point(0, 0), Point(2, 3)) - - >>> p = r.arbitrary_point(t) - - The parameter `t` used in the arbitrary point maps 0 to the - origin of the ray and 1 to the end of the ray at infinity - (which will show up as NaN). - - >>> p.subs(t, 0), p.subs(t, 1) - (Point(0, 0), Point(oo, oo)) - - The unit that `t` moves you is based on the spacing of the - points used to define the ray. - - >>> p.subs(t, 1/(S(1) + 1)) # one unit - Point(2, 3) - >>> p.subs(t, 2/(S(1) + 2)) # two units out - Point(4, 6) - >>> p.subs(t, S.Half/(S(1) + S.Half)) # half a unit out - Point(1, 3/2) - - If you want to be located a distance of 1 from the origin of the - ray, what value of `t` is needed? - - a) Find the unit length and pick `t` accordingly. - - >>> u = Segment(r.p1, p.subs(t, S.Half)).length # S.Half = 1/(1 + 1) - >>> want = 1 - >>> t_need = want/u - >>> p_want = p.subs(t, t_need/(1 + t_need)) - >>> simplify(Segment(r.p1, p_want).length) - 1 - - b) Find the `t` that makes the length from origin to `p` equal to 1. - - >>> l = Segment(r.p1, p).length - >>> t_need = solve(l**2 - want**2, t) # use the square to remove abs() if it is there - >>> t_need = [w for w in t_need if w.n() > 0][0] # take positive t - >>> p_want = p.subs(t, t_need) - >>> simplify(Segment(r.p1, p_want).length) - 1 - - """ - t = _symbol(parameter) - if t.name in (f.name for f in self.free_symbols): - raise ValueError('Symbol %s already appears in object and cannot be used as a parameter.' % t.name) - x = simplify(self.p1.x + t/(1 - t)*(self.p2.x - self.p1.x)) - y = simplify(self.p1.y + t/(1 - t)*(self.p2.y - self.p1.y)) - return Point(x, y) - def plot_interval(self, parameter='t'): - """The plot interval for the default geometric plot of the Ray. + """The plot interval for the default geometric plot of the Ray. Gives + values that will produce a ray that is 10 units long (where a unit is + the distance between the two points that define the ray). Parameters ========== @@ -1377,16 +1314,11 @@ >>> from sympy import Point, Ray, pi >>> r = Ray((0, 0), angle=pi/4) >>> r.plot_interval() - [t, 0, 5*sqrt(2)/(1 + 5*sqrt(2))] + [t, 0, 10] """ t = _symbol(parameter) - p = self.arbitrary_point(t) - # get a t corresponding to length of 10 - want = 10 - u = Segment(self.p1, p.subs(t, S.Half)).length # gives unit length - t_need = want/u - return [t, 0, t_need/(1 + t_need)] + return [t, 0, 10] def __eq__(self, other): """Is the other GeometryEntity equal to this Ray?""" @@ -1417,7 +1349,8 @@ rv = o.y <= self.source.y if isinstance(rv, bool): return rv - raise Undecidable('Cannot determine if %s is in %s' % (o, self)) + raise Undecidable( + 'Cannot determine if %s is in %s' % (o, self)) else: # Points are not collinear, so the rays are not parallel # and hence it is impossible for self to contain o @@ -1490,64 +1423,9 @@ p1, p2 = p2, p1 return LinearEntity.__new__(cls, p1, p2, **kwargs) - def arbitrary_point(self, parameter='t'): - """A parameterized point on the Segment. - - Parameters - ========== - - parameter : str, optional - The name of the parameter which will be used for the parametric - point. The default value is 't'. - - Returns - ======= - - point : Point - - - Parameters - ========== - - parameter : str, optional - The name of the parameter which will be used for the parametric - point. The default value is 't'. - - Returns - ======= - - point : Point - - Raises - ====== - - ValueError - When ``parameter`` already appears in the Segment's definition. - - See Also - ======== - - sympy.geometry.point.Point - - Examples - ======== - - >>> from sympy import Point, Segment - >>> p1, p2 = Point(1, 0), Point(5, 3) - >>> s1 = Segment(p1, p2) - >>> s1.arbitrary_point() - Point(4*t + 1, 3*t) - - """ - t = _symbol(parameter) - if t.name in (f.name for f in self.free_symbols): - raise ValueError('Symbol %s already appears in object and cannot be used as a parameter.' % t.name) - x = simplify(self.p1.x + t*(self.p2.x - self.p1.x)) - y = simplify(self.p1.y + t*(self.p2.y - self.p1.y)) - return Point(x, y) - def plot_interval(self, parameter='t'): - """The plot interval for the default geometric plot of the Segment. + """The plot interval for the default geometric plot of the Segment. Gives + values that will produce the full segment in a plot. Parameters ========== @@ -1691,7 +1569,8 @@ elif t <= 0: distance = Point.distance(self.p1, pt) else: - distance = Point.distance(self.p1 + Point(t*seg_vector.x, t*seg_vector.y), pt) + distance = Point.distance( + self.p1 + Point(t*seg_vector.x, t*seg_vector.y), pt) return distance def __eq__(self, other): diff -Nru python3-sympy-0.7.2/sympy/geometry/point.py python3-sympy-0.7.3/sympy/geometry/point.py --- python3-sympy-0.7.2/sympy/geometry/point.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/geometry/point.py 2013-07-13 17:53:32.000000000 +0000 @@ -9,13 +9,13 @@ from sympy.core import S, sympify from sympy.core.compatibility import iterable from sympy.core.containers import Tuple -from sympy.simplify import simplify +from sympy.simplify import simplify, nsimplify from sympy.geometry.exceptions import GeometryError from sympy.functions.elementary.miscellaneous import sqrt from .entity import GeometryEntity -from sympy.matrices.matrices import Matrix +from sympy.matrices import Matrix from sympy.core.numbers import Float -from sympy.simplify.simplify import nsimplify + class Point(GeometryEntity): """A point in a 2-dimensional Euclidean space. @@ -82,9 +82,10 @@ coords = Tuple(*args) if len(coords) != 2: - raise NotImplementedError("Only two dimensional points currently supported") + raise NotImplementedError( + "Only two dimensional points currently supported") if kwargs.get('evaluate', True): - coords = [nsimplify(c) for c in coords] + coords = [simplify(nsimplify(c, rational=True)) for c in coords] return GeometryEntity.__new__(cls, *coords) @@ -203,10 +204,13 @@ False """ + # Coincident points are irrelevant and can confuse this algorithm. + # Use only unique points. + points = list(set(points)) if len(points) == 0: return False if len(points) <= 2: - return True # two points always form a line + return True # two points always form a line points = [Point(a) for a in points] # XXX Cross product is used now, but that only extends to three @@ -223,7 +227,7 @@ if test is False: return False if rv and not test: - rv = test + rv = test return rv def is_concyclic(*points): @@ -567,7 +571,8 @@ return Point(*[simplify(a + b) for a, b in zip(self.args, other.args)]) else: - raise TypeError("Points must have the same number of dimensions") + raise TypeError( + "Points must have the same number of dimensions") else: raise ValueError('Cannot add non-Point, %s, to a Point' % other) diff -Nru python3-sympy-0.7.2/sympy/geometry/polygon.py python3-sympy-0.7.3/sympy/geometry/polygon.py --- python3-sympy-0.7.2/sympy/geometry/polygon.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/geometry/polygon.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,8 +1,9 @@ from sympy.core import Expr, S, sympify, oo, pi, Symbol, zoo from sympy.core.compatibility import as_int from sympy.functions.elementary.piecewise import Piecewise -from sympy.functions.elementary.trigonometric import cos, sin, tan, sqrt -from sympy.simplify import simplify, nsimplify +from sympy.functions.elementary.complexes import sign +from sympy.functions.elementary.trigonometric import cos, sin, tan, sqrt, atan +from sympy.simplify import simplify from sympy.geometry.exceptions import GeometryError from sympy.matrices import Matrix from sympy.solvers import solve @@ -16,6 +17,7 @@ import warnings + class Polygon(GeometryEntity): """A two-dimensional polygon. @@ -112,9 +114,9 @@ n = kwargs.pop('n') args = list(args) # return a virtual polygon with n sides - if len(args) == 2: # center, radius + if len(args) == 2: # center, radius args.append(n) - elif len(args) == 3: # center, radius, rotation + elif len(args) == 3: # center, radius, rotation args.insert(2, n) return RegularPolygon(*args, **kwargs) @@ -127,7 +129,7 @@ continue nodup.append(p) if len(nodup) > 1 and nodup[-1] == nodup[0]: - nodup.pop() # last point was same as first + nodup.pop() # last point was same as first # remove collinear points unless they are shared points got = set() @@ -163,7 +165,7 @@ # random set of segments since only those sides that are not # part of the convex hull can possibly intersect with other # sides of the polygon...but for now we use the n**2 algorithm - # and check all sides with intersection with any preceding sides + # and check if any side intersects with any preceding side hit = _symbol('hit') if not rv.is_convex: sides = rv.sides @@ -178,8 +180,8 @@ if tx.is_number and 0 <= tx <= 1: ty = (solve(ai[1] - aj[1]) or [S.Zero])[0] if (tx or ty) and ty.is_number and 0 <= ty <= 1: - print(ai, aj) - raise GeometryError("Polygon has intersecting sides.") + raise GeometryError( + "Polygon has intersecting sides.") return rv @@ -491,7 +493,6 @@ ========== [1] http://www.ariel.com.au/a/python-point-int-poly.html - [2] http://local.wasp.uwa.edu.au/~pbourke/geometry/insidepoly/ """ p = Point(p) @@ -501,7 +502,7 @@ # move to p, checking that the result is numeric lit = [] for v in self.vertices: - lit.append(v - p) # the difference is simplified + lit.append(v - p) # the difference is simplified if lit[-1].free_symbols: return None self = Polygon(*lit) @@ -590,9 +591,10 @@ for s in self.sides: side_perim_fraction = s.length/perimeter perim_fraction_end = perim_fraction_start + side_perim_fraction - pt = s.arbitrary_point(parameter).subs( - t, (t - perim_fraction_start)/side_perim_fraction) - sides.append((pt, (perim_fraction_start <= t < perim_fraction_end))) + pt = s.arbitrary_point(parameter).subs( + t, (t - perim_fraction_start)/side_perim_fraction) + sides.append( + (pt, (perim_fraction_start <= t < perim_fraction_end))) perim_fraction_start = perim_fraction_end return Piecewise(*sides) @@ -805,21 +807,27 @@ point2 = e1_connections[e1_ymax][1] angle1 = support_line.angle_between(Line(e1_ymax, point1)) angle2 = support_line.angle_between(Line(e1_ymax, point2)) - if angle1 < angle2: e1_next = point1 - elif angle2 < angle1: e1_next = point2 + if angle1 < angle2: + e1_next = point1 + elif angle2 < angle1: + e1_next = point2 elif Point.distance(e1_ymax, point1) > Point.distance(e1_ymax, point2): e1_next = point2 - else: e1_next = point1 + else: + e1_next = point1 point1 = e2_connections[e2_ymin][0] point2 = e2_connections[e2_ymin][1] angle1 = support_line.angle_between(Line(e2_ymin, point1)) angle2 = support_line.angle_between(Line(e2_ymin, point2)) - if angle1 > angle2: e2_next = point1 - elif angle2 > angle1: e2_next = point2 + if angle1 > angle2: + e2_next = point1 + elif angle2 > angle1: + e2_next = point2 elif Point.distance(e2_ymin, point1) > Point.distance(e2_ymin, point2): e2_next = point2 - else: e2_next = point1 + else: + e2_next = point1 ''' Loop which determins the distance between anti-podal pairs and updates the @@ -827,14 +835,16 @@ ''' while True: e1_angle = support_line.angle_between(Line(e1_current, e1_next)) - e2_angle = pi - support_line.angle_between(Line(e2_current, e2_next)) + e2_angle = pi - support_line.angle_between(Line( + e2_current, e2_next)) if e1_angle < e2_angle: support_line = Line(e1_current, e1_next) e1_segment = Segment(e1_current, e1_next) min_dist_current = e1_segment.distance(e2_current) - if min_dist_current.evalf() < min_dist.evalf(): min_dist = min_dist_current + if min_dist_current.evalf() < min_dist.evalf(): + min_dist = min_dist_current if e1_connections[e1_next][0] != e1_current: e1_current = e1_next @@ -847,7 +857,8 @@ e2_segment = Segment(e2_current, e2_next) min_dist_current = e2_segment.distance(e1_current) - if min_dist_current.evalf() < min_dist.evalf(): min_dist = min_dist_current + if min_dist_current.evalf() < min_dist.evalf(): + min_dist = min_dist_current if e2_connections[e2_next][0] != e2_current: e2_current = e2_next @@ -863,7 +874,8 @@ min2 = e2_segment.distance(e1_next) min_dist_current = min(min1, min2) - if min_dist_current.evalf() < min_dist.evalf(): min_dist = min_dist_current + if min_dist_current.evalf() < min_dist.evalf(): + min_dist = min_dist_current if e1_connections[e1_next][0] != e1_current: e1_current = e1_next @@ -878,7 +890,8 @@ else: e2_current = e2_next e2_next = e2_connections[e2_next][1] - if e1_current == e1_ymax and e2_current == e2_ymin: break + if e1_current == e1_ymax and e2_current == e2_ymin: + break return min_dist def __eq__(self, o): @@ -1020,12 +1033,12 @@ __slots__ = ['_n', '_center', '_radius', '_rot'] def __new__(self, c, r, n, rot=0, **kwargs): - r, n, rot = sympify([r, n, rot]) + r, n, rot = list(map(sympify, (r, n, rot))) c = Point(c) if not isinstance(r, Expr): raise GeometryError("r must be an Expr object, not %s" % r) if n.is_Number: - as_int(n) # let an error raise if necessary + as_int(n) # let an error raise if necessary if n < 3: raise GeometryError("n must be a >= 3, not %s" % n) @@ -1072,7 +1085,7 @@ True """ c, r, n, rot = self.args - return n*self.length**2/(4*tan(pi/n)) + return sign(r)*n*self.length**2/(4*tan(pi/n)) @property def length(self): @@ -1121,6 +1134,8 @@ """ return self._center + centroid = center + @property def circumcenter(self): """ @@ -1341,9 +1356,9 @@ ======== >>> from sympy.geometry import RegularPolygon, Point - >>> rp = RegularPolygon(Point(0, 0), 4, 8) + >>> rp = RegularPolygon(Point(0, 0), 4, 7) >>> rp.incircle - Circle(Point(0, 0), 4*cos(pi/8)) + Circle(Point(0, 0), 4*cos(pi/7)) """ return Circle(self.center, self.apothem) @@ -1360,7 +1375,9 @@ >>> from sympy import RegularPolygon, Point >>> r = RegularPolygon(Point(0, 0), 5, 3) >>> r.angles - {Point(-5/2, -5*sqrt(3)/2): pi/3, Point(-5/2, 5*sqrt(3)/2): pi/3, Point(5, 0): pi/3} + {Point(-5/2, -5*sqrt(3)/2): pi/3, + Point(-5/2, 5*sqrt(3)/2): pi/3, + Point(5, 0): pi/3} """ ret = {} ang = self.interior_angle @@ -1467,7 +1484,7 @@ """ - r = type(self)(*self.args) # need a copy or else changes are in-place + r = type(self)(*self.args) # need a copy or else changes are in-place r._rot += angle return GeometryEntity.rotate(r, angle, pt) @@ -1497,6 +1514,25 @@ r *= x return self.func(c, r, n, rot) + def reflect(self, line): + """Override GeometryEntity.reflect since this is not made of only + points. + + >>> from sympy import RegularPolygon, Line + + >>> RegularPolygon((0, 0), 1, 4).reflect(Line((0, 1), slope=-2)) + RegularPolygon(Point(4/5, 2/5), -1, 4, acos(3/5)) + + """ + c, r, n, rot = self.args + cc = c.reflect(line) + v = self.vertices[0] + vv = v.reflect(line) + # see how much it must get spun at the new center + ang = Segment(cc, vv).angle_between(Segment(c, v)) + rot = (rot + ang + pi) % (2*pi/n) + return self.func(cc, -r, n, rot) + @property def vertices(self): """The vertices of the RegularPolygon. @@ -1522,7 +1558,7 @@ """ c = self._center - r = self._radius + r = abs(self._radius) rot = self._rot v = 2*S.Pi/self._n @@ -1539,6 +1575,7 @@ def __hash__(self): return super(RegularPolygon, self).__hash__() + class Triangle(Polygon): """ A polygon with three vertices and three sides. @@ -1598,11 +1635,11 @@ def __new__(cls, *args, **kwargs): if len(args) != 3: if 'sss' in kwargs: - return _sss(*[nsimplify(a) for a in kwargs['sss']]) + return _sss(*[simplify(a) for a in kwargs['sss']]) if 'asa' in kwargs: - return _asa(*[nsimplify(a) for a in kwargs['asa']]) + return _asa(*[simplify(a) for a in kwargs['asa']]) if 'sas' in kwargs: - return _sas(*[nsimplify(a) for a in kwargs['sas']]) + return _sas(*[simplify(a) for a in kwargs['sas']]) msg = "Triangle instantiates with three points or a valid keyword." raise GeometryError(msg) @@ -1615,7 +1652,7 @@ continue nodup.append(p) if len(nodup) > 1 and nodup[-1] == nodup[0]: - nodup.pop() # last point was same as first + nodup.pop() # last point was same as first # remove collinear points i = -3 @@ -1701,6 +1738,7 @@ s1_1, s1_2, s1_3 = [side.length for side in t1.sides] s2 = [side.length for side in t2.sides] + def _are_similar(u1, u2, u3, v1, v2, v3): e1 = simplify(u1/v1) e2 = simplify(u2/v2) @@ -1709,11 +1747,11 @@ # There's only 6 permutations, so write them out return _are_similar(s1_1, s1_2, s1_3, *s2) or \ - _are_similar(s1_1, s1_3, s1_2, *s2) or \ - _are_similar(s1_2, s1_1, s1_3, *s2) or \ - _are_similar(s1_2, s1_3, s1_1, *s2) or \ - _are_similar(s1_3, s1_1, s1_2, *s2) or \ - _are_similar(s1_3, s1_2, s1_1, *s2) + _are_similar(s1_1, s1_3, s1_2, *s2) or \ + _are_similar(s1_2, s1_1, s1_3, *s2) or \ + _are_similar(s1_2, s1_3, s1_1, *s2) or \ + _are_similar(s1_3, s1_1, s1_2, *s2) or \ + _are_similar(s1_3, s1_2, s1_1, *s2) def is_equilateral(self): """Are all the sides the same length? @@ -1818,8 +1856,8 @@ """ s = self.sides return Segment.is_perpendicular(s[0], s[1]) or \ - Segment.is_perpendicular(s[1], s[2]) or \ - Segment.is_perpendicular(s[0], s[2]) + Segment.is_perpendicular(s[1], s[2]) or \ + Segment.is_perpendicular(s[0], s[2]) @property def altitudes(self): @@ -1913,7 +1951,7 @@ >>> t.circumcenter Point(1/2, 1/2) """ - a,b,c = [x.perpendicular_bisector() for x in self.sides] + a, b, c = [x.perpendicular_bisector() for x in self.sides] return a.intersection(b)[0] @property @@ -2166,33 +2204,39 @@ # """Returns a list of the three excircles for this triangle.""" # pass + def rad(d): """Return the radian value for the given degrees (pi = 180 degrees).""" return d*pi/180 + def deg(r): """Return the degree value for the given radians (pi = 180 degrees).""" return r/pi*180 + def _slope(d): rv = tan(rad(d)) return rv + def _asa(d1, l, d2): """Return triangle having side with length l on the x-axis.""" xy = Line((0, 0), slope=_slope(d1)).intersection( - Line((l, 0), slope=_slope(180 - d2)))[0] - return Triangle((0,0),(l,0),xy) + Line((l, 0), slope=_slope(180 - d2)))[0] + return Triangle((0, 0), (l, 0), xy) + def _sss(l1, l2, l3): """Return triangle having side of length l1 on the x-axis.""" - c1 = Circle((0,0), l3) + c1 = Circle((0, 0), l3) c2 = Circle((l1, 0), l2) inter = [a for a in c1.intersection(c2) if a.y.is_nonnegative] if not inter: return None pt = inter[0] - return Triangle((0,0), (l1,0), pt) + return Triangle((0, 0), (l1, 0), pt) + def _sas(l1, d, l2): """Return triangle having side with length l2 on the x-axis.""" diff -Nru python3-sympy-0.7.2/sympy/geometry/tests/test_geometry.py python3-sympy-0.7.3/sympy/geometry/tests/test_geometry.py --- python3-sympy-0.7.2/sympy/geometry/tests/test_geometry.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/geometry/tests/test_geometry.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,11 +1,12 @@ from sympy import (Abs, C, Dummy, Rational, Float, S, Symbol, cos, oo, pi, - simplify, sqrt, symbols, tan) + simplify, sin, sqrt, symbols, tan) from sympy.geometry import (Circle, Curve, Ellipse, GeometryError, Line, Point, Polygon, Ray, RegularPolygon, Segment, Triangle, are_similar, convex_hull, intersection, centroid) from sympy.geometry.line import Undecidable from sympy.geometry.entity import rotate, scale, translate from sympy.geometry.polygon import _asa as asa, rad, deg +from sympy.utilities.randtest import test_numerically from sympy.utilities.pytest import raises, XFAIL x = Symbol('x', real=True) @@ -15,12 +16,14 @@ x2 = Symbol('x2', real=True) y1 = Symbol('y1', real=True) y2 = Symbol('y2', real=True) -half = Rational(1,2) +half = Rational(1, 2) + def feq(a, b): """Test if two floating point values are 'equal'.""" t = Float("1.0E-10") - return -t < a-b < t + return -t < a - b < t + def test_curve(): s = Symbol('s') @@ -40,8 +43,10 @@ assert c.parameter == s assert c.functions == (2*s, s**2) t = Symbol('t') - assert c.arbitrary_point() != Point(2*t, t**2) # the t returned as assumptions - t = Symbol('t', real=True) # now t has the same assumptions so the test passes + # the t returned as assumptions + assert c.arbitrary_point() != Point(2*t, t**2) + t = Symbol('t', real=True) + # now t has the same assumptions so the test passes assert c.arbitrary_point() == Point(2*t, t**2) assert c.arbitrary_point(z) == Point(2*z, z**2) assert c.arbitrary_point(c.parameter) == Point(2*s, s**2) @@ -49,12 +54,11 @@ assert c.plot_interval() == [t, 0, 2] assert c.plot_interval(z) == [z, 0, 2] - assert Curve([x, x], (x, 0, 1) - ).rotate(pi/2, (1, 2)).scale(2, 3).translate(1, 3).arbitrary_point(s - ) == \ - Line((0, 0), (1, 1) - ).rotate(pi/2, (1, 2)).scale(2, 3).translate(1, 3).arbitrary_point(s - ) == Point(-2*s + 7, 3*s + 6) + assert Curve([x, x], (x, 0, 1)).rotate(pi/2, (1, 2)).scale(2, 3).translate( + 1, 3).arbitrary_point(s) == \ + Line((0, 0), (1, 1)).rotate(pi/2, (1, 2)).scale(2, 3).translate( + 1, 3).arbitrary_point(s) == \ + Point(-2*s + 7, 3*s + 6) raises(ValueError, lambda: Curve((s), (s, 1, 2))) raises(ValueError, lambda: Curve((x, x * 2), (1, x))) @@ -62,17 +66,19 @@ raises(ValueError, lambda: Curve((s, s + t), (s, 1, 2)).arbitrary_point()) raises(ValueError, lambda: Curve((s, s + t), (t, 1, 2)).arbitrary_point(s)) + def test_point(): p1 = Point(x1, x2) p2 = Point(y1, y2) p3 = Point(0, 0) p4 = Point(1, 1) + p5 = Point(0, 1) assert p1 in p1 assert p1 not in p2 assert p2.y == y2 assert (p3 + p4) == p4 - assert (p2 - p1) == Point(y1-x1, y2-x2) + assert (p2 - p1) == Point(y1 - x1, y2 - x2) assert p4*5 == Point(5, 5) assert -p2 == Point(-y1, -y2) @@ -91,7 +97,8 @@ assert Point.is_collinear(p3) assert Point.is_collinear(p3, p4) assert Point.is_collinear(p3, p4, p1_1, p1_2) - assert Point.is_collinear(p3, p4, p1_1, p1_3) == False + assert Point.is_collinear(p3, p4, p1_1, p1_3) is False + assert Point.is_collinear(p3, p3, p4, p5) is False assert p3.intersection(Point(0, 0)) == [p3] assert p3.intersection(p4) == [] @@ -105,8 +112,8 @@ assert Point.is_concyclic(p2_1) assert Point.is_concyclic(p2_1, p2_2) assert Point.is_concyclic(p2_1, p2_2, p2_3, p2_4) - assert Point.is_concyclic(p2_1, p2_2, p2_3, p2_5) == False - assert Point.is_concyclic(p4, p4 * 2, p4 * 3) == False + assert Point.is_concyclic(p2_1, p2_2, p2_3, p2_5) is False + assert Point.is_concyclic(p4, p4 * 2, p4 * 3) is False assert p4.scale(2, 3) == Point(2, 3) assert p3.scale(2, 3) == p3 @@ -139,6 +146,7 @@ assert p.translate(y=1) == Point(1, 2) assert p.translate(*p.args) == Point(2, 2) + def test_line(): p1 = Point(0, 0) p2 = Point(1, 1) @@ -178,12 +186,12 @@ assert l5.equation() == x assert l6.equation() == x - 2 assert l7.equation() == y - 1 - assert p1 in l1 # is p1 on the line l1? + assert p1 in l1 # is p1 on the line l1? assert p1 not in l3 - assert Line((-x,x),(-x+1,x-1)).coefficients == (1, 1, 0) + assert Line((-x, x), (-x + 1, x - 1)).coefficients == (1, 1, 0) - assert simplify(l1.equation()) in (x-y, y-x) - assert simplify(l3.equation()) in (x-x1, x1-x) + assert simplify(l1.equation()) in (x - y, y - x) + assert simplify(l3.equation()) in (x - x1, x1 - x) assert Line(p1, p2).scale(2, 1) == Line(p1, p9) @@ -196,7 +204,7 @@ l1_1 = Line(p1, p1_1) assert l1.perpendicular_line(p1) == l1_1 assert Line.is_perpendicular(l1, l1_1) - assert Line.is_perpendicular(l1 , l2) == False + assert Line.is_perpendicular(l1, l2) is False p = l1.random_point() assert l1.perpendicular_segment(p) == p @@ -206,7 +214,7 @@ assert l2.parallel_line(p1_1) == Line(p2_1, p1_1) assert l2_1.parallel_line(p1) == Line(p1, Point(0, 2)) assert Line.is_parallel(l1, l2) - assert Line.is_parallel(l2, l3) == False + assert Line.is_parallel(l2, l3) is False assert Line.is_parallel(l2, l2.parallel_line(p1_1)) assert Line.is_parallel(l2_1, l2_1.parallel_line(p1)) @@ -217,17 +225,18 @@ assert intersection(l1, l1.parallel_line(p5)) == [] # Concurrency - l3_1 = Line(Point(5, x1), Point(-Rational(3,5), x1)) - assert Line.is_concurrent(l1) == False + l3_1 = Line(Point(5, x1), Point(-Rational(3, 5), x1)) + assert Line.is_concurrent(l1) is False assert Line.is_concurrent(l1, l3) assert Line.is_concurrent(l1, l3, l3_1) - assert Line.is_concurrent(l1, l1_1, l3) == False + assert Line.is_concurrent(l1, l1_1, l3) is False # Projection assert l2.projection(p4) == p4 assert l1.projection(p1_1) == p1 assert l3.projection(p2) == Point(x1, 1) - raises(GeometryError, lambda: Line(Point(0, 0), Point(1, 0)).projection(Circle(Point(0, 0), 1))) + raises(GeometryError, lambda: Line(Point(0, 0), Point(1, 0)) + .projection(Circle(Point(0, 0), 1))) # Finding angles l1_1 = Line(p1, Point(5, 0)) @@ -244,8 +253,8 @@ assert Ray((1, 1), angle=3.0*pi) == Ray((1, 1), (0, 1)) assert Ray((1, 1), angle=4.0*pi) == Ray((1, 1), (2, 1)) assert Ray((1, 1), angle=0) == Ray((1, 1), (2, 1)) - # XXX don't know why this fails without str - assert str(Ray((1, 1), angle=4.2*pi)) == str(Ray(Point(1, 1), Point(2, 1 + C.tan(0.2*pi)))) + assert Ray((1, 1), angle=4.05*pi) == Ray(Point(1, 1), + Point(2, 1 + C.tan(4.05*pi))) assert Ray((1, 1), angle=5) == Ray((1, 1), (2, 1 + C.tan(5))) raises(ValueError, lambda: Ray((1, 1), 1)) @@ -260,11 +269,12 @@ assert l1.projection(r2) == p1 assert r3 != r1 t = Symbol('t', real=True) - assert Ray((1, 1), angle=pi/4).arbitrary_point() == Point(1/(1 - t), 1/(1 - t)) + assert Ray((1, 1), angle=pi/4).arbitrary_point() == \ + Point(t + 1, t + 1) s1 = Segment(p1, p2) s2 = Segment(p1, p1_1) - assert s1.midpoint == Point(Rational(1,2), Rational(1,2)) + assert s1.midpoint == Point(Rational(1, 2), Rational(1, 2)) assert s2.length == sqrt( 2*(x1**2) ) assert s1.perpendicular_bisector() == Line(Point(0, 1), Point(1, 0)) assert Segment((1, 1), (2, 3)).arbitrary_point() == Point(1 + t, 1 + 2*t) @@ -276,14 +286,16 @@ assert s3.intersection(s1) == [s3] assert r4.intersection(s3) == [s3] assert r4.intersection(Segment(Point(2, 3), Point(3, 4))) == [] - assert r4.intersection(Segment(Point(-1, -1), Point(0.5, 0.5))) == [Segment(p1, Point(0.5, 0.5))] + assert r4.intersection(Segment(Point(-1, -1), Point(0.5, 0.5))) == \ + [Segment(p1, Point(0.5, 0.5))] s3 = Segment(Point(1, 1), Point(2, 2)) assert s1.intersection(s3) == [Point(1, 1)] s3 = Segment(Point(0.5, 0.5), Point(1.5, 1.5)) assert s1.intersection(s3) == [Segment(Point(0.5, 0.5), p2)] assert s1.intersection(Segment(Point(4, 4), Point(5, 5))) == [] assert s1.intersection(Segment(Point(-1, -1), p1)) == [p1] - assert s1.intersection(Segment(Point(-1, -1), Point(0.5, 0.5))) == [Segment(p1, Point(0.5, 0.5))] + assert s1.intersection(Segment(Point(-1, -1), Point(0.5, 0.5))) == \ + [Segment(p1, Point(0.5, 0.5))] assert r4.intersection(r5) == [s1] assert r5.intersection(r6) == [] assert r4.intersection(r7) == r7.intersection(r4) == [r7] @@ -338,8 +350,8 @@ assert intersection(r1, l1) == [r1] assert intersection(s1, l1) == [s1] - entity1 = Segment(Point(-10,10), Point(10,10)) - entity2 = Segment(Point(-5,-5), Point(-5,5)) + entity1 = Segment(Point(-10, 10), Point(10, 10)) + entity2 = Segment(Point(-5, -5), Point(-5, 5)) assert intersection(entity1, entity2) == [] r1 = Ray(p1, Point(0, 1)) @@ -363,8 +375,8 @@ assert hash(s1) == hash(s2) p11 = p10.scale(2, 2) assert s1.is_similar(Segment(p10, p11)) - assert s1.is_similar(r1) == False - assert (r1 in s1) == False + assert s1.is_similar(r1) is False + assert (r1 in s1) is False assert Segment(p1, p2) in s1 assert s1.plot_interval() == [t, 0, 1] assert s1 in Line(p1, p10) @@ -372,7 +384,8 @@ assert Line(p1, p10) != p1 assert Line(p1, p10).plot_interval() == [t, -5, 5] assert Ray((0, 0), angle=pi/4).plot_interval() == \ - [t, 0, 5*sqrt(2)/(1 + 5*sqrt(2))] + [t, 0, 10] + def test_ellipse(): p1 = Point(0, 0) @@ -388,11 +401,12 @@ # Test creation with three points cen, rad = Point(3*half, 2), 5*half - assert Circle(Point(0,0), Point(3,0), Point(0,4)) == Circle(cen, rad) - raises(GeometryError, lambda: Circle(Point(0,0), Point(1,1), Point(2,2))) + assert Circle(Point(0, 0), Point(3, 0), Point(0, 4)) == Circle(cen, rad) + raises( + GeometryError, lambda: Circle(Point(0, 0), Point(1, 1), Point(2, 2))) raises(ValueError, lambda: Ellipse(None, None, None, 1)) - raises(GeometryError, lambda: Circle(Point(0,0))) + raises(GeometryError, lambda: Circle(Point(0, 0))) # Basic Stuff assert Ellipse(None, 1, 1).center == Point(0, 0) @@ -402,7 +416,7 @@ assert p2 not in e2 assert e1.area == pi assert e2.area == pi/2 - assert e3.area == pi*(y1**2) + assert e3.area == pi*y1*abs(y1) assert c1.area == e1.area assert c1.circumference == e1.circumference assert e3.circumference == 2*pi*y1 @@ -417,27 +431,28 @@ # Private Functions assert hash(c1) == hash(Circle(Point(1, 0), Point(0, 1), Point(0, -1))) assert c1 in e1 - assert (Line(p1, p2) in e1) == False + assert (Line(p1, p2) in e1) is False assert e1.__cmp__(e1) == 0 assert e1.__cmp__(Point(0, 0)) > 0 # Encloses - assert e1.encloses(Segment(Point(-0.5, -0.5), Point(0.5, 0.5))) == True - assert e1.encloses(Line(p1, p2)) == False - assert e1.encloses(Ray(p1, p2)) == False - assert e1.encloses(e1) == False - assert e1.encloses(Polygon(Point(-0.5, -0.5), Point(-0.5, 0.5), Point(0.5, 0.5))) == True - assert e1.encloses(RegularPolygon(p1, 0.5, 3)) == True - assert e1.encloses(RegularPolygon(p1, 5, 3)) == False - assert e1.encloses(RegularPolygon(p2, 5, 3)) == False + assert e1.encloses(Segment(Point(-0.5, -0.5), Point(0.5, 0.5))) is True + assert e1.encloses(Line(p1, p2)) is False + assert e1.encloses(Ray(p1, p2)) is False + assert e1.encloses(e1) is False + assert e1.encloses( + Polygon(Point(-0.5, -0.5), Point(-0.5, 0.5), Point(0.5, 0.5))) is True + assert e1.encloses(RegularPolygon(p1, 0.5, 3)) is True + assert e1.encloses(RegularPolygon(p1, 5, 3)) is False + assert e1.encloses(RegularPolygon(p2, 5, 3)) is False # with generic symbols, the hradius is assumed to contain the major radius M = Symbol('M') m = Symbol('m') c = Ellipse(p1, M, m).circumference _x = c.atoms(Dummy).pop() - assert c == \ - 4*M*C.Integral(sqrt((1 - _x**2*(M**2 - m**2)/M**2)/(1 - _x**2)), (_x, 0, 1)) + assert c == 4*M*C.Integral( + sqrt((1 - _x**2*(M**2 - m**2)/M**2)/(1 - _x**2)), (_x, 0, 1)) assert e2.arbitrary_point() in e2 @@ -459,23 +474,24 @@ assert e2.is_tangent(Line(p1_2, p2 + Point(half, 1))) assert e2.is_tangent(Line(p1_3, p2 + Point(half, 1))) assert c1.is_tangent(Line(p1_1, Point(0, sqrt(2)))) - assert e1.is_tangent(Line(Point(0, 0), Point(1, 1))) == False - assert c1.is_tangent(e1) == False - assert c1.is_tangent(Ellipse(Point(2, 0), 1, 1)) == True - assert c1.is_tangent(Polygon(Point(1, 1), Point(1, -1), Point(2, 0))) == True - assert c1.is_tangent(Polygon(Point(1, 1), Point(1, 0), Point(2, 0))) == False - + assert e1.is_tangent(Line(Point(0, 0), Point(1, 1))) is False + assert c1.is_tangent(e1) is False + assert c1.is_tangent(Ellipse(Point(2, 0), 1, 1)) is True + assert c1.is_tangent( + Polygon(Point(1, 1), Point(1, -1), Point(2, 0))) is True + assert c1.is_tangent( + Polygon(Point(1, 1), Point(1, 0), Point(2, 0))) is False assert Ellipse(Point(5, 5), 2, 1).tangent_lines(Point(0, 0)) == \ - [Line(Point(0, 0), Point(S(77)/25, S(132)/25)), + [Line(Point(0, 0), Point(S(77)/25, S(132)/25)), Line(Point(0, 0), Point(S(33)/5, S(22)/5))] assert Ellipse(Point(5, 5), 2, 1).tangent_lines(Point(3, 4)) == \ - [Line(Point(3, 4), Point(4, 4)), Line(Point(3, 4), Point(3, 5))] + [Line(Point(3, 4), Point(3, 5)), Line(Point(3, 4), Point(5, 4))] assert Circle(Point(5, 5), 2).tangent_lines(Point(3, 3)) == \ - [Line(Point(3, 3), Point(4, 3)), Line(Point(3, 3), Point(3, 4))] + [Line(Point(3, 3), Point(3, 5)), Line(Point(3, 3), Point(5, 3))] assert Circle(Point(5, 5), 2).tangent_lines(Point(5 - 2*sqrt(2), 5)) == \ - [Line(Point(5 - 2*sqrt(2), 5), Point(5 - sqrt(2), 5 - sqrt(2))), - Line(Point(5 - 2*sqrt(2), 5), Point(5 - sqrt(2), 5 + sqrt(2))),] + [Line(Point(5 - 2*sqrt(2), 5), Point(5 - sqrt(2), 5 - sqrt(2))), + Line(Point(5 - 2*sqrt(2), 5), Point(5 - sqrt(2), 5 + sqrt(2))), ] # Properties major = 3 @@ -543,7 +559,8 @@ [[Point(5, 0), Point(-5, 0)], [Point(-5, 0), Point(5, 0)]] assert elip.tangent_lines(Point(0, 0)) == [] elip = Ellipse(Point(0, 0), 3, 2) - assert elip.tangent_lines(Point(3, 0)) == [Line(Point(3, 0), Point(3, -12))] + assert elip.tangent_lines(Point(3, 0)) == \ + [Line(Point(3, 0), Point(3, -12))] e1 = Ellipse(Point(0, 0), 5, 10) e2 = Ellipse(Point(2, 1), 4, 8) @@ -552,6 +569,8 @@ ans = [Point(a - c/8, a/2 + c), Point(a + c/8, a/2 - c)] assert e1.intersection(e2) == ans e2 = Ellipse(Point(x, y), 4, 8) + c = sqrt(3991) + ans = [Point(c/68 + a, -2*c/17 + a/2), Point(-c/68 + a, 2*c/17 + a/2)] assert [p.subs({x: 2, y:1}) for p in e1.intersection(e2)] == ans # Combinations of above @@ -559,7 +578,7 @@ e = Ellipse((1, 2), 3, 2) assert e.tangent_lines(Point(10, 0)) == \ - [Line(Point(10, 0), Point(1, 0)), + [Line(Point(10, 0), Point(1, 0)), Line(Point(10, 0), Point(S(14)/5, S(18)/5))] # encloses_point @@ -568,13 +587,15 @@ assert e.encloses_point(e.center + Point(0, e.vradius - Rational(1, 10))) assert e.encloses_point(e.center + Point(e.hradius - Rational(1, 10), 0)) assert e.encloses_point(e.center + Point(e.hradius, 0)) is False - assert e.encloses_point(e.center + Point(e.hradius + Rational(1, 10), 0)) is False + assert e.encloses_point( + e.center + Point(e.hradius + Rational(1, 10), 0)) is False e = Ellipse((0, 0), 2, 1) assert e.encloses_point(e.center) assert e.encloses_point(e.center + Point(0, e.vradius - Rational(1, 10))) assert e.encloses_point(e.center + Point(e.hradius - Rational(1, 10), 0)) assert e.encloses_point(e.center + Point(e.hradius, 0)) is False - assert e.encloses_point(e.center + Point(e.hradius + Rational(1, 10), 0)) is False + assert e.encloses_point( + e.center + Point(e.hradius + Rational(1, 10), 0)) is False assert c1.encloses_point(Point(1, 0)) is False assert c1.encloses_point(Point(0.3, 0.4)) is True @@ -584,6 +605,13 @@ assert e.rotate(pi/3, (1, 2)) == \ Ellipse(Point(S(1)/2 + sqrt(3), -sqrt(3)/2 + 1), 2, 1) + # transformations + c = Circle((1, 1), 2) + assert c.scale(-1) == Circle((-1, 1), 2) + assert c.scale(y=-1) == Circle((1, -1), 2) + assert c.scale(2) == Ellipse((2, 1), 4, 2) + + def test_ellipse_random_point(): e3 = Ellipse(Point(0, 0), y1, y1) rx, ry = Symbol('rx'), Symbol('ry') @@ -592,6 +620,7 @@ # substitution should give zero*y1**2 assert e3.equation(rx, ry).subs(list(zip((rx, ry), r.args))).equals(0) + def test_polygon(): t = Triangle(Point(0, 0), Point(2, 0), Point(3, 3)) assert Polygon(Point(0, 0), Point(1, 0), Point(2, 0), Point(3, 3)) == t @@ -599,11 +628,11 @@ assert Polygon(Point(2, 0), Point(3, 3), Point(0, 0), Point(1, 0)) == t p1 = Polygon( - Point(0, 0), Point(3,-1), + Point(0, 0), Point(3, -1), Point(6, 0), Point(4, 5), Point(2, 3), Point(0, 3)) p2 = Polygon( - Point(6, 0), Point(3,-1), + Point(6, 0), Point(3, -1), Point(0, 0), Point(0, 3), Point(2, 3), Point(4, 5)) p3 = Polygon( @@ -622,37 +651,43 @@ assert p1 == p2 assert len(p1.args) == 6 assert len(p1.sides) == 6 - assert p1.perimeter == 5+2*sqrt(10)+sqrt(29)+sqrt(8) + assert p1.perimeter == 5 + 2*sqrt(10) + sqrt(29) + sqrt(8) assert p1.area == 22 assert not p1.is_convex() + # ensure convex for both CW and CCW point specification assert p3.is_convex() - assert p4.is_convex() # ensure convex for both CW and CCW point specification + assert p4.is_convex() dict5 = p5.angles assert dict5[Point(0, 0)] == pi / 4 assert dict5[Point(0, 4)] == pi / 2 - assert p5.encloses_point(Point(x, y)) == None + assert p5.encloses_point(Point(x, y)) is None assert p5.encloses_point(Point(1, 3)) - assert p5.encloses_point(Point(0, 0)) == False - assert p5.encloses_point(Point(4, 0)) == False + assert p5.encloses_point(Point(0, 0)) is False + assert p5.encloses_point(Point(4, 0)) is False p5.plot_interval('x') == [x, 0, 1] - assert p5.distance(Polygon(Point(10, 10), Point(14, 14), Point(10, 14))) == 6 * sqrt(2) - assert p5.distance(Polygon(Point(1, 8), Point(5, 8), Point(8, 12), Point(1, 12))) == 4 + assert p5.distance( + Polygon(Point(10, 10), Point(14, 14), Point(10, 14))) == 6 * sqrt(2) + assert p5.distance( + Polygon(Point(1, 8), Point(5, 8), Point(8, 12), Point(1, 12))) == 4 raises(UserWarning, - lambda: Polygon(Point(0, 0), Point(1, 0), Point(1,1)).distance(Polygon(Point(0, 0), Point(0, 1), Point(1, 1)))) + lambda: Polygon(Point(0, 0), Point(1, 0), Point(1, 1)).distance(Polygon(Point(0, 0), Point(0, 1), Point(1, 1)))) assert hash(p5) == hash(Polygon(Point(0, 0), Point(4, 4), Point(0, 4))) assert p5 == Polygon(Point(4, 4), Point(0, 4), Point(0, 0)) assert Polygon(Point(4, 4), Point(0, 4), Point(0, 0)) in p5 assert p5 != Point(0, 4) assert Point(0, 1) in p5 - assert p5.arbitrary_point('t').subs(Symbol('t', real=True), 0) == Point(0, 0) - raises(ValueError, lambda: Polygon(Point(x, 0), Point(0, y), Point(x, y)).arbitrary_point('x')) + assert p5.arbitrary_point('t').subs(Symbol('t', real=True), 0) == \ + Point(0, 0) + raises(ValueError, lambda: Polygon( + Point(x, 0), Point(0, y), Point(x, y)).arbitrary_point('x')) # # Regular polygon # p1 = RegularPolygon(Point(0, 0), 10, 5) p2 = RegularPolygon(Point(0, 0), 5, 5) - raises(GeometryError, lambda: RegularPolygon(Point(0, 0), Point(0, 1), Point(1, 1))) + raises(GeometryError, lambda: RegularPolygon(Point(0, 0), Point(0, + 1), Point(1, 1))) raises(GeometryError, lambda: RegularPolygon(Point(0, 0), 1, 2)) raises(ValueError, lambda: RegularPolygon(Point(0, 0), 1, 2.5)) @@ -671,7 +706,7 @@ assert p1.is_convex() assert p1.rotation == 0 assert p1.encloses_point(Point(0, 0)) - assert p1.encloses_point(Point(11, 0)) == False + assert p1.encloses_point(Point(11, 0)) is False assert p2.encloses_point(Point(0, 4.9)) p1.spin(pi/3) assert p1.rotation == pi/3 @@ -692,7 +727,8 @@ assert p1.area == (-250*sqrt(5) + 1250)/(4*tan(pi/5)) assert p1.length == 20*sqrt(-sqrt(5)/8 + S(5)/8) - assert p1.scale(2, 2) == RegularPolygon(p1.center, p1.radius*2, p1._n, p1.rotation) + assert p1.scale(2, 2) == \ + RegularPolygon(p1.center, p1.radius*2, p1._n, p1.rotation) assert RegularPolygon((0, 0), 1, 4).scale(2, 3) == \ Polygon(Point(2, 0), Point(0, 3), Point(-2, 0), Point(0, -3)) @@ -720,7 +756,7 @@ p2 = Point(5, 0) p3 = Point(0, 5) t1 = Triangle(p1, p2, p3) - t2 = Triangle(p1, p2, Point(Rational(5,2), sqrt(Rational(75,4)))) + t2 = Triangle(p1, p2, Point(Rational(5, 2), sqrt(Rational(75, 4)))) t3 = Triangle(p1, Point(x1, 0), Point(0, x1)) s1 = t1.sides assert Triangle(p1, p2, p1) == Polygon(p1, p2, p1) == Segment(p1, p2) @@ -729,9 +765,9 @@ # Basic stuff assert Triangle(p1, p1, p1) == p1 assert Triangle(p2, p2*2, p2*3) == Segment(p2, p2*3) - assert t1.area == Rational(25,2) + assert t1.area == Rational(25, 2) assert t1.is_right() - assert t2.is_right() == False + assert t2.is_right() is False assert t3.is_right() assert p1 in t1 assert t1.sides[0] in t1 @@ -740,17 +776,17 @@ assert t1.is_convex() assert feq(t1.angles[p1].evalf(), pi.evalf()/2) - assert t1.is_equilateral() == False + assert t1.is_equilateral() is False assert t2.is_equilateral() - assert t3.is_equilateral() == False - assert are_similar(t1, t2) == False + assert t3.is_equilateral() is False + assert are_similar(t1, t2) is False assert are_similar(t1, t3) - assert are_similar(t2, t3) == False - assert t1.is_similar(Point(0, 0)) == False + assert are_similar(t2, t3) is False + assert t1.is_similar(Point(0, 0)) is False # Bisectors bisectors = t1.bisectors() - assert bisectors[p1] == Segment(p1, Point(Rational(5,2), Rational(5,2))) + assert bisectors[p1] == Segment(p1, Point(Rational(5, 2), Rational(5, 2))) ic = (250 - 125*sqrt(2)) / 50 assert t1.incenter == Point(ic, ic) @@ -764,15 +800,15 @@ # Medians + Centroid m = t1.medians - assert t1.centroid == Point(Rational(5,3), Rational(5,3)) - assert m[p1] == Segment(p1, Point(Rational(5,2), Rational(5,2))) + assert t1.centroid == Point(Rational(5, 3), Rational(5, 3)) + assert m[p1] == Segment(p1, Point(Rational(5, 2), Rational(5, 2))) assert t3.medians[p1] == Segment(p1, Point(x1/2, x1/2)) assert intersection(m[p1], m[p2], m[p3]) == [t1.centroid] assert t1.medial == Triangle(Point(2.5, 0), Point(0, 2.5), Point(2.5, 2.5)) # Perpendicular altitudes = t1.altitudes - assert altitudes[p1] == Segment(p1, Point(Rational(5,2), Rational(5,2))) + assert altitudes[p1] == Segment(p1, Point(Rational(5, 2), Rational(5, 2))) assert altitudes[p2] == s1[0] assert altitudes[p3] == s1[2] assert t1.orthocenter == p1 @@ -796,7 +832,7 @@ Point(1, 1), Point(0, 1)) p2 = Polygon( Point(0, Rational(5)/4), Point(1, Rational(5)/4), - Point(1, Rational(9)/4), Point(0, Rational(9)/4)) + Point(1, Rational(9)/4), Point(0, Rational(9)/4)) p3 = Polygon( Point(1, 2), Point(2, 2), Point(2, 1)) @@ -812,6 +848,7 @@ assert p2.distance(pt1) == Rational(3)/4 assert p3.distance(pt2) == sqrt(2)/2 + @XFAIL def test_polygon_to_polygon(): '''Polygon to Polygon''' @@ -821,13 +858,16 @@ import warnings # p1.distance(p2) emits a warning # First, test the warning - warnings.filterwarnings("error", "Polygons may intersect producing erroneous output") + warnings.filterwarnings( + "error", "Polygons may intersect producing erroneous output") raises(UserWarning, lambda: p1.distance(p2)) # now test the actual output - warnings.filterwarnings("ignore", "Polygons may intersect producing erroneous output") + warnings.filterwarnings( + "ignore", "Polygons may intersect producing erroneous output") assert p1.distance(p2) == half/2 # Keep testing reasonably thread safe, so reset the warning - warnings.filterwarnings("default", "Polygons may intersect producing erroneous output") + warnings.filterwarnings( + "default", "Polygons may intersect producing erroneous output") # Note, in Python 2.6+, this can be done more nicely using the # warnings.catch_warnings context manager. # See http://docs.python.org/library/warnings#testing-warnings. @@ -836,15 +876,18 @@ assert p3.distance(p4) == (sqrt(2)/2 - sqrt(Rational(2)/25)/2) assert p5.distance(p6) == Rational(7)/10 + def test_convex_hull(): - p = [Point(-5,-1), Point(-2,1), Point(-2,-1), Point(-1,-3), Point(0,0), - Point(1,1), Point(2,2), Point(2,-1), Point(3,1), Point(4,-1), Point(6,2)] + p = [Point(-5, -1), Point(-2, 1), Point(-2, -1), Point(-1, -3), + Point(0, 0), Point(1, 1), Point(2, 2), Point(2, -1), Point(3, 1), + Point(4, -1), Point(6, 2)] ch = Polygon(p[0], p[3], p[9], p[10], p[6], p[1]) #test handling of duplicate points p.append(p[3]) #more than 3 collinear points - another_p = [Point(-45, -85), Point(-45, 85), Point(-45, 26),Point(-45, -24)] + another_p = [Point(-45, -85), Point(-45, 85), Point(-45, 26), + Point(-45, -24)] ch2 = Segment(another_p[0], another_p[1]) assert convex_hull(*another_p) == ch2 @@ -856,17 +899,19 @@ assert convex_hull(*[p[-1]]*3) == p[-1] # collection of items - assert convex_hull(*[Point(0,0), + assert convex_hull(*[Point(0, 0), Segment(Point(1, 0), Point(1, 1)), RegularPolygon(Point(2, 0), 2, 4)]) == \ - Polygon(Point(0, 0), Point(2, -2), Point(4, 0), Point(2, 2)) + Polygon(Point(0, 0), Point(2, -2), Point(4, 0), Point(2, 2)) + def test_concyclic_doctest_bug(): - p1,p2 = Point(-1, 0), Point(1, 0) - p3,p4 = Point(0, 1), Point(-1, 2) + p1, p2 = Point(-1, 0), Point(1, 0) + p3, p4 = Point(0, 1), Point(-1, 2) assert Point.is_concyclic(p1, p2, p3) assert not Point.is_concyclic(p1, p2, p3, p4) + def test_subs(): p = Point(x, 2) q = Point(1, 1) @@ -877,52 +922,62 @@ Line(p, q), Triangle(p, q, r), RegularPolygon(p, 3, 6), - Polygon(p, q, r, Point(5,4)), + Polygon(p, q, r, Point(5, 4)), Circle(p, 3), Ellipse(p, 3, 4)]: assert 'y' in str(o.subs(x, y)) assert p.subs({x: 1}) == Point(1, 2) assert Point(1, 2).subs(Point(1, 2), Point(3, 4)) == Point(3, 4) - assert Point(1, 2).subs((1,2), Point(3,4)) == Point(3, 4) - assert Point(1, 2).subs(Point(1,2), Point(3,4)) == Point(3, 4) + assert Point(1, 2).subs((1, 2), Point(3, 4)) == Point(3, 4) + assert Point(1, 2).subs(Point(1, 2), Point(3, 4)) == Point(3, 4) assert Point(1, 2).subs(set([(1, 2)])) == Point(2, 2) raises(ValueError, lambda: Point(1, 2).subs(1)) - raises(ValueError, lambda: Point(1, 1).subs((Point(1, 1), Point(1, 2)), 1, 2)) + raises(ValueError, lambda: Point(1, 1).subs((Point(1, 1), Point(1, + 2)), 1, 2)) + def test_encloses(): # square with a dimpled left side - s = Polygon(Point(0, 0), Point(1, 0), Point(1, 1), Point(0, 1), Point(S.Half, S.Half)) + s = Polygon(Point(0, 0), Point(1, 0), Point(1, 1), Point(0, 1), + Point(S.Half, S.Half)) # the following will be True if the polygon isn't treated as closing on itself assert s.encloses(Point(0, S.Half)) is False - assert s.encloses(Point(S.Half, S.Half)) is False # it's a vertex + assert s.encloses(Point(S.Half, S.Half)) is False # it's a vertex assert s.encloses(Point(Rational(3, 4), S.Half)) is True + def test_free_symbols(): a, b, c, d, e, f, s = symbols('a:f,s') - assert Point(a,b).free_symbols == set([a, b]) - assert Line((a,b),(c,d)).free_symbols == set([a, b, c, d]) - assert Ray((a,b),(c,d)).free_symbols == set([a, b, c, d]) - assert Ray((a,b),angle=c).free_symbols == set([a, b, c]) - assert Segment((a,b),(c,d)).free_symbols == set([a, b, c, d]) - assert Line((a,b),slope=c).free_symbols == set([a, b, c]) - assert Curve((a*s,b*s),(s,c,d)).free_symbols == set([a, b, c, d]) - assert Ellipse((a,b),c,d).free_symbols == set([a, b, c, d]) - assert Ellipse((a,b),c, eccentricity=d).free_symbols == set([a, b, c, d]) - assert Ellipse((a,b),vradius=c, eccentricity=d).free_symbols == set([a, b, c, d]) - assert Circle((a,b),c).free_symbols == set([a, b, c]) - assert Circle((a,b),(c,d),(e,f)).free_symbols == set([e, d, c, b, f, a]) - assert Polygon((a,b),(c,d),(e,f)).free_symbols == set([e, b, d, f, a, c]) - assert RegularPolygon((a,b),c,d,e).free_symbols == set([e, a, b, c, d]) + assert Point(a, b).free_symbols == set([a, b]) + assert Line((a, b), (c, d)).free_symbols == set([a, b, c, d]) + assert Ray((a, b), (c, d)).free_symbols == set([a, b, c, d]) + assert Ray((a, b), angle=c).free_symbols == set([a, b, c]) + assert Segment((a, b), (c, d)).free_symbols == set([a, b, c, d]) + assert Line((a, b), slope=c).free_symbols == set([a, b, c]) + assert Curve((a*s, b*s), (s, c, d)).free_symbols == set([a, b, c, d]) + assert Ellipse((a, b), c, d).free_symbols == set([a, b, c, d]) + assert Ellipse((a, b), c, eccentricity=d).free_symbols == \ + set([a, b, c, d]) + assert Ellipse((a, b), vradius=c, eccentricity=d).free_symbols == \ + set([a, b, c, d]) + assert Circle((a, b), c).free_symbols == set([a, b, c]) + assert Circle((a, b), (c, d), (e, f)).free_symbols == \ + set([e, d, c, b, f, a]) + assert Polygon((a, b), (c, d), (e, f)).free_symbols == \ + set([e, b, d, f, a, c]) + assert RegularPolygon((a, b), c, d, e).free_symbols == set([e, a, b, c, d]) + def test_util_centroid(): p = Polygon((0, 0), (10, 0), (10, 10)) q = p.translate(0, 20) assert centroid(p, q) == Point(20, 40)/3 - p = Segment((0,0),(2,0)) - q = Segment((0,0),(2,2)) + p = Segment((0, 0), (2, 0)) + q = Segment((0, 0), (2, 2)) assert centroid(p, q) == Point(1, 2*sqrt(2)/(2 + 2*sqrt(2))) - assert centroid(Point(0,0), Point(2,0)) == Point(2, 0)/2 - assert centroid(Point(0,0), Point(0,0), Point(2,0)) == Point(2, 0)/3 + assert centroid(Point(0, 0), Point(2, 0)) == Point(2, 0)/2 + assert centroid(Point(0, 0), Point(0, 0), Point(2, 0)) == Point(2, 0)/3 + def test_util(): # coverage for some leftover functions in sympy.geometry.util @@ -930,35 +985,41 @@ raises(ValueError, lambda: intersection(Point(0, 0), 3)) raises(ValueError, lambda: convex_hull(Point(0, 0), 3)) + def test_repr(): assert repr(Circle((0, 1), 2)) == 'Circle(Point(0, 1), 2)' + def test_transform(): p = Point(1, 1) - p.transform(rotate(pi/2)) == Point(-1, 1) - p.transform(scale(3, 2)) == Point(3, 2) - p.transform(translate(1, 2)) == Point(2, 3) + assert p.transform(rotate(pi/2)) == Point(-1, 1) + assert p.transform(scale(3, 2)) == Point(3, 2) + assert p.transform(translate(1, 2)) == Point(2, 3) + def test_line_intersection(): assert asa(120, 8, 52) == \ - Triangle( - Point(0, 0), - Point(8, 0), - Point( - 8*tan(32*pi/45)/(tan(32*pi/45) + sqrt(3)), - (24*tan(32*pi/45) - 8*sqrt(3)*tan(32*pi/45)**2)/ - (-3 + tan(32*pi/45)**2))) - assert Line((0,0), (1,1)).intersection(Ray((1,0), (1,2))) == [Point(1,1)] - assert Line((0,0), (1,1)).intersection(Segment((1,0), (1,2))) == [Point(1,1)] - assert Ray((0,0), (1,1)).intersection(Ray((1,0), (1,2))) == [Point(1,1)] - assert Ray((0,0), (1,1)).intersection(Segment((1,0), (1,2))) == [Point(1,1)] - assert Ray((0,0), (10,10)).contains(Segment((1,1), (2,2))) is True - assert Segment((1,1),(2,2)) in Line((0,0),(10,10)) + Triangle( + Point(0, 0), + Point(8, 0), + Point(-4*cos(19*pi/90)/sin(2*pi/45), + 4*sqrt(3)*cos(19*pi/90)/sin(2*pi/45))) + assert Line((0, 0), (1, 1)).intersection(Ray((1, 0), (1, 2))) == \ + [Point(1, 1)] + assert Line((0, 0), (1, 1)).intersection(Segment((1, 0), (1, 2))) == \ + [Point(1, 1)] + assert Ray((0, 0), (1, 1)).intersection(Ray((1, 0), (1, 2))) == \ + [Point(1, 1)] + assert Ray((0, 0), (1, 1)).intersection(Segment((1, 0), (1, 2))) == \ + [Point(1, 1)] + assert Ray((0, 0), (10, 10)).contains(Segment((1, 1), (2, 2))) is True + assert Segment((1, 1), (2, 2)) in Line((0, 0), (10, 10)) x = 8*tan(13*pi/45)/(tan(13*pi/45) + sqrt(3)) - y = (-8*sqrt(3)*tan(13*pi/45)**2 + 24*tan(13*pi/45))/\ + y = (-8*sqrt(3)*tan(13*pi/45)**2 + 24*tan(13*pi/45))/ \ (-3 + tan(13*pi/45)**2) assert Line(Point(0, 0), Point(1, -sqrt(3))).contains(Point(x, y)) is True + def test_triangle_kwargs(): assert Triangle(sss=(3, 4, 5)) == \ Triangle(Point(0, 0), Point(3, 0), Point(3, 4)) @@ -966,9 +1027,10 @@ Triangle(Point(0, 0), Point(2, 0), Point(1, sqrt(3)/3)) assert Triangle(sas=(1, 45, 2)) == \ Triangle(Point(0, 0), Point(2, 0), Point(sqrt(2)/2, sqrt(2)/2)) - assert Triangle(sss=(1,2,5)) is None + assert Triangle(sss=(1, 2, 5)) is None assert deg(rad(180)) == 180 + def test_geometry_transforms(): from sympy import Tuple c = Curve((x, x**2), (x, 0, 1)) @@ -1003,6 +1065,46 @@ assert Point(1, 1).translate(4, 5) == \ Point(5, 6) assert scale(1, 2, (3, 4)).tolist() == \ - [[1, 0, 0], [0, 2, 0], [0, -4, 1]] + [[1, 0, 0], [0, 2, 0], [0, -4, 1]] assert RegularPolygon((0, 0), 1, 4).scale(2, 3, (4, 5)) == \ Polygon(Point(-2, -10), Point(-4, -7), Point(-6, -10), Point(-4, -13)) + +def test_reflect(): + b = Symbol('b') + m = Symbol('m') + l = Line((0, b), slope=m) + p = Point(x, y) + r = p.reflect(l) + dp = l.perpendicular_segment(p).length + dr = l.perpendicular_segment(r).length + assert test_numerically(dp, dr) + t = Triangle((0, 0), (1, 0), (2, 3)) + assert t.area == -t.reflect(l).area + e = Ellipse((1, 0), 1, 2) + assert e.area == -e.reflect(Line((1, 0), slope=0)).area + assert e.area == -e.reflect(Line((1, 0), slope=oo)).area + raises(NotImplementedError, lambda: e.reflect(Line((1,0), slope=m))) + assert Polygon((1, 0), (2, 0), (2, 2)).reflect(Line((3, 0), slope=oo)) \ + == Triangle(Point(5, 0), Point(4, 0), Point(4, 2)) + assert Polygon((1, 0), (2, 0), (2, 2)).reflect(Line((0, 3), slope=oo)) \ + == Triangle(Point(-1, 0), Point(-2, 0), Point(-2, 2)) + assert Polygon((1, 0), (2, 0), (2, 2)).reflect(Line((0, 3), slope=0)) \ + == Triangle(Point(1, 6), Point(2, 6), Point(2, 4)) + assert Polygon((1, 0), (2, 0), (2, 2)).reflect(Line((3, 0), slope=0)) \ + == Triangle(Point(1, 0), Point(2, 0), Point(2, -2)) + + # test entity overrides + c = Circle((x, y), 3) + cr = c.reflect(l) + assert cr == Circle(r, -3) + assert c.area == -cr.area + pent = RegularPolygon((1, 2), 1, 5) + l = Line((0, pi), slope=sqrt(2)) + rpent = pent.reflect(l) + poly_pent = Polygon(*pent.vertices) + assert rpent.center == pent.center.reflect(l) + assert str([w.n(3) for w in rpent.vertices]) == ( + '[Point(-0.586, 4.27), Point(-1.69, 4.66), ' + 'Point(-2.41, 3.73), Point(-1.74, 2.76), ' + 'Point(-0.616, 3.10)]') + assert pent.area.equals(-rpent.area) diff -Nru python3-sympy-0.7.2/sympy/geometry/util.py python3-sympy-0.7.3/sympy/geometry/util.py --- python3-sympy-0.7.2/sympy/geometry/util.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/geometry/util.py 2013-07-13 17:53:32.000000000 +0000 @@ -9,6 +9,7 @@ """ from sympy import Symbol, Function, solve + def idiff(eq, y, x, dep=None): """Return dy/dx assuming that y and any other variables given in dep depend on x. @@ -34,11 +35,13 @@ dep = set(dep) dep.add(y) - f = dict([(s, Function(s.name)(x)) for s in eq.atoms(Symbol) if s != x and s in dep]) + f = dict([(s, Function( + s.name)(x)) for s in eq.atoms(Symbol) if s != x and s in dep]) dydx = Function(y.name)(x).diff(x) return solve(eq.subs(f).diff(x), dydx)[0].subs( [(b, a) for a, b in f.items()]) + def _symbol(s, matching_symbol=None): """Return s if s is a Symbol, else return either a new Symbol (real=True) with the same name s or the matching_symbol if s is a string and it matches @@ -79,6 +82,7 @@ else: raise ValueError('symbol must be string for symbol name or Symbol') + def intersection(*entities): """The intersection of a collection of GeometryEntity instances. @@ -132,7 +136,8 @@ >>> intersection(c, Point(1, 0)) [Point(1, 0)] >>> intersection(c, l2) - [Point(-sqrt(5)/5 + 1, 2*sqrt(5)/5 + 1), Point(sqrt(5)/5 + 1, -2*sqrt(5)/5 + 1)] + [Point(-sqrt(5)/5 + 1, 2*sqrt(5)/5 + 1), + Point(sqrt(5)/5 + 1, -2*sqrt(5)/5 + 1)] """ from .entity import GeometryEntity @@ -181,7 +186,8 @@ [1] http://en.wikipedia.org/wiki/Graham_scan [2] Andrew's Monotone Chain Algorithm - ( A.M. Andrew, "Another Efficient Algorithm for Convex Hulls in Two Dimensions", 1979) + (A.M. Andrew, + "Another Efficient Algorithm for Convex Hulls in Two Dimensions", 1979) http://softsurfer.com/Archive/algorithm_0109/algorithm_0109.htm See Also @@ -217,7 +223,8 @@ elif isinstance(e, Polygon): p.update(e.vertices) else: - raise NotImplementedError('Convex hull for %s not implemented.' % type(e)) + raise NotImplementedError( + 'Convex hull for %s not implemented.' % type(e)) p = list(p) if len(p) == 1: @@ -307,7 +314,9 @@ except AttributeError: n1 = e1.__class__.__name__ n2 = e2.__class__.__name__ - raise GeometryError("Cannot test similarity between %s and %s" % (n1, n2)) + raise GeometryError( + "Cannot test similarity between %s and %s" % (n1, n2)) + def centroid(*args): """Find the centroid (center of mass) of the collection containing only Points, diff -Nru python3-sympy-0.7.2/sympy/integrals/deltafunctions.py python3-sympy-0.7.3/sympy/integrals/deltafunctions.py --- python3-sympy-0.7.2/sympy/integrals/deltafunctions.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/integrals/deltafunctions.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,7 +1,8 @@ -import sympy +from sympy.core import Mul from sympy.functions import DiracDelta, Heaviside from sympy.solvers import solve -from sympy.utilities.misc import default_sort_key +from sympy.core.compatibility import default_sort_key + def change_mul(node, x): """change_mul(node, x) @@ -25,11 +26,11 @@ >>> from sympy import DiracDelta, cos >>> from sympy.integrals.deltafunctions import change_mul >>> from sympy.abc import x, y - >>> change_mul(x*y*DiracDelta(x)*cos(x),x) + >>> change_mul(x*y*DiracDelta(x)*cos(x), x) (DiracDelta(x), x*y*cos(x)) - >>> change_mul(x*y*DiracDelta(x**2-1)*cos(x),x) + >>> change_mul(x*y*DiracDelta(x**2 - 1)*cos(x), x) (None, x*y*cos(x)*DiracDelta(x - 1)/2 + x*y*cos(x)*DiracDelta(x + 1)/2) - >>> change_mul(x*y*DiracDelta(cos(x))*cos(x),x) + >>> change_mul(x*y*DiracDelta(cos(x))*cos(x), x) (None, None) See Also @@ -38,7 +39,7 @@ sympy.functions.special.delta_functions.DiracDelta deltaintegrate """ - if not node.is_Mul: + if not (node.is_Mul or node.is_Pow): return node new_args = [] @@ -51,27 +52,29 @@ sorted_args.extend(nc) for arg in sorted_args: - if arg.func == DiracDelta and arg.is_simple(x) \ - and (len(arg.args) <= 1 or arg.args[1]==0): - if dirac is None: - dirac = arg - else: - new_args.append(arg) + if arg.is_Pow and arg.base.func is DiracDelta: + new_args.append(arg.func(arg.base, arg.exp - 1)) + arg = arg.base + if dirac is None and (arg.func is DiracDelta and arg.is_simple(x) + and (len(arg.args) <= 1 or arg.args[1] == 0)): + dirac = arg else: - new_args.append(change_mul(arg, x)) - if not dirac: # there was no simple dirac + new_args.append(arg) + if not dirac: # there was no simple dirac new_args = [] for arg in sorted_args: - if arg.func == DiracDelta: + if arg.func is DiracDelta: new_args.append(arg.simplify(x)) + elif arg.is_Pow and arg.base.func is DiracDelta: + new_args.append(arg.func(arg.base.simplify(x), arg.exp)) else: new_args.append(change_mul(arg, x)) if new_args != sorted_args: - nnode = node.__class__(*new_args).expand() - else: #if the node didn't change there is nothing to do + nnode = Mul(*new_args).expand() + else: # if the node didn't change there is nothing to do nnode = None return (None, nnode) - return (dirac, node.func(*new_args)) + return (dirac, Mul(*new_args)) def deltaintegrate(f, x): @@ -129,38 +132,43 @@ """ if not f.has(DiracDelta): return None + + from sympy.integrals import Integral, integrate + # g(x) = DiracDelta(h(x)) if f.func == DiracDelta: h = f.simplify(x) - if h == f:#can't simplify the expression + if h == f: # can't simplify the expression #FIXME: the second term tells whether is DeltaDirac or Derivative #For integrating derivatives of DiracDelta we need the chain rule if f.is_simple(x): - if (len(f.args) <= 1 or f.args[1]==0): + if (len(f.args) <= 1 or f.args[1] == 0): return Heaviside(f.args[0]) else: - return (DiracDelta(f.args[0],f.args[1]-1)/ f.args[0].as_poly().LC()) - else:#let's try to integrate the simplified expression - fh = sympy.integrals.integrate(h, x) + return (DiracDelta(f.args[0], f.args[1] - 1) / + f.args[0].as_poly().LC()) + else: # let's try to integrate the simplified expression + fh = integrate(h, x) return fh - elif f.is_Mul: #g(x)=a*b*c*f(DiracDelta(h(x)))*d*e + elif f.is_Mul or f.is_Pow: # g(x) = a*b*c*f(DiracDelta(h(x)))*d*e g = f.expand() - if f != g:#the expansion worked - fh = sympy.integrals.integrate(g, x) - if fh and not isinstance(fh, sympy.integrals.Integral): + if f != g: # the expansion worked + fh = integrate(g, x) + if fh is not None and not isinstance(fh, Integral): return fh - else:#no expansion performed, try to extract a simple DiracDelta term + else: + # no expansion performed, try to extract a simple DiracDelta term dg, rest_mult = change_mul(f, x) if not dg: if rest_mult: - fh = sympy.integrals.integrate(rest_mult, x) + fh = integrate(rest_mult, x) return fh else: dg = dg.simplify(x) - if dg.is_Mul: # Take out any extracted factors + if dg.is_Mul: # Take out any extracted factors dg, rest_mult_2 = change_mul(dg, x) rest_mult = rest_mult*rest_mult_2 - point = solve(dg.args[0],x)[0] + point = solve(dg.args[0], x)[0] return (rest_mult.subs(x, point)*Heaviside(x - point)) return None diff -Nru python3-sympy-0.7.2/sympy/integrals/heurisch.py python3-sympy-0.7.3/sympy/integrals/heurisch.py --- python3-sympy-0.7.2/sympy/integrals/heurisch.py 1970-01-01 00:00:00.000000000 +0000 +++ python3-sympy-0.7.3/sympy/integrals/heurisch.py 2013-07-13 17:53:32.000000000 +0000 @@ -0,0 +1,557 @@ +from collections import defaultdict + +from sympy.core.add import Add +from sympy.core.basic import Basic +from sympy.core.mul import Mul +from sympy.core.symbol import Symbol, Wild, Dummy +from sympy.core.basic import C, sympify +from sympy.core.numbers import Rational, I, pi +from sympy.core.relational import Eq +from sympy.core.singleton import S +from sympy.core.compatibility import permutations + +from sympy.functions import exp, sin, cos, tan, cot, asin, atan +from sympy.functions import log, sinh, cosh, tanh, coth, asinh, acosh +from sympy.functions import sqrt, erf, erfi, li, Ei +from sympy.functions.elementary.piecewise import Piecewise + +from sympy.logic.boolalg import And +from sympy.solvers.solvers import solve, denoms +from sympy.utilities.iterables import uniq + +from sympy.polys import quo, gcd, lcm, \ + monomials, factor, cancel, PolynomialError +from sympy.polys.polyroots import root_factors + +from sympy.core.compatibility import reduce, default_sort_key +from functools import reduce + + +def components(f, x): + """ + Returns a set of all functional components of the given expression + which includes symbols, function applications and compositions and + non-integer powers. Fractional powers are collected with with + minimal, positive exponents. + + >>> from sympy import cos, sin + >>> from sympy.abc import x, y + >>> from sympy.integrals.heurisch import components + + >>> components(sin(x)*cos(x)**2, x) + set([x, sin(x), cos(x)]) + + See Also + ======== + + heurisch + """ + result = set() + + if x in f.free_symbols: + if f.is_Symbol: + result.add(f) + elif f.is_Function or f.is_Derivative: + for g in f.args: + result |= components(g, x) + + result.add(f) + elif f.is_Pow: + result |= components(f.base, x) + + if not f.exp.is_Integer: + if f.exp.is_Rational: + result.add(f.base**Rational(1, f.exp.q)) + else: + result |= components(f.exp, x) | set([f]) + else: + for g in f.args: + result |= components(g, x) + + return result + +# name -> [] of symbols +_symbols_cache = {} + + +# NB @cacheit is not convenient here +def _symbols(name, n): + """get vector of symbols local to this module""" + try: + lsyms = _symbols_cache[name] + except KeyError: + lsyms = [] + _symbols_cache[name] = lsyms + + while len(lsyms) < n: + lsyms.append( Dummy('%s%i' % (name, len(lsyms))) ) + + return lsyms[:n] + + +def heurisch_wrapper(f, x, rewrite=False, hints=None, mappings=None, retries=3, + degree_offset=0, unnecessary_permutations=None): + """ + A wrapper around the heurisch integration algorithm. + + This method takes the result from heurisch and checks for poles in the + denominator. For each of these poles, the integral is reevaluated, and + the final integration result is given in terms of a Piecewise. + + Examples + ======== + + >>> from sympy.core import symbols + >>> from sympy.functions import cos + >>> from sympy.integrals.heurisch import heurisch, heurisch_wrapper + >>> n, x = symbols('n x') + >>> heurisch(cos(n*x), x) + sin(n*x)/n + >>> heurisch_wrapper(cos(n*x), x) + Piecewise((x, n == 0), (sin(n*x)/n, True)) + + See Also + ======== + + heurisch + """ + f = sympify(f) + if x not in f.free_symbols: + return f*x + + res = heurisch(f, x, rewrite, hints, mappings, retries, degree_offset, + unnecessary_permutations) + if not isinstance(res, Basic): + return res + # We consider each denominator in the expression, and try to find + # cases where one or more symbolic denominator might be zero. The + # conditions for these cases are stored in the list slns. + slns = [] + for d in denoms(res): + try: + slns += solve(d, dict=True, exclude=(x,)) + except NotImplementedError: + pass + if not slns: + return res + slns = list(uniq(slns)) + # Remove the solutions corresponding to poles in the original expression. + slns0 = [] + for d in denoms(f): + try: + slns0 += solve(d, dict=True, exclude=(x,)) + except NotImplementedError: + pass + slns = [s for s in slns if s not in slns0] + if not slns: + return res + if len(slns) > 1: + eqs = [] + for sub_dict in slns: + eqs.extend([Eq(key, value) for key, value in sub_dict.items()]) + slns = solve(eqs, dict=True, exclude=(x,)) + slns + # For each case listed in the list slns, we reevaluate the integral. + pairs = [] + for sub_dict in slns: + expr = heurisch(f.subs(sub_dict), x, rewrite, hints, mappings, retries, + degree_offset, unnecessary_permutations) + cond = And(*[Eq(key, value) for key, value in sub_dict.items()]) + pairs.append((expr, cond)) + pairs.append((heurisch(f, x, rewrite, hints, mappings, retries, + degree_offset, unnecessary_permutations), True)) + return Piecewise(*pairs) + + +def heurisch(f, x, rewrite=False, hints=None, mappings=None, retries=3, + degree_offset=0, unnecessary_permutations=None): + """ + Compute indefinite integral using heuristic Risch algorithm. + + This is a heuristic approach to indefinite integration in finite + terms using the extended heuristic (parallel) Risch algorithm, based + on Manuel Bronstein's "Poor Man's Integrator". + + The algorithm supports various classes of functions including + transcendental elementary or special functions like Airy, + Bessel, Whittaker and Lambert. + + Note that this algorithm is not a decision procedure. If it isn't + able to compute the antiderivative for a given function, then this is + not a proof that such a functions does not exist. One should use + recursive Risch algorithm in such case. It's an open question if + this algorithm can be made a full decision procedure. + + This is an internal integrator procedure. You should use toplevel + 'integrate' function in most cases, as this procedure needs some + preprocessing steps and otherwise may fail. + + Specification + ============= + + heurisch(f, x, rewrite=False, hints=None) + + where + f : expression + x : symbol + + rewrite -> force rewrite 'f' in terms of 'tan' and 'tanh' + hints -> a list of functions that may appear in anti-derivate + + - hints = None --> no suggestions at all + - hints = [ ] --> try to figure out + - hints = [f1, ..., fn] --> we know better + + Examples + ======== + + >>> from sympy import tan + >>> from sympy.integrals.heurisch import heurisch + >>> from sympy.abc import x, y + + >>> heurisch(y*tan(x), x) + y*log(tan(x)**2 + 1)/2 + + See Manuel Bronstein's "Poor Man's Integrator": + + [1] http://www-sop.inria.fr/cafe/Manuel.Bronstein/pmint/index.html + + For more information on the implemented algorithm refer to: + + [2] K. Geddes, L. Stefanus, On the Risch-Norman Integration + Method and its Implementation in Maple, Proceedings of + ISSAC'89, ACM Press, 212-217. + + [3] J. H. Davenport, On the Parallel Risch Algorithm (I), + Proceedings of EUROCAM'82, LNCS 144, Springer, 144-157. + + [4] J. H. Davenport, On the Parallel Risch Algorithm (III): + Use of Tangents, SIGSAM Bulletin 16 (1982), 3-6. + + [5] J. H. Davenport, B. M. Trager, On the Parallel Risch + Algorithm (II), ACM Transactions on Mathematical + Software 11 (1985), 356-362. + + See Also + ======== + + sympy.integrals.integrals.Integral.doit + sympy.integrals.integrals.Integral + components + """ + f = sympify(f) + if x not in f.free_symbols: + return f*x + + if not f.is_Add: + indep, f = f.as_independent(x) + else: + indep = S.One + + rewritables = { + (sin, cos, cot): tan, + (sinh, cosh, coth): tanh, + } + + if rewrite: + for candidates, rule in rewritables.items(): + f = f.rewrite(candidates, rule) + else: + for candidates in rewritables.keys(): + if f.has(*candidates): + break + else: + rewrite = True + + terms = components(f, x) + + if hints is not None: + if not hints: + a = Wild('a', exclude=[x]) + b = Wild('b', exclude=[x]) + c = Wild('c', exclude=[x]) + + for g in set(terms): + if g.is_Function: + if g.func is li: + M = g.args[0].match(a*x**b) + + if M is not None: + terms.add( x*(li(M[a]*x**M[b]) - (M[a]*x**M[b])**(-1/M[b])*Ei((M[b]+1)*log(M[a]*x**M[b])/M[b])) ) + #terms.add( x*(li(M[a]*x**M[b]) - (x**M[b])**(-1/M[b])*Ei((M[b]+1)*log(M[a]*x**M[b])/M[b])) ) + #terms.add( x*(li(M[a]*x**M[b]) - x*Ei((M[b]+1)*log(M[a]*x**M[b])/M[b])) ) + #terms.add( li(M[a]*x**M[b]) - Ei((M[b]+1)*log(M[a]*x**M[b])/M[b]) ) + + elif g.func is exp: + M = g.args[0].match(a*x**2) + + if M is not None: + if M[a].is_positive: + terms.add(erfi(sqrt(M[a])*x)) + else: # M[a].is_negative or unknown + terms.add(erf(sqrt(-M[a])*x)) + + M = g.args[0].match(a*x**2 + b*x + c) + + if M is not None: + if M[a].is_positive: + terms.add(sqrt(pi/4*(-M[a]))*exp(M[c] - M[b]**2/(4*M[a]))* + erfi(sqrt(M[a])*x + M[b]/(2*sqrt(M[a])))) + elif M[a].is_negative: + terms.add(sqrt(pi/4*(-M[a]))*exp(M[c] - M[b]**2/(4*M[a]))* + erf(sqrt(-M[a])*x - M[b]/(2*sqrt(-M[a])))) + + M = g.args[0].match(a*log(x)**2) + + if M is not None: + if M[a].is_positive: + terms.add(erfi(sqrt(M[a])*log(x) + 1/(2*sqrt(M[a])))) + if M[a].is_negative: + terms.add(erf(sqrt(-M[a])*log(x) - 1/(2*sqrt(-M[a])))) + + elif g.is_Pow: + if g.exp.is_Rational and g.exp.q == 2: + M = g.base.match(a*x**2 + b) + + if M is not None and M[b].is_positive: + if M[a].is_positive: + terms.add(asinh(sqrt(M[a]/M[b])*x)) + elif M[a].is_negative: + terms.add(asin(sqrt(-M[a]/M[b])*x)) + + M = g.base.match(a*x**2 - b) + + if M is not None and M[b].is_positive: + if M[a].is_positive: + terms.add(acosh(sqrt(M[a]/M[b])*x)) + elif M[a].is_negative: + terms.add((-M[b]/2*sqrt(-M[a])* + atan(sqrt(-M[a])*x/sqrt(M[a]*x**2 - M[b])))) + + else: + terms |= set(hints) + + for g in set(terms): + terms |= components(cancel(g.diff(x)), x) + + # TODO: caching is significant factor for why permutations work at all. Change this. + V = _symbols('x', len(terms)) + + mapping = dict(list(zip(terms, V))) + + rev_mapping = {} + + if unnecessary_permutations is None: + unnecessary_permutations = [] + for k, v in mapping.items(): + rev_mapping[v] = k + + if mappings is None: + # Pre-sort mapping in order of largest to smallest expressions (last is always x). + def _sort_key(arg): + return default_sort_key(arg[0].as_independent(x)[1]) + #optimizing the number of permutations of mappping + unnecessary_permutations = [(x, mapping[x])] + del mapping[x] + mapping = sorted(list(mapping.items()), key=_sort_key, reverse=True) + mappings = permutations(mapping) + + def _substitute(expr): + return expr.subs(mapping) + + for mapping in mappings: + mapping = list(mapping) + mapping = mapping + unnecessary_permutations + diffs = [ _substitute(cancel(g.diff(x))) for g in terms ] + denoms = [ g.as_numer_denom()[1] for g in diffs ] + if all(h.is_polynomial(*V) for h in denoms) and _substitute(f).is_rational_function(*V): + denom = reduce(lambda p, q: lcm(p, q, *V), denoms) + break + else: + if not rewrite: + result = heurisch(f, x, rewrite=True, hints=hints, unnecessary_permutations=unnecessary_permutations) + + if result is not None: + return indep*result + return None + + numers = [ cancel(denom*g) for g in diffs ] + def _derivation(h): + return Add(*[ d * h.diff(v) for d, v in zip(numers, V) ]) + + def _deflation(p): + for y in V: + if not p.has(y): + continue + + if _derivation(p) is not S.Zero: + c, q = p.as_poly(y).primitive() + return _deflation(c)*gcd(q, q.diff(y)).as_expr() + else: + return p + + def _splitter(p): + for y in V: + if not p.has(y): + continue + + if _derivation(y) is not S.Zero: + c, q = p.as_poly(y).primitive() + + q = q.as_expr() + + h = gcd(q, _derivation(q), y) + s = quo(h, gcd(q, q.diff(y), y), y) + + c_split = _splitter(c) + + if s.as_poly(y).degree() == 0: + return (c_split[0], q * c_split[1]) + + q_split = _splitter(cancel(q / s)) + + return (c_split[0]*q_split[0]*s, c_split[1]*q_split[1]) + else: + return (S.One, p) + + special = {} + + for term in terms: + if term.is_Function: + if term.func is tan: + special[1 + _substitute(term)**2] = False + elif term.func is tanh: + special[1 + _substitute(term)] = False + special[1 - _substitute(term)] = False + elif term.func is C.LambertW: + special[_substitute(term)] = True + + F = _substitute(f) + + P, Q = F.as_numer_denom() + + u_split = _splitter(denom) + v_split = _splitter(Q) + + polys = list(v_split) + [ u_split[0] ] + list(special.keys()) + + s = u_split[0] * Mul(*[ k for k, v in special.items() if v ]) + polified = [ p.as_poly(*V) for p in [s, P, Q] ] + + if None in polified: + return None + + a, b, c = [ p.total_degree() for p in polified ] + + poly_denom = (s * v_split[0] * _deflation(v_split[1])).as_expr() + + def _exponent(g): + if g.is_Pow: + if g.exp.is_Rational and g.exp.q != 1: + if g.exp.p > 0: + return g.exp.p + g.exp.q - 1 + else: + return abs(g.exp.p + g.exp.q) + else: + return 1 + elif not g.is_Atom and g.args: + return max([ _exponent(h) for h in g.args ]) + else: + return 1 + + A, B = _exponent(f), a + max(b, c) + + if A > 1 and B > 1: + monoms = monomials(V, A + B - 1 + degree_offset) + else: + monoms = monomials(V, A + B + degree_offset) + + poly_coeffs = _symbols('A', len(monoms)) + + poly_part = Add(*[ poly_coeffs[i]*monomial + for i, monomial in enumerate(monoms) ]) + + reducibles = set() + + for poly in polys: + if poly.has(*V): + try: + factorization = factor(poly, greedy=True) + except PolynomialError: + factorization = poly + factorization = poly + + if factorization.is_Mul: + reducibles |= set(factorization.args) + else: + reducibles.add(factorization) + + def _integrate(field=None): + irreducibles = set() + + for poly in reducibles: + for z in poly.atoms(Symbol): + if z in V: + break + else: + continue + + irreducibles |= set(root_factors(poly, z, filter=field)) + + log_coeffs, log_part = [], [] + B = _symbols('B', len(irreducibles)) + + for i, poly in enumerate(irreducibles): + if poly.has(*V): + log_coeffs.append(B[i]) + log_part.append(log_coeffs[-1] * log(poly)) + + coeffs = poly_coeffs + log_coeffs + + candidate = poly_part/poly_denom + Add(*log_part) + + h = F - _derivation(candidate) / denom + + numer = h.as_numer_denom()[0].expand(force=True) + + equations = defaultdict(lambda: S.Zero) + + for term in Add.make_args(numer): + coeff, dependent = term.as_independent(*V) + equations[dependent] += coeff + + solution = solve(list(equations.values()), *coeffs) + + return (solution, candidate, coeffs) if solution else None + + if not (F.atoms(Symbol) - set(V)): + result = _integrate('Q') + + if result is None: + result = _integrate() + else: + result = _integrate() + + if result is not None: + (solution, candidate, coeffs) = result + + antideriv = candidate.subs(solution) + + for coeff in coeffs: + if coeff not in solution: + antideriv = antideriv.subs(coeff, S.Zero) + + antideriv = antideriv.subs(rev_mapping) + antideriv = cancel(antideriv).expand(force=True) + + if antideriv.is_Add: + antideriv = antideriv.as_independent(x)[1] + + return indep * antideriv + else: + if retries >= 0: + result = heurisch(f, x, mappings=mappings, rewrite=rewrite, hints=hints, retries=retries - 1, unnecessary_permutations=unnecessary_permutations) + + if result is not None: + return indep*result + + return None diff -Nru python3-sympy-0.7.2/sympy/integrals/integrals.py python3-sympy-0.7.3/sympy/integrals/integrals.py --- python3-sympy-0.7.2/sympy/integrals/integrals.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/integrals/integrals.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,12 +1,20 @@ -from sympy.core import (Basic, Expr, S, C, Symbol, Wild, Add, sympify, diff, - oo, Tuple, Interval) - -from sympy.core.symbol import Dummy +from sympy.core.add import Add +from sympy.core.basic import Basic, C from sympy.core.compatibility import is_sequence +from sympy.core.containers import Tuple +from sympy.core.expr import Expr +from sympy.core.function import diff +from sympy.core.numbers import oo +from sympy.core.relational import Eq +from sympy.core.sets import Interval +from sympy.core.singleton import S +from sympy.core.symbol import (Dummy, Symbol, Wild) +from sympy.core.sympify import sympify +from sympy.integrals.manualintegrate import manualintegrate from sympy.integrals.trigonometry import trigintegrate from sympy.integrals.deltafunctions import deltaintegrate from sympy.integrals.rationaltools import ratint -from sympy.integrals.risch import heurisch +from sympy.integrals.heurisch import heurisch, heurisch_wrapper from sympy.integrals.meijerint import meijerint_definite, meijerint_indefinite from sympy.utilities import xthreaded, flatten from sympy.utilities.misc import filldedent @@ -17,8 +25,42 @@ from sympy.functions.elementary.piecewise import piecewise_fold from sympy.series import limit + +# TODO get these helper functions into a super class for sum-like +# objects: Sum, Product, Integral (issue 3662) + +def _free_symbols(expr_with_limits): + """ + This method returns the symbols that will exist when the object is + evaluated. This is useful if one is trying to determine whether the + objet contains a certain symbol or not. + + Examples + ======== + + >>> from sympy import Sum + >>> from sympy.abc import x, y + >>> Sum(x, (x, y, 1)).free_symbols + set([y]) + """ + self = expr_with_limits + function = self.function + if function.is_zero: + return set() + limits = self.limits + isyms = function.free_symbols + for xab in limits: + # take out the target symbol + if xab[0] in isyms: + isyms.remove(xab[0]) + # add in the new symbols + for i in xab[1:]: + isyms.update(i.free_symbols) + return isyms + + def _process_limits(*symbols): - """Convert the symbols-related limits into proper limits, + """Process the list of symbols and convert them to canonical limits, storing them as Tuple(symbol, lower, upper). The sign of the function is also returned when the upper limit is missing so (x, 1, None) becomes (x, None, 1) and the sign is changed. @@ -59,6 +101,157 @@ return limits, sign + +def _as_dummy(expr_with_limits): + """ + Replace instances of the limit variables with their dummy + counterparts to make clear what are dummy variables and what + are real-world symbols in an object. + + Examples + ======== + + >>> from sympy import Integral + >>> from sympy.abc import x, y + >>> Integral(x, (x, x, y), (y, x, y)).as_dummy() + Integral(_x, (_x, x, _y), (_y, x, y)) + + If the object supperts the "integral at" limit ``(x,)`` it + is not treated as a dummy, but the explicit form, ``(x, x)`` + of length 2 does treat the variable as a dummy. + + >>> Integral(x, x).as_dummy() + Integral(x, x) + >>> Integral(x, (x, x)).as_dummy() + Integral(_x, (_x, x)) + + If there were no dummies in the original expression, then the + the symbols which cannot be changed by subs() are clearly seen as + those with an underscore prefix. + + See Also + ======== + + variables : Lists the integration variables + transform : Perform mapping on the integration variable + """ + self = expr_with_limits + reps = {} + f = self.function + limits = list(self.limits) + for i in range(-1, -len(limits) - 1, -1): + xab = list(limits[i]) + if len(xab) == 1: + continue + x = xab[0] + xab[0] = x.as_dummy() + for j in range(1, len(xab)): + xab[j] = xab[j].subs(reps) + reps[x] = xab[0] + limits[i] = xab + f = f.subs(reps) + return self.func(f, *limits) + + +def _eval_subs(expr_with_limits, old, new): + """ + Substitute old with new in the function and the limits, but don't + change anything that is (or corresponds to) a bound symbol, + + The normal substitution semantics -- traversing all arguments looking + for matching patterns -- should not be applied to the sum-like objects + since changing the limit variables should also entail a change in the + limits (which should be done with the transform method). So + this method just makes changes in the function and the limits. + + Not all instances of a given variable are conceptually the same: the + first argument of the limit tuple with length greater than 1 and any + corresponding variable in the function are dummy variables while + every other symbol is a symbol that will be unchanged when the integral + is evaluated. For example, the dummy variables for ``i`` can be seen + as symbols with a preppended underscore. (The discussion below applies + ti Integral and any other "function with limits" sort of objects.) + + >>> from sympy import Integral + >>> from sympy.abc import a, b, c, x, y + >>> i = Integral(a + x, (a, a, b)) + >>> i.as_dummy() + Integral(_a + x, (_a, a, b)) + + If you want to change the lower limit to 1 there is no reason to + prohibit this since it is not conceptually related to the integration + variable, ``_a``. Nor is there reason to disallow changing the ``b`` + to 1. + + If a second limit were added, however, as in: + + >>> i = Integral(x + a, (a, a, b), (b, 1, 2)) + + the dummy variables become: + + >>> i.as_dummy() + Integral(_a + x, (_a, a, _b), (_b, 1, 2)) + + Note that the ``b`` of the first limit is now a dummy variable since + ``b`` is a dummy variable in the second limit. + + The "evaluate at" form of an integral allows some flexibility in how + the integral will be treated by subs: if there is no second argument, + none of the symbols matching the integration symbol are considered to + be dummy variables, but if an explicit expression is given for a limit + then the usual interpretation of the integration symbol as a dummy + symbol applies: + + >>> Integral(x).as_dummy() # implicit integration wrt x + Integral(x, x) + >>> Integral(x, x).as_dummy() + Integral(x, x) + >>> _.subs(x, 1) + Integral(1, x) + >>> i = Integral(x, (x, x)) + >>> i.as_dummy() + Integral(_x, (_x, x)) + >>> i.subs(x, 1) + Integral(x, (x, 1)) + + Summary + ======= + + No variable of the integrand or limit can be the target of + substitution if it appears as a variable of integration in a limit + positioned to the right of it. The only exception is for a variable + that defines an indefinite integral limit (a single symbol): that + symbol *can* be replaced in the integrand. + + >>> i = Integral(a + x, (a, a, 3), (b, x, c)) + >>> i.free_symbols # only these can be changed + set([a, c, x]) + >>> i.subs(a, c) # note that the variable of integration is unchanged + Integral(a + x, (a, c, 3), (b, x, c)) + >>> i.subs(a + x, b) == i # there is no x + a, only x + + True + >>> i.subs(x, y - c) + Integral(a - c + y, (a, a, 3), (b, -c + y, c)) + """ + self = expr_with_limits + func, limits = self.function, self.limits + old_atoms = old.free_symbols + limits = list(limits) + + dummies = set() + for i in range(-1, -len(limits) - 1, -1): + xab = limits[i] + if len(xab) == 1: + continue + if not dummies.intersection(old_atoms): + limits[i] = Tuple( + xab[0], *[l._subs(old, new) for l in xab[1:]]) + dummies.add(xab[0]) + if not dummies.intersection(old_atoms): + func = func.subs(old, new) + return self.func(func, *limits) + + class Integral(Expr): """Represents unevaluated integral.""" @@ -126,7 +319,8 @@ # no symbols provided -- let's compute full anti-derivative free = function.free_symbols if len(free) != 1: - raise ValueError("specify variables of integration for %s" % function) + raise ValueError( + "specify variables of integration for %s" % function) limits, sign = [Tuple(s) for s in free], 1 while isinstance(function, Integral): @@ -138,7 +332,7 @@ arglist = [sign*function] arglist.extend(limits) obj._args = tuple(arglist) - obj.is_commutative = function.is_commutative # limits already checked + obj.is_commutative = function.is_commutative # limits already checked return obj @@ -272,7 +466,7 @@ is_number """ if (self.function.is_zero or - any(len(xab) == 3 and xab[1] == xab[2] for xab in self.limits)): + any(len(xab) == 3 and xab[1] == xab[2] for xab in self.limits)): return True if not self.free_symbols and self.function.is_number: # the integrand is a number and the limits are numerical @@ -283,18 +477,14 @@ """ Return True if the Integral will result in a number, else False. - sympy considers anything that will result in a number to have - is_number == True. - - >>> from sympy import log - >>> log(2).is_number - True - Integrals are a special case since they contain symbols that can be replaced with numbers. Whether the integral can be done or not is another issue. But answering whether the final result is a number is not difficult. + Examples + ======== + >>> from sympy import Integral >>> from sympy.abc import x, y >>> Integral(x).is_number @@ -325,9 +515,9 @@ for xab in limits: if len(xab) == 1: isyms.add(xab[0]) - continue # it may be removed later - elif len(xab) == 3 and xab[1] == xab[2]: # XXX naive equality test - return True # integral collapsed + continue # it may be removed later + elif len(xab) == 3 and xab[1] == xab[2]: # XXX naive equality test + return True # integral collapsed if xab[0] in isyms: # take it out of the symbols since it will be replace # with whatever the limits of the integral are @@ -339,50 +529,7 @@ return len(isyms) == 0 def as_dummy(self): - """ - Replace instances of the integration variables with their dummy - counterparts to make clear what are dummy variables and what - are real-world symbols in an Integral. - - >>> from sympy import Integral - >>> from sympy.abc import x, y - >>> Integral(x, (x, x, y), (y, x, y)).as_dummy() - Integral(_x, (_x, x, _y), (_y, x, y)) - - The "integral at" limit that has a length of 1 is not treated as - though the integration symbol is a dummy, but the explicit form - of length 2 does treat the integration variable as a dummy. - - >>> Integral(x, x).as_dummy() - Integral(x, x) - >>> Integral(x, (x, x)).as_dummy() - Integral(_x, (_x, x)) - - If there were no dummies in the original expression, then the - output of this function will show which symbols cannot be - changed by subs(), those with an underscore prefix. - - See Also - ======== - - variables : Lists the integration variables - transform : Perform mapping on the integration variable - """ - reps = {} - f = self.function - limits = list(self.limits) - for i in range(-1, -len(limits) - 1, -1): - xab = list(limits[i]) - if len(xab) == 1: - continue - x = xab[0] - xab[0] = x.as_dummy() - for j in range(1, len(xab)): - xab[j] = xab[j].subs(reps) - reps[x] = xab[0] - limits[i] = xab - f = f.subs(reps) - return Integral(f, *limits) + return _as_dummy(self) def transform(self, x, u, inverse=False): r""" @@ -495,9 +642,9 @@ # when this is removed, update the docstring from sympy.utilities.exceptions import SymPyDeprecationWarning SymPyDeprecationWarning( - feature="transform(x, f(x), inverse=True)", - useinstead="transform(f(x), x)", - issue=3380, deprecated_since_version="0.7.2", + feature="transform(x, f(x), inverse=True)", + useinstead="transform(f(x), x)", + issue=3380, deprecated_since_version="0.7.2", ).warn() # in the old style x and u contained the same variable so # don't worry about using the old-style feature with the @@ -509,7 +656,8 @@ xfree = x.free_symbols.intersection(self.variables) if len(xfree) > 1: - raise ValueError('F(x) can only contain one of: %s' % self.variables) + raise ValueError( + 'F(x) can only contain one of: %s' % self.variables) xvar = xfree.pop() if xfree else d if xvar not in self.variables: @@ -613,7 +761,7 @@ else: newlimits.append(xab) - return Integral(newfunc, *newlimits) + return self.func(newfunc, *newlimits) def doit(self, **hints): """ @@ -625,7 +773,7 @@ >>> from sympy import Integral >>> from sympy.abc import x, i >>> Integral(x**i, (i, 1, 3)).doit() - x**3/log(x) - x/log(x) + Piecewise((2, log(x) == 0), (x**3/log(x) - x/log(x), True)) See Also ======== @@ -641,10 +789,16 @@ deep = hints.get('deep', True) meijerg = hints.get('meijerg', None) conds = hints.get('conds', 'piecewise') + risch = hints.get('risch', None) + manual = hints.get('manual', None) + if conds not in ['separate', 'piecewise', 'none']: - raise ValueError('conds must be one of "separate", "piecewise", ' \ + raise ValueError('conds must be one of "separate", "piecewise", ' '"none", got: %s' % conds) + if risch and any(len(xab) > 1 for xab in self.limits): + raise ValueError('risch=True is only allowed for indefinite integrals.') + # check for the trivial case of equal upper and lower limits if self.is_zero: return S.Zero @@ -660,7 +814,8 @@ # There is no trivial answer, so continue undone_limits = [] - ulj = set() # free symbols of any undone limits' upper and lower limits + # ulj = free symbols of any undone limits' upper and lower limits + ulj = set() for xab in self.limits: # compute uli, the free symbols in the # Upper and Lower limits of limit I @@ -703,7 +858,7 @@ (Integral(function, (x, a, b)), True)) elif conds == 'separate': if len(self.limits) != 1: - raise ValueError('conds=separate not supported in ' \ + raise ValueError('conds=separate not supported in ' 'multiple integrals') ret = f, cond else: @@ -712,8 +867,8 @@ meijerg1 = meijerg if len(xab) == 3 and xab[1].is_real and xab[2].is_real \ - and not function.is_Poly and \ - (xab[1].has(oo, -oo) or xab[2].has(oo, -oo)): + and not function.is_Poly and \ + (xab[1].has(oo, -oo) or xab[2].has(oo, -oo)): ret = try_meijerg(function, xab) if ret is not None: function = ret @@ -731,7 +886,10 @@ if meijerg1 is False and meijerg is True: antideriv = None else: - antideriv = self._eval_integral(function, xab[0], meijerg1) + antideriv = self._eval_integral( + function, xab[0], + meijerg=meijerg1, risch=risch, manual=manual, + conds=conds) if antideriv is None and meijerg1 is True: ret = try_meijerg(function, xab) if ret is not None: @@ -776,6 +934,16 @@ return self.func(*([function] + undone_limits)) return function + def _eval_adjoint(self): + if all([x.is_real for x in flatten(self.limits)]): + return self.func(self.function.adjoint(), *self.limits) + return None + + def _eval_conjugate(self): + if all([x.is_real for x in flatten(self.limits)]): + return self.func(self.function.conjugate(), *self.limits) + return None + def _eval_derivative(self, sym): """Evaluate the derivative of the current Integral object by differentiating under the integral sign [1], using the Fundamental @@ -829,8 +997,8 @@ a = b = None x = limit[0] - if limits: # f is the argument to an integral - f = Integral(f, *tuple(limits)) + if limits: # f is the argument to an integral + f = self.func(f, *tuple(limits)) # assemble the pieces def _do(f, ab): @@ -840,7 +1008,7 @@ if isinstance(f, Integral): limits = [(x, x) if (len(l) == 1 and l[0] == x) else l for l in f.limits] - f = Integral(f.function, *limits) + f = self.func(f.function, *limits) return f.subs(x, ab)*dab_dsym rv = 0 if b is not None: @@ -858,48 +1026,109 @@ # while differentiating u = Dummy('u') arg = f.subs(x, u).diff(sym).subs(u, x) - rv += Integral(arg, Tuple(x, a, b)) + rv += self.func(arg, Tuple(x, a, b)) return rv - def _eval_integral(self, f, x, meijerg=None): - """Calculate the anti-derivative to the function f(x). - - This is a powerful function that should in theory be able to integrate - everything that can be integrated. If you find something, that it - doesn't, it is easy to implement it. - - (1) Simple heuristics (based on pattern matching and integral table): - - - most frequently used functions (e.g. polynomials) - - functions non-integrable by any of the following algorithms (e.g. - exp(-x**2)) + def _eval_integral(self, f, x, meijerg=None, risch=None, manual=None, + conds='piecewise'): + """ + Calculate the anti-derivative to the function f(x). - (2) Integration of rational functions: + The following algorithms are applied (roughly in this order): - (a) using apart() - apart() is full partial fraction decomposition - procedure based on Bronstein-Salvy algorithm. It gives formal - decomposition with no polynomial factorization at all (so it's - fast and gives the most general results). However it needs an - implementation of the RootsOf class. - (b) using Trager's algorithm - possibly faster than (a) but needs - implementation :) + 1. Simple heuristics (based on pattern matching and integral table): - (3) Whichever implementation of pmInt (Mateusz, Kirill's or a - combination of both). + - most frequently used functions (e.g. polynomials, products of trig functions) - - this way we can handle efficiently huge class of elementary and - special functions + 2. Integration of rational functions: + + - A complete algorithm for integrating rational functions is + implemented (the Lazard-Rioboo-Trager algorithm). The algorithm + also uses the partial fraction decomposition algorithm + implemented in apart() as a preprocessor to make this process + faster. Note that the integral of a rational function is always + elementary, but in general, it may include a RootSum. + + 3. Full Risch algorithm: + + - The Risch algorithm is a complete decision + procedure for integrating elementary functions, which means that + given any elementary function, it will either compute an + elementary antiderivative, or else prove that none exists. + Currently, part of transcendental case is implemented, meaning + elementary integrals containing exponentials, logarithms, and + (soon!) trigonometric functions can be computed. The algebraic + case, e.g., functions containing roots, is much more difficult + and is not implemented yet. + + - If the routine fails (because the integrand is not elementary, or + because a case is not implemented yet), it continues on to the + next algorithms below. If the routine proves that the integrals + is nonelementary, it still moves on to the algorithms below, + because we might be able to find a closed-form solution in terms + of special functions. If risch=True, however, it will stop here. + + 4. The Meijer G-Function algorithm: + + - This algorithm works by first rewriting the integrand in terms of + very general Meijer G-Function (meijerg in SymPy), integrating + it, and then rewriting the result back, if possible. This + algorithm is particularly powerful for definite integrals (which + is actually part of a different method of Integral), since it can + compute closed-form solutions of definite integrals even when no + closed-form indefinite integral exists. But it also is capable + of computing many indefinite integrals as well. + + - Another advantage of this method is that it can use some results + about the Meijer G-Function to give a result in terms of a + Piecewise expression, which allows to express conditionally + convergent integrals. + + - Setting meijerg=True will cause integrate() to use only this + method. + + 5. The "manual integration" algorithm: + + - This algorithm tries to mimic how a person would find an + antiderivative by hand, for example by looking for a + substitution or applying integration by parts. This algorithm + does not handle as many integrands but can return results in a + more familiar form. + + - Sometimes this algorithm can evaluate parts of an integral; in + this case integrate() will try to evaluate the rest of the + integrand using the other methods here. + + - Setting manual=True will cause integrate() to use only this + method. + + 6. The Heuristic Risch algorithm: + + - This is a heuristic version of the Risch algorithm, meaning that + it is not deterministic. This is tried as a last resort because + it can be very slow. It is still used because not enough of the + full Risch algorithm is implemented, so that there are still some + integrals that can only be computed using this method. The goal + is to implement enough of the Risch and Meijer G methods so that + this can be deleted. - (4) Recursive Risch algorithm as described in Bronstein's integration - tutorial. + """ + from sympy.integrals.risch import risch_integrate - - this way we can handle those integrable functions for which (3) - fails + if risch: + try: + return risch_integrate(f, x, conds=conds) + except NotImplementedError: + return None - (5) Powerful heuristics based mostly on user defined rules. + if manual: + try: + result = manualintegrate(f, x) + if result is not None and result.func != Integral: + return result + except (ValueError, PolynomialError): + pass - - handle complicated, rarely used cases - """ # if it is a poly(x) then let the polynomial integrate itself (fast) # @@ -924,9 +1153,30 @@ if poly is not None and not meijerg: return poly.integrate().as_expr() + if risch is not False: + try: + result, i = risch_integrate(f, x, separate_integral=True, conds=conds) + except NotImplementedError: + pass + else: + if i: + # There was a nonelementary integral. Try integrating it. + return result + i.doit(risch=False) + else: + return result + # since Integral(f=g1+g2+...) == Integral(g1) + Integral(g2) + ... # we are going to handle Add terms separately, # if `f` is not Add -- we only have one term + + # Note that in general, this is a bad idea, because Integral(g1) + + # Integral(g2) might not be computable, even if Integral(g1 + g2) is. + # For example, Integral(x**x + x**x*log(x)). But many heuristics only + # work term-wise. So we compute this step last, after trying + # risch_integrate. We also try risch_integrate again in this loop, + # because maybe the integral is a sum of an elementary part and a + # nonelementary part (like erf(x) + exp(x)). risch_integrate() is + # quite fast, so this is acceptable. parts = [] args = Add.make_args(f) for g in args: @@ -947,7 +1197,8 @@ h_order_expr = self._eval_integral(order_term.expr, x) if h_order_expr is not None: - h_order_term = order_term.func(h_order_expr, *order_term.variables) + h_order_term = order_term.func( + h_order_expr, *order_term.variables) parts.append(coeff*(h + h_order_term)) continue @@ -966,8 +1217,12 @@ if M is not None: if g.exp == -1: h = C.log(g.base) - else: + elif conds != 'piecewise': h = g.base**(g.exp + 1) / (g.exp + 1) + else: + h1 = C.log(g.base) + h2 = g.base**(g.exp + 1) / (g.exp + 1) + h = Piecewise((h1, Eq(g.exp, -1)), (h2, True)) parts.append(coeff * h / M[a]) continue @@ -981,7 +1236,7 @@ if not meijerg: # g(x) = Mul(trig) - h = trigintegrate(g, x) + h = trigintegrate(g, x, conds=conds) if h is not None: parts.append(coeff * h) continue @@ -992,10 +1247,25 @@ parts.append(coeff * h) continue - if not meijerg: - # fall back to the more general algorithm + # Try risch again. + if risch is not False: + try: + h, i = risch_integrate(g, x, separate_integral=True, conds=conds) + except NotImplementedError: + h = None + else: + if i: + h = h + i.doit(risch=False) + + parts.append(coeff*h) + continue + + # fall back to heurisch try: - h = heurisch(g, x, hints=[]) + if conds == 'piecewise': + h = heurisch_wrapper(g, x, hints=[]) + else: + h = heurisch(g, x, hints=[]) except PolynomialError: # XXX: this exception means there is a bug in the # implementation of heuristic Risch integration @@ -1016,6 +1286,27 @@ parts.append(coeff * h) continue + if h is None and manual is not False: + try: + result = manualintegrate(g, x) + if result is not None and not isinstance(result, Integral): + if result.has(Integral): + # try to have other algorithms do the integrals + # manualintegrate can't handle + result = result.func(*[ + arg.doit(manual=False) if arg.has(Integral) else arg + for arg in result.args + ]).expand(multinomial=False, + log=False, + power_exp=False, + power_base=False) + if not result.has(Integral): + parts.append(coeff * result) + continue + except (ValueError, PolynomialError): + # can't handle some SymPy expressions + pass + # if we failed maybe it was because we had # a product that could have been expanded, # so let's try an expansion of the whole @@ -1030,8 +1321,10 @@ if not h and len(args) == 1: f = f.expand(mul=True, deep=False) if f.is_Add: - return self._eval_integral(f, x, meijerg) - + # Note: risch will be identical on the expanded + # expression, but maybe it will be able to pick out parts, + # like x*(exp(x) + erf(x)). + return self._eval_integral(f, x, meijerg=meijerg, risch=risch, conds=conds) if h is not None: parts.append(coeff * h) @@ -1045,158 +1338,88 @@ yield integrate(term, *self.limits) def _eval_nseries(self, x, n, logx): - terms, order = self.function.nseries(x, n=n, logx=logx).as_coeff_add(C.Order) + terms, order = self.function.nseries( + x, n=n, logx=logx).as_coeff_add(C.Order) return integrate(terms, *self.limits) + Add(*order)*x def _eval_subs(self, old, new): - """ - Substitute old with new in the integrand and the limits, but don't - change anything that is (or corresponds to) a dummy variable of - integration. - - The normal substitution semantics -- traversing all arguments looking - for matching patterns -- should not be applied to the Integrals since - changing the integration variables should also entail a change in the - integration limits (which should be done with the transform method). So - this method just makes changes in the integrand and the limits. - - Not all instances of a given variable are conceptually the same: the - first argument of the limit tuple with length greater than 1 and any - corresponding variable in the integrand are dummy variables while - every other symbol is a symbol that will be unchanged when the integral - is evaluated. For example, the dummy variables for ``i`` can be seen - as symbols with a preppended underscore: - - >>> from sympy import Integral - >>> from sympy.abc import a, b, c, x, y - >>> i = Integral(a + x, (a, a, b)) - >>> i.as_dummy() - Integral(_a + x, (_a, a, b)) - - If you want to change the lower limit to 1 there is no reason to - prohibit this since it is not conceptually related to the integration - variable, _a. Nor is there reason to disallow changing the b to 1. - - If a second limit were added, however, as in: - - >>> i = Integral(x + a, (a, a, b), (b, 1, 2)) - - the dummy variables become: - - >>> i.as_dummy() - Integral(_a + x, (_a, a, _b), (_b, 1, 2)) - - Note that the ``b`` of the first limit is now a dummy variable since - ``b`` is a dummy variable in the second limit. - - The "evaluate at" form of an integral allows some flexibility in how - the integral will be treated by subs: if there is no second argument, - none of the symbols matching the integration symbol are considered to - be dummy variables, but if an explicit expression is given for a limit - then the usual interpretation of the integration symbol as a dummy - symbol applies: - - >>> Integral(x).as_dummy() # implicit integration wrt x - Integral(x, x) - >>> Integral(x, x).as_dummy() - Integral(x, x) - >>> _.subs(x, 1) - Integral(1, x) - >>> i = Integral(x, (x, x)) - >>> i.as_dummy() - Integral(_x, (_x, x)) - >>> i.subs(x, 1) - Integral(x, (x, 1)) - - Summary: no variable of the integrand or limit can be the target of - substitution if it appears as a variable of integration in a limit - positioned to the right of it. The only exception is for a variable - that defines an indefinite integral limit (a single symbol): that - symbol *can* be replaced in the integrand. - - >>> i = Integral(a + x, (a, a, 3), (b, x, c)) - >>> i.free_symbols # only these can be changed - set([a, c, x]) - >>> i.subs(a, c) # note that the variable of integration is unchanged - Integral(a + x, (a, c, 3), (b, x, c)) - >>> i.subs(a + x, b) == i # there is no x + a, only x + - True - >>> i.subs(x, y - c) - Integral(a - c + y, (a, a, 3), (b, -c + y, c)) - """ - integrand, limits = self.function, self.limits - old_atoms = old.free_symbols - limits = list(limits) + return _eval_subs(self, old, new) - dummies = set() - for i in range(-1, -len(limits) - 1, -1): - xab = limits[i] - if len(xab) == 1: - continue - if not dummies.intersection(old_atoms): - limits[i] = Tuple(xab[0], - *[l._subs(old, new) for l in xab[1:]]) - dummies.add(xab[0]) - if not dummies.intersection(old_atoms): - integrand = integrand.subs(old, new) - return Integral(integrand, *limits) + def _eval_transpose(self): + if all([x.is_real for x in flatten(self.limits)]): + return self.func(self.function.transpose(), *self.limits) + return None def as_sum(self, n, method="midpoint"): """ - Approximates the integral by a sum. + Approximates the definite integral by a sum. - method ... one of: left, right, midpoint + method ... one of: left, right, midpoint, trapezoid - This is basically just the rectangle method [1], the only difference is - where the function value is taken in each interval. + These are all basically the rectangle method [1], the only difference + is where the function value is taken in each interval to define the + rectangle. [1] http://en.wikipedia.org/wiki/Rectangle_method - **method = midpoint**: - - Uses the n-order midpoint rule to evaluate the integral. - - Midpoint rule uses rectangles approximation for the given area (e.g. - definite integral) of the function with heights equal to the point on - the curve exactly in the middle of each interval (thus midpoint - method). See [1] for more information. - Examples ======== - >>> from sympy import sqrt + >>> from sympy import sin, sqrt >>> from sympy.abc import x >>> from sympy.integrals import Integral - >>> e = Integral(sqrt(x**3+1), (x, 2, 10)) + >>> e = Integral(sin(x), (x, 3, 7)) >>> e - Integral(sqrt(x**3 + 1), (x, 2, 10)) - >>> e.as_sum(4, method="midpoint") - 4*sqrt(7) + 6*sqrt(14) + 4*sqrt(86) + 2*sqrt(730) - >>> e.as_sum(4, method="midpoint").n() - 124.164447891310 - >>> e.n() - 124.616199194723 - - **method=left**: - - Uses the n-order rectangle rule to evaluate the integral, at each - interval the function value is taken at the left hand side of the - interval. + Integral(sin(x), (x, 3, 7)) - Examples - ======== + For demonstration purposes, this interval will only be split into 2 + regions, bounded by [3, 5] and [5, 7]. - >>> from sympy import sqrt - >>> from sympy.abc import x - >>> e = Integral(sqrt(x**3+1), (x, 2, 10)) - >>> e - Integral(sqrt(x**3 + 1), (x, 2, 10)) - >>> e.as_sum(4, method="left") - 6 + 2*sqrt(65) + 2*sqrt(217) + 6*sqrt(57) - >>> e.as_sum(4, method="left").n() - 96.8853618335341 - >>> e.n() - 124.616199194723 + The left-hand rule uses function evaluations at the left of each + interval: + + >>> e.as_sum(2, 'left') + 2*sin(5) + 2*sin(3) + + The midpoint rule uses evaluations at the center of each interval: + + >>> e.as_sum(2, 'midpoint') + 2*sin(4) + 2*sin(6) + + The right-hand rule uses function evaluations at the right of each + interval: + + >>> e.as_sum(2, 'right') + 2*sin(5) + 2*sin(7) + + The trapezoid rule uses function evaluations on both sides of the + intervals. This is equivalent to taking the average of the left and + right hand rule results: + + >>> e.as_sum(2, 'trapezoid') + 2*sin(5) + sin(3) + sin(7) + >>> (e.as_sum(2, 'left') + e.as_sum(2, 'right'))/2 == _ + True + + All but the trapexoid method may be used when dealing with a function + with a discontinuity. Here, the discontinuity at x = 0 can be avoided + by using the midpoint or right-hand method: + + >>> e = Integral(1/sqrt(x), (x, 0, 1)) + >>> e.as_sum(5).n(4) + 1.730 + >>> e.as_sum(10).n(4) + 1.809 + >>> e.doit().n(4) # the actual value is 2 + 2.000 + + The left- or trapezoid method will encounter the discontinuity and + return oo: + + >>> e.as_sum(5, 'left') + oo + >>> e.as_sum(5, 'trapezoid') + oo See Also ======== @@ -1206,16 +1429,31 @@ limits = self.limits if len(limits) > 1: - raise NotImplementedError("Multidimensional midpoint rule not implemented yet") + raise NotImplementedError( + "Multidimensional midpoint rule not implemented yet") else: limit = limits[0] + if len(limit) != 3: + raise ValueError("Expecting a definite integral.") if n <= 0: raise ValueError("n must be > 0") if n == oo: raise NotImplementedError("Infinite summation not yet implemented") sym, lower_limit, upper_limit = limit dx = (upper_limit - lower_limit)/n - result = 0. + + if method == 'trapezoid': + l = self.function.subs(sym, lower_limit) + r = self.function.subs(sym, upper_limit) + result = (l + r)/2 + for i in range(1, n): + x = lower_limit + i*dx + result += self.function.subs(sym, x) + return result*dx + elif method not in ('left', 'right', 'midpoint'): + raise NotImplementedError("Unknown method %s" % method) + + result = 0 for i in range(n): if method == "midpoint": xi = lower_limit + i*dx + dx/2 @@ -1223,8 +1461,6 @@ xi = lower_limit + i*dx elif method == "right": xi = lower_limit + i*dx + dx - else: - raise NotImplementedError("Unknown method %s" % method) result += self.function.subs(sym, xi) return result*dx @@ -1261,15 +1497,34 @@ **Strategy** - SymPy uses various approaches to integration. One method is to find - an antiderivative for the integrand, and then use the fundamental + SymPy uses various approaches to definite integration. One method is to + find an antiderivative for the integrand, and then use the fundamental theorem of calculus. Various functions are implemented to integrate polynomial, rational and trigonometric functions, and integrands - containing DiracDelta terms. There is also a (very successful, - albeit somewhat slow) general implementation of the heuristic risch - algorithm. See the docstring of Integral._eval_integral() for more + containing DiracDelta terms. + + SymPy also implements the part of the Risch algorithm, which is a decision + procedure for integrating elementary functions, i.e., the algorithm can + either find an elementary antiderivative, or prove that one does not + exist. There is also a (very successful, albeit somewhat slow) general + implementation of the heuristic Risch algorithm. This algorithm will + eventually be phased out as more of the full Risch algorithm is + implemented. See the docstring of Integral._eval_integral() for more details on computing the antiderivative using algebraic methods. + The option risch=True can be used to use only the (full) Risch algorithm. + This is useful if you want to know if an elementary function has an + elementary antiderivative. If the indefinite Integral returned by this + function is an instance of NonElementaryIntegral, that means that the + Risch algorithm has proven that integral to be non-elementary. Note that + by default, additional methods (such as the Meijer G method outlined + below) are tried on these integrals, as they may be expressible in terms + of special functions, so if you only care about elementary answers, use + risch=True. Also note that an unevaluated Integral returned by this + function is not necessarily a NonElementaryIntegral, even with risch=True, + as it may just be an indication that the particular part of the Risch + algorithm needed to integrate that function is not yet implemented. + Another family of strategies comes from re-writing the integrand in terms of so-called Meijer G-functions. Indefinite integrals of a single G-function can always be computed, and the definite integral @@ -1278,6 +1533,12 @@ as G-functions, and use this information to compute integrals (see the ``meijerint`` module). + The option manual=True can be used to use only an algorithm that tries + to mimic integration by hand. This algorithm does not handle as many + integrands as the other algorithms implemented but may return results in + a more familiar form. The ``manualintegrate`` module has functions that + return the steps used (see the module docstring for more information). + In general, the algebraic methods work best for computing antiderivatives of (possibly complicated) combinations of elementary functions. The G-function methods work best for computing definite @@ -1339,7 +1600,8 @@ in interactive sessions and should be avoided in library code. >>> integrate(x**a*exp(-x), (x, 0, oo)) # same as conds='piecewise' - Piecewise((gamma(a + 1), -re(a) < 1), (Integral(x**a*exp(-x), (x, 0, oo)), True)) + Piecewise((gamma(a + 1), -re(a) < 1), + (Integral(x**a*exp(-x), (x, 0, oo)), True)) >>> integrate(x**a*exp(-x), (x, 0, oo), conds='none') gamma(a + 1) @@ -1351,16 +1613,21 @@ ======== Integral, Integral.doit + """ meijerg = kwargs.pop('meijerg', None) conds = kwargs.pop('conds', 'piecewise') + risch = kwargs.pop('risch', None) + manual = kwargs.pop('manual', None) integral = Integral(*args, **kwargs) if isinstance(integral, Integral): - return integral.doit(deep = False, meijerg = meijerg, conds = conds) + return integral.doit(deep=False, meijerg=meijerg, conds=conds, + risch=risch, manual=manual) else: return integral + @xthreaded def line_integrate(field, curve, vars): """line_integrate(field, Curve, variables) @@ -1383,7 +1650,8 @@ """ F = sympify(field) if not F: - raise ValueError("Expecting function specifying field as first argument.") + raise ValueError( + "Expecting function specifying field as first argument.") if not isinstance(curve, Curve): raise ValueError("Expecting Curve entity as second argument.") if not is_sequence(vars): @@ -1406,5 +1674,5 @@ Ft = Ft.subs(var, _f) Ft = Ft * sqrt(dldt) - integral = Integral(Ft, curve.limits).doit(deep = False) + integral = Integral(Ft, curve.limits).doit(deep=False) return integral diff -Nru python3-sympy-0.7.2/sympy/integrals/manualintegrate.py python3-sympy-0.7.3/sympy/integrals/manualintegrate.py --- python3-sympy-0.7.2/sympy/integrals/manualintegrate.py 1970-01-01 00:00:00.000000000 +0000 +++ python3-sympy-0.7.3/sympy/integrals/manualintegrate.py 2013-07-13 17:53:32.000000000 +0000 @@ -0,0 +1,860 @@ +"""Integration method that emulates by-hand techniques. + +This module also provides functionality to get the steps used to evaluate a +particular integral, in the ``integral_steps`` function. This will return +nested namedtuples representing the integration rules used. The +``manualintegrate`` function computes the integral using those steps given +an integrand; given the steps, ``_manualintegrate`` will evaluate them. + +The integrator can be extended with new heuristics and evaluation +techniques. To do so, write a function that accepts an ``IntegralInfo`` +object and returns either a namedtuple representing a rule or +``None``. Then, write another function that accepts the namedtuple's fields +and returns the antiderivative, and decorate it with +``@evaluates(namedtuple_type)``. + +""" +import sympy + +from sympy.functions.elementary.trigonometric import TrigonometricFunction +from sympy.simplify import fraction +from sympy.strategies.core import (switch, identity, do_one, null_safe, + condition, tryit) + +from sympy.core.compatibility import namedtuple +from functools import reduce + +def Rule(name, props=""): + # GOTCHA: namedtuple class name not considered! + def __eq__(self, other): + return self.__class__ == other.__class__ and tuple.__eq__(self, other) + __neq__ = lambda self, other: not __eq__(self, other) + cls = namedtuple(name, props + " context symbol") + cls.__eq__ = __eq__ + cls.__ne__ = __neq__ + return cls + +ConstantRule = Rule("ConstantRule", "constant") +ConstantTimesRule = Rule("ConstantTimesRule", "constant other substep") +PowerRule = Rule("PowerRule", "base exp") +AddRule = Rule("AddRule", "substeps") +URule = Rule("URule", "u_var u_func constant substep") +PartsRule = Rule("PartsRule", "u dv v_step second_step") +CyclicPartsRule = Rule("CyclicPartsRule", "parts_rules coefficient") +TrigRule = Rule("TrigRule", "func arg") +ExpRule = Rule("ExpRule", "base exp") +LogRule = Rule("LogRule", "func") +ArctanRule = Rule("ArctanRule") +AlternativeRule = Rule("AlternativeRule", "alternatives") +DontKnowRule = Rule("DontKnowRule") +DerivativeRule = Rule("DerivativeRule") +RewriteRule = Rule("RewriteRule", "rewritten substep") + +IntegralInfo = namedtuple('IntegralInfo', 'integrand symbol') + +evaluators = {} +def evaluates(rule): + def _evaluates(func): + func.rule = rule + evaluators[rule] = func + return func + return _evaluates + +def contains_dont_know(rule): + if isinstance(rule, DontKnowRule): + return True + else: + for val in rule: + if isinstance(val, tuple): + if contains_dont_know(val): + return True + elif isinstance(val, list): + if any(contains_dont_know(i) for i in val): + return True + return False + +def manual_diff(f, symbol): + """Derivative of f in form expected by find_substitutions + + SymPy's derivatives for some trig functions (like cot) aren't in a form + that works well with finding substitutions; this replaces the + derivatives for those particular forms with something that works better. + + """ + if f.args: + arg = f.args[0] + if isinstance(f, sympy.tan): + return arg.diff(symbol) * sympy.sec(arg)**2 + elif isinstance(f, sympy.cot): + return -arg.diff(symbol) * sympy.csc(arg)**2 + elif isinstance(f, sympy.sec): + return arg.diff(symbol) * sympy.sec(arg) * sympy.tan(arg) + elif isinstance(f, sympy.csc): + return -arg.diff(symbol) * sympy.csc(arg) * sympy.cot(arg) + elif isinstance(f, sympy.Add): + return sum([manual_diff(arg, symbol) for arg in f.args]) + return f.diff(symbol) + +# Method based on that on SIN, described in "Symbolic Integration: The +# Stormy Decade" + +def find_substitutions(integrand, symbol, u_var): + results = [] + + def test_subterm(u, u_diff): + substituted = integrand / u_diff + if symbol not in substituted.free_symbols: + # replaced everything already + return False + + substituted = substituted.subs(u, u_var).cancel() + if symbol not in substituted.free_symbols: + return substituted + return False + + def possible_subterms(term): + if any(isinstance(term, cls) + for cls in (sympy.sin, sympy.cos, sympy.tan, + sympy.asin, sympy.acos, sympy.atan, + sympy.exp, sympy.log)): + return [term.args[0]] + elif isinstance(term, sympy.Mul): + r = [] + for u in term.args: + numer, denom = fraction(u) + if numer == 1: + r.append(denom) + r.extend(possible_subterms(denom)) + else: + r.append(u) + r.extend(possible_subterms(u)) + return r + elif isinstance(term, sympy.Pow): + if term.args[1].is_constant(symbol): + return [term.args[0]] + elif term.args[0].is_constant(symbol): + return [term.args[1]] + elif isinstance(term, sympy.Add): + return term.args + return [] + + for u in possible_subterms(integrand): + if u == symbol: + continue + new_integrand = test_subterm(u, manual_diff(u, symbol)) + if new_integrand is not False: + constant = new_integrand.as_coeff_mul()[0] + substitution = (u, constant, new_integrand) + if substitution not in results: + results.append(substitution) + + return results + +def rewriter(condition, rewrite): + """Strategy that rewrites an integrand.""" + def _rewriter(integral): + integrand, symbol = integral + if condition(*integral): + rewritten = rewrite(*integral) + if rewritten != integrand: + substep = integral_steps(rewritten, symbol) + if not isinstance(substep, DontKnowRule): + return RewriteRule( + rewritten, + substep, + integrand, symbol) + return _rewriter + +def proxy_rewriter(condition, rewrite): + """Strategy that rewrites an integrand based on some other criteria.""" + def _proxy_rewriter(criteria): + criteria, integral = criteria + integrand, symbol = integral + args = criteria + list(integral) + if condition(*args): + rewritten = rewrite(*args) + if rewritten != integrand: + return RewriteRule( + rewritten, + integral_steps(rewritten, symbol), + integrand, symbol) + return _proxy_rewriter + +def multiplexer(conditions): + """Apply the rule that matches the condition, else None""" + def multiplexer_rl(expr): + for key, rule in list(conditions.items()): + if key(expr): + return rule(expr) + return multiplexer_rl + +def alternatives(*rules): + """Strategy that makes an AlternativeRule out of multiple possible results.""" + def _alternatives(integral): + alts = [] + for rule in rules: + result = rule(integral) + if result and not isinstance(result, DontKnowRule) and result != integral: + alts.append(result) + if len(alts) == 1: + return alts[0] + elif len(alts) > 1: + return AlternativeRule(alts, *integral) + return _alternatives + +def constant_rule(integral): + integrand, symbol = integral + return ConstantRule(integral.integrand, *integral) + +def power_rule(integral): + integrand, symbol = integral + base, exp = integrand.as_base_exp() + + if symbol not in exp.free_symbols and isinstance(base, sympy.Symbol): + if sympy.simplify(exp + 1) == 0: + return LogRule(base, integrand, symbol) + return PowerRule(base, exp, integrand, symbol) + elif symbol not in base.free_symbols and isinstance(exp, sympy.Symbol): + return ExpRule(base, exp, integrand, symbol) + +def exp_rule(integral): + integrand, symbol = integral + if isinstance(integrand.args[0], sympy.Symbol): + return ExpRule(sympy.E, integrand.args[0], integrand, symbol) + +def arctan_rule(integral): + integrand, symbol = integral + base, exp = integrand.as_base_exp() + + if sympy.simplify(exp + 1) == 0: + a = sympy.Wild('a', exclude=[symbol]) + b = sympy.Wild('b', exclude=[symbol]) + match = base.match(a + b*symbol**2) + if match: + a, b = match[a], match[b] + + if a != 1 or b != 1: + u_var = sympy.Dummy() + rewritten = sympy.Rational(1, a) * (base / a) ** (-1) + u_func = sympy.sqrt(sympy.Rational(b, a)) * symbol + constant = 1 / sympy.sqrt(sympy.Rational(b, a)) + substituted = rewritten.subs(u_func, u_var) + + if a == b: + substep = ArctanRule(integrand, symbol) + else: + subrule = ArctanRule(substituted, u_var) + if constant != 1: + subrule = ConstantTimesRule( + constant, substituted, subrule, + substituted, symbol) + + substep = URule(u_var, u_func, constant, + subrule, + integrand, symbol) + + if a != 1: + other = (base / a) ** (-1) + return ConstantTimesRule( + sympy.Rational(1, a), other, + substep, integrand, symbol) + return substep + + return ArctanRule(integrand, symbol) + +def add_rule(integral): + integrand, symbol = integral + return AddRule( + [integral_steps(g, symbol) + for g in integrand.as_ordered_terms()], + integrand, symbol) + +def mul_rule(integral): + integrand, symbol = integral + args = integrand.args + + # Constant times function case + coeff, f = integrand.as_independent(symbol) + + if coeff != 1: + return ConstantTimesRule( + coeff, f, + integral_steps(f, symbol), + integrand, symbol) + +def _parts_rule(integrand, symbol): + # LIATE rule: + # log, inverse trig, algebraic (polynomial), trigonometric, exponential + def pull_out_polys(integrand): + integrand = integrand.together() + polys = [arg for arg in integrand.args if arg.is_polynomial(symbol)] + if polys: + u = sympy.Mul(*polys) + dv = integrand / u + return u, dv + + def pull_out_u(*functions): + def pull_out_u_rl(integrand): + if any([integrand.has(f) for f in functions]): + args = [arg for arg in integrand.args + if any(isinstance(arg, cls) for cls in functions)] + if args: + u = reduce(lambda a,b: a*b, args) + dv = integrand / u + return u, dv + + return pull_out_u_rl + + liate_rules = [pull_out_u(sympy.log), pull_out_u(sympy.atan), + pull_out_polys, pull_out_u(sympy.sin, sympy.cos), + pull_out_u(sympy.exp)] + + + dummy = sympy.Dummy() + # we can integrate log(x) and atan(x) by setting dv = 1 + if isinstance(integrand, sympy.log) or isinstance(integrand, sympy.atan): + integrand = dummy * integrand + + for index, rule in enumerate(liate_rules): + result = rule(integrand) + + if result: + u, dv = result + + # Don't pick u to be a constant if possible + if symbol not in u.free_symbols and not u.has(dummy): + return + + u = u.subs(dummy, 1) + dv = dv.subs(dummy, 1) + + for rule in liate_rules[index + 1:]: + r = rule(integrand) + # make sure dv is amenable to integration + if r and r[0].subs(dummy, 1) == dv: + du = u.diff(symbol) + v_step = integral_steps(dv, symbol) + v = _manualintegrate(v_step) + + return u, dv, v, du, v_step + +def parts_rule(integral): + integrand, symbol = integral + constant, integrand = integrand.as_coeff_Mul() + + result = _parts_rule(integrand, symbol) + + steps = [] + if result: + u, dv, v, du, v_step = result + steps.append(result) + + if isinstance(v, sympy.Integral): + return + + while True: + if symbol not in (integrand / (v * du)).cancel().free_symbols: + coefficient = ((v * du) / integrand).cancel() + rule = CyclicPartsRule( + [PartsRule(u, dv, v_step, None, None, None) + for (u, dv, v, du, v_step) in steps], + (-1) ** len(steps) * coefficient, + integrand, symbol + ) + if constant != 1: + rule = ConstantTimesRule(constant, integrand, rule, + constant * integrand, symbol) + return rule + + result = _parts_rule(v * du, symbol) + + if result: + u, dv, v, du, v_step = result + steps.append(result) + else: + break + + def make_second_step(steps, integrand): + if steps: + u, dv, v, du, v_step = steps[0] + return PartsRule(u, dv, v_step, + make_second_step(steps[1:], v * du), + integrand, symbol) + else: + return integral_steps(integrand, symbol) + + if steps: + u, dv, v, du, v_step = steps[0] + rule = PartsRule(u, dv, v_step, + make_second_step(steps[1:], v * du), + integrand, symbol) + if constant != 1: + rule = ConstantTimesRule(constant, integrand, rule, + constant * integrand, symbol) + return rule + + +def trig_rule(integral): + integrand, symbol = integral + if isinstance(integrand, sympy.sin) or isinstance(integrand, sympy.cos): + arg = integrand.args[0] + + if not isinstance(arg, sympy.Symbol): + return # perhaps a substitution can deal with it + + if isinstance(integrand, sympy.sin): + func = 'sin' + else: + func = 'cos' + + return TrigRule(func, arg, integrand, symbol) + + if isinstance(integrand, sympy.tan): + rewritten = sympy.sin(*integrand.args) / sympy.cos(*integrand.args) + elif isinstance(integrand, sympy.cot): + rewritten = sympy.cos(*integrand.args) / sympy.sin(*integrand.args) + elif isinstance(integrand, sympy.sec): + arg = integrand.args[0] + rewritten = ((sympy.sec(arg)**2 + sympy.tan(arg) * sympy.sec(arg)) / + (sympy.sec(arg) + sympy.tan(arg))) + elif isinstance(integrand, sympy.csc): + arg = integrand.args[0] + rewritten = ((sympy.csc(arg)**2 + sympy.cot(arg) * sympy.csc(arg)) / + (sympy.csc(arg) + sympy.cot(arg))) + return RewriteRule( + rewritten, + integral_steps(rewritten, symbol), + integrand, symbol + ) + +def trig_product_rule(integral): + integrand, symbol = integral + + sectan = sympy.sec(symbol) * sympy.tan(symbol) + q = integrand / sectan + + if symbol not in q.free_symbols: + rule = TrigRule('sec*tan', symbol, sectan, symbol) + if q != 1: + rule = ConstantTimesRule(q, sectan, rule, integrand, symbol) + + return rule + + csccot = -sympy.csc(symbol) * sympy.cot(symbol) + q = integrand / csccot + + if symbol not in q.free_symbols: + rule = TrigRule('csc*cot', symbol, csccot, symbol) + if q != 1: + rule = ConstantTimesRule(q, csccot, rule, integrand, symbol) + + return rule + +@sympy.cacheit +def make_wilds(symbol): + a = sympy.Wild('a', exclude=[symbol]) + b = sympy.Wild('b', exclude=[symbol]) + m = sympy.Wild('m', exclude=[symbol], properties=[lambda n: isinstance(n, sympy.Integer)]) + n = sympy.Wild('n', exclude=[symbol], properties=[lambda n: isinstance(n, sympy.Integer)]) + + return a, b, m, n + +@sympy.cacheit +def sincos_pattern(symbol): + a, b, m, n = make_wilds(symbol) + pattern = sympy.sin(a*symbol)**m * sympy.cos(b*symbol)**n + + return pattern, a, b, m, n + +@sympy.cacheit +def tansec_pattern(symbol): + a, b, m, n = make_wilds(symbol) + pattern = sympy.tan(a*symbol)**m * sympy.sec(b*symbol)**n + + return pattern, a, b, m, n + +@sympy.cacheit +def cotcsc_pattern(symbol): + a, b, m, n = make_wilds(symbol) + pattern = sympy.cot(a*symbol)**m * sympy.csc(b*symbol)**n + + return pattern, a, b, m, n + +def uncurry(func): + def uncurry_rl(args): + return func(*args) + return uncurry_rl + +def trig_rewriter(rewrite): + def trig_rewriter_rl(args): + a, b, m, n, integrand, symbol = args + rewritten = rewrite(a, b, m, n, integrand, symbol) + if rewritten != integrand: + return RewriteRule( + rewritten, + integral_steps(rewritten, symbol), + integrand, symbol) + return trig_rewriter_rl + +sincos_botheven_condition = uncurry(lambda a, b, m, n, i, s: m.is_even and n.is_even) + +sincos_botheven = trig_rewriter( + lambda a, b, m, n, i, symbol: ( (((1 - sympy.cos(2*a*symbol)) / 2) ** (m / 2)) * + (((1 + sympy.cos(2*b*symbol)) / 2) ** (n / 2)) )) + +sincos_sinodd_condition = uncurry(lambda a, b, m, n, i, s: m.is_odd and m >= 3) + +sincos_sinodd = trig_rewriter( + lambda a, b, m, n, i, symbol: ( (1 - sympy.cos(a*symbol)**2)**((m - 1) / 2) * + sympy.sin(a*symbol) * + sympy.cos(b*symbol) ** n)) + +sincos_cosodd_condition = uncurry(lambda a, b, m, n, i, s: n.is_odd and n >= 3) + +sincos_cosodd = trig_rewriter( + lambda a, b, m, n, i, symbol: ( (1 - sympy.sin(b*symbol)**2)**((n - 1) / 2) * + sympy.cos(b*symbol) * + sympy.sin(a*symbol) ** m)) + +tansec_seceven_condition = uncurry(lambda a, b, m, n, i, s: n.is_even and n >= 4) +tansec_seceven = trig_rewriter( + lambda a, b, m, n, i, symbol: ( (1 + sympy.tan(b*symbol)**2) ** (n/2 - 1) * + sympy.sec(b*symbol)**2 * + sympy.tan(a*symbol) ** m )) + +tansec_tanodd_condition = uncurry(lambda a, b, m, n, i, s: m.is_odd) +tansec_tanodd = trig_rewriter( + lambda a, b, m, n, i, symbol: ( (sympy.sec(a*symbol)**2 - 1) ** ((m - 1) / 2) * + sympy.tan(a*symbol) * + sympy.sec(b*symbol) ** n )) + +cotcsc_csceven_condition = uncurry(lambda a, b, m, n, i, s: n.is_even and n >= 4) +cotcsc_csceven = trig_rewriter( + lambda a, b, m, n, i, symbol: ( (1 + sympy.cot(b*symbol)**2) ** (n/2 - 1) * + sympy.csc(b*symbol)**2 * + sympy.cot(a*symbol) ** m )) + +cotcsc_cotodd_condition = uncurry(lambda a, b, m, n, i, s: m.is_odd) +cotcsc_cotodd = trig_rewriter( + lambda a, b, m, n, i, symbol: ( (sympy.csc(a*symbol)**2 - 1) ** ((m - 1) / 2) * + sympy.cot(a*symbol) * + sympy.csc(b*symbol) ** n )) + +def trig_powers_products_rule(integral): + integrand, symbol = integral + + if any(integrand.has(f) for f in (sympy.sin, sympy.cos)): + pattern, a, b, m, n = sincos_pattern(symbol) + match = integrand.match(pattern) + + if match: + a, b, m, n = match.get(a, 0),match.get(b, 0), match.get(m, 0), match.get(n, 0) + return multiplexer({ + sincos_botheven_condition: sincos_botheven, + sincos_sinodd_condition: sincos_sinodd, + sincos_cosodd_condition: sincos_cosodd + })((a, b, m, n, integrand, symbol)) + + integrand = integrand.subs({ + 1 / sympy.cos(symbol): sympy.sec(symbol) + }) + + if any(integrand.has(f) for f in (sympy.tan, sympy.sec)): + pattern, a, b, m, n = tansec_pattern(symbol) + match = integrand.match(pattern) + + if match: + a, b, m, n = match.get(a, 0),match.get(b, 0), match.get(m, 0), match.get(n, 0) + return multiplexer({ + tansec_tanodd_condition: tansec_tanodd, + tansec_seceven_condition: tansec_seceven + })((a, b, m, n, integrand, symbol)) + + integrand = integrand.subs({ + 1 / sympy.sin(symbol): sympy.csc(symbol), + 1 / sympy.tan(symbol): sympy.cot(symbol), + sympy.cos(symbol) / sympy.tan(symbol): sympy.cot(symbol) + }) + + if any(integrand.has(f) for f in (sympy.cot, sympy.csc)): + pattern, a, b, m, n = cotcsc_pattern(symbol) + match = integrand.match(pattern) + + if match: + a, b, m, n = match.get(a, 0),match.get(b, 0), match.get(m, 0), match.get(n, 0) + return multiplexer({ + cotcsc_cotodd_condition: cotcsc_cotodd, + cotcsc_csceven_condition: cotcsc_csceven + })((a, b, m, n, integrand, symbol)) + +def substitution_rule(integral): + integrand, symbol = integral + + u_var = sympy.Dummy() + substitutions = find_substitutions(integrand, symbol, u_var) + if substitutions: + ways = [] + for u_func, c, substituted in substitutions: + subrule = integral_steps(substituted / c, u_var) + if contains_dont_know(subrule): + continue + + if sympy.simplify(c - 1) != 0: + subrule = ConstantTimesRule( + c, substituted / c, subrule, + substituted, symbol + ) + + ways.append(URule(u_var, u_func, c, + subrule, + integrand, symbol)) + + if len(ways) > 1: + return AlternativeRule(ways, integrand, symbol) + elif ways: + return ways[0] + + elif integrand.has(sympy.exp): + u_func = sympy.exp(symbol) + c = 1 + substituted = integrand / u_func.diff(symbol) + substituted = substituted.subs(u_func, u_var) + + if symbol not in substituted.free_symbols: + return URule(u_var, u_func, c, + integral_steps(substituted, u_var), + integrand, symbol) + +partial_fractions_rule = rewriter( + lambda integrand, symbol: integrand.is_rational_function(), + lambda integrand, symbol: integrand.apart(symbol)) + +distribute_expand_rule = rewriter( + lambda integrand, symbol: ( + all(arg.is_Pow or arg.is_polynomial(symbol) for arg in integrand.args) + or isinstance(integrand, sympy.Pow) + or isinstance(integrand, sympy.Mul)), + lambda integrand, symbol: integrand.expand()) + +def derivative_rule(integral): + variables = integral[0].args[1:] + + if variables[-1] == integral.symbol: + return DerivativeRule(*integral) + else: + return ConstantRule(integral.integrand, *integral) + +def fallback_rule(integral): + return DontKnowRule(*integral) + +_integral_cache = {} +def integral_steps(integrand, symbol, **options): + """Returns the steps needed to compute an integral. + + This function attempts to mirror what a student would do by hand as + closely as possible. + + Returns + ======= + rule : namedtuple + The first step; most rules have substeps that must also be + considered. These substeps can be evaluated using `manualintegrate` + to obtain a result. + """ + cachekey = (integrand, symbol) + if cachekey in _integral_cache: + if _integral_cache[cachekey] is None: + # cyclic integral! null_safe will eliminate that path + return None + else: + return _integral_cache[cachekey] + else: + _integral_cache[cachekey] = None + + integral = IntegralInfo(integrand, symbol) + + def key(integral): + integrand = integral.integrand + + if isinstance(integrand, TrigonometricFunction): + return TrigonometricFunction + elif isinstance(integrand, sympy.Derivative): + return sympy.Derivative + elif symbol not in integrand.free_symbols: + return sympy.Number + else: + for cls in (sympy.Pow, sympy.Symbol, sympy.exp, sympy.log, + sympy.Add, sympy.Mul, sympy.atan): + if isinstance(integrand, cls): + return cls + + def integral_is_subclass(*klasses): + def _integral_is_subclass(integral): + k = key(integral) + return k and issubclass(k, klasses) + return _integral_is_subclass + + result = do_one( + null_safe(switch(key, { + sympy.Pow: do_one(null_safe(power_rule), null_safe(arctan_rule)), + sympy.Symbol: power_rule, + sympy.exp: exp_rule, + sympy.Add: add_rule, + sympy.Mul: do_one(null_safe(mul_rule), null_safe(trig_product_rule)), + sympy.Derivative: derivative_rule, + TrigonometricFunction: trig_rule, + sympy.Number: constant_rule + })), + null_safe( + alternatives( + substitution_rule, + condition( + integral_is_subclass(sympy.Mul, sympy.log, sympy.atan), + parts_rule), + condition( + integral_is_subclass(sympy.Mul), + partial_fractions_rule), + condition( + integral_is_subclass(sympy.Mul, sympy.Pow), + distribute_expand_rule), + trig_powers_products_rule + ) + ), + fallback_rule)(integral) + _integral_cache[cachekey] = result + return result + +@evaluates(ConstantRule) +def eval_constant(constant, integrand, symbol): + return constant * symbol + +@evaluates(ConstantTimesRule) +def eval_constanttimes(constant, other, substep, integrand, symbol): + return constant * _manualintegrate(substep) + +@evaluates(PowerRule) +def eval_power(base, exp, integrand, symbol): + return (base ** (exp + 1)) / (exp + 1) + +@evaluates(ExpRule) +def eval_exp(base, exp, integrand, symbol): + return integrand / sympy.ln(base) + +@evaluates(AddRule) +def eval_add(substeps, integrand, symbol): + return sum(map(_manualintegrate, substeps)) + +@evaluates(URule) +def eval_u(u_var, u_func, constant, substep, integrand, symbol): + result = _manualintegrate(substep) + return result.subs(u_var, u_func) + +@evaluates(PartsRule) +def eval_parts(u, dv, v_step, second_step, integrand, symbol): + v = _manualintegrate(v_step) + return u * v - _manualintegrate(second_step) + +@evaluates(CyclicPartsRule) +def eval_cyclicparts(parts_rules, coefficient, integrand, symbol): + coefficient = 1 - coefficient + result = [] + + sign = 1 + for rule in parts_rules: + result.append(sign * rule.u * _manualintegrate(rule.v_step)) + sign *= -1 + + return sympy.Add(*result) / coefficient + +@evaluates(TrigRule) +def eval_trig(func, arg, integrand, symbol): + if func == 'sin': + return -sympy.cos(arg) + elif func == 'cos': + return sympy.sin(arg) + elif func == 'sec*tan': + return sympy.sec(arg) + elif func == 'csc*cot': + return sympy.csc(arg) + +@evaluates(LogRule) +def eval_log(func, integrand, symbol): + return sympy.ln(func) + +@evaluates(ArctanRule) +def eval_arctan(integrand, symbol): + return sympy.atan(symbol) + +@evaluates(AlternativeRule) +def eval_alternative(alternatives, integrand, symbol): + return _manualintegrate(alternatives[0]) + +@evaluates(RewriteRule) +def eval_rewrite(rewritten, substep, integrand, symbol): + return _manualintegrate(substep) + +@evaluates(DerivativeRule) +def eval_derivativerule(integrand, symbol): + # isinstance(integrand, Derivative) should be True + if len(integrand.args) == 2: + return integrand.args[0] + else: + return sympy.Derivative(integrand.args[0], *integrand.args[1:-1]) + +@evaluates(DontKnowRule) +def eval_dontknowrule(integrand, symbol): + return sympy.Integral(integrand, symbol) + +def _manualintegrate(rule): + evaluator = evaluators.get(rule.__class__) + if not evaluator: + raise ValueError("Cannot evaluate rule %s" % rule) + return evaluator(*rule) + +def manualintegrate(f, var): + """manualintegrate(f, var) + + Compute indefinite integral of a single variable using an algorithm that + resembles what a student would do by hand. + + Unlike ``integrate``, var can only be a single symbol. + + Examples + ======== + + >>> from sympy import sin, cos, tan, exp, log, integrate + >>> from sympy.integrals.manualintegrate import manualintegrate + >>> from sympy.abc import x + >>> manualintegrate(1 / x, x) + log(x) + >>> integrate(1/x) + log(x) + >>> manualintegrate(log(x), x) + x*log(x) - x + >>> integrate(log(x)) + x*log(x) - x + >>> manualintegrate(exp(x) / (1 + exp(2 * x)), x) + atan(exp(x)) + >>> integrate(exp(x) / (1 + exp(2 * x))) + RootSum(4*_z**2 + 1, Lambda(_i, _i*log(2*_i + exp(x)))) + >>> manualintegrate(cos(x)**4 * sin(x), x) + -cos(x)**5/5 + >>> integrate(cos(x)**4 * sin(x), x) + -cos(x)**5/5 + >>> manualintegrate(cos(x)**4 * sin(x)**3, x) + cos(x)**7/7 - cos(x)**5/5 + >>> integrate(cos(x)**4 * sin(x)**3, x) + cos(x)**7/7 - cos(x)**5/5 + >>> manualintegrate(tan(x), x) + -log(cos(x)) + >>> integrate(tan(x), x) + -log(sin(x)**2 - 1)/2 + + See Also + ======== + + sympy.integrals.integrals.integrate + sympy.integrals.integrals.Integral.doit + sympy.integrals.integrals.Integral + """ + return _manualintegrate(integral_steps(f, var)) diff -Nru python3-sympy-0.7.2/sympy/integrals/meijerint.py python3-sympy-0.7.3/sympy/integrals/meijerint.py --- python3-sympy-0.7.2/sympy/integrals/meijerint.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/integrals/meijerint.py 2013-07-13 17:53:32.000000000 +0000 @@ -25,7 +25,8 @@ Integrals and Series: More Special Functions, Vol. 3,. Gordon and Breach Science Publisher """ -from sympy.core import oo, S, pi +from sympy.core import oo, S, pi, Expr +from sympy.core.compatibility import next from sympy.core.function import expand, expand_mul, expand_power_base from sympy.core.add import Add from sympy.core.mul import Mul @@ -36,11 +37,14 @@ from sympy.functions.special.delta_functions import Heaviside from sympy.functions.elementary.piecewise import Piecewise from sympy.functions.special.hyper import meijerg +from sympy.utilities.iterables import multiset_partitions, ordered from sympy.utilities.misc import debug as _debug from sympy.utilities import default_sort_key # keep this at top for easy reference z = Dummy('z') + + def _create_lookup_table(table): """ Add formulae for the function -> meijerg lookup table. """ def wild(n): @@ -48,11 +52,14 @@ p, q, a, b, c = list(map(wild, 'pqabc')) n = Wild('n', properties=[lambda x: x.is_Integer and x > 0]) t = p*z**q + def add(formula, an, ap, bm, bq, arg=t, fac=S(1), cond=True, hint=True): table.setdefault(_mytype(formula, z), []).append((formula, [(fac, meijerg(an, ap, bm, bq, arg))], cond, hint)) + def addi(formula, inst, cond, hint=True): - table.setdefault(_mytype(formula, z), []).append((formula, inst, cond, hint)) + table.setdefault( + _mytype(formula, z), []).append((formula, inst, cond, hint)) def constant(a): return [(a, meijerg([1], [], [], [0], z)), @@ -62,8 +69,10 @@ # [P], Section 8. from sympy import unpolarify, Function, Not + class IsNonPositiveInteger(Function): nargs = 1 + @classmethod def eval(cls, arg): arg = unpolarify(arg) @@ -72,31 +81,33 @@ # Section 8.4.2 from sympy import (gamma, pi, cos, exp, re, sin, sqrt, sinh, cosh, - factorial, log, erf, polar_lift) + factorial, log, erf, erfc, erfi, polar_lift) # TODO this needs more polar_lift (c/f entry for exp) - add(Heaviside(t - b)*(t - b)**(a-1), [a], [], [], [0], t/b, - gamma(a)*b**(a-1), And(b > 0)) - add(Heaviside(b - t)*(b - t)**(a-1), [], [a], [0], [], t/b, - gamma(a)*b**(a-1), And(b > 0)) - add(Heaviside(z - (b/p)**(1/q))*(t - b)**(a-1), [a], [], [], [0], t/b, - gamma(a)*b**(a-1), And(b > 0)) - add(Heaviside((b/p)**(1/q) - z)*(b - t)**(a-1), [], [a], [0], [], t/b, - gamma(a)*b**(a-1), And(b > 0)) + add(Heaviside(t - b)*(t - b)**(a - 1), [a], [], [], [0], t/b, + gamma(a)*b**(a - 1), And(b > 0)) + add(Heaviside(b - t)*(b - t)**(a - 1), [], [a], [0], [], t/b, + gamma(a)*b**(a - 1), And(b > 0)) + add(Heaviside(z - (b/p)**(1/q))*(t - b)**(a - 1), [a], [], [], [0], t/b, + gamma(a)*b**(a - 1), And(b > 0)) + add(Heaviside((b/p)**(1/q) - z)*(b - t)**(a - 1), [], [a], [0], [], t/b, + gamma(a)*b**(a - 1), And(b > 0)) add((b + t)**(-a), [1 - a], [], [0], [], t/b, b**(-a)/gamma(a), hint=Not(IsNonPositiveInteger(a))) add(abs(b - t)**(-a), [1 - a], [(1 - a)/2], [0], [(1 - a)/2], t/b, pi/(gamma(a)*cos(pi*a/2))*abs(b)**(-a), re(a) < 1) add((t**a - b**a)/(t - b), [0, a], [], [0, a], [], t/b, - b**(a-1)*sin(a*pi)/pi) + b**(a - 1)*sin(a*pi)/pi) # 12 - def A1(r, sign, nu): return pi**(-S(1)/2)*(-sign*nu/2)**(1-2*r) + def A1(r, sign, nu): + return pi**(-S(1)/2)*(-sign*nu/2)**(1 - 2*r) + def tmpadd(r, sgn): # XXX the a**2 is bad for matching - add((sqrt(a**2 + t) + sgn*a)**b/(a**2+t)**r, - [(1 + b)/2, 1-2*r + b/2], [], + add((sqrt(a**2 + t) + sgn*a)**b/(a**2 + t)**r, + [(1 + b)/2, 1 - 2*r + b/2], [], [(b - sgn*b)/2], [(b + sgn*b)/2], t/a**2, - a**(b-2*r)*A1(r, sgn, b)) + a**(b - 2*r)*A1(r, sgn, b)) tmpadd(0, 1) tmpadd(0, -1) tmpadd(S(1)/2, 1) @@ -131,6 +142,7 @@ N = subs[n] return [((-1)**N*factorial(N), meijerg([], [1]*(N + 1), [0]*(N + 1), [], t))] + def make_log2(subs): N = subs[n] return [(factorial(N), @@ -140,14 +152,15 @@ # TODO also it would be nice to derive them recursively ... addi(log(t)**n*Heaviside(1 - t), make_log1, True) addi(log(t)**n*Heaviside(t - 1), make_log2, True) + def make_log3(subs): return make_log1(subs) + make_log2(subs) addi(log(t)**n, make_log3, True) addi(log(t + a), constant(log(a)) + [(S(1), meijerg([1, 1], [], [1], [0], t/a))], True) - addi(log(abs(t - a)), constant(log(abs(a))) + \ - [(pi, meijerg([1, 1], [S(1)/2], [1], [0, S(1)/2], t/a))], + addi(log(abs(t - a)), constant(log(abs(a))) + + [(pi, meijerg([1, 1], [S(1)/2], [1], [0, S(1)/2], t/a))], True) # TODO log(x)/(x+a) and log(x)/(x-1) can also be done. should they # be derivable? @@ -159,7 +172,8 @@ # Section 8.4.11 from sympy import Ei, I, expint, Si, Ci, Shi, Chi, fresnels, fresnelc addi(Ei(t), - constant(-I*pi) + [(S(-1), meijerg([], [1], [0, 0], [], t*polar_lift(-1)))], + constant(-I*pi) + [(S(-1), meijerg([], [1], [0, 0], [], + t*polar_lift(-1)))], True) # Section 8.4.12 @@ -169,19 +183,23 @@ # Section 8.4.13 add(Shi(t), [S(1)/2], [], [0], [S(-1)/2, S(-1)/2], polar_lift(-1)*t**2/4, t*sqrt(pi)/4) - add(Chi(t), [], [S(1)/2, 1], [0, 0], [S(1)/2, S(1)/2], t**2/4, -pi**S('3/2')/2) + add(Chi(t), [], [S(1)/2, 1], [0, 0], [S(1)/2, S(1)/2], t**2/4, - + pi**S('3/2')/2) # generalized exponential integral add(expint(a, t), [], [a], [a - 1, 0], [], t) # Section 8.4.14 - # TODO erfc add(erf(t), [1], [], [S(1)/2], [0], t**2, 1/sqrt(pi)) # TODO exp(-x)*erf(I*x) does not work + add(erfc(t), [], [1], [0, S(1)/2], [], t**2, 1/sqrt(pi)) + # This formula for erfi(z) yields a wrong(?) minus sign + #add(erfi(t), [1], [], [S(1)/2], [0], -t**2, I/sqrt(pi)) + add(erfi(t), [S(1)/2], [], [0], [-S(1)/2], -t**2, t/sqrt(pi)) # Fresnel Integrals - add(fresnels(t), [1], [], [S(3)/4], [0, S(1)/4], pi**2*t**4/16, S(1)/2) - add(fresnelc(t), [1], [], [S(1)/4], [0, S(3)/4], pi**2*t**4/16, S(1)/2) + add(fresnels(t), [1], [], [S(3)/4], [0, S(1)/4], pi**2*t**4/16, S(1)/2) + add(fresnelc(t), [1], [], [S(1)/4], [0, S(3)/4], pi**2*t**4/16, S(1)/2) ##### bessel-type functions ##### from sympy import besselj, bessely, besseli, besselk @@ -199,7 +217,7 @@ # [-(a+b)/2, (a - b)/2, (b - a)/2], t**2, 1/sqrt(pi)) # Section 8.4.20 - add(bessely(a, t), [], [-(a+1)/2], [a/2, -a/2], [-(a+1)/2], t**2/4) + add(bessely(a, t), [], [-(a + 1)/2], [a/2, -a/2], [-(a + 1)/2], t**2/4) # TODO all of the following should be derivable #add(sin(t)*bessely(a, t), [S(1)/4, S(3)/4], [(1 - a - 1)/2], @@ -233,6 +251,11 @@ add(besselk(a, t), [], [], [a/2, -a/2], [], t**2/4, S(1)/2) # TODO many more formulas. should all be derivable + # Complete elliptic integrals K(z) and E(z) + from sympy import elliptic_k, elliptic_e + add(elliptic_k(t), [S.Half, S.Half], [], [0], [0], -t, S.Half) + add(elliptic_e(t), [S.Half, 3*S.Half], [], [0], [0], -t, -S.Half/2) + #################################################################### # First some helper functions. @@ -241,9 +264,10 @@ from sympy.utilities.timeutils import timethis timeit = timethis('meijerg') + def _mytype(f, x): """ Create a hashable entity describing the type of f. """ - if not f.has(x): + if x not in f.free_symbols: return () elif f.is_Function: return (type(f),) @@ -255,12 +279,14 @@ res.sort() return tuple(res) + class _CoeffExpValueError(ValueError): """ Exception raised by _get_coeff_exp, for internal use only. """ pass + def _get_coeff_exp(expr, x): """ When expr is known to be of the form c*x**b, with c and/or b possibly 1, @@ -291,6 +317,7 @@ else: raise _CoeffExpValueError('expr not of form a*x**b: %s' % expr) + def _exponents(expr, x): """ Find the exponents of ``x`` (not including zero) in ``expr``. @@ -320,10 +347,12 @@ _exponents_(expr, x, res) return res + def _functions(expr, x): """ Find the types of functions in expr, to estimate the complexity. """ from sympy import Function - return set(e.func for e in expr.atoms(Function) if e.has(x)) + return set(e.func for e in expr.atoms(Function) if x in e.free_symbols) + def _find_splitting_points(expr, x): """ @@ -342,10 +371,11 @@ """ from sympy import Tuple p, q = [Wild(n, exclude=[x]) for n in 'pq'] + def compute_innermost(expr, res): - if isinstance(expr, Tuple): + if not isinstance(expr, Expr): return - m = expr.match(p*x+q) + m = expr.match(p*x + q) if m and m[p] != 0: res.add(-m[q]/m[p]) return @@ -357,6 +387,7 @@ compute_innermost(expr, innermost) return innermost + def _split_mul(f, x): """ Split expression ``f`` into fac, po, g, where fac is a constant factor, @@ -370,18 +401,18 @@ """ from sympy import polarify, unpolarify fac = S(1) - po = S(1) - g = S(1) + po = S(1) + g = S(1) f = expand_power_base(f) args = Mul.make_args(f) for a in args: if a == x: po *= x - elif not a.has(x): + elif x not in a.free_symbols: fac *= a else: - if a.is_Pow: + if a.is_Pow and x not in a.exp.free_symbols: c, t = a.base.as_coeff_mul(x) if t != (x,): c, t = expand_mul(a.base).as_coeff_mul(x) @@ -393,6 +424,7 @@ return fac, po, g + def _mul_args(f): """ Return a list ``L`` such that Mul(*L) == f. @@ -415,25 +447,35 @@ gs.append(g) return gs + def _mul_as_two_parts(f): """ Find all the ways to split f into a product of two terms. Return None on failure. + Although the order is canonical from multiset_partitions, this is + not necessarily the best order to process the terms. For example, + if the case of len(gs) == 2 is removed and multiset is allowed to + sort the terms, some tests fail. + + Examples + ======== + >>> from sympy.integrals.meijerint import _mul_as_two_parts - >>> from sympy import sin, exp + >>> from sympy import sin, exp, ordered >>> from sympy.abc import x - >>> _mul_as_two_parts(x*sin(x)*exp(x)) - [(x*exp(x), sin(x)), (x, exp(x)*sin(x)), (x*sin(x), exp(x))] + >>> list(ordered(_mul_as_two_parts(x*sin(x)*exp(x)))) + [(x, exp(x)*sin(x)), (x*exp(x), sin(x)), (x*sin(x), exp(x))] """ - from sympy.utilities.iterables import multiset_partitions gs = _mul_args(f) if len(gs) < 2: return None - + if len(gs) == 2: + return [tuple(gs)] return [(Mul(*x), Mul(*y)) for (x, y) in multiset_partitions(gs, 2)] + def _inflate_g(g, n): """ Return C, h such that h is a G function of argument z**n and g = C*h. """ @@ -453,13 +495,16 @@ inflate(g.bm, n), inflate(g.bother, n), g.argument**n * n**(n*v)) + def _flip_g(g): """ Turn the G function into one of inverse argument (i.e. G(1/x) -> G'(x)) """ # See [L], section 5.2 - def tr(l): return [1 - a for a in l] + def tr(l): + return [1 - a for a in l] return meijerg(tr(g.bm), tr(g.bother), tr(g.an), tr(g.aother), 1/g.argument) + def _inflate_fox_h(g, a): r""" Let d denote the integrand in the definition of the G function ``g``. @@ -480,12 +525,14 @@ # theorem. D, g = _inflate_g(g, q) z = g.argument - D /= (2*pi)**((1-p)/2)*p**(-S(1)/2) + D /= (2*pi)**((1 - p)/2)*p**(-S(1)/2) z /= p**p - bs = [(n+1)/p for n in range(p)] + bs = [(n + 1)/p for n in range(p)] return D, meijerg(g.an, g.aother, g.bm, list(g.bother) + bs, z) _dummies = {} + + def _dummy(name, token, expr, **kwargs): """ Return a dummy. This will return the same dummy if the same token+name is @@ -493,9 +540,11 @@ This is for being cache-friendly. """ d = _dummy_(name, token, **kwargs) - if expr.has(d): + if d in expr.free_symbols: return Dummy(name, **kwargs) return d + + def _dummy_(name, token, **kwargs): """ Return a dummy associated to name and token. Same effect as declaring @@ -506,11 +555,13 @@ _dummies[(name, token)] = Dummy(name, **kwargs) return _dummies[(name, token)] + def _is_analytic(f, x): """ Check if f(x), when expressed using G functions on the positive reals, will in fact agree with the G functions almost everywhere """ from sympy import Heaviside, Abs - return not any(expr.has(x) for expr in f.atoms(Heaviside, Abs)) + return not any(x in expr.free_symbols for expr in f.atoms(Heaviside, Abs)) + def _condsimp(cond): """ @@ -527,8 +578,9 @@ >>> simp(Or(x <= y, And(x < y, z))) x <= y """ - from sympy import (symbols, Wild, Eq, unbranched_argument, exp_polar, pi, I, - periodic_argument, oo, polar_lift) + from sympy import ( + symbols, Wild, Eq, unbranched_argument, exp_polar, pi, I, + periodic_argument, oo, polar_lift) from sympy.logic.boolalg import BooleanFunction if not isinstance(cond, BooleanFunction): return cond @@ -536,24 +588,24 @@ change = True p, q, r = symbols('p q r', cls=Wild) rules = [ - (Or(p < q, Eq(p, q)), p <= q), - # The next two obviously are instances of a general pattern, but it is - # easier to spell out the few cases we care about. - (And(abs(unbranched_argument(p)) <= pi, + (Or(p < q, Eq(p, q)), p <= q), + # The next two obviously are instances of a general pattern, but it is + # easier to spell out the few cases we care about. + (And(abs(unbranched_argument(p)) <= pi, abs(unbranched_argument(exp_polar(-2*pi*I)*p)) <= pi), Eq(unbranched_argument(exp_polar(-I*pi)*p), 0)), - (And(abs(unbranched_argument(p)) <= pi/2, + (And(abs(unbranched_argument(p)) <= pi/2, abs(unbranched_argument(exp_polar(-pi*I)*p)) <= pi/2), Eq(unbranched_argument(exp_polar(-I*pi/2)*p), 0)), - (Or(p <= q, And(p < q, r)), p <= q) - ] + (Or(p <= q, And(p < q, r)), p <= q) + ] while change: change = False for fro, to in rules: if fro.func != cond.func: continue for n, arg in enumerate(cond.args): - if fro.args[0].has(r): + if r in fro.args[0].free_symbols: m = arg.match(fro.args[1]) num = 1 else: @@ -561,7 +613,7 @@ m = arg.match(fro.args[0]) if not m: continue - otherargs = [x.subs(m) for x in fro.args[:num] + fro.args[num+1:]] + otherargs = [x.subs(m) for x in fro.args[:num] + fro.args[num + 1:]] otherlist = [n] for arg2 in otherargs: for k, arg3 in enumerate(cond.args): @@ -571,21 +623,22 @@ otherlist += [k] break if arg3.func is And and arg2.args[1] == r and \ - arg2.func is And and arg2.args[0] in arg3.args: + arg2.func is And and arg2.args[0] in arg3.args: otherlist += [k] break if arg3.func is And and arg2.args[0] == r and \ - arg2.func is And and arg2.args[1] in arg3.args: + arg2.func is And and arg2.args[1] in arg3.args: otherlist += [k] break if len(otherlist) != len(otherargs) + 1: continue - newargs = [arg for (k, arg) in enumerate(cond.args) \ + newargs = [arg for (k, arg) in enumerate(cond.args) if k not in otherlist] + [to.subs(m)] cond = cond.func(*newargs) change = True break # final tweak + def repl_eq(orig): if orig.lhs == 0: expr = orig.rhs @@ -596,12 +649,14 @@ m = expr.match(unbranched_argument(polar_lift(p)**q)) if not m: if expr.func is periodic_argument and not expr.args[0].is_polar \ - and expr.args[1] == oo: + and expr.args[1] == oo: return (expr.args[0] > 0) return orig return (m[p] > 0) - return cond.replace(lambda expr: expr.is_Relational and expr.rel_op == '==', - repl_eq) + return cond.replace( + lambda expr: expr.is_Relational and expr.rel_op == '==', + repl_eq) + def _eval_cond(cond): """ Re-evaluate the conditions. """ @@ -613,6 +668,7 @@ # Now the "backbone" functions to do actual integration. #################################################################### + def _my_principal_branch(expr, period, full_pb=False): """ Bring expr nearer to its principal branch by removing superfluous factors. @@ -625,6 +681,7 @@ res = res.replace(principal_branch, lambda x, y: x) return res + def _rewrite_saxena_1(fac, po, g, x): """ Rewrite the integral fac*po*g dx, from zero to infinity, as @@ -637,12 +694,15 @@ a = _my_principal_branch(a, period) # We substitute t = x**b. - C = fac/(abs(b)*a**((s+1)/b - 1)) + C = fac/(abs(b)*a**((s + 1)/b - 1)) # Absorb a factor of (at)**((1 + s)/b - 1). - def tr(l): return [a + (1 + s)/b - 1 for a in l] + + def tr(l): + return [a + (1 + s)/b - 1 for a in l] return C, meijerg(tr(g.an), tr(g.aother), tr(g.bm), tr(g.bother), a*x) + def _check_antecedents_1(g, x, helper=False): """ Return a condition under which the mellin transform of g exists. @@ -659,10 +719,11 @@ delta = g.delta eta, _ = _get_coeff_exp(g.argument, x) m, n, p, q = S([len(g.bm), len(g.an), len(g.ap), len(g.bq)]) - xi = m + n - p + xi = m + n - p if p > q: - def tr(l): return [1 - x for x in l] + def tr(l): + return [1 - x for x in l] return _check_antecedents_1(meijerg(tr(g.bm), tr(g.bother), tr(g.an), tr(g.aother), x/eta), x) @@ -687,7 +748,7 @@ debug('Checking antecedents for 1 function:') debug(' delta=%s, eta=%s, m=%s, n=%s, p=%s, q=%s' - % (delta, eta, m, n, p, q)) + % (delta, eta, m, n, p, q)) debug(' ap = %s, %s' % (list(g.an), list(g.aother))) debug(' bq = %s, %s' % (list(g.bm), list(g.bother))) debug(' cond_3=%s, cond_3*=%s, cond_4=%s' % (cond_3, cond_3_star, cond_4)) @@ -715,7 +776,7 @@ if helper: extra = [] case2 = [And(Eq(n, 0), p + 1 <= m, m <= q, - abs(arg(eta)) < delta*pi, *extra)] + abs(arg(eta)) < delta*pi, *extra)] conds += case2 debug(' case 2:', case2) @@ -723,7 +784,8 @@ extra = [cond_3, cond_4] if helper: extra = [] - case3 = [And(p < q, 1 <= m, delta > 0, Eq(abs(arg(eta)), delta*pi), *extra)] + case3 = [And(p < q, 1 <= m, delta > 0, Eq(abs(arg(eta)), delta*pi), + *extra)] case3 += [And(p <= q - 2, Eq(delta, 0), Eq(abs(arg(eta)), 0), *extra)] conds += case3 debug(' case 3:', case3) @@ -757,6 +819,7 @@ return Or(*conds) + def _int0oo_1(g, x): """ Evaluate int_0^\infty g dx using G functions, @@ -783,6 +846,7 @@ res /= gamma(a + 1) return combsimp(unpolarify(res)) + def _rewrite_saxena(fac, po, g1, g2, x, full_pb=False): """ Rewrite the integral fac*po*g1*g2 from 0 to oo in terms of G functions @@ -841,12 +905,15 @@ # TODO should we try both? exp = (s + 1)/b - 1 fac = fac/(abs(b) * a1**exp) - def tr(l): return [a + exp for a in l] + + def tr(l): + return [a + exp for a in l] g1 = meijerg(tr(g1.an), tr(g1.aother), tr(g1.bm), tr(g1.bother), a1*x) g2 = meijerg(g2.an, g2.aother, g2.bm, g2.bother, a2*x) return powdenest(fac, polar=True), g1, g2 + def _check_antecedents(g1, g2, x): """ Return a condition under which the integral theorem applies. """ from sympy import (re, Eq, Not, Ne, cos, I, exp, ceiling, sin, sign, @@ -870,17 +937,17 @@ bstar = s + t - (u + v)/2 cstar = m + n - (p + q)/2 rho = g1.nu + (u - v)/2 + 1 - mu = g2.nu + (p - q)/2 + 1 + mu = g2.nu + (p - q)/2 + 1 phi = q - p - (v - u) eta = 1 - (v - u) - mu - rho psi = (pi*(q - m - n) + abs(arg(omega)))/(q - p) theta = (pi*(v - s - t) + abs(arg(sigma)))/(v - u) lambda_c = (q - p)*abs(omega)**(1/(q - p))*cos(psi) \ - + (v - u)*abs(sigma)**(1/(v - u))*cos(theta) + + (v - u)*abs(sigma)**(1/(v - u))*cos(theta) def lambda_s0(c1, c2): - return c1*(q-p)*abs(omega)**(1/(q-p))*sin(psi) \ - + c2*(v-u)*abs(sigma)**(1/(v-u))*sin(theta) + return c1*(q - p)*abs(omega)**(1/(q - p))*sin(psi) \ + + c2*(v - u)*abs(sigma)**(1/(v - u))*sin(theta) lambda_s = Piecewise( ((lambda_s0(+1, +1)*lambda_s0(-1, -1)), And(Eq(arg(sigma), 0), Eq(arg(omega), 0))), @@ -937,8 +1004,10 @@ tmp += [(u - v)*re(1 + d) - re(rho) > -S(3)/2] c7 = And(*tmp) - c8 = (abs(phi) + 2*re((rho - 1)*(q - p) + (v - u)*(q - p) + (mu - 1)*(v - u)) > 0) - c9 = (abs(phi) - 2*re((rho - 1)*(q - p) + (v - u)*(q - p) + (mu - 1)*(v - u)) > 0) + c8 = (abs(phi) + 2*re((rho - 1)*(q - p) + (v - u)*(q - p) + (mu - + 1)*(v - u)) > 0) + c9 = (abs(phi) - 2*re((rho - 1)*(q - p) + (v - u)*(q - p) + (mu - + 1)*(v - u)) > 0) c10 = (abs(arg(sigma)) < bstar*pi) c11 = Eq(abs(arg(sigma)), bstar*pi) c12 = (abs(arg(omega)) < cstar*pi) @@ -992,77 +1061,77 @@ (c12, 12), (c13, 13), (c14, 14), (c15, 15)]: _debug(' c%s:' % i, cond) - # We will return Or(*conds) conds = [] def pr(count): _debug(' case %s:' % count, conds[-1]) - conds += [And(m*n*s*t != 0, bstar > 0, cstar > 0, c1, c2, c3, c10, c12)] #1 + conds += [And(m*n*s*t != 0, bstar > 0, cstar > 0, c1, c2, c3, c10, + c12)] # 1 pr(1) conds += [And(Eq(u, v), Eq(bstar, 0), cstar > 0, sigma > 0, re(rho) < 1, - c1, c2, c3, c12)] #2 + c1, c2, c3, c12)] # 2 pr(2) conds += [And(Eq(p, q), Eq(cstar, 0), bstar > 0, omega > 0, re(mu) < 1, - c1, c2, c3, c10)] #3 + c1, c2, c3, c10)] # 3 pr(3) conds += [And(Eq(p, q), Eq(u, v), Eq(bstar, 0), Eq(cstar, 0), sigma > 0, omega > 0, re(mu) < 1, re(rho) < 1, - Ne(sigma, omega), c1, c2, c3)] #4 + Ne(sigma, omega), c1, c2, c3)] # 4 pr(4) conds += [And(Eq(p, q), Eq(u, v), Eq(bstar, 0), Eq(cstar, 0), sigma > 0, omega > 0, re(mu + rho) < 1, - Ne(omega, sigma), c1, c2, c3)] #5 + Ne(omega, sigma), c1, c2, c3)] # 5 pr(5) conds += [And(p > q, s > 0, bstar > 0, cstar >= 0, - c1, c2, c3, c5, c10, c13)] #6 + c1, c2, c3, c5, c10, c13)] # 6 pr(6) conds += [And(p < q, t > 0, bstar > 0, cstar >= 0, - c1, c2, c3, c4, c10, c13)] #7 + c1, c2, c3, c4, c10, c13)] # 7 pr(7) conds += [And(u > v, m > 0, cstar > 0, bstar >= 0, - c1, c2, c3, c7, c11, c12)] #8 + c1, c2, c3, c7, c11, c12)] # 8 pr(8) conds += [And(u < v, n > 0, cstar > 0, bstar >= 0, - c1, c2, c3, c6, c11, c12)] #9 + c1, c2, c3, c6, c11, c12)] # 9 pr(9) conds += [And(p > q, Eq(u, v), Eq(bstar, 0), cstar >= 0, sigma > 0, - re(rho) < 1, c1, c2, c3, c5, c13)] #10 + re(rho) < 1, c1, c2, c3, c5, c13)] # 10 pr(10) conds += [And(p < q, Eq(u, v), Eq(bstar, 0), cstar >= 0, sigma > 0, - re(rho) < 1, c1, c2, c3, c4, c13)] #11 + re(rho) < 1, c1, c2, c3, c4, c13)] # 11 pr(11) conds += [And(Eq(p, q), u > v, bstar >= 0, Eq(cstar, 0), omega > 0, - re(mu) < 1, c1, c2, c3, c7, c11)] #12 + re(mu) < 1, c1, c2, c3, c7, c11)] # 12 pr(12) conds += [And(Eq(p, q), u < v, bstar >= 0, Eq(cstar, 0), omega > 0, - re(mu) < 1, c1, c2, c3, c6, c11)] #13 + re(mu) < 1, c1, c2, c3, c6, c11)] # 13 pr(13) conds += [And(p < q, u > v, bstar >= 0, cstar >= 0, - c1, c2,c3, c4, c7, c11, c13)] #14 + c1, c2, c3, c4, c7, c11, c13)] # 14 pr(14) conds += [And(p > q, u < v, bstar >= 0, cstar >= 0, - c1, c2, c3, c5, c6, c11, c13)] #15 + c1, c2, c3, c5, c6, c11, c13)] # 15 pr(15) conds += [And(p > q, u > v, bstar >= 0, cstar >= 0, - c1, c2, c3, c5, c7, c8, c11, c13, c14)] #16 + c1, c2, c3, c5, c7, c8, c11, c13, c14)] # 16 pr(16) conds += [And(p < q, u < v, bstar >= 0, cstar >= 0, - c1, c2, c3, c4, c6, c9, c11, c13, c14)] #17 + c1, c2, c3, c4, c6, c9, c11, c13, c14)] # 17 pr(17) - conds += [And(Eq(t, 0), s > 0, bstar > 0, phi > 0, c1, c2, c10)] #18 + conds += [And(Eq(t, 0), s > 0, bstar > 0, phi > 0, c1, c2, c10)] # 18 pr(18) - conds += [And(Eq(s, 0), t > 0, bstar > 0, phi < 0, c1, c3, c10)] #19 + conds += [And(Eq(s, 0), t > 0, bstar > 0, phi < 0, c1, c3, c10)] # 19 pr(19) - conds += [And(Eq(n, 0), m > 0, cstar > 0, phi < 0, c1, c2, c12)] #20 + conds += [And(Eq(n, 0), m > 0, cstar > 0, phi < 0, c1, c2, c12)] # 20 pr(20) - conds += [And(Eq(m, 0), n > 0, cstar > 0, phi > 0, c1, c3, c12)] #21 + conds += [And(Eq(m, 0), n > 0, cstar > 0, phi > 0, c1, c3, c12)] # 21 pr(21) conds += [And(Eq(s*t, 0), bstar > 0, cstar > 0, - c1, c2, c3, c10, c12)] #22 + c1, c2, c3, c10, c12)] # 22 pr(22) conds += [And(Eq(m*n, 0), bstar > 0, cstar > 0, - c1, c2, c3, c10, c12)] #23 + c1, c2, c3, c10, c12)] # 23 pr(23) # The following case is from [Luke1969]. As far as I can tell, it is *not* @@ -1090,57 +1159,60 @@ conds += [And(m + n > p, Eq(t, 0), Eq(phi, 0), s > 0, bstar > 0, cstar < 0, abs(arg(omega)) < (m + n - p + 1)*pi, - c1, c2, c10, c14, c15)] #24 + c1, c2, c10, c14, c15)] # 24 pr(24) conds += [And(m + n > q, Eq(s, 0), Eq(phi, 0), t > 0, bstar > 0, cstar < 0, abs(arg(omega)) < (m + n - q + 1)*pi, - c1, c3, c10, c14, c15)] #25 + c1, c3, c10, c14, c15)] # 25 pr(25) conds += [And(Eq(p, q - 1), Eq(t, 0), Eq(phi, 0), s > 0, bstar > 0, cstar >= 0, cstar*pi < abs(arg(omega)), - c1, c2, c10, c14, c15)] #26 + c1, c2, c10, c14, c15)] # 26 pr(26) conds += [And(Eq(p, q + 1), Eq(s, 0), Eq(phi, 0), t > 0, bstar > 0, cstar >= 0, cstar*pi < abs(arg(omega)), - c1, c3, c10, c14, c15)] #27 + c1, c3, c10, c14, c15)] # 27 pr(27) conds += [And(p < q - 1, Eq(t, 0), Eq(phi, 0), s > 0, bstar > 0, cstar >= 0, cstar*pi < abs(arg(omega)), abs(arg(omega)) < (m + n - p + 1)*pi, - c1, c2, c10, c14, c15)] #28 + c1, c2, c10, c14, c15)] # 28 pr(28) - conds += [And(p > q + 1, Eq(s, 0), Eq(phi, 0), t > 0, bstar > 0, cstar >= 0, + conds += [And( + p > q + 1, Eq(s, 0), Eq(phi, 0), t > 0, bstar > 0, cstar >= 0, cstar*pi < abs(arg(omega)), abs(arg(omega)) < (m + n - q + 1)*pi, - c1, c3, c10, c14, c15)] #29 + c1, c3, c10, c14, c15)] # 29 pr(29) conds += [And(Eq(n, 0), Eq(phi, 0), s + t > 0, m > 0, cstar > 0, bstar < 0, abs(arg(sigma)) < (s + t - u + 1)*pi, - c1, c2, c12, c14, c15)] #30 + c1, c2, c12, c14, c15)] # 30 pr(30) conds += [And(Eq(m, 0), Eq(phi, 0), s + t > v, n > 0, cstar > 0, bstar < 0, abs(arg(sigma)) < (s + t - v + 1)*pi, - c1, c3, c12, c14, c15)] #31 + c1, c3, c12, c14, c15)] # 31 pr(31) conds += [And(Eq(n, 0), Eq(phi, 0), Eq(u, v - 1), m > 0, cstar > 0, bstar >= 0, bstar*pi < abs(arg(sigma)), abs(arg(sigma)) < (bstar + 1)*pi, - c1, c2, c12, c14, c15)] #32 + c1, c2, c12, c14, c15)] # 32 pr(32) conds += [And(Eq(m, 0), Eq(phi, 0), Eq(u, v + 1), n > 0, cstar > 0, bstar >= 0, bstar*pi < abs(arg(sigma)), abs(arg(sigma)) < (bstar + 1)*pi, - c1, c3, c12, c14, c15)] #33 + c1, c3, c12, c14, c15)] # 33 pr(33) - conds += [And(Eq(n, 0), Eq(phi, 0), u < v - 1, m > 0, cstar > 0, bstar >= 0, - bstar*pi < abs(arg(sigma)), - abs(arg(sigma)) < (s + t - u + 1)*pi, - c1, c2, c12, c14, c15)] #34 + conds += [And( + Eq(n, 0), Eq(phi, 0), u < v - 1, m > 0, cstar > 0, bstar >= 0, + bstar*pi < abs(arg(sigma)), + abs(arg(sigma)) < (s + t - u + 1)*pi, + c1, c2, c12, c14, c15)] # 34 pr(34) - conds += [And(Eq(m, 0), Eq(phi, 0), u > v + 1, n > 0, cstar > 0, bstar >= 0, - bstar*pi < abs(arg(sigma)), - abs(arg(sigma)) < (s + t - v + 1)*pi, - c1, c3, c12, c14, c15)] #35 + conds += [And( + Eq(m, 0), Eq(phi, 0), u > v + 1, n > 0, cstar > 0, bstar >= 0, + bstar*pi < abs(arg(sigma)), + abs(arg(sigma)) < (s + t - v + 1)*pi, + c1, c3, c12, c14, c15)] # 35 pr(35) return Or(*conds) @@ -1148,6 +1220,7 @@ # NOTE An alternative, but as far as I can tell weaker, set of conditions # can be found in [L, section 5.6.2]. + def _int0oo(g1, g2, x): """ Express integral from zero to infinity g1*g2 using a G function, @@ -1162,9 +1235,11 @@ 4*meijerg(((1/2, 0), ()), ((m/2,), (-m/2,)), s**(-2))/s**2 """ # See: [L, section 5.6.2, equation (1)] - eta, _ = _get_coeff_exp(g1.argument, x) + eta, _ = _get_coeff_exp(g1.argument, x) omega, _ = _get_coeff_exp(g2.argument, x) - def neg(l): return [-x for x in l] + + def neg(l): + return [-x for x in l] a1 = neg(g1.bm) + list(g2.an) a2 = list(g2.aother) + neg(g1.bother) b1 = neg(g1.an) + list(g2.bm) @@ -1176,10 +1251,13 @@ """ Absorb ``po`` == x**s into g. """ _, s = _get_coeff_exp(po, x) a, b = _get_coeff_exp(g.argument, x) - def tr(l): return [t + s/b for t in l] + + def tr(l): + return [t + s/b for t in l] return (powdenest(fac/a**(s/b), polar=True), meijerg(tr(g.an), tr(g.aother), tr(g.bm), tr(g.bother), g.argument)) + def _check_antecedents_inversion(g, x): """ Check antecedents for the laplace inversion integral. """ from sympy import re, im, Or, And, Eq, exp, I, Add, nan, Ne @@ -1208,6 +1286,7 @@ conds += [And(Ne(b, 0), Eq(im(c), 0), re(c) > 0, re(w) <= 0, re(a) <= -1)] return Or(*conds) + def statement(a, b, c, z): """ Provide a convergence statement for z**a * exp(b*z**c), c/f sphinx docs. """ @@ -1229,7 +1308,7 @@ theta = ((1 - sigma)/2 + Add(*g.bq) - Add(*g.ap))/sigma delta = g.delta _debug(' m=%s, n=%s, p=%s, q=%s, tau=%s, nu=%s, rho=%s, sigma=%s' % ( - m, n, p, q, tau, nu, rho, sigma)) + m, n, p, q, tau, nu, rho, sigma)) _debug(' epsilon=%s, theta=%s, delta=%s' % (epsilon, theta, delta)) # First check if the computation is valid. @@ -1257,10 +1336,17 @@ _debug(' Using asymptotic slater expansion.') return And(*[statement(a - 1, 0, 0, z) for a in g.an]) - def E(z): return And(*[statement(a - 1, 0, z) for a in g.an]) - def H(z): return statement(theta, -sigma, 1/sigma, z) - def Hp(z): return statement_half(theta, -sigma, 1/sigma, z, True) - def Hm(z): return statement_half(theta, -sigma, 1/sigma, z, False) + def E(z): + return And(*[statement(a - 1, 0, z) for a in g.an]) + + def H(z): + return statement(theta, -sigma, 1/sigma, z) + + def Hp(z): + return statement_half(theta, -sigma, 1/sigma, z, True) + + def Hm(z): + return statement_half(theta, -sigma, 1/sigma, z, False) # [L], section 5.10 conds = [] @@ -1270,7 +1356,7 @@ # Theorem 2, statements (2) and (3) conds += [And(p + 1 <= m, m + 1 <= q, delta > 0, delta < pi/2, n == 0, (m - p + 1)*pi - delta >= pi/2, - Hp(z*exp(I*pi*(q-m))), Hm(z*exp(-I*pi*(q-m))))] + Hp(z*exp(I*pi*(q - m))), Hm(z*exp(-I*pi*(q - m))))] # Theorem 2, statement (5) conds += [And(p < q, m == q, n == 0, delta > 0, (sigma + epsilon)*pi - delta >= pi/2, H(z))] @@ -1292,6 +1378,7 @@ return Or(*conds) + def _int_inversion(g, x, t): """ Compute the laplace inversion integral, assuming the formula applies. @@ -1306,6 +1393,8 @@ #################################################################### _lookup_table = None + + @cacheit @timeit def _rewrite_single(f, x, recursive=True): @@ -1342,7 +1431,7 @@ if t in _lookup_table: l = _lookup_table[t] for formula, terms, cond, hint in l: - subs = f.match(formula) + subs = f.match(formula, old=True) if subs: subs_ = {} for fro, to in list(subs.items()): @@ -1383,6 +1472,7 @@ inverse_mellin_transform, IntegralTransformError, MellinTransformStripError) from sympy import oo, nan, zoo, simplify, cancel + def my_imt(F, s, x, strip): """ Calling simplify() all the time is slow and not helpful, since most of the time it only factors things in a way that has to be @@ -1392,11 +1482,13 @@ return inverse_mellin_transform(F, s, x, strip, as_meijerg=True, needeval=True) except MellinTransformStripError: - return inverse_mellin_transform(simplify(cancel(expand(F))), s, x, strip, - as_meijerg=True, needeval=True) + return inverse_mellin_transform( + simplify(cancel(expand(F))), s, x, strip, + as_meijerg=True, needeval=True) f = f_ s = _dummy('s', 'rewrite-single', f) # to avoid infinite recursion, we have to force the two g functions case + def my_integrator(f, x): from sympy import Integral, hyperexpand r = _meijerint_definite_4(f, x, only_double=True) @@ -1417,7 +1509,7 @@ # (also if the dummy is already in the expression, there is no point in # putting in another one) a = _dummy_('a', 'rewrite-single') - if not f.has(a) and _is_analytic(f, x): + if a not in f.free_symbols and _is_analytic(f, x): try: F, strip, _ = mellin_transform(f.subs(x, a*x), x, s, integrator=my_integrator, @@ -1437,11 +1529,13 @@ g = m[0] a, b = _get_coeff_exp(g.argument, x) res += [(c, 0, meijerg(g.an, g.aother, g.bm, g.bother, - unpolarify(polarify(a, lift=True), exponents_only=True) \ + unpolarify(polarify( + a, lift=True), exponents_only=True) *x**b))] _debug('Recursive mellin transform worked:', g) return res, True + def _rewrite1(f, x, recursive=True): """ Try to rewrite f using a (sum of) single G functions with argument a*x**b. @@ -1455,6 +1549,7 @@ if g: return fac, po, g[0], g[1] + def _rewrite2(f, x): """ Try to rewrite f as a product of two G functions of arguments a*x**b. @@ -1469,10 +1564,12 @@ l = _mul_as_two_parts(g) if not l: return None - l.sort(key=lambda p: (max(len(_exponents(p[0], x)), len(_exponents(p[1], x))), - max(len(_functions(p[0], x)), len(_functions(p[1], x))), - max(len(_find_splitting_points(p[0], x)), - len(_find_splitting_points(p[1], x))))) + l = list(ordered(l, [ + lambda p: max(len(_exponents(p[0], x)), len(_exponents(p[1], x))), + lambda p: max(len(_functions(p[0], x)), len(_functions(p[1], x))), + lambda p: max(len(_find_splitting_points(p[0], x)), + len(_find_splitting_points(p[1], x)))])) + for recursive in [False, True]: for fac1, fac2 in l: g1 = _rewrite_single(fac1, x, recursive) @@ -1482,6 +1579,7 @@ if cond is not False: return fac, po, g1[0], g2[0], cond + def meijerint_indefinite(f, x): """ Compute an indefinite integral of ``f`` by rewriting it as a G function. @@ -1502,7 +1600,8 @@ if not res.has(hyper, meijerg): return results[-1] if results: - return sorted(results, key=count_ops)[0] + return next(ordered(results)) + def _meijerint_indefinite_1(f, x): """ Helper that does not attempt any substitution. """ @@ -1535,11 +1634,15 @@ # (Note that this dummy will immediately go away again, so we # can safely pass S(1) for ``expr``.) t = _dummy('t', 'meijerint-indefinite', S(1)) - def tr(p): return [a + rho + 1 for a in p] + + def tr(p): + return [a + rho + 1 for a in p] if any(b.is_integer and b <= 0 for b in tr(g.bm)): - r = -meijerg(tr(g.an), tr(g.aother) + [1], tr(g.bm) + [0], tr(g.bother), t) + r = -meijerg( + tr(g.an), tr(g.aother) + [1], tr(g.bm) + [0], tr(g.bother), t) else: - r = meijerg(tr(g.an) + [1], tr(g.aother), tr(g.bm), tr(g.bother) + [0], t) + r = meijerg( + tr(g.an) + [1], tr(g.aother), tr(g.bm), tr(g.bother) + [0], t) r = hyperexpand(r.subs(t, a*x**b)) # now substitute back @@ -1568,7 +1671,7 @@ 1 """ from sympy import cancel - res= expand_mul(cancel(res), deep=False) + res = expand_mul(cancel(res), deep=False) return Add._from_args(res.as_coeff_add(x)[1]) res = piecewise_fold(res) @@ -1582,6 +1685,7 @@ res = _my_unpolarify(_clean(res)) return Piecewise((res, _my_unpolarify(cond)), (Integral(f, x), True)) + @timeit def meijerint_definite(f, x, a, b): """ @@ -1640,7 +1744,7 @@ if res1 is None: _debug(' But could not compute first integral.') continue - res2 = _meijerint_definite_2(f.subs(x, c-x), x) + res2 = _meijerint_definite_2(f.subs(x, c - x), x) if res2 is None: _debug(' But could not compute second integral.') continue @@ -1668,7 +1772,7 @@ for split in _find_splitting_points(f, x): if (a - split >= 0) is True: _debug('Trying x --> x + %s' % split) - res = _meijerint_definite_2(f.subs(x, x + split) \ + res = _meijerint_definite_2(f.subs(x, x + split) *Heaviside(x + split - a), x) if res is not None: if res[0].has(meijerg): @@ -1697,6 +1801,7 @@ if results: return sorted(results, key=lambda x: count_ops(x[0]))[0] + def _guess_expansion(f, x): """ Try to guess sensible rewritings for integrand f(x). """ from sympy import expand_trig @@ -1719,6 +1824,7 @@ return res + def _meijerint_definite_2(f, x): """ Try to integrate f dx from zero to infinty. @@ -1747,6 +1853,7 @@ if res is not None and res[1] is not False: return res + def _meijerint_definite_3(f, x): """ Try to integrate f dx from zero to infinity. @@ -1770,10 +1877,12 @@ if c is not False: return res, c + def _my_unpolarify(f): from sympy import unpolarify return _eval_cond(unpolarify(f)) + @timeit def _meijerint_definite_4(f, x, only_double=False): """ @@ -1817,7 +1926,7 @@ for C1, s1, f1 in g1: for C2, s2, f2 in g2: r = _rewrite_saxena(fac*C1*C2, po*x**(s1 + s2), - f1, f2, x, full_pb) + f1, f2, x, full_pb) if r is None: _debug('Non-rational exponents.') return @@ -1834,6 +1943,7 @@ return res, cond return _my_unpolarify(hyperexpand(res)), cond + def meijerint_inversion(f, x, t): """ Compute the inverse laplace transform @@ -1851,7 +1961,7 @@ from sympy import I, Integral, exp, expand, log, Add, Mul, Heaviside f_ = f t_ = t - t = Dummy('t', polar=True) # We don't want sqrt(t**2) = abs(t) etc + t = Dummy('t', polar=True) # We don't want sqrt(t**2) = abs(t) etc f = f.subs(t_, t) c = Dummy('c') _debug('Laplace-inverting', f) @@ -1885,7 +1995,7 @@ if arg2.is_Mul: args += arg2.args continue - if not arg.base.has(x): + if x not in arg.base.free_symbols: try: a, b = _get_coeff_exp(arg.exp, x) except _CoeffExpValueError: diff -Nru python3-sympy-0.7.2/sympy/integrals/meijerint_doc.py python3-sympy-0.7.3/sympy/integrals/meijerint_doc.py --- python3-sympy-0.7.2/sympy/integrals/meijerint_doc.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/integrals/meijerint_doc.py 2013-07-13 17:53:32.000000000 +0000 @@ -13,7 +13,8 @@ if about == (): doc += 'Elementary functions:\n\n' else: - doc += 'Functions involving ' + ', '.join('`%s`' % latex(list(category[0][0].atoms(func))[0]) for func in about) + ':\n\n' + doc += 'Functions involving ' + ', '.join('`%s`' % latex( + list(category[0][0].atoms(func))[0]) for func in about) + ':\n\n' for formula, gs, cond, hint in category: if not isinstance(gs, list): g = Symbol('\\text{generated}') diff -Nru python3-sympy-0.7.2/sympy/integrals/prde.py python3-sympy-0.7.3/sympy/integrals/prde.py --- python3-sympy-0.7.2/sympy/integrals/prde.py 1970-01-01 00:00:00.000000000 +0000 +++ python3-sympy-0.7.3/sympy/integrals/prde.py 2013-07-13 17:53:32.000000000 +0000 @@ -0,0 +1,899 @@ +""" +Algorithms for solving Parametric Risch Differential Equations. + +The methods used for solving Parametric Risch Differential Equations parallel +those for solving Risch Differential Equations. See the outline in the +docstring of rde.py for more information. + +The Parametric Risch Differential Equation problem is, given f, g1, ..., gm in +K(t), to determine if there exist y in K(t) and c1, ..., cm in Const(K) such +that Dy + f*y == Sum(ci*gi, (i, 1, m)), and to find such y and ci if they exist. + +For the algorithms here G is a list of tuples of factions of the terms on the +right hand side of the equation (i.e., gi in k(t)), and Q is a list of terms on +the right hand side of the equation (i.e., qi in k[t]). See the docstring of +each function for more information. +""" + +from sympy.core import Dummy, ilcm, Add, Mul, Pow, S + +from sympy.matrices import Matrix, zeros, eye + +from sympy import im, sqrt, re +from sympy.solvers import solve + +from sympy.polys import Poly, lcm, cancel, sqf_list + +from sympy.integrals.risch import (gcdex_diophantine, frac_in, derivation, + NonElementaryIntegralException, residue_reduce, splitfactor, + residue_reduce_derivation, DecrementLevel, recognize_log_derivative) +from sympy.integrals.rde import (order_at, order_at_oo, weak_normalizer, + bound_degree, spde, solve_poly_rde) +from functools import reduce + + +def prde_normal_denom(fa, fd, G, DE): + """ + Parametric Risch Differential Equation - Normal part of the denominator. + + Given a derivation D on k[t] and f, g1, ..., gm in k(t) with f weakly + normalized with respect to t, return the tuple (a, b, G, h) such that + a, h in k[t], b in k, G = [g1, ..., gm] in k(t)^m, and for any solution + c1, ..., cm in Const(k) and y in k(t) of Dy + f*y == Sum(ci*gi, (i, 1, m)), + q == y*h in k satisfies a*Dq + b*q == Sum(ci*Gi, (i, 1, m)). + """ + dn, ds = splitfactor(fd, DE) + Gas, Gds = list(zip(*G)) + gd = reduce(lambda i, j: i.lcm(j), Gds, Poly(1, DE.t)) + en, es = splitfactor(gd, DE) + + p = dn.gcd(en) + h = en.gcd(en.diff(DE.t)).quo(p.gcd(p.diff(DE.t))) + + a = dn*h + c = a*h + + ba = a*fa - dn*derivation(h, DE)*fd + ba, bd = ba.cancel(fd, include=True) + + G = [(c*A).cancel(D, include=True) for A, D in G] + + return (a, (ba, bd), G, h) + +def real_imag(ba, bd, gen): + """ + Helper function, to get the real and imaginary part of a rational function + evaluated at sqrt(-1) without actually evaluating it at sqrt(-1) + + Seperates the even and odd power terms by checking the degree of terms wrt + mod 4. Returns a tuple (ba[0], ba[1], bd) where ba[0] is real part + of the numerator ba[1] is the imaginary part and bd is the denominator + of the rational function. + """ + bd = bd.as_poly(gen).as_dict() + ba = ba.as_poly(gen).as_dict() + denom_real = [value if key[0] % 4 == 0 else -value if key[0] % 4 == 2 else 0 for key, value in list(bd.items())] + denom_imag = [value if key[0] % 4 == 1 else -value if key[0] % 4 == 3 else 0 for key, value in list(bd.items())] + bd_real = sum(r for r in denom_real) + bd_imag = sum(r for r in denom_imag) + num_real = [value if key[0] % 4 == 0 else -value if key[0] % 4 == 2 else 0 for key, value in list(ba.items())] + num_imag = [value if key[0] % 4 == 1 else -value if key[0] % 4 == 3 else 0 for key, value in list(ba.items())] + ba_real = sum(r for r in num_real) + ba_imag = sum(r for r in num_imag) + ba = ((ba_real*bd_real + ba_imag*bd_imag).as_poly(gen), (ba_imag*bd_real - ba_real*bd_imag).as_poly(gen)) + bd = (bd_real*bd_real + bd_imag*bd_imag).as_poly(gen) + return (ba[0], ba[1], bd) + + +def prde_special_denom(a, ba, bd, G, DE, case='auto'): + """ + Parametric Risch Differential Equation - Special part of the denominator. + + case is on of {'exp', 'tan', 'primitive'} for the hyperexponential, + hypertangent, and primitive cases, respectively. For the hyperexponential + (resp. hypertangent) case, given a derivation D on k[t] and a in k[t], + b in k, and g1, ..., gm in k(t) with Dt/t in k (resp. Dt/(t**2 + 1) in + k, sqrt(-1) not in k), a != 0, and gcd(a, t) == 1 (resp. + gcd(a, t**2 + 1) == 1), return the tuple (A, B, GG, h) such that A, B, h in + k[t], GG = [gg1, ..., ggm] in k(t)^m, and for any solution c1, ..., cm in + Const(k) and q in k of a*Dq + b*q == Sum(ci*gi, (i, 1, m)), r == q*h in + k[t] satisfies A*Dr + B*r == Sum(ci*ggi, (i, 1, m)). + + For case == 'primitive', k == k[t], so it returns (a, b, G, 1) in this + case. + """ + # TODO: Merge this with the very similar special_denom() in rde.py + if case == 'auto': + case = DE.case + + if case == 'exp': + p = Poly(DE.t, DE.t) + elif case == 'tan': + p = Poly(DE.t**2 + 1, DE.t) + elif case in ['primitive', 'base']: + B = ba.quo(bd) + return (a, B, G, Poly(1, DE.t)) + else: + raise ValueError("case must be one of {'exp', 'tan', 'primitive', " + "'base'}, not %s." % case) + + nb = order_at(ba, p, DE.t) - order_at(bd, p, DE.t) + nc = min([order_at(Ga, p, DE.t) - order_at(Gd, p, DE.t) for Ga, Gd in G]) + n = min(0, nc - min(0, nb)) + if not nb: + # Possible cancellation. + if case == 'exp': + dcoeff = DE.d.quo(Poly(DE.t, DE.t)) + with DecrementLevel(DE): # We are guaranteed to not have problems, + # because case != 'base'. + alphaa, alphad = frac_in(-ba.eval(0)/bd.eval(0)/a.eval(0), DE.t) + etaa, etad = frac_in(dcoeff, DE.t) + A = parametric_log_deriv(alphaa, alphad, etaa, etad, DE) + if A is not None: + a, m, z = A + if a == 1: + n = min(n, m) + + elif case == 'tan': + dcoeff = DE.d.quo(Poly(DE.t**2 + 1, DE.t)) + with DecrementLevel(DE): # We are guaranteed to not have problems, + # because case != 'base'. + betaa, alphaa, alphad = real_imag(ba, bd*a, DE.t) + betad = alphad + etaa, etad = frac_in(dcoeff, DE.t) + if recognize_log_derivative(2*betaa, betad, DE): + A = parametric_log_deriv(alphaa, alphad, etaa, etad, DE) + B = parametric_log_deriv(betaa, betad, etaa, etad, DE) + if A is not None and B is not None: + a, s, z = A + if a == 1: + n = min(n, s/2) + + N = max(0, -nb) + pN = p**N + pn = p**-n # This is 1/h + + A = a*pN + B = ba*pN.quo(bd) + Poly(n, DE.t)*a*derivation(p, DE).quo(p)*pN + G = [(Ga*pN*pn).cancel(Gd, include=True) for Ga, Gd in G] + h = pn + + # (a*p**N, (b + n*a*Dp/p)*p**N, g1*p**(N - n), ..., gm*p**(N - n), p**-n) + return (A, B, G, h) + + +def prde_linear_constraints(a, b, G, DE): + """ + Parametric Risch Differential Equation - Generate linear constraints on the constants. + + Given a derivation D on k[t], a, b, in k[t] with gcd(a, b) == 1, and + G = [g1, ..., gm] in k(t)^m, return Q = [q1, ..., qm] in k[t]^m and a + matrix M with entries in k(t) such that for any solution c1, ..., cm in + Const(k) and p in k[t] of a*Dp + b*p == Sum(ci*gi, (i, 1, m)), + (c1, ..., cm) is a solution of Mx == 0, and p and the ci satisfy + a*Dp + b*p == Sum(ci*qi, (i, 1, m)). + + Because M has entries in k(t), and because Matrix doesn't play well with + Poly, M will be a Matrix of Basic expressions. + """ + m = len(G) + + Gns, Gds = list(zip(*G)) + d = reduce(lambda i, j: i.lcm(j), Gds) + d = Poly(d, field=True) + Q = [(ga*(d).quo(gd)).div(d) for ga, gd in G] + + if not all([ri.is_zero for _, ri in Q]): + N = max([ri.degree(DE.t) for _, ri in Q]) + M = Matrix(N + 1, m, lambda i, j: Q[j][1].nth(i)) + else: + M = Matrix() # No constraints, return the empty matrix. + + qs, _ = list(zip(*Q)) + return (qs, M) + + +def constant_system(A, u, DE): + """ + Generate a system for the constant solutions. + + Given a differential field (K, D) with constant field C = Const(K), a Matrix + A, and a vector (Matrix) u with coefficients in K, returns the tuple + (B, v, s), where B is a Matrix with coefficients in C and v is a vector + (Matrix) such that either v has coefficients in C, in which case s is True + and the solutions in C of Ax == u are exactly all the solutions of Bx == v, + or v has a non-constant coefficient, in which case s is False Ax == u has no + constant solution. + + This algorithm is used both in solving parametric problems and in + determining if an element a of K is a derivative of an element of K or the + logarithmic derivative of a K-radical using the structure theorem approach. + + Because Poly does not play well with Matrix yet, this algorithm assumes that + all matrix entries are Basic expressions. + """ + Au = A.row_join(u) + Au = Au.rref(simplify=cancel)[0] + # Warning: This will NOT return correct results if cancel() cannot reduce + # an identically zero expression to 0. The danger is that we might + # incorrectly prove that an integral is nonelementary (such as + # risch_integrate(exp((sin(x)**2 + cos(x)**2 - 1)*x**2), x). + # But this is a limitation in computer algebra in general, and implicit + # in the correctness of the Risch Algorithm is the computability of the + # constant field (actually, this same correctness problem exists in any + # algorithm that uses rref()). + # + # We therefore limit ourselves to constant fields that are computable + # via the cancel() function, in order to prevent a speed bottleneck from + # calling some more complex simplification function (rational function + # coefficients will fall into this class). Furthermore, (I believe) this + # problem will only crop up if the integral explicitly contains an + # expression in the constant field that is identically zero, but cannot + # be reduced to such by cancel(). Therefore, a careful user can avoid this + # problem entirely by being careful with the sorts of expressions that + # appear in his integrand in the variables other than the integration + # variable (the structure theorems should be able to completely decide these + # problems in the integration variable). + + Au = Au.applyfunc(cancel) + A, u = Au[:, :-1], Au[:, -1] + + for j in range(A.cols): + for i in range(A.rows): + if A[i, j].has(*DE.T): + # This assumes that const(F(t0, ..., tn) == const(K) == F + Ri = A[i, :] + # Rm+1; m = A.rows + Rm1 = Ri.applyfunc(lambda x: derivation(x, DE, basic=True)/ + derivation(A[i, j], DE, basic=True)) + Rm1 = Rm1.applyfunc(cancel) + um1 = cancel(derivation(u[i], DE, basic=True)/ + derivation(A[i, j], DE, basic=True)) + + for s in range(A.rows): + # A[s, :] = A[s, :] - A[s, i]*A[:, m+1] + Asj = A[s, j] + A.row_op(s, lambda r, jj: cancel(r - Asj*Rm1[jj])) + # u[s] = u[s] - A[s, j]*u[m+1 + u.row_op(s, lambda r, jj: cancel(r - Asj*um1)) + + A = A.col_join(Rm1) + u = u.col_join(Matrix([um1])) + + return (A, u) + + +def prde_spde(a, b, Q, n, DE): + """ + Special Polynomial Differential Equation algorithm: Parametric Version. + + Given a derivation D on k[t], an integer n, and a, b, q1, ..., qm in k[t] + with deg(a) > 0 and gcd(a, b) == 1, return (A, B, Q, R, n1), with + Qq = [q1, ..., qm] and R = [r1, ..., rm], such that for any solution + c1, ..., cm in Const(k) and q in k[t] of degree at most n of + a*Dq + b*q == Sum(ci*gi, (i, 1, m)), p = (q - Sum(ci*ri, (i, 1, m)))/a has + degree at most n1 and satisfies A*Dp + B*p == Sum(ci*qi, (i, 1, m)) + """ + R, Z = list(zip(*[gcdex_diophantine(b, a, qi) for qi in Q])) + + A = a + B = b + derivation(a, DE) + Qq = [zi - derivation(ri, DE) for ri, zi in zip(R, Z)] + R = list(R) + n1 = n - a.degree(DE.t) + + return (A, B, Qq, R, n1) + + +def prde_no_cancel_b_large(b, Q, n, DE): + """ + Parametric Poly Risch Differential Equation - No cancellation: deg(b) large enough. + + Given a derivation D on k[t], n in ZZ, and b, q1, ..., qm in k[t] with + b != 0 and either D == d/dt or deg(b) > max(0, deg(D) - 1), returns + h1, ..., hr in k[r] and a matrix A with coefficients in Const(k) such that + if c1, ..., cm in Const(k) and q in k[t] satisfy deg(q) <= n and + Dq + b*Q == Sum(ci*qi, (i, 1, m)), then q = Sum(dj*hj, (j, 1, r)), where + d1, ..., dr in Const(k) and A*Matrix([[c1, ..., cm, d1, ..., dr]]).T == 0. + """ + db = b.degree(DE.t) + m = len(Q) + H = [Poly(0, DE.t)]*m + + for N in range(n, -1, -1): # [n, ..., 0] + for i in range(m): + si = Q[i].nth(N + db)/b.LC() + sitn = Poly(si*DE.t**N, DE.t) + H[i] = H[i] + sitn + Q[i] = Q[i] - derivation(sitn, DE) - b*sitn + + if all(qi.is_zero for qi in Q): + dc = -1 + M = zeros(0, 2) + else: + dc = max([qi.degree(t) for qi in Q]) + M = Matrix(dc + 1, m, lambda i, j: Q[j].nth(i)) + A, u = constant_system(M, zeros(dc + 1, 1), DE) + c = eye(m) + A = A.row_join(zeros(A.rows, m)).col_join(c.row_join(-c)) + + return (H, A) + + +def prde_no_cancel_b_small(b, Q, n, DE): + """ + Parametric Poly Risch Differential Equation - No cancellation: deg(b) small enough. + + Given a derivation D on k[t], n in ZZ, and b, q1, ..., qm in k[t] with + deg(b) < deg(D) - 1 and either D == d/dt or deg(D) >= 2, returns + h1, ..., hr in k[t] and a matrix A with coefficients in Const(k) such that + if c1, ..., cm in Const(k) and q in k[t] satisfy deg(q) <= n and + Dq + b*q == Sum(ci*qi, (i, 1, m)) then q = Sum(dj*hj, (j, 1, r)) where + d1, ..., dr in Const(k) and A*Matrix([[c1, ..., cm, d1, ..., dr]]).T == 0. + """ + m = len(Q) + H = [Poly(0, DE.t)]*m + + for N in range(n, 0, -1): # [n, ..., 1] + for i in range(m): + si = Q[i].nth(N + DE.d.degree(DE.t) - 1)/(N*DE.d.LC()) + sitn = Poly(si*DE.t**N, DE.t) + H[i] = H[i] + sitn + Q[i] = Q[i] - derivation(sitn, DE) - b*sitn + + if b.degree(DE.t) > 0: + for i in range(m): + si = Poly(Q[i].nth(b.degree(DE.t))/b.LC(), DE.t) + H[i] = H[i] + si + Q[i] = Q[i] - derivation(si, DE) - b*si + if all(qi.is_zero for qi in Q): + dc = -1 + M = Matrix() + else: + dc = max([qi.degree(DE.t) for qi in Q]) + M = Matrix(dc + 1, m, lambda i, j: Q[j].nth(i)) + A, u = constant_system(M, zeros(dc + 1, 1), DE) + c = eye(m) + A = A.row_join(zeros(A.rows, m)).col_join(c.row_join(-c)) + return (H, A) + else: + # TODO: implement this (requires recursive param_rischDE() call) + raise NotImplementedError + + +def param_rischDE(fa, fd, G, DE): + """ + Solve a Parametric Risch Differential Equation: Dy + f*y == Sum(ci*Gi, (i, 1, m)). + """ + _, (fa, fd) = weak_normalizer(fa, fd, DE) + a, (ba, bd), G, hn = prde_normal_denom(ga, gd, G, DE) + A, B, G, hs = prde_special_denom(a, ba, bd, G, DE) + g = gcd(A, B) + A, B, G = A.quo(g), B.quo(g), [gia.cancel(gid*g, include=True) for + gia, gid in G] + Q, M = prde_linear_constraints(A, B, G, DE) + M, _ = constant_system(M, zeros(M.rows, 1), DE) + # Reduce number of constants at this point + try: + # Similar to rischDE(), we try oo, even though it might lead to + # non-termination when there is no solution. At least for prde_spde, + # it will always terminate no matter what n is. + n = bound_degree(A, B, G, DE, parametric=True) + except NotImplementedError: + # Useful for debugging: + # import warnings + # warnings.warn("param_rischDE: Proceeding with n = oo; may cause " + # "non-termination.") + n = oo + + A, B, Q, R, n1 = prde_spde(A, B, Q, n, DE) + + +def limited_integrate_reduce(fa, fd, G, DE): + """ + Simpler version of step 1 & 2 for the limited integration problem. + + Given a derivation D on k(t) and f, g1, ..., gn in k(t), return + (a, b, h, N, g, V) such that a, b, h in k[t], N is a non-negative integer, + g in k(t), V == [v1, ..., vm] in k(t)^m, and for any solution v in k(t), + c1, ..., cm in C of f == Dv + Sum(ci*wi, (i, 1, m)), p = v*h is in k, and + p and the ci satisfy a*Dp + b*p == g + Sum(ci*vi, (i, 1, m)). Furthermore, + if S1irr == Sirr, then p is in k[t], and if t is nonlinear or Liouvillian + over k, then deg(p) <= N. + + So that the special part is always computed, this function calls the more + general prde_special_denom() automatically if it cannot determine that + S1irr == Sirr. Furthermore, it will automatically call bound_degree() when + t is linear and non-Liouvillian, which for the transcendental case, implies + that Dt == a*t + b with for some a, b in k*. + """ + dn, ds = splitfactor(fd, DE) + E = [splitfactor(gd, DE) for _, gd in G] + En, Es = list(zip(*E)) + c = reduce(lambda i, j: i.lcm(j), (dn,) + En) # lcm(dn, en1, ..., enm) + hn = c.gcd(c.diff(DE.t)) + a = hn + b = -derivation(hn, DE) + N = 0 + + # These are the cases where we know that S1irr = Sirr, but there could be + # others, and this algorithm will need to be extended to handle them. + if DE.case in ['base', 'primitive', 'exp', 'tan']: + hs = reduce(lambda i, j: i.lcm(j), (ds,) + Es) # lcm(ds, es1, ..., esm) + a = hn*hs + b = -derivation(hn, DE) - (hn*derivation(hs, DE)).quo(hs) + mu = min(order_at_oo(fa, fd, DE.t), min([order_at_oo(ga, gd, DE.t) for + ga, gd in G])) + # So far, all the above are also nonlinear or Liouvillian, but if this + # changes, then this will need to be updated to call bound_degree() + # as per the docstring of this function (DE.case == 'other_linear'). + N = hn.degree(DE.t) + hs.degree(DE.t) + max(0, 1 - DE.d.degree(DE.t) - mu) + else: + # TODO: implement this + raise NotImplementedError + + V = [(-a*hn*ga).cancel(gd, include=True) for ga, gd in G] + return (a, b, a, N, (a*hn*fa).cancel(fd, include=True), V) + + +def limited_integrate(fa, fd, G, DE): + """ + Solves the limited integration problem: f = Dv + Sum(ci*wi, (i, 1, n)) + """ + fa, fd = fa*Poly(1/fd.LC(), DE.t), fd.monic() + A, B, h, N, g, V = limited_integrate_reduce(fa, fd, G, DE) + V = [g] + V + g = A.gcd(B) + A, B, V = A.quo(g), B.quo(g), [via.cancel(vid*g, include=True) for + via, vid in V] + Q, M = prde_linear_constraints(A, B, V, DE) + M, _ = constant_system(M, zeros(M.rows, 1), DE) + l = M.nullspace() + if M == Matrix() or len(l) > 1: + # Continue with param_rischDE() + raise NotImplementedError("param_rischDE() is required to solve this " + "integral.") + elif len(l) == 0: + raise NonElementaryIntegralException + elif len(l) == 1: + # The c1 == 1. In this case, we can assume a normal Risch DE + if l[0][0].is_zero: + raise NonElementaryIntegralException + else: + l[0] *= 1/l[0][0] + C = sum([Poly(i, DE.t)*q for (i, q) in zip(l[0], Q)]) + # Custom version of rischDE() that uses the already computed + # denominator and degree bound from above. + B, C, m, alpha, beta = spde(A, B, C, N, DE) + y = solve_poly_rde(B, C, m, DE) + + return ((alpha*y + beta, h), list(l[0][1:])) + else: + raise NotImplementedError + + +def parametric_log_deriv_heu(fa, fd, wa, wd, DE, c1=None): + """ + Parametric logarithmic derivative heuristic. + + Given a derivation D on k[t], f in k(t), and a hyperexponential monomial + theta over k(t), raises either NotImplementedError, in which case the + heuristic failed, or returns None, in which case it has proven that no + solution exists, or returns a solution (n, m, v) of the equation + n*f == Dv/v + m*Dtheta/theta, with v in k(t)* and n, m in ZZ with n != 0. + + If this heuristic fails, the structure theorem approach will need to be + used. + + The argument w == Dtheta/theta + """ + # TODO: finish writing this and write tests + c1 = c1 or Dummy('c1') + + p, a = fa.div(fd) + q, b = wa.div(wd) + + B = max(0, derivation(DE.t, DE).degree(DE.t) - 1) + C = max(p.degree(DE.t), q.degree(DE.t)) + + if q.degree(DE.t) > B: + eqs = [p.nth(i) - c1*q.nth(i) for i in range(B + 1, C + 1)] + s = solve(eqs, c1) + if not s or not s[c1].is_Rational: + # deg(q) > B, no solution for c. + return None + + N, M = s[c1].as_numer_denom() # N and M are integers + N, M = Poly(N, DE.t), Poly(M, DE.t) + + nfmwa = N*fa*wd - M*wa*fd + nfmwd = fd*wd + Qv = is_log_deriv_k_t_radical_in_field(N*fa*wd - M*wa*fd, fd*wd, DE, + 'auto') + if Qv is None: + # (N*f - M*w) is not the logarithmic derivative of a k(t)-radical. + return None + + Q, e, v = Qv + if e != 1: + return None + + if Q.is_zero or v.is_zero: + # Q == 0 or v == 0. + return None + + return (Q*N, Q*M, v) + + if p.degree(DE.t) > B: + return None + + c = lcm(fd.as_poly(DE.t).LC(), wd.as_poly(DE.t).LC()) + l = fd.monic().lcm(wd.monic())*Poly(c, DE.t) + ln, ls = splitfactor(l, DE) + z = ls*ln.gcd(ln.diff(DE.t)) + + if not z.has(DE.t): + raise NotImplementedError("parametric_log_deriv_heu() " + "heuristic failed: z in k.") + + u1, r1 = (fa*l.quo(fd)).div(z) # (l*f).div(z) + u2, r2 = (wa*l.quo(wd)).div(z) # (l*w).div(z) + + eqs = [r1.nth(i) - c1*r2.nth(i) for i in range(z.degree(DE.t))] + s = solve(eqs, c1) + if not s or not s[c1].is_Rational: + # deg(q) <= B, no solution for c. + return None + + M, N = s[c1].as_numer_denom() + + nfmwa = N.as_poly(DE.t)*fa*wd - M.as_poly(DE.t)*wa*fd + nfmwd = fd*wd + Qv = is_log_deriv_k_t_radical_in_field(nfmwa, nfmwd, DE) + if Qv is None: + # (N*f - M*w) is not the logarithmic derivative of a k(t)-radical. + return None + + Q, v = Qv + + if Q.is_zero or v.is_zero: + # Q == 0 or v == 0. + return None + + return (Q*N, Q*M, v) + + +def parametric_log_deriv(fa, fd, wa, wd, DE): + # TODO: Write the full algorithm using the structure theorems. +# try: + A = parametric_log_deriv_heu(fa, fd, wa, wd, DE) +# except NotImplementedError: + # Heuristic failed, we have to use the full method. + # TODO: This could be implemented more efficiently. + # It isn't too worrisome, because the heuristic handles most difficult + # cases. + return A + + +def is_deriv_k(fa, fd, DE): + """ + Checks if Df/f is the derivative of an element of k(t). + + a in k(t) is the derivative of an element of k(t) if there exists b in k(t) + such that a = Db. Either returns (ans, u), such that Df/f == Du, or None, + which means that Df/f is not the derivative of an element of k(t). ans is + a list of tuples such that Add(*[i*j for i, j in ans]) == u. This is useful + for seeing exactly which elements of k(t) produce u. + + This function uses the structure theorem approach, which says that for any + f in K, Df/f is the derivative of a element of K if and only if there are ri + in QQ such that:: + + --- --- Dt + \ r * Dt + \ r * i Df + / i i / i --- = --. + --- --- t f + i in L i in E i + K/C(x) K/C(x) + + + Where C = Const(K), L_K/C(x) = { i in {1, ..., n} such that t_i is + transcendental over C(x)(t_1, ..., t_i-1) and Dt_i = Da_i/a_i, for some a_i + in C(x)(t_1, ..., t_i-1)* } (i.e., the set of all indices of logarithmic + monomials of K over C(x)), and E_K/C(x) = { i in {1, ..., n} such that t_i + is transcendental over C(x)(t_1, ..., t_i-1) and Dt_i/t_i = Da_i, for some + a_i in C(x)(t_1, ..., t_i-1) } (i.e., the set of all indices of + hyperexponential monomials of K over C(x)). If K is an elementary extension + over C(x), then the cardinality of L_K/C(x) U E_K/C(x) is exactly the + transcendence degree of K over C(x). Furthermore, because Const_D(K) == + Const_D(C(x)) == C, deg(Dt_i) == 1 when t_i is in E_K/C(x) and + deg(Dt_i) == 0 when t_i is in L_K/C(x), implying in particular that E_K/C(x) + and L_K/C(x) are disjoint. + + The sets L_K/C(x) and E_K/C(x) must, by their nature, be computed + recursively using this same function. Therefore, it is required to pass + them as indices to D (or T). E_args are the arguments of the + hyperexponentials indexed by E_K (i.e., if i is in E_K, then T[i] == + exp(E_args[i])). This is needed to compute the final answer u such that + Df/f == Du. + + log(f) will be the same as u up to a additive constant. This is because + they will both behave the same as monomials. For example, both log(x) and + log(2*x) == log(x) + log(2) satisfy Dt == 1/x, because log(2) is constant. + Therefore, the term const is returned. const is such that + log(const) + f == u. This is calculated by dividing the arguments of one + logarithm from the other. Therefore, it is necessary to pass the arguments + of the logarithmic terms in L_args. + + To handle the case where we are given Df/f, not f, use is_deriv_k_in_field(). + """ + # Compute Df/f + dfa, dfd = fd*(fd*derivation(fa, DE) - fa*derivation(fd, DE)), fd**2*fa + dfa, dfd = dfa.cancel(dfd, include=True) + + # Our assumption here is that each monomial is recursively transcendental + if len(DE.L_K) + len(DE.E_K) != len(DE.D) - 1: + if [i for i in DE.cases if i == 'tan'] or \ + set([i for i in DE.cases if i == 'primitive']) - set(DE.L_K): + raise NotImplementedError("Real version of the structure " + "theorems with hypertangent support is not yet implemented.") + + # TODO: What should really be done in this case? + raise NotImplementedError("Nonelementary extensions not supported " + "in the structure theorems.") + + E_part = [DE.D[i].quo(Poly(DE.T[i], DE.T[i])).as_expr() for i in DE.E_K] + L_part = [DE.D[i].as_expr() for i in DE.L_K] + + lhs = Matrix([E_part + L_part]) + rhs = Matrix([dfa.as_expr()/dfd.as_expr()]) + + A, u = constant_system(lhs, rhs, DE) + + if not all(derivation(i, DE, basic=True).is_zero for i in u) or not A: + # If the elements of u are not all constant + # Note: See comment in constant_system + + # Also note: derivation(basic=True) calls cancel() + return None + else: + if not all(i.is_Rational for i in u): + raise NotImplementedError("Cannot work with non-rational " + "coefficients in this case.") + else: + terms = DE.E_args + [DE.T[i] for i in DE.L_K] + ans = list(zip(terms, u)) + result = Add(*[Mul(i, j) for i, j in ans]) + argterms = [DE.T[i] for i in DE.E_K] + DE.L_args + l = [] + for i, j in zip(argterms, u): + # We need to get around things like sqrt(x**2) != x + # and also sqrt(x**2 + 2*x + 1) != x + 1 + icoeff, iterms = sqf_list(i) + l.append(Mul(*([Pow(icoeff, j)] + [Pow(b, e*j) for b, e in iterms]))) + const = cancel(fa.as_expr()/fd.as_expr()/Mul(*l)) + + return (ans, result, const) + + +def is_log_deriv_k_t_radical(fa, fd, DE, Df=True): + """ + Checks if Df is the logarithmic derivative of a k(t)-radical. + + b in k(t) can be written as the logarithmic derivative of a k(t) radical if + there exist n in ZZ and u in k(t) with n, u != 0 such that n*b == Du/u. + Either returns (ans, u, n, const) or None, which means that Df cannot be + written as the logarithmic derivative of a k(t)-radical. ans is a list of + tuples such that Mul(*[i**j for i, j in ans]) == u. This is useful for + seeing exactly what elements of k(t) produce u. + + This function uses the structure theorem approach, which says that for any + f in K, Df is the logarithmic derivative of a K-radical if and only if there + are ri in QQ such that:: + + --- --- Dt + \ r * Dt + \ r * i + / i i / i --- = Df. + --- --- t + i in L i in E i + K/C(x) K/C(x) + + + Where C = Const(K), L_K/C(x) = { i in {1, ..., n} such that t_i is + transcendental over C(x)(t_1, ..., t_i-1) and Dt_i = Da_i/a_i, for some a_i + in C(x)(t_1, ..., t_i-1)* } (i.e., the set of all indices of logarithmic + monomials of K over C(x)), and E_K/C(x) = { i in {1, ..., n} such that t_i + is transcendental over C(x)(t_1, ..., t_i-1) and Dt_i/t_i = Da_i, for some + a_i in C(x)(t_1, ..., t_i-1) } (i.e., the set of all indices of + hyperexponential monomials of K over C(x)). If K is an elementary extension + over C(x), then the cardinality of L_K/C(x) U E_K/C(x) is exactly the + transcendence degree of K over C(x). Furthermore, because Const_D(K) == + Const_D(C(x)) == C, deg(Dt_i) == 1 when t_i is in E_K/C(x) and + deg(Dt_i) == 0 when t_i is in L_K/C(x), implying in particular that E_K/C(x) + and L_K/C(x) are disjoint. + + The sets L_K/C(x) and E_K/C(x) must, by their nature, be computed + recursively using this same function. Therefore, it is required to pass + them as indices to D (or T). L_args are the arguments of the logarithms + indexed by L_K (i.e., if i is in L_K, then T[i] == log(L_args[i])). This is + needed to compute the final answer u such that n*f == Du/u. + + exp(f) will be the same as u up to a multiplicative constant. This is + because they will both behave the same as monomials. For example, both + exp(x) and exp(x + 1) == E*exp(x) satisfy Dt == t. Therefore, the term const + is returned. const is such that exp(const)*f == u. This is calculated by + subtracting the arguments of one exponential from the other. Therefore, it + is necessary to pass the arguments of the exponential terms in E_args. + + To handle the case where we are given Df, not f, use + is_log_deriv_k_t_radical_in_field(). + """ + H = [] + if Df: + dfa, dfd = (fd*derivation(fa, DE) - fa*derivation(fd, DE)).cancel(fd**2, + include=True) + else: + dfa, dfd = fa, fd + + # Our assumption here is that each monomial is recursively transcendental + if len(DE.L_K) + len(DE.E_K) != len(DE.D) - 1: + if [i for i in DE.cases if i == 'tan'] or \ + set([i for i in DE.cases if i == 'primitive']) - set(DE.L_K): + raise NotImplementedError("Real version of the structure " + "theorems with hypertangent support is not yet implemented.") + + # TODO: What should really be done in this case? + raise NotImplementedError("Nonelementary extensions not supported " + "in the structure theorems.") + + E_part = [DE.D[i].quo(Poly(DE.T[i], DE.T[i])).as_expr() for i in DE.E_K] + L_part = [DE.D[i].as_expr() for i in DE.L_K] + + lhs = Matrix([E_part + L_part]) + rhs = Matrix([dfa.as_expr()/dfd.as_expr()]) + + A, u = constant_system(lhs, rhs, DE) + if not all(derivation(i, DE, basic=True).is_zero for i in u) or not A: + # If the elements of u are not all constant + # Note: See comment in constant_system + + # Also note: derivation(basic=True) calls cancel() + return None + else: + if not all(i.is_Rational for i in u): + # TODO: But maybe we can tell if they're not rational, like + # log(2)/log(3). Also, there should be an option to continue + # anyway, even if the result might potentially be wrong. + raise NotImplementedError("Cannot work with non-rational " + "coefficients in this case.") + else: + n = reduce(ilcm, [i.as_numer_denom()[1] for i in u]) + u *= n + terms = [DE.T[i] for i in DE.E_K] + DE.L_args + ans = list(zip(terms, u)) + result = Mul(*[Pow(i, j) for i, j in ans]) + + # exp(f) will be the same as result up to a multiplicative + # constant. We now find the log of that constant. + argterms = DE.E_args + [DE.T[i] for i in DE.L_K] + const = cancel(fa.as_expr()/fd.as_expr() - + Add(*[Mul(i, j/n) for i, j in zip(argterms, u)])) + + return (ans, result, n, const) + + +def is_log_deriv_k_t_radical_in_field(fa, fd, DE, case='auto', z=None): + """ + Checks if f can be written as the logarithmic derivative of a k(t)-radical. + + f in k(t) can be written as the logarithmic derivative of a k(t) radical if + there exist n in ZZ and u in k(t) with n, u != 0 such that n*f == Du/u. + Either returns (n, u) or None, which means that f cannot be written as the + logarithmic derivative of a k(t)-radical. + + case is one of {'primitive', 'exp', 'tan', 'auto'} for the primitive, + hyperexponential, and hypertangent cases, respectively. If case it 'auto', + it will attempt to determine the type of the derivation automatically. + """ + fa, fd = fa.cancel(fd, include=True) + + # f must be simple + n, s = splitfactor(fd, DE) + if not s.is_one: + pass + #return None + + z = z or Dummy('z') + H, b = residue_reduce(fa, fd, DE, z=z) + if not b: + # I will have to verify, but I believe that the answer should be + # None in this case. This should never happen for the + # functions given when solving the parametric logarithmic + # derivative problem when integration elementary functions (see + # Bronstein's book, page 255), so most likely this indicates a bug. + return None + + roots = [(i, i.real_roots()) for i, _ in H] + if not all(len(j) == i.degree() and all(k.is_Rational for k in j) for + i, j in roots): + # If f is the logarithmic derivative of a k(t)-radical, then all the + # roots of the resultant must be rational numbers. + return None + + # [(a, i), ...], where i*log(a) is a term in the log-part of the integral + # of f + respolys, residues = list(zip(*roots)) or [[], []] + # Note: this might be empty, but everything below should work find in that + # case (it should be the same as if it were [[1, 1]]) + residueterms = [(H[j][1].subs(z, i), i) for j in range(len(H)) for + i in residues[j]] + + # TODO: finish writing this and write tests + + p = cancel(fa.as_expr()/fd.as_expr() - residue_reduce_derivation(H, DE, z)) + + p = p.as_poly(DE.t) + if p is None: + # f - Dg will be in k[t] if f is the logarithmic derivative of a k(t)-radical + return None + + if p.degree(DE.t) >= max(1, DE.d.degree(DE.t)): + return None + + if case == 'auto': + case = DE.case + + if case == 'exp': + wa, wd = derivation(DE.t, DE).cancel(Poly(DE.t, DE.t), include=True) + with DecrementLevel(DE): + pa, pd = frac_in(p, DE.t, cancel=True) + wa, wd = frac_in((wa, wd), DE.t) + A = parametric_log_deriv(pa, pd, wa, wd, DE) + if A is None: + return None + n, e, u = A + u *= DE.t**e +# raise NotImplementedError("The hyperexponential case is " +# "not yet completely implemented for is_log_deriv_k_t_radical_in_field().") + + elif case == 'primitive': + with DecrementLevel(DE): + pa, pd = frac_in(p, DE.t) + A = is_log_deriv_k_t_radical_in_field(pa, pd, DE, case='auto') + if A is None: + return None + n, u = A + + elif case == 'base': + # TODO: we can use more efficient residue reduction from ratint() + if not fd.is_sqf or fa.degree() >= fd.degree(): + # f is the logarithmic derivative in the base case if and only if + # f = fa/fd, fd is square-free, deg(fa) < deg(fd), and + # gcd(fa, fd) == 1. The last condition is handled by cancel() above. + return None + # Note: if residueterms = [], returns (1, 1) + # f had better be 0 in that case. + n = reduce(ilcm, [i.as_numer_denom()[1] for _, i in residueterms], S(1)) + u = Mul(*[Pow(i, j*n) for i, j in residueterms]) + return (n, u) + + elif case == 'tan': + raise NotImplementedError("The hypertangent case is " + "not yet implemented for is_log_deriv_k_t_radical_in_field()") + + elif case in ['other_linear', 'other_nonlinear']: + # XXX: If these are supported by the structure theorems, change to NotImplementedError. + raise ValueError("The %s case is not supported in this function." % case) + + else: + raise ValueError("case must be one of {'primitive', 'exp', 'tan', " + "'base', 'auto'}, not %s" % case) + + common_denom = reduce(ilcm, [i.as_numer_denom()[1] for i in [j for _, j in + residueterms]] + [n], S(1)) + residueterms = [(i, j*common_denom) for i, j in residueterms] + m = common_denom//n + assert common_denom == n*m # Verify exact division + u = cancel(u**m*Mul(*[Pow(i, j) for i, j in residueterms])) + + return (common_denom, u) diff -Nru python3-sympy-0.7.2/sympy/integrals/quadrature.py python3-sympy-0.7.3/sympy/integrals/quadrature.py --- python3-sympy-0.7.2/sympy/integrals/quadrature.py 1970-01-01 00:00:00.000000000 +0000 +++ python3-sympy-0.7.3/sympy/integrals/quadrature.py 2013-07-13 17:53:32.000000000 +0000 @@ -0,0 +1,496 @@ +from sympy.core import S, Dummy, pi +from sympy.functions.combinatorial.factorials import factorial +from sympy.functions.elementary.trigonometric import sin, cos +from sympy.functions.elementary.miscellaneous import sqrt +from sympy.functions.special.gamma_functions import gamma +from sympy.polys.orthopolys import legendre_poly, laguerre_poly, hermite_poly, jacobi_poly +from sympy.polys.rootoftools import RootOf + +def gauss_legendre(n, n_digits): + r""" + Computes the Gauss-Legendre quadrature [1]_ points and weights. + + The Gauss-Legendre quadrature approximates the integral: + + .. math:: + \int_{-1}^1 f(x)\,dx \approx \sum_{i=1}^n w_i f(x_i) + + The nodes `x_i` of an order `n` quadrature rule are the roots of `P_n` + and the weights `w_i` are given by: + + .. math:: + w_i = \frac{2}{\left(1-x_i^2\right) \left(P'_n(x_i)\right)^2} + + Parameters + ========== + + n : the order of quadrature + + n_digits : number of significant digits of the points and weights to return + + Returns + ======= + + (x, w) : the ``x`` and ``w`` are lists of points and weights as Floats. + The points `x_i` and weights `w_i` are returned as ``(x, w)`` + tuple of lists. + + Examples + ======== + + >>> from sympy.integrals.quadrature import gauss_legendre + >>> x, w = gauss_legendre(3, 5) + >>> x + [-0.7746, 0, 0.7746] + >>> w + [0.55556, 0.88889, 0.55556] + >>> x, w = gauss_legendre(4, 5) + >>> x + [-0.86114, -0.33998, 0.33998, 0.86114] + >>> w + [0.34786, 0.65215, 0.65215, 0.34786] + + See Also + ======== + + gauss_laguerre, gauss_gen_laguerre, gauss_hermite, gauss_chebyshev_t, gauss_chebyshev_u, gauss_jacobi + + References + ========== + + .. [1] http://en.wikipedia.org/wiki/Gaussian_quadrature + .. [2] http://people.sc.fsu.edu/~jburkardt/cpp_src/legendre_rule/legendre_rule.html + """ + x = Dummy("x") + p = legendre_poly(n, x, polys=True) + pd = p.diff(x) + xi = [] + w = [] + for r in p.real_roots(): + if isinstance(r, RootOf): + r = r.eval_rational(S(1)/10**(n_digits+2)) + xi.append(r.n(n_digits)) + w.append((2/((1-r**2) * pd.subs(x, r)**2)).n(n_digits)) + return xi, w + +def gauss_laguerre(n, n_digits): + r""" + Computes the Gauss-Laguerre quadrature [1]_ points and weights. + + The Gauss-Laguerre quadrature approximates the integral: + + .. math:: + \int_0^{\infty} e^{-x} f(x)\,dx \approx \sum_{i=1}^n w_i f(x_i) + + + The nodes `x_i` of an order `n` quadrature rule are the roots of `L_n` + and the weights `w_i` are given by: + + .. math:: + w_i = \frac{x_i}{(n+1)^2 \left(L_{n+1}(x_i)\right)^2} + + Parameters + ========== + + n : the order of quadrature + + n_digits : number of significant digits of the points and weights to return + + Returns + ======= + + (x, w) : the ``x`` and ``w`` are lists of points and weights as Floats. + The points `x_i` and weights `w_i` are returned as ``(x, w)`` + tuple of lists. + + Examples + ======== + + >>> from sympy.integrals.quadrature import gauss_laguerre + >>> x, w = gauss_laguerre(3, 5) + >>> x + [0.41577, 2.2943, 6.2899] + >>> w + [0.71109, 0.27852, 0.010389] + >>> x, w = gauss_laguerre(6, 5) + >>> x + [0.22285, 1.1889, 2.9927, 5.7751, 9.8375, 15.983] + >>> w + [0.45896, 0.417, 0.11337, 0.010399, 0.00026102, 8.9855e-7] + + See Also + ======== + + gauss_legendre, gauss_gen_laguerre, gauss_hermite, gauss_chebyshev_t, gauss_chebyshev_u, gauss_jacobi + + References + ========== + + .. [1] http://en.wikipedia.org/wiki/Gauss%E2%80%93Laguerre_quadrature + .. [2] http://people.sc.fsu.edu/~jburkardt/cpp_src/laguerre_rule/laguerre_rule.html + """ + x = Dummy("x") + p = laguerre_poly(n, x, polys=True) + p1 = laguerre_poly(n+1, x, polys=True) + xi = [] + w = [] + for r in p.real_roots(): + if isinstance(r, RootOf): + r = r.eval_rational(S(1)/10**(n_digits+2)) + xi.append(r.n(n_digits)) + w.append((r/((n+1)**2 * p1.subs(x, r)**2)).n(n_digits)) + return xi, w + +def gauss_hermite(n, n_digits): + r""" + Computes the Gauss-Hermite quadrature [1]_ points and weights. + + The Gauss-Hermite quadrature approximates the integral: + + .. math:: + \int_{-\infty}^{\infty} e^{-x^2} f(x)\,dx \approx \sum_{i=1}^n w_i f(x_i) + + The nodes `x_i` of an order `n` quadrature rule are the roots of `H_n` + and the weights `w_i` are given by: + + .. math:: + w_i = \frac{2^{n-1} n! \sqrt{\pi}}{n^2 \left(H_{n-1}(x_i)\right)^2} + + Parameters + ========== + + n : the order of quadrature + + n_digits : number of significant digits of the points and weights to return + + Returns + ======= + + (x, w) : the ``x`` and ``w`` are lists of points and weights as Floats. + The points `x_i` and weights `w_i` are returned as ``(x, w)`` + tuple of lists. + + Examples + ======== + + >>> from sympy.integrals.quadrature import gauss_hermite + >>> x, w = gauss_hermite(3, 5) + >>> x + [-1.2247, 0, 1.2247] + >>> w + [0.29541, 1.1816, 0.29541] + + >>> x, w = gauss_hermite(6, 5) + >>> x + [-2.3506, -1.3358, -0.43608, 0.43608, 1.3358, 2.3506] + >>> w + [0.00453, 0.15707, 0.72463, 0.72463, 0.15707, 0.00453] + + See Also + ======== + + gauss_legendre, gauss_laguerre, gauss_gen_laguerre, gauss_chebyshev_t, gauss_chebyshev_u, gauss_jacobi + + References + ========== + + .. [1] http://en.wikipedia.org/wiki/Gauss-Hermite_Quadrature + .. [2] http://people.sc.fsu.edu/~jburkardt/cpp_src/hermite_rule/hermite_rule.html + .. [3] http://people.sc.fsu.edu/~jburkardt/cpp_src/gen_hermite_rule/gen_hermite_rule.html + """ + x = Dummy("x") + p = hermite_poly(n, x, polys=True) + p1 = hermite_poly(n-1, x, polys=True) + xi = [] + w = [] + for r in p.real_roots(): + if isinstance(r, RootOf): + r = r.eval_rational(S(1)/10**(n_digits+2)) + xi.append(r.n(n_digits)) + w.append(((2**(n-1) * factorial(n) * sqrt(pi))/(n**2 * p1.subs(x, r)**2)).n(n_digits)) + return xi, w + +def gauss_gen_laguerre(n, alpha, n_digits): + r""" + Computes the generalized Gauss-Laguerre quadrature [1]_ points and weights. + + The generalized Gauss-Laguerre quadrature approximates the integral: + + .. math:: + \int_{0}^\infty x^{\alpha} e^{-x} f(x)\,dx \approx \sum_{i=1}^n w_i f(x_i) + + The nodes `x_i` of an order `n` quadrature rule are the roots of `L^{\alpha}_n` + and the weights `w_i` are given by: + + .. math:: + w_i = \frac{\Gamma(\alpha+n)}{n \Gamma(n) L^{\alpha}_{n-1}(x_i) L^{\alpha+1}_{n-1}(x_i)} + + Parameters + ========== + + n : the order of quadrature + + alpha : the exponent of the singularity, `\alpha > -1` + + n_digits : number of significant digits of the points and weights to return + + Returns + ======= + + (x, w) : the ``x`` and ``w`` are lists of points and weights as Floats. + The points `x_i` and weights `w_i` are returned as ``(x, w)`` + tuple of lists. + + Examples + ======== + + >>> from sympy import S + >>> from sympy.integrals.quadrature import gauss_gen_laguerre + >>> x, w = gauss_gen_laguerre(3, -S.Half, 5) + >>> x + [0.19016, 1.7845, 5.5253] + >>> w + [1.4493, 0.31413, 0.00906] + + >>> x, w = gauss_gen_laguerre(4, 3*S.Half, 5) + >>> x + [0.97851, 2.9904, 6.3193, 11.712] + >>> w + [0.53087, 0.67721, 0.11895, 0.0023152] + + See Also + ======== + + gauss_legendre, gauss_laguerre, gauss_hermite, gauss_chebyshev_t, gauss_chebyshev_u, gauss_jacobi + + References + ========== + + .. [1] http://en.wikipedia.org/wiki/Gauss%E2%80%93Laguerre_quadrature + .. [2] http://people.sc.fsu.edu/~jburkardt/cpp_src/gen_laguerre_rule/gen_laguerre_rule.html + """ + x = Dummy("x") + p = laguerre_poly(n, x, alpha=alpha, polys=True) + p1 = laguerre_poly(n-1, x, alpha=alpha, polys=True) + p2 = laguerre_poly(n-1, x, alpha=alpha+1, polys=True) + xi = [] + w = [] + for r in p.real_roots(): + if isinstance(r, RootOf): + r = r.eval_rational(S(1)/10**(n_digits+2)) + xi.append(r.n(n_digits)) + w.append((gamma(alpha+n)/(n*gamma(n)*p1.subs(x, r)*p2.subs(x, r))).n(n_digits)) + return xi, w + +def gauss_chebyshev_t(n, n_digits): + r""" + Computes the Gauss-Chebyshev quadrature [1]_ points and weights of + the first kind. + + The Gauss-Chebyshev quadrature of the first kind approximates the integral: + + .. math:: + \int_{-1}^{1} \frac{1}{\sqrt{1-x^2}} f(x)\,dx \approx \sum_{i=1}^n w_i f(x_i) + + The nodes `x_i` of an order `n` quadrature rule are the roots of `T_n` + and the weights `w_i` are given by: + + .. math:: + w_i = \frac{\pi}{n} + + Parameters + ========== + + n : the order of quadrature + + n_digits : number of significant digits of the points and weights to return + + Returns + ======= + + (x, w) : the ``x`` and ``w`` are lists of points and weights as Floats. + The points `x_i` and weights `w_i` are returned as ``(x, w)`` + tuple of lists. + + Examples + ======== + + >>> from sympy import S + >>> from sympy.integrals.quadrature import gauss_chebyshev_t + >>> x, w = gauss_chebyshev_t(3, 5) + >>> x + [0.86602, 0, -0.86602] + >>> w + [1.0472, 1.0472, 1.0472] + + >>> x, w = gauss_chebyshev_t(6, 5) + >>> x + [0.96593, 0.70711, 0.25882, -0.25882, -0.70711, -0.96593] + >>> w + [0.5236, 0.5236, 0.5236, 0.5236, 0.5236, 0.5236] + + See Also + ======== + + gauss_legendre, gauss_laguerre, gauss_hermite, gauss_gen_laguerre, gauss_chebyshev_u, gauss_jacobi + + References + ========== + + .. [1] http://en.wikipedia.org/wiki/Chebyshev%E2%80%93Gauss_quadrature + .. [2] http://people.sc.fsu.edu/~jburkardt/cpp_src/chebyshev1_rule/chebyshev1_rule.html + """ + x = Dummy("x") + xi = [] + w = [] + for i in range(1,n+1): + xi.append((cos((2*i-S.One)/(2*n)*S.Pi)).n(n_digits)) + w.append((S.Pi/n).n(n_digits)) + return xi, w + +def gauss_chebyshev_u(n, n_digits): + r""" + Computes the Gauss-Chebyshev quadrature [1]_ points and weights of + the second kind. + + The Gauss-Chebyshev quadrature of the second kind approximates the integral: + + .. math:: + \int_{-1}^{1} \sqrt{1-x^2} f(x)\,dx \approx \sum_{i=1}^n w_i f(x_i) + + The nodes `x_i` of an order `n` quadrature rule are the roots of `U_n` + and the weights `w_i` are given by: + + .. math:: + w_i = \frac{\pi}{n+1} \sin^2 \left(\frac{i}{n+1}\pi\right) + + Parameters + ========== + + n : the order of quadrature + + n_digits : number of significant digits of the points and weights to return + + Returns + ======= + + (x, w) : the ``x`` and ``w`` are lists of points and weights as Floats. + The points `x_i` and weights `w_i` are returned as ``(x, w)`` + tuple of lists. + + Examples + ======== + + >>> from sympy import S + >>> from sympy.integrals.quadrature import gauss_chebyshev_u + >>> x, w = gauss_chebyshev_u(3, 5) + >>> x + [0.70711, 0, -0.70711] + >>> w + [0.3927, 0.7854, 0.3927] + + >>> x, w = gauss_chebyshev_u(6, 5) + >>> x + [0.90097, 0.62349, 0.22252, -0.22252, -0.62349, -0.90097] + >>> w + [0.084489, 0.27433, 0.42658, 0.42658, 0.27433, 0.084489] + + See Also + ======== + + gauss_legendre, gauss_laguerre, gauss_hermite, gauss_gen_laguerre, gauss_chebyshev_t, gauss_jacobi + + References + ========== + + .. [1] http://en.wikipedia.org/wiki/Chebyshev%E2%80%93Gauss_quadrature + .. [2] http://people.sc.fsu.edu/~jburkardt/cpp_src/chebyshev2_rule/chebyshev2_rule.html + """ + x = Dummy("x") + xi = [] + w = [] + for i in range(1,n+1): + xi.append((cos(i/(n+S.One)*S.Pi)).n(n_digits)) + w.append((S.Pi/(n+S.One)*sin(i*S.Pi/(n+S.One))**2).n(n_digits)) + return xi, w + +def gauss_jacobi(n, alpha, beta, n_digits): + r""" + Computes the Gauss-Jacobi quadrature [1]_ points and weights. + + The Gauss-Jacobi quadrature of the first kind approximates the integral: + + .. math:: + \int_{-1}^1 (1-x)^\alpha (1+x)^\beta f(x)\,dx \approx \sum_{i=1}^n w_i f(x_i) + + The nodes `x_i` of an order `n` quadrature rule are the roots of `P^{(\alpha,\beta)}_n` + and the weights `w_i` are given by: + + .. math:: + w_i = -\frac{2n+\alpha+\beta+2}{n+\alpha+\beta+1}\frac{\Gamma(n+\alpha+1)\Gamma(n+\beta+1)} + {\Gamma(n+\alpha+\beta+1)(n+1)!} \frac{2^{\alpha+\beta}}{P'_n(x_i) + P^{(\alpha,\beta)}_{n+1}(x_i)} + + Parameters + ========== + + n : the order of quadrature + + alpha : the first parameter of the Jacobi Polynomial, `\alpha > -1` + + beta : the second parameter of the Jacobi Polynomial, `\beta > -1` + + n_digits : number of significant digits of the points and weights to return + + Returns + ======= + + (x, w) : the ``x`` and ``w`` are lists of points and weights as Floats. + The points `x_i` and weights `w_i` are returned as ``(x, w)`` + tuple of lists. + + Examples + ======== + + >>> from sympy import S + >>> from sympy.integrals.quadrature import gauss_jacobi + >>> x, w = gauss_jacobi(3, S.Half, -S.Half, 5) + >>> x + [-0.90097, -0.22252, 0.62349] + >>> w + [1.7063, 1.0973, 0.33795] + + >>> x, w = gauss_jacobi(6, 1, 1, 5) + >>> x + [-0.87174, -0.5917, -0.2093, 0.2093, 0.5917, 0.87174] + >>> w + [0.050584, 0.22169, 0.39439, 0.39439, 0.22169, 0.050584] + + See Also + ======== + + gauss_legendre, gauss_laguerre, gauss_hermite, gauss_gen_laguerre, gauss_chebyshev_t, gauss_chebyshev_u + + References + ========== + + .. [1] http://en.wikipedia.org/wiki/Gauss%E2%80%93Jacobi_quadrature + .. [2] http://people.sc.fsu.edu/~jburkardt/cpp_src/jacobi_rule/jacobi_rule.html + .. [3] http://people.sc.fsu.edu/~jburkardt/cpp_src/gegenbauer_rule/gegenbauer_rule.html + """ + x = Dummy("x") + p = jacobi_poly(n, alpha, beta, x, polys=True) + pd = p.diff(x) + pn = jacobi_poly(n+1, alpha, beta, x, polys=True) + xi = [] + w = [] + for r in p.real_roots(): + if isinstance(r, RootOf): + r = r.eval_rational(S(1)/10**(n_digits+2)) + xi.append(r.n(n_digits)) + w.append(( + - (2*n+alpha+beta+2) / (n+alpha+beta+S.One) + * (gamma(n+alpha+1)*gamma(n+beta+1)) / (gamma(n+alpha+beta+S.One)*gamma(n+2)) + * 2**(alpha+beta) / (pd.subs(x, r) * pn.subs(x, r)) + ).n(n_digits)) + return xi, w diff -Nru python3-sympy-0.7.2/sympy/integrals/rationaltools.py python3-sympy-0.7.3/sympy/integrals/rationaltools.py --- python3-sympy-0.7.2/sympy/integrals/rationaltools.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/integrals/rationaltools.py 2013-07-13 17:53:32.000000000 +0000 @@ -5,6 +5,7 @@ from sympy.polys import Poly, subresultants, resultant, ZZ + def ratint(f, x, **flags): """Performs indefinite integration of rational functions. @@ -35,7 +36,7 @@ else: p, q = f - p, q = Poly(p, x, composite=False), Poly(q, x, composite=False) + p, q = Poly(p, x, composite=False, field=True), Poly(q, x, composite=False, field=True) coeff, p, q = p.cancel(q) poly, p = p.div(q) @@ -74,8 +75,7 @@ else: p, q = f - atoms = p.atoms() \ - | q.atoms() + atoms = p.atoms() | q.atoms() for elt in atoms - set([x]): if not elt.is_real: @@ -88,7 +88,8 @@ if not real: for h, q in L: - eps += RootSum(q, Lambda(t, t*log(h.as_expr())), quadratic=True) + eps += RootSum( + q, Lambda(t, t*log(h.as_expr())), quadratic=True) else: for h, q in L: R = log_to_real(h, q, x, t) @@ -96,12 +97,14 @@ if R is not None: eps += R else: - eps += RootSum(q, Lambda(t, t*log(h.as_expr())), quadratic=True) + eps += RootSum( + q, Lambda(t, t*log(h.as_expr())), quadratic=True) result += eps return coeff*result + def ratint_ratpart(f, g, x): """ Horowitz-Ostrogradsky algorithm. @@ -139,8 +142,8 @@ n = u.degree() m = v.degree() - A_coeffs = [ Dummy('a' + str(n-i)) for i in range(0, n) ] - B_coeffs = [ Dummy('b' + str(m-i)) for i in range(0, m) ] + A_coeffs = [ Dummy('a' + str(n - i)) for i in range(0, n) ] + B_coeffs = [ Dummy('b' + str(m - i)) for i in range(0, m) ] C_coeffs = A_coeffs + B_coeffs @@ -159,6 +162,7 @@ return rat_part, log_part + def ratint_logpart(f, g, x, t=None): """ Lazard-Rioboo-Trager algorithm. @@ -198,9 +202,9 @@ t = t or Dummy('t') a, b = g, f - g.diff()*Poly(t, x) - R = subresultants(a, b) + res, R = resultant(a, b, includePRS=True) - res = Poly(resultant(a, b), t, composite=False) + res = Poly(res, t, composite=False) R_map, H = {}, [] @@ -242,6 +246,7 @@ return H + def log_to_atan(f, g): """ Convert complex logarithms to real arctangents. @@ -282,11 +287,12 @@ return 2*atan(p.as_expr()) else: s, t, h = g.gcdex(-f) - u = (f*s+g*t).quo(h) + u = (f*s + g*t).quo(h) A = 2*atan(u.as_expr()) return A + log_to_atan(s, t) + def log_to_real(h, q, x, t): """ Convert complex logarithms to real functions. @@ -319,8 +325,8 @@ """ u, v = symbols('u,v', cls=Dummy) - H = h.as_expr().subs({t:u+I*v}).expand() - Q = q.as_expr().subs({t:u+I*v}).expand() + H = h.as_expr().subs({t: u + I*v}).expand() + Q = q.as_expr().subs({t: u + I*v}).expand() H_map = collect(H, I, evaluate=False) Q_map = collect(Q, I, evaluate=False) @@ -338,7 +344,7 @@ result = S(0) for r_u in R_u.keys(): - C = Poly(c.subs({u:r_u}), v) + C = Poly(c.subs({u: r_u}), v) R_v = roots(C, filter='R') if len(R_v) != C.count_roots(): @@ -348,13 +354,13 @@ if not r_v.is_positive: continue - D = d.subs({u:r_u, v:r_v}) + D = d.subs({u: r_u, v: r_v}) if D.evalf(chop=True) != 0: continue - A = Poly(a.subs({u:r_u, v:r_v}), x) - B = Poly(b.subs({u:r_u, v:r_v}), x) + A = Poly(a.subs({u: r_u, v: r_v}), x) + B = Poly(b.subs({u: r_u, v: r_v}), x) AB = (A**2 + B**2).as_expr() diff -Nru python3-sympy-0.7.2/sympy/integrals/rde.py python3-sympy-0.7.3/sympy/integrals/rde.py --- python3-sympy-0.7.2/sympy/integrals/rde.py 1970-01-01 00:00:00.000000000 +0000 +++ python3-sympy-0.7.3/sympy/integrals/rde.py 2013-07-13 17:53:32.000000000 +0000 @@ -0,0 +1,744 @@ +""" +Algorithms for solving the Risch differential equation. + +Given a differential field K of characteristic 0 that is a simple +monomial extension of a base field k and f, g in K, the Risch +Differential Equation problem is to decide if there exist y in K such +that Dy + f*y == g and to find one if there are some. If t is a +monomial over k and the coefficients of f and g are in k(t), then y is +in k(t), and the outline of the algorithm here is given as: + +1. Compute the normal part n of the denominator of y. The problem is +then reduced to finding y' in k, where y == y'/n. +2. Compute the special part s of the denominator of y. The problem is +then reduced to finding y'' in k[t], where y == y''/(n*s) +3. Bound the degree of y''. +4. Reduce the equation Dy + f*y == g to a similar equation with f, g in +k[t]. +5. Find the solutions in k[t] of bounded degree of the reduced equation. + +See Chapter 6 of "Symbolic Integration I: Transcendental Functions" by +Manuel Bronstein. See also the docstring of risch.py. +""" + + +from operator import mul + +from sympy.core import oo +from sympy.core.symbol import Dummy + +from sympy.polys import Poly, gcd, ZZ, cancel + +from sympy.integrals.risch import (gcdex_diophantine, frac_in, derivation, + splitfactor, NonElementaryIntegralException, DecrementLevel) +from functools import reduce + +# TODO: Add messages to NonElementaryIntegralException errors + + +def order_at(a, p, t): + """ + Computes the order of a at p, with respect to t. + + For a, p in k[t], the order of a at p is defined as nu_p(a) = max({n + in Z+ such that p**n|a}), where a != 0. If a == 0, nu_p(a) = +oo. + + To compute the order at a rational function, a/b, use the fact that + nu_p(a/b) == nu_p(a) - nu_p(b). + """ + if a.is_zero: + return oo + if p == Poly(t, t): + return a.as_poly(t).ET()[0][0] + + # TODO: Can this be done more efficiently? + # Perhaps using sqf factorization, binary search with an upper bound of + # a.degree(t)//p.degree(t), or some other clever method. + n = -1 + p1 = Poly(1, t) + r = Poly(0, t) + while r.is_zero: + n += 1 + p1 = p1*p + r = a.rem(p1) + + return n + + +def order_at_oo(a, d, t): + """ + Computes the order of a/d at oo (infinity), with respect to t. + + For f in k(t), the order or f at oo is defined as deg(d) - deg(a), where + f == a/d. + """ + if a.is_zero: + return oo + return d.degree(t) - a.degree(t) + + +def weak_normalizer(a, d, DE, z=None): + """ + Weak normalization. + + Given a derivation D on k[t] and f == a/d in k(t), return q in k[t] + such that f - Dq/q is weakly normalized with respect to t. + + f in k(t) is said to be "weakly normalized" with respect to t if + residue_p(f) is not a positive integer for any normal irreducible p + in k[t] such that f is in R_p (Definition 6.1.1). If f has an + elementary integral, this is equivalent to no logarithm of + integral(f) whose argument depends on t has a positive integer + coefficient, where the arguments of the logarithms not in k(t) are + in k[t]. + + Returns (q, f - Dq/q) + """ + z = z or Dummy('z') + dn, ds = splitfactor(d, DE) + + # Compute d1, where dn == d1*d2**2*...*dn**n is a square-free + # factorization of d. + g = gcd(dn, dn.diff(DE.t)) + d_sqf_part = dn.quo(g) + d1 = d_sqf_part.quo(gcd(d_sqf_part, g)) + + a1, b = gcdex_diophantine(d.quo(d1).as_poly(DE.t), d1.as_poly(DE.t), + a.as_poly(DE.t)) + r = (a - Poly(z, DE.t)*derivation(d1, DE)).as_poly(DE.t).resultant( + d1.as_poly(DE.t)) + r = Poly(r, z) + + if not r.has(z): + return (Poly(1, DE.t), (a, d)) + + N = [i for i in r.real_roots() if i in ZZ and i > 0] + + q = reduce(mul, [gcd(a - Poly(n, DE.t)*derivation(d1, DE), d1) for n in N], + Poly(1, DE.t)) + + dq = derivation(q, DE) + sn = q*a - d*dq + sd = q*d + sn, sd = sn.cancel(sd, include=True) + + return (q, (sn, sd)) + + +def normal_denom(fa, fd, ga, gd, DE): + """ + Normal part of the denominator. + + Given a derivation D on k[t] and f, g in k(t) with f weakly + normalized with respect to t, either raise NonElementaryIntegralException, + in which case the equation Dy + f*y == g has no solution in k(t), or the + quadruplet (a, b, c, h) such that a, h in k[t], b, c in k, and for any + solution y in k(t) of Dy + f*y == g, q = y*h in k satisfies + a*Dq + b*q == c. + + This constitutes step 1 in the outline given in the rde.py docstring. + """ + dn, ds = splitfactor(fd, DE) + en, es = splitfactor(gd, DE) + + p = dn.gcd(en) + h = en.gcd(en.diff(DE.t)).quo(p.gcd(p.diff(DE.t))) + + a = dn*h + c = a*h + if c.div(en)[1]: + # en does not divide dn*h**2 + raise NonElementaryIntegralException + ca = c*ga + ca, cd = ca.cancel(gd, include=True) + + ba = a*fa - dn*derivation(h, DE)*fd + ba, bd = ba.cancel(fd, include=True) + + # (dn*h, dn*h*f - dn*Dh, dn*h**2*g, h) + return (a, (ba, bd), (ca, cd), h) + + +def special_denom(a, ba, bd, ca, cd, DE, case='auto'): + """ + Special part of the denominator. + + case is one of {'exp', 'tan', 'primitive'} for the hyperexponential, + hypertangent, and primitive cases, respectively. For the + hyperexponential (resp. hypertangent) case, given a derivation D on + k[t] and a in k[t], b, c, in k with Dt/t in k (resp. Dt/(t**2 + 1) in + k, sqrt(-1) not in k), a != 0, and gcd(a, t) == 1 (resp. + gcd(a, t**2 + 1) == 1), return the quadruplet (A, B, C, 1/h) such that + A, B, C, h in k[t] and for any solution q in k of a*Dq + b*q == c, + r = qh in k[t] satisfies A*Dr + B*r == C. + + For case == 'primitive', k == k[t], so it returns (a, b, c, 1) in + this case. + + This constitutes step 2 of the outline given in the rde.py docstring. + """ + from sympy.integrals.prde import parametric_log_deriv + # TODO: finish writing this and write tests + + if case == 'auto': + case = DE.case + + if case == 'exp': + p = Poly(DE.t, DE.t) + elif case == 'tan': + p = Poly(DE.t**2 + 1, DE.t) + elif case in ['primitive', 'base']: + B = ba.to_field().quo(bd) + C = ca.to_field().quo(cd) + return (a, B, C, Poly(1, DE.t)) + else: + raise ValueError("case must be one of {'exp', 'tan', 'primitive', " + "'base'}, not %s." % case) + # assert a.div(p)[1] + + nb = order_at(ba, p, DE.t) - order_at(bd, p, DE.t) + nc = order_at(ca, p, DE.t) - order_at(cd, p, DE.t) + + n = min(0, nc - min(0, nb)) + if not nb: + # Possible cancellation. + + if case == 'exp': + dcoeff = DE.d.quo(Poly(DE.t, DE.t)) + with DecrementLevel(DE): # We are guaranteed to not have problems, + # because case != 'base'. + alphaa, alphad = frac_in(-ba.eval(0)/bd.eval(0)/a.eval(0), DE.t) + etaa, etad = frac_in(dcoeff, DE.t) + A = parametric_log_deriv(alphaa, alphad, etaa, etad, DE) + if A is not None: + a, m, z = A + if a == 1: + n = min(n, m) + + elif case == 'tan': + dcoeff = DE.d.quo(Poly(DE.t**2+1, DE.t)) + with DecrementLevel(DE): # We are guaranteed to not have problems, + # because case != 'base'. + alphaa, alphad = frac_in(im(-ba.eval(sqrt(-1))/bd.eval(sqrt(-1))/a.eval(sqrt(-1))), DE.t) + betaa, betad = frac_in(re(-ba.eval(sqrt(-1))/bd.eval(sqrt(-1))/a.eval(sqrt(-1))), DE.t) + etaa, etad = frac_in(dcoeff, DE.t) + + if recognize_log_derivative(2*betaa, betad, DE): + A = parametric_log_deriv(alphaa*sqrt(-1)*betad+alphad*betaa, alphad*betad, etaa, etad, DE) + if A is not None: + a, m, z = A + if a == 1: + n = min(n, m) + N = max(0, -nb, n - nc) + pN = p**N + pn = p**-n + + A = a*pN + B = ba*pN.quo(bd) + Poly(n, DE.t)*a*derivation(p, DE).quo(p)*pN + C = (ca*pN*pn).quo(cd) + h = pn + + # (a*p**N, (b + n*a*Dp/p)*p**N, c*p**(N - n), p**-n) + return (A, B, C, h) + + +def bound_degree(a, b, cQ, DE, case='auto', parametric=False): + """ + Bound on polynomial solutions. + + Given a derivation D on k[t] and a, b, c in k[t] with a != 0, return + n in ZZ such that deg(q) <= n for any solution q in k[t] of + a*Dq + b*q == c, when parametric=False, or deg(q) <= n for any solution + c1, ..., cm in Const(k) and q in k[t] of a*Dq + b*q == Sum(ci*gi, (i, 1, m)) + when parametric=True. + + For parametric=False, cQ is c, a Poly; for parametric=True, cQ is Q == + [q1, ..., qm], a list of Polys. + + This constitutes step 3 of the outline given in the rde.py docstring. + """ + from sympy.integrals.prde import (parametric_log_deriv, limited_integrate, + is_log_deriv_k_t_radical_in_field) + # TODO: finish writing this and write tests + + if case == 'auto': + case = DE.case + + da = a.degree(DE.t) + db = b.degree(DE.t) + + # The parametric and regular cases are identical, except for this part + if parametric: + dc = max([i.degree(DE.t) for i in cQ]) + else: + dc = cQ.degree(DE.t) + + alpha = cancel(-b.as_poly(DE.t).LC().as_expr()/ + a.as_poly(DE.t).LC().as_expr()) + + if case == 'base': + n = max(0, dc - max(db, da - 1)) + if db == da - 1 and alpha.is_Integer: + n = max(0, alpha, dc - db) + + elif case == 'primitive': + if db > da: + n = max(0, dc - db) + else: + n = max(0, dc - da + 1) + + etaa, etad = frac_in(DE.d, DE.T[DE.level - 1]) + + t1 = DE.t + with DecrementLevel(DE): + alphaa, alphad = frac_in(alpha, DE.t) + if db == da - 1: + # if alpha == m*Dt + Dz for z in k and m in ZZ: + try: + (za, zd), m = limited_integrate(alphaa, alphad, [(etaa, etad)], + DE) + except NonElementaryIntegralException: + pass + else: + assert len(m) == 1 + n = max(n, m[0]) + + elif db == da: + # if alpha == Dz/z for z in k*: + # beta = -lc(a*Dz + b*z)/(z*lc(a)) + # if beta == m*Dt + Dw for w in k and m in ZZ: + # n = max(n, m) + A = is_log_deriv_k_t_radical_in_field(alphaa, alphad, DE) + if A is not None: + aa, z = A + if aa == 1: + beta = -(a*derivation(z, DE).as_poly(t1) + + b*z.as_poly(t1)).LC()/(z.as_expr()*a.LC()) + betaa, betad = frac_in(beta, DE.t) + try: + (za, zd), m = limited_integrate(betaa, betad, + [(etaa, etad)], DE) + except NonElementaryIntegralException: + pass + else: + assert len(m) == 1 + n = max(n, m[0]) + + elif case == 'exp': + n = max(0, dc - max(db, da)) + if da == db: + etaa, etad = frac_in(DE.d.quo(Poly(DE.t, DE.t)), DE.T[DE.level - 1]) + with DecrementLevel(DE): + alphaa, alphad = frac_in(alpha, DE.t) + A = parametric_log_deriv(alphaa, alphad, etaa, etad, DE) + if A is not None: + # if alpha == m*Dt/t + Dz/z for z in k* and m in ZZ: + # n = max(n, m) + a, m, z = A + if a == 1: + n = max(n, m) + + elif case in ['tan', 'other_nonlinear']: + delta = DE.d.degree(DE.t) + lam = DE.d.LC() + alpha = cancel(alpha/lam) + n = max(0, dc - max(da + delta - 1, db)) + if db == da + delta - 1 and alpha.is_Integer: + n = max(0, alpha, dc - db) + + else: + raise ValueError("case must be one of {'exp', 'tan', 'primitive', " + "'other_nonlinear', 'base'}, not %s." % case) + + return n + + +def spde(a, b, c, n, DE): + """ + Rothstein's Special Polynomial Differential Equation algorithm. + + Given a derivation D on k[t], an integer n and a, b, c in k[t] with + a != 0, either raise NonElementaryIntegralException, in which case the + equation a*Dq + b*q == c has no solution of degree at most n in + k[t], or return the tuple (B, C, m, alpha, beta) such that B, C, + alpha, beta in k[t], m in ZZ, and any solution q in k[t] of degree + at most n of a*Dq + b*q == c must be of the form + q == alpha*h + beta, where h in k[t], deg(h) <= m, and Dh + B*h == C. + + This constitutes step 4 of the outline given in the rde.py docstring. + """ + zero = Poly(0, DE.t) + + alpha = Poly(1, DE.t) + beta = Poly(0, DE.t) + pow_a = 0 + + while True: + if n < 0: + if c.is_zero: + return (zero, zero, 0, zero, beta) + raise NonElementaryIntegralException + + g = a.gcd(b) + if not c.rem(g).is_zero: # g does not divide c + raise NonElementaryIntegralException + + a, b, c = a.quo(g), b.quo(g), c.quo(g) + + if a.degree(DE.t) == 0: + b = b.to_field().quo(a) + c = c.to_field().quo(a) + return (b, c, n, alpha, beta) + + r, z = gcdex_diophantine(b, a, c) + b += derivation(a, DE) + c = z - derivation(r, DE) + n -= a.degree(DE.t) + alpha *= a + beta += (a**pow_a)*r + pow_a += 1 + +def no_cancel_b_large(b, c, n, DE): + """ + Poly Risch Differential Equation - No cancellation: deg(b) large enough. + + Given a derivation D on k[t], n either an integer or +oo, and b, c + in k[t] with b != 0 and either D == d/dt or + deg(b) > max(0, deg(D) - 1), either raise NonElementaryIntegralException, in + which case the equation Dq + b*q == c has no solution of degree at + most n in k[t], or a solution q in k[t] of this equation with + deg(q) < n. + """ + q = Poly(0, DE.t) + + while not c.is_zero: + m = c.degree(DE.t) - b.degree(DE.t) + if not 0 <= m <= n: # n < 0 or m < 0 or m > n + raise NonElementaryIntegralException + + p = Poly(c.as_poly(DE.t).LC()/b.as_poly(DE.t).LC()*DE.t**m, DE.t, + expand=False) + q = q + p + n = m - 1 + c = c - derivation(p, DE) - b*p + + return q + + +def no_cancel_b_small(b, c, n, DE): + """ + Poly Risch Differential Equation - No cancellation: deg(b) small enough. + + Given a derivation D on k[t], n either an integer or +oo, and b, c + in k[t] with deg(b) < deg(D) - 1 and either D == d/dt or + deg(D) >= 2, either raise NonElementaryIntegralException, in which case the + equation Dq + b*q == c has no solution of degree at most n in k[t], + or a solution q in k[t] of this equation with deg(q) <= n, or the + tuple (h, b0, c0) such that h in k[t], b0, c0, in k, and for any + solution q in k[t] of degree at most n of Dq + bq == c, y == q - h + is a solution in k of Dy + b0*y == c0. + """ + q = Poly(0, DE.t) + + while not c.is_zero: + if n == 0: + m = 0 + else: + m = c.degree(DE.t) - DE.d.degree(DE.t) + 1 + + if not 0 <= m <= n: # n < 0 or m < 0 or m > n + raise NonElementaryIntegralException + + if m > 0: + p = Poly(c.as_poly(DE.t).LC()/(m*DE.d.as_poly(DE.t).LC())*DE.t**m, + DE.t, expand=False) + else: + if b.degree(DE.t) != c.degree(DE.t): + raise NonElementaryIntegralException + if b.degree(DE.t) == 0: + return (q, b.as_poly(DE.T[DE.level - 1]), + c.as_poly(DE.T[DE.level - 1])) + p = Poly(c.as_poly(DE.t).LC()/b.as_poly(DE.t).LC(), DE.t, + expand=False) + + q = q + p + n = m - 1 + c = c - derivation(p, DE) - b*p + + return q + + +# TODO: better name for this function +def no_cancel_equal(b, c, n, DE): + """ + Poly Risch Differential Equation - No cancellation: deg(b) == deg(D) - 1 + + Given a derivation D on k[t] with deg(D) >= 2, n either an integer + or +oo, and b, c in k[t] with deg(b) == deg(D) - 1, either raise + NonElementaryIntegralException, in which case the equation Dq + b*q == c has + no solution of degree at most n in k[t], or a solution q in k[t] of + this equation with deg(q) <= n, or the tuple (h, m, C) such that h + in k[t], m in ZZ, and C in k[t], and for any solution q in k[t] of + degree at most n of Dq + b*q == c, y == q - h is a solution in k[t] + of degree at most m of Dy + b*y == C. + """ + q = Poly(0, DE.t) + lc = cancel(-b.as_poly(DE.t).LC()/DE.d.as_poly(DE.t).LC()) + if lc.is_Integer and lc.is_positive: + M = lc + else: + M = -1 + + while not c.is_zero: + m = max(M, c.degree(DE.t) - DE.d.degree(DE.t) + 1) + + if not 0 <= m <= n: # n < 0 or m < 0 or m > n + raise NonElementaryIntegralException + + u = cancel(m*DE.d.as_poly(DE.t).LC() + b.as_poly(DE.t).LC()) + if u.is_zero: + return (q, m, c) + if m > 0: + p = Poly(c.as_poly(DE.t).LC()/u*DE.t**m, DE.t, expand=False) + else: + if c.degree(DE.t) != DE.d.degree(DE.t) - 1: + raise NonElementaryIntegralException + else: + p = c.as_poly(DE.t).LC()/b.as_poly(DE.t).LC() + + q = q + p + n = m - 1 + c = c - derivation(p, DE) - b*p + + return q + + +def cancel_primitive(b, c, n, DE): + """ + Poly Risch Differential Equation - Cancellation: Primitive case. + + Given a derivation D on k[t], n either an integer or +oo, b in k, and + c in k[t] with Dt in k and b != 0, either raise + NonElementaryIntegralException, in which case the equation Dq + b*q == c + has no solution of degree at most n in k[t], or a solution q in k[t] of + this equation with deg(q) <= n. + """ + from sympy.integrals.prde import is_log_deriv_k_t_radical_in_field + + with DecrementLevel(DE): + ba, bd = frac_in(b, DE.t) + A = is_log_deriv_k_t_radical_in_field(ba, bd, DE) + if A is not None: + n, z = A + if n == 1: # b == Dz/z + raise NotImplementedError("is_deriv_in_field() is required to " + " solve this problem.") + # if z*c == Dp for p in k[t] and deg(p) <= n: + # return p/z + # else: + # raise NonElementaryIntegralException + + if c.is_zero: + return c # return 0 + + if n < c.degree(DE.t): + raise NonElementaryIntegralException + + q = Poly(0, DE.t) + while not c.is_zero: + m = c.degree(DE.t) + if n < m: + raise NonElementaryIntegralException + with DecrementLevel(DE): + a2a, a2d = frac_in(c.LC(), DE.t) + sa, sd = rischDE(ba, bd, a2a, a2d, DE) + stm = Poly(sa.as_expr()/sd.as_expr()*DE.t**m, DE.t, expand=False) + q += stm + n = m - 1 + c -= b*stm + derivation(stm, DE) + + return q + + +def cancel_exp(b, c, n, DE): + """ + Poly Risch Differential Equation - Cancellation: Hyperexponential case. + + Given a derivation D on k[t], n either an integer or +oo, b in k, and + c in k[t] with Dt/t in k and b != 0, either raise + NonElementaryIntegralException, in which case the equation Dq + b*q == c + has no solution of degree at most n in k[t], or a solution q in k[t] of + this equation with deg(q) <= n. + """ + from sympy.integrals.prde import parametric_log_deriv + + eta = DE.d.quo(Poly(DE.t, DE.t)).as_expr() + + with DecrementLevel(DE): + etaa, etad = frac_in(eta, DE.t) + ba, bd = frac_in(b, DE.t) + A = parametric_log_deriv(ba, bd, etaa, etad, DE) + if A is not None: + a, m, z = A + if a == 1: + raise NotImplementedError("is_deriv_in_field() is required to " + "solve this problem.") + # if c*z*t**m == Dp for p in k and q = p/(z*t**m) in k[t] and + # deg(q) <= n: + # return q + # else: + # raise NonElementaryIntegralException + + if c.is_zero: + return c # return 0 + + if n < c.degree(DE.t): + raise NonElementaryIntegralException + + q = Poly(0, DE.t) + while not c.is_zero: + m = c.degree(DE.t) + if n < m: + raise NonElementaryIntegralException + # a1 = b + m*Dt/t + a1 = b.as_expr() + with DecrementLevel(DE): + # TODO: Write a dummy function that does this idiom + a1a, a1d = frac_in(a1, DE.t) + a1a = a1a*etad + etaa*a1d*Poly(m, DE.t) + a1d = a1d*etad + + a2a, a2d = frac_in(c.LC(), DE.t) + + sa, sd = rischDE(a1a, a1d, a2a, a2d, DE) + stm = Poly(sa.as_expr()/sd.as_expr()*DE.t**m, DE.t, expand=False) + q += stm + n = m - 1 + c -= b*stm + derivation(stm, DE) # deg(c) becomes smaller + return q + + +def solve_poly_rde(b, cQ, n, DE, parametric=False): + """ + Solve a Polynomial Risch Differential Equation with degree bound n. + + This constitutes step 4 of the outline given in the rde.py docstring. + + For parametric=False, cQ is c, a Poly; for parametric=True, cQ is Q == + [q1, ..., qm], a list of Polys. + """ + from sympy.integrals.prde import (prde_no_cancel_b_large, + prde_no_cancel_b_small) + + # No cancellation + if not b.is_zero and (DE.case == 'base' or + b.degree(DE.t) > max(0, DE.d.degree(DE.t) - 1)): + + if parametric: + return prde_no_cancel_b_large(b, cQ, n, DE) + return no_cancel_b_large(b, cQ, n, DE) + + elif (b.is_zero or b.degree(DE.t) < DE.d.degree(DE.t) - 1) and \ + (DE.case == 'base' or DE.d.degree(DE.t) >= 2): + + if parametric: + return prde_no_cancel_b_small(b, cQ, n, DE) + + R = no_cancel_b_small(b, cQ, n, DE) + + if isinstance(R, Poly): + return R + else: + # XXX: Might k be a field? (pg. 209) + h, b0, c0 = R + with DecrementLevel(DE): + b0, c0 = b0.as_poly(DE.t), c0.as_poly(DE.t) + assert b0 is not None # See above comment + assert c0 is not None + y = solve_poly_rde(b0, c0, n, DE).as_poly(DE.t) + return h + y + + elif DE.d.degree(DE.t) >= 2 and b.degree(DE.t) == DE.d.degree(DE.t) - 1 and \ + n > -b.as_poly(DE.t).LC()/DE.d.as_poly(DE.t).LC(): + + # TODO: Is this check necessary, and if so, what should it do if it fails? + # b comes from the first element returned from spde() + assert b.as_poly(DE.t).LC().is_number + + if parametric: + raise NotImplementedError("prde_no_cancel_b_equal() is not yet " + "implemented.") + + R = no_cancel_equal(b, cQ, n, DE) + + if isinstance(R, Poly): + return R + else: + h, m, C = R + # XXX: Or should it be rischDE()? + y = solve_poly_rde(b, C, m, DE) + return h + y + + else: + # Cancellation + if b.is_zero: + raise NotImplementedError("Remaining cases for Poly (P)RDE are " + "not yet implemented (is_deriv_in_field() required).") + else: + if DE.case == 'exp': + if parametric: + raise NotImplementedError("Parametric RDE cancellation " + "hyperexponential case is not yet implemented.") + return cancel_exp(b, cQ, n, DE) + + elif DE.case == 'primitive': + if parametric: + raise NotImplementedError("Parametric RDE cancellation " + "primitive case is not yet implemented.") + return cancel_primitive(b, cQ, n, DE) + + else: + raise NotImplementedError("Other Poly (P)RDE cancellation " + "cases are not yet implemented (%s)." % case) + + if parametric: + raise NotImplementedError("Remaining cases for Poly PRDE not yet " + "implemented.") + raise NotImplementedError("Remaining cases for Poly RDE not yet " + "implemented.") + + +def rischDE(fa, fd, ga, gd, DE): + """ + Solve a Risch Differential Equation: Dy + f*y == g. + + See the outline in the docstring of rde.py for more information + about the procedure used. Either raise NonElementaryIntegralException, in + which case there is no solution y in the given differential field, + or return y in k(t) satisfying Dy + f*y == g, or raise + NotImplementedError, in which case, the algorithms necessary to + solve the given Risch Differential Equation have not yet been + implemented. + """ + _, (fa, fd) = weak_normalizer(fa, fd, DE) + a, (ba, bd), (ca, cd), hn = normal_denom(fa, fd, ga, gd, DE) + A, B, C, hs = special_denom(a, ba, bd, ca, cd, DE) + try: + # Until this is fully implemented, use oo. Note that this will almost + # certainly cause non-termination in spde() (unless A == 1), and + # *might* lead to non-termination in the next step for a nonelementary + # integral (I don't know for certain yet). Fortunately, spde() is + # currently written recursively, so this will just give + # RuntimeError: maximum recursion depth exceeded. + n = bound_degree(A, B, C, DE) + except NotImplementedError: + # Useful for debugging: + # import warnings + # warnings.warn("rischDE: Proceeding with n = oo; may cause " + # "non-termination.") + n = oo + + B, C, m, alpha, beta = spde(A, B, C, n, DE) + y = solve_poly_rde(B, C, m, DE) + + return (alpha*y + beta, hn*hs) diff -Nru python3-sympy-0.7.2/sympy/integrals/risch.py python3-sympy-0.7.3/sympy/integrals/risch.py --- python3-sympy-0.7.2/sympy/integrals/risch.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/integrals/risch.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,465 +1,1696 @@ -from collections import defaultdict +""" +The Risch Algorithm for transcendental function integration. -from sympy.core.add import Add +The core algorithms for the Risch algorithm are here. The subproblem +algorithms are in the rde.py and prde.py files for the Risch +Differential Equation solver and the parametric problems solvers, +respectively. All important information concerning the differential extension +for an integrand is stored in a DifferentialExtension object, which in the code +is usually called DE. Throughout the code and Inside the DifferentialExtension +object, the conventions/attribute names are that the base domain is QQ and each +differential extension is x, t0, t1, ..., tn-1 = DE.t. DE.x is the variable of +integration (Dx == 1), DE.D is a list of the derivatives of +x, t1, t2, ..., tn-1 = t, DE.T is the list [x, t1, t2, ..., tn-1], DE.t is the +outer-most variable of the differential extension at the given level (the level +can be adjusted using DE.increment_level() and DE.decrement_level()), +k is the field C(x, t0, ..., tn-2), where C is the constant field. The +numerator of a fraction is denoted by a and the denominator by +d. If the fraction is named f, fa == numer(f) and fd == denom(f). +Fractions are returned as tuples (fa, fd). DE.d and DE.t are used to +represent the topmost derivation and extension variable, respectively. +The docstring of a function signifies whether an argument is in k[t], in +which case it will just return a Poly in t, or in k(t), in which case it +will return the fraction (fa, fd). Other variable names probably come +from the names used in Bronstein's book. +""" + +from sympy import real_roots +from sympy.abc import z +from sympy.core.function import Lambda +from sympy.core.numbers import ilcm from sympy.core.mul import Mul -from sympy.core.symbol import Symbol, Wild, Dummy -from sympy.core.basic import C, sympify -from sympy.core.numbers import Rational, I, pi +from sympy.core.power import Pow +from sympy.core.relational import Eq, Ne from sympy.core.singleton import S -from sympy.core.compatibility import permutations +from sympy.core.symbol import Symbol, Dummy +from sympy.core.compatibility import reduce, ordered +from sympy.integrals.heurisch import _symbols -from sympy.functions import exp, sin, cos, tan, cot, asin, atan -from sympy.functions import log, sinh, cosh, tanh, coth, asinh, acosh -from sympy.functions import sqrt, erf +from sympy.functions import (acos, acot, asin, atan, cos, cot, exp, log, + Piecewise, sin, tan) -from sympy.solvers import solve +from sympy.functions import sinh, cosh, tanh, coth, asinh, acosh , atanh , acoth +from sympy.integrals import Integral, integrate -from sympy.polys import quo, gcd, lcm, \ - monomials, factor, cancel, PolynomialError -from sympy.polys.polyroots import root_factors +from sympy.polys import gcd, cancel, PolynomialError, Poly, reduced, RootSum, DomainError -from sympy.core.compatibility import reduce -from sympy.utilities.misc import default_sort_key +from sympy.utilities.iterables import numbered_symbols from functools import reduce -def components(f, x): - """Returns a set of all functional components of the given expression - which includes symbols, function applications and compositions and - non-integer powers. Fractional powers are collected with with - minimal, positive exponents. - - >>> from sympy import cos, sin - >>> from sympy.abc import x, y - >>> from sympy.integrals.risch import components +def integer_powers(exprs): + """ + Rewrites a list of expressions as integer multiples of each other. - >>> components(sin(x)*cos(x)**2, x) - set([x, sin(x), cos(x)]) + For example, if you have [x, x/2, x**2 + 1, 2*x/3], then you can rewrite + this as [(x/6) * 6, (x/6) * 3, (x**2 + 1) * 1, (x/6) * 4]. This is useful + in the Risch integration algorithm, where we must write exp(x) + exp(x/2) + as (exp(x/2))**2 + exp(x/2), but not as exp(x) + sqrt(exp(x)) (this is + because only the transcendental case is implemented and we therefore cannot + integrate algebraic extensions). The integer multiples returned by this + function for each term are the smallest possible (their content equals 1). + + Returns a list of tuples where the first element is the base term and the + second element is a list of `(item, factor)` terms, where `factor` is the + integer multiplicative factor that must multiply the base term to obtain + the original item. + + The easiest way to understand this is to look at an example: + + >>> from sympy.abc import x + >>> from sympy.integrals.risch import integer_powers + >>> integer_powers([x, x/2, x**2 + 1, 2*x/3]) + [(x/6, [(x, 6), (x/2, 3), (2*x/3, 4)]), (x**2 + 1, [(x**2 + 1, 1)])] + + We can see how this relates to the example at the beginning of the + docstring. It chose x/6 as the first base term. Then, x can be written as + (x/2) * 2, so we get (0, 2), and so on. Now only element (x**2 + 1) + remains, and there are no other terms that can be written as a rational + multiple of that, so we get that it can be written as (x**2 + 1) * 1. + + """ + # Here is the strategy: + + # First, go through each term and determine if it can be rewritten as a + # rational multiple of any of the terms gathered so far. + # cancel(a/b).is_Rational is sufficient for this. If it is a multiple, we + # add its multiple to the dictionary. + + terms = {} + for term in exprs: + for j in terms: + a = cancel(term/j) + if a.is_Rational: + terms[j].append((term, a)) + break + else: + terms[term] = [(term, S(1))] + + # After we have done this, we have all the like terms together, so we just + # need to find a common denominator so that we can get the base term and + # integer multiples such that each term can be written as an integer + # multiple of the base term, and the content of the integers is 1. + + newterms = {} + for term in terms: + common_denom = reduce(ilcm, [i.as_numer_denom()[1] for _, i in + terms[term]]) + newterm = term/common_denom + newmults = [(i, j*common_denom) for i, j in terms[term]] + newterms[newterm] = newmults + + return sorted(iter(newterms.items()), key=lambda item: item[0].sort_key()) - See Also - ======== - heurisch +class DifferentialExtension(object): """ - result = set() + A container for all the information relating to a differential extension. - if f.has(x): - if f.is_Symbol: - result.add(f) - elif f.is_Function or f.is_Derivative: - for g in f.args: - result |= components(g, x) - - result.add(f) - elif f.is_Pow: - result |= components(f.base, x) - - if not f.exp.is_Integer: - if f.exp.is_Rational: - result.add(f.base**Rational(1, f.exp.q)) - else: - result |= components(f.exp, x) | set([f]) + The attributes of this object are (see also the docstring of __init__): + + - f: The original (Expr) integrand. + - x: The variable of integration. + - T: List of variables in the extension. + - D: List of derivations in the extension; corresponds to the elements of T. + - fa: Poly of the numerator of the integrand. + - fd: Poly of the denominator of the integrand. + - Tfuncs: Lambda() representations of each element of T (except for x). + For back-substitution after integration. + - backsubs: A (possibly empty) list of further substitutions to be made on + the final integral to make it look more like the integrand. + - E_K: List of the positions of the exponential extensions in T. + - E_args: The arguments of each of the exponentials in E_K. + - L_K: List of the positions of the logarithmic extensions in T. + - L_args: The arguments of each of the logarithms in L_K. + (See the docstrings of is_deriv_k() and is_log_deriv_k_t_radical() for + more information on E_K, E_args, L_K, and L_args) + - cases: List of string representations of the cases of T. + - t: The top level extension variable, as defined by the current level + (see level below). + - d: The top level extension derivation, as defined by the current + derivation (see level below). + - case: The string representation of the case of self.d. + (Note that self.T and self.D will always contain the complete extension, + regardless of the level. Therefore, you should ALWAYS use DE.t and DE.d + instead of DE.T[-1] and DE.D[-1]. If you want to have a list of the + derivations or variables only up to the current level, use + DE.D[:len(DE.D) + DE.level + 1] and DE.T[:len(DE.T) + DE.level + 1]. Note + that, in particular, the derivation() function does this.) + + The following are also attributes, but will probably not be useful other + than in internal use: + - newf: Expr form of fa/fd. + - level: The number (between -1 and -len(self.T)) such that + self.T[self.level] == self.t and self.D[self.level] == self.d. + Use the methods self.increment_level() and self.decrement_level() to change + the current level. + """ + # __slots__ is defined mainly so we can iterate over all the attributes + # of the class easily (the memory use doesn't matter too much, since we + # only create one DifferentialExtension per integration). Also, it's nice + # to have a safeguard when debugging. + __slots__ = ('f', 'x', 'T', 'D', 'fa', 'fd', 'Tfuncs', 'backsubs', 'E_K', + 'E_args', 'L_K', 'L_args', 'cases', 'case', 't', 'd', 'newf', 'level', + 'ts') + + def __init__(self, f=None, x=None, handle_first='log', dummy=True, extension=None, rewrite_complex=False): + """ + Tries to build a transcendental extension tower from f with respect to x. + + If it is successful, creates a DifferentialExtension object with, among + others, the attributes fa, fd, D, T, Tfuncs, and backsubs such that + fa and fd are Polys in T[-1] with rational coefficients in T[:-1], + fa/fd == f, and D[i] is a Poly in T[i] with rational coefficients in + T[:i] representing the derivative of T[i] for each i from 1 to len(T). + Tfuncs is a list of Lambda objects for back replacing the functions + after integrating. Lambda() is only used (instead of lambda) to make + them easier to test and debug. Note that Tfuncs corresponds to the + elements of T, except for T[0] == x, but they should be back-substituted + in reverse order. backsubs is a (possibly empty) back-substitution list + that should be applied on the completed integral to make it look more + like the original integrand. + + If it is unsuccessful, it raises NotImplementedError. + + You can also create an object by manually setting the attributes as a + dictionary to the extension keyword argument. You must include at least + D. Warning, any attribute that is not given will be set to None. The + attributes T, t, d, cases, case, x, and level are set automatically and + do not need to be given. The functions in the Risch Algorithm will NOT + check to see if an attribute is None before using it. This also does not + check to see if the extension is valid (non-algebraic) or even if it is + self-consistent. Therefore, this should only be used for + testing/debugging purposes. + """ + # XXX: If you need to debug this function, set the break point here + + if extension: + if 'D' not in extension: + raise ValueError("At least the key D must be included with " + "the extension flag to DifferentialExtension.") + for attr in extension: + setattr(self, attr, extension[attr]) + + self._auto_attrs() + + return + elif f is None or x is None: + raise ValueError("Either both f and x or a manual extension must " + "be given.") + + from sympy.integrals.prde import is_deriv_k + + if handle_first not in ['log', 'exp']: + raise ValueError("handle_first must be 'log' or 'exp', not %s." % + str(handle_first)) + + # f will be the original function, self.f might change if we reset + # (e.g., we pull out a constant from an exponential) + self.f = f + self.x = x + self.reset(dummy=dummy) + exp_new_extension, log_new_extension = True, True + if rewrite_complex: + rewritables = { + (sin, cos, cot, tan, sinh, cosh, coth, tanh): exp, + (asin, acos, acot, atan): log, + } + #rewrite the trigonometric components + for candidates, rule in rewritables.items(): + self.newf = self.newf.rewrite(candidates, rule) else: - for g in f.args: - result |= components(g, x) + if any(i.has(x) for i in self.f.atoms(sin, cos, tan, atan, asin, acos)): + raise NotImplementedError("Trigonometric extensions are not " + "supported (yet!)") + + def update(seq, atoms, func): + s = set(seq) + new = atoms - s + s = atoms.intersection(s) + s.update(list(filter(func, new))) + return list(s) + + exps = set() + pows = set() + numpows = set() + sympows = set() + logs = set() + symlogs = set() + + while True: + restart = False + if self.newf.is_rational_function(*self.T): + break - return result + if not exp_new_extension and not log_new_extension: + # We couldn't find a new extension on the last pass, so I guess + # we can't do it. + raise NotImplementedError("Couldn't find an elementary " + "transcendental extension for %s. Try using a " % str(f) + + "manual extension with the extension flag.") + + # Pre-preparsing. + ################# + # Get all exp arguments, so we can avoid ahead of time doing + # something like t1 = exp(x), t2 = exp(x/2) == sqrt(t1). + + # Things like sqrt(exp(x)) do not automatically simplify to + # exp(x/2), so they will be viewed as algebraic. The easiest way + # to handle this is to convert all instances of (a**b)**Rational + # to a**(Rational*b) before doing anything else. Note that the + # _exp_part code can generate terms of this form, so we do need to + # do this at each pass (or else modify it to not do that). + + ratpows = [i for i in self.newf.atoms(Pow).union( + self.newf.atoms(exp)) if (i.base.is_Pow or i.base.func is exp) + and i.exp.is_Rational] + + ratpows_repl = [ + (i, i.base.base**(i.exp*i.base.exp)) for i in ratpows] + self.backsubs += [(j, i) for i, j in ratpows_repl] + self.newf = self.newf.xreplace(dict(ratpows_repl)) + + # To make the process deterministic, the args are sorted + # so that functions with smaller op-counts are processed first. + # Ties are broken with the default_sort_key. + + # XXX Although the method is deterministic no additional work + # has been done to guarantee that the simplest solution is + # returned and that it would be affected be using different + # variables. Though it is possible that this is the case + # one should know that it has not been done intentionally so + # further improvements may possible. + + # TODO: This probably doesn't need to be completely recomputed at + # each pass. + exps = update(exps, self.newf.atoms(exp), + lambda i: i.exp.is_rational_function(*self.T) and + i.exp.has(*self.T)) + pows = update(pows, self.newf.atoms(Pow), + lambda i: i.exp.is_rational_function(*self.T) and + i.exp.has(*self.T)) + numpows = update(numpows, set(pows), + lambda i: not i.base.has(*self.T)) + sympows = update(sympows, set(pows) - set(numpows), + lambda i: i.base.is_rational_function(*self.T) and + not i.exp.is_Integer) + + # The easiest way to deal with non-base E powers is to convert them + # into base E, integrate, and then convert back. + for i in ordered(pows): + old = i + new = exp(i.exp*log(i.base)) + # If exp is ever changed to automatically reduce exp(x*log(2)) + # to 2**x, then this will break. The solution is to not change + # exp to do that :) + if i in sympows: + if i.exp.is_Rational: + raise NotImplementedError("Algebraic extensions are " + "not supported (%s)." % str(i)) + # We can add a**b only if log(a) in the extension, because + # a**b == exp(b*log(a)). + basea, based = frac_in(i.base, self.t) + A = is_deriv_k(basea, based, self) + if A is None: + # Nonelementary monomial (so far) + + # TODO: Would there ever be any benefit from just + # adding log(base) as a new monomial? + # ANSWER: Yes, otherwise we can't integrate x**x (or + # rather prove that it has no elementary integral) + # without first manually rewriting it as exp(x*log(x)) + continue + ans, u, const = A + newterm = exp(i.exp*(log(const) + u)) + # Under the current implementation, exp kills terms + # only if they are of the form a*log(x), where a is a + # Number. This case should have already been killed by the + # above tests. Again, if this changes to kill more than + # that, this will break, which maybe is a sign that you + # shouldn't be changing that. Actually, if anything, this + # auto-simplification should be removed. See + # http://groups.google.com/group/sympy/browse_thread/thread/a61d48235f16867f -# name -> [] of symbols -_symbols_cache = {} + self.newf = self.newf.xreplace({i: newterm}) -# NB @cacheit is not convenient here -def _symbols(name, n): - """get vector of symbols local to this module""" - try: - lsyms = _symbols_cache[name] - except KeyError: - lsyms = [] - _symbols_cache[name] = lsyms + elif i not in numpows: + continue + else: + # i in numpows + newterm = new + # TODO: Just put it in self.Tfuncs + self.backsubs.append((new, old)) + self.newf = self.newf.xreplace({old: newterm}) + exps.append(newterm) + + atoms = self.newf.atoms(log) + logs = update(logs, atoms, + lambda i: i.args[0].is_rational_function(*self.T) and + i.args[0].has(*self.T)) + symlogs = update(symlogs, atoms, + lambda i: i.has(*self.T) and i.args[0].is_Pow and + i.args[0].base.is_rational_function(*self.T) and + not i.args[0].exp.is_Integer) + + # We can handle things like log(x**y) by converting it to y*log(x) + # This will fix not only symbolic exponents of the argument, but any + # non-Integer exponent, like log(sqrt(x)). The exponent can also + # depend on x, like log(x**x). + for i in ordered(symlogs): + # Unlike in the exponential case above, we do not ever + # potentially add new monomials (above we had to add log(a)). + # Therefore, there is no need to run any is_deriv functions + # here. Just convert log(a**b) to b*log(a) and let + # log_new_extension() handle it from there. + lbase = log(i.args[0].base) + logs.append(lbase) + new = i.args[0].exp*lbase + self.newf = self.newf.xreplace({i: new}) + self.backsubs.append((new, i)) + + # remove any duplicates + logs = list(set(logs)) + + if handle_first == 'exp' or not log_new_extension: + exp_new_extension = self._exp_part(exps, dummy=dummy) + if exp_new_extension is None: + # reset and restart + self.f = self.newf + self.reset(dummy=dummy) + exp_new_extension = True + continue + + if handle_first == 'log' or not exp_new_extension: + log_new_extension = self._log_part(logs, dummy=dummy) + + self.fa, self.fd = frac_in(self.newf, self.t) + self._auto_attrs() + + return + + def __getattr__(self, attr): + # Avoid AttributeErrors when debugging + if attr not in self.__slots__: + raise AttributeError("%s has no attribute %s" % (repr(self), repr(attr))) + return None + + def _auto_attrs(self): + """ + Set attributes that are generated automatically. + """ + if not self.T: + # i.e., when using the extension flag and T isn't given + self.T = [i.gen for i in self.D] + if not self.x: + self.x = self.T[0] + self.cases = [get_case(d, t) for d, t in zip(self.D, self.T)] + self.level = -1 + self.t = self.T[self.level] + self.d = self.D[self.level] + self.case = self.cases[self.level] + + def _exp_part(self, exps, dummy=True): + """ + Try to build an exponential extension. + + Returns True if there was a new extension, False if there was no new + extension but it was able to rewrite the given exponentials in terms + of the existing extension, and None if the entire extension building + process should be restarted. If the process fails because there is no + way around an algebraic extension (e.g., exp(log(x)/2)), it will raise + NotImplementedError. + """ + from sympy.integrals.prde import is_log_deriv_k_t_radical + + new_extension = False + restart = False + expargs = [i.exp for i in exps] + ip = integer_powers(expargs) + for arg, others in ip: + # Minimize potential problems with algebraic substitution + others.sort(key=lambda i: i[1]) + + arga, argd = frac_in(arg, self.t) + A = is_log_deriv_k_t_radical(arga, argd, self) + + if A is not None: + ans, u, n, const = A + # if n is 1 or -1, it's algebraic, but we can handle it + if n == -1: + # This probably will never happen, because + # Rational.as_numer_denom() returns the negative term in + # the numerator. But in case that changes, reduce it to + # n == 1. + n = 1 + u **= -1 + const *= -1 + ans = [(i, -j) for i, j in ans] + + if n == 1: + # Example: exp(x + x**2) over QQ(x, exp(x), exp(x**2)) + self.newf = self.newf.xreplace({exp(arg): exp(const)*Mul(*[ + u**power for u, power in ans])}) + self.newf = self.newf.xreplace(dict([(exp(p*exparg), + exp(const*p) * Mul(*[u**power for u, power in ans])) + for exparg, p in others])) + # TODO: Add something to backsubs to put exp(const*p) + # back together. + + continue + + else: + # Bad news: we have an algebraic radical. But maybe we + # could still avoid it by choosing a different extension. + # For example, integer_powers() won't handle exp(x/2 + 1) + # over QQ(x, exp(x)), but if we pull out the exp(1), it + # will. Or maybe we have exp(x + x**2/2), over + # QQ(x, exp(x), exp(x**2)), which is exp(x)*sqrt(exp(x**2)), + # but if we use QQ(x, exp(x), exp(x**2/2)), then they will + # all work. + # + # So here is what we do: If there is a non-zero const, pull + # it out and retry. Also, if len(ans) > 1, then rewrite + # exp(arg) as the product of exponentials from ans, and + # retry that. If const == 0 and len(ans) == 1, then we + # assume that it would have been handled by either + # integer_powers() or n == 1 above if it could be handled, + # so we give up at that point. For example, you can never + # handle exp(log(x)/2) because it equals sqrt(x). + + if const or len(ans) > 1: + rad = Mul(*[term**(power/n) for term, power in ans]) + self.newf = self.newf.xreplace(dict((exp(p*exparg), + exp(const*p)*rad) for exparg, p in others)) + self.newf = self.newf.xreplace(dict(list(zip(reversed(self.T), + reversed([f(self.x) for f in self.Tfuncs]))))) + restart = True + break + else: + # TODO: give algebraic dependence in error string + raise NotImplementedError("Cannot integrate over " + "algebraic extensions.") - while len(lsyms) < n: - lsyms.append( Dummy('%s%i' % (name, len(lsyms))) ) + else: + arga, argd = frac_in(arg, self.t) + darga = (argd*derivation(Poly(arga, self.t), self) - + arga*derivation(Poly(argd, self.t), self)) + dargd = argd**2 + darga, dargd = darga.cancel(dargd, include=True) + darg = darga.as_expr()/dargd.as_expr() + self.t = next(self.ts) + self.T.append(self.t) + self.E_args.append(arg) + self.E_K.append(len(self.T) - 1) + self.D.append(darg.as_poly(self.t, expand=False)*Poly(self.t, + self.t, expand=False)) + if dummy: + i = Dummy("i") + else: + i = Symbol('i') + self.Tfuncs = self.Tfuncs + [Lambda(i, exp(arg.subs(self.x, i)))] + self.newf = self.newf.xreplace( + dict((exp(exparg), self.t**p) for exparg, p in others)) + new_extension = True + + if restart: + return None + return new_extension + + def _log_part(self, logs, dummy=True): + """ + Try to build a logarithmic extension. + + Returns True if there was a new extension and False if there was no new + extension but it was able to rewrite the given logarithms in terms + of the existing extension. Unlike with exponential extensions, there + is no way that a logarithm is not transcendental over and cannot be + rewritten in terms of an already existing extension in a non-algebraic + way, so this function does not ever return None or raise + NotImplementedError. + """ + from sympy.integrals.prde import is_deriv_k + + new_extension = False + logargs = [i.args[0] for i in logs] + for arg in ordered(logargs): + # The log case is easier, because whenever a logarithm is algebraic + # over the base field, it is of the form a1*t1 + ... an*tn + c, + # which is a polynomial, so we can just replace it with that. + # In other words, we don't have to worry about radicals. + arga, argd = frac_in(arg, self.t) + A = is_deriv_k(arga, argd, self) + if A is not None: + ans, u, const = A + newterm = log(const) + u + self.newf = self.newf.xreplace({log(arg): newterm}) + continue - return lsyms[:n] + else: + arga, argd = frac_in(arg, self.t) + darga = (argd*derivation(Poly(arga, self.t), self) - + arga*derivation(Poly(argd, self.t), self)) + dargd = argd**2 + darg = darga.as_expr()/dargd.as_expr() + self.t = next(self.ts) + self.T.append(self.t) + self.L_args.append(arg) + self.L_K.append(len(self.T) - 1) + self.D.append(cancel(darg.as_expr()/arg).as_poly(self.t, + expand=False)) + if dummy: + i = Dummy("i") + else: + i = Symbol('i') + self.Tfuncs = self.Tfuncs + [Lambda(i, log(arg.subs(self.x, i)))] + self.newf = self.newf.xreplace({log(arg): self.t}) + new_extension = True + + return new_extension + + @property + def _important_attrs(self): + """ + Returns some of the more important attributes of self. + + Used for testing and debugging purposes. + + The attributes are (fa, fd, D, T, Tfuncs, backsubs, E_K, E_args, + L_K, L_args). + """ + # XXX: This might be easier to read as a dict or something + # Maybe a named tuple. + return (self.fa, self.fd, self.D, self.T, self.Tfuncs, + self.backsubs, self.E_K, self.E_args, self.L_K, self.L_args) + + # TODO: Implement __repr__ + + def __str__(self): + return str(self._important_attrs) + + def reset(self, dummy=True): + """ + Reset self to an initial state. Used by __init__. + """ + self.t = self.x + self.T = [self.x] + self.D = [Poly(1, self.x)] + self.level = -1 + self.L_K, self.E_K, self.L_args, self.E_args = [], [], [], [] + if dummy: + self.ts = numbered_symbols('t', cls=Dummy) + else: + # For testing + self.ts = numbered_symbols('t') + # For various things that we change to make things work that we need to + # change back when we are done. + self.backsubs = [] + self.Tfuncs = [] + self.newf = self.f + + def increment_level(self): + """ + Increment the level of self. + + This makes the working differential extension larger. self.level is + given relative to the end of the list (-1, -2, etc.), so we don't need + do worry about it when building the extension. + """ + if self.level >= -1: + raise ValueError("The level of the differential extension cannot " + "be incremented any further.") + + self.level += 1 + self.t = self.T[self.level] + self.d = self.D[self.level] + self.case = self.cases[self.level] + return None + def decrement_level(self): + """ + Decrease the level of self. + + This makes the working differential extension smaller. self.level is + given relative to the end of the list (-1, -2, etc.), so we don't need + do worry about it when building the extension. + """ + if self.level <= -len(self.T): + raise ValueError("The level of the differential extension cannot " + "be decremented any further.") + + self.level -= 1 + self.t = self.T[self.level] + self.d = self.D[self.level] + self.case = self.cases[self.level] + return None -def heurisch(f, x, rewrite=False, hints=None, mappings=None, retries=3): - """Compute indefinite integral using heuristic Risch algorithm. - This is a heuristic approach to indefinite integration in finite - terms using the extended heuristic (parallel) Risch algorithm, based - on Manuel Bronstein's "Poor Man's Integrator". +class DecrementLevel(object): + """ + A context manager for decrementing the level of a DifferentialExtension. + """ + __slots__ = ('DE',) - The algorithm supports various classes of functions including - transcendental elementary or special functions like Airy, - Bessel, Whittaker and Lambert. + def __init__(self, DE): + self.DE = DE + return - Note that this algorithm is not a decision procedure. If it isn't - able to compute the antiderivative for a given function, then this is - not a proof that such a functions does not exist. One should use - recursive Risch algorithm in such case. It's an open question if - this algorithm can be made a full decision procedure. + def __enter__(self): + self.DE.decrement_level() - This is an internal integrator procedure. You should use toplevel - '_integrate' function in most cases, as this procedure needs some - preprocessing steps and otherwise may fail. + def __exit__(self, exc_type, exc_value, traceback): + self.DE.increment_level() - **Specification** - heurisch(f, x, rewrite=False, hints=None) +class NonElementaryIntegralException(Exception): + """ + Exception used by subroutines within the Risch algorithm to indicate to one + another that the function being integrated does not have an elementary + integral in the given differential field. + """ + # TODO: Rewrite algorithms below to use this (?) + + # TODO: Pass through information about why the integral was nonelementary, + # and store that in the resulting NonElementaryIntegral somehow. + pass - where - f : expression - x : symbol - rewrite -> force rewrite 'f' in terms of 'tan' and 'tanh' - hints -> a list of functions that may appear in anti-derivate +def gcdex_diophantine(a, b, c): + """ + Extended Euclidean Algorithm, Diophantine version. + + Given a, b in K[x] and c in (a, b), the ideal generated by a and b, + return (s, t) such that s*a + t*b == c and either s == 0 or s.degree() + < b.degree(). + """ + # Extended Euclidean Algorithm (Diophantine Version) pg. 13 + # TODO: This should go in densetools.py. + # XXX: Bettter name? - - hints = None --> no suggestions at all - - hints = [ ] --> try to figure out - - hints = [f1, ..., fn] --> we know better + s, g = a.half_gcdex(b) + q = c.exquo(g) # Inexact division means c is not in (a, b) + s = q*s - Examples - ======== + if not s.is_zero and b.degree() >= b.degree(): + q, s = s.div(b) - >>> from sympy import tan - >>> from sympy.integrals.risch import heurisch - >>> from sympy.abc import x, y + t = (c - s*a).exquo(b) - >>> heurisch(y*tan(x), x) - y*log(tan(x)**2 + 1)/2 + return (s, t) - See Manuel Bronstein's "Poor Man's Integrator": - [1] http://www-sop.inria.fr/cafe/Manuel.Bronstein/pmint/index.html +def frac_in(f, t, **kwargs): + """ + Returns the tuple (fa, fd), where fa and fd are Polys in t. - For more information on the implemented algorithm refer to: + This is a common idiom in the Risch Algorithm functions, so we abstract + it out here. f should be a basic expresion, a Poly, or a tuple (fa, fd), + where fa and fd are either basic expressions or Polys, and f == fa/fd. + **kwargs are applied to Poly. + """ + cancel = kwargs.pop('cancel', False) + if type(f) is tuple: + fa, fd = f + f = fa.as_expr()/fd.as_expr() + fa, fd = f.as_expr().as_numer_denom() + fa, fd = fa.as_poly(t, **kwargs), fd.as_poly(t, **kwargs) + if cancel: + fa, fd = fa.cancel(fd, include=True) + if fa is None or fd is None: + raise ValueError("Could not turn %s into a fraction in %s." % (f, t)) + return (fa, fd) - [2] K. Geddes, L. Stefanus, On the Risch-Norman Integration - Method and its Implementation in Maple, Proceedings of - ISSAC'89, ACM Press, 212-217. - [3] J. H. Davenport, On the Parallel Risch Algorithm (I), - Proceedings of EUROCAM'82, LNCS 144, Springer, 144-157. +def as_poly_1t(p, t, z): + """ + (Hackish) way to convert an element p of K[t, 1/t] to K[t, z]. - [4] J. H. Davenport, On the Parallel Risch Algorithm (III): - Use of Tangents, SIGSAM Bulletin 16 (1982), 3-6. + In other words, z == 1/t will be a dummy variable that Poly can handle + better. - [5] J. H. Davenport, B. M. Trager, On the Parallel Risch - Algorithm (II), ACM Transactions on Mathematical - Software 11 (1985), 356-362. + See issue 2032. - See Also + Examples ======== - sympy.integrals.integrals.Integral.doit - sympy.integrals.integrals.Integral - components + >>> from sympy import Symbol, random_poly + >>> from sympy.integrals.risch import as_poly_1t + >>> from sympy.abc import x, z + + >>> p1 = random_poly(x, 10, -10, 10) + >>> p2 = random_poly(x, 10, -10, 10) + >>> p = p1 + p2.subs(x, 1/x) + >>> as_poly_1t(p, x, z).as_expr().subs(z, 1/x) == p + True """ - f = sympify(f) + # TODO: Use this on the final result. That way, we can avoid answers like + # (...)*exp(-x). + pa, pd = frac_in(p, t, cancel=True) + if not pd.is_monomial: + # XXX: Is there a better Poly exception that we could raise here + # Either way, if you see this (from the Risch Algorithm) it indicates + # a bug. + raise PolynomialError("%s is not an element of K[%s, 1/%s]." % (p, t, t)) + d = pd.degree(t) + one_t_part = pa.slice(0, d + 1) + r = pd.degree() - pa.degree() + t_part = pa - one_t_part + try: + t_part = t_part.to_field().exquo(pd) + except DomainError as e: + # Issue 1851 + raise NotImplementedError(e) + # Compute the negative degree parts. Also requires polys11. + one_t_part = Poly.from_list(reversed(one_t_part.rep.rep), *one_t_part.gens, + **{'domain': one_t_part.domain}) + if r > 0: + one_t_part *= Poly(t**r, t) + + one_t_part = one_t_part.replace(t, z) # z will be 1/t + if pd.nth(d): + one_t_part *= Poly(1/pd.nth(d), z, expand=False) + ans = t_part.as_poly(t, z, expand=False) + one_t_part.as_poly(t, z, + expand=False) - if not f.is_Add: - indep, f = f.as_independent(x) - else: - indep = S.One + return ans - if not f.has(x): - return indep * f * x - rewritables = { - (sin, cos, cot) : tan, - (sinh, cosh, coth) : tanh, - } - - if rewrite: - for candidates, rule in rewritables.items(): - f = f.rewrite(candidates, rule) - else: - for candidates in rewritables.keys(): - if f.has(*candidates): - break - else: - rewrite = True +def derivation(p, DE, coefficientD=False, basic=False): + """ + Computes Dp. - terms = components(f, x) + Given the derivation D with D = d/dx and p is a polynomial in t over + K(x), return Dp. - if hints is not None: - if not hints: - a = Wild('a', exclude=[x]) - b = Wild('b', exclude=[x]) - c = Wild('c', exclude=[x]) - - for g in set(terms): - if g.is_Function: - if g.func is exp: - M = g.args[0].match(a*x**2) - - if M is not None: - terms.add(erf(sqrt(-M[a])*x)) - - M = g.args[0].match(a*x**2 + b*x + c) - - if M is not None: - if M[a].is_positive: - terms.add(sqrt(pi/4*(-M[a]))*exp(M[c]-M[b]**2/(4*M[a]))* \ - erf(-sqrt(-M[a])*x + M[b]/(2*sqrt(-M[a])))) - elif M[a].is_negative: - terms.add(sqrt(pi/4*(-M[a]))*exp(M[c]-M[b]**2/(4*M[a]))* \ - erf(sqrt(-M[a])*x - M[b]/(2*sqrt(-M[a])))) - - M = g.args[0].match(a*log(x)**2) - - if M is not None: - if M[a].is_positive: - terms.add(-I*erf(I*(sqrt(M[a])*log(x)+1/(2*sqrt(M[a]))))) - if M[a].is_negative: - terms.add(erf(sqrt(-M[a])*log(x)-1/(2*sqrt(-M[a])))) - - elif g.is_Pow: - if g.exp.is_Rational and g.exp.q == 2: - M = g.base.match(a*x**2 + b) - - if M is not None and M[b].is_positive: - if M[a].is_positive: - terms.add(asinh(sqrt(M[a]/M[b])*x)) - elif M[a].is_negative: - terms.add(asin(sqrt(-M[a]/M[b])*x)) - - M = g.base.match(a*x**2 - b) - - if M is not None and M[b].is_positive: - if M[a].is_positive: - terms.add(acosh(sqrt(M[a]/M[b])*x)) - elif M[a].is_negative: - terms.add((-M[b]/2*sqrt(-M[a])*\ - atan(sqrt(-M[a])*x/sqrt(M[a]*x**2-M[b])))) + If coefficientD is True, it computes the derivation kD + (kappaD), which is defined as kD(sum(ai*Xi**i, (i, 0, n))) == + sum(Dai*Xi**i, (i, 1, n)) (Definition 3.2.2, page 80). X in this case is + T[-1], so coefficientD computes the derivative just with respect to T[:-1], + with T[-1] treated as a constant. + If basic=True, the returns a Basic expression. Elements of D can still be + instances of Poly. + """ + if basic: + r = 0 + else: + r = Poly(0, DE.t) + + t = DE.t + if coefficientD: + if DE.level <= -len(DE.T): + # 'base' case, the answer is 0. + return r + DE.decrement_level() + + D = DE.D[:len(DE.D) + DE.level + 1] + T = DE.T[:len(DE.T) + DE.level + 1] + + for d, v in zip(D, T): + pv = p.as_poly(v) + if pv is None or basic: + pv = p.as_expr() + + if basic: + r += d.as_expr()*pv.diff(v) else: - terms |= set(hints) + r += (d*pv.diff(v)).as_poly(t) - for g in set(terms): - terms |= components(cancel(g.diff(x)), x) + if basic: + r = cancel(r) + if coefficientD: + DE.increment_level() - # TODO: caching is significant factor for why permutations work at all. Change this. - V = _symbols('x', len(terms)) + return r - mapping = dict(list(zip(terms, V))) - rev_mapping = {} +def get_case(d, t): + """ + Returns the type of the derivation d. - for k, v in mapping.items(): - rev_mapping[v] = k + Returns one of {'exp', 'tan', 'base', 'primitive', 'other_linear', + 'other_nonlinear'}. + """ + if not d.has(t): + if d.is_one: + return 'base' + return 'primitive' + if d.rem(Poly(t, t)).is_zero: + return 'exp' + if d.rem(Poly(1 + t**2, t)).is_zero: + return 'tan' + if d.degree(t) > 1: + return 'other_nonlinear' + return 'other_linear' - if mappings is None: - # Pre-sort mapping in order of largest to smallest expressions (last is always x). - def _sort_key(arg): - return default_sort_key(arg[0].as_independent(x)[1]) - mapping = sorted(list(mapping.items()), key=_sort_key, reverse=True) - mappings = permutations(mapping) - def _substitute(expr): - return expr.subs(mapping) +def splitfactor(p, DE, coefficientD=False, z=None): + """ + Splitting factorization. - for mapping in mappings: - # TODO: optimize this by not generating permutations where mapping[-1] != x. - if mapping[-1][0] != x: - continue + Given a derivation D on k[t] and p in k[t], return (p_n, p_s) in + k[t] x k[t] such that p = p_n*p_s, p_s is special, and each square + factor of p_n is normal. - mapping = list(mapping) + Page. 100 + """ + kinv = [1/x for x in DE.T[:DE.level]] + if z: + kinv.append(z) + + One = Poly(1, DE.t, domain=p.get_domain()) + Dp = derivation(p, DE, coefficientD=coefficientD) + # XXX: Is this right? + if p.is_zero: + return (p, One) + + if not p.has(DE.t): + s = p.as_poly(*kinv).gcd(Dp.as_poly(*kinv)).as_poly(DE.t) + n = p.exquo(s) + return (n, s) + + if not Dp.is_zero: + h = p.gcd(Dp).to_field() + g = p.gcd(p.diff(DE.t)).to_field() + s = h.exquo(g) - diffs = [ _substitute(cancel(g.diff(x))) for g in terms ] - denoms = [ g.as_numer_denom()[1] for g in diffs ] + if s.degree(DE.t) == 0: + return (p, One) - if all(h.is_polynomial(*V) for h in denoms) and _substitute(f).is_rational_function(*V): - denom = reduce(lambda p, q: lcm(p, q, *V), denoms) - break + q_split = splitfactor(p.exquo(s), DE, coefficientD=coefficientD) + + return (q_split[0], q_split[1]*s) else: - if not rewrite: - result = heurisch(f, x, rewrite=True, hints=hints) + return (p, One) - if result is not None: - return indep*result - return None +def splitfactor_sqf(p, DE, coefficientD=False, z=None, basic=False): + """ + Splitting Square-free Factorization - numers = [ cancel(denom*g) for g in diffs ] + Given a derivation D on k[t] and p in k[t], returns (N1, ..., Nm) + and (S1, ..., Sm) in k[t]^m such that p = + (N1*N2**2*...*Nm**m)*(S1*S2**2*...*Sm**m) is a splitting + factorization of p and the Ni and Si are square-free and coprime. + """ + # TODO: This algorithm appears to be faster in every case + # TODO: Verify this and splitfactor() for multiple extensions + kkinv = [1/x for x in DE.T[:DE.level]] + DE.T[:DE.level] + if z: + kkinv = [z] + + S = [] + N = [] + p_sqf = p.sqf_list_include() + if p.is_zero: + return (((p, 1),), ()) + + for pi, i in p_sqf: + Si = pi.as_poly(*kkinv).gcd(derivation(pi, DE, + coefficientD=coefficientD,basic=basic).as_poly(*kkinv)).as_poly(DE.t) + pi = Poly(pi, DE.t) + Si = Poly(Si, DE.t) + Ni = pi.exquo(Si) + if not Si.is_one: + S.append((Si, i)) + if not Ni.is_one: + N.append((Ni, i)) - def _derivation(h): - return Add(*[ d * h.diff(v) for d, v in zip(numers, V) ]) + return (tuple(N), tuple(S)) - def _deflation(p): - for y in V: - if not p.has(y): - continue - if _derivation(p) is not S.Zero: - c, q = p.as_poly(y).primitive() - return _deflation(c)*gcd(q, q.diff(y)).as_expr() - else: - return p +def canonical_representation(a, d, DE): + """ + Canonical Representation. - def _splitter(p): - for y in V: - if not p.has(y): - continue + Given a derivation D on k[t] and f = a/d in k(t), return (f_p, f_s, + f_n) in k[t] x k(t) x k(t) such that f = f_p + f_s + f_n is the + canonical representation of f (f_p is a polynomial, f_s is reduced + (has a special denominator), and f_n is simple (has a normal + denominator). + """ + # Make d monic + l = Poly(1/d.LC(), DE.t) + a, d = a.mul(l), d.mul(l) - if _derivation(y) is not S.Zero: - c, q = p.as_poly(y).primitive() + q, r = a.div(d) + dn, ds = splitfactor(d, DE) - q = q.as_expr() + b, c = gcdex_diophantine(dn.as_poly(DE.t), ds.as_poly(DE.t), r.as_poly(DE.t)) + b, c = b.as_poly(DE.t), c.as_poly(DE.t) - h = gcd(q, _derivation(q), y) - s = quo(h, gcd(q, q.diff(y), y), y) + return (q, (b, ds), (c, dn)) - c_split = _splitter(c) - if s.as_poly(y).degree() == 0: - return (c_split[0], q * c_split[1]) +def hermite_reduce(a, d, DE): + """ + Hermite Reduction - Mack's Linear Version. - q_split = _splitter(cancel(q / s)) + Given a derivation D on k(t) and f = a/d in k(t), returns g, h, r in + k(t) such that f = Dg + h + r, h is simple, and r is reduced. - return (c_split[0]*q_split[0]*s, c_split[1]*q_split[1]) - else: - return (S.One, p) + """ + # Make d monic + l = Poly(1/d.LC(), DE.t) + a, d = a.mul(l), d.mul(l) - special = {} + fp, fs, fn = canonical_representation(a, d, DE) + a, d = fn + l = Poly(1/d.LC(), DE.t) + a, d = a.mul(l), d.mul(l) - for term in terms: - if term.is_Function: - if term.func is tan: - special[1 + _substitute(term)**2] = False - elif term.func is tanh: - special[1 + _substitute(term)] = False - special[1 - _substitute(term)] = False - elif term.func is C.LambertW: - special[_substitute(term)] = True + ga = Poly(0, DE.t) + gd = Poly(1, DE.t) - F = _substitute(f) + dd = derivation(d, DE) + dm = gcd(d, dd).as_poly(DE.t) + ds, r = d.div(dm) - P, Q = F.as_numer_denom() + while dm.degree(DE.t)>0: - u_split = _splitter(denom) - v_split = _splitter(Q) + ddm = derivation(dm, DE) + dm2 = gcd(dm, ddm) + dms, r = dm.div(dm2) + ds_ddm = ds.mul(ddm) + ds_ddm_dm, r = ds_ddm.div(dm) - polys = list(v_split) + [ u_split[0] ] + list(special.keys()) + b, c = gcdex_diophantine(-ds_ddm_dm.as_poly(DE.t), dms.as_poly(DE.t), a.as_poly(DE.t)) + b, c = b.as_poly(DE.t), c.as_poly(DE.t) - s = u_split[0] * Mul(*[ k for k, v in special.items() if v ]) - polified = [ p.as_poly(*V) for p in [s, P, Q] ] + db = derivation(b, DE).as_poly(DE.t) + ds_dms, r = ds.div(dms) + a = c.as_poly(DE.t) - db.mul(ds_dms).as_poly(DE.t) - if None in polified: - return None + ga = ga*dm + b*gd + gd = gd*dm + ga, gd = ga.cancel(gd, include=True) + dm = dm2 - a, b, c = [ p.total_degree() for p in polified ] + d = ds + q, r = a.div(d) + ga, gd = ga.cancel(gd, include=True) - poly_denom = (s * v_split[0] * _deflation(v_split[1])).as_expr() + r, d = r.cancel(d, include=True) + rra = q*fs[1] + fp*fs[1] + fs[0] + rrd = fs[1] + rra, rrd = rra.cancel(rrd, include=True) - def _exponent(g): - if g.is_Pow: - if g.exp.is_Rational and g.exp.q != 1: - if g.exp.p > 0: - return g.exp.p + g.exp.q - 1 - else: - return abs(g.exp.p + g.exp.q) - else: - return 1 - elif not g.is_Atom and g.args: - return max([ _exponent(h) for h in g.args ]) - else: - return 1 + return ((ga, gd), (r, d), (rra, rrd)) + + +def polynomial_reduce(p, DE): + """ + Polynomial Reduction. + + Given a derivation D on k(t) and p in k[t] where t is a nonlinear + monomial over k, return q, r in k[t] such that p = Dq + r, and + deg(r) < deg_t(Dt). + """ + q = Poly(0, DE.t) + while p.degree(DE.t) >= DE.d.degree(DE.t): + m = p.degree(DE.t) - DE.d.degree(DE.t) + 1 + q0 = Poly(DE.t**m, DE.t).mul(Poly(p.as_poly(DE.t).LC()/ + (m*DE.d.LC()), DE.t)) + q += q0 + p = p - derivation(q0, DE) + + return (q, p) + + +def laurent_series(a, d, F, n, DE): + """ + Contribution of F to the full partial fraction decomposition of A/D + + Given a field K of characteristic 0 and A,D,F in K[x] with D monic, + nonzero, coprime with A, and F the factor of multiplicity n in the square- + free factorization of D, return the principal parts of the Laurent series of + A/D at all the zeros of F. + """ + if F.degree()==0: + return 0 + Z = _symbols('z', n) + Z.insert(0, z) + delta_a = Poly(0, DE.t) + delta_d = Poly(1, DE.t) + + E = d.quo(F**n) + ha, hd = (a, E*Poly(z**n, DE.t)) + dF = derivation(F,DE) + B, G = gcdex_diophantine(E, F, Poly(1,DE.t)) + C, G = gcdex_diophantine(dF, F, Poly(1,DE.t)) + + # initialization + F_store = F + V, DE_D_list, H_list= [], [], [] + + for j in range(0, n): + # jth derivative of z would be substituted with dfnth/(j+1) where dfnth =(d^n)f/(dx)^n + F_store = derivation(F_store, DE) + v = (F_store.as_expr())/(j + 1) + V.append(v) + DE_D_list.append(Poly(Z[j + 1],Z[j])) + + DE_new = DifferentialExtension(extension = {'D': DE_D_list}) #a differential indeterminate + for j in range(0, n): + zEha = Poly(z**(n + j), DE.t)*E**(j + 1)*ha + zEhd = hd + Pa, Pd = cancel((zEha, zEhd))[1], cancel((zEha, zEhd))[2] + Q = Pa.quo(Pd) + for i in range(0, j + 1): + Q = Q.subs(Z[i], V[i]) + Dha = hd*derivation(ha, DE, basic=True) + ha*derivation(hd, DE, basic=True) + Dha += hd*derivation(ha, DE_new, basic=True) + ha*derivation(hd, DE_new, basic=True) + Dhd = Poly(j + 1, DE.t)*hd**2 + ha, hd = Dha, Dhd + + Ff, Fr = F.div(gcd(F, Q)) + F_stara, F_stard = frac_in(Ff, DE.t) + if F_stara.degree(DE.t) - F_stard.degree(DE.t) > 0: + QBC = Poly(Q, DE.t)*B**(1 + j)*C**(n + j) + H = QBC + H_list.append(H) + H = (QBC*F_stard).rem(F_stara) + alphas = real_roots(F_stara) + for alpha in list(alphas): + delta_a = delta_a*Poly((DE.t - alpha)**(n - j), DE.t) + Poly(H.eval(alpha), DE.t) + delta_d = delta_d*Poly((DE.t - alpha)**(n - j), DE.t) + return (delta_a, delta_d, H_list) + + +def recognize_derivative(a, d, DE, z=None): + """ + Compute the squarefree factorization of the denominator of f + and for each Di the polynomial H in K[x] (see Theorem 2.7.1), using the + LaurentSeries algorithm. Write Di = GiEi where Gj = gcd(Hn, Di) and + gcd(Ei,Hn) = 1. Since the residues of f at the roots of Gj are all 0, and + the residue of f at a root alpha of Ei is Hi(a) != 0, f is the derivative of a + rational function if and only if Ei = 1 for each i, which is equivalent to + Di | H[-1] for each i. + """ + flag =True + a, d = a.cancel(d, include=True) + q, r = a.div(d) + Np, Sp = splitfactor_sqf(d, DE, coefficientD=True, z=z) + + j = 1 + for (s, i) in Sp: + delta_a, delta_d, H = laurent_series(r, d, s, j, DE) + g = gcd(d, H[-1]).as_poly() + if g is not d: + flag = False + break + j = j + 1 + return flag + +def recognize_log_derivative(a, d, DE, z=None): + """ + There exists a v in K(x)* such that f = dv/v + where f a rational function if and only if f can be written as f = A/D + where D is squarefree,deg(A) < deg(D), gcd(A, D) = 1, + and all the roots of the Rothstein-Trager resultant are integers. In that case, + any of the Rothstein-Trager, Lazard-Rioboo-Trager or Czichowski algorithm + produces u in K(x) such that du/dx = uf. + """ + + z = z or Dummy('z') + a, d = a.cancel(d, include=True) + p, a = a.div(d) + + pz = Poly(z, DE.t) + Dd = derivation(d, DE) + q = a - pz*Dd + r, R = d.resultant(q, includePRS=True) + r = Poly(r, z) + Np, Sp = splitfactor_sqf(r, DE, coefficientD=True, z=z) + + for s, i in Sp: + # TODO also consider the complex roots + # incase we have complex roots it should turn the flag false + a = real_roots(s.as_poly(z)) + + if any(not j.is_Integer for j in a): + return False + return True + +def residue_reduce(a, d, DE, z=None, invert=True): + """ + Lazard-Rioboo-Rothstein-Trager resultant reduction. - A, B = _exponent(f), a + max(b, c) + Given a derivation D on k(t) and f in k(t) simple, return g + elementary over k(t) and a Boolean b in {True, False} such that f - + Dg in k[t] if b == True or f + h and f + h - Dg do not have an + elementary integral over k(t) for any h in k (reduced) if b == + False. + + Returns (G, b), where G is a tuple of tuples of the form (s_i, S_i), + such that g = Add(*[RootSum(s_i, lambda z: z*log(S_i(z, t))) for + S_i, s_i in G]). f - Dg is the remaining integral, which is elementary + only if b == True, and hence the integral of f is elementary only if + b == True. - if A > 1 and B > 1: - monoms = monomials(V, A + B - 1) + f - Dg is not calculated in this function because that would require + explicitly calculating the RootSum. Use residue_reduce_derivation(). + """ + # TODO: Use log_to_atan() from rationaltools.py + # If r = residue_reduce(...), then the logarithmic part is given by: + # sum([RootSum(a[0].as_poly(z), lambda i: i*log(a[1].as_expr()).subs(z, + # i)).subs(t, log(x)) for a in r[0]]) + + z = z or Dummy('z') + a, d = a.cancel(d, include=True) + kkinv = [1/x for x in DE.T[:DE.level]] + DE.T[:DE.level] + + if a.is_zero: + return ([], True) + p, a = a.div(d) + + pz = Poly(z, DE.t) + + Dd = derivation(d, DE) + q = a - pz*Dd + + if Dd.degree(DE.t) <= d.degree(DE.t): + r, R = d.resultant(q, includePRS=True) else: - monoms = monomials(V, A + B) + r, R = q.resultant(d, includePRS=True) + + R_map, H = {}, [] + for i in R: + R_map[i.degree()] = i + + r = Poly(r, z) + Np, Sp = splitfactor_sqf(r, DE, coefficientD=True, z=z) + + for s, i in Sp: + if i == d.degree(DE.t): + s = Poly(s, z).monic() + H.append((s, d)) + else: + h = R_map.get(i) + if h is None: + continue + h_lc = Poly(h.as_poly(DE.t).LC(), DE.t, field=True) + + h_lc_sqf = h_lc.sqf_list_include(all=True) + + for a, j in h_lc_sqf: + h = Poly(h, DE.t, field=True).exquo(Poly(gcd(a, s**j, *kkinv), + DE.t)) + + s = Poly(s, z).monic() + + if invert: + h_lc = Poly(h.as_poly(DE.t).LC(), DE.t, field=True, expand=False) + inv, coeffs = h_lc.as_poly(z, field=True).invert(s), [S(1)] + + for coeff in h.coeffs()[1:]: + L = reduced(inv*coeff, [s])[1] + coeffs.append(L.as_expr()) + + h = Poly(dict(list(zip(h.monoms(), coeffs))), DE.t) + + H.append((s, h)) + + b = all([not cancel(i.as_expr()).has(DE.t, z) for i, _ in Np]) + + return (H, b) + + +def residue_reduce_to_basic(H, DE, z): + """ + Converts the tuple returned by residue_reduce() into a Basic expression. + """ + # TODO: check what Lambda does with RootOf + i = Dummy('i') + s = list(zip(reversed(DE.T), reversed([f(DE.x) for f in DE.Tfuncs]))) + + return sum((RootSum(a[0].as_poly(z), Lambda(i, i*log(a[1].as_expr()).subs( + {z: i}).subs(s))) for a in H)) + + +def residue_reduce_derivation(H, DE, z): + """ + Computes the derivation of an expression returned by residue_reduce(). + + In general, this is a rational function in t, so this returns an + as_expr() result. + """ + # TODO: verify that this is correct for multiple extensions + i = Dummy('i') + return S(sum((RootSum(a[0].as_poly(z), Lambda(i, i*derivation(a[1], + DE).as_expr().subs(z, i)/a[1].as_expr().subs(z, i))) for a in H))) + + +def integrate_primitive_polynomial(p, DE): + """ + Integration of primitive polynomials. + + Given a primitive monomial t over k, and p in k[t], return q in k[t], + r in k, and a bool b in {True, False} such that r = p - Dq is in k if b is + True, or r = p - Dq does not have an elementary integral over k(t) if b is + False. + """ + from sympy.integrals.prde import limited_integrate - poly_coeffs = _symbols('A', len(monoms)) + Zero = Poly(0, DE.t) + q = Poly(0, DE.t) - poly_part = Add(*[ poly_coeffs[i]*monomial - for i, monomial in enumerate(monoms) ]) + if not p.has(DE.t): + return (Zero, p, True) - reducibles = set() + while True: + if not p.has(DE.t): + return (q, p, True) + + Dta, Dtb = frac_in(DE.d, DE.T[DE.level - 1]) + + with DecrementLevel(DE): # We had better be integrating the lowest extension (x) + # with ratint(). + a = p.LC() + aa, ad = frac_in(a, DE.t) - for poly in polys: - if poly.has(*V): try: - factorization = factor(poly, greedy=True) - except PolynomialError: - factorization = poly - factorization = poly + (ba, bd), c = limited_integrate(aa, ad, [(Dta, Dtb)], DE) + assert len(c) == 1 + except NonElementaryIntegralException: + return (q, p, False) - if factorization.is_Mul: - reducibles |= set(factorization.args) - else: - reducibles.add(factorization) + m = p.degree(DE.t) + q0 = c[0].as_poly(DE.t)*Poly(DE.t**(m + 1)/(m + 1), DE.t) + \ + (ba.as_expr()/bd.as_expr()).as_poly(DE.t)*Poly(DE.t**m, DE.t) - def _integrate(field=None): - irreducibles = set() + p = p - derivation(q0, DE) + q = q + q0 - for poly in reducibles: - for z in poly.atoms(Symbol): - if z in V: - break - else: + +def integrate_primitive(a, d, DE, z=None): + """ + Integration of primitive functions. + + Given a primitive monomial t over k and f in k(t), return g elementary over + k(t), i in k(t), and b in {True, False} such that i = f - Dg is in k if b + is True or i = f - Dg does not have an elementary integral over k(t) if b + is False. + + This function returns a Basic expression for the first argument. If b is + True, the second argument is Basic expression in k to recursively integrate. + If b is False, the second argument is an unevaluated Integral, which has + been proven to be nonelementary. + """ + # XXX: a and d must be canceled, or this might return incorrect results + z = z or Dummy("z") + s = list(zip(reversed(DE.T), reversed([f(DE.x) for f in DE.Tfuncs]))) + + g1, h, r = hermite_reduce(a, d, DE) + g2, b = residue_reduce(h[0], h[1], DE, z=z) + if not b: + i = cancel(a.as_expr()/d.as_expr() - (g1[1]*derivation(g1[0], DE) - + g1[0]*derivation(g1[1], DE)).as_expr()/(g1[1]**2).as_expr() - + residue_reduce_derivation(g2, DE, z)) + i = NonElementaryIntegral(cancel(i).subs(s), DE.x) + return ((g1[0].as_expr()/g1[1].as_expr()).subs(s) + + residue_reduce_to_basic(g2, DE, z), i, b) + + # h - Dg2 + r + p = cancel(h[0].as_expr()/h[1].as_expr() - residue_reduce_derivation(g2, + DE, z) + r[0].as_expr()/r[1].as_expr()) + p = p.as_poly(DE.t) + + q, i, b = integrate_primitive_polynomial(p, DE) + + ret = ((g1[0].as_expr()/g1[1].as_expr() + q.as_expr()).subs(s) + + residue_reduce_to_basic(g2, DE, z)) + if not b: + # TODO: This does not do the right thing when b is False + i = NonElementaryIntegral(cancel(i.as_expr()).subs(s), DE.x) + else: + i = cancel(i.as_expr()) + + return (ret, i, b) + + +def integrate_hyperexponential_polynomial(p, DE, z): + """ + Integration of hyperexponential polynomials. + + Given a hyperexponential monomial t over k and p in k[t, 1/t], return q in + k[t, 1/t] and a bool b in {True, False} such that p - Dq in k if b is True, + or p - Dq does not have an elementary integral over k(t) if b is False. + """ + from sympy.integrals.rde import rischDE + + t1 = DE.t + dtt = DE.d.exquo(Poly(DE.t, DE.t)) + qa = Poly(0, DE.t) + qd = Poly(1, DE.t) + b = True + + with DecrementLevel(DE): + for i in range(-p.degree(z), p.degree(t1) + 1): + if not i: continue + elif i < 0: + # If you get AttributeError: 'NoneType' object has no attribute 'nth' + # then this should really not have expand=False + # But it shouldn't happen because p is already a Poly in t and z + a = p.as_poly(z, expand=False).nth(-i) + else: + # If you get AttributeError: 'NoneType' object has no attribute 'nth' + # then this should really not have expand=False + a = p.as_poly(t1, expand=False).nth(i) + + aa, ad = frac_in(a, DE.t, field=True) + aa, ad = aa.cancel(ad, include=True) + iDt = Poly(i, t1)*dtt + iDta, iDtd = frac_in(iDt, DE.t, field=True) + try: + va, vd = rischDE(iDta, iDtd, Poly(aa, DE.t), Poly(ad, DE.t), DE) + va, vd = frac_in((va, vd), t1) + except NonElementaryIntegralException: + b = False + else: + qa = qa*vd + va*Poly(t1**i)*qd + qd *= vd - irreducibles |= set(root_factors(poly, z, filter=field)) + return (qa, qd, b) - log_coeffs, log_part = [], [] - B = _symbols('B', len(irreducibles)) - for i, poly in enumerate(irreducibles): - if poly.has(*V): - log_coeffs.append(B[i]) - log_part.append(log_coeffs[-1] * log(poly)) +def integrate_hyperexponential(a, d, DE, z=None, conds='piecewise'): + """ + Integration of hyperexponential functions. - coeffs = poly_coeffs + log_coeffs + Given a hyperexponential monomial t over k and f in k(t), return g + elementary over k(t), i in k(t), and a bool b in {True, False} such that + i = f - Dg is in k if b is True or i = f - Dg does not have an elementary + integral over k(t) if b is False. + + This function returns a Basic expression for the first argument. If b is + True, the second argument is Basic expression in k to recursively integrate. + If b is False, the second argument is an unevaluated Integral, which has + been proven to be nonelementary. + """ + # XXX: a and d must be canceled, or this might return incorrect results + z = z or Dummy("z") + s = list(zip(reversed(DE.T), reversed([f(DE.x) for f in DE.Tfuncs]))) + + g1, h, r = hermite_reduce(a, d, DE) + g2, b = residue_reduce(h[0], h[1], DE, z=z) + if not b: + i = cancel(a.as_expr()/d.as_expr() - (g1[1]*derivation(g1[0], DE) - + g1[0]*derivation(g1[1], DE)).as_expr()/(g1[1]**2).as_expr() - + residue_reduce_derivation(g2, DE, z)) + i = NonElementaryIntegral(cancel(i.subs(s)), DE.x) + return ((g1[0].as_expr()/g1[1].as_expr()).subs(s) + + residue_reduce_to_basic(g2, DE, z), i, b) + + # p should be a polynomial in t and 1/t, because Sirr == k[t, 1/t] + # h - Dg2 + r + p = cancel(h[0].as_expr()/h[1].as_expr() - residue_reduce_derivation(g2, + DE, z) + r[0].as_expr()/r[1].as_expr()) + pp = as_poly_1t(p, DE.t, z) + + qa, qd, b = integrate_hyperexponential_polynomial(pp, DE, z) + + i = pp.nth(0, 0) + + ret = ((g1[0].as_expr()/g1[1].as_expr()).subs(s) \ + + residue_reduce_to_basic(g2, DE, z)) + + qds = qd.as_expr().subs(s) + if conds == 'piecewise' and DE.x not in qds.free_symbols: + # We have to be careful if the exponent is S.Zero! + ret += Piecewise( + (integrate(p/DE.t, DE.x), Eq(qds, 0)), + (qa.as_expr().subs(s) / qds, True) + ) + else: + ret += qa.as_expr().subs(s) / qds - candidate = poly_part/poly_denom + Add(*log_part) + if not b: + i = p - (qd*derivation(qa, DE) - qa*derivation(qd, DE)).as_expr()/\ + (qd**2).as_expr() + i = NonElementaryIntegral(cancel(i).subs(s), DE.x) + return (ret, i, b) - h = F - _derivation(candidate) / denom - numer = h.as_numer_denom()[0].expand(force=True) +def integrate_hypertangent_polynomial(p, DE): + """ + Integration of hypertangent polynomials. - equations = defaultdict(lambda: S.Zero) + Given a differential field k such that sqrt(-1) is not in k, a + hypertangent monomial t over k, and p in k[t], return q in k[t] and + c in k such that p - Dq - c*D(t**2 + 1)/(t**1 + 1) is in k and p - + Dq does not have an elementary integral over k(t) if Dc != 0. + """ + # XXX: Make sure that sqrt(-1) is not in k. + q, r = polynomial_reduce(p, DE) + a = DE.d.exquo(Poly(DE.t**2 + 1, DE.t)) + c = Poly(r.nth(1)/(2*a.as_expr()), DE.t) + return (q, c) - for term in Add.make_args(numer): - coeff, dependent = term.as_independent(*V) - equations[dependent] += coeff - solution = solve(list(equations.values()), *coeffs) +def integrate_nonlinear_no_specials(a, d, DE, z=None): + """ + Integration of nonlinear monomials with no specials. - return (solution, candidate, coeffs) if solution else None + Given a nonlinear monomial t over k such that Sirr ({p in k[t] | p is + special, monic, and irreducible}) is empty, and f in k(t), returns g + elementary over k(t) and a Boolean b in {True, False} such that f - Dg is + in k if b == True, or f - Dg does not have an elementary integral over k(t) + if b == False. + + This function is applicable to all nonlinear extensions, but in the case + where it returns b == False, it will only have proven that the integral of + f - Dg is nonelementary if Sirr is empty. - if not (F.atoms(Symbol) - set(V)): - result = _integrate('Q') + This function returns a Basic expression. + """ + # TODO: Integral from k? + # TODO: split out nonelementary integral + # XXX: a and d must be canceled, or this might not return correct results + z = z or Dummy("z") + s = list(zip(reversed(DE.T), reversed([f(DE.x) for f in DE.Tfuncs]))) + + g1, h, r = hermite_reduce(a, d, DE) + g2, b = residue_reduce(h[0], h[1], DE, z=z) + if not b: + return ((g1[0].as_expr()/g1[1].as_expr()).subs(s) + + residue_reduce_to_basic(g2, DE, z), b) + + # Because f has no specials, this should be a polynomial in t, or else + # there is a bug. + p = cancel(h[0].as_expr()/h[1].as_expr() - residue_reduce_derivation(g2, + DE, z).as_expr() + r[0].as_expr()/r[1].as_expr()).as_poly(DE.t) + q1, q2 = polynomial_reduce(p, DE) - if result is None: - result = _integrate() + if q2.has(DE.t): + b = False else: - result = _integrate() + b = True - if result is not None: - (solution, candidate, coeffs) = result + ret = (cancel(g1[0].as_expr()/g1[1].as_expr() + q1.as_expr()).subs(s) + + residue_reduce_to_basic(g2, DE, z)) + return (ret, b) - antideriv = candidate.subs(solution) - for coeff in coeffs: - if coeff not in solution: - antideriv = antideriv.subs(coeff, S.Zero) +class NonElementaryIntegral(Integral): + """ + Represents a nonelementary Integral. - antideriv = antideriv.subs(rev_mapping) - antideriv = cancel(antideriv).expand(force=True) + If the result of integrate() is an instance of this class, it is + guaranteed to be nonelementary. Note that integrate() by default will try + to find any closed-form solution, even in terms of special functions which + may themselves not be elementary. To make integrate() only give + elementary solutions, or, in the cases where it can prove the integral to + be nonelementary, instances of this class, use integrate(risch=True). + In this case, integrate() may raise NotImplementedError if it cannot make + such a determination. + + integrate() uses the deterministic Risch algorithm to integrate elementary + functions or prove that they have no elementary integral. In some cases, + this algorithm can split an integral into an elementary and nonelementary + part, so that the result of integrate will be the sum of an elementary + expression and a NonElementaryIntegral. + + Example + ======= + + >>> from sympy import integrate, exp, log, Integral + >>> from sympy.abc import x + + >>> a = integrate(exp(-x**2), x, risch=True) + >>> print(a) + Integral(exp(-x**2), x) + >>> type(a) + + + >>> expr = (2*log(x)**2 - log(x) - x**2)/(log(x)**3 - x**2*log(x)) + >>> b = integrate(expr, x, risch=True) + >>> print(b) + -log(-x + log(x))/2 + log(x + log(x))/2 + Integral(1/log(x), x) + >>> type(b.atoms(Integral).pop()) + - if antideriv.is_Add: - antideriv = antideriv.as_independent(x)[1] + """ + # TODO: This is useful in and of itself, because isinstance(result, + # NonElementaryIntegral) will tell if the integral has been proven to be + # elementary. But should we do more? Perhaps a no-op .doit() if + # elementary=True? Or maybe some information on why the integral is + # nonelementary. + pass + + +def risch_integrate(f, x, extension=None, handle_first='log', + separate_integral=False, rewrite_complex=False, + conds='piecewise'): + r""" + The Risch Integration Algorithm. + + Only transcendental functions are supported. Currently, only exponentials + and logarithms are supported, but support for trigonometric functions is + forthcoming. + + If this function returns an unevaluated Integral in the result, it means + that it has proven that integral to be nonelementary. Any errors will + result in raising NotImplementedError. The unevaluated Integral will be + an instance of NonElementaryIntegral, a subclass of Integral. + + handle_first may be either 'exp' or 'log'. This changes the order in + which the extension is built, and may result in a different (but + equivalent) solution (for an example of this, see issue 2010). It is also + possible that the integral may be computed with one but not the other, + because not all cases have been implemented yet. It defaults to 'log' so + that the outer extension is exponential when possible, because more of the + exponential case has been implemented. + + If separate_integral is True, the result is returned as a tuple (ans, i), + where the integral is ans + i, ans is elementary, and i is either a + NonElementaryIntegral or 0. This useful if you want to try further + integrating the NonElementaryIntegral part using other algorithms to + possibly get a solution in terms of special functions. It is False by + default. - return indep * antideriv - else: - if retries >= 0: - result = heurisch(f, x, mappings=mappings, rewrite=rewrite, hints=hints, retries=retries-1) + Examples + ======== + >>> from sympy.integrals.risch import risch_integrate + >>> from sympy import exp, log, pprint + >>> from sympy.abc import x + + First, we try integrating exp(-x**2). Except for a constant factor of + 2/sqrt(pi), this is the famous error function. + + >>> pprint(risch_integrate(exp(-x**2), x)) + / + | + | 2 + | -x + | e dx + | + / + + The unevaluated Integral in the result means that risch_integrate() has + proven that exp(-x**2) does not have an elementary anti-derivative. + + In many cases, risch_integrate() can split out the elementary + anti-derivative part from the nonelementary anti-derivative part. + For example, + + >>> pprint(risch_integrate((2*log(x)**2 - log(x) - x**2)/(log(x)**3 - + ... x**2*log(x)), x)) + / + | + log(-x + log(x)) log(x + log(x)) | 1 + - ---------------- + --------------- + | ------ dx + 2 2 | log(x) + | + / + + This means that it has proven that the integral of 1/log(x) is + nonelementary. This function is also known as the logarithmic integral, + and is often denoted as Li(x). + + risch_integrate() currently only accepts purely transcendental functions + with exponentials and logarithms, though note that this can include + nested exponentials and logarithms, as well as exponentials with bases + other than E. + + >>> pprint(risch_integrate(exp(x)*exp(exp(x)), x)) + / x\ + \e / + e + >>> pprint(risch_integrate(exp(exp(x)), x)) + / + | + | / x\ + | \e / + | e dx + | + / + + >>> pprint(risch_integrate(x*x**x*log(x) + x**x + x*x**x, x)) + x + x*x + >>> pprint(risch_integrate(x**x*log(x), x)) + / + | + | x + | x *log(x) dx + | + / + + >>> pprint(risch_integrate(-1/(x*log(x)*log(log(x))**2), x)) + 1 + ----------- + log(log(x)) + + """ + f = S(f) - if result is not None: - return indep*result + DE = extension or DifferentialExtension(f, x, handle_first=handle_first, rewrite_complex=rewrite_complex) + fa, fd = DE.fa, DE.fd - return None + result = S(0) + for case in reversed(DE.cases): + if not DE.fa.has(DE.t) and not fd.has(DE.t) and not case == 'base': + DE.decrement_level() + fa, fd = frac_in((fa, fd), DE.t) + continue + + fa, fd = fa.cancel(fd, include=True) + if case == 'exp': + ans, i, b = integrate_hyperexponential(fa, fd, DE, conds=conds) + elif case == 'primitive': + ans, i, b = integrate_primitive(fa, fd, DE) + elif case == 'base': + # XXX: We can't call ratint() directly here because it doesn't + # handle polynomials correctly. + ans = integrate(fa.as_expr()/fd.as_expr(), DE.x, risch=False) + b = False + i = S(0) + else: + raise NotImplementedError("Only exponential and logarithmic " + "extensions are currently supported.") + + result += ans + if b: + DE.decrement_level() + fa, fd = frac_in(i, DE.t) + else: + result, i = result.subs(DE.backsubs), i.subs(DE.backsubs) + if not separate_integral: + result += i + return result + else: + + if isinstance(i, NonElementaryIntegral): + return (result, i) + else: + return (result, 0) diff -Nru python3-sympy-0.7.2/sympy/integrals/tests/test_deltafunctions.py python3-sympy-0.7.3/sympy/integrals/tests/test_deltafunctions.py --- python3-sympy-0.7.2/sympy/integrals/tests/test_deltafunctions.py 1970-01-01 00:00:00.000000000 +0000 +++ python3-sympy-0.7.3/sympy/integrals/tests/test_deltafunctions.py 2013-07-13 17:53:32.000000000 +0000 @@ -0,0 +1,71 @@ +from sympy import cos, DiracDelta, Heaviside, Function, pi, S, sin, symbols +from sympy.integrals.deltafunctions import change_mul, deltaintegrate + +f = Function("f") +x_1, x_2, x, y, z = symbols("x_1 x_2 x y z") + + +def test_change_mul(): + assert change_mul(x, x) == x + assert change_mul(x*y, x) == (None, None) + assert change_mul(x*y*DiracDelta(x), x) == (DiracDelta(x), x*y) + assert change_mul(x*y*DiracDelta(x)*DiracDelta(y), x) == \ + (DiracDelta(x), x*y*DiracDelta(y)) + assert change_mul(DiracDelta(x)**2, x) == \ + (DiracDelta(x), DiracDelta(x)) + assert change_mul(y*DiracDelta(x)**2, x) == \ + (DiracDelta(x), y*DiracDelta(x)) + + +def test_deltaintegrate(): + assert deltaintegrate(x, x) is None + assert deltaintegrate(x + DiracDelta(x), x) is None + assert deltaintegrate(DiracDelta(x, 0), x) == Heaviside(x) + for n in range(10): + assert deltaintegrate(DiracDelta(x, n + 1), x) == DiracDelta(x, n) + assert deltaintegrate(DiracDelta(x), x) == Heaviside(x) + assert deltaintegrate(DiracDelta(-x), x) == Heaviside(x) + assert deltaintegrate(DiracDelta(x - y), x) == Heaviside(x - y) + assert deltaintegrate(DiracDelta(y - x), x) == Heaviside(x - y) + + assert deltaintegrate(x*DiracDelta(x), x) == 0 + assert deltaintegrate((x - y)*DiracDelta(x - y), x) == 0 + + assert deltaintegrate(DiracDelta(x)**2, x) == DiracDelta(0)*Heaviside(x) + assert deltaintegrate(y*DiracDelta(x)**2, x) == \ + y*DiracDelta(0)*Heaviside(x) + assert deltaintegrate(DiracDelta(x, 1)**2, x) is None + assert deltaintegrate(y*DiracDelta(x, 1)**2, x) is None + + assert deltaintegrate(DiracDelta(x) * f(x), x) == f(0) * Heaviside(x) + assert deltaintegrate(DiracDelta(-x) * f(x), x) == f(0) * Heaviside(x) + assert deltaintegrate(DiracDelta(x - 1) * f(x), x) == f(1) * Heaviside(x - 1) + assert deltaintegrate(DiracDelta(1 - x) * f(x), x) == f(1) * Heaviside(x - 1) + assert deltaintegrate(DiracDelta(x**2 + x - 2), x) == \ + Heaviside(x - 1)/3 + Heaviside(x + 2)/3 + + p = cos(x)*(DiracDelta(x) + DiracDelta(x**2 - 1))*sin(x)*(x - pi) + assert deltaintegrate(p, x) - (-pi*(cos(1)*Heaviside(-1 + x)*sin(1)/2 - \ + cos(1)*Heaviside(1 + x)*sin(1)/2) + \ + cos(1)*Heaviside(1 + x)*sin(1)/2 + \ + cos(1)*Heaviside(-1 + x)*sin(1)/2) == 0 + + p = x_2*DiracDelta(x - x_2)*DiracDelta(x_2 - x_1) + assert deltaintegrate(p, x_2) == x*DiracDelta(x - x_1)*Heaviside(x_2 - x) + + p = x*y**2*z*DiracDelta(y - x)*DiracDelta(y - z)*DiracDelta(x - z) + assert deltaintegrate(p, y) == x**3*z*DiracDelta(x - z)**2*Heaviside(y - x) + assert deltaintegrate((x + 1)*DiracDelta(2*x), x) == S(1)/2 * Heaviside(x) + assert deltaintegrate((x + 1)*DiracDelta(2*x/3 + 4/S(9)), x) == \ + S(1)/2 * Heaviside(x + S(2)/3) + + a, b, c = symbols('a b c', commutative=False) + assert deltaintegrate(DiracDelta(x - y)*f(x - b)*f(x - a), x) == \ + f(y - b)*f(y - a)*Heaviside(x - y) + + p = f(x - a)*DiracDelta(x - y)*f(x - c)*f(x - b) + assert deltaintegrate(p, x) == f(y - a)*f(y - c)*f(y - b)*Heaviside(x - y) + + p = DiracDelta(x - z)*f(x - b)*f(x - a)*DiracDelta(x - y) + assert deltaintegrate(p, x) == DiracDelta(y - z)*f(y - b)*f(y - a) * \ + Heaviside(x - y) diff -Nru python3-sympy-0.7.2/sympy/integrals/tests/test_failing_integrals.py python3-sympy-0.7.3/sympy/integrals/tests/test_failing_integrals.py --- python3-sympy-0.7.2/sympy/integrals/tests/test_failing_integrals.py 1970-01-01 00:00:00.000000000 +0000 +++ python3-sympy-0.7.3/sympy/integrals/tests/test_failing_integrals.py 2013-07-13 17:53:32.000000000 +0000 @@ -0,0 +1,162 @@ +# A collection of failing integrals from the issues. + + + +from sympy import ( + integrate, Integral, exp, I, oo, pi, sign, sqrt, Rational, Symbol, sin, cos, + tan, S, log, Function, gamma, sinh, +) + +from sympy.utilities.pytest import XFAIL, skip, slow + +from sympy.abc import x, k, c, y, R, b, h, a, m, A, z, t + +import signal + + +class TimeOutError(Exception): + pass + + +def timeout(signum, frame, time): + raise TimeOutError("Timed out after %d seconds" % time) + + +def run_with_timeout(test, time): + # Set the signal handler and a 5-second alarm + signal.signal(signal.SIGALRM, lambda s, f: timeout(s, f, time)) + signal.alarm(time) + r = eval(test) + signal.alarm(0) # Disable the alarm + return r + + +@XFAIL +@slow +def test_issue_781(): + # integrate_hyperexponential(Poly(t*2*(1 - t0**2)*t0*(x**3 + x**2), t), Poly((1 + t0**2)**2*2*(x**2 + x + 1), t), [Poly(1, x), Poly(1 + t0**2, t0), Poly(t, t)], [x, t0, t], [exp, tan]) + assert not integrate(exp(x)*cos(2*x)*sin(2*x) * (x**3 + x**2)/(2*(x**2 + x + 1)), x).has(Integral) + + +@XFAIL +def test_issue_1113(): + assert not integrate(sign(x), x).has(Integral) + + +@XFAIL +def test_issue_1135(): + assert not integrate(1/sqrt(1 + tan(x)**2)).has(Integral) + + +@XFAIL +def test_issue_1227(): + assert integrate(((h*(x - R + b))/b)*sqrt(R**2 - x**2), (x, R - b, R)).has(Integral) + + +@XFAIL +def test_issue_1392(): + assert not integrate(x*sqrt(x**2 + 2*x + 4), x).has(Integral) + + +@XFAIL +def test_issue_1393(): + assert not integrate(x**2 * sqrt(5 - x**2), x).has(Integral) + + +@XFAIL +@slow +def test_issue_1412(): + # This works, but gives a complicated answer. The correct answer is x - cos(x). + # The last one is what Maple gives. It is also quite slow. + assert integrate(cos(x)**2 / (1 - sin(x))) in [x - cos(x), 1 - cos(x) + x, + -2/(tan((S(1)/2)*x)**2 + 1) + x] + + +@XFAIL +def test_issue_1415(): + # The correct answer is 2*sin(x) + assert not integrate(sin(2*x)/ sin(x)).has(Integral) + + +@XFAIL +def test_issue_1426(): + # Warning: takes a long time + assert not integrate((x**m * (1 - x)**n * (a + b*x + c*x**2))/(1 + x**2), (x, 0, 1)).has(Integral) + + +@XFAIL +@slow +def test_issue_1441(): + # Note, this integral is probably nonelementary + assert not integrate( + (sin(1/x) - x*exp(x)) / + ((-sin(1/x) + x*exp(x))*x + x*sin(1/x)), x).has(Integral) + + +@XFAIL +def test_issue_1452(): + assert integrate(1/(x*sqrt(1 - x**2)), x).has(Integral) + + +@XFAIL +def test_issue_1638a(): + # Implementation of Si() + assert integrate(sin(x)/x, x).has(Integral) + + +@XFAIL +def test_issue_1638b(): + assert integrate(sin(x)/x, (x, -oo, oo)) == pi/2 + + +@XFAIL +@slow +def test_issue_1792(): + # Requires the hypergeometric function. + assert not integrate(cos(x)**y, x).has(Integral) + + +@XFAIL +def test_issue_1796a(): + assert not integrate(exp(2*b*x)*exp(-a*x**2), x).has(Integral) + + +@XFAIL +def test_issue_1796b(): + assert not integrate(exp(2*b*x)*exp(-a*x**2), (x, -oo, 0)).has(Integral) + + +@XFAIL +def test_issue_1796c(): + assert not integrate(exp(2*b*x)*exp(-a*x**2), (x, -oo, oo)).has(Integral) + + +@XFAIL +def test_issue_1796d(): + assert not integrate(exp(2*b*x)*exp(-a*x**2), (x, 0, oo)).has(Integral) + + +@XFAIL +@slow +def test_issue_1842(): + assert not integrate(sqrt(1 + sinh(x/20)**2), (x, -25, 25)).has(Integral) + + +@XFAIL +@slow +def test_issue_1851(): + # Problem is with exception + assert not integrate((-60*exp(x) - 19.2*exp(4*x))*exp(4*x), x).has(Integral) + + +@XFAIL +@slow +def test_issue_1869(): + assert not integrate(sin(log(x**2))).has(Integral) + + +@XFAIL +@slow +def test_issue_1893(): + # Nonelementary integral. Requires hypergeometric/Meijer-G handling. + assert not integrate(log(x) * x**(k - 1) * exp(-x) / gamma(k), (x, 0, oo)).has(Integral) diff -Nru python3-sympy-0.7.2/sympy/integrals/tests/test_heurisch.py python3-sympy-0.7.3/sympy/integrals/tests/test_heurisch.py --- python3-sympy-0.7.2/sympy/integrals/tests/test_heurisch.py 1970-01-01 00:00:00.000000000 +0000 +++ python3-sympy-0.7.3/sympy/integrals/tests/test_heurisch.py 2013-07-13 17:53:32.000000000 +0000 @@ -0,0 +1,264 @@ +from sympy import Rational, sqrt, symbols, sin, exp, log, sinh, cosh, cos, pi, \ + I, S, erf, tan, asin, asinh, acos, acosh, Function, Derivative, diff, simplify, \ + LambertW, Eq, Piecewise, Symbol +from sympy.integrals.heurisch import components, heurisch, heurisch_wrapper +from sympy.utilities.pytest import XFAIL, skip, slow + +x, y, z = symbols('x,y,z') +f = Function('f') + + +def test_components(): + assert components(x*y, x) == set([x]) + assert components(1/(x + y), x) == set([x]) + assert components(sin(x), x) == set([sin(x), x]) + assert components(sin(x)*sqrt(log(x)), x) == \ + set([log(x), sin(x), sqrt(log(x)), x]) + assert components(x*sin(exp(x)*y), x) == \ + set([sin(y*exp(x)), x, exp(x)]) + assert components(x**Rational(17, 54)/sqrt(sin(x)), x) == \ + set([sin(x), x**Rational(1, 54), sqrt(sin(x)), x]) + + assert components(f(x), x) == \ + set([x, f(x)]) + assert components(Derivative(f(x), x), x) == \ + set([x, f(x), Derivative(f(x), x)]) + assert components(f(x)*diff(f(x), x), x) == \ + set([x, f(x), Derivative(f(x), x), Derivative(f(x), x)]) + + +def test_heurisch_polynomials(): + assert heurisch(1, x) == x + assert heurisch(x, x) == x**2/2 + assert heurisch(x**17, x) == x**18/18 + + +def test_heurisch_fractions(): + assert heurisch(1/x, x) == log(x) + assert heurisch(1/(2 + x), x) == log(x + 2) + assert heurisch(1/(x + sin(y)), x) == log(x + sin(y)) + + # Up to a constant, where C = 5*pi*I/12, Mathematica gives identical + # result in the first case. The difference is because sympy changes + # signs of expressions without any care. + # XXX ^ ^ ^ is this still correct? + assert heurisch(5*x**5/( + 2*x**6 - 5), x) in [5*log(2*x**6 - 5) / 12, 5*log(-2*x**6 + 5) / 12] + assert heurisch(5*x**5/(2*x**6 + 5), x) == 5*log(2*x**6 + 5) / 12 + + assert heurisch(1/x**2, x) == -1/x + assert heurisch(-1/x**5, x) == 1/(4*x**4) + + +def test_heurisch_log(): + assert heurisch(log(x), x) == x*log(x) - x + assert heurisch(log(3*x), x) == -x + x*log(3) + x*log(x) + assert heurisch(log(x**2), x) in [x*log(x**2) - 2*x, 2*x*log(x) - 2*x] + + +def test_heurisch_exp(): + assert heurisch(exp(x), x) == exp(x) + assert heurisch(exp(-x), x) == -exp(-x) + assert heurisch(exp(17*x), x) == exp(17*x) / 17 + assert heurisch(x*exp(x), x) == x*exp(x) - exp(x) + assert heurisch(x*exp(x**2), x) == exp(x**2) / 2 + + assert heurisch(exp(-x**2), x) is None + + assert heurisch(2**x, x) == 2**x/log(2) + assert heurisch(x*2**x, x) == x*2**x/log(2) - 2**x*log(2)**(-2) + + +def test_heurisch_trigonometric(): + assert heurisch(sin(x), x) == -cos(x) + assert heurisch(pi*sin(x) + 1, x) == x - pi*cos(x) + + assert heurisch(cos(x), x) == sin(x) + assert heurisch(tan(x), x) in [ + log(1 + tan(x)**2)/2, + log(tan(x) + I) + I*x, + log(tan(x) - I) - I*x, + ] + + assert heurisch(sin(x)*sin(y), x) == -cos(x)*sin(y) + assert heurisch(sin(x)*sin(y), y) == -cos(y)*sin(x) + + # gives sin(x) in answer when run via setup.py and cos(x) when run via py.test + assert heurisch(sin(x)*cos(x), x) in [sin(x)**2 / 2, -cos(x)**2 / 2] + assert heurisch(cos(x)/sin(x), x) == log(sin(x)) + + assert heurisch(x*sin(7*x), x) == sin(7*x) / 49 - x*cos(7*x) / 7 + assert heurisch(1/pi/4 * x**2*cos(x), x) == 1/pi/4*(x**2*sin(x) - + 2*sin(x) + 2*x*cos(x)) + + assert heurisch(acos(x/4) * asin(x/4), x) == 2*x - (sqrt(16 - x**2))*asin(x/4) \ + + (sqrt(16 - x**2))*acos(x/4) + x*asin(x/4)*acos(x/4) + + +def test_heurisch_hyperbolic(): + assert heurisch(sinh(x), x) == cosh(x) + assert heurisch(cosh(x), x) == sinh(x) + + assert heurisch(x*sinh(x), x) == x*cosh(x) - sinh(x) + assert heurisch(x*cosh(x), x) == x*sinh(x) - cosh(x) + + assert heurisch( + x*asinh(x/2), x) == x**2*asinh(x/2)/2 + asinh(x/2) - x*sqrt(4 + x**2)/4 + + +def test_heurisch_mixed(): + assert heurisch(sin(x)*exp(x), x) == exp(x)*sin(x)/2 - exp(x)*cos(x)/2 + + +def test_heurisch_radicals(): + assert heurisch(1/sqrt(x), x) == 2*sqrt(x) + assert heurisch(1/sqrt(x)**3, x) == -2/sqrt(x) + assert heurisch(sqrt(x)**3, x) == 2*sqrt(x)**5/5 + + assert heurisch(sin(x)*sqrt(cos(x)), x) == -2*sqrt(cos(x))**3/3 + y = Symbol('y') + assert heurisch(sin(y*sqrt(x)), x) == 2/y**2*sin(y*sqrt(x)) - \ + 2*sqrt(x)*cos(y*sqrt(x))/y + assert heurisch_wrapper(sin(y*sqrt(x)), x) == Piecewise( + (0, Eq(y, 0)), + (-2*sqrt(x)*cos(sqrt(x)*y)/y + 2*sin(sqrt(x)*y)/y**2, True)) + y = Symbol('y', positive=True) + assert heurisch_wrapper(sin(y*sqrt(x)), x) == 2/y**2*sin(y*sqrt(x)) - \ + 2*sqrt(x)*cos(y*sqrt(x))/y + + +def test_heurisch_special(): + assert heurisch(erf(x), x) == x*erf(x) + exp(-x**2)/sqrt(pi) + assert heurisch(exp(-x**2)*erf(x), x) == sqrt(pi)*erf(x)**2 / 4 + + +def test_heurisch_symbolic_coeffs(): + assert heurisch(1/(x + y), x) == log(x + y) + assert heurisch(1/(x + sqrt(2)), x) == log(x + sqrt(2)) + assert simplify(diff(heurisch(log(x + y + z), y), y)) == log(x + y + z) + + +def test_heurisch_symbolic_coeffs_1130(): + y = Symbol('y') + assert heurisch_wrapper(1/(x**2 + y), x) == Piecewise( + (-1/x, Eq(y, 0)), + (-I*log(x - I*sqrt(y))/(2*sqrt(y)) + I*log(x + I*sqrt(y))/(2*sqrt(y)), True)) + y = Symbol('y', positive=True) + assert heurisch_wrapper(1/(x**2 + y), x) in [I/sqrt(y)*log(x + sqrt(-y))/2 - + I/sqrt(y)*log(x - sqrt(-y))/2, I*log(x + I*sqrt(y)) / + (2*sqrt(y)) - I*log(x - I*sqrt(y))/(2*sqrt(y))] + + +def test_heurisch_hacking(): + assert heurisch(sqrt(1 + 7*x**2), x, hints=[]) == \ + x*sqrt(1 + 7*x**2)/2 + sqrt(7)*asinh(sqrt(7)*x)/14 + assert heurisch(sqrt(1 - 7*x**2), x, hints=[]) == \ + x*sqrt(1 - 7*x**2)/2 + sqrt(7)*asin(sqrt(7)*x)/14 + + assert heurisch(1/sqrt(1 + 7*x**2), x, hints=[]) == \ + sqrt(7)*asinh(sqrt(7)*x)/7 + assert heurisch(1/sqrt(1 - 7*x**2), x, hints=[]) == \ + sqrt(7)*asin(sqrt(7)*x)/7 + + assert heurisch(exp(-7*x**2), x, hints=[]) == \ + sqrt(7*pi)*erf(sqrt(7)*x)/14 + + assert heurisch(1/sqrt(9 - 4*x**2), x, hints=[]) == \ + asin(2*x/3)/2 + + assert heurisch(1/sqrt(9 + 4*x**2), x, hints=[]) == \ + asinh(2*x/3)/2 + + +def test_heurisch_function(): + df = diff(f(x), x) + + assert heurisch(f(x), x) is None + assert heurisch(f(x)*df, x) == f(x)**2/2 + assert heurisch(f(x)**2 * df, x) == f(x)**3/3 + assert heurisch(df / f(x), x) == log(f(x)) + + +def test_heurisch_wrapper(): + f = 1/(y + x) + assert heurisch_wrapper(f, x) == log(x + y) + f = 1/(y - x) + assert heurisch_wrapper(f, x) == -log(x - y) + f = 1/((y - x)*(y + x)) + assert heurisch_wrapper(f, x) == \ + Piecewise((1/x, Eq(y, 0)), (log(x + y)/2/y - log(x - y)/2/y, True)) + # issue 3827 + f = sqrt(x**2/((y - x)*(y + x))) + assert heurisch_wrapper(f, x) == x*sqrt(x**2)*sqrt(1/(-x**2 + y**2)) \ + - y**2*sqrt(x**2)*sqrt(1/(-x**2 + y**2))/x + + +def test_issue510(): + assert heurisch(1/(x * (1 + log(x)**2)), x) == I*log(log(x) + I)/2 - \ + I*log(log(x) - I)/2 + +### These are examples from the Poor Man's Integrator +### http://www-sop.inria.fr/cafe/Manuel.Bronstein/pmint/examples/ +# +# NB: correctness assured as ratsimp(diff(g,x) - f) == 0 in maxima +# SymPy is unable to do it :( + +# Besides, they are skipped(), because they take too much time to execute. + + +@XFAIL +def test_pmint_rat(): + f = (x**7 - 24*x**4 - 4*x**2 + 8*x - 8) / (x**8 + 6*x**6 + 12*x**4 + 8*x**2) + g = (4 + 8*x**2 + 6*x + 3*x**3) / (x*(x**4 + 4*x**2 + 4)) + log(x) + + assert heurisch(f, x) == g + + +@XFAIL +def test_pmint_trig(): + f = (x - tan(x)) / tan(x)**2 + tan(x) + g = (-x - tan(x)*x**2 / 2) / tan(x) + log(1 + tan(x)**2) / 2 + + assert heurisch(f, x) == g + + +@slow +@XFAIL +def test_pmint_logexp(): + f = (1 + x + x*exp(x))*(x + log(x) + exp(x) - 1)/(x + log(x) + exp(x))**2/x + g = 1/(x + log(x) + exp(x)) + log(x + log(x) + exp(x)) + + assert heurisch(f, x) == g + + +@slow +@XFAIL +def test_pmint_erf(): + f = exp(-x**2)*erf(x)/(erf(x)**3 - erf(x)**2 - erf(x) + 1) + g = sqrt(pi)/4 * (-1/(erf(x) - 1) - log(erf(x) + 1)/2 + log(erf(x) - 1)/2) + + assert heurisch(f, x) == g + + +def test_pmint_lambertw(): + g = (x**2 + (LambertW(x)*x)**2 - LambertW(x)*x**2)/(x*LambertW(x)) + assert simplify(heurisch(LambertW(x), x) - g) == 0 + +# TODO: convert the rest of PMINT tests: +# Airy functions +# f = (x - AiryAi(x)*AiryAi(1, x)) / (x**2 - AiryAi(x)**2) +# g = Rational(1,2)*ln(x + AiryAi(x)) + Rational(1,2)*ln(x - AiryAi(x)) +# f = x**2 * AiryAi(x) +# g = -AiryAi(x) + AiryAi(1, x)*x + +# Bessel functions +# f = BesselJ(nu + 1, x) / BesselJ(nu, x) +# g = nu*ln(x) - ln(BesselJ(nu, x)) +# f = (nu * BesselJ(nu, x) / x) - BesselJ(nu + 1, x) +# g = BesselJ(nu, x) + +# Whittaker functions +# f = WhittakerW(mu + 1, nu, x) / (WhittakerW(mu, nu, x) * x) +# g = x/2 - mu*ln(x) - ln(WhittakerW(mu, nu, x)) + +# - Wright omega diff -Nru python3-sympy-0.7.2/sympy/integrals/tests/test_integrals.py python3-sympy-0.7.3/sympy/integrals/tests/test_integrals.py --- python3-sympy-0.7.2/sympy/integrals/tests/test_integrals.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/integrals/tests/test_integrals.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,15 +1,20 @@ -from sympy import (S, symbols, integrate, Integral, Derivative, exp, erf, oo, Symbol, - Function, Rational, log, sin, cos, pi, E, I, Poly, LambertW, diff, Matrix, - sympify, sqrt, atan, asin, acos, asinh, acosh, DiracDelta, Heaviside, - Lambda, sstr, Add, Tuple, Interval, Sum, factor, trigsimp, simplify, O, - terms_gcd, EulerGamma, Ci) -from sympy.utilities.pytest import XFAIL, raises -from sympy.physics.units import m, s +from sympy import ( + Abs, acos, acosh, Add, adjoint, asin, asinh, atan, Ci, conjugate, cos, + Derivative, diff, DiracDelta, E, exp, erf, erfi, EulerGamma, factor, Function, + Heaviside, I, Integral, integrate, Interval, Lambda, LambertW, log, + Matrix, O, oo, pi, Piecewise, Poly, Rational, S, simplify, sin, sqrt, + sstr, Sum, Symbol, symbols, sympify, terms_gcd, transpose, trigsimp, + Tuple, nan, And, Eq, Or +) +from sympy.integrals.risch import NonElementaryIntegral +from sympy.utilities.pytest import XFAIL, raises, slow +from sympy.physics import units -x,y,a,t,x_1,x_2,z = symbols('x,y,a,t,x_1,x_2,z') +x, y, a, t, x_1, x_2, z = symbols('x y a t x_1 x_2 z') n = Symbol('n', integer=True) f = Function('f') + def diff_test(i): """Return the set of symbols, s, which were used in testing that i.diff(s) agrees with i.doit().diff(s). If there is an error then @@ -19,10 +24,12 @@ assert (i.diff(s).doit() - i.doit().diff(s)).expand() == 0 return syms + def test_improper_integral(): assert integrate(log(x), (x, 0, 1)) == -1 assert integrate(x**(-2), (x, 1, oo)) == 1 + def test_constructor(): # this is shared by Sum, so testing Integral's constructor # is equivalent to testing Sum's @@ -38,6 +45,7 @@ s5 = Integral(n, (n, Interval(1, 2))) assert s5.limits == (Tuple(n, 1, 2),) + def test_basics(): assert Integral(0, x) != 0 @@ -45,27 +53,27 @@ assert Integral(oo, x) != oo assert Integral(S.NaN, x) == S.NaN - assert diff(Integral(y, y), x) == 0 - assert diff(Integral(x, (x,0,1)), x) == 0 - assert diff(Integral(x, x), x) == x - assert diff(Integral(t, (t,0,x)), x) == x + Integral(0, (t, 0, x)) - - e=(t+1)**2 - assert diff(integrate(e, (t,0,x)), x) == \ - diff(Integral(e, (t, 0, x)), x).doit().expand() == \ - ((1+x)**2).expand() - assert diff(integrate(e, (t,0,x)), t) == \ - diff(Integral(e, (t,0,x)), t) == 0 - assert diff(integrate(e, (t,0,x)), a) == \ - diff(Integral(e, (t, 0, x)), a) == 0 + assert diff(Integral(y, y), x) == 0 + assert diff(Integral(x, (x, 0, 1)), x) == 0 + assert diff(Integral(x, x), x) == x + assert diff(Integral(t, (t, 0, x)), x) == x + Integral(0, (t, 0, x)) + + e = (t + 1)**2 + assert diff(integrate(e, (t, 0, x)), x) == \ + diff(Integral(e, (t, 0, x)), x).doit().expand() == \ + ((1 + x)**2).expand() + assert diff(integrate(e, (t, 0, x)), t) == \ + diff(Integral(e, (t, 0, x)), t) == 0 + assert diff(integrate(e, (t, 0, x)), a) == \ + diff(Integral(e, (t, 0, x)), a) == 0 assert diff(integrate(e, t), a) == diff(Integral(e, t), a) == 0 - assert integrate(e, (t,a,x)).diff(x) == \ - Integral(e, (t, a, x)).diff(x).doit().expand() - assert Integral(e, (t, a, x)).diff(x).doit() == ((1+x)**2) - assert integrate(e, (t,x,a)).diff(x).doit() == (-(1+x)**2).expand() + assert integrate(e, (t, a, x)).diff(x) == \ + Integral(e, (t, a, x)).diff(x).doit().expand() + assert Integral(e, (t, a, x)).diff(x).doit() == ((1 + x)**2) + assert integrate(e, (t, x, a)).diff(x).doit() == (-(1 + x)**2).expand() - assert integrate(t**2, (t,x,2*x)).diff(x) == 7*x**2 + assert integrate(t**2, (t, x, 2*x)).diff(x) == 7*x**2 assert Integral(x, x).atoms() == set([x]) assert Integral(f(x), (x, 0, 1)).atoms() == set([S(0), S(1), x]) @@ -80,6 +88,7 @@ n = Symbol('n', commutative=False) assert Integral(n + x, x).is_commutative is False + def test_basics_multiple(): assert diff_test(Integral(x, (x, 3*x, 5*y), (y, x, 2*x))) == set([x]) @@ -90,45 +99,67 @@ assert diff_test(Integral(x + y, y, (y, 1, x))) == set([x]) assert diff_test(Integral(x + y, (x, x, y), (y, y, x))) == set([x, y]) + +def test_conjugate_transpose(): + A, B = symbols("A B", commutative=False) + + x = Symbol("x", complex=True) + p = Integral(A*B, (x,)) + assert p.adjoint().doit() == p.doit().adjoint() + assert p.conjugate().doit() == p.doit().conjugate() + assert p.transpose().doit() == p.doit().transpose() + + x = Symbol("x", real=True) + p = Integral(A*B, (x,)) + assert p.adjoint().doit() == p.doit().adjoint() + assert p.conjugate().doit() == p.doit().conjugate() + assert p.transpose().doit() == p.doit().transpose() + + def test_integration(): - assert integrate(0, (t,0,x)) == 0 - assert integrate(3, (t,0,x)) == 3*x - assert integrate(t, (t,0,x)) == x**2/2 - assert integrate(3*t, (t,0,x))== 3*x**2/2 - assert integrate(3*t**2, (t,0,x)) == x**3 - assert integrate(1/t, (t,1,x)) == log(x) - assert integrate(-1/t**2, (t,1,x)) == 1/x-1 - assert integrate(t**2+5*t-8, (t,0,x)) == x**3/3+5*x**2/2-8*x + assert integrate(0, (t, 0, x)) == 0 + assert integrate(3, (t, 0, x)) == 3*x + assert integrate(t, (t, 0, x)) == x**2/2 + assert integrate(3*t, (t, 0, x)) == 3*x**2/2 + assert integrate(3*t**2, (t, 0, x)) == x**3 + assert integrate(1/t, (t, 1, x)) == log(x) + assert integrate(-1/t**2, (t, 1, x)) == 1/x - 1 + assert integrate(t**2 + 5*t - 8, (t, 0, x)) == x**3/3 + 5*x**2/2 - 8*x assert integrate(x**2, x) == x**3/3 assert integrate((3*t*x)**5, x) == (3*t)**5 * x**6 / 6 b = Symbol("b") c = Symbol("c") - assert integrate(a*t, (t,0,x))==a*x**2/2 - assert integrate(a*t**4, (t,0,x))==a*x**5/5 - assert integrate(a*t**2+b*t+c, (t,0,x))==a*x**3/3+b*x**2/2+c*x + assert integrate(a*t, (t, 0, x)) == a*x**2/2 + assert integrate(a*t**4, (t, 0, x)) == a*x**5/5 + assert integrate(a*t**2 + b*t + c, (t, 0, x)) == a*x**3/3 + b*x**2/2 + c*x + def test_multiple_integration(): - assert integrate((x**2)*(y**2), (x,0,1), (y,-1,2)) == Rational(1) - assert integrate((y**2)*(x**2), x, y) == Rational(1,9)*(x**3)*(y**3) - assert integrate(1/(x+3)/(1+x)**3, x) == -S(1)/8*log(3 + x) + S(1)/8*log(1 + x) + x/(4 + 8*x + 4*x**2) + assert integrate((x**2)*(y**2), (x, 0, 1), (y, -1, 2)) == Rational(1) + assert integrate((y**2)*(x**2), x, y) == Rational(1, 9)*(x**3)*(y**3) + assert integrate(1/(x + 3)/(1 + x)**3, x) == \ + -S(1)/8*log(3 + x) + S(1)/8*log(1 + x) + x/(4 + 8*x + 4*x**2) + def test_issue433(): - assert integrate(exp(-x), (x,0,oo)) == 1 + assert integrate(exp(-x), (x, 0, oo)) == 1 + def test_issue461(): assert integrate(sqrt(x)**3, x) == 2*sqrt(x)**5/5 assert integrate(sqrt(x), x) == 2*sqrt(x)**3/3 assert integrate(1/sqrt(x)**3, x) == -2/sqrt(x) + def test_integrate_poly(): p = Poly(x + x**2*y + y**3, x, y) qx = integrate(p, x) qy = integrate(p, y) - assert isinstance(qx, Poly) == True - assert isinstance(qy, Poly) == True + assert isinstance(qx, Poly) is True + assert isinstance(qy, Poly) is True assert qx.gens == (x, y) assert qy.gens == (x, y) @@ -136,21 +167,23 @@ assert qx.as_expr() == x**2/2 + x**3*y/3 + x*y**3 assert qy.as_expr() == x*y + x**2*y**2/2 + y**4/4 + def test_integrate_poly_defined(): p = Poly(x + x**2*y + y**3, x, y) Qx = integrate(p, (x, 0, 1)) Qy = integrate(p, (y, 0, pi)) - assert isinstance(Qx, Poly) == True - assert isinstance(Qy, Poly) == True + assert isinstance(Qx, Poly) is True + assert isinstance(Qy, Poly) is True assert Qx.gens == (y,) assert Qy.gens == (x,) - assert Qx.as_expr() == Rational(1,2) + y/3 + y**3 + assert Qx.as_expr() == Rational(1, 2) + y/3 + y**3 assert Qy.as_expr() == pi**4/4 + pi*x + pi**2*x**2/2 + def test_integrate_omit_var(): y = Symbol('y') @@ -159,93 +192,121 @@ raises(ValueError, lambda: integrate(2)) raises(ValueError, lambda: integrate(x*y)) + def test_integrate_poly_accurately(): y = Symbol('y') - assert integrate(x*sin(y), x) == x**2*sin(y)/2 + assert integrate(x*sin(y), x) == x**2*sin(y)/2 # when passed to risch_norman, this will be a CPU hog, so this really # checks, that integrated function is recognized as polynomial assert integrate(x**1000*sin(y), x) == x**1001*sin(y)/1001 + def test_issue536(): y = Symbol('y') assert integrate(x**2, y) == x**2*y assert integrate(x**2, (y, -1, 1)) == 2*x**2 # works in sympy and py.test but hangs in `setup.py test` + + def test_integrate_linearterm_pow(): # check integrate((a*x+b)^c, x) -- #400 - y = Symbol('y') - assert integrate(x**y, x) == x**(y+1)/(y+1) - assert integrate((exp(y)*x + 1/y)**(1+sin(y)), x) == exp(-y)*(exp(y)*x + 1/y)**(2+sin(y)) / (2+sin(y)) + y = Symbol('y', positive=True) + # TODO: Remove conds='none' below, let the assumption take care of it. + assert integrate(x**y, x, conds='none') == x**(y + 1)/(y + 1) + assert integrate((exp(y)*x + 1/y)**(1 + sin(y)), x, conds='none') == \ + exp(-y)*(exp(y)*x + 1/y)**(2 + sin(y)) / (2 + sin(y)) + def test_issue519(): - assert integrate(pi*sqrt(x),x) == 2*pi*sqrt(x)**3/3 - assert integrate(pi*sqrt(x) + E*sqrt(x)**3,x) == \ - 2*pi*sqrt(x)**3/3 + \ - 2*E *sqrt(x)**5/5 + assert integrate(pi*sqrt(x), x) == 2*pi*sqrt(x)**3/3 + assert integrate(pi*sqrt(x) + E*sqrt(x)**3, x) == \ + 2*pi*sqrt(x)**3/3 + 2*E *sqrt(x)**5/5 + + def test_issue524(): - assert integrate(cos((n+1) * x), x) == sin(x*(n+1)) / (n+1) - assert integrate(cos((n-1) * x), x) == sin(x*(n-1)) / (n-1) + assert integrate(cos((n + 1)*x), x) == Piecewise( + (x, Eq(n + 1, 0)), (sin((n + 1)*x)/(n + 1), True)) + assert integrate(cos((n - 1)*x), x) == Piecewise( + (x, Eq(n - 1, 0)), (sin((n - 1)*x)/(n - 1), True)) + assert integrate(cos((n + 1)*x) + cos((n - 1)*x), x) == \ + Piecewise((x, Eq(n + 1, 0)), (sin((n + 1)*x)/(n + 1), True)) + \ + Piecewise((x, Eq(n - 1, 0)), (sin((n - 1)*x)/(n - 1), True)) - assert integrate(cos((n+1) * x) + cos((n-1) * x), x) == \ - sin(x*(n+1)) / (n+1) + \ - sin(x*(n-1)) / (n-1) def test_issue565(): - assert integrate(-1./2 * x * sin(n * pi * x/2), [x, -2, 0]) == 2*cos(pi*n)/(pi*n) - assert integrate(-Rational(1)/2 * x * sin(n * pi * x/2), [x, -2, 0]) \ - == 2*cos(pi*n)/(pi*n) + n = Symbol('n', integer=True, nonzero=True) + assert integrate(-1./2 * x * sin(n * pi * x/2), [x, -2, 0]) == \ + 2*cos(pi*n)/(pi*n) + assert integrate(-Rational(1)/2 * x * sin(n * pi * x/2), [x, -2, 0]) == \ + 2*cos(pi*n)/(pi*n) + + def test_issue580(): # definite integration of rational functions gives wrong answers - assert NS(Integral(1/(x**2-8*x+17), (x, 2, 4))) == '1.10714871779409' + assert NS(Integral(1/(x**2 - 8*x + 17), (x, 2, 4))) == '1.10714871779409' -def test_issue587(): # remove this when fresnel itegrals are implemented + +def test_issue587(): # remove this when fresnel itegrals are implemented from sympy import expand_func, fresnels assert expand_func(integrate(sin(x**2), x)) == \ - sqrt(2)*sqrt(pi)*fresnels(sqrt(2)*x/sqrt(pi))/2 + sqrt(2)*sqrt(pi)*fresnels(sqrt(2)*x/sqrt(pi))/2 def test_integrate_units(): + m = units.m + s = units.s assert integrate(x * m/s, (x, 1*s, 5*s)) == 12*m*s + def test_transcendental_functions(): - assert integrate(LambertW(2*x), x) == -x + x*LambertW(2*x) + x/LambertW(2*x) + assert integrate(LambertW(2*x), x) == \ + -x + x*LambertW(2*x) + x/LambertW(2*x) + def test_issue641(): - f=4*log(x)-2*log(x)**2 - fid=diff(integrate(f,x),x) - assert abs(f.subs(x,42).evalf() - fid.subs(x,42).evalf()) < 1e-10 + f = 4*log(x) - 2*log(x)**2 + fid = diff(integrate(f, x), x) + assert abs(f.subs(x, 42).evalf() - fid.subs(x, 42).evalf()) < 1e-10 + def test_issue689(): - assert integrate(1/(1+x**2), x) == atan(x) + assert integrate(1/(1 + x**2), x) == atan(x) + def test_issue853(): f = sin(x) assert integrate(f, x) == -cos(x) raises(ValueError, lambda: integrate(f, 2*x)) + def test_issue1417(): assert integrate(2**x - 2*x, x) == 2**x/log(2) - x**2 + def test_matrices(): - M = Matrix(2, 2, lambda i, j: (i+j+1)*sin((i+j+1)*x)) + M = Matrix(2, 2, lambda i, j: (i + j + 1)*sin((i + j + 1)*x)) assert integrate(M, x) == Matrix([ - [-cos(x), -cos(2*x)], + [-cos(x), -cos(2*x)], [-cos(2*x), -cos(3*x)], ]) # issue1012 + + def test_integrate_functions(): - assert integrate(f(x), x) == Integral(f(x), x) - assert integrate(f(x), (x,0,1)) == Integral(f(x), (x,0,1)) + assert integrate(f(x), x) == Integral(f(x), x) + assert integrate(f(x), (x, 0, 1)) == Integral(f(x), (x, 0, 1)) assert integrate(f(x)*diff(f(x), x), x) == f(x)**2/2 - assert integrate(diff(f(x),x) / f(x),x) == log(f(x)) + assert integrate(diff(f(x), x) / f(x), x) == log(f(x)) + def test_integrate_derivatives(): assert integrate(Derivative(f(x), x), x) == f(x) assert integrate(Derivative(f(y), y), x) == x*Derivative(f(y), y) + def test_transform(): a = Integral(x**2 + 1, (x, -1, 2)) fx = x @@ -261,12 +322,14 @@ a = Integral(exp(-x**2), (x, -oo, oo)) assert a.transform(x, 2*y) == Integral(2*exp(-4*y**2), (y, -oo, oo)) # < 3 arg limit handled properly - assert Integral(x, x).transform(x, a*y).doit() == Integral(y*a**2, y).doit() + assert Integral(x, x).transform(x, a*y).doit() == \ + Integral(y*a**2, y).doit() _3 = S(3) assert Integral(x, (x, 0, -_3)).transform(x, 1/y).doit() == \ - Integral(-1/x**3, (x, -oo, -1/_3)).doit() + Integral(-1/x**3, (x, -oo, -1/_3)).doit() assert Integral(x, (x, 0, _3)).transform(x, 1/y) == \ - Integral(y**(-3), (y, 1/_3, oo)) + Integral(y**(-3), (y, 1/_3, oo)) + def test_issue953(): f = S(1)/2*asin(x) + x*sqrt(1 - x**2)/2 @@ -274,44 +337,61 @@ assert integrate(cos(asin(x)), x) == f assert integrate(sin(acos(x)), x) == f + def NS(e, n=15, **options): return sstr(sympify(e).evalf(n, **options), full_prec=True) + def test_evalf_integrals(): assert NS(Integral(x, (x, 2, 5)), 15) == '10.5000000000000' gauss = Integral(exp(-x**2), (x, -oo, oo)) assert NS(gauss, 15) == '1.77245385090552' - assert NS(gauss**2 - pi + E*Rational(1,10**20), 15) in ('2.71828182845904e-20', '2.71828182845905e-20') + assert NS(gauss**2 - pi + E*Rational( + 1, 10**20), 15) in ('2.71828182845904e-20', '2.71828182845905e-20') # A monster of an integral from http://mathworld.wolfram.com/DefiniteIntegral.html t = Symbol('t') - a = 8*sqrt(3)/(1+3*t**2) - b = 16*sqrt(2)*(3*t+1)*sqrt(4*t**2+t+1)**3 - c = (3*t**2+1)*(11*t**2+2*t+3)**2 - d = sqrt(2)*(249*t**2+54*t+65)/(11*t**2+2*t+3)**2 + a = 8*sqrt(3)/(1 + 3*t**2) + b = 16*sqrt(2)*(3*t + 1)*sqrt(4*t**2 + t + 1)**3 + c = (3*t**2 + 1)*(11*t**2 + 2*t + 3)**2 + d = sqrt(2)*(249*t**2 + 54*t + 65)/(11*t**2 + 2*t + 3)**2 f = a - b/c - d - assert NS(Integral(f, (t, 0, 1)), 50) == NS((3*sqrt(2)-49*pi+162*atan(sqrt(2)))/12,50) + assert NS(Integral(f, (t, 0, 1)), 50) == \ + NS((3*sqrt(2) - 49*pi + 162*atan(sqrt(2)))/12, 50) # http://mathworld.wolfram.com/VardisIntegral.html - assert NS(Integral(log(log(1/x))/(1+x+x**2), (x, 0, 1)), 15) == NS('pi/sqrt(3) * log(2*pi**(5/6) / gamma(1/6))', 15) + assert NS(Integral(log(log(1/x))/(1 + x + x**2), (x, 0, 1)), 15) == \ + NS('pi/sqrt(3) * log(2*pi**(5/6) / gamma(1/6))', 15) # http://mathworld.wolfram.com/AhmedsIntegral.html - assert NS(Integral(atan(sqrt(x**2+2))/(sqrt(x**2+2)*(x**2+1)), (x, 0, 1)), 15) == NS(5*pi**2/96, 15) + assert NS(Integral(atan(sqrt(x**2 + 2))/(sqrt(x**2 + 2)*(x**2 + 1)), (x, + 0, 1)), 15) == NS(5*pi**2/96, 15) # http://mathworld.wolfram.com/AbelsIntegral.html - assert NS(Integral(x/((exp(pi*x)-exp(-pi*x))*(x**2+1)), (x, 0, oo)), 15) == NS('log(2)/2-1/4',15) + assert NS(Integral(x/((exp(pi*x) - exp( + -pi*x))*(x**2 + 1)), (x, 0, oo)), 15) == NS('log(2)/2-1/4', 15) # Complex part trimming # http://mathworld.wolfram.com/VardisIntegral.html assert NS(Integral(log(log(sin(x)/cos(x))), (x, pi/4, pi/2)), 15, chop=True) == \ NS('pi/4*log(4*pi**3/gamma(1/4)**4)', 15) # # Endpoints causing trouble (rounding error in integration points -> complex log) - assert NS(2+Integral(log(2*cos(x/2)), (x, -pi, pi)), 17, chop=True) == NS(2, 17) - assert NS(2+Integral(log(2*cos(x/2)), (x, -pi, pi)), 20, chop=True) == NS(2, 20) - assert NS(2+Integral(log(2*cos(x/2)), (x, -pi, pi)), 22, chop=True) == NS(2, 22) + assert NS( + 2 + Integral(log(2*cos(x/2)), (x, -pi, pi)), 17, chop=True) == NS(2, 17) + assert NS( + 2 + Integral(log(2*cos(x/2)), (x, -pi, pi)), 20, chop=True) == NS(2, 20) + assert NS( + 2 + Integral(log(2*cos(x/2)), (x, -pi, pi)), 22, chop=True) == NS(2, 22) # Needs zero handling - assert NS(pi - 4*Integral('sqrt(1-x**2)', (x, 0, 1)), 15, maxn=30, chop=True) in ('0.0', '0') + assert NS(pi - 4*Integral( + 'sqrt(1-x**2)', (x, 0, 1)), 15, maxn=30, chop=True) in ('0.0', '0') # Oscillatory quadrature a = Integral(sin(x)/x**2, (x, 1, oo)).evalf(maxn=15) assert 0.49 < a < 0.51 - assert NS(Integral(sin(x)/x**2, (x, 1, oo)), quad='osc') == '0.504067061906928' - assert NS(Integral(cos(pi*x+1)/x, (x, -oo, -1)), quad='osc') == '0.276374705640365' + assert NS( + Integral(sin(x)/x**2, (x, 1, oo)), quad='osc') == '0.504067061906928' + assert NS(Integral( + cos(pi*x + 1)/x, (x, -oo, -1)), quad='osc') == '0.276374705640365' + # indefinite integrals aren't evaluated + assert NS(Integral(x, x)) == 'Integral(x, x)' + assert NS(Integral(x, (x, y))) == 'Integral(x, (x, y))' + @XFAIL def test_evalf_issue_939(): @@ -321,78 +401,107 @@ # revisions, making this test a bit useless. This can't be said about # other two tests. For now, all values of this evaluation are used here, # but in future this should be reconsidered. - assert NS(integrate(1/(x**5+1), x).subs(x, 4), chop=True) in \ + assert NS(integrate(1/(x**5 + 1), x).subs(x, 4), chop=True) in \ ['-0.000976138910649103', '0.965906660135753', '1.93278945918216'] - assert NS(Integral(1/(x**5+1), (x, 2, 4))) == '0.0144361088886740' - assert NS(integrate(1/(x**5+1), (x, 2, 4)), chop=True) == '0.0144361088886740' + assert NS(Integral(1/(x**5 + 1), (x, 2, 4))) == '0.0144361088886740' + assert NS( + integrate(1/(x**5 + 1), (x, 2, 4)), chop=True) == '0.0144361088886740' + -def xtest_failing_integrals(): +@XFAIL +def test_failing_integrals(): #--- # Double integrals not implemented - assert NS(Integral(sqrt(x)+x*y, (x, 1, 2), (y, -1, 1)), 15) == '2.43790283299492' + assert NS(Integral( + sqrt(x) + x*y, (x, 1, 2), (y, -1, 1)), 15) == '2.43790283299492' # double integral + zero detection - assert NS(Integral(sin(x+x*y), (x, -1, 1), (y, -1, 1)), 15) == '0.0' + assert NS(Integral(sin(x + x*y), (x, -1, 1), (y, -1, 1)), 15) == '0.0' + def test_integrate_DiracDelta(): - assert integrate(DiracDelta(x),x) == Heaviside(x) - assert integrate(DiracDelta(x) * f(x),x) == f(0) * Heaviside(x) - assert integrate(DiracDelta(x) * f(x),(x,-oo,oo)) == f(0) - assert integrate(DiracDelta(-x) * f(x),(x,-oo,oo)) == f(0) - assert integrate(DiracDelta(-(x-1)) * f(x),(x,-oo,oo)) == f(1) - assert integrate(DiracDelta(x) * f(x),(x,0,oo)) == f(0)/2 - assert integrate(DiracDelta(x**2+x-2),x) - \ - (Heaviside(-1 + x)/3 + Heaviside(2 + x)/3) == 0 - assert integrate(cos(x)*(DiracDelta(x)+DiracDelta(x**2-1))*sin(x)*(x-pi),x) - \ - (-pi*(cos(1)*Heaviside(-1 + x)*sin(1)/2 - cos(1)*Heaviside(1 + x)*sin(1)/2) + \ - cos(1)*Heaviside(1 + x)*sin(1)/2 + cos(1)*Heaviside(-1 + x)*sin(1)/2) == 0 - assert integrate(x_2*DiracDelta(x - x_2)*DiracDelta(x_2 - x_1), (x_2, -oo, oo)) == \ - x*DiracDelta(x - x_1) - assert integrate(x*y**2*z*DiracDelta(y - x)*DiracDelta(y - z)*DiracDelta(x - z), (y, -oo, oo)) \ - == x**3*z*DiracDelta(x - z)**2 - assert integrate((x+1)*DiracDelta(2*x), (x, -oo, oo)) == S(1)/2 - assert integrate((x+1)*DiracDelta(2*x/3 + 4/S(9)), (x, -oo, oo)) == S(1)/2 - - a, b, c = symbols('a b c', commutative=False) - assert integrate(DiracDelta(x - y)*f(x - b)*f(x - a), (x, -oo, oo)) == \ - f(y - b)*f(y - a) - assert integrate(f(x - a)*DiracDelta(x - y)*f(x - c)*f(x - b), \ - (x, -oo, oo)) == f(y - a)*f(y - c)*f(y - b) + # This is here to check that deltaintegrate is being called, but also + # to test definite integrals. More tests are in test_deltafunctions.py + assert integrate(DiracDelta(x) * f(x), (x, -oo, oo)) == f(0) + assert integrate(DiracDelta(x) * f(x), (x, 0, oo)) == f(0)/2 + assert integrate(DiracDelta(x)**2, (x, -oo, oo)) == DiracDelta(0) + # issue 1423 + assert integrate(integrate((4 - 4*x + x*y - 4*y) * \ + DiracDelta(x)*DiracDelta(y - 1), (x, 0, 1)), (y, 0, 1)) == 0 + # issue 2630 + p = exp(-(x**2 + y**2))/pi + assert integrate(p*DiracDelta(x - 10*y), (x, -oo, oo), (y, -oo, oo)) == \ + integrate(p*DiracDelta(x - 10*y), (y, -oo, oo), (x, -oo, oo)) == \ + integrate(p*DiracDelta(10*x - y), (x, -oo, oo), (y, -oo, oo)) == \ + integrate(p*DiracDelta(10*x - y), (y, -oo, oo), (x, -oo, oo)) == \ + 1/sqrt(101*pi) + # issue 3328 + assert integrate(integrate(integrate( + DiracDelta(x - y - z), (z, 0, oo)), (y, 0, 1)), (x, 0, 1)) == 1 + + +def test_integrate_returns_piecewise(): + assert integrate(x**y, x) == Piecewise( + (log(x), Eq(y, -1)), (x**(y + 1)/(y + 1), True)) + assert integrate(x**y, y) == Piecewise( + (y, Eq(log(x), 0)), (x**y/log(x), True)) + assert integrate(exp(n*x), x) == Piecewise( + (x, Eq(n, 0)), (exp(n*x)/n, True)) + assert integrate(x*exp(n*x), x) == Piecewise( + (x**2/2, Eq(n**3, 0)), ((x*n**2 - n)*exp(n*x)/n**3, True)) + assert integrate(x**(n*y), x) == Piecewise( + (log(x), Eq(n*y, -1)), (x**(n*y + 1)/(n*y + 1), True)) + assert integrate(x**(n*y), y) == Piecewise( + (y, Eq(n*log(x), 0)), (x**(n*y)/(n*log(x)), True)) + assert integrate(cos(n*x), x) == Piecewise( + (x, Eq(n, 0)), (sin(n*x)/n, True)) + assert integrate(cos(n*x)**2, x) == Piecewise( + (x, Eq(n, 0)), ((n*x/2 + sin(n*x)*cos(n*x)/2)/n, True)) + assert integrate(x*cos(n*x), x) == Piecewise( + (x**2/2, Eq(n, 0)), (x*sin(n*x)/n + cos(n*x)/n**2, True)) + assert integrate(sin(n*x), x) == Piecewise( + (0, Eq(n, 0)), (-cos(n*x)/n, True)) + assert integrate(sin(n*x)**2, x) == Piecewise( + (0, Eq(n, 0)), ((n*x/2 - sin(n*x)*cos(n*x)/2)/n, True)) + assert integrate(x*sin(n*x), x) == Piecewise( + (0, Eq(n, 0)), (-x*cos(n*x)/n + sin(n*x)/n**2, True)) - assert integrate(DiracDelta(x - z)*f(x - b)*f(x - a)*DiracDelta(x - y), \ - (x, -oo, oo)) == DiracDelta(y - z)*f(y - b)*f(y - a) def test_subs1(): - e = Integral(exp(x-y), x) - assert e.subs(y, 3) == Integral(exp(x-3), x) - e = Integral(exp(x-y), (x, 0, 1)) - assert e.subs(y, 3) == Integral(exp(x-3), (x, 0, 1)) + e = Integral(exp(x - y), x) + assert e.subs(y, 3) == Integral(exp(x - 3), x) + e = Integral(exp(x - y), (x, 0, 1)) + assert e.subs(y, 3) == Integral(exp(x - 3), (x, 0, 1)) f = Lambda(x, exp(-x**2)) - conv = Integral(f(x-y)*f(y), (y, -oo, oo)) - assert conv.subs({x:0}) == Integral(exp(-2*y**2), (y, -oo, oo)) + conv = Integral(f(x - y)*f(y), (y, -oo, oo)) + assert conv.subs({x: 0}) == Integral(exp(-2*y**2), (y, -oo, oo)) + def test_subs2(): - e = Integral(exp(x-y), x, t) - assert e.subs(y, 3) == Integral(exp(x-3), x, t) - e = Integral(exp(x-y), (x, 0, 1), (t, 0, 1)) - assert e.subs(y, 3) == Integral(exp(x-3), (x, 0, 1), (t, 0, 1)) + e = Integral(exp(x - y), x, t) + assert e.subs(y, 3) == Integral(exp(x - 3), x, t) + e = Integral(exp(x - y), (x, 0, 1), (t, 0, 1)) + assert e.subs(y, 3) == Integral(exp(x - 3), (x, 0, 1), (t, 0, 1)) f = Lambda(x, exp(-x**2)) - conv = Integral(f(x-y)*f(y), (y, -oo, oo), (t, 0, 1)) - assert conv.subs({x:0}) == Integral(exp(-2*y**2), (y, -oo, oo), (t, 0, 1)) + conv = Integral(f(x - y)*f(y), (y, -oo, oo), (t, 0, 1)) + assert conv.subs({x: 0}) == Integral(exp(-2*y**2), (y, -oo, oo), (t, 0, 1)) + def test_subs3(): - e = Integral(exp(x-y), (x, 0, y), (t, y, 1)) - assert e.subs(y, 3) == Integral(exp(x-3), (x, 0, 3), (t, 3, 1)) + e = Integral(exp(x - y), (x, 0, y), (t, y, 1)) + assert e.subs(y, 3) == Integral(exp(x - 3), (x, 0, 3), (t, 3, 1)) f = Lambda(x, exp(-x**2)) - conv = Integral(f(x-y)*f(y), (y, -oo, oo), (t, x, 1)) - assert conv.subs({x:0}) == Integral(exp(-2*y**2), (y, -oo, oo), (t, 0, 1)) + conv = Integral(f(x - y)*f(y), (y, -oo, oo), (t, x, 1)) + assert conv.subs({x: 0}) == Integral(exp(-2*y**2), (y, -oo, oo), (t, 0, 1)) + def test_subs4(): e = Integral(exp(x), (x, 0, y), (t, y, 1)) assert e.subs(y, 3) == Integral(exp(x), (x, 0, 3), (t, 3, 1)) f = Lambda(x, exp(-x**2)) conv = Integral(f(y)*f(y), (y, -oo, oo), (t, x, 1)) - assert conv.subs({x:0}) == Integral(exp(-2*y**2), (y, -oo, oo), (t, 0, 1)) + assert conv.subs({x: 0}) == Integral(exp(-2*y**2), (y, -oo, oo), (t, 0, 1)) + def test_subs5(): e = Integral(exp(-x**2), x) @@ -404,13 +513,14 @@ e = Integral(exp(-x**2 + y), x) assert e.subs(x, 5) == Integral(exp(y - 25), x) assert e.subs(y, 5) == Integral(exp(-x**2 + 5), x) - e = Integral(exp(-x**2+y), (x, x)) + e = Integral(exp(-x**2 + y), (x, x)) assert e.subs(x, 5) == Integral(exp(y - x**2), (x, 5)) assert e.subs(y, 5) == Integral(exp(-x**2 + 5), (x, x)) - e = Integral(exp(-x**2+y), (y, -oo, oo), (x, -oo, oo)) + e = Integral(exp(-x**2 + y), (y, -oo, oo), (x, -oo, oo)) assert e.subs(x, 5) == e assert e.subs(y, 5) == e + def test_subs6(): a, b = symbols('a b') e = Integral(x*y, (x, f(x), f(y))) @@ -422,70 +532,82 @@ e = Integral(x*y, (x, f(x), f(a)), (y, f(x), f(a))) assert e.subs(a, 1) == Integral(x*y, (x, f(x), f(1)), (y, f(x), f(1))) + def test_subs7(): e = Integral(x, (x, 1, y), (y, 1, 2)) - assert e.subs({x:1, y:2}) == e + assert e.subs({x: 1, y: 2}) == e e = Integral(sin(x) + sin(y), (x, sin(x), sin(y)), (y, 1, 2)) assert e.subs(sin(y), 1) == e assert e.subs(sin(x), 1) == Integral(sin(x) + sin(y), (x, 1, sin(y)), - (y, 1, 2)) + (y, 1, 2)) + def test_integration_variable(): raises(ValueError, lambda: Integral(exp(-x**2), 3)) raises(ValueError, lambda: Integral(exp(-x**2), (3, -oo, oo))) + def test_expand_integral(): - assert Integral(cos(x**2)*(sin(x**2)+1),(x, 0, 1)).expand() == Integral(cos(x**2)*sin(x**2) + cos(x**2), (x, 0, 1)) - assert Integral(cos(x**2)*(sin(x**2)+1),x).expand() == Integral(cos(x**2)*sin(x**2) + cos(x**2), x) - i = Integral(x, (x, 1, 2), (x, 1, 2)) + assert Integral(cos(x**2)*(sin(x**2) + 1), (x, 0, 1)).expand() == \ + Integral(cos(x**2)*sin(x**2) + cos(x**2), (x, 0, 1)) + assert Integral(cos(x**2)*(sin(x**2) + 1), x).expand() == \ + Integral(cos(x**2)*sin(x**2) + cos(x**2), x) + def test_as_sum_midpoint1(): - e = Integral(sqrt(x**3+1), (x, 2, 10)) + e = Integral(sqrt(x**3 + 1), (x, 2, 10)) assert e.as_sum(1, method="midpoint") == 8*sqrt(217) assert e.as_sum(2, method="midpoint") == 4*sqrt(65) + 12*sqrt(57) assert e.as_sum(3, method="midpoint") == 8*sqrt(217)/3 + \ - 8*sqrt(3081)/27 + 8*sqrt(52809)/27 + 8*sqrt(3081)/27 + 8*sqrt(52809)/27 assert e.as_sum(4, method="midpoint") == 2*sqrt(730) + \ - 4*sqrt(7) + 4*sqrt(86) + 6*sqrt(14) + 4*sqrt(7) + 4*sqrt(86) + 6*sqrt(14) assert abs(e.as_sum(4, method="midpoint").n() - e.n()) < 0.5 - e = Integral(sqrt(x**3+y**3), (x, 2, 10), (y, 0, 10)) + e = Integral(sqrt(x**3 + y**3), (x, 2, 10), (y, 0, 10)) raises(NotImplementedError, lambda: e.as_sum(4)) + def test_as_sum_midpoint2(): - e = Integral((x+y)**2, (x, 0, 1)) + e = Integral((x + y)**2, (x, 0, 1)) assert e.as_sum(1, method="midpoint").expand() == S(1)/4 + y + y**2 assert e.as_sum(2, method="midpoint").expand() == S(5)/16 + y + y**2 assert e.as_sum(3, method="midpoint").expand() == S(35)/108 + y + y**2 assert e.as_sum(4, method="midpoint").expand() == S(21)/64 + y + y**2 + def test_as_sum_left(): - e = Integral((x+y)**2, (x, 0, 1)) + e = Integral((x + y)**2, (x, 0, 1)) assert e.as_sum(1, method="left").expand() == y**2 assert e.as_sum(2, method="left").expand() == S(1)/8 + y/2 + y**2 assert e.as_sum(3, method="left").expand() == S(5)/27 + 2*y/3 + y**2 assert e.as_sum(4, method="left").expand() == S(7)/32 + 3*y/4 + y**2 + def test_as_sum_right(): - e = Integral((x+y)**2, (x, 0, 1)) + e = Integral((x + y)**2, (x, 0, 1)) assert e.as_sum(1, method="right").expand() == 1 + 2*y + y**2 assert e.as_sum(2, method="right").expand() == S(5)/8 + 3*y/2 + y**2 assert e.as_sum(3, method="right").expand() == S(14)/27 + 4*y/3 + y**2 assert e.as_sum(4, method="right").expand() == S(15)/32 + 5*y/4 + y**2 + def test_as_sum_raises(): - e = Integral((x+y)**2, (x, 0, 1)) + e = Integral((x + y)**2, (x, 0, 1)) raises(ValueError, lambda: e.as_sum(-1)) raises(ValueError, lambda: e.as_sum(0)) + raises(ValueError, lambda: Integral(x).as_sum(3)) raises(NotImplementedError, lambda: e.as_sum(oo)) raises(NotImplementedError, lambda: e.as_sum(3, method='xxxx2')) + def test_nested_doit(): e = Integral(Integral(x, x), x) f = Integral(x, x, x) assert e.doit() == f.doit() + def test_issue1566(): # Allow only upper or lower limit evaluation e = Integral(x**2, (x, None, 1)) @@ -498,10 +620,12 @@ assert integrate(x**2, (x, 1, None)) == Rational(-1, 3) assert integrate("x**2", ("x", "1", None)) == Rational(-1, 3) + def test_integral_reconstruct(): e = Integral(x**2, (x, -1, 1)) assert e == Integral(*e.args) + def test_doit(): e = Integral(Integral(2*x), (x, 0, 1)) assert e.doit() == Rational(1, 3) @@ -512,30 +636,38 @@ # doesn't matter if the limits can't be evaluated assert Integral(0, (x, 1, Integral(f(x), x))).doit() == 0 -def issue_1785(): - assert integrate(sqrt(x)*(1+x)) == 2*sqrt(x)**3/3 + 2*sqrt(x)**5/5 - assert integrate(x**x*(1+log(x))) == x**x + +def test_issue_1785(): + assert integrate(sqrt(x)*(1 + x)) == \ + Piecewise( + (2*sqrt(x)*(x + 1)**2/5 - 2*sqrt(x)*(x + 1)/15 - 4*sqrt(x)/15, + Abs(x + 1) > 1), + (2*I*sqrt(-x)*(x + 1)**2/5 - 2*I*sqrt(-x)*(x + 1)/15 - + 4*I*sqrt(-x)/15, True)) + assert integrate(x**x*(1 + log(x))) == x**x + def test_is_number(): from sympy.abc import x, y, z from sympy import cos, sin - assert Integral(x).is_number == False - assert Integral(1, x).is_number == False - assert Integral(1, (x, 1)).is_number == True - assert Integral(1, (x, 1, 2)).is_number == True - assert Integral(1, (x, 1, y)).is_number == False - assert Integral(x, y).is_number == False - assert Integral(x, (y, 1, x)).is_number == False - assert Integral(x, (y, 1, 2)).is_number == False - assert Integral(x, (x, 1, 2)).is_number == True - assert Integral(x, (y, 1, 1)).is_number == True - assert Integral(x*y, (x, 1, 2), (y, 1, 3)).is_number == True - assert Integral(x*y, (x, 1, 2), (y, 1, z)).is_number == False - assert Integral(x, (x, 1)).is_number == True - assert Integral(x, (x, 1, Integral(y, (y, 1, 2)))).is_number == True + assert Integral(x).is_number is False + assert Integral(1, x).is_number is False + assert Integral(1, (x, 1)).is_number is True + assert Integral(1, (x, 1, 2)).is_number is True + assert Integral(1, (x, 1, y)).is_number is False + assert Integral(x, y).is_number is False + assert Integral(x, (y, 1, x)).is_number is False + assert Integral(x, (y, 1, 2)).is_number is False + assert Integral(x, (x, 1, 2)).is_number is True + assert Integral(x, (y, 1, 1)).is_number is True + assert Integral(x*y, (x, 1, 2), (y, 1, 3)).is_number is True + assert Integral(x*y, (x, 1, 2), (y, 1, z)).is_number is False + assert Integral(x, (x, 1)).is_number is True + assert Integral(x, (x, 1, Integral(y, (y, 1, 2)))).is_number is True # it is possible to get a false negative if the integrand is # actually an unsimplified zero, but this is true of is_number in general. - assert Integral(sin(x)**2 + cos(x)**2 - 1, x).is_number == False + assert Integral(sin(x)**2 + cos(x)**2 - 1, x).is_number is False + def test_symbols(): from sympy.abc import x, y, z @@ -554,7 +686,9 @@ assert Integral(x, (y, 1, 2), (x, 1, y)).free_symbols == set([y]) assert Integral(2, (y, 1, 2), (y, 1, x), (x, 1, 2)).free_symbols == set() assert Integral(2, (y, x, 2), (y, 1, x), (x, 1, 2)).free_symbols == set() - assert Integral(2, (x, 1, 2), (y, x, 2), (y, 1, 2)).free_symbols == set([x]) + assert Integral(2, (x, 1, 2), (y, x, 2), (y, 1, 2)).free_symbols == \ + set([x]) + def test_is_zero(): from sympy.abc import x, m, n @@ -563,25 +697,33 @@ assert Integral(1, (x, 1, 2)).is_zero is False assert Integral(sin(m*x)*cos(n*x), (x, 0, 2*pi)).is_zero is None + def test_series(): from sympy.abc import x i = Integral(cos(x)) e = i.lseries(x) assert i.nseries(x, n=8).removeO() == Add(*[next(e) for j in range(4)]) + def test_issue_1304(): z = Symbol('z', positive=True) - assert integrate(sqrt(x**2 + z**2),x) == z**2*asinh(x/z)/2 + x*sqrt(x**2 + z**2)/2 - assert integrate(sqrt(x**2 - z**2),x) == -z**2*acosh(x/z)/2 + x*sqrt(x**2 - z**2)/2 + assert integrate(sqrt(x**2 + z**2), x) == \ + z**2*asinh(x/z)/2 + x*sqrt(x**2 + z**2)/2 + assert integrate(sqrt(x**2 - z**2), x) == \ + -z**2*acosh(x/z)/2 + x*sqrt(x**2 - z**2)/2 + @XFAIL def test_issue_1304_2(): - assert integrate(sqrt(-x**2 - 4), x) == -2*atan(x/sqrt(-4 - x**2)) + x*sqrt(-4 - x**2)/2 + assert integrate(sqrt(-x**2 - 4), x) == \ + -2*atan(x/sqrt(-4 - x**2)) + x*sqrt(-4 - x**2)/2 -def tets_issue_1001(): + +def test_issue_1001(): R = Symbol('R', positive=True) assert integrate(sqrt(R**2 - x**2), (x, 0, R)) == pi*R**2/4 + def test_issue2068(): from sympy.abc import w, x, y, z f = Function('f') @@ -591,7 +733,7 @@ assert Integral(Integral(f(x)), y).args == (f(x), Tuple(x), Tuple(y)) assert Integral(Integral(f(x), z), y).args == (f(x), Tuple(z), Tuple(y)) assert Integral(Integral(Integral(f(x), x), y), z).args == \ - (f(x), Tuple(x), Tuple(y), Tuple(z)) + (f(x), Tuple(x), Tuple(y), Tuple(z)) assert integrate(Integral(f(x), x), x) == Integral(f(x), x, x) assert integrate(Integral(f(x), y), x) == Integral(y*f(x), x) assert integrate(Integral(f(x), x), y) == Integral(y*f(x), x) @@ -602,55 +744,87 @@ # do as many as possibble assert Integral(f(x), y, x, y, x).doit() == Integral(y**2*f(x)/2, x, x) assert Integral(f(x), (x, 1, 2), (w, 1, x), (z, 1, y)).doit() == \ - Integral(-f(x) + y*f(x), (x, 1, 2), (w, 1, x)) + Integral(-f(x) + y*f(x), (x, 1, 2), (w, 1, x)) + def test_issue_1791(): z = Symbol('z', positive=True) - assert integrate(exp(-log(x)**2),x) == sqrt(pi)*erf(-S(1)/2 + log(x))*exp(S(1)/4)/2 - assert integrate(exp(log(x)**2),x) == -I*sqrt(pi)*erf(I*log(x) + I/2)*exp(-S(1)/4)/2 - assert integrate(exp(-z*log(x)**2),x) == \ - sqrt(pi)*erf(sqrt(z)*log(x) - 1/(2*sqrt(z)))*exp(S(1)/(4*z))/(2*sqrt(z)) + assert integrate(exp(-log(x)**2), x) == \ + sqrt(pi)*exp(S(1)/4)*erf(log(x)-S(1)/2)/2 + assert integrate(exp(log(x)**2), x) == \ + sqrt(pi)*exp(-S(1)/4)*erfi(log(x)+S(1)/2)/2 + assert integrate(exp(-z*log(x)**2), x) == \ + sqrt(pi)*exp(1/(4*z))*erf(sqrt(z)*log(x) - 1/(2*sqrt(z)))/(2*sqrt(z)) + def test_issue_1277(): - assert simplify(integrate(n*(x**(1/n)-1), (x, 0, S.Half)) - + n = Symbol('n', integer=True, positive=True) + assert simplify(integrate(n*(x**(1/n) - 1), (x, 0, S.Half)) - (n**2 - 2**(1/n)*n**2 - n*2**(1/n))/(2**(1 + 1/n) + n*2**(1 + 1/n))) == 0 + +@slow def test_issue_1418(): - assert integrate((sqrt(x) - x**3)/x**Rational(1,3), x) == \ - 6*x**Rational(7,6)/7 - 3*x**Rational(11,3)/11 + assert integrate((sqrt(x) - x**3)/x**Rational(1, 3), x) == \ + 6*x**Rational(7, 6)/7 - 3*x**Rational(11, 3)/11 + + +def test_issue_1428(): + k, m = symbols('k m', integer=True) + assert integrate(sin(k*x)*sin(m*x), (x, 0, pi)) == Piecewise( + (0, And(Eq(k, 0), Eq(m, 0))), + (-pi/2, Eq(k, -m)), + (pi/2, Eq(k, m)), + (0, True)) + assert integrate(sin(k*x)*sin(m*x), (x,)) == Piecewise( + (0, And(Eq(k, 0), Eq(m, 0))), + (-x*sin(m*x)**2/2 - x*cos(m*x)**2/2 + sin(m*x)*cos(m*x)/(2*m), Eq(k, -m)), + (x*sin(m*x)**2/2 + x*cos(m*x)**2/2 - sin(m*x)*cos(m*x)/(2*m), Eq(k, m)), + (m*sin(k*x)*cos(m*x)/(k**2 - m**2) - + k*sin(m*x)*cos(k*x)/(k**2 - m**2), True)) def test_issue_1100(): ypos = Symbol('y', positive=True) - assert integrate(exp(-I*2*pi*ypos*x)*x, (x, -oo, oo)) == \ - Integral(exp(-I*2*pi*ypos*x)*x, (x, -oo, oo)) + # TODO: Remove conds='none' below, let the assumption take care of it. + assert integrate(exp(-I*2*pi*ypos*x)*x, (x, -oo, oo), conds='none') == \ + Integral(exp(-I*2*pi*ypos*x)*x, (x, -oo, oo)) + def test_issue_841(): - a,b,c,d = symbols('a:d', positive=True, bounded=True) - assert integrate(exp(-x**2 + I*c*x), x) == sqrt(pi)*erf(x - I*c/2)*exp(-c**S(2)/4)/2 + a, b, c, d = symbols('a:d', positive=True, bounded=True) + assert integrate(exp(-x**2 + I*c*x), x) == \ + -sqrt(pi)*exp(-c**2/4)*erf(I*c/2 - x)/2 assert integrate(exp(a*x**2 + b*x + c), x) == \ - I*sqrt(pi)*erf(-I*x*sqrt(a) - I*b/(2*sqrt(a)))*exp(c)*exp(-b**2/(4*a))/(2*sqrt(a)) + sqrt(pi)*exp(c)*exp(-b**2/(4*a))*erfi(sqrt(a)*x + b/(2*sqrt(a)))/(2*sqrt(a)) + def test_issue_2314(): # Note that this is not the same as testing ratint() becuase integrate() # pulls out the coefficient. - assert integrate(-a/(a**2+x**2), x) == \ - -a*(sqrt(-1/a**2)*log(x + a**2*sqrt(-1/a**2))/2 - \ - sqrt(-1/a**2)*log(x - a**2*sqrt(-1/a**2))/2) + assert integrate(-a/(a**2 + x**2), x) == I*log(-I*a + x)/2 - I*log(I*a + x)/2 + def test_issue_1793a(): - A, z, c = symbols('A z c') + A, z = symbols('A z') + c = Symbol('c', nonzero=True) P1 = -A*exp(-z) P2 = -A/(c*t)*(sin(x)**2 + cos(y)**2) - # TODO: make trigsimp() deterministic h1 = -sin(x)**2 - cos(y)**2 h2 = -sin(x)**2 + sin(y)**2 - 1 + # there is still some non-deterministic behavior in integrate + # or trigsimp which permits one of the following assert integrate(c*(P2 - P1), t) in [ - c*(A*h1*log(c*t)/c + A*t*exp(-z)), - c*(A*h2*log(c*t)/c + A*t*exp(-z)), + c*(-A*(-h1)*log(c*t)/c + A*t*exp(-z)), + c*(-A*(-h2)*log(c*t)/c + A*t*exp(-z)), + c*( A* h1 *log(c*t)/c + A*t*exp(-z)), + c*( A* h2 *log(c*t)/c + A*t*exp(-z)), + (A*c*t - A*(-h1)*log(t)*exp(z))*exp(-z), + (A*c*t - A*(-h2)*log(t)*exp(z))*exp(-z), ] + def test_issue_1793b(): # Issues relating to issue 1497 are making the actual result of this hard # to test. The answer should be something like @@ -663,10 +837,12 @@ expr = (sin(y)*x**3 + 2*cos(y)*x**2 + 12)/(x**2 + 2) assert trigsimp(factor(integrate(expr, x).diff(x) - expr)) == 0 + def test_issue_2079(): assert integrate(sin(x)*f(y, z), (x, 0, pi), (y, 0, pi), (z, 0, pi)) == \ Integral(2*f(y, z), (y, 0, pi), (z, 0, pi)) + def test_integrate_series(): f = sin(x).series(x, 0, 10) g = x**2/2 - x**4/24 + x**6/720 - x**8/40320 + x**10/3628800 + O(x**11) @@ -676,63 +852,122 @@ assert integrate(O(x**5), x) == O(x**6) + def test_atom_bug(): from sympy import meijerg - from sympy.integrals.risch import heurisch + from sympy.integrals.heurisch import heurisch assert heurisch(meijerg([], [], [1], [], x), x) is None + def test_limit_bug(): + z = Symbol('z', nonzero=True) assert integrate(sin(x*y*z), (x, 0, pi), (y, 0, pi)) == \ - -((-log(pi*z) + log(pi**2*z**2)/2 + Ci(pi**2*z) - )/z) + log(z**2)/(2*z) + EulerGamma/z + 2*log(pi)/z + -((-log(pi*z) + log(pi**2*z**2)/2 + Ci(pi**2*z))/z) + \ + log(z**2)/(2*z) + EulerGamma/z + 2*log(pi)/z + + +def test_issue_1604(): + g = Function('g') + assert integrate(exp(x)*g(x), x).has(Integral) + + +def test_issue_1888(): + f = Function('f') + assert integrate(f(x).diff(x)**2, x).has(Integral) # The following tests work using meijerint. + + +def test_issue459(): + from sympy import Si + assert integrate(cos(x*y), (x, -pi/2, pi/2), (y, 0, pi)) == 2*Si(pi**2/2) + + def test_issue841(): from sympy import expand_mul from sympy.abc import k assert expand_mul(integrate(exp(-x**2)*exp(I*k*x), (x, -oo, oo))) == \ - sqrt(pi)*exp(-k**2/4) + sqrt(pi)*exp(-k**2/4) a, d = symbols('a d', positive=True) assert expand_mul(integrate(exp(-a*x**2 + 2*d*x), (x, -oo, oo))) == \ - sqrt(pi)*exp(d**2/a)/sqrt(a) + sqrt(pi)*exp(d**2/a)/sqrt(a) + def test_issue1304(): - assert integrate(1/(x**2+y**2)**S('3/2'), x) == 1/(y**2*sqrt(1 + y**2/x**2)) + x = Symbol('x', real=True) + y = Symbol('y', nonzero=True, real=True) + assert integrate(1/(x**2 + y**2)**S('3/2'), x) == \ + 1/(y**2*sqrt(1 + y**2/x**2)) + + +def test_issue_1323(): + assert integrate(1/sqrt(16 + 4*x**2), x) == asinh(x/2) / 2 -def test_issue459(): - from sympy import Si - integrate(cos(x*y), (x, -pi/2, pi/2), (y, 0, pi)) == 2*Si(pi**2/2) def test_issue1394(): from sympy import simplify - assert simplify(integrate(x*sqrt(1+2*x), x)) == \ - sqrt(2*x + 1)*(6*x**2 + x - 1)/15 + assert simplify(integrate(x*sqrt(1 + 2*x), x)) == \ + sqrt(2*x + 1)*(6*x**2 + x - 1)/15 + def test_issue1638(): assert integrate(sin(x)/x, (x, -oo, oo)) == pi assert integrate(sin(x)/x, (x, 0, oo)) == pi/2 + def test_issue1893(): from sympy import simplify, expand_func, polygamma, gamma a = Symbol('a', positive=True) assert simplify(expand_func(integrate(exp(-x)*log(x)*x**a, (x, 0, oo)))) == \ - (a*polygamma(0, a) + 1)*gamma(a) + (a*polygamma(0, a) + 1)*gamma(a) + def test_issue1388(): from sympy import lowergamma, simplify assert simplify(integrate(exp(-x)*x**y, x)) == lowergamma(y + 1, x) + @XFAIL -def test_issue_1116() : +def test_issue_1116(): x = Symbol("x") assert integrate(1/(x**2), (x, -1, 1)) == oo + def test_issue_1301(): + n = Symbol('n', integer=True, positive=True) assert integrate((x**n)*log(x), x) == \ - n*x*x**n*log(x)/(n**2 + 2*n + 1) + x*x**n*log(x)/(n**2 + 2*n + 1) - \ - x*x**n/(n**2 + 2*n + 1) + n*x*x**n*log(x)/(n**2 + 2*n + 1) + x*x**n*log(x)/(n**2 + 2*n + 1) - \ + x*x**n/(n**2 + 2*n + 1) + def test_issue_3154(): # Note: this used to raise NotImplementedError - assert integrate((sqrt(1-x)+sqrt(1+x))**2/x, x, meijerg=True) == \ - Integral((sqrt(-x + 1) + sqrt(x + 1))**2/x, x) + assert integrate((sqrt(1 - x) + sqrt(1 + x))**2/x, x, meijerg=True) == \ + Integral((sqrt(-x + 1) + sqrt(x + 1))**2/x, x) + + +def test_issue1054(): + assert integrate(1/(1 + x + y + z), (x, 0, 1), (y, 0, 1), (z, 0, 1)) in [ + -12*log(3) - 3*log(6)/2 + 3*log(8)/2 + 5*log(2) + 7*log(4), + 6*log(2) + 8*log(4) - 27*log(3)/2, 22*log(2) - 27*log(3)/2, + -12*log(3) - 3*log(6)/2 + 47*log(2)/2] + + +def test_issue_1227(): + R, b, h = symbols('R b h') + # It doesn't matter if we can do the integral. Just make sure the result + # doesn't contain nan. This is really a test against _eval_interval. + assert not integrate(((h*(x - R + b))/b)*sqrt(R**2 - x**2), (x, R - b, R)).has(nan) + + +def test_powers(): + assert integrate(2**x + 3**x, x) == 2**x/log(2) + 3**x/log(3) + + +def test_risch_option(): + # risch=True only allowed on indefinite integrals + raises(ValueError, lambda: integrate(1/log(x), (x, 0, oo), risch=True)) + assert integrate(exp(-x**2), x, risch=True) == NonElementaryIntegral(exp(-x**2), x) + assert integrate(log(1/x)*y, x, y, risch=True) == y**2*(x*log(1/x)/2 + x/2) + assert integrate(erf(x), x, risch=True) == Integral(erf(x), x) + # TODO: How to test risch=False? diff -Nru python3-sympy-0.7.2/sympy/integrals/tests/test_lineintegrals.py python3-sympy-0.7.3/sympy/integrals/tests/test_lineintegrals.py --- python3-sympy-0.7.2/sympy/integrals/tests/test_lineintegrals.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/integrals/tests/test_lineintegrals.py 2013-07-13 17:53:32.000000000 +0000 @@ -3,6 +3,7 @@ s, t, x, y, z = symbols('s,t,x,y,z') + def test_lineintegral(): c = Curve([E**t + 1, E**t - 1], (t, 0, ln(2))) assert line_integrate(x + y, c, [x, y]) == 3*sqrt(2) diff -Nru python3-sympy-0.7.2/sympy/integrals/tests/test_manual.py python3-sympy-0.7.3/sympy/integrals/tests/test_manual.py --- python3-sympy-0.7.2/sympy/integrals/tests/test_manual.py 1970-01-01 00:00:00.000000000 +0000 +++ python3-sympy-0.7.3/sympy/integrals/tests/test_manual.py 2013-07-13 17:53:32.000000000 +0000 @@ -0,0 +1,115 @@ +from sympy import (sin, cos, tan, sec, csc, cot, log, exp, atan, + Symbol, Mul, Integral, integrate, pi, Dummy, + Derivative, diff, I, sqrt, erf) +from sympy.integrals.manualintegrate import manualintegrate, find_substitutions, \ + integral_steps, _parts_rule + +x = Symbol('x') +y = Symbol('y') +u = Symbol('u') + +def test_find_substitutions(): + assert find_substitutions((cot(x)**2 + 1)**2*csc(x)**2*cot(x)**2, x, u) == \ + [(cot(x), 1, -u**6 - 2*u**4 - u**2)] + assert find_substitutions((sec(x)**2 + tan(x) * sec(x)) / (sec(x) + tan(x)), + x, u) == [(sec(x) + tan(x), 1, 1/u)] + +def test_manualintegrate_polynomials(): + assert manualintegrate(y, x) == x*y + assert manualintegrate(exp(2), x) == x * exp(2) + assert manualintegrate(x**2, x) == x**3 / 3 + assert manualintegrate(3 * x**2 + 4 * x**3, x) == x**3 + x**4 + + assert manualintegrate((x + 2)**3, x) == (x + 2)**4 / 4 + assert manualintegrate((3*x + 4)**2, x) == (3*x + 4)**3 / 9 + + assert manualintegrate((u + 2)**3, u) == (u + 2)**4 / 4 + assert manualintegrate((3*u + 4)**2, u) == (3*u + 4)**3 / 9 + +def test_manualintegrate_exponentials(): + assert manualintegrate(exp(2*x), x) == exp(2*x) / 2 + assert manualintegrate(2**x, x) == (2 ** x) / log(2) + + assert manualintegrate(1 / x, x) == log(x) + assert manualintegrate(1 / (2*x + 3), x) == log(2*x + 3) / 2 + assert manualintegrate(log(x)**2 / x, x) == log(x)**3 / 3 + +def test_manualintegrate_parts(): + assert manualintegrate(exp(x) * sin(x), x) == \ + (exp(x) * sin(x)) / 2 - (exp(x) * cos(x)) / 2 + assert manualintegrate(2*x*cos(x), x) == 2*x*sin(x) + 2*cos(x) + assert manualintegrate(x * log(x), x) == x**2*log(x)/2 - x**2/4 + assert manualintegrate(log(x), x) == x * log(x) - x + assert manualintegrate((3*x**2 + 5) * exp(x), x) == \ + -6*x*exp(x) + (3*x**2 + 5)*exp(x) + 6*exp(x) + assert manualintegrate(atan(x), x) == x*atan(x) - log(x**2 + 1)/2 + + # Make sure _parts_rule doesn't pick u = constant but can pick dv = + # constant if necessary, e.g. for integrate(atan(x)) + assert _parts_rule(cos(x), x) == None + assert _parts_rule(exp(x), x) == None + assert _parts_rule(x**2, x) == None + result = _parts_rule(atan(x), x) + assert result[0] == atan(x) and result[1] == 1 + +def test_manualintegrate_trigonometry(): + assert manualintegrate(sin(x), x) == -cos(x) + assert manualintegrate(tan(x), x) == -log(cos(x)) + + assert manualintegrate(sec(x), x) == log(sec(x) + tan(x)) + assert manualintegrate(csc(x), x) == -log(csc(x) + cot(x)) + + assert manualintegrate(sin(x) * cos(x), x) in [sin(x) ** 2 / 2, -cos(x)**2 / 2] + assert manualintegrate(-sec(x) * tan(x), x) == -sec(x) + assert manualintegrate(csc(x) * cot(x), x) == -csc(x) + +def test_manualintegrate_trigpowers(): + assert manualintegrate(sin(x)**2 * cos(x), x) == sin(x)**3 / 3 + assert manualintegrate(sin(x)**2 * cos(x) **2, x) == \ + x / 8 - sin(4*x) / 32 + assert manualintegrate(sin(x) * cos(x)**3, x) == -cos(x)**4 / 4 + assert manualintegrate(sin(x)**3 * cos(x)**2, x) == \ + cos(x)**5 / 5 - cos(x)**3 / 3 + + assert manualintegrate(tan(x)**3 * sec(x), x) == sec(x)**3/3 - sec(x) + assert manualintegrate(tan(x) * sec(x) **2, x) == sec(x)**2/2 + + assert manualintegrate(cot(x)**5 * csc(x), x) == \ + -csc(x)**5/5 + 2*csc(x)**3/3 - csc(x) + assert manualintegrate(cot(x)**2 * csc(x)**6, x) == \ + -cot(x)**7/7 - 2*cot(x)**5/5 - cot(x)**3/3 + +def test_manualintegrate_inversetrig(): + assert manualintegrate(exp(x) / (1 + exp(2*x)), x) == atan(exp(x)) + assert manualintegrate(1 / (4 + 9 * x**2), x) == atan(3 * x/2) / 6 + assert manualintegrate(1 / (16 + 16 * x**2), x) == atan(x) / 16 + assert manualintegrate(1 / (4 + x**2), x) == atan(x / 2) / 2 + assert manualintegrate(1 / (1 + 4 * x**2), x) == atan(2*x) / 2 + +def test_manualintegrate_derivative(): + assert manualintegrate(pi * Derivative(x**2 + 2*x + 3), x) == \ + pi * ((x**2 + 2*x + 3)) + assert manualintegrate(Derivative(x**2 + 2*x + 3, y), x) == \ + x * Derivative(x**2 + 2*x + 3, y) + assert manualintegrate(Derivative(sin(x), x, x, y, x), x) == \ + Derivative(sin(x), x, x, y) + +def test_issue_3700(): + r, x, phi = list(map(Symbol, 'r x phi'.split())) + n = Symbol('n', integer=True, positive=True) + + integrand = (cos(n*(x-phi))*cos(n*x)) + limits = (x, -pi, pi) + assert manualintegrate(integrand, x).has(Integral) + assert r * integrate(integrand.expand(trig=True), limits) / pi == r * cos(n * phi) + assert not integrate(integrand, limits).has(Dummy) + +def test_issue_3796(): + assert manualintegrate(diff(exp(x + x**2)), x) == exp(x + x**2) + assert integrate(x * exp(x**4), x, risch=False) == -I*sqrt(pi)*erf(I*x**2)/4 + +def test_manual_true(): + assert integrate(exp(x) * sin(x), x, manual=True) == \ + (exp(x) * sin(x)) / 2 - (exp(x) * cos(x)) / 2 + assert integrate(sin(x) * cos(x), x, manual=True) in \ + [sin(x) ** 2 / 2, -cos(x)**2 / 2] diff -Nru python3-sympy-0.7.2/sympy/integrals/tests/test_meijerint.py python3-sympy-0.7.3/sympy/integrals/tests/test_meijerint.py --- python3-sympy-0.7.2/sympy/integrals/tests/test_meijerint.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/integrals/tests/test_meijerint.py 2013-07-13 17:53:32.000000000 +0000 @@ -8,12 +8,14 @@ random_complex_number as randcplx) from sympy.abc import x, y, a, b, c, d, s, t, z + def test_rewrite_single(): def t(expr, c, m): e = _rewrite_single(meijerg([a], [b], [c], [d], expr), x) assert e is not None assert isinstance(e[0][0][2], meijerg) assert e[0][0][2].argument.as_coeff_mul(x) == (c, (m,)) + def tn(expr): assert _rewrite_single(meijerg([a], [b], [c], [d], expr), x) is None @@ -26,7 +28,8 @@ def u(expr, x): from sympy import Add, exp, exp_polar r = _rewrite_single(expr, x) - e = Add(*[res[0]*res[2] for res in r[0]]).replace(exp_polar, exp) # XXX Hack? + e = Add(*[res[0]*res[2] for res in r[0]]).replace( + exp_polar, exp) # XXX Hack? assert test_numerically(e, expr, x) u(exp(-x)*sin(x), x) @@ -42,19 +45,20 @@ # exp_polar). #u(exp(x)*sin(x), x) assert _rewrite_single(exp(x)*sin(x), x) == \ - ([(-sqrt(2)/(2*sqrt(pi)), 0, - meijerg(((-S(1)/2, 0, S(1)/4, S(1)/2, S(3)/4), (1,)), - ((), (-S(1)/2, 0)), 64*exp_polar(-4*I*pi)/x**4))], True) + ([(-sqrt(2)/(2*sqrt(pi)), 0, + meijerg(((-S(1)/2, 0, S(1)/4, S(1)/2, S(3)/4), (1,)), + ((), (-S(1)/2, 0)), 64*exp_polar(-4*I*pi)/x**4))], True) + def test_rewrite1(): - assert _rewrite1(x**3*meijerg([a], [b], [c], [d], x**2 + y*x**2)*5, x) \ - == (5, x**3, [(1, 0, meijerg([a], [b], [c], [d], x**2*(y + 1)))], \ - True) + assert _rewrite1(x**3*meijerg([a], [b], [c], [d], x**2 + y*x**2)*5, x) == \ + (5, x**3, [(1, 0, meijerg([a], [b], [c], [d], x**2*(y + 1)))], True) + def test_meijerint_indefinite_numerically(): def t(fac, arg): g = meijerg([a], [b], [c], [d], arg)*fac - subs = {a: randcplx()/10, b:randcplx()/10 + I, + subs = {a: randcplx()/10, b: randcplx()/10 + I, c: randcplx(), d: randcplx()} integral = meijerint_indefinite(g, x) assert integral is not None @@ -67,9 +71,11 @@ t(x**3, x) t(3*x**S('3/2'), 4*x**S('7/3')) + def test_inflate(): subs = {a: randcplx()/10, b: randcplx()/10 + I, c: randcplx(), - d: randcplx(), y:randcplx()/10} + d: randcplx(), y: randcplx()/10} + def t(a, b, arg, n): from sympy import Mul m1 = meijerg(a, b, arg) @@ -81,20 +87,23 @@ assert t([[a, y], [b]], [[c], [d]], x, 3) assert t([[a], [b]], [[c, y], [d]], 2*x**3, 3) + def test_recursive(): from sympy import symbols, exp_polar, expand a, b, c = symbols('a b c', positive=True) - assert simplify(integrate(exp(-(x-a)**2)*exp(-(x - b)**2), (x, 0, oo))) \ - == sqrt(2*pi)/4*(1 + erf(sqrt(2)/2*(a + b))) \ - *exp(-a**2 - b**2 + (a + b)**2/2) - assert simplify(integrate - (exp(-(x - a)**2)*exp(-(x - b)**2)*exp(c*x), (x, 0, oo))) \ - == sqrt(2*pi)/4*(1 + erf(sqrt(2)/4*(2*a + 2*b + c))) \ - *exp(-a**2 - b**2 + (2*a + 2*b + c)**2/8) - assert simplify(integrate(exp(-(x - a - b - c)**2), (x, 0, oo))) \ - == sqrt(pi)/2*(1 + erf(a + b + c)) - assert simplify(integrate(exp(-(x + a + b + c)**2), (x, 0, oo))) \ - == sqrt(pi)/2*(1 - erf(a + b + c)) + e = integrate(exp(-(x - a)**2)*exp(-(x - b)**2), (x, 0, oo)) + assert simplify(e.expand()) == ( + sqrt(2)*sqrt(pi)*( + (erf(sqrt(2)*(a + b)/2) + 1)*exp(-a**2/2 + a*b - b**2/2))/4) + e = integrate(exp(-(x - a)**2)*exp(-(x - b)**2)*exp(c*x), (x, 0, oo)) + assert simplify(e) == ( + sqrt(2)*sqrt(pi)*(erf(sqrt(2)*(2*a + 2*b + c)/4) + 1)*exp(-a**2 - b**2 + + (2*a + 2*b + c)**2/8)/4) + assert simplify(integrate(exp(-(x - a - b - c)**2), (x, 0, oo))) == \ + sqrt(pi)/2*(1 + erf(a + b + c)) + assert simplify(integrate(exp(-(x + a + b + c)**2), (x, 0, oo))) == \ + sqrt(pi)/2*(1 - erf(a + b + c)) + def test_meijerint(): from sympy import symbols, expand, arg @@ -103,11 +112,11 @@ *meijerg([], [], [mu/2], [-mu/2], t**2/4), (t, 0, oo)).is_Piecewise s = symbols('s', positive=True) - assert integrate(x**s*meijerg([[],[]], [[0],[]], x), (x, 0, oo)) \ - == gamma(s + 1) - assert integrate(x**s*meijerg([[],[]], [[0],[]], x), (x, 0, oo), + assert integrate(x**s*meijerg([[], []], [[0], []], x), (x, 0, oo)) == \ + gamma(s + 1) + assert integrate(x**s*meijerg([[], []], [[0], []], x), (x, 0, oo), meijerg=True) == gamma(s + 1) - assert isinstance(integrate(x**s*meijerg([[],[]], [[0],[]], x), + assert isinstance(integrate(x**s*meijerg([[], []], [[0], []], x), (x, 0, oo), meijerg=False), Integral) @@ -116,17 +125,16 @@ # TODO what simplifications should be done automatically? # This tests "extra case" for antecedents_1. a, b = symbols('a b', positive=True) - assert simplify(meijerint_definite(x**a, x, 0, b)[0]) \ - == b**(a + 1)/(a + 1) + assert simplify(meijerint_definite(x**a, x, 0, b)[0]) == \ + b**(a + 1)/(a + 1) # This tests various conditions and expansions: - meijerint_definite((x+1)**3*exp(-x), x, 0, oo) == (16, True) + meijerint_definite((x + 1)**3*exp(-x), x, 0, oo) == (16, True) # Again, how about simplifications? sigma, mu = symbols('sigma mu', positive=True) i, c = meijerint_definite(exp(-((x - mu)/(2*sigma))**2), x, 0, oo) - assert simplify(i) \ - == sqrt(pi)*sigma*(erf(mu/(2*sigma)) + 1) + assert simplify(i) == sqrt(pi)*sigma*(erf(mu/(2*sigma)) + 1) assert c is True i, _ = meijerint_definite(exp(-mu*x)*exp(sigma*x), x, 0, oo) @@ -137,14 +145,14 @@ assert meijerint_definite(exp(x), x, -oo, 2) == (exp(2), True) assert expand(meijerint_definite(exp(x), x, 0, I)[0]) == exp(I) - 1 assert expand(meijerint_definite(exp(-x), x, 0, x)[0]) == \ - 1 - exp(-exp(I*arg(x))*abs(x)) + 1 - exp(-exp(I*arg(x))*abs(x)) # Test -oo to oo assert meijerint_definite(exp(-x**2), x, -oo, oo) == (sqrt(pi), True) assert meijerint_definite(exp(-abs(x)), x, -oo, oo) == (2, True) - assert meijerint_definite(exp(-(2*x-3)**2), x, -oo, oo) == \ + assert meijerint_definite(exp(-(2*x - 3)**2), x, -oo, oo) == \ (sqrt(pi)/2, True) - assert meijerint_definite(exp(-abs(2*x-3)), x, -oo, oo) == (1, True) + assert meijerint_definite(exp(-abs(2*x - 3)), x, -oo, oo) == (1, True) assert meijerint_definite(exp(-((x - mu)/sigma)**2/2)/sqrt(2*pi*sigma**2), x, -oo, oo) == (1, True) @@ -152,68 +160,69 @@ assert meijerint_definite(exp(-x)*sin(x), x, 0, oo) == (S(1)/2, True) # Test a bug - def res(n): return (1/(1+x**2)).diff(x, n).subs(x,1)*(-1)**n + def res(n): + return (1/(1 + x**2)).diff(x, n).subs(x, 1)*(-1)**n for n in range(6): assert integrate(exp(-x)*sin(x)*x**n, (x, 0, oo), meijerg=True) == \ - res(n) + res(n) # This used to test trigexpand... now it is done by linear substitution assert simplify(integrate(exp(-x)*sin(x + a), (x, 0, oo), meijerg=True) - ).expand().rewrite(sin).expand() == sin(a)/2 + cos(a)/2 + ) == sqrt(2)*sin(a + pi/4)/2 # Test the condition 14 from prudnikov. # (This is besselj*besselj in disguise, to stop the product from being # recognised in the tables.) a, b, s = symbols('a b s') from sympy import And, re - assert meijerint_definite(meijerg([], [], [a/2], [-a/2], x/4) \ - *meijerg([], [], [b/2], [-b/2], x/4)*x**(s-1), x, 0, oo) == \ - (4*2**(2*s - 2)*gamma(-2*s + 1)*gamma(a/2 + b/2 + s) \ - /(gamma(-a/2 + b/2 - s + 1)*gamma(a/2 - b/2 - s + 1) \ - *gamma(a/2 + b/2 - s + 1)), + assert meijerint_definite(meijerg([], [], [a/2], [-a/2], x/4) + *meijerg([], [], [b/2], [-b/2], x/4)*x**(s - 1), x, 0, oo) == \ + (4*2**(2*s - 2)*gamma(-2*s + 1)*gamma(a/2 + b/2 + s) + /(gamma(-a/2 + b/2 - s + 1)*gamma(a/2 - b/2 - s + 1) + *gamma(a/2 + b/2 - s + 1)), And(0 < -2*re(4*s) + 8, 0 < re(a/2 + b/2 + s), re(2*s) < 1)) # test a bug assert integrate(sin(x**a)*sin(x**b), (x, 0, oo), meijerg=True) == \ - Integral(sin(x**a)*sin(x**b), (x, 0, oo)) + Integral(sin(x**a)*sin(x**b), (x, 0, oo)) # test better hyperexpand assert integrate(exp(-x**2)*log(x), (x, 0, oo), meijerg=True) == \ - (sqrt(pi)*polygamma(0, S(1)/2)/4).expand() + (sqrt(pi)*polygamma(0, S(1)/2)/4).expand() # Test hyperexpand bug. from sympy import lowergamma - n = symbols('n', integer = True) + n = symbols('n', integer=True) assert simplify(integrate(exp(-x)*x**n, x, meijerg=True)) == \ - lowergamma(n + 1, x) + lowergamma(n + 1, x) # Test a bug with argument 1/x alpha = symbols('alpha', positive=True) - assert meijerint_definite((2-x)**alpha*sin(alpha/x), x, 0, 2) == \ - (sqrt(pi)*gamma(alpha + 1) \ - *meijerg([S(1)/2, 0, S(1)/2], [1], [], - [-alpha/2, -alpha/2 - S(1)/2], 16/alpha**2), True) + assert meijerint_definite((2 - x)**alpha*sin(alpha/x), x, 0, 2) == \ + (sqrt(pi)*alpha*gamma(alpha + 1)*meijerg(((), (alpha/2 + S(1)/2, + alpha/2 + 1)), ((0, 0, S(1)/2), (-S(1)/2,)), alpha**S(2)/16)/4, True) # test a bug related to 3016 a, s = symbols('a s', positive=True) assert simplify(integrate(x**s*exp(-a*x**2), (x, -oo, oo))) == \ - a**(-s/2 - S(1)/2)*(exp(I*pi*s) + 1)*gamma(s/2 + S(1)/2)/2 + a**(-s/2 - S(1)/2)*((-1)**s + 1)*gamma(s/2 + S(1)/2)/2 + def test_bessel(): from sympy import (besselj, Heaviside, besseli, polar_lift, exp_polar, powdenest) assert simplify(integrate(besselj(a, z)*besselj(b, z)/z, (z, 0, oo), meijerg=True, conds='none')) == \ - 2*sin(pi*(a/2 - b/2))/(pi*(a - b)*(a + b)) + 2*sin(pi*(a/2 - b/2))/(pi*(a - b)*(a + b)) assert simplify(integrate(besselj(a, z)*besselj(a, z)/z, (z, 0, oo), meijerg=True, conds='none')) == 1/(2*a) # TODO more orthogonality integrals - assert simplify(integrate(sin(z*x)*(x**2-1)**(-(y+S(1)/2)), + assert simplify(integrate(sin(z*x)*(x**2 - 1)**(-(y + S(1)/2)), (x, 1, oo), meijerg=True, conds='none') - *2/((z/2)**y*sqrt(pi)*gamma(S(1)/2-y))) == \ - besselj(y, z) + *2/((z/2)**y*sqrt(pi)*gamma(S(1)/2 - y))) == \ + besselj(y, z) # Werner Rosenheinrich # SOME INDEFINITE INTEGRALS OF BESSEL FUNCTIONS @@ -224,17 +233,17 @@ # reduced to order 0, 1? assert integrate(besselj(1, x), x, meijerg=True) == -besselj(0, x) assert integrate(besselj(1, x)**2/x, x, meijerg=True) == \ - -(besselj(0, x)**2 + besselj(1, x)**2)/2 + -(besselj(0, x)**2 + besselj(1, x)**2)/2 # TODO more besseli when tables are extended or recursive mellin works assert integrate(besselj(0, x)**2/x**2, x, meijerg=True) == \ - -2*x*besselj(0, x)**2 - 2*x*besselj(1, x)**2 \ - + 2*besselj(0, x)*besselj(1, x) - besselj(0, x)**2/x + -2*x*besselj(0, x)**2 - 2*x*besselj(1, x)**2 \ + + 2*besselj(0, x)*besselj(1, x) - besselj(0, x)**2/x assert integrate(besselj(0, x)*besselj(1, x), x, meijerg=True) == \ - -besselj(0, x)**2/2 + -besselj(0, x)**2/2 assert integrate(x**2*besselj(0, x)*besselj(1, x), x, meijerg=True) == \ - x**2*besselj(1, x)**2/2 + x**2*besselj(1, x)**2/2 assert integrate(besselj(0, x)*besselj(1, x)/x, x, meijerg=True) == \ - (x*besselj(0, x)**2 + x*besselj(1, x)**2 - \ + (x*besselj(0, x)**2 + x*besselj(1, x)**2 - besselj(0, x)*besselj(1, x)) # TODO how does besselj(0, a*x)*besselj(0, b*x) work? # TODO how does besselj(0, x)**2*besselj(1, x)**2 work? @@ -247,9 +256,12 @@ assert integrate(besselj(1, x**2)*x, x, meijerg=True) == \ -besselj(0, x**2)/2 + def test_inversion(): from sympy import piecewise_fold, besselj, sqrt, I, sin, cos, Heaviside - def inv(f): return piecewise_fold(meijerint_inversion(f, s, t)) + + def inv(f): + return piecewise_fold(meijerint_inversion(f, s, t)) assert inv(1/(s**2 + 1)) == sin(t)*Heaviside(t) assert inv(s/(s**2 + 1)) == cos(t)*Heaviside(t) assert inv(exp(-s)/s) == Heaviside(t - 1) @@ -260,6 +272,7 @@ assert inv(exp(s**2)) is None assert meijerint_inversion(exp(-s**2), s, t) is None + def test_lookup_table(): from random import uniform, randrange from sympy import Add, unpolarify, exp_polar, exp @@ -274,13 +287,13 @@ # these Wilds match positive integers subs[a] = randrange(1, 10) else: - subs[a] = uniform(1.5, 3.5) + subs[a] = uniform(1.5, 2.0) if not isinstance(terms, list): terms = terms(subs) # First test that hyperexpand can do this. expanded = [hyperexpand(g) for (_, g) in terms] - assert all (x.is_Piecewise or not x.has(meijerg) for x in expanded) + assert all(x.is_Piecewise or not x.has(meijerg) for x in expanded) # Now test that the meijer g-function is indeed as advertised. expanded = Add(*[f*x for (f, x) in terms]) @@ -291,19 +304,22 @@ else: assert (abs(a - b)/r).n() <= 1e-10 + def test_branch_bug(): from sympy import powdenest, lowergamma # TODO combsimp cannot prove that the factor is unity assert powdenest(integrate(erf(x**3), x, meijerg=True).diff(x), polar=True) == 2*erf(x**3)*gamma(S(2)/3)/3/gamma(S(5)/3) assert integrate(erf(x**3), x, meijerg=True) == \ - 2*x*erf(x**3)*gamma(S(2)/3)/(3*gamma(S(5)/3)) \ - - 2*gamma(S(2)/3)*lowergamma(S(2)/3, x**6)/(3*sqrt(pi)*gamma(S(5)/3)) + 2*x*erf(x**3)*gamma(S(2)/3)/(3*gamma(S(5)/3)) \ + - 2*gamma(S(2)/3)*lowergamma(S(2)/3, x**6)/(3*sqrt(pi)*gamma(S(5)/3)) + def test_linear_subs(): from sympy import besselj - assert integrate(sin(x-1), x, meijerg=True) == -cos(1 - x) - assert integrate(besselj(1, x-1), x, meijerg=True) == -besselj(0, 1 - x) + assert integrate(sin(x - 1), x, meijerg=True) == -cos(1 - x) + assert integrate(besselj(1, x - 1), x, meijerg=True) == -besselj(0, 1 - x) + def test_probability(): # various integrals from probability theory @@ -311,10 +327,12 @@ from sympy import symbols, Symbol, Abs, expand_mul, combsimp, powsimp, sin mu1, mu2 = symbols('mu1 mu2', real=True, finite=True, bounded=True) sigma1, sigma2 = symbols('sigma1 sigma2', real=True, finite=True, - bounded=True, positive=True) + bounded=True, positive=True) rate = Symbol('lambda', real=True, positive=True, bounded=True) + def normal(x, mu, sigma): return 1/sqrt(2*pi*sigma**2)*exp(-(x - mu)**2/2/sigma**2) + def exponential(x, rate): return rate*exp(-rate*x) @@ -322,9 +340,9 @@ assert integrate(x*normal(x, mu1, sigma1), (x, -oo, oo), meijerg=True) == \ mu1 assert integrate(x**2*normal(x, mu1, sigma1), (x, -oo, oo), meijerg=True) \ - == mu1**2 + sigma1**2 + == mu1**2 + sigma1**2 assert integrate(x**3*normal(x, mu1, sigma1), (x, -oo, oo), meijerg=True) \ - == mu1**3 + 3*mu1*sigma1**2 + == mu1**3 + 3*mu1*sigma1**2 assert integrate(normal(x, mu1, sigma1)*normal(y, mu2, sigma2), (x, -oo, oo), (y, -oo, oo), meijerg=True) == 1 assert integrate(x*normal(x, mu1, sigma1)*normal(y, mu2, sigma2), @@ -345,41 +363,41 @@ assert simplify(i) == mu1**2 + sigma1**2 assert integrate(y**2*normal(x, mu1, sigma1)*normal(y, mu2, sigma2), (x, -oo, oo), (y, -oo, oo), meijerg=True) == \ - sigma2**2 + mu2**2 + sigma2**2 + mu2**2 assert integrate(exponential(x, rate), (x, 0, oo), meijerg=True) == 1 assert integrate(x*exponential(x, rate), (x, 0, oo), meijerg=True) == \ 1/rate - assert integrate(x**2*exponential(x, rate), (x, 0, oo), meijerg=True) \ - == 2/rate**2 + assert integrate(x**2*exponential(x, rate), (x, 0, oo), meijerg=True) == \ + 2/rate**2 def E(expr): res1 = integrate(expr*exponential(x, rate)*normal(y, mu1, sigma1), (x, 0, oo), (y, -oo, oo), meijerg=True) res2 = integrate(expr*exponential(x, rate)*normal(y, mu1, sigma1), - (y, -oo, oo), (x, 0, oo), meijerg=True) + (y, -oo, oo), (x, 0, oo), meijerg=True) assert expand_mul(res1) == expand_mul(res2) return res1 assert E(1) == 1 assert E(x*y) == mu1/rate assert E(x*y**2) == mu1**2/rate + sigma1**2/rate - ans = (rate**2*sigma1**2 + 1)/rate**2 + ans = sigma1**2 + 1/rate**2 assert simplify(E((x + y + 1)**2) - E(x + y + 1)**2) == ans assert simplify(E((x + y - 1)**2) - E(x + y - 1)**2) == ans assert simplify(E((x + y)**2) - E(x + y)**2) == ans # Beta' distribution alpha, beta = symbols('alpha beta', positive=True) - betadist = x**(alpha-1)*(1+x)**(-alpha - beta)*gamma(alpha + beta) \ - /gamma(alpha)/gamma(beta) + betadist = x**(alpha - 1)*(1 + x)**(-alpha - beta)*gamma(alpha + beta) \ + /gamma(alpha)/gamma(beta) assert integrate(betadist, (x, 0, oo), meijerg=True) == 1 i = integrate(x*betadist, (x, 0, oo), meijerg=True, conds='separate') assert (combsimp(i[0]), i[1]) == (alpha/(beta - 1), 1 < beta) j = integrate(x**2*betadist, (x, 0, oo), meijerg=True, conds='separate') assert j[1] == (1 < beta - 1) assert combsimp(j[0] - i[0]**2) == (alpha + beta - 1)*alpha \ - /(beta - 2)/(beta - 1)**2 + /(beta - 2)/(beta - 1)**2 # Beta distribution # NOTE: this is evaluated using antiderivatives. It also tests that @@ -390,43 +408,45 @@ assert simplify(integrate(x*betadist, (x, 0, 1), meijerg=True)) == \ a/(a + b) assert simplify(integrate(x**2*betadist, (x, 0, 1), meijerg=True)) == \ - a*(a + 1)/(a + b)/(a + b + 1) + a*(a + 1)/(a + b)/(a + b + 1) assert simplify(integrate(x**y*betadist, (x, 0, 1), meijerg=True)) == \ - gamma(a + b)*gamma(a + y)/gamma(a)/gamma(a + b + y) + gamma(a + b)*gamma(a + y)/gamma(a)/gamma(a + b + y) # Chi distribution k = Symbol('k', integer=True, positive=True) - chi = 2**(1-k/2)*x**(k-1)*exp(-x**2/2)/gamma(k/2) + chi = 2**(1 - k/2)*x**(k - 1)*exp(-x**2/2)/gamma(k/2) assert powsimp(integrate(chi, (x, 0, oo), meijerg=True)) == 1 assert simplify(integrate(x*chi, (x, 0, oo), meijerg=True)) == \ - sqrt(2)*gamma((k + 1)/2)/gamma(k/2) + sqrt(2)*gamma((k + 1)/2)/gamma(k/2) assert simplify(integrate(x**2*chi, (x, 0, oo), meijerg=True)) == k # Chi^2 distribution - chisquared = 2**(-k/2)/gamma(k/2)*x**(k/2-1)*exp(-x/2) + chisquared = 2**(-k/2)/gamma(k/2)*x**(k/2 - 1)*exp(-x/2) assert powsimp(integrate(chisquared, (x, 0, oo), meijerg=True)) == 1 assert simplify(integrate(x*chisquared, (x, 0, oo), meijerg=True)) == k assert simplify(integrate(x**2*chisquared, (x, 0, oo), meijerg=True)) == \ - k*(k + 2) + k*(k + 2) assert combsimp(integrate(((x - k)/sqrt(2*k))**3*chisquared, (x, 0, oo), meijerg=True)) == 2*sqrt(2)/sqrt(k) # Dagum distribution a, b, p = symbols('a b p', positive=True) # XXX (x/b)**a does not work - dagum = a*p/x*(x/b)**(a*p)/(1 + x**a/b**a)**(p+1) + dagum = a*p/x*(x/b)**(a*p)/(1 + x**a/b**a)**(p + 1) assert simplify(integrate(dagum, (x, 0, oo), meijerg=True)) == 1 # XXX conditions are a mess arg = x*dagum assert simplify(integrate(arg, (x, 0, oo), meijerg=True, conds='none') - ) == b*gamma(1 - 1/a)*gamma(p + 1/a)/gamma(p) + ) == a*b*gamma(1 - 1/a)*gamma(p + 1 + 1/a)/( + (a*p + 1)*gamma(p)) assert simplify(integrate(x*arg, (x, 0, oo), meijerg=True, conds='none') - ) == b**2*gamma(1 - 2/a)*gamma(p + 2/a)/gamma(p) + ) == a*b**2*gamma(1 - 2/a)*gamma(p + 1 + 2/a)/( + (a*p + 2)*gamma(p)) # F-distribution d1, d2 = symbols('d1 d2', positive=True) - f = sqrt(((d1*x)**d1 * d2**d2)/(d1*x + d2)**(d1+d2))/x \ - /gamma(d1/2)/gamma(d2/2)*gamma((d1 + d2)/2) + f = sqrt(((d1*x)**d1 * d2**d2)/(d1*x + d2)**(d1 + d2))/x \ + /gamma(d1/2)/gamma(d2/2)*gamma((d1 + d2)/2) assert simplify(integrate(f, (x, 0, oo), meijerg=True)) == 1 # TODO conditions are a mess assert simplify(integrate(x*f, (x, 0, oo), meijerg=True, conds='none') @@ -452,20 +472,20 @@ # higher moments oo # log-logistic - distn = (beta/alpha)*x**(beta-1)/alpha**(beta-1)\ - /(1 + x**beta/alpha**beta)**2 + distn = (beta/alpha)*x**(beta - 1)/alpha**(beta - 1)/ \ + (1 + x**beta/alpha**beta)**2 assert simplify(integrate(distn, (x, 0, oo))) == 1 # NOTE the conditions are a mess, but correctly state beta > 1 assert simplify(integrate(x*distn, (x, 0, oo), conds='none')) == \ - pi*alpha/beta/sin(pi/beta) + pi*alpha/beta/sin(pi/beta) # (similar comment for conditions applies) assert simplify(integrate(x**y*distn, (x, 0, oo), conds='none')) == \ - pi*alpha**y*y/beta/sin(pi*y/beta) + pi*alpha**y*y/beta/sin(pi*y/beta) # weibull k = Symbol('k', positive=True) n = Symbol('n', positive=True) - distn = k/lamda*(x/lamda)**(k-1)*exp(-(x/lamda)**k) + distn = k/lamda*(x/lamda)**(k - 1)*exp(-(x/lamda)**k) assert simplify(integrate(distn, (x, 0, oo))) == 1 assert simplify(integrate(x**n*distn, (x, 0, oo))) == \ lamda**n*gamma(1 + n/k) @@ -473,7 +493,7 @@ # rice distribution from sympy import besseli nu, sigma = symbols('nu sigma', positive=True) - rice = x/sigma**2*exp(-(x**2+ nu**2)/2/sigma**2)*besseli(0, x*nu/sigma**2) + rice = x/sigma**2*exp(-(x**2 + nu**2)/2/sigma**2)*besseli(0, x*nu/sigma**2) assert integrate(rice, (x, 0, oo), meijerg=True) == 1 # can someone verify higher moments? @@ -493,6 +513,7 @@ assert combsimp(expand_mul(integrate(log(x)*x**(k - 1)*exp(-x)/gamma(k), (x, 0, oo)))) == polygamma(0, k) + def test_expint(): """ Test various exponential integrals. """ from sympy import (expint, unpolarify, Symbol, Ci, Si, Shi, Chi, @@ -503,39 +524,39 @@ assert integrate(exp(-z*x)/x, (x, 1, oo), meijerg=True, conds='none').rewrite(expint).expand() == \ - expint(1, z) + expint(1, z) assert integrate(exp(-z*x)/x**2, (x, 1, oo), meijerg=True, conds='none').rewrite(expint).expand() == \ - expint(2, z).rewrite(Ei).rewrite(expint) + expint(2, z).rewrite(Ei).rewrite(expint) assert integrate(exp(-z*x)/x**3, (x, 1, oo), meijerg=True, conds='none').rewrite(expint).expand() == \ - expint(3, z).rewrite(Ei).rewrite(expint).expand() + expint(3, z).rewrite(Ei).rewrite(expint).expand() t = Symbol('t', positive=True) assert integrate(-cos(x)/x, (x, t, oo), meijerg=True).expand() == Ci(t) assert integrate(-sin(x)/x, (x, t, oo), meijerg=True).expand() == \ - Si(t) - pi/2 + Si(t) - pi/2 assert integrate(sin(x)/x, (x, 0, z), meijerg=True) == Si(z) assert integrate(sinh(x)/x, (x, 0, z), meijerg=True) == Shi(z) assert integrate(exp(-x)/x, x, meijerg=True).expand().rewrite(expint) == \ - I*pi - expint(1, x) + I*pi - expint(1, x) assert integrate(exp(-x)/x**2, x, meijerg=True).rewrite(expint).expand() \ - == expint(1, x) - exp(-x)/x - I*pi + == expint(1, x) - exp(-x)/x - I*pi u = Symbol('u', polar=True) assert integrate(cos(u)/u, u, meijerg=True).expand().as_independent(u)[1] \ - == Ci(u) - assert integrate(cosh(u)/u, u, meijerg=True).expand().as_independent(u)[1]\ - == Chi(u) + == Ci(u) + assert integrate(cosh(u)/u, u, meijerg=True).expand().as_independent(u)[1] \ + == Chi(u) assert integrate(expint(1, x), x, meijerg=True ).rewrite(expint).expand() == x*expint(1, x) - exp(-x) assert integrate(expint(2, x), x, meijerg=True ).rewrite(expint).expand() == \ - -x**2*expint(1, x)/2 + x*exp(-x)/2 - exp(-x)/2 - assert simplify(unpolarify(integrate(expint(y,x), x, + -x**2*expint(1, x)/2 + x*exp(-x)/2 - exp(-x)/2 + assert simplify(unpolarify(integrate(expint(y, x), x, meijerg=True).rewrite(expint).expand(func=True))) == \ - -expint(y + 1, x) + -expint(y + 1, x) assert integrate(Si(x), x, meijerg=True) == x*Si(x) + cos(x) assert integrate(Ci(u), u, meijerg=True).expand() == u*Ci(u) - sin(u) @@ -545,6 +566,7 @@ assert integrate(Si(x)*exp(-x), (x, 0, oo), meijerg=True) == pi/4 assert integrate(expint(1, x)*sin(x), (x, 0, oo), meijerg=True) == log(2)/2 + def test_messy(): from sympy import (laplace_transform, Si, Ci, Shi, Chi, atan, Piecewise, atanh, acoth, E1, besselj, acosh, asin, Ne, And, re, @@ -555,44 +577,51 @@ # where should the logs be simplified? assert laplace_transform(Chi(x), x, s) == \ - ((log(s**(-2)) - log((s**2 - 1)/s**2))/(2*s), 1, True) + ((log(s**(-2)) - log((s**2 - 1)/s**2))/(2*s), 1, True) # TODO maybe simplify the inequalities? assert laplace_transform(besselj(a, x), x, s)[1:] == \ - (0, And(S(0) < re(a/2) + S(1)/2, S(0) < re(a/2) + 1)) + (0, And(S(0) < re(a/2) + S(1)/2, S(0) < re(a/2) + 1)) # NOTE s < 0 can be done, but argument reduction is not good enough yet assert fourier_transform(besselj(1, x)/x, x, s, noconds=False) == \ - (Piecewise((0, 1 < 4*abs(pi**2*s**2)), - (2*sqrt(-4*pi**2*s**2 + 1), True)), 0 < s) + (Piecewise((0, 1 < 4*abs(pi**2*s**2)), + (2*sqrt(-4*pi**2*s**2 + 1), True)), 0 < s) # TODO FT(besselj(0,x)) - conditions are messy (but for acceptable reasons) # - folding could be better - assert integrate(E1(x)*besselj(0, x), (x, 0, oo), meijerg=True) \ - == log(1 + sqrt(2)) - assert integrate(E1(x)*besselj(1, x), (x, 0, oo), meijerg=True) \ - == log(S(1)/2 + sqrt(2)/2) + assert integrate(E1(x)*besselj(0, x), (x, 0, oo), meijerg=True) == \ + log(1 + sqrt(2)) + assert integrate(E1(x)*besselj(1, x), (x, 0, oo), meijerg=True) == \ + log(S(1)/2 + sqrt(2)/2) assert integrate(1/x/sqrt(1 - x**2), x, meijerg=True) == \ - Piecewise((-acosh(1/x), 1 < abs(x**(-2))), (I*asin(1/x), True)) + Piecewise((-acosh(1/x), 1 < abs(x**(-2))), (I*asin(1/x), True)) + def test_3023(): assert integrate(exp(-I*x**2), (x, -oo, oo), meijerg=True) == \ - -I*sqrt(pi)*exp(I*pi/4) + -I*sqrt(pi)*exp(I*pi/4) + def test_3153(): - expr = 1/x/(a+b*x)**(S(1)/3) + expr = 1/x/(a + b*x)**(S(1)/3) anti = integrate(expr, x, meijerg=True) assert not expr.has(hyper) # XXX the expression is a mess, but actually upon differentiation and # putting in numerical values seems to work... + def test_3249(): assert integrate(exp(I*x)/(1 + x**2), (x, -oo, oo)).simplify().rewrite(exp) \ - == pi*exp(-1) + == pi*exp(-1) + def test_fresnel(): from sympy import fresnels, fresnelc - assert expand_func(integrate(sin(pi*x**2/2),x)) == fresnels(x) - assert expand_func(integrate(cos(pi*x**2/2),x)) == fresnelc(x) + assert expand_func(integrate(sin(pi*x**2/2), x)) == fresnels(x) + assert expand_func(integrate(cos(pi*x**2/2), x)) == fresnelc(x) + +def test_3761(): + assert meijerint_indefinite(x**x**x, x) is None diff -Nru python3-sympy-0.7.2/sympy/integrals/tests/test_prde.py python3-sympy-0.7.3/sympy/integrals/tests/test_prde.py --- python3-sympy-0.7.2/sympy/integrals/tests/test_prde.py 1970-01-01 00:00:00.000000000 +0000 +++ python3-sympy-0.7.3/sympy/integrals/tests/test_prde.py 2013-07-13 17:53:32.000000000 +0000 @@ -0,0 +1,215 @@ +"""Most of these tests come from the examples in Bronstein's book.""" + +from sympy import Poly, Matrix, S, symbols, I +from sympy.integrals.risch import DifferentialExtension +from sympy.integrals.prde import (prde_normal_denom, prde_special_denom, + prde_linear_constraints, constant_system, prde_spde, prde_no_cancel_b_large, + prde_no_cancel_b_small, limited_integrate_reduce, limited_integrate, + is_deriv_k, is_log_deriv_k_t_radical, parametric_log_deriv_heu, + is_log_deriv_k_t_radical_in_field) + +from sympy.abc import x, t, n + +t0, t1, t2, t3, k = symbols('t:4 k') + + +def test_prde_normal_denom(): + DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(1 + t**2, t)]}) + fa = Poly(1, t) + fd = Poly(x, t) + G = [(Poly(t, t), Poly(1 + t**2, t)), (Poly(1, t), Poly(x + x*t**2, t))] + assert prde_normal_denom(fa, fd, G, DE) == \ + (Poly(x, t), (Poly(1, t), Poly(1, t)), [(Poly(x*t, t), + Poly(t**2 + 1, t)), (Poly(1, t), Poly(t**2 + 1, t))], Poly(1, t)) + G = [(Poly(t, t), Poly(t**2 + 2*t + 1, t)), (Poly(x*t, t), + Poly(t**2 + 2*t + 1, t)), (Poly(x*t**2, t), Poly(t**2 + 2*t + 1, t))] + DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(t, t)]}) + assert prde_normal_denom(Poly(x, t), Poly(1, t), G, DE) == \ + (Poly(t + 1, t), (Poly((-1 + x)*t + x, t), Poly(1, t)), [(Poly(t, t), + Poly(1, t)), (Poly(x*t, t), Poly(1, t)), (Poly(x*t**2, t), + Poly(1, t))], Poly(t + 1, t)) + + +def test_prde_special_denom(): + a = Poly(t + 1, t) + ba = Poly(t**2, t) + bd = Poly(1, t) + G = [(Poly(t, t), Poly(1, t)), (Poly(t**2, t), Poly(1, t)), (Poly(t**3, t), Poly(1, t))] + DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(t, t)]}) + assert prde_special_denom(a, ba, bd, G, DE) == \ + (Poly(t + 1, t), Poly(t**2, t), [(Poly(t, t), Poly(1, t)), + (Poly(t**2, t), Poly(1, t)), (Poly(t**3, t), Poly(1, t))], Poly(1, t)) + G = [(Poly(t, t), Poly(1, t)), (Poly(1, t), Poly(t, t))] + assert prde_special_denom(Poly(1, t), Poly(t**2, t), Poly(1, t), G, DE) == \ + (Poly(1, t), Poly(t**2 - 1, t), [(Poly(t**2, t), Poly(1, t)), + (Poly(1, t), Poly(1, t))], Poly(t, t)) + DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(-2*x*t0, t0)]}) + DE.decrement_level() + G = [(Poly(t, t), Poly(t**2, t)), (Poly(2*t, t), Poly(t, t))] + assert prde_special_denom(Poly(5*x*t + 1, t), Poly(t**2 + 2*x**3*t, t), Poly(t**3 + 2, t), G, DE) == \ + (Poly(5*x*t + 1, t), Poly(0, t), [(Poly(t, t), Poly(t**2, t)), + (Poly(2*t, t), Poly(t, t))], Poly(1, x)) + DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly((t**2 + 1)*2*x, t)]}) + G = [(Poly(t + x, t), Poly(t*x, t)), (Poly(2*t, t), Poly(x**2, x))] + assert prde_special_denom(Poly(5*x*t + 1, t), Poly(t**2 + 2*x**3*t, t), Poly(t**3, t), G, DE) == \ + (Poly(5*x*t + 1, t), Poly(0, t), [(Poly(t + x, t), Poly(x*t, t)), + (Poly(2*t, t, x), Poly(x**2, t, x))], Poly(1, t)) + assert prde_special_denom(Poly(t + 1, t), Poly(t**2, t), Poly(t**3, t), G, DE) == \ + (Poly(t + 1, t), Poly(0, t), [(Poly(t + x, t), Poly(x*t, t)), (Poly(2*t, t, x), + Poly(x**2, t, x))], Poly(1, t)) + + +def test_prde_linear_constraints(): + DE = DifferentialExtension(extension={'D': [Poly(1, x)]}) + G = [(Poly(2*x**3 + 3*x + 1, x), Poly(x**2 - 1, x)), (Poly(1, x), Poly(x - 1, x)), + (Poly(1, x), Poly(x + 1, x))] + assert prde_linear_constraints(Poly(1, x), Poly(0, x), G, DE) == \ + ((Poly(2*x, x), Poly(0, x), Poly(0, x)), Matrix([[1, 1, -1], [5, 1, 1]])) + G = [(Poly(t, t), Poly(1, t)), (Poly(t**2, t), Poly(1, t)), (Poly(t**3, t), Poly(1, t))] + DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(t, t)]}) + assert prde_linear_constraints(Poly(t + 1, t), Poly(t**2, t), G, DE) == \ + ((Poly(t, t), Poly(t**2, t), Poly(t**3, t)), Matrix()) + G = [(Poly(2*x, t), Poly(t, t)), (Poly(-x, t), Poly(t, t))] + DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(1/x, t)]}) + prde_linear_constraints(Poly(1, t), Poly(0, t), G, DE) == \ + ((Poly(0, t), Poly(0, t)), Matrix([[2*x, -x]])) + + +def test_constant_system(): + A = Matrix([[-(x + 3)/(x - 1), (x + 1)/(x - 1), 1], + [-x - 3, x + 1, x - 1], + [2*(x + 3)/(x - 1), 0, 0]]) + u = Matrix([(x + 1)/(x - 1), x + 1, 0]) + DE = DifferentialExtension(extension={'D': [Poly(1, x)]}) + assert constant_system(A, u, DE) == \ + (Matrix([[1, 0, 0], + [0, 1, 0], + [0, 0, 0], + [0, 0, 1]]), Matrix([0, 1, 0, 0])) + + +def test_prde_spde(): + D = [Poly(x, t), Poly(-x*t, t)] + DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(1/x, t)]}) + # TODO: when bound_degree() can handle this, test degree bound from that too + assert prde_spde(Poly(t, t), Poly(-1/x, t), D, n, DE) == \ + (Poly(t, t), Poly(0, t), [Poly(2*x, t), Poly(-x, t)], + [Poly(-x**2, t), Poly(0, t)], n - 1) + + +def test_prde_no_cancel(): + # b large + DE = DifferentialExtension(extension={'D': [Poly(1, x)]}) + assert prde_no_cancel_b_large(Poly(1, x), [Poly(x**2, x), Poly(1, x)], 2, DE) == \ + ([Poly(x**2 - 2*x + 2, x), Poly(1, x)], Matrix([[1, 0, -1, 0], + [0, 1, 0, -1]])) + assert prde_no_cancel_b_large(Poly(1, x), [Poly(x**3, x), Poly(1, x)], 3, DE) == \ + ([Poly(x**3 - 3*x**2 + 6*x - 6, x), Poly(1, x)], Matrix([[1, 0, -1, 0], + [0, 1, 0, -1]])) + # b small + # XXX: Is there a better example of a monomial with D.degree() > 2? + DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(t**3 + 1, t)]}) + + # My original q was t**4 + t + 1, but this solution implies q == t**4 + # (c1 = 4), with some of the ci for the original q equal to 0. + G = [Poly(t**6, t), Poly(x*t**5, t), Poly(t**3, t), Poly(x*t**2, t), Poly(1 + x, t)] + assert prde_no_cancel_b_small(Poly(x*t, t), G, 4, DE) == \ + ([Poly(t**4/4 - x/12*t**3 + x**2/24*t**2 + (-S(11)/12 - x**3/24)*t + x/24, t), + Poly(x/3*t**3 - x**2/6*t**2 + (-S(1)/3 + x**3/6)*t - x/6, t), Poly(t, t), + Poly(0, t), Poly(0, t)], Matrix([[1, 0, -1, 0, 0, 0, 0, 0, 0, 0], + [0, 1, -S(1)/4, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 1, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 1, 0, 0, 0, 0, 0], + [1, 0, 0, 0, 0, -1, 0, 0, 0, 0], + [0, 1, 0, 0, 0, 0, -1, 0, 0, 0], + [0, 0, 1, 0, 0, 0, 0, -1, 0, 0], + [0, 0, 0, 1, 0, 0, 0, 0, -1, 0], + [0, 0, 0, 0, 1, 0, 0, 0, 0, -1]])) + + # TODO: Add test for deg(b) <= 0 with b small + + +def test_limited_integrate_reduce(): + DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(1/x, t)]}) + assert limited_integrate_reduce(Poly(x, t), Poly(t**2, t), [(Poly(x, t), + Poly(t, t))], DE) == \ + (Poly(t, t), Poly(-1/x, t), Poly(t, t), 1, (Poly(x, t), Poly(1, t)), + [(Poly(-x*t, t), Poly(1, t))]) + + +def test_limited_integrate(): + DE = DifferentialExtension(extension={'D': [Poly(1, x)]}) + G = [(Poly(x, x), Poly(x + 1, x))] + assert limited_integrate(Poly(-(1 + x + 5*x**2 - 3*x**3), x), + Poly(1 - x - x**2 + x**3, x), G, DE) == \ + ((Poly(x**2 - x + 2, x), Poly(x - 1, x)), [2]) + G = [(Poly(1, x), Poly(x, x))] + assert limited_integrate(Poly(5*x**2, x), Poly(3, x), G, DE) == \ + ((Poly(5*x**3/9, x), Poly(1, x)), [0]) + + +def test_is_log_deriv_k_t_radical(): + DE = DifferentialExtension(extension={'D': [Poly(1, x)], 'E_K': [], 'L_K': [], + 'E_args': [], 'L_args': []}) + assert is_log_deriv_k_t_radical(Poly(2*x, x), Poly(1, x), DE) is None + + DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(2*t1, t1), Poly(1/x, t2)], + 'L_K': [2], 'E_K': [1], 'L_args': [x], 'E_args': [2*x]}) + assert is_log_deriv_k_t_radical(Poly(x + t2/2, t2), Poly(1, t2), DE) == \ + ([(t1, 1), (x, 1)], t1*x, 2, 0) + # TODO: Add more tests + + DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(t0, t0), Poly(1/x, t)], + 'L_K': [2], 'E_K': [1], 'L_args': [x], 'E_args': [x]}) + assert is_log_deriv_k_t_radical(Poly(x + t/2 + 3, t), Poly(1, t), DE) == \ + ([(t0, 2), (x, 1)], x*t0**2, 2, 3) + + +def test_is_deriv_k(): + DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(1/x, t1), Poly(1/(x + 1), t2)], + 'L_K': [1, 2], 'E_K': [], 'L_args': [x, x + 1], 'E_args': []}) + assert is_deriv_k(Poly(2*x**2 + 2*x, t2), Poly(1, t2), DE) == \ + ([(t1, 1), (t2, 1)], t1 + t2, 2) + + DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(1/x, t1), Poly(t2, t2)], + 'L_K': [1], 'E_K': [2], 'L_args': [x], 'E_args': [x]}) + assert is_deriv_k(Poly(x**2*t2**3, t2), Poly(1, t2), DE) == \ + ([(x, 3), (t1, 2)], 2*t1 + 3*x, 1) + # TODO: Add more tests, including ones with exponentials + + DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(2/x, t1)], + 'L_K': [1], 'E_K': [], 'L_args': [x**2], 'E_args': []}) + assert is_deriv_k(Poly(x, t1), Poly(1, t1), DE) == \ + ([(t1, S(1)/2)], t1/2, 1) + + DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(2/(1 + x), t0)], + 'L_K': [1], 'E_K': [], 'L_args': [x**2 + 2*x + 1], 'E_args': []}) + assert is_deriv_k(Poly(1 + x, t0), Poly(1, t0), DE) == \ + ([(t0, S(1)/2)], t0/2, 1) + + +def test_is_log_deriv_k_t_radical_in_field(): + # Note, any constant term in the second element of the result doesn't matter, + # because it cancels in Da/a. + DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(1/x, t)]}) + assert is_log_deriv_k_t_radical_in_field(Poly(5*t + 1, t), Poly(2*t*x, t), DE) == \ + (2, 2*t*x**5) + assert is_log_deriv_k_t_radical_in_field(Poly(2 + 3*t, t), Poly(5*x*t, t), DE) == \ + (5, 125*x**3*t**2) + + DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(-t/x**2, t)]}) + assert is_log_deriv_k_t_radical_in_field(Poly(-(1 + 2*t), t), + Poly(2*x**2 + 2*x**2*t, t), DE) == \ + (2, 2*t + 2*t**2) + assert is_log_deriv_k_t_radical_in_field(Poly(-1, t), Poly(x**2, t), DE) == \ + (1, t) + assert is_log_deriv_k_t_radical_in_field(Poly(1, t), Poly(2*x**2, t), DE) == \ + (2, 1/t) + + +def test_parametric_log_deriv(): + DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(1/x, t)]}) + assert parametric_log_deriv_heu(Poly(5*t**2 + t - 6, t), Poly(2*x*t**2, t), + Poly(-1, t), Poly(x*t**2, t), DE) == \ + (2, 6, 2*t*x**5) diff -Nru python3-sympy-0.7.2/sympy/integrals/tests/test_quadrature.py python3-sympy-0.7.3/sympy/integrals/tests/test_quadrature.py --- python3-sympy-0.7.2/sympy/integrals/tests/test_quadrature.py 1970-01-01 00:00:00.000000000 +0000 +++ python3-sympy-0.7.3/sympy/integrals/tests/test_quadrature.py 2013-07-13 17:53:32.000000000 +0000 @@ -0,0 +1,458 @@ +from sympy.core import S +from sympy.integrals.quadrature import (gauss_legendre, gauss_laguerre, + gauss_hermite, gauss_gen_laguerre, + gauss_chebyshev_t, gauss_chebyshev_u, + gauss_jacobi) + +def test_legendre(): + x, w = gauss_legendre(1, 17) + assert [str(r) for r in x] == ['0'] + assert [str(r) for r in w] == ['2.0000000000000000'] + + x, w = gauss_legendre(2, 17) + assert [str(r) for r in x] == ['-0.57735026918962576', + '0.57735026918962576'] + assert [str(r) for r in w] == ['1.0000000000000000', '1.0000000000000000'] + + x, w = gauss_legendre(3, 17) + assert [str(r) for r in x] == ['-0.77459666924148338', '0', + '0.77459666924148338'] + assert [str(r) for r in w] == ['0.55555555555555556', + '0.88888888888888889', '0.55555555555555556'] + + x, w = gauss_legendre(4, 17) + assert [str(r) for r in x] == ['-0.86113631159405258', + '-0.33998104358485626', '0.33998104358485626', + '0.86113631159405258'] + assert [str(r) for r in w] == ['0.34785484513745386', + '0.65214515486254614', '0.65214515486254614', + '0.34785484513745386'] + +def test_legendre_precise(): + x, w = gauss_legendre(3, 40) + assert [str(r) for r in x] == \ + ['-0.7745966692414833770358530799564799221666', '0', + '0.7745966692414833770358530799564799221666'] + assert [str(r) for r in w] == \ + ['0.5555555555555555555555555555555555555556', + '0.8888888888888888888888888888888888888889', + '0.5555555555555555555555555555555555555556'] + +def test_laguerre(): + x, w = gauss_laguerre(1, 17) + assert [str(r) for r in x] == ['1.0000000000000000'] + assert [str(r) for r in w] == ['1.0000000000000000'] + + x, w = gauss_laguerre(2, 17) + assert [str(r) for r in x] == ['0.58578643762690495', + '3.4142135623730950'] + assert [str(r) for r in w] == ['0.85355339059327376', + '0.14644660940672624'] + + x, w = gauss_laguerre(3, 17) + assert [str(r) for r in x] == [ + '0.41577455678347908', + '2.2942803602790417', + '6.2899450829374792', + ] + assert [str(r) for r in w] == [ + '0.71109300992917302', + '0.27851773356924085', + '0.010389256501586136', + ] + + x, w = gauss_laguerre(4, 17) + assert [str(r) for r in x] == ['0.32254768961939231', '1.7457611011583466', + '4.5366202969211280', '9.3950709123011331'] + assert [str(r) for r in w] == ['0.60315410434163360', + '0.35741869243779969', '0.038887908515005384', + '0.00053929470556132745'] + + x, w = gauss_laguerre(5, 17) + assert [str(r) for r in x] == ['0.26356031971814091', '1.4134030591065168', + '3.5964257710407221', '7.0858100058588376', '12.640800844275783'] + assert [str(r) for r in w] == ['0.52175561058280865', + '0.39866681108317593', '0.075942449681707595', + '0.0036117586799220485', '2.3369972385776228e-5'] + +def test_laguerre_precise(): + x, w = gauss_laguerre(3, 40) + assert [str(r) for r in x] == \ + ['0.4157745567834790833115338731282744735466', + '2.294280360279041719822050361359593868960', + '6.289945082937479196866415765512131657493'] + assert [str(r) for r in w] == \ + ['0.7110930099291730154495901911425944313094', + '0.2785177335692408488014448884567264810349', + '0.01038925650158613574896492040067908765572'] + +def test_hermite(): + x, w = gauss_hermite(1, 17) + assert [str(r) for r in x] == ['0'] + assert [str(r) for r in w] == ['1.7724538509055160'] + + x, w = gauss_hermite(2, 17) + assert [str(r) for r in x] == ['-0.70710678118654752', + '0.70710678118654752'] + + assert [str(r) for r in w] == ['0.88622692545275801', + '0.88622692545275801'] + + x, w = gauss_hermite(3, 17) + assert [str(r) for r in x] == [ + '-1.2247448713915890', + '0', + '1.2247448713915890'] + assert [str(r) for r in w] == [ + '0.29540897515091934', + '1.1816359006036774', + '0.29540897515091934'] + + x, w = gauss_hermite(4, 17) + assert [str(r) for r in x] == [ + '-1.6506801238857846', + '-0.52464762327529032', + '0.52464762327529032', + '1.6506801238857846' + ] + assert [str(r) for r in w] == [ + '0.081312835447245177', + '0.80491409000551284', + '0.80491409000551284', + '0.081312835447245177' + ] + + x, w = gauss_hermite(5, 17) + assert [str(r) for r in x] == [ + '-2.0201828704560856', + '-0.95857246461381851', + '0', + '0.95857246461381851', + '2.0201828704560856' + ] + assert [str(r) for r in w] == [ + '0.019953242059045913', + '0.39361932315224116', + '0.94530872048294188', + '0.39361932315224116', + '0.019953242059045913' + ] + +def test_hermite_precise(): + x, w = gauss_hermite(3, 40) + assert [str(r) for r in x] == [ + '-1.224744871391589049098642037352945695983', + '0', + '1.224744871391589049098642037352945695983' + ] + assert [str(r) for r in w] == [ + '0.2954089751509193378830279138901908637996', + '1.181635900603677351532111655560763455198', + '0.2954089751509193378830279138901908637996' + ] + +def test_gen_laguerre(): + x, w = gauss_gen_laguerre(1, -S.Half, 17) + assert [str(r) for r in x] == ['0.50000000000000000'] + assert [str(r) for r in w] == ['1.7724538509055160'] + + x, w = gauss_gen_laguerre(2, -S.Half, 17) + assert [str(r) for r in x] == ['0.27525512860841095', + '2.7247448713915890'] + assert [str(r) for r in w] == ['1.6098281800110257', + '0.16262567089449035'] + + x, w = gauss_gen_laguerre(3, -S.Half, 17) + assert [str(r) for r in x] == ['0.19016350919348813', + '1.7844927485432516', + '5.5253437422632603'] + assert [str(r) for r in w] == ['1.4492591904487850', + '0.31413464064571329', + '0.0090600198110176913'] + + x, w = gauss_gen_laguerre(4, -S.Half, 17) + assert [str(r) for r in x] == ['0.14530352150331709', + '1.3390972881263614', + '3.9269635013582872', + '8.5886356890120343'] + assert [str(r) for r in w] ==['1.3222940251164826', + '0.41560465162978376', + '0.034155966014826951', + '0.00039920814442273524'] + + x, w = gauss_gen_laguerre(5, -S.Half, 17) + assert [str(r) for r in x] ==['0.11758132021177814', + '1.0745620124369040', + '3.0859374437175500', + '6.4147297336620305', + '11.807189489971737'] + assert [str(r) for r in w] ==['1.2217252674706516', + '0.48027722216462937', + '0.067748788910962126', + '0.0026872914935624654', + '1.5280865710465241e-5'] + + x, w = gauss_gen_laguerre(1, 2, 17) + assert [str(r) for r in x] ==['3.0000000000000000'] + assert [str(r) for r in w] == ['2.0000000000000000'] + + x, w = gauss_gen_laguerre(2, 2, 17) + assert [str(r) for r in x] == ['2.0000000000000000', + '6.0000000000000000'] + assert [str(r) for r in w] ==['1.5000000000000000', + '0.50000000000000000'] + + x, w = gauss_gen_laguerre(3, 2, 17) + assert [str(r) for r in x] ==['1.5173870806774125', + '4.3115831337195203', + '9.1710297856030672'] + assert [str(r) for r in w] ==['1.0374949614904253', + '0.90575000470306537', + '0.056755033806509347'] + + x, w = gauss_gen_laguerre(4, 2, 17) + assert [str(r) for r in x] ==['1.2267632635003021', + '3.4125073586969460', + '6.9026926058516134', + '12.458036771951139'] + assert [str(r) for r in w] ==['0.72552499769865438', + '1.0634242919791946', + '0.20669613102835355', + '0.0043545792937974889'] + + x, w = gauss_gen_laguerre(5, 2, 17) + assert [str(r) for r in x] ==['1.0311091440933816', + '2.8372128239538217', + '5.6202942725987079', + '9.6829098376640271', + '15.828473921690062'] + assert [str(r) for r in w] == ['0.52091739683509184', + '1.0667059331592211', + '0.38354972366693113', + '0.028564233532974658', + '0.00026271280578124935'] + +def test_gen_laguerre_precise(): + x, w = gauss_gen_laguerre(3, -S.Half, 40) + assert [str(r) for r in x] ==['0.1901635091934881328718554276203028970878', + '1.784492748543251591186722461957367638500', + '5.525343742263260275941422110422329464413'] + assert [str(r) for r in w] == ['1.449259190448785048183829411195134343108', + '0.3141346406457132878326231270167565378246', + '0.009060019811017691281714945129254301865020'] + + x, w = gauss_gen_laguerre(3, 2, 40) + assert [str(r) for r in x] == ['1.517387080677412495020323111016672547482', + '4.311583133719520302881184669723530562299', + '9.171029785603067202098492219259796890218'] + assert [str(r) for r in w] ==['1.037494961490425285817554606541269153041', + '0.9057500047030653669269785048806009945254', + '0.05675503380650934725546688857812985243312'] + +def test_chebyshev_t(): + x, w = gauss_chebyshev_t(1, 17) + assert [str(r) for r in x] == ['0'] + assert [str(r) for r in w] == ['3.1415926535897932'] + + x, w = gauss_chebyshev_t(2, 17) + assert [str(r) for r in x] == ['0.70710678118654752', + '-0.70710678118654752'] + assert [str(r) for r in w] == ['1.5707963267948966', + '1.5707963267948966'] + + x, w = gauss_chebyshev_t(3, 17) + assert [str(r) for r in x] == ['0.86602540378443865', + '0', + '-0.86602540378443865'] + assert [str(r) for r in w] == ['1.0471975511965977', + '1.0471975511965977', + '1.0471975511965977'] + + x, w = gauss_chebyshev_t(4, 17) + assert [str(r) for r in x] == ['0.92387953251128676', + '0.38268343236508977', + '-0.38268343236508977', + '-0.92387953251128676'] + + assert [str(r) for r in w] == ['0.78539816339744831', + '0.78539816339744831', + '0.78539816339744831', + '0.78539816339744831'] + + x, w = gauss_chebyshev_t(5, 17) + assert [str(r) for r in x] == ['0.95105651629515357', + '0.58778525229247313', + '0', + '-0.58778525229247313', + '-0.95105651629515357'] + + assert [str(r) for r in w] == ['0.62831853071795865', + '0.62831853071795865', + '0.62831853071795865', + '0.62831853071795865', + '0.62831853071795865'] + +def test_chebyshev_t_precise(): + x, w = gauss_chebyshev_t(3, 40) + assert [str(r) for r in x] == [ + '0.8660254037844386467637231707529361834714', + '0', + '-0.8660254037844386467637231707529361834714'] + assert [str(r) for r in w] == [ + '1.047197551196597746154214461093167628066', + '1.047197551196597746154214461093167628066', + '1.047197551196597746154214461093167628066'] + +def test_chebyshev_u(): + x, w = gauss_chebyshev_u(1, 17) + assert [str(r) for r in x] == ['0'] + assert [str(r) for r in w] == ['1.5707963267948966'] + + x, w = gauss_chebyshev_u(2, 17) + assert [str(r) for r in x] == ['0.50000000000000000', + '-0.50000000000000000'] + assert [str(r) for r in w] == ['0.78539816339744831', + '0.78539816339744831'] + + x, w = gauss_chebyshev_u(3, 17) + assert [str(r) for r in x] == ['0.70710678118654752', + '0', + '-0.70710678118654752'] + assert [str(r) for r in w] == ['0.39269908169872415', + '0.78539816339744831', + '0.39269908169872415'] + + x, w = gauss_chebyshev_u(4, 17) + assert [str(r) for r in x] == ['0.80901699437494742', + '0.30901699437494742', + '-0.30901699437494742', + '-0.80901699437494742'] + assert [str(r) for r in w] == ['0.21707871342270599', + '0.56831944997474231', + '0.56831944997474231', + '0.21707871342270599'] + + x, w = gauss_chebyshev_u(5, 17) + assert [str(r) for r in x] == ['0.86602540378443865', + '0.50000000000000000', + '0', + '-0.50000000000000000', + '-0.86602540378443865'] + assert [str(r) for r in w] == ['0.13089969389957472', + '0.39269908169872415', + '0.52359877559829887', + '0.39269908169872415', + '0.13089969389957472'] + +def test_chebyshev_u_precise(): + x, w = gauss_chebyshev_u(3, 40) + assert [str(r) for r in x] == [ + '0.7071067811865475244008443621048490392848', + '0', + '-0.7071067811865475244008443621048490392848'] + assert [str(r) for r in w] == [ + '0.3926990816987241548078304229099378605246', + '0.7853981633974483096156608458198757210493', + '0.3926990816987241548078304229099378605246'] + +def test_jacobi(): + x, w = gauss_jacobi(1, -S.Half, S.Half, 17) + assert [str(r) for r in x] == ['0.50000000000000000'] + assert [str(r) for r in w] == ['3.1415926535897932'] + + x, w = gauss_jacobi(2, -S.Half, S.Half, 17) + assert [str(r) for r in x] == ['0.80901699437494742', + '-0.30901699437494742'] + assert [str(r) for r in w] == ['2.2732777998989693', + '0.86831485369082398'] + + x, w = gauss_jacobi(3, -S.Half, S.Half, 17) + assert [str(r) for r in x] == ['-0.62348980185873353', + '0.22252093395631440', + '0.90096886790241913'] + assert [str(r) for r in w] == ['0.33795476356635433', + '1.0973322242791115', + '1.7063056657443274'] + + x, w = gauss_jacobi(4, -S.Half, S.Half, 17) + assert [str(r) for r in x] == ['-0.76604444311897804', + '-0.17364817766693035', + '0.50000000000000000', + '0.93969262078590838'] + assert [str(r) for r in w] == ['0.16333179083642836', + '0.57690240318269103', + '1.0471975511965977', + '1.3541609083740761'] + + x, w = gauss_jacobi(5, -S.Half, S.Half, 17) + assert [str(r) for r in x] == ['-0.84125353283118117', + '-0.41541501300188643', + '0.14231483827328514', + '0.65486073394528506', + '0.95949297361449739'] + assert [str(r) for r in w] == ['0.090675770007435371', + '0.33391416373675607', + '0.65248870981926643', + '0.94525424081394926', + '1.1192597692123861'] + + x, w = gauss_jacobi(1, 2, 3, 17) + assert [str(r) for r in x] == ['0.14285714285714286'] + assert [str(r) for r in w] == ['1.0666666666666667'] + + x, w = gauss_jacobi(2, 2, 3, 17) + assert [str(r) for r in x] == ['0.46247529557426437', + '-0.24025307335204215'] + assert [str(r) for r in w] == ['0.58152042148828007', + '0.48514624517838660'] + + x, w = gauss_jacobi(3, 2, 3, 17) + assert [str(r) for r in x] == ['-0.46115870378089762', + '0.10438533038323902', + '0.62950064612493132'] + assert [str(r) for r in w] == ['0.17937613502213266', + '0.61595640991147154', + '0.27133412173306246'] + + x, w = gauss_jacobi(4, 2, 3, 17) + assert [str(r) for r in x] == ['-0.59903470850824782', + '-0.14761105199952565', + '0.32554377081188859', + '0.72879429738819258'] + assert [str(r) for r in w] == ['0.067809641836772187', + '0.38956404952032481', + '0.47995970868024150', + '0.12933326662932816'] + + x, w = gauss_jacobi(5, 2, 3, 17) + assert [str(r) for r in x] == ['-0.69045775012676106', + '-0.32651993134900065', + '0.082337849552034905', + '0.47517887061283164', + '0.79279429464422850'] + assert [str(r) for r in w] ==['0.027410178066337099', + '0.21291786060364828', + '0.43908437944395081', + '0.32220656547221822', + '0.065047683080512268'] + +def test_jacobi_precise(): + x, w = gauss_jacobi(3, -S.Half, S.Half, 40) + assert [str(r) for r in x] == [ + '-0.6234898018587335305250048840042398106323', + '0.2225209339563144042889025644967947594664', + '0.9009688679024191262361023195074450511659'] + assert [str(r) for r in w] == [ + '0.3379547635663543330553835737094171534907', + '1.097332224279111467485302294320899710461', + '1.706305665744327437921957515249186020246'] + + x, w = gauss_jacobi(3, 2, 3, 40) + assert [str(r) for r in x] == [ + '-0.4611587037808976179121958105554375981274', + '0.1043853303832390210914918407615869143233', + '0.6295006461249313240934312425211234110769'] + assert [str(r) for r in w] == [ + '0.1793761350221326596137764371503859752628', + '0.6159564099114715430909548532229749439714', + '0.2713341217330624639619353762933057474325'] diff -Nru python3-sympy-0.7.2/sympy/integrals/tests/test_rationaltools.py python3-sympy-0.7.3/sympy/integrals/tests/test_rationaltools.py --- python3-sympy-0.7.2/sympy/integrals/tests/test_rationaltools.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/integrals/tests/test_rationaltools.py 2013-07-13 17:53:32.000000000 +0000 @@ -6,6 +6,7 @@ half = S(1)/2 + def test_ratint(): assert ratint(S(0), x) == 0 assert ratint(S(7), x) == 7*x @@ -14,13 +15,13 @@ assert ratint(2*x, x) == x**2 assert ratint(-2*x, x) == -x**2 - assert ratint(8*x**7+2*x+1, x) == x**8+x**2+x + assert ratint(8*x**7 + 2*x + 1, x) == x**8 + x**2 + x f = S(1) g = x + 1 assert ratint(f / g, x) == log(x + 1) - assert ratint((f,g), x) == log(x + 1) + assert ratint((f, g), x) == log(x + 1) f = x**3 - x g = x - 1 @@ -41,19 +42,19 @@ assert ratint(f/g, x, real=False) == I*log(x + I)/2 - I*log(x - I)/2 f = S(36) - g = x**5-2*x**4-2*x**3+4*x**2+x-2 + g = x**5 - 2*x**4 - 2*x**3 + 4*x**2 + x - 2 assert ratint(f/g, x) == \ -4*log(x + 1) + 4*log(x - 2) + (12*x + 6)/(x**2 - 1) - f = x**4-3*x**2+6 - g = x**6-5*x**4+5*x**2+4 + f = x**4 - 3*x**2 + 6 + g = x**6 - 5*x**4 + 5*x**2 + 4 assert ratint(f/g, x) == \ atan(x) + atan(x**3) + atan(x/2 - 3*x**S(3)/2 + S(1)/2*x**5) - f = x**7-24*x**4-4*x**2+8*x-8 - g = x**8+6*x**6+12*x**4+8*x**2 + f = x**7 - 24*x**4 - 4*x**2 + 8*x - 8 + g = x**8 + 6*x**6 + 12*x**4 + 8*x**2 assert ratint(f/g, x) == \ (4 + 6*x + 8*x**2 + 3*x**3)/(4*x + 4*x**3 + x**5) + log(x) @@ -62,65 +63,73 @@ -(12 - 16*x + 6*x**2 - 14*x**3)/(4 + 4*x**2 + x**4) - \ 5*sqrt(2)*atan(x*sqrt(2)/2) + S(1)/2*x**2 - 3*log(2 + x**2) - f = x**5-x**4+4*x**3+x**2-x+5 - g = x**4-2*x**3+5*x**2-4*x+4 + f = x**5 - x**4 + 4*x**3 + x**2 - x + 5 + g = x**4 - 2*x**3 + 5*x**2 - 4*x + 4 assert ratint(f/g, x) == \ - x + S(1)/2*x**2 + S(1)/2*log(2-x+x**2) - (4*x-9)/(14-7*x+7*x**2) + \ + x + S(1)/2*x**2 + S(1)/2*log(2 - x + x**2) - (4*x - 9)/(14 - 7*x + 7*x**2) + \ 13*sqrt(7)*atan(-S(1)/7*sqrt(7) + 2*x*sqrt(7)/7)/49 - assert ratint(1/(x**2+x+1), x) == \ + assert ratint(1/(x**2 + x + 1), x) == \ 2*sqrt(3)*atan(sqrt(3)/3 + 2*x*sqrt(3)/3)/3 - assert ratint(1/(x**3+1), x) == \ - -log(1 - x + x**2)/6 + log(1 + x)/3 + sqrt(3)*atan(-sqrt(3)/3 + 2*x*sqrt(3)/3)/3 + assert ratint(1/(x**3 + 1), x) == \ + -log(1 - x + x**2)/6 + log(1 + x)/3 + sqrt(3)*atan(-sqrt(3) + /3 + 2*x*sqrt(3)/3)/3 - assert ratint(1/(x**2+x+1), x, real=False) == \ + assert ratint(1/(x**2 + x + 1), x, real=False) == \ -I*3**half*log(half + x - half*I*3**half)/3 + \ I*3**half*log(half + x + half*I*3**half)/3 - assert ratint(1/(x**3+1), x, real=False) == log(1 + x)/3 + \ + assert ratint(1/(x**3 + 1), x, real=False) == log(1 + x)/3 + \ (-S(1)/6 + I*3**half/6)*log(-half + x + I*3**half/2) + \ (-S(1)/6 - I*3**half/6)*log(-half + x - I*3**half/2) # Issue 1892 - assert ratint(1/(x*(a+b*x)**3), x) == \ - (sqrt(a**(-6))*log(x + (a - a**4*sqrt(a**(-6)))/(2*b)) + - (3*a + 2*b*x)/(2*a**2*b**2*x**2 + 4*b*x*a**3 + 2*a**4) - - sqrt(a**(-6))*log(x + (a + a**4*sqrt(a**(-6)))/(2*b))) + assert ratint(1/(x*(a + b*x)**3), x) == \ + (3*a + 2*b*x)/(2*a**4 + 4*a**3*b*x + 2*a**2*b**2*x**2) + ( + log(x) - log(a/b + x))/a**3 assert ratint(x/(1 - x**2), x) == -log(x**2 - 1)/2 assert ratint(-x/(1 - x**2), x) == log(x**2 - 1)/2 + assert ratint((x/4 - 4/(1 - x)).diff(x), x) == x/4 + 4/(x - 1) + ans = atan(x) assert ratint(1/(x**2 + 1), x, symbol=x) == ans assert ratint(1/(x**2 + 1), x, symbol='x') == ans assert ratint(1/(x**2 + 1), x, symbol=a) == ans + def test_ratint_logpart(): - assert ratint_logpart(x, x**2-9, x, t) == \ + assert ratint_logpart(x, x**2 - 9, x, t) == \ [(Poly(x**2 - 9, x), Poly(-2*t + 1, t))] - assert ratint_logpart(x**2, x**3-5, x, t) == \ + assert ratint_logpart(x**2, x**3 - 5, x, t) == \ [(Poly(x**3 - 5, x), Poly(-3*t + 1, t))] + def test_issue_2315(): assert ratint(1/(x**2 + 16), x) == atan(x/4)/4 + def test_issue_2150(): - assert ratint(1/(x**2 + a**2), x) == \ - sqrt(-1/a**2)*log(x + a**2*sqrt(-1/a**2))/2 - sqrt(-1/a**2)*log(x - - a**2*sqrt(-1/a**2))/2 + assert ratint( + 1/(x**2 + a**2), x) == (-I*log(-I*a + x)/2 + I*log(I*a + x)/2)/a + def test_issue_2718(): a, b, c = symbols('a,b,c', positive=True) assert simplify(ratint(a/(b*c*x**2 + a**2 + b*a), x)) == \ - sqrt(a)*atan(sqrt(b)*sqrt(c)*x/(sqrt(a)*sqrt(a + b)))/(sqrt(b)*sqrt(c)*sqrt(a + b)) + sqrt(a)*atan(sqrt( + b)*sqrt(c)*x/(sqrt(a)*sqrt(a + b)))/(sqrt(b)*sqrt(c)*sqrt(a + b)) + def test_issue_2882(): u = symbols('u') assert integrate(1/(u**2 + 1)) == atan(u) + def test_log_to_atan(): f, g = (Poly(x + S(1)/2, x, domain='QQ'), Poly(sqrt(3)/2, x, domain='EX')) fg_ans = 2*atan(2*sqrt(3)*x/3 + sqrt(3)/3) diff -Nru python3-sympy-0.7.2/sympy/integrals/tests/test_rde.py python3-sympy-0.7.3/sympy/integrals/tests/test_rde.py --- python3-sympy-0.7.2/sympy/integrals/tests/test_rde.py 1970-01-01 00:00:00.000000000 +0000 +++ python3-sympy-0.7.3/sympy/integrals/tests/test_rde.py 2013-07-13 17:53:32.000000000 +0000 @@ -0,0 +1,178 @@ +"""Most of these tests come from the examples in Bronstein's book.""" + +from sympy import Poly, S, symbols, oo, I +from sympy.integrals.risch import (DifferentialExtension, + NonElementaryIntegralException) +from sympy.integrals.rde import (order_at, order_at_oo, weak_normalizer, + normal_denom, special_denom, bound_degree, spde, solve_poly_rde, + no_cancel_equal, cancel_primitive, cancel_exp, rischDE) + +from sympy.utilities.pytest import raises, XFAIL +from sympy.abc import x, t, z, n + +t0, t1, t2, k = symbols('t:3 k') + + +def test_order_at(): + a = Poly(t**4, t) + b = Poly((t**2 + 1)**3*t, t) + p1 = Poly(t, t) + p2 = Poly(1 + t**2, t) + assert order_at(a, p1, t) == 4 + assert order_at(b, p1, t) == 1 + assert order_at(a, p2, t) == 0 + assert order_at(b, p2, t) == 3 + assert order_at(Poly(0, t), Poly(t, t), t) == oo + assert order_at_oo(Poly(t**2 - 1, t), Poly(t + 1), t) == \ + order_at_oo(Poly(t - 1, t), Poly(1, t), t) == -1 + assert order_at_oo(Poly(0, t), Poly(1, t), t) == oo + + +def test_weak_normalizer(): + a = Poly((1 + x)*t**5 + 4*t**4 + (-1 - 3*x)*t**3 - 4*t**2 + (-2 + 2*x)*t, t) + d = Poly(t**4 - 3*t**2 + 2, t) + DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(t, t)]}) + r = weak_normalizer(a, d, DE, z) + assert r == (Poly(t**5 - t**4 - 4*t**3 + 4*t**2 + 4*t - 4, t), + (Poly((1 + x)*t**2 + x*t, t), Poly(t + 1, t))) + assert weak_normalizer(r[1][0], r[1][1], DE) == (Poly(1, t), r[1]) + r = weak_normalizer(Poly(1 + t**2), Poly(t**2 - 1, t), DE, z) + assert r == (Poly(t**4 - 2*t**2 + 1, t), (Poly(-3*t**2 + 1, t), Poly(t**2 - 1, t))) + assert weak_normalizer(r[1][0], r[1][1], DE, z) == (Poly(1, t), r[1]) + DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(1 + t**2)]}) + r = weak_normalizer(Poly(1 + t**2), Poly(t, t), DE, z) + assert r == (Poly(t, t), (Poly(0, t), Poly(1, t))) + assert weak_normalizer(r[1][0], r[1][1], DE, z) == (Poly(1, t), r[1]) + + +def test_normal_denom(): + DE = DifferentialExtension(extension={'D': [Poly(1, x)]}) + raises(NonElementaryIntegralException, lambda: normal_denom(Poly(1, x), Poly(1, x), + Poly(1, x), Poly(x, x), DE)) + fa, fd = Poly(t**2 + 1, t), Poly(1, t) + ga, gd = Poly(1, t), Poly(t**2, t) + DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(t**2 + 1, t)]}) + assert normal_denom(fa, fd, ga, gd, DE) == \ + (Poly(t, t), (Poly(t**3 - t**2 + t - 1, t), Poly(1, t)), (Poly(1, t), + Poly(1, t)), Poly(t, t)) + + +def test_special_denom(): + # TODO: add more tests here + DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(t, t)]}) + assert special_denom(Poly(1, t), Poly(t**2, t), Poly(1, t), Poly(t**2 - 1, t), + Poly(t, t), DE) == \ + (Poly(1, t), Poly(t**2 - 1, t), Poly(t**2 - 1, t), Poly(t, t)) +# assert special_denom(Poly(1, t), Poly(2*x, t), Poly((1 + 2*x)*t, t), DE) == 1 + + # Issue 841 + # Note, this isn't a very good test, because the denominator is just 1, + # but at least it tests the exp cancellation case + DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(-2*x*t0, t0), + Poly(I*k*t1, t1)]}) + DE.decrement_level() + assert special_denom(Poly(1, t0), Poly(I*k, t0), Poly(1, t0), Poly(t0, t0), + Poly(1, t0), DE) == \ + (Poly(1, t0), Poly(I*k, t0), Poly(t0, t0), Poly(1, t0)) + + +@XFAIL +def test_bound_degree_fail(): + # Primitive + DE = DifferentialExtension(extension={'D': [Poly(1, x), + Poly(t0/x**2, t0), Poly(1/x, t)]}) + assert bound_degree(Poly(t**2, t), Poly(-(1/x**2*t**2 + 1/x), t), + Poly((2*x - 1)*t**4 + (t0 + x)/x*t**3 - (t0 + 4*x**2)/2*x*t**2 + x*t, + t), DE) == 3 + + +def test_bound_degree(): + # Base + DE = DifferentialExtension(extension={'D': [Poly(1, x)]}) + assert bound_degree(Poly(1, x), Poly(-2*x, x), Poly(1, x), DE) == 0 + + # Primitive (see above test_bound_degree_fail) + # TODO: Add test for when the degree bound becomes larger after limited_integrate + # TODO: Add test for db == da - 1 case + + # Exp + # TODO: Add tests + # TODO: Add test for when the degree becomes larger after parametric_log_deriv() + + # Nonlinear + DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(t**2 + 1, t)]}) + assert bound_degree(Poly(t, t), Poly((t - 1)*(t**2 + 1), t), Poly(1, t), DE) == 0 + + +def test_spde(): + DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(t**2 + 1, t)]}) + raises(NonElementaryIntegralException, lambda: spde(Poly(t, t), Poly((t - 1)*(t**2 + 1), t), Poly(1, t), 0, DE)) + DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(t, t)]}) + assert spde(Poly(t**2 + x*t*2 + x**2, t), Poly(t**2/x**2 + (2/x - 1)*t, t), + Poly(t**2/x**2 + (2/x - 1)*t, t), 0, DE) == \ + (Poly(0, t), Poly(0, t), 0, Poly(0, t), Poly(1, t)) + DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(t0/x**2, t0), Poly(1/x, t)]}) + assert spde(Poly(t**2, t), Poly(-t**2/x**2 - 1/x, t), + Poly((2*x - 1)*t**4 + (t0 + x)/x*t**3 - (t0 + 4*x**2)/(2*x)*t**2 + x*t, t), 3, DE) == \ + (Poly(0, t), Poly(0, t), 0, Poly(0, t), + Poly(t0*t**2/2 + x**2*t**2 - x**2*t, t)) + DE = DifferentialExtension(extension={'D': [Poly(1, x)]}) + assert spde(Poly(x**2 + x + 1, x), Poly(-2*x - 1, x), Poly(x**5/2 + + 3*x**4/4 + x**3 - x**2 + 1, x), 4, DE) == \ + (Poly(0, x), Poly(x/2 - S(1)/4, x), 2, Poly(x**2 + x + 1, x), Poly(5*x/4, x)) + assert spde(Poly(x**2 + x + 1, x), Poly(-2*x - 1, x), Poly(x**5/2 + + 3*x**4/4 + x**3 - x**2 + 1, x), n, DE) == \ + (Poly(0, x), Poly(x/2 - S(1)/4, x), -2 + n, Poly(x**2 + x + 1, x), Poly(5*x/4, x)) + DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(1, t)]}) + raises(NonElementaryIntegralException, lambda: spde(Poly((t - 1)*(t**2 + 1)**2, t), Poly((t - 1)*(t**2 + 1), t), Poly(1, t), 0, DE)) + +def test_solve_poly_rde_no_cancel(): + # deg(b) large + DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(1 + t**2, t)]}) + assert solve_poly_rde(Poly(t**2 + 1, t), Poly(t**3 + (x + 1)*t**2 + t + x + 2, t), + oo, DE) == Poly(t + x, t) + # deg(b) small + DE = DifferentialExtension(extension={'D': [Poly(1, x)]}) + assert solve_poly_rde(Poly(0, x), Poly(x/2 - S(1)/4, x), oo, DE) == \ + Poly(x**2/4 - x/4, x) + DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(t**2 + 1, t)]}) + assert solve_poly_rde(Poly(2, t), Poly(t**2 + 2*t + 3, t), 1, DE) == \ + Poly(t + 1, t, x) + # deg(b) == deg(D) - 1 + DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(t**2 + 1, t)]}) + assert no_cancel_equal(Poly(1 - t, t), + Poly(t**3 + t**2 - 2*x*t - 2*x, t), oo, DE) == \ + (Poly(t**2, t), 1, Poly((-2 - 2*x)*t - 2*x, t)) + + +def test_solve_poly_rde_cancel(): + # exp + DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(t, t)]}) + assert cancel_exp(Poly(2*x, t), Poly(2*x, t), 0, DE) == \ + Poly(1, t) + assert cancel_exp(Poly(2*x, t), Poly((1 + 2*x)*t, t), 1, DE) == \ + Poly(t, t) + # TODO: Add more exp tests, including tests that require is_deriv_in_field() + + # primitive + DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(1/x, t)]}) + + # If the DecrementLevel context manager is working correctly, this shouldn't + # cause any problems with the further tests. + raises(NonElementaryIntegralException, lambda: cancel_primitive(Poly(1, t), Poly(t, t), oo, DE)) + + assert cancel_primitive(Poly(1, t), Poly(t + 1/x, t), 2, DE) == \ + Poly(t, t) + assert cancel_primitive(Poly(4*x, t), Poly(4*x*t**2 + 2*t/x, t), 3, DE) == \ + Poly(t**2, t) + + # TODO: Add more primitive tests, including tests that require is_deriv_in_field() + + +def test_rischDE(): + # TODO: Add more tests for rischDE, including ones from the text + DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(t, t)]}) + DE.decrement_level() + assert rischDE(Poly(-2*x, x), Poly(1, x), Poly(1 - 2*x - 2*x**2, x), + Poly(1, x), DE) == \ + (Poly(x + 1, x), Poly(1, x)) diff -Nru python3-sympy-0.7.2/sympy/integrals/tests/test_risch.py python3-sympy-0.7.3/sympy/integrals/tests/test_risch.py --- python3-sympy-0.7.2/sympy/integrals/tests/test_risch.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/integrals/tests/test_risch.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,215 +1,623 @@ -from sympy import Rational, sqrt, symbols, sin, exp, log, sinh, cosh, cos, pi, \ - I, S, erf, tan, asin, asinh, acos, acosh, Function, Derivative, diff, simplify, \ - LambertW -from sympy.integrals.risch import heurisch, components -from sympy.utilities.pytest import XFAIL, skip, slow - -x, y, z = symbols('x,y,z') -f = Function('f') - -def test_components(): - assert components(x*y, x) == set([x]) - assert components(1/(x+y), x) == set([x]) - assert components(sin(x), x) == set([sin(x), x]) - assert components(sin(x)*sqrt(log(x)), x) == \ - set([log(x), sin(x), sqrt(log(x)), x]) - assert components(x*sin(exp(x)*y), x) == \ - set([sin(y*exp(x)), x, exp(x)]) - assert components(x**Rational(17,54)/sqrt(sin(x)), x) == \ - set([sin(x), x**Rational(1,54), sqrt(sin(x)), x]) - - assert components(f(x), x) == \ - set([x, f(x)]) - assert components(Derivative(f(x),x), x) == \ - set([x, f(x), Derivative(f(x), x)]) - assert components(f(x)*diff(f(x), x), x) == \ - set([x, f(x), Derivative(f(x), x), Derivative(f(x), x)]) - -def test_heurisch_polynomials(): - assert heurisch(1, x) == x - assert heurisch(x, x) == x**2/2 - assert heurisch(x**17, x) == x**18/18 - -def test_heurisch_fractions(): - assert heurisch(1/x, x) == log(x) - assert heurisch(1/(2 + x), x) == log(x + 2) - assert heurisch(1/(x+sin(y)), x) == log(x+sin(y)) - - # Up to a constant, where C = 5*pi*I/12, Mathematica gives identical - # result in the first case. The difference is because sympy changes - # signs of expressions without any care. - # XXX ^ ^ ^ is this still correct? - assert heurisch(5*x**5/(2*x**6 - 5), x) in [5*log(2*x**6 - 5) / 12, 5*log(-2*x**6 + 5) / 12] - assert heurisch(5*x**5/(2*x**6 + 5), x) == 5*log(2*x**6 + 5) / 12 - - assert heurisch(1/x**2, x) == -1/x - assert heurisch(-1/x**5, x) == 1/(4*x**4) - -def test_heurisch_log(): - assert heurisch(log(x), x) == x*log(x) - x - assert heurisch(log(3*x), x) == -x + x*log(3) + x*log(x) - assert heurisch(log(x**2), x) in [x*log(x**2) - 2*x, 2*x*log(x) - 2*x] - -def test_heurisch_exp(): - assert heurisch(exp(x), x) == exp(x) - assert heurisch(exp(-x), x) == -exp(-x) - assert heurisch(exp(17*x), x) == exp(17*x) / 17 - assert heurisch(x*exp(x), x) == x*exp(x) - exp(x) - assert heurisch(x*exp(x**2), x) == exp(x**2) / 2 - - assert heurisch(exp(-x**2), x) is None - - assert heurisch(2**x, x) == 2**x/log(2) - assert heurisch(x*2**x, x) == x*2**x/log(2) - 2**x*log(2)**(-2) - -def test_heurisch_trigonometric(): - assert heurisch(sin(x), x) == -cos(x) - assert heurisch(pi*sin(x)+1, x) == x-pi*cos(x) - - assert heurisch(cos(x), x) == sin(x) - assert heurisch(tan(x), x) in [ - log(1 + tan(x)**2)/2, - log(tan(x) + I) + I*x, - log(tan(x) - I) - I*x, - ] - - assert heurisch(sin(x)*sin(y), x) == -cos(x)*sin(y) - assert heurisch(sin(x)*sin(y), y) == -cos(y)*sin(x) - - # gives sin(x) in answer when run via setup.py and cos(x) when run via py.test - assert heurisch(sin(x)*cos(x), x) in [sin(x)**2 / 2, -cos(x)**2 / 2] - assert heurisch(cos(x)/sin(x), x) == log(sin(x)) - - assert heurisch(x*sin(7*x), x) == sin(7*x) / 49 - x*cos(7*x) / 7 - assert heurisch(1/pi/4 * x**2*cos(x), x) == 1/pi/4*(x**2*sin(x) - 2*sin(x) + 2*x*cos(x)) - - assert heurisch(acos(x/4) * asin(x/4), x) == 2*x - (sqrt(16-x**2))*asin(x/4) \ - + (sqrt(16 - x**2))*acos(x/4) + x*asin(x/4)*acos(x/4) - -def test_heurisch_hyperbolic(): - assert heurisch(sinh(x), x) == cosh(x) - assert heurisch(cosh(x), x) == sinh(x) - - assert heurisch(x*sinh(x), x) == x*cosh(x) - sinh(x) - assert heurisch(x*cosh(x), x) == x*sinh(x) - cosh(x) - - assert heurisch(x*asinh(x/2), x) == x**2*asinh(x/2)/2 + asinh(x/2) - x*sqrt(4+x**2)/4 - -def test_heurisch_mixed(): - assert heurisch(sin(x)*exp(x), x) == exp(x)*sin(x)/2 - exp(x)*cos(x)/2 - -def test_heurisch_radicals(): - assert heurisch(1/sqrt(x), x) == 2*sqrt(x) - assert heurisch(1/sqrt(x)**3, x) == -2/sqrt(x) - assert heurisch(sqrt(x)**3, x) == 2*sqrt(x)**5/5 - - assert heurisch(sin(x)*sqrt(cos(x)), x) == -2*sqrt(cos(x))**3/3 - assert heurisch(sin(y*sqrt(x)), x) == 2/y**2*sin(y*sqrt(x)) - \ - 2*sqrt(x)*cos(y*sqrt(x))/y - -def test_heurisch_special(): - assert heurisch(erf(x), x) == x*erf(x) + exp(-x**2)/sqrt(pi) - assert heurisch(exp(-x**2)*erf(x), x) == sqrt(pi)*erf(x)**2 / 4 - -def test_heurisch_symbolic_coeffs(): - assert heurisch(1/(x+y), x) == log(x+y) - assert heurisch(1/(x+sqrt(2)), x) == log(x+sqrt(2)) - assert simplify(diff(heurisch(log(x+y+z), y), y)) == log(x+y+z) - -def test_heurisch_symbolic_coeffs_1130(): - assert heurisch(1/(x**2+y), x) in [I/sqrt(y)*log(x + sqrt(-y))/2 - \ - I/sqrt(y)*log(x - sqrt(-y))/2, I*log(x + I*sqrt(y)) / \ - (2*sqrt(y)) - I*log(x - I*sqrt(y))/(2*sqrt(y))] - -def test_heurisch_hacking(): - assert heurisch(sqrt(1 + 7*x**2), x, hints=[]) == \ - x*sqrt(1+7*x**2)/2 + sqrt(7)*asinh(sqrt(7)*x)/14 - assert heurisch(sqrt(1 - 7*x**2), x, hints=[]) == \ - x*sqrt(1-7*x**2)/2 + sqrt(7)*asin(sqrt(7)*x)/14 - - assert heurisch(1/sqrt(1 + 7*x**2), x, hints=[]) == \ - sqrt(7)*asinh(sqrt(7)*x)/7 - assert heurisch(1/sqrt(1 - 7*x**2), x, hints=[]) == \ - sqrt(7)*asin(sqrt(7)*x)/7 - - assert heurisch(exp(-7*x**2),x,hints=[]) == \ - sqrt(7*pi)*erf(sqrt(7)*x)/14 - - assert heurisch(1/sqrt(9 - 4*x**2), x, hints=[]) == \ - asin(2*x/3)/2 - - assert heurisch(1/sqrt(9 + 4*x**2), x, hints=[]) == \ - asinh(2*x/3)/2 - -def test_heurisch_function(): - df = diff(f(x), x) - - assert heurisch(f(x), x) == None - assert heurisch(f(x)*df, x) == f(x)**2/2 - assert heurisch(f(x)**2 * df, x) == f(x)**3/3 - assert heurisch(df / f(x), x) == log(f(x)) - -def test_issue510(): - assert heurisch(1/(x * (1 + log(x)**2)), x) == I*log(log(x) + I)/2 - \ - I*log(log(x) - I)/2 - -### These are examples from the Poor Man's Integrator -### http://www-sop.inria.fr/cafe/Manuel.Bronstein/pmint/examples/ -# -# NB: correctness assured as ratsimp(diff(g,x) - f) == 0 in maxima -# SymPy is unable to do it :( - -# Besides, they are skipped(), because they take too much time to execute. - -@XFAIL -def test_pmint_rat(): - f = (x**7-24*x**4-4*x**2+8*x-8) / (x**8+6*x**6+12*x**4+8*x**2) - g = (4 + 8*x**2 + 6*x + 3*x**3) / (x*(x**4 + 4*x**2 + 4)) + log(x) - - assert heurisch(f, x) == g - -@XFAIL -def test_pmint_trig(): - f = (x-tan(x)) / tan(x)**2 + tan(x) - g = (-x - tan(x)*x**2 / 2) / tan(x) + log(1+tan(x)**2) / 2 - - assert heurisch(f, x) == g - -@slow -@XFAIL -def test_pmint_logexp(): - f = (1+x+x*exp(x))*(x+log(x)+exp(x)-1)/(x+log(x)+exp(x))**2/x - g = 1/(x+log(x)+exp(x)) + log(x + log(x) + exp(x)) - - assert heurisch(f, x) == g - -@slow -@XFAIL -def test_pmint_erf(): - f = exp(-x**2)*erf(x)/(erf(x)**3-erf(x)**2-erf(x)+1) - g = sqrt(pi)/4 * (-1/(erf(x)-1) - log(erf(x)+1)/2 + log(erf(x)-1)/2) - - assert heurisch(f, x) == g - -def test_pmint_lambertw(): - g = (x**2 + (LambertW(x)*x)**2 - LambertW(x)*x**2)/(x*LambertW(x)) - assert simplify(heurisch(LambertW(x), x) - g) == 0 - -# TODO: convert the rest of PMINT tests: -# Airy functions -# f = (x - AiryAi(x)*AiryAi(1, x)) / (x**2 - AiryAi(x)**2) -# g = Rational(1,2)*ln(x + AiryAi(x)) + Rational(1,2)*ln(x - AiryAi(x)) -# f = x**2 * AiryAi(x) -# g = -AiryAi(x) + AiryAi(1, x)*x - -# Bessel functions -# f = BesselJ(nu + 1, x) / BesselJ(nu, x) -# g = nu*ln(x) - ln(BesselJ(nu, x)) -# f = (nu * BesselJ(nu, x) / x) - BesselJ(nu + 1, x) -# g = BesselJ(nu, x) - -# Whittaker functions -# f = WhittakerW(mu + 1, nu, x) / (WhittakerW(mu, nu, x) * x) -# g = x/2 - mu*ln(x) - ln(WhittakerW(mu, nu, x)) +"""Most of these tests come from the examples in Bronstein's book.""" -# - Wright omega +from sympy import (Poly, I, S, Function, log, symbols, exp, tan, sqrt, + Symbol, Lambda, sin, cos, Eq, Piecewise) +from sympy.integrals.risch import (gcdex_diophantine, frac_in, as_poly_1t, + derivation, splitfactor, splitfactor_sqf, canonical_representation, + hermite_reduce, polynomial_reduce, residue_reduce, residue_reduce_to_basic, + integrate_primitive, integrate_hyperexponential_polynomial, + integrate_hyperexponential, integrate_hypertangent_polynomial, + integrate_nonlinear_no_specials, integer_powers, DifferentialExtension, + risch_integrate, DecrementLevel, NonElementaryIntegral, recognize_log_derivative, + recognize_derivative, laurent_series) +from sympy.utilities.pytest import raises + +from sympy.abc import x, t, nu, z, a, y +t0, t1, t2 = symbols('t:3') +i = Symbol('i') + +def test_gcdex_diophantine(): + assert gcdex_diophantine(Poly(x**4 - 2*x**3 - 6*x**2 + 12*x + 15), + Poly(x**3 + x**2 - 4*x - 4), Poly(x**2 - 1)) == \ + (Poly((-x**2 + 4*x - 3)/5), Poly((x**3 - 7*x**2 + 16*x - 10)/5)) + + +def test_frac_in(): + assert frac_in(Poly((x + 1)/x*t, t), x) == \ + (Poly(t*x + t, x), Poly(x, x)) + assert frac_in((x + 1)/x*t, x) == \ + (Poly(t*x + t, x), Poly(x, x)) + assert frac_in((Poly((x + 1)/x*t, t), Poly(t + 1, t)), x) == \ + (Poly(t*x + t, x), Poly((1 + t)*x, x)) + raises(ValueError, lambda: frac_in((x + 1)/log(x)*t, x)) + assert frac_in(Poly((2 + 2*x + x*(1 + x))/(1 + x)**2, t), x, cancel=True) == \ + (Poly(x + 2, x), Poly(x + 1, x)) + + +def test_as_poly_1t(): + assert as_poly_1t(2/t + t, t, z) in [ + Poly(t + 2*z, t, z), Poly(t + 2*z, z, t)] + assert as_poly_1t(2/t + 3/t**2, t, z) in [ + Poly(2*z + 3*z**2, t, z), Poly(2*z + 3*z**2, z, t)] + assert as_poly_1t(2/((exp(2) + 1)*t), t, z) in [ + Poly(2/(exp(2) + 1)*z, t, z), Poly(2/(exp(2) + 1)*z, z, t)] + assert as_poly_1t(2/((exp(2) + 1)*t) + t, t, z) in [ + Poly(t + 2/(exp(2) + 1)*z, t, z), Poly(t + 2/(exp(2) + 1)*z, z, t)] + + +def test_derivation(): + p = Poly(4*x**4*t**5 + (-4*x**3 - 4*x**4)*t**4 + (-3*x**2 + 2*x**3)*t**3 + + (2*x + 7*x**2 + 2*x**3)*t**2 + (1 - 4*x - 4*x**2)*t - 1 + 2*x, t) + DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(-t**2 - 3/(2*x)*t + 1/(2*x), t)]}) + assert derivation(p, DE) == Poly(-20*x**4*t**6 + (2*x**3 + 16*x**4)*t**5 + + (21*x**2 + 12*x**3)*t**4 + (7*x/2 - 25*x**2 - 12*x**3)*t**3 + + (-5 - 15*x/2 + 7*x**2)*t**2 - (3 - 8*x - 10*x**2 - 4*x**3)/(2*x)*t + + (1 - 4*x**2)/(2*x), t) + assert derivation(Poly(1, t), DE) == Poly(0, t) + assert derivation(Poly(t, t), DE) == DE.d + assert derivation(Poly(t**2 + 1/x*t + (1 - 2*x)/(4*x**2), t), DE) == \ + Poly(-2*t**3 - 4/x*t**2 - (5 - 2*x)/(2*x**2)*t - (1 - 2*x)/(2*x**3), t, domain='ZZ(x)') + DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(1/x, t1), Poly(t, t)]}) + assert derivation(Poly(x*t*t1, t), DE) == Poly(t*t1 + x*t*t1 + t, t) + assert derivation(Poly(x*t*t1, t), DE, coefficientD=True) == \ + Poly((1 + t1)*t, t) + DE = DifferentialExtension(extension={'D': [Poly(1, x)]}) + assert derivation(Poly(x, x), DE) == Poly(1, x) + # Test basic option + assert derivation((x + 1)/(x - 1), DE, basic=True) == -2/(1 - 2*x + x**2) + DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(t, t)]}) + assert derivation((t + 1)/(t - 1), DE, basic=True) == -2*t/(1 - 2*t + t**2) + assert derivation(t + 1, DE, basic=True) == t + + +def test_splitfactor(): + p = Poly(4*x**4*t**5 + (-4*x**3 - 4*x**4)*t**4 + (-3*x**2 + 2*x**3)*t**3 + + (2*x + 7*x**2 + 2*x**3)*t**2 + (1 - 4*x - 4*x**2)*t - 1 + 2*x, t, field=True) + DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(-t**2 - 3/(2*x)*t + 1/(2*x), t)]}) + assert splitfactor(p, DE) == (Poly(4*x**4*t**3 + (-8*x**3 - 4*x**4)*t**2 + + (4*x**2 + 8*x**3)*t - 4*x**2, t), Poly(t**2 + 1/x*t + (1 - 2*x)/(4*x**2), t, domain='ZZ(x)')) + assert splitfactor(Poly(x, t), DE) == (Poly(x, t), Poly(1, t)) + r = Poly(-4*x**4*z**2 + 4*x**6*z**2 - z*x**3 - 4*x**5*z**3 + 4*x**3*z**3 + x**4 + z*x**5 - x**6, t) + DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(1/x, t)]}) + assert splitfactor(r, DE, coefficientD=True) == \ + (Poly(x*z - x**2 - z*x**3 + x**4, t), Poly(-x**2 + 4*x**2*z**2, t)) + assert splitfactor_sqf(r, DE, coefficientD=True) == \ + (((Poly(x*z - x**2 - z*x**3 + x**4, t), 1),), ((Poly(-x**2 + 4*x**2*z**2, t), 1),)) + assert splitfactor(Poly(0, t), DE) == (Poly(0, t), Poly(1, t)) + assert splitfactor_sqf(Poly(0, t), DE) == (((Poly(0, t), 1),), ()) + + +def test_canonical_representation(): + DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(1 + t**2, t)]}) + assert canonical_representation(Poly(x - t, t), Poly(t**2, t), DE) == \ + (Poly(0, t), (Poly(0, t), + Poly(1, t)), (Poly(-t + x, t), + Poly(t**2, t))) + DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(t**2 + 1, t)]}) + assert canonical_representation(Poly(t**5 + t**3 + x**2*t + 1, t), + Poly((t**2 + 1)**3, t), DE) == \ + (Poly(0, t), (Poly(t**5 + t**3 + x**2*t + 1, t), + Poly(t**6 + 3*t**4 + 3*t**2 + 1, t)), (Poly(0, t), Poly(1, t))) + + +def test_hermite_reduce(): + DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(t**2 + 1, t)]}) + assert hermite_reduce(Poly(x - t, t), Poly(t**2, t), DE) == \ + ((Poly(-x, t), Poly(t, t)), (Poly(0, t), Poly(1, t)), (Poly(-x, t), Poly(1, t))) + DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(-t**2 - t/x - (1 - nu**2/x**2), t)]}) + # TODO: Fix this domain='EX' bug + assert hermite_reduce(Poly(x**2*t**5 + x*t**4 - nu**2*t**3 - x*(x**2 + 1)*t**2 - + (x**2 - nu**2)*t - x**5/4, t), Poly(x**2*t**4 + x**2*(x**2 + 2)*t**2 + x**2 + + x**4 + x**6/4, t), DE) == \ + ((Poly(-1 - x**2/4, t, domain='EX'), Poly(t**2 + 1 + x**2/2, t, domain='EX')), + (Poly((2*nu**2 + x**4)/-(2*x**2)*t - (1 + x**2)/x, t, domain='EX', expand=False), + Poly(t**2 + 1 + x**2/2, t, domain='EX')), (Poly(t + 1/x, t, domain='EX'), + Poly(1, t, domain='EX'))) + DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(1/x, t)]}) + assert hermite_reduce(Poly(-t**2 + 2*t + 2, t), + Poly(-x*t**2 + 2*x*t - x, t), DE) == \ + ((Poly(3, t), Poly(t - 1, t)), (Poly(0, t), Poly(1, t)), (Poly(1, t), Poly(x, t))) + assert hermite_reduce(Poly(-x**2*t**6 + (-1 - 2*x**3 + x**4)*t**3 + + (-3 - 3*x**4)*t**2 - 2*x*t - x - 3*x**2, t), + Poly(x**4*t**6 - 2*x**2*t**3 + 1, t), DE) == \ + ((Poly(x**3*t + 1 + x**4, t), Poly(x**3*t**3 - x, t)), (Poly(0, t), + Poly(1, t)), (Poly(-1, t), Poly(x**2, t))) + assert hermite_reduce(Poly((-2 + 3*x)*t**3 + (-1 + x)*t**2 + + (-4*x + 2*x**2)*t + x**2, t), Poly(x*t**6 - 4*x**2*t**5 + + 6*x**3*t**4 - 4*x**4*t**3 + x**5*t**2, t), DE) == \ + ((Poly(3*t**2 + t + 3*x, t), Poly(3*t**4 - 9*x*t**3 + 9*x**2*t**2 - + 3*x**3*t, t)), (Poly(0, t), Poly(1, t)), (Poly(0, t), Poly(1, t))) + + +def test_polynomial_reduce(): + DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(1 + t**2, t)]}) + assert polynomial_reduce(Poly(1 + x*t + t**2, t), DE) == \ + (Poly(t, t), Poly(x*t, t)) + assert polynomial_reduce(Poly(0, t), DE) == \ + (Poly(0, t), Poly(0, t)) + + +def test_laurent_series(): + DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(1, t)]}) + a = Poly(36, t) + d = Poly((t - 2)*(t**2 - 1)**2, t) + F = Poly(t**2 - 1, t) + n = 2 + assert laurent_series(a, d, F, n, DE) == \ + (Poly(-3*t**3 + 3*t**2 - 6*t - 8, t), Poly(t**5 + t**4 - 2*t**3 - 2*t**2 + t + 1, t), + [Poly(-3*t**3 - 6*t**2, t), Poly(2*t**6 + 6*t**5 - 8*t**3, t)]) + + +def test_recognize_derivative(): + DE = DifferentialExtension(extension={'D': [Poly(1, t)]}) + a = Poly(36, t) + d = Poly((t - 2)*(t**2 - 1)**2, t) + assert recognize_derivative(a, d, DE) == False + DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(1/x, t)]}) + a = Poly(2, t) + d = Poly(t**2 - 1, t) + assert recognize_derivative(a, d, DE) == False + assert recognize_derivative(Poly(x*t, t), Poly(1, t), DE) == True + DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(t**2 + 1, t)]}) + assert recognize_derivative(Poly(t, t), Poly(1, t), DE) == True + + +def test_recognize_log_derivative(): + + a = Poly(2*x**2 + 4*x*t - 2*t - x**2*t, t) + d = Poly((2*x + t)*(t + x**2), t) + DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(t, t)]}) + assert recognize_log_derivative(a, d, DE, z) == True + DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(1/x, t)]}) + assert recognize_log_derivative(Poly(t + 1, t), Poly(t + x, t), DE) == True + assert recognize_log_derivative(Poly(2, t), Poly(t**2 - 1), DE) == True + DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(1, t)]}) + assert recognize_log_derivative(Poly(1, t), Poly(t**2 - 2), DE) == False + assert recognize_log_derivative(Poly(1, t), Poly(t**2 + t), DE) == True + + +def test_residue_reduce(): + a = Poly(2*t**2 - t - x**2, t) + d = Poly(t**3 - x**2*t, t) + DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(1/x, t)], 'Tfuncs': [log]}) + assert residue_reduce(a, d, DE, z, invert=False) == \ + ([(Poly(z**2 - S(1)/4, z), Poly((1 + 3*x*z - 6*z**2 - + 2*x**2 + 4*x**2*z**2)*t - x*z + x**2 + 2*x**2*z**2 - 2*z*x**3, t))], False) + assert residue_reduce(a, d, DE, z, invert=True) == \ + ([(Poly(z**2 - S(1)/4, z), Poly(t + 2*x*z, t))], False) + assert residue_reduce(Poly(-2/x, t), Poly(t**2 - 1, t,), DE, z, invert=False) == \ + ([(Poly(z**2 - 1, z), Poly(-z*t - 1, t))], True) + ans = residue_reduce(Poly(-2/x, t), Poly(t**2 - 1, t), DE, z, invert=True) + assert ans == ([(Poly(z**2 - 1, z), Poly(t + z, t))], True) + assert residue_reduce_to_basic(ans[0], DE, z) == -log(-1 + log(x)) + log(1 + log(x)) + + DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(-t**2 - t/x - (1 - nu**2/x**2), t)]}) + # TODO: Skip or make faster + assert residue_reduce(Poly((-2*nu**2 - x**4)/(2*x**2)*t - (1 + x**2)/x, t), + Poly(t**2 + 1 + x**2/2, t), DE, z) == \ + ([(Poly(z + S(1)/2, z, domain='QQ'), Poly(t**2 + 1 + x**2/2, t, domain='EX'))], True) + DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(1 + t**2, t)]}) + assert residue_reduce(Poly(-2*x*t + 1 - x**2, t), + Poly(t**2 + 2*x*t + 1 + x**2, t), DE, z) == \ + ([(Poly(z**2 + S(1)/4, z), Poly(t + x + 2*z, t))], True) + DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(t, t)]}) + assert residue_reduce(Poly(t, t), Poly(t + sqrt(2), t), DE, z) == \ + ([(Poly(z - 1, z), Poly(t + sqrt(2), t))], True) + + +def test_integrate_hyperexponential(): + # TODO: Add tests for integrate_hyperexponential() from the book + a = Poly((1 + 2*t1 + t1**2 + 2*t1**3)*t**2 + (1 + t1**2)*t + 1 + t1**2, t) + d = Poly(1, t) + DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(1 + t1**2, t1), + Poly(t*(1 + t1**2), t)], 'Tfuncs': [tan, Lambda(i, exp(tan(i)))]}) + assert integrate_hyperexponential(a, d, DE) == \ + (exp(2*tan(x))*tan(x) + exp(tan(x)), 1 + t1**2, True) + # exp(2*tan(x))*tan(x) + tan(x) + exp(tan(x)) + a = Poly((t1**3 + (x + 1)*t1**2 + t1 + x + 2)*t, t) + assert integrate_hyperexponential(a, d, DE) == \ + ((x + tan(x))*exp(tan(x)), 0, True) + + a = Poly(t, t) + d = Poly(1, t) + DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(2*x*t, t)], + 'Tfuncs': [Lambda(i, exp(x**2))]}) + + assert integrate_hyperexponential(a, d, DE) == \ + (0, NonElementaryIntegral(exp(x**2), x), False) + + DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(t, t)], 'Tfuncs': [exp]}) + assert integrate_hyperexponential(a, d, DE) == (exp(x), 0, True) + + a = Poly(25*t**6 - 10*t**5 + 7*t**4 - 8*t**3 + 13*t**2 + 2*t - 1, t) + d = Poly(25*t**6 + 35*t**4 + 11*t**2 + 1, t) + assert integrate_hyperexponential(a, d, DE) == \ + (-(11 - 10*exp(x))/(5 + 25*exp(2*x)) + log(1 + exp(2*x)), -1, True) + # -(55 - 50*exp(x))/(25 + 125*exp(2*x)) - x + log(1 + exp(2*x)) + DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(t0, t0), Poly(t0*t, t)], + 'Tfuncs': [exp, Lambda(i, exp(exp(i)))]}) + assert integrate_hyperexponential(Poly(2*t0*t**2, t), Poly(1, t), DE) == (exp(2*exp(x)), 0, True) + + DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(t0, t0), Poly(-t0*t, t)], + 'Tfuncs': [exp, Lambda(i, exp(-exp(i)))]}) + assert integrate_hyperexponential(Poly(-27*exp(9) - 162*t0*exp(9) + + 27*x*t0*exp(9), t), Poly((36*exp(18) + x**2*exp(18) - 12*x*exp(18))*t, t), DE) == \ + (27*exp(exp(x))/(-6*exp(9) + x*exp(9)), 0, True) + + DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(t, t)], 'Tfuncs': [exp]}) + assert integrate_hyperexponential(Poly(x**2/2*t, t), Poly(1, t), DE) == \ + ((2 - 2*x + x**2)*exp(x)/2, 0, True) + assert integrate_hyperexponential(Poly(1 + t, t), Poly(t, t), DE) == \ + (-exp(-x), 1, True) # x - exp(-x) + assert integrate_hyperexponential(Poly(x, t), Poly(t + 1, t), DE) == \ + (0, NonElementaryIntegral(x/(1 + exp(x)), x), False) + + DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(1/x, t0), Poly(2*x*t1, t1)], + 'Tfuncs': [log, Lambda(i, exp(i**2))]}) + assert integrate_hyperexponential(Poly((8*x**7 - 12*x**5 + 6*x**3 - x)*t1**4 + + (8*t0*x**7 - 8*t0*x**6 - 4*t0*x**5 + 2*t0*x**3 + 2*t0*x**2 - t0*x + + 24*x**8 - 36*x**6 - 4*x**5 + 22*x**4 + 4*x**3 - 7*x**2 - x + 1)*t1**3 + + (8*t0*x**8 - 4*t0*x**6 - 16*t0*x**5 - 2*t0*x**4 + 12*t0*x**3 + + t0*x**2 - 2*t0*x + 24*x**9 - 36*x**7 - 8*x**6 + 22*x**5 + 12*x**4 - + 7*x**3 - 6*x**2 + x + 1)*t1**2 + (8*t0*x**8 - 8*t0*x**6 - 16*t0*x**5 + + 6*t0*x**4 + 10*t0*x**3 - 2*t0*x**2 - t0*x + 8*x**10 - 12*x**8 - 4*x**7 + + 2*x**6 + 12*x**5 + 3*x**4 - 9*x**3 - x**2 + 2*x)*t1 + 8*t0*x**7 - + 12*t0*x**6 - 4*t0*x**5 + 8*t0*x**4 - t0*x**2 - 4*x**7 + 4*x**6 + + 4*x**5 - 4*x**4 - x**3 + x**2, t1), Poly((8*x**7 - 12*x**5 + 6*x**3 - + x)*t1**4 + (24*x**8 + 8*x**7 - 36*x**6 - 12*x**5 + 18*x**4 + 6*x**3 - + 3*x**2 - x)*t1**3 + (24*x**9 + 24*x**8 - 36*x**7 - 36*x**6 + 18*x**5 + + 18*x**4 - 3*x**3 - 3*x**2)*t1**2 + (8*x**10 + 24*x**9 - 12*x**8 - + 36*x**7 + 6*x**6 + 18*x**5 - x**4 - 3*x**3)*t1 + 8*x**10 - 12*x**8 + + 6*x**6 - x**4, t1), DE) == \ + (-(x*log(x) - log(x))/(2*x**3 - x + (2*x**2 - 1)*exp(x**2)), + NonElementaryIntegral(exp(x**2)/(exp(x**2) + 1), x), False) + +def test_integrate_hyperexponential_polynomial(): + # Without proper cancellation within integrate_hyperexponential_polynomial(), + # this will take a long time to complete, and will return a complicated + # expression + p = Poly((-28*x**11*t0 - 6*x**8*t0 + 6*x**9*t0 - 15*x**8*t0**2 + + 15*x**7*t0**2 + 84*x**10*t0**2 - 140*x**9*t0**3 - 20*x**6*t0**3 + + 20*x**7*t0**3 - 15*x**6*t0**4 + 15*x**5*t0**4 + 140*x**8*t0**4 - + 84*x**7*t0**5 - 6*x**4*t0**5 + 6*x**5*t0**5 + x**3*t0**6 - x**4*t0**6 + + 28*x**6*t0**6 - 4*x**5*t0**7 + x**9 - x**10 + 4*x**12)/(-8*x**11*t0 + + 28*x**10*t0**2 - 56*x**9*t0**3 + 70*x**8*t0**4 - 56*x**7*t0**5 + + 28*x**6*t0**6 - 8*x**5*t0**7 + x**4*t0**8 + x**12)*t1**2 + + (-28*x**11*t0 - 12*x**8*t0 + 12*x**9*t0 - 30*x**8*t0**2 + + 30*x**7*t0**2 + 84*x**10*t0**2 - 140*x**9*t0**3 - 40*x**6*t0**3 + + 40*x**7*t0**3 - 30*x**6*t0**4 + 30*x**5*t0**4 + 140*x**8*t0**4 - + 84*x**7*t0**5 - 12*x**4*t0**5 + 12*x**5*t0**5 - 2*x**4*t0**6 + + 2*x**3*t0**6 + 28*x**6*t0**6 - 4*x**5*t0**7 + 2*x**9 - 2*x**10 + + 4*x**12)/(-8*x**11*t0 + 28*x**10*t0**2 - 56*x**9*t0**3 + + 70*x**8*t0**4 - 56*x**7*t0**5 + 28*x**6*t0**6 - 8*x**5*t0**7 + + x**4*t0**8 + x**12)*t1 + (-2*x**2*t0 + 2*x**3*t0 + x*t0**2 - + x**2*t0**2 + x**3 - x**4)/(-4*x**5*t0 + 6*x**4*t0**2 - 4*x**3*t0**3 + + x**2*t0**4 + x**6), t1, z, expand=False) + DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(1/x, t0), Poly(2*x*t1, t1)]}) + assert integrate_hyperexponential_polynomial(p, DE, z) == ( + Poly((x - t0)*t1**2 + (-2*t0 + 2*x)*t1, t1), Poly(-2*x*t0 + x**2 + + t0**2, t1), True) + + +def test_integrate_hyperexponential_returns_piecewise(): + a, b = symbols('a b') + DE = DifferentialExtension(a**x, x) + assert integrate_hyperexponential(DE.fa, DE.fd, DE) == (Piecewise( + (x, Eq(log(a), 0)), (exp(x*log(a))/log(a), True)), 0, True) + DE = DifferentialExtension(a**(b*x), x) + assert integrate_hyperexponential(DE.fa, DE.fd, DE) == (Piecewise( + (x, Eq(b*log(a), 0)), (exp(b*x*log(a))/(b*log(a)), True)), 0, True) + DE = DifferentialExtension(exp(a*x), x) + assert integrate_hyperexponential(DE.fa, DE.fd, DE) == (Piecewise( + (x, Eq(a, 0)), (exp(a*x)/a, True)), 0, True) + DE = DifferentialExtension(x*exp(a*x), x) + assert integrate_hyperexponential(DE.fa, DE.fd, DE) == (Piecewise( + (x**2/2, Eq(a**3, 0)), ((x*a**2 - a)*exp(a*x)/a**3, True)), 0, True) + DE = DifferentialExtension(x**2*exp(a*x), x) + assert integrate_hyperexponential(DE.fa, DE.fd, DE) == (Piecewise( + (x**3/3, Eq(a**6, 0)), + ((x**2*a**5 - 2*x*a**4 + 2*a**3)*exp(a*x)/a**6, True)), 0, True) + + +def test_integrate_primitive(): + DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(1/x, t)], + 'Tfuncs': [log]}) + assert integrate_primitive(Poly(t, t), Poly(1, t), DE) == (x*log(x), -1, True) + # (x*log(x) - x, True) + assert integrate_primitive(Poly(x, t), Poly(t, t), DE) == (0, NonElementaryIntegral(x/log(x), x), False) + + DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(1/x, t1), Poly(1/(x + 1), t2)], + 'Tfuncs': [log, Lambda(i, log(i + 1))]}) + assert integrate_primitive(Poly(t1, t2), Poly(t2, t2), DE) == \ + (0, NonElementaryIntegral(log(x)/log(1 + x), x), False) + + DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(1/x, t1), Poly(1/(x*t1), t2)], + 'Tfuncs': [log, Lambda(i, log(log(i)))]}) + assert integrate_primitive(Poly(t2, t2), Poly(t1, t2), DE) == \ + (0, NonElementaryIntegral(log(log(x))/log(x), x), False) + + DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(1/x, t0)], + 'Tfuncs': [log]}) + assert integrate_primitive(Poly(x**2*t0**3 + (3*x**2 + x)*t0**2 + (3*x**2 + + 2*x)*t0 + x**2 + x, t0), Poly(x**2*t0**4 + 4*x**2*t0**3 + 6*x**2*t0**2 + + 4*x**2*t0 + x**2, t0), DE) == \ + (-1/(log(x) + 1), NonElementaryIntegral(1/(log(x) + 1), x), False) + +def test_integrate_hypertangent_polynomial(): + DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(t**2 + 1, t)]}) + assert integrate_hypertangent_polynomial(Poly(t**2 + x*t + 1, t), DE) == \ + (Poly(t, t), Poly(x/2, t)) + DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(a*(t**2 + 1), t)]}) + assert integrate_hypertangent_polynomial(Poly(t**5, t), DE) == \ + (Poly(1/(4*a)*t**4 - 1/(2*a)*t**2, t), Poly(1/(2*a), t)) + + +def test_integrate_nonlinear_no_specials(): + a, d, = Poly(x**2*t**5 + x*t**4 - nu**2*t**3 - x*(x**2 + 1)*t**2 - (x**2 - + nu**2)*t - x**5/4, t), Poly(x**2*t**4 + x**2*(x**2 + 2)*t**2 + x**2 + x**4 + x**6/4, t) + # f(x) == phi_nu(x), the logarithmic derivative of J_v, the Bessel function, + # which has no specials (see Chapter 5, note 4 of Bronstein's book). + f = Function('phi_nu') + DE = DifferentialExtension(extension={'D': [Poly(1, x), + Poly(-t**2 - t/x - (1 - nu**2/x**2), t)], 'Tfuncs': [f]}) + assert integrate_nonlinear_no_specials(a, d, DE) == \ + (-log(1 + f(x)**2 + x**2/2)/2 - (4 + x**2)/(4 + 2*x**2 + 4*f(x)**2), True) + assert integrate_nonlinear_no_specials(Poly(t, t), Poly(1, t), DE) == \ + (0, False) + + +def test_integer_powers(): + assert integer_powers([x, x/2, x**2 + 1, 2*x/3]) == [ + (x/6, [(x, 6), (x/2, 3), (2*x/3, 4)]), + (1 + x**2, [(1 + x**2, 1)])] + + +def test_DifferentialExtension_exp(): + assert DifferentialExtension(exp(x) + exp(x**2), x, dummy=False)._important_attrs == \ + (Poly(t1 + t0, t1), Poly(1, t1), [Poly(1, x,), Poly(t0, t0), + Poly(2*x*t1, t1)], [x, t0, t1], [Lambda(i, exp(i)), + Lambda(i, exp(i**2))], [], [1, 2], [x, x**2], [], []) + assert DifferentialExtension(exp(x) + exp(2*x), x, dummy=False)._important_attrs == \ + (Poly(t0**2 + t0, t0), Poly(1, t0), [Poly(1, x), Poly(t0, t0)], [x, t0], + [Lambda(i, exp(i))], [], [1], [x], [], []) + assert DifferentialExtension(exp(x) + exp(x/2), x, dummy=False)._important_attrs == \ + (Poly(t0**2 + t0, t0), Poly(1, t0), [Poly(1, x), Poly(t0/2, t0)], + [x, t0], [Lambda(i, exp(i/2))], [], [1], [x/2], [], []) + assert DifferentialExtension(exp(x) + exp(x**2) + exp(x + x**2), x, + dummy=False)._important_attrs == \ + (Poly((1 + t0)*t1 + t0, t1), Poly(1, t1), [Poly(1, x), Poly(t0, t0), + Poly(2*x*t1, t1)], [x, t0, t1], [Lambda(i, exp(i)), + Lambda(i, exp(i**2))], [], [1, 2], [x, x**2], [], []) + assert DifferentialExtension(exp(x) + exp(x**2) + exp(x + x**2 + 1), x, + dummy=False)._important_attrs == \ + (Poly((1 + S.Exp1*t0)*t1 + t0, t1), Poly(1, t1), [Poly(1, x), + Poly(t0, t0), Poly(2*x*t1, t1)], [x, t0, t1], [Lambda(i, exp(i)), + Lambda(i, exp(i**2))], [], [1, 2], [x, x**2], [], []) + assert DifferentialExtension(exp(x) + exp(x**2) + exp(x/2 + x**2), x, + dummy=False)._important_attrs == \ + (Poly((t0 + 1)*t1 + t0**2, t1), Poly(1, t1), [Poly(1, x), + Poly(t0/2, t0), Poly(2*x*t1, t1)], [x, t0, t1], + [Lambda(i, exp(i/2)), Lambda(i, exp(i**2))], + [(exp(x/2), sqrt(exp(x)))], [1, 2], [x/2, x**2], [], []) + assert DifferentialExtension(exp(x) + exp(x**2) + exp(x/2 + x**2 + 3), x, + dummy=False)._important_attrs == \ + (Poly((t0*exp(3) + 1)*t1 + t0**2, t1), Poly(1, t1), [Poly(1, x), + Poly(t0/2, t0), Poly(2*x*t1, t1)], [x, t0, t1], [Lambda(i, exp(i/2)), + Lambda(i, exp(i**2))], [(exp(x/2), sqrt(exp(x)))], [1, 2], [x/2, x**2], + [], []) + assert DifferentialExtension(sqrt(exp(x)), x, dummy=False)._important_attrs == \ + (Poly(t0, t0), Poly(1, t0), [Poly(1, x), Poly(t0/2, t0)], [x, t0], + [Lambda(i, exp(i/2))], [(exp(x/2), sqrt(exp(x)))], [1], [x/2], [], []) + + assert DifferentialExtension(exp(x/2), x, dummy=False)._important_attrs == \ + (Poly(t0, t0), Poly(1, t0), [Poly(1, x), Poly(t0/2, t0)], [x, t0], + [Lambda(i, exp(i/2))], [], [1], [x/2], [], []) + + +def test_DifferentialExtension_log(): + assert DifferentialExtension(log(x)*log(x + 1)*log(2*x**2 + 2*x), x, + dummy=False)._important_attrs == \ + (Poly(t0*t1**2 + (t0*log(2) + t0**2)*t1, t1), Poly(1, t1), + [Poly(1, x), Poly(1/x, t0), + Poly(1/(x + 1), t1, expand=False)], [x, t0, t1], + [Lambda(i, log(i)), Lambda(i, log(i + 1))], [], [], [], + [1, 2], [x, x + 1]) + assert DifferentialExtension(x**x*log(x), x, dummy=False)._important_attrs == \ + (Poly(t0*t1, t1), Poly(1, t1), [Poly(1, x), Poly(1/x, t0), + Poly((1 + t0)*t1, t1)], [x, t0, t1], [Lambda(i, log(i)), + Lambda(i, exp(t0*i))], [(exp(x*log(x)), x**x)], [2], [t0*x], [1], [x]) + + +def test_DifferentialExtension_symlog(): + assert DifferentialExtension(log(x**x), x, dummy=False)._important_attrs == \ + (Poly(x*t0, t0), Poly(1, t0), [Poly(1, x), Poly(1/x, t0)], [x, t0], + [Lambda(i, log(i))], [(x*log(x), log(x**x))], [], [], [1], [x]) + assert DifferentialExtension(log(x**y), x, dummy=False)._important_attrs == \ + (Poly(y*t0, t0), Poly(1, t0), [Poly(1, x), Poly(1/x, t0)], [x, t0], + [Lambda(i, log(i))], [(y*log(x), log(x**y))], [], [], [1], [x]) + assert DifferentialExtension(log(sqrt(x)), x, dummy=False)._important_attrs == \ + (Poly(t0, t0), Poly(2, t0), [Poly(1, x), Poly(1/x, t0)], [x, t0], + [Lambda(i, log(i))], [(log(x)/2, log(sqrt(x)))], [], [], [1], [x]) + + +def test_DifferentialExtension_handle_first(): + assert DifferentialExtension(exp(x)*log(x), x, handle_first='log', + dummy=False)._important_attrs == \ + (Poly(t0*t1, t1), Poly(1, t1), [Poly(1, x), Poly(1/x, t0), + Poly(t1, t1)], [x, t0, t1], [Lambda(i, log(i)), Lambda(i, exp(i))], + [], [2], [x], [1], [x]) + assert DifferentialExtension(exp(x)*log(x), x, handle_first='exp', + dummy=False)._important_attrs == \ + (Poly(t0*t1, t1), Poly(1, t1), [Poly(1, x), Poly(t0, t0), + Poly(1/x, t1)], [x, t0, t1], [Lambda(i, exp(i)), Lambda(i, log(i))], + [], [1], [x], [2], [x]) + + # This one must have the log first, regardless of what we set it to + # (because the log is inside of the exponential: x**x == exp(x*log(x))) + assert DifferentialExtension(-x**x*log(x)**2 + x**x - x**x/x, x, + handle_first='exp', dummy=False)._important_attrs == \ + DifferentialExtension(-x**x*log(x)**2 + x**x - x**x/x, x, + handle_first='log', dummy=False)._important_attrs == \ + (Poly((-1 + x - x*t0**2)*t1, t1), Poly(x, t1), + [Poly(1, x), Poly(1/x, t0), Poly((1 + t0)*t1, t1)], [x, t0, t1], + [Lambda(i, log(i)), Lambda(i, exp(t0*i))], [(exp(x*log(x)), x**x)], + [2], [t0*x], [1], [x]) + + +def test_DifferentialExtension_all_attrs(): + # Test 'unimportant' attributes + DE = DifferentialExtension(exp(x)*log(x), x, dummy=False, handle_first='exp') + assert DE.f == exp(x)*log(x) + assert DE.newf == t0*t1 + assert DE.x == x + assert DE.cases == ['base', 'exp', 'primitive'] + assert DE.case == 'primitive' + + assert DE.level == -1 + assert DE.t == t1 == DE.T[DE.level] + assert DE.d == Poly(1/x, t1) == DE.D[DE.level] + raises(ValueError, lambda: DE.increment_level()) + DE.decrement_level() + assert DE.level == -2 + assert DE.t == t0 == DE.T[DE.level] + assert DE.d == Poly(t0, t0) == DE.D[DE.level] + assert DE.case == 'exp' + DE.decrement_level() + assert DE.level == -3 + assert DE.t == x == DE.T[DE.level] == DE.x + assert DE.d == Poly(1, x) == DE.D[DE.level] + assert DE.case == 'base' + raises(ValueError, lambda: DE.decrement_level()) + DE.increment_level() + DE.increment_level() + assert DE.level == -1 + assert DE.t == t1 == DE.T[DE.level] + assert DE.d == Poly(1/x, t1) == DE.D[DE.level] + assert DE.case == 'primitive' + + +def test_DifferentialExtension_extension_flag(): + raises(ValueError, lambda: DifferentialExtension(extension={'T': [x, t]})) + DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(t, t)]}) + assert DE._important_attrs == (None, None, [Poly(1, x), Poly(t, t)], [x, t], + None, None, None, None, None, None) + assert DE.d == Poly(t, t) + assert DE.t == t + assert DE.level == -1 + assert DE.cases == ['base', 'exp'] + assert DE.x == x + assert DE.case == 'exp' + + DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(t, t)], + 'E_K': [1], 'E_args': [x], 'L_K': [], 'L_args': []}) + assert DE._important_attrs == (None, None, [Poly(1, x), Poly(t, t)], [x, t], + None, None, [1], [x], [], []) + raises(ValueError, lambda: DifferentialExtension()) + + +def test_DifferentialExtension_misc(): + # Odd ends + assert DifferentialExtension(sin(y)*exp(x), x, dummy=False)._important_attrs == \ + (Poly(sin(y)*t0, t0, domain='ZZ[sin(y)]'), Poly(1, t0, domain='ZZ'), + [Poly(1, x, domain='ZZ'), Poly(t0, t0, domain='ZZ')], [x, t0], + [Lambda(i, exp(i))], [], [1], [x], [], []) + raises(NotImplementedError, lambda: DifferentialExtension(sin(x), x)) + assert DifferentialExtension(10**x, x, dummy=False)._important_attrs == \ + (Poly(t0, t0), Poly(1, t0), [Poly(1, x), Poly(log(10)*t0, t0)], [x, t0], + [Lambda(i, exp(i*log(10)))], [(exp(x*log(10)), 10**x)], [1], [x*log(10)], + [], []) + assert DifferentialExtension(log(x) + log(x**2), x, dummy=False)._important_attrs in [ + (Poly(3*t0, t0), Poly(2, t0), [Poly(1, x), Poly(2/x, t0)], [x, t0], + [Lambda(i, log(i**2))], [], [], [], [1], [x**2]), + (Poly(3*t0, t0), Poly(1, t0), [Poly(1, x), Poly(1/x, t0)], [x, t0], + [Lambda(i, log(i))], [], [], [], [1], [x])] + assert DifferentialExtension(S.Zero, x, dummy=False)._important_attrs == \ + (Poly(0, x), Poly(1, x), [Poly(1, x)], [x], [], [], [], [], [], []) + + +def test_DifferentialExtension_Rothstein(): + # Rothstein's integral + f = (2581284541*exp(x) + 1757211400)/(39916800*exp(3*x) + + 119750400*exp(x)**2 + 119750400*exp(x) + 39916800)*exp(1/(exp(x) + 1) - 10*x) + assert DifferentialExtension(f, x, dummy=False)._important_attrs == \ + (Poly((1757211400 + 2581284541*t0)*t1, t1), Poly(39916800 + + 119750400*t0 + 119750400*t0**2 + 39916800*t0**3, t1), + [Poly(1, x), Poly(t0, t0), Poly(-(10 + 21*t0 + 10*t0**2)/(1 + 2*t0 + + t0**2)*t1, t1, domain='ZZ(t0)')], [x, t0, t1], + [Lambda(i, exp(i)), Lambda(i, exp(1/(t0 + 1) - 10*i))], [], [1, 2], + [x, 1/(t0 + 1) - 10*x], [], []) + + +class TestingException(Exception): + """Dummy Exception class for testing.""" + pass + + +def test_DecrementLevel(): + DE = DifferentialExtension(x*log(exp(x) + 1), x, dummy=False) + assert DE.level == -1 + assert DE.t == t1 + assert DE.d == Poly(t0/(t0 + 1), t1) + assert DE.case == 'primitive' + + with DecrementLevel(DE): + assert DE.level == -2 + assert DE.t == t0 + assert DE.d == Poly(t0, t0) + assert DE.case == 'exp' + + with DecrementLevel(DE): + assert DE.level == -3 + assert DE.t == x + assert DE.d == Poly(1, x) + assert DE.case == 'base' + + assert DE.level == -2 + assert DE.t == t0 + assert DE.d == Poly(t0, t0) + assert DE.case == 'exp' + + assert DE.level == -1 + assert DE.t == t1 + assert DE.d == Poly(t0/(t0 + 1), t1) + assert DE.case == 'primitive' + + # Test that __exit__ is called after an exception correctly + try: + with DecrementLevel(DE): + raise TestingException + except TestingException: + pass + else: + raise AssertionError("Did not raise.") + + assert DE.level == -1 + assert DE.t == t1 + assert DE.d == Poly(t0/(t0 + 1), t1) + assert DE.case == 'primitive' + + +def test_risch_integrate(): + assert risch_integrate(t0*exp(x), x) == t0*exp(x) + assert risch_integrate(sin(x), x, rewrite_complex=True) == -exp(I*x)/2 - exp(-I*x)/2 + + # From my GSoC writeup + assert risch_integrate((1 + 2*x**2 + x**4 + 2*x**3*exp(2*x**2))/ + (x**4*exp(x**2) + 2*x**2*exp(x**2) + exp(x**2)), x) == \ + NonElementaryIntegral(exp(-x**2), x) + exp(x**2)/(1 + x**2) + + + assert risch_integrate(0, x) == 0 + + # These are tested here in addition to in test_DifferentialExtension above + # (symlogs) to test that backsubs works correctly. The integrals should be + # written in terms of the original logarithms in the integrands. + assert risch_integrate(log(x**x), x) == x*log(x**x)/2 - x**2/4 + assert risch_integrate(log(x**y), x) == x*log(x**y) - x*y + assert risch_integrate(log(sqrt(x)), x) == x*log(sqrt(x)) - x/2 + +def test_NonElementaryIntegral(): + assert isinstance(risch_integrate(exp(x**2), x), NonElementaryIntegral) + assert isinstance(risch_integrate(x**x*log(x), x), NonElementaryIntegral) + # Make sure methods of Integral still give back a NonElementaryIntegral + assert isinstance(NonElementaryIntegral(x**x*t0, x).subs(t0, log(x)), NonElementaryIntegral) diff -Nru python3-sympy-0.7.2/sympy/integrals/tests/test_transforms.py python3-sympy-0.7.3/sympy/integrals/tests/test_transforms.py --- python3-sympy-0.7.2/sympy/integrals/tests/test_transforms.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/integrals/tests/test_transforms.py 2013-07-13 17:53:32.000000000 +0000 @@ -7,47 +7,54 @@ LaplaceTransform, FourierTransform, SineTransform, CosineTransform, InverseLaplaceTransform, InverseFourierTransform, InverseSineTransform, InverseCosineTransform, HankelTransform, InverseHankelTransform) -from sympy import (gamma, exp, oo, Heaviside, symbols, Symbol, re, factorial, pi, - cos, S, And, sin, sqrt, I, log, tan, hyperexpand, meijerg, - EulerGamma, erf, besselj, bessely, besseli, besselk, - exp_polar, polar_lift, unpolarify, Function, expint) +from sympy import ( + gamma, exp, oo, Heaviside, symbols, Symbol, re, factorial, pi, + cos, S, And, sin, sqrt, I, log, tan, hyperexpand, meijerg, + EulerGamma, erf, besselj, bessely, besseli, besselk, + exp_polar, polar_lift, unpolarify, Function, expint, expand_mul, + combsimp, trigsimp) from sympy.utilities.pytest import XFAIL, slow, skip -from sympy.abc import x, s, a, b +from sympy.abc import x, s, a, b, c, d nu, beta, rho = symbols('nu beta rho') + def test_undefined_function(): from sympy import Function, MellinTransform f = Function('f') assert mellin_transform(f(x), x, s) == MellinTransform(f(x), x, s) assert mellin_transform(f(x) + exp(-x), x, s) == \ - (MellinTransform(f(x), x, s) + gamma(s), (0, oo), True) + (MellinTransform(f(x), x, s) + gamma(s), (0, oo), True) assert laplace_transform(2*f(x), x, s) == 2*LaplaceTransform(f(x), x, s) # TODO test derivative and other rules when implemented + def test_free_symbols(): from sympy import Function f = Function('f') assert mellin_transform(f(x), x, s).free_symbols == set([s]) assert mellin_transform(f(x)*a, x, s).free_symbols == set([s, a]) + def test_as_integral(): from sympy import Function, Integral f = Function('f') assert mellin_transform(f(x), x, s).rewrite('Integral') == \ - Integral(x**(s - 1)*f(x), (x, 0, oo)) + Integral(x**(s - 1)*f(x), (x, 0, oo)) assert fourier_transform(f(x), x, s).rewrite('Integral') == \ - Integral(f(x)*exp(-2*I*pi*s*x), (x, -oo, oo)) + Integral(f(x)*exp(-2*I*pi*s*x), (x, -oo, oo)) assert laplace_transform(f(x), x, s).rewrite('Integral') == \ - Integral(f(x)*exp(-s*x), (x, 0, oo)) + Integral(f(x)*exp(-s*x), (x, 0, oo)) assert str(inverse_mellin_transform(f(s), s, x, (a, b)).rewrite('Integral')) \ - == "Integral(x**(-s)*f(s), (s, _c - oo*I, _c + oo*I))" - assert str(inverse_laplace_transform(f(s), s, x).rewrite('Integral')) \ - == "Integral(f(s)*exp(s*x), (s, _c - oo*I, _c + oo*I))" + == "Integral(x**(-s)*f(s), (s, _c - oo*I, _c + oo*I))" + assert str(inverse_laplace_transform(f(s), s, x).rewrite('Integral')) == \ + "Integral(f(s)*exp(s*x), (s, _c - oo*I, _c + oo*I))" assert inverse_fourier_transform(f(s), s, x).rewrite('Integral') == \ - Integral(f(s)*exp(2*I*pi*s*x), (s, -oo, oo)) + Integral(f(s)*exp(2*I*pi*s*x), (s, -oo, oo)) # NOTE this is stuck in risch because meijerint cannot handle it + + @slow @XFAIL def test_mellin_transform_fail(): @@ -59,23 +66,26 @@ bpos = symbols('b', positive=True) bneg = symbols('b', negative=True) - expr = (sqrt(x+b**2)+b)**a/sqrt(x+b**2) + expr = (sqrt(x + b**2) + b)**a/sqrt(x + b**2) # TODO does not work with bneg, argument wrong. Needs changes to matching. assert MT(expr.subs(b, -bpos), x, s) == \ - ((-1)**(a+1)*2**(a + 2*s)*bpos**(a + 2*s - 1)*gamma(a + s) \ - *gamma(1 - a - 2*s)/gamma(1 - s), + ((-1)**(a + 1)*2**(a + 2*s)*bpos**(a + 2*s - 1)*gamma(a + s) + *gamma(1 - a - 2*s)/gamma(1 - s), (-re(a), -re(a)/2 + S(1)/2), True) - expr = (sqrt(x+b**2)+b)**a + expr = (sqrt(x + b**2) + b)**a assert MT(expr.subs(b, -bpos), x, s) == \ - (2**(a + 2*s)*a*bpos**(a + 2*s)*gamma(-a - 2*s)*gamma(a + s)/gamma(-s + 1), + ( + 2**(a + 2*s)*a*bpos**(a + 2*s)*gamma(-a - 2* + s)*gamma(a + s)/gamma(-s + 1), (-re(a), -re(a)/2), True) # Test exponent 1: - assert MT(expr.subs({b: -bpos, a:1}), x, s) == \ - (-bpos**(2*s + 1)*gamma(s)*gamma(-s - S(1)/2)/(2*sqrt(pi)), + assert MT(expr.subs({b: -bpos, a: 1}), x, s) == \ + (-bpos**(2*s + 1)*gamma(s)*gamma(-s - S(1)/2)/(2*sqrt(pi)), (-1, -S(1)/2), True) + def test_mellin_transform(): from sympy import Max, Min, Ne MT = mellin_transform @@ -83,42 +93,41 @@ bpos = symbols('b', positive=True) # 8.4.2 - assert MT(x**nu*Heaviside(x - 1), x, s) \ - == (1/(-nu - s), (-oo, -re(nu)), True) - assert MT(x**nu*Heaviside(1 - x), x, s) \ - == (1/(nu + s), (-re(nu), oo), True) - - assert MT((1-x)**(beta - 1)*Heaviside(1-x), x, s) \ - == (gamma(beta)*gamma(s)/gamma(beta + s), - (0, oo), re(-beta) < 0) - assert MT((x-1)**(beta - 1)*Heaviside(x-1), x, s) \ - == (gamma(beta)*gamma(1 - beta - s)/gamma(1 - s), - (-oo, -re(beta) + 1), re(-beta) < 0) + assert MT(x**nu*Heaviside(x - 1), x, s) == \ + (-1/(nu + s), (-oo, -re(nu)), True) + assert MT(x**nu*Heaviside(1 - x), x, s) == \ + (1/(nu + s), (-re(nu), oo), True) + + assert MT((1 - x)**(beta - 1)*Heaviside(1 - x), x, s) == \ + (gamma(beta)*gamma(s)/gamma(beta + s), (0, oo), re(-beta) < 0) + assert MT((x - 1)**(beta - 1)*Heaviside(x - 1), x, s) == \ + (gamma(beta)*gamma(1 - beta - s)/gamma(1 - s), + (-oo, -re(beta) + 1), re(-beta) < 0) - assert MT((1+x)**(-rho), x, s) == (gamma(s)*gamma(rho-s)/gamma(rho), - (0, re(rho)), True) + assert MT((1 + x)**(-rho), x, s) == \ + (gamma(s)*gamma(rho - s)/gamma(rho), (0, re(rho)), True) # TODO also the conditions should be simplified - assert MT(abs(1-x)**(-rho), x, s) == \ - (cos(pi*(rho/2 - s))*gamma(s)*gamma(rho - s)/(cos(pi*rho/2)*gamma(rho)), + assert MT(abs(1 - x)**(-rho), x, s) == ( + cos(pi*(rho/2 - s))*gamma(s)*gamma(rho - s)/(cos(pi*rho/2)*gamma(rho)), (0, re(rho)), And(re(rho) - 1 < 0, re(rho) < 1)) - mt = MT((1-x)**(beta-1)*Heaviside(1-x) - + a*(x-1)**(beta-1)*Heaviside(x-1), x, s) + mt = MT((1 - x)**(beta - 1)*Heaviside(1 - x) + + a*(x - 1)**(beta - 1)*Heaviside(x - 1), x, s) assert mt[1], mt[2] == ((0, -re(beta) + 1), True) - assert MT((x**a-b**a)/(x-b), x, s)[0] == \ - pi*b**(a+s-1)*sin(pi*a)/(sin(pi*s)*sin(pi*(a + s))) - assert MT((x**a-bpos**a)/(x-bpos), x, s) == \ - (pi*bpos**(a+s-1)*sin(pi*a)/(sin(pi*s)*sin(pi*(a + s))), + assert MT((x**a - b**a)/(x - b), x, s)[0] == \ + pi*b**(a + s - 1)*sin(pi*a)/(sin(pi*s)*sin(pi*(a + s))) + assert MT((x**a - bpos**a)/(x - bpos), x, s) == \ + (pi*bpos**(a + s - 1)*sin(pi*a)/(sin(pi*s)*sin(pi*(a + s))), (Max(-re(a), 0), Min(1 - re(a), 1)), True) - expr = (sqrt(x+b**2)+b)**a + expr = (sqrt(x + b**2) + b)**a assert MT(expr.subs(b, bpos), x, s) == \ - (-a*(2*bpos)**(a + 2*s)*gamma(s)*gamma(-a - 2*s)/gamma(-a - s + 1), - (0, -re(a)/2), True) - expr = (sqrt(x+b**2)+b)**a/sqrt(x+b**2) + (-a*(2*bpos)**(a + 2*s)*gamma(s)*gamma(-a - 2*s)/gamma(-a - s + 1), + (0, -re(a)/2), True) + expr = (sqrt(x + b**2) + b)**a/sqrt(x + b**2) assert MT(expr.subs(b, bpos), x, s) == \ - (2**(a + 2*s)*bpos**(a + 2*s - 1)*gamma(s) \ + (2**(a + 2*s)*bpos**(a + 2*s - 1)*gamma(s) *gamma(1 - a - 2*s)/gamma(1 - a - s), (0, -re(a)/2 + S(1)/2), True) @@ -127,8 +136,8 @@ assert MT(exp(-1/x), x, s) == (gamma(-s), (-oo, 0), True) # 8.4.5 - assert MT(log(x)**4*Heaviside(1-x), x, s) == (24/s**5, (0, oo), True) - assert MT(log(x)**3*Heaviside(x-1), x, s) == (6/s**4, (-oo, 0), True) + assert MT(log(x)**4*Heaviside(1 - x), x, s) == (24/s**5, (0, oo), True) + assert MT(log(x)**3*Heaviside(x - 1), x, s) == (6/s**4, (-oo, 0), True) assert MT(log(x + 1), x, s) == (pi/(s*sin(pi*s)), (-1, 0), True) assert MT(log(1/x + 1), x, s) == (pi/(s*sin(pi*s)), (0, 1), True) assert MT(log(abs(1 - x)), x, s) == (pi/(s*tan(pi*s)), (-1, 0), True) @@ -137,19 +146,19 @@ # TODO we cannot currently do these (needs summation of 3F2(-1)) # this also implies that they cannot be written as a single g-function # (although this is possible) - mt = MT(log(x)/(x+1), x, s) + mt = MT(log(x)/(x + 1), x, s) assert mt[1:] == ((0, 1), True) assert not hyperexpand(mt[0], allow_hyper=True).has(meijerg) - mt = MT(log(x)**2/(x+1), x, s) + mt = MT(log(x)**2/(x + 1), x, s) assert mt[1:] == ((0, 1), True) assert not hyperexpand(mt[0], allow_hyper=True).has(meijerg) - mt = MT(log(x)/(x+1)**2, x, s) + mt = MT(log(x)/(x + 1)**2, x, s) assert mt[1:] == ((0, 2), True) assert not hyperexpand(mt[0], allow_hyper=True).has(meijerg) # 8.4.14 assert MT(erf(sqrt(x)), x, s) == \ - (-gamma(s + S(1)/2)/(sqrt(pi)*s), (-S(1)/2, 0), True) + (-gamma(s + S(1)/2)/(sqrt(pi)*s), (-S(1)/2, 0), True) def test_mellin_transform_bessel(): @@ -158,90 +167,96 @@ # 8.4.19 assert MT(besselj(a, 2*sqrt(x)), x, s) == \ - (gamma(a/2 + s)/gamma(a/2 - s + 1), (-re(a)/2, S(3)/4), True) + (gamma(a/2 + s)/gamma(a/2 - s + 1), (-re(a)/2, S(3)/4), True) assert MT(sin(sqrt(x))*besselj(a, sqrt(x)), x, s) == \ - (2**a*gamma(S(1)/2 - 2*s)*gamma((a+1)/2 + s) \ - / (gamma(1 - s- a/2)*gamma(1 + a - 2*s)), - (-(re(a) + 1)/2, S(1)/4), True) + (2**a*gamma(-2*s + S(1)/2)*gamma(a/2 + s + S(1)/2)/( + gamma(-a/2 - s + 1)*gamma(a - 2*s + 1)), ( + -re(a)/2 - S(1)/2, S(1)/4), True) assert MT(cos(sqrt(x))*besselj(a, sqrt(x)), x, s) == \ - (2**a*gamma(a/2 + s)*gamma(-2*s + S(1)/2)/(gamma(-a/2 - s + S(1)/2)* - gamma(a - 2*s + 1)), (-re(a)/2, S(1)/4), True) + (2**a*gamma(a/2 + s)*gamma(-2*s + S(1)/2)/( + gamma(-a/2 - s + S(1)/2)*gamma(a - 2*s + 1)), ( + -re(a)/2, S(1)/4), True) assert MT(besselj(a, sqrt(x))**2, x, s) == \ - (gamma(a + s)*gamma(S(1)/2 - s) - / (sqrt(pi)*gamma(1 - s)*gamma(1 + a - s)), + (gamma(a + s)*gamma(S(1)/2 - s) + / (sqrt(pi)*gamma(1 - s)*gamma(1 + a - s)), (-re(a), S(1)/2), True) assert MT(besselj(a, sqrt(x))*besselj(-a, sqrt(x)), x, s) == \ - (gamma(s)*gamma(S(1)/2 - s) - / (sqrt(pi)*gamma(1 - a - s)*gamma(1 + a - s)), + (gamma(s)*gamma(S(1)/2 - s) + / (sqrt(pi)*gamma(1 - a - s)*gamma(1 + a - s)), (0, S(1)/2), True) # NOTE: prudnikov gives the strip below as (1/2 - re(a), 1). As far as # I can see this is wrong (since besselj(z) ~ 1/sqrt(z) for z large) assert MT(besselj(a - 1, sqrt(x))*besselj(a, sqrt(x)), x, s) == \ - (gamma(1-s)*gamma(a + s - S(1)/2) - / (sqrt(pi)*gamma(S(3)/2 - s)*gamma(a - s + S(1)/2)), + (gamma(1 - s)*gamma(a + s - S(1)/2) + / (sqrt(pi)*gamma(S(3)/2 - s)*gamma(a - s + S(1)/2)), (S(1)/2 - re(a), S(1)/2), True) assert MT(besselj(a, sqrt(x))*besselj(b, sqrt(x)), x, s) == \ - (4**s*gamma(1 - 2*s)*gamma((a+b)/2 + s) - / (gamma(1 - s + (b-a)/2)*gamma(1 - s + (a-b)/2) - *gamma( 1 - s + (a+b)/2)), + (4**s*gamma(1 - 2*s)*gamma((a + b)/2 + s) + / (gamma(1 - s + (b - a)/2)*gamma(1 - s + (a - b)/2) + *gamma( 1 - s + (a + b)/2)), (-(re(a) + re(b))/2, S(1)/2), True) assert MT(besselj(a, sqrt(x))**2 + besselj(-a, sqrt(x))**2, x, s)[1:] == \ - ((Max(re(a), -re(a)), S(1)/2), True) + ((Max(re(a), -re(a)), S(1)/2), True) # Section 8.4.20 assert MT(bessely(a, 2*sqrt(x)), x, s) == \ - (-cos(pi*(a/2 - s))*gamma(s - a/2)*gamma(s + a/2)/pi, + (-cos(pi*(a/2 - s))*gamma(s - a/2)*gamma(s + a/2)/pi, (Max(-re(a)/2, re(a)/2), S(3)/4), True) assert MT(sin(sqrt(x))*bessely(a, sqrt(x)), x, s) == \ - (-4**s*sin(pi*(a/2 - s))*gamma(S(1)/2 - 2*s) - * gamma((1-a)/2 + s)*gamma((1+a)/2 + s) - / (sqrt(pi)*gamma(1 - s - a/2)*gamma(1 - s + a/2)), + (-4**s*sin(pi*(a/2 - s))*gamma(S(1)/2 - 2*s) + * gamma((1 - a)/2 + s)*gamma((1 + a)/2 + s) + / (sqrt(pi)*gamma(1 - s - a/2)*gamma(1 - s + a/2)), (Max(-(re(a) + 1)/2, (re(a) - 1)/2), S(1)/4), True) assert MT(cos(sqrt(x))*bessely(a, sqrt(x)), x, s) == \ - (-4**s*cos(pi*(a/2 - s))*gamma(s - a/2)*gamma(s + a/2)*gamma(S(1)/2 - 2*s) - / (sqrt(pi)*gamma(S(1)/2 - s - a/2)*gamma(S(1)/2 - s + a/2)), + (-4**s*cos(pi*(a/2 - s))*gamma(s - a/2)*gamma(s + a/2)*gamma(S(1)/2 - 2*s) + / (sqrt(pi)*gamma(S(1)/2 - s - a/2)*gamma(S(1)/2 - s + a/2)), (Max(-re(a)/2, re(a)/2), S(1)/4), True) assert MT(besselj(a, sqrt(x))*bessely(a, sqrt(x)), x, s) == \ - (-cos(pi*s)*gamma(s)*gamma(a + s)*gamma(S(1)/2 - s) - / (pi**S('3/2')*gamma(1 + a - s)), + (-cos(pi*s)*gamma(s)*gamma(a + s)*gamma(S(1)/2 - s) + / (pi**S('3/2')*gamma(1 + a - s)), (Max(-re(a), 0), S(1)/2), True) assert MT(besselj(a, sqrt(x))*bessely(b, sqrt(x)), x, s) == \ - (-4**s*cos(pi*(a/2 - b/2 + s))*gamma(1 - 2*s) - * gamma(a/2 - b/2 + s)*gamma(a/2 + b/2 + s) - / (pi*gamma(a/2 - b/2 - s + 1)*gamma(a/2 + b/2 - s + 1)), + (-4**s*cos(pi*(a/2 - b/2 + s))*gamma(1 - 2*s) + * gamma(a/2 - b/2 + s)*gamma(a/2 + b/2 + s) + / (pi*gamma(a/2 - b/2 - s + 1)*gamma(a/2 + b/2 - s + 1)), (Max((-re(a) + re(b))/2, (-re(a) - re(b))/2), S(1)/2), True) # NOTE bessely(a, sqrt(x))**2 and bessely(a, sqrt(x))*bessely(b, sqrt(x)) # are a mess (no matter what way you look at it ...) assert MT(bessely(a, sqrt(x))**2, x, s)[1:] == \ - ((Max(-re(a), 0, re(a)), S(1)/2), True) + ((Max(-re(a), 0, re(a)), S(1)/2), True) # Section 8.4.22 # TODO we can't do any of these (delicate cancellation) # Section 8.4.23 assert MT(besselk(a, 2*sqrt(x)), x, s) == \ - (gamma(s - a/2)*gamma(s + a/2)/2, (Max(-re(a)/2, re(a)/2), oo), True) - assert MT(besselj(a, 2*sqrt(2*sqrt(x)))*besselk(a, 2*sqrt(2*sqrt(x))), x, s) == \ - (4**(-s)*gamma(2*s)*gamma(a/2 + s)/gamma(a/2 - s + 1)/2, - (Max(-re(a)/2, 0), oo), True) + (gamma( + s - a/2)*gamma(s + a/2)/2, (Max(-re(a)/2, re(a)/2), oo), True) + assert MT(besselj(a, 2*sqrt(2*sqrt(x)))*besselk( + a, 2*sqrt(2*sqrt(x))), x, s) == (4**(-s)*gamma(2*s)* + gamma(a/2 + s)/(2*gamma(a/2 - s + 1)), (Max(0, -re(a)/2), oo), True) # TODO bessely(a, x)*besselk(a, x) is a mess assert MT(besseli(a, sqrt(x))*besselk(a, sqrt(x)), x, s) == \ - (gamma(s)*gamma(a + s)*gamma(-s + S(1)/2)/(2*sqrt(pi)*gamma(a - s + 1)), - (Max(-re(a), 0), S(1)/2), True) + (gamma(s)*gamma( + a + s)*gamma(-s + S(1)/2)/(2*sqrt(pi)*gamma(a - s + 1)), + (Max(-re(a), 0), S(1)/2), True) assert MT(besseli(b, sqrt(x))*besselk(a, sqrt(x)), x, s) == \ - (4**s*gamma(-2*s + 1)*gamma(-a/2 + b/2 + s)*gamma(a/2 + b/2 + s)/ - (2*gamma(-a/2 + b/2 - s + 1)*gamma(a/2 + b/2 - s + 1)), - (Max(-re(a)/2 - re(b)/2, re(a)/2 - re(b)/2), S(1)/2), True) + (2**(2*s - 1)*gamma(-2*s + 1)*gamma(-a/2 + b/2 + s)* \ + gamma(a/2 + b/2 + s)/(gamma(-a/2 + b/2 - s + 1)* \ + gamma(a/2 + b/2 - s + 1)), (Max(-re(a)/2 - re(b)/2, \ + re(a)/2 - re(b)/2), S(1)/2), True) # TODO products of besselk are a mess - # TODO this can be simplified considerably (although I have no idea how) mt = MT(exp(-x/2)*besselk(a, x/2), x, s) - assert not mt[0].has(meijerg, hyper) + mt0 = combsimp((trigsimp(combsimp(mt[0].expand(func=True))))) + assert mt0 == 2*pi**(S(3)/2)*cos(pi*s)*gamma(-s + S(1)/2)/( + (cos(2*pi*a) - cos(2*pi*s))*gamma(-a - s + 1)*gamma(a - s + 1)) assert mt[1:] == ((Max(-re(a), re(a)), oo), True) # TODO exp(x/2)*besselk(a, x/2) [etc] cannot currently be done # TODO various strange products of special orders + def test_expint(): from sympy import E1, expint, Max, re, lerchphi, Symbol, simplify, Si, Ci, Ei aneg = Symbol('a', negative=True) @@ -251,39 +266,42 @@ assert inverse_mellin_transform(gamma(s)/s, s, x, (0, oo)).rewrite(expint).expand() == E1(x) assert mellin_transform(expint(a, x), x, s) == \ - (gamma(s)/(a + s - 1), (Max(1 - re(a), 0), oo), True) + (gamma(s)/(a + s - 1), (Max(1 - re(a), 0), oo), True) # XXX IMT has hickups with complicated strips ... assert simplify(unpolarify( - inverse_mellin_transform(gamma(s)/(aneg + s - 1), s, x, - (1 - aneg, oo)).rewrite(expint).expand(func=True))) \ - == expint(aneg, x) + inverse_mellin_transform(gamma(s)/(aneg + s - 1), s, x, + (1 - aneg, oo)).rewrite(expint).expand(func=True))) == \ + expint(aneg, x) assert mellin_transform(Si(x), x, s) == \ - (-2**s*sqrt(pi)*gamma((s + 1)/2)/(2*s*gamma(-s/2 + 1)), (-1, 0), True) - assert inverse_mellin_transform(-2**s*sqrt(pi)*gamma((s + 1)/2) \ + (-2**s*sqrt(pi)*gamma(s/2 + S(1)/2)/( + 2*s*gamma(-s/2 + 1)), (-1, 0), True) + assert inverse_mellin_transform(-2**s*sqrt(pi)*gamma((s + 1)/2) /(2*s*gamma(-s/2 + 1)), s, x, (-1, 0)) \ - == Si(x) + == Si(x) assert mellin_transform(Ci(sqrt(x)), x, s) == \ - (-4**s*sqrt(pi)*gamma(s)/(2*s*gamma(-s + S(1)/2)), (0, 1), True) - assert inverse_mellin_transform(-4**s*sqrt(pi)*gamma(s)/(2*s*gamma(-s + S(1)/2)), - s, u, (0, 1)).expand() == Ci(sqrt(u)) + (-2**(2*s - 1)*sqrt(pi)*gamma(s)/(s*gamma(-s + S(1)/2)), (0, 1), True) + assert inverse_mellin_transform( + -4**s*sqrt(pi)*gamma(s)/(2*s*gamma(-s + S(1)/2)), + s, u, (0, 1)).expand() == Ci(sqrt(u)) # TODO LT of Si, Shi, Chi is a mess ... assert laplace_transform(Ci(x), x, s) == (-log(1 + s**2)/2/s, 0, True) assert laplace_transform(expint(a, x), x, s) == \ - (lerchphi(s*polar_lift(-1), 1, a), 0, S(0) < re(a)) + (lerchphi(s*polar_lift(-1), 1, a), 0, S(0) < re(a)) assert laplace_transform(expint(1, x), x, s) == (log(s + 1)/s, 0, True) assert laplace_transform(expint(2, x), x, s) == \ - ((s - log(s + 1))/s**2, 0, True) + ((s - log(s + 1))/s**2, 0, True) assert inverse_laplace_transform(-log(1 + s**2)/2/s, s, u).expand() == \ - Heaviside(u)*Ci(u) + Heaviside(u)*Ci(u) assert inverse_laplace_transform(log(s + 1)/s, s, x).rewrite(expint) == \ - Heaviside(x)*E1(x) + Heaviside(x)*E1(x) assert inverse_laplace_transform((s - log(s + 1))/s**2, s, x).rewrite(expint).expand() == \ - (expint(2, x)*Heaviside(x)).rewrite(Ei).rewrite(expint).expand() + (expint(2, x)*Heaviside(x)).rewrite(Ei).rewrite(expint).expand() + def test_inverse_mellin_transform(): from sympy import (sin, simplify, expand_func, powsimp, Max, Min, expand, @@ -292,31 +310,29 @@ assert IMT(gamma(s), s, x, (0, oo)) == exp(-x) assert IMT(gamma(-s), s, x, (-oo, 0)) == exp(-1/x) - assert simplify(IMT(s/(2*s**2 - 2), s, x, (2, oo))) \ - == (x**2 + 1)*Heaviside(1 - x)/(4*x) + assert simplify(IMT(s/(2*s**2 - 2), s, x, (2, oo))) == \ + (x**2 + 1)*Heaviside(1 - x)/(4*x) # test passing "None" - assert IMT(1/(s**2 - 1), s, x, (-1, None)) \ - == -x*Heaviside(-x + 1)/2 - Heaviside(x - 1)/(2*x) - assert IMT(1/(s**2 - 1), s, x, (None, 1)) \ - == -x*Heaviside(-x + 1)/2 - Heaviside(x - 1)/(2*x) + assert IMT(1/(s**2 - 1), s, x, (-1, None)) == \ + -x*Heaviside(-x + 1)/2 - Heaviside(x - 1)/(2*x) + assert IMT(1/(s**2 - 1), s, x, (None, 1)) == \ + -x*Heaviside(-x + 1)/2 - Heaviside(x - 1)/(2*x) # test expansion of sums - assert IMT(gamma(s) + gamma(s-1), s, x, (1, oo)) == (x + 1)*exp(-x)/x + assert IMT(gamma(s) + gamma(s - 1), s, x, (1, oo)) == (x + 1)*exp(-x)/x # test factorisation of polys r = symbols('r', real=True) assert IMT(1/(s**2 + 1), s, exp(-x), (None, oo) ).subs(x, r).rewrite(sin).simplify() \ - == sin(r)*Heaviside(1 - exp(-r)) + == sin(r)*Heaviside(1 - exp(-r)) # test multiplicative substitution - a, b = symbols('a b', positive=True) - c, d = symbols('c d') - assert IMT(b**(-s/a)*factorial(s/a)/s, s, x, (0, oo)) == exp(-b*x**a) - assert IMT(factorial(a/b + s/b)/(a+ s), s, x, (-a, oo)) == x**a*exp(-x**b) + _a, _b = symbols('a b', positive=True) + assert IMT(_b**(-s/_a)*factorial(s/_a)/s, s, x, (0, oo)) == exp(-_b*x**_a) + assert IMT(factorial(_a/_b + s/_b)/(_a + s), s, x, (-_a, oo)) == x**_a*exp(-x**_b) - from sympy import expand_mul def simp_pows(expr): return simplify(powsimp(expand_mul(expr, deep=False), force=True)).replace(exp_polar, exp) @@ -326,32 +342,33 @@ assert IMT(-1/(nu + s), s, x, (-oo, None)) == x**nu*Heaviside(x - 1) assert IMT(1/(nu + s), s, x, (None, oo)) == x**nu*Heaviside(1 - x) assert simp_pows(IMT(gamma(beta)*gamma(s)/gamma(s + beta), s, x, (0, oo))) \ - == (1 - x)**(beta - 1)*Heaviside(1 - x) - assert simp_pows(IMT(gamma(beta)*gamma(1-beta-s)/gamma(1-s), + == (1 - x)**(beta - 1)*Heaviside(1 - x) + assert simp_pows(IMT(gamma(beta)*gamma(1 - beta - s)/gamma(1 - s), s, x, (-oo, None))) \ - == (x - 1)**(beta - 1)*Heaviside(x - 1) - assert simp_pows(IMT(gamma(s)*gamma(rho-s)/gamma(rho), s, x, (0, None))) \ - == (1/(x + 1))**rho - assert simp_pows(IMT(d**c*d**(s-1)*sin(pi*c) \ - *gamma(s)*gamma(s+c)*gamma(1-s)*gamma(1-s-c)/pi, + == (x - 1)**(beta - 1)*Heaviside(x - 1) + assert simp_pows(IMT(gamma(s)*gamma(rho - s)/gamma(rho), s, x, (0, None))) \ + == (1/(x + 1))**rho + assert simp_pows(IMT(d**c*d**(s - 1)*sin(pi*c) + *gamma(s)*gamma(s + c)*gamma(1 - s)*gamma(1 - s - c)/pi, s, x, (Max(-re(c), 0), Min(1 - re(c), 1)))) \ - == (x**c - d**c)/(x - d) + == (x**c - d**c)/(x - d) - assert simplify(IMT(1/sqrt(pi)*(-c/2)*gamma(s)*gamma((1-c)/2 - s) \ - *gamma(-c/2-s)/gamma(1-c-s), - s, x, (0, -re(c)/2))) == \ - (1 + sqrt(x + 1))**c - assert simplify(IMT(2**(a + 2*s)*b**(a + 2*s - 1)*gamma(s)*gamma(1 - a - 2*s) \ + assert simplify(IMT(1/sqrt(pi)*(-c/2)*gamma(s)*gamma((1 - c)/2 - s) + *gamma(-c/2 - s)/gamma(1 - c - s), + s, x, (0, -re(c)/2))) == \ + (1 + sqrt(x + 1))**c + assert simplify(IMT(2**(a + 2*s)*b**(a + 2*s - 1)*gamma(s)*gamma(1 - a - 2*s) /gamma(1 - a - s), s, x, (0, (-re(a) + 1)/2))) == \ - (b + sqrt(b**2 + x))**(a - 1)*(b**2 + b*sqrt(b**2 + x) + x)/(b**2 + x) - assert simplify(IMT(-2**(c + 2*s)*c*b**(c + 2*s)*gamma(s)*gamma(-c - 2*s) \ - / gamma(-c - s + 1), s, x, (0, -re(c)/2))) == \ - (b + sqrt(b**2 + x))**c + b**(a - 1)*(sqrt(1 + x/b**2) + 1)**(a - 1)*(b**2*sqrt(1 + x/b**2) + + b**2 + x)/(b**2 + x) + assert simplify(IMT(-2**(c + 2*s)*c*b**(c + 2*s)*gamma(s)*gamma(-c - 2*s) + / gamma(-c - s + 1), s, x, (0, -re(c)/2))) == \ + b**c*(sqrt(1 + x/b**2) + 1)**c # Section 8.4.5 assert IMT(24/s**5, s, x, (0, oo)) == log(x)**4*Heaviside(1 - x) assert expand(IMT(6/s**4, s, x, (-oo, 0)), force=True) == \ - log(x)**3*Heaviside(x - 1) + log(x)**3*Heaviside(x - 1) assert IMT(pi/(s*sin(pi*s)), s, x, (-1, 0)) == log(x + 1) assert IMT(pi/(s*sin(pi*s/2)), s, x, (-2, 0)) == log(x**2 + 1) assert IMT(pi/(s*sin(2*pi*s)), s, x, (-S(1)/2, 0)) == log(sqrt(x) + 1) @@ -360,63 +377,66 @@ # TODO def mysimp(expr): from sympy import expand, logcombine, powsimp - return expand(powsimp(logcombine(expr, force=True), force=True, deep=True), - force=True).replace(exp_polar, exp) + return expand( + powsimp(logcombine(expr, force=True), force=True, deep=True), + force=True).replace(exp_polar, exp) + assert mysimp(mysimp(IMT(pi/(s*tan(pi*s)), s, x, (-1, 0)))) in [ - log(1-x)*Heaviside(1-x) + log(x-1)*Heaviside(x-1), + log(1 - x)*Heaviside(1 - x) + log(x - 1)*Heaviside(x - 1), log(x)*Heaviside(x - 1) + log(1 - 1/x)*Heaviside(x - 1) + log(-x + 1)*Heaviside(-x + 1)] # test passing cot assert mysimp(IMT(pi*cot(pi*s)/s, s, x, (0, 1))) in [ - log(1/x - 1)*Heaviside(1-x) + log(1 - 1/x)*Heaviside(x-1), + log(1/x - 1)*Heaviside(1 - x) + log(1 - 1/x)*Heaviside(x - 1), -log(x)*Heaviside(-x + 1) + log(1 - 1/x)*Heaviside(x - 1) + log(-x + - 1)*Heaviside(-x + 1),] + 1)*Heaviside(-x + 1), ] # 8.4.14 assert IMT(-gamma(s + S(1)/2)/(sqrt(pi)*s), s, x, (-S(1)/2, 0)) == \ - erf(sqrt(x)) + erf(sqrt(x)) # 8.4.19 assert simplify(IMT(gamma(a/2 + s)/gamma(a/2 - s + 1), s, x, (-re(a)/2, S(3)/4))) \ - == besselj(a, 2*sqrt(x)) - assert simplify(IMT(2**a*gamma(S(1)/2 - 2*s)*gamma(s + (a + 1)/2) \ + == besselj(a, 2*sqrt(x)) + assert simplify(IMT(2**a*gamma(S(1)/2 - 2*s)*gamma(s + (a + 1)/2) / (gamma(1 - s - a/2)*gamma(1 - 2*s + a)), s, x, (-(re(a) + 1)/2, S(1)/4))) == \ - sin(sqrt(x))*besselj(a, sqrt(x)) - assert simplify(IMT(2**a*gamma(a/2 + s)*gamma(S(1)/2 - 2*s) \ + sin(sqrt(x))*besselj(a, sqrt(x)) + assert simplify(IMT(2**a*gamma(a/2 + s)*gamma(S(1)/2 - 2*s) / (gamma(S(1)/2 - s - a/2)*gamma(1 - 2*s + a)), s, x, (-re(a)/2, S(1)/4))) == \ - cos(sqrt(x))*besselj(a, sqrt(x)) + cos(sqrt(x))*besselj(a, sqrt(x)) # TODO this comes out as an amazing mess, but simplifies nicely - assert simplify(IMT(gamma(a + s)*gamma(S(1)/2 - s) \ + assert simplify(IMT(gamma(a + s)*gamma(S(1)/2 - s) / (sqrt(pi)*gamma(1 - s)*gamma(1 + a - s)), s, x, (-re(a), S(1)/2))) == \ - besselj(a, sqrt(x))**2 - assert simplify(IMT(gamma(s)*gamma(S(1)/2 - s) \ + besselj(a, sqrt(x))**2 + assert simplify(IMT(gamma(s)*gamma(S(1)/2 - s) / (sqrt(pi)*gamma(1 - s - a)*gamma(1 + a - s)), s, x, (0, S(1)/2))) == \ - besselj(-a, sqrt(x))*besselj(a, sqrt(x)) - assert simplify(IMT(4**s*gamma(-2*s + 1)*gamma(a/2 + b/2 + s) \ - / (gamma(-a/2 + b/2 - s + 1)*gamma(a/2 - b/2 - s + 1) \ + besselj(-a, sqrt(x))*besselj(a, sqrt(x)) + assert simplify(IMT(4**s*gamma(-2*s + 1)*gamma(a/2 + b/2 + s) + / (gamma(-a/2 + b/2 - s + 1)*gamma(a/2 - b/2 - s + 1) *gamma(a/2 + b/2 - s + 1)), s, x, (-(re(a) + re(b))/2, S(1)/2))) == \ - besselj(a, sqrt(x))*besselj(b, sqrt(x)) + besselj(a, sqrt(x))*besselj(b, sqrt(x)) # Section 8.4.20 # TODO this can be further simplified! - assert simplify(IMT(-2**(2*s)*cos(pi*a/2 - pi*b/2 + pi*s)*gamma(-2*s + 1) * \ - gamma(a/2 - b/2 + s)*gamma(a/2 + b/2 + s) / \ + assert simplify(IMT(-2**(2*s)*cos(pi*a/2 - pi*b/2 + pi*s)*gamma(-2*s + 1) * + gamma(a/2 - b/2 + s)*gamma(a/2 + b/2 + s) / (pi*gamma(a/2 - b/2 - s + 1)*gamma(a/2 + b/2 - s + 1)), - s, x, + s, x, (Max(-re(a)/2 - re(b)/2, -re(a)/2 + re(b)/2), S(1)/2))) == \ - (-cos(pi*b)*besselj(b, sqrt(x)) + besselj(-b, sqrt(x))) * \ - besselj(a, sqrt(x))/sin(pi*b)*(-1) + (cos(pi*b)*besselj(b, sqrt(x)) - besselj(-b, sqrt(x)))*besselj(a, + sqrt(x))/sin(pi*b) # TODO more # for coverage assert IMT(pi/cos(pi*s), s, x, (0, S(1)/2)) == sqrt(x)/(x + 1) + def test_laplace_transform(): from sympy import (fresnels, fresnelc, hyper) LT = laplace_transform @@ -427,7 +447,8 @@ # Test unevaluated form assert laplace_transform(f(t), t, w) == LaplaceTransform(f(t), t, w) - assert inverse_laplace_transform(f(w), w, t, plane=0) == InverseLaplaceTransform(f(w), w, t, 0) + assert inverse_laplace_transform( + f(w), w, t, plane=0) == InverseLaplaceTransform(f(w), w, t, 0) # test a bug spos = symbols('s', positive=True) @@ -435,30 +456,31 @@ # basic tests from wikipedia - assert LT((t-a)**b*exp(-c*(t-a))*Heaviside(t-a), t, s) \ - == ((s + c)**(-b - 1)*exp(-a*s)*gamma(b + 1), -c, True) + assert LT((t - a)**b*exp(-c*(t - a))*Heaviside(t - a), t, s) == \ + ((s + c)**(-b - 1)*exp(-a*s)*gamma(b + 1), -c, True) assert LT(t**a, t, s) == (s**(-a - 1)*gamma(a + 1), 0, True) assert LT(Heaviside(t), t, s) == (1/s, 0, True) assert LT(Heaviside(t - a), t, s) == (exp(-a*s)/s, 0, True) assert LT(1 - exp(-a*t), t, s) == (a/(s*(a + s)), 0, True) - assert LT((exp(2*t)-1)*exp(-b - t)*Heaviside(t)/2, t, s, noconds=True) \ - == exp(-b)/(s**2 - 1) + assert LT((exp(2*t) - 1)*exp(-b - t)*Heaviside(t)/2, t, s, noconds=True) \ + == exp(-b)/(s**2 - 1) - assert LT(exp(t), t, s)[:2] == (1/(s-1), 1) - assert LT(exp(2*t), t, s)[:2] == (1/(s-2), 2) - assert LT(exp(a*t), t, s)[:2] == (1/(s-a), a) + assert LT(exp(t), t, s)[:2] == (1/(s - 1), 1) + assert LT(exp(2*t), t, s)[:2] == (1/(s - 2), 2) + assert LT(exp(a*t), t, s)[:2] == (1/(s - a), a) - assert LT(log(t/a), t, s) == ((log(a) + log(s) + EulerGamma)/(-s), 0, True) + assert LT(log(t/a), t, s) == ((log(a*s) + EulerGamma)/s/-1, 0, True) assert LT(erf(t), t, s) == ((-erf(s/2) + 1)*exp(s**2/4)/s, 0, True) assert LT(sin(a*t), t, s) == (a/(a**2 + s**2), 0, True) assert LT(cos(a*t), t, s) == (s/(a**2 + s**2), 0, True) # TODO would be nice to have these come out better - assert LT(exp(-a*t)*sin(b*t), t, s) == (1/b/(1 + (a + s)**2/b**2), -a, True) + assert LT( + exp(-a*t)*sin(b*t), t, s) == (b/(b**2 + (a + s)**2), -a, True) assert LT(exp(-a*t)*cos(b*t), t, s) == \ - (1/(s + a)/(1 + b**2/(a + s)**2), -a, True) + ((a + s)/(b**2 + (a + s)**2), -a, True) # TODO sinh, cosh have delicate cancellation assert LT(besselj(0, t), t, s) == (1/sqrt(1 + s**2), 0, True) @@ -471,64 +493,71 @@ assert LT(exp(t)*cos(t), t, s)[:-1] in [ ((s - 1)/(s**2 - 2*s + 2), -oo), ((s - 1)/((s - 1)**2 + 1), -oo), - ] + ] # Fresnel functions assert laplace_transform(fresnels(t), t, s) == \ - ((-sin(s**2/(2*pi))*fresnels(s/pi) + sin(s**2/(2*pi))/2 - + ((-sin(s**2/(2*pi))*fresnels(s/pi) + sin(s**2/(2*pi))/2 - cos(s**2/(2*pi))*fresnelc(s/pi) + cos(s**2/(2*pi))/2)/s, 0, True) - assert laplace_transform(fresnelc(t), t, s) == \ - ((sin(s**2/(2*pi))*fresnelc(s/pi) - sin(s**2/(2*pi))/2 - - cos(s**2/(2*pi))*fresnels(s/pi) + cos(s**2/(2*pi))/2)/s, 0, True) + assert laplace_transform(fresnelc(t), t, s) == ( + (sin(s**2/(2*pi))*fresnelc(s/pi)/s - cos(s**2/(2*pi))*fresnels(s/pi)/s + + sqrt(2)*cos(s**2/(2*pi) + pi/4)/(2*s), 0, True)) + def test_inverse_laplace_transform(): from sympy import (expand, sinh, cosh, besselj, besseli, exp_polar, - unpolarify, simplify) + unpolarify, simplify, factor_terms) ILT = inverse_laplace_transform a, b, c, = symbols('a b c', positive=True) t = symbols('t') def simp_hyp(expr): - return expand(expand(expr).rewrite(sin)) + return factor_terms(expand_mul(expr)).rewrite(sin) # just test inverses of all of the above assert ILT(1/s, s, t) == Heaviside(t) assert ILT(1/s**2, s, t) == t*Heaviside(t) assert ILT(1/s**5, s, t) == t**4*Heaviside(t)/24 - assert ILT(exp(-a*s)/s, s, t) == Heaviside(t-a) - assert ILT(exp(-a*s)/(s+b), s, t) == exp(b*(a - t))*Heaviside(-a + t) + assert ILT(exp(-a*s)/s, s, t) == Heaviside(t - a) + assert ILT(exp(-a*s)/(s + b), s, t) == exp(b*(a - t))*Heaviside(-a + t) assert ILT(a/(s**2 + a**2), s, t) == sin(a*t)*Heaviside(t) assert ILT(s/(s**2 + a**2), s, t) == cos(a*t)*Heaviside(t) # TODO is there a way around simp_hyp? assert simp_hyp(ILT(a/(s**2 - a**2), s, t)) == sinh(a*t)*Heaviside(t) assert simp_hyp(ILT(s/(s**2 - a**2), s, t)) == cosh(a*t)*Heaviside(t) - assert ILT(a/((s+b)**2 + a**2), s, t) == exp(-b*t)*sin(a*t)*Heaviside(t) - assert ILT((s+b)/((s+b)**2 + a**2), s, t) == exp(-b*t)*cos(a*t)*Heaviside(t) + assert ILT(a/((s + b)**2 + a**2), s, t) == exp(-b*t)*sin(a*t)*Heaviside(t) + assert ILT( + (s + b)/((s + b)**2 + a**2), s, t) == exp(-b*t)*cos(a*t)*Heaviside(t) # TODO sinh/cosh shifted come out a mess. also delayed trig is a mess # TODO should this simplify further? assert ILT(exp(-a*s)/s**b, s, t) == \ - (t - a)**(b - 1)*Heaviside(t - a)/gamma(b) + (t - a)**(b - 1)*Heaviside(t - a)/gamma(b) assert ILT(exp(-a*s)/sqrt(1 + s**2), s, t) == \ - Heaviside(t - a)*besselj(0, a - t) # note: besselj(0, x) is even + Heaviside(t - a)*besselj(0, a - t) # note: besselj(0, x) is even # XXX ILT turns these branch factor into trig functions ... assert simplify(ILT(a**b*(s + sqrt(s**2 - a**2))**(-b)/sqrt(s**2 - a**2), s, t).rewrite(exp)) == \ Heaviside(t)*besseli(b, a*t) assert ILT(a**b*(s + sqrt(s**2 + a**2))**(-b)/sqrt(s**2 + a**2), - s, t).rewrite(exp) == \ + s, t).rewrite(exp) == \ Heaviside(t)*besselj(b, a*t) - assert ILT(1/(s*sqrt(s+1)), s, t) == Heaviside(t)*erf(sqrt(t)) + assert ILT(1/(s*sqrt(s + 1)), s, t) == Heaviside(t)*erf(sqrt(t)) # TODO can we make erf(t) work? + def test_fourier_transform(): from sympy import simplify, expand, expand_complex, factor, expand_trig FT = fourier_transform IFT = inverse_fourier_transform - def simp(x): return simplify(expand_trig(expand_complex(expand(x)))) - def sinc(x): return sin(pi*x)/(pi*x) + + def simp(x): + return simplify(expand_trig(expand_complex(expand(x)))) + + def sinc(x): + return sin(pi*x)/(pi*x) k = symbols('k', real=True) f = Function("f") @@ -540,16 +569,17 @@ # Test unevaluated form assert fourier_transform(f(x), x, k) == FourierTransform(f(x), x, k) - assert inverse_fourier_transform(f(k), k, x) == InverseFourierTransform(f(k), k, x) + assert inverse_fourier_transform( + f(k), k, x) == InverseFourierTransform(f(k), k, x) # basic examples from wikipedia assert simp(FT(Heaviside(1 - abs(2*a*x)), x, k)) == sinc(k/a)/a # TODO IFT is a *mess* - assert simp(FT(Heaviside(1-abs(a*x))*(1-abs(a*x)), x, k)) == sinc(k/a)**2/a + assert simp(FT(Heaviside(1 - abs(a*x))*(1 - abs(a*x)), x, k)) == sinc(k/a)**2/a # TODO IFT - assert factor(FT(exp(-a*x)*Heaviside(x), x, k), extension=I) \ - == 1/(a + 2*pi*I*k) + assert factor(FT(exp(-a*x)*Heaviside(x), x, k), extension=I) == \ + 1/(a + 2*pi*I*k) # NOTE: the ift comes out in pieces assert IFT(1/(a + 2*pi*I*x), x, posk, noconds=False) == (exp(-a*posk), True) @@ -559,10 +589,10 @@ noconds=False) == (0, True) # TODO IFT without factoring comes out as meijer g - assert factor(FT(x*exp(-a*x)*Heaviside(x), x, k), extension=I) \ - == 1/(a + 2*pi*I*k)**2 - assert FT(exp(-a*x)*sin(b*x)*Heaviside(x), x, k) \ - == 1/b/(1 + a**2*(1 + 2*pi*I*k/a)**2/b**2) + assert factor(FT(x*exp(-a*x)*Heaviside(x), x, k), extension=I) == \ + 1/(a + 2*pi*I*k)**2 + assert FT(exp(-a*x)*sin(b*x)*Heaviside(x), x, k) == \ + b/(b**2 + (a + 2*I*pi*k)**2) assert FT(exp(-a*x**2), x, k) == sqrt(pi)*exp(-pi**2*k**2/a)/sqrt(a) assert IFT(sqrt(pi/a)*exp(-(pi*k)**2/a), k, x) == exp(-a*x**2) @@ -573,6 +603,7 @@ # TODO are there other common transforms (no distributions!)? + def test_sine_transform(): from sympy import sinh, cosh, EulerGamma @@ -583,23 +614,33 @@ # Test unevaluated form assert sine_transform(f(t), t, w) == SineTransform(f(t), t, w) - assert inverse_sine_transform(f(w), w, t) == InverseSineTransform(f(w), w, t) + assert inverse_sine_transform( + f(w), w, t) == InverseSineTransform(f(w), w, t) assert sine_transform(1/sqrt(t), t, w) == 1/sqrt(w) assert inverse_sine_transform(1/sqrt(w), w, t) == 1/sqrt(t) - assert sine_transform((1/sqrt(t))**3, t, w) == sqrt(w)*gamma(S(1)/4)/(2*gamma(S(5)/4)) - - assert sine_transform(t**(-a), t, w) == 2**(-a + S(1)/2)*w**(a - 1)*gamma(-a/2 + 1)/gamma((a + 1)/2) - assert inverse_sine_transform(2**(-a + S(1)/2)*w**(a - 1)*gamma(-a/2 + 1)/gamma(a/2 + S(1)/2), w, t) == t**(-a) - - assert sine_transform(exp(-a*t), t, w) == sqrt(2)*w/(sqrt(pi)*(a**2 + w**2)) - assert inverse_sine_transform(sqrt(2)*w/(sqrt(pi)*(a**2 + w**2)), w, t) == -sinh(a*t) + cosh(a*t) + assert sine_transform( + (1/sqrt(t))**3, t, w) == sqrt(w)*gamma(S(1)/4)/(2*gamma(S(5)/4)) - assert sine_transform(log(t)/t, t, w) == sqrt(2)*sqrt(pi)*(-log(w**2) - 2*EulerGamma)/4 + assert sine_transform(t**(-a), t, w) == 2**( + -a + S(1)/2)*w**(a - 1)*gamma(-a/2 + 1)/gamma((a + 1)/2) + assert inverse_sine_transform(2**(-a + S( + 1)/2)*w**(a - 1)*gamma(-a/2 + 1)/gamma(a/2 + S(1)/2), w, t) == t**(-a) + + assert sine_transform( + exp(-a*t), t, w) == sqrt(2)*w/(sqrt(pi)*(a**2 + w**2)) + assert inverse_sine_transform( + sqrt(2)*w/(sqrt(pi)*(a**2 + w**2)), w, t) == exp(-a*t) + + assert sine_transform( + log(t)/t, t, w) == -sqrt(2)*sqrt(pi)*(log(w**2) + 2*EulerGamma)/4 + + assert sine_transform( + t*exp(-a*t**2), t, w) == sqrt(2)*w*exp(-w**2/(4*a))/(4*a**(S(3)/2)) + assert inverse_sine_transform( + sqrt(2)*w*exp(-w**2/(4*a))/(4*a**(S(3)/2)), w, t) == t*exp(-a*t**2) - assert sine_transform(t*exp(-a*t**2), t, w) == sqrt(2)*w*exp(-w**2/(4*a))/(4*a**(S(3)/2)) - assert inverse_sine_transform(sqrt(2)*w*exp(-w**2/(4*a))/(4*a**(S(3)/2)), w, t) == t*exp(-a*t**2) def test_cosine_transform(): from sympy import sinh, cosh, Si, Ci @@ -611,27 +652,38 @@ # Test unevaluated form assert cosine_transform(f(t), t, w) == CosineTransform(f(t), t, w) - assert inverse_cosine_transform(f(w), w, t) == InverseCosineTransform(f(w), w, t) + assert inverse_cosine_transform( + f(w), w, t) == InverseCosineTransform(f(w), w, t) assert cosine_transform(1/sqrt(t), t, w) == 1/sqrt(w) assert inverse_cosine_transform(1/sqrt(w), w, t) == 1/sqrt(t) - assert cosine_transform(1/(a**2+t**2), t, w) == sqrt(2)*sqrt(pi)*(-sinh(a*w) + cosh(a*w))/(2*a) + assert cosine_transform(1/( + a**2 + t**2), t, w) == sqrt(2)*sqrt(pi)*exp(-a*w)/(2*a) - assert cosine_transform(t**(-a), t, w) == 2**(-a + S(1)/2)*w**(a - 1)*gamma((-a + 1)/2)/gamma(a/2) - assert inverse_cosine_transform(2**(-a + S(1)/2)*w**(a - 1)*gamma(-a/2 + S(1)/2)/gamma(a/2), w, t) == t**(-a) + assert cosine_transform(t**( + -a), t, w) == 2**(-a + S(1)/2)*w**(a - 1)*gamma((-a + 1)/2)/gamma(a/2) + assert inverse_cosine_transform(2**(-a + S( + 1)/2)*w**(a - 1)*gamma(-a/2 + S(1)/2)/gamma(a/2), w, t) == t**(-a) + + assert cosine_transform( + exp(-a*t), t, w) == sqrt(2)*a/(sqrt(pi)*(a**2 + w**2)) + assert inverse_cosine_transform( + sqrt(2)*a/(sqrt(pi)*(a**2 + w**2)), w, t) == exp(-a*t) + + assert cosine_transform(exp(-a*sqrt(t))*cos(a*sqrt( + t)), t, w) == a*exp(-a**2/(2*w))/(2*w**(S(3)/2)) + + assert cosine_transform(1/(a + t), t, w) == sqrt(2)*( + (-2*Si(a*w) + pi)*sin(a*w)/2 - cos(a*w)*Ci(a*w))/sqrt(pi) + assert inverse_cosine_transform(sqrt(2)*meijerg(((S(1)/2, 0), ()), ( + (S(1)/2, 0, 0), (S(1)/2,)), a**2*w**2/4)/(2*pi), w, t) == 1/(a + t) - assert cosine_transform(exp(-a*t), t, w) == sqrt(2)*a/(sqrt(pi)*(a**2 + w**2)) - assert inverse_cosine_transform(sqrt(2)*a/(sqrt(pi)*(a**2 + w**2)), w, t) == -sinh(a*t) + cosh(a*t) - - assert cosine_transform(exp(-a*sqrt(t))*cos(a*sqrt(t)), t, w) == a*(-sinh(a**2/(2*w)) + cosh(a**2/(2*w)))/(2*w**(S(3)/2)) - - assert cosine_transform(1/(a+t), t, w) == -sqrt(2)*((2*Si(a*w) - pi)*sin(a*w) + 2*cos(a*w)*Ci(a*w))/(2*sqrt(pi)) - assert inverse_cosine_transform(sqrt(2)*meijerg(((S(1)/2, 0), ()), ((S(1)/2, 0, 0), (S(1)/2,)), a**2*w**2/4)/(2*pi), w, t) == 1/(a + t) - - assert cosine_transform(1/sqrt(a**2+t**2), t, w) == sqrt(2)*meijerg(((S(1)/2,), ()), ((0, 0), (S(1)/2,)), a**2*w**2/4)/(2*sqrt(pi)) + assert cosine_transform(1/sqrt(a**2 + t**2), t, w) == sqrt(2)*meijerg( + ((S(1)/2,), ()), ((0, 0), (S(1)/2,)), a**2*w**2/4)/(2*sqrt(pi)) assert inverse_cosine_transform(sqrt(2)*meijerg(((S(1)/2,), ()), ((0, 0), (S(1)/2,)), a**2*w**2/4)/(2*sqrt(pi)), w, t) == 1/(t*sqrt(a**2/t**2 + 1)) + def test_hankel_transform(): from sympy import sinh, cosh, gamma, sqrt, exp @@ -644,13 +696,19 @@ assert hankel_transform(1/r, r, k, 0) == 1/k assert inverse_hankel_transform(1/k, k, r, 0) == 1/r - assert hankel_transform(1/r**m, r, k, 0) == 2**(-m + 1)*k**(m - 2)*gamma(-m/2 + 1)/gamma(m/2) - assert inverse_hankel_transform(2**(-m + 1)*k**(m - 2)*gamma(-m/2 + 1)/gamma(m/2), k, r, 0) == r**(-m) - - assert hankel_transform(1/r**m, r, k, nu) == 2**(-m + 1)*k**(m - 2)*gamma(-m/2 + nu/2 + 1)/gamma(m/2 + nu/2) - assert inverse_hankel_transform(2**(-m + 1)*k**(m - 2)*gamma(-m/2 + nu/2 + 1)/gamma(m/2 + nu/2), k, r, nu) == r**(-m) + assert hankel_transform( + 1/r**m, r, k, 0) == 2**(-m + 1)*k**(m - 2)*gamma(-m/2 + 1)/gamma(m/2) + assert inverse_hankel_transform( + 2**(-m + 1)*k**(m - 2)*gamma(-m/2 + 1)/gamma(m/2), k, r, 0) == r**(-m) + + assert hankel_transform(1/r**m, r, k, nu) == ( + 2*2**(-m)*k**(m - 2)*gamma(-m/2 + nu/2 + 1)/gamma(m/2 + nu/2)) + assert inverse_hankel_transform(2**(-m + 1)*k**( + m - 2)*gamma(-m/2 + nu/2 + 1)/gamma(m/2 + nu/2), k, r, nu) == r**(-m) assert hankel_transform(r**nu*exp(-a*r), r, k, nu) == \ - 2**(nu + 1)*a*k**(-nu - 3)*(a**2/k**2 + 1)**(-nu - S(3)/2)*gamma(nu + S(3)/2)/sqrt(pi) - assert inverse_hankel_transform(2**(nu + 1)*a*k**(-nu - 3)*(a**2/k**2 + 1)**(-nu - S(3)/2)*gamma(nu + S(3)/2)/sqrt(pi), k, r, nu) == \ - r**nu*(-sinh(a*r) + cosh(a*r)) + 2**(nu + 1)*a*k**(-nu - 3)*(a**2/k**2 + 1)**(-nu - S( + 3)/2)*gamma(nu + S(3)/2)/sqrt(pi) + assert inverse_hankel_transform( + 2**(nu + 1)*a*k**(-nu - 3)*(a**2/k**2 + 1)**(-nu - S(3)/2)*gamma( + nu + S(3)/2)/sqrt(pi), k, r, nu) == r**nu*exp(-a*r) diff -Nru python3-sympy-0.7.2/sympy/integrals/tests/test_trigonometry.py python3-sympy-0.7.3/sympy/integrals/tests/test_trigonometry.py --- python3-sympy-0.7.2/sympy/integrals/tests/test_trigonometry.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/integrals/tests/test_trigonometry.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,72 +1,90 @@ -from sympy import Symbol, Rational, sin, cos, tan, csc, sec, cot +from sympy.core import Eq, Rational, Symbol +from sympy.functions import sin, cos, tan, csc, sec, cot, log, Piecewise from sympy.integrals.trigonometry import trigintegrate -from sympy.functions.elementary.exponential import log + x = Symbol('x') -y = Symbol('y') def test_trigintegrate_odd(): - assert trigintegrate(Rational(1), x) == x - assert trigintegrate(x, x) is None - assert trigintegrate(x**2, x) is None + assert trigintegrate(Rational(1), x) == x + assert trigintegrate(x, x) is None + assert trigintegrate(x**2, x) is None assert trigintegrate(sin(x), x) == -cos(x) - assert trigintegrate(cos(x), x) == sin(x) + assert trigintegrate(cos(x), x) == sin(x) assert trigintegrate(sin(3*x), x) == -cos(3*x)/3 - assert trigintegrate(cos(3*x), x) == sin(3*x)/3 - - assert trigintegrate(sin(y*x), x) == -cos(y*x)/y - assert trigintegrate(cos(y*x), x) == sin(y*x)/y + assert trigintegrate(cos(3*x), x) == sin(3*x)/3 - assert trigintegrate(sin(x)*cos(x), x) == sin(x)**2/2 - assert trigintegrate(sin(x)*cos(x)**2, x) == -cos(x)**3/3 - assert trigintegrate(sin(x)**2*cos(x), x) == sin(x)**3/3 + y = Symbol('y') + assert trigintegrate(sin(y*x), x) == \ + Piecewise((0, Eq(y, 0)), (-cos(y*x)/y, True)) + assert trigintegrate(cos(y*x), x) == \ + Piecewise((x, Eq(y, 0)), (sin(y*x)/y, True)) + assert trigintegrate(sin(y*x)**2, x) == \ + Piecewise((0, Eq(y, 0)), ((x*y/2 - sin(x*y)*cos(x*y)/2)/y, True)) + assert trigintegrate(sin(y*x)*cos(y*x), x) == \ + Piecewise((0, Eq(y, 0)), (sin(x*y)**2/(2*y), True)) + assert trigintegrate(cos(y*x)**2, x) == \ + Piecewise((x, Eq(y, 0)), ((x*y/2 + sin(x*y)*cos(x*y)/2)/y, True)) + + y = Symbol('y', positive=True) + # TODO: remove conds='none' below. For this to work we would have to rule + # out (e.g. by trying solve) the condition y = 0, incompatible with + # y.is_positive being True. + assert trigintegrate(sin(y*x), x, conds='none') == -cos(y*x)/y + assert trigintegrate(cos(y*x), x, conds='none') == sin(y*x)/y + + assert trigintegrate(sin(x)*cos(x), x) == sin(x)**2/2 + assert trigintegrate(sin(x)*cos(x)**2, x) == -cos(x)**3/3 + assert trigintegrate(sin(x)**2*cos(x), x) == sin(x)**3/3 # check if it selects right function to substitute, # so the result is kept simple - assert trigintegrate(sin(x)**7 * cos(x), x) == sin(x)**8/8 + assert trigintegrate(sin(x)**7 * cos(x), x) == sin(x)**8/8 assert trigintegrate(sin(x) * cos(x)**7, x) == -cos(x)**8/8 - assert trigintegrate(sin(x)**7 * cos(x)**3, x) == -sin(x)**10/10 + sin(x)**8/8 - assert trigintegrate(sin(x)**3 * cos(x)**7, x) == cos(x)**10/10 - cos(x)**8/8 + assert trigintegrate(sin(x)**7 * cos(x)**3, x) == \ + -sin(x)**10/10 + sin(x)**8/8 + assert trigintegrate(sin(x)**3 * cos(x)**7, x) == \ + cos(x)**10/10 - cos(x)**8/8 def test_trigintegrate_even(): - assert trigintegrate(sin(x)**2, x) == x/2 - cos(x)*sin(x)/2 - assert trigintegrate(cos(x)**2, x) == x/2 + cos(x)*sin(x)/2 + assert trigintegrate(sin(x)**2, x) == x/2 - cos(x)*sin(x)/2 + assert trigintegrate(cos(x)**2, x) == x/2 + cos(x)*sin(x)/2 + + assert trigintegrate(sin(3*x)**2, x) == x/2 - cos(3*x)*sin(3*x)/6 + assert trigintegrate(cos(3*x)**2, x) == x/2 + cos(3*x)*sin(3*x)/6 + assert trigintegrate(sin(x)**2 * cos(x)**2, x) == \ + x/8 - sin(2*x)*cos(2*x)/16 + + assert trigintegrate(sin(x)**4 * cos(x)**2, x) == \ + x/16 - sin(x) *cos(x)/16 - sin(x)**3*cos(x)/24 + \ + sin(x)**5*cos(x)/6 + + assert trigintegrate(sin(x)**2 * cos(x)**4, x) == \ + x/16 + cos(x) *sin(x)/16 + cos(x)**3*sin(x)/24 - \ + cos(x)**5*sin(x)/6 - assert trigintegrate(sin(3*x)**2, x)== x/2 - cos(3*x)*sin(3*x)/6 - assert trigintegrate(cos(3*x)**2, x)== x/2 + cos(3*x)*sin(3*x)/6 - assert trigintegrate(sin(x)**2 * cos(x)**2, x) == x/8 - cos(2*x)*sin(2*x)/16 - - assert trigintegrate(sin(x)**4 * cos(x)**2, x) == x/16- sin(x) *cos(x)/16 \ - - sin(x)**3*cos(x)/24 \ - + sin(x)**5*cos(x)/6 - - assert trigintegrate(sin(x)**2 * cos(x)**4, x) == x/16+ cos(x) *sin(x)/16 \ - + cos(x)**3*sin(x)/24 \ - - cos(x)**5*sin(x)/6 - - assert trigintegrate(sin(x)**(-4),x) == -2*cos(x)/(3*sin(x)) \ - - cos(x)/(3*sin(x)**3) - - assert trigintegrate(cos(x)**(-6),x) == sin(x)/(5*cos(x)**5)\ - + 4*sin(x)/(15*cos(x)**3)\ - + 8*sin(x)/(15*cos(x)) + assert trigintegrate(sin(x)**(-4), x) == -2*cos(x)/(3*sin(x)) \ + - cos(x)/(3*sin(x)**3) + + assert trigintegrate(cos(x)**(-6), x) == sin(x)/(5*cos(x)**5) \ + + 4*sin(x)/(15*cos(x)**3) + 8*sin(x)/(15*cos(x)) def test_trigintegrate_mixed(): - assert trigintegrate(sin(x)*sec(x), x) == -log(sin(x)**2 - 1)/2 - assert trigintegrate(sin(x)*csc(x), x) == x - assert trigintegrate(sin(x)*cot(x), x) == sin(x) - - assert trigintegrate(cos(x)*sec(x), x) == x - assert trigintegrate(cos(x)*csc(x), x) == log(cos(x)**2 - 1)/2 - assert trigintegrate(cos(x)*tan(x), x) == -cos(x) - assert trigintegrate(cos(x)*cot(x), x) == log(cos(x) - 1)/2 \ - - log(cos(x) + 1)/2 \ - + cos(x) + assert trigintegrate(sin(x)*sec(x), x) == -log(sin(x)**2 - 1)/2 + assert trigintegrate(sin(x)*csc(x), x) == x + assert trigintegrate(sin(x)*cot(x), x) == sin(x) + + assert trigintegrate(cos(x)*sec(x), x) == x + assert trigintegrate(cos(x)*csc(x), x) == log(cos(x)**2 - 1)/2 + assert trigintegrate(cos(x)*tan(x), x) == -cos(x) + assert trigintegrate(cos(x)*cot(x), x) == log(cos(x) - 1)/2 \ + - log(cos(x) + 1)/2 + cos(x) + def test_trigintegrate_symbolic(): n = Symbol('n', integer=True) diff -Nru python3-sympy-0.7.2/sympy/integrals/transforms.py python3-sympy-0.7.3/sympy/integrals/transforms.py --- python3-sympy-0.7.2/sympy/integrals/transforms.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/integrals/transforms.py 2013-07-13 17:53:32.000000000 +0000 @@ -14,6 +14,7 @@ # Helpers / Utilities ########################################################################## + class IntegralTransformError(NotImplementedError): """ Exception raised in relation to problems computing transforms. @@ -30,6 +31,7 @@ "%s Transform could not be computed: %s." % (transform, msg)) self.function = function + class IntegralTransform(Function): """ Base class for integral transforms. @@ -70,7 +72,7 @@ is evaluated. """ return self.function.free_symbols.union(set([self.transform_variable])) \ - - set([self.function_variable]) + - set([self.function_variable]) def _compute_transform(self, f, x, s, **hints): raise NotImplementedError @@ -105,7 +107,7 @@ from sympy import Add, expand_mul, Mul from sympy.core.function import AppliedUndef needeval = hints.pop('needeval', False) - try_directly = not any(func.has(self.function_variable) \ + try_directly = not any(func.has(self.function_variable) for func in self.function.atoms(AppliedUndef)) if try_directly: try: @@ -140,7 +142,8 @@ pass if needeval: - raise IntegralTransformError(self.__class__._name, self.function, 'needeval') + raise IntegralTransformError( + self.__class__._name, self.function, 'needeval') # TODO handle derivatives etc @@ -158,12 +161,14 @@ from sympy.solvers.inequalities import _solve_inequality + def _simplify(expr, doit): from sympy import powdenest, piecewise_fold if doit: return simplify(powdenest(piecewise_fold(expr), polar=True)) return expr + def _noconds_(default): """ This is a decorator generator for dropping convergence conditions. @@ -181,6 +186,7 @@ """ def make_wrapper(func): from sympy.core.decorators import wraps + @wraps(func) def wrapper(*args, **kwargs): noconds = kwargs.pop('noconds', default) @@ -200,6 +206,7 @@ def _default_integrator(f, x): return integrate(f, (x, 0, oo)) + @_noconds def _mellin_transform(f, x, s_, integrator=_default_integrator, simplify=True): """ Backend function to compute Mellin transforms. """ @@ -207,7 +214,7 @@ # We use a fresh dummy, because assumptions on s might drop conditions on # convergence of the integral. s = _dummy('s', 'mellin-transform', f) - F = integrator(x**(s-1) * f, x) + F = integrator(x**(s - 1) * f, x) if not F.has(Integral): return _simplify(F.subs(s, s_), simplify), (-oo, oo), True @@ -217,7 +224,8 @@ F, cond = F.args[0] if F.has(Integral): - raise IntegralTransformError('Mellin', f, 'integral in unexpected form') + raise IntegralTransformError( + 'Mellin', f, 'integral in unexpected form') def process_conds(cond): """ @@ -233,15 +241,16 @@ b_ = -oo aux_ = [] for d in disjuncts(c): - d_ = d.replace(re, lambda x: x.as_real_imag()[0]).subs(re(s), t) + d_ = d.replace( + re, lambda x: x.as_real_imag()[0]).subs(re(s), t) if not d.is_Relational or \ - d.rel_op not in ('>', '>=', '<', '<=') \ - or d_.has(s) or not d_.has(t): + d.rel_op not in ('>', '>=', '<', '<=') \ + or d_.has(s) or not d_.has(t): aux_ += [d] continue soln = _solve_inequality(d_, t) if not soln.is_Relational or \ - soln.rel_op not in ('>', '>=', '<', '<='): + soln.rel_op not in ('>', '>=', '<', '<='): aux_ += [d] continue if soln.lts == t: @@ -258,7 +267,7 @@ conds = [process_conds(c) for c in disjuncts(cond)] conds = [x for x in conds if x[2] is not False] - conds.sort(key=lambda x: (x[0]-x[1], count_ops(x[2]))) + conds.sort(key=lambda x: (x[0] - x[1], count_ops(x[2]))) if not conds: raise IntegralTransformError('Mellin', f, 'no convergence found') @@ -266,6 +275,7 @@ a, b, aux = conds[0] return _simplify(F.subs(s, s_), simplify), (a, b), aux + class MellinTransform(IntegralTransform): """ Class representing unevaluated Mellin transforms. @@ -283,7 +293,7 @@ def _as_integral(self, f, x, s): from sympy import Integral - return Integral(f*x**(s-1), (x, 0, oo)) + return Integral(f*x**(s - 1), (x, 0, oo)) def _collapse_extra(self, extra): from sympy import And, Max, Min @@ -296,9 +306,11 @@ cond += [c] res = (Max(*a), Min(*b)), And(*cond) if (res[0][0] >= res[0][1]) is True or res[1] is False: - raise IntegralTransformError('Mellin', None, 'no combined convergence.') + raise IntegralTransformError( + 'Mellin', None, 'no combined convergence.') return res + def mellin_transform(f, x, s, **hints): r""" Compute the Mellin transform `F(s)` of `f(x)`, @@ -306,17 +318,17 @@ .. math :: F(s) = \int_0^\infty x^{s-1} f(x) \mathrm{d}x. For all "sensible" functions, this converges absolutely in a strip - `a < Re(s) < b`. + `a < \operatorname{Re}(s) < b`. The Mellin transform is related via change of variables to the Fourier transform, and also to the (bilateral) Laplace transform. - This function returns (F, (a, b), cond) - where `F` is the Mellin transform of `f`, `(a, b)` is the fundamental strip - (as above), and cond are auxiliary convergence conditions. + This function returns ``(F, (a, b), cond)`` + where ``F`` is the Mellin transform of ``f``, ``(a, b)`` is the fundamental strip + (as above), and ``cond`` are auxiliary convergence conditions. If the integral cannot be computed in closed form, this function returns - an unevaluated MellinTransform object. + an unevaluated :class:`MellinTransform` object. For a description of possible hints, refer to the docstring of :func:`sympy.integrals.transforms.IntegralTransform.doit`. If ``noconds=False``, @@ -337,12 +349,13 @@ """ return MellinTransform(f, x, s).doit(**hints) + def _rewrite_sin(xxx_todo_changeme, s, a, b): """ - Re-write the sine function sin(m*s + n) as gamma functions, compatible + Re-write the sine function ``sin(m*s + n)`` as gamma functions, compatible with the strip (a, b). - Return (gamma1, gamma2, fac) so that f == fac/(gamma1 * gamma2). + Return ``(gamma1, gamma2, fac)`` so that ``f == fac/(gamma1 * gamma2)``. >>> from sympy.integrals.transforms import _rewrite_sin >>> from sympy import pi, S @@ -366,15 +379,17 @@ from sympy import expand_mul, pi, ceiling, gamma, re m = expand_mul(m/pi) n = expand_mul(n/pi) - r = ceiling(-m*a - n.as_real_imag()[0]) # Don't use re(n), does not expand + r = ceiling(-m*a - n.as_real_imag()[0]) # Don't use re(n), does not expand return gamma(m*s + n + r), gamma(1 - n - r - m*s), (-1)**r*pi + class MellinTransformStripError(ValueError): """ Exception raised by _rewrite_gamma. Mainly for internal use. """ pass + def _rewrite_gamma(f, s, a, b): """ Try to rewrite the product f(s) as a product of gamma functions, @@ -436,6 +451,7 @@ # 5) Combine all the exponentials. a_, b_ = S([a, b]) + def left(c, is_numer): """ Decide whether pole at c lies to the left of the fundamental strip. @@ -453,7 +469,7 @@ if is_numer: return None if a_.free_symbols or b_.free_symbols or c.free_symbols: - return None # XXX + return None # XXX #raise IntegralTransformError('Inverse Mellin', f, # 'Could not determine position of singularity %s' # ' relative to fundamental strip' % c) @@ -486,13 +502,14 @@ s_multipliers = [x/common_coefficient for x in s_multipliers] if any(not x.is_Rational for x in s_multipliers): raise NotImplementedError - s_multiplier = common_coefficient/reduce(ilcm, [S(x.q) for x in s_multipliers], S(1)) + s_multiplier = common_coefficient/reduce(ilcm, [S(x.q) + for x in s_multipliers], S(1)) if s_multiplier == common_coefficient: if len(s_multipliers) == 0: s_multiplier = common_coefficient else: s_multiplier = common_coefficient \ - *reduce(igcd, [S(x.p) for x in s_multipliers]) + *reduce(igcd, [S(x.p) for x in s_multipliers]) exponent = S(1) fac = S(1) @@ -517,6 +534,7 @@ denom_gammas = [] # exponentials will contain bases for exponentials of s exponentials = [] + def exception(fact): return IntegralTransformError("Inverse Mellin", f, "Unrecognised form '%s'." % fact) while args: @@ -544,10 +562,10 @@ elif fact.is_Pow or isinstance(fact, exp_): if fact.is_Pow: base = fact.base - exp = fact.exp + exp = fact.exp else: base = exp_polar(1) - exp = fact.args[0] + exp = fact.args[0] if exp.is_Integer: cond = is_numer if exp < 0: @@ -592,7 +610,8 @@ if is_numer: if (a > 0 and (left(-b/a, is_numer) is False)) or \ (a < 0 and (left(-b/a, is_numer) is True)): - raise NotImplementedError('Gammas partially over the strip.') + raise NotImplementedError( + 'Gammas partially over the strip.') ugammas += [(a, b)] elif isinstance(fact, sin): # We try to re-write all trigs as gammas. This is not in @@ -664,6 +683,7 @@ return (an, ap), (bm, bq), arg, exponent, fac + @_noconds_(True) def _inverse_mellin_transform(F, s, x_, strip, as_meijerg=False): """ A helper for the real inverse_mellin_transform function, this one here @@ -678,7 +698,7 @@ if g.is_Add: # do all terms separately ress = [_inverse_mellin_transform(G, s, x, strip, as_meijerg, - noconds=False) \ + noconds=False) for G in g.args] conds = [p[1] for p in ress] ress = [p[0] for p in ress] @@ -699,7 +719,7 @@ if h.is_Piecewise and len(h.args) == 3: # XXX we break modularity here! h = Heaviside(x - abs(C))*h.args[0].args[0] \ - + Heaviside(abs(C) - x)*h.args[1].args[0] + + Heaviside(abs(C) - x)*h.args[1].args[0] # We must ensure that the intgral along the line we want converges, # and return that value. # See [L], 5.2 @@ -710,12 +730,15 @@ abs(arg(G.argument)) == G.delta*pi)] cond = Or(*cond) if cond is False: - raise IntegralTransformError('Inverse Mellin', F, 'does not converge') + raise IntegralTransformError( + 'Inverse Mellin', F, 'does not converge') return (h*fac).subs(x, x_), cond raise IntegralTransformError('Inverse Mellin', F, '') _allowed = None + + class InverseMellinTransform(IntegralTransform): """ Class representing unevaluated inverse Mellin transforms. @@ -741,7 +764,7 @@ @property def fundamental_strip(self): - a, b = self.args[3], self.args[4] + a, b = self.args[3], self.args[4] if a is InverseMellinTransform._none_sentinel: a = None if b is InverseMellinTransform._none_sentinel: @@ -752,10 +775,12 @@ from sympy import postorder_traversal global _allowed if _allowed is None: - from sympy import (exp, gamma, sin, cos, tan, cot, cosh, sinh, tanh, - coth, factorial, rf) - _allowed = set([exp, gamma, sin, cos, tan, cot, cosh, sinh, tanh, coth, - factorial, rf]) + from sympy import ( + exp, gamma, sin, cos, tan, cot, cosh, sinh, tanh, + coth, factorial, rf) + _allowed = set( + [exp, gamma, sin, cos, tan, cot, cosh, sinh, tanh, coth, + factorial, rf]) for f in postorder_traversal(F): if f.is_Function and f.has(s) and f.func not in _allowed: raise IntegralTransformError('Inverse Mellin', F, @@ -768,6 +793,7 @@ c = self.__class__._c return Integral(F*x**(-s), (s, c - I*oo, c + I*oo)) + def inverse_mellin_transform(F, s, x, strip, **hints): r""" Compute the inverse Mellin transform of `F(s)` over the fundamental @@ -782,11 +808,11 @@ this recovers `f` from its Mellin transform `F` (and vice versa), for positive real `x`. - One of `a` or `b` may be passed as None; a suitable `c` will be + One of `a` or `b` may be passed as ``None``; a suitable `c` will be inferred. If the integral cannot be computed in closed form, this function returns - an unevaluated InverseMellinTransform object. + an unevaluated :class:`InverseMellinTransform` object. Note that this function will assume x to be positive and real, regardless of the sympy assumptions! @@ -804,11 +830,11 @@ >>> f = 1/(s**2 - 1) >>> inverse_mellin_transform(f, s, x, (-oo, -1)) - x*(1 - 1/x**2)*Heaviside(x - 1)/2 + (x/2 - 1/(2*x))*Heaviside(x - 1) >>> inverse_mellin_transform(f, s, x, (-1, 1)) -x*Heaviside(-x + 1)/2 - Heaviside(x - 1)/(2*x) >>> inverse_mellin_transform(f, s, x, (1, oo)) - (-x**2/2 + 1/2)*Heaviside(-x + 1)/x + (-x/2 + 1/(2*x))*Heaviside(-x + 1) See Also ======== @@ -824,8 +850,8 @@ ########################################################################## def _simplifyconds(expr, s, a): - """ - Naively simplify some conditions occuring in ``expr``, given that Re(s) > a. + r""" + Naively simplify some conditions occuring in ``expr``, given that `\operatorname{Re}(s) > a`. >>> from sympy.integrals.transforms import _simplifyconds as simp >>> from sympy.abc import x @@ -861,6 +887,7 @@ if ex.is_Pow and ex.base == s: return ex.exp return None + def bigger(ex1, ex2): """ Return True only if |ex1| > |ex2|, False only if |ex1| < |ex2|. Else return None. """ @@ -879,19 +906,22 @@ return False if n < 0 and (abs(ex1) >= abs(a)**n) is True: return True + def replie(x, y): """ simplify x < y """ if not (x.is_positive or x.func is Abs) \ - or not (y.is_positive or y.func is Abs): + or not (y.is_positive or y.func is Abs): return (x < y) r = bigger(x, y) if r is not None: return not r return (x < y) + def replue(x, y): if bigger(x, y) in (True, False): return True return Unequality(x, y) + def repl(ex, *args): if isinstance(ex, bool): return ex @@ -901,6 +931,7 @@ expr = repl(expr, Unequality, replue) return expr + @_noconds def _laplace_transform(f, t, s_, simplify=True): """ The backend function for Laplace transforms. """ @@ -913,11 +944,13 @@ return _simplify(F.subs(s, s_), simplify), -oo, True if not F.is_Piecewise: - raise IntegralTransformError('Laplace', f, 'could not compute integral') + raise IntegralTransformError( + 'Laplace', f, 'could not compute integral') F, cond = F.args[0] if F.has(Integral): - raise IntegralTransformError('Laplace', f, 'integral in unexpected form') + raise IntegralTransformError( + 'Laplace', f, 'integral in unexpected form') def process_conds(conds): """ Turn ``conds`` into a strip and auxiliary conditions. """ @@ -925,7 +958,8 @@ aux = True conds = conjuncts(to_cnf(conds)) u = Dummy('u', real=True) - p, q, w1, w2, w3, w4, w5 = symbols('p q w1 w2 w3 w4 w5', cls=Wild, exclude=[s]) + p, q, w1, w2, w3, w4, w5 = symbols( + 'p q w1 w2 w3 w4 w5', cls=Wild, exclude=[s]) for c in conds: a_ = oo aux_ = [] @@ -940,20 +974,23 @@ if m: if m[q] > 0 and m[w2]/m[p] == pi/2: d = re(s + m[w3]) > 0 - m = d.match(0 < cos(abs(arg(s**w1*w5, q))*w2)*abs(s**w3)**w4 - p) + m = d.match( + 0 < cos(abs(arg(s**w1*w5, q))*w2)*abs(s**w3)**w4 - p) if not m: - m = d.match(0 < cos(abs(arg(polar_lift(s)**w1*w5, q))*w2)*abs(s**w3)**w4 - p) + m = d.match(0 < cos(abs( + arg(polar_lift(s)**w1*w5, q))*w2)*abs(s**w3)**w4 - p) if m and all(m[wild] > 0 for wild in [w1, w2, w3, w4, w5]): d = re(s) > m[p] - d_ = d.replace(re, lambda x: x.expand().as_real_imag()[0]).subs(re(s), t) + d_ = d.replace( + re, lambda x: x.expand().as_real_imag()[0]).subs(re(s), t) if not d.is_Relational or \ - d.rel_op not in ('>', '>=', '<', '<=') \ - or d_.has(s) or not d_.has(t): + d.rel_op not in ('>', '>=', '<', '<=') \ + or d_.has(s) or not d_.has(t): aux_ += [d] continue soln = _solve_inequality(d_, t) if not soln.is_Relational or \ - soln.rel_op not in ('>', '>=', '<', '<='): + soln.rel_op not in ('>', '>=', '<', '<='): aux_ += [d] continue if soln.lts == t: @@ -972,6 +1009,7 @@ if not conds2: conds2 = [x for x in conds if x[1] is not False] conds = conds2 + def cnt(expr): if isinstance(expr, bool): return 0 @@ -991,6 +1029,7 @@ aux = _simplifyconds(aux, s, a) return _simplify(F.subs(s, s_), simplify), sbs(a), sbs(aux) + class LaplaceTransform(IntegralTransform): """ Class representing unevaluated Laplace transforms. @@ -1027,9 +1066,11 @@ cond = And(*conds) plane = Max(*planes) if cond is False: - raise IntegralTransformError('Laplace', None, 'No combined convergence.') + raise IntegralTransformError( + 'Laplace', None, 'No combined convergence.') return plane, cond + def laplace_transform(f, t, s, **hints): r""" Compute the Laplace Transform `F(s)` of `f(t)`, @@ -1037,14 +1078,14 @@ .. math :: F(s) = \int_0^\infty e^{-st} f(t) \mathrm{d}t. For all "sensible" functions, this converges absolutely in a - half plane `a < Re(s)`. + half plane `a < \operatorname{Re}(s)`. - This function returns (F, a, cond) - where `F` is the Laplace transform of `f`, `Re(s) > a` is the half-plane - of convergence, and cond are auxiliary convergence conditions. + This function returns ``(F, a, cond)`` + where ``F`` is the Laplace transform of ``f``, `\operatorname{Re}(s) > a` is the half-plane + of convergence, and ``cond`` are auxiliary convergence conditions. If the integral cannot be computed in closed form, this function returns - an unevaluated LaplaceTransform object. + an unevaluated :class:`LaplaceTransform` object. For a description of possible hints, refer to the docstring of :func:`sympy.integrals.transforms.IntegralTransform.doit`. If ``noconds=True``, @@ -1053,7 +1094,7 @@ >>> from sympy.integrals import laplace_transform >>> from sympy.abc import t, s, a >>> laplace_transform(t**a, t, s) - (s**(-a - 1)*gamma(a + 1), 0, -re(a) < 1) + (s**(-a)*gamma(a + 1)/s, 0, -re(a) < 1) See Also ======== @@ -1063,6 +1104,7 @@ """ return LaplaceTransform(f, t, s).doit(**hints) + @_noconds_(True) def _inverse_laplace_transform(F, s, t_, plane, simplify=True): """ The backend function for inverse Laplace transforms. """ @@ -1073,6 +1115,7 @@ # 2) Use the inversion integral. t = Dummy('t', real=True) + def pw_simp(*args): """ Simplify a piecewise expression from hyperexpand. """ # XXX we break modularity here! @@ -1083,7 +1126,7 @@ e1 = args[0].args[0] e2 = args[1].args[0] return Heaviside(1/abs(coeff) - t**exponent)*e1 \ - + Heaviside(t**exponent - 1/abs(coeff))*e2 + + Heaviside(t**exponent - 1/abs(coeff))*e2 try: f, cond = inverse_mellin_transform(F, s, exp(-t), (None, oo), @@ -1109,6 +1152,7 @@ return f.subs(t, t_), cond u = Dummy('u') + def simp_heaviside(arg): a = arg.subs(exp(-t), u) if a.has(t): @@ -1131,6 +1175,7 @@ return _simplify(f.subs(t, t_), simplify), cond + class InverseLaplaceTransform(IntegralTransform): """ Class representing unevaluated inverse Laplace transforms. @@ -1167,6 +1212,7 @@ c = self.__class__._c return Integral(exp(s*t)*F, (s, c - I*oo, c + I*oo)) + def inverse_laplace_transform(F, s, t, plane=None, **hints): r""" Compute the inverse Laplace transform of `F(s)`, defined as @@ -1174,7 +1220,7 @@ .. math :: f(t) = \int_{c-i\infty}^{c+i\infty} e^{st} F(s) \mathrm{d}s, for `c` so large that `F(s)` has no singularites in the - half-plane `Re(s) > c-\epsilon`. + half-plane `\operatorname{Re}(s) > c-\epsilon`. The plane can be specified by argument ``plane``, but will be inferred if passed as None. @@ -1184,7 +1230,7 @@ versa. If the integral cannot be computed in closed form, this function returns - an unevaluated InverseLaplaceTransform object. + an unevaluated :class:`InverseLaplaceTransform` object. Note that this function will always assume `t` to be real, regardless of the sympy assumption on `t`. @@ -1236,6 +1282,7 @@ return _simplify(F, simplify), cond + class FourierTypeTransform(IntegralTransform): """ Base class for Fourier transforms. Specify cls._a and cls._b. @@ -1252,6 +1299,7 @@ b = self.__class__._b return Integral(a*f*exp(b*I*x*k), (x, -oo, oo)) + class FourierTransform(FourierTypeTransform): """ Class representing unevaluated Fourier transforms. @@ -1266,6 +1314,7 @@ _a = 1 _b = -2*S.Pi + def fourier_transform(f, x, k, **hints): r""" Compute the unitary, ordinary-frequency Fourier transform of `f`, defined @@ -1274,7 +1323,7 @@ .. math:: F(k) = \int_{-\infty}^\infty f(x) e^{-2\pi i x k} \mathrm{d} x. If the transform cannot be computed in closed form, this - function returns an unevaluated FourierTransform object. + function returns an unevaluated :class:`FourierTransform` object. For other Fourier transform conventions, see the function :func:`sympy.integrals.transforms._fourier_transform`. @@ -1301,6 +1350,7 @@ """ return FourierTransform(f, x, k).doit(**hints) + class InverseFourierTransform(FourierTypeTransform): """ Class representing unevaluated inverse Fourier transforms. @@ -1315,6 +1365,7 @@ _a = 1 _b = 2*S.Pi + def inverse_fourier_transform(F, k, x, **hints): r""" Compute the unitary, ordinary-frequency inverse Fourier transform of `F`, @@ -1323,7 +1374,7 @@ .. math:: f(x) = \int_{-\infty}^\infty F(k) e^{2\pi i x k} \mathrm{d} k. If the transform cannot be computed in closed form, this - function returns an unevaluated InverseFourierTransform object. + function returns an unevaluated :class:`InverseFourierTransform` object. For other Fourier transform conventions, see the function :func:`sympy.integrals.transforms._fourier_transform`. @@ -1357,6 +1408,7 @@ from sympy import sin, cos, sqrt, pi, I, oo + @_noconds_(True) def _sine_cosine_transform(f, x, k, a, b, K, name, simplify=True): """ @@ -1381,6 +1433,7 @@ return _simplify(F, simplify), cond + class SineCosineTypeTransform(IntegralTransform): """ Base class for sine and cosine transforms. @@ -1400,6 +1453,7 @@ K = self.__class__._kern return Integral(a*f*K(b*x*k), (x, 0, oo)) + class SineTransform(SineCosineTypeTransform): """ Class representing unevaluated sine transforms. @@ -1415,6 +1469,7 @@ _a = sqrt(2)/sqrt(pi) _b = 1 + def sine_transform(f, x, k, **hints): r""" Compute the unitary, ordinary-frequency sine transform of `f`, defined @@ -1423,7 +1478,7 @@ .. math:: F(k) = \sqrt{\frac{2}{\pi}} \int_{0}^\infty f(x) \sin(2\pi x k) \mathrm{d} x. If the transform cannot be computed in closed form, this - function returns an unevaluated SineTransform object. + function returns an unevaluated :class:`SineTransform` object. For a description of possible hints, refer to the docstring of :func:`sympy.integrals.transforms.IntegralTransform.doit`. @@ -1447,6 +1502,7 @@ """ return SineTransform(f, x, k).doit(**hints) + class InverseSineTransform(SineCosineTypeTransform): """ Class representing unevaluated inverse sine transforms. @@ -1462,6 +1518,7 @@ _a = sqrt(2)/sqrt(pi) _b = 1 + def inverse_sine_transform(F, k, x, **hints): r""" Compute the unitary, ordinary-frequency inverse sine transform of `F`, @@ -1470,7 +1527,7 @@ .. math:: f(x) = \sqrt{\frac{2}{\pi}} \int_{0}^\infty F(k) \sin(2\pi x k) \mathrm{d} k. If the transform cannot be computed in closed form, this - function returns an unevaluated InverseSineTransform object. + function returns an unevaluated :class:`InverseSineTransform` object. For a description of possible hints, refer to the docstring of :func:`sympy.integrals.transforms.IntegralTransform.doit`. @@ -1478,7 +1535,8 @@ >>> from sympy import inverse_sine_transform, exp, sqrt, gamma, pi >>> from sympy.abc import x, k, a - >>> inverse_sine_transform(2**((1-2*a)/2)*k**(a - 1)*gamma(-a/2 + 1)/gamma((a+1)/2), k, x) + >>> inverse_sine_transform(2**((1-2*a)/2)*k**(a - 1)* + ... gamma(-a/2 + 1)/gamma((a+1)/2), k, x) x**(-a) >>> inverse_sine_transform(sqrt(2)*k*exp(-k**2/(4*a))/(4*sqrt(a)**3), k, x) x*exp(-a*x**2) @@ -1494,6 +1552,7 @@ """ return InverseSineTransform(F, k, x).doit(**hints) + class CosineTransform(SineCosineTypeTransform): """ Class representing unevaluated cosine transforms. @@ -1509,6 +1568,7 @@ _a = sqrt(2)/sqrt(pi) _b = 1 + def cosine_transform(f, x, k, **hints): r""" Compute the unitary, ordinary-frequency cosine transform of `f`, defined @@ -1517,7 +1577,7 @@ .. math:: F(k) = \sqrt{\frac{2}{\pi}} \int_{0}^\infty f(x) \cos(2\pi x k) \mathrm{d} x. If the transform cannot be computed in closed form, this - function returns an unevaluated CosineTransform object. + function returns an unevaluated :class:`CosineTransform` object. For a description of possible hints, refer to the docstring of :func:`sympy.integrals.transforms.IntegralTransform.doit`. @@ -1528,7 +1588,7 @@ >>> cosine_transform(exp(-a*x), x, k) sqrt(2)*a/(sqrt(pi)*(a**2 + k**2)) >>> cosine_transform(exp(-a*sqrt(x))*cos(a*sqrt(x)), x, k) - a*(-sinh(a**2/(2*k)) + cosh(a**2/(2*k)))/(2*k**(3/2)) + a*exp(-a**2/(2*k))/(2*k**(3/2)) See Also ======== @@ -1541,6 +1601,7 @@ """ return CosineTransform(f, x, k).doit(**hints) + class InverseCosineTransform(SineCosineTypeTransform): """ Class representing unevaluated inverse cosine transforms. @@ -1556,6 +1617,7 @@ _a = sqrt(2)/sqrt(pi) _b = 1 + def inverse_cosine_transform(F, k, x, **hints): r""" Compute the unitary, ordinary-frequency inverse cosine transform of `F`, @@ -1564,7 +1626,7 @@ .. math:: f(x) = \sqrt{\frac{2}{\pi}} \int_{0}^\infty F(k) \cos(2\pi x k) \mathrm{d} k. If the transform cannot be computed in closed form, this - function returns an unevaluated InverseCosineTransform object. + function returns an unevaluated :class:`InverseCosineTransform` object. For a description of possible hints, refer to the docstring of :func:`sympy.integrals.transforms.IntegralTransform.doit`. @@ -1573,7 +1635,7 @@ >>> from sympy import inverse_cosine_transform, exp, sqrt, pi >>> from sympy.abc import x, k, a >>> inverse_cosine_transform(sqrt(2)*a/(sqrt(pi)*(a**2 + k**2)), k, x) - -sinh(a*x) + cosh(a*x) + exp(-a*x) >>> inverse_cosine_transform(1/sqrt(k), k, x) 1/sqrt(x) @@ -1615,6 +1677,7 @@ return _simplify(F, simplify), cond + class HankelTypeTransform(IntegralTransform): """ Base class for Hankel transforms. @@ -1643,6 +1706,7 @@ self.transform_variable, self.args[3]) + class HankelTransform(HankelTypeTransform): """ Class representing unevaluated Hankel transforms. @@ -1655,6 +1719,7 @@ _name = 'Hankel' + def hankel_transform(f, r, k, nu, **hints): r""" Compute the Hankel transform of `f`, defined as @@ -1674,7 +1739,7 @@ >>> ht = hankel_transform(1/r**m, r, k, nu) >>> ht - 2**(-m + 1)*k**(m - 2)*gamma(-m/2 + nu/2 + 1)/gamma(m/2 + nu/2) + 2*2**(-m)*k**(m - 2)*gamma(-m/2 + nu/2 + 1)/gamma(m/2 + nu/2) >>> inverse_hankel_transform(ht, k, r, nu) r**(-m) @@ -1684,7 +1749,7 @@ a/(k**3*(a**2/k**2 + 1)**(3/2)) >>> inverse_hankel_transform(ht, k, r, 0) - -sinh(a*r) + cosh(a*r) + exp(-a*r) See Also ======== @@ -1697,6 +1762,7 @@ """ return HankelTransform(f, r, k, nu).doit(**hints) + class InverseHankelTransform(HankelTypeTransform): """ Class representing unevaluated inverse Hankel transforms. @@ -1709,6 +1775,7 @@ _name = 'Inverse Hankel' + def inverse_hankel_transform(F, k, r, nu, **hints): r""" Compute the inverse Hankel transform of `F` defined as @@ -1728,7 +1795,7 @@ >>> ht = hankel_transform(1/r**m, r, k, nu) >>> ht - 2**(-m + 1)*k**(m - 2)*gamma(-m/2 + nu/2 + 1)/gamma(m/2 + nu/2) + 2*2**(-m)*k**(m - 2)*gamma(-m/2 + nu/2 + 1)/gamma(m/2 + nu/2) >>> inverse_hankel_transform(ht, k, r, nu) r**(-m) @@ -1738,7 +1805,7 @@ a/(k**3*(a**2/k**2 + 1)**(3/2)) >>> inverse_hankel_transform(ht, k, r, 0) - -sinh(a*r) + cosh(a*r) + exp(-a*r) See Also ======== diff -Nru python3-sympy-0.7.2/sympy/integrals/trigonometry.py python3-sympy-0.7.3/sympy/integrals/trigonometry.py --- python3-sympy-0.7.2/sympy/integrals/trigonometry.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/integrals/trigonometry.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,9 +1,7 @@ # -*- coding: utf-8 -*- -from sympy.core import Dummy, Wild, S -from sympy.core.numbers import Rational, Integer -from sympy.functions import binomial, sin, cos, tan, sec, csc, cot -from sympy.core.cache import cacheit +from sympy.core import cacheit, Dummy, Eq, Integer, Rational, S, Wild +from sympy.functions import binomial, sin, cos, tan, sec, csc, cot, Piecewise # TODO sin(a*x)*cos(b*x) -> sin((a+b)x) + sin((a-b)x) ? @@ -12,6 +10,8 @@ # effectively block caching. # # so we cache the pattern + + @cacheit def _pat_sincos(x): a = Wild('a', exclude=[x]) @@ -22,7 +22,8 @@ _u = Dummy('u') -def trigintegrate(f, x): + +def trigintegrate(f, x, conds='piecewise'): """Integrate f = Mul(trig) over x >>> from sympy import Symbol, sin, cos, tan, sec, csc, cot @@ -41,7 +42,7 @@ >>> trigintegrate(sin(x)*tan(x), x) -log(sin(x) - 1)/2 + log(sin(x) + 1)/2 - sin(x) - http://en.wikibooks.org/wiki/Calculus/Further_integration_techniques + http://en.wikibooks.org/wiki/Calculus/Integration_techniques See Also ======== @@ -58,9 +59,10 @@ if M is None: return - n, m = M[n], M[m] + n, m = M[n], M[m] if n is S.Zero and m is S.Zero: return x + zz = x if n is S.Zero else S.Zero a = M[a] @@ -70,23 +72,25 @@ # take smallest n or m -- to choose simplest substitution if n_ and m_: - n_ = n_ and (n < m) # NB: careful here, one of the - m_ = m_ and not (n < m) # conditions *must* be true + n_ = n_ and (n < m) # NB: careful here, one of the + m_ = m_ and not (n < m) # conditions *must* be true # n m u=C (n-1)/2 m # S(x) * C(x) dx --> -(1-u^2) * u du if n_: - ff = -(1-u**2)**((n-1)/2) * u**m + ff = -(1 - u**2)**((n - 1)/2) * u**m uu = cos(a*x) # n m u=S n (m-1)/2 # S(x) * C(x) dx --> u * (1-u^2) du elif m_: - ff = u**n * (1-u**2)**((m-1)/2) + ff = u**n * (1 - u**2)**((m - 1)/2) uu = sin(a*x) - fi = integrate(ff, u) # XXX cyclic deps + fi = integrate(ff, u) # XXX cyclic deps fx = fi.subs(u, uu) + if conds == 'piecewise': + return Piecewise((zz, Eq(a, 0)), (fx / a, True)) return fx / a # n & m are both even @@ -111,10 +115,10 @@ if n_: # 2k 2 k i 2i # C = (1 - S ) = sum(i, (-) * B(k, i) * S ) - if m > 0 : + if m > 0: for i in range(0, m//2 + 1): res += ((-1)**i * binomial(m//2, i) * - _sin_pow_integrate(n+2*i, x)) + _sin_pow_integrate(n + 2*i, x)) elif m == 0: res = _sin_pow_integrate(n, x) @@ -136,9 +140,9 @@ # m + 1 m + 1 | # / - res = (Rational(-1, m+1) * cos(x)**(m+1) * sin(x)**(n-1) + - Rational(n-1, m+1) * - trigintegrate(cos(x)**(m+2)*sin(x)**(n-2), x)) + res = (Rational(-1, m + 1) * cos(x)**(m + 1) * sin(x)**(n - 1) + + Rational(n - 1, m + 1) * + trigintegrate(cos(x)**(m + 2)*sin(x)**(n - 2), x)) elif m_: # 2k 2 k i 2i @@ -160,9 +164,9 @@ for i in range(0, n//2 + 1): res += ((-1)**i * binomial(n//2, i) * - _cos_pow_integrate(m+2*i, x)) + _cos_pow_integrate(m + 2*i, x)) - elif n == 0 : + elif n == 0: # / # | @@ -192,11 +196,11 @@ # n + 1 n + 1 | # / - res = (Rational(1, n+1) * cos(x)**(m-1)*sin(x)**(n+1) + - Rational(m-1, n+1) * - trigintegrate(cos(x)**(m-2)*sin(x)**(n+2), x)) + res = (Rational(1, n + 1) * cos(x)**(m - 1)*sin(x)**(n + 1) + + Rational(m - 1, n + 1) * + trigintegrate(cos(x)**(m - 2)*sin(x)**(n + 2), x)) - else : + else: if m == n: ##Substitute sin(2x)/2 for sin(x)cos(x) and then Integrate. res = integrate((Rational(1, 2)*sin(2*x))**m, x) @@ -206,17 +210,20 @@ # the function argument to integrate in the end will # be 1 , this cannot be integrated by trigintegrate. # Hence use sympy.integrals.integrate. - res = (Rational(1, n+1) * cos(x)**(m-1) * sin(x)**(n+1) + - Rational(m-1, n+1) * - integrate(cos(x)**(m-2) * sin(x)**(n+2), x)) + res = (Rational(1, n + 1) * cos(x)**(m - 1) * sin(x)**(n + 1) + + Rational(m - 1, n + 1) * + integrate(cos(x)**(m - 2) * sin(x)**(n + 2), x)) else: - res = (Rational(-1, m+1) * cos(x)**(m+1) * sin(x)**(n-1) + - Rational(n-1, m+1) * - integrate(cos(x)**(m+2)*sin(x)**(n-2), x)) + res = (Rational(-1, m + 1) * cos(x)**(m + 1) * sin(x)**(n - 1) + + Rational(n - 1, m + 1) * + integrate(cos(x)**(m + 2)*sin(x)**(n - 2), x)) + if conds == 'piecewise': + return Piecewise((zz, Eq(a, 0)), (res.subs(x, a*x) / a, True)) return res.subs(x, a*x) / a + def _sin_pow_integrate(n, x): - if n > 0 : + if n > 0: if n == 1: #Recursion break return -cos(x) @@ -232,8 +239,8 @@ # # - return (Rational(-1, n) * cos(x) * sin(x)**(n-1) + - Rational(n-1, n) * _sin_pow_integrate(n-2, x)) + return (Rational(-1, n) * cos(x) * sin(x)**(n - 1) + + Rational(n - 1, n) * _sin_pow_integrate(n - 2, x)) if n < 0: if n == -1: @@ -251,17 +258,18 @@ #/ / # - return (Rational(1, n+1) * cos(x) * sin(x)**(n+1) + - Rational(n+2, n+1) * _sin_pow_integrate(n+2, x)) + return (Rational(1, n + 1) * cos(x) * sin(x)**(n + 1) + + Rational(n + 2, n + 1) * _sin_pow_integrate(n + 2, x)) else: #n == 0 #Recursion break. return x + def _cos_pow_integrate(n, x): - if n > 0 : - if n==1: + if n > 0: + if n == 1: #Recursion break. return sin(x) @@ -275,8 +283,8 @@ #/ / # - return (Rational(1, n) * sin(x) * cos(x)**(n-1) + - Rational(n-1, n) * _cos_pow_integrate(n-2, x)) + return (Rational(1, n) * sin(x) * cos(x)**(n - 1) + + Rational(n - 1, n) * _cos_pow_integrate(n - 2, x)) if n < 0: if n == -1: @@ -293,9 +301,9 @@ #/ / # - return (Rational(-1, n+1) * sin(x) * cos(x)**(n+1) + - Rational(n+2, n+1) * _cos_pow_integrate(n+2, x)) - else : + return (Rational(-1, n + 1) * sin(x) * cos(x)**(n + 1) + + Rational(n + 2, n + 1) * _cos_pow_integrate(n + 2, x)) + else: # n == 0 #Recursion Break. return x diff -Nru python3-sympy-0.7.2/sympy/interactive/ipythonprinting.py python3-sympy-0.7.3/sympy/interactive/ipythonprinting.py --- python3-sympy-0.7.2/sympy/interactive/ipythonprinting.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/interactive/ipythonprinting.py 2013-07-13 17:53:32.000000000 +0000 @@ -26,26 +26,24 @@ # Imports #----------------------------------------------------------------------------- +import warnings + from sympy.interactive.printing import init_printing +from sympy.utilities.exceptions import SymPyDeprecationWarning #----------------------------------------------------------------------------- # Definitions of special display functions for use with IPython #----------------------------------------------------------------------------- -_loaded = False - def load_ipython_extension(ip): """Load the extension in IPython.""" - import IPython - - global _loaded - # Use extension manager to track loaded status if available - # This is currently in IPython 0.14.dev - if hasattr(ip.extension_manager, 'loaded'): - loaded = 'sympy.interactive.ipythonprinting' not in ip.extension_manager.loaded - else: - loaded = _loaded - - if not loaded: - init_printing(ip=ip) - _loaded = True + # Since Python filters deprecation warnings by default, + # we add a filter to make sure this message will be shown. + warnings.simplefilter("once", SymPyDeprecationWarning) + SymPyDeprecationWarning( + feature="using %load_ext sympy.interactive.ipythonprinting", + useinstead="from sympy import init_printing ; init_printing()", + deprecated_since_version="0.7.3", + issue=3914 + ).warn() + init_printing(ip=ip) diff -Nru python3-sympy-0.7.2/sympy/interactive/printing.py python3-sympy-0.7.3/sympy/interactive/printing.py --- python3-sympy-0.7.2/sympy/interactive/printing.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/interactive/printing.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,10 +1,15 @@ """Tools for setting up printing in interactive sessions. """ +from io import StringIO + from sympy import latex +from sympy import preview + def _init_python_printing(stringify_func): """Setup printing in Python interactive session. """ - import builtins, sys + import builtins + import sys def _displayhook(arg): """Python's pretty-printer display hook. @@ -21,40 +26,47 @@ sys.displayhook = _displayhook -def _init_ipython_printing(ip, stringify_func, render_latex): + +def _init_ipython_printing(ip, stringify_func, use_latex, euler, + forecolor, backcolor, fontsize, latex_mode): """Setup printing in IPython interactive session. """ - # For IPython >= 0.11, will use latex_to_png to render LaTeX - try: - from IPython.lib.latextools import latex_to_png - except ImportError: - pass - def _print_pretty(arg, p, cycle): + preamble = "\\documentclass[%s]{article}\n" \ + "\\pagestyle{empty}\n" \ + "\\usepackage{amsmath,amsfonts}%s\\begin{document}" + if euler: + addpackages = '\\usepackage{euler}' + else: + addpackages = '' + preamble = preamble % (fontsize, addpackages) + + imagesize = 'tight' + offset = "0cm,0cm" + resolution = 150 + dvi = r"-T %s -D %d -bg %s -fg %s -O %s" % ( + imagesize, resolution, backcolor, forecolor, offset) + dvioptions = dvi.split() + # print "DVIOPTIONS", dvioptions + # print "PREAMBLE", preamble + + def _print_plain(arg, p, cycle): """caller for pretty, for use in IPython 0.11""" - p.text(stringify_func(arg)) + if _can_print_latex(arg): + p.text(stringify_func(arg)) + else: + p.text(IPython.lib.pretty.pretty(arg)) - def _print_png(o): - """ - A function to display sympy expressions using inline style LaTeX in PNG. - """ - s = latex(o, mode='inline') - # mathtext does not understand centain latex flags, so we try to - # replace them with suitable subs - s = s.replace(r'\operatorname', '') - s = s.replace(r'\overline', r'\bar') - png = latex_to_png(s) - return png + def _preview_wrapper(o): + exprbuffer = StringIO() + preview(o, output='png', viewer='StringIO', outputbuffer=exprbuffer, + preamble=preamble, dvioptions=dvioptions) + return exprbuffer.getvalue() - def _print_display_png(o): - """ - A function to display sympy expression using display style LaTeX in PNG. - """ - s = latex(o, mode='plain') - s = s.strip('$') - # As matplotlib does not support display style, dvipng backend is used - # here - png = latex_to_png(s, backend='dvipng', wrap=True) - return png + def _print_latex_png(o): + if _can_print_latex(o): + s = latex(o, mode=latex_mode) + return _preview_wrapper(s) + return None def _can_print_latex(o): """Return True if type o can be printed with LaTeX. @@ -67,11 +79,13 @@ return all(_can_print_latex(i) for i in o) elif isinstance(o, dict): return all((isinstance(i, str) or _can_print_latex(i)) and _can_print_latex(o[i]) for i in o) - elif isinstance(o,(sympy.Basic, sympy.matrices.MatrixBase, int, float)): + elif isinstance(o, bool): + return False + elif isinstance(o, (sympy.Basic, sympy.matrices.MatrixBase, int, float)): return True return False - def _print_latex(o): + def _print_latex_text(o): """ A function to generate the latex representation of sympy expressions. """ @@ -103,46 +117,40 @@ import IPython if IPython.__version__ >= '0.11': - printable_containers = [tuple, list, set, frozenset] + from sympy.core.basic import Basic + from sympy.matrices.matrices import MatrixBase + printable_types = [Basic, MatrixBase, int, int, float, + tuple, list, set, frozenset, dict] plaintext_formatter = ip.display_formatter.formatters['text/plain'] - for cls in [object, str, dict] + printable_containers: - plaintext_formatter.for_type(cls, _print_pretty) + for cls in printable_types: + plaintext_formatter.for_type(cls, _print_plain) - plaintext_formatter.for_type_by_name( - 'sympy.core.basic', 'Basic', _print_pretty - ) - plaintext_formatter.for_type_by_name( - 'sympy.matrices.matrices', 'MatrixBase', _print_pretty - ) - - if render_latex: - png_formatter = ip.display_formatter.formatters['image/png'] - - png_formatter.for_type_by_name( - 'sympy.core.basic', 'Basic', _print_png - ) - png_formatter.for_type_by_name( - 'sympy.matrices.matrices', 'MatrixBase', _print_display_png - ) - - for cls in [dict, int, int, float] + printable_containers: - png_formatter.for_type(cls, _print_png) - - latex_formatter = ip.display_formatter.formatters['text/latex'] - latex_formatter.for_type_by_name( - 'sympy.core.basic', 'Basic', _print_latex - ) - latex_formatter.for_type_by_name( - 'sympy.matrices.matrices', 'MatrixBase', _print_latex - ) - for cls in printable_containers: - latex_formatter.for_type(cls, _print_latex) + png_formatter = ip.display_formatter.formatters['image/png'] + if use_latex in (True, 'png'): + for cls in printable_types: + png_formatter.for_type(cls, _print_latex_png) + png_formatter.enabled = True + else: + png_formatter.enabled = False + + latex_formatter = ip.display_formatter.formatters['text/latex'] + if use_latex in (True, 'mathjax'): + for cls in printable_types: + latex_formatter.for_type(cls, _print_latex_text) + latex_formatter.enabled = True + else: + latex_formatter.enabled = False else: ip.set_hook('result_display', _result_display) -def init_printing(pretty_print=True, order=None, use_unicode=None, use_latex=None, wrap_line=None, num_columns=None, no_global=False, ip=None): + +def init_printing(pretty_print=True, order=None, use_unicode=None, + use_latex=None, wrap_line=None, num_columns=None, + no_global=False, ip=None, euler=False, forecolor='Black', + backcolor='Transparent', fontsize='10pt', + latex_mode='equation*'): """ Initializes pretty-printer depending on the environment. @@ -162,9 +170,11 @@ use_unicode: boolean or None If True, use unicode characters; if False, do not use unicode characters. - use_latex: boolean or None + use_latex: string, boolean or None If True, use latex rendering in GUI interfaces; - if False, do not use latex rendering + if False, do not use latex rendering; the string + 'png' specifies using latex-rendered images while + the string 'mathjax' specifies using MathJax only. wrap_line: boolean If True, lines will wrap at the end; if False, they will not wrap but continue as one line. @@ -213,6 +223,7 @@ x + y + x**2 + y**2 """ + import sys from sympy.printing.printer import Printer if pretty_print: @@ -227,30 +238,45 @@ except NameError: pass - if ip: + if ip and pretty_print: try: - from IPython.zmq.zmqshell import ZMQInteractiveShell + import IPython + # IPython 1.0 deprecates the frontend module, so we import directly + # from the terminal module to prevent a deprecation message from being + # shown. + if IPython.__version__ >= '1.0': + from IPython.terminal.interactiveshell import TerminalInteractiveShell + else: + from IPython.frontend.terminal.interactiveshell import TerminalInteractiveShell + from code import InteractiveConsole except ImportError: pass else: - # If in qtconsole or notebook - if isinstance(ip, ZMQInteractiveShell): + # This will be True if we are in the qtconsole or notebook + if not isinstance(ip, (InteractiveConsole, TerminalInteractiveShell)) \ + and 'ipython-console' not in ''.join(sys.argv): if use_unicode is None: use_unicode = True if use_latex is None: use_latex = True if not no_global: - Printer.set_global_settings(order=order, use_unicode=use_unicode, wrap_line=wrap_line, num_columns=num_columns) + Printer.set_global_settings(order=order, use_unicode=use_unicode, + wrap_line=wrap_line, num_columns=num_columns) else: _stringify_func = stringify_func if pretty_print: - stringify_func = lambda expr: _stringify_func(expr, order=order, use_unicode=use_unicode, wrap_line=wrap_line, num_columns=num_columns) + stringify_func = lambda expr: \ + _stringify_func(expr, order=order, + use_unicode=use_unicode, + wrap_line=wrap_line, + num_columns=num_columns) else: stringify_func = lambda expr: _stringify_func(expr, order=order) if ip is not None and ip.__module__.startswith('IPython'): - _init_ipython_printing(ip, stringify_func, use_latex) + _init_ipython_printing(ip, stringify_func, use_latex, euler, forecolor, + backcolor, fontsize, latex_mode) else: _init_python_printing(stringify_func) diff -Nru python3-sympy-0.7.2/sympy/interactive/session.py python3-sympy-0.7.3/sympy/interactive/session.py --- python3-sympy-0.7.2/sympy/interactive/session.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/interactive/session.py 2013-07-13 17:53:32.000000000 +0000 @@ -22,6 +22,7 @@ just install the 'ipython' package and start isympy again. """ + def _make_message(ipython=True, quiet=False, source=None): """Create a banner for an interactive session. """ from sympy import __version__ as sympy_version @@ -68,6 +69,7 @@ return message + def int_to_Integer(s): """ Wrap integer literals with Integer. @@ -79,6 +81,7 @@ Example ======= + >>> >>> from sympy.interactive.session import int_to_Integer >>> from sympy import Integer >>> s = '1.2 + 1/2 - 0x12 + a1' @@ -87,7 +90,7 @@ >>> s = 'print (1/2)' >>> int_to_Integer(s) 'print (Integer (1 )/Integer (2 ))' - >>> exec(s) #doctest: +SKIP + >>> exec(s) 0.5 >>> exec(int_to_Integer(s)) 1/2 @@ -106,7 +109,7 @@ result = [] g = generate_tokens(StringIO(s).readline) # tokenize the string - for toknum, tokval, _, _, _ in g: + for toknum, tokval, _, _, _ in g: if toknum == NUMBER and _is_int(tokval): # replace NUMBER tokens result.extend([ (NAME, 'Integer'), @@ -155,6 +158,7 @@ # """ # app.shell.prefilter_manager.register_transformer(int_transformer) + def enable_automatic_int_sympification(app): """ Allow IPython to automatically convert integer literals to Integer. @@ -166,6 +170,7 @@ old_run_cell = app.shell.run_cell else: old_run_cell = app.run_cell + def my_run_cell(cell, *args, **kwargs): try: # Check the cell for syntax errors. This way, the syntax error @@ -185,6 +190,7 @@ else: app.run_cell = my_run_cell + def enable_automatic_symbols(app): """Allow IPython to automatially create symbols (``isympy -a``). """ # XXX: This should perhaps use tokenize, like int_to_Integer() above. @@ -225,7 +231,8 @@ # multiple times. import re - re_nameerror = re.compile("name '(?P[A-Za-z_][A-Za-z0-9_]*)' is not defined") + re_nameerror = re.compile( + "name '(?P[A-Za-z_][A-Za-z0-9_]*)' is not defined") def _handler(self, etype, value, tb, tb_offset=None): """Handle :exc:`NameError` exception and allow injection of missing symbols. """ @@ -248,7 +255,8 @@ self.run_cell("del %s" % match.group("symbol"), store_history=False) - stb = self.InteractiveTB.structured_traceback(etype, value, tb, tb_offset=tb_offset) + stb = self.InteractiveTB.structured_traceback( + etype, value, tb, tb_offset=tb_offset) self._showtraceback(etype, value, stb) if hasattr(app, 'shell'): @@ -257,13 +265,20 @@ # This was restructured in IPython 0.13 app.set_custom_exc((NameError,), _handler) + def init_ipython_session(argv=[], auto_symbols=False, auto_int_to_Integer=False): """Construct new IPython session. """ import IPython if IPython.__version__ >= '0.11': # use an app to parse the command line, and init config - from IPython.frontend.terminal import ipapp + # IPython 1.0 deprecates the frontend module, so we import directly + # from the terminal module to prevent a deprecation message from being + # shown. + if IPython.__version__ >= '1.0': + from IPython.terminal import ipapp + else: + from IPython.frontend.terminal import ipapp app = ipapp.TerminalIPythonApp() # don't draw IPython banner during initialization: @@ -280,6 +295,7 @@ from IPython.Shell import make_IPython return make_IPython(argv) + def init_python_session(): """Construct new Python session. """ from code import InteractiveConsole @@ -312,6 +328,7 @@ return SymPyConsole() + def init_session(ipython=None, pretty_print=True, order=None, use_unicode=None, use_latex=None, quiet=False, auto_symbols=False, auto_int_to_Integer=False, argv=[]): @@ -354,7 +371,8 @@ ipython: boolean or None If True, printing will initialize for an IPython console; if False, printing will initialize for a normal console; - The default is None, which does what False does. + The default is None, which automatically determines whether we are in + an ipython instance or not. argv: list of arguments for IPython See sympy.bin.isympy for options that can be used to initialize IPython. @@ -401,23 +419,14 @@ in_ipython = False - if ipython is False: - ip = init_python_session() - mainloop = ip.interact - else: + if ipython is not False: try: import IPython except ImportError: - if ipython is not True: - if not quiet: - print(no_ipython) - ip = init_python_session() - mainloop = ip.interact - else: + if ipython is True: raise RuntimeError("IPython is not available on this system") + ip = None else: - ipython = True - if IPython.__version__ >= '0.11': try: ip = get_ipython() @@ -427,30 +436,35 @@ ip = IPython.ipapi.get() if ip: ip = ip.IP + in_ipython = bool(ip) + if ipython is None: + ipython = in_ipython - if ip is not None: - in_ipython = True - else: - ip = init_ipython_session(argv=argv, - auto_symbols=auto_symbols, auto_int_to_Integer=auto_int_to_Integer) - - if IPython.__version__ >= '0.11': - # runsource is gone, use run_cell instead, which doesn't - # take a symbol arg. The second arg is `store_history`, - # and False means don't add the line to IPython's history. - ip.runsource = lambda src, symbol='exec': ip.run_cell(src, False) + if ipython is False: + ip = init_python_session() + mainloop = ip.interact + else: + if ip is None: + ip = init_ipython_session(argv=argv, auto_symbols=auto_symbols, + auto_int_to_Integer=auto_int_to_Integer) + + if IPython.__version__ >= '0.11': + # runsource is gone, use run_cell instead, which doesn't + # take a symbol arg. The second arg is `store_history`, + # and False means don't add the line to IPython's history. + ip.runsource = lambda src, symbol='exec': ip.run_cell(src, False) - #Enable interactive plotting using pylab. - try: - ip.enable_pylab(import_all=False) - except Exception: - # Causes an import error if matplotlib is not installed. - # Causes other errors (depending on the backend) if there - # is no display, or if there is some problem in the - # backend, so we have a bare "except Exception" here - pass - if not in_ipython: - mainloop = ip.mainloop + #Enable interactive plotting using pylab. + try: + ip.enable_pylab(import_all=False) + except Exception: + # Causes an import error if matplotlib is not installed. + # Causes other errors (depending on the backend) if there + # is no display, or if there is some problem in the + # backend, so we have a bare "except Exception" here + pass + if not in_ipython: + mainloop = ip.mainloop if auto_symbols and (not ipython or IPython.__version__ < '0.11'): raise RuntimeError("automatic construction of symbols is possible only in IPython 0.11 or above") diff -Nru python3-sympy-0.7.2/sympy/interactive/tests/test_interactive.py python3-sympy-0.7.3/sympy/interactive/tests/test_interactive.py --- python3-sympy-0.7.2/sympy/interactive/tests/test_interactive.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/interactive/tests/test_interactive.py 2013-07-13 17:53:32.000000000 +0000 @@ -2,6 +2,7 @@ from sympy.interactive.session import int_to_Integer + def test_int_to_Integer(): assert int_to_Integer("1 + 2.2 + 0x3 + 40") == \ 'Integer (1 )+2.2 +Integer (0x3 )+Integer (40 )' @@ -12,4 +13,5 @@ assert int_to_Integer("0b101") == 'Integer (0b101 )' assert int_to_Integer("ab1 + 1 + '1 + 2'") == "ab1 +Integer (1 )+'1 + 2'" assert int_to_Integer("(2 + \n3)") == '(Integer (2 )+\nInteger (3 ))' - assert int_to_Integer("2 + 2.0 + 2j + 2e-10") == 'Integer (2 )+2.0 +2j +2e-10 ' + assert int_to_Integer( + "2 + 2.0 + 2j + 2e-10") == 'Integer (2 )+2.0 +2j +2e-10 ' diff -Nru python3-sympy-0.7.2/sympy/interactive/tests/test_ipython.py python3-sympy-0.7.3/sympy/interactive/tests/test_ipython.py --- python3-sympy-0.7.2/sympy/interactive/tests/test_ipython.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/interactive/tests/test_ipython.py 2013-07-13 17:53:32.000000000 +0000 @@ -12,12 +12,14 @@ # @requires('IPython', version=">=0.11") # def test_automatic_symbols(ipython): +# run_cell was added in IPython 0.11 ipython = import_module("IPython", min_module_version="0.11") if not ipython: #bin/test will not execute any tests now disabled = True + def test_automatic_symbols(): # NOTE: Because of the way the hook works, you have to use run_cell(code, # True). This means that the code must have no Out, or it will be printed @@ -39,12 +41,13 @@ # Check that built-in names aren't overridden app.run_cell("a = all == __builtin__.all", True) assert "all" not in app.user_ns - assert app.user_ns['a'] == True + assert app.user_ns['a'] is True # Check that sympy names aren't overridden app.run_cell("import sympy") app.run_cell("a = factorial == sympy.factorial", True) - assert app.user_ns['a'] == True + assert app.user_ns['a'] is True + def test_int_to_Integer(): # XXX: Warning, don't test with == here. 0.5 == Rational(1, 2) is True! diff -Nru python3-sympy-0.7.2/sympy/interactive/tests/test_ipythonprinting.py python3-sympy-0.7.3/sympy/interactive/tests/test_ipythonprinting.py --- python3-sympy-0.7.2/sympy/interactive/tests/test_ipythonprinting.py 1970-01-01 00:00:00.000000000 +0000 +++ python3-sympy-0.7.3/sympy/interactive/tests/test_ipythonprinting.py 2013-07-13 17:53:32.000000000 +0000 @@ -0,0 +1,44 @@ +"""Tests that the IPython printing module is properly loaded. """ + +from sympy.interactive.session import init_ipython_session +from sympy.external import import_module + +# run_cell was added in IPython 0.11 +ipython = import_module("IPython", min_module_version="0.11") + +# disable tests if ipython is not present +if not ipython: + disabled = True + +def test_ipythonprinting(): + # Initialize and setup IPython session + app = init_ipython_session() + app.run_cell("ip = get_ipython()") + app.run_cell("inst = ip.instance()") + app.run_cell("format = inst.display_formatter.format") + app.run_cell("from sympy import Symbol") + + # Printing without printing extension + app.run_cell("a = format(Symbol('pi'))") + app.run_cell("a2 = format(Symbol('pi')**2)") + # Deal with API change starting at IPython 1.0 + if int(ipython.__version__.split(".")[0]) < 1: + assert app.user_ns['a']['text/plain'] == "pi" + assert app.user_ns['a2']['text/plain'] == "pi**2" + else: + assert app.user_ns['a'][0]['text/plain'] == "pi" + assert app.user_ns['a2'][0]['text/plain'] == "pi**2" + + # Load printing extension + app.run_cell("from sympy import init_printing") + app.run_cell("init_printing()") + # Printing with printing extension + app.run_cell("a = format(Symbol('pi'))") + app.run_cell("a2 = format(Symbol('pi')**2)") + # Deal with API change starting at IPython 1.0 + if int(ipython.__version__.split(".")[0]) < 1: + assert app.user_ns['a']['text/plain'] in ('\u03c0', 'pi') + assert app.user_ns['a2']['text/plain'] in (' 2\n\u03c0 ', ' 2\npi ') + else: + assert app.user_ns['a'][0]['text/plain'] in ('\u03c0', 'pi') + assert app.user_ns['a2'][0]['text/plain'] in (' 2\n\u03c0 ', ' 2\npi ') diff -Nru python3-sympy-0.7.2/sympy/logic/__init__.py python3-sympy-0.7.3/sympy/logic/__init__.py --- python3-sympy-0.7.2/sympy/logic/__init__.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/logic/__init__.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,2 +1,3 @@ -from .boolalg import to_cnf, And, Or, Not, Xor, Nand, Nor, Implies, Equivalent, ITE +from .boolalg import (to_cnf, And, Or, Not, Xor, Nand, Nor, Implies, Equivalent, + ITE, POSform, SOPform, simplify_logic, bool_equal) from .inference import satisfiable diff -Nru python3-sympy-0.7.2/sympy/logic/algorithms/dpll.py python3-sympy-0.7.3/sympy/logic/algorithms/dpll.py --- python3-sympy-0.7.2/sympy/logic/algorithms/dpll.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/logic/algorithms/dpll.py 2013-07-13 17:53:32.000000000 +0000 @@ -14,6 +14,7 @@ from sympy.logic.inference import pl_true, literal_symbol from functools import reduce + def dpll_satisfiable(expr): """ Check satisfiability of a propositional sentence. @@ -36,9 +37,10 @@ return result output = {} for key in result: - output.update({symbols[key-1]: result[key]}) + output.update({symbols[key - 1]: result[key]}) return output + def dpll(clauses, symbols, model): """ Compute satisfiability in a partial model. @@ -55,27 +57,30 @@ while P: model.update({P: value}) symbols.remove(P) - if not value: P = ~P + if not value: + P = ~P clauses = unit_propagate(clauses, P) P, value = find_unit_clause(clauses, model) P, value = find_pure_symbol(symbols, clauses) while P: model.update({P: value}) symbols.remove(P) - if not value: P = ~P + if not value: + P = ~P clauses = unit_propagate(clauses, P) P, value = find_pure_symbol(symbols, clauses) # end DP kernel unknown_clauses = [] for c in clauses: - val = pl_true(c, model) - if val == False: + val = pl_true(c, model) + if val is False: return False - if val != True: + if val is not True: unknown_clauses.append(c) if not unknown_clauses: return model - if not clauses: return model + if not clauses: + return model P = symbols.pop() model_copy = model.copy() model.update({P: True}) @@ -84,6 +89,7 @@ return (dpll(unit_propagate(unknown_clauses, P), symbols, model) or dpll(unit_propagate(unknown_clauses, Not(P)), symbols_copy, model_copy)) + def dpll_int_repr(clauses, symbols, model): """ Compute satisfiability in a partial model. @@ -114,7 +120,7 @@ # end DP kernel unknown_clauses = [] for c in clauses: - val = pl_true_int_repr(c, model) + val = pl_true_int_repr(c, model) if val is False: return False if val is not True: @@ -131,6 +137,7 @@ ### helper methods for DPLL + def pl_true_int_repr(clause, model={}): """ Lightweight version of pl_true. @@ -157,6 +164,7 @@ result = None return result + def unit_propagate(clauses, symbol): """ Returns an equivalent set of clauses @@ -190,6 +198,7 @@ output.append(c) return output + def unit_propagate_int_repr(clauses, s): """ Same as unit_propagate, but arguments are expected to be in integer @@ -219,18 +228,23 @@ for sym in symbols: found_pos, found_neg = False, False for c in unknown_clauses: - if not found_pos and sym in disjuncts(c): found_pos = True - if not found_neg and Not(sym) in disjuncts(c): found_neg = True - if found_pos != found_neg: return sym, found_pos + if not found_pos and sym in disjuncts(c): + found_pos = True + if not found_neg and Not(sym) in disjuncts(c): + found_neg = True + if found_pos != found_neg: + return sym, found_pos return None, None + def find_pure_symbol_int_repr(symbols, unknown_clauses): """ Same as find_pure_symbol, but arguments are expected to be in integer representation >>> from sympy.logic.algorithms.dpll import find_pure_symbol_int_repr - >>> find_pure_symbol_int_repr(set([1,2,3]), [set([1, -2]), set([-2, -3]), set([3, 1])]) + >>> find_pure_symbol_int_repr(set([1,2,3]), + ... [set([1, -2]), set([-2, -3]), set([3, 1])]) (1, True) """ @@ -245,6 +259,7 @@ return -p, False return None, None + def find_unit_clause(clauses, model): """ A unit clause has only 1 variable that is not bound in the model. @@ -267,13 +282,15 @@ return P, value return None, None + def find_unit_clause_int_repr(clauses, model): """ Same as find_unit_clause, but arguments are expected to be in integer representation. >>> from sympy.logic.algorithms.dpll import find_unit_clause_int_repr - >>> find_unit_clause_int_repr([set([1, 2, 3]), set([2, -3]), set([1, -2])], {1: True}) + >>> find_unit_clause_int_repr([set([1, 2, 3]), + ... set([2, -3]), set([1, -2])], {1: True}) (2, False) """ diff -Nru python3-sympy-0.7.2/sympy/logic/algorithms/dpll2.py python3-sympy-0.7.3/sympy/logic/algorithms/dpll2.py --- python3-sympy-0.7.2/sympy/logic/algorithms/dpll2.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/logic/algorithms/dpll2.py 2013-07-13 17:53:32.000000000 +0000 @@ -15,6 +15,7 @@ from sympy import Predicate from sympy.logic.boolalg import conjuncts, to_cnf, to_int_repr + def dpll_satisfiable(expr): """ Check satisfiability of a propositional sentence. @@ -25,7 +26,7 @@ >>> from sympy import symbols >>> from sympy.abc import A, B - >>> from sympy.logic.algorithms.dpll import dpll_satisfiable + >>> from sympy.logic.algorithms.dpll2 import dpll_satisfiable >>> dpll_satisfiable(A & ~B) {A: True, B: False} >>> dpll_satisfiable(A & ~A) @@ -57,8 +58,8 @@ normal form. """ - def __init__(self, clauses, variables, var_settings, heuristic = 'vsids', \ - clause_learning = 'none', INTERVAL = 500): + def __init__(self, clauses, variables, var_settings, heuristic='vsids', + clause_learning='none', INTERVAL=500): self.var_settings = var_settings self.heuristic = heuristic self.is_unsatisfied = False @@ -132,7 +133,6 @@ for lit in self.clauses[i]: self.occurrence_count[lit] += 1 - def _find_model(self): """Main DPLL loop. @@ -209,10 +209,9 @@ # Try the opposite setting of the most recent decision flip_lit = -self._current_level.decision self._undo() - self.levels.append(Level(flip_lit, flipped = True)) + self.levels.append(Level(flip_lit, flipped=True)) flip_var = True - ######################## # Helper Methods # ######################## @@ -360,7 +359,6 @@ # Pop the level off the stack self.levels.pop() - ######################### # Propagation # ######################### @@ -422,6 +420,7 @@ """Initialize the data structures needed for the VSIDS heuristic.""" self.lit_heap = [] self.lit_scores = {} + def _nfloat(a): """Return negative, float value of a. @@ -544,11 +543,9 @@ for lit in cls: self.lit_scores[lit] += 1 - ######################## # Clause Learning # ######################## - def _simple_add_learned_clause(self, cls): """Add a new clause to the theory. @@ -605,13 +602,14 @@ """Clean up learned clauses.""" pass + class Level(object): """ Represents a single level in the DPLL algorithm, and contains enough information for a sound backtracking procedure. """ - def __init__(self, decision, flipped = False): + def __init__(self, decision, flipped=False): self.decision = decision self.var_settings = set() self.flipped = flipped diff -Nru python3-sympy-0.7.2/sympy/logic/boolalg.py python3-sympy-0.7.3/sympy/logic/boolalg.py --- python3-sympy-0.7.2/sympy/logic/boolalg.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/logic/boolalg.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,7 +1,13 @@ """Boolean algebra module for SymPy""" +from collections import defaultdict + from sympy.core.basic import Basic +from sympy.core.numbers import Number +from sympy.core.decorators import deprecated from sympy.core.operations import LatticeOp from sympy.core.function import Application, sympify +from sympy.core.compatibility import ordered, product + class Boolean(Basic): """A boolean object is an object for which logic operations make sense.""" @@ -41,79 +47,108 @@ def __call__(self, *args): return self.func(*[arg(*args) for arg in self.args]) + def _eval_simplify(self, ratio, measure): + return simplify_logic(self) + + class And(LatticeOp, BooleanFunction): """ Logical AND function. - It evaluates its arguments in order, giving False immediately if any of them - are False, and True if they are all True. + It evaluates its arguments in order, giving False immediately + if any of them are False, and True if they are all True. Examples ======== - >>> from sympy.core import symbols - >>> from sympy.abc import x, y - >>> x & y - And(x, y) + >>> from sympy.core import symbols + >>> from sympy.abc import x, y + >>> from sympy.logic.boolalg import And + >>> x & y + And(x, y) + + Notes + ===== + + The operator operator ``&`` will perform bitwise operations + on integers and for convenience will construct an Add when + the arguments are symbolic, but the And function does not + perform bitwise operations and when any argument is True it + is simply removed from the arguments: + + >>> And(x, y).subs(x, 1) + y """ zero = False identity = True + @classmethod + def _new_args_filter(cls, args): + newargs = [] + for x in args: + if isinstance(x, Number) or x in (0, 1): + newargs.append(True if x else False) + else: + newargs.append(x) + return LatticeOp._new_args_filter(newargs, And) + + class Or(LatticeOp, BooleanFunction): """ Logical OR function - It evaluates its arguments in order, giving True immediately if any of them are - True, and False if they are all False. + It evaluates its arguments in order, giving True immediately + if any of them are True, and False if they are all False. + + Examples + ======== + + >>> from sympy.core import symbols + >>> from sympy.abc import x, y + >>> from sympy.logic.boolalg import Or + >>> x | y + Or(x, y) + + Notes + ===== + + The operator operator ``|`` will perform bitwise operations + on integers and for convenience will construct an Or when + the arguments are symbolic, but the Or function does not + perform bitwise operations and when any argument is False it + is simply removed from the arguments: + + >>> Or(x, y).subs(x, 0) + y """ zero = True identity = False -class Xor(BooleanFunction): - """ - Logical XOR (exclusive OR) function. - """ @classmethod - def eval(cls, *args): - """ - Logical XOR (exclusive OR) function. - - Returns True if an odd number of the arguments are True, and the rest are False. - Returns False if an even number of the arguments are True, and the rest are False. - - Examples - ======== - - >>> from sympy.logic.boolalg import Xor - >>> Xor(True, False) - True - >>> Xor(True, True) - False + def _new_args_filter(cls, args): + newargs = [] + for x in args: + if isinstance(x, Number) or x in (0, 1): + newargs.append(True if x else False) + else: + newargs.append(x) + return LatticeOp._new_args_filter(newargs, Or) - >>> Xor(True, False, True, True, False) - True - >>> Xor(True, False, True, False) - False - """ - if not args: return False - args = list(args) - A = args.pop() - while args: - B = args.pop() - A = Or(And(A, Not(B)), And(Not(A), B)) - return A class Not(BooleanFunction): """ Logical Not function (negation) - Note: De Morgan rules applied automatically + Notes + ===== + + De Morgan rules are applied automatically. """ is_Not = True @classmethod - def eval(cls, *args): + def eval(cls, arg): """ Logical Not function (negation) @@ -133,22 +168,11 @@ True >>> Not(Or(True, False)) False - - If multiple statements are given, returns an array of each result - - >>> Not(True, False) - [False, True] - >>> Not(True and False, True or False, True) - [True, False, False] - >>> Not(And(And(True, x), Or(x, False))) Not(x) """ - if len(args) > 1: - return list(map(cls, args)) - arg = args[0] - if type(arg) is bool: - return not arg + if isinstance(arg, Number) or arg in (0, 1): + return False if arg else True # apply De Morgan Rules if arg.func is And: return Or(*[Not(a) for a in arg.args]) @@ -157,6 +181,45 @@ if arg.func is Not: return arg.args[0] + +class Xor(BooleanFunction): + """ + Logical XOR (exclusive OR) function. + """ + @classmethod + def eval(cls, *args): + """ + Logical XOR (exclusive OR) function. + + Returns True if an odd number of the arguments are True + and the rest are False. + Returns False if an even number of the arguments are True + and the rest are False. + + Examples + ======== + + >>> from sympy.logic.boolalg import Xor + >>> Xor(True, False) + True + >>> Xor(True, True) + False + + >>> Xor(True, False, True, True, False) + True + >>> Xor(True, False, True, False) + False + """ + if not args: + return False + args = list(args) + A = args.pop() + while args: + B = args.pop() + A = Or(And(A, Not(B)), And(Not(A), B)) + return A + + class Nand(BooleanFunction): """ Logical NAND function. @@ -183,6 +246,7 @@ """ return Not(And(*args)) + class Nor(BooleanFunction): """ Logical NOR function. @@ -213,6 +277,7 @@ """ return Not(Or(*args)) + class Implies(BooleanFunction): """ Logical implication. @@ -242,19 +307,28 @@ True """ try: - A, B = args + newargs = [] + for x in args: + if isinstance(x, Number) or x in (0, 1): + newargs.append(True if x else False) + else: + newargs.append(x) + A, B = newargs except ValueError: - raise ValueError("%d operand(s) used for an Implies (pairs are required): %s" % (len(args), str(args))) + raise ValueError( + "%d operand(s) used for an Implies " + "(pairs are required): %s" % (len(args), str(args))) if A is True or A is False or B is True or B is False: return Or(Not(A), B) else: return Basic.__new__(cls, *args) + class Equivalent(BooleanFunction): """ Equivalence relation. - Equivalent(A, B) is True if and only if A and B are both True or both False + Equivalent(A, B) is True iff A and B are both True or both False """ @classmethod def eval(cls, *args): @@ -278,7 +352,13 @@ """ - argset = set(args) + newargs = [] + for x in args: + if isinstance(x, Number) or x in (0, 1): + newargs.append(True if x else False) + else: + newargs.append(x) + argset = set(newargs) if len(argset) <= 1: return True if True in argset: @@ -289,6 +369,7 @@ return Nor(*argset) return Basic.__new__(cls, *set(args)) + class ITE(BooleanFunction): """ If then else clause. @@ -305,11 +386,11 @@ ======== >>> from sympy.logic.boolalg import ITE, And, Xor, Or - >>> from sympy.abc import x,y,z + >>> from sympy.abc import x, y, z >>> x = True >>> y = False >>> z = True - >>> ITE(x,y,z) + >>> ITE(x, y, z) False >>> ITE(Or(x, y), And(x, z), Xor(z, x)) True @@ -317,35 +398,17 @@ args = list(args) if len(args) == 3: return Or(And(args[0], args[1]), And(Not(args[0]), args[2])) - raise ValueError("ITE expects 3 arguments, but got %d: %s" % (len(args), str(args))) + raise ValueError("ITE expects 3 arguments, but got %d: %s" % + (len(args), str(args))) ### end class definitions. Some useful methods -def fuzzy_not(arg): - """ - Not in fuzzy logic - - Will return Not if arg is a boolean value, and None if argument - is None. - - Examples: - - >>> from sympy.logic.boolalg import fuzzy_not - >>> fuzzy_not(True) - False - >>> fuzzy_not(None) - >>> fuzzy_not(False) - True - - """ - if arg is None: - return - return not arg def conjuncts(expr): """Return a list of the conjuncts in the expr s. - Examples: + Examples + ======== >>> from sympy.logic.boolalg import conjuncts >>> from sympy.abc import A, B @@ -357,10 +420,12 @@ """ return And.make_args(expr) + def disjuncts(expr): """Return a list of the disjuncts in the sentence s. - Examples: + Examples + ======== >>> from sympy.logic.boolalg import disjuncts >>> from sympy.abc import A, B @@ -372,6 +437,7 @@ """ return Or.make_args(expr) + def distribute_and_over_or(expr): """ Given a sentence s consisting of conjunctions and disjunctions @@ -385,22 +451,49 @@ >>> distribute_and_over_or(Or(A, And(Not(B), Not(C)))) And(Or(A, Not(B)), Or(A, Not(C))) """ - if expr.func is Or: - for arg in expr.args: - if arg.func is And: + return _distribute((expr, And, Or)) + + +def distribute_or_over_and(expr): + """ + Given a sentence s consisting of conjunctions and disjunctions + of literals, return an equivalent sentence in DNF. + + Note that the output is NOT simplified. + + Examples + ======== + + >>> from sympy.logic.boolalg import distribute_or_over_and, And, Or, Not + >>> from sympy.abc import A, B, C + >>> distribute_or_over_and(And(Or(Not(A), B), C)) + Or(And(B, C), And(C, Not(A))) + """ + return _distribute((expr, Or, And)) + + +def _distribute(info): + """ + Distributes info[1] over info[2] with respect to info[0]. + """ + if info[0].func is info[2]: + for arg in info[0].args: + if arg.func is info[1]: conj = arg break else: - return expr - rest = Or(*[a for a in expr.args if a is not conj]) - return And(*list(map(distribute_and_over_or, - [Or(c, rest) for c in conj.args]))) - elif expr.func is And: - return And(*list(map(distribute_and_over_or, expr.args))) + return info[0] + rest = info[2](*[a for a in info[0].args if a is not conj]) + return info[1](*list(map(_distribute, + [(info[2](c, rest), info[1], info[2]) for c in conj.args]))) + elif info[0].func is info[1]: + return info[1](*list(map(_distribute, + [(x, info[1], info[2]) for x in info[0].args]))) else: - return expr + return info[0] -def to_cnf(expr): + +def to_cnf(expr, simplify=False): """ Convert a propositional logical sentence s to conjunctive normal form. That is, of the form ((A | ~B | ...) & (B | C | ...) & ...) @@ -414,14 +507,58 @@ And(Or(D, Not(A)), Or(D, Not(B))) """ + expr = sympify(expr) + if not isinstance(expr, BooleanFunction): + return expr + + if simplify: + simplified_expr = distribute_and_over_or(simplify_logic(expr)) + if len(simplified_expr.args) < len(to_cnf(expr).args): + return simplified_expr + else: + return to_cnf(expr) + # Don't convert unless we have to if is_cnf(expr): return expr - expr = sympify(expr) expr = eliminate_implications(expr) return distribute_and_over_or(expr) + +def to_dnf(expr, simplify=False): + """ + Convert a propositional logical sentence s to disjunctive normal form. + That is, of the form ((A & ~B & ...) | (B & C & ...) | ...) + + Examples + ======== + + >>> from sympy.logic.boolalg import to_dnf + >>> from sympy.abc import A, B, C, D + >>> to_dnf(B & (A | C)) + Or(And(A, B), And(B, C)) + + """ + expr = sympify(expr) + if not isinstance(expr, BooleanFunction): + return expr + + if simplify: + simplified_expr = distribute_or_over_and(simplify_logic(expr)) + if len(simplified_expr.args) < len(to_dnf(expr).args): + return simplified_expr + else: + return to_dnf(expr) + + # Don't convert unless we have to + if is_dnf(expr): + return expr + + expr = eliminate_implications(expr) + return distribute_or_over_and(expr) + + def is_cnf(expr): """ Test whether or not an expression is in conjunctive normal form. @@ -439,10 +576,44 @@ False """ + return _is_form(expr, And, Or) + + +def is_dnf(expr): + """ + Test whether or not an expression is in disjunctive normal form. + + Examples + ======== + + >>> from sympy.logic.boolalg import is_dnf + >>> from sympy.abc import A, B, C + >>> is_dnf(A | B | C) + True + >>> is_dnf(A & B & C) + True + >>> is_dnf((A & B) | C) + True + >>> is_dnf(A & (B | C)) + False + + """ + return _is_form(expr, Or, And) + + +def _is_form(expr, function1, function2): + """ + Test whether or not an expression is of the required form. + + """ expr = sympify(expr) - # Special case of a single disjunction - if expr.func is Or: + # Special case of an Atom + if expr.is_Atom: + return True + + # Special case of a single expression of function2 + if expr.func is function2: for lit in expr.args: if lit.func is Not: if not lit.args[0].is_Atom: @@ -457,7 +628,7 @@ if not expr.args[0].is_Atom: return False - if expr.func is not And: + if expr.func is not function1: return False for cls in expr.args: @@ -466,7 +637,7 @@ if cls.func is Not: if not cls.args[0].is_Atom: return False - elif cls.func is not Or: + elif cls.func is not function2: return False for lit in cls.args: if lit.func is Not: @@ -478,6 +649,7 @@ return True + def eliminate_implications(expr): """ Change >>, <<, and Equivalent into &, |, and ~. That is, return an @@ -487,7 +659,8 @@ Examples ======== - >>> from sympy.logic.boolalg import Implies, Equivalent, eliminate_implications + >>> from sympy.logic.boolalg import Implies, Equivalent, \ + eliminate_implications >>> from sympy.abc import A, B, C >>> eliminate_implications(Implies(A, B)) Or(B, Not(A)) @@ -496,7 +669,7 @@ """ expr = sympify(expr) if expr.is_Atom: - return expr ## (Atoms are unchanged.) + return expr # (Atoms are unchanged.) args = list(map(eliminate_implications, expr.args)) if expr.func is Implies: a, b = args[0], args[-1] @@ -507,26 +680,19 @@ else: return expr.func(*args) + +@deprecated( + useinstead="sympify", issue=3451, deprecated_since_version="0.7.3") def compile_rule(s): """ - Transforms a rule into a sympy expression + Transforms a rule into a SymPy expression A rule is a string of the form "symbol1 & symbol2 | ..." - See sympy.assumptions.known_facts for examples of rules - - TODO: can this be replaced by sympify ? - Examples - ======== + Note: This function is deprecated. Use sympify() instead. - >>> from sympy.logic.boolalg import compile_rule - >>> compile_rule('A & B') - And(A, B) - >>> compile_rule('(~B & ~C)|A') - Or(A, And(Not(B), Not(C))) """ import re - from sympy.core import Symbol - return eval(re.sub(r'([a-zA-Z0-9_.]+)', r'Symbol("\1")', s), {'Symbol' : Symbol}) + return sympify(re.sub(r'([a-zA-Z_][a-zA-Z0-9_]*)', r'Symbol("\1")', s)) def to_int_repr(clauses, symbols): @@ -536,10 +702,10 @@ Examples ======== - >>> from sympy.logic.boolalg import to_int_repr - >>> from sympy.abc import x, y - >>> to_int_repr([x | y, y], [x, y]) == [set([1, 2]), set([2])] - True + >>> from sympy.logic.boolalg import to_int_repr + >>> from sympy.abc import x, y + >>> to_int_repr([x | y, y], [x, y]) == [set([1, 2]), set([2])] + True """ @@ -552,5 +718,389 @@ else: return symbols[arg] - return [set(append_symbol(arg, symbols) for arg in Or.make_args(c)) \ - for c in clauses] + return [set(append_symbol(arg, symbols) for arg in Or.make_args(c)) + for c in clauses] + + +def _check_pair(minterm1, minterm2): + """ + Checks if a pair of minterms differs by only one bit. If yes, returns + index, else returns -1. + """ + index = -1 + for x, (i, j) in enumerate(list(zip(minterm1, minterm2))): + if i != j: + if index == -1: + index = x + else: + return -1 + return index + + +def _convert_to_varsSOP(minterm, variables): + """ + Converts a term in the expansion of a function from binary to it's + variable form (for SOP). + """ + temp = [] + for i, m in enumerate(minterm): + if m == 0: + temp.append(Not(variables[i])) + elif m == 1: + temp.append(variables[i]) + else: + pass # ignore the 3s + return And(*temp) + + +def _convert_to_varsPOS(maxterm, variables): + """ + Converts a term in the expansion of a function from binary to it's + variable form (for POS). + """ + temp = [] + for i, m in enumerate(maxterm): + if m == 1: + temp.append(Not(variables[i])) + elif m == 0: + temp.append(variables[i]) + else: + pass # ignore the 3s + return Or(*temp) + + +def _simplified_pairs(terms): + """ + Reduces a set of minterms, if possible, to a simplified set of minterms + with one less variable in the terms using QM method. + """ + simplified_terms = [] + todo = list(range(len(terms))) + for i, ti in enumerate(terms[:-1]): + for j_i, tj in enumerate(terms[(i + 1):]): + index = _check_pair(ti, tj) + if index != -1: + todo[i] = todo[j_i + i + 1] = None + newterm = ti[:] + newterm[index] = 3 + if newterm not in simplified_terms: + simplified_terms.append(newterm) + simplified_terms.extend( + [terms[i] for i in [_ for _ in todo if _ is not None]]) + return simplified_terms + + +def _compare_term(minterm, term): + """ + Return True if a binary term is satisfied by the given term. Used + for recognizing prime implicants. + """ + for i, x in enumerate(term): + if x != 3 and x != minterm[i]: + return False + return True + + +def _rem_redundancy(l1, terms): + """ + After the truth table has been sufficiently simplified, use the prime + implicant table method to recognize and eliminate redundant pairs, + and return the essential arguments. + """ + essential = [] + for x in terms: + temporary = [] + for y in l1: + if _compare_term(x, y): + temporary.append(y) + if len(temporary) == 1: + if temporary[0] not in essential: + essential.append(temporary[0]) + for x in terms: + for y in essential: + if _compare_term(x, y): + break + else: + for z in l1: + if _compare_term(x, z): + if z not in essential: + essential.append(z) + break + + return essential + + +def SOPform(variables, minterms, dontcares=None): + """ + The SOPform function uses simplified_pairs and a redundant group- + eliminating algorithm to convert the list of all input combos that + generate '1' (the minterms) into the smallest Sum of Products form. + + The variables must be given as the first argument. + + Return a logical Or function (i.e., the "sum of products" or "SOP" + form) that gives the desired outcome. If there are inputs that can + be ignored, pass them as a list, too. + + The result will be one of the (perhaps many) functions that satisfy + the conditions. + + Examples + ======== + + >>> from sympy.logic import SOPform + >>> minterms = [[0, 0, 0, 1], [0, 0, 1, 1], + ... [0, 1, 1, 1], [1, 0, 1, 1], [1, 1, 1, 1]] + >>> dontcares = [[0, 0, 0, 0], [0, 0, 1, 0], [0, 1, 0, 1]] + >>> SOPform(['w','x','y','z'], minterms, dontcares) + Or(And(Not(w), z), And(y, z)) + + References + ========== + + .. [1] en.wikipedia.org/wiki/Quine-McCluskey_algorithm + + """ + from sympy.core.symbol import Symbol + + variables = [Symbol(v) if not isinstance(v, Symbol) else v + for v in variables] + if minterms == []: + return False + + minterms = [list(i) for i in minterms] + dontcares = [list(i) for i in (dontcares or [])] + for d in dontcares: + if d in minterms: + raise ValueError('%s in minterms is also in dontcares' % d) + + old = None + new = minterms + dontcares + while new != old: + old = new + new = _simplified_pairs(old) + essential = _rem_redundancy(new, minterms) + return Or(*[_convert_to_varsSOP(x, variables) for x in essential]) + + +def POSform(variables, minterms, dontcares=None): + """ + The POSform function uses simplified_pairs and a redundant-group + eliminating algorithm to convert the list of all input combinations + that generate '1' (the minterms) into the smallest Product of Sums form. + + The variables must be given as the first argument. + + Return a logical And function (i.e., the "product of sums" or "POS" + form) that gives the desired outcome. If there are inputs that can + be ignored, pass them as a list, too. + + The result will be one of the (perhaps many) functions that satisfy + the conditions. + + Examples + ======== + + >>> from sympy.logic import POSform + >>> minterms = [[0, 0, 0, 1], [0, 0, 1, 1], [0, 1, 1, 1], + ... [1, 0, 1, 1], [1, 1, 1, 1]] + >>> dontcares = [[0, 0, 0, 0], [0, 0, 1, 0], [0, 1, 0, 1]] + >>> POSform(['w','x','y','z'], minterms, dontcares) + And(Or(Not(w), y), z) + + References + ========== + + .. [1] en.wikipedia.org/wiki/Quine-McCluskey_algorithm + + """ + from sympy.core.symbol import Symbol + + variables = [Symbol(v) if not isinstance(v, Symbol) else v + for v in variables] + if minterms == []: + return False + + minterms = [list(i) for i in minterms] + dontcares = [list(i) for i in (dontcares or [])] + for d in dontcares: + if d in minterms: + raise ValueError('%s in minterms is also in dontcares' % d) + + maxterms = [] + for t in product([0, 1], repeat=len(variables)): + t = list(t) + if (t not in minterms) and (t not in dontcares): + maxterms.append(t) + old = None + new = maxterms + dontcares + while new != old: + old = new + new = _simplified_pairs(old) + essential = _rem_redundancy(new, maxterms) + return And(*[_convert_to_varsPOS(x, variables) for x in essential]) + + +def simplify_logic(expr): + """ + This function simplifies a boolean function to its + simplified version in SOP or POS form. The return type is an + Or or And object in SymPy. The input can be a string or a boolean + expression. + + Examples + ======== + + >>> from sympy.logic import simplify_logic + >>> from sympy.abc import x, y, z + >>> from sympy import S + + >>> b = '(~x & ~y & ~z) | ( ~x & ~y & z)' + >>> simplify_logic(b) + And(Not(x), Not(y)) + + >>> S(b) + Or(And(Not(x), Not(y), Not(z)), And(Not(x), Not(y), z)) + >>> simplify_logic(_) + And(Not(x), Not(y)) + + """ + expr = sympify(expr) + if not isinstance(expr, BooleanFunction): + return expr + variables = list(expr.free_symbols) + truthtable = [] + for t in product([0, 1], repeat=len(variables)): + t = list(t) + if expr.subs(list(zip(variables, t))) == True: + truthtable.append(t) + if (len(truthtable) >= (2 ** (len(variables) - 1))): + return SOPform(variables, truthtable) + else: + return POSform(variables, truthtable) + + +def _finger(eq): + """ + Assign a 5-item fingerprint to each symbol in the equation: + [ + # of times it appeared as a Symbol, + # of times it appeared as a Not(symbol), + # of times it appeared as a Symbol in an And or Or, + # of times it appeared as a Not(Symbol) in an And or Or, + sum of the number of arguments with which it appeared, + counting Symbol as 1 and Not(Symbol) as 2 + ] + + >>> from sympy.logic.boolalg import _finger as finger + >>> from sympy import And, Or, Not + >>> from sympy.abc import a, b, x, y + >>> eq = Or(And(Not(y), a), And(Not(y), b), And(x, y)) + >>> dict(finger(eq)) + {(0, 0, 1, 0, 2): [x], (0, 0, 1, 0, 3): [a, b], (0, 0, 1, 2, 8): [y]} + + So y and x have unique fingerprints, but a and b do not. + """ + f = eq.free_symbols + d = dict(list(zip(f, [[0] * 5 for fi in f]))) + for a in eq.args: + if a.is_Symbol: + d[a][0] += 1 + elif a.is_Not: + d[a.args[0]][1] += 1 + else: + o = len(a.args) + sum(ai.func is Not for ai in a.args) + for ai in a.args: + if ai.is_Symbol: + d[ai][2] += 1 + d[ai][-1] += o + else: + d[ai.args[0]][3] += 1 + d[ai.args[0]][-1] += o + inv = defaultdict(list) + for k, v in ordered(iter(d.items())): + inv[tuple(v)].append(k) + return inv + + +def bool_equal(bool1, bool2, info=False): + """Return True if the two expressions represent the same logical + behavior for some correspondence between the variables of each + (which may be different). For example, And(x, y) is logically + equivalent to And(a, b) for {x: a, y: b} (or vice versa). If the + mapping is desired, then set ``info`` to True and the simplified + form of the functions and the mapping of variables will be + returned. + + Examples + ======== + + >>> from sympy import SOPform, bool_equal, Or, And, Not, Xor + >>> from sympy.abc import w, x, y, z, a, b, c, d + >>> function1 = SOPform(['x','z','y'],[[1, 0, 1], [0, 0, 1]]) + >>> function2 = SOPform(['a','b','c'],[[1, 0, 1], [1, 0, 0]]) + >>> bool_equal(function1, function2, info=True) + (And(Not(z), y), {y: a, z: b}) + + The results are not necessarily unique, but they are canonical. Here, + ``(w, z)`` could be ``(a, d)`` or ``(d, a)``: + + >>> eq = Or(And(Not(y), w), And(Not(y), z), And(x, y)) + >>> eq2 = Or(And(Not(c), a), And(Not(c), d), And(b, c)) + >>> bool_equal(eq, eq2) + True + >>> bool_equal(eq, eq2, info=True) + (Or(And(Not(y), w), And(Not(y), z), And(x, y)), {w: a, x: b, y: c, z: d}) + >>> eq = And(Xor(a, b), c, And(c,d)) + >>> bool_equal(eq, eq.subs(c, x), info=True) + (And(Or(Not(a), Not(b)), Or(a, b), c, d), {a: a, b: b, c: d, d: x}) + + """ + + def match(function1, function2): + """Return the mapping that equates variables between two + simplified boolean expressions if possible. + + By "simplified" we mean that a function has been denested + and is either an And (or an Or) whose arguments are either + symbols (x), negated symbols (Not(x)), or Or (or an And) whose + arguments are only symbols or negated symbols. For example, + And(x, Not(y), Or(w, Not(z))). + + Basic.match is not robust enough (see issue 1736) so this is + a workaround that is valid for simplified boolean expressions + """ + + # do some quick checks + if function1.__class__ != function2.__class__: + return None + if len(function1.args) != len(function2.args): + return None + if function1.is_Symbol: + return {function1: function2} + + # get the fingerprint dictionaries + f1 = _finger(function1) + f2 = _finger(function2) + + # more quick checks + if len(f1) != len(f2): + return False + + # assemble the match dictionary if possible + matchdict = {} + for k in list(f1.keys()): + if k not in f2: + return False + if len(f1[k]) != len(f2[k]): + return False + for i, x in enumerate(f1[k]): + matchdict[x] = f2[k][i] + return matchdict + + a = simplify_logic(bool1) + b = simplify_logic(bool2) + m = match(a, b) + if m and info: + return a, m + return m is not None diff -Nru python3-sympy-0.7.2/sympy/logic/inference.py python3-sympy-0.7.3/sympy/logic/inference.py --- python3-sympy-0.7.2/sympy/logic/inference.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/logic/inference.py 2013-07-13 17:53:32.000000000 +0000 @@ -4,11 +4,39 @@ from sympy.core.basic import C from sympy.core.sympify import sympify + +def is_literal(expr): + """ + Returns True if expr is a literal, else False. + + Examples + ======== + + >>> from sympy import Symbol, Or + >>> from sympy.abc import A, B + >>> from sympy.logic.inference import is_literal + >>> is_literal(A) + True + >>> is_literal(~A) + True + >>> is_literal(Or(A, B)) + False + + """ + + try: + literal_symbol(expr) + return True + except (ValueError): + return False + + def literal_symbol(literal): """ The symbol in this literal (without the negation). - Examples: + Examples + ======== >>> from sympy import Symbol >>> from sympy.abc import A @@ -20,10 +48,18 @@ """ - if literal.func is Not: - return literal.args[0] - else: + if literal is True or literal is False: return literal + try: + if literal.is_Symbol: + return literal + if literal.is_Not: + return literal_symbol(literal.args[0]) + else: + raise ValueError + except (AttributeError, ValueError): + raise ValueError("Argument must be a boolean literal.") + def satisfiable(expr, algorithm="dpll2"): """ @@ -49,6 +85,7 @@ return dpll_satisfiable(expr) raise NotImplementedError + def pl_true(expr, model={}): """ Return True if the propositional logic expression is true in the model, @@ -81,21 +118,27 @@ if func is Not: p = pl_true(args[0], model) - if p is None: return None - else: return not p + if p is None: + return None + else: + return not p elif func is Or: result = False for arg in args: p = pl_true(arg, model) - if p == True: return True - if p == None: result = None + if p is True: + return True + if p is None: + result = None return result elif func is And: result = True for arg in args: p = pl_true(arg, model) - if p == False: return False - if p == None: result = None + if p is False: + return False + if p is None: + result = None return result elif func is Implies: @@ -105,10 +148,10 @@ elif func is Equivalent: p, q = args pt = pl_true(p, model) - if pt == None: + if pt is None: return None qt = pl_true(q, model) - if qt == None: + if qt is None: return None return pt == qt else: @@ -156,7 +199,8 @@ [Or(x, y), y] """ for c in conjuncts(to_cnf(sentence)): - if not c in self.clauses: self.clauses.append(c) + if not c in self.clauses: + self.clauses.append(c) def ask(self, query): """Checks if the query is true given the set of clauses. @@ -173,7 +217,8 @@ >>> l.ask(y) False """ - if len(self.clauses) == 0: return False + if len(self.clauses) == 0: + return False from sympy.logic.algorithms.dpll import dpll query_conjuncts = self.clauses[:] query_conjuncts.extend(conjuncts(to_cnf(query))) diff -Nru python3-sympy-0.7.2/sympy/logic/tests/test_boolalg.py python3-sympy-0.7.3/sympy/logic/tests/test_boolalg.py --- python3-sympy-0.7.2/sympy/logic/tests/test_boolalg.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/logic/tests/test_boolalg.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,11 +1,18 @@ -from sympy.logic.boolalg import to_cnf, eliminate_implications, distribute_and_over_or, \ - compile_rule, conjuncts, disjuncts, to_int_repr, fuzzy_not, Boolean, is_cnf -from sympy import symbols, And, Or, Xor, Not, Nand, Nor, Implies, Equivalent, ITE +from sympy import symbols, sympify, Dummy, simplify +from sympy.logic.boolalg import ( + And, Boolean, Equivalent, ITE, Implies, Nand, Nor, Not, Or, POSform, + SOPform, Xor, conjuncts, disjuncts, distribute_or_over_and, + distribute_and_over_or, eliminate_implications, is_cnf, is_dnf, + simplify_logic, to_cnf, to_dnf, to_int_repr, bool_equal +) from sympy.utilities.pytest import raises + +A, B, C = symbols('A,B,C') + + def test_overloading(): """Test that |, & are overloaded as expected""" - A, B, C = list(map(Boolean, symbols('A,B,C'))) assert A & B == And(A, B) assert A | B == Or(A, B) @@ -15,147 +22,228 @@ assert ~A == Not(A) assert A ^ B == Xor(A, B) + def test_And(): - A, B, C = list(map(Boolean, symbols('A,B,C'))) - assert And() == True + assert And() is True assert And(A) == A - assert And(True) == True - assert And(False) == False - assert And(True, True ) == True - assert And(True, False) == False - assert And(False, False) == False - assert And(True, A) == A - assert And(False, A) == False - assert And(True, True, True) == True - assert And(True, True , A) == A - assert And(True, False, A) == False + assert And(True) is True + assert And(False) is False + assert And(True, True ) is True + assert And(True, False) is False + assert And(False, False) is False + assert And(True, A) == A + assert And(False, A) is False + assert And(True, True, True) is True + assert And(True, True, A) == A + assert And(True, False, A) is False + assert And(2, A) == A + assert And(2, 3) is True + def test_Or(): - A, B, C = list(map(Boolean, symbols('A,B,C'))) - assert Or() == False + assert Or() is False assert Or(A) == A - assert Or(True) == True - assert Or(False) == False - assert Or(True, True ) == True - assert Or(True, False) == True - assert Or(False, False) == False - assert Or(True, A) == True + assert Or(True) is True + assert Or(False) is False + assert Or(True, True ) is True + assert Or(True, False) is True + assert Or(False, False) is False + assert Or(True, A) is True assert Or(False, A) == A - assert Or(True, False, False) == True - assert Or(True, False, A) == True + assert Or(True, False, False) is True + assert Or(True, False, A) is True assert Or(False, False, A) == A + assert Or(2, A) is True + def test_Xor(): - A, B, C = list(map(Boolean, symbols('A,B,C'))) - assert Xor() == False + assert Xor() is False assert Xor(A) == A - assert Xor(True) == True - assert Xor(False) == False - assert Xor(True, True ) == False - assert Xor(True, False) == True - assert Xor(False, False) == False + assert Xor(True) is True + assert Xor(False) is False + assert Xor(True, True ) is False + assert Xor(True, False) is True + assert Xor(False, False) is False assert Xor(True, A) == ~A assert Xor(False, A) == A - assert Xor(True, False, False) == True + assert Xor(True, False, False) is True assert Xor(True, False, A) == ~A assert Xor(False, False, A) == A + def test_Not(): - assert Not(True) == False - assert Not(False) == True - assert Not(True, True ) == [False, False] - assert Not(True, False) == [False, True ] - assert Not(False,False) == [True, True ] + + raises(TypeError, lambda: Not(True, False)) + assert Not(True) is False + assert Not(False) is True + assert Not(0) is True + assert Not(1) is False + assert Not(2) is False + def test_Nand(): - A, B, C = list(map(Boolean, symbols('A,B,C'))) - assert Nand() == False + assert Nand() is False assert Nand(A) == ~A - assert Nand(True) == False - assert Nand(False) == True - assert Nand(True, True ) == False - assert Nand(True, False) == True - assert Nand(False, False) == True - assert Nand(True, A) == ~A - assert Nand(False, A) == True - assert Nand(True, True, True) == False - assert Nand(True, True , A) == ~A - assert Nand(True, False, A) == True + assert Nand(True) is False + assert Nand(False) is True + assert Nand(True, True ) is False + assert Nand(True, False) is True + assert Nand(False, False) is True + assert Nand(True, A) == ~A + assert Nand(False, A) is True + assert Nand(True, True, True) is False + assert Nand(True, True, A) == ~A + assert Nand(True, False, A) is True + def test_Nor(): - A, B, C = list(map(Boolean, symbols('A,B,C'))) - assert Nor() == True + assert Nor() is True assert Nor(A) == ~A - assert Nor(True) == False - assert Nor(False) == True - assert Nor(True, True ) == False - assert Nor(True, False) == False - assert Nor(False, False) == True - assert Nor(True, A) == False + assert Nor(True) is False + assert Nor(False) is True + assert Nor(True, True ) is False + assert Nor(True, False) is False + assert Nor(False, False) is True + assert Nor(True, A) is False assert Nor(False, A) == ~A - assert Nor(True, True, True) == False - assert Nor(True, True , A) == False - assert Nor(True, False, A) == False + assert Nor(True, True, True) is False + assert Nor(True, True, A) is False + assert Nor(True, False, A) is False + def test_Implies(): - A, B, C = list(map(Boolean, symbols('A,B,C'))) - raises(ValueError, lambda: Implies(A,B,C)) - assert Implies(True, True) == True - assert Implies(True, False) == False - assert Implies(False, True) == True - assert Implies(False, False) == True + raises(ValueError, lambda: Implies(A, B, C)) + assert Implies(True, True) is True + assert Implies(True, False) is False + assert Implies(False, True) is True + assert Implies(False, False) is True + assert Implies(0, A) is True + assert Implies(1, 1) is True + assert Implies(1, 0) is False assert A >> B == B << A + def test_Equivalent(): - A, B, C = list(map(Boolean, symbols('A,B,C'))) assert Equivalent(A, B) == Equivalent(B, A) == Equivalent(A, B, A) - assert Equivalent() == True - assert Equivalent(A, A) == Equivalent(A) == True - assert Equivalent(True, True) == Equivalent(False, False) == True - assert Equivalent(True, False) == Equivalent(False, True) == False + assert Equivalent() is True + assert Equivalent(A, A) == Equivalent(A) is True + assert Equivalent(True, True) == Equivalent(False, False) is True + assert Equivalent(True, False) == Equivalent(False, True) is False assert Equivalent(A, True) == A assert Equivalent(A, False) == Not(A) assert Equivalent(A, B, True) == A & B assert Equivalent(A, B, False) == ~A & ~B + assert Equivalent(1, A) == A + assert Equivalent(0, A) == Not(A) + + +def test_simplification(): + """ + Test working of simplification methods. + """ + set1 = [[0, 0, 1], [0, 1, 1], [1, 0, 0], [1, 1, 0]] + set2 = [[0, 0, 0], [0, 1, 0], [1, 0, 1], [1, 1, 1]] + from sympy.abc import w, x, y, z + assert SOPform('xyz', set1) == Or(And(Not(x), z), And(Not(z), x)) + assert Not(SOPform('xyz', set2)) == And(Or(Not(x), Not(z)), Or(x, z)) + assert POSform('xyz', set1 + set2) is True + assert SOPform('xyz', set1 + set2) is True + assert SOPform([Dummy(), Dummy(), Dummy()], set1 + set2) is True + + minterms = [[0, 0, 0, 1], [0, 0, 1, 1], [0, 1, 1, 1], [1, 0, 1, 1], + [1, 1, 1, 1]] + dontcares = [[0, 0, 0, 0], [0, 0, 1, 0], [0, 1, 0, 1]] + assert ( + SOPform('wxyz', minterms, dontcares) == + Or(And(Not(w), z), And(y, z))) + assert POSform('wxyz', minterms, dontcares) == And(Or(Not(w), y), z) + + # test simplification + ans = And(A, Or(B, C)) + assert simplify_logic('A & (B | C)') == ans + assert simplify_logic('(A & B) | (A & C)') == ans + assert simplify_logic(Implies(A, B)) == Or(Not(A), B) + assert simplify_logic(Equivalent(A, B)) == \ + Or(And(A, B), And(Not(A), Not(B))) + + # check input + ans = SOPform('xy', [[1, 0]]) + assert SOPform([x, y], [[1, 0]]) == ans + assert POSform(['x', 'y'], [[1, 0]]) == ans + + raises(ValueError, lambda: SOPform('x', [[1]], [[1]])) + assert SOPform('x', [[1]], [[0]]) is True + assert SOPform('x', [[0]], [[1]]) is True + assert SOPform('x', [], []) is False + + raises(ValueError, lambda: POSform('x', [[1]], [[1]])) + assert POSform('x', [[1]], [[0]]) is True + assert POSform('x', [[0]], [[1]]) is True + assert POSform('x', [], []) is False + + #check working of simplify + assert simplify('(A & B) | (A & C)') == sympify('And(A, Or(B, C))') + assert simplify(And(x, Not(x))) == False + assert simplify(Or(x, Not(x))) == True + + +def test_bool_equal(): + """ + Test working of bool_equal function. + """ + + minterms = [[0, 0, 0, 1], [0, 0, 1, 1], [0, 1, 1, 1], [1, 0, 1, 1], + [1, 1, 1, 1]] + from sympy.abc import a, b, c, x, y, z + assert bool_equal(Not(Not(a)), a) + assert bool_equal(SOPform(['w', 'x', 'y', 'z'], minterms), + POSform(['w', 'x', 'y', 'z'], minterms)) + assert bool_equal(SOPform(['x', 'z', 'y'],[[1, 0, 1]]), + SOPform(['a', 'b', 'c'],[[1, 0, 1]])) != False + function1 = SOPform(['x','z','y'],[[1, 0, 1], [0, 0, 1]]) + function2 = SOPform(['a','b','c'],[[1, 0, 1], [1, 0, 0]]) + assert bool_equal(function1, function2, info=True) == \ + (function1, {y: a, z: b}) + def test_bool_symbol(): """Test that mixing symbols with boolean values works as expected""" - A, B, C = list(map(Boolean, symbols('A,B,C'))) - assert And(A, True) == A + assert And(A, True) == A assert And(A, True, True) == A - assert And(A, False) == False - assert And(A, True, False) == False - assert Or(A, True) == True - assert Or(A, False) == A + assert And(A, False) is False + assert And(A, True, False) is False + assert Or(A, True) is True + assert Or(A, False) == A + def test_subs(): - A, B, C = list(map(Boolean, symbols('A,B,C'))) assert (A & B).subs(A, True) == B - assert (A & B).subs(A, False) == False + assert (A & B).subs(A, False) is False assert (A & B).subs(B, True) == A - assert (A & B).subs(B, False) == False - assert (A & B).subs({A: True, B:True}) == True - assert (A | B).subs(A, True) == True + assert (A & B).subs(B, False) is False + assert (A & B).subs({A: True, B: True}) is True + assert (A | B).subs(A, True) is True assert (A | B).subs(A, False) == B - assert (A | B).subs(B, True) == True + assert (A | B).subs(B, True) is True assert (A | B).subs(B, False) == A - assert (A | B).subs({A: True, B:True}) == True + assert (A | B).subs({A: True, B: True}) is True """ we test for axioms of boolean algebra see http://en.wikipedia.org/wiki/Boolean_algebra_(structure) """ + def test_commutative(): """Test for commutativity of And and Or""" A, B = list(map(Boolean, symbols('A,B'))) @@ -163,72 +251,88 @@ assert A & B == B & A assert A | B == B | A + def test_and_associativity(): """Test for associativity of And""" - A, B, C = list(map(Boolean, symbols('A,B,C'))) assert (A & B) & C == A & (B & C) + def test_or_assicativity(): - A, B, C = list(map(Boolean, symbols('A,B,C'))) assert ((A | B) | C) == (A | (B | C)) + def test_double_negation(): a = Boolean() assert ~(~a) == a + def test_De_Morgan(): - A, B, C = list(map(Boolean, symbols('A,B,C'))) assert ~(A & B) == (~A) | (~B) assert ~(A | B) == (~A) & (~B) - assert ~(A | B | C) == ~A & ~B & ~C + assert ~(A | B | C) == ~A & ~B & ~C # test methods + + def test_eliminate_implications(): - A, B, C = list(map(Boolean, symbols('A,B,C'))) assert eliminate_implications(Implies(A, B, evaluate=False)) == (~A) | B - assert eliminate_implications(A >> (C >>Not(B))) == Or(Or(Not(B), Not(C)), Not(A)) + assert eliminate_implications( + A >> (C >> Not(B))) == Or(Or(Not(B), Not(C)), Not(A)) + def test_conjuncts(): - A, B, C = list(map(Boolean, symbols('A,B,C'))) assert conjuncts(A & B & C) == set([A, B, C]) assert conjuncts((A | B) & C) == set([A | B, C]) assert conjuncts(A) == set([A]) assert conjuncts(True) == set([True]) assert conjuncts(False) == set([False]) + def test_disjuncts(): - A, B, C = list(map(Boolean, symbols('A,B,C'))) assert disjuncts(A | B | C) == set([A, B, C]) assert disjuncts((A | B) & C) == set([(A | B) & C]) assert disjuncts(A) == set([A]) assert disjuncts(True) == set([True]) assert disjuncts(False) == set([False]) + def test_distribute(): - A, B, C = list(map(Boolean, symbols('A,B,C'))) assert distribute_and_over_or(Or(And(A, B), C)) == And(Or(A, C), Or(B, C)) + assert distribute_or_over_and(And(A, Or(B, C))) == Or(And(A, B), And(A, C)) + def test_to_cnf(): - A, B, C = list(map(Boolean, symbols('A,B,C'))) assert to_cnf(~(B | C)) == And(Not(B), Not(C)) assert to_cnf((A & B) | C) == And(Or(A, C), Or(B, C)) assert to_cnf(A >> B) == (~A) | B assert to_cnf(A >> (B & C)) == (~A | B) & (~A | C) + assert to_cnf(A & (B | C) | ~A & (B | C), True) == B | C assert to_cnf(Equivalent(A, B)) == And(Or(A, Not(B)), Or(B, Not(A))) - assert to_cnf(Equivalent(A, B & C)) == (~A | B) & (~A | C) & (~B | ~C | A) - assert to_cnf(Equivalent(A, B | C)) == \ - And(Or(Not(B), A), Or(Not(C), A), Or(B, C, Not(A))) - -def test_compile_rule(): - from sympy import sympify - assert compile_rule("A & B") == sympify("A & B") + assert to_cnf(Equivalent(A, B & C)) == \ + (~A | B) & (~A | C) & (~B | ~C | A) + assert to_cnf(Equivalent(A, B | C), True) == \ + And(Or(Not(B), A), Or(Not(C), A), Or(B, C, Not(A))) + + +def test_to_dnf(): + + assert to_dnf(~(B | C)) == And(Not(B), Not(C)) + assert to_dnf(A & (B | C)) == Or(And(A, B), And(A, C)) + assert to_dnf(A >> B) == (~A) | B + assert to_dnf(A >> (B & C)) == (~A) | (B & C) + + assert to_dnf(Equivalent(A, B), True) == \ + Or(And(A, B), And(Not(A), Not(B))) + assert to_dnf(Equivalent(A, B & C), True) == \ + Or(And(A, B, C), And(Not(A), Not(B)), And(Not(A), Not(C))) + def test_to_int_repr(): x, y, z = list(map(Boolean, symbols('x,y,z'))) @@ -236,27 +340,40 @@ def sorted_recursive(arg): try: return sorted(sorted_recursive(x) for x in arg) - except TypeError: #arg is not a sequence + except TypeError: # arg is not a sequence return arg assert sorted_recursive(to_int_repr([x | y, z | x], [x, y, z])) == \ - sorted_recursive([[1, 2], [1, 3]]) + sorted_recursive([[1, 2], [1, 3]]) assert sorted_recursive(to_int_repr([x | y, z | ~x], [x, y, z])) == \ - sorted_recursive([[1, 2], [3, -1]]) + sorted_recursive([[1, 2], [3, -1]]) + def test_is_cnf(): x, y, z = symbols('x,y,z') - assert is_cnf(x | y | z) == True - assert is_cnf(x & y & z) == True - assert is_cnf((x | y) & z) == True - assert is_cnf((x & y) | z) == False + assert is_cnf(x) is True + assert is_cnf(x | y | z) is True + assert is_cnf(x & y & z) is True + assert is_cnf((x | y) & z) is True + assert is_cnf((x & y) | z) is False + + +def test_is_dnf(): + x, y, z = symbols('x,y,z') + assert is_dnf(x) is True + assert is_dnf(x | y | z) is True + assert is_dnf(x & y & z) is True + assert is_dnf((x & y) | z) is True + assert is_dnf((x | y) & z) is False + def test_ITE(): A, B, C = list(map(Boolean, symbols('A,B,C'))) - assert ITE(True, False, True) == False - assert ITE(True, True, False) == True - assert ITE(False, True, False) == False - assert ITE(False, False, True) == True + + assert ITE(True, False, True) is False + assert ITE(True, True, False) is True + assert ITE(False, True, False) is False + assert ITE(False, False, True) is True A = True assert ITE(A, B, C) == B @@ -264,4 +381,4 @@ assert ITE(A, B, C) == C B = True assert ITE(And(A, B), B, C) == C - assert ITE(Or(A, False), And(B, True), False) == False + assert ITE(Or(A, False), And(B, True), False) is False diff -Nru python3-sympy-0.7.2/sympy/logic/tests/test_dimacs.py python3-sympy-0.7.3/sympy/logic/tests/test_dimacs.py --- python3-sympy-0.7.2/sympy/logic/tests/test_dimacs.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/logic/tests/test_dimacs.py 2013-07-13 17:53:32.000000000 +0000 @@ -7,18 +7,23 @@ from sympy.logic.algorithms.dpll import dpll_satisfiable from sympy.utilities.pytest import skip + def test_f1(): assert bool(dpll_satisfiable(load(f1))) + def test_f2(): assert bool(dpll_satisfiable(load(f2))) + def test_f3(): assert bool(dpll_satisfiable(load(f3))) + def test_f4(): assert not bool(dpll_satisfiable(load(f4))) + def test_f5(): assert bool(dpll_satisfiable(load(f5))) diff -Nru python3-sympy-0.7.2/sympy/logic/tests/test_inference.py python3-sympy-0.7.3/sympy/logic/tests/test_inference.py --- python3-sympy-0.7.2/sympy/logic/tests/test_inference.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/logic/tests/test_inference.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,22 +1,39 @@ """For more tests on satisfiability, see test_dimacs""" from sympy import symbols -from sympy.logic.boolalg import Equivalent, Implies -from sympy.logic.inference import pl_true, satisfiable, PropKB +from sympy.logic.boolalg import Or, Equivalent, Implies +from sympy.logic.inference import is_literal, literal_symbol, \ + pl_true, satisfiable, PropKB from sympy.logic.algorithms.dpll import dpll, dpll_satisfiable, \ find_pure_symbol, find_unit_clause, unit_propagate, \ find_pure_symbol_int_repr, find_unit_clause_int_repr, \ unit_propagate_int_repr from sympy.utilities.pytest import raises + +def test_literal(): + A, B = symbols('A,B') + assert is_literal(True) is True + assert is_literal(False) is True + assert is_literal(A) is True + assert is_literal(~A) is True + assert is_literal(Or(A, B)) is False + assert literal_symbol(True) is True + assert literal_symbol(False) is False + assert literal_symbol(A) is A + assert literal_symbol(~A) is A + + def test_find_pure_symbol(): A, B, C = symbols('A,B,C') assert find_pure_symbol([A], [A]) == (A, True) assert find_pure_symbol([A, B], [~A | B, ~B | A]) == (None, None) assert find_pure_symbol([A, B, C], [ A | ~B, ~B | ~C, C | A]) == (A, True) - assert find_pure_symbol([A, B, C], [~A | B, B | ~C, C | A]) == (B, True) + assert find_pure_symbol([A, B, C], [~A | B, B | ~C, C | A]) == (B, True) assert find_pure_symbol([A, B, C], [~A | ~B, ~B | ~C, C | A]) == (B, False) - assert find_pure_symbol([A, B, C], [~A | B, ~B | ~C, C | A]) == (None, None) + assert find_pure_symbol( + [A, B, C], [~A | B, ~B | ~C, C | A]) == (None, None) + def test_find_pure_symbol_int_repr(): assert find_pure_symbol_int_repr([1], [set([1])]) == (1, True) @@ -31,122 +48,136 @@ assert find_pure_symbol_int_repr([1, 2, 3], [set([-1, 2]), set([-2, -3]), set([3, 1])]) == (None, None) + def test_unit_clause(): A, B, C = symbols('A,B,C') assert find_unit_clause([A], {}) == (A, True) - assert find_unit_clause([A, ~A], {}) == (A, True) ### Wrong ?? + assert find_unit_clause([A, ~A], {}) == (A, True) # Wrong ?? assert find_unit_clause([A | B], {A: True}) == (B, True) assert find_unit_clause([A | B], {B: True}) == (A, True) - assert find_unit_clause([A | B | C, B | ~C, A | ~B], {A:True}) == (B, False) - assert find_unit_clause([A | B | C, B | ~C, A | B], {A:True}) == (B, True) + assert find_unit_clause( + [A | B | C, B | ~C, A | ~B], {A: True}) == (B, False) + assert find_unit_clause([A | B | C, B | ~C, A | B], {A: True}) == (B, True) assert find_unit_clause([A | B | C, B | ~C, A ], {}) == (A, True) + def test_unit_clause_int_repr(): assert find_unit_clause_int_repr(list(map(set, [[1]])), {}) == (1, True) assert find_unit_clause_int_repr(list(map(set, [[1], [-1]])), {}) == (1, True) - assert find_unit_clause_int_repr([set([1,2])], {1: True}) == (2, True) - assert find_unit_clause_int_repr([set([1,2])], {2: True}) == (1, True) - assert find_unit_clause_int_repr(list(map(set, [[1,2,3], [2, -3], [1, -2]])), {1: True}) == \ - (2, False) - assert find_unit_clause_int_repr(list(map(set, [[1, 2, 3], [3, -3], [1, 2]])), {1: True}) == \ - (2, True) + assert find_unit_clause_int_repr([set([1, 2])], {1: True}) == (2, True) + assert find_unit_clause_int_repr([set([1, 2])], {2: True}) == (1, True) + assert find_unit_clause_int_repr(list(map(set, + [[1, 2, 3], [2, -3], [1, -2]])), {1: True}) == (2, False) + assert find_unit_clause_int_repr(list(map(set, + [[1, 2, 3], [3, -3], [1, 2]])), {1: True}) == (2, True) - A,B,C = symbols('A,B,C') + A, B, C = symbols('A,B,C') assert find_unit_clause([A | B | C, B | ~C, A ], {}) == (A, True) + def test_unit_propagate(): A, B, C = symbols('A,B,C') assert unit_propagate([A | B], A) == [] assert unit_propagate([A | B, ~A | C, ~C | B, A], A) == [C, ~C | B, A] + def test_unit_propagate_int_repr(): assert unit_propagate_int_repr([set([1, 2])], 1) == [] - assert unit_propagate_int_repr(list(map(set, [[1, 2], [-1, 3], [-3, 2], [1]])), 1) == \ - [set([3]), set([-3, 2])] + assert unit_propagate_int_repr(list(map(set, + [[1, 2], [-1, 3], [-3, 2], [1]])), 1) == [set([3]), set([-3, 2])] + def test_dpll(): """This is also tested in test_dimacs""" A, B, C = symbols('A,B,C') assert dpll([A | B], [A, B], {A: True, B: True}) == {A: True, B: True} + def test_dpll_satisfiable(): A, B, C = symbols('A,B,C') - assert dpll_satisfiable( A & ~A ) == False + assert dpll_satisfiable( A & ~A ) is False assert dpll_satisfiable( A & ~B ) == {A: True, B: False} - assert dpll_satisfiable( A | B ) in ({A: True}, {B: True}, {A: True, B: True}) - assert dpll_satisfiable( (~A | B) & (~B | A) ) in ({A: True, B: True}, {A: False, B:False}) + assert dpll_satisfiable( + A | B ) in ({A: True}, {B: True}, {A: True, B: True}) + assert dpll_satisfiable( + (~A | B) & (~B | A) ) in ({A: True, B: True}, {A: False, B: False}) assert dpll_satisfiable( (A | B) & (~B | C) ) in ({A: True, B: False}, - {A: True, C:True}, {B: True, C: True}) + {A: True, C: True}, {B: True, C: True}) assert dpll_satisfiable( A & B & C ) == {A: True, B: True, C: True} assert dpll_satisfiable( (A | B) & (A >> B) ) == {B: True} assert dpll_satisfiable( Equivalent(A, B) & A ) == {A: True, B: True} assert dpll_satisfiable( Equivalent(A, B) & ~A ) == {A: False, B: False} + def test_satisfiable(): A, B, C = symbols('A,B,C') - assert satisfiable(A & (A >> B) & ~B) == False + assert satisfiable(A & (A >> B) & ~B) is False + def test_pl_true(): A, B, C = symbols('A,B,C') - assert pl_true(True) == True - assert pl_true( A & B, {A : True, B : True}) == True - assert pl_true( A | B, {A : True}) == True - assert pl_true( A | B, {B : True}) == True - assert pl_true( A | B, {A: None, B: True}) == True - assert pl_true( A >> B, {A: False}) == True - assert pl_true( A | B | ~C, {A: False, B: True, C: True}) == True - assert pl_true(Equivalent(A, B), {A:False, B:False}) == True + assert pl_true(True) is True + assert pl_true( A & B, {A: True, B: True}) is True + assert pl_true( A | B, {A: True}) is True + assert pl_true( A | B, {B: True}) is True + assert pl_true( A | B, {A: None, B: True}) is True + assert pl_true( A >> B, {A: False}) is True + assert pl_true( A | B | ~C, {A: False, B: True, C: True}) is True + assert pl_true(Equivalent(A, B), {A: False, B: False}) is True # test for false - assert pl_true(False) == False - assert pl_true( A & B, {A: False, B: False}) == False - assert pl_true( A & B, {A: False}) == False - assert pl_true( A & B, {B: False}) == False - assert pl_true( A | B, {A: False, B: False}) == False + assert pl_true(False) is False + assert pl_true( A & B, {A: False, B: False}) is False + assert pl_true( A & B, {A: False}) is False + assert pl_true( A & B, {B: False}) is False + assert pl_true( A | B, {A: False, B: False}) is False #test for None assert pl_true(B, {B: None}) is None assert pl_true( A & B, {A: True, B: None}) is None assert pl_true( A >> B, {A: True, B: None}) is None - assert pl_true(Equivalent(A, B), {A:None}) is None - assert pl_true(Equivalent(A, B), {A:True, B:None}) is None + assert pl_true(Equivalent(A, B), {A: None}) is None + assert pl_true(Equivalent(A, B), {A: True, B: None}) is None + def test_pl_true_wrong_input(): from sympy import pi raises(ValueError, lambda: pl_true('John Cleese')) - raises(ValueError, lambda: pl_true(42+pi+pi**2)) + raises(ValueError, lambda: pl_true(42 + pi + pi ** 2)) raises(ValueError, lambda: pl_true(42)) + def test_PropKB(): A, B, C = symbols('A,B,C') kb = PropKB() kb.tell(A >> B) kb.tell(B >> C) - assert kb.ask(A) == True - assert kb.ask(B) == True - assert kb.ask(C) == True - assert kb.ask(~A) == True - assert kb.ask(~B) == True - assert kb.ask(~C) == True + assert kb.ask(A) is True + assert kb.ask(B) is True + assert kb.ask(C) is True + assert kb.ask(~A) is True + assert kb.ask(~B) is True + assert kb.ask(~C) is True kb.tell(A) - assert kb.ask(A) == True - assert kb.ask(B) == True - assert kb.ask(C) == True - assert kb.ask(~C) == False + assert kb.ask(A) is True + assert kb.ask(B) is True + assert kb.ask(C) is True + assert kb.ask(~C) is False kb.retract(A) - assert kb.ask(~C) == True + assert kb.ask(~C) is True kb2 = PropKB(Equivalent(A, B)) - assert kb2.ask(A) == True - assert kb2.ask(B) == True + assert kb2.ask(A) is True + assert kb2.ask(B) is True kb2.tell(A) - assert kb2.ask(A) == True + assert kb2.ask(A) is True kb3 = PropKB() kb3.tell(A) + def test_propKB_tolerant(): """"tolerant to bad input""" kb = PropKB() A, B, C = symbols('A,B,C') - assert kb.ask(B) == False + assert kb.ask(B) is False diff -Nru python3-sympy-0.7.2/sympy/logic/utilities/dimacs.py python3-sympy-0.7.3/sympy/logic/utilities/dimacs.py --- python3-sympy-0.7.2/sympy/logic/utilities/dimacs.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/logic/utilities/dimacs.py 2013-07-13 17:53:32.000000000 +0000 @@ -9,6 +9,7 @@ from sympy.logic.boolalg import And, Or import re + def load(s): """Loads a boolean expression from a string. @@ -44,20 +45,24 @@ list = [] for lit in nums: if lit != '': - if int(lit) == 0: continue + if int(lit) == 0: + continue num = abs(int(lit)) sign = True if int(lit) < 0: sign = False - if sign: list.append(Symbol("cnf_%s" % num)) - else: list.append(~Symbol("cnf_%s" % num)) + if sign: + list.append(Symbol("cnf_%s" % num)) + else: + list.append(~Symbol("cnf_%s" % num)) if len(list) > 0: clauses.append(Or(*list)) return And(*clauses) + def load_file(location): """Loads a boolean expression from a file.""" with open(location) as f: diff -Nru python3-sympy-0.7.2/sympy/matrices/__init__.py python3-sympy-0.7.3/sympy/matrices/__init__.py --- python3-sympy-0.7.2/sympy/matrices/__init__.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/matrices/__init__.py 2013-07-13 17:53:32.000000000 +0000 @@ -3,16 +3,28 @@ Includes functions for fast creating matrices like zero, one/eye, random matrix, etc. """ -from .matrices import (SparseMatrix, zeros, ones, eye, diag, - hessian, randMatrix, GramSchmidt, wronskian, casoratian, - list2numpy, matrix2numpy, DeferredVector, symarray, ShapeError, - NonSquareMatrixError, rot_axis1, rot_axis2, rot_axis3) - -from .matrices import MutableMatrix as Matrix - -from .immutable_matrix import ImmutableMatrix - -from .expressions import (BlockDiagMatrix, BlockMatrix, FunctionMatrix, - Identity, Inverse, MatAdd, MatMul, MatPow, MatrixExpr, MatrixSymbol, - Trace, Transpose, ZeroMatrix, block_collapse, linear_factors, - matrix_symbols, matrixify) +from .matrices import (DeferredVector, ShapeError, NonSquareMatrixError, + MatrixBase) + +from .dense import ( + GramSchmidt, Matrix, casoratian, diag, eye, hessian, jordan_cell, + list2numpy, matrix2numpy, matrix_multiply_elementwise, ones, + randMatrix, rot_axis1, rot_axis2, rot_axis3, symarray, wronskian, + zeros) + +MutableDenseMatrix = MutableMatrix = Matrix + +from .sparse import MutableSparseMatrix + +SparseMatrix = MutableSparseMatrix + +from .immutable import ImmutableMatrix, ImmutableSparseMatrix + +MutableSparseMatrix = SparseMatrix +ImmutableDenseMatrix = ImmutableMatrix + +from .expressions import (MatrixSlice, BlockDiagMatrix, BlockMatrix, + FunctionMatrix, Identity, Inverse, MatAdd, MatMul, MatPow, MatrixExpr, + MatrixSymbol, Trace, Transpose, ZeroMatrix, blockcut, block_collapse, + matrix_symbols, Adjoint, hadamard_product, HadamardProduct, + Determinant, det, DiagonalMatrix, DiagonalOf, trace) diff -Nru python3-sympy-0.7.2/sympy/matrices/dense.py python3-sympy-0.7.3/sympy/matrices/dense.py --- python3-sympy-0.7.2/sympy/matrices/dense.py 1970-01-01 00:00:00.000000000 +0000 +++ python3-sympy-0.7.3/sympy/matrices/dense.py 2013-07-13 17:53:32.000000000 +0000 @@ -0,0 +1,1674 @@ +import random + +from sympy.core.basic import Basic +from sympy.core.compatibility import is_sequence, as_int +from sympy.core.function import count_ops +from sympy.core.decorators import call_highest_priority +from sympy.core.singleton import S +from sympy.core.symbol import Symbol +from sympy.core.sympify import sympify +from sympy.functions.elementary.trigonometric import cos, sin +from sympy.functions.elementary.miscellaneous import sqrt +from sympy.simplify import simplify as _simplify +from sympy.utilities.exceptions import SymPyDeprecationWarning +from sympy.utilities.misc import filldedent +from sympy.utilities.decorator import doctest_depends_on + +from sympy.matrices.matrices import (MatrixBase, + ShapeError, a2idx, classof) +import collections + + +def _iszero(x): + """Returns True if x is zero.""" + return x.is_zero + + +class DenseMatrix(MatrixBase): + + is_MatrixExpr = False + + _op_priority = 10.01 + _class_priority = 4 + + def __getitem__(self, key): + """Return portion of self defined by key. If the key involves a slice + then a list will be returned (if key is a single slice) or a matrix + (if key was a tuple involving a slice). + + Examples + ======== + + >>> from sympy import Matrix, I + >>> m = Matrix([ + ... [1, 2 + I], + ... [3, 4 ]]) + + If the key is a tuple that doesn't involve a slice then that element + is returned: + + >>> m[1, 0] + 3 + + When a tuple key involves a slice, a matrix is returned. Here, the + first column is selected (all rows, column 0): + + >>> m[:, 0] + Matrix([ + [1], + [3]]) + + If the slice is not a tuple then it selects from the underlying + list of elements that are arranged in row order and a list is + returned if a slice is involved: + + >>> m[0] + 1 + >>> m[::2] + [1, 3] + """ + if type(key) is tuple: + i, j = key + if type(i) is slice or type(j) is slice: + return self.submatrix(key) + else: + i, j = self.key2ij(key) + return self._mat[i*self.cols + j] + else: + # row-wise decomposition of matrix + if type(key) is slice: + return self._mat[key] + return self._mat[a2idx(key)] + + def __setitem__(self, key, value): + raise NotImplementedError() + + def __hash__(self): + # issue 880 suggests that there should be no hash for a mutable + # object...but at least we aren't caching the result + return hash((type(self).__name__,) + (self.shape, tuple(self._mat))) + + @property + def is_Identity(self): + if not self.is_square: + return False + if not all(self[i, i] == 1 for i in range(self.rows)): + return False + for i in range(self.rows): + for j in range(i + 1, self.cols): + if self[i, j] or self[j, i]: + return False + return True + + def tolist(self): + """Return the Matrix as a nested Python list. + + Examples + ======== + + >>> from sympy import Matrix, ones + >>> m = Matrix(3, 3, list(range(9))) + >>> m + Matrix([ + [0, 1, 2], + [3, 4, 5], + [6, 7, 8]]) + >>> m.tolist() + [[0, 1, 2], [3, 4, 5], [6, 7, 8]] + >>> ones(3, 0).tolist() + [[], [], []] + + When there are no rows then it will not be possible to tell how + many columns were in the original matrix: + + >>> ones(0, 3).tolist() + [] + + """ + if not self.rows: + return [] + if not self.cols: + return [[] for i in range(self.rows)] + return [self._mat[i: i + self.cols] + for i in range(0, len(self), self.cols)] + + def row(self, i, f=None): + """Elementary row selector. + + Examples + ======== + + >>> from sympy import eye + >>> eye(2).row(0) + Matrix([[1, 0]]) + + See Also + ======== + + col + row_op + row_swap + row_del + row_join + row_insert + """ + if f is None: + return self[i, :] + SymPyDeprecationWarning( + feature="calling .row(i, f)", + useinstead=".row_op(i, f)", + deprecated_since_version="0.7.2", + ).warn() + self.row_op(i, f) + + def col(self, j, f=None): + """Elementary column selector. + + Examples + ======== + + >>> from sympy import eye + >>> eye(2).col(0) + Matrix([ + [1], + [0]]) + + See Also + ======== + + row + col_op + col_swap + col_del + col_join + col_insert + """ + if f is None: + return self[:, j] + SymPyDeprecationWarning( + feature="calling .col(j, f)", + useinstead=".col_op(j, f)", + deprecated_since_version="0.7.2", + ).warn() + self.col_op(j, f) + + def _eval_trace(self): + """Calculate the trace of a square matrix. + + Examples + ======== + + >>> from sympy.matrices import eye + >>> eye(3).trace() + 3 + + """ + trace = 0 + for i in range(self.cols): + trace += self._mat[i*self.cols + i] + return trace + + def _eval_determinant(self): + return self.det() + + def _eval_transpose(self): + """Matrix transposition. + + Examples + ======== + + >>> from sympy import Matrix, I + >>> m=Matrix(((1, 2+I), (3, 4))) + >>> m + Matrix([ + [1, 2 + I], + [3, 4]]) + >>> m.transpose() + Matrix([ + [ 1, 3], + [2 + I, 4]]) + >>> m.T == m.transpose() + True + + See Also + ======== + + conjugate: By-element conjugation + """ + a = [] + for i in range(self.cols): + a.extend(self._mat[i::self.cols]) + return self._new(self.cols, self.rows, a) + + def _eval_conjugate(self): + """By-element conjugation. + + See Also + ======== + + transpose: Matrix transposition + H: Hermite conjugation + D: Dirac conjugation + """ + out = self._new(self.rows, self.cols, + lambda i, j: self[i, j].conjugate()) + return out + + def _eval_adjoint(self): + return self.T.C + + def _eval_inverse(self, **kwargs): + """Return the matrix inverse using the method indicated (default + is Gauss elimination). + + kwargs + ====== + + method : ('GE', 'LU', or 'ADJ') + iszerofunc + try_block_diag + + Notes + ===== + + According to the ``method`` keyword, it calls the appropriate method: + + GE .... inverse_GE(); default + LU .... inverse_LU() + ADJ ... inverse_ADJ() + + According to the ``try_block_diag`` keyword, it will try to form block + diagonal matrices using the method get_diag_blocks(), invert these + individually, and then reconstruct the full inverse matrix. + + Note, the GE and LU methods may require the matrix to be simplified + before it is inverted in order to properly detect zeros during + pivoting. In difficult cases a custom zero detection function can + be provided by setting the ``iszerosfunc`` argument to a function that + should return True if its argument is zero. The ADJ routine computes + the determinant and uses that to detect singular matrices in addition + to testing for zeros on the diagonal. + + See Also + ======== + + inverse_LU + inverse_GE + inverse_ADJ + """ + from sympy.matrices import diag + + method = kwargs.get('method', 'GE') + iszerofunc = kwargs.get('iszerofunc', _iszero) + if kwargs.get('try_block_diag', False): + blocks = self.get_diag_blocks() + r = [] + for block in blocks: + r.append(block.inv(method=method, iszerofunc=iszerofunc)) + return diag(*r) + + M = self.as_mutable() + if method == "GE": + rv = M.inverse_GE(iszerofunc=iszerofunc) + elif method == "LU": + rv = M.inverse_LU(iszerofunc=iszerofunc) + elif method == "ADJ": + rv = M.inverse_ADJ(iszerofunc=iszerofunc) + else: + # make sure to add an invertibility check (as in inverse_LU) + # if a new method is added. + raise ValueError("Inversion method unrecognized") + return self._new(rv) + + def equals(self, other, failing_expression=False): + """Applies ``equals`` to corresponding elements of the matrices, + trying to prove that the elements are equivalent, returning True + if they are, False if any pair is not, and None (or the first + failing expression if failing_expression is True) if it cannot + be decided if the expressions are equivalent or not. This is, in + general, an expensive operation. + + Examples + ======== + + >>> from sympy.matrices import Matrix + >>> from sympy.abc import x + >>> from sympy import cos + >>> A = Matrix([x*(x - 1), 0]) + >>> B = Matrix([x**2 - x, 0]) + >>> A == B + False + >>> A.simplify() == B.simplify() + True + >>> A.equals(B) + True + >>> A.equals(2) + False + + See Also + ======== + sympy.core.expr.equals + """ + try: + if self.shape != other.shape: + return False + rv = True + for i in range(self.rows): + for j in range(self.cols): + ans = self[i, j].equals(other[i, j], failing_expression) + if ans is False: + return False + elif ans is not True and rv is True: + rv = ans + return rv + except AttributeError: + return False + + def __eq__(self, other): + try: + if self.shape != other.shape: + return False + if isinstance(other, Matrix): + return self._mat == other._mat + elif isinstance(other, MatrixBase): + return self._mat == Matrix(other)._mat + except AttributeError: + return False + + def __ne__(self, other): + return not self == other + + def _cholesky(self): + """Helper function of cholesky. + Without the error checks. + To be used privately. """ + L = zeros(self.rows, self.rows) + for i in range(self.rows): + for j in range(i): + L[i, j] = (1 / L[j, j])*(self[i, j] - + sum(L[i, k]*L[j, k] for k in range(j))) + L[i, i] = sqrt(self[i, i] - + sum(L[i, k]**2 for k in range(i))) + return self._new(L) + + def _LDLdecomposition(self): + """Helper function of LDLdecomposition. + Without the error checks. + To be used privately. + """ + D = zeros(self.rows, self.rows) + L = eye(self.rows) + for i in range(self.rows): + for j in range(i): + L[i, j] = (1 / D[j, j])*(self[i, j] - sum( + L[i, k]*L[j, k]*D[k, k] for k in range(j))) + D[i, i] = self[i, i] - sum(L[i, k]**2*D[k, k] + for k in range(i)) + return self._new(L), self._new(D) + + def _lower_triangular_solve(self, rhs): + """Helper function of function lower_triangular_solve. + Without the error checks. + To be used privately. + """ + X = zeros(self.rows, rhs.cols) + for j in range(rhs.cols): + for i in range(self.rows): + if self[i, i] == 0: + raise TypeError("Matrix must be non-singular.") + X[i, j] = (rhs[i, j] - sum(self[i, k]*X[k, j] + for k in range(i))) / self[i, i] + return self._new(X) + + def _upper_triangular_solve(self, rhs): + """Helper function of function upper_triangular_solve. + Without the error checks, to be used privately. """ + X = zeros(self.rows, rhs.cols) + for j in range(rhs.cols): + for i in reversed(list(range(self.rows))): + if self[i, i] == 0: + raise ValueError("Matrix must be non-singular.") + X[i, j] = (rhs[i, j] - sum(self[i, k]*X[k, j] + for k in range(i + 1, self.rows))) / self[i, i] + return self._new(X) + + def _diagonal_solve(self, rhs): + """Helper function of function diagonal_solve, + without the error checks, to be used privately. + """ + return self._new(rhs.rows, rhs.cols, lambda i, j: rhs[i, j] / self[i, i]) + + def applyfunc(self, f): + """Apply a function to each element of the matrix. + + Examples + ======== + + >>> from sympy import Matrix + >>> m = Matrix(2, 2, lambda i, j: i*2+j) + >>> m + Matrix([ + [0, 1], + [2, 3]]) + >>> m.applyfunc(lambda i: 2*i) + Matrix([ + [0, 2], + [4, 6]]) + + """ + if not isinstance(f, collections.Callable): + raise TypeError("`f` must be callable.") + + out = self._new(self.rows, self.cols, list(map(f, self._mat))) + return out + + def reshape(self, rows, cols): + """Reshape the matrix. Total number of elements must remain the same. + + Examples + ======== + + >>> from sympy import Matrix + >>> m = Matrix(2, 3, lambda i, j: 1) + >>> m + Matrix([ + [1, 1, 1], + [1, 1, 1]]) + >>> m.reshape(1, 6) + Matrix([[1, 1, 1, 1, 1, 1]]) + >>> m.reshape(3, 2) + Matrix([ + [1, 1], + [1, 1], + [1, 1]]) + + """ + if len(self) != rows*cols: + raise ValueError("Invalid reshape parameters %d %d" % (rows, cols)) + return self._new(rows, cols, lambda i, j: self._mat[i*cols + j]) + + def as_mutable(self): + """Returns a mutable version of this matrix + + Examples + ======== + + >>> from sympy import ImmutableMatrix + >>> X = ImmutableMatrix([[1, 2], [3, 4]]) + >>> Y = X.as_mutable() + >>> Y[1, 1] = 5 # Can set values in Y + >>> Y + Matrix([ + [1, 2], + [3, 5]]) + """ + return Matrix(self) + + def as_immutable(self): + """Returns an Immutable version of this Matrix + """ + from .immutable import ImmutableMatrix as cls + if self.rows: + return cls._new(self.tolist()) + return cls._new(0, self.cols, []) + + @classmethod + def zeros(cls, r, c=None): + """Return an r x c matrix of zeros, square if c is omitted.""" + if is_sequence(r): + SymPyDeprecationWarning( + feature="The syntax zeros([%i, %i])" % tuple(r), + useinstead="zeros(%i, %i)." % tuple(r), + issue=3381, deprecated_since_version="0.7.2", + ).warn() + r, c = r + else: + c = r if c is None else c + r = as_int(r) + c = as_int(c) + return cls._new(r, c, [cls._sympify(0)]*r*c) + + @classmethod + def eye(cls, n): + """Return an n x n identity matrix.""" + n = as_int(n) + mat = [cls._sympify(0)]*n*n + mat[::n + 1] = [cls._sympify(1)]*n + return cls._new(n, n, mat) + + ############################ + # Mutable matrix operators # + ############################ + + @call_highest_priority('__radd__') + def __add__(self, other): + return super(DenseMatrix, self).__add__(_force_mutable(other)) + + @call_highest_priority('__add__') + def __radd__(self, other): + return super(DenseMatrix, self).__radd__(_force_mutable(other)) + + @call_highest_priority('__rsub__') + def __sub__(self, other): + return super(DenseMatrix, self).__sub__(_force_mutable(other)) + + @call_highest_priority('__sub__') + def __rsub__(self, other): + return super(DenseMatrix, self).__rsub__(_force_mutable(other)) + + @call_highest_priority('__rmul__') + def __mul__(self, other): + return super(DenseMatrix, self).__mul__(_force_mutable(other)) + + @call_highest_priority('__mul__') + def __rmul__(self, other): + return super(DenseMatrix, self).__rmul__(_force_mutable(other)) + + @call_highest_priority('__div__') + def __div__(self, other): + return super(DenseMatrix, self).__div__(_force_mutable(other)) + + @call_highest_priority('__truediv__') + def __truediv__(self, other): + return super(DenseMatrix, self).__truediv__(_force_mutable(other)) + + @call_highest_priority('__rpow__') + def __pow__(self, other): + return super(DenseMatrix, self).__pow__(other) + + @call_highest_priority('__pow__') + def __rpow__(self, other): + raise NotImplementedError("Matrix Power not defined") + + +def _force_mutable(x): + """Return a matrix as a Matrix, otherwise return x.""" + if getattr(x, 'is_Matrix', False): + return x.as_mutable() + elif isinstance(x, Basic): + return x + elif hasattr(x, '__array__'): + a = x.__array__() + if len(a.shape) == 0: + return sympify(a) + return Matrix(x) + return x + + +class MutableDenseMatrix(DenseMatrix, MatrixBase): + @classmethod + def _new(cls, *args, **kwargs): + rows, cols, flat_list = cls._handle_creation_inputs(*args, **kwargs) + self = object.__new__(cls) + self.rows = rows + self.cols = cols + self._mat = list(flat_list) # create a shallow copy + return self + + def __new__(cls, *args, **kwargs): + return cls._new(*args, **kwargs) + + def as_mutable(self): + return self.copy() + + def __setitem__(self, key, value): + """ + + Examples + ======== + + >>> from sympy import Matrix, I, zeros, ones + >>> m = Matrix(((1, 2+I), (3, 4))) + >>> m + Matrix([ + [1, 2 + I], + [3, 4]]) + >>> m[1, 0] = 9 + >>> m + Matrix([ + [1, 2 + I], + [9, 4]]) + >>> m[1, 0] = [[0, 1]] + + To replace row r you assign to position r*m where m + is the number of columns: + + >>> M = zeros(4) + >>> m = M.cols + >>> M[3*m] = ones(1, m)*2; M + Matrix([ + [0, 0, 0, 0], + [0, 0, 0, 0], + [0, 0, 0, 0], + [2, 2, 2, 2]]) + + And to replace column c you can assign to position c: + + >>> M[2] = ones(m, 1)*4; M + Matrix([ + [0, 0, 4, 0], + [0, 0, 4, 0], + [0, 0, 4, 0], + [2, 2, 4, 2]]) + """ + rv = self._setitem(key, value) + if rv is not None: + i, j, value = rv + self._mat[i*self.cols + j] = value + + def copyin_matrix(self, key, value): + """Copy in values from a matrix into the given bounds. + + Parameters + ========== + + key : slice + The section of this matrix to replace. + value : Matrix + The matrix to copy values from. + + Examples + ======== + + >>> from sympy.matrices import Matrix, eye + >>> M = Matrix([[0, 1], [2, 3], [4, 5]]) + >>> I = eye(3) + >>> I[:3, :2] = M + >>> I + Matrix([ + [0, 1, 0], + [2, 3, 0], + [4, 5, 1]]) + >>> I[0, 1] = M + >>> I + Matrix([ + [0, 0, 1], + [2, 2, 3], + [4, 4, 5]]) + + See Also + ======== + + copyin_list + """ + rlo, rhi, clo, chi = self.key2bounds(key) + shape = value.shape + dr, dc = rhi - rlo, chi - clo + if shape != (dr, dc): + raise ShapeError(filldedent("The Matrix `value` doesn't have the " + "same dimensions " + "as the in sub-Matrix given by `key`.")) + + for i in range(value.rows): + for j in range(value.cols): + self[i + rlo, j + clo] = value[i, j] + + def copyin_list(self, key, value): + """Copy in elements from a list. + + Parameters + ========== + + key : slice + The section of this matrix to replace. + value : iterable + The iterable to copy values from. + + Examples + ======== + + >>> from sympy.matrices import eye + >>> I = eye(3) + >>> I[:2, 0] = [1, 2] # col + >>> I + Matrix([ + [1, 0, 0], + [2, 1, 0], + [0, 0, 1]]) + >>> I[1, :2] = [[3, 4]] + >>> I + Matrix([ + [1, 0, 0], + [3, 4, 0], + [0, 0, 1]]) + + See Also + ======== + + copyin_matrix + """ + if not is_sequence(value): + raise TypeError("`value` must be an ordered iterable, not %s." % type(value)) + return self.copyin_matrix(key, Matrix(value)) + + def zip_row_op(self, i, k, f): + """In-place operation on row ``i`` using two-arg functor whose args are + interpreted as ``(self[i, j], self[k, j])``. + + Examples + ======== + + >>> from sympy.matrices import eye + >>> M = eye(3) + >>> M.zip_row_op(1, 0, lambda v, u: v + 2*u); M + Matrix([ + [1, 0, 0], + [2, 1, 0], + [0, 0, 1]]) + + See Also + ======== + row + row_op + col_op + + """ + i0 = i*self.cols + k0 = k*self.cols + + ri = self._mat[i0: i0 + self.cols] + rk = self._mat[k0: k0 + self.cols] + + self._mat[i0: i0 + self.cols] = [ f(x, y) for x, y in zip(ri, rk) ] + + def row_op(self, i, f): + """In-place operation on row ``i`` using two-arg functor whose args are + interpreted as ``(self[i, j], j)``. + + Examples + ======== + + >>> from sympy.matrices import eye + >>> M = eye(3) + >>> M.row_op(1, lambda v, j: v + 2*M[0, j]); M + Matrix([ + [1, 0, 0], + [2, 1, 0], + [0, 0, 1]]) + + See Also + ======== + row + zip_row_op + col_op + + """ + i0 = i*self.cols + ri = self._mat[i0: i0 + self.cols] + self._mat[i0: i0 + self.cols] = [ f(x, j) for x, j in zip(ri, list(range(self.cols))) ] + + def col_op(self, j, f): + """In-place operation on col j using two-arg functor whose args are + interpreted as (self[i, j], i). + + Examples + ======== + + >>> from sympy.matrices import eye + >>> M = eye(3) + >>> M.col_op(1, lambda v, i: v + 2*M[i, 0]); M + Matrix([ + [1, 2, 0], + [0, 1, 0], + [0, 0, 1]]) + + See Also + ======== + col + row_op + """ + self._mat[j::self.cols] = [f(*t) for t in zip(self._mat[j::self.cols], list(range(self.rows)))] + + def row_swap(self, i, j): + """Swap the two given rows of the matrix in-place. + + Examples + ======== + + >>> from sympy.matrices import Matrix + >>> M = Matrix([[0, 1], [1, 0]]) + >>> M + Matrix([ + [0, 1], + [1, 0]]) + >>> M.row_swap(0, 1) + >>> M + Matrix([ + [1, 0], + [0, 1]]) + + See Also + ======== + + row + col_swap + """ + for k in range(0, self.cols): + self[i, k], self[j, k] = self[j, k], self[i, k] + + def col_swap(self, i, j): + """Swap the two given columns of the matrix in-place. + + Examples + ======== + + >>> from sympy.matrices import Matrix + >>> M = Matrix([[1, 0], [1, 0]]) + >>> M + Matrix([ + [1, 0], + [1, 0]]) + >>> M.col_swap(0, 1) + >>> M + Matrix([ + [0, 1], + [0, 1]]) + + See Also + ======== + + col + row_swap + """ + for k in range(0, self.rows): + self[k, i], self[k, j] = self[k, j], self[k, i] + + def row_del(self, i): + """Delete the given row. + + Examples + ======== + + >>> from sympy.matrices import eye + >>> M = eye(3) + >>> M.row_del(1) + >>> M + Matrix([ + [1, 0, 0], + [0, 0, 1]]) + + See Also + ======== + + row + col_del + """ + self._mat = self._mat[:i*self.cols] + self._mat[(i + 1)*self.cols:] + self.rows -= 1 + + def col_del(self, i): + """Delete the given column. + + Examples + ======== + + >>> from sympy.matrices import eye + >>> M = eye(3) + >>> M.col_del(1) + >>> M + Matrix([ + [1, 0], + [0, 0], + [0, 1]]) + + See Also + ======== + + col + row_del + """ + for j in range(self.rows - 1, -1, -1): + del self._mat[i + j*self.cols] + self.cols -= 1 + + # Utility functions + def simplify(self, ratio=1.7, measure=count_ops): + """Applies simplify to the elements of a matrix in place. + + This is a shortcut for M.applyfunc(lambda x: simplify(x, ratio, measure)) + + See Also + ======== + + sympy.simplify.simplify.simplify + """ + for i in range(len(self._mat)): + self._mat[i] = _simplify(self._mat[i], ratio=ratio, + measure=measure) + + def fill(self, value): + """Fill the matrix with the scalar value. + + See Also + ======== + + zeros + ones + """ + self._mat = [value]*len(self) + +MutableMatrix = Matrix = MutableDenseMatrix + +########### +# Numpy Utility Functions: +# list2numpy, matrix2numpy, symmarray, rot_axis[123] +########### + + +def list2numpy(l): # pragma: no cover + """Converts python list of SymPy expressions to a NumPy array. + + See Also + ======== + + matrix2numpy + """ + from numpy import empty + a = empty(len(l), dtype=object) + for i, s in enumerate(l): + a[i] = s + return a + + +def matrix2numpy(m): # pragma: no cover + """Converts SymPy's matrix to a NumPy array. + + See Also + ======== + + list2numpy + """ + from numpy import empty + a = empty(m.shape, dtype=object) + for i in range(m.rows): + for j in range(m.cols): + a[i, j] = m[i, j] + return a + +@doctest_depends_on(modules=('numpy',)) +def symarray(prefix, shape): # pragma: no cover + """Create a numpy ndarray of symbols (as an object array). + + The created symbols are named ``prefix_i1_i2_``... You should thus provide a + non-empty prefix if you want your symbols to be unique for different output + arrays, as SymPy symbols with identical names are the same object. + + Parameters + ---------- + + prefix : string + A prefix prepended to the name of every symbol. + + shape : int or tuple + Shape of the created array. If an int, the array is one-dimensional; for + more than one dimension the shape must be a tuple. + + Examples + -------- + These doctests require numpy. + + >>> from sympy import symarray + >>> symarray('', 3) + [_0 _1 _2] + + If you want multiple symarrays to contain distinct symbols, you *must* + provide unique prefixes: + + >>> a = symarray('', 3) + >>> b = symarray('', 3) + >>> a[0] is b[0] + True + >>> a = symarray('a', 3) + >>> b = symarray('b', 3) + >>> a[0] is b[0] + False + + Creating symarrays with a prefix: + + >>> symarray('a', 3) + [a_0 a_1 a_2] + + For more than one dimension, the shape must be given as a tuple: + + >>> symarray('a', (2, 3)) + [[a_0_0 a_0_1 a_0_2] + [a_1_0 a_1_1 a_1_2]] + >>> symarray('a', (2, 3, 2)) + [[[a_0_0_0 a_0_0_1] + [a_0_1_0 a_0_1_1] + [a_0_2_0 a_0_2_1]] + + [[a_1_0_0 a_1_0_1] + [a_1_1_0 a_1_1_1] + [a_1_2_0 a_1_2_1]]] + + """ + from numpy import empty, ndindex + arr = empty(shape, dtype=object) + for index in ndindex(shape): + arr[index] = Symbol('%s_%s' % (prefix, '_'.join(map(str, index)))) + return arr + + +def rot_axis3(theta): + """Returns a rotation matrix for a rotation of theta (in radians) about + the 3-axis. + + Examples + ======== + + >>> from sympy import pi + >>> from sympy.matrices import rot_axis3 + + A rotation of pi/3 (60 degrees): + + >>> theta = pi/3 + >>> rot_axis3(theta) + Matrix([ + [ 1/2, sqrt(3)/2, 0], + [-sqrt(3)/2, 1/2, 0], + [ 0, 0, 1]]) + + If we rotate by pi/2 (90 degrees): + + >>> rot_axis3(pi/2) + Matrix([ + [ 0, 1, 0], + [-1, 0, 0], + [ 0, 0, 1]]) + + See Also + ======== + + rot_axis1: Returns a rotation matrix for a rotation of theta (in radians) + about the 1-axis + rot_axis2: Returns a rotation matrix for a rotation of theta (in radians) + about the 2-axis + """ + ct = cos(theta) + st = sin(theta) + lil = ((ct, st, 0), + (-st, ct, 0), + (0, 0, 1)) + return Matrix(lil) + + +def rot_axis2(theta): + """Returns a rotation matrix for a rotation of theta (in radians) about + the 2-axis. + + Examples + ======== + + >>> from sympy import pi + >>> from sympy.matrices import rot_axis2 + + A rotation of pi/3 (60 degrees): + + >>> theta = pi/3 + >>> rot_axis2(theta) + Matrix([ + [ 1/2, 0, -sqrt(3)/2], + [ 0, 1, 0], + [sqrt(3)/2, 0, 1/2]]) + + If we rotate by pi/2 (90 degrees): + + >>> rot_axis2(pi/2) + Matrix([ + [0, 0, -1], + [0, 1, 0], + [1, 0, 0]]) + + See Also + ======== + + rot_axis1: Returns a rotation matrix for a rotation of theta (in radians) + about the 1-axis + rot_axis3: Returns a rotation matrix for a rotation of theta (in radians) + about the 3-axis + """ + ct = cos(theta) + st = sin(theta) + lil = ((ct, 0, -st), + (0, 1, 0), + (st, 0, ct)) + return Matrix(lil) + + +def rot_axis1(theta): + """Returns a rotation matrix for a rotation of theta (in radians) about + the 1-axis. + + Examples + ======== + + >>> from sympy import pi + >>> from sympy.matrices import rot_axis1 + + A rotation of pi/3 (60 degrees): + + >>> theta = pi/3 + >>> rot_axis1(theta) + Matrix([ + [1, 0, 0], + [0, 1/2, sqrt(3)/2], + [0, -sqrt(3)/2, 1/2]]) + + If we rotate by pi/2 (90 degrees): + + >>> rot_axis1(pi/2) + Matrix([ + [1, 0, 0], + [0, 0, 1], + [0, -1, 0]]) + + See Also + ======== + + rot_axis2: Returns a rotation matrix for a rotation of theta (in radians) + about the 2-axis + rot_axis3: Returns a rotation matrix for a rotation of theta (in radians) + about the 3-axis + """ + ct = cos(theta) + st = sin(theta) + lil = ((1, 0, 0), + (0, ct, st), + (0, -st, ct)) + return Matrix(lil) + +############### +# Functions +############### + + +def matrix_add(A, B): + SymPyDeprecationWarning( + feature="matrix_add(A, B)", + useinstead="A + B", + deprecated_since_version="0.7.2", + ).warn() + return A + B + + +def matrix_multiply(A, B): + SymPyDeprecationWarning( + feature="matrix_multiply(A, B)", + useinstead="A*B", + deprecated_since_version="0.7.2", + ).warn() + return A*B + + +def matrix_multiply_elementwise(A, B): + """Return the Hadamard product (elementwise product) of A and B + + >>> from sympy.matrices import matrix_multiply_elementwise + >>> from sympy.matrices import Matrix + >>> A = Matrix([[0, 1, 2], [3, 4, 5]]) + >>> B = Matrix([[1, 10, 100], [100, 10, 1]]) + >>> matrix_multiply_elementwise(A, B) + Matrix([ + [ 0, 10, 200], + [300, 40, 5]]) + + See Also + ======== + + __mul__ + """ + if A.shape != B.shape: + raise ShapeError() + shape = A.shape + return classof(A, B)._new(shape[0], shape[1], + lambda i, j: A[i, j]*B[i, j]) + + +def ones(r, c=None): + """Returns a matrix of ones with ``r`` rows and ``c`` columns; + if ``c`` is omitted a square matrix will be returned. + + See Also + ======== + + zeros + eye + diag + """ + from .dense import Matrix + + if is_sequence(r): + SymPyDeprecationWarning( + feature="The syntax ones([%i, %i])" % tuple(r), + useinstead="ones(%i, %i)." % tuple(r), + issue=3381, deprecated_since_version="0.7.2", + ).warn() + r, c = r + else: + c = r if c is None else c + r = as_int(r) + c = as_int(c) + return Matrix(r, c, [S.One]*r*c) + + +def zeros(r, c=None, cls=None): + """Returns a matrix of zeros with ``r`` rows and ``c`` columns; + if ``c`` is omitted a square matrix will be returned. + + See Also + ======== + + ones + eye + diag + """ + if cls is None: + from .dense import Matrix as cls + return cls.zeros(r, c) + + +def eye(n, cls=None): + """Create square identity matrix n x n + + See Also + ======== + + diag + zeros + ones + """ + if cls is None: + from sympy.matrices import Matrix as cls + return cls.eye(n) + +def diag(*values, **kwargs): + """Create a sparse, diagonal matrix from a list of diagonal values. + + Notes + ===== + + When arguments are matrices they are fitted in resultant matrix. + + The returned matrix is a mutable, dense matrix. To make it a different + type, send the desired class for keyword ``cls``. + + Examples + ======== + + >>> from sympy.matrices import diag, Matrix, ones + >>> diag(1, 2, 3) + Matrix([ + [1, 0, 0], + [0, 2, 0], + [0, 0, 3]]) + >>> diag(*[1, 2, 3]) + Matrix([ + [1, 0, 0], + [0, 2, 0], + [0, 0, 3]]) + + The diagonal elements can be matrices; diagonal filling will + continue on the diagonal from the last element of the matrix: + + >>> from sympy.abc import x, y, z + >>> a = Matrix([x, y, z]) + >>> b = Matrix([[1, 2], [3, 4]]) + >>> c = Matrix([[5, 6]]) + >>> diag(a, 7, b, c) + Matrix([ + [x, 0, 0, 0, 0, 0], + [y, 0, 0, 0, 0, 0], + [z, 0, 0, 0, 0, 0], + [0, 7, 0, 0, 0, 0], + [0, 0, 1, 2, 0, 0], + [0, 0, 3, 4, 0, 0], + [0, 0, 0, 0, 5, 6]]) + + When diagonal elements are lists, they will be treated as arguments + to Matrix: + + >>> diag([1, 2, 3], 4) + Matrix([ + [1, 0], + [2, 0], + [3, 0], + [0, 4]]) + >>> diag([[1, 2, 3]], 4) + Matrix([ + [1, 2, 3, 0], + [0, 0, 0, 4]]) + + A given band off the diagonal can be made by padding with a + vertical or horizontal "kerning" vector: + + >>> hpad = ones(0, 2) + >>> vpad = ones(2, 0) + >>> diag(vpad, 1, 2, 3, hpad) + diag(hpad, 4, 5, 6, vpad) + Matrix([ + [0, 0, 4, 0, 0], + [0, 0, 0, 5, 0], + [1, 0, 0, 0, 6], + [0, 2, 0, 0, 0], + [0, 0, 3, 0, 0]]) + + + + The type is mutable by default but can be made immutable by setting + the ``mutable`` flag to False: + + >>> type(diag(1)) + + >>> from sympy.matrices import ImmutableMatrix + >>> type(diag(1, cls=ImmutableMatrix)) + + + See Also + ======== + + eye + """ + from .sparse import MutableSparseMatrix + + cls = kwargs.pop('cls', None) + if cls is None: + from .dense import Matrix as cls + + if kwargs: + raise ValueError('unrecognized keyword%s: %s' % ( + 's' if len(kwargs) > 1 else '', + ', '.join(list(kwargs.keys())))) + rows = 0 + cols = 0 + values = list(values) + for i in range(len(values)): + m = values[i] + if isinstance(m, MatrixBase): + rows += m.rows + cols += m.cols + elif is_sequence(m): + m = values[i] = Matrix(m) + rows += m.rows + cols += m.cols + else: + rows += 1 + cols += 1 + res = MutableSparseMatrix.zeros(rows, cols) + i_row = 0 + i_col = 0 + for m in values: + if isinstance(m, MatrixBase): + res[i_row:i_row + m.rows, i_col:i_col + m.cols] = m + i_row += m.rows + i_col += m.cols + else: + res[i_row, i_col] = m + i_row += 1 + i_col += 1 + return cls._new(res) + + +def jordan_cell(eigenval, n): + """ + Create matrix of Jordan cell kind: + + Examples + ======== + + >>> from sympy.matrices import jordan_cell + >>> from sympy.abc import x + >>> jordan_cell(x, 4) + Matrix([ + [x, 1, 0, 0], + [0, x, 1, 0], + [0, 0, x, 1], + [0, 0, 0, x]]) + """ + n = as_int(n) + out = zeros(n) + for i in range(n - 1): + out[i, i] = eigenval + out[i, i + 1] = S.One + out[n - 1, n - 1] = eigenval + return out + + +def hessian(f, varlist, constraints=[]): + """Compute Hessian matrix for a function f wrt parameters in varlist + which may be given as a sequence or a row/column vector. A list of + constraints may optionally be given. + + Examples + ======== + + >>> from sympy import Function, hessian, pprint + >>> from sympy.abc import x, y + >>> f = Function('f')(x, y) + >>> g1 = Function('g')(x, y) + >>> g2 = x**2 + 3*y + >>> pprint(hessian(f, (x, y), [g1, g2])) + [ d d ] + [ 0 0 --(g(x, y)) --(g(x, y)) ] + [ dx dy ] + [ ] + [ 0 0 2*x 3 ] + [ ] + [ 2 2 ] + [d d d ] + [--(g(x, y)) 2*x ---(f(x, y)) -----(f(x, y))] + [dx 2 dy dx ] + [ dx ] + [ ] + [ 2 2 ] + [d d d ] + [--(g(x, y)) 3 -----(f(x, y)) ---(f(x, y)) ] + [dy dy dx 2 ] + [ dy ] + + References + ========== + + http://en.wikipedia.org/wiki/Hessian_matrix + + See Also + ======== + + sympy.matrices.mutable.Matrix.jacobian + wronskian + """ + # f is the expression representing a function f, return regular matrix + if isinstance(varlist, MatrixBase): + if 1 not in varlist.shape: + raise ShapeError("`varlist` must be a column or row vector.") + if varlist.cols == 1: + varlist = varlist.T + varlist = varlist.tolist()[0] + if is_sequence(varlist): + n = len(varlist) + if not n: + raise ShapeError("`len(varlist)` must not be zero.") + else: + raise ValueError("Improper variable list in hessian function") + if not getattr(f, 'diff'): + # check differentiability + raise ValueError("Function `f` (%s) is not differentiable" % f) + m = len(constraints) + N = m + n + out = zeros(N) + for k, g in enumerate(constraints): + if not getattr(g, 'diff'): + # check differentiability + raise ValueError("Function `f` (%s) is not differentiable" % f) + for i in range(n): + out[k, i + m] = g.diff(varlist[i]) + for i in range(n): + for j in range(i, n): + out[i + m, j + m] = f.diff(varlist[i]).diff(varlist[j]) + for i in range(N): + for j in range(i + 1, N): + out[j, i] = out[i, j] + return out + + +def GramSchmidt(vlist, orthog=False): + """ + Apply the Gram-Schmidt process to a set of vectors. + + see: http://en.wikipedia.org/wiki/Gram%E2%80%93Schmidt_process + """ + out = [] + m = len(vlist) + for i in range(m): + tmp = vlist[i] + for j in range(i): + tmp -= vlist[i].project(out[j]) + if not list(tmp.values()): + raise ValueError( + "GramSchmidt: vector set not linearly independent") + out.append(tmp) + if orthog: + for i in range(len(out)): + out[i] = out[i].normalized() + return out + + +def wronskian(functions, var, method='bareis'): + """ + Compute Wronskian for [] of functions + + :: + + | f1 f2 ... fn | + | f1' f2' ... fn' | + | . . . . | + W(f1, ..., fn) = | . . . . | + | . . . . | + | (n) (n) (n) | + | D (f1) D (f2) ... D (fn) | + + see: http://en.wikipedia.org/wiki/Wronskian + + See Also + ======== + + sympy.matrices.mutable.Matrix.jacobian + hessian + """ + from .dense import Matrix + + for index in range(0, len(functions)): + functions[index] = sympify(functions[index]) + n = len(functions) + if n == 0: + return 1 + W = Matrix(n, n, lambda i, j: functions[i].diff(var, j)) + return W.det(method) + + +def casoratian(seqs, n, zero=True): + """Given linear difference operator L of order 'k' and homogeneous + equation Ly = 0 we want to compute kernel of L, which is a set + of 'k' sequences: a(n), b(n), ... z(n). + + Solutions of L are linearly independent iff their Casoratian, + denoted as C(a, b, ..., z), do not vanish for n = 0. + + Casoratian is defined by k x k determinant:: + + + a(n) b(n) . . . z(n) + + | a(n+1) b(n+1) . . . z(n+1) | + | . . . . | + | . . . . | + | . . . . | + + a(n+k-1) b(n+k-1) . . . z(n+k-1) + + + It proves very useful in rsolve_hyper() where it is applied + to a generating set of a recurrence to factor out linearly + dependent solutions and return a basis: + + >>> from sympy import Symbol, casoratian, factorial + >>> n = Symbol('n', integer=True) + + Exponential and factorial are linearly independent: + + >>> casoratian([2**n, factorial(n)], n) != 0 + True + + """ + from .dense import Matrix + + seqs = list(map(sympify, seqs)) + + if not zero: + f = lambda i, j: seqs[j].subs(n, n + i) + else: + f = lambda i, j: seqs[j].subs(n, i) + + k = len(seqs) + + return Matrix(k, k, f).det() + + +def randMatrix(r, c=None, min=0, max=99, seed=None, symmetric=False, percent=100): + """Create random matrix with dimensions ``r`` x ``c``. If ``c`` is omitted + the matrix will be square. If ``symmetric`` is True the matrix must be + square. If ``percent`` is less than 100 then only approximately the given + percentage of elements will be non-zero. + + Examples + ======== + + >>> from sympy.matrices import randMatrix + >>> randMatrix(3) # doctest:+SKIP + [25, 45, 27] + [44, 54, 9] + [23, 96, 46] + >>> randMatrix(3, 2) # doctest:+SKIP + [87, 29] + [23, 37] + [90, 26] + >>> randMatrix(3, 3, 0, 2) # doctest:+SKIP + [0, 2, 0] + [2, 0, 1] + [0, 0, 1] + >>> randMatrix(3, symmetric=True) # doctest:+SKIP + [85, 26, 29] + [26, 71, 43] + [29, 43, 57] + >>> A = randMatrix(3, seed=1) + >>> B = randMatrix(3, seed=2) + >>> A == B # doctest:+SKIP + False + >>> A == randMatrix(3, seed=1) + True + >>> randMatrix(3, symmetric=True, percent=50) # doctest:+SKIP + [0, 68, 43] + [0, 68, 0] + [0, 91, 34] + """ + if c is None: + c = r + if seed is None: + prng = random.Random() # use system time + else: + prng = random.Random(seed) + if symmetric and r != c: + raise ValueError( + 'For symmetric matrices, r must equal c, but %i != %i' % (r, c)) + if not symmetric: + m = Matrix._new(r, c, lambda i, j: prng.randint(min, max)) + else: + m = zeros(r) + for i in range(r): + for j in range(i, r): + m[i, j] = prng.randint(min, max) + for i in range(r): + for j in range(i): + m[i, j] = m[j, i] + if percent == 100: + return m + else: + z = int(r*c*percent // 100) + m._mat[:z] = [S.Zero]*z + prng.shuffle(m._mat) + return m diff -Nru python3-sympy-0.7.2/sympy/matrices/expressions/__init__.py python3-sympy-0.7.3/sympy/matrices/expressions/__init__.py --- python3-sympy-0.7.2/sympy/matrices/expressions/__init__.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/matrices/expressions/__init__.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,12 +1,17 @@ """ A module which handles Matrix Expressions """ -from .blockmatrix import BlockMatrix, BlockDiagMatrix, block_collapse +from .slice import MatrixSlice +from .blockmatrix import BlockMatrix, BlockDiagMatrix, block_collapse, blockcut from .funcmatrix import FunctionMatrix from .inverse import Inverse from .matadd import MatAdd from .matexpr import (Identity, MatrixExpr, MatrixSymbol, ZeroMatrix, - linear_factors, matrix_symbols, matrixify) + matrix_symbols) from .matmul import MatMul from .matpow import MatPow -from .trace import Trace +from .trace import Trace, trace +from .determinant import Determinant, det from .transpose import Transpose +from .adjoint import Adjoint +from .hadamard import hadamard_product, HadamardProduct +from .diagonal import DiagonalMatrix, DiagonalOf diff -Nru python3-sympy-0.7.2/sympy/matrices/expressions/adjoint.py python3-sympy-0.7.3/sympy/matrices/expressions/adjoint.py --- python3-sympy-0.7.2/sympy/matrices/expressions/adjoint.py 1970-01-01 00:00:00.000000000 +0000 +++ python3-sympy-0.7.3/sympy/matrices/expressions/adjoint.py 2013-07-13 17:53:32.000000000 +0000 @@ -0,0 +1,62 @@ +from sympy.core import Basic +from sympy.functions import adjoint, conjugate +from sympy.matrices.expressions.transpose import transpose +from sympy.matrices.expressions.matexpr import MatrixExpr + + +class Adjoint(MatrixExpr): + """ + The Hermitian adjoint of a matrix expression. + + This is a symbolic object that simply stores its argument without + evaluating it. To actually compute the adjoint, use the ``adjoint()`` + function. + + Examples + ======== + + >>> from sympy.matrices import MatrixSymbol, Adjoint + >>> from sympy.functions import adjoint + >>> A = MatrixSymbol('A', 3, 5) + >>> B = MatrixSymbol('B', 5, 3) + >>> Adjoint(A*B) + Adjoint(A*B) + >>> adjoint(A*B) + Adjoint(B)*Adjoint(A) + >>> adjoint(A*B) == Adjoint(A*B) + False + >>> adjoint(A*B) == Adjoint(A*B).doit() + True + """ + is_Adjoint = True + + def doit(self, **hints): + arg = self.arg + if hints.get('deep', True) and isinstance(arg, Basic): + return adjoint(arg.doit(**hints)) + else: + return adjoint(self.arg) + + @property + def arg(self): + return self.args[0] + + @property + def shape(self): + return self.arg.shape[::-1] + + def _entry(self, i, j): + return conjugate(self.arg._entry(j, i)) + + def _eval_adjoint(self): + return self.arg + + def _eval_conjugate(self): + return transpose(self.arg) + + def _eval_trace(self): + from sympy.matrices.expressions.trace import Trace + return conjugate(Trace(self.arg)) + + def _eval_transpose(self): + return conjugate(self.arg) diff -Nru python3-sympy-0.7.2/sympy/matrices/expressions/blockmatrix.py python3-sympy-0.7.3/sympy/matrices/expressions/blockmatrix.py --- python3-sympy-0.7.2/sympy/matrices/expressions/blockmatrix.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/matrices/expressions/blockmatrix.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,11 +1,20 @@ -from .matexpr import MatrixExpr, ZeroMatrix, Identity -from .matmul import MatMul -from .matadd import MatAdd -from .transpose import Transpose -from .trace import Trace -from .inverse import Inverse -from sympy.matrices import Matrix, eye -from sympy import Tuple, Basic, sympify, FiniteSet, Add +from sympy import ask, Q +from sympy.core import Tuple, Basic, Add +from sympy.strategies import typed, exhaust, condition, debug, do_one, unpack, chain +from sympy.strategies.traverse import bottom_up +from sympy.utilities import sift + +from sympy.matrices.expressions.matexpr import MatrixExpr, ZeroMatrix, Identity +from sympy.matrices.expressions.matmul import MatMul +from sympy.matrices.expressions.matadd import MatAdd +from sympy.matrices.expressions.matpow import MatPow +from sympy.matrices.expressions.transpose import Transpose, transpose +from sympy.matrices.expressions.trace import Trace +from sympy.matrices.expressions.determinant import det, Determinant +from sympy.matrices.expressions.slice import MatrixSlice +from sympy.matrices.expressions.inverse import Inverse +from sympy.matrices import Matrix, eye, ShapeError + class BlockMatrix(MatrixExpr): """A BlockMatrix is a Matrix composed of other smaller, submatrices @@ -13,121 +22,130 @@ The submatrices are stored in a SymPy Matrix object but accessed as part of a Matrix Expression - >>> from sympy import MatrixSymbol, BlockMatrix, symbols, Identity, ZeroMatrix, block_collapse + >>> from sympy import (MatrixSymbol, BlockMatrix, symbols, + ... Identity, ZeroMatrix, block_collapse) >>> n,m,l = symbols('n m l') >>> X = MatrixSymbol('X', n, n) >>> Y = MatrixSymbol('Y', m ,m) >>> Z = MatrixSymbol('Z', n, m) >>> B = BlockMatrix([[X, Z], [ZeroMatrix(m,n), Y]]) >>> print(B) - [X, Z] - [0, Y] + Matrix([ + [X, Z], + [0, Y]]) >>> C = BlockMatrix([[Identity(n), Z]]) >>> print(C) - [I, Z] + Matrix([[I, Z]]) >>> print(block_collapse(C*B)) - [X, Z + Z*Y] + Matrix([[X, Z + Z*Y]]) """ - is_BlockMatrix = True - is_BlockDiagMatrix = False - def __new__(cls, mat): - if not isinstance(mat, Matrix): - mat = Matrix(mat) - data = Tuple(*mat.mat) - shape = Tuple(*sympify(mat.shape)) - obj = Basic.__new__(cls, data, shape) - obj.mat = mat + def __new__(cls, *args): + from sympy.matrices.immutable import ImmutableMatrix + mat = ImmutableMatrix(*args) + + obj = Basic.__new__(cls, mat) return obj @property def shape(self): numrows = numcols = 0 - M = self.mat + M = self.blocks for i in range(M.shape[0]): - numrows += M[i,0].shape[0] + numrows += M[i, 0].shape[0] for i in range(M.shape[1]): - numcols += M[0,i].shape[1] + numcols += M[0, i].shape[1] return (numrows, numcols) @property def blockshape(self): - return self.mat.shape + return self.blocks.shape @property def blocks(self): - return self.mat + return self.args[0] @property def rowblocksizes(self): - return [self.blocks[i,0].rows for i in range(self.blockshape[0])] + return [self.blocks[i, 0].rows for i in range(self.blockshape[0])] @property def colblocksizes(self): - return [self.blocks[0,i].cols for i in range(self.blockshape[1])] + return [self.blocks[0, i].cols for i in range(self.blockshape[1])] - def _blockmul(self, other): + def structurally_equal(self, other): + return (isinstance(other, BlockMatrix) + and self.shape == other.shape + and self.blockshape == other.blockshape + and self.rowblocksizes == other.rowblocksizes + and self.colblocksizes == other.colblocksizes) - if (other.is_Matrix and other.is_BlockMatrix and - self.blockshape[1] == other.blockshape[0] and + def _blockmul(self, other): + if (isinstance(other, BlockMatrix) and self.colblocksizes == other.rowblocksizes): - return BlockMatrix(self.mat*other.mat) + return BlockMatrix(self.blocks*other.blocks) - return MatrixExpr.__mul__(self, other) + return self * other def _blockadd(self, other): + if (isinstance(other, BlockMatrix) + and self.structurally_equal(other)): + return BlockMatrix(self.blocks + other.blocks) - if (other.is_Matrix and other.is_BlockMatrix and - self.blockshape == other.blockshape and - self.rowblocksizes == other.rowblocksizes and - self.colblocksizes == other.colblocksizes): - return BlockMatrix(self.mat + other.mat) - - return MatrixExpr.__add__(self, other) + return self + other def _eval_transpose(self): # Flip all the individual matrices - matrices = [Transpose(matrix) for matrix in self.mat.mat] + matrices = [transpose(matrix) for matrix in self.blocks] # Make a copy - mat = Matrix(self.blockshape[0], self.blockshape[1], matrices) + M = Matrix(self.blockshape[0], self.blockshape[1], matrices) # Transpose the block structure - mat = mat.transpose() - return BlockMatrix(mat) + M = M.transpose() + return BlockMatrix(M) def _eval_trace(self): if self.rowblocksizes == self.colblocksizes: - return Add(*[Trace(self.mat[i,i]) + return Add(*[Trace(self.blocks[i, i]) for i in range(self.blockshape[0])]) - raise NotImplementedError("Can't perform trace of irregular blockshape") - - #def transpose(self): - # return self.eval_transpose() - - def _eval_inverse(self, expand=False): - # Inverse of one by one block matrix is easy - if self.blockshape==(1,1): - mat = Matrix(1, 1, (Inverse(self.blocks[0]), )) - return BlockMatrix(mat) - # Inverse of a two by two block matrix is known - elif expand and self.blockshape==(2,2): - # Cite: The Matrix Cookbook Section 9.1.3 - A11, A12, A21, A22 = (self.blocks[0,0], self.blocks[0,1], - self.blocks[1,0], self.blocks[1,1]) - C1 = A11 - A12*Inverse(A22)*A21 - C2 = A22 - A21*Inverse(A11)*A12 - mat = Matrix([[Inverse(C1), Inverse(-A11)*A12*Inverse(C2)], - [-Inverse(C2)*A21*Inverse(A11), Inverse(C2)]]) - return BlockMatrix(mat) - else: - raise NotImplementedError() + raise NotImplementedError( + "Can't perform trace of irregular blockshape") - def inverse(self): - return Inverse(self) + def _eval_determinant(self): + if self.blockshape == (2, 2): + [[A, B], + [C, D]] = self.blocks.tolist() + if ask(Q.invertible(A)): + return det(A)*det(D - C*A.I*B) + elif ask(Q.invertible(D)): + return det(D)*det(A - B*D.I*C) + return Determinant(self) + + def transpose(self): + """Return transpose of matrix. + + Examples + ======== + + >>> from sympy import MatrixSymbol, BlockMatrix, ZeroMatrix + >>> from sympy.abc import l, m, n + >>> X = MatrixSymbol('X', n, n) + >>> Y = MatrixSymbol('Y', m ,m) + >>> Z = MatrixSymbol('Z', n, m) + >>> B = BlockMatrix([[X, Z], [ZeroMatrix(m,n), Y]]) + >>> B.transpose() + Matrix([ + [X', 0], + [Z', Y']]) + >>> _.transpose() + Matrix([ + [X, Z], + [0, Y]]) + """ + return self._eval_transpose() def _entry(self, i, j): - idx = 0 # Find row entry for row_block, numrows in enumerate(self.rowblocksizes): if i < numrows: @@ -139,7 +157,7 @@ break else: j -= numcols - return self.blocks[row_block, col_block][i,j] + return self.blocks[row_block, col_block][i, j] @property def is_Identity(self): @@ -147,174 +165,277 @@ return False for i in range(self.blockshape[0]): for j in range(self.blockshape[1]): - if i==j and not self.mat[i,j].is_Identity: + if i==j and not self.blocks[i, j].is_Identity: return False - if i!=j and not self.mat[i,j].is_ZeroMatrix: + if i!=j and not self.blocks[i, j].is_ZeroMatrix: return False return True + @property def is_structurally_symmetric(self): return self.rowblocksizes == self.colblocksizes + def equals(self, other): + if self == other: + return True + if (isinstance(other, BlockMatrix) and self.blocks == other.blocks): + return True + return super(BlockMatrix, self).equals(other) + class BlockDiagMatrix(BlockMatrix): - """A BlockDiagMatrix is a BlockMatrix with matrices only along the diagonal + """ + A BlockDiagMatrix is a BlockMatrix with matrices only along the diagonal >>> from sympy import MatrixSymbol, BlockDiagMatrix, symbols, Identity >>> n,m,l = symbols('n m l') >>> X = MatrixSymbol('X', n, n) >>> Y = MatrixSymbol('Y', m ,m) >>> BlockDiagMatrix(X, Y) - [X, 0] - [0, Y] + Matrix([ + [X, 0], + [0, Y]]) """ - is_BlockDiagMatrix = True def __new__(cls, *mats): - data_matrix = eye(len(mats)) - for i, mat in enumerate(mats): - data_matrix[i,i] = mat - - for r in range(len(mats)): - for c in range(len(mats)): - if r == c: - continue - n = mats[r].rows - m = mats[c].cols - data_matrix[r, c] = ZeroMatrix(n, m) - - shape = Tuple(*sympify(mat.shape)) - data = Tuple(*data_matrix.mat) - obj = Basic.__new__(cls, data, shape, Tuple(*mats)) - obj.mat = data_matrix - return obj + return Basic.__new__(BlockDiagMatrix, *mats) @property def diag(self): - return self.args[2] + return self.args + + @property + def blocks(self): + from sympy.matrices.immutable import ImmutableMatrix + mats = self.args + data = [[mats[i] if i == j else ZeroMatrix(mats[i].rows, mats[j].cols) + for j in range(len(mats))] + for i in range(len(mats))] + return ImmutableMatrix(data) + + @property + def shape(self): + return (sum(block.rows for block in self.args), + sum(block.cols for block in self.args)) + + @property + def blockshape(self): + n = len(self.args) + return (n, n) + + @property + def rowblocksizes(self): + return [block.rows for block in self.args] + + @property + def colblocksizes(self): + return [block.cols for block in self.args] - def _eval_inverse(self): - return BlockDiagMatrix(*[Inverse(mat) for mat in self.diag]) + def _eval_inverse(self, expand='ignored'): + return BlockDiagMatrix(*[mat.inverse() for mat in self.args]) def _blockmul(self, other): - if (other.is_Matrix and other.is_BlockMatrix and - other.is_BlockDiagMatrix and - self.blockshape[1] == other.blockshape[0] and + if (isinstance(other, BlockDiagMatrix) and self.colblocksizes == other.rowblocksizes): - return BlockDiagMatrix(*[a*b for a, b in zip(self.diag,other.diag)]) + return BlockDiagMatrix(*[a*b for a, b in zip(self.args, other.args)]) else: return BlockMatrix._blockmul(self, other) def _blockadd(self, other): - - if (other.is_Matrix and other.is_BlockMatrix and - other.is_BlockDiagMatrix and + if (isinstance(other, BlockDiagMatrix) and self.blockshape == other.blockshape and self.rowblocksizes == other.rowblocksizes and self.colblocksizes == other.colblocksizes): - return BlockDiagMatrix(*[a+b for a, b in zip(self.diag,other.diag)]) + return BlockDiagMatrix(*[a + b for a, b in zip(self.args, other.args)]) else: return BlockMatrix._blockadd(self, other) + def block_collapse(expr): """Evaluates a block matrix expression - >>> from sympy import MatrixSymbol, BlockMatrix, symbols, Identity, Matrix, ZeroMatrix, block_collapse + >>> from sympy import MatrixSymbol, BlockMatrix, symbols, \ + Identity, Matrix, ZeroMatrix, block_collapse >>> n,m,l = symbols('n m l') >>> X = MatrixSymbol('X', n, n) >>> Y = MatrixSymbol('Y', m ,m) >>> Z = MatrixSymbol('Z', n, m) >>> B = BlockMatrix([[X, Z], [ZeroMatrix(m, n), Y]]) >>> print(B) - [X, Z] - [0, Y] + Matrix([ + [X, Z], + [0, Y]]) >>> C = BlockMatrix([[Identity(n), Z]]) >>> print(C) - [I, Z] + Matrix([[I, Z]]) >>> print(block_collapse(C*B)) - [X, Z + Z*Y] + Matrix([[X, Z + Z*Y]]) """ - if expr.__class__ in [tuple, list, set, frozenset]: - return expr.__class__([block_collapse(arg) for arg in expr]) - if expr.__class__ in [Tuple, FiniteSet]: - return expr.__class__(*[block_collapse(arg) for arg in expr]) - - if not expr.is_Matrix or (not expr.is_Add and not expr.is_Mul - and not expr.is_Transpose and not expr.is_Pow - and not expr.is_Inverse): + hasbm = lambda expr: isinstance(expr, MatrixExpr) and expr.has(BlockMatrix) + rule = exhaust( + bottom_up(exhaust(condition(hasbm, typed( + {MatAdd: do_one(bc_matadd, bc_block_plus_ident), + MatMul: do_one(bc_matmul, bc_dist), + Transpose: bc_transpose, + Inverse: bc_inverse, + BlockMatrix: do_one(bc_unpack, deblock)}))))) + result = rule(expr) + try: + return result.doit() + except AttributeError: + return result + +def bc_unpack(expr): + if expr.blockshape == (1, 1): + return expr.blocks[0, 0] + return expr + +def bc_matadd(expr): + args = sift(expr.args, lambda M: isinstance(M, BlockMatrix)) + blocks = args[True] + if not blocks: return expr - if expr.is_Transpose: - expr = Transpose(block_collapse(expr.arg)) - if expr.is_Transpose and expr.arg.is_BlockMatrix: - expr = expr.arg._eval_transpose() + nonblocks = args[False] + block = blocks[0] + for b in blocks[1:]: + block = block._blockadd(b) + if nonblocks: + return MatAdd(*nonblocks) + block + else: + return block + +def bc_block_plus_ident(expr): + idents = [arg for arg in expr.args if arg.is_Identity] + if not idents: return expr - if expr.is_Inverse: - return Inverse(block_collapse(expr.arg)) - - # Recurse on the subargs - args = list(expr.args) - for i in range(len(args)): - arg = args[i] - newarg = block_collapse(arg) - while(newarg != arg): # Repeat until no new changes - arg = newarg - newarg = block_collapse(arg) - args[i] = newarg - - if tuple(args) != expr.args: - expr = expr.__class__(*args) - - # Turn -[X, Y] into [-X, -Y] - if (expr.is_Mul and len(expr.args)==2 and not expr.args[0].is_Matrix - and expr.args[1].is_BlockMatrix): - if expr.args[1].is_BlockDiagMatrix: - return BlockDiagMatrix( - *[expr.args[0]*arg for arg in expr.args[1].diag]) + blocks = [arg for arg in expr.args if isinstance(arg, BlockMatrix)] + if (blocks and all(b.structurally_equal(blocks[0]) for b in blocks) + and blocks[0].is_structurally_symmetric): + block_id = BlockDiagMatrix(*[Identity(k) + for k in blocks[0].rowblocksizes]) + return MatAdd(block_id * len(idents), *blocks).doit() + + return expr + +def bc_dist(expr): + """ Turn a*[X, Y] into [a*X, a*Y] """ + factor, mat = expr.as_coeff_mmul() + if factor != 1 and isinstance(unpack(mat), BlockMatrix): + B = unpack(mat).blocks + return BlockMatrix([[factor * B[i, j] for j in range(B.cols)] + for i in range(B.rows)]) + return expr + + +def bc_matmul(expr): + factor, matrices = expr.as_coeff_matrices() + + i = 0 + while (i+1 < len(matrices)): + A, B = matrices[i:i+2] + if isinstance(A, BlockMatrix) and isinstance(B, BlockMatrix): + matrices[i] = A._blockmul(B) + matrices.pop(i+1) + elif isinstance(A, BlockMatrix): + matrices[i] = A._blockmul(BlockMatrix([[B]])) + matrices.pop(i+1) + elif isinstance(B, BlockMatrix): + matrices[i] = BlockMatrix([[A]])._blockmul(B) + matrices.pop(i+1) else: - return BlockMatrix(expr.args[0]*expr.args[1].mat) + i+=1 + return MatMul(factor, *matrices).doit() - if expr.is_Add: - nonblocks = [arg for arg in expr.args if not arg.is_BlockMatrix] - blocks = [arg for arg in expr.args if arg.is_BlockMatrix] - if not blocks: - return MatAdd(*nonblocks) - block = blocks[0] - for b in blocks[1:]: - block = block._blockadd(b) - if block.blockshape == (1,1): - # Bring all the non-blocks into the block_matrix - mat = Matrix(1, 1, (block.blocks[0,0] + MatAdd(*nonblocks), )) - return BlockMatrix(mat) - # Add identities to the blocks as block identities - for i, mat in enumerate(nonblocks): - c, M = mat.as_coeff_Mul() - if M.is_Identity and block.is_structurally_symmetric: - block_id = BlockDiagMatrix( - *[c*Identity(k) for k in block.rowblocksizes]) - nonblocks.pop(i) - block = block._blockadd(block_id) - - - return MatAdd(*(nonblocks+[block])) - - if expr.is_Mul: - nonmatrices = [arg for arg in expr.args if not arg.is_Matrix] - matrices = [arg for arg in expr.args if arg.is_Matrix] - i = 0 - while (i+1 < len(matrices)): - A, B = matrices[i:i+2] - if A.is_BlockMatrix and B.is_BlockMatrix: - matrices[i] = A._blockmul(B) - matrices.pop(i+1) - else: - i+=1 - return MatMul(*(nonmatrices + matrices)) +def bc_transpose(expr): + return BlockMatrix(block_collapse(expr.arg).blocks.applyfunc(transpose).T) + + +def bc_inverse(expr): + expr2 = blockinverse_1x1(expr) + if expr != expr2: + return expr2 + return blockinverse_2x2(Inverse(reblock_2x2(expr.arg))) + +def blockinverse_1x1(expr): + if isinstance(expr.arg, BlockMatrix) and expr.arg.blockshape == (1, 1): + mat = Matrix([[expr.arg.blocks[0].inverse()]]) + return BlockMatrix(mat) + return expr + +def blockinverse_2x2(expr): + if isinstance(expr.arg, BlockMatrix) and expr.arg.blockshape == (2, 2): + # Cite: The Matrix Cookbook Section 9.1.3 + [[A, B], + [C, D]] = expr.arg.blocks.tolist() + + return BlockMatrix([[ (A - B*D.I*C).I, (-A).I*B*(D - C*A.I*B).I], + [-(D - C*A.I*B).I*C*A.I, (D - C*A.I*B).I]]) + else: + return expr + +def deblock(B): + """ Flatten a BlockMatrix of BlockMatrices """ + if not isinstance(B, BlockMatrix) or not B.blocks.has(BlockMatrix): + return B + wrap = lambda x: x if isinstance(x, BlockMatrix) else BlockMatrix([[x]]) + bb = B.blocks.applyfunc(wrap) # everything is a block + + from sympy import Matrix + try: + MM = Matrix(0, sum(bb[0, i].blocks.shape[1] for i in range(bb.shape[1])), []) + for row in range(0, bb.shape[0]): + M = Matrix(bb[row, 0].blocks) + for col in range(1, bb.shape[1]): + M = M.row_join(bb[row, col].blocks) + MM = MM.col_join(M) + + return BlockMatrix(MM) + except ShapeError: + return B + + + +def reblock_2x2(B): + """ Reblock a BlockMatrix so that it has 2x2 blocks of block matrices """ + if not isinstance(B, BlockMatrix) or not all(d > 2 for d in B.blocks.shape): + return B + + BM = BlockMatrix # for brevity's sake + return BM([[ B.blocks[0, 0], BM(B.blocks[0, 1:])], + [BM(B.blocks[1:, 0]), BM(B.blocks[1:, 1:])]]) + + +def bounds(sizes): + """ Convert sequence of numbers into pairs of low-high pairs + + >>> from sympy.matrices.expressions.blockmatrix import bounds + >>> bounds((1, 10, 50)) + [(0, 1), (1, 11), (11, 61)] + """ + low = 0 + rv = [] + for size in sizes: + rv.append((low, low + size)) + low += size + return rv + +def blockcut(expr, rowsizes, colsizes): + """ Cut a matrix expression into Blocks + + >>> from sympy import ImmutableMatrix, blockcut + >>> M = ImmutableMatrix(4, 4, list(range(16))) + >>> B = blockcut(M, (1, 3), (1, 3)) + >>> type(B).__name__ + 'BlockMatrix' + >>> ImmutableMatrix(B.blocks[0, 1]) + Matrix([[1, 2, 3]]) + """ - if expr.is_Pow: - rv = expr.base - for i in range(1, expr.exp): - rv = rv._blockmul(expr.base) - return rv + rowbounds = bounds(rowsizes) + colbounds = bounds(colsizes) + return BlockMatrix([[MatrixSlice(expr, rowbound, colbound) + for colbound in colbounds] + for rowbound in rowbounds]) diff -Nru python3-sympy-0.7.2/sympy/matrices/expressions/determinant.py python3-sympy-0.7.3/sympy/matrices/expressions/determinant.py --- python3-sympy-0.7.2/sympy/matrices/expressions/determinant.py 1970-01-01 00:00:00.000000000 +0000 +++ python3-sympy-0.7.3/sympy/matrices/expressions/determinant.py 2013-07-13 17:53:32.000000000 +0000 @@ -0,0 +1,50 @@ +from sympy import Basic, Expr, S, Q +from .matexpr import ShapeError + + +class Determinant(Expr): + """Matrix Determinant + + Represents the determinant of a matrix expression. + + >>> from sympy import MatrixSymbol, Determinant, eye + >>> A = MatrixSymbol('A', 3, 3) + >>> Determinant(A) + Determinant(A) + + >>> Determinant(eye(3)).doit() + 1 + """ + + def __new__(cls, mat): + if not mat.is_Matrix: + raise TypeError("Input to Determinant, %s, not a matrix" % str(mat)) + + if not mat.is_square: + raise ShapeError("Det of a non-square matrix") + + return Basic.__new__(cls, mat) + + @property + def arg(self): + return self.args[0] + + def doit(self, expand=False): + try: + return self.arg._eval_determinant() + except (AttributeError, NotImplementedError): + return self + +def det(matexpr): + """ Matrix Determinant + + >>> from sympy import MatrixSymbol, det, eye + >>> A = MatrixSymbol('A', 3, 3) + >>> det(A) + Determinant(A) + + >>> det(eye(3)) + 1 + """ + + return Determinant(matexpr).doit() diff -Nru python3-sympy-0.7.2/sympy/matrices/expressions/diagonal.py python3-sympy-0.7.3/sympy/matrices/expressions/diagonal.py --- python3-sympy-0.7.2/sympy/matrices/expressions/diagonal.py 1970-01-01 00:00:00.000000000 +0000 +++ python3-sympy-0.7.3/sympy/matrices/expressions/diagonal.py 2013-07-13 17:53:32.000000000 +0000 @@ -0,0 +1,16 @@ +from sympy.matrices.expressions import MatrixExpr +from sympy.core import S + +class DiagonalMatrix(MatrixExpr): + arg = property(lambda self: self.args[0]) + shape = property(lambda self: (self.arg.shape[0], self.arg.shape[0])) + + def _entry(self, i, j): + return S.Zero if i != j else self.arg[i, 0] + +class DiagonalOf(MatrixExpr): + arg = property(lambda self: self.args[0]) + shape = property(lambda self: (self.arg.shape[0], S.One)) + + def _entry(self, i, j): + return self.arg[i, i] diff -Nru python3-sympy-0.7.2/sympy/matrices/expressions/factorizations.py python3-sympy-0.7.3/sympy/matrices/expressions/factorizations.py --- python3-sympy-0.7.2/sympy/matrices/expressions/factorizations.py 1970-01-01 00:00:00.000000000 +0000 +++ python3-sympy-0.7.3/sympy/matrices/expressions/factorizations.py 2013-07-13 17:53:32.000000000 +0000 @@ -0,0 +1,44 @@ +from sympy.matrices.expressions import MatrixExpr +from sympy import Q + +class Factorization(MatrixExpr): + arg = property(lambda self: self.args[0]) + shape = property(lambda self: self.arg.shape) + +class LofLU(Factorization): + predicates = Q.lower_triangular, +class UofLU(Factorization): + predicates = Q.upper_triangular, + +class LofCholesky(LofLU): pass +class UofCholesky(UofLU): pass + +class QofQR(Factorization): + predicates = Q.orthogonal, +class RofQR(Factorization): + predicates = Q.upper_triangular, + +class EigenVectors(Factorization): + predicates = Q.orthogonal, +class EigenValues(Factorization): + predicates = Q.diagonal, + +class UofSVD(Factorization): + predicates = Q.orthogonal, +class SofSVD(Factorization): + predicates = Q.diagonal, +class VofSVD(Factorization): + predicates = Q.orthogonal, + + +def lu(expr): + return LofLU(expr), UofLU(expr) + +def qr(expr): + return QofQR(expr), RofQR(expr) + +def eig(expr): + return EigenValues(expr), EigenVectors(expr) + +def svd(expr): + return UofSVD(expr), SofSVD(expr), VofSVD(expr) diff -Nru python3-sympy-0.7.2/sympy/matrices/expressions/fourier.py python3-sympy-0.7.3/sympy/matrices/expressions/fourier.py --- python3-sympy-0.7.2/sympy/matrices/expressions/fourier.py 1970-01-01 00:00:00.000000000 +0000 +++ python3-sympy-0.7.3/sympy/matrices/expressions/fourier.py 2013-07-13 17:53:32.000000000 +0000 @@ -0,0 +1,23 @@ +from sympy.matrices.expressions import MatrixExpr +from sympy import S, I, sqrt, exp + +class DFT(MatrixExpr): + """ Discrete Fourier Transform """ + n = property(lambda self: self.args[0]) + shape = property(lambda self: (self.n, self.n)) + + def _entry(self, i, j): + w = exp(-2*S.Pi*I/self.n) + return w**(i*j) / sqrt(self.n) + + def _eval_inverse(self): + return IDFT(self.n) + +class IDFT(DFT): + """ Inverse Discrete Fourier Transform """ + def _entry(self, i, j): + w = exp(-2*S.Pi*I/self.n) + return w**(-i*j) / sqrt(self.n) + + def _eval_inverse(self): + return DFT(self.n) diff -Nru python3-sympy-0.7.2/sympy/matrices/expressions/funcmatrix.py python3-sympy-0.7.3/sympy/matrices/expressions/funcmatrix.py --- python3-sympy-0.7.2/sympy/matrices/expressions/funcmatrix.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/matrices/expressions/funcmatrix.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,6 +1,7 @@ from .matexpr import MatrixExpr from sympy import Basic, sympify + class FunctionMatrix(MatrixExpr): """ Represents a Matrix using a function (Lambda) @@ -11,9 +12,10 @@ >>> i, j = symbols('i,j') >>> X = FunctionMatrix(3, 3, Lambda((i, j), i + j)) >>> Matrix(X) - [0, 1, 2] - [1, 2, 3] - [2, 3, 4] + Matrix([ + [0, 1, 2], + [1, 2, 3], + [2, 3, 4]]) >>> Y = FunctionMatrix(1000, 1000, Lambda((i, j), i + j)) @@ -36,4 +38,8 @@ return self.args[2] def _entry(self, i, j): - return self.lamda(i,j) + return self.lamda(i, j) + + def _eval_trace(self): + from sympy.matrices.expressions.trace import Trace + return Trace._eval_rewrite_as_Sum(Trace(self)).doit() diff -Nru python3-sympy-0.7.2/sympy/matrices/expressions/hadamard.py python3-sympy-0.7.3/sympy/matrices/expressions/hadamard.py --- python3-sympy-0.7.2/sympy/matrices/expressions/hadamard.py 1970-01-01 00:00:00.000000000 +0000 +++ python3-sympy-0.7.3/sympy/matrices/expressions/hadamard.py 2013-07-13 17:53:32.000000000 +0000 @@ -0,0 +1,80 @@ +from sympy.core import Mul, Basic, sympify +from sympy.strategies import unpack, flatten, sort, condition, exhaust, do_one + +from sympy.matrices.expressions.matexpr import MatrixExpr, ShapeError + +def hadamard_product(*matrices): + """ + Return the elementwise (aka Hadamard) product of matrices. + + Examples + -------- + >>> from sympy.matrices import hadamard_product, MatrixSymbol + >>> A = MatrixSymbol('A', 2, 3) + >>> B = MatrixSymbol('B', 2, 3) + >>> hadamard_product(A) + A + >>> hadamard_product(A, B) + A.*B + >>> hadamard_product(A, B)[0, 1] + A[0, 1]*B[0, 1] + """ + if not matrices: + raise TypeError("Empty Hadamard product is undefined") + validate(*matrices) + if len(matrices) == 1: + return matrices[0] + else: + return HadamardProduct(*matrices).doit() + + +class HadamardProduct(MatrixExpr): + """ + Elementwise product of matrix expressions + + This is a symbolic object that simply stores its argument without + evaluating it. To actually compute the product, use the function + ``hadamard_product()``. + + >>> from sympy.matrices import hadamard_product, HadamardProduct, MatrixSymbol + >>> A = MatrixSymbol('A', 5, 5) + >>> B = MatrixSymbol('B', 5, 5) + >>> isinstance(hadamard_product(A, B), HadamardProduct) + True + """ + is_HadamardProduct = True + + def __new__(cls, *args, **kwargs): + args = list(map(sympify, args)) + check = kwargs.get('check' , True) + if check: + validate(*args) + return super(HadamardProduct, cls).__new__(cls, *args) + + @property + def shape(self): + return self.args[0].shape + + def _entry(self, i, j): + return Mul(*[arg._entry(i, j) for arg in self.args]) + + def _eval_transpose(self): + from sympy.matrices.expressions.transpose import transpose + return HadamardProduct(*list(map(transpose, self.args))) + + def doit(self, **ignored): + return canonicalize(self) + +def validate(*args): + if not all(arg.is_Matrix for arg in args): + raise TypeError("Mix of Matrix and Scalar symbols") + A = args[0] + for B in args[1:]: + if A.shape != B.shape: + raise ShapeError("Matrices %s and %s are not aligned" % (A, B)) + +rules = (unpack, + flatten) + +canonicalize = exhaust(condition(lambda x: isinstance(x, HadamardProduct), + do_one(*rules))) diff -Nru python3-sympy-0.7.2/sympy/matrices/expressions/inverse.py python3-sympy-0.7.3/sympy/matrices/expressions/inverse.py --- python3-sympy-0.7.2/sympy/matrices/expressions/inverse.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/matrices/expressions/inverse.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,38 +1,43 @@ -from .matexpr import ShapeError -from .matpow import MatPow +from sympy.core.sympify import _sympify +from sympy.core import S, Basic + +from sympy.matrices.expressions.matexpr import ShapeError +from sympy.matrices.expressions.matpow import MatPow + class Inverse(MatPow): - """Matrix Inverse + """ + The multiplicative inverse of a matrix expression - Represents the Inverse of a matrix expression + This is a symbolic object that simply stores its argument without + evaluating it. To actually compute the inverse, use the ``.inverse()`` + method of matrices. - Use .I as shorthand + Examples + ======== >>> from sympy import MatrixSymbol, Inverse >>> A = MatrixSymbol('A', 3, 3) >>> B = MatrixSymbol('B', 3, 3) >>> Inverse(A) A^-1 - >>> A.I - A^-1 - >>> Inverse(A*B) + >>> A.inverse() == Inverse(A) + True + >>> (A*B).inverse() B^-1*A^-1 + >>> Inverse(A*B) + (A*B)^-1 """ is_Inverse = True + exp = S(-1) - def __new__(cls, mat, **kwargs): - - if not mat.is_Matrix: - return mat**(-1) - + def __new__(cls, mat): + mat = _sympify(mat) + assert mat.is_Matrix if not mat.is_square: - raise ShapeError("Inverse of non-square matrix %s"%mat) - - try: - return mat._eval_inverse(**kwargs) - except (AttributeError, NotImplementedError): - return MatPow.__new__(cls, mat, -1) + raise ShapeError("Inverse of non-square matrix %s" % mat) + return Basic.__new__(cls, mat) @property def arg(self): @@ -44,3 +49,13 @@ def _eval_inverse(self): return self.arg + + def _eval_determinant(self): + from sympy.matrices.expressions.determinant import det + return 1/det(self.arg) + + def doit(self, **hints): + if hints.get('deep', True): + return self.arg.doit(**hints).inverse() + else: + return self.arg.inverse() diff -Nru python3-sympy-0.7.2/sympy/matrices/expressions/matadd.py python3-sympy-0.7.3/sympy/matrices/expressions/matadd.py --- python3-sympy-0.7.2/sympy/matrices/expressions/matadd.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/matrices/expressions/matadd.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,7 +1,11 @@ -from .matexpr import MatrixExpr, ShapeError, matrixify, ZeroMatrix -from sympy import Add, S +from sympy.core import Add, Basic, sympify +from sympy.functions import adjoint +from sympy.matrices.expressions.transpose import transpose +from sympy.strategies import (rm_id, unpack, flatten, sort, condition, debug, + exhaust, do_one, glom) +from sympy.matrices.expressions.matexpr import MatrixExpr, ShapeError, ZeroMatrix -class MatAdd(MatrixExpr, Add): +class MatAdd(MatrixExpr): """A Sum of Matrix Expressions MatAdd inherits from and operates like SymPy Add @@ -13,54 +17,58 @@ >>> MatAdd(A, B, C) A + B + C """ + is_MatAdd = True - def __new__(cls, *args): + def __new__(cls, *args, **kwargs): + check = kwargs.get('check', True) - args = list(map(matrixify, args)) - - args = [arg for arg in args if arg!=0] - - if not all(arg.is_Matrix for arg in args): - raise ValueError("Mix of Matrix and Scalar symbols") - - # Check that the shape of the args is consistent - A = args[0] - for B in args[1:]: - if A.shape != B.shape: - raise ShapeError("Matrices %s and %s are not aligned"%(A,B)) - - expr = Add.__new__(cls, *args) - if expr == S.Zero: - return ZeroMatrix(*args[0].shape) - expr = matrixify(expr) - - if expr.is_Mul: - return MatMul(*expr.args) - - # Clear out Identities - # Any zeros around? - if expr.is_Add and any(M.is_ZeroMatrix for M in expr.args): - newargs = [M for M in expr.args if not M.is_ZeroMatrix] # clear out - if len(newargs)==0: # Did we lose everything? - return ZeroMatrix(*args[0].shape) - if expr.args != newargs: # Removed some 0's but not everything? - return MatAdd(*newargs) # Repeat with simpler expr - - return expr + obj = Basic.__new__(cls, *args) + if check: + validate(*args) + return obj @property def shape(self): return self.args[0].shape def _entry(self, i, j): - return Add(*[arg._entry(i,j) for arg in self.args]) + return Add(*[arg._entry(i, j) for arg in self.args]) def _eval_transpose(self): - from .transpose import Transpose - return MatAdd(*[Transpose(arg) for arg in self.args]) + return MatAdd(*[transpose(arg) for arg in self.args]).doit() + + def _eval_adjoint(self): + return MatAdd(*[adjoint(arg) for arg in self.args]).doit() def _eval_trace(self): from .trace import Trace - return MatAdd(*[Trace(arg) for arg in self.args]) + return MatAdd(*[Trace(arg) for arg in self.args]).doit() + + def doit(self, **ignored): + return canonicalize(self) + +def validate(*args): + if not all(arg.is_Matrix for arg in args): + raise TypeError("Mix of Matrix and Scalar symbols") + A = args[0] + for B in args[1:]: + if A.shape != B.shape: + raise ShapeError("Matrices %s and %s are not aligned"%(A, B)) + +factor_of = lambda arg: arg.as_coeff_mmul()[0] +matrix_of = lambda arg: unpack(arg.as_coeff_mmul()[1]) +def combine(cnt, mat): + from .matmul import MatMul + if cnt == 1: + return mat + else: + return cnt * mat + +rules = (rm_id(lambda x: x == 0 or isinstance(x, ZeroMatrix)), + unpack, + flatten, + glom(matrix_of, factor_of, combine), + sort(str)) -from .matmul import MatMul +canonicalize = exhaust(condition(lambda x: isinstance(x, MatAdd), + do_one(*rules))) diff -Nru python3-sympy-0.7.2/sympy/matrices/expressions/matexpr.py python3-sympy-0.7.3/sympy/matrices/expressions/matexpr.py --- python3-sympy-0.7.2/sympy/matrices/expressions/matexpr.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/matrices/expressions/matexpr.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,10 +1,30 @@ -from sympy import Expr, Symbol, Mul, Add, Pow, expand, sympify, Tuple, Integer -from sympy.core.basic import Basic -from sympy.core.singleton import S -from sympy.core.decorators import _sympifyit, call_highest_priority -from sympy.matrices import ShapeError, Matrix +from functools import wraps -class MatrixExpr(Expr): +from sympy.core import S, Symbol, sympify, Tuple, Integer, Basic, Expr +from sympy.core.decorators import call_highest_priority +from sympy.core.sympify import SympifyError, sympify +from sympy.functions import conjugate, adjoint +from sympy.matrices import ShapeError +from sympy.simplify import simplify + + +def _sympifyit(arg, retval=None): + # This version of _sympifyit sympifies MutableMatrix objects + def deco(func): + @wraps(func) + def __sympifyit_wrapper(a, b): + try: + b = sympify(b, strict=True) + return func(a, b) + except SympifyError: + return retval + + return __sympifyit_wrapper + + return deco + + +class MatrixExpr(Basic): """ Matrix Expression Class Matrix Expressions subclass SymPy Expr's so that MatAdd inherits from Add @@ -25,73 +45,85 @@ is_Inverse = False is_Transpose = False is_ZeroMatrix = False - is_BlockMatrix = False + is_MatAdd = False + is_MatMul = False is_commutative = False # The following is adapted from the core Expr object def __neg__(self): - return MatMul(S.NegativeOne, self) + return MatMul(S.NegativeOne, self).doit() + def __abs__(self): raise NotImplementedError @_sympifyit('other', NotImplemented) @call_highest_priority('__radd__') def __add__(self, other): - return MatAdd(self, other) + return MatAdd(self, other).doit() + @_sympifyit('other', NotImplemented) @call_highest_priority('__add__') def __radd__(self, other): - return MatAdd(other, self) + return MatAdd(other, self).doit() @_sympifyit('other', NotImplemented) @call_highest_priority('__rsub__') def __sub__(self, other): - return MatAdd(self, -other) + return MatAdd(self, -other).doit() + @_sympifyit('other', NotImplemented) @call_highest_priority('__sub__') def __rsub__(self, other): - return MatAdd(other, -self) + return MatAdd(other, -self).doit() @_sympifyit('other', NotImplemented) @call_highest_priority('__rmul__') def __mul__(self, other): - return MatMul(self, other) + return MatMul(self, other).doit() + @_sympifyit('other', NotImplemented) @call_highest_priority('__mul__') def __rmul__(self, other): - return MatMul(other, self) + return MatMul(other, self).doit() @_sympifyit('other', NotImplemented) @call_highest_priority('__rpow__') def __pow__(self, other): - if other == -S.One: + if not self.is_square: + raise ShapeError("Power of non-square matrix %s" % self) + if other is S.NegativeOne: return Inverse(self) + elif other is S.Zero: + return Identity(self.rows) + elif other is S.One: + return self return MatPow(self, other) + @_sympifyit('other', NotImplemented) @call_highest_priority('__pow__') def __rpow__(self, other): raise NotImplementedError("Matrix Power not defined") + @_sympifyit('other', NotImplemented) @call_highest_priority('__rdiv__') def __div__(self, other): - return MatMul(self, other**S.NegativeOne) + return self * other**S.NegativeOne + @_sympifyit('other', NotImplemented) @call_highest_priority('__div__') def __rdiv__(self, other): raise NotImplementedError() #return MatMul(other, Pow(self, S.NegativeOne)) - def __getitem__(self, key): - raise NotImplementedError() - __truediv__ = __div__ __rtruediv__ = __rdiv__ @property def rows(self): return self.shape[0] + @property def cols(self): return self.shape[1] @@ -100,55 +132,69 @@ def is_square(self): return self.rows == self.cols - def _eval_transpose(self): - raise NotImplementedError() + def _eval_conjugate(self): + from sympy.matrices.expressions.adjoint import Adjoint + from sympy.matrices.expressions.transpose import Transpose + return Adjoint(Transpose(self)) def _eval_inverse(self): - raise NotImplementedError() + from sympy.matrices.expressions.inverse import Inverse + return Inverse(self) + + def _eval_transpose(self): + return Transpose(self) + + def _eval_power(self, exp): + return MatPow(self, exp) + + def _eval_simplify(self, **kwargs): + if self.is_Atom: + return self + else: + return self.__class__(*[simplify(x, **kwargs) for x in self.args]) + + def _eval_adjoint(self): + from sympy.matrices.expressions.adjoint import Adjoint + return Adjoint(self) + + def _entry(self, i, j): + raise NotImplementedError( + "Indexing not implemented for %s" % self.__class__.__name__) def adjoint(self): - return MatMul(*[arg.adjoint() for arg in self.args[::-1]]) + return adjoint(self) def conjugate(self): - return MatMul(*[arg.conjugate() for arg in self.args]) + return conjugate(self) def transpose(self): - if isinstance(self, Transpose): - return self.arg + from sympy.matrices.expressions.transpose import transpose + return transpose(self) - if self.is_Mul: - return MatMul(*[Transpose(arg) for arg in self.args[::-1]]) + T = property(transpose, None, None, 'Matrix transposition.') - if self.is_Add: - return MatAdd(*[Transpose(arg) for arg in self.args]) - - try: - return self._eval_transpose() - except (AttributeError, NotImplementedError): - return Basic.__new__(Transpose, self) - - @property - def T(self): - return self.transpose() + def inverse(self): + return self._eval_inverse() @property def I(self): - return Inverse(self) - - def _entry(self, i, j): - raise NotImplementedError("Indexing not implemented") + return self.inverse() def valid_index(self, i, j): def is_valid(idx): - return isinstance(idx, (int, Integer, Symbol)) + return isinstance(idx, (int, Integer, Symbol, Expr)) return (is_valid(i) and is_valid(j) and 0 <= i < self.rows and 0 <= j < self.cols) def __getitem__(self, key): - if isinstance(key, tuple) and len(key)==2: + if not isinstance(key, tuple) and isinstance(key, slice): + from sympy.matrices.expressions.slice import MatrixSlice + return MatrixSlice(self, key, (0, None, 1)) + if isinstance(key, tuple) and len(key) == 2: i, j = key if isinstance(i, slice) or isinstance(j, slice): - raise NotImplementedError("Slicing is not implemented") + from sympy.matrices.expressions.slice import MatrixSlice + return MatrixSlice(self, i, j) i, j = sympify(i), sympify(j) if self.valid_index(i, j) is not False: return self._entry(i, j) @@ -162,42 +208,50 @@ Returns an object of type ImmutableMatrix. + Examples + ======== + >>> from sympy import Identity >>> I = Identity(3) >>> I I >>> I.as_explicit() - [1, 0, 0] - [0, 1, 0] - [0, 0, 1] + Matrix([ + [1, 0, 0], + [0, 1, 0], + [0, 0, 1]]) See Also - -------- - as_mutable: returns MutableMatrix type + ======== + as_mutable: returns mutable Matrix type """ - from sympy.matrices.immutable_matrix import ImmutableMatrix - return ImmutableMatrix([[ self[i,j] + from sympy.matrices.immutable import ImmutableMatrix + return ImmutableMatrix([[ self[i, j] for j in range(self.cols)] for i in range(self.rows)]) def as_mutable(self): """ - Returns a dense Matrix with elements represented explicitly + Returns a dense, mutable matrix with elements represented explicitly - Returns an object of type MutableMatrix. + Examples + ======== >>> from sympy import Identity >>> I = Identity(3) >>> I I + >>> I.shape + (3, 3) >>> I.as_mutable() - [1, 0, 0] - [0, 1, 0] - [0, 0, 1] + Matrix([ + [1, 0, 0], + [0, 1, 0], + [0, 0, 1]]) See Also - -------- + ======== as_explicit: returns ImmutableMatrix """ return self.as_explicit().as_mutable() @@ -221,7 +275,20 @@ """ return self.as_explicit().equals(other) -class MatrixSymbol(MatrixExpr, Symbol): + def canonicalize(self): + return self + + def as_coeff_mmul(self): + return 1, MatMul(self) + + +class MatrixElement(Expr): + parent = property(lambda self: self.args[0]) + i = property(lambda self: self.args[1]) + j = property(lambda self: self.args[2]) + + +class MatrixSymbol(MatrixExpr): """Symbolic representation of a Matrix object Creates a SymPy Symbol to represent a Matrix. This matrix has a shape and @@ -233,7 +300,7 @@ >>> A.shape (3, 4) >>> 2*A*B + Identity(3) - I + 2*A*B + 2*A*B + I """ is_commutative = False @@ -262,16 +329,23 @@ raise TypeError( "%s object is not callable" % self.__class__ ) def _entry(self, i, j): - # MatMul _entry will pass us a Dummy and ask that we remember it - # so that it can be summed over later. We'll use the function syntax - if i.is_Dummy or j.is_Dummy: - return Symbol(self.name)(i,j) - # If that isn't the case we'd really rather just make a symbol - # They are simpler and look much nicer + return MatrixElement(self, i, j) + + @property + def free_symbols(self): + return set((self,)) + + def doit(self, **hints): + if hints.get('deep', True): + return type(self)(self.name, self.args[1].doit(**hints), + self.args[2].doit(**hints)) else: - return Symbol('%s_%s%s'%(self.name, str(i), str(j))) + return self -class Identity(MatrixSymbol): + def _eval_simplify(self, **kwargs): + return self + +class Identity(MatrixExpr): """The Matrix Identity I - multiplicative identity >>> from sympy.matrices import Identity, MatrixSymbol @@ -282,8 +356,21 @@ """ is_Identity = True + def __new__(cls, n): - return MatrixSymbol.__new__(cls, "I", n, n) + return super(Identity, cls).__new__(cls, sympify(n)) + + @property + def rows(self): + return self.args[0] + + @property + def cols(self): + return self.args[0] + + @property + def shape(self): + return (self.args[0], self.args[0]) def _eval_transpose(self): return self @@ -294,13 +381,17 @@ def _eval_inverse(self): return self + def conjugate(self): + return self + def _entry(self, i, j): - if i==j: + if i == j: return S.One else: return S.Zero -class ZeroMatrix(MatrixSymbol): + +class ZeroMatrix(MatrixExpr): """The Matrix Zero 0 - additive identity >>> from sympy import MatrixSymbol, ZeroMatrix @@ -312,8 +403,23 @@ 0 """ is_ZeroMatrix = True - def __new__(cls, n, m): - return MatrixSymbol.__new__(cls, "0", n, m) + + def __new__(cls, m, n): + return super(ZeroMatrix, cls).__new__(cls, m, n) + + @property + def shape(self): + return (self.args[0], self.args[1]) + + + @_sympifyit('other', NotImplemented) + @call_highest_priority('__rpow__') + def __pow__(self, other): + if other != 1 and not self.is_square: + raise ShapeError("Power of non-square matrix %s" % self) + if other == 0: + return Identity(self.rows) + return self def _eval_transpose(self): return ZeroMatrix(self.cols, self.rows) @@ -321,106 +427,18 @@ def _eval_trace(self): return S.Zero + def conjugate(self): + return self + def _entry(self, i, j): return S.Zero -def matrix_symbols(expr): - return [sym for sym in expr.free_symbols if sym.is_Matrix] - -def matrixify(expr): - """ - Recursively walks down an expression tree changing Expr's to MatExpr's - i.e. Add -> MatAdd - Mul -> MatMul + def __bool__(self): + return False - Only changes those Exprs which contain MatrixSymbols - This function is useful when traditional SymPy functions which use Mul and - Add are called on MatrixExpressions. Examples flatten, expand, simplify... - - Calling matrixify after calling these functions will reset classes back to - their matrix equivalents - """ - class_dict = {Mul:MatMul, Add:MatAdd, MatMul:MatMul, MatAdd:MatAdd, - Pow:MatPow, MatPow:MatPow} - - if expr.__class__ not in class_dict: - return expr - - args = list(map(matrixify, expr.args)) # Recursively call down the tree - - if not any(arg.is_Matrix for arg in args): - return expr - else: - return Basic.__new__(class_dict[expr.__class__], *args) - -def linear_factors(expr, *syms): - """Reduce a Matrix Expression to a sum of linear factors - - Given symbols and a matrix expression linear in those symbols return a - dict mapping symbol to the linear factor - - >>> from sympy import MatrixSymbol, linear_factors, symbols - >>> n, m, l = symbols('n m l') - >>> A = MatrixSymbol('A', n, m) - >>> B = MatrixSymbol('B', m, l) - >>> C = MatrixSymbol('C', n, l) - >>> linear_factors(2*A*B + C, B, C) - {B: 2*A, C: I} - """ - - expr = matrixify(expand(expr)) - d = {} - if expr.is_Matrix and expr.is_Symbol: - if expr in syms: - d[expr] = Identity(expr.rows) - - if expr.is_Add: - for sym in syms: - total_factor = 0 - for arg in expr.args: - factor = arg.coeff(sym) - if not factor: - # .coeff fails when powers are in the expression - if sym in arg.free_symbols: - raise ValueError("Expression not linear in symbols") - else: - factor = 0 - factor = sympify(factor) - if not factor.is_Matrix: - if factor.is_zero: - factor = ZeroMatrix(expr.rows, sym.rows) - if not sym.cols == expr.cols: - raise ShapeError( - "%s not compatible as factor of %s"%(sym, expr)) - else: - factor = Identity(sym.rows)*factor - total_factor += factor - d[sym] = total_factor - elif expr.is_Mul: - for sym in syms: - factor = expr.coeff(sym) - if not factor: - # .coeff fails when powers are in the expression - if sym in expr.free_symbols: - raise ValueError("Expression not linear in symbols") - else: - factor = 0 - factor = sympify(factor) - if not factor.is_Matrix: - if factor.is_zero: - factor = ZeroMatrix(expr.rows, sym.rows) - if not sym.cols == expr.cols: - raise ShapeError("%s not compatible as factor of %s"% - (sym, expr)) - else: - factor = Identity(sym.rows)*factor - d[sym] = factor - - if any(sym in matrix_symbols(Tuple(*list(d.values()))) for sym in syms): - raise ValueError("Expression not linear in symbols") - - return d +def matrix_symbols(expr): + return [sym for sym in expr.free_symbols if sym.is_Matrix] from .matmul import MatMul from .matadd import MatAdd diff -Nru python3-sympy-0.7.2/sympy/matrices/expressions/matmul.py python3-sympy-0.7.3/sympy/matrices/expressions/matmul.py --- python3-sympy-0.7.2/sympy/matrices/expressions/matmul.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/matrices/expressions/matmul.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,10 +1,18 @@ -from .matexpr import MatrixExpr, ShapeError, matrixify, Identity, ZeroMatrix -from sympy.core import Mul, Add, Basic +from sympy.core import Mul, Basic, sympify, Add +from sympy.functions import transpose, adjoint +from sympy.matrices.expressions.transpose import transpose +from sympy.strategies import (rm_id, unpack, typed, debug, flatten, exhaust, + do_one, new) +from sympy.matrices.expressions.matexpr import (MatrixExpr, ShapeError, + Identity, ZeroMatrix) -class MatMul(MatrixExpr, Mul): - """A Product of Matrix Expressions - MatMul inherits from and operates like SymPy Mul +class MatMul(MatrixExpr): + """ + A product of matrix expressions + + Examples + ======== >>> from sympy import MatMul, MatrixSymbol >>> A = MatrixSymbol('A', 5, 4) @@ -13,96 +21,166 @@ >>> MatMul(A, B, C) A*B*C """ + is_MatMul = True - def __new__(cls, *args): - - # Check that the shape of the args is consistent - matrices = [arg for arg in args if arg.is_Matrix] - - for i in range(len(matrices)-1): - A,B = matrices[i:i+2] - if A.cols != B.rows: - raise ShapeError("Matrices %s and %s are not aligned"%(A, B)) - - if any(arg.is_zero for arg in args): - return ZeroMatrix(matrices[0].rows, matrices[-1].cols) - - expr = matrixify(Mul.__new__(cls, *args)) - if expr.is_Add: - return MatAdd(*expr.args) - if expr.is_Pow: - assert expr.exp.is_Integer - expr = Basic.__new__(MatMul, *[expr.base for i in range(expr.exp)]) - if not expr.is_Mul: - return expr - - if any(arg.is_Matrix and arg.is_ZeroMatrix for arg in expr.args): - return ZeroMatrix(*expr.shape) - - # Clear out Identities - nonmats = [M for M in expr.args if not M.is_Matrix] # scalars - mats = [M for M in expr.args if M.is_Matrix] # matrices - if any(M.is_Identity for M in mats): # Any identities around? - newmats = [M for M in mats if not M.is_Identity] # clear out - if len(newmats)==0: # Did we lose everything? - newmats = [Identity(expr.rows)] # put just one back in + def __new__(cls, *args, **kwargs): + check = kwargs.get('check', True) - if mats != newmats: # Removed some I's but not everything? - return MatMul(*(nonmats+newmats)) # Repeat with simpler expr - - return expr + args = list(map(sympify, args)) + obj = Basic.__new__(cls, *args) + factor, matrices = obj.as_coeff_matrices() + if check: + validate(*matrices) + return obj @property def shape(self): matrices = [arg for arg in self.args if arg.is_Matrix] return (matrices[0].rows, matrices[-1].cols) - def _entry(self, i, j): - coeff, matmul = self.as_coeff_mmul() - if not matmul.is_Mul: # situation like 2*X, matmul is just X - return coeff * matmul[i,j] + def _entry(self, i, j, expand=True): + coeff, matrices = self.as_coeff_matrices() + + if len(matrices) == 1: # situation like 2*X, matmul is just X + return coeff * matrices[0][i, j] - head, tail = matmul.args[0], matmul.args[1:] + head, tail = matrices[0], matrices[1:] assert len(tail) != 0 X = head Y = MatMul(*tail) - if X.shape[1].is_Number: - # Numeric shape like (3,5) - return coeff*Add(*[X[i,k]*Y[k,j] for k in range(X.shape[1])]) - else: - # Symbolic shape like (n, m) - from sympy import Dummy, summation - k = Dummy('k', integer=True) - return summation(coeff*X[i,k]*Y[k,j], (k, 0, X.cols-1)) + from sympy.core.symbol import Dummy + from sympy.concrete.summations import Sum + from sympy.matrices import ImmutableMatrix, MatrixBase + k = Dummy('k', integer=True) + if X.has(ImmutableMatrix) or Y.has(ImmutableMatrix): + return coeff*Add(*[X[i, k]*Y[k, j] for k in range(X.cols)]) + result = Sum(coeff*X[i, k]*Y[k, j], (k, 0, X.cols - 1)) + return result.doit() if expand else result - def as_coeff_mmul(self): + def as_coeff_matrices(self): scalars = [x for x in self.args if not x.is_Matrix] matrices = [x for x in self.args if x.is_Matrix] coeff = Mul(*scalars) + return coeff, matrices + + def as_coeff_mmul(self): + coeff, matrices = self.as_coeff_matrices() return coeff, MatMul(*matrices) def _eval_transpose(self): - from .transpose import Transpose - return MatMul(*[Transpose(arg) for arg in self.args[::-1]]) + return MatMul(*[transpose(arg) for arg in self.args[::-1]]).doit() + + def _eval_adjoint(self): + return MatMul(*[adjoint(arg) for arg in self.args[::-1]]).doit() def _eval_trace(self): - factor = Mul(*[arg for arg in self.args if not arg.is_Matrix]) - matrix = MatMul(*[arg for arg in self.args if arg.is_Matrix]) + factor, mmul = self.as_coeff_mmul() if factor != 1: from .trace import Trace - return factor * Trace(matrix) + return factor * Trace(mmul) else: raise NotImplementedError("Can't simplify any further") + def _eval_determinant(self): + from sympy.matrices.expressions.determinant import Determinant + factor, matrices = self.as_coeff_matrices() + square_matrices = only_squares(*matrices) + return factor**self.rows * Mul(*list(map(Determinant, square_matrices))) + def _eval_inverse(self): - from .inverse import Inverse try: - return MatMul(*[Inverse(arg) for arg in self.args[::-1]]) + return MatMul(*[ + arg.inverse() if isinstance(arg, MatrixExpr) else arg**-1 + for arg in self.args[::-1]]).doit() except ShapeError: - raise NotImplementedError("Can not decompose this Inverse") + from sympy.matrices.expressions.inverse import Inverse + return Inverse(self) + def doit(self, **kwargs): + deep = kwargs.get('deep', False) + if deep: + args = [arg.doit(**kwargs) for arg in self.args] + else: + args = self.args + return canonicalize(MatMul(*args)) -from .matadd import MatAdd +def validate(*matrices): + """ Checks for valid shapes for args of MatMul """ + for i in range(len(matrices)-1): + A, B = matrices[i:i+2] + if A.cols != B.rows: + raise ShapeError("Matrices %s and %s are not aligned"%(A, B)) + +# Rules + + +def newmul(*args): + if args[0] == 1: + args = args[1:] + return new(MatMul, *args) + +def any_zeros(mul): + if any([arg.is_zero or (arg.is_Matrix and arg.is_ZeroMatrix) + for arg in mul.args]): + matrices = [arg for arg in mul.args if arg.is_Matrix] + return ZeroMatrix(matrices[0].rows, matrices[-1].cols) + return mul + +def xxinv(mul): + """ Y * X * X.I -> Y """ + from sympy.matrices.expressions import Inverse + factor, matrices = mul.as_coeff_matrices() + for i, (X, Y) in enumerate(list(zip(matrices[:-1], matrices[1:]))): + try: + if X.is_square and Y.is_square and X == Y.inverse(): + I = Identity(X.rows) + return newmul(factor, *(matrices[:i] + [I] + matrices[i+2:])) + except ValueError: # Y might not be invertible + pass + + return mul + +def remove_ids(mul): + """ Remove Identities from a MatMul + + This is a modified version of sympy.strategies.rm_id. + This is necesssary because MatMul may contain both MatrixExprs and Exprs + as args. + + See Also + -------- + sympy.strategies.rm_id + """ + # Separate Exprs from MatrixExprs in args + factor, mmul = mul.as_coeff_mmul() + # Apply standard rm_id for MatMuls + result = rm_id(lambda x: x.is_Identity is True)(mmul) + if result != mmul: + return newmul(factor, *result.args) # Recombine and return + else: + return mul + +def factor_in_front(mul): + factor, matrices = mul.as_coeff_matrices() + if factor != 1: + return newmul(factor, *matrices) + return mul + +rules = (any_zeros, remove_ids, xxinv, unpack, rm_id(lambda x: x == 1), + factor_in_front, flatten) + +canonicalize = exhaust(typed({MatMul: do_one(*rules)})) + +def only_squares(*matrices): + """ factor matrices only if they are square """ + assert matrices[0].rows == matrices[-1].cols + out = [] + start = 0 + for i, M in enumerate(matrices): + if M.cols == matrices[start].rows: + out.append(MatMul(*matrices[start:i+1]).doit()) + start = i+1 + return out diff -Nru python3-sympy-0.7.2/sympy/matrices/expressions/matpow.py python3-sympy-0.7.3/sympy/matrices/expressions/matpow.py --- python3-sympy-0.7.2/sympy/matrices/expressions/matpow.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/matrices/expressions/matpow.py 2013-07-13 17:53:32.000000000 +0000 @@ -2,19 +2,22 @@ from sympy import Pow, S, Basic from sympy.core.sympify import _sympify -class MatPow(MatrixExpr, Pow): - def __new__(cls, b, e): - assert b.is_Matrix - e = _sympify(e) - if e is S.One or b.is_ZeroMatrix: - return b - elif not b.is_square: - raise ShapeError("Power of non-square matrix %s"%b) - elif e is S.Zero: - return Identity(b.rows) - else: - return MatrixExpr.__new__(cls, b, e) +class MatPow(MatrixExpr): + + def __new__(cls, base, exp): + base = _sympify(base) + assert base.is_Matrix + exp = _sympify(exp) + return super(MatPow, cls).__new__(cls, base, exp) + + @property + def base(self): + return self.args[0] + + @property + def exp(self): + return self.args[1] @property def shape(self): @@ -23,7 +26,6 @@ def _entry(self, i, j): if self.exp.is_Integer: # Make an explicity MatMul out of the MatPow - return Basic.__new__(MatMul, - *[self.base for k in range(self.exp)])._entry(i, j) + return MatMul(*[self.base for k in range(self.exp)])._entry(i, j) from .matmul import MatMul diff -Nru python3-sympy-0.7.2/sympy/matrices/expressions/slice.py python3-sympy-0.7.3/sympy/matrices/expressions/slice.py --- python3-sympy-0.7.2/sympy/matrices/expressions/slice.py 1970-01-01 00:00:00.000000000 +0000 +++ python3-sympy-0.7.3/sympy/matrices/expressions/slice.py 2013-07-13 17:53:32.000000000 +0000 @@ -0,0 +1,112 @@ +from sympy.matrices.expressions.matexpr import MatrixExpr +from sympy import Tuple, Basic +from sympy.functions.elementary.integers import floor +from sympy.assumptions import Q, ask + +def normalize(i, parentsize): + if isinstance(i, slice): + i = (i.start, i.stop, i.step) + if not isinstance(i, (tuple, list, Tuple)): + if i < 0: + i += parentsize + i = (i, i+1, 1) + i = list(i) + if len(i) == 2: + i.append(1) + start, stop, step = i + start = start or 0 + if stop == None: + stop = parentsize + if start < 0: + start += parentsize + if stop < 0: + stop += parentsize + step = step or 1 + + if (stop - start) * step < 1: + raise IndexError() + + return (start, stop, step) + +class MatrixSlice(MatrixExpr): + """ A MatrixSlice of a Matrix Expression + + Examples + + >>> from sympy import MatrixSlice, ImmutableMatrix + >>> M = ImmutableMatrix(4, 4, list(range(16))) + >>> print(M) + Matrix([ + [ 0, 1, 2, 3], + [ 4, 5, 6, 7], + [ 8, 9, 10, 11], + [12, 13, 14, 15]]) + + >>> B = MatrixSlice(M, (0, 2), (2, 4)) + >>> print(ImmutableMatrix(B)) + Matrix([ + [2, 3], + [6, 7]]) + """ + parent = property(lambda self: self.args[0]) + rowslice = property(lambda self: self.args[1]) + colslice = property(lambda self: self.args[2]) + + def __new__(cls, parent, rowslice, colslice): + rowslice = normalize(rowslice, parent.shape[0]) + colslice = normalize(colslice, parent.shape[1]) + if not (len(rowslice) == len(colslice) == 3): + raise IndexError() + if ((0 > rowslice[0]) == True or + (parent.shape[0] < rowslice[1]) == True or + (0 > colslice[0]) == True or + (parent.shape[1] < colslice[1]) == True): + raise IndexError() + if isinstance(parent, MatrixSlice): + return mat_slice_of_slice(parent, rowslice, colslice) + return Basic.__new__(cls, parent, Tuple(*rowslice), Tuple(*colslice)) + + @property + def shape(self): + rows = self.rowslice[1] - self.rowslice[0] + rows = rows if self.rowslice[2] == 1 else floor(rows/self.rowslice[2]) + cols = self.colslice[1] - self.colslice[0] + cols = cols if self.colslice[2] == 1 else floor(cols/self.colslice[2]) + return rows, cols + + def _entry(self, i, j): + return self.parent._entry(i*self.rowslice[2] + self.rowslice[0], + j*self.colslice[2] + self.colslice[0]) + + @property + def on_diag(self): + return self.rowslice == self.colslice + + +def slice_of_slice(s, t): + start1, stop1, step1 = s + start2, stop2, step2 = t + + start = start1 + start2*step1 + step = step1 * step2 + stop = start1 + step1*stop2 + + if stop > stop1: + raise IndexError() + + return start, stop, step + + +def mat_slice_of_slice(parent, rowslice, colslice): + """ Collapse nested matrix slices + + >>> from sympy import MatrixSymbol + >>> X = MatrixSymbol('X', 10, 10) + >>> X[:, 1:5][5:8, :] + X[5:8, 1:5] + >>> X[1:9:2, 2:6][1:3, 2] + X[3:7:2, 4] + """ + row = slice_of_slice(parent.rowslice, rowslice) + col = slice_of_slice(parent.colslice, colslice) + return MatrixSlice(parent.parent, row, col) diff -Nru python3-sympy-0.7.2/sympy/matrices/expressions/tests/test_adjoint.py python3-sympy-0.7.3/sympy/matrices/expressions/tests/test_adjoint.py --- python3-sympy-0.7.2/sympy/matrices/expressions/tests/test_adjoint.py 1970-01-01 00:00:00.000000000 +0000 +++ python3-sympy-0.7.3/sympy/matrices/expressions/tests/test_adjoint.py 2013-07-13 17:53:32.000000000 +0000 @@ -0,0 +1,34 @@ +from sympy.core import symbols, S +from sympy.functions import adjoint, conjugate, transpose +from sympy.matrices.expressions import MatrixSymbol, Adjoint, trace, Transpose +from sympy.matrices import eye, Matrix + +n, m, l, k, p = symbols('n m l k p', integer=True) +A = MatrixSymbol('A', n, m) +B = MatrixSymbol('B', m, l) +C = MatrixSymbol('C', n, n) + + +def test_adjoint(): + Sq = MatrixSymbol('Sq', n, n) + + assert Adjoint(A).shape == (m, n) + assert Adjoint(A*B).shape == (l, n) + assert adjoint(Adjoint(A)) == A + assert isinstance(Adjoint(Adjoint(A)), Adjoint) + + assert conjugate(Adjoint(A)) == Transpose(A) + assert transpose(Adjoint(A)) == Adjoint(Transpose(A)) + + assert Adjoint(eye(3)).doit() == eye(3) + + assert Adjoint(S(5)).doit() == S(5) + + assert Adjoint(Matrix([[1, 2], [3, 4]])).doit() == Matrix([[1, 3], [2, 4]]) + + assert adjoint(trace(Sq)) == conjugate(trace(Sq)) + assert trace(adjoint(Sq)) == conjugate(trace(Sq)) + + assert Adjoint(Sq)[0, 1] == conjugate(Sq[1, 0]) + + assert Adjoint(A*B).doit() == Adjoint(B) * Adjoint(A) diff -Nru python3-sympy-0.7.2/sympy/matrices/expressions/tests/test_blockmatrix.py python3-sympy-0.7.3/sympy/matrices/expressions/tests/test_blockmatrix.py --- python3-sympy-0.7.2/sympy/matrices/expressions/tests/test_blockmatrix.py 1970-01-01 00:00:00.000000000 +0000 +++ python3-sympy-0.7.3/sympy/matrices/expressions/tests/test_blockmatrix.py 2013-07-13 17:53:32.000000000 +0000 @@ -0,0 +1,205 @@ + +from sympy.matrices.expressions.blockmatrix import (block_collapse, bc_matmul, + bc_block_plus_ident, BlockDiagMatrix, BlockMatrix, bc_dist, bc_matadd, + bc_transpose, blockcut, reblock_2x2, deblock) +from sympy.matrices.expressions import (MatrixSymbol, Identity, MatMul, + Inverse, trace, Transpose, det) +from sympy.matrices import Matrix, ImmutableMatrix +from sympy.core import Tuple, symbols, Expr +from sympy.functions import transpose + +i, j, k, l, m, n, p = symbols('i:n, p', integer=True) +A = MatrixSymbol('A', n, n) +B = MatrixSymbol('B', n, n) +C = MatrixSymbol('C', n, n) +D = MatrixSymbol('D', n, n) +G = MatrixSymbol('G', n, n) +H = MatrixSymbol('H', n, n) +b1 = BlockMatrix([[G, H]]) +b2 = BlockMatrix([[G], [H]]) + +def test_bc_matmul(): + assert bc_matmul(H*b1*b2*G) == BlockMatrix([[(H*G*G + H*H*H)*G]]) + +def test_bc_matadd(): + assert bc_matadd(BlockMatrix([[G, H]]) + BlockMatrix([[H, H]])) == \ + BlockMatrix([[G+H, H+H]]) + +def test_bc_transpose(): + assert bc_transpose(Transpose(BlockMatrix([[A, B], [C, D]]))) == \ + BlockMatrix([[A.T, C.T], [B.T, D.T]]) + +def test_bc_dist_diag(): + A = MatrixSymbol('A', n, n) + B = MatrixSymbol('B', m, m) + C = MatrixSymbol('C', l, l) + X = BlockDiagMatrix(A, B, C) + + assert bc_dist(X+X).equals(BlockDiagMatrix(2*A, 2*B, 2*C)) + +def test_block_plus_ident(): + A = MatrixSymbol('A', n, n) + B = MatrixSymbol('B', n, m) + C = MatrixSymbol('C', m, n) + D = MatrixSymbol('D', m, m) + X = BlockMatrix([[A, B], [C, D]]) + assert bc_block_plus_ident(X+Identity(m+n)) == \ + BlockDiagMatrix(Identity(n), Identity(m)) + X + +def test_BlockMatrix(): + A = MatrixSymbol('A', n, m) + B = MatrixSymbol('B', n, k) + C = MatrixSymbol('C', l, m) + D = MatrixSymbol('D', l, k) + M = MatrixSymbol('M', m + k, p) + N = MatrixSymbol('N', l + n, k + m) + X = BlockMatrix(Matrix([[A, B], [C, D]])) + + assert X.__class__(*X.args) == X + + # block_collapse does nothing on normal inputs + E = MatrixSymbol('E', n, m) + assert block_collapse(A + 2*E) == A + 2*E + F = MatrixSymbol('F', m, m) + assert block_collapse(E.T*A*F) == E.T*A*F + + assert X.shape == (l + n, k + m) + assert X.blockshape == (2, 2) + assert transpose(X) == BlockMatrix(Matrix([[A.T, C.T], [B.T, D.T]])) + assert transpose(X).shape == X.shape[::-1] + + # Test that BlockMatrices and MatrixSymbols can still mix + assert (X*M).is_MatMul + assert X._blockmul(M).is_MatMul + assert (X*M).shape == (n + l, p) + assert (X + N).is_MatAdd + assert X._blockadd(N).is_MatAdd + assert (X + N).shape == X.shape + + E = MatrixSymbol('E', m, 1) + F = MatrixSymbol('F', k, 1) + + Y = BlockMatrix(Matrix([[E], [F]])) + + assert (X*Y).shape == (l + n, 1) + assert block_collapse(X*Y).blocks[0, 0] == A*E + B*F + assert block_collapse(X*Y).blocks[1, 0] == C*E + D*F + + # block_collapse passes down into container objects, transposes, and inverse + assert block_collapse(transpose(X*Y)) == transpose(block_collapse(X*Y)) + assert block_collapse(Tuple(X*Y, 2*X)) == ( + block_collapse(X*Y), block_collapse(2*X)) + + # Make sure that MatrixSymbols will enter 1x1 BlockMatrix if it simplifies + Ab = BlockMatrix([[A]]) + Z = MatrixSymbol('Z', *A.shape) + assert block_collapse(Ab + Z) == A + Z + + +def test_BlockMatrix_trace(): + A, B, C, D = [MatrixSymbol(s, 3, 3) for s in 'ABCD'] + X = BlockMatrix([[A, B], [C, D]]) + assert trace(X) == trace(A) + trace(D) + +def test_BlockMatrix_Determinant(): + A, B, C, D = [MatrixSymbol(s, 3, 3) for s in 'ABCD'] + X = BlockMatrix([[A, B], [C, D]]) + from sympy import assuming, Q + with assuming(Q.invertible(A)): + assert det(X) == det(A) * det(D - C*A.I*B) + + assert isinstance(det(X), Expr) + +def test_squareBlockMatrix(): + A = MatrixSymbol('A', n, n) + B = MatrixSymbol('B', n, m) + C = MatrixSymbol('C', m, n) + D = MatrixSymbol('D', m, m) + X = BlockMatrix([[A, B], [C, D]]) + Y = BlockMatrix([[A]]) + + assert X.is_square + + assert (block_collapse(X + Identity(m + n)) == + BlockMatrix([[A + Identity(n), B], [C, D + Identity(m)]])) + Q = X + Identity(m + n) + + assert (X + MatrixSymbol('Q', n + m, n + m)).is_MatAdd + assert (X * MatrixSymbol('Q', n + m, n + m)).is_MatMul + + assert block_collapse(Y.I) == A.I + assert block_collapse(X.inverse()) == BlockMatrix([ + [(-B*D.I*C + A).I, -A.I*B*(D + -C*A.I*B).I], + [-(D - C*A.I*B).I*C*A.I, (D - C*A.I*B).I]]) + + assert isinstance(X.inverse(), Inverse) + + assert not X.is_Identity + + Z = BlockMatrix([[Identity(n), B], [C, D]]) + assert not Z.is_Identity + + +def test_BlockDiagMatrix(): + A = MatrixSymbol('A', n, n) + B = MatrixSymbol('B', m, m) + C = MatrixSymbol('C', l, l) + M = MatrixSymbol('M', n + m + l, n + m + l) + + X = BlockDiagMatrix(A, B, C) + Y = BlockDiagMatrix(A, 2*B, 3*C) + + assert X.blocks[1, 1] == B + assert X.shape == (n + m + l, n + m + l) + assert all(X.blocks[i, j].is_ZeroMatrix if i != j else X.blocks[i, j] in [A, B, C] + for i in range(3) for j in range(3)) + assert X.__class__(*X.args) == X + + assert isinstance(block_collapse(X.I * X), Identity) + + assert bc_matmul(X*X) == BlockDiagMatrix(A*A, B*B, C*C) + assert block_collapse(X*X) == BlockDiagMatrix(A*A, B*B, C*C) + #XXX: should be == ?? + assert block_collapse(X + X).equals(BlockDiagMatrix(2*A, 2*B, 2*C)) + assert block_collapse(X*Y) == BlockDiagMatrix(A*A, 2*B*B, 3*C*C) + assert block_collapse(X + Y) == BlockDiagMatrix(2*A, 3*B, 4*C) + + # Ensure that BlockDiagMatrices can still interact with normal MatrixExprs + assert (X*(2*M)).is_MatMul + assert (X + (2*M)).is_MatAdd + + assert (X._blockmul(M)).is_MatMul + assert (X._blockadd(M)).is_MatAdd + +def test_blockcut(): + A = MatrixSymbol('A', n, m) + B = blockcut(A, (n/2, n/2), (m/2, m/2)) + assert A[i, j] == B[i, j] + assert B == BlockMatrix([[A[:n/2, :m/2], A[:n/2, m/2:]], + [A[n/2:, :m/2], A[n/2:, m/2:]]]) + + M = ImmutableMatrix(4, 4, list(range(16))) + B = blockcut(M, (2, 2), (2, 2)) + assert M == ImmutableMatrix(B) + + B = blockcut(M, (1, 3), (2, 2)) + assert ImmutableMatrix(B.blocks[0, 1]) == ImmutableMatrix([[2, 3]]) + +def test_reblock_2x2(): + B = BlockMatrix([[MatrixSymbol('A_%d%d'%(i,j), 2, 2) + for j in range(3)] + for i in range(3)]) + assert B.blocks.shape == (3, 3) + + BB = reblock_2x2(B) + assert BB.blocks.shape == (2, 2) + + assert B.shape == BB.shape + assert B.as_explicit() == BB.as_explicit() + +def test_deblock(): + B = BlockMatrix([[MatrixSymbol('A_%d%d'%(i,j), n, n) + for j in range(4)] + for i in range(4)]) + + assert deblock(reblock_2x2(B)) == B diff -Nru python3-sympy-0.7.2/sympy/matrices/expressions/tests/test_determinant.py python3-sympy-0.7.3/sympy/matrices/expressions/tests/test_determinant.py --- python3-sympy-0.7.2/sympy/matrices/expressions/tests/test_determinant.py 1970-01-01 00:00:00.000000000 +0000 +++ python3-sympy-0.7.3/sympy/matrices/expressions/tests/test_determinant.py 2013-07-13 17:53:32.000000000 +0000 @@ -0,0 +1,26 @@ +from sympy.core import Lambda, S, symbols +from sympy.functions import adjoint, conjugate, transpose +from sympy.matrices import eye, Matrix, ShapeError +from sympy.matrices.expressions import ( + Adjoint, Identity, FunctionMatrix, MatrixExpr, MatrixSymbol, Determinant, + det, ZeroMatrix +) +from sympy.utilities.pytest import raises + +n = symbols('n', integer=True) +A = MatrixSymbol('A', n, n) +B = MatrixSymbol('B', n, n) +C = MatrixSymbol('C', 3, 4) + + +def test_det(): + assert isinstance(Determinant(A), Determinant) + assert not isinstance(Determinant(A), MatrixExpr) + raises(ShapeError, lambda: Determinant(C)) + assert det(eye(3)) == 1 + assert det(Matrix(3, 3, [1, 3, 2, 4, 1, 3, 2, 5, 2])) == 17 + A / det(A) # Make sure this is possible + + raises(TypeError, lambda: Determinant(S.One)) + + assert Determinant(A).arg is A diff -Nru python3-sympy-0.7.2/sympy/matrices/expressions/tests/test_diagonal.py python3-sympy-0.7.3/sympy/matrices/expressions/tests/test_diagonal.py --- python3-sympy-0.7.2/sympy/matrices/expressions/tests/test_diagonal.py 1970-01-01 00:00:00.000000000 +0000 +++ python3-sympy-0.7.3/sympy/matrices/expressions/tests/test_diagonal.py 2013-07-13 17:53:32.000000000 +0000 @@ -0,0 +1,21 @@ +from sympy.matrices.expressions import MatrixSymbol +from sympy.matrices.expressions.diagonal import DiagonalMatrix, DiagonalOf +from sympy import Symbol, ask, Q + +n = Symbol('n') +x = MatrixSymbol('x', n, 1) +X = MatrixSymbol('X', n, n) +D = DiagonalMatrix(x) +d = DiagonalOf(X) + +def test_DiagonalMatrix(): + assert D.shape == (n, n) + assert D[1, 2] == 0 + assert D[1, 1] == x[1, 0] + +def test_DiagonalMatrix_Assumptions(): + assert ask(Q.diagonal(D)) + +def test_DiagonalOf(): + assert d.shape == (n, 1) + assert d[2, 0] == X[2, 2] diff -Nru python3-sympy-0.7.2/sympy/matrices/expressions/tests/test_factorizations.py python3-sympy-0.7.3/sympy/matrices/expressions/tests/test_factorizations.py --- python3-sympy-0.7.2/sympy/matrices/expressions/tests/test_factorizations.py 1970-01-01 00:00:00.000000000 +0000 +++ python3-sympy-0.7.3/sympy/matrices/expressions/tests/test_factorizations.py 2013-07-13 17:53:32.000000000 +0000 @@ -0,0 +1,27 @@ +from sympy.matrices.expressions.factorizations import lu, LofCholesky, qr, svd +from sympy import Symbol, MatrixSymbol, ask, Q + +n = Symbol('n') +X = MatrixSymbol('X', n, n) + +def test_LU(): + L, U = lu(X) + assert L.shape == U.shape == X.shape + assert ask(Q.lower_triangular(L)) + assert ask(Q.upper_triangular(U)) + +def test_Cholesky(): + L = LofCholesky(X) + +def test_QR(): + Q_, R = qr(X) + assert Q_.shape == R.shape == X.shape + assert ask(Q.orthogonal(Q_)) + assert ask(Q.upper_triangular(R)) + +def test_svd(): + U, S, V = svd(X) + assert U.shape == S.shape == V.shape == X.shape + assert ask(Q.orthogonal(U)) + assert ask(Q.orthogonal(V)) + assert ask(Q.diagonal(S)) diff -Nru python3-sympy-0.7.2/sympy/matrices/expressions/tests/test_fourier.py python3-sympy-0.7.3/sympy/matrices/expressions/tests/test_fourier.py --- python3-sympy-0.7.2/sympy/matrices/expressions/tests/test_fourier.py 1970-01-01 00:00:00.000000000 +0000 +++ python3-sympy-0.7.3/sympy/matrices/expressions/tests/test_fourier.py 2013-07-13 17:53:32.000000000 +0000 @@ -0,0 +1,10 @@ +from sympy import S, I, ask, Q, Abs, simplify, exp, sqrt +from sympy.matrices.expressions.fourier import DFT, IDFT +from sympy.matrices import det, Matrix, Identity +from sympy.abc import n, i, j +def test_dft(): + assert DFT(4).shape == (4, 4) + assert ask(Q.unitary(DFT(4))) + assert Abs(simplify(det(Matrix(DFT(4))))) == 1 + assert DFT(n)*IDFT(n) == Identity(n) + assert DFT(n)[i, j] == exp(-2*S.Pi*I/n)**(i*j) / sqrt(n) diff -Nru python3-sympy-0.7.2/sympy/matrices/expressions/tests/test_funcmatrix.py python3-sympy-0.7.3/sympy/matrices/expressions/tests/test_funcmatrix.py --- python3-sympy-0.7.2/sympy/matrices/expressions/tests/test_funcmatrix.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/matrices/expressions/tests/test_funcmatrix.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,12 +1,12 @@ from sympy import (symbols, FunctionMatrix, MatrixExpr, Lambda, Matrix) -from sympy.utilities.pytest import raises, XFAIL + def test_funcmatrix(): - i,j = symbols('i,j') - X = FunctionMatrix(3,3, Lambda((i,j), i-j)) - assert X[1,1] == 0 - assert X[1,2] == -1 - assert X.shape == (3,3) + i, j = symbols('i,j') + X = FunctionMatrix(3, 3, Lambda((i, j), i - j)) + assert X[1, 1] == 0 + assert X[1, 2] == -1 + assert X.shape == (3, 3) assert X.rows == X.cols == 3 - assert Matrix(X) == Matrix(3, 3, lambda i,j : i-j) - assert isinstance(X*X+X, MatrixExpr) + assert Matrix(X) == Matrix(3, 3, lambda i, j: i - j) + assert isinstance(X*X + X, MatrixExpr) diff -Nru python3-sympy-0.7.2/sympy/matrices/expressions/tests/test_hadamard.py python3-sympy-0.7.3/sympy/matrices/expressions/tests/test_hadamard.py --- python3-sympy-0.7.2/sympy/matrices/expressions/tests/test_hadamard.py 1970-01-01 00:00:00.000000000 +0000 +++ python3-sympy-0.7.3/sympy/matrices/expressions/tests/test_hadamard.py 2013-07-13 17:53:32.000000000 +0000 @@ -0,0 +1,59 @@ + + +from sympy.core import symbols +from sympy.utilities.pytest import raises + +from sympy.matrices import ShapeError, MatrixSymbol +from sympy.matrices.expressions import HadamardProduct, hadamard_product + +n, m, k = symbols('n,m,k') +Z = MatrixSymbol('Z', n, n) +A = MatrixSymbol('A', n, m) +B = MatrixSymbol('B', n, m) +C = MatrixSymbol('C', m, k) + +def test_HadamardProduct(): + assert HadamardProduct(A, B, A).shape == A.shape + + raises(ShapeError, lambda: HadamardProduct(A, B.T)) + raises(TypeError, lambda: HadamardProduct(A, n)) + raises(TypeError, lambda: HadamardProduct(A, 1)) + + assert HadamardProduct(A, 2*B, -A)[1, 1] == \ + -2 * A[1, 1] * B[1, 1] * A[1, 1] + + mix = HadamardProduct(Z*A, B)*C + assert mix.shape == (n, k) + + assert set(HadamardProduct(A, B, A).T.args) == set((A.T, A.T, B.T)) + +def test_HadamardProduct_isnt_commutative(): + assert HadamardProduct(A, B) != HadamardProduct(B, A) + +def test_mixed_indexing(): + X = MatrixSymbol('X', 2, 2) + Y = MatrixSymbol('Y', 2, 2) + Z = MatrixSymbol('Z', 2, 2) + + assert (X*HadamardProduct(Y, Z))[0, 0] == \ + X[0, 0]*Y[0, 0]*Z[0, 0] + X[0, 1]*Y[1, 0]*Z[1, 0] + +def test_canonicalize(): + X = MatrixSymbol('X', 2, 2) + expr = HadamardProduct(X, check=False) + assert isinstance(expr, HadamardProduct) + expr2 = expr.doit() # unpack is called + assert isinstance(expr2, MatrixSymbol) + +def test_hadamard(): + m, n, p = symbols('m, n, p', integer=True) + A = MatrixSymbol('A', m, n) + B = MatrixSymbol('B', m, n) + C = MatrixSymbol('C', m, p) + with raises(TypeError): + hadamard_product() + assert hadamard_product(A) == A + assert isinstance(hadamard_product(A, B), HadamardProduct) + assert hadamard_product(A, B).doit() == hadamard_product(A, B) + with raises(ShapeError): + hadamard_product(A, C) diff -Nru python3-sympy-0.7.2/sympy/matrices/expressions/tests/test_indexing.py python3-sympy-0.7.3/sympy/matrices/expressions/tests/test_indexing.py --- python3-sympy-0.7.2/sympy/matrices/expressions/tests/test_indexing.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/matrices/expressions/tests/test_indexing.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,57 +1,68 @@ from sympy import (symbols, MatrixSymbol, Symbol, MatPow, BlockMatrix, - Identity, ZeroMatrix, ImmutableMatrix, eye) -from sympy.utilities.pytest import raises, XFAIL + Identity, ZeroMatrix, ImmutableMatrix, eye, Sum) +from sympy.utilities.pytest import raises -k,l,m,n = symbols('k l m n', integer=True) -i,j = symbols('i j', integer=True) +k, l, m, n = symbols('k l m n', integer=True) +i, j = symbols('i j', integer=True) W = MatrixSymbol('W', k, l) X = MatrixSymbol('X', l, m) Y = MatrixSymbol('Y', l, m) Z = MatrixSymbol('Z', m, n) -A = MatrixSymbol('A', 2,2) -B = MatrixSymbol('B', 2,2) -x = MatrixSymbol('x', 1,2) -y = MatrixSymbol('x', 2,1) +A = MatrixSymbol('A', 2, 2) +B = MatrixSymbol('B', 2, 2) +x = MatrixSymbol('x', 1, 2) +y = MatrixSymbol('x', 2, 1) + def test_symbolic_indexing(): - x12 = X[1,2] - assert x12 == Symbol(X.name+"_12") - assert X[i,j] == Symbol(X.name+"_ij") + x12 = X[1, 2] + assert all(s in str(x12) for s in ['1', '2', X.name]) + # We don't care about the exact form of this. We do want to make sure + # that all of these features are present + def test_add_index(): - assert (X+Y)[i,j] == X[i,j] + Y[i,j] + assert (X + Y)[i, j] == X[i, j] + Y[i, j] + def test_mul_index(): - assert (A*y)[0,0] == A[0,0]*y[0,0] + A[0,1]*y[1,0] + assert (A*y)[0, 0] == A[0, 0]*y[0, 0] + A[0, 1]*y[1, 0] assert (A*B).as_mutable() == (A.as_mutable() * B.as_mutable()) X = MatrixSymbol('X', n, m) Y = MatrixSymbol('Y', m, k) - # Using str to avoid dealing with a Dummy variable - assert str((X*Y)[4,2]) == "Sum(X(4, _k)*Y(_k, 2), (_k, 0, m - 1))" + + result = (X*Y)[4,2] + expected = Sum(X[4, i]*Y[i, 2], (i, 0, m - 1)) + assert result.args[0].dummy_eq(expected.args[0], i) + assert result.args[1][1:] == expected.args[1][1:] + def test_pow_index(): Q = MatPow(A, 2) - assert Q[0,0] == A[0,0]**2 + A[0,1]*A[1,0] + assert Q[0, 0] == A[0, 0]**2 + A[0, 1]*A[1, 0] + def test_transpose_index(): - assert X.T[i,j] == X[j,i] + assert X.T[i, j] == X[j, i] + def test_Identity_index(): I = Identity(3) - assert I[0,0] == I[1,1] == I[2,2] == 1 - assert I[1,0] == I[0,1] == I[2,1] == 0 - raises(IndexError, lambda: I[3,3]) + assert I[0, 0] == I[1, 1] == I[2, 2] == 1 + assert I[1, 0] == I[0, 1] == I[2, 1] == 0 + raises(IndexError, lambda: I[3, 3]) + def test_block_index(): I = Identity(3) - Z = ZeroMatrix(3,3) - B = BlockMatrix([[I,I],[I,I]]) + Z = ZeroMatrix(3, 3) + B = BlockMatrix([[I, I], [I, I]]) e3 = ImmutableMatrix(eye(3)) BB = BlockMatrix([[e3, e3], [e3, e3]]) - assert B[0,0] == B[3,0] == B[0,3] == B[3,3] == 1 - assert B[4,3] == B[5,1] == 0 + assert B[0, 0] == B[3, 0] == B[0, 3] == B[3, 3] == 1 + assert B[4, 3] == B[5, 1] == 0 BB = BlockMatrix([[e3, e3], [e3, e3]]) assert B.as_explicit() == BB.as_explicit() @@ -60,10 +71,11 @@ assert BI.as_explicit().equals(eye(6)) + def test_slicing(): - raises(NotImplementedError, lambda: W[3,:]) - A.as_explicit()[0,:] # does not raise an error + A.as_explicit()[0, :] # does not raise an error + def test_errors(): - raises(IndexError, lambda: Identity(2)[1,2,3,4,5]) - raises(IndexError, lambda: Identity(2)[[1,2,3,4,5]]) + raises(IndexError, lambda: Identity(2)[1, 2, 3, 4, 5]) + raises(IndexError, lambda: Identity(2)[[1, 2, 3, 4, 5]]) diff -Nru python3-sympy-0.7.2/sympy/matrices/expressions/tests/test_inverse.py python3-sympy-0.7.3/sympy/matrices/expressions/tests/test_inverse.py --- python3-sympy-0.7.2/sympy/matrices/expressions/tests/test_inverse.py 1970-01-01 00:00:00.000000000 +0000 +++ python3-sympy-0.7.3/sympy/matrices/expressions/tests/test_inverse.py 2013-07-13 17:53:32.000000000 +0000 @@ -0,0 +1,38 @@ +from sympy.core import symbols, S +from sympy.functions import adjoint, conjugate, transpose +from sympy.matrices.expressions import MatrixSymbol, Inverse +from sympy.matrices import eye, Identity, Matrix, ShapeError +from sympy.utilities.pytest import raises + +n, m, l = symbols('n m l', integer=True) +A = MatrixSymbol('A', n, m) +B = MatrixSymbol('B', m, l) +C = MatrixSymbol('C', n, n) +D = MatrixSymbol('D', n, n) +E = MatrixSymbol('E', m, n) + + +def test_inverse(): + raises(ShapeError, lambda: Inverse(A)) + raises(ShapeError, lambda: Inverse(A*B)) + + assert Inverse(C).shape == (n, n) + assert Inverse(A*E).shape == (n, n) + assert Inverse(E*A).shape == (m, m) + assert Inverse(C).inverse() == C + assert isinstance(Inverse(Inverse(C)), Inverse) + + assert C.inverse().inverse() == C + + assert C.inverse()*C == Identity(C.rows) + + assert Identity(n).inverse() == Identity(n) + assert (3*Identity(n)).inverse() == Identity(n)/3 + + # Simplifies Muls if possible (i.e. submatrices are square) + assert (C*D).inverse() == D.I*C.I + # But still works when not possible + assert isinstance((A*E).inverse(), Inverse) + + assert Inverse(eye(3)).doit() == eye(3) + assert Inverse(eye(3)).doit(deep=False) == eye(3) diff -Nru python3-sympy-0.7.2/sympy/matrices/expressions/tests/test_matmul.py python3-sympy-0.7.3/sympy/matrices/expressions/tests/test_matmul.py --- python3-sympy-0.7.2/sympy/matrices/expressions/tests/test_matmul.py 1970-01-01 00:00:00.000000000 +0000 +++ python3-sympy-0.7.3/sympy/matrices/expressions/tests/test_matmul.py 2013-07-13 17:53:32.000000000 +0000 @@ -0,0 +1,89 @@ +from sympy.core import I, symbols +from sympy.functions import adjoint, transpose +from sympy.matrices import Identity, Inverse, Matrix, MatrixSymbol, ZeroMatrix +from sympy.matrices.expressions import Adjoint, Transpose, det +from sympy.matrices.expressions.matmul import (factor_in_front, remove_ids, + MatMul, xxinv, any_zeros, unpack, only_squares) +from sympy.strategies import null_safe + +n, m, l, k = symbols('n m l k', integer=True) +A = MatrixSymbol('A', n, m) +B = MatrixSymbol('B', m, l) +C = MatrixSymbol('C', n, n) +D = MatrixSymbol('D', n, n) +E = MatrixSymbol('E', m, n) + + +def test_adjoint(): + assert adjoint(A*B) == Adjoint(B)*Adjoint(A) + assert adjoint(2*A*B) == 2*Adjoint(B)*Adjoint(A) + assert adjoint(2*I*C) == -2*I*Adjoint(C) + + M = Matrix(2, 2, [1, 2 + I, 3, 4]) + MA = Matrix(2, 2, [1, 3, 2 - I, 4]) + assert adjoint(M) == MA + assert adjoint(2*M) == 2*MA + assert adjoint(MatMul(2, M)) == MatMul(2, MA) + + +def test_transpose(): + assert transpose(A*B) == Transpose(B)*Transpose(A) + assert transpose(2*A*B) == 2*Transpose(B)*Transpose(A) + assert transpose(2*I*C) == 2*I*Transpose(C) + + M = Matrix(2, 2, [1, 2 + I, 3, 4]) + MT = Matrix(2, 2, [1, 3, 2 + I, 4]) + assert transpose(M) == MT + assert transpose(2*M) == 2*MT + assert transpose(MatMul(2, M)) == MatMul(2, MT) + + +def test_factor_in_front(): + assert factor_in_front(MatMul(A, 2, B, evaluate=False)) ==\ + MatMul(2, A, B, evaluate=False) + +def test_remove_ids(): + assert remove_ids(MatMul(A, Identity(m), B, evaluate=False)) == \ + MatMul(A, B, evaluate=False) + assert null_safe(remove_ids)(MatMul(Identity(n), evaluate=False)) == \ + MatMul(Identity(n), evaluate=False) + +def test_xxinv(): + assert xxinv(MatMul(D, Inverse(D), D, evaluate=False)) == \ + MatMul(Identity(n), D, evaluate=False) + +def test_any_zeros(): + assert any_zeros(MatMul(A, ZeroMatrix(m, k), evaluate=False)) == \ + ZeroMatrix(n, k) + +def test_unpack(): + assert unpack(MatMul(A, evaluate=False)) == A + x = MatMul(A, B) + assert unpack(x) == x + +def test_only_squares(): + A = MatrixSymbol('A', n, m) + C = MatrixSymbol('C', n, n) + D = MatrixSymbol('D', n, n) + + assert only_squares(C) == [C] + assert only_squares(C, D) == [C, D] + assert only_squares(C, A, A.T, D) == [C, A*A.T, D] + +def test_determinant(): + A = MatrixSymbol('A', n, m) + C = MatrixSymbol('C', n, n) + D = MatrixSymbol('D', n, n) + + assert det(2*C) == 2**n*det(C) + assert det(2*C*D) == 2**n*det(C)*det(D) + assert det(3*C*A*A.T*D) == 3**n*det(C)*det(A*A.T)*det(D) + +def test_doit(): + C = MatrixSymbol('C', n, n) + D = MatrixSymbol('D', n, n) + + assert MatMul(C, 2, D).args == (C, 2, D) + assert MatMul(C, 2, D).doit().args == (2, C, D) + assert MatMul(C, Transpose(D*C)).args == (C, Transpose(D*C)) + assert MatMul(C, Transpose(D*C)).doit(deep=True).args == (C, C.T, D.T) diff -Nru python3-sympy-0.7.2/sympy/matrices/expressions/tests/test_matrix_exprs.py python3-sympy-0.7.3/sympy/matrices/expressions/tests/test_matrix_exprs.py --- python3-sympy-0.7.2/sympy/matrices/expressions/tests/test_matrix_exprs.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/matrices/expressions/tests/test_matrix_exprs.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,247 +1,75 @@ -from sympy.utilities.pytest import raises -from sympy import S, symbols, Symbol, Tuple, Mul, Lambda -from sympy.matrices import (eye, MatrixSymbol, Transpose, Inverse, ShapeError, - MatMul, Identity, BlockMatrix, BlockDiagMatrix, block_collapse, Matrix, - ZeroMatrix, MatAdd, MatPow, matrixify, ImmutableMatrix, Trace, - MatrixExpr, FunctionMatrix) - -def test_transpose(): - n, m, l = symbols('n m l', integer=True) - A = MatrixSymbol('A', n, m) - B = MatrixSymbol('B', m, l) - - assert Transpose(A).shape == (m,n) - assert Transpose(A*B).shape == (l,n) - assert Transpose(Transpose(A)) == A - assert Transpose(eye(3)) == eye(3) - assert Transpose(S(5)) == S(5) - - assert Transpose(Matrix([[1,2],[3,4]])) == Matrix([[1,3],[2,4]]) - -def test_inverse(): - n, m, l = symbols('n m l', integer=True) - A = MatrixSymbol('A', n, m) - B = MatrixSymbol('B', m, l) - C = MatrixSymbol('C', n, n) - D = MatrixSymbol('D', n, n) - E = MatrixSymbol('E', m, n) - - raises(ShapeError, lambda: Inverse(A)) - assert Inverse(Inverse(C)) == C - - assert Inverse(C)*C == Identity(C.rows) - - assert Inverse(eye(3)) == eye(3) - - assert Inverse(S(3)) == S(1)/3 - - assert Inverse(Identity(n)) == Identity(n) - - # Simplifies Muls if possible (i.e. submatrices are square) - assert Inverse(C*D) == D.I*C.I - # But still works when not possible - assert Inverse(A*E).is_Inverse - - # We play nice with traditional explicit matrices - assert Inverse(Matrix([[1,2],[3,4]])) == Matrix([[1,2],[3,4]]).inv() - -def test_trace(): - n, m, l = symbols('n m l', integer=True) - A = MatrixSymbol('A', n, n) - B = MatrixSymbol('B', n, n) - assert isinstance(Trace(A), Trace) - assert not isinstance(Trace(A), MatrixExpr) - raises(ShapeError, lambda : Trace(MatrixSymbol('B', 3, 4))) - assert Trace(eye(3)) == 3 - assert Trace(Matrix(3,3,[1,2,3,4,5,6,7,8,9])) == 15 - - A / Trace(A) # Make sure this is possible - - # Some easy simplifications - assert Trace(Identity(5)) == 5 - assert Trace(ZeroMatrix(5,5)) == 0 - assert Trace(2*A*B) == 2 * Trace(A*B) - assert Trace(A.T) == Trace(A) - - i,j = symbols('i,j') - F = FunctionMatrix(3,3, Lambda((i,j), i+j)) - assert Trace(F).doit() == (0+0) + (1+1) + (2+2) +from sympy.core import S, symbols, Add, Mul +from sympy.functions import transpose, sin, cos, sqrt +from sympy.simplify import simplify +from sympy.matrices import (Identity, ImmutableMatrix, Inverse, MatAdd, MatMul, + MatPow, Matrix, MatrixExpr, MatrixSymbol, ShapeError, ZeroMatrix, + Transpose, Adjoint) +from sympy.utilities.pytest import raises - raises(TypeError, lambda : Trace(S.One)) +n, m, l, k, p = symbols('n m l k p', integer=True) +x = symbols('x') +A = MatrixSymbol('A', n, m) +B = MatrixSymbol('B', m, l) +C = MatrixSymbol('C', n, n) +D = MatrixSymbol('D', n, n) +E = MatrixSymbol('E', m, n) - assert Trace(A).arg is A def test_shape(): - n, m, l = symbols('n m l', integer=True) - A = MatrixSymbol('A', n, m) - B = MatrixSymbol('B', m, l) assert A.shape == (n, m) assert (A*B).shape == (n, l) raises(ShapeError, lambda: B*A) -def test_matexpr(): - n, m, l = symbols('n m l', integer=True) - x = Symbol('x') - A = MatrixSymbol('A', n, m) - B = MatrixSymbol('B', m, l) +def test_matexpr(): assert (x*A).shape == A.shape assert (x*A).__class__ == MatMul assert 2*A - A - A == ZeroMatrix(*A.shape) + assert (A*B).shape == (n, l) + def test_subs(): - n, m, l = symbols('n m l', integer=True) A = MatrixSymbol('A', n, m) B = MatrixSymbol('B', m, l) C = MatrixSymbol('C', m, l) - assert A.subs(n,m).shape == (m,m) - - assert (A*B).subs(B,C) == A*C - - assert (A*B).subs(l,n).is_square - - -def test_BlockMatrix(): - n,m,l,k,p = symbols('n m l k p', integer=True) - A = MatrixSymbol('A', n, m) - B = MatrixSymbol('B', n, k) - C = MatrixSymbol('C', l, m) - D = MatrixSymbol('D', l, k) - M = MatrixSymbol('M', m+k, p) - N = MatrixSymbol('N', l+n, k+m) - X = BlockMatrix(Matrix([[A,B],[C,D]])) - - # block_collapse does nothing on normal inputs - E = MatrixSymbol('E', n, m) - assert block_collapse(A+2*E) == A+2*E - F = MatrixSymbol('F', m, m) - assert block_collapse(E.T*A*F) == E.T*A*F - - assert X.shape == (l+n, k+m) - assert (block_collapse(Transpose(X)) == - BlockMatrix(Matrix([[A.T, C.T], [B.T, D.T]]))) - assert Transpose(X).shape == X.shape[::-1] - assert X.blockshape == (2,2) - - # Test that BlockMatrices and MatrixSymbols can still mix - assert (X*M).is_Mul - assert X._blockmul(M).is_Mul - assert (X*M).shape == (n+l, p) - assert (X+N).is_Add - assert X._blockadd(N).is_Add - assert (X+N).shape == X.shape - - E = MatrixSymbol('E', m, 1) - F = MatrixSymbol('F', k, 1) - - Y = BlockMatrix(Matrix([[E], [F]])) - - assert (X*Y).shape == (l+n, 1) - assert block_collapse(X*Y).blocks[0,0] == A*E + B*F - assert block_collapse(X*Y).blocks[1,0] == C*E + D*F - assert (block_collapse(Transpose(block_collapse(Transpose(X*Y)))) == - block_collapse(X*Y)) - - # block_collapse passes down into container objects, transposes, and inverse - assert block_collapse((X*Y, 2*X)) == (block_collapse(X*Y), block_collapse(2*X)) - assert block_collapse(Tuple(X*Y, 2*X)) == ( - block_collapse(X*Y), block_collapse(2*X)) - assert (block_collapse(Transpose(X*Y)) == - block_collapse(Transpose(block_collapse(X*Y)))) - - Ab = BlockMatrix([[A]]) - Z = MatrixSymbol('Z', *A.shape) - - # Make sure that MatrixSymbols will enter 1x1 BlockMatrix if it simplifies - assert block_collapse(Ab+Z) == BlockMatrix([[A+Z]]) - -def test_BlockMatrix_Trace(): - A,B,C,D = [MatrixSymbol(s, 3,3) for s in 'ABCD'] - X = BlockMatrix([[A,B],[C,D]]) - assert Trace(X) == Trace(A) + Trace(D) - -def test_squareBlockMatrix(): - n,m,l,k = symbols('n m l k', integer=True) - A = MatrixSymbol('A', n, n) - B = MatrixSymbol('B', n, m) - C = MatrixSymbol('C', m, n) - D = MatrixSymbol('D', m, m) - X = BlockMatrix([[A,B],[C,D]]) - Y = BlockMatrix([[A]]) + assert A.subs(n, m).shape == (m, m) - assert X.is_square + assert (A*B).subs(B, C) == A*C - assert block_collapse(X+Identity(m+n)) == BlockMatrix( - [[A+Identity(n), B], [C, D+Identity(m)]]) - Q = X+Identity(m+n) - assert block_collapse(Inverse(Q)) == Inverse(block_collapse(Q)) + assert (A*B).subs(l, n).is_square - assert (X + MatrixSymbol('Q', n+m, n+m)).is_Add - assert (X * MatrixSymbol('Q', n+m, n+m)).is_Mul - - assert Y.I.blocks[0,0] == A.I - assert Inverse(X, expand=True) == BlockMatrix([ - [(-B*D.I*C + A).I, -A.I*B*(D+-C*A.I*B).I], - [-(D-C*A.I*B).I*C*A.I, (D-C*A.I*B).I]]) - - assert Inverse(X, expand=False).is_Inverse - assert X.inverse().is_Inverse - - assert not X.is_Identity - - Z = BlockMatrix([[Identity(n),B],[C,D]]) - assert not Z.is_Identity - - -def test_BlockDiagMatrix(): - n,m,l = symbols('n m l', integer=True) - A = MatrixSymbol('A', n, n) - B = MatrixSymbol('B', m, m) - C = MatrixSymbol('C', l, l) - M = MatrixSymbol('M', n+m+l, n+m+l) - - X = BlockDiagMatrix(A,B,C) - Y = BlockDiagMatrix(A, 2*B, 3*C) - - assert X.blocks[1,1] == B - assert X.shape == (n+m+l, n+m+l) - assert all(X.blocks[i,j].is_ZeroMatrix if i!=j else X.blocks[i,j] in [A,B,C] - for i in range(3) for j in range(3)) - - assert block_collapse(X.I * X).is_Identity - - assert block_collapse(X*X) == BlockDiagMatrix(A*A, B*B, C*C) - - assert block_collapse(X+X) == BlockDiagMatrix(2*A, 2*B, 2*C) - - assert block_collapse(X*Y) == BlockDiagMatrix(A*A, 2*B*B, 3*C*C) - - assert block_collapse(X+Y) == BlockDiagMatrix(2*A, 3*B, 4*C) - - # Ensure that BlockDiagMatrices can still interact with normal MatrixExprs - assert (X*(2*M)).is_Mul - assert (X+(2*M)).is_Add - - assert (X._blockmul(M)).is_Mul - assert (X._blockadd(M)).is_Add def test_ZeroMatrix(): - n,m = symbols('n m', integer=True) A = MatrixSymbol('A', n, m) Z = ZeroMatrix(n, m) - assert A+Z == A - assert A*Z.T == ZeroMatrix(n,n) - assert Z*A.T == ZeroMatrix(n,n) - assert A-A == ZeroMatrix(*A.shape) + assert A + Z == A + assert A*Z.T == ZeroMatrix(n, n) + assert Z*A.T == ZeroMatrix(n, n) + assert A - A == ZeroMatrix(*A.shape) + + assert not Z + + assert transpose(Z) == ZeroMatrix(m, n) + assert Z.conjugate() == Z + + assert ZeroMatrix(n, n)**0 == Identity(n) + with raises(ShapeError): + Z**0 + with raises(ShapeError): + Z**2 + +def test_ZeroMatrix_doit(): + Znn = ZeroMatrix(Add(n, n, evaluate=False), n) + assert isinstance(Znn.rows, Add) + assert Znn.doit() == ZeroMatrix(2*n, n) + assert isinstance(Znn.doit().rows, Mul) - assert Transpose(Z) == ZeroMatrix(m, n) def test_Identity(): - n,m = symbols('n m', integer=True) A = MatrixSymbol('A', n, m) In = Identity(n) Im = Identity(m) @@ -249,106 +77,120 @@ assert A*Im == A assert In*A == A - assert Transpose(In) == In - assert Inverse(In) == In + assert transpose(In) == In + assert In.inverse() == In + assert In.conjugate() == In + +def test_Identity_doit(): + Inn = Identity(Add(n, n, evaluate=False)) + assert isinstance(Inn.rows, Add) + assert Inn.doit() == Identity(2*n) + assert isinstance(Inn.doit().rows, Mul) -def test_MatAdd(): - n, m = symbols('n m', integer=True) +def test_addition(): A = MatrixSymbol('A', n, m) B = MatrixSymbol('B', n, m) - assert (A+B).shape == A.shape - assert MatAdd(A, -A, 2*B).is_Mul + assert isinstance(A + B, MatAdd) + assert (A + B).shape == A.shape + assert isinstance(A - A + 2*B, MatMul) raises(ShapeError, lambda: A + B.T) - raises(ValueError, lambda: A+1) - raises(ValueError, lambda: 5+A) - raises(ValueError, lambda: 5-A) + raises(TypeError, lambda: A + 1) + raises(TypeError, lambda: 5 + A) + raises(TypeError, lambda: 5 - A) - assert MatAdd(A, ZeroMatrix(n,m), -A) == ZeroMatrix(n,m) - assert MatAdd(ZeroMatrix(n,m), S(0)) == ZeroMatrix(n,m) + assert A + ZeroMatrix(n, m) - A == ZeroMatrix(n, m) + with raises(TypeError): + ZeroMatrix(n,m) + S(0) -def test_MatMul(): - n, m, l = symbols('n m l', integer=True) +def test_multiplication(): A = MatrixSymbol('A', n, m) B = MatrixSymbol('B', m, l) C = MatrixSymbol('C', n, n) - assert (2*A*B).shape == (n,l) + assert (2*A*B).shape == (n, l) - assert (A*0*B) == ZeroMatrix(n,l) + assert (A*0*B) == ZeroMatrix(n, l) raises(ShapeError, lambda: B*A) assert (2*A).shape == A.shape - assert MatMul(A, ZeroMatrix(m,m), B) == ZeroMatrix(n,l) + assert A * ZeroMatrix(m, m) * B == ZeroMatrix(n, l) - assert MatMul(C*Identity(n)*C.I) == Identity(n) + assert C * Identity(n) * C.I == Identity(n) assert B/2 == S.Half*B raises(NotImplementedError, lambda: 2/B) A = MatrixSymbol('A', n, n) B = MatrixSymbol('B', n, n) - assert MatMul(Identity(n), (A + B)).is_Add + assert Identity(n) * (A + B) == A + B + def test_MatPow(): - n = Symbol('n', integer=True) A = MatrixSymbol('A', n, n) - assert Inverse(A).is_Pow AA = MatPow(A, 2) - assert AA.is_Pow assert AA.exp == 2 assert AA.base == A assert (A**n).exp == n assert A**0 == Identity(n) assert A**1 == A + assert A**2 == AA assert A**-1 == Inverse(A) - raises(ShapeError, lambda: MatrixSymbol('B', 3,2)**2) + assert A**S.Half == sqrt(A) + raises(ShapeError, lambda: MatrixSymbol('B', 3, 2)**2) -def test_linear_factors(): - from sympy.matrices import MatrixSymbol, linear_factors - n, m, l = symbols('n m l') - A = MatrixSymbol('A', n, m) - B = MatrixSymbol('B', m, l) - C = MatrixSymbol('C', n, l) - assert linear_factors(2*A*B + C, B, C) == { C: Identity(n), B: 2*A} - assert linear_factors(2*A*B + C, B) == { B: 2*A} - assert linear_factors(2*A*B, B) == {B: 2*A} - assert linear_factors(2*A*B, C) == {C: ZeroMatrix(n, n)} +def test_MatrixSymbol(): + n, m, t = symbols('n,m,t') + X = MatrixSymbol('X', n, m) + assert X.shape == (n, m) + raises(TypeError, lambda: MatrixSymbol('X', n, m)(t)) # issue 2756 + assert X.doit() == X - A = MatrixSymbol('A', n, n) - B = MatrixSymbol('B', n, n) - C = MatrixSymbol('C', n, n) - D = MatrixSymbol('C', m, m) - raises(ValueError, lambda: linear_factors(2*A*A + B, A)) - raises(ValueError, lambda: linear_factors(2*A*A, A)) - raises(ValueError, lambda: linear_factors(2*A*B, A, B)) - raises(ShapeError, lambda: linear_factors(2*A*B, D)) - raises(ShapeError, lambda: linear_factors(2*A*B+C, D)) - assert linear_factors(A, A) == {A:Identity(n)} +def test_dense_conversion(): + X = MatrixSymbol('X', 2, 2) + assert ImmutableMatrix(X) == ImmutableMatrix(2, 2, lambda i, j: X[i, j]) + assert Matrix(X) == Matrix(2, 2, lambda i, j: X[i, j]) -def test_MatrixSymbol(): - n,m,t = symbols('n,m,t') - X = MatrixSymbol('X', n, m) - assert X.shape == (n,m) - raises(TypeError, lambda: MatrixSymbol('X', n, m)(t)) # issue 2756 -def test_matrixify(): - n, m, l = symbols('n m l') +def test_free_symbols(): + assert (C*D).free_symbols == set((C, D)) + + +def test_zero_matmul(): + assert isinstance(S.Zero * MatrixSymbol('X', 2, 2), MatrixExpr) + + +def test_matadd_simplify(): + A = MatrixSymbol('A', 1, 1) + assert simplify(MatAdd(A, ImmutableMatrix([[sin(x)**2 + cos(x)**2]]))) == \ + MatAdd(A, ImmutableMatrix([[1]])) + + +def test_matmul_simplify(): + A = MatrixSymbol('A', 1, 1) + assert simplify(MatMul(A, ImmutableMatrix([[sin(x)**2 + cos(x)**2]]))) == \ + MatMul(A, ImmutableMatrix([[1]])) + +def test_invariants(): A = MatrixSymbol('A', n, m) B = MatrixSymbol('B', m, l) - assert matrixify(n+m) == n+m - assert matrixify(Mul(A,B)) == MatMul(A,B) + X = MatrixSymbol('X', n, n) + objs = [Identity(n), ZeroMatrix(m, n), A, MatMul(A, B), MatAdd(A, A), + Transpose(A), Adjoint(A), Inverse(X), MatPow(X, 2), MatPow(X, -1), + MatPow(X, 0)] + for obj in objs: + assert obj == obj.__class__(*obj.args) -def test_dense_conversion(): - X = MatrixSymbol('X', 2,2) - x00,x01,x10,x11 = symbols('X_00 X_01 X_10 X_11') - assert ImmutableMatrix(X) == ImmutableMatrix([[x00, x01], [x10, x11]]) - assert Matrix(X) == Matrix([[x00, x01], [x10, x11]]) +def test_indexing(): + A = MatrixSymbol('A', n, m) + A[1, 2] + A[l, k] + A[l+1, k+1] diff -Nru python3-sympy-0.7.2/sympy/matrices/expressions/tests/test_slice.py python3-sympy-0.7.3/sympy/matrices/expressions/tests/test_slice.py --- python3-sympy-0.7.2/sympy/matrices/expressions/tests/test_slice.py 1970-01-01 00:00:00.000000000 +0000 +++ python3-sympy-0.7.3/sympy/matrices/expressions/tests/test_slice.py 2013-07-13 17:53:32.000000000 +0000 @@ -0,0 +1,66 @@ + + +from sympy.matrices.expressions.slice import MatrixSlice +from sympy.matrices.expressions import MatrixSymbol +from sympy.abc import a, b, c, d, k, l, m, n +from sympy.utilities.pytest import raises, XFAIL +from sympy.functions.elementary.integers import floor +from sympy.assumptions import assuming, Q + + +X = MatrixSymbol('X', n, m) +Y = MatrixSymbol('Y', m, k) + +def test_shape(): + B = MatrixSlice(X, (a, b), (c, d)) + assert B.shape == (b - a, d - c) + +def test_entry(): + B = MatrixSlice(X, (a, b), (c, d)) + assert B[0,0] == X[a, c] + assert B[k,l] == X[a+k, c+l] + raises(IndexError, lambda : MatrixSlice(X, 1, (2, 5))[1, 0]) + + assert X[1::2, :][1, 3] == X[1+2, 3] + assert X[:, 1::2][3, 1] == X[3, 1+2] + +def test_on_diag(): + assert not MatrixSlice(X, (a, b), (c, d)).on_diag + assert MatrixSlice(X, (a, b), (a, b)).on_diag + +def test_inputs(): + assert MatrixSlice(X, 1, (2, 5)) == MatrixSlice(X, (1, 2), (2, 5)) + assert MatrixSlice(X, 1, (2, 5)).shape == (1, 3) + +def test_slicing(): + assert X[1:5, 2:4] == MatrixSlice(X, (1, 5), (2, 4)) + assert X[1, 2:4] == MatrixSlice(X, 1, (2, 4)) + assert X[1:5, :].shape == (4, X.shape[1]) + assert X[:, 1:5].shape == (X.shape[0], 4) + + assert X[::2, ::2].shape == (floor(n/2), floor(m/2)) + assert X[2, :] == MatrixSlice(X, 2, (0, m)) + +def test_exceptions(): + X = MatrixSymbol('x', 10, 20) + raises(IndexError, lambda: X[0:12, 2]) + raises(IndexError, lambda: X[0:9, 22]) + raises(IndexError, lambda: X[-1:5, 2]) + +@XFAIL +def test_symmetry(): + X = MatrixSymbol('x', 10, 10) + Y = X[:5, 5:] + with assuming(Q.symmetric(X)): + assert Y.T == X[5:, :5] + +def test_slice_of_slice(): + X = MatrixSymbol('x', 10, 10) + assert X[2, :][:, 3][0, 0] == X[2, 3] + assert X[:5, :5][:4, :4] == X[:4, :4] + assert X[1:5, 2:6][1:3, 2] == X[2:4, 4] + assert X[1:9:2, 2:6][1:3, 2] == X[3:7:2, 4] + +def test_negative_index(): + X = MatrixSymbol('x', 10, 10) + assert X[-1, :] == X[9, :] diff -Nru python3-sympy-0.7.2/sympy/matrices/expressions/tests/test_trace.py python3-sympy-0.7.3/sympy/matrices/expressions/tests/test_trace.py --- python3-sympy-0.7.2/sympy/matrices/expressions/tests/test_trace.py 1970-01-01 00:00:00.000000000 +0000 +++ python3-sympy-0.7.3/sympy/matrices/expressions/tests/test_trace.py 2013-07-13 17:53:32.000000000 +0000 @@ -0,0 +1,48 @@ +from sympy.core import Lambda, S, symbols +from sympy.concrete import Sum +from sympy.functions import adjoint, conjugate, transpose +from sympy.matrices import eye, Matrix, ShapeError +from sympy.matrices.expressions import ( + Adjoint, Identity, FunctionMatrix, MatrixExpr, MatrixSymbol, Trace, + ZeroMatrix, trace +) +from sympy.utilities.pytest import raises, XFAIL + +n = symbols('n', integer=True) +A = MatrixSymbol('A', n, n) +B = MatrixSymbol('B', n, n) +C = MatrixSymbol('C', 3, 4) + + +def test_Trace(): + assert isinstance(Trace(A), Trace) + assert not isinstance(Trace(A), MatrixExpr) + raises(ShapeError, lambda: Trace(C)) + assert trace(eye(3)) == 3 + assert trace(Matrix(3, 3, [1, 2, 3, 4, 5, 6, 7, 8, 9])) == 15 + + assert adjoint(Trace(A)) == trace(Adjoint(A)) + assert conjugate(Trace(A)) == trace(Adjoint(A)) + assert transpose(Trace(A)) == Trace(A) + + A / Trace(A) # Make sure this is possible + + # Some easy simplifications + assert trace(Identity(5)) == 5 + assert trace(ZeroMatrix(5, 5)) == 0 + assert trace(2*A*B) == 2 * trace(A*B) + assert trace(A.T) == trace(A) + + i, j = symbols('i j') + F = FunctionMatrix(3, 3, Lambda((i, j), i + j)) + assert trace(F) == (0 + 0) + (1 + 1) + (2 + 2) + + raises(TypeError, lambda: Trace(S.One)) + + assert Trace(A).arg is A + + assert str(trace(A)) == str(Trace(A).doit(deep=True)) + +@XFAIL +def test_rewrite(): + assert isinstance(trace(A).rewrite(Sum), Sum) diff -Nru python3-sympy-0.7.2/sympy/matrices/expressions/tests/test_transpose.py python3-sympy-0.7.3/sympy/matrices/expressions/tests/test_transpose.py --- python3-sympy-0.7.2/sympy/matrices/expressions/tests/test_transpose.py 1970-01-01 00:00:00.000000000 +0000 +++ python3-sympy-0.7.3/sympy/matrices/expressions/tests/test_transpose.py 2013-07-13 17:53:32.000000000 +0000 @@ -0,0 +1,35 @@ +from sympy.functions import adjoint, conjugate, transpose +from sympy.matrices.expressions import MatrixSymbol, Adjoint, trace, Transpose +from sympy.matrices import eye, Matrix +from sympy import symbols, S, assuming, Q + +n, m, l, k, p = symbols('n m l k p', integer=True) +A = MatrixSymbol('A', n, m) +B = MatrixSymbol('B', m, l) +C = MatrixSymbol('C', n, n) + + +def test_transpose(): + Sq = MatrixSymbol('Sq', n, n) + + assert transpose(A) == Transpose(A) + assert Transpose(A).shape == (m, n) + assert Transpose(A*B).shape == (l, n) + assert transpose(Transpose(A)) == A + assert isinstance(Transpose(Transpose(A)), Transpose) + + assert adjoint(Transpose(A)) == Adjoint(Transpose(A)) + assert conjugate(Transpose(A)) == Adjoint(A) + + assert Transpose(eye(3)).doit() == eye(3) + + assert Transpose(S(5)).doit() == S(5) + + assert Transpose(Matrix([[1, 2], [3, 4]])).doit() == Matrix([[1, 3], [2, 4]]) + + assert transpose(trace(Sq)) == trace(Sq) + assert trace(Transpose(Sq)) == trace(Sq) + + assert Transpose(Sq)[0, 1] == Sq[1, 0] + + assert Transpose(A*B).doit() == Transpose(B) * Transpose(A) diff -Nru python3-sympy-0.7.2/sympy/matrices/expressions/trace.py python3-sympy-0.7.3/sympy/matrices/expressions/trace.py --- python3-sympy-0.7.2/sympy/matrices/expressions/trace.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/matrices/expressions/trace.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,6 +1,7 @@ -from sympy import Basic, Expr, sympify +from sympy import Basic, Expr from .matexpr import ShapeError + class Trace(Expr): """Matrix Trace @@ -11,26 +12,56 @@ >>> Trace(A) Trace(A) - >>> Trace(eye(3)) - 3 + See Also: + trace """ is_Trace = True + def __new__(cls, mat): if not mat.is_Matrix: - raise TypeError("input to Trace, %s, is not a matrix"%str(mat)) + raise TypeError("input to Trace, %s, is not a matrix" % str(mat)) if not mat.is_square: raise ShapeError("Trace of a non-square matrix") - try: - return mat._eval_trace() - except (AttributeError, NotImplementedError): - return Basic.__new__(cls, mat) + return Basic.__new__(cls, mat) + + def _eval_transpose(self): + return self @property def arg(self): return self.args[0] - def doit(self): - from sympy import Add - return Add(*[self.arg[i,i] for i in range(self.arg.rows)]) + def doit(self, **kwargs): + if kwargs.get('deep', False): + arg = self.arg.doit() + else: + arg = self.arg + try: + return arg._eval_trace() + except (AttributeError, NotImplementedError): + return Trace(arg) + + def _eval_rewrite_as_Sum(self): + from sympy import Sum, Dummy + i = Dummy('i') + return Sum(self.arg[i, i], (i, 0, self.arg.rows-1)).doit() + + +def trace(expr): + """ Trace of a Matrix. Sum of the diagonal elements + + >>> from sympy import trace, Symbol, MatrixSymbol, pprint, eye + >>> n = Symbol('n') + >>> X = MatrixSymbol('X', n, n) # A square matrix + >>> trace(2*X) + 2*Trace(X) + + >>> trace(eye(3)) + 3 + + See Also: + Trace + """ + return Trace(expr).doit() diff -Nru python3-sympy-0.7.2/sympy/matrices/expressions/transpose.py python3-sympy-0.7.3/sympy/matrices/expressions/transpose.py --- python3-sympy-0.7.2/sympy/matrices/expressions/transpose.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/matrices/expressions/transpose.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,29 +1,45 @@ -from .matexpr import MatrixExpr -from sympy import Basic +from sympy import Basic, Q +from sympy.functions import adjoint, conjugate + +from sympy.matrices.expressions.matexpr import MatrixExpr +from sympy.matrices import MatrixBase class Transpose(MatrixExpr): - """Matrix Transpose + """ + The transpose of a matrix expression. - Represents the transpose of a matrix expression. + This is a symbolic object that simply stores its argument without + evaluating it. To actually compute the transpose, use the ``transpose()`` + function, or the ``.T`` attribute of matrices. - Use .T as shorthand + Examples + ======== - >>> from sympy import MatrixSymbol, Transpose + >>> from sympy.matrices import MatrixSymbol, Transpose + >>> from sympy.functions import transpose >>> A = MatrixSymbol('A', 3, 5) >>> B = MatrixSymbol('B', 5, 3) >>> Transpose(A) A' - >>> A.T - A' + >>> A.T == transpose(A) == Transpose(A) + True >>> Transpose(A*B) + (A*B)' + >>> transpose(A*B) B'*A' + """ is_Transpose = True - def __new__(cls, mat): + + def doit(self, **hints): + arg = self.arg + if hints.get('deep', True) and isinstance(arg, Basic): + arg = arg.doit(**hints) try: - return mat.transpose() - except (AttributeError, NotImplementedError): - return Basic.__new__(cls, mat) + result = arg._eval_transpose() + return result if result is not None else Transpose(arg) + except AttributeError: + return Transpose(arg) @property def arg(self): @@ -36,9 +52,23 @@ def _entry(self, i, j): return self.arg._entry(j, i) + def _eval_adjoint(self): + return conjugate(self.arg) + + def _eval_conjugate(self): + return adjoint(self.arg) + def _eval_transpose(self): return self.arg def _eval_trace(self): from .trace import Trace - return Trace(self.arg) # Trace(X.T) => Trace(X) + return Trace(self.arg) # Trace(X.T) => Trace(X) + + def _eval_determinant(self): + from sympy.matrices.expressions.determinant import det + return det(self.arg) + +def transpose(expr): + """ Matrix transpose """ + return Transpose(expr).doit() diff -Nru python3-sympy-0.7.2/sympy/matrices/immutable.py python3-sympy-0.7.3/sympy/matrices/immutable.py --- python3-sympy-0.7.2/sympy/matrices/immutable.py 1970-01-01 00:00:00.000000000 +0000 +++ python3-sympy-0.7.3/sympy/matrices/immutable.py 2013-07-13 17:53:32.000000000 +0000 @@ -0,0 +1,136 @@ +from sympy.core import Basic, Integer, Tuple, Dict +from sympy.core.sympify import converter as sympify_converter + +from sympy.matrices.matrices import MatrixBase +from sympy.matrices.dense import DenseMatrix +from sympy.matrices.sparse import SparseMatrix, MutableSparseMatrix +from sympy.matrices.expressions import MatrixExpr + + +def sympify_matrix(arg): + return ImmutableMatrix(arg) +sympify_converter[MatrixBase] = sympify_matrix + +class ImmutableMatrix(MatrixExpr, DenseMatrix): + """Create an immutable version of a matrix. + + Examples + ======== + + >>> from sympy import eye + >>> from sympy.matrices import ImmutableMatrix + >>> ImmutableMatrix(eye(3)) + Matrix([ + [1, 0, 0], + [0, 1, 0], + [0, 0, 1]]) + >>> _[0, 0] = 42 + Traceback (most recent call last): + ... + TypeError: Cannot set values of ImmutableDenseMatrix + """ + + _class_priority = 8 + + @classmethod + def _new(cls, *args, **kwargs): + if len(args) == 1 and isinstance(args[0], ImmutableMatrix): + return args[0] + rows, cols, flat_list = cls._handle_creation_inputs(*args, **kwargs) + rows = Integer(rows) + cols = Integer(cols) + mat = Tuple(*flat_list) + return Basic.__new__(cls, rows, cols, mat) + + def __new__(cls, *args, **kwargs): + return cls._new(*args, **kwargs) + + @property + def shape(self): + return tuple([int(i) for i in self.args[:2]]) + + @property + def _mat(self): + return list(self.args[2]) + + def _entry(self, i, j): + return DenseMatrix.__getitem__(self, (i, j)) + + __getitem__ = DenseMatrix.__getitem__ + + def __setitem__(self, *args): + raise TypeError("Cannot set values of ImmutableMatrix") + + adjoint = MatrixBase.adjoint + conjugate = MatrixBase.conjugate + # C and T are defined in MatrixExpr...I don't know why C alone + # needs to be defined here + C = MatrixBase.C + + as_mutable = DenseMatrix.as_mutable + _eval_trace = DenseMatrix._eval_trace + _eval_transpose = DenseMatrix._eval_transpose + _eval_conjugate = DenseMatrix._eval_conjugate + _eval_adjoint = DenseMatrix._eval_adjoint + _eval_inverse = DenseMatrix._eval_inverse + _eval_simplify = DenseMatrix._eval_simplify + + equals = DenseMatrix.equals + is_Identity = DenseMatrix.is_Identity + + __add__ = MatrixBase.__add__ + __radd__ = MatrixBase.__radd__ + __mul__ = MatrixBase.__mul__ + __rmul__ = MatrixBase.__rmul__ + __pow__ = MatrixBase.__pow__ + __sub__ = MatrixBase.__sub__ + __rsub__ = MatrixBase.__rsub__ + __neg__ = MatrixBase.__neg__ + __div__ = MatrixBase.__div__ + __truediv__ = MatrixBase.__truediv__ + + +class ImmutableSparseMatrix(Basic, SparseMatrix): + """Create an immutable version of a sparse matrix. + + Examples + ======== + + >>> from sympy import eye + >>> from sympy.matrices.immutable import ImmutableSparseMatrix + >>> ImmutableSparseMatrix(1, 1, {}) + Matrix([[0]]) + >>> ImmutableSparseMatrix(eye(3)) + Matrix([ + [1, 0, 0], + [0, 1, 0], + [0, 0, 1]]) + >>> _[0, 0] = 42 + Traceback (most recent call last): + ... + TypeError: Cannot set values of ImmutableSparseMatrix + >>> _.shape + (3, 3) + """ + + _class_priority = 9 + + @classmethod + def _new(cls, *args, **kwargs): + s = MutableSparseMatrix(*args) + rows = Integer(s.rows) + cols = Integer(s.cols) + mat = Dict(s._smat) + obj = Basic.__new__(cls, rows, cols, mat) + obj.rows = s.rows + obj.cols = s.cols + obj._smat = s._smat + return obj + + def __new__(cls, *args, **kwargs): + return cls._new(*args, **kwargs) + + def __setitem__(self, *args): + raise TypeError("Cannot set values of ImmutableSparseMatrix") + + subs = MatrixBase.subs diff -Nru python3-sympy-0.7.2/sympy/matrices/immutable_matrix.py python3-sympy-0.7.3/sympy/matrices/immutable_matrix.py --- python3-sympy-0.7.2/sympy/matrices/immutable_matrix.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/matrices/immutable_matrix.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,55 +0,0 @@ -from .matrices import MatrixBase, MutableMatrix -from .expressions import MatrixExpr, Transpose -from sympy import Basic, Integer, Tuple - -class ImmutableMatrix(MatrixExpr, MatrixBase): - - _class_priority = 8 - - @classmethod - def _new(cls, *args, **kwargs): - if len(args)==1 and isinstance(args[0], ImmutableMatrix): - return args[0] - rows, cols, mat = MatrixBase._handle_creation_inputs(*args, **kwargs) - rows = Integer(rows) - cols = Integer(cols) - mat = Tuple(*mat) - return Basic.__new__(cls, rows, cols, mat) - def __new__(cls, *args, **kwargs): - return cls._new(*args, **kwargs) - - @property - def shape(self): - return self.args[0:2] - - @property - def mat(self): - return self.args[2] - - def _entry(self, i, j): - return MatrixBase.__getitem__(self, (i,j)) - - def __setitem__(self, *args): - raise TypeError("Can not set values in Immutable Matrix. " - "Use Matrix instead.") - - __getitem__ = MatrixBase.__getitem__ - - as_mutable = MatrixBase.as_mutable - - adjoint = MatrixBase.adjoint - conjugate = MatrixBase.conjugate - equals = MatrixBase.equals - is_Identity = MatrixBase.is_Identity - transpose = MatrixBase.transpose - - __add__ = MatrixBase.__add__ - __radd__ = MatrixBase.__radd__ - __mul__ = MatrixBase.__mul__ - __rmul__ = MatrixBase.__rmul__ - __pow__ = MatrixBase.__pow__ - __sub__ = MatrixBase.__sub__ - __rsub__ = MatrixBase.__rsub__ - __neg__ = MatrixBase.__neg__ - __div__ = MatrixBase.__div__ - __truediv__ = MatrixBase.__truediv__ diff -Nru python3-sympy-0.7.2/sympy/matrices/matrices.py python3-sympy-0.7.3/sympy/matrices/matrices.py --- python3-sympy-0.7.2/sympy/matrices/matrices.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/matrices/matrices.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,47 +1,51 @@ from sympy.core.add import Add from sympy.core.basic import Basic, C +from sympy.core.expr import Expr from sympy.core.function import count_ops from sympy.core.power import Pow from sympy.core.symbol import Symbol, Dummy from sympy.core.numbers import Integer, ilcm, Rational, Float from sympy.core.singleton import S -from sympy.core.sympify import sympify, SympifyError -from sympy.core.compatibility import is_sequence +from sympy.core.sympify import sympify +from sympy.core.compatibility import is_sequence, default_sort_key from sympy.polys import PurePoly, roots, cancel from sympy.simplify import simplify as _simplify, signsimp, nsimplify from sympy.utilities.iterables import flatten -from sympy.utilities.misc import filldedent, default_sort_key from sympy.functions.elementary.miscellaneous import sqrt, Max, Min from sympy.printing import sstr -from sympy.functions.elementary.trigonometric import cos, sin - -from sympy.core.compatibility import callable, reduce +from sympy.core.compatibility import callable, reduce, as_int from sympy.utilities.exceptions import SymPyDeprecationWarning -from sympy.core.decorators import call_highest_priority -import random from types import FunctionType import collections from functools import reduce + +def _iszero(x): + """Returns True if x is zero.""" + return x.is_zero + + class MatrixError(Exception): pass + class ShapeError(ValueError, MatrixError): """Wrong matrix shape""" pass + class NonSquareMatrixError(ShapeError): pass -def _iszero(x): - """Returns True if x is zero.""" - return x.is_zero class DeferredVector(Symbol): """A vector whose components are deferred (e.g. for use with lambdify) + Examples + ======== + >>> from sympy import DeferredVector, lambdify >>> X = DeferredVector( 'X' ) >>> X @@ -51,197 +55,286 @@ >>> func( [1, 2, 3] ) (3, 6) """ - def __getitem__(self,i): + def __getitem__(self, i): if i == -0: i = 0 if i < 0: raise IndexError('DeferredVector index out of range') - component_name = '%s[%d]'%(self.name,i) + component_name = '%s[%d]' % (self.name, i) return Symbol(component_name) def __str__(self): return sstr(self) def __repr__(self): - return "DeferredVector('%s')"%(self.name) + return "DeferredVector('%s')" % (self.name) class MatrixBase(object): # Added just for numpy compatibility - # TODO: investigate about __array_priority__ - __array_priority__ = 10.0 + __array_priority__ = 11 is_Matrix = True + is_Identity = None _class_priority = 3 - - def _sympy_(self): - #return self.as_immutable() - raise SympifyError('Matrix cannot be sympified') + _sympify = staticmethod(sympify) @classmethod def _handle_creation_inputs(cls, *args, **kwargs): - """ - Matrix can be constructed with values or a rule. + """Return the number of rows, cols and flat matrix elements. + + Examples + ======== >>> from sympy import Matrix, I - >>> Matrix( ((1,2+I), (3,4)) ) #doctest:+NORMALIZE_WHITESPACE - [1, 2 + I] - [3, 4] - >>> Matrix(2, 2, lambda i,j: (i+1)*j ) #doctest:+NORMALIZE_WHITESPACE - [0, 1] - [0, 2] + + Matrix can be constructed as follows: + + * from a nested list of iterables + + >>> Matrix( ((1, 2+I), (3, 4)) ) + Matrix([ + [1, 2 + I], + [3, 4]]) + + * from un-nested iterable (interpreted as a column) + + >>> Matrix( [1, 2] ) + Matrix([ + [1], + [2]]) + + * from un-nested iterable with dimensions + + >>> Matrix(1, 2, [1, 2] ) + Matrix([[1, 2]]) + + * from no arguments (a 0 x 0 matrix) + + >>> Matrix() + Matrix(0, 0, []) + + * from a rule + + >>> Matrix(2, 2, lambda i, j: i/(j + 1) ) + Matrix([ + [0, 0], + [1, 1/2]]) """ + from sympy.matrices.sparse import SparseMatrix + + # Matrix(SparseMatrix(...)) + if len(args) == 1 and isinstance(args[0], SparseMatrix): + return args[0].rows, args[0].cols, flatten(args[0].tolist()) + # Matrix(Matrix(...)) if len(args) == 1 and isinstance(args[0], MatrixBase): - return args[0].rows, args[0].cols, args[0].mat + return args[0].rows, args[0].cols, args[0]._mat - # Matrix(MatrixSymbol('X', 2,2)) + # Matrix(MatrixSymbol('X', 2, 2)) if len(args) == 1 and isinstance(args[0], Basic) and args[0].is_Matrix: - return args[0].rows, args[0].cols, args[0].as_explicit().mat + return args[0].rows, args[0].cols, args[0].as_explicit()._mat + + if len(args) == 3: + rows = as_int(args[0]) + cols = as_int(args[1]) - # Matrix(2, 2, lambda i,j: i+j) + # Matrix(2, 2, lambda i, j: i+j) if len(args) == 3 and isinstance(args[2], collections.Callable): operation = args[2] - rows = args[0] - cols = args[1] - mat = [] + flat_list = [] for i in range(rows): - for j in range(cols): - mat.append(sympify(operation(i, j))) + flat_list.extend([cls._sympify(operation(cls._sympify(i), j)) + for j in range(cols)]) - # Matrix(2, 2, [1,2,3,4]) - elif len(args)==3 and is_sequence(args[2]): - rows = args[0] - cols = args[1] - mat = args[2] - if len(mat) != rows*cols: + # Matrix(2, 2, [1, 2, 3, 4]) + elif len(args) == 3 and is_sequence(args[2]): + flat_list = args[2] + if len(flat_list) != rows*cols: raise ValueError('List length should be equal to rows*columns') - mat = [sympify(i) for i in mat] + flat_list = [cls._sympify(i) for i in flat_list] - # Matrix(numpy.ones((2,2))) - elif len(args) == 1: - in_mat = args[0] - if hasattr(in_mat, "__array__"): #pragma: no cover - # NumPy array or matrix or some other object that implements - # __array__. So let's first use this method to get a - # numpy.array() and then make a python list out of it. - arr = in_mat.__array__() - if len(arr.shape) == 2: - rows, cols = arr.shape[0], arr.shape[1] - mat = [sympify(i) for i in arr.ravel()] - return rows, cols, mat - elif len(arr.shape) == 1: - rows, cols = 1, arr.shape[0] - mat = [0]*cols - for i in range(len(arr)): - mat[i] = sympify(arr[i]) - return rows, cols, mat - else: - raise NotImplementedError("SymPy supports just 1D and 2D matrices") - elif not is_sequence(in_mat, include=MatrixBase): - raise TypeError("Matrix constructor doesn't accept %s as input" - % str(type(in_mat))) + # Matrix(numpy.ones((2, 2))) + elif len(args) == 1 and hasattr(args[0], "__array__"): # pragma: no cover + # NumPy array or matrix or some other object that implements + # __array__. So let's first use this method to get a + # numpy.array() and then make a python list out of it. + arr = args[0].__array__() + if len(arr.shape) == 2: + rows, cols = arr.shape[0], arr.shape[1] + flat_list = [cls._sympify(i) for i in arr.ravel()] + return rows, cols, flat_list + elif len(arr.shape) == 1: + rows, cols = 1, arr.shape[0] + flat_list = [S.Zero]*cols + for i in range(len(arr)): + flat_list[i] = cls._sympify(arr[i]) + return rows, cols, flat_list + else: + raise NotImplementedError( + "SymPy supports just 1D and 2D matrices") + + # Matrix([1, 2, 3]) or Matrix([[1, 2], [3, 4]]) + elif len(args) == 1 and is_sequence(args[0]): in_mat = [] + ncol = set() for row in args[0]: if isinstance(row, MatrixBase): in_mat.extend(row.tolist()) + if row.cols or row.rows: # only pay attention if it's not 0x0 + ncol.add(row.cols) else: in_mat.append(row) + try: + ncol.add(len(row)) + except TypeError: + ncol.add(1) + if len(ncol) > 1: + raise ValueError("Got rows of variable lengths: %s" % + sorted(list(ncol))) rows = len(in_mat) - if len(in_mat): + if rows: if not is_sequence(in_mat[0]): cols = 1 - mat = [sympify(i) for i in in_mat] - return rows, cols, mat - cols = len(in_mat[0]) + flat_list = [cls._sympify(i) for i in in_mat] + return rows, cols, flat_list + cols = ncol.pop() else: cols = 0 - mat = [] + flat_list = [] for j in range(rows): - if len(in_mat[j]) != cols: - raise ValueError("Input %s inconsistant to form a Matrix." % - args) for i in range(cols): - mat.append(sympify(in_mat[j][i])) + flat_list.append(cls._sympify(in_mat[j][i])) # Matrix() elif len(args) == 0: # Empty Matrix rows = cols = 0 - mat = [] + flat_list = [] + else: raise TypeError("Data type not understood") - return rows, cols, mat + return rows, cols, flat_list - def _eval_transpose(self): - return self.transpose() + def _setitem(self, key, value): + """Helper to set value at location given by key. - def _eval_trace(self): - return self.trace() + Examples + ======== - def transpose(self): - """ - Matrix transposition. + >>> from sympy import Matrix, I, zeros, ones + >>> m = Matrix(((1, 2+I), (3, 4))) + >>> m + Matrix([ + [1, 2 + I], + [3, 4]]) + >>> m[1, 0] = 9 + >>> m + Matrix([ + [1, 2 + I], + [9, 4]]) + >>> m[1, 0] = [[0, 1]] - >>> from sympy import Matrix, I - >>> m=Matrix(((1,2+I),(3,4))) - >>> m #doctest: +NORMALIZE_WHITESPACE - [1, 2 + I] - [3, 4] - >>> m.transpose() #doctest: +NORMALIZE_WHITESPACE - [ 1, 3] - [2 + I, 4] - >>> m.T == m.transpose() - True + To replace row r you assign to position r*m where m + is the number of columns: - See Also - ======== + >>> M = zeros(4) + >>> m = M.cols + >>> M[3*m] = ones(1, m)*2; M + Matrix([ + [0, 0, 0, 0], + [0, 0, 0, 0], + [0, 0, 0, 0], + [2, 2, 2, 2]]) - conjugate: By-element conjugation + And to replace column c you can assign to position c: + + >>> M[2] = ones(m, 1)*4; M + Matrix([ + [0, 0, 4, 0], + [0, 0, 4, 0], + [0, 0, 4, 0], + [2, 2, 4, 2]]) """ - a = [0]*len(self) - for i in range(self.cols): - a[i*self.rows:(i+1)*self.rows] = self.mat[i::self.cols] - return self._new(self.cols,self.rows,a) + from .dense import Matrix - T = property(transpose,None,None,"Matrix transposition.") + is_slice = isinstance(key, slice) + i, j = key = self.key2ij(key) + is_mat = isinstance(value, MatrixBase) + if type(i) is slice or type(j) is slice: + if is_mat: + self.copyin_matrix(key, value) + return + if not isinstance(value, Expr) and is_sequence(value): + self.copyin_list(key, value) + return + raise ValueError('unexpected value: %s' % value) + else: + if (not is_mat and + not isinstance(value, Basic) and is_sequence(value)): + value = Matrix(value) + is_mat = True + if is_mat: + if is_slice: + key = (slice(*divmod(i, self.cols)), + slice(*divmod(j, self.cols))) + else: + key = (slice(i, i + value.rows), + slice(j, j + value.cols)) + self.copyin_matrix(key, value) + else: + return i, j, self._sympify(value) + return - def conjugate(self): - """By-element conjugation. + def copy(self): + return self._new(self.rows, self.cols, self._mat) - See Also - ======== + def trace(self): + if not self.is_square: + raise NonSquareMatrixError() + return self._eval_trace() - transpose: Matrix transposition - H: Hermite conjugation - D: Dirac conjugation - """ - out = self._new(self.rows,self.cols, - lambda i,j: self[i,j].conjugate()) - return out + def inv(self, method=None, **kwargs): + if not self.is_square: + raise NonSquareMatrixError() + if method is not None: + kwargs['method'] = method + return self._eval_inverse(**kwargs) + + def transpose(self): + return self._eval_transpose() - C = property(conjugate,None,None,"By-element conjugation.") + T = property(transpose, None, None, "Matrix transposition.") + + def conjugate(self): + return self._eval_conjugate() + + C = property(conjugate, None, None, "By-element conjugation.") def adjoint(self): """Conjugate transpose or Hermitian conjugation.""" - return self.conjugate().transpose() + return self.T.C @property def H(self): - """ - Hermite conjugation. + """Return Hermite conjugate. + + Examples + ======== >>> from sympy import Matrix, I - >>> m=Matrix(((1,2+I),(3,4))) - >>> m #doctest: +NORMALIZE_WHITESPACE - [1, 2 + I] - [3, 4] - >>> m.H #doctest: +NORMALIZE_WHITESPACE - [ 1, 3] - [2 - I, 4] + >>> m = Matrix((0, 1 + I, 2, 3)) + >>> m + Matrix([ + [ 0], + [1 + I], + [ 2], + [ 3]]) + >>> m.H + Matrix([[0, 1 - I, 2, 3]]) See Also ======== @@ -249,12 +342,35 @@ conjugate: By-element conjugation D: Dirac conjugation """ - out = self.T.C - return out + return self.T.C @property def D(self): - """Dirac conjugation. + """Return Dirac conjugate (if self.rows == 4). + + Examples + ======== + + >>> from sympy import Matrix, I, eye + >>> m = Matrix((0, 1 + I, 2, 3)) + >>> m.D + Matrix([[0, 1 - I, -2, -3]]) + >>> m = (eye(4) + I*eye(4)) + >>> m[0, 3] = 2 + >>> m.D + Matrix([ + [1 - I, 0, 0, 0], + [ 0, 1 - I, 0, 0], + [ 0, 0, -1 + I, 0], + [ 2, 0, 0, -1 + I]]) + + If the matrix does not have 4 rows an AttributeError will be raised + because this property is only defined for matrices with 4 rows. + + >>> Matrix(eye(2)).D + Traceback (most recent call last): + ... + AttributeError: Matrix has no attribute D. See Also ======== @@ -263,172 +379,124 @@ H: Hermite conjugation """ from sympy.physics.matrices import mgamma - try: - out = self.H * mgamma(0) - return out - # In Python 3.2, properties can only return an AttributeError, so we - # have to catch the ShapeError; see also the commit making this change - except ShapeError: - raise AttributeError("Dirac conjugation not possible.") - - def __getitem__(self,key): - """ - >>> from sympy import Matrix, I - >>> m=Matrix(((1,2+I),(3,4))) - >>> m #doctest: +NORMALIZE_WHITESPACE - [1, 2 + I] - [3, 4] - >>> m[1,0] - 3 - >>> m.H[1,0] - 2 - I - - """ - if type(key) is tuple: - i, j = key - if type(i) is slice or type(j) is slice: - return self.submatrix(key) - - else: - # a2idx inlined - if type(i) is not int: - try: - i = i.__index__() - except AttributeError: - raise IndexError("Invalid index a[%r]" % (key,)) - # a2idx inlined - if type(j) is not int: - try: - j = j.__index__() - except AttributeError: - raise IndexError("Invalid index a[%r]" % (key,)) - - i, j = self.key2ij((i, j)) - if not (i>=0 and i=0 and j < self.cols): - raise IndexError("Index out of range: a[%s]" % (key,)) - else: - return self.mat[i*self.cols + j] - - - else: - # row-wise decomposition of matrix - if type(key) is slice: - return self.mat[key] - else: - k = a2idx(key) - if k is not None: - return self.mat[k] - raise IndexError("Invalid index: a[%s]" % repr(key)) - - def __setitem__(self, key, value): - raise NotImplementedError() - - def as_mutable(self): - """ - Returns a Mutable version of this Matrix - - >>> from sympy import ImmutableMatrix - >>> X = ImmutableMatrix([[1,2],[3,4]]) - >>> Y = X.as_mutable() - >>> Y[1,1] = 5 # Can set values in Y - >>> Y - [1, 2] - [3, 5] - """ - return MutableMatrix(self.rows, self.cols, self.mat) - - def as_immutable(self): - """ - Returns an Immutable version of this Matrix - """ - from .immutable_matrix import ImmutableMatrix - return ImmutableMatrix(self.rows, self.cols, self.mat) + if self.rows != 4: + # In Python 3.2, properties can only return an AttributeError + # so we can't raise a ShapeError -- see commit which added the + # first line of this inline comment. Also, there is no need + # for a message since MatrixBase will raise the AttributeError + raise AttributeError + return self.H*mgamma(0) def __array__(self): + from .dense import matrix2numpy return matrix2numpy(self) def __len__(self): - """ - Return the number of elements of self. + """Return the number of elements of self. Implemented mainly so bool(Matrix()) == False. """ - return self.rows * self.cols - - def tolist(self): - """ - Return the Matrix converted in a python list. - - >>> from sympy import Matrix - >>> m=Matrix(3, 3, list(range(9))) - >>> m - [0, 1, 2] - [3, 4, 5] - [6, 7, 8] - >>> m.tolist() - [[0, 1, 2], [3, 4, 5], [6, 7, 8]] - - """ - ret = [0]*self.rows - for i in range(self.rows): - ret[i] = self.mat[i*self.cols:(i+1)*self.cols] - return ret - - def hash(self): - """Compute a hash every time, because the matrix elements - could change.""" - return hash(self.__str__() ) + return self.rows*self.cols @property def shape(self): - """The shape (dimensions) of the matrix as the 2-tuple (rows, cols).""" - return (self.rows, self.cols) + """The shape (dimensions) of the matrix as the 2-tuple (rows, cols). - def __rmul__(self,a): - if hasattr(a, "__array__") and a.shape != (): - return matrix_multiply(a,self) - out = self._new(self.rows, self.cols, [a*i for i in self.mat]) - return out - - def expand(self, **hints): - """ - Expand each element of the matrix by calling ``expand()``. - """ - out = self._new(self.rows, self.cols, - [i.expand(**hints) for i in self.mat]) - return out + Examples + ======== - def subs(self, *args, **kwargs): - """ - Create substituted expressions for each element with ``Expr.subs``. + >>> from sympy.matrices import zeros + >>> M = zeros(2, 3) + >>> M.shape + (2, 3) + >>> M.rows + 2 + >>> M.cols + 3 """ - out = self._new(self.rows, self.cols, - [i.subs(*args, **kwargs) for i in self.mat]) - return out + return (self.rows, self.cols) - def __sub__(self,a): + def __sub__(self, a): return self + (-a) - def __rsub__(self,a): + def __rsub__(self, a): return (-self) + a - def __mul__(self,a): - if hasattr(a, "__array__") and a.shape != (): - return matrix_multiply(self,a) - out = self._new(self.rows, self.cols, [i*a for i in self.mat]) - return out + def __mul__(self, other): + """Return self*other where other is either a scalar or a matrix + of compatible dimensions. + + Examples + ======== + + >>> from sympy.matrices import Matrix + >>> A = Matrix([[1, 2, 3], [4, 5, 6]]) + >>> 2*A == A*2 == Matrix([[2, 4, 6], [8, 10, 12]]) + True + >>> B = Matrix([[1, 2, 3], [4, 5, 6], [7, 8, 9]]) + >>> A*B + Matrix([ + [30, 36, 42], + [66, 81, 96]]) + >>> B*A + Traceback (most recent call last): + ... + ShapeError: Matrices size mismatch. + >>> + + See Also + ======== + + matrix_multiply_elementwise + """ + if getattr(other, 'is_Matrix', False): + # The following implmentation is equivalent, but about 5% slower + #ma, na = A.shape + #mb, nb = B.shape + # + #if na != mb: + # raise ShapeError() + #product = Matrix(ma, nb, lambda i, j: 0) + #for i in range(ma): + # for j in range(nb): + # s = 0 + # for k in range(na): + # s += A[i, k]*B[k, j] + # product[i, j] = s + #return product + A = self + B = other + if A.cols != B.rows: + raise ShapeError("Matrices size mismatch.") + if A.cols == 0: + return classof(A, B)._new(A.rows, B.cols, lambda i, j: 0) + blst = B.T.tolist() + alst = A.tolist() + return classof(A, B)._new(A.rows, B.cols, lambda i, j: + reduce(lambda k, l: k + l, + [a_ik * b_kj for a_ik, b_kj in zip(alst[i], blst[j])])) + else: + return self._new(self.rows, self.cols, + [i*other for i in self._mat]) + + def __rmul__(self, a): + if getattr(a, 'is_Matrix', False): + return self._new(a)*self + return self*a def __pow__(self, num): + from sympy.matrices import eye + if not self.is_square: raise NonSquareMatrixError() if isinstance(num, int) or isinstance(num, Integer): n = int(num) if n < 0: - return self.inv() ** -n # A**-2 = (A**-1)**2 + return self.inv()**-n # A**-2 = (A**-1)**2 a = eye(self.cols) s = self while n: - if n%2: + if n % 2: a *= s n -= 1 if not n: @@ -440,26 +508,43 @@ try: P, D = self.diagonalize() except MatrixError: - raise NotImplementedError("Implemented only for diagonalizable matrices") + raise NotImplementedError( + "Implemented only for diagonalizable matrices") for i in range(D.rows): D[i, i] = D[i, i]**num - return self._new(P * D * P.inv()) + return self._new(P*D*P.inv()) else: - raise NotImplementedError("Only integer and rational values are supported") + raise NotImplementedError( + "Only integer and rational values are supported") + + def __add__(self, other): + """Return self + other, raising ShapeError if shapes don't match.""" + if getattr(other, 'is_Matrix', False): + A = self + B = other + if A.shape != B.shape: + raise ShapeError("Matrices size mismatch.") + alst = A.tolist() + blst = B.tolist() + ret = [S.Zero]*A.rows + for i in range(A.shape[0]): + ret[i] = list(map(lambda j, k: j + k, alst[i], blst[i])) + return classof(A, B)._new(ret) + raise TypeError('cannot add matrix and %s' % type(other)) - def __add__(self,a): - return matrix_add(self,a) + def __radd__(self, other): + return self + other - def __radd__(self,a): - return matrix_add(a,self) + def __div__(self, other): + return self*(S.One / other) - def __div__(self,a): - return self * (S.One/a) + def __truediv__(self, other): + return self.__div__(other) - def __truediv__(self,a): - return self.__div__(a) + def __neg__(self): + return -1*self - def multiply(self,b): + def multiply(self, b): """Returns self*b See Also @@ -467,37 +552,56 @@ dot cross - multiply_elementwise """ - return matrix_multiply(self,b) + return self*b - def add(self,b): - """Return self+b """ - return matrix_add(self,b) + def add(self, b): + """Return self + b """ + return self + b - def __neg__(self): - return -1*self + def table(self, printer, rowsep='\n', colsep=', ', align='right'): + r""" + String form of Matrix as a table. - def equals(self, other): - try: - return (self.shape == other.shape and - all([self[i,j] == other[i,j] - for i in range(self.rows) - for j in range(self.cols)])) - except AttributeError: - return False + ``printer`` is the printer to use for on the elements (generally + something like StrPrinter()) + + ``rowsep`` is the string used to separate rows (by default a newline). - def __eq__(self, other): - return self.equals(other) + ``colsep`` is the string used to separate columns (by default ', '). - def __ne__(self, other): - return not self == other + ``align`` defines how the elements are aligned. Must be one of 'left', + 'right', or 'center'. You can also use '<', '>', and '^' to mean the + same thing, respectively. - def __hash__(self): - return super(MatrixBase, self).__hash__() + This is used by the string printer for Matrix. + + Examples + ======== - def _format_str(self, strfunc, rowsep='\n'): + >>> from sympy import Matrix + >>> from sympy.printing.str import StrPrinter + >>> M = Matrix([[1, 2], [-33, 4]]) + >>> printer = StrPrinter() + >>> M.table(printer) + '[ 1, 2]\n[-33, 4]' + >>> print(M.table(printer)) + [ 1, 2] + [-33, 4] + >>> print(M.table(printer, rowsep=',\n')) + [ 1, 2], + [-33, 4] + >>> print('[%s]' % M.table(printer, rowsep=',\n')) + [[ 1, 2], + [-33, 4]] + >>> print(M.table(printer, colsep=' ')) + [ 1 2] + [-33 4] + >>> print(M.table(printer, align='center')) + [ 1 , 2] + [-33, 4] + """ # Handle zero dimensions: if self.rows == 0 or self.cols == 0: return '[]' @@ -508,41 +612,65 @@ for i in range(self.rows): res.append([]) for j in range(self.cols): - string = strfunc(self[i,j]) - res[-1].append(string) - maxlen[j] = max(len(string), maxlen[j]) + s = printer._print(self[i,j]) + res[-1].append(s) + maxlen[j] = max(len(s), maxlen[j]) # Patch strings together + align = { + 'left': str.ljust, + 'right': str.rjust, + 'center': str.center, + '<': str.ljust, + '>': str.rjust, + '^': str.center, + }[align] for i, row in enumerate(res): for j, elem in enumerate(row): - # Pad each element up to maxlen so the columns line up - row[j] = elem.rjust(maxlen[j]) - res[i] = "[" + ", ".join(row) + "]" + row[j] = align(elem, maxlen[j]) + res[i] = "[" + colsep.join(row) + "]" return rowsep.join(res) + def _format_str(self, printer=None): + if not printer: + from sympy.printing.str import StrPrinter + printer = StrPrinter() + # Handle zero dimensions: + if self.rows == 0 or self.cols == 0: + return 'Matrix(%s, %s, [])' % (self.rows, self.cols) + if self.rows == 1: + return "Matrix([%s])" % self.table(printer, rowsep=',\n') + return "Matrix([\n%s])" % self.table(printer, rowsep=',\n') + def __str__(self): - return sstr(self) + if self.rows == 0 or self.cols == 0: + return 'Matrix(%s, %s, [])' % (self.rows, self.cols) + return "Matrix(%s)" % str(self.tolist()) def __repr__(self): return sstr(self) def cholesky(self): - """ - Returns the Cholesky Decomposition L of a Matrix A + """Returns the Cholesky decomposition L of a matrix A such that L * L.T = A A must be a square, symmetric, positive-definite - and non-singular matrix + and non-singular matrix. + + Examples + ======== >>> from sympy.matrices import Matrix - >>> A = Matrix(((25,15,-5),(15,18,0),(-5,0,11))) + >>> A = Matrix(((25, 15, -5), (15, 18, 0), (-5, 0, 11))) >>> A.cholesky() - [ 5, 0, 0] - [ 3, 3, 0] - [-1, 1, 3] + Matrix([ + [ 5, 0, 0], + [ 3, 3, 0], + [-1, 1, 3]]) >>> A.cholesky() * A.cholesky().T - [25, 15, -5] - [15, 18, 0] - [-5, 0, 11] + Matrix([ + [25, 15, -5], + [15, 18, 0], + [-5, 0, 11]]) See Also ======== @@ -558,40 +686,30 @@ raise ValueError("Matrix must be symmetric.") return self._cholesky() - def _cholesky(self): - """ - Helper function of cholesky. - Without the error checks. - To be used privately. """ - L = zeros(self.rows, self.rows) - for i in range(self.rows): - for j in range(i): - L[i, j] = (1 / L[j, j]) * (self[i, j] - sum(L[i, k] * L[j, k] - for k in range(j))) - L[i, i] = sqrt(self[i, i] - sum(L[i, k] ** 2 - for k in range(i))) - return self._new(L) - def LDLdecomposition(self): - """ - Returns the LDL Decomposition (L,D) of matrix A, + """Returns the LDL Decomposition (L, D) of matrix A, such that L * D * L.T == A This method eliminates the use of square root. Further this ensures that all the diagonal entries of L are 1. A must be a square, symmetric, positive-definite and non-singular matrix. + Examples + ======== + >>> from sympy.matrices import Matrix, eye - >>> A = Matrix(((25,15,-5),(15,18,0),(-5,0,11))) + >>> A = Matrix(((25, 15, -5), (15, 18, 0), (-5, 0, 11))) >>> L, D = A.LDLdecomposition() >>> L - [ 1, 0, 0] - [ 3/5, 1, 0] - [-1/5, 1/3, 1] + Matrix([ + [ 1, 0, 0], + [ 3/5, 1, 0], + [-1/5, 1/3, 1]]) >>> D - [25, 0, 0] - [ 0, 9, 0] - [ 0, 0, 9] + Matrix([ + [25, 0, 0], + [ 0, 9, 0], + [ 0, 0, 9]]) >>> L * D * L.T * A.inv() == eye(A.rows) True @@ -608,25 +726,8 @@ raise ValueError("Matrix must be symmetric.") return self._LDLdecomposition() - def _LDLdecomposition(self): - """ - Helper function of LDLdecomposition. - Without the error checks. - To be used privately. - """ - D = zeros(self.rows, self.rows) - L = eye(self.rows) - for i in range(self.rows): - for j in range(i): - L[i, j] = (1 / D[j, j]) * (self[i, j] - sum( - L[i, k] * L[j, k] * D[k, k] for k in range(j))) - D[i, i] = self[i, i] - sum(L[i, k]**2 * D[k, k] - for k in range(i)) - return self._new(L), self._new(D) - def lower_triangular_solve(self, rhs): - """ - Solves Ax = B, where A is a lower triangular matrix. + """Solves Ax = B, where A is a lower triangular matrix. See Also ======== @@ -643,27 +744,12 @@ raise NonSquareMatrixError("Matrix must be square.") if rhs.rows != self.rows: raise ShapeError("Matrices size mismatch.") - if not self.is_lower(): + if not self.is_lower: raise ValueError("Matrix must be lower triangular.") return self._lower_triangular_solve(rhs) - def _lower_triangular_solve(self, rhs): - """ - Helper function of function lower_triangular_solve. - Without the error checks. - To be used privately. - """ - X = zeros(self.rows, 1) - for i in range(self.rows): - if self[i, i] == 0: - raise TypeError("Matrix must be non-singular.") - X[i, 0] = (rhs[i, 0] - sum(self[i, k] * X[k, 0] - for k in range(i))) / self[i, i] - return self._new(X) - def upper_triangular_solve(self, rhs): - """ - Solves Ax = B, where A is an upper triangular matrix. + """Solves Ax = B, where A is an upper triangular matrix. See Also ======== @@ -679,25 +765,12 @@ raise NonSquareMatrixError("Matrix must be square.") if rhs.rows != self.rows: raise TypeError("Matrix size mismatch.") - if not self.is_upper(): + if not self.is_upper: raise TypeError("Matrix is not upper triangular.") return self._upper_triangular_solve(rhs) - def _upper_triangular_solve(self, rhs): - """ - Helper function of function upper_triangular_solve. - Without the error checks, to be used privately. """ - X = zeros(self.rows, 1) - for i in reversed(range(self.rows)): - if self[i, i] == 0: - raise ValueError("Matrix must be non-singular.") - X[i, 0] = (rhs[i, 0] - sum(self[i, k] * X[k, 0] - for k in range(i+1, self.rows))) / self[i, i] - return self._new(X) - def cholesky_solve(self, rhs): - """ - Solves Ax = B using Cholesky decomposition, + """Solves Ax = B using Cholesky decomposition, for a general square non-singular matrix. For a non-square matrix with rows > cols, the least squares solution is returned. @@ -715,18 +788,26 @@ if self.is_symmetric(): L = self._cholesky() elif self.rows >= self.cols: - L = (self.T * self)._cholesky() - rhs = self.T * rhs + L = (self.T*self)._cholesky() + rhs = self.T*rhs else: raise NotImplementedError("Under-determined System.") Y = L._lower_triangular_solve(rhs) return (L.T)._upper_triangular_solve(Y) def diagonal_solve(self, rhs): - """ - Solves Ax = B efficiently, where A is a diagonal Matrix, + """Solves Ax = B efficiently, where A is a diagonal Matrix, with non-zero diagonal entries. + Examples + ======== + + >>> from sympy.matrices import Matrix, eye + >>> A = eye(2)*2 + >>> B = Matrix([[1, 2], [3, 4]]) + >>> A.diagonal_solve(B) == B/2 + True + See Also ======== @@ -743,21 +824,22 @@ raise TypeError("Size mis-match") return self._diagonal_solve(rhs) - def _diagonal_solve(self, rhs): - """ - Helper function of function diagonal_solve, - without the error checks, to be used privately. - """ - return self._new(rhs.rows, 1, lambda i, j: rhs[i, 0] / self[i, i]) - def LDLsolve(self, rhs): - """ - Solves Ax = B using LDL decomposition, + """Solves Ax = B using LDL decomposition, for a general square and non-singular matrix. For a non-square matrix with rows > cols, the least squares solution is returned. + Examples + ======== + + >>> from sympy.matrices import Matrix, eye + >>> A = eye(2)*2 + >>> B = Matrix([[1, 2], [3, 4]]) + >>> A.LDLsolve(B) == B/2 + True + See Also ======== @@ -772,297 +854,171 @@ if self.is_symmetric(): L, D = self.LDLdecomposition() elif self.rows >= self.cols: - L, D = (self.T * self).LDLdecomposition() - rhs = self.T * rhs + L, D = (self.T*self).LDLdecomposition() + rhs = self.T*rhs else: raise NotImplementedError("Under-determined System.") Y = L._lower_triangular_solve(rhs) Z = D._diagonal_solve(Y) return (L.T)._upper_triangular_solve(Z) - def inv(self, method="GE", iszerofunc=_iszero, try_block_diag=False): - """ - Calculates the matrix inverse. - - According to the "method" parameter, it calls the appropriate method: + def solve_least_squares(self, rhs, method='CH'): + """Return the least-square fit to the data. - GE .... inverse_GE() - LU .... inverse_LU() - ADJ ... inverse_ADJ() - - According to the "try_block_diag" parameter, it will try to form block - diagonal matrices using the method get_diag_blocks(), invert these - individually, and then reconstruct the full inverse matrix. - - Note, the GE and LU methods may require the matrix to be simplified - before it is inverted in order to properly detect zeros during - pivoting. In difficult cases a custom zero detection function can - be provided by setting the iszerosfunc argument to a function that - should return True if its argument is zero. The ADJ routine computes - the determinant and uses that to detect singular matrices in addition - to testing for zeros on the diagonal. + By default the cholesky_solve routine is used (method='CH'); other + methods of matrix inversion can be used. To find out which are + available, see the docstring of the .inv() method. - See Also + Examples ======== - inverse_LU - inverse_GE - inverse_ADJ + >>> from sympy.matrices import Matrix, ones + >>> A = Matrix([1, 2, 3]) + >>> B = Matrix([2, 3, 4]) + >>> S = Matrix(A.row_join(B)) + >>> S + Matrix([ + [1, 2], + [2, 3], + [3, 4]]) + + If each line of S represent coefficients of Ax + By + and x and y are [2, 3] then S*xy is: + + >>> r = S*Matrix([2, 3]); r + Matrix([ + [ 8], + [13], + [18]]) + + But let's add 1 to the middle value and then solve for the + least-squares value of xy: + + >>> xy = S.solve_least_squares(Matrix([8, 14, 18])); xy + Matrix([ + [ 5/3], + [10/3]]) + + The error is given by S*xy - r: + + >>> S*xy - r + Matrix([ + [1/3], + [1/3], + [1/3]]) + >>> _.norm().n(2) + 0.58 + + If a different xy is used, the norm will be higher: + + >>> xy += ones(2, 1)/10 + >>> (S*xy - r).norm().n(2) + 1.5 + + """ + if method == 'CH': + return self.cholesky_solve(rhs) + t = self.T + return (t*self).inv(method=method)*t*rhs + + def solve(self, rhs, method='GE'): + """Return solution to self*soln = rhs using given inversion method. + + For a list of possible inversion methods, see the .inv() docstring. """ if not self.is_square: - raise NonSquareMatrixError() - if try_block_diag: - blocks = self.get_diag_blocks() - r = [] - for block in blocks: - r.append(block.inv(method=method, iszerofunc=iszerofunc)) - return diag(*r) - if method == "GE": - return self.inverse_GE(iszerofunc=iszerofunc) - elif method == "LU": - return self.inverse_LU(iszerofunc=iszerofunc) - elif method == "ADJ": - return self.inverse_ADJ(iszerofunc=iszerofunc) + if self.rows < self.cols: + raise ValueError('Under-determined system.') + elif self.rows > self.cols: + raise ValueError('For over-determined system, M, having ' + 'more rows than columns, try M.solve_least_squares(rhs).') else: - # make sure to add an invertibility check (as in inverse_LU) - # if a new method is added. - raise ValueError("Inversion method unrecognized") - - def _eval_inverse(self): - return self.inv() + return self.inv(method=method)*rhs def __mathml__(self): mml = "" for i in range(self.rows): mml += "" for j in range(self.cols): - mml += self[i,j].__mathml__() + mml += self[i, j].__mathml__() mml += "" return "" + mml + "" - def row_join(self, rhs): + def submatrix(self, keys): """ - Concatenates two matrices along self's last and rhs's first column + Get a slice/submatrix of the matrix using the given slice. + + Examples + ======== >>> from sympy import Matrix - >>> M = Matrix(3,3,lambda i,j: i+j) - >>> V = Matrix(3,1,lambda i,j: 3+i+j) - >>> M.row_join(V) - [0, 1, 2, 3] - [1, 2, 3, 4] - [2, 3, 4, 5] + >>> m = Matrix(4, 4, lambda i, j: i+j) + >>> m + Matrix([ + [0, 1, 2, 3], + [1, 2, 3, 4], + [2, 3, 4, 5], + [3, 4, 5, 6]]) + >>> m[:1, 1] + Matrix([[1]]) + >>> m[:2, :1] + Matrix([ + [0], + [1]]) + >>> m[2:4, 2:4] + Matrix([ + [4, 5], + [5, 6]]) See Also ======== - row - col_join + extract """ - if self.rows != rhs.rows: - raise ShapeError("`self` and `rhs` must have the same number of rows.") + rlo, rhi, clo, chi = self.key2bounds(keys) + rows, cols = rhi - rlo, chi - clo + mat = [S.Zero]*rows*cols + for i in range(rows): + mat[i*cols:(i + 1)*cols] = \ + self._mat[(i + rlo)*self.cols + clo:(i + rlo)*self.cols + chi] + return self._new(rows, cols, mat) - newmat = self.zeros(self.rows, self.cols + rhs.cols) - newmat[:,:self.cols] = self[:,:] - newmat[:,self.cols:] = rhs - return newmat - - def col_join(self, bott): - """ - Concatenates two matrices along self's last and bott's first row - - >>> from sympy import Matrix, ones - >>> M = ones(3, 3) - >>> V = Matrix([[7,7,7]]) - >>> M.col_join(V) - [1, 1, 1] - [1, 1, 1] - [1, 1, 1] - [7, 7, 7] - - See Also - ======== - - col - row_join - """ - if self.cols != bott.cols: - raise ShapeError("`self` and `bott` must have the same number of columns.") - - newmat = self.zeros(self.rows+bott.rows, self.cols) - newmat[:self.rows,:] = self[:,:] - newmat[self.rows:,:] = bott - return newmat - - def row_insert(self, pos, mti): - """ - Insert a row at the given position. - - >>> from sympy import Matrix, zeros - >>> M = Matrix(3,3,lambda i,j: i+j) - >>> M - [0, 1, 2] - [1, 2, 3] - [2, 3, 4] - >>> V = zeros(1, 3) - >>> V - [0, 0, 0] - >>> M.row_insert(1,V) - [0, 1, 2] - [0, 0, 0] - [1, 2, 3] - [2, 3, 4] - - See Also - ======== - - row - col_insert - """ - if pos == 0: - return mti.col_join(self) - elif pos < 0: - pos = self.rows + pos - if pos < 0: - pos = 0 - elif pos > self.rows: - pos = self.rows - - if self.cols != mti.cols: - raise ShapeError("`self` and `mti` must have the same number of columns.") - - newmat = self.zeros(self.rows + mti.rows, self.cols) - newmat[:pos,:] = self[:pos,:] - newmat[pos:pos+mti.rows,:] = mti[:,:] - newmat[pos+mti.rows:,:] = self[pos:,:] - return newmat - - def col_insert(self, pos, mti): - """ - Insert a column at the given position. - - >>> from sympy import Matrix, zeros - >>> M = Matrix(3,3,lambda i,j: i+j) - >>> M - [0, 1, 2] - [1, 2, 3] - [2, 3, 4] - >>> V = zeros(3, 1) - >>> V - [0] - [0] - [0] - >>> M.col_insert(1,V) - [0, 0, 1, 2] - [1, 0, 2, 3] - [2, 0, 3, 4] - - See Also - ======== - - col - row_insert - """ - if pos == 0: - return mti.row_join(self) - elif pos < 0: - pos = self.cols + pos - if pos < 0: - pos = 0 - elif pos > self.cols: - pos = self.cols - - if self.rows != mti.rows: - raise ShapeError("self and mti must have the same number of rows.") - - newmat = self.zeros(self.rows, self.cols + mti.cols) - newmat[:,:pos] = self[:,:pos] - newmat[:,pos:pos+mti.cols] = mti[:,:] - newmat[:,pos+mti.cols:] = self[:,pos:] - return newmat - - def trace(self): - """ - Calculate the trace of a (square) matrix. - - >>> import sympy - >>> M = sympy.matrices.eye(3) - >>> M.trace() - 3 - - """ - if not self.is_square: - raise NonSquareMatrixError() - - trace = 0 - for i in range(self.cols): - trace += self[i,i] - return trace - - def submatrix(self, keys): - """ - Get a slice/submatrix of the matrix using the given slice. - - >>> from sympy import Matrix - >>> m = Matrix(4,4,lambda i,j: i+j) - >>> m #doctest: +NORMALIZE_WHITESPACE - [0, 1, 2, 3] - [1, 2, 3, 4] - [2, 3, 4, 5] - [3, 4, 5, 6] - >>> m[:1, 1] #doctest: +NORMALIZE_WHITESPACE - [1] - >>> m[:2, :1] #doctest: +NORMALIZE_WHITESPACE - [0] - [1] - >>> m[2:4, 2:4] #doctest: +NORMALIZE_WHITESPACE - [4, 5] - [5, 6] - - See Also - ======== - - extract - """ - rlo, rhi, clo, chi = self.key2bounds(keys) - outLines, outCols = rhi-rlo, chi-clo - outMat = [0]*outLines*outCols - for i in range(outLines): - outMat[i*outCols:(i+1)*outCols] = self.mat[(i+rlo)*self.cols+clo:(i+rlo)*self.cols+chi] - return self._new(outLines,outCols,outMat) - - def extract(self, rowsList, colsList): - """ - Extract a submatrix by specifying a list of rows and columns. - Negative indices can be given. All indices must be in the range - -n <= i < n where n is the number of rows or columns. + def extract(self, rowsList, colsList): + """Return a submatrix by specifying a list of rows and columns. + Negative indices can be given. All indices must be in the range + -n <= i < n where n is the number of rows or columns. Examples ======== >>> from sympy import Matrix >>> m = Matrix(4, 3, list(range(12))) - >>> m #doctest: +NORMALIZE_WHITESPACE - [0, 1, 2] - [3, 4, 5] - [6, 7, 8] - [9, 10, 11] - >>> m.extract([0,1,3],[0,1]) #doctest: +NORMALIZE_WHITESPACE - [0, 1] - [3, 4] - [9, 10] + >>> m + Matrix([ + [0, 1, 2], + [3, 4, 5], + [6, 7, 8], + [9, 10, 11]]) + >>> m.extract([0, 1, 3], [0, 1]) + Matrix([ + [0, 1], + [3, 4], + [9, 10]]) Rows or columns can be repeated: - >>> m.extract([0,0,1], [-1]) #doctest: +NORMALIZE_WHITESPACE - [2] - [2] - [5] + >>> m.extract([0, 0, 1], [-1]) + Matrix([ + [2], + [2], + [5]]) Every other row can be taken by using range to provide the indices: - >>> m.extract(list(range(0, m.rows, 2)),[-1]) #doctest: +NORMALIZE_WHITESPACE - [2] - [8] + >>> m.extract(list(range(0, m.rows, 2)), [-1]) + Matrix([ + [2], + [8]]) See Also ======== @@ -1070,11 +1026,11 @@ submatrix """ cols = self.cols - mat = self.mat - rowsList = [self.key2ij((k,0))[0] for k in rowsList] - colsList = [self.key2ij((0,k))[1] for k in colsList] + flat_list = self._mat + rowsList = [a2idx(k, self.rows) for k in rowsList] + colsList = [a2idx(k, self.cols) for k in colsList] return self._new(len(rowsList), len(colsList), - lambda i,j: mat[rowsList[i]*cols + colsList[j]]) + lambda i, j: flat_list[rowsList[i]*cols + colsList[j]]) def key2bounds(self, keys): """Converts a key with potentially mixed types of keys (integer and slice) @@ -1085,88 +1041,49 @@ ======== key2ij - slice2bounds """ islice, jslice = [isinstance(k, slice) for k in keys] if islice: - rlo, rhi = self.slice2bounds(keys[0], self.rows) + if not self.rows: + rlo = rhi = 0 + else: + rlo, rhi = keys[0].indices(self.rows)[:2] else: - # assuming we don't have a - rlo, _ = self.slice2bounds((keys[0], 0), self.rows) - rhi = rlo + 1 + rlo = a2idx(keys[0], self.rows) + rhi = rlo + 1 if jslice: - clo, chi = self.slice2bounds(keys[1], self.cols) + if not self.cols: + clo = chi = 0 + else: + clo, chi = keys[1].indices(self.cols)[:2] else: - _, clo = self.slice2bounds((0, keys[1]), self.cols) + clo = a2idx(keys[1], self.cols) chi = clo + 1 - if not ( 0<=rlo<=rhi and 0<=clo<=chi ): - raise IndexError("Slice indices out of range: a[%s]"%repr(keys)) return rlo, rhi, clo, chi def key2ij(self, key): - """Converts key=(4,6) to 4,6 and ensures the key is correct. Negative - indices are also supported and are remapped to positives provided they - are valid indices. - - See Also - ======== - - key2bounds - slice2bounds - """ - - if not (is_sequence(key) and len(key) == 2): - raise TypeError("wrong syntax: a[%s]. Use a[i,j] or a[(i,j)]" - %repr(key)) - i, j = [(k + n) if k < 0 else k for k, n in zip(key, (self.rows, self.cols))] - if not (i>=0 and i=0 and j < self.cols): - raise IndexError("Index out of range: a[%s]"%repr(key)) - return i,j - - def slice2bounds(self, key, defmax): - """ - Takes slice or number and returns (min,max) for iteration - Takes a default maxval to deal with the slice ':' which is (none, none) + """Converts key into canonical form, converting integers or indexable + items into valid integers for self's range or returning slices + unchanged. See Also ======== key2bounds - key2ij """ - if isinstance(key, slice): - return key.indices(defmax)[:2] - elif isinstance(key, tuple): - key = [defmax - 1 if i == -1 else i for i in key] - return self.key2ij(key) + if is_sequence(key): + if not len(key) == 2: + raise TypeError('key must be a sequence of length 2') + return [a2idx(i, n) if not isinstance(i, slice) else i + for i, n in zip(key, self.shape)] + elif isinstance(key, slice): + return key.indices(len(self))[:2] else: - raise IndexError("Improper index type") - - def applyfunc(self, f): - """ - Apply a function to each element of the matrix. - - >>> from sympy import Matrix - >>> m = Matrix(2,2,lambda i,j: i*2+j) - >>> m #doctest: +NORMALIZE_WHITESPACE - [0, 1] - [2, 3] - >>> m.applyfunc(lambda i: 2*i) #doctest: +NORMALIZE_WHITESPACE - [0, 2] - [4, 6] - - """ - if not isinstance(f, collections.Callable): - raise TypeError("`f` must be callable.") - - out = self._new(self.rows, self.cols, list(map(f,self.mat))) - return out + return divmod(a2idx(key, len(self)), self.cols) def evalf(self, prec=None, **options): - """ - Evaluate each element of the matrix as a float. - """ + """Apply evalf() to each element of self.""" if prec is None: return self.applyfunc(lambda i: i.evalf(**options)) else: @@ -1174,44 +1091,79 @@ n = evalf - def reshape(self, _rows, _cols): - """ - Reshape the matrix. Total number of elements must remain the same. + def subs(self, *args, **kwargs): # should mirror core.basic.subs + """Return a new matrix with subs applied to each entry. - >>> from sympy import Matrix - >>> m = Matrix(2,3,lambda i,j: 1) - >>> m #doctest: +NORMALIZE_WHITESPACE - [1, 1, 1] - [1, 1, 1] - >>> m.reshape(1,6) #doctest: +NORMALIZE_WHITESPACE - [1, 1, 1, 1, 1, 1] - >>> m.reshape(3,2) #doctest: +NORMALIZE_WHITESPACE - [1, 1] - [1, 1] - [1, 1] + Examples + ======== + + >>> from sympy.abc import x, y + >>> from sympy.matrices import SparseMatrix, Matrix + >>> SparseMatrix(1, 1, [x]) + Matrix([[x]]) + >>> _.subs(x, y) + Matrix([[y]]) + >>> Matrix(_).subs(y, x) + Matrix([[x]]) + """ + return self.applyfunc(lambda x: x.subs(*args, **kwargs)) + + def expand(self, deep=True, modulus=None, power_base=True, power_exp=True, + mul=True, log=True, multinomial=True, basic=True, **hints): + """Apply core.function.expand to each entry of the matrix. + + Examples + ======== + + >>> from sympy.abc import x + >>> from sympy.matrices import Matrix + >>> Matrix(1, 1, [x*(x+1)]) + Matrix([[x*(x + 1)]]) + >>> _.expand() + Matrix([[x**2 + x]]) """ - if len(self) != _rows*_cols: - raise ValueError("Invalid reshape parameters %d %d" % (_rows, _cols)) - return self._new(_rows, _cols, lambda i,j: self.mat[i*_cols + j]) + return self.applyfunc(lambda x: x.expand( + deep, modulus, power_base, power_exp, mul, log, multinomial, basic, + **hints)) + + def simplify(self, ratio=1.7, measure=count_ops): + """Apply simplify to each element of the matrix. - def print_nonzero (self, symb="X"): + Examples + ======== + + >>> from sympy.abc import x, y + >>> from sympy import sin, cos + >>> from sympy.matrices import SparseMatrix + >>> SparseMatrix(1, 1, [x*sin(y)**2 + x*cos(y)**2]) + Matrix([[x*sin(y)**2 + x*cos(y)**2]]) + >>> _.simplify() + Matrix([[x]]) """ - Shows location of non-zero entries for fast shape lookup. + return self.applyfunc(lambda x: x.simplify(ratio, measure)) + _eval_simplify = simplify + + def doit(self, **kwargs): + return self + + def print_nonzero(self, symb="X"): + """Shows location of non-zero entries for fast shape lookup. Examples ======== - >>> from sympy import Matrix, matrices - >>> m = Matrix(2,3,lambda i,j: i*3+j) - >>> m #doctest: +NORMALIZE_WHITESPACE - [0, 1, 2] - [3, 4, 5] - >>> m.print_nonzero() #doctest: +NORMALIZE_WHITESPACE + >>> from sympy.matrices import Matrix, eye + >>> m = Matrix(2, 3, lambda i, j: i*3+j) + >>> m + Matrix([ + [0, 1, 2], + [3, 4, 5]]) + >>> m.print_nonzero() [ XX] [XXX] - >>> m = matrices.eye(4) - >>> m.print_nonzero("x") #doctest: +NORMALIZE_WHITESPACE + >>> m = eye(4) + >>> m.print_nonzero("x") [x ] [ x ] [ x ] @@ -1222,7 +1174,7 @@ for i in range(self.rows): line = [] for j in range(self.cols): - if self[i,j] == 0: + if self[i, j] == 0: line.append(" ") else: line.append(str(symb)) @@ -1230,9 +1182,7 @@ print('\n'.join(s)) def LUsolve(self, rhs, iszerofunc=_iszero): - """ - Solve the linear system Ax = b for x. - self is the coefficient matrix A and rhs is the right side b. + """Solve the linear system Ax = rhs for x where A = self. This is for symbolic matrices, for real or complex ones use sympy.mpmath.lu_solve or sympy.mpmath.qr_solve. @@ -1257,17 +1207,19 @@ # forward substitution, all diag entries are scaled to 1 for i in range(n): for j in range(i): - b.row(i, lambda x,k: x - b[j,k]*A[i,j]) + scale = A[i, j] + b.zip_row_op(i, j, lambda x, y: x - y*scale) # backward substitution - for i in range(n-1,-1,-1): - for j in range(i+1, n): - b.row(i, lambda x,k: x - b[j,k]*A[i,j]) - b.row(i, lambda x,k: x / A[i,i]) + for i in range(n - 1, -1, -1): + for j in range(i + 1, n): + scale = A[i, j] + b.zip_row_op(i, j, lambda x, y: x - y*scale) + scale = A[i, i] + b.row_op(i, lambda x, _: x/scale) return rhs.__class__(b) def LUdecomposition(self, iszerofunc=_iszero): - """ - Returns the decomposition LU and the row swaps p. + """Returns the decomposition LU and the row swaps p. Examples ======== @@ -1276,11 +1228,13 @@ >>> a = Matrix([[4, 3], [6, 3]]) >>> L, U, _ = a.LUdecomposition() >>> L - [ 1, 0] - [3/2, 1] + Matrix([ + [ 1, 0], + [3/2, 1]]) >>> U - [4, 3] - [0, -3/2] + Matrix([ + [4, 3], + [0, -3/2]]) See Also ======== @@ -1298,16 +1252,15 @@ for i in range(self.rows): for j in range(self.rows): if i > j: - L[i,j] = combined[i,j] + L[i, j] = combined[i, j] else: if i == j: - L[i,i] = 1 - U[i,j] = combined[i,j] + L[i, i] = 1 + U[i, j] = combined[i, j] return L, U, p def LUdecomposition_Simple(self, iszerofunc=_iszero): - """ - Returns A comprised of L,U (L's diag entries are 1) and + """Returns A comprised of L, U (L's diag entries are 1) and p which is the list of the row swaps (in order). See Also @@ -1318,7 +1271,7 @@ LUsolve """ if not self.is_square: - raise NonSquareMatrixError() + raise NonSquareMatrixError("A Matrix must be square to apply LUdecomposition_Simple().") n = self.rows A = self.as_mutable() p = [] @@ -1326,30 +1279,28 @@ for j in range(n): for i in range(j): for k in range(i): - A[i,j] = A[i,j] - A[i,k]*A[k,j] + A[i, j] = A[i, j] - A[i, k]*A[k, j] pivot = -1 - for i in range(j,n): + for i in range(j, n): for k in range(j): - A[i,j] = A[i,j] - A[i,k]*A[k,j] + A[i, j] = A[i, j] - A[i, k]*A[k, j] # find the first non-zero pivot, includes any expression - if pivot == -1 and not iszerofunc(A[i,j]): + if pivot == -1 and not iszerofunc(A[i, j]): pivot = i if pivot < 0: # this result is based on iszerofunc's analysis of the possible pivots, so even though # the element may not be strictly zero, the supplied iszerofunc's evaluation gave True raise ValueError("No nonzero pivot found; inversion failed.") - if pivot != j: # row must be swapped - A.row_swap(pivot,j) - p.append([pivot,j]) - scale = 1 / A[j,j] - for i in range(j+1,n): - A[i,j] = A[i,j] * scale + if pivot != j: # row must be swapped + A.row_swap(pivot, j) + p.append([pivot, j]) + scale = 1 / A[j, j] + for i in range(j + 1, n): + A[i, j] = A[i, j]*scale return A, p - def LUdecompositionFF(self): - """ - Compute a fraction-free LU decomposition. + """Compute a fraction-free LU decomposition. Returns 4 matrices P, L, D, U such that PA = L D**-1 U. If the elements of the matrix belong to some integral domain I, then all @@ -1367,14 +1318,18 @@ LUdecomposition_Simple LUsolve """ + from sympy.matrices import SparseMatrix + zeros = SparseMatrix.zeros + eye = SparseMatrix.eye + n, m = self.rows, self.cols U, L, P = self.as_mutable(), eye(n), eye(n) - DD = zeros(n) # store it smarter since it's just diagonal + DD = zeros(n, n) oldpivot = 1 - for k in range(n-1): - if U[k,k] == 0: - for kpivot in range(k+1, n): + for k in range(n - 1): + if U[k, k] == 0: + for kpivot in range(k + 1, n): if U[kpivot, k]: break else: @@ -1382,20 +1337,19 @@ U[k, k:], U[kpivot, k:] = U[kpivot, k:], U[k, k:] L[k, :k], L[kpivot, :k] = L[kpivot, :k], L[k, :k] P[k, :], P[kpivot, :] = P[kpivot, :], P[k, :] - L[k,k] = Ukk = U[k,k] - DD[k,k] = oldpivot * Ukk - for i in range(k+1, n): - L[i,k] = Uik = U[i,k] - for j in range(k+1, m): - U[i,j] = (Ukk * U[i,j] - U[k,j]*Uik) / oldpivot - U[i,k] = 0 + L[k, k] = Ukk = U[k, k] + DD[k, k] = oldpivot*Ukk + for i in range(k + 1, n): + L[i, k] = Uik = U[i, k] + for j in range(k + 1, m): + U[i, j] = (Ukk*U[i, j] - U[k, j]*Uik) / oldpivot + U[i, k] = 0 oldpivot = Ukk - DD[n-1,n-1] = oldpivot + DD[n - 1, n - 1] = oldpivot return P, L, DD, U def cofactorMatrix(self, method="berkowitz"): - """ - Return a matrix containing the cofactor of each element. + """Return a matrix containing the cofactor of each element. See Also ======== @@ -1405,13 +1359,12 @@ minorMatrix adjugate """ - out = self._new(self.rows, self.cols, lambda i,j: + out = self._new(self.rows, self.cols, lambda i, j: self.cofactor(i, j, method)) return out def minorEntry(self, i, j, method="berkowitz"): - """ - Calculate the minor of an element. + """Calculate the minor of an element. See Also ======== @@ -1423,11 +1376,10 @@ if not 0 <= i < self.rows or not 0 <= j < self.cols: raise ValueError("`i` and `j` must satisfy 0 <= i < `self.rows` " + "(%d)" % self.rows + "and 0 <= j < `self.cols` (%d)." % self.cols) - return self.minorMatrix(i,j).det(method) + return self.minorMatrix(i, j).det(method) def minorMatrix(self, i, j): - """ - Creates the minor matrix of a given element. + """Creates the minor matrix of a given element. See Also ======== @@ -1439,11 +1391,13 @@ if not 0 <= i < self.rows or not 0 <= j < self.cols: raise ValueError("`i` and `j` must satisfy 0 <= i < `self.rows` " + "(%d)" % self.rows + "and 0 <= j < `self.cols` (%d)." % self.cols) - return self.delRowCol(i,j) + M = self.as_mutable() + M.row_del(i) + M.col_del(j) + return self._new(M) def cofactor(self, i, j, method="berkowitz"): - """ - Calculate the cofactor of an element. + """Calculate the cofactor of an element. See Also ======== @@ -1452,38 +1406,40 @@ minorEntry minorMatrix """ - if (i+j) % 2 == 0: + if (i + j) % 2 == 0: return self.minorEntry(i, j, method) else: - return -1 * self.minorEntry(i, j, method) + return -1*self.minorEntry(i, j, method) def jacobian(self, X): - """ - Calculates the Jacobian matrix (derivative of a vectorial function). + """Calculates the Jacobian matrix (derivative of a vectorial function). + + Parameters + ========== - *self* - A vector of expressions representing functions f_i(x_1, ..., x_n). - *X* - The set of x_i's in order, it can be a list or a Matrix + self : vector of expressions representing functions f_i(x_1, ..., x_n). + X : set of x_i's in order, it can be a list or a Matrix Both self and X can be a row or a column matrix in any order - (jacobian() should always work). + (i.e., jacobian() should always work). Examples ======== - >>> from sympy import sin, cos, Matrix - >>> from sympy.abc import rho, phi - >>> X = Matrix([rho*cos(phi), rho*sin(phi), rho**2]) - >>> Y = Matrix([rho, phi]) - >>> X.jacobian(Y) - [cos(phi), -rho*sin(phi)] - [sin(phi), rho*cos(phi)] - [ 2*rho, 0] - >>> X = Matrix([rho*cos(phi), rho*sin(phi)]) - >>> X.jacobian(Y) - [cos(phi), -rho*sin(phi)] - [sin(phi), rho*cos(phi)] + >>> from sympy import sin, cos, Matrix + >>> from sympy.abc import rho, phi + >>> X = Matrix([rho*cos(phi), rho*sin(phi), rho**2]) + >>> Y = Matrix([rho, phi]) + >>> X.jacobian(Y) + Matrix([ + [cos(phi), -rho*sin(phi)], + [sin(phi), rho*cos(phi)], + [ 2*rho, 0]]) + >>> X = Matrix([rho*cos(phi), rho*sin(phi)]) + >>> X.jacobian(Y) + Matrix([ + [cos(phi), -rho*sin(phi)], + [sin(phi), rho*cos(phi)]]) See Also ======== @@ -1513,40 +1469,43 @@ return self._new(m, n, lambda j, i: self[j].diff(X[i])) def QRdecomposition(self): - """ - Return Q,R where A = Q*R, Q is orthogonal and R is upper triangular. + """Return Q, R where A = Q*R, Q is orthogonal and R is upper triangular. Examples ======== This is the example from wikipedia: - >>> from sympy import Matrix, eye - >>> A = Matrix([[12,-51,4],[6,167,-68],[-4,24,-41]]) + >>> from sympy import Matrix + >>> A = Matrix([[12, -51, 4], [6, 167, -68], [-4, 24, -41]]) >>> Q, R = A.QRdecomposition() >>> Q - [ 6/7, -69/175, -58/175] - [ 3/7, 158/175, 6/175] - [-2/7, 6/35, -33/35] + Matrix([ + [ 6/7, -69/175, -58/175], + [ 3/7, 158/175, 6/175], + [-2/7, 6/35, -33/35]]) >>> R - [14, 21, -14] - [ 0, 175, -70] - [ 0, 0, 35] + Matrix([ + [14, 21, -14], + [ 0, 175, -70], + [ 0, 0, 35]]) >>> A == Q*R True QR factorization of an identity matrix: - >>> A = Matrix([[1,0,0],[0,1,0],[0,0,1]]) + >>> A = Matrix([[1, 0, 0], [0, 1, 0], [0, 0, 1]]) >>> Q, R = A.QRdecomposition() >>> Q - [1, 0, 0] - [0, 1, 0] - [0, 0, 1] + Matrix([ + [1, 0, 0], + [0, 1, 0], + [0, 0, 1]]) >>> R - [1, 0, 0] - [0, 1, 0] - [0, 0, 1] + Matrix([ + [1, 0, 0], + [0, 1, 0], + [0, 0, 1]]) See Also ======== @@ -1560,35 +1519,36 @@ self = self.as_mutable() if not self.rows >= self.cols: - raise MatrixError("The number of rows must be greater than columns") + raise MatrixError( + "The number of rows must be greater than columns") n = self.rows m = self.cols rank = n row_reduced = self.rref()[0] for i in range(row_reduced.rows): - if MutableMatrix(row_reduced[i*m:(i+1)*m]).norm() == 0: + if row_reduced.row(i).norm() == 0: rank -= 1 if not rank == self.cols: raise MatrixError("The rank of the matrix must match the columns") Q, R = self.zeros(n, m), self.zeros(m) for j in range(m): # for each column vector - tmp = self[:,j] # take original v + tmp = self[:, j] # take original v for i in range(j): # subtract the project of self on new vector - tmp -= Q[:,i] * self[:,j].dot(Q[:,i]) + tmp -= Q[:, i]*self[:, j].dot(Q[:, i]) tmp.expand() # normalize it - R[j,j] = tmp.norm() - Q[:,j] = tmp / R[j,j] - if Q[:,j].norm() != 1: - raise NotImplementedError("Could not normalize the vector %d." % j) + R[j, j] = tmp.norm() + Q[:, j] = tmp / R[j, j] + if Q[:, j].norm() != 1: + raise NotImplementedError( + "Could not normalize the vector %d." % j) for i in range(j): - R[i,j] = Q[:,i].dot(self[:,j]) + R[i, j] = Q[:, i].dot(self[:, j]) return cls(Q), cls(R) def QRsolve(self, b): - """ - Solve the linear system 'Ax = b'. + """Solve the linear system 'Ax = b'. 'self' is the matrix 'A', the method argument is the vector 'b'. The method returns the solution vector 'x'. If 'b' is a @@ -1616,7 +1576,7 @@ """ Q, R = self.as_mutable().QRdecomposition() - y = Q.T * b + y = Q.T*b # back substitution to solve R*x = y: # We build up the result "backwards" in the vector 'x' and reverse it @@ -1624,20 +1584,14 @@ x = [] n = R.rows for j in range(n - 1, -1, -1): - tmp = y[j,:] - for k in range(j+1, n): - tmp -= R[j,k] * x[n-1-k] - x.append(tmp/R[j,j]) - return self._new([row.mat for row in reversed(x)]) - - #def evaluate(self): # no more eval() so should be removed - # for i in range(self.rows): - # for j in range(self.cols): - # self[i,j] = self[i,j].eval() + tmp = y[j, :] + for k in range(j + 1, n): + tmp -= R[j, k]*x[n - 1 - k] + x.append(tmp / R[j, j]) + return self._new([row._mat for row in reversed(x)]) def cross(self, b): - """ - Calculate the cross product of ``self`` and ``b``. + """Calculate the cross product of ``self`` and ``b``. See Also ======== @@ -1646,16 +1600,16 @@ multiply multiply_elementwise """ - if not is_sequence(b, include=MatrixBase): + if not is_sequence(b): raise TypeError("`b` must be an ordered iterable or Matrix, not %s." % type(b)) - if not (self.rows == 1 and self.cols == 3 or \ - self.rows == 3 and self.cols == 1 ) and \ - (b.rows == 1 and b.cols == 3 or \ - b.rows == 3 and b.cols == 1): + if not ((self.rows == 1 and self.cols == 3 or + self.rows == 3 and self.cols == 1) and \ + (b.rows == 1 and b.cols == 3 or + b.rows == 3 and b.cols == 1)): raise ShapeError("Dimensions incorrect for cross product.") else: - return self._new(1,3,((self[1]*b[2] - self[2]*b[1]), + return self._new(1, 3, ((self[1]*b[2] - self[2]*b[1]), (self[2]*b[0] - self[0]*b[2]), (self[0]*b[1] - self[1]*b[0]))) @@ -1667,8 +1621,11 @@ of results is returned (and in that case the number of columns in self must match the length of b). + Examples + ======== + >>> from sympy import Matrix - >>> M = Matrix([[1,2,3], [4,5,6], [7,8,9]]) + >>> M = Matrix([[1, 2, 3], [4, 5, 6], [7, 8, 9]]) >>> v = [1, 1, 1] >>> M.row(0).dot(v) 6 @@ -1684,11 +1641,13 @@ multiply multiply_elementwise """ + from .dense import Matrix + if not isinstance(b, MatrixBase): if is_sequence(b): if len(b) != self.cols and len(b) != self.rows: raise ShapeError("Dimensions incorrect for dot product.") - return self.dot(MutableMatrix(b)) + return self.dot(Matrix(b)) else: raise TypeError("`b` must be an ordered iterable or Matrix, not %s." % type(b)) @@ -1710,12 +1669,16 @@ def multiply_elementwise(self, b): """Return the Hadamard product (elementwise product) of A and B - >>> from sympy.matrices.matrices import Matrix + Examples + ======== + + >>> from sympy.matrices import Matrix >>> A = Matrix([[0, 1, 2], [3, 4, 5]]) >>> B = Matrix([[1, 10, 100], [100, 10, 1]]) >>> A.multiply_elementwise(B) - [ 0, 10, 200] - [300, 40, 5] + Matrix([ + [ 0, 10, 200], + [300, 40, 5]]) See Also ======== @@ -1724,8 +1687,14 @@ dot multiply """ + from sympy.matrices import matrix_multiply_elementwise + return matrix_multiply_elementwise(self, b) + def values(self): + """Return non-zero values of self.""" + return [i for i in flatten(self.tolist()) if not i.is_zero] + def norm(self, ord=None): """Return the Norm of a Matrix or Vector. In the simplest case this is the geometric size of the vector @@ -1746,20 +1715,27 @@ other - does not exist sum(abs(x)**ord)**(1./ord) ===== ============================ ========================== - >>> from sympy import Matrix, Symbol, trigsimp, cos, sin + Examples + ======== + + >>> from sympy import Matrix, Symbol, trigsimp, cos, sin, oo >>> x = Symbol('x', real=True) >>> v = Matrix([cos(x), sin(x)]) >>> trigsimp( v.norm() ) 1 >>> v.norm(10) (sin(x)**10 + cos(x)**10)**(1/10) - >>> A = Matrix([[1,1], [1,1]]) + >>> A = Matrix([[1, 1], [1, 1]]) >>> A.norm(2)# Spectral norm (max of |Ax|/|x| under 2-vector-norm) 2 >>> A.norm(-2) # Inverse spectral norm (smallest singular value) 0 >>> A.norm() # Frobenius Norm 2 + >>> Matrix([1, -2]).norm(oo) + 2 + >>> Matrix([-1, 2]).norm(-oo) + 1 See Also ======== @@ -1767,29 +1743,30 @@ normalized """ # Row or Column Vector Norms + vals = list(self.values()) or [0] if self.rows == 1 or self.cols == 1: - if ord == 2 or ord == None: # Common case sqrt() - return sqrt(Add(*(abs(i)**2 for i in self.mat))) + if ord == 2 or ord is None: # Common case sqrt() + return sqrt(Add(*(abs(i)**2 for i in vals))) - elif ord == 1: # sum(abs(x)) - return Add(*(abs(i) for i in self.mat)) + elif ord == 1: # sum(abs(x)) + return Add(*(abs(i) for i in vals)) - elif ord == S.Infinity: # max(abs(x)) - return Max(*self.applyfunc(abs)) + elif ord == S.Infinity: # max(abs(x)) + return Max(*[abs(i) for i in vals]) - elif ord == S.NegativeInfinity: # min(abs(x)) - return Min(*self.applyfunc(abs)) + elif ord == S.NegativeInfinity: # min(abs(x)) + return Min(*[abs(i) for i in vals]) # Otherwise generalize the 2-norm, Sum(x_i**ord)**(1/ord) # Note that while useful this is not mathematically a norm try: - return Pow( Add(*(abs(i)**ord for i in self.mat)), S(1)/ord ) - except TypeError: + return Pow(Add(*(abs(i)**ord for i in vals)), S(1) / ord) + except (NotImplementedError, TypeError): raise ValueError("Expected order to be Number, Symbol, oo") # Matrix Norms else: - if ord == 2: # Spectral Norm + if ord == 2: # Spectral Norm # Maximum singular value return Max(*self.singular_values()) @@ -1797,7 +1774,7 @@ # Minimum singular value return Min(*self.singular_values()) - elif (ord == None or isinstance(ord,str) and ord.lower() in + elif (ord is None or isinstance(ord, str) and ord.lower() in ['f', 'fro', 'frobenius', 'vector']): # Reshape as vector and send back to norm function return self.vec().norm(ord=2) @@ -1806,8 +1783,7 @@ raise NotImplementedError("Matrix Norms under development") def normalized(self): - """ - Return the normalized version of ``self``. + """Return the normalized version of ``self``. See Also ======== @@ -1823,136 +1799,83 @@ def project(self, v): """Return the projection of ``self`` onto the line containing ``v``. + Examples + ======== + >>> from sympy import Matrix, S, sqrt - >>> V = Matrix([sqrt(3)/2,S.Half]) + >>> V = Matrix([sqrt(3)/2, S.Half]) >>> x = Matrix([[1, 0]]) >>> V.project(x) - [sqrt(3)/2, 0] + Matrix([[sqrt(3)/2, 0]]) >>> V.project(-x) - [sqrt(3)/2, 0] + Matrix([[sqrt(3)/2, 0]]) """ - return v * (self.dot(v) / v.dot(v)) + return v*(self.dot(v) / v.dot(v)) def permuteBkwd(self, perm): - """ - Permute the rows of the matrix with the given permutation in reverse. + """Permute the rows of the matrix with the given permutation in reverse. + + Examples + ======== - >>> import sympy - >>> M = sympy.matrices.eye(3) - >>> M.permuteBkwd([[0,1],[0,2]]) - [0, 1, 0] - [0, 0, 1] - [1, 0, 0] + >>> from sympy.matrices import eye + >>> M = eye(3) + >>> M.permuteBkwd([[0, 1], [0, 2]]) + Matrix([ + [0, 1, 0], + [0, 0, 1], + [1, 0, 0]]) See Also ======== permuteFwd """ - copy = self[:,:] - for i in range(len(perm)-1, -1, -1): + copy = self.copy() + for i in range(len(perm) - 1, -1, -1): copy.row_swap(perm[i][0], perm[i][1]) return copy def permuteFwd(self, perm): - """ - Permute the rows of the matrix with the given permutation. + """Permute the rows of the matrix with the given permutation. + + Examples + ======== - >>> import sympy - >>> M = sympy.matrices.eye(3) - >>> M.permuteFwd([[0,1],[0,2]]) - [0, 0, 1] - [1, 0, 0] - [0, 1, 0] + >>> from sympy.matrices import eye + >>> M = eye(3) + >>> M.permuteFwd([[0, 1], [0, 2]]) + Matrix([ + [0, 0, 1], + [1, 0, 0], + [0, 1, 0]]) See Also ======== permuteBkwd """ - copy = self[:,:] + copy = self.copy() for i in range(len(perm)): copy.row_swap(perm[i][0], perm[i][1]) return copy - def delRowCol(self, i, j): - """ - Creates a copy of the matrix with the given row and column deleted. - - Examples - ======== - - >>> import sympy - >>> I = sympy.matrices.eye(4) - >>> I.delRowCol(1,2) - [1, 0, 0] - [0, 0, 0] - [0, 0, 1] - - See Also - ======== - - row_del - col_del - """ - # used only for cofactors, makes a copy - M = self.as_mutable() - M.row_del(i) - M.col_del(j) - return self._new(M) - def exp(self): - """ Returns the exponentiation of a matrix - - See Also - ======== - - matrix_multiply - """ + """Return the exponentiation of a square matrix.""" if not self.is_square: - raise NonSquareMatrixError("Exponentiation is valid only for square matrices") + raise NonSquareMatrixError( + "Exponentiation is valid only for square matrices") try: U, D = self.diagonalize() except MatrixError: raise NotImplementedError("Exponentiation is implemented only for diagonalizable matrices") for i in range(0, D.rows): D[i, i] = C.exp(D[i, i]) - return U * D * U.inv() - - @classmethod - def zeros(cls, r, c=None): - """Returns a matrix of zeros with ``r`` rows and ``c`` columns; - if ``c`` is omitted a square matrix will be returned. - - See Also - ======== - - ones - fill - """ - if is_sequence(r): - SymPyDeprecationWarning( - feature="The syntax zeros([%i, %i])" % tuple(r), useinstead="zeros(%i, %i)." % tuple(r), - issue=3381, deprecated_since_version="0.7.2", - ).warn() - r, c = r - else: - c = r if c is None else c - r, c = [int(i) for i in [r, c]] - return MutableMatrix(r, c, [S.Zero]*r*c) - - @classmethod - def eye(cls, n): - """Returns the identity matrix of size n.""" - tmp = cls.zeros(n) - for i in range(tmp.rows): - tmp[i, i] = S.One - return tmp + return U*D*U.inv() @property def is_square(self): - """ - Checks if a matrix is square. + """Checks if a matrix is square. A matrix is square if the number of rows equals the number of columns. The empty matrix is square by definition, since the number of rows and @@ -1976,8 +1899,7 @@ @property def is_zero(self): - """ - Checks if a matrix is a zero matrix. + """Checks if a matrix is a zero matrix. A matrix is zero if every element is zero. A matrix need not be square to be considered zero. The empty matrix is zero by the principle of @@ -2000,11 +1922,10 @@ >>> d.is_zero True """ - return all(i.is_zero for i in self) + return not list(self.values()) def is_nilpotent(self): - """ - Checks if a matrix is nilpotent. + """Checks if a matrix is nilpotent. A matrix B is nilpotent if for some integer k, B**k is a zero matrix. @@ -2013,49 +1934,55 @@ ======== >>> from sympy import Matrix - >>> a = Matrix([[0,0,0],[1,0,0],[1,1,0]]) + >>> a = Matrix([[0, 0, 0], [1, 0, 0], [1, 1, 0]]) >>> a.is_nilpotent() True - >>> a = Matrix([[1,0,1],[1,0,0],[1,1,0]]) + >>> a = Matrix([[1, 0, 1], [1, 0, 0], [1, 1, 0]]) >>> a.is_nilpotent() False """ if not self.is_square: - raise NonSquareMatrixError("Nilpotency is valid only for square matrices") + raise NonSquareMatrixError( + "Nilpotency is valid only for square matrices") x = Dummy('x') if self.charpoly(x).args[0] == x**self.rows: return True return False + @property def is_upper(self): - """ - Check if matrix is an upper triangular matrix. + """Check if matrix is an upper triangular matrix. True can be returned + even if the matrix is not square. Examples ======== >>> from sympy import Matrix - >>> m = Matrix(2,2,[1, 0, 0, 1]) + >>> m = Matrix(2, 2, [1, 0, 0, 1]) >>> m - [1, 0] - [0, 1] - >>> m.is_upper() + Matrix([ + [1, 0], + [0, 1]]) + >>> m.is_upper True - >>> m = Matrix(3,3,[5, 1, 9, 0, 4 , 6, 0, 0, 5]) + >>> m = Matrix(4, 3, [5, 1, 9, 0, 4 , 6, 0, 0, 5, 0, 0, 0]) >>> m - [5, 1, 9] - [0, 4, 6] - [0, 0, 5] - >>> m.is_upper() + Matrix([ + [5, 1, 9], + [0, 4, 6], + [0, 0, 5], + [0, 0, 0]]) + >>> m.is_upper True - >>> m = Matrix(2,3,[4, 2, 5, 6, 1, 1]) + >>> m = Matrix(2, 3, [4, 2, 5, 6, 1, 1]) >>> m - [4, 2, 5] - [6, 1, 1] - >>> m.is_upper() + Matrix([ + [4, 2, 5], + [6, 1, 1]]) + >>> m.is_upper False See Also @@ -2065,41 +1992,44 @@ is_diagonal is_upper_hessenberg """ - for i in range(1, self.rows): - for j in range(0, i): - if self[i,j]: - return False - return True + return all(self[i, j].is_zero + for i in range(1, self.rows) + for j in range(i)) + @property def is_lower(self): - """ - Check if matrix is a lower triangular matrix. + """Check if matrix is a lower triangular matrix. True can be returned + even if the matrix is not square. Examples ======== >>> from sympy import Matrix - >>> m = Matrix(2,2,[1, 0, 0, 1]) + >>> m = Matrix(2, 2, [1, 0, 0, 1]) >>> m - [1, 0] - [0, 1] - >>> m.is_lower() + Matrix([ + [1, 0], + [0, 1]]) + >>> m.is_lower True - >>> m = Matrix(3,3,[2, 0, 0, 1, 4 , 0, 6, 6, 5]) + >>> m = Matrix(4, 3, [0, 0, 0, 2, 0, 0, 1, 4 , 0, 6, 6, 5]) >>> m - [2, 0, 0] - [1, 4, 0] - [6, 6, 5] - >>> m.is_lower() + Matrix([ + [0, 0, 0], + [2, 0, 0], + [1, 4, 0], + [6, 6, 5]]) + >>> m.is_lower True >>> from sympy.abc import x, y - >>> m = Matrix(2,2,[x**2 + y, y**2 + x, 0, x + y]) + >>> m = Matrix(2, 2, [x**2 + y, y**2 + x, 0, x + y]) >>> m - [x**2 + y, x + y**2] - [ 0, x + y] - >>> m.is_lower() + Matrix([ + [x**2 + y, x + y**2], + [ 0, x + y]]) + >>> m.is_lower False See Also @@ -2109,15 +2039,13 @@ is_diagonal is_lower_hessenberg """ - for i in range(0, self.rows): - for j in range(i+1, self.cols): - if self[i, j]: - return False - return True + return all(self[i, j].is_zero + for i in range(self.rows) + for j in range(i + 1, self.cols)) + @property def is_upper_hessenberg(self): - """ - Checks if the matrix is the upper hessenberg form. + """Checks if the matrix is the upper-Hessenberg form. The upper hessenberg matrix has zero entries below the first subdiagonal. @@ -2126,13 +2054,14 @@ ======== >>> from sympy.matrices import Matrix - >>> a = Matrix([[1,4,2,3],[3,4,1,7],[0,2,3,4],[0,0,1,3]]) + >>> a = Matrix([[1, 4, 2, 3], [3, 4, 1, 7], [0, 2, 3, 4], [0, 0, 1, 3]]) >>> a - [1, 4, 2, 3] - [3, 4, 1, 7] - [0, 2, 3, 4] - [0, 0, 1, 3] - >>> a.is_upper_hessenberg() + Matrix([ + [1, 4, 2, 3], + [3, 4, 1, 7], + [0, 2, 3, 4], + [0, 0, 1, 3]]) + >>> a.is_upper_hessenberg True See Also @@ -2141,15 +2070,13 @@ is_lower_hessenberg is_upper """ - for i in range(2, self.rows): - for j in range(0, i - 1): - if self[i,j]: - return False - return True + return all(self[i, j].is_zero + for i in range(2, self.rows) + for j in range(i - 1)) + @property def is_lower_hessenberg(self): - r""" - Checks if the matrix is in the lower hessenberg form. + r"""Checks if the matrix is in the lower-Hessenberg form. The lower hessenberg matrix has zero entries above the first superdiagonal. @@ -2158,13 +2085,14 @@ ======== >>> from sympy.matrices import Matrix - >>> a = Matrix([[1,2,0,0],[5,2,3,0],[3,4,3,7],[5,6,1,1]]) + >>> a = Matrix([[1, 2, 0, 0], [5, 2, 3, 0], [3, 4, 3, 7], [5, 6, 1, 1]]) >>> a - [1, 2, 0, 0] - [5, 2, 3, 0] - [3, 4, 3, 7] - [5, 6, 1, 1] - >>> a.is_lower_hessenberg() + Matrix([ + [1, 2, 0, 0], + [5, 2, 3, 0], + [3, 4, 3, 7], + [5, 6, 1, 1]]) + >>> a.is_lower_hessenberg True See Also @@ -2173,31 +2101,27 @@ is_upper_hessenberg is_lower """ - for i in range(0, self.rows): - for j in range(i + 2, self.cols): - if self[i, j]: - return False - return True + return all(self[i, j].is_zero + for i in range(self.rows) + for j in range(i + 2, self.cols)) def is_symbolic(self): - """ - Checks if any elements are symbols. + """Checks if any elements contain Symbols. Examples ======== - >>> import sympy + >>> from sympy.matrices import Matrix >>> from sympy.abc import x, y - >>> M = sympy.matrices.Matrix([[x, y], [1, 0]]) + >>> M = Matrix([[x, y], [1, 0]]) >>> M.is_symbolic() True """ - return any(element.has(Symbol) for element in self.mat) + return any(element.has(Symbol) for element in list(self.values())) def is_symmetric(self, simplify=True): - """ - Check if matrix is symmetric matrix, + """Check if matrix is symmetric matrix, that is square matrix and is equal to its transpose. By default, simplifications occur before testing symmetry. @@ -2208,33 +2132,37 @@ ======== >>> from sympy import Matrix - >>> m = Matrix(2,2,[0, 1, 1, 2]) + >>> m = Matrix(2, 2, [0, 1, 1, 2]) >>> m - [0, 1] - [1, 2] + Matrix([ + [0, 1], + [1, 2]]) >>> m.is_symmetric() True - >>> m = Matrix(2,2,[0, 1, 2, 0]) + >>> m = Matrix(2, 2, [0, 1, 2, 0]) >>> m - [0, 1] - [2, 0] + Matrix([ + [0, 1], + [2, 0]]) >>> m.is_symmetric() False - >>> m = Matrix(2,3,[0, 0, 0, 0, 0, 0]) + >>> m = Matrix(2, 3, [0, 0, 0, 0, 0, 0]) >>> m - [0, 0, 0] - [0, 0, 0] + Matrix([ + [0, 0, 0], + [0, 0, 0]]) >>> m.is_symmetric() False >>> from sympy.abc import x, y - >>> m = Matrix(3,3,[1, x**2 + 2*x + 1, y, (x + 1)**2 , 2, 0, y, 0, 3]) + >>> m = Matrix(3, 3, [1, x**2 + 2*x + 1, y, (x + 1)**2 , 2, 0, y, 0, 3]) >>> m - [ 1, x**2 + 2*x + 1, y] - [(x + 1)**2, 2, 0] - [ y, 0, 3] + Matrix([ + [ 1, x**2 + 2*x + 1, y], + [(x + 1)**2, 2, 0], + [ y, 0, 3]]) >>> m.is_symmetric() True @@ -2257,8 +2185,7 @@ return self == self.transpose() def is_anti_symmetric(self, simplify=True): - """ - Check if matrix M is an antisymmetric matrix, + """Check if matrix M is an antisymmetric matrix, that is, M is a square matrix with all M[i, j] == -M[j, i]. When ``simplify=True`` (default), the sum M[i, j] + M[j, i] is @@ -2273,17 +2200,19 @@ ======== >>> from sympy import Matrix, symbols - >>> m = Matrix(2,2,[0, 1, -1, 0]) + >>> m = Matrix(2, 2, [0, 1, -1, 0]) >>> m - [ 0, 1] - [-1, 0] + Matrix([ + [ 0, 1], + [-1, 0]]) >>> m.is_anti_symmetric() True >>> x, y = symbols('x y') - >>> m = Matrix(2,3,[0, 0, x, -y, 0, 0]) + >>> m = Matrix(2, 3, [0, 0, x, -y, 0, 0]) >>> m - [ 0, 0, x] - [-y, 0, 0] + Matrix([ + [ 0, 0, x], + [-y, 0, 0]]) >>> m.is_anti_symmetric() False @@ -2319,7 +2248,7 @@ """ # accept custom simplification simpfunc = simplify if isinstance(simplify, FunctionType) else \ - _simplify if simplify else False + _simplify if simplify else False if not self.is_square: return False @@ -2342,35 +2271,36 @@ return False return True - def is_diagonal(self): - """ - Check if matrix is diagonal, + """Check if matrix is diagonal, that is matrix in which the entries outside the main diagonal are all zero. Examples ======== >>> from sympy import Matrix, diag - >>> m = Matrix(2,2,[1, 0, 0, 2]) + >>> m = Matrix(2, 2, [1, 0, 0, 2]) >>> m - [1, 0] - [0, 2] + Matrix([ + [1, 0], + [0, 2]]) >>> m.is_diagonal() True - >>> m = Matrix(2,2,[1, 1, 0, 2]) + >>> m = Matrix(2, 2, [1, 1, 0, 2]) >>> m - [1, 1] - [0, 2] + Matrix([ + [1, 1], + [0, 2]]) >>> m.is_diagonal() False >>> m = diag(1, 2, 3) >>> m - [1, 0, 0] - [0, 2, 0] - [0, 0, 3] + Matrix([ + [1, 0, 0], + [0, 2, 0], + [0, 0, 3]]) >>> m.is_diagonal() True @@ -2388,15 +2318,8 @@ return False return True - def clone(self): - """ - Create a shallow copy of this matrix. - """ - return self._new(self.rows, self.cols, lambda i, j: self[i, j]) - def det(self, method="bareis"): - """ - Computes the matrix determinant using the method "method". + """Computes the matrix determinant using the method "method". Possible values for "method": bareis ... det_bareis @@ -2425,7 +2348,7 @@ elif method == "det_LU": return self.det_LU_decomposition() else: - raise ValueError("Determinant method unrecognized") + raise ValueError("Determinant method '%s' unrecognized" % method) def det_bareis(self): """Compute matrix determinant using Bareis' fraction-free @@ -2435,7 +2358,8 @@ minimal number of fractions. It means that less term rewriting is needed on resulting formulae. - TODO: Implement algorithm for sparse matrices (SFF). + TODO: Implement algorithm for sparse matrices (SFF), + http://www.eecis.udel.edu/~saunders/papers/sffge/it5.ps. See Also ======== @@ -2448,20 +2372,23 @@ if not self: return S.One - M, n = self[:,:], self.rows + M, n = self.copy(), self.rows if n == 1: det = M[0, 0] elif n == 2: det = M[0, 0]*M[1, 1] - M[0, 1]*M[1, 0] + elif n == 3: + det = (M[0, 0]*M[1, 1]*M[2, 2] + M[0, 1]*M[1, 2]*M[2, 0] + M[0, 2]*M[1, 0]*M[2, 1]) - \ + (M[0, 2]*M[1, 1]*M[2, 0] + M[0, 0]*M[1, 2]*M[2, 1] + M[0, 1]*M[1, 0]*M[2, 2]) else: - sign = 1 # track current sign in case of column swap + sign = 1 # track current sign in case of column swap - for k in range(n-1): + for k in range(n - 1): # look for a pivot in the current column # and assume det == 0 if none is found if M[k, k] == 0: - for i in range(k+1, n): + for i in range(k + 1, n): if M[i, k]: M.row_swap(i, k) sign *= -1 @@ -2471,19 +2398,19 @@ # proceed with Bareis' fraction-free (FF) # form of Gaussian elimination algorithm - for i in range(k+1, n): - for j in range(k+1, n): + for i in range(k + 1, n): + for j in range(k + 1, n): D = M[k, k]*M[i, j] - M[i, k]*M[k, j] if k > 0: - D /= M[k-1, k-1] + D /= M[k - 1, k - 1] if D.is_Atom: M[i, j] = D else: M[i, j] = cancel(D) - det = sign * M[n-1, n-1] + det = sign*M[n - 1, n - 1] return det.expand() @@ -2494,7 +2421,8 @@ fails. In particular, if the matrix has no inverse this method will fail. - TODO: Implement algorithm for sparse matrices (SFF). + TODO: Implement algorithm for sparse matrices (SFF), + http://www.eecis.udel.edu/~saunders/papers/sffge/it5.ps. See Also ======== @@ -2508,20 +2436,19 @@ if not self: return S.One - M, n = self[:,:], self.rows - p, prod = [] , 1 + M, n = self.copy(), self.rows + p, prod = [], 1 l, u, p = M.LUdecomposition() - if len(p) % 2: + if len(p) % 2: prod = -1 for k in range(n): - prod = prod*u[k,k]*l[k,k] + prod = prod*u[k, k]*l[k, k] return prod.expand() def adjugate(self, method="berkowitz"): - """ - Returns the adjugate matrix. + """Returns the adjugate matrix. Adjugate matrix is the transpose of the cofactor matrix. @@ -2537,10 +2464,8 @@ return self.cofactorMatrix(method).T - def inverse_LU(self, iszerofunc=_iszero): - """ - Calculates the inverse using LU decomposition. + """Calculates the inverse using LU decomposition. See Also ======== @@ -2559,8 +2484,7 @@ return self.LUsolve(self.eye(self.rows), iszerofunc=_iszero) def inverse_GE(self, iszerofunc=_iszero): - """ - Calculates the inverse using Gaussian elimination. + """Calculates the inverse using Gaussian elimination. See Also ======== @@ -2569,19 +2493,19 @@ inverse_LU inverse_ADJ """ + from .dense import Matrix if not self.is_square: - raise NonSquareMatrixError() + raise NonSquareMatrixError("A Matrix must be square to invert.") - big = self.row_join(self.eye(self.rows)) + big = Matrix.hstack(self.as_mutable(), Matrix.eye(self.rows)) red = big.rref(iszerofunc=iszerofunc, simplify=True)[0] if any(iszerofunc(red[j, j]) for j in range(red.rows)): raise ValueError("Matrix det == 0; not invertible.") - return red[:,big.rows:] + return self._new(red[:, big.rows:]) def inverse_ADJ(self, iszerofunc=_iszero): - """ - Calculates the inverse using the adjugate matrix and a determinant. + """Calculates the inverse using the adjugate matrix and a determinant. See Also ======== @@ -2591,7 +2515,7 @@ inverse_GE """ if not self.is_square: - raise NonSquareMatrixError() + raise NonSquareMatrixError("A Matrix must be square to invert.") d = self.berkowitz_det() zero = d.equals(0) @@ -2602,73 +2526,99 @@ if zero: raise ValueError("Matrix det == 0; not invertible.") - return self.adjugate()/d + return self.adjugate() / d def rref(self, simplified=False, iszerofunc=_iszero, simplify=False): - """ - Return reduced row-echelon form of matrix and indices of pivot vars. + """Return reduced row-echelon form of matrix and indices of pivot vars. To simplify elements before finding nonzero pivots set simplify=True (to use the default SymPy simplify function) or pass a custom simplify function. + Examples + ======== + >>> from sympy import Matrix >>> from sympy.abc import x >>> m = Matrix([[1, 2], [x, 1 - 1/x]]) >>> m.rref() - ([1, 0] - [0, 1], [0, 1]) + (Matrix([ + [1, 0], + [0, 1]]), [0, 1]) """ if simplified is not False: SymPyDeprecationWarning( feature="'simplified' as a keyword to rref", useinstead="simplify=True, or set simplify equal to your " - "own custom simplification function", + "own custom simplification function", issue=3382, deprecated_since_version="0.7.2", ).warn() simplify = simplify or True - simpfunc = simplify if isinstance(simplify, FunctionType) else _simplify - pivot, r = 0, self[:,:].as_mutable() # pivot: index of next row to contain a pivot - pivotlist = [] # indices of pivot variables (non-free) + simpfunc = simplify if isinstance( + simplify, FunctionType) else _simplify + # pivot: index of next row to contain a pivot + pivot, r = 0, self.as_mutable() + # pivotlist: indices of pivot variables (non-free) + pivotlist = [] for i in range(r.cols): if pivot == r.rows: break if simplify: - r[pivot,i] = simpfunc(r[pivot,i]) - if iszerofunc(r[pivot,i]): + r[pivot, i] = simpfunc(r[pivot, i]) + if iszerofunc(r[pivot, i]): for k in range(pivot, r.rows): if simplify and k > pivot: - r[k,i] = simpfunc(r[k,i]) - if not iszerofunc(r[k,i]): + r[k, i] = simpfunc(r[k, i]) + if not iszerofunc(r[k, i]): break - if k == r.rows - 1 and iszerofunc(r[k,i]): + if k == r.rows - 1 and iszerofunc(r[k, i]): continue - r.row_swap(pivot,k) - scale = r[pivot,i] - r.row(pivot, lambda x, _: x/scale) + r.row_swap(pivot, k) + scale = r[pivot, i] + r.row_op(pivot, lambda x, _: x / scale) for j in range(r.rows): if j == pivot: continue - scale = r[j,i] - r.row(j, lambda x, k: x - scale*r[pivot,k]) + scale = r[j, i] + r.zip_row_op(j, pivot, lambda x, y: x - scale*y) pivotlist.append(i) pivot += 1 return self._new(r), pivotlist - def nullspace(self, simplified=False, simplify=False): + def rank(self, simplified=False, iszerofunc=_iszero, + simplify=False): + """ + Returns the rank of a matrix + + >>> from sympy import Matrix + >>> from sympy.abc import x + >>> m = Matrix([[1, 2], [x, 1 - 1/x]]) + >>> m.rank() + 2 + >>> n = Matrix(3, 3, list(range(1, 10))) + >>> n.rank() + 2 """ - Returns list of vectors (Matrix objects) that span nullspace of self + row_reduced = self.rref(simplified=simplified, iszerofunc=iszerofunc, simplify=simplify) + rank = len(row_reduced[-1]) + return rank + + def nullspace(self, simplified=False, simplify=False): + """Returns list of vectors (Matrix objects) that span nullspace of self """ + from sympy.matrices import zeros + if simplified is not False: SymPyDeprecationWarning( feature="'simplified' as a keyword to nullspace", useinstead="simplify=True, or set simplify equal to your " - "own custom simplification function", + "own custom simplification function", issue=3382, deprecated_since_version="0.7.2", ).warn() simplify = simplify or True - simpfunc = simplify if isinstance(simplify, FunctionType) else _simplify + simpfunc = simplify if isinstance( + simplify, FunctionType) else _simplify reduced, pivots = self.rref(simplify=simpfunc) basis = [] @@ -2682,10 +2632,10 @@ basiskey[cur] = i cur += 1 for i in range(self.cols): - if i not in pivots: # free var, just set vector's ith place to 1 - basis[basiskey.index(i)][i,0] = 1 + if i not in pivots: # free var, just set vector's ith place to 1 + basis[basiskey.index(i)][i, 0] = 1 else: # add negative of nonpivot entry to corr vector - for j in range(i+1, self.cols): + for j in range(i + 1, self.cols): line = pivots.index(i) v = reduced[line, j] if simplify: @@ -2693,8 +2643,9 @@ if v: if j in pivots: # XXX: Is this the correct error? - raise NotImplementedError("Could not compute the nullspace of `self`.") - basis[basiskey.index(j)][i,0] = -v + raise NotImplementedError( + "Could not compute the nullspace of `self`.") + basis[basiskey.index(j)][i, 0] = -v return [self._new(b) for b in basis] def berkowitz(self): @@ -2723,7 +2674,7 @@ >>> from sympy import Matrix >>> from sympy.abc import x, y, z - >>> M = Matrix([[x,y,z], [1,0,0], [y,z,x]]) + >>> M = Matrix([[x, y, z], [1, 0, 0], [y, z, x]]) >>> p, q, r = M.berkowitz() @@ -2754,37 +2705,39 @@ berkowitz_charpoly berkowitz_eigenvals """ + from sympy.matrices import zeros + if not self.is_square: raise NonSquareMatrixError() A, N = self, self.rows - transforms = [0] * (N-1) + transforms = [0]*(N - 1) for n in range(N, 1, -1): - T, k = zeros(n+1, n), n - 1 + T, k = zeros(n + 1, n), n - 1 - R, C = -A[k,:k], A[:k,k] - A, a = A[:k,:k], -A[k,k] + R, C = -A[k, :k], A[:k, k] + A, a = A[:k, :k], -A[k, k] - items = [ C ] + items = [C] - for i in range(0, n-2): - items.append(A * items[i]) + for i in range(0, n - 2): + items.append(A*items[i]) for i, B in enumerate(items): - items[i] = (R * B)[0,0] + items[i] = (R*B)[0, 0] - items = [ S.One, a ] + items + items = [S.One, a] + items for i in range(n): - T[i:,i] = items[:n-i+1] + T[i:, i] = items[:n - i + 1] - transforms[k-1] = T + transforms[k - 1] = T - polys = [ self._new([S.One, -A[0,0]]) ] + polys = [self._new([S.One, -A[0, 0]])] for i, T in enumerate(transforms): - polys.append(T * polys[i]) + polys.append(T*polys[i]) return tuple(map(tuple, polys)) @@ -2802,8 +2755,8 @@ if not self: return S.One poly = self.berkowitz()[-1] - sign = (-1)**(len(poly)-1) - return sign * poly[-1] + sign = (-1)**(len(poly) - 1) + return sign*poly[-1] def berkowitz_minors(self): """Computes principal minors using Berkowitz method. @@ -2827,6 +2780,9 @@ A PurePoly is returned so using different variables for ``x`` does not affect the comparison or the polynomials: + Examples + ======== + >>> from sympy import Matrix >>> from sympy.abc import x, y >>> A = Matrix([[1, 3], [2, 0]]) @@ -2879,12 +2835,11 @@ # unless the nsimplify flag indicates that this has already # been done, e.g. in eigenvects if flags.pop('rational', True): - float = False if any(v.has(Float) for v in self): - float=True - self = self._new(self.rows, self.cols, [nsimplify(v, rational=True) for v in self]) + self = self._new(self.rows, self.cols, + [nsimplify(v, rational=True) for v in self]) - flags.pop('simplify', None) # pop unsupported flag + flags.pop('simplify', None) # pop unsupported flag return self.berkowitz_eigenvals(**flags) def eigenvects(self, **flags): @@ -2902,19 +2857,21 @@ evaluated with evalf. If it is desired to removed small imaginary portions during the evalf step, pass a value for the ``chop`` flag. """ + from sympy.matrices import eye simplify = flags.get('simplify', True) primitive = bool(flags.get('simplify', False)) chop = flags.pop('chop', False) - flags.pop('multiple', None) # remove this if it's there + flags.pop('multiple', None) # remove this if it's there # roots doesn't like Floats, so replace them with Rationals float = False if any(v.has(Float) for v in self): float = True - self = self._new(self.rows, self.cols, [nsimplify(v, rational=True) for v in self]) - flags['rational'] = False # to tell eigenvals not to do this + self = self._new(self.rows, self.cols, [nsimplify( + v, rational=True) for v in self]) + flags['rational'] = False # to tell eigenvals not to do this out, vlist = [], self.eigenvals(**flags) vlist = list(vlist.items()) @@ -2922,7 +2879,7 @@ flags.pop('rational', None) for r, k in vlist: - tmp = self - eye(self.rows)*r + tmp = self.as_mutable() - eye(self.rows)*r basis = tmp.nullspace() # whether tmp.is_symbolic() is True or False, it is possible that # the basis will come back as [] in which case simplification is @@ -2931,7 +2888,8 @@ # The nullspace routine failed, try it again with simplification basis = tmp.nullspace(simplify=simplify) if not basis: - raise NotImplementedError("Can't evaluate eigenvector for eigenvalue %s" % r) + raise NotImplementedError( + "Can't evaluate eigenvector for eigenvalue %s" % r) if primitive: # the relationship A*e = lambda*e will still hold if we change the # eigenvector; so if simplify is True we tidy up any normalization @@ -2947,16 +2905,19 @@ if l != 1: basis[0] *= l if float: - out.append((r.evalf(chop=chop), k, [self._new(b).evalf(chop=chop) for b in basis])) + out.append((r.evalf(chop=chop), k, [ + self._new(b).evalf(chop=chop) for b in basis])) else: out.append((r, k, [self._new(b) for b in basis])) return out def singular_values(self): - """ - Compute the singular values of a Matrix + """Compute the singular values of a Matrix + + Examples + ======== - >>> from sympy import Matrix, Symbol, eye + >>> from sympy import Matrix, Symbol >>> x = Symbol('x', real=True) >>> A = Matrix([[0, 1, 0], [0, x, 0], [-1, 0, 0]]) >>> A.singular_values() @@ -2973,21 +2934,23 @@ # Expands result from eigenvals into a simple list vals = [] - for k,v in list(valmultpairs.items()): - vals += [sqrt(k)]*v # dangerous! same k in several spots! + for k, v in list(valmultpairs.items()): + vals += [sqrt(k)]*v # dangerous! same k in several spots! # sort them in descending order vals.sort(reverse=True, key=default_sort_key) return vals def condition_number(self): - """ - Returns the condition number of a matrix. + """Returns the condition number of a matrix. This is the maximum singular value divided by the minimum singular value + Examples + ======== + >>> from sympy import Matrix, S - >>> A = Matrix([[1, 0, 0], [0, 10, 0], [0,0,S.One/10]]) + >>> A = Matrix([[1, 0, 0], [0, 10, 0], [0, 0, S.One/10]]) >>> A.condition_number() 100 @@ -3001,30 +2964,32 @@ return Max(*singularvalues) / Min(*singularvalues) def __getattr__(self, attr): - if attr in ('diff','integrate','limit'): + if attr in ('diff', 'integrate', 'limit'): def doit(*args): item_doit = lambda item: getattr(item, attr)(*args) - return self.applyfunc( item_doit ) + return self.applyfunc(item_doit) return doit else: - raise AttributeError("Matrix has no attribute %s." % attr) + raise AttributeError( + "%s has no attribute %s." % (self.__class__.__name__, attr)) def integrate(self, *args): - """ - Integrate each element of the matrix. + """Integrate each element of the matrix. Examples ======== - >>> import sympy + >>> from sympy.matrices import Matrix >>> from sympy.abc import x, y - >>> M = sympy.matrices.Matrix([[x, y], [1, 0]]) - >>> M.integrate((x,)) - [x**2/2, x*y] - [ x, 0] + >>> M = Matrix([[x, y], [1, 0]]) + >>> M.integrate((x, )) + Matrix([ + [x**2/2, x*y], + [ x, 0]]) >>> M.integrate((x, 0, 2)) - [2, 2*y] - [2, 0] + Matrix([ + [2, 2*y], + [2, 0]]) See Also ======== @@ -3036,18 +3001,18 @@ lambda i, j: self[i, j].integrate(*args)) def limit(self, *args): - """ - Calculate the limit of each element in the matrix. + """Calculate the limit of each element in the matrix. Examples ======== - >>> import sympy + >>> from sympy.matrices import Matrix >>> from sympy.abc import x, y - >>> M = sympy.matrices.Matrix([[x, y], [1, 0]]) + >>> M = Matrix([[x, y], [1, 0]]) >>> M.limit(x, 2) - [2, y] - [1, 0] + Matrix([ + [2, y], + [1, 0]]) See Also ======== @@ -3059,18 +3024,18 @@ lambda i, j: self[i, j].limit(*args)) def diff(self, *args): - """ - Calculate the derivative of each element in the matrix. + """Calculate the derivative of each element in the matrix. Examples ======== - >>> import sympy + >>> from sympy.matrices import Matrix >>> from sympy.abc import x, y - >>> M = sympy.matrices.Matrix([[x, y], [1, 0]]) + >>> M = Matrix([[x, y], [1, 0]]) >>> M.diff(x) - [1, 0] - [0, 0] + Matrix([ + [1, 0], + [0, 0]]) See Also ======== @@ -3082,53 +3047,63 @@ lambda i, j: self[i, j].diff(*args)) def vec(self): - """ - Return the Matrix converted into a one column matrix by stacking columns + """Return the Matrix converted into a one column matrix by stacking columns + + Examples + ======== >>> from sympy import Matrix - >>> m=Matrix([[1,3], [2,4]]) + >>> m=Matrix([[1, 3], [2, 4]]) >>> m - [1, 3] - [2, 4] + Matrix([ + [1, 3], + [2, 4]]) >>> m.vec() - [1] - [2] - [3] - [4] + Matrix([ + [1], + [2], + [3], + [4]]) See Also ======== vech """ - return self.__class__(len(self), 1, self.transpose().mat) + return self.T.reshape(len(self), 1) def vech(self, diagonal=True, check_symmetry=True): - """ - Return the unique elements of a symmetric Matrix as a one column matrix + """Return the unique elements of a symmetric Matrix as a one column matrix by stacking the elements in the lower triangle. Arguments: diagonal -- include the diagonal cells of self or not check_symmetry -- checks symmetry of self but not completely reliably + Examples + ======== + >>> from sympy import Matrix - >>> m=Matrix([[1,2], [2,3]]) + >>> m=Matrix([[1, 2], [2, 3]]) >>> m - [1, 2] - [2, 3] + Matrix([ + [1, 2], + [2, 3]]) >>> m.vech() - [1] - [2] - [3] + Matrix([ + [1], + [2], + [3]]) >>> m.vech(diagonal=False) - [2] + Matrix([[2]]) See Also ======== vec """ + from sympy.matrices import zeros + c = self.cols if c != self.rows: raise ShapeError("Matrix must be square") @@ -3138,16 +3113,16 @@ raise ValueError("Matrix appears to be asymmetric; consider check_symmetry=False") count = 0 if diagonal: - v = zeros(c * (c + 1) // 2, 1) + v = zeros(c*(c + 1) // 2, 1) for j in range(c): - for i in range(j,c): - v[count] = self[i,j] + for i in range(j, c): + v[count] = self[i, j] count += 1 else: - v = zeros(c * (c - 1) // 2, 1) + v = zeros(c*(c - 1) // 2, 1) for j in range(c): - for i in range(j+1,c): - v[count] = self[i,j] + for i in range(j + 1, c): + v[count] = self[i, j] count += 1 return v @@ -3161,21 +3136,22 @@ Examples ======== - >>> from sympy import Matrix, symbols + >>> from sympy import Matrix >>> from sympy.abc import x, y, z >>> A = Matrix([[1, 3, 0, 0], [y, z*z, 0, 0], [0, 0, x, 0], [0, 0, 0, 0]]) >>> a1, a2, a3 = A.get_diag_blocks() >>> a1 - [1, 3] - [y, z**2] + Matrix([ + [1, 3], + [y, z**2]]) >>> a2 - [x] + Matrix([[x]]) >>> a3 - [0] - >>> + Matrix([[0]]) """ sub_blocks = [] + def recurse_sub_blocks(M): i = 1 while i <= M.shape[0]: @@ -3198,9 +3174,9 @@ recurse_sub_blocks(self) return sub_blocks - def diagonalize(self, reals_only = False): + def diagonalize(self, reals_only=False, sort=False, normalize=False): """ - Return diagonalized matrix D and transformation P such as + Return (P, D), where D is diagonal and D = P^-1 * M * P @@ -3210,31 +3186,38 @@ ======== >>> from sympy import Matrix - >>> m = Matrix(3,3,[1, 2, 0, 0, 3, 0, 2, -4, 2]) + >>> m = Matrix(3, 3, [1, 2, 0, 0, 3, 0, 2, -4, 2]) >>> m - [1, 2, 0] - [0, 3, 0] - [2, -4, 2] + Matrix([ + [1, 2, 0], + [0, 3, 0], + [2, -4, 2]]) >>> (P, D) = m.diagonalize() >>> D - [1, 0, 0] - [0, 2, 0] - [0, 0, 3] + Matrix([ + [1, 0, 0], + [0, 2, 0], + [0, 0, 3]]) >>> P - [-1, 0, -1] - [ 0, 0, -1] - [ 2, 1, 2] + Matrix([ + [-1, 0, -1], + [ 0, 0, -1], + [ 2, 1, 2]]) >>> P.inv() * m * P - [1, 0, 0] - [0, 2, 0] - [0, 0, 3] + Matrix([ + [1, 0, 0], + [0, 2, 0], + [0, 0, 3]]) See Also ======== is_diagonal is_diagonalizable + """ + from sympy.matrices import diag + if not self.is_square: raise NonSquareMatrixError() if not self.is_diagonalizable(reals_only, False): @@ -3243,20 +3226,24 @@ else: if self._eigenvects is None: self._eigenvects = self.eigenvects(simplify=True) + if sort: + self._eigenvects.sort(key=default_sort_key) + self._eigenvects.reverse() diagvals = [] - P = MutableMatrix(self.rows, 0, []) + P = self._new(self.rows, 0, []) for eigenval, multiplicity, vects in self._eigenvects: for k in range(multiplicity): diagvals.append(eigenval) vec = vects[k] + if normalize: + vec = vec / vec.norm() P = P.col_insert(P.cols, vec) D = diag(*diagvals) self._diagonalize_clear_subproducts() return (P, D) - def is_diagonalizable(self, reals_only = False, clear_subproducts=True): - """ - Check if matrix is diagonalizable. + def is_diagonalizable(self, reals_only=False, clear_subproducts=True): + """Check if matrix is diagonalizable. If reals_only==True then check that diagonalized matrix consists of the only not complex values. @@ -3267,23 +3254,26 @@ ======== >>> from sympy import Matrix - >>> m = Matrix(3,3,[1, 2, 0, 0, 3, 0, 2, -4, 2]) + >>> m = Matrix(3, 3, [1, 2, 0, 0, 3, 0, 2, -4, 2]) >>> m - [1, 2, 0] - [0, 3, 0] - [2, -4, 2] + Matrix([ + [1, 2, 0], + [0, 3, 0], + [2, -4, 2]]) >>> m.is_diagonalizable() True - >>> m = Matrix(2,2,[0, 1, 0, 0]) + >>> m = Matrix(2, 2, [0, 1, 0, 0]) >>> m - [0, 1] - [0, 0] + Matrix([ + [0, 1], + [0, 0]]) >>> m.is_diagonalizable() False - >>> m = Matrix(2,2,[0, 1, -1, 0]) + >>> m = Matrix(2, 2, [0, 1, -1, 0]) >>> m - [ 0, 1] - [-1, 0] + Matrix([ + [ 0, 1], + [-1, 0]]) >>> m.is_diagonalizable() True >>> m.is_diagonalizable(True) @@ -3323,9 +3313,8 @@ del self._is_symmetric del self._eigenvects - def jordan_form(self, calc_transformation = True): - """ - Return Jordan form J of current matrix. + def jordan_form(self, calc_transformation=True): + """Return Jordan form J of current matrix. If calc_transformation is specified as False, then transformation P such that @@ -3342,32 +3331,32 @@ ======== >>> from sympy import Matrix - >>> m = Matrix(4, 4, [6, 5, -2, -3, -3, -1, 3, 3, 2, 1, -2, -3, -1, 1, 5, 5]) - >>> m - [ 6, 5, -2, -3] - [-3, -1, 3, 3] - [ 2, 1, -2, -3] - [-1, 1, 5, 5] - + >>> m = Matrix([ + ... [ 6, 5, -2, -3], + ... [-3, -1, 3, 3], + ... [ 2, 1, -2, -3], + ... [-1, 1, 5, 5]]) >>> (P, J) = m.jordan_form() >>> J - [2, 1, 0, 0] - [0, 2, 0, 0] - [0, 0, 2, 1] - [0, 0, 0, 2] + Matrix([ + [2, 1, 0, 0], + [0, 2, 0, 0], + [0, 0, 2, 1], + [0, 0, 0, 2]]) See Also ======== jordan_cells """ + from sympy.matrices import diag + (P, Jcells) = self.jordan_cells(calc_transformation) J = diag(*Jcells) return (P, J) - def jordan_cells(self, calc_transformation = True): - """ - Return a list of Jordan cells of current matrix. + def jordan_cells(self, calc_transformation=True): + """Return a list of Jordan cells of current matrix. This list shape Jordan matrix J. If calc_transformation is specified as False, then transformation P such that @@ -3385,26 +3374,29 @@ ======== >>> from sympy import Matrix - >>> m = Matrix(4, 4, [6, 5, -2, -3, -3, -1, 3, 3, 2, 1, -2, -3, -1, 1, 5, 5]) - >>> m - [ 6, 5, -2, -3] - [-3, -1, 3, 3] - [ 2, 1, -2, -3] - [-1, 1, 5, 5] + >>> m = Matrix(4, 4, [ + ... 6, 5, -2, -3, + ... -3, -1, 3, 3, + ... 2, 1, -2, -3, + ... -1, 1, 5, 5]) >>> (P, Jcells) = m.jordan_cells() >>> Jcells[0] - [2, 1] - [0, 2] + Matrix([ + [2, 1], + [0, 2]]) >>> Jcells[1] - [2, 1] - [0, 2] + Matrix([ + [2, 1], + [0, 2]]) See Also ======== jordan_form """ + from sympy.matrices import jordan_cell, diag + if not self.is_square: raise NonSquareMatrixError() _eigenvects = self.eigenvects() @@ -3412,7 +3404,7 @@ for eigenval, multiplicity, vects in _eigenvects: geometrical = len(vects) if geometrical == multiplicity: - Jcell = diag( *([eigenval] * multiplicity)) + Jcell = diag(*([eigenval]*multiplicity)) Jcells.append(Jcell) else: sizes = self._jordan_split(multiplicity, geometrical) @@ -3424,17 +3416,16 @@ return (None, Jcells) def _jordan_split(self, algebraical, geometrical): - """return a list of integers with sum equal to 'algebraical' + """Return a list of integers with sum equal to 'algebraical' and length equal to 'geometrical'""" n1 = algebraical // geometrical - res = [n1] * geometrical + res = [n1]*geometrical res[len(res) - 1] += algebraical % geometrical assert sum(res) == algebraical return res def has(self, *patterns): - """ - Test whether any subexpression matches any of the patterns. + """Test whether any subexpression matches any of the patterns. Examples ======== @@ -3449,25 +3440,12 @@ >>> A.has(Float) True """ - return any(a.has(*patterns) for a in self.mat) - - @property - def is_Identity(self): - if not self.is_square: - return False - for i in range(self.rows): - for j in range(self.cols): - if i==j and self[i,j] != 1: - return False - if i!=j and self[i,j]: - return False - return True + return any(a.has(*patterns) for a in self._mat) def dual(self): - """ - Returns the dual of a matrix, which is: + """Returns the dual of a matrix, which is: - `(1/2)*levicivita(i,j,k,l)*M(k,l)` summed over indices `k` and `l` + `(1/2)*levicivita(i, j, k, l)*M(k, l)` summed over indices `k` and `l` Since the levicivita method is anti_symmetric for any pairwise exchange of indices, the dual of a symmetric matrix is the zero @@ -3477,8 +3455,9 @@ """ from sympy import LeviCivita + from sympy.matrices import zeros - M, n = self[:,:], self.rows + M, n = self[:, :], self.rows work = zeros(n) if self.is_symmetric(): return work @@ -3491,10 +3470,10 @@ work[i, j] = acum work[j, i] = -acum - for l in range(1,n): + for l in range(1, n): acum = 0 - for a in range(1,n): - for b in range(1,n): + for a in range(1, n): + for b in range(1, n): acum += LeviCivita(0, l, a, b)*M[a, b] acum /= 2 work[0, l] = -acum @@ -3502,1478 +3481,251 @@ return work -class MutableMatrix(MatrixBase): - - is_MatrixExpr = False - - _op_priority = 12.0 - _class_priority = 10 - @classmethod - def _new(cls, *args, **kwargs): - rows, cols, mat = MatrixBase._handle_creation_inputs(*args, **kwargs) - self = object.__new__(cls) - self.rows = rows - self.cols = cols - self.mat = list(mat) # create a shallow copy - return self - def __new__(cls, *args, **kwargs): - return cls._new(*args, **kwargs) - - def __setitem__(self, key, value): - """ - >>> from sympy import Matrix, I - >>> m=Matrix(((1,2+I),(3,4))) - >>> m #doctest: +NORMALIZE_WHITESPACE - [1, 2 + I] - [3, 4] - >>> m[1,0]=9 - >>> m #doctest: +NORMALIZE_WHITESPACE - [1, 2 + I] - [9, 4] - - """ - if type(key) is tuple: - i, j = key - if type(i) is slice or type(j) is slice: - if isinstance(value, MatrixBase): - self.copyin_matrix(key, value) - return - if is_sequence(value): - self.copyin_list(key, value) - return - else: - # a2idx inlined - if type(i) is not int: - try: - i = i.__index__() - except AttributeError: - raise IndexError("Invalid index a[%r]" % (key,)) - - # a2idx inlined - if type(j) is not int: - try: - j = j.__index__() - except AttributeError: - raise IndexError("Invalid index a[%r]" % (key,)) - - - i, j = self.key2ij((i,j)) - if not (i>=0 and i=0 and j < self.cols): - raise IndexError("Index out of range: a[%s]" % (key,)) - else: - self.mat[i*self.cols + j] = sympify(value) - return - - else: - # row-wise decomposition of matrix - if type(key) is slice: - raise IndexError("Vector slices not implemented yet.") - else: - k = a2idx(key) - if k is not None: - self.mat[k] = sympify(value) - return - raise IndexError("Invalid index: a[%s]"%repr(key)) - - def copyin_matrix(self, key, value): - """ - Copy in values from a matrix into the given bounds. - - Parameters - ========== - - key : slice - The section of this matrix to replace. - value : Matrix - The matrix to copy values from. + def hstack(cls, *args): + """Return a matrix formed by joining args horizontally (i.e. + by repeated application of row_join). Examples ======== - >>> import sympy - >>> M = sympy.matrices.Matrix([[0,1],[2,3]]) - >>> I = sympy.matrices.eye(5) - >>> I.copyin_matrix((slice(0,2), slice(0,2)),M) - >>> I - [0, 1, 0, 0, 0] - [2, 3, 0, 0, 0] - [0, 0, 1, 0, 0] - [0, 0, 0, 1, 0] - [0, 0, 0, 0, 1] - - See Also - ======== - - copyin_list - """ - rlo, rhi, clo, chi = self.key2bounds(key) - - if value.rows != rhi - rlo or value.cols != chi - clo: - raise ShapeError("The Matrix `value` doesn't have the same dimensions " + - "as the in sub-Matrix given by `key`.") - - for i in range(value.rows): - for j in range(value.cols): - self[i+rlo, j+clo] = sympify(value[i,j]) - - def copyin_list(self, key, value): + >>> from sympy.matrices import Matrix, eye + >>> Matrix.hstack(eye(2), 2*eye(2)) + Matrix([ + [1, 0, 2, 0], + [0, 1, 0, 2]]) """ - Copy in elements from a list. + return reduce(cls.row_join, args) - Parameters - ========== - - key : slice - The section of this matrix to replace. - value : iterable - The iterable to copy values from. + @classmethod + def vstack(cls, *args): + """Return a matrix formed by joining args vertically (i.e. + by repeated application of col_join). Examples ======== - >>> import sympy - >>> I = sympy.matrices.eye(5) - >>> I.copyin_list((slice(0,2), slice(0,1)), [1,2]) - >>> I - [1, 0, 0, 0, 0] - [2, 1, 0, 0, 0] - [0, 0, 1, 0, 0] - [0, 0, 0, 1, 0] - [0, 0, 0, 0, 1] - - See Also - ======== - - copyin_matrix - """ - if not is_sequence(value): - raise TypeError("`value` must be an ordered iterable, not %s." % type(value)) - return self.copyin_matrix(key, MutableMatrix(value)) - - def row(self, i, f=None): + >>> from sympy.matrices import Matrix, eye + >>> Matrix.vstack(eye(2), 2*eye(2)) + Matrix([ + [1, 0], + [0, 1], + [2, 0], + [0, 2]]) """ - Elementary row selector (default) or operation using functor - which is a function two args interpreted as (self[i, j], j). + return reduce(cls.col_join, args) - >>> from sympy import ones - >>> I = ones(3) - >>> I.row(1, lambda v,i: v*3) - >>> I - [1, 1, 1] - [3, 3, 3] - [1, 1, 1] - >>> I.row(1) - [3, 3, 3] + def row_join(self, rhs): + """Concatenates two matrices along self's last and rhs's first column - See Also + Examples ======== - col - row_swap - row_del - row_join - row_insert - delRowCol - """ - if f is None: - return self[i, :] - for j in range(0, self.cols): - self[i, j] = f(self[i, j], j) - - def col(self, j, f=None): - """ - Elementary column selector (default) or operation using functor - which is a function two args interpreted as (self[i, j], i). - - >>> from sympy import ones - >>> I = ones(3) - >>> I.col(0, lambda v, i: v*3) - >>> I - [3, 1, 1] - [3, 1, 1] - [3, 1, 1] - >>> I.col(0) - [3] - [3] - [3] + >>> from sympy import zeros, ones + >>> M = zeros(3) + >>> V = ones(3, 1) + >>> M.row_join(V) + Matrix([ + [0, 0, 0, 1], + [0, 0, 0, 1], + [0, 0, 0, 1]]) See Also ======== row - col_swap - col_del col_join - col_insert - delRowCol """ - if f is None: - return self[:, j] - for i in range(0, self.rows): - self[i, j] = f(self[i, j], i) + if self.rows != rhs.rows: + raise ShapeError( + "`self` and `rhs` must have the same number of rows.") - def row_swap(self, i, j): - """ - Swap the two given rows of the matrix in-place. + newmat = self.zeros(self.rows, self.cols + rhs.cols) + newmat[:, :self.cols] = self + newmat[:, self.cols:] = rhs + return newmat - >>> from sympy.matrices import Matrix - >>> M = Matrix([[0,1],[1,0]]) - >>> M - [0, 1] - [1, 0] - >>> M.row_swap(0, 1) - >>> M - [1, 0] - [0, 1] + def col_join(self, bott): + """Concatenates two matrices along self's last and bott's first row - See Also + Examples ======== - row - col_swap - """ - for k in range(0, self.cols): - self[i, k], self[j, k] = self[j, k], self[i, k] - - def col_swap(self, i, j): - """ - Swap the two given columns of the matrix in-place. - - >>> from sympy.matrices import Matrix - >>> M = Matrix([[1,0],[1,0]]) - >>> M - [1, 0] - [1, 0] - >>> M.col_swap(0, 1) - >>> M - [0, 1] - [0, 1] + >>> from sympy import zeros, ones + >>> M = zeros(3) + >>> V = ones(1, 3) + >>> M.col_join(V) + Matrix([ + [0, 0, 0], + [0, 0, 0], + [0, 0, 0], + [1, 1, 1]]) See Also ======== col - row_swap + row_join """ - for k in range(0, self.rows): - self[k, i], self[k, j] = self[k, j], self[k, i] + if self.cols != bott.cols: + raise ShapeError( + "`self` and `bott` must have the same number of columns.") - def row_del(self, i): - """ - Delete the given row. + newmat = self.zeros(self.rows + bott.rows, self.cols) + newmat[:self.rows, :] = self + newmat[self.rows:, :] = bott + return newmat - >>> import sympy - >>> M = sympy.matrices.eye(3) - >>> M.row_del(1) - >>> M #doctest: +NORMALIZE_WHITESPACE - [1, 0, 0] - [0, 0, 1] + def row_insert(self, pos, mti): + """Insert one or more rows at the given row position. - See Also + Examples ======== - row - col_del - """ - self.mat = self.mat[:i*self.cols] + self.mat[(i+1)*self.cols:] - self.rows -= 1 - - def col_del(self, i): - """ - Delete the given column. - - >>> import sympy - >>> M = sympy.matrices.eye(3) - >>> M.col_del(1) - >>> M #doctest: +NORMALIZE_WHITESPACE - [1, 0] - [0, 0] - [0, 1] + >>> from sympy import zeros, ones + >>> M = zeros(3) + >>> V = ones(1, 3) + >>> M.row_insert(1, V) + Matrix([ + [0, 0, 0], + [1, 1, 1], + [0, 0, 0], + [0, 0, 0]]) See Also ======== - col - row_del + row + col_insert """ - for j in range(self.rows-1, -1, -1): - del self.mat[i+j*self.cols] - self.cols -= 1 + if pos == 0: + return mti.col_join(self) + elif pos < 0: + pos = self.rows + pos + if pos < 0: + pos = 0 + elif pos > self.rows: + pos = self.rows - # Utility functions - def simplify(self, ratio=1.7, measure=count_ops): - """Applies simplify to the elements of a matrix in place. + if self.cols != mti.cols: + raise ShapeError( + "`self` and `mti` must have the same number of columns.") - This is a shortcut for M.applyfunc(lambda x: simplify(x, ratio, measure)) + newmat = self.zeros(self.rows + mti.rows, self.cols) + i, j = pos, pos + mti.rows + newmat[:i, :] = self[:i, :] + newmat[i: j, :] = mti + newmat[j:, :] = self[i:, :] + return newmat - See Also - ======== + def col_insert(self, pos, mti): + """Insert one or more columns at the given column position. - sympy.simplify.simplify.simplify - """ - for i in range(len(self.mat)): - self.mat[i] = _simplify(self.mat[i], ratio=ratio, measure=measure) + Examples + ======== - def fill(self, value): - """Fill the matrix with the scalar value. + >>> from sympy import zeros, ones + >>> M = zeros(3) + >>> V = ones(3, 1) + >>> M.col_insert(1, V) + Matrix([ + [0, 1, 0, 0], + [0, 1, 0, 0], + [0, 1, 0, 0]]) See Also ======== - zeros - ones + col + row_insert """ - self.mat = [value]*len(self) - - ############################ - # Mutable matrix operators # - ############################ - - @call_highest_priority('__radd__') - def __add__(self, other): - return MatrixBase.__add__(self, force_mutable(other)) + if pos == 0: + return mti.row_join(self) + elif pos < 0: + pos = self.cols + pos + if pos < 0: + pos = 0 + elif pos > self.cols: + pos = self.cols - @call_highest_priority('__add__') - def __radd__(self, other): - return MatrixBase.__radd__(self, force_mutable(other)) + if self.rows != mti.rows: + raise ShapeError("self and mti must have the same number of rows.") - @call_highest_priority('__rsub__') - def __sub__(self, other): - return MatrixBase.__sub__(self, force_mutable(other)) - @call_highest_priority('__sub__') - def __rsub__(self, other): - return MatrixBase.__rsub__(self, force_mutable(other)) + newmat = self.zeros(self.rows, self.cols + mti.cols) + i, j = pos, pos + mti.cols + newmat[:, :i] = self[:, :i] + newmat[:, i:j] = mti + newmat[:, j:] = self[:, i:] + return newmat - @call_highest_priority('__rmul__') - def __mul__(self, other): - return MatrixBase.__mul__(self, force_mutable(other)) - @call_highest_priority('__mul__') - def __rmul__(self, other): - return MatrixBase.__rmul__(self, force_mutable(other)) + def replace(self, F, G, map=False): + """Replaces Function F in Matrix entries with Function G. - @call_highest_priority('__div__') - def __div__(self, other): - return MatrixBase.__div__(self, force_mutable(other)) - @call_highest_priority('__truediv__') - def __truediv__(self, other): - return MatrixBase.__truediv__(self, force_mutable(other)) - - @call_highest_priority('__rpow__') - def __pow__(self, other): - return MatrixBase.__pow__(self, other) + Examples + ======== - @call_highest_priority('__pow__') - def __rpow__(self, other): - raise NotImplementedError("Matrix Power not defined") + >>> from sympy import symbols, Function, Matrix + >>> F, G = symbols('F, G', cls=Function) + >>> M = Matrix(2, 2, lambda i, j: F(i+j)) ; M + Matrix([ + [F(0), F(1)], + [F(1), F(2)]]) + >>> N = M.replace(F,G) + >>> N + Matrix([ + [G(0), G(1)], + [G(1), G(2)]]) + """ + M = self[:, :] -def force_mutable(x): - """ - Safely turn a Matrix object into a Mutable Matrix - """ - if not isinstance(x, Basic): - return x - if not x.is_Matrix: - return x - if x.is_MatrixExpr: - return x.as_mutable() - return x + return M.applyfunc(lambda x: x.replace(F, G, map)) -def classof(A,B): +def classof(A, B): """ - Determines strategy for combining Immutable and Mutable matrices + Get the type of the result when combining matrices of different types. - Currently the strategy is that Mutability is contagious + Currently the strategy is that immutability is contagious. Examples ======== >>> from sympy import Matrix, ImmutableMatrix >>> from sympy.matrices.matrices import classof - >>> M = Matrix([[1,2],[3,4]]) # a Mutable Matrix - >>> IM = ImmutableMatrix([[1,2],[3,4]]) + >>> M = Matrix([[1, 2], [3, 4]]) # a Mutable Matrix + >>> IM = ImmutableMatrix([[1, 2], [3, 4]]) >>> classof(M, IM) - + """ - from .immutable_matrix import ImmutableMatrix try: if A._class_priority > B._class_priority: return A.__class__ else: return B.__class__ - except: pass + except: + pass try: import numpy if isinstance(A, numpy.ndarray): return B.__class__ if isinstance(B, numpy.ndarray): return A.__class__ - except: pass - raise TypeError("Incompatible classes %s, %s"%(A.__class__, B.__class__)) - -def matrix_multiply(A, B): - """ - Matrix product A*B. - - A and B must be of appropriate dimensions. If A is an m x k matrix, and B - is a k x n matrix, the product will be an m x n matrix. - - Examples - ======== - - >>> from sympy import Matrix - >>> A = Matrix([[1, 2, 3], [4, 5, 6]]) - >>> B = Matrix([[1, 2, 3], [4, 5, 6], [7, 8, 9]]) - >>> A*B - [30, 36, 42] - [66, 81, 96] - >>> B*A - Traceback (most recent call last): - ... - ShapeError: Matrices size mismatch. - >>> - - See Also - ======== - - matrix_multiply_elementwise - matrix_add - """ - # The following implmentation is equivalent, but about 5% slower - #ma, na = A.shape - #mb, nb = B.shape - # - #if na != mb: - # raise ShapeError() - #product = Matrix(ma, nb, lambda i,j: 0) - #for i in xrange(ma): - # for j in xrange(nb): - # s = 0 - # for k in range(na): - # s += A[i, k]*B[k, j] - # product[i, j] = s - #return product - if A.shape[1] != B.shape[0]: - raise ShapeError("Matrices size mismatch.") - blst = B.T.tolist() - alst = A.tolist() - return classof(A,B)._new(A.shape[0], B.shape[1], lambda i, j: - reduce(lambda k, l: k+l, - list(map(lambda n, m: n*m, - alst[i], - blst[j])), 0)) - -def matrix_multiply_elementwise(A, B): - """Return the Hadamard product (elementwise product) of A and B - - >>> from sympy.matrices.matrices import Matrix, matrix_multiply_elementwise - >>> A = Matrix([[0, 1, 2], [3, 4, 5]]) - >>> B = Matrix([[1, 10, 100], [100, 10, 1]]) - >>> matrix_multiply_elementwise(A, B) - [ 0, 10, 200] - [300, 40, 5] - - See Also - ======== - - matrix_multiply - matrix_add - """ - if A.shape != B.shape: - raise ShapeError() - shape = A.shape - return classof(A,B)._new(shape[0], shape[1], - lambda i, j: A[i,j] * B[i, j]) - -def matrix_add(A, B): - """Return A + B - - See Also - ======== - - matrix_multiply - matrix_multiply_elementwise - """ - if A.shape != B.shape: - raise ShapeError() - alst = A.tolist() - blst = B.tolist() - ret = [0]*A.shape[0] - for i in range(A.shape[0]): - ret[i] = list(map(lambda j,k: j+k, alst[i], blst[i])) - return classof(A,B)._new(ret) - -def zeros(r, c=None, cls=MutableMatrix): - """Returns a matrix of zeros with ``r`` rows and ``c`` columns; - if ``c`` is omitted a square matrix will be returned. - - See Also - ======== - - ones - eye - diag - """ - if is_sequence(r): - SymPyDeprecationWarning( - feature="The syntax zeros([%i, %i])" % tuple(r), useinstead="zeros(%i, %i)." % tuple(r), - issue=3381, deprecated_since_version="0.7.2", - ).warn() - r, c = r - else: - c = r if c is None else c - r, c = [int(i) for i in [r, c]] - return cls.zeros(r, c) - -def ones(r, c=None): - """Returns a matrix of ones with ``r`` rows and ``c`` columns; - if ``c`` is omitted a square matrix will be returned. - - See Also - ======== - - zeros - eye - diag - """ - - if is_sequence(r): - SymPyDeprecationWarning( - feature="The syntax ones([%i, %i])" % tuple(r), useinstead="ones(%i, %i)." % tuple(r), - issue=3381, deprecated_since_version="0.7.2", - ).warn() - r, c = r - else: - c = r if c is None else c - r, c = [int(i) for i in [r, c]] - return MutableMatrix(r, c, [S.One]*r*c) - -def eye(n, cls=MutableMatrix): - """Create square identity matrix n x n - - See Also - ======== - - diag - zeros - ones - """ - n = int(n) - out = cls.zeros(n) - for i in range(n): - out[i, i] = S.One - return out - -def diag(*values): - """Create diagonal matrix from a list as a diagonal values. - - Arguments might be matrices too, in case of it they are fitted in result matrix + except: + pass + raise TypeError("Incompatible classes %s, %s" % (A.__class__, B.__class__)) - Examples - ======== - - >>> from sympy.matrices import diag, Matrix - >>> diag(1, 2, 3) - [1, 0, 0] - [0, 2, 0] - [0, 0, 3] - - >>> from sympy.abc import x, y, z - >>> a = Matrix([x, y, z]) - >>> b = Matrix([[1, 2], [3, 4]]) - >>> c = Matrix([[5, 6]]) - >>> diag(a, 7, b, c) - [x, 0, 0, 0, 0, 0] - [y, 0, 0, 0, 0, 0] - [z, 0, 0, 0, 0, 0] - [0, 7, 0, 0, 0, 0] - [0, 0, 1, 2, 0, 0] - [0, 0, 3, 4, 0, 0] - [0, 0, 0, 0, 5, 6] - - See Also - ======== - - eye - """ - rows = 0 - cols = 0 - for m in values: - if isinstance(m, MatrixBase): - rows += m.rows - cols += m.cols - else: - rows += 1 - cols += 1 - res = zeros(rows, cols) - i_row = 0 - i_col = 0 - for m in values: - if isinstance(m, MatrixBase): - res[i_row:i_row + m.rows, i_col:i_col + m.cols] = m - i_row += m.rows - i_col += m.cols - else: - res[i_row, i_col] = m - i_row += 1 - i_col += 1 - return res - -def jordan_cell(eigenval, n): - """ - Create matrix of Jordan cell kind: - - Examples - ======== - - >>> from sympy.matrices.matrices import jordan_cell - >>> from sympy.abc import x - >>> jordan_cell(x, 4) - [x, 1, 0, 0] - [0, x, 1, 0] - [0, 0, x, 1] - [0, 0, 0, x] - """ - n = int(n) - out = zeros(n) - for i in range(n-1): - out[i, i] = eigenval - out[i, i+1] = S.One - out[n-1, n-1] = eigenval - return out - -def randMatrix(r, c=None, min=0, max=99, seed=None, symmetric=False): - """Create random matrix with dimensions ``r`` x ``c``. If ``c`` is omitted - the matrix will be square. If ``symmetric`` is True the matrix must be - square. - - Examples - ======== - - >>> from sympy.matrices import randMatrix - >>> randMatrix(3) # doctest:+SKIP - [25, 45, 27] - [44, 54, 9] - [23, 96, 46] - >>> randMatrix(3, 2) # doctest:+SKIP - [87, 29] - [23, 37] - [90, 26] - >>> randMatrix(3, 3, 0, 2) # doctest:+SKIP - [0, 2, 0] - [2, 0, 1] - [0, 0, 1] - >>> randMatrix(3, symmetric=True) # doctest:+SKIP - [85, 26, 29] - [26, 71, 43] - [29, 43, 57] - >>> A = randMatrix(3, seed=1) - >>> B = randMatrix(3, seed=2) - >>> A == B # doctest:+SKIP - False - >>> A == randMatrix(3, seed=1) - True - """ - if c is None: - c = r - if seed is None: - prng = random.Random() # use system time - else: - prng = random.Random(seed) - if symmetric and r != c: - raise ValueError('For symmetric matrices, r must equal c, but %i != %i' % (r, c)) - if not symmetric: - return MutableMatrix(r, c, lambda i, j: prng.randint(min, max)) - m = zeros(r) - for i in range(r): - for j in range(i, r): - m[i, j] = prng.randint(min, max) - for i in range(r): - for j in range(i): - m[i, j] = m[j, i] - return m - -def hessian(f, varlist): - """Compute Hessian matrix for a function f - - see: http://en.wikipedia.org/wiki/Hessian_matrix - - See Also - ======== - - sympy.matrices.matrices.Matrix.jacobian - wronskian - """ - # f is the expression representing a function f, return regular matrix - if is_sequence(varlist): - m = len(varlist) - if not m: - raise ShapeError("`len(varlist)` must not be zero.") - elif isinstance(varlist, MatrixBase): - m = varlist.cols - if not m: - raise ShapeError("`varlist.cols` must not be zero.") - if varlist.rows != 1: - raise ShapeError("`varlist` must be a row vector.") - else: - raise ValueError("Improper variable list in hessian function") - if not getattr(f, 'diff'): - # check differentiability - raise ValueError("Function `f` (%s) is not differentiable" % f) - out = zeros(m) - for i in range(m): - for j in range(i,m): - out[i,j] = f.diff(varlist[i]).diff(varlist[j]) - for i in range(m): - for j in range(i): - out[i,j] = out[j,i] - return out - -def GramSchmidt(vlist, orthog=False): - """ - Apply the Gram-Schmidt process to a set of vectors. - - see: http://en.wikipedia.org/wiki/Gram%E2%80%93Schmidt_process - """ - out = [] - m = len(vlist) - for i in range(m): - tmp = vlist[i] - for j in range(i): - tmp -= vlist[i].project(out[j]) - if tmp == MutableMatrix([[0,0,0]]): - raise ValueError("GramSchmidt: vector set not linearly independent") - out.append(tmp) - if orthog: - for i in range(len(out)): - out[i] = out[i].normalized() - return out - -def wronskian(functions, var, method='bareis'): - """ - Compute Wronskian for [] of functions - - :: - - | f1 f2 ... fn | - | f1' f2' ... fn' | - | . . . . | - W(f1,...,fn) = | . . . . | - | . . . . | - | (n) (n) (n) | - | D (f1) D (f2) ... D (fn) | - - see: http://en.wikipedia.org/wiki/Wronskian - - See Also - ======== - - sympy.matrices.matrices.Matrix.jacobian - hessian - """ - - for index in range(0, len(functions)): - functions[index] = sympify(functions[index]) - n = len(functions) - if n == 0: - return 1 - W = MutableMatrix(n, n, lambda i,j: functions[i].diff(var, j) ) - return W.det(method) - -def casoratian(seqs, n, zero=True): - """Given linear difference operator L of order 'k' and homogeneous - equation Ly = 0 we want to compute kernel of L, which is a set - of 'k' sequences: a(n), b(n), ... z(n). - - Solutions of L are linearly independent iff their Casoratian, - denoted as C(a, b, ..., z), do not vanish for n = 0. - - Casoratian is defined by k x k determinant:: - - + a(n) b(n) . . . z(n) + - | a(n+1) b(n+1) . . . z(n+1) | - | . . . . | - | . . . . | - | . . . . | - + a(n+k-1) b(n+k-1) . . . z(n+k-1) + - - It proves very useful in rsolve_hyper() where it is applied - to a generating set of a recurrence to factor out linearly - dependent solutions and return a basis: - - >>> from sympy import Symbol, casoratian, factorial - >>> n = Symbol('n', integer=True) - - Exponential and factorial are linearly independent: - - >>> casoratian([2**n, factorial(n)], n) != 0 - True - - """ - seqs = list(map(sympify, seqs)) - - if not zero: - f = lambda i, j: seqs[j].subs(n, n+i) - else: - f = lambda i, j: seqs[j].subs(n, i) - - k = len(seqs) - - return MutableMatrix(k, k, f).det() - - - -class SparseMatrix(MatrixBase): - """ - A sparse matrix (a matrix with a large number of zero elements). - - See Also - ======== - - :class:`Matrix` - """ - - def __init__(self, *args): - self.mat = {} - if len(args) == 3 and isinstance(args[2], collections.Callable): - op = args[2] - if not isinstance(args[0], (int, Integer)) or not isinstance(args[1], (int, Integer)): - raise TypeError("`args[0]` and `args[1]` must both be integers.") - self.rows = args[0] - self.cols = args[1] - for i in range(self.rows): - for j in range(self.cols): - value = sympify(op(i,j)) - if value: - self.mat[(i,j)] = value - elif len(args)==3 and isinstance(args[0],int) and \ - isinstance(args[1],int) and is_sequence(args[2]): - self.rows = args[0] - self.cols = args[1] - mat = args[2] - for i in range(self.rows): - for j in range(self.cols): - value = sympify(mat[i*self.cols+j]) - if value: - self.mat[(i,j)] = value - elif len(args)==3 and isinstance(args[0],int) and \ - isinstance(args[1],int) and isinstance(args[2], dict): - self.rows = args[0] - self.cols = args[1] - # manual copy, copy.deepcopy() doesn't work - for key in list(args[2].keys()): - self.mat[key] = args[2][key] - else: - # TODO: _handle_creation_inputs creates a temporary dense array - # and calls sympify on each element. This is a waste of time. - # Just like above rewrite the rest of the handled cases with - # "sparse" logic. - r, c, mat = self._handle_creation_inputs(*args) - self.rows = r - self.cols = c - for i in range(self.rows): - for j in range(self.cols): - value = mat[self.cols*i+j] - if value: - self.mat[(i,j)] = value - - def __getitem__(self, key): - if isinstance(key, slice) or isinstance(key, int): - lo, hi = self.slice2bounds(key, len(self)) - L = [] - for i in range(lo, hi): - m, n = self.rowdecomp(i) - if (m, n) in self.mat: - L.append(self.mat[(m, n)]) - else: - L.append(S.Zero) - if len(L) == 1: - return L[0] - else: - return L - if len(key) != 2: - raise ValueError("`key` must be of length 2.") - - if isinstance(key[0], int) and isinstance(key[1], int): - i, j=self.key2ij(key) - if (i, j) in self.mat: - return self.mat[(i, j)] - else: - return S.Zero - elif isinstance(key[0], slice) or isinstance(key[1], slice): - return self.submatrix(key) - else: - raise IndexError("Index out of range: a[%s]"%repr(key)) - - def rowdecomp(self, num): - """ - Perform a row decomposition on the matrix. - """ - nmax = len(self) - if not (0 <= num < nmax) or not (0 <= -num < nmax): - raise ValueError("`num` must satisfy 0 <= `num` < `self.rows*" + - "*self.cols` (%d) and 0 <= -num < " % nmax + - "`self.rows*self.cols` (%d) to apply redecomp()." % nmax) - i, j = 0, num - while j >= self.cols: - j -= self.cols - i += 1 - return i,j - - def __setitem__(self, key, value): - # almost identical, need to test for 0 - if len(key) != 2: - raise ValueError("`key` must be of length 2.") - - if isinstance(key[0], slice) or isinstance(key[1], slice): - if isinstance(value, Matrix): - self.copyin_matrix(key, value) - if is_sequence(value): - self.copyin_list(key, value) - else: - i, j=self.key2ij(key) - testval = sympify(value) - if testval: - self.mat[(i, j)] = testval - elif (i, j) in self.mat: - del self.mat[(i, j)] - - def row_del(self, k): - """ - Delete the given row of the matrix. - - Examples - ======== - - >>> import sympy - >>> M = sympy.matrices.SparseMatrix([[0,0],[0,1]]) - >>> M - [0, 0] - [0, 1] - >>> M.row_del(0) - >>> M - [0, 1] - - See Also - ======== - - col_del - """ - newD = {} - k = self.key2ij((k, 0))[0] - for (i, j) in list(self.mat.keys()): - if i == k: - pass - elif i > k: - newD[i - 1, j] = self.mat[i, j] - else: - newD[i, j] = self.mat[i, j] - self.mat = newD - self.rows -= 1 - - def col_del(self, k): - """ - Delete the given column of the matrix. - - Examples - ======== - - >>> import sympy - >>> M = sympy.matrices.SparseMatrix([[0,0],[0,1]]) - >>> M - [0, 0] - [0, 1] - >>> M.col_del(0) - >>> M - [0] - [1] - - See Also - ======== - - row_del - """ - newD = {} - k = self.key2ij((0, k))[1] - for (i, j) in list(self.mat.keys()): - if j == k: - pass - elif j > k: - newD[i, j - 1] = self.mat[i, j] - else: - newD[i, j] = self.mat[i, j] - self.mat = newD - self.cols -= 1 - - def toMatrix(self): - """ - Convert this sparse matrix into a matrix. - """ - l = [] - for i in range(self.rows): - c = [] - l.append(c) - for j in range(self.cols): - if (i, j) in self.mat: - c.append(self[i, j]) - else: - c.append(S.Zero) - return Matrix(l) - - def row_list(self): - """ - Returns a Row-sorted list of non-zero elements of the matrix. - - >>> from sympy.matrices import SparseMatrix - >>> a=SparseMatrix(((1,2),(3,4))) - >>> a - [1, 2] - [3, 4] - >>> a.RL - [(0, 0, 1), (0, 1, 2), (1, 0, 3), (1, 1, 4)] - - See Also - ======== - - col_list - """ - - new=[] - for i in range(self.rows): - for j in range(self.cols): - value = self[(i, j)] - if value: - new.append((i, j, value)) - return new - - RL = property(row_list,None,None,"Alternate faster representation") - - def col_list(self): - """ - Returns a Column-sorted list of non-zero elements of the matrix. - >>> from sympy.matrices import SparseMatrix - >>> a=SparseMatrix(((1,2),(3,4))) - >>> a - [1, 2] - [3, 4] - >>> a.CL - [(0, 0, 1), (1, 0, 3), (0, 1, 2), (1, 1, 4)] - - See Also - ======== - - row_list - """ - new=[] - for j in range(self.cols): - for i in range(self.rows): - value = self[(i, j)] - if value: - new.append((i, j, value)) - return new - - CL = property(col_list,None,None,"Alternate faster representation") - - def transpose(self): - """ - Returns the transposed SparseMatrix of this SparseMatrix - >>> from sympy.matrices import SparseMatrix - >>> a = SparseMatrix(((1,2),(3,4))) - >>> a - [1, 2] - [3, 4] - >>> a.T - [1, 3] - [2, 4] - """ - tran = SparseMatrix(self.cols, self.rows, {}) - for key, value in self.mat.items(): - tran.mat[key[1], key[0]]=value - return tran - - T = property(transpose,None,None,"Matrix transposition.") - - - def __add__(self, other): - if isinstance(other, SparseMatrix): - return self.add(other) - else: - raise NotImplementedError("Only SparseMatrix + SparseMatrix supported") - - def __radd__(self, other): - if isinstance(other, SparseMatrix): - return self.add(other) - else: - raise NotImplementedError("Only SparseMatrix + SparseMatrix supported") - - def add(self, other): - """ - Add two sparse matrices with dictionary representation. - - >>> from sympy.matrices.matrices import SparseMatrix - >>> A = SparseMatrix(5, 5, lambda i, j: i * j + i) - >>> A - [0, 0, 0, 0, 0] - [1, 2, 3, 4, 5] - [2, 4, 6, 8, 10] - [3, 6, 9, 12, 15] - [4, 8, 12, 16, 20] - >>> B = SparseMatrix(5, 5, lambda i, j: i + 2 * j) - >>> B - [0, 2, 4, 6, 8] - [1, 3, 5, 7, 9] - [2, 4, 6, 8, 10] - [3, 5, 7, 9, 11] - [4, 6, 8, 10, 12] - >>> A + B - [0, 2, 4, 6, 8] - [2, 5, 8, 11, 14] - [4, 8, 12, 16, 20] - [6, 11, 16, 21, 26] - [8, 14, 20, 26, 32] - - See Also - ======== - - multiply - """ - if self.shape != other.shape: - raise ShapeError() - a, b = list(self.mat.keys()), list(other.mat.keys()) - a.sort() - b.sort() - i = j = 0 - c = {} - while i < len(a) or j < len(b): - if j >= len(b) or (i < len(a) and a[i] < b[j]): - c[a[i]] = self.mat[a[i]] - i = i + 1 - continue - elif i >= len(a) or (j < len(b) and a[i] > b[j]): - c[b[j]] = other.mat[b[j]] - j = j + 1 - continue - else: - c[a[i]] = self.mat[a[i]] + other.mat[b[j]] - i = i + 1 - j = j + 1 - return SparseMatrix(self.rows, self.cols, c) - - - - # from here to end all functions are same as in matrices.py - # with Matrix replaced with SparseMatrix - def copyin_list(self, key, value): - if not is_sequence(value): - raise TypeError("`value` must be of type list or tuple.") - self.copyin_matrix(key, SparseMatrix(value)) - - def multiply(self,b): - """Returns self*b - - See Also - ======== - - add - """ - - def dotprod(a, b, i, j): - if a.cols != b.rows: - raise ShapeError("`self.cols` must equal `b.rows`.") - r=0 - for x in range(a.cols): - r+=a[i, x]*b[x, j] - return r - - r = SparseMatrix(self.rows, b.cols, - lambda i,j: dotprod(self, b, i, j)) - if r.rows == 1 and r.cols ==1: - return r[0, 0] - return r - - def submatrix(self, keys): - rlo, rhi, clo, chi = self.key2bounds(keys) - return SparseMatrix(rhi -rlo, chi - clo, - lambda i, j: self[i + rlo, j + clo]) - - def reshape(self, _rows, _cols): - if len(self) != _rows*_cols: - raise ValueError("Invalid reshape parameters %d %d" % (_rows, _cols)) - newD = {} - for i in range(_rows): - for j in range(_cols): - m, n = self.rowdecomp(i*_cols + j) - if (m, n) in self.mat: - newD[(i, j)] = self.mat[(m, n)] - return SparseMatrix(_rows, _cols, newD) - - def cross(self, b): - if not is_sequence(b, include=Matrix): - raise TypeError("`b` must be an ordered iterable or Matrix, not %s." % - type(b)) - if not (self.rows == 1 and self.cols == 3 or \ - self.rows == 3 and self.cols == 1 ) and \ - (b.rows == 1 and b.cols == 3 or \ - b.rows == 3 and b.cols == 1): - raise ShapeError("Dimensions incorrect for cross product") - else: - return SparseMatrix(1,3,((self[1]*b[2] - self[2]*b[1]), - (self[2]*b[0] - self[0]*b[2]), - (self[0]*b[1] - self[1]*b[0]))) - - - @classmethod - def zeros(cls, r, c=None): - """Returns a matrix of zeros with ``r`` rows and ``c`` columns; - if ``c`` is omitted a square matrix will be returned.""" - if is_sequence(r): - SymPyDeprecationWarning( - feature="The syntax zeros([%i, %i])" % tuple(r), useinstead="zeros(%i, %i)." % tuple(r), - issue=3381, deprecated_since_version="0.7.2", - ).warn() - r, c = r - else: - c = r if c is None else c - r, c = [int(i) for i in [r, c]] - return cls(r, c, {}) - @classmethod - def eye(cls, n): - n = int(n) - tmp = cls.zeros(n) - for i in range(tmp.rows): - tmp[i, i] = 1 - return tmp - - def __hash__(self): - return super(Matrix, self).__hash__() - -def list2numpy(l): # pragma: no cover - """Converts python list of SymPy expressions to a NumPy array. - - See Also - ======== - - matrix2numpy - """ - from numpy import empty - a = empty(len(l), dtype=object) - for i, s in enumerate(l): - a[i] = s - return a - -def matrix2numpy(m): # pragma: no cover - """Converts SymPy's matrix to a NumPy array. - - See Also - ======== - - list2numpy - """ - from numpy import empty - a = empty(m.shape, dtype=object) - for i in range(m.rows): - for j in range(m.cols): - a[i, j] = m[i, j] - return a - -def a2idx(a): - """ - Tries to convert "a" to an index, returns None on failure. - - The result of a2idx() (if not None) can be safely used as an index to - arrays/matrices. - """ - if hasattr(a, "__int__"): - return int(a) - if hasattr(a, "__index__"): - return a.__index__() - -def symarray(prefix, shape): - """Create a numpy ndarray of symbols (as an object array). - - The created symbols are named ``prefix_i1_i2_``... You should thus provide a - non-empty prefix if you want your symbols to be unique for different output - arrays, as SymPy symbols with identical names are the same object. - - Parameters - ---------- - - prefix : string - A prefix prepended to the name of every symbol. - - shape : int or tuple - Shape of the created array. If an int, the array is one-dimensional; for - more than one dimension the shape must be a tuple. - - Examples - -------- - These doctests require numpy. - - >>> from sympy import symarray - >>> symarray('', 3) #doctest: +SKIP - [_0, _1, _2] - - If you want multiple symarrays to contain distinct symbols, you *must* - provide unique prefixes: - - >>> a = symarray('', 3) #doctest: +SKIP - >>> b = symarray('', 3) #doctest: +SKIP - >>> a[0] is b[0] #doctest: +SKIP - True - >>> a = symarray('a', 3) #doctest: +SKIP - >>> b = symarray('b', 3) #doctest: +SKIP - >>> a[0] is b[0] #doctest: +SKIP - False - - Creating symarrays with a prefix: - - >>> symarray('a', 3) #doctest: +SKIP - [a_0, a_1, a_2] - - For more than one dimension, the shape must be given as a tuple: - - >>> symarray('a', (2, 3)) #doctest: +SKIP - [[a_0_0, a_0_1, a_0_2], - [a_1_0, a_1_1, a_1_2]] - >>> symarray('a', (2, 3, 2)) #doctest: +SKIP - [[[a_0_0_0, a_0_0_1], - [a_0_1_0, a_0_1_1], - [a_0_2_0, a_0_2_1]], - - [[a_1_0_0, a_1_0_1], - [a_1_1_0, a_1_1_1], - [a_1_2_0, a_1_2_1]]] - - """ - try: - import numpy as np - except ImportError: - raise ImportError("symarray requires numpy to be installed") - - arr = np.empty(shape, dtype=object) - for index in np.ndindex(shape): - arr[index] = Symbol('%s_%s' % (prefix, '_'.join(map(str, index)))) - return arr - -def rot_axis3(theta): - """Returns a rotation matrix for a rotation of theta (in radians) about - the 3-axis. - - Examples - -------- - - >>> from sympy import pi - >>> from sympy.matrices import rot_axis3 - - A rotation of pi/3 (60 degrees): - - >>> theta = pi/3 - >>> rot_axis3(theta) - [ 1/2, sqrt(3)/2, 0] - [-sqrt(3)/2, 1/2, 0] - [ 0, 0, 1] - - If we rotate by pi/2 (90 degrees): - - >>> rot_axis3(pi/2) - [ 0, 1, 0] - [-1, 0, 0] - [ 0, 0, 1] - - See Also - ======== - - rot_axis1: Returns a rotation matrix for a rotation of theta (in radians) - about the 1-axis - rot_axis2: Returns a rotation matrix for a rotation of theta (in radians) - about the 2-axis - """ - ct = cos(theta) - st = sin(theta) - mat = ((ct,st,0), - (-st,ct,0), - (0,0,1)) - return MutableMatrix(mat) - -def rot_axis2(theta): - """Returns a rotation matrix for a rotation of theta (in radians) about - the 2-axis. - - Examples - -------- - - >>> from sympy import pi - >>> from sympy.matrices import rot_axis2 - - A rotation of pi/3 (60 degrees): - - >>> theta = pi/3 - >>> rot_axis2(theta) - [ 1/2, 0, -sqrt(3)/2] - [ 0, 1, 0] - [sqrt(3)/2, 0, 1/2] - - If we rotate by pi/2 (90 degrees): - - >>> rot_axis2(pi/2) - [0, 0, -1] - [0, 1, 0] - [1, 0, 0] - - See Also - ======== - - rot_axis1: Returns a rotation matrix for a rotation of theta (in radians) - about the 1-axis - rot_axis3: Returns a rotation matrix for a rotation of theta (in radians) - about the 3-axis - """ - ct = cos(theta) - st = sin(theta) - mat = ((ct,0,-st), - (0,1,0), - (st,0,ct)) - return MutableMatrix(mat) - -def rot_axis1(theta): - """Returns a rotation matrix for a rotation of theta (in radians) about - the 1-axis. - - Examples - -------- - - >>> from sympy import pi - >>> from sympy.matrices import rot_axis1 - - A rotation of pi/3 (60 degrees): - - >>> theta = pi/3 - >>> rot_axis1(theta) - [1, 0, 0] - [0, 1/2, sqrt(3)/2] - [0, -sqrt(3)/2, 1/2] - - If we rotate by pi/2 (90 degrees): - - >>> rot_axis1(pi/2) - [1, 0, 0] - [0, 0, 1] - [0, -1, 0] - - See Also - ======== - - rot_axis2: Returns a rotation matrix for a rotation of theta (in radians) - about the 2-axis - rot_axis3: Returns a rotation matrix for a rotation of theta (in radians) - about the 3-axis - """ - ct = cos(theta) - st = sin(theta) - mat = ((1,0,0), - (0,ct,st), - (0,-st,ct)) - return MutableMatrix(mat) - -Matrix = MutableMatrix +def a2idx(j, n=None): + """Return integer after making positive and validating against n.""" + if isinstance(j, slice): + return j + if type(j) is not int: + try: + j = j.__index__() + except AttributeError: + raise IndexError("Invalid index a[%r]" % (j, )) + if n is not None: + if j < 0: + j += n + if not (j >= 0 and j < n): + raise IndexError("Index out of range: a[%s]" % (j, )) + return int(j) diff -Nru python3-sympy-0.7.2/sympy/matrices/sparse.py python3-sympy-0.7.3/sympy/matrices/sparse.py --- python3-sympy-0.7.2/sympy/matrices/sparse.py 1970-01-01 00:00:00.000000000 +0000 +++ python3-sympy-0.7.3/sympy/matrices/sparse.py 2013-07-13 17:53:32.000000000 +0000 @@ -0,0 +1,1524 @@ +import copy +from collections import defaultdict + +from sympy.core.containers import Dict +from sympy.core.compatibility import is_sequence, as_int +from sympy.core.singleton import S +from sympy.functions.elementary.miscellaneous import sqrt +from sympy.utilities.exceptions import SymPyDeprecationWarning + +from .matrices import MatrixBase, ShapeError, a2idx +from .dense import Matrix +import collections + + +class SparseMatrix(MatrixBase): + """ + A sparse matrix (a matrix with a large number of zero elements). + + Examples + ======== + + >>> from sympy.matrices import SparseMatrix + >>> SparseMatrix(2, 2, list(range(4))) + Matrix([ + [0, 1], + [2, 3]]) + >>> SparseMatrix(2, 2, {(1, 1): 2}) + Matrix([ + [0, 0], + [0, 2]]) + + See Also + ======== + sympy.matrices.dense.Matrix + """ + + def __init__(self, *args): + + if len(args) == 1 and isinstance(args[0], SparseMatrix): + self.rows = args[0].rows + self.cols = args[0].cols + self._smat = dict(args[0]._smat) + return + + self._smat = {} + + if len(args) == 3: + self.rows = as_int(args[0]) + self.cols = as_int(args[1]) + + if isinstance(args[2], collections.Callable): + op = args[2] + for i in range(self.rows): + for j in range(self.cols): + value = self._sympify(op(i, j)) + if value: + self._smat[(i, j)] = value + elif isinstance(args[2], (dict, Dict)): + # manual copy, copy.deepcopy() doesn't work + for key in list(args[2].keys()): + v = args[2][key] + if v: + self._smat[key] = v + elif is_sequence(args[2]): + if len(args[2]) != self.rows*self.cols: + raise ValueError( + 'List length (%s) != rows*columns (%s)' % + (len(args[2]), self.rows*self.cols)) + flat_list = args[2] + for i in range(self.rows): + for j in range(self.cols): + value = self._sympify(flat_list[i*self.cols + j]) + if value: + self._smat[(i, j)] = value + else: + # handle full matrix forms with _handle_creation_inputs + r, c, _list = Matrix._handle_creation_inputs(*args) + self.rows = r + self.cols = c + for i in range(self.rows): + for j in range(self.cols): + value = _list[self.cols*i + j] + if value: + self._smat[(i, j)] = value + + def __getitem__(self, key): + + if type(key) is tuple: + i, j = key + if isinstance(i, int) and isinstance(j, int): + i, j = self.key2ij(key) + rv = self._smat.get((i, j), S.Zero) + return rv + elif isinstance(i, slice) or isinstance(j, slice): + return self.submatrix(key) + + # check for single arg, like M[:] or M[3] + if isinstance(key, slice): + lo, hi = key.indices(len(self))[:2] + L = [] + for i in range(lo, hi): + m, n = divmod(i, self.cols) + L.append(self._smat.get((m, n), S.Zero)) + return L + + i, j = divmod(a2idx(key, len(self)), self.cols) + return self._smat.get((i, j), S.Zero) + + def __setitem__(self, key, value): + raise NotImplementedError() + + def copy(self): + return self._new(self.rows, self.cols, self._smat) + + @property + def is_Identity(self): + if not self.is_square: + return False + if not all(self[i, i] == 1 for i in range(self.rows)): + return False + return len(self) == self.rows + + def tolist(self): + """Convert this sparse matrix into a list of nested Python lists. + + Examples + ======== + + >>> from sympy.matrices import SparseMatrix, ones + >>> a = SparseMatrix(((1, 2), (3, 4))) + >>> a.tolist() + [[1, 2], [3, 4]] + + When there are no rows then it will not be possible to tell how + many columns were in the original matrix: + + >>> SparseMatrix(ones(0, 3)).tolist() + [] + + """ + if not self.rows: + return [] + if not self.cols: + return [[] for i in range(self.rows)] + I, J = self.shape + return [[self[i, j] for j in range(J)] for i in range(I)] + + def row(self, i): + """Returns column i from self as a row vector. + + Examples + ======== + + >>> from sympy.matrices import SparseMatrix + >>> a = SparseMatrix(((1, 2), (3, 4))) + >>> a.row(0) + Matrix([[1, 2]]) + + See Also + ======== + col + row_list + """ + return self[i,:] + + def col(self, j): + """Returns column j from self as a column vector. + + Examples + ======== + + >>> from sympy.matrices import SparseMatrix + >>> a = SparseMatrix(((1, 2), (3, 4))) + >>> a.col(0) + Matrix([ + [1], + [3]]) + + See Also + ======== + row + col_list + """ + return self[:, j] + + def row_list(self): + """Returns a row-sorted list of non-zero elements of the matrix. + + Examples + ======== + + >>> from sympy.matrices import SparseMatrix + >>> a = SparseMatrix(((1, 2), (3, 4))) + >>> a + Matrix([ + [1, 2], + [3, 4]]) + >>> a.RL + [(0, 0, 1), (0, 1, 2), (1, 0, 3), (1, 1, 4)] + + See Also + ======== + row_op + col_list + """ + return [tuple(k + (self[k],)) for k in sorted(list(self._smat.keys()), key=lambda k: list(k))] + + RL = property(row_list, None, None, "Alternate faster representation") + + def col_list(self): + """Returns a column-sorted list of non-zero elements of the matrix. + + Examples + ======== + + >>> from sympy.matrices import SparseMatrix + >>> a=SparseMatrix(((1, 2), (3, 4))) + >>> a + Matrix([ + [1, 2], + [3, 4]]) + >>> a.CL + [(0, 0, 1), (1, 0, 3), (0, 1, 2), (1, 1, 4)] + + See Also + ======== + col_op + row_list + """ + return [tuple(k + (self[k],)) for k in sorted(list(self._smat.keys()), key=lambda k: list(reversed(k)))] + + CL = property(col_list, None, None, "Alternate faster representation") + + def _eval_trace(self): + """Calculate the trace of a square matrix. + + Examples + ======== + + >>> from sympy.matrices import eye + >>> eye(3).trace() + 3 + + """ + trace = S.Zero + for i in range(self.cols): + trace += self._smat.get((i, i), 0) + return trace + + def _eval_transpose(self): + """Returns the transposed SparseMatrix of this SparseMatrix. + + Examples + ======== + + >>> from sympy.matrices import SparseMatrix + >>> a = SparseMatrix(((1, 2), (3, 4))) + >>> a + Matrix([ + [1, 2], + [3, 4]]) + >>> a.T + Matrix([ + [1, 3], + [2, 4]]) + """ + tran = self.zeros(self.cols, self.rows) + for key, value in self._smat.items(): + key = key[1], key[0] # reverse + tran._smat[key] = value + return tran + + def _eval_conjugate(self): + """Return the by-element conjugation. + + Examples + ======== + + >>> from sympy.matrices import SparseMatrix + >>> from sympy import I + >>> a = SparseMatrix(((1, 2 + I), (3, 4), (I, -I))) + >>> a + Matrix([ + [1, 2 + I], + [3, 4], + [I, -I]]) + >>> a.C + Matrix([ + [ 1, 2 - I], + [ 3, 4], + [-I, I]]) + + See Also + ======== + + transpose: Matrix transposition + H: Hermite conjugation + D: Dirac conjugation + """ + conj = self.copy() + for key, value in self._smat.items(): + conj._smat[key] = value.conjugate() + return conj + + def multiply(self, other): + """Fast multiplication exploiting the sparsity of the matrix. + + Examples + ======== + + >>> from sympy.matrices import SparseMatrix, ones + >>> A, B = SparseMatrix(ones(4, 3)), SparseMatrix(ones(3, 4)) + >>> A.multiply(B) == 3*ones(4) + True + + See Also + ======== + + add + """ + A = self + B = other + # sort B's row_list into list of rows + Blist = [[] for i in range(B.rows)] + for i, j, v in B.row_list(): + Blist[i].append((j, v)) + Cdict = defaultdict(int) + for k, j, Akj in A.row_list(): + for n, Bjn in Blist[j]: + temp = Akj*Bjn + Cdict[k, n] += temp + rv = self.zeros(A.rows, B.cols) + rv._smat = dict([(k, v) for k, v in Cdict.items() if v]) + return rv + + def scalar_multiply(self, scalar): + "Scalar element-wise multiplication" + M = self.zeros(*self.shape) + if scalar: + for i in self._smat: + v = scalar*self._smat[i] + if v: + M._smat[i] = v + else: + M._smat.pop(i, None) + return M + + def __mul__(self, other): + """Multiply self and other, watching for non-matrix entities. + + When multiplying be a non-sparse matrix, the result is no longer + sparse. + + Examples + ======== + + >>> from sympy.matrices import SparseMatrix, eye, zeros + >>> I = SparseMatrix(eye(3)) + >>> I*I == I + True + >>> Z = zeros(3) + >>> I*Z + Matrix([ + [0, 0, 0], + [0, 0, 0], + [0, 0, 0]]) + >>> I*2 == 2*I + True + """ + if isinstance(other, SparseMatrix): + return self.multiply(other) + if isinstance(other, MatrixBase): + return other._new(self*self._new(other)) + return self.scalar_multiply(other) + + def __rmul__(self, other): + """Return product the same type as other (if a Matrix). + + When multiplying be a non-sparse matrix, the result is no longer + sparse. + + Examples + ======== + + >>> from sympy.matrices import Matrix, SparseMatrix + >>> A = Matrix(2, 2, list(range(1, 5))) + >>> S = SparseMatrix(2, 2, list(range(2, 6))) + >>> A*S == S*A + False + >>> (isinstance(A*S, SparseMatrix) == + ... isinstance(S*A, SparseMatrix) == False) + True + """ + if isinstance(other, MatrixBase): + return other*other._new(self) + return self.scalar_multiply(other) + + def __add__(self, other): + """Add other to self, efficiently if possible. + + When adding a non-sparse matrix, the result is no longer + sparse. + + Examples + ======== + + >>> from sympy.matrices import SparseMatrix, eye + >>> A = SparseMatrix(eye(3)) + SparseMatrix(eye(3)) + >>> B = SparseMatrix(eye(3)) + eye(3) + >>> A + Matrix([ + [2, 0, 0], + [0, 2, 0], + [0, 0, 2]]) + >>> A == B + True + >>> isinstance(A, SparseMatrix) and isinstance(B, SparseMatrix) + False + + """ + if isinstance(other, SparseMatrix): + return self.add(other) + elif isinstance(other, MatrixBase): + return other._new(other + self) + else: + raise NotImplementedError( + "Cannot add %s to %s" % + tuple([c.__class__.__name__ for c in (other, self)])) + + def __neg__(self): + """Negate all elements of self. + + Examples + ======== + + >>> from sympy.matrices import SparseMatrix, eye + >>> -SparseMatrix(eye(3)) + Matrix([ + [-1, 0, 0], + [ 0, -1, 0], + [ 0, 0, -1]]) + + """ + + rv = self.copy() + for k, v in rv._smat.items(): + rv._smat[k] = -v + return rv + + def add(self, other): + """Add two sparse matrices with dictionary representation. + + Examples + ======== + + >>> from sympy.matrices import SparseMatrix, eye, ones + >>> SparseMatrix(eye(3)).add(SparseMatrix(ones(3))) + Matrix([ + [2, 1, 1], + [1, 2, 1], + [1, 1, 2]]) + >>> SparseMatrix(eye(3)).add(-SparseMatrix(eye(3))) + Matrix([ + [0, 0, 0], + [0, 0, 0], + [0, 0, 0]]) + + Only the non-zero elements are stored, so the resulting dictionary + that is used to represent the sparse matrix is empty: + >>> _._smat + {} + + See Also + ======== + + multiply + """ + if not isinstance(other, SparseMatrix): + raise ValueError('only use add with %s, not %s' % + tuple([c.__class__.__name__ for c in (self, other)])) + if self.shape != other.shape: + raise ShapeError() + M = self.copy() + for i, v in other._smat.items(): + v = M[i] + v + if v: + M._smat[i] = v + else: + M._smat.pop(i, None) + return M + + def submatrix(self, keys): + rlo, rhi, clo, chi = self.key2bounds(keys) + r, c = rhi - rlo, chi - clo + if r*c < len(self._smat): + # the subregion is smaller than the number of elements in self + if r == 1: + getter = lambda i, j: self[rlo, j + clo] + elif c == 1: + getter = lambda i, j: self[i + rlo, clo] + else: + getter = lambda i, j: self[i + rlo, j + clo] + return self._new(r, c, getter) + else: + # the number of non-zero elements is smaller than the subregion + smat = {} + for rk, ck in self._smat: + if rlo <= rk < rhi and clo <= ck < chi: + smat[(rk-rlo, ck-clo)] = self._smat[(rk, ck)] + return self._new(r, c, smat) + + def is_symmetric(self, simplify=True): + """Return True if self is symmetric. + + Examples + ======== + + >>> from sympy.matrices import SparseMatrix, eye + >>> M = SparseMatrix(eye(3)) + >>> M.is_symmetric() + True + >>> M[0, 2] = 1 + >>> M.is_symmetric() + False + """ + if simplify: + return all((k[1], k[0]) in self._smat and + not (self[k] - self[(k[1], k[0])]).simplify() + for k in self._smat) + else: + return all((k[1], k[0]) in self._smat and + self[k] == self[(k[1], k[0])] for k in self._smat) + + def has(self, *patterns): + """Test whether any subexpression matches any of the patterns. + + Examples + ======== + + >>> from sympy import SparseMatrix, Float + >>> from sympy.abc import x, y + >>> A = SparseMatrix(((1, x), (0.2, 3))) + >>> A.has(x) + True + >>> A.has(y) + False + >>> A.has(Float) + True + """ + return any(self[key].has(*patterns) for key in self._smat) + + def applyfunc(self, f): + """Apply a function to each element of the matrix. + + Examples + ======== + + >>> from sympy.matrices import SparseMatrix + >>> m = SparseMatrix(2, 2, lambda i, j: i*2+j) + >>> m + Matrix([ + [0, 1], + [2, 3]]) + >>> m.applyfunc(lambda i: 2*i) + Matrix([ + [0, 2], + [4, 6]]) + + """ + if not isinstance(f, collections.Callable): + raise TypeError("`f` must be callable.") + + out = self.copy() + for k, v in self._smat.items(): + fv = f(v) + if fv: + out._smat[k] = fv + else: + out._smat.pop(k, None) + return out + + def reshape(self, rows, cols): + """Reshape matrix while retaining original size. + + Examples + ======== + + >>> from sympy.matrices import SparseMatrix + >>> S = SparseMatrix(4, 2, list(range(8))) + >>> S.reshape(2, 4) + Matrix([ + [0, 1, 2, 3], + [4, 5, 6, 7]]) + + """ + if len(self) != rows*cols: + raise ValueError("Invalid reshape parameters %d %d" % (rows, cols)) + smat = {} + for k, v in self._smat.items(): + i, j = k + n = i*self.cols + j + ii, jj = divmod(n, cols) + smat[(ii, jj)] = self._smat[(i, j)] + return self._new(rows, cols, smat) + + def liupc(self): + """Liu's algorithm, for pre-determination of the Elimination Tree of + the given matrix, used in row-based symbolic Cholesky factorization. + + Examples + ======== + + >>> from sympy.matrices import SparseMatrix + >>> S = SparseMatrix([ + ... [1, 0, 3, 2], + ... [0, 0, 1, 0], + ... [4, 0, 0, 5], + ... [0, 6, 7, 0]]) + >>> S.liupc() + ([[0], [], [0], [1, 2]], [4, 3, 4, 4]) + + References + ========== + + Symbolic Sparse Cholesky Factorization using Elimination Trees, + Jeroen Van Grondelle (1999) + http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.39.7582, + downloaded from http://tinyurl.com/9o2jsxj + """ + # Algorithm 2.4, p 17 of reference + + # get the indices of the elements that are non-zero on or below diag + R = [[] for r in range(self.rows)] + for r, c, _ in self.row_list(): + if c <= r: + R[r].append(c) + + inf = len(R) # nothing will be this large + parent = [inf]*self.rows + virtual = [inf]*self.rows + for r in range(self.rows): + for c in R[r][:-1]: + while virtual[c] < r: + t = virtual[c] + virtual[c] = r + c = t + if virtual[c] == inf: + parent[c] = virtual[c] = r + return R, parent + + def row_structure_symbolic_cholesky(self): + """Symbolic cholesky factorization, for pre-determination of the + non-zero structure of the Cholesky factororization. + + Examples + ======== + + >>> from sympy.matrices import SparseMatrix + >>> S = SparseMatrix([ + ... [1, 0, 3, 2], + ... [0, 0, 1, 0], + ... [4, 0, 0, 5], + ... [0, 6, 7, 0]]) + >>> S.row_structure_symbolic_cholesky() + [[0], [], [0], [1, 2]] + + References + ========== + + Symbolic Sparse Cholesky Factorization using Elimination Trees, + Jeroen Van Grondelle (1999) + http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.39.7582, + downloaded from http://tinyurl.com/9o2jsxj + """ + + R, parent = self.liupc() + inf = len(R) # this acts as infinity + Lrow = copy.deepcopy(R) + for k in range(self.rows): + for j in R[k]: + while j != inf and j != k: + Lrow[k].append(j) + j = parent[j] + Lrow[k] = list(sorted(set(Lrow[k]))) + return Lrow + + def _cholesky_sparse(self): + """Algorithm for numeric Cholesky factorization of a sparse matrix.""" + Crowstruc = self.row_structure_symbolic_cholesky() + C = self.zeros(self.rows) + for i in range(len(Crowstruc)): + for j in Crowstruc[i]: + if i != j: + C[i, j] = self[i, j] + summ = 0 + for p1 in Crowstruc[i]: + if p1 < j: + for p2 in Crowstruc[j]: + if p2 < j: + if p1 == p2: + summ += C[i, p1]*C[j, p1] + else: + break + else: + break + C[i, j] -= summ + C[i, j] /= C[j, j] + else: + C[j, j] = self[j, j] + summ = 0 + for k in Crowstruc[j]: + if k < j: + summ += C[j, k]**2 + else: + break + C[j, j] -= summ + C[j, j] = sqrt(C[j, j]) + + return C + + def _LDL_sparse(self): + """Algorithm for numeric LDL factization, exploiting sparse structure. + """ + Lrowstruc = self.row_structure_symbolic_cholesky() + L = self.eye(self.rows) + D = self.zeros(self.rows, self.cols) + + for i in range(len(Lrowstruc)): + for j in Lrowstruc[i]: + if i != j: + L[i, j] = self[i, j] + summ = 0 + for p1 in Lrowstruc[i]: + if p1 < j: + for p2 in Lrowstruc[j]: + if p2 < j: + if p1 == p2: + summ += L[i, p1]*L[j, p1]*D[p1, p1] + else: + break + else: + break + L[i, j] -= summ + L[i, j] /= D[j, j] + elif i == j: + D[i, i] = self[i, i] + summ = 0 + for k in Lrowstruc[i]: + if k < i: + summ += L[i, k]**2*D[k, k] + else: + break + D[i, i] -= summ + + return L, D + + def _lower_triangular_solve(self, rhs): + """Fast algorithm for solving a lower-triangular system, + exploiting the sparsity of the given matrix. + """ + rows = [[] for i in range(self.rows)] + for i, j, v in self.row_list(): + if i > j: + rows[i].append((j, v)) + X = rhs.copy() + for i in range(self.rows): + for j, v in rows[i]: + X[i, 0] -= v*X[j, 0] + X[i, 0] /= self[i, i] + return self._new(X) + + def _upper_triangular_solve(self, rhs): + """Fast algorithm for solving an upper-triangular system, + exploiting the sparsity of the given matrix. + """ + rows = [[] for i in range(self.rows)] + for i, j, v in self.row_list(): + if i < j: + rows[i].append((j, v)) + X = rhs.copy() + for i in range(self.rows - 1, -1, -1): + rows[i].reverse() + for j, v in rows[i]: + X[i, 0] -= v*X[j, 0] + X[i, 0] /= self[i, i] + return self._new(X) + + def _diagonal_solve(self, rhs): + "Diagonal solve." + return self._new(self.rows, 1, lambda i, j: rhs[i, 0] / self[i, i]) + + def _cholesky_solve(self, rhs): + # for speed reasons, this is not uncommented, but if you are + # having difficulties, try uncommenting to make sure that the + # input matrix is symmetric + + #assert self.is_symmetric() + L = self._cholesky_sparse() + Y = L._lower_triangular_solve(rhs) + rv = L.T._upper_triangular_solve(Y) + return rv + + def _LDL_solve(self, rhs): + # for speed reasons, this is not uncommented, but if you are + # having difficulties, try uncommenting to make sure that the + # input matrix is symmetric + + #assert self.is_symmetric() + L, D = self._LDL_sparse() + Z = L._lower_triangular_solve(rhs) + Y = D._diagonal_solve(Z) + return L.T._upper_triangular_solve(Y) + + def cholesky(self): + """ + Returns the Cholesky decomposition L of a matrix A + such that L * L.T = A + + A must be a square, symmetric, positive-definite + and non-singular matrix + + Examples + ======== + + >>> from sympy.matrices import SparseMatrix + >>> A = SparseMatrix(((25,15,-5),(15,18,0),(-5,0,11))) + >>> A.cholesky() + Matrix([ + [ 5, 0, 0], + [ 3, 3, 0], + [-1, 1, 3]]) + >>> A.cholesky() * A.cholesky().T == A + True + """ + + from sympy.core.numbers import nan, oo + if not self.is_symmetric(): + raise ValueError('Cholesky decomposition applies only to ' + 'symmetric matrices.') + M = self.as_mutable()._cholesky_sparse() + if M.has(nan) or M.has(oo): + raise ValueError('Cholesky decomposition applies only to ' + 'positive-definite matrices') + return self._new(M) + + def LDLdecomposition(self): + """ + Returns the LDL Decomposition (matrices ``L`` and ``D``) of matrix + ``A``, such that ``L * D * L.T == A``. ``A`` must be a square, + symmetric, positive-definite and non-singular. + + This method eliminates the use of square root and ensures that all + the diagonal entries of L are 1. + + Examples + ======== + + >>> from sympy.matrices import SparseMatrix + >>> A = SparseMatrix(((25, 15, -5), (15, 18, 0), (-5, 0, 11))) + >>> L, D = A.LDLdecomposition() + >>> L + Matrix([ + [ 1, 0, 0], + [ 3/5, 1, 0], + [-1/5, 1/3, 1]]) + >>> D + Matrix([ + [25, 0, 0], + [ 0, 9, 0], + [ 0, 0, 9]]) + >>> L * D * L.T == A + True + + """ + from sympy.core.numbers import nan, oo + if not self.is_symmetric(): + raise ValueError('LDL decomposition applies only to ' + 'symmetric matrices.') + L, D = self.as_mutable()._LDL_sparse() + if L.has(nan) or L.has(oo) or D.has(nan) or D.has(oo): + raise ValueError('LDL decomposition applies only to ' + 'positive-definite matrices') + + return self._new(L), self._new(D) + + def solve_least_squares(self, rhs, method='LDL'): + """Return the least-square fit to the data. + + By default the cholesky_solve routine is used (method='CH'); other + methods of matrix inversion can be used. To find out which are + available, see the docstring of the .inv() method. + + Examples + ======== + + >>> from sympy.matrices import SparseMatrix, Matrix, ones + >>> A = Matrix([1, 2, 3]) + >>> B = Matrix([2, 3, 4]) + >>> S = SparseMatrix(A.row_join(B)) + >>> S + Matrix([ + [1, 2], + [2, 3], + [3, 4]]) + + If each line of S represent coefficients of Ax + By + and x and y are [2, 3] then S*xy is: + + >>> r = S*Matrix([2, 3]); r + Matrix([ + [ 8], + [13], + [18]]) + + But let's add 1 to the middle value and then solve for the + least-squares value of xy: + + >>> xy = S.solve_least_squares(Matrix([8, 14, 18])); xy + Matrix([ + [ 5/3], + [10/3]]) + + The error is given by S*xy - r: + + >>> S*xy - r + Matrix([ + [1/3], + [1/3], + [1/3]]) + >>> _.norm().n(2) + 0.58 + + If a different xy is used, the norm will be higher: + + >>> xy += ones(2, 1)/10 + >>> (S*xy - r).norm().n(2) + 1.5 + + """ + t = self.T + return (t*self).inv(method=method)*t*rhs + + def solve(self, rhs, method='LDL'): + """Return solution to self*soln = rhs using given inversion method. + + For a list of possible inversion methods, see the .inv() docstring. + """ + if not self.is_square: + if self.rows < self.cols: + raise ValueError('Under-determined system.') + elif self.rows > self.cols: + raise ValueError('For over-determined system, M, having ' + 'more rows than columns, try M.solve_least_squares(rhs).') + else: + return self.inv(method=method)*rhs + + def _eval_inverse(self, **kwargs): + """Return the matrix inverse using Cholesky or LDL (default) + decomposition as selected with the ``method`` keyword: 'CH' or 'LDL', + respectively. + + Examples + ======== + + >>> from sympy import SparseMatrix, Matrix + >>> A = SparseMatrix([ + ... [ 2, -1, 0], + ... [-1, 2, -1], + ... [ 0, 0, 2]]) + >>> A.inv('CH') + Matrix([ + [2/3, 1/3, 1/6], + [1/3, 2/3, 1/3], + [ 0, 0, 1/2]]) + >>> A.inv(method='LDL') # use of 'method=' is optional + Matrix([ + [2/3, 1/3, 1/6], + [1/3, 2/3, 1/3], + [ 0, 0, 1/2]]) + >>> A * _ + Matrix([ + [1, 0, 0], + [0, 1, 0], + [0, 0, 1]]) + + """ + sym = self.is_symmetric() + M = self.as_mutable() + I = M.eye(M.rows) + if not sym: + t = M.T + r1 = M[0, :] + M = t*M + I = t*I + method = kwargs.get('method', 'LDL') + if method in "LDL": + solve = M._LDL_solve + elif method == "CH": + solve = M._cholesky_solve + else: + raise NotImplementedError( + 'Method may be "CH" or "LDL", not %s.' % method) + rv = M.hstack(*[solve(I[:, i]) for i in range(I.cols)]) + if not sym: + scale = (r1*rv[:, 0])[0, 0] + rv /= scale + return self._new(rv) + + def __eq__(self, other): + try: + if self.shape != other.shape: + return False + if isinstance(other, SparseMatrix): + return self._smat == other._smat + elif isinstance(other, MatrixBase): + return self._smat == MutableSparseMatrix(other)._smat + except AttributeError: + return False + + def __ne__(self, other): + return not self == other + + def as_mutable(self): + """Returns a mutable version of this matrix. + + Examples + ======== + + >>> from sympy import ImmutableMatrix + >>> X = ImmutableMatrix([[1, 2], [3, 4]]) + >>> Y = X.as_mutable() + >>> Y[1, 1] = 5 # Can set values in Y + >>> Y + Matrix([ + [1, 2], + [3, 5]]) + """ + return MutableSparseMatrix(self) + + def as_immutable(self): + """Returns an Immutable version of this Matrix.""" + from .immutable import ImmutableSparseMatrix + return ImmutableSparseMatrix(self) + + def nnz(self): + """Returns the number of non-zero elements in Matrix.""" + return len(self._smat) + + @classmethod + def zeros(cls, r, c=None): + """Return an r x c matrix of zeros, square if c is omitted.""" + if is_sequence(r): + SymPyDeprecationWarning( + feature="The syntax zeros([%i, %i])" % tuple(r), + useinstead="zeros(%i, %i)." % tuple(r), + issue=3381, deprecated_since_version="0.7.2", + ).warn() + r, c = r + else: + c = r if c is None else c + r = as_int(r) + c = as_int(c) + return cls(r, c, {}) + + @classmethod + def eye(cls, n): + """Return an n x n identity matrix.""" + n = as_int(n) + return cls(n, n, dict([((i, i), S.One) for i in range(n)])) + + def __hash__(self): + return hash((type(self).__name__,) + (self.shape, tuple(self._mat))) + + +class MutableSparseMatrix(SparseMatrix, MatrixBase): + @classmethod + def _new(cls, *args, **kwargs): + return cls(*args) + + def as_mutable(self): + return self.copy() + + def __setitem__(self, key, value): + """Assign value to position designated by key. + + Examples + ======== + + >>> from sympy.matrices import SparseMatrix, ones + >>> M = SparseMatrix(2, 2, {}) + >>> M[1] = 1; M + Matrix([ + [0, 1], + [0, 0]]) + >>> M[1, 1] = 2; M + Matrix([ + [0, 1], + [0, 2]]) + >>> M = SparseMatrix(2, 2, {}) + >>> M[:, 1] = [1, 1]; M + Matrix([ + [0, 1], + [0, 1]]) + >>> M = SparseMatrix(2, 2, {}) + >>> M[1, :] = [[1, 1]]; M + Matrix([ + [0, 0], + [1, 1]]) + + + To replace row r you assign to position r*m where m + is the number of columns: + + >>> M = SparseMatrix(4, 4, {}) + >>> m = M.cols + >>> M[3*m] = ones(1, m)*2; M + Matrix([ + [0, 0, 0, 0], + [0, 0, 0, 0], + [0, 0, 0, 0], + [2, 2, 2, 2]]) + + And to replace column c you can assign to position c: + + >>> M[2] = ones(m, 1)*4; M + Matrix([ + [0, 0, 4, 0], + [0, 0, 4, 0], + [0, 0, 4, 0], + [2, 2, 4, 2]]) + """ + rv = self._setitem(key, value) + if rv is not None: + i, j, value = rv + if value: + self._smat[(i, j)] = value + elif (i, j) in self._smat: + del self._smat[(i, j)] + + def __hash__(self): + return hash((type(self).__name__,) + (self.shape, tuple(self._mat))) + + def row_del(self, k): + """Delete the given row of the matrix. + + Examples + ======== + + >>> from sympy.matrices import SparseMatrix + >>> M = SparseMatrix([[0, 0], [0, 1]]) + >>> M + Matrix([ + [0, 0], + [0, 1]]) + >>> M.row_del(0) + >>> M + Matrix([[0, 1]]) + + See Also + ======== + + col_del + """ + newD = {} + k = a2idx(k, self.rows) + for (i, j) in self._smat: + if i == k: + pass + elif i > k: + newD[i - 1, j] = self._smat[i, j] + else: + newD[i, j] = self._smat[i, j] + self._smat = newD + self.rows -= 1 + + def col_del(self, k): + """Delete the given column of the matrix. + + Examples + ======== + + >>> from sympy.matrices import SparseMatrix + >>> M = SparseMatrix([[0, 0], [0, 1]]) + >>> M + Matrix([ + [0, 0], + [0, 1]]) + >>> M.col_del(0) + >>> M + Matrix([ + [0], + [1]]) + + See Also + ======== + + row_del + """ + newD = {} + k = a2idx(k, self.cols) + for (i, j) in self._smat: + if j == k: + pass + elif j > k: + newD[i, j - 1] = self._smat[i, j] + else: + newD[i, j] = self._smat[i, j] + self._smat = newD + self.cols -= 1 + + def row_swap(self, i, j): + """Swap, in place, columns i and j. + + Examples + ======== + + >>> from sympy.matrices import SparseMatrix + >>> S = SparseMatrix.eye(3); S[2, 1] = 2 + >>> S.row_swap(1, 0); S + Matrix([ + [0, 1, 0], + [1, 0, 0], + [0, 2, 1]]) + """ + if i > j: + i, j = j, i + rows = self.row_list() + temp = [] + for ii, jj, v in rows: + if ii == i: + self._smat.pop((ii, jj)) + temp.append((jj, v)) + elif ii == j: + self._smat.pop((ii, jj)) + self._smat[i, jj] = v + elif ii > j: + break + for k, v in temp: + self._smat[j, k] = v + + def col_swap(self, i, j): + """Swap, in place, columns i and j. + + Examples + ======== + + >>> from sympy.matrices import SparseMatrix + >>> S = SparseMatrix.eye(3); S[2, 1] = 2 + >>> S.col_swap(1, 0); S + Matrix([ + [0, 1, 0], + [1, 0, 0], + [2, 0, 1]]) + """ + if i > j: + i, j = j, i + rows = self.col_list() + temp = [] + for ii, jj, v in rows: + if jj == i: + self._smat.pop((ii, jj)) + temp.append((ii, v)) + elif jj == j: + self._smat.pop((ii, jj)) + self._smat[ii, i] = v + elif jj > j: + break + for k, v in temp: + self._smat[k, j] = v + + def row_join(self, other): + """Returns B appended after A (column-wise augmenting):: + + [A B] + + Examples + ======== + + >>> from sympy import SparseMatrix, Matrix + >>> A = SparseMatrix(((1, 0, 1), (0, 1, 0), (1, 1, 0))) + >>> A + Matrix([ + [1, 0, 1], + [0, 1, 0], + [1, 1, 0]]) + >>> B = SparseMatrix(((1, 0, 0), (0, 1, 0), (0, 0, 1))) + >>> B + Matrix([ + [1, 0, 0], + [0, 1, 0], + [0, 0, 1]]) + >>> C = A.row_join(B); C + Matrix([ + [1, 0, 1, 1, 0, 0], + [0, 1, 0, 0, 1, 0], + [1, 1, 0, 0, 0, 1]]) + >>> C == A.row_join(Matrix(B)) + True + + Joining at row ends is the same as appending columns at the end + of the matrix: + + >>> C == A.col_insert(A.cols, B) + True + """ + A, B = self, other + if not A.rows == B.rows: + raise ShapeError() + A = A.copy() + if not isinstance(B, SparseMatrix): + k = 0 + b = B._mat + for i in range(B.rows): + for j in range(B.cols): + v = b[k] + if v: + A._smat[(i, j + A.cols)] = v + k += 1 + else: + for (i, j), v in B._smat.items(): + A._smat[(i, j + A.cols)] = v + A.cols += B.cols + return A + + def col_join(self, other): + """Returns B augmented beneath A (row-wise joining):: + + [A] + [B] + + Examples + ======== + + >>> from sympy import SparseMatrix, Matrix, ones + >>> A = SparseMatrix(ones(3)) + >>> A + Matrix([ + [1, 1, 1], + [1, 1, 1], + [1, 1, 1]]) + >>> B = SparseMatrix.eye(3) + >>> B + Matrix([ + [1, 0, 0], + [0, 1, 0], + [0, 0, 1]]) + >>> C = A.col_join(B); C + Matrix([ + [1, 1, 1], + [1, 1, 1], + [1, 1, 1], + [1, 0, 0], + [0, 1, 0], + [0, 0, 1]]) + >>> C == A.col_join(Matrix(B)) + True + + Joining along columns is the same as appending rows at the end + of the matrix: + + >>> C == A.row_insert(A.rows, Matrix(B)) + True + """ + A, B = self, other + if not A.cols == B.cols: + raise ShapeError() + A = A.copy() + if not isinstance(B, SparseMatrix): + k = 0 + b = B._mat + for i in range(B.rows): + for j in range(B.cols): + v = b[k] + if v: + A._smat[(i + A.rows, j)] = v + k += 1 + else: + for (i, j), v in B._smat.items(): + A._smat[i + A.rows, j] = v + A.rows += B.rows + return A + + def copyin_list(self, key, value): + if not is_sequence(value): + raise TypeError("`value` must be of type list or tuple.") + self.copyin_matrix(key, Matrix(value)) + + def copyin_matrix(self, key, value): + # include this here because it's not part of BaseMatrix + rlo, rhi, clo, chi = self.key2bounds(key) + shape = value.shape + dr, dc = rhi - rlo, chi - clo + if shape != (dr, dc): + raise ShapeError( + "The Matrix `value` doesn't have the same dimensions " + "as the in sub-Matrix given by `key`.") + if not isinstance(value, SparseMatrix): + for i in range(value.rows): + for j in range(value.cols): + self[i + rlo, j + clo] = value[i, j] + else: + if (rhi - rlo)*(chi - clo) < len(self): + for i in range(rlo, rhi): + for j in range(clo, chi): + self._smat.pop((i, j), None) + else: + for i, j, v in self.row_list(): + if rlo <= i < rhi and clo <= j < chi: + self._smat.pop((i, j), None) + for k, v in value._smat.items(): + i, j = k + self[i + rlo, j + clo] = value[i, j] + + def zip_row_op(self, i, k, f): + """In-place operation on row ``i`` using two-arg functor whose args are + interpreted as ``(self[i, j], self[k, j])``. + + Examples + ======== + + >>> from sympy.matrices import SparseMatrix + >>> M = SparseMatrix.eye(3)*2 + >>> M[0, 1] = -1 + >>> M.zip_row_op(1, 0, lambda v, u: v + 2*u); M + Matrix([ + [2, -1, 0], + [4, 0, 0], + [0, 0, 2]]) + + See Also + ======== + row + row_op + col_op + + """ + self.row_op(i, lambda v, j: f(v, self[k, j])) + + def row_op(self, i, f): + """In-place operation on row ``i`` using two-arg functor whose args are + interpreted as ``(self[i, j], j)``. + + Examples + ======== + + >>> from sympy.matrices import SparseMatrix + >>> M = SparseMatrix.eye(3)*2 + >>> M[0, 1] = -1 + >>> M.row_op(1, lambda v, j: v + 2*M[0, j]); M + Matrix([ + [2, -1, 0], + [4, 0, 0], + [0, 0, 2]]) + + See Also + ======== + row + zip_row_op + col_op + + """ + for j in range(self.cols): + v = self._smat.get((i, j), S.Zero) + fv = f(v, j) + if fv: + self._smat[(i, j)] = fv + elif v: + self._smat.pop((i, j)) + + def col_op(self, j, f): + """In-place operation on col j using two-arg functor whose args are + interpreted as (self[i, j], i) for i in range(self.rows). + + Examples + ======== + + >>> from sympy.matrices import SparseMatrix + >>> M = SparseMatrix.eye(3)*2 + >>> M[1, 0] = -1 + >>> M.col_op(1, lambda v, i: v + 2*M[i, 0]); M + Matrix([ + [ 2, 4, 0], + [-1, 0, 0], + [ 0, 0, 2]]) + """ + for i in range(self.rows): + v = self._smat.get((i, j), S.Zero) + fv = f(v, i) + if fv: + self._smat[(i, j)] = fv + elif v: + self._smat.pop((i, j)) + + def fill(self, value): + """Fill self with the given value. + + Notes + ===== + + Unless many values are going to be deleted (i.e. set to zero) + this will create a matrix that is slower than a dense matrix in + operations. + + Examples + ======== + + >>> from sympy.matrices import SparseMatrix + >>> M = SparseMatrix.zeros(3); M + Matrix([ + [0, 0, 0], + [0, 0, 0], + [0, 0, 0]]) + >>> M.fill(1); M + Matrix([ + [1, 1, 1], + [1, 1, 1], + [1, 1, 1]]) + """ + if not value: + self._smat = {} + else: + v = self._sympify(value) + self._smat = dict([((i, j), v) + for i in range(self.rows) for j in range(self.cols)]) diff -Nru python3-sympy-0.7.2/sympy/matrices/sparsetools.py python3-sympy-0.7.3/sympy/matrices/sparsetools.py --- python3-sympy-0.7.2/sympy/matrices/sparsetools.py 1970-01-01 00:00:00.000000000 +0000 +++ python3-sympy-0.7.3/sympy/matrices/sparsetools.py 2013-07-13 17:53:32.000000000 +0000 @@ -0,0 +1,34 @@ +from sympy import SparseMatrix + + +def _doktocsr(dok): + """Converts a sparse matrix to Compressed Sparse Row (CSR) format. + + Parameters + ========== + + A : contains non-zero elements sorted by key (row, column) + JA : JA[i] is the column corresponding to A[i] + IA : IA[i] contains the index in A for the first non-zero element + of row[i]. Thus IA[i+1] - IA[i] gives number of non-zero + elements row[i]. The length of IA is always 1 more than the + number of rows in the matrix. + """ + row, JA, A = [list(i) for i in zip(*dok.row_list())] + IA = [0]*((row[0] if row else 0) + 1) + for i, r in enumerate(row): + IA.extend([i]*(r - row[i - 1])) # if i = 0 nothing is extended + IA.extend([len(A)]*(dok.rows - len(IA) + 1)) + shape = [dok.rows, dok.cols] + return [A, JA, IA, shape] + + +def _csrtodok(csr): + """Converts a CSR representation to DOK representation""" + smat = {} + A, JA, IA, shape = csr + for i in range(len(IA) - 1): + indices = slice(IA[i], IA[i + 1]) + for l, m in zip(A[indices], JA[indices]): + smat[i, m] = l + return SparseMatrix(*(shape + [smat])) diff -Nru python3-sympy-0.7.2/sympy/matrices/tests/test_immutable.py python3-sympy-0.7.3/sympy/matrices/tests/test_immutable.py --- python3-sympy-0.7.2/sympy/matrices/tests/test_immutable.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/matrices/tests/test_immutable.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,52 +1,59 @@ + from sympy import ImmutableMatrix, Matrix, eye, zeros from sympy.abc import x, y -from sympy.utilities.pytest import raises, XFAIL +from sympy.utilities.pytest import raises -IM = ImmutableMatrix([[1,2,3], [4,5,6], [7,8,9]]) +IM = ImmutableMatrix([[1, 2, 3], [4, 5, 6], [7, 8, 9]]) ieye = ImmutableMatrix(eye(3)) + def test_immutable_creation(): - assert IM.shape == (3,3) - assert IM[1,2] == 6 - assert IM[2,2] == 9 + assert IM.shape == (3, 3) + assert IM[1, 2] == 6 + assert IM[2, 2] == 9 + def test_immutability(): with raises(TypeError): - IM[2,2] = 5 + IM[2, 2] = 5 + def test_slicing(): - IM[1,:] == ImmutableMatrix([[4,5,6]]) - IM[:2, :2] == ImmutableMatrix([[1,2],[4,5]]) + assert IM[1, :] == ImmutableMatrix([[4, 5, 6]]) + assert IM[:2, :2] == ImmutableMatrix([[1, 2], [4, 5]]) + def test_subs(): - A = ImmutableMatrix([[1,2],[3,4]]) - B = ImmutableMatrix([[1,2],[x,4]]) - C = ImmutableMatrix([[-x,x*y],[-(x+y),y**2]]) + A = ImmutableMatrix([[1, 2], [3, 4]]) + B = ImmutableMatrix([[1, 2], [x, 4]]) + C = ImmutableMatrix([[-x, x*y], [-(x + y), y**2]]) assert B.subs(x, 3) == A assert (x*B).subs(x, 3) == 3*A assert (x*eye(2) + B).subs(x, 3) == 3*eye(2) + A - assert C.subs([[x,-1],[y,-2]]) == A - assert C.subs([(x,-1),(y,-2)]) == A - assert C.subs({x:-1,y:-2}) == A - assert C.subs({x:y-1, y:x-1}, simultaneous=True) == \ - ImmutableMatrix([[1-y, (x-1)*(y-1)], [2-x-y, (x-1)**2]]) + assert C.subs([[x, -1], [y, -2]]) == A + assert C.subs([(x, -1), (y, -2)]) == A + assert C.subs({x: -1, y: -2}) == A + assert C.subs({x: y - 1, y: x - 1}, simultaneous=True) == \ + ImmutableMatrix([[1 - y, (x - 1)*(y - 1)], [2 - x - y, (x - 1)**2]]) + def test_as_immutable(): - X = Matrix([[1,2], [3,4]]) - assert X.as_immutable() == ImmutableMatrix([[1,2],[3,4]]) + X = Matrix([[1, 2], [3, 4]]) + assert X.as_immutable() == ImmutableMatrix([[1, 2], [3, 4]]) + def test_function_return_types(): # Lets ensure that decompositions of immutable matrices remain immutable # I.e. do MatrixBase methods return the correct class? - X = ImmutableMatrix([[1,2],[3,4]]) - Y = ImmutableMatrix([[1],[0]]) + X = ImmutableMatrix([[1, 2], [3, 4]]) + Y = ImmutableMatrix([[1], [0]]) q, r = X.QRdecomposition() assert (type(q), type(r)) == (ImmutableMatrix, ImmutableMatrix) assert type(X.LUsolve(Y)) == ImmutableMatrix assert type(X.QRsolve(Y)) == ImmutableMatrix - X = ImmutableMatrix([[1,2],[2,1]]) + X = ImmutableMatrix([[1, 2], [2, 1]]) assert X.T == X assert X.is_symmetric assert type(X.cholesky()) == ImmutableMatrix @@ -59,22 +66,24 @@ assert type(X.eigenvects()[0][2][0]) == ImmutableMatrix - assert type(zeros(3,3).as_immutable().nullspace()[0]) == ImmutableMatrix + assert type(zeros(3, 3).as_immutable().nullspace()[0]) == ImmutableMatrix - X = ImmutableMatrix([[1,0], [2,1]]) + X = ImmutableMatrix([[1, 0], [2, 1]]) assert type(X.lower_triangular_solve(Y)) == ImmutableMatrix assert type(X.T.upper_triangular_solve(Y)) == ImmutableMatrix - assert type(X.minorMatrix(0,0)) == ImmutableMatrix + assert type(X.minorMatrix(0, 0)) == ImmutableMatrix # Issue 3180 # http://code.google.com/p/sympy/issues/detail?id=3180 # Test that Immutable _op_ Immutable => Immutable and not MatExpr + + def test_immutable_evaluation(): X = ImmutableMatrix(eye(3)) - A = ImmutableMatrix(3,3, list(range(9))) + A = ImmutableMatrix(3, 3, list(range(9))) assert isinstance(X + A, ImmutableMatrix) assert isinstance(X * A, ImmutableMatrix) assert isinstance(X * 2, ImmutableMatrix) assert isinstance(2 * X, ImmutableMatrix) - assert isinstance(A**2, ImmutableMatrix) + assert isinstance(A**2, ImmutableMatrix) diff -Nru python3-sympy-0.7.2/sympy/matrices/tests/test_interactions.py python3-sympy-0.7.3/sympy/matrices/tests/test_interactions.py --- python3-sympy-0.7.2/sympy/matrices/tests/test_interactions.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/matrices/tests/test_interactions.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,6 +1,6 @@ """ We have a few different kind of Matrices -MutableMatrix, ImmutableMatrix, MatrixExpr +Matrix, ImmutableMatrix, MatrixExpr Here we test the extent to which they cooperate """ @@ -8,52 +8,59 @@ from sympy import symbols from sympy.matrices import (Matrix, MatrixSymbol, eye, Identity, ImmutableMatrix) -from sympy.matrices.matrices import MutableMatrix, classof -from sympy.utilities.pytest import raises, XFAIL - - +from sympy.matrices.expressions import MatrixExpr, MatAdd +from sympy.matrices.matrices import classof +from sympy.utilities.pytest import raises SM = MatrixSymbol('X', 3, 3) -MM = Matrix([[1,2,3], [4,5,6], [7,8,9]]) -IM = ImmutableMatrix([[1,2,3], [4,5,6], [7,8,9]]) +MM = Matrix([[1, 2, 3], [4, 5, 6], [7, 8, 9]]) +IM = ImmutableMatrix([[1, 2, 3], [4, 5, 6], [7, 8, 9]]) meye = eye(3) imeye = ImmutableMatrix(eye(3)) ideye = Identity(3) -a,b,c = symbols('a,b,c') +a, b, c = symbols('a,b,c') + def test_IM_MM(): - assert (MM+IM).__class__ is MutableMatrix - assert (IM+MM).__class__ is MutableMatrix - assert (2*IM + MM).__class__ is MutableMatrix + assert isinstance(MM + IM, ImmutableMatrix) + assert isinstance(IM + MM, ImmutableMatrix) + assert isinstance(2*IM + MM, ImmutableMatrix) assert MM.equals(IM) + def test_ME_MM(): - assert (Identity(3) + MM).__class__ is MutableMatrix - assert (SM + MM).__class__ is MutableMatrix - assert (MM + SM).__class__ is MutableMatrix - assert (Identity(3) + MM)[1,1] == 6 + assert isinstance(Identity(3) + MM, MatrixExpr) + assert isinstance(SM + MM, MatAdd) + assert isinstance(MM + SM, MatAdd) + assert (Identity(3) + MM)[1, 1] == 6 + def test_equality(): - a,b,c = Identity(3), eye(3), ImmutableMatrix(eye(3)) - for x in [a,b,c]: - for y in [a,b,c]: + a, b, c = Identity(3), eye(3), ImmutableMatrix(eye(3)) + for x in [a, b, c]: + for y in [a, b, c]: assert x.equals(y) + def test_matrix_symbol_MM(): - X = MatrixSymbol('X', 3,3) + X = MatrixSymbol('X', 3, 3) Y = eye(3) + X - assert Y[1,1] == 1 + X[1,1] + assert Y[1, 1] == 1 + X[1, 1] + def test_indexing_interactions(): - assert (a * IM)[1,1] == 5*a - assert (SM + IM)[1,1] == SM[1,1] + IM[1,1] - assert (SM * IM)[1,1] == SM[1,0]*IM[0,1] + SM[1,1]*IM[1,1] + SM[1,2]*IM[2,1] + assert (a * IM)[1, 1] == 5*a + assert (SM + IM)[1, 1] == SM[1, 1] + IM[1, 1] + assert (SM * IM)[1, 1] == SM[1, 0]*IM[0, 1] + SM[1, 1]*IM[1, 1] + \ + SM[1, 2]*IM[2, 1] + def test_classof(): - A = MutableMatrix(3,3,list(range(9))) - B = ImmutableMatrix(3,3,list(range(9))) - C = MatrixSymbol('C', 3,3) - assert classof(A,A) == MutableMatrix - assert classof(B,B) == ImmutableMatrix - assert classof(A,B) == MutableMatrix - raises(TypeError, lambda:classof(A,C)) + A = Matrix(3, 3, list(range(9))) + B = ImmutableMatrix(3, 3, list(range(9))) + C = MatrixSymbol('C', 3, 3) + assert classof(A, A) == Matrix + assert classof(B, B) == ImmutableMatrix + assert classof(A, B) == ImmutableMatrix + assert classof(B, A) == ImmutableMatrix + raises(TypeError, lambda: classof(A, C)) diff -Nru python3-sympy-0.7.2/sympy/matrices/tests/test_matrices.py python3-sympy-0.7.3/sympy/matrices/tests/test_matrices.py --- python3-sympy-0.7.2/sympy/matrices/tests/test_matrices.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/matrices/tests/test_matrices.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,91 +1,125 @@ -from sympy import (symbols, Matrix, SparseMatrix, eye, I, Symbol, Rational, - Float, wronskian, cos, sin, exp, hessian, sqrt, zeros, ones, randMatrix, - Poly, S, pi, E, oo, trigsimp, Integer, N, sympify, - Pow, simplify, Min, Max, Abs, PurePoly, count_ops, signsimp) + +from sympy import ( + Abs, E, Float, I, Integer, Max, Min, N, Poly, Pow, PurePoly, Rational, + S, Symbol, cos, exp, oo, pi, signsimp, simplify, sin, sqrt, symbols, + sympify, trigsimp) from sympy.matrices.matrices import (ShapeError, MatrixError, - matrix_multiply_elementwise, diag, GramSchmidt, casoratian, - SparseMatrix, SparseMatrix, NonSquareMatrixError, - matrix_multiply_elementwise, diag, NonSquareMatrixError, DeferredVector) -from sympy.matrices import ImmutableMatrix + NonSquareMatrixError, DeferredVector) +from sympy.matrices import ( + GramSchmidt, ImmutableMatrix, ImmutableSparseMatrix, Matrix, + SparseMatrix, casoratian, diag, eye, hessian, + matrix_multiply_elementwise, ones, randMatrix, rot_axis1, rot_axis2, + rot_axis3, wronskian, zeros) from sympy.utilities.iterables import flatten, capture from sympy.utilities.pytest import raises, XFAIL -from sympy.matrices import rot_axis1, rot_axis2, rot_axis3 + +from sympy.abc import x, y, z + +# don't re-order this list +classes = (Matrix, SparseMatrix, ImmutableMatrix, ImmutableSparseMatrix) + + +def test_args(): + for c, cls in enumerate(classes): + m = cls.zeros(3, 2) + # all should give back the same type of arguments, e.g. ints for shape + assert m.shape == (3, 2) and all(type(i) is int for i in m.shape) + assert m.rows == 3 and type(m.rows) is int + assert m.cols == 2 and type(m.cols) is int + if not c % 2: + assert type(m._mat) is list + else: + assert type(m._smat) is dict + def test_division(): - x, y, z = symbols('x y z') - v = Matrix(1,2,[x, y]) - assert v.__div__(z) == Matrix(1,2,[x/z, y/z]) - assert v.__truediv__(z) == Matrix(1,2,[x/z, y/z]) - assert v/z == Matrix(1,2,[x/z, y/z]) + v = Matrix(1, 2, [x, y]) + assert v.__div__(z) == Matrix(1, 2, [x/z, y/z]) + assert v.__truediv__(z) == Matrix(1, 2, [x/z, y/z]) + assert v/z == Matrix(1, 2, [x/z, y/z]) + def test_sum(): - x, y, z = symbols('x y z') - m = Matrix([[1,2,3],[x,y,x],[2*y,-50,z*x]]) - assert m+m == Matrix([[2,4,6],[2*x,2*y,2*x],[4*y,-100,2*z*x]]) + m = Matrix([[1, 2, 3], [x, y, x], [2*y, -50, z*x]]) + assert m + m == Matrix([[2, 4, 6], [2*x, 2*y, 2*x], [4*y, -100, 2*z*x]]) n = Matrix(1, 2, [1, 2]) - raises(ShapeError, lambda: m+n) + raises(ShapeError, lambda: m + n) + + +def test_addition(): + a = Matrix(( + (1, 2), + (3, 1), + )) + + b = Matrix(( + (1, 2), + (3, 0), + )) + + assert a + b == a.add(b) == Matrix([[2, 4], [6, 1]]) + def test_multiplication(): - a=Matrix(( + a = Matrix(( (1, 2), (3, 1), (0, 6), - )) + )) - b = Matrix (( + b = Matrix(( (1, 2), (3, 0), - )) + )) - c= a*b - assert c[0,0]==7 - assert c[0,1]==2 - assert c[1,0]==6 - assert c[1,1]==6 - assert c[2,0]==18 - assert c[2,1]==0 + c = a*b + assert c[0, 0] == 7 + assert c[0, 1] == 2 + assert c[1, 0] == 6 + assert c[1, 1] == 6 + assert c[2, 0] == 18 + assert c[2, 1] == 0 h = matrix_multiply_elementwise(a, c) assert h == a.multiply_elementwise(c) - assert h[0,0]==7 - assert h[0,1]==4 - assert h[1,0]==18 - assert h[1,1]==6 - assert h[2,0]==0 - assert h[2,1]==0 + assert h[0, 0] == 7 + assert h[0, 1] == 4 + assert h[1, 0] == 18 + assert h[1, 1] == 6 + assert h[2, 0] == 0 + assert h[2, 1] == 0 raises(ShapeError, lambda: matrix_multiply_elementwise(a, b)) - x = Symbol("x") - c = b * Symbol("x") - assert isinstance(c,Matrix) - assert c[0,0] == x - assert c[0,1] == 2*x - assert c[1,0] == 3*x - assert c[1,1] == 0 + assert isinstance(c, Matrix) + assert c[0, 0] == x + assert c[0, 1] == 2*x + assert c[1, 0] == 3*x + assert c[1, 1] == 0 c2 = x * b assert c == c2 c = 5 * b - assert isinstance(c,Matrix) - assert c[0,0] == 5 - assert c[0,1] == 2*5 - assert c[1,0] == 3*5 - assert c[1,1] == 0 + assert isinstance(c, Matrix) + assert c[0, 0] == 5 + assert c[0, 1] == 2*5 + assert c[1, 0] == 3*5 + assert c[1, 1] == 0 + def test_power(): raises(NonSquareMatrixError, lambda: Matrix((1, 2))**2) R = Rational - A = Matrix([[2,3],[4,5]]) + A = Matrix([[2, 3], [4, 5]]) assert (A**-3)[:] == [R(-269)/8, R(153)/8, R(51)/2, R(-29)/2] assert (A**5)[:] == [6140, 8097, 10796, 14237] - A = Matrix([[2, 1, 3],[4,2, 4], [6,12, 1]]) + A = Matrix([[2, 1, 3], [4, 2, 4], [6, 12, 1]]) assert (A**3)[:] == [290, 262, 251, 448, 440, 368, 702, 954, 433] assert A**0 == eye(3) assert A**1 == A - assert (Matrix([[2]]) ** 100)[0,0] == 2**100 + assert (Matrix([[2]]) ** 100)[0, 0] == 2**100 assert eye(2)**10000000 == eye(2) assert Matrix([[1, 2], [3, 4]])**Integer(2) == Matrix([[7, 10], [15, 22]]) @@ -94,41 +128,41 @@ A = Matrix([[0, 4], [-1, 5]]) assert (A**(S(1)/2))**2 == A + def test_creation(): raises(ValueError, lambda: Matrix(5, 5, list(range(20)))) raises(IndexError, lambda: Matrix((1, 2))[2]) with raises(IndexError): - Matrix((1, 2))[1:2] = 5 + Matrix((1, 2))[1:2] = 5 with raises(IndexError): - Matrix((1, 2))[3] = 5 + Matrix((1, 2))[3] = 5 - x = Symbol("x") a = Matrix([[x, 0], [0, 0]]) m = a assert m.cols == m.rows assert m.cols == 2 - assert m[:] == [x,0,0,0] + assert m[:] == [x, 0, 0, 0] - b = Matrix(2,2, [x, 0, 0, 0]) + b = Matrix(2, 2, [x, 0, 0, 0]) m = b assert m.cols == m.rows assert m.cols == 2 - assert m[:] == [x,0,0,0] + assert m[:] == [x, 0, 0, 0] assert a == b assert Matrix(b) == b c = Matrix(( - Matrix(( + Matrix(( (1, 2, 3), (4, 5, 6) - )), - (7, 8, 9) + )), + (7, 8, 9) )) assert c.cols == 3 assert c.rows == 3 - assert c[:] == [1,2,3,4,5,6,7,8,9] + assert c[:] == [1, 2, 3, 4, 5, 6, 7, 8, 9] assert Matrix(eye(2)) == eye(2) assert ImmutableMatrix(ImmutableMatrix(eye(2))) == ImmutableMatrix(eye(2)) @@ -137,22 +171,27 @@ assert c is not Matrix(c) + def test_tolist(): - x, y, z = symbols('x y z') - lst = [[S.One,S.Half,x*y,S.Zero],[x,y,z,x**2],[y,-S.One,z*x,3]] + lst = [[S.One, S.Half, x*y, S.Zero], [x, y, z, x**2], [y, -S.One, z*x, 3]] m = Matrix(lst) assert m.tolist() == lst + +def test_as_mutable(): + assert zeros(0, 3).as_mutable() == zeros(0, 3) + assert zeros(0, 3).as_immutable() == ImmutableMatrix(zeros(0, 3)) + + def test_determinant(): - x, y, z = Symbol('x'), Symbol('y'), Symbol('z') for M in [Matrix(), Matrix([[1]])]: assert ( - M.det() == - M.det_bareis() == - M.berkowitz_det() == - M.det_LU_decomposition() == - 1) + M.det() == + M.det_bareis() == + M.berkowitz_det() == + M.det_LU_decomposition() == + 1) M = Matrix(( (-3, 2), ( 8, -5) )) @@ -160,13 +199,11 @@ assert M.det(method="bareis") == -1 assert M.det(method="berkowitz") == -1 - M = Matrix(( (x, 1), (y, 2*y) )) - assert M.det(method="bareis") == 2*x*y-y - assert M.det(method="berkowitz") == 2*x*y-y - + assert M.det(method="bareis") == 2*x*y - y + assert M.det(method="berkowitz") == 2*x*y - y M = Matrix(( (1, 1, 1), (1, 2, 3), @@ -175,7 +212,6 @@ assert M.det(method="bareis") == 1 assert M.det(method="berkowitz") == 1 - M = Matrix(( ( 3, -2, 0, 5), (-2, 1, -2, 2), ( 0, -2, 5, 0), @@ -184,7 +220,6 @@ assert M.det(method="bareis") == -289 assert M.det(method="berkowitz") == -289 - M = Matrix(( ( 1, 2, 3, 4), ( 5, 6, 7, 8), ( 9, 10, 11, 12), @@ -193,8 +228,6 @@ assert M.det(method="bareis") == 0 assert M.det(method="berkowitz") == 0 - - M = Matrix(( (3, 2, 0, 0, 0), (0, 3, 2, 0, 0), (0, 0, 3, 2, 0), @@ -204,7 +237,6 @@ assert M.det(method="bareis") == 275 assert M.det(method="berkowitz") == 275 - M = Matrix(( (1, 0, 1, 2, 12), (2, 0, 1, 1, 4), (2, 1, 1, -1, 3), @@ -214,7 +246,6 @@ assert M.det(method="bareis") == -55 assert M.det(method="berkowitz") == -55 - M = Matrix(( (-5, 2, 3, 4, 5), ( 1, -4, 3, 4, 5), ( 1, 2, -3, 4, 5), @@ -224,7 +255,6 @@ assert M.det(method="bareis") == 11664 assert M.det(method="berkowitz") == 11664 - M = Matrix(( ( 2, 7, -1, 3, 2), ( 0, 0, 1, 0, 1), (-2, 0, 7, 0, 2), @@ -234,17 +264,15 @@ assert M.det(method="bareis") == 123 assert M.det(method="berkowitz") == 123 - - M = Matrix(( (x,y,z), - (1,0,0), - (y,z,x) )) + M = Matrix(( (x, y, z), + (1, 0, 0), + (y, z, x) )) assert M.det(method="bareis") == z**2 - x*y assert M.det(method="berkowitz") == z**2 - x*y - def test_det_LU_decomposition(): - x, y, z = symbols('x y z') +def test_det_LU_decomposition(): for M in [Matrix(), Matrix([[1]])]: assert M.det(method="det_LU") == 1 @@ -257,7 +285,7 @@ M = Matrix(( (x, 1), (y, 2*y) )) - assert M.det(method="det_LU") == 2*x*y-y + assert M.det(method="det_LU") == 2*x*y - y M = Matrix(( (1, 1, 1), (1, 2, 3), @@ -304,9 +332,9 @@ assert M.det(method="det_LU") == 123 - M = Matrix(( (x,y,z), - (1,0,0), - (y,z,x) )) + M = Matrix(( (x, y, z), + (1, 0, 0), + (y, z, x) )) assert M.det(method="det_LU") == z**2 - x*y @@ -316,122 +344,133 @@ assert B.berkowitz_minors() == (1, -3) + def test_submatrix(): m0 = eye(4) assert m0[:3, :3] == eye(3) assert m0[2:4, 0:2] == zeros(2) - m1 = Matrix(3,3, lambda i,j: i+j) - assert m1[0,:] == Matrix(1,3,(0,1,2)) - assert m1[1:3, 1] == Matrix(2,1,(2,3)) - - m2 = Matrix([[0,1,2,3],[4,5,6,7],[8,9,10,11],[12,13,14,15]]) - assert m2[:,-1] == Matrix(4,1,[3,7,11,15]) - assert m2[-2:,:] == Matrix([[8,9,10,11],[12,13,14,15]]) + m1 = Matrix(3, 3, lambda i, j: i + j) + assert m1[0, :] == Matrix(1, 3, (0, 1, 2)) + assert m1[1:3, 1] == Matrix(2, 1, (2, 3)) + + m2 = Matrix([[0, 1, 2, 3], [4, 5, 6, 7], [8, 9, 10, 11], [12, 13, 14, 15]]) + assert m2[:, -1] == Matrix(4, 1, [3, 7, 11, 15]) + assert m2[-2:, :] == Matrix([[8, 9, 10, 11], [12, 13, 14, 15]]) + def test_submatrix_assignment(): m = zeros(4) m[2:4, 2:4] = eye(2) - assert m == Matrix(((0,0,0,0), - (0,0,0,0), - (0,0,1,0), - (0,0,0,1))) + assert m == Matrix(((0, 0, 0, 0), + (0, 0, 0, 0), + (0, 0, 1, 0), + (0, 0, 0, 1))) m[:2, :2] = eye(2) assert m == eye(4) - m[:,0] = Matrix(4,1,(1,2,3,4)) - assert m == Matrix(((1,0,0,0), - (2,1,0,0), - (3,0,1,0), - (4,0,0,1))) - m[:,:] = zeros(4) + m[:, 0] = Matrix(4, 1, (1, 2, 3, 4)) + assert m == Matrix(((1, 0, 0, 0), + (2, 1, 0, 0), + (3, 0, 1, 0), + (4, 0, 0, 1))) + m[:, :] = zeros(4) assert m == zeros(4) - m[:,:] = ((1,2,3,4),(5,6,7,8),(9, 10, 11, 12),(13,14,15,16)) - assert m == Matrix(((1,2,3,4), - (5,6,7,8), + m[:, :] = [(1, 2, 3, 4), (5, 6, 7, 8), (9, 10, 11, 12), (13, 14, 15, 16)] + assert m == Matrix(((1, 2, 3, 4), + (5, 6, 7, 8), (9, 10, 11, 12), - (13,14,15,16))) - m[:2, 0] = [0,0] - assert m == Matrix(((0,2,3,4), - (0,6,7,8), + (13, 14, 15, 16))) + m[:2, 0] = [0, 0] + assert m == Matrix(((0, 2, 3, 4), + (0, 6, 7, 8), (9, 10, 11, 12), - (13,14,15,16))) + (13, 14, 15, 16))) + def test_extract(): m = Matrix(4, 3, lambda i, j: i*3 + j) - assert m.extract([0,1,3],[0,1]) == Matrix(3,2,[0,1,3,4,9,10]) - assert m.extract([0,3],[0,0,2]) == Matrix(2,3,[0,0,2,9,9,11]) - assert m.extract(list(range(4)),list(range(3))) == m + assert m.extract([0, 1, 3], [0, 1]) == Matrix(3, 2, [0, 1, 3, 4, 9, 10]) + assert m.extract([0, 3], [0, 0, 2]) == Matrix(2, 3, [0, 0, 2, 9, 9, 11]) + assert m.extract(list(range(4)), list(range(3))) == m raises(IndexError, lambda: m.extract([4], [0])) raises(IndexError, lambda: m.extract([0], [3])) + def test_reshape(): m0 = eye(3) - assert m0.reshape(1,9) == Matrix(1,9,(1,0,0,0,1,0,0,0,1)) - m1 = Matrix(3,4, lambda i,j: i+j) - assert m1.reshape(4,3) == Matrix(((0,1,2), (3,1,2), (3,4,2), (3,4,5))) - assert m1.reshape(2,6) == Matrix(((0,1,2,3,1,2), (3,4,2,3,4,5))) + assert m0.reshape(1, 9) == Matrix(1, 9, (1, 0, 0, 0, 1, 0, 0, 0, 1)) + m1 = Matrix(3, 4, lambda i, j: i + j) + assert m1.reshape( + 4, 3) == Matrix(((0, 1, 2), (3, 1, 2), (3, 4, 2), (3, 4, 5))) + assert m1.reshape(2, 6) == Matrix(((0, 1, 2, 3, 1, 2), (3, 4, 2, 3, 4, 5))) + def test_applyfunc(): m0 = eye(3) - assert m0.applyfunc(lambda x:2*x) == eye(3)*2 + assert m0.applyfunc(lambda x: 2*x) == eye(3)*2 assert m0.applyfunc(lambda x: 0 ) == zeros(3) + def test_expand(): - x,y = symbols('x y') - m0 = Matrix([[x*(x+y),2],[((x+y)*y)*x,x*(y+x*(x+y))]]) + m0 = Matrix([[x*(x + y), 2], [((x + y)*y)*x, x*(y + x*(x + y))]]) # Test if expand() returns a matrix m1 = m0.expand() - assert m1 == Matrix([[x*y+x**2,2],[x*y**2+y*x**2,x*y+y*x**2+x**3]]) + assert m1 == Matrix( + [[x*y + x**2, 2], [x*y**2 + y*x**2, x*y + y*x**2 + x**3]]) a = Symbol('a', real=True) assert Matrix([exp(I*a)]).expand(complex=True) == \ Matrix([cos(a) + I*sin(a)]) + def test_random(): - M = randMatrix(3,3) - M = randMatrix(3,3,seed=3) - M = randMatrix(3,4,0,150) + M = randMatrix(3, 3) + M = randMatrix(3, 3, seed=3) + M = randMatrix(3, 4, 0, 150) M = randMatrix(3, symmetric=True) + S = M.copy() + S.simplify() + assert S == M # doesn't fail when elements are Numbers, not int + def test_LUdecomp(): - testmat = Matrix([[0,2,5,3], - [3,3,7,4], - [8,4,0,2], - [-2,6,3,4]]) - L,U,p = testmat.LUdecomposition() - assert L.is_lower() - assert U.is_upper() - assert (L*U).permuteBkwd(p)-testmat == zeros(4) - - testmat = Matrix([[6,-2,7,4], - [0,3,6,7], - [1,-2,7,4], - [-9,2,6,3]]) - L,U,p = testmat.LUdecomposition() - assert L.is_lower() - assert U.is_upper() - assert (L*U).permuteBkwd(p)-testmat == zeros(4) + testmat = Matrix([[0, 2, 5, 3], + [3, 3, 7, 4], + [8, 4, 0, 2], + [-2, 6, 3, 4]]) + L, U, p = testmat.LUdecomposition() + assert L.is_lower + assert U.is_upper + assert (L*U).permuteBkwd(p) - testmat == zeros(4) + + testmat = Matrix([[6, -2, 7, 4], + [0, 3, 6, 7], + [1, -2, 7, 4], + [-9, 2, 6, 3]]) + L, U, p = testmat.LUdecomposition() + assert L.is_lower + assert U.is_upper + assert (L*U).permuteBkwd(p) - testmat == zeros(4) - x, y, z = Symbol('x'), Symbol('y'), Symbol('z') M = Matrix(((1, x, 1), (2, y, 0), (y, 0, z))) L, U, p = M.LUdecomposition() - assert L.is_lower() - assert U.is_upper() - assert (L*U).permuteBkwd(p)-M == zeros(3) + assert L.is_lower + assert U.is_upper + assert (L*U).permuteBkwd(p) - M == zeros(3) mL = Matrix(( - (1,0,0), - (2,3,0), + (1, 0, 0), + (2, 3, 0), )) - assert mL.is_lower() == True - assert mL.is_upper() == False + assert mL.is_lower is True + assert mL.is_upper is False mU = Matrix(( - (1,2,3), - (0,4,5), + (1, 2, 3), + (0, 4, 5), )) - assert mU.is_lower() == False - assert mU.is_upper() == True + assert mU.is_lower is False + assert mU.is_upper is True # test FF LUdecomp M = Matrix([[1, 3, 3], @@ -440,179 +479,211 @@ P, L, Dee, U = M.LUdecompositionFF() assert P*M == L*Dee.inv()*U - M = Matrix([[1, 2, 3, 4], - [3, -1, 2, 3], - [3, 1, 3, -2], - [6, -1, 0, 2]]) + M = Matrix([[1, 2, 3, 4], + [3, -1, 2, 3], + [3, 1, 3, -2], + [6, -1, 0, 2]]) P, L, Dee, U = M.LUdecompositionFF() assert P*M == L*Dee.inv()*U M = Matrix([[0, 0, 1], - [2,3,0], - [3, 1, 4]]) + [2, 3, 0], + [3, 1, 4]]) P, L, Dee, U = M.LUdecompositionFF() assert P*M == L*Dee.inv()*U + def test_LUsolve(): - A = Matrix([[2,3,5], - [3,6,2], - [8,3,6]]) - x = Matrix(3,1,[3,7,5]) + A = Matrix([[2, 3, 5], + [3, 6, 2], + [8, 3, 6]]) + x = Matrix(3, 1, [3, 7, 5]) b = A*x soln = A.LUsolve(b) assert soln == x - A = Matrix([[0,-1,2], - [5,10,7], - [8,3,4]]) - x = Matrix(3,1,[-1,2,5]) + A = Matrix([[0, -1, 2], + [5, 10, 7], + [8, 3, 4]]) + x = Matrix(3, 1, [-1, 2, 5]) b = A*x soln = A.LUsolve(b) assert soln == x + def test_QRsolve(): - A = Matrix([[2,3,5], - [3,6,2], - [8,3,6]]) - x = Matrix(3,1,[3,7,5]) + A = Matrix([[2, 3, 5], + [3, 6, 2], + [8, 3, 6]]) + x = Matrix(3, 1, [3, 7, 5]) b = A*x soln = A.QRsolve(b) assert soln == x - x = Matrix([[1,2],[3,4],[5,6]]) + x = Matrix([[1, 2], [3, 4], [5, 6]]) b = A*x soln = A.QRsolve(b) assert soln == x - A = Matrix([[0,-1,2], - [5,10,7], - [8,3,4]]) - x = Matrix(3,1,[-1,2,5]) + A = Matrix([[0, -1, 2], + [5, 10, 7], + [8, 3, 4]]) + x = Matrix(3, 1, [-1, 2, 5]) b = A*x soln = A.QRsolve(b) assert soln == x - x = Matrix([[7,8],[9,10],[11,12]]) + x = Matrix([[7, 8], [9, 10], [11, 12]]) b = A*x soln = A.QRsolve(b) assert soln == x + def test_inverse(): A = eye(4) assert A.inv() == eye(4) - assert A.inv("LU") == eye(4) - assert A.inv("ADJ") == eye(4) - A = Matrix([[2,3,5], - [3,6,2], - [8,3,6]]) + assert A.inv(method="LU") == eye(4) + assert A.inv(method="ADJ") == eye(4) + A = Matrix([[2, 3, 5], + [3, 6, 2], + [8, 3, 6]]) Ainv = A.inv() assert A*Ainv == eye(3) - assert A.inv("LU") == Ainv - assert A.inv("ADJ") == Ainv + assert A.inv(method="LU") == Ainv + assert A.inv(method="ADJ") == Ainv + + # test that immutability is not a problem + cls = ImmutableMatrix + m = cls([[48, 49, 31], + [ 9, 71, 94], + [59, 28, 65]]) + assert all(type(m.inv(s)) is cls for s in 'GE ADJ LU'.split()) + cls = ImmutableSparseMatrix + m = cls([[48, 49, 31], + [ 9, 71, 94], + [59, 28, 65]]) + assert all(type(m.inv(s)) is cls for s in 'CH LDL'.split()) + def test_util(): R = Rational - v1 = Matrix(1,3,[1,2,3]) - v2 = Matrix(1,3,[3,4,5]) - assert v1.cross(v2) == Matrix(1,3,[-2,4,-2]) + v1 = Matrix(1, 3, [1, 2, 3]) + v2 = Matrix(1, 3, [3, 4, 5]) + assert v1.cross(v2) == Matrix(1, 3, [-2, 4, -2]) assert v1.norm() == sqrt(14) assert v1.project(v2) == Matrix(1, 3, [R(39)/25, R(52)/25, R(13)/5]) assert Matrix.zeros(1, 2) == Matrix(1, 2, [0, 0]) assert ones(1, 2) == Matrix(1, 2, [1, 1]) - assert v1.clone() == v1 + assert v1.copy() == v1 # cofactor assert eye(3) == eye(3).cofactorMatrix() - test = Matrix([[1,3,2],[2,6,3],[2,3,6]]) - assert test.cofactorMatrix() == Matrix([[27,-6,-6],[-12,2,3],[-3,1,0]]) - test = Matrix([[1,2,3],[4,5,6],[7,8,9]]) - assert test.cofactorMatrix() == Matrix([[-3,6,-3],[6,-12,6],[-3,6,-3]]) + test = Matrix([[1, 3, 2], [2, 6, 3], [2, 3, 6]]) + assert test.cofactorMatrix() == \ + Matrix([[27, -6, -6], [-12, 2, 3], [-3, 1, 0]]) + test = Matrix([[1, 2, 3], [4, 5, 6], [7, 8, 9]]) + assert test.cofactorMatrix() == \ + Matrix([[-3, 6, -3], [6, -12, 6], [-3, 6, -3]]) + raises(ShapeError, lambda: Matrix(1, 2, [1, 1]).cross(Matrix(1, 2, [1, 1]))) def test_jacobian_hessian(): - x = Symbol('x') - y = Symbol('y') - L = Matrix(1,2,[x**2*y, 2*y**2 + x*y]) - syms = [x,y] - assert L.jacobian(syms) == Matrix([[2*x*y, x**2],[y, 4*y+x]]) + L = Matrix(1, 2, [x**2*y, 2*y**2 + x*y]) + syms = [x, y] + assert L.jacobian(syms) == Matrix([[2*x*y, x**2], [y, 4*y + x]]) - L = Matrix(1,2,[x, x**2*y**3]) + L = Matrix(1, 2, [x, x**2*y**3]) assert L.jacobian(syms) == Matrix([[1, 0], [2*x*y**3, x**2*3*y**2]]) f = x**2*y - syms = [x,y] + syms = [x, y] assert hessian(f, syms) == Matrix([[2*y, 2*x], [2*x, 0]]) f = x**2*y**3 - assert hessian(f, syms) == Matrix([[2*y**3, 6*x*y**2],[6*x*y**2, 6*x**2*y]]) + assert hessian(f, syms) == \ + Matrix([[2*y**3, 6*x*y**2], [6*x*y**2, 6*x**2*y]]) + + f = z + x*y**2 + g = x**2 + 2*y**3 + ans = Matrix([[0, 2*y], + [2*y, 2*x]]) + assert ans == hessian(f, Matrix([x, y])) + assert ans == hessian(f, Matrix([x, y]).T) + assert hessian(f, (y, x), [g]) == Matrix([ + [ 0, 6*y**2, 2*x], + [6*y**2, 2*x, 2*y], + [ 2*x, 2*y, 0]]) + def test_QR(): - A = Matrix([[1,2],[2,3]]) + A = Matrix([[1, 2], [2, 3]]) Q, S = A.QRdecomposition() R = Rational assert Q == Matrix([ - [5**R(-1,2), (R(2)/5)*(R(1)/5)**R(-1,2)], - [2*5**R(-1,2), (-R(1)/5)*(R(1)/5)**R(-1,2)]]) - assert S == Matrix([[5**R(1,2), 8*5**R(-1,2)], [0, (R(1)/5)**R(1,2)]]) + [ 5**R(-1, 2), (R(2)/5)*(R(1)/5)**R(-1, 2)], + [2*5**R(-1, 2), (-R(1)/5)*(R(1)/5)**R(-1, 2)]]) + assert S == Matrix([[5**R(1, 2), 8*5**R(-1, 2)], [0, (R(1)/5)**R(1, 2)]]) assert Q*S == A assert Q.T * Q == eye(2) - A = Matrix([[1,1,1],[1,1,3],[2,3,4]]) + A = Matrix([[1, 1, 1], [1, 1, 3], [2, 3, 4]]) Q, R = A.QRdecomposition() assert Q.T * Q == eye(Q.cols) - assert R.is_upper() + assert R.is_upper assert A == Q*R + def test_QR_non_square(): - A = Matrix([[9,0,26],[12,0,-7],[0,4,4],[0,-3,-3]]) + A = Matrix([[9, 0, 26], [12, 0, -7], [0, 4, 4], [0, -3, -3]]) Q, R = A.QRdecomposition() assert Q.T * Q == eye(Q.cols) - assert R.is_upper() + assert R.is_upper assert A == Q*R - A = Matrix([[1,-1,4],[1,4,-2],[1,4,2],[1,-1,0]]) + A = Matrix([[1, -1, 4], [1, 4, -2], [1, 4, 2], [1, -1, 0]]) Q, R = A.QRdecomposition() assert Q.T * Q == eye(Q.cols) - assert R.is_upper() + assert R.is_upper assert A == Q*R + def test_nullspace(): # first test reduced row-ech form R = Rational - M = Matrix([[5,7,2,1], - [1,6,2,-1]]) + M = Matrix([[5, 7, 2, 1], + [1, 6, 2, -1]]) out, tmp = M.rref() - assert out == Matrix([[1,0,-R(2)/23,R(13)/23], - [0,1,R(8)/23, R(-6)/23]]) + assert out == Matrix([[1, 0, -R(2)/23, R(13)/23], + [0, 1, R(8)/23, R(-6)/23]]) - M = Matrix([[-5,-1, 4,-3,-1], - [ 1,-1,-1, 1, 0], - [-1, 0, 0, 0, 0], - [ 4, 1,-4, 3, 1], - [-2, 0, 2,-2,-1]]) - assert M*M.nullspace()[0] == Matrix(5,1,[0]*5) - - M = Matrix([[1,3,0,2,6,3,1], - [-2,-6,0,-2,-8,3,1], - [3,9,0,0,6,6,2], - [-1,-3,0,1,0,9,3]]) + M = Matrix([[-5, -1, 4, -3, -1], + [ 1, -1, -1, 1, 0], + [-1, 0, 0, 0, 0], + [ 4, 1, -4, 3, 1], + [-2, 0, 2, -2, -1]]) + assert M*M.nullspace()[0] == Matrix(5, 1, [0]*5) + + M = Matrix([[ 1, 3, 0, 2, 6, 3, 1], + [-2, -6, 0, -2, -8, 3, 1], + [ 3, 9, 0, 0, 6, 6, 2], + [-1, -3, 0, 1, 0, 9, 3]]) out, tmp = M.rref() - assert out == Matrix([[1,3,0,0,2,0,0], - [0,0,0,1,2,0,0], - [0,0,0,0,0,1,R(1)/3], - [0,0,0,0,0,0,0]]) + assert out == Matrix([[1, 3, 0, 0, 2, 0, 0], + [0, 0, 0, 1, 2, 0, 0], + [0, 0, 0, 0, 0, 1, R(1)/3], + [0, 0, 0, 0, 0, 0, 0]]) # now check the vectors basis = M.nullspace() - assert basis[0] == Matrix([-3,1,0,0,0,0,0]) - assert basis[1] == Matrix([0,0,1,0,0,0,0]) - assert basis[2] == Matrix([-2,0,0,-2,1,0,0]) - assert basis[3] == Matrix([0,0,0,0,0,R(-1)/3, 1]) + assert basis[0] == Matrix([-3, 1, 0, 0, 0, 0, 0]) + assert basis[1] == Matrix([0, 0, 1, 0, 0, 0, 0]) + assert basis[2] == Matrix([-2, 0, 0, -2, 1, 0, 0]) + assert basis[3] == Matrix([0, 0, 0, 0, 0, R(-1)/3, 1]) # issue 1698; just see that we can do it when rows > cols - M = Matrix([[1,2],[2,4],[3,6]]) + M = Matrix([[1, 2], [2, 4], [3, 6]]) assert M.nullspace() + def test_wronskian(): - x = Symbol('x') assert wronskian([cos(x), sin(x)], x) == cos(x)**2 + sin(x)**2 assert wronskian([exp(x), exp(2*x)], x) == exp(3*x) assert wronskian([exp(x), x], x) == exp(x) - x*exp(x) @@ -620,96 +691,97 @@ w1 = -6*exp(x)*sin(x)*x + 6*cos(x)*exp(x)*x**2 - 6*exp(x)*cos(x)*x - \ exp(x)*cos(x)*x**3 + exp(x)*sin(x)*x**3 assert wronskian([exp(x), cos(x), x**3], x).expand() == w1 - assert wronskian([exp(x), cos(x), x**3], x, method='berkowitz' - ).expand() == w1 + assert wronskian([exp(x), cos(x), x**3], x, method='berkowitz').expand() \ + == w1 w2 = -x**3*cos(x)**2 - x**3*sin(x)**2 - 6*x*cos(x)**2 - 6*x*sin(x)**2 assert wronskian([sin(x), cos(x), x**3], x).expand() == w2 - assert wronskian([sin(x), cos(x), x**3], x, \ - method='berkowitz').expand() == w2 + assert wronskian([sin(x), cos(x), x**3], x, method='berkowitz').expand() \ + == w2 assert wronskian([], x) == 1 + def test_eigen(): - x,y = symbols('x y') R = Rational - assert eye(3).charpoly(x) == Poly((x-1)**3, x) - assert eye(3).charpoly(y) == Poly((y-1)**3, y) + assert eye(3).charpoly(x) == Poly((x - 1)**3, x) + assert eye(3).charpoly(y) == Poly((y - 1)**3, y) - M = Matrix([[1,0,0], - [0,1,0], - [0,0,1]]) + M = Matrix([[1, 0, 0], + [0, 1, 0], + [0, 0, 1]]) assert M.eigenvals(multiple=False) == {S.One: 3} assert M.eigenvects() == ( - [(1, 3, [Matrix([1,0,0]), - Matrix([0,1,0]), - Matrix([0,0,1])])]) - - M = Matrix([[0,1,1], - [1,0,0], - [1,1,1]]) + [(1, 3, [Matrix([1, 0, 0]), + Matrix([0, 1, 0]), + Matrix([0, 0, 1])])]) + + M = Matrix([[0, 1, 1], + [1, 0, 0], + [1, 1, 1]]) assert M.eigenvals() == {2*S.One: 1, -S.One: 1, S.Zero: 1} assert M.eigenvects() == ( [ - (-1, 1, [Matrix([-1, 1, 0])]), - ( 0, 1, [Matrix([0, -1, 1])]), - ( 2, 1, [Matrix([R(2, 3), R(1, 3), 1])])]) + (-1, 1, [Matrix([-1, 1, 0])]), + ( 0, 1, [Matrix([0, -1, 1])]), + ( 2, 1, [Matrix([R(2, 3), R(1, 3), 1])]) + ]) M = Matrix([[1, -1], - [1, 3]]) - assert M.eigenvects() == ( - [(2, 2, [Matrix(2,1,[-1,1])])]) + [1, 3]]) + assert M.eigenvects() == ([(2, 2, [Matrix(2, 1, [-1, 1])])]) M = Matrix([[1, 2, 3], [4, 5, 6], [7, 8, 9]]) - a=R(15,2) - b=3*33**R(1,2) - c=R(13,2) - d=(R(33,8) + 3*b/8) - e=(R(33,8) - 3*b/8) + a = R(15, 2) + b = 3*33**R(1, 2) + c = R(13, 2) + d = (R(33, 8) + 3*b/8) + e = (R(33, 8) - 3*b/8) + def NS(e, n): return str(N(e, n)) r = [ (a - b/2, 1, [Matrix([(12 + 24/(c - b/2))/((c - b/2)*e) + 3/(c - b/2), - (6 + 12/(c - b/2))/e,1])]), - ( 0, 1, [Matrix([1,-2,1])]), + (6 + 12/(c - b/2))/e, 1])]), + ( 0, 1, [Matrix([1, -2, 1])]), (a + b/2, 1, [Matrix([(12 + 24/(c + b/2))/((c + b/2)*d) + 3/(c + b/2), - (6 + 12/(c + b/2))/d,1])]), - ] - r1 = [(NS(r[i][0],2),NS(r[i][1],2), - [NS(j,2) for j in r[i][2][0]]) for i in range(len(r))] + (6 + 12/(c + b/2))/d, 1])]), + ] + r1 = [(NS(r[i][0], 2), NS(r[i][1], 2), + [NS(j, 2) for j in r[i][2][0]]) for i in range(len(r))] r = M.eigenvects() - r2 = [(NS(r[i][0],2),NS(r[i][1],2), - [NS(j,2) for j in r[i][2][0]]) for i in range(len(r))] + r2 = [(NS(r[i][0], 2), NS(r[i][1], 2), + [NS(j, 2) for j in r[i][2][0]]) for i in range(len(r))] assert sorted(r1) == sorted(r2) - eps = Symbol('eps',real=True) + eps = Symbol('eps', real=True) M = Matrix([[abs(eps), I*eps ], - [-I*eps, abs(eps) ]]) + [-I*eps, abs(eps) ]]) assert M.eigenvects() == ( [ - ( 0, 1, [Matrix([[-I*eps/abs(eps)],[1]])]), - ( 2*abs(eps), 1, [ Matrix([[I*eps/abs(eps)],[1]]) ] ), + ( 0, 1, [Matrix([[-I*eps/abs(eps)], [1]])]), + ( 2*abs(eps), 1, [ Matrix([[I*eps/abs(eps)], [1]]) ] ), ]) - M = Matrix(3,3,[1, 2, 0, 0, 3, 0, 2, -4, 2]) + M = Matrix(3, 3, [1, 2, 0, 0, 3, 0, 2, -4, 2]) M._eigenvects = M.eigenvects(simplify=False) assert max(i.q for i in M._eigenvects[0][2][0]) > 1 M._eigenvects = M.eigenvects(simplify=True) assert max(i.q for i in M._eigenvects[0][2][0]) == 1 M = Matrix([[S(1)/4, 1], [1, 1]]) assert M.eigenvects(simplify=True) == [ - (S(5)/8 + sqrt(73)/8, 1, [Matrix([[8/(3 + sqrt(73))], [1]])]), + (S(5)/8 + sqrt(73)/8, 1, [Matrix([[8/(3 + sqrt(73))], [1]])]), (-sqrt(73)/8 + S(5)/8, 1, [Matrix([[8/(-sqrt(73) + 3)], [1]])])] assert M.eigenvects(simplify=False) == [ - (Rational(5, 8) + sqrt(73)/8, 1, + (Rational(5, 8) + sqrt(73)/8, 1, [Matrix([[-1/(-sqrt(73)/8 + Rational(-3, 8))], [1]])]), - (-sqrt(73)/8 + Rational(5, 8), 1, + (-sqrt(73)/8 + Rational(5, 8), 1, [Matrix([[-1/(Rational(-3, 8) + sqrt(73)/8)], [1]])]), ] @@ -720,474 +792,147 @@ sevals = list(sorted(evals.keys())) assert all(abs(nevals[i] - sevals[i]) < 1e-9 for i in range(len(nevals))) -@XFAIL -def test_sparse_matrix(): - def eye(n): - tmp = SparseMatrix(n,n,lambda i,j:0) - for i in range(tmp.rows): - tmp[i,i] = 1 - return tmp - - def zeros(n): - return SparseMatrix(n,n,lambda i,j:0) - - # test element assignment - a = SparseMatrix(( - (1, 0), - (0, 1) - )) - a[0, 0] = 2 - assert a == SparseMatrix(( - (2, 0), - (0, 1) - )) - a[1, 0] = 5 - assert a == SparseMatrix(( - (2, 0), - (5, 1) - )) - a[1, 1] = 0 - assert a == SparseMatrix(( - (2, 0), - (5, 0) - )) - assert a.mat == {(0, 0): 2, (1, 0): 5} - - # test_multiplication - a=SparseMatrix(( - (1, 2), - (3, 1), - (0, 6), - )) - - b = SparseMatrix (( - (1, 2), - (3, 0), - )) - - c= a*b - assert c[0,0]==7 - assert c[0,1]==2 - assert c[1,0]==6 - assert c[1,1]==6 - assert c[2,0]==18 - assert c[2,1]==0 - - x = Symbol("x") - - c = b * Symbol("x") - assert isinstance(c,SparseMatrix) - assert c[0,0] == x - assert c[0,1] == 2*x - assert c[1,0] == 3*x - assert c[1,1] == 0 - - c = 5 * b - assert isinstance(c,SparseMatrix) - assert c[0,0] == 5 - assert c[0,1] == 2*5 - assert c[1,0] == 3*5 - assert c[1,1] == 0 - - #test_power - A = SparseMatrix([[2,3],[4,5]]) - assert (A**5)[:] == [6140, 8097, 10796, 14237] - A = SparseMatrix([[2, 1, 3],[4,2, 4], [6,12, 1]]) - assert (A**3)[:] == [290, 262, 251, 448, 440, 368, 702, 954, 433] - - - # test_creation - x = Symbol("x") - a = SparseMatrix([x, 0], [0, 0]) - m = a - assert m.cols == m.rows - assert m.cols == 2 - assert m[:] == [x,0,0,0] - b = SparseMatrix(2,2, [x, 0, 0, 0]) - m = b - assert m.cols == m.rows - assert m.cols == 2 - assert m[:] == [x,0,0,0] - - assert a == b - - a = SparseMatrix(1, 2, [1, 2]) - b = a - c = a - assert a[0] == 1 - assert a.row_del(0) == SparseMatrix(0, 2, []) - assert b.col_del(1) == SparseMatrix(1, 1, [1]) - assert c.toMatrix() == Matrix(1, 2, [1, 2]) - - # test_determinant - x, y = Symbol('x'), Symbol('y') - - assert SparseMatrix(1, 1, [0]).det() == 0 - - assert SparseMatrix([[1]]).det() == 1 - - assert SparseMatrix(( (-3, 2), - ( 8, -5) )).det() == -1 - - assert SparseMatrix(( (x, 1), - (y, 2*y) )).det() == 2*x*y-y - - assert SparseMatrix(( (1, 1, 1), - (1, 2, 3), - (1, 3, 6) )).det() == 1 - - assert SparseMatrix(( ( 3, -2, 0, 5), - (-2, 1, -2, 2), - ( 0, -2, 5, 0), - ( 5, 0, 3, 4) )).det() == -289 - - assert SparseMatrix(( ( 1, 2, 3, 4), - ( 5, 6, 7, 8), - ( 9, 10, 11, 12), - (13, 14, 15, 16) )).det() == 0 - - assert SparseMatrix(( (3, 2, 0, 0, 0), - (0, 3, 2, 0, 0), - (0, 0, 3, 2, 0), - (0, 0, 0, 3, 2), - (2, 0, 0, 0, 3) )).det() == 275 - - assert SparseMatrix(( (1, 0, 1, 2, 12), - (2, 0, 1, 1, 4), - (2, 1, 1, -1, 3), - (3, 2, -1, 1, 8), - (1, 1, 1, 0, 6) )).det() == -55 - - assert SparseMatrix(( (-5, 2, 3, 4, 5), - ( 1, -4, 3, 4, 5), - ( 1, 2, -3, 4, 5), - ( 1, 2, 3, -2, 5), - ( 1, 2, 3, 4, -1) )).det() == 11664 - - assert SparseMatrix(( ( 2, 7, -1, 3, 2), - ( 0, 0, 1, 0, 1), - (-2, 0, 7, 0, 2), - (-3, -2, 4, 5, 3), - ( 1, 0, 0, 0, 1) )).det() == 123 - - # test_submatrix - m0 = eye(4) - assert m0[:3, :3] == eye(3) - assert m0[2:4, 0:2] == zeros(2) - - m1 = SparseMatrix(3,3, lambda i,j: i+j) - assert m1[0,:] == SparseMatrix(1,3,(0,1,2)) - assert m1[1:3, 1] == SparseMatrix(2,1,(2,3)) - - m2 = SparseMatrix([0,1,2,3],[4,5,6,7],[8,9,10,11],[12,13,14,15]) - assert m2[:,-1] == SparseMatrix(4,1,[3,7,11,15]) - assert m2[-2:,:] == SparseMatrix([[8,9,10,11],[12,13,14,15]]) - - assert SparseMatrix([[1, 2], [3, 4]]).submatrix([1, 1]) == Matrix([[4]]) - - # test_submatrix_assignment - m = zeros(4) - m[2:4, 2:4] = eye(2) - assert m == SparseMatrix((0,0,0,0), - (0,0,0,0), - (0,0,1,0), - (0,0,0,1)) - m[:2, :2] = eye(2) - assert m == eye(4) - m[:,0] = SparseMatrix(4,1,(1,2,3,4)) - assert m == SparseMatrix((1,0,0,0), - (2,1,0,0), - (3,0,1,0), - (4,0,0,1)) - m[:,:] = zeros(4) - assert m == zeros(4) - m[:,:] = ((1,2,3,4),(5,6,7,8),(9, 10, 11, 12),(13,14,15,16)) - assert m == SparseMatrix(((1,2,3,4), - (5,6,7,8), - (9, 10, 11, 12), - (13,14,15,16))) - m[:2, 0] = [0,0] - assert m == SparseMatrix(((0,2,3,4), - (0,6,7,8), - (9, 10, 11, 12), - (13,14,15,16))) - - # test_reshape - m0 = eye(3) - assert m0.reshape(1,9) == SparseMatrix(1,9,(1,0,0,0,1,0,0,0,1)) - m1 = SparseMatrix(3,4, lambda i,j: i+j) - assert m1.reshape(4,3) == SparseMatrix((0,1,2), (3,1,2), (3,4,2), (3,4,5)) - assert m1.reshape(2,6) == SparseMatrix((0,1,2,3,1,2), (3,4,2,3,4,5)) - - # test_applyfunc - m0 = eye(3) - assert m0.applyfunc(lambda x:2*x) == eye(3)*2 - assert m0.applyfunc(lambda x: 0 ) == zeros(3) - - # test_LUdecomp - testmat = SparseMatrix([[0,2,5,3], - [3,3,7,4], - [8,4,0,2], - [-2,6,3,4]]) - L,U,p = testmat.LUdecomposition() - assert L.is_lower() - assert U.is_upper() - assert (L*U).permuteBkwd(p)-testmat == zeros(4) - - testmat = SparseMatrix([[6,-2,7,4], - [0,3,6,7], - [1,-2,7,4], - [-9,2,6,3]]) - L,U,p = testmat.LUdecomposition() - assert L.is_lower() - assert U.is_upper() - assert (L*U).permuteBkwd(p)-testmat == zeros(4) - - x, y, z = Symbol('x'), Symbol('y'), Symbol('z') - M = Matrix(((1, x, 1), (2, y, 0), (y, 0, z))) - L, U, p = M.LUdecomposition() - assert L.is_lower() - assert U.is_upper() - assert (L*U).permuteBkwd(p)-M == zeros(3) - - # test_LUsolve - A = SparseMatrix([[2,3,5], - [3,6,2], - [8,3,6]]) - x = SparseMatrix(3,1,[3,7,5]) - b = A*x - soln = A.LUsolve(b) - assert soln == x - A = SparseMatrix([[0,-1,2], - [5,10,7], - [8,3,4]]) - x = SparseMatrix(3,1,[-1,2,5]) - b = A*x - soln = A.LUsolve(b) - assert soln == x - - # test_inverse - A = eye(4) - assert A.inv() == eye(4) - assert A.inv("LU") == eye(4) - assert A.inv("ADJ") == eye(4) - A = SparseMatrix([[2,3,5], - [3,6,2], - [8,3,6]]) - Ainv = A.inv() - assert A*Ainv == eye(3) - assert A.inv("LU") == Ainv - assert A.inv("ADJ") == Ainv - # test_cross - v1 = Matrix(1,3,[1,2,3]) - v2 = Matrix(1,3,[3,4,5]) - assert v1.cross(v2) == Matrix(1,3,[-2,4,-2]) - assert v1.norm(v1) == 14 - - # test_cofactor - assert eye(3) == eye(3).cofactorMatrix() - test = SparseMatrix([[1,3,2],[2,6,3],[2,3,6]]) - assert test.cofactorMatrix() == \ - SparseMatrix([[27,-6,-6],[-12,2,3],[-3,1,0]]) - test = SparseMatrix([[1,2,3],[4,5,6],[7,8,9]]) - assert test.cofactorMatrix() == \ - SparseMatrix([[-3,6,-3],[6,-12,6],[-3,6,-3]]) - - # test_jacobian - x = Symbol('x') - y = Symbol('y') - L = SparseMatrix(1,2,[x**2*y, 2*y**2 + x*y]) - syms = [x,y] - assert L.jacobian(syms) == Matrix([[2*x*y, x**2],[y, 4*y+x]]) - - L = SparseMatrix(1,2,[x, x**2*y**3]) - assert L.jacobian(syms) == SparseMatrix([[1, 0], [2*x*y**3, x**2*3*y**2]]) - - # test_QR - A = Matrix([[1,2],[2,3]]) - Q, S = A.QRdecomposition() - R = Rational - assert Q == Matrix([ - [5**R(-1,2), (R(2)/5)*(R(1)/5)**R(-1,2)], - [2*5**R(-1,2), (-R(1)/5)*(R(1)/5)**R(-1,2)]]) - assert S == Matrix([ - [5**R(1,2), 8*5**R(-1,2)], - [0, (R(1)/5)**R(1,2)]]) - assert Q*S == A - assert Q.T * Q == eye(2) - - # test nullspace - # first test reduced row-ech form - R = Rational - - M = Matrix([[5,7,2,1], - [1,6,2,-1]]) - out, tmp = M.rref() - assert out == Matrix([[1,0,-R(2)/23,R(13)/23], - [0,1,R(8)/23, R(-6)/23]]) +def test_subs(): + assert Matrix([[1, x], [x, 4]]).subs(x, 5) == Matrix([[1, 5], [5, 4]]) + assert Matrix([[x, 2], [x + y, 4]]).subs([[x, -1], [y, -2]]) == \ + Matrix([[-1, 2], [-3, 4]]) + assert Matrix([[x, 2], [x + y, 4]]).subs([(x, -1), (y, -2)]) == \ + Matrix([[-1, 2], [-3, 4]]) + assert Matrix([[x, 2], [x + y, 4]]).subs({x: -1, y: -2}) == \ + Matrix([[-1, 2], [-3, 4]]) + assert Matrix([x*y]).subs({x: y - 1, y: x - 1}, simultaneous=True) == \ + Matrix([(x - 1)*(y - 1)]) - M = Matrix([[1,3,0,2,6,3,1], - [-2,-6,0,-2,-8,3,1], - [3,9,0,0,6,6,2], - [-1,-3,0,1,0,9,3]]) - out, tmp = M.rref() - assert out == Matrix([[1,3,0,0,2,0,0], - [0,0,0,1,2,0,0], - [0,0,0,0,0,1,R(1)/3], - [0,0,0,0,0,0,0]]) - # now check the vectors - basis = M.nullspace() - assert basis[0] == Matrix([[-3,1,0,0,0,0,0]]) - assert basis[1] == Matrix([[0,0,1,0,0,0,0]]) - assert basis[2] == Matrix([[-2,0,0,-2,1,0,0]]) - assert basis[3] == Matrix([[0,0,0,0,0,R(-1)/3, 1]]) - - - # test eigen - x = Symbol('x') - y = Symbol('y') - eye3 = eye(3) - assert eye3.charpoly(x) == (1-x)**3 - assert eye3.charpoly(y) == (1-y)**3 - # test values - M = Matrix([(0,1,-1), - (1,1,0), - (-1,0,1) ]) - vals = M.eigenvals() - vals.sort() - assert vals == [-1, 1, 2] + for cls in classes: + assert Matrix([[2, 0], [0, 2]]) == cls.eye(2).subs(1, 2) - R = Rational - M = Matrix([[1,0,0], - [0,1,0], - [0,0,1]]) - assert M.eigenvects() == [[1, 3, [ - Matrix(1,3,[1,0,0]), - Matrix(1,3,[0,1,0]), - Matrix(1,3,[0,0,1])]]] - M = Matrix([[5,0,2], - [3,2,0], - [0,0,1]]) - assert M.eigenvects() == [[1, 1, [Matrix(1,3,[R(-1)/2,R(3)/2,1])]], - [2, 1, [Matrix(1,3,[0,1,0])]], - [5, 1, [Matrix(1,3,[1,1,0])]]] - assert M.zeros(3, 5) == SparseMatrix(3, 5, {}) +def test_simplify(): + f, n = symbols('f, n') -def test_subs(): - x = Symbol('x') - assert Matrix([[1,x],[x,4]]).subs(x, 5) == Matrix([[1,5],[5,4]]) - y = Symbol('y') - assert Matrix([[x,2],[x+y,4]]).subs([[x,-1],[y,-2]]) == \ - Matrix([[-1,2],[-3,4]]) - assert Matrix([[x,2],[x+y,4]]).subs([(x,-1),(y,-2)]) == \ - Matrix([[-1,2],[-3,4]]) - assert Matrix([[x,2],[x+y,4]]).subs({x:-1,y:-2}) == \ - Matrix([[-1,2],[-3,4]]) - assert Matrix([x*y]).subs({x:y-1, y:x-1}, simultaneous=True) == \ - Matrix([(x-1)*(y-1)]) + m = Matrix([[1, x], [x + 1/x, x - 1]]) + m = m.row_join(eye(m.cols)) + raw = m.rref(simplify=lambda x: x)[0] + assert raw != m.rref(simplify=True)[0] -def test_simplify(): - x,y,f,n = symbols('x y f n') - M = Matrix([[ 1/x + 1/y, (x + x*y)/ x ], - [(f(x) + y*f(x))/f(x), 2 * (1/n - cos(n * pi)/n)/ pi ] - ]) + M = Matrix([[ 1/x + 1/y, (x + x*y) / x ], + [ (f(x) + y*f(x))/f(x), 2 * (1/n - cos(n * pi)/n) / pi ]]) M.simplify() - assert M == Matrix([[(x + y)/(x * y), 1 + y ], - [ 1 + y, 2*((1 - 1*cos(pi*n))/(pi*n)) ]]) + assert M == Matrix([[ (x + y)/(x * y), 1 + y ], + [ 1 + y, 2*((1 - 1*cos(pi*n))/(pi*n)) ]]) M = Matrix([[(1 + x)**2]]) M.simplify() assert M == Matrix([[(1 + x)**2]]) M.simplify(ratio=oo) assert M == Matrix([[1 + 2*x + x**2]]) + def test_transpose(): - M = Matrix([[1,2,3,4,5,6,7,8,9,0], - [1,2,3,4,5,6,7,8,9,0]]) - assert M.T == Matrix( [ [1,1], - [2,2], - [3,3], - [4,4], - [5,5], - [6,6], - [7,7], - [8,8], - [9,9], - [0,0] ]) + M = Matrix([[1, 2, 3, 4, 5, 6, 7, 8, 9, 0], + [1, 2, 3, 4, 5, 6, 7, 8, 9, 0]]) + assert M.T == Matrix( [ [1, 1], + [2, 2], + [3, 3], + [4, 4], + [5, 5], + [6, 6], + [7, 7], + [8, 8], + [9, 9], + [0, 0] ]) assert M.T.T == M assert M.T == M.transpose() + def test_conjugate(): - M = Matrix([[0,I,5], - [1,2,0]]) + M = Matrix([[0, I, 5], + [1, 2, 0]]) - assert M.T == Matrix([[0,1], - [I,2], - [5,0]]) + assert M.T == Matrix([[0, 1], + [I, 2], + [5, 0]]) - assert M.C == Matrix([[0,-I,5], - [1,2,0]]) + assert M.C == Matrix([[0, -I, 5], + [1, 2, 0]]) assert M.C == M.conjugate() assert M.H == M.T.C - assert M.H == Matrix([[0,1], - [-I,2], - [5,0]]) + assert M.H == Matrix([[ 0, 1], + [-I, 2], + [ 5, 0]]) + def test_conj_dirac(): raises(AttributeError, lambda: eye(3).D) - M = Matrix([[1,I,I,I], - [0,1,I,I], - [0,0,1,I], - [0,0,0,1] ]) - - assert M.D == Matrix([ - [1,0,0,0], - [-I,1,0,0], - [-I,-I,-1,0], - [-I,-I,I,-1] ]) + M = Matrix([[1, I, I, I], + [0, 1, I, I], + [0, 0, 1, I], + [0, 0, 0, 1]]) + + assert M.D == Matrix([[ 1, 0, 0, 0], + [-I, 1, 0, 0], + [-I, -I, -1, 0], + [-I, -I, I, -1]]) def test_trace(): - M = Matrix([[1,0,0], - [0,5,0], - [0,0,8]]) + M = Matrix([[1, 0, 0], + [0, 5, 0], + [0, 0, 8]]) assert M.trace() == 14 + def test_shape(): - x, y = symbols("x y") - M = Matrix([[x,0,0], - [0,y,0]]) + M = Matrix([[x, 0, 0], + [0, y, 0]]) assert M.shape == (2, 3) -def test_col_row(): - x, y = symbols("x y") - M = Matrix([[x,0,0], - [0,y,0]]) - M.row(1,lambda r, j: r+j+1) - assert M == Matrix([[x,0,0], - [1,y+2,3]]) - M.col(0,lambda c, j: c+y**j) - assert M == Matrix([[x+1,0,0], - [1+y,y+2,3]]) + +def test_col_row_op(): + M = Matrix([[x, 0, 0], + [0, y, 0]]) + M.row_op(1, lambda r, j: r + j + 1) + assert M == Matrix([[x, 0, 0], + [1, y + 2, 3]]) + + M.col_op(0, lambda c, j: c + y**j) + assert M == Matrix([[x + 1, 0, 0], + [1 + y, y + 2, 3]]) + # neither row nor slice give copies that allow the original matrix to # be changed - assert M.row(0) == Matrix([[x+1, 0, 0]]) + assert M.row(0) == Matrix([[x + 1, 0, 0]]) r1 = M.row(0) r1[0] = 42 - assert M[0,0] == x + 1 - r1 = M[0, :-1] # also testing negative slice + assert M[0, 0] == x + 1 + r1 = M[0, :-1] # also testing negative slice r1[0] = 42 - assert M[0,0] == x + 1 + assert M[0, 0] == x + 1 c1 = M.col(0) assert c1 == Matrix([x + 1, 1 + y]) c1[0] = 0 - assert M[0,0] == x + 1 + assert M[0, 0] == x + 1 c1 = M[:, 0] c1[0] = 42 - assert M[0,0] == x + 1 + assert M[0, 0] == x + 1 + + +def test_zip_row_op(): + for cls in classes[:2]: # XXX: immutable matrices don't support row ops + M = cls.eye(3) + M.zip_row_op(1, 0, lambda v, u: v + 2*u) + assert M == cls([[1, 0, 0], + [2, 1, 0], + [0, 0, 1]]) + + M = cls.eye(3)*2 + M[0, 1] = -1 + M.zip_row_op(1, 0, lambda v, u: v + 2*u); M + assert M == cls([[2, -1, 0], + [4, 0, 0], + [0, 0, 2]]) def test_issue851(): m = Matrix([1, 2, 3]) @@ -1199,10 +944,12 @@ assert m == a assert m != b + def test_issue882(): class Index1(object): def __index__(self): return 1 + class Index2(object): def __index__(self): return 2 @@ -1217,58 +964,63 @@ assert m[2] == 5 m = Matrix([[1, 2, 3], [4, 5, 6]]) - assert m[index1,index2] == 6 - assert m[1,index2] == 6 - assert m[index1,2] == 6 + assert m[index1, index2] == 6 + assert m[1, index2] == 6 + assert m[index1, 2] == 6 - m[index1,index2] = 4 + m[index1, index2] = 4 assert m[1, 2] == 4 - m[1,index2] = 6 + m[1, index2] = 6 assert m[1, 2] == 6 - m[index1,2] = 8 + m[index1, 2] = 8 assert m[1, 2] == 8 + def test_evalf(): a = Matrix([sqrt(5), 6]) assert all(a.evalf()[i] == a[i].evalf() for i in range(2)) assert all(a.evalf(2)[i] == a[i].evalf(2) for i in range(2)) assert all(a.n(2)[i] == a[i].n(2) for i in range(2)) + def test_is_symbolic(): - x = Symbol('x') - a = Matrix([[x,x],[x,x]]) - assert a.is_symbolic() == True - a = Matrix([[1,2,3,4],[5,6,7,8]]) - assert a.is_symbolic() == False - a = Matrix([[1,2,3,4],[5,6,x,8]]) - assert a.is_symbolic() == True - a = Matrix([[1,x,3]]) - assert a.is_symbolic() == True - a = Matrix([[1,2,3]]) - assert a.is_symbolic() == False - a = Matrix([[1],[x],[3]]) - assert a.is_symbolic() == True - a = Matrix([[1],[2],[3]]) - assert a.is_symbolic() == False + a = Matrix([[x, x], [x, x]]) + assert a.is_symbolic() is True + a = Matrix([[1, 2, 3, 4], [5, 6, 7, 8]]) + assert a.is_symbolic() is False + a = Matrix([[1, 2, 3, 4], [5, 6, x, 8]]) + assert a.is_symbolic() is True + a = Matrix([[1, x, 3]]) + assert a.is_symbolic() is True + a = Matrix([[1, 2, 3]]) + assert a.is_symbolic() is False + a = Matrix([[1], [x], [3]]) + assert a.is_symbolic() is True + a = Matrix([[1], [2], [3]]) + assert a.is_symbolic() is False + def test_is_upper(): - a = Matrix([[1,2,3]]) - assert a.is_upper() == True - a = Matrix([[1],[2],[3]]) - assert a.is_upper() == False + a = Matrix([[1, 2, 3]]) + assert a.is_upper is True + a = Matrix([[1], [2], [3]]) + assert a.is_upper is False + def test_is_lower(): - a = Matrix([[1,2,3]]) - assert a.is_lower() == False - a = Matrix([[1],[2],[3]]) - assert a.is_lower() == True + a = Matrix([[1, 2, 3]]) + assert a.is_lower is False + a = Matrix([[1], [2], [3]]) + assert a.is_lower is True + def test_is_nilpotent(): - a = Matrix(4, 4, [0,2,1,6,0,0,1,2,0,0,0,3,0,0,0,0]) + a = Matrix(4, 4, [0, 2, 1, 6, 0, 0, 1, 2, 0, 0, 0, 3, 0, 0, 0, 0]) assert a.is_nilpotent() - a = Matrix([[1,0],[0,1]]) + a = Matrix([[1, 0], [0, 1]]) assert not a.is_nilpotent() + def test_zeros_ones_fill(): n, m = 3, 5 @@ -1281,10 +1033,11 @@ assert a.rows == b.rows == 3 assert a.cols == b.cols == 5 assert a.shape == b.shape == (3, 5) - assert zeros(2) == zeros(2,2) - assert ones(2) == ones(2,2) - assert zeros(2,3) == Matrix(2, 3, [0]*6) - assert ones(2,3) == Matrix(2, 3, [1]*6) + assert zeros(2) == zeros(2, 2) + assert ones(2) == ones(2, 2) + assert zeros(2, 3) == Matrix(2, 3, [0]*6) + assert ones(2, 3) == Matrix(2, 3, [1]*6) + def test_empty_zeros(): a = zeros(0) @@ -1296,30 +1049,33 @@ assert a.rows == 2 assert a.cols == 0 + def test_issue650(): - x, y = symbols('x y') - a = Matrix([[x**2, x*y],[x*sin(y), x*cos(y)]]) - assert a.diff(x) == Matrix([[2*x, y],[sin(y), cos(y)]]) + a = Matrix([[x**2, x*y], [x*sin(y), x*cos(y)]]) + assert a.diff(x) == Matrix([[2*x, y], [sin(y), cos(y)]]) assert Matrix([ [x, -x, x**2], - [exp(x),1/x-exp(-x), x+1/x]]).limit(x, oo) == \ - Matrix([[oo, -oo, oo],[oo, 0, oo]]) + [exp(x), 1/x - exp(-x), x + 1/x]]).limit(x, oo) == \ + Matrix([[oo, -oo, oo], [oo, 0, oo]]) assert Matrix([ - [(exp(x)-1)/x, 2*x + y*x, x**x ], - [1/x, abs(x) , abs(sin(x+1))]]).limit(x, 0) == \ - Matrix([[1, 0, 1],[oo, 0, sin(1)]]) + [(exp(x) - 1)/x, 2*x + y*x, x**x ], + [1/x, abs(x), abs(sin(x + 1))]]).limit(x, 0) == \ + Matrix([[1, 0, 1], [oo, 0, sin(1)]]) assert a.integrate(x) == Matrix([ - [Rational(1,3)*x**3, y*x**2/2], + [Rational(1, 3)*x**3, y*x**2/2], [x**2*sin(y)/2, x**2*cos(y)/2]]) + def test_inv_iszerofunc(): A = eye(4) - A.col_swap(0,1) + A.col_swap(0, 1) for method in "GE", "LU": - assert A.inv(method, iszerofunc=lambda x: x == 0) == A.inv("ADJ") + assert A.inv(method=method, iszerofunc=lambda x: x == 0) == \ + A.inv(method="ADJ") + def test_jacobian_metrics(): - rho, phi = symbols("rho phi") + rho, phi = symbols("rho,phi") X = Matrix([rho*cos(phi), rho*sin(phi)]) Y = Matrix([rho, phi]) J = X.jacobian(Y) @@ -1330,119 +1086,128 @@ g = g.applyfunc(trigsimp) assert g == Matrix([[1, 0], [0, rho**2]]) + def test_jacobian2(): - rho, phi = symbols("rho phi") + rho, phi = symbols("rho,phi") X = Matrix([rho*cos(phi), rho*sin(phi), rho**2]) Y = Matrix([rho, phi]) J = Matrix([ - [cos(phi), -rho*sin(phi)], - [sin(phi), rho*cos(phi)], - [ 2*rho, 0], - ]) + [cos(phi), -rho*sin(phi)], + [sin(phi), rho*cos(phi)], + [ 2*rho, 0], + ]) assert X.jacobian(Y) == J + def test_issue1465(): - x, y, z = symbols('x y z') X = Matrix([exp(x + y + z), exp(x + y + z), exp(x + y + z)]) Y = Matrix([x, y, z]) for i in range(1, 3): for j in range(1, 3): - X_slice = X[:i,:] - Y_slice = Y[:j,:] + X_slice = X[:i, :] + Y_slice = Y[:j, :] J = X_slice.jacobian(Y_slice) assert J.rows == i assert J.cols == j for k in range(j): - assert J[:,k] == X_slice + assert J[:, k] == X_slice + def test_nonvectorJacobian(): - x, y, z = symbols('x y z') X = Matrix([[exp(x + y + z), exp(x + y + z)], - [exp(x + y + z), exp(x + y + z)] ]) + [exp(x + y + z), exp(x + y + z)]]) raises(TypeError, lambda: X.jacobian(Matrix([x, y, z]))) - X = X[0,:] - Y = Matrix([[x, y], [x,z]]) + X = X[0, :] + Y = Matrix([[x, y], [x, z]]) raises(TypeError, lambda: X.jacobian(Y)) raises(TypeError, lambda: X.jacobian(Matrix([ [x, y], [x, z] ]))) + def test_vec(): - m = Matrix([[1,3], [2,4]]) + m = Matrix([[1, 3], [2, 4]]) m_vec = m.vec() assert m_vec.cols == 1 for i in range(4): assert m_vec[i] == i + 1 + def test_vech(): - m = Matrix([[1,2], [2,3]]) + m = Matrix([[1, 2], [2, 3]]) m_vech = m.vech() assert m_vech.cols == 1 for i in range(3): assert m_vech[i] == i + 1 m_vech = m.vech(diagonal=False) assert m_vech[0] == 2 - x,y = symbols('x,y') - m = Matrix([[1, x*(x+y)], [y*x+x**2, 1]]) + + m = Matrix([[1, x*(x + y)], [y*x + x**2, 1]]) m_vech = m.vech(diagonal=False) assert m_vech[0] == x*(x + y) - x,y = symbols('x,y') - m = Matrix([[1, x*(x+y)], [y*x, 1]]) + + m = Matrix([[1, x*(x + y)], [y*x, 1]]) m_vech = m.vech(diagonal=False, check_symmetry=False) assert m_vech[0] == y*x + def test_vech_errors(): - m = Matrix([[1,3]]) + m = Matrix([[1, 3]]) raises(ShapeError, lambda: m.vech()) - m = Matrix([[1,3], [2,4]]) + m = Matrix([[1, 3], [2, 4]]) raises(ValueError, lambda: m.vech()) - raises(ShapeError, lambda: Matrix([ [1,3] ]).vech()) - raises(ValueError, lambda: Matrix([ [1,3], [2,4] ]).vech()) + raises(ShapeError, lambda: Matrix([ [1, 3] ]).vech()) + raises(ValueError, lambda: Matrix([ [1, 3], [2, 4] ]).vech()) + def test_diag(): - x, y, z = symbols("x y z") a = Matrix([[1, 2], [2, 3]]) b = Matrix([[3, x], [y, 3]]) c = Matrix([[3, x, 3], [y, 3, z], [x, y, z]]) assert diag(a, b, b) == Matrix([ - [1, 2, 0, 0, 0, 0], - [2, 3, 0, 0, 0, 0], - [0, 0, 3, x, 0, 0], - [0, 0, y, 3, 0, 0], - [0, 0, 0, 0, 3, x], - [0, 0, 0, 0, y, 3], - ]) + [1, 2, 0, 0, 0, 0], + [2, 3, 0, 0, 0, 0], + [0, 0, 3, x, 0, 0], + [0, 0, y, 3, 0, 0], + [0, 0, 0, 0, 3, x], + [0, 0, 0, 0, y, 3], + ]) assert diag(a, b, c) == Matrix([ - [1, 2, 0, 0, 0, 0, 0], - [2, 3, 0, 0, 0, 0, 0], - [0, 0, 3, x, 0, 0, 0], - [0, 0, y, 3, 0, 0, 0], - [0, 0, 0, 0, 3, x, 3], - [0, 0, 0, 0, y, 3, z], - [0, 0, 0, 0, x, y, z], - ]) + [1, 2, 0, 0, 0, 0, 0], + [2, 3, 0, 0, 0, 0, 0], + [0, 0, 3, x, 0, 0, 0], + [0, 0, y, 3, 0, 0, 0], + [0, 0, 0, 0, 3, x, 3], + [0, 0, 0, 0, y, 3, z], + [0, 0, 0, 0, x, y, z], + ]) assert diag(a, c, b) == Matrix([ - [1, 2, 0, 0, 0, 0, 0], - [2, 3, 0, 0, 0, 0, 0], - [0, 0, 3, x, 3, 0, 0], - [0, 0, y, 3, z, 0, 0], - [0, 0, x, y, z, 0, 0], - [0, 0, 0, 0, 0, 3, x], - [0, 0, 0, 0, 0, y, 3], - ]) + [1, 2, 0, 0, 0, 0, 0], + [2, 3, 0, 0, 0, 0, 0], + [0, 0, 3, x, 3, 0, 0], + [0, 0, y, 3, z, 0, 0], + [0, 0, x, y, z, 0, 0], + [0, 0, 0, 0, 0, 3, x], + [0, 0, 0, 0, 0, y, 3], + ]) a = Matrix([x, y, z]) b = Matrix([[1, 2], [3, 4]]) c = Matrix([[5, 6]]) assert diag(a, 7, b, c) == Matrix([ - [x, 0, 0, 0, 0, 0], - [y, 0, 0, 0, 0, 0], - [z, 0, 0, 0, 0, 0], - [0, 7, 0, 0, 0, 0], - [0, 0, 1, 2, 0, 0], - [0, 0, 3, 4, 0, 0], - [0, 0, 0, 0, 5, 6], - ]) + [x, 0, 0, 0, 0, 0], + [y, 0, 0, 0, 0, 0], + [z, 0, 0, 0, 0, 0], + [0, 7, 0, 0, 0, 0], + [0, 0, 1, 2, 0, 0], + [0, 0, 3, 4, 0, 0], + [0, 0, 0, 0, 5, 6], + ]) + assert diag(1, [2, 3], [[4, 5]]) == Matrix([ + [1, 0, 0, 0], + [0, 2, 0, 0], + [0, 3, 0, 0], + [0, 0, 4, 5]]) + def test_get_diag_blocks1(): - x, y, z = symbols("x y z") a = Matrix([[1, 2], [2, 3]]) b = Matrix([[3, x], [y, 3]]) c = Matrix([[3, x, 3], [y, 3, z], [x, y, z]]) @@ -1450,8 +1215,8 @@ assert b.get_diag_blocks() == [b] assert c.get_diag_blocks() == [c] + def test_get_diag_blocks2(): - x, y, z = symbols("x y z") a = Matrix([[1, 2], [2, 3]]) b = Matrix([[3, x], [y, 3]]) c = Matrix([[3, x, 3], [y, 3, z], [x, y, z]]) @@ -1460,8 +1225,8 @@ assert diag(a, c, b).get_diag_blocks() == [a, c, b] assert diag(c, c, b).get_diag_blocks() == [c, c, b] + def test_inv_block(): - x, y, z = symbols("x y z") a = Matrix([[1, 2], [2, 3]]) b = Matrix([[3, x], [y, 3]]) c = Matrix([[3, x, 3], [y, 3, z], [x, y, z]]) @@ -1478,6 +1243,7 @@ a.inv(method="ADJ"), a.inv(method="ADJ"), b.inv(method="ADJ"), a.inv(method="ADJ"), c.inv(method="ADJ"), a.inv(method="ADJ")) + def test_creation_args(): """ Check that matrix dimensions can be specified using any reasonable type @@ -1494,22 +1260,22 @@ assert ones(3, Integer(4)) == ones(3, 4) raises(TypeError, lambda: Matrix(5)) raises(TypeError, lambda: Matrix(1, 2)) - raises(TypeError, lambda: SparseMatrix(1, 2)) + def test_diagonal_symmetrical(): - m = Matrix(2,2,[0, 1, 1, 0]) + m = Matrix(2, 2, [0, 1, 1, 0]) assert not m.is_diagonal() assert m.is_symmetric() assert m.is_symmetric(simplify=False) - m = Matrix(2,2,[1, 0, 0, 1]) + m = Matrix(2, 2, [1, 0, 0, 1]) assert m.is_diagonal() m = diag(1, 2, 3) assert m.is_diagonal() assert m.is_symmetric() - m = Matrix(3,3,[1, 0, 0, 0, 2, 0, 0, 0, 3]) + m = Matrix(3, 3, [1, 0, 0, 0, 2, 0, 0, 0, 3]) assert m == diag(1, 2, 3) m = Matrix(2, 3, zeros(2, 3)) @@ -1522,15 +1288,14 @@ m = Matrix(((5, 0, 0), (0, 6, 0))) assert m.is_diagonal() - x, y = symbols('x y') - m = Matrix(3,3,[1, x**2 + 2*x + 1, y, (x + 1)**2 , 2, 0, y, 0, 3]) + m = Matrix(3, 3, [1, x**2 + 2*x + 1, y, (x + 1)**2, 2, 0, y, 0, 3]) assert m.is_symmetric() assert not m.is_symmetric(simplify=False) assert m.expand().is_symmetric(simplify=False) + def test_diagonalization(): - x, y, z = symbols('x y z') - m = Matrix(3,2,[-3, 1, -3, 20, 3, 10]) + m = Matrix(3, 2, [-3, 1, -3, 20, 3, 10]) assert not m.is_diagonalizable() assert not m.is_symmetric() raises(NonSquareMatrixError, lambda: m.diagonalize()) @@ -1541,13 +1306,13 @@ assert P == eye(3) assert D == m - m = Matrix(2,2,[0, 1, 1, 0]) + m = Matrix(2, 2, [0, 1, 1, 0]) assert m.is_symmetric() assert m.is_diagonalizable() (P, D) = m.diagonalize() assert P.inv() * m * P == D - m = Matrix(2,2,[1, 0, 0, 3]) + m = Matrix(2, 2, [1, 0, 0, 3]) assert m.is_symmetric() assert m.is_diagonalizable() (P, D) = m.diagonalize() @@ -1555,19 +1320,19 @@ assert P == eye(2) assert D == m - m = Matrix(2,2,[1, 1, 0, 0]) + m = Matrix(2, 2, [1, 1, 0, 0]) assert m.is_diagonalizable() (P, D) = m.diagonalize() assert P.inv() * m * P == D - m = Matrix(3,3,[1, 2, 0, 0, 3, 0, 2, -4, 2]) + m = Matrix(3, 3, [1, 2, 0, 0, 3, 0, 2, -4, 2]) assert m.is_diagonalizable() (P, D) = m.diagonalize() assert P.inv() * m * P == D for i in P: assert i.as_numer_denom()[1] == 1 - m = Matrix(2,2,[1, 0, 0, 0]) + m = Matrix(2, 2, [1, 0, 0, 0]) assert m.is_diagonal() assert m.is_diagonalizable() (P, D) = m.diagonalize() @@ -1575,7 +1340,7 @@ assert P == Matrix([[0, 1], [1, 0]]) # diagonalizable, complex only - m = Matrix(2,2,[0, 1, -1, 0]) + m = Matrix(2, 2, [0, 1, -1, 0]) assert not m.is_diagonalizable(True) raises(MatrixError, lambda: m.diagonalize(True)) assert m.is_diagonalizable() @@ -1583,23 +1348,24 @@ assert P.inv() * m * P == D # not diagonalizable - m = Matrix(2,2,[0, 1, 0, 0]) + m = Matrix(2, 2, [0, 1, 0, 0]) assert not m.is_diagonalizable() raises(MatrixError, lambda: m.diagonalize()) - m = Matrix(3,3,[-3, 1, -3, 20, 3, 10, 2, -2, 4]) + m = Matrix(3, 3, [-3, 1, -3, 20, 3, 10, 2, -2, 4]) assert not m.is_diagonalizable() raises(MatrixError, lambda: m.diagonalize()) # symbolic a, b, c, d = symbols('a b c d') - m = Matrix(2,2,[a, c, c, b]) + m = Matrix(2, 2, [a, c, c, b]) assert m.is_symmetric() assert m.is_diagonalizable() + @XFAIL def test_eigen_vects(): - m = Matrix(2,2,[1, 0, 0, I]) + m = Matrix(2, 2, [1, 0, 0, I]) raises(NotImplementedError, lambda: m.is_diagonalizable(True)) # !!! bug because of eigenvects() or roots(x**2 + (-1 - I)*x + I, x) # see issue 2193 @@ -1607,9 +1373,10 @@ raises(MatrixError, lambda: m.diagonalize(True)) (P, D) = m.diagonalize(True) + def test_jordan_form(): - m = Matrix(3,2,[-3, 1, -3, 20, 3, 10]) + m = Matrix(3, 2, [-3, 1, -3, 20, 3, 10]) raises(NonSquareMatrixError, lambda: m.jordan_form()) # diagonalizable @@ -1662,16 +1429,17 @@ (P, J) = m.jordan_form() assert Jmust == J + def test_Matrix_berkowitz_charpoly(): - x, UA, K_i, K_w = symbols('x UA K_i K_w') + UA, K_i, K_w = symbols('UA K_i K_w') - A = Matrix([[-K_i - UA + K_i**2/(K_i + K_w), K_i*K_w/(K_i + K_w)], + A = Matrix([[-K_i - UA + K_i**2/(K_i + K_w), K_i*K_w/(K_i + K_w)], [ K_i*K_w/(K_i + K_w), -K_w + K_w**2/(K_i + K_w)]]) charpoly = A.berkowitz_charpoly(x) assert charpoly == \ - Poly(x**2 + (K_i*UA + K_w*UA + 2*K_i*K_w)/(K_i + K_w)*x + \ + Poly(x**2 + (K_i*UA + K_w*UA + 2*K_i*K_w)/(K_i + K_w)*x + K_i*K_w*UA/(K_i + K_w), x, domain='ZZ(K_i,K_w,UA)') assert type(charpoly) is PurePoly @@ -1680,62 +1448,54 @@ assert A.charpoly() == A.charpoly(x) == PurePoly(x**2 - x - 6) -def test_exp(): - m = Matrix([[3,4],[0,-2]]) - assert m.exp() == Matrix([[exp(3),-4*exp(-2)/5 + 4*exp(3)/5],[0,exp(-2)]]) - m = Matrix([[1,0],[0,1]]) - assert m.exp() == Matrix([[E,0],[0,E]]) +def test_exp(): + m = Matrix([[3, 4], [0, -2]]) + assert m.exp() == \ + Matrix([[exp(3), -4*exp(-2)/5 + 4*exp(3)/5], [0, exp(-2)]]) -def test_SparseMatrix_transpose(): - assert SparseMatrix(((1,2),(3,4))).transpose() == Matrix(((1,3),(2,4))) + m = Matrix([[1, 0], [0, 1]]) + assert m.exp() == Matrix([[E, 0], [0, E]]) -def test_SparseMatrix_CL_RL(): - assert SparseMatrix(((1,2),(3,4))).row_list() == \ - [(0, 0, 1), (0, 1, 2), (1, 0, 3), (1, 1, 4)] - assert SparseMatrix(((1,2),(3,4))).col_list() == \ - [(0, 0, 1), (1, 0, 3), (0, 1, 2), (1, 1, 4)] - -def test_SparseMatrix_add(): - assert SparseMatrix(((1,0), (0,1))) + SparseMatrix(((0,1), (1,0))) == \ - SparseMatrix(((1,1), (1,1))) - a = SparseMatrix(100, 100, lambda i, j: int(j != 0 and i % j == 0)) - b = SparseMatrix(100, 100, lambda i, j: int(i != 0 and j % i == 0)) - assert (len(a.mat) + len(b.mat) - len((a+b).mat) > 0) def test_has(): - x, y, z = symbols('x,y,z') - A = Matrix(((x,y),(2,3))) + A = Matrix(((x, y), (2, 3))) assert A.has(x) assert not A.has(z) assert A.has(Symbol) - A = A.subs(x,2) + A = A.subs(x, 2) assert not A.has(x) + def test_errors(): # Note, some errors not tested. See 'XXX' in code. raises(ValueError, lambda: Matrix([[1, 2], [1]])) raises(IndexError, lambda: Matrix([[1, 2]])[1.2, 5]) raises(IndexError, lambda: Matrix([[1, 2]])[1, 5.2]) raises(ValueError, lambda: randMatrix(3, c=4, symmetric=True)) - raises(IndexError, lambda: Matrix([1, 2]).slice2bounds('a', 4)) raises(ValueError, lambda: Matrix([1, 2]).reshape(4, 6)) raises(ShapeError, lambda: Matrix([[1, 2], [3, 4]]).copyin_matrix([1, 0], Matrix([1, 2]))) - raises(TypeError, lambda: Matrix([[1, 2], [3, 4]]).copyin_list([0, 1], set([]))) + raises(TypeError, lambda: Matrix([[1, 2], [3, 4]]).copyin_list([0, + 1], set([]))) raises(NonSquareMatrixError, lambda: Matrix([[1, 2, 3], [2, 3, 0]]).inv()) raises(ShapeError, lambda: Matrix(1, 2, [1, 2]).row_join(Matrix([[1, 2], [3, 4]]))) - raises(ShapeError, lambda: Matrix([1, 2]).col_join(Matrix([[1, 2], [3, 4]]))) - raises(ShapeError, lambda: Matrix([1]).row_insert(1, Matrix([[1, 2], [3, 4]]))) - raises(ShapeError, lambda: Matrix([1]).col_insert(1, Matrix([[1, 2], [3, 4]]))) + raises( + ShapeError, lambda: Matrix([1, 2]).col_join(Matrix([[1, 2], [3, 4]]))) + raises(ShapeError, lambda: Matrix([1]).row_insert(1, Matrix([[1, + 2], [3, 4]]))) + raises(ShapeError, lambda: Matrix([1]).col_insert(1, Matrix([[1, + 2], [3, 4]]))) raises(NonSquareMatrixError, lambda: Matrix([1, 2]).trace()) raises(TypeError, lambda: Matrix([1]).applyfunc(1)) raises(ShapeError, lambda: Matrix([1]).LUsolve(Matrix([[1, 2], [3, 4]]))) - raises(MatrixError, lambda: Matrix([[1,2,3],[4,5,6],[7,8,9]]).QRdecomposition()) + raises(MatrixError, lambda: Matrix([[1, 2, 3], [4, 5, 6], [7, 8, 9] + ]).QRdecomposition()) raises(MatrixError, lambda: Matrix(1, 2, [1, 2]).QRdecomposition()) - raises(NonSquareMatrixError, lambda: Matrix([1, 2]).LUdecomposition_Simple()) + raises( + NonSquareMatrixError, lambda: Matrix([1, 2]).LUdecomposition_Simple()) raises(ValueError, lambda: Matrix([[1, 2], [3, 4]]).minorEntry(4, 5)) raises(ValueError, lambda: Matrix([[1, 2], [3, 4]]).minorMatrix(4, 5)) raises(TypeError, lambda: Matrix([1, 2, 3]).cross(1)) @@ -1743,7 +1503,8 @@ raises(ShapeError, lambda: Matrix([1, 2, 3]).dot(Matrix([1, 2]))) raises(ShapeError, lambda: Matrix([1, 2]).dot([])) raises(TypeError, lambda: Matrix([1, 2]).dot('a')) - raises(NotImplementedError, lambda: Matrix([[0,1,2],[0,0,-1], [0,0,0]]).exp()) + raises(NotImplementedError, lambda: Matrix([[0, 1, 2], [0, 0, -1], + [0, 0, 0]]).exp()) raises(NonSquareMatrixError, lambda: Matrix([1, 2, 3]).exp()) raises(ShapeError, lambda: Matrix([[1, 2], [3, 4]]).normalized()) raises(ValueError, lambda: Matrix([1, 2]).inv(method='not a method')) @@ -1752,8 +1513,8 @@ raises(NonSquareMatrixError, lambda: Matrix([1, 2]).inverse_ADJ()) raises(ValueError, lambda: Matrix([[1, 2], [1, 2]]).inverse_ADJ()) raises(NonSquareMatrixError, lambda: Matrix([1, 2]).inverse_LU()) - raises(NonSquareMatrixError, lambda: Matrix([1,2]).is_nilpotent()) - raises(NonSquareMatrixError, lambda: Matrix([1,2]).det()) + raises(NonSquareMatrixError, lambda: Matrix([1, 2]).is_nilpotent()) + raises(NonSquareMatrixError, lambda: Matrix([1, 2]).det()) raises(ValueError, lambda: Matrix([[1, 2], [3, 4]]).det(method='Not a real method')) raises(NonSquareMatrixError, lambda: Matrix([1, 2]).det_bareis()) @@ -1763,30 +1524,18 @@ lambda: hessian(Matrix([[1, 2], [3, 4]]), Matrix([[1, 2], [2, 1]]))) raises(ValueError, lambda: hessian(Matrix([[1, 2], [3, 4]]), [])) raises(ValueError, lambda: hessian(Symbol('x')**2, 'a')) - raises(TypeError, lambda: SparseMatrix(1.4, 2, lambda i, j: 0)) - raises(TypeError, lambda: SparseMatrix([1, 2, 3], [1, 2])) - raises(ValueError, lambda: SparseMatrix([[1, 2], [3, 4]])[(1, 2, 3)]) - raises(ValueError, lambda: SparseMatrix([[1, 2], [3, 4]]).rowdecomp(5)) - with raises(ValueError): - SparseMatrix([[1, 2], [3, 4]])[1, 2, 3] = 4 - raises(TypeError, - lambda: SparseMatrix([[1, 2], [3, 4]]).copyin_list([0, 1], set([]))) - raises(IndexError, lambda: SparseMatrix([[1, 2], [3, 4]]).submatrix((1, 2))) - raises(TypeError, lambda: SparseMatrix([1, 2, 3]).cross(1)) - raises(IndexError, lambda: SparseMatrix(1, 2, [1, 2])[3]) - raises(ShapeError, - lambda: SparseMatrix(1, 2, [1, 2]) + SparseMatrix(2, 1, [2, 1])) raises(ValueError, - lambda: Matrix([[5, 10, 7],[0, -1, 2],[8, 3, 4]] - ).LUdecomposition_Simple(iszerofunc=lambda x:abs(x)<=4)) - raises(NotImplementedError, lambda: Matrix([[1, 0],[1, 1]])**(S(1)/2)) + lambda: Matrix([[5, 10, 7], [0, -1, 2], [8, 3, 4]] + ).LUdecomposition_Simple(iszerofunc=lambda x: abs(x) <= 4)) + raises(NotImplementedError, lambda: Matrix([[1, 0], [1, 1]])**(S(1)/2)) raises(NotImplementedError, - lambda: Matrix([[1, 2, 3],[4, 5, 6],[7, 8, 9]])**(0.5)) - raises(IndexError, lambda: eye(3)[5,2]) - raises(IndexError, lambda: eye(3)[2,5]) - M = Matrix(((1,2,3,4),(5,6,7,8),(9,10,11,12),(13,14,15,16))) + lambda: Matrix([[1, 2, 3], [4, 5, 6], [7, 8, 9]])**(0.5)) + raises(IndexError, lambda: eye(3)[5, 2]) + raises(IndexError, lambda: eye(3)[2, 5]) + M = Matrix(((1, 2, 3, 4), (5, 6, 7, 8), (9, 10, 11, 12), (13, 14, 15, 16))) raises(ValueError, lambda: M.det('method=LU_decomposition()')) + def test_len(): assert len(Matrix()) == 0 assert len(Matrix([[1, 2]])) == len(Matrix([[1], [2]])) == 2 @@ -1796,103 +1545,101 @@ assert Matrix([1]) == Matrix([[1]]) assert not Matrix() assert Matrix() == Matrix([]) - assert not SparseMatrix() - assert SparseMatrix() == SparseMatrix([]) -@XFAIL -def test_len_different_shapes(): - assert Matrix() == Matrix([[]]) - assert SparseMatrix() == SparseMatrix([[]]) def test_integrate(): - x, y = symbols('x,y') - A = Matrix(((1,4,x),(y,2,4),(10,5,x**2))) + A = Matrix(((1, 4, x), (y, 2, 4), (10, 5, x**2))) assert A.integrate(x) == \ Matrix(((x, 4*x, x**2/2), (x*y, 2*x, 4*x), (10*x, 5*x, x**3/3))) assert A.integrate(y) == \ - Matrix(((y, 4*y, x*y),(y**2/2, 2*y, 4*y), (10*y, 5*y, y*x**2))) + Matrix(((y, 4*y, x*y), (y**2/2, 2*y, 4*y), (10*y, 5*y, y*x**2))) + def test_limit(): - x, y = symbols('x,y') - A = Matrix(((1,4,sin(x)/x),(y,2,4),(10,5,x**2+1))) - assert A.limit(x,0) == Matrix(((1,4,1),(y,2,4),(10,5,1))) + A = Matrix(((1, 4, sin(x)/x), (y, 2, 4), (10, 5, x**2 + 1))) + assert A.limit(x, 0) == Matrix(((1, 4, 1), (y, 2, 4), (10, 5, 1))) + def test_diff(): - x, y = symbols('x,y') - A = Matrix(((1,4,x),(y,2,4),(10,5,x**2+1))) - assert A.diff(x) == Matrix(((0,0,1),(0,0,0),(0,0,2*x))) - assert A.diff(y) == Matrix(((0,0,0),(1,0,0),(0,0,0))) + A = Matrix(((1, 4, x), (y, 2, 4), (10, 5, x**2 + 1))) + assert A.diff(x) == Matrix(((0, 0, 1), (0, 0, 0), (0, 0, 2*x))) + assert A.diff(y) == Matrix(((0, 0, 0), (1, 0, 0), (0, 0, 0))) + def test_getattr(): - x, y = symbols('x,y') - A = Matrix(((1,4,x),(y,2,4),(10,5,x**2+1))) - raises (AttributeError, lambda: A.nonexistantattribute) - assert getattr(A, 'diff')(x) == Matrix(((0,0,1),(0,0,0),(0,0,2*x))) + A = Matrix(((1, 4, x), (y, 2, 4), (10, 5, x**2 + 1))) + raises(AttributeError, lambda: A.nonexistantattribute) + assert getattr(A, 'diff')(x) == Matrix(((0, 0, 1), (0, 0, 0), (0, 0, 2*x))) + def test_hessenberg(): - A = Matrix([[3, 4, 1],[2, 4 ,5],[0, 1, 2]]) - assert A.is_upper_hessenberg() + A = Matrix([[3, 4, 1], [2, 4, 5], [0, 1, 2]]) + assert A.is_upper_hessenberg A = A.T - assert A.is_lower_hessenberg() + assert A.is_lower_hessenberg A[0, -1] = 1 - assert A.is_lower_hessenberg() is False + assert A.is_lower_hessenberg is False + + A = Matrix([[3, 4, 1], [2, 4, 5], [3, 1, 2]]) + assert not A.is_upper_hessenberg - A = Matrix([[3, 4, 1],[2, 4 ,5],[3, 1, 2]]) - assert not A.is_upper_hessenberg() def test_cholesky(): raises(NonSquareMatrixError, lambda: Matrix((1, 2)).cholesky()) raises(ValueError, lambda: Matrix(((1, 2), (3, 4))).cholesky()) - A = Matrix(((25,15,-5),(15,18,0),(-5,0,11))) + A = Matrix(((25, 15, -5), (15, 18, 0), (-5, 0, 11))) assert A.cholesky() * A.cholesky().T == A - assert A.cholesky().is_lower() + assert A.cholesky().is_lower assert A.cholesky() == Matrix([[5, 0, 0], [3, 3, 0], [-1, 1, 3]]) + def test_LDLdecomposition(): raises(NonSquareMatrixError, lambda: Matrix((1, 2)).LDLdecomposition()) raises(ValueError, lambda: Matrix(((1, 2), (3, 4))).LDLdecomposition()) - A = Matrix(((25,15,-5), (15,18,0), (-5,0,11))) + A = Matrix(((25, 15, -5), (15, 18, 0), (-5, 0, 11))) L, D = A.LDLdecomposition() assert L * D * L.T == A - assert L.is_lower() + assert L.is_lower assert L == Matrix([[1, 0, 0], [ S(3)/5, 1, 0], [S(-1)/5, S(1)/3, 1]]) assert D.is_diagonal() assert D == Matrix([[25, 0, 0], [0, 9, 0], [0, 0, 9]]) + def test_cholesky_solve(): - A = Matrix([[2,3,5], - [3,6,2], - [8,3,6]]) - x = Matrix(3,1,[3,7,5]) + A = Matrix([[2, 3, 5], + [3, 6, 2], + [8, 3, 6]]) + x = Matrix(3, 1, [3, 7, 5]) b = A*x soln = A.cholesky_solve(b) assert soln == x - A = Matrix([[0,-1,2], - [5,10,7], - [8,3,4]]) - x = Matrix(3,1,[-1,2,5]) + A = Matrix([[0, -1, 2], + [5, 10, 7], + [8, 3, 4]]) + x = Matrix(3, 1, [-1, 2, 5]) b = A*x soln = A.cholesky_solve(b) assert soln == x + def test_LDLsolve(): - A = Matrix([[2,3,5], - [3,6,2], - [8,3,6]]) - x = Matrix(3,1,[3,7,5]) + A = Matrix([[2, 3, 5], + [3, 6, 2], + [8, 3, 6]]) + x = Matrix(3, 1, [3, 7, 5]) b = A*x soln = A.LDLsolve(b) assert soln == x - A = Matrix([[0,-1,2], - [5,10,7], - [8,3,4]]) - x = Matrix(3,1,[-1,2,5]) + A = Matrix([[0, -1, 2], + [5, 10, 7], + [8, 3, 4]]) + x = Matrix(3, 1, [-1, 2, 5]) b = A*x soln = A.LDLsolve(b) assert soln == x + def test_lower_triangular_solve(): - x, y = symbols('x y') raises(NonSquareMatrixError, lambda: Matrix([1, 0]).lower_triangular_solve(Matrix([0, 1]))) @@ -1900,17 +1647,17 @@ lambda: Matrix([[1, 0], [0, 1]]).lower_triangular_solve(Matrix([1]))) raises(ValueError, lambda: Matrix([[2, 1], [1, 2]]).lower_triangular_solve( - Matrix([[1, 0], [0, 1]]))) + Matrix([[1, 0], [0, 1]]))) A = Matrix([[1, 0], [0, 1]]) B = Matrix([[x, y], [y, x]]) C = Matrix([[4, 8], [2, 9]]) - assert A.lower_triangular_solve(B) == Matrix([x, y]) - assert A.lower_triangular_solve(C) == Matrix([4, 2]) + assert A.lower_triangular_solve(B) == B + assert A.lower_triangular_solve(C) == C + def test_upper_triangular_solve(): - x, y = symbols('x y') raises(NonSquareMatrixError, lambda: Matrix([1, 0]).upper_triangular_solve(Matrix([0, 1]))) @@ -1918,17 +1665,22 @@ lambda: Matrix([[1, 0], [0, 1]]).upper_triangular_solve(Matrix([1]))) raises(TypeError, lambda: Matrix([[2, 1], [1, 2]]).upper_triangular_solve( - Matrix([[1, 0], [0, 1]]))) + Matrix([[1, 0], [0, 1]]))) A = Matrix([[1, 0], [0, 1]]) B = Matrix([[x, y], [y, x]]) C = Matrix([[2, 4], [3, 8]]) - assert A.upper_triangular_solve(B) == Matrix([x, y]) - assert A.upper_triangular_solve(C) == Matrix([2, 3]) + assert A.upper_triangular_solve(B) == B + assert A.upper_triangular_solve(C) == C + def test_diagonal_solve(): raises(TypeError, lambda: Matrix([1, 1]).diagonal_solve(Matrix([1]))) + A = Matrix([[1, 0], [0, 1]])*2 + B = Matrix([[x, y], [y, x]]) + assert A.diagonal_solve(B) == B/2 + def test_matrix_norm(): # Vector Tests @@ -1939,27 +1691,26 @@ assert v.norm(10) == Pow(cos(x)**10 + sin(x)**10, S(1)/10) # Test Rows - y = Matrix([[5, Rational(3,2)]]) - assert y.norm() == Pow(25 + Rational(9,4),S(1)/2) - assert y.norm(oo) == max(y.mat) - assert y.norm(-oo) == min(y.mat) + A = Matrix([[5, Rational(3, 2)]]) + assert A.norm() == Pow(25 + Rational(9, 4), S(1)/2) + assert A.norm(oo) == max(A._mat) + assert A.norm(-oo) == min(A._mat) # Matrix Tests # Intuitive test - A = Matrix([[1,1], [1,1]]) - assert A.norm(2)==2 - assert A.norm(-2)==0 - assert A.norm('frobenius')==2 - assert eye(10).norm(2)==eye(10).norm(-2)==1 + A = Matrix([[1, 1], [1, 1]]) + assert A.norm(2) == 2 + assert A.norm(-2) == 0 + assert A.norm('frobenius') == 2 + assert eye(10).norm(2) == eye(10).norm(-2) == 1 # Test with Symbols and more complex entries - y = Symbol('y') - A = Matrix([[3,y,y],[x,S(1)/2, -pi]]) + A = Matrix([[3, y, y], [x, S(1)/2, -pi]]) assert (A.norm('fro') == sqrt(S(37)/4 + 2*abs(y)**2 + pi**2 + x**2)) # Check non-square - A = Matrix([[1,2,-3],[4,5,Rational(13,2)]]) + A = Matrix([[1, 2, -3], [4, 5, Rational(13, 2)]]) assert A.norm(2) == sqrt(S(389)/8 + sqrt(78665)/8) assert A.norm(-2) == S(0) assert A.norm('frobenius') == sqrt(389)/2 @@ -1967,11 +1718,11 @@ # Test properties of matrix norms # http://en.wikipedia.org/wiki/Matrix_norm#Definition # Two matrices - A = Matrix([[1,2],[3,4]]) - B = Matrix([[5,5],[-2,2]]) - C = Matrix([[0,-I],[I,0]]) - D = Matrix([[1,0],[0,-1]]) - L = [A,B,C,D] + A = Matrix([[1, 2], [3, 4]]) + B = Matrix([[5, 5], [-2, 2]]) + C = Matrix([[0, -I], [I, 0]]) + D = Matrix([[1, 0], [0, -1]]) + L = [A, B, C, D] alpha = Symbol('alpha', real=True) for order in ['fro', 2, -2]: @@ -1980,81 +1731,86 @@ # Check Triangle Inequality for all Pairs of Matrices for X in L: for Y in L: - assert X.norm(order)+Y.norm(order) >= (X+Y).norm(order) + assert X.norm(order) + Y.norm(order) >= (X + Y).norm(order) # Scalar multiplication linearity - for M in [A,B,C,D]: - if order in [2,-2]: + for M in [A, B, C, D]: + if order in [2, -2]: # Abs is causing tests to fail when Abs(alpha) is inside a Max # or Min. The tests produce mathematically true statements that # are too complex to be simplified well. - continue; + continue try: assert ((alpha*M).norm(order) == abs(alpha) * M.norm(order)) except NotImplementedError: - pass; # Some Norms fail on symbolic matrices due to Max issue + pass # Some Norms fail on symbolic matrices due to Max issue # Test Properties of Vector Norms # http://en.wikipedia.org/wiki/Vector_norm # Two column vectors - a = Matrix([1,1-1*I,-3]) + a = Matrix([1, 1 - 1*I, -3]) b = Matrix([S(1)/2, 1*I, 1]) - c = Matrix([-1,-1,-1]) + c = Matrix([-1, -1, -1]) d = Matrix([3, 2, I]) - e = Matrix([Integer(1e2),Rational(1,1e2),1]) - L = [a,b,c,d,e] + e = Matrix([Integer(1e2), Rational(1, 1e2), 1]) + L = [a, b, c, d, e] alpha = Symbol('alpha', real=True) - for order in [1,2,-1, -2, S.Infinity, S.NegativeInfinity, pi]: + for order in [1, 2, -1, -2, S.Infinity, S.NegativeInfinity, pi]: # Zero Check - assert Matrix([0,0,0]).norm(order) == S(0) + if order > 0: + assert Matrix([0, 0, 0]).norm(order) == S(0) # Triangle inequality on all pairs - if order >= 1: # Triangle InEq holds only for these norms + if order >= 1: # Triangle InEq holds only for these norms for v in L: for w in L: - assert v.norm(order)+w.norm(order) >= (v+w).norm(order) + assert v.norm(order) + w.norm(order) >= (v + w).norm(order) # Linear to scalar multiplication - if order in [1,2, -1, -2, S.Infinity, S.NegativeInfinity]: + if order in [1, 2, -1, -2, S.Infinity, S.NegativeInfinity]: for vec in L: try: - assert simplify( (alpha*v).norm(order) - - (abs(alpha) * v.norm(order)) ) == 0 + assert simplify((alpha*v).norm(order) - + (abs(alpha) * v.norm(order))) == 0 except NotImplementedError: - pass; # Some Norms fail on symbolics due to Max issue + pass # Some Norms fail on symbolics due to Max issue def test_singular_values(): x = Symbol('x', real=True) - A = Matrix([[0,1*I],[2,0]]) - assert A.singular_values() == [2,1] + A = Matrix([[0, 1*I], [2, 0]]) + assert A.singular_values() == [2, 1] - A = eye(3); A[1,1] = x; A[2,2] = 5 - vals = A.singular_values(); + A = eye(3) + A[1, 1] = x + A[2, 2] = 5 + vals = A.singular_values() assert 1 in vals and 5 in vals and abs(x) in vals - A = Matrix([[sin(x), cos(x)],[-cos(x), sin(x)]]) + A = Matrix([[sin(x), cos(x)], [-cos(x), sin(x)]]) vals = [sv.trigsimp() for sv in A.singular_values()] assert vals == [S(1), S(1)] + def test_condition_number(): x = Symbol('x', real=True) - A = eye(3); - A[0,0] = 10; - A[2,2] = S(1)/10; + A = eye(3) + A[0, 0] = 10 + A[2, 2] = S(1)/10 assert A.condition_number() == 100 - A[1,1] = x - assert A.condition_number() == Max(10, Abs(x)) / Min(S(1)/10 , Abs(x)) + A[1, 1] = x + assert A.condition_number() == Max(10, Abs(x)) / Min(S(1)/10, Abs(x)) M = Matrix([[cos(x), sin(x)], [-sin(x), cos(x)]]) Mc = M.condition_number() - assert all(Float(1.).epsilon_eq(Mc.subs(x, val).evalf()) for val in \ - [Rational(1,5), Rational(1, 2), Rational(1, 10), pi/2, pi, 7*pi/4 ]) + assert all(Float(1.).epsilon_eq(Mc.subs(x, val).evalf()) for val in + [Rational(1, 5), Rational(1, 2), Rational(1, 10), pi/2, pi, 7*pi/4 ]) + def test_equality(): - A = Matrix(((1,2,3),(4,5,6),(7,8,9))) - B = Matrix(((9,8,7),(6,5,4),(3,2,1))) + A = Matrix(((1, 2, 3), (4, 5, 6), (7, 8, 9))) + B = Matrix(((9, 8, 7), (6, 5, 4), (3, 2, 1))) assert A == A[:, :] assert not A != A[:, :] assert not A == B @@ -2063,56 +1819,73 @@ assert not A == 10 # A SparseMatrix can be equal to a Matrix - C = SparseMatrix(((1,0,0),(0,1,0),(0,0,1))) - D = Matrix(((1,0,0),(0,1,0),(0,0,1))) + C = SparseMatrix(((1, 0, 0), (0, 1, 0), (0, 0, 1))) + D = Matrix(((1, 0, 0), (0, 1, 0), (0, 0, 1))) assert C == D assert not C != D + def test_col_join(): - assert eye(3).col_join(Matrix([[7,7,7]])) == \ - Matrix([[1,0,0], - [0,1,0], - [0,0,1], - [7,7,7]]) + assert eye(3).col_join(Matrix([[7, 7, 7]])) == \ + Matrix([[1, 0, 0], + [0, 1, 0], + [0, 0, 1], + [7, 7, 7]]) + def test_row_insert(): r4 = Matrix([[4, 4, 4]]) for i in range(-4, 5): - l=[1,0,0] - l.insert(i,4) + l = [1, 0, 0] + l.insert(i, 4) assert flatten(eye(3).row_insert(i, r4).col(0).tolist()) == l + def test_col_insert(): c4 = Matrix([4, 4, 4]) for i in range(-4, 5): - l=[0,0,0] - l.insert(i,4) + l = [0, 0, 0] + l.insert(i, 4) assert flatten(zeros(3).col_insert(i, c4).row(0).tolist()) == l + def test_normalized(): - assert Matrix([3,4]).normalized() == \ + assert Matrix([3, 4]).normalized() == \ Matrix([Rational(3, 5), Rational(4, 5)]) + def test_print_nonzero(): - assert capture(lambda:eye(3).print_nonzero()) == \ - '[X ]\n[ X ]\n[ X]\n' - assert capture(lambda:eye(3).print_nonzero('.')) == \ - '[. ]\n[ . ]\n[ .]\n' + assert capture(lambda: eye(3).print_nonzero()) == \ + '[X ]\n[ X ]\n[ X]\n' + assert capture(lambda: eye(3).print_nonzero('.')) == \ + '[. ]\n[ . ]\n[ .]\n' + def test_zeros_eye(): assert Matrix.eye(3) == eye(3) - assert SparseMatrix.eye(3) == eye(3, cls=SparseMatrix) assert Matrix.zeros(3) == zeros(3) - assert SparseMatrix.zeros(3) == zeros(3, cls=SparseMatrix) - # ones doesn't have a cls argument since it is, by definition, never Sparse assert ones(3, 4) == Matrix(3, 4, [1]*12) + i = Matrix([[1, 0], [0, 1]]) + z = Matrix([[0, 0], [0, 0]]) + for cls in classes: + m = cls.eye(2) + assert i == m # but m == i will fail if m is immutable + assert i == eye(2, cls=cls) + assert type(m) == cls + m = cls.zeros(2) + assert z == m + assert z == zeros(2, cls=cls) + assert type(m) == cls + + def test_is_zero(): assert Matrix().is_zero assert Matrix([[0, 0], [0, 0]]).is_zero assert zeros(3, 4).is_zero assert not eye(3).is_zero + def test_rotation_matrices(): # This tests the rotation matrices by rotating about an axis and back. theta = pi/3 @@ -2136,9 +1909,11 @@ assert rot_axis2(0) == eye(3) assert rot_axis3(0) == eye(3) + def test_DeferredVector(): - d = DeferredVector("vector") - assert str(d[4]) == "vector[4]" + assert str(DeferredVector("vector")[4]) == "vector[4]" + assert sympify(DeferredVector("d")) == DeferredVector("d") + def test_GramSchmidt(): R = Rational @@ -2146,27 +1921,64 @@ m2 = Matrix(1, 2, [2, 3]) assert GramSchmidt([m1, m2]) == \ [Matrix(1, 2, [1, 2]), Matrix(1, 2, [R(2)/5, R(-1)/5])] + assert GramSchmidt([m1.T, m2.T]) == \ + [Matrix(2, 1, [1, 2]), Matrix(2, 1, [R(2)/5, R(-1)/5])] + # from wikipedia + assert GramSchmidt([Matrix([3, 1]), Matrix([2, 2])], True) == [ + Matrix([3*sqrt(10)/10, sqrt(10)/10]), + Matrix([-sqrt(10)/10, 3*sqrt(10)/10])] + def test_casoratian(): assert casoratian([1, 2, 3, 4], 1) == 0 assert casoratian([1, 2, 3, 4], 1, zero=False) == 0 + def test_zero_dimension_multiply(): assert (Matrix()*zeros(0, 3)).shape == (0, 3) assert zeros(3, 0)*zeros(0, 3) == zeros(3, 3) assert zeros(0, 3)*zeros(3, 0) == Matrix() + def test_slice_issue_2884(): - m = Matrix(2,2,list(range(4))) - assert m[1,:] == Matrix([[2, 3]]) - assert m[-1,:] == Matrix([[2, 3]]) - assert m[:,1] == Matrix([[1, 3]]).T - assert m[:,-1] == Matrix([[1, 3]]).T - raises(IndexError, lambda: m[2,:]) - raises(IndexError, lambda: m[2,2]) + m = Matrix(2, 2, list(range(4))) + assert m[1, :] == Matrix([[2, 3]]) + assert m[-1, :] == Matrix([[2, 3]]) + assert m[:, 1] == Matrix([[1, 3]]).T + assert m[:, -1] == Matrix([[1, 3]]).T + raises(IndexError, lambda: m[2, :]) + raises(IndexError, lambda: m[2, 2]) + + +def test_slice_issue_3401(): + assert zeros(0, 3)[:, -1].shape == (0, 1) + assert zeros(3, 0)[0, :] == Matrix(1, 0, []) + + +def test_copyin(): + s = zeros(3, 3) + s[3] = 1 + assert s[:, 0] == Matrix([0, 1, 0]) + assert s[3] == 1 + assert s[3: 4] == [1] + s[1, 1] = 42 + assert s[1, 1] == 42 + assert s[1, 1:] == Matrix([[42, 0]]) + s[1, 1:] = Matrix([[5, 6]]) + assert s[1, :] == Matrix([[1, 5, 6]]) + s[1, 1:] = [[42, 43]] + assert s[1, :] == Matrix([[1, 42, 43]]) + s[0, 0] = 17 + assert s[:, :1] == Matrix([17, 1, 0]) + s[0, 0] = [1, 1, 1] + assert s[:, 0] == Matrix([1, 1, 1]) + s[0, 0] = Matrix([1, 1, 1]) + assert s[:, 0] == Matrix([1, 1, 1]) + s[0, 0] = SparseMatrix([1, 1, 1]) + assert s[:, 0] == Matrix([1, 1, 1]) + def test_invertible_check(): - x = symbols('x') # sometimes a singular matrix will have a pivot vector shorter than # the number of rows in a matrix... assert Matrix([[1, 2], [1, 2]]).rref() == (Matrix([[1, 2], [0, 0]]), [0]) @@ -2174,9 +1986,10 @@ # ... but sometimes it won't, so that is an insufficient test of # whether something is invertible. m = Matrix([ - [-1, -1, 0], - [ x, 1, 1], - [ 1, x, -1],]) + [-1, -1, 0], + [ x, 1, 1], + [ 1, x, -1], + ]) assert len(m.rref()[1]) == m.rows # in addition, unless simplify=True in the call to rref, the identity # matrix will be returned even though m is not invertible @@ -2186,18 +1999,18 @@ raises(ValueError, lambda: m.inv(method="GE")) raises(ValueError, lambda: m.inv(method="LU")) + @XFAIL def test_issue_860(): - x, y=symbols('x, y') + x, y = symbols('x, y') e = x*y assert e.subs(x, Matrix([3, 5, 3])) == Matrix([3, 5, 3])*y + @XFAIL -def test_issue_2865() : +def test_issue_2865(): assert str(Matrix([[1, 2], [3, 4]])) == 'Matrix([[1, 2], [3, 4]])' -def test_DeferredVector(): - assert sympify(DeferredVector("d")) == DeferredVector("d") def test_is_Identity(): assert eye(3).is_Identity @@ -2205,43 +2018,37 @@ assert not zeros(3).is_Identity assert not ones(3).is_Identity # issue 3143 - assert not Matrix([[1,0,0]]).is_Identity + assert not Matrix([[1, 0, 0]]).is_Identity + def test_dot(): - assert ones(1,3).dot(ones(3,1)) == 3 - assert ones(1,3).dot([1,1,1]) == 3 + assert ones(1, 3).dot(ones(3, 1)) == 3 + assert ones(1, 3).dot([1, 1, 1]) == 3 -def test_simplify(): - from sympy.abc import x - m = Matrix([[1, x], [x + 1/x, x - 1]]) - m = m.row_join(eye(m.cols)) - raw = m.rref(simplify=lambda x: x)[0] - assert raw != \ - m.rref(simplify=True)[0] def test_dual(): - B_x, B_y, B_z, E_x, E_y, E_z = symbols('B_x B_y B_z E_x E_y E_z',real=True) - F = Matrix(( - (0,E_x,E_y,E_z), - (-E_x,0,B_z,-B_y), - (-E_y,-B_z,0,B_x), - (-E_z,B_y,-B_x,0) + B_x, B_y, B_z, E_x, E_y, E_z = symbols( + 'B_x B_y B_z E_x E_y E_z', real=True) + F = Matrix(( + ( 0, E_x, E_y, E_z), + (-E_x, 0, B_z, -B_y), + (-E_y, -B_z, 0, B_x), + (-E_z, B_y, -B_x, 0) + )) + Fd = Matrix(( + ( 0, -B_x, -B_y, -B_z), + (B_x, 0, E_z, -E_y), + (B_y, -E_z, 0, E_x), + (B_z, E_y, -E_x, 0) )) - Fd = Matrix( ( - (0,-B_x,-B_y,-B_z), - (B_x,0,E_z,-E_y), - (B_y,-E_z,0,E_x), - (B_z,E_y,-E_x,0)) ) assert F.dual().equals(Fd) assert eye(3).dual().equals(zeros(3)) assert F.dual().dual().equals(-F) + def test_anti_symmetric(): - x, y = symbols('x y') assert Matrix([1, 2]).is_anti_symmetric() is False - m = Matrix(3, 3, [0, x**2 + 2*x + 1, y, - -(x + 1)**2 , 0, x*y, - -y, -x*y, 0]) + m = Matrix(3, 3, [0, x**2 + 2*x + 1, y, -(x + 1)**2, 0, x*y, -y, -x*y, 0]) assert m.is_anti_symmetric() is True assert m.is_anti_symmetric(simplify=False) is False assert m.is_anti_symmetric(simplify=lambda x: x) is False @@ -2256,3 +2063,106 @@ assert m.is_anti_symmetric(simplify=False) is True m[0, 0] = 1 assert m.is_anti_symmetric() is False + + +def test_normalize_sort_diogonalization(): + A = Matrix(((1, 2), (2, 1))) + P, Q = A.diagonalize(normalize=True) + assert P*P.T == P.T*P == eye(P.cols) + P, Q = A.diagonalize(normalize=True, sort=True) + assert P*P.T == P.T*P == eye(P.cols) + assert P*Q*P.inv() == A + + +def test_issue2222(): + raises(ValueError, lambda: Matrix([[1, 2, 3], Matrix(0, 1, [])])) + + +def test_issue2221(): + assert Matrix.hstack(eye(2), 2*eye(2)) == Matrix([ + [1, 0, 2, 0], + [0, 1, 0, 2] + ]) + assert Matrix.vstack(eye(2), 2*eye(2)) == Matrix([ + [1, 0], + [0, 1], + [2, 0], + [0, 2] + ]) + cls = SparseMatrix + assert cls.hstack(cls(eye(2)), cls(2*eye(2))) == Matrix([ + [1, 0, 2, 0], + [0, 1, 0, 2] + ]) + + +def test_cross(): + a = [1, 2, 3] + b = [3, 4, 5] + ans = Matrix([-2, 4, -2]).T + + def test(M): + assert ans == M + assert type(M) == cls + for cls in classes: + A = cls(a) + B = cls(b) + test(A.cross(B)) + test(A.T.cross(B)) + test(A.T.cross(B.T)) + test(A.cross(B.T)) + + +def test_hash(): + for cls in classes[-2:]: + s = set([cls.eye(1), cls.eye(1)]) + assert len(s) == 1 and s.pop() == cls.eye(1) + # issue 880 + for cls in classes[1:2]: + raises(AttributeError, lambda: hash(cls.eye(1))) + + +@XFAIL +def test_issue880(): + # when this passes, delete this and change the [1:2] + # to [:2] in the test_hash above for issue 880 + cls = classes[0] + raises(AttributeError, lambda: hash(cls.eye(1))) + + +def test_adjoint(): + dat = [[0, I], [1, 0]] + ans = Matrix([[0, 1], [-I, 0]]) + for cls in classes: + assert ans == cls(dat).adjoint() + +def test_simplify(): + from sympy import simplify, sin, cos + assert simplify(ImmutableMatrix([[sin(x)**2 + cos(x)**2]])) == \ + ImmutableMatrix([[1]]) + +def test_rank(): + from sympy.abc import x + m = Matrix([[1, 2], [x, 1 - 1/x]]) + assert m.rank() == 2 + n = Matrix(3, 3, list(range(1, 10))) + assert n.rank() == 2 + p = zeros(3) + assert p.rank() == 0 + +def test_replace(): + from sympy import symbols, Function, Matrix + F, G = symbols('F, G', cls=Function) + K = Matrix(2, 2, lambda i, j: G(i+j)) + M = Matrix(2, 2, lambda i, j: F(i+j)) + N = M.replace(F, G) + assert N == K + +def test_replace_map(): + from sympy import symbols, Function, Matrix + F, G = symbols('F, G', cls=Function) + K = Matrix(2, 2, [(G(0), {F(0): G(0)}), (G(1), {F(1): G(1)}), (G(1), {F(1)\ + : G(1)}), (G(2), {F(2): G(2)})]) + M = Matrix(2, 2, lambda i, j: F(i+j)) + N = M.replace(F, G, True) + assert N == K diff -Nru python3-sympy-0.7.2/sympy/matrices/tests/test_sparse.py python3-sympy-0.7.3/sympy/matrices/tests/test_sparse.py --- python3-sympy-0.7.2/sympy/matrices/tests/test_sparse.py 1970-01-01 00:00:00.000000000 +0000 +++ python3-sympy-0.7.3/sympy/matrices/tests/test_sparse.py 2013-07-13 17:53:32.000000000 +0000 @@ -0,0 +1,559 @@ +from sympy import S, Symbol, I, Rational, PurePoly +from sympy.matrices import Matrix, SparseMatrix, eye, zeros, ShapeError +from sympy.utilities.pytest import raises, XFAIL + + +def test_sparse_matrix(): + def sparse_eye(n): + return SparseMatrix.eye(n) + + def sparse_zeros(n): + return SparseMatrix.zeros(n) + + # creation args + raises(TypeError, lambda: SparseMatrix(1, 2)) + + a = SparseMatrix(( + (1, 0), + (0, 1) + )) + assert SparseMatrix(a) == a + + # test element assignment + a = SparseMatrix(( + (1, 0), + (0, 1) + )) + + a[3] = 4 + assert a[1, 1] == 4 + a[3] = 1 + + a[0, 0] = 2 + assert a == SparseMatrix(( + (2, 0), + (0, 1) + )) + a[1, 0] = 5 + assert a == SparseMatrix(( + (2, 0), + (5, 1) + )) + a[1, 1] = 0 + assert a == SparseMatrix(( + (2, 0), + (5, 0) + )) + assert a._smat == {(0, 0): 2, (1, 0): 5} + + # test_multiplication + a = SparseMatrix(( + (1, 2), + (3, 1), + (0, 6), + )) + + b = SparseMatrix(( + (1, 2), + (3, 0), + )) + + c = a*b + assert c[0, 0] == 7 + assert c[0, 1] == 2 + assert c[1, 0] == 6 + assert c[1, 1] == 6 + assert c[2, 0] == 18 + assert c[2, 1] == 0 + + x = Symbol("x") + + c = b * Symbol("x") + assert isinstance(c, SparseMatrix) + assert c[0, 0] == x + assert c[0, 1] == 2*x + assert c[1, 0] == 3*x + assert c[1, 1] == 0 + + c = 5 * b + assert isinstance(c, SparseMatrix) + assert c[0, 0] == 5 + assert c[0, 1] == 2*5 + assert c[1, 0] == 3*5 + assert c[1, 1] == 0 + + #test_power + A = SparseMatrix([[2, 3], [4, 5]]) + assert (A**5)[:] == [6140, 8097, 10796, 14237] + A = SparseMatrix([[2, 1, 3], [4, 2, 4], [6, 12, 1]]) + assert (A**3)[:] == [290, 262, 251, 448, 440, 368, 702, 954, 433] + + # test_creation + x = Symbol("x") + a = SparseMatrix([[x, 0], [0, 0]]) + m = a + assert m.cols == m.rows + assert m.cols == 2 + assert m[:] == [x, 0, 0, 0] + b = SparseMatrix(2, 2, [x, 0, 0, 0]) + m = b + assert m.cols == m.rows + assert m.cols == 2 + assert m[:] == [x, 0, 0, 0] + + assert a == b + S = sparse_eye(3) + S.row_del(1) + assert S == SparseMatrix([ + [1, 0, 0], + [0, 0, 1]]) + S = sparse_eye(3) + S.col_del(1) + assert S == SparseMatrix([ + [1, 0], + [0, 0], + [0, 1]]) + S = SparseMatrix.eye(3) + S[2, 1] = 2 + S.col_swap(1, 0) + assert S == SparseMatrix([ + [0, 1, 0], + [1, 0, 0], + [2, 0, 1]]) + + a = SparseMatrix(1, 2, [1, 2]) + b = a.copy() + c = a.copy() + assert a[0] == 1 + a.row_del(0) + assert a == SparseMatrix(0, 2, []) + b.col_del(1) + assert b == SparseMatrix(1, 1, [1]) + + # test_determinant + x, y = Symbol('x'), Symbol('y') + + assert SparseMatrix(1, 1, [0]).det() == 0 + + assert SparseMatrix([[1]]).det() == 1 + + assert SparseMatrix(((-3, 2), (8, -5))).det() == -1 + + assert SparseMatrix(((x, 1), (y, 2*y))).det() == 2*x*y - y + + assert SparseMatrix(( (1, 1, 1), + (1, 2, 3), + (1, 3, 6) )).det() == 1 + + assert SparseMatrix(( ( 3, -2, 0, 5), + (-2, 1, -2, 2), + ( 0, -2, 5, 0), + ( 5, 0, 3, 4) )).det() == -289 + + assert SparseMatrix(( ( 1, 2, 3, 4), + ( 5, 6, 7, 8), + ( 9, 10, 11, 12), + (13, 14, 15, 16) )).det() == 0 + + assert SparseMatrix(( (3, 2, 0, 0, 0), + (0, 3, 2, 0, 0), + (0, 0, 3, 2, 0), + (0, 0, 0, 3, 2), + (2, 0, 0, 0, 3) )).det() == 275 + + assert SparseMatrix(( (1, 0, 1, 2, 12), + (2, 0, 1, 1, 4), + (2, 1, 1, -1, 3), + (3, 2, -1, 1, 8), + (1, 1, 1, 0, 6) )).det() == -55 + + assert SparseMatrix(( (-5, 2, 3, 4, 5), + ( 1, -4, 3, 4, 5), + ( 1, 2, -3, 4, 5), + ( 1, 2, 3, -2, 5), + ( 1, 2, 3, 4, -1) )).det() == 11664 + + assert SparseMatrix(( ( 2, 7, -1, 3, 2), + ( 0, 0, 1, 0, 1), + (-2, 0, 7, 0, 2), + (-3, -2, 4, 5, 3), + ( 1, 0, 0, 0, 1) )).det() == 123 + + # test_submatrix + m0 = sparse_eye(4) + assert m0[:3, :3] == sparse_eye(3) + assert m0[2:4, 0:2] == sparse_zeros(2) + + m1 = SparseMatrix(3, 3, lambda i, j: i + j) + assert m1[0, :] == SparseMatrix(1, 3, (0, 1, 2)) + assert m1[1:3, 1] == SparseMatrix(2, 1, (2, 3)) + + m2 = SparseMatrix( + [[0, 1, 2, 3], [4, 5, 6, 7], [8, 9, 10, 11], [12, 13, 14, 15]]) + assert m2[:, -1] == SparseMatrix(4, 1, [3, 7, 11, 15]) + assert m2[-2:, :] == SparseMatrix([[8, 9, 10, 11], [12, 13, 14, 15]]) + + assert SparseMatrix([[1, 2], [3, 4]]).submatrix([1, 1]) == Matrix([[4]]) + + # test_submatrix_assignment + m = sparse_zeros(4) + m[2:4, 2:4] = sparse_eye(2) + assert m == SparseMatrix([(0, 0, 0, 0), + (0, 0, 0, 0), + (0, 0, 1, 0), + (0, 0, 0, 1)]) + assert len(m._smat) == 2 + m[:2, :2] = sparse_eye(2) + assert m == sparse_eye(4) + m[:, 0] = SparseMatrix(4, 1, (1, 2, 3, 4)) + assert m == SparseMatrix([(1, 0, 0, 0), + (2, 1, 0, 0), + (3, 0, 1, 0), + (4, 0, 0, 1)]) + m[:, :] = sparse_zeros(4) + assert m == sparse_zeros(4) + m[:, :] = ((1, 2, 3, 4), (5, 6, 7, 8), (9, 10, 11, 12), (13, 14, 15, 16)) + assert m == SparseMatrix((( 1, 2, 3, 4), + ( 5, 6, 7, 8), + ( 9, 10, 11, 12), + (13, 14, 15, 16))) + m[:2, 0] = [0, 0] + assert m == SparseMatrix((( 0, 2, 3, 4), + ( 0, 6, 7, 8), + ( 9, 10, 11, 12), + (13, 14, 15, 16))) + + # test_reshape + m0 = sparse_eye(3) + assert m0.reshape(1, 9) == SparseMatrix(1, 9, (1, 0, 0, 0, 1, 0, 0, 0, 1)) + m1 = SparseMatrix(3, 4, lambda i, j: i + j) + assert m1.reshape(4, 3) == \ + SparseMatrix([(0, 1, 2), (3, 1, 2), (3, 4, 2), (3, 4, 5)]) + assert m1.reshape(2, 6) == \ + SparseMatrix([(0, 1, 2, 3, 1, 2), (3, 4, 2, 3, 4, 5)]) + + # test_applyfunc + m0 = sparse_eye(3) + assert m0.applyfunc(lambda x: 2*x) == sparse_eye(3)*2 + assert m0.applyfunc(lambda x: 0 ) == sparse_zeros(3) + + # test_LUdecomp + testmat = SparseMatrix([[ 0, 2, 5, 3], + [ 3, 3, 7, 4], + [ 8, 4, 0, 2], + [-2, 6, 3, 4]]) + L, U, p = testmat.LUdecomposition() + assert L.is_lower + assert U.is_upper + assert (L*U).permuteBkwd(p) - testmat == sparse_zeros(4) + + testmat = SparseMatrix([[ 6, -2, 7, 4], + [ 0, 3, 6, 7], + [ 1, -2, 7, 4], + [-9, 2, 6, 3]]) + L, U, p = testmat.LUdecomposition() + assert L.is_lower + assert U.is_upper + assert (L*U).permuteBkwd(p) - testmat == sparse_zeros(4) + + x, y, z = Symbol('x'), Symbol('y'), Symbol('z') + M = Matrix(((1, x, 1), (2, y, 0), (y, 0, z))) + L, U, p = M.LUdecomposition() + assert L.is_lower + assert U.is_upper + assert (L*U).permuteBkwd(p) - M == sparse_zeros(3) + + # test_LUsolve + A = SparseMatrix([[2, 3, 5], + [3, 6, 2], + [8, 3, 6]]) + x = SparseMatrix(3, 1, [3, 7, 5]) + b = A*x + soln = A.LUsolve(b) + assert soln == x + A = SparseMatrix([[0, -1, 2], + [5, 10, 7], + [8, 3, 4]]) + x = SparseMatrix(3, 1, [-1, 2, 5]) + b = A*x + soln = A.LUsolve(b) + assert soln == x + + # test_inverse + A = sparse_eye(4) + assert A.inv() == sparse_eye(4) + assert A.inv(method="CH") == sparse_eye(4) + assert A.inv(method="LDL") == sparse_eye(4) + + A = SparseMatrix([[2, 3, 5], + [3, 6, 2], + [7, 2, 6]]) + Ainv = SparseMatrix(Matrix(A).inv()) + assert A*Ainv == sparse_eye(3) + assert A.inv(method="CH") == Ainv + assert A.inv(method="LDL") == Ainv + + A = SparseMatrix([[2, 3, 5], + [3, 6, 2], + [5, 2, 6]]) + Ainv = SparseMatrix(Matrix(A).inv()) + assert A*Ainv == sparse_eye(3) + assert A.inv(method="CH") == Ainv + assert A.inv(method="LDL") == Ainv + + # test_cross + v1 = Matrix(1, 3, [1, 2, 3]) + v2 = Matrix(1, 3, [3, 4, 5]) + assert v1.cross(v2) == Matrix(1, 3, [-2, 4, -2]) + assert v1.norm(2)**2 == 14 + + # conjugate + a = SparseMatrix(((1, 2 + I), (3, 4))) + assert a.C == SparseMatrix([ + [1, 2 - I], + [3, 4] + ]) + + # mul + assert a*Matrix(2, 2, [1, 0, 0, 1]) == a + assert a + Matrix(2, 2, [1, 1, 1, 1]) == SparseMatrix([ + [2, 3 + I], + [4, 5] + ]) + + # col join + assert a.col_join(sparse_eye(2)) == SparseMatrix([ + [1, 2 + I], + [3, 4], + [1, 0], + [0, 1] + ]) + + # symmetric + assert not a.is_symmetric(simplify=False) + + # test_cofactor + assert sparse_eye(3) == sparse_eye(3).cofactorMatrix() + test = SparseMatrix([[1, 3, 2], [2, 6, 3], [2, 3, 6]]) + assert test.cofactorMatrix() == \ + SparseMatrix([[27, -6, -6], [-12, 2, 3], [-3, 1, 0]]) + test = SparseMatrix([[1, 2, 3], [4, 5, 6], [7, 8, 9]]) + assert test.cofactorMatrix() == \ + SparseMatrix([[-3, 6, -3], [6, -12, 6], [-3, 6, -3]]) + + # test_jacobian + x = Symbol('x') + y = Symbol('y') + L = SparseMatrix(1, 2, [x**2*y, 2*y**2 + x*y]) + syms = [x, y] + assert L.jacobian(syms) == Matrix([[2*x*y, x**2], [y, 4*y + x]]) + + L = SparseMatrix(1, 2, [x, x**2*y**3]) + assert L.jacobian(syms) == SparseMatrix([[1, 0], [2*x*y**3, x**2*3*y**2]]) + + # test_QR + A = Matrix([[1, 2], [2, 3]]) + Q, S = A.QRdecomposition() + R = Rational + assert Q == Matrix([ + [ 5**R(-1, 2), (R(2)/5)*(R(1)/5)**R(-1, 2)], + [2*5**R(-1, 2), (-R(1)/5)*(R(1)/5)**R(-1, 2)]]) + assert S == Matrix([ + [5**R(1, 2), 8*5**R(-1, 2)], + [ 0, (R(1)/5)**R(1, 2)]]) + assert Q*S == A + assert Q.T * Q == sparse_eye(2) + + R = Rational + # test nullspace + # first test reduced row-ech form + + M = SparseMatrix([[5, 7, 2, 1], + [1, 6, 2, -1]]) + out, tmp = M.rref() + assert out == Matrix([[1, 0, -R(2)/23, R(13)/23], + [0, 1, R(8)/23, R(-6)/23]]) + + M = SparseMatrix([[ 1, 3, 0, 2, 6, 3, 1], + [-2, -6, 0, -2, -8, 3, 1], + [ 3, 9, 0, 0, 6, 6, 2], + [-1, -3, 0, 1, 0, 9, 3]]) + + out, tmp = M.rref() + assert out == Matrix([[1, 3, 0, 0, 2, 0, 0], + [0, 0, 0, 1, 2, 0, 0], + [0, 0, 0, 0, 0, 1, R(1)/3], + [0, 0, 0, 0, 0, 0, 0]]) + # now check the vectors + basis = M.nullspace() + assert basis[0] == Matrix([-3, 1, 0, 0, 0, 0, 0]) + assert basis[1] == Matrix([0, 0, 1, 0, 0, 0, 0]) + assert basis[2] == Matrix([-2, 0, 0, -2, 1, 0, 0]) + assert basis[3] == Matrix([0, 0, 0, 0, 0, R(-1)/3, 1]) + + # test eigen + x = Symbol('x') + y = Symbol('y') + sparse_eye3 = sparse_eye(3) + assert sparse_eye3.charpoly(x) == PurePoly(((x - 1)**3)) + assert sparse_eye3.charpoly(y) == PurePoly(((y - 1)**3)) + + # test values + M = Matrix([( 0, 1, -1), + ( 1, 1, 0), + (-1, 0, 1)]) + vals = M.eigenvals() + assert sorted(vals.keys()) == [-1, 1, 2] + + R = Rational + M = Matrix([[1, 0, 0], + [0, 1, 0], + [0, 0, 1]]) + assert M.eigenvects() == [(1, 3, [ + Matrix([1, 0, 0]), + Matrix([0, 1, 0]), + Matrix([0, 0, 1])])] + M = Matrix([[5, 0, 2], + [3, 2, 0], + [0, 0, 1]]) + assert M.eigenvects() == [(1, 1, [Matrix([R(-1)/2, R(3)/2, 1])]), + (2, 1, [Matrix([0, 1, 0])]), + (5, 1, [Matrix([1, 1, 0])])] + + assert M.zeros(3, 5) == SparseMatrix(3, 5, {}) + A = SparseMatrix(10, 10, {(0, 0): 18, (0, 9): 12, (1, 4): 18, (2, 7): 16, (3, 9): 12, (4, 2): 19, (5, 7): 16, (6, 2): 12, (9, 7): 18}) + assert A.row_list() == [(0, 0, 18), (0, 9, 12), (1, 4, 18), (2, 7, 16), (3, 9, 12), (4, 2, 19), (5, 7, 16), (6, 2, 12), (9, 7, 18)] + assert A.col_list() == [(0, 0, 18), (4, 2, 19), (6, 2, 12), (1, 4, 18), (2, 7, 16), (5, 7, 16), (9, 7, 18), (0, 9, 12), (3, 9, 12)] + assert SparseMatrix.eye(2).nnz() == 2 + + +def test_transpose(): + assert SparseMatrix(((1, 2), (3, 4))).transpose() == \ + SparseMatrix(((1, 3), (2, 4))) + + +def test_trace(): + assert SparseMatrix(((1, 2), (3, 4))).trace() == 5 + assert SparseMatrix(((0, 0), (0, 4))).trace() == 4 + + +def test_CL_RL(): + assert SparseMatrix(((1, 2), (3, 4))).row_list() == \ + [(0, 0, 1), (0, 1, 2), (1, 0, 3), (1, 1, 4)] + assert SparseMatrix(((1, 2), (3, 4))).col_list() == \ + [(0, 0, 1), (1, 0, 3), (0, 1, 2), (1, 1, 4)] + + +def test_add(): + assert SparseMatrix(((1, 0), (0, 1))) + SparseMatrix(((0, 1), (1, 0))) == \ + SparseMatrix(((1, 1), (1, 1))) + a = SparseMatrix(100, 100, lambda i, j: int(j != 0 and i % j == 0)) + b = SparseMatrix(100, 100, lambda i, j: int(i != 0 and j % i == 0)) + assert (len(a._smat) + len(b._smat) - len((a + b)._smat) > 0) + + +def test_errors(): + raises(ValueError, lambda: SparseMatrix(1.4, 2, lambda i, j: 0)) + raises(TypeError, lambda: SparseMatrix([1, 2, 3], [1, 2])) + raises(ValueError, lambda: SparseMatrix([[1, 2], [3, 4]])[(1, 2, 3)]) + raises(IndexError, lambda: SparseMatrix([[1, 2], [3, 4]])[5]) + raises(ValueError, lambda: SparseMatrix([[1, 2], [3, 4]])[1, 2, 3]) + raises(TypeError, + lambda: SparseMatrix([[1, 2], [3, 4]]).copyin_list([0, 1], set([]))) + raises( + IndexError, lambda: SparseMatrix([[1, 2], [3, 4]]).submatrix((1, 2))) + raises(TypeError, lambda: SparseMatrix([1, 2, 3]).cross(1)) + raises(IndexError, lambda: SparseMatrix(1, 2, [1, 2])[3]) + raises(ShapeError, + lambda: SparseMatrix(1, 2, [1, 2]) + SparseMatrix(2, 1, [2, 1])) + + +def test_len(): + assert not SparseMatrix() + assert SparseMatrix() == SparseMatrix([]) + + +@XFAIL +def test_len_different_shapes(): + assert Matrix() == Matrix([[]]) + assert SparseMatrix() == SparseMatrix([[]]) + + +def test_sparse_zeros_sparse_eye(): + assert SparseMatrix.eye(3) == eye(3, cls=SparseMatrix) + assert len(SparseMatrix.eye(3)._smat) == 3 + assert SparseMatrix.zeros(3) == zeros(3, cls=SparseMatrix) + assert len(SparseMatrix.zeros(3)._smat) == 0 + + +def test_copyin(): + s = SparseMatrix(3, 3, {}) + s[1, 0] = 1 + assert s[:, 0] == SparseMatrix(Matrix([0, 1, 0])) + assert s[3] == 1 + assert s[3: 4] == [1] + s[1, 1] = 42 + assert s[1, 1] == 42 + assert s[1, 1:] == SparseMatrix([[42, 0]]) + s[1, 1:] = Matrix([[5, 6]]) + assert s[1, :] == SparseMatrix([[1, 5, 6]]) + s[1, 1:] = [[42, 43]] + assert s[1, :] == SparseMatrix([[1, 42, 43]]) + s[0, 0] = 17 + assert s[:, :1] == SparseMatrix([17, 1, 0]) + s[0, 0] = [1, 1, 1] + assert s[:, 0] == SparseMatrix([1, 1, 1]) + s[0, 0] = Matrix([1, 1, 1]) + assert s[:, 0] == SparseMatrix([1, 1, 1]) + s[0, 0] = SparseMatrix([1, 1, 1]) + assert s[:, 0] == SparseMatrix([1, 1, 1]) + + +def test_sparse_solve(): + from sympy.matrices import SparseMatrix + A = SparseMatrix(((25, 15, -5), (15, 18, 0), (-5, 0, 11))) + assert A.cholesky() == Matrix([ + [ 5, 0, 0], + [ 3, 3, 0], + [-1, 1, 3]]) + assert A.cholesky() * A.cholesky().T == Matrix([ + [25, 15, -5], + [15, 18, 0], + [-5, 0, 11]]) + + A = SparseMatrix(((25, 15, -5), (15, 18, 0), (-5, 0, 11))) + L, D = A.LDLdecomposition() + assert 15*L == Matrix([ + [15, 0, 0], + [ 9, 15, 0], + [-3, 5, 15]]) + assert D == Matrix([ + [25, 0, 0], + [ 0, 9, 0], + [ 0, 0, 9]]) + assert L * D * L.T == A + + A = SparseMatrix(((3, 0, 2), (0, 0, 1), (1, 2, 0))) + assert A.inv() * A == SparseMatrix(eye(3)) + + A = SparseMatrix([ + [ 2, -1, 0], + [-1, 2, -1], + [ 0, 0, 2]]) + ans = SparseMatrix([ + [S(2)/3, S(1)/3, S(1)/6], + [S(1)/3, S(2)/3, S(1)/3], + [ 0, 0, S(1)/2]]) + assert A.inv(method='CH') == ans + assert A.inv(method='LDL') == ans + assert A * ans == SparseMatrix(eye(3)) + + s = A.solve(A[:, 0], 'LDL') + assert A*s == A[:, 0] + s = A.solve(A[:, 0], 'CH') + assert A*s == A[:, 0] + A = A.col_join(A) + s = A.solve_least_squares(A[:, 0], 'CH') + assert A*s == A[:, 0] + s = A.solve_least_squares(A[:, 0], 'LDL') + assert A*s == A[:, 0] diff -Nru python3-sympy-0.7.2/sympy/matrices/tests/test_sparsetools.py python3-sympy-0.7.3/sympy/matrices/tests/test_sparsetools.py --- python3-sympy-0.7.2/sympy/matrices/tests/test_sparsetools.py 1970-01-01 00:00:00.000000000 +0000 +++ python3-sympy-0.7.3/sympy/matrices/tests/test_sparsetools.py 2013-07-13 17:53:32.000000000 +0000 @@ -0,0 +1,38 @@ +from sympy.matrices.sparsetools import _doktocsr, _csrtodok +from sympy import SparseMatrix + + +def test_doktocsr(): + a = SparseMatrix([[1, 2, 0, 0], [0, 3, 9, 0], [0, 1, 4, 0]]) + b = SparseMatrix(4, 6, [10, 20, 0, 0, 0, 0, 0, 30, 0, 40, 0, 0, 0, 0, 50, + 60, 70, 0, 0, 0, 0, 0, 0, 80]) + c = SparseMatrix(4, 4, [0, 0, 0, 0, 0, 12, 0, 2, 15, 0, 12, 0, 0, 0, 0, 4]) + d = SparseMatrix(10, 10, {(1, 1): 12, (3, 5): 7, (7, 8): 12}) + e = SparseMatrix([[0, 0, 0], [1, 0, 2], [3, 0, 0]]) + f = SparseMatrix(7, 8, {(2, 3): 5, (4, 5):12}) + assert _doktocsr(a) == [[1, 2, 3, 9, 1, 4], [0, 1, 1, 2, 1, 2], + [0, 2, 4, 6], [3, 4]] + assert _doktocsr(b) == [[10, 20, 30, 40, 50, 60, 70, 80], + [0, 1, 1, 3, 2, 3, 4, 5], [0, 2, 4, 7, 8], [4, 6]] + assert _doktocsr(c) == [[12, 2, 15, 12, 4], [1, 3, 0, 2, 3], + [0, 0, 2, 4, 5], [4, 4]] + assert _doktocsr(d) == [[12, 7, 12], [1, 5, 8], + [0, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3], [10, 10]] + assert _doktocsr(e) == [[1, 2, 3], [0, 2, 0], [0, 0, 2, 3], [3, 3]] + assert _doktocsr(f) == [[5, 12], [3, 5], [0, 0, 0, 1, 1, 2, 2, 2], [7, 8]] + + +def test_csrtodok(): + h = [[5, 7, 5], [2, 1, 3], [0, 1, 1, 3], [3, 4]] + g = [[12, 5, 4], [2, 4, 2], [0, 1, 2, 3], [3, 7]] + i = [[1, 3, 12], [0, 2, 4], [0, 2, 3], [2, 5]] + j = [[11, 15, 12, 15], [2, 4, 1, 2], [0, 1, 1, 2, 3, 4], [5, 8]] + k = [[1, 3], [2, 1], [0, 1, 1, 2], [3, 3]] + assert _csrtodok(h) == SparseMatrix(3, 4, + {(0, 2): 5, (2, 1): 7, (2, 3): 5}) + assert _csrtodok(g) == SparseMatrix(3, 7, + {(0, 2): 12, (1, 4): 5, (2, 2): 4}) + assert _csrtodok(i) == SparseMatrix([[1, 0, 3, 0, 0], [0, 0, 0, 0, 12]]) + assert _csrtodok(j) == SparseMatrix(5, 8, + {(0, 2): 11, (2, 4): 15, (3, 1): 12, (4, 2): 15}) + assert _csrtodok(k) == SparseMatrix(3, 3, {(0, 2): 1, (2, 1): 3}) diff -Nru python3-sympy-0.7.2/sympy/mpmath/__init__.py python3-sympy-0.7.3/sympy/mpmath/__init__.py --- python3-sympy-0.7.2/sympy/mpmath/__init__.py 2012-09-13 23:10:35.000000000 +0000 +++ python3-sympy-0.7.3/sympy/mpmath/__init__.py 2013-07-13 17:50:18.000000000 +0000 @@ -417,7 +417,8 @@ def doctests(): try: - import psyco; psyco.full() + import psyco + psyco.full() except ImportError: pass import sys diff -Nru python3-sympy-0.7.2/sympy/mpmath/ctx_fp.py python3-sympy-0.7.3/sympy/mpmath/ctx_fp.py --- python3-sympy-0.7.2/sympy/mpmath/ctx_fp.py 2012-09-13 23:10:35.000000000 +0000 +++ python3-sympy-0.7.3/sympy/mpmath/ctx_fp.py 2013-07-13 17:50:18.000000000 +0000 @@ -206,7 +206,10 @@ while 1: for i in num: t *= (coeffs[i]+k) for i in den: t /= (coeffs[i]+k) - k += 1; t /= k; t *= z; s += t + k += 1 + t /= k + t *= z + s += t if abs(t) < tol: return s if k > maxterms: diff -Nru python3-sympy-0.7.2/sympy/mpmath/ctx_iv.py python3-sympy-0.7.3/sympy/mpmath/ctx_iv.py --- python3-sympy-0.7.2/sympy/mpmath/ctx_iv.py 2012-09-13 23:10:35.000000000 +0000 +++ python3-sympy-0.7.3/sympy/mpmath/ctx_iv.py 2013-07-13 17:50:18.000000000 +0000 @@ -258,8 +258,10 @@ ivmpf.__div__, ivmpf.__rdiv__, ivmpc.__div__, ivmpc.__rdiv__ = _binary_op(mpi_div, mpci_div) ivmpf.__pow__, ivmpf.__rpow__, ivmpc.__pow__, ivmpc.__rpow__ = _binary_op(mpi_pow, mpci_pow) -ivmpf.__truediv__ = ivmpf.__div__; ivmpf.__rtruediv__ = ivmpf.__rdiv__ -ivmpc.__truediv__ = ivmpc.__div__; ivmpc.__rtruediv__ = ivmpc.__rdiv__ +ivmpf.__truediv__ = ivmpf.__div__ +ivmpf.__rtruediv__ = ivmpf.__rdiv__ +ivmpc.__truediv__ = ivmpc.__div__ +ivmpc.__rtruediv__ = ivmpc.__rdiv__ class ivmpf_constant(ivmpf): def __new__(cls, f): @@ -500,7 +502,10 @@ while 1: for i in num: t *= (coeffs[i]+k) for i in den: t /= (coeffs[i]+k) - k += 1; t /= k; t *= z; s += t + k += 1 + t /= k + t *= z + s += t if t == 0: return s #if abs(t) < tol: diff -Nru python3-sympy-0.7.2/sympy/mpmath/function_docs.py python3-sympy-0.7.3/sympy/mpmath/function_docs.py --- python3-sympy-0.7.2/sympy/mpmath/function_docs.py 2012-09-13 23:10:35.000000000 +0000 +++ python3-sympy-0.7.3/sympy/mpmath/function_docs.py 2013-07-13 17:50:18.000000000 +0000 @@ -3335,7 +3335,7 @@ 0.06674960718150520648014567 -[1] http://www.math.ucla.edu/~cbm/aands/page_504.htm +[1] http://people.math.sfu.ca/~cbm/aands/page_504.htm """ hyp2f0 = r""" @@ -3402,7 +3402,7 @@ [1.0, -2.0, 4.5, -7.5, 6.5625, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0] -[1] http://www.math.ucla.edu/~cbm/aands/page_504.htm +[1] http://people.math.sfu.ca/~cbm/aands/page_504.htm """ diff -Nru python3-sympy-0.7.2/sympy/mpmath/functions/bessel.py python3-sympy-0.7.3/sympy/mpmath/functions/bessel.py --- python3-sympy-0.7.2/sympy/mpmath/functions/bessel.py 2012-09-13 23:10:35.000000000 +0000 +++ python3-sympy-0.7.3/sympy/mpmath/functions/bessel.py 2013-07-13 17:50:18.000000000 +0000 @@ -478,7 +478,9 @@ # http://functions.wolfram.com/03.07.06.0005.01 if ctx._re(z) > 4: ctx.prec += extraprec - w = z**1.5; r = -0.75/w; u = -2*w/3 + w = z**1.5 + r = -0.75/w + u = -2*w/3 ctx.prec -= extraprec C = -ctx.exp(u)/(2*ctx.sqrt(ctx.pi))*ctx.nthroot(z,4) return ([C],[1],[],[],[(-1,6),(7,6)],[],r), @@ -502,10 +504,17 @@ w = z**3/9 ctx.prec -= extraprec q13,q23,q43 = ctx.mpq_1_3, ctx.mpq_2_3, ctx.mpq_4_3 - a1=q13; a2=1; b1=(1-n)*q13; b2=(2-n)*q13; b3=1-n*q13 + a1=q13 + a2=1 + b1=(1-n)*q13 + b2=(2-n)*q13 + b3=1-n*q13 T1 = [3, z], [n-q23, -n], [a1], [b1,b2,b3], \ [a1,a2], [b1,b2,b3], w - a1=q23; b1=(2-n)*q13; b2=1-n*q13; b3=(4-n)*q13 + a1=q23 + b1=(2-n)*q13 + b2=1-n*q13 + b3=(4-n)*q13 T2 = [3, z, -z], [n-q43, -n, 1], [a1], [b1,b2,b3], \ [a1,a2], [b1,b2,b3], w return T1, T2 @@ -520,7 +529,9 @@ # the following expansion is better. # TODO: asymptotic series for derivatives ctx.prec += extraprec - w = z**1.5; r = -0.75/w; u = -2*w/3 + w = z**1.5 + r = -0.75/w + u = -2*w/3 ctx.prec -= extraprec C = ctx.exp(u)/(2*ctx.sqrt(ctx.pi)*ctx.nthroot(z,4)) return ([C],[1],[],[],[(1,6),(5,6)],[],r), @@ -588,10 +599,17 @@ q13,q23,q43 = ctx.mpq_1_3, ctx.mpq_2_3, ctx.mpq_4_3 q16 = ctx.mpq_1_6 q56 = ctx.mpq_5_6 - a1=q13; a2=1; b1=(1-n)*q13; b2=(2-n)*q13; b3=1-n*q13 + a1=q13 + a2=1 + b1=(1-n)*q13 + b2=(2-n)*q13 + b3=1-n*q13 T1 = [3, z], [n-q16, -n], [a1], [b1,b2,b3], \ [a1,a2], [b1,b2,b3], w - a1=q23; b1=(2-n)*q13; b2=1-n*q13; b3=(4-n)*q13 + a1=q23 + b1=(2-n)*q13 + b2=1-n*q13 + b3=(4-n)*q13 T2 = [3, z], [n-q56, 1-n], [a1], [b1,b2,b3], \ [a1,a2], [b1,b2,b3], w return T1, T2 @@ -764,7 +782,8 @@ try: chi = ctx._coulomb_chi(l, eta) jw = ctx.j*w - s = ctx.sin(chi); c = ctx.cos(chi) + s = ctx.sin(chi) + c = ctx.cos(chi) C1 = ctx.coulombc(l,eta) C2 = ctx.coulombc(l2,eta) u = ctx.exp(jw*z) diff -Nru python3-sympy-0.7.2/sympy/mpmath/functions/elliptic.py python3-sympy-0.7.3/sympy/mpmath/functions/elliptic.py --- python3-sympy-0.7.2/sympy/mpmath/functions/elliptic.py 2012-09-13 23:10:35.000000000 +0000 +++ python3-sympy-0.7.3/sympy/mpmath/functions/elliptic.py 2013-07-13 17:50:18.000000000 +0000 @@ -528,7 +528,10 @@ sp = ctx.sqrt(pm) lm = sx*sy + sx*sz + sy*sz Am1 = (Am+lm)*g - xm = (xm+lm)*g; ym = (ym+lm)*g; zm = (zm+lm)*g; pm = (pm+lm)*g + xm = (xm+lm)*g + ym = (ym+lm)*g + zm = (zm+lm)*g + pm = (pm+lm)*g dm = (sp+sx) * (sp+sy) * (sp+sz) em = delta * ctx.power(4, -3*m) / dm**2 if pow4 * Q < abs(Am): diff -Nru python3-sympy-0.7.2/sympy/mpmath/functions/functions.py python3-sympy-0.7.3/sympy/mpmath/functions/functions.py --- python3-sympy-0.7.2/sympy/mpmath/functions/functions.py 2012-09-13 23:10:35.000000000 +0000 +++ python3-sympy-0.7.3/sympy/mpmath/functions/functions.py 2013-07-13 17:50:18.000000000 +0000 @@ -365,9 +365,11 @@ # Simple linear approximation return 0.2 + 0.3*z if (not imag_sign) and x > 0.0: - L1 = math.log(x); L2 = math.log(L1) + L1 = math.log(x) + L2 = math.log(L1) else: - L1 = cmath.log(z); L2 = cmath.log(L1) + L1 = cmath.log(z) + L2 = cmath.log(L1) elif k == -1: # return real type r = -0.367879441171442 diff -Nru python3-sympy-0.7.2/sympy/mpmath/functions/hypergeometric.py python3-sympy-0.7.3/sympy/mpmath/functions/hypergeometric.py --- python3-sympy-0.7.2/sympy/mpmath/functions/hypergeometric.py 2012-09-13 23:10:35.000000000 +0000 +++ python3-sympy-0.7.3/sympy/mpmath/functions/hypergeometric.py 2013-07-13 17:50:18.000000000 +0000 @@ -450,7 +450,9 @@ # Use 1/z transformation if absz >= 1.3: def h(a,b): - t = ctx.mpq_1-c; ab = a-b; rz = 1/z + t = ctx.mpq_1-c + ab = a-b + rz = 1/z T1 = ([-z],[-a], [c,-ab],[b,c-a], [a,t+a],[ctx.mpq_1+ab], rz) T2 = ([-z],[-b], [c,ab],[a,c-b], [b,t+b],[ctx.mpq_1-ab], rz) return T1, T2 @@ -459,7 +461,10 @@ # Use 1-z transformation elif abs(1-z) <= 0.75: def h(a,b): - t = c-a-b; ca = c-a; cb = c-b; rz = 1-z + t = c-a-b + ca = c-a + cb = c-b + rz = 1-z T1 = [], [], [c,t], [ca,cb], [a,b], [1-t], rz T2 = [rz], [t], [c,a+b-c], [a,b], [ca,cb], [1+t], rz return T1, T2 diff -Nru python3-sympy-0.7.2/sympy/mpmath/functions/rszeta.py python3-sympy-0.7.3/sympy/mpmath/functions/rszeta.py --- python3-sympy-0.7.2/sympy/mpmath/functions/rszeta.py 2012-09-13 23:10:35.000000000 +0000 +++ python3-sympy-0.7.3/sympy/mpmath/functions/rszeta.py 2013-07-13 17:50:18.000000000 +0000 @@ -445,8 +445,14 @@ ctx.prec = xwpd[1]+10 xpsigma = 1-(2*xsigma) xd = {} - xd[0,0,-2]=0; xd[0,0,-1]=0; xd[0,0,0]=1; xd[0,0,1]=0 - xd[0,-1,-2]=0; xd[0,-1,-1]=0; xd[0,-1,0]=1; xd[0,-1,1]=0 + xd[0,0,-2]=0 + xd[0,0,-1]=0 + xd[0,0,0]=1 + xd[0,0,1]=0 + xd[0,-1,-2]=0 + xd[0,-1,-1]=0 + xd[0,-1,0]=1 + xd[0,-1,1]=0 for n in range(1,L): ctx.prec = xwpd[n]+10 for k in range(0,3*n//2+1): @@ -462,7 +468,9 @@ for r in range(0,k): add=xd[0,n,r]*(ctx.mpf('1.0')*ctx.fac(2*k-2*r)/ctx.fac(k-r)) xd[0,n,k] -= ((-1)**(k-r))*add - xd[0,n,-2]=0; xd[0,n,-1]=0; xd[0,n,3*n//2+1]=0 + xd[0,n,-2]=0 + xd[0,n,-1]=0 + xd[0,n,3*n//2+1]=0 for mu in range(-2,der+1): for n in range(-2,L): for k in range(-3,max(1,3*n//2+2)): @@ -489,8 +497,14 @@ ctx.prec = ywpd[1]+10 ypsigma = 1-(2*ysigma) yd = {} - yd[0,0,-2]=0; yd[0,0,-1]=0; yd[0,0,0]=1; yd[0,0,1]=0 - yd[0,-1,-2]=0; yd[0,-1,-1]=0; yd[0,-1,0]=1; yd[0,-1,1]=0 + yd[0,0,-2]=0 + yd[0,0,-1]=0 + yd[0,0,0]=1 + yd[0,0,1]=0 + yd[0,-1,-2]=0 + yd[0,-1,-1]=0 + yd[0,-1,0]=1 + yd[0,-1,1]=0 for n in range(1,L): ctx.prec = ywpd[n]+10 for k in range(0,3*n//2+1): @@ -506,7 +520,9 @@ for r in range(0,k): add=yd[0,n,r]*(ctx.mpf('1.0')*ctx.fac(2*k-2*r)/ctx.fac(k-r)) yd[0,n,k] -= ((-1)**(k-r))*add - yd[0,n,-2]=0; yd[0,n,-1]=0; yd[0,n,3*n//2+1]=0 + yd[0,n,-2]=0 + yd[0,n,-1]=0 + yd[0,n,3*n//2+1]=0 for mu in range(-2,der+1): for n in range(-2,L): @@ -948,8 +964,14 @@ ctx.prec = wpd[1]+10 psigma = 1-(2*sigma) d = {} - d[0,0,-2]=0; d[0,0,-1]=0; d[0,0,0]=1; d[0,0,1]=0 - d[0,-1,-2]=0; d[0,-1,-1]=0; d[0,-1,0]=1; d[0,-1,1]=0 + d[0,0,-2]=0 + d[0,0,-1]=0 + d[0,0,0]=1 + d[0,0,1]=0 + d[0,-1,-2]=0 + d[0,-1,-1]=0 + d[0,-1,0]=1 + d[0,-1,1]=0 for n in range(1,L): ctx.prec = wpd[n]+10 for k in range(0,3*n//2+1): @@ -965,7 +987,9 @@ for r in range(0,k): add = d[0,n,r]*(ctx.one*ctx.fac(2*k-2*r)/ctx.fac(k-r)) d[0,n,k] -= ((-1)**(k-r))*add - d[0,n,-2]=0; d[0,n,-1]=0; d[0,n,3*n//2+1]=0 + d[0,n,-2]=0 + d[0,n,-1]=0 + d[0,n,3*n//2+1]=0 for mu in range(-2,der+1): for n in range(-2,L): @@ -1382,7 +1406,8 @@ if derivative > 4: raise NotImplementedError s = ctx.convert(s) - re = ctx._re(s); im = ctx._im(s) + re = ctx._re(s) + im = ctx._im(s) if im < 0: z = ctx.conj(ctx.rs_zeta(ctx.conj(s), derivative)) return z @@ -1395,7 +1420,8 @@ @defun def rs_z(ctx, w, derivative=0): w = ctx.convert(w) - re = ctx._re(w); im = ctx._im(w) + re = ctx._re(w) + im = ctx._im(w) if re < 0: return rs_z(ctx, -w, derivative) critical_line = (im == 0) diff -Nru python3-sympy-0.7.2/sympy/mpmath/libmp/backend.py python3-sympy-0.7.3/sympy/mpmath/libmp/backend.py --- python3-sympy-0.7.2/sympy/mpmath/libmp/backend.py 2012-09-13 23:10:35.000000000 +0000 +++ python3-sympy-0.7.3/sympy/mpmath/libmp/backend.py 2013-07-13 17:50:18.000000000 +0000 @@ -61,7 +61,7 @@ import gmpy except ImportError: raise ImportError - if gmpy.version() >= '1.03': + if gmpy.version() >= '1.13': BACKEND = 'gmpy' MPZ = gmpy.mpz except: diff -Nru python3-sympy-0.7.2/sympy/mpmath/libmp/gammazeta.py python3-sympy-0.7.3/sympy/mpmath/libmp/gammazeta.py --- python3-sympy-0.7.2/sympy/mpmath/libmp/gammazeta.py 2012-09-13 23:10:35.000000000 +0000 +++ python3-sympy-0.7.3/sympy/mpmath/libmp/gammazeta.py 2013-07-13 17:50:18.000000000 +0000 @@ -1791,18 +1791,28 @@ u = (t*t)>>prec # u = 1/x**2 s = ln_sqrt2pi_fixed(prec) - x # Add initial terms of Stirling's series - s += t//12; t = (t*u)>>prec - s -= t//360; t = (t*u)>>prec - s += t//1260; t = (t*u)>>prec - s -= t//1680; t = (t*u)>>prec + s += t//12 + t = (t*u)>>prec + s -= t//360 + t = (t*u)>>prec + s += t//1260 + t = (t*u)>>prec + s -= t//1680 + t = (t*u)>>prec if not t: return s - s += t//1188; t = (t*u)>>prec - s -= 691*t//360360; t = (t*u)>>prec - s += t//156; t = (t*u)>>prec + s += t//1188 + t = (t*u)>>prec + s -= 691*t//360360 + t = (t*u)>>prec + s += t//156 + t = (t*u)>>prec if not t: return s - s -= 3617*t//122400; t = (t*u)>>prec - s += 43867*t//244188; t = (t*u)>>prec - s -= 174611*t//125400; t = (t*u)>>prec + s -= 3617*t//122400 + t = (t*u)>>prec + s += 43867*t//244188 + t = (t*u)>>prec + s -= 174611*t//125400 + t = (t*u)>>prec if not t: return s k = 22 # From here on, the coefficients are growing, so we @@ -1846,27 +1856,37 @@ sim = -y # Add initial terms of Stirling's series - sre += tre//12; sim += tim//12; + sre += tre//12 + sim += tim//12 tre, tim = ((tre*ure-tim*uim)>>prec), ((tre*uim+tim*ure)>>prec) - sre -= tre//360; sim -= tim//360; + sre -= tre//360 + sim -= tim//360 tre, tim = ((tre*ure-tim*uim)>>prec), ((tre*uim+tim*ure)>>prec) - sre += tre//1260; sim += tim//1260; + sre += tre//1260 + sim += tim//1260 tre, tim = ((tre*ure-tim*uim)>>prec), ((tre*uim+tim*ure)>>prec) - sre -= tre//1680; sim -= tim//1680; + sre -= tre//1680 + sim -= tim//1680 tre, tim = ((tre*ure-tim*uim)>>prec), ((tre*uim+tim*ure)>>prec) if abs(tre) + abs(tim) < 5: return sre, sim - sre += tre//1188; sim += tim//1188; + sre += tre//1188 + sim += tim//1188 tre, tim = ((tre*ure-tim*uim)>>prec), ((tre*uim+tim*ure)>>prec) - sre -= 691*tre//360360; sim -= 691*tim//360360; + sre -= 691*tre//360360 + sim -= 691*tim//360360 tre, tim = ((tre*ure-tim*uim)>>prec), ((tre*uim+tim*ure)>>prec) - sre += tre//156; sim += tim//156; + sre += tre//156 + sim += tim//156 tre, tim = ((tre*ure-tim*uim)>>prec), ((tre*uim+tim*ure)>>prec) if abs(tre) + abs(tim) < 5: return sre, sim - sre -= 3617*tre//122400; sim -= 3617*tim//122400; + sre -= 3617*tre//122400 + sim -= 3617*tim//122400 tre, tim = ((tre*ure-tim*uim)>>prec), ((tre*uim+tim*ure)>>prec) - sre += 43867*tre//244188; sim += 43867*tim//244188; + sre += 43867*tre//244188 + sim += 43867*tim//244188 tre, tim = ((tre*ure-tim*uim)>>prec), ((tre*uim+tim*ure)>>prec) - sre -= 174611*tre//125400; sim -= 174611*tim//125400; + sre -= 174611*tre//125400 + sim -= 174611*tim//125400 tre, tim = ((tre*ure-tim*uim)>>prec), ((tre*uim+tim*ure)>>prec) if abs(tre) + abs(tim) < 5: return sre, sim diff -Nru python3-sympy-0.7.2/sympy/mpmath/libmp/libelefun.py python3-sympy-0.7.3/sympy/mpmath/libmp/libelefun.py --- python3-sympy-0.7.2/sympy/mpmath/libmp/libelefun.py 2012-09-13 23:10:35.000000000 +0000 +++ python3-sympy-0.7.3/sympy/mpmath/libmp/libelefun.py 2013-07-13 17:50:18.000000000 +0000 @@ -1035,8 +1035,12 @@ s0 = s1 = MPZ_ZERO k = 2 while a: - a //= (k-1)*k; s0 += a; k += 2 - a //= (k-1)*k; s1 += a; k += 2 + a //= (k-1)*k + s0 += a + k += 2 + a //= (k-1)*k + s1 += a + k += 2 a = (a*x4) >> wp s1 = (x2*s1) >> wp if alt: @@ -1097,8 +1101,12 @@ k = 2 a = x2 = (x*x) >> prec while a: - a //= k; s0 += a; k += 1 - a //= k; s1 += a; k += 1 + a //= k + s0 += a + k += 1 + a //= k + s1 += a + k += 1 a = (a*x2) >> prec s1 = (s1*x) >> prec s = s0 + s1 @@ -1144,8 +1152,14 @@ k = 2 a = -((x*x) >> prec) while a: - a //= k; cos += a; k += 1; a = (a*x) >> prec - a //= k; sin += a; k += 1; a = -((a*x) >> prec) + a //= k + cos += a + k += 1 + a = (a*x) >> prec + a //= k + sin += a + k += 1 + a = -((a*x) >> prec) return ((cos*cos_t-sin*sin_t) >> prec), ((sin*cos_t+cos*sin_t) >> prec) def mpf_exp(x, prec, rnd=round_fast): diff -Nru python3-sympy-0.7.2/sympy/mpmath/libmp/libintmath.py python3-sympy-0.7.3/sympy/mpmath/libmp/libintmath.py --- python3-sympy-0.7.2/sympy/mpmath/libmp/libintmath.py 2012-10-17 01:53:14.000000000 +0000 +++ python3-sympy-0.7.3/sympy/mpmath/libmp/libintmath.py 2013-07-13 17:50:18.000000000 +0000 @@ -298,8 +298,12 @@ sqrt_fixed2 = sqrt_fixed if BACKEND == 'gmpy': - isqrt_small = isqrt_fast = isqrt = gmpy.sqrt - sqrtrem = gmpy.sqrtrem + if gmpy.version() >= "2": + isqrt_small = isqrt_fast = isqrt = gmpy.isqrt + sqrtrem = gmpy.isqrt_rem + else: + isqrt_small = isqrt_fast = isqrt = gmpy.sqrt + sqrtrem = gmpy.sqrtrem elif BACKEND == 'sage': isqrt_small = isqrt_fast = isqrt = \ getattr(sage_utils, "isqrt", lambda n: MPZ(n).isqrt()) diff -Nru python3-sympy-0.7.2/sympy/mpmath/libmp/libmpi.py python3-sympy-0.7.3/sympy/mpmath/libmp/libmpi.py --- python3-sympy-0.7.2/sympy/mpmath/libmp/libmpi.py 2012-09-13 23:10:35.000000000 +0000 +++ python3-sympy-0.7.3/sympy/mpmath/libmp/libmpi.py 2013-07-13 17:50:18.000000000 +0000 @@ -876,7 +876,8 @@ # Assume type != 1 if type == 1: - (a1,a2) = mpi_add((a1,a2), mpi_one, wp); z = (a1,a2), (b1,b2) + (a1,a2) = mpi_add((a1,a2), mpi_one, wp) + z = (a1,a2), (b1,b2) type = 0 # Avoid non-monotonic region near the negative real axis diff -Nru python3-sympy-0.7.2/sympy/mpmath/math2.py python3-sympy-0.7.3/sympy/mpmath/math2.py --- python3-sympy-0.7.2/sympy/mpmath/math2.py 2012-09-13 23:10:35.000000000 +0000 +++ python3-sympy-0.7.3/sympy/mpmath/math2.py 2013-07-13 17:50:18.000000000 +0000 @@ -290,13 +290,20 @@ s = 0.918938533204672742 + (x-0.5)*log(x) - x r = 1./x r2 = r*r - s += 0.083333333333333333333*r; r *= r2 - s += -0.0027777777777777777778*r; r *= r2 - s += 0.00079365079365079365079*r; r *= r2 - s += -0.0005952380952380952381*r; r *= r2 - s += 0.00084175084175084175084*r; r *= r2 - s += -0.0019175269175269175269*r; r *= r2 - s += 0.0064102564102564102564*r; r *= r2 + s += 0.083333333333333333333*r + r *= r2 + s += -0.0027777777777777777778*r + r *= r2 + s += 0.00079365079365079365079*r + r *= r2 + s += -0.0005952380952380952381*r + r *= r2 + s += 0.00084175084175084175084*r + r *= r2 + s += -0.0019175269175269175269*r + r *= r2 + s += 0.0064102564102564102564*r + r *= r2 s += -0.02955065359477124183*r return s + p diff -Nru python3-sympy-0.7.2/sympy/mpmath/matrices/__init__.py python3-sympy-0.7.3/sympy/mpmath/matrices/__init__.py --- python3-sympy-0.7.2/sympy/mpmath/matrices/__init__.py 2012-07-31 09:37:14.000000000 +0000 +++ python3-sympy-0.7.3/sympy/mpmath/matrices/__init__.py 2013-07-13 17:50:18.000000000 +0000 @@ -0,0 +1 @@ + diff -Nru python3-sympy-0.7.2/sympy/mpmath/tests/__init__.py python3-sympy-0.7.3/sympy/mpmath/tests/__init__.py --- python3-sympy-0.7.2/sympy/mpmath/tests/__init__.py 2012-01-30 20:18:38.000000000 +0000 +++ python3-sympy-0.7.3/sympy/mpmath/tests/__init__.py 2013-07-13 17:50:18.000000000 +0000 @@ -0,0 +1 @@ + diff -Nru python3-sympy-0.7.2/sympy/mpmath/tests/test_convert.py python3-sympy-0.7.3/sympy/mpmath/tests/test_convert.py --- python3-sympy-0.7.2/sympy/mpmath/tests/test_convert.py 2012-09-13 23:10:35.000000000 +0000 +++ python3-sympy-0.7.3/sympy/mpmath/tests/test_convert.py 2013-07-13 17:50:18.000000000 +0000 @@ -144,11 +144,46 @@ assert (y+z).ae(mpc('4.3')) assert (z+w).ae(mpc('4.3', '1.7')) assert (w+z).ae(mpc('4.3', '1.7')) - x-y; y-x; x-w; w-x; z-y; y-z; z-w; w-z - x*y; y*x; x*w; w*x; z*y; y*z; z*w; w*z - x/y; y/x; x/w; w/x; z/y; y/z; z/w; w/z - x**y; y**x; x**w; w**x; z**y; y**z; z**w; w**z - x==y; y==x; x==w; w==x; z==y; y==z; z==w; w==z + x-y + y-x + x-w + w-x + z-y + y-z + z-w + w-z + x*y + y*x + x*w + w*x + z*y + y*z + z*w + w*z + x/y + y/x + x/w + w/x + z/y + y/z + z/w + w/z + x**y + y**x + x**w + w**x + z**y + y**z + z**w + w**z + x==y + y==x + x==w + w==x + z==y + y==z + z==w + w==z mp.dps = 15 assert x.__add__(a) is NotImplemented assert x.__radd__(a) is NotImplemented diff -Nru python3-sympy-0.7.2/sympy/mpmath/tests/test_division.py python3-sympy-0.7.3/sympy/mpmath/tests/test_division.py --- python3-sympy-0.7.2/sympy/mpmath/tests/test_division.py 2012-07-31 09:37:14.000000000 +0000 +++ python3-sympy-0.7.3/sympy/mpmath/tests/test_division.py 2013-07-13 17:50:18.000000000 +0000 @@ -84,7 +84,9 @@ b = choice([1, -1]) * randint(1, 1< 0.05 or once: return t for i in range(3): - t1=clock(); + t1=clock() # Evaluate multiple times because the timer function # has a significant overhead - g();g();g();g();g();g();g();g();g();g() + g() + g() + g() + g() + g() + g() + g() + g() + g() + g() t2=clock() t=min(t,(t2-t1)/10) return t diff -Nru python3-sympy-0.7.2/sympy/ntheory/__init__.py python3-sympy-0.7.3/sympy/ntheory/__init__.py --- python3-sympy-0.7.2/sympy/ntheory/__init__.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/ntheory/__init__.py 2013-07-13 17:53:32.000000000 +0000 @@ -2,13 +2,13 @@ Number theory module (primes, etc) """ -from .generate import nextprime, prevprime, prime, primepi, primerange,\ -randprime, Sieve, sieve, primorial, cycle_length +from .generate import nextprime, prevprime, prime, primepi, primerange, \ + randprime, Sieve, sieve, primorial, cycle_length from .primetest import isprime -from .factor_ import divisors, factorint, multiplicity, perfect_power,\ -pollard_pm1, pollard_rho, primefactors, totient, trailing, divisor_count +from .factor_ import divisors, factorint, multiplicity, perfect_power, \ + pollard_pm1, pollard_rho, primefactors, totient, trailing, divisor_count from .partitions_ import npartitions from .residue_ntheory import is_primitive_root, is_quad_residue, \ legendre_symbol, jacobi_symbol, n_order -from .multinomial import binomial_coefficients, binomial_coefficients_list,\ -multinomial_coefficients +from .multinomial import binomial_coefficients, binomial_coefficients_list, \ + multinomial_coefficients diff -Nru python3-sympy-0.7.2/sympy/ntheory/bbp_pi.py python3-sympy-0.7.3/sympy/ntheory/bbp_pi.py --- python3-sympy-0.7.2/sympy/ntheory/bbp_pi.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/ntheory/bbp_pi.py 2013-07-13 17:53:32.000000000 +0000 @@ -46,26 +46,29 @@ ''' import math + + def _series(j, n): # Left sum from the bbp algorithm s = 0 D = _dn(n) - for k in range(0, n+1): - r = 8*k+j - s = (s + (pow(16,n-k,r)<<4*(D))//r) + for k in range(0, n + 1): + r = 8*k + j + s = (s + (pow(16, n - k, r) << 4*(D))//r) # Right sum. should iterate to infinty, but now just iterates to the point where # one iterations change is beyond the resolution of the data type used t = 0 - for k in range(n+1, n+15): - xp = int(16**(n-k) * (16**(D)) ) - t = t + xp // (8*k+j) - total = s+t + for k in range(n + 1, n + 15): + xp = int(16**(n - k) * (16**(D)) ) + t = t + xp // (8*k + j) + total = s + t return total + def pi_hex_digits(n): """Returns a string containing 14 digits after the nth value of pi in hex The decimal has been taken out of the number, so @@ -83,23 +86,24 @@ # main of implementation arrays holding formulae coefficients n -= 1 - a= [4,2,1,1] - j = [1,4,5,6] + a = [4, 2, 1, 1] + j = [1, 4, 5, 6] #formulae - x = + (a[0]*_series(j[0], n) + x = + (a[0]*_series(j[0], n) - a[1]*_series(j[1], n) - a[2]*_series(j[2], n) - - a[3]*_series(j[3], n)) & (16**(_dn(n)) -1) + - a[3]*_series(j[3], n)) & (16**(_dn(n)) - 1) - s=("%014x" % x) + s = ("%014x" % x) #s is constrained between 0 and 14 return s[:14] + def _dn(n): # controller for n dependence on precision if (n < 1000): - f=16 + f = 16 else: - f = int((math.log10(n//1000))+18) + f = int((math.log10(n//1000)) + 18) return f diff -Nru python3-sympy-0.7.2/sympy/ntheory/factor_.py python3-sympy-0.7.3/sympy/ntheory/factor_.py --- python3-sympy-0.7.2/sympy/ntheory/factor_.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/ntheory/factor_.py 2013-07-13 17:53:32.000000000 +0000 @@ -4,19 +4,21 @@ import random import math -from sympy.core import Mul +from sympy.core import sympify from sympy.core.evalf import bitcount -from sympy.core.numbers import igcd +from sympy.core.numbers import igcd, oo, Rational from sympy.core.power import integer_nthroot, Pow from sympy.core.mul import Mul -from sympy.core.compatibility import as_int +from sympy.core.compatibility import as_int, SYMPY_INTS from .primetest import isprime from .generate import sieve, primerange, nextprime from sympy.core.singleton import S +from sympy.core.function import Function -small_trailing = [i and max(int(not i % 2**j) and j for j in range(1,8)) \ +small_trailing = [i and max(int(not i % 2**j) and j for j in range(1, 8)) for i in range(256)] + def smoothness(n): """ Return the B-smooth and B-power smooth values of n. @@ -39,10 +41,11 @@ """ if n == 1: - return (1, 1) # not prime, but otherwise this causes headaches + return (1, 1) # not prime, but otherwise this causes headaches facs = factorint(n) return max(facs), max([m**facs[m] for m in facs]) + def smoothness_p(n, m=-1, power=0, visual=None): """ Return a list of [m, (p, (M, sm(p + m), psm(p + m)))...] @@ -86,7 +89,7 @@ The table of the output logic is: ====== ====== ======= ======= - Visual + | Visual ------ ---------------------- Input True False other ====== ====== ======= ======= @@ -104,14 +107,19 @@ """ from sympy.utilities import flatten + # visual must be True, False or other (stored as None) + if visual in (1, 0): + visual = bool(visual) + elif visual not in (True, False): + visual = None + if type(n) is str: if visual: return n d = {} for li in n.splitlines(): - k, v = [int(i) for i in li.split('has')[0] - .split('=')[1] - .split('**')] + k, v = [int(i) for i in + li.split('has')[0].split('=')[1].split('**')] d[k] = v if visual is not True and visual is not False: return d @@ -125,13 +133,13 @@ k = 1 if type(n) is not tuple: rv = (m, sorted([(f, - tuple([M] + list(smoothness(f + m)))) - for f, M in [i for i in list(facs.items())]], - key=lambda x: (x[1][k], x[0]))) + tuple([M] + list(smoothness(f + m)))) + for f, M in [i for i in list(facs.items())]], + key=lambda x: (x[1][k], x[0]))) else: rv = n - if visual is False or (visual != True) and (type(n) in [int, Mul]): + if visual is False or (visual is not True) and (type(n) in [int, Mul]): return rv lines = [] for dat in rv[1]: @@ -140,6 +148,7 @@ lines.append('p**i=%i**%i has p%+i B=%i, B-pow=%i' % tuple(dat)) return '\n'.join(lines) + def trailing(n): """Count the number of trailing zero digits in the binary representation of n, i.e. determine the largest power of 2 @@ -163,20 +172,21 @@ # 2**m is quick for z up through 2**30 z = bitcount(n) - 1 - if type(z) is int: + if isinstance(z, SYMPY_INTS): if n == 1 << z: return z t = 0 p = 8 while not n & 1: - while not n & ((1<>= p t += p p *= 2 p //= 2 return t + def multiplicity(p, n): """ Find the greatest integer m such that p**m divides n. @@ -185,11 +195,38 @@ ======== >>> from sympy.ntheory import multiplicity + >>> from sympy.core.numbers import Rational as R >>> [multiplicity(5, n) for n in [8, 5, 25, 125, 250]] [0, 1, 2, 3, 3] + >>> multiplicity(3, R(1, 9)) + -2 """ - p, n = as_int(p), as_int(n) + try: + p, n = as_int(p), as_int(n) + except ValueError: + if all(isinstance(i, (SYMPY_INTS, Rational)) for i in (p, n)): + try: + p = Rational(p) + n = Rational(n) + if p.q == 1: + if n.p == 1: + return -multiplicity(p.p, n.q) + return S.Zero + elif p.p == 1: + return multiplicity(p.q, n.q) + else: + like = min( + multiplicity(p.p, n.p), + multiplicity(p.q, n.q)) + cross = min( + multiplicity(p.q, n.p), + multiplicity(p.p, n.q)) + return like - cross + except AttributeError: + pass + raise ValueError('expecting ints or fractions, got %s and %s' % (p, n)) + if p == 2: return trailing(n) if p < 2: @@ -218,6 +255,7 @@ n, rem = divmod(n, p) return m + def perfect_power(n, candidates=None, big=True, factor=True): """ Return ``(b, e)`` such that ``n`` == ``b**e`` if ``n`` is a @@ -249,8 +287,8 @@ if n < 3: return False logn = math.log(n, 2) - max_possible = int(logn) + 2 # only check values less than this - not_square = n % 10 in [2, 3, 7, 8] # squares cannot end in 2, 3, 7, 8 + max_possible = int(logn) + 2 # only check values less than this + not_square = n % 10 in [2, 3, 7, 8] # squares cannot end in 2, 3, 7, 8 if not candidates: candidates = primerange(2 + not_square, max_possible) @@ -321,6 +359,7 @@ else: return False + def pollard_rho(n, s=2, a=1, retries=5, seed=1234, max_steps=None, F=None): r""" Use Pollard's rho method to try to extract a nontrivial factor @@ -398,7 +437,6 @@ - Richard Crandall & Carl Pomerance (2005), "Prime Numbers: A Computational Perspective", Springer, 2nd edition, 229-231 - - http://www.csh.rit.edu/~pat/math/quickies/rho/ """ n = int(n) @@ -416,7 +454,7 @@ break j += 1 U = F(U) - V = F(F(V)) # V is 2x further along than U + V = F(F(V)) # V is 2x further along than U g = igcd(U - V, n) if g == 1: continue @@ -424,10 +462,11 @@ break return int(g) V = prng.randint(0, n - 1) - a = prng.randint(1, n - 3) # for x**2 + a, a%n should not be 0 or -2 + a = prng.randint(1, n - 3) # for x**2 + a, a%n should not be 0 or -2 F = None return None + def pollard_pm1(n, B=10, a=2, retries=0, seed=1234): """ Use Pollard's p-1 method to try to extract a nontrivial factor @@ -557,7 +596,6 @@ A Computational Perspective", Springer, 2nd edition, 236-238 - http://modular.math.washington.edu/edu/2007/spring/ent/ent-html/ node81.html - - http://www.math.mcgill.ca/darmon/courses/05-06/usra/charest.pdf - http://www.cs.toronto.edu/~yuvalf/Factorization.pdf """ @@ -585,6 +623,7 @@ # say 'a' should be coprime to n, but either will detect factors. a = prng.randint(2, n - 2) + def _trial(factors, n, candidates, verbose=False): """ Helper function for integer factorization. Trial factors ``n` @@ -605,12 +644,9 @@ print(factor_msg % (k, factors[k])) return int(n), len(factors) != nfactors -def _check_termination(factors, n, - limitp1, - use_trial, - use_rho, - use_pm1, - verbose): + +def _check_termination(factors, n, limitp1, use_trial, use_rho, use_pm1, + verbose): """ Helper function for integer factorization. Checks if ``n`` is a prime or a perfect power, and in those cases updates @@ -629,12 +665,8 @@ limit = limitp1 - 1 else: limit = limitp1 - facs = factorint(base, - limit, - use_trial, - use_rho, - use_pm1, - verbose=False) + facs = factorint(base, limit, use_trial, use_rho, use_pm1, + verbose=False) for b, e in list(facs.items()): if verbose: print(factor_msg % (b, e)) @@ -656,6 +688,7 @@ fermat_msg = 'Close factors satisying Fermat condition found.' complete_msg = 'Factorization is complete.' + def _factorint_small(factors, n, limit, fail_max): """ Return the value of n and either a 0 (indicating that factorization up @@ -756,8 +789,9 @@ return done(n, d) + def factorint(n, limit=None, use_trial=True, use_rho=True, use_pm1=True, - verbose=False, visual=None): + verbose=False, visual=None): r""" Given a positive integer ``n``, ``factorint(n)`` returns a dict containing the prime factors of ``n`` as keys and their respective multiplicities @@ -897,13 +931,9 @@ """ factordict = {} if visual and not isinstance(n, Mul) and not isinstance(n, dict): - factordict = factorint(n, - limit=limit, - use_trial=use_trial, - use_rho=use_rho, - use_pm1=use_pm1, - verbose=verbose, - visual=False) + factordict = factorint(n, limit=limit, use_trial=use_trial, + use_rho=use_rho, use_pm1=use_pm1, + verbose=verbose, visual=False) elif isinstance(n, Mul): factordict = dict([(int(k), int(v)) for k, v in list(n.as_powers_dict().items())]) @@ -915,13 +945,8 @@ if isprime(k): continue e = factordict.pop(k) - d = factorint(k, - limit=limit, - use_trial=use_trial, - use_rho=use_rho, - use_pm1=use_pm1, - verbose=verbose, - visual=False) + d = factorint(k, limit=limit, use_trial=use_trial, use_rho=use_rho, + use_pm1=use_pm1, verbose=verbose, visual=False) for k, v in list(d.items()): if k in factordict: factordict[k] += v*e @@ -939,20 +964,21 @@ args = [] args.extend([Pow(*i, **{'evaluate':False}) for i in sorted(factordict.items())]) - return Mul(*args, **{'evaluate':False}) + return Mul(*args, **{'evaluate': False}) elif isinstance(n, dict) or isinstance(n, Mul): return factordict assert use_trial or use_rho or use_pm1 - n = int(n) + n = as_int(n) if limit: limit = int(limit) # special cases if n < 0: - factors = factorint(-n, limit=limit, use_trial=use_trial, use_rho=use_rho, - use_pm1=use_pm1, verbose=verbose, visual=False) + factors = factorint( + -n, limit=limit, use_trial=use_trial, use_rho=use_rho, + use_pm1=use_pm1, verbose=verbose, visual=False) factors[-1] = 1 return factors @@ -1008,12 +1034,8 @@ if verbose: print('Exceeded limit:', limit) - _check_termination(factors, n, - limit, - use_trial, - use_rho, - use_pm1, - verbose) + _check_termination(factors, n, limit, use_trial, use_rho, use_pm1, + verbose) if n > 1: factors[int(n)] = 1 @@ -1033,30 +1055,23 @@ b, fermat = integer_nthroot(b2, 2) if fermat: break - b2 += 2*a + 1 # equiv to (a+1)**2 - n - a += 1 + b2 += 2*a + 1 # equiv to (a+1)**2 - n + a += 1 if fermat: if verbose: print(fermat_msg) if limit: limit -= 1 for r in [a - b, a + b]: - facs = factorint(r, - limit=limit, - use_trial=use_trial, - use_rho=use_rho, - use_pm1=use_pm1, - verbose=verbose) + facs = factorint(r, limit=limit, use_trial=use_trial, + use_rho=use_rho, use_pm1=use_pm1, + verbose=verbose) factors.update(facs) raise StopIteration # ...see if factorization can be terminated - _check_termination(factors, n, - limit, - use_trial, - use_rho, - use_pm1, - verbose) + _check_termination(factors, n, limit, use_trial, use_rho, use_pm1, + verbose) except StopIteration: if verbose: @@ -1085,12 +1100,8 @@ ps = sieve.primerange(low, high_) n, found_trial = _trial(factors, n, ps, verbose) if found_trial: - _check_termination(factors, n, - limit, - use_trial, - use_rho, - use_pm1, - verbose) + _check_termination(factors, n, limit, use_trial, use_rho, + use_pm1, verbose) else: found_trial = False @@ -1113,42 +1124,32 @@ c = pollard_pm1(n, B=high_root, seed=high_) if c: # factor it and let _trial do the update - ps = factorint(c, - limit=limit-1, - use_trial=use_trial, - use_rho=use_rho, - use_pm1=use_pm1, - verbose=verbose) + ps = factorint(c, limit=limit - 1, + use_trial=use_trial, + use_rho=use_rho, + use_pm1=use_pm1, + verbose=verbose) n, _ = _trial(factors, n, ps, verbose=False) - _check_termination(factors, n, - limit, - use_trial, - use_rho, - use_pm1, - verbose) + _check_termination(factors, n, limit, use_trial, + use_rho, use_pm1, verbose) # Pollard rho if use_rho: max_steps = high_root if verbose: print((rho_msg % (1, max_steps, high_))) - c = pollard_rho(n, retries=1, max_steps=max_steps, \ - seed=high_) + c = pollard_rho(n, retries=1, max_steps=max_steps, + seed=high_) if c: # factor it and let _trial do the update - ps = factorint(c, - limit=limit-1, - use_trial=use_trial, - use_rho=use_rho, - use_pm1=use_pm1, - verbose=verbose) + ps = factorint(c, limit=limit - 1, + use_trial=use_trial, + use_rho=use_rho, + use_pm1=use_pm1, + verbose=verbose) n, _ = _trial(factors, n, ps, verbose=False) - _check_termination(factors, n, - limit, - use_trial, - use_rho, - use_pm1, - verbose) + _check_termination(factors, n, limit, use_trial, + use_rho, use_pm1, verbose) except StopIteration: if verbose: @@ -1198,16 +1199,17 @@ s += [factors[-1]] return s + def _divisors(n): """Helper function for divisors which generates the divisors.""" factordict = factorint(n) ps = sorted(factordict.keys()) - def rec_gen(n = 0): + def rec_gen(n=0): if n == len(ps): yield 1 - else : + else: pows = [1] for j in range(factordict[ps[n]]): pows.append(pows[-1] * ps[n]) @@ -1215,9 +1217,10 @@ for p in pows: yield p * q - for p in rec_gen() : + for p in rec_gen(): yield p + def divisors(n, generator=False): r""" Return all divisors of n sorted from 1..n by default. @@ -1248,7 +1251,7 @@ primefactors, factorint, divisor_count """ - n = abs(n) + n = int(abs(n)) if isprime(n): return [1, n] elif n == 1: @@ -1261,6 +1264,7 @@ return sorted(rv) return rv + def divisor_count(n, modulus=1): """ Return the number of divisors of ``n``. If ``modulus`` is not 1 then only @@ -1289,9 +1293,10 @@ return 0 if n == 0: return 0 - return Mul(*[v+1 for k, v in list(factorint(n).items()) if k > 1]) + return Mul(*[v + 1 for k, v in list(factorint(n).items()) if k > 1]) -def totient(n): + +class totient(Function): """ Calculate the Euler totient function phi(n) @@ -1306,11 +1311,14 @@ divisor_count """ - n = as_int(n) - if n < 1: - raise ValueError("n must be a positive integer") - factors = factorint(n) - t = 1 - for p, k in factors.items(): - t *= (p-1) * p**(k-1) - return t + @classmethod + def eval(cls, n): + n = sympify(n) + if n.is_Integer: + if n < 1: + raise ValueError("n must be a positive integer") + factors = factorint(n) + t = 1 + for p, k in factors.items(): + t *= (p - 1) * p**(k - 1) + return t diff -Nru python3-sympy-0.7.2/sympy/ntheory/generate.py python3-sympy-0.7.3/sympy/ntheory/generate.py --- python3-sympy-0.7.2/sympy/ntheory/generate.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/ntheory/generate.py 2013-07-13 17:53:32.000000000 +0000 @@ -126,7 +126,7 @@ i = self.search(a)[1] maxi = len(self._list) + 1 while i < maxi: - p = self._list[i-1] + p = self._list[i - 1] if p < b: yield p i += 1 @@ -215,9 +215,10 @@ """ n = as_int(nth) if n < 1: - raise ValueError("nth must be a positive integer; prime(1) == 2"); + raise ValueError("nth must be a positive integer; prime(1) == 2") return sieve[n] + def primepi(n): """ Return the value of the prime counting function pi(n) = the number of prime numbers less than or equal to n. @@ -240,9 +241,9 @@ if n < 2: return 0 else: - n = int(n) return sieve.search(n)[0] + def nextprime(n, ith=1): """ Return the ith prime greater than n. @@ -304,6 +305,7 @@ return n n += 4 + def prevprime(n): """ Return the largest prime smaller than n. @@ -348,6 +350,7 @@ return n n -= 4 + def primerange(a, b): """ Generate a list of all prime numbers in the range [a, b). @@ -428,6 +431,7 @@ else: return + def randprime(a, b): """ Return a random prime number in the range [a, b). @@ -465,6 +469,7 @@ raise ValueError("no primes exist in the specified range") return p + def primorial(n, nth=True): """ Returns the product of the first n primes (default) or @@ -527,6 +532,7 @@ p *= i return p + def cycle_length(f, x0, nmax=None, values=False): """For a given iterated sequence, return a generator that gives the length of the iterated cycle (lambda) and the length of terms @@ -583,7 +589,7 @@ # main phase: search successive powers of two power = lam = 1 - tortoise, hare = x0, f(x0) # f(x0) is the element/node next to x0. + tortoise, hare = x0, f(x0) # f(x0) is the element/node next to x0. i = 0 while tortoise != hare and (not nmax or i < nmax): i += 1 diff -Nru python3-sympy-0.7.2/sympy/ntheory/modular.py python3-sympy-0.7.3/sympy/ntheory/modular.py --- python3-sympy-0.7.2/sympy/ntheory/modular.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/ntheory/modular.py 2013-07-13 17:53:32.000000000 +0000 @@ -6,6 +6,7 @@ from sympy.polys.galoistools import gf_crt, gf_crt1, gf_crt2 from functools import reduce + def symmetric_residue(a, m): """Return the residual mod m such that it is within half of the modulus. @@ -20,6 +21,7 @@ else: return a - m + def crt(m, v, symmetric=False, check=True): r"""Chinese Remainder Theorem. @@ -95,6 +97,7 @@ return symmetric_residue(result, mm), mm return result, mm + def crt1(m): """First part of Chinese Remainder Theorem, for multiple application. @@ -108,6 +111,7 @@ return gf_crt1(m, ZZ) + def crt2(m, v, mm, e, s, symmetric=False): """Second part of Chinese Remainder Theorem, for multiple application. @@ -126,6 +130,7 @@ return symmetric_residue(result, mm), mm return result, mm + def solve_congruence(*remainder_modulus_pairs, **hint): """Compute the integer ``n`` that has the residual ``ai`` when it is divided by ``mi`` where the ``ai`` and ``mi`` are given as pairs to @@ -187,7 +192,6 @@ - http://en.wikipedia.org/wiki/Method_of_successive_substitution """ - from sympy.core.numbers import igcdex a1, m1 = c1 a2, m2 = c2 a, b, c = m1, a2 - a1, m2 diff -Nru python3-sympy-0.7.2/sympy/ntheory/multinomial.py python3-sympy-0.7.3/sympy/ntheory/multinomial.py --- python3-sympy-0.7.2/sympy/ntheory/multinomial.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/ntheory/multinomial.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,6 +1,7 @@ from collections import defaultdict + def binomial_coefficients(n): """Return a dictionary containing pairs :math:`{(k1,k2) : C_kn}` where :math:`C_kn` are binomial coefficients and :math:`n=k1+k2`. @@ -9,20 +10,22 @@ >>> from sympy.ntheory import binomial_coefficients >>> binomial_coefficients(9) - {(0, 9): 1, (1, 8): 9, (2, 7): 36, (3, 6): 84, (4, 5): 126, (5, 4): 126, (6, 3): 84, (7, 2): 36, (8, 1): 9, (9, 0): 1} + {(0, 9): 1, (1, 8): 9, (2, 7): 36, (3, 6): 84, + (4, 5): 126, (5, 4): 126, (6, 3): 84, (7, 2): 36, (8, 1): 9, (9, 0): 1} See Also ======== binomial_coefficients_list, multinomial_coefficients """ - d = {(0, n):1, (n, 0):1} + d = {(0, n): 1, (n, 0): 1} a = 1 - for k in range(1, n//2+1): - a = (a * (n-k+1))//k - d[k, n-k] = d[n-k, k] = a + for k in range(1, n//2 + 1): + a = (a * (n - k + 1))//k + d[k, n - k] = d[n - k, k] = a return d + def binomial_coefficients_list(n): """ Return a list of binomial coefficients as rows of the Pascal's triangle. @@ -39,13 +42,14 @@ binomial_coefficients, multinomial_coefficients """ - d = [1] * (n+1) + d = [1] * (n + 1) a = 1 - for k in range(1, n//2+1): - a = (a * (n-k+1))//k - d[k] = d[n-k] = a + for k in range(1, n//2 + 1): + a = (a * (n - k + 1))//k + d[k] = d[n - k] = a return d + def multinomial_coefficients0(m, n, _tuple=tuple, _zip=zip): """Return a dictionary containing pairs ``{(k1,k2,..,km) : C_kn}`` where ``C_kn`` are multinomial coefficients such that @@ -81,7 +85,7 @@ return {(): 1} if m == 2: return binomial_coefficients(n) - symbols = [(0,)*i + (1,) + (0,)*(m-i-1) for i in range(m)] + symbols = [(0,)*i + (1,) + (0,)*(m - i - 1) for i in range(m)] s0 = symbols[0] p0 = [_tuple(aa - bb for aa, bb in _zip(s, s0)) for s in symbols] r = {_tuple(aa*n for aa in s0): 1} @@ -104,6 +108,7 @@ r.update(r1) return r + def multinomial_coefficients(m, n): r"""Return a dictionary containing pairs ``{(k1,k2,..,km) : C_kn}`` where ``C_kn`` are multinomial coefficients such that @@ -141,7 +146,7 @@ t = [n] + [0] * (m - 1) r = {tuple(t): 1} if n: - j = 0 # j will be the leftmost nonzero position + j = 0 # j will be the leftmost nonzero position else: j = m # enumerate tuples in co-lex order @@ -172,6 +177,7 @@ r[tuple(t)] = (v * tj) // (n - t[0]) return r + def multinomial_coefficients_iterator(m, n, _tuple=tuple): """multinomial coefficient iterator @@ -210,7 +216,7 @@ b = _tuple(filter(None, t1)) yield (t1, mc[b]) if n: - j = 0 # j will be the leftmost nonzero position + j = 0 # j will be the leftmost nonzero position else: j = m # enumerate tuples in co-lex order diff -Nru python3-sympy-0.7.2/sympy/ntheory/partitions_.py python3-sympy-0.7.3/sympy/ntheory/partitions_.py --- python3-sympy-0.7.2/sympy/ntheory/partitions_.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/ntheory/partitions_.py 2013-07-13 17:53:32.000000000 +0000 @@ -5,6 +5,7 @@ from sympy.core.numbers import igcd import math + def _a(n, j, prec): """Compute the inner sum in the HRR formula.""" if j == 1: @@ -12,7 +13,7 @@ s = fzero pi = pi_fixed(prec) for h in range(1, j): - if igcd(h,j) != 1: + if igcd(h, j) != 1: continue # & with mask to compute fractional part of fixed-point number one = 1 << prec @@ -22,13 +23,16 @@ if j >= 3: for k in range(1, j): t = h*k*one//j - if t > 0: frac = t & onemask - else: frac = -((-t) & onemask) + if t > 0: + frac = t & onemask + else: + frac = -((-t) & onemask) g += k*(frac - half) g = ((g - 2*h*n*one)*pi//j) >> prec s = mpf_add(s, mpf_cos(from_man_exp(g, -prec), prec), prec) return s + def _d(n, j, prec, sq23pi, sqrt8): """ Compute the sinh term in the outer sum of the HRR formula. @@ -37,13 +41,14 @@ j = from_int(j) pi = mpf_pi(prec) a = mpf_div(sq23pi, j, prec) - b = mpf_sub(from_int(n), from_rational(1,24,prec), prec) + b = mpf_sub(from_int(n), from_rational(1, 24, prec), prec) c = mpf_sqrt(b, prec) - ch, sh = mpf_cosh_sinh(mpf_mul(a,c), prec) - D = mpf_div(mpf_sqrt(j,prec), mpf_mul(mpf_mul(sqrt8,b),pi), prec) - E = mpf_sub(mpf_mul(a,ch), mpf_div(sh,c,prec), prec) + ch, sh = mpf_cosh_sinh(mpf_mul(a, c), prec) + D = mpf_div(mpf_sqrt(j, prec), mpf_mul(mpf_mul(sqrt8, b), pi), prec) + E = mpf_sub(mpf_mul(a, ch), mpf_div(sh, c, prec), prec) return mpf_mul(D, E) + def npartitions(n, verbose=False): """ Calculate the partition function P(n), i.e. the number of ways that @@ -63,19 +68,21 @@ 1958 """ n = int(n) - if n < 0: return 0 - if n <= 5: return [1, 1, 2, 3, 5, 7][n] + if n < 0: + return 0 + if n <= 5: + return [1, 1, 2, 3, 5, 7][n] # Estimate number of bits in p(n). This formula could be tidied - pbits = int((math.pi*(2*n/3.)**0.5-math.log(4*n))/math.log(10)+1)*\ - math.log(10,2) + pbits = int((math.pi*(2*n/3.)**0.5 - math.log(4*n))/math.log(10) + 1) * \ + math.log(10, 2) prec = p = int(pbits*1.1 + 100) s = fzero - M = max(6, int(0.24*n**0.5+4)) - sq23pi = mpf_mul(mpf_sqrt(from_rational(2,3,p), p), mpf_pi(p), p) + M = max(6, int(0.24*n**0.5 + 4)) + sq23pi = mpf_mul(mpf_sqrt(from_rational(2, 3, p), p), mpf_pi(p), p) sqrt8 = mpf_sqrt(from_int(8), p) for q in range(1, M): - a = _a(n,q,p) - d = _d(n,q,p, sq23pi, sqrt8) + a = _a(n, q, p) + d = _d(n, q, p, sq23pi, sqrt8) s = mpf_add(s, mpf_mul(a, d), prec) if verbose: print("step", q, "of", M, to_str(a, 10), to_str(d, 10)) diff -Nru python3-sympy-0.7.2/sympy/ntheory/primetest.py python3-sympy-0.7.3/sympy/ntheory/primetest.py --- python3-sympy-0.7.2/sympy/ntheory/primetest.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/ntheory/primetest.py 2013-07-13 17:53:32.000000000 +0000 @@ -3,74 +3,59 @@ """ -# prime list to use when number must be tested as a probable prime. -#>>> list(primerange(2, 200)) -_isprime_fallback_primes = [ - 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, - 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, - 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, - 173, 179, 181, 191, 193, 197, 199] -#>>> len(_) -#46 # pseudoprimes that will pass through last mr_safe test _pseudos = set([ 669094855201, - 1052516956501,2007193456621,2744715551581,9542968210729, - 17699592963781,19671510288601, - 24983920772821,24984938689453,29661584268781,37473222618541, - 46856248255981,47922612926653,48103703944453,49110566041153, - 49752242681221,91206655032481,91481980096033,119034193492321, - 123645258399601,128928036060253,137364148720147,150753857310253, - 153131886327421,155216912613121,185610214763821,224334357392701, - 227752294950181,230058334559041,304562854940401,306001576998253, - 335788261073821,377133492079081,379242177424951,389970770948461, - 397319638319521,448114903362253,523235160050221,628999496281621, - 699349238838253,746667678235753,790198268451301,794036495175661, - 823820871230281,867739535711821,1039918661294761,1099127938585141, - 1104388025338153,1173374598605653,1262797719066157,1265872947674653, - 1325898212229667,1327034517143653,1418575746675583,1666122072463621, - 1837400535259453,1857422490084961,1870756820971741,1914550540480717, - 2018963273468221,2163829000939453,2206020317369221,2301037384029121, - 2416062055125421,2435076500074921,2545656135020833,2594428516569781, - 2669983768115821,2690937050990653,2758640869506607,2833525461416653, - 2876662942007221,2932155806957821,2957010595723801,3183606449929153, - 3220133449185901,3424103775720253,3625360152399541,3939300299037421, - 3947917710714841,3980273496750253,4182256679324041,4450605887818261, - 4727893739521501,4750350311306953,4755334362931153,5756440863559753, - 5760976603475341,5794399356078761,5954850603819253,6125544931991761, - 6320931714094861,6347593619672581,6406268028524101,6510632945054941, - 6620082224794741,6627325072566061,6844056606431101,6989404981060153, - 7144293947609521,7288348593229021,7288539837129253,7406102904971689, - 7430233301822341,7576425305871193,7601696719033861,7803926845356487, - 7892007967006633,7947797946559453,8207000460596953,8295064717807513, - 8337196000698841,8352714234009421,8389755717406381,8509654470665701, - 8757647355282841,8903933671696381,8996133652295653,9074421465661261, - 9157536631454221,9188353522314541]) + 1052516956501, 2007193456621, 2744715551581, 9542968210729, + 17699592963781, 19671510288601, + 24983920772821, 24984938689453, 29661584268781, 37473222618541, + 46856248255981, 47922612926653, 48103703944453, 49110566041153, + 49752242681221, 91206655032481, 91481980096033, 119034193492321, + 123645258399601, 128928036060253, 137364148720147, 150753857310253, + 153131886327421, 155216912613121, 185610214763821, 224334357392701, + 227752294950181, 230058334559041, 304562854940401, 306001576998253, + 335788261073821, 377133492079081, 379242177424951, 389970770948461, + 397319638319521, 448114903362253, 523235160050221, 628999496281621, + 699349238838253, 746667678235753, 790198268451301, 794036495175661, + 823820871230281, 867739535711821, 1039918661294761, 1099127938585141, + 1104388025338153, 1173374598605653, 1262797719066157, 1265872947674653, + 1325898212229667, 1327034517143653, 1418575746675583, 1666122072463621, + 1837400535259453, 1857422490084961, 1870756820971741, 1914550540480717, + 2018963273468221, 2163829000939453, 2206020317369221, 2301037384029121, + 2416062055125421, 2435076500074921, 2545656135020833, 2594428516569781, + 2669983768115821, 2690937050990653, 2758640869506607, 2833525461416653, + 2876662942007221, 2932155806957821, 2957010595723801, 3183606449929153, + 3220133449185901, 3424103775720253, 3625360152399541, 3939300299037421, + 3947917710714841, 3980273496750253, 4182256679324041, 4450605887818261, + 4727893739521501, 4750350311306953, 4755334362931153, 5756440863559753, + 5760976603475341, 5794399356078761, 5954850603819253, 6125544931991761, + 6320931714094861, 6347593619672581, 6406268028524101, 6510632945054941, + 6620082224794741, 6627325072566061, 6844056606431101, 6989404981060153, + 7144293947609521, 7288348593229021, 7288539837129253, 7406102904971689, + 7430233301822341, 7576425305871193, 7601696719033861, 7803926845356487, + 7892007967006633, 7947797946559453, 8207000460596953, 8295064717807513, + 8337196000698841, 8352714234009421, 8389755717406381, 8509654470665701, + 8757647355282841, 8903933671696381, 8996133652295653, 9074421465661261, + 9157536631454221, 9188353522314541]) -def _test(n, base): + +def _test(n, base, s, t): """Miller-Rabin strong pseudoprime test for one base. Return False if n is definitely composite, True if n is probably prime, with a probability greater than 3/4. """ - from sympy.ntheory.factor_ import trailing - - n = int(n) - if n < 2: - return False - # remove powers of 2 from n (= t * 2**s) - s = trailing(n - 1) - t = n >> s # do the Fermat test b = pow(base, t, n) - if b == 1 or b == n-1: + if b == 1 or b == n - 1: return True else: for j in range(1, s): - b = (b**2) % n - if b == n-1: + b = pow(b, 2, n) + if b == n - 1: return True return False + def mr(n, bases): """Perform a Miller-Rabin strong pseudoprime test on n using a given list of bases/witnesses. @@ -82,7 +67,8 @@ A Computational Perspective", Springer, 2nd edition, 135-138 A list of thresholds and the bases they require are here: - http://en.wikipedia.org/wiki/Miller%E2%80%93Rabin_primality_test#Deterministic_variants_of_the_test + http://en.wikipedia.org/wiki/ + Miller%E2%80%93Rabin_primality_test#Deterministic_variants_of_the_test Examples ======== @@ -93,12 +79,22 @@ >>> mr(479001599, [31, 73]) True """ + from sympy.ntheory.factor_ import trailing + from sympy.polys.domains import ZZ + n = int(n) + if n < 2: + return False + # remove powers of 2 from n (= t * 2**s) + s = trailing(n - 1) + t = n >> s for base in bases: - if not _test(n, base): + base = ZZ(base) + if not _test(n, base, s, t): return False return True + def _mr_safe(n): """For n < 10**16, use the Miller-Rabin test to determine with certainty (unless the code is buggy!) whether n is prime. @@ -147,7 +143,7 @@ return mr(n, [350, 3958281543]) # [350, 3958281543] stot = 1 clear [2, 3, 5, 7, 29, 67, 679067] if n < 4759123141: - return mr(n, [2, 7, 61]) # ref [3] + return mr(n, [2, 7, 61]) # ref [3] # [2, 7, 61] stot = 3 clear == bases if n < 75792980677: return mr(n, [2, 379215, 457083754]) @@ -170,6 +166,7 @@ # [2, 3, 7, 61, 24251] stot = 5 clear == bases raise ValueError("n too large") + def isprime(n): """ Test if n is a prime number (True) or not (False). For n < 10**16 the @@ -181,9 +178,9 @@ The function first looks for trivial factors, and if none is found, performs a safe Miller-Rabin strong pseudoprime test with bases that are known to prove a number prime. Finally, a general Miller-Rabin - test is done with the first k bases which, which will report a - pseudoprime as a prime with an error of about 4**-k. The current value - of k is 46 so the error is about 2 x 10**-28. + test is done with the first k bases which will report a pseudoprime as a + prime with an error of about 4**-k. The current value of k is 46 so the + error is about 2 x 10**-28. Examples ======== @@ -218,7 +215,15 @@ try: return _mr_safe(n) except ValueError: - return mr(n, _isprime_fallback_primes) + # prime list to use when number must be tested as a probable prime; + # these are the 46 primes less than 200 + bases = [ + 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, + 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, + 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, + 173, 179, 181, 191, 193, 197, 199] + return mr(n, bases) + def _mr_safe_helper(_s): """ @@ -249,7 +254,7 @@ factors = [] tot = 0 for b in bases: - tot += trailing(b-1) + tot += trailing(b - 1) f = factorint(b) factors.extend(f) factors = sorted(set(factors)) @@ -259,7 +264,7 @@ else: factors = str(factors) return ' # %s stot = %s clear %s' % tuple( - [str(x).replace('L','') for x in (list(bases), tot, factors)]) + [str(x).replace('L', '') for x in (list(bases), tot, factors)]) _r = [int(_x) for _x in _s.split('[')[1].split(']')[0].split(',')] return _info(_r) diff -Nru python3-sympy-0.7.2/sympy/ntheory/residue_ntheory.py python3-sympy-0.7.3/sympy/ntheory/residue_ntheory.py --- python3-sympy-0.7.2/sympy/ntheory/residue_ntheory.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/ntheory/residue_ntheory.py 2013-07-13 17:53:32.000000000 +0000 @@ -3,6 +3,7 @@ from .primetest import isprime from .factor_ import factorint, trailing, totient + def n_order(a, n): """Returns the order of ``a`` modulo ``n``. @@ -150,6 +151,7 @@ else: return -1 + def jacobi_symbol(m, n): """ Returns the product of the legendre_symbol(m, p) diff -Nru python3-sympy-0.7.2/sympy/ntheory/tests/test_ntheory.py python3-sympy-0.7.3/sympy/ntheory/tests/test_ntheory.py --- python3-sympy-0.7.2/sympy/ntheory/tests/test_ntheory.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/ntheory/tests/test_ntheory.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,6 +1,7 @@ from sympy import Sieve, binomial_coefficients, binomial_coefficients_list, \ - multinomial_coefficients, Mul, S, Pow, sieve -from sympy import factorial as fac + multinomial_coefficients, Mul, S, Pow, sieve, Symbol, summation, Dummy, \ + factorial as fac, Rational +from sympy.core.numbers import Integer from sympy.ntheory import isprime, n_order, is_primitive_root, \ is_quad_residue, legendre_symbol, jacobi_symbol, npartitions, totient, \ @@ -17,6 +18,7 @@ from sympy.utilities.iterables import capture from sympy.ntheory.multinomial import multinomial_coefficients_iterator + def test_trailing(): assert trailing(0) == 0 assert trailing(1) == 0 @@ -25,10 +27,11 @@ assert trailing(7) == 0 assert trailing(-7) == 0 for i in range(100): - assert trailing((1< n: return 0 - if p > n//2: return 1 + if p > n: + return 0 + if p > n//2: + return 1 q, m = n, 0 while q >= p: q //= p m += q return m + def multiproduct(seq=(), start=1): """ Return the product of a sequence of factors with multiplicities, @@ -228,38 +248,40 @@ multi.append((base, exp//2)) return units * multiproduct(multi)**2 + def test_factorint(): assert primefactors(123456) == [2, 3, 643] - assert factorint(0) == {0:1} + assert factorint(0) == {0: 1} assert factorint(1) == {} - assert factorint(-1) == {-1:1} - assert factorint(-2) == {-1:1, 2:1} - assert factorint(-16) == {-1:1, 2:4} - assert factorint(2) == {2:1} - assert factorint(126) == {2:1, 3:2, 7:1} - assert factorint(123456) == {2:6, 3:1, 643:1} - assert factorint(5951757) == {3:1, 7:1, 29:2, 337:1} - assert factorint(64015937) == {7993:1, 8009:1} - assert factorint(2**(2**6) + 1) == {274177:1, 67280421310721:1} + assert factorint(-1) == {-1: 1} + assert factorint(-2) == {-1: 1, 2: 1} + assert factorint(-16) == {-1: 1, 2: 4} + assert factorint(2) == {2: 1} + assert factorint(126) == {2: 1, 3: 2, 7: 1} + assert factorint(123456) == {2: 6, 3: 1, 643: 1} + assert factorint(5951757) == {3: 1, 7: 1, 29: 2, 337: 1} + assert factorint(64015937) == {7993: 1, 8009: 1} + assert factorint(2**(2**6) + 1) == {274177: 1, 67280421310721: 1} assert multiproduct(factorint(fac(200))) == fac(200) for b, e in list(factorint(fac(150)).items()): assert e == fac_multiplicity(150, b) - assert factorint(103005006059**7) == {103005006059:7} - assert factorint(31337**191) == {31337:191} + assert factorint(103005006059**7) == {103005006059: 7} + assert factorint(31337**191) == {31337: 191} assert factorint(2**1000 * 3**500 * 257**127 * 383**60) == \ - {2:1000, 3:500, 257:127, 383:60} + {2: 1000, 3: 500, 257: 127, 383: 60} assert len(factorint(fac(10000))) == 1229 assert factorint(12932983746293756928584532764589230) == \ {2: 1, 5: 1, 73: 1, 727719592270351: 1, 63564265087747: 1, 383: 1} - assert factorint(727719592270351) == {727719592270351:1} - assert factorint(2**64+1, use_trial=False) == factorint(2**64+1) + assert factorint(727719592270351) == {727719592270351: 1} + assert factorint(2**64 + 1, use_trial=False) == factorint(2**64 + 1) for n in range(60000): assert multiproduct(factorint(n)) == n - assert pollard_rho(2**64+1, seed=1) == 274177 + assert pollard_rho(2**64 + 1, seed=1) == 274177 assert pollard_rho(19, seed=1) is None assert factorint(3, limit=2) == {3: 1} assert factorint(12345) == {3: 1, 5: 1, 823: 1} - assert factorint(12345, limit=3) == {4115: 1, 3: 1} # the 5 is greater than the limit + assert factorint( + 12345, limit=3) == {4115: 1, 3: 1} # the 5 is greater than the limit assert factorint(1, limit=1) == {} assert factorint(12, limit=1) == {12: 1} assert factorint(30, limit=2) == {2: 1, 15: 1} @@ -272,12 +294,12 @@ assert factorint(p1*p2*p3) == {p1: 1, p2: 1, p3: 1} assert factorint(13*17*19, limit=15) == {13: 1, 17*19: 1} assert factorint(1951*15013*15053, limit=2000) == {225990689: 1, 1951: 1} - assert factorint(primorial(17)+1, use_pm1=0) == \ - {19026377261: 1, 3467: 1, 277: 1, 105229: 1} + assert factorint(primorial(17) + 1, use_pm1=0) == \ + {19026377261: 1, 3467: 1, 277: 1, 105229: 1} # when prime b is closer than approx sqrt(8*p) to prime p then they are # "close" and have a trivial factorization - a=nextprime(2**2**8) # 78 digits - b=nextprime(a + 2**2**4) + a = nextprime(2**2**8) # 78 digits + b = nextprime(a + 2**2**4) assert 'Fermat' in capture(lambda: factorint(a*b, verbose=1)) raises(ValueError, lambda: pollard_rho(4)) @@ -288,31 +310,34 @@ assert 'with primes' in capture(lambda: factorint(n, verbose=1)) capture(lambda: factorint(nextprime(2**16)*1012, verbose=1)) - n=nextprime(2**17) - capture(lambda: factorint(n**3, verbose=1)) # perfect power termination - capture(lambda: factorint(2*n, verbose=1)) # factoring complete msg + n = nextprime(2**17) + capture(lambda: factorint(n**3, verbose=1)) # perfect power termination + capture(lambda: factorint(2*n, verbose=1)) # factoring complete msg # exceed 1st - n=nextprime(2**17) - n*=nextprime(n) + n = nextprime(2**17) + n *= nextprime(n) assert '1000' in capture(lambda: factorint(n, limit=1000, verbose=1)) - n*=nextprime(n) + n *= nextprime(n) assert len(factorint(n)) == 3 assert len(factorint(n, limit=p1)) == 3 - n*=nextprime(2*n) + n *= nextprime(2*n) # exceed 2nd assert '2001' in capture(lambda: factorint(n, limit=2000, verbose=1)) - assert capture(lambda: factorint(n, limit=4000, verbose=1)).count('Pollard') == 2 + assert capture( + lambda: factorint(n, limit=4000, verbose=1)).count('Pollard') == 2 # non-prime pm1 result - n=nextprime(8069) - n*=nextprime(2*n)*nextprime(2*n, 2) - capture(lambda: factorint(n, verbose=1)) # non-prime pm1 result + n = nextprime(8069) + n *= nextprime(2*n)*nextprime(2*n, 2) + capture(lambda: factorint(n, verbose=1)) # non-prime pm1 result # factor fermat composite p1 = nextprime(2**17) p2 = nextprime(2*p1) assert factorint((p1*p2**2)**3) == {p1: 3, p2: 6} + # Test for non integer input + raises(ValueError, lambda: factorint(4.5)) -def divisors_and_divisor_count(): +def test_divisors_and_divisor_count(): assert divisors(-1) == [1] assert divisors(0) == [] assert divisors(1) == [1] @@ -332,12 +357,23 @@ assert divisor_count(180, 3) == divisor_count(180//3) assert divisor_count(2*3*5, 7) == 0 +def test_issue3882(): + S = set(divisors(4)).union(set(divisors(Integer(2)))) + assert S == set([1,2,4]) + def test_totient(): assert [totient(k) for k in range(1, 12)] == \ [1, 1, 2, 2, 4, 2, 6, 4, 6, 4, 10] assert totient(5005) == 2880 assert totient(5006) == 2502 assert totient(5009) == 5008 + assert totient(2**100) == 2**99 + + m = Symbol("m", integer=True) + assert totient(m) + assert totient(m).subs(m, 3**10) == 3**10 - 3**9 + assert summation(totient(m), (m, 1, 11)) == 42 + def test_partitions(): assert [npartitions(k) for k in range(13)] == \ @@ -349,6 +385,7 @@ assert npartitions(10000) % 10**10 == 6916435144 assert npartitions(100000) % 10**10 == 9421098519 + def test_residue(): assert n_order(2, 13) == 12 assert [n_order(a, 7) for a in range(1, 7)] == \ @@ -357,20 +394,20 @@ assert n_order(17, 11) == n_order(6, 11) assert n_order(101, 119) == 6 - assert is_primitive_root(2, 7) == False - assert is_primitive_root(3, 8) == False - assert is_primitive_root(11, 14) == False + assert is_primitive_root(2, 7) is False + assert is_primitive_root(3, 8) is False + assert is_primitive_root(11, 14) is False assert is_primitive_root(12, 17) == is_primitive_root(29, 17) - assert is_quad_residue(3, 7) == False - assert is_quad_residue(10, 13) == True + assert is_quad_residue(3, 7) is False + assert is_quad_residue(10, 13) is True assert is_quad_residue(12364, 139) == is_quad_residue(12364 % 139, 139) - assert is_quad_residue(207, 251) == True - assert is_quad_residue(0, 1) == True - assert is_quad_residue(1, 1) == True - assert is_quad_residue(0, 2) == is_quad_residue(1, 2) == True - assert is_quad_residue(1, 4) == True - assert is_quad_residue(2, 27) == False + assert is_quad_residue(207, 251) is True + assert is_quad_residue(0, 1) is True + assert is_quad_residue(1, 1) is True + assert is_quad_residue(0, 2) == is_quad_residue(1, 2) is True + assert is_quad_residue(1, 4) is True + assert is_quad_residue(2, 27) is False assert [j for j in range(14) if is_quad_residue(j, 14)] == \ [0, 1, 2, 4, 7, 8, 9, 11] raises(ValueError, lambda: is_quad_residue(1.1, 2)) @@ -394,11 +431,13 @@ assert jacobi_symbol(1, 3) == 1 raises(ValueError, lambda: jacobi_symbol(3, 8)) + def test_hex_pi_nth_digits(): assert pi_hex_digits(0) == '3243f6a8885a30' assert pi_hex_digits(1) == '243f6a8885a308' assert pi_hex_digits(10000) == '68ac8fcfb8016c' + def test_crt(): def mcrt(m, v, r, symmetric=False): assert crt(m, v, symmetric)[0] == r @@ -413,6 +452,7 @@ assert crt([656, 350], [811, 133], symmetric=True) == (-56917, 114800) + def test_binomial_coefficients_list(): assert binomial_coefficients_list(0) == [1] assert binomial_coefficients_list(1) == [1, 1] @@ -422,12 +462,14 @@ assert binomial_coefficients_list(5) == [1, 5, 10, 10, 5, 1] assert binomial_coefficients_list(6) == [1, 6, 15, 20, 15, 6, 1] + def test_binomial_coefficients(): for n in range(15): c = binomial_coefficients(n) l = [c[k] for k in sorted(c)] assert l == binomial_coefficients_list(n) + def test_multinomial_coefficients(): assert multinomial_coefficients(1, 1) == {(1,): 1} assert multinomial_coefficients(1, 2) == {(2,): 1} @@ -446,27 +488,32 @@ (1, 0, 2): 3, (0, 2, 1): 3, (0, 1, 2): 3, (3, 0, 0): 1, (2, 0, 1): 3, (1, 2, 0): 3, (1, 1, 1): 6, (0, 0, 3): 1} assert dict(multinomial_coefficients_iterator(2, 0)) == {(0, 0): 1} - assert dict(multinomial_coefficients_iterator(2, 1)) == {(0, 1): 1, (1, 0): 1} + assert dict( + multinomial_coefficients_iterator(2, 1)) == {(0, 1): 1, (1, 0): 1} assert dict(multinomial_coefficients_iterator(2, 2)) == \ {(2, 0): 1, (0, 2): 1, (1, 1): 2} assert dict(multinomial_coefficients_iterator(3, 3)) == mc it = multinomial_coefficients_iterator(7, 2) assert [next(it) for i in range(4)] == \ - [((2, 0, 0, 0, 0, 0, 0), 1), ((1, 1, 0, 0, 0, 0, 0), 2), + [((2, 0, 0, 0, 0, 0, 0), 1), ((1, 1, 0, 0, 0, 0, 0), 2), ((0, 2, 0, 0, 0, 0, 0), 1), ((1, 0, 1, 0, 0, 0, 0), 2)] + def test_issue1257(): assert factorint(1030903) == {53: 2, 367: 1} + def test_divisors(): assert divisors(28) == [1, 2, 4, 7, 14, 28] assert [x for x in divisors(3*5*7, 1)] == [1, 3, 5, 15, 7, 21, 35, 105] assert divisors(0) == [] + def test_divisor_count(): assert divisor_count(0) == 0 assert divisor_count(6) == 4 + def test_primorial(): assert primorial(1) == 2 assert primorial(1, nth=0) == 1 @@ -474,6 +521,7 @@ assert primorial(2, nth=0) == 2 assert primorial(4, nth=0) == 6 + def test_smoothness_and_smoothness_p(): assert smoothness(1) == (1, 1) assert smoothness(2**4*3**2) == (3, 16) @@ -488,6 +536,7 @@ 'p**i=4410317**1 has p-1 B=1787, B-pow=1787\n' + \ 'p**i=4869863**1 has p-1 B=2434931, B-pow=2434931' + def test_visual_factorint(): assert factorint(1, visual=1) == 1 forty2 = factorint(42, visual=True) @@ -500,6 +549,7 @@ Pow(7, 2, **no), **no) assert -1 in factorint(-42, visual=True).args + def test_visual_io(): sm = smoothness_p fi = factorint @@ -515,7 +565,7 @@ for th in [d, s, t, n, m]: assert sm(th, visual=False) == t assert [sm(th, visual=None) for th in [d, s, t, n, m]] == [s, d, s, t, t] - assert [sm(th, visual=0) for th in [d, s, t, n, m]] == [s, d, s, t, t] + assert [sm(th, visual=2) for th in [d, s, t, n, m]] == [s, d, s, t, t] # with factorint for th in [d, m, n]: @@ -536,17 +586,23 @@ assert fi(Mul(*[Pow(k, v, **no) for k, v in list({4: 2, 2: 6}.items())], **no), visual=False) == fi(2**10) + def test_modular(): assert solve_congruence(*list(zip([3, 4, 2], [12, 35, 17]))) == (1719, 7140) assert solve_congruence(*list(zip([3, 4, 2], [12, 6, 17]))) is None assert solve_congruence(*list(zip([3, 4, 2], [13, 7, 17]))) == (172, 1547) assert solve_congruence(*list(zip([-10, -3, -15], [13, 7, 17]))) == (172, 1547) assert solve_congruence(*list(zip([-10, -3, 1, -15], [13, 7, 7, 17]))) is None - assert solve_congruence(*list(zip([-10, -5, 2, -15], [13, 7, 7, 17]))) == (835, 1547) - assert solve_congruence(*list(zip([-10, -5, 2, -15], [13, 7, 14, 17]))) == (2382, 3094) - assert solve_congruence(*list(zip([-10, 2, 2, -15], [13, 7, 14, 17]))) == (2382, 3094) - assert solve_congruence(*list(zip((1, 1, 2),(3, 2, 4)))) is None - raises(ValueError, lambda: solve_congruence(*list(zip([3, 4, 2], [12.1, 35, 17])))) + assert solve_congruence( + *list(zip([-10, -5, 2, -15], [13, 7, 7, 17]))) == (835, 1547) + assert solve_congruence( + *list(zip([-10, -5, 2, -15], [13, 7, 14, 17]))) == (2382, 3094) + assert solve_congruence( + *list(zip([-10, 2, 2, -15], [13, 7, 14, 17]))) == (2382, 3094) + assert solve_congruence(*list(zip((1, 1, 2), (3, 2, 4)))) is None + raises( + ValueError, lambda: solve_congruence(*list(zip([3, 4, 2], [12.1, 35, 17])))) + def test_search(): assert 2 in sieve diff -Nru python3-sympy-0.7.2/sympy/parsing/ast_parser.py python3-sympy-0.7.3/sympy/parsing/ast_parser.py --- python3-sympy-0.7.2/sympy/parsing/ast_parser.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/parsing/ast_parser.py 2013-07-13 17:53:32.000000000 +0000 @@ -29,7 +29,7 @@ try: from ast import parse, NodeTransformer, Call, Name, Load, \ - fix_missing_locations, Str, Tuple + fix_missing_locations, Str, Tuple ast_enabled = True except ImportError: ast_enabled = False @@ -68,9 +68,11 @@ def visit_Lambda(self, node): args = [self.visit(arg) for arg in node.args.args] body = self.visit(node.body) - n = Call(Name('Lambda', Load()), [Tuple(args, Load()), body], [], None, None) + n = Call(Name('Lambda', Load()), + [Tuple(args, Load()), body], [], None, None) return fix_missing_locations(n) + def parse_expr(s, local_dict): """ Converts the string "s" to a SymPy expression, in local_dict. @@ -84,7 +86,7 @@ try: a = parse(s.strip(), mode="eval") except SyntaxError: - raise SympifyError("Cannot parse %s." %repr(s)) + raise SympifyError("Cannot parse %s." % repr(s)) a = Transform(local_dict, global_dict).visit(a) e = compile(a, "", "eval") return eval(e, global_dict, local_dict) @@ -95,4 +97,4 @@ try: return SymPyParser(local_dict=local_dict).parse_expr(s) except SyntaxError: - raise SympifyError("Cannot parse %s." %repr(s)) + raise SympifyError("Cannot parse %s." % repr(s)) diff -Nru python3-sympy-0.7.2/sympy/parsing/mathematica.py python3-sympy-0.7.3/sympy/parsing/mathematica.py --- python3-sympy-0.7.2/sympy/parsing/mathematica.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/parsing/mathematica.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,33 +1,36 @@ from re import match from sympy import sympify -def mathematica (s): + +def mathematica(s): return sympify(parse(s)) -def parse (s): + +def parse(s): s = s.strip() #Begin rules rules = ( - (r"\A(\w+)\[([^\]]+[^\[]*)\]\Z", #Function call - lambda m: translateFunction(m.group(1)) + "(" + parse(m.group(2)) + ")" ), + (r"\A(\w+)\[([^\]]+[^\[]*)\]\Z", # Function call + lambda m: translateFunction( + m.group(1)) + "(" + parse(m.group(2)) + ")" ), - (r"\((.+)\)\((.+)\)", #Parenthesized implied multiplication + (r"\((.+)\)\((.+)\)", # Parenthesized implied multiplication lambda m: "(" + parse(m.group(1)) + ")*(" + parse(m.group(2)) + ")" ), - (r"\A\((.+)\)\Z", #Parenthesized expression + (r"\A\((.+)\)\Z", # Parenthesized expression lambda m: "(" + parse(m.group(1)) + ")" ), - (r"\A(.*[\w\.])\((.+)\)\Z", #Implied multiplication - a(b) + (r"\A(.*[\w\.])\((.+)\)\Z", # Implied multiplication - a(b) lambda m: parse(m.group(1)) + "*(" + parse(m.group(2)) + ")" ), - (r"\A\((.+)\)([\w\.].*)\Z", #Implied multiplication - (a)b + (r"\A\((.+)\)([\w\.].*)\Z", # Implied multiplication - (a)b lambda m: "(" + parse(m.group(1)) + ")*" + parse(m.group(2)) ), - (r"\A([\d\.]+)([a-zA-Z].*)\Z", #Implied multiplicatin - 2a + (r"\A([\d\.]+)([a-zA-Z].*)\Z", # Implied multiplicatin - 2a lambda m: parse(m.group(1)) + "*" + parse(m.group(2)) ), - (r"\A([^=]+)([\^\-\*/\+=]=?)(.+)\Z", #Infix operator + (r"\A([^=]+)([\^\-\*/\+=]=?)(.+)\Z", # Infix operator lambda m: parse(m.group(1)) + translateOperator(m.group(2)) + parse(m.group(3)) )) #End rules @@ -38,13 +41,15 @@ return s -def translateFunction (s): + +def translateFunction(s): if s.startswith("Arc"): return "a" + s[3:] return s.lower() -def translateOperator (s): - dictionary = {'^':'**'} + +def translateOperator(s): + dictionary = {'^': '**'} if s in dictionary: return dictionary[s] return s diff -Nru python3-sympy-0.7.2/sympy/parsing/maxima.py python3-sympy-0.7.3/sympy/parsing/maxima.py --- python3-sympy-0.7.2/sympy/parsing/maxima.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/parsing/maxima.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,6 +1,7 @@ import re from sympy import sympify, Sum, product, sin, cos + class MaximaHelpers: def maxima_expand(expr): return expr.expand() @@ -14,8 +15,8 @@ def maxima_sum(a1, a2, a3, a4): return Sum(a1, (a2, a3, a4)).doit() - def maxima_product(a1,a2,a3,a4): - return product(a1, (a2,a3,a4)) + def maxima_product(a1, a2, a3, a4): + return product(a1, (a2, a3, a4)) def maxima_csc(expr): return 1/sin(expr) @@ -24,30 +25,31 @@ return 1/cos(expr) sub_dict = { - 'pi' : re.compile('%pi'), - 'E' : re.compile('%e'), - 'I' : re.compile('%i'), - '**': re.compile('\^'), - 'oo': re.compile(r'\binf\b'), - '-oo': re.compile(r'\bminf\b'), - "'-'" : re.compile(r'\bminus\b'), - 'maxima_expand' : re.compile(r'\bexpand\b'), - 'maxima_float' : re.compile(r'\bfloat\b'), - 'maxima_trigexpand' : re.compile(r'\btrigexpand'), - 'maxima_sum' : re.compile(r'\bsum\b'), - 'maxima_product' : re.compile(r'\bproduct\b'), - 'cancel' : re.compile(r'\bratsimp\b'), - 'maxima_csc' : re.compile(r'\bcsc\b'), - 'maxima_sec' : re.compile(r'\bsec\b') + 'pi': re.compile('%pi'), + 'E': re.compile('%e'), + 'I': re.compile('%i'), + '**': re.compile('\^'), + 'oo': re.compile(r'\binf\b'), + '-oo': re.compile(r'\bminf\b'), + "'-'": re.compile(r'\bminus\b'), + 'maxima_expand': re.compile(r'\bexpand\b'), + 'maxima_float': re.compile(r'\bfloat\b'), + 'maxima_trigexpand': re.compile(r'\btrigexpand'), + 'maxima_sum': re.compile(r'\bsum\b'), + 'maxima_product': re.compile(r'\bproduct\b'), + 'cancel': re.compile(r'\bratsimp\b'), + 'maxima_csc': re.compile(r'\bcsc\b'), + 'maxima_sec': re.compile(r'\bsec\b') } var_name = re.compile('^\s*(\w+)\s*:') + def parse_maxima(str, globals=None, name_dict={}): str = str.strip() str = str.rstrip('; ') - for k,v in list(sub_dict.items()): + for k, v in list(sub_dict.items()): str = v.sub(k, str) assign_var = None @@ -58,7 +60,7 @@ dct = MaximaHelpers.__dict__.copy() dct.update(name_dict) - obj = sympify(str, locals= dct) + obj = sympify(str, locals=dct) if assign_var and globals: globals[assign_var] = obj diff -Nru python3-sympy-0.7.2/sympy/parsing/sympy_parser.py python3-sympy-0.7.3/sympy/parsing/sympy_parser.py --- python3-sympy-0.7.2/sympy/parsing/sympy_parser.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/parsing/sympy_parser.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,17 +1,54 @@ """Transform a string with Python-like source code into SymPy expression. """ from .sympy_tokenize import \ - generate_tokens, untokenize, TokenError, NUMBER, STRING, NAME, OP + generate_tokens, untokenize, TokenError, \ + NUMBER, STRING, NAME, OP, ENDMARKER from keyword import iskeyword from io import StringIO import re +import unicodedata from sympy.core.basic import Basic, C import collections _re_repeated = re.compile(r"^(\d*)\.(\d*)\[(\d+)\]$") +def _token_splittable(token): + """ + Predicate for whether a token name can be split into multiple tokens. + + A token is splittable if it does not contain an underscore character and + it is not the name of a Greek letter. This is used to implicitly convert + expressions like 'xyz' into 'x*y*z'. + """ + if '_' in token: + return False + else: + try: + return not unicodedata.lookup('GREEK SMALL LETTER ' + token) + except KeyError: + pass + if len(token) > 1: + return True + return False + + +def _token_callable(token, local_dict, global_dict, nextToken=None): + """ + Predicate for whether a token name represents a callable function. + """ + func = local_dict.get(token[1]) + if not func: + func = global_dict.get(token[1]) + is_Function = getattr(func, 'is_Function', False) + if (is_Function or + (isinstance(func, collections.Callable) and not hasattr(func, 'is_Function')) or + isinstance(nextToken, AppliedFunction)): + return True + return False + + def _add_factorial_tokens(name, result): if result == [] or result[-1][1] == '(': raise TokenError() @@ -24,7 +61,7 @@ for index, token in enumerate(result[::-1]): toknum, tokval = token - i = length-index-1 + i = length - index - 1 if tokval == ')': diff += 1 @@ -32,20 +69,498 @@ diff -= 1 if diff == 0: - if i-1 >= 0 and result[i-1][0] == NAME: - return result[:i-1] + beginning + result[i-1:] + end + if i - 1 >= 0 and result[i - 1][0] == NAME: + return result[:i - 1] + beginning + result[i - 1:] + end else: return result[:i] + beginning + result[i:] + end return result -def _transform(s, local_dict, global_dict, rationalize, convert_xor): - g = generate_tokens(StringIO(s).readline) +class AppliedFunction(object): + """ + A group of tokens representing a function and its arguments. + + `exponent` is for handling the shorthand sin^2, ln^2, etc. + """ + def __init__(self, function, args, exponent=None): + if exponent is None: + exponent = [] + self.function = function + self.args = args + self.exponent = exponent + self.items = ['function', 'args', 'exponent'] + + def expand(self): + """Return a list of tokens representing the function""" + result = [] + result.append(self.function) + result.extend(self.args) + return result + + def __getitem__(self, index): + return getattr(self, self.items[index]) + + def __repr__(self): + return "AppliedFunction(%s, %s, %s)" % (self.function, self.args, + self.exponent) + + +class ParenthesisGroup(list): + """List of tokens representing an expression in parentheses.""" + pass + + +def _flatten(result): + result2 = [] + for tok in result: + if isinstance(tok, AppliedFunction): + result2.extend(tok.expand()) + else: + result2.append(tok) + return result2 + + +def _group_parentheses(recursor): + def _inner(tokens, local_dict, global_dict): + """Group tokens between parentheses with ParenthesisGroup. + + Also processes those tokens recursively. + + """ + result = [] + stacks = [] + stacklevel = 0 + for token in tokens: + if token[0] == OP: + if token[1] == '(': + stacks.append(ParenthesisGroup([])) + stacklevel += 1 + elif token[1] == ')': + stacks[-1].append(token) + stack = stacks.pop() + + if len(stacks) > 0: + # We don't recurse here since the upper-level stack + # would reprocess these tokens + stacks[-1].extend(stack) + else: + # Recurse here to handle nested parentheses + # Strip off the outer parentheses to avoid an infinite loop + inner = stack[1:-1] + inner = recursor(inner, + local_dict, + global_dict) + parenGroup = [stack[0]] + inner + [stack[-1]] + result.append(ParenthesisGroup(parenGroup)) + stacklevel -= 1 + continue + if stacklevel: + stacks[-1].append(token) + else: + result.append(token) + return result + return _inner + + +def _apply_functions(tokens, local_dict, global_dict): + """Convert a NAME token + ParenthesisGroup into an AppliedFunction. + + Note that ParenthesisGroups, if not applied to any function, are + converted back into lists of tokens. + + """ + result = [] + symbol = None + for tok in tokens: + if tok[0] == NAME: + symbol = tok + result.append(tok) + elif isinstance(tok, ParenthesisGroup): + if symbol: + result[-1] = AppliedFunction(symbol, tok) + symbol = None + else: + result.extend(tok) + else: + symbol = None + result.append(tok) + return result + + +def _implicit_multiplication(tokens, local_dict, global_dict): + """Implicitly adds '*' tokens. + + Cases: + + - Two AppliedFunctions next to each other ("sin(x)cos(x)") + + - AppliedFunction next to an open parenthesis ("sin x (cos x + 1)") + + - A close parenthesis next to an AppliedFunction ("(x+2)sin x")\ + + - A close parenthesis next to an open parenthesis ("(x+2)(x+3)") + + - AppliedFunction next to an implicitly applied function ("sin(x)cos x") + + """ + result = [] + for tok, nextTok in zip(tokens, tokens[1:]): + result.append(tok) + if (isinstance(tok, AppliedFunction) and + isinstance(nextTok, AppliedFunction)): + result.append((OP, '*')) + elif (isinstance(tok, AppliedFunction) and + nextTok[0] == OP and nextTok[1] == '('): + # Applied function followed by an open parenthesis + result.append((OP, '*')) + elif (tok[0] == OP and tok[1] == ')' and + isinstance(nextTok, AppliedFunction)): + # Close parenthesis followed by an applied function + result.append((OP, '*')) + elif (tok[0] == OP and tok[1] == ')' and + nextTok[0] == NAME): + # Close parenthesis followed by an implicitly applied function + result.append((OP, '*')) + elif (tok[0] == nextTok[0] == OP + and tok[1] == ')' and nextTok[1] == '('): + # Close parenthesis followed by an open parenthesis + result.append((OP, '*')) + elif (isinstance(tok, AppliedFunction) and nextTok[0] == NAME): + # Applied function followed by implicitly applied function + result.append((OP, '*')) + result.append(tokens[-1]) + return result + + +def _implicit_application(tokens, local_dict, global_dict): + """Adds parentheses as needed after functions.""" + result = [] + appendParen = 0 # number of closing parentheses to add + skip = 0 # number of tokens to delay before adding a ')' (to + # capture **, ^, etc.) + exponentSkip = False # skipping tokens before inserting parentheses to + # work with function exponentiation + for tok, nextTok in zip(tokens, tokens[1:]): + result.append(tok) + if (tok[0] == NAME and + nextTok[0] != OP and + nextTok[0] != ENDMARKER): + if _token_callable(tok, local_dict, global_dict, nextTok): + result.append((OP, '(')) + appendParen += 1 + # name followed by exponent - function exponentiation + elif (tok[0] == NAME and nextTok[0] == OP and nextTok[1] == '**'): + if _token_callable(tok, local_dict, global_dict): + exponentSkip = True + elif exponentSkip: + # if the last token added was an applied function (i.e. the + # power of the function exponent) OR a multiplication (as + # implicit multiplication would have added an extraneous + # multiplication) + if (isinstance(tok, AppliedFunction) + or (tok[0] == OP and tok[1] == '*')): + # don't add anything if the next token is a multiplication + # or if there's already a parenthesis (if parenthesis, still + # stop skipping tokens) + if not (nextTok[0] == OP and nextTok[1] == '*'): + if not(nextTok[0] == OP and nextTok[1] == '('): + result.append((OP, '(')) + appendParen += 1 + exponentSkip = False + elif appendParen: + if nextTok[0] == OP and nextTok[1] in ('^', '**', '*'): + skip = 1 + continue + if skip: + skip -= 1 + continue + result.append((OP, ')')) + appendParen -= 1 + + result.append(tokens[-1]) + + if appendParen: + result.extend([(OP, ')')] * appendParen) + return result + + +def function_exponentiation(tokens, local_dict, global_dict): + """Allows functions to be exponentiated, e.g. ``cos**2(x)``. + + Example: + + >>> from sympy.parsing.sympy_parser import (parse_expr, + ... standard_transformations, function_exponentiation) + >>> transformations = standard_transformations + (function_exponentiation,) + >>> parse_expr('sin**4(x)', transformations=transformations) + sin(x)**4 + """ + result = [] + exponent = [] + consuming_exponent = False + level = 0 + for tok, nextTok in zip(tokens, tokens[1:]): + if tok[0] == NAME and nextTok[0] == OP and nextTok[1] == '**': + if _token_callable(tok, local_dict, global_dict): + consuming_exponent = True + elif consuming_exponent: + exponent.append(tok) + + # only want to stop after hitting ) + if tok[0] == nextTok[0] == OP and tok[1] == ')' and nextTok[1] == '(': + consuming_exponent = False + # if implicit multiplication was used, we may have )*( instead + if tok[0] == nextTok[0] == OP and tok[1] == '*' and nextTok[1] == '(': + consuming_exponent = False + del exponent[-1] + continue + elif exponent and not consuming_exponent: + if tok[0] == OP: + if tok[1] == '(': + level += 1 + elif tok[1] == ')': + level -= 1 + if level == 0: + result.append(tok) + result.extend(exponent) + exponent = [] + continue + result.append(tok) + result.append(tokens[-1]) + if exponent: + result.extend(exponent) + return result + + +def split_symbols_custom(predicate): + """Creates a transformation that splits symbol names. + + ``predicate`` should return True if the symbol name is to be split. + + For instance, to retain the default behavior but avoid splitting certain + symbol names, a predicate like this would work: + + + >>> from sympy.parsing.sympy_parser import (parse_expr, _token_splittable, + ... standard_transformations, implicit_multiplication, + ... split_symbols_custom) + >>> def can_split(symbol): + ... if symbol not in ('list', 'of', 'unsplittable', 'names'): + ... return _token_splittable(symbol) + ... return False + ... + >>> transformation = split_symbols_custom(can_split) + >>> parse_expr('unsplittable', transformations=standard_transformations + + ... (transformation, implicit_multiplication)) + unsplittable + """ + def _split_symbols(tokens, local_dict, global_dict): + result = [] + split = False + for tok in tokens: + if tok[0] == NAME and tok[1] == 'Symbol': + split = True + elif split and tok[0] == NAME: + symbol = tok[1][1:-1] + if predicate(symbol): + for char in symbol: + result.extend([(NAME, "'%s'" % char), (OP, ')'), + (NAME, 'Symbol'), (OP, '(')]) + # Delete the last three tokens: get rid of the extraneous + # Symbol( we just added, and also get rid of the last ) + # because the closing parenthesis of the original Symbol is + # still there + del result[-3:] + split = False + continue + else: + split = False + result.append(tok) + return result + return _split_symbols + + +#: Splits symbol names for implicit multiplication. +#: +#: Intended to let expressions like ``xyz`` be parsed as ``x*y*z``. Does not +#: split Greek character names, so ``theta`` will *not* become +#: ``t*h*e*t*a``. Generally this should be used with +#: ``implicit_multiplication``. +split_symbols = split_symbols_custom(_token_splittable) + + +def implicit_multiplication(result, local_dict, global_dict): + """Makes the multiplication operator optional in most cases. + + Use this before :func:`implicit_application`, otherwise expressions like + ``sin 2x`` will be parsed as ``x * sin(2)`` rather than ``sin(2*x)``. + + Example: + + >>> from sympy.parsing.sympy_parser import (parse_expr, + ... standard_transformations, implicit_multiplication) + >>> transformations = standard_transformations + (implicit_multiplication,) + >>> parse_expr('3 x y', transformations=transformations) + 3*x*y + """ + # These are interdependent steps, so we don't expose them separately + for step in (_group_parentheses(implicit_multiplication), + _apply_functions, + _implicit_multiplication): + result = step(result, local_dict, global_dict) + + result = _flatten(result) + return result + + +def implicit_application(result, local_dict, global_dict): + """Makes parentheses optional in some cases for function calls. + + Use this after :func:`implicit_multiplication`, otherwise expressions + like ``sin 2x`` will be parsed as ``x * sin(2)`` rather than + ``sin(2*x)``. + + Example: + + >>> from sympy.parsing.sympy_parser import (parse_expr, + ... standard_transformations, implicit_application) + >>> transformations = standard_transformations + (implicit_application,) + >>> parse_expr('cot z + csc z', transformations=transformations) + csc(z) + cot(z) + """ + for step in (_group_parentheses(implicit_application), + _apply_functions, + _implicit_application,): + result = step(result, local_dict, global_dict) + + result = _flatten(result) + return result + + +def implicit_multiplication_application(result, local_dict, global_dict): + """Allows a slightly relaxed syntax. + + - Parentheses for single-argument method calls are optional. + + - Multiplication is implicit. + + - Symbol names can be split (i.e. spaces are not needed between + symbols). + + - Functions can be exponentiated. + + Example: + + >>> from sympy.parsing.sympy_parser import (parse_expr, + ... standard_transformations, implicit_multiplication_application) + >>> parse_expr("10sin**2 x**2 + 3xyz + tan theta", + ... transformations=(standard_transformations + + ... (implicit_multiplication_application,))) + 3*x*y*z + 10*sin(x**2)**2 + tan(theta) + + """ + for step in (split_symbols, implicit_multiplication, + implicit_application, function_exponentiation): + result = step(result, local_dict, global_dict) + + return result + + +def auto_symbol(tokens, local_dict, global_dict): + """Inserts calls to ``Symbol`` for undefined variables.""" + result = [] + prevTok = (None, None) + + tokens.append((None, None)) # so zip traverses all tokens + for tok, nextTok in zip(tokens, tokens[1:]): + tokNum, tokVal = tok + nextTokNum, nextTokVal = nextTok + if tokNum == NAME: + name = tokVal + + if (name in ['True', 'False', 'None'] + or iskeyword(name) + or name in local_dict + # Don't convert attribute access + or (prevTok[0] == OP and prevTok[1] == '.') + # Don't convert keyword arguments + or (prevTok[0] == OP and prevTok[1] in ('(', ',') + and nextTokNum == OP and nextTokVal == '=')): + result.append((NAME, name)) + continue + elif name in global_dict: + obj = global_dict[name] + if isinstance(obj, (Basic, type)) or isinstance(obj, collections.Callable): + result.append((NAME, name)) + continue + + result.extend([ + (NAME, 'Symbol'), + (OP, '('), + (NAME, repr(str(name))), + (OP, ')'), + ]) + else: + result.append((tokNum, tokVal)) + + prevTok = (tokNum, tokVal) + + return result + + +def factorial_notation(tokens, local_dict, global_dict): + """Allows standard notation for factorial.""" + result = [] + prevtoken = '' + for toknum, tokval in tokens: + if toknum == OP: + op = tokval + + if op == '!!': + if prevtoken == '!' or prevtoken == '!!': + raise TokenError + result = _add_factorial_tokens('factorial2', result) + elif op == '!': + if prevtoken == '!' or prevtoken == '!!': + raise TokenError + result = _add_factorial_tokens('factorial', result) + else: + result.append((OP, op)) + else: + result.append((toknum, tokval)) + + prevtoken = tokval + + return result + + +def convert_xor(tokens, local_dict, global_dict): + """Treats XOR, ``^``, as exponentiation, ``**``.""" + result = [] + for toknum, tokval in tokens: + if toknum == OP: + if tokval == '^': + result.append((OP, '**')) + else: + result.append((toknum, tokval)) + else: + result.append((toknum, tokval)) + + return result + + +def auto_number(tokens, local_dict, global_dict): + """Converts numeric literals to use SymPy equivalents. + + Complex numbers use ``I``; integer literals use ``Integer``, float + literals use ``Float``, and repeating decimals use ``Rational``. + + """ result = [] prevtoken = '' - for toknum, tokval, _, _, _ in g: + for toknum, tokval in tokens: if toknum == NUMBER: number = tokval postfix = [] @@ -63,7 +578,8 @@ pre, post, repetend = match.groups() zeros = '0'*len(post) - post, repetends = [w.lstrip('0') for w in [post, repetend]] # or else interpreted as octal + post, repetends = [w.lstrip('0') for w in [post, repetend]] + # or else interpreted as octal a = pre or '0' b, c = post or '0', '1' + zeros @@ -71,100 +587,140 @@ seq = [ (OP, '('), - (NAME, 'Integer'), (OP, '('), (NUMBER, a), (OP, ')'), + (NAME, + 'Integer'), (OP, '('), (NUMBER, a), (OP, ')'), (OP, '+'), - (NAME, 'Rational'), (OP, '('), (NUMBER, b), (OP, ','), (NUMBER, c), (OP, ')'), + (NAME, 'Rational'), (OP, '('), ( + NUMBER, b), (OP, ','), (NUMBER, c), (OP, ')'), (OP, '+'), - (NAME, 'Rational'), (OP, '('), (NUMBER, d), (OP, ','), (NUMBER, e), (OP, ')'), + (NAME, 'Rational'), (OP, '('), ( + NUMBER, d), (OP, ','), (NUMBER, e), (OP, ')'), (OP, ')'), ] - elif rationalize: - seq = [(NAME, 'Rational'), (OP, '('), (STRING, repr(str(number))), (OP, ')')] else: - seq = [(NAME, 'Float'), (OP, '('), (NUMBER, repr(str(number))), (OP, ')')] + seq = [(NAME, 'Float'), (OP, '('), + (NUMBER, repr(str(number))), (OP, ')')] else: - seq = [(NAME, 'Integer'), (OP, '('), (NUMBER, number), (OP, ')')] + seq = [(NAME, 'Integer'), (OP, '('), ( + NUMBER, number), (OP, ')')] result.extend(seq + postfix) - elif toknum == NAME: - name = tokval - - if name in ['True', 'False', 'None'] or iskeyword(name) or name in local_dict: - result.append((NAME, name)) - continue - elif name in global_dict: - obj = global_dict[name] + else: + result.append((toknum, tokval)) - if isinstance(obj, (Basic, type)) or isinstance(obj, collections.Callable): - result.append((NAME, name)) - continue + return result - result.extend([ - (NAME, 'Symbol'), - (OP, '('), - (NAME, repr(str(name))), - (OP, ')'), - ]) - elif toknum == OP: - op = tokval - if op == '^' and convert_xor: - result.append((OP, '**')) - elif op == '!!': - if prevtoken == '!' or prevtoken == '!!': - raise TokenError - result = _add_factorial_tokens('factorial2', result) - elif op == '!': - if prevtoken == '!' or prevtoken == '!!': - raise TokenError - result = _add_factorial_tokens('factorial', result) - else: - result.append((OP, op)) +def rationalize(tokens, local_dict, global_dict): + """Converts floats into ``Rational``. Run AFTER ``auto_number``.""" + result = [] + passed_float = False + for toknum, tokval in tokens: + if toknum == NAME: + if tokval == 'Float': + passed_float = True + tokval = 'Rational' + result.append((toknum, tokval)) + elif passed_float == True and toknum == NUMBER: + passed_float = False + result.append((STRING, tokval)) else: result.append((toknum, tokval)) - prevtoken = tokval + return result + + +#: Standard transformations for :func:`parse_expr`. +#: Inserts calls to :class:`Symbol`, :class:`Integer`, and other SymPy +#: datatypes and allows the use of standard factorial notation (e.g. ``x!``). +standard_transformations = (auto_symbol, auto_number, factorial_notation) - return untokenize(result) -def parse_expr(s, local_dict=None, rationalize=False, convert_xor=False): +def stringify_expr(s, local_dict, global_dict, transformations): """ - Converts the string ``s`` to a SymPy expression, in ``local_dict`` + Converts the string ``s`` to Python code, in ``local_dict`` + + Generally, ``parse_expr`` should be used. + """ + + tokens = [] + input_code = StringIO(s.strip()) + for toknum, tokval, _, _, _ in generate_tokens(input_code.readline): + tokens.append((toknum, tokval)) + + for transform in transformations: + tokens = transform(tokens, local_dict, global_dict) + + return untokenize(tokens) + + +def eval_expr(code, local_dict, global_dict): + """ + Evaluate Python code generated by ``stringify_expr``. + + Generally, ``parse_expr`` should be used. + """ + expr = eval( + code, global_dict, local_dict) # take local objects in preference + + return expr + + +def parse_expr(s, local_dict=None, transformations=standard_transformations, + global_dict=None): + """Converts the string ``s`` to a SymPy expression, in ``local_dict`` + + Parameters + ========== + + s : str + The string to parse. + + local_dict : dict, optional + A dictionary of local variables to use when parsing. + + global_dict : dict, optional + A dictionary of global variables. By default, this is initialized + with ``from sympy import *``; provide this parameter to override + this behavior (for instance, to parse ``"Q & S"``). + + transformations : tuple, optional + A tuple of transformation functions used to modify the tokens of the + parsed expression before evaluation. The default transformations + convert numeric literals into their SymPy equivalents, convert + undefined variables into SymPy symbols, and allow the use of standard + mathematical factorial notation (e.g. ``x!``). + Examples ======== >>> from sympy.parsing.sympy_parser import parse_expr - >>> parse_expr("1/2") 1/2 >>> type(_) + >>> from sympy.parsing.sympy_parser import standard_transformations,\\ + ... implicit_multiplication_application + >>> transformations = (standard_transformations + + ... (implicit_multiplication_application,)) + >>> parse_expr("2x", transformations=transformations) + 2*x + + See Also + ======== + + stringify_expr, eval_expr, standard_transformations, + implicit_multiplication_application """ + if local_dict is None: local_dict = {} - global_dict = {} - exec('from sympy import *', global_dict) + if global_dict is None: + global_dict = {} + exec('from sympy import *', global_dict) - # keep autosimplification from joining Integer or - # minus sign into a Mul; this modification doesn't - # prevent the 2-arg Mul from becoming and Add. - hit = False - if '(' in s: - kern = '_kern' - while kern in s: - kern += "_" - s = re.sub(r'(\d *\*|-) *\(', r'\1%s*(' % kern, s) - hit = kern in s - - code = _transform(s.strip(), local_dict, global_dict, rationalize, convert_xor) - expr = eval(code, global_dict, local_dict) # take local objects in preference - - if not hit: - return expr - try: - return expr.xreplace({C.Symbol(kern): 1}) - except (TypeError, AttributeError): - return expr + code = stringify_expr(s, local_dict, global_dict, transformations) + return eval_expr(code, local_dict, global_dict) diff -Nru python3-sympy-0.7.2/sympy/parsing/sympy_tokenize.py python3-sympy-0.7.3/sympy/parsing/sympy_tokenize.py --- python3-sympy-0.7.2/sympy/parsing/sympy_tokenize.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/parsing/sympy_tokenize.py 2013-07-13 17:53:32.000000000 +0000 @@ -26,7 +26,8 @@ __credits__ = \ 'GvR, ESR, Tim Peters, Thomas Wouters, Fred Drake, Skip Montanaro, Raymond Hettinger' -import string, re +import string +import re from token import * import token @@ -40,9 +41,17 @@ tok_name[NL] = 'NL' N_TOKENS += 2 -def group(*choices): return '(' + '|'.join(choices) + ')' -def any(*choices): return group(*choices) + '*' -def maybe(*choices): return group(*choices) + '?' + +def group(*choices): + return '(' + '|'.join(choices) + ')' + + +def any(*choices): + return group(*choices) + '*' + + +def maybe(*choices): + return group(*choices) + '?' Whitespace = r'[ \f\t]*' Comment = r'#[^\r\n]*' @@ -142,16 +151,22 @@ tabsize = 8 -class TokenError(Exception): pass -class StopTokenizing(Exception): pass +class TokenError(Exception): + pass -def printtoken(type, token, srow_scol, erow_ecol, line): # for testing + +class StopTokenizing(Exception): + pass + + +def printtoken(type, token, srow_scol, erow_ecol, line): # for testing srow, scol = srow_scol erow, ecol = erow_ecol print("%d,%d-%d,%d:\t%s\t%s" % \ (srow, scol, erow, ecol, tok_name[type], repr(token))) + def tokenize(readline, tokeneater=printtoken): """ The tokenize() function accepts two parameters: one representing the @@ -171,10 +186,13 @@ pass # backwards compatible interface + + def tokenize_loop(readline, tokeneater): for token_info in generate_tokens(readline): tokeneater(*token_info) + class Untokenizer: def __init__(self): @@ -240,6 +258,7 @@ startline = False toks_append(tokval) + def untokenize(iterable): """Transform tokens back into Python source code. @@ -262,6 +281,7 @@ ut = Untokenizer() return ut.untokenize(iterable) + def generate_tokens(readline): """ The generate_tokens() generator requires one argment, readline, which @@ -305,7 +325,7 @@ contline = None elif needcont and line[-2:] != '\\\n' and line[-3:] != '\\\r\n': yield (ERRORTOKEN, contstr + line, - strstart, (lnum, len(line)), contline) + strstart, (lnum, len(line)), contline) contstr = '' contline = None continue @@ -315,15 +335,21 @@ continue elif parenlev == 0 and not continued: # new statement - if not line: break + if not line: + break column = 0 while pos < max: # measure leading whitespace - if line[pos] == ' ': column = column + 1 - elif line[pos] == '\t': column = (column/tabsize + 1)*tabsize - elif line[pos] == '\f': column = 0 - else: break + if line[pos] == ' ': + column = column + 1 + elif line[pos] == '\t': + column = (column/tabsize + 1)*tabsize + elif line[pos] == '\f': + column = 0 + else: + break pos = pos + 1 - if pos == max: break + if pos == max: + break if line[pos] in '#\r\n': # skip comments or blank lines if line[pos] == '#': @@ -362,7 +388,7 @@ token, initial = line[start:end], line[start] if initial in numchars or \ - (initial == '.' and token != '.'): # ordinary number + (initial == '.' and token != '.'): # ordinary number yield (NUMBER, token, spos, epos, line) elif initial in '\r\n': yield (NL if parenlev > 0 else NEWLINE, token, spos, epos, line) @@ -382,7 +408,7 @@ break elif initial in single_quoted or \ token[:2] in single_quoted or \ - token[:3] in single_quoted: + token[:3] in single_quoted: if token[-1] == '\n': # continued string endprog = (endprogs[initial] or endprogs[token[1]] or endprogs[token[2]]) @@ -396,12 +422,14 @@ elif initial == '\\': # continued stmt continued = 1 else: - if initial in '([{': parenlev = parenlev + 1 - elif initial in ')]}': parenlev = parenlev - 1 + if initial in '([{': + parenlev = parenlev + 1 + elif initial in ')]}': + parenlev = parenlev - 1 yield (OP, token, spos, epos, line) else: yield (ERRORTOKEN, line[pos], - (lnum, pos), (lnum, pos+1), line) + (lnum, pos), (lnum, pos + 1), line) pos = pos + 1 for indent in indents[1:]: # pop remaining indent levels @@ -410,5 +438,7 @@ if __name__ == '__main__': # testing import sys - if len(sys.argv) > 1: tokenize(open(sys.argv[1]).readline) - else: tokenize(sys.stdin.readline) + if len(sys.argv) > 1: + tokenize(open(sys.argv[1]).readline) + else: + tokenize(sys.stdin.readline) diff -Nru python3-sympy-0.7.2/sympy/parsing/tests/test_implicit_multiplication_application.py python3-sympy-0.7.3/sympy/parsing/tests/test_implicit_multiplication_application.py --- python3-sympy-0.7.2/sympy/parsing/tests/test_implicit_multiplication_application.py 1970-01-01 00:00:00.000000000 +0000 +++ python3-sympy-0.7.3/sympy/parsing/tests/test_implicit_multiplication_application.py 2013-07-13 17:53:32.000000000 +0000 @@ -0,0 +1,159 @@ +from sympy.parsing.sympy_parser import ( + parse_expr, + standard_transformations, + convert_xor, + implicit_multiplication_application, + implicit_multiplication, + implicit_application, + function_exponentiation, + split_symbols, + split_symbols_custom, + _token_splittable +) +from sympy.utilities.pytest import raises + + +def test_implicit_multiplication(): + cases = { + '5x': '5*x', + 'abc': 'a*b*c', + '3sin(x)': '3*sin(x)', + '(x+1)(x+2)': '(x+1)*(x+2)', + '(5 x**2)sin(x)': '(5*x**2)*sin(x)', + '2 sin(x) cos(x)': '2*sin(x)*cos(x)' + } + transformations = standard_transformations + (convert_xor,) + transformations2 = transformations + (split_symbols, + implicit_multiplication) + for case in cases: + implicit = parse_expr(case, transformations=transformations2) + normal = parse_expr(cases[case], transformations=transformations) + assert(implicit == normal) + + application = ['sin x', 'cos 2*x', 'sin cos x'] + for case in application: + raises(SyntaxError, + lambda: parse_expr(case, transformations=transformations2)) + raises(TypeError, + lambda: parse_expr('sin**2(x)', transformations=transformations2)) + + +def test_implicit_application(): + cases = { + 'factorial': 'factorial', + 'sin x': 'sin(x)', + 'tan y**3': 'tan(y**3)', + 'cos 2*x': 'cos(2*x)', + '(cot)': 'cot', + 'sin cos tan x': 'sin(cos(tan(x)))' + } + transformations = standard_transformations + (convert_xor,) + transformations2 = transformations + (implicit_application,) + for case in cases: + implicit = parse_expr(case, transformations=transformations2) + normal = parse_expr(cases[case], transformations=transformations) + assert(implicit == normal) + + multiplication = ['x y', 'x sin x', '2x'] + for case in multiplication: + raises(SyntaxError, + lambda: parse_expr(case, transformations=transformations2)) + raises(TypeError, + lambda: parse_expr('sin**2(x)', transformations=transformations2)) + + + +def test_function_exponentiation(): + cases = { + 'sin**2(x)': 'sin(x)**2', + 'exp^y(z)': 'exp(z)^y', + 'sin**2(E^(x))': 'sin(E^(x))**2' + } + transformations = standard_transformations + (convert_xor,) + transformations2 = transformations + (function_exponentiation,) + for case in cases: + implicit = parse_expr(case, transformations=transformations2) + normal = parse_expr(cases[case], transformations=transformations) + assert(implicit == normal) + + other_implicit = ['x y', 'x sin x', '2x', 'sin x', + 'cos 2*x', 'sin cos x'] + for case in other_implicit: + raises(SyntaxError, + lambda: parse_expr(case, transformations=transformations2)) + + +def test_symbol_splitting(): + # By default Greek letter names should not be split (lambda is a keyword + # so skip it) + transformations = standard_transformations + (split_symbols,) + greek_letters = ('alpha', 'beta', 'gamma', 'delta', 'epsilon', 'zeta', + 'eta', 'theta', 'iota', 'kappa', 'mu', 'nu', 'xi', + 'omicron', 'pi', 'rho', 'sigma', 'tau', 'upsilon', + 'phi', 'chi', 'psi', 'omega') + + for letter in greek_letters: + assert(parse_expr(letter, transformations=transformations) == + parse_expr(letter)) + + # Make sure custom splitting works + def can_split(symbol): + if symbol not in ('unsplittable', 'names'): + return _token_splittable(symbol) + return False + transformations = standard_transformations + transformations += (split_symbols_custom(can_split), + implicit_multiplication) + + assert(parse_expr('unsplittable', transformations=transformations) == + parse_expr('unsplittable')) + assert(parse_expr('names', transformations=transformations) == + parse_expr('names')) + assert(parse_expr('xy', transformations=transformations) == + parse_expr('x*y')) + for letter in greek_letters: + assert(parse_expr(letter, transformations=transformations) == + parse_expr(letter)) + + +def test_all_implicit_steps(): + cases = { + '2x': '2*x', # implicit multiplication + 'x y': 'x*y', + 'xy': 'x*y', + 'sin x': 'sin(x)', # add parentheses + '2sin x': '2*sin(x)', + 'x y z': 'x*y*z', + 'sin(2 * 3x)': 'sin(2 * 3 * x)', + 'sin(x) (1 + cos(x))': 'sin(x) * (1 + cos(x))', + '(x + 2) sin(x)': '(x + 2) * sin(x)', + '(x + 2) sin x': '(x + 2) * sin(x)', + 'sin(sin x)': 'sin(sin(x))', + 'sin x!': 'sin(factorial(x))', + 'sin x!!': 'sin(factorial2(x))', + 'factorial': 'factorial', # don't apply a bare function + 'x sin x': 'x * sin(x)', # both application and multiplication + 'xy sin x': 'x * y * sin(x)', + '(x+2)(x+3)': '(x + 2) * (x+3)', + 'x**2 + 2xy + y**2': 'x**2 + 2 * x * y + y**2', # split the xy + 'pi': 'pi', # don't mess with constants + 'None': 'None', + 'ln sin x': 'ln(sin(x))', # multiple implicit function applications + 'factorial': 'factorial', # don't add parentheses + 'sin x**2': 'sin(x**2)', # implicit application to an exponential + 'alpha': 'Symbol("alpha")', # don't split Greek letters/subscripts + 'x_2': 'Symbol("x_2")', + 'sin^2 x**2': 'sin(x**2)**2', # function raised to a power + 'sin**3(x)': 'sin(x)**3', + '(factorial)': 'factorial', + 'tan 3x': 'tan(3*x)', + 'sin^2(3*E^(x))': 'sin(3*E**(x))**2', + 'sin**2(E^(3x))': 'sin(E**(3*x))**2', + 'sin^2 (3x*E^(x))': 'sin(3*x*E^x)**2' + } + transformations = standard_transformations + (convert_xor,) + transformations2 = transformations + (implicit_multiplication_application,) + for case in cases: + implicit = parse_expr(case, transformations=transformations2) + normal = parse_expr(cases[case], transformations=transformations) + assert(implicit == normal) diff -Nru python3-sympy-0.7.2/sympy/parsing/tests/test_mathematica.py python3-sympy-0.7.3/sympy/parsing/tests/test_mathematica.py --- python3-sympy-0.7.2/sympy/parsing/tests/test_mathematica.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/parsing/tests/test_mathematica.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,18 +1,19 @@ from sympy.parsing.mathematica import mathematica from sympy import sympify + def test_mathematica(): - d = {'Sin[x]^2':'sin(x)**2', - '2(x-1)':'2*(x-1)', - '3y+8':'3*y+8', - 'Arcsin[2x+9(4-x)^2]/x':'asin(2*x+9*(4-x)**2)/x', - 'x+y':'x+y', - '355/113':'355/113', - '2.718281828':'2.718281828', - 'Sin[12]':'sin(12)', - 'Exp[Log[4]]':'exp(log(4))', - '(x+1)(x+3)':'(x+1)*(x+3)', - 'Cos[Arccos[3.6]]':'cos(acos(3.6))', - 'Cos[x]==Sin[y]':'cos(x)==sin(y)'} + d = {'Sin[x]^2': 'sin(x)**2', + '2(x-1)': '2*(x-1)', + '3y+8': '3*y+8', + 'Arcsin[2x+9(4-x)^2]/x': 'asin(2*x+9*(4-x)**2)/x', + 'x+y': 'x+y', + '355/113': '355/113', + '2.718281828': '2.718281828', + 'Sin[12]': 'sin(12)', + 'Exp[Log[4]]': 'exp(log(4))', + '(x+1)(x+3)': '(x+1)*(x+3)', + 'Cos[Arccos[3.6]]': 'cos(acos(3.6))', + 'Cos[x]==Sin[y]': 'cos(x)==sin(y)'} for e in d: assert mathematica(e) == sympify(d[e]) diff -Nru python3-sympy-0.7.2/sympy/parsing/tests/test_maxima.py python3-sympy-0.7.3/sympy/parsing/tests/test_maxima.py --- python3-sympy-0.7.2/sympy/parsing/tests/test_maxima.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/parsing/tests/test_maxima.py 2013-07-13 17:53:32.000000000 +0000 @@ -8,34 +8,36 @@ def test_parser(): assert Abs(parse_maxima('float(1/3)') - 0.333333333) < 10**(-5) assert parse_maxima('13^26') == 91733330193268616658399616009 - assert parse_maxima('sin(%pi/2) + cos(%pi/3)') == Rational(3,2) + assert parse_maxima('sin(%pi/2) + cos(%pi/3)') == Rational(3, 2) assert parse_maxima('log(%e)') == 1 + def test_injection(): parse_maxima('c: x+1', globals=globals()) - assert c==x+1 + assert c == x + 1 parse_maxima('g: sqrt(81)', globals=globals()) - assert g==9 + assert g == 9 + def test_maxima_functions(): assert parse_maxima('expand( (x+1)^2)') == x**2 + 2*x + 1 - assert parse_maxima('factor( x**2 + 2*x + 1)') == (x+1)**2 - assert parse_maxima('trigsimp(2*cos(x)^2 + sin(x)^2)') == 2 - sin(x)**2 - assert parse_maxima('trigexpand(sin(2*x)+cos(2*x))') == (-1) + 2*cos(x)**2 + 2*cos(x)*sin(x) + assert parse_maxima('factor( x**2 + 2*x + 1)') == (x + 1)**2 + assert parse_maxima('2*cos(x)^2 + sin(x)^2') == 2*cos(x)**2 + sin(x)**2 + assert parse_maxima('trigexpand(sin(2*x)+cos(2*x))') == \ + -1 + 2*cos(x)**2 + 2*cos(x)*sin(x) assert parse_maxima('solve(x^2-4,x)') == [-2, 2] assert parse_maxima('limit((1+1/x)^x,x,inf)') == E assert parse_maxima('limit(sqrt(-x)/x,x,0,minus)') == -oo assert parse_maxima('diff(x^x, x)') == x**x*(1 + log(x)) assert parse_maxima('sum(k, k, 1, n)', name_dict=dict( - n=Symbol('n',integer=True), - k=Symbol('k',integer=True) - )) == (n**2 +n)/2 - assert parse_maxima('product(k, k, 1, n)', - name_dict=dict( - n=Symbol('n',integer=True), - k=Symbol('k',integer=True) - ) - ) == factorial(n) - assert parse_maxima('ratsimp((x^2-1)/(x+1))') == x-1 - assert Abs( parse_maxima('float(sec(%pi/3) + csc(%pi/3))') - 3.154700538379252) < 10**(-5) + n=Symbol('n', integer=True), + k=Symbol('k', integer=True) + )) == (n**2 + n)/2 + assert parse_maxima('product(k, k, 1, n)', name_dict=dict( + n=Symbol('n', integer=True), + k=Symbol('k', integer=True) + )) == factorial(n) + assert parse_maxima('ratsimp((x^2-1)/(x+1))') == x - 1 + assert Abs( parse_maxima( + 'float(sec(%pi/3) + csc(%pi/3))') - 3.154700538379252) < 10**(-5) diff -Nru python3-sympy-0.7.2/sympy/parsing/tests/test_sympy_parser.py python3-sympy-0.7.3/sympy/parsing/tests/test_sympy_parser.py --- python3-sympy-0.7.2/sympy/parsing/tests/test_sympy_parser.py 1970-01-01 00:00:00.000000000 +0000 +++ python3-sympy-0.7.3/sympy/parsing/tests/test_sympy_parser.py 2013-07-13 17:53:32.000000000 +0000 @@ -0,0 +1,74 @@ +from sympy.core import Symbol, Float, Rational, Integer, I, Mul, Pow +from sympy.functions import exp, factorial, sin +from sympy.logic import And +from sympy.series import Limit + +from sympy.parsing.sympy_parser import ( + parse_expr, standard_transformations, rationalize, TokenError +) + + +def test_sympy_parser(): + x = Symbol('x') + inputs = { + '2*x': 2 * x, + '3.00': Float(3), + '22/7': Rational(22, 7), + '2+3j': 2 + 3*I, + 'exp(x)': exp(x), + 'x!': factorial(x), + '3.[3]': Rational(10, 3), + '10!': 3628800, + '-(2)': -Integer(2), + '[-1, -2, 3]': [Integer(-1), Integer(-2), Integer(3)], + 'Symbol("x").free_symbols': x.free_symbols, + "S('S(3).n(n=3)')": 3.00, + 'factorint(12, visual=True)': Mul( + Pow(2, 2, evaluate=False), + Pow(3, 1, evaluate=False), + evaluate=False), + 'Limit(sin(x), x, 0, dir="-")': Limit(sin(x), x, 0, dir='-'), + + } + for text, result in list(inputs.items()): + assert parse_expr(text) == result + + +def test_rationalize(): + inputs = { + '0.123': Rational(123, 1000) + } + transformations = standard_transformations + (rationalize,) + for text, result in list(inputs.items()): + assert parse_expr(text, transformations=transformations) == result + + +def test_factorial_fail(): + inputs = ['x!!!', 'x!!!!', '(!)'] + + for text in inputs: + try: + parse_expr(text) + assert False + except TokenError: + assert True + +def test_local_dict(): + local_dict = { + 'my_function': lambda x: x + 2 + } + inputs = { + 'my_function(2)': Integer(4) + } + for text, result in list(inputs.items()): + assert parse_expr(text, local_dict=local_dict) == result + +def test_global_dict(): + global_dict = { + 'Symbol': Symbol + } + inputs = { + 'Q & S': And(Symbol('Q'), Symbol('S')) + } + for text, result in list(inputs.items()): + assert parse_expr(text, global_dict=global_dict) == result diff -Nru python3-sympy-0.7.2/sympy/physics/gaussopt.py python3-sympy-0.7.3/sympy/physics/gaussopt.py --- python3-sympy-0.7.2/sympy/physics/gaussopt.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/physics/gaussopt.py 2013-07-13 17:53:32.000000000 +0000 @@ -30,6 +30,7 @@ # A, B, C, D matrices ### + class RayTransferMatrix(Matrix): """ Base class for a Ray Transfer Matrix. @@ -50,12 +51,14 @@ >>> mat = RayTransferMatrix(1, 2, 3, 4) >>> mat - [1, 2] - [3, 4] + Matrix([ + [1, 2], + [3, 4]]) >>> RayTransferMatrix(Matrix([[1, 2], [3, 4]])) - [1, 2] - [3, 4] + Matrix([ + [1, 2], + [3, 4]]) >>> mat.A 1 @@ -63,8 +66,9 @@ >>> f = Symbol('f') >>> lens = ThinLens(f) >>> lens - [ 1, 0] - [-1/f, 1] + Matrix([ + [ 1, 0], + [-1/f, 1]]) >>> lens.C -1/f @@ -79,7 +83,7 @@ References ========== - [1] http://en.wikipedia.org/wiki/Ray_transfer_matrix_analysis + .. [1] http://en.wikipedia.org/wiki/Ray_transfer_matrix_analysis """ def __new__(cls, *args): @@ -87,8 +91,8 @@ if len(args) == 4: temp = ((args[0], args[1]), (args[2], args[3])) elif len(args) == 1 \ - and isinstance(args[0], Matrix) \ - and args[0].shape == (2, 2): + and isinstance(args[0], Matrix) \ + and args[0].shape == (2, 2): temp = args[0] else: raise ValueError(filldedent(''' @@ -104,9 +108,9 @@ elif isinstance(other, BeamParameter): temp = self*Matrix(((other.q,), (1,))) q = (temp[0]/temp[1]).expand(complex=True) - return BeamParameter(other.wavelen, \ - together(re(q)), \ - z_r = together(im(q))) + return BeamParameter(other.wavelen, + together(re(q)), + z_r=together(im(q))) else: return Matrix.__mul__(self, other) @@ -170,6 +174,7 @@ """ return self[1, 1] + class FreeSpace(RayTransferMatrix): """ Ray Transfer Matrix for free space. @@ -191,12 +196,14 @@ >>> from sympy import symbols >>> d = symbols('d') >>> FreeSpace(d) - [1, d] - [0, 1] + Matrix([ + [1, d], + [0, 1]]) """ def __new__(cls, d): return RayTransferMatrix.__new__(cls, 1, d, 0, 1) + class FlatRefraction(RayTransferMatrix): """ Ray Transfer Matrix for refraction. @@ -219,13 +226,15 @@ >>> from sympy import symbols >>> n1, n2 = symbols('n1 n2') >>> FlatRefraction(n1, n2) - [1, 0] - [0, n1/n2] + Matrix([ + [1, 0], + [0, n1/n2]]) """ def __new__(cls, n1, n2): - n1, n2 = sympify((n1, n2)) + n1, n2 = list(map(sympify, (n1, n2))) return RayTransferMatrix.__new__(cls, 1, 0, 0, n1/n2) + class CurvedRefraction(RayTransferMatrix): """ Ray Transfer Matrix for refraction on curved interface. @@ -249,12 +258,14 @@ >>> from sympy import symbols >>> R, n1, n2 = symbols('R n1 n2') >>> CurvedRefraction(R, n1, n2) - [ 1, 0] - [(n1 - n2)/(R*n2), n1/n2] + Matrix([ + [ 1, 0], + [(n1 - n2)/(R*n2), n1/n2]]) """ def __new__(cls, R, n1, n2): - R, n1 , n2 = sympify((R, n1, n2)) - return RayTransferMatrix.__new__(cls, 1, 0, (n1-n2)/R/n2, n1/n2) + R, n1, n2 = list(map(sympify, (R, n1, n2))) + return RayTransferMatrix.__new__(cls, 1, 0, (n1 - n2)/R/n2, n1/n2) + class FlatMirror(RayTransferMatrix): """ @@ -270,12 +281,14 @@ >>> from sympy.physics.gaussopt import FlatMirror >>> FlatMirror() - [1, 0] - [0, 1] + Matrix([ + [1, 0], + [0, 1]]) """ def __new__(cls): return RayTransferMatrix.__new__(cls, 1, 0, 0, 1) + class CurvedMirror(RayTransferMatrix): """ Ray Transfer Matrix for reflection from curved surface. @@ -297,13 +310,15 @@ >>> from sympy import symbols >>> R = symbols('R') >>> CurvedMirror(R) - [ 1, 0] - [-2/R, 1] + Matrix([ + [ 1, 0], + [-2/R, 1]]) """ def __new__(cls, R): R = sympify(R) return RayTransferMatrix.__new__(cls, 1, 0, -2/R, 1) + class ThinLens(RayTransferMatrix): """ Ray Transfer Matrix for a thin lens. @@ -325,8 +340,9 @@ >>> from sympy import symbols >>> f = symbols('f') >>> ThinLens(f) - [ 1, 0] - [-1/f, 1] + Matrix([ + [ 1, 0], + [-1/f, 1]]) """ def __new__(cls, f): f = sympify(f) @@ -356,16 +372,19 @@ >>> d, h, angle = symbols('d, h, angle') >>> GeometricRay(h, angle) - [ h] - [angle] + Matrix([ + [ h], + [angle]]) >>> FreeSpace(d)*GeometricRay(h, angle) - [angle*d + h] - [ angle] + Matrix([ + [angle*d + h], + [ angle]]) >>> GeometricRay( Matrix( ((h,), (angle,)) ) ) - [ h] - [angle] + Matrix([ + [ h], + [angle]]) See Also ======== @@ -376,7 +395,7 @@ def __new__(cls, *args): if len(args) == 1 and isinstance(args[0], Matrix) \ - and args[0].shape == (2, 1): + and args[0].shape == (2, 1): temp = args[0] elif len(args) == 2: temp = ((args[0],), (args[1],)) @@ -468,7 +487,7 @@ References ========== - [1] http://en.wikipedia.org/wiki/Complex_beam_parameter + .. [1] http://en.wikipedia.org/wiki/Complex_beam_parameter """ #TODO A class Complex may be implemented. The BeamParameter may # subclass it. See: @@ -477,11 +496,11 @@ __slots__ = ['z', 'z_r', 'wavelen'] def __new__(cls, wavelen, z, **kwargs): - wavelen, z = sympify((wavelen, z)) + wavelen, z = list(map(sympify, (wavelen, z))) inst = Expr.__new__(cls, wavelen, z) inst.wavelen = wavelen inst.z = z - if len(kwargs) !=1: + if len(kwargs) != 1: raise ValueError('Constructor expects exactly one named argument.') elif 'z_r' in kwargs: inst.z_r = sympify(kwargs['z_r']) @@ -519,7 +538,7 @@ >>> p.radius 0.2809/pi**2 + 1 """ - return self.z*(1+(self.z/self.z_r)**2) + return self.z*(1 + (self.z/self.z_r)**2) @property def w(self): @@ -539,7 +558,7 @@ >>> p.w 0.001*sqrt(0.2809/pi**2 + 1) """ - return self.w_0*sqrt(1+(self.z/self.z_r)**2) + return self.w_0*sqrt(1 + (self.z/self.z_r)**2) @property def w_0(self): @@ -632,9 +651,10 @@ >>> waist2rayleigh(w, wavelen) pi*w**2/wavelen """ - w, wavelen = sympify((w, wavelen)) + w, wavelen = list(map(sympify, (w, wavelen))) return w**2*pi/wavelen + def rayleigh2waist(z_r, wavelen): """Calculate the waist from the rayleigh range of a gaussian beam. @@ -652,7 +672,7 @@ >>> rayleigh2waist(z_r, wavelen) sqrt(wavelen*z_r)/sqrt(pi) """ - z_r, wavelen = sympify((z_r, wavelen)) + z_r, wavelen = list(map(sympify, (z_r, wavelen))) return sqrt(z_r/pi*wavelen) @@ -677,11 +697,12 @@ >>> geometric_conj_ab(a, b) a*b/(a + b) """ - a, b = sympify((a, b)) + a, b = list(map(sympify, (a, b))) if abs(a) == oo or abs(b) == oo: return a if abs(b) == oo else b else: - return a*b/(a+b) + return a*b/(a + b) + def geometric_conj_af(a, f): """ @@ -707,11 +728,12 @@ >>> geometric_conj_bf(b, f) b*f/(b - f) """ - a, f = sympify((a, f)) + a, f = list(map(sympify, (a, f))) return -geometric_conj_ab(a, -f) geometric_conj_bf = geometric_conj_af + def gaussian_conj(s_in, z_r_in, f): """ Conjugation relation for gaussian beams. @@ -747,12 +769,13 @@ >>> gaussian_conj(s_in, z_r_in, f)[2] 1/sqrt(1 - s_in**2/f**2 + z_r_in**2/f**2) """ - s_in, z_r_in, f = sympify((s_in, z_r_in, f)) - s_out = 1 / ( -1/(s_in + z_r_in**2/(s_in-f)) + 1/f ) - m = 1/sqrt((1-(s_in/f)**2) + (z_r_in/f)**2) - z_r_out = z_r_in / ((1-(s_in/f)**2) + (z_r_in/f)**2) + s_in, z_r_in, f = list(map(sympify, (s_in, z_r_in, f))) + s_out = 1 / ( -1/(s_in + z_r_in**2/(s_in - f)) + 1/f ) + m = 1/sqrt((1 - (s_in/f)**2) + (z_r_in/f)**2) + z_r_out = z_r_in / ((1 - (s_in/f)**2) + (z_r_in/f)**2) return (s_out, z_r_out, m) + def conjugate_gauss_beams(wavelen, waist_in, waist_out, **kwargs): """ Find the optical setup conjugating the object/image waists. @@ -783,13 +806,14 @@ f*(-sqrt(w_i**2/w_o**2 - pi**2*w_i**4/(f**2*l**2)) + 1) >>> factor(conjugate_gauss_beams(l, w_i, w_o, f=f)[1]) - f*w_o**2*(w_i**2/w_o**2 - sqrt(w_i**2/w_o**2 - pi**2*w_i**4/(f**2*l**2)))/w_i**2 + f*w_o**2*(w_i**2/w_o**2 - sqrt(w_i**2/w_o**2 - + pi**2*w_i**4/(f**2*l**2)))/w_i**2 >>> conjugate_gauss_beams(l, w_i, w_o, f=f)[2] f """ #TODO add the other possible arguments - wavelen, waist_in, waist_out = sympify((wavelen, waist_in, waist_out)) + wavelen, waist_in, waist_out = list(map(sympify, (wavelen, waist_in, waist_out))) m = waist_out / waist_in z = waist2rayleigh(waist_in, wavelen) if len(kwargs) != 1: diff -Nru python3-sympy-0.7.2/sympy/physics/hydrogen.py python3-sympy-0.7.3/sympy/physics/hydrogen.py --- python3-sympy-0.7.2/sympy/physics/hydrogen.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/physics/hydrogen.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,5 +1,6 @@ from sympy import factorial, sqrt, exp, S, assoc_laguerre, Float + def R_nl(n, l, r, Z=1): """ Returns the Hydrogen radial wavefunction R_{nl}. @@ -70,14 +71,15 @@ # radial quantum number n_r = n - l - 1 # rescaled "r" - a = 1/Z # Bohr radius + a = 1/Z # Bohr radius r0 = 2 * r / (n * a) # normalization coefficient - C = sqrt((S(2)/(n*a))**3 * factorial(n_r) / (2*n*factorial(n+l))) + C = sqrt((S(2)/(n*a))**3 * factorial(n_r) / (2*n*factorial(n + l))) # This is an equivalent normalization coefficient, that can be found in # some books. Both coefficients seem to be the same fast: # C = S(2)/n**2 * sqrt(1/a**3 * factorial(n_r) / (factorial(n+l))) - return C * r0**l * assoc_laguerre(n_r, 2*l+1, r0).expand() * exp(-r0/2) + return C * r0**l * assoc_laguerre(n_r, 2*l + 1, r0).expand() * exp(-r0/2) + def E_nl(n, Z=1): """ @@ -109,6 +111,7 @@ raise ValueError("'n' must be positive integer") return -Z**2/(2*n**2) + def E_nl_dirac(n, l, spin_up=True, Z=1, c=Float("137.035999037")): """ Returns the relativistic energy of the state (n, l, spin) in Hartree atomic @@ -157,7 +160,7 @@ raise ValueError("'l' must be positive or zero") if not (n > l): raise ValueError("'n' must be greater than 'l'") - if (l==0 and spin_up is False): + if (l == 0 and spin_up is False): raise ValueError("Spin must be up for l==0.") # skappa is sign*kappa, where sign contains the correct sign if spin_up: @@ -166,4 +169,4 @@ skappa = -l c = S(c) beta = sqrt(skappa**2 - Z**2/c**2) - return c**2/sqrt(1+Z**2/(n + skappa + beta)**2/c**2) - c**2 + return c**2/sqrt(1 + Z**2/(n + skappa + beta)**2/c**2) - c**2 diff -Nru python3-sympy-0.7.2/sympy/physics/matrices.py python3-sympy-0.7.3/sympy/physics/matrices.py --- python3-sympy-0.7.2/sympy/physics/matrices.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/physics/matrices.py 2013-07-13 17:53:32.000000000 +0000 @@ -2,41 +2,44 @@ from sympy import Matrix, I + def msigma(i): """Returns a Pauli matrix sigma_i. i=1,2,3 - See Also - ======== + References + ========== - http://en.wikipedia.org/wiki/Pauli_matrices + .. [1] http://en.wikipedia.org/wiki/Pauli_matrices Examples ======== >>> from sympy.physics.matrices import msigma >>> msigma(1) - [0, 1] - [1, 0] + Matrix([ + [0, 1], + [1, 0]]) """ if i == 1: mat = ( ( (0, 1), (1, 0) - ) ) + ) ) elif i == 2: mat = ( ( (0, -I), (I, 0) - ) ) + ) ) elif i == 3: mat = ( ( (1, 0), (0, -1) - ) ) + ) ) else: raise IndexError("Invalid Pauli index") return Matrix(mat) + def pat_matrix(m, dx, dy, dz): """Returns the Parallel Axis Theorem matrix to translate the inertia matrix a distance of (dx, dy, dz) for a body of mass m. @@ -47,24 +50,31 @@ length and 1 unit along the x-axis we get: >>> from sympy.physics.matrices import pat_matrix >>> pat_matrix(2,1,0,0) - [0, 0, 0] - [0, 2, 0] - [0, 0, 2] + Matrix([ + [0, 0, 0], + [0, 2, 0], + [0, 0, 2]]) In case we want to find the inertia along a vector of (1,1,1): >>> pat_matrix(2,1,1,1) - [ 4, -2, -2] - [-2, 4, -2] - [-2, -2, 4] + Matrix([ + [ 4, -2, -2], + [-2, 4, -2], + [-2, -2, 4]]) """ - dxdy = -dx*dy ; dydz = -dy*dz ; dzdx = -dz*dx - dxdx = dx**2 ; dydy = dy**2 ; dzdz = dz**2 + dxdy = -dx*dy + dydz = -dy*dz + dzdx = -dz*dx + dxdx = dx**2 + dydy = dy**2 + dzdz = dz**2 mat = ((dydy + dzdz, dxdy, dzdx), (dxdy, dxdx + dzdz, dydz), (dzdx, dydz, dydy + dxdx)) return m*Matrix(mat) -def mgamma(mu,lower=False): + +def mgamma(mu, lower=False): """Returns a Dirac gamma matrix gamma^mu in the standard (Dirac) representation. @@ -75,69 +85,70 @@ gamma^5 = I * gamma^0 * gamma^1 * gamma^2 * gamma^3 gamma_5 = I * gamma_0 * gamma_1 * gamma_2 * gamma_3 = - gamma^5 - See Also - ======== + References + ========== - http://en.wikipedia.org/wiki/Gamma_matrices + .. [1] http://en.wikipedia.org/wiki/Gamma_matrices Examples ======== >>> from sympy.physics.matrices import mgamma >>> mgamma(1) - [ 0, 0, 0, 1] - [ 0, 0, 1, 0] - [ 0, -1, 0, 0] - [-1, 0, 0, 0] + Matrix([ + [ 0, 0, 0, 1], + [ 0, 0, 1, 0], + [ 0, -1, 0, 0], + [-1, 0, 0, 0]]) """ - if not mu in [0,1,2,3,5]: + if not mu in [0, 1, 2, 3, 5]: raise IndexError("Invalid Dirac index") if mu == 0: mat = ( - (1,0,0,0), - (0,1,0,0), - (0,0,-1,0), - (0,0,0,-1) - ) + (1, 0, 0, 0), + (0, 1, 0, 0), + (0, 0, -1, 0), + (0, 0, 0, -1) + ) elif mu == 1: mat = ( - (0,0,0,1), - (0,0,1,0), - (0,-1,0,0), - (-1,0,0,0) - ) + (0, 0, 0, 1), + (0, 0, 1, 0), + (0, -1, 0, 0), + (-1, 0, 0, 0) + ) elif mu == 2: mat = ( - (0,0,0,-I), - (0,0,I,0), - (0,I,0,0), - (-I,0,0,0) - ) + (0, 0, 0, -I), + (0, 0, I, 0), + (0, I, 0, 0), + (-I, 0, 0, 0) + ) elif mu == 3: mat = ( - (0,0,1,0), - (0,0,0,-1), - (-1,0,0,0), - (0,1,0,0) - ) + (0, 0, 1, 0), + (0, 0, 0, -1), + (-1, 0, 0, 0), + (0, 1, 0, 0) + ) elif mu == 5: mat = ( - (0,0,1,0), - (0,0,0,1), - (1,0,0,0), - (0,1,0,0) - ) - m= Matrix(mat) + (0, 0, 1, 0), + (0, 0, 0, 1), + (1, 0, 0, 0), + (0, 1, 0, 0) + ) + m = Matrix(mat) if lower: - if mu in [1,2,3,5]: - m = - m + if mu in [1, 2, 3, 5]: + m = -m return m #Minkowski tensor using the convention (+,-,-,-) used in the Quantum Field #Theory minkowski_tensor = Matrix( ( - (1,0,0,0), - (0,-1,0,0), - (0,0,-1,0), - (0,0,0,-1) - )) + (1, 0, 0, 0), + (0, -1, 0, 0), + (0, 0, -1, 0), + (0, 0, 0, -1) +)) diff -Nru python3-sympy-0.7.2/sympy/physics/mechanics/essential.py python3-sympy-0.7.3/sympy/physics/mechanics/essential.py --- python3-sympy-0.7.2/sympy/physics/mechanics/essential.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/physics/mechanics/essential.py 2013-07-13 17:53:32.000000000 +0000 @@ -2,9 +2,10 @@ 'MechanicsStrPrinter', 'MechanicsPrettyPrinter', 'MechanicsLatexPrinter'] -from sympy import (Matrix, Symbol, sin, cos, eye, trigsimp, diff, sqrt, sympify, - expand, zeros, Derivative, Function, symbols, Add, - solve, S) +from sympy import ( + Matrix, Symbol, sin, cos, eye, trigsimp, diff, sqrt, sympify, + expand, zeros, Derivative, Function, symbols, Add, + solve, S) from sympy.core import C from sympy.core.function import UndefinedFunction from sympy.printing.conventions import split_super_sub @@ -16,6 +17,7 @@ from sympy.core.compatibility import reduce from functools import reduce + class Dyadic(object): """A Dyadic object. @@ -44,7 +46,7 @@ added = 0 for i, v in enumerate(self.args): if ((str(inlist[0][1]) == str(self.args[i][1])) and - (str(inlist[0][2]) == str(self.args[i][2]))): + (str(inlist[0][2]) == str(self.args[i][2]))): self.args[i] = (self.args[i][0] + inlist[0][0], inlist[0][1], inlist[0][2]) inlist.remove(inlist[0]) @@ -57,7 +59,7 @@ # This code is to remove empty parts from the list while i < len(self.args): if ((self.args[i][0] == 0) | (self.args[i][1] == 0) | - (self.args[i][2] == 0)): + (self.args[i][2] == 0)): self.args.remove(self.args[i]) i -= 1 i += 1 @@ -156,10 +158,10 @@ return self * -1 def _latex(self, printer=None): - ar = self.args # just to shorten things + ar = self.args # just to shorten things if len(ar) == 0: return str(0) - ol = [] # output list, to be concatenated to a string + ol = [] # output list, to be concatenated to a string mlp = MechanicsLatexPrinter() for i, v in enumerate(ar): # if the coef of the dyadic is 1, we skip the 1 @@ -196,15 +198,17 @@ def _pretty(self, printer=None): e = self + class Fake(object): baseline = 0 + def render(self, *args, **kwargs): self = e - ar = self.args # just to shorten things + ar = self.args # just to shorten things mpp = MechanicsPrettyPrinter() if len(ar) == 0: return str(0) - ol = [] # output list, to be concatenated to a string + ol = [] # output list, to be concatenated to a string for i, v in enumerate(ar): # if the coef of the dyadic is 1, we skip the 1 if ar[i][0] == 1: @@ -300,10 +304,10 @@ def __str__(self, printer=None): """Printing method. """ - ar = self.args # just to shorten things + ar = self.args # just to shorten things if len(ar) == 0: return str(0) - ol = [] # output list, to be concatenated to a string + ol = [] # output list, to be concatenated to a string for i, v in enumerate(ar): # if the coef of the dyadic is 1, we skip the 1 if ar[i][0] == 1: @@ -396,7 +400,7 @@ """ - if frame2 == None: + if frame2 is None: frame2 = frame1 _check_frame(frame1) _check_frame(frame2) @@ -524,7 +528,7 @@ # The if statements below are for custom printing of basis-vectors for # each frame. # First case, when custom indices are supplied - if indices != None: + if indices is not None: if not isinstance(indices, (tuple, list)): raise TypeError('Supply the indices as a list') if len(indices) != 3: @@ -561,7 +565,7 @@ (r"\mathbf{\hat{%s}_z}" % name.lower())] self.indices = ['x', 'y', 'z'] # Different step, for custom latex basis vectors - if latexs != None: + if latexs is not None: if not isinstance(latexs, (tuple, list)): raise TypeError('Supply the indices as a list') if len(latexs) != 3: @@ -618,7 +622,7 @@ for i, v in enumerate(oldlist): if v[-1] != other: outlist.remove(v) - outlist.sort(key = len) + outlist.sort(key=len) if len(outlist) != 0: return outlist[0] raise ValueError('No Connecting Path found between ' + self.name + @@ -723,9 +727,10 @@ >>> N = ReferenceFrame('N') >>> A = N.orientnew('A', 'Axis', [q1, N.x]) >>> N.dcm(A) - [1, 0, 0] - [0, cos(q1), -sin(q1)] - [0, sin(q1), cos(q1)] + Matrix([ + [1, 0, 0], + [0, cos(q1), -sin(q1)], + [0, sin(q1), cos(q1)]]) """ @@ -739,9 +744,6 @@ def orient(self, parent, rot_type, amounts, rot_order=''): """Defines the orientation of this frame relative to a parent frame. - Supported orientation types are Body, Space, Quaternion, Axis. - Examples show correct usage. - Parameters ========== @@ -749,7 +751,9 @@ The frame that this ReferenceFrame will have its orientation matrix defined in relation to. rot_type : str - The type of orientation matrix that is being created. + The type of orientation matrix that is being created. Supported + types are 'Body', 'Space', 'Quaternion', and 'Axis'. See examples + for correct usage. amounts : list OR value The quantities that the orientation matrix will be defined by. rot_order : str @@ -804,6 +808,7 @@ for i, v in enumerate(amounts): if not isinstance(v, Vector): amounts[i] = sympify(v) + def _rot(axis, angle): """DCM for simple axis 1,2,or 3 rotations. """ if axis == 1: @@ -821,8 +826,9 @@ approved_orders = ('123', '231', '312', '132', '213', '321', '121', '131', '212', '232', '313', '323', '') - rot_order = str(rot_order).upper() # Now we need to make sure XYZ = 123 - rot_type = rot_type.upper() + rot_order = str( + rot_order).upper() # Now we need to make sure XYZ = 123 + rot_type = rot_type.upper() rot_order = [i.replace('X', '1') for i in rot_order] rot_order = [i.replace('Y', '2') for i in rot_order] rot_order = [i.replace('Z', '3') for i in rot_order] @@ -844,11 +850,12 @@ axis = axis.express(parent).normalize() axis = axis.args[0][0] parent_orient = ((eye(3) - axis * axis.T) * cos(theta) + - Matrix([[0, -axis[2], axis[1]],[axis[2], 0, -axis[0]], + Matrix([[0, -axis[2], axis[1]], [axis[2], 0, -axis[0]], [-axis[1], axis[0], 0]]) * sin(theta) + axis * axis.T) elif rot_type == 'QUATERNION': if not rot_order == '': - raise TypeError('Quaternion orientation takes no rotation order') + raise TypeError( + 'Quaternion orientation takes no rotation order') if not (isinstance(amounts, (list, tuple)) & (len(amounts) == 4)): raise TypeError('Amounts are a list or tuple of length 4') q0, q1, q2, q3 = amounts @@ -1126,7 +1133,7 @@ out += ((v2[0].T) * (v2[1].dcm(v1[1])) * (v1[0]))[0] - if Vector.simp == True: + if Vector.simp is True: return trigsimp(sympify(out), recursive=True) else: return sympify(out) @@ -1235,10 +1242,10 @@ def _latex(self, printer=None): """Latex Printing method. """ - ar = self.args # just to shorten things + ar = self.args # just to shorten things if len(ar) == 0: return str(0) - ol = [] # output list, to be concatenated to a string + ol = [] # output list, to be concatenated to a string for i, v in enumerate(ar): for j in 0, 1, 2: # if the coef of the basis vector is 1, we skip the 1 @@ -1252,7 +1259,7 @@ # also, we might wrap it in parentheses, for readability. arg_str = MechanicsStrPrinter().doprint(ar[i][0][j]) if isinstance(ar[i][0][j], Add): - arg_str = "(%s)"%arg_str + arg_str = "(%s)" % arg_str if arg_str[0] == '-': arg_str = arg_str[1:] str_start = ' - ' @@ -1270,14 +1277,16 @@ def _pretty(self, printer=None): """Pretty Printing method. """ e = self + class Fake(object): baseline = 0 + def render(self, *args, **kwargs): self = e - ar = self.args # just to shorten things + ar = self.args # just to shorten things if len(ar) == 0: return str(0) - ol = [] # output list, to be concatenated to a string + ol = [] # output list, to be concatenated to a string for i, v in enumerate(ar): for j in 0, 1, 2: # if the coef of the basis vector is 1, we skip the 1 @@ -1292,7 +1301,7 @@ arg_str = (MechanicsPrettyPrinter().doprint( ar[i][0][j])) if isinstance(ar[i][0][j], Add): - arg_str = "(%s)"%arg_str + arg_str = "(%s)" % arg_str if arg_str[0] == "-": arg_str = arg_str[1:] str_start = " - " @@ -1352,10 +1361,10 @@ def __str__(self, printer=None): """Printing method. """ - ar = self.args # just to shorten things + ar = self.args # just to shorten things if len(ar) == 0: return str(0) - ol = [] # output list, to be concatenated to a string + ol = [] # output list, to be concatenated to a string for i, v in enumerate(ar): for j in 0, 1, 2: # if the coef of the basis vector is 1, we skip the 1 @@ -1369,7 +1378,7 @@ # also, we might wrap it in parentheses, for readability. arg_str = MechanicsStrPrinter().doprint(ar[i][0][j]) if isinstance(ar[i][0][j], Add): - arg_str = "(%s)"%arg_str + arg_str = "(%s)" % arg_str if arg_str[0] == '-': arg_str = arg_str[1:] str_start = ' - ' @@ -1435,7 +1444,7 @@ mat[1][1] * mat[2][0])) outvec = Vector([]) - ar = other.args # For brevity + ar = other.args # For brevity for i, v in enumerate(ar): tempx = v[1].x tempy = v[1].y @@ -1496,7 +1505,7 @@ wrt = sympify(wrt) _check_frame(otherframe) outvec = S(0) - for i,v in enumerate(self.args): + for i, v in enumerate(self.args): if v[1] == otherframe: outvec += Vector([(v[0].diff(wrt), otherframe)]) else: @@ -1512,7 +1521,7 @@ """Calls .doit() on each term in the Vector""" ov = S(0) for i, v in enumerate(self.args): - ov += Vector([(v[0].applyfunc(lambda x: x.doit(**hints)) , v[1])]) + ov += Vector([(v[0].applyfunc(lambda x: x.doit(**hints)), v[1])]) return ov def dt(self, otherframe): @@ -1585,7 +1594,7 @@ if v[1] != otherframe: temp = otherframe.dcm(v[1]) * v[0] for i2, v2 in enumerate(temp): - if Vector.simp == True: + if Vector.simp is True: temp[i2] = trigsimp(v2, recursive=True) else: temp[i2] = v2 @@ -1634,7 +1643,7 @@ def _print_Derivative(self, e): t = dynamicsymbols._t if (bool(sum([i == t for i in e.variables])) & - isinstance(type(e.args[0]), UndefinedFunction)): + isinstance(type(e.args[0]), UndefinedFunction)): ol = str(e.args[0].func) for i, v in enumerate(e.variables): ol += dynamicsymbols._str @@ -1645,8 +1654,8 @@ def _print_Function(self, e): t = dynamicsymbols._t if isinstance(type(e), UndefinedFunction): - return StrPrinter().doprint(e).replace("(%s)"%t, '') - return e.func.__name__ + "(%s)"%self.stringify(e.args, ", ") + return StrPrinter().doprint(e).replace("(%s)" % t, '') + return e.func.__name__ + "(%s)" % self.stringify(e.args, ", ") class MechanicsLatexPrinter(LatexPrinter): @@ -1678,8 +1687,8 @@ inv_trig_power_case = False # If it is applicable to fold the argument brackets can_fold_brackets = self._settings['fold_func_brackets'] and \ - len(args) == 1 and \ - not self._needs_function_brackets(expr.args[0]) + len(args) == 1 and \ + not self._needs_function_brackets(expr.args[0]) inv_trig_table = ["asin", "acos", "atan", "acot"] @@ -1882,6 +1891,7 @@ other = Vector([]) return other + def dynamicsymbols(names, level=0): """Uses symbols and Function for functions of time. diff -Nru python3-sympy-0.7.2/sympy/physics/mechanics/functions.py python3-sympy-0.7.3/sympy/physics/mechanics/functions.py --- python3-sympy-0.7.2/sympy/physics/mechanics/functions.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/physics/mechanics/functions.py 2013-07-13 17:53:32.000000000 +0000 @@ -5,6 +5,7 @@ 'inertia', 'mechanics_printing', 'mprint', + 'msprint', 'mpprint', 'mlatex', 'kinematic_equations', @@ -27,6 +28,7 @@ from sympy import sympify, diff, sin, cos, Matrix from sympy.core.basic import S + def cross(vec1, vec2): """Cross product convenience wrapper for Vector.cross(): \n""" if not isinstance(vec1, (Vector, Dyadic)): @@ -34,6 +36,7 @@ return vec1 ^ vec2 cross.__doc__ += Vector.cross.__doc__ + def dot(vec1, vec2): """Dot product convenience wrapper for Vector.dot(): \n""" if not isinstance(vec1, (Vector, Dyadic)): @@ -41,6 +44,7 @@ return vec1 & vec2 dot.__doc__ += Vector.dot.__doc__ + def express(vec, frame, frame2=None): """Express convenience wrapper for Vector.express(): \n""" if not isinstance(vec, (Vector, Dyadic)): @@ -52,13 +56,15 @@ express.__doc__ += Vector.express.__doc__ + def outer(vec1, vec2): - """Outer prodcut convenience wrapper for Vector.outer():\n""" + """Outer product convenience wrapper for Vector.outer():\n""" if not isinstance(vec1, Vector): raise TypeError('Outer product is between two Vectors') return vec1 | vec2 outer.__doc__ += Vector.express.__doc__ + def inertia(frame, ixx, iyy, izz, ixy=0, iyz=0, izx=0): """Simple way to create inertia Dyadic object. @@ -95,7 +101,7 @@ if not isinstance(frame, ReferenceFrame): raise TypeError('Need to define the inertia in a frame') - ol = sympify(ixx) * (frame.x | frame.x) + ol = sympify(ixx) * (frame.x | frame.x) ol += sympify(ixy) * (frame.x | frame.y) ol += sympify(izx) * (frame.x | frame.z) ol += sympify(ixy) * (frame.y | frame.x) @@ -106,6 +112,7 @@ ol += sympify(izz) * (frame.z | frame.z) return ol + def inertia_of_point_mass(mass, pos_vec, frame): """Inertia dyadic of a point mass realtive to point O. @@ -136,6 +143,7 @@ (frame.z | frame.z)) * (pos_vec & pos_vec) - (pos_vec | pos_vec)) + def mechanics_printing(): """Sets up interactive printing for mechanics' derivatives. @@ -171,6 +179,7 @@ import sys sys.displayhook = mprint + def mprint(expr, **settings): r"""Function for printing of expressions generated in mechanics. @@ -198,14 +207,44 @@ """ - pr = MechanicsStrPrinter(settings) - outstr = pr.doprint(expr) + outstr = msprint(expr, **settings) import builtins if (outstr != 'None'): builtins._ = outstr print(outstr) + +def msprint(expr, **settings): + r"""Function for displaying expressions generated in mechanics. + + Returns the output of mprint() as a string. + + Parameters + ========== + + expr : valid sympy object + SymPy expression to print + settings : args + Same as print for SymPy + + Examples + ======== + + >>> from sympy.physics.mechanics import msprint, dynamicsymbols + >>> u1, u2 = dynamicsymbols('u1 u2') + >>> u2d = dynamicsymbols('u2', level=1) + >>> print(("%s = %s" % (u1, u2 + u2d))) + u1(t) = u2(t) + Derivative(u2(t), t) + >>> print(("%s = %s" % (msprint(u1), msprint(u2 + u2d)))) + u1 = u2 + u2' + + """ + + pr = MechanicsStrPrinter(settings) + return pr.doprint(expr) + + def mpprint(expr, **settings): r"""Function for pretty printing of expressions generated in mechanics. @@ -231,6 +270,7 @@ mp = MechanicsPrettyPrinter(settings) print((mp.doprint(expr))) + def mlatex(expr, **settings): r"""Function for printing latex representation of mechanics objects. @@ -268,6 +308,7 @@ return MechanicsLatexPrinter(settings).doprint(expr) + def kinematic_equations(speeds, coords, rot_type, rot_order=''): """Gives equations relating the qdot's to u's for a rotation type. @@ -305,18 +346,18 @@ # Code below is checking and sanitizing input approved_orders = ('123', '231', '312', '132', '213', '321', '121', '131', '212', '232', '313', '323', '1', '2', '3', '') - rot_order = str(rot_order).upper() # Now we need to make sure XYZ = 123 - rot_type = rot_type.upper() + rot_order = str(rot_order).upper() # Now we need to make sure XYZ = 123 + rot_type = rot_type.upper() rot_order = [i.replace('X', '1') for i in rot_order] rot_order = [i.replace('Y', '2') for i in rot_order] rot_order = [i.replace('Z', '3') for i in rot_order] rot_order = ''.join(rot_order) - if not isinstance(speeds,(list, tuple)): + if not isinstance(speeds, (list, tuple)): raise TypeError('Need to supply speeds in a list') if len(speeds) != 3: raise TypeError('Need to supply 3 body-fixed speeds') - if not isinstance(coords,(list, tuple)): + if not isinstance(coords, (list, tuple)): raise TypeError('Need to supply coordinates in a list') if rot_type.lower() in ['body', 'space']: if rot_order not in approved_orders: @@ -418,6 +459,7 @@ else: raise ValueError('Not an approved rotation type for this function') + def partial_velocity(vel_list, u_list, frame): """Returns a list of partial velocities. @@ -469,6 +511,7 @@ list_of_pvlists += [pvlist] return list_of_pvlists + def linear_momentum(frame, *body): """Linear momentum of the system. @@ -518,6 +561,7 @@ raise TypeError('*body must have only Particle or RigidBody') return linear_momentum_sys + def angular_momentum(point, frame, *body): """Angular momentum of a system @@ -575,6 +619,7 @@ raise TypeError('*body must have only Particle or RigidBody') return angular_momentum_sys + def kinetic_energy(frame, *body): """Kinetic energy of a multibody system. @@ -630,6 +675,7 @@ raise TypeError('*body must have only Particle or RigidBody') return ke_sys + def potential_energy(*body): """Potential energy of a multibody system. @@ -681,6 +727,7 @@ raise TypeError('*body must have only Particle or RigidBody') return pe_sys + def Lagrangian(frame, *body): """Lagrangian of a multibody system. diff -Nru python3-sympy-0.7.2/sympy/physics/mechanics/kane.py python3-sympy-0.7.3/sympy/physics/mechanics/kane.py --- python3-sympy-0.7.2/sympy/physics/mechanics/kane.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/physics/mechanics/kane.py 2013-07-13 17:53:32.000000000 +0000 @@ -10,6 +10,7 @@ partial_velocity) from functools import reduce + class KanesMethod(object): """Kane's method object. @@ -89,10 +90,11 @@ >>> forcing = KM.forcing >>> rhs = MM.inv() * forcing >>> rhs - [(-c*u(t) - k*q(t))/m] + Matrix([[(-c*u(t) - k*q(t))/m]]) >>> KM.linearize()[0] - [ 0, 1] - [-k, -c] + Matrix([ + [ 0, 1], + [-k, -c]]) Please look at the documentation pages for more information on how to perform linearization and how to deal with dependent coordinates & speeds, @@ -178,8 +180,8 @@ r1, c1 = A.shape r2, c2 = B.shape - temp1 = Matrix(r1, c1, lambda i, j: Symbol('x' + str(j + r1 * i))) - temp2 = Matrix(r2, c2, lambda i, j: Symbol('y' + str(j + r2 * i))) + temp1 = Matrix(r1, c1, lambda i, j: Symbol('x' + str(j) + str(r1 * i))) + temp2 = Matrix(r2, c2, lambda i, j: Symbol('y' + str(j) + str(r2 * i))) for i in range(len(temp1)): if A[i] == 0: temp1[i] = 0 @@ -193,7 +195,7 @@ return temp3.subs(dict(list(zip(temp1, A)))).subs(dict(list(zip(temp2, B)))) def _coords(self, qind, qdep=[], coneqs=[]): - """Supply all the generalized coordiantes in a list. + """Supply all the generalized coordinates in a list. If some coordinates are dependent, supply them as part of qdep. Their dependent nature will only show up in the linearization process though. @@ -262,7 +264,7 @@ if len(udep) != len(coneqs): raise ValueError('There must be an equal number of dependent ' 'speeds and constraints.') - if diffconeqs != None: + if diffconeqs is not None: if len(udep) != len(diffconeqs): raise ValueError('There must be an equal number of dependent ' 'speeds and constraints.') @@ -277,7 +279,7 @@ self._f_nh = coneqs.subs(uzero) self._k_nh = (coneqs - self._f_nh).jacobian(u) # if no differentiated non holonomic constraints were given, calculate - if diffconeqs == None: + if diffconeqs is None: self._k_dnh = self._k_nh self._f_dnh = (self._k_nh.diff(dynamicsymbols._t) * Matrix(u) + self._f_nh.diff(dynamicsymbols._t)) @@ -285,26 +287,26 @@ self._f_dnh = diffconeqs.subs(udotzero) self._k_dnh = (diffconeqs - self._f_dnh).jacobian(udot) - o = len(u) # number of generalized speeds - m = len(udep) # number of motion constraints - p = o - m # number of independent speeds + o = len(u) # number of generalized speeds + m = len(udep) # number of motion constraints + p = o - m # number of independent speeds # For a reminder, form of non-holonomic constraints is: # B u + C = 0 - B = self._k_nh[:m, :] - C = self._f_nh[:m, 0] + B = self._k_nh[:, :] + C = self._f_nh[:, 0] # We partition B into indenpendent and dependent columns # Ars is then -Bdep.inv() * Bind, and it relates depedent speeds to # independent speeds as: udep = Ars uind, neglecting the C term here. self._depB = B self._depC = C - mr1 = B[:m, :p] - ml1 = B[:m, p:o] + mr1 = B[:, :p] + ml1 = B[:, p:o] self._Ars = - self._mat_inv_mul(ml1, mr1) def kindiffdict(self): """Returns the qdot's in a dictionary. """ - if self._k_kqdot == None: + if self._k_kqdot is None: raise ValueError('Kin. diff. eqs need to be supplied first.') sub_dict = solve_linear_system_LU(Matrix([self._k_kqdot.T, -(self._k_ku * Matrix(self._u) + self._f_k).T]).T, self._qdot) @@ -367,8 +369,8 @@ N = self._inertial self._forcelist = fl[:] u = self._u - o = len(u) # number of gen. speeds - b = len(fl) # number of forces + o = len(u) # number of gen. speeds + b = len(fl) # number of forces FR = zeros(o, 1) @@ -391,7 +393,7 @@ FR[i] -= partials[j][i] & f_list[j] # In case there are dependent speeds - m = len(self._udep) # number of dependent speeds + m = len(self._udep) # number of dependent speeds if m != 0: p = o - m FRtilde = FR[:p, 0] @@ -421,8 +423,8 @@ t = dynamicsymbols._t N = self._inertial self._bodylist = bl - u = self._u # all speeds - udep = self._udep # dependent speeds + u = self._u # all speeds + udep = self._udep # dependent speeds o = len(u) m = len(udep) p = o - m @@ -461,15 +463,7 @@ for i, v in enumerate(bl): if isinstance(v, RigidBody): M = v.mass.subs(uaz).doit() - I, P = v.inertia - if P != v.masscenter: - # redefine I about the center of mass - # have I S/O, want I S/S* - # I S/O = I S/S* + I S*/O; I S/S* = I S/O - I S*/O - f = v.frame - d = v.masscenter.pos_from(P) - I -= inertia_of_point_mass(M, d, f) - I = I.subs(uaz).doit() + I = v.central_inertia.subs(uaz).doit() for j in range(o): for k in range(o): # translational @@ -551,17 +545,23 @@ """ - if (self._q == None) or (self._u == None): + if (self._q is None) or (self._u is None): raise ValueError('Speeds and coordinates must be supplied first.') - if (self._k_kqdot == None): - raise ValueError('Supply kinematic differential equations, please.') - + if (self._k_kqdot is None): + raise ValueError( + 'Supply kinematic differential equations, please.') fr = self._form_fr(FL) frstar = self._form_frstar(BL) if self._uaux != []: - km = KanesMethod(self._inertial, self._q, self._uaux, + if self._udep == []: + km = KanesMethod(self._inertial, self._q, self._uaux, u_auxiliary=self._uaux) + else: + km = KanesMethod(self._inertial, self._q, self._uaux, + u_auxiliary=self._uaux, u_dependent=self._udep, + velocity_constraints=(self._k_nh * Matrix(self._u) + self._f_nh)) + self._km = km fraux = km._form_fr(FL) frstaraux = km._form_frstar(BL) self._aux_eq = fraux + frstaraux @@ -604,7 +604,7 @@ """ - if (self._fr == None) or (self._frstar == None): + if (self._fr is None) or (self._frstar is None): raise ValueError('Need to compute Fr, Fr* first.') # Note that this is now unneccessary, and it should never be @@ -622,7 +622,8 @@ # Checking for dynamic symbols outside the dynamic differential # equations; throws error if there is. - insyms = set(self._q + self._qdot + self._u + self._udot + uaux + uauxdot) + insyms = set( + self._q + self._qdot + self._u + self._udot + uaux + uauxdot) if any(self._find_dynamicsymbols(i, insyms) for i in [self._k_kqdot, self._k_ku, self._f_k, @@ -642,15 +643,15 @@ raise ValueError('Cannot have derivatives of specified ' 'quantities when linearizing forcing terms.') - o = len(self._u) # number of speeds - n = len(self._q) # number of coordinates - l = len(self._qdep) # number of configuration constraints - m = len(self._udep) # number of motion constraints - qi = Matrix(self._q[: n - l]) # independent coords - qd = Matrix(self._q[n - l : n]) # dependent coords; could be empty - ui = Matrix(self._u[: o - m]) # independent speeds - ud = Matrix(self._u[o - m : o]) # dependent speeds; could be empty - qdot = Matrix(self._qdot) # time derivatives of coordinates + o = len(self._u) # number of speeds + n = len(self._q) # number of coordinates + l = len(self._qdep) # number of configuration constraints + m = len(self._udep) # number of motion constraints + qi = Matrix(self._q[: n - l]) # independent coords + qd = Matrix(self._q[n - l: n]) # dependent coords; could be empty + ui = Matrix(self._u[: o - m]) # independent speeds + ud = Matrix(self._u[o - m: o]) # dependent speeds; could be empty + qdot = Matrix(self._qdot) # time derivatives of coordinates # with equations in the form MM udot = forcing, expand that to: # MM_full [q,u].T = forcing_full. This combines coordinates and @@ -732,7 +733,7 @@ dqdot_dui = - self._k_kqdot.inv() * fku.jacobian(ui) dqdot_dqi = - self._k_kqdot.inv() * (fku.jacobian(qi) + fkf.jacobian(qi) + (fku.jacobian(qd) + fkf.jacobian(qd)) * - dqd_dqi) + dqd_dqi) f1_q = (f1.jacobian(qi) + f1.jacobian(qd) * dqd_dqi) f1_u = f1.jacobian(ui) f2_jac_qdot = f2.jacobian(qdot) @@ -793,7 +794,7 @@ """ - if inv_method == None: + if inv_method is None: self._rhs = self._mat_inv_mul(self.mass_matrix_full, self.forcing_full) else: @@ -803,7 +804,7 @@ @property def auxiliary_eqs(self): - if (self._fr == None) or (self._frstar == None): + if (self._fr is None) or (self._frstar is None): raise ValueError('Need to compute Fr, Fr* first.') if self._uaux == []: raise ValueError('No auxiliary speeds have been declared.') @@ -813,14 +814,14 @@ def mass_matrix(self): # Returns the mass matrix, which is augmented by the differentiated non # holonomic equations if necessary - if (self._frstar == None) & (self._fr == None): + if (self._frstar is None) & (self._fr is None): raise ValueError('Need to compute Fr, Fr* first.') return Matrix([self._k_d, self._k_dnh]) @property def mass_matrix_full(self): # Returns the mass matrix from above, augmented by kin diff's k_kqdot - if (self._frstar == None) & (self._fr == None): + if (self._frstar is None) & (self._fr is None): raise ValueError('Need to compute Fr, Fr* first.') o = len(self._u) n = len(self._q) @@ -831,7 +832,7 @@ def forcing(self): # Returns the forcing vector, which is augmented by the differentiated # non holonomic equations if necessary - if (self._frstar == None) & (self._fr == None): + if (self._frstar is None) & (self._fr is None): raise ValueError('Need to compute Fr, Fr* first.') return -Matrix([self._f_d, self._f_dnh]) @@ -839,7 +840,7 @@ def forcing_full(self): # Returns the forcing vector, which is augmented by the differentiated # non holonomic equations if necessary - if (self._frstar == None) & (self._fr == None): + if (self._frstar is None) & (self._fr is None): raise ValueError('Need to compute Fr, Fr* first.') f1 = self._k_ku * Matrix(self._u) + self._f_k return -Matrix([f1, self._f_d, self._f_dnh]) diff -Nru python3-sympy-0.7.2/sympy/physics/mechanics/lagrange.py python3-sympy-0.7.3/sympy/physics/mechanics/lagrange.py --- python3-sympy-0.7.2/sympy/physics/mechanics/lagrange.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/physics/mechanics/lagrange.py 2013-07-13 17:53:32.000000000 +0000 @@ -3,6 +3,7 @@ from sympy import diff, zeros, Matrix, eye, sympify from sympy.physics.mechanics import (dynamicsymbols, ReferenceFrame, Point) + class LagrangesMethod(object): """Lagrange's method object. @@ -78,19 +79,18 @@ >>> l = LagrangesMethod(L, [q], forcelist = fl, frame = N) >>> print(l.form_lagranges_equations()) - [b*Derivative(q(t), t) + 1.0*k*q(t) + m*Derivative(q(t), t, t)] + Matrix([[b*Derivative(q(t), t) + 1.0*k*q(t) + m*Derivative(q(t), t, t)]]) We can also solve for the states using the 'rhs' method. >>> print(l.rhs()) - [ Derivative(q(t), t)] - [(-b*Derivative(q(t), t) - 1.0*k*q(t))/m] + Matrix([[Derivative(q(t), t)], [(-b*Derivative(q(t), t) - 1.0*k*q(t))/m]]) Please refer to the docstrings on each method for more details. """ - def __init__(self, Lagrangian, q_list, coneqs = None, forcelist = None, frame = None): + def __init__(self, Lagrangian, q_list, coneqs=None, forcelist=None, frame=None): """Supply the following for the initialization of LagrangesMethod Lagrangian : Sympifyable @@ -116,12 +116,12 @@ """ self._L = sympify(Lagrangian) - self.eom = None #initializing the eom Matrix - self._m_cd = Matrix([]) #Mass Matrix of differentiated coneqs - self._m_d = Matrix([]) #Mass Matrix of dynamic equations - self._f_cd = Matrix([]) #Forcing part of the diff coneqs - self._f_d = Matrix([]) #Forcing part of the dynamic equations - self.lam_coeffs = Matrix([]) #Initializing the coeffecients of lams + self.eom = None # initializing the eom Matrix + self._m_cd = Matrix([]) # Mass Matrix of differentiated coneqs + self._m_d = Matrix([]) # Mass Matrix of dynamic equations + self._f_cd = Matrix([]) # Forcing part of the diff coneqs + self._f_d = Matrix([]) # Forcing part of the dynamic equations + self.lam_coeffs = Matrix([]) # Initializing the coeffecients of lams self.forcelist = forcelist self.inertial = frame @@ -169,7 +169,7 @@ #term1 and term2 will be there no matter what so leave them as they are - if self.coneqs != None: + if self.coneqs is not None: coneqs = self.coneqs #If there are coneqs supplied then the following will be created coneqs = list(coneqs) @@ -205,7 +205,7 @@ else: self._term3 = zeros(n, 1) - if self.forcelist != None: + if self.forcelist is not None: forcelist = self.forcelist N = self.inertial if not isinstance(N, ReferenceFrame): @@ -214,8 +214,8 @@ raise TypeError('Forces must be supplied in a list of: lists' ' or tuples') self._term4 = zeros(n, 1) - for i,v in enumerate(qd): - for j,w in enumerate(forcelist): + for i, v in enumerate(qd): + for j, w in enumerate(forcelist): if isinstance(w[0], ReferenceFrame): speed = w[0].ang_vel_in(N) self._term4[i] += speed.diff(v, N) & w[1] @@ -248,7 +248,7 @@ """ - if self.eom == None: + if self.eom is None: raise ValueError('Need to compute the equations of motion first') #The 'dynamic' mass matrix is generated by the following @@ -264,33 +264,33 @@ """ Augments the coefficients of qdots to the mass_matrix. """ n = len(self._q) - if self.eom == None: + if self.eom is None: raise ValueError('Need to compute the equations of motion first') #THE FIRST TWO ROWS OF THE MATRIX - row1 = eye(n).row_join(zeros(n,n)) - row2 = zeros(n,n).row_join(self.mass_matrix) - if self.coneqs != None: + row1 = eye(n).row_join(zeros(n, n)) + row2 = zeros(n, n).row_join(self.mass_matrix) + if self.coneqs is not None: m = len(self.coneqs) - I = eye(n).row_join(zeros(n,n+m)) - below_eye = zeros(n+m,n) - A = (self.mass_matrix).col_join((self._m_cd).row_join(zeros(m,m))) + I = eye(n).row_join(zeros(n, n + m)) + below_eye = zeros(n + m, n) + A = (self.mass_matrix).col_join((self._m_cd).row_join(zeros(m, m))) below_I = below_eye.row_join(A) return I.col_join(below_I) else: - A = row1.col_join(row2) - return A + A = row1.col_join(row2) + return A @property def forcing(self): """ Returns the forcing vector from 'lagranges_equations' method. """ - if self.eom == None: + if self.eom is None: raise ValueError('Need to compute the equations of motion first') qdd = self._qdoubledots qddzero = dict(list(zip(qdd, [0] * len(qdd)))) - if self.coneqs != None: + if self.coneqs is not None: lam = self.lam_vec lamzero = dict(list(zip(lam, [0] * len(lam)))) @@ -307,14 +307,14 @@ def forcing_full(self): """ Augments qdots to the forcing vector above. """ - if self.eom == None: + if self.eom is None: raise ValueError('Need to compute the equations of motion first') - if self.coneqs != None: + if self.coneqs is not None: return (Matrix(self._qdots)).col_join((self.forcing).col_join(self._f_cd)) else: return (Matrix(self._qdots)).col_join(self.forcing) - def rhs(self, method = "GE"): + def rhs(self, method="GE"): """ Returns equations that can be solved numerically Parameters @@ -328,5 +328,5 @@ # TODO- should probably use the matinvmul method from Kane - return ((self.mass_matrix_full).inv(method, try_block_diag = True) * + return ((self.mass_matrix_full).inv(method, try_block_diag=True) * self.forcing_full) diff -Nru python3-sympy-0.7.2/sympy/physics/mechanics/particle.py python3-sympy-0.7.3/sympy/physics/mechanics/particle.py --- python3-sympy-0.7.2/sympy/physics/mechanics/particle.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/physics/mechanics/particle.py 2013-07-13 17:53:32.000000000 +0000 @@ -3,6 +3,7 @@ from sympy import sympify from sympy.physics.mechanics.point import Point + class Particle(object): """A particle. @@ -15,11 +16,11 @@ ========== name : str Name of particle - mass : sympifyable - A SymPy expression representing the Particle's mass point : Point A physics/mechanics Point which represents the position, velocity, and acceleration of this Particle + mass : sympifyable + A SymPy expression representing the Particle's mass Examples ======== diff -Nru python3-sympy-0.7.2/sympy/physics/mechanics/point.py python3-sympy-0.7.3/sympy/physics/mechanics/point.py --- python3-sympy-0.7.2/sympy/physics/mechanics/point.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/physics/mechanics/point.py 2013-07-13 17:53:32.000000000 +0000 @@ -2,6 +2,7 @@ from sympy.physics.mechanics.essential import _check_frame, _check_vector + class Point(object): """This object represents a point in a dynamic system. @@ -44,7 +45,7 @@ for i, v in enumerate(oldlist): if v[-1] != other: outlist.remove(v) - outlist.sort(key = len) + outlist.sort(key=len) if len(outlist) != 0: return outlist[0] raise ValueError('No Connecting Path found between ' + other.name + diff -Nru python3-sympy-0.7.2/sympy/physics/mechanics/rigidbody.py python3-sympy-0.7.3/sympy/physics/mechanics/rigidbody.py --- python3-sympy-0.7.2/sympy/physics/mechanics/rigidbody.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/physics/mechanics/rigidbody.py 2013-07-13 17:53:32.000000000 +0000 @@ -4,6 +4,7 @@ from sympy.physics.mechanics.point import Point from sympy.physics.mechanics.essential import ReferenceFrame, Dyadic + class RigidBody(object): """An idealized rigid body. @@ -98,9 +99,22 @@ raise TypeError("RigidBody inertia must be about a Point.") self._inertia = I[0] self._inertia_point = I[1] + # have I S/O, want I S/S* + # I S/O = I S/S* + I S*/O; I S/S* = I S/O - I S*/O + # I_S/S* = I_S/O - I_S*/O + from sympy.physics.mechanics.functions import inertia_of_point_mass + I_Ss_O = inertia_of_point_mass(self.mass, + self.masscenter.pos_from(I[1]), + self.frame) + self._central_inertia = I[0] - I_Ss_O inertia = property(get_inertia, set_inertia) + @property + def central_inertia(self): + """The body's central inertia dyadic.""" + return self._central_inertia + def linear_momentum(self, frame): """ Linear momentum of the rigid body. @@ -178,7 +192,7 @@ """ - return ((self.inertia[0] & self.frame.ang_vel_in(frame)) + + return ((self.central_inertia & self.frame.ang_vel_in(frame)) + (point.vel(frame) ^ -self.masscenter.pos_from(point)) * self.mass) @@ -198,8 +212,8 @@ frame : ReferenceFrame The RigidBody's angular velocity and the velocity of it's mass - center is typically defined with respect to an inertial frame but - any relevant frame in which the velocity is known can be supplied. + center are typically defined with respect to an inertial frame but + any relevant frame in which the velocities are known can be supplied. Examples ======== @@ -221,7 +235,7 @@ """ - rotational_KE = (self.frame.ang_vel_in(frame) & (self.inertia[0] & + rotational_KE = (self.frame.ang_vel_in(frame) & (self.central_inertia & self.frame.ang_vel_in(frame)) / sympify(2)) translational_KE = (self.mass * (self.masscenter.vel(frame) & diff -Nru python3-sympy-0.7.2/sympy/physics/mechanics/tests/test_essential.py python3-sympy-0.7.3/sympy/physics/mechanics/tests/test_essential.py --- python3-sympy-0.7.2/sympy/physics/mechanics/tests/test_essential.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/physics/mechanics/tests/test_essential.py 2013-07-13 17:53:32.000000000 +0000 @@ -5,6 +5,7 @@ Vector.simp = True A = ReferenceFrame('A') + def test_dyadic(): d1 = A.x | A.x d2 = A.y | A.y @@ -40,6 +41,7 @@ assert d1.express(A, B) == (cos(q)) * (A.x | B.x) + (-sin(q)) * (A.x | B.y) assert d1.dt(B) == (-qd) * (A.y | A.x) + (-qd) * (A.x | A.y) + def test_ang_vel(): q1, q2, q3, q4 = dynamicsymbols('q1 q2 q3 q4') q1d, q2d, q3d, q4d = dynamicsymbols('q1 q2 q3 q4', 1) @@ -105,6 +107,7 @@ assert G.ang_vel_in(N) == q1d * (N.x + N.y).normalize() assert N.ang_vel_in(G) == -q1d * (N.x + N.y).normalize() + def test_dcm(): q1, q2, q3, q4 = dynamicsymbols('q1 q2 q3 q4') N = ReferenceFrame('N') @@ -117,25 +120,26 @@ [- sin(q1) * sin(q2) * sin(q3) + cos(q1) * cos(q3), - sin(q1) * cos(q2), sin(q1) * sin(q2) * cos(q3) + sin(q3) * cos(q1)], [sin(q1) * cos(q3) + sin(q2) * sin(q3) * cos(q1), cos(q1) * cos(q2), sin(q1) * - sin(q3) - sin(q2) * cos(q1) * cos(q3)], [- sin(q3) * cos(q2), sin(q2), + sin(q3) - sin(q2) * cos(q1) * cos(q3)], [- sin(q3) * cos(q2), sin(q2), cos(q2) * cos(q3)]]) # This is a little touchy. Is it ok to use simplify in assert? assert D.dcm(C) == Matrix( [[cos(q1) * cos(q3) * cos(q4) - sin(q3) * (- sin(q4) * cos(q2) + sin(q1) * sin(q2) * cos(q4)), - sin(q2) * sin(q4) - sin(q1) * - cos(q2) * cos(q4), sin(q3) * cos(q1) * cos(q4) + cos(q3) * (- sin(q4) * + cos(q2) * cos(q4), sin(q3) * cos(q1) * cos(q4) + cos(q3) * (- sin(q4) * cos(q2) + sin(q1) * sin(q2) * cos(q4))], [sin(q1) * cos(q3) + sin(q2) * sin(q3) * cos(q1), cos(q1) * cos(q2), sin(q1) * sin(q3) - - sin(q2) * cos(q1) * cos(q3)], [sin(q4) * cos(q1) * cos(q3) - + sin(q2) * cos(q1) * cos(q3)], [sin(q4) * cos(q1) * cos(q3) - sin(q3) * (cos(q2) * cos(q4) + sin(q1) * sin(q2) * sin(q4)), sin(q2) * - cos(q4) - sin(q1) * sin(q4) * cos(q2), sin(q3) * sin(q4) * cos(q1) + - cos(q3) * (cos(q2) * cos(q4) + sin(q1) * sin(q2) * sin(q4))]]) + cos(q4) - sin(q1) * sin(q4) * cos(q2), sin(q3) * sin(q4) * cos(q1) + + cos(q3) * (cos(q2) * cos(q4) + sin(q1) * sin(q2) * sin(q4))]]) assert E.dcm(N) == Matrix( [[cos(q2)*cos(q3), sin(q3)*cos(q2), -sin(q2)], [sin(q1)*sin(q2)*cos(q3) - sin(q3)*cos(q1), sin(q1)*sin(q2)*sin(q3) + cos(q1)*cos(q3), sin(q1)*cos(q2)], [sin(q1)*sin(q3) + sin(q2)*cos(q1)*cos(q3), - sin(q1)*cos(q3) + sin(q2)*sin(q3)*cos(q1), - cos(q1)*cos(q2)]]) + cos(q1)*cos(q2)]]) + def test_Vector(): assert A.x != A.y @@ -159,9 +163,9 @@ assert isinstance(v3, Vector) # We probably shouldn't be using simplify in dot... - assert dot(v3, A.x) == x + x**2 - assert dot(v3, A.y) == y + y**2 - assert dot(v3, A.z) == z + z**2 + assert dot(v3, A.x) == x**2 + x + assert dot(v3, A.y) == y**2 + y + assert dot(v3, A.z) == z**2 + z assert isinstance(v4, Vector) # We probably shouldn't be using simplify in dot... @@ -169,6 +173,7 @@ assert dot(v4, A.y) == y - y**2 assert dot(v4, A.z) == z - z**2 + def test_Vector_diffs(): q1, q2, q3, q4 = dynamicsymbols('q1 q2 q3 q4') q1d, q2d, q3d, q4d = dynamicsymbols('q1 q2 q3 q4', 1) @@ -231,6 +236,7 @@ assert v4.diff(q2d, B) == A.x - q3 * cos(q3) * N.z assert v4.diff(q3d, B) == B.x + q3 * N.x + N.y + def test_vector_simplify(): x, y, z, k, n, m, w, f, s, A = symbols('x, y, z, k, n, m, w, f, s, A') N = ReferenceFrame('N') @@ -252,6 +258,7 @@ test4.simplify() assert (test4 & N.x) == -2 * y + def test_dyadic_simplify(): x, y, z, k, n, m, w, f, s, A = symbols('x, y, z, k, n, m, w, f, s, A') N = ReferenceFrame('N') diff -Nru python3-sympy-0.7.2/sympy/physics/mechanics/tests/test_functions.py python3-sympy-0.7.3/sympy/physics/mechanics/tests/test_functions.py --- python3-sympy-0.7.2/sympy/physics/mechanics/tests/test_functions.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/physics/mechanics/tests/test_functions.py 2013-07-13 17:53:32.000000000 +0000 @@ -15,6 +15,7 @@ B = A.orientnew('B', 'Axis', [q2, A.x]) C = B.orientnew('C', 'Axis', [q3, B.y]) + def test_dot(): assert dot(A.x, A.x) == 1 assert dot(A.x, A.y) == 0 @@ -30,6 +31,7 @@ # TODO: Add dot product tests from different frames + def test_cross(): assert cross(A.x, A.x) == 0 assert cross(A.x, A.y) == A.z @@ -43,13 +45,14 @@ assert cross(A.z, A.y) == -A.x assert cross(A.z, A.z) == 0 + def test_cross_different_frames(): assert cross(N.x, A.x) == sin(q1)*A.z assert cross(N.x, A.y) == cos(q1)*A.z - assert cross(N.x, A.z) == -sin(q1)*A.x-cos(q1)*A.y + assert cross(N.x, A.z) == -sin(q1)*A.x - cos(q1)*A.y assert cross(N.y, A.x) == -cos(q1)*A.z assert cross(N.y, A.y) == sin(q1)*A.z - assert cross(N.y, A.z) == cos(q1)*A.x-sin(q1)*A.y + assert cross(N.y, A.z) == cos(q1)*A.x - sin(q1)*A.y assert cross(N.z, A.x) == A.y assert cross(N.z, A.y) == -A.x assert cross(N.z, A.z) == 0 @@ -66,12 +69,13 @@ assert cross(C.y, A.x) == sin(q3)*C.x - cos(q3)*C.z assert cross(C.z, A.x) == cos(q3)*C.y + def test_express(): assert express(A.x, C) == cos(q3)*C.x + sin(q3)*C.z assert express(A.y, C) == sin(q2)*sin(q3)*C.x + cos(q2)*C.y - \ - sin(q2)*cos(q3)*C.z + sin(q2)*cos(q3)*C.z assert express(A.z, C) == -sin(q3)*cos(q2)*C.x + sin(q2)*C.y + \ - cos(q2)*cos(q3)*C.z + cos(q2)*cos(q3)*C.z assert express(A.x, N) == cos(q1)*N.x + sin(q1)*N.y assert express(A.y, N) == -sin(q1)*N.x + cos(q1)*N.y assert express(A.z, N) == N.z @@ -83,9 +87,9 @@ assert express(A.z, B) == sin(q2)*B.y + cos(q2)*B.z assert express(A.x, C) == cos(q3)*C.x + sin(q3)*C.z assert express(A.y, C) == sin(q2)*sin(q3)*C.x + cos(q2)*C.y - \ - sin(q2)*cos(q3)*C.z + sin(q2)*cos(q3)*C.z assert express(A.z, C) == -sin(q3)*cos(q2)*C.x + sin(q2)*C.y + \ - cos(q2)*cos(q3)*C.z + cos(q2)*cos(q3)*C.z # Check to make sure UnitVectors get converted properly assert express(N.x, N) == N.x assert express(N.y, N) == N.y @@ -93,19 +97,19 @@ assert express(N.x, A) == (cos(q1)*A.x - sin(q1)*A.y) assert express(N.y, A) == (sin(q1)*A.x + cos(q1)*A.y) assert express(N.z, A) == A.z - assert express(N.x, B) == (cos(q1)*B.x - sin(q1)*cos(q2)*B.y + \ + assert express(N.x, B) == (cos(q1)*B.x - sin(q1)*cos(q2)*B.y + sin(q1)*sin(q2)*B.z) - assert express(N.y, B) == (sin(q1)*B.x + cos(q1)*cos(q2)*B.y - \ + assert express(N.y, B) == (sin(q1)*B.x + cos(q1)*cos(q2)*B.y - sin(q2)*cos(q1)*B.z) assert express(N.z, B) == (sin(q2)*B.y + cos(q2)*B.z) assert express(N.x, C) == ( - (cos(q1)*cos(q3)-sin(q1)*sin(q2)*sin(q3))*C.x - - sin(q1)*cos(q2)*C.y + - (sin(q3)*cos(q1)+sin(q1)*sin(q2)*cos(q3))*C.z) + (cos(q1)*cos(q3) - sin(q1)*sin(q2)*sin(q3))*C.x - + sin(q1)*cos(q2)*C.y + + (sin(q3)*cos(q1) + sin(q1)*sin(q2)*cos(q3))*C.z) assert express(N.y, C) == ( - (sin(q1)*cos(q3) + sin(q2)*sin(q3)*cos(q1))*C.x + - cos(q1)*cos(q2)*C.y + - (sin(q1)*sin(q3) - sin(q2)*cos(q1)*cos(q3))*C.z) + (sin(q1)*cos(q3) + sin(q2)*sin(q3)*cos(q1))*C.x + + cos(q1)*cos(q2)*C.y + + (sin(q1)*sin(q3) - sin(q2)*cos(q1)*cos(q3))*C.z) assert express(N.z, C) == (-sin(q3)*cos(q2)*C.x + sin(q2)*C.y + cos(q2)*cos(q3)*C.z) @@ -140,15 +144,15 @@ assert express(B.z, C) == (-sin(q3)*C.x + cos(q3)*C.z) assert express(C.x, N) == ( - (cos(q1)*cos(q3)-sin(q1)*sin(q2)*sin(q3))*N.x + - (sin(q1)*cos(q3)+sin(q2)*sin(q3)*cos(q1))*N.y - - sin(q3)*cos(q2)*N.z) + (cos(q1)*cos(q3) - sin(q1)*sin(q2)*sin(q3))*N.x + + (sin(q1)*cos(q3) + sin(q2)*sin(q3)*cos(q1))*N.y - + sin(q3)*cos(q2)*N.z) assert express(C.y, N) == ( - -sin(q1)*cos(q2)*N.x + cos(q1)*cos(q2)*N.y + sin(q2)*N.z) + -sin(q1)*cos(q2)*N.x + cos(q1)*cos(q2)*N.y + sin(q2)*N.z) assert express(C.z, N) == ( - (sin(q3)*cos(q1)+sin(q1)*sin(q2)*cos(q3))*N.x + - (sin(q1)*sin(q3)-sin(q2)*cos(q1)*cos(q3))*N.y + - cos(q2)*cos(q3)*N.z) + (sin(q3)*cos(q1) + sin(q1)*sin(q2)*cos(q3))*N.x + + (sin(q1)*sin(q3) - sin(q2)*cos(q1)*cos(q3))*N.y + + cos(q2)*cos(q3)*N.z) assert express(C.x, A) == (cos(q3)*A.x + sin(q2)*sin(q3)*A.y - sin(q3)*cos(q2)*A.z) assert express(C.y, A) == (cos(q2)*A.y + sin(q2)*A.z) @@ -233,6 +237,7 @@ assert C.x == express((cos(q3)*B.x - sin(q3)*B.z), C) assert C.z == express((sin(q3)*B.x + cos(q3)*B.z), C) + def test_inertia(): N = ReferenceFrame('N') ixx, iyy, izz = symbols('ixx iyy izz') @@ -242,9 +247,10 @@ assert inertia(N, 0, 0, 0) == 0 * (N.x | N.x) assert inertia(N, ixx, iyy, izz, ixy, iyz, izx) == (ixx * (N.x | N.x) + ixy * (N.x | N.y) + izx * (N.x | N.z) + ixy * (N.y | N.x) + iyy * - (N.y | N.y) + iyz * (N.y | N.z) + izx * (N.z | N.x) + iyz * (N.z | + (N.y | N.y) + iyz * (N.y | N.z) + izx * (N.z | N.x) + iyz * (N.z | N.y) + izz * (N.z | N.z)) + def test_kin_eqs(): q0, q1, q2, q3 = dynamicsymbols('q0 q1 q2 q3') q0d, q1d, q2d, q3d = dynamicsymbols('q0 q1 q2 q3', 1) @@ -255,6 +261,7 @@ -0.5 * q0 * u3 - 0.5 * q1 * u2 + 0.5 * q2 * u1 + q3d, 0.5 * q1 * u1 + 0.5 * q2 * u2 + 0.5 * q3 * u3 + q0d] + def test_inertia_of_point_mass(): r, s, t, m = symbols('r s t m') N = ReferenceFrame('N') @@ -283,8 +290,9 @@ m * s * t * (N.z | N.y) + m * (r**2 + s**2) * (N.z | N.z)) + def test_partial_velocity(): - q1, q2, q3, u1, u2, u3 = dynamicsymbols('q1 q2 q3 u1 u2 u3') + q1, q2, q3, u1, u2, u3 = dynamicsymbols('q1 q2 q3 u1 u2 u3') u4, u5 = dynamicsymbols('u4, u5') r = symbols('r') @@ -306,6 +314,7 @@ [0, 0, 0, L.x, cos(q2)*L.y - sin(q2)*L.z], [L.x, L.y, L.z, 0, 0]]) + def test_linear_momentum(): N = ReferenceFrame('N') Ac = Point('Ac') @@ -317,6 +326,7 @@ Pa.point.set_vel(N, 10 * N.x) assert linear_momentum(N, A, Pa) == 10 * N.x + 500 * N.y + def test_angular_momentum_and_linear_momentum(): m, M, l1 = symbols('m M l1') q1d = dynamicsymbols('q1d') @@ -332,8 +342,11 @@ Pa = Particle('Pa', P, m) I = outer(N.z, N.z) A = RigidBody('A', Ac, a, M, (I, Ac)) - assert linear_momentum(N, A, Pa) == 2 * m * q1d* l1 * N.y + M * l1 * q1d * N.y - assert angular_momentum(O, N, A, Pa) == 4 * m * q1d * l1**2 * N.z + q1d * N.z + assert linear_momentum( + N, A, Pa) == 2 * m * q1d* l1 * N.y + M * l1 * q1d * N.y + assert angular_momentum( + O, N, A, Pa) == 4 * m * q1d * l1**2 * N.z + q1d * N.z + def test_kinetic_energy(): m, M, l1 = symbols('m M l1') @@ -353,6 +366,7 @@ assert 0 == kinetic_energy(N, Pa, A) - (M*l1**2*omega**2/2 + 2*l1**2*m*omega**2 + omega**2/2) + def test_potential_energy(): m, M, l1, g, h, H = symbols('m M l1 g h H') omega = dynamicsymbols('omega') diff -Nru python3-sympy-0.7.2/sympy/physics/mechanics/tests/test_kane.py python3-sympy-0.7.3/sympy/physics/mechanics/tests/test_kane.py --- python3-sympy-0.7.2/sympy/physics/mechanics/tests/test_kane.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/physics/mechanics/tests/test_kane.py 2013-07-13 17:53:32.000000000 +0000 @@ -2,6 +2,7 @@ from sympy.physics.mechanics import (dynamicsymbols, ReferenceFrame, Point, RigidBody, KanesMethod, inertia, Particle) + def test_one_dof(): # This is for a 1 dof spring-mass-damper case. # It is described in more detail in the KanesMethod docstring. @@ -23,7 +24,9 @@ forcing = KM.forcing rhs = MM.inv() * forcing assert expand(rhs[0]) == expand(-(q * k + u * c) / m) - assert KM.linearize() == (Matrix([[0, 1], [-k, -c]]), Matrix([]), Matrix([])) + assert KM.linearize() == \ + (Matrix([[0, 1], [-k, -c]]), Matrix([]), Matrix([])) + def test_two_dof(): # This is for a 2 d.o.f., 2 particle spring-mass-damper. @@ -60,6 +63,7 @@ assert expand(rhs[1]) == expand((k1 * q1 + c1 * u1 - 2 * k2 * q2 - 2 * c2 * u2) / m) + def test_pend(): q, u = dynamicsymbols('q u') qd, ud = dynamicsymbols('q u', 1) @@ -102,7 +106,8 @@ L = Y.orientnew('L', 'Axis', [q2, Y.x]) R = L.orientnew('R', 'Axis', [q3, L.y]) R.set_ang_vel(N, u1 * L.x + u2 * L.y + u3 * L.z) - R.set_ang_acc(N, R.ang_vel_in(N).dt(R) + (R.ang_vel_in(N) ^ R.ang_vel_in(N))) + R.set_ang_acc( + N, R.ang_vel_in(N).dt(R) + (R.ang_vel_in(N) ^ R.ang_vel_in(N))) # This is the translational kinematics. We create a point with no velocity # in N; this is the contact point between the disc and ground. Next we form @@ -145,13 +150,14 @@ assert rhs.expand() == Matrix([(10*u2*u3*r - 5*u3**2*r*tan(q2) + 4*g*sin(q2))/(5*r), -2*u1*u3/3, u1*(-2*u2 + u3*tan(q2))]).expand() + def test_aux(): # Same as above, except we have 2 auxiliary speeds for the ground contact # point, which is known to be zero. In one case, we go through then # substitute the aux. speeds in at the end (they are zero, as well as their # derivative), in the other case, we use the built-in auxiliary speed part # of KanesMethod. The equations from each should be the same. - q1, q2, q3, u1, u2, u3 = dynamicsymbols('q1 q2 q3 u1 u2 u3') + q1, q2, q3, u1, u2, u3 = dynamicsymbols('q1 q2 q3 u1 u2 u3') q1d, q2d, q3d, u1d, u2d, u3d = dynamicsymbols('q1 q2 q3 u1 u2 u3', 1) u4, u5, f1, f2 = dynamicsymbols('u4, u5, f1, f2') u4d, u5d = dynamicsymbols('u4, u5', 1) @@ -182,34 +188,35 @@ KM = KanesMethod(N, q_ind=[q1, q2, q3], u_ind=[u1, u2, u3, u4, u5], kd_eqs=kd) (fr, frstar) = KM.kanes_equations(ForceList, BodyList) - fr = fr.subs({u4d: 0, u5d: 0}).subs({u4: 0, u5:0}) - frstar = frstar.subs({u4d: 0, u5d: 0}).subs({u4: 0, u5:0}) + fr = fr.subs({u4d: 0, u5d: 0}).subs({u4: 0, u5: 0}) + frstar = frstar.subs({u4d: 0, u5d: 0}).subs({u4: 0, u5: 0}) KM2 = KanesMethod(N, q_ind=[q1, q2, q3], u_ind=[u1, u2, u3], kd_eqs=kd, u_auxiliary=[u4, u5]) (fr2, frstar2) = KM2.kanes_equations(ForceList, BodyList) - fr2 = fr2.subs({u4d: 0, u5d: 0}).subs({u4: 0, u5:0}) - frstar2 = frstar2.subs({u4d: 0, u5d: 0}).subs({u4: 0, u5:0}) + fr2 = fr2.subs({u4d: 0, u5d: 0}).subs({u4: 0, u5: 0}) + frstar2 = frstar2.subs({u4d: 0, u5d: 0}).subs({u4: 0, u5: 0}) assert fr.expand() == fr2.expand() assert frstar.expand() == frstar2.expand() + def test_parallel_axis(): # This is for a 2 dof inverted pendulum on a cart. # This tests the parallel axis code in KanesMethod. The inertia of the # pendulum is defined about the hinge, not about the center of mass. # Defining the constants and knowns of the system - gravity = symbols('g') - k, ls = symbols('k ls') - a, mA, mC = symbols('a mA mC') - F = dynamicsymbols('F') - Ix, Iy, Iz = symbols('Ix Iy Iz') + gravity = symbols('g') + k, ls = symbols('k ls') + a, mA, mC = symbols('a mA mC') + F = dynamicsymbols('F') + Ix, Iy, Iz = symbols('Ix Iy Iz') # Declaring the Generalized coordinates and speeds - q1, q2 = dynamicsymbols('q1 q2') + q1, q2 = dynamicsymbols('q1 q2') q1d, q2d = dynamicsymbols('q1 q2', 1) - u1, u2 = dynamicsymbols('u1 u2') + u1, u2 = dynamicsymbols('u1 u2') u1d, u2d = dynamicsymbols('u1 u2', 1) # Creating reference frames @@ -224,28 +231,28 @@ # Creating and Locating the positions of the cart, C, and the # center of mass of the pendulum, A - C = O.locatenew('C', q1 * N.x) + C = O.locatenew('C', q1 * N.x) Ao = C.locatenew('Ao', a * A.y) # Defining velocities of the points O.set_vel(N, 0) C.set_vel(N, u1 * N.x) Ao.v2pt_theory(C, N, A) - Cart = Particle('Cart', C, mC) + Cart = Particle('Cart', C, mC) Pendulum = RigidBody('Pendulum', Ao, A, mA, (inertia(A, Ix, Iy, Iz), C)) # kinematical differential equations - kindiffs = [q1d - u1, q2d - u2] + kindiffs = [q1d - u1, q2d - u2] - bodyList = [Cart, Pendulum] + bodyList = [Cart, Pendulum] forceList = [(Ao, -N.y * gravity * mA), - (C, -N.y * gravity * mC), - (C, -N.x * k * (q1 - ls)), - (C, N.x * F)] + (C, -N.y * gravity * mC), + (C, -N.x * k * (q1 - ls)), + (C, N.x * F)] km = KanesMethod(N, [q1, q2], [u1, u2], kindiffs) - (fr,frstar) = km.kanes_equations(forceList, bodyList) + (fr, frstar) = km.kanes_equations(forceList, bodyList) mm = km.mass_matrix_full assert mm[3, 3] == Iz diff -Nru python3-sympy-0.7.2/sympy/physics/mechanics/tests/test_kane2.py python3-sympy-0.7.3/sympy/physics/mechanics/tests/test_kane2.py --- python3-sympy-0.7.2/sympy/physics/mechanics/tests/test_kane2.py 1970-01-01 00:00:00.000000000 +0000 +++ python3-sympy-0.7.3/sympy/physics/mechanics/tests/test_kane2.py 2013-07-13 17:53:32.000000000 +0000 @@ -0,0 +1,325 @@ +from sympy import cos, expand, Matrix, Poly, sin, solve, symbols +from sympy import tan, trigsimp, zeros +from sympy.physics.mechanics import (cross, dot, dynamicsymbols, KanesMethod, + inertia, inertia_of_point_mass, Particle, + Point, ReferenceFrame, RigidBody) + + +def test_aux_dep(): + # This test is about rolling disc dynamics, comparing the results found + # with KanesMethod to those found when deriving the equations "manually" + # with SymPy. + # The terms Fr, Fr*, and Fr*_steady are all compared between the two + # methods. Here, Fr*_steady refers to the generalized inertia forces for an + # equilibrium configuration. + # Note: comparing to the test of test_rolling_disc() in test_kane.py, this + # test also tests auxiliary speeds and configuration and motion constraints + #, seen in the generalized dependent coordinates q[3], and depend speeds + # u[3], u[4] and u[5]. + + + # First, mannual derivation of Fr, Fr_star, Fr_star_steady. + + # Symbols for time and constant parameters. + # Symbols for contact forces: Fx, Fy, Fz. + t, r, m, g, I, J = symbols('t r m g I J') + Fx, Fy, Fz = symbols('Fx Fy Fz') + + # Configuration variables and their time derivatives: + # q[0] -- yaw + # q[1] -- lean + # q[2] -- spin + # q[3] -- dot(-r*B.z, A.z) -- distance from ground plane to disc center in + # A.z direction + # Generalized speeds and their time derivatives: + # u[0] -- disc angular velocity component, disc fixed x direction + # u[1] -- disc angular velocity component, disc fixed y direction + # u[2] -- disc angular velocity component, disc fixed z direction + # u[3] -- disc velocity component, A.x direction + # u[4] -- disc velocity component, A.y direction + # u[5] -- disc velocity component, A.z direction + # Auxiliary generalized speeds: + # ua[0] -- contact point auxiliary generalized speed, A.x direction + # ua[1] -- contact point auxiliary generalized speed, A.y direction + # ua[2] -- contact point auxiliary generalized speed, A.z direction + q = dynamicsymbols('q:4') + qd = [qi.diff(t) for qi in q] + u = dynamicsymbols('u:6') + ud = [ui.diff(t) for ui in u] + #ud_zero = {udi : 0 for udi in ud} + ud_zero = dict(list(zip(ud, [0.]*len(ud)))) + ua = dynamicsymbols('ua:3') + #ua_zero = {uai : 0 for uai in ua} + ua_zero = dict(list(zip(ua, [0.]*len(ua)))) + + # Reference frames: + # Yaw intermediate frame: A. + # Lean intermediate frame: B. + # Disc fixed frame: C. + N = ReferenceFrame('N') + A = N.orientnew('A', 'Axis', [q[0], N.z]) + B = A.orientnew('B', 'Axis', [q[1], A.x]) + C = B.orientnew('C', 'Axis', [q[2], B.y]) + + # Angular velocity and angular acceleration of disc fixed frame + # u[0], u[1] and u[2] are generalized independent speeds. + C.set_ang_vel(N, u[0]*B.x + u[1]*B.y + u[2]*B.z) + C.set_ang_acc(N, C.ang_vel_in(N).diff(t, B) + + cross(B.ang_vel_in(N), C.ang_vel_in(N))) + + # Velocity and acceleration of points: + # Disc-ground contact point: P. + # Center of disc: O, defined from point P with depend coordinate: q[3] + # u[3], u[4] and u[5] are generalized dependent speeds. + P = Point('P') + P.set_vel(N, ua[0]*A.x + ua[1]*A.y + ua[2]*A.z) + O = P.locatenew('O', q[3]*A.z + r*sin(q[1])*A.y) + O.set_vel(N, u[3]*A.x + u[4]*A.y + u[5]*A.z) + O.set_acc(N, O.vel(N).diff(t, A) + cross(A.ang_vel_in(N), O.vel(N))) + + # Kinematic differential equations: + # Two equalities: one is w_c_n_qd = C.ang_vel_in(N) in three coordinates + # directions of B, for qd0, qd1 and qd2. + # the other is v_o_n_qd = O.vel(N) in A.z direction for qd3. + # Then, solve for dq/dt's in terms of u's: qd_kd. + w_c_n_qd = qd[0]*A.z + qd[1]*B.x + qd[2]*B.y + v_o_n_qd = O.pos_from(P).diff(t, A) + cross(A.ang_vel_in(N), O.pos_from(P)) + kindiffs = Matrix([dot(w_c_n_qd - C.ang_vel_in(N), uv) for uv in B] + + [dot(v_o_n_qd - O.vel(N), A.z)]) + qd_kd = solve(kindiffs, qd) + + # Values of generalized speeds during a steady turn for later substitution + # into the Fr_star_steady. + steady_conditions = solve(kindiffs.subs({qd[1] : 0, qd[3] : 0}), u) + steady_conditions.update({qd[1] : 0, qd[3] : 0}) + + # Partial angular velocities and velocities. + partial_w_C = [C.ang_vel_in(N).diff(ui, N) for ui in u + ua] + partial_v_O = [O.vel(N).diff(ui, N) for ui in u + ua] + partial_v_P = [P.vel(N).diff(ui, N) for ui in u + ua] + + # Configuration constraint: f_c, the projection of radius r in A.z direction + # is q[3]. + # Velocity constraints: f_v, for u3, u4 and u5. + # Acceleration constraints: f_a. + f_c = Matrix([dot(-r*B.z, A.z) - q[3]]) + f_v = Matrix([dot(O.vel(N) - (P.vel(N) + cross(C.ang_vel_in(N), + O.pos_from(P))), ai).expand() for ai in A]) + v_o_n = cross(C.ang_vel_in(N), O.pos_from(P)) + a_o_n = v_o_n.diff(t, A) + cross(A.ang_vel_in(N), v_o_n) + f_a = Matrix([dot(O.acc(N) - a_o_n, ai) for ai in A]) + + # Solve for constraint equations in the form of + # u_dependent = A_rs * [u_i; u_aux]. + # First, obtain constraint coefficient matrix: M_v * [u; ua] = 0; + # Second, taking u[0], u[1], u[2] as independent, + # taking u[3], u[4], u[5] as dependent, + # rearranging the matrix of M_v to be A_rs for u_dependent. + # Third, u_aux ==0 for u_dep, and resulting dictionary of u_dep_dict. + M_v = zeros(3, 9) + for i in range(3): + for j, ui in enumerate(u + ua): + M_v[i, j] = f_v[i].diff(ui) + + M_v_i = M_v[:, :3] + M_v_d = M_v[:, 3:6] + M_v_aux = M_v[:, 6:] + M_v_i_aux = M_v_i.row_join(M_v_aux) + A_rs = - M_v_d.inv() * M_v_i_aux + + u_dep = A_rs[:, :3] * Matrix(u[:3]) + u_dep_dict = dict(list(zip(u[3:], u_dep))) + #u_dep_dict = {udi : u_depi[0] for udi, u_depi in zip(u[3:], u_dep.tolist())} + + # Active forces: F_O acting on point O; F_P acting on point P. + # Generalized active forces (unconstrained): Fr_u = F_point * pv_point. + F_O = m*g*A.z + F_P = Fx * A.x + Fy * A.y + Fz * A.z + Fr_u = Matrix([dot(F_O, pv_o) + dot(F_P, pv_p) for pv_o, pv_p in + zip(partial_v_O, partial_v_P)]) + + # Inertia force: R_star_O. + # Inertia of disc: I_C_O, where J is a inertia component about principal axis. + # Inertia torque: T_star_C. + # Generalized inertia forces (unconstrained): Fr_star_u. + R_star_O = -m*O.acc(N) + I_C_O = inertia(B, I, J, I) + T_star_C = -(dot(I_C_O, C.ang_acc_in(N)) \ + + cross(C.ang_vel_in(N), dot(I_C_O, C.ang_vel_in(N)))) + Fr_star_u = Matrix([dot(R_star_O, pv) + dot(T_star_C, pav) for pv, pav in + zip(partial_v_O, partial_w_C)]) + + # Form nonholonomic Fr: Fr_c, and nonholonomic Fr_star: Fr_star_c. + # Also, nonholonomic Fr_star in steady turning condition: Fr_star_steady. + Fr_c = Fr_u[:3, :].col_join(Fr_u[6:, :]) + A_rs.T * Fr_u[3:6, :] + Fr_star_c = Fr_star_u[:3, :].col_join(Fr_star_u[6:, :])\ + + A_rs.T * Fr_star_u[3:6, :] + Fr_star_steady = Fr_star_c.subs(ud_zero).subs(u_dep_dict)\ + .subs(steady_conditions).subs({q[3]: -r*cos(q[1])}).expand() + + + # Second, using KaneMethod in mechanics for fr, frstar and frstar_steady. + + # Rigid Bodies: disc, with inertia I_C_O. + iner_tuple = (I_C_O, O) + disc = RigidBody('disc', O, C, m, iner_tuple) + bodyList = [disc] + + # Generalized forces: Gravity: F_o; Auxiliary forces: F_p. + F_o = (O, F_O) + F_p = (P, F_P) + forceList = [F_o, F_p] + + # KanesMethod. + kane = KanesMethod( + N, q_ind= q[:3], u_ind= u[:3], kd_eqs=kindiffs, + q_dependent=q[3:], configuration_constraints = f_c, + u_dependent=u[3:], velocity_constraints= f_v, + u_auxiliary=ua + ) + + # fr, frstar, frstar_steady and kdd(kinematic differential equations). + (fr, frstar)= kane.kanes_equations(forceList, bodyList) + frstar_steady = frstar.subs(ud_zero).subs(u_dep_dict).subs(steady_conditions)\ + .subs({q[3]: -r*cos(q[1])}).expand() + kdd = kane.kindiffdict() + + + # Test + # First try Fr_c == fr; + # Second try Fr_star_c == frstar; + # Third try Fr_star_steady == frstar_steady. + # Both signs are checked in case the equations were found with an inverse + # sign. + assert ((Matrix(Fr_c).expand() == fr.expand()) or + (Matrix(Fr_c).expand() == (-fr).expand())) + + assert ((Matrix(Fr_star_c).expand() == frstar.expand()) or + (Matrix(Fr_star_c).expand() == (-frstar).expand())) + + assert ((Matrix(Fr_star_steady).expand() == frstar_steady.expand()) or + (Matrix(Fr_star_steady).expand() == (-frstar_steady).expand())) + + +def test_mat_inv_mul(): + # Just a quick test to check that KanesMethod._mat_inv_mul works as + # intended. Uses SymPy generated primes as matrix entries, so each entry in + # each matrix should be symbolic and unique, allowing proper comparison. + # Checks _mat_inv_mul against Matrix.inv / Matrix.__mul__. + from sympy import Matrix, prime + from sympy.physics.mechanics import ReferenceFrame, KanesMethod + + # Just need to create an instance of KanesMethod to get to _mat_inv_mul + mat_inv_mul = KanesMethod(ReferenceFrame('N'), [1], [1])._mat_inv_mul + + # going to form 3 matrices + # 1 n x n + # different n x n + # 1 n x 2n + n = 3 + m1 = Matrix(n, n, lambda i, j: prime(i * n + j + 2)) + m2 = Matrix(n, n, lambda i, j: prime(i * n + j + 5)) + m3 = Matrix(n, n, lambda i, j: prime(i + j * n + 2)) + + assert mat_inv_mul(m1, m2) == m1.inv() * m2 + assert mat_inv_mul(m1, m3) == m1.inv() * m3 + + +def test_non_central_inertia(): + # This tests that the calculation of Fr* does not depend the point + # about which the inertia of a rigid body is defined. This test solves + # exercises 8.12, 8.17 from Kane 1985. + + # Declare symbols + q1, q2, q3 = dynamicsymbols('q1:4') + q1d, q2d, q3d = dynamicsymbols('q1:4', level=1) + u1, u2, u3, u4, u5 = dynamicsymbols('u1:6') + u_prime, R, M, g, e, f, theta = symbols('u\' R, M, g, e, f, theta') + a, b, mA, mB, IA, J, K, t = symbols('a b mA mB IA J K t') + Q1, Q2, Q3 = symbols('Q1, Q2 Q3') + IA22, IA23, IA33 = symbols('IA22 IA23 IA33') + + # Reference Frames + F = ReferenceFrame('F') + P = F.orientnew('P', 'axis', [-theta, F.y]) + A = P.orientnew('A', 'axis', [q1, P.x]) + A.set_ang_vel(F, u1*A.x + u3*A.z) + # define frames for wheels + B = A.orientnew('B', 'axis', [q2, A.z]) + C = A.orientnew('C', 'axis', [q3, A.z]) + B.set_ang_vel(A, u4 * A.z) + C.set_ang_vel(A, u5 * A.z) + + # define points D, S*, Q on frame A and their velocities + pD = Point('D') + pD.set_vel(A, 0) + # u3 will not change v_D_F since wheels are still assumed to roll without slip. + pD.set_vel(F, u2 * A.y) + + pS_star = pD.locatenew('S*', e*A.y) + pQ = pD.locatenew('Q', f*A.y - R*A.x) + for p in [pS_star, pQ]: + p.v2pt_theory(pD, F, A) + + # masscenters of bodies A, B, C + pA_star = pD.locatenew('A*', a*A.y) + pB_star = pD.locatenew('B*', b*A.z) + pC_star = pD.locatenew('C*', -b*A.z) + for p in [pA_star, pB_star, pC_star]: + p.v2pt_theory(pD, F, A) + + # points of B, C touching the plane P + pB_hat = pB_star.locatenew('B^', -R*A.x) + pC_hat = pC_star.locatenew('C^', -R*A.x) + pB_hat.v2pt_theory(pB_star, F, B) + pC_hat.v2pt_theory(pC_star, F, C) + + # the velocities of B^, C^ are zero since B, C are assumed to roll without slip + #kde = [dot(p.vel(F), b) for b in A for p in [pB_hat, pC_hat]] + kde = [q1d - u1, q2d - u4, q3d - u5] + vc = [dot(p.vel(F), A.y) for p in [pB_hat, pC_hat]] + + # inertias of bodies A, B, C + # IA22, IA23, IA33 are not specified in the problem statement, but are + # necessary to define an inertia object. Although the values of + # IA22, IA23, IA33 are not known in terms of the variables given in the + # problem statement, they do not appear in the general inertia terms. + inertia_A = inertia(A, IA, IA22, IA33, 0, IA23, 0) + inertia_B = inertia(B, K, K, J) + inertia_C = inertia(C, K, K, J) + + # define the rigid bodies A, B, C + rbA = RigidBody('rbA', pA_star, A, mA, (inertia_A, pA_star)) + rbB = RigidBody('rbB', pB_star, B, mB, (inertia_B, pB_star)) + rbC = RigidBody('rbC', pC_star, C, mB, (inertia_C, pC_star)) + + km = KanesMethod(F, q_ind=[q1, q2, q3], u_ind=[u1, u2], kd_eqs=kde, + u_dependent=[u4, u5], velocity_constraints=vc, + u_auxiliary=[u3]) + + forces = [(pS_star, -M*g*F.x), (pQ, Q1*A.x + Q2*A.y + Q3*A.z)] + bodies = [rbA, rbB, rbC] + fr, fr_star = km.kanes_equations(forces, bodies) + vc_map = solve(vc, [u4, u5]) + + # KanesMethod returns the negative of Fr, Fr* as defined in Kane1985. + fr_star_expected = Matrix([ + -(IA + 2*J*b**2/R**2 + 2*K + + mA*a**2 + 2*mB*b**2) * u1.diff(t) - mA*a*u1*u2, + -(mA + 2*mB +2*J/R**2) * u2.diff(t) + mA*a*u1**2, + 0]) * -1 + assert (trigsimp(fr_star.subs(vc_map).subs(u3, 0)).doit().expand() == + fr_star_expected.expand()) + + # define inertias of rigid bodies A, B, C about point D + # I_S/O = I_S/S* + I_S*/O + bodies2 = [] + for rb, I_star in zip([rbA, rbB, rbC], [inertia_A, inertia_B, inertia_C]): + I = I_star + inertia_of_point_mass(rb.mass, + rb.masscenter.pos_from(pD), + rb.frame) + bodies2.append(RigidBody('', rb.masscenter, rb.frame, rb.mass, + (I, pD))) + fr2, fr_star2 = km.kanes_equations(forces, bodies2) + assert (trigsimp(fr_star2.subs(vc_map).subs(u3, 0)).doit().expand() == + fr_star_expected.expand()) diff -Nru python3-sympy-0.7.2/sympy/physics/mechanics/tests/test_lagrange.py python3-sympy-0.7.3/sympy/physics/mechanics/tests/test_lagrange.py --- python3-sympy-0.7.2/sympy/physics/mechanics/tests/test_lagrange.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/physics/mechanics/tests/test_lagrange.py 2013-07-13 17:53:32.000000000 +0000 @@ -2,7 +2,9 @@ RigidBody, LagrangesMethod, Particle, kinetic_energy, dynamicsymbols, inertia, potential_energy, Lagrangian) -from sympy import symbols, pi, sin, cos, simplify, expand +from sympy import symbols, pi, sin, cos, tan, simplify, expand, Function, \ + Derivative + def test_disc_on_an_incline_plane(): # Disc rolling on an inclined plane @@ -19,7 +21,7 @@ # Next, we create the inertial reference frame 'N'. A reference frame 'A' # is attached to the inclined plane. Finally a frame is created which is attached to the disk. N = ReferenceFrame('N') - A = N.orientnew('A', 'Axis', [pi/2 -alpha, N.z]) + A = N.orientnew('A', 'Axis', [pi/2 - alpha, N.z]) B = A.orientnew('B', 'Axis', [-theta, A.z]) # Creating the disc 'D'; we create the point that represents the mass @@ -48,7 +50,8 @@ coneq = [yd - R * thetad] m = LagrangesMethod(L, q, coneq) m.form_lagranges_equations() - assert m.rhs()[2] == 2*g*sin(alpha)/3 + assert m.rhs()[2] == 2*g*sin(alpha)/3 + def test_simp_pen(): # This tests that the equations generated by LagrangesMethod are identical @@ -90,6 +93,7 @@ RHS = lm.rhs() assert RHS[1] == -g*sin(q)/l + def test_dub_pen(): # The system considered is the double pendulum. Like in the @@ -130,12 +134,13 @@ lm = LagrangesMethod(L, [q1, q2]) lm.form_lagranges_equations() - assert expand(l*m*(2*g*sin(q1) + l*sin(q1)*sin(q2)*q2dd + assert simplify(l*m*(2*g*sin(q1) + l*sin(q1)*sin(q2)*q2dd + l*sin(q1)*cos(q2)*q2d**2 - l*sin(q2)*cos(q1)*q2d**2 - + l*cos(q1)*cos(q2)*q2dd + 2*l*q1dd) - (simplify(lm.eom[0]))) == 0 - assert expand((l*m*(g*sin(q2) + l*sin(q1)*sin(q2)*q1dd + + l*cos(q1)*cos(q2)*q2dd + 2*l*q1dd) - lm.eom[0]) == 0 + assert simplify(l*m*(g*sin(q2) + l*sin(q1)*sin(q2)*q1dd - l*sin(q1)*cos(q2)*q1d**2 + l*sin(q2)*cos(q1)*q1d**2 - + l*cos(q1)*cos(q2)*q1dd + l*q2dd)) - (simplify(lm.eom[1]))) == 0 + + l*cos(q1)*cos(q2)*q1dd + l*q2dd) - lm.eom[1]) == 0 + def test_rolling_disc(): # Rolling Disc Example @@ -175,11 +180,19 @@ BodyD.set_potential_energy(- m * g * r * cos(q2)) Lag = Lagrangian(N, BodyD) q = [q1, q2, q3] + q1 = Function('q1') + q2 = Function('q2') + q3 = Function('q3') l = LagrangesMethod(Lag, q) l.form_lagranges_equations() RHS = l.rhs() RHS.simplify() + t = symbols('t') + assert (l.mass_matrix[3:6] == [0, 5*m*r**2/4, 0]) - assert (RHS[4] == (-4*g*sin(q2) + 5*r*sin(q2)*cos(q2)*q1d**2 - + 6*r*cos(q2)*q1d*q3d)/(5*r)) - assert RHS[5] == (5*sin(q2)**2*q1d + 6*sin(q2)*q3d - q1d)*q2d/cos(q2) + assert RHS[4].simplify() == ( + (-8*g*sin(q2(t)) + r*(5*sin(2*q2(t))*Derivative(q1(t), t) + + 12*cos(q2(t))*Derivative(q3(t), t))*Derivative(q1(t), t))/(10*r)) + assert RHS[5] == (-5*cos(q2(t))*Derivative(q1(t), t) + 6*tan(q2(t) + )*Derivative(q3(t), t) + 4*Derivative(q1(t), t)/cos(q2(t)) + )*Derivative(q2(t), t) diff -Nru python3-sympy-0.7.2/sympy/physics/mechanics/tests/test_particle.py python3-sympy-0.7.3/sympy/physics/mechanics/tests/test_particle.py --- python3-sympy-0.7.2/sympy/physics/mechanics/tests/test_particle.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/physics/mechanics/tests/test_particle.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,6 +1,7 @@ from sympy import symbols from sympy.physics.mechanics import Point, Particle, ReferenceFrame + def test_particle(): m, m2, v1, v2, v3, r, g, h = symbols('m m2 v1 v2 v3 r g h') P = Point('P') @@ -32,4 +33,7 @@ assert p.angular_momentum(O, N) == m2 * r * (v3 * N.x - v1 * N.z) p.set_potential_energy(m * g * h) assert p.potential_energy == m * g * h - assert p.kinetic_energy(N) == m2 * v1**2 / 2 + m2 * v2**2 / 2+ m2 * v3**2 / 2 + # TODO make the result not be system-dependent + assert p.kinetic_energy( + N) in [m2*(v1**2 + v2**2 + v3**2)/2, + m2 * v1**2 / 2 + m2 * v2**2 / 2 + m2 * v3**2 / 2] diff -Nru python3-sympy-0.7.2/sympy/physics/mechanics/tests/test_point.py python3-sympy-0.7.3/sympy/physics/mechanics/tests/test_point.py --- python3-sympy-0.7.2/sympy/physics/mechanics/tests/test_point.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/physics/mechanics/tests/test_point.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,5 +1,6 @@ from sympy.physics.mechanics import dynamicsymbols, Point, ReferenceFrame + def test_point_v1pt_theorys(): q, q2 = dynamicsymbols('q q2') qd, q2d = dynamicsymbols('q q2', 1) @@ -17,6 +18,7 @@ P.set_vel(B, B.z) assert P.v1pt_theory(O, N, B) == B.z + N.x + qd * B.y + def test_point_a1pt_theorys(): q, q2 = dynamicsymbols('q q2') qd, q2d = dynamicsymbols('q q2', 1) @@ -28,13 +30,14 @@ P = O.locatenew('P', B.x) P.set_vel(B, 0) O.set_vel(N, 0) - assert P.a1pt_theory(O, N, B) == -(qd**2) * B.x + qdd * B.y + assert P.a1pt_theory(O, N, B) == -(qd**2) * B.x + qdd * B.y P.set_vel(B, q2d * B.z) assert P.a1pt_theory(O, N, B) == -(qd**2) * B.x + qdd * B.y + q2dd * B.z O.set_vel(N, q2d * B.x) assert P.a1pt_theory(O, N, B) == ((q2dd - qd**2) * B.x + (q2d * qd + qdd) * B.y + q2dd * B.z) + def test_point_v2pt_theorys(): q = dynamicsymbols('q') qd = dynamicsymbols('q', 1) @@ -49,6 +52,7 @@ O.set_vel(N, N.x) assert P.v2pt_theory(O, N, B) == N.x + qd * B.y + def test_point_a2pt_theorys(): q = dynamicsymbols('q') qd = dynamicsymbols('q', 1) @@ -62,6 +66,7 @@ P.set_pos(O, B.x) assert P.a2pt_theory(O, N, B) == (-qd**2) * B.x + (qdd) * B.y + def test_point_funcs(): q, q2 = dynamicsymbols('q q2') qd, q2d = dynamicsymbols('q q2', 1) @@ -93,6 +98,7 @@ O.set_vel(N, 0) assert P.v1pt_theory(O, N, B) == qd * B.x + q2d * B.y - 5 * q * B.z + def test_point_pos(): q = dynamicsymbols('q') N = ReferenceFrame('N') diff -Nru python3-sympy-0.7.2/sympy/physics/mechanics/tests/test_rigidbody.py python3-sympy-0.7.3/sympy/physics/mechanics/tests/test_rigidbody.py --- python3-sympy-0.7.2/sympy/physics/mechanics/tests/test_rigidbody.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/physics/mechanics/tests/test_rigidbody.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,9 +1,11 @@ from sympy import symbols from sympy.physics.mechanics import Point, ReferenceFrame, Dyadic, RigidBody from sympy.physics.mechanics import dynamicsymbols, outer +from sympy.physics.mechanics import inertia_of_point_mass + def test_rigidbody(): - m, m2, v1,v2, v3, omega = symbols('m m2 v1 v2 v3 omega') + m, m2, v1, v2, v3, omega = symbols('m m2 v1 v2 v3 omega') A = ReferenceFrame('A') A2 = ReferenceFrame('A2') P = Point('P') @@ -28,17 +30,18 @@ assert B.inertia == (I2, B.masscenter) # Testing linear momentum function assuming A2 is the inertial frame - N = ReferenceFrame('N') + N = ReferenceFrame('N') P2.set_vel(N, v1 * N.x + v2 * N.y + v3 * N.z) assert B.linear_momentum(N) == m2 * (v1 * N.x + v2 * N.y + v3 * N.z) + def test_rigidbody2(): M, v, r, omega, g, h = dynamicsymbols('M v r omega g h') N = ReferenceFrame('N') b = ReferenceFrame('b') b.set_ang_vel(N, omega * b.x) P = Point('P') - I = outer (b.x, b.x) + I = outer(b.x, b.x) Inertia_tuple = (I, P) B = RigidBody('B', P, b, M, Inertia_tuple) P.set_vel(N, v * b.x) @@ -50,3 +53,23 @@ B.set_potential_energy(M * g * h) assert B.potential_energy == M * g * h assert B.kinetic_energy(N) == (omega**2 + M * v**2) / 2 + +def test_rigidbody3(): + q1, q2, q3, q4 = dynamicsymbols('q1:5') + p1, p2, p3 = symbols('p1:4') + m = symbols('m') + + A = ReferenceFrame('A') + B = A.orientnew('B', 'axis', [q1, A.x]) + O = Point('O') + O.set_vel(A, q2*A.x + q3*A.y + q4*A.z) + P = O.locatenew('P', p1*B.x + p2*B.y + p3*B.z) + I = outer(B.x, B.x) + + rb1 = RigidBody('rb1', P, B, m, (I, P)) + # I_S/O = I_S/S* + I_S*/O + rb2 = RigidBody('rb2', P, B, m, + (I + inertia_of_point_mass(m, P.pos_from(O), B), O)) + + assert rb1.central_inertia == rb2.central_inertia + assert rb1.angular_momentum(O, A) == rb2.angular_momentum(O, A) diff -Nru python3-sympy-0.7.2/sympy/physics/paulialgebra.py python3-sympy-0.7.3/sympy/physics/paulialgebra.py --- python3-sympy-0.7.2/sympy/physics/paulialgebra.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/physics/paulialgebra.py 2013-07-13 17:53:32.000000000 +0000 @@ -4,15 +4,17 @@ See the documentation to the class Pauli for examples. -See also: - http://en.wikipedia.org/wiki/Pauli_matrices +References +~~~~~~~~~~ +.. [1] http://en.wikipedia.org/wiki/Pauli_matrices """ from sympy import Symbol, I __all__ = ['evaluate_pauli_product'] -def delta(i,j): + +def delta(i, j): """ Returns 1 if i == j, else 0. @@ -27,12 +29,13 @@ >>> delta(2, 3) 0 """ - if i==j: + if i == j: return 1 else: return 0 -def epsilon(i,j,k): + +def epsilon(i, j, k): """ Return 1 if i,j,k is equal to (1,2,3), (2,3,1), or (3,1,2); -1 if i,j,k is equal to (1,3,2), (3,2,1), or (2,1,3); @@ -49,13 +52,14 @@ >>> epsilon(1, 3, 2) -1 """ - if (i,j,k) in [(1,2,3), (2,3,1), (3,1,2)]: + if (i, j, k) in [(1, 2, 3), (2, 3, 1), (3, 1, 2)]: return 1 - elif (i,j,k) in [(1,3,2), (3,2,1), (2,1,3)]: + elif (i, j, k) in [(1, 3, 2), (3, 2, 1), (2, 1, 3)]: return -1 else: return 0 + class Pauli(Symbol): """The class representing algebraic properties of Pauli matrices @@ -102,10 +106,10 @@ __slots__ = ["i"] def __new__(cls, i): - if not i in [1,2,3]: + if not i in [1, 2, 3]: raise IndexError("Invalid Pauli index") - obj = Symbol.__new__(cls, "sigma%d"%i, commutative=False) - obj.i=i + obj = Symbol.__new__(cls, "sigma%d" % i, commutative=False) + obj.i = i return obj def __getnewargs__(self): @@ -114,18 +118,19 @@ # FIXME don't work for -I*Pauli(2)*Pauli(3) def __mul__(self, other): if isinstance(other, Pauli): - j=self.i - k=other.i - return delta(j,k) \ - +I*epsilon(j,k,1)*Pauli(1) \ - +I*epsilon(j,k,2)*Pauli(2) \ - +I*epsilon(j,k,3)*Pauli(3) + j = self.i + k = other.i + return delta(j, k) \ + + I*epsilon(j, k, 1)*Pauli(1) \ + + I*epsilon(j, k, 2)*Pauli(2) \ + + I*epsilon(j, k, 3)*Pauli(3) return super(Pauli, self).__mul__(other) def _eval_power(b, e): if e.is_Integer and e.is_positive: return super(Pauli, b).__pow__(int(e) % 2) + def evaluate_pauli_product(arg): '''Help function to evaluate Pauli matrices product with symbolic objects @@ -155,4 +160,4 @@ sigma_product *= el else: com_product *= el - return (sigma_product*com_product) + return (tmp[0]*sigma_product*com_product) diff -Nru python3-sympy-0.7.2/sympy/physics/qho_1d.py python3-sympy-0.7.3/sympy/physics/qho_1d.py --- python3-sympy-0.7.2/sympy/physics/qho_1d.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/physics/qho_1d.py 2013-07-13 17:53:32.000000000 +0000 @@ -2,6 +2,7 @@ from sympy.functions import hermite, sqrt, exp, factorial from sympy.physics.quantum.constants import hbar + def psi_n(n, x, m, omega): """ Returns the wavefunction psi_{n} for the One-dimensional harmonic oscillator. @@ -32,12 +33,12 @@ n, x, m, omega = list(map(S, [n, x, m, omega])) nu = m * omega / hbar # normalization coefficient - C = (nu/pi)**(S(1)/4) * sqrt(1/(2**n*factorial(n))) + C = (nu/pi)**(S(1)/4) * sqrt(1/(2**n*factorial(n))) return C * exp(-nu* x**2 /2) * hermite(n, sqrt(nu)*x) -def E_n(n,omega): +def E_n(n, omega): """ Returns the Energy of the One-dimensional harmonic oscillator @@ -62,4 +63,4 @@ hbar*omega*(x + 1/2) """ - return hbar * omega*(n + Rational(1,2)) + return hbar * omega*(n + Rational(1, 2)) diff -Nru python3-sympy-0.7.2/sympy/physics/quantum/anticommutator.py python3-sympy-0.7.3/sympy/physics/quantum/anticommutator.py --- python3-sympy-0.7.2/sympy/physics/quantum/anticommutator.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/physics/quantum/anticommutator.py 2013-07-13 17:53:32.000000000 +0000 @@ -83,8 +83,10 @@ @classmethod def eval(cls, a, b): - if not (a and b): return S.Zero - if a == b: return Integer(2)*a**2 + if not (a and b): + return S.Zero + if a == b: + return Integer(2)*a**2 if a.is_commutative or b.is_commutative: return Integer(2)*a*b @@ -99,7 +101,7 @@ # Canonical ordering of arguments #The Commutator [A,B] is on canonical form if A < B. if a.compare(b) == 1: - return cls(b,a) + return cls(b, a) def doit(self, **hints): """ Evaluate anticommutator """ @@ -122,7 +124,8 @@ def _sympyrepr(self, printer, *args): return "%s(%s,%s)" % ( - self.__class__.__name__, printer._print(self.args[0]), printer._print(self.args[1]) + self.__class__.__name__, printer._print( + self.args[0]), printer._print(self.args[1]) ) def _sympystr(self, printer, *args): diff -Nru python3-sympy-0.7.2/sympy/physics/quantum/cartesian.py python3-sympy-0.7.3/sympy/physics/quantum/cartesian.py --- python3-sympy-0.7.2/sympy/physics/quantum/cartesian.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/physics/quantum/cartesian.py 2013-07-13 17:53:32.000000000 +0000 @@ -35,6 +35,7 @@ # Position operators #------------------------------------------------------------------------- + class XOp(HermitianOperator): """1D cartesian position operator.""" @@ -58,7 +59,7 @@ def _represent_PxKet(self, basis, **options): index = options.pop("index", 1) - states = basis._enumerate_state(2, start_index = index) + states = basis._enumerate_state(2, start_index=index) coord1 = states[0].momentum coord2 = states[1].momentum d = DifferentialOperator(coord1) @@ -66,6 +67,7 @@ return I*hbar*(d*delta) + class YOp(HermitianOperator): """ Y cartesian coordinate operator (for 2D or 3D systems) """ @@ -80,6 +82,7 @@ def _apply_operator_PositionKet3D(self, ket): return ket.position_y*ket + class ZOp(HermitianOperator): """ Z cartesian coordinate operator (for 3D systems) """ @@ -98,6 +101,7 @@ # Momentum operators #------------------------------------------------------------------------- + class PxOp(HermitianOperator): """1D cartesian momentum operator.""" @@ -115,7 +119,7 @@ def _represent_XKet(self, basis, **options): index = options.pop("index", 1) - states = basis._enumerate_state(2, start_index = index) + states = basis._enumerate_state(2, start_index=index) coord1 = states[0].position coord2 = states[1].position d = DifferentialOperator(coord1) @@ -132,6 +136,7 @@ # Position eigenstates #------------------------------------------------------------------------- + class XKet(Ket): """1D cartesian position eigenket.""" @@ -140,7 +145,7 @@ return self.__new__(self, *_lowercase_labels(op), **options) def _state_to_operators(self, op_class, **options): - return op_class.__new__(op_class, \ + return op_class.__new__(op_class, *_uppercase_labels(self), **options) @classmethod @@ -160,11 +165,12 @@ return _enumerate_continuous_1D(self, num_states, **options) def _eval_innerproduct_XBra(self, bra, **hints): - return DiracDelta(self.position-bra.position) + return DiracDelta(self.position - bra.position) def _eval_innerproduct_PxBra(self, bra, **hints): return exp(-I*self.position*bra.momentum/hbar)/sqrt(2*pi*hbar) + class XBra(Bra): """1D cartesian position eigenbra.""" @@ -181,6 +187,7 @@ """The position of the state.""" return self.label[0] + class PositionState3D(State): """ Base class for 3D cartesian position eigenstates """ @@ -189,7 +196,7 @@ return self.__new__(self, *_lowercase_labels(op), **options) def _state_to_operators(self, op_class, **options): - return op_class.__new__(op_class, \ + return op_class.__new__(op_class, *_uppercase_labels(self), **options) @classmethod @@ -211,6 +218,7 @@ """ The z coordinate of the state """ return self.label[2] + class PositionKet3D(Ket, PositionState3D): """ 3D cartesian position eigenket """ @@ -225,6 +233,7 @@ def dual_class(self): return PositionBra3D + class PositionBra3D(Bra, PositionState3D): """ 3D cartesian position eigenbra """ @@ -236,6 +245,7 @@ # Momentum eigenstates #------------------------------------------------------------------------- + class PxKet(Ket): """1D cartesian momentum eigenket.""" @@ -244,7 +254,7 @@ return self.__new__(self, *_lowercase_labels(op), **options) def _state_to_operators(self, op_class, **options): - return op_class.__new__(op_class, \ + return op_class.__new__(op_class, *_uppercase_labels(self), **options) @classmethod @@ -267,7 +277,8 @@ return exp(I*self.momentum*bra.position/hbar)/sqrt(2*pi*hbar) def _eval_innerproduct_PxBra(self, bra, **hints): - return DiracDelta(self.momentum-bra.momentum) + return DiracDelta(self.momentum - bra.momentum) + class PxBra(Bra): """1D cartesian momentum eigenbra.""" @@ -289,6 +300,7 @@ # Global helper functions #------------------------------------------------------------------------- + def _enumerate_continuous_1D(*args, **options): state = args[0] num_states = args[1] @@ -307,17 +319,19 @@ return enum_states + def _lowercase_labels(ops): if not isinstance(ops, set): ops = [ops] return [str(arg.label[0]).lower() for arg in ops] + def _uppercase_labels(ops): if not isinstance(ops, set): ops = [ops] - new_args = [str(arg.label[0])[0].upper() + \ + new_args = [str(arg.label[0])[0].upper() + str(arg.label[0])[1:] for arg in ops] return new_args diff -Nru python3-sympy-0.7.2/sympy/physics/quantum/cg.py python3-sympy-0.7.3/sympy/physics/quantum/cg.py --- python3-sympy-0.7.2/sympy/physics/quantum/cg.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/physics/quantum/cg.py 2013-07-13 17:53:32.000000000 +0000 @@ -23,6 +23,7 @@ # CG Coefficients #----------------------------------------------------------------------------- + class Wigner3j(Expr): """Class for the Wigner-3j symbols @@ -64,7 +65,7 @@ is_commutative = True def __new__(cls, j1, m1, j2, m2, j3, m3): - args = list(map(sympify, (j1,m1,j2,m2,j3,m3))) + args = list(map(sympify, (j1, m1, j2, m2, j3, m3))) return Expr.__new__(cls, *args) @property @@ -97,8 +98,8 @@ # This is modified from the _print_Matrix method def _pretty(self, printer, *args): - m = ((printer._print(self.j1), printer._print(self.m1)), \ - (printer._print(self.j2), printer._print(self.m2)), \ + m = ((printer._print(self.j1), printer._print(self.m1)), + (printer._print(self.j2), printer._print(self.m2)), (printer._print(self.j3), printer._print(self.m3))) hsep = 2 vsep = 1 @@ -111,7 +112,7 @@ for j in range(3): s = m[j][i] wdelta = maxw[j] - s.width() - wleft = wdelta //2 + wleft = wdelta //2 wright = wdelta - wleft s = prettyForm(*s.right(' '*wright)) @@ -132,9 +133,10 @@ return D def _latex(self, printer, *args): - label = list(map(printer._print, (self.j1, self.j2, self.j3, self.m1, self.m2, self.m3))) + label = list(map(printer._print, (self.j1, self.j2, self.j3, + self.m1, self.m2, self.m3))) return r'\left(\begin{array}{ccc} %s & %s & %s \\ %s & %s & %s \end{array}\right)' % \ - tuple(label) + tuple(label) def doit(self, **hints): if self.is_symbolic: @@ -187,10 +189,11 @@ def doit(self, **hints): if self.is_symbolic: raise ValueError("Coefficients must be numerical") - return clebsch_gordan(self.j1,self.j2, self.j3, self.m1, self.m2, self.m3) + return clebsch_gordan(self.j1, self.j2, self.j3, self.m1, self.m2, self.m3) def _pretty(self, printer, *args): - bot = printer._print_seq((self.j1, self.m1, self.j2, self.m2), delimiter=',') + bot = printer._print_seq( + (self.j1, self.m1, self.j2, self.m2), delimiter=',') top = printer._print_seq((self.j3, self.m3), delimiter=',') pad = max(top.width(), bot.width()) @@ -198,16 +201,17 @@ top = prettyForm(*top.left(' ')) if not pad == bot.width(): - bot = prettyForm(*bot.right(' ' * (pad-bot.width()))) + bot = prettyForm(*bot.right(' ' * (pad - bot.width()))) if not pad == top.width(): - top = prettyForm(*top.right(' ' * (pad-top.width()))) + top = prettyForm(*top.right(' ' * (pad - top.width()))) s = stringPict('C' + ' '*pad) s = prettyForm(*s.below(bot)) s = prettyForm(*s.above(top)) return s def _latex(self, printer, *args): - label = list(map(printer._print, (self.j3, self.m3, self.j1, self.m1, self.j2, self.m2))) + label = list(map(printer._print, (self.j3, self.m3, self.j1, + self.m1, self.j2, self.m2))) return r'C^{%s,%s}_{%s,%s,%s,%s}' % tuple(label) @@ -221,7 +225,7 @@ """ def __new__(cls, j1, j2, j12, j3, j, j23): - args = list(map(sympify, (j1,j2,j12,j3,j,j23))) + args = list(map(sympify, (j1, j2, j12, j3, j, j23))) return Expr.__new__(cls, *args) @property @@ -254,8 +258,8 @@ # This is modified from the _print_Matrix method def _pretty(self, printer, *args): - m = ((printer._print(self.j1), printer._print(self.j3)), \ - (printer._print(self.j2), printer._print(self.j)), \ + m = ((printer._print(self.j1), printer._print(self.j3)), + (printer._print(self.j2), printer._print(self.j)), (printer._print(self.j12), printer._print(self.j23))) hsep = 2 vsep = 1 @@ -268,7 +272,7 @@ for j in range(3): s = m[j][i] wdelta = maxw[j] - s.width() - wleft = wdelta //2 + wleft = wdelta //2 wright = wdelta - wleft s = prettyForm(*s.right(' '*wright)) @@ -289,9 +293,10 @@ return D def _latex(self, printer, *args): - label = list(map(printer._print, (self.j1, self.j2, self.j12, self.j3, self.j, self.j23))) + label = list(map(printer._print, (self.j1, self.j2, self.j12, + self.j3, self.j, self.j23))) return r'\left\{\begin{array}{ccc} %s & %s & %s \\ %s & %s & %s \end{array}\right\}' % \ - tuple(label) + tuple(label) def doit(self, **hints): if self.is_symbolic: @@ -309,7 +314,7 @@ """ def __new__(cls, j1, j2, j12, j3, j4, j34, j13, j24, j): - args = list(map(sympify, (j1,j2, j12, j3, j4, j34, j13, j24, j))) + args = list(map(sympify, (j1, j2, j12, j3, j4, j34, j13, j24, j))) return Expr.__new__(cls, *args) @property @@ -354,8 +359,11 @@ # This is modified from the _print_Matrix method def _pretty(self, printer, *args): - m = ((printer._print(self.j1), printer._print(self.j3), printer._print(self.j13)), \ - (printer._print(self.j2), printer._print(self.j4), printer._print(self.j24)), \ + m = ( + (printer._print( + self.j1), printer._print(self.j3), printer._print(self.j13)), + (printer._print( + self.j2), printer._print(self.j4), printer._print(self.j24)), (printer._print(self.j12), printer._print(self.j34), printer._print(self.j))) hsep = 2 vsep = 1 @@ -368,7 +376,7 @@ for j in range(3): s = m[j][i] wdelta = maxw[j] - s.width() - wleft = wdelta //2 + wleft = wdelta //2 wright = wdelta - wleft s = prettyForm(*s.right(' '*wright)) @@ -392,7 +400,7 @@ label = list(map(printer._print, (self.j1, self.j2, self.j12, self.j3, self.j4, self.j34, self.j13, self.j24, self.j))) return r'\left\{\begin{array}{ccc} %s & %s & %s \\ %s & %s & %s \\ %s & %s & %s \end{array}\right\}' % \ - tuple(label) + tuple(label) def doit(self, **hints): if self.is_symbolic: @@ -482,71 +490,75 @@ other_part.append(other) cg_part, other = _check_varsh_872_9(cg_part) other_part.append(other) - return Add(*cg_part)+Add(*other_part) + return Add(*cg_part) + Add(*other_part) + def _check_varsh_871_1(term_list): # Sum( CG(a,alpha,b,0,a,alpha), (alpha, -a, a)) == KroneckerDelta(b,0) - a,alpha,b,lt = list(map(Wild,('a','alpha','b','lt'))) - expr = lt*CG(a,alpha,b,0,a,alpha) - simp = (2*a+1)*KroneckerDelta(b,0) + a, alpha, b, lt = list(map(Wild, ('a', 'alpha', 'b', 'lt'))) + expr = lt*CG(a, alpha, b, 0, a, alpha) + simp = (2*a + 1)*KroneckerDelta(b, 0) sign = lt/abs(lt) - build_expr = 2*a+1 - index_expr = a+alpha - return _check_cg_simp(expr, simp, sign, lt, term_list, (a,alpha,b,lt), (a,b), build_expr, index_expr) + build_expr = 2*a + 1 + index_expr = a + alpha + return _check_cg_simp(expr, simp, sign, lt, term_list, (a, alpha, b, lt), (a, b), build_expr, index_expr) def _check_varsh_871_2(term_list): # Sum((-1)**(a-alpha)*CG(a,alpha,a,-alpha,c,0),(alpha,-a,a)) - a,alpha,c,lt = list(map(Wild,('a','alpha','c','lt'))) - expr = lt*CG(a,alpha,a,-alpha,c,0) - simp = sqrt(2*a+1)*KroneckerDelta(c,0) - sign = (-1)**(a-alpha)*lt/abs(lt) - build_expr = 2*a+1 - index_expr = a+alpha - return _check_cg_simp(expr, simp, sign, lt, term_list, (a,alpha,c,lt), (a,c), build_expr, index_expr) + a, alpha, c, lt = list(map(Wild, ('a', 'alpha', 'c', 'lt'))) + expr = lt*CG(a, alpha, a, -alpha, c, 0) + simp = sqrt(2*a + 1)*KroneckerDelta(c, 0) + sign = (-1)**(a - alpha)*lt/abs(lt) + build_expr = 2*a + 1 + index_expr = a + alpha + return _check_cg_simp(expr, simp, sign, lt, term_list, (a, alpha, c, lt), (a, c), build_expr, index_expr) + def _check_varsh_872_9(term_list): # Sum( CG(a,alpha,b,beta,c,gamma)*CG(a,alpha',b,beta',c,gamma), (gamma, -c, c), (c, abs(a-b), a+b)) - a,alpha,alphap,b,beta,betap,c,gamma,lt = list(map(Wild, ('a','alpha','alphap','b','beta','betap','c','gamma','lt'))) + a, alpha, alphap, b, beta, betap, c, gamma, lt = list(map(Wild, ( + 'a', 'alpha', 'alphap', 'b', 'beta', 'betap', 'c', 'gamma', 'lt'))) # Case alpha==alphap, beta==betap # For numerical alpha,beta - expr = lt*CG(a,alpha,b,beta,c,gamma)**2 + expr = lt*CG(a, alpha, b, beta, c, gamma)**2 simp = 1 sign = lt/abs(lt) - x = abs(a-b) - y = abs(alpha+beta) - build_expr = a+b+1-Piecewise((x,x>y),(0,Eq(x,y)),(y,y>x)) - index_expr = a+b-c - term_list, other1 = _check_cg_simp(expr, simp, sign, lt, term_list, (a,alpha,b,beta,c,gamma,lt), (a,alpha,b,beta), build_expr, index_expr) + x = abs(a - b) + y = abs(alpha + beta) + build_expr = a + b + 1 - Piecewise((x, x > y), (0, Eq(x, y)), (y, y > x)) + index_expr = a + b - c + term_list, other1 = _check_cg_simp(expr, simp, sign, lt, term_list, (a, alpha, b, beta, c, gamma, lt), (a, alpha, b, beta), build_expr, index_expr) # For symbolic alpha,beta - x = abs(a-b) - y = a+b - build_expr = (y+1-x)*(x+y+1) - index_expr = (c-x)*(x+c)+c+gamma - term_list, other2 = _check_cg_simp(expr, simp, sign, lt, term_list, (a,alpha,b,beta,c,gamma,lt), (a,alpha,b,beta), build_expr, index_expr) + x = abs(a - b) + y = a + b + build_expr = (y + 1 - x)*(x + y + 1) + index_expr = (c - x)*(x + c) + c + gamma + term_list, other2 = _check_cg_simp(expr, simp, sign, lt, term_list, (a, alpha, b, beta, c, gamma, lt), (a, alpha, b, beta), build_expr, index_expr) # Case alpha!=alphap or beta!=betap # Note: this only works with leading term of 1, pattern matching is unable to match when there is a Wild leading term # For numerical alpha,alphap,beta,betap - expr = CG(a,alpha,b,beta,c,gamma)*CG(a,alphap,b,betap,c,gamma) - simp = KroneckerDelta(alpha,alphap)*KroneckerDelta(beta,betap) + expr = CG(a, alpha, b, beta, c, gamma)*CG(a, alphap, b, betap, c, gamma) + simp = KroneckerDelta(alpha, alphap)*KroneckerDelta(beta, betap) sign = sympify(1) - x = abs(a-b) - y = abs(alpha+beta) - build_expr = a+b+1-Piecewise((x,x>y),(0,Eq(x,y)),(y,y>x)) - index_expr = a+b-c - term_list, other3 = _check_cg_simp(expr, simp, sign, sympify(1), term_list, (a,alpha,alphap,b,beta,betap,c,gamma), (a,alpha,alphap,b,beta,betap), build_expr, index_expr) + x = abs(a - b) + y = abs(alpha + beta) + build_expr = a + b + 1 - Piecewise((x, x > y), (0, Eq(x, y)), (y, y > x)) + index_expr = a + b - c + term_list, other3 = _check_cg_simp(expr, simp, sign, sympify(1), term_list, (a, alpha, alphap, b, beta, betap, c, gamma), (a, alpha, alphap, b, beta, betap), build_expr, index_expr) # For symbolic alpha,alphap,beta,betap - x = abs(a-b) - y = a+b - build_expr = (y+1-x)*(x+y+1) - index_expr = (c-x)*(x+c)+c+gamma - term_list, other4 = _check_cg_simp(expr, simp, sign, sympify(1), term_list, (a,alpha,alphap,b,beta,betap,c,gamma), (a,alpha,alphap,b,beta,betap), build_expr, index_expr) + x = abs(a - b) + y = a + b + build_expr = (y + 1 - x)*(x + y + 1) + index_expr = (c - x)*(x + c) + c + gamma + term_list, other4 = _check_cg_simp(expr, simp, sign, sympify(1), term_list, (a, alpha, alphap, b, beta, betap, c, gamma), (a, alpha, alphap, b, beta, betap), build_expr, index_expr) + + return term_list, other1 + other2 + other4 - return term_list, other1+other2+other4 def _check_cg_simp(expr, simp, sign, lt, term_list, variables, dep_variables, build_index_expr, index_expr): """ Checks for simplifications that can be made, returning a tuple of the @@ -599,15 +611,15 @@ if not sympify(build_index_expr.subs(sub_1)).is_number: i += 1 continue - sub_dep = [(x,sub_1[x]) for x in dep_variables] + sub_dep = [(x, sub_1[x]) for x in dep_variables] cg_index = [None] * build_index_expr.subs(sub_1) - for j in range(i,len(term_list)): - sub_2 = _check_cg(term_list[j], expr.subs(sub_dep), len(variables)-len(dep_variables), sign=(sign.subs(sub_1),sign.subs(sub_dep))) + for j in range(i, len(term_list)): + sub_2 = _check_cg(term_list[j], expr.subs(sub_dep), len(variables) - len(dep_variables), sign=(sign.subs(sub_1), sign.subs(sub_dep))) if sub_2 is None: continue if not sympify(index_expr.subs(sub_dep).subs(sub_2)).is_number: continue - cg_index[index_expr.subs(sub_dep).subs(sub_2)] = j, expr.subs(lt,1).subs(sub_dep).subs(sub_2), lt.subs(sub_2), sign.subs(sub_dep).subs(sub_2) + cg_index[index_expr.subs(sub_dep).subs(sub_2)] = j, expr.subs(lt, 1).subs(sub_dep).subs(sub_2), lt.subs(sub_2), sign.subs(sub_dep).subs(sub_2) if all(i is not None for i in cg_index): min_lt = min(*[ abs(term[2]) for term in cg_index ]) indicies = [ term[0] for term in cg_index] @@ -616,12 +628,13 @@ [ term_list.pop(i) for i in indicies ] for term in cg_index: if abs(term[2]) > min_lt: - term_list.append( (term[2]-min_lt*term[3]) * term[1] ) + term_list.append( (term[2] - min_lt*term[3]) * term[1] ) other_part += min_lt * (sign*simp).subs(sub_1) else: i += 1 return term_list, other_part + def _check_cg(cg_term, expr, length, sign=None): """Checks whether a term matches the given expression""" # TODO: Check for symmetries @@ -636,30 +649,35 @@ if len(matches) == length: return matches + def _cg_simp_sum(e): e = _check_varsh_sum_871_1(e) e = _check_varsh_sum_871_2(e) e = _check_varsh_sum_872_4(e) return e + def _check_varsh_sum_871_1(e): a = Wild('a') alpha = symbols('alpha') b = Wild('b') - match = e.match(Sum(CG(a,alpha,b,0,a,alpha),(alpha,-a,a))) + match = e.match(Sum(CG(a, alpha, b, 0, a, alpha), (alpha, -a, a))) if match is not None and len(match) == 2: - return ((2*a+1)*KroneckerDelta(b,0)).subs(match) + return ((2*a + 1)*KroneckerDelta(b, 0)).subs(match) return e + def _check_varsh_sum_871_2(e): a = Wild('a') alpha = symbols('alpha') c = Wild('c') - match = e.match(Sum((-1)**(a-alpha)*CG(a,alpha,a,-alpha,c,0),(alpha,-a,a))) + match = e.match( + Sum((-1)**(a - alpha)*CG(a, alpha, a, -alpha, c, 0), (alpha, -a, a))) if match is not None and len(match) == 2: - return (sqrt(2*a+1)*KroneckerDelta(c,0)).subs(match) + return (sqrt(2*a + 1)*KroneckerDelta(c, 0)).subs(match) return e + def _check_varsh_sum_872_4(e): a = Wild('a') alpha = Wild('alpha') @@ -669,14 +687,17 @@ cp = Wild('cp') gamma = Wild('gamma') gammap = Wild('gammap') - match1 = e.match(Sum(CG(a,alpha,b,beta,c,gamma)*CG(a,alpha,b,beta,cp,gammap),(alpha,-a,a),(beta,-b,b))) + match1 = e.match(Sum(CG(a, alpha, b, beta, c, gamma)*CG( + a, alpha, b, beta, cp, gammap), (alpha, -a, a), (beta, -b, b))) if match1 is not None and len(match1) == 8: - return (KroneckerDelta(c,cp)*KroneckerDelta(gamma,gammap)).subs(match1) - match2 = e.match(Sum(CG(a,alpha,b,beta,c,gamma)**2,(alpha,-a,a),(beta,-b,b))) + return (KroneckerDelta(c, cp)*KroneckerDelta(gamma, gammap)).subs(match1) + match2 = e.match(Sum( + CG(a, alpha, b, beta, c, gamma)**2, (alpha, -a, a), (beta, -b, b))) if match2 is not None and len(match2) == 6: return 1 return e + def _cg_list(term): if isinstance(term, CG): return (term,), 1, 1 diff -Nru python3-sympy-0.7.2/sympy/physics/quantum/circuitplot.py python3-sympy-0.7.3/sympy/physics/quantum/circuitplot.py --- python3-sympy-0.7.2/sympy/physics/quantum/circuitplot.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/physics/quantum/circuitplot.py 2013-07-13 17:53:32.000000000 +0000 @@ -24,8 +24,9 @@ ] np = import_module('numpy', min_python_version=(2, 6)) -matplotlib = import_module('matplotlib', __import__kwargs={'fromlist':['pyplot']}, - catch=(RuntimeError,)) # This is raised in environments that have no display. +matplotlib = import_module( + 'matplotlib', __import__kwargs={'fromlist': ['pyplot']}, + catch=(RuntimeError,)) # This is raised in environments that have no display. if not np or not matplotlib: class CircuitPlot(object): @@ -68,38 +69,38 @@ def _create_grid(self): """Create the grid of wires.""" scale = self.scale - wire_grid = np.arange(0.0,self.nqubits*scale,scale,dtype=float) - gate_grid = np.arange(0.0,self.ngates*scale,scale,dtype=float) + wire_grid = np.arange(0.0, self.nqubits*scale, scale, dtype=float) + gate_grid = np.arange(0.0, self.ngates*scale, scale, dtype=float) self._wire_grid = wire_grid self._gate_grid = gate_grid def _create_figure(self): """Create the main matplotlib figure.""" self._figure = pyplot.figure( - figsize=(self.ngates*self.scale,self.nqubits*self.scale), + figsize=(self.ngates*self.scale, self.nqubits*self.scale), facecolor='w', edgecolor='w' ) ax = self._figure.add_subplot( - 1,1,1, + 1, 1, 1, frameon=True ) ax.set_axis_off() offset = 0.5*self.scale - ax.set_xlim(self._gate_grid[0]-offset,self._gate_grid[-1]+offset) - ax.set_ylim(self._wire_grid[0]-offset,self._wire_grid[-1]+offset) + ax.set_xlim(self._gate_grid[0] - offset, self._gate_grid[-1] + offset) + ax.set_ylim(self._wire_grid[0] - offset, self._wire_grid[-1] + offset) ax.set_aspect('equal') self._axes = ax def _plot_wires(self): """Plot the wires of the circuit diagram.""" xstart = self._gate_grid[0] - xstop = self._gate_grid[-1] - xdata = (xstart-self.scale, xstop+self.scale) + xstop = self._gate_grid[-1] + xdata = (xstart - self.scale, xstop + self.scale) for i in range(self.nqubits): ydata = (self._wire_grid[i], self._wire_grid[i]) line = Line2D( - xdata,ydata, + xdata, ydata, color='k', lw=self.linewidth ) @@ -131,7 +132,7 @@ color='k', ha='center', va='center', - bbox = dict(ec='k',fc='w',fill=True,lw=self.linewidth), + bbox=dict(ec='k', fc='w', fill=True, lw=self.linewidth), size=self.fontsize ) @@ -140,7 +141,7 @@ xdata = (self._gate_grid[gate_idx], self._gate_grid[gate_idx]) ydata = (self._wire_grid[min_wire], self._wire_grid[max_wire]) line = Line2D( - xdata,ydata, + xdata, ydata, color='k', lw=self.linewidth ) @@ -152,7 +153,7 @@ y = self._wire_grid[wire_idx] radius = self.control_radius c = Circle( - (x,y), + (x, y), radius*self.scale, ec='k', fc='k', @@ -167,7 +168,7 @@ y = self._wire_grid[wire_idx] radius = self.not_radius c = Circle( - (x,y), + (x, y), radius, ec='k', fc='w', @@ -176,7 +177,7 @@ ) self._axes.add_patch(c) l = Line2D( - (x,x),(y-radius,y+radius), + (x, x), (y - radius, y + radius), color='k', lw=self.linewidth ) @@ -188,21 +189,20 @@ y = self._wire_grid[wire_idx] d = self.swap_delta l1 = Line2D( - (x-d,x+d), - (y-d,y+d), + (x - d, x + d), + (y - d, y + d), color='k', lw=self.linewidth ) l2 = Line2D( - (x-d,x+d), - (y+d,y-d), + (x - d, x + d), + (y + d, y - d), color='k', lw=self.linewidth ) self._axes.add_line(l1) self._axes.add_line(l2) - def circuit_plot(c, nqubits, **kwargs): """Draw the circuit diagram for the circuit with nqubits. diff -Nru python3-sympy-0.7.2/sympy/physics/quantum/circuitutils.py python3-sympy-0.7.3/sympy/physics/quantum/circuitutils.py --- python3-sympy-0.7.2/sympy/physics/quantum/circuitutils.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/physics/quantum/circuitutils.py 2013-07-13 17:53:32.000000000 +0000 @@ -15,6 +15,7 @@ 'random_insert' ] + def kmp_table(word): """Build the 'partial match' table of the Knuth-Morris-Pratt algorithm. @@ -34,7 +35,7 @@ table.append(0) while pos < len(word): - if word[pos-1] == word[cnd]: + if word[pos - 1] == word[cnd]: cnd = cnd + 1 table.append(cnd) pos = pos + 1 @@ -46,6 +47,7 @@ return table + def find_subcircuit(circuit, subcircuit, start=0, end=0): """Finds the subcircuit in circuit, if it exists. @@ -130,6 +132,7 @@ return -1 + def replace_subcircuit(circuit, subcircuit, replace=None, pos=0): """Replaces a subcircuit with another subcircuit in circuit, if it exists. @@ -211,12 +214,14 @@ return circuit + def _sympify_qubit_map(mapping): new_map = {} for key in mapping: new_map[key] = sympify(mapping[key]) return new_map + def convert_to_symbolic_indices(seq, start=None, gen=None, qubit_map=None): """Returns the circuit with symbolic indices and the dictionary mapping symbolic indices to real indices. @@ -313,6 +318,7 @@ return sym_seq, ndx_map, cur_ndx, index_gen + def convert_to_real_indices(seq, qubit_map): """Returns the circuit with real indices. @@ -350,12 +356,10 @@ for item in seq: # Nested items, so recurse if isinstance(item, Gate): - real_item = convert_to_real_indices( - item.args, qubit_map) + real_item = convert_to_real_indices(item.args, qubit_map) elif isinstance(item, tuple) or isinstance(item, Tuple): - real_item = convert_to_real_indices( - item, qubit_map) + real_item = convert_to_real_indices(item, qubit_map) else: real_item = qubit_map[item] @@ -367,6 +371,7 @@ return real_seq + def random_reduce(circuit, gate_ids, seed=None): """Shorten the length of a quantum circuit. @@ -413,6 +418,7 @@ # return circuit with the identity removed return replace_subcircuit(circuit, id) + def random_insert(circuit, choices, seed=None): """Insert a circuit into another quantum circuit. @@ -455,6 +461,8 @@ return tuple(circuit) # Flatten the GateIdentity objects (with gate rules) into one single list + + def flatten_ids(ids): collapse = lambda acc, an_id: acc + sorted(an_id.equivalent_ids, key=default_sort_key) diff -Nru python3-sympy-0.7.2/sympy/physics/quantum/commutator.py python3-sympy-0.7.3/sympy/physics/quantum/commutator.py --- python3-sympy-0.7.2/sympy/physics/quantum/commutator.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/physics/quantum/commutator.py 2013-07-13 17:53:32.000000000 +0000 @@ -16,7 +16,6 @@ #----------------------------------------------------------------------------- - class Commutator(Expr): """The standard commutator, in an unevaluated state. @@ -192,7 +191,8 @@ def _sympyrepr(self, printer, *args): return "%s(%s,%s)" % ( - self.__class__.__name__, printer._print(self.args[0]), printer._print(self.args[1]) + self.__class__.__name__, printer._print( + self.args[0]), printer._print(self.args[1]) ) def _sympystr(self, printer, *args): diff -Nru python3-sympy-0.7.2/sympy/physics/quantum/constants.py python3-sympy-0.7.3/sympy/physics/quantum/constants.py --- python3-sympy-0.7.2/sympy/physics/quantum/constants.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/physics/quantum/constants.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,6 +1,7 @@ """Constants (like hbar) related to quantum mechanics.""" from sympy.core.numbers import NumberSymbol +from sympy.core.singleton import Singleton from sympy.printing.pretty.stringpict import prettyForm import sympy.mpmath.libmp as mlib @@ -12,7 +13,8 @@ 'hbar' ] -class HBar(NumberSymbol): + +class HBar(NumberSymbol, metaclass=Singleton): """Reduced Plank's constant in numerical and symbolic form [1]_. Examples @@ -32,7 +34,6 @@ is_positive = True is_negative = False is_irrational = True - __slots__ = [] def _as_mpf_val(self, prec): diff -Nru python3-sympy-0.7.2/sympy/physics/quantum/dagger.py python3-sympy-0.7.3/sympy/physics/quantum/dagger.py --- python3-sympy-0.7.2/sympy/physics/quantum/dagger.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/physics/quantum/dagger.py 2013-07-13 17:53:32.000000000 +0000 @@ -59,11 +59,13 @@ >>> from sympy import Matrix, I >>> m = Matrix([[1,I],[2,I]]) >>> m - [1, I] - [2, I] + Matrix([ + [1, I], + [2, I]]) >>> Dagger(m) - [ 1, 2] - [-I, -I] + Matrix([ + [ 1, 2], + [-I, -I]]) References ========== diff -Nru python3-sympy-0.7.2/sympy/physics/quantum/density.py python3-sympy-0.7.3/sympy/physics/quantum/density.py --- python3-sympy-0.7.2/sympy/physics/quantum/density.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/physics/quantum/density.py 2013-07-13 17:53:32.000000000 +0000 @@ -8,6 +8,7 @@ from sympy.physics.quantum.tensorproduct import TensorProduct, tensor_product_simp from sympy.core.compatibility import product + class Density(HermitianOperator): """Density operator for representing mixed states. @@ -40,7 +41,7 @@ for arg in args: # Check if arg is a tuple if not (isinstance(arg, Tuple) and - len(arg) == 2 ): + len(arg) == 2): raise ValueError("Each argument should be of form [state,prob]" " or ( state, prob )") @@ -159,22 +160,22 @@ terms = [] for (state, prob) in self.args: - state = state.expand() # needed to break up (a+b)*c + state = state.expand() # needed to break up (a+b)*c if (isinstance(state, Add)): for arg in product(state.args, repeat=2): terms.append(prob * self._generate_outer_prod(arg[0], arg[1])) else: terms.append(prob * - self._generate_outer_prod(state,state)) + self._generate_outer_prod(state, state)) return Add(*terms) - def _generate_outer_prod(self,arg1,arg2): + def _generate_outer_prod(self, arg1, arg2): c_part1, nc_part1 = arg1.args_cnc() c_part2, nc_part2 = arg2.args_cnc() - if ( len(nc_part1) == 0 or + if ( len(nc_part1) == 0 or len(nc_part2) == 0 ): raise ValueError('Atleast one-pair of' ' Non-commutative instance required' @@ -183,7 +184,7 @@ # Muls of Tensor Products should be expanded # before this function is called if (isinstance(nc_part1[0], TensorProduct) and - len(nc_part1) == 1 and len(nc_part2) == 1): + len(nc_part1) == 1 and len(nc_part2) == 1): op = tensor_product_simp(nc_part1[0] * Dagger(nc_part2[0])) else: op = Mul(*nc_part1) * Dagger(Mul(*nc_part2)) @@ -200,7 +201,7 @@ return prettyForm("\u03C1") def _eval_trace(self, **kwargs): - indices = kwargs.get('indices',[]) + indices = kwargs.get('indices', []) return Tr(self.doit(), indices).doit() def entropy(self): @@ -210,6 +211,7 @@ """ return entropy(self) + def entropy(density): """Compute the entropy of a matrix/density object. @@ -239,7 +241,7 @@ """ if isinstance(density, Density): - density = represent(density) #represent in Matrix + density = represent(density) # represent in Matrix if isinstance(density, scipy_sparse_matrix): density = to_numpy(density) @@ -252,7 +254,8 @@ eigvals = np.linalg.eigvals(density) return -np.sum(eigvals*np.log(eigvals)) else: - raise ValueError("numpy.ndarray, scipy.sparse or sympy matrix expected") + raise ValueError( + "numpy.ndarray, scipy.sparse or sympy matrix expected") def fidelity(state1, state2): @@ -299,14 +302,14 @@ state2 = represent(state2) if isinstance(state2, Density) else state2 if (not isinstance(state1, Matrix) or - not isinstance(state2, Matrix)): + not isinstance(state2, Matrix)): raise ValueError("state1 and state2 must be of type Density or Matrix " "received type=%s for state1 and type=%s for state2" % (type(state1), type(state2))) if ( state1.shape != state2.shape and state1.is_square): - raise ValueError("The dimensions of both args should be equal and the" + raise ValueError("The dimensions of both args should be equal and the " "matrix obtained should be a square matrix") - sqrt_state1 = state1**Rational(1,2) + sqrt_state1 = state1**Rational(1, 2) return Tr((sqrt_state1 * state2 * sqrt_state1)**Rational(1, 2)).doit() diff -Nru python3-sympy-0.7.2/sympy/physics/quantum/gate.py python3-sympy-0.7.3/sympy/physics/quantum/gate.py --- python3-sympy-0.7.2/sympy/physics/quantum/gate.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/physics/quantum/gate.py 2013-07-13 17:53:32.000000000 +0000 @@ -70,11 +70,12 @@ _normalized = True + def normalized(normalize): - """Should Hadamard gates be normalized by a 1/sqrt(2). + """Set flag controlling normalization of Hadamard gates by 1/sqrt(2). This is a global setting that can be used to simplify the look of various - expressions, by leaving of the leading 1/sqrt(2) of the Hadamard gate. + expressions, by leaving off the leading 1/sqrt(2) of the Hadamard gate. Parameters ---------- @@ -135,7 +136,7 @@ @classmethod def _eval_hilbert_space(cls, args): """This returns the smallest possible Hilbert space.""" - return ComplexSpace(2)**(max(args)+1) + return ComplexSpace(2)**(max(args) + 1) #------------------------------------------------------------------------- # Properties @@ -153,7 +154,7 @@ @property def min_qubits(self): """The minimum number of qubits this gate needs to act on.""" - return max(self.targets)+1 + return max(self.targets) + 1 @property def targets(self): @@ -176,7 +177,8 @@ format : str The format string ('sympy','numpy', etc.) """ - raise NotImplementedError('get_target_matrix is not implemented in Gate.') + raise NotImplementedError( + 'get_target_matrix is not implemented in Gate.') #------------------------------------------------------------------------- # Apply @@ -192,8 +194,8 @@ # Check number of qubits this gate acts on. if qubits.nqubits < self.min_qubits: raise QuantumError( - 'Gate needs a minimum of %r qubits to act on, got: %r' %\ - (self.min_qubits, qubits.nqubits) + 'Gate needs a minimum of %r qubits to act on, got: %r' % + (self.min_qubits, qubits.nqubits) ) # If the controls are not met, just return @@ -209,8 +211,8 @@ n = 1 for target in targets: column_index += n*qubits[target] - n = n<<1 - column = target_matrix[:,int(column_index)] + n = n << 1 + column = target_matrix[:, int(column_index)] # Now apply each column element to the qubit. result = 0 @@ -222,7 +224,7 @@ new_qubit = qubits.__class__(*qubits.args) # Flip the bits that need to be flipped. for bit in range(len(targets)): - if new_qubit[targets[bit]] != (index>>bit)&1: + if new_qubit[targets[bit]] != (index >> bit) & 1: new_qubit = new_qubit.flip(targets[bit]) # The value in that row and column times the flipped-bit qubit # is the result for that part. @@ -237,10 +239,11 @@ return self._represent_ZGate(None, **options) def _represent_ZGate(self, basis, **options): - format = options.get('format','sympy') - nqubits = options.get('nqubits',0) + format = options.get('format', 'sympy') + nqubits = options.get('nqubits', 0) if nqubits == 0: - raise QuantumError('The number of qubits must be given as nqubits.') + raise QuantumError( + 'The number of qubits must be given as nqubits.') # Make sure we have enough qubits for the gate. if nqubits < self.min_qubits: @@ -280,7 +283,6 @@ raise NotImplementedError('plot_gate is not implemented.') - class CGate(Gate): """A general unitary gate with control qubits. @@ -318,13 +320,13 @@ if not is_sequence(controls): controls = (controls,) controls = UnitaryOperator._eval_args(controls) - _validate_targets_controls(chain(controls,gate.targets)) + _validate_targets_controls(chain(controls, gate.targets)) return (Tuple(*controls), gate) @classmethod def _eval_hilbert_space(cls, args): """This returns the smallest possible Hilbert space.""" - return ComplexSpace(2)**max(max(args[0])+1,args[1].min_qubits) + return ComplexSpace(2)**max(max(args[0]) + 1, args[1].min_qubits) #------------------------------------------------------------------------- # Properties @@ -337,12 +339,12 @@ For controlled gate subclasses this includes both target and control qubits, so that, for examples the CNOT gate acts on 2 qubits. """ - return len(self.targets)+len(self.controls) + return len(self.targets) + len(self.controls) @property def min_qubits(self): """The minimum number of qubits this gate needs to act on.""" - return max(max(self.controls),max(self.targets))+1 + return max(max(self.controls), max(self.targets)) + 1 @property def targets(self): @@ -368,7 +370,7 @@ def eval_controls(self, qubit): """Return True/False to indicate if the controls are satisfied.""" - return all(qubit[bit]==self.control_value for bit in self.controls) + return all(qubit[bit] == self.control_value for bit in self.controls) def decompose(self, **options): """Decompose the controlled gate into CNOT and single qubits gates.""" @@ -396,11 +398,11 @@ def _print_label(self, printer, *args): controls = self._print_sequence(self.controls, ',', printer, *args) gate = printer._print(self.gate, *args) - return '(%s),%s' %\ - (controls, gate) + return '(%s),%s' % (controls, gate) def _pretty(self, printer, *args): - controls = self._print_sequence_pretty(self.controls, ',', printer, *args) + controls = self._print_sequence_pretty( + self.controls, ',', printer, *args) gate = printer._print(self.gate) gate_name = stringPict(str(self.gate_name)) first = self._print_subscript_pretty(gate_name, controls) @@ -411,7 +413,7 @@ def _latex(self, printer, *args): controls = self._print_sequence(self.controls, ',', printer, *args) gate = printer._print(self.gate, *args) - return r'%s_{%s}{\left(%s\right)}' %\ + return r'%s_{%s}{\left(%s\right)}' % \ (self.gate_name_latex, controls, gate) def plot_gate(self, circ_plot, gate_idx): @@ -449,6 +451,7 @@ else: return Gate._eval_power(self, exp) + class UGate(Gate): """General gate specified by a set of targets and a target matrix. @@ -479,7 +482,7 @@ dim = 2**len(targets) if not all(dim == shape for shape in mat.shape): raise IndexError( - 'Number of targets must match the matrix size: %r %r' %\ + 'Number of targets must match the matrix size: %r %r' % (targets, mat) ) return (targets, mat) @@ -487,7 +490,7 @@ @classmethod def _eval_hilbert_space(cls, args): """This returns the smallest possible Hilbert space.""" - return ComplexSpace(2)**(max(args[0])+1) + return ComplexSpace(2)**(max(args[0]) + 1) #------------------------------------------------------------------------- # Properties @@ -516,7 +519,8 @@ # Print methods #------------------------------------------------------------------------- def _pretty(self, printer, *args): - targets = self._print_sequence_pretty(self.targets, ',', printer, *args) + targets = self._print_sequence_pretty( + self.targets, ',', printer, *args) gate_name = stringPict(str(self.gate_name)) return self._print_subscript_pretty(gate_name, targets) @@ -554,6 +558,7 @@ return Integer(2)*self*other return Operator._eval_anticommutator(self, other, **hints) + class TwoQubitGate(Gate): """A two qubit unitary gate base class.""" @@ -601,6 +606,17 @@ Examples -------- + >>> from sympy import sqrt + >>> from sympy.physics.quantum.qubit import Qubit + >>> from sympy.physics.quantum.gate import HadamardGate + >>> from sympy.physics.quantum.qapply import qapply + >>> qapply(HadamardGate(0)*Qubit('1')) + sqrt(2)*|0>/2 - sqrt(2)*|1>/2 + >>> # Hadamard on bell state, applied on 2 qubits. + >>> psi = 1/sqrt(2)*(Qubit('00')+Qubit('11')) + >>> qapply(HadamardGate(0)*HadamardGate(1)*psi) + sqrt(2)*|00>/2 + sqrt(2)*|11>/2 + """ gate_name = 'H' gate_name_latex = 'H' @@ -615,7 +631,7 @@ return I*sqrt(2)*YGate(self.targets[0]) def _eval_commutator_YGate(self, other, **hints): - return I*sqrt(2)*(ZGate(self.targets[0])-XGate(self.targets[0])) + return I*sqrt(2)*(ZGate(self.targets[0]) - XGate(self.targets[0])) def _eval_commutator_ZGate(self, other, **hints): return -I*sqrt(2)*YGate(self.targets[0]) @@ -666,7 +682,6 @@ return Integer(0) - class YGate(HermitianOperator, OneQubitGate): """The single qubit Y gate. @@ -804,6 +819,13 @@ Examples -------- + >>> from sympy.physics.quantum.gate import CNOT + >>> from sympy.physics.quantum.qapply import qapply + >>> from sympy.physics.quantum.qubit import Qubit + >>> c = CNOT(1,0) + >>> qapply(c*Qubit('10')) # note that qubits are indexed from right to left + |11> + """ gate_name = 'CNOT' gate_name_latex = 'CNOT' @@ -820,7 +842,7 @@ @classmethod def _eval_hilbert_space(cls, args): """This returns the smallest possible Hilbert space.""" - return ComplexSpace(2)**(max(args)+1) + return ComplexSpace(2)**(max(args) + 1) #------------------------------------------------------------------------- # Properties @@ -829,7 +851,7 @@ @property def min_qubits(self): """The minimum number of qubits this gate needs to act on.""" - return max(self.label)+1 + return max(self.label) + 1 @property def targets(self): @@ -895,6 +917,7 @@ else: raise NotImplementedError('Commutator not implemented: %r' % other) + class SwapGate(TwoQubitGate): """Two qubit SWAP gate. @@ -917,7 +940,7 @@ def decompose(self, **options): """Decompose the SWAP gate into CNOT gates.""" - i,j = self.targets[0], self.targets[1] + i, j = self.targets[0], self.targets[1] g1 = CNotGate(i, j) g2 = CNotGate(j, i) return g1*g2*g1 @@ -940,7 +963,7 @@ targets = [int(t) for t in self.targets] min_target = min(targets) max_target = max(targets) - nqubits = options.get('nqubits',self.min_qubits) + nqubits = options.get('nqubits', self.min_qubits) op01 = matrix_cache.get_matrix('op01', format) op10 = matrix_cache.get_matrix('op10', format) @@ -949,10 +972,10 @@ eye2 = matrix_cache.get_matrix('eye2', format) result = None - for i, j in ((op01,op10),(op10,op01),(op00,op00),(op11,op11)): + for i, j in ((op01, op10), (op10, op01), (op00, op00), (op11, op11)): product = nqubits*[eye2] - product[nqubits-min_target-1] = i - product[nqubits-max_target-1] = j + product[nqubits - min_target - 1] = i + product[nqubits - max_target - 1] = j new_result = matrix_tensor_product(*product) if result is None: result = new_result @@ -1021,8 +1044,8 @@ bit = targets[0] # Fill product with [I1,Gate,I2] such that the unitaries, # I, cause the gate to be applied to the correct Qubit - if bit != nqubits-1: - product.append(matrix_eye(2**(nqubits-bit-1), format=format)) + if bit != nqubits - 1: + product.append(matrix_eye(2**(nqubits - bit - 1), format=format)) product.append(target_matrix) if bit != 0: product.append(matrix_eye(2**bit, format=format)) @@ -1030,18 +1053,18 @@ # Single target, multiple controls. elif len(targets) == 1 and len(controls) >= 1: - target = targets[0] + target = targets[0] # Build the non-trivial part. product2 = [] for i in range(nqubits): product2.append(matrix_eye(2, format=format)) for control in controls: - product2[nqubits-1-control] = op11 - product2[nqubits-1-target] = target_matrix - eye2 + product2[nqubits - 1 - control] = op11 + product2[nqubits - 1 - target] = target_matrix - eye2 - return matrix_eye(2**nqubits, format=format) +\ - matrix_tensor_product(*product2) + return matrix_eye(2**nqubits, format=format) + \ + matrix_tensor_product(*product2) # Multi-target, multi-control is not yet implemented. else: @@ -1085,13 +1108,13 @@ # T**2 = S, S**2 = Z if isinstance(circuit_args[i], Pow): if isinstance(circuit_args[i].base, - (HadamardGate, XGate, YGate, ZGate))\ - and isinstance(circuit_args[i].exp, Number): + (HadamardGate, XGate, YGate, ZGate)) \ + and isinstance(circuit_args[i].exp, Number): # Build a new circuit taking replacing the # H,X,Y,Z squared with one. - newargs = (circuit_args[:i] +\ - (circuit_args[i].base**(circuit_args[i].exp % 2),) +\ - circuit_args[i+1:]) + newargs = (circuit_args[:i] + + (circuit_args[i].base**(circuit_args[i].exp % 2),) + + circuit_args[i + 1:]) # Recursively simplify the new circuit. circuit = gate_simp(Mul(*newargs)) break @@ -1100,27 +1123,27 @@ # in simplification. newargs = circuit_args[:i] # Replace PhaseGate**2 with ZGate. - newargs = newargs + (ZGate(circuit_args[i].base.args[0])**\ - (Integer(circuit_args[i].exp/2)), circuit_args[i].base**\ + newargs = newargs + (ZGate(circuit_args[i].base.args[0])** + (Integer(circuit_args[i].exp/2)), circuit_args[i].base** (circuit_args[i].exp % 2)) # Append the last elements. - newargs = newargs + circuit_args[i+1:] + newargs = newargs + circuit_args[i + 1:] # Recursively simplify the new circuit. - circuit = gate_simp(Mul(*newargs)) + circuit = gate_simp(Mul(*newargs)) break elif isinstance(circuit_args[i].base, TGate): # Build a new circuit taking all the old elements. newargs = circuit_args[:i] # Put an Phasegate in place of any TGate**2. - newargs = newargs + (PhaseGate(circuit_args[i].base.args[0])**\ - Integer(circuit_args[i].exp/2), circuit_args[i].base**\ - (circuit_args[i].exp % 2)) + newargs = newargs + (PhaseGate(circuit_args[i].base.args[0])** + Integer(circuit_args[i].exp/2), circuit_args[i].base** + (circuit_args[i].exp % 2)) # Append the last elements. - newargs = newargs + circuit_args[i+1:] + newargs = newargs + circuit_args[i + 1:] # Recursively simplify the new circuit. - circuit = gate_simp(Mul(*newargs)) + circuit = gate_simp(Mul(*newargs)) break return circuit @@ -1149,28 +1172,28 @@ while changes: changes = False circ_array = circuit.args - for i in range(len(circ_array)-1): + for i in range(len(circ_array) - 1): # Go through each element and switch ones that are in wrong order - if isinstance(circ_array[i], (Gate, Pow)) and\ - isinstance(circ_array[i+1], (Gate, Pow)): + if isinstance(circ_array[i], (Gate, Pow)) and \ + isinstance(circ_array[i + 1], (Gate, Pow)): # If we have a Pow object, look at only the base first_base, first_exp = circ_array[i].as_base_exp() - second_base, second_exp = circ_array[i+1].as_base_exp() + second_base, second_exp = circ_array[i + 1].as_base_exp() # Use sympy's hash based sorting. This is not mathematical # sorting, but is rather based on comparing hashes of objects. # See Basic.compare for details. if first_base.compare(second_base) > 0: if Commutator(first_base, second_base).doit() == 0: - new_args = (circuit.args[:i] + (circuit.args[i+1],) +\ - (circuit.args[i],) + circuit.args[i+2:]) + new_args = (circuit.args[:i] + (circuit.args[i + 1],) + + (circuit.args[i],) + circuit.args[i + 2:]) circuit = Mul(*new_args) circ_array = circuit.args changes = True break if AntiCommutator(first_base, second_base).doit() == 0: - new_args = (circuit.args[:i] + (circuit.args[i+1],) +\ - (circuit.args[i],) + circuit.args[i+2:]) + new_args = (circuit.args[:i] + (circuit.args[i + 1],) + + (circuit.args[i],) + circuit.args[i + 2:]) sign = Integer(-1)**(first_exp*second_exp) circuit = sign*Mul(*new_args) circ_array = circuit.args @@ -1206,7 +1229,7 @@ for i in range(ngates): g = random.choice(gate_space) if g == CNotGate or g == SwapGate: - qubits = random.sample(qubit_space,2) + qubits = random.sample(qubit_space, 2) g = g(*qubits) else: qubit = random.choice(qubit_space) diff -Nru python3-sympy-0.7.2/sympy/physics/quantum/grover.py python3-sympy-0.7.3/sympy/physics/quantum/grover.py --- python3-sympy-0.7.2/sympy/physics/quantum/grover.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/physics/quantum/grover.py 2013-07-13 17:53:32.000000000 +0000 @@ -26,6 +26,7 @@ 'apply_grover' ] + def superposition_basis(nqubits): """Creates an equal superposition of the computational basis. @@ -54,6 +55,7 @@ amp = 1/sqrt(2**nqubits) return sum([amp*IntQubit(n, nqubits) for n in range(2**nqubits)]) + class OracleGate(Gate): """A black box gate. @@ -99,7 +101,7 @@ if len(args) != 2: raise QuantumError( 'Insufficient/excessive arguments to Oracle. Please ' + - 'supply the number of qubits and an unknown function.' + 'supply the number of qubits and an unknown function.' ) sub_args = (args[0],) sub_args = UnitaryOperator._eval_args(sub_args) @@ -151,7 +153,7 @@ if qubits.nqubits != self.nqubits: raise QuantumError( 'OracleGate operates on %r qubits, got: %r' - (self.nqubits, qubits.nqubits) + % (self.nqubits, qubits.nqubits) ) # If function returns 1 on qubits # return the negative of the qubits (flip the sign) @@ -169,6 +171,7 @@ "Represent for the Oracle has not been implemented yet" ) + class WGate(Gate): """General n qubit W Gate in Grover's algorithm. @@ -191,7 +194,7 @@ if len(args) != 1: raise QuantumError( 'Insufficient/excessive arguments to W gate. Please ' + - 'supply the number of qubits to operate on.' + 'supply the number of qubits to operate on.' ) args = UnitaryOperator._eval_args(args) if not args[0].is_Integer: @@ -218,7 +221,7 @@ if qubits.nqubits != self.nqubits: raise QuantumError( 'WGate operates on %r qubits, got: %r' - (self.nqubits, qubits.nqubits) + % (self.nqubits, qubits.nqubits) ) # See 'Quantum Computer Science' by David Mermin p.92 -> W|a> result @@ -229,6 +232,7 @@ change_to_basis = (2/sqrt(2**self.nqubits))*basis_states return change_to_basis - qubits + def grover_iteration(qstate, oracle): """Applies one application of the Oracle and W Gate, WV. @@ -266,6 +270,7 @@ wgate = WGate(oracle.nqubits) return wgate*oracle*qstate + def apply_grover(oracle, nqubits, iterations=None): """Applies grover's algorithm. @@ -298,7 +303,7 @@ if nqubits <= 0: raise QuantumError( 'Grover\'s algorithm needs nqubits > 0, received %r qubits' - % nqubits + % nqubits ) if iterations is None: iterations = floor(sqrt(2**nqubits)*(pi/4)) diff -Nru python3-sympy-0.7.2/sympy/physics/quantum/hilbert.py python3-sympy-0.7.3/sympy/physics/quantum/hilbert.py --- python3-sympy-0.7.2/sympy/physics/quantum/hilbert.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/physics/quantum/hilbert.py 2013-07-13 17:53:32.000000000 +0000 @@ -25,6 +25,7 @@ # Main objects #----------------------------------------------------------------------------- + class HilbertSpaceError(QuantumError): pass @@ -32,6 +33,7 @@ # Main objects #----------------------------------------------------------------------------- + class HilbertSpace(Basic): """An abstract Hilbert space for quantum mechanics. @@ -75,7 +77,7 @@ def __pow__(self, other, mod=None): if mod is not None: - raise ValueError('The third argument to __pow__ is not supported\ + raise ValueError('The third argument to __pow__ is not supported \ for Hilbert spaces.') return TensorPowerHilbertSpace(self, other) @@ -146,16 +148,16 @@ @classmethod def eval(cls, dimension): if len(dimension.atoms()) == 1: - if not (dimension.is_Integer and dimension > 0 or dimension is oo\ + if not (dimension.is_Integer and dimension > 0 or dimension is oo or dimension.is_Symbol): raise TypeError('The dimension of a ComplexSpace can only' - 'be a positive integer, oo, or a Symbol: %r' \ + 'be a positive integer, oo, or a Symbol: %r' % dimension) else: for dim in dimension.atoms(): if not (dim.is_Integer or dim is oo or dim.is_Symbol): raise TypeError('The dimension of a ComplexSpace can only' - ' contain integers, oo, or a Symbol: %r' \ + ' contain integers, oo, or a Symbol: %r' % dim) @property @@ -203,7 +205,7 @@ def __new__(cls, interval): if not isinstance(interval, Interval): - raise TypeError('L2 interval must be an Interval instance: %r'\ + raise TypeError('L2 interval must be an Interval instance: %r' % interval) obj = Basic.__new__(cls, interval) return obj @@ -341,29 +343,29 @@ elif isinstance(arg, (HilbertSpace, TensorPowerHilbertSpace)): new_args.append(arg) else: - raise TypeError('Hilbert spaces can only be multiplied by\ + raise TypeError('Hilbert spaces can only be multiplied by \ other Hilbert spaces: %r' % arg) #combine like arguments into direct powers comb_args = [] prev_arg = None for new_arg in new_args: - if prev_arg != None: - if isinstance(new_arg, TensorPowerHilbertSpace) and\ - isinstance(prev_arg, TensorPowerHilbertSpace) and\ - new_arg.base == prev_arg.base: - prev_arg = new_arg.base**(new_arg.exp+prev_arg.exp) - elif isinstance(new_arg, TensorPowerHilbertSpace) and\ - new_arg.base == prev_arg: - prev_arg = prev_arg**(new_arg.exp+1) - elif isinstance(prev_arg, TensorPowerHilbertSpace) and\ - new_arg == prev_arg.base: - prev_arg = new_arg**(prev_arg.exp+1) + if prev_arg is not None: + if isinstance(new_arg, TensorPowerHilbertSpace) and \ + isinstance(prev_arg, TensorPowerHilbertSpace) and \ + new_arg.base == prev_arg.base: + prev_arg = new_arg.base**(new_arg.exp + prev_arg.exp) + elif isinstance(new_arg, TensorPowerHilbertSpace) and \ + new_arg.base == prev_arg: + prev_arg = prev_arg**(new_arg.exp + 1) + elif isinstance(prev_arg, TensorPowerHilbertSpace) and \ + new_arg == prev_arg.base: + prev_arg = new_arg**(prev_arg.exp + 1) elif new_arg == prev_arg: prev_arg = new_arg**2 else: comb_args.append(prev_arg) prev_arg = new_arg - elif prev_arg == None: + elif prev_arg is None: prev_arg = new_arg comb_args.append(prev_arg) if recall: @@ -379,7 +381,7 @@ if oo in arg_list: return oo else: - return reduce(lambda x,y: x*y, arg_list) + return reduce(lambda x, y: x*y, arg_list) @property def spaces(self): @@ -414,7 +416,7 @@ *next_pform.parens(left='(', right=')') ) pform = prettyForm(*pform.right(next_pform)) - if i != length-1: + if i != length - 1: if printer._use_unicode: pform = prettyForm(*pform.right(' ' + '\u2a02' + ' ')) else: @@ -430,7 +432,7 @@ TensorProductHilbertSpace)): arg_s = r'\left(%s\right)' % arg_s s = s + arg_s - if i != length-1: + if i != length - 1: s = s + r'\otimes ' return s @@ -486,7 +488,7 @@ elif isinstance(arg, HilbertSpace): new_args.append(arg) else: - raise TypeError('Hilbert spaces can only be summed with other\ + raise TypeError('Hilbert spaces can only be summed with other \ Hilbert spaces: %r' % arg) if recall: return DirectSumHilbertSpace(*new_args) @@ -499,7 +501,7 @@ if oo in arg_list: return oo else: - return reduce(lambda x,y: x+y, arg_list) + return reduce(lambda x, y: x + y, arg_list) @property def spaces(self): @@ -525,7 +527,7 @@ *next_pform.parens(left='(', right=')') ) pform = prettyForm(*pform.right(next_pform)) - if i != length-1: + if i != length - 1: if printer._use_unicode: pform = prettyForm(*pform.right(' ' + '\u2295' + ' ')) else: @@ -541,7 +543,7 @@ TensorProductHilbertSpace)): arg_s = r'\left(%s\right)' % arg_s s = s + arg_s - if i != length-1: + if i != length - 1: s = s + r'\oplus ' return s @@ -603,12 +605,12 @@ #check (and allow) for hs**(x+42+y...) case if len(exp.atoms()) == 1: if not (exp.is_Integer and exp >= 0 or exp.is_Symbol): - raise ValueError('Hilbert spaces can only be raised to\ + raise ValueError('Hilbert spaces can only be raised to \ positive integers or Symbols: %r' % exp) else: for power in exp.atoms(): if not (power.is_Integer or power.is_Symbol): - raise ValueError('Tensor powers can only contain integers\ + raise ValueError('Tensor powers can only contain integers \ or Symbols: %r' % power) return new_args @@ -628,11 +630,11 @@ return self.base.dimension**self.exp def _sympyrepr(self, printer, *args): - return "TensorPowerHilbertSpace(%s,%s)" % (printer._print(self.base,\ + return "TensorPowerHilbertSpace(%s,%s)" % (printer._print(self.base, *args), printer._print(self.exp, *args)) def _sympystr(self, printer, *args): - return "%s**%s" % (printer._print(self.base, *args),\ + return "%s**%s" % (printer._print(self.base, *args), printer._print(self.exp, *args)) def _pretty(self, printer, *args): diff -Nru python3-sympy-0.7.2/sympy/physics/quantum/identitysearch.py python3-sympy-0.7.3/sympy/physics/quantum/identitysearch.py --- python3-sympy-0.7.2/sympy/physics/quantum/identitysearch.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/physics/quantum/identitysearch.py 2013-07-13 17:53:32.000000000 +0000 @@ -27,7 +27,8 @@ ] np = import_module('numpy', min_python_version=(2, 6)) -scipy = import_module('scipy', __import__kwargs={'fromlist':['sparse']}) +scipy = import_module('scipy', __import__kwargs={'fromlist': ['sparse']}) + def is_scalar_sparse_matrix(circuit, nqubits, identity_only, eps=1e-11): """Checks if a given scipy.sparse matrix is a scalar matrix. @@ -75,10 +76,10 @@ # the matrix into real and imaginary components # Find the real values in between -eps and eps bool_real = np.logical_and(dense_matrix.real > -eps, - dense_matrix.real < eps) + dense_matrix.real < eps) # Find the imaginary values between -eps and eps bool_imag = np.logical_and(dense_matrix.imag > -eps, - dense_matrix.imag < eps) + dense_matrix.imag < eps) # Replaces values between -eps and eps with 0 corrected_real = np.where(bool_real, 0.0, dense_matrix.real) corrected_imag = np.where(bool_imag, 0.0, dense_matrix.imag) @@ -98,7 +99,7 @@ first_element = corrected_dense[0][0] # If the first element is a zero, then can't rescale matrix # and definitely not diagonal - if (first_element == 0.0+0.0j): + if (first_element == 0.0 + 0.0j): return False # The dimensions of the dense matrix should still @@ -114,7 +115,8 @@ imag_is_zero = abs(first_element.imag) < eps is_one = real_is_one and imag_is_zero is_identity = is_one if identity_only else True - return is_diagonal and has_correct_trace and is_identity + return bool(is_diagonal and has_correct_trace and is_identity) + def is_scalar_nonsparse_matrix(circuit, nqubits, identity_only): """Checks if a given circuit, in matrix form, is equivalent to @@ -157,21 +159,22 @@ # The matrix is scalar if it's diagonal and the adjusted trace # value is equal to 2^nqubits - return (matrix.is_diagonal() and - has_correct_trace and - is_identity) + return bool( + matrix.is_diagonal() and has_correct_trace and is_identity) if np and scipy: is_scalar_matrix = is_scalar_sparse_matrix else: is_scalar_matrix = is_scalar_nonsparse_matrix + def _get_min_qubits(a_gate): if isinstance(a_gate, Pow): return a_gate.base.min_qubits else: return a_gate.min_qubits + def ll_op(left, right): """Perform a LL operation. @@ -210,9 +213,7 @@ if (len(left) > 0): ll_gate = left[0] ll_gate_is_unitary = is_scalar_matrix( - (Dagger(ll_gate), ll_gate), - _get_min_qubits(ll_gate), - True) + (Dagger(ll_gate), ll_gate), _get_min_qubits(ll_gate), True) if (len(left) > 0 and ll_gate_is_unitary): # Get the new left side w/o the leftmost gate @@ -224,6 +225,7 @@ return None + def lr_op(left, right): """Perform a LR operation. @@ -260,15 +262,13 @@ """ if (len(left) > 0): - lr_gate = left[len(left)-1] + lr_gate = left[len(left) - 1] lr_gate_is_unitary = is_scalar_matrix( - (Dagger(lr_gate), lr_gate), - _get_min_qubits(lr_gate), - True) + (Dagger(lr_gate), lr_gate), _get_min_qubits(lr_gate), True) if (len(left) > 0 and lr_gate_is_unitary): # Get the new left side w/o the rightmost gate - new_left = left[0:len(left)-1] + new_left = left[0:len(left) - 1] # Add the rightmost gate to the right position on the right side new_right = right + (Dagger(lr_gate),) # Return the new gate rule @@ -276,6 +276,7 @@ return None + def rl_op(left, right): """Perform a RL operation. @@ -314,9 +315,7 @@ if (len(right) > 0): rl_gate = right[0] rl_gate_is_unitary = is_scalar_matrix( - (Dagger(rl_gate), rl_gate), - _get_min_qubits(rl_gate), - True) + (Dagger(rl_gate), rl_gate), _get_min_qubits(rl_gate), True) if (len(right) > 0 and rl_gate_is_unitary): # Get the new right side w/o the leftmost gate @@ -328,6 +327,7 @@ return None + def rr_op(left, right): """Perform a RR operation. @@ -364,15 +364,13 @@ """ if (len(right) > 0): - rr_gate = right[len(right)-1] + rr_gate = right[len(right) - 1] rr_gate_is_unitary = is_scalar_matrix( - (Dagger(rr_gate), rr_gate), - _get_min_qubits(rr_gate), - True) + (Dagger(rr_gate), rr_gate), _get_min_qubits(rr_gate), True) if (len(right) > 0 and rr_gate_is_unitary): # Get the new right side w/o the rightmost gate - new_right = right[0:len(right)-1] + new_right = right[0:len(right) - 1] # Add the rightmost gate to the right position on the right side new_left = left + (Dagger(rr_gate),) # Return the new gate rule @@ -380,6 +378,7 @@ return None + def generate_gate_rules(gate_seq, return_as_muls=False): """Returns a set of gate rules. Each gate rules is represented as a 2-tuple of tuples or Muls. An empty tuple represents an arbitrary @@ -524,6 +523,7 @@ return rules + def generate_equivalent_ids(gate_seq, return_as_muls=False): """Returns a set of equivalent gate identities. @@ -602,6 +602,7 @@ return eq_ids + class GateIdentity(Basic): """Wrapper class for circuits that reduce to a scalar value. @@ -662,6 +663,7 @@ """Returns the string of gates in a tuple.""" return str(self.circuit) + def is_degenerate(identity_set, gate_identity): """Checks if a gate identity is a permutation of another identity. @@ -700,6 +702,7 @@ return True return False + def is_reducible(circuit, nqubits, begin, end): """Determines if a circuit is reducible by checking if its subcircuits are scalar values. @@ -750,6 +753,7 @@ return False + def bfs_identity_search(gate_list, nqubits, max_depth=None, identity_only=False): """Constructs a set of gate identities from the list of possible gates. @@ -818,15 +822,16 @@ # the evaluated matrix will actually be an integer if (is_scalar_matrix(new_circuit, nqubits, id_only) and not is_degenerate(ids, new_circuit) and - not circuit_reducible): + not circuit_reducible): ids.add(GateIdentity(*new_circuit)) elif (len(new_circuit) < max_depth and - not circuit_reducible): + not circuit_reducible): queue.append(new_circuit) return ids + def random_identity_search(gate_list, numgates, nqubits): """Randomly selects numgates from gate_list and checks if it is a gate identity. diff -Nru python3-sympy-0.7.2/sympy/physics/quantum/matrixcache.py python3-sympy-0.7.3/sympy/physics/quantum/matrixcache.py --- python3-sympy-0.7.2/sympy/physics/quantum/matrixcache.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/physics/quantum/matrixcache.py 2013-07-13 17:53:32.000000000 +0000 @@ -7,6 +7,7 @@ to_sympy, to_numpy, to_scipy_sparse ) + class MatrixCache(object): """A cache for small matrices in different formats. @@ -43,7 +44,6 @@ except ImportError: pass - def get_matrix(self, name, format): """Get a cached matrix by name and format. @@ -58,7 +58,7 @@ if m is not None: return m raise NotImplementedError( - 'Matrix with name %s and format %s is not available.' %\ + 'Matrix with name %s and format %s is not available.' % (name, format) ) @@ -79,15 +79,15 @@ self._store_matrix(name, 'scipy.sparse', m) -sqrt2_inv = Pow(2, Rational(-1,2), evaluate=False) +sqrt2_inv = Pow(2, Rational(-1, 2), evaluate=False) # Save the common matrices that we will need matrix_cache = MatrixCache() -matrix_cache.cache_matrix('eye2', Matrix([[1,0],[0,1]])) -matrix_cache.cache_matrix('op11', Matrix([[0,0],[0,1]])) # |1><1| -matrix_cache.cache_matrix('op00', Matrix([[1,0],[0,0]])) # |0><0| -matrix_cache.cache_matrix('op10', Matrix([[0,0],[1,0]])) # |1><0| -matrix_cache.cache_matrix('op01', Matrix([[0,1],[0,0]])) # |0><1| +matrix_cache.cache_matrix('eye2', Matrix([[1, 0], [0, 1]])) +matrix_cache.cache_matrix('op11', Matrix([[0, 0], [0, 1]])) # |1><1| +matrix_cache.cache_matrix('op00', Matrix([[1, 0], [0, 0]])) # |0><0| +matrix_cache.cache_matrix('op10', Matrix([[0, 0], [1, 0]])) # |1><0| +matrix_cache.cache_matrix('op01', Matrix([[0, 1], [0, 0]])) # |0><1| matrix_cache.cache_matrix('X', Matrix([[0, 1], [1, 0]])) matrix_cache.cache_matrix('Y', Matrix([[0, -I], [I, 0]])) matrix_cache.cache_matrix('Z', Matrix([[1, 0], [0, -1]])) @@ -95,6 +95,7 @@ matrix_cache.cache_matrix('T', Matrix([[1, 0], [0, exp(I*pi/4)]])) matrix_cache.cache_matrix('H', sqrt2_inv*Matrix([[1, 1], [1, -1]])) matrix_cache.cache_matrix('Hsqrt2', Matrix([[1, 1], [1, -1]])) -matrix_cache.cache_matrix('SWAP',Matrix([[1,0,0,0],[0,0,1,0],[0,1,0,0],[0,0,0,1]])) -matrix_cache.cache_matrix('ZX', sqrt2_inv*Matrix([[1,1],[1,-1]])) -matrix_cache.cache_matrix('ZY', Matrix([[I,0],[0,-I]])) +matrix_cache.cache_matrix( + 'SWAP', Matrix([[1, 0, 0, 0], [0, 0, 1, 0], [0, 1, 0, 0], [0, 0, 0, 1]])) +matrix_cache.cache_matrix('ZX', sqrt2_inv*Matrix([[1, 1], [1, -1]])) +matrix_cache.cache_matrix('ZY', Matrix([[I, 0], [0, -I]])) diff -Nru python3-sympy-0.7.2/sympy/physics/quantum/matrixutils.py python3-sympy-0.7.3/sympy/physics/quantum/matrixutils.py --- python3-sympy-0.7.2/sympy/physics/quantum/matrixutils.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/physics/quantum/matrixutils.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,7 +1,7 @@ """Utilities to deal with sympy.Matrix, numpy and scipy.sparse.""" from sympy import Matrix, I, Expr, Integer -from sympy.matrices import matrices +from sympy.matrices import eye, zeros from sympy.external import import_module __all__ = [ @@ -16,7 +16,8 @@ 'to_sympy', 'to_numpy', 'to_scipy_sparse', - 'matrix_tensor_product' + 'matrix_tensor_product', + 'matrix_zeros' ] # Conditionally define the base classes for numpy and scipy.sparse arrays @@ -29,7 +30,7 @@ else: numpy_ndarray = np.ndarray -scipy = import_module('scipy', __import__kwargs={'fromlist':['sparse']}) +scipy = import_module('scipy', __import__kwargs={'fromlist': ['sparse']}) if not scipy: class scipy_sparse_matrix(object): pass @@ -49,7 +50,7 @@ """Convert a sympy Matrix/complex number to a numpy matrix or scalar.""" if not np: raise ImportError - dtype = options.get('dtype','complex') + dtype = options.get('dtype', 'complex') if isinstance(m, Matrix): return np.matrix(m.tolist(), dtype=dtype) elif isinstance(m, Expr): @@ -62,7 +63,7 @@ """Convert a sympy Matrix/complex number to a numpy matrix or scalar.""" if not np or not sparse: raise ImportError - dtype = options.get('dtype','complex') + dtype = options.get('dtype', 'complex') if isinstance(m, Matrix): return sparse.csr_matrix(np.matrix(m.tolist(), dtype=dtype)) elif isinstance(m, Expr): @@ -93,9 +94,10 @@ return m raise TypeError('Expected sympy/numpy/scipy.sparse matrix, got: %r' % m) + def to_numpy(m, **options): """Convert a sympy/scipy.sparse matrix to a numpy matrix.""" - dtype = options.get('dtype','complex') + dtype = options.get('dtype', 'complex') if isinstance(m, (Matrix, Expr)): return sympy_to_numpy(m, dtype=dtype) elif isinstance(m, numpy_ndarray): @@ -107,8 +109,8 @@ def to_scipy_sparse(m, **options): """Convert a sympy/numpy matrix to a scipy.sparse matrix.""" - dtype = options.get('dtype','complex') - if isinstance(m, (Matrix, Expr)): + dtype = options.get('dtype', 'complex') + if isinstance(m, (Matrix, Expr)): return sympy_to_scipy_sparse(m, dtype=dtype) elif isinstance(m, numpy_ndarray): if not sparse: @@ -122,11 +124,11 @@ def flatten_scalar(e): """Flatten a 1x1 matrix to a scalar, return larger matrices unchanged.""" if isinstance(e, Matrix): - if e.shape == (1,1): + if e.shape == (1, 1): e = e[0] if isinstance(e, (numpy_ndarray, scipy_sparse_matrix)): - if e.shape == (1,1): - e = complex(e[0,0]) + if e.shape == (1, 1): + e = complex(e[0, 0]) return e @@ -160,21 +162,23 @@ Examples ======== - >>> from sympy import I, Matrix, symbols - >>> from sympy.physics.quantum.matrixutils import _sympy_tensor_product + >>> from sympy import I, Matrix, symbols + >>> from sympy.physics.quantum.matrixutils import _sympy_tensor_product - >>> m1 = Matrix([[1,2],[3,4]]) - >>> m2 = Matrix([[1,0],[0,1]]) - >>> _sympy_tensor_product(m1, m2) - [1, 0, 2, 0] - [0, 1, 0, 2] - [3, 0, 4, 0] - [0, 3, 0, 4] - >>> _sympy_tensor_product(m2, m1) - [1, 2, 0, 0] - [3, 4, 0, 0] - [0, 0, 1, 2] - [0, 0, 3, 4] + >>> m1 = Matrix([[1,2],[3,4]]) + >>> m2 = Matrix([[1,0],[0,1]]) + >>> _sympy_tensor_product(m1, m2) + Matrix([ + [1, 0, 2, 0], + [0, 1, 0, 2], + [3, 0, 4, 0], + [0, 3, 0, 4]]) + >>> _sympy_tensor_product(m2, m1) + Matrix([ + [1, 2, 0, 0], + [3, 4, 0, 0], + [0, 0, 1, 2], + [0, 0, 3, 4]]) References ========== @@ -182,14 +186,13 @@ [1] http://en.wikipedia.org/wiki/Kronecker_product """ # Make sure we have a sequence of Matrices - testmat = [isinstance(m, Matrix) for m in matrices] - if not all(testmat): + if not all(isinstance(m, Matrix) for m in matrices): raise TypeError( 'Sequence of Matrices expected, got: %s' % repr(matrices) ) # Pull out the first element in the product. - matrix_expansion = matrices[-1] + matrix_expansion = matrices[-1] # Do the tensor product working from right to left. for mat in reversed(matrices[:-1]): rows = mat.rows @@ -199,9 +202,9 @@ for i in range(rows): start = matrix_expansion*mat[i*cols] # Go through each column joining each item - for j in range(cols-1): + for j in range(cols - 1): start = start.row_join( - matrix_expansion*mat[i*cols+j+1] + matrix_expansion*mat[i*cols + j + 1] ) # If this is the first element, make it the start of the # new row. @@ -261,9 +264,9 @@ def matrix_eye(n, **options): """Get the version of eye and tensor_product for a given format.""" - format = options.get('format','sympy') + format = options.get('format', 'sympy') if format == 'sympy': - return matrices.eye(n) + return eye(n) elif format == 'numpy': return _numpy_eye(n) elif format == 'scipy.sparse': @@ -271,6 +274,40 @@ raise NotImplementedError('Invalid format: %r' % format) +def _numpy_zeros(m, n, **options): + """numpy verson of zeros.""" + dtype = options.get('dtype', 'float64') + if not np: + raise ImportError + return np.zeros((m, n), dtype=dtype) + + +def _scipy_sparse_zeros(m, n, **options): + """scipy.sparse verson of zeros.""" + spmatrix = options.get('spmatrix', 'csr') + dtype = options.get('dtype', 'float64') + if not sparse: + raise ImportError + if spmatrix == 'lil': + return sparse.lil_matrix((m, n), dtype=dtype) + elif spmatrix == 'csr': + return sparse.csr_matrix((m, n), dtype=dtype) + + +def matrix_zeros(m, n, **options): + """"Get a zeros matrix for a given format.""" + format = options.get('format', 'sympy') + dtype = options.get('dtype', 'float64') + spmatrix = options.get('spmatrix', 'csr') + if format == 'sympy': + return zeros(m, n) + elif format == 'numpy': + return _numpy_zeros(m, n, **options) + elif format == 'scipy.sparse': + return _scipy_sparse_zeros(m, n, **options) + raise NotImplementedError('Invaild format: %r' % format) + + def _numpy_matrix_to_zero(e): """Convert a numpy zero matrix to the zero scalar.""" if not np: @@ -297,7 +334,7 @@ def matrix_to_zero(e): """Convert a zero matrix to the scalar zero.""" if isinstance(e, Matrix): - if matrices.zeros(*e.shape) == e: + if zeros(*e.shape) == e: e = Integer(0) elif isinstance(e, numpy_ndarray): e = _numpy_matrix_to_zero(e) diff -Nru python3-sympy-0.7.2/sympy/physics/quantum/operator.py python3-sympy-0.7.3/sympy/physics/quantum/operator.py --- python3-sympy-0.7.2/sympy/physics/quantum/operator.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/physics/quantum/operator.py 2013-07-13 17:53:32.000000000 +0000 @@ -26,6 +26,7 @@ # Operators and outer products #----------------------------------------------------------------------------- + class Operator(QExpr): """Base class for non-commuting quantum operators. @@ -89,13 +90,14 @@ References ========== - .. [1] http://en.wikipedia.org/wiki/Operator_(physics) + .. [1] http://en.wikipedia.org/wiki/Operator_%28physics%29 .. [2] http://en.wikipedia.org/wiki/Observable """ @classmethod def default_args(self): return ("O",) + #------------------------------------------------------------------------- # Printing #------------------------------------------------------------------------- @@ -162,17 +164,12 @@ def matrix_element(self, *args): raise NotImplementedError('matrix_elements is not defined') - #------------------------------------------------------------------------- - # Printing - #------------------------------------------------------------------------- - def inverse(self): return self._eval_inverse() inv = inverse def _eval_inverse(self): - # TODO: make non-commutative Exprs print powers using A**-1, not 1/A. return self**(-1) @@ -311,7 +308,7 @@ raise TypeError('BraBase subclass expected, got: %r' % ket) if not ket.dual_class() == bra.__class__: raise TypeError( - 'ket and bra are not dual classes: %r, %r' % \ + 'ket and bra are not dual classes: %r, %r' % (ket.__class__, bra.__class__) ) # TODO: make sure the hilbert spaces of the bra and ket are compatible @@ -333,7 +330,7 @@ return OuterProduct(Dagger(self.bra), Dagger(self.ket)) def _sympystr(self, printer, *args): - return str(self.ket)+str(self.bra) + return str(self.ket) + str(self.bra) def _sympyrepr(self, printer, *args): return '%s(%s,%s)' % (self.__class__.__name__, @@ -346,18 +343,19 @@ def _latex(self, printer, *args): k = printer._print(self.ket, *args) b = printer._print(self.bra, *args) - return k+b + return k + b def _represent(self, **options): k = self.ket._represent(**options) b = self.bra._represent(**options) return k*b - def _eval_trace(self,**kwargs): + def _eval_trace(self, **kwargs): # TODO if operands are tensorproducts this may be will be handled # differently. - return self.ket._eval_trace(self.bra,**kwargs); + return self.ket._eval_trace(self.bra, **kwargs) + class DifferentialOperator(Operator): """An operator for representing the differential operator, i.e. d/dx @@ -506,7 +504,7 @@ return '%s(%s)' % ( self._print_operator_name(printer, *args), self._print_label(printer, *args) - ) + ) def _print_pretty(self, printer, *args): pform = self._print_operator_name_pretty(printer, *args) diff -Nru python3-sympy-0.7.2/sympy/physics/quantum/operatorset.py python3-sympy-0.7.3/sympy/physics/quantum/operatorset.py --- python3-sympy-0.7.2/sympy/physics/quantum/operatorset.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/physics/quantum/operatorset.py 2013-07-13 17:53:32.000000000 +0000 @@ -34,15 +34,16 @@ #frozenset is used so that the reverse mapping can be made #(regular sets are not hashable because they are mutable -state_mapping = { JxKet : frozenset((J2Op, JxOp)), - JyKet : frozenset((J2Op, JyOp)), - JzKet : frozenset((J2Op, JzOp)), - Ket : Operator, - PositionKet3D : frozenset((XOp, YOp, ZOp)), - PxKet : PxOp, - XKet : XOp } +state_mapping = { JxKet: frozenset((J2Op, JxOp)), + JyKet: frozenset((J2Op, JyOp)), + JzKet: frozenset((J2Op, JzOp)), + Ket: Operator, + PositionKet3D: frozenset((XOp, YOp, ZOp)), + PxKet: PxOp, + XKet: XOp } + +op_mapping = dict((v, k) for k, v in state_mapping.items()) -op_mapping = dict((v,k) for k,v in state_mapping.items()) def operators_to_state(operators, **options): """ Returns the eigenstate of the given operator or set of operators @@ -98,20 +99,20 @@ |psi> """ - if not (isinstance(operators, Operator) \ + if not (isinstance(operators, Operator) or isinstance(operators, set) or issubclass(operators, Operator)): raise NotImplementedError("Argument is not an Operator or a set!") if isinstance(operators, set): for s in operators: - if not (isinstance(s, Operator) \ + if not (isinstance(s, Operator) or issubclass(s, Operator)): raise NotImplementedError("Set is not all Operators!") #ops = tuple(operators) ops = frozenset(operators) - if ops in op_mapping: #ops is a list of classes in this case + if ops in op_mapping: # ops is a list of classes in this case #Try to get an object from default instances of the #operators...if this fails, return the class try: @@ -145,6 +146,7 @@ else: return None + def state_to_operators(state, **options): """ Returns the operator or set of operators corresponding to the given eigenstate @@ -207,23 +209,23 @@ if not (isinstance(state, StateBase) or issubclass(state, StateBase)): raise NotImplementedError("Argument is not a state!") - if state in state_mapping: #state is a class + if state in state_mapping: # state is a class state_inst = _make_default(state) try: - ret = _get_ops(state_inst, \ + ret = _get_ops(state_inst, _make_set(state_mapping[state]), **options) except (NotImplementedError, TypeError): ret = state_mapping[state] elif type(state) in state_mapping: - ret = _get_ops(state, \ + ret = _get_ops(state, _make_set(state_mapping[type(state)]), **options) elif isinstance(state, BraBase) and state.dual_class() in state_mapping: - ret = _get_ops(state, \ + ret = _get_ops(state, _make_set(state_mapping[state.dual_class()])) elif issubclass(state, BraBase) and state.dual_class() in state_mapping: state_inst = _make_default(state) try: - ret = _get_ops(state_inst, \ + ret = _get_ops(state_inst, _make_set(state_mapping[state.dual_class()])) except (NotImplementedError, TypeError): ret = state_mapping[state.dual_class()] @@ -232,6 +234,7 @@ return _make_set(ret) + def _make_default(expr): try: ret = expr() @@ -240,6 +243,7 @@ return ret + def _get_state(state_class, ops, **options): # Try to get a state instance from the operator INSTANCES. # If this fails, get the class @@ -250,6 +254,7 @@ return ret + def _get_ops(state_inst, op_classes, **options): # Try to get operator instances from the state INSTANCE. # If this fails, just return the classes @@ -266,6 +271,7 @@ return ret + def _make_set(ops): if isinstance(ops, (tuple, list, frozenset)): return set(ops) diff -Nru python3-sympy-0.7.2/sympy/physics/quantum/piab.py python3-sympy-0.7.3/sympy/physics/quantum/piab.py --- python3-sympy-0.7.2/sympy/physics/quantum/piab.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/physics/quantum/piab.py 2013-07-13 17:53:32.000000000 +0000 @@ -24,7 +24,7 @@ @classmethod def _eval_hilbert_space(cls, label): - return L2(Interval(S.NegativeInfinity,S.Infinity)) + return L2(Interval(S.NegativeInfinity, S.Infinity)) def _apply_operator_PIABKet(self, ket, **options): n = ket.label[0] @@ -36,7 +36,7 @@ @classmethod def _eval_hilbert_space(cls, args): - return L2(Interval(S.NegativeInfinity,S.Infinity)) + return L2(Interval(S.NegativeInfinity, S.Infinity)) @classmethod def dual_class(self): @@ -48,7 +48,7 @@ def _represent_XOp(self, basis, **options): x = Symbol('x') n = Symbol('n') - subs_info = options.get('subs',{}) + subs_info = options.get('subs', {}) return sqrt(2/L)*sin(n*pi*x/L).subs(subs_info) def _eval_innerproduct_PIABBra(self, bra): @@ -60,7 +60,7 @@ @classmethod def _eval_hilbert_space(cls, label): - return L2(Interval(S.NegativeInfinity,S.Infinity)) + return L2(Interval(S.NegativeInfinity, S.Infinity)) @classmethod def dual_class(self): diff -Nru python3-sympy-0.7.2/sympy/physics/quantum/qapply.py python3-sympy-0.7.3/sympy/physics/quantum/qapply.py --- python3-sympy-0.7.2/sympy/physics/quantum/qapply.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/physics/quantum/qapply.py 2013-07-13 17:53:32.000000000 +0000 @@ -79,7 +79,8 @@ # For a Density operator call qapply on its state elif isinstance(e, Density): - new_args = [(qapply(state, **options),prob) for (state,prob) in e.args] + new_args = [(qapply(state, **options), prob) for (state, + prob) in e.args] return Density(*new_args) # For a raw TensorProduct, call qapply on its args. @@ -118,13 +119,13 @@ # Make sure we have two non-commutative objects before proceeding. if (sympify(rhs).is_commutative and not isinstance(rhs, Wavefunction)) or \ - (sympify(lhs).is_commutative and not isinstance(lhs, Wavefunction)): + (sympify(lhs).is_commutative and not isinstance(lhs, Wavefunction)): return e # For a Pow with an integer exponent, apply one of them and reduce the # exponent by one. if isinstance(lhs, Pow) and lhs.exp.is_Integer: - args.append(lhs.base**(lhs.exp-1)) + args.append(lhs.base**(lhs.exp - 1)) lhs = lhs.base # Pull OuterProduct apart @@ -137,7 +138,7 @@ comm = lhs.doit() if isinstance(comm, Add): return qapply( - e.func(*(args + [comm.args[0], rhs])) +\ + e.func(*(args + [comm.args[0], rhs])) + e.func(*(args + [comm.args[1], rhs])), **options ) @@ -145,8 +146,8 @@ return qapply(e.func(*args)*comm*rhs, **options) # Apply tensor products of operators to states - if isinstance(lhs, TensorProduct) and all([isinstance(arg,Operator) or arg == 1 for arg in lhs.args]) and \ - isinstance(rhs, TensorProduct) and all([isinstance(arg,State) or arg == 1 for arg in rhs.args]) and \ + if isinstance(lhs, TensorProduct) and all([isinstance(arg, Operator) or arg == 1 for arg in lhs.args]) and \ + isinstance(rhs, TensorProduct) and all([isinstance(arg, State) or arg == 1 for arg in rhs.args]) and \ len(lhs.args) == len(rhs.args): result = TensorProduct(*[qapply(lhs.args[n]*rhs.args[n], **options) for n in range(len(lhs.args))]).expand(tensorproduct=True) return qapply_Mul(e.func(*args), **options)*result @@ -173,7 +174,7 @@ # We had two args to begin with so args=[]. return e else: - return qapply_Mul(e.func(*(args+[lhs])), **options)*rhs + return qapply_Mul(e.func(*(args + [lhs])), **options)*rhs elif isinstance(result, InnerProduct): return result*qapply_Mul(e.func(*args), **options) else: # result is a scalar times a Mul, Add or TensorProduct diff -Nru python3-sympy-0.7.2/sympy/physics/quantum/qexpr.py python3-sympy-0.7.3/sympy/physics/quantum/qexpr.py --- python3-sympy-0.7.2/sympy/physics/quantum/qexpr.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/physics/quantum/qexpr.py 2013-07-13 17:53:32.000000000 +0000 @@ -50,6 +50,7 @@ return tuple(__qsympify_sequence_helper(seq)) + def __qsympify_sequence_helper(seq): """ Helper function for _qsympify_sequence @@ -161,7 +162,7 @@ This must be a tuple, rather than a Tuple. """ - if len(self.args) == 0: # If there is no label specified, return the default + if len(self.args) == 0: # If there is no label specified, return the default return self._eval_args(list(self.default_args())) else: return self.args @@ -323,7 +324,8 @@ # than str(). See L1072 of basic.py. # This will call self.rule(*self.args) for rewriting. if hints.get('deep', False): - args = [ a._eval_rewrite(pattern, rule, **hints) for a in self.args ] + args = [ a._eval_rewrite(pattern, rule, **hints) + for a in self.args ] else: args = self.args @@ -377,7 +379,7 @@ the representation, such as the number of basis functions to be used. """ - basis = options.pop('basis',None) + basis = options.pop('basis', None) if basis is None: result = self._represent_default_basis(**options) else: @@ -393,18 +395,20 @@ return to_sympy(result) elif format == 'numpy' and not isinstance(result, numpy_ndarray): return to_numpy(result) - elif format == 'scipy.sparse' and\ - not isinstance(result, scipy_sparse_matrix): + elif format == 'scipy.sparse' and \ + not isinstance(result, scipy_sparse_matrix): return to_scipy_sparse(result) return result + def split_commutative_parts(e): """Split into commutative and non-commutative parts.""" c_part, nc_part = e.args_cnc() c_part = list(c_part) return c_part, nc_part + def split_qexpr_parts(e): """Split an expression into Expr and noncommutative QExpr parts.""" expr_part = [] @@ -427,6 +431,6 @@ if result is not None: return result raise NotImplementedError( - "%s.%s can't handle: %r" % \ - (self.__class__.__name__, basename, arg) + "%s.%s can't handle: %r" % + (self.__class__.__name__, basename, arg) ) diff -Nru python3-sympy-0.7.2/sympy/physics/quantum/qft.py python3-sympy-0.7.3/sympy/physics/quantum/qft.py --- python3-sympy-0.7.2/sympy/physics/quantum/qft.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/physics/quantum/qft.py 2013-07-13 17:53:32.000000000 +0000 @@ -16,7 +16,7 @@ from sympy.physics.quantum.qapply import qapply from sympy.physics.quantum.qexpr import QuantumError, QExpr -from sympy.matrices.matrices import eye +from sympy.matrices import eye from sympy.physics.quantum.tensorproduct import matrix_tensor_product from sympy.physics.quantum.gate import ( @@ -81,8 +81,9 @@ def get_target_matrix(self, format='sympy'): if format == 'sympy': - return Matrix([[1,0],[0,exp(Integer(2)*pi*I/(Integer(2)**self.k))]]) - raise NotImplementedError('Invalid format for the R_k gate: %r' % format) + return Matrix([[1, 0], [0, exp(Integer(2)*pi*I/(Integer(2)**self.k))]]) + raise NotImplementedError( + 'Invalid format for the R_k gate: %r' % format) Rk = RkGate @@ -108,9 +109,10 @@ """ Represents the (I)QFT In the Z Basis """ - nqubits = options.get('nqubits',0) + nqubits = options.get('nqubits', 0) if nqubits == 0: - raise QuantumError('The number of qubits must be given as nqubits.') + raise QuantumError( + 'The number of qubits must be given as nqubits.') if nqubits < self.min_qubits: raise QuantumError( 'The number of qubits %r is too small for the gate.' % nqubits @@ -119,20 +121,22 @@ omega = self.omega #Make a matrix that has the basic Fourier Transform Matrix - arrayFT = [[omega**(i*j%size)/sqrt(size) for i in range(size)] for j in range(size)] + arrayFT = [[omega**( + i*j % size)/sqrt(size) for i in range(size)] for j in range(size)] matrixFT = Matrix(arrayFT) #Embed the FT Matrix in a higher space, if necessary if self.label[0] != 0: matrixFT = matrix_tensor_product(eye(2**self.label[0]), matrixFT) if self.min_qubits < nqubits: - matrixFT = matrix_tensor_product(matrixFT, eye(2**(nqubits-self.min_qubits))) + matrixFT = matrix_tensor_product( + matrixFT, eye(2**(nqubits - self.min_qubits))) return matrixFT @property def targets(self): - return list(range(self.label[0],self.label[1])) + return list(range(self.label[0], self.label[1])) @property def min_qubits(self): @@ -141,7 +145,7 @@ @property def size(self): """Size is the size of the QFT matrix""" - return 2**(self.label[1]-self.label[0]) + return 2**(self.label[1] - self.label[0]) @property def omega(self): @@ -161,10 +165,10 @@ circuit = 1 for level in reversed(list(range(start, finish))): circuit = HadamardGate(level)*circuit - for i in range(level-start): - circuit = CGate(level-i-1, RkGate(level, i+2))*circuit - for i in range((finish-start)//2): - circuit = SwapGate(i+start, finish-i-1)*circuit + for i in range(level - start): + circuit = CGate(level - i - 1, RkGate(level, i + 2))*circuit + for i in range((finish - start)//2): + circuit = SwapGate(i + start, finish - i - 1)*circuit return circuit def _apply_operator_Qubit(self, qubits, **options): @@ -189,11 +193,11 @@ start = self.args[0] finish = self.args[1] circuit = 1 - for i in range((finish-start)//2): - circuit = SwapGate(i+start, finish-i-1)*circuit + for i in range((finish - start)//2): + circuit = SwapGate(i + start, finish - i - 1)*circuit for level in range(start, finish): - for i in reversed(list(range(level-start))): - circuit = CGate(level-i-1, RkGate(level, -i-2))*circuit + for i in reversed(list(range(level - start))): + circuit = CGate(level - i - 1, RkGate(level, -i - 2))*circuit circuit = HadamardGate(level)*circuit return circuit diff -Nru python3-sympy-0.7.2/sympy/physics/quantum/qubit.py python3-sympy-0.7.3/sympy/physics/quantum/qubit.py --- python3-sympy-0.7.2/sympy/physics/quantum/qubit.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/physics/quantum/qubit.py 2013-07-13 17:53:32.000000000 +0000 @@ -10,7 +10,7 @@ from sympy import Integer, log, Mul, Add, Pow, conjugate from sympy.core.basic import sympify -from sympy.matrices.matrices import Matrix, zeros +from sympy.matrices import Matrix, zeros from sympy.printing.pretty.stringpict import prettyForm @@ -42,6 +42,7 @@ # Qubit Classes #----------------------------------------------------------------------------- + class QubitState(State): """Base class for Qubit and QubitBra.""" @@ -65,7 +66,8 @@ # Validate input (must have 0 or 1 input) for element in args: if not (element == 1 or element == 0): - raise ValueError("Qubit values must be 0 or 1, got: %r" % element) + raise ValueError( + "Qubit values must be 0 or 1, got: %r" % element) return args @classmethod @@ -98,7 +100,7 @@ return self.dimension def __getitem__(self, bit): - return self.qubit_values[int(self.dimension-bit-1)] + return self.qubit_values[int(self.dimension - bit - 1)] #------------------------------------------------------------------------- # Utility methods @@ -108,7 +110,7 @@ """Flip the bit(s) given.""" newargs = list(self.qubit_values) for i in bits: - bit = int(self.dimension-i-1) + bit = int(self.dimension - i - 1) if newargs[bit] == 1: newargs[bit] = 0 else: @@ -171,7 +173,6 @@ 1 """ - @classmethod def dual_class(self): return QubitBra @@ -217,7 +218,7 @@ #trace out for each of index new_mat = self*bra - for i in range(len(sorted_idx)-1, -1, -1): + for i in range(len(sorted_idx) - 1, -1, -1): # start from tracing out from leftmost qubit new_mat = self._reduced_density(new_mat, int(sorted_idx[i])) @@ -247,10 +248,11 @@ for k in range(2): col = find_index_that_is_projected(j, k, qubit) row = find_index_that_is_projected(i, k, qubit) - new_matrix[i,j] += old_matrix[row,col] + new_matrix[i, j] += old_matrix[row, col] return new_matrix + class QubitBra(QubitState, Bra): """A multi-qubit bra in the computational (z) basis. @@ -287,15 +289,16 @@ if len(args) == 1 and args[0] > 1: #rvalues is the minimum number of bits needed to express the number rvalues = reversed(range(bitcount(abs(args[0])))) - qubit_values = [(args[0]>>i)&1 for i in rvalues] + qubit_values = [(args[0] >> i) & 1 for i in rvalues] return QubitState._eval_args(qubit_values) # For two numbers, the second number is the number of bits # on which it is expressed, so IntQubit(0,5) == |00000>. elif len(args) == 2 and args[1] > 1: need = bitcount(abs(args[0])) if args[1] < need: - raise ValueError('cannot represent %s with %s bits' % (args[0], args[1])) - qubit_values = [(args[0]>>i)&1 for i in reversed(list(range(args[1])))] + raise ValueError( + 'cannot represent %s with %s bits' % (args[0], args[1])) + qubit_values = [(args[0] >> i) & 1 for i in reversed(list(range(args[1])))] return QubitState._eval_args(qubit_values) else: return QubitState._eval_args(args) @@ -306,7 +309,7 @@ n = 1 for i in reversed(self.qubit_values): number += n*i - n = n<<1 + n = n << 1 return number def _print_label(self, printer, *args): @@ -372,6 +375,8 @@ def dual_class(self): return IntQubitBra + def _eval_innerproduct_IntQubitBra(self, bra, **hints): + return Qubit._eval_innerproduct_QubitBra(self, bra) class IntQubitBra(IntQubitState, QubitBra): """A qubit bra that store integers as binary numbers in qubit values.""" @@ -438,24 +443,25 @@ result = 0 for i in range(mlistlen): if ket: - element = matrix[i,0] + element = matrix[i, 0] else: - element = matrix[0,i] + element = matrix[0, i] if format == 'numpy' or format == 'scipy.sparse': element = complex(element) if element != 0.0: # Form Qubit array; 0 in bit-locations where i is 0, 1 in # bit-locations where i is 1 - qubit_array = [int(i & (1< random_number: break result += 1 - return Qubit(IntQubit(result, int(math.log(max(m.shape),2)+.1))) + return Qubit(IntQubit(result, int(math.log(max(m.shape), 2) + .1))) else: raise NotImplementedError( "This function can't handle non-sympy matrix formats yet" diff -Nru python3-sympy-0.7.2/sympy/physics/quantum/represent.py python3-sympy-0.7.3/sympy/physics/quantum/represent.py --- python3-sympy-0.7.2/sympy/physics/quantum/represent.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/physics/quantum/represent.py 2013-07-13 17:53:32.000000000 +0000 @@ -32,6 +32,7 @@ # Represent #----------------------------------------------------------------------------- + def _sympy_to_scalar(e): """Convert from a sympy scalar to a Python scalar.""" if isinstance(e, Expr): @@ -82,7 +83,7 @@ can be any object that contains the basis set information. options : dict Key/value pairs of options that are passed to the underlying method - that does finds the representation. These options can be used to + that finds the representation. These options can be used to control how the representation is done. For example, this is where the size of the basis set would be set. @@ -90,7 +91,7 @@ ======= e : Expr - The sympy expression of the represented quantum expression. + The SymPy expression of the represented quantum expression. Examples ======== @@ -112,8 +113,9 @@ >>> sz = SzOp('Sz') >>> up = SzUpKet('up') >>> represent(up, basis=sz) - [1] - [0] + Matrix([ + [1], + [0]]) Here we see an example of representations in a continuous basis. We see that the result of representing various combinations @@ -182,7 +184,7 @@ B = represent(expr.args[1], **options) return A*B + B*A elif isinstance(expr, InnerProduct): - return represent(Mul(expr.bra,expr.ket), **options) + return represent(Mul(expr.bra, expr.ket), **options) elif not (isinstance(expr, Mul) or isinstance(expr, OuterProduct)): # For numpy and scipy.sparse, we can only handle numerical prefactors. if format == 'numpy' or format == 'scipy.sparse': @@ -225,6 +227,7 @@ return result + def rep_innerproduct(expr, **options): """ Returns an innerproduct like representation (e.g. ````) for the @@ -268,9 +271,10 @@ if isinstance(expr, BraBase): bra = expr - ket = (basis_kets[1] if basis_kets[0].dual == expr else basis_kets[0]) + ket = (basis_kets[1] if basis_kets[0].dual == expr else basis_kets[0]) else: - bra = (basis_kets[1].dual if basis_kets[0] == expr else basis_kets[0].dual) + bra = (basis_kets[1].dual if basis_kets[0] + == expr else basis_kets[0].dual) ket = expr prod = InnerProduct(bra, ket) @@ -279,6 +283,7 @@ format = options.get('format', 'sympy') return expr._format_represent(result, format) + def rep_expectation(expr, **options): """ Returns an ```` type representation for the given operator. @@ -321,6 +326,7 @@ return qapply(bra*expr*ket) + def integrate_result(orig_expr, result, **options): """ Returns the result of integrating over any unities ``(|x>>> x, x_1, x_2 = symbols('x, x_1, x_2') >>> integrate_result(X_op*x_ket, x*DiracDelta(x-x_1)*DiracDelta(x_1-x_2)) x*DiracDelta(x - x_1)*DiracDelta(x_1 - x_2) - >>> integrate_result(X_op*x_ket, x*DiracDelta(x-x_1)*DiracDelta(x_1-x_2), unities=[1]) + >>> integrate_result(X_op*x_ket, x*DiracDelta(x-x_1)*DiracDelta(x_1-x_2), + ... unities=[1]) x*DiracDelta(x - x_2) """ @@ -394,6 +401,7 @@ return result + def get_basis(expr, **options): """ Returns a basis state instance corresponding to the basis specified in @@ -461,7 +469,7 @@ return (state_inst if state_inst is not None else None) else: return None - elif (isinstance(basis, Operator) or \ + elif (isinstance(basis, Operator) or (not isinstance(basis, StateBase) and issubclass(basis, Operator))): state = operators_to_state(basis) if state is None: @@ -477,6 +485,7 @@ else: return None + def _make_default(expr): try: expr = expr() @@ -485,6 +494,7 @@ return expr + def enumerate_states(*args, **options): """ Returns instances of the given state with dummy indices appended diff -Nru python3-sympy-0.7.2/sympy/physics/quantum/sho1d.py python3-sympy-0.7.3/sympy/physics/quantum/sho1d.py --- python3-sympy-0.7.2/sympy/physics/quantum/sho1d.py 1970-01-01 00:00:00.000000000 +0000 +++ python3-sympy-0.7.3/sympy/physics/quantum/sho1d.py 2013-07-13 17:53:32.000000000 +0000 @@ -0,0 +1,682 @@ +"""Simple Harmonic Oscillator 1-Dimension""" + +from sympy import sqrt, I, Symbol, Integer, S +from sympy.physics.quantum.constants import hbar +from sympy.physics.quantum.operator import Operator +from sympy.physics.quantum.state import Bra, Ket, State +from sympy.physics.quantum.qexpr import QExpr +from sympy.physics.quantum.cartesian import X, Px +from sympy.functions.special.tensor_functions import KroneckerDelta +from sympy.physics.quantum.hilbert import ComplexSpace +from sympy.physics.quantum.matrixutils import matrix_zeros +from sympy.physics.quantum.represent import represent + +#------------------------------------------------------------------------------ + +class SHOOp(Operator): + """A base class for the SHO Operators. + + We are limiting the number of arguments to be 1. + + """ + + @classmethod + def _eval_args(cls, args): + args = QExpr._eval_args(args) + if len(args) == 1: + return args + else: + raise ValueError("Too many arguments") + + @classmethod + def _eval_hilbert_space(cls, label): + return ComplexSpace(S.Infinity) + +class RaisingOp(SHOOp): + """The Raising Operator or a^dagger. + + When a^dagger acts on a state it raises the state up by one. Taking + the adjoint of a^dagger returns 'a', the Lowering Operator. a^dagger + can be rewritten in terms of position and momentum. We can represent + a^dagger as a matrix, which will be its default basis. + + Parameters + ========== + + args : tuple + The list of numbers or parameters that uniquely specify the + operator. + + Examples + ======== + + Create a Raising Operator and rewrite it in terms of position and + momentum, and show that taking its adjoint returns 'a': + + >>> from sympy.physics.quantum.sho1d import RaisingOp + >>> from sympy.physics.quantum import Dagger + + >>> ad = RaisingOp('a') + >>> ad.rewrite('xp').doit() + sqrt(2)*(m*omega*X - I*Px)/(2*sqrt(hbar)*sqrt(m*omega)) + + >>> Dagger(ad) + a + + Taking the commutator of a^dagger with other Operators: + + >>> from sympy.physics.quantum import Commutator + >>> from sympy.physics.quantum.sho1d import RaisingOp, LoweringOp + >>> from sympy.physics.quantum.sho1d import NumberOp + + >>> ad = RaisingOp('a') + >>> a = LoweringOp('a') + >>> N = NumberOp('N') + >>> Commutator(ad, a).doit() + -1 + >>> Commutator(ad, N).doit() + -RaisingOp(a) + + Apply a^dagger to a state: + + >>> from sympy.physics.quantum import qapply + >>> from sympy.physics.quantum.sho1d import RaisingOp, SHOKet + + >>> ad = RaisingOp('a') + >>> k = SHOKet('k') + >>> qapply(ad*k) + sqrt(k + 1)*|k + 1> + + Matrix Representation + + >>> from sympy.physics.quantum.sho1d import RaisingOp + >>> from sympy.physics.quantum.represent import represent + >>> ad = RaisingOp('a') + >>> represent(ad, basis=N, ndim=4, format='sympy') + Matrix([ + [0, 0, 0, 0], + [1, 0, 0, 0], + [0, sqrt(2), 0, 0], + [0, 0, sqrt(3), 0]]) + + """ + + def _eval_rewrite_as_xp(self, *args): + return (Integer(1)/sqrt(Integer(2)*hbar*m*omega))*( + Integer(-1)*I*Px + m*omega*X) + + def _eval_adjoint(self): + return LoweringOp(*self.args) + + def _eval_commutator_LoweringOp(self, other): + return Integer(-1) + + def _eval_commutator_NumberOp(self, other): + return Integer(-1)*self + + def _apply_operator_SHOKet(self, ket): + temp = ket.n + Integer(1) + return sqrt(temp)*SHOKet(temp) + + def _represent_default_basis(self, **options): + return self._represent_NumberOp(None, **options) + + def _represent_XOp(self, basis, **options): + # This logic is good but the underlying position + # representation logic is broken. + # temp = self.rewrite('xp').doit() + # result = represent(temp, basis=X) + # return result + raise NotImplementedError('Position representation is not implemented') + + def _represent_NumberOp(self, basis, **options): + ndim_info = options.get('ndim', 4) + format = options.get('format','sympy') + spmatrix = options.get('spmatrix', 'csr') + matrix = matrix_zeros(ndim_info, ndim_info, **options) + for i in range(ndim_info - 1): + value = sqrt(i + 1) + if format == 'scipy.sparse': + value = float(value) + matrix[i + 1, i] = value + if format == 'scipy.sparse': + matrix = matrix.tocsr() + return matrix + + #-------------------------------------------------------------------------- + # Printing Methods + #-------------------------------------------------------------------------- + + def _print_contents(self, printer, *args): + arg0 = printer._print(self.args[0], *args) + return '%s(%s)' % (self.__class__.__name__, arg0) + + def _print_contents_pretty(self, printer, *args): + from sympy.printing.pretty.stringpict import prettyForm + pform = printer._print(self.args[0], *args) + pform = pform**prettyForm('\u2020') + return pform + + def _print_contents_latex(self, printer, *args): + arg = printer._print(self.args[0]) + return '%s^{\\dag}' % arg + +class LoweringOp(SHOOp): + """The Lowering Operator or 'a'. + + When 'a' acts on a state it lowers the state up by one. Taking + the adjoint of 'a' returns a^dagger, the Raising Operator. 'a' + can be rewritten in terms of position and momentum. We can + represent 'a' as a matrix, which will be its default basis. + + Parameters + ========== + + args : tuple + The list of numbers or parameters that uniquely specify the + operator. + + Examples + ======== + + Create a Lowering Operator and rewrite it in terms of position and + momentum, and show that taking its adjoint returns a^dagger: + + >>> from sympy.physics.quantum.sho1d import LoweringOp + >>> from sympy.physics.quantum import Dagger + + >>> a = LoweringOp('a') + >>> a.rewrite('xp').doit() + sqrt(2)*(m*omega*X + I*Px)/(2*sqrt(hbar)*sqrt(m*omega)) + + >>> Dagger(a) + RaisingOp(a) + + Taking the commutator of 'a' with other Operators: + + >>> from sympy.physics.quantum import Commutator + >>> from sympy.physics.quantum.sho1d import LoweringOp, RaisingOp + >>> from sympy.physics.quantum.sho1d import NumberOp + + >>> a = LoweringOp('a') + >>> ad = RaisingOp('a') + >>> N = NumberOp('N') + >>> Commutator(a, ad).doit() + 1 + >>> Commutator(a, N).doit() + a + + Apply 'a' to a state: + + >>> from sympy.physics.quantum import qapply + >>> from sympy.physics.quantum.sho1d import LoweringOp, SHOKet + + >>> a = LoweringOp('a') + >>> k = SHOKet('k') + >>> qapply(a*k) + sqrt(k)*|k - 1> + + Taking 'a' of the lowest state will return 0: + + >>> from sympy.physics.quantum import qapply + >>> from sympy.physics.quantum.sho1d import LoweringOp, SHOKet + + >>> a = LoweringOp('a') + >>> k = SHOKet(0) + >>> qapply(a*k) + 0 + + Matrix Representation + + >>> from sympy.physics.quantum.sho1d import LoweringOp + >>> from sympy.physics.quantum.represent import represent + >>> a = LoweringOp('a') + >>> represent(a, basis=N, ndim=4, format='sympy') + Matrix([ + [0, 1, 0, 0], + [0, 0, sqrt(2), 0], + [0, 0, 0, sqrt(3)], + [0, 0, 0, 0]]) + + """ + + def _eval_rewrite_as_xp(self, *args): + return (Integer(1)/sqrt(Integer(2)*hbar*m*omega))*( + I*Px + m*omega*X) + + def _eval_adjoint(self): + return RaisingOp(*self.args) + + def _eval_commutator_RaisingOp(self, other): + return Integer(1) + + def _eval_commutator_NumberOp(self, other): + return Integer(1)*self + + def _apply_operator_SHOKet(self, ket): + temp = ket.n - Integer(1) + if ket.n == Integer(0): + return Integer(0) + else: + return sqrt(ket.n)*SHOKet(temp) + + def _represent_default_basis(self, **options): + return self._represent_NumberOp(None, **options) + + def _represent_XOp(self, basis, **options): + # This logic is good but the underlying position + # representation logic is broken. + # temp = self.rewrite('xp').doit() + # result = represent(temp, basis=X) + # return result + raise NotImplementedError('Position representation is not implemented') + + def _represent_NumberOp(self, basis, **options): + ndim_info = options.get('ndim', 4) + format = options.get('format', 'sympy') + spmatrix = options.get('spmatrix', 'csr') + matrix = matrix_zeros(ndim_info, ndim_info, **options) + for i in range(ndim_info - 1): + value = sqrt(i + 1) + if format == 'scipy.sparse': + value = float(value) + matrix[i,i + 1] = value + if format == 'scipy.sparse': + matrix = matrix.tocsr() + return matrix + + +class NumberOp(SHOOp): + """The Number Operator is simply a^dagger*a + + It is often useful to write a^dagger*a as simply the Number Operator + because the Number Operator commutes with the Hamiltonian. And can be + expressed using the Number Operator. Also the Number Operator can be + applied to states. We can represent the Number Operator as a matrix, + which will be its default basis. + + Parameters + ========== + + args : tuple + The list of numbers or parameters that uniquely specify the + operator. + + Examples + ======== + + Create a Number Operator and rewrite it in terms of the ladder + operators, position and momentum operators, and Hamiltonian: + + >>> from sympy.physics.quantum.sho1d import NumberOp + + >>> N = NumberOp('N') + >>> N.rewrite('a').doit() + RaisingOp(a)*a + >>> N.rewrite('xp').doit() + -1/2 + (m**2*omega**2*X**2 + Px**2)/(2*hbar*m*omega) + >>> N.rewrite('H').doit() + -1/2 + H/(hbar*omega) + + Take the Commutator of the Number Operator with other Operators: + + >>> from sympy.physics.quantum import Commutator + >>> from sympy.physics.quantum.sho1d import NumberOp, Hamiltonian + >>> from sympy.physics.quantum.sho1d import RaisingOp, LoweringOp + + >>> N = NumberOp('N') + >>> H = Hamiltonian('H') + >>> ad = RaisingOp('a') + >>> a = LoweringOp('a') + >>> Commutator(N,H).doit() + 0 + >>> Commutator(N,ad).doit() + RaisingOp(a) + >>> Commutator(N,a).doit() + -a + + Apply the Number Operator to a state: + + >>> from sympy.physics.quantum import qapply + >>> from sympy.physics.quantum.sho1d import NumberOp, SHOKet + + >>> N = NumberOp('N') + >>> k = SHOKet('k') + >>> qapply(N*k) + k*|k> + + Matrix Representation + + >>> from sympy.physics.quantum.sho1d import NumberOp + >>> from sympy.physics.quantum.represent import represent + >>> N = NumberOp('N') + >>> represent(N, basis=N, ndim=4, format='sympy') + Matrix([ + [0, 0, 0, 0], + [0, 1, 0, 0], + [0, 0, 2, 0], + [0, 0, 0, 3]]) + + """ + + def _eval_rewrite_as_a(self, *args): + return ad*a + + def _eval_rewrite_as_xp(self, *args): + return (Integer(1)/(Integer(2)*m*hbar*omega))*(Px**2 + ( + m*omega*X)**2) - Integer(1)/Integer(2) + + def _eval_rewrite_as_H(self, *args): + return H/(hbar*omega) - Integer(1)/Integer(2) + + def _apply_operator_SHOKet(self, ket): + return ket.n*ket + + def _eval_commutator_Hamiltonian(self, other): + return Integer(0) + + def _eval_commutator_RaisingOp(self, other): + return other + + def _eval_commutator_LoweringOp(self, other): + return Integer(-1)*other + + def _represent_default_basis(self, **options): + return self._represent_NumberOp(None, **options) + + def _represent_XOp(self, basis, **options): + # This logic is good but the underlying position + # representation logic is broken. + # temp = self.rewrite('xp').doit() + # result = represent(temp, basis=X) + # return result + raise NotImplementedError('Position representation is not implemented') + + def _represent_NumberOp(self, basis, **options): + ndim_info = options.get('ndim', 4) + format = options.get('format', 'sympy') + spmatrix = options.get('spmatrix', 'csr') + matrix = matrix_zeros(ndim_info, ndim_info, **options) + for i in range(ndim_info): + value = i + if format == 'scipy.sparse': + value = float(value) + matrix[i,i] = value + if format == 'scipy.sparse': + matrix = matrix.tocsr() + return matrix + + +class Hamiltonian(SHOOp): + """The Hamiltonian Operator. + + The Hamiltonian is used to solve the time-independent Schrodinger + equation. The Hamiltonian can be expressed using the ladder operators, + as well as by position and momentum. We can represent the Hamiltonian + Operator as a matrix, which will be its default basis. + + Parameters + ========== + + args : tuple + The list of numbers or parameters that uniquely specify the + operator. + + Examples + ======== + + Create a Hamiltonian Operator and rewrite it in terms of the ladder + operators, position and momentum, and the Number Operator: + + >>> from sympy.physics.quantum.sho1d import Hamiltonian + + >>> H = Hamiltonian('H') + >>> H.rewrite('a').doit() + hbar*omega*(1/2 + RaisingOp(a)*a) + >>> H.rewrite('xp').doit() + (m**2*omega**2*X**2 + Px**2)/(2*m) + >>> H.rewrite('N').doit() + hbar*omega*(1/2 + N) + + Take the Commutator of the Hamiltonian and the Number Operator: + + >>> from sympy.physics.quantum import Commutator + >>> from sympy.physics.quantum.sho1d import Hamiltonian, NumberOp + + >>> H = Hamiltonian('H') + >>> N = NumberOp('N') + >>> Commutator(H,N).doit() + 0 + + Apply the Hamiltonian Operator to a state: + + >>> from sympy.physics.quantum import qapply + >>> from sympy.physics.quantum.sho1d import Hamiltonian, SHOKet + + >>> H = Hamiltonian('H') + >>> k = SHOKet('k') + >>> qapply(H*k) + hbar*k*omega*|k> + hbar*omega*|k>/2 + + Matrix Representation + + >>> from sympy.physics.quantum.sho1d import Hamiltonian + >>> from sympy.physics.quantum.represent import represent + + >>> H = Hamiltonian('H') + >>> represent(H, basis=N, ndim=4, format='sympy') + Matrix([ + [hbar*omega/2, 0, 0, 0], + [ 0, 3*hbar*omega/2, 0, 0], + [ 0, 0, 5*hbar*omega/2, 0], + [ 0, 0, 0, 7*hbar*omega/2]]) + + """ + + def _eval_rewrite_as_a(self, *args): + return hbar*omega*(ad*a + Integer(1)/Integer(2)) + + def _eval_rewrite_as_xp(self, *args): + return (Integer(1)/(Integer(2)*m))*(Px**2 + (m*omega*X)**2) + + def _eval_rewrite_as_N(self, *args): + return hbar*omega*(N + Integer(1)/Integer(2)) + + def _apply_operator_SHOKet(self, ket): + return (hbar*omega*(ket.n + Integer(1)/Integer(2)))*ket + + def _eval_commutator_NumberOp(self, other): + return Integer(0) + + def _represent_default_basis(self, **options): + return self._represent_NumberOp(None, **options) + + def _represent_XOp(self, basis, **options): + # This logic is good but the underlying position + # representation logic is broken. + # temp = self.rewrite('xp').doit() + # result = represent(temp, basis=X) + # return result + raise NotImplementedError('Position representation is not implemented') + + def _represent_NumberOp(self, basis, **options): + ndim_info = options.get('ndim', 4) + format = options.get('format', 'sympy') + spmatrix = options.get('spmatrix', 'csr') + matrix = matrix_zeros(ndim_info, ndim_info, **options) + for i in range(ndim_info): + value = i + Integer(1)/Integer(2) + if format == 'scipy.sparse': + value = float(value) + matrix[i,i] = value + if format == 'scipy.sparse': + matrix = matrix.tocsr() + return hbar*omega*matrix + +#------------------------------------------------------------------------------ + +class SHOState(State): + """State class for SHO states""" + + @classmethod + def _eval_hilbert_space(cls, label): + return ComplexSpace(S.Infinity) + + @property + def n(self): + return self.args[0] + + +class SHOKet(SHOState, Ket): + """1D eigenket. + + Inherits from SHOState and Ket. + + Parameters + ========== + + args : tuple + The list of numbers or parameters that uniquely specify the ket + This is usually its quantum numbers or its symbol. + + Examples + ======== + + Ket's know about their associated bra: + + >>> from sympy.physics.quantum.sho1d import SHOKet + + >>> k = SHOKet('k') + >>> k.dual + >> k.dual_class() + + + Take the Inner Product with a bra: + + >>> from sympy.physics.quantum import InnerProduct + >>> from sympy.physics.quantum.sho1d import SHOKet, SHOBra + + >>> k = SHOKet('k') + >>> b = SHOBra('b') + >>> InnerProduct(b,k).doit() + KroneckerDelta(b, k) + + Vector representation of a numerical state ket: + + >>> from sympy.physics.quantum.sho1d import SHOKet, NumberOp + >>> from sympy.physics.quantum.represent import represent + + >>> k = SHOKet(3) + >>> N = NumberOp('N') + >>> represent(k, basis=N, ndim=4) + Matrix([ + [0], + [0], + [0], + [1]]) + + """ + + @classmethod + def dual_class(self): + return SHOBra + + def _eval_innerproduct_SHOBra(self, bra, **hints): + result = KroneckerDelta(self.n, bra.n) + return result + + def _represent_default_basis(self, **options): + return self._represent_NumberOp(None, **options) + + def _represent_NumberOp(self, basis, **options): + ndim_info = options.get('ndim', 4) + format = options.get('format', 'sympy') + options['spmatrix'] = 'lil' + vector = matrix_zeros(ndim_info, 1, **options) + if isinstance(self.n, Integer): + if self.n >= ndim_info: + return ValueError("N-Dimension too small") + value = Integer(1) + if format == 'scipy.sparse': + vector[int(self.n), 0] = 1.0 + vector = vector.tocsr() + elif format == 'numpy': + vector[int(self.n), 0] = 1.0 + else: + vector[self.n, 0] = Integer(1) + return vector + else: + return ValueError("Not Numerical State") + + +class SHOBra(SHOState, Bra): + """A time-independent Bra in SHO. + + Inherits from SHOState and Bra. + + Parameters + ========== + + args : tuple + The list of numbers or parameters that uniquely specify the ket + This is usually its quantum numbers or its symbol. + + Examples + ======== + + Bra's know about their associated ket: + + >>> from sympy.physics.quantum.sho1d import SHOBra + + >>> b = SHOBra('b') + >>> b.dual + |b> + >>> b.dual_class() + + + Vector representation of a numerical state bra: + + >>> from sympy.physics.quantum.sho1d import SHOBra, NumberOp + >>> from sympy.physics.quantum.represent import represent + + >>> b = SHOBra(3) + >>> N = NumberOp('N') + >>> represent(b, basis=N, ndim=4) + Matrix([[0, 0, 0, 1]]) + + """ + + @classmethod + def dual_class(self): + return SHOKet + + def _represent_default_basis(self, **options): + return self._represent_NumberOp(None, **options) + + def _represent_NumberOp(self, basis, **options): + ndim_info = options.get('ndim', 4) + format = options.get('format', 'sympy') + options['spmatrix'] = 'lil' + vector = matrix_zeros(1, ndim_info, **options) + if isinstance(self.n, Integer): + if self.n >= ndim_info: + return ValueError("N-Dimension too small") + if format == 'scipy.sparse': + vector[0, int(self.n)] = 1.0 + vector = vector.tocsr() + elif format == 'numpy': + vector[0, int(self.n)] = 1.0 + else: + vector[0, self.n] = Integer(1) + return vector + else: + return ValueError("Not Numerical State") + + +ad = RaisingOp('a') +a = LoweringOp('a') +H = Hamiltonian('H') +N = NumberOp('N') +omega = Symbol('omega') +m = Symbol('m') diff -Nru python3-sympy-0.7.2/sympy/physics/quantum/shor.py python3-sympy-0.7.3/sympy/physics/quantum/shor.py --- python3-sympy-0.7.2/sympy/physics/quantum/shor.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/physics/quantum/shor.py 2013-07-13 17:53:32.000000000 +0000 @@ -13,6 +13,7 @@ from sympy import Mul, S from sympy import log, sqrt from sympy.core.numbers import igcd +from sympy.utilities.iterables import variations from sympy.physics.quantum.gate import Gate from sympy.physics.quantum.qubit import Qubit, measure_partial_oneshot @@ -65,18 +66,18 @@ k = 0 # Determine the value stored in high memory. for i in range(self.t): - k = k + n*qubits[self.t+i] + k = k + n*qubits[self.t + i] n = n*2 # The value to go in low memory will be out. - out = int(self.a**k%self.N) + out = int(self.a**k % self.N) # Create array for new qbit-ket which will have high memory unaffected outarray = list(qubits.args[0][:self.t]) # Place out in low memory for i in reversed(list(range(self.t))): - outarray.append((out>>i)&1) + outarray.append((out >> i) & 1) return Qubit(*outarray) @@ -91,38 +92,23 @@ be used to calculate factors by taking a**(r/2)-1 and a**(r/2)+1. These values are returned. """ - a = random.randrange(N-2)+2 - if igcd(N,a) != 1: + a = random.randrange(N - 2) + 2 + if igcd(N, a) != 1: print("got lucky with rand") - return igcd(N,a) - print("a= ",a) - print("N= ",N) - r = period_find(a,N) - print("r= ",r) - if r%2 == 1: + return igcd(N, a) + print("a= ", a) + print("N= ", N) + r = period_find(a, N) + print("r= ", r) + if r % 2 == 1: print("r is not even, begin again") shor(N) - answer = (igcd(a**(r/2)-1, N), igcd(a**(r/2)+1, N)) + answer = (igcd(a**(r/2) - 1, N), igcd(a**(r/2) + 1, N)) return answer -def arr(num, t): - """This function returns num as an array in binary - - It does this with the 0th digit being on the right - - >>> from sympy.physics.quantum.shor import arr - >>> arr(5, 4) - [0, 1, 0, 1] - """ - binary_array = [] - for i in reversed(list(range(t))): - binary_array.append((num>>i)&1) - return binary_array - - def getr(x, y, N): - fraction = continued_fraction(x,y) + fraction = continued_fraction(x, y) # Now convert into r total = ratioize(fraction, N) return total @@ -149,9 +135,9 @@ y = int(y) temp = x//y if temp*y == x: - return [temp,] + return [temp, ] - list = continued_fraction(y, x-temp*y) + list = continued_fraction(y, x - temp*y) list.insert(0, temp) return list @@ -166,19 +152,19 @@ """ epsilon = .5 #picks out t's such that maintains accuracy within epsilon - t = int(2*math.ceil(log(N,2))) + t = int(2*math.ceil(log(N, 2))) # make the first half of register be 0's |000...000> start = [0 for x in range(t)] #Put second half into superposition of states so we have |1>x|0> + |2>x|0> + ... |k>x>|0> + ... + |2**n-1>x|0> factor = 1/sqrt(2**t) qubits = 0 - for i in range(2**t): - qbitArray = arr(i, t) + start + for arr in variations(list(range(2)), t, repetition=True): + qbitArray = arr + start qubits = qubits + Qubit(*qbitArray) circuit = (factor*qubits).expand() #Controlled second half of register so that we have: # |1>x|a**1 %N> + |2>x|a**2 %N> + ... + |k>x|a**k %N >+ ... + |2**n-1=k>x|a**k % n> - circuit = CMod(t,a,N)*circuit + circuit = CMod(t, a, N)*circuit #will measure first half of register giving one of the a**k%N's circuit = qapply(circuit) print("controlled Mod'd") @@ -188,10 +174,10 @@ # circuit = qapply(circuit) print("measured 1") #Now apply Inverse Quantum Fourier Transform on the second half of the register - circuit = qapply(QFT(t, t*2).decompose()*circuit, floatingPoint = True) + circuit = qapply(QFT(t, t*2).decompose()*circuit, floatingPoint=True) print("QFT'd") for i in range(t): - circuit = measure_partial_oneshot(circuit, i+t) + circuit = measure_partial_oneshot(circuit, i + t) # circuit = measure(i+t)*circuit # circuit = qapply(circuit) print(circuit) @@ -206,10 +192,11 @@ n = 1 answer = 0 for i in range(len(register)/2): - answer += n*register[i+t] - n = n<<1 + answer += n*register[i + t] + n = n << 1 if answer == 0: - raise OrderFindingException("Order finder returned 0. Happens with chance %f" % epsilon) + raise OrderFindingException( + "Order finder returned 0. Happens with chance %f" % epsilon) #turn answer into r using continued fractions g = getr(answer, 2**t, N) print(g) diff -Nru python3-sympy-0.7.2/sympy/physics/quantum/spin.py python3-sympy-0.7.3/sympy/physics/quantum/spin.py --- python3-sympy-0.7.2/sympy/physics/quantum/spin.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/physics/quantum/spin.py 2013-07-13 17:53:32.000000000 +0000 @@ -2,8 +2,8 @@ from sympy import (Add, binomial, cos, exp, Expr, factorial, I, Integer, Mul, pi, Rational, S, sin, simplify, sqrt, Sum, symbols, sympify, - Tuple) -from sympy.matrices.matrices import zeros + Tuple, Dummy) +from sympy.matrices import zeros from sympy.printing.pretty.stringpict import prettyForm, stringPict from sympy.printing.pretty.pretty_symbology import pretty_symbol @@ -53,7 +53,7 @@ raise ValueError( 'Only integer or half-integer values allowed for j, got: : %r' % j ) - return size, [j-i for i in range(int(2*j+1))] + return size, [j - i for i in range(int(2*j + 1))] #----------------------------------------------------------------------------- @@ -85,7 +85,7 @@ return r'%s_%s' % ((str(self.name), self._coord)) def _represent_base(self, basis, **options): - j = options.get('j', Rational(1,2)) + j = options.get('j', Rational(1, 2)) size, mvals = m_values(j) result = zeros(size, size) for p in range(size): @@ -136,7 +136,7 @@ arg = [] arg.extend(tp.args[:n]) arg.append(self._apply_operator(tp.args[n])) - arg.extend(tp.args[n+1:]) + arg.extend(tp.args[n + 1:]) result.append(tp.__class__(*arg)) return Add(*result).expand() @@ -156,7 +156,6 @@ return self._represent_default_basis().trace() - class JplusOp(SpinOpBase, Operator): """The J+ operator.""" @@ -173,7 +172,7 @@ if m.is_Number and j.is_Number: if m >= j: return S.Zero - return hbar*sqrt(j*(j+S.One)-m*(m+S.One))*JzKet(j, m+S.One) + return hbar*sqrt(j*(j + S.One) - m*(m + S.One))*JzKet(j, m + S.One) def _apply_operator_JzKetCoupled(self, ket, **options): j = ket.j @@ -183,11 +182,11 @@ if m.is_Number and j.is_Number: if m >= j: return S.Zero - return hbar*sqrt(j*(j+S.One)-m*(m+S.One))*JzKetCoupled(j, m+S.One,jn,coupling) + return hbar*sqrt(j*(j + S.One) - m*(m + S.One))*JzKetCoupled(j, m + S.One, jn, coupling) def matrix_element(self, j, m, jp, mp): - result = hbar*sqrt(j*(j+S.One)-mp*(mp+S.One)) - result *= KroneckerDelta(m, mp+1) + result = hbar*sqrt(j*(j + S.One) - mp*(mp + S.One)) + result *= KroneckerDelta(m, mp + 1) result *= KroneckerDelta(j, jp) return result @@ -214,7 +213,7 @@ if m.is_Number and j.is_Number: if m <= -j: return S.Zero - return hbar*sqrt(j*(j+S.One)-m*(m-S.One))*JzKet(j, m-S.One) + return hbar*sqrt(j*(j + S.One) - m*(m - S.One))*JzKet(j, m - S.One) def _apply_operator_JzKetCoupled(self, ket, **options): j = ket.j @@ -224,11 +223,11 @@ if m.is_Number and j.is_Number: if m <= -j: return S.Zero - return hbar*sqrt(j*(j+S.One)-m*(m-S.One))*JzKetCoupled(j, m-S.One,jn,coupling) + return hbar*sqrt(j*(j + S.One) - m*(m - S.One))*JzKetCoupled(j, m - S.One, jn, coupling) def matrix_element(self, j, m, jp, mp): - result = hbar*sqrt(j*(j+S.One)-mp*(mp-S.One)) - result *= KroneckerDelta(m, mp-1) + result = hbar*sqrt(j*(j + S.One) - mp*(mp - S.One)) + result *= KroneckerDelta(m, mp - 1) result *= KroneckerDelta(j, jp) return result @@ -366,30 +365,30 @@ def _apply_operator_JxKet(self, ket, **options): j = ket.j - return hbar**2*j*(j+1)*ket + return hbar**2*j*(j + 1)*ket def _apply_operator_JxKetCoupled(self, ket, **options): j = ket.j - return hbar**2*j*(j+1)*ket + return hbar**2*j*(j + 1)*ket def _apply_operator_JyKet(self, ket, **options): j = ket.j - return hbar**2*j*(j+1)*ket + return hbar**2*j*(j + 1)*ket def _apply_operator_JyKetCoupled(self, ket, **options): j = ket.j - return hbar**2*j*(j+1)*ket + return hbar**2*j*(j + 1)*ket def _apply_operator_JzKet(self, ket, **options): j = ket.j - return hbar**2*j*(j+1)*ket + return hbar**2*j*(j + 1)*ket def _apply_operator_JzKetCoupled(self, ket, **options): j = ket.j - return hbar**2*j*(j+1)*ket + return hbar**2*j*(j + 1)*ket def matrix_element(self, j, m, jp, mp): - result = (hbar**2)*j*(j+1) + result = (hbar**2)*j*(j + 1) result *= KroneckerDelta(m, mp) result *= KroneckerDelta(j, jp) return result @@ -413,8 +412,8 @@ def _eval_rewrite_as_plusminus(self, *args): a = args[0] - return JzOp(a)**2 +\ - Rational(1,2)*(JplusOp(a)*JminusOp(a) + JminusOp(a)*JplusOp(a)) + return JzOp(a)**2 + \ + Rational(1, 2)*(JplusOp(a)*JminusOp(a) + JminusOp(a)*JplusOp(a)) class Rotation(UnitaryOperator): @@ -549,7 +548,7 @@ WignerD: Symbolic Wigner-D function """ - return WignerD(j,m,mp,alpha,beta,gamma) + return WignerD(j, m, mp, alpha, beta, gamma) @classmethod def d(cls, j, m, mp, beta): @@ -589,17 +588,17 @@ WignerD: Symbolic Wigner-D function """ - return WignerD(j,m,mp,0,beta,0) + return WignerD(j, m, mp, 0, beta, 0) def matrix_element(self, j, m, jp, mp): result = self.__class__.D( jp, m, mp, self.alpha, self.beta, self.gamma ) - result *= KroneckerDelta(j,jp) + result *= KroneckerDelta(j, jp) return result def _represent_base(self, basis, **options): - j = sympify(options.get('j', Rational(1,2))) + j = sympify(options.get('j', Rational(1, 2))) # TODO: move evaluation up to represent function/implement elsewhere evaluate = sympify(options.get('doit')) size, mvals = m_values(j) @@ -619,6 +618,70 @@ def _represent_JzOp(self, basis, **options): return self._represent_base(basis, **options) + def _apply_operator_uncoupled(self, state, ket, **options): + a = self.alpha + b = self.beta + g = self.gamma + j = ket.j + m = ket.m + if j.is_number: + s = [] + size = m_values(j) + sz = size[1] + for mp in sz: + r = Rotation.D(j, m, mp, a, b, g) + z = r.doit() + s.append(z * state(j, mp)) + return Add(*s) + else: + if options.pop('dummy', True): + mp = Dummy('mp') + else: + mp = symbols('mp') + return Sum(Rotation.D(j, m, mp, a, b, g) * state(j, mp), (mp, -j, j)) + + def _apply_operator_JxKet(self, ket, **options): + return self._apply_operator_uncoupled(JxKet, ket, **options) + + def _apply_operator_JyKet(self, ket, **options): + return self._apply_operator_uncoupled(JyKet, ket, **options) + + def _apply_operator_JzKet(self, ket, **options): + return self._apply_operator_uncoupled(JzKet, ket, **options) + + def _apply_operator_coupled(self, state, ket, **options): + a = self.alpha + b = self.beta + g = self.gamma + j = ket.j + m = ket.m + jn = ket.jn + coupling = ket.coupling + if j.is_number: + s = [] + size = m_values(j) + sz = size[1] + for mp in sz: + r = Rotation.D(j, m, mp, a, b, g) + z = r.doit() + s.append(z * state(j, mp, jn, coupling)) + return Add(*s) + else: + if options.pop('dummy', True): + mp = Dummy('mp') + else: + mp = symbols('mp') + return Sum(Rotation.D(j, m, mp, a, b, g) * state( + j, mp, jn, coupling), (mp, -j, j)) + + def _apply_operator_JxKetCoupled(self, ket, **options): + return self._apply_operator_coupled(JxKetCoupled, ket, **options) + + def _apply_operator_JyKetCoupled(self, ket, **options): + return self._apply_operator_coupled(JyKetCoupled, ket, **options) + + def _apply_operator_JzKetCoupled(self, ket, **options): + return self._apply_operator_coupled(JzKetCoupled, ket, **options) class WignerD(Expr): """Wigner-D function @@ -738,11 +801,15 @@ def _latex(self, printer, *args): if self.alpha == 0 and self.gamma == 0: return r'd^{%s}_{%s,%s}\left(%s\right)' % \ - ( printer._print(self.j), printer._print(self.m), printer._print(self.mp), - printer._print(self.beta) ) + ( + printer._print(self.j), printer._print( + self.m), printer._print(self.mp), + printer._print(self.beta) ) return r'D^{%s}_{%s,%s}\left(%s,%s,%s\right)' % \ - ( printer._print(self.j), printer._print(self.m), printer._print(self.mp), - printer._print(self.alpha), printer._print(self.beta), printer._print(self.gamma) ) + ( + printer._print( + self.j), printer._print(self.m), printer._print(self.mp), + printer._print(self.alpha), printer._print(self.beta), printer._print(self.gamma) ) def _pretty(self, printer, *args): top = printer._print(self.j) @@ -755,9 +822,9 @@ top = prettyForm(*top.left(' ')) bot = prettyForm(*bot.left(' ')) if pad > top.width(): - top = prettyForm(*top.right(' ' * (pad-top.width()))) + top = prettyForm(*top.right(' ' * (pad - top.width()))) if pad > bot.width(): - bot = prettyForm(*bot.right(' ' * (pad-bot.width()))) + bot = prettyForm(*bot.right(' ' * (pad - bot.width()))) if self.alpha == 0 and self.gamma == 0: args = printer._print(self.beta) s = stringPict('d' + ' '*pad) @@ -788,17 +855,18 @@ beta = sympify(self.beta) gamma = sympify(self.gamma) if not j.is_number: - raise ValueError("j parameter must be numerical to evaluate, got %s", j) + raise ValueError( + 'j parameter must be numerical to evaluate, got %s' % j) r = 0 if beta == pi/2: # Varshalovich Equation (5), Section 4.16, page 113, setting # alpha=gamma=0. - for k in range(2*j+1): - if k > j+mp or k > j-m or k < mp-m: + for k in range(2*j + 1): + if k > j + mp or k > j - m or k < mp - m: continue - r += (-S(1))**k * binomial(j+mp, k) * binomial(j-mp, k+m-mp) - r *= (-S(1))**(m-mp) / 2**j * sqrt(factorial(j+m) * \ - factorial(j-m) / (factorial(j+mp) * factorial(j-mp))) + r += (-S(1))**k * binomial(j + mp, k) * binomial(j - mp, k + m - mp) + r *= (-S(1))**(m - mp) / 2**j * sqrt(factorial(j + m) * + factorial(j - m) / (factorial(j + mp) * factorial(j - mp))) else: # Varshalovich Equation(5), Section 4.7.2, page 87, where we set # beta1=beta2=pi/2, and we get alpha=gamma=pi/2 and beta=phi+pi, @@ -808,13 +876,13 @@ # except that we need to substitute -mp for mp. size, mvals = m_values(j) for mpp in mvals: - r += Rotation.d(j, m, mpp, pi/2).doit() * (cos(-mpp*beta)+I*sin(-mpp*beta)) * \ + r += Rotation.d(j, m, mpp, pi/2).doit() * (cos(-mpp*beta) + I*sin(-mpp*beta)) * \ Rotation.d(j, mpp, -mp, pi/2).doit() # Empirical normalization factor so results match Varshalovich # Tables 4.3-4.12 # Note that this exact normalization does not follow from the # above equations - r = r * I**(2*j-m-mp) * (-1)**(2*m) + r = r * I**(2*j - m - mp) * (-1)**(2*m) # Finally, simplify the whole expression r = simplify(r) r *= exp(-I*m*alpha)*exp(-I*mp*gamma) @@ -844,16 +912,18 @@ m = sympify(m) if j.is_number: if 2*j != int(2*j): - raise ValueError('j must be integer or half-integer, got: %s' % j) + raise ValueError( + 'j must be integer or half-integer, got: %s' % j) if j < 0: raise ValueError('j must be >= 0, got: %s' % j) if m.is_number: if 2*m != int(2*m): - raise ValueError('m must be integer or half-integer, got: %s' % m) + raise ValueError( + 'm must be integer or half-integer, got: %s' % m) if j.is_number and m.is_number: if abs(m) > j: raise ValueError('Allowed values for m are -j <= m <= j, got j, m: %s, %s' % (j, m)) - if int(j-m) != j-m: + if int(j - m) != j - m: raise ValueError('Both j and m must be integer or half-integer, got j, m: %s, %s' % (j, m)) return State.__new__(cls, j, m) @@ -867,7 +937,7 @@ @classmethod def _eval_hilbert_space(cls, label): - return ComplexSpace(2*label[0]+1) + return ComplexSpace(2*label[0] + 1) def _represent_base(self, **options): j = self.j @@ -881,9 +951,11 @@ # breaks finding angles on L930 for p, mval in enumerate(mvals): if m.is_number: - result[p,0] = Rotation.D(self.j, mval, self.m, alpha, beta, gamma).doit() + result[p, 0] = Rotation.D( + self.j, mval, self.m, alpha, beta, gamma).doit() else: - result[p,0] = Rotation.D(self.j, mval, self.m, alpha, beta, gamma) + result[p, 0] = Rotation.D(self.j, mval, + self.m, alpha, beta, gamma) return result def _eval_rewrite_as_Jx(self, *args, **options): @@ -910,11 +982,12 @@ if j == int(j): start = j**2 else: - start = (2*j-1)*(2*j+1)/4 + start = (2*j - 1)*(2*j + 1)/4 else: start = 0 vect = represent(self, basis=basis, **options) - result = Add(*[vect[start+i] * evect(j,j-i,*args) for i in range(2*j+1)]) + result = Add( + *[vect[start + i] * evect(j, j - i, *args) for i in range(2*j + 1)]) if isinstance(self, CoupledSpinState) and options.get('coupled') is False: return uncouple(result) return result @@ -922,48 +995,53 @@ i = 0 mi = symbols('mi') # make sure not to introduce a symbol already in the state - while self.subs(mi,0) != self: + while self.subs(mi, 0) != self: i += 1 mi = symbols('mi%d' % i) break # TODO: better way to get angles of rotation if isinstance(self, CoupledSpinState): - test_args = (0,mi,(0,0)) + test_args = (0, mi, (0, 0)) else: - test_args = (0,mi) + test_args = (0, mi) if isinstance(self, Ket): - angles = represent(self.__class__(*test_args),basis=basis)[0].args[3:6] + angles = represent( + self.__class__(*test_args), basis=basis)[0].args[3:6] else: - angles = represent(self.__class__(*test_args),basis=basis)[0].args[0].args[3:6] - if angles == (0,0,0): + angles = represent(self.__class__( + *test_args), basis=basis)[0].args[0].args[3:6] + if angles == (0, 0, 0): return self else: state = evect(j, mi, *args) lt = Rotation.D(j, mi, self.m, *angles) - return Sum(lt * state, (mi,-j,j)) + return Sum(lt * state, (mi, -j, j)) def _eval_innerproduct_JxBra(self, bra, **hints): result = KroneckerDelta(self.j, bra.j) if bra.dual_class() is not self.__class__: - result *= self._represent_JxOp(None)[bra.j-bra.m] + result *= self._represent_JxOp(None)[bra.j - bra.m] else: - result *= KroneckerDelta(self.j, bra.j) * KroneckerDelta(self.m, bra.m) + result *= KroneckerDelta( + self.j, bra.j) * KroneckerDelta(self.m, bra.m) return result def _eval_innerproduct_JyBra(self, bra, **hints): result = KroneckerDelta(self.j, bra.j) if bra.dual_class() is not self.__class__: - result *= self._represent_JyOp(None)[bra.j-bra.m] + result *= self._represent_JyOp(None)[bra.j - bra.m] else: - result *= KroneckerDelta(self.j, bra.j) * KroneckerDelta(self.m, bra.m) + result *= KroneckerDelta( + self.j, bra.j) * KroneckerDelta(self.m, bra.m) return result def _eval_innerproduct_JzBra(self, bra, **hints): result = KroneckerDelta(self.j, bra.j) if bra.dual_class() is not self.__class__: - result *= self._represent_JzOp(None)[bra.j-bra.m] + result *= self._represent_JzOp(None)[bra.j - bra.m] else: - result *= KroneckerDelta(self.j, bra.j) * KroneckerDelta(self.m, bra.m) + result *= KroneckerDelta( + self.j, bra.j) * KroneckerDelta(self.m, bra.m) return result def _eval_trace(self, bra, **hints): @@ -981,6 +1059,7 @@ return (bra*self).doit() + class JxKet(SpinState, Ket): """Eigenket of Jx. @@ -1013,6 +1092,7 @@ def _represent_JzOp(self, basis, **options): return self._represent_base(beta=pi/2, **options) + class JxBra(SpinState, Bra): """Eigenbra of Jx. @@ -1064,7 +1144,7 @@ return self._represent_base(**options) def _represent_JzOp(self, basis, **options): - return self._represent_base(alpha=3*pi/2,beta=-pi/2,gamma=pi/2, **options) + return self._represent_base(alpha=3*pi/2, beta=-pi/2, gamma=pi/2, **options) class JyBra(SpinState, Bra): @@ -1130,9 +1210,10 @@ >>> from sympy.physics.quantum.represent import represent >>> from sympy.physics.quantum.spin import Jx, Jz >>> represent(JzKet(1,-1), basis=Jx) - [ 1/2] - [sqrt(2)/2] - [ 1/2] + Matrix([ + [ 1/2], + [sqrt(2)/2], + [ 1/2]]) Apply innerproducts between states: @@ -1166,25 +1247,27 @@ tensor product of the vector representation of the component eigenstates: >>> represent(TensorProduct(JzKet(1,0),JzKet(1,1))) - [0] - [0] - [0] - [1] - [0] - [0] - [0] - [0] - [0] + Matrix([ + [0], + [0], + [0], + [1], + [0], + [0], + [0], + [0], + [0]]) >>> represent(TensorProduct(JzKet(1,1),JxKet(1,1)), basis=Jz) - [ 1/2] - [sqrt(2)/2] - [ 1/2] - [ 0] - [ 0] - [ 0] - [ 0] - [ 0] - [ 0] + Matrix([ + [ 1/2], + [sqrt(2)/2], + [ 1/2], + [ 0], + [ 0], + [ 0], + [ 0], + [ 0], + [ 0]]) See Also ======== @@ -1211,7 +1294,7 @@ return self._represent_base(beta=3*pi/2, **options) def _represent_JyOp(self, basis, **options): - return self._represent_base(alpha=3*pi/2,beta=pi/2,gamma=pi/2, **options) + return self._represent_base(alpha=3*pi/2, beta=pi/2, gamma=pi/2, **options) def _represent_JzOp(self, basis, **options): return self._represent_base(**options) @@ -1243,14 +1326,14 @@ # This same method is also used by the uncouple method, and is separated from # the CoupledSpinState class to maintain consistency in defining coupling def _build_coupled(jcoupling, length): - n_list = [ [n+1] for n in range(length) ] + n_list = [ [n + 1] for n in range(length) ] coupled_jn = [] coupled_n = [] - for n1,n2,j_new in jcoupling: + for n1, n2, j_new in jcoupling: coupled_jn.append(j_new) - coupled_n.append( (n_list[n1-1], n_list[n2-1]) ) - n_sort = sorted(n_list[n1-1]+n_list[n2-1]) - n_list[n_sort[0]-1] = n_sort + coupled_n.append( (n_list[n1 - 1], n_list[n2 - 1]) ) + n_sort = sorted(n_list[n1 - 1] + n_list[n2 - 1]) + n_list[n_sort[0] - 1] = n_sort return coupled_n, coupled_jn @@ -1264,30 +1347,35 @@ if len(jcoupling) == 0: # Use default coupling scheme jcoupling = [] - for n in range(2,len(jn)): - jcoupling.append( (1,n,Add(*[jn[i] for i in range(n)])) ) - jcoupling.append( (1,len(jn),j) ) + for n in range(2, len(jn)): + jcoupling.append( (1, n, Add(*[jn[i] for i in range(n)])) ) + jcoupling.append( (1, len(jn), j) ) elif len(jcoupling) == 1: # Use specified coupling scheme jcoupling = jcoupling[0] else: - raise TypeError("CoupledSpinState only takes 3 or 4 arguments, got: %s" % (len(jcoupling)+3) ) + raise TypeError("CoupledSpinState only takes 3 or 4 arguments, got: %s" % (len(jcoupling) + 3) ) # Check arguments have correct form if not (isinstance(jn, list) or isinstance(jn, tuple) or isinstance(jn, Tuple)): - raise TypeError('jn must be Tuple, list or tuple, got %s' % jn.__class__.__name__) + raise TypeError('jn must be Tuple, list or tuple, got %s' % + jn.__class__.__name__) if not (isinstance(jcoupling, list) or isinstance(jcoupling, tuple) or isinstance(jcoupling, Tuple)): - raise TypeError('jcoupling must be Tuple, list or tuple, got %s' % jcoupling.__class__.__name__) + raise TypeError('jcoupling must be Tuple, list or tuple, got %s' % + jcoupling.__class__.__name__) if not all(isinstance(term, list) or isinstance(term, tuple) or isinstance(term, Tuple) for term in jcoupling): - raise TypeError('All elements of jcoupling must be list, tuple or Tuple') - if not len(jn)-1 == len(jcoupling): - raise ValueError('jcoupling must have length of %d, got %d' % (len(jn)-1, len(jcoupling))) + raise TypeError( + 'All elements of jcoupling must be list, tuple or Tuple') + if not len(jn) - 1 == len(jcoupling): + raise ValueError('jcoupling must have length of %d, got %d' % + (len(jn) - 1, len(jcoupling))) if not all(len(x) == 3 for x in jcoupling): raise ValueError('All elements of jcoupling must have length 3') # Build sympified args j = sympify(j) m = sympify(m) jn = Tuple( *[sympify(ji) for ji in jn] ) - jcoupling = Tuple( *[Tuple(sympify(n1), sympify(n2), sympify(ji)) for (n1, n2, ji) in jcoupling] ) + jcoupling = Tuple( *[Tuple(sympify( + n1), sympify(n2), sympify(ji)) for (n1, n2, ji) in jcoupling] ) # Check values in coupling scheme give physical state if any(2*ji != int(2*ji) for ji in jn if ji.is_number): raise ValueError('All elements of jn must be integer or half-integer, got: %s' % jn) @@ -1299,20 +1387,20 @@ raise ValueError('All coupled j values in coupling scheme must be integer or half-integer') coupled_n, coupled_jn = _build_coupled(jcoupling, len(jn)) jvals = list(jn) - for n, (n1,n2) in enumerate(coupled_n): - j1 = jvals[min(n1)-1] - j2 = jvals[min(n2)-1] + for n, (n1, n2) in enumerate(coupled_n): + j1 = jvals[min(n1) - 1] + j2 = jvals[min(n2) - 1] j3 = coupled_jn[n] if sympify(j1).is_number and sympify(j2).is_number and sympify(j3).is_number: - if j1+j2 < j3: - raise ValueError('All couplings must have j1+j2 >= j3, '\ - 'in coupling number %d got j1,j2,j3: %d,%d,%d' % (n+1, j1, j2, j3)) - if abs(j1-j2) > j3: - raise ValueError("All couplings must have |j1+j2| <= j3, "\ - "in coupling number %d got j1,j2,j3: %d,%d,%d" % (n+1, j1, j2, j3)) - if int(j1+j2) == j1+j2: + if j1 + j2 < j3: + raise ValueError('All couplings must have j1+j2 >= j3, ' + 'in coupling number %d got j1,j2,j3: %d,%d,%d' % (n + 1, j1, j2, j3)) + if abs(j1 - j2) > j3: + raise ValueError("All couplings must have |j1+j2| <= j3, " + "in coupling number %d got j1,j2,j3: %d,%d,%d" % (n + 1, j1, j2, j3)) + if int(j1 + j2) == j1 + j2: pass - jvals[min(n1+n2)-1] = j3 + jvals[min(n1 + n2) - 1] = j3 if len(jcoupling) > 0 and jcoupling[-1][2] != j: raise ValueError('Last j value coupled together must be the final j of the state') # Return state @@ -1325,11 +1413,11 @@ # label.append('j%d=%s' % (i, ji) ) for i, ji in enumerate(self.jn): label.append('j%d=%s' % ( - i+1, printer._print(ji) + i + 1, printer._print(ji) )) - for jn, (n1,n2) in zip(self.coupled_jn[:-1], self.coupled_n[:-1]): + for jn, (n1, n2) in zip(self.coupled_jn[:-1], self.coupled_n[:-1]): label.append('j(%s)=%s' % ( - ','.join(str(i) for i in sorted(n1+n2)), printer._print(jn) + ','.join(str(i) for i in sorted(n1 + n2)), printer._print(jn) )) return ','.join(label) @@ -1339,13 +1427,13 @@ #for i, ji in enumerate(self.jn, start=1): # n = '%d' % (i) for i, ji in enumerate(self.jn): - symb = 'j%d' % (i+1) + symb = 'j%d' % (i + 1) symb = pretty_symbol(symb) symb = prettyForm(symb + '=') item = prettyForm(*symb.right(printer._print(ji))) label.append(item) - for jn, (n1,n2) in zip(self.coupled_jn[:-1], self.coupled_n[:-1]): - n = ','.join(pretty_symbol("j%d" % i)[-1] for i in sorted(n1+n2)) + for jn, (n1, n2) in zip(self.coupled_jn[:-1], self.coupled_n[:-1]): + n = ','.join(pretty_symbol("j%d" % i)[-1] for i in sorted(n1 + n2)) symb = prettyForm('j' + n + '=') item = prettyForm(*symb.right(printer._print(jn))) label.append(item) @@ -1359,9 +1447,9 @@ #for i, ji in enumerate(self.jn, start=1): # label.append('j_{%d}=%s' % (i, printer._print(ji)) ) for i, ji in enumerate(self.jn): - label.append('j_{%d}=%s' % (i+1, printer._print(ji)) ) - for jn, (n1,n2) in zip(self.coupled_jn[:-1], self.coupled_n[:-1]): - n = ','.join(str(i) for i in sorted(n1+n2)) + label.append('j_{%d}=%s' % (i + 1, printer._print(ji)) ) + for jn, (n1, n2) in zip(self.coupled_jn[:-1], self.coupled_n[:-1]): + n = ','.join(str(i) for i in sorted(n1 + n2)) label.append('j_{%s}=%s' % (n, printer._print(jn)) ) return self._print_sequence( label, self._label_separator, printer, *args @@ -1387,27 +1475,30 @@ def _eval_hilbert_space(cls, label): j = Add(*label[2]) if j.is_number: - return DirectSumHilbertSpace(*[ ComplexSpace(x) for x in range(int(2*j+1),0,-2) ]) + return DirectSumHilbertSpace(*[ ComplexSpace(x) for x in range(int(2*j + 1), 0, -2) ]) else: # TODO: Need hilbert space fix, see issue 2633 # Desired behavior: #ji = symbols('ji') #ret = Sum(ComplexSpace(2*ji + 1), (ji, 0, j)) # Temporary fix: - return ComplexSpace(2*j+1) + return ComplexSpace(2*j + 1) def _represent_coupled_base(self, **options): evect = self.uncoupled_class() if not self.j.is_number: - raise ValueError('State must not have symbolic j value to represent') + raise ValueError( + 'State must not have symbolic j value to represent') if not self.hilbert_space.dimension.is_number: - raise ValueError('State must not have symbolic j values to represent') + raise ValueError( + 'State must not have symbolic j values to represent') result = zeros(self.hilbert_space.dimension, 1) if self.j == int(self.j): start = self.j**2 else: - start = (2*self.j-1)*(1+2*self.j)/4 - result[start:start+2*self.j+1,0] = evect(self.j, self.m)._represent_base(**options) + start = (2*self.j - 1)*(1 + 2*self.j)/4 + result[start:start + 2*self.j + 1, 0] = evect( + self.j, self.m)._represent_base(**options) return result def _eval_rewrite_as_Jx(self, *args, **options): @@ -1510,7 +1601,7 @@ return self._represent_coupled_base(**options) def _represent_JzOp(self, basis, **options): - return self._represent_coupled_base(alpha=3*pi/2,beta=-pi/2,gamma=pi/2, **options) + return self._represent_coupled_base(alpha=3*pi/2, beta=-pi/2, gamma=pi/2, **options) class JyBraCoupled(CoupledSpinState, Bra): @@ -1636,10 +1727,11 @@ >>> from sympy.physics.quantum.spin import Jx >>> from sympy import S >>> represent(JzKetCoupled(1,-1,(S(1)/2,S(1)/2)), basis=Jx) - [ 0] - [ 1/2] - [sqrt(2)/2] - [ 1/2] + Matrix([ + [ 0], + [ 1/2], + [sqrt(2)/2], + [ 1/2]]) See Also ======== @@ -1665,7 +1757,7 @@ return self._represent_coupled_base(beta=3*pi/2, **options) def _represent_JyOp(self, basis, **options): - return self._represent_coupled_base(alpha=3*pi/2,beta=pi/2,gamma=pi/2, **options) + return self._represent_coupled_base(alpha=3*pi/2, beta=pi/2, gamma=pi/2, **options) def _represent_JzOp(self, basis, **options): return self._represent_coupled_base(**options) @@ -1695,6 +1787,7 @@ # Coupling/uncoupling #----------------------------------------------------------------------------- + def couple(expr, jcoupling_list=None): """ Couple a tensor product of spin states @@ -1764,6 +1857,7 @@ expr = expr.subs(tp, _couple(tp, jcoupling_list)) return expr + def _couple(tp, jcoupling_list): states = tp.args coupled_evect = states[0].coupled_class() @@ -1772,21 +1866,22 @@ if jcoupling_list is None: jcoupling_list = [] for n in range(1, len(states)): - jcoupling_list.append( (1, n+1) ) + jcoupling_list.append( (1, n + 1) ) # Check jcoupling_list valid - if not len(jcoupling_list) == len(states)-1: - raise TypeError('jcoupling_list must be length %d, got %d' % (len(states)-1,len(jcoupling_list))) + if not len(jcoupling_list) == len(states) - 1: + raise TypeError('jcoupling_list must be length %d, got %d' % + (len(states) - 1, len(jcoupling_list))) if not all( len(coupling) == 2 for coupling in jcoupling_list): raise ValueError('Each coupling must define 2 spaces') if any([n1 == n2 for n1, n2 in jcoupling_list]): raise ValueError('Spin spaces cannot couple to themselves') - if all([sympify(n1).is_number and sympify(n2).is_number for n1,n2 in jcoupling_list]): + if all([sympify(n1).is_number and sympify(n2).is_number for n1, n2 in jcoupling_list]): j_test = [0]*len(states) for n1, n2 in jcoupling_list: - if j_test[n1-1] == -1 or j_test[n2-1] == -1: + if j_test[n1 - 1] == -1 or j_test[n2 - 1] == -1: raise ValueError('Spaces coupling j_n\'s are referenced by smallest n value') - j_test[max(n1,n2)-1] = -1 + j_test[max(n1, n2) - 1] = -1 # j values of states to be coupled together jn = [state.j for state in states] @@ -1795,26 +1890,27 @@ # Create coupling_list, which defines all the couplings between all # the spaces from jcoupling_list coupling_list = [] - n_list = [ [i+1] for i in range(len(states)) ] + n_list = [ [i + 1] for i in range(len(states)) ] for j_coupling in jcoupling_list: # Least n for all j_n which is coupled as first and second spaces n1, n2 = j_coupling # List of all n's coupled in first and second spaces - j1_n = list(n_list[n1-1]) - j2_n = list(n_list[n2-1]) + j1_n = list(n_list[n1 - 1]) + j2_n = list(n_list[n2 - 1]) coupling_list.append( (j1_n, j2_n) ) # Set new j_n to be coupling of all j_n in both first and second spaces - n_list[ min(n1,n2) - 1 ] = sorted(j1_n+j2_n) + n_list[ min(n1, n2) - 1 ] = sorted(j1_n + j2_n) if all(state.j.is_number and state.m.is_number for state in states): # Numerical coupling # Iterate over difference between maximum possible j value of each coupling and the actual value - diff_max = [ Add( *[ jn[n-1]-mn[n-1] for n in coupling[0]+coupling[1] ] ) for coupling in coupling_list ] + diff_max = [ Add( *[ jn[n - 1] - mn[n - 1] for n in coupling[0] + + coupling[1] ] ) for coupling in coupling_list ] result = [] - for diff in range(diff_max[-1]+1): + for diff in range(diff_max[-1] + 1): # Determine available configurations n = len(coupling_list) - tot = binomial(diff+n-1, diff) + tot = binomial(diff + n - 1, diff) for config_num in range(tot): diff_list = _confignum_to_difflist(config_num, diff, n) @@ -1828,13 +1924,13 @@ cg_terms = [] coupled_j = list(jn) jcoupling = [] - for (j1_n,j2_n), coupling_diff in zip(coupling_list, diff_list): - j1 = coupled_j[ min(j1_n)-1 ] - j2 = coupled_j[ min(j2_n)-1 ] + for (j1_n, j2_n), coupling_diff in zip(coupling_list, diff_list): + j1 = coupled_j[ min(j1_n) - 1 ] + j2 = coupled_j[ min(j2_n) - 1 ] j3 = j1 + j2 - coupling_diff - coupled_j[ min(j1_n+j2_n) - 1 ] = j3 - m1 = Add( *[ mn[x-1] for x in j1_n] ) - m2 = Add( *[ mn[x-1] for x in j2_n] ) + coupled_j[ min(j1_n + j2_n) - 1 ] = j3 + m1 = Add( *[ mn[x - 1] for x in j1_n] ) + m2 = Add( *[ mn[x - 1] for x in j2_n] ) m3 = m1 + m2 cg_terms.append( (j1, m1, j2, m2, j3, m3) ) jcoupling.append( (min(j1_n), min(j2_n), j3) ) @@ -1855,21 +1951,21 @@ jcoupling = [] sum_terms = [] coupled_j = list(jn) - for j1_n,j2_n in coupling_list: - j1 = coupled_j[ min(j1_n)-1 ] - j2 = coupled_j[ min(j2_n)-1 ] - if len(j1_n+j2_n) == len(states): + for j1_n, j2_n in coupling_list: + j1 = coupled_j[ min(j1_n) - 1 ] + j2 = coupled_j[ min(j2_n) - 1 ] + if len(j1_n + j2_n) == len(states): j3 = symbols('j') else: - j3_name = 'j' + ''.join(["%s" % n for n in j1_n+j2_n]) + j3_name = 'j' + ''.join(["%s" % n for n in j1_n + j2_n]) j3 = symbols(j3_name) - coupled_j[ min(j1_n+j2_n) - 1 ] = j3 - m1 = Add( *[ mn[x-1] for x in j1_n] ) - m2 = Add( *[ mn[x-1] for x in j2_n] ) + coupled_j[ min(j1_n + j2_n) - 1 ] = j3 + m1 = Add( *[ mn[x - 1] for x in j1_n] ) + m2 = Add( *[ mn[x - 1] for x in j2_n] ) m3 = m1 + m2 cg_terms.append( (j1, m1, j2, m2, j3, m3) ) jcoupling.append( (min(j1_n), min(j2_n), j3) ) - sum_terms.append((j3,m3,j1+j2)) + sum_terms.append((j3, m3, j1 + j2)) coeff = Mul( *[ CG(*term) for term in cg_terms] ) state = coupled_evect(j3, m3, jn, jcoupling) return Sum(coeff*state, *sum_terms) @@ -1958,16 +2054,17 @@ elif isinstance(state, SpinState): if jn is None: raise ValueError("Must specify j-values for coupled state") - if not (isinstance(jn,list) or isinstance(jn,tuple)): + if not (isinstance(jn, list) or isinstance(jn, tuple)): raise TypeError("jn must be list or tuple") if jcoupling_list is None: # Use default jcoupling_list = [] - for i in range(1,len(jn)): - jcoupling_list.append( (1,1+i,Add(*[jn[j] for j in range(i+1)])) ) - if not (isinstance(jcoupling_list,list) or isinstance(jcoupling_list,tuple)): + for i in range(1, len(jn)): + jcoupling_list.append( + (1, 1 + i, Add(*[jn[j] for j in range(i + 1)])) ) + if not (isinstance(jcoupling_list, list) or isinstance(jcoupling_list, tuple)): raise TypeError("jcoupling must be a list or tuple") - if not len(jcoupling_list) == len(jn)-1: + if not len(jcoupling_list) == len(jn) - 1: raise ValueError("Must specify 2 fewer coupling terms than the number of j values") coupled_n, coupled_jn = _build_coupled(jcoupling_list, len(jn)) evect = state.__class__ @@ -1979,21 +2076,21 @@ j_list = list(jn) # Create coupling, which defines all the couplings between all the spaces - for j3, (n1,n2) in zip(coupled_jn, coupled_n): + for j3, (n1, n2) in zip(coupled_jn, coupled_n): # j's which are coupled as first and second spaces - j1 = j_list[n1[0]-1] - j2 = j_list[n2[0]-1] + j1 = j_list[n1[0] - 1] + j2 = j_list[n2[0] - 1] # Build coupling list coupling_list.append( (n1, n2, j1, j2, j3) ) # Set new value in j_list - j_list[min(n1+n2)-1] = j3 + j_list[min(n1 + n2) - 1] = j3 if j.is_number and m.is_number: diff_max = [ 2*x for x in jn ] diff = Add(*jn) - m n = len(jn) - tot = binomial(diff+n-1, diff) + tot = binomial(diff + n - 1, diff) result = [] for config_num in range(tot): @@ -2004,28 +2101,29 @@ cg_terms = [] for coupling in coupling_list: j1_n, j2_n, j1, j2, j3 = coupling - m1 = Add( *[ jn[x-1] - diff_list[x-1] for x in j1_n ] ) - m2 = Add( *[ jn[x-1] - diff_list[x-1] for x in j2_n ] ) - m3 = m1+m2 + m1 = Add( *[ jn[x - 1] - diff_list[x - 1] for x in j1_n ] ) + m2 = Add( *[ jn[x - 1] - diff_list[x - 1] for x in j2_n ] ) + m3 = m1 + m2 cg_terms.append( (j1, m1, j2, m2, j3, m3) ) coeff = Mul( *[ CG(*term).doit() for term in cg_terms ] ) - state = TensorProduct( *[ evect(j, j - d) for j,d in zip(jn,diff_list) ] ) + state = TensorProduct( + *[ evect(j, j - d) for j, d in zip(jn, diff_list) ] ) result.append(coeff*state) return Add(*result) else: # Symbolic coupling - m_str = "m1:%d" % (len(jn)+1) + m_str = "m1:%d" % (len(jn) + 1) mvals = symbols(m_str) - cg_terms = [(j1, Add(*[mvals[n-1] for n in j1_n]), - j2, Add(*[mvals[n-1] for n in j2_n]), - j3, Add(*[mvals[n-1] for n in j1_n+j2_n])) for j1_n,j2_n,j1,j2,j3 in coupling_list[:-1] ] - cg_terms.append(*[(j1, Add(*[mvals[n-1] for n in j1_n]), - j2, Add(*[mvals[n-1] for n in j2_n]), - j, m) for j1_n,j2_n,j1,j2,j3 in [coupling_list[-1]] ]) + cg_terms = [(j1, Add(*[mvals[n - 1] for n in j1_n]), + j2, Add(*[mvals[n - 1] for n in j2_n]), + j3, Add(*[mvals[n - 1] for n in j1_n + j2_n])) for j1_n, j2_n, j1, j2, j3 in coupling_list[:-1] ] + cg_terms.append(*[(j1, Add(*[mvals[n - 1] for n in j1_n]), + j2, Add(*[mvals[n - 1] for n in j2_n]), + j, m) for j1_n, j2_n, j1, j2, j3 in [coupling_list[-1]] ]) cg_coeff = Mul(*[CG(*cg_term) for cg_term in cg_terms]) - sum_terms = [ (m,-j,j) for j,m in zip(jn,mvals) ] - state = TensorProduct( *[ evect(j,m) for j,m in zip(jn,mvals) ] ) - return Sum(cg_coeff*state,*sum_terms) + sum_terms = [ (m, -j, j) for j, m in zip(jn, mvals) ] + state = TensorProduct( *[ evect(j, m) for j, m in zip(jn, mvals) ] ) + return Sum(cg_coeff*state, *sum_terms) def _confignum_to_difflist(config_num, diff, list_len): @@ -2034,12 +2132,12 @@ for n in range(list_len): prev_diff = diff # Number of spots after current one - rem_spots = list_len-n-1 + rem_spots = list_len - n - 1 # Number of configurations of distributing diff among the remaining spots - rem_configs = binomial(diff+rem_spots-1, diff) + rem_configs = binomial(diff + rem_spots - 1, diff) while config_num >= rem_configs: config_num -= rem_configs diff -= 1 - rem_configs = binomial(diff+rem_spots-1, diff) - diff_list.append(prev_diff-diff) + rem_configs = binomial(diff + rem_spots - 1, diff) + diff_list.append(prev_diff - diff) return diff_list diff -Nru python3-sympy-0.7.2/sympy/physics/quantum/state.py python3-sympy-0.7.3/sympy/physics/quantum/state.py --- python3-sympy-0.7.2/sympy/physics/quantum/state.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/physics/quantum/state.py 2013-07-13 17:53:32.000000000 +0000 @@ -85,12 +85,13 @@ operator instances. See cartesian.py for examples, """ - raise NotImplementedError("Cannot map this state to operators. Method not implemented!") + raise NotImplementedError( + "Cannot map this state to operators. Method not implemented!") @property def operators(self): """Return the operator(s) that this state is an eigenstate of""" - from .operatorset import state_to_operators #import internally to avoid circular import errors + from .operatorset import state_to_operators # import internally to avoid circular import errors return state_to_operators(self) def _enumerate_state(self, num_states, **options): @@ -145,18 +146,22 @@ for bracket in lbracket, rbracket: # Create left bracket if bracket in set([_lbracket, _lbracket_ucode]): - bracket_args = [ ' ' * (height//2-i-1) + slash for i in range(height // 2)] - bracket_args.extend([ ' ' * i + bslash for i in range(height // 2)]) + bracket_args = [ ' ' * (height//2 - i - 1) + + slash for i in range(height // 2)] + bracket_args.extend( + [ ' ' * i + bslash for i in range(height // 2)]) # Create right bracket elif bracket in set([_rbracket, _rbracket_ucode]): bracket_args = [ ' ' * i + bslash for i in range(height // 2)] - bracket_args.extend([ ' ' * (height//2-i-1) + slash for i in range(height // 2)]) + bracket_args.extend([ ' ' * ( + height//2 - i - 1) + slash for i in range(height // 2)]) # Create straight bracket elif bracket in set([_straight_bracket, _straight_bracket_ucode]): bracket_args = [vert for i in range(height)] else: raise ValueError(bracket) - brackets.append(stringPict('\n'.join(bracket_args), baseline=height//2)) + brackets.append( + stringPict('\n'.join(bracket_args), baseline=height//2)) return brackets def _sympystr(self, printer, *args): @@ -167,7 +172,8 @@ from sympy.printing.pretty.stringpict import prettyForm # Get brackets pform = self._print_contents_pretty(printer, *args) - lbracket, rbracket = self._pretty_brackets(pform.height(), printer._use_unicode) + lbracket, rbracket = self._pretty_brackets( + pform.height(), printer._use_unicode) # Put together state pform = prettyForm(*pform.left(lbracket)) pform = prettyForm(*pform.right(rbracket)) @@ -258,6 +264,7 @@ """ return dispatch_method(self, '_apply_operator', op, **options) + class BraBase(StateBase): """Base class for Bras. @@ -320,7 +327,6 @@ pass - class Ket(State, KetBase): """A general time-independent Ket in quantum mechanics. @@ -385,6 +391,7 @@ def dual_class(self): return Bra + class Bra(State, BraBase): """A general time-independent Bra in quantum mechanics. @@ -449,6 +456,7 @@ # Time dependent states, bras and kets. #----------------------------------------------------------------------------- + class TimeDepState(StateBase): """Base class for a general time-dependent quantum state. @@ -518,7 +526,8 @@ return printer._print_seq((label, time), delimiter=';') def _print_contents_latex(self, printer, *args): - label = self._print_sequence(self.label, self._label_separator, printer, *args) + label = self._print_sequence( + self.label, self._label_separator, printer, *args) time = self._print_time_latex(printer, *args) return '%s;%s' % (label, time) @@ -603,6 +612,7 @@ def dual_class(self): return TimeDepKet + class Wavefunction(Function): """Class for representations in continuous bases @@ -655,7 +665,7 @@ >>> from sympy.functions import sqrt, sin >>> from sympy.physics.quantum.state import Wavefunction >>> x, L = symbols('x,L', positive=True) - >>> n = symbols('n', integer=True) + >>> n = symbols('n', integer=True, positive=True) >>> g = sqrt(2/L)*sin(n*pi*x/L) >>> f = Wavefunction(g, (x, 0, L)) >>> f.norm @@ -699,7 +709,7 @@ new_args[ct] = Tuple(*arg) else: new_args[ct] = arg - ct+=1 + ct += 1 return super(Function, cls).__new__(cls, *new_args, **options) @@ -707,19 +717,20 @@ var = self.variables if len(args) != len(var): - raise NotImplementedError("Incorrect number of arguments to function!") + raise NotImplementedError( + "Incorrect number of arguments to function!") ct = 0 #If the passed value is outside the specified bounds, return 0 for v in var: - lower,upper = self.limits[v] + lower, upper = self.limits[v] #Do the comparison to limits only if the passed symbol is actually #a symbol present in the limits; #Had problems with a comparison of x > L if isinstance(args[ct], Expr) and \ - not (lower in args[ct].free_symbols \ - or upper in args[ct].free_symbols): + not (lower in args[ct].free_symbols + or upper in args[ct].free_symbols): continue if args[ct] < lower or args[ct] > upper: @@ -810,7 +821,7 @@ {x: (-oo, oo), y: (-1, 2)} """ - limits = [(g[1], g[2]) if isinstance(g, Tuple) else (-oo, oo) \ + limits = [(g[1], g[2]) if isinstance(g, Tuple) else (-oo, oo) for g in self._args[1:]] return dict(list(zip(self.variables, tuple(limits)))) @@ -844,7 +855,7 @@ >>> from sympy.functions import sqrt, sin >>> from sympy.physics.quantum.state import Wavefunction >>> x, L = symbols('x,L', positive=True) - >>> n = symbols('n', integer=True) + >>> n = symbols('n', integer=True, positive=True) >>> g = sqrt(2/L)*sin(n*pi*x/L) >>> f = Wavefunction(g, (x, 0, L)) >>> f.is_normalized @@ -870,7 +881,7 @@ >>> from sympy.functions import sqrt, sin >>> from sympy.physics.quantum.state import Wavefunction >>> x, L = symbols('x,L', positive=True) - >>> n = symbols('n', integer=True) + >>> n = symbols('n', integer=True, positive=True) >>> g = sqrt(2/L)*sin(n*pi*x/L) >>> f = Wavefunction(g, (x, 0, L)) >>> f.norm @@ -902,8 +913,9 @@ >>> from sympy import symbols, pi >>> from sympy.functions import sqrt, sin >>> from sympy.physics.quantum.state import Wavefunction - >>> x, L = symbols('x,L', real=True) - >>> n = symbols('n', integer=True) + >>> x = symbols('x', real=True) + >>> L = symbols('L', positive=True) + >>> n = symbols('n', integer=True, positive=True) >>> g = sin(n*pi*x/L) >>> f = Wavefunction(g, (x, 0, L)) >>> f.normalize() diff -Nru python3-sympy-0.7.2/sympy/physics/quantum/tensorproduct.py python3-sympy-0.7.3/sympy/physics/quantum/tensorproduct.py --- python3-sympy-0.7.2/sympy/physics/quantum/tensorproduct.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/physics/quantum/tensorproduct.py 2013-07-13 17:53:32.000000000 +0000 @@ -55,15 +55,17 @@ >>> m1 = Matrix([[1,2],[3,4]]) >>> m2 = Matrix([[1,0],[0,1]]) >>> TensorProduct(m1, m2) - [1, 0, 2, 0] - [0, 1, 0, 2] - [3, 0, 4, 0] - [0, 3, 0, 4] + Matrix([ + [1, 0, 2, 0], + [0, 1, 0, 2], + [3, 0, 4, 0], + [0, 3, 0, 4]]) >>> TensorProduct(m2, m1) - [1, 2, 0, 0] - [3, 4, 0, 0] - [0, 0, 1, 2] - [0, 0, 3, 4] + Matrix([ + [1, 2, 0, 0], + [3, 4, 0, 0], + [0, 0, 1, 2], + [0, 0, 3, 4]]) We can also construct tensor products of non-commutative symbols: @@ -134,7 +136,7 @@ s = s + sstr(self.args[i]) if isinstance(self.args[i], (Add, Pow, Mul)): s = s + ')' - if i != length-1: + if i != length - 1: s = s + 'x' return s @@ -148,7 +150,7 @@ *next_pform.parens(left='(', right=')') ) pform = prettyForm(*pform.right(next_pform)) - if i != length-1: + if i != length - 1: if printer._use_unicode: pform = prettyForm(*pform.right('\u2a02' + ' ')) else: @@ -166,7 +168,7 @@ s = s + '{' + printer._print(self.args[i], *args) + '}' if isinstance(self.args[i], (Add, Mul)): s = s + '\\right)' - if i != length-1: + if i != length - 1: s = s + '\\otimes ' return s @@ -181,7 +183,7 @@ for i in range(len(args)): if isinstance(args[i], Add): for aa in args[i].args: - tp = TensorProduct(*args[:i]+(aa,)+args[i+1:]) + tp = TensorProduct(*args[:i] + (aa,) + args[i + 1:]) if isinstance(tp, TensorProduct): tp = tp._eval_expand_tensorproduct() add_args.append(tp) @@ -202,6 +204,7 @@ return Mul(*[Tr(value).doit() if idx in indices else value for idx, value in enumerate(exp.args)]) + def tensor_product_simp_Mul(e): """Simplify a Mul with TensorProducts. @@ -229,7 +232,8 @@ This is an example of the type of simplification that this function performs:: - >>> from sympy.physics.quantum.tensorproduct import tensor_product_simp_Mul, TensorProduct + >>> from sympy.physics.quantum.tensorproduct import \ + tensor_product_simp_Mul, TensorProduct >>> from sympy import Symbol >>> A = Symbol('A',commutative=False) >>> B = Symbol('B',commutative=False) @@ -262,7 +266,7 @@ if isinstance(next, TensorProduct): if n_terms != len(next.args): raise QuantumError( - 'TensorProducts of different lengths: %r and %r' % \ + 'TensorProducts of different lengths: %r and %r' % (current, next) ) for i in range(len(new_args)): diff -Nru python3-sympy-0.7.2/sympy/physics/quantum/tests/test_anticommutator.py python3-sympy-0.7.3/sympy/physics/quantum/tests/test_anticommutator.py --- python3-sympy-0.7.2/sympy/physics/quantum/tests/test_anticommutator.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/physics/quantum/tests/test_anticommutator.py 2013-07-13 17:53:32.000000000 +0000 @@ -10,21 +10,22 @@ def test_anticommutator(): - ac = AComm(A,B) + ac = AComm(A, B) assert isinstance(ac, AComm) - assert ac.is_commutative == False - assert ac.subs(A,C) == AComm(C,B) + assert ac.is_commutative is False + assert ac.subs(A, C) == AComm(C, B) + def test_commutator_identities(): - assert AComm(a*A,b*B) == a*b*AComm(A,B) + assert AComm(a*A, b*B) == a*b*AComm(A, B) assert AComm(A, A) == 2*A**2 assert AComm(A, B) == AComm(B, A) assert AComm(a, b) == 2*a*b - assert AComm(A,B).doit() == A*B + B*A + assert AComm(A, B).doit() == A*B + B*A def test_anticommutator_dagger(): - assert Dagger(AComm(A, B)) == AComm(Dagger(A),Dagger(B)) + assert Dagger(AComm(A, B)) == AComm(Dagger(A), Dagger(B)) class Foo(Operator): @@ -47,8 +48,8 @@ F = Foo('F') B = Bar('B') T = Tam('T') - assert AComm(F,B).doit() == 0 - assert AComm(B,F).doit() == 0 - assert AComm(F,T).doit() == 1 - assert AComm(T,F).doit() == 1 - assert AComm(B,T).doit() == B*T + T*B + assert AComm(F, B).doit() == 0 + assert AComm(B, F).doit() == 0 + assert AComm(F, T).doit() == 1 + assert AComm(T, F).doit() == 1 + assert AComm(B, T).doit() == B*T + T*B diff -Nru python3-sympy-0.7.2/sympy/physics/quantum/tests/test_cartesian.py python3-sympy-0.7.3/sympy/physics/quantum/tests/test_cartesian.py --- python3-sympy-0.7.2/sympy/physics/quantum/tests/test_cartesian.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/physics/quantum/tests/test_cartesian.py 2013-07-13 17:53:32.000000000 +0000 @@ -20,47 +20,50 @@ assert qapply(X*XKet(x)) == x*XKet(x) assert XKet(x).dual_class() == XBra assert XBra(x).dual_class() == XKet - assert (Dagger(XKet(y))*XKet(x)).doit() == DiracDelta(x-y) - assert (PxBra(px)*XKet(x)).doit() ==\ + assert (Dagger(XKet(y))*XKet(x)).doit() == DiracDelta(x - y) + assert (PxBra(px)*XKet(x)).doit() == \ exp(-I*x*px/hbar)/sqrt(2*pi*hbar) - assert represent(XKet(x)) == DiracDelta(x-x_1) + assert represent(XKet(x)) == DiracDelta(x - x_1) assert represent(XBra(x)) == DiracDelta(-x + x_1) assert XBra(x).position == x - assert represent(XOp()*XKet()) == x*DiracDelta(x-x_2) + assert represent(XOp()*XKet()) == x*DiracDelta(x - x_2) assert represent(XOp()*XKet()*XBra('y')) == \ - x*DiracDelta(x - x_3)*DiracDelta(x_1 - y) + x*DiracDelta(x - x_3)*DiracDelta(x_1 - y) assert represent(XBra("y")*XKet()) == DiracDelta(x - y) - assert represent(XKet()*XBra()) == DiracDelta(x - x_2) * DiracDelta(x_1 - x) + assert represent( + XKet()*XBra()) == DiracDelta(x - x_2) * DiracDelta(x_1 - x) - rep_p = represent(XOp(), basis = PxOp) + rep_p = represent(XOp(), basis=PxOp) assert rep_p == hbar*I*DiracDelta(px_1 - px_2)*DifferentialOperator(px_1) - assert rep_p == represent(XOp(), basis = PxOp()) - assert rep_p == represent(XOp(), basis = PxKet) - assert rep_p == represent(XOp(), basis = PxKet()) + assert rep_p == represent(XOp(), basis=PxOp()) + assert rep_p == represent(XOp(), basis=PxKet) + assert rep_p == represent(XOp(), basis=PxKet()) + + assert represent(XOp()*PxKet(), basis=PxKet) == \ + hbar*I*DiracDelta(px - px_2)*DifferentialOperator(px) - assert represent(XOp()*PxKet(), basis = PxKet) == \ - hbar*I*DiracDelta(px - px_2)*DifferentialOperator(px) def test_p(): assert Px.hilbert_space == L2(Interval(S.NegativeInfinity, S.Infinity)) assert qapply(Px*PxKet(px)) == px*PxKet(px) assert PxKet(px).dual_class() == PxBra assert PxBra(x).dual_class() == PxKet - assert (Dagger(PxKet(py))*PxKet(px)).doit() == DiracDelta(px-py) - assert (XBra(x)*PxKet(px)).doit() ==\ + assert (Dagger(PxKet(py))*PxKet(px)).doit() == DiracDelta(px - py) + assert (XBra(x)*PxKet(px)).doit() == \ exp(I*x*px/hbar)/sqrt(2*pi*hbar) - assert represent(PxKet(px)) == DiracDelta(px-px_1) + assert represent(PxKet(px)) == DiracDelta(px - px_1) - rep_x = represent(PxOp(), basis = XOp) + rep_x = represent(PxOp(), basis=XOp) assert rep_x == -hbar*I*DiracDelta(x_1 - x_2)*DifferentialOperator(x_1) - assert rep_x == represent(PxOp(), basis = XOp()) - assert rep_x == represent(PxOp(), basis = XKet) - assert rep_x == represent(PxOp(), basis = XKet()) + assert rep_x == represent(PxOp(), basis=XOp()) + assert rep_x == represent(PxOp(), basis=XKet) + assert rep_x == represent(PxOp(), basis=XKet()) assert represent(PxOp()*XKet(), basis=XKet) == \ - -hbar*I*DiracDelta(x - x_2)*DifferentialOperator(x) + -hbar*I*DiracDelta(x - x_2)*DifferentialOperator(x) assert represent(XBra("y")*PxOp()*XKet(), basis=XKet) == \ - -hbar*I*DiracDelta(x-y)*DifferentialOperator(x) + -hbar*I*DiracDelta(x - y)*DifferentialOperator(x) + def test_3dpos(): assert Y.hilbert_space == L2(Interval(S.NegativeInfinity, S.Infinity)) @@ -83,7 +86,7 @@ other_ket = PositionKet3D(x_1, y_1, z_1) assert (Dagger(other_ket)*test_ket).doit() == \ - DiracDelta(x - x_1)*DiracDelta(y - y_1)*DiracDelta(z - z_1) + DiracDelta(x - x_1)*DiracDelta(y - y_1)*DiracDelta(z - z_1) assert test_ket.position_x == x assert test_ket.position_y == y diff -Nru python3-sympy-0.7.2/sympy/physics/quantum/tests/test_cg.py python3-sympy-0.7.3/sympy/physics/quantum/tests/test_cg.py --- python3-sympy-0.7.2/sympy/physics/quantum/tests/test_cg.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/physics/quantum/tests/test_cg.py 2013-07-13 17:53:32.000000000 +0000 @@ -7,156 +7,168 @@ def test_cg_simp_add(): j, m1, m1p, m2, m2p = symbols('j m1 m1p m2 m2p') # Test Varshalovich 8.7.1 Eq 1 - a = CG(S(1)/2,S(1)/2,0,0,S(1)/2,S(1)/2) - b = CG(S(1)/2,-S(1)/2,0,0,S(1)/2,-S(1)/2) - c = CG(1,1,0,0,1,1) - d = CG(1,0,0,0,1,0) - e = CG(1,-1,0,0,1,-1) - assert cg_simp(a+b) == 2 - assert cg_simp(c+d+e) == 3 - assert cg_simp(a+b+c+d+e) == 5 - assert cg_simp(a+b+c) == 2+c - assert cg_simp(2*a+b) == 2+a - assert cg_simp(2*c+d+e) == 3+c - assert cg_simp(5*a+5*b) == 10 - assert cg_simp(5*c+5*d+5*e) == 15 - assert cg_simp(-a-b) == -2 - assert cg_simp(-c-d-e) == -3 - assert cg_simp(-6*a-6*b) == -12 - assert cg_simp(-4*c-4*d-4*e) == -12 - a = CG(S(1)/2,S(1)/2,j,0,S(1)/2,S(1)/2) - b = CG(S(1)/2,-S(1)/2,j,0,S(1)/2,-S(1)/2) - c = CG(1,1,j,0,1,1) - d = CG(1,0,j,0,1,0) - e = CG(1,-1,j,0,1,-1) - assert cg_simp(a+b) == 2*KroneckerDelta(j,0) - assert cg_simp(c+d+e) == 3*KroneckerDelta(j,0) - assert cg_simp(a+b+c+d+e) == 5*KroneckerDelta(j,0) - assert cg_simp(a+b+c) == 2*KroneckerDelta(j,0)+c - assert cg_simp(2*a+b) == 2*KroneckerDelta(j,0)+a - assert cg_simp(2*c+d+e) == 3*KroneckerDelta(j,0)+c - assert cg_simp(5*a+5*b) == 10*KroneckerDelta(j,0) - assert cg_simp(5*c+5*d+5*e) == 15*KroneckerDelta(j,0) - assert cg_simp(-a-b) == -2*KroneckerDelta(j,0) - assert cg_simp(-c-d-e) == -3*KroneckerDelta(j,0) - assert cg_simp(-6*a-6*b) == -12*KroneckerDelta(j,0) - assert cg_simp(-4*c-4*d-4*e) == -12*KroneckerDelta(j,0) + a = CG(S(1)/2, S(1)/2, 0, 0, S(1)/2, S(1)/2) + b = CG(S(1)/2, -S(1)/2, 0, 0, S(1)/2, -S(1)/2) + c = CG(1, 1, 0, 0, 1, 1) + d = CG(1, 0, 0, 0, 1, 0) + e = CG(1, -1, 0, 0, 1, -1) + assert cg_simp(a + b) == 2 + assert cg_simp(c + d + e) == 3 + assert cg_simp(a + b + c + d + e) == 5 + assert cg_simp(a + b + c) == 2 + c + assert cg_simp(2*a + b) == 2 + a + assert cg_simp(2*c + d + e) == 3 + c + assert cg_simp(5*a + 5*b) == 10 + assert cg_simp(5*c + 5*d + 5*e) == 15 + assert cg_simp(-a - b) == -2 + assert cg_simp(-c - d - e) == -3 + assert cg_simp(-6*a - 6*b) == -12 + assert cg_simp(-4*c - 4*d - 4*e) == -12 + a = CG(S(1)/2, S(1)/2, j, 0, S(1)/2, S(1)/2) + b = CG(S(1)/2, -S(1)/2, j, 0, S(1)/2, -S(1)/2) + c = CG(1, 1, j, 0, 1, 1) + d = CG(1, 0, j, 0, 1, 0) + e = CG(1, -1, j, 0, 1, -1) + assert cg_simp(a + b) == 2*KroneckerDelta(j, 0) + assert cg_simp(c + d + e) == 3*KroneckerDelta(j, 0) + assert cg_simp(a + b + c + d + e) == 5*KroneckerDelta(j, 0) + assert cg_simp(a + b + c) == 2*KroneckerDelta(j, 0) + c + assert cg_simp(2*a + b) == 2*KroneckerDelta(j, 0) + a + assert cg_simp(2*c + d + e) == 3*KroneckerDelta(j, 0) + c + assert cg_simp(5*a + 5*b) == 10*KroneckerDelta(j, 0) + assert cg_simp(5*c + 5*d + 5*e) == 15*KroneckerDelta(j, 0) + assert cg_simp(-a - b) == -2*KroneckerDelta(j, 0) + assert cg_simp(-c - d - e) == -3*KroneckerDelta(j, 0) + assert cg_simp(-6*a - 6*b) == -12*KroneckerDelta(j, 0) + assert cg_simp(-4*c - 4*d - 4*e) == -12*KroneckerDelta(j, 0) # Test Varshalovich 8.7.1 Eq 2 - a = CG(S(1)/2,S(1)/2,S(1)/2,-S(1)/2,0,0) - b = CG(S(1)/2,-S(1)/2,S(1)/2,S(1)/2,0,0) - c = CG(1,1,1,-1,0,0) - d = CG(1,0,1,0,0,0) - e = CG(1,-1,1,1,0,0) - assert cg_simp(a-b) == sqrt(2) - assert cg_simp(c-d+e) == sqrt(3) - assert cg_simp(a-b+c-d+e) == sqrt(2)+sqrt(3) - assert cg_simp(a-b+c) == sqrt(2)+c - assert cg_simp(2*a-b) == sqrt(2)+a - assert cg_simp(2*c-d+e) == sqrt(3)+c - assert cg_simp(5*a-5*b) == 5*sqrt(2) - assert cg_simp(5*c-5*d+5*e) == 5*sqrt(3) - assert cg_simp(-a+b) == -sqrt(2) - assert cg_simp(-c+d-e) == -sqrt(3) - assert cg_simp(-6*a+6*b) == -6*sqrt(2) - assert cg_simp(-4*c+4*d-4*e) == -4*sqrt(3) - a = CG(S(1)/2,S(1)/2,S(1)/2,-S(1)/2,j,0) - b = CG(S(1)/2,-S(1)/2,S(1)/2,S(1)/2,j,0) - c = CG(1,1,1,-1,j,0) - d = CG(1,0,1,0,j,0) - e = CG(1,-1,1,1,j,0) - assert cg_simp(a-b) == sqrt(2)*KroneckerDelta(j,0) - assert cg_simp(c-d+e) == sqrt(3)*KroneckerDelta(j,0) - assert cg_simp(a-b+c-d+e) == sqrt(2)*KroneckerDelta(j,0)+sqrt(3)*KroneckerDelta(j,0) - assert cg_simp(a-b+c) == sqrt(2)*KroneckerDelta(j,0)+c - assert cg_simp(2*a-b) == sqrt(2)*KroneckerDelta(j,0)+a - assert cg_simp(2*c-d+e) == sqrt(3)*KroneckerDelta(j,0)+c - assert cg_simp(5*a-5*b) == 5*sqrt(2)*KroneckerDelta(j,0) - assert cg_simp(5*c-5*d+5*e) == 5*sqrt(3)*KroneckerDelta(j,0) - assert cg_simp(-a+b) == -sqrt(2)*KroneckerDelta(j,0) - assert cg_simp(-c+d-e) == -sqrt(3)*KroneckerDelta(j,0) - assert cg_simp(-6*a+6*b) == -6*sqrt(2)*KroneckerDelta(j,0) - assert cg_simp(-4*c+4*d-4*e) == -4*sqrt(3)*KroneckerDelta(j,0) + a = CG(S(1)/2, S(1)/2, S(1)/2, -S(1)/2, 0, 0) + b = CG(S(1)/2, -S(1)/2, S(1)/2, S(1)/2, 0, 0) + c = CG(1, 1, 1, -1, 0, 0) + d = CG(1, 0, 1, 0, 0, 0) + e = CG(1, -1, 1, 1, 0, 0) + assert cg_simp(a - b) == sqrt(2) + assert cg_simp(c - d + e) == sqrt(3) + assert cg_simp(a - b + c - d + e) == sqrt(2) + sqrt(3) + assert cg_simp(a - b + c) == sqrt(2) + c + assert cg_simp(2*a - b) == sqrt(2) + a + assert cg_simp(2*c - d + e) == sqrt(3) + c + assert cg_simp(5*a - 5*b) == 5*sqrt(2) + assert cg_simp(5*c - 5*d + 5*e) == 5*sqrt(3) + assert cg_simp(-a + b) == -sqrt(2) + assert cg_simp(-c + d - e) == -sqrt(3) + assert cg_simp(-6*a + 6*b) == -6*sqrt(2) + assert cg_simp(-4*c + 4*d - 4*e) == -4*sqrt(3) + a = CG(S(1)/2, S(1)/2, S(1)/2, -S(1)/2, j, 0) + b = CG(S(1)/2, -S(1)/2, S(1)/2, S(1)/2, j, 0) + c = CG(1, 1, 1, -1, j, 0) + d = CG(1, 0, 1, 0, j, 0) + e = CG(1, -1, 1, 1, j, 0) + assert cg_simp(a - b) == sqrt(2)*KroneckerDelta(j, 0) + assert cg_simp(c - d + e) == sqrt(3)*KroneckerDelta(j, 0) + assert cg_simp(a - b + c - d + e) == sqrt( + 2)*KroneckerDelta(j, 0) + sqrt(3)*KroneckerDelta(j, 0) + assert cg_simp(a - b + c) == sqrt(2)*KroneckerDelta(j, 0) + c + assert cg_simp(2*a - b) == sqrt(2)*KroneckerDelta(j, 0) + a + assert cg_simp(2*c - d + e) == sqrt(3)*KroneckerDelta(j, 0) + c + assert cg_simp(5*a - 5*b) == 5*sqrt(2)*KroneckerDelta(j, 0) + assert cg_simp(5*c - 5*d + 5*e) == 5*sqrt(3)*KroneckerDelta(j, 0) + assert cg_simp(-a + b) == -sqrt(2)*KroneckerDelta(j, 0) + assert cg_simp(-c + d - e) == -sqrt(3)*KroneckerDelta(j, 0) + assert cg_simp(-6*a + 6*b) == -6*sqrt(2)*KroneckerDelta(j, 0) + assert cg_simp(-4*c + 4*d - 4*e) == -4*sqrt(3)*KroneckerDelta(j, 0) # Test Varshalovich 8.7.2 Eq 9 # alpha=alphap,beta=betap case # numerical - a = CG(S(1)/2,S(1)/2,S(1)/2,-S(1)/2,1,0)**2 - b = CG(S(1)/2,S(1)/2,S(1)/2,-S(1)/2,0,0)**2 - c = CG(1,0,1,1,1,1)**2 - d = CG(1,0,1,1,2,1)**2 - assert cg_simp(a+b) == 1 - assert cg_simp(c+d) == 1 - assert cg_simp(a+b+c+d) == 2 - assert cg_simp(4*a+4*b) == 4 - assert cg_simp(4*c+4*d) == 4 - assert cg_simp(5*a+3*b) == 3+2*a - assert cg_simp(5*c+3*d) == 3+2*c - assert cg_simp(-a-b) == -1 - assert cg_simp(-c-d) == -1 + a = CG(S(1)/2, S(1)/2, S(1)/2, -S(1)/2, 1, 0)**2 + b = CG(S(1)/2, S(1)/2, S(1)/2, -S(1)/2, 0, 0)**2 + c = CG(1, 0, 1, 1, 1, 1)**2 + d = CG(1, 0, 1, 1, 2, 1)**2 + assert cg_simp(a + b) == 1 + assert cg_simp(c + d) == 1 + assert cg_simp(a + b + c + d) == 2 + assert cg_simp(4*a + 4*b) == 4 + assert cg_simp(4*c + 4*d) == 4 + assert cg_simp(5*a + 3*b) == 3 + 2*a + assert cg_simp(5*c + 3*d) == 3 + 2*c + assert cg_simp(-a - b) == -1 + assert cg_simp(-c - d) == -1 # symbolic - a = CG(S(1)/2,m1,S(1)/2,m2,1,1)**2 - b = CG(S(1)/2,m1,S(1)/2,m2,1,0)**2 - c = CG(S(1)/2,m1,S(1)/2,m2,1,-1)**2 - d = CG(S(1)/2,m1,S(1)/2,m2,0,0)**2 - assert cg_simp(a+b+c+d) == 1 - assert cg_simp(4*a+4*b+4*c+4*d) == 4 - assert cg_simp(3*a+5*b+3*c+4*d) == 3+2*b+d - assert cg_simp(-a-b-c-d) == -1 - a = CG(1,m1,1,m2,2,2)**2 - b = CG(1,m1,1,m2,2,1)**2 - c = CG(1,m1,1,m2,2,0)**2 - d = CG(1,m1,1,m2,2,-1)**2 - e = CG(1,m1,1,m2,2,-2)**2 - f = CG(1,m1,1,m2,1,1)**2 - g = CG(1,m1,1,m2,1,0)**2 - h = CG(1,m1,1,m2,1,-1)**2 - i = CG(1,m1,1,m2,0,0)**2 - assert cg_simp(a+b+c+d+e+f+g+h+i) == 1 - assert cg_simp(4*(a+b+c+d+e+f+g+h+i)) == 4 - assert cg_simp(a+b+2*c+d+4*e+f+g+h+i) == 1+c+3*e - assert cg_simp(-a-b-c-d-e-f-g-h-i) == -1 + a = CG(S(1)/2, m1, S(1)/2, m2, 1, 1)**2 + b = CG(S(1)/2, m1, S(1)/2, m2, 1, 0)**2 + c = CG(S(1)/2, m1, S(1)/2, m2, 1, -1)**2 + d = CG(S(1)/2, m1, S(1)/2, m2, 0, 0)**2 + assert cg_simp(a + b + c + d) == 1 + assert cg_simp(4*a + 4*b + 4*c + 4*d) == 4 + assert cg_simp(3*a + 5*b + 3*c + 4*d) == 3 + 2*b + d + assert cg_simp(-a - b - c - d) == -1 + a = CG(1, m1, 1, m2, 2, 2)**2 + b = CG(1, m1, 1, m2, 2, 1)**2 + c = CG(1, m1, 1, m2, 2, 0)**2 + d = CG(1, m1, 1, m2, 2, -1)**2 + e = CG(1, m1, 1, m2, 2, -2)**2 + f = CG(1, m1, 1, m2, 1, 1)**2 + g = CG(1, m1, 1, m2, 1, 0)**2 + h = CG(1, m1, 1, m2, 1, -1)**2 + i = CG(1, m1, 1, m2, 0, 0)**2 + assert cg_simp(a + b + c + d + e + f + g + h + i) == 1 + assert cg_simp(4*(a + b + c + d + e + f + g + h + i)) == 4 + assert cg_simp(a + b + 2*c + d + 4*e + f + g + h + i) == 1 + c + 3*e + assert cg_simp(-a - b - c - d - e - f - g - h - i) == -1 # alpha!=alphap or beta!=betap case # numerical - a = CG(S(1)/2,S(1)/2,S(1)/2,-S(1)/2,1,0)*CG(S(1)/2,-S(1)/2,S(1)/2,S(1)/2,1,0) - b = CG(S(1)/2,S(1)/2,S(1)/2,-S(1)/2,0,0)*CG(S(1)/2,-S(1)/2,S(1)/2,S(1)/2,0,0) - c = CG(1,1,1,0,2,1)*CG(1,0,1,1,2,1) - d = CG(1,1,1,0,1,1)*CG(1,0,1,1,1,1) - assert cg_simp(a+b) == 0 - assert cg_simp(c+d) == 0 + a = CG(S(1)/2, S( + 1)/2, S(1)/2, -S(1)/2, 1, 0)*CG(S(1)/2, -S(1)/2, S(1)/2, S(1)/2, 1, 0) + b = CG(S(1)/2, S( + 1)/2, S(1)/2, -S(1)/2, 0, 0)*CG(S(1)/2, -S(1)/2, S(1)/2, S(1)/2, 0, 0) + c = CG(1, 1, 1, 0, 2, 1)*CG(1, 0, 1, 1, 2, 1) + d = CG(1, 1, 1, 0, 1, 1)*CG(1, 0, 1, 1, 1, 1) + assert cg_simp(a + b) == 0 + assert cg_simp(c + d) == 0 # symbolic - a = CG(S(1)/2,m1,S(1)/2,m2,1,1)*CG(S(1)/2,m1p,S(1)/2,m2p,1,1) - b = CG(S(1)/2,m1,S(1)/2,m2,1,0)*CG(S(1)/2,m1p,S(1)/2,m2p,1,0) - c = CG(S(1)/2,m1,S(1)/2,m2,1,-1)*CG(S(1)/2,m1p,S(1)/2,m2p,1,-1) - d = CG(S(1)/2,m1,S(1)/2,m2,0,0)*CG(S(1)/2,m1p,S(1)/2,m2p,0,0) - assert cg_simp(a+b+c+d) == KroneckerDelta(m1,m1p)*KroneckerDelta(m2,m2p) - a = CG(1,m1,1,m2,2,2)*CG(1,m1p,1,m2p,2,2) - b = CG(1,m1,1,m2,2,1)*CG(1,m1p,1,m2p,2,1) - c = CG(1,m1,1,m2,2,0)*CG(1,m1p,1,m2p,2,0) - d = CG(1,m1,1,m2,2,-1)*CG(1,m1p,1,m2p,2,-1) - e = CG(1,m1,1,m2,2,-2)*CG(1,m1p,1,m2p,2,-2) - f = CG(1,m1,1,m2,1,1)*CG(1,m1p,1,m2p,1,1) - g = CG(1,m1,1,m2,1,0)*CG(1,m1p,1,m2p,1,0) - h = CG(1,m1,1,m2,1,-1)*CG(1,m1p,1,m2p,1,-1) - i = CG(1,m1,1,m2,0,0)*CG(1,m1p,1,m2p,0,0) - assert cg_simp(a+b+c+d+e+f+g+h+i) == KroneckerDelta(m1,m1p)*KroneckerDelta(m2,m2p) + a = CG(S(1)/2, m1, S(1)/2, m2, 1, 1)*CG(S(1)/2, m1p, S(1)/2, m2p, 1, 1) + b = CG(S(1)/2, m1, S(1)/2, m2, 1, 0)*CG(S(1)/2, m1p, S(1)/2, m2p, 1, 0) + c = CG(S(1)/2, m1, S(1)/2, m2, 1, -1)*CG(S(1)/2, m1p, S(1)/2, m2p, 1, -1) + d = CG(S(1)/2, m1, S(1)/2, m2, 0, 0)*CG(S(1)/2, m1p, S(1)/2, m2p, 0, 0) + assert cg_simp(a + b + c + d) == KroneckerDelta(m1, m1p)*KroneckerDelta(m2, m2p) + a = CG(1, m1, 1, m2, 2, 2)*CG(1, m1p, 1, m2p, 2, 2) + b = CG(1, m1, 1, m2, 2, 1)*CG(1, m1p, 1, m2p, 2, 1) + c = CG(1, m1, 1, m2, 2, 0)*CG(1, m1p, 1, m2p, 2, 0) + d = CG(1, m1, 1, m2, 2, -1)*CG(1, m1p, 1, m2p, 2, -1) + e = CG(1, m1, 1, m2, 2, -2)*CG(1, m1p, 1, m2p, 2, -2) + f = CG(1, m1, 1, m2, 1, 1)*CG(1, m1p, 1, m2p, 1, 1) + g = CG(1, m1, 1, m2, 1, 0)*CG(1, m1p, 1, m2p, 1, 0) + h = CG(1, m1, 1, m2, 1, -1)*CG(1, m1p, 1, m2p, 1, -1) + i = CG(1, m1, 1, m2, 0, 0)*CG(1, m1p, 1, m2p, 0, 0) + assert cg_simp( + a + b + c + d + e + f + g + h + i) == KroneckerDelta(m1, m1p)*KroneckerDelta(m2, m2p) + def test_cg_simp_sum(): - x, a, b, c, cp, alpha, beta, gamma, gammap = symbols('x a b c cp alpha beta gamma gammap') + x, a, b, c, cp, alpha, beta, gamma, gammap = symbols( + 'x a b c cp alpha beta gamma gammap') # Varshalovich 8.7.1 Eq 1 - assert cg_simp(x * Sum(CG(a,alpha,b,0,a,alpha), (alpha,-a,a))) == x*(2*a+1)*KroneckerDelta(b,0) - assert cg_simp(x * Sum(CG(a,alpha,b,0,a,alpha), (alpha,-a,a))+CG(1,0,1,0,1,0)) == x*(2*a+1)*KroneckerDelta(b,0)+CG(1,0,1,0,1,0) - assert cg_simp(2 * Sum(CG(1,alpha,0,0,1,alpha), (alpha,-1,1))) == 6 + assert cg_simp(x * Sum(CG(a, alpha, b, 0, a, alpha), (alpha, -a, a) + )) == x*(2*a + 1)*KroneckerDelta(b, 0) + assert cg_simp(x * Sum(CG(a, alpha, b, 0, a, alpha), (alpha, -a, a)) + CG(1, 0, 1, 0, 1, 0)) == x*(2*a + 1)*KroneckerDelta(b, 0) + CG(1, 0, 1, 0, 1, 0) + assert cg_simp(2 * Sum(CG(1, alpha, 0, 0, 1, alpha), (alpha, -1, 1))) == 6 # Varshalovich 8.7.1 Eq 2 - assert cg_simp(x*Sum((-1)**(a-alpha) * CG(a,alpha,a,-alpha,c,0), (alpha,-a,a))) == x*sqrt(2*a+1)*KroneckerDelta(c,0) - assert cg_simp(3*Sum((-1)**(2-alpha) * CG(2,alpha,2,-alpha,0,0), (alpha,-2,2))) == 3*sqrt(5) + assert cg_simp(x*Sum((-1)**(a - alpha) * CG(a, alpha, a, -alpha, c, + 0), (alpha, -a, a))) == x*sqrt(2*a + 1)*KroneckerDelta(c, 0) + assert cg_simp(3*Sum((-1)**(2 - alpha) * CG( + 2, alpha, 2, -alpha, 0, 0), (alpha, -2, 2))) == 3*sqrt(5) # Varshalovich 8.7.2 Eq 4 - assert cg_simp(Sum(CG(a,alpha,b,beta,c,gamma)*CG(a,alpha,b,beta,cp,gammap),(alpha,-a,a),(beta,-b,b))) == KroneckerDelta(c,cp)*KroneckerDelta(gamma,gammap) - assert cg_simp(Sum(CG(a,alpha,b,beta,c,gamma)*CG(a,alpha,b,beta,c,gammap),(alpha,-a,a),(beta,-b,b))) == KroneckerDelta(gamma,gammap) - assert cg_simp(Sum(CG(a,alpha,b,beta,c,gamma)*CG(a,alpha,b,beta,cp,gamma),(alpha,-a,a),(beta,-b,b))) == KroneckerDelta(c,cp) - assert cg_simp(Sum(CG(a,alpha,b,beta,c,gamma)**2,(alpha,-a,a),(beta,-b,b))) == 1 - assert cg_simp(Sum(CG(2,alpha,1,beta,2,gamma)*CG(2,alpha,1,beta,2,gammap), (alpha,-2,2), (beta,-1,1))) == KroneckerDelta(gamma,gammap) + assert cg_simp(Sum(CG(a, alpha, b, beta, c, gamma)*CG(a, alpha, b, beta, cp, gammap), (alpha, -a, a), (beta, -b, b))) == KroneckerDelta(c, cp)*KroneckerDelta(gamma, gammap) + assert cg_simp(Sum(CG(a, alpha, b, beta, c, gamma)*CG(a, alpha, b, beta, c, gammap), (alpha, -a, a), (beta, -b, b))) == KroneckerDelta(gamma, gammap) + assert cg_simp(Sum(CG(a, alpha, b, beta, c, gamma)*CG(a, alpha, b, beta, cp, gamma), (alpha, -a, a), (beta, -b, b))) == KroneckerDelta(c, cp) + assert cg_simp(Sum(CG( + a, alpha, b, beta, c, gamma)**2, (alpha, -a, a), (beta, -b, b))) == 1 + assert cg_simp(Sum(CG(2, alpha, 1, beta, 2, gamma)*CG(2, alpha, 1, beta, 2, gammap), (alpha, -2, 2), (beta, -1, 1))) == KroneckerDelta(gamma, gammap) + def test_doit(): - assert Wigner3j(1/2,-1/2,1/2,1/2,0,0).doit() == -sqrt(2)/2 - assert Wigner6j(1,2,3,2,1,2).doit() == sqrt(21)/105 - assert Wigner9j(2,1,1,S(3)/2,S(1)/2,1,S(1)/2,S(1)/2,0).doit() == sqrt(2)/12 - assert CG(1/2,1/2,1/2,-1/2,1,0).doit() == sqrt(2)/2 + assert Wigner3j(1/2, -1/2, 1/2, 1/2, 0, 0).doit() == -sqrt(2)/2 + assert Wigner6j(1, 2, 3, 2, 1, 2).doit() == sqrt(21)/105 + assert Wigner9j( + 2, 1, 1, S(3)/2, S(1)/2, 1, S(1)/2, S(1)/2, 0).doit() == sqrt(2)/12 + assert CG(1/2, 1/2, 1/2, -1/2, 1, 0).doit() == sqrt(2)/2 diff -Nru python3-sympy-0.7.2/sympy/physics/quantum/tests/test_circuitutils.py python3-sympy-0.7.3/sympy/physics/quantum/tests/test_circuitutils.py --- python3-sympy-0.7.2/sympy/physics/quantum/tests/test_circuitutils.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/physics/quantum/tests/test_circuitutils.py 2013-07-13 17:53:32.000000000 +0000 @@ -8,10 +8,12 @@ convert_to_real_indices, random_reduce, random_insert, flatten_ids) + def create_gate_sequence(qubit=0): gates = (X(qubit), Y(qubit), Z(qubit), H(qubit)) return gates + def test_kmp_table(): word = ('a', 'b', 'c', 'd', 'a', 'b', 'd') expected_table = [-1, 0, 0, 0, 0, 1, 2] @@ -20,7 +22,7 @@ word = ('P', 'A', 'R', 'T', 'I', 'C', 'I', 'P', 'A', 'T', 'E', ' ', 'I', 'N', ' ', 'P', 'A', 'R', 'A', 'C', 'H', 'U', 'T', 'E') expected_table = [-1, 0, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, - 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0] + 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0] assert expected_table == kmp_table(word) x = X(0) @@ -35,6 +37,7 @@ expected_table = [-1, 0, 1, 0, 0] assert expected_table == kmp_table(word) + def test_find_subcircuit(): x = X(0) y = Y(0) @@ -82,12 +85,13 @@ result = find_subcircuit(circuit, subcircuit) assert result == 0 + def test_replace_subcircuit(): x = X(0) y = Y(0) z = Z(0) h = H(0) - cnot = CNOT(1,0) + cnot = CNOT(1, 0) cgate_z = CGate((0,), Z(1)) # Standard cases @@ -131,17 +135,18 @@ replace=replace, pos=1) assert actual == (x, y, h, cnot, cgate_z, z) + def test_convert_to_symbolic_indices(): (x, y, z, h) = create_gate_sequence() i0 = Symbol('i0') - exp_map = {i0 : Integer(0)} + exp_map = {i0: Integer(0)} actual, act_map, sndx, gen = convert_to_symbolic_indices((x,)) assert actual == (X(i0),) assert act_map == exp_map expected = (X(i0), Y(i0), Z(i0), H(i0)) - exp_map = {i0 : Integer(0)} + exp_map = {i0: Integer(0)} actual, act_map, sndx, gen = convert_to_symbolic_indices((x, y, z, h)) assert actual == expected assert exp_map == act_map @@ -150,32 +155,32 @@ i1 = Symbol('i1') expected = (X(i0), Y(i0), Z(i0), H(i0)) - exp_map = {i0 : Integer(1)} + exp_map = {i0: Integer(1)} actual, act_map, sndx, gen = convert_to_symbolic_indices((x1, y1, z1, h1)) assert actual == expected assert act_map == exp_map expected = (X(i0), Y(i0), Z(i0), H(i0), X(i1), Y(i1), Z(i1), H(i1)) - exp_map = {i0 : Integer(0), i1 : Integer(1)} + exp_map = {i0: Integer(0), i1: Integer(1)} actual, act_map, sndx, gen = convert_to_symbolic_indices((x, y, z, h, x1, y1, z1, h1)) assert actual == expected assert act_map == exp_map - exp_map = {i0 : Integer(1), i1 : Integer(0)} + exp_map = {i0: Integer(1), i1: Integer(0)} actual, act_map, sndx, gen = convert_to_symbolic_indices(Mul(x1, y1, z1, h1, x, y, z, h)) assert actual == expected assert act_map == exp_map expected = (X(i0), X(i1), Y(i0), Y(i1), Z(i0), Z(i1), H(i0), H(i1)) - exp_map = {i0 : Integer(0), i1 : Integer(1)} + exp_map = {i0: Integer(0), i1: Integer(1)} actual, act_map, sndx, gen = convert_to_symbolic_indices(Mul(x, x1, y, y1, z, z1, h, h1)) assert actual == expected assert act_map == exp_map - exp_map = {i0 : Integer(1), i1 : Integer(0)} + exp_map = {i0: Integer(1), i1: Integer(0)} actual, act_map, sndx, gen = convert_to_symbolic_indices((x1, x, y1, y, z1, z, h1, h)) assert actual == expected @@ -189,7 +194,7 @@ expected = (X(i0), X(i1), Y(i0), Y(i1), Z(i0), Z(i1), H(i0), H(i1), CNOT(i1, i0), CNOT(i0, i1), CGate(i1, Z(i0)), CGate(i0, Z(i1))) - exp_map = {i0 : Integer(0), i1 : Integer(1)} + exp_map = {i0: Integer(0), i1: Integer(1)} args = (x, x1, y, y1, z, z1, h, h1, cnot_10, cnot_01, cgate_z_10, cgate_z_01) actual, act_map, sndx, gen = convert_to_symbolic_indices(args) @@ -201,27 +206,27 @@ expected = (X(i0), X(i1), Y(i0), Y(i1), Z(i0), Z(i1), H(i0), H(i1), CNOT(i0, i1), CNOT(i1, i0), CGate(i0, Z(i1)), CGate(i1, Z(i0))) - exp_map = {i0 : Integer(1), i1 : Integer(0)} + exp_map = {i0: Integer(1), i1: Integer(0)} actual, act_map, sndx, gen = convert_to_symbolic_indices(args) assert actual == expected assert act_map == exp_map args = (cnot_10, h, cgate_z_01, h) expected = (CNOT(i0, i1), H(i1), CGate(i1, Z(i0)), H(i1)) - exp_map = {i0 : Integer(1), i1 : Integer(0)} + exp_map = {i0: Integer(1), i1: Integer(0)} actual, act_map, sndx, gen = convert_to_symbolic_indices(args) assert actual == expected assert act_map == exp_map args = (cnot_01, h1, cgate_z_10, h1) - exp_map = {i0 : Integer(0), i1 : Integer(1)} + exp_map = {i0: Integer(0), i1: Integer(1)} actual, act_map, sndx, gen = convert_to_symbolic_indices(args) assert actual == expected assert act_map == exp_map args = (cnot_10, h1, cgate_z_01, h1) expected = (CNOT(i0, i1), H(i0), CGate(i1, Z(i0)), H(i0)) - exp_map = {i0 : Integer(1), i1 : Integer(0)} + exp_map = {i0: Integer(1), i1: Integer(0)} actual, act_map, sndx, gen = convert_to_symbolic_indices(args) assert actual == expected assert act_map == exp_map @@ -232,30 +237,31 @@ args = (ccgate_z, ccgate_x) expected = (CGate(i0, CGate(i1, Z(i2))), CGate(i1, CGate(i2, X(i0)))) - exp_map = {i0 : Integer(0), i1 : Integer(1), i2 : Integer(2)} + exp_map = {i0: Integer(0), i1: Integer(1), i2: Integer(2)} actual, act_map, sndx, gen = convert_to_symbolic_indices(args) assert actual == expected assert act_map == exp_map - ndx_map = {i0 : Integer(0)} + ndx_map = {i0: Integer(0)} index_gen = numbered_symbols(prefix='i', start=1) actual, act_map, sndx, gen = convert_to_symbolic_indices(args, qubit_map=ndx_map, start=i0, - gen = index_gen) + gen=index_gen) assert actual == expected assert act_map == exp_map i3 = Symbol('i3') - cgate_x0_c321 = CGate((3,2,1), X(0)) - exp_map = {i0 : Integer(3), i1 : Integer(2), - i2 : Integer(1), i3 : Integer(0)} + cgate_x0_c321 = CGate((3, 2, 1), X(0)) + exp_map = {i0: Integer(3), i1: Integer(2), + i2: Integer(1), i3: Integer(0)} expected = (CGate((i0, i1, i2), X(i3)),) args = (cgate_x0_c321,) actual, act_map, sndx, gen = convert_to_symbolic_indices(args) assert actual == expected assert act_map == exp_map + def test_convert_to_real_indices(): i0 = Symbol('i0') i1 = Symbol('i1') @@ -266,14 +272,14 @@ y_i0 = Y(i0) z_i0 = Z(i0) - qubit_map = {i0 : 0} + qubit_map = {i0: 0} args = (z_i0, y_i0, x_i0) expected = (z, y, x) actual = convert_to_real_indices(args, qubit_map) assert actual == expected - cnot_10 = CNOT(1,0) - cnot_01 = CNOT(0,1) + cnot_10 = CNOT(1, 0) + cnot_01 = CNOT(0, 1) cgate_z_10 = CGate(1, Z(0)) cgate_z_01 = CGate(0, Z(1)) @@ -281,7 +287,7 @@ cnot_i0_i1 = CNOT(i0, i1) cgate_z_i1_i0 = CGate(i1, Z(i0)) - qubit_map = {i0 : 0, i1 : 1} + qubit_map = {i0: 0, i1: 1} args = (cnot_i1_i0,) expected = (cnot_10,) actual = convert_to_real_indices(args, qubit_map) @@ -297,7 +303,7 @@ actual = convert_to_real_indices(args, qubit_map) assert actual == expected - qubit_map = {i0 : 1, i1 : 0} + qubit_map = {i0: 1, i1: 0} args = (cgate_z_i1_i0,) expected = (cgate_z_01,) actual = convert_to_real_indices(args, qubit_map) @@ -307,24 +313,25 @@ ccgate_z = CGate(i0, CGate(i1, Z(i2))) ccgate_x = CGate(i1, CGate(i2, X(i0))) - qubit_map = {i0 : 0, i1 : 1, i2 : 2} + qubit_map = {i0: 0, i1: 1, i2: 2} args = (ccgate_z, ccgate_x) expected = (CGate(0, CGate(1, Z(2))), CGate(1, CGate(2, X(0)))) actual = convert_to_real_indices(Mul(*args), qubit_map) assert actual == expected - qubit_map = {i0 : 1, i2 : 0, i1 : 2} + qubit_map = {i0: 1, i2: 0, i1: 2} args = (ccgate_x, ccgate_z) expected = (CGate(2, CGate(0, X(1))), CGate(1, CGate(2, Z(0)))) actual = convert_to_real_indices(args, qubit_map) assert actual == expected + def test_random_reduce(): x = X(0) y = Y(0) z = Z(0) h = H(0) - cnot = CNOT(1,0) + cnot = CNOT(1, 0) cgate_z = CGate((0,), Z(1)) gate_list = [x, y, z] @@ -354,6 +361,7 @@ circuit = Mul(*circuit) assert random_reduce(circuit, ids, seed=seq) == expected + def test_random_insert(): x = X(0) y = Y(0) @@ -362,7 +370,6 @@ cnot = CNOT(1, 0) cgate_z = CGate((0,), Z(1)) - choices = [(x, x)] circuit = (y, y) loc, choice = 0, 0 diff -Nru python3-sympy-0.7.2/sympy/physics/quantum/tests/test_commutator.py python3-sympy-0.7.3/sympy/physics/quantum/tests/test_commutator.py --- python3-sympy-0.7.2/sympy/physics/quantum/tests/test_commutator.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/physics/quantum/tests/test_commutator.py 2013-07-13 17:53:32.000000000 +0000 @@ -10,14 +10,14 @@ def test_commutator(): - c = Comm(A,B) - assert c.is_commutative == False + c = Comm(A, B) + assert c.is_commutative is False assert isinstance(c, Comm) - assert c.subs(A,C) == Comm(C,B) + assert c.subs(A, C) == Comm(C, B) def test_commutator_identities(): - assert Comm(a*A,b*B) == a*b*Comm(A,B) + assert Comm(a*A, b*B) == a*b*Comm(A, B) assert Comm(A, A) == 0 assert Comm(a, b) == 0 assert Comm(A, B) == -Comm(B, A) @@ -28,15 +28,15 @@ assert Comm(A + B, C + D).expand(commutator=True) == \ Comm(A, C) + Comm(A, D) + Comm(B, C) + Comm(B, D) assert Comm(A, B + C).expand(commutator=True) == Comm(A, B) + Comm(A, C) - e = Comm(A, Comm(B, C))+Comm(B, Comm(C, A)) + Comm(C, Comm(A, B)) + e = Comm(A, Comm(B, C)) + Comm(B, Comm(C, A)) + Comm(C, Comm(A, B)) assert e.doit().expand() == 0 def test_commutator_dagger(): - comm = Comm(A*B,C) - assert Dagger(comm).expand(commutator=True) ==\ - - Comm(Dagger(B),Dagger(C))*Dagger(A) -\ - Dagger(B)*Comm(Dagger(A),Dagger(C)) + comm = Comm(A*B, C) + assert Dagger(comm).expand(commutator=True) == \ + - Comm(Dagger(B), Dagger(C))*Dagger(A) - \ + Dagger(B)*Comm(Dagger(A), Dagger(C)) class Foo(Operator): @@ -59,8 +59,8 @@ F = Foo('F') B = Bar('B') T = Tam('T') - assert Comm(F,B).doit() == 0 - assert Comm(B,F).doit() == 0 - assert Comm(F,T).doit() == -1 - assert Comm(T,F).doit() == 1 - assert Comm(B,T).doit() == B*T - T*B + assert Comm(F, B).doit() == 0 + assert Comm(B, F).doit() == 0 + assert Comm(F, T).doit() == -1 + assert Comm(T, F).doit() == 1 + assert Comm(B, T).doit() == B*T - T*B diff -Nru python3-sympy-0.7.2/sympy/physics/quantum/tests/test_constants.py python3-sympy-0.7.3/sympy/physics/quantum/tests/test_constants.py --- python3-sympy-0.7.2/sympy/physics/quantum/tests/test_constants.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/physics/quantum/tests/test_constants.py 2013-07-13 17:53:32.000000000 +0000 @@ -2,11 +2,12 @@ from sympy.physics.quantum.constants import hbar + def test_hbar(): - assert hbar.is_commutative == True - assert hbar.is_real == True - assert hbar.is_positive == True - assert hbar.is_negative == False - assert hbar.is_irrational == True + assert hbar.is_commutative is True + assert hbar.is_real is True + assert hbar.is_positive is True + assert hbar.is_negative is False + assert hbar.is_irrational is True assert hbar.evalf() == Float(1.05457162e-34) diff -Nru python3-sympy-0.7.2/sympy/physics/quantum/tests/test_dagger.py python3-sympy-0.7.3/sympy/physics/quantum/tests/test_dagger.py --- python3-sympy-0.7.2/sympy/physics/quantum/tests/test_dagger.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/physics/quantum/tests/test_dagger.py 2013-07-13 17:53:32.000000000 +0000 @@ -6,11 +6,11 @@ def test_scalars(): - x = symbols('x',complex=True) + x = symbols('x', complex=True) assert Dagger(x) == conjugate(x) assert Dagger(I*x) == -I*conjugate(x) - i = symbols('i',real=True) + i = symbols('i', real=True) assert Dagger(i) == i p = symbols('p') @@ -20,12 +20,12 @@ assert Dagger(i) == i A = symbols('A', commutative=False) - assert Dagger(A).is_commutative == False + assert Dagger(A).is_commutative is False def test_matrix(): x = symbols('x') - m = Matrix([[I,x*I],[2,4]]) + m = Matrix([[I, x*I], [2, 4]]) assert Dagger(m) == m.H @@ -42,16 +42,18 @@ np = import_module('numpy', min_python_version=(2, 6)) + def test_numpy_dagger(): if not np: skip("numpy not installed or Python too old.") - a = np.matrix([[1.0,2.0j],[-1.0j,2.0]]) + a = np.matrix([[1.0, 2.0j], [-1.0j, 2.0]]) adag = a.copy().transpose().conjugate() assert (Dagger(a) == adag).all() -scipy = import_module('scipy', __import__kwargs={'fromlist':['sparse']}) +scipy = import_module('scipy', __import__kwargs={'fromlist': ['sparse']}) + def test_scipy_sparse_dagger(): if not np: @@ -61,6 +63,6 @@ else: sparse = scipy.sparse - a = sparse.csr_matrix([[1.0+0.0j,2.0j],[-1.0j,2.0+0.0j]]) + a = sparse.csr_matrix([[1.0 + 0.0j, 2.0j], [-1.0j, 2.0 + 0.0j]]) adag = a.copy().transpose().conjugate() assert np.linalg.norm((Dagger(a) - adag).todense()) == 0.0 diff -Nru python3-sympy-0.7.2/sympy/physics/quantum/tests/test_density.py python3-sympy-0.7.3/sympy/physics/quantum/tests/test_density.py --- python3-sympy-0.7.2/sympy/physics/quantum/tests/test_density.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/physics/quantum/tests/test_density.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,5 +1,5 @@ from sympy import pprint, latex, symbols, S, log -from sympy.matrices.matrices import Matrix +from sympy.matrices import Matrix from sympy.core.trace import Tr from sympy.external import import_module from sympy.physics.quantum.density import Density, entropy, fidelity @@ -32,70 +32,68 @@ # check for value error, when prob is not provided raises(ValueError, lambda: Density([Ket(0)], [Ket(1)])) + def test_doit(): - x,y = symbols('x y') - A, B, C, D, E, F= symbols('A B C D E F', commutative=False) - d = Density([XKet(),0.5], [PxKet(),0.5]) + x, y = symbols('x y') + A, B, C, D, E, F = symbols('A B C D E F', commutative=False) + d = Density([XKet(), 0.5], [PxKet(), 0.5]) assert (0.5*(PxKet()*Dagger(PxKet())) + 0.5*(XKet()*Dagger(XKet()))) == d.doit() # check for kets with expr in them - d_with_sym = Density([XKet(x*y),0.5], [PxKet(x*y),0.5]) + d_with_sym = Density([XKet(x*y), 0.5], [PxKet(x*y), 0.5]) assert (0.5*(PxKet(x*y)*Dagger(PxKet(x*y))) + 0.5*(XKet(x*y)*Dagger(XKet(x*y)))) == d_with_sym.doit() - - d = Density([(A+B)*C, 1.0]) + d = Density([(A + B)*C, 1.0]) assert d.doit() == (1.0*A*C*Dagger(C)*Dagger(A) + 1.0*A*C*Dagger(C)*Dagger(B) + 1.0*B*C*Dagger(C)*Dagger(A) + 1.0*B*C*Dagger(C)*Dagger(B)) - # With TensorProducts as args - # Density with simple tensor products as args t = TensorProduct(A, B, C) d = Density([t, 1.0]) - assert d.doit() == 1.0 * TensorProduct(A*Dagger(A), B*Dagger(B),C*Dagger(C)) + assert d.doit() == \ + 1.0 * TensorProduct(A*Dagger(A), B*Dagger(B), C*Dagger(C)) # Density with multiple Tensorproducts as states - t2 = TensorProduct(A,B) - t3 = TensorProduct(C,D) + t2 = TensorProduct(A, B) + t3 = TensorProduct(C, D) d = Density([t2, 0.5], [t3, 0.5]) assert d.doit() == (0.5 * TensorProduct(A*Dagger(A), B*Dagger(B)) + 0.5 * TensorProduct(C*Dagger(C), D*Dagger(D))) #Density with mixed states - d = Density([t2+t3,1.0]) + d = Density([t2 + t3, 1.0]) assert d.doit() == (1.0 * TensorProduct(A*Dagger(A), B*Dagger(B)) + 1.0 * TensorProduct(A*Dagger(C), B*Dagger(D)) + 1.0 * TensorProduct(C*Dagger(A), D*Dagger(B)) + 1.0 * TensorProduct(C*Dagger(C), D*Dagger(D))) - #Density operators with spin states - tp1 = TensorProduct(JzKet(1,1), JzKet(1,-1)) + tp1 = TensorProduct(JzKet(1, 1), JzKet(1, -1)) d = Density([tp1, 1]) # full trace - t = Tr(d); + t = Tr(d) assert t.doit() == 1 #Partial trace on density operators with spin states t = Tr(d, [0]) - assert t.doit() == JzKet(1,-1) * Dagger(JzKet(1,-1)) + assert t.doit() == JzKet(1, -1) * Dagger(JzKet(1, -1)) t = Tr(d, [1]) - assert t.doit() == JzKet(1,1) * Dagger(JzKet(1,1)) + assert t.doit() == JzKet(1, 1) * Dagger(JzKet(1, 1)) # with another spin state tp2 = TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, -S(1)/2)) d = Density([tp2, 1]) #full trace - t = Tr(d); + t = Tr(d) assert t.doit() == 1 #Partial trace on density operators with spin states @@ -104,19 +102,21 @@ t = Tr(d, [1]) assert t.doit() == JzKet(S(1)/2, S(1)/2) * Dagger(JzKet(S(1)/2, S(1)/2)) + def test_apply_op(): d = Density([Ket(0), 0.5], [Ket(1), 0.5]) assert d.apply_op(XOp()) == Density([XOp()*Ket(0), 0.5], - [XOp()*Ket(1), 0.5]) + [XOp()*Ket(1), 0.5]) + def test_represent(): - x,y = symbols('x y') - d = Density([XKet(),0.5], [PxKet(),0.5]) + x, y = symbols('x y') + d = Density([XKet(), 0.5], [PxKet(), 0.5]) assert (represent(0.5*(PxKet()*Dagger(PxKet()))) + represent(0.5*(XKet()*Dagger(XKet())))) == represent(d) # check for kets with expr in them - d_with_sym = Density([XKet(x*y),0.5], [PxKet(x*y),0.5]) + d_with_sym = Density([XKet(x*y), 0.5], [PxKet(x*y), 0.5]) assert (represent(0.5*(PxKet(x*y)*Dagger(PxKet(x*y)))) + represent(0.5*(XKet(x*y)*Dagger(XKet(x*y))))) == \ represent(d_with_sym) @@ -126,63 +126,72 @@ represent(0.5*(PxKet()*Dagger(PxKet())), basis=PxOp())) == \ represent(d, basis=PxOp()) + def test_states(): d = Density([Ket(0), 0.5], [Ket(1), 0.5]) states = d.states() assert states[0] == Ket(0) and states[1] == Ket(1) + def test_probs(): d = Density([Ket(0), .75], [Ket(1), 0.25]) probs = d.probs() assert probs[0] == 0.75 and probs[1] == 0.25 #probs can be symbols - x,y = symbols('x y') + x, y = symbols('x y') d = Density([Ket(0), x], [Ket(1), y]) probs = d.probs() assert probs[0] == x and probs[1] == y + def test_get_state(): - x,y = symbols('x y') + x, y = symbols('x y') d = Density([Ket(0), x], [Ket(1), y]) states = (d.get_state(0), d.get_state(1)) assert states[0] == Ket(0) and states[1] == Ket(1) + def test_get_prob(): - x,y = symbols('x y') + x, y = symbols('x y') d = Density([Ket(0), x], [Ket(1), y]) probs = (d.get_prob(0), d.get_prob(1)) assert probs[0] == x and probs[1] == y + def test_entropy(): - up = JzKet(S(1)/2,S(1)/2) - down = JzKet(S(1)/2,-S(1)/2) - d = Density((up,0.5),(down,0.5)) + up = JzKet(S(1)/2, S(1)/2) + down = JzKet(S(1)/2, -S(1)/2) + d = Density((up, 0.5), (down, 0.5)) # test for density object ent = entropy(d) assert entropy(d) == 0.5*log(2) assert d.entropy() == 0.5*log(2) - np = import_module('numpy', min_python_version=(2, 6), min_module_version='1.4.0') + np = import_module( + 'numpy', min_python_version=(2, 6), min_module_version='1.4.0') if np: #do this test only if 'numpy' is available on test machine np_mat = represent(d, format='numpy') ent = entropy(np_mat) - assert isinstance(np_mat, np.matrixlib.defmatrix.matrix) and \ - ent.real == 0.69314718055994529 and ent.imag == 0 + assert isinstance(np_mat, np.matrixlib.defmatrix.matrix) + assert ent.real == 0.69314718055994529 + assert ent.imag == 0 - scipy = import_module('scipy', __import__kwargs={'fromlist':['sparse']}) + scipy = import_module('scipy', __import__kwargs={'fromlist': ['sparse']}) if scipy and np: #do this test only if numpy and scipy are available mat = represent(d, format="scipy.sparse") - assert isinstance(mat, scipy_sparse_matrix) and ent.real == \ - 0.69314718055994529 and ent.imag == 0 + assert isinstance(mat, scipy_sparse_matrix) + assert ent.real == 0.69314718055994529 + assert ent.imag == 0 + def test_eval_trace(): - up = JzKet(S(1)/2,S(1)/2) - down = JzKet(S(1)/2,-S(1)/2) - d = Density((up,0.5),(down,0.5)) + up = JzKet(S(1)/2, S(1)/2) + down = JzKet(S(1)/2, -S(1)/2) + d = Density((up, 0.5), (down, 0.5)) t = Tr(d) assert t.doit() == 1 @@ -196,8 +205,8 @@ k1 = TestTimeDepKet(0, 0.5) k2 = TestTimeDepKet(0, 1) d = Density([k1, 0.5], [k2, 0.5]) - assert d.doit() == (0.5 * OuterProduct(k1, k1.dual()) + - 0.5 * OuterProduct(k2, k2.dual())) + assert d.doit() == (0.5 * OuterProduct(k1, k1.dual) + + 0.5 * OuterProduct(k2, k2.dual)) t = Tr(d) assert t.doit() == 1 @@ -236,7 +245,6 @@ assert abs(fidelity(d1, d2) - 0.991) < 1e-3 assert abs(fidelity(d2, d1) - fidelity(d1, d2)) < 1e-3 - #using qubits/density(pure states) state1 = Qubit('0') state2 = Qubit('1') @@ -255,7 +263,7 @@ #using qubits/density(mixed states) d1 = Density([state3, 0.70], [state4, 0.30]) d2 = Density([state3, 0.20], [state4, 0.80]) - assert abs(fidelity(d1, d1) - 1) < 1e-3 + assert abs(fidelity(d1, d1) - 1) < 1e-3 assert abs(fidelity(d1, d2) - 0.996) < 1e-3 assert abs(fidelity(d1, d2) - fidelity(d2, d1)) < 1e-3 @@ -278,5 +286,5 @@ raises(ValueError, lambda: fidelity(mat1, mat2)) # unsupported data-type - x, y = 1, 2 #random values that is not a matrix + x, y = 1, 2 # random values that is not a matrix raises(ValueError, lambda: fidelity(x, y)) diff -Nru python3-sympy-0.7.2/sympy/physics/quantum/tests/test_gate.py python3-sympy-0.7.3/sympy/physics/quantum/tests/test_gate.py --- python3-sympy-0.7.2/sympy/physics/quantum/tests/test_gate.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/physics/quantum/tests/test_gate.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,5 +1,5 @@ from sympy import exp, symbols, sqrt, I, pi, Mul, Integer, Wild -from sympy.matrices.matrices import Matrix +from sympy.matrices import Matrix from sympy.physics.quantum.gate import (XGate, YGate, ZGate, random_circuit, CNOT, IdentityGate, H, X, Y, S, T, Z, SwapGate, gate_simp, gate_sort, @@ -8,12 +8,13 @@ from sympy.physics.quantum.anticommutator import AntiCommutator from sympy.physics.quantum.represent import represent from sympy.physics.quantum.qapply import qapply -from sympy.physics.quantum.qubit import Qubit, IntQubit, qubit_to_matrix,\ - matrix_to_qubit +from sympy.physics.quantum.qubit import Qubit, IntQubit, qubit_to_matrix, \ + matrix_to_qubit from sympy.physics.quantum.matrixutils import matrix_to_zero from sympy.physics.quantum.matrixcache import sqrt2_inv from sympy.physics.quantum import Dagger + def test_gate(): """Test a basic gate.""" h = HadamardGate(1) @@ -38,13 +39,14 @@ assert cnot_10_w1 != cnot_01_w1 assert cnot_10_w2 != cnot_01_w1 + def test_UGate(): - a,b,c,d = symbols('a,b,c,d') - uMat = Matrix([[a,b],[c,d]]) + a, b, c, d = symbols('a,b,c,d') + uMat = Matrix([[a, b], [c, d]]) # Test basic case where gate exists in 1-qubit space u1 = UGate((0,), uMat) - assert represent(u1, nqubits = 1) == uMat + assert represent(u1, nqubits=1) == uMat assert qapply(u1*Qubit('0')) == a*Qubit('0') + c*Qubit('1') assert qapply(u1*Qubit('1')) == b*Qubit('0') + d*Qubit('1') @@ -52,44 +54,49 @@ u2 = UGate((1,), uMat) u2Rep = represent(u2, nqubits=2) for i in range(4): - assert u2Rep*qubit_to_matrix(IntQubit(i,2)) ==\ - qubit_to_matrix(qapply(u2*IntQubit(i,2))) + assert u2Rep*qubit_to_matrix(IntQubit(i, 2)) == \ + qubit_to_matrix(qapply(u2*IntQubit(i, 2))) def test_cgate(): """Test the general CGate.""" # Test single control functionality - CNOTMatrix = Matrix([[1,0,0,0],[0,1,0,0],[0,0,0,1],[0,0,1,0]]) + CNOTMatrix = Matrix( + [[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 0, 1], [0, 0, 1, 0]]) assert represent(CGate(1, XGate(0)), nqubits=2) == CNOTMatrix # Test multiple control bit functionality - ToffoliGate = CGate((1,2), XGate(0)) + ToffoliGate = CGate((1, 2), XGate(0)) assert represent(ToffoliGate, nqubits=3) == \ - Matrix([[1,0,0,0,0,0,0,0],[0,1,0,0,0,0,0,0],[0,0,1,0,0,0,0,0],\ - [0,0,0,1,0,0,0,0],[0,0,0,0,1,0,0,0],[0,0,0,0,0,1,0,0],[0,0,0,0,0,0,0,1],\ - [0,0,0,0,0,0,1,0]]) + Matrix( + [[1, 0, 0, 0, 0, 0, 0, 0], [0, 1, 0, 0, 0, 0, 0, 0], [0, 0, 1, 0, 0, 0, 0, 0], + [0, 0, 0, 1, 0, 0, 0, 0], [0, 0, 0, 0, 1, 0, 0, 0], [0, 0, 0, 0, 0, + 1, 0, 0], [0, 0, 0, 0, 0, 0, 0, 1], + [0, 0, 0, 0, 0, 0, 1, 0]]) - ToffoliGate = CGate((3,0), XGate(1)) + ToffoliGate = CGate((3, 0), XGate(1)) assert qapply(ToffoliGate*Qubit('1001')) == \ - matrix_to_qubit(represent(ToffoliGate*Qubit('1001'), nqubits=4)) + matrix_to_qubit(represent(ToffoliGate*Qubit('1001'), nqubits=4)) assert qapply(ToffoliGate*Qubit('0000')) == \ - matrix_to_qubit(represent(ToffoliGate*Qubit('0000'), nqubits=4)) + matrix_to_qubit(represent(ToffoliGate*Qubit('0000'), nqubits=4)) CYGate = CGate(1, YGate(0)) - CYGate_matrix = Matrix(((1,0,0,0),(0,1,0,0),(0,0,0,-I),(0,0,I,0))) + CYGate_matrix = Matrix( + ((1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 0, -I), (0, 0, I, 0))) # Test 2 qubit controlled-Y gate decompose method. assert represent(CYGate.decompose(), nqubits=2) == CYGate_matrix CZGate = CGate(0, ZGate(1)) - CZGate_matrix = Matrix(((1,0,0,0),(0,1,0,0),(0,0,1,0),(0,0,0,-1))) + CZGate_matrix = Matrix( + ((1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0), (0, 0, 0, -1))) assert qapply(CZGate*Qubit('11')) == -Qubit('11') - assert matrix_to_qubit(represent(CZGate*Qubit('11'),nqubits=2)) ==\ + assert matrix_to_qubit(represent(CZGate*Qubit('11'), nqubits=2)) == \ -Qubit('11') # Test 2 qubit controlled-Z gate decompose method. assert represent(CZGate.decompose(), nqubits=2) == CZGate_matrix CPhaseGate = CGate(0, PhaseGate(1)) - assert qapply(CPhaseGate*Qubit('11')) ==\ + assert qapply(CPhaseGate*Qubit('11')) == \ I*Qubit('11') assert matrix_to_qubit(represent(CPhaseGate*Qubit('11'), nqubits=2)) == \ I*Qubit('11') @@ -103,15 +110,16 @@ assert Dagger(CPhaseGate) == pow(CPhaseGate, -1) assert pow(CPhaseGate, -1) == CPhaseGate.inverse() + def test_UGate_CGate_combo(): - a,b,c,d = symbols('a,b,c,d') - uMat = Matrix([[a,b],[c,d]]) - cMat = Matrix([[1,0,0,0],[0,1,0,0],[0,0,a,b],[0,0,c,d]]) + a, b, c, d = symbols('a,b,c,d') + uMat = Matrix([[a, b], [c, d]]) + cMat = Matrix([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, a, b], [0, 0, c, d]]) # Test basic case where gate exists in 1-qubit space. u1 = UGate((0,), uMat) cu1 = CGate(1, u1) - assert represent(cu1, nqubits = 2) == cMat + assert represent(cu1, nqubits=2) == cMat assert qapply(cu1*Qubit('10')) == a*Qubit('10') + c*Qubit('11') assert qapply(cu1*Qubit('11')) == b*Qubit('10') + d*Qubit('11') assert qapply(cu1*Qubit('01')) == Qubit('01') @@ -121,8 +129,8 @@ u2 = UGate((1,), uMat) u2Rep = represent(u2, nqubits=2) for i in range(4): - assert u2Rep*qubit_to_matrix(IntQubit(i,2)) ==\ - qubit_to_matrix(qapply(u2*IntQubit(i,2))) + assert u2Rep*qubit_to_matrix(IntQubit(i, 2)) == \ + qubit_to_matrix(qapply(u2*IntQubit(i, 2))) def test_represent_hadamard(): @@ -132,6 +140,7 @@ # Check that the answers are same to within an epsilon. assert answer == Matrix([sqrt2_inv, sqrt2_inv, 0, 0]) + def test_represent_xgate(): """Test the representation of the X gate.""" circuit = XGate(0)*Qubit('00') @@ -144,7 +153,7 @@ circuit = YGate(0)*Qubit('00') answer = represent(circuit, nqubits=2) assert answer[0] == 0 and answer[1] == I and \ - answer[2] == 0 and answer[3] == 0 + answer[2] == 0 and answer[3] == 0 def test_represent_zgate(): @@ -158,7 +167,7 @@ """Test the representation of the S gate.""" circuit = PhaseGate(0)*Qubit('01') answer = represent(circuit, nqubits=2) - assert Matrix([0, I,0,0]) == answer + assert Matrix([0, I, 0, 0]) == answer def test_represent_tgate(): @@ -171,29 +180,30 @@ """Test a compound gate representation.""" circuit = YGate(0)*ZGate(0)*XGate(0)*HadamardGate(0)*Qubit('00') answer = represent(circuit, nqubits=2) - assert Matrix([I/sqrt(2),I/sqrt(2), 0, 0]) == answer + assert Matrix([I/sqrt(2), I/sqrt(2), 0, 0]) == answer def test_cnot_gate(): """Test the CNOT gate.""" - circuit = CNotGate(1,0) - assert represent(circuit, nqubits=2) ==\ - Matrix([[1,0,0,0],[0,1,0,0],[0,0,0,1],[0,0,1,0]]) + circuit = CNotGate(1, 0) + assert represent(circuit, nqubits=2) == \ + Matrix([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 0, 1], [0, 0, 1, 0]]) circuit = circuit*Qubit('111') - assert matrix_to_qubit(represent(circuit, nqubits=3)) ==\ + assert matrix_to_qubit(represent(circuit, nqubits=3)) == \ qapply(circuit) - circuit = CNotGate(1,0) + circuit = CNotGate(1, 0) assert Dagger(circuit) == circuit assert Dagger(Dagger(circuit)) == circuit assert circuit*circuit == 1 + def test_gate_sort(): """Test gate_sort.""" for g in (X, Y, Z, H, S, T): assert gate_sort(g(2)*g(1)*g(0)) == g(0)*g(1)*g(2) - e = gate_sort(X(1)*H(0)**2*CNOT(0,1)*X(1)*X(0)) - assert e == H(0)**2*CNOT(0,1)*X(0)*X(1)**2 + e = gate_sort(X(1)*H(0)**2*CNOT(0, 1)*X(1)*X(0)) + assert e == H(0)**2*CNOT(0, 1)*X(0)*X(1)**2 assert gate_sort(Z(0)*X(0)) == -X(0)*Z(0) assert gate_sort(Z(0)*X(0)**2) == X(0)**2*Z(0) assert gate_sort(Y(0)*H(0)) == -H(0)*Y(0) @@ -202,24 +212,24 @@ assert gate_sort(T(0)*S(0)) == S(0)*T(0) assert gate_sort(Z(0)*S(0)) == S(0)*Z(0) assert gate_sort(Z(0)*T(0)) == T(0)*Z(0) - assert gate_sort(Z(0)*CNOT(0,1)) == CNOT(0,1)*Z(0) - assert gate_sort(S(0)*CNOT(0,1)) == CNOT(0,1)*S(0) - assert gate_sort(T(0)*CNOT(0,1)) == CNOT(0,1)*T(0) - assert gate_sort(X(1)*CNOT(0,1)) == CNOT(0,1)*X(1) + assert gate_sort(Z(0)*CNOT(0, 1)) == CNOT(0, 1)*Z(0) + assert gate_sort(S(0)*CNOT(0, 1)) == CNOT(0, 1)*S(0) + assert gate_sort(T(0)*CNOT(0, 1)) == CNOT(0, 1)*T(0) + assert gate_sort(X(1)*CNOT(0, 1)) == CNOT(0, 1)*X(1) # This takes a long time and should only be uncommented once in a while. # nqubits = 5 # ngates = 10 # trials = 10 # for i in range(trials): # c = random_circuit(ngates, nqubits) - # assert represent(c, nqubits=nqubits) ==\ + # assert represent(c, nqubits=nqubits) == \ # represent(gate_sort(c), nqubits=nqubits) def test_gate_simp(): """Test gate_simp.""" - e = H(0)*X(1)*H(0)**2*CNOT(0,1)*X(1)**3*X(0)*Z(3)**2*S(4)**3 - assert gate_simp(e) == H(0)*CNOT(0,1)*S(4)*X(0)*Z(4) + e = H(0)*X(1)*H(0)**2*CNOT(0, 1)*X(1)**3*X(0)*Z(3)**2*S(4)**3 + assert gate_simp(e) == H(0)*CNOT(0, 1)*S(4)*X(0)*Z(4) assert gate_simp(X(0)*X(0)) == 1 assert gate_simp(Y(0)*Y(0)) == 1 assert gate_simp(Z(0)*Z(0)) == 1 @@ -232,36 +242,39 @@ def test_swap_gate(): """Test the SWAP gate.""" - swap_gate_matrix = Matrix(((1,0,0,0),(0,0,1,0),(0,1,0,0),(0,0,0,1))) - assert represent(SwapGate(1,0).decompose(), nqubits=2) == swap_gate_matrix - assert qapply(SwapGate(1,3)*Qubit('0010')) == Qubit('1000') + swap_gate_matrix = Matrix( + ((1, 0, 0, 0), (0, 0, 1, 0), (0, 1, 0, 0), (0, 0, 0, 1))) + assert represent(SwapGate(1, 0).decompose(), nqubits=2) == swap_gate_matrix + assert qapply(SwapGate(1, 3)*Qubit('0010')) == Qubit('1000') nqubits = 4 for i in range(nqubits): for j in range(i): - assert represent(SwapGate(i,j), nqubits=nqubits) ==\ - represent(SwapGate(i,j).decompose(), nqubits=nqubits) + assert represent(SwapGate(i, j), nqubits=nqubits) == \ + represent(SwapGate(i, j).decompose(), nqubits=nqubits) + def test_one_qubit_commutators(): """Test single qubit gate commutation relations.""" for g1 in (IdentityGate, X, Y, Z, H, T, S): for g2 in (IdentityGate, X, Y, Z, H, T, S): - e = Commutator(g1(0),g2(0)) + e = Commutator(g1(0), g2(0)) a = matrix_to_zero(represent(e, nqubits=1, format='sympy')) b = matrix_to_zero(represent(e.doit(), nqubits=1, format='sympy')) assert a == b - e = Commutator(g1(0),g2(1)) + e = Commutator(g1(0), g2(1)) assert e.doit() == 0 + def test_one_qubit_anticommutators(): """Test single qubit gate anticommutation relations.""" for g1 in (IdentityGate, X, Y, Z, H): for g2 in (IdentityGate, X, Y, Z, H): - e = AntiCommutator(g1(0),g2(0)) + e = AntiCommutator(g1(0), g2(0)) a = matrix_to_zero(represent(e, nqubits=1, format='sympy')) b = matrix_to_zero(represent(e.doit(), nqubits=1, format='sympy')) assert a == b - e = AntiCommutator(g1(0),g2(1)) + e = AntiCommutator(g1(0), g2(1)) a = matrix_to_zero(represent(e, nqubits=2, format='sympy')) b = matrix_to_zero(represent(e.doit(), nqubits=2, format='sympy')) assert a == b @@ -269,53 +282,59 @@ def test_cnot_commutators(): """Test commutators of involving CNOT gates.""" - assert Commutator(CNOT(0,1),Z(0)).doit() == 0 - assert Commutator(CNOT(0,1),T(0)).doit() == 0 - assert Commutator(CNOT(0,1),S(0)).doit() == 0 - assert Commutator(CNOT(0,1),X(1)).doit() == 0 - assert Commutator(CNOT(0,1),CNOT(0,1)).doit() == 0 - assert Commutator(CNOT(0,1),CNOT(0,2)).doit() == 0 - assert Commutator(CNOT(0,2),CNOT(0,1)).doit() == 0 - assert Commutator(CNOT(1,2),CNOT(1,0)).doit() == 0 + assert Commutator(CNOT(0, 1), Z(0)).doit() == 0 + assert Commutator(CNOT(0, 1), T(0)).doit() == 0 + assert Commutator(CNOT(0, 1), S(0)).doit() == 0 + assert Commutator(CNOT(0, 1), X(1)).doit() == 0 + assert Commutator(CNOT(0, 1), CNOT(0, 1)).doit() == 0 + assert Commutator(CNOT(0, 1), CNOT(0, 2)).doit() == 0 + assert Commutator(CNOT(0, 2), CNOT(0, 1)).doit() == 0 + assert Commutator(CNOT(1, 2), CNOT(1, 0)).doit() == 0 def test_random_circuit(): - c = random_circuit(10,3) + c = random_circuit(10, 3) assert isinstance(c, Mul) m = represent(c, nqubits=3) - assert m.shape == (8,8) + assert m.shape == (8, 8) assert isinstance(m, Matrix) + def test_hermitian_XGate(): x = XGate(1, 2) x_dagger = Dagger(x) assert (x == x_dagger) + def test_hermitian_YGate(): y = YGate(1, 2) y_dagger = Dagger(y) assert (y == y_dagger) + def test_hermitian_ZGate(): z = ZGate(1, 2) z_dagger = Dagger(z) assert (z == z_dagger) + def test_unitary_XGate(): x = XGate(1, 2) x_dagger = Dagger(x) assert (x*x_dagger == 1) + def test_unitary_YGate(): y = YGate(1, 2) y_dagger = Dagger(y) assert (y*y_dagger == 1) + def test_unitary_ZGate(): z = ZGate(1, 2) z_dagger = Dagger(z) diff -Nru python3-sympy-0.7.2/sympy/physics/quantum/tests/test_grover.py python3-sympy-0.7.3/sympy/physics/quantum/tests/test_grover.py --- python3-sympy-0.7.2/sympy/physics/quantum/tests/test_grover.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/physics/quantum/tests/test_grover.py 2013-07-13 17:53:32.000000000 +0000 @@ -4,12 +4,15 @@ from sympy.physics.quantum.grover import (apply_grover, superposition_basis, OracleGate, grover_iteration, WGate) + def return_one_on_two(qubits): return qubits == IntQubit(2, qubits.nqubits) + def return_one_on_one(qubits): return qubits == IntQubit(1, qubits.nqubits) + def test_superposition_basis(): nbits = 2 first_half_state = IntQubit(0, nbits)/2 + IntQubit(1, nbits)/2 @@ -23,6 +26,7 @@ fourthq = (1/sqrt(8))*IntQubit(6, nbits) + (1/sqrt(8))*IntQubit(7, nbits) assert firstq + secondq + thirdq + fourthq == superposition_basis(nbits) + def test_OracleGate(): v = OracleGate(1, lambda qubits: qubits == IntQubit(0)) assert qapply(v*IntQubit(0)) == -IntQubit(0) @@ -35,6 +39,7 @@ assert qapply(v*IntQubit(2, nbits)) == -IntQubit(2, nbits) assert qapply(v*IntQubit(3, nbits)) == IntQubit(3, nbits) + def test_WGate(): nqubits = 2 basis_states = superposition_basis(nqubits) @@ -43,6 +48,7 @@ expected = ((2/sqrt(pow(2, nqubits)))*basis_states) - IntQubit(1, nqubits) assert qapply(WGate(nqubits)*IntQubit(1, nqubits)) == expected + def test_grover_iteration_1(): numqubits = 2 basis_states = superposition_basis(numqubits) @@ -50,6 +56,7 @@ expected = IntQubit(1, numqubits) assert qapply(grover_iteration(basis_states, v)) == expected + def test_grover_iteration_2(): numqubits = 4 basis_states = superposition_basis(numqubits) @@ -73,6 +80,7 @@ expected = (-13*basis_states)/64 + 264*IntQubit(2, numqubits)/256 assert qapply(expected) == iterated + def test_grover(): nqubits = 2 assert apply_grover(return_one_on_one, nqubits) == IntQubit(1, nqubits) diff -Nru python3-sympy-0.7.2/sympy/physics/quantum/tests/test_hilbert.py python3-sympy-0.7.3/sympy/physics/quantum/tests/test_hilbert.py --- python3-sympy-0.7.2/sympy/physics/quantum/tests/test_hilbert.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/physics/quantum/tests/test_hilbert.py 2013-07-13 17:53:32.000000000 +0000 @@ -5,12 +5,14 @@ from sympy import Interval, oo, Symbol, sstr, srepr + def test_hilbert_space(): hs = HilbertSpace() assert isinstance(hs, HilbertSpace) assert sstr(hs) == 'H' assert srepr(hs) == 'HilbertSpace()' + def test_complex_space(): c1 = ComplexSpace(2) assert isinstance(c1, ComplexSpace) @@ -24,7 +26,8 @@ assert c2.dimension == n assert sstr(c2) == 'C(n)' assert srepr(c2) == "ComplexSpace(Symbol('n'))" - assert c2.subs(n,2) == ComplexSpace(2) + assert c2.subs(n, 2) == ComplexSpace(2) + def test_L2(): b1 = L2(Interval(-oo, 1)) @@ -34,10 +37,11 @@ x = Symbol('x', real=True) y = Symbol('y', real=True) - b2 = L2(Interval(x,y)) + b2 = L2(Interval(x, y)) assert b2.dimension == oo - assert b2.interval == Interval(x,y) - assert b2.subs(x,-1) == L2(Interval(-1,y)) + assert b2.interval == Interval(x, y) + assert b2.subs(x, -1) == L2(Interval(-1, y)) + def test_fock_space(): f1 = FockSpace() @@ -46,6 +50,7 @@ assert f1.dimension == oo assert f1 == f2 + def test_tensor_product(): n = Symbol('n') hs1 = ComplexSpace(2) @@ -66,6 +71,7 @@ h = hs1*hs2*f assert h.dimension == oo + def test_tensor_power(): n = Symbol('n') hs1 = ComplexSpace(2) @@ -83,14 +89,15 @@ assert h.exp == 3 assert h.dimension == n**3 + def test_direct_sum(): n = Symbol('n') hs1 = ComplexSpace(2) hs2 = ComplexSpace(n) - h = hs1+hs2 + h = hs1 + hs2 assert isinstance(h, DirectSumHilbertSpace) - assert h.dimension == 2+n + assert h.dimension == 2 + n assert h.spaces == (hs1, hs2) f = FockSpace() diff -Nru python3-sympy-0.7.2/sympy/physics/quantum/tests/test_identitysearch.py python3-sympy-0.7.3/sympy/physics/quantum/tests/test_identitysearch.py --- python3-sympy-0.7.2/sympy/physics/quantum/tests/test_identitysearch.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/physics/quantum/tests/test_identitysearch.py 2013-07-13 17:53:32.000000000 +0000 @@ -9,10 +9,12 @@ is_scalar_nonsparse_matrix, is_degenerate, is_reducible) from sympy.utilities.pytest import skip + def create_gate_sequence(qubit=0): gates = (X(qubit), Y(qubit), Z(qubit), H(qubit)) return gates + def test_generate_gate_rules_1(): # Test with tuples (x, y, z, h) = create_gate_sequence() @@ -21,32 +23,33 @@ assert generate_gate_rules((x,)) == set([((x,), ())]) - gate_rules = set([((x,x), ()), + gate_rules = set([((x, x), ()), ((x,), (x,))]) assert generate_gate_rules((x, x)) == gate_rules - gate_rules = set([((x,y,x), ()), - ((y,x,x), ()), - ((x,x,y), ()), - ((y,x), (x,)), - ((x,y), (x,)), - ((y,), (x,x))]) + gate_rules = set([((x, y, x), ()), + ((y, x, x), ()), + ((x, x, y), ()), + ((y, x), (x,)), + ((x, y), (x,)), + ((y,), (x, x))]) assert generate_gate_rules((x, y, x)) == gate_rules - gate_rules = set([((x,y,z), ()), ((y,z,x), ()), ((z,x,y), ()), - ((), (x,z,y)), ((), (y,x,z)), ((), (z,y,x)), - ((x,), (z,y)), ((y,z), (x,)), ((y,), (x,z)), - ((z,x), (y,)), ((z,), (y,x)), ((x,y), (z,))]) + gate_rules = set([((x, y, z), ()), ((y, z, x), ()), ((z, x, y), ()), + ((), (x, z, y)), ((), (y, x, z)), ((), (z, y, x)), + ((x,), (z, y)), ((y, z), (x,)), ((y,), (x, z)), + ((z, x), (y,)), ((z,), (y, x)), ((x, y), (z,))]) actual = generate_gate_rules((x, y, z)) assert actual == gate_rules - gate_rules = set([((), (h,z,y,x)), ((), (x,h,z,y)), ((), (y,x,h,z)), - ((), (z,y,x,h)), ((h,), (z,y,x)), ((x,), (h,z,y)), - ((y,), (x,h,z)), ((z,), (y,x,h)), ((h,x), (z,y)), - ((x,y), (h,z)), ((y,z), (x,h)), ((z,h), (y,x)), - ((h,x,y), (z,)), ((x,y,z), (h,)), ((y,z,h), (x,)), - ((z,h,x), (y,)), ((h,x,y,z), ()), ((x,y,z,h), ()), - ((y,z,h,x), ()), ((z,h,x,y), ())]) + gate_rules = set( + [((), (h, z, y, x)), ((), (x, h, z, y)), ((), (y, x, h, z)), + ((), (z, y, x, h)), ((h,), (z, y, x)), ((x,), (h, z, y)), + ((y,), (x, h, z)), ((z,), (y, x, h)), ((h, x), (z, y)), + ((x, y), (h, z)), ((y, z), (x, h)), ((z, h), (y, x)), + ((h, x, y), (z,)), ((x, y, z), (h,)), ((y, z, h), (x,)), + ((z, h, x), (y,)), ((h, x, y, z), ()), ((x, y, z, h), ()), + ((y, z, h, x), ()), ((z, h, x, y), ())]) actual = generate_gate_rules((x, y, z, h)) assert actual == gate_rules @@ -80,6 +83,7 @@ actual = generate_gate_rules((x, ph, cgate_t), return_as_muls=True) assert actual == gate_rules + def test_generate_gate_rules_2(): # Test with Muls (x, y, z, h) = create_gate_sequence() @@ -164,12 +168,13 @@ actual = generate_gate_rules(x*ph*cgate_t) assert actual == gate_rules + def test_generate_equivalent_ids_1(): # Test with tuples (x, y, z, h) = create_gate_sequence() assert generate_equivalent_ids((x,)) == set([(x,)]) - assert generate_equivalent_ids((x, x)) == set([(x,x)]) + assert generate_equivalent_ids((x, x)) == set([(x, x)]) assert generate_equivalent_ids((x, y)) == set([(x, y), (y, x)]) gate_seq = (x, y, z) @@ -185,7 +190,7 @@ gate_ids = set([(x, y, z, h), (y, z, h, x), (h, x, y, z), (h, z, y, x), (z, y, x, h), (y, x, h, z), - (z, h, x, y) ,(x, h, z, y)]) + (z, h, x, y), (x, h, z, y)]) assert generate_equivalent_ids(gate_seq) == gate_ids gate_seq = (x, y, x, y) @@ -197,13 +202,14 @@ gate_ids = set([(y, cgate_y, y, cgate_y), (cgate_y, y, cgate_y, y)]) assert generate_equivalent_ids(gate_seq) == gate_ids - cnot = CNOT(1,0) + cnot = CNOT(1, 0) cgate_z = CGate((0,), Z(1)) gate_seq = (cnot, h, cgate_z, h) gate_ids = set([(cnot, h, cgate_z, h), (h, cgate_z, h, cnot), (h, cnot, h, cgate_z), (cgate_z, h, cnot, h)]) assert generate_equivalent_ids(gate_seq) == gate_ids + def test_generate_equivalent_ids_2(): # Test with Muls (x, y, z, h) = create_gate_sequence() @@ -240,68 +246,70 @@ gate_ids = set([y*cgate_y*y*cgate_y, cgate_y*y*cgate_y*y]) assert generate_equivalent_ids(circuit, return_as_muls=True) == gate_ids - cnot = CNOT(1,0) + cnot = CNOT(1, 0) cgate_z = CGate((0,), Z(1)) circuit = Mul(*(cnot, h, cgate_z, h)) gate_ids = set([cnot*h*cgate_z*h, h*cgate_z*h*cnot, h*cnot*h*cgate_z, cgate_z*h*cnot*h]) assert generate_equivalent_ids(circuit, return_as_muls=True) == gate_ids + def test_is_scalar_nonsparse_matrix(): numqubits = 2 id_only = False id_gate = (IdentityGate(1),) actual = is_scalar_nonsparse_matrix(id_gate, numqubits, id_only) - assert actual == True + assert actual is True x0 = X(0) xx_circuit = (x0, x0) actual = is_scalar_nonsparse_matrix(xx_circuit, numqubits, id_only) - assert actual == True + assert actual is True x1 = X(1) y1 = Y(1) xy_circuit = (x1, y1) actual = is_scalar_nonsparse_matrix(xy_circuit, numqubits, id_only) - assert actual == False + assert actual is False z1 = Z(1) xyz_circuit = (x1, y1, z1) actual = is_scalar_nonsparse_matrix(xyz_circuit, numqubits, id_only) - assert actual == True + assert actual is True - cnot = CNOT(1,0) + cnot = CNOT(1, 0) cnot_circuit = (cnot, cnot) actual = is_scalar_nonsparse_matrix(cnot_circuit, numqubits, id_only) - assert actual == True + assert actual is True h = H(0) hh_circuit = (h, h) actual = is_scalar_nonsparse_matrix(hh_circuit, numqubits, id_only) - assert actual == True + assert actual is True h1 = H(1) xhzh_circuit = (x1, h1, z1, h1) actual = is_scalar_nonsparse_matrix(xhzh_circuit, numqubits, id_only) - assert actual == True + assert actual is True id_only = True actual = is_scalar_nonsparse_matrix(xhzh_circuit, numqubits, id_only) - assert actual == True + assert actual is True actual = is_scalar_nonsparse_matrix(xyz_circuit, numqubits, id_only) - assert actual == False + assert actual is False actual = is_scalar_nonsparse_matrix(cnot_circuit, numqubits, id_only) - assert actual == True + assert actual is True actual = is_scalar_nonsparse_matrix(hh_circuit, numqubits, id_only) - assert actual == True + assert actual is True + def test_is_scalar_sparse_matrix(): np = import_module('numpy', min_python_version=(2, 6)) if not np: skip("numpy not installed or Python too old.") - scipy = import_module('scipy', __import__kwargs={'fromlist':['sparse']}) + scipy = import_module('scipy', __import__kwargs={'fromlist': ['sparse']}) if not scipy: skip("scipy not installed.") @@ -309,41 +317,42 @@ id_only = False id_gate = (IdentityGate(1),) - assert is_scalar_sparse_matrix(id_gate, numqubits, id_only) == True + assert is_scalar_sparse_matrix(id_gate, numqubits, id_only) is True x0 = X(0) xx_circuit = (x0, x0) - assert is_scalar_sparse_matrix(xx_circuit, numqubits, id_only) == True + assert is_scalar_sparse_matrix(xx_circuit, numqubits, id_only) is True x1 = X(1) y1 = Y(1) xy_circuit = (x1, y1) - assert is_scalar_sparse_matrix(xy_circuit, numqubits, id_only) == False + assert is_scalar_sparse_matrix(xy_circuit, numqubits, id_only) is False z1 = Z(1) xyz_circuit = (x1, y1, z1) - assert is_scalar_sparse_matrix(xyz_circuit, numqubits, id_only) == True + assert is_scalar_sparse_matrix(xyz_circuit, numqubits, id_only) is True - cnot = CNOT(1,0) + cnot = CNOT(1, 0) cnot_circuit = (cnot, cnot) - assert is_scalar_sparse_matrix(cnot_circuit, numqubits, id_only) == True + assert is_scalar_sparse_matrix(cnot_circuit, numqubits, id_only) is True h = H(0) hh_circuit = (h, h) - assert is_scalar_sparse_matrix(hh_circuit, numqubits, id_only) == True + assert is_scalar_sparse_matrix(hh_circuit, numqubits, id_only) is True # NOTE: # The elements of the sparse matrix for the following circuit # is actually 1.0000000000000002+0.0j. h1 = H(1) xhzh_circuit = (x1, h1, z1, h1) - assert is_scalar_sparse_matrix(xhzh_circuit, numqubits, id_only) == True + assert is_scalar_sparse_matrix(xhzh_circuit, numqubits, id_only) is True id_only = True - assert is_scalar_sparse_matrix(xhzh_circuit, numqubits, id_only) == True - assert is_scalar_sparse_matrix(xyz_circuit, numqubits, id_only) == False - assert is_scalar_sparse_matrix(cnot_circuit, numqubits, id_only) == True - assert is_scalar_sparse_matrix(hh_circuit, numqubits, id_only) == True + assert is_scalar_sparse_matrix(xhzh_circuit, numqubits, id_only) is True + assert is_scalar_sparse_matrix(xyz_circuit, numqubits, id_only) is False + assert is_scalar_sparse_matrix(cnot_circuit, numqubits, id_only) is True + assert is_scalar_sparse_matrix(hh_circuit, numqubits, id_only) is True + def test_is_degenerate(): (x, y, z, h) = create_gate_sequence() @@ -352,26 +361,28 @@ ids = set([gate_id]) another_id = (z, y, x) - assert is_degenerate(ids, another_id) == True + assert is_degenerate(ids, another_id) is True + def test_is_reducible(): nqubits = 2 (x, y, z, h) = create_gate_sequence() circuit = (x, y, y) - assert is_reducible(circuit, nqubits, 1, 3) == True + assert is_reducible(circuit, nqubits, 1, 3) is True circuit = (x, y, x) - assert is_reducible(circuit, nqubits, 1, 3) == False + assert is_reducible(circuit, nqubits, 1, 3) is False circuit = (x, y, y, x) - assert is_reducible(circuit, nqubits, 0, 4) == True + assert is_reducible(circuit, nqubits, 0, 4) is True circuit = (x, y, y, x) - assert is_reducible(circuit, nqubits, 1, 3) == True + assert is_reducible(circuit, nqubits, 1, 3) is True circuit = (x, y, z, y, y) - assert is_reducible(circuit, nqubits, 1, 5) == True + assert is_reducible(circuit, nqubits, 1, 5) is True + def test_bfs_identity_search(): assert bfs_identity_search([], 1) == set() @@ -443,7 +454,7 @@ assert id_set == bfs_identity_search(gate_list, 1, max_depth=4, identity_only=True) - cnot = CNOT(1,0) + cnot = CNOT(1, 0) gate_list = [x, cnot] id_set = set([GateIdentity(x, x), GateIdentity(cnot, cnot), diff -Nru python3-sympy-0.7.2/sympy/physics/quantum/tests/test_innerproduct.py python3-sympy-0.7.3/sympy/physics/quantum/tests/test_innerproduct.py --- python3-sympy-0.7.2/sympy/physics/quantum/tests/test_innerproduct.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/physics/quantum/tests/test_innerproduct.py 2013-07-13 17:53:32.000000000 +0000 @@ -8,13 +8,14 @@ def test_innerproduct(): k = Ket('k') b = Bra('b') - ip = InnerProduct(b,k) + ip = InnerProduct(b, k) assert isinstance(ip, InnerProduct) assert ip.bra == b assert ip.ket == k - assert b*k == InnerProduct(b,k) - assert k*(b*k)*b == k*InnerProduct(b,k)*b - assert InnerProduct(b,k).subs(b,Dagger(k)) == Dagger(k)*k + assert b*k == InnerProduct(b, k) + assert k*(b*k)*b == k*InnerProduct(b, k)*b + assert InnerProduct(b, k).subs(b, Dagger(k)) == Dagger(k)*k + def test_innerproduct_dagger(): k = Ket('k') @@ -65,6 +66,6 @@ def test_doit(): f = FooKet('foo') b = BarBra('bar') - assert InnerProduct(b,f).doit() == I - assert InnerProduct(Dagger(f),Dagger(b)).doit() == -I - assert InnerProduct(Dagger(f),f).doit() == Integer(1) + assert InnerProduct(b, f).doit() == I + assert InnerProduct(Dagger(f), Dagger(b)).doit() == -I + assert InnerProduct(Dagger(f), f).doit() == Integer(1) diff -Nru python3-sympy-0.7.2/sympy/physics/quantum/tests/test_matrixutils.py python3-sympy-0.7.3/sympy/physics/quantum/tests/test_matrixutils.py --- python3-sympy-0.7.2/sympy/physics/quantum/tests/test_matrixutils.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/physics/quantum/tests/test_matrixutils.py 2013-07-13 17:53:32.000000000 +0000 @@ -2,13 +2,13 @@ from sympy.physics.quantum.matrixutils import ( to_sympy, to_numpy, to_scipy_sparse, matrix_tensor_product, - matrix_to_zero + matrix_to_zero, matrix_zeros, numpy_ndarray, scipy_sparse_matrix ) from sympy.external import import_module from sympy.utilities.pytest import skip -m = Matrix([[1,2],[3,4]]) +m = Matrix([[1, 2], [3, 4]]) def test_sympy_to_sympy(): @@ -17,17 +17,19 @@ def test_matrix_to_zero(): assert matrix_to_zero(m) == m - assert matrix_to_zero(Matrix([[0,0],[0,0]])) == Integer(0) + assert matrix_to_zero(Matrix([[0, 0], [0, 0]])) == Integer(0) np = import_module('numpy', min_python_version=(2, 6)) + def test_to_numpy(): if not np: skip("numpy not installed or Python too old.") - result = np.matrix([[1,2],[3,4]], dtype='complex') + result = np.matrix([[1, 2], [3, 4]], dtype='complex') assert (to_numpy(m) == result).all() + def test_matrix_tensor_product(): if not np: skip("numpy not installed or Python too old.") @@ -41,59 +43,60 @@ l3 = zeros(2) for i in range(4): l3[i] = i - vec = Matrix([1,2,3]) + vec = Matrix([1, 2, 3]) #test for Matrix known 4x4 matricies numpyl1 = np.matrix(l1.tolist()) numpyl2 = np.matrix(l2.tolist()) - numpy_product = np.kron(numpyl1,numpyl2) + numpy_product = np.kron(numpyl1, numpyl2) args = [l1, l2] sympy_product = matrix_tensor_product(*args) assert numpy_product.tolist() == sympy_product.tolist() - numpy_product = np.kron(numpyl2,numpyl1) + numpy_product = np.kron(numpyl2, numpyl1) args = [l2, l1] sympy_product = matrix_tensor_product(*args) assert numpy_product.tolist() == sympy_product.tolist() #test for other known matrix of different dimensions numpyl2 = np.matrix(l3.tolist()) - numpy_product = np.kron(numpyl1,numpyl2) + numpy_product = np.kron(numpyl1, numpyl2) args = [l1, l3] sympy_product = matrix_tensor_product(*args) assert numpy_product.tolist() == sympy_product.tolist() - numpy_product = np.kron(numpyl2,numpyl1) + numpy_product = np.kron(numpyl2, numpyl1) args = [l3, l1] sympy_product = matrix_tensor_product(*args) assert numpy_product.tolist() == sympy_product.tolist() #test for non square matrix numpyl2 = np.matrix(vec.tolist()) - numpy_product = np.kron(numpyl1,numpyl2) + numpy_product = np.kron(numpyl1, numpyl2) args = [l1, vec] sympy_product = matrix_tensor_product(*args) assert numpy_product.tolist() == sympy_product.tolist() - numpy_product = np.kron(numpyl2,numpyl1) + numpy_product = np.kron(numpyl2, numpyl1) args = [vec, l1] sympy_product = matrix_tensor_product(*args) assert numpy_product.tolist() == sympy_product.tolist() #test for random matrix with random values that are floats - random_matrix1 = np.random.rand(np.random.rand()*5+1,np.random.rand()*5+1) - random_matrix2 = np.random.rand(np.random.rand()*5+1,np.random.rand()*5+1) - numpy_product = np.kron(random_matrix1,random_matrix2) - args = [Matrix(random_matrix1.tolist()),Matrix(random_matrix2.tolist())] + random_matrix1 = np.random.rand(np.random.rand()*5 + 1, np.random.rand()*5 + 1) + random_matrix2 = np.random.rand(np.random.rand()*5 + 1, np.random.rand()*5 + 1) + numpy_product = np.kron(random_matrix1, random_matrix2) + args = [Matrix(random_matrix1.tolist()), Matrix(random_matrix2.tolist())] sympy_product = matrix_tensor_product(*args) assert not (sympy_product - Matrix(numpy_product.tolist())).tolist() > \ - (ones(sympy_product.rows, sympy_product.cols)*epsilon).tolist() + (ones(sympy_product.rows, sympy_product.cols)*epsilon).tolist() #test for three matrix kronecker - sympy_product = matrix_tensor_product(l1,vec,l2) + sympy_product = matrix_tensor_product(l1, vec, l2) - numpy_product = np.kron(l1,np.kron(vec,l2)) + numpy_product = np.kron(l1, np.kron(vec, l2)) assert numpy_product.tolist() == sympy_product.tolist() -scipy = import_module('scipy', __import__kwargs={'fromlist':['sparse']}) +scipy = import_module('scipy', __import__kwargs={'fromlist': ['sparse']}) + def test_to_scipy_sparse(): if not np: @@ -103,7 +106,28 @@ else: sparse = scipy.sparse - result = sparse.csr_matrix([[1,2],[3,4]], dtype='complex') + result = sparse.csr_matrix([[1, 2], [3, 4]], dtype='complex') assert np.linalg.norm((to_scipy_sparse(m) - result).todense()) == 0.0 epsilon = .000001 + + +def test_matrix_zeros_sympy(): + sym = matrix_zeros(4, 4, format='sympy') + assert isinstance(sym, Matrix) + +def test_matrix_zeros_numpy(): + if not np: + skip("numpy not installed or Python too old.") + + num = matrix_zeros(4, 4, format='numpy') + assert isinstance(num, numpy_ndarray) + +def test_matrix_zeros_scipy(): + if not np: + skip("numpy not installed or Python too old.") + if not scipy: + skip("scipy not installed.") + + sci = matrix_zeros(4, 4, format='scipy.sparse') + assert isinstance(sci, scipy_sparse_matrix) diff -Nru python3-sympy-0.7.2/sympy/physics/quantum/tests/test_operator.py python3-sympy-0.7.3/sympy/physics/quantum/tests/test_operator.py --- python3-sympy-0.7.2/sympy/physics/quantum/tests/test_operator.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/physics/quantum/tests/test_operator.py 2013-07-13 17:53:32.000000000 +0000 @@ -9,21 +9,23 @@ from sympy.physics.quantum.state import Ket, Bra, Wavefunction from sympy.physics.quantum.qapply import qapply from sympy.core.trace import Tr -from sympy.physics.quantum.spin import JzKet, JzBra +from sympy.physics.quantum.spin import JzKet, JzBra -class TestKet(Ket): +class CustomKet(Ket): @classmethod def default_args(self): return ("t",) -class TestOp(HermitianOperator): + +class CustomOp(HermitianOperator): @classmethod def default_args(self): return ("T",) -t_ket = TestKet() -t_op = TestOp() +t_ket = CustomKet() +t_op = CustomOp() + def test_operator(): A = Operator('A') @@ -34,13 +36,13 @@ assert isinstance(A, QExpr) assert A.label == (Symbol('A'),) - assert A.is_commutative == False + assert A.is_commutative is False assert A.hilbert_space == HilbertSpace() assert A*B != B*A - assert (A*(B+C)).expand() == A*B + A*C - assert ((A+B)**2).expand() == A**2 + A*B + B*A + B**2 + assert (A*(B + C)).expand() == A*B + A*C + assert ((A + B)**2).expand() == A**2 + A*B + B*A + B**2 assert t_op.label[0] == Symbol(t_op.default_args()[0]) @@ -61,8 +63,9 @@ assert Dagger(H) == H assert H.inv() != H - assert H.is_commutative == False - assert Dagger(H).is_commutative == False + assert H.is_commutative is False + assert Dagger(H).is_commutative is False + def test_unitary(): U = UnitaryOperator('U') @@ -73,8 +76,8 @@ assert U.inv() == Dagger(U) assert U*Dagger(U) == 1 assert Dagger(U)*U == 1 - assert U.is_commutative == False - assert Dagger(U).is_commutative == False + assert U.is_commutative is False + assert Dagger(U).is_commutative is False def test_outer_product(): @@ -88,7 +91,7 @@ assert op.ket == k assert op.bra == b assert op.label == (k, b) - assert op.is_commutative == False + assert op.is_commutative is False op = k*b @@ -98,7 +101,7 @@ assert op.ket == k assert op.bra == b assert op.label == (k, b) - assert op.is_commutative == False + assert op.is_commutative is False op = 2*k*b @@ -108,19 +111,21 @@ assert op == Mul(Integer(2), OuterProduct(k, b)) - assert Dagger(k*b) == OuterProduct(Dagger(b),Dagger(k)) - assert Dagger(k*b).is_commutative == False + assert Dagger(k*b) == OuterProduct(Dagger(b), Dagger(k)) + assert Dagger(k*b).is_commutative is False #test the _eval_trace - assert Tr(OuterProduct(JzKet(1,1), JzBra(1,1))).doit() == 1 + assert Tr(OuterProduct(JzKet(1, 1), JzBra(1, 1))).doit() == 1 + def test_operator_dagger(): A = Operator('A') B = Operator('B') assert Dagger(A*B) == Dagger(B)*Dagger(A) - assert Dagger(A+B) == Dagger(A) + Dagger(B) + assert Dagger(A + B) == Dagger(A) + Dagger(B) assert Dagger(A**2) == Dagger(A)**2 + def test_differential_operator(): x = Symbol('x') f = Function('f') @@ -145,36 +150,36 @@ assert d.function == f(x) assert d.variables == (x,) assert diff(d, x) == \ - DifferentialOperator(Derivative(1/x*Derivative(f(x), x), x), f(x)) + DifferentialOperator(Derivative(1/x*Derivative(f(x), x), x), f(x)) assert qapply(d*g) == Wavefunction(3*x, x) # 2D cartesian Laplacian y = Symbol('y') - d = DifferentialOperator(Derivative(f(x, y), x, 2) + \ + d = DifferentialOperator(Derivative(f(x, y), x, 2) + Derivative(f(x, y), y, 2), f(x, y)) w = Wavefunction(x**3*y**2 + y**3*x**2, x, y) assert d.expr == Derivative(f(x, y), x, 2) + Derivative(f(x, y), y, 2) assert d.function == f(x, y) assert d.variables == (x, y) assert diff(d, x) == \ - DifferentialOperator(Derivative(d.expr, x), f(x, y)) + DifferentialOperator(Derivative(d.expr, x), f(x, y)) assert diff(d, y) == \ - DifferentialOperator(Derivative(d.expr, y), f(x, y)) - assert qapply(d*w) == Wavefunction(2*x**3 + 6*x*y**2 + 6*x**2*y + 2*y**3, \ + DifferentialOperator(Derivative(d.expr, y), f(x, y)) + assert qapply(d*w) == Wavefunction(2*x**3 + 6*x*y**2 + 6*x**2*y + 2*y**3, x, y) # 2D polar Laplacian (th = theta) r, th = symbols('r th') - d = DifferentialOperator(1/r*Derivative(r*Derivative(f(r, th), r) , r) + \ + d = DifferentialOperator(1/r*Derivative(r*Derivative(f(r, th), r), r) + 1/(r**2)*Derivative(f(r, th), th, 2), f(r, th)) w = Wavefunction(r**2*sin(th), r, (th, 0, pi)) assert d.expr == \ - 1/r*Derivative(r*Derivative(f(r, th), r), r) + \ - 1/(r**2)*Derivative(f(r, th), th, 2) + 1/r*Derivative(r*Derivative(f(r, th), r), r) + \ + 1/(r**2)*Derivative(f(r, th), th, 2) assert d.function == f(r, th) assert d.variables == (r, th) assert diff(d, r) == \ - DifferentialOperator(Derivative(d.expr, r), f(r, th)) + DifferentialOperator(Derivative(d.expr, r), f(r, th)) assert diff(d, th) == \ - DifferentialOperator(Derivative(d.expr, th), f(r, th)) + DifferentialOperator(Derivative(d.expr, th), f(r, th)) assert qapply(d*w) == Wavefunction(3*sin(th), r, (th, 0, pi)) diff -Nru python3-sympy-0.7.2/sympy/physics/quantum/tests/test_operatorset.py python3-sympy-0.7.3/sympy/physics/quantum/tests/test_operatorset.py --- python3-sympy-0.7.2/sympy/physics/quantum/tests/test_operatorset.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/physics/quantum/tests/test_operatorset.py 2013-07-13 17:53:32.000000000 +0000 @@ -17,14 +17,15 @@ from sympy.utilities.pytest import XFAIL + @XFAIL def test_spin(): assert operators_to_state(set([J2Op, JxOp])) == JxKet() assert operators_to_state(set([J2Op, JyOp])) == JyKet() assert operators_to_state(set([J2Op, JzOp])) == JzKet() - assert operators_to_state(set([J2Op(), JxOp()])) == JxKet() - assert operators_to_state(set([J2Op(), JyOp()])) == JyKet() - assert operators_to_state(set([J2Op(), JzOp()])) == JzKet() + assert operators_to_state(set([J2Op(), JxOp()])) == JxKet() + assert operators_to_state(set([J2Op(), JyOp()])) == JyKet() + assert operators_to_state(set([J2Op(), JzOp()])) == JzKet() assert state_to_operators(JxKet) == set([J2Op(), JxOp()]) assert state_to_operators(JyKet) == set([J2Op(), JyOp()]) @@ -40,6 +41,7 @@ assert state_to_operators(JyBra()) == set([J2Op(), JyOp()]) assert state_to_operators(JzBra()) == set([J2Op(), JzOp()]) + def test_op_to_state(): assert operators_to_state(XOp) == XKet() assert operators_to_state(PxOp) == PxKet() @@ -50,6 +52,7 @@ raises(NotImplementedError, lambda: operators_to_state(XKet)) + def test_state_to_op(): assert state_to_operators(XKet) == XOp() assert state_to_operators(PxKet) == PxOp() diff -Nru python3-sympy-0.7.2/sympy/physics/quantum/tests/test_piab.py python3-sympy-0.7.3/sympy/physics/quantum/tests/test_piab.py --- python3-sympy-0.7.2/sympy/physics/quantum/tests/test_piab.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/physics/quantum/tests/test_piab.py 2013-07-13 17:53:32.000000000 +0000 @@ -7,16 +7,18 @@ i, j, n, x = symbols('i j n x') + def test_H(): - assert PIABHamiltonian('H').hilbert_space ==\ - L2(Interval(S.NegativeInfinity,S.Infinity)) - assert qapply(PIABHamiltonian('H')*PIABKet(n)) ==\ + assert PIABHamiltonian('H').hilbert_space == \ + L2(Interval(S.NegativeInfinity, S.Infinity)) + assert qapply(PIABHamiltonian('H')*PIABKet(n)) == \ (n**2*pi**2*hbar**2)/(2*m*L**2)*PIABKet(n) + def test_states(): assert PIABKet(n).dual_class() == PIABBra - assert PIABKet(n).hilbert_space ==\ - L2(Interval(S.NegativeInfinity,S.Infinity)) + assert PIABKet(n).hilbert_space == \ + L2(Interval(S.NegativeInfinity, S.Infinity)) assert represent(PIABKet(n)) == sqrt(2/L)*sin(n*pi*x/L) assert (PIABBra(i)*PIABKet(j)).doit() == KroneckerDelta(i, j) assert PIABBra(n).dual_class() == PIABKet diff -Nru python3-sympy-0.7.2/sympy/physics/quantum/tests/test_printing.py python3-sympy-0.7.3/sympy/physics/quantum/tests/test_printing.py --- python3-sympy-0.7.2/sympy/physics/quantum/tests/test_printing.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/physics/quantum/tests/test_printing.py 2013-07-13 17:53:32.000000000 +0000 @@ -17,6 +17,7 @@ from sympy.physics.quantum.spin import Jz, J2, JzBra, JzBraCoupled, JzKet, JzKetCoupled, Rotation, WignerD from sympy.physics.quantum.state import Bra, Ket, TimeDepBra, TimeDepKet from sympy.physics.quantum.tensorproduct import TensorProduct +from sympy.physics.quantum.sho1d import RaisingOp from sympy import Derivative, Function, Interval, Matrix, Pow, S, symbols, Symbol, oo from sympy.utilities.pytest import XFAIL @@ -31,8 +32,12 @@ from sympy.printing.pretty import pretty as xpretty from sympy.printing.latex import latex +MutableDenseMatrix = Matrix + ENV = {} exec("from sympy import *", ENV) + + def sT(expr, string): """ sT := sreprTest @@ -41,10 +46,12 @@ assert srepr(expr) == string assert eval(string) == expr + def pretty(expr): """ASCII pretty-printing""" return xpretty(expr, use_unicode=False, wrap_line=False) + def upretty(expr): """Unicode pretty-printing""" return xpretty(expr, use_unicode=True, wrap_line=False) @@ -53,8 +60,8 @@ def test_anticommutator(): A = Operator('A') B = Operator('B') - ac = AntiCommutator(A,B) - ac_tall = AntiCommutator(A**2,B) + ac = AntiCommutator(A, B) + ac_tall = AntiCommutator(A**2, B) assert str(ac) == '{A,B}' assert pretty(ac) == '{A,B}' assert upretty(ac) == '{A,B}' @@ -78,8 +85,9 @@ assert latex(ac_tall) == r'\left\{\left(A\right)^{2},B\right\}' sT(ac_tall, "AntiCommutator(Pow(Operator(Symbol('A')), Integer(2)),Operator(Symbol('B')))") + def test_cg(): - cg = CG(1,2,3,4,5,6) + cg = CG(1, 2, 3, 4, 5, 6) wigner3j = Wigner3j(1, 2, 3, 4, 5, 6) wigner6j = Wigner6j(1, 2, 3, 4, 5, 6) wigner9j = Wigner9j(1, 2, 3, 4, 5, 6, 7, 8, 9) @@ -159,6 +167,7 @@ r'\left\{\begin{array}{ccc} 1 & 2 & 3 \\ 4 & 5 & 6 \\ 7 & 8 & 9 \end{array}\right\}' sT(wigner9j, "Wigner9j(Integer(1), Integer(2), Integer(3), Integer(4), Integer(5), Integer(6), Integer(7), Integer(8), Integer(9))") + def test_commutator(): A = Operator('A') B = Operator('B') @@ -185,6 +194,7 @@ assert latex(c_tall) == r'\left[\left(A\right)^{2},B\right]' sT(c_tall, "Commutator(Pow(Operator(Symbol('A')), Integer(2)),Operator(Symbol('B')))") + def test_constants(): assert str(hbar) == 'hbar' assert pretty(hbar) == 'hbar' @@ -192,6 +202,7 @@ assert latex(hbar) == r'\hbar' sT(hbar, "HBar()") + def test_dagger(): x = symbols('x') expr = Dagger(x) @@ -211,20 +222,22 @@ assert latex(expr) == r'x^{\dag}' sT(expr, "Dagger(Symbol('x'))") + @XFAIL def test_gate_failing(): - a,b,c,d = symbols('a,b,c,d') - uMat = Matrix([[a,b],[c,d]]) + a, b, c, d = symbols('a,b,c,d') + uMat = Matrix([[a, b], [c, d]]) g = UGate((0,), uMat) assert str(g) == 'U(0)' + def test_gate(): - a,b,c,d = symbols('a,b,c,d') - uMat = Matrix([[a,b],[c,d]]) - q = Qubit(1,0,1,0,1) + a, b, c, d = symbols('a,b,c,d') + uMat = Matrix([[a, b], [c, d]]) + q = Qubit(1, 0, 1, 0, 1) g1 = IdentityGate(2) - g2 = CGate((3,0), XGate(1)) - g3 = CNotGate(1,0) + g2 = CGate((3, 0), XGate(1)) + g3 = CNotGate(1, 0) g4 = UGate((0,), uMat) assert str(g1) == '1(2)' assert pretty(g1) == '1 \n 2' @@ -291,13 +304,14 @@ assert pretty(g4) == ascii_str assert upretty(g4) == ucode_str assert latex(g4) == r'U_{0}' - sT(g4, "UGate(Tuple(Integer(0)),Matrix([[Symbol('a'), Symbol('b')], [Symbol('c'), Symbol('d')]]))") + sT(g4, "UGate(Tuple(Integer(0)),MutableDenseMatrix([[Symbol('a'), Symbol('b')], [Symbol('c'), Symbol('d')]]))") + def test_hilbert(): h1 = HilbertSpace() h2 = ComplexSpace(2) h3 = FockSpace() - h4 = L2(Interval(0,oo)) + h4 = L2(Interval(0, oo)) assert str(h1) == 'H' assert pretty(h1) == 'H' assert upretty(h1) == 'H' @@ -338,7 +352,7 @@ assert upretty(h4) == ucode_str assert latex(h4) == r'{\mathcal{L}^2}\left( \left[0, \infty\right) \right)' sT(h4, "L2(Interval(Integer(0), oo, False, True))") - assert str(h1+h2) == 'H+C(2)' + assert str(h1 + h2) == 'H+C(2)' ascii_str = \ """\ 2\n\ @@ -349,10 +363,10 @@ 2\n\ H ⊕ C \ """ - assert pretty(h1+h2) == ascii_str - assert upretty(h1+h2) == ucode_str - assert latex(h1+h2) - sT(h1+h2, "DirectSumHilbertSpace(HilbertSpace(),ComplexSpace(Integer(2)))") + assert pretty(h1 + h2) == ascii_str + assert upretty(h1 + h2) == ucode_str + assert latex(h1 + h2) + sT(h1 + h2, "DirectSumHilbertSpace(HilbertSpace(),ComplexSpace(Integer(2)))") assert str(h1*h2) == "H*C(2)" ascii_str = \ """\ @@ -367,7 +381,8 @@ assert pretty(h1*h2) == ascii_str assert upretty(h1*h2) == ucode_str assert latex(h1*h2) - sT(h1*h2, "TensorProductHilbertSpace(HilbertSpace(),ComplexSpace(Integer(2)))") + sT(h1*h2, + "TensorProductHilbertSpace(HilbertSpace(),ComplexSpace(Integer(2)))") assert str(h1**2) == 'H**2' ascii_str = \ """\ @@ -384,19 +399,21 @@ assert latex(h1**2) == r'{\mathcal{H}}^{\otimes 2}' sT(h1**2, "TensorPowerHilbertSpace(HilbertSpace(),Integer(2))") + def test_innerproduct(): x = symbols('x') ip1 = InnerProduct(Bra(), Ket()) - ip2 = InnerProduct(TimeDepBra(),TimeDepKet()) - ip3 = InnerProduct(JzBra(1,1),JzKet(1,1)) - ip4 = InnerProduct(JzBraCoupled(1, 1, (1,1)),JzKetCoupled(1, 1, (1,1))) + ip2 = InnerProduct(TimeDepBra(), TimeDepKet()) + ip3 = InnerProduct(JzBra(1, 1), JzKet(1, 1)) + ip4 = InnerProduct(JzBraCoupled(1, 1, (1, 1)), JzKetCoupled(1, 1, (1, 1))) ip_tall1 = InnerProduct(Bra(x/2), Ket(x/2)) ip_tall2 = InnerProduct(Bra(x), Ket(x/2)) ip_tall3 = InnerProduct(Bra(x/2), Ket(x)) assert str(ip1) == '' assert pretty(ip1) == '' assert upretty(ip1) == '⟨ψ❘ψ⟩' - assert latex(ip1) == r'\left\langle \psi \right. {\left|\psi\right\rangle }' + assert latex( + ip1) == r'\left\langle \psi \right. {\left|\psi\right\rangle }' sT(ip1, "InnerProduct(Bra(Symbol('psi')),Ket(Symbol('psi')))") assert str(ip2) == '' assert pretty(ip2) == '' @@ -433,7 +450,7 @@ assert pretty(ip_tall1) == ascii_str assert upretty(ip_tall1) == ucode_str assert latex(ip_tall1) == \ - r'\left\langle \frac{1}{2} x \right. {\left|\frac{1}{2} x\right\rangle }' + r'\left\langle \frac{x}{2} \right. {\left|\frac{x}{2}\right\rangle }' sT(ip_tall1, "InnerProduct(Bra(Mul(Rational(1, 2), Symbol('x'))),Ket(Mul(Rational(1, 2), Symbol('x'))))") assert str(ip_tall2) == '' ascii_str = \ @@ -453,8 +470,9 @@ assert pretty(ip_tall2) == ascii_str assert upretty(ip_tall2) == ucode_str assert latex(ip_tall2) == \ - r'\left\langle x \right. {\left|\frac{1}{2} x\right\rangle }' - sT(ip_tall2, "InnerProduct(Bra(Symbol('x')),Ket(Mul(Rational(1, 2), Symbol('x'))))") + r'\left\langle x \right. {\left|\frac{x}{2}\right\rangle }' + sT(ip_tall2, + "InnerProduct(Bra(Symbol('x')),Ket(Mul(Rational(1, 2), Symbol('x'))))") assert str(ip_tall3) == '' ascii_str = \ """\ @@ -473,8 +491,10 @@ assert pretty(ip_tall3) == ascii_str assert upretty(ip_tall3) == ucode_str assert latex(ip_tall3) == \ - r'\left\langle \frac{1}{2} x \right. {\left|x\right\rangle }' - sT(ip_tall3, "InnerProduct(Bra(Mul(Rational(1, 2), Symbol('x'))),Ket(Symbol('x')))") + r'\left\langle \frac{x}{2} \right. {\left|x\right\rangle }' + sT(ip_tall3, + "InnerProduct(Bra(Mul(Rational(1, 2), Symbol('x'))),Ket(Symbol('x')))") + def test_operator(): a = Operator('A') @@ -482,7 +502,7 @@ inv = a.inv() f = Function('f') x = symbols('x') - d = DifferentialOperator(Derivative(f(x),x), f(x)) + d = DifferentialOperator(Derivative(f(x), x), f(x)) op = OuterProduct(Ket(), Bra()) assert str(a) == 'A' assert pretty(a) == 'A' @@ -520,7 +540,7 @@ assert pretty(d) == ascii_str assert upretty(d) == ucode_str assert latex(d) == \ - r'DifferentialOperator\left(\frac{\partial}{\partial x} \operatorname{f}{\left (x \right )},\operatorname{f}{\left (x \right )}\right)' + r'DifferentialOperator\left(\frac{d}{d x} f{\left (x \right )},f{\left (x \right )}\right)' sT(d, "DifferentialOperator(Derivative(Function('f')(Symbol('x')), Symbol('x')),Function('f')(Symbol('x')))") assert str(b) == 'Operator(B,t,1/2)' assert pretty(b) == 'Operator(B,t,1/2)' @@ -533,6 +553,7 @@ assert latex(op) == r'{\left|\psi\right\rangle }{\left\langle \psi\right|}' sT(op, "OuterProduct(Ket(Symbol('psi')),Bra(Symbol('psi')))") + def test_qexpr(): q = QExpr('q') assert str(q) == 'q' @@ -541,6 +562,7 @@ assert latex(q) == r'q' sT(q, "QExpr(Symbol('q'))") + def test_qubit(): q1 = Qubit('0101') q2 = IntQubit(8) @@ -548,24 +570,25 @@ assert pretty(q1) == '|0101>' assert upretty(q1) == '❘0101⟩' assert latex(q1) == r'{\left|0101\right\rangle }' - sT(q1,"Qubit(Integer(0),Integer(1),Integer(0),Integer(1))") + sT(q1, "Qubit(Integer(0),Integer(1),Integer(0),Integer(1))") assert str(q2) == '|8>' assert pretty(q2) == '|8>' assert upretty(q2) == '❘8⟩' assert latex(q2) == r'{\left|8\right\rangle }' sT(q2, "IntQubit(8)") + def test_spin(): lz = JzOp('L') ket = JzKet(1, 0) bra = JzBra(1, 0) cket = JzKetCoupled(1, 0, (1, 2)) cbra = JzBraCoupled(1, 0, (1, 2)) - cket_big = JzKetCoupled(1, 0, (1,2,3)) - cbra_big = JzBraCoupled(1, 0, (1,2,3)) - rot = Rotation(1,2,3) - bigd = WignerD(1,2,3,4,5,6) - smalld = WignerD(1,2,3,0,4,0) + cket_big = JzKetCoupled(1, 0, (1, 2, 3)) + cbra_big = JzBraCoupled(1, 0, (1, 2, 3)) + rot = Rotation(1, 2, 3) + bigd = WignerD(1, 2, 3, 4, 5, 6) + smalld = WignerD(1, 2, 3, 0, 4, 0) assert str(lz) == 'Lz' ascii_str = \ """\ @@ -685,6 +708,7 @@ assert latex(smalld) == r'd^{1}_{2,3}\left(4\right)' sT(smalld, "WignerD(Integer(1), Integer(2), Integer(3), Integer(0), Integer(4), Integer(0))") + def test_state(): x = symbols('x') bra = Bra() @@ -720,7 +744,7 @@ """ assert pretty(bra_tall) == ascii_str assert upretty(bra_tall) == ucode_str - assert latex(bra_tall) == r'{\left\langle \frac{1}{2} x\right|}' + assert latex(bra_tall) == r'{\left\langle \frac{x}{2}\right|}' sT(bra_tall, "Bra(Mul(Rational(1, 2), Symbol('x')))") assert str(ket_tall) == '|x/2>' ascii_str = \ @@ -739,7 +763,7 @@ """ assert pretty(ket_tall) == ascii_str assert upretty(ket_tall) == ucode_str - assert latex(ket_tall) == r'{\left|\frac{1}{2} x\right\rangle }' + assert latex(ket_tall) == r'{\left|\frac{x}{2}\right\rangle }' sT(ket_tall, "Ket(Mul(Rational(1, 2), Symbol('x')))") assert str(tbra) == 'x|1,0>' assert pretty(tp) == '|1,1>x |1,0>' assert upretty(tp) == '❘1,1⟩⨂ ❘1,0⟩' @@ -761,13 +786,15 @@ r'{{\left|1,1\right\rangle }}\otimes {{\left|1,0\right\rangle }}' sT(tp, "TensorProduct(JzKet(Integer(1),Integer(1)), JzKet(Integer(1),Integer(0)))") + def test_big_expr(): f = Function('f') x = symbols('x') - e1 = Dagger(AntiCommutator(Operator('A')+Operator('B'),Pow(DifferentialOperator(Derivative(f(x), x), f(x)),3))*TensorProduct(Jz**2,Operator('A')+Operator('B')))*(JzBra(1,0)+JzBra(1,1))*(JzKet(0,0)+JzKet(1,-1)) - e2 = Commutator(Jz**2,Operator('A')+Operator('B'))*AntiCommutator(Dagger(Operator('C')*Operator('D')),Operator('E').inv()**2)*Dagger(Commutator(Jz,J2)) - e3 = Wigner3j(1,2,3,4,5,6)*TensorProduct(Commutator(Operator('A')+Dagger(Operator('B')),Operator('C')+Operator('D')),Jz-J2)*Dagger(OuterProduct(Dagger(JzBra(1,1)),JzBra(1,0)))*TensorProduct(JzKetCoupled(1,1,(1,1))+JzKetCoupled(1,0,(1,1)),JzKetCoupled(1,-1,(1,1))) - e4 = (ComplexSpace(1)*ComplexSpace(2)+FockSpace()**2)*(L2(Interval(0,oo))+HilbertSpace()) + e1 = Dagger(AntiCommutator(Operator('A') + Operator('B'), Pow(DifferentialOperator(Derivative(f(x), x), f(x)), 3))*TensorProduct(Jz**2, Operator('A') + Operator('B')))*(JzBra(1, 0) + JzBra(1, 1))*(JzKet(0, 0) + JzKet(1, -1)) + e2 = Commutator(Jz**2, Operator('A') + Operator('B'))*AntiCommutator(Dagger(Operator('C')*Operator('D')), Operator('E').inv()**2)*Dagger(Commutator(Jz, J2)) + e3 = Wigner3j(1, 2, 3, 4, 5, 6)*TensorProduct(Commutator(Operator('A') + Dagger(Operator('B')), Operator('C') + Operator('D')), Jz - J2)*Dagger(OuterProduct(Dagger(JzBra(1, 1)), JzBra(1, 0)))*TensorProduct(JzKetCoupled(1, 1, (1, 1)) + JzKetCoupled(1, 0, (1, 1)), JzKetCoupled(1, -1, (1, 1))) + e4 = (ComplexSpace(1)*ComplexSpace(2) + FockSpace()**2)*(L2(Interval( + 0, oo)) + HilbertSpace()) assert str(e1) == '(Jz**2)x(Dagger(A) + Dagger(B))*{Dagger(DifferentialOperator(Derivative(f(x), x),f(x)))**3,Dagger(A) + Dagger(B)}*(<1,0| + <1,1|)*(|0,0> + |1,-1>)' ascii_str = \ """\ @@ -788,7 +815,7 @@ assert pretty(e1) == ascii_str assert upretty(e1) == ucode_str assert latex(e1) == \ - r'{\left(J_z\right)^{2}}\otimes \left({A^{\dag} + B^{\dag}}\right) \left\{\left(DifferentialOperator\left(\frac{\partial}{\partial x} \operatorname{f}{\left (x \right )},\operatorname{f}{\left (x \right )}\right)^{\dag}\right)^{3},A^{\dag} + B^{\dag}\right\} \left({\left\langle 1,0\right|} + {\left\langle 1,1\right|}\right) \left({\left|0,0\right\rangle } + {\left|1,-1\right\rangle }\right)' + r'{\left(J_z\right)^{2}}\otimes \left({A^{\dag} + B^{\dag}}\right) \left\{\left(DifferentialOperator\left(\frac{d}{d x} f{\left (x \right )},f{\left (x \right )}\right)^{\dag}\right)^{3},A^{\dag} + B^{\dag}\right\} \left({\left\langle 1,0\right|} + {\left\langle 1,1\right|}\right) \left({\left|0,0\right\rangle } + {\left|1,-1\right\rangle }\right)' sT(e1, "Mul(TensorProduct(Pow(JzOp(Symbol('J')), Integer(2)), Add(Dagger(Operator(Symbol('A'))), Dagger(Operator(Symbol('B'))))), AntiCommutator(Pow(Dagger(DifferentialOperator(Derivative(Function('f')(Symbol('x')), Symbol('x')),Function('f')(Symbol('x')))), Integer(3)),Add(Dagger(Operator(Symbol('A'))), Dagger(Operator(Symbol('B'))))), Add(JzBra(Integer(1),Integer(0)), JzBra(Integer(1),Integer(1))), Add(JzKet(Integer(0),Integer(0)), JzKet(Integer(1),Integer(-1))))") assert str(e2) == '[Jz**2,A + B]*{E**(-2),Dagger(D)*Dagger(C)}*[J2,Jz]' ascii_str = \ @@ -845,3 +872,9 @@ assert latex(e4) == \ r'\left(\left(\mathcal{C}^{1}\otimes \mathcal{C}^{2}\right)\oplus {\mathcal{F}}^{\otimes 2}\right)\otimes \left({\mathcal{L}^2}\left( \left[0, \infty\right) \right)\oplus \mathcal{H}\right)' sT(e4, "TensorProductHilbertSpace((DirectSumHilbertSpace(TensorProductHilbertSpace(ComplexSpace(Integer(1)),ComplexSpace(Integer(2))),TensorPowerHilbertSpace(FockSpace(),Integer(2)))),(DirectSumHilbertSpace(L2(Interval(Integer(0), oo, False, True)),HilbertSpace())))") + + +def _test_sho1d(): + ad = RaisingOp('a') + assert pretty(ad) == ' \u2020\na ' + assert latex(ad) == 'a^{\\dag}' diff -Nru python3-sympy-0.7.2/sympy/physics/quantum/tests/test_qapply.py python3-sympy-0.7.3/sympy/physics/quantum/tests/test_qapply.py --- python3-sympy-0.7.2/sympy/physics/quantum/tests/test_qapply.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/physics/quantum/tests/test_qapply.py 2013-07-13 17:53:32.000000000 +0000 @@ -16,9 +16,9 @@ j, jp, m, mp = symbols("j j' m m'") -z = JzKet(1,0) -po = JzKet(1,1) -mo = JzKet(1,-1) +z = JzKet(1, 0) +po = JzKet(1, 1) +mo = JzKet(1, -1) A = Operator('A') @@ -43,7 +43,8 @@ extra = z.dual*A*z assert qapply(Jz*po*extra) == hbar*po*extra assert qapply(Jx*z*extra) == (hbar*po/sqrt(2) + hbar*mo/sqrt(2))*extra - assert qapply((Jplus + Jminus)*z/sqrt(2)*extra) == hbar*po*extra + hbar*mo*extra + assert qapply( + (Jplus + Jminus)*z/sqrt(2)*extra) == hbar*po*extra + hbar*mo*extra assert qapply(Jz*(po + mo)*extra) == hbar*po*extra - hbar*mo*extra assert qapply(Jz*po*extra + Jz*mo*extra) == hbar*po*extra - hbar*mo*extra assert qapply(Jminus*Jminus*po*extra) == 2*hbar**2*mo*extra @@ -62,7 +63,7 @@ def test_commutator(): - assert qapply(Commutator(Jx,Jy)*Jz*po) == I*hbar**3*po + assert qapply(Commutator(Jx, Jy)*Jz*po) == I*hbar**3*po assert qapply(Commutator(J2, Jz)*Jz*po) == 0 assert qapply(Commutator(Jz, Foo('F'))*po) == 0 assert qapply(Commutator(Foo('F'), Jz)*po) == 0 @@ -88,11 +89,12 @@ def test_issue2974(): x, y = symbols('x y', commutative=False) - A = Ket(x,y) + A = Ket(x, y) B = Operator('B') assert qapply(A) == A assert qapply(A.dual*B) == A.dual*B + def test_density(): d = Density([Jz*mo, 0.5], [Jz*po, 0.5]) assert qapply(d) == Density([-hbar*mo, 0.5], [hbar*po, 0.5]) diff -Nru python3-sympy-0.7.2/sympy/physics/quantum/tests/test_qexpr.py python3-sympy-0.7.3/sympy/physics/quantum/tests/test_qexpr.py --- python3-sympy-0.7.2/sympy/physics/quantum/tests/test_qexpr.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/physics/quantum/tests/test_qexpr.py 2013-07-13 17:53:32.000000000 +0000 @@ -6,38 +6,40 @@ x = Symbol('x') y = Symbol('y') + def test_qexpr_new(): q = QExpr(0) assert q.label == (0,) assert q.hilbert_space == HilbertSpace() - assert q.is_commutative == False + assert q.is_commutative is False - q = QExpr(0,1) - assert q.label == (Integer(0),Integer(1)) + q = QExpr(0, 1) + assert q.label == (Integer(0), Integer(1)) q = QExpr._new_rawargs(HilbertSpace(), Integer(0), Integer(1)) - assert q.label == (Integer(0),Integer(1)) + assert q.label == (Integer(0), Integer(1)) assert q.hilbert_space == HilbertSpace() def test_qexpr_commutative(): q1 = QExpr(x) q2 = QExpr(y) - assert q1.is_commutative == False - assert q2.is_commutative == False + assert q1.is_commutative is False + assert q2.is_commutative is False assert q1*q2 != q2*q1 - q = QExpr._new_rawargs(0,1,HilbertSpace()) - assert q.is_commutative == False + q = QExpr._new_rawargs(0, 1, HilbertSpace()) + assert q.is_commutative is False def test_qexpr_subs(): - q1 = QExpr(x,y) - assert q1.subs(x, y) == QExpr(y,y) - assert q1.subs({x:1,y:2}) == QExpr(1,2) + q1 = QExpr(x, y) + assert q1.subs(x, y) == QExpr(y, y) + assert q1.subs({x: 1, y: 2}) == QExpr(1, 2) + def test_qsympify(): - assert _qsympify_sequence([[1,2], [1,3]]) == (Tuple(1,2), Tuple(1,3)) - assert _qsympify_sequence(([1,2,[3,4,[2,]],1],3)) ==\ - (Tuple(1,2,Tuple(3,4,Tuple(2,)),1),3) + assert _qsympify_sequence([[1, 2], [1, 3]]) == (Tuple(1, 2), Tuple(1, 3)) + assert _qsympify_sequence(([1, 2, [3, 4, [2, ]], 1], 3)) == \ + (Tuple(1, 2, Tuple(3, 4, Tuple(2,)), 1), 3) assert _qsympify_sequence((1,)) == (1,) diff -Nru python3-sympy-0.7.2/sympy/physics/quantum/tests/test_qft.py python3-sympy-0.7.3/sympy/physics/quantum/tests/test_qft.py --- python3-sympy-0.7.2/sympy/physics/quantum/tests/test_qft.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/physics/quantum/tests/test_qft.py 2013-07-13 17:53:32.000000000 +0000 @@ -10,34 +10,37 @@ def test_RkGate(): x = Symbol('x') - assert RkGate(1,x).k == x - assert RkGate(1,x).targets == (1,) - assert RkGate(1,1) == ZGate(1) - assert RkGate(2,2) == PhaseGate(2) - assert RkGate(3,3) == TGate(3) + assert RkGate(1, x).k == x + assert RkGate(1, x).targets == (1,) + assert RkGate(1, 1) == ZGate(1) + assert RkGate(2, 2) == PhaseGate(2) + assert RkGate(3, 3) == TGate(3) - assert represent(RkGate(0,x), nqubits =1) ==\ - Matrix([[1,0],[0,exp(2*I*pi/2**x)]]) + assert represent( + RkGate(0, x), nqubits=1) == Matrix([[1, 0], [0, exp(2*I*pi/2**x)]]) -def test_RkGate_controled(): - pass def test_quantum_fourier(): - assert QFT(0,3).decompose() == SwapGate(0,2)*HadamardGate(0)*CGate((0,), PhaseGate(1))\ - *HadamardGate(1)*CGate((0,), TGate(2))*CGate((1,), PhaseGate(2))*HadamardGate(2) + assert QFT(0, 3).decompose() == \ + SwapGate(0, 2)*HadamardGate(0)*CGate((0,), PhaseGate(1)) * \ + HadamardGate(1)*CGate((0,), TGate(2))*CGate((1,), PhaseGate(2)) * \ + HadamardGate(2) + + assert IQFT(0, 3).decompose() == \ + HadamardGate(2)*CGate((1,), RkGate(2, -2))*CGate((0,), RkGate(2, -3)) * \ + HadamardGate(1)*CGate((0,), RkGate(1, -2))*HadamardGate(0)*SwapGate(0, 2) + + assert represent(QFT(0, 3), nqubits=3) == \ + Matrix([[exp(2*pi*I/8)**(i*j % 8)/sqrt(8) for i in range(8)] for j in range(8)]) + + assert QFT(0, 4).decompose() # non-trivial decomposition + assert qapply(QFT(0, 3).decompose()*Qubit(0, 0, 0)).expand() == qapply( + HadamardGate(0)*HadamardGate(1)*HadamardGate(2)*Qubit(0, 0, 0) + ).expand() - assert IQFT(0,3).decompose() == HadamardGate(2)*CGate((1,), RkGate(2,-2))*CGate((0,),RkGate(2,-3))\ - *HadamardGate(1)*CGate((0,), RkGate(1,-2))*HadamardGate(0)*SwapGate(0,2) - - assert represent(QFT(0,3), nqubits=3)\ - == Matrix([[exp(2*pi*I/8)**(i*j%8)/sqrt(8) for i in range(8)] for j in range(8)]) - - assert QFT(0,4).decompose() #non-trivial decomposition - assert qapply(QFT(0,3).decompose()*Qubit(0,0,0)).expand() ==\ - qapply(HadamardGate(0)*HadamardGate(1)*HadamardGate(2)*Qubit(0,0,0)).expand() def test_qft_represent(): - c = QFT(0,3) - a = represent(c,nqubits=3) - b = represent(c.decompose(),nqubits=3) + c = QFT(0, 3) + a = represent(c, nqubits=3) + b = represent(c.decompose(), nqubits=3) assert a.evalf(prec=10) == b.evalf(prec=10) diff -Nru python3-sympy-0.7.2/sympy/physics/quantum/tests/test_qubit.py python3-sympy-0.7.3/sympy/physics/quantum/tests/test_qubit.py --- python3-sympy-0.7.2/sympy/physics/quantum/tests/test_qubit.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/physics/quantum/tests/test_qubit.py 2013-07-13 17:53:32.000000000 +0000 @@ -18,61 +18,68 @@ epsilon = .000001 + def test_Qubit(): - array = [0,0,1,1,0] + array = [0, 0, 1, 1, 0] qb = Qubit('00110') assert qb.flip(0) == Qubit('00111') assert qb.flip(1) == Qubit('00100') assert qb.flip(4) == Qubit('10110') assert qb.dimension == 5 for i in range(5): - assert qb[i] == array[4-i] + assert qb[i] == array[4 - i] assert len(qb) == 5 qb = Qubit('110') + def test_QubitBra(): assert Qubit(0).dual_class() == QubitBra assert QubitBra(0).dual_class() == Qubit - assert represent(Qubit(1,1,0), nqubits=3).H ==\ - represent(QubitBra(1,1,0), nqubits=3) - assert Qubit(0,1)._eval_innerproduct_QubitBra(QubitBra(1,0)) == Integer(0) - assert Qubit(0,1)._eval_innerproduct_QubitBra(QubitBra(0,1)) == Integer(1) + assert represent(Qubit(1, 1, 0), nqubits=3).H == \ + represent(QubitBra(1, 1, 0), nqubits=3) + assert Qubit( + 0, 1)._eval_innerproduct_QubitBra(QubitBra(1, 0)) == Integer(0) + assert Qubit( + 0, 1)._eval_innerproduct_QubitBra(QubitBra(0, 1)) == Integer(1) + def test_IntQubit(): assert IntQubit(8).as_int() == 8 - assert IntQubit(8).qubit_values == (1,0,0,0) - assert IntQubit(7, 4).qubit_values == (0,1,1,1) - assert IntQubit(3) == IntQubit(3,2) + assert IntQubit(8).qubit_values == (1, 0, 0, 0) + assert IntQubit(7, 4).qubit_values == (0, 1, 1, 1) + assert IntQubit(3) == IntQubit(3, 2) #test Dual Classes assert IntQubit(3).dual_class() == IntQubitBra assert IntQubitBra(3).dual_class() == IntQubit + assert IntQubit(5)._eval_innerproduct_IntQubitBra(IntQubitBra(5)) == Integer(1) + assert IntQubit(4)._eval_innerproduct_IntQubitBra(IntQubitBra(5)) == Integer(0) raises(ValueError, lambda: IntQubit(4, 1)) + def test_superposition_of_states(): - assert qapply(CNOT(0,1)*HadamardGate(0)*(1/sqrt(2)*Qubit('01') + 1/sqrt(2)*Qubit('10'))).expand() == (Qubit('01')/2 + Qubit('00')/2 - Qubit('11')/2 +\ + assert qapply(CNOT(0, 1)*HadamardGate(0)*(1/sqrt(2)*Qubit('01') + 1/sqrt(2)*Qubit('10'))).expand() == (Qubit('01')/2 + Qubit('00')/2 - Qubit('11')/2 + Qubit('10')/2) - assert matrix_to_qubit(represent(CNOT(0,1)*HadamardGate(0)\ - *(1/sqrt(2)*Qubit('01') + 1/sqrt(2)*Qubit('10')), nqubits=2))\ - == (Qubit('01')/2 + Qubit('00')/2 - Qubit('11')/2 + Qubit('10')/2) + assert matrix_to_qubit(represent(CNOT(0, 1)*HadamardGate(0) + *(1/sqrt(2)*Qubit('01') + 1/sqrt(2)*Qubit('10')), nqubits=2)) == \ + (Qubit('01')/2 + Qubit('00')/2 - Qubit('11')/2 + Qubit('10')/2) #test apply methods def test_apply_represent_equality(): - gates = [HadamardGate(int(3*random.random())),\ - XGate(int(3*random.random())), ZGate(int(3*random.random())),\ - YGate(int(3*random.random())), ZGate(int(3*random.random())),\ - PhaseGate(int(3*random.random()))] - - circuit = Qubit(int(random.random()*2),int(random.random()*2),\ - int(random.random()*2),int(random.random()*2),int(random.random()*2),\ - int(random.random()*2)) + gates = [HadamardGate(int(3*random.random())), + XGate(int(3*random.random())), ZGate(int(3*random.random())), + YGate(int(3*random.random())), ZGate(int(3*random.random())), + PhaseGate(int(3*random.random()))] + + circuit = Qubit(int(random.random()*2), int(random.random()*2), + int(random.random()*2), int(random.random()*2), int(random.random()*2), + int(random.random()*2)) for i in range(int(random.random()*6)): circuit = gates[int(random.random()*6)]*circuit - mat = represent(circuit, nqubits=6) states = qapply(circuit) state_rep = matrix_to_qubit(mat) @@ -82,62 +89,68 @@ def test_matrix_to_qubits(): - assert matrix_to_qubit(Matrix([1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]))\ - == Qubit(0,0,0,0) - assert qubit_to_matrix(Qubit(0,0,0,0)) ==\ - Matrix([1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]) - assert matrix_to_qubit(sqrt(2)*2*Matrix([1,1,1,1,1,1,1,1])) ==\ - (2*sqrt(2)*(Qubit(0,0,0) + Qubit(0,0,1) + Qubit(0,1,0) + Qubit(0,1,1)\ - + Qubit(1,0,0) + Qubit(1,0,1) + Qubit(1,1,0) + Qubit(1,1,1))).expand() - assert qubit_to_matrix(2*sqrt(2)*(Qubit(0,0,0) + Qubit(0,0,1) + Qubit(0,1,0)\ - + Qubit(0,1,1) + Qubit(1,0,0) + Qubit(1,0,1) + Qubit(1,1,0) + Qubit(1,1,1)))\ - == sqrt(2)*2*Matrix([1,1,1,1,1,1,1,1]) + assert matrix_to_qubit( + Matrix([1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])) == \ + Qubit(0, 0, 0, 0) + assert qubit_to_matrix(Qubit(0, 0, 0, 0)) == \ + Matrix([1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) + assert matrix_to_qubit(sqrt(2)*2*Matrix([1, 1, 1, 1, 1, 1, 1, 1])) == \ + (2*sqrt(2)*(Qubit(0, 0, 0) + Qubit(0, 0, 1) + Qubit(0, 1, 0) + + Qubit(0, 1, 1) + Qubit(1, 0, 0) + Qubit(1, 0, 1) + Qubit(1, 1, 0) + + Qubit(1, 1, 1))).expand() + assert qubit_to_matrix(2*sqrt(2)*(Qubit(0, 0, 0) + Qubit(0, 0, 1) + + Qubit(0, 1, 0) + Qubit(0, 1, 1) + Qubit(1, 0, 0) + Qubit(1, 0, 1) + + Qubit(1, 1, 0) + Qubit(1, 1, 1))) == \ + sqrt(2)*2*Matrix([1, 1, 1, 1, 1, 1, 1, 1]) + def test_measure_normalize(): - a,b = symbols('a b') + a, b = symbols('a b') state = a*Qubit('110') + b*Qubit('111') - assert measure_partial(state, (0,), normalize=False) ==\ - [(a*Qubit('110'), a*a.conjugate()), (b*Qubit('111'),b*b.conjugate())] - assert measure_all(state, normalize=False) ==\ - [(Qubit('110'), a*a.conjugate()),(Qubit('111'), b*b.conjugate())] + assert measure_partial(state, (0,), normalize=False) == \ + [(a*Qubit('110'), a*a.conjugate()), (b*Qubit('111'), b*b.conjugate())] + assert measure_all(state, normalize=False) == \ + [(Qubit('110'), a*a.conjugate()), (Qubit('111'), b*b.conjugate())] + def test_measure_partial(): #Basic test of collapse of entangled two qubits (Bell States) state = Qubit('01') + Qubit('10') - assert sorted(measure_partial(state, (0,))) ==\ - [(Qubit('01'), Rational(1,2)), (Qubit('10'), Rational(1,2))] - assert sorted(measure_partial(state, (0,))) ==\ - sorted(measure_partial(state, (1,))) + assert sorted(measure_partial(state, (0,))) == \ + [(Qubit('01'), Rational(1, 2)), (Qubit('10'), Rational(1, 2))] + assert sorted(measure_partial(state, (0,))) == \ + sorted(measure_partial(state, (1,))) #Test of more complex collapse and probability calculation state1 = sqrt(2)/sqrt(3)*Qubit('00001') + 1/sqrt(3)*Qubit('11111') - assert measure_partial(state1, (0,)) ==\ - [(sqrt(2)/sqrt(3)*Qubit('00001') + 1/sqrt(3)*Qubit('11111'), 1)] - assert measure_partial(state1, (1,2)) == measure_partial(state1, (3,4)) - assert measure_partial(state1, (1,2,3)) ==\ - [(Qubit('00001'), Rational(2,3)), (Qubit('11111'), Rational(1,3))] + assert measure_partial(state1, (0,)) == \ + [(sqrt(2)/sqrt(3)*Qubit('00001') + 1/sqrt(3)*Qubit('11111'), 1)] + assert measure_partial(state1, (1, 2)) == measure_partial(state1, (3, 4)) + assert measure_partial(state1, (1, 2, 3)) == \ + [(Qubit('00001'), Rational(2, 3)), (Qubit('11111'), Rational(1, 3))] #test of measuring multiple bits at once state2 = Qubit('1111') + Qubit('1101') + Qubit('1011') + Qubit('1000') - assert sorted(measure_partial(state2, (0,1,3))) ==\ - sorted([(Qubit('1011')/sqrt(2) + Qubit('1111')/sqrt(2), Rational(1,2)), \ - (Qubit('1101'), Rational(1,4)), (Qubit('1000'), Rational(1,4))]) - assert sorted(measure_partial(state2, (0,))) ==\ - sorted([(Qubit('1111')/sqrt(3) + Qubit('1101')/sqrt(3) + Qubit('1011')/sqrt(3), Rational(3,4)),\ - (Qubit('1000'), Rational(1,4))]) + assert sorted(measure_partial(state2, (0, 1, 3))) == sorted( + [(Qubit('1011')/sqrt(2) + Qubit('1111')/sqrt(2), Rational(1, 2)), + (Qubit('1101'), Rational(1, 4)), (Qubit('1000'), Rational(1, 4))]) + assert sorted(measure_partial(state2, (0,))) == sorted( + [(Qubit('1111')/sqrt(3) + Qubit('1101')/sqrt(3) + + Qubit('1011')/sqrt(3), Rational(3, 4)), + (Qubit('1000'), Rational(1, 4))]) def test_measure_all(): assert measure_all(Qubit('11')) == [(Qubit('11'), 1)] state = Qubit('11') + Qubit('10') - assert sorted(measure_all(state)) == sorted([(Qubit('11'), Rational(1,2)),\ - (Qubit('10'), Rational(1,2))]) + assert sorted(measure_all(state)) == sorted([(Qubit('11'), Rational(1, 2)), + (Qubit('10'), Rational(1, 2))]) state2 = Qubit('11')/sqrt(5) + 2*Qubit('00')/sqrt(5) - assert sorted(measure_all(state2)) == sorted([(Qubit('11'), Rational(1,5)), \ - (Qubit('00'), Rational(4,5))]) + assert sorted(measure_all(state2)) == sorted( + [(Qubit('11'), Rational(1, 5)), (Qubit('00'), Rational(4, 5))]) -def test_eval_trace(): +def test_eval_trace(): q1 = Qubit('10110') q2 = Qubit('01010') d = Density([q1, 0.6], [q2, 0.4]) @@ -157,7 +170,7 @@ assert t.doit() == (0.4*Density([Qubit('0110'), 1]) + 0.6*Density([Qubit('1010'), 1])) #trace all indices - t = Tr(d, [0,1,2,3,4]) + t = Tr(d, [0, 1, 2, 3, 4]) assert t.doit() == 1 # trace some indices, initialized in @@ -168,11 +181,12 @@ # mixed states q = (1/sqrt(2)) * (Qubit('00') + Qubit('11')) - d = Density ( [q, 1.0] ) + d = Density( [q, 1.0] ) t = Tr(d, 0) assert t.doit() == (0.5*Density([Qubit('0'), 1]) + 0.5*Density([Qubit('1'), 1])) + def test_matrix_to_density(): mat = Matrix([[0, 0], [0, 1]]) assert matrix_to_density(mat) == Density([Qubit('1'), 1]) diff -Nru python3-sympy-0.7.2/sympy/physics/quantum/tests/test_represent.py python3-sympy-0.7.3/sympy/physics/quantum/tests/test_represent.py --- python3-sympy-0.7.2/sympy/physics/quantum/tests/test_represent.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/physics/quantum/tests/test_represent.py 2013-07-13 17:53:32.000000000 +0000 @@ -19,9 +19,10 @@ from sympy.physics.quantum.qapply import qapply from sympy.physics.quantum.operatorset import operators_to_state -Amat = Matrix([[1,I],[-I,1]]) -Bmat = Matrix([[1,2],[3,4]]) -Avec = Matrix([[1],[I]]) +Amat = Matrix([[1, I], [-I, 1]]) +Bmat = Matrix([[1, 2], [3, 4]]) +Avec = Matrix([[1], [I]]) + class AKet(Ket): @@ -77,19 +78,19 @@ (A, Amat), (Dagger(A), Dagger(Amat)), # OuterProduct - (OuterProduct(k,b), Avec*Avec.H), + (OuterProduct(k, b), Avec*Avec.H), # TensorProduct - (TensorProduct(A,B), matrix_tensor_product(Amat,Bmat)), + (TensorProduct(A, B), matrix_tensor_product(Amat, Bmat)), # Pow (A**2, Amat**2), # Add/Mul (A*B + 2*A, Amat*Bmat + 2*Amat), # Commutator - (Commutator(A,B), Amat*Bmat - Bmat*Amat), + (Commutator(A, B), Amat*Bmat - Bmat*Amat), # AntiCommutator - (AntiCommutator(A,B), Amat*Bmat + Bmat*Amat), + (AntiCommutator(A, B), Amat*Bmat + Bmat*Amat), # InnerProduct - (InnerProduct(b,k), (Avec.H*Avec)[0]) + (InnerProduct(b, k), (Avec.H*Avec)[0]) ] @@ -99,14 +100,16 @@ rhs = to_sympy(test[1]) assert lhs == rhs + def test_scalar_sympy(): assert represent(Integer(1)) == Integer(1) assert represent(Float(1.0)) == Float(1.0) - assert represent(1.0+I) == 1.0+I + assert represent(1.0 + I) == 1.0 + I np = import_module('numpy', min_python_version=(2, 6)) + def test_format_numpy(): if not np: skip("numpy not installed or Python too old.") @@ -119,16 +122,18 @@ else: assert lhs == rhs + def test_scalar_numpy(): if not np: skip("numpy not installed or Python too old.") assert represent(Integer(1), format='numpy') == 1 assert represent(Float(1.0), format='numpy') == 1.0 - assert represent(1.0+I, format='numpy') == 1.0+1.0j + assert represent(1.0 + I, format='numpy') == 1.0 + 1.0j + +scipy = import_module('scipy', __import__kwargs={'fromlist': ['sparse']}) -scipy = import_module('scipy', __import__kwargs={'fromlist':['sparse']}) def test_format_scipy_sparse(): if not np: @@ -140,10 +145,11 @@ lhs = represent(test[0], basis=A, format='scipy.sparse') rhs = to_scipy_sparse(test[1]) if isinstance(lhs, scipy_sparse_matrix): - assert np.linalg.norm((lhs-rhs).todense()) == 0.0 + assert np.linalg.norm((lhs - rhs).todense()) == 0.0 else: assert lhs == rhs + def test_scalar_scipy_sparse(): if not np: skip("numpy not installed or Python too old.") @@ -152,12 +158,13 @@ assert represent(Integer(1), format='scipy.sparse') == 1 assert represent(Float(1.0), format='scipy.sparse') == 1.0 - assert represent(1.0+I, format='scipy.sparse') == 1.0+1.0j + assert represent(1.0 + I, format='scipy.sparse') == 1.0 + 1.0j x_ket = XKet('x') x_bra = XBra('x') x_op = XOp('X') + def test_innerprod_represent(): assert rep_innerproduct(x_ket) == InnerProduct(XBra("x_1"), x_ket).doit() assert rep_innerproduct(x_bra) == InnerProduct(x_bra, XKet("x_1")).doit() @@ -167,11 +174,15 @@ except TypeError: return True + def test_operator_represent(): basis_kets = enumerate_states(operators_to_state(x_op), 1, 2) - assert rep_expectation(x_op) == qapply(basis_kets[1].dual*x_op*basis_kets[0]) + assert rep_expectation( + x_op) == qapply(basis_kets[1].dual*x_op*basis_kets[0]) + def test_enumerate_states(): test = XKet("foo") assert enumerate_states(test, 1, 1) == [XKet("foo_1")] - assert enumerate_states(test, [1, 2, 4]) == [XKet("foo_1"), XKet("foo_2"), XKet("foo_4")] + assert enumerate_states( + test, [1, 2, 4]) == [XKet("foo_1"), XKet("foo_2"), XKet("foo_4")] diff -Nru python3-sympy-0.7.2/sympy/physics/quantum/tests/test_sho1d.py python3-sympy-0.7.3/sympy/physics/quantum/tests/test_sho1d.py --- python3-sympy-0.7.2/sympy/physics/quantum/tests/test_sho1d.py 1970-01-01 00:00:00.000000000 +0000 +++ python3-sympy-0.7.3/sympy/physics/quantum/tests/test_sho1d.py 2013-07-13 17:53:32.000000000 +0000 @@ -0,0 +1,119 @@ +"""Tests for sho1d.py""" + +from sympy import Integer, Symbol, sqrt, I, S +from sympy.physics.quantum import Dagger +from sympy.physics.quantum.constants import hbar +from sympy.physics.quantum import Commutator +from sympy.physics.quantum.qapply import qapply +from sympy.physics.quantum.innerproduct import InnerProduct +from sympy.physics.quantum.cartesian import X, Px +from sympy.functions.special.tensor_functions import KroneckerDelta +from sympy.physics.quantum.hilbert import ComplexSpace +from sympy.physics.quantum.represent import represent +from sympy.external import import_module +from sympy.utilities.pytest import skip + +from sympy.physics.quantum.sho1d import (RaisingOp, LoweringOp, + SHOKet, SHOBra, + Hamiltonian, NumberOp) + +ad = RaisingOp('a') +a = LoweringOp('a') +k = SHOKet('k') +kz = SHOKet(0) +kf = SHOKet(1) +k3 = SHOKet(3) +b = SHOBra('b') +b3 = SHOBra(3) +H = Hamiltonian('H') +N = NumberOp('N') +omega = Symbol('omega') +m = Symbol('m') +ndim = Integer(4) + +np = import_module('numpy', min_python_version=(2, 6)) +scipy = import_module('scipy', __import__kwargs={'fromlist': ['sparse']}) + +ad_rep_sympy = represent(ad, basis=N, ndim=4, format='sympy') +a_rep = represent(a, basis=N, ndim=4, format='sympy') +N_rep = represent(N, basis=N, ndim=4, format='sympy') +H_rep = represent(H, basis=N, ndim=4, format='sympy') +k3_rep = represent(k3, basis=N, ndim=4, format='sympy') +b3_rep = represent(b3, basis=N, ndim=4, format='sympy') + +def test_RaisingOp(): + assert Dagger(ad) == a + assert Commutator(ad, a).doit() == Integer(-1) + assert Commutator(ad, N).doit() == Integer(-1)*ad + assert qapply(ad*k) == (sqrt(k.n + 1)*SHOKet(k.n + 1)).expand() + assert qapply(ad*kz) == (sqrt(kz.n + 1)*SHOKet(kz.n + 1)).expand() + assert qapply(ad*kf) == (sqrt(kf.n + 1)*SHOKet(kf.n + 1)).expand() + assert ad.rewrite('xp').doit() == \ + (Integer(1)/sqrt(Integer(2)*hbar*m*omega))*(Integer(-1)*I*Px + m*omega*X) + assert ad.hilbert_space == ComplexSpace(S.Infinity) + for i in range(ndim - 1): + assert ad_rep_sympy[i + 1,i] == sqrt(i + 1) + + if not np: + skip("numpy not installed or Python too old.") + + ad_rep_numpy = represent(ad, basis=N, ndim=4, format='numpy') + for i in range(ndim - 1): + assert ad_rep_numpy[i + 1,i] == float(sqrt(i + 1)) + + if not np: + skip("numpy not installed or Python too old.") + if not scipy: + skip("scipy not installed.") + else: + sparse = scipy.sparse + + ad_rep_scipy = represent(ad, basis=N, ndim=4, format='scipy.sparse', spmatrix='lil') + for i in range(ndim - 1): + assert ad_rep_scipy[i + 1,i] == float(sqrt(i + 1)) + + assert ad_rep_numpy.dtype == 'float64' + assert ad_rep_scipy.dtype == 'float64' + +def test_LoweringOp(): + assert Dagger(a) == ad + assert Commutator(a, ad).doit() == Integer(1) + assert Commutator(a, N).doit() == a + assert qapply(a*k) == (sqrt(k.n)*SHOKet(k.n-Integer(1))).expand() + assert qapply(a*kz) == Integer(0) + assert qapply(a*kf) == (sqrt(kf.n)*SHOKet(kf.n-Integer(1))).expand() + assert a.rewrite('xp').doit() == \ + (Integer(1)/sqrt(Integer(2)*hbar*m*omega))*(I*Px + m*omega*X) + for i in range(ndim - 1): + assert a_rep[i,i + 1] == sqrt(i + 1) + +def test_NumberOp(): + assert Commutator(N, ad).doit() == ad + assert Commutator(N, a).doit() == Integer(-1)*a + assert Commutator(N, H).doit() == Integer(0) + assert qapply(N*k) == (k.n*k).expand() + assert N.rewrite('a').doit() == ad*a + assert N.rewrite('xp').doit() == (Integer(1)/(Integer(2)*m*hbar*omega))*( + Px**2 + (m*omega*X)**2) - Integer(1)/Integer(2) + assert N.rewrite('H').doit() == H/(hbar*omega) - Integer(1)/Integer(2) + for i in range(ndim): + assert N_rep[i,i] == i + assert N_rep == ad_rep_sympy*a_rep + +def test_Hamiltonian(): + assert Commutator(H, N).doit() == Integer(0) + assert qapply(H*k) == ((hbar*omega*(k.n + Integer(1)/Integer(2)))*k).expand() + assert H.rewrite('a').doit() == hbar*omega*(ad*a + Integer(1)/Integer(2)) + assert H.rewrite('xp').doit() == \ + (Integer(1)/(Integer(2)*m))*(Px**2 + (m*omega*X)**2) + assert H.rewrite('N').doit() == hbar*omega*(N + Integer(1)/Integer(2)) + for i in range(ndim): + assert H_rep[i,i] == hbar*omega*(i + Integer(1)/Integer(2)) + +def test_SHOKet(): + assert SHOKet('k').dual_class() == SHOBra + assert SHOBra('b').dual_class() == SHOKet + assert InnerProduct(b,k).doit() == KroneckerDelta(k.n, b.n) + assert k.hilbert_space == ComplexSpace(S.Infinity) + assert k3_rep[k3.n, 0] == Integer(1) + assert b3_rep[0, b3.n] == Integer(1) diff -Nru python3-sympy-0.7.2/sympy/physics/quantum/tests/test_shor.py python3-sympy-0.7.3/sympy/physics/quantum/tests/test_shor.py --- python3-sympy-0.7.2/sympy/physics/quantum/tests/test_shor.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/physics/quantum/tests/test_shor.py 2013-07-13 17:53:32.000000000 +0000 @@ -3,26 +3,24 @@ from sympy.physics.quantum.qapply import qapply from sympy.physics.quantum.qubit import Qubit from sympy.physics.quantum.shor import ( - CMod, continued_fraction, getr, arr + CMod, continued_fraction, getr ) @XFAIL def test_CMod(): - assert qapply(CMod(4, 2, 2)*Qubit(0,0,1,0,0,0,0,0)) ==\ - Qubit(0,0,1,0,0,0,0,0) - assert qapply(CMod(5, 5, 7)*Qubit(0,0,1,0,0,0,0,0,0,0)) ==\ - Qubit(0,0,1,0,0,0,0,0,1,0) - assert qapply(CMod(3, 2, 3)*Qubit(0,1,0,0,0,0)) ==\ - Qubit(0,1,0,0,0,1) + assert qapply(CMod(4, 2, 2)*Qubit(0, 0, 1, 0, 0, 0, 0, 0)) == \ + Qubit(0, 0, 1, 0, 0, 0, 0, 0) + assert qapply(CMod(5, 5, 7)*Qubit(0, 0, 1, 0, 0, 0, 0, 0, 0, 0)) == \ + Qubit(0, 0, 1, 0, 0, 0, 0, 0, 1, 0) + assert qapply(CMod(3, 2, 3)*Qubit(0, 1, 0, 0, 0, 0)) == \ + Qubit(0, 1, 0, 0, 0, 1) + def test_continued_frac(): - assert continued_fraction(3245, 10000) == [0,3,12,4,13] + assert continued_fraction(3245, 10000) == [0, 3, 12, 4, 13] assert continued_fraction(1932, 2568) == [0, 1, 3, 26, 2] assert continued_fraction(6589, 2569) == [2, 1, 1, 3, 2, 1, 3, 1, 23] assert getr(513, 1024, 10) == 2 assert getr(169, 1024, 11) == 6 assert getr(314, 4096, 16) == 13 - assert arr(5,3) == [1,0,1] - assert arr(4,3) == [1,0,0] - assert arr(8,5) == [0,1,0,0,0] diff -Nru python3-sympy-0.7.2/sympy/physics/quantum/tests/test_spin.py python3-sympy-0.7.3/sympy/physics/quantum/tests/test_spin.py --- python3-sympy-0.7.2/sympy/physics/quantum/tests/test_spin.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/physics/quantum/tests/test_spin.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,7 +1,6 @@ from sympy import cos, exp, expand, I, Matrix, pi, S, sin, sqrt, Sum, symbols from sympy.abc import alpha, beta, gamma, j, m - from sympy.physics.quantum import hbar, represent, Commutator, InnerProduct from sympy.physics.quantum.qapply import qapply from sympy.physics.quantum.tensorproduct import TensorProduct @@ -17,1367 +16,1633 @@ from sympy.utilities.pytest import raises -j1,j2,j3,j4,m1,m2,m3,m4 = symbols('j1:5 m1:5') -j12,j13,j24,j34,j123,j134,mi,mi1,mp = symbols('j12 j13 j24 j34 j123 j134 mi mi1 mp') +j1, j2, j3, j4, m1, m2, m3, m4 = symbols('j1:5 m1:5') +j12, j13, j24, j34, j123, j134, mi, mi1, mp = symbols( + 'j12 j13 j24 j34 j123 j134 mi mi1 mp') + def test_represent_spin_operators(): - assert represent(Jx) == hbar*Matrix([[0,1],[1,0]])/2 - assert represent(Jx, j=1) == hbar*sqrt(2)*Matrix([[0,1,0],[1,0,1],[0,1,0]])/2 - assert represent(Jy) == hbar*I*Matrix([[0,-1],[1,0]])/2 - assert represent(Jy, j=1) == hbar*I*sqrt(2)*Matrix([[0,-1,0],[1,0,-1],[0,1,0]])/2 - assert represent(Jz) == hbar*Matrix([[1,0],[0,-1]])/2 - assert represent(Jz, j=1) == hbar*Matrix([[1,0,0],[0,0,0],[0,0,-1]]) + assert represent(Jx) == hbar*Matrix([[0, 1], [1, 0]])/2 + assert represent( + Jx, j=1) == hbar*sqrt(2)*Matrix([[0, 1, 0], [1, 0, 1], [0, 1, 0]])/2 + assert represent(Jy) == hbar*I*Matrix([[0, -1], [1, 0]])/2 + assert represent(Jy, j=1) == hbar*I*sqrt(2)*Matrix([[0, -1, 0], [1, + 0, -1], [0, 1, 0]])/2 + assert represent(Jz) == hbar*Matrix([[1, 0], [0, -1]])/2 + assert represent( + Jz, j=1) == hbar*Matrix([[1, 0, 0], [0, 0, 0], [0, 0, -1]]) + def test_represent_spin_states(): # Jx basis - assert represent(JxKet(S(1)/2,S(1)/2), basis=Jx) == Matrix([1,0]) - assert represent(JxKet(S(1)/2,-S(1)/2), basis=Jx) == Matrix([0,1]) - assert represent(JxKet(1,1), basis=Jx) == Matrix([1,0,0]) - assert represent(JxKet(1,0), basis=Jx) == Matrix([0,1,0]) - assert represent(JxKet(1,-1), basis=Jx) == Matrix([0,0,1]) - assert represent(JyKet(S(1)/2,S(1)/2), basis=Jx) == Matrix([exp(-I*pi/4),0]) - assert represent(JyKet(S(1)/2,-S(1)/2), basis=Jx) == Matrix([0,exp(I*pi/4)]) - assert represent(JyKet(1,1), basis=Jx) == Matrix([-I,0,0]) - assert represent(JyKet(1,0), basis=Jx) == Matrix([0,1,0]) - assert represent(JyKet(1,-1), basis=Jx) == Matrix([0,0,I]) - assert represent(JzKet(S(1)/2,S(1)/2), basis=Jx) == sqrt(2)*Matrix([-1,1])/2 - assert represent(JzKet(S(1)/2,-S(1)/2), basis=Jx) == sqrt(2)*Matrix([-1,-1])/2 - assert represent(JzKet(1,1), basis=Jx) == Matrix([1,-sqrt(2),1])/2 - assert represent(JzKet(1,0), basis=Jx) == sqrt(2)*Matrix([1,0,-1])/2 - assert represent(JzKet(1,-1), basis=Jx) == Matrix([1,sqrt(2),1])/2 + assert represent(JxKet(S(1)/2, S(1)/2), basis=Jx) == Matrix([1, 0]) + assert represent(JxKet(S(1)/2, -S(1)/2), basis=Jx) == Matrix([0, 1]) + assert represent(JxKet(1, 1), basis=Jx) == Matrix([1, 0, 0]) + assert represent(JxKet(1, 0), basis=Jx) == Matrix([0, 1, 0]) + assert represent(JxKet(1, -1), basis=Jx) == Matrix([0, 0, 1]) + assert represent( + JyKet(S(1)/2, S(1)/2), basis=Jx) == Matrix([exp(-I*pi/4), 0]) + assert represent( + JyKet(S(1)/2, -S(1)/2), basis=Jx) == Matrix([0, exp(I*pi/4)]) + assert represent(JyKet(1, 1), basis=Jx) == Matrix([-I, 0, 0]) + assert represent(JyKet(1, 0), basis=Jx) == Matrix([0, 1, 0]) + assert represent(JyKet(1, -1), basis=Jx) == Matrix([0, 0, I]) + assert represent( + JzKet(S(1)/2, S(1)/2), basis=Jx) == sqrt(2)*Matrix([-1, 1])/2 + assert represent( + JzKet(S(1)/2, -S(1)/2), basis=Jx) == sqrt(2)*Matrix([-1, -1])/2 + assert represent(JzKet(1, 1), basis=Jx) == Matrix([1, -sqrt(2), 1])/2 + assert represent(JzKet(1, 0), basis=Jx) == sqrt(2)*Matrix([1, 0, -1])/2 + assert represent(JzKet(1, -1), basis=Jx) == Matrix([1, sqrt(2), 1])/2 # Jy basis - assert represent(JxKet(S(1)/2,S(1)/2), basis=Jy) == Matrix([exp(-3*I*pi/4),0]) - assert represent(JxKet(S(1)/2,-S(1)/2), basis=Jy) == Matrix([0,exp(3*I*pi/4)]) - assert represent(JxKet(1,1), basis=Jy) == Matrix([I,0,0]) - assert represent(JxKet(1,0), basis=Jy) == Matrix([0,1,0]) - assert represent(JxKet(1,-1), basis=Jy) == Matrix([0,0,-I]) - assert represent(JyKet(S(1)/2,S(1)/2), basis=Jy) == Matrix([1,0]) - assert represent(JyKet(S(1)/2,-S(1)/2), basis=Jy) == Matrix([0,1]) - assert represent(JyKet(1,1), basis=Jy) == Matrix([1,0,0]) - assert represent(JyKet(1,0), basis=Jy) == Matrix([0,1,0]) - assert represent(JyKet(1,-1), basis=Jy) == Matrix([0,0,1]) - assert represent(JzKet(S(1)/2,S(1)/2), basis=Jy) == sqrt(2)*Matrix([-1,I])/2 - assert represent(JzKet(S(1)/2,-S(1)/2), basis=Jy) == sqrt(2)*Matrix([I,-1])/2 - assert represent(JzKet(1,1), basis=Jy) == Matrix([1,-I*sqrt(2),-1])/2 - assert represent(JzKet(1,0), basis=Jy) == Matrix([-sqrt(2)*I,0,-sqrt(2)*I])/2 - assert represent(JzKet(1,-1), basis=Jy) == Matrix([-1,-sqrt(2)*I,1])/2 + assert represent( + JxKet(S(1)/2, S(1)/2), basis=Jy) == Matrix([exp(-3*I*pi/4), 0]) + assert represent( + JxKet(S(1)/2, -S(1)/2), basis=Jy) == Matrix([0, exp(3*I*pi/4)]) + assert represent(JxKet(1, 1), basis=Jy) == Matrix([I, 0, 0]) + assert represent(JxKet(1, 0), basis=Jy) == Matrix([0, 1, 0]) + assert represent(JxKet(1, -1), basis=Jy) == Matrix([0, 0, -I]) + assert represent(JyKet(S(1)/2, S(1)/2), basis=Jy) == Matrix([1, 0]) + assert represent(JyKet(S(1)/2, -S(1)/2), basis=Jy) == Matrix([0, 1]) + assert represent(JyKet(1, 1), basis=Jy) == Matrix([1, 0, 0]) + assert represent(JyKet(1, 0), basis=Jy) == Matrix([0, 1, 0]) + assert represent(JyKet(1, -1), basis=Jy) == Matrix([0, 0, 1]) + assert represent( + JzKet(S(1)/2, S(1)/2), basis=Jy) == sqrt(2)*Matrix([-1, I])/2 + assert represent( + JzKet(S(1)/2, -S(1)/2), basis=Jy) == sqrt(2)*Matrix([I, -1])/2 + assert represent(JzKet(1, 1), basis=Jy) == Matrix([1, -I*sqrt(2), -1])/2 + assert represent( + JzKet(1, 0), basis=Jy) == Matrix([-sqrt(2)*I, 0, -sqrt(2)*I])/2 + assert represent(JzKet(1, -1), basis=Jy) == Matrix([-1, -sqrt(2)*I, 1])/2 # Jz basis - assert represent(JxKet(S(1)/2,S(1)/2), basis=Jz) == sqrt(2)*Matrix([1,1])/2 - assert represent(JxKet(S(1)/2,-S(1)/2), basis=Jz) == sqrt(2)*Matrix([-1,1])/2 - assert represent(JxKet(1,1), basis=Jz) == Matrix([1,sqrt(2),1])/2 - assert represent(JxKet(1,0), basis=Jz) == sqrt(2)*Matrix([-1,0,1])/2 - assert represent(JxKet(1,-1), basis=Jz) == Matrix([1,-sqrt(2),1])/2 - assert represent(JyKet(S(1)/2,S(1)/2), basis=Jz) == sqrt(2)*Matrix([-1,-I])/2 - assert represent(JyKet(S(1)/2,-S(1)/2), basis=Jz) == sqrt(2)*Matrix([-I,-1])/2 - assert represent(JyKet(1,1), basis=Jz) == Matrix([1,sqrt(2)*I,-1])/2 - assert represent(JyKet(1,0), basis=Jz) == sqrt(2)*Matrix([I,0,I])/2 - assert represent(JyKet(1,-1), basis=Jz) == Matrix([-1,sqrt(2)*I,1])/2 - assert represent(JzKet(S(1)/2,S(1)/2), basis=Jz) == Matrix([1,0]) - assert represent(JzKet(S(1)/2,-S(1)/2), basis=Jz) == Matrix([0,1]) - assert represent(JzKet(1,1), basis=Jz) == Matrix([1,0,0]) - assert represent(JzKet(1,0), basis=Jz) == Matrix([0,1,0]) - assert represent(JzKet(1,-1), basis=Jz) == Matrix([0,0,1]) + assert represent( + JxKet(S(1)/2, S(1)/2), basis=Jz) == sqrt(2)*Matrix([1, 1])/2 + assert represent( + JxKet(S(1)/2, -S(1)/2), basis=Jz) == sqrt(2)*Matrix([-1, 1])/2 + assert represent(JxKet(1, 1), basis=Jz) == Matrix([1, sqrt(2), 1])/2 + assert represent(JxKet(1, 0), basis=Jz) == sqrt(2)*Matrix([-1, 0, 1])/2 + assert represent(JxKet(1, -1), basis=Jz) == Matrix([1, -sqrt(2), 1])/2 + assert represent( + JyKet(S(1)/2, S(1)/2), basis=Jz) == sqrt(2)*Matrix([-1, -I])/2 + assert represent( + JyKet(S(1)/2, -S(1)/2), basis=Jz) == sqrt(2)*Matrix([-I, -1])/2 + assert represent(JyKet(1, 1), basis=Jz) == Matrix([1, sqrt(2)*I, -1])/2 + assert represent(JyKet(1, 0), basis=Jz) == sqrt(2)*Matrix([I, 0, I])/2 + assert represent(JyKet(1, -1), basis=Jz) == Matrix([-1, sqrt(2)*I, 1])/2 + assert represent(JzKet(S(1)/2, S(1)/2), basis=Jz) == Matrix([1, 0]) + assert represent(JzKet(S(1)/2, -S(1)/2), basis=Jz) == Matrix([0, 1]) + assert represent(JzKet(1, 1), basis=Jz) == Matrix([1, 0, 0]) + assert represent(JzKet(1, 0), basis=Jz) == Matrix([0, 1, 0]) + assert represent(JzKet(1, -1), basis=Jz) == Matrix([0, 0, 1]) + def test_represent_uncoupled_states(): # Jx basis - assert represent(TensorProduct(JxKet(S(1)/2,S(1)/2),JxKet(S(1)/2,S(1)/2)), basis=Jx) == \ - Matrix([1,0,0,0]) - assert represent(TensorProduct(JxKet(S(1)/2,S(1)/2),JxKet(S(1)/2,-S(1)/2)), basis=Jx) == \ - Matrix([0,1,0,0]) - assert represent(TensorProduct(JxKet(S(1)/2,-S(1)/2),JxKet(S(1)/2,S(1)/2)), basis=Jx) == \ - Matrix([0,0,1,0]) - assert represent(TensorProduct(JxKet(S(1)/2,-S(1)/2),JxKet(S(1)/2,-S(1)/2)), basis=Jx) == \ - Matrix([0,0,0,1]) - assert represent(TensorProduct(JyKet(S(1)/2,S(1)/2),JyKet(S(1)/2,S(1)/2)), basis=Jx) == \ - Matrix([-I,0,0,0]) - assert represent(TensorProduct(JyKet(S(1)/2,S(1)/2),JyKet(S(1)/2,-S(1)/2)), basis=Jx) == \ - Matrix([0,1,0,0]) - assert represent(TensorProduct(JyKet(S(1)/2,-S(1)/2),JyKet(S(1)/2,S(1)/2)), basis=Jx) == \ - Matrix([0,0,1,0]) - assert represent(TensorProduct(JyKet(S(1)/2,-S(1)/2),JyKet(S(1)/2,-S(1)/2)), basis=Jx) == \ - Matrix([0,0,0,I]) - assert represent(TensorProduct(JzKet(S(1)/2,S(1)/2),JzKet(S(1)/2,S(1)/2)), basis=Jx) == \ - Matrix([S(1)/2,-S(1)/2,-S(1)/2,S(1)/2]) - assert represent(TensorProduct(JzKet(S(1)/2,S(1)/2),JzKet(S(1)/2,-S(1)/2)), basis=Jx) == \ - Matrix([S(1)/2,S(1)/2,-S(1)/2,-S(1)/2]) - assert represent(TensorProduct(JzKet(S(1)/2,-S(1)/2),JzKet(S(1)/2,S(1)/2)), basis=Jx) == \ - Matrix([S(1)/2,-S(1)/2,S(1)/2,-S(1)/2]) - assert represent(TensorProduct(JzKet(S(1)/2,-S(1)/2),JzKet(S(1)/2,-S(1)/2)), basis=Jx) == \ - Matrix([S(1)/2,S(1)/2,S(1)/2,S(1)/2]) + assert represent(TensorProduct(JxKet(S(1)/2, S(1)/2), JxKet(S(1)/2, S(1)/2)), basis=Jx) == \ + Matrix([1, 0, 0, 0]) + assert represent(TensorProduct(JxKet(S(1)/2, S(1)/2), JxKet(S(1)/2, -S(1)/2)), basis=Jx) == \ + Matrix([0, 1, 0, 0]) + assert represent(TensorProduct(JxKet(S(1)/2, -S(1)/2), JxKet(S(1)/2, S(1)/2)), basis=Jx) == \ + Matrix([0, 0, 1, 0]) + assert represent(TensorProduct(JxKet(S(1)/2, -S(1)/2), JxKet(S(1)/2, -S(1)/2)), basis=Jx) == \ + Matrix([0, 0, 0, 1]) + assert represent(TensorProduct(JyKet(S(1)/2, S(1)/2), JyKet(S(1)/2, S(1)/2)), basis=Jx) == \ + Matrix([-I, 0, 0, 0]) + assert represent(TensorProduct(JyKet(S(1)/2, S(1)/2), JyKet(S(1)/2, -S(1)/2)), basis=Jx) == \ + Matrix([0, 1, 0, 0]) + assert represent(TensorProduct(JyKet(S(1)/2, -S(1)/2), JyKet(S(1)/2, S(1)/2)), basis=Jx) == \ + Matrix([0, 0, 1, 0]) + assert represent(TensorProduct(JyKet(S(1)/2, -S(1)/2), JyKet(S(1)/2, -S(1)/2)), basis=Jx) == \ + Matrix([0, 0, 0, I]) + assert represent(TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2)), basis=Jx) == \ + Matrix([S(1)/2, -S(1)/2, -S(1)/2, S(1)/2]) + assert represent(TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, -S(1)/2)), basis=Jx) == \ + Matrix([S(1)/2, S(1)/2, -S(1)/2, -S(1)/2]) + assert represent(TensorProduct(JzKet(S(1)/2, -S(1)/2), JzKet(S(1)/2, S(1)/2)), basis=Jx) == \ + Matrix([S(1)/2, -S(1)/2, S(1)/2, -S(1)/2]) + assert represent(TensorProduct(JzKet(S(1)/2, -S(1)/2), JzKet(S(1)/2, -S(1)/2)), basis=Jx) == \ + Matrix([S(1)/2, S(1)/2, S(1)/2, S(1)/2]) # Jy basis - assert represent(TensorProduct(JxKet(S(1)/2,S(1)/2),JxKet(S(1)/2,S(1)/2)), basis=Jy) == \ - Matrix([I,0,0,0]) - assert represent(TensorProduct(JxKet(S(1)/2,S(1)/2),JxKet(S(1)/2,-S(1)/2)), basis=Jy) == \ - Matrix([0,1,0,0]) - assert represent(TensorProduct(JxKet(S(1)/2,-S(1)/2),JxKet(S(1)/2,S(1)/2)), basis=Jy) == \ - Matrix([0,0,1,0]) - assert represent(TensorProduct(JxKet(S(1)/2,-S(1)/2),JxKet(S(1)/2,-S(1)/2)), basis=Jy) == \ - Matrix([0,0,0,-I]) - assert represent(TensorProduct(JyKet(S(1)/2,S(1)/2),JyKet(S(1)/2,S(1)/2)), basis=Jy) == \ - Matrix([1,0,0,0]) - assert represent(TensorProduct(JyKet(S(1)/2,S(1)/2),JyKet(S(1)/2,-S(1)/2)), basis=Jy) == \ - Matrix([0,1,0,0]) - assert represent(TensorProduct(JyKet(S(1)/2,-S(1)/2),JyKet(S(1)/2,S(1)/2)), basis=Jy) == \ - Matrix([0,0,1,0]) - assert represent(TensorProduct(JyKet(S(1)/2,-S(1)/2),JyKet(S(1)/2,-S(1)/2)), basis=Jy) == \ - Matrix([0,0,0,1]) - assert represent(TensorProduct(JzKet(S(1)/2,S(1)/2),JzKet(S(1)/2,S(1)/2)), basis=Jy) == \ - Matrix([S(1)/2,-I/2,-I/2,-S(1)/2]) - assert represent(TensorProduct(JzKet(S(1)/2,S(1)/2),JzKet(S(1)/2,-S(1)/2)), basis=Jy) == \ - Matrix([-I/2,S(1)/2,-S(1)/2,-I/2]) - assert represent(TensorProduct(JzKet(S(1)/2,-S(1)/2),JzKet(S(1)/2,S(1)/2)), basis=Jy) == \ - Matrix([-I/2,-S(1)/2,S(1)/2,-I/2]) - assert represent(TensorProduct(JzKet(S(1)/2,-S(1)/2),JzKet(S(1)/2,-S(1)/2)), basis=Jy) == \ - Matrix([-S(1)/2,-I/2,-I/2,S(1)/2]) + assert represent(TensorProduct(JxKet(S(1)/2, S(1)/2), JxKet(S(1)/2, S(1)/2)), basis=Jy) == \ + Matrix([I, 0, 0, 0]) + assert represent(TensorProduct(JxKet(S(1)/2, S(1)/2), JxKet(S(1)/2, -S(1)/2)), basis=Jy) == \ + Matrix([0, 1, 0, 0]) + assert represent(TensorProduct(JxKet(S(1)/2, -S(1)/2), JxKet(S(1)/2, S(1)/2)), basis=Jy) == \ + Matrix([0, 0, 1, 0]) + assert represent(TensorProduct(JxKet(S(1)/2, -S(1)/2), JxKet(S(1)/2, -S(1)/2)), basis=Jy) == \ + Matrix([0, 0, 0, -I]) + assert represent(TensorProduct(JyKet(S(1)/2, S(1)/2), JyKet(S(1)/2, S(1)/2)), basis=Jy) == \ + Matrix([1, 0, 0, 0]) + assert represent(TensorProduct(JyKet(S(1)/2, S(1)/2), JyKet(S(1)/2, -S(1)/2)), basis=Jy) == \ + Matrix([0, 1, 0, 0]) + assert represent(TensorProduct(JyKet(S(1)/2, -S(1)/2), JyKet(S(1)/2, S(1)/2)), basis=Jy) == \ + Matrix([0, 0, 1, 0]) + assert represent(TensorProduct(JyKet(S(1)/2, -S(1)/2), JyKet(S(1)/2, -S(1)/2)), basis=Jy) == \ + Matrix([0, 0, 0, 1]) + assert represent(TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2)), basis=Jy) == \ + Matrix([S(1)/2, -I/2, -I/2, -S(1)/2]) + assert represent(TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, -S(1)/2)), basis=Jy) == \ + Matrix([-I/2, S(1)/2, -S(1)/2, -I/2]) + assert represent(TensorProduct(JzKet(S(1)/2, -S(1)/2), JzKet(S(1)/2, S(1)/2)), basis=Jy) == \ + Matrix([-I/2, -S(1)/2, S(1)/2, -I/2]) + assert represent(TensorProduct(JzKet(S(1)/2, -S(1)/2), JzKet(S(1)/2, -S(1)/2)), basis=Jy) == \ + Matrix([-S(1)/2, -I/2, -I/2, S(1)/2]) # Jz basis - assert represent(TensorProduct(JxKet(S(1)/2,S(1)/2),JxKet(S(1)/2,S(1)/2)), basis=Jz) == \ - Matrix([S(1)/2,S(1)/2,S(1)/2,S(1)/2]) - assert represent(TensorProduct(JxKet(S(1)/2,S(1)/2),JxKet(S(1)/2,-S(1)/2)), basis=Jz) == \ - Matrix([-S(1)/2,S(1)/2,-S(1)/2,S(1)/2]) - assert represent(TensorProduct(JxKet(S(1)/2,-S(1)/2),JxKet(S(1)/2,S(1)/2)), basis=Jz) == \ - Matrix([-S(1)/2,-S(1)/2,S(1)/2,S(1)/2]) - assert represent(TensorProduct(JxKet(S(1)/2,-S(1)/2),JxKet(S(1)/2,-S(1)/2)), basis=Jz) == \ - Matrix([S(1)/2,-S(1)/2,-S(1)/2,S(1)/2]) - assert represent(TensorProduct(JyKet(S(1)/2,S(1)/2),JyKet(S(1)/2,S(1)/2)), basis=Jz) == \ - Matrix([S(1)/2,I/2,I/2,-S(1)/2]) - assert represent(TensorProduct(JyKet(S(1)/2,S(1)/2),JyKet(S(1)/2,-S(1)/2)), basis=Jz) == \ - Matrix([I/2,S(1)/2,-S(1)/2,I/2]) - assert represent(TensorProduct(JyKet(S(1)/2,-S(1)/2),JyKet(S(1)/2,S(1)/2)), basis=Jz) == \ - Matrix([I/2,-S(1)/2,S(1)/2,I/2]) - assert represent(TensorProduct(JyKet(S(1)/2,-S(1)/2),JyKet(S(1)/2,-S(1)/2)), basis=Jz) == \ - Matrix([-S(1)/2,I/2,I/2,S(1)/2]) - assert represent(TensorProduct(JzKet(S(1)/2,S(1)/2),JzKet(S(1)/2,S(1)/2)), basis=Jz) == \ - Matrix([1,0,0,0]) - assert represent(TensorProduct(JzKet(S(1)/2,S(1)/2),JzKet(S(1)/2,-S(1)/2)), basis=Jz) == \ - Matrix([0,1,0,0]) - assert represent(TensorProduct(JzKet(S(1)/2,-S(1)/2),JzKet(S(1)/2,S(1)/2)), basis=Jz) == \ - Matrix([0,0,1,0]) - assert represent(TensorProduct(JzKet(S(1)/2,-S(1)/2),JzKet(S(1)/2,-S(1)/2)), basis=Jz) == \ - Matrix([0,0,0,1]) + assert represent(TensorProduct(JxKet(S(1)/2, S(1)/2), JxKet(S(1)/2, S(1)/2)), basis=Jz) == \ + Matrix([S(1)/2, S(1)/2, S(1)/2, S(1)/2]) + assert represent(TensorProduct(JxKet(S(1)/2, S(1)/2), JxKet(S(1)/2, -S(1)/2)), basis=Jz) == \ + Matrix([-S(1)/2, S(1)/2, -S(1)/2, S(1)/2]) + assert represent(TensorProduct(JxKet(S(1)/2, -S(1)/2), JxKet(S(1)/2, S(1)/2)), basis=Jz) == \ + Matrix([-S(1)/2, -S(1)/2, S(1)/2, S(1)/2]) + assert represent(TensorProduct(JxKet(S(1)/2, -S(1)/2), JxKet(S(1)/2, -S(1)/2)), basis=Jz) == \ + Matrix([S(1)/2, -S(1)/2, -S(1)/2, S(1)/2]) + assert represent(TensorProduct(JyKet(S(1)/2, S(1)/2), JyKet(S(1)/2, S(1)/2)), basis=Jz) == \ + Matrix([S(1)/2, I/2, I/2, -S(1)/2]) + assert represent(TensorProduct(JyKet(S(1)/2, S(1)/2), JyKet(S(1)/2, -S(1)/2)), basis=Jz) == \ + Matrix([I/2, S(1)/2, -S(1)/2, I/2]) + assert represent(TensorProduct(JyKet(S(1)/2, -S(1)/2), JyKet(S(1)/2, S(1)/2)), basis=Jz) == \ + Matrix([I/2, -S(1)/2, S(1)/2, I/2]) + assert represent(TensorProduct(JyKet(S(1)/2, -S(1)/2), JyKet(S(1)/2, -S(1)/2)), basis=Jz) == \ + Matrix([-S(1)/2, I/2, I/2, S(1)/2]) + assert represent(TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2)), basis=Jz) == \ + Matrix([1, 0, 0, 0]) + assert represent(TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, -S(1)/2)), basis=Jz) == \ + Matrix([0, 1, 0, 0]) + assert represent(TensorProduct(JzKet(S(1)/2, -S(1)/2), JzKet(S(1)/2, S(1)/2)), basis=Jz) == \ + Matrix([0, 0, 1, 0]) + assert represent(TensorProduct(JzKet(S(1)/2, -S(1)/2), JzKet(S(1)/2, -S(1)/2)), basis=Jz) == \ + Matrix([0, 0, 0, 1]) + def test_represent_coupled_states(): # Jx basis - assert represent(JxKetCoupled(0, 0, (S(1)/2,S(1)/2)), basis=Jx) == \ - Matrix([1,0,0,0]) - assert represent(JxKetCoupled(1, 1, (S(1)/2,S(1)/2)), basis=Jx) == \ - Matrix([0,1,0,0]) - assert represent(JxKetCoupled(1, 0, (S(1)/2,S(1)/2)), basis=Jx) == \ - Matrix([0,0,1,0]) - assert represent(JxKetCoupled(1, -1, (S(1)/2,S(1)/2)), basis=Jx) == \ - Matrix([0,0,0,1]) - assert represent(JyKetCoupled(0, 0, (S(1)/2,S(1)/2)), basis=Jx) == \ - Matrix([1,0,0,0]) - assert represent(JyKetCoupled(1, 1, (S(1)/2,S(1)/2)), basis=Jx) == \ - Matrix([0,-I,0,0]) - assert represent(JyKetCoupled(1, 0, (S(1)/2,S(1)/2)), basis=Jx) == \ - Matrix([0,0,1,0]) - assert represent(JyKetCoupled(1, -1, (S(1)/2,S(1)/2)), basis=Jx) == \ - Matrix([0,0,0,I]) - assert represent(JzKetCoupled(0, 0, (S(1)/2,S(1)/2)), basis=Jx) == \ - Matrix([1,0,0,0]) - assert represent(JzKetCoupled(1, 1, (S(1)/2,S(1)/2)), basis=Jx) == \ - Matrix([0,S(1)/2,-sqrt(2)/2,S(1)/2]) - assert represent(JzKetCoupled(1, 0, (S(1)/2,S(1)/2)), basis=Jx) == \ - Matrix([0,sqrt(2)/2,0,-sqrt(2)/2]) - assert represent(JzKetCoupled(1, -1, (S(1)/2,S(1)/2)), basis=Jx) == \ - Matrix([0,S(1)/2,sqrt(2)/2,S(1)/2]) + assert represent(JxKetCoupled(0, 0, (S(1)/2, S(1)/2)), basis=Jx) == \ + Matrix([1, 0, 0, 0]) + assert represent(JxKetCoupled(1, 1, (S(1)/2, S(1)/2)), basis=Jx) == \ + Matrix([0, 1, 0, 0]) + assert represent(JxKetCoupled(1, 0, (S(1)/2, S(1)/2)), basis=Jx) == \ + Matrix([0, 0, 1, 0]) + assert represent(JxKetCoupled(1, -1, (S(1)/2, S(1)/2)), basis=Jx) == \ + Matrix([0, 0, 0, 1]) + assert represent(JyKetCoupled(0, 0, (S(1)/2, S(1)/2)), basis=Jx) == \ + Matrix([1, 0, 0, 0]) + assert represent(JyKetCoupled(1, 1, (S(1)/2, S(1)/2)), basis=Jx) == \ + Matrix([0, -I, 0, 0]) + assert represent(JyKetCoupled(1, 0, (S(1)/2, S(1)/2)), basis=Jx) == \ + Matrix([0, 0, 1, 0]) + assert represent(JyKetCoupled(1, -1, (S(1)/2, S(1)/2)), basis=Jx) == \ + Matrix([0, 0, 0, I]) + assert represent(JzKetCoupled(0, 0, (S(1)/2, S(1)/2)), basis=Jx) == \ + Matrix([1, 0, 0, 0]) + assert represent(JzKetCoupled(1, 1, (S(1)/2, S(1)/2)), basis=Jx) == \ + Matrix([0, S(1)/2, -sqrt(2)/2, S(1)/2]) + assert represent(JzKetCoupled(1, 0, (S(1)/2, S(1)/2)), basis=Jx) == \ + Matrix([0, sqrt(2)/2, 0, -sqrt(2)/2]) + assert represent(JzKetCoupled(1, -1, (S(1)/2, S(1)/2)), basis=Jx) == \ + Matrix([0, S(1)/2, sqrt(2)/2, S(1)/2]) # Jy basis - assert represent(JxKetCoupled(0, 0, (S(1)/2,S(1)/2)), basis=Jy) == \ - Matrix([1,0,0,0]) - assert represent(JxKetCoupled(1, 1, (S(1)/2,S(1)/2)), basis=Jy) == \ - Matrix([0,I,0,0]) - assert represent(JxKetCoupled(1, 0, (S(1)/2,S(1)/2)), basis=Jy) == \ - Matrix([0,0,1,0]) - assert represent(JxKetCoupled(1, -1, (S(1)/2,S(1)/2)), basis=Jy) == \ - Matrix([0,0,0,-I]) - assert represent(JyKetCoupled(0, 0, (S(1)/2,S(1)/2)), basis=Jy) == \ - Matrix([1,0,0,0]) - assert represent(JyKetCoupled(1, 1, (S(1)/2,S(1)/2)), basis=Jy) == \ - Matrix([0,1,0,0]) - assert represent(JyKetCoupled(1, 0, (S(1)/2,S(1)/2)), basis=Jy) == \ - Matrix([0,0,1,0]) - assert represent(JyKetCoupled(1, -1, (S(1)/2,S(1)/2)), basis=Jy) == \ - Matrix([0,0,0,1]) - assert represent(JzKetCoupled(0, 0, (S(1)/2,S(1)/2)), basis=Jy) == \ - Matrix([1,0,0,0]) - assert represent(JzKetCoupled(1, 1, (S(1)/2,S(1)/2)), basis=Jy) == \ - Matrix([0,S(1)/2,-I*sqrt(2)/2,-S(1)/2]) - assert represent(JzKetCoupled(1, 0, (S(1)/2,S(1)/2)), basis=Jy) == \ - Matrix([0,-I*sqrt(2)/2,0,-I*sqrt(2)/2]) - assert represent(JzKetCoupled(1, -1, (S(1)/2,S(1)/2)), basis=Jy) == \ - Matrix([0,-S(1)/2,-I*sqrt(2)/2,S(1)/2]) + assert represent(JxKetCoupled(0, 0, (S(1)/2, S(1)/2)), basis=Jy) == \ + Matrix([1, 0, 0, 0]) + assert represent(JxKetCoupled(1, 1, (S(1)/2, S(1)/2)), basis=Jy) == \ + Matrix([0, I, 0, 0]) + assert represent(JxKetCoupled(1, 0, (S(1)/2, S(1)/2)), basis=Jy) == \ + Matrix([0, 0, 1, 0]) + assert represent(JxKetCoupled(1, -1, (S(1)/2, S(1)/2)), basis=Jy) == \ + Matrix([0, 0, 0, -I]) + assert represent(JyKetCoupled(0, 0, (S(1)/2, S(1)/2)), basis=Jy) == \ + Matrix([1, 0, 0, 0]) + assert represent(JyKetCoupled(1, 1, (S(1)/2, S(1)/2)), basis=Jy) == \ + Matrix([0, 1, 0, 0]) + assert represent(JyKetCoupled(1, 0, (S(1)/2, S(1)/2)), basis=Jy) == \ + Matrix([0, 0, 1, 0]) + assert represent(JyKetCoupled(1, -1, (S(1)/2, S(1)/2)), basis=Jy) == \ + Matrix([0, 0, 0, 1]) + assert represent(JzKetCoupled(0, 0, (S(1)/2, S(1)/2)), basis=Jy) == \ + Matrix([1, 0, 0, 0]) + assert represent(JzKetCoupled(1, 1, (S(1)/2, S(1)/2)), basis=Jy) == \ + Matrix([0, S(1)/2, -I*sqrt(2)/2, -S(1)/2]) + assert represent(JzKetCoupled(1, 0, (S(1)/2, S(1)/2)), basis=Jy) == \ + Matrix([0, -I*sqrt(2)/2, 0, -I*sqrt(2)/2]) + assert represent(JzKetCoupled(1, -1, (S(1)/2, S(1)/2)), basis=Jy) == \ + Matrix([0, -S(1)/2, -I*sqrt(2)/2, S(1)/2]) # Jz basis - assert represent(JxKetCoupled(0, 0, (S(1)/2,S(1)/2)), basis=Jz) == \ - Matrix([1,0,0,0]) - assert represent(JxKetCoupled(1, 1, (S(1)/2,S(1)/2)), basis=Jz) == \ - Matrix([0,S(1)/2,sqrt(2)/2,S(1)/2]) - assert represent(JxKetCoupled(1, 0, (S(1)/2,S(1)/2)), basis=Jz) == \ - Matrix([0,-sqrt(2)/2,0,sqrt(2)/2]) - assert represent(JxKetCoupled(1, -1, (S(1)/2,S(1)/2)), basis=Jz) == \ - Matrix([0,S(1)/2,-sqrt(2)/2,S(1)/2]) - assert represent(JyKetCoupled(0, 0, (S(1)/2,S(1)/2)), basis=Jz) == \ - Matrix([1,0,0,0]) - assert represent(JyKetCoupled(1, 1, (S(1)/2,S(1)/2)), basis=Jz) == \ - Matrix([0,S(1)/2,I*sqrt(2)/2,-S(1)/2]) - assert represent(JyKetCoupled(1, 0, (S(1)/2,S(1)/2)), basis=Jz) == \ - Matrix([0,I*sqrt(2)/2,0,I*sqrt(2)/2]) - assert represent(JyKetCoupled(1, -1, (S(1)/2,S(1)/2)), basis=Jz) == \ - Matrix([0,-S(1)/2,I*sqrt(2)/2,S(1)/2]) - assert represent(JzKetCoupled(0, 0, (S(1)/2,S(1)/2)), basis=Jz) == \ - Matrix([1,0,0,0]) - assert represent(JzKetCoupled(1, 1, (S(1)/2,S(1)/2)), basis=Jz) == \ - Matrix([0,1,0,0]) - assert represent(JzKetCoupled(1, 0, (S(1)/2,S(1)/2)), basis=Jz) == \ - Matrix([0,0,1,0]) - assert represent(JzKetCoupled(1, -1, (S(1)/2,S(1)/2)), basis=Jz) == \ - Matrix([0,0,0,1]) + assert represent(JxKetCoupled(0, 0, (S(1)/2, S(1)/2)), basis=Jz) == \ + Matrix([1, 0, 0, 0]) + assert represent(JxKetCoupled(1, 1, (S(1)/2, S(1)/2)), basis=Jz) == \ + Matrix([0, S(1)/2, sqrt(2)/2, S(1)/2]) + assert represent(JxKetCoupled(1, 0, (S(1)/2, S(1)/2)), basis=Jz) == \ + Matrix([0, -sqrt(2)/2, 0, sqrt(2)/2]) + assert represent(JxKetCoupled(1, -1, (S(1)/2, S(1)/2)), basis=Jz) == \ + Matrix([0, S(1)/2, -sqrt(2)/2, S(1)/2]) + assert represent(JyKetCoupled(0, 0, (S(1)/2, S(1)/2)), basis=Jz) == \ + Matrix([1, 0, 0, 0]) + assert represent(JyKetCoupled(1, 1, (S(1)/2, S(1)/2)), basis=Jz) == \ + Matrix([0, S(1)/2, I*sqrt(2)/2, -S(1)/2]) + assert represent(JyKetCoupled(1, 0, (S(1)/2, S(1)/2)), basis=Jz) == \ + Matrix([0, I*sqrt(2)/2, 0, I*sqrt(2)/2]) + assert represent(JyKetCoupled(1, -1, (S(1)/2, S(1)/2)), basis=Jz) == \ + Matrix([0, -S(1)/2, I*sqrt(2)/2, S(1)/2]) + assert represent(JzKetCoupled(0, 0, (S(1)/2, S(1)/2)), basis=Jz) == \ + Matrix([1, 0, 0, 0]) + assert represent(JzKetCoupled(1, 1, (S(1)/2, S(1)/2)), basis=Jz) == \ + Matrix([0, 1, 0, 0]) + assert represent(JzKetCoupled(1, 0, (S(1)/2, S(1)/2)), basis=Jz) == \ + Matrix([0, 0, 1, 0]) + assert represent(JzKetCoupled(1, -1, (S(1)/2, S(1)/2)), basis=Jz) == \ + Matrix([0, 0, 0, 1]) + def test_represent_rotation(): assert represent(Rotation(0, pi/2, 0)) == \ - Matrix([[WignerD(S(1)/2, S(1)/2, S(1)/2, 0, pi/2, 0), WignerD(S(1)/2, S(1)/2, -S(1)/2, 0, pi/2, 0)], \ + Matrix( + [[WignerD( + S( + 1)/2, S( + 1)/2, S( + 1)/2, 0, pi/2, 0), WignerD( + S(1)/2, S(1)/2, -S(1)/2, 0, pi/2, 0)], [WignerD(S(1)/2, -S(1)/2, S(1)/2, 0, pi/2, 0), WignerD(S(1)/2, -S(1)/2, -S(1)/2, 0, pi/2, 0)]]) assert represent(Rotation(0, pi/2, 0), doit=True) == \ - Matrix([[sqrt(2)/2, -sqrt(2)/2], \ + Matrix([[sqrt(2)/2, -sqrt(2)/2], [sqrt(2)/2, sqrt(2)/2]]) + def test_rewrite_same(): # Rewrite to same basis - assert JxBra(1,1).rewrite('Jx') == JxBra(1,1) - assert JxBra(j,m).rewrite('Jx') == JxBra(j,m) - assert JxKet(1,1).rewrite('Jx') == JxKet(1,1) - assert JxKet(j,m).rewrite('Jx') == JxKet(j,m) + assert JxBra(1, 1).rewrite('Jx') == JxBra(1, 1) + assert JxBra(j, m).rewrite('Jx') == JxBra(j, m) + assert JxKet(1, 1).rewrite('Jx') == JxKet(1, 1) + assert JxKet(j, m).rewrite('Jx') == JxKet(j, m) + def test_rewrite_Bra(): # Numerical - assert JxBra(1,1).rewrite('Jy') == -I*JyBra(1,1) - assert JxBra(1,0).rewrite('Jy') == JyBra(1,0) - assert JxBra(1,-1).rewrite('Jy') == I*JyBra(1,-1) - assert JxBra(1,1).rewrite('Jz') == JzBra(1,1)/2+JzBra(1,0)/sqrt(2)+JzBra(1,-1)/2 - assert JxBra(1,0).rewrite('Jz') == -sqrt(2)*JzBra(1,1)/2+sqrt(2)*JzBra(1,-1)/2 - assert JxBra(1,-1).rewrite('Jz') == JzBra(1,1)/2-JzBra(1,0)/sqrt(2)+JzBra(1,-1)/2 - assert JyBra(1,1).rewrite('Jx') == I*JxBra(1,1) - assert JyBra(1,0).rewrite('Jx') == JxBra(1,0) - assert JyBra(1,-1).rewrite('Jx') == -I*JxBra(1,-1) - assert JyBra(1,1).rewrite('Jz') == JzBra(1,1)/2-sqrt(2)*I*JzBra(1,0)/2-JzBra(1,-1)/2 - assert JyBra(1,0).rewrite('Jz') == -sqrt(2)*I*JzBra(1,1)/2-sqrt(2)*I*JzBra(1,-1)/2 - assert JyBra(1,-1).rewrite('Jz') == -JzBra(1,1)/2-sqrt(2)*I*JzBra(1,0)/2+JzBra(1,-1)/2 - assert JzBra(1,1).rewrite('Jx') == JxBra(1,1)/2-sqrt(2)*JxBra(1,0)/2+JxBra(1,-1)/2 - assert JzBra(1,0).rewrite('Jx') == sqrt(2)*JxBra(1,1)/2-sqrt(2)*JxBra(1,-1)/2 - assert JzBra(1,-1).rewrite('Jx') == JxBra(1,1)/2+sqrt(2)*JxBra(1,0)/2+JxBra(1,-1)/2 - assert JzBra(1,1).rewrite('Jy') == JyBra(1,1)/2+sqrt(2)*I*JyBra(1,0)/2-JyBra(1,-1)/2 - assert JzBra(1,0).rewrite('Jy') == sqrt(2)*I*JyBra(1,1)/2+sqrt(2)*I*JyBra(1,-1)/2 - assert JzBra(1,-1).rewrite('Jy') == -JyBra(1,1)/2+sqrt(2)*I*JyBra(1,0)/2+JyBra(1,-1)/2 - # Symbolic - assert JxBra(j,m).rewrite('Jy') == Sum(WignerD(j,mi,m,3*pi/2,0,0) * JyBra(j,mi), (mi, -j, j)) - assert JxBra(j,m).rewrite('Jz') == Sum(WignerD(j,mi,m,0,pi/2,0) * JzBra(j,mi), (mi, -j, j)) - assert JyBra(j,m).rewrite('Jx') == Sum(WignerD(j,mi,m,0,0,pi/2) * JxBra(j,mi), (mi, -j, j)) - assert JyBra(j,m).rewrite('Jz') == Sum(WignerD(j,mi,m,3*pi/2,-pi/2,pi/2) * JzBra(j,mi), (mi, -j, j)) - assert JzBra(j,m).rewrite('Jx') == Sum(WignerD(j,mi,m,0,3*pi/2,0) * JxBra(j,mi), (mi, -j, j)) - assert JzBra(j,m).rewrite('Jy') == Sum(WignerD(j,mi,m,3*pi/2,pi/2,pi/2) * JyBra(j,mi), (mi, -j, j)) + assert JxBra(1, 1).rewrite('Jy') == -I*JyBra(1, 1) + assert JxBra(1, 0).rewrite('Jy') == JyBra(1, 0) + assert JxBra(1, -1).rewrite('Jy') == I*JyBra(1, -1) + assert JxBra(1, 1).rewrite( + 'Jz') == JzBra(1, 1)/2 + JzBra(1, 0)/sqrt(2) + JzBra(1, -1)/2 + assert JxBra( + 1, 0).rewrite('Jz') == -sqrt(2)*JzBra(1, 1)/2 + sqrt(2)*JzBra(1, -1)/2 + assert JxBra(1, -1).rewrite( + 'Jz') == JzBra(1, 1)/2 - JzBra(1, 0)/sqrt(2) + JzBra(1, -1)/2 + assert JyBra(1, 1).rewrite('Jx') == I*JxBra(1, 1) + assert JyBra(1, 0).rewrite('Jx') == JxBra(1, 0) + assert JyBra(1, -1).rewrite('Jx') == -I*JxBra(1, -1) + assert JyBra(1, 1).rewrite( + 'Jz') == JzBra(1, 1)/2 - sqrt(2)*I*JzBra(1, 0)/2 - JzBra(1, -1)/2 + assert JyBra(1, 0).rewrite( + 'Jz') == -sqrt(2)*I*JzBra(1, 1)/2 - sqrt(2)*I*JzBra(1, -1)/2 + assert JyBra(1, -1).rewrite( + 'Jz') == -JzBra(1, 1)/2 - sqrt(2)*I*JzBra(1, 0)/2 + JzBra(1, -1)/2 + assert JzBra(1, 1).rewrite( + 'Jx') == JxBra(1, 1)/2 - sqrt(2)*JxBra(1, 0)/2 + JxBra(1, -1)/2 + assert JzBra( + 1, 0).rewrite('Jx') == sqrt(2)*JxBra(1, 1)/2 - sqrt(2)*JxBra(1, -1)/2 + assert JzBra(1, -1).rewrite( + 'Jx') == JxBra(1, 1)/2 + sqrt(2)*JxBra(1, 0)/2 + JxBra(1, -1)/2 + assert JzBra(1, 1).rewrite( + 'Jy') == JyBra(1, 1)/2 + sqrt(2)*I*JyBra(1, 0)/2 - JyBra(1, -1)/2 + assert JzBra(1, 0).rewrite( + 'Jy') == sqrt(2)*I*JyBra(1, 1)/2 + sqrt(2)*I*JyBra(1, -1)/2 + assert JzBra(1, -1).rewrite( + 'Jy') == -JyBra(1, 1)/2 + sqrt(2)*I*JyBra(1, 0)/2 + JyBra(1, -1)/2 + # Symbolic + assert JxBra(j, m).rewrite('Jy') == Sum( + WignerD(j, mi, m, 3*pi/2, 0, 0) * JyBra(j, mi), (mi, -j, j)) + assert JxBra(j, m).rewrite('Jz') == Sum( + WignerD(j, mi, m, 0, pi/2, 0) * JzBra(j, mi), (mi, -j, j)) + assert JyBra(j, m).rewrite('Jx') == Sum( + WignerD(j, mi, m, 0, 0, pi/2) * JxBra(j, mi), (mi, -j, j)) + assert JyBra(j, m).rewrite('Jz') == Sum( + WignerD(j, mi, m, 3*pi/2, -pi/2, pi/2) * JzBra(j, mi), (mi, -j, j)) + assert JzBra(j, m).rewrite('Jx') == Sum( + WignerD(j, mi, m, 0, 3*pi/2, 0) * JxBra(j, mi), (mi, -j, j)) + assert JzBra(j, m).rewrite('Jy') == Sum( + WignerD(j, mi, m, 3*pi/2, pi/2, pi/2) * JyBra(j, mi), (mi, -j, j)) + def test_rewrite_Ket(): # Numerical - assert JxKet(1,1).rewrite('Jy') == I*JyKet(1,1) - assert JxKet(1,0).rewrite('Jy') == JyKet(1,0) - assert JxKet(1,-1).rewrite('Jy') == -I*JyKet(1,-1) - assert JxKet(1,1).rewrite('Jz') == JzKet(1,1)/2+JzKet(1,0)/sqrt(2)+JzKet(1,-1)/2 - assert JxKet(1,0).rewrite('Jz') == -sqrt(2)*JzKet(1,1)/2+sqrt(2)*JzKet(1,-1)/2 - assert JxKet(1,-1).rewrite('Jz') == JzKet(1,1)/2-JzKet(1,0)/sqrt(2)+JzKet(1,-1)/2 - assert JyKet(1,1).rewrite('Jx') == -I*JxKet(1,1) - assert JyKet(1,0).rewrite('Jx') == JxKet(1,0) - assert JyKet(1,-1).rewrite('Jx') == I*JxKet(1,-1) - assert JyKet(1,1).rewrite('Jz') == JzKet(1,1)/2+sqrt(2)*I*JzKet(1,0)/2-JzKet(1,-1)/2 - assert JyKet(1,0).rewrite('Jz') == sqrt(2)*I*JzKet(1,1)/2+sqrt(2)*I*JzKet(1,-1)/2 - assert JyKet(1,-1).rewrite('Jz') == -JzKet(1,1)/2+sqrt(2)*I*JzKet(1,0)/2+JzKet(1,-1)/2 - assert JzKet(1,1).rewrite('Jx') == JxKet(1,1)/2-sqrt(2)*JxKet(1,0)/2+JxKet(1,-1)/2 - assert JzKet(1,0).rewrite('Jx') == sqrt(2)*JxKet(1,1)/2-sqrt(2)*JxKet(1,-1)/2 - assert JzKet(1,-1).rewrite('Jx') == JxKet(1,1)/2+sqrt(2)*JxKet(1,0)/2+JxKet(1,-1)/2 - assert JzKet(1,1).rewrite('Jy') == JyKet(1,1)/2-sqrt(2)*I*JyKet(1,0)/2-JyKet(1,-1)/2 - assert JzKet(1,0).rewrite('Jy') == -sqrt(2)*I*JyKet(1,1)/2-sqrt(2)*I*JyKet(1,-1)/2 - assert JzKet(1,-1).rewrite('Jy') == -JyKet(1,1)/2-sqrt(2)*I*JyKet(1,0)/2+JyKet(1,-1)/2 - # Symbolic - assert JxKet(j,m).rewrite('Jy') == Sum(WignerD(j,mi,m,3*pi/2,0,0) * JyKet(j,mi), (mi, -j, j)) - assert JxKet(j,m).rewrite('Jz') == Sum(WignerD(j,mi,m,0,pi/2,0) * JzKet(j,mi), (mi, -j, j)) - assert JyKet(j,m).rewrite('Jx') == Sum(WignerD(j,mi,m,0,0,pi/2) * JxKet(j,mi), (mi, -j, j)) - assert JyKet(j,m).rewrite('Jz') == Sum(WignerD(j,mi,m,3*pi/2,-pi/2,pi/2) * JzKet(j,mi), (mi, -j, j)) - assert JzKet(j,m).rewrite('Jx') == Sum(WignerD(j,mi,m,0,3*pi/2,0) * JxKet(j,mi), (mi, -j, j)) - assert JzKet(j,m).rewrite('Jy') == Sum(WignerD(j,mi,m,3*pi/2,pi/2,pi/2) * JyKet(j,mi), (mi, -j, j)) + assert JxKet(1, 1).rewrite('Jy') == I*JyKet(1, 1) + assert JxKet(1, 0).rewrite('Jy') == JyKet(1, 0) + assert JxKet(1, -1).rewrite('Jy') == -I*JyKet(1, -1) + assert JxKet(1, 1).rewrite( + 'Jz') == JzKet(1, 1)/2 + JzKet(1, 0)/sqrt(2) + JzKet(1, -1)/2 + assert JxKet( + 1, 0).rewrite('Jz') == -sqrt(2)*JzKet(1, 1)/2 + sqrt(2)*JzKet(1, -1)/2 + assert JxKet(1, -1).rewrite( + 'Jz') == JzKet(1, 1)/2 - JzKet(1, 0)/sqrt(2) + JzKet(1, -1)/2 + assert JyKet(1, 1).rewrite('Jx') == -I*JxKet(1, 1) + assert JyKet(1, 0).rewrite('Jx') == JxKet(1, 0) + assert JyKet(1, -1).rewrite('Jx') == I*JxKet(1, -1) + assert JyKet(1, 1).rewrite( + 'Jz') == JzKet(1, 1)/2 + sqrt(2)*I*JzKet(1, 0)/2 - JzKet(1, -1)/2 + assert JyKet(1, 0).rewrite( + 'Jz') == sqrt(2)*I*JzKet(1, 1)/2 + sqrt(2)*I*JzKet(1, -1)/2 + assert JyKet(1, -1).rewrite( + 'Jz') == -JzKet(1, 1)/2 + sqrt(2)*I*JzKet(1, 0)/2 + JzKet(1, -1)/2 + assert JzKet(1, 1).rewrite( + 'Jx') == JxKet(1, 1)/2 - sqrt(2)*JxKet(1, 0)/2 + JxKet(1, -1)/2 + assert JzKet( + 1, 0).rewrite('Jx') == sqrt(2)*JxKet(1, 1)/2 - sqrt(2)*JxKet(1, -1)/2 + assert JzKet(1, -1).rewrite( + 'Jx') == JxKet(1, 1)/2 + sqrt(2)*JxKet(1, 0)/2 + JxKet(1, -1)/2 + assert JzKet(1, 1).rewrite( + 'Jy') == JyKet(1, 1)/2 - sqrt(2)*I*JyKet(1, 0)/2 - JyKet(1, -1)/2 + assert JzKet(1, 0).rewrite( + 'Jy') == -sqrt(2)*I*JyKet(1, 1)/2 - sqrt(2)*I*JyKet(1, -1)/2 + assert JzKet(1, -1).rewrite( + 'Jy') == -JyKet(1, 1)/2 - sqrt(2)*I*JyKet(1, 0)/2 + JyKet(1, -1)/2 + # Symbolic + assert JxKet(j, m).rewrite('Jy') == Sum( + WignerD(j, mi, m, 3*pi/2, 0, 0) * JyKet(j, mi), (mi, -j, j)) + assert JxKet(j, m).rewrite('Jz') == Sum( + WignerD(j, mi, m, 0, pi/2, 0) * JzKet(j, mi), (mi, -j, j)) + assert JyKet(j, m).rewrite('Jx') == Sum( + WignerD(j, mi, m, 0, 0, pi/2) * JxKet(j, mi), (mi, -j, j)) + assert JyKet(j, m).rewrite('Jz') == Sum( + WignerD(j, mi, m, 3*pi/2, -pi/2, pi/2) * JzKet(j, mi), (mi, -j, j)) + assert JzKet(j, m).rewrite('Jx') == Sum( + WignerD(j, mi, m, 0, 3*pi/2, 0) * JxKet(j, mi), (mi, -j, j)) + assert JzKet(j, m).rewrite('Jy') == Sum( + WignerD(j, mi, m, 3*pi/2, pi/2, pi/2) * JyKet(j, mi), (mi, -j, j)) + def test_rewrite_uncoupled_state(): # Numerical - assert TensorProduct(JyKet(1,1),JxKet(1,1)).rewrite('Jx') == -I*TensorProduct(JxKet(1,1),JxKet(1,1)) - assert TensorProduct(JyKet(1,0),JxKet(1,1)).rewrite('Jx') == TensorProduct(JxKet(1,0),JxKet(1,1)) - assert TensorProduct(JyKet(1,-1),JxKet(1,1)).rewrite('Jx') == I*TensorProduct(JxKet(1,-1),JxKet(1,1)) - assert TensorProduct(JzKet(1,1),JxKet(1,1)).rewrite('Jx') == \ - TensorProduct(JxKet(1,-1),JxKet(1,1))/2-sqrt(2)*TensorProduct(JxKet(1,0),JxKet(1,1))/2+TensorProduct(JxKet(1,1),JxKet(1,1))/2 - assert TensorProduct(JzKet(1,0),JxKet(1,1)).rewrite('Jx') == \ - -sqrt(2)*TensorProduct(JxKet(1,-1),JxKet(1,1))/2+sqrt(2)*TensorProduct(JxKet(1,1),JxKet(1,1))/2 - assert TensorProduct(JzKet(1,-1),JxKet(1,1)).rewrite('Jx') == \ - TensorProduct(JxKet(1,-1),JxKet(1,1))/2 + sqrt(2)*TensorProduct(JxKet(1,0),JxKet(1,1))/2 + TensorProduct(JxKet(1,1),JxKet(1,1))/2 - assert TensorProduct(JxKet(1,1),JyKet(1,1)).rewrite('Jy') == I*TensorProduct(JyKet(1,1),JyKet(1,1)) - assert TensorProduct(JxKet(1,0),JyKet(1,1)).rewrite('Jy') == TensorProduct(JyKet(1,0),JyKet(1,1)) - assert TensorProduct(JxKet(1,-1),JyKet(1,1)).rewrite('Jy') == -I*TensorProduct(JyKet(1,-1),JyKet(1,1)) - assert TensorProduct(JzKet(1,1),JyKet(1,1)).rewrite('Jy') == \ - -TensorProduct(JyKet(1,-1),JyKet(1,1))/2 - sqrt(2)*I*TensorProduct(JyKet(1,0),JyKet(1,1))/2 + TensorProduct(JyKet(1,1),JyKet(1,1))/2 - assert TensorProduct(JzKet(1,0),JyKet(1,1)).rewrite('Jy') == \ - -sqrt(2)*I*TensorProduct(JyKet(1,-1),JyKet(1,1))/2 - sqrt(2)*I*TensorProduct(JyKet(1,1),JyKet(1,1))/2 - assert TensorProduct(JzKet(1,-1),JyKet(1,1)).rewrite('Jy') == \ - TensorProduct(JyKet(1,-1),JyKet(1,1))/2 - sqrt(2)*I*TensorProduct(JyKet(1,0),JyKet(1,1))/2 - TensorProduct(JyKet(1,1),JyKet(1,1))/2 - assert TensorProduct(JxKet(1,1),JzKet(1,1)).rewrite('Jz') == \ - TensorProduct(JzKet(1,-1),JzKet(1,1))/2 + sqrt(2)*TensorProduct(JzKet(1,0),JzKet(1,1))/2 + TensorProduct(JzKet(1,1),JzKet(1,1))/2 - assert TensorProduct(JxKet(1,0),JzKet(1,1)).rewrite('Jz') == \ - sqrt(2)*TensorProduct(JzKet(1,-1),JzKet(1,1))/2 - sqrt(2)*TensorProduct(JzKet(1,1),JzKet(1,1))/2 - assert TensorProduct(JxKet(1,-1),JzKet(1,1)).rewrite('Jz') == \ - TensorProduct(JzKet(1,-1),JzKet(1,1))/2 - sqrt(2)*TensorProduct(JzKet(1,0),JzKet(1,1))/2 + TensorProduct(JzKet(1,1),JzKet(1,1))/2 - assert TensorProduct(JyKet(1,1),JzKet(1,1)).rewrite('Jz') == \ - -TensorProduct(JzKet(1,-1),JzKet(1,1))/2 + sqrt(2)*I*TensorProduct(JzKet(1,0),JzKet(1,1))/2 + TensorProduct(JzKet(1,1),JzKet(1,1))/2 - assert TensorProduct(JyKet(1,0),JzKet(1,1)).rewrite('Jz') == \ - sqrt(2)*I*TensorProduct(JzKet(1,-1),JzKet(1,1))/2 + sqrt(2)*I*TensorProduct(JzKet(1,1),JzKet(1,1))/2 - assert TensorProduct(JyKet(1,-1),JzKet(1,1)).rewrite('Jz') == \ - TensorProduct(JzKet(1,-1),JzKet(1,1))/2 + sqrt(2)*I*TensorProduct(JzKet(1,0),JzKet(1,1))/2 - TensorProduct(JzKet(1,1),JzKet(1,1))/2 - # Symbolic - assert TensorProduct(JyKet(j1,m1), JxKet(j2,m2)).rewrite('Jy') == \ - TensorProduct(JyKet(j1,m1), Sum(WignerD(j2,mi,m2,3*pi/2,0,0) * JyKet(j2,mi), (mi, -j2, j2))) - assert TensorProduct(JzKet(j1,m1), JxKet(j2,m2)).rewrite('Jz') == \ - TensorProduct(JzKet(j1,m1), Sum(WignerD(j2,mi,m2,0,pi/2,0) * JzKet(j2,mi), (mi, -j2, j2))) - assert TensorProduct(JxKet(j1,m1), JyKet(j2,m2)).rewrite('Jx') == \ - TensorProduct(JxKet(j1,m1), Sum(WignerD(j2,mi,m2,0,0,pi/2) * JxKet(j2,mi), (mi, -j2, j2))) - assert TensorProduct(JzKet(j1,m1), JyKet(j2,m2)).rewrite('Jz') == \ - TensorProduct(JzKet(j1,m1), Sum(WignerD(j2,mi,m2,3*pi/2,-pi/2,pi/2) * JzKet(j2,mi), (mi, -j2, j2))) - assert TensorProduct(JxKet(j1,m1), JzKet(j2,m2)).rewrite('Jx') == \ - TensorProduct(JxKet(j1,m1), Sum(WignerD(j2,mi,m2,0,3*pi/2,0) * JxKet(j2,mi), (mi, -j2, j2))) - assert TensorProduct(JyKet(j1,m1), JzKet(j2,m2)).rewrite('Jy') == \ - TensorProduct(JyKet(j1,m1), Sum(WignerD(j2,mi,m2,3*pi/2,pi/2,pi/2) * JyKet(j2,mi), (mi, -j2, j2))) + assert TensorProduct(JyKet(1, 1), JxKet( + 1, 1)).rewrite('Jx') == -I*TensorProduct(JxKet(1, 1), JxKet(1, 1)) + assert TensorProduct(JyKet(1, 0), JxKet( + 1, 1)).rewrite('Jx') == TensorProduct(JxKet(1, 0), JxKet(1, 1)) + assert TensorProduct(JyKet(1, -1), JxKet( + 1, 1)).rewrite('Jx') == I*TensorProduct(JxKet(1, -1), JxKet(1, 1)) + assert TensorProduct(JzKet(1, 1), JxKet(1, 1)).rewrite('Jx') == \ + TensorProduct(JxKet(1, -1), JxKet(1, 1))/2 - sqrt(2)*TensorProduct(JxKet( + 1, 0), JxKet(1, 1))/2 + TensorProduct(JxKet(1, 1), JxKet(1, 1))/2 + assert TensorProduct(JzKet(1, 0), JxKet(1, 1)).rewrite('Jx') == \ + -sqrt(2)*TensorProduct(JxKet(1, -1), JxKet(1, 1))/2 + sqrt( + 2)*TensorProduct(JxKet(1, 1), JxKet(1, 1))/2 + assert TensorProduct(JzKet(1, -1), JxKet(1, 1)).rewrite('Jx') == \ + TensorProduct(JxKet(1, -1), JxKet(1, 1))/2 + sqrt(2)*TensorProduct(JxKet(1, 0), JxKet(1, 1))/2 + TensorProduct(JxKet(1, 1), JxKet(1, 1))/2 + assert TensorProduct(JxKet(1, 1), JyKet( + 1, 1)).rewrite('Jy') == I*TensorProduct(JyKet(1, 1), JyKet(1, 1)) + assert TensorProduct(JxKet(1, 0), JyKet( + 1, 1)).rewrite('Jy') == TensorProduct(JyKet(1, 0), JyKet(1, 1)) + assert TensorProduct(JxKet(1, -1), JyKet( + 1, 1)).rewrite('Jy') == -I*TensorProduct(JyKet(1, -1), JyKet(1, 1)) + assert TensorProduct(JzKet(1, 1), JyKet(1, 1)).rewrite('Jy') == \ + -TensorProduct(JyKet(1, -1), JyKet(1, 1))/2 - sqrt(2)*I*TensorProduct(JyKet(1, 0), JyKet(1, 1))/2 + TensorProduct(JyKet(1, 1), JyKet(1, 1))/2 + assert TensorProduct(JzKet(1, 0), JyKet(1, 1)).rewrite('Jy') == \ + -sqrt(2)*I*TensorProduct(JyKet(1, -1), JyKet( + 1, 1))/2 - sqrt(2)*I*TensorProduct(JyKet(1, 1), JyKet(1, 1))/2 + assert TensorProduct(JzKet(1, -1), JyKet(1, 1)).rewrite('Jy') == \ + TensorProduct(JyKet(1, -1), JyKet(1, 1))/2 - sqrt(2)*I*TensorProduct(JyKet(1, 0), JyKet(1, 1))/2 - TensorProduct(JyKet(1, 1), JyKet(1, 1))/2 + assert TensorProduct(JxKet(1, 1), JzKet(1, 1)).rewrite('Jz') == \ + TensorProduct(JzKet(1, -1), JzKet(1, 1))/2 + sqrt(2)*TensorProduct(JzKet(1, 0), JzKet(1, 1))/2 + TensorProduct(JzKet(1, 1), JzKet(1, 1))/2 + assert TensorProduct(JxKet(1, 0), JzKet(1, 1)).rewrite('Jz') == \ + sqrt(2)*TensorProduct(JzKet(1, -1), JzKet( + 1, 1))/2 - sqrt(2)*TensorProduct(JzKet(1, 1), JzKet(1, 1))/2 + assert TensorProduct(JxKet(1, -1), JzKet(1, 1)).rewrite('Jz') == \ + TensorProduct(JzKet(1, -1), JzKet(1, 1))/2 - sqrt(2)*TensorProduct(JzKet(1, 0), JzKet(1, 1))/2 + TensorProduct(JzKet(1, 1), JzKet(1, 1))/2 + assert TensorProduct(JyKet(1, 1), JzKet(1, 1)).rewrite('Jz') == \ + -TensorProduct(JzKet(1, -1), JzKet(1, 1))/2 + sqrt(2)*I*TensorProduct(JzKet(1, 0), JzKet(1, 1))/2 + TensorProduct(JzKet(1, 1), JzKet(1, 1))/2 + assert TensorProduct(JyKet(1, 0), JzKet(1, 1)).rewrite('Jz') == \ + sqrt(2)*I*TensorProduct(JzKet(1, -1), JzKet( + 1, 1))/2 + sqrt(2)*I*TensorProduct(JzKet(1, 1), JzKet(1, 1))/2 + assert TensorProduct(JyKet(1, -1), JzKet(1, 1)).rewrite('Jz') == \ + TensorProduct(JzKet(1, -1), JzKet(1, 1))/2 + sqrt(2)*I*TensorProduct(JzKet(1, 0), JzKet(1, 1))/2 - TensorProduct(JzKet(1, 1), JzKet(1, 1))/2 + # Symbolic + assert TensorProduct(JyKet(j1, m1), JxKet(j2, m2)).rewrite('Jy') == \ + TensorProduct(JyKet(j1, m1), Sum( + WignerD(j2, mi, m2, 3*pi/2, 0, 0) * JyKet(j2, mi), (mi, -j2, j2))) + assert TensorProduct(JzKet(j1, m1), JxKet(j2, m2)).rewrite('Jz') == \ + TensorProduct(JzKet(j1, m1), Sum( + WignerD(j2, mi, m2, 0, pi/2, 0) * JzKet(j2, mi), (mi, -j2, j2))) + assert TensorProduct(JxKet(j1, m1), JyKet(j2, m2)).rewrite('Jx') == \ + TensorProduct(JxKet(j1, m1), Sum( + WignerD(j2, mi, m2, 0, 0, pi/2) * JxKet(j2, mi), (mi, -j2, j2))) + assert TensorProduct(JzKet(j1, m1), JyKet(j2, m2)).rewrite('Jz') == \ + TensorProduct(JzKet(j1, m1), Sum(WignerD( + j2, mi, m2, 3*pi/2, -pi/2, pi/2) * JzKet(j2, mi), (mi, -j2, j2))) + assert TensorProduct(JxKet(j1, m1), JzKet(j2, m2)).rewrite('Jx') == \ + TensorProduct(JxKet(j1, m1), Sum( + WignerD(j2, mi, m2, 0, 3*pi/2, 0) * JxKet(j2, mi), (mi, -j2, j2))) + assert TensorProduct(JyKet(j1, m1), JzKet(j2, m2)).rewrite('Jy') == \ + TensorProduct(JyKet(j1, m1), Sum(WignerD( + j2, mi, m2, 3*pi/2, pi/2, pi/2) * JyKet(j2, mi), (mi, -j2, j2))) + def test_rewrite_coupled_state(): # Numerical - assert JyKetCoupled(0, 0, (S(1)/2,S(1)/2)).rewrite('Jx') == \ - JxKetCoupled(0, 0, (S(1)/2,S(1)/2)) - assert JyKetCoupled(1, 1, (S(1)/2,S(1)/2)).rewrite('Jx') == \ - -I*JxKetCoupled(1, 1, (S(1)/2,S(1)/2)) - assert JyKetCoupled(1, 0, (S(1)/2,S(1)/2)).rewrite('Jx') == \ - JxKetCoupled(1, 0, (S(1)/2,S(1)/2)) - assert JyKetCoupled(1, -1, (S(1)/2,S(1)/2)).rewrite('Jx') == \ - I*JxKetCoupled(1, -1, (S(1)/2,S(1)/2)) - assert JzKetCoupled(0, 0, (S(1)/2,S(1)/2)).rewrite('Jx') == \ - JxKetCoupled(0, 0, (S(1)/2,S(1)/2)) - assert JzKetCoupled(1, 1, (S(1)/2,S(1)/2)).rewrite('Jx') == \ - JxKetCoupled(1, 1, (S(1)/2,S(1)/2))/2 - sqrt(2)*JxKetCoupled(1, 0, (S(1)/2,S(1)/2))/2 + JxKetCoupled(1, -1, (S(1)/2,S(1)/2))/2 - assert JzKetCoupled(1, 0, (S(1)/2,S(1)/2)).rewrite('Jx') == \ - sqrt(2)*JxKetCoupled(1, 1, (S(1)/2,S(1)/2))/2 - sqrt(2)*JxKetCoupled(1, -1, (S(1)/2,S(1)/2))/2 - assert JzKetCoupled(1, -1, (S(1)/2,S(1)/2)).rewrite('Jx') == \ - JxKetCoupled(1, 1, (S(1)/2,S(1)/2))/2 + sqrt(2)*JxKetCoupled(1, 0, (S(1)/2,S(1)/2))/2 + JxKetCoupled(1, -1, (S(1)/2,S(1)/2))/2 - assert JxKetCoupled(0, 0, (S(1)/2,S(1)/2)).rewrite('Jy') == \ + assert JyKetCoupled(0, 0, (S(1)/2, S(1)/2)).rewrite('Jx') == \ + JxKetCoupled(0, 0, (S(1)/2, S(1)/2)) + assert JyKetCoupled(1, 1, (S(1)/2, S(1)/2)).rewrite('Jx') == \ + -I*JxKetCoupled(1, 1, (S(1)/2, S(1)/2)) + assert JyKetCoupled(1, 0, (S(1)/2, S(1)/2)).rewrite('Jx') == \ + JxKetCoupled(1, 0, (S(1)/2, S(1)/2)) + assert JyKetCoupled(1, -1, (S(1)/2, S(1)/2)).rewrite('Jx') == \ + I*JxKetCoupled(1, -1, (S(1)/2, S(1)/2)) + assert JzKetCoupled(0, 0, (S(1)/2, S(1)/2)).rewrite('Jx') == \ + JxKetCoupled(0, 0, (S(1)/2, S(1)/2)) + assert JzKetCoupled(1, 1, (S(1)/2, S(1)/2)).rewrite('Jx') == \ + JxKetCoupled(1, 1, (S(1)/2, S(1)/2))/2 - sqrt(2)*JxKetCoupled(1, 0, ( + S(1)/2, S(1)/2))/2 + JxKetCoupled(1, -1, (S(1)/2, S(1)/2))/2 + assert JzKetCoupled(1, 0, (S(1)/2, S(1)/2)).rewrite('Jx') == \ + sqrt(2)*JxKetCoupled(1, 1, (S( + 1)/2, S(1)/2))/2 - sqrt(2)*JxKetCoupled(1, -1, (S(1)/2, S(1)/2))/2 + assert JzKetCoupled(1, -1, (S(1)/2, S(1)/2)).rewrite('Jx') == \ + JxKetCoupled(1, 1, (S(1)/2, S(1)/2))/2 + sqrt(2)*JxKetCoupled(1, 0, ( + S(1)/2, S(1)/2))/2 + JxKetCoupled(1, -1, (S(1)/2, S(1)/2))/2 + assert JxKetCoupled(0, 0, (S(1)/2, S(1)/2)).rewrite('Jy') == \ + JyKetCoupled(0, 0, (S(1)/2, S(1)/2)) + assert JxKetCoupled(1, 1, (S(1)/2, S(1)/2)).rewrite('Jy') == \ + I*JyKetCoupled(1, 1, (S(1)/2, S(1)/2)) + assert JxKetCoupled(1, 0, (S(1)/2, S(1)/2)).rewrite('Jy') == \ + JyKetCoupled(1, 0, (S(1)/2, S(1)/2)) + assert JxKetCoupled(1, -1, (S(1)/2, S(1)/2)).rewrite('Jy') == \ + -I*JyKetCoupled(1, -1, (S(1)/2, S(1)/2)) + assert JzKetCoupled(0, 0, (S(1)/2, S(1)/2)).rewrite('Jy') == \ JyKetCoupled(0, 0, (S(1)/2, S(1)/2)) - assert JxKetCoupled(1, 1, (S(1)/2,S(1)/2)).rewrite('Jy') == \ - I*JyKetCoupled(1, 1, (S(1)/2,S(1)/2)) - assert JxKetCoupled(1, 0, (S(1)/2,S(1)/2)).rewrite('Jy') == \ - JyKetCoupled(1, 0, (S(1)/2,S(1)/2)) - assert JxKetCoupled(1, -1, (S(1)/2,S(1)/2)).rewrite('Jy') == \ - -I*JyKetCoupled(1, -1, (S(1)/2,S(1)/2)) - assert JzKetCoupled(0, 0, (S(1)/2,S(1)/2)).rewrite('Jy') == \ - JyKetCoupled(0, 0, (S(1)/2,S(1)/2)) - assert JzKetCoupled(1, 1, (S(1)/2,S(1)/2)).rewrite('Jy') == \ - JyKetCoupled(1, 1, (S(1)/2,S(1)/2))/2 - I*sqrt(2)*JyKetCoupled(1, 0, (S(1)/2,S(1)/2))/2 - JyKetCoupled(1, -1, (S(1)/2,S(1)/2))/2 - assert JzKetCoupled(1, 0, (S(1)/2,S(1)/2)).rewrite('Jy') == \ - -I*sqrt(2)*JyKetCoupled(1, 1, (S(1)/2,S(1)/2))/2 - I*sqrt(2)*JyKetCoupled(1, -1, (S(1)/2,S(1)/2))/2 - assert JzKetCoupled(1, -1, (S(1)/2,S(1)/2)).rewrite('Jy') == \ - -JyKetCoupled(1, 1, (S(1)/2,S(1)/2))/2 - I*sqrt(2)*JyKetCoupled(1, 0, (S(1)/2,S(1)/2))/2 + JyKetCoupled(1, -1, (S(1)/2,S(1)/2))/2 - assert JxKetCoupled(0, 0, (S(1)/2,S(1)/2)).rewrite('Jz') == \ - JzKetCoupled(0, 0, (S(1)/2,S(1)/2)) - assert JxKetCoupled(1, 1, (S(1)/2,S(1)/2)).rewrite('Jz') == \ - JzKetCoupled(1, 1, (S(1)/2,S(1)/2))/2 + sqrt(2)*JzKetCoupled(1, 0, (S(1)/2,S(1)/2))/2 + JzKetCoupled(1, -1, (S(1)/2,S(1)/2))/2 - assert JxKetCoupled(1, 0, (S(1)/2,S(1)/2)).rewrite('Jz') == \ - -sqrt(2)*JzKetCoupled(1, 1, (S(1)/2,S(1)/2))/2 + sqrt(2)*JzKetCoupled(1, -1, (S(1)/2,S(1)/2))/2 - assert JxKetCoupled(1, -1, (S(1)/2,S(1)/2)).rewrite('Jz') == \ - JzKetCoupled(1, 1, (S(1)/2,S(1)/2))/2 - sqrt(2)*JzKetCoupled(1, 0, (S(1)/2,S(1)/2))/2 + JzKetCoupled(1, -1, (S(1)/2,S(1)/2))/2 - assert JyKetCoupled(0, 0, (S(1)/2,S(1)/2)).rewrite('Jz') == \ - JzKetCoupled(0, 0, (S(1)/2,S(1)/2)) - assert JyKetCoupled(1, 1, (S(1)/2,S(1)/2)).rewrite('Jz') == \ - JzKetCoupled(1, 1, (S(1)/2,S(1)/2))/2 + I*sqrt(2)*JzKetCoupled(1, 0, (S(1)/2,S(1)/2))/2 - JzKetCoupled(1, -1, (S(1)/2,S(1)/2))/2 - assert JyKetCoupled(1, 0, (S(1)/2,S(1)/2)).rewrite('Jz') == \ - I*sqrt(2)*JzKetCoupled(1, 1, (S(1)/2,S(1)/2))/2 + I*sqrt(2)*JzKetCoupled(1, -1, (S(1)/2,S(1)/2))/2 - assert JyKetCoupled(1, -1, (S(1)/2,S(1)/2)).rewrite('Jz') == \ - -JzKetCoupled(1, 1, (S(1)/2,S(1)/2))/2 + I*sqrt(2)*JzKetCoupled(1, 0, (S(1)/2,S(1)/2))/2 + JzKetCoupled(1, -1, (S(1)/2,S(1)/2))/2 - # Symbolic - assert JyKetCoupled(j, m, (j1,j2)).rewrite('Jx') == \ - Sum(WignerD(j,mi,m,0,0,pi/2) * JxKetCoupled(j, mi, (j1,j2)), (mi,-j,j)) - assert JzKetCoupled(j, m, (j1,j2)).rewrite('Jx') == \ - Sum(WignerD(j,mi,m,0,3*pi/2,0) * JxKetCoupled(j, mi, (j1,j2)), (mi,-j,j)) - assert JxKetCoupled(j, m, (j1,j2)).rewrite('Jy') == \ - Sum(WignerD(j,mi,m,3*pi/2,0,0) * JyKetCoupled(j, mi, (j1,j2)), (mi,-j,j)) - assert JzKetCoupled(j, m, (j1,j2)).rewrite('Jy') == \ - Sum(WignerD(j,mi,m,3*pi/2,pi/2,pi/2) * JyKetCoupled(j, mi, (j1,j2)), (mi,-j,j)) - assert JxKetCoupled(j, m, (j1,j2)).rewrite('Jz') == \ - Sum(WignerD(j,mi,m,0,pi/2,0) * JzKetCoupled(j, mi, (j1,j2)), (mi,-j,j)) - assert JyKetCoupled(j, m, (j1,j2)).rewrite('Jz') == \ - Sum(WignerD(j,mi,m,3*pi/2,-pi/2,pi/2) * JzKetCoupled(j, mi, (j1,j2)), (mi,-j,j)) + assert JzKetCoupled(1, 1, (S(1)/2, S(1)/2)).rewrite('Jy') == \ + JyKetCoupled(1, 1, (S(1)/2, S(1)/2))/2 - I*sqrt(2)*JyKetCoupled(1, 0, ( + S(1)/2, S(1)/2))/2 - JyKetCoupled(1, -1, (S(1)/2, S(1)/2))/2 + assert JzKetCoupled(1, 0, (S(1)/2, S(1)/2)).rewrite('Jy') == \ + -I*sqrt(2)*JyKetCoupled(1, 1, (S(1)/2, S(1)/2))/2 - I*sqrt( + 2)*JyKetCoupled(1, -1, (S(1)/2, S(1)/2))/2 + assert JzKetCoupled(1, -1, (S(1)/2, S(1)/2)).rewrite('Jy') == \ + -JyKetCoupled(1, 1, (S(1)/2, S(1)/2))/2 - I*sqrt(2)*JyKetCoupled(1, 0, (S(1)/2, S(1)/2))/2 + JyKetCoupled(1, -1, (S(1)/2, S(1)/2))/2 + assert JxKetCoupled(0, 0, (S(1)/2, S(1)/2)).rewrite('Jz') == \ + JzKetCoupled(0, 0, (S(1)/2, S(1)/2)) + assert JxKetCoupled(1, 1, (S(1)/2, S(1)/2)).rewrite('Jz') == \ + JzKetCoupled(1, 1, (S(1)/2, S(1)/2))/2 + sqrt(2)*JzKetCoupled(1, 0, ( + S(1)/2, S(1)/2))/2 + JzKetCoupled(1, -1, (S(1)/2, S(1)/2))/2 + assert JxKetCoupled(1, 0, (S(1)/2, S(1)/2)).rewrite('Jz') == \ + -sqrt(2)*JzKetCoupled(1, 1, (S( + 1)/2, S(1)/2))/2 + sqrt(2)*JzKetCoupled(1, -1, (S(1)/2, S(1)/2))/2 + assert JxKetCoupled(1, -1, (S(1)/2, S(1)/2)).rewrite('Jz') == \ + JzKetCoupled(1, 1, (S(1)/2, S(1)/2))/2 - sqrt(2)*JzKetCoupled(1, 0, ( + S(1)/2, S(1)/2))/2 + JzKetCoupled(1, -1, (S(1)/2, S(1)/2))/2 + assert JyKetCoupled(0, 0, (S(1)/2, S(1)/2)).rewrite('Jz') == \ + JzKetCoupled(0, 0, (S(1)/2, S(1)/2)) + assert JyKetCoupled(1, 1, (S(1)/2, S(1)/2)).rewrite('Jz') == \ + JzKetCoupled(1, 1, (S(1)/2, S(1)/2))/2 + I*sqrt(2)*JzKetCoupled(1, 0, ( + S(1)/2, S(1)/2))/2 - JzKetCoupled(1, -1, (S(1)/2, S(1)/2))/2 + assert JyKetCoupled(1, 0, (S(1)/2, S(1)/2)).rewrite('Jz') == \ + I*sqrt(2)*JzKetCoupled(1, 1, (S(1)/2, S(1)/2))/2 + I*sqrt( + 2)*JzKetCoupled(1, -1, (S(1)/2, S(1)/2))/2 + assert JyKetCoupled(1, -1, (S(1)/2, S(1)/2)).rewrite('Jz') == \ + -JzKetCoupled(1, 1, (S(1)/2, S(1)/2))/2 + I*sqrt(2)*JzKetCoupled(1, 0, (S(1)/2, S(1)/2))/2 + JzKetCoupled(1, -1, (S(1)/2, S(1)/2))/2 + # Symbolic + assert JyKetCoupled(j, m, (j1, j2)).rewrite('Jx') == \ + Sum(WignerD(j, mi, m, 0, 0, pi/2) * JxKetCoupled(j, mi, ( + j1, j2)), (mi, -j, j)) + assert JzKetCoupled(j, m, (j1, j2)).rewrite('Jx') == \ + Sum(WignerD(j, mi, m, 0, 3*pi/2, 0) * JxKetCoupled(j, mi, ( + j1, j2)), (mi, -j, j)) + assert JxKetCoupled(j, m, (j1, j2)).rewrite('Jy') == \ + Sum(WignerD(j, mi, m, 3*pi/2, 0, 0) * JyKetCoupled(j, mi, ( + j1, j2)), (mi, -j, j)) + assert JzKetCoupled(j, m, (j1, j2)).rewrite('Jy') == \ + Sum(WignerD(j, mi, m, 3*pi/2, pi/2, pi/2) * JyKetCoupled(j, + mi, (j1, j2)), (mi, -j, j)) + assert JxKetCoupled(j, m, (j1, j2)).rewrite('Jz') == \ + Sum(WignerD(j, mi, m, 0, pi/2, 0) * JzKetCoupled(j, mi, ( + j1, j2)), (mi, -j, j)) + assert JyKetCoupled(j, m, (j1, j2)).rewrite('Jz') == \ + Sum(WignerD(j, mi, m, 3*pi/2, -pi/2, pi/2) * JzKetCoupled( + j, mi, (j1, j2)), (mi, -j, j)) + def test_innerproducts_of_rewritten_states(): # Numerical - assert qapply(JxBra(1,1)*JxKet(1,1).rewrite('Jy')).doit() == 1 - assert qapply(JxBra(1,0)*JxKet(1,0).rewrite('Jy')).doit() == 1 - assert qapply(JxBra(1,-1)*JxKet(1,-1).rewrite('Jy')).doit() == 1 - assert qapply(JxBra(1,1)*JxKet(1,1).rewrite('Jz')).doit() == 1 - assert qapply(JxBra(1,0)*JxKet(1,0).rewrite('Jz')).doit() == 1 - assert qapply(JxBra(1,-1)*JxKet(1,-1).rewrite('Jz')).doit() == 1 - assert qapply(JyBra(1,1)*JyKet(1,1).rewrite('Jx')).doit() == 1 - assert qapply(JyBra(1,0)*JyKet(1,0).rewrite('Jx')).doit() == 1 - assert qapply(JyBra(1,-1)*JyKet(1,-1).rewrite('Jx')).doit() == 1 - assert qapply(JyBra(1,1)*JyKet(1,1).rewrite('Jz')).doit() == 1 - assert qapply(JyBra(1,0)*JyKet(1,0).rewrite('Jz')).doit() == 1 - assert qapply(JyBra(1,-1)*JyKet(1,-1).rewrite('Jz')).doit() == 1 - assert qapply(JyBra(1,1)*JyKet(1,1).rewrite('Jz')).doit() == 1 - assert qapply(JyBra(1,0)*JyKet(1,0).rewrite('Jz')).doit() == 1 - assert qapply(JyBra(1,-1)*JyKet(1,-1).rewrite('Jz')).doit() == 1 - assert qapply(JzBra(1,1)*JzKet(1,1).rewrite('Jy')).doit() == 1 - assert qapply(JzBra(1,0)*JzKet(1,0).rewrite('Jy')).doit() == 1 - assert qapply(JzBra(1,-1)*JzKet(1,-1).rewrite('Jy')).doit() == 1 - assert qapply(JxBra(1,1)*JxKet(1,0).rewrite('Jy')).doit() == 0 - assert qapply(JxBra(1,1)*JxKet(1,-1).rewrite('Jy')) == 0 - assert qapply(JxBra(1,1)*JxKet(1,0).rewrite('Jz')).doit() == 0 - assert qapply(JxBra(1,1)*JxKet(1,-1).rewrite('Jz')) == 0 - assert qapply(JyBra(1,1)*JyKet(1,0).rewrite('Jx')).doit() == 0 - assert qapply(JyBra(1,1)*JyKet(1,-1).rewrite('Jx')) == 0 - assert qapply(JyBra(1,1)*JyKet(1,0).rewrite('Jz')).doit() == 0 - assert qapply(JyBra(1,1)*JyKet(1,-1).rewrite('Jz')) == 0 - assert qapply(JzBra(1,1)*JzKet(1,0).rewrite('Jx')).doit() == 0 - assert qapply(JzBra(1,1)*JzKet(1,-1).rewrite('Jx')) == 0 - assert qapply(JzBra(1,1)*JzKet(1,0).rewrite('Jy')).doit() == 0 - assert qapply(JzBra(1,1)*JzKet(1,-1).rewrite('Jy')) == 0 - assert qapply(JxBra(1,0)*JxKet(1,1).rewrite('Jy')) == 0 - assert qapply(JxBra(1,0)*JxKet(1,-1).rewrite('Jy')) == 0 - assert qapply(JxBra(1,0)*JxKet(1,1).rewrite('Jz')) == 0 - assert qapply(JxBra(1,0)*JxKet(1,-1).rewrite('Jz')) == 0 - assert qapply(JyBra(1,0)*JyKet(1,1).rewrite('Jx')) == 0 - assert qapply(JyBra(1,0)*JyKet(1,-1).rewrite('Jx')) == 0 - assert qapply(JyBra(1,0)*JyKet(1,1).rewrite('Jz')) == 0 - assert qapply(JyBra(1,0)*JyKet(1,-1).rewrite('Jz')) == 0 - assert qapply(JzBra(1,0)*JzKet(1,1).rewrite('Jx')) == 0 - assert qapply(JzBra(1,0)*JzKet(1,-1).rewrite('Jx')) == 0 - assert qapply(JzBra(1,0)*JzKet(1,1).rewrite('Jy')) == 0 - assert qapply(JzBra(1,0)*JzKet(1,-1).rewrite('Jy')) == 0 - assert qapply(JxBra(1,-1)*JxKet(1,1).rewrite('Jy')) == 0 - assert qapply(JxBra(1,-1)*JxKet(1,0).rewrite('Jy')).doit() == 0 - assert qapply(JxBra(1,-1)*JxKet(1,1).rewrite('Jz')) == 0 - assert qapply(JxBra(1,-1)*JxKet(1,0).rewrite('Jz')).doit() == 0 - assert qapply(JyBra(1,-1)*JyKet(1,1).rewrite('Jx')) == 0 - assert qapply(JyBra(1,-1)*JyKet(1,0).rewrite('Jx')).doit() == 0 - assert qapply(JyBra(1,-1)*JyKet(1,1).rewrite('Jz')) == 0 - assert qapply(JyBra(1,-1)*JyKet(1,0).rewrite('Jz')).doit() == 0 - assert qapply(JzBra(1,-1)*JzKet(1,1).rewrite('Jx')) == 0 - assert qapply(JzBra(1,-1)*JzKet(1,0).rewrite('Jx')).doit() == 0 - assert qapply(JzBra(1,-1)*JzKet(1,1).rewrite('Jy')) == 0 - assert qapply(JzBra(1,-1)*JzKet(1,0).rewrite('Jy')).doit() == 0 + assert qapply(JxBra(1, 1)*JxKet(1, 1).rewrite('Jy')).doit() == 1 + assert qapply(JxBra(1, 0)*JxKet(1, 0).rewrite('Jy')).doit() == 1 + assert qapply(JxBra(1, -1)*JxKet(1, -1).rewrite('Jy')).doit() == 1 + assert qapply(JxBra(1, 1)*JxKet(1, 1).rewrite('Jz')).doit() == 1 + assert qapply(JxBra(1, 0)*JxKet(1, 0).rewrite('Jz')).doit() == 1 + assert qapply(JxBra(1, -1)*JxKet(1, -1).rewrite('Jz')).doit() == 1 + assert qapply(JyBra(1, 1)*JyKet(1, 1).rewrite('Jx')).doit() == 1 + assert qapply(JyBra(1, 0)*JyKet(1, 0).rewrite('Jx')).doit() == 1 + assert qapply(JyBra(1, -1)*JyKet(1, -1).rewrite('Jx')).doit() == 1 + assert qapply(JyBra(1, 1)*JyKet(1, 1).rewrite('Jz')).doit() == 1 + assert qapply(JyBra(1, 0)*JyKet(1, 0).rewrite('Jz')).doit() == 1 + assert qapply(JyBra(1, -1)*JyKet(1, -1).rewrite('Jz')).doit() == 1 + assert qapply(JyBra(1, 1)*JyKet(1, 1).rewrite('Jz')).doit() == 1 + assert qapply(JyBra(1, 0)*JyKet(1, 0).rewrite('Jz')).doit() == 1 + assert qapply(JyBra(1, -1)*JyKet(1, -1).rewrite('Jz')).doit() == 1 + assert qapply(JzBra(1, 1)*JzKet(1, 1).rewrite('Jy')).doit() == 1 + assert qapply(JzBra(1, 0)*JzKet(1, 0).rewrite('Jy')).doit() == 1 + assert qapply(JzBra(1, -1)*JzKet(1, -1).rewrite('Jy')).doit() == 1 + assert qapply(JxBra(1, 1)*JxKet(1, 0).rewrite('Jy')).doit() == 0 + assert qapply(JxBra(1, 1)*JxKet(1, -1).rewrite('Jy')) == 0 + assert qapply(JxBra(1, 1)*JxKet(1, 0).rewrite('Jz')).doit() == 0 + assert qapply(JxBra(1, 1)*JxKet(1, -1).rewrite('Jz')) == 0 + assert qapply(JyBra(1, 1)*JyKet(1, 0).rewrite('Jx')).doit() == 0 + assert qapply(JyBra(1, 1)*JyKet(1, -1).rewrite('Jx')) == 0 + assert qapply(JyBra(1, 1)*JyKet(1, 0).rewrite('Jz')).doit() == 0 + assert qapply(JyBra(1, 1)*JyKet(1, -1).rewrite('Jz')) == 0 + assert qapply(JzBra(1, 1)*JzKet(1, 0).rewrite('Jx')).doit() == 0 + assert qapply(JzBra(1, 1)*JzKet(1, -1).rewrite('Jx')) == 0 + assert qapply(JzBra(1, 1)*JzKet(1, 0).rewrite('Jy')).doit() == 0 + assert qapply(JzBra(1, 1)*JzKet(1, -1).rewrite('Jy')) == 0 + assert qapply(JxBra(1, 0)*JxKet(1, 1).rewrite('Jy')) == 0 + assert qapply(JxBra(1, 0)*JxKet(1, -1).rewrite('Jy')) == 0 + assert qapply(JxBra(1, 0)*JxKet(1, 1).rewrite('Jz')) == 0 + assert qapply(JxBra(1, 0)*JxKet(1, -1).rewrite('Jz')) == 0 + assert qapply(JyBra(1, 0)*JyKet(1, 1).rewrite('Jx')) == 0 + assert qapply(JyBra(1, 0)*JyKet(1, -1).rewrite('Jx')) == 0 + assert qapply(JyBra(1, 0)*JyKet(1, 1).rewrite('Jz')) == 0 + assert qapply(JyBra(1, 0)*JyKet(1, -1).rewrite('Jz')) == 0 + assert qapply(JzBra(1, 0)*JzKet(1, 1).rewrite('Jx')) == 0 + assert qapply(JzBra(1, 0)*JzKet(1, -1).rewrite('Jx')) == 0 + assert qapply(JzBra(1, 0)*JzKet(1, 1).rewrite('Jy')) == 0 + assert qapply(JzBra(1, 0)*JzKet(1, -1).rewrite('Jy')) == 0 + assert qapply(JxBra(1, -1)*JxKet(1, 1).rewrite('Jy')) == 0 + assert qapply(JxBra(1, -1)*JxKet(1, 0).rewrite('Jy')).doit() == 0 + assert qapply(JxBra(1, -1)*JxKet(1, 1).rewrite('Jz')) == 0 + assert qapply(JxBra(1, -1)*JxKet(1, 0).rewrite('Jz')).doit() == 0 + assert qapply(JyBra(1, -1)*JyKet(1, 1).rewrite('Jx')) == 0 + assert qapply(JyBra(1, -1)*JyKet(1, 0).rewrite('Jx')).doit() == 0 + assert qapply(JyBra(1, -1)*JyKet(1, 1).rewrite('Jz')) == 0 + assert qapply(JyBra(1, -1)*JyKet(1, 0).rewrite('Jz')).doit() == 0 + assert qapply(JzBra(1, -1)*JzKet(1, 1).rewrite('Jx')) == 0 + assert qapply(JzBra(1, -1)*JzKet(1, 0).rewrite('Jx')).doit() == 0 + assert qapply(JzBra(1, -1)*JzKet(1, 1).rewrite('Jy')) == 0 + assert qapply(JzBra(1, -1)*JzKet(1, 0).rewrite('Jy')).doit() == 0 + def test_uncouple_2_coupled_states(): # j1=1/2, j2=1/2 - assert TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2)) == \ - expand(uncouple(couple( TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2)) ))) - assert TensorProduct(JzKet(S(1)/2,-S(1)/2), JzKet(S(1)/2,S(1)/2)) == \ - expand(uncouple(couple( TensorProduct(JzKet(S(1)/2,-S(1)/2), JzKet(S(1)/2,S(1)/2)) ))) - assert TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,-S(1)/2)) == \ - expand(uncouple(couple( TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,-S(1)/2)) ))) - assert TensorProduct(JzKet(S(1)/2,-S(1)/2), JzKet(S(1)/2,-S(1)/2)) == \ - expand(uncouple(couple( TensorProduct(JzKet(S(1)/2,-S(1)/2), JzKet(S(1)/2,-S(1)/2)) ))) + assert TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2)) == \ + expand(uncouple(couple( + TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2)) ))) + assert TensorProduct(JzKet(S(1)/2, -S(1)/2), JzKet(S(1)/2, S(1)/2)) == \ + expand(uncouple(couple( + TensorProduct(JzKet(S(1)/2, -S(1)/2), JzKet(S(1)/2, S(1)/2)) ))) + assert TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, -S(1)/2)) == \ + expand(uncouple(couple( + TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, -S(1)/2)) ))) + assert TensorProduct(JzKet(S(1)/2, -S(1)/2), JzKet(S(1)/2, -S(1)/2)) == \ + expand(uncouple(couple( + TensorProduct(JzKet(S(1)/2, -S(1)/2), JzKet(S(1)/2, -S(1)/2)) ))) # j1=1/2, j2=1 - assert TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(1,1)) == \ - expand(uncouple(couple( TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(1,1)) ))) - assert TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(1,0)) == \ - expand(uncouple(couple( TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(1,0)) ))) - assert TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(1,-1)) == \ - expand(uncouple(couple( TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(1,-1)) ))) - assert TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(1,1)) == \ - expand(uncouple(couple( TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(1,1)) ))) - assert TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(1,0)) == \ - expand(uncouple(couple( TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(1,0)) ))) - assert TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(1,-1)) == \ - expand(uncouple(couple( TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(1,-1)) ))) + assert TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(1, 1)) == \ + expand(uncouple( + couple( TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(1, 1)) ))) + assert TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(1, 0)) == \ + expand(uncouple( + couple( TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(1, 0)) ))) + assert TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(1, -1)) == \ + expand(uncouple( + couple( TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(1, -1)) ))) + assert TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(1, 1)) == \ + expand(uncouple( + couple( TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(1, 1)) ))) + assert TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(1, 0)) == \ + expand(uncouple( + couple( TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(1, 0)) ))) + assert TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(1, -1)) == \ + expand(uncouple( + couple( TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(1, -1)) ))) # j1=1, j2=1 - assert TensorProduct(JzKet(1,1), JzKet(1,1)) == \ - expand(uncouple(couple( TensorProduct(JzKet(1,1), JzKet(1,1)) ))) - assert TensorProduct(JzKet(1,1), JzKet(1,0)) == \ - expand(uncouple(couple( TensorProduct(JzKet(1,1), JzKet(1,0)) ))) - assert TensorProduct(JzKet(1,1), JzKet(1,-1)) == \ - expand(uncouple(couple( TensorProduct(JzKet(1,1), JzKet(1,-1)) ))) - assert TensorProduct(JzKet(1,0), JzKet(1,1)) == \ - expand(uncouple(couple( TensorProduct(JzKet(1,0), JzKet(1,1)) ))) - assert TensorProduct(JzKet(1,0), JzKet(1,0)) == \ - expand(uncouple(couple( TensorProduct(JzKet(1,0), JzKet(1,0)) ))) - assert TensorProduct(JzKet(1,0), JzKet(1,-1)) == \ - expand(uncouple(couple( TensorProduct(JzKet(1,0), JzKet(1,-1)) ))) - assert TensorProduct(JzKet(1,-1), JzKet(1,1)) == \ - expand(uncouple(couple( TensorProduct(JzKet(1,-1), JzKet(1,1)) ))) - assert TensorProduct(JzKet(1,-1), JzKet(1,0)) == \ - expand(uncouple(couple( TensorProduct(JzKet(1,-1), JzKet(1,0)) ))) - assert TensorProduct(JzKet(1,-1), JzKet(1,-1)) == \ - expand(uncouple(couple( TensorProduct(JzKet(1,-1), JzKet(1,-1)) ))) + assert TensorProduct(JzKet(1, 1), JzKet(1, 1)) == \ + expand(uncouple(couple( TensorProduct(JzKet(1, 1), JzKet(1, 1)) ))) + assert TensorProduct(JzKet(1, 1), JzKet(1, 0)) == \ + expand(uncouple(couple( TensorProduct(JzKet(1, 1), JzKet(1, 0)) ))) + assert TensorProduct(JzKet(1, 1), JzKet(1, -1)) == \ + expand(uncouple(couple( TensorProduct(JzKet(1, 1), JzKet(1, -1)) ))) + assert TensorProduct(JzKet(1, 0), JzKet(1, 1)) == \ + expand(uncouple(couple( TensorProduct(JzKet(1, 0), JzKet(1, 1)) ))) + assert TensorProduct(JzKet(1, 0), JzKet(1, 0)) == \ + expand(uncouple(couple( TensorProduct(JzKet(1, 0), JzKet(1, 0)) ))) + assert TensorProduct(JzKet(1, 0), JzKet(1, -1)) == \ + expand(uncouple(couple( TensorProduct(JzKet(1, 0), JzKet(1, -1)) ))) + assert TensorProduct(JzKet(1, -1), JzKet(1, 1)) == \ + expand(uncouple(couple( TensorProduct(JzKet(1, -1), JzKet(1, 1)) ))) + assert TensorProduct(JzKet(1, -1), JzKet(1, 0)) == \ + expand(uncouple(couple( TensorProduct(JzKet(1, -1), JzKet(1, 0)) ))) + assert TensorProduct(JzKet(1, -1), JzKet(1, -1)) == \ + expand(uncouple(couple( TensorProduct(JzKet(1, -1), JzKet(1, -1)) ))) + def test_uncouple_3_coupled_states(): # Default coupling # j1=1/2, j2=1/2, j3=1/2 - assert TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2)) == \ - expand(uncouple(couple( TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2)) ))) - assert TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(-1)/2)) == \ - expand(uncouple(couple( TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(-1)/2)) ))) - assert TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(1)/2)) == \ - expand(uncouple(couple( TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(1)/2)) ))) - assert TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(-1)/2)) == \ - expand(uncouple(couple( TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(-1)/2)) ))) - assert TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2)) == \ - expand(uncouple(couple( TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2)) ))) - assert TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(-1)/2)) == \ - expand(uncouple(couple( TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(-1)/2)) ))) - assert TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(1)/2)) == \ - expand(uncouple(couple( TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(1)/2)) ))) - assert TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(-1)/2)) == \ - expand(uncouple(couple( TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(-1)/2)) ))) + assert TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2)) == \ + expand(uncouple(couple( TensorProduct(JzKet( + S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2)) ))) + assert TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(-1)/2)) == \ + expand(uncouple(couple( TensorProduct(JzKet(S( + 1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(-1)/2)) ))) + assert TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(1)/2)) == \ + expand(uncouple(couple( TensorProduct(JzKet(S( + 1)/2, S(1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(1)/2)) ))) + assert TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(-1)/2)) == \ + expand(uncouple(couple( TensorProduct(JzKet(S( + 1)/2, S(1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(-1)/2)) ))) + assert TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2)) == \ + expand(uncouple(couple( TensorProduct(JzKet(S( + 1)/2, S(-1)/2), JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2)) ))) + assert TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(-1)/2)) == \ + expand(uncouple(couple( TensorProduct(JzKet(S( + 1)/2, S(-1)/2), JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(-1)/2)) ))) + assert TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(1)/2)) == \ + expand(uncouple(couple( TensorProduct(JzKet(S( + 1)/2, S(-1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(1)/2)) ))) + assert TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(-1)/2)) == \ + expand(uncouple(couple( TensorProduct(JzKet(S(1)/2, S(-1)/ + 2), JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(-1)/2)) ))) # j1=1/2, j2=1, j3=1/2 - assert TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(1,1), JzKet(S(1)/2,S(1)/2)) == \ - expand(uncouple(couple( TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(1,1), JzKet(S(1)/2,S(1)/2)) ))) - assert TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(1,1), JzKet(S(1)/2,S(-1)/2)) == \ - expand(uncouple(couple( TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(1,1), JzKet(S(1)/2,S(-1)/2)) ))) - assert TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(1,0), JzKet(S(1)/2,S(1)/2)) == \ - expand(uncouple(couple( TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(1,0), JzKet(S(1)/2,S(1)/2)) ))) - assert TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(1,0), JzKet(S(1)/2,S(-1)/2)) == \ - expand(uncouple(couple( TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(1,0), JzKet(S(1)/2,S(-1)/2)) ))) - assert TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(1,-1), JzKet(S(1)/2,S(1)/2)) == \ - expand(uncouple(couple( TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(1,-1), JzKet(S(1)/2,S(1)/2)) ))) - assert TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(1,-1), JzKet(S(1)/2,S(-1)/2)) == \ - expand(uncouple(couple( TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(1,-1), JzKet(S(1)/2,S(-1)/2)) ))) - assert TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(1,1), JzKet(S(1)/2,S(1)/2)) == \ - expand(uncouple(couple( TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(1,1), JzKet(S(1)/2,S(1)/2)) ))) - assert TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(1,1), JzKet(S(1)/2,S(-1)/2)) == \ - expand(uncouple(couple( TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(1,1), JzKet(S(1)/2,S(-1)/2)) ))) - assert TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(1,0), JzKet(S(1)/2,S(1)/2)) == \ - expand(uncouple(couple( TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(1,0), JzKet(S(1)/2,S(1)/2)) ))) - assert TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(1,0), JzKet(S(1)/2,S(-1)/2)) == \ - expand(uncouple(couple( TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(1,0), JzKet(S(1)/2,S(-1)/2)) ))) - assert TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(1,-1), JzKet(S(1)/2,S(1)/2)) == \ - expand(uncouple(couple( TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(1,-1), JzKet(S(1)/2,S(1)/2)) ))) - assert TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(1,-1), JzKet(S(1)/2,S(-1)/2)) == \ - expand(uncouple(couple( TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(1,-1), JzKet(S(1)/2,S(-1)/2)) ))) + assert TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(1, 1), JzKet(S(1)/2, S(1)/2)) == \ + expand(uncouple(couple( TensorProduct( + JzKet(S(1)/2, S(1)/2), JzKet(1, 1), JzKet(S(1)/2, S(1)/2)) ))) + assert TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(1, 1), JzKet(S(1)/2, S(-1)/2)) == \ + expand(uncouple(couple( TensorProduct( + JzKet(S(1)/2, S(1)/2), JzKet(1, 1), JzKet(S(1)/2, S(-1)/2)) ))) + assert TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(1, 0), JzKet(S(1)/2, S(1)/2)) == \ + expand(uncouple(couple( TensorProduct( + JzKet(S(1)/2, S(1)/2), JzKet(1, 0), JzKet(S(1)/2, S(1)/2)) ))) + assert TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(1, 0), JzKet(S(1)/2, S(-1)/2)) == \ + expand(uncouple(couple( TensorProduct( + JzKet(S(1)/2, S(1)/2), JzKet(1, 0), JzKet(S(1)/2, S(-1)/2)) ))) + assert TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(1, -1), JzKet(S(1)/2, S(1)/2)) == \ + expand(uncouple(couple( TensorProduct( + JzKet(S(1)/2, S(1)/2), JzKet(1, -1), JzKet(S(1)/2, S(1)/2)) ))) + assert TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(1, -1), JzKet(S(1)/2, S(-1)/2)) == \ + expand(uncouple(couple( TensorProduct( + JzKet(S(1)/2, S(1)/2), JzKet(1, -1), JzKet(S(1)/2, S(-1)/2)) ))) + assert TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(1, 1), JzKet(S(1)/2, S(1)/2)) == \ + expand(uncouple(couple( TensorProduct( + JzKet(S(1)/2, S(-1)/2), JzKet(1, 1), JzKet(S(1)/2, S(1)/2)) ))) + assert TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(1, 1), JzKet(S(1)/2, S(-1)/2)) == \ + expand(uncouple(couple( TensorProduct( + JzKet(S(1)/2, S(-1)/2), JzKet(1, 1), JzKet(S(1)/2, S(-1)/2)) ))) + assert TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(1, 0), JzKet(S(1)/2, S(1)/2)) == \ + expand(uncouple(couple( TensorProduct( + JzKet(S(1)/2, S(-1)/2), JzKet(1, 0), JzKet(S(1)/2, S(1)/2)) ))) + assert TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(1, 0), JzKet(S(1)/2, S(-1)/2)) == \ + expand(uncouple(couple( TensorProduct( + JzKet(S(1)/2, S(-1)/2), JzKet(1, 0), JzKet(S(1)/2, S(-1)/2)) ))) + assert TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(1, -1), JzKet(S(1)/2, S(1)/2)) == \ + expand(uncouple(couple( TensorProduct( + JzKet(S(1)/2, S(-1)/2), JzKet(1, -1), JzKet(S(1)/2, S(1)/2)) ))) + assert TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(1, -1), JzKet(S(1)/2, S(-1)/2)) == \ + expand(uncouple(couple( TensorProduct( + JzKet(S(1)/2, S(-1)/2), JzKet(1, -1), JzKet(S(1)/2, S(-1)/2)) ))) # Coupling j1+j3=j13, j13+j2=j # j1=1/2, j2=1/2, j3=1/2 - assert TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2)) == \ - expand(uncouple(couple( TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2)), ((1,3),(1,2)) ))) - assert TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(-1)/2)) == \ - expand(uncouple(couple( TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(-1)/2)), ((1,3),(1,2)) ))) - assert TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(1)/2)) == \ - expand(uncouple(couple( TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(1)/2)), ((1,3),(1,2)) ))) - assert TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(-1)/2)) == \ - expand(uncouple(couple( TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(-1)/2)), ((1,3),(1,2)) ))) - assert TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2)) == \ - expand(uncouple(couple( TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2)), ((1,3),(1,2)) ))) - assert TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(-1)/2)) == \ - expand(uncouple(couple( TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(-1)/2)), ((1,3),(1,2)) ))) - assert TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(1)/2)) == \ - expand(uncouple(couple( TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(1)/2)), ((1,3),(1,2)) ))) - assert TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(-1)/2)) == \ - expand(uncouple(couple( TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(-1)/2)), ((1,3),(1,2)) ))) + assert TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2)) == \ + expand(uncouple(couple( TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet( + S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2)), ((1, 3), (1, 2)) ))) + assert TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(-1)/2)) == \ + expand(uncouple(couple( TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet( + S(1)/2, S(1)/2), JzKet(S(1)/2, S(-1)/2)), ((1, 3), (1, 2)) ))) + assert TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(1)/2)) == \ + expand(uncouple(couple( TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet( + S(1)/2, S(-1)/2), JzKet(S(1)/2, S(1)/2)), ((1, 3), (1, 2)) ))) + assert TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(-1)/2)) == \ + expand(uncouple(couple( TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet( + S(1)/2, S(-1)/2), JzKet(S(1)/2, S(-1)/2)), ((1, 3), (1, 2)) ))) + assert TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2)) == \ + expand(uncouple(couple( TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet( + S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2)), ((1, 3), (1, 2)) ))) + assert TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(-1)/2)) == \ + expand(uncouple(couple( TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet( + S(1)/2, S(1)/2), JzKet(S(1)/2, S(-1)/2)), ((1, 3), (1, 2)) ))) + assert TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(1)/2)) == \ + expand(uncouple(couple( TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet( + S(1)/2, S(-1)/2), JzKet(S(1)/2, S(1)/2)), ((1, 3), (1, 2)) ))) + assert TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(-1)/2)) == \ + expand(uncouple(couple( TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet( + S(1)/2, S(-1)/2), JzKet(S(1)/2, S(-1)/2)), ((1, 3), (1, 2)) ))) # j1=1/2, j2=1, j3=1/2 - assert TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(1,1), JzKet(S(1)/2,S(1)/2)) == \ - expand(uncouple(couple( TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(1,1), JzKet(S(1)/2,S(1)/2)), ((1,3),(1,2)) ))) - assert TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(1,1), JzKet(S(1)/2,S(-1)/2)) == \ - expand(uncouple(couple( TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(1,1), JzKet(S(1)/2,S(-1)/2)), ((1,3),(1,2)) ))) - assert TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(1,0), JzKet(S(1)/2,S(1)/2)) == \ - expand(uncouple(couple( TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(1,0), JzKet(S(1)/2,S(1)/2)), ((1,3),(1,2)) ))) - assert TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(1,0), JzKet(S(1)/2,S(-1)/2)) == \ - expand(uncouple(couple( TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(1,0), JzKet(S(1)/2,S(-1)/2)), ((1,3),(1,2)) ))) - assert TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(1,-1), JzKet(S(1)/2,S(1)/2)) == \ - expand(uncouple(couple( TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(1,-1), JzKet(S(1)/2,S(1)/2)), ((1,3),(1,2)) ))) - assert TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(1,-1), JzKet(S(1)/2,S(-1)/2)) == \ - expand(uncouple(couple( TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(1,-1), JzKet(S(1)/2,S(-1)/2)), ((1,3),(1,2)) ))) - assert TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(1,1), JzKet(S(1)/2,S(1)/2)) == \ - expand(uncouple(couple( TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(1,1), JzKet(S(1)/2,S(1)/2)), ((1,3),(1,2)) ))) - assert TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(1,1), JzKet(S(1)/2,S(-1)/2)) == \ - expand(uncouple(couple( TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(1,1), JzKet(S(1)/2,S(-1)/2)), ((1,3),(1,2)) ))) - assert TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(1,0), JzKet(S(1)/2,S(1)/2)) == \ - expand(uncouple(couple( TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(1,0), JzKet(S(1)/2,S(1)/2)), ((1,3),(1,2)) ))) - assert TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(1,0), JzKet(S(1)/2,S(-1)/2)) == \ - expand(uncouple(couple( TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(1,0), JzKet(S(1)/2,S(-1)/2)), ((1,3),(1,2)) ))) - assert TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(1,-1), JzKet(S(1)/2,S(1)/2)) == \ - expand(uncouple(couple( TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(1,-1), JzKet(S(1)/2,S(1)/2)), ((1,3),(1,2)) ))) - assert TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(1,-1), JzKet(S(1)/2,S(-1)/2)) == \ - expand(uncouple(couple( TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(1,-1), JzKet(S(1)/2,S(-1)/2)), ((1,3),(1,2)) ))) + assert TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(1, 1), JzKet(S(1)/2, S(1)/2)) == \ + expand(uncouple(couple( TensorProduct(JzKet(S(1)/2, S( + 1)/2), JzKet(1, 1), JzKet(S(1)/2, S(1)/2)), ((1, 3), (1, 2)) ))) + assert TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(1, 1), JzKet(S(1)/2, S(-1)/2)) == \ + expand(uncouple(couple( TensorProduct(JzKet(S(1)/2, S( + 1)/2), JzKet(1, 1), JzKet(S(1)/2, S(-1)/2)), ((1, 3), (1, 2)) ))) + assert TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(1, 0), JzKet(S(1)/2, S(1)/2)) == \ + expand(uncouple(couple( TensorProduct(JzKet(S(1)/2, S( + 1)/2), JzKet(1, 0), JzKet(S(1)/2, S(1)/2)), ((1, 3), (1, 2)) ))) + assert TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(1, 0), JzKet(S(1)/2, S(-1)/2)) == \ + expand(uncouple(couple( TensorProduct(JzKet(S(1)/2, S( + 1)/2), JzKet(1, 0), JzKet(S(1)/2, S(-1)/2)), ((1, 3), (1, 2)) ))) + assert TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(1, -1), JzKet(S(1)/2, S(1)/2)) == \ + expand(uncouple(couple( TensorProduct(JzKet(S(1)/2, S( + 1)/2), JzKet(1, -1), JzKet(S(1)/2, S(1)/2)), ((1, 3), (1, 2)) ))) + assert TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(1, -1), JzKet(S(1)/2, S(-1)/2)) == \ + expand(uncouple(couple( TensorProduct(JzKet(S(1)/2, S( + 1)/2), JzKet(1, -1), JzKet(S(1)/2, S(-1)/2)), ((1, 3), (1, 2)) ))) + assert TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(1, 1), JzKet(S(1)/2, S(1)/2)) == \ + expand(uncouple(couple( TensorProduct(JzKet(S(1)/2, S( + -1)/2), JzKet(1, 1), JzKet(S(1)/2, S(1)/2)), ((1, 3), (1, 2)) ))) + assert TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(1, 1), JzKet(S(1)/2, S(-1)/2)) == \ + expand(uncouple(couple( TensorProduct(JzKet(S(1)/2, S( + -1)/2), JzKet(1, 1), JzKet(S(1)/2, S(-1)/2)), ((1, 3), (1, 2)) ))) + assert TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(1, 0), JzKet(S(1)/2, S(1)/2)) == \ + expand(uncouple(couple( TensorProduct(JzKet(S(1)/2, S( + -1)/2), JzKet(1, 0), JzKet(S(1)/2, S(1)/2)), ((1, 3), (1, 2)) ))) + assert TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(1, 0), JzKet(S(1)/2, S(-1)/2)) == \ + expand(uncouple(couple( TensorProduct(JzKet(S(1)/2, S( + -1)/2), JzKet(1, 0), JzKet(S(1)/2, S(-1)/2)), ((1, 3), (1, 2)) ))) + assert TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(1, -1), JzKet(S(1)/2, S(1)/2)) == \ + expand(uncouple(couple( TensorProduct(JzKet(S(1)/2, S( + -1)/2), JzKet(1, -1), JzKet(S(1)/2, S(1)/2)), ((1, 3), (1, 2)) ))) + assert TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(1, -1), JzKet(S(1)/2, S(-1)/2)) == \ + expand(uncouple(couple( TensorProduct(JzKet(S(1)/2, S(-1)/ + 2), JzKet(1, -1), JzKet(S(1)/2, S(-1)/2)), ((1, 3), (1, 2)) ))) + def test_uncouple_4_coupled_states(): # j1=1/2, j2=1/2, j3=1/2, j4=1/2 - assert TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2),JzKet(S(1)/2,S(1)/2)) == \ - expand(uncouple(couple( TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2)) ))) - assert TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2),JzKet(S(1)/2,S(-1)/2)) == \ - expand(uncouple(couple( TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(-1)/2)) ))) - assert TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(-1)/2),JzKet(S(1)/2,S(1)/2)) == \ - expand(uncouple(couple( TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(1)/2)) ))) - assert TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(-1)/2),JzKet(S(1)/2,S(-1)/2)) == \ - expand(uncouple(couple( TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(-1)/2)) ))) - assert TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(1)/2),JzKet(S(1)/2,S(1)/2)) == \ - expand(uncouple(couple( TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2)) ))) - assert TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(1)/2),JzKet(S(1)/2,S(-1)/2)) == \ - expand(uncouple(couple( TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(-1)/2)) ))) - assert TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(-1)/2),JzKet(S(1)/2,S(1)/2)) == \ - expand(uncouple(couple( TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(1)/2)) ))) - assert TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(-1)/2),JzKet(S(1)/2,S(-1)/2)) == \ - expand(uncouple(couple( TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(-1)/2)) ))) - assert TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2),JzKet(S(1)/2,S(1)/2)) == \ - expand(uncouple(couple( TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2)) ))) - assert TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2),JzKet(S(1)/2,S(-1)/2)) == \ - expand(uncouple(couple( TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(-1)/2)) ))) - assert TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(-1)/2),JzKet(S(1)/2,S(1)/2)) == \ - expand(uncouple(couple( TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(1)/2)) ))) - assert TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(-1)/2),JzKet(S(1)/2,S(-1)/2)) == \ - expand(uncouple(couple( TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(-1)/2)) ))) - assert TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(1)/2),JzKet(S(1)/2,S(1)/2)) == \ - expand(uncouple(couple( TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2)) ))) - assert TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(1)/2),JzKet(S(1)/2,S(-1)/2)) == \ - expand(uncouple(couple( TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(-1)/2)) ))) - assert TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(-1)/2),JzKet(S(1)/2,S(1)/2)) == \ - expand(uncouple(couple( TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(1)/2)) ))) - assert TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(-1)/2),JzKet(S(1)/2,S(-1)/2)) == \ - expand(uncouple(couple( TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(-1)/2)) ))) + assert TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2)) == \ + expand(uncouple(couple( TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet( + S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2)) ))) + assert TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(-1)/2)) == \ + expand(uncouple(couple( TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S( + 1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(-1)/2)) ))) + assert TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(1)/2)) == \ + expand(uncouple(couple( TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S( + 1)/2, S(1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(1)/2)) ))) + assert TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(-1)/2)) == \ + expand(uncouple(couple( TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S( + 1)/2, S(1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(-1)/2)) ))) + assert TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2)) == \ + expand(uncouple(couple( TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S( + 1)/2, S(-1)/2), JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2)) ))) + assert TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(-1)/2)) == \ + expand(uncouple(couple( TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S( + 1)/2, S(-1)/2), JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(-1)/2)) ))) + assert TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(1)/2)) == \ + expand(uncouple(couple( TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S( + 1)/2, S(-1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(1)/2)) ))) + assert TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(-1)/2)) == \ + expand(uncouple(couple( TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(-1)/2)) ))) + assert TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2)) == \ + expand(uncouple(couple( TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet( + S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2)) ))) + assert TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(-1)/2)) == \ + expand(uncouple(couple( TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(S( + 1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(-1)/2)) ))) + assert TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(1)/2)) == \ + expand(uncouple(couple( TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(S( + 1)/2, S(1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(1)/2)) ))) + assert TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(-1)/2)) == \ + expand(uncouple(couple( TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(S( + 1)/2, S(1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(-1)/2)) ))) + assert TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2)) == \ + expand(uncouple(couple( TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(S( + 1)/2, S(-1)/2), JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2)) ))) + assert TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(-1)/2)) == \ + expand(uncouple(couple( TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(S( + 1)/2, S(-1)/2), JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(-1)/2)) ))) + assert TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(1)/2)) == \ + expand(uncouple(couple( TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(S( + 1)/2, S(-1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(1)/2)) ))) + assert TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(-1)/2)) == \ + expand(uncouple(couple( TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(-1)/2)) ))) # j1=1/2, j2=1/2, j3=1, j4=1/2 - assert TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,1),JzKet(S(1)/2,S(1)/2)) == \ - expand(uncouple(couple( TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,1), JzKet(S(1)/2,S(1)/2)) ))) - assert TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,1),JzKet(S(1)/2,S(-1)/2)) == \ - expand(uncouple(couple( TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,1), JzKet(S(1)/2,S(-1)/2)) ))) - assert TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,0),JzKet(S(1)/2,S(1)/2)) == \ - expand(uncouple(couple( TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,0), JzKet(S(1)/2,S(1)/2)) ))) - assert TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,0),JzKet(S(1)/2,S(-1)/2)) == \ - expand(uncouple(couple( TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,0), JzKet(S(1)/2,S(-1)/2)) ))) - assert TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,-1),JzKet(S(1)/2,S(1)/2)) == \ - expand(uncouple(couple( TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,-1), JzKet(S(1)/2,S(1)/2)) ))) - assert TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,-1),JzKet(S(1)/2,S(-1)/2)) == \ - expand(uncouple(couple( TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,-1), JzKet(S(1)/2,S(-1)/2)) ))) - assert TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(1,1),JzKet(S(1)/2,S(1)/2)) == \ - expand(uncouple(couple( TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(1,1), JzKet(S(1)/2,S(1)/2)) ))) - assert TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(1,1),JzKet(S(1)/2,S(-1)/2)) == \ - expand(uncouple(couple( TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(1,1), JzKet(S(1)/2,S(-1)/2)) ))) - assert TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(1,0),JzKet(S(1)/2,S(1)/2)) == \ - expand(uncouple(couple( TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(1,0), JzKet(S(1)/2,S(1)/2)) ))) - assert TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(1,0),JzKet(S(1)/2,S(-1)/2)) == \ - expand(uncouple(couple( TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(1,0), JzKet(S(1)/2,S(-1)/2)) ))) - assert TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(1,-1),JzKet(S(1)/2,S(1)/2)) == \ - expand(uncouple(couple( TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(1,-1), JzKet(S(1)/2,S(1)/2)) ))) - assert TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(1,-1),JzKet(S(1)/2,S(-1)/2)) == \ - expand(uncouple(couple( TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(1,-1), JzKet(S(1)/2,S(-1)/2)) ))) - assert TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,1),JzKet(S(1)/2,S(1)/2)) == \ - expand(uncouple(couple( TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,1), JzKet(S(1)/2,S(1)/2)) ))) - assert TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,1),JzKet(S(1)/2,S(-1)/2)) == \ - expand(uncouple(couple( TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,1), JzKet(S(1)/2,S(-1)/2)) ))) - assert TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,0),JzKet(S(1)/2,S(1)/2)) == \ - expand(uncouple(couple( TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,0), JzKet(S(1)/2,S(1)/2)) ))) - assert TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,0),JzKet(S(1)/2,S(-1)/2)) == \ - expand(uncouple(couple( TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,0), JzKet(S(1)/2,S(-1)/2)) ))) - assert TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,-1),JzKet(S(1)/2,S(1)/2)) == \ - expand(uncouple(couple( TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,-1), JzKet(S(1)/2,S(1)/2)) ))) - assert TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,-1),JzKet(S(1)/2,S(-1)/2)) == \ - expand(uncouple(couple( TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,-1), JzKet(S(1)/2,S(-1)/2)) ))) - assert TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(1,1),JzKet(S(1)/2,S(1)/2)) == \ - expand(uncouple(couple( TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(1,1), JzKet(S(1)/2,S(1)/2)) ))) - assert TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(1,1),JzKet(S(1)/2,S(-1)/2)) == \ - expand(uncouple(couple( TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(1,1), JzKet(S(1)/2,S(-1)/2)) ))) - assert TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(1,0),JzKet(S(1)/2,S(1)/2)) == \ - expand(uncouple(couple( TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(1,0), JzKet(S(1)/2,S(1)/2)) ))) - assert TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(1,0),JzKet(S(1)/2,S(-1)/2)) == \ - expand(uncouple(couple( TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(1,0), JzKet(S(1)/2,S(-1)/2)) ))) - assert TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(1,-1),JzKet(S(1)/2,S(1)/2)) == \ - expand(uncouple(couple( TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(1,-1), JzKet(S(1)/2,S(1)/2)) ))) - assert TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(1,-1),JzKet(S(1)/2,S(-1)/2)) == \ - expand(uncouple(couple( TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(1,-1), JzKet(S(1)/2,S(-1)/2)) ))) + assert TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, 1), JzKet(S(1)/2, S(1)/2)) == \ + expand(uncouple(couple( TensorProduct(JzKet(S(1)/2, S(1)/2), + JzKet(S(1)/2, S(1)/2), JzKet(1, 1), JzKet(S(1)/2, S(1)/2)) ))) + assert TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, 1), JzKet(S(1)/2, S(-1)/2)) == \ + expand(uncouple(couple( TensorProduct(JzKet(S(1)/2, S(1)/2), + JzKet(S(1)/2, S(1)/2), JzKet(1, 1), JzKet(S(1)/2, S(-1)/2)) ))) + assert TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, 0), JzKet(S(1)/2, S(1)/2)) == \ + expand(uncouple(couple( TensorProduct(JzKet(S(1)/2, S(1)/2), + JzKet(S(1)/2, S(1)/2), JzKet(1, 0), JzKet(S(1)/2, S(1)/2)) ))) + assert TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, 0), JzKet(S(1)/2, S(-1)/2)) == \ + expand(uncouple(couple( TensorProduct(JzKet(S(1)/2, S(1)/2), + JzKet(S(1)/2, S(1)/2), JzKet(1, 0), JzKet(S(1)/2, S(-1)/2)) ))) + assert TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, -1), JzKet(S(1)/2, S(1)/2)) == \ + expand(uncouple(couple( TensorProduct(JzKet(S(1)/2, S(1)/2), + JzKet(S(1)/2, S(1)/2), JzKet(1, -1), JzKet(S(1)/2, S(1)/2)) ))) + assert TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, -1), JzKet(S(1)/2, S(-1)/2)) == \ + expand(uncouple(couple( TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet( + S(1)/2, S(1)/2), JzKet(1, -1), JzKet(S(1)/2, S(-1)/2)) ))) + assert TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(1, 1), JzKet(S(1)/2, S(1)/2)) == \ + expand(uncouple(couple( TensorProduct(JzKet(S(1)/2, S(1)/2), + JzKet(S(1)/2, S(-1)/2), JzKet(1, 1), JzKet(S(1)/2, S(1)/2)) ))) + assert TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(1, 1), JzKet(S(1)/2, S(-1)/2)) == \ + expand(uncouple(couple( TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet( + S(1)/2, S(-1)/2), JzKet(1, 1), JzKet(S(1)/2, S(-1)/2)) ))) + assert TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(1, 0), JzKet(S(1)/2, S(1)/2)) == \ + expand(uncouple(couple( TensorProduct(JzKet(S(1)/2, S(1)/2), + JzKet(S(1)/2, S(-1)/2), JzKet(1, 0), JzKet(S(1)/2, S(1)/2)) ))) + assert TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(1, 0), JzKet(S(1)/2, S(-1)/2)) == \ + expand(uncouple(couple( TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet( + S(1)/2, S(-1)/2), JzKet(1, 0), JzKet(S(1)/2, S(-1)/2)) ))) + assert TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(1, -1), JzKet(S(1)/2, S(1)/2)) == \ + expand(uncouple(couple( TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet( + S(1)/2, S(-1)/2), JzKet(1, -1), JzKet(S(1)/2, S(1)/2)) ))) + assert TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(1, -1), JzKet(S(1)/2, S(-1)/2)) == \ + expand(uncouple(couple( TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet( + S(1)/2, S(-1)/2), JzKet(1, -1), JzKet(S(1)/2, S(-1)/2)) ))) + assert TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, 1), JzKet(S(1)/2, S(1)/2)) == \ + expand(uncouple(couple( TensorProduct(JzKet(S(1)/2, S(-1)/2), + JzKet(S(1)/2, S(1)/2), JzKet(1, 1), JzKet(S(1)/2, S(1)/2)) ))) + assert TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, 1), JzKet(S(1)/2, S(-1)/2)) == \ + expand(uncouple(couple( TensorProduct(JzKet(S(1)/2, S(-1)/2), + JzKet(S(1)/2, S(1)/2), JzKet(1, 1), JzKet(S(1)/2, S(-1)/2)) ))) + assert TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, 0), JzKet(S(1)/2, S(1)/2)) == \ + expand(uncouple(couple( TensorProduct(JzKet(S(1)/2, S(-1)/2), + JzKet(S(1)/2, S(1)/2), JzKet(1, 0), JzKet(S(1)/2, S(1)/2)) ))) + assert TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, 0), JzKet(S(1)/2, S(-1)/2)) == \ + expand(uncouple(couple( TensorProduct(JzKet(S(1)/2, S(-1)/2), + JzKet(S(1)/2, S(1)/2), JzKet(1, 0), JzKet(S(1)/2, S(-1)/2)) ))) + assert TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, -1), JzKet(S(1)/2, S(1)/2)) == \ + expand(uncouple(couple( TensorProduct(JzKet(S(1)/2, S(-1)/2), + JzKet(S(1)/2, S(1)/2), JzKet(1, -1), JzKet(S(1)/2, S(1)/2)) ))) + assert TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, -1), JzKet(S(1)/2, S(-1)/2)) == \ + expand(uncouple(couple( TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet( + S(1)/2, S(1)/2), JzKet(1, -1), JzKet(S(1)/2, S(-1)/2)) ))) + assert TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(1, 1), JzKet(S(1)/2, S(1)/2)) == \ + expand(uncouple(couple( TensorProduct(JzKet(S(1)/2, S(-1)/2), + JzKet(S(1)/2, S(-1)/2), JzKet(1, 1), JzKet(S(1)/2, S(1)/2)) ))) + assert TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(1, 1), JzKet(S(1)/2, S(-1)/2)) == \ + expand(uncouple(couple( TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet( + S(1)/2, S(-1)/2), JzKet(1, 1), JzKet(S(1)/2, S(-1)/2)) ))) + assert TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(1, 0), JzKet(S(1)/2, S(1)/2)) == \ + expand(uncouple(couple( TensorProduct(JzKet(S(1)/2, S(-1)/2), + JzKet(S(1)/2, S(-1)/2), JzKet(1, 0), JzKet(S(1)/2, S(1)/2)) ))) + assert TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(1, 0), JzKet(S(1)/2, S(-1)/2)) == \ + expand(uncouple(couple( TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet( + S(1)/2, S(-1)/2), JzKet(1, 0), JzKet(S(1)/2, S(-1)/2)) ))) + assert TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(1, -1), JzKet(S(1)/2, S(1)/2)) == \ + expand(uncouple(couple( TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet( + S(1)/2, S(-1)/2), JzKet(1, -1), JzKet(S(1)/2, S(1)/2)) ))) + assert TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(1, -1), JzKet(S(1)/2, S(-1)/2)) == \ + expand(uncouple(couple( TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet( + S(1)/2, S(-1)/2), JzKet(1, -1), JzKet(S(1)/2, S(-1)/2)) ))) # Couple j1+j3=j13, j2+j4=j24, j13+j24=j # j1=1/2, j2=1/2, j3=1/2, j4=1/2 - assert TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2),JzKet(S(1)/2,S(1)/2)) == \ - expand(uncouple(couple( TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2)), ((1,3),(2,4),(1,2)) ))) - assert TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2),JzKet(S(1)/2,S(-1)/2)) == \ - expand(uncouple(couple( TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(-1)/2)), ((1,3),(2,4),(1,2)) ))) - assert TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(-1)/2),JzKet(S(1)/2,S(1)/2)) == \ - expand(uncouple(couple( TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(1)/2)), ((1,3),(2,4),(1,2)) ))) - assert TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(-1)/2),JzKet(S(1)/2,S(-1)/2)) == \ - expand(uncouple(couple( TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(-1)/2)), ((1,3),(2,4),(1,2)) ))) - assert TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(1)/2),JzKet(S(1)/2,S(1)/2)) == \ - expand(uncouple(couple( TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2)), ((1,3),(2,4),(1,2)) ))) - assert TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(1)/2),JzKet(S(1)/2,S(-1)/2)) == \ - expand(uncouple(couple( TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(-1)/2)), ((1,3),(2,4),(1,2)) ))) - assert TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(-1)/2),JzKet(S(1)/2,S(1)/2)) == \ - expand(uncouple(couple( TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(1)/2)), ((1,3),(2,4),(1,2)) ))) - assert TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(-1)/2),JzKet(S(1)/2,S(-1)/2)) == \ - expand(uncouple(couple( TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(-1)/2)), ((1,3),(2,4),(1,2)) ))) - assert TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2),JzKet(S(1)/2,S(1)/2)) == \ - expand(uncouple(couple( TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2)), ((1,3),(2,4),(1,2)) ))) - assert TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2),JzKet(S(1)/2,S(-1)/2)) == \ - expand(uncouple(couple( TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(-1)/2)), ((1,3),(2,4),(1,2)) ))) - assert TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(-1)/2),JzKet(S(1)/2,S(1)/2)) == \ - expand(uncouple(couple( TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(1)/2)), ((1,3),(2,4),(1,2)) ))) - assert TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(-1)/2),JzKet(S(1)/2,S(-1)/2)) == \ - expand(uncouple(couple( TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(-1)/2)), ((1,3),(2,4),(1,2)) ))) - assert TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(1)/2),JzKet(S(1)/2,S(1)/2)) == \ - expand(uncouple(couple( TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2)), ((1,3),(2,4),(1,2)) ))) - assert TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(1)/2),JzKet(S(1)/2,S(-1)/2)) == \ - expand(uncouple(couple( TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(-1)/2)), ((1,3),(2,4),(1,2)) ))) - assert TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(-1)/2),JzKet(S(1)/2,S(1)/2)) == \ - expand(uncouple(couple( TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(1)/2)), ((1,3),(2,4),(1,2)) ))) - assert TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(-1)/2),JzKet(S(1)/2,S(-1)/2)) == \ - expand(uncouple(couple( TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(-1)/2)), ((1,3),(2,4),(1,2)) ))) + assert TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2)) == \ + expand(uncouple(couple( TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2)), ((1, 3), (2, 4), (1, 2)) ))) + assert TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(-1)/2)) == \ + expand(uncouple(couple( TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(-1)/2)), ((1, 3), (2, 4), (1, 2)) ))) + assert TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(1)/2)) == \ + expand(uncouple(couple( TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(1)/2)), ((1, 3), (2, 4), (1, 2)) ))) + assert TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(-1)/2)) == \ + expand(uncouple(couple( TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(-1)/2)), ((1, 3), (2, 4), (1, 2)) ))) + assert TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2)) == \ + expand(uncouple(couple( TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2)), ((1, 3), (2, 4), (1, 2)) ))) + assert TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(-1)/2)) == \ + expand(uncouple(couple( TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(-1)/2)), ((1, 3), (2, 4), (1, 2)) ))) + assert TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(1)/2)) == \ + expand(uncouple(couple( TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(1)/2)), ((1, 3), (2, 4), (1, 2)) ))) + assert TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(-1)/2)) == \ + expand(uncouple(couple( TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(-1)/2)), ((1, 3), (2, 4), (1, 2)) ))) + assert TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2)) == \ + expand(uncouple(couple( TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2)), ((1, 3), (2, 4), (1, 2)) ))) + assert TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(-1)/2)) == \ + expand(uncouple(couple( TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(-1)/2)), ((1, 3), (2, 4), (1, 2)) ))) + assert TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(1)/2)) == \ + expand(uncouple(couple( TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(1)/2)), ((1, 3), (2, 4), (1, 2)) ))) + assert TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(-1)/2)) == \ + expand(uncouple(couple( TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(-1)/2)), ((1, 3), (2, 4), (1, 2)) ))) + assert TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2)) == \ + expand(uncouple(couple( TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2)), ((1, 3), (2, 4), (1, 2)) ))) + assert TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(-1)/2)) == \ + expand(uncouple(couple( TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(-1)/2)), ((1, 3), (2, 4), (1, 2)) ))) + assert TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(1)/2)) == \ + expand(uncouple(couple( TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(1)/2)), ((1, 3), (2, 4), (1, 2)) ))) + assert TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(-1)/2)) == \ + expand(uncouple(couple( TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(-1)/2)), ((1, 3), (2, 4), (1, 2)) ))) # j1=1/2, j2=1/2, j3=1, j4=1/2 - assert TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,1),JzKet(S(1)/2,S(1)/2)) == \ - expand(uncouple(couple( TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,1), JzKet(S(1)/2,S(1)/2)), ((1,3),(2,4),(1,2)) ))) - assert TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,1),JzKet(S(1)/2,S(-1)/2)) == \ - expand(uncouple(couple( TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,1), JzKet(S(1)/2,S(-1)/2)), ((1,3),(2,4),(1,2)) ))) - assert TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,0),JzKet(S(1)/2,S(1)/2)) == \ - expand(uncouple(couple( TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,0), JzKet(S(1)/2,S(1)/2)), ((1,3),(2,4),(1,2)) ))) - assert TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,0),JzKet(S(1)/2,S(-1)/2)) == \ - expand(uncouple(couple( TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,0), JzKet(S(1)/2,S(-1)/2)), ((1,3),(2,4),(1,2)) ))) - assert TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,-1),JzKet(S(1)/2,S(1)/2)) == \ - expand(uncouple(couple( TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,-1), JzKet(S(1)/2,S(1)/2)), ((1,3),(2,4),(1,2)) ))) - assert TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,-1),JzKet(S(1)/2,S(-1)/2)) == \ - expand(uncouple(couple( TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,-1), JzKet(S(1)/2,S(-1)/2)), ((1,3),(2,4),(1,2)) ))) - assert TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(1,1),JzKet(S(1)/2,S(1)/2)) == \ - expand(uncouple(couple( TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(1,1), JzKet(S(1)/2,S(1)/2)), ((1,3),(2,4),(1,2)) ))) - assert TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(1,1),JzKet(S(1)/2,S(-1)/2)) == \ - expand(uncouple(couple( TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(1,1), JzKet(S(1)/2,S(-1)/2)), ((1,3),(2,4),(1,2)) ))) - assert TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(1,0),JzKet(S(1)/2,S(1)/2)) == \ - expand(uncouple(couple( TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(1,0), JzKet(S(1)/2,S(1)/2)), ((1,3),(2,4),(1,2)) ))) - assert TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(1,0),JzKet(S(1)/2,S(-1)/2)) == \ - expand(uncouple(couple( TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(1,0), JzKet(S(1)/2,S(-1)/2)), ((1,3),(2,4),(1,2)) ))) - assert TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(1,-1),JzKet(S(1)/2,S(1)/2)) == \ - expand(uncouple(couple( TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(1,-1), JzKet(S(1)/2,S(1)/2)), ((1,3),(2,4),(1,2)) ))) - assert TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(1,-1),JzKet(S(1)/2,S(-1)/2)) == \ - expand(uncouple(couple( TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(1,-1), JzKet(S(1)/2,S(-1)/2)), ((1,3),(2,4),(1,2)) ))) - assert TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,1),JzKet(S(1)/2,S(1)/2)) == \ - expand(uncouple(couple( TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,1), JzKet(S(1)/2,S(1)/2)), ((1,3),(2,4),(1,2)) ))) - assert TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,1),JzKet(S(1)/2,S(-1)/2)) == \ - expand(uncouple(couple( TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,1), JzKet(S(1)/2,S(-1)/2)), ((1,3),(2,4),(1,2)) ))) - assert TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,0),JzKet(S(1)/2,S(1)/2)) == \ - expand(uncouple(couple( TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,0), JzKet(S(1)/2,S(1)/2)), ((1,3),(2,4),(1,2)) ))) - assert TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,0),JzKet(S(1)/2,S(-1)/2)) == \ - expand(uncouple(couple( TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,0), JzKet(S(1)/2,S(-1)/2)), ((1,3),(2,4),(1,2)) ))) - assert TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,-1),JzKet(S(1)/2,S(1)/2)) == \ - expand(uncouple(couple( TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,-1), JzKet(S(1)/2,S(1)/2)), ((1,3),(2,4),(1,2)) ))) - assert TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,-1),JzKet(S(1)/2,S(-1)/2)) == \ - expand(uncouple(couple( TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,-1), JzKet(S(1)/2,S(-1)/2)), ((1,3),(2,4),(1,2)) ))) - assert TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(1,1),JzKet(S(1)/2,S(1)/2)) == \ - expand(uncouple(couple( TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(1,1), JzKet(S(1)/2,S(1)/2)), ((1,3),(2,4),(1,2)) ))) - assert TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(1,1),JzKet(S(1)/2,S(-1)/2)) == \ - expand(uncouple(couple( TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(1,1), JzKet(S(1)/2,S(-1)/2)), ((1,3),(2,4),(1,2)) ))) - assert TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(1,0),JzKet(S(1)/2,S(1)/2)) == \ - expand(uncouple(couple( TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(1,0), JzKet(S(1)/2,S(1)/2)), ((1,3),(2,4),(1,2)) ))) - assert TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(1,0),JzKet(S(1)/2,S(-1)/2)) == \ - expand(uncouple(couple( TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(1,0), JzKet(S(1)/2,S(-1)/2)), ((1,3),(2,4),(1,2)) ))) - assert TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(1,-1),JzKet(S(1)/2,S(1)/2)) == \ - expand(uncouple(couple( TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(1,-1), JzKet(S(1)/2,S(1)/2)), ((1,3),(2,4),(1,2)) ))) - assert TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(1,-1),JzKet(S(1)/2,S(-1)/2)) == \ - expand(uncouple(couple( TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(1,-1), JzKet(S(1)/2,S(-1)/2)), ((1,3),(2,4),(1,2)) ))) + assert TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, 1), JzKet(S(1)/2, S(1)/2)) == \ + expand(uncouple(couple( TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, 1), JzKet(S(1)/2, S(1)/2)), ((1, 3), (2, 4), (1, 2)) ))) + assert TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, 1), JzKet(S(1)/2, S(-1)/2)) == \ + expand(uncouple(couple( TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, 1), JzKet(S(1)/2, S(-1)/2)), ((1, 3), (2, 4), (1, 2)) ))) + assert TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, 0), JzKet(S(1)/2, S(1)/2)) == \ + expand(uncouple(couple( TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, 0), JzKet(S(1)/2, S(1)/2)), ((1, 3), (2, 4), (1, 2)) ))) + assert TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, 0), JzKet(S(1)/2, S(-1)/2)) == \ + expand(uncouple(couple( TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, 0), JzKet(S(1)/2, S(-1)/2)), ((1, 3), (2, 4), (1, 2)) ))) + assert TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, -1), JzKet(S(1)/2, S(1)/2)) == \ + expand(uncouple(couple( TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, -1), JzKet(S(1)/2, S(1)/2)), ((1, 3), (2, 4), (1, 2)) ))) + assert TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, -1), JzKet(S(1)/2, S(-1)/2)) == \ + expand(uncouple(couple( TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, -1), JzKet(S(1)/2, S(-1)/2)), ((1, 3), (2, 4), (1, 2)) ))) + assert TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(1, 1), JzKet(S(1)/2, S(1)/2)) == \ + expand(uncouple(couple( TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(1, 1), JzKet(S(1)/2, S(1)/2)), ((1, 3), (2, 4), (1, 2)) ))) + assert TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(1, 1), JzKet(S(1)/2, S(-1)/2)) == \ + expand(uncouple(couple( TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(1, 1), JzKet(S(1)/2, S(-1)/2)), ((1, 3), (2, 4), (1, 2)) ))) + assert TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(1, 0), JzKet(S(1)/2, S(1)/2)) == \ + expand(uncouple(couple( TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(1, 0), JzKet(S(1)/2, S(1)/2)), ((1, 3), (2, 4), (1, 2)) ))) + assert TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(1, 0), JzKet(S(1)/2, S(-1)/2)) == \ + expand(uncouple(couple( TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(1, 0), JzKet(S(1)/2, S(-1)/2)), ((1, 3), (2, 4), (1, 2)) ))) + assert TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(1, -1), JzKet(S(1)/2, S(1)/2)) == \ + expand(uncouple(couple( TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(1, -1), JzKet(S(1)/2, S(1)/2)), ((1, 3), (2, 4), (1, 2)) ))) + assert TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(1, -1), JzKet(S(1)/2, S(-1)/2)) == \ + expand(uncouple(couple( TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(1, -1), JzKet(S(1)/2, S(-1)/2)), ((1, 3), (2, 4), (1, 2)) ))) + assert TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, 1), JzKet(S(1)/2, S(1)/2)) == \ + expand(uncouple(couple( TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, 1), JzKet(S(1)/2, S(1)/2)), ((1, 3), (2, 4), (1, 2)) ))) + assert TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, 1), JzKet(S(1)/2, S(-1)/2)) == \ + expand(uncouple(couple( TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, 1), JzKet(S(1)/2, S(-1)/2)), ((1, 3), (2, 4), (1, 2)) ))) + assert TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, 0), JzKet(S(1)/2, S(1)/2)) == \ + expand(uncouple(couple( TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, 0), JzKet(S(1)/2, S(1)/2)), ((1, 3), (2, 4), (1, 2)) ))) + assert TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, 0), JzKet(S(1)/2, S(-1)/2)) == \ + expand(uncouple(couple( TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, 0), JzKet(S(1)/2, S(-1)/2)), ((1, 3), (2, 4), (1, 2)) ))) + assert TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, -1), JzKet(S(1)/2, S(1)/2)) == \ + expand(uncouple(couple( TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, -1), JzKet(S(1)/2, S(1)/2)), ((1, 3), (2, 4), (1, 2)) ))) + assert TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, -1), JzKet(S(1)/2, S(-1)/2)) == \ + expand(uncouple(couple( TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, -1), JzKet(S(1)/2, S(-1)/2)), ((1, 3), (2, 4), (1, 2)) ))) + assert TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(1, 1), JzKet(S(1)/2, S(1)/2)) == \ + expand(uncouple(couple( TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(1, 1), JzKet(S(1)/2, S(1)/2)), ((1, 3), (2, 4), (1, 2)) ))) + assert TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(1, 1), JzKet(S(1)/2, S(-1)/2)) == \ + expand(uncouple(couple( TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(1, 1), JzKet(S(1)/2, S(-1)/2)), ((1, 3), (2, 4), (1, 2)) ))) + assert TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(1, 0), JzKet(S(1)/2, S(1)/2)) == \ + expand(uncouple(couple( TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(1, 0), JzKet(S(1)/2, S(1)/2)), ((1, 3), (2, 4), (1, 2)) ))) + assert TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(1, 0), JzKet(S(1)/2, S(-1)/2)) == \ + expand(uncouple(couple( TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(1, 0), JzKet(S(1)/2, S(-1)/2)), ((1, 3), (2, 4), (1, 2)) ))) + assert TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(1, -1), JzKet(S(1)/2, S(1)/2)) == \ + expand(uncouple(couple( TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(1, -1), JzKet(S(1)/2, S(1)/2)), ((1, 3), (2, 4), (1, 2)) ))) + assert TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(1, -1), JzKet(S(1)/2, S(-1)/2)) == \ + expand(uncouple(couple( TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(1, -1), JzKet(S(1)/2, S(-1)/2)), ((1, 3), (2, 4), (1, 2)) ))) + def test_uncouple_2_coupled_states_numerical(): # j1=1/2, j2=1/2 - assert uncouple(JzKetCoupled(0, 0, (S(1)/2,S(1)/2))) == \ - sqrt(2)*TensorProduct(JzKet(S(1)/2,S(1)/2),JzKet(S(1)/2,-S(1)/2))/2 - \ - sqrt(2)*TensorProduct(JzKet(S(1)/2,-S(1)/2),JzKet(S(1)/2,S(1)/2))/2 - assert uncouple(JzKetCoupled(1, 1, (S(1)/2,S(1)/2))) == \ - TensorProduct(JzKet(S(1)/2,S(1)/2),JzKet(S(1)/2,S(1)/2)) - assert uncouple(JzKetCoupled(1, 0, (S(1)/2,S(1)/2))) == \ - sqrt(2)*TensorProduct(JzKet(S(1)/2,S(1)/2),JzKet(S(1)/2,-S(1)/2))/2 + \ - sqrt(2)*TensorProduct(JzKet(S(1)/2,-S(1)/2),JzKet(S(1)/2,S(1)/2))/2 - assert uncouple(JzKetCoupled(1, -1, (S(1)/2,S(1)/2))) == \ - TensorProduct(JzKet(S(1)/2,-S(1)/2),JzKet(S(1)/2,-S(1)/2)) + assert uncouple(JzKetCoupled(0, 0, (S(1)/2, S(1)/2))) == \ + sqrt(2)*TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, -S(1)/2))/2 - \ + sqrt(2)*TensorProduct(JzKet(S(1)/2, -S(1)/2), JzKet(S(1)/2, S(1)/2))/2 + assert uncouple(JzKetCoupled(1, 1, (S(1)/2, S(1)/2))) == \ + TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2)) + assert uncouple(JzKetCoupled(1, 0, (S(1)/2, S(1)/2))) == \ + sqrt(2)*TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, -S(1)/2))/2 + \ + sqrt(2)*TensorProduct(JzKet(S(1)/2, -S(1)/2), JzKet(S(1)/2, S(1)/2))/2 + assert uncouple(JzKetCoupled(1, -1, (S(1)/2, S(1)/2))) == \ + TensorProduct(JzKet(S(1)/2, -S(1)/2), JzKet(S(1)/2, -S(1)/2)) # j1=1, j2=1/2 - assert uncouple(JzKetCoupled(S(1)/2, S(1)/2, (1,S(1)/2))) == \ - -sqrt(3)*TensorProduct(JzKet(1,0),JzKet(S(1)/2,S(1)/2))/3 +\ - sqrt(6)*TensorProduct(JzKet(1,1),JzKet(S(1)/2,-S(1)/2))/3 - assert uncouple(JzKetCoupled(S(1)/2, -S(1)/2, (1,S(1)/2))) == \ - sqrt(3)*TensorProduct(JzKet(1,0),JzKet(S(1)/2,-S(1)/2))/3 - \ - sqrt(6)*TensorProduct(JzKet(1,-1),JzKet(S(1)/2,S(1)/2))/3 - assert uncouple(JzKetCoupled(S(3)/2, S(3)/2, (1,S(1)/2))) == \ - TensorProduct(JzKet(1,1),JzKet(S(1)/2,S(1)/2)) - assert uncouple(JzKetCoupled(S(3)/2, S(1)/2, (1,S(1)/2))) == \ - sqrt(3)*TensorProduct(JzKet(1,1),JzKet(S(1)/2,-S(1)/2))/3 + \ - sqrt(6)*TensorProduct(JzKet(1,0),JzKet(S(1)/2,S(1)/2))/3 - assert uncouple(JzKetCoupled(S(3)/2, -S(1)/2, (1,S(1)/2))) == \ - sqrt(6)*TensorProduct(JzKet(1,0),JzKet(S(1)/2,-S(1)/2))/3 + \ - sqrt(3)*TensorProduct(JzKet(1,-1),JzKet(S(1)/2,S(1)/2))/3 - assert uncouple(JzKetCoupled(S(3)/2, -S(3)/2, (1,S(1)/2))) == \ - TensorProduct(JzKet(1,-1),JzKet(S(1)/2,-S(1)/2)) + assert uncouple(JzKetCoupled(S(1)/2, S(1)/2, (1, S(1)/2))) == \ + -sqrt(3)*TensorProduct(JzKet(1, 0), JzKet(S(1)/2, S(1)/2))/3 + \ + sqrt(6)*TensorProduct(JzKet(1, 1), JzKet(S(1)/2, -S(1)/2))/3 + assert uncouple(JzKetCoupled(S(1)/2, -S(1)/2, (1, S(1)/2))) == \ + sqrt(3)*TensorProduct(JzKet(1, 0), JzKet(S(1)/2, -S(1)/2))/3 - \ + sqrt(6)*TensorProduct(JzKet(1, -1), JzKet(S(1)/2, S(1)/2))/3 + assert uncouple(JzKetCoupled(S(3)/2, S(3)/2, (1, S(1)/2))) == \ + TensorProduct(JzKet(1, 1), JzKet(S(1)/2, S(1)/2)) + assert uncouple(JzKetCoupled(S(3)/2, S(1)/2, (1, S(1)/2))) == \ + sqrt(3)*TensorProduct(JzKet(1, 1), JzKet(S(1)/2, -S(1)/2))/3 + \ + sqrt(6)*TensorProduct(JzKet(1, 0), JzKet(S(1)/2, S(1)/2))/3 + assert uncouple(JzKetCoupled(S(3)/2, -S(1)/2, (1, S(1)/2))) == \ + sqrt(6)*TensorProduct(JzKet(1, 0), JzKet(S(1)/2, -S(1)/2))/3 + \ + sqrt(3)*TensorProduct(JzKet(1, -1), JzKet(S(1)/2, S(1)/2))/3 + assert uncouple(JzKetCoupled(S(3)/2, -S(3)/2, (1, S(1)/2))) == \ + TensorProduct(JzKet(1, -1), JzKet(S(1)/2, -S(1)/2)) # j1=1, j2=1 - assert uncouple(JzKetCoupled(0, 0, (1,1))) == \ - sqrt(3)*TensorProduct(JzKet(1,1),JzKet(1,-1))/3 - \ - sqrt(3)*TensorProduct(JzKet(1,0),JzKet(1,0))/3 + \ - sqrt(3)*TensorProduct(JzKet(1,-1),JzKet(1,1))/3 - assert uncouple(JzKetCoupled(1, 1, (1,1))) == \ - sqrt(2)*TensorProduct(JzKet(1,1),JzKet(1,0))/2 - \ - sqrt(2)*TensorProduct(JzKet(1,0),JzKet(1,1))/2 - assert uncouple(JzKetCoupled(1, 0, (1,1))) == \ - sqrt(2)*TensorProduct(JzKet(1,1),JzKet(1,-1))/2 - \ - sqrt(2)*TensorProduct(JzKet(1,-1),JzKet(1,1))/2 - assert uncouple(JzKetCoupled(1, -1, (1,1))) == \ - sqrt(2)*TensorProduct(JzKet(1,0),JzKet(1,-1))/2 - \ - sqrt(2)*TensorProduct(JzKet(1,-1),JzKet(1,0))/2 - assert uncouple(JzKetCoupled(2, 2, (1,1))) == \ - TensorProduct(JzKet(1,1),JzKet(1,1)) - assert uncouple(JzKetCoupled(2, 1, (1,1))) == \ - sqrt(2)*TensorProduct(JzKet(1,1),JzKet(1,0))/2 + \ - sqrt(2)*TensorProduct(JzKet(1,0),JzKet(1,1))/2 - assert uncouple(JzKetCoupled(2, 0, (1,1))) == \ - sqrt(6)*TensorProduct(JzKet(1,1),JzKet(1,-1))/6 + \ - sqrt(6)*TensorProduct(JzKet(1,0),JzKet(1,0))/3 + \ - sqrt(6)*TensorProduct(JzKet(1,-1),JzKet(1,1))/6 - assert uncouple(JzKetCoupled(2, -1, (1,1))) == \ - sqrt(2)*TensorProduct(JzKet(1,0),JzKet(1,-1))/2 + \ - sqrt(2)*TensorProduct(JzKet(1,-1),JzKet(1,0))/2 - assert uncouple(JzKetCoupled(2, -2, (1,1))) == \ - TensorProduct(JzKet(1,-1),JzKet(1,-1)) + assert uncouple(JzKetCoupled(0, 0, (1, 1))) == \ + sqrt(3)*TensorProduct(JzKet(1, 1), JzKet(1, -1))/3 - \ + sqrt(3)*TensorProduct(JzKet(1, 0), JzKet(1, 0))/3 + \ + sqrt(3)*TensorProduct(JzKet(1, -1), JzKet(1, 1))/3 + assert uncouple(JzKetCoupled(1, 1, (1, 1))) == \ + sqrt(2)*TensorProduct(JzKet(1, 1), JzKet(1, 0))/2 - \ + sqrt(2)*TensorProduct(JzKet(1, 0), JzKet(1, 1))/2 + assert uncouple(JzKetCoupled(1, 0, (1, 1))) == \ + sqrt(2)*TensorProduct(JzKet(1, 1), JzKet(1, -1))/2 - \ + sqrt(2)*TensorProduct(JzKet(1, -1), JzKet(1, 1))/2 + assert uncouple(JzKetCoupled(1, -1, (1, 1))) == \ + sqrt(2)*TensorProduct(JzKet(1, 0), JzKet(1, -1))/2 - \ + sqrt(2)*TensorProduct(JzKet(1, -1), JzKet(1, 0))/2 + assert uncouple(JzKetCoupled(2, 2, (1, 1))) == \ + TensorProduct(JzKet(1, 1), JzKet(1, 1)) + assert uncouple(JzKetCoupled(2, 1, (1, 1))) == \ + sqrt(2)*TensorProduct(JzKet(1, 1), JzKet(1, 0))/2 + \ + sqrt(2)*TensorProduct(JzKet(1, 0), JzKet(1, 1))/2 + assert uncouple(JzKetCoupled(2, 0, (1, 1))) == \ + sqrt(6)*TensorProduct(JzKet(1, 1), JzKet(1, -1))/6 + \ + sqrt(6)*TensorProduct(JzKet(1, 0), JzKet(1, 0))/3 + \ + sqrt(6)*TensorProduct(JzKet(1, -1), JzKet(1, 1))/6 + assert uncouple(JzKetCoupled(2, -1, (1, 1))) == \ + sqrt(2)*TensorProduct(JzKet(1, 0), JzKet(1, -1))/2 + \ + sqrt(2)*TensorProduct(JzKet(1, -1), JzKet(1, 0))/2 + assert uncouple(JzKetCoupled(2, -2, (1, 1))) == \ + TensorProduct(JzKet(1, -1), JzKet(1, -1)) + def test_uncouple_3_coupled_states_numerical(): # Default coupling # j1=1/2, j2=1/2, j3=1/2 - assert uncouple(JzKetCoupled(S(3)/2, S(3)/2, (S(1)/2,S(1)/2,S(1)/2))) == \ - TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2)) - assert uncouple(JzKetCoupled(S(3)/2, S(1)/2, (S(1)/2,S(1)/2,S(1)/2))) == \ - sqrt(3)*TensorProduct(JzKet(S(1)/2,-S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2))/3 + \ - sqrt(3)*TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,-S(1)/2), JzKet(S(1)/2,S(1)/2))/3 + \ - sqrt(3)*TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,-S(1)/2))/3 - assert uncouple(JzKetCoupled(S(3)/2, -S(1)/2, (S(1)/2,S(1)/2,S(1)/2))) == \ - sqrt(3)*TensorProduct(JzKet(S(1)/2,-S(1)/2), JzKet(S(1)/2,-S(1)/2), JzKet(S(1)/2,S(1)/2))/3 + \ - sqrt(3)*TensorProduct(JzKet(S(1)/2,-S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,-S(1)/2))/3 + \ - sqrt(3)*TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,-S(1)/2), JzKet(S(1)/2,-S(1)/2))/3 - assert uncouple(JzKetCoupled(S(3)/2, -S(3)/2, (S(1)/2,S(1)/2,S(1)/2))) == \ - TensorProduct(JzKet(S(1)/2,-S(1)/2), JzKet(S(1)/2,-S(1)/2), JzKet(S(1)/2,-S(1)/2)) + assert uncouple(JzKetCoupled(S(3)/2, S(3)/2, (S(1)/2, S(1)/2, S(1)/2))) == \ + TensorProduct(JzKet( + S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2)) + assert uncouple(JzKetCoupled(S(3)/2, S(1)/2, (S(1)/2, S(1)/2, S(1)/2))) == \ + sqrt(3)*TensorProduct(JzKet(S(1)/2, -S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2))/3 + \ + sqrt(3)*TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, -S(1)/2), JzKet(S(1)/2, S(1)/2))/3 + \ + sqrt(3)*TensorProduct(JzKet( + S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, -S(1)/2))/3 + assert uncouple(JzKetCoupled(S(3)/2, -S(1)/2, (S(1)/2, S(1)/2, S(1)/2))) == \ + sqrt(3)*TensorProduct(JzKet(S(1)/2, -S(1)/2), JzKet(S(1)/2, -S(1)/2), JzKet(S(1)/2, S(1)/2))/3 + \ + sqrt(3)*TensorProduct(JzKet(S(1)/2, -S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, -S(1)/2))/3 + \ + sqrt(3)*TensorProduct(JzKet( + S(1)/2, S(1)/2), JzKet(S(1)/2, -S(1)/2), JzKet(S(1)/2, -S(1)/2))/3 + assert uncouple(JzKetCoupled(S(3)/2, -S(3)/2, (S(1)/2, S(1)/2, S(1)/2))) == \ + TensorProduct(JzKet( + S(1)/2, -S(1)/2), JzKet(S(1)/2, -S(1)/2), JzKet(S(1)/2, -S(1)/2)) # j1=1/2, j2=1/2, j3=1 assert uncouple(JzKetCoupled(2, 2, (S(1)/2, S(1)/2, 1))) == \ - TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,1)) + TensorProduct( + JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, 1)) assert uncouple(JzKetCoupled(2, 1, (S(1)/2, S(1)/2, 1))) == \ - TensorProduct(JzKet(S(1)/2,-S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,1))/2 + \ - TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,-S(1)/2), JzKet(1,1))/2 + \ - sqrt(2)*TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,0))/2 + TensorProduct(JzKet(S(1)/2, -S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, 1))/2 + \ + TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, -S(1)/2), JzKet(1, 1))/2 + \ + sqrt(2)*TensorProduct( + JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, 0))/2 assert uncouple(JzKetCoupled(2, 0, (S(1)/2, S(1)/2, 1))) == \ - sqrt(6)*TensorProduct(JzKet(S(1)/2,-S(1)/2), JzKet(S(1)/2,-S(1)/2), JzKet(1,1))/6 + \ - sqrt(3)*TensorProduct(JzKet(S(1)/2,-S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,0))/3 + \ - sqrt(3)*TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,-S(1)/2), JzKet(1,0))/3 + \ - sqrt(6)*TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,-1))/6 + sqrt(6)*TensorProduct(JzKet(S(1)/2, -S(1)/2), JzKet(S(1)/2, -S(1)/2), JzKet(1, 1))/6 + \ + sqrt(3)*TensorProduct(JzKet(S(1)/2, -S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, 0))/3 + \ + sqrt(3)*TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, -S(1)/2), JzKet(1, 0))/3 + \ + sqrt(6)*TensorProduct( + JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, -1))/6 assert uncouple(JzKetCoupled(2, -1, (S(1)/2, S(1)/2, 1))) == \ - sqrt(2)*TensorProduct(JzKet(S(1)/2,-S(1)/2), JzKet(S(1)/2,-S(1)/2), JzKet(1,0))/2 + \ - TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,-S(1)/2), JzKet(1,-1))/2 + \ - TensorProduct(JzKet(S(1)/2,-S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,-1))/2 + sqrt(2)*TensorProduct(JzKet(S(1)/2, -S(1)/2), JzKet(S(1)/2, -S(1)/2), JzKet(1, 0))/2 + \ + TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, -S(1)/2), JzKet(1, -1))/2 + \ + TensorProduct( + JzKet(S(1)/2, -S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, -1))/2 assert uncouple(JzKetCoupled(2, -2, (S(1)/2, S(1)/2, 1))) == \ - TensorProduct(JzKet(S(1)/2,-S(1)/2), JzKet(S(1)/2,-S(1)/2), JzKet(1,-1)) + TensorProduct( + JzKet(S(1)/2, -S(1)/2), JzKet(S(1)/2, -S(1)/2), JzKet(1, -1)) assert uncouple(JzKetCoupled(1, 1, (S(1)/2, S(1)/2, 1))) == \ - -TensorProduct(JzKet(S(1)/2,-S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,1))/2 - \ - TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,-S(1)/2), JzKet(1,1))/2 + \ - sqrt(2)*TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,0))/2 + -TensorProduct(JzKet(S(1)/2, -S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, 1))/2 - \ + TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, -S(1)/2), JzKet(1, 1))/2 + \ + sqrt(2)*TensorProduct( + JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, 0))/2 assert uncouple(JzKetCoupled(1, 0, (S(1)/2, S(1)/2, 1))) == \ - -sqrt(2)*TensorProduct(JzKet(S(1)/2,-S(1)/2), JzKet(S(1)/2,-S(1)/2), JzKet(1,1))/2 + \ - sqrt(2)*TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,-1))/2 + -sqrt(2)*TensorProduct(JzKet(S(1)/2, -S(1)/2), JzKet(S(1)/2, -S(1)/2), JzKet(1, 1))/2 + \ + sqrt(2)*TensorProduct( + JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, -1))/2 assert uncouple(JzKetCoupled(1, -1, (S(1)/2, S(1)/2, 1))) == \ - -sqrt(2)*TensorProduct(JzKet(S(1)/2, -S(1)/2), JzKet(S(1)/2,-S(1)/2), JzKet(1,0))/2 + \ - TensorProduct(JzKet(S(1)/2,-S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,-1))/2 + \ - TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,-S(1)/2), JzKet(1,-1))/2 + -sqrt(2)*TensorProduct(JzKet(S(1)/2, -S(1)/2), JzKet(S(1)/2, -S(1)/2), JzKet(1, 0))/2 + \ + TensorProduct(JzKet(S(1)/2, -S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, -1))/2 + \ + TensorProduct( + JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, -S(1)/2), JzKet(1, -1))/2 # j1=1/2, j2=1, j3=1 assert uncouple(JzKetCoupled(S(5)/2, S(5)/2, (S(1)/2, 1, 1))) == \ - TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(1,1), JzKet(1,1)) + TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(1, 1), JzKet(1, 1)) assert uncouple(JzKetCoupled(S(5)/2, S(3)/2, (S(1)/2, 1, 1))) == \ - sqrt(5)*TensorProduct(JzKet(S(1)/2,-S(1)/2), JzKet(1,1), JzKet(1,1))/5 + \ - sqrt(10)*TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(1,0), JzKet(1,1))/5 + \ - sqrt(10)*TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(1,1), JzKet(1,0))/5 + sqrt(5)*TensorProduct(JzKet(S(1)/2, -S(1)/2), JzKet(1, 1), JzKet(1, 1))/5 + \ + sqrt(10)*TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(1, 0), JzKet(1, 1))/5 + \ + sqrt(10)*TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(1, 1), + JzKet(1, 0))/5 assert uncouple(JzKetCoupled(S(5)/2, S(1)/2, (S(1)/2, 1, 1))) == \ - sqrt(5)*TensorProduct(JzKet(S(1)/2,-S(1)/2), JzKet(1,0), JzKet(1,1))/5 + \ - sqrt(5)*TensorProduct(JzKet(S(1)/2,-S(1)/2), JzKet(1,1), JzKet(1,0))/5 + \ - sqrt(10)*TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(1,-1), JzKet(1,1))/10 + \ - sqrt(10)*TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(1,0), JzKet(1,0))/5 + \ - sqrt(10)*TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(1,1), JzKet(1,-1))/10 + sqrt(5)*TensorProduct(JzKet(S(1)/2, -S(1)/2), JzKet(1, 0), JzKet(1, 1))/5 + \ + sqrt(5)*TensorProduct(JzKet(S(1)/2, -S(1)/2), JzKet(1, 1), JzKet(1, 0))/5 + \ + sqrt(10)*TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(1, -1), JzKet(1, 1))/10 + \ + sqrt(10)*TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(1, 0), JzKet(1, 0))/5 + \ + sqrt(10)*TensorProduct( + JzKet(S(1)/2, S(1)/2), JzKet(1, 1), JzKet(1, -1))/10 assert uncouple(JzKetCoupled(S(5)/2, -S(1)/2, (S(1)/2, 1, 1))) == \ - sqrt(10)*TensorProduct(JzKet(S(1)/2,-S(1)/2), JzKet(1,-1), JzKet(1,1))/10 + \ - sqrt(10)*TensorProduct(JzKet(S(1)/2,-S(1)/2), JzKet(1,0), JzKet(1,0))/5 + \ - sqrt(10)*TensorProduct(JzKet(S(1)/2,-S(1)/2), JzKet(1,1), JzKet(1,-1))/10 + \ - sqrt(5)*TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(1,-1), JzKet(1,0))/5 + \ - sqrt(5)*TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(1,0), JzKet(1,-1))/5 + sqrt(10)*TensorProduct(JzKet(S(1)/2, -S(1)/2), JzKet(1, -1), JzKet(1, 1))/10 + \ + sqrt(10)*TensorProduct(JzKet(S(1)/2, -S(1)/2), JzKet(1, 0), JzKet(1, 0))/5 + \ + sqrt(10)*TensorProduct(JzKet(S(1)/2, -S(1)/2), JzKet(1, 1), JzKet(1, -1))/10 + \ + sqrt(5)*TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(1, -1), JzKet(1, 0))/5 + \ + sqrt(5)*TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(1, 0), + JzKet(1, -1))/5 assert uncouple(JzKetCoupled(S(5)/2, -S(3)/2, (S(1)/2, 1, 1))) == \ - sqrt(10)*TensorProduct(JzKet(S(1)/2,-S(1)/2), JzKet(1,-1), JzKet(1,0))/5 + \ - sqrt(10)*TensorProduct(JzKet(S(1)/2,-S(1)/2), JzKet(1,0), JzKet(1,-1))/5 + \ - sqrt(5)*TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(1,-1), JzKet(1,-1))/5 + sqrt(10)*TensorProduct(JzKet(S(1)/2, -S(1)/2), JzKet(1, -1), JzKet(1, 0))/5 + \ + sqrt(10)*TensorProduct(JzKet(S(1)/2, -S(1)/2), JzKet(1, 0), JzKet(1, -1))/5 + \ + sqrt(5)*TensorProduct( + JzKet(S(1)/2, S(1)/2), JzKet(1, -1), JzKet(1, -1))/5 assert uncouple(JzKetCoupled(S(5)/2, -S(5)/2, (S(1)/2, 1, 1))) == \ - TensorProduct(JzKet(S(1)/2,-S(1)/2), JzKet(1,-1), JzKet(1,-1)) + TensorProduct(JzKet(S(1)/2, -S(1)/2), JzKet(1, -1), JzKet(1, -1)) assert uncouple(JzKetCoupled(S(3)/2, S(3)/2, (S(1)/2, 1, 1))) == \ - -sqrt(30)*TensorProduct(JzKet(S(1)/2,-S(1)/2), JzKet(1,1), JzKet(1,1))/15 - \ - 2*sqrt(15)*TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(1,0), JzKet(1,1))/15 + \ - sqrt(15)*TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(1,1), JzKet(1,0))/5 + -sqrt(30)*TensorProduct(JzKet(S(1)/2, -S(1)/2), JzKet(1, 1), JzKet(1, 1))/15 - \ + 2*sqrt(15)*TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(1, 0), JzKet(1, 1))/15 + \ + sqrt(15)*TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(1, 1), + JzKet(1, 0))/5 assert uncouple(JzKetCoupled(S(3)/2, S(1)/2, (S(1)/2, 1, 1))) == \ - -4*sqrt(5)*TensorProduct(JzKet(S(1)/2,-S(1)/2), JzKet(1,0), JzKet(1,1))/15 + \ - sqrt(5)*TensorProduct(JzKet(S(1)/2,-S(1)/2), JzKet(1,1), JzKet(1,0))/15 - \ - 2*sqrt(10)*TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(1,-1), JzKet(1,1))/15 + \ - sqrt(10)*TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(1,0), JzKet(1,0))/15 + \ - sqrt(10)*TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(1,1), JzKet(1,-1))/5 + -4*sqrt(5)*TensorProduct(JzKet(S(1)/2, -S(1)/2), JzKet(1, 0), JzKet(1, 1))/15 + \ + sqrt(5)*TensorProduct(JzKet(S(1)/2, -S(1)/2), JzKet(1, 1), JzKet(1, 0))/15 - \ + 2*sqrt(10)*TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(1, -1), JzKet(1, 1))/15 + \ + sqrt(10)*TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(1, 0), JzKet(1, 0))/15 + \ + sqrt(10)*TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(1, 1), + JzKet(1, -1))/5 assert uncouple(JzKetCoupled(S(3)/2, -S(1)/2, (S(1)/2, 1, 1))) == \ - -sqrt(10)*TensorProduct(JzKet(S(1)/2,-S(1)/2), JzKet(1,-1), JzKet(1,1))/5 - \ - sqrt(10)*TensorProduct(JzKet(S(1)/2,-S(1)/2), JzKet(1,0), JzKet(1,0))/15 + \ - 2*sqrt(10)*TensorProduct(JzKet(S(1)/2,-S(1)/2), JzKet(1,1), JzKet(1,-1))/15 - \ - sqrt(5)*TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(1,-1), JzKet(1,0))/15 + \ - 4*sqrt(5)*TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(1,0), JzKet(1,-1))/15 + -sqrt(10)*TensorProduct(JzKet(S(1)/2, -S(1)/2), JzKet(1, -1), JzKet(1, 1))/5 - \ + sqrt(10)*TensorProduct(JzKet(S(1)/2, -S(1)/2), JzKet(1, 0), JzKet(1, 0))/15 + \ + 2*sqrt(10)*TensorProduct(JzKet(S(1)/2, -S(1)/2), JzKet(1, 1), JzKet(1, -1))/15 - \ + sqrt(5)*TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(1, -1), JzKet(1, 0))/15 + \ + 4*sqrt(5)*TensorProduct( + JzKet(S(1)/2, S(1)/2), JzKet(1, 0), JzKet(1, -1))/15 assert uncouple(JzKetCoupled(S(3)/2, -S(3)/2, (S(1)/2, 1, 1))) == \ - -sqrt(15)*TensorProduct(JzKet(S(1)/2,-S(1)/2), JzKet(1,-1), JzKet(1,0))/5 + \ - 2*sqrt(15)*TensorProduct(JzKet(S(1)/2,-S(1)/2), JzKet(1,0), JzKet(1,-1))/15 + \ - sqrt(30)*TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(1,-1), JzKet(1,-1))/15 + -sqrt(15)*TensorProduct(JzKet(S(1)/2, -S(1)/2), JzKet(1, -1), JzKet(1, 0))/5 + \ + 2*sqrt(15)*TensorProduct(JzKet(S(1)/2, -S(1)/2), JzKet(1, 0), JzKet(1, -1))/15 + \ + sqrt(30)*TensorProduct( + JzKet(S(1)/2, S(1)/2), JzKet(1, -1), JzKet(1, -1))/15 assert uncouple(JzKetCoupled(S(1)/2, S(1)/2, (S(1)/2, 1, 1))) == \ - TensorProduct(JzKet(S(1)/2,-S(1)/2), JzKet(1,0), JzKet(1,1))/3 - \ - TensorProduct(JzKet(S(1)/2,-S(1)/2), JzKet(1,1), JzKet(1,0))/3 + \ - sqrt(2)*TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(1,-1), JzKet(1,1))/6 - \ - sqrt(2)*TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(1,0), JzKet(1,0))/3 + \ - sqrt(2)*TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(1,1), JzKet(1,-1))/2 + TensorProduct(JzKet(S(1)/2, -S(1)/2), JzKet(1, 0), JzKet(1, 1))/3 - \ + TensorProduct(JzKet(S(1)/2, -S(1)/2), JzKet(1, 1), JzKet(1, 0))/3 + \ + sqrt(2)*TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(1, -1), JzKet(1, 1))/6 - \ + sqrt(2)*TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(1, 0), JzKet(1, 0))/3 + \ + sqrt(2)*TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(1, 1), + JzKet(1, -1))/2 assert uncouple(JzKetCoupled(S(1)/2, -S(1)/2, (S(1)/2, 1, 1))) == \ - sqrt(2)*TensorProduct(JzKet(S(1)/2,-S(1)/2), JzKet(1,-1), JzKet(1,1))/2 - \ - sqrt(2)*TensorProduct(JzKet(S(1)/2,-S(1)/2), JzKet(1,0), JzKet(1,0))/3 + \ - sqrt(2)*TensorProduct(JzKet(S(1)/2,-S(1)/2), JzKet(1,1), JzKet(1,-1))/6 - \ - TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(1,-1), JzKet(1,0))/3 + \ - TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(1,0), JzKet(1,-1))/3 + sqrt(2)*TensorProduct(JzKet(S(1)/2, -S(1)/2), JzKet(1, -1), JzKet(1, 1))/2 - \ + sqrt(2)*TensorProduct(JzKet(S(1)/2, -S(1)/2), JzKet(1, 0), JzKet(1, 0))/3 + \ + sqrt(2)*TensorProduct(JzKet(S(1)/2, -S(1)/2), JzKet(1, 1), JzKet(1, -1))/6 - \ + TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(1, -1), JzKet(1, 0))/3 + \ + TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(1, 0), JzKet(1, -1))/3 # j1=1, j2=1, j3=1 - assert uncouple(JzKetCoupled(3, 3, (1,1,1))) == \ - TensorProduct(JzKet(1,1), JzKet(1,1), JzKet(1,1)) - assert uncouple(JzKetCoupled(3, 2, (1,1,1))) == \ - sqrt(3)*TensorProduct(JzKet(1,0), JzKet(1,1), JzKet(1,1))/3 + \ - sqrt(3)*TensorProduct(JzKet(1,1), JzKet(1,0), JzKet(1,1))/3 + \ - sqrt(3)*TensorProduct(JzKet(1,1), JzKet(1,1), JzKet(1,0))/3 - assert uncouple(JzKetCoupled(3, 1, (1,1,1))) == \ - sqrt(15)*TensorProduct(JzKet(1,-1), JzKet(1,1), JzKet(1,1))/15 + \ - 2*sqrt(15)*TensorProduct(JzKet(1,0), JzKet(1,0), JzKet(1,1))/15 + \ - 2*sqrt(15)*TensorProduct(JzKet(1,0), JzKet(1,1), JzKet(1,0))/15 + \ - sqrt(15)*TensorProduct(JzKet(1,1), JzKet(1,-1), JzKet(1,1))/15 + \ - 2*sqrt(15)*TensorProduct(JzKet(1,1), JzKet(1,0), JzKet(1,0))/15 + \ - sqrt(15)*TensorProduct(JzKet(1,1), JzKet(1,1), JzKet(1,-1))/15 - assert uncouple(JzKetCoupled(3, 0, (1,1,1))) == \ - sqrt(10)*TensorProduct(JzKet(1,-1), JzKet(1,0), JzKet(1,1))/10 + \ - sqrt(10)*TensorProduct(JzKet(1,-1), JzKet(1,1), JzKet(1,0))/10 + \ - sqrt(10)*TensorProduct(JzKet(1,0), JzKet(1,-1), JzKet(1,1))/10 + \ - sqrt(10)*TensorProduct(JzKet(1,0), JzKet(1,0), JzKet(1,0))/5 + \ - sqrt(10)*TensorProduct(JzKet(1,0), JzKet(1,1), JzKet(1,-1))/10 + \ - sqrt(10)*TensorProduct(JzKet(1,1), JzKet(1,-1), JzKet(1,0))/10 + \ - sqrt(10)*TensorProduct(JzKet(1,1), JzKet(1,0), JzKet(1,-1))/10 - assert uncouple(JzKetCoupled(3, -1, (1,1,1))) == \ - sqrt(15)*TensorProduct(JzKet(1,-1), JzKet(1,-1), JzKet(1,1))/15 + \ - 2*sqrt(15)*TensorProduct(JzKet(1,-1), JzKet(1,0), JzKet(1,0))/15 + \ - sqrt(15)*TensorProduct(JzKet(1,-1), JzKet(1,1), JzKet(1,-1))/15 + \ - 2*sqrt(15)*TensorProduct(JzKet(1,0), JzKet(1,-1), JzKet(1,0))/15 + \ - 2*sqrt(15)*TensorProduct(JzKet(1,0), JzKet(1,0), JzKet(1,-1))/15 + \ - sqrt(15)*TensorProduct(JzKet(1,1), JzKet(1,-1), JzKet(1,-1))/15 - assert uncouple(JzKetCoupled(3, -2, (1,1,1))) == \ - sqrt(3)*TensorProduct(JzKet(1,-1), JzKet(1,-1), JzKet(1,0))/3 + \ - sqrt(3)*TensorProduct(JzKet(1,-1), JzKet(1,0), JzKet(1,-1))/3 + \ - sqrt(3)*TensorProduct(JzKet(1,0), JzKet(1,-1), JzKet(1,-1))/3 - assert uncouple(JzKetCoupled(3, -3, (1,1,1))) == \ - TensorProduct(JzKet(1,-1), JzKet(1,-1), JzKet(1,-1)) - assert uncouple(JzKetCoupled(2, 2, (1,1,1))) == \ - -sqrt(6)*TensorProduct(JzKet(1,0), JzKet(1,1), JzKet(1,1))/6 - \ - sqrt(6)*TensorProduct(JzKet(1,1), JzKet(1,0), JzKet(1,1))/6 + \ - sqrt(6)*TensorProduct(JzKet(1,1), JzKet(1,1), JzKet(1,0))/3 - assert uncouple(JzKetCoupled(2, 1, (1,1,1))) == \ - -sqrt(3)*TensorProduct(JzKet(1,-1), JzKet(1,1), JzKet(1,1))/6 - \ - sqrt(3)*TensorProduct(JzKet(1,0), JzKet(1,0), JzKet(1,1))/3 + \ - sqrt(3)*TensorProduct(JzKet(1,0), JzKet(1,1), JzKet(1,0))/6 - \ - sqrt(3)*TensorProduct(JzKet(1,1), JzKet(1,-1), JzKet(1,1))/6 + \ - sqrt(3)*TensorProduct(JzKet(1,1), JzKet(1,0), JzKet(1,0))/6 + \ - sqrt(3)*TensorProduct(JzKet(1,1), JzKet(1,1), JzKet(1,-1))/3 - assert uncouple(JzKetCoupled(2, 0, (1,1,1))) == \ - -TensorProduct(JzKet(1,-1), JzKet(1,0), JzKet(1,1))/2 - \ - TensorProduct(JzKet(1,0), JzKet(1,-1), JzKet(1,1))/2 + \ - TensorProduct(JzKet(1,0), JzKet(1,1), JzKet(1,-1))/2 + \ - TensorProduct(JzKet(1,1), JzKet(1,0), JzKet(1,-1))/2 - assert uncouple(JzKetCoupled(2, -1, (1,1,1))) == \ - -sqrt(3)*TensorProduct(JzKet(1,-1), JzKet(1,-1), JzKet(1,1))/3 - \ - sqrt(3)*TensorProduct(JzKet(1,-1), JzKet(1,0), JzKet(1,0))/6 + \ - sqrt(3)*TensorProduct(JzKet(1,-1), JzKet(1,1), JzKet(1,-1))/6 - \ - sqrt(3)*TensorProduct(JzKet(1,0), JzKet(1,-1), JzKet(1,0))/6 + \ - sqrt(3)*TensorProduct(JzKet(1,0), JzKet(1,0), JzKet(1,-1))/3 + \ - sqrt(3)*TensorProduct(JzKet(1,1), JzKet(1,-1), JzKet(1,-1))/6 - assert uncouple(JzKetCoupled(2, -2, (1,1,1))) == \ - -sqrt(6)*TensorProduct(JzKet(1,-1), JzKet(1,-1), JzKet(1,0))/3 + \ - sqrt(6)*TensorProduct(JzKet(1,-1), JzKet(1,0), JzKet(1,-1))/6 + \ - sqrt(6)*TensorProduct(JzKet(1,0), JzKet(1,-1), JzKet(1,-1))/6 - assert uncouple(JzKetCoupled(1, 1, (1,1,1))) == \ - sqrt(15)*TensorProduct(JzKet(1,-1), JzKet(1,1), JzKet(1,1))/30 + \ - sqrt(15)*TensorProduct(JzKet(1,0), JzKet(1,0), JzKet(1,1))/15 - \ - sqrt(15)*TensorProduct(JzKet(1,0), JzKet(1,1), JzKet(1,0))/10 + \ - sqrt(15)*TensorProduct(JzKet(1,1), JzKet(1,-1), JzKet(1,1))/30 - \ - sqrt(15)*TensorProduct(JzKet(1,1), JzKet(1,0), JzKet(1,0))/10 + \ - sqrt(15)*TensorProduct(JzKet(1,1), JzKet(1,1), JzKet(1,-1))/5 - assert uncouple(JzKetCoupled(1, 0, (1,1,1))) == \ - sqrt(15)*TensorProduct(JzKet(1,-1), JzKet(1,0), JzKet(1,1))/10 - \ - sqrt(15)*TensorProduct(JzKet(1,-1), JzKet(1,1), JzKet(1,0))/15 + \ - sqrt(15)*TensorProduct(JzKet(1,0), JzKet(1,-1), JzKet(1,1))/10 - \ - 2*sqrt(15)*TensorProduct(JzKet(1,0), JzKet(1,0), JzKet(1,0))/15 + \ - sqrt(15)*TensorProduct(JzKet(1,0), JzKet(1,1), JzKet(1,-1))/10 - \ - sqrt(15)*TensorProduct(JzKet(1,1), JzKet(1,-1), JzKet(1,0))/15 + \ - sqrt(15)*TensorProduct(JzKet(1,1), JzKet(1,0), JzKet(1,-1))/10 - assert uncouple(JzKetCoupled(1, -1, (1,1,1))) == \ - sqrt(15)*TensorProduct(JzKet(1,-1), JzKet(1,-1), JzKet(1,1))/5 - \ - sqrt(15)*TensorProduct(JzKet(1,-1), JzKet(1,0), JzKet(1,0))/10 + \ - sqrt(15)*TensorProduct(JzKet(1,-1), JzKet(1,1), JzKet(1,-1))/30 - \ - sqrt(15)*TensorProduct(JzKet(1,0), JzKet(1,-1), JzKet(1,0))/10 + \ - sqrt(15)*TensorProduct(JzKet(1,0), JzKet(1,0), JzKet(1,-1))/15 + \ - sqrt(15)*TensorProduct(JzKet(1,1), JzKet(1,-1), JzKet(1,-1))/30 + assert uncouple(JzKetCoupled(3, 3, (1, 1, 1))) == \ + TensorProduct(JzKet(1, 1), JzKet(1, 1), JzKet(1, 1)) + assert uncouple(JzKetCoupled(3, 2, (1, 1, 1))) == \ + sqrt(3)*TensorProduct(JzKet(1, 0), JzKet(1, 1), JzKet(1, 1))/3 + \ + sqrt(3)*TensorProduct(JzKet(1, 1), JzKet(1, 0), JzKet(1, 1))/3 + \ + sqrt(3)*TensorProduct(JzKet(1, 1), JzKet(1, 1), JzKet(1, 0))/3 + assert uncouple(JzKetCoupled(3, 1, (1, 1, 1))) == \ + sqrt(15)*TensorProduct(JzKet(1, -1), JzKet(1, 1), JzKet(1, 1))/15 + \ + 2*sqrt(15)*TensorProduct(JzKet(1, 0), JzKet(1, 0), JzKet(1, 1))/15 + \ + 2*sqrt(15)*TensorProduct(JzKet(1, 0), JzKet(1, 1), JzKet(1, 0))/15 + \ + sqrt(15)*TensorProduct(JzKet(1, 1), JzKet(1, -1), JzKet(1, 1))/15 + \ + 2*sqrt(15)*TensorProduct(JzKet(1, 1), JzKet(1, 0), JzKet(1, 0))/15 + \ + sqrt(15)*TensorProduct(JzKet(1, 1), JzKet(1, 1), JzKet(1, -1))/15 + assert uncouple(JzKetCoupled(3, 0, (1, 1, 1))) == \ + sqrt(10)*TensorProduct(JzKet(1, -1), JzKet(1, 0), JzKet(1, 1))/10 + \ + sqrt(10)*TensorProduct(JzKet(1, -1), JzKet(1, 1), JzKet(1, 0))/10 + \ + sqrt(10)*TensorProduct(JzKet(1, 0), JzKet(1, -1), JzKet(1, 1))/10 + \ + sqrt(10)*TensorProduct(JzKet(1, 0), JzKet(1, 0), JzKet(1, 0))/5 + \ + sqrt(10)*TensorProduct(JzKet(1, 0), JzKet(1, 1), JzKet(1, -1))/10 + \ + sqrt(10)*TensorProduct(JzKet(1, 1), JzKet(1, -1), JzKet(1, 0))/10 + \ + sqrt(10)*TensorProduct(JzKet(1, 1), JzKet(1, 0), JzKet(1, -1))/10 + assert uncouple(JzKetCoupled(3, -1, (1, 1, 1))) == \ + sqrt(15)*TensorProduct(JzKet(1, -1), JzKet(1, -1), JzKet(1, 1))/15 + \ + 2*sqrt(15)*TensorProduct(JzKet(1, -1), JzKet(1, 0), JzKet(1, 0))/15 + \ + sqrt(15)*TensorProduct(JzKet(1, -1), JzKet(1, 1), JzKet(1, -1))/15 + \ + 2*sqrt(15)*TensorProduct(JzKet(1, 0), JzKet(1, -1), JzKet(1, 0))/15 + \ + 2*sqrt(15)*TensorProduct(JzKet(1, 0), JzKet(1, 0), JzKet(1, -1))/15 + \ + sqrt(15)*TensorProduct(JzKet(1, 1), JzKet(1, -1), JzKet(1, -1))/15 + assert uncouple(JzKetCoupled(3, -2, (1, 1, 1))) == \ + sqrt(3)*TensorProduct(JzKet(1, -1), JzKet(1, -1), JzKet(1, 0))/3 + \ + sqrt(3)*TensorProduct(JzKet(1, -1), JzKet(1, 0), JzKet(1, -1))/3 + \ + sqrt(3)*TensorProduct(JzKet(1, 0), JzKet(1, -1), JzKet(1, -1))/3 + assert uncouple(JzKetCoupled(3, -3, (1, 1, 1))) == \ + TensorProduct(JzKet(1, -1), JzKet(1, -1), JzKet(1, -1)) + assert uncouple(JzKetCoupled(2, 2, (1, 1, 1))) == \ + -sqrt(6)*TensorProduct(JzKet(1, 0), JzKet(1, 1), JzKet(1, 1))/6 - \ + sqrt(6)*TensorProduct(JzKet(1, 1), JzKet(1, 0), JzKet(1, 1))/6 + \ + sqrt(6)*TensorProduct(JzKet(1, 1), JzKet(1, 1), JzKet(1, 0))/3 + assert uncouple(JzKetCoupled(2, 1, (1, 1, 1))) == \ + -sqrt(3)*TensorProduct(JzKet(1, -1), JzKet(1, 1), JzKet(1, 1))/6 - \ + sqrt(3)*TensorProduct(JzKet(1, 0), JzKet(1, 0), JzKet(1, 1))/3 + \ + sqrt(3)*TensorProduct(JzKet(1, 0), JzKet(1, 1), JzKet(1, 0))/6 - \ + sqrt(3)*TensorProduct(JzKet(1, 1), JzKet(1, -1), JzKet(1, 1))/6 + \ + sqrt(3)*TensorProduct(JzKet(1, 1), JzKet(1, 0), JzKet(1, 0))/6 + \ + sqrt(3)*TensorProduct(JzKet(1, 1), JzKet(1, 1), JzKet(1, -1))/3 + assert uncouple(JzKetCoupled(2, 0, (1, 1, 1))) == \ + -TensorProduct(JzKet(1, -1), JzKet(1, 0), JzKet(1, 1))/2 - \ + TensorProduct(JzKet(1, 0), JzKet(1, -1), JzKet(1, 1))/2 + \ + TensorProduct(JzKet(1, 0), JzKet(1, 1), JzKet(1, -1))/2 + \ + TensorProduct(JzKet(1, 1), JzKet(1, 0), JzKet(1, -1))/2 + assert uncouple(JzKetCoupled(2, -1, (1, 1, 1))) == \ + -sqrt(3)*TensorProduct(JzKet(1, -1), JzKet(1, -1), JzKet(1, 1))/3 - \ + sqrt(3)*TensorProduct(JzKet(1, -1), JzKet(1, 0), JzKet(1, 0))/6 + \ + sqrt(3)*TensorProduct(JzKet(1, -1), JzKet(1, 1), JzKet(1, -1))/6 - \ + sqrt(3)*TensorProduct(JzKet(1, 0), JzKet(1, -1), JzKet(1, 0))/6 + \ + sqrt(3)*TensorProduct(JzKet(1, 0), JzKet(1, 0), JzKet(1, -1))/3 + \ + sqrt(3)*TensorProduct(JzKet(1, 1), JzKet(1, -1), JzKet(1, -1))/6 + assert uncouple(JzKetCoupled(2, -2, (1, 1, 1))) == \ + -sqrt(6)*TensorProduct(JzKet(1, -1), JzKet(1, -1), JzKet(1, 0))/3 + \ + sqrt(6)*TensorProduct(JzKet(1, -1), JzKet(1, 0), JzKet(1, -1))/6 + \ + sqrt(6)*TensorProduct(JzKet(1, 0), JzKet(1, -1), JzKet(1, -1))/6 + assert uncouple(JzKetCoupled(1, 1, (1, 1, 1))) == \ + sqrt(15)*TensorProduct(JzKet(1, -1), JzKet(1, 1), JzKet(1, 1))/30 + \ + sqrt(15)*TensorProduct(JzKet(1, 0), JzKet(1, 0), JzKet(1, 1))/15 - \ + sqrt(15)*TensorProduct(JzKet(1, 0), JzKet(1, 1), JzKet(1, 0))/10 + \ + sqrt(15)*TensorProduct(JzKet(1, 1), JzKet(1, -1), JzKet(1, 1))/30 - \ + sqrt(15)*TensorProduct(JzKet(1, 1), JzKet(1, 0), JzKet(1, 0))/10 + \ + sqrt(15)*TensorProduct(JzKet(1, 1), JzKet(1, 1), JzKet(1, -1))/5 + assert uncouple(JzKetCoupled(1, 0, (1, 1, 1))) == \ + sqrt(15)*TensorProduct(JzKet(1, -1), JzKet(1, 0), JzKet(1, 1))/10 - \ + sqrt(15)*TensorProduct(JzKet(1, -1), JzKet(1, 1), JzKet(1, 0))/15 + \ + sqrt(15)*TensorProduct(JzKet(1, 0), JzKet(1, -1), JzKet(1, 1))/10 - \ + 2*sqrt(15)*TensorProduct(JzKet(1, 0), JzKet(1, 0), JzKet(1, 0))/15 + \ + sqrt(15)*TensorProduct(JzKet(1, 0), JzKet(1, 1), JzKet(1, -1))/10 - \ + sqrt(15)*TensorProduct(JzKet(1, 1), JzKet(1, -1), JzKet(1, 0))/15 + \ + sqrt(15)*TensorProduct(JzKet(1, 1), JzKet(1, 0), JzKet(1, -1))/10 + assert uncouple(JzKetCoupled(1, -1, (1, 1, 1))) == \ + sqrt(15)*TensorProduct(JzKet(1, -1), JzKet(1, -1), JzKet(1, 1))/5 - \ + sqrt(15)*TensorProduct(JzKet(1, -1), JzKet(1, 0), JzKet(1, 0))/10 + \ + sqrt(15)*TensorProduct(JzKet(1, -1), JzKet(1, 1), JzKet(1, -1))/30 - \ + sqrt(15)*TensorProduct(JzKet(1, 0), JzKet(1, -1), JzKet(1, 0))/10 + \ + sqrt(15)*TensorProduct(JzKet(1, 0), JzKet(1, 0), JzKet(1, -1))/15 + \ + sqrt(15)*TensorProduct(JzKet(1, 1), JzKet(1, -1), JzKet(1, -1))/30 # Defined j13 # j1=1/2, j2=1/2, j3=1, j13=1/2 - assert uncouple(JzKetCoupled(1, 1, (S(1)/2,S(1)/2,1), ((1,3,S(1)/2),(1,2,1)) )) == \ - -sqrt(6)*TensorProduct(JzKet(S(1)/2,-S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,1))/3 + \ - sqrt(3)*TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,0))/3 - assert uncouple(JzKetCoupled(1, 0, (S(1)/2,S(1)/2,1), ((1,3,S(1)/2),(1,2,1)) )) == \ - -sqrt(3)*TensorProduct(JzKet(S(1)/2,-S(1)/2), JzKet(S(1)/2,-S(1)/2), JzKet(1,1))/3 - \ - sqrt(6)*TensorProduct(JzKet(S(1)/2,-S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,0))/6 + \ - sqrt(6)*TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,-S(1)/2), JzKet(1,0))/6 + \ - sqrt(3)*TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,-1))/3 - assert uncouple(JzKetCoupled(1, -1, (S(1)/2,S(1)/2,1), ((1,3,S(1)/2),(1,2,1)) )) == \ - -sqrt(3)*TensorProduct(JzKet(S(1)/2,-S(1)/2), JzKet(S(1)/2,-S(1)/2), JzKet(1,0))/3 + \ - sqrt(6)*TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,-S(1)/2), JzKet(1,-1))/3 + assert uncouple(JzKetCoupled(1, 1, (S(1)/2, S(1)/2, 1), ((1, 3, S(1)/2), (1, 2, 1)) )) == \ + -sqrt(6)*TensorProduct(JzKet(S(1)/2, -S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, 1))/3 + \ + sqrt(3)*TensorProduct( + JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, 0))/3 + assert uncouple(JzKetCoupled(1, 0, (S(1)/2, S(1)/2, 1), ((1, 3, S(1)/2), (1, 2, 1)) )) == \ + -sqrt(3)*TensorProduct(JzKet(S(1)/2, -S(1)/2), JzKet(S(1)/2, -S(1)/2), JzKet(1, 1))/3 - \ + sqrt(6)*TensorProduct(JzKet(S(1)/2, -S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, 0))/6 + \ + sqrt(6)*TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, -S(1)/2), JzKet(1, 0))/6 + \ + sqrt(3)*TensorProduct( + JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, -1))/3 + assert uncouple(JzKetCoupled(1, -1, (S(1)/2, S(1)/2, 1), ((1, 3, S(1)/2), (1, 2, 1)) )) == \ + -sqrt(3)*TensorProduct(JzKet(S(1)/2, -S(1)/2), JzKet(S(1)/2, -S(1)/2), JzKet(1, 0))/3 + \ + sqrt(6)*TensorProduct( + JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, -S(1)/2), JzKet(1, -1))/3 # j1=1/2, j2=1, j3=1, j13=1/2 - assert uncouple(JzKetCoupled(S(3)/2, S(3)/2, (S(1)/2,1,1), ((1,3,S(1)/2),(1,2,S(3)/2)))) == \ - -sqrt(6)*TensorProduct(JzKet(S(1)/2,-S(1)/2), JzKet(1,1), JzKet(1,1))/3 + \ - sqrt(3)*TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(1,1), JzKet(1,0))/3 - assert uncouple(JzKetCoupled(S(3)/2, S(1)/2, (S(1)/2,1,1), ((1,3,S(1)/2),(1,2,S(3)/2)))) == \ - -2*TensorProduct(JzKet(S(1)/2,-S(1)/2), JzKet(1,0), JzKet(1,1))/3 - \ - TensorProduct(JzKet(S(1)/2,-S(1)/2), JzKet(1,1), JzKet(1,0))/3 + \ - sqrt(2)*TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(1,0), JzKet(1,0))/3 + \ - sqrt(2)*TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(1,1), JzKet(1,-1))/3 - assert uncouple(JzKetCoupled(S(3)/2, -S(1)/2, (S(1)/2,1,1), ((1,3,S(1)/2),(1,2,S(3)/2)))) == \ - -sqrt(2)*TensorProduct(JzKet(S(1)/2,-S(1)/2), JzKet(1,-1), JzKet(1,1))/3 - \ - sqrt(2)*TensorProduct(JzKet(S(1)/2,-S(1)/2), JzKet(1,0), JzKet(1,0))/3 + \ - TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(1,-1), JzKet(1,0))/3 + \ - 2*TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(1,0), JzKet(1,-1))/3 - assert uncouple(JzKetCoupled(S(3)/2, -S(3)/2, (S(1)/2,1,1), ((1,3,S(1)/2),(1,2,S(3)/2)))) == \ - -sqrt(3)*TensorProduct(JzKet(S(1)/2,-S(1)/2), JzKet(1,-1), JzKet(1,0))/3 + \ - sqrt(6)*TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(1,-1), JzKet(1,-1))/3 + assert uncouple(JzKetCoupled(S(3)/2, S(3)/2, (S(1)/2, 1, 1), ((1, 3, S(1)/2), (1, 2, S(3)/2)))) == \ + -sqrt(6)*TensorProduct(JzKet(S(1)/2, -S(1)/2), JzKet(1, 1), JzKet(1, 1))/3 + \ + sqrt(3)*TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(1, 1), + JzKet(1, 0))/3 + assert uncouple(JzKetCoupled(S(3)/2, S(1)/2, (S(1)/2, 1, 1), ((1, 3, S(1)/2), (1, 2, S(3)/2)))) == \ + -2*TensorProduct(JzKet(S(1)/2, -S(1)/2), JzKet(1, 0), JzKet(1, 1))/3 - \ + TensorProduct(JzKet(S(1)/2, -S(1)/2), JzKet(1, 1), JzKet(1, 0))/3 + \ + sqrt(2)*TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(1, 0), JzKet(1, 0))/3 + \ + sqrt(2)*TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(1, 1), + JzKet(1, -1))/3 + assert uncouple(JzKetCoupled(S(3)/2, -S(1)/2, (S(1)/2, 1, 1), ((1, 3, S(1)/2), (1, 2, S(3)/2)))) == \ + -sqrt(2)*TensorProduct(JzKet(S(1)/2, -S(1)/2), JzKet(1, -1), JzKet(1, 1))/3 - \ + sqrt(2)*TensorProduct(JzKet(S(1)/2, -S(1)/2), JzKet(1, 0), JzKet(1, 0))/3 + \ + TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(1, -1), JzKet(1, 0))/3 + \ + 2*TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(1, 0), JzKet(1, -1))/3 + assert uncouple(JzKetCoupled(S(3)/2, -S(3)/2, (S(1)/2, 1, 1), ((1, 3, S(1)/2), (1, 2, S(3)/2)))) == \ + -sqrt(3)*TensorProduct(JzKet(S(1)/2, -S(1)/2), JzKet(1, -1), JzKet(1, 0))/3 + \ + sqrt(6)*TensorProduct( + JzKet(S(1)/2, S(1)/2), JzKet(1, -1), JzKet(1, -1))/3 # j1=1, j2=1, j3=1, j13=1 - assert uncouple(JzKetCoupled(2, 2, (1,1,1), ((1,3,1),(1,2,2)))) == \ - -sqrt(2)*TensorProduct(JzKet(1,0), JzKet(1,1), JzKet(1,1))/2 + \ - sqrt(2)*TensorProduct(JzKet(1,1), JzKet(1,1), JzKet(1,0))/2 - assert uncouple(JzKetCoupled(2, 1, (1,1,1), ((1,3,1),(1,2,2)))) == \ - -TensorProduct(JzKet(1,-1), JzKet(1,1), JzKet(1,1))/2 - \ - TensorProduct(JzKet(1,0), JzKet(1,0), JzKet(1,1))/2 + \ - TensorProduct(JzKet(1,1), JzKet(1,0), JzKet(1,0))/2 + \ - TensorProduct(JzKet(1,1), JzKet(1,1), JzKet(1,-1))/2 - assert uncouple(JzKetCoupled(2, 0, (1,1,1), ((1,3,1),(1,2,2)))) == \ - -sqrt(3)*TensorProduct(JzKet(1,-1), JzKet(1,0), JzKet(1,1))/3 - \ - sqrt(3)*TensorProduct(JzKet(1,-1), JzKet(1,1), JzKet(1,0))/6 - \ - sqrt(3)*TensorProduct(JzKet(1,0), JzKet(1,-1), JzKet(1,1))/6 + \ - sqrt(3)*TensorProduct(JzKet(1,0), JzKet(1,1), JzKet(1,-1))/6 + \ - sqrt(3)*TensorProduct(JzKet(1,1), JzKet(1,-1), JzKet(1,0))/6 + \ - sqrt(3)*TensorProduct(JzKet(1,1), JzKet(1,0), JzKet(1,-1))/3 - assert uncouple(JzKetCoupled(2, -1, (1,1,1), ((1,3,1),(1,2,2)))) == \ - -TensorProduct(JzKet(1,-1), JzKet(1,-1), JzKet(1,1))/2 - \ - TensorProduct(JzKet(1,-1), JzKet(1,0), JzKet(1,0))/2 + \ - TensorProduct(JzKet(1,0), JzKet(1,0), JzKet(1,-1))/2 + \ - TensorProduct(JzKet(1,1), JzKet(1,-1), JzKet(1,-1))/2 - assert uncouple(JzKetCoupled(2, -2, (1,1,1), ((1,3,1),(1,2,2)))) == \ - -sqrt(2)*TensorProduct(JzKet(1,-1), JzKet(1,-1), JzKet(1,0))/2 + \ - sqrt(2)*TensorProduct(JzKet(1,0), JzKet(1,-1), JzKet(1,-1))/2 - assert uncouple(JzKetCoupled(1, 1, (1,1,1), ((1,3,1),(1,2,1)))) == \ - TensorProduct(JzKet(1,-1), JzKet(1,1), JzKet(1,1))/2 - \ - TensorProduct(JzKet(1,0), JzKet(1,0), JzKet(1,1))/2 + \ - TensorProduct(JzKet(1,1), JzKet(1,0), JzKet(1,0))/2 - \ - TensorProduct(JzKet(1,1), JzKet(1,1), JzKet(1,-1))/2 - assert uncouple(JzKetCoupled(1, 0, (1,1,1), ((1,3,1),(1,2,1)))) == \ - TensorProduct(JzKet(1,-1), JzKet(1,1), JzKet(1,0))/2 - \ - TensorProduct(JzKet(1,0), JzKet(1,-1), JzKet(1,1))/2 - \ - TensorProduct(JzKet(1,0), JzKet(1,1), JzKet(1,-1))/2 + \ - TensorProduct(JzKet(1,1), JzKet(1,-1), JzKet(1,0))/2 - assert uncouple(JzKetCoupled(1, -1, (1,1,1), ((1,3,1),(1,2,1)))) == \ - -TensorProduct(JzKet(1,-1), JzKet(1,-1), JzKet(1,1))/2 + \ - TensorProduct(JzKet(1,-1), JzKet(1,0), JzKet(1,0))/2 - \ - TensorProduct(JzKet(1,0), JzKet(1,0), JzKet(1,-1))/2 + \ - TensorProduct(JzKet(1,1), JzKet(1,-1), JzKet(1,-1))/2 + assert uncouple(JzKetCoupled(2, 2, (1, 1, 1), ((1, 3, 1), (1, 2, 2)))) == \ + -sqrt(2)*TensorProduct(JzKet(1, 0), JzKet(1, 1), JzKet(1, 1))/2 + \ + sqrt(2)*TensorProduct(JzKet(1, 1), JzKet(1, 1), JzKet(1, 0))/2 + assert uncouple(JzKetCoupled(2, 1, (1, 1, 1), ((1, 3, 1), (1, 2, 2)))) == \ + -TensorProduct(JzKet(1, -1), JzKet(1, 1), JzKet(1, 1))/2 - \ + TensorProduct(JzKet(1, 0), JzKet(1, 0), JzKet(1, 1))/2 + \ + TensorProduct(JzKet(1, 1), JzKet(1, 0), JzKet(1, 0))/2 + \ + TensorProduct(JzKet(1, 1), JzKet(1, 1), JzKet(1, -1))/2 + assert uncouple(JzKetCoupled(2, 0, (1, 1, 1), ((1, 3, 1), (1, 2, 2)))) == \ + -sqrt(3)*TensorProduct(JzKet(1, -1), JzKet(1, 0), JzKet(1, 1))/3 - \ + sqrt(3)*TensorProduct(JzKet(1, -1), JzKet(1, 1), JzKet(1, 0))/6 - \ + sqrt(3)*TensorProduct(JzKet(1, 0), JzKet(1, -1), JzKet(1, 1))/6 + \ + sqrt(3)*TensorProduct(JzKet(1, 0), JzKet(1, 1), JzKet(1, -1))/6 + \ + sqrt(3)*TensorProduct(JzKet(1, 1), JzKet(1, -1), JzKet(1, 0))/6 + \ + sqrt(3)*TensorProduct(JzKet(1, 1), JzKet(1, 0), JzKet(1, -1))/3 + assert uncouple(JzKetCoupled(2, -1, (1, 1, 1), ((1, 3, 1), (1, 2, 2)))) == \ + -TensorProduct(JzKet(1, -1), JzKet(1, -1), JzKet(1, 1))/2 - \ + TensorProduct(JzKet(1, -1), JzKet(1, 0), JzKet(1, 0))/2 + \ + TensorProduct(JzKet(1, 0), JzKet(1, 0), JzKet(1, -1))/2 + \ + TensorProduct(JzKet(1, 1), JzKet(1, -1), JzKet(1, -1))/2 + assert uncouple(JzKetCoupled(2, -2, (1, 1, 1), ((1, 3, 1), (1, 2, 2)))) == \ + -sqrt(2)*TensorProduct(JzKet(1, -1), JzKet(1, -1), JzKet(1, 0))/2 + \ + sqrt(2)*TensorProduct(JzKet(1, 0), JzKet(1, -1), JzKet(1, -1))/2 + assert uncouple(JzKetCoupled(1, 1, (1, 1, 1), ((1, 3, 1), (1, 2, 1)))) == \ + TensorProduct(JzKet(1, -1), JzKet(1, 1), JzKet(1, 1))/2 - \ + TensorProduct(JzKet(1, 0), JzKet(1, 0), JzKet(1, 1))/2 + \ + TensorProduct(JzKet(1, 1), JzKet(1, 0), JzKet(1, 0))/2 - \ + TensorProduct(JzKet(1, 1), JzKet(1, 1), JzKet(1, -1))/2 + assert uncouple(JzKetCoupled(1, 0, (1, 1, 1), ((1, 3, 1), (1, 2, 1)))) == \ + TensorProduct(JzKet(1, -1), JzKet(1, 1), JzKet(1, 0))/2 - \ + TensorProduct(JzKet(1, 0), JzKet(1, -1), JzKet(1, 1))/2 - \ + TensorProduct(JzKet(1, 0), JzKet(1, 1), JzKet(1, -1))/2 + \ + TensorProduct(JzKet(1, 1), JzKet(1, -1), JzKet(1, 0))/2 + assert uncouple(JzKetCoupled(1, -1, (1, 1, 1), ((1, 3, 1), (1, 2, 1)))) == \ + -TensorProduct(JzKet(1, -1), JzKet(1, -1), JzKet(1, 1))/2 + \ + TensorProduct(JzKet(1, -1), JzKet(1, 0), JzKet(1, 0))/2 - \ + TensorProduct(JzKet(1, 0), JzKet(1, 0), JzKet(1, -1))/2 + \ + TensorProduct(JzKet(1, 1), JzKet(1, -1), JzKet(1, -1))/2 + def test_uncouple_4_coupled_states_numerical(): # j1=1/2, j2=1/2, j3=1, j4=1, default coupling - assert uncouple(JzKetCoupled(3, 3, (S(1)/2,S(1)/2,1,1))) == \ - TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,1), JzKet(1,1)) - assert uncouple(JzKetCoupled(3, 2, (S(1)/2,S(1)/2,1,1))) == \ - sqrt(6)*TensorProduct(JzKet(S(1)/2,-S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,1), JzKet(1,1))/6 + \ - sqrt(6)*TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,-S(1)/2), JzKet(1,1), JzKet(1,1))/6 + \ - sqrt(3)*TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,0), JzKet(1,1))/3 + \ - sqrt(3)*TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,1), JzKet(1,0))/3 - assert uncouple(JzKetCoupled(3, 1, (S(1)/2,S(1)/2,1,1))) == \ - sqrt(15)*TensorProduct(JzKet(S(1)/2,-S(1)/2), JzKet(S(1)/2,-S(1)/2), JzKet(1,1), JzKet(1,1))/15 + \ - sqrt(30)*TensorProduct(JzKet(S(1)/2,-S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,0), JzKet(1,1))/15 + \ - sqrt(30)*TensorProduct(JzKet(S(1)/2,-S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,1), JzKet(1,0))/15 + \ - sqrt(30)*TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,-S(1)/2), JzKet(1,0), JzKet(1,1))/15 + \ - sqrt(30)*TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,-S(1)/2), JzKet(1,1), JzKet(1,0))/15 + \ - sqrt(15)*TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,-1), JzKet(1,1))/15 + \ - 2*sqrt(15)*TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,0), JzKet(1,0))/15 + \ - sqrt(15)*TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,1), JzKet(1,-1))/15 - assert uncouple(JzKetCoupled(3, 0, (S(1)/2,S(1)/2,1,1))) == \ - sqrt(10)*TensorProduct(JzKet(S(1)/2,-S(1)/2), JzKet(S(1)/2,-S(1)/2), JzKet(1,0), JzKet(1,1))/10 + \ - sqrt(10)*TensorProduct(JzKet(S(1)/2,-S(1)/2), JzKet(S(1)/2,-S(1)/2), JzKet(1,1), JzKet(1,0))/10 + \ - sqrt(5)*TensorProduct(JzKet(S(1)/2,-S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,-1), JzKet(1,1))/10 + \ - sqrt(5)*TensorProduct(JzKet(S(1)/2,-S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,0), JzKet(1,0))/5 + \ - sqrt(5)*TensorProduct(JzKet(S(1)/2,-S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,1), JzKet(1,-1))/10 + \ - sqrt(5)*TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,-S(1)/2), JzKet(1,-1), JzKet(1,1))/10 + \ - sqrt(5)*TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,-S(1)/2), JzKet(1,0), JzKet(1,0))/5 + \ - sqrt(5)*TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,-S(1)/2), JzKet(1,1), JzKet(1,-1))/10 + \ - sqrt(10)*TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,-1), JzKet(1,0))/10 + \ - sqrt(10)*TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,0), JzKet(1,-1))/10 - assert uncouple(JzKetCoupled(3, -1, (S(1)/2,S(1)/2,1,1))) == \ - sqrt(15)*TensorProduct(JzKet(S(1)/2,-S(1)/2), JzKet(S(1)/2,-S(1)/2), JzKet(1,-1), JzKet(1,1))/15 + \ - 2*sqrt(15)*TensorProduct(JzKet(S(1)/2,-S(1)/2), JzKet(S(1)/2,-S(1)/2), JzKet(1,0), JzKet(1,0))/15 + \ - sqrt(15)*TensorProduct(JzKet(S(1)/2,-S(1)/2), JzKet(S(1)/2,-S(1)/2), JzKet(1,1), JzKet(1,-1))/15 + \ - sqrt(30)*TensorProduct(JzKet(S(1)/2,-S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,-1), JzKet(1,0))/15 + \ - sqrt(30)*TensorProduct(JzKet(S(1)/2,-S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,0), JzKet(1,-1))/15 + \ - sqrt(30)*TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,-S(1)/2), JzKet(1,-1), JzKet(1,0))/15 + \ - sqrt(30)*TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,-S(1)/2), JzKet(1,0), JzKet(1,-1))/15 + \ - sqrt(15)*TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,-1), JzKet(1,-1))/15 - assert uncouple(JzKetCoupled(3, -2, (S(1)/2,S(1)/2,1,1))) == \ - sqrt(3)*TensorProduct(JzKet(S(1)/2,-S(1)/2), JzKet(S(1)/2,-S(1)/2), JzKet(1,-1), JzKet(1,0))/3 + \ - sqrt(3)*TensorProduct(JzKet(S(1)/2,-S(1)/2), JzKet(S(1)/2,-S(1)/2), JzKet(1,0), JzKet(1,-1))/3 + \ - sqrt(6)*TensorProduct(JzKet(S(1)/2,-S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,-1), JzKet(1,-1))/6 + \ - sqrt(6)*TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,-S(1)/2), JzKet(1,-1), JzKet(1,-1))/6 - assert uncouple(JzKetCoupled(3, -3, (S(1)/2,S(1)/2,1,1))) == \ - TensorProduct(JzKet(S(1)/2,-S(1)/2), JzKet(S(1)/2,-S(1)/2), JzKet(1,-1), JzKet(1,-1)) - assert uncouple(JzKetCoupled(2, 2, (S(1)/2,S(1)/2,1,1))) == \ - -sqrt(3)*TensorProduct(JzKet(S(1)/2,-S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,1), JzKet(1,1))/6 - \ - sqrt(3)*TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,-S(1)/2), JzKet(1,1), JzKet(1,1))/6 - \ - sqrt(6)*TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,0), JzKet(1,1))/6 + \ - sqrt(6)*TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,1), JzKet(1,0))/3 - assert uncouple(JzKetCoupled(2, 1, (S(1)/2,S(1)/2,1,1))) == \ - -sqrt(3)*TensorProduct(JzKet(S(1)/2,-S(1)/2), JzKet(S(1)/2,-S(1)/2), JzKet(1,1), JzKet(1,1))/6 - \ - sqrt(6)*TensorProduct(JzKet(S(1)/2,-S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,0), JzKet(1,1))/6 + \ - sqrt(6)*TensorProduct(JzKet(S(1)/2,-S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,1), JzKet(1,0))/12 - \ - sqrt(6)*TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,-S(1)/2), JzKet(1,0), JzKet(1,1))/6 + \ - sqrt(6)*TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,-S(1)/2), JzKet(1,1), JzKet(1,0))/12 - \ - sqrt(3)*TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,-1), JzKet(1,1))/6 + \ - sqrt(3)*TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,0), JzKet(1,0))/6 + \ - sqrt(3)*TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,1), JzKet(1,-1))/3 - assert uncouple(JzKetCoupled(2, 0, (S(1)/2,S(1)/2,1,1))) == \ - -TensorProduct(JzKet(S(1)/2,-S(1)/2), JzKet(S(1)/2,-S(1)/2), JzKet(1,0), JzKet(1,1))/2 - \ - sqrt(2)*TensorProduct(JzKet(S(1)/2,-S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,-1), JzKet(1,1))/4 + \ - sqrt(2)*TensorProduct(JzKet(S(1)/2,-S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,1), JzKet(1,-1))/4 - \ - sqrt(2)*TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,-S(1)/2), JzKet(1,-1), JzKet(1,1))/4 + \ - sqrt(2)*TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,-S(1)/2), JzKet(1,1), JzKet(1,-1))/4 + \ - TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,0), JzKet(1,-1))/2 - assert uncouple(JzKetCoupled(2, -1, (S(1)/2,S(1)/2,1,1))) == \ - -sqrt(3)*TensorProduct(JzKet(S(1)/2,-S(1)/2), JzKet(S(1)/2,-S(1)/2), JzKet(1,-1), JzKet(1,1))/3 - \ - sqrt(3)*TensorProduct(JzKet(S(1)/2,-S(1)/2), JzKet(S(1)/2,-S(1)/2), JzKet(1,0), JzKet(1,0))/6 + \ - sqrt(3)*TensorProduct(JzKet(S(1)/2,-S(1)/2), JzKet(S(1)/2,-S(1)/2), JzKet(1,1), JzKet(1,-1))/6 - \ - sqrt(6)*TensorProduct(JzKet(S(1)/2,-S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,-1), JzKet(1,0))/12 + \ - sqrt(6)*TensorProduct(JzKet(S(1)/2,-S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,0), JzKet(1,-1))/6 - \ - sqrt(6)*TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,-S(1)/2), JzKet(1,-1), JzKet(1,0))/12 + \ - sqrt(6)*TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,-S(1)/2), JzKet(1,0), JzKet(1,-1))/6 + \ - sqrt(3)*TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,-1), JzKet(1,-1))/6 - assert uncouple(JzKetCoupled(2, -2, (S(1)/2,S(1)/2,1,1))) == \ - -sqrt(6)*TensorProduct(JzKet(S(1)/2,-S(1)/2), JzKet(S(1)/2,-S(1)/2), JzKet(1,-1), JzKet(1,0))/3 + \ - sqrt(6)*TensorProduct(JzKet(S(1)/2,-S(1)/2), JzKet(S(1)/2,-S(1)/2), JzKet(1,0), JzKet(1,-1))/6 + \ - sqrt(3)*TensorProduct(JzKet(S(1)/2,-S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,-1), JzKet(1,-1))/6 + \ - sqrt(3)*TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,-S(1)/2), JzKet(1,-1), JzKet(1,-1))/6 - assert uncouple(JzKetCoupled(1, 1, (S(1)/2,S(1)/2,1,1))) == \ - sqrt(15)*TensorProduct(JzKet(S(1)/2,-S(1)/2), JzKet(S(1)/2,-S(1)/2), JzKet(1,1), JzKet(1,1))/30 + \ - sqrt(30)*TensorProduct(JzKet(S(1)/2,-S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,0), JzKet(1,1))/30 - \ - sqrt(30)*TensorProduct(JzKet(S(1)/2,-S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,1), JzKet(1,0))/20 + \ - sqrt(30)*TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,-S(1)/2), JzKet(1,0), JzKet(1,1))/30 - \ - sqrt(30)*TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,-S(1)/2), JzKet(1,1), JzKet(1,0))/20 + \ - sqrt(15)*TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,-1), JzKet(1,1))/30 - \ - sqrt(15)*TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,0), JzKet(1,0))/10 + \ - sqrt(15)*TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,1), JzKet(1,-1))/5 - assert uncouple(JzKetCoupled(1, 0, (S(1)/2,S(1)/2,1,1))) == \ - sqrt(15)*TensorProduct(JzKet(S(1)/2,-S(1)/2), JzKet(S(1)/2,-S(1)/2), JzKet(1,0), JzKet(1,1))/10 - \ - sqrt(15)*TensorProduct(JzKet(S(1)/2,-S(1)/2), JzKet(S(1)/2,-S(1)/2), JzKet(1,1), JzKet(1,0))/15 + \ - sqrt(30)*TensorProduct(JzKet(S(1)/2,-S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,-1), JzKet(1,1))/20 - \ - sqrt(30)*TensorProduct(JzKet(S(1)/2,-S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,0), JzKet(1,0))/15 + \ - sqrt(30)*TensorProduct(JzKet(S(1)/2,-S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,1), JzKet(1,-1))/20 + \ - sqrt(30)*TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,-S(1)/2), JzKet(1,-1), JzKet(1,1))/20 - \ - sqrt(30)*TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,-S(1)/2), JzKet(1,0), JzKet(1,0))/15 + \ - sqrt(30)*TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,-S(1)/2), JzKet(1,1), JzKet(1,-1))/20 - \ - sqrt(15)*TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,-1), JzKet(1,0))/15 + \ - sqrt(15)*TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,0), JzKet(1,-1))/10 - assert uncouple(JzKetCoupled(1, -1, (S(1)/2,S(1)/2,1,1))) == \ - sqrt(15)*TensorProduct(JzKet(S(1)/2,-S(1)/2), JzKet(S(1)/2,-S(1)/2), JzKet(1,-1), JzKet(1,1))/5 - \ - sqrt(15)*TensorProduct(JzKet(S(1)/2,-S(1)/2), JzKet(S(1)/2,-S(1)/2), JzKet(1,0), JzKet(1,0))/10 + \ - sqrt(15)*TensorProduct(JzKet(S(1)/2,-S(1)/2), JzKet(S(1)/2,-S(1)/2), JzKet(1,1), JzKet(1,-1))/30 - \ - sqrt(30)*TensorProduct(JzKet(S(1)/2,-S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,-1), JzKet(1,0))/20 + \ - sqrt(30)*TensorProduct(JzKet(S(1)/2,-S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,0), JzKet(1,-1))/30 - \ - sqrt(30)*TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,-S(1)/2), JzKet(1,-1), JzKet(1,0))/20 + \ - sqrt(30)*TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,-S(1)/2), JzKet(1,0), JzKet(1,-1))/30 + \ - sqrt(15)*TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,-1), JzKet(1,-1))/30 + assert uncouple(JzKetCoupled(3, 3, (S(1)/2, S(1)/2, 1, 1))) == \ + TensorProduct(JzKet( + S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, 1), JzKet(1, 1)) + assert uncouple(JzKetCoupled(3, 2, (S(1)/2, S(1)/2, 1, 1))) == \ + sqrt(6)*TensorProduct(JzKet(S(1)/2, -S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, 1), JzKet(1, 1))/6 + \ + sqrt(6)*TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, -S(1)/2), JzKet(1, 1), JzKet(1, 1))/6 + \ + sqrt(3)*TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, 0), JzKet(1, 1))/3 + \ + sqrt(3)*TensorProduct(JzKet(S( + 1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, 1), JzKet(1, 0))/3 + assert uncouple(JzKetCoupled(3, 1, (S(1)/2, S(1)/2, 1, 1))) == \ + sqrt(15)*TensorProduct(JzKet(S(1)/2, -S(1)/2), JzKet(S(1)/2, -S(1)/2), JzKet(1, 1), JzKet(1, 1))/15 + \ + sqrt(30)*TensorProduct(JzKet(S(1)/2, -S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, 0), JzKet(1, 1))/15 + \ + sqrt(30)*TensorProduct(JzKet(S(1)/2, -S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, 1), JzKet(1, 0))/15 + \ + sqrt(30)*TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, -S(1)/2), JzKet(1, 0), JzKet(1, 1))/15 + \ + sqrt(30)*TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, -S(1)/2), JzKet(1, 1), JzKet(1, 0))/15 + \ + sqrt(15)*TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, -1), JzKet(1, 1))/15 + \ + 2*sqrt(15)*TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, 0), JzKet(1, 0))/15 + \ + sqrt(15)*TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, + S(1)/2), JzKet(1, 1), JzKet(1, -1))/15 + assert uncouple(JzKetCoupled(3, 0, (S(1)/2, S(1)/2, 1, 1))) == \ + sqrt(10)*TensorProduct(JzKet(S(1)/2, -S(1)/2), JzKet(S(1)/2, -S(1)/2), JzKet(1, 0), JzKet(1, 1))/10 + \ + sqrt(10)*TensorProduct(JzKet(S(1)/2, -S(1)/2), JzKet(S(1)/2, -S(1)/2), JzKet(1, 1), JzKet(1, 0))/10 + \ + sqrt(5)*TensorProduct(JzKet(S(1)/2, -S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, -1), JzKet(1, 1))/10 + \ + sqrt(5)*TensorProduct(JzKet(S(1)/2, -S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, 0), JzKet(1, 0))/5 + \ + sqrt(5)*TensorProduct(JzKet(S(1)/2, -S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, 1), JzKet(1, -1))/10 + \ + sqrt(5)*TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, -S(1)/2), JzKet(1, -1), JzKet(1, 1))/10 + \ + sqrt(5)*TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, -S(1)/2), JzKet(1, 0), JzKet(1, 0))/5 + \ + sqrt(5)*TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, -S(1)/2), JzKet(1, 1), JzKet(1, -1))/10 + \ + sqrt(10)*TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, -1), JzKet(1, 0))/10 + \ + sqrt(10)*TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, + S(1)/2), JzKet(1, 0), JzKet(1, -1))/10 + assert uncouple(JzKetCoupled(3, -1, (S(1)/2, S(1)/2, 1, 1))) == \ + sqrt(15)*TensorProduct(JzKet(S(1)/2, -S(1)/2), JzKet(S(1)/2, -S(1)/2), JzKet(1, -1), JzKet(1, 1))/15 + \ + 2*sqrt(15)*TensorProduct(JzKet(S(1)/2, -S(1)/2), JzKet(S(1)/2, -S(1)/2), JzKet(1, 0), JzKet(1, 0))/15 + \ + sqrt(15)*TensorProduct(JzKet(S(1)/2, -S(1)/2), JzKet(S(1)/2, -S(1)/2), JzKet(1, 1), JzKet(1, -1))/15 + \ + sqrt(30)*TensorProduct(JzKet(S(1)/2, -S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, -1), JzKet(1, 0))/15 + \ + sqrt(30)*TensorProduct(JzKet(S(1)/2, -S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, 0), JzKet(1, -1))/15 + \ + sqrt(30)*TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, -S(1)/2), JzKet(1, -1), JzKet(1, 0))/15 + \ + sqrt(30)*TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, -S(1)/2), JzKet(1, 0), JzKet(1, -1))/15 + \ + sqrt(15)*TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, + S(1)/2), JzKet(1, -1), JzKet(1, -1))/15 + assert uncouple(JzKetCoupled(3, -2, (S(1)/2, S(1)/2, 1, 1))) == \ + sqrt(3)*TensorProduct(JzKet(S(1)/2, -S(1)/2), JzKet(S(1)/2, -S(1)/2), JzKet(1, -1), JzKet(1, 0))/3 + \ + sqrt(3)*TensorProduct(JzKet(S(1)/2, -S(1)/2), JzKet(S(1)/2, -S(1)/2), JzKet(1, 0), JzKet(1, -1))/3 + \ + sqrt(6)*TensorProduct(JzKet(S(1)/2, -S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, -1), JzKet(1, -1))/6 + \ + sqrt(6)*TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, + -S(1)/2), JzKet(1, -1), JzKet(1, -1))/6 + assert uncouple(JzKetCoupled(3, -3, (S(1)/2, S(1)/2, 1, 1))) == \ + TensorProduct(JzKet(S(1)/2, -S( + 1)/2), JzKet(S(1)/2, -S(1)/2), JzKet(1, -1), JzKet(1, -1)) + assert uncouple(JzKetCoupled(2, 2, (S(1)/2, S(1)/2, 1, 1))) == \ + -sqrt(3)*TensorProduct(JzKet(S(1)/2, -S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, 1), JzKet(1, 1))/6 - \ + sqrt(3)*TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, -S(1)/2), JzKet(1, 1), JzKet(1, 1))/6 - \ + sqrt(6)*TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, 0), JzKet(1, 1))/6 + \ + sqrt(6)*TensorProduct(JzKet(S( + 1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, 1), JzKet(1, 0))/3 + assert uncouple(JzKetCoupled(2, 1, (S(1)/2, S(1)/2, 1, 1))) == \ + -sqrt(3)*TensorProduct(JzKet(S(1)/2, -S(1)/2), JzKet(S(1)/2, -S(1)/2), JzKet(1, 1), JzKet(1, 1))/6 - \ + sqrt(6)*TensorProduct(JzKet(S(1)/2, -S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, 0), JzKet(1, 1))/6 + \ + sqrt(6)*TensorProduct(JzKet(S(1)/2, -S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, 1), JzKet(1, 0))/12 - \ + sqrt(6)*TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, -S(1)/2), JzKet(1, 0), JzKet(1, 1))/6 + \ + sqrt(6)*TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, -S(1)/2), JzKet(1, 1), JzKet(1, 0))/12 - \ + sqrt(3)*TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, -1), JzKet(1, 1))/6 + \ + sqrt(3)*TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, 0), JzKet(1, 0))/6 + \ + sqrt(3)*TensorProduct(JzKet(S( + 1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, 1), JzKet(1, -1))/3 + assert uncouple(JzKetCoupled(2, 0, (S(1)/2, S(1)/2, 1, 1))) == \ + -TensorProduct(JzKet(S(1)/2, -S(1)/2), JzKet(S(1)/2, -S(1)/2), JzKet(1, 0), JzKet(1, 1))/2 - \ + sqrt(2)*TensorProduct(JzKet(S(1)/2, -S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, -1), JzKet(1, 1))/4 + \ + sqrt(2)*TensorProduct(JzKet(S(1)/2, -S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, 1), JzKet(1, -1))/4 - \ + sqrt(2)*TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, -S(1)/2), JzKet(1, -1), JzKet(1, 1))/4 + \ + sqrt(2)*TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, -S(1)/2), JzKet(1, 1), JzKet(1, -1))/4 + \ + TensorProduct(JzKet(S( + 1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, 0), JzKet(1, -1))/2 + assert uncouple(JzKetCoupled(2, -1, (S(1)/2, S(1)/2, 1, 1))) == \ + -sqrt(3)*TensorProduct(JzKet(S(1)/2, -S(1)/2), JzKet(S(1)/2, -S(1)/2), JzKet(1, -1), JzKet(1, 1))/3 - \ + sqrt(3)*TensorProduct(JzKet(S(1)/2, -S(1)/2), JzKet(S(1)/2, -S(1)/2), JzKet(1, 0), JzKet(1, 0))/6 + \ + sqrt(3)*TensorProduct(JzKet(S(1)/2, -S(1)/2), JzKet(S(1)/2, -S(1)/2), JzKet(1, 1), JzKet(1, -1))/6 - \ + sqrt(6)*TensorProduct(JzKet(S(1)/2, -S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, -1), JzKet(1, 0))/12 + \ + sqrt(6)*TensorProduct(JzKet(S(1)/2, -S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, 0), JzKet(1, -1))/6 - \ + sqrt(6)*TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, -S(1)/2), JzKet(1, -1), JzKet(1, 0))/12 + \ + sqrt(6)*TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, -S(1)/2), JzKet(1, 0), JzKet(1, -1))/6 + \ + sqrt(3)*TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, + S(1)/2), JzKet(1, -1), JzKet(1, -1))/6 + assert uncouple(JzKetCoupled(2, -2, (S(1)/2, S(1)/2, 1, 1))) == \ + -sqrt(6)*TensorProduct(JzKet(S(1)/2, -S(1)/2), JzKet(S(1)/2, -S(1)/2), JzKet(1, -1), JzKet(1, 0))/3 + \ + sqrt(6)*TensorProduct(JzKet(S(1)/2, -S(1)/2), JzKet(S(1)/2, -S(1)/2), JzKet(1, 0), JzKet(1, -1))/6 + \ + sqrt(3)*TensorProduct(JzKet(S(1)/2, -S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, -1), JzKet(1, -1))/6 + \ + sqrt(3)*TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, + -S(1)/2), JzKet(1, -1), JzKet(1, -1))/6 + assert uncouple(JzKetCoupled(1, 1, (S(1)/2, S(1)/2, 1, 1))) == \ + sqrt(15)*TensorProduct(JzKet(S(1)/2, -S(1)/2), JzKet(S(1)/2, -S(1)/2), JzKet(1, 1), JzKet(1, 1))/30 + \ + sqrt(30)*TensorProduct(JzKet(S(1)/2, -S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, 0), JzKet(1, 1))/30 - \ + sqrt(30)*TensorProduct(JzKet(S(1)/2, -S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, 1), JzKet(1, 0))/20 + \ + sqrt(30)*TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, -S(1)/2), JzKet(1, 0), JzKet(1, 1))/30 - \ + sqrt(30)*TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, -S(1)/2), JzKet(1, 1), JzKet(1, 0))/20 + \ + sqrt(15)*TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, -1), JzKet(1, 1))/30 - \ + sqrt(15)*TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, 0), JzKet(1, 0))/10 + \ + sqrt(15)*TensorProduct(JzKet(S( + 1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, 1), JzKet(1, -1))/5 + assert uncouple(JzKetCoupled(1, 0, (S(1)/2, S(1)/2, 1, 1))) == \ + sqrt(15)*TensorProduct(JzKet(S(1)/2, -S(1)/2), JzKet(S(1)/2, -S(1)/2), JzKet(1, 0), JzKet(1, 1))/10 - \ + sqrt(15)*TensorProduct(JzKet(S(1)/2, -S(1)/2), JzKet(S(1)/2, -S(1)/2), JzKet(1, 1), JzKet(1, 0))/15 + \ + sqrt(30)*TensorProduct(JzKet(S(1)/2, -S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, -1), JzKet(1, 1))/20 - \ + sqrt(30)*TensorProduct(JzKet(S(1)/2, -S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, 0), JzKet(1, 0))/15 + \ + sqrt(30)*TensorProduct(JzKet(S(1)/2, -S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, 1), JzKet(1, -1))/20 + \ + sqrt(30)*TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, -S(1)/2), JzKet(1, -1), JzKet(1, 1))/20 - \ + sqrt(30)*TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, -S(1)/2), JzKet(1, 0), JzKet(1, 0))/15 + \ + sqrt(30)*TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, -S(1)/2), JzKet(1, 1), JzKet(1, -1))/20 - \ + sqrt(15)*TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, -1), JzKet(1, 0))/15 + \ + sqrt(15)*TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, + S(1)/2), JzKet(1, 0), JzKet(1, -1))/10 + assert uncouple(JzKetCoupled(1, -1, (S(1)/2, S(1)/2, 1, 1))) == \ + sqrt(15)*TensorProduct(JzKet(S(1)/2, -S(1)/2), JzKet(S(1)/2, -S(1)/2), JzKet(1, -1), JzKet(1, 1))/5 - \ + sqrt(15)*TensorProduct(JzKet(S(1)/2, -S(1)/2), JzKet(S(1)/2, -S(1)/2), JzKet(1, 0), JzKet(1, 0))/10 + \ + sqrt(15)*TensorProduct(JzKet(S(1)/2, -S(1)/2), JzKet(S(1)/2, -S(1)/2), JzKet(1, 1), JzKet(1, -1))/30 - \ + sqrt(30)*TensorProduct(JzKet(S(1)/2, -S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, -1), JzKet(1, 0))/20 + \ + sqrt(30)*TensorProduct(JzKet(S(1)/2, -S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, 0), JzKet(1, -1))/30 - \ + sqrt(30)*TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, -S(1)/2), JzKet(1, -1), JzKet(1, 0))/20 + \ + sqrt(30)*TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, -S(1)/2), JzKet(1, 0), JzKet(1, -1))/30 + \ + sqrt(15)*TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, + S(1)/2), JzKet(1, -1), JzKet(1, -1))/30 # j1=1/2, j2=1/2, j3=1, j4=1, j12=1, j34=1 - assert uncouple(JzKetCoupled(2, 2, (S(1)/2,S(1)/2,1,1), ((1,2,1),(3,4,1),(1,3,2)))) == \ - -sqrt(2)*TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,0), JzKet(1,1))/2 + \ - sqrt(2)*TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,1), JzKet(1,0))/2 - assert uncouple(JzKetCoupled(2, 1, (S(1)/2,S(1)/2,1,1), ((1,2,1),(3,4,1),(1,3,2)))) == \ - -sqrt(2)*TensorProduct(JzKet(S(1)/2,-S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,0), JzKet(1,1))/4 + \ - sqrt(2)*TensorProduct(JzKet(S(1)/2,-S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,1), JzKet(1,0))/4 - \ - sqrt(2)*TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,-S(1)/2), JzKet(1,0), JzKet(1,1))/4 + \ - sqrt(2)*TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,-S(1)/2), JzKet(1,1), JzKet(1,0))/4 - \ - TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,-1), JzKet(1,1))/2 + \ - TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,1), JzKet(1,-1))/2 - assert uncouple(JzKetCoupled(2, 0, (S(1)/2,S(1)/2,1,1), ((1,2,1),(3,4,1),(1,3,2)))) == \ - -sqrt(3)*TensorProduct(JzKet(S(1)/2,-S(1)/2), JzKet(S(1)/2,-S(1)/2), JzKet(1,0), JzKet(1,1))/6 + \ - sqrt(3)*TensorProduct(JzKet(S(1)/2,-S(1)/2), JzKet(S(1)/2,-S(1)/2), JzKet(1,1), JzKet(1,0))/6 - \ - sqrt(6)*TensorProduct(JzKet(S(1)/2,-S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,-1), JzKet(1,1))/6 + \ - sqrt(6)*TensorProduct(JzKet(S(1)/2,-S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,1), JzKet(1,-1))/6 - \ - sqrt(6)*TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,-S(1)/2), JzKet(1,-1), JzKet(1,1))/6 + \ - sqrt(6)*TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,-S(1)/2), JzKet(1,1), JzKet(1,-1))/6 - \ - sqrt(3)*TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,-1), JzKet(1,0))/6 + \ - sqrt(3)*TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,0), JzKet(1,-1))/6 - assert uncouple(JzKetCoupled(2, -1, (S(1)/2,S(1)/2,1,1), ((1,2,1),(3,4,1),(1,3,2)))) == \ - -TensorProduct(JzKet(S(1)/2,-S(1)/2), JzKet(S(1)/2,-S(1)/2), JzKet(1,-1), JzKet(1,1))/2 + \ - TensorProduct(JzKet(S(1)/2,-S(1)/2), JzKet(S(1)/2,-S(1)/2), JzKet(1,1), JzKet(1,-1))/2 - \ - sqrt(2)*TensorProduct(JzKet(S(1)/2,-S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,-1), JzKet(1,0))/4 + \ - sqrt(2)*TensorProduct(JzKet(S(1)/2,-S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,0), JzKet(1,-1))/4 - \ - sqrt(2)*TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,-S(1)/2), JzKet(1,-1), JzKet(1,0))/4 + \ - sqrt(2)*TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,-S(1)/2), JzKet(1,0), JzKet(1,-1))/4 - assert uncouple(JzKetCoupled(2, -2, (S(1)/2,S(1)/2,1,1), ((1,2,1),(3,4,1),(1,3,2)))) == \ - -sqrt(2)*TensorProduct(JzKet(S(1)/2,-S(1)/2), JzKet(S(1)/2,-S(1)/2), JzKet(1,-1), JzKet(1,0))/2 + \ - sqrt(2)*TensorProduct(JzKet(S(1)/2,-S(1)/2), JzKet(S(1)/2,-S(1)/2), JzKet(1,0), JzKet(1,-1))/2 - assert uncouple(JzKetCoupled(1, 1, (S(1)/2,S(1)/2,1,1), ((1,2,1),(3,4,1),(1,3,1)))) == \ - sqrt(2)*TensorProduct(JzKet(S(1)/2,-S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,0), JzKet(1,1))/4 - \ - sqrt(2)*TensorProduct(JzKet(S(1)/2,-S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,1), JzKet(1,0))/4 + \ - sqrt(2)*TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,-S(1)/2), JzKet(1,0), JzKet(1,1))/4 - \ - sqrt(2)*TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,-S(1)/2), JzKet(1,1), JzKet(1,0))/4 - \ - TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,-1), JzKet(1,1))/2 + \ - TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,1), JzKet(1,-1))/2 - assert uncouple(JzKetCoupled(1, 0, (S(1)/2,S(1)/2,1,1), ((1,2,1),(3,4,1),(1,3,1)))) == \ - TensorProduct(JzKet(S(1)/2,-S(1)/2), JzKet(S(1)/2,-S(1)/2), JzKet(1,0), JzKet(1,1))/2 - \ - TensorProduct(JzKet(S(1)/2,-S(1)/2), JzKet(S(1)/2,-S(1)/2), JzKet(1,1), JzKet(1,0))/2 - \ - TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,-1), JzKet(1,0))/2 + \ - TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,0), JzKet(1,-1))/2 - assert uncouple(JzKetCoupled(1, -1, (S(1)/2,S(1)/2,1,1), ((1,2,1),(3,4,1),(1,3,1)))) == \ - TensorProduct(JzKet(S(1)/2,-S(1)/2), JzKet(S(1)/2,-S(1)/2), JzKet(1,-1), JzKet(1,1))/2 - \ - TensorProduct(JzKet(S(1)/2,-S(1)/2), JzKet(S(1)/2,-S(1)/2), JzKet(1,1), JzKet(1,-1))/2 - \ - sqrt(2)*TensorProduct(JzKet(S(1)/2,-S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,-1), JzKet(1,0))/4 + \ - sqrt(2)*TensorProduct(JzKet(S(1)/2,-S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,0), JzKet(1,-1))/4 - \ - sqrt(2)*TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,-S(1)/2), JzKet(1,-1), JzKet(1,0))/4 + \ - sqrt(2)*TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,-S(1)/2), JzKet(1,0), JzKet(1,-1))/4 + assert uncouple(JzKetCoupled(2, 2, (S(1)/2, S(1)/2, 1, 1), ((1, 2, 1), (3, 4, 1), (1, 3, 2)))) == \ + -sqrt(2)*TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, 0), JzKet(1, 1))/2 + \ + sqrt(2)*TensorProduct(JzKet(S( + 1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, 1), JzKet(1, 0))/2 + assert uncouple(JzKetCoupled(2, 1, (S(1)/2, S(1)/2, 1, 1), ((1, 2, 1), (3, 4, 1), (1, 3, 2)))) == \ + -sqrt(2)*TensorProduct(JzKet(S(1)/2, -S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, 0), JzKet(1, 1))/4 + \ + sqrt(2)*TensorProduct(JzKet(S(1)/2, -S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, 1), JzKet(1, 0))/4 - \ + sqrt(2)*TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, -S(1)/2), JzKet(1, 0), JzKet(1, 1))/4 + \ + sqrt(2)*TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, -S(1)/2), JzKet(1, 1), JzKet(1, 0))/4 - \ + TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, -1), JzKet(1, 1))/2 + \ + TensorProduct(JzKet(S( + 1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, 1), JzKet(1, -1))/2 + assert uncouple(JzKetCoupled(2, 0, (S(1)/2, S(1)/2, 1, 1), ((1, 2, 1), (3, 4, 1), (1, 3, 2)))) == \ + -sqrt(3)*TensorProduct(JzKet(S(1)/2, -S(1)/2), JzKet(S(1)/2, -S(1)/2), JzKet(1, 0), JzKet(1, 1))/6 + \ + sqrt(3)*TensorProduct(JzKet(S(1)/2, -S(1)/2), JzKet(S(1)/2, -S(1)/2), JzKet(1, 1), JzKet(1, 0))/6 - \ + sqrt(6)*TensorProduct(JzKet(S(1)/2, -S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, -1), JzKet(1, 1))/6 + \ + sqrt(6)*TensorProduct(JzKet(S(1)/2, -S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, 1), JzKet(1, -1))/6 - \ + sqrt(6)*TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, -S(1)/2), JzKet(1, -1), JzKet(1, 1))/6 + \ + sqrt(6)*TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, -S(1)/2), JzKet(1, 1), JzKet(1, -1))/6 - \ + sqrt(3)*TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, -1), JzKet(1, 0))/6 + \ + sqrt(3)*TensorProduct(JzKet(S( + 1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, 0), JzKet(1, -1))/6 + assert uncouple(JzKetCoupled(2, -1, (S(1)/2, S(1)/2, 1, 1), ((1, 2, 1), (3, 4, 1), (1, 3, 2)))) == \ + -TensorProduct(JzKet(S(1)/2, -S(1)/2), JzKet(S(1)/2, -S(1)/2), JzKet(1, -1), JzKet(1, 1))/2 + \ + TensorProduct(JzKet(S(1)/2, -S(1)/2), JzKet(S(1)/2, -S(1)/2), JzKet(1, 1), JzKet(1, -1))/2 - \ + sqrt(2)*TensorProduct(JzKet(S(1)/2, -S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, -1), JzKet(1, 0))/4 + \ + sqrt(2)*TensorProduct(JzKet(S(1)/2, -S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, 0), JzKet(1, -1))/4 - \ + sqrt(2)*TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, -S(1)/2), JzKet(1, -1), JzKet(1, 0))/4 + \ + sqrt(2)*TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, + -S(1)/2), JzKet(1, 0), JzKet(1, -1))/4 + assert uncouple(JzKetCoupled(2, -2, (S(1)/2, S(1)/2, 1, 1), ((1, 2, 1), (3, 4, 1), (1, 3, 2)))) == \ + -sqrt(2)*TensorProduct(JzKet(S(1)/2, -S(1)/2), JzKet(S(1)/2, -S(1)/2), JzKet(1, -1), JzKet(1, 0))/2 + \ + sqrt(2)*TensorProduct(JzKet(S(1)/2, -S(1)/2), JzKet(S(1)/2, + -S(1)/2), JzKet(1, 0), JzKet(1, -1))/2 + assert uncouple(JzKetCoupled(1, 1, (S(1)/2, S(1)/2, 1, 1), ((1, 2, 1), (3, 4, 1), (1, 3, 1)))) == \ + sqrt(2)*TensorProduct(JzKet(S(1)/2, -S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, 0), JzKet(1, 1))/4 - \ + sqrt(2)*TensorProduct(JzKet(S(1)/2, -S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, 1), JzKet(1, 0))/4 + \ + sqrt(2)*TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, -S(1)/2), JzKet(1, 0), JzKet(1, 1))/4 - \ + sqrt(2)*TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, -S(1)/2), JzKet(1, 1), JzKet(1, 0))/4 - \ + TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, -1), JzKet(1, 1))/2 + \ + TensorProduct(JzKet(S( + 1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, 1), JzKet(1, -1))/2 + assert uncouple(JzKetCoupled(1, 0, (S(1)/2, S(1)/2, 1, 1), ((1, 2, 1), (3, 4, 1), (1, 3, 1)))) == \ + TensorProduct(JzKet(S(1)/2, -S(1)/2), JzKet(S(1)/2, -S(1)/2), JzKet(1, 0), JzKet(1, 1))/2 - \ + TensorProduct(JzKet(S(1)/2, -S(1)/2), JzKet(S(1)/2, -S(1)/2), JzKet(1, 1), JzKet(1, 0))/2 - \ + TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, -1), JzKet(1, 0))/2 + \ + TensorProduct(JzKet(S( + 1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, 0), JzKet(1, -1))/2 + assert uncouple(JzKetCoupled(1, -1, (S(1)/2, S(1)/2, 1, 1), ((1, 2, 1), (3, 4, 1), (1, 3, 1)))) == \ + TensorProduct(JzKet(S(1)/2, -S(1)/2), JzKet(S(1)/2, -S(1)/2), JzKet(1, -1), JzKet(1, 1))/2 - \ + TensorProduct(JzKet(S(1)/2, -S(1)/2), JzKet(S(1)/2, -S(1)/2), JzKet(1, 1), JzKet(1, -1))/2 - \ + sqrt(2)*TensorProduct(JzKet(S(1)/2, -S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, -1), JzKet(1, 0))/4 + \ + sqrt(2)*TensorProduct(JzKet(S(1)/2, -S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, 0), JzKet(1, -1))/4 - \ + sqrt(2)*TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, -S(1)/2), JzKet(1, -1), JzKet(1, 0))/4 + \ + sqrt(2)*TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, + -S(1)/2), JzKet(1, 0), JzKet(1, -1))/4 # j1=1/2, j2=1/2, j3=1, j4=1, j12=1, j34=2 - assert uncouple(JzKetCoupled(3, 3, (S(1)/2,S(1)/2,1,1), ((1,2,1),(3,4,2),(1,3,3)))) == \ - TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,1), JzKet(1,1)) - assert uncouple(JzKetCoupled(3, 2, (S(1)/2,S(1)/2,1,1), ((1,2,1),(3,4,2),(1,3,3)))) == \ - sqrt(6)*TensorProduct(JzKet(S(1)/2,-S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,1), JzKet(1,1))/6 + \ - sqrt(6)*TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,-S(1)/2), JzKet(1,1), JzKet(1,1))/6 + \ - sqrt(3)*TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,0), JzKet(1,1))/3 + \ - sqrt(3)*TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,1), JzKet(1,0))/3 - assert uncouple(JzKetCoupled(3, 1, (S(1)/2,S(1)/2,1,1), ((1,2,1),(3,4,2),(1,3,3)))) == \ - sqrt(15)*TensorProduct(JzKet(S(1)/2,-S(1)/2), JzKet(S(1)/2,-S(1)/2), JzKet(1,1), JzKet(1,1))/15 + \ - sqrt(30)*TensorProduct(JzKet(S(1)/2,-S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,0), JzKet(1,1))/15 + \ - sqrt(30)*TensorProduct(JzKet(S(1)/2,-S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,1), JzKet(1,0))/15 + \ - sqrt(30)*TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,-S(1)/2), JzKet(1,0), JzKet(1,1))/15 + \ - sqrt(30)*TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,-S(1)/2), JzKet(1,1), JzKet(1,0))/15 + \ - sqrt(15)*TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,-1), JzKet(1,1))/15 + \ - 2*sqrt(15)*TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,0), JzKet(1,0))/15 + \ - sqrt(15)*TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,1), JzKet(1,-1))/15 - assert uncouple(JzKetCoupled(3, 0, (S(1)/2,S(1)/2,1,1), ((1,2,1),(3,4,2),(1,3,3)))) == \ - sqrt(10)*TensorProduct(JzKet(S(1)/2,-S(1)/2), JzKet(S(1)/2,-S(1)/2), JzKet(1,0), JzKet(1,1))/10 + \ - sqrt(10)*TensorProduct(JzKet(S(1)/2,-S(1)/2), JzKet(S(1)/2,-S(1)/2), JzKet(1,1), JzKet(1,0))/10 + \ - sqrt(5)*TensorProduct(JzKet(S(1)/2,-S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,-1), JzKet(1,1))/10 + \ - sqrt(5)*TensorProduct(JzKet(S(1)/2,-S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,0), JzKet(1,0))/5 + \ - sqrt(5)*TensorProduct(JzKet(S(1)/2,-S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,1), JzKet(1,-1))/10 + \ - sqrt(5)*TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,-S(1)/2), JzKet(1,-1), JzKet(1,1))/10 + \ - sqrt(5)*TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,-S(1)/2), JzKet(1,0), JzKet(1,0))/5 + \ - sqrt(5)*TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,-S(1)/2), JzKet(1,1), JzKet(1,-1))/10 + \ - sqrt(10)*TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,-1), JzKet(1,0))/10 + \ - sqrt(10)*TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,0), JzKet(1,-1))/10 - assert uncouple(JzKetCoupled(3, -1, (S(1)/2,S(1)/2,1,1), ((1,2,1),(3,4,2),(1,3,3)))) == \ - sqrt(15)*TensorProduct(JzKet(S(1)/2,-S(1)/2), JzKet(S(1)/2,-S(1)/2), JzKet(1,-1), JzKet(1,1))/15 + \ - 2*sqrt(15)*TensorProduct(JzKet(S(1)/2,-S(1)/2), JzKet(S(1)/2,-S(1)/2), JzKet(1,0), JzKet(1,0))/15 + \ - sqrt(15)*TensorProduct(JzKet(S(1)/2,-S(1)/2), JzKet(S(1)/2,-S(1)/2), JzKet(1,1), JzKet(1,-1))/15 + \ - sqrt(30)*TensorProduct(JzKet(S(1)/2,-S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,-1), JzKet(1,0))/15 + \ - sqrt(30)*TensorProduct(JzKet(S(1)/2,-S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,0), JzKet(1,-1))/15 + \ - sqrt(30)*TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,-S(1)/2), JzKet(1,-1), JzKet(1,0))/15 + \ - sqrt(30)*TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,-S(1)/2), JzKet(1,0), JzKet(1,-1))/15 + \ - sqrt(15)*TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,-1), JzKet(1,-1))/15 - assert uncouple(JzKetCoupled(3, -2, (S(1)/2,S(1)/2,1,1), ((1,2,1),(3,4,2),(1,3,3)))) == \ - sqrt(3)*TensorProduct(JzKet(S(1)/2,-S(1)/2), JzKet(S(1)/2,-S(1)/2), JzKet(1,-1), JzKet(1,0))/3 + \ - sqrt(3)*TensorProduct(JzKet(S(1)/2,-S(1)/2), JzKet(S(1)/2,-S(1)/2), JzKet(1,0), JzKet(1,-1))/3 + \ - sqrt(6)*TensorProduct(JzKet(S(1)/2,-S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,-1), JzKet(1,-1))/6 + \ - sqrt(6)*TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,-S(1)/2), JzKet(1,-1), JzKet(1,-1))/6 - assert uncouple(JzKetCoupled(3, -3, (S(1)/2,S(1)/2,1,1), ((1,2,1),(3,4,2),(1,3,3)))) == \ - TensorProduct(JzKet(S(1)/2,-S(1)/2), JzKet(S(1)/2,-S(1)/2), JzKet(1,-1), JzKet(1,-1)) - assert uncouple(JzKetCoupled(2, 2, (S(1)/2,S(1)/2,1,1), ((1,2,1),(3,4,2),(1,3,2)))) == \ - -sqrt(3)*TensorProduct(JzKet(S(1)/2,-S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,1), JzKet(1,1))/3 - \ - sqrt(3)*TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,-S(1)/2), JzKet(1,1), JzKet(1,1))/3 + \ - sqrt(6)*TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,0), JzKet(1,1))/6 + \ - sqrt(6)*TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,1), JzKet(1,0))/6 - assert uncouple(JzKetCoupled(2, 1, (S(1)/2,S(1)/2,1,1), ((1,2,1),(3,4,2),(1,3,2)))) == \ - -sqrt(3)*TensorProduct(JzKet(S(1)/2,-S(1)/2), JzKet(S(1)/2,-S(1)/2), JzKet(1,1), JzKet(1,1))/3 - \ - sqrt(6)*TensorProduct(JzKet(S(1)/2,-S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,0), JzKet(1,1))/12 - \ - sqrt(6)*TensorProduct(JzKet(S(1)/2,-S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,1), JzKet(1,0))/12 - \ - sqrt(6)*TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,-S(1)/2), JzKet(1,0), JzKet(1,1))/12 - \ - sqrt(6)*TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,-S(1)/2), JzKet(1,1), JzKet(1,0))/12 + \ - sqrt(3)*TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,-1), JzKet(1,1))/6 + \ - sqrt(3)*TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,0), JzKet(1,0))/3 + \ - sqrt(3)*TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,1), JzKet(1,-1))/6 - assert uncouple(JzKetCoupled(2, 0, (S(1)/2,S(1)/2,1,1), ((1,2,1),(3,4,2),(1,3,2)))) == \ - -TensorProduct(JzKet(S(1)/2,-S(1)/2), JzKet(S(1)/2,-S(1)/2), JzKet(1,0), JzKet(1,1))/2 - \ - TensorProduct(JzKet(S(1)/2,-S(1)/2), JzKet(S(1)/2,-S(1)/2), JzKet(1,1), JzKet(1,0))/2 + \ - TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,-1), JzKet(1,0))/2 + \ - TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,0), JzKet(1,-1))/2 - assert uncouple(JzKetCoupled(2, -1, (S(1)/2,S(1)/2,1,1), ((1,2,1),(3,4,2),(1,3,2)))) == \ - -sqrt(3)*TensorProduct(JzKet(S(1)/2,-S(1)/2), JzKet(S(1)/2,-S(1)/2), JzKet(1,-1), JzKet(1,1))/6 - \ - sqrt(3)*TensorProduct(JzKet(S(1)/2,-S(1)/2), JzKet(S(1)/2,-S(1)/2), JzKet(1,0), JzKet(1,0))/3 - \ - sqrt(3)*TensorProduct(JzKet(S(1)/2,-S(1)/2), JzKet(S(1)/2,-S(1)/2), JzKet(1,1), JzKet(1,-1))/6 + \ - sqrt(6)*TensorProduct(JzKet(S(1)/2,-S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,-1), JzKet(1,0))/12 + \ - sqrt(6)*TensorProduct(JzKet(S(1)/2,-S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,0), JzKet(1,-1))/12 + \ - sqrt(6)*TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,-S(1)/2), JzKet(1,-1), JzKet(1,0))/12 + \ - sqrt(6)*TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,-S(1)/2), JzKet(1,0), JzKet(1,-1))/12 + \ - sqrt(3)*TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,-1), JzKet(1,-1))/3 - assert uncouple(JzKetCoupled(2, -2, (S(1)/2,S(1)/2,1,1), ((1,2,1),(3,4,2),(1,3,2)))) == \ - -sqrt(6)*TensorProduct(JzKet(S(1)/2,-S(1)/2), JzKet(S(1)/2,-S(1)/2), JzKet(1,-1), JzKet(1,0))/6 - \ - sqrt(6)*TensorProduct(JzKet(S(1)/2,-S(1)/2), JzKet(S(1)/2,-S(1)/2), JzKet(1,0), JzKet(1,-1))/6 + \ - sqrt(3)*TensorProduct(JzKet(S(1)/2,-S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,-1), JzKet(1,-1))/3 + \ - sqrt(3)*TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,-S(1)/2), JzKet(1,-1), JzKet(1,-1))/3 - assert uncouple(JzKetCoupled(1, 1, (S(1)/2,S(1)/2,1,1), ((1,2,1),(3,4,2),(1,3,1)))) == \ - sqrt(15)*TensorProduct(JzKet(S(1)/2,-S(1)/2), JzKet(S(1)/2,-S(1)/2), JzKet(1,1), JzKet(1,1))/5 - \ - sqrt(30)*TensorProduct(JzKet(S(1)/2,-S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,0), JzKet(1,1))/20 - \ - sqrt(30)*TensorProduct(JzKet(S(1)/2,-S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,1), JzKet(1,0))/20 - \ - sqrt(30)*TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,-S(1)/2), JzKet(1,0), JzKet(1,1))/20 - \ - sqrt(30)*TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,-S(1)/2), JzKet(1,1), JzKet(1,0))/20 + \ - sqrt(15)*TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,-1), JzKet(1,1))/30 + \ - sqrt(15)*TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,0), JzKet(1,0))/15 + \ - sqrt(15)*TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,1), JzKet(1,-1))/30 - assert uncouple(JzKetCoupled(1, 0, (S(1)/2,S(1)/2,1,1), ((1,2,1),(3,4,2),(1,3,1)))) == \ - sqrt(15)*TensorProduct(JzKet(S(1)/2,-S(1)/2), JzKet(S(1)/2,-S(1)/2), JzKet(1,0), JzKet(1,1))/10 + \ - sqrt(15)*TensorProduct(JzKet(S(1)/2,-S(1)/2), JzKet(S(1)/2,-S(1)/2), JzKet(1,1), JzKet(1,0))/10 - \ - sqrt(30)*TensorProduct(JzKet(S(1)/2,-S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,-1), JzKet(1,1))/30 - \ - sqrt(30)*TensorProduct(JzKet(S(1)/2,-S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,0), JzKet(1,0))/15 - \ - sqrt(30)*TensorProduct(JzKet(S(1)/2,-S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,1), JzKet(1,-1))/30 - \ - sqrt(30)*TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,-S(1)/2), JzKet(1,-1), JzKet(1,1))/30 - \ - sqrt(30)*TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,-S(1)/2), JzKet(1,0), JzKet(1,0))/15 - \ - sqrt(30)*TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,-S(1)/2), JzKet(1,1), JzKet(1,-1))/30 + \ - sqrt(15)*TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,-1), JzKet(1,0))/10 + \ - sqrt(15)*TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,0), JzKet(1,-1))/10 - assert uncouple(JzKetCoupled(1, -1, (S(1)/2,S(1)/2,1,1), ((1,2,1),(3,4,2),(1,3,1)))) == \ - sqrt(15)*TensorProduct(JzKet(S(1)/2,-S(1)/2), JzKet(S(1)/2,-S(1)/2), JzKet(1,-1), JzKet(1,1))/30 + \ - sqrt(15)*TensorProduct(JzKet(S(1)/2,-S(1)/2), JzKet(S(1)/2,-S(1)/2), JzKet(1,0), JzKet(1,0))/15 + \ - sqrt(15)*TensorProduct(JzKet(S(1)/2,-S(1)/2), JzKet(S(1)/2,-S(1)/2), JzKet(1,1), JzKet(1,-1))/30 - \ - sqrt(30)*TensorProduct(JzKet(S(1)/2,-S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,-1), JzKet(1,0))/20 - \ - sqrt(30)*TensorProduct(JzKet(S(1)/2,-S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,0), JzKet(1,-1))/20 - \ - sqrt(30)*TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,-S(1)/2), JzKet(1,-1), JzKet(1,0))/20 - \ - sqrt(30)*TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,-S(1)/2), JzKet(1,0), JzKet(1,-1))/20 + \ - sqrt(15)*TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,-1), JzKet(1,-1))/5 + assert uncouple(JzKetCoupled(3, 3, (S(1)/2, S(1)/2, 1, 1), ((1, 2, 1), (3, 4, 2), (1, 3, 3)))) == \ + TensorProduct(JzKet( + S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, 1), JzKet(1, 1)) + assert uncouple(JzKetCoupled(3, 2, (S(1)/2, S(1)/2, 1, 1), ((1, 2, 1), (3, 4, 2), (1, 3, 3)))) == \ + sqrt(6)*TensorProduct(JzKet(S(1)/2, -S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, 1), JzKet(1, 1))/6 + \ + sqrt(6)*TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, -S(1)/2), JzKet(1, 1), JzKet(1, 1))/6 + \ + sqrt(3)*TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, 0), JzKet(1, 1))/3 + \ + sqrt(3)*TensorProduct(JzKet(S( + 1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, 1), JzKet(1, 0))/3 + assert uncouple(JzKetCoupled(3, 1, (S(1)/2, S(1)/2, 1, 1), ((1, 2, 1), (3, 4, 2), (1, 3, 3)))) == \ + sqrt(15)*TensorProduct(JzKet(S(1)/2, -S(1)/2), JzKet(S(1)/2, -S(1)/2), JzKet(1, 1), JzKet(1, 1))/15 + \ + sqrt(30)*TensorProduct(JzKet(S(1)/2, -S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, 0), JzKet(1, 1))/15 + \ + sqrt(30)*TensorProduct(JzKet(S(1)/2, -S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, 1), JzKet(1, 0))/15 + \ + sqrt(30)*TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, -S(1)/2), JzKet(1, 0), JzKet(1, 1))/15 + \ + sqrt(30)*TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, -S(1)/2), JzKet(1, 1), JzKet(1, 0))/15 + \ + sqrt(15)*TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, -1), JzKet(1, 1))/15 + \ + 2*sqrt(15)*TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, 0), JzKet(1, 0))/15 + \ + sqrt(15)*TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, + S(1)/2), JzKet(1, 1), JzKet(1, -1))/15 + assert uncouple(JzKetCoupled(3, 0, (S(1)/2, S(1)/2, 1, 1), ((1, 2, 1), (3, 4, 2), (1, 3, 3)))) == \ + sqrt(10)*TensorProduct(JzKet(S(1)/2, -S(1)/2), JzKet(S(1)/2, -S(1)/2), JzKet(1, 0), JzKet(1, 1))/10 + \ + sqrt(10)*TensorProduct(JzKet(S(1)/2, -S(1)/2), JzKet(S(1)/2, -S(1)/2), JzKet(1, 1), JzKet(1, 0))/10 + \ + sqrt(5)*TensorProduct(JzKet(S(1)/2, -S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, -1), JzKet(1, 1))/10 + \ + sqrt(5)*TensorProduct(JzKet(S(1)/2, -S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, 0), JzKet(1, 0))/5 + \ + sqrt(5)*TensorProduct(JzKet(S(1)/2, -S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, 1), JzKet(1, -1))/10 + \ + sqrt(5)*TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, -S(1)/2), JzKet(1, -1), JzKet(1, 1))/10 + \ + sqrt(5)*TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, -S(1)/2), JzKet(1, 0), JzKet(1, 0))/5 + \ + sqrt(5)*TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, -S(1)/2), JzKet(1, 1), JzKet(1, -1))/10 + \ + sqrt(10)*TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, -1), JzKet(1, 0))/10 + \ + sqrt(10)*TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, + S(1)/2), JzKet(1, 0), JzKet(1, -1))/10 + assert uncouple(JzKetCoupled(3, -1, (S(1)/2, S(1)/2, 1, 1), ((1, 2, 1), (3, 4, 2), (1, 3, 3)))) == \ + sqrt(15)*TensorProduct(JzKet(S(1)/2, -S(1)/2), JzKet(S(1)/2, -S(1)/2), JzKet(1, -1), JzKet(1, 1))/15 + \ + 2*sqrt(15)*TensorProduct(JzKet(S(1)/2, -S(1)/2), JzKet(S(1)/2, -S(1)/2), JzKet(1, 0), JzKet(1, 0))/15 + \ + sqrt(15)*TensorProduct(JzKet(S(1)/2, -S(1)/2), JzKet(S(1)/2, -S(1)/2), JzKet(1, 1), JzKet(1, -1))/15 + \ + sqrt(30)*TensorProduct(JzKet(S(1)/2, -S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, -1), JzKet(1, 0))/15 + \ + sqrt(30)*TensorProduct(JzKet(S(1)/2, -S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, 0), JzKet(1, -1))/15 + \ + sqrt(30)*TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, -S(1)/2), JzKet(1, -1), JzKet(1, 0))/15 + \ + sqrt(30)*TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, -S(1)/2), JzKet(1, 0), JzKet(1, -1))/15 + \ + sqrt(15)*TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, + S(1)/2), JzKet(1, -1), JzKet(1, -1))/15 + assert uncouple(JzKetCoupled(3, -2, (S(1)/2, S(1)/2, 1, 1), ((1, 2, 1), (3, 4, 2), (1, 3, 3)))) == \ + sqrt(3)*TensorProduct(JzKet(S(1)/2, -S(1)/2), JzKet(S(1)/2, -S(1)/2), JzKet(1, -1), JzKet(1, 0))/3 + \ + sqrt(3)*TensorProduct(JzKet(S(1)/2, -S(1)/2), JzKet(S(1)/2, -S(1)/2), JzKet(1, 0), JzKet(1, -1))/3 + \ + sqrt(6)*TensorProduct(JzKet(S(1)/2, -S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, -1), JzKet(1, -1))/6 + \ + sqrt(6)*TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, + -S(1)/2), JzKet(1, -1), JzKet(1, -1))/6 + assert uncouple(JzKetCoupled(3, -3, (S(1)/2, S(1)/2, 1, 1), ((1, 2, 1), (3, 4, 2), (1, 3, 3)))) == \ + TensorProduct(JzKet(S(1)/2, -S( + 1)/2), JzKet(S(1)/2, -S(1)/2), JzKet(1, -1), JzKet(1, -1)) + assert uncouple(JzKetCoupled(2, 2, (S(1)/2, S(1)/2, 1, 1), ((1, 2, 1), (3, 4, 2), (1, 3, 2)))) == \ + -sqrt(3)*TensorProduct(JzKet(S(1)/2, -S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, 1), JzKet(1, 1))/3 - \ + sqrt(3)*TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, -S(1)/2), JzKet(1, 1), JzKet(1, 1))/3 + \ + sqrt(6)*TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, 0), JzKet(1, 1))/6 + \ + sqrt(6)*TensorProduct(JzKet(S( + 1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, 1), JzKet(1, 0))/6 + assert uncouple(JzKetCoupled(2, 1, (S(1)/2, S(1)/2, 1, 1), ((1, 2, 1), (3, 4, 2), (1, 3, 2)))) == \ + -sqrt(3)*TensorProduct(JzKet(S(1)/2, -S(1)/2), JzKet(S(1)/2, -S(1)/2), JzKet(1, 1), JzKet(1, 1))/3 - \ + sqrt(6)*TensorProduct(JzKet(S(1)/2, -S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, 0), JzKet(1, 1))/12 - \ + sqrt(6)*TensorProduct(JzKet(S(1)/2, -S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, 1), JzKet(1, 0))/12 - \ + sqrt(6)*TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, -S(1)/2), JzKet(1, 0), JzKet(1, 1))/12 - \ + sqrt(6)*TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, -S(1)/2), JzKet(1, 1), JzKet(1, 0))/12 + \ + sqrt(3)*TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, -1), JzKet(1, 1))/6 + \ + sqrt(3)*TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, 0), JzKet(1, 0))/3 + \ + sqrt(3)*TensorProduct(JzKet(S( + 1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, 1), JzKet(1, -1))/6 + assert uncouple(JzKetCoupled(2, 0, (S(1)/2, S(1)/2, 1, 1), ((1, 2, 1), (3, 4, 2), (1, 3, 2)))) == \ + -TensorProduct(JzKet(S(1)/2, -S(1)/2), JzKet(S(1)/2, -S(1)/2), JzKet(1, 0), JzKet(1, 1))/2 - \ + TensorProduct(JzKet(S(1)/2, -S(1)/2), JzKet(S(1)/2, -S(1)/2), JzKet(1, 1), JzKet(1, 0))/2 + \ + TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, -1), JzKet(1, 0))/2 + \ + TensorProduct(JzKet(S( + 1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, 0), JzKet(1, -1))/2 + assert uncouple(JzKetCoupled(2, -1, (S(1)/2, S(1)/2, 1, 1), ((1, 2, 1), (3, 4, 2), (1, 3, 2)))) == \ + -sqrt(3)*TensorProduct(JzKet(S(1)/2, -S(1)/2), JzKet(S(1)/2, -S(1)/2), JzKet(1, -1), JzKet(1, 1))/6 - \ + sqrt(3)*TensorProduct(JzKet(S(1)/2, -S(1)/2), JzKet(S(1)/2, -S(1)/2), JzKet(1, 0), JzKet(1, 0))/3 - \ + sqrt(3)*TensorProduct(JzKet(S(1)/2, -S(1)/2), JzKet(S(1)/2, -S(1)/2), JzKet(1, 1), JzKet(1, -1))/6 + \ + sqrt(6)*TensorProduct(JzKet(S(1)/2, -S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, -1), JzKet(1, 0))/12 + \ + sqrt(6)*TensorProduct(JzKet(S(1)/2, -S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, 0), JzKet(1, -1))/12 + \ + sqrt(6)*TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, -S(1)/2), JzKet(1, -1), JzKet(1, 0))/12 + \ + sqrt(6)*TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, -S(1)/2), JzKet(1, 0), JzKet(1, -1))/12 + \ + sqrt(3)*TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, + S(1)/2), JzKet(1, -1), JzKet(1, -1))/3 + assert uncouple(JzKetCoupled(2, -2, (S(1)/2, S(1)/2, 1, 1), ((1, 2, 1), (3, 4, 2), (1, 3, 2)))) == \ + -sqrt(6)*TensorProduct(JzKet(S(1)/2, -S(1)/2), JzKet(S(1)/2, -S(1)/2), JzKet(1, -1), JzKet(1, 0))/6 - \ + sqrt(6)*TensorProduct(JzKet(S(1)/2, -S(1)/2), JzKet(S(1)/2, -S(1)/2), JzKet(1, 0), JzKet(1, -1))/6 + \ + sqrt(3)*TensorProduct(JzKet(S(1)/2, -S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, -1), JzKet(1, -1))/3 + \ + sqrt(3)*TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, + -S(1)/2), JzKet(1, -1), JzKet(1, -1))/3 + assert uncouple(JzKetCoupled(1, 1, (S(1)/2, S(1)/2, 1, 1), ((1, 2, 1), (3, 4, 2), (1, 3, 1)))) == \ + sqrt(15)*TensorProduct(JzKet(S(1)/2, -S(1)/2), JzKet(S(1)/2, -S(1)/2), JzKet(1, 1), JzKet(1, 1))/5 - \ + sqrt(30)*TensorProduct(JzKet(S(1)/2, -S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, 0), JzKet(1, 1))/20 - \ + sqrt(30)*TensorProduct(JzKet(S(1)/2, -S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, 1), JzKet(1, 0))/20 - \ + sqrt(30)*TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, -S(1)/2), JzKet(1, 0), JzKet(1, 1))/20 - \ + sqrt(30)*TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, -S(1)/2), JzKet(1, 1), JzKet(1, 0))/20 + \ + sqrt(15)*TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, -1), JzKet(1, 1))/30 + \ + sqrt(15)*TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, 0), JzKet(1, 0))/15 + \ + sqrt(15)*TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, + S(1)/2), JzKet(1, 1), JzKet(1, -1))/30 + assert uncouple(JzKetCoupled(1, 0, (S(1)/2, S(1)/2, 1, 1), ((1, 2, 1), (3, 4, 2), (1, 3, 1)))) == \ + sqrt(15)*TensorProduct(JzKet(S(1)/2, -S(1)/2), JzKet(S(1)/2, -S(1)/2), JzKet(1, 0), JzKet(1, 1))/10 + \ + sqrt(15)*TensorProduct(JzKet(S(1)/2, -S(1)/2), JzKet(S(1)/2, -S(1)/2), JzKet(1, 1), JzKet(1, 0))/10 - \ + sqrt(30)*TensorProduct(JzKet(S(1)/2, -S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, -1), JzKet(1, 1))/30 - \ + sqrt(30)*TensorProduct(JzKet(S(1)/2, -S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, 0), JzKet(1, 0))/15 - \ + sqrt(30)*TensorProduct(JzKet(S(1)/2, -S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, 1), JzKet(1, -1))/30 - \ + sqrt(30)*TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, -S(1)/2), JzKet(1, -1), JzKet(1, 1))/30 - \ + sqrt(30)*TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, -S(1)/2), JzKet(1, 0), JzKet(1, 0))/15 - \ + sqrt(30)*TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, -S(1)/2), JzKet(1, 1), JzKet(1, -1))/30 + \ + sqrt(15)*TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, -1), JzKet(1, 0))/10 + \ + sqrt(15)*TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, + S(1)/2), JzKet(1, 0), JzKet(1, -1))/10 + assert uncouple(JzKetCoupled(1, -1, (S(1)/2, S(1)/2, 1, 1), ((1, 2, 1), (3, 4, 2), (1, 3, 1)))) == \ + sqrt(15)*TensorProduct(JzKet(S(1)/2, -S(1)/2), JzKet(S(1)/2, -S(1)/2), JzKet(1, -1), JzKet(1, 1))/30 + \ + sqrt(15)*TensorProduct(JzKet(S(1)/2, -S(1)/2), JzKet(S(1)/2, -S(1)/2), JzKet(1, 0), JzKet(1, 0))/15 + \ + sqrt(15)*TensorProduct(JzKet(S(1)/2, -S(1)/2), JzKet(S(1)/2, -S(1)/2), JzKet(1, 1), JzKet(1, -1))/30 - \ + sqrt(30)*TensorProduct(JzKet(S(1)/2, -S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, -1), JzKet(1, 0))/20 - \ + sqrt(30)*TensorProduct(JzKet(S(1)/2, -S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, 0), JzKet(1, -1))/20 - \ + sqrt(30)*TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, -S(1)/2), JzKet(1, -1), JzKet(1, 0))/20 - \ + sqrt(30)*TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, -S(1)/2), JzKet(1, 0), JzKet(1, -1))/20 + \ + sqrt(15)*TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, + S(1)/2), JzKet(1, -1), JzKet(1, -1))/5 + def test_uncouple_symbolic(): - assert uncouple(JzKetCoupled(j, m, (j1,j2) )) == \ - Sum(CG(j1,m1,j2,m2,j,m) * \ - TensorProduct(JzKet(j1,m1), JzKet(j2,m2)), \ + assert uncouple(JzKetCoupled(j, m, (j1, j2) )) == \ + Sum(CG(j1, m1, j2, m2, j, m) * + TensorProduct(JzKet(j1, m1), JzKet(j2, m2)), (m1, -j1, j1), (m2, -j2, j2)) - assert uncouple(JzKetCoupled(j, m, (j1,j2,j3) )) == \ - Sum(CG(j1,m1,j2,m2,j1+j2,m1+m2) * CG(j1+j2,m1+m2,j3,m3,j,m) * \ - TensorProduct(JzKet(j1,m1), JzKet(j2,m2), JzKet(j3,m3)), \ - (m1,-j1,j1), (m2,-j2,j2), (m3,-j3,j3)) - assert uncouple(JzKetCoupled(j, m, (j1,j2,j3), ((1,3,j13),(1,2,j)) )) == \ - Sum(CG(j1,m1,j3,m3,j13,m1+m3) * CG(j13,m1+m3,j2,m2,j,m) * \ - TensorProduct(JzKet(j1,m1), JzKet(j2,m2), JzKet(j3,m3)), \ - (m1,-j1,j1), (m2,-j2,j2), (m3,-j3,j3)) - assert uncouple(JzKetCoupled(j, m, (j1,j2,j3,j4) )) == \ - Sum(CG(j1,m1,j2,m2,j1+j2,m1+m2) * CG(j1+j2,m1+m2,j3,m3,j1+j2+j3,m1+m2+m3) * CG(j1+j2+j3,m1+m2+m3,j4,m4,j,m) * \ - TensorProduct(JzKet(j1,m1), JzKet(j2,m2), JzKet(j3,m3), JzKet(j4,m4)), \ - (m1,-j1,j1), (m2,-j2,j2), (m3,-j3,j3), (m4,-j4,j4)) - assert uncouple(JzKetCoupled(j, m, (j1,j2,j3,j4), ((1,3,j13),(2,4,j24),(1,2,j)) )) == \ - Sum(CG(j1,m1,j3,m3,j13,m1+m3) * CG(j2,m2,j4,m4,j24,m2+m4) * CG(j13,m1+m3,j24,m2+m4,j,m) * \ - TensorProduct(JzKet(j1,m1), JzKet(j2,m2), JzKet(j3,m3), JzKet(j4,m4)), \ - (m1,-j1,j1), (m2,-j2,j2), (m3,-j3,j3), (m4,-j4,j4)) + assert uncouple(JzKetCoupled(j, m, (j1, j2, j3) )) == \ + Sum(CG(j1, m1, j2, m2, j1 + j2, m1 + m2) * CG(j1 + j2, m1 + m2, j3, m3, j, m) * + TensorProduct(JzKet(j1, m1), JzKet(j2, m2), JzKet(j3, m3)), + (m1, -j1, j1), (m2, -j2, j2), (m3, -j3, j3)) + assert uncouple(JzKetCoupled(j, m, (j1, j2, j3), ((1, 3, j13), (1, 2, j)) )) == \ + Sum(CG(j1, m1, j3, m3, j13, m1 + m3) * CG(j13, m1 + m3, j2, m2, j, m) * + TensorProduct(JzKet(j1, m1), JzKet(j2, m2), JzKet(j3, m3)), + (m1, -j1, j1), (m2, -j2, j2), (m3, -j3, j3)) + assert uncouple(JzKetCoupled(j, m, (j1, j2, j3, j4) )) == \ + Sum(CG(j1, m1, j2, m2, j1 + j2, m1 + m2) * CG(j1 + j2, m1 + m2, j3, m3, j1 + j2 + j3, m1 + m2 + m3) * CG(j1 + j2 + j3, m1 + m2 + m3, j4, m4, j, m) * + TensorProduct( + JzKet(j1, m1), JzKet(j2, m2), JzKet(j3, m3), JzKet(j4, m4)), + (m1, -j1, j1), (m2, -j2, j2), (m3, -j3, j3), (m4, -j4, j4)) + assert uncouple(JzKetCoupled(j, m, (j1, j2, j3, j4), ((1, 3, j13), (2, 4, j24), (1, 2, j)) )) == \ + Sum(CG(j1, m1, j3, m3, j13, m1 + m3) * CG(j2, m2, j4, m4, j24, m2 + m4) * CG(j13, m1 + m3, j24, m2 + m4, j, m) * + TensorProduct( + JzKet(j1, m1), JzKet(j2, m2), JzKet(j3, m3), JzKet(j4, m4)), + (m1, -j1, j1), (m2, -j2, j2), (m3, -j3, j3), (m4, -j4, j4)) + def test_couple_2_states(): # j1=1/2, j2=1/2 - assert JzKetCoupled(0, 0, (S(1)/2,S(1)/2)) == \ - expand(couple(uncouple( JzKetCoupled(0, 0, (S(1)/2,S(1)/2)) ))) - assert JzKetCoupled(1, 1, (S(1)/2,S(1)/2)) == \ - expand(couple(uncouple( JzKetCoupled(1, 1, (S(1)/2,S(1)/2)) ))) - assert JzKetCoupled(1, 0, (S(1)/2,S(1)/2)) == \ - expand(couple(uncouple( JzKetCoupled(1, 0, (S(1)/2,S(1)/2)) ))) - assert JzKetCoupled(1, -1, (S(1)/2,S(1)/2)) == \ - expand(couple(uncouple( JzKetCoupled(1, -1, (S(1)/2,S(1)/2)) ))) + assert JzKetCoupled(0, 0, (S(1)/2, S(1)/2)) == \ + expand(couple(uncouple( JzKetCoupled(0, 0, (S(1)/2, S(1)/2)) ))) + assert JzKetCoupled(1, 1, (S(1)/2, S(1)/2)) == \ + expand(couple(uncouple( JzKetCoupled(1, 1, (S(1)/2, S(1)/2)) ))) + assert JzKetCoupled(1, 0, (S(1)/2, S(1)/2)) == \ + expand(couple(uncouple( JzKetCoupled(1, 0, (S(1)/2, S(1)/2)) ))) + assert JzKetCoupled(1, -1, (S(1)/2, S(1)/2)) == \ + expand(couple(uncouple( JzKetCoupled(1, -1, (S(1)/2, S(1)/2)) ))) # j1=1, j2=1/2 assert JzKetCoupled(S(1)/2, S(1)/2, (1, S(1)/2)) == \ expand(couple(uncouple( JzKetCoupled(S(1)/2, S(1)/2, (1, S(1)/2)) ))) @@ -1392,2153 +1657,2591 @@ assert JzKetCoupled(S(3)/2, -S(3)/2, (1, S(1)/2)) == \ expand(couple(uncouple( JzKetCoupled(S(3)/2, -S(3)/2, (1, S(1)/2)) ))) # j1=1, j2=1 - assert JzKetCoupled(0, 0, (1,1)) == \ - expand(couple(uncouple( JzKetCoupled(0, 0, (1,1)) ))) - assert JzKetCoupled(1, 1, (1,1)) == \ - expand(couple(uncouple( JzKetCoupled(1, 1, (1,1)) ))) - assert JzKetCoupled(1, 0, (1,1)) == \ - expand(couple(uncouple( JzKetCoupled(1, 0, (1,1)) ))) - assert JzKetCoupled(1, -1, (1,1)) == \ - expand(couple(uncouple( JzKetCoupled(1, -1, (1,1)) ))) - assert JzKetCoupled(2, 2, (1,1)) == \ - expand(couple(uncouple( JzKetCoupled(2, 2, (1,1)) ))) - assert JzKetCoupled(2, 1, (1,1)) == \ - expand(couple(uncouple( JzKetCoupled(2, 1, (1,1)) ))) - assert JzKetCoupled(2, 0, (1,1)) == \ - expand(couple(uncouple( JzKetCoupled(2, 0, (1,1)) ))) - assert JzKetCoupled(2, -1, (1,1)) == \ - expand(couple(uncouple( JzKetCoupled(2, -1, (1,1)) ))) - assert JzKetCoupled(2, -2, (1,1)) == \ - expand(couple(uncouple( JzKetCoupled(2, -2, (1,1)) ))) + assert JzKetCoupled(0, 0, (1, 1)) == \ + expand(couple(uncouple( JzKetCoupled(0, 0, (1, 1)) ))) + assert JzKetCoupled(1, 1, (1, 1)) == \ + expand(couple(uncouple( JzKetCoupled(1, 1, (1, 1)) ))) + assert JzKetCoupled(1, 0, (1, 1)) == \ + expand(couple(uncouple( JzKetCoupled(1, 0, (1, 1)) ))) + assert JzKetCoupled(1, -1, (1, 1)) == \ + expand(couple(uncouple( JzKetCoupled(1, -1, (1, 1)) ))) + assert JzKetCoupled(2, 2, (1, 1)) == \ + expand(couple(uncouple( JzKetCoupled(2, 2, (1, 1)) ))) + assert JzKetCoupled(2, 1, (1, 1)) == \ + expand(couple(uncouple( JzKetCoupled(2, 1, (1, 1)) ))) + assert JzKetCoupled(2, 0, (1, 1)) == \ + expand(couple(uncouple( JzKetCoupled(2, 0, (1, 1)) ))) + assert JzKetCoupled(2, -1, (1, 1)) == \ + expand(couple(uncouple( JzKetCoupled(2, -1, (1, 1)) ))) + assert JzKetCoupled(2, -2, (1, 1)) == \ + expand(couple(uncouple( JzKetCoupled(2, -2, (1, 1)) ))) # j1=1/2, j2=3/2 - assert JzKetCoupled(1, 1, (S(1)/2,S(3)/2)) == \ - expand(couple(uncouple( JzKetCoupled(1, 1, (S(1)/2,S(3)/2)) ))) - assert JzKetCoupled(1, 0, (S(1)/2,S(3)/2)) == \ - expand(couple(uncouple( JzKetCoupled(1, 0, (S(1)/2,S(3)/2)) ))) - assert JzKetCoupled(1, -1, (S(1)/2,S(3)/2)) == \ - expand(couple(uncouple( JzKetCoupled(1, -1, (S(1)/2,S(3)/2)) ))) - assert JzKetCoupled(2, 2, (S(1)/2,S(3)/2)) == \ - expand(couple(uncouple( JzKetCoupled(2, 2, (S(1)/2,S(3)/2)) ))) - assert JzKetCoupled(2, 1, (S(1)/2,S(3)/2)) == \ - expand(couple(uncouple( JzKetCoupled(2, 1, (S(1)/2,S(3)/2)) ))) - assert JzKetCoupled(2, 0, (S(1)/2,S(3)/2)) == \ - expand(couple(uncouple( JzKetCoupled(2, 0, (S(1)/2,S(3)/2)) ))) - assert JzKetCoupled(2, -1, (S(1)/2,S(3)/2)) == \ - expand(couple(uncouple( JzKetCoupled(2, -1, (S(1)/2,S(3)/2)) ))) - assert JzKetCoupled(2, -2, (S(1)/2,S(3)/2)) == \ - expand(couple(uncouple( JzKetCoupled(2, -2, (S(1)/2,S(3)/2)) ))) + assert JzKetCoupled(1, 1, (S(1)/2, S(3)/2)) == \ + expand(couple(uncouple( JzKetCoupled(1, 1, (S(1)/2, S(3)/2)) ))) + assert JzKetCoupled(1, 0, (S(1)/2, S(3)/2)) == \ + expand(couple(uncouple( JzKetCoupled(1, 0, (S(1)/2, S(3)/2)) ))) + assert JzKetCoupled(1, -1, (S(1)/2, S(3)/2)) == \ + expand(couple(uncouple( JzKetCoupled(1, -1, (S(1)/2, S(3)/2)) ))) + assert JzKetCoupled(2, 2, (S(1)/2, S(3)/2)) == \ + expand(couple(uncouple( JzKetCoupled(2, 2, (S(1)/2, S(3)/2)) ))) + assert JzKetCoupled(2, 1, (S(1)/2, S(3)/2)) == \ + expand(couple(uncouple( JzKetCoupled(2, 1, (S(1)/2, S(3)/2)) ))) + assert JzKetCoupled(2, 0, (S(1)/2, S(3)/2)) == \ + expand(couple(uncouple( JzKetCoupled(2, 0, (S(1)/2, S(3)/2)) ))) + assert JzKetCoupled(2, -1, (S(1)/2, S(3)/2)) == \ + expand(couple(uncouple( JzKetCoupled(2, -1, (S(1)/2, S(3)/2)) ))) + assert JzKetCoupled(2, -2, (S(1)/2, S(3)/2)) == \ + expand(couple(uncouple( JzKetCoupled(2, -2, (S(1)/2, S(3)/2)) ))) + def test_couple_3_states(): # Default coupling # j1=1/2, j2=1/2, j3=1/2 - assert JzKetCoupled(S(1)/2, S(1)/2, (S(1)/2,S(1)/2,S(1)/2)) == \ - expand(couple(uncouple( JzKetCoupled(S(1)/2, S(1)/2, (S(1)/2,S(1)/2,S(1)/2)) ))) - assert JzKetCoupled(S(1)/2, S(-1)/2, (S(1)/2,S(1)/2,S(1)/2)) == \ - expand(couple(uncouple( JzKetCoupled(S(1)/2, S(-1)/2, (S(1)/2,S(1)/2,S(1)/2)) ))) - assert JzKetCoupled(S(3)/2, S(3)/2, (S(1)/2,S(1)/2,S(1)/2)) == \ - expand(couple(uncouple( JzKetCoupled(S(3)/2, S(3)/2, (S(1)/2,S(1)/2,S(1)/2)) ))) - assert JzKetCoupled(S(3)/2, S(1)/2, (S(1)/2,S(1)/2,S(1)/2)) == \ - expand(couple(uncouple( JzKetCoupled(S(3)/2, S(1)/2, (S(1)/2,S(1)/2,S(1)/2)) ))) - assert JzKetCoupled(S(3)/2, S(-1)/2, (S(1)/2,S(1)/2,S(1)/2)) == \ - expand(couple(uncouple( JzKetCoupled(S(3)/2, S(-1)/2, (S(1)/2,S(1)/2,S(1)/2)) ))) - assert JzKetCoupled(S(3)/2, S(-3)/2, (S(1)/2,S(1)/2,S(1)/2)) == \ - expand(couple(uncouple( JzKetCoupled(S(3)/2, S(-3)/2, (S(1)/2,S(1)/2,S(1)/2)) ))) + assert JzKetCoupled(S(1)/2, S(1)/2, (S(1)/2, S(1)/2, S(1)/2)) == \ + expand(couple(uncouple( + JzKetCoupled(S(1)/2, S(1)/2, (S(1)/2, S(1)/2, S(1)/2)) ))) + assert JzKetCoupled(S(1)/2, S(-1)/2, (S(1)/2, S(1)/2, S(1)/2)) == \ + expand(couple(uncouple( + JzKetCoupled(S(1)/2, S(-1)/2, (S(1)/2, S(1)/2, S(1)/2)) ))) + assert JzKetCoupled(S(3)/2, S(3)/2, (S(1)/2, S(1)/2, S(1)/2)) == \ + expand(couple(uncouple( + JzKetCoupled(S(3)/2, S(3)/2, (S(1)/2, S(1)/2, S(1)/2)) ))) + assert JzKetCoupled(S(3)/2, S(1)/2, (S(1)/2, S(1)/2, S(1)/2)) == \ + expand(couple(uncouple( + JzKetCoupled(S(3)/2, S(1)/2, (S(1)/2, S(1)/2, S(1)/2)) ))) + assert JzKetCoupled(S(3)/2, S(-1)/2, (S(1)/2, S(1)/2, S(1)/2)) == \ + expand(couple(uncouple( + JzKetCoupled(S(3)/2, S(-1)/2, (S(1)/2, S(1)/2, S(1)/2)) ))) + assert JzKetCoupled(S(3)/2, S(-3)/2, (S(1)/2, S(1)/2, S(1)/2)) == \ + expand(couple(uncouple( + JzKetCoupled(S(3)/2, S(-3)/2, (S(1)/2, S(1)/2, S(1)/2)) ))) # j1=1/2, j2=1/2, j3=1 - assert JzKetCoupled(0, 0, (S(1)/2,S(1)/2,1)) == \ - expand(couple(uncouple( JzKetCoupled(0, 0, (S(1)/2,S(1)/2,1)) ))) - assert JzKetCoupled(1, 1, (S(1)/2,S(1)/2,1)) == \ - expand(couple(uncouple( JzKetCoupled(1, 1, (S(1)/2,S(1)/2,1)) ))) - assert JzKetCoupled(1, 0, (S(1)/2,S(1)/2,1)) == \ - expand(couple(uncouple( JzKetCoupled(1, 0, (S(1)/2,S(1)/2,1)) ))) - assert JzKetCoupled(1, -1, (S(1)/2,S(1)/2,1)) == \ - expand(couple(uncouple( JzKetCoupled(1, -1, (S(1)/2,S(1)/2,1)) ))) - assert JzKetCoupled(2, 2, (S(1)/2,S(1)/2,1)) == \ - expand(couple(uncouple( JzKetCoupled(2, 2, (S(1)/2,S(1)/2,1)) ))) - assert JzKetCoupled(2, 1, (S(1)/2,S(1)/2,1)) == \ - expand(couple(uncouple( JzKetCoupled(2, 1, (S(1)/2,S(1)/2,1)) ))) - assert JzKetCoupled(2, 0, (S(1)/2,S(1)/2,1)) == \ - expand(couple(uncouple( JzKetCoupled(2, 0, (S(1)/2,S(1)/2,1)) ))) - assert JzKetCoupled(2, -1, (S(1)/2,S(1)/2,1)) == \ - expand(couple(uncouple( JzKetCoupled(2, -1, (S(1)/2,S(1)/2,1)) ))) - assert JzKetCoupled(2, -2, (S(1)/2,S(1)/2,1)) == \ - expand(couple(uncouple( JzKetCoupled(2, -2, (S(1)/2,S(1)/2,1)) ))) + assert JzKetCoupled(0, 0, (S(1)/2, S(1)/2, 1)) == \ + expand(couple(uncouple( JzKetCoupled(0, 0, (S(1)/2, S(1)/2, 1)) ))) + assert JzKetCoupled(1, 1, (S(1)/2, S(1)/2, 1)) == \ + expand(couple(uncouple( JzKetCoupled(1, 1, (S(1)/2, S(1)/2, 1)) ))) + assert JzKetCoupled(1, 0, (S(1)/2, S(1)/2, 1)) == \ + expand(couple(uncouple( JzKetCoupled(1, 0, (S(1)/2, S(1)/2, 1)) ))) + assert JzKetCoupled(1, -1, (S(1)/2, S(1)/2, 1)) == \ + expand(couple(uncouple( JzKetCoupled(1, -1, (S(1)/2, S(1)/2, 1)) ))) + assert JzKetCoupled(2, 2, (S(1)/2, S(1)/2, 1)) == \ + expand(couple(uncouple( JzKetCoupled(2, 2, (S(1)/2, S(1)/2, 1)) ))) + assert JzKetCoupled(2, 1, (S(1)/2, S(1)/2, 1)) == \ + expand(couple(uncouple( JzKetCoupled(2, 1, (S(1)/2, S(1)/2, 1)) ))) + assert JzKetCoupled(2, 0, (S(1)/2, S(1)/2, 1)) == \ + expand(couple(uncouple( JzKetCoupled(2, 0, (S(1)/2, S(1)/2, 1)) ))) + assert JzKetCoupled(2, -1, (S(1)/2, S(1)/2, 1)) == \ + expand(couple(uncouple( JzKetCoupled(2, -1, (S(1)/2, S(1)/2, 1)) ))) + assert JzKetCoupled(2, -2, (S(1)/2, S(1)/2, 1)) == \ + expand(couple(uncouple( JzKetCoupled(2, -2, (S(1)/2, S(1)/2, 1)) ))) # Couple j1+j3=j13, j13+j2=j # j1=1/2, j2=1/2, j3=1/2, j13=0 - assert JzKetCoupled(S(1)/2, S(1)/2, (S(1)/2,S(1)/2,S(1)/2), ((1,3,0),(1,2,S(1)/2))) == \ - expand(couple(uncouple( JzKetCoupled(S(1)/2, S(1)/2, (S(1)/2,S(1)/2,S(1)/2), ((1,3,0),(1,2,S(1)/2))) ), ((1,3),(1,2)) )) - assert JzKetCoupled(S(1)/2, S(-1)/2, (S(1)/2,S(1)/2,S(1)/2), ((1,3,0),(1,2,S(1)/2))) == \ - expand(couple(uncouple( JzKetCoupled(S(1)/2, S(-1)/2, (S(1)/2,S(1)/2,S(1)/2), ((1,3,0),(1,2,S(1)/2))) ), ((1,3),(1,2)) )) + assert JzKetCoupled(S(1)/2, S(1)/2, (S(1)/2, S(1)/2, S(1)/2), ((1, 3, 0), (1, 2, S(1)/2))) == \ + expand(couple(uncouple( JzKetCoupled(S(1)/2, S(1)/2, (S(1)/2, S( + 1)/2, S(1)/2), ((1, 3, 0), (1, 2, S(1)/2))) ), ((1, 3), (1, 2)) )) + assert JzKetCoupled(S(1)/2, S(-1)/2, (S(1)/2, S(1)/2, S(1)/2), ((1, 3, 0), (1, 2, S(1)/2))) == \ + expand(couple(uncouple( JzKetCoupled(S(1)/2, S(-1)/2, (S(1)/2, S( + 1)/2, S(1)/2), ((1, 3, 0), (1, 2, S(1)/2))) ), ((1, 3), (1, 2)) )) # j1=1, j2=1/2, j3=1, j13=1 - assert JzKetCoupled(S(1)/2, S(1)/2, (1,S(1)/2,1), ((1,3,1),(1,2,S(1)/2))) == \ - expand(couple(uncouple( JzKetCoupled(S(1)/2, S(1)/2, (1,S(1)/2,1), ((1,3,1),(1,2,S(1)/2))) ), ((1,3),(1,2)) )) - assert JzKetCoupled(S(1)/2, S(-1)/2, (1,S(1)/2,1), ((1,3,1),(1,2,S(1)/2))) == \ - expand(couple(uncouple( JzKetCoupled(S(1)/2, S(-1)/2, (1,S(1)/2,1), ((1,3,1),(1,2,S(1)/2))) ), ((1,3),(1,2)) )) - assert JzKetCoupled(S(3)/2, S(3)/2, (1,S(1)/2,1), ((1,3,1),(1,2,S(3)/2))) == \ - expand(couple(uncouple( JzKetCoupled(S(3)/2, S(3)/2, (1,S(1)/2,1), ((1,3,1),(1,2,S(3)/2))) ), ((1,3),(1,2)) )) - assert JzKetCoupled(S(3)/2, S(1)/2, (1,S(1)/2,1), ((1,3,1),(1,2,S(3)/2))) == \ - expand(couple(uncouple( JzKetCoupled(S(3)/2, S(1)/2, (1,S(1)/2,1), ((1,3,1),(1,2,S(3)/2))) ), ((1,3),(1,2)) )) - assert JzKetCoupled(S(3)/2, S(-1)/2, (1,S(1)/2,1), ((1,3,1),(1,2,S(3)/2))) == \ - expand(couple(uncouple( JzKetCoupled(S(3)/2, S(-1)/2, (1,S(1)/2,1), ((1,3,1),(1,2,S(3)/2))) ), ((1,3),(1,2)) )) - assert JzKetCoupled(S(3)/2, S(-3)/2, (1,S(1)/2,1), ((1,3,1),(1,2,S(3)/2))) == \ - expand(couple(uncouple( JzKetCoupled(S(3)/2, S(-3)/2, (1,S(1)/2,1), ((1,3,1),(1,2,S(3)/2))) ), ((1,3),(1,2)) )) + assert JzKetCoupled(S(1)/2, S(1)/2, (1, S(1)/2, 1), ((1, 3, 1), (1, 2, S(1)/2))) == \ + expand(couple(uncouple( JzKetCoupled(S(1)/2, S(1)/2, ( + 1, S(1)/2, 1), ((1, 3, 1), (1, 2, S(1)/2))) ), ((1, 3), (1, 2)) )) + assert JzKetCoupled(S(1)/2, S(-1)/2, (1, S(1)/2, 1), ((1, 3, 1), (1, 2, S(1)/2))) == \ + expand(couple(uncouple( JzKetCoupled(S(1)/2, S(-1)/2, ( + 1, S(1)/2, 1), ((1, 3, 1), (1, 2, S(1)/2))) ), ((1, 3), (1, 2)) )) + assert JzKetCoupled(S(3)/2, S(3)/2, (1, S(1)/2, 1), ((1, 3, 1), (1, 2, S(3)/2))) == \ + expand(couple(uncouple( JzKetCoupled(S(3)/2, S(3)/2, ( + 1, S(1)/2, 1), ((1, 3, 1), (1, 2, S(3)/2))) ), ((1, 3), (1, 2)) )) + assert JzKetCoupled(S(3)/2, S(1)/2, (1, S(1)/2, 1), ((1, 3, 1), (1, 2, S(3)/2))) == \ + expand(couple(uncouple( JzKetCoupled(S(3)/2, S(1)/2, ( + 1, S(1)/2, 1), ((1, 3, 1), (1, 2, S(3)/2))) ), ((1, 3), (1, 2)) )) + assert JzKetCoupled(S(3)/2, S(-1)/2, (1, S(1)/2, 1), ((1, 3, 1), (1, 2, S(3)/2))) == \ + expand(couple(uncouple( JzKetCoupled(S(3)/2, S(-1)/2, ( + 1, S(1)/2, 1), ((1, 3, 1), (1, 2, S(3)/2))) ), ((1, 3), (1, 2)) )) + assert JzKetCoupled(S(3)/2, S(-3)/2, (1, S(1)/2, 1), ((1, 3, 1), (1, 2, S(3)/2))) == \ + expand(couple(uncouple( JzKetCoupled(S(3)/2, S(-3)/2, ( + 1, S(1)/2, 1), ((1, 3, 1), (1, 2, S(3)/2))) ), ((1, 3), (1, 2)) )) + def test_couple_4_states(): # Default coupling # j1=1/2, j2=1/2, j3=1/2, j4=1/2 - assert JzKetCoupled(1, 1, (S(1)/2,S(1)/2,S(1)/2,S(1)/2)) == \ - expand(couple(uncouple( JzKetCoupled(1, 1, (S(1)/2,S(1)/2,S(1)/2,S(1)/2)) ))) - assert JzKetCoupled(1, 0, (S(1)/2,S(1)/2,S(1)/2,S(1)/2)) == \ - expand(couple(uncouple( JzKetCoupled(1, 0, (S(1)/2,S(1)/2,S(1)/2,S(1)/2)) ))) - assert JzKetCoupled(1, -1, (S(1)/2,S(1)/2,S(1)/2,S(1)/2)) == \ - expand(couple(uncouple( JzKetCoupled(1, -1, (S(1)/2,S(1)/2,S(1)/2,S(1)/2)) ))) - assert JzKetCoupled(2, 2, (S(1)/2,S(1)/2,S(1)/2,S(1)/2)) == \ - expand(couple(uncouple( JzKetCoupled(2, 2, (S(1)/2,S(1)/2,S(1)/2,S(1)/2)) ))) - assert JzKetCoupled(2, 1, (S(1)/2,S(1)/2,S(1)/2,S(1)/2)) == \ - expand(couple(uncouple( JzKetCoupled(2, 1, (S(1)/2,S(1)/2,S(1)/2,S(1)/2)) ))) - assert JzKetCoupled(2, 0, (S(1)/2,S(1)/2,S(1)/2,S(1)/2)) == \ - expand(couple(uncouple( JzKetCoupled(2, 0, (S(1)/2,S(1)/2,S(1)/2,S(1)/2)) ))) - assert JzKetCoupled(2, -1, (S(1)/2,S(1)/2,S(1)/2,S(1)/2)) == \ - expand(couple(uncouple( JzKetCoupled(2, -1, (S(1)/2,S(1)/2,S(1)/2,S(1)/2)) ))) - assert JzKetCoupled(2, -2, (S(1)/2,S(1)/2,S(1)/2,S(1)/2)) == \ - expand(couple(uncouple( JzKetCoupled(2, -2, (S(1)/2,S(1)/2,S(1)/2,S(1)/2)) ))) + assert JzKetCoupled(1, 1, (S(1)/2, S(1)/2, S(1)/2, S(1)/2)) == \ + expand(couple( + uncouple( JzKetCoupled(1, 1, (S(1)/2, S(1)/2, S(1)/2, S(1)/2)) ))) + assert JzKetCoupled(1, 0, (S(1)/2, S(1)/2, S(1)/2, S(1)/2)) == \ + expand(couple( + uncouple( JzKetCoupled(1, 0, (S(1)/2, S(1)/2, S(1)/2, S(1)/2)) ))) + assert JzKetCoupled(1, -1, (S(1)/2, S(1)/2, S(1)/2, S(1)/2)) == \ + expand(couple(uncouple( + JzKetCoupled(1, -1, (S(1)/2, S(1)/2, S(1)/2, S(1)/2)) ))) + assert JzKetCoupled(2, 2, (S(1)/2, S(1)/2, S(1)/2, S(1)/2)) == \ + expand(couple( + uncouple( JzKetCoupled(2, 2, (S(1)/2, S(1)/2, S(1)/2, S(1)/2)) ))) + assert JzKetCoupled(2, 1, (S(1)/2, S(1)/2, S(1)/2, S(1)/2)) == \ + expand(couple( + uncouple( JzKetCoupled(2, 1, (S(1)/2, S(1)/2, S(1)/2, S(1)/2)) ))) + assert JzKetCoupled(2, 0, (S(1)/2, S(1)/2, S(1)/2, S(1)/2)) == \ + expand(couple( + uncouple( JzKetCoupled(2, 0, (S(1)/2, S(1)/2, S(1)/2, S(1)/2)) ))) + assert JzKetCoupled(2, -1, (S(1)/2, S(1)/2, S(1)/2, S(1)/2)) == \ + expand(couple(uncouple( + JzKetCoupled(2, -1, (S(1)/2, S(1)/2, S(1)/2, S(1)/2)) ))) + assert JzKetCoupled(2, -2, (S(1)/2, S(1)/2, S(1)/2, S(1)/2)) == \ + expand(couple(uncouple( + JzKetCoupled(2, -2, (S(1)/2, S(1)/2, S(1)/2, S(1)/2)) ))) # j1=1/2, j2=1/2, j3=1/2, j4=1 - assert JzKetCoupled(S(1)/2, S(1)/2, (S(1)/2,S(1)/2,S(1)/2,1)) == \ - expand(couple(uncouple( JzKetCoupled(S(1)/2, S(1)/2, (S(1)/2,S(1)/2,S(1)/2,1)) ))) - assert JzKetCoupled(S(1)/2, S(-1)/2, (S(1)/2,S(1)/2,S(1)/2,1)) == \ - expand(couple(uncouple( JzKetCoupled(S(1)/2, S(-1)/2, (S(1)/2,S(1)/2,S(1)/2,1)) ))) - assert JzKetCoupled(S(3)/2, S(3)/2, (S(1)/2,S(1)/2,S(1)/2,1)) == \ - expand(couple(uncouple( JzKetCoupled(S(3)/2, S(3)/2, (S(1)/2,S(1)/2,S(1)/2,1)) ))) - assert JzKetCoupled(S(3)/2, S(1)/2, (S(1)/2,S(1)/2,S(1)/2,1)) == \ - expand(couple(uncouple( JzKetCoupled(S(3)/2, S(1)/2, (S(1)/2,S(1)/2,S(1)/2,1)) ))) - assert JzKetCoupled(S(3)/2, S(-1)/2, (S(1)/2,S(1)/2,S(1)/2,1)) == \ - expand(couple(uncouple( JzKetCoupled(S(3)/2, S(-1)/2, (S(1)/2,S(1)/2,S(1)/2,1)) ))) - assert JzKetCoupled(S(3)/2, S(-3)/2, (S(1)/2,S(1)/2,S(1)/2,1)) == \ - expand(couple(uncouple( JzKetCoupled(S(3)/2, S(-3)/2, (S(1)/2,S(1)/2,S(1)/2,1)) ))) - assert JzKetCoupled(S(5)/2, S(5)/2, (S(1)/2,S(1)/2,S(1)/2,1)) == \ - expand(couple(uncouple( JzKetCoupled(S(5)/2, S(5)/2, (S(1)/2,S(1)/2,S(1)/2,1)) ))) - assert JzKetCoupled(S(5)/2, S(3)/2, (S(1)/2,S(1)/2,S(1)/2,1)) == \ - expand(couple(uncouple( JzKetCoupled(S(5)/2, S(3)/2, (S(1)/2,S(1)/2,S(1)/2,1)) ))) - assert JzKetCoupled(S(5)/2, S(1)/2, (S(1)/2,S(1)/2,S(1)/2,1)) == \ - expand(couple(uncouple( JzKetCoupled(S(5)/2, S(1)/2, (S(1)/2,S(1)/2,S(1)/2,1)) ))) - assert JzKetCoupled(S(5)/2, S(-1)/2, (S(1)/2,S(1)/2,S(1)/2,1)) == \ - expand(couple(uncouple( JzKetCoupled(S(5)/2, S(-1)/2, (S(1)/2,S(1)/2,S(1)/2,1)) ))) - assert JzKetCoupled(S(5)/2, S(-3)/2, (S(1)/2,S(1)/2,S(1)/2,1)) == \ - expand(couple(uncouple( JzKetCoupled(S(5)/2, S(-3)/2, (S(1)/2,S(1)/2,S(1)/2,1)) ))) - assert JzKetCoupled(S(5)/2, S(-5)/2, (S(1)/2,S(1)/2,S(1)/2,1)) == \ - expand(couple(uncouple( JzKetCoupled(S(5)/2, S(-5)/2, (S(1)/2,S(1)/2,S(1)/2,1)) ))) + assert JzKetCoupled(S(1)/2, S(1)/2, (S(1)/2, S(1)/2, S(1)/2, 1)) == \ + expand(couple(uncouple( + JzKetCoupled(S(1)/2, S(1)/2, (S(1)/2, S(1)/2, S(1)/2, 1)) ))) + assert JzKetCoupled(S(1)/2, S(-1)/2, (S(1)/2, S(1)/2, S(1)/2, 1)) == \ + expand(couple(uncouple( + JzKetCoupled(S(1)/2, S(-1)/2, (S(1)/2, S(1)/2, S(1)/2, 1)) ))) + assert JzKetCoupled(S(3)/2, S(3)/2, (S(1)/2, S(1)/2, S(1)/2, 1)) == \ + expand(couple(uncouple( + JzKetCoupled(S(3)/2, S(3)/2, (S(1)/2, S(1)/2, S(1)/2, 1)) ))) + assert JzKetCoupled(S(3)/2, S(1)/2, (S(1)/2, S(1)/2, S(1)/2, 1)) == \ + expand(couple(uncouple( + JzKetCoupled(S(3)/2, S(1)/2, (S(1)/2, S(1)/2, S(1)/2, 1)) ))) + assert JzKetCoupled(S(3)/2, S(-1)/2, (S(1)/2, S(1)/2, S(1)/2, 1)) == \ + expand(couple(uncouple( + JzKetCoupled(S(3)/2, S(-1)/2, (S(1)/2, S(1)/2, S(1)/2, 1)) ))) + assert JzKetCoupled(S(3)/2, S(-3)/2, (S(1)/2, S(1)/2, S(1)/2, 1)) == \ + expand(couple(uncouple( + JzKetCoupled(S(3)/2, S(-3)/2, (S(1)/2, S(1)/2, S(1)/2, 1)) ))) + assert JzKetCoupled(S(5)/2, S(5)/2, (S(1)/2, S(1)/2, S(1)/2, 1)) == \ + expand(couple(uncouple( + JzKetCoupled(S(5)/2, S(5)/2, (S(1)/2, S(1)/2, S(1)/2, 1)) ))) + assert JzKetCoupled(S(5)/2, S(3)/2, (S(1)/2, S(1)/2, S(1)/2, 1)) == \ + expand(couple(uncouple( + JzKetCoupled(S(5)/2, S(3)/2, (S(1)/2, S(1)/2, S(1)/2, 1)) ))) + assert JzKetCoupled(S(5)/2, S(1)/2, (S(1)/2, S(1)/2, S(1)/2, 1)) == \ + expand(couple(uncouple( + JzKetCoupled(S(5)/2, S(1)/2, (S(1)/2, S(1)/2, S(1)/2, 1)) ))) + assert JzKetCoupled(S(5)/2, S(-1)/2, (S(1)/2, S(1)/2, S(1)/2, 1)) == \ + expand(couple(uncouple( + JzKetCoupled(S(5)/2, S(-1)/2, (S(1)/2, S(1)/2, S(1)/2, 1)) ))) + assert JzKetCoupled(S(5)/2, S(-3)/2, (S(1)/2, S(1)/2, S(1)/2, 1)) == \ + expand(couple(uncouple( + JzKetCoupled(S(5)/2, S(-3)/2, (S(1)/2, S(1)/2, S(1)/2, 1)) ))) + assert JzKetCoupled(S(5)/2, S(-5)/2, (S(1)/2, S(1)/2, S(1)/2, 1)) == \ + expand(couple(uncouple( + JzKetCoupled(S(5)/2, S(-5)/2, (S(1)/2, S(1)/2, S(1)/2, 1)) ))) # Coupling j1+j3=j13, j2+j4=j24, j13+j24=j # j1=1/2, j2=1/2, j3=1/2, j4=1/2, j13=1, j24=0 - assert JzKetCoupled(1, 1, (S(1)/2,S(1)/2,S(1)/2,S(1)/2), ((1,3,1),(2,4,0),(1,2,1)) ) == \ - expand(couple(uncouple( JzKetCoupled(1, 1, (S(1)/2,S(1)/2,S(1)/2,S(1)/2), ((1,3,1),(2,4,0),(1,2,1)) ) ), ((1,3),(2,4),(1,2)) )) - assert JzKetCoupled(1, 0, (S(1)/2,S(1)/2,S(1)/2,S(1)/2), ((1,3,1),(2,4,0),(1,2,1)) ) == \ - expand(couple(uncouple( JzKetCoupled(1, 0, (S(1)/2,S(1)/2,S(1)/2,S(1)/2), ((1,3,1),(2,4,0),(1,2,1)) ) ), ((1,3),(2,4),(1,2)) )) - assert JzKetCoupled(1, -1, (S(1)/2,S(1)/2,S(1)/2,S(1)/2), ((1,3,1),(2,4,0),(1,2,1)) ) == \ - expand(couple(uncouple( JzKetCoupled(1, -1, (S(1)/2,S(1)/2,S(1)/2,S(1)/2), ((1,3,1),(2,4,0),(1,2,1)) ) ), ((1,3),(2,4),(1,2)) )) + assert JzKetCoupled(1, 1, (S(1)/2, S(1)/2, S(1)/2, S(1)/2), ((1, 3, 1), (2, 4, 0), (1, 2, 1)) ) == \ + expand(couple(uncouple( JzKetCoupled(1, 1, (S(1)/2, S(1)/2, S(1)/2, S(1)/2), ((1, 3, 1), (2, 4, 0), (1, 2, 1)) ) ), ((1, 3), (2, 4), (1, 2)) )) + assert JzKetCoupled(1, 0, (S(1)/2, S(1)/2, S(1)/2, S(1)/2), ((1, 3, 1), (2, 4, 0), (1, 2, 1)) ) == \ + expand(couple(uncouple( JzKetCoupled(1, 0, (S(1)/2, S(1)/2, S(1)/2, S(1)/2), ((1, 3, 1), (2, 4, 0), (1, 2, 1)) ) ), ((1, 3), (2, 4), (1, 2)) )) + assert JzKetCoupled(1, -1, (S(1)/2, S(1)/2, S(1)/2, S(1)/2), ((1, 3, 1), (2, 4, 0), (1, 2, 1)) ) == \ + expand(couple(uncouple( JzKetCoupled(1, -1, (S(1)/2, S(1)/2, S(1)/2, S(1)/2), ((1, 3, 1), (2, 4, 0), (1, 2, 1)) ) ), ((1, 3), (2, 4), (1, 2)) )) # j1=1/2, j2=1/2, j3=1/2, j4=1, j13=1, j24=1/2 - assert JzKetCoupled(S(1)/2, S(1)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,3,1),(2,4,S(1)/2),(1,2,S(1)/2)) ) == \ - expand(couple(uncouple( JzKetCoupled(S(1)/2, S(1)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,3,1),(2,4,S(1)/2),(1,2,S(1)/2)) )), ((1,3),(2,4),(1,2)) )) - assert JzKetCoupled(S(1)/2, S(-1)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,3,1),(2,4,S(1)/2),(1,2,S(1)/2)) ) == \ - expand(couple(uncouple( JzKetCoupled(S(1)/2, S(-1)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,3,1),(2,4,S(1)/2),(1,2,S(1)/2)) ) ), ((1,3),(2,4),(1,2)) )) - assert JzKetCoupled(S(3)/2, S(3)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,3,1),(2,4,S(1)/2),(1,2,S(3)/2)) ) == \ - expand(couple(uncouple( JzKetCoupled(S(3)/2, S(3)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,3,1),(2,4,S(1)/2),(1,2,S(3)/2)) ) ), ((1,3),(2,4),(1,2)) )) - assert JzKetCoupled(S(3)/2, S(1)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,3,1),(2,4,S(1)/2),(1,2,S(3)/2)) ) == \ - expand(couple(uncouple( JzKetCoupled(S(3)/2, S(1)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,3,1),(2,4,S(1)/2),(1,2,S(3)/2)) ) ), ((1,3),(2,4),(1,2)) )) - assert JzKetCoupled(S(3)/2, S(-1)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,3,1),(2,4,S(1)/2),(1,2,S(3)/2)) ) == \ - expand(couple(uncouple( JzKetCoupled(S(3)/2, S(-1)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,3,1),(2,4,S(1)/2),(1,2,S(3)/2)) ) ), ((1,3),(2,4),(1,2)) )) - assert JzKetCoupled(S(3)/2, S(-3)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,3,1),(2,4,S(1)/2),(1,2,S(3)/2)) ) == \ - expand(couple(uncouple( JzKetCoupled(S(3)/2, S(-3)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,3,1),(2,4,S(1)/2),(1,2,S(3)/2)) ) ), ((1,3),(2,4),(1,2)) )) + assert JzKetCoupled(S(1)/2, S(1)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 3, 1), (2, 4, S(1)/2), (1, 2, S(1)/2)) ) == \ + expand(couple(uncouple( JzKetCoupled(S(1)/2, S(1)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 3, 1), (2, 4, S(1)/2), (1, 2, S(1)/2)) )), ((1, 3), (2, 4), (1, 2)) )) + assert JzKetCoupled(S(1)/2, S(-1)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 3, 1), (2, 4, S(1)/2), (1, 2, S(1)/2)) ) == \ + expand(couple(uncouple( JzKetCoupled(S(1)/2, S(-1)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 3, 1), (2, 4, S(1)/2), (1, 2, S(1)/2)) ) ), ((1, 3), (2, 4), (1, 2)) )) + assert JzKetCoupled(S(3)/2, S(3)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 3, 1), (2, 4, S(1)/2), (1, 2, S(3)/2)) ) == \ + expand(couple(uncouple( JzKetCoupled(S(3)/2, S(3)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 3, 1), (2, 4, S(1)/2), (1, 2, S(3)/2)) ) ), ((1, 3), (2, 4), (1, 2)) )) + assert JzKetCoupled(S(3)/2, S(1)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 3, 1), (2, 4, S(1)/2), (1, 2, S(3)/2)) ) == \ + expand(couple(uncouple( JzKetCoupled(S(3)/2, S(1)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 3, 1), (2, 4, S(1)/2), (1, 2, S(3)/2)) ) ), ((1, 3), (2, 4), (1, 2)) )) + assert JzKetCoupled(S(3)/2, S(-1)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 3, 1), (2, 4, S(1)/2), (1, 2, S(3)/2)) ) == \ + expand(couple(uncouple( JzKetCoupled(S(3)/2, S(-1)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 3, 1), (2, 4, S(1)/2), (1, 2, S(3)/2)) ) ), ((1, 3), (2, 4), (1, 2)) )) + assert JzKetCoupled(S(3)/2, S(-3)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 3, 1), (2, 4, S(1)/2), (1, 2, S(3)/2)) ) == \ + expand(couple(uncouple( JzKetCoupled(S(3)/2, S(-3)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 3, 1), (2, 4, S(1)/2), (1, 2, S(3)/2)) ) ), ((1, 3), (2, 4), (1, 2)) )) # j1=1/2, j2=1, j3=1/2, j4=1, j13=0, j24=1 - assert JzKetCoupled(1, 1, (S(1)/2,1,S(1)/2,1), ((1,3,0),(2,4,1),(1,2,1)) ) == \ - expand(couple(uncouple( JzKetCoupled(1, 1, (S(1)/2,1,S(1)/2,1), ((1,3,0),(2,4,1),(1,2,1))) ), ((1,3),(2,4),(1,2)) )) - assert JzKetCoupled(1, 0, (S(1)/2,1,S(1)/2,1), ((1,3,0),(2,4,1),(1,2,1)) ) == \ - expand(couple(uncouple( JzKetCoupled(1, 0, (S(1)/2,1,S(1)/2,1), ((1,3,0),(2,4,1),(1,2,1))) ), ((1,3),(2,4),(1,2)) )) - assert JzKetCoupled(1, -1, (S(1)/2,1,S(1)/2,1), ((1,3,0),(2,4,1),(1,2,1)) ) == \ - expand(couple(uncouple( JzKetCoupled(1, -1, (S(1)/2,1,S(1)/2,1), ((1,3,0),(2,4,1),(1,2,1))) ), ((1,3),(2,4),(1,2)) )) + assert JzKetCoupled(1, 1, (S(1)/2, 1, S(1)/2, 1), ((1, 3, 0), (2, 4, 1), (1, 2, 1)) ) == \ + expand(couple(uncouple( JzKetCoupled(1, 1, (S(1)/2, 1, S(1)/2, 1), ( + (1, 3, 0), (2, 4, 1), (1, 2, 1))) ), ((1, 3), (2, 4), (1, 2)) )) + assert JzKetCoupled(1, 0, (S(1)/2, 1, S(1)/2, 1), ((1, 3, 0), (2, 4, 1), (1, 2, 1)) ) == \ + expand(couple(uncouple( JzKetCoupled(1, 0, (S(1)/2, 1, S(1)/2, 1), ( + (1, 3, 0), (2, 4, 1), (1, 2, 1))) ), ((1, 3), (2, 4), (1, 2)) )) + assert JzKetCoupled(1, -1, (S(1)/2, 1, S(1)/2, 1), ((1, 3, 0), (2, 4, 1), (1, 2, 1)) ) == \ + expand(couple(uncouple( JzKetCoupled(1, -1, (S(1)/2, 1, S(1)/2, 1), ( + (1, 3, 0), (2, 4, 1), (1, 2, 1))) ), ((1, 3), (2, 4), (1, 2)) )) # j1=1/2, j2=1, j3=1/2, j4=1, j13=1, j24=1 - assert JzKetCoupled(0, 0, (S(1)/2,1,S(1)/2,1), ((1,3,1),(2,4,1),(1,2,0)) ) == \ - expand(couple(uncouple( JzKetCoupled(0, 0, (S(1)/2,1,S(1)/2,1), ((1,3,1),(2,4,1),(1,2,0))) ), ((1,3),(2,4),(1,2)) )) - assert JzKetCoupled(1, 1, (S(1)/2,1,S(1)/2,1), ((1,3,1),(2,4,1),(1,2,1)) ) == \ - expand(couple(uncouple( JzKetCoupled(1, 1, (S(1)/2,1,S(1)/2,1), ((1,3,1),(2,4,1),(1,2,1))) ), ((1,3),(2,4),(1,2)) )) - assert JzKetCoupled(1, 0, (S(1)/2,1,S(1)/2,1), ((1,3,1),(2,4,1),(1,2,1)) ) == \ - expand(couple(uncouple( JzKetCoupled(1, 0, (S(1)/2,1,S(1)/2,1), ((1,3,1),(2,4,1),(1,2,1))) ), ((1,3),(2,4),(1,2)) )) - assert JzKetCoupled(1, -1, (S(1)/2,1,S(1)/2,1), ((1,3,1),(2,4,1),(1,2,1)) ) == \ - expand(couple(uncouple( JzKetCoupled(1, -1, (S(1)/2,1,S(1)/2,1), ((1,3,1),(2,4,1),(1,2,1))) ), ((1,3),(2,4),(1,2)) )) - assert JzKetCoupled(2, 2, (S(1)/2,1,S(1)/2,1), ((1,3,1),(2,4,1),(1,2,2)) ) == \ - expand(couple(uncouple( JzKetCoupled(2, 2, (S(1)/2,1,S(1)/2,1), ((1,3,1),(2,4,1),(1,2,2))) ), ((1,3),(2,4),(1,2)) )) - assert JzKetCoupled(2, 1, (S(1)/2,1,S(1)/2,1), ((1,3,1),(2,4,1),(1,2,2)) ) == \ - expand(couple(uncouple( JzKetCoupled(2, 1, (S(1)/2,1,S(1)/2,1), ((1,3,1),(2,4,1),(1,2,2))) ), ((1,3),(2,4),(1,2)) )) - assert JzKetCoupled(2, 0, (S(1)/2,1,S(1)/2,1), ((1,3,1),(2,4,1),(1,2,2)) ) == \ - expand(couple(uncouple( JzKetCoupled(2, 0, (S(1)/2,1,S(1)/2,1), ((1,3,1),(2,4,1),(1,2,2))) ), ((1,3),(2,4),(1,2)) )) - assert JzKetCoupled(2, -1, (S(1)/2,1,S(1)/2,1), ((1,3,1),(2,4,1),(1,2,2)) ) == \ - expand(couple(uncouple( JzKetCoupled(2, -1, (S(1)/2,1,S(1)/2,1), ((1,3,1),(2,4,1),(1,2,2))) ), ((1,3),(2,4),(1,2)) )) - assert JzKetCoupled(2, -2, (S(1)/2,1,S(1)/2,1), ((1,3,1),(2,4,1),(1,2,2)) ) == \ - expand(couple(uncouple( JzKetCoupled(2, -2, (S(1)/2,1,S(1)/2,1), ((1,3,1),(2,4,1),(1,2,2))) ), ((1,3),(2,4),(1,2)) )) + assert JzKetCoupled(0, 0, (S(1)/2, 1, S(1)/2, 1), ((1, 3, 1), (2, 4, 1), (1, 2, 0)) ) == \ + expand(couple(uncouple( JzKetCoupled(0, 0, (S(1)/2, 1, S(1)/2, 1), ( + (1, 3, 1), (2, 4, 1), (1, 2, 0))) ), ((1, 3), (2, 4), (1, 2)) )) + assert JzKetCoupled(1, 1, (S(1)/2, 1, S(1)/2, 1), ((1, 3, 1), (2, 4, 1), (1, 2, 1)) ) == \ + expand(couple(uncouple( JzKetCoupled(1, 1, (S(1)/2, 1, S(1)/2, 1), ( + (1, 3, 1), (2, 4, 1), (1, 2, 1))) ), ((1, 3), (2, 4), (1, 2)) )) + assert JzKetCoupled(1, 0, (S(1)/2, 1, S(1)/2, 1), ((1, 3, 1), (2, 4, 1), (1, 2, 1)) ) == \ + expand(couple(uncouple( JzKetCoupled(1, 0, (S(1)/2, 1, S(1)/2, 1), ( + (1, 3, 1), (2, 4, 1), (1, 2, 1))) ), ((1, 3), (2, 4), (1, 2)) )) + assert JzKetCoupled(1, -1, (S(1)/2, 1, S(1)/2, 1), ((1, 3, 1), (2, 4, 1), (1, 2, 1)) ) == \ + expand(couple(uncouple( JzKetCoupled(1, -1, (S(1)/2, 1, S(1)/2, 1), ( + (1, 3, 1), (2, 4, 1), (1, 2, 1))) ), ((1, 3), (2, 4), (1, 2)) )) + assert JzKetCoupled(2, 2, (S(1)/2, 1, S(1)/2, 1), ((1, 3, 1), (2, 4, 1), (1, 2, 2)) ) == \ + expand(couple(uncouple( JzKetCoupled(2, 2, (S(1)/2, 1, S(1)/2, 1), ( + (1, 3, 1), (2, 4, 1), (1, 2, 2))) ), ((1, 3), (2, 4), (1, 2)) )) + assert JzKetCoupled(2, 1, (S(1)/2, 1, S(1)/2, 1), ((1, 3, 1), (2, 4, 1), (1, 2, 2)) ) == \ + expand(couple(uncouple( JzKetCoupled(2, 1, (S(1)/2, 1, S(1)/2, 1), ( + (1, 3, 1), (2, 4, 1), (1, 2, 2))) ), ((1, 3), (2, 4), (1, 2)) )) + assert JzKetCoupled(2, 0, (S(1)/2, 1, S(1)/2, 1), ((1, 3, 1), (2, 4, 1), (1, 2, 2)) ) == \ + expand(couple(uncouple( JzKetCoupled(2, 0, (S(1)/2, 1, S(1)/2, 1), ( + (1, 3, 1), (2, 4, 1), (1, 2, 2))) ), ((1, 3), (2, 4), (1, 2)) )) + assert JzKetCoupled(2, -1, (S(1)/2, 1, S(1)/2, 1), ((1, 3, 1), (2, 4, 1), (1, 2, 2)) ) == \ + expand(couple(uncouple( JzKetCoupled(2, -1, (S(1)/2, 1, S(1)/2, 1), ( + (1, 3, 1), (2, 4, 1), (1, 2, 2))) ), ((1, 3), (2, 4), (1, 2)) )) + assert JzKetCoupled(2, -2, (S(1)/2, 1, S(1)/2, 1), ((1, 3, 1), (2, 4, 1), (1, 2, 2)) ) == \ + expand(couple(uncouple( JzKetCoupled(2, -2, (S(1)/2, 1, S(1)/2, 1), ( + (1, 3, 1), (2, 4, 1), (1, 2, 2))) ), ((1, 3), (2, 4), (1, 2)) )) + def test_couple_2_states_numerical(): # j1=1/2, j2=1/2 - assert couple(TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2))) == \ - JzKetCoupled(1, 1, (S(1)/2,S(1)/2)) - assert couple(TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,-S(1)/2))) == \ - sqrt(2)*JzKetCoupled(0, 0, (S(1)/2,S(1)/2))/2 + sqrt(2)*JzKetCoupled(1, 0, (S(1)/2,S(1)/2))/2 - assert couple(TensorProduct(JzKet(S(1)/2,-S(1)/2), JzKet(S(1)/2,S(1)/2))) == \ - -sqrt(2)*JzKetCoupled(0, 0, (S(1)/2,S(1)/2))/2 + sqrt(2)*JzKetCoupled(1, 0, (S(1)/2,S(1)/2))/2 - assert couple(TensorProduct(JzKet(S(1)/2,-S(1)/2), JzKet(S(1)/2,-S(1)/2))) == \ - JzKetCoupled(1, -1, (S(1)/2,S(1)/2)) + assert couple(TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2))) == \ + JzKetCoupled(1, 1, (S(1)/2, S(1)/2)) + assert couple(TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, -S(1)/2))) == \ + sqrt(2)*JzKetCoupled(0, 0, (S( + 1)/2, S(1)/2))/2 + sqrt(2)*JzKetCoupled(1, 0, (S(1)/2, S(1)/2))/2 + assert couple(TensorProduct(JzKet(S(1)/2, -S(1)/2), JzKet(S(1)/2, S(1)/2))) == \ + -sqrt(2)*JzKetCoupled(0, 0, (S( + 1)/2, S(1)/2))/2 + sqrt(2)*JzKetCoupled(1, 0, (S(1)/2, S(1)/2))/2 + assert couple(TensorProduct(JzKet(S(1)/2, -S(1)/2), JzKet(S(1)/2, -S(1)/2))) == \ + JzKetCoupled(1, -1, (S(1)/2, S(1)/2)) # j1=1, j2=1/2 - assert couple(TensorProduct(JzKet(1,1), JzKet(S(1)/2,S(1)/2))) == \ - JzKetCoupled(S(3)/2, S(3)/2, (1,S(1)/2)) - assert couple(TensorProduct(JzKet(1,1), JzKet(S(1)/2,-S(1)/2))) == \ - sqrt(6)*JzKetCoupled(S(1)/2, S(1)/2, (1,S(1)/2))/3 + sqrt(3)*JzKetCoupled(S(3)/2, S(1)/2, (1,S(1)/2))/3 - assert couple(TensorProduct(JzKet(1,0), JzKet(S(1)/2,S(1)/2))) == \ - -sqrt(3)*JzKetCoupled(S(1)/2, S(1)/2, (1,S(1)/2))/3 + sqrt(6)*JzKetCoupled(S(3)/2, S(1)/2, (1,S(1)/2))/3 - assert couple(TensorProduct(JzKet(1,0), JzKet(S(1)/2,-S(1)/2))) == \ - sqrt(3)*JzKetCoupled(S(1)/2, -S(1)/2, (1,S(1)/2))/3 + sqrt(6)*JzKetCoupled(S(3)/2, -S(1)/2, (1,S(1)/2))/3 - assert couple(TensorProduct(JzKet(1,-1), JzKet(S(1)/2,S(1)/2))) == \ - -sqrt(6)*JzKetCoupled(S(1)/2, -S(1)/2, (1,S(1)/2))/3 + sqrt(3)*JzKetCoupled(S(3)/2, -S(1)/2, (1,S(1)/2))/3 - assert couple(TensorProduct(JzKet(1,-1), JzKet(S(1)/2,-S(1)/2))) == \ - JzKetCoupled(S(3)/2, -S(3)/2, (1,S(1)/2)) + assert couple(TensorProduct(JzKet(1, 1), JzKet(S(1)/2, S(1)/2))) == \ + JzKetCoupled(S(3)/2, S(3)/2, (1, S(1)/2)) + assert couple(TensorProduct(JzKet(1, 1), JzKet(S(1)/2, -S(1)/2))) == \ + sqrt(6)*JzKetCoupled(S(1)/2, S(1)/2, (1, S(1)/2))/3 + sqrt( + 3)*JzKetCoupled(S(3)/2, S(1)/2, (1, S(1)/2))/3 + assert couple(TensorProduct(JzKet(1, 0), JzKet(S(1)/2, S(1)/2))) == \ + -sqrt(3)*JzKetCoupled(S(1)/2, S(1)/2, (1, S(1)/2))/3 + \ + sqrt(6)*JzKetCoupled(S(3)/2, S(1)/2, (1, S(1)/2))/3 + assert couple(TensorProduct(JzKet(1, 0), JzKet(S(1)/2, -S(1)/2))) == \ + sqrt(3)*JzKetCoupled(S(1)/2, -S(1)/2, (1, S(1)/2))/3 + \ + sqrt(6)*JzKetCoupled(S(3)/2, -S(1)/2, (1, S(1)/2))/3 + assert couple(TensorProduct(JzKet(1, -1), JzKet(S(1)/2, S(1)/2))) == \ + -sqrt(6)*JzKetCoupled(S(1)/2, -S(1)/2, (1, S( + 1)/2))/3 + sqrt(3)*JzKetCoupled(S(3)/2, -S(1)/2, (1, S(1)/2))/3 + assert couple(TensorProduct(JzKet(1, -1), JzKet(S(1)/2, -S(1)/2))) == \ + JzKetCoupled(S(3)/2, -S(3)/2, (1, S(1)/2)) # j1=1, j2=1 - assert couple(TensorProduct(JzKet(1,1), JzKet(1,1))) == \ - JzKetCoupled(2, 2, (1,1)) - assert couple(TensorProduct(JzKet(1,1), JzKet(1,0))) == \ - sqrt(2)*JzKetCoupled(1, 1, (1,1))/2 + sqrt(2)*JzKetCoupled(2, 1, (1,1))/2 - assert couple(TensorProduct(JzKet(1,1), JzKet(1,-1))) == \ - sqrt(3)*JzKetCoupled(0, 0, (1,1))/3 + sqrt(2)*JzKetCoupled(1, 0, (1,1))/2 + sqrt(6)*JzKetCoupled(2, 0, (1,1))/6 - assert couple(TensorProduct(JzKet(1,0), JzKet(1,1))) == \ - -sqrt(2)*JzKetCoupled(1, 1, (1,1))/2 + sqrt(2)*JzKetCoupled(2, 1, (1,1))/2 - assert couple(TensorProduct(JzKet(1,0), JzKet(1,0))) == \ - -sqrt(3)*JzKetCoupled(0, 0, (1,1))/3+sqrt(6)*JzKetCoupled(2, 0, (1,1))/3 - assert couple(TensorProduct(JzKet(1,0), JzKet(1,-1))) == \ - sqrt(2)*JzKetCoupled(1, -1, (1,1))/2 + sqrt(2)*JzKetCoupled(2, -1, (1,1))/2 - assert couple(TensorProduct(JzKet(1,-1), JzKet(1,1))) == \ - sqrt(3)*JzKetCoupled(0, 0, (1,1))/3 - sqrt(2)*JzKetCoupled(1, 0, (1,1))/2 + sqrt(6)*JzKetCoupled(2, 0, (1,1))/6 - assert couple(TensorProduct(JzKet(1,-1), JzKet(1,0))) == \ - -sqrt(2)*JzKetCoupled(1, -1, (1,1))/2 + sqrt(2)*JzKetCoupled(2, -1, (1,1))/2 - assert couple(TensorProduct(JzKet(1,-1), JzKet(1,-1))) == \ - JzKetCoupled(2, -2, (1,1)) + assert couple(TensorProduct(JzKet(1, 1), JzKet(1, 1))) == \ + JzKetCoupled(2, 2, (1, 1)) + assert couple(TensorProduct(JzKet(1, 1), JzKet(1, 0))) == \ + sqrt(2)*JzKetCoupled( + 1, 1, (1, 1))/2 + sqrt(2)*JzKetCoupled(2, 1, (1, 1))/2 + assert couple(TensorProduct(JzKet(1, 1), JzKet(1, -1))) == \ + sqrt(3)*JzKetCoupled(0, 0, (1, 1))/3 + sqrt(2)*JzKetCoupled( + 1, 0, (1, 1))/2 + sqrt(6)*JzKetCoupled(2, 0, (1, 1))/6 + assert couple(TensorProduct(JzKet(1, 0), JzKet(1, 1))) == \ + -sqrt(2)*JzKetCoupled( + 1, 1, (1, 1))/2 + sqrt(2)*JzKetCoupled(2, 1, (1, 1))/2 + assert couple(TensorProduct(JzKet(1, 0), JzKet(1, 0))) == \ + -sqrt(3)*JzKetCoupled( + 0, 0, (1, 1))/3 + sqrt(6)*JzKetCoupled(2, 0, (1, 1))/3 + assert couple(TensorProduct(JzKet(1, 0), JzKet(1, -1))) == \ + sqrt(2)*JzKetCoupled( + 1, -1, (1, 1))/2 + sqrt(2)*JzKetCoupled(2, -1, (1, 1))/2 + assert couple(TensorProduct(JzKet(1, -1), JzKet(1, 1))) == \ + sqrt(3)*JzKetCoupled(0, 0, (1, 1))/3 - sqrt(2)*JzKetCoupled( + 1, 0, (1, 1))/2 + sqrt(6)*JzKetCoupled(2, 0, (1, 1))/6 + assert couple(TensorProduct(JzKet(1, -1), JzKet(1, 0))) == \ + -sqrt(2)*JzKetCoupled( + 1, -1, (1, 1))/2 + sqrt(2)*JzKetCoupled(2, -1, (1, 1))/2 + assert couple(TensorProduct(JzKet(1, -1), JzKet(1, -1))) == \ + JzKetCoupled(2, -2, (1, 1)) # j1=3/2, j2=1/2 - assert couple(TensorProduct(JzKet(S(3)/2,S(3)/2), JzKet(S(1)/2,S(1)/2))) == \ - JzKetCoupled(2,2,(S(3)/2,S(1)/2)) - assert couple(TensorProduct(JzKet(S(3)/2,S(3)/2), JzKet(S(1)/2,-S(1)/2))) == \ - sqrt(3)*JzKetCoupled(1,1,(S(3)/2,S(1)/2))/2 + JzKetCoupled(2,1,(S(3)/2,S(1)/2))/2 - assert couple(TensorProduct(JzKet(S(3)/2,S(1)/2), JzKet(S(1)/2,S(1)/2))) == \ - -JzKetCoupled(1,1,(S(3)/2,S(1)/2))/2 + sqrt(3)*JzKetCoupled(2,1,(S(3)/2,S(1)/2))/2 - assert couple(TensorProduct(JzKet(S(3)/2,S(1)/2), JzKet(S(1)/2,-S(1)/2))) == \ - sqrt(2)*JzKetCoupled(1,0,(S(3)/2,S(1)/2))/2 + sqrt(2)*JzKetCoupled(2,0,(S(3)/2,S(1)/2))/2 - assert couple(TensorProduct(JzKet(S(3)/2,-S(1)/2), JzKet(S(1)/2,S(1)/2))) == \ - -sqrt(2)*JzKetCoupled(1,0,(S(3)/2,S(1)/2))/2 + sqrt(2)*JzKetCoupled(2,0,(S(3)/2,S(1)/2))/2 - assert couple(TensorProduct(JzKet(S(3)/2,-S(1)/2), JzKet(S(1)/2,-S(1)/2))) == \ - JzKetCoupled(1,-1,(S(3)/2,S(1)/2))/2 + sqrt(3)*JzKetCoupled(2,-1,(S(3)/2,S(1)/2))/2 - assert couple(TensorProduct(JzKet(S(3)/2,-S(3)/2), JzKet(S(1)/2,S(1)/2))) == \ - -sqrt(3)*JzKetCoupled(1,-1,(S(3)/2,S(1)/2))/2 + JzKetCoupled(2,-1,(S(3)/2,S(1)/2))/2 - assert couple(TensorProduct(JzKet(S(3)/2,-S(3)/2), JzKet(S(1)/2,-S(1)/2))) == \ - JzKetCoupled(2,-2,(S(3)/2,S(1)/2)) + assert couple(TensorProduct(JzKet(S(3)/2, S(3)/2), JzKet(S(1)/2, S(1)/2))) == \ + JzKetCoupled(2, 2, (S(3)/2, S(1)/2)) + assert couple(TensorProduct(JzKet(S(3)/2, S(3)/2), JzKet(S(1)/2, -S(1)/2))) == \ + sqrt(3)*JzKetCoupled( + 1, 1, (S(3)/2, S(1)/2))/2 + JzKetCoupled(2, 1, (S(3)/2, S(1)/2))/2 + assert couple(TensorProduct(JzKet(S(3)/2, S(1)/2), JzKet(S(1)/2, S(1)/2))) == \ + -JzKetCoupled(1, 1, (S( + 3)/2, S(1)/2))/2 + sqrt(3)*JzKetCoupled(2, 1, (S(3)/2, S(1)/2))/2 + assert couple(TensorProduct(JzKet(S(3)/2, S(1)/2), JzKet(S(1)/2, -S(1)/2))) == \ + sqrt(2)*JzKetCoupled(1, 0, (S( + 3)/2, S(1)/2))/2 + sqrt(2)*JzKetCoupled(2, 0, (S(3)/2, S(1)/2))/2 + assert couple(TensorProduct(JzKet(S(3)/2, -S(1)/2), JzKet(S(1)/2, S(1)/2))) == \ + -sqrt(2)*JzKetCoupled(1, 0, (S( + 3)/2, S(1)/2))/2 + sqrt(2)*JzKetCoupled(2, 0, (S(3)/2, S(1)/2))/2 + assert couple(TensorProduct(JzKet(S(3)/2, -S(1)/2), JzKet(S(1)/2, -S(1)/2))) == \ + JzKetCoupled(1, -1, (S( + 3)/2, S(1)/2))/2 + sqrt(3)*JzKetCoupled(2, -1, (S(3)/2, S(1)/2))/2 + assert couple(TensorProduct(JzKet(S(3)/2, -S(3)/2), JzKet(S(1)/2, S(1)/2))) == \ + -sqrt(3)*JzKetCoupled(1, -1, (S(3)/2, S(1)/2))/2 + \ + JzKetCoupled(2, -1, (S(3)/2, S(1)/2))/2 + assert couple(TensorProduct(JzKet(S(3)/2, -S(3)/2), JzKet(S(1)/2, -S(1)/2))) == \ + JzKetCoupled(2, -2, (S(3)/2, S(1)/2)) + def test_couple_3_states_numerical(): # Default coupling # j1=1/2,j2=1/2,j3=1/2 - assert couple(TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2))) == \ - JzKetCoupled(S(3)/2, S(3)/2, (S(1)/2,S(1)/2,S(1)/2), ((1,2,1),(1,3,S(3)/2)) ) - assert couple(TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(-1)/2))) == \ - sqrt(6)*JzKetCoupled(S(1)/2, S(1)/2, (S(1)/2,S(1)/2,S(1)/2), ((1,2,1),(1,3,S(1)/2)) )/3 + \ - sqrt(3)*JzKetCoupled(S(3)/2, S(1)/2, (S(1)/2,S(1)/2,S(1)/2), ((1,2,1),(1,3,S(3)/2)) )/3 - assert couple(TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(1)/2))) == \ - sqrt(2)*JzKetCoupled(S(1)/2, S(1)/2, (S(1)/2,S(1)/2,S(1)/2), ((1,2,0),(1,3,S(1)/2)) )/2 - \ - sqrt(6)*JzKetCoupled(S(1)/2, S(1)/2, (S(1)/2,S(1)/2,S(1)/2), ((1,2,1),(1,3,S(1)/2)) )/6 + \ - sqrt(3)*JzKetCoupled(S(3)/2, S(1)/2, (S(1)/2,S(1)/2,S(1)/2), ((1,2,1),(1,3,S(3)/2)) )/3 - assert couple(TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(-1)/2))) == \ - sqrt(2)*JzKetCoupled(S(1)/2, -S(1)/2, (S(1)/2,S(1)/2,S(1)/2), ((1,2,0),(1,3,S(1)/2)) )/2 + \ - sqrt(6)*JzKetCoupled(S(1)/2, -S(1)/2, (S(1)/2,S(1)/2,S(1)/2), ((1,2,1),(1,3,S(1)/2)) )/6 + \ - sqrt(3)*JzKetCoupled(S(3)/2, -S(1)/2, (S(1)/2,S(1)/2,S(1)/2), ((1,2,1),(1,3,S(3)/2)) )/3 - assert couple(TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2))) == \ - -sqrt(2)*JzKetCoupled(S(1)/2, S(1)/2, (S(1)/2,S(1)/2,S(1)/2), ((1,2,0),(1,3,S(1)/2)) )/2 - \ - sqrt(6)*JzKetCoupled(S(1)/2, S(1)/2, (S(1)/2,S(1)/2,S(1)/2), ((1,2,1),(1,3,S(1)/2)) )/6 + \ - sqrt(3)*JzKetCoupled(S(3)/2, S(1)/2, (S(1)/2,S(1)/2,S(1)/2), ((1,2,1),(1,3,S(3)/2)) )/3 - assert couple(TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(-1)/2))) == \ - -sqrt(2)*JzKetCoupled(S(1)/2, -S(1)/2, (S(1)/2,S(1)/2,S(1)/2), ((1,2,0),(1,3,S(1)/2)) )/2 + \ - sqrt(6)*JzKetCoupled(S(1)/2, -S(1)/2, (S(1)/2,S(1)/2,S(1)/2), ((1,2,1),(1,3,S(1)/2)) )/6 + \ - sqrt(3)*JzKetCoupled(S(3)/2, -S(1)/2, (S(1)/2,S(1)/2,S(1)/2), ((1,2,1),(1,3,S(3)/2)) )/3 - assert couple(TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(1)/2))) == \ - -sqrt(6)*JzKetCoupled(S(1)/2, -S(1)/2, (S(1)/2,S(1)/2,S(1)/2), ((1,2,1),(1,3,S(1)/2)) )/3 + \ - sqrt(3)*JzKetCoupled(S(3)/2, -S(1)/2, (S(1)/2,S(1)/2,S(1)/2), ((1,2,1),(1,3,S(3)/2)) )/3 - assert couple(TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(-1)/2))) == \ - JzKetCoupled(S(3)/2, -S(3)/2, (S(1)/2,S(1)/2,S(1)/2), ((1,2,1),(1,3,S(3)/2)) ) + assert couple(TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2))) == \ + JzKetCoupled(S(3)/2, S( + 3)/2, (S(1)/2, S(1)/2, S(1)/2), ((1, 2, 1), (1, 3, S(3)/2)) ) + assert couple(TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(-1)/2))) == \ + sqrt(6)*JzKetCoupled(S(1)/2, S(1)/2, (S(1)/2, S(1)/2, S(1)/2), ((1, 2, 1), (1, 3, S(1)/2)) )/3 + \ + sqrt(3)*JzKetCoupled(S(3)/2, S(1)/2, (S(1)/2, S(1)/2, S(1)/ + 2), ((1, 2, 1), (1, 3, S(3)/2)) )/3 + assert couple(TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(1)/2))) == \ + sqrt(2)*JzKetCoupled(S(1)/2, S(1)/2, (S(1)/2, S(1)/2, S(1)/2), ((1, 2, 0), (1, 3, S(1)/2)) )/2 - \ + sqrt(6)*JzKetCoupled(S(1)/2, S(1)/2, (S(1)/2, S(1)/2, S(1)/2), ((1, 2, 1), (1, 3, S(1)/2)) )/6 + \ + sqrt(3)*JzKetCoupled(S(3)/2, S(1)/2, (S(1)/2, S(1)/2, S(1)/ + 2), ((1, 2, 1), (1, 3, S(3)/2)) )/3 + assert couple(TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(-1)/2))) == \ + sqrt(2)*JzKetCoupled(S(1)/2, -S(1)/2, (S(1)/2, S(1)/2, S(1)/2), ((1, 2, 0), (1, 3, S(1)/2)) )/2 + \ + sqrt(6)*JzKetCoupled(S(1)/2, -S(1)/2, (S(1)/2, S(1)/2, S(1)/2), ((1, 2, 1), (1, 3, S(1)/2)) )/6 + \ + sqrt(3)*JzKetCoupled(S(3)/2, -S(1)/2, (S(1)/2, S(1)/2, S(1) + /2), ((1, 2, 1), (1, 3, S(3)/2)) )/3 + assert couple(TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2))) == \ + -sqrt(2)*JzKetCoupled(S(1)/2, S(1)/2, (S(1)/2, S(1)/2, S(1)/2), ((1, 2, 0), (1, 3, S(1)/2)) )/2 - \ + sqrt(6)*JzKetCoupled(S(1)/2, S(1)/2, (S(1)/2, S(1)/2, S(1)/2), ((1, 2, 1), (1, 3, S(1)/2)) )/6 + \ + sqrt(3)*JzKetCoupled(S(3)/2, S(1)/2, (S(1)/2, S(1)/2, S(1)/ + 2), ((1, 2, 1), (1, 3, S(3)/2)) )/3 + assert couple(TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(-1)/2))) == \ + -sqrt(2)*JzKetCoupled(S(1)/2, -S(1)/2, (S(1)/2, S(1)/2, S(1)/2), ((1, 2, 0), (1, 3, S(1)/2)) )/2 + \ + sqrt(6)*JzKetCoupled(S(1)/2, -S(1)/2, (S(1)/2, S(1)/2, S(1)/2), ((1, 2, 1), (1, 3, S(1)/2)) )/6 + \ + sqrt(3)*JzKetCoupled(S(3)/2, -S(1)/2, (S(1)/2, S(1)/2, S(1) + /2), ((1, 2, 1), (1, 3, S(3)/2)) )/3 + assert couple(TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(1)/2))) == \ + -sqrt(6)*JzKetCoupled(S(1)/2, -S(1)/2, (S(1)/2, S(1)/2, S(1)/2), ((1, 2, 1), (1, 3, S(1)/2)) )/3 + \ + sqrt(3)*JzKetCoupled(S(3)/2, -S(1)/2, (S(1)/2, S(1)/2, S(1) + /2), ((1, 2, 1), (1, 3, S(3)/2)) )/3 + assert couple(TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(-1)/2))) == \ + JzKetCoupled(S(3)/2, -S( + 3)/2, (S(1)/2, S(1)/2, S(1)/2), ((1, 2, 1), (1, 3, S(3)/2)) ) # j1=S(1)/2, j2=S(1)/2, j3=1 - assert couple(TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,1))) == \ - JzKetCoupled(2, 2, (S(1)/2,S(1)/2,1), ((1,2,1),(1,3,2)) ) - assert couple(TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,0))) == \ - sqrt(2)*JzKetCoupled(1, 1, (S(1)/2,S(1)/2,1), ((1,2,1),(1,3,1)) )/2 + \ - sqrt(2)*JzKetCoupled(2, 1, (S(1)/2,S(1)/2,1), ((1,2,1),(1,3,2)) )/2 - assert couple(TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,-1))) == \ - sqrt(3)*JzKetCoupled(0, 0, (S(1)/2,S(1)/2,1), ((1,2,1),(1,3,0)) )/3 + \ - sqrt(2)*JzKetCoupled(1, 0, (S(1)/2,S(1)/2,1), ((1,2,1),(1,3,1)) )/2 + \ - sqrt(6)*JzKetCoupled(2, 0, (S(1)/2,S(1)/2,1), ((1,2,1),(1,3,2)) )/6 - assert couple(TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(1,1))) == \ - sqrt(2)*JzKetCoupled(1, 1, (S(1)/2,S(1)/2,1), ((1,2,0),(1,3,1)) )/2 - \ - JzKetCoupled(1, 1, (S(1)/2,S(1)/2,1), ((1,2,1),(1,3,1)) )/2 + \ - JzKetCoupled(2, 1, (S(1)/2,S(1)/2,1), ((1,2,1),(1,3,2)) )/2 - assert couple(TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(1,0))) == \ - -sqrt(6)*JzKetCoupled(0, 0, (S(1)/2,S(1)/2,1), ((1,2,1),(1,3,0)) )/6 + \ - sqrt(2)*JzKetCoupled(1, 0, (S(1)/2,S(1)/2,1), ((1,2,0),(1,3,1)) )/2 + \ - sqrt(3)*JzKetCoupled(2, 0, (S(1)/2,S(1)/2,1), ((1,2,1),(1,3,2)) )/3 - assert couple(TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(1,-1))) == \ - sqrt(2)*JzKetCoupled(1, -1, (S(1)/2,S(1)/2,1), ((1,2,0),(1,3,1)) )/2 + \ - JzKetCoupled(1, -1, (S(1)/2,S(1)/2,1), ((1,2,1),(1,3,1)) )/2 + \ - JzKetCoupled(2, -1, (S(1)/2,S(1)/2,1), ((1,2,1),(1,3,2)) )/2 - assert couple(TensorProduct(JzKet(S(1)/2,-S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,1))) == \ - -sqrt(2)*JzKetCoupled(1, 1, (S(1)/2,S(1)/2,1), ((1,2,0),(1,3,1)) )/2 - \ - JzKetCoupled(1, 1, (S(1)/2,S(1)/2,1), ((1,2,1),(1,3,1)) )/2 + \ - JzKetCoupled(2, 1, (S(1)/2,S(1)/2,1), ((1,2,1),(1,3,2)) )/2 - assert couple(TensorProduct(JzKet(S(1)/2,-S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,0))) == \ - -sqrt(6)*JzKetCoupled(0, 0, (S(1)/2,S(1)/2,1), ((1,2,1),(1,3,0)) )/6 - \ - sqrt(2)*JzKetCoupled(1, 0, (S(1)/2,S(1)/2,1), ((1,2,0),(1,3,1)) )/2 + \ - sqrt(3)*JzKetCoupled(2, 0, (S(1)/2,S(1)/2,1), ((1,2,1),(1,3,2)) )/3 - assert couple(TensorProduct(JzKet(S(1)/2,-S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,-1))) == \ - -sqrt(2)*JzKetCoupled(1, -1, (S(1)/2,S(1)/2,1), ((1,2,0),(1,3,1)) )/2 + \ - JzKetCoupled(1, -1, (S(1)/2,S(1)/2,1), ((1,2,1),(1,3,1)) )/2 + \ - JzKetCoupled(2, -1, (S(1)/2,S(1)/2,1), ((1,2,1),(1,3,2)) )/2 - assert couple(TensorProduct(JzKet(S(1)/2,-S(1)/2), JzKet(S(1)/2,-S(1)/2), JzKet(1,1))) == \ - sqrt(3)*JzKetCoupled(0, 0, (S(1)/2,S(1)/2,1), ((1,2,1),(1,3,0)) )/3 - \ - sqrt(2)*JzKetCoupled(1, 0, (S(1)/2,S(1)/2,1), ((1,2,1),(1,3,1)) )/2 + \ - sqrt(6)*JzKetCoupled(2, 0, (S(1)/2,S(1)/2,1), ((1,2,1),(1,3,2)) )/6 - assert couple(TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,-S(1)/2), JzKet(1,0))) == \ - -sqrt(2)*JzKetCoupled(1, -1, (S(1)/2,S(1)/2,1), ((1,2,1),(1,3,1)) )/2 + \ - sqrt(2)*JzKetCoupled(2, -1, (S(1)/2,S(1)/2,1), ((1,2,1),(1,3,2)) )/2 - assert couple(TensorProduct(JzKet(S(1)/2,-S(1)/2), JzKet(S(1)/2,-S(1)/2), JzKet(1,-1))) == \ - JzKetCoupled(2, -2, (S(1)/2,S(1)/2,1), ((1,2,1),(1,3,2)) ) + assert couple(TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, 1))) == \ + JzKetCoupled(2, 2, (S(1)/2, S(1)/2, 1), ((1, 2, 1), (1, 3, 2)) ) + assert couple(TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, 0))) == \ + sqrt(2)*JzKetCoupled(1, 1, (S(1)/2, S(1)/2, 1), ((1, 2, 1), (1, 3, 1)) )/2 + \ + sqrt(2)*JzKetCoupled( + 2, 1, (S(1)/2, S(1)/2, 1), ((1, 2, 1), (1, 3, 2)) )/2 + assert couple(TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, -1))) == \ + sqrt(3)*JzKetCoupled(0, 0, (S(1)/2, S(1)/2, 1), ((1, 2, 1), (1, 3, 0)) )/3 + \ + sqrt(2)*JzKetCoupled(1, 0, (S(1)/2, S(1)/2, 1), ((1, 2, 1), (1, 3, 1)) )/2 + \ + sqrt(6)*JzKetCoupled( + 2, 0, (S(1)/2, S(1)/2, 1), ((1, 2, 1), (1, 3, 2)) )/6 + assert couple(TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(1, 1))) == \ + sqrt(2)*JzKetCoupled(1, 1, (S(1)/2, S(1)/2, 1), ((1, 2, 0), (1, 3, 1)) )/2 - \ + JzKetCoupled(1, 1, (S(1)/2, S(1)/2, 1), ((1, 2, 1), (1, 3, 1)) )/2 + \ + JzKetCoupled(2, 1, (S(1)/2, S(1)/2, 1), ((1, 2, 1), (1, 3, 2)) )/2 + assert couple(TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(1, 0))) == \ + -sqrt(6)*JzKetCoupled(0, 0, (S(1)/2, S(1)/2, 1), ((1, 2, 1), (1, 3, 0)) )/6 + \ + sqrt(2)*JzKetCoupled(1, 0, (S(1)/2, S(1)/2, 1), ((1, 2, 0), (1, 3, 1)) )/2 + \ + sqrt(3)*JzKetCoupled( + 2, 0, (S(1)/2, S(1)/2, 1), ((1, 2, 1), (1, 3, 2)) )/3 + assert couple(TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(1, -1))) == \ + sqrt(2)*JzKetCoupled(1, -1, (S(1)/2, S(1)/2, 1), ((1, 2, 0), (1, 3, 1)) )/2 + \ + JzKetCoupled(1, -1, (S(1)/2, S(1)/2, 1), ((1, 2, 1), (1, 3, 1)) )/2 + \ + JzKetCoupled(2, -1, (S(1)/2, S(1)/2, 1), ((1, 2, 1), (1, 3, 2)) )/2 + assert couple(TensorProduct(JzKet(S(1)/2, -S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, 1))) == \ + -sqrt(2)*JzKetCoupled(1, 1, (S(1)/2, S(1)/2, 1), ((1, 2, 0), (1, 3, 1)) )/2 - \ + JzKetCoupled(1, 1, (S(1)/2, S(1)/2, 1), ((1, 2, 1), (1, 3, 1)) )/2 + \ + JzKetCoupled(2, 1, (S(1)/2, S(1)/2, 1), ((1, 2, 1), (1, 3, 2)) )/2 + assert couple(TensorProduct(JzKet(S(1)/2, -S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, 0))) == \ + -sqrt(6)*JzKetCoupled(0, 0, (S(1)/2, S(1)/2, 1), ((1, 2, 1), (1, 3, 0)) )/6 - \ + sqrt(2)*JzKetCoupled(1, 0, (S(1)/2, S(1)/2, 1), ((1, 2, 0), (1, 3, 1)) )/2 + \ + sqrt(3)*JzKetCoupled( + 2, 0, (S(1)/2, S(1)/2, 1), ((1, 2, 1), (1, 3, 2)) )/3 + assert couple(TensorProduct(JzKet(S(1)/2, -S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, -1))) == \ + -sqrt(2)*JzKetCoupled(1, -1, (S(1)/2, S(1)/2, 1), ((1, 2, 0), (1, 3, 1)) )/2 + \ + JzKetCoupled(1, -1, (S(1)/2, S(1)/2, 1), ((1, 2, 1), (1, 3, 1)) )/2 + \ + JzKetCoupled(2, -1, (S(1)/2, S(1)/2, 1), ((1, 2, 1), (1, 3, 2)) )/2 + assert couple(TensorProduct(JzKet(S(1)/2, -S(1)/2), JzKet(S(1)/2, -S(1)/2), JzKet(1, 1))) == \ + sqrt(3)*JzKetCoupled(0, 0, (S(1)/2, S(1)/2, 1), ((1, 2, 1), (1, 3, 0)) )/3 - \ + sqrt(2)*JzKetCoupled(1, 0, (S(1)/2, S(1)/2, 1), ((1, 2, 1), (1, 3, 1)) )/2 + \ + sqrt(6)*JzKetCoupled( + 2, 0, (S(1)/2, S(1)/2, 1), ((1, 2, 1), (1, 3, 2)) )/6 + assert couple(TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, -S(1)/2), JzKet(1, 0))) == \ + -sqrt(2)*JzKetCoupled(1, -1, (S(1)/2, S(1)/2, 1), ((1, 2, 1), (1, 3, 1)) )/2 + \ + sqrt(2)*JzKetCoupled( + 2, -1, (S(1)/2, S(1)/2, 1), ((1, 2, 1), (1, 3, 2)) )/2 + assert couple(TensorProduct(JzKet(S(1)/2, -S(1)/2), JzKet(S(1)/2, -S(1)/2), JzKet(1, -1))) == \ + JzKetCoupled(2, -2, (S(1)/2, S(1)/2, 1), ((1, 2, 1), (1, 3, 2)) ) # j1=S(1)/2, j2=1, j3=1 - assert couple(TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(1,1), JzKet(1,1))) == \ - JzKetCoupled(S(5)/2,S(5)/2, (S(1)/2,1,1), ((1,2,S(3)/2),(1,3,S(5)/2)) ) - assert couple(TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(1,1), JzKet(1,0))) == \ - sqrt(15)*JzKetCoupled(S(3)/2,S(3)/2, (S(1)/2,1,1), ((1,2,S(3)/2),(1,3,S(3)/2)) )/5 + \ - sqrt(10)*JzKetCoupled(S(5)/2,S(3)/2, (S(1)/2,1,1), ((1,2,S(3)/2),(1,3,S(5)/2)) )/5 - assert couple(TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(1,1), JzKet(1,-1))) == \ - sqrt(2)*JzKetCoupled(S(1)/2,S(1)/2, (S(1)/2,1,1), ((1,2,S(3)/2),(1,3,S(1)/2)) )/2 + \ - sqrt(10)*JzKetCoupled(S(3)/2,S(1)/2, (S(1)/2,1,1), ((1,2,S(3)/2),(1,3,S(3)/2)) )/5 + \ - sqrt(10)*JzKetCoupled(S(5)/2,S(1)/2, (S(1)/2,1,1), ((1,2,S(3)/2),(1,3,S(5)/2)) )/10 - assert couple(TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(1,0), JzKet(1,1))) == \ - sqrt(3)*JzKetCoupled(S(3)/2,S(3)/2, (S(1)/2,1,1), ((1,2,S(1)/2),(1,3,S(3)/2)) )/3 - \ - 2*sqrt(15)*JzKetCoupled(S(3)/2,S(3)/2, (S(1)/2,1,1), ((1,2,S(3)/2),(1,3,S(3)/2)) )/15 + \ - sqrt(10)*JzKetCoupled(S(5)/2,S(3)/2, (S(1)/2,1,1), ((1,2,S(3)/2),(1,3,S(5)/2)) )/5 - assert couple(TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(1,0), JzKet(1,0))) == \ - JzKetCoupled(S(1)/2,S(1)/2, (S(1)/2,1,1), ((1,2,S(1)/2),(1,3,S(1)/2)) )/3 - \ - sqrt(2)*JzKetCoupled(S(1)/2,S(1)/2, (S(1)/2,1,1), ((1,2,S(3)/2),(1,3,S(1)/2)) )/3 + \ - sqrt(2)*JzKetCoupled(S(3)/2,S(1)/2, (S(1)/2,1,1), ((1,2,S(1)/2),(1,3,S(3)/2)) )/3 + \ - sqrt(10)*JzKetCoupled(S(3)/2,S(1)/2, (S(1)/2,1,1), ((1,2,S(3)/2),(1,3,S(3)/2)) )/15 + \ - sqrt(10)*JzKetCoupled(S(5)/2,S(1)/2, (S(1)/2,1,1), ((1,2,S(3)/2),(1,3,S(5)/2)) )/5 - assert couple(TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(1,0), JzKet(1,-1))) == \ - sqrt(2)*JzKetCoupled(S(1)/2,-S(1)/2, (S(1)/2,1,1), ((1,2,S(1)/2),(1,3,S(1)/2)) )/3 + \ - JzKetCoupled(S(1)/2,-S(1)/2, (S(1)/2,1,1), ((1,2,S(3)/2),(1,3,S(1)/2)) )/3 + \ - JzKetCoupled(S(3)/2,-S(1)/2, (S(1)/2,1,1), ((1,2,S(1)/2),(1,3,S(3)/2)) )/3 + \ - 4*sqrt(5)*JzKetCoupled(S(3)/2,-S(1)/2, (S(1)/2,1,1), ((1,2,S(3)/2),(1,3,S(3)/2)) )/15 + \ - sqrt(5)*JzKetCoupled(S(5)/2,-S(1)/2, (S(1)/2,1,1), ((1,2,S(3)/2),(1,3,S(5)/2)) )/5 - assert couple(TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(1,-1), JzKet(1,1))) == \ - -2*JzKetCoupled(S(1)/2,S(1)/2, (S(1)/2,1,1), ((1,2,S(1)/2),(1,3,S(1)/2)) )/3 + \ - sqrt(2)*JzKetCoupled(S(1)/2,S(1)/2, (S(1)/2,1,1), ((1,2,S(3)/2),(1,3,S(1)/2)) )/6 + \ - sqrt(2)*JzKetCoupled(S(3)/2,S(1)/2, (S(1)/2,1,1), ((1,2,S(1)/2),(1,3,S(3)/2)) )/3 - \ - 2*sqrt(10)*JzKetCoupled(S(3)/2,S(1)/2, (S(1)/2,1,1), ((1,2,S(3)/2),(1,3,S(3)/2)) )/15 + \ - sqrt(10)*JzKetCoupled(S(5)/2,S(1)/2, (S(1)/2,1,1), ((1,2,S(3)/2),(1,3,S(5)/2)) )/10 - assert couple(TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(1,-1), JzKet(1,0))) == \ - -sqrt(2)*JzKetCoupled(S(1)/2,-S(1)/2, (S(1)/2,1,1), ((1,2,S(1)/2),(1,3,S(1)/2)) )/3 - \ - JzKetCoupled(S(1)/2,-S(1)/2, (S(1)/2,1,1), ((1,2,S(3)/2),(1,3,S(1)/2)) )/3 + \ - 2*JzKetCoupled(S(3)/2,-S(1)/2, (S(1)/2,1,1), ((1,2,S(1)/2),(1,3,S(3)/2)) )/3 - \ - sqrt(5)*JzKetCoupled(S(3)/2,-S(1)/2, (S(1)/2,1,1), ((1,2,S(3)/2),(1,3,S(3)/2)) )/15 + \ - sqrt(5)*JzKetCoupled(S(5)/2,-S(1)/2, (S(1)/2,1,1), ((1,2,S(3)/2),(1,3,S(5)/2)) )/5 - assert couple(TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(1,-1), JzKet(1,-1))) == \ - sqrt(6)*JzKetCoupled(S(3)/2,-S(3)/2, (S(1)/2,1,1), ((1,2,S(1)/2),(1,3,S(3)/2)) )/3 + \ - sqrt(30)*JzKetCoupled(S(3)/2,-S(3)/2, (S(1)/2,1,1), ((1,2,S(3)/2),(1,3,S(3)/2)) )/15 + \ - sqrt(5)*JzKetCoupled(S(5)/2,-S(3)/2, (S(1)/2,1,1), ((1,2,S(3)/2),(1,3,S(5)/2)) )/5 - assert couple(TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(1,1), JzKet(1,1))) == \ - -sqrt(6)*JzKetCoupled(S(3)/2,S(3)/2, (S(1)/2,1,1), ((1,2,S(1)/2),(1,3,S(3)/2)) )/3 - \ - sqrt(30)*JzKetCoupled(S(3)/2,S(3)/2, (S(1)/2,1,1), ((1,2,S(3)/2),(1,3,S(3)/2)) )/15 + \ - sqrt(5)*JzKetCoupled(S(5)/2,S(3)/2, (S(1)/2,1,1), ((1,2,S(3)/2),(1,3,S(5)/2)) )/5 - assert couple(TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(1,1), JzKet(1,0))) == \ - -sqrt(2)*JzKetCoupled(S(1)/2,S(1)/2, (S(1)/2,1,1), ((1,2,S(1)/2),(1,3,S(1)/2)) )/3 - \ - JzKetCoupled(S(1)/2,S(1)/2, (S(1)/2,1,1), ((1,2,S(3)/2),(1,3,S(1)/2)) )/3 - \ - 2*JzKetCoupled(S(3)/2,S(1)/2, (S(1)/2,1,1), ((1,2,S(1)/2),(1,3,S(3)/2)) )/3 + \ - sqrt(5)*JzKetCoupled(S(3)/2,S(1)/2, (S(1)/2,1,1), ((1,2,S(3)/2),(1,3,S(3)/2)) )/15 + \ - sqrt(5)*JzKetCoupled(S(5)/2,S(1)/2, (S(1)/2,1,1), ((1,2,S(3)/2),(1,3,S(5)/2)) )/5 - assert couple(TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(1,1), JzKet(1,-1))) == \ - -2*JzKetCoupled(S(1)/2,-S(1)/2, (S(1)/2,1,1), ((1,2,S(1)/2),(1,3,S(1)/2)) )/3 + \ - sqrt(2)*JzKetCoupled(S(1)/2,-S(1)/2, (S(1)/2,1,1), ((1,2,S(3)/2),(1,3,S(1)/2)) )/6 - \ - sqrt(2)*JzKetCoupled(S(3)/2,-S(1)/2, (S(1)/2,1,1), ((1,2,S(1)/2),(1,3,S(3)/2)) )/3 + \ - 2*sqrt(10)*JzKetCoupled(S(3)/2,-S(1)/2, (S(1)/2,1,1), ((1,2,S(3)/2),(1,3,S(3)/2)) )/15 + \ - sqrt(10)*JzKetCoupled(S(5)/2,-S(1)/2, (S(1)/2,1,1), ((1,2,S(3)/2),(1,3,S(5)/2)) )/10 - assert couple(TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(1,0), JzKet(1,1))) == \ - sqrt(2)*JzKetCoupled(S(1)/2,S(1)/2, (S(1)/2,1,1), ((1,2,S(1)/2),(1,3,S(1)/2)) )/3 + \ - JzKetCoupled(S(1)/2,S(1)/2, (S(1)/2,1,1), ((1,2,S(3)/2),(1,3,S(1)/2)) )/3 - \ - JzKetCoupled(S(3)/2,S(1)/2, (S(1)/2,1,1), ((1,2,S(1)/2),(1,3,S(3)/2)) )/3 - \ - 4*sqrt(5)*JzKetCoupled(S(3)/2,S(1)/2, (S(1)/2,1,1), ((1,2,S(3)/2),(1,3,S(3)/2)) )/15 + \ - sqrt(5)*JzKetCoupled(S(5)/2,S(1)/2, (S(1)/2,1,1), ((1,2,S(3)/2),(1,3,S(5)/2)) )/5 - assert couple(TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(1,0), JzKet(1,0))) == \ - JzKetCoupled(S(1)/2,-S(1)/2, (S(1)/2,1,1), ((1,2,S(1)/2),(1,3,S(1)/2)) )/3 - \ - sqrt(2)*JzKetCoupled(S(1)/2,-S(1)/2, (S(1)/2,1,1), ((1,2,S(3)/2),(1,3,S(1)/2)) )/3 - \ - sqrt(2)*JzKetCoupled(S(3)/2,-S(1)/2, (S(1)/2,1,1), ((1,2,S(1)/2),(1,3,S(3)/2)) )/3 - \ - sqrt(10)*JzKetCoupled(S(3)/2,-S(1)/2, (S(1)/2,1,1), ((1,2,S(3)/2),(1,3,S(3)/2)) )/15 + \ - sqrt(10)*JzKetCoupled(S(5)/2,-S(1)/2, (S(1)/2,1,1), ((1,2,S(3)/2),(1,3,S(5)/2)) )/5 - assert couple(TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(1,0), JzKet(1,-1))) == \ - -sqrt(3)*JzKetCoupled(S(3)/2,-S(3)/2, (S(1)/2,1,1), ((1,2,S(1)/2),(1,3,S(3)/2)) )/3 + \ - 2*sqrt(15)*JzKetCoupled(S(3)/2,-S(3)/2, (S(1)/2,1,1), ((1,2,S(3)/2),(1,3,S(3)/2)) )/15 + \ - sqrt(10)*JzKetCoupled(S(5)/2,-S(3)/2, (S(1)/2,1,1), ((1,2,S(3)/2),(1,3,S(5)/2)) )/5 - assert couple(TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(1,-1), JzKet(1,1))) == \ - sqrt(2)*JzKetCoupled(S(1)/2,-S(1)/2, (S(1)/2,1,1), ((1,2,S(3)/2),(1,3,S(1)/2)) )/2 - \ - sqrt(10)*JzKetCoupled(S(3)/2,-S(1)/2, (S(1)/2,1,1), ((1,2,S(3)/2),(1,3,S(3)/2)) )/5 + \ - sqrt(10)*JzKetCoupled(S(5)/2,-S(1)/2, (S(1)/2,1,1), ((1,2,S(3)/2),(1,3,S(5)/2)) )/10 - assert couple(TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(1,-1), JzKet(1,0))) == \ - -sqrt(15)*JzKetCoupled(S(3)/2,-S(3)/2, (S(1)/2,1,1), ((1,2,S(3)/2),(1,3,S(3)/2)) )/5 + \ - sqrt(10)*JzKetCoupled(S(5)/2,-S(3)/2, (S(1)/2,1,1), ((1,2,S(3)/2),(1,3,S(5)/2)) )/5 - assert couple(TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(1,-1), JzKet(1,-1))) == \ - JzKetCoupled(S(5)/2,-S(5)/2, (S(1)/2,1,1), ((1,2,S(3)/2),(1,3,S(5)/2)) ) + assert couple(TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(1, 1), JzKet(1, 1))) == \ + JzKetCoupled( + S(5)/2, S(5)/2, (S(1)/2, 1, 1), ((1, 2, S(3)/2), (1, 3, S(5)/2)) ) + assert couple(TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(1, 1), JzKet(1, 0))) == \ + sqrt(15)*JzKetCoupled(S(3)/2, S(3)/2, (S(1)/2, 1, 1), ((1, 2, S(3)/2), (1, 3, S(3)/2)) )/5 + \ + sqrt(10)*JzKetCoupled(S( + 5)/2, S(3)/2, (S(1)/2, 1, 1), ((1, 2, S(3)/2), (1, 3, S(5)/2)) )/5 + assert couple(TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(1, 1), JzKet(1, -1))) == \ + sqrt(2)*JzKetCoupled(S(1)/2, S(1)/2, (S(1)/2, 1, 1), ((1, 2, S(3)/2), (1, 3, S(1)/2)) )/2 + \ + sqrt(10)*JzKetCoupled(S(3)/2, S(1)/2, (S(1)/2, 1, 1), ((1, 2, S(3)/2), (1, 3, S(3)/2)) )/5 + \ + sqrt(10)*JzKetCoupled(S(5)/2, S(1)/2, (S(1)/2, 1, 1), ((1, + 2, S(3)/2), (1, 3, S(5)/2)) )/10 + assert couple(TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(1, 0), JzKet(1, 1))) == \ + sqrt(3)*JzKetCoupled(S(3)/2, S(3)/2, (S(1)/2, 1, 1), ((1, 2, S(1)/2), (1, 3, S(3)/2)) )/3 - \ + 2*sqrt(15)*JzKetCoupled(S(3)/2, S(3)/2, (S(1)/2, 1, 1), ((1, 2, S(3)/2), (1, 3, S(3)/2)) )/15 + \ + sqrt(10)*JzKetCoupled(S( + 5)/2, S(3)/2, (S(1)/2, 1, 1), ((1, 2, S(3)/2), (1, 3, S(5)/2)) )/5 + assert couple(TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(1, 0), JzKet(1, 0))) == \ + JzKetCoupled(S(1)/2, S(1)/2, (S(1)/2, 1, 1), ((1, 2, S(1)/2), (1, 3, S(1)/2)) )/3 - \ + sqrt(2)*JzKetCoupled(S(1)/2, S(1)/2, (S(1)/2, 1, 1), ((1, 2, S(3)/2), (1, 3, S(1)/2)) )/3 + \ + sqrt(2)*JzKetCoupled(S(3)/2, S(1)/2, (S(1)/2, 1, 1), ((1, 2, S(1)/2), (1, 3, S(3)/2)) )/3 + \ + sqrt(10)*JzKetCoupled(S(3)/2, S(1)/2, (S(1)/2, 1, 1), ((1, 2, S(3)/2), (1, 3, S(3)/2)) )/15 + \ + sqrt(10)*JzKetCoupled(S( + 5)/2, S(1)/2, (S(1)/2, 1, 1), ((1, 2, S(3)/2), (1, 3, S(5)/2)) )/5 + assert couple(TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(1, 0), JzKet(1, -1))) == \ + sqrt(2)*JzKetCoupled(S(1)/2, -S(1)/2, (S(1)/2, 1, 1), ((1, 2, S(1)/2), (1, 3, S(1)/2)) )/3 + \ + JzKetCoupled(S(1)/2, -S(1)/2, (S(1)/2, 1, 1), ((1, 2, S(3)/2), (1, 3, S(1)/2)) )/3 + \ + JzKetCoupled(S(3)/2, -S(1)/2, (S(1)/2, 1, 1), ((1, 2, S(1)/2), (1, 3, S(3)/2)) )/3 + \ + 4*sqrt(5)*JzKetCoupled(S(3)/2, -S(1)/2, (S(1)/2, 1, 1), ((1, 2, S(3)/2), (1, 3, S(3)/2)) )/15 + \ + sqrt(5)*JzKetCoupled(S(5)/2, -S(1)/2, (S(1)/2, 1, 1), ((1, + 2, S(3)/2), (1, 3, S(5)/2)) )/5 + assert couple(TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(1, -1), JzKet(1, 1))) == \ + -2*JzKetCoupled(S(1)/2, S(1)/2, (S(1)/2, 1, 1), ((1, 2, S(1)/2), (1, 3, S(1)/2)) )/3 + \ + sqrt(2)*JzKetCoupled(S(1)/2, S(1)/2, (S(1)/2, 1, 1), ((1, 2, S(3)/2), (1, 3, S(1)/2)) )/6 + \ + sqrt(2)*JzKetCoupled(S(3)/2, S(1)/2, (S(1)/2, 1, 1), ((1, 2, S(1)/2), (1, 3, S(3)/2)) )/3 - \ + 2*sqrt(10)*JzKetCoupled(S(3)/2, S(1)/2, (S(1)/2, 1, 1), ((1, 2, S(3)/2), (1, 3, S(3)/2)) )/15 + \ + sqrt(10)*JzKetCoupled(S(5)/2, S(1)/2, (S(1)/2, 1, 1), ((1, + 2, S(3)/2), (1, 3, S(5)/2)) )/10 + assert couple(TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(1, -1), JzKet(1, 0))) == \ + -sqrt(2)*JzKetCoupled(S(1)/2, -S(1)/2, (S(1)/2, 1, 1), ((1, 2, S(1)/2), (1, 3, S(1)/2)) )/3 - \ + JzKetCoupled(S(1)/2, -S(1)/2, (S(1)/2, 1, 1), ((1, 2, S(3)/2), (1, 3, S(1)/2)) )/3 + \ + 2*JzKetCoupled(S(3)/2, -S(1)/2, (S(1)/2, 1, 1), ((1, 2, S(1)/2), (1, 3, S(3)/2)) )/3 - \ + sqrt(5)*JzKetCoupled(S(3)/2, -S(1)/2, (S(1)/2, 1, 1), ((1, 2, S(3)/2), (1, 3, S(3)/2)) )/15 + \ + sqrt(5)*JzKetCoupled(S(5)/2, -S(1)/2, (S(1)/2, 1, 1), ((1, + 2, S(3)/2), (1, 3, S(5)/2)) )/5 + assert couple(TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(1, -1), JzKet(1, -1))) == \ + sqrt(6)*JzKetCoupled(S(3)/2, -S(3)/2, (S(1)/2, 1, 1), ((1, 2, S(1)/2), (1, 3, S(3)/2)) )/3 + \ + sqrt(30)*JzKetCoupled(S(3)/2, -S(3)/2, (S(1)/2, 1, 1), ((1, 2, S(3)/2), (1, 3, S(3)/2)) )/15 + \ + sqrt(5)*JzKetCoupled(S(5)/2, -S(3)/2, (S(1)/2, 1, 1), ((1, + 2, S(3)/2), (1, 3, S(5)/2)) )/5 + assert couple(TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(1, 1), JzKet(1, 1))) == \ + -sqrt(6)*JzKetCoupled(S(3)/2, S(3)/2, (S(1)/2, 1, 1), ((1, 2, S(1)/2), (1, 3, S(3)/2)) )/3 - \ + sqrt(30)*JzKetCoupled(S(3)/2, S(3)/2, (S(1)/2, 1, 1), ((1, 2, S(3)/2), (1, 3, S(3)/2)) )/15 + \ + sqrt(5)*JzKetCoupled(S( + 5)/2, S(3)/2, (S(1)/2, 1, 1), ((1, 2, S(3)/2), (1, 3, S(5)/2)) )/5 + assert couple(TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(1, 1), JzKet(1, 0))) == \ + -sqrt(2)*JzKetCoupled(S(1)/2, S(1)/2, (S(1)/2, 1, 1), ((1, 2, S(1)/2), (1, 3, S(1)/2)) )/3 - \ + JzKetCoupled(S(1)/2, S(1)/2, (S(1)/2, 1, 1), ((1, 2, S(3)/2), (1, 3, S(1)/2)) )/3 - \ + 2*JzKetCoupled(S(3)/2, S(1)/2, (S(1)/2, 1, 1), ((1, 2, S(1)/2), (1, 3, S(3)/2)) )/3 + \ + sqrt(5)*JzKetCoupled(S(3)/2, S(1)/2, (S(1)/2, 1, 1), ((1, 2, S(3)/2), (1, 3, S(3)/2)) )/15 + \ + sqrt(5)*JzKetCoupled(S( + 5)/2, S(1)/2, (S(1)/2, 1, 1), ((1, 2, S(3)/2), (1, 3, S(5)/2)) )/5 + assert couple(TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(1, 1), JzKet(1, -1))) == \ + -2*JzKetCoupled(S(1)/2, -S(1)/2, (S(1)/2, 1, 1), ((1, 2, S(1)/2), (1, 3, S(1)/2)) )/3 + \ + sqrt(2)*JzKetCoupled(S(1)/2, -S(1)/2, (S(1)/2, 1, 1), ((1, 2, S(3)/2), (1, 3, S(1)/2)) )/6 - \ + sqrt(2)*JzKetCoupled(S(3)/2, -S(1)/2, (S(1)/2, 1, 1), ((1, 2, S(1)/2), (1, 3, S(3)/2)) )/3 + \ + 2*sqrt(10)*JzKetCoupled(S(3)/2, -S(1)/2, (S(1)/2, 1, 1), ((1, 2, S(3)/2), (1, 3, S(3)/2)) )/15 + \ + sqrt(10)*JzKetCoupled(S(5)/2, -S(1)/2, (S(1)/2, 1, 1), ((1, + 2, S(3)/2), (1, 3, S(5)/2)) )/10 + assert couple(TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(1, 0), JzKet(1, 1))) == \ + sqrt(2)*JzKetCoupled(S(1)/2, S(1)/2, (S(1)/2, 1, 1), ((1, 2, S(1)/2), (1, 3, S(1)/2)) )/3 + \ + JzKetCoupled(S(1)/2, S(1)/2, (S(1)/2, 1, 1), ((1, 2, S(3)/2), (1, 3, S(1)/2)) )/3 - \ + JzKetCoupled(S(3)/2, S(1)/2, (S(1)/2, 1, 1), ((1, 2, S(1)/2), (1, 3, S(3)/2)) )/3 - \ + 4*sqrt(5)*JzKetCoupled(S(3)/2, S(1)/2, (S(1)/2, 1, 1), ((1, 2, S(3)/2), (1, 3, S(3)/2)) )/15 + \ + sqrt(5)*JzKetCoupled(S( + 5)/2, S(1)/2, (S(1)/2, 1, 1), ((1, 2, S(3)/2), (1, 3, S(5)/2)) )/5 + assert couple(TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(1, 0), JzKet(1, 0))) == \ + JzKetCoupled(S(1)/2, -S(1)/2, (S(1)/2, 1, 1), ((1, 2, S(1)/2), (1, 3, S(1)/2)) )/3 - \ + sqrt(2)*JzKetCoupled(S(1)/2, -S(1)/2, (S(1)/2, 1, 1), ((1, 2, S(3)/2), (1, 3, S(1)/2)) )/3 - \ + sqrt(2)*JzKetCoupled(S(3)/2, -S(1)/2, (S(1)/2, 1, 1), ((1, 2, S(1)/2), (1, 3, S(3)/2)) )/3 - \ + sqrt(10)*JzKetCoupled(S(3)/2, -S(1)/2, (S(1)/2, 1, 1), ((1, 2, S(3)/2), (1, 3, S(3)/2)) )/15 + \ + sqrt(10)*JzKetCoupled(S(5)/2, -S(1)/2, (S(1)/2, 1, 1), ((1, + 2, S(3)/2), (1, 3, S(5)/2)) )/5 + assert couple(TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(1, 0), JzKet(1, -1))) == \ + -sqrt(3)*JzKetCoupled(S(3)/2, -S(3)/2, (S(1)/2, 1, 1), ((1, 2, S(1)/2), (1, 3, S(3)/2)) )/3 + \ + 2*sqrt(15)*JzKetCoupled(S(3)/2, -S(3)/2, (S(1)/2, 1, 1), ((1, 2, S(3)/2), (1, 3, S(3)/2)) )/15 + \ + sqrt(10)*JzKetCoupled(S(5)/2, -S(3)/2, (S(1)/2, 1, 1), ((1, + 2, S(3)/2), (1, 3, S(5)/2)) )/5 + assert couple(TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(1, -1), JzKet(1, 1))) == \ + sqrt(2)*JzKetCoupled(S(1)/2, -S(1)/2, (S(1)/2, 1, 1), ((1, 2, S(3)/2), (1, 3, S(1)/2)) )/2 - \ + sqrt(10)*JzKetCoupled(S(3)/2, -S(1)/2, (S(1)/2, 1, 1), ((1, 2, S(3)/2), (1, 3, S(3)/2)) )/5 + \ + sqrt(10)*JzKetCoupled(S(5)/2, -S(1)/2, (S(1)/2, 1, 1), ((1, + 2, S(3)/2), (1, 3, S(5)/2)) )/10 + assert couple(TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(1, -1), JzKet(1, 0))) == \ + -sqrt(15)*JzKetCoupled(S(3)/2, -S(3)/2, (S(1)/2, 1, 1), ((1, 2, S(3)/2), (1, 3, S(3)/2)) )/5 + \ + sqrt(10)*JzKetCoupled(S(5)/2, -S(3)/2, (S(1)/2, 1, 1), ((1, + 2, S(3)/2), (1, 3, S(5)/2)) )/5 + assert couple(TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(1, -1), JzKet(1, -1))) == \ + JzKetCoupled(S( + 5)/2, -S(5)/2, (S(1)/2, 1, 1), ((1, 2, S(3)/2), (1, 3, S(5)/2)) ) # j1=1, j2=1, j3=1 - assert couple(TensorProduct(JzKet(1,1), JzKet(1,1), JzKet(1,1))) == \ - JzKetCoupled(3,3, (1,1,1), ((1,2,2),(1,3,3)) ) - assert couple(TensorProduct(JzKet(1,1), JzKet(1,1), JzKet(1,0))) == \ - sqrt(6)*JzKetCoupled(2,2, (1,1,1), ((1,2,2),(1,3,2)) )/3 + \ - sqrt(3)*JzKetCoupled(3,2, (1,1,1), ((1,2,2),(1,3,3)) )/3 - assert couple(TensorProduct(JzKet(1,1), JzKet(1,1), JzKet(1,-1))) == \ - sqrt(15)*JzKetCoupled(1,1, (1,1,1), ((1,2,2),(1,3,1)) )/5 + \ - sqrt(3)*JzKetCoupled(2,1, (1,1,1), ((1,2,2),(1,3,2)) )/3 + \ - sqrt(15)*JzKetCoupled(3,1, (1,1,1), ((1,2,2),(1,3,3)) )/15 - assert couple(TensorProduct(JzKet(1,1), JzKet(1,0), JzKet(1,1))) == \ - sqrt(2)*JzKetCoupled(2,2, (1,1,1), ((1,2,1),(1,3,2)) )/2 - \ - sqrt(6)*JzKetCoupled(2,2, (1,1,1), ((1,2,2),(1,3,2)) )/6 + \ - sqrt(3)*JzKetCoupled(3,2, (1,1,1), ((1,2,2),(1,3,3)) )/3 - assert couple(TensorProduct(JzKet(1,1), JzKet(1,0), JzKet(1,0))) == \ - JzKetCoupled(1,1, (1,1,1), ((1,2,1),(1,3,1)) )/2 - \ - sqrt(15)*JzKetCoupled(1,1, (1,1,1), ((1,2,2),(1,3,1)) )/10 + \ - JzKetCoupled(2,1, (1,1,1), ((1,2,1),(1,3,2)) )/2 + \ - sqrt(3)*JzKetCoupled(2,1, (1,1,1), ((1,2,2),(1,3,2)) )/6 + \ - 2*sqrt(15)*JzKetCoupled(3,1, (1,1,1), ((1,2,2),(1,3,3)) )/15 - assert couple(TensorProduct(JzKet(1,1), JzKet(1,0), JzKet(1,-1))) == \ - sqrt(6)*JzKetCoupled(0,0, (1,1,1), ((1,2,1),(1,3,0)) )/6 + \ - JzKetCoupled(1,0, (1,1,1), ((1,2,1),(1,3,1)) )/2 + \ - sqrt(15)*JzKetCoupled(1,0, (1,1,1), ((1,2,2),(1,3,1)) )/10 + \ - sqrt(3)*JzKetCoupled(2,0, (1,1,1), ((1,2,1),(1,3,2)) )/6 + \ - JzKetCoupled(2,0, (1,1,1), ((1,2,2),(1,3,2)) )/2 + \ - sqrt(10)*JzKetCoupled(3,0, (1,1,1), ((1,2,2),(1,3,3)) )/10 - assert couple(TensorProduct(JzKet(1,1), JzKet(1,-1), JzKet(1,1))) == \ - sqrt(3)*JzKetCoupled(1,1, (1,1,1), ((1,2,0),(1,3,1)) )/3 - \ - JzKetCoupled(1,1, (1,1,1), ((1,2,1),(1,3,1)) )/2 + \ - sqrt(15)*JzKetCoupled(1,1, (1,1,1), ((1,2,2),(1,3,1)) )/30 + \ - JzKetCoupled(2,1, (1,1,1), ((1,2,1),(1,3,2)) )/2 - \ - sqrt(3)*JzKetCoupled(2,1, (1,1,1), ((1,2,2),(1,3,2)) )/6 + \ - sqrt(15)*JzKetCoupled(3,1, (1,1,1), ((1,2,2),(1,3,3)) )/15 - assert couple(TensorProduct(JzKet(1,1), JzKet(1,-1), JzKet(1,0))) == \ - -sqrt(6)*JzKetCoupled(0,0, (1,1,1), ((1,2,1),(1,3,0)) )/6 + \ - sqrt(3)*JzKetCoupled(1,0, (1,1,1), ((1,2,0),(1,3,1)) )/3 - \ - sqrt(15)*JzKetCoupled(1,0, (1,1,1), ((1,2,2),(1,3,1)) )/15 + \ - sqrt(3)*JzKetCoupled(2,0, (1,1,1), ((1,2,1),(1,3,2)) )/3 + \ - sqrt(10)*JzKetCoupled(3,0, (1,1,1), ((1,2,2),(1,3,3)) )/10 - assert couple(TensorProduct(JzKet(1,1), JzKet(1,-1), JzKet(1,-1))) == \ - sqrt(3)*JzKetCoupled(1,-1, (1,1,1), ((1,2,0),(1,3,1)) )/3 + \ - JzKetCoupled(1,-1, (1,1,1), ((1,2,1),(1,3,1)) )/2 + \ - sqrt(15)*JzKetCoupled(1,-1, (1,1,1), ((1,2,2),(1,3,1)) )/30 + \ - JzKetCoupled(2,-1, (1,1,1), ((1,2,1),(1,3,2)) )/2 + \ - sqrt(3)*JzKetCoupled(2,-1, (1,1,1), ((1,2,2),(1,3,2)) )/6 + \ - sqrt(15)*JzKetCoupled(3,-1, (1,1,1), ((1,2,2),(1,3,3)) )/15 - assert couple(TensorProduct(JzKet(1,0), JzKet(1,1), JzKet(1,1))) == \ - -sqrt(2)*JzKetCoupled(2,2, (1,1,1), ((1,2,1),(1,3,2)) )/2 - \ - sqrt(6)*JzKetCoupled(2,2, (1,1,1), ((1,2,2),(1,3,2)) )/6 + \ - sqrt(3)*JzKetCoupled(3,2, (1,1,1), ((1,2,2),(1,3,3)) )/3 - assert couple(TensorProduct(JzKet(1,0), JzKet(1,1), JzKet(1,0))) == \ - -JzKetCoupled(1,1, (1,1,1), ((1,2,1),(1,3,1)) )/2 - \ - sqrt(15)*JzKetCoupled(1,1, (1,1,1), ((1,2,2),(1,3,1)) )/10 - \ - JzKetCoupled(2,1, (1,1,1), ((1,2,1),(1,3,2)) )/2 + \ - sqrt(3)*JzKetCoupled(2,1, (1,1,1), ((1,2,2),(1,3,2)) )/6 + \ - 2*sqrt(15)*JzKetCoupled(3,1, (1,1,1), ((1,2,2),(1,3,3)) )/15 - assert couple(TensorProduct(JzKet(1,0), JzKet(1,1), JzKet(1,-1))) == \ - -sqrt(6)*JzKetCoupled(0,0, (1,1,1), ((1,2,1),(1,3,0)) )/6 - \ - JzKetCoupled(1,0, (1,1,1), ((1,2,1),(1,3,1)) )/2 + \ - sqrt(15)*JzKetCoupled(1,0, (1,1,1), ((1,2,2),(1,3,1)) )/10 - \ - sqrt(3)*JzKetCoupled(2,0, (1,1,1), ((1,2,1),(1,3,2)) )/6 + \ - JzKetCoupled(2,0, (1,1,1), ((1,2,2),(1,3,2)) )/2 + \ - sqrt(10)*JzKetCoupled(3,0, (1,1,1), ((1,2,2),(1,3,3)) )/10 - assert couple(TensorProduct(JzKet(1,0), JzKet(1,0), JzKet(1,1))) == \ - -sqrt(3)*JzKetCoupled(1,1, (1,1,1), ((1,2,0),(1,3,1)) )/3 + \ - sqrt(15)*JzKetCoupled(1,1, (1,1,1), ((1,2,2),(1,3,1)) )/15 - \ - sqrt(3)*JzKetCoupled(2,1, (1,1,1), ((1,2,2),(1,3,2)) )/3 + \ - 2*sqrt(15)*JzKetCoupled(3,1, (1,1,1), ((1,2,2),(1,3,3)) )/15 - assert couple(TensorProduct(JzKet(1,0), JzKet(1,0), JzKet(1,0))) == \ - -sqrt(3)*JzKetCoupled(1,0, (1,1,1), ((1,2,0),(1,3,1)) )/3 - \ - 2*sqrt(15)*JzKetCoupled(1,0, (1,1,1), ((1,2,2),(1,3,1)) )/15 + \ - sqrt(10)*JzKetCoupled(3,0, (1,1,1), ((1,2,2),(1,3,3)) )/5 - assert couple(TensorProduct(JzKet(1,0), JzKet(1,0), JzKet(1,-1))) == \ - -sqrt(3)*JzKetCoupled(1,-1, (1,1,1), ((1,2,0),(1,3,1)) )/3 + \ - sqrt(15)*JzKetCoupled(1,-1, (1,1,1), ((1,2,2),(1,3,1)) )/15 + \ - sqrt(3)*JzKetCoupled(2,-1, (1,1,1), ((1,2,2),(1,3,2)) )/3 + \ - 2*sqrt(15)*JzKetCoupled(3,-1, (1,1,1), ((1,2,2),(1,3,3)) )/15 - assert couple(TensorProduct(JzKet(1,0), JzKet(1,-1), JzKet(1,1))) == \ - sqrt(6)*JzKetCoupled(0,0, (1,1,1), ((1,2,1),(1,3,0)) )/6 - \ - JzKetCoupled(1,0, (1,1,1), ((1,2,1),(1,3,1)) )/2 + \ - sqrt(15)*JzKetCoupled(1,0, (1,1,1), ((1,2,2),(1,3,1)) )/10 + \ - sqrt(3)*JzKetCoupled(2,0, (1,1,1), ((1,2,1),(1,3,2)) )/6 - \ - JzKetCoupled(2,0, (1,1,1), ((1,2,2),(1,3,2)) )/2 + \ - sqrt(10)*JzKetCoupled(3,0, (1,1,1), ((1,2,2),(1,3,3)) )/10 - assert couple(TensorProduct(JzKet(1,0), JzKet(1,-1), JzKet(1,0))) == \ - -JzKetCoupled(1,-1, (1,1,1), ((1,2,1),(1,3,1)) )/2 - \ - sqrt(15)*JzKetCoupled(1,-1, (1,1,1), ((1,2,2),(1,3,1)) )/10 + \ - JzKetCoupled(2,-1, (1,1,1), ((1,2,1),(1,3,2)) )/2 - \ - sqrt(3)*JzKetCoupled(2,-1, (1,1,1), ((1,2,2),(1,3,2)) )/6 + \ - 2*sqrt(15)*JzKetCoupled(3,-1, (1,1,1), ((1,2,2),(1,3,3)) )/15 - assert couple(TensorProduct(JzKet(1,0), JzKet(1,-1), JzKet(1,-1))) == \ - sqrt(2)*JzKetCoupled(2,-2, (1,1,1), ((1,2,1),(1,3,2)) )/2 + \ - sqrt(6)*JzKetCoupled(2,-2, (1,1,1), ((1,2,2),(1,3,2)) )/6 + \ - sqrt(3)*JzKetCoupled(3,-2, (1,1,1), ((1,2,2),(1,3,3)) )/3 - assert couple(TensorProduct(JzKet(1,-1), JzKet(1,1), JzKet(1,1))) == \ - sqrt(3)*JzKetCoupled(1,1, (1,1,1), ((1,2,0),(1,3,1)) )/3 + \ - JzKetCoupled(1,1, (1,1,1), ((1,2,1),(1,3,1)) )/2 + \ - sqrt(15)*JzKetCoupled(1,1, (1,1,1), ((1,2,2),(1,3,1)) )/30 - \ - JzKetCoupled(2,1, (1,1,1), ((1,2,1),(1,3,2)) )/2 - \ - sqrt(3)*JzKetCoupled(2,1, (1,1,1), ((1,2,2),(1,3,2)) )/6 + \ - sqrt(15)*JzKetCoupled(3,1, (1,1,1), ((1,2,2),(1,3,3)) )/15 - assert couple(TensorProduct(JzKet(1,-1), JzKet(1,1), JzKet(1,0))) == \ - sqrt(6)*JzKetCoupled(0,0, (1,1,1), ((1,2,1),(1,3,0)) )/6 + \ - sqrt(3)*JzKetCoupled(1,0, (1,1,1), ((1,2,0),(1,3,1)) )/3 - \ - sqrt(15)*JzKetCoupled(1,0, (1,1,1), ((1,2,2),(1,3,1)) )/15 - \ - sqrt(3)*JzKetCoupled(2,0, (1,1,1), ((1,2,1),(1,3,2)) )/3 + \ - sqrt(10)*JzKetCoupled(3,0, (1,1,1), ((1,2,2),(1,3,3)) )/10 - assert couple(TensorProduct(JzKet(1,-1), JzKet(1,1), JzKet(1,-1))) == \ - sqrt(3)*JzKetCoupled(1,-1, (1,1,1), ((1,2,0),(1,3,1)) )/3 - \ - JzKetCoupled(1,-1, (1,1,1), ((1,2,1),(1,3,1)) )/2 + \ - sqrt(15)*JzKetCoupled(1,-1, (1,1,1), ((1,2,2),(1,3,1)) )/30 - \ - JzKetCoupled(2,-1, (1,1,1), ((1,2,1),(1,3,2)) )/2 + \ - sqrt(3)*JzKetCoupled(2,-1, (1,1,1), ((1,2,2),(1,3,2)) )/6 + \ - sqrt(15)*JzKetCoupled(3,-1, (1,1,1), ((1,2,2),(1,3,3)) )/15 - assert couple(TensorProduct(JzKet(1,-1), JzKet(1,0), JzKet(1,1))) == \ - -sqrt(6)*JzKetCoupled(0,0, (1,1,1), ((1,2,1),(1,3,0)) )/6 + \ - JzKetCoupled(1,0, (1,1,1), ((1,2,1),(1,3,1)) )/2 + \ - sqrt(15)*JzKetCoupled(1,0, (1,1,1), ((1,2,2),(1,3,1)) )/10 - \ - sqrt(3)*JzKetCoupled(2,0, (1,1,1), ((1,2,1),(1,3,2)) )/6 - \ - JzKetCoupled(2,0, (1,1,1), ((1,2,2),(1,3,2)) )/2 + \ - sqrt(10)*JzKetCoupled(3,0, (1,1,1), ((1,2,2),(1,3,3)) )/10 - assert couple(TensorProduct(JzKet(1,-1), JzKet(1,0), JzKet(1,0))) == \ - JzKetCoupled(1,-1, (1,1,1), ((1,2,1),(1,3,1)) )/2 - \ - sqrt(15)*JzKetCoupled(1,-1, (1,1,1), ((1,2,2),(1,3,1)) )/10 - \ - JzKetCoupled(2,-1, (1,1,1), ((1,2,1),(1,3,2)) )/2 - \ - sqrt(3)*JzKetCoupled(2,-1, (1,1,1), ((1,2,2),(1,3,2)) )/6 + \ - 2*sqrt(15)*JzKetCoupled(3,-1, (1,1,1), ((1,2,2),(1,3,3)) )/15 - assert couple(TensorProduct(JzKet(1,-1), JzKet(1,0), JzKet(1,-1))) == \ - -sqrt(2)*JzKetCoupled(2,-2, (1,1,1), ((1,2,1),(1,3,2)) )/2 + \ - sqrt(6)*JzKetCoupled(2,-2, (1,1,1), ((1,2,2),(1,3,2)) )/6 + \ - sqrt(3)*JzKetCoupled(3,-2, (1,1,1), ((1,2,2),(1,3,3)) )/3 - assert couple(TensorProduct(JzKet(1,-1), JzKet(1,-1), JzKet(1,1))) == \ - sqrt(15)*JzKetCoupled(1,-1, (1,1,1), ((1,2,2),(1,3,1)) )/5 - \ - sqrt(3)*JzKetCoupled(2,-1, (1,1,1), ((1,2,2),(1,3,2)) )/3 + \ - sqrt(15)*JzKetCoupled(3,-1, (1,1,1), ((1,2,2),(1,3,3)) )/15 - assert couple(TensorProduct(JzKet(1,-1), JzKet(1,-1), JzKet(1,0))) == \ - -sqrt(6)*JzKetCoupled(2,-2, (1,1,1), ((1,2,2),(1,3,2)) )/3 + \ - sqrt(3)*JzKetCoupled(3,-2, (1,1,1), ((1,2,2),(1,3,3)) )/3 - assert couple(TensorProduct(JzKet(1,-1), JzKet(1,-1), JzKet(1,-1))) == \ - JzKetCoupled(3,-3, (1,1,1), ((1,2,2),(1,3,3)) ) + assert couple(TensorProduct(JzKet(1, 1), JzKet(1, 1), JzKet(1, 1))) == \ + JzKetCoupled(3, 3, (1, 1, 1), ((1, 2, 2), (1, 3, 3)) ) + assert couple(TensorProduct(JzKet(1, 1), JzKet(1, 1), JzKet(1, 0))) == \ + sqrt(6)*JzKetCoupled(2, 2, (1, 1, 1), ((1, 2, 2), (1, 3, 2)) )/3 + \ + sqrt(3)*JzKetCoupled(3, 2, (1, 1, 1), ((1, 2, 2), (1, 3, 3)) )/3 + assert couple(TensorProduct(JzKet(1, 1), JzKet(1, 1), JzKet(1, -1))) == \ + sqrt(15)*JzKetCoupled(1, 1, (1, 1, 1), ((1, 2, 2), (1, 3, 1)) )/5 + \ + sqrt(3)*JzKetCoupled(2, 1, (1, 1, 1), ((1, 2, 2), (1, 3, 2)) )/3 + \ + sqrt(15)*JzKetCoupled(3, 1, (1, 1, 1), ((1, 2, 2), (1, 3, 3)) )/15 + assert couple(TensorProduct(JzKet(1, 1), JzKet(1, 0), JzKet(1, 1))) == \ + sqrt(2)*JzKetCoupled(2, 2, (1, 1, 1), ((1, 2, 1), (1, 3, 2)) )/2 - \ + sqrt(6)*JzKetCoupled(2, 2, (1, 1, 1), ((1, 2, 2), (1, 3, 2)) )/6 + \ + sqrt(3)*JzKetCoupled(3, 2, (1, 1, 1), ((1, 2, 2), (1, 3, 3)) )/3 + assert couple(TensorProduct(JzKet(1, 1), JzKet(1, 0), JzKet(1, 0))) == \ + JzKetCoupled(1, 1, (1, 1, 1), ((1, 2, 1), (1, 3, 1)) )/2 - \ + sqrt(15)*JzKetCoupled(1, 1, (1, 1, 1), ((1, 2, 2), (1, 3, 1)) )/10 + \ + JzKetCoupled(2, 1, (1, 1, 1), ((1, 2, 1), (1, 3, 2)) )/2 + \ + sqrt(3)*JzKetCoupled(2, 1, (1, 1, 1), ((1, 2, 2), (1, 3, 2)) )/6 + \ + 2*sqrt(15)*JzKetCoupled(3, 1, (1, 1, 1), ((1, 2, 2), (1, 3, 3)) )/15 + assert couple(TensorProduct(JzKet(1, 1), JzKet(1, 0), JzKet(1, -1))) == \ + sqrt(6)*JzKetCoupled(0, 0, (1, 1, 1), ((1, 2, 1), (1, 3, 0)) )/6 + \ + JzKetCoupled(1, 0, (1, 1, 1), ((1, 2, 1), (1, 3, 1)) )/2 + \ + sqrt(15)*JzKetCoupled(1, 0, (1, 1, 1), ((1, 2, 2), (1, 3, 1)) )/10 + \ + sqrt(3)*JzKetCoupled(2, 0, (1, 1, 1), ((1, 2, 1), (1, 3, 2)) )/6 + \ + JzKetCoupled(2, 0, (1, 1, 1), ((1, 2, 2), (1, 3, 2)) )/2 + \ + sqrt(10)*JzKetCoupled(3, 0, (1, 1, 1), ((1, 2, 2), (1, 3, 3)) )/10 + assert couple(TensorProduct(JzKet(1, 1), JzKet(1, -1), JzKet(1, 1))) == \ + sqrt(3)*JzKetCoupled(1, 1, (1, 1, 1), ((1, 2, 0), (1, 3, 1)) )/3 - \ + JzKetCoupled(1, 1, (1, 1, 1), ((1, 2, 1), (1, 3, 1)) )/2 + \ + sqrt(15)*JzKetCoupled(1, 1, (1, 1, 1), ((1, 2, 2), (1, 3, 1)) )/30 + \ + JzKetCoupled(2, 1, (1, 1, 1), ((1, 2, 1), (1, 3, 2)) )/2 - \ + sqrt(3)*JzKetCoupled(2, 1, (1, 1, 1), ((1, 2, 2), (1, 3, 2)) )/6 + \ + sqrt(15)*JzKetCoupled(3, 1, (1, 1, 1), ((1, 2, 2), (1, 3, 3)) )/15 + assert couple(TensorProduct(JzKet(1, 1), JzKet(1, -1), JzKet(1, 0))) == \ + -sqrt(6)*JzKetCoupled(0, 0, (1, 1, 1), ((1, 2, 1), (1, 3, 0)) )/6 + \ + sqrt(3)*JzKetCoupled(1, 0, (1, 1, 1), ((1, 2, 0), (1, 3, 1)) )/3 - \ + sqrt(15)*JzKetCoupled(1, 0, (1, 1, 1), ((1, 2, 2), (1, 3, 1)) )/15 + \ + sqrt(3)*JzKetCoupled(2, 0, (1, 1, 1), ((1, 2, 1), (1, 3, 2)) )/3 + \ + sqrt(10)*JzKetCoupled(3, 0, (1, 1, 1), ((1, 2, 2), (1, 3, 3)) )/10 + assert couple(TensorProduct(JzKet(1, 1), JzKet(1, -1), JzKet(1, -1))) == \ + sqrt(3)*JzKetCoupled(1, -1, (1, 1, 1), ((1, 2, 0), (1, 3, 1)) )/3 + \ + JzKetCoupled(1, -1, (1, 1, 1), ((1, 2, 1), (1, 3, 1)) )/2 + \ + sqrt(15)*JzKetCoupled(1, -1, (1, 1, 1), ((1, 2, 2), (1, 3, 1)) )/30 + \ + JzKetCoupled(2, -1, (1, 1, 1), ((1, 2, 1), (1, 3, 2)) )/2 + \ + sqrt(3)*JzKetCoupled(2, -1, (1, 1, 1), ((1, 2, 2), (1, 3, 2)) )/6 + \ + sqrt(15)*JzKetCoupled(3, -1, (1, 1, 1), ((1, 2, 2), (1, 3, 3)) )/15 + assert couple(TensorProduct(JzKet(1, 0), JzKet(1, 1), JzKet(1, 1))) == \ + -sqrt(2)*JzKetCoupled(2, 2, (1, 1, 1), ((1, 2, 1), (1, 3, 2)) )/2 - \ + sqrt(6)*JzKetCoupled(2, 2, (1, 1, 1), ((1, 2, 2), (1, 3, 2)) )/6 + \ + sqrt(3)*JzKetCoupled(3, 2, (1, 1, 1), ((1, 2, 2), (1, 3, 3)) )/3 + assert couple(TensorProduct(JzKet(1, 0), JzKet(1, 1), JzKet(1, 0))) == \ + -JzKetCoupled(1, 1, (1, 1, 1), ((1, 2, 1), (1, 3, 1)) )/2 - \ + sqrt(15)*JzKetCoupled(1, 1, (1, 1, 1), ((1, 2, 2), (1, 3, 1)) )/10 - \ + JzKetCoupled(2, 1, (1, 1, 1), ((1, 2, 1), (1, 3, 2)) )/2 + \ + sqrt(3)*JzKetCoupled(2, 1, (1, 1, 1), ((1, 2, 2), (1, 3, 2)) )/6 + \ + 2*sqrt(15)*JzKetCoupled(3, 1, (1, 1, 1), ((1, 2, 2), (1, 3, 3)) )/15 + assert couple(TensorProduct(JzKet(1, 0), JzKet(1, 1), JzKet(1, -1))) == \ + -sqrt(6)*JzKetCoupled(0, 0, (1, 1, 1), ((1, 2, 1), (1, 3, 0)) )/6 - \ + JzKetCoupled(1, 0, (1, 1, 1), ((1, 2, 1), (1, 3, 1)) )/2 + \ + sqrt(15)*JzKetCoupled(1, 0, (1, 1, 1), ((1, 2, 2), (1, 3, 1)) )/10 - \ + sqrt(3)*JzKetCoupled(2, 0, (1, 1, 1), ((1, 2, 1), (1, 3, 2)) )/6 + \ + JzKetCoupled(2, 0, (1, 1, 1), ((1, 2, 2), (1, 3, 2)) )/2 + \ + sqrt(10)*JzKetCoupled(3, 0, (1, 1, 1), ((1, 2, 2), (1, 3, 3)) )/10 + assert couple(TensorProduct(JzKet(1, 0), JzKet(1, 0), JzKet(1, 1))) == \ + -sqrt(3)*JzKetCoupled(1, 1, (1, 1, 1), ((1, 2, 0), (1, 3, 1)) )/3 + \ + sqrt(15)*JzKetCoupled(1, 1, (1, 1, 1), ((1, 2, 2), (1, 3, 1)) )/15 - \ + sqrt(3)*JzKetCoupled(2, 1, (1, 1, 1), ((1, 2, 2), (1, 3, 2)) )/3 + \ + 2*sqrt(15)*JzKetCoupled(3, 1, (1, 1, 1), ((1, 2, 2), (1, 3, 3)) )/15 + assert couple(TensorProduct(JzKet(1, 0), JzKet(1, 0), JzKet(1, 0))) == \ + -sqrt(3)*JzKetCoupled(1, 0, (1, 1, 1), ((1, 2, 0), (1, 3, 1)) )/3 - \ + 2*sqrt(15)*JzKetCoupled(1, 0, (1, 1, 1), ((1, 2, 2), (1, 3, 1)) )/15 + \ + sqrt(10)*JzKetCoupled(3, 0, (1, 1, 1), ((1, 2, 2), (1, 3, 3)) )/5 + assert couple(TensorProduct(JzKet(1, 0), JzKet(1, 0), JzKet(1, -1))) == \ + -sqrt(3)*JzKetCoupled(1, -1, (1, 1, 1), ((1, 2, 0), (1, 3, 1)) )/3 + \ + sqrt(15)*JzKetCoupled(1, -1, (1, 1, 1), ((1, 2, 2), (1, 3, 1)) )/15 + \ + sqrt(3)*JzKetCoupled(2, -1, (1, 1, 1), ((1, 2, 2), (1, 3, 2)) )/3 + \ + 2*sqrt(15)*JzKetCoupled(3, -1, (1, 1, 1), ((1, 2, 2), (1, 3, 3)) )/15 + assert couple(TensorProduct(JzKet(1, 0), JzKet(1, -1), JzKet(1, 1))) == \ + sqrt(6)*JzKetCoupled(0, 0, (1, 1, 1), ((1, 2, 1), (1, 3, 0)) )/6 - \ + JzKetCoupled(1, 0, (1, 1, 1), ((1, 2, 1), (1, 3, 1)) )/2 + \ + sqrt(15)*JzKetCoupled(1, 0, (1, 1, 1), ((1, 2, 2), (1, 3, 1)) )/10 + \ + sqrt(3)*JzKetCoupled(2, 0, (1, 1, 1), ((1, 2, 1), (1, 3, 2)) )/6 - \ + JzKetCoupled(2, 0, (1, 1, 1), ((1, 2, 2), (1, 3, 2)) )/2 + \ + sqrt(10)*JzKetCoupled(3, 0, (1, 1, 1), ((1, 2, 2), (1, 3, 3)) )/10 + assert couple(TensorProduct(JzKet(1, 0), JzKet(1, -1), JzKet(1, 0))) == \ + -JzKetCoupled(1, -1, (1, 1, 1), ((1, 2, 1), (1, 3, 1)) )/2 - \ + sqrt(15)*JzKetCoupled(1, -1, (1, 1, 1), ((1, 2, 2), (1, 3, 1)) )/10 + \ + JzKetCoupled(2, -1, (1, 1, 1), ((1, 2, 1), (1, 3, 2)) )/2 - \ + sqrt(3)*JzKetCoupled(2, -1, (1, 1, 1), ((1, 2, 2), (1, 3, 2)) )/6 + \ + 2*sqrt(15)*JzKetCoupled(3, -1, (1, 1, 1), ((1, 2, 2), (1, 3, 3)) )/15 + assert couple(TensorProduct(JzKet(1, 0), JzKet(1, -1), JzKet(1, -1))) == \ + sqrt(2)*JzKetCoupled(2, -2, (1, 1, 1), ((1, 2, 1), (1, 3, 2)) )/2 + \ + sqrt(6)*JzKetCoupled(2, -2, (1, 1, 1), ((1, 2, 2), (1, 3, 2)) )/6 + \ + sqrt(3)*JzKetCoupled(3, -2, (1, 1, 1), ((1, 2, 2), (1, 3, 3)) )/3 + assert couple(TensorProduct(JzKet(1, -1), JzKet(1, 1), JzKet(1, 1))) == \ + sqrt(3)*JzKetCoupled(1, 1, (1, 1, 1), ((1, 2, 0), (1, 3, 1)) )/3 + \ + JzKetCoupled(1, 1, (1, 1, 1), ((1, 2, 1), (1, 3, 1)) )/2 + \ + sqrt(15)*JzKetCoupled(1, 1, (1, 1, 1), ((1, 2, 2), (1, 3, 1)) )/30 - \ + JzKetCoupled(2, 1, (1, 1, 1), ((1, 2, 1), (1, 3, 2)) )/2 - \ + sqrt(3)*JzKetCoupled(2, 1, (1, 1, 1), ((1, 2, 2), (1, 3, 2)) )/6 + \ + sqrt(15)*JzKetCoupled(3, 1, (1, 1, 1), ((1, 2, 2), (1, 3, 3)) )/15 + assert couple(TensorProduct(JzKet(1, -1), JzKet(1, 1), JzKet(1, 0))) == \ + sqrt(6)*JzKetCoupled(0, 0, (1, 1, 1), ((1, 2, 1), (1, 3, 0)) )/6 + \ + sqrt(3)*JzKetCoupled(1, 0, (1, 1, 1), ((1, 2, 0), (1, 3, 1)) )/3 - \ + sqrt(15)*JzKetCoupled(1, 0, (1, 1, 1), ((1, 2, 2), (1, 3, 1)) )/15 - \ + sqrt(3)*JzKetCoupled(2, 0, (1, 1, 1), ((1, 2, 1), (1, 3, 2)) )/3 + \ + sqrt(10)*JzKetCoupled(3, 0, (1, 1, 1), ((1, 2, 2), (1, 3, 3)) )/10 + assert couple(TensorProduct(JzKet(1, -1), JzKet(1, 1), JzKet(1, -1))) == \ + sqrt(3)*JzKetCoupled(1, -1, (1, 1, 1), ((1, 2, 0), (1, 3, 1)) )/3 - \ + JzKetCoupled(1, -1, (1, 1, 1), ((1, 2, 1), (1, 3, 1)) )/2 + \ + sqrt(15)*JzKetCoupled(1, -1, (1, 1, 1), ((1, 2, 2), (1, 3, 1)) )/30 - \ + JzKetCoupled(2, -1, (1, 1, 1), ((1, 2, 1), (1, 3, 2)) )/2 + \ + sqrt(3)*JzKetCoupled(2, -1, (1, 1, 1), ((1, 2, 2), (1, 3, 2)) )/6 + \ + sqrt(15)*JzKetCoupled(3, -1, (1, 1, 1), ((1, 2, 2), (1, 3, 3)) )/15 + assert couple(TensorProduct(JzKet(1, -1), JzKet(1, 0), JzKet(1, 1))) == \ + -sqrt(6)*JzKetCoupled(0, 0, (1, 1, 1), ((1, 2, 1), (1, 3, 0)) )/6 + \ + JzKetCoupled(1, 0, (1, 1, 1), ((1, 2, 1), (1, 3, 1)) )/2 + \ + sqrt(15)*JzKetCoupled(1, 0, (1, 1, 1), ((1, 2, 2), (1, 3, 1)) )/10 - \ + sqrt(3)*JzKetCoupled(2, 0, (1, 1, 1), ((1, 2, 1), (1, 3, 2)) )/6 - \ + JzKetCoupled(2, 0, (1, 1, 1), ((1, 2, 2), (1, 3, 2)) )/2 + \ + sqrt(10)*JzKetCoupled(3, 0, (1, 1, 1), ((1, 2, 2), (1, 3, 3)) )/10 + assert couple(TensorProduct(JzKet(1, -1), JzKet(1, 0), JzKet(1, 0))) == \ + JzKetCoupled(1, -1, (1, 1, 1), ((1, 2, 1), (1, 3, 1)) )/2 - \ + sqrt(15)*JzKetCoupled(1, -1, (1, 1, 1), ((1, 2, 2), (1, 3, 1)) )/10 - \ + JzKetCoupled(2, -1, (1, 1, 1), ((1, 2, 1), (1, 3, 2)) )/2 - \ + sqrt(3)*JzKetCoupled(2, -1, (1, 1, 1), ((1, 2, 2), (1, 3, 2)) )/6 + \ + 2*sqrt(15)*JzKetCoupled(3, -1, (1, 1, 1), ((1, 2, 2), (1, 3, 3)) )/15 + assert couple(TensorProduct(JzKet(1, -1), JzKet(1, 0), JzKet(1, -1))) == \ + -sqrt(2)*JzKetCoupled(2, -2, (1, 1, 1), ((1, 2, 1), (1, 3, 2)) )/2 + \ + sqrt(6)*JzKetCoupled(2, -2, (1, 1, 1), ((1, 2, 2), (1, 3, 2)) )/6 + \ + sqrt(3)*JzKetCoupled(3, -2, (1, 1, 1), ((1, 2, 2), (1, 3, 3)) )/3 + assert couple(TensorProduct(JzKet(1, -1), JzKet(1, -1), JzKet(1, 1))) == \ + sqrt(15)*JzKetCoupled(1, -1, (1, 1, 1), ((1, 2, 2), (1, 3, 1)) )/5 - \ + sqrt(3)*JzKetCoupled(2, -1, (1, 1, 1), ((1, 2, 2), (1, 3, 2)) )/3 + \ + sqrt(15)*JzKetCoupled(3, -1, (1, 1, 1), ((1, 2, 2), (1, 3, 3)) )/15 + assert couple(TensorProduct(JzKet(1, -1), JzKet(1, -1), JzKet(1, 0))) == \ + -sqrt(6)*JzKetCoupled(2, -2, (1, 1, 1), ((1, 2, 2), (1, 3, 2)) )/3 + \ + sqrt(3)*JzKetCoupled(3, -2, (1, 1, 1), ((1, 2, 2), (1, 3, 3)) )/3 + assert couple(TensorProduct(JzKet(1, -1), JzKet(1, -1), JzKet(1, -1))) == \ + JzKetCoupled(3, -3, (1, 1, 1), ((1, 2, 2), (1, 3, 3)) ) # j1=S(1)/2, j2=S(1)/2, j3=S(3)/2 - assert couple(TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(S(3)/2,S(3)/2))) == \ - JzKetCoupled(S(5)/2,S(5)/2, (S(1)/2,S(1)/2,S(3)/2), ((1,2,1),(1,3,S(5)/2)) ) - assert couple(TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(S(3)/2,S(1)/2))) == \ - sqrt(10)*JzKetCoupled(S(3)/2,S(3)/2, (S(1)/2,S(1)/2,S(3)/2), ((1,2,1),(1,3,S(3)/2)) )/5 + \ - sqrt(15)*JzKetCoupled(S(5)/2,S(3)/2, (S(1)/2,S(1)/2,S(3)/2), ((1,2,1),(1,3,S(5)/2)) )/5 - assert couple(TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(S(3)/2,S(-1)/2))) == \ - sqrt(6)*JzKetCoupled(S(1)/2,S(1)/2, (S(1)/2,S(1)/2,S(3)/2), ((1,2,1),(1,3,S(1)/2)) )/6 + \ - 2*sqrt(30)*JzKetCoupled(S(3)/2,S(1)/2, (S(1)/2,S(1)/2,S(3)/2), ((1,2,1),(1,3,S(3)/2)) )/15 + \ - sqrt(30)*JzKetCoupled(S(5)/2,S(1)/2, (S(1)/2,S(1)/2,S(3)/2), ((1,2,1),(1,3,S(5)/2)) )/10 - assert couple(TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(S(3)/2,S(-3)/2))) == \ - sqrt(2)*JzKetCoupled(S(1)/2,-S(1)/2, (S(1)/2,S(1)/2,S(3)/2), ((1,2,1),(1,3,S(1)/2)) )/2 + \ - sqrt(10)*JzKetCoupled(S(3)/2,-S(1)/2, (S(1)/2,S(1)/2,S(3)/2), ((1,2,1),(1,3,S(3)/2)) )/5 + \ - sqrt(10)*JzKetCoupled(S(5)/2,-S(1)/2, (S(1)/2,S(1)/2,S(3)/2), ((1,2,1),(1,3,S(5)/2)) )/10 - assert couple(TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(S(3)/2,S(3)/2))) == \ - sqrt(2)*JzKetCoupled(S(3)/2,S(3)/2, (S(1)/2,S(1)/2,S(3)/2), ((1,2,0),(1,3,S(3)/2)) )/2 - \ - sqrt(30)*JzKetCoupled(S(3)/2,S(3)/2, (S(1)/2,S(1)/2,S(3)/2), ((1,2,1),(1,3,S(3)/2)) )/10 + \ - sqrt(5)*JzKetCoupled(S(5)/2,S(3)/2, (S(1)/2,S(1)/2,S(3)/2), ((1,2,1),(1,3,S(5)/2)) )/5 - assert couple(TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(S(3)/2,S(1)/2))) == \ - -sqrt(6)*JzKetCoupled(S(1)/2,S(1)/2, (S(1)/2,S(1)/2,S(3)/2), ((1,2,1),(1,3,S(1)/2)) )/6 + \ - sqrt(2)*JzKetCoupled(S(3)/2,S(1)/2, (S(1)/2,S(1)/2,S(3)/2), ((1,2,0),(1,3,S(3)/2)) )/2 - \ - sqrt(30)*JzKetCoupled(S(3)/2,S(1)/2, (S(1)/2,S(1)/2,S(3)/2), ((1,2,1),(1,3,S(3)/2)) )/30 + \ - sqrt(30)*JzKetCoupled(S(5)/2,S(1)/2, (S(1)/2,S(1)/2,S(3)/2), ((1,2,1),(1,3,S(5)/2)) )/10 - assert couple(TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(S(3)/2,S(-1)/2))) == \ - -sqrt(6)*JzKetCoupled(S(1)/2,-S(1)/2, (S(1)/2,S(1)/2,S(3)/2), ((1,2,1),(1,3,S(1)/2)) )/6 + \ - sqrt(2)*JzKetCoupled(S(3)/2,-S(1)/2, (S(1)/2,S(1)/2,S(3)/2), ((1,2,0),(1,3,S(3)/2)) )/2 + \ - sqrt(30)*JzKetCoupled(S(3)/2,-S(1)/2, (S(1)/2,S(1)/2,S(3)/2), ((1,2,1),(1,3,S(3)/2)) )/30 + \ - sqrt(30)*JzKetCoupled(S(5)/2,-S(1)/2, (S(1)/2,S(1)/2,S(3)/2), ((1,2,1),(1,3,S(5)/2)) )/10 - assert couple(TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(S(3)/2,S(-3)/2))) == \ - sqrt(2)*JzKetCoupled(S(3)/2,-S(3)/2, (S(1)/2,S(1)/2,S(3)/2), ((1,2,0),(1,3,S(3)/2)) )/2 + \ - sqrt(30)*JzKetCoupled(S(3)/2,-S(3)/2, (S(1)/2,S(1)/2,S(3)/2), ((1,2,1),(1,3,S(3)/2)) )/10 + \ - sqrt(5)*JzKetCoupled(S(5)/2,-S(3)/2, (S(1)/2,S(1)/2,S(3)/2), ((1,2,1),(1,3,S(5)/2)) )/5 - assert couple(TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(1)/2), JzKet(S(3)/2,S(3)/2))) == \ - -sqrt(2)*JzKetCoupled(S(3)/2,S(3)/2, (S(1)/2,S(1)/2,S(3)/2), ((1,2,0),(1,3,S(3)/2)) )/2 - \ - sqrt(30)*JzKetCoupled(S(3)/2,S(3)/2, (S(1)/2,S(1)/2,S(3)/2), ((1,2,1),(1,3,S(3)/2)) )/10 + \ - sqrt(5)*JzKetCoupled(S(5)/2,S(3)/2, (S(1)/2,S(1)/2,S(3)/2), ((1,2,1),(1,3,S(5)/2)) )/5 - assert couple(TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(1)/2), JzKet(S(3)/2,S(1)/2))) == \ - -sqrt(6)*JzKetCoupled(S(1)/2,S(1)/2, (S(1)/2,S(1)/2,S(3)/2), ((1,2,1),(1,3,S(1)/2)) )/6 - \ - sqrt(2)*JzKetCoupled(S(3)/2,S(1)/2, (S(1)/2,S(1)/2,S(3)/2), ((1,2,0),(1,3,S(3)/2)) )/2 - \ - sqrt(30)*JzKetCoupled(S(3)/2,S(1)/2, (S(1)/2,S(1)/2,S(3)/2), ((1,2,1),(1,3,S(3)/2)) )/30 + \ - sqrt(30)*JzKetCoupled(S(5)/2,S(1)/2, (S(1)/2,S(1)/2,S(3)/2), ((1,2,1),(1,3,S(5)/2)) )/10 - assert couple(TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(1)/2), JzKet(S(3)/2,S(-1)/2))) == \ - -sqrt(6)*JzKetCoupled(S(1)/2,-S(1)/2, (S(1)/2,S(1)/2,S(3)/2), ((1,2,1),(1,3,S(1)/2)) )/6 - \ - sqrt(2)*JzKetCoupled(S(3)/2,-S(1)/2, (S(1)/2,S(1)/2,S(3)/2), ((1,2,0),(1,3,S(3)/2)) )/2 + \ - sqrt(30)*JzKetCoupled(S(3)/2,-S(1)/2, (S(1)/2,S(1)/2,S(3)/2), ((1,2,1),(1,3,S(3)/2)) )/30 + \ - sqrt(30)*JzKetCoupled(S(5)/2,-S(1)/2, (S(1)/2,S(1)/2,S(3)/2), ((1,2,1),(1,3,S(5)/2)) )/10 - assert couple(TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(1)/2), JzKet(S(3)/2,S(-3)/2))) == \ - -sqrt(2)*JzKetCoupled(S(3)/2,-S(3)/2, (S(1)/2,S(1)/2,S(3)/2), ((1,2,0),(1,3,S(3)/2)) )/2 + \ - sqrt(30)*JzKetCoupled(S(3)/2,-S(3)/2, (S(1)/2,S(1)/2,S(3)/2), ((1,2,1),(1,3,S(3)/2)) )/10 + \ - sqrt(5)*JzKetCoupled(S(5)/2,-S(3)/2, (S(1)/2,S(1)/2,S(3)/2), ((1,2,1),(1,3,S(5)/2)) )/5 - assert couple(TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(S(3)/2,S(3)/2))) == \ - sqrt(2)*JzKetCoupled(S(1)/2,S(1)/2, (S(1)/2,S(1)/2,S(3)/2), ((1,2,1),(1,3,S(1)/2)) )/2 - \ - sqrt(10)*JzKetCoupled(S(3)/2,S(1)/2, (S(1)/2,S(1)/2,S(3)/2), ((1,2,1),(1,3,S(3)/2)) )/5 + \ - sqrt(10)*JzKetCoupled(S(5)/2,S(1)/2, (S(1)/2,S(1)/2,S(3)/2), ((1,2,1),(1,3,S(5)/2)) )/10 - assert couple(TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(S(3)/2,S(1)/2))) == \ - sqrt(6)*JzKetCoupled(S(1)/2,-S(1)/2, (S(1)/2,S(1)/2,S(3)/2), ((1,2,1),(1,3,S(1)/2)) )/6 - \ - 2*sqrt(30)*JzKetCoupled(S(3)/2,-S(1)/2, (S(1)/2,S(1)/2,S(3)/2), ((1,2,1),(1,3,S(3)/2)) )/15 + \ - sqrt(30)*JzKetCoupled(S(5)/2,-S(1)/2, (S(1)/2,S(1)/2,S(3)/2), ((1,2,1),(1,3,S(5)/2)) )/10 - assert couple(TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(S(3)/2,S(-1)/2))) == \ - -sqrt(10)*JzKetCoupled(S(3)/2,-S(3)/2, (S(1)/2,S(1)/2,S(3)/2), ((1,2,1),(1,3,S(3)/2)) )/5 + \ - sqrt(15)*JzKetCoupled(S(5)/2,-S(3)/2, (S(1)/2,S(1)/2,S(3)/2), ((1,2,1),(1,3,S(5)/2)) )/5 - assert couple(TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(S(3)/2,S(-3)/2))) == \ - JzKetCoupled(S(5)/2,-S(5)/2, (S(1)/2,S(1)/2,S(3)/2), ((1,2,1),(1,3,S(5)/2)) ) + assert couple(TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(S(3)/2, S(3)/2))) == \ + JzKetCoupled(S(5)/2, S( + 5)/2, (S(1)/2, S(1)/2, S(3)/2), ((1, 2, 1), (1, 3, S(5)/2)) ) + assert couple(TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(S(3)/2, S(1)/2))) == \ + sqrt(10)*JzKetCoupled(S(3)/2, S(3)/2, (S(1)/2, S(1)/2, S(3)/2), ((1, 2, 1), (1, 3, S(3)/2)) )/5 + \ + sqrt(15)*JzKetCoupled(S(5)/2, S(3)/2, (S(1)/2, S(1)/2, S(3) + /2), ((1, 2, 1), (1, 3, S(5)/2)) )/5 + assert couple(TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(S(3)/2, S(-1)/2))) == \ + sqrt(6)*JzKetCoupled(S(1)/2, S(1)/2, (S(1)/2, S(1)/2, S(3)/2), ((1, 2, 1), (1, 3, S(1)/2)) )/6 + \ + 2*sqrt(30)*JzKetCoupled(S(3)/2, S(1)/2, (S(1)/2, S(1)/2, S(3)/2), ((1, 2, 1), (1, 3, S(3)/2)) )/15 + \ + sqrt(30)*JzKetCoupled(S(5)/2, S( + 1)/2, (S(1)/2, S(1)/2, S(3)/2), ((1, 2, 1), (1, 3, S(5)/2)) )/10 + assert couple(TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(S(3)/2, S(-3)/2))) == \ + sqrt(2)*JzKetCoupled(S(1)/2, -S(1)/2, (S(1)/2, S(1)/2, S(3)/2), ((1, 2, 1), (1, 3, S(1)/2)) )/2 + \ + sqrt(10)*JzKetCoupled(S(3)/2, -S(1)/2, (S(1)/2, S(1)/2, S(3)/2), ((1, 2, 1), (1, 3, S(3)/2)) )/5 + \ + sqrt(10)*JzKetCoupled(S(5)/2, -S( + 1)/2, (S(1)/2, S(1)/2, S(3)/2), ((1, 2, 1), (1, 3, S(5)/2)) )/10 + assert couple(TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(S(3)/2, S(3)/2))) == \ + sqrt(2)*JzKetCoupled(S(3)/2, S(3)/2, (S(1)/2, S(1)/2, S(3)/2), ((1, 2, 0), (1, 3, S(3)/2)) )/2 - \ + sqrt(30)*JzKetCoupled(S(3)/2, S(3)/2, (S(1)/2, S(1)/2, S(3)/2), ((1, 2, 1), (1, 3, S(3)/2)) )/10 + \ + sqrt(5)*JzKetCoupled(S(5)/2, S(3)/2, (S(1)/2, S(1)/2, S(3)/ + 2), ((1, 2, 1), (1, 3, S(5)/2)) )/5 + assert couple(TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(S(3)/2, S(1)/2))) == \ + -sqrt(6)*JzKetCoupled(S(1)/2, S(1)/2, (S(1)/2, S(1)/2, S(3)/2), ((1, 2, 1), (1, 3, S(1)/2)) )/6 + \ + sqrt(2)*JzKetCoupled(S(3)/2, S(1)/2, (S(1)/2, S(1)/2, S(3)/2), ((1, 2, 0), (1, 3, S(3)/2)) )/2 - \ + sqrt(30)*JzKetCoupled(S(3)/2, S(1)/2, (S(1)/2, S(1)/2, S(3)/2), ((1, 2, 1), (1, 3, S(3)/2)) )/30 + \ + sqrt(30)*JzKetCoupled(S(5)/2, S( + 1)/2, (S(1)/2, S(1)/2, S(3)/2), ((1, 2, 1), (1, 3, S(5)/2)) )/10 + assert couple(TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(S(3)/2, S(-1)/2))) == \ + -sqrt(6)*JzKetCoupled(S(1)/2, -S(1)/2, (S(1)/2, S(1)/2, S(3)/2), ((1, 2, 1), (1, 3, S(1)/2)) )/6 + \ + sqrt(2)*JzKetCoupled(S(3)/2, -S(1)/2, (S(1)/2, S(1)/2, S(3)/2), ((1, 2, 0), (1, 3, S(3)/2)) )/2 + \ + sqrt(30)*JzKetCoupled(S(3)/2, -S(1)/2, (S(1)/2, S(1)/2, S(3)/2), ((1, 2, 1), (1, 3, S(3)/2)) )/30 + \ + sqrt(30)*JzKetCoupled(S(5)/2, -S( + 1)/2, (S(1)/2, S(1)/2, S(3)/2), ((1, 2, 1), (1, 3, S(5)/2)) )/10 + assert couple(TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(S(3)/2, S(-3)/2))) == \ + sqrt(2)*JzKetCoupled(S(3)/2, -S(3)/2, (S(1)/2, S(1)/2, S(3)/2), ((1, 2, 0), (1, 3, S(3)/2)) )/2 + \ + sqrt(30)*JzKetCoupled(S(3)/2, -S(3)/2, (S(1)/2, S(1)/2, S(3)/2), ((1, 2, 1), (1, 3, S(3)/2)) )/10 + \ + sqrt(5)*JzKetCoupled(S(5)/2, -S(3)/2, (S(1)/2, S(1)/2, S(3) + /2), ((1, 2, 1), (1, 3, S(5)/2)) )/5 + assert couple(TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(1)/2), JzKet(S(3)/2, S(3)/2))) == \ + -sqrt(2)*JzKetCoupled(S(3)/2, S(3)/2, (S(1)/2, S(1)/2, S(3)/2), ((1, 2, 0), (1, 3, S(3)/2)) )/2 - \ + sqrt(30)*JzKetCoupled(S(3)/2, S(3)/2, (S(1)/2, S(1)/2, S(3)/2), ((1, 2, 1), (1, 3, S(3)/2)) )/10 + \ + sqrt(5)*JzKetCoupled(S(5)/2, S(3)/2, (S(1)/2, S(1)/2, S(3)/ + 2), ((1, 2, 1), (1, 3, S(5)/2)) )/5 + assert couple(TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(1)/2), JzKet(S(3)/2, S(1)/2))) == \ + -sqrt(6)*JzKetCoupled(S(1)/2, S(1)/2, (S(1)/2, S(1)/2, S(3)/2), ((1, 2, 1), (1, 3, S(1)/2)) )/6 - \ + sqrt(2)*JzKetCoupled(S(3)/2, S(1)/2, (S(1)/2, S(1)/2, S(3)/2), ((1, 2, 0), (1, 3, S(3)/2)) )/2 - \ + sqrt(30)*JzKetCoupled(S(3)/2, S(1)/2, (S(1)/2, S(1)/2, S(3)/2), ((1, 2, 1), (1, 3, S(3)/2)) )/30 + \ + sqrt(30)*JzKetCoupled(S(5)/2, S( + 1)/2, (S(1)/2, S(1)/2, S(3)/2), ((1, 2, 1), (1, 3, S(5)/2)) )/10 + assert couple(TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(1)/2), JzKet(S(3)/2, S(-1)/2))) == \ + -sqrt(6)*JzKetCoupled(S(1)/2, -S(1)/2, (S(1)/2, S(1)/2, S(3)/2), ((1, 2, 1), (1, 3, S(1)/2)) )/6 - \ + sqrt(2)*JzKetCoupled(S(3)/2, -S(1)/2, (S(1)/2, S(1)/2, S(3)/2), ((1, 2, 0), (1, 3, S(3)/2)) )/2 + \ + sqrt(30)*JzKetCoupled(S(3)/2, -S(1)/2, (S(1)/2, S(1)/2, S(3)/2), ((1, 2, 1), (1, 3, S(3)/2)) )/30 + \ + sqrt(30)*JzKetCoupled(S(5)/2, -S( + 1)/2, (S(1)/2, S(1)/2, S(3)/2), ((1, 2, 1), (1, 3, S(5)/2)) )/10 + assert couple(TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(1)/2), JzKet(S(3)/2, S(-3)/2))) == \ + -sqrt(2)*JzKetCoupled(S(3)/2, -S(3)/2, (S(1)/2, S(1)/2, S(3)/2), ((1, 2, 0), (1, 3, S(3)/2)) )/2 + \ + sqrt(30)*JzKetCoupled(S(3)/2, -S(3)/2, (S(1)/2, S(1)/2, S(3)/2), ((1, 2, 1), (1, 3, S(3)/2)) )/10 + \ + sqrt(5)*JzKetCoupled(S(5)/2, -S(3)/2, (S(1)/2, S(1)/2, S(3) + /2), ((1, 2, 1), (1, 3, S(5)/2)) )/5 + assert couple(TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(S(3)/2, S(3)/2))) == \ + sqrt(2)*JzKetCoupled(S(1)/2, S(1)/2, (S(1)/2, S(1)/2, S(3)/2), ((1, 2, 1), (1, 3, S(1)/2)) )/2 - \ + sqrt(10)*JzKetCoupled(S(3)/2, S(1)/2, (S(1)/2, S(1)/2, S(3)/2), ((1, 2, 1), (1, 3, S(3)/2)) )/5 + \ + sqrt(10)*JzKetCoupled(S(5)/2, S( + 1)/2, (S(1)/2, S(1)/2, S(3)/2), ((1, 2, 1), (1, 3, S(5)/2)) )/10 + assert couple(TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(S(3)/2, S(1)/2))) == \ + sqrt(6)*JzKetCoupled(S(1)/2, -S(1)/2, (S(1)/2, S(1)/2, S(3)/2), ((1, 2, 1), (1, 3, S(1)/2)) )/6 - \ + 2*sqrt(30)*JzKetCoupled(S(3)/2, -S(1)/2, (S(1)/2, S(1)/2, S(3)/2), ((1, 2, 1), (1, 3, S(3)/2)) )/15 + \ + sqrt(30)*JzKetCoupled(S(5)/2, -S( + 1)/2, (S(1)/2, S(1)/2, S(3)/2), ((1, 2, 1), (1, 3, S(5)/2)) )/10 + assert couple(TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(S(3)/2, S(-1)/2))) == \ + -sqrt(10)*JzKetCoupled(S(3)/2, -S(3)/2, (S(1)/2, S(1)/2, S(3)/2), ((1, 2, 1), (1, 3, S(3)/2)) )/5 + \ + sqrt(15)*JzKetCoupled(S(5)/2, -S(3)/2, (S(1)/2, S(1)/2, S( + 3)/2), ((1, 2, 1), (1, 3, S(5)/2)) )/5 + assert couple(TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(S(3)/2, S(-3)/2))) == \ + JzKetCoupled(S(5)/2, -S( + 5)/2, (S(1)/2, S(1)/2, S(3)/2), ((1, 2, 1), (1, 3, S(5)/2)) ) # Couple j1 to j3 # j1=1/2, j2=1/2, j3=1/2 - assert couple(TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2)), ((1,3),(1,2)) ) == \ - JzKetCoupled(S(3)/2,S(3)/2, (S(1)/2,S(1)/2,S(1)/2), ((1,3,1),(1,2,S(3)/2)) ) - assert couple(TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(-1)/2)), ((1,3),(1,2)) ) == \ - sqrt(2)*JzKetCoupled(S(1)/2,S(1)/2, (S(1)/2,S(1)/2,S(1)/2), ((1,3,0),(1,2,S(1)/2)) )/2 - \ - sqrt(6)*JzKetCoupled(S(1)/2,S(1)/2, (S(1)/2,S(1)/2,S(1)/2), ((1,3,1),(1,2,S(1)/2)) )/6 + \ - sqrt(3)*JzKetCoupled(S(3)/2,S(1)/2, (S(1)/2,S(1)/2,S(1)/2), ((1,3,1),(1,2,S(3)/2)) )/3 - assert couple(TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(1)/2)), ((1,3),(1,2)) ) == \ - sqrt(6)*JzKetCoupled(S(1)/2,S(1)/2, (S(1)/2,S(1)/2,S(1)/2), ((1,3,1),(1,2,S(1)/2)) )/3 + \ - sqrt(3)*JzKetCoupled(S(3)/2,S(1)/2, (S(1)/2,S(1)/2,S(1)/2), ((1,3,1),(1,2,S(3)/2)) )/3 - assert couple(TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(-1)/2)), ((1,3),(1,2)) ) == \ - sqrt(2)*JzKetCoupled(S(1)/2,-S(1)/2, (S(1)/2,S(1)/2,S(1)/2), ((1,3,0),(1,2,S(1)/2)) )/2 + \ - sqrt(6)*JzKetCoupled(S(1)/2,-S(1)/2, (S(1)/2,S(1)/2,S(1)/2), ((1,3,1),(1,2,S(1)/2)) )/6 + \ - sqrt(3)*JzKetCoupled(S(3)/2,-S(1)/2, (S(1)/2,S(1)/2,S(1)/2), ((1,3,1),(1,2,S(3)/2)) )/3 - assert couple(TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2)), ((1,3),(1,2)) ) == \ - -sqrt(2)*JzKetCoupled(S(1)/2,S(1)/2, (S(1)/2,S(1)/2,S(1)/2), ((1,3,0),(1,2,S(1)/2)) )/2 - \ - sqrt(6)*JzKetCoupled(S(1)/2,S(1)/2, (S(1)/2,S(1)/2,S(1)/2), ((1,3,1),(1,2,S(1)/2)) )/6 + \ - sqrt(3)*JzKetCoupled(S(3)/2,S(1)/2, (S(1)/2,S(1)/2,S(1)/2), ((1,3,1),(1,2,S(3)/2)) )/3 - assert couple(TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(-1)/2)), ((1,3),(1,2)) ) == \ - -sqrt(6)*JzKetCoupled(S(1)/2,-S(1)/2, (S(1)/2,S(1)/2,S(1)/2), ((1,3,1),(1,2,S(1)/2)) )/3 + \ - sqrt(3)*JzKetCoupled(S(3)/2,-S(1)/2, (S(1)/2,S(1)/2,S(1)/2), ((1,3,1),(1,2,S(3)/2)) )/3 - assert couple(TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(1)/2)), ((1,3),(1,2)) ) == \ - -sqrt(2)*JzKetCoupled(S(1)/2,-S(1)/2, (S(1)/2,S(1)/2,S(1)/2), ((1,3,0),(1,2,S(1)/2)) )/2 + \ - sqrt(6)*JzKetCoupled(S(1)/2,-S(1)/2, (S(1)/2,S(1)/2,S(1)/2), ((1,3,1),(1,2,S(1)/2)) )/6 + \ - sqrt(3)*JzKetCoupled(S(3)/2,-S(1)/2, (S(1)/2,S(1)/2,S(1)/2), ((1,3,1),(1,2,S(3)/2)) )/3 - assert couple(TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(-1)/2)), ((1,3),(1,2)) ) == \ - JzKetCoupled(S(3)/2,-S(3)/2, (S(1)/2,S(1)/2,S(1)/2), ((1,3,1),(1,2,S(3)/2)) ) + assert couple(TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2)), ((1, 3), (1, 2)) ) == \ + JzKetCoupled(S(3)/2, S( + 3)/2, (S(1)/2, S(1)/2, S(1)/2), ((1, 3, 1), (1, 2, S(3)/2)) ) + assert couple(TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(-1)/2)), ((1, 3), (1, 2)) ) == \ + sqrt(2)*JzKetCoupled(S(1)/2, S(1)/2, (S(1)/2, S(1)/2, S(1)/2), ((1, 3, 0), (1, 2, S(1)/2)) )/2 - \ + sqrt(6)*JzKetCoupled(S(1)/2, S(1)/2, (S(1)/2, S(1)/2, S(1)/2), ((1, 3, 1), (1, 2, S(1)/2)) )/6 + \ + sqrt(3)*JzKetCoupled(S(3)/2, S(1)/2, (S(1)/2, S(1)/2, S(1)/ + 2), ((1, 3, 1), (1, 2, S(3)/2)) )/3 + assert couple(TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(1)/2)), ((1, 3), (1, 2)) ) == \ + sqrt(6)*JzKetCoupled(S(1)/2, S(1)/2, (S(1)/2, S(1)/2, S(1)/2), ((1, 3, 1), (1, 2, S(1)/2)) )/3 + \ + sqrt(3)*JzKetCoupled(S(3)/2, S(1)/2, (S(1)/2, S(1)/2, S(1)/ + 2), ((1, 3, 1), (1, 2, S(3)/2)) )/3 + assert couple(TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(-1)/2)), ((1, 3), (1, 2)) ) == \ + sqrt(2)*JzKetCoupled(S(1)/2, -S(1)/2, (S(1)/2, S(1)/2, S(1)/2), ((1, 3, 0), (1, 2, S(1)/2)) )/2 + \ + sqrt(6)*JzKetCoupled(S(1)/2, -S(1)/2, (S(1)/2, S(1)/2, S(1)/2), ((1, 3, 1), (1, 2, S(1)/2)) )/6 + \ + sqrt(3)*JzKetCoupled(S(3)/2, -S(1)/2, (S(1)/2, S(1)/2, S(1) + /2), ((1, 3, 1), (1, 2, S(3)/2)) )/3 + assert couple(TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2)), ((1, 3), (1, 2)) ) == \ + -sqrt(2)*JzKetCoupled(S(1)/2, S(1)/2, (S(1)/2, S(1)/2, S(1)/2), ((1, 3, 0), (1, 2, S(1)/2)) )/2 - \ + sqrt(6)*JzKetCoupled(S(1)/2, S(1)/2, (S(1)/2, S(1)/2, S(1)/2), ((1, 3, 1), (1, 2, S(1)/2)) )/6 + \ + sqrt(3)*JzKetCoupled(S(3)/2, S(1)/2, (S(1)/2, S(1)/2, S(1)/ + 2), ((1, 3, 1), (1, 2, S(3)/2)) )/3 + assert couple(TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(-1)/2)), ((1, 3), (1, 2)) ) == \ + -sqrt(6)*JzKetCoupled(S(1)/2, -S(1)/2, (S(1)/2, S(1)/2, S(1)/2), ((1, 3, 1), (1, 2, S(1)/2)) )/3 + \ + sqrt(3)*JzKetCoupled(S(3)/2, -S(1)/2, (S(1)/2, S(1)/2, S(1) + /2), ((1, 3, 1), (1, 2, S(3)/2)) )/3 + assert couple(TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(1)/2)), ((1, 3), (1, 2)) ) == \ + -sqrt(2)*JzKetCoupled(S(1)/2, -S(1)/2, (S(1)/2, S(1)/2, S(1)/2), ((1, 3, 0), (1, 2, S(1)/2)) )/2 + \ + sqrt(6)*JzKetCoupled(S(1)/2, -S(1)/2, (S(1)/2, S(1)/2, S(1)/2), ((1, 3, 1), (1, 2, S(1)/2)) )/6 + \ + sqrt(3)*JzKetCoupled(S(3)/2, -S(1)/2, (S(1)/2, S(1)/2, S(1) + /2), ((1, 3, 1), (1, 2, S(3)/2)) )/3 + assert couple(TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(-1)/2)), ((1, 3), (1, 2)) ) == \ + JzKetCoupled(S(3)/2, -S( + 3)/2, (S(1)/2, S(1)/2, S(1)/2), ((1, 3, 1), (1, 2, S(3)/2)) ) # j1=1/2, j2=1/2, j3=1 - assert couple(TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,1)), ((1,3),(1,2)) ) == \ - JzKetCoupled(2,2, (S(1)/2,S(1)/2,1), ((1,3,S(3)/2),(1,2,2)) ) - assert couple(TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,0)), ((1,3),(1,2)) ) == \ - sqrt(3)*JzKetCoupled(1,1, (S(1)/2,S(1)/2,1), ((1,3,S(1)/2),(1,2,1)) )/3 - \ - sqrt(6)*JzKetCoupled(1,1, (S(1)/2,S(1)/2,1), ((1,3,S(3)/2),(1,2,1)) )/6 + \ - sqrt(2)*JzKetCoupled(2,1, (S(1)/2,S(1)/2,1), ((1,3,S(3)/2),(1,2,2)) )/2 - assert couple(TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,-1)), ((1,3),(1,2)) ) == \ - -sqrt(3)*JzKetCoupled(0,0, (S(1)/2,S(1)/2,1), ((1,3,S(1)/2),(1,2,0)) )/3 + \ - sqrt(3)*JzKetCoupled(1,0, (S(1)/2,S(1)/2,1), ((1,3,S(1)/2),(1,2,1)) )/3 - \ - sqrt(6)*JzKetCoupled(1,0, (S(1)/2,S(1)/2,1), ((1,3,S(3)/2),(1,2,1)) )/6 + \ - sqrt(6)*JzKetCoupled(2,0, (S(1)/2,S(1)/2,1), ((1,3,S(3)/2),(1,2,2)) )/6 - assert couple(TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(1,1)), ((1,3),(1,2)) ) == \ - sqrt(3)*JzKetCoupled(1,1, (S(1)/2,S(1)/2,1), ((1,3,S(3)/2),(1,2,1)) )/2 + \ - JzKetCoupled(2,1, (S(1)/2,S(1)/2,1), ((1,3,S(3)/2),(1,2,2)) )/2 - assert couple(TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(1,0)), ((1,3),(1,2)) ) == \ - sqrt(6)*JzKetCoupled(0,0, (S(1)/2,S(1)/2,1), ((1,3,S(1)/2),(1,2,0)) )/6 + \ - sqrt(6)*JzKetCoupled(1,0, (S(1)/2,S(1)/2,1), ((1,3,S(1)/2),(1,2,1)) )/6 + \ - sqrt(3)*JzKetCoupled(1,0, (S(1)/2,S(1)/2,1), ((1,3,S(3)/2),(1,2,1)) )/3 + \ - sqrt(3)*JzKetCoupled(2,0, (S(1)/2,S(1)/2,1), ((1,3,S(3)/2),(1,2,2)) )/3 - assert couple(TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(1,-1)), ((1,3),(1,2)) ) == \ - sqrt(6)*JzKetCoupled(1,-1, (S(1)/2,S(1)/2,1), ((1,3,S(1)/2),(1,2,1)) )/3 + \ - sqrt(3)*JzKetCoupled(1,-1, (S(1)/2,S(1)/2,1), ((1,3,S(3)/2),(1,2,1)) )/6 + \ - JzKetCoupled(2,-1, (S(1)/2,S(1)/2,1), ((1,3,S(3)/2),(1,2,2)) )/2 - assert couple(TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,1)), ((1,3),(1,2)) ) == \ - -sqrt(6)*JzKetCoupled(1,1, (S(1)/2,S(1)/2,1), ((1,3,S(1)/2),(1,2,1)) )/3 - \ - sqrt(3)*JzKetCoupled(1,1, (S(1)/2,S(1)/2,1), ((1,3,S(3)/2),(1,2,1)) )/6 + \ - JzKetCoupled(2,1, (S(1)/2,S(1)/2,1), ((1,3,S(3)/2),(1,2,2)) )/2 - assert couple(TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,0)), ((1,3),(1,2)) ) == \ - sqrt(6)*JzKetCoupled(0,0, (S(1)/2,S(1)/2,1), ((1,3,S(1)/2),(1,2,0)) )/6 - \ - sqrt(6)*JzKetCoupled(1,0, (S(1)/2,S(1)/2,1), ((1,3,S(1)/2),(1,2,1)) )/6 - \ - sqrt(3)*JzKetCoupled(1,0, (S(1)/2,S(1)/2,1), ((1,3,S(3)/2),(1,2,1)) )/3 + \ - sqrt(3)*JzKetCoupled(2,0, (S(1)/2,S(1)/2,1), ((1,3,S(3)/2),(1,2,2)) )/3 - assert couple(TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,-1)), ((1,3),(1,2)) ) == \ - -sqrt(3)*JzKetCoupled(1,-1, (S(1)/2,S(1)/2,1), ((1,3,S(3)/2),(1,2,1)) )/2 + \ - JzKetCoupled(2,-1, (S(1)/2,S(1)/2,1), ((1,3,S(3)/2),(1,2,2)) )/2 - assert couple(TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(1,1)), ((1,3),(1,2)) ) == \ - -sqrt(3)*JzKetCoupled(0,0, (S(1)/2,S(1)/2,1), ((1,3,S(1)/2),(1,2,0)) )/3 - \ - sqrt(3)*JzKetCoupled(1,0, (S(1)/2,S(1)/2,1), ((1,3,S(1)/2),(1,2,1)) )/3 + \ - sqrt(6)*JzKetCoupled(1,0, (S(1)/2,S(1)/2,1), ((1,3,S(3)/2),(1,2,1)) )/6 + \ - sqrt(6)*JzKetCoupled(2,0, (S(1)/2,S(1)/2,1), ((1,3,S(3)/2),(1,2,2)) )/6 - assert couple(TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(1,0)), ((1,3),(1,2)) ) == \ - -sqrt(3)*JzKetCoupled(1,-1, (S(1)/2,S(1)/2,1), ((1,3,S(1)/2),(1,2,1)) )/3 + \ - sqrt(6)*JzKetCoupled(1,-1, (S(1)/2,S(1)/2,1), ((1,3,S(3)/2),(1,2,1)) )/6 + \ - sqrt(2)*JzKetCoupled(2,-1, (S(1)/2,S(1)/2,1), ((1,3,S(3)/2),(1,2,2)) )/2 - assert couple(TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(1,-1)), ((1,3),(1,2)) ) == \ - JzKetCoupled(2,-2, (S(1)/2,S(1)/2,1), ((1,3,S(3)/2),(1,2,2)) ) + assert couple(TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, 1)), ((1, 3), (1, 2)) ) == \ + JzKetCoupled(2, 2, (S(1)/2, S(1)/2, 1), ((1, 3, S(3)/2), (1, 2, 2)) ) + assert couple(TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, 0)), ((1, 3), (1, 2)) ) == \ + sqrt(3)*JzKetCoupled(1, 1, (S(1)/2, S(1)/2, 1), ((1, 3, S(1)/2), (1, 2, 1)) )/3 - \ + sqrt(6)*JzKetCoupled(1, 1, (S(1)/2, S(1)/2, 1), ((1, 3, S(3)/2), (1, 2, 1)) )/6 + \ + sqrt(2)*JzKetCoupled( + 2, 1, (S(1)/2, S(1)/2, 1), ((1, 3, S(3)/2), (1, 2, 2)) )/2 + assert couple(TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, -1)), ((1, 3), (1, 2)) ) == \ + -sqrt(3)*JzKetCoupled(0, 0, (S(1)/2, S(1)/2, 1), ((1, 3, S(1)/2), (1, 2, 0)) )/3 + \ + sqrt(3)*JzKetCoupled(1, 0, (S(1)/2, S(1)/2, 1), ((1, 3, S(1)/2), (1, 2, 1)) )/3 - \ + sqrt(6)*JzKetCoupled(1, 0, (S(1)/2, S(1)/2, 1), ((1, 3, S(3)/2), (1, 2, 1)) )/6 + \ + sqrt(6)*JzKetCoupled( + 2, 0, (S(1)/2, S(1)/2, 1), ((1, 3, S(3)/2), (1, 2, 2)) )/6 + assert couple(TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(1, 1)), ((1, 3), (1, 2)) ) == \ + sqrt(3)*JzKetCoupled(1, 1, (S(1)/2, S(1)/2, 1), ((1, 3, S(3)/2), (1, 2, 1)) )/2 + \ + JzKetCoupled(2, 1, (S(1)/2, S(1)/2, 1), ((1, 3, S(3)/2), (1, 2, 2)) )/2 + assert couple(TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(1, 0)), ((1, 3), (1, 2)) ) == \ + sqrt(6)*JzKetCoupled(0, 0, (S(1)/2, S(1)/2, 1), ((1, 3, S(1)/2), (1, 2, 0)) )/6 + \ + sqrt(6)*JzKetCoupled(1, 0, (S(1)/2, S(1)/2, 1), ((1, 3, S(1)/2), (1, 2, 1)) )/6 + \ + sqrt(3)*JzKetCoupled(1, 0, (S(1)/2, S(1)/2, 1), ((1, 3, S(3)/2), (1, 2, 1)) )/3 + \ + sqrt(3)*JzKetCoupled( + 2, 0, (S(1)/2, S(1)/2, 1), ((1, 3, S(3)/2), (1, 2, 2)) )/3 + assert couple(TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(1, -1)), ((1, 3), (1, 2)) ) == \ + sqrt(6)*JzKetCoupled(1, -1, (S(1)/2, S(1)/2, 1), ((1, 3, S(1)/2), (1, 2, 1)) )/3 + \ + sqrt(3)*JzKetCoupled(1, -1, (S(1)/2, S(1)/2, 1), ((1, 3, S(3)/2), (1, 2, 1)) )/6 + \ + JzKetCoupled( + 2, -1, (S(1)/2, S(1)/2, 1), ((1, 3, S(3)/2), (1, 2, 2)) )/2 + assert couple(TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, 1)), ((1, 3), (1, 2)) ) == \ + -sqrt(6)*JzKetCoupled(1, 1, (S(1)/2, S(1)/2, 1), ((1, 3, S(1)/2), (1, 2, 1)) )/3 - \ + sqrt(3)*JzKetCoupled(1, 1, (S(1)/2, S(1)/2, 1), ((1, 3, S(3)/2), (1, 2, 1)) )/6 + \ + JzKetCoupled(2, 1, (S(1)/2, S(1)/2, 1), ((1, 3, S(3)/2), (1, 2, 2)) )/2 + assert couple(TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, 0)), ((1, 3), (1, 2)) ) == \ + sqrt(6)*JzKetCoupled(0, 0, (S(1)/2, S(1)/2, 1), ((1, 3, S(1)/2), (1, 2, 0)) )/6 - \ + sqrt(6)*JzKetCoupled(1, 0, (S(1)/2, S(1)/2, 1), ((1, 3, S(1)/2), (1, 2, 1)) )/6 - \ + sqrt(3)*JzKetCoupled(1, 0, (S(1)/2, S(1)/2, 1), ((1, 3, S(3)/2), (1, 2, 1)) )/3 + \ + sqrt(3)*JzKetCoupled( + 2, 0, (S(1)/2, S(1)/2, 1), ((1, 3, S(3)/2), (1, 2, 2)) )/3 + assert couple(TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, -1)), ((1, 3), (1, 2)) ) == \ + -sqrt(3)*JzKetCoupled(1, -1, (S(1)/2, S(1)/2, 1), ((1, 3, S(3)/2), (1, 2, 1)) )/2 + \ + JzKetCoupled( + 2, -1, (S(1)/2, S(1)/2, 1), ((1, 3, S(3)/2), (1, 2, 2)) )/2 + assert couple(TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(1, 1)), ((1, 3), (1, 2)) ) == \ + -sqrt(3)*JzKetCoupled(0, 0, (S(1)/2, S(1)/2, 1), ((1, 3, S(1)/2), (1, 2, 0)) )/3 - \ + sqrt(3)*JzKetCoupled(1, 0, (S(1)/2, S(1)/2, 1), ((1, 3, S(1)/2), (1, 2, 1)) )/3 + \ + sqrt(6)*JzKetCoupled(1, 0, (S(1)/2, S(1)/2, 1), ((1, 3, S(3)/2), (1, 2, 1)) )/6 + \ + sqrt(6)*JzKetCoupled( + 2, 0, (S(1)/2, S(1)/2, 1), ((1, 3, S(3)/2), (1, 2, 2)) )/6 + assert couple(TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(1, 0)), ((1, 3), (1, 2)) ) == \ + -sqrt(3)*JzKetCoupled(1, -1, (S(1)/2, S(1)/2, 1), ((1, 3, S(1)/2), (1, 2, 1)) )/3 + \ + sqrt(6)*JzKetCoupled(1, -1, (S(1)/2, S(1)/2, 1), ((1, 3, S(3)/2), (1, 2, 1)) )/6 + \ + sqrt(2)*JzKetCoupled( + 2, -1, (S(1)/2, S(1)/2, 1), ((1, 3, S(3)/2), (1, 2, 2)) )/2 + assert couple(TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(1, -1)), ((1, 3), (1, 2)) ) == \ + JzKetCoupled(2, -2, (S(1)/2, S(1)/2, 1), ((1, 3, S(3)/2), (1, 2, 2)) ) # j 1=1/2, j 2=1, j 3=1 - assert couple(TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(1,1), JzKet(1,1)), ((1,3),(1,2)) ) == \ - JzKetCoupled(S(5)/2,S(5)/2, (S(1)/2,1,1), ((1,3,S(3)/2),(1,2,S(5)/2)) ) - assert couple(TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(1,1), JzKet(1,0)), ((1,3),(1,2)) ) == \ - sqrt(3)*JzKetCoupled(S(3)/2,S(3)/2, (S(1)/2,1,1), ((1,3,S(1)/2),(1,2,S(3)/2)) )/3 - \ - 2*sqrt(15)*JzKetCoupled(S(3)/2,S(3)/2, (S(1)/2,1,1), ((1,3,S(3)/2),(1,2,S(3)/2)) )/15 + \ - sqrt(10)*JzKetCoupled(S(5)/2,S(3)/2, (S(1)/2,1,1), ((1,3,S(3)/2),(1,2,S(5)/2)) )/5 - assert couple(TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(1,1), JzKet(1,-1)), ((1,3),(1,2)) ) == \ - -2*JzKetCoupled(S(1)/2,S(1)/2, (S(1)/2,1,1), ((1,3,S(1)/2),(1,2,S(1)/2)) )/3 + \ - sqrt(2)*JzKetCoupled(S(1)/2,S(1)/2, (S(1)/2,1,1), ((1,3,S(3)/2),(1,2,S(1)/2)) )/6 + \ - sqrt(2)*JzKetCoupled(S(3)/2,S(1)/2, (S(1)/2,1,1), ((1,3,S(1)/2),(1,2,S(3)/2)) )/3 - \ - 2*sqrt(10)*JzKetCoupled(S(3)/2,S(1)/2, (S(1)/2,1,1), ((1,3,S(3)/2),(1,2,S(3)/2)) )/15 + \ - sqrt(10)*JzKetCoupled(S(5)/2,S(1)/2, (S(1)/2,1,1), ((1,3,S(3)/2),(1,2,S(5)/2)) )/10 - assert couple(TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(1,0), JzKet(1,1)), ((1,3),(1,2)) ) == \ - sqrt(15)*JzKetCoupled(S(3)/2,S(3)/2, (S(1)/2,1,1), ((1,3,S(3)/2),(1,2,S(3)/2)) )/5 + \ - sqrt(10)*JzKetCoupled(S(5)/2,S(3)/2, (S(1)/2,1,1), ((1,3,S(3)/2),(1,2,S(5)/2)) )/5 - assert couple(TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(1,0), JzKet(1,0)), ((1,3),(1,2)) ) == \ - JzKetCoupled(S(1)/2,S(1)/2, (S(1)/2,1,1), ((1,3,S(1)/2),(1,2,S(1)/2)) )/3 - \ - sqrt(2)*JzKetCoupled(S(1)/2,S(1)/2, (S(1)/2,1,1), ((1,3,S(3)/2),(1,2,S(1)/2)) )/3 + \ - sqrt(2)*JzKetCoupled(S(3)/2,S(1)/2, (S(1)/2,1,1), ((1,3,S(1)/2),(1,2,S(3)/2)) )/3 + \ - sqrt(10)*JzKetCoupled(S(3)/2,S(1)/2, (S(1)/2,1,1), ((1,3,S(3)/2),(1,2,S(3)/2)) )/15 + \ - sqrt(10)*JzKetCoupled(S(5)/2,S(1)/2, (S(1)/2,1,1), ((1,3,S(3)/2),(1,2,S(5)/2)) )/5 - assert couple(TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(1,0), JzKet(1,-1)), ((1,3),(1,2)) ) == \ - -sqrt(2)*JzKetCoupled(S(1)/2,-S(1)/2, (S(1)/2,1,1), ((1,3,S(1)/2),(1,2,S(1)/2)) )/3 - \ - JzKetCoupled(S(1)/2,-S(1)/2, (S(1)/2,1,1), ((1,3,S(3)/2),(1,2,S(1)/2)) )/3 + \ - 2*JzKetCoupled(S(3)/2,-S(1)/2, (S(1)/2,1,1), ((1,3,S(1)/2),(1,2,S(3)/2)) )/3 - \ - sqrt(5)*JzKetCoupled(S(3)/2,-S(1)/2, (S(1)/2,1,1), ((1,3,S(3)/2),(1,2,S(3)/2)) )/15 + \ - sqrt(5)*JzKetCoupled(S(5)/2,-S(1)/2, (S(1)/2,1,1), ((1,3,S(3)/2),(1,2,S(5)/2)) )/5 - assert couple(TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(1,-1), JzKet(1,1)), ((1,3),(1,2)) ) == \ - sqrt(2)*JzKetCoupled(S(1)/2,S(1)/2, (S(1)/2,1,1), ((1,3,S(3)/2),(1,2,S(1)/2)) )/2 + \ - sqrt(10)*JzKetCoupled(S(3)/2,S(1)/2, (S(1)/2,1,1), ((1,3,S(3)/2),(1,2,S(3)/2)) )/5 + \ - sqrt(10)*JzKetCoupled(S(5)/2,S(1)/2, (S(1)/2,1,1), ((1,3,S(3)/2),(1,2,S(5)/2)) )/10 - assert couple(TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(1,-1), JzKet(1,0)), ((1,3),(1,2)) ) == \ - sqrt(2)*JzKetCoupled(S(1)/2,-S(1)/2, (S(1)/2,1,1), ((1,3,S(1)/2),(1,2,S(1)/2)) )/3 + \ - JzKetCoupled(S(1)/2,-S(1)/2, (S(1)/2,1,1), ((1,3,S(3)/2),(1,2,S(1)/2)) )/3 + \ - JzKetCoupled(S(3)/2,-S(1)/2, (S(1)/2,1,1), ((1,3,S(1)/2),(1,2,S(3)/2)) )/3 + \ - 4*sqrt(5)*JzKetCoupled(S(3)/2,-S(1)/2, (S(1)/2,1,1), ((1,3,S(3)/2),(1,2,S(3)/2)) )/15 + \ - sqrt(5)*JzKetCoupled(S(5)/2,-S(1)/2, (S(1)/2,1,1), ((1,3,S(3)/2),(1,2,S(5)/2)) )/5 - assert couple(TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(1,-1), JzKet(1,-1)), ((1,3),(1,2)) ) == \ - sqrt(6)*JzKetCoupled(S(3)/2,-S(3)/2, (S(1)/2,1,1), ((1,3,S(1)/2),(1,2,S(3)/2)) )/3 + \ - sqrt(30)*JzKetCoupled(S(3)/2,-S(3)/2, (S(1)/2,1,1), ((1,3,S(3)/2),(1,2,S(3)/2)) )/15 + \ - sqrt(5)*JzKetCoupled(S(5)/2,-S(3)/2, (S(1)/2,1,1), ((1,3,S(3)/2),(1,2,S(5)/2)) )/5 - assert couple(TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(1,1), JzKet(1,1)), ((1,3),(1,2)) ) == \ - -sqrt(6)*JzKetCoupled(S(3)/2,S(3)/2, (S(1)/2,1,1), ((1,3,S(1)/2),(1,2,S(3)/2)) )/3 - \ - sqrt(30)*JzKetCoupled(S(3)/2,S(3)/2, (S(1)/2,1,1), ((1,3,S(3)/2),(1,2,S(3)/2)) )/15 + \ - sqrt(5)*JzKetCoupled(S(5)/2,S(3)/2, (S(1)/2,1,1), ((1,3,S(3)/2),(1,2,S(5)/2)) )/5 - assert couple(TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(1,1), JzKet(1,0)), ((1,3),(1,2)) ) == \ - sqrt(2)*JzKetCoupled(S(1)/2,S(1)/2, (S(1)/2,1,1), ((1,3,S(1)/2),(1,2,S(1)/2)) )/3 + \ - JzKetCoupled(S(1)/2,S(1)/2, (S(1)/2,1,1), ((1,3,S(3)/2),(1,2,S(1)/2)) )/3 - \ - JzKetCoupled(S(3)/2,S(1)/2, (S(1)/2,1,1), ((1,3,S(1)/2),(1,2,S(3)/2)) )/3 - \ - 4*sqrt(5)*JzKetCoupled(S(3)/2,S(1)/2, (S(1)/2,1,1), ((1,3,S(3)/2),(1,2,S(3)/2)) )/15 + \ - sqrt(5)*JzKetCoupled(S(5)/2,S(1)/2, (S(1)/2,1,1), ((1,3,S(3)/2),(1,2,S(5)/2)) )/5 - assert couple(TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(1,1), JzKet(1,-1)), ((1,3),(1,2)) ) == \ - sqrt(2)*JzKetCoupled(S(1)/2,-S(1)/2, (S(1)/2,1,1), ((1,3,S(3)/2),(1,2,S(1)/2)) )/2 - \ - sqrt(10)*JzKetCoupled(S(3)/2,-S(1)/2, (S(1)/2,1,1), ((1,3,S(3)/2),(1,2,S(3)/2)) )/5 + \ - sqrt(10)*JzKetCoupled(S(5)/2,-S(1)/2, (S(1)/2,1,1), ((1,3,S(3)/2),(1,2,S(5)/2)) )/10 - assert couple(TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(1,0), JzKet(1,1)), ((1,3),(1,2)) ) == \ - -sqrt(2)*JzKetCoupled(S(1)/2,S(1)/2, (S(1)/2,1,1), ((1,3,S(1)/2),(1,2,S(1)/2)) )/3 - \ - JzKetCoupled(S(1)/2,S(1)/2, (S(1)/2,1,1), ((1,3,S(3)/2),(1,2,S(1)/2)) )/3 - \ - 2*JzKetCoupled(S(3)/2,S(1)/2, (S(1)/2,1,1), ((1,3,S(1)/2),(1,2,S(3)/2)) )/3 + \ - sqrt(5)*JzKetCoupled(S(3)/2,S(1)/2, (S(1)/2,1,1), ((1,3,S(3)/2),(1,2,S(3)/2)) )/15 + \ - sqrt(5)*JzKetCoupled(S(5)/2,S(1)/2, (S(1)/2,1,1), ((1,3,S(3)/2),(1,2,S(5)/2)) )/5 - assert couple(TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(1,0), JzKet(1,0)), ((1,3),(1,2)) ) == \ - JzKetCoupled(S(1)/2,-S(1)/2, (S(1)/2,1,1), ((1,3,S(1)/2),(1,2,S(1)/2)) )/3 - \ - sqrt(2)*JzKetCoupled(S(1)/2,-S(1)/2, (S(1)/2,1,1), ((1,3,S(3)/2),(1,2,S(1)/2)) )/3 - \ - sqrt(2)*JzKetCoupled(S(3)/2,-S(1)/2, (S(1)/2,1,1), ((1,3,S(1)/2),(1,2,S(3)/2)) )/3 - \ - sqrt(10)*JzKetCoupled(S(3)/2,-S(1)/2, (S(1)/2,1,1), ((1,3,S(3)/2),(1,2,S(3)/2)) )/15 + \ - sqrt(10)*JzKetCoupled(S(5)/2,-S(1)/2, (S(1)/2,1,1), ((1,3,S(3)/2),(1,2,S(5)/2)) )/5 - assert couple(TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(1,0), JzKet(1,-1)), ((1,3),(1,2)) ) == \ - -sqrt(15)*JzKetCoupled(S(3)/2,-S(3)/2, (S(1)/2,1,1), ((1,3,S(3)/2),(1,2,S(3)/2)) )/5 + \ - sqrt(10)*JzKetCoupled(S(5)/2,-S(3)/2, (S(1)/2,1,1), ((1,3,S(3)/2),(1,2,S(5)/2)) )/5 - assert couple(TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(1,-1), JzKet(1,1)), ((1,3),(1,2)) ) == \ - -2*JzKetCoupled(S(1)/2,-S(1)/2, (S(1)/2,1,1), ((1,3,S(1)/2),(1,2,S(1)/2)) )/3 + \ - sqrt(2)*JzKetCoupled(S(1)/2,-S(1)/2, (S(1)/2,1,1), ((1,3,S(3)/2),(1,2,S(1)/2)) )/6 - \ - sqrt(2)*JzKetCoupled(S(3)/2,-S(1)/2, (S(1)/2,1,1), ((1,3,S(1)/2),(1,2,S(3)/2)) )/3 + \ - 2*sqrt(10)*JzKetCoupled(S(3)/2,-S(1)/2, (S(1)/2,1,1), ((1,3,S(3)/2),(1,2,S(3)/2)) )/15 + \ - sqrt(10)*JzKetCoupled(S(5)/2,-S(1)/2, (S(1)/2,1,1), ((1,3,S(3)/2),(1,2,S(5)/2)) )/10 - assert couple(TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(1,-1), JzKet(1,0)), ((1,3),(1,2)) ) == \ - -sqrt(3)*JzKetCoupled(S(3)/2,-S(3)/2, (S(1)/2,1,1), ((1,3,S(1)/2),(1,2,S(3)/2)) )/3 + \ - 2*sqrt(15)*JzKetCoupled(S(3)/2,-S(3)/2, (S(1)/2,1,1), ((1,3,S(3)/2),(1,2,S(3)/2)) )/15 + \ - sqrt(10)*JzKetCoupled(S(5)/2,-S(3)/2, (S(1)/2,1,1), ((1,3,S(3)/2),(1,2,S(5)/2)) )/5 - assert couple(TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(1,-1), JzKet(1,-1)), ((1,3),(1,2)) ) == \ - JzKetCoupled(S(5)/2,-S(5)/2, (S(1)/2,1,1), ((1,3,S(3)/2),(1,2,S(5)/2)) ) + assert couple(TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(1, 1), JzKet(1, 1)), ((1, 3), (1, 2)) ) == \ + JzKetCoupled( + S(5)/2, S(5)/2, (S(1)/2, 1, 1), ((1, 3, S(3)/2), (1, 2, S(5)/2)) ) + assert couple(TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(1, 1), JzKet(1, 0)), ((1, 3), (1, 2)) ) == \ + sqrt(3)*JzKetCoupled(S(3)/2, S(3)/2, (S(1)/2, 1, 1), ((1, 3, S(1)/2), (1, 2, S(3)/2)) )/3 - \ + 2*sqrt(15)*JzKetCoupled(S(3)/2, S(3)/2, (S(1)/2, 1, 1), ((1, 3, S(3)/2), (1, 2, S(3)/2)) )/15 + \ + sqrt(10)*JzKetCoupled(S( + 5)/2, S(3)/2, (S(1)/2, 1, 1), ((1, 3, S(3)/2), (1, 2, S(5)/2)) )/5 + assert couple(TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(1, 1), JzKet(1, -1)), ((1, 3), (1, 2)) ) == \ + -2*JzKetCoupled(S(1)/2, S(1)/2, (S(1)/2, 1, 1), ((1, 3, S(1)/2), (1, 2, S(1)/2)) )/3 + \ + sqrt(2)*JzKetCoupled(S(1)/2, S(1)/2, (S(1)/2, 1, 1), ((1, 3, S(3)/2), (1, 2, S(1)/2)) )/6 + \ + sqrt(2)*JzKetCoupled(S(3)/2, S(1)/2, (S(1)/2, 1, 1), ((1, 3, S(1)/2), (1, 2, S(3)/2)) )/3 - \ + 2*sqrt(10)*JzKetCoupled(S(3)/2, S(1)/2, (S(1)/2, 1, 1), ((1, 3, S(3)/2), (1, 2, S(3)/2)) )/15 + \ + sqrt(10)*JzKetCoupled(S(5)/2, S(1)/2, (S(1)/2, 1, 1), ((1, + 3, S(3)/2), (1, 2, S(5)/2)) )/10 + assert couple(TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(1, 0), JzKet(1, 1)), ((1, 3), (1, 2)) ) == \ + sqrt(15)*JzKetCoupled(S(3)/2, S(3)/2, (S(1)/2, 1, 1), ((1, 3, S(3)/2), (1, 2, S(3)/2)) )/5 + \ + sqrt(10)*JzKetCoupled(S( + 5)/2, S(3)/2, (S(1)/2, 1, 1), ((1, 3, S(3)/2), (1, 2, S(5)/2)) )/5 + assert couple(TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(1, 0), JzKet(1, 0)), ((1, 3), (1, 2)) ) == \ + JzKetCoupled(S(1)/2, S(1)/2, (S(1)/2, 1, 1), ((1, 3, S(1)/2), (1, 2, S(1)/2)) )/3 - \ + sqrt(2)*JzKetCoupled(S(1)/2, S(1)/2, (S(1)/2, 1, 1), ((1, 3, S(3)/2), (1, 2, S(1)/2)) )/3 + \ + sqrt(2)*JzKetCoupled(S(3)/2, S(1)/2, (S(1)/2, 1, 1), ((1, 3, S(1)/2), (1, 2, S(3)/2)) )/3 + \ + sqrt(10)*JzKetCoupled(S(3)/2, S(1)/2, (S(1)/2, 1, 1), ((1, 3, S(3)/2), (1, 2, S(3)/2)) )/15 + \ + sqrt(10)*JzKetCoupled(S( + 5)/2, S(1)/2, (S(1)/2, 1, 1), ((1, 3, S(3)/2), (1, 2, S(5)/2)) )/5 + assert couple(TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(1, 0), JzKet(1, -1)), ((1, 3), (1, 2)) ) == \ + -sqrt(2)*JzKetCoupled(S(1)/2, -S(1)/2, (S(1)/2, 1, 1), ((1, 3, S(1)/2), (1, 2, S(1)/2)) )/3 - \ + JzKetCoupled(S(1)/2, -S(1)/2, (S(1)/2, 1, 1), ((1, 3, S(3)/2), (1, 2, S(1)/2)) )/3 + \ + 2*JzKetCoupled(S(3)/2, -S(1)/2, (S(1)/2, 1, 1), ((1, 3, S(1)/2), (1, 2, S(3)/2)) )/3 - \ + sqrt(5)*JzKetCoupled(S(3)/2, -S(1)/2, (S(1)/2, 1, 1), ((1, 3, S(3)/2), (1, 2, S(3)/2)) )/15 + \ + sqrt(5)*JzKetCoupled(S(5)/2, -S(1)/2, (S(1)/2, 1, 1), ((1, + 3, S(3)/2), (1, 2, S(5)/2)) )/5 + assert couple(TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(1, -1), JzKet(1, 1)), ((1, 3), (1, 2)) ) == \ + sqrt(2)*JzKetCoupled(S(1)/2, S(1)/2, (S(1)/2, 1, 1), ((1, 3, S(3)/2), (1, 2, S(1)/2)) )/2 + \ + sqrt(10)*JzKetCoupled(S(3)/2, S(1)/2, (S(1)/2, 1, 1), ((1, 3, S(3)/2), (1, 2, S(3)/2)) )/5 + \ + sqrt(10)*JzKetCoupled(S(5)/2, S(1)/2, (S(1)/2, 1, 1), ((1, + 3, S(3)/2), (1, 2, S(5)/2)) )/10 + assert couple(TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(1, -1), JzKet(1, 0)), ((1, 3), (1, 2)) ) == \ + sqrt(2)*JzKetCoupled(S(1)/2, -S(1)/2, (S(1)/2, 1, 1), ((1, 3, S(1)/2), (1, 2, S(1)/2)) )/3 + \ + JzKetCoupled(S(1)/2, -S(1)/2, (S(1)/2, 1, 1), ((1, 3, S(3)/2), (1, 2, S(1)/2)) )/3 + \ + JzKetCoupled(S(3)/2, -S(1)/2, (S(1)/2, 1, 1), ((1, 3, S(1)/2), (1, 2, S(3)/2)) )/3 + \ + 4*sqrt(5)*JzKetCoupled(S(3)/2, -S(1)/2, (S(1)/2, 1, 1), ((1, 3, S(3)/2), (1, 2, S(3)/2)) )/15 + \ + sqrt(5)*JzKetCoupled(S(5)/2, -S(1)/2, (S(1)/2, 1, 1), ((1, + 3, S(3)/2), (1, 2, S(5)/2)) )/5 + assert couple(TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(1, -1), JzKet(1, -1)), ((1, 3), (1, 2)) ) == \ + sqrt(6)*JzKetCoupled(S(3)/2, -S(3)/2, (S(1)/2, 1, 1), ((1, 3, S(1)/2), (1, 2, S(3)/2)) )/3 + \ + sqrt(30)*JzKetCoupled(S(3)/2, -S(3)/2, (S(1)/2, 1, 1), ((1, 3, S(3)/2), (1, 2, S(3)/2)) )/15 + \ + sqrt(5)*JzKetCoupled(S(5)/2, -S(3)/2, (S(1)/2, 1, 1), ((1, + 3, S(3)/2), (1, 2, S(5)/2)) )/5 + assert couple(TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(1, 1), JzKet(1, 1)), ((1, 3), (1, 2)) ) == \ + -sqrt(6)*JzKetCoupled(S(3)/2, S(3)/2, (S(1)/2, 1, 1), ((1, 3, S(1)/2), (1, 2, S(3)/2)) )/3 - \ + sqrt(30)*JzKetCoupled(S(3)/2, S(3)/2, (S(1)/2, 1, 1), ((1, 3, S(3)/2), (1, 2, S(3)/2)) )/15 + \ + sqrt(5)*JzKetCoupled(S( + 5)/2, S(3)/2, (S(1)/2, 1, 1), ((1, 3, S(3)/2), (1, 2, S(5)/2)) )/5 + assert couple(TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(1, 1), JzKet(1, 0)), ((1, 3), (1, 2)) ) == \ + sqrt(2)*JzKetCoupled(S(1)/2, S(1)/2, (S(1)/2, 1, 1), ((1, 3, S(1)/2), (1, 2, S(1)/2)) )/3 + \ + JzKetCoupled(S(1)/2, S(1)/2, (S(1)/2, 1, 1), ((1, 3, S(3)/2), (1, 2, S(1)/2)) )/3 - \ + JzKetCoupled(S(3)/2, S(1)/2, (S(1)/2, 1, 1), ((1, 3, S(1)/2), (1, 2, S(3)/2)) )/3 - \ + 4*sqrt(5)*JzKetCoupled(S(3)/2, S(1)/2, (S(1)/2, 1, 1), ((1, 3, S(3)/2), (1, 2, S(3)/2)) )/15 + \ + sqrt(5)*JzKetCoupled(S( + 5)/2, S(1)/2, (S(1)/2, 1, 1), ((1, 3, S(3)/2), (1, 2, S(5)/2)) )/5 + assert couple(TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(1, 1), JzKet(1, -1)), ((1, 3), (1, 2)) ) == \ + sqrt(2)*JzKetCoupled(S(1)/2, -S(1)/2, (S(1)/2, 1, 1), ((1, 3, S(3)/2), (1, 2, S(1)/2)) )/2 - \ + sqrt(10)*JzKetCoupled(S(3)/2, -S(1)/2, (S(1)/2, 1, 1), ((1, 3, S(3)/2), (1, 2, S(3)/2)) )/5 + \ + sqrt(10)*JzKetCoupled(S(5)/2, -S(1)/2, (S(1)/2, 1, 1), ((1, + 3, S(3)/2), (1, 2, S(5)/2)) )/10 + assert couple(TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(1, 0), JzKet(1, 1)), ((1, 3), (1, 2)) ) == \ + -sqrt(2)*JzKetCoupled(S(1)/2, S(1)/2, (S(1)/2, 1, 1), ((1, 3, S(1)/2), (1, 2, S(1)/2)) )/3 - \ + JzKetCoupled(S(1)/2, S(1)/2, (S(1)/2, 1, 1), ((1, 3, S(3)/2), (1, 2, S(1)/2)) )/3 - \ + 2*JzKetCoupled(S(3)/2, S(1)/2, (S(1)/2, 1, 1), ((1, 3, S(1)/2), (1, 2, S(3)/2)) )/3 + \ + sqrt(5)*JzKetCoupled(S(3)/2, S(1)/2, (S(1)/2, 1, 1), ((1, 3, S(3)/2), (1, 2, S(3)/2)) )/15 + \ + sqrt(5)*JzKetCoupled(S( + 5)/2, S(1)/2, (S(1)/2, 1, 1), ((1, 3, S(3)/2), (1, 2, S(5)/2)) )/5 + assert couple(TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(1, 0), JzKet(1, 0)), ((1, 3), (1, 2)) ) == \ + JzKetCoupled(S(1)/2, -S(1)/2, (S(1)/2, 1, 1), ((1, 3, S(1)/2), (1, 2, S(1)/2)) )/3 - \ + sqrt(2)*JzKetCoupled(S(1)/2, -S(1)/2, (S(1)/2, 1, 1), ((1, 3, S(3)/2), (1, 2, S(1)/2)) )/3 - \ + sqrt(2)*JzKetCoupled(S(3)/2, -S(1)/2, (S(1)/2, 1, 1), ((1, 3, S(1)/2), (1, 2, S(3)/2)) )/3 - \ + sqrt(10)*JzKetCoupled(S(3)/2, -S(1)/2, (S(1)/2, 1, 1), ((1, 3, S(3)/2), (1, 2, S(3)/2)) )/15 + \ + sqrt(10)*JzKetCoupled(S(5)/2, -S(1)/2, (S(1)/2, 1, 1), ((1, + 3, S(3)/2), (1, 2, S(5)/2)) )/5 + assert couple(TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(1, 0), JzKet(1, -1)), ((1, 3), (1, 2)) ) == \ + -sqrt(15)*JzKetCoupled(S(3)/2, -S(3)/2, (S(1)/2, 1, 1), ((1, 3, S(3)/2), (1, 2, S(3)/2)) )/5 + \ + sqrt(10)*JzKetCoupled(S(5)/2, -S(3)/2, (S(1)/2, 1, 1), ((1, + 3, S(3)/2), (1, 2, S(5)/2)) )/5 + assert couple(TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(1, -1), JzKet(1, 1)), ((1, 3), (1, 2)) ) == \ + -2*JzKetCoupled(S(1)/2, -S(1)/2, (S(1)/2, 1, 1), ((1, 3, S(1)/2), (1, 2, S(1)/2)) )/3 + \ + sqrt(2)*JzKetCoupled(S(1)/2, -S(1)/2, (S(1)/2, 1, 1), ((1, 3, S(3)/2), (1, 2, S(1)/2)) )/6 - \ + sqrt(2)*JzKetCoupled(S(3)/2, -S(1)/2, (S(1)/2, 1, 1), ((1, 3, S(1)/2), (1, 2, S(3)/2)) )/3 + \ + 2*sqrt(10)*JzKetCoupled(S(3)/2, -S(1)/2, (S(1)/2, 1, 1), ((1, 3, S(3)/2), (1, 2, S(3)/2)) )/15 + \ + sqrt(10)*JzKetCoupled(S(5)/2, -S(1)/2, (S(1)/2, 1, 1), ((1, + 3, S(3)/2), (1, 2, S(5)/2)) )/10 + assert couple(TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(1, -1), JzKet(1, 0)), ((1, 3), (1, 2)) ) == \ + -sqrt(3)*JzKetCoupled(S(3)/2, -S(3)/2, (S(1)/2, 1, 1), ((1, 3, S(1)/2), (1, 2, S(3)/2)) )/3 + \ + 2*sqrt(15)*JzKetCoupled(S(3)/2, -S(3)/2, (S(1)/2, 1, 1), ((1, 3, S(3)/2), (1, 2, S(3)/2)) )/15 + \ + sqrt(10)*JzKetCoupled(S(5)/2, -S(3)/2, (S(1)/2, 1, 1), ((1, + 3, S(3)/2), (1, 2, S(5)/2)) )/5 + assert couple(TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(1, -1), JzKet(1, -1)), ((1, 3), (1, 2)) ) == \ + JzKetCoupled(S( + 5)/2, -S(5)/2, (S(1)/2, 1, 1), ((1, 3, S(3)/2), (1, 2, S(5)/2)) ) # j1=1, 1, 1 - assert couple(TensorProduct(JzKet(1,1), JzKet(1,1), JzKet(1,1)), ((1,3),(1,2)) ) == \ - JzKetCoupled(3,3, (1,1,1), ((1,3,2),(1,2,3)) ) - assert couple(TensorProduct(JzKet(1,1), JzKet(1,1), JzKet(1,0)), ((1,3),(1,2)) ) == \ - sqrt(2)*JzKetCoupled(2,2, (1,1,1), ((1,3,1),(1,2,2)) )/2 - \ - sqrt(6)*JzKetCoupled(2,2, (1,1,1), ((1,3,2),(1,2,2)) )/6 + \ - sqrt(3)*JzKetCoupled(3,2, (1,1,1), ((1,3,2),(1,2,3)) )/3 - assert couple(TensorProduct(JzKet(1,1), JzKet(1,1), JzKet(1,-1)), ((1,3),(1,2)) ) == \ - sqrt(3)*JzKetCoupled(1,1, (1,1,1), ((1,3,0),(1,2,1)) )/3 - \ - JzKetCoupled(1,1, (1,1,1), ((1,3,1),(1,2,1)) )/2 + \ - sqrt(15)*JzKetCoupled(1,1, (1,1,1), ((1,3,2),(1,2,1)) )/30 + \ - JzKetCoupled(2,1, (1,1,1), ((1,3,1),(1,2,2)) )/2 - \ - sqrt(3)*JzKetCoupled(2,1, (1,1,1), ((1,3,2),(1,2,2)) )/6 + \ - sqrt(15)*JzKetCoupled(3,1, (1,1,1), ((1,3,2),(1,2,3)) )/15 - assert couple(TensorProduct(JzKet(1,1), JzKet(1,0), JzKet(1,1)), ((1,3),(1,2)) ) == \ - sqrt(6)*JzKetCoupled(2,2, (1,1,1), ((1,3,2),(1,2,2)) )/3 + \ - sqrt(3)*JzKetCoupled(3,2, (1,1,1), ((1,3,2),(1,2,3)) )/3 - assert couple(TensorProduct(JzKet(1,1), JzKet(1,0), JzKet(1,0)), ((1,3),(1,2)) ) == \ - JzKetCoupled(1,1, (1,1,1), ((1,3,1),(1,2,1)) )/2 - \ - sqrt(15)*JzKetCoupled(1,1, (1,1,1), ((1,3,2),(1,2,1)) )/10 + \ - JzKetCoupled(2,1, (1,1,1), ((1,3,1),(1,2,2)) )/2 + \ - sqrt(3)*JzKetCoupled(2,1, (1,1,1), ((1,3,2),(1,2,2)) )/6 + \ - 2*sqrt(15)*JzKetCoupled(3,1, (1,1,1), ((1,3,2),(1,2,3)) )/15 - assert couple(TensorProduct(JzKet(1,1), JzKet(1,0), JzKet(1,-1)), ((1,3),(1,2)) ) == \ - -sqrt(6)*JzKetCoupled(0,0, (1,1,1), ((1,3,1),(1,2,0)) )/6 + \ - sqrt(3)*JzKetCoupled(1,0, (1,1,1), ((1,3,0),(1,2,1)) )/3 - \ - sqrt(15)*JzKetCoupled(1,0, (1,1,1), ((1,3,2),(1,2,1)) )/15 + \ - sqrt(3)*JzKetCoupled(2,0, (1,1,1), ((1,3,1),(1,2,2)) )/3 + \ - sqrt(10)*JzKetCoupled(3,0, (1,1,1), ((1,3,2),(1,2,3)) )/10 - assert couple(TensorProduct(JzKet(1,1), JzKet(1,-1), JzKet(1,1)), ((1,3),(1,2)) ) == \ - sqrt(15)*JzKetCoupled(1,1, (1,1,1), ((1,3,2),(1,2,1)) )/5 + \ - sqrt(3)*JzKetCoupled(2,1, (1,1,1), ((1,3,2),(1,2,2)) )/3 + \ - sqrt(15)*JzKetCoupled(3,1, (1,1,1), ((1,3,2),(1,2,3)) )/15 - assert couple(TensorProduct(JzKet(1,1), JzKet(1,-1), JzKet(1,0)), ((1,3),(1,2)) ) == \ - sqrt(6)*JzKetCoupled(0,0, (1,1,1), ((1,3,1),(1,2,0)) )/6 + \ - JzKetCoupled(1,0, (1,1,1), ((1,3,1),(1,2,1)) )/2 + \ - sqrt(15)*JzKetCoupled(1,0, (1,1,1), ((1,3,2),(1,2,1)) )/10 + \ - sqrt(3)*JzKetCoupled(2,0, (1,1,1), ((1,3,1),(1,2,2)) )/6 + \ - JzKetCoupled(2,0, (1,1,1), ((1,3,2),(1,2,2)) )/2 + \ - sqrt(10)*JzKetCoupled(3,0, (1,1,1), ((1,3,2),(1,2,3)) )/10 - assert couple(TensorProduct(JzKet(1,1), JzKet(1,-1), JzKet(1,-1)), ((1,3),(1,2)) ) == \ - sqrt(3)*JzKetCoupled(1,-1, (1,1,1), ((1,3,0),(1,2,1)) )/3 + \ - JzKetCoupled(1,-1, (1,1,1), ((1,3,1),(1,2,1)) )/2 + \ - sqrt(15)*JzKetCoupled(1,-1, (1,1,1), ((1,3,2),(1,2,1)) )/30 + \ - JzKetCoupled(2,-1, (1,1,1), ((1,3,1),(1,2,2)) )/2 + \ - sqrt(3)*JzKetCoupled(2,-1, (1,1,1), ((1,3,2),(1,2,2)) )/6 + \ - sqrt(15)*JzKetCoupled(3,-1, (1,1,1), ((1,3,2),(1,2,3)) )/15 - assert couple(TensorProduct(JzKet(1,0), JzKet(1,1), JzKet(1,1)), ((1,3),(1,2)) ) == \ - -sqrt(2)*JzKetCoupled(2,2, (1,1,1), ((1,3,1),(1,2,2)) )/2 - \ - sqrt(6)*JzKetCoupled(2,2, (1,1,1), ((1,3,2),(1,2,2)) )/6 + \ - sqrt(3)*JzKetCoupled(3,2, (1,1,1), ((1,3,2),(1,2,3)) )/3 - assert couple(TensorProduct(JzKet(1,0), JzKet(1,1), JzKet(1,0)), ((1,3),(1,2)) ) == \ - -sqrt(3)*JzKetCoupled(1,1, (1,1,1), ((1,3,0),(1,2,1)) )/3 + \ - sqrt(15)*JzKetCoupled(1,1, (1,1,1), ((1,3,2),(1,2,1)) )/15 - \ - sqrt(3)*JzKetCoupled(2,1, (1,1,1), ((1,3,2),(1,2,2)) )/3 + \ - 2*sqrt(15)*JzKetCoupled(3,1, (1,1,1), ((1,3,2),(1,2,3)) )/15 - assert couple(TensorProduct(JzKet(1,0), JzKet(1,1), JzKet(1,-1)), ((1,3),(1,2)) ) == \ - sqrt(6)*JzKetCoupled(0,0, (1,1,1), ((1,3,1),(1,2,0)) )/6 - \ - JzKetCoupled(1,0, (1,1,1), ((1,3,1),(1,2,1)) )/2 + \ - sqrt(15)*JzKetCoupled(1,0, (1,1,1), ((1,3,2),(1,2,1)) )/10 + \ - sqrt(3)*JzKetCoupled(2,0, (1,1,1), ((1,3,1),(1,2,2)) )/6 - \ - JzKetCoupled(2,0, (1,1,1), ((1,3,2),(1,2,2)) )/2 + \ - sqrt(10)*JzKetCoupled(3,0, (1,1,1), ((1,3,2),(1,2,3)) )/10 - assert couple(TensorProduct(JzKet(1,0), JzKet(1,0), JzKet(1,1)), ((1,3),(1,2)) ) == \ - -JzKetCoupled(1,1, (1,1,1), ((1,3,1),(1,2,1)) )/2 - \ - sqrt(15)*JzKetCoupled(1,1, (1,1,1), ((1,3,2),(1,2,1)) )/10 - \ - JzKetCoupled(2,1, (1,1,1), ((1,3,1),(1,2,2)) )/2 + \ - sqrt(3)*JzKetCoupled(2,1, (1,1,1), ((1,3,2),(1,2,2)) )/6 + \ - 2*sqrt(15)*JzKetCoupled(3,1, (1,1,1), ((1,3,2),(1,2,3)) )/15 - assert couple(TensorProduct(JzKet(1,0), JzKet(1,0), JzKet(1,0)), ((1,3),(1,2)) ) == \ - -sqrt(3)*JzKetCoupled(1,0, (1,1,1), ((1,3,0),(1,2,1)) )/3 - \ - 2*sqrt(15)*JzKetCoupled(1,0, (1,1,1), ((1,3,2),(1,2,1)) )/15 + \ - sqrt(10)*JzKetCoupled(3,0, (1,1,1), ((1,3,2),(1,2,3)) )/5 - assert couple(TensorProduct(JzKet(1,0), JzKet(1,0), JzKet(1,-1)), ((1,3),(1,2)) ) == \ - -JzKetCoupled(1,-1, (1,1,1), ((1,3,1),(1,2,1)) )/2 - \ - sqrt(15)*JzKetCoupled(1,-1, (1,1,1), ((1,3,2),(1,2,1)) )/10 + \ - JzKetCoupled(2,-1, (1,1,1), ((1,3,1),(1,2,2)) )/2 - \ - sqrt(3)*JzKetCoupled(2,-1, (1,1,1), ((1,3,2),(1,2,2)) )/6 + \ - 2*sqrt(15)*JzKetCoupled(3,-1, (1,1,1), ((1,3,2),(1,2,3)) )/15 - assert couple(TensorProduct(JzKet(1,0), JzKet(1,-1), JzKet(1,1)), ((1,3),(1,2)) ) == \ - -sqrt(6)*JzKetCoupled(0,0, (1,1,1), ((1,3,1),(1,2,0)) )/6 - \ - JzKetCoupled(1,0, (1,1,1), ((1,3,1),(1,2,1)) )/2 + \ - sqrt(15)*JzKetCoupled(1,0, (1,1,1), ((1,3,2),(1,2,1)) )/10 - \ - sqrt(3)*JzKetCoupled(2,0, (1,1,1), ((1,3,1),(1,2,2)) )/6 + \ - JzKetCoupled(2,0, (1,1,1), ((1,3,2),(1,2,2)) )/2 + \ - sqrt(10)*JzKetCoupled(3,0, (1,1,1), ((1,3,2),(1,2,3)) )/10 - assert couple(TensorProduct(JzKet(1,0), JzKet(1,-1), JzKet(1,0)), ((1,3),(1,2)) ) == \ - -sqrt(3)*JzKetCoupled(1,-1, (1,1,1), ((1,3,0),(1,2,1)) )/3 + \ - sqrt(15)*JzKetCoupled(1,-1, (1,1,1), ((1,3,2),(1,2,1)) )/15 + \ - sqrt(3)*JzKetCoupled(2,-1, (1,1,1), ((1,3,2),(1,2,2)) )/3 + \ - 2*sqrt(15)*JzKetCoupled(3,-1, (1,1,1), ((1,3,2),(1,2,3)) )/15 - assert couple(TensorProduct(JzKet(1,0), JzKet(1,-1), JzKet(1,-1)), ((1,3),(1,2)) ) == \ - sqrt(2)*JzKetCoupled(2,-2, (1,1,1), ((1,3,1),(1,2,2)) )/2 + \ - sqrt(6)*JzKetCoupled(2,-2, (1,1,1), ((1,3,2),(1,2,2)) )/6 + \ - sqrt(3)*JzKetCoupled(3,-2, (1,1,1), ((1,3,2),(1,2,3)) )/3 - assert couple(TensorProduct(JzKet(1,-1), JzKet(1,1), JzKet(1,1)), ((1,3),(1,2)) ) == \ - sqrt(3)*JzKetCoupled(1,1, (1,1,1), ((1,3,0),(1,2,1)) )/3 + \ - JzKetCoupled(1,1, (1,1,1), ((1,3,1),(1,2,1)) )/2 + \ - sqrt(15)*JzKetCoupled(1,1, (1,1,1), ((1,3,2),(1,2,1)) )/30 - \ - JzKetCoupled(2,1, (1,1,1), ((1,3,1),(1,2,2)) )/2 - \ - sqrt(3)*JzKetCoupled(2,1, (1,1,1), ((1,3,2),(1,2,2)) )/6 + \ - sqrt(15)*JzKetCoupled(3,1, (1,1,1), ((1,3,2),(1,2,3)) )/15 - assert couple(TensorProduct(JzKet(1,-1), JzKet(1,1), JzKet(1,0)), ((1,3),(1,2)) ) == \ - -sqrt(6)*JzKetCoupled(0,0, (1,1,1), ((1,3,1),(1,2,0)) )/6 + \ - JzKetCoupled(1,0, (1,1,1), ((1,3,1),(1,2,1)) )/2 + \ - sqrt(15)*JzKetCoupled(1,0, (1,1,1), ((1,3,2),(1,2,1)) )/10 - \ - sqrt(3)*JzKetCoupled(2,0, (1,1,1), ((1,3,1),(1,2,2)) )/6 - \ - JzKetCoupled(2,0, (1,1,1), ((1,3,2),(1,2,2)) )/2 + \ - sqrt(10)*JzKetCoupled(3,0, (1,1,1), ((1,3,2),(1,2,3)) )/10 - assert couple(TensorProduct(JzKet(1,-1), JzKet(1,1), JzKet(1,-1)), ((1,3),(1,2)) ) == \ - sqrt(15)*JzKetCoupled(1,-1, (1,1,1), ((1,3,2),(1,2,1)) )/5 - \ - sqrt(3)*JzKetCoupled(2,-1, (1,1,1), ((1,3,2),(1,2,2)) )/3 + \ - sqrt(15)*JzKetCoupled(3,-1, (1,1,1), ((1,3,2),(1,2,3)) )/15 - assert couple(TensorProduct(JzKet(1,-1), JzKet(1,0), JzKet(1,1)), ((1,3),(1,2)) ) == \ - sqrt(6)*JzKetCoupled(0,0, (1,1,1), ((1,3,1),(1,2,0)) )/6 + \ - sqrt(3)*JzKetCoupled(1,0, (1,1,1), ((1,3,0),(1,2,1)) )/3 - \ - sqrt(15)*JzKetCoupled(1,0, (1,1,1), ((1,3,2),(1,2,1)) )/15 - \ - sqrt(3)*JzKetCoupled(2,0, (1,1,1), ((1,3,1),(1,2,2)) )/3 + \ - sqrt(10)*JzKetCoupled(3,0, (1,1,1), ((1,3,2),(1,2,3)) )/10 - assert couple(TensorProduct(JzKet(1,-1), JzKet(1,0), JzKet(1,0)), ((1,3),(1,2)) ) == \ - JzKetCoupled(1,-1, (1,1,1), ((1,3,1),(1,2,1)) )/2 - \ - sqrt(15)*JzKetCoupled(1,-1, (1,1,1), ((1,3,2),(1,2,1)) )/10 - \ - JzKetCoupled(2,-1, (1,1,1), ((1,3,1),(1,2,2)) )/2 - \ - sqrt(3)*JzKetCoupled(2,-1, (1,1,1), ((1,3,2),(1,2,2)) )/6 + \ - 2*sqrt(15)*JzKetCoupled(3,-1, (1,1,1), ((1,3,2),(1,2,3)) )/15 - assert couple(TensorProduct(JzKet(1,-1), JzKet(1,0), JzKet(1,-1)), ((1,3),(1,2)) ) == \ - -sqrt(6)*JzKetCoupled(2,-2, (1,1,1), ((1,3,2),(1,2,2)) )/3 + \ - sqrt(3)*JzKetCoupled(3,-2, (1,1,1), ((1,3,2),(1,2,3)) )/3 - assert couple(TensorProduct(JzKet(1,-1), JzKet(1,-1), JzKet(1,1)), ((1,3),(1,2)) ) == \ - sqrt(3)*JzKetCoupled(1,-1, (1,1,1), ((1,3,0),(1,2,1)) )/3 - \ - JzKetCoupled(1,-1, (1,1,1), ((1,3,1),(1,2,1)) )/2 + \ - sqrt(15)*JzKetCoupled(1,-1, (1,1,1), ((1,3,2),(1,2,1)) )/30 - \ - JzKetCoupled(2,-1, (1,1,1), ((1,3,1),(1,2,2)) )/2 + \ - sqrt(3)*JzKetCoupled(2,-1, (1,1,1), ((1,3,2),(1,2,2)) )/6 + \ - sqrt(15)*JzKetCoupled(3,-1, (1,1,1), ((1,3,2),(1,2,3)) )/15 - assert couple(TensorProduct(JzKet(1,-1), JzKet(1,-1), JzKet(1,0)), ((1,3),(1,2)) ) == \ - -sqrt(2)*JzKetCoupled(2,-2, (1,1,1), ((1,3,1),(1,2,2)) )/2 + \ - sqrt(6)*JzKetCoupled(2,-2, (1,1,1), ((1,3,2),(1,2,2)) )/6 + \ - sqrt(3)*JzKetCoupled(3,-2, (1,1,1), ((1,3,2),(1,2,3)) )/3 - assert couple(TensorProduct(JzKet(1,-1), JzKet(1,-1), JzKet(1,-1)), ((1,3),(1,2)) ) == \ - JzKetCoupled(3,-3, (1,1,1), ((1,3,2),(1,2,3)) ) + assert couple(TensorProduct(JzKet(1, 1), JzKet(1, 1), JzKet(1, 1)), ((1, 3), (1, 2)) ) == \ + JzKetCoupled(3, 3, (1, 1, 1), ((1, 3, 2), (1, 2, 3)) ) + assert couple(TensorProduct(JzKet(1, 1), JzKet(1, 1), JzKet(1, 0)), ((1, 3), (1, 2)) ) == \ + sqrt(2)*JzKetCoupled(2, 2, (1, 1, 1), ((1, 3, 1), (1, 2, 2)) )/2 - \ + sqrt(6)*JzKetCoupled(2, 2, (1, 1, 1), ((1, 3, 2), (1, 2, 2)) )/6 + \ + sqrt(3)*JzKetCoupled(3, 2, (1, 1, 1), ((1, 3, 2), (1, 2, 3)) )/3 + assert couple(TensorProduct(JzKet(1, 1), JzKet(1, 1), JzKet(1, -1)), ((1, 3), (1, 2)) ) == \ + sqrt(3)*JzKetCoupled(1, 1, (1, 1, 1), ((1, 3, 0), (1, 2, 1)) )/3 - \ + JzKetCoupled(1, 1, (1, 1, 1), ((1, 3, 1), (1, 2, 1)) )/2 + \ + sqrt(15)*JzKetCoupled(1, 1, (1, 1, 1), ((1, 3, 2), (1, 2, 1)) )/30 + \ + JzKetCoupled(2, 1, (1, 1, 1), ((1, 3, 1), (1, 2, 2)) )/2 - \ + sqrt(3)*JzKetCoupled(2, 1, (1, 1, 1), ((1, 3, 2), (1, 2, 2)) )/6 + \ + sqrt(15)*JzKetCoupled(3, 1, (1, 1, 1), ((1, 3, 2), (1, 2, 3)) )/15 + assert couple(TensorProduct(JzKet(1, 1), JzKet(1, 0), JzKet(1, 1)), ((1, 3), (1, 2)) ) == \ + sqrt(6)*JzKetCoupled(2, 2, (1, 1, 1), ((1, 3, 2), (1, 2, 2)) )/3 + \ + sqrt(3)*JzKetCoupled(3, 2, (1, 1, 1), ((1, 3, 2), (1, 2, 3)) )/3 + assert couple(TensorProduct(JzKet(1, 1), JzKet(1, 0), JzKet(1, 0)), ((1, 3), (1, 2)) ) == \ + JzKetCoupled(1, 1, (1, 1, 1), ((1, 3, 1), (1, 2, 1)) )/2 - \ + sqrt(15)*JzKetCoupled(1, 1, (1, 1, 1), ((1, 3, 2), (1, 2, 1)) )/10 + \ + JzKetCoupled(2, 1, (1, 1, 1), ((1, 3, 1), (1, 2, 2)) )/2 + \ + sqrt(3)*JzKetCoupled(2, 1, (1, 1, 1), ((1, 3, 2), (1, 2, 2)) )/6 + \ + 2*sqrt(15)*JzKetCoupled(3, 1, (1, 1, 1), ((1, 3, 2), (1, 2, 3)) )/15 + assert couple(TensorProduct(JzKet(1, 1), JzKet(1, 0), JzKet(1, -1)), ((1, 3), (1, 2)) ) == \ + -sqrt(6)*JzKetCoupled(0, 0, (1, 1, 1), ((1, 3, 1), (1, 2, 0)) )/6 + \ + sqrt(3)*JzKetCoupled(1, 0, (1, 1, 1), ((1, 3, 0), (1, 2, 1)) )/3 - \ + sqrt(15)*JzKetCoupled(1, 0, (1, 1, 1), ((1, 3, 2), (1, 2, 1)) )/15 + \ + sqrt(3)*JzKetCoupled(2, 0, (1, 1, 1), ((1, 3, 1), (1, 2, 2)) )/3 + \ + sqrt(10)*JzKetCoupled(3, 0, (1, 1, 1), ((1, 3, 2), (1, 2, 3)) )/10 + assert couple(TensorProduct(JzKet(1, 1), JzKet(1, -1), JzKet(1, 1)), ((1, 3), (1, 2)) ) == \ + sqrt(15)*JzKetCoupled(1, 1, (1, 1, 1), ((1, 3, 2), (1, 2, 1)) )/5 + \ + sqrt(3)*JzKetCoupled(2, 1, (1, 1, 1), ((1, 3, 2), (1, 2, 2)) )/3 + \ + sqrt(15)*JzKetCoupled(3, 1, (1, 1, 1), ((1, 3, 2), (1, 2, 3)) )/15 + assert couple(TensorProduct(JzKet(1, 1), JzKet(1, -1), JzKet(1, 0)), ((1, 3), (1, 2)) ) == \ + sqrt(6)*JzKetCoupled(0, 0, (1, 1, 1), ((1, 3, 1), (1, 2, 0)) )/6 + \ + JzKetCoupled(1, 0, (1, 1, 1), ((1, 3, 1), (1, 2, 1)) )/2 + \ + sqrt(15)*JzKetCoupled(1, 0, (1, 1, 1), ((1, 3, 2), (1, 2, 1)) )/10 + \ + sqrt(3)*JzKetCoupled(2, 0, (1, 1, 1), ((1, 3, 1), (1, 2, 2)) )/6 + \ + JzKetCoupled(2, 0, (1, 1, 1), ((1, 3, 2), (1, 2, 2)) )/2 + \ + sqrt(10)*JzKetCoupled(3, 0, (1, 1, 1), ((1, 3, 2), (1, 2, 3)) )/10 + assert couple(TensorProduct(JzKet(1, 1), JzKet(1, -1), JzKet(1, -1)), ((1, 3), (1, 2)) ) == \ + sqrt(3)*JzKetCoupled(1, -1, (1, 1, 1), ((1, 3, 0), (1, 2, 1)) )/3 + \ + JzKetCoupled(1, -1, (1, 1, 1), ((1, 3, 1), (1, 2, 1)) )/2 + \ + sqrt(15)*JzKetCoupled(1, -1, (1, 1, 1), ((1, 3, 2), (1, 2, 1)) )/30 + \ + JzKetCoupled(2, -1, (1, 1, 1), ((1, 3, 1), (1, 2, 2)) )/2 + \ + sqrt(3)*JzKetCoupled(2, -1, (1, 1, 1), ((1, 3, 2), (1, 2, 2)) )/6 + \ + sqrt(15)*JzKetCoupled(3, -1, (1, 1, 1), ((1, 3, 2), (1, 2, 3)) )/15 + assert couple(TensorProduct(JzKet(1, 0), JzKet(1, 1), JzKet(1, 1)), ((1, 3), (1, 2)) ) == \ + -sqrt(2)*JzKetCoupled(2, 2, (1, 1, 1), ((1, 3, 1), (1, 2, 2)) )/2 - \ + sqrt(6)*JzKetCoupled(2, 2, (1, 1, 1), ((1, 3, 2), (1, 2, 2)) )/6 + \ + sqrt(3)*JzKetCoupled(3, 2, (1, 1, 1), ((1, 3, 2), (1, 2, 3)) )/3 + assert couple(TensorProduct(JzKet(1, 0), JzKet(1, 1), JzKet(1, 0)), ((1, 3), (1, 2)) ) == \ + -sqrt(3)*JzKetCoupled(1, 1, (1, 1, 1), ((1, 3, 0), (1, 2, 1)) )/3 + \ + sqrt(15)*JzKetCoupled(1, 1, (1, 1, 1), ((1, 3, 2), (1, 2, 1)) )/15 - \ + sqrt(3)*JzKetCoupled(2, 1, (1, 1, 1), ((1, 3, 2), (1, 2, 2)) )/3 + \ + 2*sqrt(15)*JzKetCoupled(3, 1, (1, 1, 1), ((1, 3, 2), (1, 2, 3)) )/15 + assert couple(TensorProduct(JzKet(1, 0), JzKet(1, 1), JzKet(1, -1)), ((1, 3), (1, 2)) ) == \ + sqrt(6)*JzKetCoupled(0, 0, (1, 1, 1), ((1, 3, 1), (1, 2, 0)) )/6 - \ + JzKetCoupled(1, 0, (1, 1, 1), ((1, 3, 1), (1, 2, 1)) )/2 + \ + sqrt(15)*JzKetCoupled(1, 0, (1, 1, 1), ((1, 3, 2), (1, 2, 1)) )/10 + \ + sqrt(3)*JzKetCoupled(2, 0, (1, 1, 1), ((1, 3, 1), (1, 2, 2)) )/6 - \ + JzKetCoupled(2, 0, (1, 1, 1), ((1, 3, 2), (1, 2, 2)) )/2 + \ + sqrt(10)*JzKetCoupled(3, 0, (1, 1, 1), ((1, 3, 2), (1, 2, 3)) )/10 + assert couple(TensorProduct(JzKet(1, 0), JzKet(1, 0), JzKet(1, 1)), ((1, 3), (1, 2)) ) == \ + -JzKetCoupled(1, 1, (1, 1, 1), ((1, 3, 1), (1, 2, 1)) )/2 - \ + sqrt(15)*JzKetCoupled(1, 1, (1, 1, 1), ((1, 3, 2), (1, 2, 1)) )/10 - \ + JzKetCoupled(2, 1, (1, 1, 1), ((1, 3, 1), (1, 2, 2)) )/2 + \ + sqrt(3)*JzKetCoupled(2, 1, (1, 1, 1), ((1, 3, 2), (1, 2, 2)) )/6 + \ + 2*sqrt(15)*JzKetCoupled(3, 1, (1, 1, 1), ((1, 3, 2), (1, 2, 3)) )/15 + assert couple(TensorProduct(JzKet(1, 0), JzKet(1, 0), JzKet(1, 0)), ((1, 3), (1, 2)) ) == \ + -sqrt(3)*JzKetCoupled(1, 0, (1, 1, 1), ((1, 3, 0), (1, 2, 1)) )/3 - \ + 2*sqrt(15)*JzKetCoupled(1, 0, (1, 1, 1), ((1, 3, 2), (1, 2, 1)) )/15 + \ + sqrt(10)*JzKetCoupled(3, 0, (1, 1, 1), ((1, 3, 2), (1, 2, 3)) )/5 + assert couple(TensorProduct(JzKet(1, 0), JzKet(1, 0), JzKet(1, -1)), ((1, 3), (1, 2)) ) == \ + -JzKetCoupled(1, -1, (1, 1, 1), ((1, 3, 1), (1, 2, 1)) )/2 - \ + sqrt(15)*JzKetCoupled(1, -1, (1, 1, 1), ((1, 3, 2), (1, 2, 1)) )/10 + \ + JzKetCoupled(2, -1, (1, 1, 1), ((1, 3, 1), (1, 2, 2)) )/2 - \ + sqrt(3)*JzKetCoupled(2, -1, (1, 1, 1), ((1, 3, 2), (1, 2, 2)) )/6 + \ + 2*sqrt(15)*JzKetCoupled(3, -1, (1, 1, 1), ((1, 3, 2), (1, 2, 3)) )/15 + assert couple(TensorProduct(JzKet(1, 0), JzKet(1, -1), JzKet(1, 1)), ((1, 3), (1, 2)) ) == \ + -sqrt(6)*JzKetCoupled(0, 0, (1, 1, 1), ((1, 3, 1), (1, 2, 0)) )/6 - \ + JzKetCoupled(1, 0, (1, 1, 1), ((1, 3, 1), (1, 2, 1)) )/2 + \ + sqrt(15)*JzKetCoupled(1, 0, (1, 1, 1), ((1, 3, 2), (1, 2, 1)) )/10 - \ + sqrt(3)*JzKetCoupled(2, 0, (1, 1, 1), ((1, 3, 1), (1, 2, 2)) )/6 + \ + JzKetCoupled(2, 0, (1, 1, 1), ((1, 3, 2), (1, 2, 2)) )/2 + \ + sqrt(10)*JzKetCoupled(3, 0, (1, 1, 1), ((1, 3, 2), (1, 2, 3)) )/10 + assert couple(TensorProduct(JzKet(1, 0), JzKet(1, -1), JzKet(1, 0)), ((1, 3), (1, 2)) ) == \ + -sqrt(3)*JzKetCoupled(1, -1, (1, 1, 1), ((1, 3, 0), (1, 2, 1)) )/3 + \ + sqrt(15)*JzKetCoupled(1, -1, (1, 1, 1), ((1, 3, 2), (1, 2, 1)) )/15 + \ + sqrt(3)*JzKetCoupled(2, -1, (1, 1, 1), ((1, 3, 2), (1, 2, 2)) )/3 + \ + 2*sqrt(15)*JzKetCoupled(3, -1, (1, 1, 1), ((1, 3, 2), (1, 2, 3)) )/15 + assert couple(TensorProduct(JzKet(1, 0), JzKet(1, -1), JzKet(1, -1)), ((1, 3), (1, 2)) ) == \ + sqrt(2)*JzKetCoupled(2, -2, (1, 1, 1), ((1, 3, 1), (1, 2, 2)) )/2 + \ + sqrt(6)*JzKetCoupled(2, -2, (1, 1, 1), ((1, 3, 2), (1, 2, 2)) )/6 + \ + sqrt(3)*JzKetCoupled(3, -2, (1, 1, 1), ((1, 3, 2), (1, 2, 3)) )/3 + assert couple(TensorProduct(JzKet(1, -1), JzKet(1, 1), JzKet(1, 1)), ((1, 3), (1, 2)) ) == \ + sqrt(3)*JzKetCoupled(1, 1, (1, 1, 1), ((1, 3, 0), (1, 2, 1)) )/3 + \ + JzKetCoupled(1, 1, (1, 1, 1), ((1, 3, 1), (1, 2, 1)) )/2 + \ + sqrt(15)*JzKetCoupled(1, 1, (1, 1, 1), ((1, 3, 2), (1, 2, 1)) )/30 - \ + JzKetCoupled(2, 1, (1, 1, 1), ((1, 3, 1), (1, 2, 2)) )/2 - \ + sqrt(3)*JzKetCoupled(2, 1, (1, 1, 1), ((1, 3, 2), (1, 2, 2)) )/6 + \ + sqrt(15)*JzKetCoupled(3, 1, (1, 1, 1), ((1, 3, 2), (1, 2, 3)) )/15 + assert couple(TensorProduct(JzKet(1, -1), JzKet(1, 1), JzKet(1, 0)), ((1, 3), (1, 2)) ) == \ + -sqrt(6)*JzKetCoupled(0, 0, (1, 1, 1), ((1, 3, 1), (1, 2, 0)) )/6 + \ + JzKetCoupled(1, 0, (1, 1, 1), ((1, 3, 1), (1, 2, 1)) )/2 + \ + sqrt(15)*JzKetCoupled(1, 0, (1, 1, 1), ((1, 3, 2), (1, 2, 1)) )/10 - \ + sqrt(3)*JzKetCoupled(2, 0, (1, 1, 1), ((1, 3, 1), (1, 2, 2)) )/6 - \ + JzKetCoupled(2, 0, (1, 1, 1), ((1, 3, 2), (1, 2, 2)) )/2 + \ + sqrt(10)*JzKetCoupled(3, 0, (1, 1, 1), ((1, 3, 2), (1, 2, 3)) )/10 + assert couple(TensorProduct(JzKet(1, -1), JzKet(1, 1), JzKet(1, -1)), ((1, 3), (1, 2)) ) == \ + sqrt(15)*JzKetCoupled(1, -1, (1, 1, 1), ((1, 3, 2), (1, 2, 1)) )/5 - \ + sqrt(3)*JzKetCoupled(2, -1, (1, 1, 1), ((1, 3, 2), (1, 2, 2)) )/3 + \ + sqrt(15)*JzKetCoupled(3, -1, (1, 1, 1), ((1, 3, 2), (1, 2, 3)) )/15 + assert couple(TensorProduct(JzKet(1, -1), JzKet(1, 0), JzKet(1, 1)), ((1, 3), (1, 2)) ) == \ + sqrt(6)*JzKetCoupled(0, 0, (1, 1, 1), ((1, 3, 1), (1, 2, 0)) )/6 + \ + sqrt(3)*JzKetCoupled(1, 0, (1, 1, 1), ((1, 3, 0), (1, 2, 1)) )/3 - \ + sqrt(15)*JzKetCoupled(1, 0, (1, 1, 1), ((1, 3, 2), (1, 2, 1)) )/15 - \ + sqrt(3)*JzKetCoupled(2, 0, (1, 1, 1), ((1, 3, 1), (1, 2, 2)) )/3 + \ + sqrt(10)*JzKetCoupled(3, 0, (1, 1, 1), ((1, 3, 2), (1, 2, 3)) )/10 + assert couple(TensorProduct(JzKet(1, -1), JzKet(1, 0), JzKet(1, 0)), ((1, 3), (1, 2)) ) == \ + JzKetCoupled(1, -1, (1, 1, 1), ((1, 3, 1), (1, 2, 1)) )/2 - \ + sqrt(15)*JzKetCoupled(1, -1, (1, 1, 1), ((1, 3, 2), (1, 2, 1)) )/10 - \ + JzKetCoupled(2, -1, (1, 1, 1), ((1, 3, 1), (1, 2, 2)) )/2 - \ + sqrt(3)*JzKetCoupled(2, -1, (1, 1, 1), ((1, 3, 2), (1, 2, 2)) )/6 + \ + 2*sqrt(15)*JzKetCoupled(3, -1, (1, 1, 1), ((1, 3, 2), (1, 2, 3)) )/15 + assert couple(TensorProduct(JzKet(1, -1), JzKet(1, 0), JzKet(1, -1)), ((1, 3), (1, 2)) ) == \ + -sqrt(6)*JzKetCoupled(2, -2, (1, 1, 1), ((1, 3, 2), (1, 2, 2)) )/3 + \ + sqrt(3)*JzKetCoupled(3, -2, (1, 1, 1), ((1, 3, 2), (1, 2, 3)) )/3 + assert couple(TensorProduct(JzKet(1, -1), JzKet(1, -1), JzKet(1, 1)), ((1, 3), (1, 2)) ) == \ + sqrt(3)*JzKetCoupled(1, -1, (1, 1, 1), ((1, 3, 0), (1, 2, 1)) )/3 - \ + JzKetCoupled(1, -1, (1, 1, 1), ((1, 3, 1), (1, 2, 1)) )/2 + \ + sqrt(15)*JzKetCoupled(1, -1, (1, 1, 1), ((1, 3, 2), (1, 2, 1)) )/30 - \ + JzKetCoupled(2, -1, (1, 1, 1), ((1, 3, 1), (1, 2, 2)) )/2 + \ + sqrt(3)*JzKetCoupled(2, -1, (1, 1, 1), ((1, 3, 2), (1, 2, 2)) )/6 + \ + sqrt(15)*JzKetCoupled(3, -1, (1, 1, 1), ((1, 3, 2), (1, 2, 3)) )/15 + assert couple(TensorProduct(JzKet(1, -1), JzKet(1, -1), JzKet(1, 0)), ((1, 3), (1, 2)) ) == \ + -sqrt(2)*JzKetCoupled(2, -2, (1, 1, 1), ((1, 3, 1), (1, 2, 2)) )/2 + \ + sqrt(6)*JzKetCoupled(2, -2, (1, 1, 1), ((1, 3, 2), (1, 2, 2)) )/6 + \ + sqrt(3)*JzKetCoupled(3, -2, (1, 1, 1), ((1, 3, 2), (1, 2, 3)) )/3 + assert couple(TensorProduct(JzKet(1, -1), JzKet(1, -1), JzKet(1, -1)), ((1, 3), (1, 2)) ) == \ + JzKetCoupled(3, -3, (1, 1, 1), ((1, 3, 2), (1, 2, 3)) ) # j1=1/2, j2=1/2, j3=3/2 - assert couple(TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(S(3)/2,S(3)/2)), ((1,3),(1,2)) ) == \ - JzKetCoupled(S(5)/2,S(5)/2, (S(1)/2,S(1)/2,S(3)/2), ((1,3,2),(1,2,S(5)/2)) ) - assert couple(TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(S(3)/2,S(1)/2)), ((1,3),(1,2)) ) == \ - JzKetCoupled(S(3)/2,S(3)/2, (S(1)/2,S(1)/2,S(3)/2), ((1,3,1),(1,2,S(3)/2)) )/2 - \ - sqrt(15)*JzKetCoupled(S(3)/2,S(3)/2, (S(1)/2,S(1)/2,S(3)/2), ((1,3,2),(1,2,S(3)/2)) )/10 + \ - sqrt(15)*JzKetCoupled(S(5)/2,S(3)/2, (S(1)/2,S(1)/2,S(3)/2), ((1,3,2),(1,2,S(5)/2)) )/5 - assert couple(TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(S(3)/2,S(-1)/2)), ((1,3),(1,2)) ) == \ - -sqrt(6)*JzKetCoupled(S(1)/2,S(1)/2, (S(1)/2,S(1)/2,S(3)/2), ((1,3,1),(1,2,S(1)/2)) )/6 + \ - sqrt(3)*JzKetCoupled(S(3)/2,S(1)/2, (S(1)/2,S(1)/2,S(3)/2), ((1,3,1),(1,2,S(3)/2)) )/3 - \ - sqrt(5)*JzKetCoupled(S(3)/2,S(1)/2, (S(1)/2,S(1)/2,S(3)/2), ((1,3,2),(1,2,S(3)/2)) )/5 + \ - sqrt(30)*JzKetCoupled(S(5)/2,S(1)/2, (S(1)/2,S(1)/2,S(3)/2), ((1,3,2),(1,2,S(5)/2)) )/10 - assert couple(TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(S(3)/2,S(-3)/2)), ((1,3),(1,2)) ) == \ - -sqrt(2)*JzKetCoupled(S(1)/2,-S(1)/2, (S(1)/2,S(1)/2,S(3)/2), ((1,3,1),(1,2,S(1)/2)) )/2 + \ - JzKetCoupled(S(3)/2,-S(1)/2, (S(1)/2,S(1)/2,S(3)/2), ((1,3,1),(1,2,S(3)/2)) )/2 - \ - sqrt(15)*JzKetCoupled(S(3)/2,-S(1)/2, (S(1)/2,S(1)/2,S(3)/2), ((1,3,2),(1,2,S(3)/2)) )/10 + \ - sqrt(10)*JzKetCoupled(S(5)/2,-S(1)/2, (S(1)/2,S(1)/2,S(3)/2), ((1,3,2),(1,2,S(5)/2)) )/10 - assert couple(TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(S(3)/2,S(3)/2)), ((1,3),(1,2)) ) == \ - 2*sqrt(5)*JzKetCoupled(S(3)/2,S(3)/2, (S(1)/2,S(1)/2,S(3)/2), ((1,3,2),(1,2,S(3)/2)) )/5 + \ - sqrt(5)*JzKetCoupled(S(5)/2,S(3)/2, (S(1)/2,S(1)/2,S(3)/2), ((1,3,2),(1,2,S(5)/2)) )/5 - assert couple(TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(S(3)/2,S(1)/2)), ((1,3),(1,2)) ) == \ - sqrt(6)*JzKetCoupled(S(1)/2,S(1)/2, (S(1)/2,S(1)/2,S(3)/2), ((1,3,1),(1,2,S(1)/2)) )/6 + \ - sqrt(3)*JzKetCoupled(S(3)/2,S(1)/2, (S(1)/2,S(1)/2,S(3)/2), ((1,3,1),(1,2,S(3)/2)) )/6 + \ - 3*sqrt(5)*JzKetCoupled(S(3)/2,S(1)/2, (S(1)/2,S(1)/2,S(3)/2), ((1,3,2),(1,2,S(3)/2)) )/10 + \ - sqrt(30)*JzKetCoupled(S(5)/2,S(1)/2, (S(1)/2,S(1)/2,S(3)/2), ((1,3,2),(1,2,S(5)/2)) )/10 - assert couple(TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(S(3)/2,S(-1)/2)), ((1,3),(1,2)) ) == \ - sqrt(6)*JzKetCoupled(S(1)/2,-S(1)/2, (S(1)/2,S(1)/2,S(3)/2), ((1,3,1),(1,2,S(1)/2)) )/6 + \ - sqrt(3)*JzKetCoupled(S(3)/2,-S(1)/2, (S(1)/2,S(1)/2,S(3)/2), ((1,3,1),(1,2,S(3)/2)) )/3 + \ - sqrt(5)*JzKetCoupled(S(3)/2,-S(1)/2, (S(1)/2,S(1)/2,S(3)/2), ((1,3,2),(1,2,S(3)/2)) )/5 + \ - sqrt(30)*JzKetCoupled(S(5)/2,-S(1)/2, (S(1)/2,S(1)/2,S(3)/2), ((1,3,2),(1,2,S(5)/2)) )/10 - assert couple(TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(S(3)/2,S(-3)/2)), ((1,3),(1,2)) ) == \ - sqrt(3)*JzKetCoupled(S(3)/2,-S(3)/2, (S(1)/2,S(1)/2,S(3)/2), ((1,3,1),(1,2,S(3)/2)) )/2 + \ - sqrt(5)*JzKetCoupled(S(3)/2,-S(3)/2, (S(1)/2,S(1)/2,S(3)/2), ((1,3,2),(1,2,S(3)/2)) )/10 + \ - sqrt(5)*JzKetCoupled(S(5)/2,-S(3)/2, (S(1)/2,S(1)/2,S(3)/2), ((1,3,2),(1,2,S(5)/2)) )/5 - assert couple(TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(1)/2), JzKet(S(3)/2,S(3)/2)), ((1,3),(1,2)) ) == \ - -sqrt(3)*JzKetCoupled(S(3)/2,S(3)/2, (S(1)/2,S(1)/2,S(3)/2), ((1,3,1),(1,2,S(3)/2)) )/2 - \ - sqrt(5)*JzKetCoupled(S(3)/2,S(3)/2, (S(1)/2,S(1)/2,S(3)/2), ((1,3,2),(1,2,S(3)/2)) )/10 + \ - sqrt(5)*JzKetCoupled(S(5)/2,S(3)/2, (S(1)/2,S(1)/2,S(3)/2), ((1,3,2),(1,2,S(5)/2)) )/5 - assert couple(TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(1)/2), JzKet(S(3)/2,S(1)/2)), ((1,3),(1,2)) ) == \ - sqrt(6)*JzKetCoupled(S(1)/2,S(1)/2, (S(1)/2,S(1)/2,S(3)/2), ((1,3,1),(1,2,S(1)/2)) )/6 - \ - sqrt(3)*JzKetCoupled(S(3)/2,S(1)/2, (S(1)/2,S(1)/2,S(3)/2), ((1,3,1),(1,2,S(3)/2)) )/3 - \ - sqrt(5)*JzKetCoupled(S(3)/2,S(1)/2, (S(1)/2,S(1)/2,S(3)/2), ((1,3,2),(1,2,S(3)/2)) )/5 + \ - sqrt(30)*JzKetCoupled(S(5)/2,S(1)/2, (S(1)/2,S(1)/2,S(3)/2), ((1,3,2),(1,2,S(5)/2)) )/10 - assert couple(TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(1)/2), JzKet(S(3)/2,S(-1)/2)), ((1,3),(1,2)) ) == \ - sqrt(6)*JzKetCoupled(S(1)/2,-S(1)/2, (S(1)/2,S(1)/2,S(3)/2), ((1,3,1),(1,2,S(1)/2)) )/6 - \ - sqrt(3)*JzKetCoupled(S(3)/2,-S(1)/2, (S(1)/2,S(1)/2,S(3)/2), ((1,3,1),(1,2,S(3)/2)) )/6 - \ - 3*sqrt(5)*JzKetCoupled(S(3)/2,-S(1)/2, (S(1)/2,S(1)/2,S(3)/2), ((1,3,2),(1,2,S(3)/2)) )/10 + \ - sqrt(30)*JzKetCoupled(S(5)/2,-S(1)/2, (S(1)/2,S(1)/2,S(3)/2), ((1,3,2),(1,2,S(5)/2)) )/10 - assert couple(TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(1)/2), JzKet(S(3)/2,S(-3)/2)), ((1,3),(1,2)) ) == \ - -2*sqrt(5)*JzKetCoupled(S(3)/2,-S(3)/2, (S(1)/2,S(1)/2,S(3)/2), ((1,3,2),(1,2,S(3)/2)) )/5 + \ - sqrt(5)*JzKetCoupled(S(5)/2,-S(3)/2, (S(1)/2,S(1)/2,S(3)/2), ((1,3,2),(1,2,S(5)/2)) )/5 - assert couple(TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(S(3)/2,S(3)/2)), ((1,3),(1,2)) ) == \ - -sqrt(2)*JzKetCoupled(S(1)/2,S(1)/2, (S(1)/2,S(1)/2,S(3)/2), ((1,3,1),(1,2,S(1)/2)) )/2 - \ - JzKetCoupled(S(3)/2,S(1)/2, (S(1)/2,S(1)/2,S(3)/2), ((1,3,1),(1,2,S(3)/2)) )/2 + \ - sqrt(15)*JzKetCoupled(S(3)/2,S(1)/2, (S(1)/2,S(1)/2,S(3)/2), ((1,3,2),(1,2,S(3)/2)) )/10 + \ - sqrt(10)*JzKetCoupled(S(5)/2,S(1)/2, (S(1)/2,S(1)/2,S(3)/2), ((1,3,2),(1,2,S(5)/2)) )/10 - assert couple(TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(S(3)/2,S(1)/2)), ((1,3),(1,2)) ) == \ - -sqrt(6)*JzKetCoupled(S(1)/2,-S(1)/2, (S(1)/2,S(1)/2,S(3)/2), ((1,3,1),(1,2,S(1)/2)) )/6 - \ - sqrt(3)*JzKetCoupled(S(3)/2,-S(1)/2, (S(1)/2,S(1)/2,S(3)/2), ((1,3,1),(1,2,S(3)/2)) )/3 + \ - sqrt(5)*JzKetCoupled(S(3)/2,-S(1)/2, (S(1)/2,S(1)/2,S(3)/2), ((1,3,2),(1,2,S(3)/2)) )/5 + \ - sqrt(30)*JzKetCoupled(S(5)/2,-S(1)/2, (S(1)/2,S(1)/2,S(3)/2), ((1,3,2),(1,2,S(5)/2)) )/10 - assert couple(TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(S(3)/2,S(-1)/2)), ((1,3),(1,2)) ) == \ - -JzKetCoupled(S(3)/2,-S(3)/2, (S(1)/2,S(1)/2,S(3)/2), ((1,3,1),(1,2,S(3)/2)) )/2 + \ - sqrt(15)*JzKetCoupled(S(3)/2,-S(3)/2, (S(1)/2,S(1)/2,S(3)/2), ((1,3,2),(1,2,S(3)/2)) )/10 + \ - sqrt(15)*JzKetCoupled(S(5)/2,-S(3)/2, (S(1)/2,S(1)/2,S(3)/2), ((1,3,2),(1,2,S(5)/2)) )/5 - assert couple(TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(S(3)/2,S(-3)/2)), ((1,3),(1,2)) ) == \ - JzKetCoupled(S(5)/2,-S(5)/2, (S(1)/2,S(1)/2,S(3)/2), ((1,3,2),(1,2,S(5)/2)) ) + assert couple(TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(S(3)/2, S(3)/2)), ((1, 3), (1, 2)) ) == \ + JzKetCoupled(S(5)/2, S( + 5)/2, (S(1)/2, S(1)/2, S(3)/2), ((1, 3, 2), (1, 2, S(5)/2)) ) + assert couple(TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(S(3)/2, S(1)/2)), ((1, 3), (1, 2)) ) == \ + JzKetCoupled(S(3)/2, S(3)/2, (S(1)/2, S(1)/2, S(3)/2), ((1, 3, 1), (1, 2, S(3)/2)) )/2 - \ + sqrt(15)*JzKetCoupled(S(3)/2, S(3)/2, (S(1)/2, S(1)/2, S(3)/2), ((1, 3, 2), (1, 2, S(3)/2)) )/10 + \ + sqrt(15)*JzKetCoupled(S(5)/2, S(3)/2, (S(1)/2, S(1)/2, S(3) + /2), ((1, 3, 2), (1, 2, S(5)/2)) )/5 + assert couple(TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(S(3)/2, S(-1)/2)), ((1, 3), (1, 2)) ) == \ + -sqrt(6)*JzKetCoupled(S(1)/2, S(1)/2, (S(1)/2, S(1)/2, S(3)/2), ((1, 3, 1), (1, 2, S(1)/2)) )/6 + \ + sqrt(3)*JzKetCoupled(S(3)/2, S(1)/2, (S(1)/2, S(1)/2, S(3)/2), ((1, 3, 1), (1, 2, S(3)/2)) )/3 - \ + sqrt(5)*JzKetCoupled(S(3)/2, S(1)/2, (S(1)/2, S(1)/2, S(3)/2), ((1, 3, 2), (1, 2, S(3)/2)) )/5 + \ + sqrt(30)*JzKetCoupled(S(5)/2, S( + 1)/2, (S(1)/2, S(1)/2, S(3)/2), ((1, 3, 2), (1, 2, S(5)/2)) )/10 + assert couple(TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(S(3)/2, S(-3)/2)), ((1, 3), (1, 2)) ) == \ + -sqrt(2)*JzKetCoupled(S(1)/2, -S(1)/2, (S(1)/2, S(1)/2, S(3)/2), ((1, 3, 1), (1, 2, S(1)/2)) )/2 + \ + JzKetCoupled(S(3)/2, -S(1)/2, (S(1)/2, S(1)/2, S(3)/2), ((1, 3, 1), (1, 2, S(3)/2)) )/2 - \ + sqrt(15)*JzKetCoupled(S(3)/2, -S(1)/2, (S(1)/2, S(1)/2, S(3)/2), ((1, 3, 2), (1, 2, S(3)/2)) )/10 + \ + sqrt(10)*JzKetCoupled(S(5)/2, -S( + 1)/2, (S(1)/2, S(1)/2, S(3)/2), ((1, 3, 2), (1, 2, S(5)/2)) )/10 + assert couple(TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(S(3)/2, S(3)/2)), ((1, 3), (1, 2)) ) == \ + 2*sqrt(5)*JzKetCoupled(S(3)/2, S(3)/2, (S(1)/2, S(1)/2, S(3)/2), ((1, 3, 2), (1, 2, S(3)/2)) )/5 + \ + sqrt(5)*JzKetCoupled(S(5)/2, S(3)/2, (S(1)/2, S(1)/2, S(3)/ + 2), ((1, 3, 2), (1, 2, S(5)/2)) )/5 + assert couple(TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(S(3)/2, S(1)/2)), ((1, 3), (1, 2)) ) == \ + sqrt(6)*JzKetCoupled(S(1)/2, S(1)/2, (S(1)/2, S(1)/2, S(3)/2), ((1, 3, 1), (1, 2, S(1)/2)) )/6 + \ + sqrt(3)*JzKetCoupled(S(3)/2, S(1)/2, (S(1)/2, S(1)/2, S(3)/2), ((1, 3, 1), (1, 2, S(3)/2)) )/6 + \ + 3*sqrt(5)*JzKetCoupled(S(3)/2, S(1)/2, (S(1)/2, S(1)/2, S(3)/2), ((1, 3, 2), (1, 2, S(3)/2)) )/10 + \ + sqrt(30)*JzKetCoupled(S(5)/2, S( + 1)/2, (S(1)/2, S(1)/2, S(3)/2), ((1, 3, 2), (1, 2, S(5)/2)) )/10 + assert couple(TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(S(3)/2, S(-1)/2)), ((1, 3), (1, 2)) ) == \ + sqrt(6)*JzKetCoupled(S(1)/2, -S(1)/2, (S(1)/2, S(1)/2, S(3)/2), ((1, 3, 1), (1, 2, S(1)/2)) )/6 + \ + sqrt(3)*JzKetCoupled(S(3)/2, -S(1)/2, (S(1)/2, S(1)/2, S(3)/2), ((1, 3, 1), (1, 2, S(3)/2)) )/3 + \ + sqrt(5)*JzKetCoupled(S(3)/2, -S(1)/2, (S(1)/2, S(1)/2, S(3)/2), ((1, 3, 2), (1, 2, S(3)/2)) )/5 + \ + sqrt(30)*JzKetCoupled(S(5)/2, -S( + 1)/2, (S(1)/2, S(1)/2, S(3)/2), ((1, 3, 2), (1, 2, S(5)/2)) )/10 + assert couple(TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(S(3)/2, S(-3)/2)), ((1, 3), (1, 2)) ) == \ + sqrt(3)*JzKetCoupled(S(3)/2, -S(3)/2, (S(1)/2, S(1)/2, S(3)/2), ((1, 3, 1), (1, 2, S(3)/2)) )/2 + \ + sqrt(5)*JzKetCoupled(S(3)/2, -S(3)/2, (S(1)/2, S(1)/2, S(3)/2), ((1, 3, 2), (1, 2, S(3)/2)) )/10 + \ + sqrt(5)*JzKetCoupled(S(5)/2, -S(3)/2, (S(1)/2, S(1)/2, S(3) + /2), ((1, 3, 2), (1, 2, S(5)/2)) )/5 + assert couple(TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(1)/2), JzKet(S(3)/2, S(3)/2)), ((1, 3), (1, 2)) ) == \ + -sqrt(3)*JzKetCoupled(S(3)/2, S(3)/2, (S(1)/2, S(1)/2, S(3)/2), ((1, 3, 1), (1, 2, S(3)/2)) )/2 - \ + sqrt(5)*JzKetCoupled(S(3)/2, S(3)/2, (S(1)/2, S(1)/2, S(3)/2), ((1, 3, 2), (1, 2, S(3)/2)) )/10 + \ + sqrt(5)*JzKetCoupled(S(5)/2, S(3)/2, (S(1)/2, S(1)/2, S(3)/ + 2), ((1, 3, 2), (1, 2, S(5)/2)) )/5 + assert couple(TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(1)/2), JzKet(S(3)/2, S(1)/2)), ((1, 3), (1, 2)) ) == \ + sqrt(6)*JzKetCoupled(S(1)/2, S(1)/2, (S(1)/2, S(1)/2, S(3)/2), ((1, 3, 1), (1, 2, S(1)/2)) )/6 - \ + sqrt(3)*JzKetCoupled(S(3)/2, S(1)/2, (S(1)/2, S(1)/2, S(3)/2), ((1, 3, 1), (1, 2, S(3)/2)) )/3 - \ + sqrt(5)*JzKetCoupled(S(3)/2, S(1)/2, (S(1)/2, S(1)/2, S(3)/2), ((1, 3, 2), (1, 2, S(3)/2)) )/5 + \ + sqrt(30)*JzKetCoupled(S(5)/2, S( + 1)/2, (S(1)/2, S(1)/2, S(3)/2), ((1, 3, 2), (1, 2, S(5)/2)) )/10 + assert couple(TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(1)/2), JzKet(S(3)/2, S(-1)/2)), ((1, 3), (1, 2)) ) == \ + sqrt(6)*JzKetCoupled(S(1)/2, -S(1)/2, (S(1)/2, S(1)/2, S(3)/2), ((1, 3, 1), (1, 2, S(1)/2)) )/6 - \ + sqrt(3)*JzKetCoupled(S(3)/2, -S(1)/2, (S(1)/2, S(1)/2, S(3)/2), ((1, 3, 1), (1, 2, S(3)/2)) )/6 - \ + 3*sqrt(5)*JzKetCoupled(S(3)/2, -S(1)/2, (S(1)/2, S(1)/2, S(3)/2), ((1, 3, 2), (1, 2, S(3)/2)) )/10 + \ + sqrt(30)*JzKetCoupled(S(5)/2, -S( + 1)/2, (S(1)/2, S(1)/2, S(3)/2), ((1, 3, 2), (1, 2, S(5)/2)) )/10 + assert couple(TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(1)/2), JzKet(S(3)/2, S(-3)/2)), ((1, 3), (1, 2)) ) == \ + -2*sqrt(5)*JzKetCoupled(S(3)/2, -S(3)/2, (S(1)/2, S(1)/2, S(3)/2), ((1, 3, 2), (1, 2, S(3)/2)) )/5 + \ + sqrt(5)*JzKetCoupled(S(5)/2, -S(3)/2, (S(1)/2, S(1)/2, S(3) + /2), ((1, 3, 2), (1, 2, S(5)/2)) )/5 + assert couple(TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(S(3)/2, S(3)/2)), ((1, 3), (1, 2)) ) == \ + -sqrt(2)*JzKetCoupled(S(1)/2, S(1)/2, (S(1)/2, S(1)/2, S(3)/2), ((1, 3, 1), (1, 2, S(1)/2)) )/2 - \ + JzKetCoupled(S(3)/2, S(1)/2, (S(1)/2, S(1)/2, S(3)/2), ((1, 3, 1), (1, 2, S(3)/2)) )/2 + \ + sqrt(15)*JzKetCoupled(S(3)/2, S(1)/2, (S(1)/2, S(1)/2, S(3)/2), ((1, 3, 2), (1, 2, S(3)/2)) )/10 + \ + sqrt(10)*JzKetCoupled(S(5)/2, S( + 1)/2, (S(1)/2, S(1)/2, S(3)/2), ((1, 3, 2), (1, 2, S(5)/2)) )/10 + assert couple(TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(S(3)/2, S(1)/2)), ((1, 3), (1, 2)) ) == \ + -sqrt(6)*JzKetCoupled(S(1)/2, -S(1)/2, (S(1)/2, S(1)/2, S(3)/2), ((1, 3, 1), (1, 2, S(1)/2)) )/6 - \ + sqrt(3)*JzKetCoupled(S(3)/2, -S(1)/2, (S(1)/2, S(1)/2, S(3)/2), ((1, 3, 1), (1, 2, S(3)/2)) )/3 + \ + sqrt(5)*JzKetCoupled(S(3)/2, -S(1)/2, (S(1)/2, S(1)/2, S(3)/2), ((1, 3, 2), (1, 2, S(3)/2)) )/5 + \ + sqrt(30)*JzKetCoupled(S(5)/2, -S( + 1)/2, (S(1)/2, S(1)/2, S(3)/2), ((1, 3, 2), (1, 2, S(5)/2)) )/10 + assert couple(TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(S(3)/2, S(-1)/2)), ((1, 3), (1, 2)) ) == \ + -JzKetCoupled(S(3)/2, -S(3)/2, (S(1)/2, S(1)/2, S(3)/2), ((1, 3, 1), (1, 2, S(3)/2)) )/2 + \ + sqrt(15)*JzKetCoupled(S(3)/2, -S(3)/2, (S(1)/2, S(1)/2, S(3)/2), ((1, 3, 2), (1, 2, S(3)/2)) )/10 + \ + sqrt(15)*JzKetCoupled(S(5)/2, -S(3)/2, (S(1)/2, S(1)/2, S( + 3)/2), ((1, 3, 2), (1, 2, S(5)/2)) )/5 + assert couple(TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(S(3)/2, S(-3)/2)), ((1, 3), (1, 2)) ) == \ + JzKetCoupled(S(5)/2, -S( + 5)/2, (S(1)/2, S(1)/2, S(3)/2), ((1, 3, 2), (1, 2, S(5)/2)) ) + def test_couple_4_states_numerical(): # Default coupling # j1=1/2, j2=1/2, j3=1/2, j4=1/2 - assert couple(TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2))) == \ - JzKetCoupled(2,2, (S(1)/2,S(1)/2,S(1)/2,S(1)/2), ((1,2,1),(1,3,S(3)/2),(1,4,2)) ) - assert couple(TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(-1)/2))) == \ - sqrt(3)*JzKetCoupled(1,1, (S(1)/2,S(1)/2,S(1)/2,S(1)/2), ((1,2,1),(1,3,S(3)/2),(1,4,1)) )/2 + \ - JzKetCoupled(2,1, (S(1)/2,S(1)/2,S(1)/2,S(1)/2), ((1,2,1),(1,3,S(3)/2),(1,4,2)) )/2 - assert couple(TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(1)/2))) == \ - sqrt(6)*JzKetCoupled(1,1, (S(1)/2,S(1)/2,S(1)/2,S(1)/2), ((1,2,1),(1,3,S(1)/2),(1,4,1)) )/3 - \ - sqrt(3)*JzKetCoupled(1,1, (S(1)/2,S(1)/2,S(1)/2,S(1)/2), ((1,2,1),(1,3,S(3)/2),(1,4,1)) )/6 + \ - JzKetCoupled(2,1, (S(1)/2,S(1)/2,S(1)/2,S(1)/2), ((1,2,1),(1,3,S(3)/2),(1,4,2)) )/2 - assert couple(TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(-1)/2))) == \ - sqrt(3)*JzKetCoupled(0,0, (S(1)/2,S(1)/2,S(1)/2,S(1)/2), ((1,2,1),(1,3,S(1)/2),(1,4,0)) )/3 + \ - sqrt(3)*JzKetCoupled(1,0, (S(1)/2,S(1)/2,S(1)/2,S(1)/2), ((1,2,1),(1,3,S(1)/2),(1,4,1)) )/3 + \ - sqrt(6)*JzKetCoupled(1,0, (S(1)/2,S(1)/2,S(1)/2,S(1)/2), ((1,2,1),(1,3,S(3)/2),(1,4,1)) )/6 + \ - sqrt(6)*JzKetCoupled(2,0, (S(1)/2,S(1)/2,S(1)/2,S(1)/2), ((1,2,1),(1,3,S(3)/2),(1,4,2)) )/6 - assert couple(TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2))) == \ - sqrt(2)*JzKetCoupled(1,1, (S(1)/2,S(1)/2,S(1)/2,S(1)/2), ((1,2,0),(1,3,S(1)/2),(1,4,1)) )/2 - \ - sqrt(6)*JzKetCoupled(1,1, (S(1)/2,S(1)/2,S(1)/2,S(1)/2), ((1,2,1),(1,3,S(1)/2),(1,4,1)) )/6 - \ - sqrt(3)*JzKetCoupled(1,1, (S(1)/2,S(1)/2,S(1)/2,S(1)/2), ((1,2,1),(1,3,S(3)/2),(1,4,1)) )/6 + \ - JzKetCoupled(2,1, (S(1)/2,S(1)/2,S(1)/2,S(1)/2), ((1,2,1),(1,3,S(3)/2),(1,4,2)) )/2 + assert couple(TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2))) == \ + JzKetCoupled(2, 2, (S(1)/2, S( + 1)/2, S(1)/2, S(1)/2), ((1, 2, 1), (1, 3, S(3)/2), (1, 4, 2)) ) + assert couple(TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(-1)/2))) == \ + sqrt(3)*JzKetCoupled(1, 1, (S(1)/2, S(1)/2, S(1)/2, S(1)/2), ((1, 2, 1), (1, 3, S(3)/2), (1, 4, 1)) )/2 + \ + JzKetCoupled(2, 1, (S(1)/2, S( + 1)/2, S(1)/2, S(1)/2), ((1, 2, 1), (1, 3, S(3)/2), (1, 4, 2)) )/2 + assert couple(TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(1)/2))) == \ + sqrt(6)*JzKetCoupled(1, 1, (S(1)/2, S(1)/2, S(1)/2, S(1)/2), ((1, 2, 1), (1, 3, S(1)/2), (1, 4, 1)) )/3 - \ + sqrt(3)*JzKetCoupled(1, 1, (S(1)/2, S(1)/2, S(1)/2, S(1)/2), ((1, 2, 1), (1, 3, S(3)/2), (1, 4, 1)) )/6 + \ + JzKetCoupled(2, 1, (S(1)/2, S( + 1)/2, S(1)/2, S(1)/2), ((1, 2, 1), (1, 3, S(3)/2), (1, 4, 2)) )/2 + assert couple(TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(-1)/2))) == \ + sqrt(3)*JzKetCoupled(0, 0, (S(1)/2, S(1)/2, S(1)/2, S(1)/2), ((1, 2, 1), (1, 3, S(1)/2), (1, 4, 0)) )/3 + \ + sqrt(3)*JzKetCoupled(1, 0, (S(1)/2, S(1)/2, S(1)/2, S(1)/2), ((1, 2, 1), (1, 3, S(1)/2), (1, 4, 1)) )/3 + \ + sqrt(6)*JzKetCoupled(1, 0, (S(1)/2, S(1)/2, S(1)/2, S(1)/2), ((1, 2, 1), (1, 3, S(3)/2), (1, 4, 1)) )/6 + \ + sqrt(6)*JzKetCoupled(2, 0, (S(1)/2, S( + 1)/2, S(1)/2, S(1)/2), ((1, 2, 1), (1, 3, S(3)/2), (1, 4, 2)) )/6 + assert couple(TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2))) == \ + sqrt(2)*JzKetCoupled(1, 1, (S(1)/2, S(1)/2, S(1)/2, S(1)/2), ((1, 2, 0), (1, 3, S(1)/2), (1, 4, 1)) )/2 - \ + sqrt(6)*JzKetCoupled(1, 1, (S(1)/2, S(1)/2, S(1)/2, S(1)/2), ((1, 2, 1), (1, 3, S(1)/2), (1, 4, 1)) )/6 - \ + sqrt(3)*JzKetCoupled(1, 1, (S(1)/2, S(1)/2, S(1)/2, S(1)/2), ((1, 2, 1), (1, 3, S(3)/2), (1, 4, 1)) )/6 + \ + JzKetCoupled(2, 1, (S(1)/2, S( + 1)/2, S(1)/2, S(1)/2), ((1, 2, 1), (1, 3, S(3)/2), (1, 4, 2)) )/2 assert couple(TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(-1)/2))) == \ JzKetCoupled(0, 0, (S(1)/2, S(1)/2, S(1)/2, S(1)/2), ((1, 2, 0), (1, 3, S(1)/2), (1, 4, 0)))/2 - \ sqrt(3)*JzKetCoupled(0, 0, (S(1)/2, S(1)/2, S(1)/2, S(1)/2), - ((1, 2, 1), (1, 3, S(1)/2),(1, 4, 0)))/6 + \ + ((1, 2, 1), (1, 3, S(1)/2), (1, 4, 0)))/6 + \ JzKetCoupled(1, 0, (S(1)/2, S(1)/2, S(1)/2, S(1)/2), ((1, 2, 0), (1, 3, S(1)/2), (1, 4, 1)))/2 - \ sqrt(3)*JzKetCoupled(1, 0, (S(1)/2, S(1)/2, S(1)/2, S(1)/2), - ((1, 2, 1),(1, 3, S(1)/2),(1, 4, 1)))/6 + \ + ((1, 2, 1), (1, 3, S(1)/2), (1, 4, 1)))/6 + \ sqrt(6)*JzKetCoupled(1, 0, (S(1)/2, S(1)/2, S(1)/2, S(1)/2), ((1, 2, 1), (1, 3, S(3)/2), (1, 4, 1)))/6 + \ sqrt(6)*JzKetCoupled(2, 0, (S(1)/2, S(1)/2, S(1)/2, S(1)/2), ((1, 2, 1), (1, 3, S(3)/2), (1, 4, 2)))/6 - assert couple(TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(1)/2))) == \ - -JzKetCoupled(0,0, (S(1)/2,S(1)/2,S(1)/2,S(1)/2), ((1,2,0),(1,3,S(1)/2),(1,4,0)) )/2 - \ - sqrt(3)*JzKetCoupled(0,0, (S(1)/2,S(1)/2,S(1)/2,S(1)/2), ((1,2,1),(1,3,S(1)/2),(1,4,0)) )/6 + \ - JzKetCoupled(1,0, (S(1)/2,S(1)/2,S(1)/2,S(1)/2), ((1,2,0),(1,3,S(1)/2),(1,4,1)) )/2 + \ - sqrt(3)*JzKetCoupled(1,0, (S(1)/2,S(1)/2,S(1)/2,S(1)/2), ((1,2,1),(1,3,S(1)/2),(1,4,1)) )/6 - \ - sqrt(6)*JzKetCoupled(1,0, (S(1)/2,S(1)/2,S(1)/2,S(1)/2), ((1,2,1),(1,3,S(3)/2),(1,4,1)) )/6 + \ - sqrt(6)*JzKetCoupled(2,0, (S(1)/2,S(1)/2,S(1)/2,S(1)/2), ((1,2,1),(1,3,S(3)/2),(1,4,2)) )/6 - assert couple(TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(-1)/2))) == \ - sqrt(2)*JzKetCoupled(1,-1, (S(1)/2,S(1)/2,S(1)/2,S(1)/2), ((1,2,0),(1,3,S(1)/2),(1,4,1)) )/2 + \ - sqrt(6)*JzKetCoupled(1,-1, (S(1)/2,S(1)/2,S(1)/2,S(1)/2), ((1,2,1),(1,3,S(1)/2),(1,4,1)) )/6 + \ - sqrt(3)*JzKetCoupled(1,-1, (S(1)/2,S(1)/2,S(1)/2,S(1)/2), ((1,2,1),(1,3,S(3)/2),(1,4,1)) )/6 + \ - JzKetCoupled(2,-1, (S(1)/2,S(1)/2,S(1)/2,S(1)/2), ((1,2,1),(1,3,S(3)/2),(1,4,2)) )/2 - assert couple(TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2))) == \ - -sqrt(2)*JzKetCoupled(1,1, (S(1)/2,S(1)/2,S(1)/2,S(1)/2), ((1,2,0),(1,3,S(1)/2),(1,4,1)) )/2 - \ - sqrt(6)*JzKetCoupled(1,1, (S(1)/2,S(1)/2,S(1)/2,S(1)/2), ((1,2,1),(1,3,S(1)/2),(1,4,1)) )/6 - \ - sqrt(3)*JzKetCoupled(1,1, (S(1)/2,S(1)/2,S(1)/2,S(1)/2), ((1,2,1),(1,3,S(3)/2),(1,4,1)) )/6 + \ - JzKetCoupled(2,1, (S(1)/2,S(1)/2,S(1)/2,S(1)/2), ((1,2,1),(1,3,S(3)/2),(1,4,2)) )/2 - assert couple(TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(-1)/2))) == \ - -JzKetCoupled(0,0, (S(1)/2,S(1)/2,S(1)/2,S(1)/2), ((1,2,0),(1,3,S(1)/2),(1,4,0)) )/2 - \ - sqrt(3)*JzKetCoupled(0,0, (S(1)/2,S(1)/2,S(1)/2,S(1)/2), ((1,2,1),(1,3,S(1)/2),(1,4,0)) )/6 - \ - JzKetCoupled(1,0, (S(1)/2,S(1)/2,S(1)/2,S(1)/2), ((1,2,0),(1,3,S(1)/2),(1,4,1)) )/2 - \ - sqrt(3)*JzKetCoupled(1,0, (S(1)/2,S(1)/2,S(1)/2,S(1)/2), ((1,2,1),(1,3,S(1)/2),(1,4,1)) )/6 + \ - sqrt(6)*JzKetCoupled(1,0, (S(1)/2,S(1)/2,S(1)/2,S(1)/2), ((1,2,1),(1,3,S(3)/2),(1,4,1)) )/6 + \ - sqrt(6)*JzKetCoupled(2,0, (S(1)/2,S(1)/2,S(1)/2,S(1)/2), ((1,2,1),(1,3,S(3)/2),(1,4,2)) )/6 - assert couple(TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(1)/2))) == \ - JzKetCoupled(0,0, (S(1)/2,S(1)/2,S(1)/2,S(1)/2), ((1,2,0),(1,3,S(1)/2),(1,4,0)) )/2 - \ - sqrt(3)*JzKetCoupled(0,0, (S(1)/2,S(1)/2,S(1)/2,S(1)/2), ((1,2,1),(1,3,S(1)/2),(1,4,0)) )/6 - \ - JzKetCoupled(1,0, (S(1)/2,S(1)/2,S(1)/2,S(1)/2), ((1,2,0),(1,3,S(1)/2),(1,4,1)) )/2 + \ - sqrt(3)*JzKetCoupled(1,0, (S(1)/2,S(1)/2,S(1)/2,S(1)/2), ((1,2,1),(1,3,S(1)/2),(1,4,1)) )/6 - \ - sqrt(6)*JzKetCoupled(1,0, (S(1)/2,S(1)/2,S(1)/2,S(1)/2), ((1,2,1),(1,3,S(3)/2),(1,4,1)) )/6 + \ - sqrt(6)*JzKetCoupled(2,0, (S(1)/2,S(1)/2,S(1)/2,S(1)/2), ((1,2,1),(1,3,S(3)/2),(1,4,2)) )/6 - assert couple(TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(-1)/2))) == \ - -sqrt(2)*JzKetCoupled(1,-1, (S(1)/2,S(1)/2,S(1)/2,S(1)/2), ((1,2,0),(1,3,S(1)/2),(1,4,1)) )/2 + \ - sqrt(6)*JzKetCoupled(1,-1, (S(1)/2,S(1)/2,S(1)/2,S(1)/2), ((1,2,1),(1,3,S(1)/2),(1,4,1)) )/6 + \ - sqrt(3)*JzKetCoupled(1,-1, (S(1)/2,S(1)/2,S(1)/2,S(1)/2), ((1,2,1),(1,3,S(3)/2),(1,4,1)) )/6 + \ - JzKetCoupled(2,-1, (S(1)/2,S(1)/2,S(1)/2,S(1)/2), ((1,2,1),(1,3,S(3)/2),(1,4,2)) )/2 - assert couple(TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2))) == \ - sqrt(3)*JzKetCoupled(0,0, (S(1)/2,S(1)/2,S(1)/2,S(1)/2), ((1,2,1),(1,3,S(1)/2),(1,4,0)) )/3 - \ - sqrt(3)*JzKetCoupled(1,0, (S(1)/2,S(1)/2,S(1)/2,S(1)/2), ((1,2,1),(1,3,S(1)/2),(1,4,1)) )/3 - \ - sqrt(6)*JzKetCoupled(1,0, (S(1)/2,S(1)/2,S(1)/2,S(1)/2), ((1,2,1),(1,3,S(3)/2),(1,4,1)) )/6 + \ - sqrt(6)*JzKetCoupled(2,0, (S(1)/2,S(1)/2,S(1)/2,S(1)/2), ((1,2,1),(1,3,S(3)/2),(1,4,2)) )/6 - assert couple(TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(-1)/2))) == \ - -sqrt(6)*JzKetCoupled(1,-1, (S(1)/2,S(1)/2,S(1)/2,S(1)/2), ((1,2,1),(1,3,S(1)/2),(1,4,1)) )/3 + \ - sqrt(3)*JzKetCoupled(1,-1, (S(1)/2,S(1)/2,S(1)/2,S(1)/2), ((1,2,1),(1,3,S(3)/2),(1,4,1)) )/6 + \ - JzKetCoupled(2,-1, (S(1)/2,S(1)/2,S(1)/2,S(1)/2), ((1,2,1),(1,3,S(3)/2),(1,4,2)) )/2 - assert couple(TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(1)/2))) == \ - -sqrt(3)*JzKetCoupled(1,-1, (S(1)/2,S(1)/2,S(1)/2,S(1)/2), ((1,2,1),(1,3,S(3)/2),(1,4,1)) )/2 + \ - JzKetCoupled(2,-1, (S(1)/2,S(1)/2,S(1)/2,S(1)/2), ((1,2,1),(1,3,S(3)/2),(1,4,2)) )/2 - assert couple(TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(-1)/2))) == \ - JzKetCoupled(2,-2, (S(1)/2,S(1)/2,S(1)/2,S(1)/2), ((1,2,1),(1,3,S(3)/2),(1,4,2)) ) + assert couple(TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(1)/2))) == \ + -JzKetCoupled(0, 0, (S(1)/2, S(1)/2, S(1)/2, S(1)/2), ((1, 2, 0), (1, 3, S(1)/2), (1, 4, 0)) )/2 - \ + sqrt(3)*JzKetCoupled(0, 0, (S(1)/2, S(1)/2, S(1)/2, S(1)/2), ((1, 2, 1), (1, 3, S(1)/2), (1, 4, 0)) )/6 + \ + JzKetCoupled(1, 0, (S(1)/2, S(1)/2, S(1)/2, S(1)/2), ((1, 2, 0), (1, 3, S(1)/2), (1, 4, 1)) )/2 + \ + sqrt(3)*JzKetCoupled(1, 0, (S(1)/2, S(1)/2, S(1)/2, S(1)/2), ((1, 2, 1), (1, 3, S(1)/2), (1, 4, 1)) )/6 - \ + sqrt(6)*JzKetCoupled(1, 0, (S(1)/2, S(1)/2, S(1)/2, S(1)/2), ((1, 2, 1), (1, 3, S(3)/2), (1, 4, 1)) )/6 + \ + sqrt(6)*JzKetCoupled(2, 0, (S(1)/2, S( + 1)/2, S(1)/2, S(1)/2), ((1, 2, 1), (1, 3, S(3)/2), (1, 4, 2)) )/6 + assert couple(TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(-1)/2))) == \ + sqrt(2)*JzKetCoupled(1, -1, (S(1)/2, S(1)/2, S(1)/2, S(1)/2), ((1, 2, 0), (1, 3, S(1)/2), (1, 4, 1)) )/2 + \ + sqrt(6)*JzKetCoupled(1, -1, (S(1)/2, S(1)/2, S(1)/2, S(1)/2), ((1, 2, 1), (1, 3, S(1)/2), (1, 4, 1)) )/6 + \ + sqrt(3)*JzKetCoupled(1, -1, (S(1)/2, S(1)/2, S(1)/2, S(1)/2), ((1, 2, 1), (1, 3, S(3)/2), (1, 4, 1)) )/6 + \ + JzKetCoupled(2, -1, (S(1)/2, S( + 1)/2, S(1)/2, S(1)/2), ((1, 2, 1), (1, 3, S(3)/2), (1, 4, 2)) )/2 + assert couple(TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2))) == \ + -sqrt(2)*JzKetCoupled(1, 1, (S(1)/2, S(1)/2, S(1)/2, S(1)/2), ((1, 2, 0), (1, 3, S(1)/2), (1, 4, 1)) )/2 - \ + sqrt(6)*JzKetCoupled(1, 1, (S(1)/2, S(1)/2, S(1)/2, S(1)/2), ((1, 2, 1), (1, 3, S(1)/2), (1, 4, 1)) )/6 - \ + sqrt(3)*JzKetCoupled(1, 1, (S(1)/2, S(1)/2, S(1)/2, S(1)/2), ((1, 2, 1), (1, 3, S(3)/2), (1, 4, 1)) )/6 + \ + JzKetCoupled(2, 1, (S(1)/2, S( + 1)/2, S(1)/2, S(1)/2), ((1, 2, 1), (1, 3, S(3)/2), (1, 4, 2)) )/2 + assert couple(TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(-1)/2))) == \ + -JzKetCoupled(0, 0, (S(1)/2, S(1)/2, S(1)/2, S(1)/2), ((1, 2, 0), (1, 3, S(1)/2), (1, 4, 0)) )/2 - \ + sqrt(3)*JzKetCoupled(0, 0, (S(1)/2, S(1)/2, S(1)/2, S(1)/2), ((1, 2, 1), (1, 3, S(1)/2), (1, 4, 0)) )/6 - \ + JzKetCoupled(1, 0, (S(1)/2, S(1)/2, S(1)/2, S(1)/2), ((1, 2, 0), (1, 3, S(1)/2), (1, 4, 1)) )/2 - \ + sqrt(3)*JzKetCoupled(1, 0, (S(1)/2, S(1)/2, S(1)/2, S(1)/2), ((1, 2, 1), (1, 3, S(1)/2), (1, 4, 1)) )/6 + \ + sqrt(6)*JzKetCoupled(1, 0, (S(1)/2, S(1)/2, S(1)/2, S(1)/2), ((1, 2, 1), (1, 3, S(3)/2), (1, 4, 1)) )/6 + \ + sqrt(6)*JzKetCoupled(2, 0, (S(1)/2, S( + 1)/2, S(1)/2, S(1)/2), ((1, 2, 1), (1, 3, S(3)/2), (1, 4, 2)) )/6 + assert couple(TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(1)/2))) == \ + JzKetCoupled(0, 0, (S(1)/2, S(1)/2, S(1)/2, S(1)/2), ((1, 2, 0), (1, 3, S(1)/2), (1, 4, 0)) )/2 - \ + sqrt(3)*JzKetCoupled(0, 0, (S(1)/2, S(1)/2, S(1)/2, S(1)/2), ((1, 2, 1), (1, 3, S(1)/2), (1, 4, 0)) )/6 - \ + JzKetCoupled(1, 0, (S(1)/2, S(1)/2, S(1)/2, S(1)/2), ((1, 2, 0), (1, 3, S(1)/2), (1, 4, 1)) )/2 + \ + sqrt(3)*JzKetCoupled(1, 0, (S(1)/2, S(1)/2, S(1)/2, S(1)/2), ((1, 2, 1), (1, 3, S(1)/2), (1, 4, 1)) )/6 - \ + sqrt(6)*JzKetCoupled(1, 0, (S(1)/2, S(1)/2, S(1)/2, S(1)/2), ((1, 2, 1), (1, 3, S(3)/2), (1, 4, 1)) )/6 + \ + sqrt(6)*JzKetCoupled(2, 0, (S(1)/2, S( + 1)/2, S(1)/2, S(1)/2), ((1, 2, 1), (1, 3, S(3)/2), (1, 4, 2)) )/6 + assert couple(TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(-1)/2))) == \ + -sqrt(2)*JzKetCoupled(1, -1, (S(1)/2, S(1)/2, S(1)/2, S(1)/2), ((1, 2, 0), (1, 3, S(1)/2), (1, 4, 1)) )/2 + \ + sqrt(6)*JzKetCoupled(1, -1, (S(1)/2, S(1)/2, S(1)/2, S(1)/2), ((1, 2, 1), (1, 3, S(1)/2), (1, 4, 1)) )/6 + \ + sqrt(3)*JzKetCoupled(1, -1, (S(1)/2, S(1)/2, S(1)/2, S(1)/2), ((1, 2, 1), (1, 3, S(3)/2), (1, 4, 1)) )/6 + \ + JzKetCoupled(2, -1, (S(1)/2, S( + 1)/2, S(1)/2, S(1)/2), ((1, 2, 1), (1, 3, S(3)/2), (1, 4, 2)) )/2 + assert couple(TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2))) == \ + sqrt(3)*JzKetCoupled(0, 0, (S(1)/2, S(1)/2, S(1)/2, S(1)/2), ((1, 2, 1), (1, 3, S(1)/2), (1, 4, 0)) )/3 - \ + sqrt(3)*JzKetCoupled(1, 0, (S(1)/2, S(1)/2, S(1)/2, S(1)/2), ((1, 2, 1), (1, 3, S(1)/2), (1, 4, 1)) )/3 - \ + sqrt(6)*JzKetCoupled(1, 0, (S(1)/2, S(1)/2, S(1)/2, S(1)/2), ((1, 2, 1), (1, 3, S(3)/2), (1, 4, 1)) )/6 + \ + sqrt(6)*JzKetCoupled(2, 0, (S(1)/2, S( + 1)/2, S(1)/2, S(1)/2), ((1, 2, 1), (1, 3, S(3)/2), (1, 4, 2)) )/6 + assert couple(TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(-1)/2))) == \ + -sqrt(6)*JzKetCoupled(1, -1, (S(1)/2, S(1)/2, S(1)/2, S(1)/2), ((1, 2, 1), (1, 3, S(1)/2), (1, 4, 1)) )/3 + \ + sqrt(3)*JzKetCoupled(1, -1, (S(1)/2, S(1)/2, S(1)/2, S(1)/2), ((1, 2, 1), (1, 3, S(3)/2), (1, 4, 1)) )/6 + \ + JzKetCoupled(2, -1, (S(1)/2, S( + 1)/2, S(1)/2, S(1)/2), ((1, 2, 1), (1, 3, S(3)/2), (1, 4, 2)) )/2 + assert couple(TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(1)/2))) == \ + -sqrt(3)*JzKetCoupled(1, -1, (S(1)/2, S(1)/2, S(1)/2, S(1)/2), ((1, 2, 1), (1, 3, S(3)/2), (1, 4, 1)) )/2 + \ + JzKetCoupled(2, -1, (S(1)/2, S( + 1)/2, S(1)/2, S(1)/2), ((1, 2, 1), (1, 3, S(3)/2), (1, 4, 2)) )/2 + assert couple(TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(-1)/2))) == \ + JzKetCoupled(2, -2, (S(1)/2, S( + 1)/2, S(1)/2, S(1)/2), ((1, 2, 1), (1, 3, S(3)/2), (1, 4, 2)) ) # j1=S(1)/2, S(1)/2, S(1)/2, 1 - assert couple(TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,1))) == \ - JzKetCoupled(S(5)/2,S(5)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(1,3,S(3)/2),(1,4,S(5)/2)) ); - assert couple(TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,0))) == \ - sqrt(15)*JzKetCoupled(S(3)/2,S(3)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(1,3,S(3)/2),(1,4,S(3)/2)) )/5 + \ - sqrt(10)*JzKetCoupled(S(5)/2,S(3)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(1,3,S(3)/2),(1,4,S(5)/2)) )/5 - assert couple(TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,-1))) == \ - sqrt(2)*JzKetCoupled(S(1)/2,S(1)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(1,3,S(3)/2),(1,4,S(1)/2)) )/2 + \ - sqrt(10)*JzKetCoupled(S(3)/2,S(1)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(1,3,S(3)/2),(1,4,S(3)/2)) )/5 + \ - sqrt(10)*JzKetCoupled(S(5)/2,S(1)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(1,3,S(3)/2),(1,4,S(5)/2)) )/10 - assert couple(TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(1,1))) == \ - sqrt(6)*JzKetCoupled(S(3)/2,S(3)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(1,3,S(1)/2),(1,4,S(3)/2)) )/3 - \ - sqrt(30)*JzKetCoupled(S(3)/2,S(3)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(1,3,S(3)/2),(1,4,S(3)/2)) )/15 + \ - sqrt(5)*JzKetCoupled(S(5)/2,S(3)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(1,3,S(3)/2),(1,4,S(5)/2)) )/5 - assert couple(TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(1,0))) == \ - sqrt(2)*JzKetCoupled(S(1)/2,S(1)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(1,3,S(1)/2),(1,4,S(1)/2)) )/3 - \ - JzKetCoupled(S(1)/2,S(1)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(1,3,S(3)/2),(1,4,S(1)/2)) )/3 + \ - 2*JzKetCoupled(S(3)/2,S(1)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(1,3,S(1)/2),(1,4,S(3)/2)) )/3 + \ - sqrt(5)*JzKetCoupled(S(3)/2,S(1)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(1,3,S(3)/2),(1,4,S(3)/2)) )/15 + \ - sqrt(5)*JzKetCoupled(S(5)/2,S(1)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(1,3,S(3)/2),(1,4,S(5)/2)) )/5 - assert couple(TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(1,-1))) == \ - 2*JzKetCoupled(S(1)/2,-S(1)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(1,3,S(1)/2),(1,4,S(1)/2)) )/3 + \ - sqrt(2)*JzKetCoupled(S(1)/2,-S(1)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(1,3,S(3)/2),(1,4,S(1)/2)) )/6 + \ - sqrt(2)*JzKetCoupled(S(3)/2,-S(1)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(1,3,S(1)/2),(1,4,S(3)/2)) )/3 + \ - 2*sqrt(10)*JzKetCoupled(S(3)/2,-S(1)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(1,3,S(3)/2),(1,4,S(3)/2)) )/15 + \ - sqrt(10)*JzKetCoupled(S(5)/2,-S(1)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(1,3,S(3)/2),(1,4,S(5)/2)) )/10 - assert couple(TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,1))) == \ - sqrt(2)*JzKetCoupled(S(3)/2,S(3)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,0),(1,3,S(1)/2),(1,4,S(3)/2)) )/2 - \ - sqrt(6)*JzKetCoupled(S(3)/2,S(3)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(1,3,S(1)/2),(1,4,S(3)/2)) )/6 - \ - sqrt(30)*JzKetCoupled(S(3)/2,S(3)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(1,3,S(3)/2),(1,4,S(3)/2)) )/15 + \ - sqrt(5)*JzKetCoupled(S(5)/2,S(3)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(1,3,S(3)/2),(1,4,S(5)/2)) )/5 - assert couple(TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,0))) == \ - sqrt(6)*JzKetCoupled(S(1)/2,S(1)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,0),(1,3,S(1)/2),(1,4,S(1)/2)) )/6 - \ - sqrt(2)*JzKetCoupled(S(1)/2,S(1)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(1,3,S(1)/2),(1,4,S(1)/2)) )/6 - \ - JzKetCoupled(S(1)/2,S(1)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(1,3,S(3)/2),(1,4,S(1)/2)) )/3 + \ - sqrt(3)*JzKetCoupled(S(3)/2,S(1)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,0),(1,3,S(1)/2),(1,4,S(3)/2)) )/3 - \ - JzKetCoupled(S(3)/2,S(1)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(1,3,S(1)/2),(1,4,S(3)/2)) )/3 + \ - sqrt(5)*JzKetCoupled(S(3)/2,S(1)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(1,3,S(3)/2),(1,4,S(3)/2)) )/15 + \ - sqrt(5)*JzKetCoupled(S(5)/2,S(1)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(1,3,S(3)/2),(1,4,S(5)/2)) )/5 - assert couple(TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,-1))) == \ - sqrt(3)*JzKetCoupled(S(1)/2,-S(1)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,0),(1,3,S(1)/2),(1,4,S(1)/2)) )/3 - \ - JzKetCoupled(S(1)/2,-S(1)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(1,3,S(1)/2),(1,4,S(1)/2)) )/3 + \ - sqrt(2)*JzKetCoupled(S(1)/2,-S(1)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(1,3,S(3)/2),(1,4,S(1)/2)) )/6 + \ - sqrt(6)*JzKetCoupled(S(3)/2,-S(1)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,0),(1,3,S(1)/2),(1,4,S(3)/2)) )/6 - \ - sqrt(2)*JzKetCoupled(S(3)/2,-S(1)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(1,3,S(1)/2),(1,4,S(3)/2)) )/6 + \ - 2*sqrt(10)*JzKetCoupled(S(3)/2,-S(1)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(1,3,S(3)/2),(1,4,S(3)/2)) )/15 + \ - sqrt(10)*JzKetCoupled(S(5)/2,-S(1)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(1,3,S(3)/2),(1,4,S(5)/2)) )/10 - assert couple(TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(1,1))) == \ - -sqrt(3)*JzKetCoupled(S(1)/2,S(1)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,0),(1,3,S(1)/2),(1,4,S(1)/2)) )/3 - \ - JzKetCoupled(S(1)/2,S(1)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(1,3,S(1)/2),(1,4,S(1)/2)) )/3 + \ - sqrt(2)*JzKetCoupled(S(1)/2,S(1)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(1,3,S(3)/2),(1,4,S(1)/2)) )/6 + \ - sqrt(6)*JzKetCoupled(S(3)/2,S(1)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,0),(1,3,S(1)/2),(1,4,S(3)/2)) )/6 + \ - sqrt(2)*JzKetCoupled(S(3)/2,S(1)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(1,3,S(1)/2),(1,4,S(3)/2)) )/6 - \ - 2*sqrt(10)*JzKetCoupled(S(3)/2,S(1)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(1,3,S(3)/2),(1,4,S(3)/2)) )/15 + \ - sqrt(10)*JzKetCoupled(S(5)/2,S(1)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(1,3,S(3)/2),(1,4,S(5)/2)) )/10 - assert couple(TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(1,0))) == \ - -sqrt(6)*JzKetCoupled(S(1)/2,-S(1)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,0),(1,3,S(1)/2),(1,4,S(1)/2)) )/6 - \ - sqrt(2)*JzKetCoupled(S(1)/2,-S(1)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(1,3,S(1)/2),(1,4,S(1)/2)) )/6 - \ - JzKetCoupled(S(1)/2,-S(1)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(1,3,S(3)/2),(1,4,S(1)/2)) )/3 + \ - sqrt(3)*JzKetCoupled(S(3)/2,-S(1)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,0),(1,3,S(1)/2),(1,4,S(3)/2)) )/3 + \ - JzKetCoupled(S(3)/2,-S(1)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(1,3,S(1)/2),(1,4,S(3)/2)) )/3 - \ - sqrt(5)*JzKetCoupled(S(3)/2,-S(1)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(1,3,S(3)/2),(1,4,S(3)/2)) )/15 + \ - sqrt(5)*JzKetCoupled(S(5)/2,-S(1)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(1,3,S(3)/2),(1,4,S(5)/2)) )/5 - assert couple(TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(1,-1))) == \ - sqrt(2)*JzKetCoupled(S(3)/2,-S(3)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,0),(1,3,S(1)/2),(1,4,S(3)/2)) )/2 + \ - sqrt(6)*JzKetCoupled(S(3)/2,-S(3)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(1,3,S(1)/2),(1,4,S(3)/2)) )/6 + \ - sqrt(30)*JzKetCoupled(S(3)/2,-S(3)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(1,3,S(3)/2),(1,4,S(3)/2)) )/15 + \ - sqrt(5)*JzKetCoupled(S(5)/2,-S(3)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(1,3,S(3)/2),(1,4,S(5)/2)) )/5 - assert couple(TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,1))) == \ - -sqrt(2)*JzKetCoupled(S(3)/2,S(3)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,0),(1,3,S(1)/2),(1,4,S(3)/2)) )/2 - \ - sqrt(6)*JzKetCoupled(S(3)/2,S(3)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(1,3,S(1)/2),(1,4,S(3)/2)) )/6 - \ - sqrt(30)*JzKetCoupled(S(3)/2,S(3)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(1,3,S(3)/2),(1,4,S(3)/2)) )/15 + \ - sqrt(5)*JzKetCoupled(S(5)/2,S(3)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(1,3,S(3)/2),(1,4,S(5)/2)) )/5 - assert couple(TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,0))) == \ - -sqrt(6)*JzKetCoupled(S(1)/2,S(1)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,0),(1,3,S(1)/2),(1,4,S(1)/2)) )/6 - \ - sqrt(2)*JzKetCoupled(S(1)/2,S(1)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(1,3,S(1)/2),(1,4,S(1)/2)) )/6 - \ - JzKetCoupled(S(1)/2,S(1)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(1,3,S(3)/2),(1,4,S(1)/2)) )/3 - \ - sqrt(3)*JzKetCoupled(S(3)/2,S(1)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,0),(1,3,S(1)/2),(1,4,S(3)/2)) )/3 - \ - JzKetCoupled(S(3)/2,S(1)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(1,3,S(1)/2),(1,4,S(3)/2)) )/3 + \ - sqrt(5)*JzKetCoupled(S(3)/2,S(1)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(1,3,S(3)/2),(1,4,S(3)/2)) )/15 + \ - sqrt(5)*JzKetCoupled(S(5)/2,S(1)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(1,3,S(3)/2),(1,4,S(5)/2)) )/5 - assert couple(TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,-1))) == \ - -sqrt(3)*JzKetCoupled(S(1)/2,-S(1)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,0),(1,3,S(1)/2),(1,4,S(1)/2)) )/3 - \ - JzKetCoupled(S(1)/2,-S(1)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(1,3,S(1)/2),(1,4,S(1)/2)) )/3 + \ - sqrt(2)*JzKetCoupled(S(1)/2,-S(1)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(1,3,S(3)/2),(1,4,S(1)/2)) )/6 - \ - sqrt(6)*JzKetCoupled(S(3)/2,-S(1)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,0),(1,3,S(1)/2),(1,4,S(3)/2)) )/6 - \ - sqrt(2)*JzKetCoupled(S(3)/2,-S(1)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(1,3,S(1)/2),(1,4,S(3)/2)) )/6 + \ - 2*sqrt(10)*JzKetCoupled(S(3)/2,-S(1)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(1,3,S(3)/2),(1,4,S(3)/2)) )/15 + \ - sqrt(10)*JzKetCoupled(S(5)/2,-S(1)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(1,3,S(3)/2),(1,4,S(5)/2)) )/10 - assert couple(TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(1,1))) == \ - sqrt(3)*JzKetCoupled(S(1)/2,S(1)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,0),(1,3,S(1)/2),(1,4,S(1)/2)) )/3 - \ - JzKetCoupled(S(1)/2,S(1)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(1,3,S(1)/2),(1,4,S(1)/2)) )/3 + \ - sqrt(2)*JzKetCoupled(S(1)/2,S(1)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(1,3,S(3)/2),(1,4,S(1)/2)) )/6 - \ - sqrt(6)*JzKetCoupled(S(3)/2,S(1)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,0),(1,3,S(1)/2),(1,4,S(3)/2)) )/6 + \ - sqrt(2)*JzKetCoupled(S(3)/2,S(1)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(1,3,S(1)/2),(1,4,S(3)/2)) )/6 - \ - 2*sqrt(10)*JzKetCoupled(S(3)/2,S(1)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(1,3,S(3)/2),(1,4,S(3)/2)) )/15 + \ - sqrt(10)*JzKetCoupled(S(5)/2,S(1)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(1,3,S(3)/2),(1,4,S(5)/2)) )/10 - assert couple(TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(1,0))) == \ - sqrt(6)*JzKetCoupled(S(1)/2,-S(1)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,0),(1,3,S(1)/2),(1,4,S(1)/2)) )/6 - \ - sqrt(2)*JzKetCoupled(S(1)/2,-S(1)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(1,3,S(1)/2),(1,4,S(1)/2)) )/6 - \ - JzKetCoupled(S(1)/2,-S(1)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(1,3,S(3)/2),(1,4,S(1)/2)) )/3 - \ - sqrt(3)*JzKetCoupled(S(3)/2,-S(1)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,0),(1,3,S(1)/2),(1,4,S(3)/2)) )/3 + \ - JzKetCoupled(S(3)/2,-S(1)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(1,3,S(1)/2),(1,4,S(3)/2)) )/3 - \ - sqrt(5)*JzKetCoupled(S(3)/2,-S(1)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(1,3,S(3)/2),(1,4,S(3)/2)) )/15 + \ - sqrt(5)*JzKetCoupled(S(5)/2,-S(1)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(1,3,S(3)/2),(1,4,S(5)/2)) )/5 - assert couple(TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(1,-1))) == \ - -sqrt(2)*JzKetCoupled(S(3)/2,-S(3)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,0),(1,3,S(1)/2),(1,4,S(3)/2)) )/2 + \ - sqrt(6)*JzKetCoupled(S(3)/2,-S(3)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(1,3,S(1)/2),(1,4,S(3)/2)) )/6 + \ - sqrt(30)*JzKetCoupled(S(3)/2,-S(3)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(1,3,S(3)/2),(1,4,S(3)/2)) )/15 + \ - sqrt(5)*JzKetCoupled(S(5)/2,-S(3)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(1,3,S(3)/2),(1,4,S(5)/2)) )/5 - assert couple(TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,1))) == \ - 2*JzKetCoupled(S(1)/2,S(1)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(1,3,S(1)/2),(1,4,S(1)/2)) )/3 + \ - sqrt(2)*JzKetCoupled(S(1)/2,S(1)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(1,3,S(3)/2),(1,4,S(1)/2)) )/6 - \ - sqrt(2)*JzKetCoupled(S(3)/2,S(1)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(1,3,S(1)/2),(1,4,S(3)/2)) )/3 - \ - 2*sqrt(10)*JzKetCoupled(S(3)/2,S(1)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(1,3,S(3)/2),(1,4,S(3)/2)) )/15 + \ - sqrt(10)*JzKetCoupled(S(5)/2,S(1)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(1,3,S(3)/2),(1,4,S(5)/2)) )/10 - assert couple(TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,0))) == \ - sqrt(2)*JzKetCoupled(S(1)/2,-S(1)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(1,3,S(1)/2),(1,4,S(1)/2)) )/3 - \ - JzKetCoupled(S(1)/2,-S(1)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(1,3,S(3)/2),(1,4,S(1)/2)) )/3 - \ - 2*JzKetCoupled(S(3)/2,-S(1)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(1,3,S(1)/2),(1,4,S(3)/2)) )/3 - \ - sqrt(5)*JzKetCoupled(S(3)/2,-S(1)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(1,3,S(3)/2),(1,4,S(3)/2)) )/15 + \ - sqrt(5)*JzKetCoupled(S(5)/2,-S(1)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(1,3,S(3)/2),(1,4,S(5)/2)) )/5 - assert couple(TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,-1))) == \ - -sqrt(6)*JzKetCoupled(S(3)/2,-S(3)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(1,3,S(1)/2),(1,4,S(3)/2)) )/3 + \ - sqrt(30)*JzKetCoupled(S(3)/2,-S(3)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(1,3,S(3)/2),(1,4,S(3)/2)) )/15 + \ - sqrt(5)*JzKetCoupled(S(5)/2,-S(3)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(1,3,S(3)/2),(1,4,S(5)/2)) )/5 - assert couple(TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(1,1))) == \ - sqrt(2)*JzKetCoupled(S(1)/2,-S(1)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(1,3,S(3)/2),(1,4,S(1)/2)) )/2 - \ - sqrt(10)*JzKetCoupled(S(3)/2,-S(1)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(1,3,S(3)/2),(1,4,S(3)/2)) )/5 + \ - sqrt(10)*JzKetCoupled(S(5)/2,-S(1)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(1,3,S(3)/2),(1,4,S(5)/2)) )/10 - assert couple(TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(1,0))) == \ - -sqrt(15)*JzKetCoupled(S(3)/2,-S(3)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(1,3,S(3)/2),(1,4,S(3)/2)) )/5 + \ - sqrt(10)*JzKetCoupled(S(5)/2,-S(3)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(1,3,S(3)/2),(1,4,S(5)/2)) )/5 - assert couple(TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(1,-1))) == \ - JzKetCoupled(S(5)/2,-S(5)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(1,3,S(3)/2),(1,4,S(5)/2)) ) + assert couple(TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, 1))) == \ + JzKetCoupled(S(5)/2, S(5)/2, (S(1)/2, S( + 1)/2, S(1)/2, 1), ((1, 2, 1), (1, 3, S(3)/2), (1, 4, S(5)/2)) ) + assert couple(TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, 0))) == \ + sqrt(15)*JzKetCoupled(S(3)/2, S(3)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 2, 1), (1, 3, S(3)/2), (1, 4, S(3)/2)) )/5 + \ + sqrt(10)*JzKetCoupled(S(5)/2, S(3)/2, (S(1)/2, S( + 1)/2, S(1)/2, 1), ((1, 2, 1), (1, 3, S(3)/2), (1, 4, S(5)/2)) )/5 + assert couple(TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, -1))) == \ + sqrt(2)*JzKetCoupled(S(1)/2, S(1)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 2, 1), (1, 3, S(3)/2), (1, 4, S(1)/2)) )/2 + \ + sqrt(10)*JzKetCoupled(S(3)/2, S(1)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 2, 1), (1, 3, S(3)/2), (1, 4, S(3)/2)) )/5 + \ + sqrt(10)*JzKetCoupled(S(5)/2, S(1)/2, (S(1)/2, S( + 1)/2, S(1)/2, 1), ((1, 2, 1), (1, 3, S(3)/2), (1, 4, S(5)/2)) )/10 + assert couple(TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(1, 1))) == \ + sqrt(6)*JzKetCoupled(S(3)/2, S(3)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 2, 1), (1, 3, S(1)/2), (1, 4, S(3)/2)) )/3 - \ + sqrt(30)*JzKetCoupled(S(3)/2, S(3)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 2, 1), (1, 3, S(3)/2), (1, 4, S(3)/2)) )/15 + \ + sqrt(5)*JzKetCoupled(S(5)/2, S(3)/2, (S(1)/2, S( + 1)/2, S(1)/2, 1), ((1, 2, 1), (1, 3, S(3)/2), (1, 4, S(5)/2)) )/5 + assert couple(TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(1, 0))) == \ + sqrt(2)*JzKetCoupled(S(1)/2, S(1)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 2, 1), (1, 3, S(1)/2), (1, 4, S(1)/2)) )/3 - \ + JzKetCoupled(S(1)/2, S(1)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 2, 1), (1, 3, S(3)/2), (1, 4, S(1)/2)) )/3 + \ + 2*JzKetCoupled(S(3)/2, S(1)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 2, 1), (1, 3, S(1)/2), (1, 4, S(3)/2)) )/3 + \ + sqrt(5)*JzKetCoupled(S(3)/2, S(1)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 2, 1), (1, 3, S(3)/2), (1, 4, S(3)/2)) )/15 + \ + sqrt(5)*JzKetCoupled(S(5)/2, S(1)/2, (S(1)/2, S( + 1)/2, S(1)/2, 1), ((1, 2, 1), (1, 3, S(3)/2), (1, 4, S(5)/2)) )/5 + assert couple(TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(1, -1))) == \ + 2*JzKetCoupled(S(1)/2, -S(1)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 2, 1), (1, 3, S(1)/2), (1, 4, S(1)/2)) )/3 + \ + sqrt(2)*JzKetCoupled(S(1)/2, -S(1)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 2, 1), (1, 3, S(3)/2), (1, 4, S(1)/2)) )/6 + \ + sqrt(2)*JzKetCoupled(S(3)/2, -S(1)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 2, 1), (1, 3, S(1)/2), (1, 4, S(3)/2)) )/3 + \ + 2*sqrt(10)*JzKetCoupled(S(3)/2, -S(1)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 2, 1), (1, 3, S(3)/2), (1, 4, S(3)/2)) )/15 + \ + sqrt(10)*JzKetCoupled(S(5)/2, -S(1)/2, (S(1)/2, S( + 1)/2, S(1)/2, 1), ((1, 2, 1), (1, 3, S(3)/2), (1, 4, S(5)/2)) )/10 + assert couple(TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, 1))) == \ + sqrt(2)*JzKetCoupled(S(3)/2, S(3)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 2, 0), (1, 3, S(1)/2), (1, 4, S(3)/2)) )/2 - \ + sqrt(6)*JzKetCoupled(S(3)/2, S(3)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 2, 1), (1, 3, S(1)/2), (1, 4, S(3)/2)) )/6 - \ + sqrt(30)*JzKetCoupled(S(3)/2, S(3)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 2, 1), (1, 3, S(3)/2), (1, 4, S(3)/2)) )/15 + \ + sqrt(5)*JzKetCoupled(S(5)/2, S(3)/2, (S(1)/2, S( + 1)/2, S(1)/2, 1), ((1, 2, 1), (1, 3, S(3)/2), (1, 4, S(5)/2)) )/5 + assert couple(TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, 0))) == \ + sqrt(6)*JzKetCoupled(S(1)/2, S(1)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 2, 0), (1, 3, S(1)/2), (1, 4, S(1)/2)) )/6 - \ + sqrt(2)*JzKetCoupled(S(1)/2, S(1)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 2, 1), (1, 3, S(1)/2), (1, 4, S(1)/2)) )/6 - \ + JzKetCoupled(S(1)/2, S(1)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 2, 1), (1, 3, S(3)/2), (1, 4, S(1)/2)) )/3 + \ + sqrt(3)*JzKetCoupled(S(3)/2, S(1)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 2, 0), (1, 3, S(1)/2), (1, 4, S(3)/2)) )/3 - \ + JzKetCoupled(S(3)/2, S(1)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 2, 1), (1, 3, S(1)/2), (1, 4, S(3)/2)) )/3 + \ + sqrt(5)*JzKetCoupled(S(3)/2, S(1)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 2, 1), (1, 3, S(3)/2), (1, 4, S(3)/2)) )/15 + \ + sqrt(5)*JzKetCoupled(S(5)/2, S(1)/2, (S(1)/2, S( + 1)/2, S(1)/2, 1), ((1, 2, 1), (1, 3, S(3)/2), (1, 4, S(5)/2)) )/5 + assert couple(TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, -1))) == \ + sqrt(3)*JzKetCoupled(S(1)/2, -S(1)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 2, 0), (1, 3, S(1)/2), (1, 4, S(1)/2)) )/3 - \ + JzKetCoupled(S(1)/2, -S(1)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 2, 1), (1, 3, S(1)/2), (1, 4, S(1)/2)) )/3 + \ + sqrt(2)*JzKetCoupled(S(1)/2, -S(1)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 2, 1), (1, 3, S(3)/2), (1, 4, S(1)/2)) )/6 + \ + sqrt(6)*JzKetCoupled(S(3)/2, -S(1)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 2, 0), (1, 3, S(1)/2), (1, 4, S(3)/2)) )/6 - \ + sqrt(2)*JzKetCoupled(S(3)/2, -S(1)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 2, 1), (1, 3, S(1)/2), (1, 4, S(3)/2)) )/6 + \ + 2*sqrt(10)*JzKetCoupled(S(3)/2, -S(1)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 2, 1), (1, 3, S(3)/2), (1, 4, S(3)/2)) )/15 + \ + sqrt(10)*JzKetCoupled(S(5)/2, -S(1)/2, (S(1)/2, S( + 1)/2, S(1)/2, 1), ((1, 2, 1), (1, 3, S(3)/2), (1, 4, S(5)/2)) )/10 + assert couple(TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(1, 1))) == \ + -sqrt(3)*JzKetCoupled(S(1)/2, S(1)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 2, 0), (1, 3, S(1)/2), (1, 4, S(1)/2)) )/3 - \ + JzKetCoupled(S(1)/2, S(1)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 2, 1), (1, 3, S(1)/2), (1, 4, S(1)/2)) )/3 + \ + sqrt(2)*JzKetCoupled(S(1)/2, S(1)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 2, 1), (1, 3, S(3)/2), (1, 4, S(1)/2)) )/6 + \ + sqrt(6)*JzKetCoupled(S(3)/2, S(1)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 2, 0), (1, 3, S(1)/2), (1, 4, S(3)/2)) )/6 + \ + sqrt(2)*JzKetCoupled(S(3)/2, S(1)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 2, 1), (1, 3, S(1)/2), (1, 4, S(3)/2)) )/6 - \ + 2*sqrt(10)*JzKetCoupled(S(3)/2, S(1)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 2, 1), (1, 3, S(3)/2), (1, 4, S(3)/2)) )/15 + \ + sqrt(10)*JzKetCoupled(S(5)/2, S(1)/2, (S(1)/2, S( + 1)/2, S(1)/2, 1), ((1, 2, 1), (1, 3, S(3)/2), (1, 4, S(5)/2)) )/10 + assert couple(TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(1, 0))) == \ + -sqrt(6)*JzKetCoupled(S(1)/2, -S(1)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 2, 0), (1, 3, S(1)/2), (1, 4, S(1)/2)) )/6 - \ + sqrt(2)*JzKetCoupled(S(1)/2, -S(1)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 2, 1), (1, 3, S(1)/2), (1, 4, S(1)/2)) )/6 - \ + JzKetCoupled(S(1)/2, -S(1)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 2, 1), (1, 3, S(3)/2), (1, 4, S(1)/2)) )/3 + \ + sqrt(3)*JzKetCoupled(S(3)/2, -S(1)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 2, 0), (1, 3, S(1)/2), (1, 4, S(3)/2)) )/3 + \ + JzKetCoupled(S(3)/2, -S(1)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 2, 1), (1, 3, S(1)/2), (1, 4, S(3)/2)) )/3 - \ + sqrt(5)*JzKetCoupled(S(3)/2, -S(1)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 2, 1), (1, 3, S(3)/2), (1, 4, S(3)/2)) )/15 + \ + sqrt(5)*JzKetCoupled(S(5)/2, -S(1)/2, (S(1)/2, S( + 1)/2, S(1)/2, 1), ((1, 2, 1), (1, 3, S(3)/2), (1, 4, S(5)/2)) )/5 + assert couple(TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(1, -1))) == \ + sqrt(2)*JzKetCoupled(S(3)/2, -S(3)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 2, 0), (1, 3, S(1)/2), (1, 4, S(3)/2)) )/2 + \ + sqrt(6)*JzKetCoupled(S(3)/2, -S(3)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 2, 1), (1, 3, S(1)/2), (1, 4, S(3)/2)) )/6 + \ + sqrt(30)*JzKetCoupled(S(3)/2, -S(3)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 2, 1), (1, 3, S(3)/2), (1, 4, S(3)/2)) )/15 + \ + sqrt(5)*JzKetCoupled(S(5)/2, -S(3)/2, (S(1)/2, S( + 1)/2, S(1)/2, 1), ((1, 2, 1), (1, 3, S(3)/2), (1, 4, S(5)/2)) )/5 + assert couple(TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, 1))) == \ + -sqrt(2)*JzKetCoupled(S(3)/2, S(3)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 2, 0), (1, 3, S(1)/2), (1, 4, S(3)/2)) )/2 - \ + sqrt(6)*JzKetCoupled(S(3)/2, S(3)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 2, 1), (1, 3, S(1)/2), (1, 4, S(3)/2)) )/6 - \ + sqrt(30)*JzKetCoupled(S(3)/2, S(3)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 2, 1), (1, 3, S(3)/2), (1, 4, S(3)/2)) )/15 + \ + sqrt(5)*JzKetCoupled(S(5)/2, S(3)/2, (S(1)/2, S( + 1)/2, S(1)/2, 1), ((1, 2, 1), (1, 3, S(3)/2), (1, 4, S(5)/2)) )/5 + assert couple(TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, 0))) == \ + -sqrt(6)*JzKetCoupled(S(1)/2, S(1)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 2, 0), (1, 3, S(1)/2), (1, 4, S(1)/2)) )/6 - \ + sqrt(2)*JzKetCoupled(S(1)/2, S(1)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 2, 1), (1, 3, S(1)/2), (1, 4, S(1)/2)) )/6 - \ + JzKetCoupled(S(1)/2, S(1)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 2, 1), (1, 3, S(3)/2), (1, 4, S(1)/2)) )/3 - \ + sqrt(3)*JzKetCoupled(S(3)/2, S(1)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 2, 0), (1, 3, S(1)/2), (1, 4, S(3)/2)) )/3 - \ + JzKetCoupled(S(3)/2, S(1)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 2, 1), (1, 3, S(1)/2), (1, 4, S(3)/2)) )/3 + \ + sqrt(5)*JzKetCoupled(S(3)/2, S(1)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 2, 1), (1, 3, S(3)/2), (1, 4, S(3)/2)) )/15 + \ + sqrt(5)*JzKetCoupled(S(5)/2, S(1)/2, (S(1)/2, S( + 1)/2, S(1)/2, 1), ((1, 2, 1), (1, 3, S(3)/2), (1, 4, S(5)/2)) )/5 + assert couple(TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, -1))) == \ + -sqrt(3)*JzKetCoupled(S(1)/2, -S(1)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 2, 0), (1, 3, S(1)/2), (1, 4, S(1)/2)) )/3 - \ + JzKetCoupled(S(1)/2, -S(1)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 2, 1), (1, 3, S(1)/2), (1, 4, S(1)/2)) )/3 + \ + sqrt(2)*JzKetCoupled(S(1)/2, -S(1)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 2, 1), (1, 3, S(3)/2), (1, 4, S(1)/2)) )/6 - \ + sqrt(6)*JzKetCoupled(S(3)/2, -S(1)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 2, 0), (1, 3, S(1)/2), (1, 4, S(3)/2)) )/6 - \ + sqrt(2)*JzKetCoupled(S(3)/2, -S(1)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 2, 1), (1, 3, S(1)/2), (1, 4, S(3)/2)) )/6 + \ + 2*sqrt(10)*JzKetCoupled(S(3)/2, -S(1)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 2, 1), (1, 3, S(3)/2), (1, 4, S(3)/2)) )/15 + \ + sqrt(10)*JzKetCoupled(S(5)/2, -S(1)/2, (S(1)/2, S( + 1)/2, S(1)/2, 1), ((1, 2, 1), (1, 3, S(3)/2), (1, 4, S(5)/2)) )/10 + assert couple(TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(1, 1))) == \ + sqrt(3)*JzKetCoupled(S(1)/2, S(1)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 2, 0), (1, 3, S(1)/2), (1, 4, S(1)/2)) )/3 - \ + JzKetCoupled(S(1)/2, S(1)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 2, 1), (1, 3, S(1)/2), (1, 4, S(1)/2)) )/3 + \ + sqrt(2)*JzKetCoupled(S(1)/2, S(1)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 2, 1), (1, 3, S(3)/2), (1, 4, S(1)/2)) )/6 - \ + sqrt(6)*JzKetCoupled(S(3)/2, S(1)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 2, 0), (1, 3, S(1)/2), (1, 4, S(3)/2)) )/6 + \ + sqrt(2)*JzKetCoupled(S(3)/2, S(1)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 2, 1), (1, 3, S(1)/2), (1, 4, S(3)/2)) )/6 - \ + 2*sqrt(10)*JzKetCoupled(S(3)/2, S(1)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 2, 1), (1, 3, S(3)/2), (1, 4, S(3)/2)) )/15 + \ + sqrt(10)*JzKetCoupled(S(5)/2, S(1)/2, (S(1)/2, S( + 1)/2, S(1)/2, 1), ((1, 2, 1), (1, 3, S(3)/2), (1, 4, S(5)/2)) )/10 + assert couple(TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(1, 0))) == \ + sqrt(6)*JzKetCoupled(S(1)/2, -S(1)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 2, 0), (1, 3, S(1)/2), (1, 4, S(1)/2)) )/6 - \ + sqrt(2)*JzKetCoupled(S(1)/2, -S(1)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 2, 1), (1, 3, S(1)/2), (1, 4, S(1)/2)) )/6 - \ + JzKetCoupled(S(1)/2, -S(1)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 2, 1), (1, 3, S(3)/2), (1, 4, S(1)/2)) )/3 - \ + sqrt(3)*JzKetCoupled(S(3)/2, -S(1)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 2, 0), (1, 3, S(1)/2), (1, 4, S(3)/2)) )/3 + \ + JzKetCoupled(S(3)/2, -S(1)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 2, 1), (1, 3, S(1)/2), (1, 4, S(3)/2)) )/3 - \ + sqrt(5)*JzKetCoupled(S(3)/2, -S(1)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 2, 1), (1, 3, S(3)/2), (1, 4, S(3)/2)) )/15 + \ + sqrt(5)*JzKetCoupled(S(5)/2, -S(1)/2, (S(1)/2, S( + 1)/2, S(1)/2, 1), ((1, 2, 1), (1, 3, S(3)/2), (1, 4, S(5)/2)) )/5 + assert couple(TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(1, -1))) == \ + -sqrt(2)*JzKetCoupled(S(3)/2, -S(3)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 2, 0), (1, 3, S(1)/2), (1, 4, S(3)/2)) )/2 + \ + sqrt(6)*JzKetCoupled(S(3)/2, -S(3)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 2, 1), (1, 3, S(1)/2), (1, 4, S(3)/2)) )/6 + \ + sqrt(30)*JzKetCoupled(S(3)/2, -S(3)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 2, 1), (1, 3, S(3)/2), (1, 4, S(3)/2)) )/15 + \ + sqrt(5)*JzKetCoupled(S(5)/2, -S(3)/2, (S(1)/2, S( + 1)/2, S(1)/2, 1), ((1, 2, 1), (1, 3, S(3)/2), (1, 4, S(5)/2)) )/5 + assert couple(TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, 1))) == \ + 2*JzKetCoupled(S(1)/2, S(1)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 2, 1), (1, 3, S(1)/2), (1, 4, S(1)/2)) )/3 + \ + sqrt(2)*JzKetCoupled(S(1)/2, S(1)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 2, 1), (1, 3, S(3)/2), (1, 4, S(1)/2)) )/6 - \ + sqrt(2)*JzKetCoupled(S(3)/2, S(1)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 2, 1), (1, 3, S(1)/2), (1, 4, S(3)/2)) )/3 - \ + 2*sqrt(10)*JzKetCoupled(S(3)/2, S(1)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 2, 1), (1, 3, S(3)/2), (1, 4, S(3)/2)) )/15 + \ + sqrt(10)*JzKetCoupled(S(5)/2, S(1)/2, (S(1)/2, S( + 1)/2, S(1)/2, 1), ((1, 2, 1), (1, 3, S(3)/2), (1, 4, S(5)/2)) )/10 + assert couple(TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, 0))) == \ + sqrt(2)*JzKetCoupled(S(1)/2, -S(1)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 2, 1), (1, 3, S(1)/2), (1, 4, S(1)/2)) )/3 - \ + JzKetCoupled(S(1)/2, -S(1)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 2, 1), (1, 3, S(3)/2), (1, 4, S(1)/2)) )/3 - \ + 2*JzKetCoupled(S(3)/2, -S(1)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 2, 1), (1, 3, S(1)/2), (1, 4, S(3)/2)) )/3 - \ + sqrt(5)*JzKetCoupled(S(3)/2, -S(1)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 2, 1), (1, 3, S(3)/2), (1, 4, S(3)/2)) )/15 + \ + sqrt(5)*JzKetCoupled(S(5)/2, -S(1)/2, (S(1)/2, S( + 1)/2, S(1)/2, 1), ((1, 2, 1), (1, 3, S(3)/2), (1, 4, S(5)/2)) )/5 + assert couple(TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, -1))) == \ + -sqrt(6)*JzKetCoupled(S(3)/2, -S(3)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 2, 1), (1, 3, S(1)/2), (1, 4, S(3)/2)) )/3 + \ + sqrt(30)*JzKetCoupled(S(3)/2, -S(3)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 2, 1), (1, 3, S(3)/2), (1, 4, S(3)/2)) )/15 + \ + sqrt(5)*JzKetCoupled(S(5)/2, -S(3)/2, (S(1)/2, S( + 1)/2, S(1)/2, 1), ((1, 2, 1), (1, 3, S(3)/2), (1, 4, S(5)/2)) )/5 + assert couple(TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(1, 1))) == \ + sqrt(2)*JzKetCoupled(S(1)/2, -S(1)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 2, 1), (1, 3, S(3)/2), (1, 4, S(1)/2)) )/2 - \ + sqrt(10)*JzKetCoupled(S(3)/2, -S(1)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 2, 1), (1, 3, S(3)/2), (1, 4, S(3)/2)) )/5 + \ + sqrt(10)*JzKetCoupled(S(5)/2, -S(1)/2, (S(1)/2, S( + 1)/2, S(1)/2, 1), ((1, 2, 1), (1, 3, S(3)/2), (1, 4, S(5)/2)) )/10 + assert couple(TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(1, 0))) == \ + -sqrt(15)*JzKetCoupled(S(3)/2, -S(3)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 2, 1), (1, 3, S(3)/2), (1, 4, S(3)/2)) )/5 + \ + sqrt(10)*JzKetCoupled(S(5)/2, -S(3)/2, (S(1)/2, S( + 1)/2, S(1)/2, 1), ((1, 2, 1), (1, 3, S(3)/2), (1, 4, S(5)/2)) )/5 + assert couple(TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(1, -1))) == \ + JzKetCoupled(S(5)/2, -S(5)/2, (S(1)/2, S( + 1)/2, S(1)/2, 1), ((1, 2, 1), (1, 3, S(3)/2), (1, 4, S(5)/2)) ) # Couple j1 to j2, j3 to j4 # j1=1/2, j2=1/2, j3=1/2, j4=1/2 - assert couple(TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2)), ((1,2),(3,4),(1,3)) ) == \ - JzKetCoupled(2,2, (S(1)/2,S(1)/2,S(1)/2,S(1)/2), ((1,2,1),(3,4,1),(1,3,2)) ) - assert couple(TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(-1)/2)), ((1,2),(3,4),(1,3)) ) == \ - sqrt(2)*JzKetCoupled(1,1, (S(1)/2,S(1)/2,S(1)/2,S(1)/2), ((1,2,1),(3,4,0),(1,3,1)) )/2 + \ - JzKetCoupled(1,1, (S(1)/2,S(1)/2,S(1)/2,S(1)/2), ((1,2,1),(3,4,1),(1,3,1)) )/2 + \ - JzKetCoupled(2,1, (S(1)/2,S(1)/2,S(1)/2,S(1)/2), ((1,2,1),(3,4,1),(1,3,2)) )/2 - assert couple(TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(1)/2)), ((1,2),(3,4),(1,3)) ) == \ - -sqrt(2)*JzKetCoupled(1,1, (S(1)/2,S(1)/2,S(1)/2,S(1)/2), ((1,2,1),(3,4,0),(1,3,1)) )/2 + \ - JzKetCoupled(1,1, (S(1)/2,S(1)/2,S(1)/2,S(1)/2), ((1,2,1),(3,4,1),(1,3,1)) )/2 + \ - JzKetCoupled(2,1, (S(1)/2,S(1)/2,S(1)/2,S(1)/2), ((1,2,1),(3,4,1),(1,3,2)) )/2 - assert couple(TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(-1)/2)), ((1,2),(3,4),(1,3)) ) == \ - sqrt(3)*JzKetCoupled(0,0, (S(1)/2,S(1)/2,S(1)/2,S(1)/2), ((1,2,1),(3,4,1),(1,3,0)) )/3 + \ - sqrt(2)*JzKetCoupled(1,0, (S(1)/2,S(1)/2,S(1)/2,S(1)/2), ((1,2,1),(3,4,1),(1,3,1)) )/2 + \ - sqrt(6)*JzKetCoupled(2,0, (S(1)/2,S(1)/2,S(1)/2,S(1)/2), ((1,2,1),(3,4,1),(1,3,2)) )/6 - assert couple(TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2)), ((1,2),(3,4),(1,3)) ) == \ - sqrt(2)*JzKetCoupled(1,1, (S(1)/2,S(1)/2,S(1)/2,S(1)/2), ((1,2,0),(3,4,1),(1,3,1)) )/2 - \ - JzKetCoupled(1,1, (S(1)/2,S(1)/2,S(1)/2,S(1)/2), ((1,2,1),(3,4,1),(1,3,1)) )/2 + \ - JzKetCoupled(2,1, (S(1)/2,S(1)/2,S(1)/2,S(1)/2), ((1,2,1),(3,4,1),(1,3,2)) )/2 - assert couple(TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(-1)/2)), ((1,2),(3,4),(1,3)) ) == \ - JzKetCoupled(0,0, (S(1)/2,S(1)/2,S(1)/2,S(1)/2), ((1,2,0),(3,4,0),(1,3,0)) )/2 - \ - sqrt(3)*JzKetCoupled(0,0, (S(1)/2,S(1)/2,S(1)/2,S(1)/2), ((1,2,1),(3,4,1),(1,3,0)) )/6 + \ - JzKetCoupled(1,0, (S(1)/2,S(1)/2,S(1)/2,S(1)/2), ((1,2,0),(3,4,1),(1,3,1)) )/2 + \ - JzKetCoupled(1,0, (S(1)/2,S(1)/2,S(1)/2,S(1)/2), ((1,2,1),(3,4,0),(1,3,1)) )/2 + \ - sqrt(6)*JzKetCoupled(2,0, (S(1)/2,S(1)/2,S(1)/2,S(1)/2), ((1,2,1),(3,4,1),(1,3,2)) )/6 - assert couple(TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(1)/2)), ((1,2),(3,4),(1,3)) ) == \ - -JzKetCoupled(0,0, (S(1)/2,S(1)/2,S(1)/2,S(1)/2), ((1,2,0),(3,4,0),(1,3,0)) )/2 - \ - sqrt(3)*JzKetCoupled(0,0, (S(1)/2,S(1)/2,S(1)/2,S(1)/2), ((1,2,1),(3,4,1),(1,3,0)) )/6 + \ - JzKetCoupled(1,0, (S(1)/2,S(1)/2,S(1)/2,S(1)/2), ((1,2,0),(3,4,1),(1,3,1)) )/2 - \ - JzKetCoupled(1,0, (S(1)/2,S(1)/2,S(1)/2,S(1)/2), ((1,2,1),(3,4,0),(1,3,1)) )/2 + \ - sqrt(6)*JzKetCoupled(2,0, (S(1)/2,S(1)/2,S(1)/2,S(1)/2), ((1,2,1),(3,4,1),(1,3,2)) )/6 - assert couple(TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(-1)/2)), ((1,2),(3,4),(1,3)) ) == \ - sqrt(2)*JzKetCoupled(1,-1, (S(1)/2,S(1)/2,S(1)/2,S(1)/2), ((1,2,0),(3,4,1),(1,3,1)) )/2 + \ - JzKetCoupled(1,-1, (S(1)/2,S(1)/2,S(1)/2,S(1)/2), ((1,2,1),(3,4,1),(1,3,1)) )/2 + \ - JzKetCoupled(2,-1, (S(1)/2,S(1)/2,S(1)/2,S(1)/2), ((1,2,1),(3,4,1),(1,3,2)) )/2 - assert couple(TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2)), ((1,2),(3,4),(1,3)) ) == \ - -sqrt(2)*JzKetCoupled(1,1, (S(1)/2,S(1)/2,S(1)/2,S(1)/2), ((1,2,0),(3,4,1),(1,3,1)) )/2 - \ - JzKetCoupled(1,1, (S(1)/2,S(1)/2,S(1)/2,S(1)/2), ((1,2,1),(3,4,1),(1,3,1)) )/2 + \ - JzKetCoupled(2,1, (S(1)/2,S(1)/2,S(1)/2,S(1)/2), ((1,2,1),(3,4,1),(1,3,2)) )/2 - assert couple(TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(-1)/2)), ((1,2),(3,4),(1,3)) ) == \ - -JzKetCoupled(0,0, (S(1)/2,S(1)/2,S(1)/2,S(1)/2), ((1,2,0),(3,4,0),(1,3,0)) )/2 - \ - sqrt(3)*JzKetCoupled(0,0, (S(1)/2,S(1)/2,S(1)/2,S(1)/2), ((1,2,1),(3,4,1),(1,3,0)) )/6 - \ - JzKetCoupled(1,0, (S(1)/2,S(1)/2,S(1)/2,S(1)/2), ((1,2,0),(3,4,1),(1,3,1)) )/2 + \ - JzKetCoupled(1,0, (S(1)/2,S(1)/2,S(1)/2,S(1)/2), ((1,2,1),(3,4,0),(1,3,1)) )/2 + \ - sqrt(6)*JzKetCoupled(2,0, (S(1)/2,S(1)/2,S(1)/2,S(1)/2), ((1,2,1),(3,4,1),(1,3,2)) )/6 - assert couple(TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(1)/2)), ((1,2),(3,4),(1,3)) ) == \ - JzKetCoupled(0,0, (S(1)/2,S(1)/2,S(1)/2,S(1)/2), ((1,2,0),(3,4,0),(1,3,0)) )/2 - \ - sqrt(3)*JzKetCoupled(0,0, (S(1)/2,S(1)/2,S(1)/2,S(1)/2), ((1,2,1),(3,4,1),(1,3,0)) )/6 - \ - JzKetCoupled(1,0, (S(1)/2,S(1)/2,S(1)/2,S(1)/2), ((1,2,0),(3,4,1),(1,3,1)) )/2 - \ - JzKetCoupled(1,0, (S(1)/2,S(1)/2,S(1)/2,S(1)/2), ((1,2,1),(3,4,0),(1,3,1)) )/2 + \ - sqrt(6)*JzKetCoupled(2,0, (S(1)/2,S(1)/2,S(1)/2,S(1)/2), ((1,2,1),(3,4,1),(1,3,2)) )/6 - assert couple(TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(-1)/2)), ((1,2),(3,4),(1,3)) ) == \ - -sqrt(2)*JzKetCoupled(1,-1, (S(1)/2,S(1)/2,S(1)/2,S(1)/2), ((1,2,0),(3,4,1),(1,3,1)) )/2 + \ - JzKetCoupled(1,-1, (S(1)/2,S(1)/2,S(1)/2,S(1)/2), ((1,2,1),(3,4,1),(1,3,1)) )/2 + \ - JzKetCoupled(2,-1, (S(1)/2,S(1)/2,S(1)/2,S(1)/2), ((1,2,1),(3,4,1),(1,3,2)) )/2 - assert couple(TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2)), ((1,2),(3,4),(1,3)) ) == \ - sqrt(3)*JzKetCoupled(0,0, (S(1)/2,S(1)/2,S(1)/2,S(1)/2), ((1,2,1),(3,4,1),(1,3,0)) )/3 - \ - sqrt(2)*JzKetCoupled(1,0, (S(1)/2,S(1)/2,S(1)/2,S(1)/2), ((1,2,1),(3,4,1),(1,3,1)) )/2 + \ - sqrt(6)*JzKetCoupled(2,0, (S(1)/2,S(1)/2,S(1)/2,S(1)/2), ((1,2,1),(3,4,1),(1,3,2)) )/6 - assert couple(TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(-1)/2)), ((1,2),(3,4),(1,3)) ) == \ - sqrt(2)*JzKetCoupled(1,-1, (S(1)/2,S(1)/2,S(1)/2,S(1)/2), ((1,2,1),(3,4,0),(1,3,1)) )/2 - \ - JzKetCoupled(1,-1, (S(1)/2,S(1)/2,S(1)/2,S(1)/2), ((1,2,1),(3,4,1),(1,3,1)) )/2 + \ - JzKetCoupled(2,-1, (S(1)/2,S(1)/2,S(1)/2,S(1)/2), ((1,2,1),(3,4,1),(1,3,2)) )/2 - assert couple(TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(1)/2)), ((1,2),(3,4),(1,3)) ) == \ - -sqrt(2)*JzKetCoupled(1,-1, (S(1)/2,S(1)/2,S(1)/2,S(1)/2), ((1,2,1),(3,4,0),(1,3,1)) )/2 - \ - JzKetCoupled(1,-1, (S(1)/2,S(1)/2,S(1)/2,S(1)/2), ((1,2,1),(3,4,1),(1,3,1)) )/2 + \ - JzKetCoupled(2,-1, (S(1)/2,S(1)/2,S(1)/2,S(1)/2), ((1,2,1),(3,4,1),(1,3,2)) )/2 - assert couple(TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(-1)/2)), ((1,2),(3,4),(1,3)) ) == \ - JzKetCoupled(2,-2, (S(1)/2,S(1)/2,S(1)/2,S(1)/2), ((1,2,1),(3,4,1),(1,3,2)) ) + assert couple(TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2)), ((1, 2), (3, 4), (1, 3)) ) == \ + JzKetCoupled(2, 2, (S( + 1)/2, S(1)/2, S(1)/2, S(1)/2), ((1, 2, 1), (3, 4, 1), (1, 3, 2)) ) + assert couple(TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(-1)/2)), ((1, 2), (3, 4), (1, 3)) ) == \ + sqrt(2)*JzKetCoupled(1, 1, (S(1)/2, S(1)/2, S(1)/2, S(1)/2), ((1, 2, 1), (3, 4, 0), (1, 3, 1)) )/2 + \ + JzKetCoupled(1, 1, (S(1)/2, S(1)/2, S(1)/2, S(1)/2), ((1, 2, 1), (3, 4, 1), (1, 3, 1)) )/2 + \ + JzKetCoupled(2, 1, (S(1)/2, S( + 1)/2, S(1)/2, S(1)/2), ((1, 2, 1), (3, 4, 1), (1, 3, 2)) )/2 + assert couple(TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(1)/2)), ((1, 2), (3, 4), (1, 3)) ) == \ + -sqrt(2)*JzKetCoupled(1, 1, (S(1)/2, S(1)/2, S(1)/2, S(1)/2), ((1, 2, 1), (3, 4, 0), (1, 3, 1)) )/2 + \ + JzKetCoupled(1, 1, (S(1)/2, S(1)/2, S(1)/2, S(1)/2), ((1, 2, 1), (3, 4, 1), (1, 3, 1)) )/2 + \ + JzKetCoupled(2, 1, (S(1)/2, S( + 1)/2, S(1)/2, S(1)/2), ((1, 2, 1), (3, 4, 1), (1, 3, 2)) )/2 + assert couple(TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(-1)/2)), ((1, 2), (3, 4), (1, 3)) ) == \ + sqrt(3)*JzKetCoupled(0, 0, (S(1)/2, S(1)/2, S(1)/2, S(1)/2), ((1, 2, 1), (3, 4, 1), (1, 3, 0)) )/3 + \ + sqrt(2)*JzKetCoupled(1, 0, (S(1)/2, S(1)/2, S(1)/2, S(1)/2), ((1, 2, 1), (3, 4, 1), (1, 3, 1)) )/2 + \ + sqrt(6)*JzKetCoupled(2, 0, (S(1)/2, S(1)/2, S(1)/2, S(1)/ + 2), ((1, 2, 1), (3, 4, 1), (1, 3, 2)) )/6 + assert couple(TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2)), ((1, 2), (3, 4), (1, 3)) ) == \ + sqrt(2)*JzKetCoupled(1, 1, (S(1)/2, S(1)/2, S(1)/2, S(1)/2), ((1, 2, 0), (3, 4, 1), (1, 3, 1)) )/2 - \ + JzKetCoupled(1, 1, (S(1)/2, S(1)/2, S(1)/2, S(1)/2), ((1, 2, 1), (3, 4, 1), (1, 3, 1)) )/2 + \ + JzKetCoupled(2, 1, (S(1)/2, S( + 1)/2, S(1)/2, S(1)/2), ((1, 2, 1), (3, 4, 1), (1, 3, 2)) )/2 + assert couple(TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(-1)/2)), ((1, 2), (3, 4), (1, 3)) ) == \ + JzKetCoupled(0, 0, (S(1)/2, S(1)/2, S(1)/2, S(1)/2), ((1, 2, 0), (3, 4, 0), (1, 3, 0)) )/2 - \ + sqrt(3)*JzKetCoupled(0, 0, (S(1)/2, S(1)/2, S(1)/2, S(1)/2), ((1, 2, 1), (3, 4, 1), (1, 3, 0)) )/6 + \ + JzKetCoupled(1, 0, (S(1)/2, S(1)/2, S(1)/2, S(1)/2), ((1, 2, 0), (3, 4, 1), (1, 3, 1)) )/2 + \ + JzKetCoupled(1, 0, (S(1)/2, S(1)/2, S(1)/2, S(1)/2), ((1, 2, 1), (3, 4, 0), (1, 3, 1)) )/2 + \ + sqrt(6)*JzKetCoupled(2, 0, (S(1)/2, S(1)/2, S(1)/2, S(1)/ + 2), ((1, 2, 1), (3, 4, 1), (1, 3, 2)) )/6 + assert couple(TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(1)/2)), ((1, 2), (3, 4), (1, 3)) ) == \ + -JzKetCoupled(0, 0, (S(1)/2, S(1)/2, S(1)/2, S(1)/2), ((1, 2, 0), (3, 4, 0), (1, 3, 0)) )/2 - \ + sqrt(3)*JzKetCoupled(0, 0, (S(1)/2, S(1)/2, S(1)/2, S(1)/2), ((1, 2, 1), (3, 4, 1), (1, 3, 0)) )/6 + \ + JzKetCoupled(1, 0, (S(1)/2, S(1)/2, S(1)/2, S(1)/2), ((1, 2, 0), (3, 4, 1), (1, 3, 1)) )/2 - \ + JzKetCoupled(1, 0, (S(1)/2, S(1)/2, S(1)/2, S(1)/2), ((1, 2, 1), (3, 4, 0), (1, 3, 1)) )/2 + \ + sqrt(6)*JzKetCoupled(2, 0, (S(1)/2, S(1)/2, S(1)/2, S(1)/ + 2), ((1, 2, 1), (3, 4, 1), (1, 3, 2)) )/6 + assert couple(TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(-1)/2)), ((1, 2), (3, 4), (1, 3)) ) == \ + sqrt(2)*JzKetCoupled(1, -1, (S(1)/2, S(1)/2, S(1)/2, S(1)/2), ((1, 2, 0), (3, 4, 1), (1, 3, 1)) )/2 + \ + JzKetCoupled(1, -1, (S(1)/2, S(1)/2, S(1)/2, S(1)/2), ((1, 2, 1), (3, 4, 1), (1, 3, 1)) )/2 + \ + JzKetCoupled(2, -1, (S(1)/2, S( + 1)/2, S(1)/2, S(1)/2), ((1, 2, 1), (3, 4, 1), (1, 3, 2)) )/2 + assert couple(TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2)), ((1, 2), (3, 4), (1, 3)) ) == \ + -sqrt(2)*JzKetCoupled(1, 1, (S(1)/2, S(1)/2, S(1)/2, S(1)/2), ((1, 2, 0), (3, 4, 1), (1, 3, 1)) )/2 - \ + JzKetCoupled(1, 1, (S(1)/2, S(1)/2, S(1)/2, S(1)/2), ((1, 2, 1), (3, 4, 1), (1, 3, 1)) )/2 + \ + JzKetCoupled(2, 1, (S(1)/2, S( + 1)/2, S(1)/2, S(1)/2), ((1, 2, 1), (3, 4, 1), (1, 3, 2)) )/2 + assert couple(TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(-1)/2)), ((1, 2), (3, 4), (1, 3)) ) == \ + -JzKetCoupled(0, 0, (S(1)/2, S(1)/2, S(1)/2, S(1)/2), ((1, 2, 0), (3, 4, 0), (1, 3, 0)) )/2 - \ + sqrt(3)*JzKetCoupled(0, 0, (S(1)/2, S(1)/2, S(1)/2, S(1)/2), ((1, 2, 1), (3, 4, 1), (1, 3, 0)) )/6 - \ + JzKetCoupled(1, 0, (S(1)/2, S(1)/2, S(1)/2, S(1)/2), ((1, 2, 0), (3, 4, 1), (1, 3, 1)) )/2 + \ + JzKetCoupled(1, 0, (S(1)/2, S(1)/2, S(1)/2, S(1)/2), ((1, 2, 1), (3, 4, 0), (1, 3, 1)) )/2 + \ + sqrt(6)*JzKetCoupled(2, 0, (S(1)/2, S(1)/2, S(1)/2, S(1)/ + 2), ((1, 2, 1), (3, 4, 1), (1, 3, 2)) )/6 + assert couple(TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(1)/2)), ((1, 2), (3, 4), (1, 3)) ) == \ + JzKetCoupled(0, 0, (S(1)/2, S(1)/2, S(1)/2, S(1)/2), ((1, 2, 0), (3, 4, 0), (1, 3, 0)) )/2 - \ + sqrt(3)*JzKetCoupled(0, 0, (S(1)/2, S(1)/2, S(1)/2, S(1)/2), ((1, 2, 1), (3, 4, 1), (1, 3, 0)) )/6 - \ + JzKetCoupled(1, 0, (S(1)/2, S(1)/2, S(1)/2, S(1)/2), ((1, 2, 0), (3, 4, 1), (1, 3, 1)) )/2 - \ + JzKetCoupled(1, 0, (S(1)/2, S(1)/2, S(1)/2, S(1)/2), ((1, 2, 1), (3, 4, 0), (1, 3, 1)) )/2 + \ + sqrt(6)*JzKetCoupled(2, 0, (S(1)/2, S(1)/2, S(1)/2, S(1)/ + 2), ((1, 2, 1), (3, 4, 1), (1, 3, 2)) )/6 + assert couple(TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(-1)/2)), ((1, 2), (3, 4), (1, 3)) ) == \ + -sqrt(2)*JzKetCoupled(1, -1, (S(1)/2, S(1)/2, S(1)/2, S(1)/2), ((1, 2, 0), (3, 4, 1), (1, 3, 1)) )/2 + \ + JzKetCoupled(1, -1, (S(1)/2, S(1)/2, S(1)/2, S(1)/2), ((1, 2, 1), (3, 4, 1), (1, 3, 1)) )/2 + \ + JzKetCoupled(2, -1, (S(1)/2, S( + 1)/2, S(1)/2, S(1)/2), ((1, 2, 1), (3, 4, 1), (1, 3, 2)) )/2 + assert couple(TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2)), ((1, 2), (3, 4), (1, 3)) ) == \ + sqrt(3)*JzKetCoupled(0, 0, (S(1)/2, S(1)/2, S(1)/2, S(1)/2), ((1, 2, 1), (3, 4, 1), (1, 3, 0)) )/3 - \ + sqrt(2)*JzKetCoupled(1, 0, (S(1)/2, S(1)/2, S(1)/2, S(1)/2), ((1, 2, 1), (3, 4, 1), (1, 3, 1)) )/2 + \ + sqrt(6)*JzKetCoupled(2, 0, (S(1)/2, S(1)/2, S(1)/2, S(1)/ + 2), ((1, 2, 1), (3, 4, 1), (1, 3, 2)) )/6 + assert couple(TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(-1)/2)), ((1, 2), (3, 4), (1, 3)) ) == \ + sqrt(2)*JzKetCoupled(1, -1, (S(1)/2, S(1)/2, S(1)/2, S(1)/2), ((1, 2, 1), (3, 4, 0), (1, 3, 1)) )/2 - \ + JzKetCoupled(1, -1, (S(1)/2, S(1)/2, S(1)/2, S(1)/2), ((1, 2, 1), (3, 4, 1), (1, 3, 1)) )/2 + \ + JzKetCoupled(2, -1, (S(1)/2, S( + 1)/2, S(1)/2, S(1)/2), ((1, 2, 1), (3, 4, 1), (1, 3, 2)) )/2 + assert couple(TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(1)/2)), ((1, 2), (3, 4), (1, 3)) ) == \ + -sqrt(2)*JzKetCoupled(1, -1, (S(1)/2, S(1)/2, S(1)/2, S(1)/2), ((1, 2, 1), (3, 4, 0), (1, 3, 1)) )/2 - \ + JzKetCoupled(1, -1, (S(1)/2, S(1)/2, S(1)/2, S(1)/2), ((1, 2, 1), (3, 4, 1), (1, 3, 1)) )/2 + \ + JzKetCoupled(2, -1, (S(1)/2, S( + 1)/2, S(1)/2, S(1)/2), ((1, 2, 1), (3, 4, 1), (1, 3, 2)) )/2 + assert couple(TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(-1)/2)), ((1, 2), (3, 4), (1, 3)) ) == \ + JzKetCoupled(2, -2, (S( + 1)/2, S(1)/2, S(1)/2, S(1)/2), ((1, 2, 1), (3, 4, 1), (1, 3, 2)) ) # j1=S(1)/2, S(1)/2, S(1)/2, 1 - assert couple(TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,1)), ((1,2),(3,4),(1,3)) ) == \ - JzKetCoupled(S(5)/2,S(5)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(3,4,S(3)/2),(1,3,S(5)/2)) ) - assert couple(TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,0)), ((1,2),(3,4),(1,3)) ) == \ - sqrt(3)*JzKetCoupled(S(3)/2,S(3)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(3,4,S(1)/2),(1,3,S(3)/2)) )/3 + \ - 2*sqrt(15)*JzKetCoupled(S(3)/2,S(3)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(3,4,S(3)/2),(1,3,S(3)/2)) )/15 + \ - sqrt(10)*JzKetCoupled(S(5)/2,S(3)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(3,4,S(3)/2),(1,3,S(5)/2)) )/5 - assert couple(TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,-1)), ((1,2),(3,4),(1,3)) ) == \ - 2*JzKetCoupled(S(1)/2,S(1)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(3,4,S(1)/2),(1,3,S(1)/2)) )/3 + \ - sqrt(2)*JzKetCoupled(S(1)/2,S(1)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(3,4,S(3)/2),(1,3,S(1)/2)) )/6 + \ - sqrt(2)*JzKetCoupled(S(3)/2,S(1)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(3,4,S(1)/2),(1,3,S(3)/2)) )/3 + \ - 2*sqrt(10)*JzKetCoupled(S(3)/2,S(1)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(3,4,S(3)/2),(1,3,S(3)/2)) )/15 + \ - sqrt(10)*JzKetCoupled(S(5)/2,S(1)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(3,4,S(3)/2),(1,3,S(5)/2)) )/10 - assert couple(TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(1,1)), ((1,2),(3,4),(1,3)) ) == \ - -sqrt(6)*JzKetCoupled(S(3)/2,S(3)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(3,4,S(1)/2),(1,3,S(3)/2)) )/3 + \ - sqrt(30)*JzKetCoupled(S(3)/2,S(3)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(3,4,S(3)/2),(1,3,S(3)/2)) )/15 + \ - sqrt(5)*JzKetCoupled(S(5)/2,S(3)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(3,4,S(3)/2),(1,3,S(5)/2)) )/5 - assert couple(TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(1,0)), ((1,2),(3,4),(1,3)) ) == \ - -sqrt(2)*JzKetCoupled(S(1)/2,S(1)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(3,4,S(1)/2),(1,3,S(1)/2)) )/3 + \ - JzKetCoupled(S(1)/2,S(1)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(3,4,S(3)/2),(1,3,S(1)/2)) )/3 - \ - JzKetCoupled(S(3)/2,S(1)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(3,4,S(1)/2),(1,3,S(3)/2)) )/3 + \ - 4*sqrt(5)*JzKetCoupled(S(3)/2,S(1)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(3,4,S(3)/2),(1,3,S(3)/2)) )/15 + \ - sqrt(5)*JzKetCoupled(S(5)/2,S(1)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(3,4,S(3)/2),(1,3,S(5)/2)) )/5 - assert couple(TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(1,-1)), ((1,2),(3,4),(1,3)) ) == \ - sqrt(2)*JzKetCoupled(S(1)/2,-S(1)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(3,4,S(3)/2),(1,3,S(1)/2)) )/2 + \ - sqrt(10)*JzKetCoupled(S(3)/2,-S(1)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(3,4,S(3)/2),(1,3,S(3)/2)) )/5 + \ - sqrt(10)*JzKetCoupled(S(5)/2,-S(1)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(3,4,S(3)/2),(1,3,S(5)/2)) )/10 - assert couple(TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,1)), ((1,2),(3,4),(1,3)) ) == \ - sqrt(2)*JzKetCoupled(S(3)/2,S(3)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,0),(3,4,S(3)/2),(1,3,S(3)/2)) )/2 - \ - sqrt(30)*JzKetCoupled(S(3)/2,S(3)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(3,4,S(3)/2),(1,3,S(3)/2)) )/10 + \ - sqrt(5)*JzKetCoupled(S(5)/2,S(3)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(3,4,S(3)/2),(1,3,S(5)/2)) )/5 - assert couple(TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,0)), ((1,2),(3,4),(1,3)) ) == \ - sqrt(6)*JzKetCoupled(S(1)/2,S(1)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,0),(3,4,S(1)/2),(1,3,S(1)/2)) )/6 - \ - sqrt(2)*JzKetCoupled(S(1)/2,S(1)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(3,4,S(1)/2),(1,3,S(1)/2)) )/6 - \ - JzKetCoupled(S(1)/2,S(1)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(3,4,S(3)/2),(1,3,S(1)/2)) )/3 + \ - sqrt(3)*JzKetCoupled(S(3)/2,S(1)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,0),(3,4,S(3)/2),(1,3,S(3)/2)) )/3 + \ - JzKetCoupled(S(3)/2,S(1)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(3,4,S(1)/2),(1,3,S(3)/2)) )/3 - \ - sqrt(5)*JzKetCoupled(S(3)/2,S(1)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(3,4,S(3)/2),(1,3,S(3)/2)) )/15 + \ - sqrt(5)*JzKetCoupled(S(5)/2,S(1)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(3,4,S(3)/2),(1,3,S(5)/2)) )/5 - assert couple(TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,-1)), ((1,2),(3,4),(1,3)) ) == \ - sqrt(3)*JzKetCoupled(S(1)/2,-S(1)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,0),(3,4,S(1)/2),(1,3,S(1)/2)) )/3 + \ - JzKetCoupled(S(1)/2,-S(1)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(3,4,S(1)/2),(1,3,S(1)/2)) )/3 - \ - sqrt(2)*JzKetCoupled(S(1)/2,-S(1)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(3,4,S(3)/2),(1,3,S(1)/2)) )/6 + \ - sqrt(6)*JzKetCoupled(S(3)/2,-S(1)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,0),(3,4,S(3)/2),(1,3,S(3)/2)) )/6 + \ - sqrt(2)*JzKetCoupled(S(3)/2,-S(1)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(3,4,S(1)/2),(1,3,S(3)/2)) )/3 + \ - sqrt(10)*JzKetCoupled(S(3)/2,-S(1)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(3,4,S(3)/2),(1,3,S(3)/2)) )/30 + \ - sqrt(10)*JzKetCoupled(S(5)/2,-S(1)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(3,4,S(3)/2),(1,3,S(5)/2)) )/10 - assert couple(TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(1,1)), ((1,2),(3,4),(1,3)) ) == \ - -sqrt(3)*JzKetCoupled(S(1)/2,S(1)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,0),(3,4,S(1)/2),(1,3,S(1)/2)) )/3 + \ - JzKetCoupled(S(1)/2,S(1)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(3,4,S(1)/2),(1,3,S(1)/2)) )/3 - \ - sqrt(2)*JzKetCoupled(S(1)/2,S(1)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(3,4,S(3)/2),(1,3,S(1)/2)) )/6 + \ - sqrt(6)*JzKetCoupled(S(3)/2,S(1)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,0),(3,4,S(3)/2),(1,3,S(3)/2)) )/6 - \ - sqrt(2)*JzKetCoupled(S(3)/2,S(1)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(3,4,S(1)/2),(1,3,S(3)/2)) )/3 - \ - sqrt(10)*JzKetCoupled(S(3)/2,S(1)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(3,4,S(3)/2),(1,3,S(3)/2)) )/30 + \ - sqrt(10)*JzKetCoupled(S(5)/2,S(1)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(3,4,S(3)/2),(1,3,S(5)/2)) )/10 - assert couple(TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(1,0)), ((1,2),(3,4),(1,3)) ) == \ - -sqrt(6)*JzKetCoupled(S(1)/2,-S(1)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,0),(3,4,S(1)/2),(1,3,S(1)/2)) )/6 - \ - sqrt(2)*JzKetCoupled(S(1)/2,-S(1)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(3,4,S(1)/2),(1,3,S(1)/2)) )/6 - \ - JzKetCoupled(S(1)/2,-S(1)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(3,4,S(3)/2),(1,3,S(1)/2)) )/3 + \ - sqrt(3)*JzKetCoupled(S(3)/2,-S(1)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,0),(3,4,S(3)/2),(1,3,S(3)/2)) )/3 - \ - JzKetCoupled(S(3)/2,-S(1)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(3,4,S(1)/2),(1,3,S(3)/2)) )/3 + \ - sqrt(5)*JzKetCoupled(S(3)/2,-S(1)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(3,4,S(3)/2),(1,3,S(3)/2)) )/15 + \ - sqrt(5)*JzKetCoupled(S(5)/2,-S(1)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(3,4,S(3)/2),(1,3,S(5)/2)) )/5 - assert couple(TensorProduct(JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(1,-1)), ((1,2),(3,4),(1,3)) ) == \ - sqrt(2)*JzKetCoupled(S(3)/2,-S(3)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,0),(3,4,S(3)/2),(1,3,S(3)/2)) )/2 + \ - sqrt(30)*JzKetCoupled(S(3)/2,-S(3)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(3,4,S(3)/2),(1,3,S(3)/2)) )/10 + \ - sqrt(5)*JzKetCoupled(S(5)/2,-S(3)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(3,4,S(3)/2),(1,3,S(5)/2)) )/5 - assert couple(TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,1)), ((1,2),(3,4),(1,3)) ) == \ - -sqrt(2)*JzKetCoupled(S(3)/2,S(3)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,0),(3,4,S(3)/2),(1,3,S(3)/2)) )/2 - \ - sqrt(30)*JzKetCoupled(S(3)/2,S(3)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(3,4,S(3)/2),(1,3,S(3)/2)) )/10 + \ - sqrt(5)*JzKetCoupled(S(5)/2,S(3)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(3,4,S(3)/2),(1,3,S(5)/2)) )/5 - assert couple(TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,0)), ((1,2),(3,4),(1,3)) ) == \ - -sqrt(6)*JzKetCoupled(S(1)/2,S(1)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,0),(3,4,S(1)/2),(1,3,S(1)/2)) )/6 - \ - sqrt(2)*JzKetCoupled(S(1)/2,S(1)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(3,4,S(1)/2),(1,3,S(1)/2)) )/6 - \ - JzKetCoupled(S(1)/2,S(1)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(3,4,S(3)/2),(1,3,S(1)/2)) )/3 - \ - sqrt(3)*JzKetCoupled(S(3)/2,S(1)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,0),(3,4,S(3)/2),(1,3,S(3)/2)) )/3 + \ - JzKetCoupled(S(3)/2,S(1)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(3,4,S(1)/2),(1,3,S(3)/2)) )/3 - \ - sqrt(5)*JzKetCoupled(S(3)/2,S(1)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(3,4,S(3)/2),(1,3,S(3)/2)) )/15 + \ - sqrt(5)*JzKetCoupled(S(5)/2,S(1)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(3,4,S(3)/2),(1,3,S(5)/2)) )/5 - assert couple(TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,-1)), ((1,2),(3,4),(1,3)) ) == \ - -sqrt(3)*JzKetCoupled(S(1)/2,-S(1)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,0),(3,4,S(1)/2),(1,3,S(1)/2)) )/3 + \ - JzKetCoupled(S(1)/2,-S(1)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(3,4,S(1)/2),(1,3,S(1)/2)) )/3 - \ - sqrt(2)*JzKetCoupled(S(1)/2,-S(1)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(3,4,S(3)/2),(1,3,S(1)/2)) )/6 - \ - sqrt(6)*JzKetCoupled(S(3)/2,-S(1)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,0),(3,4,S(3)/2),(1,3,S(3)/2)) )/6 + \ - sqrt(2)*JzKetCoupled(S(3)/2,-S(1)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(3,4,S(1)/2),(1,3,S(3)/2)) )/3 + \ - sqrt(10)*JzKetCoupled(S(3)/2,-S(1)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(3,4,S(3)/2),(1,3,S(3)/2)) )/30 + \ - sqrt(10)*JzKetCoupled(S(5)/2,-S(1)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(3,4,S(3)/2),(1,3,S(5)/2)) )/10 - assert couple(TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(1,1)), ((1,2),(3,4),(1,3)) ) == \ - sqrt(3)*JzKetCoupled(S(1)/2,S(1)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,0),(3,4,S(1)/2),(1,3,S(1)/2)) )/3 + \ - JzKetCoupled(S(1)/2,S(1)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(3,4,S(1)/2),(1,3,S(1)/2)) )/3 - \ - sqrt(2)*JzKetCoupled(S(1)/2,S(1)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(3,4,S(3)/2),(1,3,S(1)/2)) )/6 - \ - sqrt(6)*JzKetCoupled(S(3)/2,S(1)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,0),(3,4,S(3)/2),(1,3,S(3)/2)) )/6 - \ - sqrt(2)*JzKetCoupled(S(3)/2,S(1)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(3,4,S(1)/2),(1,3,S(3)/2)) )/3 - \ - sqrt(10)*JzKetCoupled(S(3)/2,S(1)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(3,4,S(3)/2),(1,3,S(3)/2)) )/30 + \ - sqrt(10)*JzKetCoupled(S(5)/2,S(1)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(3,4,S(3)/2),(1,3,S(5)/2)) )/10 - assert couple(TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(1,0)), ((1,2),(3,4),(1,3)) ) == \ - sqrt(6)*JzKetCoupled(S(1)/2,-S(1)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,0),(3,4,S(1)/2),(1,3,S(1)/2)) )/6 - \ - sqrt(2)*JzKetCoupled(S(1)/2,-S(1)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(3,4,S(1)/2),(1,3,S(1)/2)) )/6 - \ - JzKetCoupled(S(1)/2,-S(1)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(3,4,S(3)/2),(1,3,S(1)/2)) )/3 - \ - sqrt(3)*JzKetCoupled(S(3)/2,-S(1)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,0),(3,4,S(3)/2),(1,3,S(3)/2)) )/3 - \ - JzKetCoupled(S(3)/2,-S(1)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(3,4,S(1)/2),(1,3,S(3)/2)) )/3 + \ - sqrt(5)*JzKetCoupled(S(3)/2,-S(1)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(3,4,S(3)/2),(1,3,S(3)/2)) )/15 + \ - sqrt(5)*JzKetCoupled(S(5)/2,-S(1)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(3,4,S(3)/2),(1,3,S(5)/2)) )/5 - assert couple(TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(1,-1)), ((1,2),(3,4),(1,3)) ) == \ - -sqrt(2)*JzKetCoupled(S(3)/2,-S(3)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,0),(3,4,S(3)/2),(1,3,S(3)/2)) )/2 + \ - sqrt(30)*JzKetCoupled(S(3)/2,-S(3)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(3,4,S(3)/2),(1,3,S(3)/2)) )/10 + \ - sqrt(5)*JzKetCoupled(S(5)/2,-S(3)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(3,4,S(3)/2),(1,3,S(5)/2)) )/5 - assert couple(TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,1)), ((1,2),(3,4),(1,3)) ) == \ - sqrt(2)*JzKetCoupled(S(1)/2,S(1)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(3,4,S(3)/2),(1,3,S(1)/2)) )/2 - \ - sqrt(10)*JzKetCoupled(S(3)/2,S(1)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(3,4,S(3)/2),(1,3,S(3)/2)) )/5 + \ - sqrt(10)*JzKetCoupled(S(5)/2,S(1)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(3,4,S(3)/2),(1,3,S(5)/2)) )/10 - assert couple(TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,0)), ((1,2),(3,4),(1,3)) ) == \ - -sqrt(2)*JzKetCoupled(S(1)/2,-S(1)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(3,4,S(1)/2),(1,3,S(1)/2)) )/3 + \ - JzKetCoupled(S(1)/2,-S(1)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(3,4,S(3)/2),(1,3,S(1)/2)) )/3 + \ - JzKetCoupled(S(3)/2,-S(1)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(3,4,S(1)/2),(1,3,S(3)/2)) )/3 - \ - 4*sqrt(5)*JzKetCoupled(S(3)/2,-S(1)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(3,4,S(3)/2),(1,3,S(3)/2)) )/15 + \ - sqrt(5)*JzKetCoupled(S(5)/2,-S(1)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(3,4,S(3)/2),(1,3,S(5)/2)) )/5 - assert couple(TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(1)/2), JzKet(1,-1)), ((1,2),(3,4),(1,3)) ) == \ - sqrt(6)*JzKetCoupled(S(3)/2,-S(3)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(3,4,S(1)/2),(1,3,S(3)/2)) )/3 - \ - sqrt(30)*JzKetCoupled(S(3)/2,-S(3)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(3,4,S(3)/2),(1,3,S(3)/2)) )/15 + \ - sqrt(5)*JzKetCoupled(S(5)/2,-S(3)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(3,4,S(3)/2),(1,3,S(5)/2)) )/5 - assert couple(TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(1,1)), ((1,2),(3,4),(1,3)) ) == \ - 2*JzKetCoupled(S(1)/2,-S(1)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(3,4,S(1)/2),(1,3,S(1)/2)) )/3 + \ - sqrt(2)*JzKetCoupled(S(1)/2,-S(1)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(3,4,S(3)/2),(1,3,S(1)/2)) )/6 - \ - sqrt(2)*JzKetCoupled(S(3)/2,-S(1)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(3,4,S(1)/2),(1,3,S(3)/2)) )/3 - \ - 2*sqrt(10)*JzKetCoupled(S(3)/2,-S(1)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(3,4,S(3)/2),(1,3,S(3)/2)) )/15 + \ - sqrt(10)*JzKetCoupled(S(5)/2,-S(1)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(3,4,S(3)/2),(1,3,S(5)/2)) )/10 - assert couple(TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(1,0)), ((1,2),(3,4),(1,3)) ) == \ - -sqrt(3)*JzKetCoupled(S(3)/2,-S(3)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(3,4,S(1)/2),(1,3,S(3)/2)) )/3 - \ - 2*sqrt(15)*JzKetCoupled(S(3)/2,-S(3)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(3,4,S(3)/2),(1,3,S(3)/2)) )/15 + \ - sqrt(10)*JzKetCoupled(S(5)/2,-S(3)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(3,4,S(3)/2),(1,3,S(5)/2)) )/5 - assert couple(TensorProduct(JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(S(1)/2,S(-1)/2), JzKet(1,-1)), ((1,2),(3,4),(1,3)) ) == \ - JzKetCoupled(S(5)/2,-S(5)/2, (S(1)/2,S(1)/2,S(1)/2,1), ((1,2,1),(3,4,S(3)/2),(1,3,S(5)/2)) ) + assert couple(TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, 1)), ((1, 2), (3, 4), (1, 3)) ) == \ + JzKetCoupled(S(5)/2, S(5)/2, (S(1)/2, S( + 1)/2, S(1)/2, 1), ((1, 2, 1), (3, 4, S(3)/2), (1, 3, S(5)/2)) ) + assert couple(TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, 0)), ((1, 2), (3, 4), (1, 3)) ) == \ + sqrt(3)*JzKetCoupled(S(3)/2, S(3)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 2, 1), (3, 4, S(1)/2), (1, 3, S(3)/2)) )/3 + \ + 2*sqrt(15)*JzKetCoupled(S(3)/2, S(3)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 2, 1), (3, 4, S(3)/2), (1, 3, S(3)/2)) )/15 + \ + sqrt(10)*JzKetCoupled(S(5)/2, S(3)/2, (S(1)/2, S( + 1)/2, S(1)/2, 1), ((1, 2, 1), (3, 4, S(3)/2), (1, 3, S(5)/2)) )/5 + assert couple(TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, -1)), ((1, 2), (3, 4), (1, 3)) ) == \ + 2*JzKetCoupled(S(1)/2, S(1)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 2, 1), (3, 4, S(1)/2), (1, 3, S(1)/2)) )/3 + \ + sqrt(2)*JzKetCoupled(S(1)/2, S(1)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 2, 1), (3, 4, S(3)/2), (1, 3, S(1)/2)) )/6 + \ + sqrt(2)*JzKetCoupled(S(3)/2, S(1)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 2, 1), (3, 4, S(1)/2), (1, 3, S(3)/2)) )/3 + \ + 2*sqrt(10)*JzKetCoupled(S(3)/2, S(1)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 2, 1), (3, 4, S(3)/2), (1, 3, S(3)/2)) )/15 + \ + sqrt(10)*JzKetCoupled(S(5)/2, S(1)/2, (S(1)/2, S( + 1)/2, S(1)/2, 1), ((1, 2, 1), (3, 4, S(3)/2), (1, 3, S(5)/2)) )/10 + assert couple(TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(1, 1)), ((1, 2), (3, 4), (1, 3)) ) == \ + -sqrt(6)*JzKetCoupled(S(3)/2, S(3)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 2, 1), (3, 4, S(1)/2), (1, 3, S(3)/2)) )/3 + \ + sqrt(30)*JzKetCoupled(S(3)/2, S(3)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 2, 1), (3, 4, S(3)/2), (1, 3, S(3)/2)) )/15 + \ + sqrt(5)*JzKetCoupled(S(5)/2, S(3)/2, (S(1)/2, S( + 1)/2, S(1)/2, 1), ((1, 2, 1), (3, 4, S(3)/2), (1, 3, S(5)/2)) )/5 + assert couple(TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(1, 0)), ((1, 2), (3, 4), (1, 3)) ) == \ + -sqrt(2)*JzKetCoupled(S(1)/2, S(1)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 2, 1), (3, 4, S(1)/2), (1, 3, S(1)/2)) )/3 + \ + JzKetCoupled(S(1)/2, S(1)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 2, 1), (3, 4, S(3)/2), (1, 3, S(1)/2)) )/3 - \ + JzKetCoupled(S(3)/2, S(1)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 2, 1), (3, 4, S(1)/2), (1, 3, S(3)/2)) )/3 + \ + 4*sqrt(5)*JzKetCoupled(S(3)/2, S(1)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 2, 1), (3, 4, S(3)/2), (1, 3, S(3)/2)) )/15 + \ + sqrt(5)*JzKetCoupled(S(5)/2, S(1)/2, (S(1)/2, S( + 1)/2, S(1)/2, 1), ((1, 2, 1), (3, 4, S(3)/2), (1, 3, S(5)/2)) )/5 + assert couple(TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(1, -1)), ((1, 2), (3, 4), (1, 3)) ) == \ + sqrt(2)*JzKetCoupled(S(1)/2, -S(1)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 2, 1), (3, 4, S(3)/2), (1, 3, S(1)/2)) )/2 + \ + sqrt(10)*JzKetCoupled(S(3)/2, -S(1)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 2, 1), (3, 4, S(3)/2), (1, 3, S(3)/2)) )/5 + \ + sqrt(10)*JzKetCoupled(S(5)/2, -S(1)/2, (S(1)/2, S( + 1)/2, S(1)/2, 1), ((1, 2, 1), (3, 4, S(3)/2), (1, 3, S(5)/2)) )/10 + assert couple(TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, 1)), ((1, 2), (3, 4), (1, 3)) ) == \ + sqrt(2)*JzKetCoupled(S(3)/2, S(3)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 2, 0), (3, 4, S(3)/2), (1, 3, S(3)/2)) )/2 - \ + sqrt(30)*JzKetCoupled(S(3)/2, S(3)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 2, 1), (3, 4, S(3)/2), (1, 3, S(3)/2)) )/10 + \ + sqrt(5)*JzKetCoupled(S(5)/2, S(3)/2, (S(1)/2, S( + 1)/2, S(1)/2, 1), ((1, 2, 1), (3, 4, S(3)/2), (1, 3, S(5)/2)) )/5 + assert couple(TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, 0)), ((1, 2), (3, 4), (1, 3)) ) == \ + sqrt(6)*JzKetCoupled(S(1)/2, S(1)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 2, 0), (3, 4, S(1)/2), (1, 3, S(1)/2)) )/6 - \ + sqrt(2)*JzKetCoupled(S(1)/2, S(1)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 2, 1), (3, 4, S(1)/2), (1, 3, S(1)/2)) )/6 - \ + JzKetCoupled(S(1)/2, S(1)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 2, 1), (3, 4, S(3)/2), (1, 3, S(1)/2)) )/3 + \ + sqrt(3)*JzKetCoupled(S(3)/2, S(1)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 2, 0), (3, 4, S(3)/2), (1, 3, S(3)/2)) )/3 + \ + JzKetCoupled(S(3)/2, S(1)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 2, 1), (3, 4, S(1)/2), (1, 3, S(3)/2)) )/3 - \ + sqrt(5)*JzKetCoupled(S(3)/2, S(1)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 2, 1), (3, 4, S(3)/2), (1, 3, S(3)/2)) )/15 + \ + sqrt(5)*JzKetCoupled(S(5)/2, S(1)/2, (S(1)/2, S( + 1)/2, S(1)/2, 1), ((1, 2, 1), (3, 4, S(3)/2), (1, 3, S(5)/2)) )/5 + assert couple(TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, -1)), ((1, 2), (3, 4), (1, 3)) ) == \ + sqrt(3)*JzKetCoupled(S(1)/2, -S(1)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 2, 0), (3, 4, S(1)/2), (1, 3, S(1)/2)) )/3 + \ + JzKetCoupled(S(1)/2, -S(1)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 2, 1), (3, 4, S(1)/2), (1, 3, S(1)/2)) )/3 - \ + sqrt(2)*JzKetCoupled(S(1)/2, -S(1)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 2, 1), (3, 4, S(3)/2), (1, 3, S(1)/2)) )/6 + \ + sqrt(6)*JzKetCoupled(S(3)/2, -S(1)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 2, 0), (3, 4, S(3)/2), (1, 3, S(3)/2)) )/6 + \ + sqrt(2)*JzKetCoupled(S(3)/2, -S(1)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 2, 1), (3, 4, S(1)/2), (1, 3, S(3)/2)) )/3 + \ + sqrt(10)*JzKetCoupled(S(3)/2, -S(1)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 2, 1), (3, 4, S(3)/2), (1, 3, S(3)/2)) )/30 + \ + sqrt(10)*JzKetCoupled(S(5)/2, -S(1)/2, (S(1)/2, S( + 1)/2, S(1)/2, 1), ((1, 2, 1), (3, 4, S(3)/2), (1, 3, S(5)/2)) )/10 + assert couple(TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(1, 1)), ((1, 2), (3, 4), (1, 3)) ) == \ + -sqrt(3)*JzKetCoupled(S(1)/2, S(1)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 2, 0), (3, 4, S(1)/2), (1, 3, S(1)/2)) )/3 + \ + JzKetCoupled(S(1)/2, S(1)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 2, 1), (3, 4, S(1)/2), (1, 3, S(1)/2)) )/3 - \ + sqrt(2)*JzKetCoupled(S(1)/2, S(1)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 2, 1), (3, 4, S(3)/2), (1, 3, S(1)/2)) )/6 + \ + sqrt(6)*JzKetCoupled(S(3)/2, S(1)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 2, 0), (3, 4, S(3)/2), (1, 3, S(3)/2)) )/6 - \ + sqrt(2)*JzKetCoupled(S(3)/2, S(1)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 2, 1), (3, 4, S(1)/2), (1, 3, S(3)/2)) )/3 - \ + sqrt(10)*JzKetCoupled(S(3)/2, S(1)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 2, 1), (3, 4, S(3)/2), (1, 3, S(3)/2)) )/30 + \ + sqrt(10)*JzKetCoupled(S(5)/2, S(1)/2, (S(1)/2, S( + 1)/2, S(1)/2, 1), ((1, 2, 1), (3, 4, S(3)/2), (1, 3, S(5)/2)) )/10 + assert couple(TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(1, 0)), ((1, 2), (3, 4), (1, 3)) ) == \ + -sqrt(6)*JzKetCoupled(S(1)/2, -S(1)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 2, 0), (3, 4, S(1)/2), (1, 3, S(1)/2)) )/6 - \ + sqrt(2)*JzKetCoupled(S(1)/2, -S(1)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 2, 1), (3, 4, S(1)/2), (1, 3, S(1)/2)) )/6 - \ + JzKetCoupled(S(1)/2, -S(1)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 2, 1), (3, 4, S(3)/2), (1, 3, S(1)/2)) )/3 + \ + sqrt(3)*JzKetCoupled(S(3)/2, -S(1)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 2, 0), (3, 4, S(3)/2), (1, 3, S(3)/2)) )/3 - \ + JzKetCoupled(S(3)/2, -S(1)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 2, 1), (3, 4, S(1)/2), (1, 3, S(3)/2)) )/3 + \ + sqrt(5)*JzKetCoupled(S(3)/2, -S(1)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 2, 1), (3, 4, S(3)/2), (1, 3, S(3)/2)) )/15 + \ + sqrt(5)*JzKetCoupled(S(5)/2, -S(1)/2, (S(1)/2, S( + 1)/2, S(1)/2, 1), ((1, 2, 1), (3, 4, S(3)/2), (1, 3, S(5)/2)) )/5 + assert couple(TensorProduct(JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(1, -1)), ((1, 2), (3, 4), (1, 3)) ) == \ + sqrt(2)*JzKetCoupled(S(3)/2, -S(3)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 2, 0), (3, 4, S(3)/2), (1, 3, S(3)/2)) )/2 + \ + sqrt(30)*JzKetCoupled(S(3)/2, -S(3)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 2, 1), (3, 4, S(3)/2), (1, 3, S(3)/2)) )/10 + \ + sqrt(5)*JzKetCoupled(S(5)/2, -S(3)/2, (S(1)/2, S( + 1)/2, S(1)/2, 1), ((1, 2, 1), (3, 4, S(3)/2), (1, 3, S(5)/2)) )/5 + assert couple(TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, 1)), ((1, 2), (3, 4), (1, 3)) ) == \ + -sqrt(2)*JzKetCoupled(S(3)/2, S(3)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 2, 0), (3, 4, S(3)/2), (1, 3, S(3)/2)) )/2 - \ + sqrt(30)*JzKetCoupled(S(3)/2, S(3)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 2, 1), (3, 4, S(3)/2), (1, 3, S(3)/2)) )/10 + \ + sqrt(5)*JzKetCoupled(S(5)/2, S(3)/2, (S(1)/2, S( + 1)/2, S(1)/2, 1), ((1, 2, 1), (3, 4, S(3)/2), (1, 3, S(5)/2)) )/5 + assert couple(TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, 0)), ((1, 2), (3, 4), (1, 3)) ) == \ + -sqrt(6)*JzKetCoupled(S(1)/2, S(1)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 2, 0), (3, 4, S(1)/2), (1, 3, S(1)/2)) )/6 - \ + sqrt(2)*JzKetCoupled(S(1)/2, S(1)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 2, 1), (3, 4, S(1)/2), (1, 3, S(1)/2)) )/6 - \ + JzKetCoupled(S(1)/2, S(1)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 2, 1), (3, 4, S(3)/2), (1, 3, S(1)/2)) )/3 - \ + sqrt(3)*JzKetCoupled(S(3)/2, S(1)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 2, 0), (3, 4, S(3)/2), (1, 3, S(3)/2)) )/3 + \ + JzKetCoupled(S(3)/2, S(1)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 2, 1), (3, 4, S(1)/2), (1, 3, S(3)/2)) )/3 - \ + sqrt(5)*JzKetCoupled(S(3)/2, S(1)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 2, 1), (3, 4, S(3)/2), (1, 3, S(3)/2)) )/15 + \ + sqrt(5)*JzKetCoupled(S(5)/2, S(1)/2, (S(1)/2, S( + 1)/2, S(1)/2, 1), ((1, 2, 1), (3, 4, S(3)/2), (1, 3, S(5)/2)) )/5 + assert couple(TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, -1)), ((1, 2), (3, 4), (1, 3)) ) == \ + -sqrt(3)*JzKetCoupled(S(1)/2, -S(1)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 2, 0), (3, 4, S(1)/2), (1, 3, S(1)/2)) )/3 + \ + JzKetCoupled(S(1)/2, -S(1)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 2, 1), (3, 4, S(1)/2), (1, 3, S(1)/2)) )/3 - \ + sqrt(2)*JzKetCoupled(S(1)/2, -S(1)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 2, 1), (3, 4, S(3)/2), (1, 3, S(1)/2)) )/6 - \ + sqrt(6)*JzKetCoupled(S(3)/2, -S(1)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 2, 0), (3, 4, S(3)/2), (1, 3, S(3)/2)) )/6 + \ + sqrt(2)*JzKetCoupled(S(3)/2, -S(1)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 2, 1), (3, 4, S(1)/2), (1, 3, S(3)/2)) )/3 + \ + sqrt(10)*JzKetCoupled(S(3)/2, -S(1)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 2, 1), (3, 4, S(3)/2), (1, 3, S(3)/2)) )/30 + \ + sqrt(10)*JzKetCoupled(S(5)/2, -S(1)/2, (S(1)/2, S( + 1)/2, S(1)/2, 1), ((1, 2, 1), (3, 4, S(3)/2), (1, 3, S(5)/2)) )/10 + assert couple(TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(1, 1)), ((1, 2), (3, 4), (1, 3)) ) == \ + sqrt(3)*JzKetCoupled(S(1)/2, S(1)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 2, 0), (3, 4, S(1)/2), (1, 3, S(1)/2)) )/3 + \ + JzKetCoupled(S(1)/2, S(1)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 2, 1), (3, 4, S(1)/2), (1, 3, S(1)/2)) )/3 - \ + sqrt(2)*JzKetCoupled(S(1)/2, S(1)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 2, 1), (3, 4, S(3)/2), (1, 3, S(1)/2)) )/6 - \ + sqrt(6)*JzKetCoupled(S(3)/2, S(1)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 2, 0), (3, 4, S(3)/2), (1, 3, S(3)/2)) )/6 - \ + sqrt(2)*JzKetCoupled(S(3)/2, S(1)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 2, 1), (3, 4, S(1)/2), (1, 3, S(3)/2)) )/3 - \ + sqrt(10)*JzKetCoupled(S(3)/2, S(1)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 2, 1), (3, 4, S(3)/2), (1, 3, S(3)/2)) )/30 + \ + sqrt(10)*JzKetCoupled(S(5)/2, S(1)/2, (S(1)/2, S( + 1)/2, S(1)/2, 1), ((1, 2, 1), (3, 4, S(3)/2), (1, 3, S(5)/2)) )/10 + assert couple(TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(1, 0)), ((1, 2), (3, 4), (1, 3)) ) == \ + sqrt(6)*JzKetCoupled(S(1)/2, -S(1)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 2, 0), (3, 4, S(1)/2), (1, 3, S(1)/2)) )/6 - \ + sqrt(2)*JzKetCoupled(S(1)/2, -S(1)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 2, 1), (3, 4, S(1)/2), (1, 3, S(1)/2)) )/6 - \ + JzKetCoupled(S(1)/2, -S(1)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 2, 1), (3, 4, S(3)/2), (1, 3, S(1)/2)) )/3 - \ + sqrt(3)*JzKetCoupled(S(3)/2, -S(1)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 2, 0), (3, 4, S(3)/2), (1, 3, S(3)/2)) )/3 - \ + JzKetCoupled(S(3)/2, -S(1)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 2, 1), (3, 4, S(1)/2), (1, 3, S(3)/2)) )/3 + \ + sqrt(5)*JzKetCoupled(S(3)/2, -S(1)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 2, 1), (3, 4, S(3)/2), (1, 3, S(3)/2)) )/15 + \ + sqrt(5)*JzKetCoupled(S(5)/2, -S(1)/2, (S(1)/2, S( + 1)/2, S(1)/2, 1), ((1, 2, 1), (3, 4, S(3)/2), (1, 3, S(5)/2)) )/5 + assert couple(TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(1, -1)), ((1, 2), (3, 4), (1, 3)) ) == \ + -sqrt(2)*JzKetCoupled(S(3)/2, -S(3)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 2, 0), (3, 4, S(3)/2), (1, 3, S(3)/2)) )/2 + \ + sqrt(30)*JzKetCoupled(S(3)/2, -S(3)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 2, 1), (3, 4, S(3)/2), (1, 3, S(3)/2)) )/10 + \ + sqrt(5)*JzKetCoupled(S(5)/2, -S(3)/2, (S(1)/2, S( + 1)/2, S(1)/2, 1), ((1, 2, 1), (3, 4, S(3)/2), (1, 3, S(5)/2)) )/5 + assert couple(TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, 1)), ((1, 2), (3, 4), (1, 3)) ) == \ + sqrt(2)*JzKetCoupled(S(1)/2, S(1)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 2, 1), (3, 4, S(3)/2), (1, 3, S(1)/2)) )/2 - \ + sqrt(10)*JzKetCoupled(S(3)/2, S(1)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 2, 1), (3, 4, S(3)/2), (1, 3, S(3)/2)) )/5 + \ + sqrt(10)*JzKetCoupled(S(5)/2, S(1)/2, (S(1)/2, S( + 1)/2, S(1)/2, 1), ((1, 2, 1), (3, 4, S(3)/2), (1, 3, S(5)/2)) )/10 + assert couple(TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, 0)), ((1, 2), (3, 4), (1, 3)) ) == \ + -sqrt(2)*JzKetCoupled(S(1)/2, -S(1)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 2, 1), (3, 4, S(1)/2), (1, 3, S(1)/2)) )/3 + \ + JzKetCoupled(S(1)/2, -S(1)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 2, 1), (3, 4, S(3)/2), (1, 3, S(1)/2)) )/3 + \ + JzKetCoupled(S(3)/2, -S(1)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 2, 1), (3, 4, S(1)/2), (1, 3, S(3)/2)) )/3 - \ + 4*sqrt(5)*JzKetCoupled(S(3)/2, -S(1)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 2, 1), (3, 4, S(3)/2), (1, 3, S(3)/2)) )/15 + \ + sqrt(5)*JzKetCoupled(S(5)/2, -S(1)/2, (S(1)/2, S( + 1)/2, S(1)/2, 1), ((1, 2, 1), (3, 4, S(3)/2), (1, 3, S(5)/2)) )/5 + assert couple(TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(1)/2), JzKet(1, -1)), ((1, 2), (3, 4), (1, 3)) ) == \ + sqrt(6)*JzKetCoupled(S(3)/2, -S(3)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 2, 1), (3, 4, S(1)/2), (1, 3, S(3)/2)) )/3 - \ + sqrt(30)*JzKetCoupled(S(3)/2, -S(3)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 2, 1), (3, 4, S(3)/2), (1, 3, S(3)/2)) )/15 + \ + sqrt(5)*JzKetCoupled(S(5)/2, -S(3)/2, (S(1)/2, S( + 1)/2, S(1)/2, 1), ((1, 2, 1), (3, 4, S(3)/2), (1, 3, S(5)/2)) )/5 + assert couple(TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(1, 1)), ((1, 2), (3, 4), (1, 3)) ) == \ + 2*JzKetCoupled(S(1)/2, -S(1)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 2, 1), (3, 4, S(1)/2), (1, 3, S(1)/2)) )/3 + \ + sqrt(2)*JzKetCoupled(S(1)/2, -S(1)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 2, 1), (3, 4, S(3)/2), (1, 3, S(1)/2)) )/6 - \ + sqrt(2)*JzKetCoupled(S(3)/2, -S(1)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 2, 1), (3, 4, S(1)/2), (1, 3, S(3)/2)) )/3 - \ + 2*sqrt(10)*JzKetCoupled(S(3)/2, -S(1)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 2, 1), (3, 4, S(3)/2), (1, 3, S(3)/2)) )/15 + \ + sqrt(10)*JzKetCoupled(S(5)/2, -S(1)/2, (S(1)/2, S( + 1)/2, S(1)/2, 1), ((1, 2, 1), (3, 4, S(3)/2), (1, 3, S(5)/2)) )/10 + assert couple(TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(1, 0)), ((1, 2), (3, 4), (1, 3)) ) == \ + -sqrt(3)*JzKetCoupled(S(3)/2, -S(3)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 2, 1), (3, 4, S(1)/2), (1, 3, S(3)/2)) )/3 - \ + 2*sqrt(15)*JzKetCoupled(S(3)/2, -S(3)/2, (S(1)/2, S(1)/2, S(1)/2, 1), ((1, 2, 1), (3, 4, S(3)/2), (1, 3, S(3)/2)) )/15 + \ + sqrt(10)*JzKetCoupled(S(5)/2, -S(3)/2, (S(1)/2, S( + 1)/2, S(1)/2, 1), ((1, 2, 1), (3, 4, S(3)/2), (1, 3, S(5)/2)) )/5 + assert couple(TensorProduct(JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(S(1)/2, S(-1)/2), JzKet(1, -1)), ((1, 2), (3, 4), (1, 3)) ) == \ + JzKetCoupled(S(5)/2, -S(5)/2, (S(1)/2, S( + 1)/2, S(1)/2, 1), ((1, 2, 1), (3, 4, S(3)/2), (1, 3, S(5)/2)) ) + def test_couple_symbolic(): - assert couple(TensorProduct(JzKet(j1,m1), JzKet(j2,m2))) == \ - Sum(CG(j1,m1,j2,m2,j,m1+m2) * JzKetCoupled(j, m1+m2, (j1,j2)), (j,m1+m2,j1+j2)) - assert couple(TensorProduct(JzKet(j1,m1), JzKet(j2,m2), JzKet(j3,m3))) == \ - Sum(CG(j1,m1,j2,m2,j12,m1+m2) * CG(j12,m1+m2,j3,m3,j,m1+m2+m3) * \ - JzKetCoupled(j, m1+m2+m3, (j1,j2,j3), ((1,2,j12),(1,3,j)) ), \ + assert couple(TensorProduct(JzKet(j1, m1), JzKet(j2, m2))) == \ + Sum(CG(j1, m1, j2, m2, j, m1 + m2) * JzKetCoupled(j, m1 + m2, ( + j1, j2)), (j, m1 + m2, j1 + j2)) + assert couple(TensorProduct(JzKet(j1, m1), JzKet(j2, m2), JzKet(j3, m3))) == \ + Sum(CG(j1, m1, j2, m2, j12, m1 + m2) * CG(j12, m1 + m2, j3, m3, j, m1 + m2 + m3) * + JzKetCoupled(j, m1 + m2 + m3, (j1, j2, j3), ((1, 2, j12), (1, 3, j)) ), (j12, m1 + m2, j1 + j2), (j, m1 + m2 + m3, j12 + j3)) - assert couple(TensorProduct(JzKet(j1,m1), JzKet(j2,m2), JzKet(j3,m3)), ((1,3),(1,2)) ) == \ - Sum(CG(j1,m1,j3,m3,j13,m1+m3) * CG(j13,m1+m3,j2,m2,j,m1+m2+m3) * \ - JzKetCoupled(j, m1+m2+m3, (j1,j2,j3), ((1,3,j13),(1,2,j)) ), \ - (j13, m1+m3, j1+j3), (j, m1+m2+m3, j13+j2)) - assert couple(TensorProduct(JzKet(j1,m1), JzKet(j2,m2), JzKet(j3,m3), JzKet(j4,m4))) == \ - Sum(CG(j1,m1,j2,m2,j12,m1+m2) * CG(j12,m1+m2,j3,m3,j123,m1+m2+m3) * CG(j123,m1+m2+m3,j4,m4,j,m1+m2+m3+m4) * \ - JzKetCoupled(j, m1+m2+m3+m4, (j1,j2,j3,j4), ((1,2,j12),(1,3,j123),(1,4,j)) ), \ - (j12, m1+m2, j1+j2), (j123, m1+m2+m3, j12+j3), (j, m1+m2+m3+m4, j123+j4)) - assert couple(TensorProduct(JzKet(j1,m1), JzKet(j2,m2), JzKet(j3,m3), JzKet(j4,m4)), ((1,2),(3,4),(1,3)) ) == \ - Sum(CG(j1,m1,j2,m2,j12,m1+m2) * CG(j3,m3,j4,m4,j34,m3+m4) * CG(j12,m1+m2,j34,m3+m4,j,m1+m2+m3+m4) * \ - JzKetCoupled(j, m1+m2+m3+m4, (j1,j2,j3,j4), ((1,2,j12),(3,4,j34),(1,3,j)) ), \ - (j12, m1+m2, j1+j2), (j34, m3+m4, j3+j4), (j, m1+m2+m3+m4, j12+j34)) - assert couple(TensorProduct(JzKet(j1,m1), JzKet(j2,m2), JzKet(j3,m3), JzKet(j4,m4)), ((1,3),(1,4),(1,2)) ) == \ - Sum(CG(j1,m1,j3,m3,j13,m1+m3) * CG(j13,m1+m3,j4,m4,j134,m1+m3+m4) * CG(j134,m1+m3+m4,j2,m2,j,m1+m2+m3+m4) * \ - JzKetCoupled(j, m1+m2+m3+m4, (j1,j2,j3,j4), ((1,3,j13),(1,4,j134),(1,2,j)) ), \ - (j13, m1+m3, j1+j3), (j134, m1+m3+m4, j13+j4), (j, m1+m2+m3+m4, j134+j2)) + assert couple(TensorProduct(JzKet(j1, m1), JzKet(j2, m2), JzKet(j3, m3)), ((1, 3), (1, 2)) ) == \ + Sum(CG(j1, m1, j3, m3, j13, m1 + m3) * CG(j13, m1 + m3, j2, m2, j, m1 + m2 + m3) * + JzKetCoupled(j, m1 + m2 + m3, (j1, j2, j3), ((1, 3, j13), (1, 2, j)) ), + (j13, m1 + m3, j1 + j3), (j, m1 + m2 + m3, j13 + j2)) + assert couple(TensorProduct(JzKet(j1, m1), JzKet(j2, m2), JzKet(j3, m3), JzKet(j4, m4))) == \ + Sum(CG(j1, m1, j2, m2, j12, m1 + m2) * CG(j12, m1 + m2, j3, m3, j123, m1 + m2 + m3) * CG(j123, m1 + m2 + m3, j4, m4, j, m1 + m2 + m3 + m4) * + JzKetCoupled(j, m1 + m2 + m3 + m4, ( + j1, j2, j3, j4), ((1, 2, j12), (1, 3, j123), (1, 4, j)) ), + (j12, m1 + m2, j1 + j2), (j123, m1 + m2 + m3, j12 + j3), (j, m1 + m2 + m3 + m4, j123 + j4)) + assert couple(TensorProduct(JzKet(j1, m1), JzKet(j2, m2), JzKet(j3, m3), JzKet(j4, m4)), ((1, 2), (3, 4), (1, 3)) ) == \ + Sum(CG(j1, m1, j2, m2, j12, m1 + m2) * CG(j3, m3, j4, m4, j34, m3 + m4) * CG(j12, m1 + m2, j34, m3 + m4, j, m1 + m2 + m3 + m4) * + JzKetCoupled(j, m1 + m2 + m3 + m4, ( + j1, j2, j3, j4), ((1, 2, j12), (3, 4, j34), (1, 3, j)) ), + (j12, m1 + m2, j1 + j2), (j34, m3 + m4, j3 + j4), (j, m1 + m2 + m3 + m4, j12 + j34)) + assert couple(TensorProduct(JzKet(j1, m1), JzKet(j2, m2), JzKet(j3, m3), JzKet(j4, m4)), ((1, 3), (1, 4), (1, 2)) ) == \ + Sum(CG(j1, m1, j3, m3, j13, m1 + m3) * CG(j13, m1 + m3, j4, m4, j134, m1 + m3 + m4) * CG(j134, m1 + m3 + m4, j2, m2, j, m1 + m2 + m3 + m4) * + JzKetCoupled(j, m1 + m2 + m3 + m4, ( + j1, j2, j3, j4), ((1, 3, j13), (1, 4, j134), (1, 2, j)) ), + (j13, m1 + m3, j1 + j3), (j134, m1 + m3 + m4, j13 + j4), (j, m1 + m2 + m3 + m4, j134 + j2)) + def test_innerproduct(): - assert InnerProduct(JzBra(1,1), JzKet(1,1)).doit() == 1 - assert InnerProduct(JzBra(S(1)/2,S(1)/2), JzKet(S(1)/2,-S(1)/2)).doit() == 0 - assert InnerProduct(JzBra(j,m), JzKet(j,m)).doit() == 1 - assert InnerProduct(JzBra(1,0), JyKet(1,1)).doit() == I/sqrt(2) - assert InnerProduct(JxBra(S(1)/2,S(1)/2), JzKet(S(1)/2,S(1)/2)).doit() == -sqrt(2)/2 - assert InnerProduct(JyBra(1,1), JzKet(1,1)).doit() == S(1)/2 - assert InnerProduct(JxBra(1,-1), JyKet(1,1)).doit() == 0 + assert InnerProduct(JzBra(1, 1), JzKet(1, 1)).doit() == 1 + assert InnerProduct( + JzBra(S(1)/2, S(1)/2), JzKet(S(1)/2, -S(1)/2)).doit() == 0 + assert InnerProduct(JzBra(j, m), JzKet(j, m)).doit() == 1 + assert InnerProduct(JzBra(1, 0), JyKet(1, 1)).doit() == I/sqrt(2) + assert InnerProduct( + JxBra(S(1)/2, S(1)/2), JzKet(S(1)/2, S(1)/2)).doit() == -sqrt(2)/2 + assert InnerProduct(JyBra(1, 1), JzKet(1, 1)).doit() == S(1)/2 + assert InnerProduct(JxBra(1, -1), JyKet(1, 1)).doit() == 0 + def test_rotation_small_d(): # Symbolic tests # j = 1/2 - assert Rotation.d(S(1)/2,S(1)/2,S(1)/2,beta).doit() == cos(beta/2) - assert Rotation.d(S(1)/2,S(1)/2,-S(1)/2,beta).doit() == -sin(beta/2) - assert Rotation.d(S(1)/2,-S(1)/2,S(1)/2,beta).doit() == sin(beta/2) - assert Rotation.d(S(1)/2,-S(1)/2,-S(1)/2,beta).doit() == cos(beta/2) + assert Rotation.d(S(1)/2, S(1)/2, S(1)/2, beta).doit() == cos(beta/2) + assert Rotation.d(S(1)/2, S(1)/2, -S(1)/2, beta).doit() == -sin(beta/2) + assert Rotation.d(S(1)/2, -S(1)/2, S(1)/2, beta).doit() == sin(beta/2) + assert Rotation.d(S(1)/2, -S(1)/2, -S(1)/2, beta).doit() == cos(beta/2) # j = 1 - assert Rotation.d(1,1,1,beta).doit() == (1+cos(beta))/2 - assert Rotation.d(1,1,0,beta).doit() == -sin(beta)/sqrt(2) - assert Rotation.d(1,1,-1,beta).doit() == (1-cos(beta))/2 - assert Rotation.d(1,0,1,beta).doit() == sin(beta)/sqrt(2) - assert Rotation.d(1,0,0,beta).doit() == cos(beta) - assert Rotation.d(1,0,-1,beta).doit() == -sin(beta)/sqrt(2) - assert Rotation.d(1,-1,1,beta).doit() == (1-cos(beta))/2 - assert Rotation.d(1,-1,0,beta).doit() == sin(beta)/sqrt(2) - assert Rotation.d(1,-1,-1,beta).doit() == (1+cos(beta))/2 + assert Rotation.d(1, 1, 1, beta).doit() == (1 + cos(beta))/2 + assert Rotation.d(1, 1, 0, beta).doit() == -sin(beta)/sqrt(2) + assert Rotation.d(1, 1, -1, beta).doit() == (1 - cos(beta))/2 + assert Rotation.d(1, 0, 1, beta).doit() == sin(beta)/sqrt(2) + assert Rotation.d(1, 0, 0, beta).doit() == cos(beta) + assert Rotation.d(1, 0, -1, beta).doit() == -sin(beta)/sqrt(2) + assert Rotation.d(1, -1, 1, beta).doit() == (1 - cos(beta))/2 + assert Rotation.d(1, -1, 0, beta).doit() == sin(beta)/sqrt(2) + assert Rotation.d(1, -1, -1, beta).doit() == (1 + cos(beta))/2 # j = 3/2 - assert Rotation.d(S(3)/2,S(3)/2,S(3)/2,beta).doit() == (3*cos(beta/2)+cos(3*beta/2))/4 - assert Rotation.d(S(3)/2,S(3)/2,S(1)/2,beta).doit() == sqrt(3)*(-sin(beta/2)-sin(3*beta/2))/4 - assert Rotation.d(S(3)/2,S(3)/2,-S(1)/2,beta).doit() == sqrt(3)*(cos(beta/2)-cos(3*beta/2))/4 - assert Rotation.d(S(3)/2,S(3)/2,-S(3)/2,beta).doit() == (-3*sin(beta/2)+sin(3*beta/2))/4 - assert Rotation.d(S(3)/2,S(1)/2,S(3)/2,beta).doit() == sqrt(3)*(sin(beta/2)+sin(3*beta/2))/4 - assert Rotation.d(S(3)/2,S(1)/2,S(1)/2,beta).doit() == (cos(beta/2)+3*cos(3*beta/2))/4 - assert Rotation.d(S(3)/2,S(1)/2,-S(1)/2,beta).doit() == (sin(beta/2)-3*sin(3*beta/2))/4 - assert Rotation.d(S(3)/2,S(1)/2,-S(3)/2,beta).doit() == sqrt(3)*(cos(beta/2)-cos(3*beta/2))/4 - assert Rotation.d(S(3)/2,-S(1)/2,S(3)/2,beta).doit() == sqrt(3)*(cos(beta/2)-cos(3*beta/2))/4 - assert Rotation.d(S(3)/2,-S(1)/2,S(1)/2,beta).doit() == (-sin(beta/2)+3*sin(3*beta/2))/4 - assert Rotation.d(S(3)/2,-S(1)/2,-S(1)/2,beta).doit() == (cos(beta/2)+3*cos(3*beta/2))/4 - assert Rotation.d(S(3)/2,-S(1)/2,-S(3)/2,beta).doit() == sqrt(3)*(-sin(beta/2)-sin(3*beta/2))/4 - assert Rotation.d(S(3)/2,-S(3)/2,S(3)/2,beta).doit() == (3*sin(beta/2)-sin(3*beta/2))/4 - assert Rotation.d(S(3)/2,-S(3)/2,S(1)/2,beta).doit() == sqrt(3)*(cos(beta/2)-cos(3*beta/2))/4 - assert Rotation.d(S(3)/2,-S(3)/2,-S(1)/2,beta).doit() == sqrt(3)*(sin(beta/2)+sin(3*beta/2))/4 - assert Rotation.d(S(3)/2,-S(3)/2,-S(3)/2,beta).doit() == (3*cos(beta/2)+cos(3*beta/2))/4 + assert Rotation.d(S( + 3)/2, S(3)/2, S(3)/2, beta).doit() == (3*cos(beta/2) + cos(3*beta/2))/4 + assert Rotation.d(S(3)/2, S( + 3)/2, S(1)/2, beta).doit() == -sqrt(3)*(sin(beta/2) + sin(3*beta/2))/4 + assert Rotation.d(S(3)/2, S( + 3)/2, -S(1)/2, beta).doit() == sqrt(3)*(cos(beta/2) - cos(3*beta/2))/4 + assert Rotation.d(S(3)/2, S( + 3)/2, -S(3)/2, beta).doit() == (-3*sin(beta/2) + sin(3*beta/2))/4 + assert Rotation.d(S(3)/2, S( + 1)/2, S(3)/2, beta).doit() == sqrt(3)*(sin(beta/2) + sin(3*beta/2))/4 + assert Rotation.d(S( + 3)/2, S(1)/2, S(1)/2, beta).doit() == (cos(beta/2) + 3*cos(3*beta/2))/4 + assert Rotation.d(S( + 3)/2, S(1)/2, -S(1)/2, beta).doit() == (sin(beta/2) - 3*sin(3*beta/2))/4 + assert Rotation.d(S(3)/2, S( + 1)/2, -S(3)/2, beta).doit() == sqrt(3)*(cos(beta/2) - cos(3*beta/2))/4 + assert Rotation.d(S(3)/2, -S( + 1)/2, S(3)/2, beta).doit() == sqrt(3)*(cos(beta/2) - cos(3*beta/2))/4 + assert Rotation.d(S(3)/2, -S( + 1)/2, S(1)/2, beta).doit() == (-sin(beta/2) + 3*sin(3*beta/2))/4 + assert Rotation.d(S(3)/2, -S( + 1)/2, -S(1)/2, beta).doit() == (cos(beta/2) + 3*cos(3*beta/2))/4 + assert Rotation.d(S(3)/2, -S( + 1)/2, -S(3)/2, beta).doit() == -sqrt(3)*(sin(beta/2) + sin(3*beta/2))/4 + assert Rotation.d(S( + 3)/2, -S(3)/2, S(3)/2, beta).doit() == (3*sin(beta/2) - sin(3*beta/2))/4 + assert Rotation.d(S(3)/2, -S( + 3)/2, S(1)/2, beta).doit() == sqrt(3)*(cos(beta/2) - cos(3*beta/2))/4 + assert Rotation.d(S(3)/2, -S( + 3)/2, -S(1)/2, beta).doit() == sqrt(3)*(sin(beta/2) + sin(3*beta/2))/4 + assert Rotation.d(S(3)/2, -S( + 3)/2, -S(3)/2, beta).doit() == (3*cos(beta/2) + cos(3*beta/2))/4 # j = 2 - assert Rotation.d(2,2,2,beta).doit() == (3+4*cos(beta)+cos(2*beta))/8 - assert Rotation.d(2,2,1,beta).doit() == (-2*sin(beta)-sin(2*beta))/4 - assert Rotation.d(2,2,0,beta).doit() == sqrt(6)*(1-cos(2*beta))/8 - assert Rotation.d(2,2,-1,beta).doit() == (-2*sin(beta)+sin(2*beta))/4 - assert Rotation.d(2,2,-2,beta).doit() == (3-4*cos(beta)+cos(2*beta))/8 - assert Rotation.d(2,1,2,beta).doit() == (2*sin(beta)+sin(2*beta))/4 - assert Rotation.d(2,1,1,beta).doit() == (cos(beta)+cos(2*beta))/2 - assert Rotation.d(2,1,0,beta).doit() == -sqrt(6)*sin(2*beta)/4 - assert Rotation.d(2,1,-1,beta).doit() == (cos(beta)-cos(2*beta))/2 - assert Rotation.d(2,1,-2,beta).doit() == (-2*sin(beta)+sin(2*beta))/4 - assert Rotation.d(2,0,2,beta).doit() == sqrt(6)*(1-cos(2*beta))/8 - assert Rotation.d(2,0,1,beta).doit() == sqrt(6)*sin(2*beta)/4 - assert Rotation.d(2,0,0,beta).doit() == (1+3*cos(2*beta))/4 - assert Rotation.d(2,0,-1,beta).doit() == -sqrt(6)*sin(2*beta)/4 - assert Rotation.d(2,0,-2,beta).doit() == sqrt(6)*(1-cos(2*beta))/8 - assert Rotation.d(2,-1,2,beta).doit() == (2*sin(beta)-sin(2*beta))/4 - assert Rotation.d(2,-1,1,beta).doit() == (cos(beta)-cos(2*beta))/2 - assert Rotation.d(2,-1,0,beta).doit() == sqrt(6)*sin(2*beta)/4 - assert Rotation.d(2,-1,-1,beta).doit() == (cos(beta)+cos(2*beta))/2 - assert Rotation.d(2,-1,-2,beta).doit() == (-2*sin(beta)-sin(2*beta))/4 - assert Rotation.d(2,-2,2,beta).doit() == (3-4*cos(beta)+cos(2*beta))/8 - assert Rotation.d(2,-2,1,beta).doit() == (2*sin(beta)-sin(2*beta))/4 - assert Rotation.d(2,-2,0,beta).doit() == sqrt(6)*(1-cos(2*beta))/8 - assert Rotation.d(2,-2,-1,beta).doit() == (2*sin(beta)+sin(2*beta))/4 - assert Rotation.d(2,-2,-2,beta).doit() == (3+4*cos(beta)+cos(2*beta))/8 + assert Rotation.d(2, 2, 2, beta).doit() == (3 + 4*cos(beta) + cos(2*beta))/8 + assert Rotation.d(2, 2, 1, beta).doit() == -((cos(beta) + 1)*sin(beta))/2 + assert Rotation.d(2, 2, 0, beta).doit() == sqrt(6)*sin(beta)**2/4 + assert Rotation.d(2, 2, -1, beta).doit() == (cos(beta) - 1)*sin(beta)/2 + assert Rotation.d(2, 2, -2, beta).doit() == (3 - 4*cos(beta) + cos(2*beta))/8 + assert Rotation.d(2, 1, 2, beta).doit() == (cos(beta) + 1)*sin(beta)/2 + assert Rotation.d(2, 1, 1, beta).doit() == (cos(beta) + cos(2*beta))/2 + assert Rotation.d(2, 1, 0, beta).doit() == -sqrt(6)*sin(2*beta)/4 + assert Rotation.d(2, 1, -1, beta).doit() == (cos(beta) - cos(2*beta))/2 + assert Rotation.d(2, 1, -2, beta).doit() == (cos(beta) - 1)*sin(beta)/2 + assert Rotation.d(2, 0, 2, beta).doit() == sqrt(6)*sin(beta)**2/4 + assert Rotation.d(2, 0, 1, beta).doit() == sqrt(6)*sin(2*beta)/4 + assert Rotation.d(2, 0, 0, beta).doit() == (1 + 3*cos(2*beta))/4 + assert Rotation.d(2, 0, -1, beta).doit() == -sqrt(6)*sin(2*beta)/4 + assert Rotation.d(2, 0, -2, beta).doit() == sqrt(6)*sin(beta)**2/4 + assert Rotation.d(2, -1, 2, beta).doit() == (2*sin(beta) - sin(2*beta))/4 + assert Rotation.d(2, -1, 1, beta).doit() == (cos(beta) - cos(2*beta))/2 + assert Rotation.d(2, -1, 0, beta).doit() == sqrt(6)*sin(2*beta)/4 + assert Rotation.d(2, -1, -1, beta).doit() == (cos(beta) + cos(2*beta))/2 + assert Rotation.d(2, -1, -2, beta).doit() == -((cos(beta) + 1)*sin(beta))/2 + assert Rotation.d(2, -2, 2, beta).doit() == (3 - 4*cos(beta) + cos(2*beta))/8 + assert Rotation.d(2, -2, 1, beta).doit() == (2*sin(beta) - sin(2*beta))/4 + assert Rotation.d(2, -2, 0, beta).doit() == sqrt(6)*sin(beta)**2/4 + assert Rotation.d(2, -2, -1, beta).doit() == (cos(beta) + 1)*sin(beta)/2 + assert Rotation.d(2, -2, -2, beta).doit() == (3 + 4*cos(beta) + cos(2*beta))/8 # Numerical tests # j = 1/2 - assert Rotation.d(S(1)/2,S(1)/2,S(1)/2,pi/2).doit() == sqrt(2)/2 - assert Rotation.d(S(1)/2,S(1)/2,-S(1)/2,pi/2).doit() == -sqrt(2)/2 - assert Rotation.d(S(1)/2,-S(1)/2,S(1)/2,pi/2).doit() == sqrt(2)/2 - assert Rotation.d(S(1)/2,-S(1)/2,-S(1)/2,pi/2).doit() == sqrt(2)/2 + assert Rotation.d(S(1)/2, S(1)/2, S(1)/2, pi/2).doit() == sqrt(2)/2 + assert Rotation.d(S(1)/2, S(1)/2, -S(1)/2, pi/2).doit() == -sqrt(2)/2 + assert Rotation.d(S(1)/2, -S(1)/2, S(1)/2, pi/2).doit() == sqrt(2)/2 + assert Rotation.d(S(1)/2, -S(1)/2, -S(1)/2, pi/2).doit() == sqrt(2)/2 # j = 1 - assert Rotation.d(1,1,1,pi/2).doit() == 1/2 - assert Rotation.d(1,1,0,pi/2).doit() == -sqrt(2)/2 - assert Rotation.d(1,1,-1,pi/2).doit() == 1/2 - assert Rotation.d(1,0,1,pi/2).doit() == sqrt(2)/2 - assert Rotation.d(1,0,0,pi/2).doit() == 0 - assert Rotation.d(1,0,-1,pi/2).doit() == -sqrt(2)/2 - assert Rotation.d(1,-1,1,pi/2).doit() == 1/2 - assert Rotation.d(1,-1,0,pi/2).doit() == sqrt(2)/2 - assert Rotation.d(1,-1,-1,pi/2).doit() == 1/2 + assert Rotation.d(1, 1, 1, pi/2).doit() == 1/2 + assert Rotation.d(1, 1, 0, pi/2).doit() == -sqrt(2)/2 + assert Rotation.d(1, 1, -1, pi/2).doit() == 1/2 + assert Rotation.d(1, 0, 1, pi/2).doit() == sqrt(2)/2 + assert Rotation.d(1, 0, 0, pi/2).doit() == 0 + assert Rotation.d(1, 0, -1, pi/2).doit() == -sqrt(2)/2 + assert Rotation.d(1, -1, 1, pi/2).doit() == 1/2 + assert Rotation.d(1, -1, 0, pi/2).doit() == sqrt(2)/2 + assert Rotation.d(1, -1, -1, pi/2).doit() == 1/2 # j = 3/2 - assert Rotation.d(S(3)/2,S(3)/2,S(3)/2,pi/2).doit() == sqrt(2)/4 - assert Rotation.d(S(3)/2,S(3)/2,S(1)/2,pi/2).doit() == -sqrt(6)/4 - assert Rotation.d(S(3)/2,S(3)/2,-S(1)/2,pi/2).doit() == sqrt(6)/4 - assert Rotation.d(S(3)/2,S(3)/2,-S(3)/2,pi/2).doit() == -sqrt(2)/4 - assert Rotation.d(S(3)/2,S(1)/2,S(3)/2,pi/2).doit() == sqrt(6)/4 - assert Rotation.d(S(3)/2,S(1)/2,S(1)/2,pi/2).doit() == -sqrt(2)/4 - assert Rotation.d(S(3)/2,S(1)/2,-S(1)/2,pi/2).doit() == -sqrt(2)/4 - assert Rotation.d(S(3)/2,S(1)/2,-S(3)/2,pi/2).doit() == sqrt(6)/4 - assert Rotation.d(S(3)/2,-S(1)/2,S(3)/2,pi/2).doit() == sqrt(6)/4 - assert Rotation.d(S(3)/2,-S(1)/2,S(1)/2,pi/2).doit() == sqrt(2)/4 - assert Rotation.d(S(3)/2,-S(1)/2,-S(1)/2,pi/2).doit() == -sqrt(2)/4 - assert Rotation.d(S(3)/2,-S(1)/2,-S(3)/2,pi/2).doit() == -sqrt(6)/4 - assert Rotation.d(S(3)/2,-S(3)/2,S(3)/2,pi/2).doit() == sqrt(2)/4 - assert Rotation.d(S(3)/2,-S(3)/2,S(1)/2,pi/2).doit() == sqrt(6)/4 - assert Rotation.d(S(3)/2,-S(3)/2,-S(1)/2,pi/2).doit() == sqrt(6)/4 - assert Rotation.d(S(3)/2,-S(3)/2,-S(3)/2,pi/2).doit() == sqrt(2)/4 + assert Rotation.d(S(3)/2, S(3)/2, S(3)/2, pi/2).doit() == sqrt(2)/4 + assert Rotation.d(S(3)/2, S(3)/2, S(1)/2, pi/2).doit() == -sqrt(6)/4 + assert Rotation.d(S(3)/2, S(3)/2, -S(1)/2, pi/2).doit() == sqrt(6)/4 + assert Rotation.d(S(3)/2, S(3)/2, -S(3)/2, pi/2).doit() == -sqrt(2)/4 + assert Rotation.d(S(3)/2, S(1)/2, S(3)/2, pi/2).doit() == sqrt(6)/4 + assert Rotation.d(S(3)/2, S(1)/2, S(1)/2, pi/2).doit() == -sqrt(2)/4 + assert Rotation.d(S(3)/2, S(1)/2, -S(1)/2, pi/2).doit() == -sqrt(2)/4 + assert Rotation.d(S(3)/2, S(1)/2, -S(3)/2, pi/2).doit() == sqrt(6)/4 + assert Rotation.d(S(3)/2, -S(1)/2, S(3)/2, pi/2).doit() == sqrt(6)/4 + assert Rotation.d(S(3)/2, -S(1)/2, S(1)/2, pi/2).doit() == sqrt(2)/4 + assert Rotation.d(S(3)/2, -S(1)/2, -S(1)/2, pi/2).doit() == -sqrt(2)/4 + assert Rotation.d(S(3)/2, -S(1)/2, -S(3)/2, pi/2).doit() == -sqrt(6)/4 + assert Rotation.d(S(3)/2, -S(3)/2, S(3)/2, pi/2).doit() == sqrt(2)/4 + assert Rotation.d(S(3)/2, -S(3)/2, S(1)/2, pi/2).doit() == sqrt(6)/4 + assert Rotation.d(S(3)/2, -S(3)/2, -S(1)/2, pi/2).doit() == sqrt(6)/4 + assert Rotation.d(S(3)/2, -S(3)/2, -S(3)/2, pi/2).doit() == sqrt(2)/4 # j = 2 - assert Rotation.d(2,2,2,pi/2).doit() == 1/4 - assert Rotation.d(2,2,1,pi/2).doit() == -1/2 - assert Rotation.d(2,2,0,pi/2).doit() == sqrt(6)/4 - assert Rotation.d(2,2,-1,pi/2).doit() == -1/2 - assert Rotation.d(2,2,-2,pi/2).doit() == 1/4 - assert Rotation.d(2,1,2,pi/2).doit() == 1/2 - assert Rotation.d(2,1,1,pi/2).doit() == -1/2 - assert Rotation.d(2,1,0,pi/2).doit() == 0 - assert Rotation.d(2,1,-1,pi/2).doit() == 1/2 - assert Rotation.d(2,1,-2,pi/2).doit() == -1/2 - assert Rotation.d(2,0,2,pi/2).doit() == sqrt(6)/4 - assert Rotation.d(2,0,1,pi/2).doit() == 0 - assert Rotation.d(2,0,0,pi/2).doit() == -1/2 - assert Rotation.d(2,0,-1,pi/2).doit() == 0 - assert Rotation.d(2,0,-2,pi/2).doit() == sqrt(6)/4 - assert Rotation.d(2,-1,2,pi/2).doit() == 1/2 - assert Rotation.d(2,-1,1,pi/2).doit() == 1/2 - assert Rotation.d(2,-1,0,pi/2).doit() == 0 - assert Rotation.d(2,-1,-1,pi/2).doit() == -1/2 - assert Rotation.d(2,-1,-2,pi/2).doit() == -1/2 - assert Rotation.d(2,-2,2,pi/2).doit() == 1/4 - assert Rotation.d(2,-2,1,pi/2).doit() == 1/2 - assert Rotation.d(2,-2,0,pi/2).doit() == sqrt(6)/4 - assert Rotation.d(2,-2,-1,pi/2).doit() == 1/2 - assert Rotation.d(2,-2,-2,pi/2).doit() == 1/4 + assert Rotation.d(2, 2, 2, pi/2).doit() == 1/4 + assert Rotation.d(2, 2, 1, pi/2).doit() == -1/2 + assert Rotation.d(2, 2, 0, pi/2).doit() == sqrt(6)/4 + assert Rotation.d(2, 2, -1, pi/2).doit() == -1/2 + assert Rotation.d(2, 2, -2, pi/2).doit() == 1/4 + assert Rotation.d(2, 1, 2, pi/2).doit() == 1/2 + assert Rotation.d(2, 1, 1, pi/2).doit() == -1/2 + assert Rotation.d(2, 1, 0, pi/2).doit() == 0 + assert Rotation.d(2, 1, -1, pi/2).doit() == 1/2 + assert Rotation.d(2, 1, -2, pi/2).doit() == -1/2 + assert Rotation.d(2, 0, 2, pi/2).doit() == sqrt(6)/4 + assert Rotation.d(2, 0, 1, pi/2).doit() == 0 + assert Rotation.d(2, 0, 0, pi/2).doit() == -1/2 + assert Rotation.d(2, 0, -1, pi/2).doit() == 0 + assert Rotation.d(2, 0, -2, pi/2).doit() == sqrt(6)/4 + assert Rotation.d(2, -1, 2, pi/2).doit() == 1/2 + assert Rotation.d(2, -1, 1, pi/2).doit() == 1/2 + assert Rotation.d(2, -1, 0, pi/2).doit() == 0 + assert Rotation.d(2, -1, -1, pi/2).doit() == -1/2 + assert Rotation.d(2, -1, -2, pi/2).doit() == -1/2 + assert Rotation.d(2, -2, 2, pi/2).doit() == 1/4 + assert Rotation.d(2, -2, 1, pi/2).doit() == 1/2 + assert Rotation.d(2, -2, 0, pi/2).doit() == sqrt(6)/4 + assert Rotation.d(2, -2, -1, pi/2).doit() == 1/2 + assert Rotation.d(2, -2, -2, pi/2).doit() == 1/4 + def test_rotation_d(): # Symbolic tests # j = 1/2 - assert Rotation.D(S(1)/2,S(1)/2,S(1)/2,alpha,beta,gamma).doit() == cos(beta/2)*exp(-I*alpha/2)*exp(-I*gamma/2) - assert Rotation.D(S(1)/2,S(1)/2,-S(1)/2,alpha,beta,gamma).doit() == -sin(beta/2)*exp(-I*alpha/2)*exp(I*gamma/2) - assert Rotation.D(S(1)/2,-S(1)/2,S(1)/2,alpha,beta,gamma).doit() == sin(beta/2)*exp(I*alpha/2)*exp(-I*gamma/2) - assert Rotation.D(S(1)/2,-S(1)/2,-S(1)/2,alpha,beta,gamma).doit() == cos(beta/2)*exp(I*alpha/2)*exp(I*gamma/2) + assert Rotation.D(S(1)/2, S(1)/2, S(1)/2, alpha, beta, gamma).doit() == \ + cos(beta/2)*exp(-I*alpha/2)*exp(-I*gamma/2) + assert Rotation.D(S(1)/2, S(1)/2, -S(1)/2, alpha, beta, gamma).doit() == \ + -sin(beta/2)*exp(-I*alpha/2)*exp(I*gamma/2) + assert Rotation.D(S(1)/2, -S(1)/2, S(1)/2, alpha, beta, gamma).doit() == \ + sin(beta/2)*exp(I*alpha/2)*exp(-I*gamma/2) + assert Rotation.D(S(1)/2, -S(1)/2, -S(1)/2, alpha, beta, gamma).doit() == \ + cos(beta/2)*exp(I*alpha/2)*exp(I*gamma/2) # j = 1 - assert Rotation.D(1,1,1,alpha,beta,gamma).doit() == (1+cos(beta))/2*exp(-I*alpha)*exp(-I*gamma) - assert Rotation.D(1,1,0,alpha,beta,gamma).doit() == -sin(beta)/sqrt(2)*exp(-I*alpha) - assert Rotation.D(1,1,-1,alpha,beta,gamma).doit() == (1-cos(beta))/2*exp(-I*alpha)*exp(I*gamma) - assert Rotation.D(1,0,1,alpha,beta,gamma).doit() == sin(beta)/sqrt(2)*exp(-I*gamma) - assert Rotation.D(1,0,0,alpha,beta,gamma).doit() == cos(beta) - assert Rotation.D(1,0,-1,alpha,beta,gamma).doit() == -sin(beta)/sqrt(2)*exp(I*gamma) - assert Rotation.D(1,-1,1,alpha,beta,gamma).doit() == (1-cos(beta))/2*exp(I*alpha)*exp(-I*gamma) - assert Rotation.D(1,-1,0,alpha,beta,gamma).doit() == sin(beta)/sqrt(2)*exp(I*alpha) - assert Rotation.D(1,-1,-1,alpha,beta,gamma).doit() == (1+cos(beta))/2*exp(I*alpha)*exp(I*gamma) + assert Rotation.D(1, 1, 1, alpha, beta, gamma).doit() == \ + (1 + cos(beta))/2*exp(-I*alpha)*exp(-I*gamma) + assert Rotation.D(1, 1, 0, alpha, beta, gamma).doit() == -sin( + beta)/sqrt(2)*exp(-I*alpha) + assert Rotation.D(1, 1, -1, alpha, beta, gamma).doit() == \ + (1 - cos(beta))/2*exp(-I*alpha)*exp(I*gamma) + assert Rotation.D(1, 0, 1, alpha, beta, gamma).doit() == \ + sin(beta)/sqrt(2)*exp(-I*gamma) + assert Rotation.D(1, 0, 0, alpha, beta, gamma).doit() == cos(beta) + assert Rotation.D(1, 0, -1, alpha, beta, gamma).doit() == \ + -sin(beta)/sqrt(2)*exp(I*gamma) + assert Rotation.D(1, -1, 1, alpha, beta, gamma).doit() == \ + (1 - cos(beta))/2*exp(I*alpha)*exp(-I*gamma) + assert Rotation.D(1, -1, 0, alpha, beta, gamma).doit() == \ + sin(beta)/sqrt(2)*exp(I*alpha) + assert Rotation.D(1, -1, -1, alpha, beta, gamma).doit() == \ + (1 + cos(beta))/2*exp(I*alpha)*exp(I*gamma) # j = 3/2 - assert Rotation.D(S(3)/2,S(3)/2,S(3)/2,alpha,beta,gamma).doit() == (3*cos(beta/2)+cos(3*beta/2))/4*exp(-3*I*alpha/2)*exp(-3*I*gamma/2) - assert Rotation.D(S(3)/2,S(3)/2,S(1)/2,alpha,beta,gamma).doit() == sqrt(3)*(-sin(beta/2)-sin(3*beta/2))/4*exp(-3*I*alpha/2)*exp(-I*gamma/2) - assert Rotation.D(S(3)/2,S(3)/2,-S(1)/2,alpha,beta,gamma).doit() == sqrt(3)*(cos(beta/2)-cos(3*beta/2))/4*exp(-3*I*alpha/2)*exp(I*gamma/2) - assert Rotation.D(S(3)/2,S(3)/2,-S(3)/2,alpha,beta,gamma).doit() == (-3*sin(beta/2)+sin(3*beta/2))/4*exp(-3*I*alpha/2)*exp(3*I*gamma/2) - assert Rotation.D(S(3)/2,S(1)/2,S(3)/2,alpha,beta,gamma).doit() == sqrt(3)*(sin(beta/2)+sin(3*beta/2))/4*exp(-I*alpha/2)*exp(-3*I*gamma/2) - assert Rotation.D(S(3)/2,S(1)/2,S(1)/2,alpha,beta,gamma).doit() == (cos(beta/2)+3*cos(3*beta/2))/4*exp(-I*alpha/2)*exp(-I*gamma/2) - assert Rotation.D(S(3)/2,S(1)/2,-S(1)/2,alpha,beta,gamma).doit() == (sin(beta/2)-3*sin(3*beta/2))/4*exp(-I*alpha/2)*exp(I*gamma/2) - assert Rotation.D(S(3)/2,S(1)/2,-S(3)/2,alpha,beta,gamma).doit() == sqrt(3)*(cos(beta/2)-cos(3*beta/2))/4*exp(-I*alpha/2)*exp(3*I*gamma/2) - assert Rotation.D(S(3)/2,-S(1)/2,S(3)/2,alpha,beta,gamma).doit() == sqrt(3)*(cos(beta/2)-cos(3*beta/2))/4*exp(I*alpha/2)*exp(-3*I*gamma/2) - assert Rotation.D(S(3)/2,-S(1)/2,S(1)/2,alpha,beta,gamma).doit() == (-sin(beta/2)+3*sin(3*beta/2))/4*exp(I*alpha/2)*exp(-I*gamma/2) - assert Rotation.D(S(3)/2,-S(1)/2,-S(1)/2,alpha,beta,gamma).doit() == (cos(beta/2)+3*cos(3*beta/2))/4*exp(I*alpha/2)*exp(I*gamma/2) - assert Rotation.D(S(3)/2,-S(1)/2,-S(3)/2,alpha,beta,gamma).doit() == sqrt(3)*(-sin(beta/2)-sin(3*beta/2))/4*exp(I*alpha/2)*exp(3*I*gamma/2) - assert Rotation.D(S(3)/2,-S(3)/2,S(3)/2,alpha,beta,gamma).doit() == (3*sin(beta/2)-sin(3*beta/2))/4*exp(3*I*alpha/2)*exp(-3*I*gamma/2) - assert Rotation.D(S(3)/2,-S(3)/2,S(1)/2,alpha,beta,gamma).doit() == sqrt(3)*(cos(beta/2)-cos(3*beta/2))/4*exp(3*I*alpha/2)*exp(-I*gamma/2) - assert Rotation.D(S(3)/2,-S(3)/2,-S(1)/2,alpha,beta,gamma).doit() == sqrt(3)*(sin(beta/2)+sin(3*beta/2))/4*exp(3*I*alpha/2)*exp(I*gamma/2) - assert Rotation.D(S(3)/2,-S(3)/2,-S(3)/2,alpha,beta,gamma).doit() == (3*cos(beta/2)+cos(3*beta/2))/4*exp(3*I*alpha/2)*exp(3*I*gamma/2) + assert Rotation.D(S(3)/2, S(3)/2, S(3)/2, alpha, beta, gamma).doit() == \ + (3*cos(beta/2) + cos(3*beta/2))/4*exp(-3*I*alpha/2)*exp(-3*I*gamma/2) + assert Rotation.D(S(3)/2, S(3)/2, S(1)/2, alpha, beta, gamma).doit() == \ + -sqrt(3)*(sin(beta/2) + sin(3*beta/2))/4*exp(-3*I*alpha/2)*exp(-I*gamma/2) + assert Rotation.D(S(3)/2, S(3)/2, -S(1)/2, alpha, beta, gamma).doit() == \ + sqrt(3)*(cos(beta/2) - cos(3*beta/2))/4*exp(-3*I*alpha/2)*exp(I*gamma/2) + assert Rotation.D(S(3)/2, S(3)/2, -S(3)/2, alpha, beta, gamma).doit() == \ + (-3*sin(beta/2) + sin(3*beta/2))/4*exp(-3*I*alpha/2)*exp(3*I*gamma/2) + assert Rotation.D(S(3)/2, S(1)/2, S(3)/2, alpha, beta, gamma).doit() == \ + sqrt(3)*(sin(beta/2) + sin(3*beta/2))/4*exp(-I*alpha/2)*exp(-3*I*gamma/2) + assert Rotation.D(S(3)/2, S(1)/2, S(1)/2, alpha, beta, gamma).doit() == \ + (cos(beta/2) + 3*cos(3*beta/2))/4*exp(-I*alpha/2)*exp(-I*gamma/2) + assert Rotation.D(S(3)/2, S(1)/2, -S(1)/2, alpha, beta, gamma).doit() == \ + (sin(beta/2) - 3*sin(3*beta/2))/4*exp(-I*alpha/2)*exp(I*gamma/2) + assert Rotation.D(S(3)/2, S(1)/2, -S(3)/2, alpha, beta, gamma).doit() == \ + sqrt(3)*(cos(beta/2) - cos(3*beta/2))/4*exp(-I*alpha/2)*exp(3*I*gamma/2) + assert Rotation.D(S(3)/2, -S(1)/2, S(3)/2, alpha, beta, gamma).doit() == \ + sqrt(3)*(cos(beta/2) - cos(3*beta/2))/4*exp(I*alpha/2)*exp(-3*I*gamma/2) + assert Rotation.D(S(3)/2, -S(1)/2, S(1)/2, alpha, beta, gamma).doit() == \ + (-sin(beta/2) + 3*sin(3*beta/2))/4*exp(I*alpha/2)*exp(-I*gamma/2) + assert Rotation.D(S(3)/2, -S(1)/2, -S(1)/2, alpha, beta, gamma).doit() == \ + (cos(beta/2) + 3*cos(3*beta/2))/4*exp(I*alpha/2)*exp(I*gamma/2) + assert Rotation.D(S(3)/2, -S(1)/2, -S(3)/2, alpha, beta, gamma).doit() == \ + -sqrt(3)*(sin(beta/2) + sin(3*beta/2))/4*exp(I*alpha/2)*exp(3*I*gamma/2) + assert Rotation.D(S(3)/2, -S(3)/2, S(3)/2, alpha, beta, gamma).doit() == \ + (3*sin(beta/2) - sin(3*beta/2))/4*exp(3*I*alpha/2)*exp(-3*I*gamma/2) + assert Rotation.D(S(3)/2, -S(3)/2, S(1)/2, alpha, beta, gamma).doit() == \ + sqrt(3)*(cos(beta/2) - cos(3*beta/2))/4*exp(3*I*alpha/2)*exp(-I*gamma/2) + assert Rotation.D(S(3)/2, -S(3)/2, -S(1)/2, alpha, beta, gamma).doit() == \ + sqrt(3)*(sin(beta/2) + sin(3*beta/2))/4*exp(3*I*alpha/2)*exp(I*gamma/2) + assert Rotation.D(S(3)/2, -S(3)/2, -S(3)/2, alpha, beta, gamma).doit() == \ + (3*cos(beta/2) + cos(3*beta/2))/4*exp(3*I*alpha/2)*exp(3*I*gamma/2) # j = 2 - assert Rotation.D(2,2,2,alpha,beta,gamma).doit() == (3+4*cos(beta)+cos(2*beta))/8*exp(-2*I*alpha)*exp(-2*I*gamma) - assert Rotation.D(2,2,1,alpha,beta,gamma).doit() == (-2*sin(beta)-sin(2*beta))/4*exp(-2*I*alpha)*exp(-I*gamma) - assert Rotation.D(2,2,0,alpha,beta,gamma).doit() == sqrt(6)*(1-cos(2*beta))/8*exp(-2*I*alpha) - assert Rotation.D(2,2,-1,alpha,beta,gamma).doit() == (-2*sin(beta)+sin(2*beta))/4*exp(-2*I*alpha)*exp(I*gamma) - assert Rotation.D(2,2,-2,alpha,beta,gamma).doit() == (3-4*cos(beta)+cos(2*beta))/8*exp(-2*I*alpha)*exp(2*I*gamma) - assert Rotation.D(2,1,2,alpha,beta,gamma).doit() == (2*sin(beta)+sin(2*beta))/4*exp(-I*alpha)*exp(-2*I*gamma) - assert Rotation.D(2,1,1,alpha,beta,gamma).doit() == (cos(beta)+cos(2*beta))/2*exp(-I*alpha)*exp(-I*gamma) - assert Rotation.D(2,1,0,alpha,beta,gamma).doit() == -sqrt(6)*sin(2*beta)/4*exp(-I*alpha) - assert Rotation.D(2,1,-1,alpha,beta,gamma).doit() == (cos(beta)-cos(2*beta))/2*exp(-I*alpha)*exp(I*gamma) - assert Rotation.D(2,1,-2,alpha,beta,gamma).doit() == (-2*sin(beta)+sin(2*beta))/4*exp(-I*alpha)*exp(2*I*gamma) - assert Rotation.D(2,0,2,alpha,beta,gamma).doit() == sqrt(6)*(1-cos(2*beta))/8*exp(-2*I*gamma) - assert Rotation.D(2,0,1,alpha,beta,gamma).doit() == sqrt(6)*sin(2*beta)/4*exp(-I*gamma) - assert Rotation.D(2,0,0,alpha,beta,gamma).doit() == (1+3*cos(2*beta))/4 - assert Rotation.D(2,0,-1,alpha,beta,gamma).doit() == -sqrt(6)*sin(2*beta)/4*exp(I*gamma) - assert Rotation.D(2,0,-2,alpha,beta,gamma).doit() == sqrt(6)*(1-cos(2*beta))/8*exp(2*I*gamma) - assert Rotation.D(2,-1,2,alpha,beta,gamma).doit() == (2*sin(beta)-sin(2*beta))/4*exp(I*alpha)*exp(-2*I*gamma) - assert Rotation.D(2,-1,1,alpha,beta,gamma).doit() == (cos(beta)-cos(2*beta))/2*exp(I*alpha)*exp(-I*gamma) - assert Rotation.D(2,-1,0,alpha,beta,gamma).doit() == sqrt(6)*sin(2*beta)/4*exp(I*alpha) - assert Rotation.D(2,-1,-1,alpha,beta,gamma).doit() == (cos(beta)+cos(2*beta))/2*exp(I*alpha)*exp(I*gamma) - assert Rotation.D(2,-1,-2,alpha,beta,gamma).doit() == (-2*sin(beta)-sin(2*beta))/4*exp(I*alpha)*exp(2*I*gamma) - assert Rotation.D(2,-2,2,alpha,beta,gamma).doit() == (3-4*cos(beta)+cos(2*beta))/8*exp(2*I*alpha)*exp(-2*I*gamma) - assert Rotation.D(2,-2,1,alpha,beta,gamma).doit() == (2*sin(beta)-sin(2*beta))/4*exp(2*I*alpha)*exp(-I*gamma) - assert Rotation.D(2,-2,0,alpha,beta,gamma).doit() == sqrt(6)*(1-cos(2*beta))/8*exp(2*I*alpha) - assert Rotation.D(2,-2,-1,alpha,beta,gamma).doit() == (2*sin(beta)+sin(2*beta))/4*exp(2*I*alpha)*exp(I*gamma) - assert Rotation.D(2,-2,-2,alpha,beta,gamma).doit() == (3+4*cos(beta)+cos(2*beta))/8*exp(2*I*alpha)*exp(2*I*gamma) + assert Rotation.D(2, 2, 2, alpha, beta, gamma).doit() == \ + (3 + 4*cos(beta) + cos(2*beta))/8*exp(-2*I*alpha)*exp(-2*I*gamma) + assert Rotation.D(2, 2, 1, alpha, beta, gamma).doit() == \ + -((cos(beta) + 1)*exp(-2*I*alpha)*exp(-I*gamma)*sin(beta))/2 + assert Rotation.D(2, 2, 0, alpha, beta, gamma).doit() == \ + sqrt(6)*sin(beta)**2/4*exp(-2*I*alpha) + assert Rotation.D(2, 2, -1, alpha, beta, gamma).doit() == \ + (cos(beta) - 1)*sin(beta)/2*exp(-2*I*alpha)*exp(I*gamma) + assert Rotation.D(2, 2, -2, alpha, beta, gamma).doit() == \ + (3 - 4*cos(beta) + cos(2*beta))/8*exp(-2*I*alpha)*exp(2*I*gamma) + assert Rotation.D(2, 1, 2, alpha, beta, gamma).doit() == \ + (cos(beta) + 1)*sin(beta)/2*exp(-I*alpha)*exp(-2*I*gamma) + assert Rotation.D(2, 1, 1, alpha, beta, gamma).doit() == \ + (cos(beta) + cos(2*beta))/2*exp(-I*alpha)*exp(-I*gamma) + assert Rotation.D(2, 1, 0, alpha, beta, gamma).doit() == -sqrt(6)* \ + sin(2*beta)/4*exp(-I*alpha) + assert Rotation.D(2, 1, -1, alpha, beta, gamma).doit() == \ + (cos(beta) - cos(2*beta))/2*exp(-I*alpha)*exp(I*gamma) + assert Rotation.D(2, 1, -2, alpha, beta, gamma).doit() == \ + (cos(beta) - 1)*sin(beta)/2*exp(-I*alpha)*exp(2*I*gamma) + assert Rotation.D(2, 0, 2, alpha, beta, gamma).doit() == \ + sqrt(6)*sin(beta)**2/4*exp(-2*I*gamma) + assert Rotation.D(2, 0, 1, alpha, beta, gamma).doit() == sqrt(6)* \ + sin(2*beta)/4*exp(-I*gamma) + assert Rotation.D( + 2, 0, 0, alpha, beta, gamma).doit() == (1 + 3*cos(2*beta))/4 + assert Rotation.D(2, 0, -1, alpha, beta, gamma).doit() == -sqrt(6)* \ + sin(2*beta)/4*exp(I*gamma) + assert Rotation.D(2, 0, -2, alpha, beta, gamma).doit() == \ + sqrt(6)*sin(beta)**2/4*exp(2*I*gamma) + assert Rotation.D(2, -1, 2, alpha, beta, gamma).doit() == \ + (2*sin(beta) - sin(2*beta))/4*exp(I*alpha)*exp(-2*I*gamma) + assert Rotation.D(2, -1, 1, alpha, beta, gamma).doit() == \ + (cos(beta) - cos(2*beta))/2*exp(I*alpha)*exp(-I*gamma) + assert Rotation.D(2, -1, 0, alpha, beta, gamma).doit() == sqrt(6)* \ + sin(2*beta)/4*exp(I*alpha) + assert Rotation.D(2, -1, -1, alpha, beta, gamma).doit() == \ + (cos(beta) + cos(2*beta))/2*exp(I*alpha)*exp(I*gamma) + assert Rotation.D(2, -1, -2, alpha, beta, gamma).doit() == \ + -((cos(beta) + 1)*sin(beta))/2*exp(I*alpha)*exp(2*I*gamma) + assert Rotation.D(2, -2, 2, alpha, beta, gamma).doit() == \ + (3 - 4*cos(beta) + cos(2*beta))/8*exp(2*I*alpha)*exp(-2*I*gamma) + assert Rotation.D(2, -2, 1, alpha, beta, gamma).doit() == \ + (2*sin(beta) - sin(2*beta))/4*exp(2*I*alpha)*exp(-I*gamma) + assert Rotation.D(2, -2, 0, alpha, beta, gamma).doit() == \ + sqrt(6)*sin(beta)**2/4*exp(2*I*alpha) + assert Rotation.D(2, -2, -1, alpha, beta, gamma).doit() == \ + (cos(beta) + 1)*sin(beta)/2*exp(2*I*alpha)*exp(I*gamma) + assert Rotation.D(2, -2, -2, alpha, beta, gamma).doit() == \ + (3 + 4*cos(beta) + cos(2*beta))/8*exp(2*I*alpha)*exp(2*I*gamma) # Numerical tests # j = 1/2 - assert Rotation.D(S(1)/2,S(1)/2,S(1)/2,pi/2,pi/2,pi/2).doit() == -I*sqrt(2)/2 - assert Rotation.D(S(1)/2,S(1)/2,-S(1)/2,pi/2,pi/2,pi/2).doit() == -sqrt(2)/2 - assert Rotation.D(S(1)/2,-S(1)/2,S(1)/2,pi/2,pi/2,pi/2).doit() == sqrt(2)/2 - assert Rotation.D(S(1)/2,-S(1)/2,-S(1)/2,pi/2,pi/2,pi/2).doit() == I*sqrt(2)/2 + assert Rotation.D( + S(1)/2, S(1)/2, S(1)/2, pi/2, pi/2, pi/2).doit() == -I*sqrt(2)/2 + assert Rotation.D( + S(1)/2, S(1)/2, -S(1)/2, pi/2, pi/2, pi/2).doit() == -sqrt(2)/2 + assert Rotation.D( + S(1)/2, -S(1)/2, S(1)/2, pi/2, pi/2, pi/2).doit() == sqrt(2)/2 + assert Rotation.D( + S(1)/2, -S(1)/2, -S(1)/2, pi/2, pi/2, pi/2).doit() == I*sqrt(2)/2 # j = 1 - assert Rotation.D(1,1,1,pi/2,pi/2,pi/2).doit() == -1/2 - assert Rotation.D(1,1,0,pi/2,pi/2,pi/2).doit() == I*sqrt(2)/2 - assert Rotation.D(1,1,-1,pi/2,pi/2,pi/2).doit() == 1/2 - assert Rotation.D(1,0,1,pi/2,pi/2,pi/2).doit() == -I*sqrt(2)/2 - assert Rotation.D(1,0,0,pi/2,pi/2,pi/2).doit() == 0 - assert Rotation.D(1,0,-1,pi/2,pi/2,pi/2).doit() == -I*sqrt(2)/2 - assert Rotation.D(1,-1,1,pi/2,pi/2,pi/2).doit() == 1/2 - assert Rotation.D(1,-1,0,pi/2,pi/2,pi/2).doit() == I*sqrt(2)/2 - assert Rotation.D(1,-1,-1,pi/2,pi/2,pi/2).doit() == -1/2 + assert Rotation.D(1, 1, 1, pi/2, pi/2, pi/2).doit() == -1/2 + assert Rotation.D(1, 1, 0, pi/2, pi/2, pi/2).doit() == I*sqrt(2)/2 + assert Rotation.D(1, 1, -1, pi/2, pi/2, pi/2).doit() == 1/2 + assert Rotation.D(1, 0, 1, pi/2, pi/2, pi/2).doit() == -I*sqrt(2)/2 + assert Rotation.D(1, 0, 0, pi/2, pi/2, pi/2).doit() == 0 + assert Rotation.D(1, 0, -1, pi/2, pi/2, pi/2).doit() == -I*sqrt(2)/2 + assert Rotation.D(1, -1, 1, pi/2, pi/2, pi/2).doit() == 1/2 + assert Rotation.D(1, -1, 0, pi/2, pi/2, pi/2).doit() == I*sqrt(2)/2 + assert Rotation.D(1, -1, -1, pi/2, pi/2, pi/2).doit() == -1/2 # j = 3/2 - assert Rotation.D(S(3)/2,S(3)/2,S(3)/2,pi/2,pi/2,pi/2).doit() == I*sqrt(2)/4 - assert Rotation.D(S(3)/2,S(3)/2,S(1)/2,pi/2,pi/2,pi/2).doit() == sqrt(6)/4 - assert Rotation.D(S(3)/2,S(3)/2,-S(1)/2,pi/2,pi/2,pi/2).doit() == -I*sqrt(6)/4 - assert Rotation.D(S(3)/2,S(3)/2,-S(3)/2,pi/2,pi/2,pi/2).doit() == -sqrt(2)/4 - assert Rotation.D(S(3)/2,S(1)/2,S(3)/2,pi/2,pi/2,pi/2).doit() == -sqrt(6)/4 - assert Rotation.D(S(3)/2,S(1)/2,S(1)/2,pi/2,pi/2,pi/2).doit() == I*sqrt(2)/4 - assert Rotation.D(S(3)/2,S(1)/2,-S(1)/2,pi/2,pi/2,pi/2).doit() == -sqrt(2)/4 - assert Rotation.D(S(3)/2,S(1)/2,-S(3)/2,pi/2,pi/2,pi/2).doit() == I*sqrt(6)/4 - assert Rotation.D(S(3)/2,-S(1)/2,S(3)/2,pi/2,pi/2,pi/2).doit() == -I*sqrt(6)/4 - assert Rotation.D(S(3)/2,-S(1)/2,S(1)/2,pi/2,pi/2,pi/2).doit() == sqrt(2)/4 - assert Rotation.D(S(3)/2,-S(1)/2,-S(1)/2,pi/2,pi/2,pi/2).doit() == -I*sqrt(2)/4 - assert Rotation.D(S(3)/2,-S(1)/2,-S(3)/2,pi/2,pi/2,pi/2).doit() == sqrt(6)/4 - assert Rotation.D(S(3)/2,-S(3)/2,S(3)/2,pi/2,pi/2,pi/2).doit() == sqrt(2)/4 - assert Rotation.D(S(3)/2,-S(3)/2,S(1)/2,pi/2,pi/2,pi/2).doit() == I*sqrt(6)/4 - assert Rotation.D(S(3)/2,-S(3)/2,-S(1)/2,pi/2,pi/2,pi/2).doit() == -sqrt(6)/4 - assert Rotation.D(S(3)/2,-S(3)/2,-S(3)/2,pi/2,pi/2,pi/2).doit() == -I*sqrt(2)/4 + assert Rotation.D( + S(3)/2, S(3)/2, S(3)/2, pi/2, pi/2, pi/2).doit() == I*sqrt(2)/4 + assert Rotation.D( + S(3)/2, S(3)/2, S(1)/2, pi/2, pi/2, pi/2).doit() == sqrt(6)/4 + assert Rotation.D( + S(3)/2, S(3)/2, -S(1)/2, pi/2, pi/2, pi/2).doit() == -I*sqrt(6)/4 + assert Rotation.D( + S(3)/2, S(3)/2, -S(3)/2, pi/2, pi/2, pi/2).doit() == -sqrt(2)/4 + assert Rotation.D( + S(3)/2, S(1)/2, S(3)/2, pi/2, pi/2, pi/2).doit() == -sqrt(6)/4 + assert Rotation.D( + S(3)/2, S(1)/2, S(1)/2, pi/2, pi/2, pi/2).doit() == I*sqrt(2)/4 + assert Rotation.D( + S(3)/2, S(1)/2, -S(1)/2, pi/2, pi/2, pi/2).doit() == -sqrt(2)/4 + assert Rotation.D( + S(3)/2, S(1)/2, -S(3)/2, pi/2, pi/2, pi/2).doit() == I*sqrt(6)/4 + assert Rotation.D( + S(3)/2, -S(1)/2, S(3)/2, pi/2, pi/2, pi/2).doit() == -I*sqrt(6)/4 + assert Rotation.D( + S(3)/2, -S(1)/2, S(1)/2, pi/2, pi/2, pi/2).doit() == sqrt(2)/4 + assert Rotation.D( + S(3)/2, -S(1)/2, -S(1)/2, pi/2, pi/2, pi/2).doit() == -I*sqrt(2)/4 + assert Rotation.D( + S(3)/2, -S(1)/2, -S(3)/2, pi/2, pi/2, pi/2).doit() == sqrt(6)/4 + assert Rotation.D( + S(3)/2, -S(3)/2, S(3)/2, pi/2, pi/2, pi/2).doit() == sqrt(2)/4 + assert Rotation.D( + S(3)/2, -S(3)/2, S(1)/2, pi/2, pi/2, pi/2).doit() == I*sqrt(6)/4 + assert Rotation.D( + S(3)/2, -S(3)/2, -S(1)/2, pi/2, pi/2, pi/2).doit() == -sqrt(6)/4 + assert Rotation.D( + S(3)/2, -S(3)/2, -S(3)/2, pi/2, pi/2, pi/2).doit() == -I*sqrt(2)/4 # j = 2 - assert Rotation.D(2,2,2,pi/2,pi/2,pi/2).doit() == 1/4 - assert Rotation.D(2,2,1,pi/2,pi/2,pi/2).doit() == -I/2 - assert Rotation.D(2,2,0,pi/2,pi/2,pi/2).doit() == -sqrt(6)/4 - assert Rotation.D(2,2,-1,pi/2,pi/2,pi/2).doit() == I/2 - assert Rotation.D(2,2,-2,pi/2,pi/2,pi/2).doit() == 1/4 - assert Rotation.D(2,1,2,pi/2,pi/2,pi/2).doit() == I/2 - assert Rotation.D(2,1,1,pi/2,pi/2,pi/2).doit() == 1/2 - assert Rotation.D(2,1,0,pi/2,pi/2,pi/2).doit() == 0 - assert Rotation.D(2,1,-1,pi/2,pi/2,pi/2).doit() == 1/2 - assert Rotation.D(2,1,-2,pi/2,pi/2,pi/2).doit() == -I/2 - assert Rotation.D(2,0,2,pi/2,pi/2,pi/2).doit() == -sqrt(6)/4 - assert Rotation.D(2,0,1,pi/2,pi/2,pi/2).doit() == 0 - assert Rotation.D(2,0,0,pi/2,pi/2,pi/2).doit() == -1/2 - assert Rotation.D(2,0,-1,pi/2,pi/2,pi/2).doit() == 0 - assert Rotation.D(2,0,-2,pi/2,pi/2,pi/2).doit() == -sqrt(6)/4 - assert Rotation.D(2,-1,2,pi/2,pi/2,pi/2).doit() == -I/2 - assert Rotation.D(2,-1,1,pi/2,pi/2,pi/2).doit() == 1/2 - assert Rotation.D(2,-1,0,pi/2,pi/2,pi/2).doit() == 0 - assert Rotation.D(2,-1,-1,pi/2,pi/2,pi/2).doit() == 1/2 - assert Rotation.D(2,-1,-2,pi/2,pi/2,pi/2).doit() == I/2 - assert Rotation.D(2,-2,2,pi/2,pi/2,pi/2).doit() == 1/4 - assert Rotation.D(2,-2,1,pi/2,pi/2,pi/2).doit() == I/2 - assert Rotation.D(2,-2,0,pi/2,pi/2,pi/2).doit() == -sqrt(6)/4 - assert Rotation.D(2,-2,-1,pi/2,pi/2,pi/2).doit() == -I/2 - assert Rotation.D(2,-2,-2,pi/2,pi/2,pi/2).doit() == 1/4 + assert Rotation.D(2, 2, 2, pi/2, pi/2, pi/2).doit() == 1/4 + assert Rotation.D(2, 2, 1, pi/2, pi/2, pi/2).doit() == -I/2 + assert Rotation.D(2, 2, 0, pi/2, pi/2, pi/2).doit() == -sqrt(6)/4 + assert Rotation.D(2, 2, -1, pi/2, pi/2, pi/2).doit() == I/2 + assert Rotation.D(2, 2, -2, pi/2, pi/2, pi/2).doit() == 1/4 + assert Rotation.D(2, 1, 2, pi/2, pi/2, pi/2).doit() == I/2 + assert Rotation.D(2, 1, 1, pi/2, pi/2, pi/2).doit() == 1/2 + assert Rotation.D(2, 1, 0, pi/2, pi/2, pi/2).doit() == 0 + assert Rotation.D(2, 1, -1, pi/2, pi/2, pi/2).doit() == 1/2 + assert Rotation.D(2, 1, -2, pi/2, pi/2, pi/2).doit() == -I/2 + assert Rotation.D(2, 0, 2, pi/2, pi/2, pi/2).doit() == -sqrt(6)/4 + assert Rotation.D(2, 0, 1, pi/2, pi/2, pi/2).doit() == 0 + assert Rotation.D(2, 0, 0, pi/2, pi/2, pi/2).doit() == -1/2 + assert Rotation.D(2, 0, -1, pi/2, pi/2, pi/2).doit() == 0 + assert Rotation.D(2, 0, -2, pi/2, pi/2, pi/2).doit() == -sqrt(6)/4 + assert Rotation.D(2, -1, 2, pi/2, pi/2, pi/2).doit() == -I/2 + assert Rotation.D(2, -1, 1, pi/2, pi/2, pi/2).doit() == 1/2 + assert Rotation.D(2, -1, 0, pi/2, pi/2, pi/2).doit() == 0 + assert Rotation.D(2, -1, -1, pi/2, pi/2, pi/2).doit() == 1/2 + assert Rotation.D(2, -1, -2, pi/2, pi/2, pi/2).doit() == I/2 + assert Rotation.D(2, -2, 2, pi/2, pi/2, pi/2).doit() == 1/4 + assert Rotation.D(2, -2, 1, pi/2, pi/2, pi/2).doit() == I/2 + assert Rotation.D(2, -2, 0, pi/2, pi/2, pi/2).doit() == -sqrt(6)/4 + assert Rotation.D(2, -2, -1, pi/2, pi/2, pi/2).doit() == -I/2 + assert Rotation.D(2, -2, -2, pi/2, pi/2, pi/2).doit() == 1/4 + def test_wignerd(): - assert Rotation.D(j, m, mp, alpha, beta, gamma) == WignerD(j, m, mp, alpha, beta, gamma) + assert Rotation.D( + j, m, mp, alpha, beta, gamma) == WignerD(j, m, mp, alpha, beta, gamma) assert Rotation.d(j, m, mp, beta) == WignerD(j, m, mp, 0, beta, 0) + def test_jplus(): assert Commutator(Jplus, Jminus).doit() == 2*hbar*Jz - assert Jplus.matrix_element(1,1,1,1) == 0 + assert Jplus.matrix_element(1, 1, 1, 1) == 0 assert Jplus.rewrite('xyz') == Jx + I*Jy # Normal operators, normal states # Numerical - assert qapply(Jplus*JxKet(1,1)) == -hbar*sqrt(2)*JxKet(1,0)/2+hbar*JxKet(1,1) - assert qapply(Jplus*JyKet(1,1)) == hbar*sqrt(2)*JyKet(1,0)/2 + I*hbar*JyKet(1,1) - assert qapply(Jplus*JzKet(1,1)) == 0 - # Symbolic - assert qapply(Jplus*JxKet(j,m)) == \ - Sum(hbar * sqrt(-mi**2-mi+j**2+j) * WignerD(j,mi,m,0,pi/2,0) * \ - Sum(WignerD(j,mi1,mi+1,0,3*pi/2,0) * JxKet(j, mi1), \ - (mi1,-j,j)), (mi,-j,j)) - assert qapply(Jplus*JyKet(j,m)) == \ - Sum(hbar * sqrt(j**2+j-mi**2- mi) * WignerD(j,mi,m,3*pi/2,-pi/2,pi/2) * \ - Sum(WignerD(j,mi1,mi+1,3*pi/2,pi/2,pi/2) * JyKet(j,mi1), - (mi1,-j,j)), (mi,-j,j)) - assert qapply(Jplus*JzKet(j,m)) == \ - hbar*sqrt(j**2+j-m**2-m)*JzKet(j,m+1) + assert qapply(Jplus*JxKet(1, 1)) == \ + -hbar*sqrt(2)*JxKet(1, 0)/2 + hbar*JxKet(1, 1) + assert qapply(Jplus*JyKet(1, 1)) == \ + hbar*sqrt(2)*JyKet(1, 0)/2 + I*hbar*JyKet(1, 1) + assert qapply(Jplus*JzKet(1, 1)) == 0 + # Symbolic + assert qapply(Jplus*JxKet(j, m)) == \ + Sum(hbar * sqrt(-mi**2 - mi + j**2 + j) * WignerD(j, mi, m, 0, pi/2, 0) * + Sum(WignerD(j, mi1, mi + 1, 0, 3*pi/2, 0) * JxKet(j, mi1), + (mi1, -j, j)), (mi, -j, j)) + assert qapply(Jplus*JyKet(j, m)) == \ + Sum(hbar * sqrt(j**2 + j - mi**2 - mi) * WignerD(j, mi, m, 3*pi/2, -pi/2, pi/2) * + Sum(WignerD(j, mi1, mi + 1, 3*pi/2, pi/2, pi/2) * JyKet(j, mi1), + (mi1, -j, j)), (mi, -j, j)) + assert qapply(Jplus*JzKet(j, m)) == \ + hbar*sqrt(j**2 + j - m**2 - m)*JzKet(j, m + 1) # Normal operators, coupled states # Numerical - assert qapply(Jplus*JxKetCoupled(1,1,(1,1))) == -hbar*sqrt(2)*JxKetCoupled(1,0,(1,1))/2+hbar*JxKetCoupled(1,1,(1,1)) - assert qapply(Jplus*JyKetCoupled(1,1,(1,1))) == hbar*sqrt(2)*JyKetCoupled(1,0,(1,1))/2 + I*hbar*JyKetCoupled(1,1,(1,1)) - assert qapply(Jplus*JzKet(1,1)) == 0 - # Symbolic - assert qapply(Jplus*JxKetCoupled(j,m,(j1,j2))) == \ - Sum(hbar * sqrt(-mi**2-mi+j**2+j) * WignerD(j,mi,m,0,pi/2,0) * \ - Sum(WignerD(j,mi1,mi+1,0,3*pi/2,0) * JxKetCoupled(j, mi1, (j1,j2)), \ - (mi1,-j,j)), (mi,-j,j)) - assert qapply(Jplus*JyKetCoupled(j,m,(j1,j2))) == \ - Sum(hbar * sqrt(j**2+j-mi**2- mi) * WignerD(j,mi,m,3*pi/2,-pi/2,pi/2) * \ - Sum(WignerD(j,mi1,mi+1,3*pi/2,pi/2,pi/2) * JyKetCoupled(j,mi1,(j1,j2)), - (mi1,-j,j)), (mi,-j,j)) - assert qapply(Jplus*JzKetCoupled(j,m,(j1,j2))) == \ - hbar*sqrt(j**2+j-m**2-m)*JzKetCoupled(j,m+1,(j1,j2)) + assert qapply(Jplus*JxKetCoupled(1, 1, (1, 1))) == -hbar*sqrt(2) * \ + JxKetCoupled(1, 0, (1, 1))/2 + hbar*JxKetCoupled(1, 1, (1, 1)) + assert qapply(Jplus*JyKetCoupled(1, 1, (1, 1))) == hbar*sqrt(2) * \ + JyKetCoupled(1, 0, (1, 1))/2 + I*hbar*JyKetCoupled(1, 1, (1, 1)) + assert qapply(Jplus*JzKet(1, 1)) == 0 + # Symbolic + assert qapply(Jplus*JxKetCoupled(j, m, (j1, j2))) == \ + Sum(hbar * sqrt(-mi**2 - mi + j**2 + j) * WignerD(j, mi, m, 0, pi/2, 0) * + Sum( + WignerD( + j, mi1, mi + 1, 0, 3*pi/2, 0) * JxKetCoupled(j, mi1, (j1, j2)), + (mi1, -j, j)), (mi, -j, j)) + assert qapply(Jplus*JyKetCoupled(j, m, (j1, j2))) == \ + Sum(hbar * sqrt(j**2 + j - mi**2 - mi) * WignerD(j, mi, m, 3*pi/2, -pi/2, pi/2) * + Sum( + WignerD(j, mi1, mi + 1, 3*pi/2, pi/2, pi/2) * + JyKetCoupled(j, mi1, (j1, j2)), + (mi1, -j, j)), (mi, -j, j)) + assert qapply(Jplus*JzKetCoupled(j, m, (j1, j2))) == \ + hbar*sqrt(j**2 + j - m**2 - m)*JzKetCoupled(j, m + 1, (j1, j2)) # Uncoupled operators, uncoupled states # Numerical - assert qapply(TensorProduct(Jplus,1)*TensorProduct(JxKet(1,1),JxKet(1,-1))) == \ - -hbar*sqrt(2)*TensorProduct(JxKet(1,0),JxKet(1,-1))/2 + \ - hbar*TensorProduct(JxKet(1,1),JxKet(1,-1)) - assert qapply(TensorProduct(1,Jplus)*TensorProduct(JxKet(1,1),JxKet(1,-1))) == \ - -hbar*TensorProduct(JxKet(1,1),JxKet(1,-1)) + \ - hbar*sqrt(2)*TensorProduct(JxKet(1,1),JxKet(1,0))/2 - assert qapply(TensorProduct(Jplus,1)*TensorProduct(JyKet(1,1),JyKet(1,-1))) == \ - hbar*sqrt(2)*TensorProduct(JyKet(1,0),JyKet(1,-1))/2 + \ - hbar*I*TensorProduct(JyKet(1,1),JyKet(1,-1)) - assert qapply(TensorProduct(1,Jplus)*TensorProduct(JyKet(1,1),JyKet(1,-1))) == \ - -hbar*I*TensorProduct(JyKet(1,1),JyKet(1,-1)) + \ - hbar*sqrt(2)*TensorProduct(JyKet(1,1),JyKet(1,0))/2 - assert qapply(TensorProduct(Jplus,1)*TensorProduct(JzKet(1,1),JzKet(1,-1))) == 0 - assert qapply(TensorProduct(1,Jplus)*TensorProduct(JzKet(1,1),JzKet(1,-1))) == \ - hbar*sqrt(2)*TensorProduct(JzKet(1,1),JzKet(1,0)) - # Symbolic - assert qapply(TensorProduct(Jplus,1)*TensorProduct(JxKet(j1,m1),JxKet(j2,m2))) == \ - TensorProduct(Sum(hbar * sqrt(-mi**2-mi+j1**2+j1) * WignerD(j1,mi,m1,0,pi/2,0) * \ - Sum(WignerD(j1,mi1,mi+1,0,3*pi/2,0) * JxKet(j1, mi1), \ - (mi1,-j1,j1)), (mi,-j1,j1)), JxKet(j2,m2)) - assert qapply(TensorProduct(1,Jplus)*TensorProduct(JxKet(j1,m1),JxKet(j2,m2))) == \ - TensorProduct(JxKet(j1,m1), Sum(hbar * sqrt(-mi**2-mi+j2**2+j2) * WignerD(j2,mi,m2,0,pi/2,0) * \ - Sum(WignerD(j2,mi1,mi+1,0,3*pi/2,0) * JxKet(j2, mi1), \ - (mi1,-j2,j2)), (mi,-j2,j2))) - assert qapply(TensorProduct(Jplus,1)*TensorProduct(JyKet(j1,m1),JyKet(j2,m2))) == \ - TensorProduct(Sum(hbar * sqrt(j1**2+j1-mi**2- mi) * WignerD(j1,mi,m1,3*pi/2,-pi/2,pi/2) * \ - Sum(WignerD(j1,mi1,mi+1,3*pi/2,pi/2,pi/2) * JyKet(j1,mi1), - (mi1,-j1,j1)), (mi,-j1,j1)), JyKet(j2,m2)) - assert qapply(TensorProduct(1,Jplus)*TensorProduct(JyKet(j1,m1),JyKet(j2,m2))) == \ - TensorProduct(JyKet(j1,m1), Sum(hbar * sqrt(j2**2+j2-mi**2- mi) * WignerD(j2,mi,m2,3*pi/2,-pi/2,pi/2) * \ - Sum(WignerD(j2,mi1,mi+1,3*pi/2,pi/2,pi/2) * JyKet(j2,mi1), - (mi1,-j2,j2)), (mi,-j2,j2))) - assert qapply(TensorProduct(Jplus,1)*TensorProduct(JzKet(j1,m1),JzKet(j2,m2))) == \ - hbar*sqrt(j1**2+j1-m1**2-m1)*TensorProduct(JzKet(j1,m1+1),JzKet(j2,m2)) - assert qapply(TensorProduct(1,Jplus)*TensorProduct(JzKet(j1,m1),JzKet(j2,m2))) == \ - hbar*sqrt(j2**2+j2-m2**2-m2)*TensorProduct(JzKet(j1,m1),JzKet(j2,m2+1)) + assert qapply(TensorProduct(Jplus, 1)*TensorProduct(JxKet(1, 1), JxKet(1, -1))) == \ + -hbar*sqrt(2)*TensorProduct(JxKet(1, 0), JxKet(1, -1))/2 + \ + hbar*TensorProduct(JxKet(1, 1), JxKet(1, -1)) + assert qapply(TensorProduct(1, Jplus)*TensorProduct(JxKet(1, 1), JxKet(1, -1))) == \ + -hbar*TensorProduct(JxKet(1, 1), JxKet(1, -1)) + \ + hbar*sqrt(2)*TensorProduct(JxKet(1, 1), JxKet(1, 0))/2 + assert qapply(TensorProduct(Jplus, 1)*TensorProduct(JyKet(1, 1), JyKet(1, -1))) == \ + hbar*sqrt(2)*TensorProduct(JyKet(1, 0), JyKet(1, -1))/2 + \ + hbar*I*TensorProduct(JyKet(1, 1), JyKet(1, -1)) + assert qapply(TensorProduct(1, Jplus)*TensorProduct(JyKet(1, 1), JyKet(1, -1))) == \ + -hbar*I*TensorProduct(JyKet(1, 1), JyKet(1, -1)) + \ + hbar*sqrt(2)*TensorProduct(JyKet(1, 1), JyKet(1, 0))/2 + assert qapply( + TensorProduct(Jplus, 1)*TensorProduct(JzKet(1, 1), JzKet(1, -1))) == 0 + assert qapply(TensorProduct(1, Jplus)*TensorProduct(JzKet(1, 1), JzKet(1, -1))) == \ + hbar*sqrt(2)*TensorProduct(JzKet(1, 1), JzKet(1, 0)) + # Symbolic + assert qapply(TensorProduct(Jplus, 1)*TensorProduct(JxKet(j1, m1), JxKet(j2, m2))) == \ + TensorProduct(Sum(hbar * sqrt(-mi**2 - mi + j1**2 + j1) * WignerD(j1, mi, m1, 0, pi/2, 0) * + Sum(WignerD(j1, mi1, mi + 1, 0, 3*pi/2, 0) * JxKet(j1, mi1), + (mi1, -j1, j1)), (mi, -j1, j1)), JxKet(j2, m2)) + assert qapply(TensorProduct(1, Jplus)*TensorProduct(JxKet(j1, m1), JxKet(j2, m2))) == \ + TensorProduct(JxKet(j1, m1), Sum(hbar * sqrt(-mi**2 - mi + j2**2 + j2) * WignerD(j2, mi, m2, 0, pi/2, 0) * + Sum(WignerD(j2, mi1, mi + 1, 0, 3*pi/2, 0) * JxKet(j2, mi1), + (mi1, -j2, j2)), (mi, -j2, j2))) + assert qapply(TensorProduct(Jplus, 1)*TensorProduct(JyKet(j1, m1), JyKet(j2, m2))) == \ + TensorProduct(Sum(hbar * sqrt(j1**2 + j1 - mi**2 - mi) * WignerD(j1, mi, m1, 3*pi/2, -pi/2, pi/2) * + Sum(WignerD(j1, mi1, mi + 1, 3*pi/2, pi/2, pi/2) * JyKet(j1, mi1), + (mi1, -j1, j1)), (mi, -j1, j1)), JyKet(j2, m2)) + assert qapply(TensorProduct(1, Jplus)*TensorProduct(JyKet(j1, m1), JyKet(j2, m2))) == \ + TensorProduct(JyKet(j1, m1), Sum(hbar * sqrt(j2**2 + j2 - mi**2 - mi) * WignerD(j2, mi, m2, 3*pi/2, -pi/2, pi/2) * + Sum(WignerD(j2, mi1, mi + 1, 3*pi/2, pi/2, pi/2) * JyKet(j2, mi1), + (mi1, -j2, j2)), (mi, -j2, j2))) + assert qapply(TensorProduct(Jplus, 1)*TensorProduct(JzKet(j1, m1), JzKet(j2, m2))) == \ + hbar*sqrt( + j1**2 + j1 - m1**2 - m1)*TensorProduct(JzKet(j1, m1 + 1), JzKet(j2, m2)) + assert qapply(TensorProduct(1, Jplus)*TensorProduct(JzKet(j1, m1), JzKet(j2, m2))) == \ + hbar*sqrt( + j2**2 + j2 - m2**2 - m2)*TensorProduct(JzKet(j1, m1), JzKet(j2, m2 + 1)) + def test_jminus(): - assert qapply(Jminus*JzKet(1,-1)) == 0 - assert Jminus.matrix_element(1,0,1,1) == sqrt(2)*hbar + assert qapply(Jminus*JzKet(1, -1)) == 0 + assert Jminus.matrix_element(1, 0, 1, 1) == sqrt(2)*hbar assert Jminus.rewrite('xyz') == Jx - I*Jy # Normal operators, normal states # Numerical - assert qapply(Jminus*JxKet(1,1)) == hbar*sqrt(2)*JxKet(1,0)/2+hbar*JxKet(1,1) - assert qapply(Jminus*JyKet(1,1)) == hbar*sqrt(2)*JyKet(1,0)/2-hbar*I*JyKet(1,1) - assert qapply(Jminus*JzKet(1,1)) == sqrt(2)*hbar*JzKet(1,0) - # Symbolic - assert qapply(Jminus*JxKet(j,m)) == \ - Sum(hbar*sqrt(j**2+j-mi**2+mi)*WignerD(j,mi,m,0,pi/2,0) * \ - Sum(WignerD(j,mi1,mi-1,0,3*pi/2,0)*JxKet(j,mi1), \ - (mi1,-j,j)), (mi,-j,j)) - assert qapply(Jminus*JyKet(j,m)) == \ - Sum(hbar*sqrt(j**2+j-mi**2+mi)*WignerD(j,mi,m,3*pi/2,-pi/2,pi/2) * \ - Sum(WignerD(j,mi1,mi-1,3*pi/2,pi/2,pi/2)*JyKet(j,mi1), \ - (mi1,-j,j)), (mi,-j,j)) - assert qapply(Jminus*JzKet(j,m)) == \ - hbar*sqrt(j**2+j-m**2+m)*JzKet(j,m-1) + assert qapply(Jminus*JxKet(1, 1)) == \ + hbar*sqrt(2)*JxKet(1, 0)/2 + hbar*JxKet(1, 1) + assert qapply(Jminus*JyKet(1, 1)) == \ + hbar*sqrt(2)*JyKet(1, 0)/2 - hbar*I*JyKet(1, 1) + assert qapply(Jminus*JzKet(1, 1)) == sqrt(2)*hbar*JzKet(1, 0) + # Symbolic + assert qapply(Jminus*JxKet(j, m)) == \ + Sum(hbar*sqrt(j**2 + j - mi**2 + mi)*WignerD(j, mi, m, 0, pi/2, 0) * + Sum(WignerD(j, mi1, mi - 1, 0, 3*pi/2, 0)*JxKet(j, mi1), + (mi1, -j, j)), (mi, -j, j)) + assert qapply(Jminus*JyKet(j, m)) == \ + Sum(hbar*sqrt(j**2 + j - mi**2 + mi)*WignerD(j, mi, m, 3*pi/2, -pi/2, pi/2) * + Sum(WignerD(j, mi1, mi - 1, 3*pi/2, pi/2, pi/2)*JyKet(j, mi1), + (mi1, -j, j)), (mi, -j, j)) + assert qapply(Jminus*JzKet(j, m)) == \ + hbar*sqrt(j**2 + j - m**2 + m)*JzKet(j, m - 1) # Normal operators, coupled states # Numerical - assert qapply(Jminus*JxKetCoupled(1,1,(1,1))) == \ - hbar*sqrt(2)*JxKetCoupled(1,0,(1,1))/2 + \ - hbar*JxKetCoupled(1,1,(1,1)) - assert qapply(Jminus*JyKetCoupled(1,1,(1,1))) == \ - hbar*sqrt(2)*JyKetCoupled(1,0,(1,1))/2 - \ - hbar*I*JyKetCoupled(1,1,(1,1)) - assert qapply(Jminus*JzKetCoupled(1,1,(1,1))) == \ - sqrt(2)*hbar*JzKetCoupled(1,0,(1,1)) - # Symbolic - assert qapply(Jminus*JxKetCoupled(j,m,(j1,j2))) == \ - Sum(hbar*sqrt(j**2+j-mi**2+mi)*WignerD(j,mi,m,0,pi/2,0) * \ - Sum(WignerD(j,mi1,mi-1,0,3*pi/2,0)*JxKetCoupled(j,mi1,(j1,j2)), \ - (mi1,-j,j)), (mi,-j,j)) - assert qapply(Jminus*JyKetCoupled(j,m,(j1,j2))) == \ - Sum(hbar*sqrt(j**2+j-mi**2+mi)*WignerD(j,mi,m,3*pi/2,-pi/2,pi/2) * \ - Sum(WignerD(j,mi1,mi-1,3*pi/2,pi/2,pi/2)*JyKetCoupled(j,mi1,(j1,j2)), \ - (mi1,-j,j)), (mi,-j,j)) - assert qapply(Jminus*JzKetCoupled(j,m,(j1,j2))) == \ - hbar*sqrt(j**2+j-m**2+m)*JzKetCoupled(j,m-1,(j1,j2)) + assert qapply(Jminus*JxKetCoupled(1, 1, (1, 1))) == \ + hbar*sqrt(2)*JxKetCoupled(1, 0, (1, 1))/2 + \ + hbar*JxKetCoupled(1, 1, (1, 1)) + assert qapply(Jminus*JyKetCoupled(1, 1, (1, 1))) == \ + hbar*sqrt(2)*JyKetCoupled(1, 0, (1, 1))/2 - \ + hbar*I*JyKetCoupled(1, 1, (1, 1)) + assert qapply(Jminus*JzKetCoupled(1, 1, (1, 1))) == \ + sqrt(2)*hbar*JzKetCoupled(1, 0, (1, 1)) + # Symbolic + assert qapply(Jminus*JxKetCoupled(j, m, (j1, j2))) == \ + Sum(hbar*sqrt(j**2 + j - mi**2 + mi)*WignerD(j, mi, m, 0, pi/2, 0) * + Sum(WignerD(j, mi1, mi - 1, 0, 3*pi/2, 0)*JxKetCoupled(j, mi1, (j1, j2)), + (mi1, -j, j)), (mi, -j, j)) + assert qapply(Jminus*JyKetCoupled(j, m, (j1, j2))) == \ + Sum(hbar*sqrt(j**2 + j - mi**2 + mi)*WignerD(j, mi, m, 3*pi/2, -pi/2, pi/2) * + Sum( + WignerD(j, mi1, mi - 1, 3*pi/2, pi/2, pi/2)* + JyKetCoupled(j, mi1, (j1, j2)), + (mi1, -j, j)), (mi, -j, j)) + assert qapply(Jminus*JzKetCoupled(j, m, (j1, j2))) == \ + hbar*sqrt(j**2 + j - m**2 + m)*JzKetCoupled(j, m - 1, (j1, j2)) # Uncoupled operators, uncoupled states # Numerical - assert qapply(TensorProduct(Jminus,1)*TensorProduct(JxKet(1,1),JxKet(1,-1))) == \ - hbar*sqrt(2)*TensorProduct(JxKet(1,0),JxKet(1,-1))/2 + \ - hbar*TensorProduct(JxKet(1,1),JxKet(1,-1)) - assert qapply(TensorProduct(1,Jminus)*TensorProduct(JxKet(1,1),JxKet(1,-1))) == \ - -hbar*TensorProduct(JxKet(1,1),JxKet(1,-1)) - \ - hbar*sqrt(2)*TensorProduct(JxKet(1,1),JxKet(1,0))/2 - assert qapply(TensorProduct(Jminus,1)*TensorProduct(JyKet(1,1),JyKet(1,-1))) == \ - hbar*sqrt(2)*TensorProduct(JyKet(1,0),JyKet(1,-1))/2 - \ - hbar*I*TensorProduct(JyKet(1,1),JyKet(1,-1)) - assert qapply(TensorProduct(1,Jminus)*TensorProduct(JyKet(1,1),JyKet(1,-1))) == \ - hbar*I*TensorProduct(JyKet(1,1),JyKet(1,-1)) + \ - hbar*sqrt(2)*TensorProduct(JyKet(1,1),JyKet(1,0))/2 - assert qapply(TensorProduct(Jminus,1)*TensorProduct(JzKet(1,1),JzKet(1,-1))) == \ - sqrt(2)*hbar*TensorProduct(JzKet(1,0),JzKet(1,-1)) - assert qapply(TensorProduct(1,Jminus)*TensorProduct(JzKet(1,1),JzKet(1,-1))) == 0 - # Symbolic - assert qapply(TensorProduct(Jminus,1)*TensorProduct(JxKet(j1,m1),JxKet(j2,m2))) == \ - TensorProduct(Sum(hbar*sqrt(j1**2+j1-mi**2+mi)*WignerD(j1,mi,m1,0,pi/2,0) * \ - Sum(WignerD(j1,mi1,mi-1,0,3*pi/2,0)*JxKet(j1,mi1), \ - (mi1,-j1,j1)), (mi,-j1,j1)),JxKet(j2,m2)) - assert qapply(TensorProduct(1,Jminus)*TensorProduct(JxKet(j1,m1),JxKet(j2,m2))) == \ - TensorProduct(JxKet(j1,m1), Sum(hbar*sqrt(j2**2+j2-mi**2+mi)*WignerD(j2,mi,m2,0,pi/2,0) * \ - Sum(WignerD(j2,mi1,mi-1,0,3*pi/2,0)*JxKet(j2,mi1), \ - (mi1,-j2,j2)), (mi,-j2,j2))) - assert qapply(TensorProduct(Jminus,1)*TensorProduct(JyKet(j1,m1),JyKet(j2,m2))) == \ - TensorProduct(Sum(hbar*sqrt(j1**2+j1-mi**2+mi)*WignerD(j1,mi,m1,3*pi/2,-pi/2,pi/2) * \ - Sum(WignerD(j1,mi1,mi-1,3*pi/2,pi/2,pi/2)*JyKet(j1,mi1), \ - (mi1,-j1,j1)), (mi,-j1,j1)), JyKet(j2,m2)) - assert qapply(TensorProduct(1,Jminus)*TensorProduct(JyKet(j1,m1),JyKet(j2,m2))) == \ - TensorProduct(JyKet(j1,m1), Sum(hbar*sqrt(j2**2+j2-mi**2+mi)*WignerD(j2,mi,m2,3*pi/2,-pi/2,pi/2) * \ - Sum(WignerD(j2,mi1,mi-1,3*pi/2,pi/2,pi/2)*JyKet(j2,mi1), \ - (mi1,-j2,j2)), (mi,-j2,j2))) - assert qapply(TensorProduct(Jminus,1)*TensorProduct(JzKet(j1,m1),JzKet(j2,m2))) == \ - hbar*sqrt(j1**2+j1-m1**2+m1)*TensorProduct(JzKet(j1,m1-1),JzKet(j2,m2)) - assert qapply(TensorProduct(1,Jminus)*TensorProduct(JzKet(j1,m1),JzKet(j2,m2))) == \ - hbar*sqrt(j2**2+j2-m2**2+m2)*TensorProduct(JzKet(j1,m1),JzKet(j2,m2-1)) + assert qapply(TensorProduct(Jminus, 1)*TensorProduct(JxKet(1, 1), JxKet(1, -1))) == \ + hbar*sqrt(2)*TensorProduct(JxKet(1, 0), JxKet(1, -1))/2 + \ + hbar*TensorProduct(JxKet(1, 1), JxKet(1, -1)) + assert qapply(TensorProduct(1, Jminus)*TensorProduct(JxKet(1, 1), JxKet(1, -1))) == \ + -hbar*TensorProduct(JxKet(1, 1), JxKet(1, -1)) - \ + hbar*sqrt(2)*TensorProduct(JxKet(1, 1), JxKet(1, 0))/2 + assert qapply(TensorProduct(Jminus, 1)*TensorProduct(JyKet(1, 1), JyKet(1, -1))) == \ + hbar*sqrt(2)*TensorProduct(JyKet(1, 0), JyKet(1, -1))/2 - \ + hbar*I*TensorProduct(JyKet(1, 1), JyKet(1, -1)) + assert qapply(TensorProduct(1, Jminus)*TensorProduct(JyKet(1, 1), JyKet(1, -1))) == \ + hbar*I*TensorProduct(JyKet(1, 1), JyKet(1, -1)) + \ + hbar*sqrt(2)*TensorProduct(JyKet(1, 1), JyKet(1, 0))/2 + assert qapply(TensorProduct(Jminus, 1)*TensorProduct(JzKet(1, 1), JzKet(1, -1))) == \ + sqrt(2)*hbar*TensorProduct(JzKet(1, 0), JzKet(1, -1)) + assert qapply(TensorProduct( + 1, Jminus)*TensorProduct(JzKet(1, 1), JzKet(1, -1))) == 0 + # Symbolic + assert qapply(TensorProduct(Jminus, 1)*TensorProduct(JxKet(j1, m1), JxKet(j2, m2))) == \ + TensorProduct(Sum(hbar*sqrt(j1**2 + j1 - mi**2 + mi)*WignerD(j1, mi, m1, 0, pi/2, 0) * + Sum(WignerD(j1, mi1, mi - 1, 0, 3*pi/2, 0)*JxKet(j1, mi1), + (mi1, -j1, j1)), (mi, -j1, j1)), JxKet(j2, m2)) + assert qapply(TensorProduct(1, Jminus)*TensorProduct(JxKet(j1, m1), JxKet(j2, m2))) == \ + TensorProduct(JxKet(j1, m1), Sum(hbar*sqrt(j2**2 + j2 - mi**2 + mi)*WignerD(j2, mi, m2, 0, pi/2, 0) * + Sum(WignerD(j2, mi1, mi - 1, 0, 3*pi/2, 0)*JxKet(j2, mi1), + (mi1, -j2, j2)), (mi, -j2, j2))) + assert qapply(TensorProduct(Jminus, 1)*TensorProduct(JyKet(j1, m1), JyKet(j2, m2))) == \ + TensorProduct(Sum(hbar*sqrt(j1**2 + j1 - mi**2 + mi)*WignerD(j1, mi, m1, 3*pi/2, -pi/2, pi/2) * + Sum(WignerD(j1, mi1, mi - 1, 3*pi/2, pi/2, pi/2)*JyKet(j1, mi1), + (mi1, -j1, j1)), (mi, -j1, j1)), JyKet(j2, m2)) + assert qapply(TensorProduct(1, Jminus)*TensorProduct(JyKet(j1, m1), JyKet(j2, m2))) == \ + TensorProduct(JyKet(j1, m1), Sum(hbar*sqrt(j2**2 + j2 - mi**2 + mi)*WignerD(j2, mi, m2, 3*pi/2, -pi/2, pi/2) * + Sum(WignerD(j2, mi1, mi - 1, 3*pi/2, pi/2, pi/2)*JyKet(j2, mi1), + (mi1, -j2, j2)), (mi, -j2, j2))) + assert qapply(TensorProduct(Jminus, 1)*TensorProduct(JzKet(j1, m1), JzKet(j2, m2))) == \ + hbar*sqrt( + j1**2 + j1 - m1**2 + m1)*TensorProduct(JzKet(j1, m1 - 1), JzKet(j2, m2)) + assert qapply(TensorProduct(1, Jminus)*TensorProduct(JzKet(j1, m1), JzKet(j2, m2))) == \ + hbar*sqrt( + j2**2 + j2 - m2**2 + m2)*TensorProduct(JzKet(j1, m1), JzKet(j2, m2 - 1)) + def test_j2(): assert Commutator(J2, Jz).doit() == 0 - assert J2.matrix_element(1,1,1,1) == 2*hbar**2 + assert J2.matrix_element(1, 1, 1, 1) == 2*hbar**2 # Normal operators, normal states # Numerical - assert qapply(J2*JxKet(1,1)) == 2*hbar**2*JxKet(1,1) - assert qapply(J2*JyKet(1,1)) == 2*hbar**2*JyKet(1,1) - assert qapply(J2*JzKet(1,1)) == 2*hbar**2*JzKet(1,1) - # Symbolic - assert qapply(J2*JxKet(j,m)) == hbar**2*j**2*JxKet(j,m)+hbar**2*j*JxKet(j,m) - assert qapply(J2*JyKet(j,m)) == hbar**2*j**2*JyKet(j,m)+hbar**2*j*JyKet(j,m) - assert qapply(J2*JzKet(j,m)) == hbar**2*j**2*JzKet(j,m)+hbar**2*j*JzKet(j,m) + assert qapply(J2*JxKet(1, 1)) == 2*hbar**2*JxKet(1, 1) + assert qapply(J2*JyKet(1, 1)) == 2*hbar**2*JyKet(1, 1) + assert qapply(J2*JzKet(1, 1)) == 2*hbar**2*JzKet(1, 1) + # Symbolic + assert qapply(J2*JxKet(j, m)) == \ + hbar**2*j**2*JxKet(j, m) + hbar**2*j*JxKet(j, m) + assert qapply(J2*JyKet(j, m)) == \ + hbar**2*j**2*JyKet(j, m) + hbar**2*j*JyKet(j, m) + assert qapply(J2*JzKet(j, m)) == \ + hbar**2*j**2*JzKet(j, m) + hbar**2*j*JzKet(j, m) # Normal operators, coupled states # Numerical - assert qapply(J2*JxKetCoupled(1,1,(1,1))) == \ - 2*hbar**2*JxKetCoupled(1,1,(1,1)) - assert qapply(J2*JyKetCoupled(1,1,(1,1))) == \ - 2*hbar**2*JyKetCoupled(1,1,(1,1)) - assert qapply(J2*JzKetCoupled(1,1,(1,1))) == \ - 2*hbar**2*JzKetCoupled(1,1,(1,1)) - # Symbolic - assert qapply(J2*JxKetCoupled(j,m,(j1,j2))) == \ - hbar**2*j**2*JxKetCoupled(j,m,(j1,j2)) + \ - hbar**2*j*JxKetCoupled(j,m,(j1,j2)) - assert qapply(J2*JyKetCoupled(j,m,(j1,j2))) == \ - hbar**2*j**2*JyKetCoupled(j,m,(j1,j2)) + \ - hbar**2*j*JyKetCoupled(j,m,(j1,j2)) - assert qapply(J2*JzKetCoupled(j,m,(j1,j2))) == \ - hbar**2*j**2*JzKetCoupled(j,m,(j1,j2)) + \ - hbar**2*j*JzKetCoupled(j,m,(j1,j2)) + assert qapply(J2*JxKetCoupled(1, 1, (1, 1))) == \ + 2*hbar**2*JxKetCoupled(1, 1, (1, 1)) + assert qapply(J2*JyKetCoupled(1, 1, (1, 1))) == \ + 2*hbar**2*JyKetCoupled(1, 1, (1, 1)) + assert qapply(J2*JzKetCoupled(1, 1, (1, 1))) == \ + 2*hbar**2*JzKetCoupled(1, 1, (1, 1)) + # Symbolic + assert qapply(J2*JxKetCoupled(j, m, (j1, j2))) == \ + hbar**2*j**2*JxKetCoupled(j, m, (j1, j2)) + \ + hbar**2*j*JxKetCoupled(j, m, (j1, j2)) + assert qapply(J2*JyKetCoupled(j, m, (j1, j2))) == \ + hbar**2*j**2*JyKetCoupled(j, m, (j1, j2)) + \ + hbar**2*j*JyKetCoupled(j, m, (j1, j2)) + assert qapply(J2*JzKetCoupled(j, m, (j1, j2))) == \ + hbar**2*j**2*JzKetCoupled(j, m, (j1, j2)) + \ + hbar**2*j*JzKetCoupled(j, m, (j1, j2)) # Uncoupled operators, uncoupled states # Numerical - assert qapply(TensorProduct(J2,1)*TensorProduct(JxKet(1,1),JxKet(1,-1))) == \ - 2*hbar**2*TensorProduct(JxKet(1,1),JxKet(1,-1)) - assert qapply(TensorProduct(1,J2)*TensorProduct(JxKet(1,1),JxKet(1,-1))) == \ - 2*hbar**2*TensorProduct(JxKet(1,1),JxKet(1,-1)) - assert qapply(TensorProduct(J2,1)*TensorProduct(JyKet(1,1),JyKet(1,-1))) == \ - 2*hbar**2*TensorProduct(JyKet(1,1),JyKet(1,-1)) - assert qapply(TensorProduct(1,J2)*TensorProduct(JyKet(1,1),JyKet(1,-1))) == \ - 2*hbar**2*TensorProduct(JyKet(1,1),JyKet(1,-1)) - assert qapply(TensorProduct(J2,1)*TensorProduct(JzKet(1,1),JzKet(1,-1))) == \ - 2*hbar**2*TensorProduct(JzKet(1,1),JzKet(1,-1)) - assert qapply(TensorProduct(1,J2)*TensorProduct(JzKet(1,1),JzKet(1,-1))) == \ - 2*hbar**2*TensorProduct(JzKet(1,1),JzKet(1,-1)) - # Symbolic - assert qapply(TensorProduct(J2,1)*TensorProduct(JxKet(j1,m1),JxKet(j2,m2))) == \ - hbar**2*j1**2*TensorProduct(JxKet(j1,m1),JxKet(j2,m2)) + \ - hbar**2*j1*TensorProduct(JxKet(j1,m1),JxKet(j2,m2)) - assert qapply(TensorProduct(1,J2)*TensorProduct(JxKet(j1,m1),JxKet(j2,m2))) == \ - hbar**2*j2**2*TensorProduct(JxKet(j1,m1),JxKet(j2,m2)) + \ - hbar**2*j2*TensorProduct(JxKet(j1,m1),JxKet(j2,m2)) - assert qapply(TensorProduct(J2,1)*TensorProduct(JyKet(j1,m1),JyKet(j2,m2))) == \ - hbar**2*j1**2*TensorProduct(JyKet(j1,m1),JyKet(j2,m2)) + \ - hbar**2*j1*TensorProduct(JyKet(j1,m1),JyKet(j2,m2)) - assert qapply(TensorProduct(1,J2)*TensorProduct(JyKet(j1,m1),JyKet(j2,m2))) == \ - hbar**2*j2**2*TensorProduct(JyKet(j1,m1),JyKet(j2,m2)) + \ - hbar**2*j2*TensorProduct(JyKet(j1,m1),JyKet(j2,m2)) - assert qapply(TensorProduct(J2,1)*TensorProduct(JzKet(j1,m1),JzKet(j2,m2))) == \ - hbar**2*j1**2*TensorProduct(JzKet(j1,m1),JzKet(j2,m2)) + \ - hbar**2*j1*TensorProduct(JzKet(j1,m1),JzKet(j2,m2)) - assert qapply(TensorProduct(1,J2)*TensorProduct(JzKet(j1,m1),JzKet(j2,m2))) == \ - hbar**2*j2**2*TensorProduct(JzKet(j1,m1),JzKet(j2,m2)) + \ - hbar**2*j2*TensorProduct(JzKet(j1,m1),JzKet(j2,m2)) + assert qapply(TensorProduct(J2, 1)*TensorProduct(JxKet(1, 1), JxKet(1, -1))) == \ + 2*hbar**2*TensorProduct(JxKet(1, 1), JxKet(1, -1)) + assert qapply(TensorProduct(1, J2)*TensorProduct(JxKet(1, 1), JxKet(1, -1))) == \ + 2*hbar**2*TensorProduct(JxKet(1, 1), JxKet(1, -1)) + assert qapply(TensorProduct(J2, 1)*TensorProduct(JyKet(1, 1), JyKet(1, -1))) == \ + 2*hbar**2*TensorProduct(JyKet(1, 1), JyKet(1, -1)) + assert qapply(TensorProduct(1, J2)*TensorProduct(JyKet(1, 1), JyKet(1, -1))) == \ + 2*hbar**2*TensorProduct(JyKet(1, 1), JyKet(1, -1)) + assert qapply(TensorProduct(J2, 1)*TensorProduct(JzKet(1, 1), JzKet(1, -1))) == \ + 2*hbar**2*TensorProduct(JzKet(1, 1), JzKet(1, -1)) + assert qapply(TensorProduct(1, J2)*TensorProduct(JzKet(1, 1), JzKet(1, -1))) == \ + 2*hbar**2*TensorProduct(JzKet(1, 1), JzKet(1, -1)) + # Symbolic + assert qapply(TensorProduct(J2, 1)*TensorProduct(JxKet(j1, m1), JxKet(j2, m2))) == \ + hbar**2*j1**2*TensorProduct(JxKet(j1, m1), JxKet(j2, m2)) + \ + hbar**2*j1*TensorProduct(JxKet(j1, m1), JxKet(j2, m2)) + assert qapply(TensorProduct(1, J2)*TensorProduct(JxKet(j1, m1), JxKet(j2, m2))) == \ + hbar**2*j2**2*TensorProduct(JxKet(j1, m1), JxKet(j2, m2)) + \ + hbar**2*j2*TensorProduct(JxKet(j1, m1), JxKet(j2, m2)) + assert qapply(TensorProduct(J2, 1)*TensorProduct(JyKet(j1, m1), JyKet(j2, m2))) == \ + hbar**2*j1**2*TensorProduct(JyKet(j1, m1), JyKet(j2, m2)) + \ + hbar**2*j1*TensorProduct(JyKet(j1, m1), JyKet(j2, m2)) + assert qapply(TensorProduct(1, J2)*TensorProduct(JyKet(j1, m1), JyKet(j2, m2))) == \ + hbar**2*j2**2*TensorProduct(JyKet(j1, m1), JyKet(j2, m2)) + \ + hbar**2*j2*TensorProduct(JyKet(j1, m1), JyKet(j2, m2)) + assert qapply(TensorProduct(J2, 1)*TensorProduct(JzKet(j1, m1), JzKet(j2, m2))) == \ + hbar**2*j1**2*TensorProduct(JzKet(j1, m1), JzKet(j2, m2)) + \ + hbar**2*j1*TensorProduct(JzKet(j1, m1), JzKet(j2, m2)) + assert qapply(TensorProduct(1, J2)*TensorProduct(JzKet(j1, m1), JzKet(j2, m2))) == \ + hbar**2*j2**2*TensorProduct(JzKet(j1, m1), JzKet(j2, m2)) + \ + hbar**2*j2*TensorProduct(JzKet(j1, m1), JzKet(j2, m2)) + def test_jx(): assert Commutator(Jx, Jz).doit() == -I*hbar*Jy assert Jx.rewrite('plusminus') == (Jminus + Jplus)/2 - assert represent(Jx, basis=Jz, j=1) == (represent(Jplus, basis=Jz, j=1)+represent(Jminus, basis=Jz, j=1))/2 + assert represent(Jx, basis=Jz, j=1) == ( + represent(Jplus, basis=Jz, j=1) + represent(Jminus, basis=Jz, j=1))/2 # Normal operators, normal states # Numerical - assert qapply(Jx*JxKet(1,1)) == hbar*JxKet(1,1) - assert qapply(Jx*JyKet(1,1)) == hbar*JyKet(1,1) - assert qapply(Jx*JzKet(1,1)) == sqrt(2)*hbar*JzKet(1,0)/2 - # Symbolic - assert qapply(Jx*JxKet(j,m)) == hbar*m*JxKet(j,m) - assert qapply(Jx*JyKet(j,m)) == \ - Sum(hbar*mi*WignerD(j,mi,m,0,0,pi/2)*Sum(WignerD(j,mi1,mi,3*pi/2,0,0)*JyKet(j,mi1),(mi1,-j,j)),(mi,-j,j)) - assert qapply(Jx*JzKet(j,m)) == \ - hbar*sqrt(j**2+j-m**2-m)*JzKet(j,m+1)/2 + hbar*sqrt(j**2+j-m**2+m)*JzKet(j,m-1)/2 + assert qapply(Jx*JxKet(1, 1)) == hbar*JxKet(1, 1) + assert qapply(Jx*JyKet(1, 1)) == hbar*JyKet(1, 1) + assert qapply(Jx*JzKet(1, 1)) == sqrt(2)*hbar*JzKet(1, 0)/2 + # Symbolic + assert qapply(Jx*JxKet(j, m)) == hbar*m*JxKet(j, m) + assert qapply(Jx*JyKet(j, m)) == \ + Sum(hbar*mi*WignerD(j, mi, m, 0, 0, pi/2)*Sum(WignerD(j, + mi1, mi, 3*pi/2, 0, 0)*JyKet(j, mi1), (mi1, -j, j)), (mi, -j, j)) + assert qapply(Jx*JzKet(j, m)) == \ + hbar*sqrt(j**2 + j - m**2 - m)*JzKet(j, m + 1)/2 + hbar*sqrt(j**2 + + j - m**2 + m)*JzKet(j, m - 1)/2 # Normal operators, coupled states # Numerical - assert qapply(Jx*JxKetCoupled(1,1,(1,1))) == \ - hbar*JxKetCoupled(1,1,(1,1)) - assert qapply(Jx*JyKetCoupled(1,1,(1,1))) == \ - hbar*JyKetCoupled(1,1,(1,1)) - assert qapply(Jx*JzKetCoupled(1,1,(1,1))) == \ - sqrt(2)*hbar*JzKetCoupled(1,0,(1,1))/2 - # Symbolic - assert qapply(Jx*JxKetCoupled(j,m,(j1,j2))) == \ - hbar*m*JxKetCoupled(j,m,(j1,j2)) - assert qapply(Jx*JyKetCoupled(j,m,(j1,j2))) == \ - Sum(hbar*mi*WignerD(j,mi,m,0,0,pi/2)*Sum(WignerD(j,mi1,mi,3*pi/2,0,0)*JyKetCoupled(j,mi1,(j1,j2)), (mi1,-j,j)), (mi,-j,j)) - assert qapply(Jx*JzKetCoupled(j,m,(j1,j2))) == \ - hbar*sqrt(j**2+j-m**2-m)*JzKetCoupled(j,m+1,(j1,j2))/2 + \ - hbar*sqrt(j**2+j-m**2+m)*JzKetCoupled(j,m-1,(j1,j2))/2 + assert qapply(Jx*JxKetCoupled(1, 1, (1, 1))) == \ + hbar*JxKetCoupled(1, 1, (1, 1)) + assert qapply(Jx*JyKetCoupled(1, 1, (1, 1))) == \ + hbar*JyKetCoupled(1, 1, (1, 1)) + assert qapply(Jx*JzKetCoupled(1, 1, (1, 1))) == \ + sqrt(2)*hbar*JzKetCoupled(1, 0, (1, 1))/2 + # Symbolic + assert qapply(Jx*JxKetCoupled(j, m, (j1, j2))) == \ + hbar*m*JxKetCoupled(j, m, (j1, j2)) + assert qapply(Jx*JyKetCoupled(j, m, (j1, j2))) == \ + Sum(hbar*mi*WignerD(j, mi, m, 0, 0, pi/2)*Sum(WignerD(j, mi1, mi, 3*pi/2, 0, 0)*JyKetCoupled(j, mi1, (j1, j2)), (mi1, -j, j)), (mi, -j, j)) + assert qapply(Jx*JzKetCoupled(j, m, (j1, j2))) == \ + hbar*sqrt(j**2 + j - m**2 - m)*JzKetCoupled(j, m + 1, (j1, j2))/2 + \ + hbar*sqrt(j**2 + j - m**2 + m)*JzKetCoupled(j, m - 1, (j1, j2))/2 # Normal operators, uncoupled states # Numerical - assert qapply(Jx*TensorProduct(JxKet(1,1), JxKet(1,1))) == \ - 2*hbar*TensorProduct(JxKet(1,1), JxKet(1,1)) - assert qapply(Jx*TensorProduct(JyKet(1,1), JyKet(1,1))) == \ - hbar*TensorProduct(JyKet(1,1),JyKet(1,1)) + \ - hbar*TensorProduct(JyKet(1,1),JyKet(1,1)) - assert qapply(Jx*TensorProduct(JzKet(1,1), JzKet(1,1))) == \ - sqrt(2)*hbar*TensorProduct(JzKet(1,1),JzKet(1,0))/2 + \ - sqrt(2)*hbar*TensorProduct(JzKet(1,0),JzKet(1,1))/2 - assert qapply(Jx*TensorProduct(JxKet(1,1), JxKet(1,-1))) == 0 - # Symbolic - assert qapply(Jx*TensorProduct(JxKet(j1,m1), JxKet(j2,m2))) == \ - hbar*m1*TensorProduct(JxKet(j1,m1),JxKet(j2,m2)) + \ - hbar*m2*TensorProduct(JxKet(j1,m1),JxKet(j2,m2)) - assert qapply(Jx*TensorProduct(JyKet(j1,m1), JyKet(j2,m2))) == \ - TensorProduct(Sum(hbar*mi*WignerD(j1,mi,m1,0,0,pi/2)*Sum(WignerD(j1,mi1,mi,3*pi/2,0,0)*JyKet(j1,mi1),(mi1,-j1,j1)),(mi,-j1,j1)),JyKet(j2,m2)) + \ - TensorProduct(JyKet(j1,m1),Sum(hbar*mi*WignerD(j2,mi,m2,0,0,pi/2)*Sum(WignerD(j2,mi1,mi,3*pi/2,0,0)*JyKet(j2,mi1),(mi1,-j2,j2)),(mi,-j2,j2))) - assert qapply(Jx*TensorProduct(JzKet(j1,m1), JzKet(j2,m2))) == \ - hbar*sqrt(j1**2+j1-m1**2-m1)*TensorProduct(JzKet(j1,m1+1),JzKet(j2,m2))/2 + \ - hbar*sqrt(j1**2+j1-m1**2+m1)*TensorProduct(JzKet(j1,m1-1),JzKet(j2,m2))/2 + \ - hbar*sqrt(j2**2+j2-m2**2-m2)*TensorProduct(JzKet(j1,m1),JzKet(j2,m2+1))/2 + \ - hbar*sqrt(j2**2+j2-m2**2+m2)*TensorProduct(JzKet(j1,m1),JzKet(j2,m2-1))/2 + assert qapply(Jx*TensorProduct(JxKet(1, 1), JxKet(1, 1))) == \ + 2*hbar*TensorProduct(JxKet(1, 1), JxKet(1, 1)) + assert qapply(Jx*TensorProduct(JyKet(1, 1), JyKet(1, 1))) == \ + hbar*TensorProduct(JyKet(1, 1), JyKet(1, 1)) + \ + hbar*TensorProduct(JyKet(1, 1), JyKet(1, 1)) + assert qapply(Jx*TensorProduct(JzKet(1, 1), JzKet(1, 1))) == \ + sqrt(2)*hbar*TensorProduct(JzKet(1, 1), JzKet(1, 0))/2 + \ + sqrt(2)*hbar*TensorProduct(JzKet(1, 0), JzKet(1, 1))/2 + assert qapply(Jx*TensorProduct(JxKet(1, 1), JxKet(1, -1))) == 0 + # Symbolic + assert qapply(Jx*TensorProduct(JxKet(j1, m1), JxKet(j2, m2))) == \ + hbar*m1*TensorProduct(JxKet(j1, m1), JxKet(j2, m2)) + \ + hbar*m2*TensorProduct(JxKet(j1, m1), JxKet(j2, m2)) + assert qapply(Jx*TensorProduct(JyKet(j1, m1), JyKet(j2, m2))) == \ + TensorProduct(Sum(hbar*mi*WignerD(j1, mi, m1, 0, 0, pi/2)*Sum(WignerD(j1, mi1, mi, 3*pi/2, 0, 0)*JyKet(j1, mi1), (mi1, -j1, j1)), (mi, -j1, j1)), JyKet(j2, m2)) + \ + TensorProduct(JyKet(j1, m1), Sum(hbar*mi*WignerD(j2, mi, m2, 0, 0, pi/2)*Sum(WignerD(j2, mi1, mi, 3*pi/2, 0, 0)*JyKet(j2, mi1), (mi1, -j2, j2)), (mi, -j2, j2))) + assert qapply(Jx*TensorProduct(JzKet(j1, m1), JzKet(j2, m2))) == \ + hbar*sqrt(j1**2 + j1 - m1**2 - m1)*TensorProduct(JzKet(j1, m1 + 1), JzKet(j2, m2))/2 + \ + hbar*sqrt(j1**2 + j1 - m1**2 + m1)*TensorProduct(JzKet(j1, m1 - 1), JzKet(j2, m2))/2 + \ + hbar*sqrt(j2**2 + j2 - m2**2 - m2)*TensorProduct(JzKet(j1, m1), JzKet(j2, m2 + 1))/2 + \ + hbar*sqrt( + j2**2 + j2 - m2**2 + m2)*TensorProduct(JzKet(j1, m1), JzKet(j2, m2 - 1))/2 # Uncoupled operators, uncoupled states # Numerical - assert qapply(TensorProduct(Jx,1)*TensorProduct(JxKet(1,1),JxKet(1,-1))) == \ - hbar*TensorProduct(JxKet(1,1),JxKet(1,-1)) - assert qapply(TensorProduct(1,Jx)*TensorProduct(JxKet(1,1),JxKet(1,-1))) == \ - -hbar*TensorProduct(JxKet(1,1),JxKet(1,-1)) - assert qapply(TensorProduct(Jx,1)*TensorProduct(JyKet(1,1),JyKet(1,-1))) == \ - hbar*TensorProduct(JyKet(1,1),JyKet(1,-1)) - assert qapply(TensorProduct(1,Jx)*TensorProduct(JyKet(1,1),JyKet(1,-1))) == \ - -hbar*TensorProduct(JyKet(1,1),JyKet(1,-1)) - assert qapply(TensorProduct(Jx,1)*TensorProduct(JzKet(1,1),JzKet(1,-1))) == \ - hbar*sqrt(2)*TensorProduct(JzKet(1,0),JzKet(1,-1))/2 - assert qapply(TensorProduct(1,Jx)*TensorProduct(JzKet(1,1),JzKet(1,-1))) == \ - hbar*sqrt(2)*TensorProduct(JzKet(1,1),JzKet(1,0))/2 - # Symbolic - assert qapply(TensorProduct(Jx,1)*TensorProduct(JxKet(j1,m1),JxKet(j2,m2))) == \ - hbar*m1*TensorProduct(JxKet(j1,m1),JxKet(j2,m2)) - assert qapply(TensorProduct(1,Jx)*TensorProduct(JxKet(j1,m1),JxKet(j2,m2))) == \ - hbar*m2*TensorProduct(JxKet(j1,m1),JxKet(j2,m2)) - assert qapply(TensorProduct(Jx,1)*TensorProduct(JyKet(j1,m1),JyKet(j2,m2))) == \ - TensorProduct(Sum(hbar*mi*WignerD(j1,mi,m1,0,0,pi/2) * Sum(WignerD(j1,mi1,mi,3*pi/2,0,0)*JyKet(j1,mi1),(mi1,-j1,j1)), (mi,-j1,j1)),JyKet(j2,m2)) - assert qapply(TensorProduct(1,Jx)*TensorProduct(JyKet(j1,m1),JyKet(j2,m2))) == \ - TensorProduct(JyKet(j1,m1),Sum(hbar*mi*WignerD(j2,mi,m2,0,0,pi/2) * Sum(WignerD(j2,mi1,mi,3*pi/2,0,0)*JyKet(j2,mi1),(mi1,-j2,j2)), (mi,-j2,j2))) - assert qapply(TensorProduct(Jx,1)*TensorProduct(JzKet(j1,m1),JzKet(j2,m2))) == \ - hbar*sqrt(j1**2+j1-m1**2-m1)*TensorProduct(JzKet(j1,m1+1),JzKet(j2,m2))/2 + \ - hbar*sqrt(j1**2+j1-m1**2+m1)*TensorProduct(JzKet(j1,m1-1),JzKet(j2,m2))/2 - assert qapply(TensorProduct(1,Jx)*TensorProduct(JzKet(j1,m1),JzKet(j2,m2))) == \ - hbar*sqrt(j2**2+j2-m2**2-m2)*TensorProduct(JzKet(j1,m1),JzKet(j2,m2+1))/2 + \ - hbar*sqrt(j2**2+j2-m2**2+m2)*TensorProduct(JzKet(j1,m1),JzKet(j2,m2-1))/2 + assert qapply(TensorProduct(Jx, 1)*TensorProduct(JxKet(1, 1), JxKet(1, -1))) == \ + hbar*TensorProduct(JxKet(1, 1), JxKet(1, -1)) + assert qapply(TensorProduct(1, Jx)*TensorProduct(JxKet(1, 1), JxKet(1, -1))) == \ + -hbar*TensorProduct(JxKet(1, 1), JxKet(1, -1)) + assert qapply(TensorProduct(Jx, 1)*TensorProduct(JyKet(1, 1), JyKet(1, -1))) == \ + hbar*TensorProduct(JyKet(1, 1), JyKet(1, -1)) + assert qapply(TensorProduct(1, Jx)*TensorProduct(JyKet(1, 1), JyKet(1, -1))) == \ + -hbar*TensorProduct(JyKet(1, 1), JyKet(1, -1)) + assert qapply(TensorProduct(Jx, 1)*TensorProduct(JzKet(1, 1), JzKet(1, -1))) == \ + hbar*sqrt(2)*TensorProduct(JzKet(1, 0), JzKet(1, -1))/2 + assert qapply(TensorProduct(1, Jx)*TensorProduct(JzKet(1, 1), JzKet(1, -1))) == \ + hbar*sqrt(2)*TensorProduct(JzKet(1, 1), JzKet(1, 0))/2 + # Symbolic + assert qapply(TensorProduct(Jx, 1)*TensorProduct(JxKet(j1, m1), JxKet(j2, m2))) == \ + hbar*m1*TensorProduct(JxKet(j1, m1), JxKet(j2, m2)) + assert qapply(TensorProduct(1, Jx)*TensorProduct(JxKet(j1, m1), JxKet(j2, m2))) == \ + hbar*m2*TensorProduct(JxKet(j1, m1), JxKet(j2, m2)) + assert qapply(TensorProduct(Jx, 1)*TensorProduct(JyKet(j1, m1), JyKet(j2, m2))) == \ + TensorProduct(Sum(hbar*mi*WignerD(j1, mi, m1, 0, 0, pi/2) * Sum(WignerD(j1, mi1, mi, 3*pi/2, 0, 0)*JyKet(j1, mi1), (mi1, -j1, j1)), (mi, -j1, j1)), JyKet(j2, m2)) + assert qapply(TensorProduct(1, Jx)*TensorProduct(JyKet(j1, m1), JyKet(j2, m2))) == \ + TensorProduct(JyKet(j1, m1), Sum(hbar*mi*WignerD(j2, mi, m2, 0, 0, pi/2) * Sum(WignerD(j2, mi1, mi, 3*pi/2, 0, 0)*JyKet(j2, mi1), (mi1, -j2, j2)), (mi, -j2, j2))) + assert qapply(TensorProduct(Jx, 1)*TensorProduct(JzKet(j1, m1), JzKet(j2, m2))) == \ + hbar*sqrt(j1**2 + j1 - m1**2 - m1)*TensorProduct(JzKet(j1, m1 + 1), JzKet(j2, m2))/2 + \ + hbar*sqrt( + j1**2 + j1 - m1**2 + m1)*TensorProduct(JzKet(j1, m1 - 1), JzKet(j2, m2))/2 + assert qapply(TensorProduct(1, Jx)*TensorProduct(JzKet(j1, m1), JzKet(j2, m2))) == \ + hbar*sqrt(j2**2 + j2 - m2**2 - m2)*TensorProduct(JzKet(j1, m1), JzKet(j2, m2 + 1))/2 + \ + hbar*sqrt( + j2**2 + j2 - m2**2 + m2)*TensorProduct(JzKet(j1, m1), JzKet(j2, m2 - 1))/2 + def test_jy(): assert Commutator(Jy, Jz).doit() == I*hbar*Jx assert Jy.rewrite('plusminus') == (Jplus - Jminus)/(2*I) - assert represent(Jy, basis=Jz) == (represent(Jplus, basis=Jz) - represent(Jminus, basis=Jz))/(2*I) + assert represent(Jy, basis=Jz) == ( + represent(Jplus, basis=Jz) - represent(Jminus, basis=Jz))/(2*I) # Normal operators, normal states # Numerical - assert qapply(Jy*JxKet(1,1)) == hbar*JxKet(1,1) - assert qapply(Jy*JyKet(1,1)) == hbar*JyKet(1,1) - assert qapply(Jy*JzKet(1,1)) == sqrt(2)*hbar*I*JzKet(1,0)/2 - # Symbolic - assert qapply(Jy*JxKet(j,m)) == \ - Sum(hbar*mi*WignerD(j,mi,m,3*pi/2,0,0)*Sum(WignerD(j,mi1,mi,0,0,pi/2)*JxKet(j,mi1),(mi1,-j,j)), (mi,-j,j)) - assert qapply(Jy*JyKet(j,m)) == hbar*m*JyKet(j,m) - assert qapply(Jy*JzKet(j,m)) == \ - -hbar*I*sqrt(j**2+j-m**2-m)*JzKet(j,m+1)/2 + hbar*I*sqrt(j**2+j-m**2+m)*JzKet(j,m-1)/2 + assert qapply(Jy*JxKet(1, 1)) == hbar*JxKet(1, 1) + assert qapply(Jy*JyKet(1, 1)) == hbar*JyKet(1, 1) + assert qapply(Jy*JzKet(1, 1)) == sqrt(2)*hbar*I*JzKet(1, 0)/2 + # Symbolic + assert qapply(Jy*JxKet(j, m)) == \ + Sum(hbar*mi*WignerD(j, mi, m, 3*pi/2, 0, 0)*Sum(WignerD( + j, mi1, mi, 0, 0, pi/2)*JxKet(j, mi1), (mi1, -j, j)), (mi, -j, j)) + assert qapply(Jy*JyKet(j, m)) == hbar*m*JyKet(j, m) + assert qapply(Jy*JzKet(j, m)) == \ + -hbar*I*sqrt(j**2 + j - m**2 - m)*JzKet( + j, m + 1)/2 + hbar*I*sqrt(j**2 + j - m**2 + m)*JzKet(j, m - 1)/2 # Normal operators, coupled states # Numerical - assert qapply(Jy*JxKetCoupled(1,1,(1,1))) == \ - hbar*JxKetCoupled(1,1,(1,1)) - assert qapply(Jy*JyKetCoupled(1,1,(1,1))) == \ - hbar*JyKetCoupled(1,1,(1,1)) - assert qapply(Jy*JzKetCoupled(1,1,(1,1))) == \ - sqrt(2)*hbar*I*JzKetCoupled(1,0,(1,1))/2 - # Symbolic - assert qapply(Jy*JxKetCoupled(j,m,(j1,j2))) == \ - Sum(hbar*mi*WignerD(j,mi,m,3*pi/2,0,0)*Sum(WignerD(j,mi1,mi,0,0,pi/2)*JxKetCoupled(j,mi1,(j1,j2)), (mi1,-j,j)), (mi,-j,j)) - assert qapply(Jy*JyKetCoupled(j,m,(j1,j2))) == \ - hbar*m*JyKetCoupled(j,m,(j1,j2)) - assert qapply(Jy*JzKetCoupled(j,m,(j1,j2))) == \ - -hbar*I*sqrt(j**2+j-m**2-m)*JzKetCoupled(j,m+1,(j1,j2))/2 + \ - hbar*I*sqrt(j**2+j-m**2+m)*JzKetCoupled(j,m-1,(j1,j2))/2 + assert qapply(Jy*JxKetCoupled(1, 1, (1, 1))) == \ + hbar*JxKetCoupled(1, 1, (1, 1)) + assert qapply(Jy*JyKetCoupled(1, 1, (1, 1))) == \ + hbar*JyKetCoupled(1, 1, (1, 1)) + assert qapply(Jy*JzKetCoupled(1, 1, (1, 1))) == \ + sqrt(2)*hbar*I*JzKetCoupled(1, 0, (1, 1))/2 + # Symbolic + assert qapply(Jy*JxKetCoupled(j, m, (j1, j2))) == \ + Sum(hbar*mi*WignerD(j, mi, m, 3*pi/2, 0, 0)*Sum(WignerD(j, mi1, mi, 0, 0, pi/2)*JxKetCoupled(j, mi1, (j1, j2)), (mi1, -j, j)), (mi, -j, j)) + assert qapply(Jy*JyKetCoupled(j, m, (j1, j2))) == \ + hbar*m*JyKetCoupled(j, m, (j1, j2)) + assert qapply(Jy*JzKetCoupled(j, m, (j1, j2))) == \ + -hbar*I*sqrt(j**2 + j - m**2 - m)*JzKetCoupled(j, m + 1, (j1, j2))/2 + \ + hbar*I*sqrt(j**2 + j - m**2 + m)*JzKetCoupled(j, m - 1, (j1, j2))/2 # Normal operators, uncoupled states # Numerical - assert qapply(Jy*TensorProduct(JxKet(1,1), JxKet(1,1))) == \ - hbar*TensorProduct(JxKet(1,1),JxKet(1,1)) + \ - hbar*TensorProduct(JxKet(1,1),JxKet(1,1)) - assert qapply(Jy*TensorProduct(JyKet(1,1), JyKet(1,1))) == \ - 2*hbar*TensorProduct(JyKet(1,1), JyKet(1,1)) - assert qapply(Jy*TensorProduct(JzKet(1,1), JzKet(1,1))) == \ - sqrt(2)*hbar*I*TensorProduct(JzKet(1,1),JzKet(1,0))/2 + \ - sqrt(2)*hbar*I*TensorProduct(JzKet(1,0),JzKet(1,1))/2 - assert qapply(Jy*TensorProduct(JyKet(1,1), JyKet(1,-1))) == 0 - # Symbolic - assert qapply(Jy*TensorProduct(JxKet(j1,m1), JxKet(j2,m2))) == \ - TensorProduct(JxKet(j1,m1),Sum(hbar*mi*WignerD(j2,mi,m2,3*pi/2,0,0)*Sum(WignerD(j2,mi1,mi,0,0,pi/2)*JxKet(j2,mi1),(mi1,-j2,j2)),(mi,-j2,j2))) + \ - TensorProduct(Sum(hbar*mi*WignerD(j1,mi,m1,3*pi/2,0,0)*Sum(WignerD(j1,mi1,mi,0,0,pi/2)*JxKet(j1,mi1),(mi1,-j1,j1)),(mi,-j1,j1)),JxKet(j2,m2)) - assert qapply(Jy*TensorProduct(JyKet(j1,m1), JyKet(j2,m2))) == \ - hbar*m1*TensorProduct(JyKet(j1,m1),JyKet(j2,m2))+hbar*m2*TensorProduct(JyKet(j1,m1),JyKet(j2,m2)) - assert qapply(Jy*TensorProduct(JzKet(j1,m1), JzKet(j2,m2))) == \ - -hbar*I*sqrt(j1**2+j1-m1**2-m1)*TensorProduct(JzKet(j1,m1+1),JzKet(j2,m2))/2 + \ - hbar*I*sqrt(j1**2+j1-m1**2+m1)*TensorProduct(JzKet(j1,m1-1),JzKet(j2,m2))/2 + \ - -hbar*I*sqrt(j2**2+j2-m2**2-m2)*TensorProduct(JzKet(j1,m1),JzKet(j2,m2+1))/2 + \ - hbar*I*sqrt(j2**2+j2-m2**2+m2)*TensorProduct(JzKet(j1,m1),JzKet(j2,m2-1))/2 + assert qapply(Jy*TensorProduct(JxKet(1, 1), JxKet(1, 1))) == \ + hbar*TensorProduct(JxKet(1, 1), JxKet(1, 1)) + \ + hbar*TensorProduct(JxKet(1, 1), JxKet(1, 1)) + assert qapply(Jy*TensorProduct(JyKet(1, 1), JyKet(1, 1))) == \ + 2*hbar*TensorProduct(JyKet(1, 1), JyKet(1, 1)) + assert qapply(Jy*TensorProduct(JzKet(1, 1), JzKet(1, 1))) == \ + sqrt(2)*hbar*I*TensorProduct(JzKet(1, 1), JzKet(1, 0))/2 + \ + sqrt(2)*hbar*I*TensorProduct(JzKet(1, 0), JzKet(1, 1))/2 + assert qapply(Jy*TensorProduct(JyKet(1, 1), JyKet(1, -1))) == 0 + # Symbolic + assert qapply(Jy*TensorProduct(JxKet(j1, m1), JxKet(j2, m2))) == \ + TensorProduct(JxKet(j1, m1), Sum(hbar*mi*WignerD(j2, mi, m2, 3*pi/2, 0, 0)*Sum(WignerD(j2, mi1, mi, 0, 0, pi/2)*JxKet(j2, mi1), (mi1, -j2, j2)), (mi, -j2, j2))) + \ + TensorProduct(Sum(hbar*mi*WignerD(j1, mi, m1, 3*pi/2, 0, 0)*Sum(WignerD(j1, mi1, mi, 0, 0, pi/2)*JxKet(j1, mi1), (mi1, -j1, j1)), (mi, -j1, j1)), JxKet(j2, m2)) + assert qapply(Jy*TensorProduct(JyKet(j1, m1), JyKet(j2, m2))) == \ + hbar*m1*TensorProduct(JyKet(j1, m1), JyKet( + j2, m2)) + hbar*m2*TensorProduct(JyKet(j1, m1), JyKet(j2, m2)) + assert qapply(Jy*TensorProduct(JzKet(j1, m1), JzKet(j2, m2))) == \ + -hbar*I*sqrt(j1**2 + j1 - m1**2 - m1)*TensorProduct(JzKet(j1, m1 + 1), JzKet(j2, m2))/2 + \ + hbar*I*sqrt(j1**2 + j1 - m1**2 + m1)*TensorProduct(JzKet(j1, m1 - 1), JzKet(j2, m2))/2 + \ + -hbar*I*sqrt(j2**2 + j2 - m2**2 - m2)*TensorProduct(JzKet(j1, m1), JzKet(j2, m2 + 1))/2 + \ + hbar*I*sqrt( + j2**2 + j2 - m2**2 + m2)*TensorProduct(JzKet(j1, m1), JzKet(j2, m2 - 1))/2 # Uncoupled operators, uncoupled states # Numerical - assert qapply(TensorProduct(Jy,1)*TensorProduct(JxKet(1,1),JxKet(1,-1))) == \ - hbar*TensorProduct(JxKet(1,1),JxKet(1,-1)) - assert qapply(TensorProduct(1,Jy)*TensorProduct(JxKet(1,1),JxKet(1,-1))) == \ - -hbar*TensorProduct(JxKet(1,1),JxKet(1,-1)) - assert qapply(TensorProduct(Jy,1)*TensorProduct(JyKet(1,1),JyKet(1,-1))) == \ - hbar*TensorProduct(JyKet(1,1),JyKet(1,-1)) - assert qapply(TensorProduct(1,Jy)*TensorProduct(JyKet(1,1),JyKet(1,-1))) == \ - -hbar*TensorProduct(JyKet(1,1),JyKet(1,-1)) - assert qapply(TensorProduct(Jy,1)*TensorProduct(JzKet(1,1),JzKet(1,-1))) == \ - hbar*sqrt(2)*I*TensorProduct(JzKet(1,0),JzKet(1,-1))/2 - assert qapply(TensorProduct(1,Jy)*TensorProduct(JzKet(1,1),JzKet(1,-1))) == \ - -hbar*sqrt(2)*I*TensorProduct(JzKet(1,1),JzKet(1,0))/2 - # Symbolic - assert qapply(TensorProduct(Jy,1)*TensorProduct(JxKet(j1,m1),JxKet(j2,m2))) == \ - TensorProduct(Sum(hbar*mi*WignerD(j1,mi,m1,3*pi/2,0,0) * Sum(WignerD(j1,mi1,mi,0,0,pi/2)*JxKet(j1,mi1),(mi1,-j1,j1)), (mi,-j1,j1)), JxKet(j2,m2)) - assert qapply(TensorProduct(1,Jy)*TensorProduct(JxKet(j1,m1),JxKet(j2,m2))) == \ - TensorProduct(JxKet(j1,m1), Sum(hbar*mi*WignerD(j2,mi,m2,3*pi/2,0,0) * Sum(WignerD(j2,mi1,mi,0,0,pi/2)*JxKet(j2,mi1),(mi1,-j2,j2)), (mi,-j2,j2))) - assert qapply(TensorProduct(Jy,1)*TensorProduct(JyKet(j1,m1),JyKet(j2,m2))) == \ - hbar*m1*TensorProduct(JyKet(j1,m1), JyKet(j2,m2)) - assert qapply(TensorProduct(1,Jy)*TensorProduct(JyKet(j1,m1),JyKet(j2,m2))) == \ - hbar*m2*TensorProduct(JyKet(j1,m1), JyKet(j2,m2)) - assert qapply(TensorProduct(Jy,1)*TensorProduct(JzKet(j1,m1),JzKet(j2,m2))) == \ - -hbar*I*sqrt(j1**2+j1-m1**2-m1)*TensorProduct(JzKet(j1,m1+1),JzKet(j2,m2))/2 + \ - hbar*I*sqrt(j1**2+j1-m1**2+m1)*TensorProduct(JzKet(j1,m1-1),JzKet(j2,m2))/2 - assert qapply(TensorProduct(1,Jy)*TensorProduct(JzKet(j1,m1),JzKet(j2,m2))) == \ - -hbar*I*sqrt(j2**2+j2-m2**2-m2)*TensorProduct(JzKet(j1,m1),JzKet(j2,m2+1))/2 + \ - hbar*I*sqrt(j2**2+j2-m2**2+m2)*TensorProduct(JzKet(j1,m1),JzKet(j2,m2-1))/2 + assert qapply(TensorProduct(Jy, 1)*TensorProduct(JxKet(1, 1), JxKet(1, -1))) == \ + hbar*TensorProduct(JxKet(1, 1), JxKet(1, -1)) + assert qapply(TensorProduct(1, Jy)*TensorProduct(JxKet(1, 1), JxKet(1, -1))) == \ + -hbar*TensorProduct(JxKet(1, 1), JxKet(1, -1)) + assert qapply(TensorProduct(Jy, 1)*TensorProduct(JyKet(1, 1), JyKet(1, -1))) == \ + hbar*TensorProduct(JyKet(1, 1), JyKet(1, -1)) + assert qapply(TensorProduct(1, Jy)*TensorProduct(JyKet(1, 1), JyKet(1, -1))) == \ + -hbar*TensorProduct(JyKet(1, 1), JyKet(1, -1)) + assert qapply(TensorProduct(Jy, 1)*TensorProduct(JzKet(1, 1), JzKet(1, -1))) == \ + hbar*sqrt(2)*I*TensorProduct(JzKet(1, 0), JzKet(1, -1))/2 + assert qapply(TensorProduct(1, Jy)*TensorProduct(JzKet(1, 1), JzKet(1, -1))) == \ + -hbar*sqrt(2)*I*TensorProduct(JzKet(1, 1), JzKet(1, 0))/2 + # Symbolic + assert qapply(TensorProduct(Jy, 1)*TensorProduct(JxKet(j1, m1), JxKet(j2, m2))) == \ + TensorProduct(Sum(hbar*mi*WignerD(j1, mi, m1, 3*pi/2, 0, 0) * Sum(WignerD(j1, mi1, mi, 0, 0, pi/2)*JxKet(j1, mi1), (mi1, -j1, j1)), (mi, -j1, j1)), JxKet(j2, m2)) + assert qapply(TensorProduct(1, Jy)*TensorProduct(JxKet(j1, m1), JxKet(j2, m2))) == \ + TensorProduct(JxKet(j1, m1), Sum(hbar*mi*WignerD(j2, mi, m2, 3*pi/2, 0, 0) * Sum(WignerD(j2, mi1, mi, 0, 0, pi/2)*JxKet(j2, mi1), (mi1, -j2, j2)), (mi, -j2, j2))) + assert qapply(TensorProduct(Jy, 1)*TensorProduct(JyKet(j1, m1), JyKet(j2, m2))) == \ + hbar*m1*TensorProduct(JyKet(j1, m1), JyKet(j2, m2)) + assert qapply(TensorProduct(1, Jy)*TensorProduct(JyKet(j1, m1), JyKet(j2, m2))) == \ + hbar*m2*TensorProduct(JyKet(j1, m1), JyKet(j2, m2)) + assert qapply(TensorProduct(Jy, 1)*TensorProduct(JzKet(j1, m1), JzKet(j2, m2))) == \ + -hbar*I*sqrt(j1**2 + j1 - m1**2 - m1)*TensorProduct(JzKet(j1, m1 + 1), JzKet(j2, m2))/2 + \ + hbar*I*sqrt( + j1**2 + j1 - m1**2 + m1)*TensorProduct(JzKet(j1, m1 - 1), JzKet(j2, m2))/2 + assert qapply(TensorProduct(1, Jy)*TensorProduct(JzKet(j1, m1), JzKet(j2, m2))) == \ + -hbar*I*sqrt(j2**2 + j2 - m2**2 - m2)*TensorProduct(JzKet(j1, m1), JzKet(j2, m2 + 1))/2 + \ + hbar*I*sqrt( + j2**2 + j2 - m2**2 + m2)*TensorProduct(JzKet(j1, m1), JzKet(j2, m2 - 1))/2 + def test_jz(): assert Commutator(Jz, Jminus).doit() == -hbar*Jminus # Normal operators, normal states # Numerical - assert qapply(Jz*JxKet(1,1)) == -sqrt(2)*hbar*JxKet(1,0)/2 - assert qapply(Jz*JyKet(1,1)) == -sqrt(2)*hbar*I*JyKet(1,0)/2 - assert qapply(Jz*JzKet(2,1)) == hbar*JzKet(2,1) - # Symbolic - assert qapply(Jz*JxKet(j,m)) == \ - Sum(hbar*mi*WignerD(j,mi,m,0,pi/2,0)*Sum(WignerD(j,mi1,mi,0,3*pi/2,0)*JxKet(j,mi1),(mi1,-j,j)), (mi,-j,j)) - assert qapply(Jz*JyKet(j,m)) == \ - Sum(hbar*mi*WignerD(j,mi,m,3*pi/2,-pi/2,pi/2)*Sum(WignerD(j,mi1,mi,3*pi/2,pi/2,pi/2)*JyKet(j,mi1),(mi1,-j,j)), (mi,-j,j)) - assert qapply(Jz*JzKet(j,m)) == hbar*m*JzKet(j,m) + assert qapply(Jz*JxKet(1, 1)) == -sqrt(2)*hbar*JxKet(1, 0)/2 + assert qapply(Jz*JyKet(1, 1)) == -sqrt(2)*hbar*I*JyKet(1, 0)/2 + assert qapply(Jz*JzKet(2, 1)) == hbar*JzKet(2, 1) + # Symbolic + assert qapply(Jz*JxKet(j, m)) == \ + Sum(hbar*mi*WignerD(j, mi, m, 0, pi/2, 0)*Sum(WignerD(j, + mi1, mi, 0, 3*pi/2, 0)*JxKet(j, mi1), (mi1, -j, j)), (mi, -j, j)) + assert qapply(Jz*JyKet(j, m)) == \ + Sum(hbar*mi*WignerD(j, mi, m, 3*pi/2, -pi/2, pi/2)*Sum(WignerD(j, mi1, + mi, 3*pi/2, pi/2, pi/2)*JyKet(j, mi1), (mi1, -j, j)), (mi, -j, j)) + assert qapply(Jz*JzKet(j, m)) == hbar*m*JzKet(j, m) # Normal operators, coupled states # Numerical - assert qapply(Jz*JxKetCoupled(1,1,(1,1))) == \ - -sqrt(2)*hbar*JxKetCoupled(1,0,(1,1))/2 - assert qapply(Jz*JyKetCoupled(1,1,(1,1))) == \ - -sqrt(2)*hbar*I*JyKetCoupled(1,0,(1,1))/2 - assert qapply(Jz*JzKetCoupled(1,1,(1,1))) == \ - hbar*JzKetCoupled(1,1,(1,1)) - # Symbolic - assert qapply(Jz*JxKetCoupled(j,m,(j1,j2))) == \ - Sum(hbar*mi*WignerD(j,mi,m,0,pi/2,0)*Sum(WignerD(j,mi1,mi,0,3*pi/2,0)*JxKetCoupled(j,mi1,(j1,j2)), (mi1,-j,j)), (mi,-j,j)) - assert qapply(Jz*JyKetCoupled(j,m,(j1,j2))) == \ - Sum(hbar*mi*WignerD(j,mi,m,3*pi/2,-pi/2,pi/2)*Sum(WignerD(j,mi1,mi,3*pi/2,pi/2,pi/2)*JyKetCoupled(j,mi1,(j1,j2)), (mi1,-j,j)), (mi,-j,j)) - assert qapply(Jz*JzKetCoupled(j,m,(j1,j2))) == \ - hbar*m*JzKetCoupled(j,m,(j1,j2)) + assert qapply(Jz*JxKetCoupled(1, 1, (1, 1))) == \ + -sqrt(2)*hbar*JxKetCoupled(1, 0, (1, 1))/2 + assert qapply(Jz*JyKetCoupled(1, 1, (1, 1))) == \ + -sqrt(2)*hbar*I*JyKetCoupled(1, 0, (1, 1))/2 + assert qapply(Jz*JzKetCoupled(1, 1, (1, 1))) == \ + hbar*JzKetCoupled(1, 1, (1, 1)) + # Symbolic + assert qapply(Jz*JxKetCoupled(j, m, (j1, j2))) == \ + Sum(hbar*mi*WignerD(j, mi, m, 0, pi/2, 0)*Sum(WignerD(j, mi1, mi, 0, 3*pi/2, 0)*JxKetCoupled(j, mi1, (j1, j2)), (mi1, -j, j)), (mi, -j, j)) + assert qapply(Jz*JyKetCoupled(j, m, (j1, j2))) == \ + Sum(hbar*mi*WignerD(j, mi, m, 3*pi/2, -pi/2, pi/2)*Sum(WignerD(j, mi1, mi, 3*pi/2, pi/2, pi/2)*JyKetCoupled(j, mi1, (j1, j2)), (mi1, -j, j)), (mi, -j, j)) + assert qapply(Jz*JzKetCoupled(j, m, (j1, j2))) == \ + hbar*m*JzKetCoupled(j, m, (j1, j2)) # Normal operators, uncoupled states # Numerical - assert qapply(Jz*TensorProduct(JxKet(1,1), JxKet(1,1))) == \ - -sqrt(2)*hbar*TensorProduct(JxKet(1,1),JxKet(1,0))/2 - \ - sqrt(2)*hbar*TensorProduct(JxKet(1,0),JxKet(1,1))/2 - assert qapply(Jz*TensorProduct(JyKet(1,1), JyKet(1,1))) == \ - -sqrt(2)*hbar*I*TensorProduct(JyKet(1,1), JyKet(1,0))/2 - \ - sqrt(2)*hbar*I*TensorProduct(JyKet(1,0), JyKet(1,1))/2 - assert qapply(Jz*TensorProduct(JzKet(1,1), JzKet(1,1))) == \ - 2*hbar*TensorProduct(JzKet(1,1), JzKet(1,1)) - assert qapply(Jz*TensorProduct(JzKet(1,1), JzKet(1,-1))) == 0 - # Symbolic - assert qapply(Jz*TensorProduct(JxKet(j1,m1), JxKet(j2,m2))) == \ - TensorProduct(JxKet(j1,m1),Sum(hbar*mi*WignerD(j2,mi,m2,0,pi/2,0)*Sum(WignerD(j2,mi1,mi,0,3*pi/2,0)*JxKet(j2,mi1),(mi1,-j2,j2)),(mi,-j2,j2))) + \ - TensorProduct(Sum(hbar*mi*WignerD(j1,mi,m1,0,pi/2,0)*Sum(WignerD(j1,mi1,mi,0,3*pi/2,0)*JxKet(j1,mi1),(mi1,-j1,j1)),(mi,-j1,j1)),JxKet(j2,m2)) - assert qapply(Jz*TensorProduct(JyKet(j1,m1), JyKet(j2,m2))) == \ - TensorProduct(JyKet(j1,m1),Sum(hbar*mi*WignerD(j2,mi,m2,3*pi/2,-pi/2,pi/2)*Sum(WignerD(j2,mi1,mi,3*pi/2,pi/2,pi/2)*JyKet(j2,mi1),(mi1,-j2,j2)),(mi,-j2,j2))) + \ - TensorProduct(Sum(hbar*mi*WignerD(j1,mi,m1,3*pi/2,-pi/2,pi/2)*Sum(WignerD(j1,mi1,mi,3*pi/2,pi/2,pi/2)*JyKet(j1,mi1),(mi1,-j1,j1)),(mi,-j1,j1)),JyKet(j2,m2)) - assert qapply(Jz*TensorProduct(JzKet(j1,m1), JzKet(j2,m2))) == \ - hbar*m1*TensorProduct(JzKet(j1,m1),JzKet(j2,m2))+hbar*m2*TensorProduct(JzKet(j1,m1),JzKet(j2,m2)) + assert qapply(Jz*TensorProduct(JxKet(1, 1), JxKet(1, 1))) == \ + -sqrt(2)*hbar*TensorProduct(JxKet(1, 1), JxKet(1, 0))/2 - \ + sqrt(2)*hbar*TensorProduct(JxKet(1, 0), JxKet(1, 1))/2 + assert qapply(Jz*TensorProduct(JyKet(1, 1), JyKet(1, 1))) == \ + -sqrt(2)*hbar*I*TensorProduct(JyKet(1, 1), JyKet(1, 0))/2 - \ + sqrt(2)*hbar*I*TensorProduct(JyKet(1, 0), JyKet(1, 1))/2 + assert qapply(Jz*TensorProduct(JzKet(1, 1), JzKet(1, 1))) == \ + 2*hbar*TensorProduct(JzKet(1, 1), JzKet(1, 1)) + assert qapply(Jz*TensorProduct(JzKet(1, 1), JzKet(1, -1))) == 0 + # Symbolic + assert qapply(Jz*TensorProduct(JxKet(j1, m1), JxKet(j2, m2))) == \ + TensorProduct(JxKet(j1, m1), Sum(hbar*mi*WignerD(j2, mi, m2, 0, pi/2, 0)*Sum(WignerD(j2, mi1, mi, 0, 3*pi/2, 0)*JxKet(j2, mi1), (mi1, -j2, j2)), (mi, -j2, j2))) + \ + TensorProduct(Sum(hbar*mi*WignerD(j1, mi, m1, 0, pi/2, 0)*Sum(WignerD(j1, mi1, mi, 0, 3*pi/2, 0)*JxKet(j1, mi1), (mi1, -j1, j1)), (mi, -j1, j1)), JxKet(j2, m2)) + assert qapply(Jz*TensorProduct(JyKet(j1, m1), JyKet(j2, m2))) == \ + TensorProduct(JyKet(j1, m1), Sum(hbar*mi*WignerD(j2, mi, m2, 3*pi/2, -pi/2, pi/2)*Sum(WignerD(j2, mi1, mi, 3*pi/2, pi/2, pi/2)*JyKet(j2, mi1), (mi1, -j2, j2)), (mi, -j2, j2))) + \ + TensorProduct(Sum(hbar*mi*WignerD(j1, mi, m1, 3*pi/2, -pi/2, pi/2)*Sum(WignerD(j1, mi1, mi, 3*pi/2, pi/2, pi/2)*JyKet(j1, mi1), (mi1, -j1, j1)), (mi, -j1, j1)), JyKet(j2, m2)) + assert qapply(Jz*TensorProduct(JzKet(j1, m1), JzKet(j2, m2))) == \ + hbar*m1*TensorProduct(JzKet(j1, m1), JzKet( + j2, m2)) + hbar*m2*TensorProduct(JzKet(j1, m1), JzKet(j2, m2)) # Uncoupled Operators # Numerical - assert qapply(TensorProduct(Jz,1)*TensorProduct(JxKet(1,1),JxKet(1,-1))) == \ - -sqrt(2)*hbar*TensorProduct(JxKet(1,0),JxKet(1,-1))/2 - assert qapply(TensorProduct(1,Jz)*TensorProduct(JxKet(1,1),JxKet(1,-1))) == \ - -sqrt(2)*hbar*TensorProduct(JxKet(1,1),JxKet(1,0))/2 - assert qapply(TensorProduct(Jz,1)*TensorProduct(JyKet(1,1),JyKet(1,-1))) == \ - -sqrt(2)*I*hbar*TensorProduct(JyKet(1,0),JyKet(1,-1))/2 - assert qapply(TensorProduct(1,Jz)*TensorProduct(JyKet(1,1),JyKet(1,-1))) == \ - sqrt(2)*I*hbar*TensorProduct(JyKet(1,1),JyKet(1,0))/2 - assert qapply(TensorProduct(Jz,1)*TensorProduct(JzKet(1,1),JzKet(1,-1))) == \ - hbar*TensorProduct(JzKet(1,1),JzKet(1,-1)) - assert qapply(TensorProduct(1,Jz)*TensorProduct(JzKet(1,1),JzKet(1,-1))) == \ - -hbar*TensorProduct(JzKet(1,1),JzKet(1,-1)) - # Symbolic - assert qapply(TensorProduct(Jz,1)*TensorProduct(JxKet(j1,m1),JxKet(j2,m2))) == \ - TensorProduct(Sum(hbar*mi*WignerD(j1,mi,m1,0,pi/2,0)*Sum(WignerD(j1,mi1,mi,0,3*pi/2,0)*JxKet(j1,mi1),(mi1,-j1,j1)),(mi,-j1,j1)),JxKet(j2,m2)) - assert qapply(TensorProduct(1,Jz)*TensorProduct(JxKet(j1,m1),JxKet(j2,m2))) == \ - TensorProduct(JxKet(j1,m1),Sum(hbar*mi*WignerD(j2,mi,m2,0,pi/2,0)*Sum(WignerD(j2,mi1,mi,0,3*pi/2,0)*JxKet(j2,mi1),(mi1,-j2,j2)),(mi,-j2,j2))) - assert qapply(TensorProduct(Jz,1)*TensorProduct(JyKet(j1,m1),JyKet(j2,m2))) == \ - TensorProduct(Sum(hbar*mi*WignerD(j1,mi,m1,3*pi/2,-pi/2,pi/2)*Sum(WignerD(j1,mi1,mi,3*pi/2,pi/2,pi/2)*JyKet(j1,mi1),(mi1,-j1,j1)),(mi,-j1,j1)),JyKet(j2,m2)) - assert qapply(TensorProduct(1,Jz)*TensorProduct(JyKet(j1,m1),JyKet(j2,m2))) == \ - TensorProduct(JyKet(j1,m1),Sum(hbar*mi*WignerD(j2,mi,m2,3*pi/2,-pi/2,pi/2)*Sum(WignerD(j2,mi1,mi,3*pi/2,pi/2,pi/2)*JyKet(j2,mi1),(mi1,-j2,j2)),(mi,-j2,j2))) - assert qapply(TensorProduct(Jz,1)*TensorProduct(JzKet(j1,m1),JzKet(j2,m2))) == \ - hbar*m1*TensorProduct(JzKet(j1,m1),JzKet(j2,m2)) - assert qapply(TensorProduct(1,Jz)*TensorProduct(JzKet(j1,m1),JzKet(j2,m2))) == \ - hbar*m2*TensorProduct(JzKet(j1,m1),JzKet(j2,m2)) + assert qapply(TensorProduct(Jz, 1)*TensorProduct(JxKet(1, 1), JxKet(1, -1))) == \ + -sqrt(2)*hbar*TensorProduct(JxKet(1, 0), JxKet(1, -1))/2 + assert qapply(TensorProduct(1, Jz)*TensorProduct(JxKet(1, 1), JxKet(1, -1))) == \ + -sqrt(2)*hbar*TensorProduct(JxKet(1, 1), JxKet(1, 0))/2 + assert qapply(TensorProduct(Jz, 1)*TensorProduct(JyKet(1, 1), JyKet(1, -1))) == \ + -sqrt(2)*I*hbar*TensorProduct(JyKet(1, 0), JyKet(1, -1))/2 + assert qapply(TensorProduct(1, Jz)*TensorProduct(JyKet(1, 1), JyKet(1, -1))) == \ + sqrt(2)*I*hbar*TensorProduct(JyKet(1, 1), JyKet(1, 0))/2 + assert qapply(TensorProduct(Jz, 1)*TensorProduct(JzKet(1, 1), JzKet(1, -1))) == \ + hbar*TensorProduct(JzKet(1, 1), JzKet(1, -1)) + assert qapply(TensorProduct(1, Jz)*TensorProduct(JzKet(1, 1), JzKet(1, -1))) == \ + -hbar*TensorProduct(JzKet(1, 1), JzKet(1, -1)) + # Symbolic + assert qapply(TensorProduct(Jz, 1)*TensorProduct(JxKet(j1, m1), JxKet(j2, m2))) == \ + TensorProduct(Sum(hbar*mi*WignerD(j1, mi, m1, 0, pi/2, 0)*Sum(WignerD(j1, mi1, mi, 0, 3*pi/2, 0)*JxKet(j1, mi1), (mi1, -j1, j1)), (mi, -j1, j1)), JxKet(j2, m2)) + assert qapply(TensorProduct(1, Jz)*TensorProduct(JxKet(j1, m1), JxKet(j2, m2))) == \ + TensorProduct(JxKet(j1, m1), Sum(hbar*mi*WignerD(j2, mi, m2, 0, pi/2, 0)*Sum(WignerD(j2, mi1, mi, 0, 3*pi/2, 0)*JxKet(j2, mi1), (mi1, -j2, j2)), (mi, -j2, j2))) + assert qapply(TensorProduct(Jz, 1)*TensorProduct(JyKet(j1, m1), JyKet(j2, m2))) == \ + TensorProduct(Sum(hbar*mi*WignerD(j1, mi, m1, 3*pi/2, -pi/2, pi/2)*Sum(WignerD(j1, mi1, mi, 3*pi/2, pi/2, pi/2)*JyKet(j1, mi1), (mi1, -j1, j1)), (mi, -j1, j1)), JyKet(j2, m2)) + assert qapply(TensorProduct(1, Jz)*TensorProduct(JyKet(j1, m1), JyKet(j2, m2))) == \ + TensorProduct(JyKet(j1, m1), Sum(hbar*mi*WignerD(j2, mi, m2, 3*pi/2, -pi/2, pi/2)*Sum(WignerD(j2, mi1, mi, 3*pi/2, pi/2, pi/2)*JyKet(j2, mi1), (mi1, -j2, j2)), (mi, -j2, j2))) + assert qapply(TensorProduct(Jz, 1)*TensorProduct(JzKet(j1, m1), JzKet(j2, m2))) == \ + hbar*m1*TensorProduct(JzKet(j1, m1), JzKet(j2, m2)) + assert qapply(TensorProduct(1, Jz)*TensorProduct(JzKet(j1, m1), JzKet(j2, m2))) == \ + hbar*m2*TensorProduct(JzKet(j1, m1), JzKet(j2, m2)) + + +def test_rotation(): + a, b, g = symbols('a b g') + j, m = symbols('j m') + #Uncoupled + answ = [JxKet(1,-1)/2 - sqrt(2)*JxKet(1,0)/2 + JxKet(1,1)/2 , + JyKet(1,-1)/2 - sqrt(2)*JyKet(1,0)/2 + JyKet(1,1)/2 , + JzKet(1,-1)/2 - sqrt(2)*JzKet(1,0)/2 + JzKet(1,1)/2] + fun = [state(1, 1) for state in (JxKet, JyKet, JzKet)] + for state in fun: + got = qapply(Rotation(0, pi/2, 0)*state) + assert got in answ + answ.remove(got) + assert not answ + arg = Rotation(a, b, g)*fun[0] + assert qapply(arg) == (-exp(-I*a)*exp(I*g)*cos(b)*JxKet(1,-1)/2 + + exp(-I*a)*exp(I*g)*JxKet(1,-1)/2 - sqrt(2)*exp(-I*a)*sin(b)*JxKet(1,0)/2 + + exp(-I*a)*exp(-I*g)*cos(b)*JxKet(1,1)/2 + exp(-I*a)*exp(-I*g)*JxKet(1,1)/2) + #dummy effective + assert str(qapply(Rotation(a, b, g)*JzKet(j, m), dummy=False)) == str( + qapply(Rotation(a, b, g)*JzKet(j, m), dummy=True)).replace('_','') + #Coupled + ans = [JxKetCoupled(1,-1,(1,1))/2 - sqrt(2)*JxKetCoupled(1,0,(1,1))/2 + + JxKetCoupled(1,1,(1,1))/2 , + JyKetCoupled(1,-1,(1,1))/2 - sqrt(2)*JyKetCoupled(1,0,(1,1))/2 + + JyKetCoupled(1,1,(1,1))/2 , + JzKetCoupled(1,-1,(1,1))/2 - sqrt(2)*JzKetCoupled(1,0,(1,1))/2 + + JzKetCoupled(1,1,(1,1))/2] + fun = [state(1, 1, (1,1)) for state in (JxKetCoupled, JyKetCoupled, JzKetCoupled)] + for state in fun: + got = qapply(Rotation(0, pi/2, 0)*state) + assert got in ans + ans.remove(got) + assert not ans + arg = Rotation(a, b, g)*fun[0] + assert qapply(arg) == ( + -exp(-I*a)*exp(I*g)*cos(b)*JxKetCoupled(1,-1,(1,1))/2 + + exp(-I*a)*exp(I*g)*JxKetCoupled(1,-1,(1,1))/2 - + sqrt(2)*exp(-I*a)*sin(b)*JxKetCoupled(1,0,(1,1))/2 + + exp(-I*a)*exp(-I*g)*cos(b)*JxKetCoupled(1,1,(1,1))/2 + + exp(-I*a)*exp(-I*g)*JxKetCoupled(1,1,(1,1))/2) + #dummy effective + assert str(qapply(Rotation(a,b,g)*JzKetCoupled(j,m,(j1,j2)), dummy=False)) == str( + qapply(Rotation(a,b,g)*JzKetCoupled(j,m,(j1,j2)), dummy=True)).replace('_','') + def test_jzket(): j, m = symbols('j m') # j not integer or half integer - raises(ValueError, lambda: JzKet(S(2)/3,-S(1)/3)) - raises(ValueError, lambda: JzKet(S(2)/3,m)) + raises(ValueError, lambda: JzKet(S(2)/3, -S(1)/3)) + raises(ValueError, lambda: JzKet(S(2)/3, m)) # j < 0 - raises(ValueError, lambda: JzKet(-1,1)) - raises(ValueError, lambda: JzKet(-1,m)) + raises(ValueError, lambda: JzKet(-1, 1)) + raises(ValueError, lambda: JzKet(-1, m)) # m not integer or half integer - raises(ValueError, lambda: JzKet(j,-S(1)/3)) + raises(ValueError, lambda: JzKet(j, -S(1)/3)) # abs(m) > j - raises(ValueError, lambda: JzKet(1,2)) - raises(ValueError, lambda: JzKet(1,-2)) + raises(ValueError, lambda: JzKet(1, 2)) + raises(ValueError, lambda: JzKet(1, -2)) # j-m not integer - raises(ValueError, lambda: JzKet(1,S(1)/2)) + raises(ValueError, lambda: JzKet(1, S(1)/2)) + def test_jzketcoupled(): j, m = symbols('j m') @@ -3558,25 +4261,27 @@ # checks types on coupling scheme raises(TypeError, lambda: JzKetCoupled(1, 1, 1)) raises(TypeError, lambda: JzKetCoupled(1, 1, (1,), 1)) - raises(TypeError, lambda: JzKetCoupled(1, 1, (1,1), (1,))) - raises(TypeError, lambda: JzKetCoupled(1, 1, (1,1,1), (1,2,1), (1,3,1))) + raises(TypeError, lambda: JzKetCoupled(1, 1, (1, 1), (1,))) + raises(TypeError, lambda: JzKetCoupled(1, 1, (1, 1, 1), (1, 2, 1), + (1, 3, 1))) # checks length of coupling terms - raises(ValueError, lambda: JzKetCoupled(1, 1, (1,), ((1,2,1),))) - raises(ValueError, lambda: JzKetCoupled(1, 1, (1,1), ((1,2),))) + raises(ValueError, lambda: JzKetCoupled(1, 1, (1,), ((1, 2, 1),))) + raises(ValueError, lambda: JzKetCoupled(1, 1, (1, 1), ((1, 2),))) # all jn are integer or half-integer raises(ValueError, lambda: JzKetCoupled(1, 1, (S(1)/3, S(2)/3))) # indicies in coupling scheme must be integers - raises(ValueError, lambda: JzKetCoupled(1, 1, (1,1), ((S(1)/2,1,2),) )) - raises(ValueError, lambda: JzKetCoupled(1, 1, (1,1), ((1,S(1)/2,2),) )) + raises(ValueError, lambda: JzKetCoupled(1, 1, (1, 1), ((S(1)/2, 1, 2),) )) + raises(ValueError, lambda: JzKetCoupled(1, 1, (1, 1), ((1, S(1)/2, 2),) )) # indicies out of range - raises(ValueError, lambda: JzKetCoupled(1, 1, (1,1), ((0,2,1),) )) - raises(ValueError, lambda: JzKetCoupled(1, 1, (1,1), ((3,2,1),) )) - raises(ValueError, lambda: JzKetCoupled(1, 1, (1,1), ((1,0,1),) )) - raises(ValueError, lambda: JzKetCoupled(1, 1, (1,1), ((1,3,1),) )) + raises(ValueError, lambda: JzKetCoupled(1, 1, (1, 1), ((0, 2, 1),) )) + raises(ValueError, lambda: JzKetCoupled(1, 1, (1, 1), ((3, 2, 1),) )) + raises(ValueError, lambda: JzKetCoupled(1, 1, (1, 1), ((1, 0, 1),) )) + raises(ValueError, lambda: JzKetCoupled(1, 1, (1, 1), ((1, 3, 1),) )) # all j values in coupling scheme must by integer or half-integer - raises(ValueError, lambda: JzKetCoupled(1, 1, (1,1,1), ((1,2,S(4)/3),(1,3,1)) )) + raises(ValueError, lambda: JzKetCoupled(1, 1, (1, 1, 1), ((1, 2, S( + 4)/3), (1, 3, 1)) )) # each coupling must satisfy |j1-j2| <= j3 <= j1+j2 - raises(ValueError, lambda: JzKetCoupled(1, 1, (1,5))) - raises(ValueError, lambda: JzKetCoupled(5, 1, (1,1))) + raises(ValueError, lambda: JzKetCoupled(1, 1, (1, 5))) + raises(ValueError, lambda: JzKetCoupled(5, 1, (1, 1))) # final j of coupling must be j of the state - raises(ValueError, lambda: JzKetCoupled(1, 1, (1,1), ((1,2,2),) )) + raises(ValueError, lambda: JzKetCoupled(1, 1, (1, 1), ((1, 2, 2),) )) diff -Nru python3-sympy-0.7.2/sympy/physics/quantum/tests/test_state.py python3-sympy-0.7.3/sympy/physics/quantum/tests/test_state.py --- python3-sympy-0.7.2/sympy/physics/quantum/tests/test_state.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/physics/quantum/tests/test_state.py 2013-07-13 17:53:32.000000000 +0000 @@ -12,26 +12,31 @@ x, y, t = symbols('x,y,t') -class TestKet(Ket): + +class CustomKet(Ket): @classmethod def default_args(self): return ("test",) -class TestKetMultipleLabels(Ket): + +class CustomKetMultipleLabels(Ket): @classmethod def default_args(self): return ("r", "theta", "phi") -class TestTimeDepKet(TimeDepKet): + +class CustomTimeDepKet(TimeDepKet): @classmethod def default_args(self): return ("test", "t") -class TestTimeDepKetMultipleLabels(TimeDepKet): + +class CustomTimeDepKetMultipleLabels(TimeDepKet): @classmethod def default_args(self): return ("r", "theta", "phi", "t") + def test_ket(): k = Ket('0') @@ -42,26 +47,26 @@ assert k.label == (Symbol('0'),) assert k.hilbert_space == HilbertSpace() - assert k.is_commutative == False + assert k.is_commutative is False # Make sure this doesn't get converted to the number pi. k = Ket('pi') assert k.label == (Symbol('pi'),) - k = Ket(x,y) - assert k.label == (x,y) + k = Ket(x, y) + assert k.label == (x, y) assert k.hilbert_space == HilbertSpace() - assert k.is_commutative == False + assert k.is_commutative is False assert k.dual_class() == Bra - assert k.dual == Bra(x,y) - assert k.subs(x,y) == Ket(y,y) + assert k.dual == Bra(x, y) + assert k.subs(x, y) == Ket(y, y) - k = TestKet() - assert k == TestKet("test") + k = CustomKet() + assert k == CustomKet("test") - k = TestKetMultipleLabels() - assert k == TestKetMultipleLabels("r", "theta", "phi") + k = CustomKetMultipleLabels() + assert k == CustomKetMultipleLabels("r", "theta", "phi") assert Ket() == Ket('psi') @@ -76,23 +81,24 @@ assert b.label == (Symbol('0'),) assert b.hilbert_space == HilbertSpace() - assert b.is_commutative == False + assert b.is_commutative is False # Make sure this doesn't get converted to the number pi. b = Bra('pi') assert b.label == (Symbol('pi'),) - b = Bra(x,y) - assert b.label == (x,y) + b = Bra(x, y) + assert b.label == (x, y) assert b.hilbert_space == HilbertSpace() - assert b.is_commutative == False + assert b.is_commutative is False assert b.dual_class() == Ket - assert b.dual == Ket(x,y) - assert b.subs(x,y) == Bra(y,y) + assert b.dual == Ket(x, y) + assert b.subs(x, y) == Bra(y, y) assert Bra() == Bra('psi') + def test_ops(): k0 = Ket(0) k1 = Ket(1) @@ -102,7 +108,7 @@ def test_time_dep_ket(): - k = TimeDepKet(0,t) + k = TimeDepKet(0, t) assert isinstance(k, TimeDepKet) assert isinstance(k, KetBase) @@ -110,32 +116,33 @@ assert isinstance(k, QExpr) assert k.label == (Integer(0),) - assert k.args == (Integer(0),t) + assert k.args == (Integer(0), t) assert k.time == t assert k.dual_class() == TimeDepBra - assert k.dual == TimeDepBra(0,t) + assert k.dual == TimeDepBra(0, t) - assert k.subs(t,2) == TimeDepKet(0,2) + assert k.subs(t, 2) == TimeDepKet(0, 2) k = TimeDepKet(x, 0.5) assert k.label == (x,) - assert k.args == (x,sympify(0.5)) + assert k.args == (x, sympify(0.5)) - k = TestTimeDepKet() + k = CustomTimeDepKet() assert k.label == (Symbol("test"),) assert k.time == Symbol("t") - assert k == TestTimeDepKet("test", "t") + assert k == CustomTimeDepKet("test", "t") - k = TestTimeDepKetMultipleLabels() + k = CustomTimeDepKetMultipleLabels() assert k.label == (Symbol("r"), Symbol("theta"), Symbol("phi")) assert k.time == Symbol("t") - assert k == TestTimeDepKetMultipleLabels("r", "theta", "phi", "t") + assert k == CustomTimeDepKetMultipleLabels("r", "theta", "phi", "t") assert TimeDepKet() == TimeDepKet("psi", "t") + def test_time_dep_bra(): - b = TimeDepBra(0,t) + b = TimeDepBra(0, t) assert isinstance(b, TimeDepBra) assert isinstance(b, BraBase) @@ -143,39 +150,42 @@ assert isinstance(b, QExpr) assert b.label == (Integer(0),) - assert b.args == (Integer(0),t) + assert b.args == (Integer(0), t) assert b.time == t assert b.dual_class() == TimeDepKet - assert b.dual == TimeDepKet(0,t) + assert b.dual == TimeDepKet(0, t) k = TimeDepBra(x, 0.5) assert k.label == (x,) - assert k.args == (x,sympify(0.5)) + assert k.args == (x, sympify(0.5)) assert TimeDepBra() == TimeDepBra("psi", "t") + def test_bra_ket_dagger(): - x = symbols('x',complex=True) + x = symbols('x', complex=True) k = Ket('k') b = Bra('b') assert Dagger(k) == Bra('k') assert Dagger(b) == Ket('b') - assert Dagger(k).is_commutative == False + assert Dagger(k).is_commutative is False k2 = Ket('k2') e = 2*I*k + x*k2 assert Dagger(e) == conjugate(x)*Dagger(k2) - 2*I*Dagger(k) + def test_wavefunction(): - x, y, L = symbols('x,y,L', real=True) - n = symbols('n', integer=True) + x, y = symbols('x y', real=True) + L = symbols('L', positive=True) + n = symbols('n', integer=True, positive=True) f = Wavefunction(x**2, x) p = f.prob() lims = f.limits - assert f.is_normalized == False + assert f.is_normalized is False assert f.norm == oo assert f(10) == 100 assert p(10) == 10000 @@ -185,32 +195,32 @@ assert conjugate(f) == Wavefunction(conjugate(f.expr), x) assert conjugate(f) == Dagger(f) - g = Wavefunction(x**2*y+y**2*x, (x, 0, 1), (y, 0, 2)) + g = Wavefunction(x**2*y + y**2*x, (x, 0, 1), (y, 0, 2)) lims_g = g.limits assert lims_g[x] == (0, 1) assert lims_g[y] == (0, 2) - assert g.is_normalized == False + assert g.is_normalized is False assert g.norm == sqrt(42)/3 - assert g(2,4) == 0 - assert g(1,1) == 2 + assert g(2, 4) == 0 + assert g(1, 1) == 2 assert diff(diff(g, x), y) == Wavefunction(2*x + 2*y, (x, 0, 1), (y, 0, 2)) assert conjugate(g) == Wavefunction(conjugate(g.expr), *g.args[1:]) assert conjugate(g) == Dagger(g) h = Wavefunction(sqrt(5)*x**2, (x, 0, 1)) - assert h.is_normalized == True + assert h.is_normalized is True assert h.normalize() == h assert conjugate(h) == Wavefunction(conjugate(h.expr), (x, 0, 1)) assert conjugate(h) == Dagger(h) piab = Wavefunction(sin(n*pi*x/L), (x, 0, L)) assert piab.norm == sqrt(L/2) - assert piab(L+1) == 0 + assert piab(L + 1) == 0 assert piab(0.5) == sin(0.5*n*pi/L) assert piab(0.5, n=1, L=1) == sin(0.5*pi) assert piab.normalize() == \ - Wavefunction(sqrt(2)/sqrt(L)*sin(n*pi*x/L), (x, 0, L)) + Wavefunction(sqrt(2)/sqrt(L)*sin(n*pi*x/L), (x, 0, L)) assert conjugate(piab) == Wavefunction(conjugate(piab.expr), (x, 0, L)) assert conjugate(piab) == Dagger(piab) diff -Nru python3-sympy-0.7.2/sympy/physics/quantum/tests/test_tensorproduct.py python3-sympy-0.7.3/sympy/physics/quantum/tests/test_tensorproduct.py --- python3-sympy-0.7.2/sympy/physics/quantum/tests/test_tensorproduct.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/physics/quantum/tests/test_tensorproduct.py 2013-07-13 17:53:32.000000000 +0000 @@ -10,55 +10,59 @@ from sympy.physics.quantum.density import Density from sympy.core.trace import Tr -A,B,C = symbols('A,B,C', commutative=False) +A, B, C = symbols('A,B,C', commutative=False) x = symbols('x') -mat1 = Matrix([[1,2*I],[1+I,3]]) -mat2 = Matrix([[2*I,3],[4*I,2]]) +mat1 = Matrix([[1, 2*I], [1 + I, 3]]) +mat2 = Matrix([[2*I, 3], [4*I, 2]]) + def test_tensor_product_dagger(): - assert Dagger(TensorProduct(I*A, B)) ==\ - -I*TensorProduct(Dagger(A),Dagger(B)) - assert Dagger(TensorProduct(mat1,mat2)) ==\ - TensorProduct(Dagger(mat1),Dagger(mat2)) + assert Dagger(TensorProduct(I*A, B)) == \ + -I*TensorProduct(Dagger(A), Dagger(B)) + assert Dagger(TensorProduct(mat1, mat2)) == \ + TensorProduct(Dagger(mat1), Dagger(mat2)) + def test_tensor_product_abstract(): - assert TP(x*A,2*B) == x*2*TP(A,B) - assert TP(A,B) != TP(B,A) - assert TP(A,B).is_commutative == False - assert isinstance(TP(A,B), TP) - assert TP(A,B).subs(A,C) == TP(C,B) + assert TP(x*A, 2*B) == x*2*TP(A, B) + assert TP(A, B) != TP(B, A) + assert TP(A, B).is_commutative is False + assert isinstance(TP(A, B), TP) + assert TP(A, B).subs(A, C) == TP(C, B) def test_tensor_product_expand(): - assert TP(A+B,B+C).expand(tensorproduct=True) ==\ - TP(A,B) + TP(A,C) + TP(B,B) + TP(B,C) + assert TP(A + B, B + C).expand(tensorproduct=True) == \ + TP(A, B) + TP(A, C) + TP(B, B) + TP(B, C) def test_tensor_product_commutator(): - assert TP(Comm(A,B),C).doit().expand(tensorproduct=True) ==\ - TP(A*B,C) - TP(B*A,C) - assert Comm(TP(A,B),TP(B,C)).doit() ==\ - TP(A,B)*TP(B,C) - TP(B,C)*TP(A,B) + assert TP(Comm(A, B), C).doit().expand(tensorproduct=True) == \ + TP(A*B, C) - TP(B*A, C) + assert Comm(TP(A, B), TP(B, C)).doit() == \ + TP(A, B)*TP(B, C) - TP(B, C)*TP(A, B) def test_tensor_product_simp(): - assert tensor_product_simp(TP(A,B)*TP(B,C)) == TP(A*B,B*C) + assert tensor_product_simp(TP(A, B)*TP(B, C)) == TP(A*B, B*C) + def test_issue_2824(): # most of the issue regarding sympification of args has been handled # and is tested internally by the use of args_cnc through the quantum # module, but the following is a test from the issue that used to raise. assert TensorProduct(1, Qubit('1')*Qubit('1').dual) == \ - TensorProduct(1, OuterProduct(Qubit(1), QubitBra(1))) + TensorProduct(1, OuterProduct(Qubit(1), QubitBra(1))) + def test_eval_trace(): # This test includes tests with dependencies between TensorProducts #and density operators. Since, the test is more to test the behavior of #TensorProducts it remains here - A, B, C, D, E, F= symbols('A B C D E F', commutative=False) + A, B, C, D, E, F = symbols('A B C D E F', commutative=False) # Density with simple tensor products as args t = TensorProduct(A, B) @@ -69,7 +73,7 @@ ## partial trace with simple tensor products as args t = TensorProduct(A, B, C) d = Density([t, 1.0]) - tr = Tr(d,[1]) + tr = Tr(d, [1]) assert tr.doit() == 1.0*A*Dagger(A)*Tr(B*Dagger(B))*C*Dagger(C) tr = Tr(d, [0, 2]) @@ -89,7 +93,7 @@ 0.5*Tr(C*Dagger(C))*D*Dagger(D)) #Density with mixed states - d = Density([t2+t3, 1.0]) + d = Density([t2 + t3, 1.0]) t = Tr(d) assert t.doit() == ( 1.0*Tr(A*Dagger(A))*Tr(B*Dagger(B)) + 1.0*Tr(A*Dagger(C))*Tr(B*Dagger(D)) + diff -Nru python3-sympy-0.7.2/sympy/physics/secondquant.py python3-sympy-0.7.3/sympy/physics/secondquant.py --- python3-sympy-0.7.2/sympy/physics/secondquant.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/physics/secondquant.py 2013-07-13 17:53:32.000000000 +0000 @@ -15,6 +15,7 @@ from sympy.physics.quantum.qexpr import split_commutative_parts from sympy.core.compatibility import reduce from sympy.utilities.iterables import has_dups +from sympy.utilities import default_sort_key from functools import reduce __all__ = [ @@ -55,24 +56,31 @@ 'simplify_index_permutations', ] + class SecondQuantizationError(Exception): pass + class AppliesOnlyToSymbolicIndex(SecondQuantizationError): pass + class ContractionAppliesOnlyToFermions(SecondQuantizationError): pass + class ViolationOfPauliPrinciple(SecondQuantizationError): pass + class SubstitutionOfAmbigousOperatorFailed(SecondQuantizationError): pass + class WicksTheoremDoesNotApply(SecondQuantizationError): pass + class Dagger(Expr): """ Hermitian conjugate of creation/annihilation operators. @@ -130,7 +138,7 @@ if arg.is_Number: return arg if arg.is_Pow: - return Pow(Dagger(arg.args[0]),arg.args[1]) + return Pow(Dagger(arg.args[0]), arg.args[1]) if arg == I: return -arg else: @@ -173,8 +181,10 @@ def __new__(cls, symbol, upper, lower): try: - upper, signu = _sort_anticommuting_fermions(upper, key=cls._sortkey) - lower, signl = _sort_anticommuting_fermions(lower, key=cls._sortkey) + upper, signu = _sort_anticommuting_fermions( + upper, key=cls._sortkey) + lower, signl = _sort_anticommuting_fermions( + lower, key=cls._sortkey) except ViolationOfPauliPrinciple: return S.Zero @@ -186,7 +196,8 @@ if (signu + signl) % 2: return -TensorSymbol.__new__(cls, symbol, upper, lower) else: - return TensorSymbol.__new__(cls, symbol, upper, lower) + + return TensorSymbol.__new__(cls, symbol, upper, lower) @classmethod def _sortkey(cls, index): @@ -212,13 +223,12 @@ else: return (12, h) - - def _latex(self,printer): - return "%s^{%s}_{%s}" %( - self.symbol, - "".join([ i.name for i in self.args[1]]), - "".join([ i.name for i in self.args[2]]) - ) + def _latex(self, printer): + return "%s^{%s}_{%s}" % ( + self.symbol, + "".join([ i.name for i in self.args[1]]), + "".join([ i.name for i in self.args[2]]) + ) @property def symbol(self): @@ -282,7 +292,7 @@ return self.args[2] def __str__(self): - return "%s(%s,%s)" %self.args + return "%s(%s,%s)" % self.args def doit(self, **kw_args): """ @@ -300,6 +310,7 @@ """ return self + class SqOperator(Expr): """ Base class for Second Quantization operators. @@ -352,7 +363,7 @@ else: return True - def doit(self,**kw_args): + def doit(self, **kw_args): """ FIXME: hack to prevent crash further up... """ @@ -370,12 +381,15 @@ """ raise NotImplementedError('implement apply_operator in a subclass') + class BosonicOperator(SqOperator): pass + class Annihilator(SqOperator): pass + class Creator(SqOperator): pass @@ -419,10 +433,11 @@ amp = sqrt(state[element]) return amp*state.down(element) else: - return Mul(self,state) + return Mul(self, state) def __repr__(self): - return "AnnihilateBoson(%s)"%self.state + return "AnnihilateBoson(%s)" % self.state + class CreateBoson(BosonicOperator, Creator): """ @@ -454,10 +469,10 @@ amp = sqrt(state[element] + 1) return amp*state.up(element) else: - return Mul(self,state) + return Mul(self, state) def __repr__(self): - return "CreateBoson(%s)"%self.state + return "CreateBoson(%s)" % self.state B = AnnihilateBoson Bd = CreateBoson @@ -496,11 +511,12 @@ """ ass = self.args[0].assumptions0 - if ass.get("below_fermi"): return -1 - if ass.get("above_fermi"): return 1 + if ass.get("below_fermi"): + return -1 + if ass.get("above_fermi"): + return 1 return 0 - @property def is_above_fermi(self): """ @@ -639,12 +655,12 @@ c_part, nc_part = state.args_cnc() if isinstance(nc_part[0], FockStateFermionKet): element = self.state - return Mul(*(c_part+[nc_part[0].down(element)]+nc_part[1:])) + return Mul(*(c_part + [nc_part[0].down(element)] + nc_part[1:])) else: - return Mul(self,state) + return Mul(self, state) else: - return Mul(self,state) + return Mul(self, state) @property def is_q_creator(self): @@ -666,7 +682,8 @@ -1 """ - if self.is_below_fermi: return -1 + if self.is_below_fermi: + return -1 return 0 @property @@ -689,7 +706,8 @@ 1 """ - if self.is_above_fermi: return 1 + if self.is_above_fermi: + return 1 return 0 @property @@ -736,10 +754,11 @@ return self.is_only_above_fermi def __repr__(self): - return "AnnihilateFermion(%s)"%self.state + return "AnnihilateFermion(%s)" % self.state + + def _latex(self, printer): + return "a_{%s}" % self.state.name - def _latex(self,printer): - return "a_{%s}"%self.state.name class CreateFermion(FermionicOperator, Creator): """ @@ -770,7 +789,6 @@ element = self.state return state.up(element) - elif isinstance(state, Mul): c_part, nc_part = state.args_cnc() if isinstance(nc_part[0], FockStateFermionKet): @@ -799,7 +817,8 @@ 1 """ - if self.is_above_fermi: return 1 + if self.is_above_fermi: + return 1 return 0 @property @@ -822,7 +841,8 @@ -1 """ - if self.is_below_fermi: return -1 + if self.is_below_fermi: + return -1 return 0 @property @@ -868,16 +888,15 @@ return self.is_only_below_fermi def __repr__(self): - return "CreateFermion(%s)"%self.state + return "CreateFermion(%s)" % self.state - def _latex(self,printer): - return "a^\\dagger_{%s}"%self.state.name + def _latex(self, printer): + return "a^\\dagger_{%s}" % self.state.name Fd = CreateFermion F = AnnihilateFermion - class FockState(Expr): """ Many particle Fock state with a sequence of occupation numbers. @@ -912,7 +931,7 @@ return ("FockState(%r)") % (self.args) def __str__(self): - return "%s%r%s" % (self.lbracket,self._labels(),self.rbracket) + return "%s%r%s" % (self.lbracket, self._labels(), self.rbracket) def _labels(self): return self.args[0] @@ -920,6 +939,7 @@ def __len__(self): return len(self.args[0]) + class BosonState(FockState): """ Base class for FockStateBoson(Ket/Bra). @@ -941,7 +961,7 @@ """ i = int(i) new_occs = list(self.args[0]) - new_occs[i] = new_occs[i]+S.One + new_occs[i] = new_occs[i] + S.One return self.__class__(new_occs) def down(self, i): @@ -960,10 +980,10 @@ """ i = int(i) new_occs = list(self.args[0]) - if new_occs[i]==S.Zero: + if new_occs[i] == S.Zero: return S.Zero else: - new_occs[i] = new_occs[i]-S.One + new_occs[i] = new_occs[i] - S.One return self.__class__(new_occs) @@ -972,13 +992,14 @@ Base class for FockStateFermion(Ket/Bra). """ - fermi_level=0 + fermi_level = 0 def __new__(cls, occupations, fermi_level=0): - occupations = list(map(sympify,occupations)) - if len(occupations) >1: + occupations = list(map(sympify, occupations)) + if len(occupations) > 1: try: - (occupations,sign) = _sort_anticommuting_fermions(occupations, key=hash) + (occupations, sign) = _sort_anticommuting_fermions( + occupations, key=hash) except ViolationOfPauliPrinciple: return S.Zero else: @@ -989,11 +1010,10 @@ if cls._count_holes(occupations) > fermi_level: return S.Zero - - if sign%2: - return S.NegativeOne*FockState.__new__(cls,occupations) + if sign % 2: + return S.NegativeOne*FockState.__new__(cls, occupations) else: - return FockState.__new__(cls,occupations) + return FockState.__new__(cls, occupations) def up(self, i): """ @@ -1034,11 +1054,11 @@ return S.Zero else: if present: - hole = Dummy("i",below_fermi=True) - return KroneckerDelta(i,hole)*self._remove_orbit(i) + hole = Dummy("i", below_fermi=True) + return KroneckerDelta(i, hole)*self._remove_orbit(i) else: - particle = Dummy("a",above_fermi=True) - return KroneckerDelta(i,particle)*self._add_orbit(i) + particle = Dummy("a", above_fermi=True) + return KroneckerDelta(i, particle)*self._add_orbit(i) def down(self, i): """ @@ -1082,30 +1102,27 @@ return self._add_orbit(i) else: if present: - hole = Dummy("i",below_fermi=True) - return KroneckerDelta(i,hole)*self._add_orbit(i) + hole = Dummy("i", below_fermi=True) + return KroneckerDelta(i, hole)*self._add_orbit(i) else: - particle = Dummy("a",above_fermi=True) - return KroneckerDelta(i,particle)*self._remove_orbit(i) - - + particle = Dummy("a", above_fermi=True) + return KroneckerDelta(i, particle)*self._remove_orbit(i) @classmethod - def _only_below_fermi(cls,i): + def _only_below_fermi(cls, i): """ Tests if given orbit is only below fermi surface. If nothing can be concluded we return a conservative False. """ if i.is_number: - return i<= cls.fermi_level + return i <= cls.fermi_level if i.assumptions0.get('below_fermi'): return True return False - @classmethod - def _only_above_fermi(cls,i): + def _only_above_fermi(cls, i): """ Tests if given orbit is only above fermi surface. @@ -1113,51 +1130,49 @@ If nothing can be concluded we return a conservative False. """ if i.is_number: - return i> cls.fermi_level + return i > cls.fermi_level if i.assumptions0.get('above_fermi'): return True return not cls.fermi_level - - def _remove_orbit(self,i): + def _remove_orbit(self, i): """ Removes particle/fills hole in orbit i. No input tests performed here. """ new_occs = list(self.args[0]) pos = new_occs.index(i) del new_occs[pos] - if (pos)%2: - return S.NegativeOne*self.__class__(new_occs,self.fermi_level) + if (pos) % 2: + return S.NegativeOne*self.__class__(new_occs, self.fermi_level) else: return self.__class__(new_occs, self.fermi_level) - def _add_orbit(self,i): + def _add_orbit(self, i): """ Adds particle/creates hole in orbit i. No input tests performed here. """ - return self.__class__((i,)+self.args[0], self.fermi_level) + return self.__class__((i,) + self.args[0], self.fermi_level) @classmethod - def _count_holes(cls,list): + def _count_holes(cls, list): """ returns number of identified hole states in list. """ return len([i for i in list if cls._only_below_fermi(i)]) - def _negate_holes(self,list): - return tuple([-i if i<=self.fermi_level else i for i in list]) + def _negate_holes(self, list): + return tuple([-i if i <= self.fermi_level else i for i in list]) def __repr__(self): if self.fermi_level: - return "FockStateKet(%r, fermi_level=%s)"%(self.args[0],self.fermi_level) + return "FockStateKet(%r, fermi_level=%s)" % (self.args[0], self.fermi_level) else: - return "FockStateKet(%r)"%(self.args[0],) + return "FockStateKet(%r)" % (self.args[0],) def _labels(self): return self._negate_holes(self.args[0]) - class FockStateKet(FockState): """ Representation of a ket. @@ -1173,14 +1188,14 @@ lbracket = '<' rbracket = '|' - def __mul__(self, other): if isinstance(other, FockStateKet): return InnerProduct(self, other) else: return Expr.__mul__(self, other) -class FockStateBosonKet(BosonState,FockStateKet): + +class FockStateBosonKet(BosonState, FockStateKet): """ Many particle Fock state with a sequence of occupation numbers. @@ -1196,7 +1211,8 @@ def _dagger_(self): return FockStateBosonBra(*self.args) -class FockStateBosonBra(BosonState,FockStateBra): + +class FockStateBosonBra(BosonState, FockStateBra): """ Describes a collection of BosonBra particles. @@ -1210,7 +1226,8 @@ def _dagger_(self): return FockStateBosonKet(*self.args) -class FockStateFermionKet(FermionState,FockStateKet): + +class FockStateFermionKet(FermionState, FockStateKet): """ Many-particle Fock state with a sequence of occupied orbits. @@ -1233,7 +1250,8 @@ def _dagger_(self): return FockStateFermionBra(*self.args) -class FockStateFermionBra(FermionState,FockStateBra): + +class FockStateFermionBra(FermionState, FockStateBra): """ See Also ======== @@ -1255,6 +1273,7 @@ FBra = FockStateFermionBra FKet = FockStateFermionKet + def _apply_Mul(m): """ Take a Mul instance with operators and apply them to states. @@ -1290,18 +1309,19 @@ return _apply_Mul(Mul(*(c_part + nc_part[:-2] + [result]))) elif isinstance(next_to_last, Pow): if isinstance(next_to_last.base, SqOperator) and \ - next_to_last.exp.is_Integer: + next_to_last.exp.is_Integer: if next_to_last.base.is_symbolic: return m else: result = last for i in range(next_to_last.exp): result = next_to_last.base.apply_operator(result) - if result == 0: break + if result == 0: + break if result == 0: return S.Zero else: - return _apply_Mul(Mul(*(c_part+nc_part[:-2]+[result]))) + return _apply_Mul(Mul(*(c_part + nc_part[:-2] + [result]))) else: return m elif isinstance(next_to_last, FockStateBra): @@ -1309,7 +1329,7 @@ if result == 0: return S.Zero else: - return _apply_Mul(Mul(*(c_part+nc_part[:-2]+[result]))) + return _apply_Mul(Mul(*(c_part + nc_part[:-2] + [result]))) else: return m else: @@ -1330,7 +1350,7 @@ """ e = e.expand() muls = e.atoms(Mul) - subs_list = [(m,_apply_Mul(m)) for m in iter(muls)] + subs_list = [(m, _apply_Mul(m)) for m in iter(muls)] return e.subs(subs_list) @@ -1354,8 +1374,8 @@ @classmethod def eval(cls, bra, ket): result = S.One - for i,j in zip(bra.args[0], ket.args[0]): - result *= KroneckerDelta(i,j) + for i, j in zip(bra.args[0], ket.args[0]): + result *= KroneckerDelta(i, j) if result == 0: break return result @@ -1390,16 +1410,17 @@ >>> b = VarBosonicBasis(5) >>> o = B(0) >>> matrix_rep(o, b) - [0, 1, 0, 0, 0] - [0, 0, sqrt(2), 0, 0] - [0, 0, 0, sqrt(3), 0] - [0, 0, 0, 0, 2] - [0, 0, 0, 0, 0] + Matrix([ + [0, 1, 0, 0, 0], + [0, 0, sqrt(2), 0, 0], + [0, 0, 0, sqrt(3), 0], + [0, 0, 0, 0, 2], + [0, 0, 0, 0, 0]]) """ a = zeros(len(basis)) for i in range(len(basis)): for j in range(len(basis)): - a[i,j] = apply_operators(Dagger(basis[i])*op*basis[j]) + a[i, j] = apply_operators(Dagger(basis[i])*op*basis[j]) return a @@ -1420,7 +1441,8 @@ >>> from sympy.physics.secondquant import VarBosonicBasis >>> b = VarBosonicBasis(5) >>> b - [FockState((0,)), FockState((1,)), FockState((2,)), FockState((3,)), FockState((4,))] + [FockState((0,)), FockState((1,)), FockState((2,)), + FockState((3,)), FockState((4,))] """ def __init__(self, n_max): @@ -1646,7 +1668,8 @@ >>> comm = Commutator(Fd(p)*Fd(q),F(i)); comm Commutator(CreateFermion(p)*CreateFermion(q), AnnihilateFermion(i)) >>> comm.doit(wicks=True) - -KroneckerDelta(p, i)*CreateFermion(q) + KroneckerDelta(q, i)*CreateFermion(p) + -KroneckerDelta(i, p)*CreateFermion(q) + + KroneckerDelta(i, q)*CreateFermion(p) """ @@ -1654,7 +1677,7 @@ nargs = 2 @classmethod - def eval(cls, a,b): + def eval(cls, a, b): """ The Commutator [A,B] is on canonical form if A < B. @@ -1668,8 +1691,10 @@ >>> Commutator.eval(c1, c2) 0 """ - if not (a and b): return S.Zero - if a == b: return S.Zero + if not (a and b): + return S.Zero + if a == b: + return S.Zero if a.is_commutative or b.is_commutative: return S.Zero @@ -1677,11 +1702,11 @@ # [A+B,C] -> [A,C] + [B,C] # a = a.expand() - if isinstance(a,Add): - return Add(*[cls(term,b) for term in a.args]) + if isinstance(a, Add): + return Add(*[cls(term, b) for term in a.args]) b = b.expand() - if isinstance(b,Add): - return Add(*[cls(a,term) for term in b.args]) + if isinstance(b, Add): + return Add(*[cls(a, term) for term in b.args]) # # [xA,yB] -> xy*[A,B] @@ -1692,28 +1717,26 @@ if c_part: return Mul(Mul(*c_part), cls(Mul._from_args(nca), Mul._from_args(ncb))) - # # single second quantization operators # if isinstance(a, BosonicOperator) and isinstance(b, BosonicOperator): - if isinstance(b,CreateBoson) and isinstance(a,AnnihilateBoson): - return KroneckerDelta(a.state,b.state) - if isinstance(a,CreateBoson) and isinstance(b,AnnihilateBoson): - return S.NegativeOne*KroneckerDelta(a.state,b.state) + if isinstance(b, CreateBoson) and isinstance(a, AnnihilateBoson): + return KroneckerDelta(a.state, b.state) + if isinstance(a, CreateBoson) and isinstance(b, AnnihilateBoson): + return S.NegativeOne*KroneckerDelta(a.state, b.state) else: return S.Zero if isinstance(a, FermionicOperator) and isinstance(b, FermionicOperator): - return wicks(a*b)- wicks(b*a) + return wicks(a*b) - wicks(b*a) # # Canonical ordering of arguments # - if a > b: + if a.sort_key() > b.sort_key(): return S.NegativeOne*cls(b, a) - - def doit(self,**hints): + def doit(self, **hints): """ Enables the computation of complex expressions. @@ -1743,19 +1766,17 @@ return (a*b - b*a).doit(**hints) - def __repr__(self): - return "Commutator(%s,%s)" %(self.args[0],self.args[1]) + return "Commutator(%s,%s)" % (self.args[0], self.args[1]) def __str__(self): - return "[%s,%s]" %(self.args[0],self.args[1]) + return "[%s,%s]" % (self.args[0], self.args[1]) - def _latex(self,printer): - return "\\left[%s,%s\\right]"%tuple([ + def _latex(self, printer): + return "\\left[%s,%s\\right]" % tuple([ printer._print(arg) for arg in self.args]) - class NO(Expr): """ This Object is used to represent normal ordering brackets. @@ -1786,8 +1807,7 @@ nargs = 1 is_commutative = False - - def __new__(cls,arg): + def __new__(cls, arg): """ Use anticommutation to get canonical form of operators. @@ -1817,7 +1837,6 @@ else: coeff = S.One - # {ab{cd}} = {abcd} newseq = [] foundit = False @@ -1835,16 +1854,16 @@ raise NotImplementedError try: - newseq,sign = _sort_anticommuting_fermions(seq) + newseq, sign = _sort_anticommuting_fermions(seq) except ViolationOfPauliPrinciple: return S.Zero - if sign%2: + if sign % 2: return (S.NegativeOne*coeff)*cls(Mul(*newseq)) elif sign: return coeff*cls(Mul(*newseq)) else: - pass #since sign==0, no permutations was necessary + pass # since sign==0, no permutations was necessary # if we couldn't do anything with Mul object, we just # mark it as normal ordered @@ -1852,7 +1871,7 @@ return coeff*cls(Mul(*newseq)) return Expr.__new__(cls, Mul(*newseq)) - if isinstance(arg,NO): + if isinstance(arg, NO): return arg # if object was not Mul or Add, normal ordering does not apply @@ -1929,7 +1948,7 @@ if kw_args.get("remove_brackets", True): return self._remove_brackets() else: - return self.__new__(type(self),self.args[0].doit(**kw_args)) + return self.__new__(type(self), self.args[0].doit(**kw_args)) def _remove_brackets(self): """ @@ -1940,7 +1959,7 @@ """ # check if any creator is also an annihilator - subslist=[] + subslist = [] for i in self.iter_q_creators(): if self[i].is_q_annihilator: assume = self[i].state.assumptions0 @@ -1950,20 +1969,20 @@ # create indices with fermi restriction assume.pop("above_fermi", None) - assume["below_fermi"]=True + assume["below_fermi"] = True below = Dummy('i', **assume) assume.pop("below_fermi", None) - assume["above_fermi"]=True + assume["above_fermi"] = True above = Dummy('a', **assume) cls = type(self[i]) split = ( - self[i].__new__(cls,below) - * KroneckerDelta(below,self[i].state) - + self[i].__new__(cls,above) - * KroneckerDelta(above,self[i].state) - ) - subslist.append((self[i],split)) + self[i].__new__(cls, below) + * KroneckerDelta(below, self[i].state) + + self[i].__new__(cls, above) + * KroneckerDelta(above, self[i].state) + ) + subslist.append((self[i], split)) else: raise SubstitutionOfAmbigousOperatorFailed(self[i]) if subslist: @@ -1988,8 +2007,8 @@ """ return NO(self._remove_brackets) - def __getitem__(self,i): - if isinstance(i,slice): + def __getitem__(self, i): + if isinstance(i, slice): indices = i.indices(len(self)) return [self.args[0].args[i] for i in range(*indices)] else: @@ -2020,7 +2039,7 @@ """ ops = self.args[0].args - iter = range(len(ops)-1, -1, -1) + iter = range(len(ops) - 1, -1, -1) for i in iter: if ops[i].is_q_annihilator: yield i @@ -2072,22 +2091,22 @@ NO(AnnihilateFermion(p)*AnnihilateFermion(r)) """ - arg0 = self.args[0] # it's a Mul by definition of how it's created + arg0 = self.args[0] # it's a Mul by definition of how it's created mul = arg0._new_rawargs(arg0.args[:i] + arg0.args[i + 1:]) return NO(mul) - def _latex(self,printer): - return "\\left\\{%s\\right\\}"%printer._print(self.args[0]) + def _latex(self, printer): + return "\\left\\{%s\\right\\}" % printer._print(self.args[0]) def __repr__(self): - return "NO(%s)"%self.args[0] + return "NO(%s)" % self.args[0] def __str__(self): return ":%s:" % self.args[0] # @cacheit -def contraction(a,b): +def contraction(a, b): """ Calculates contraction of Fermionic operators a and b. @@ -2112,9 +2131,9 @@ the fermi surface: >>> contraction(Fd(p),F(q)) - KroneckerDelta(p, q)*KroneckerDelta(q, _i) + KroneckerDelta(_i, q)*KroneckerDelta(p, q) >>> contraction(F(p),Fd(q)) - KroneckerDelta(p, q)*KroneckerDelta(q, _a) + KroneckerDelta(_a, q)*KroneckerDelta(p, q) Two creators or two annihilators always vanishes: @@ -2124,44 +2143,46 @@ 0 """ - if isinstance(b,FermionicOperator) and isinstance(a,FermionicOperator): - if isinstance(a,AnnihilateFermion) and isinstance(b,CreateFermion): + if isinstance(b, FermionicOperator) and isinstance(a, FermionicOperator): + if isinstance(a, AnnihilateFermion) and isinstance(b, CreateFermion): if b.state.assumptions0.get("below_fermi"): return S.Zero if a.state.assumptions0.get("below_fermi"): return S.Zero if b.state.assumptions0.get("above_fermi"): - return KroneckerDelta(a.state,b.state) + return KroneckerDelta(a.state, b.state) if a.state.assumptions0.get("above_fermi"): - return KroneckerDelta(a.state,b.state) + return KroneckerDelta(a.state, b.state) - return (KroneckerDelta(a.state,b.state)* - KroneckerDelta(b.state,Dummy('a', above_fermi=True))) - if isinstance(b,AnnihilateFermion) and isinstance(a,CreateFermion): + return (KroneckerDelta(a.state, b.state)* + KroneckerDelta(b.state, Dummy('a', above_fermi=True))) + if isinstance(b, AnnihilateFermion) and isinstance(a, CreateFermion): if b.state.assumptions0.get("above_fermi"): return S.Zero if a.state.assumptions0.get("above_fermi"): return S.Zero if b.state.assumptions0.get("below_fermi"): - return KroneckerDelta(a.state,b.state) + return KroneckerDelta(a.state, b.state) if a.state.assumptions0.get("below_fermi"): - return KroneckerDelta(a.state,b.state) + return KroneckerDelta(a.state, b.state) - return (KroneckerDelta(a.state,b.state)* - KroneckerDelta(b.state,Dummy('i', below_fermi=True))) + return (KroneckerDelta(a.state, b.state)* + KroneckerDelta(b.state, Dummy('i', below_fermi=True))) # vanish if 2xAnnihilator or 2xCreator return S.Zero else: #not fermion operators - t = ( isinstance(i,FermionicOperator) for i in (a,b) ) + t = ( isinstance(i, FermionicOperator) for i in (a, b) ) raise ContractionAppliesOnlyToFermions(*t) + def _sqkey(sq_operator): """Generates key for canonical sorting of SQ operators.""" return sq_operator._sortkey() + def _sort_anticommuting_fermions(string1, key=_sqkey): """Sort fermionic operators to canonical order, assuming all pairs anticommute. @@ -2183,8 +2204,8 @@ verified = False sign = 0 - rng = list(range(len(string1)-1)) - rev = list(range(len(string1)-3,-1,-1)) + rng = list(range(len(string1) - 1)) + rev = list(range(len(string1) - 3, -1, -1)) keys = list(map(key, string1)) key_val = dict(list(zip(keys, string1))) @@ -2193,26 +2214,27 @@ verified = True for i in rng: left = keys[i] - right = keys[i+1] + right = keys[i + 1] if left == right: - raise ViolationOfPauliPrinciple([left,right]) + raise ViolationOfPauliPrinciple([left, right]) if left > right: verified = False - keys[i:i+2] = [right, left] - sign = sign+1 + keys[i:i + 2] = [right, left] + sign = sign + 1 if verified: break for i in rev: left = keys[i] - right = keys[i+1] + right = keys[i + 1] if left == right: - raise ViolationOfPauliPrinciple([left,right]) + raise ViolationOfPauliPrinciple([left, right]) if left > right: verified = False - keys[i:i+2] = [right, left] - sign = sign+1 + keys[i:i + 2] = [right, left] + sign = sign + 1 string1 = [ key_val[k] for k in keys ] - return (string1,sign) + return (string1, sign) + def evaluate_deltas(e): """ @@ -2278,18 +2300,16 @@ f(_i)*KroneckerDelta(_i, _p) """ - # We treat Deltas only in mul objects - # for general function objects we don't evaluate KroneckerDeltas in arguments, # but here we hard code exceptions to this rule accepted_functions = ( - Add, - ) + Add, + ) if isinstance(e, accepted_functions): return e.func(*[evaluate_deltas(arg) for arg in e.args]) - elif isinstance(e,Mul): + elif isinstance(e, Mul): # find all occurences of delta function and count each index present in # expression. deltas = [] @@ -2300,17 +2320,20 @@ indices[s] += 1 else: indices[s] = 0 # geek counting simplifies logic below - if isinstance(i, KroneckerDelta): deltas.append(i) + if isinstance(i, KroneckerDelta): + deltas.append(i) for d in deltas: # If we do something, and there are more deltas, we should recurse # to treat the resulting expression properly if indices[d.killable_index]: - e = e.subs(d.killable_index,d.preferred_index) - if len(deltas)>1: return evaluate_deltas(e) + e = e.subs(d.killable_index, d.preferred_index) + if len(deltas) > 1: + return evaluate_deltas(e) elif indices[d.preferred_index] and d.indices_contain_equal_information: - e = e.subs(d.preferred_index,d.killable_index) - if len(deltas)>1: return evaluate_deltas(e) + e = e.subs(d.preferred_index, d.killable_index) + if len(deltas) > 1: + return evaluate_deltas(e) else: pass @@ -2385,30 +2408,30 @@ # setup the replacing dummies if new_indices: - letters_above = pretty_indices.get('above', "") - letters_below = pretty_indices.get('below', "") - letters_general= pretty_indices.get('general', "") - len_above = len(letters_above) - len_below = len(letters_below) - len_general= len(letters_general) + letters_above = pretty_indices.get('above', "") + letters_below = pretty_indices.get('below', "") + letters_general = pretty_indices.get('general', "") + len_above = len(letters_above) + len_below = len(letters_below) + len_general = len(letters_general) def _i(number): try: return letters_below[number] except IndexError: - return 'i_'+str(number-len_below) + return 'i_' + str(number - len_below) def _a(number): try: return letters_above[number] except IndexError: - return 'a_'+str(number-len_above) + return 'a_' + str(number - len_above) def _p(number): try: return letters_general[number] except IndexError: - return 'p_'+str(number-len_general) + return 'p_' + str(number - len_general) aboves = [] belows = [] @@ -2416,7 +2439,7 @@ dummies = expr.atoms(Dummy) if not new_indices: - dummies = sorted(dummies) + dummies = sorted(dummies, key=default_sort_key) # generate lists with the dummies we will insert a = i = p = 0 @@ -2424,13 +2447,19 @@ assum = d.assumptions0 if assum.get("above_fermi"): - if new_indices: sym = _a(a); a +=1 + if new_indices: + sym = _a(a) + a += 1 l1 = aboves elif assum.get("below_fermi"): - if new_indices: sym = _i(i); i +=1 + if new_indices: + sym = _i(i) + i += 1 l1 = belows else: - if new_indices: sym = _p(p); p +=1 + if new_indices: + sym = _p(p) + p += 1 l1 = generals if new_indices: @@ -2438,7 +2467,6 @@ else: l1.append(d) - expr = expr.expand() terms = Add.make_args(expr) new_terms = [] @@ -2446,7 +2474,7 @@ i = iter(belows) a = iter(aboves) p = iter(generals) - ordered = _get_ordered_dummies(term) + ordered = _get_ordered_dummies(term) subsdict = {} for d in ordered: if d.assumptions0.get('below_fermi'): @@ -2479,16 +2507,19 @@ new_terms.append(term.subs(subslist)) return Add(*new_terms) + class KeyPrinter(StrPrinter): """Printer for which only equal objects are equal in print""" def _print_Dummy(self, expr): return "(%s_%i)" % (expr.name, expr.dummy_index) + def __kprint(expr): p = KeyPrinter() return p.doprint(expr) -def _get_ordered_dummies(mul, verbose = False): + +def _get_ordered_dummies(mul, verbose=False): """Returns all dummies in the mul sorted in canonical order The purpose of the canonical ordering is that dummies can be substituted @@ -2567,7 +2598,8 @@ def _key(d): dumstruct = [ fac for fac in fac_dum if d in fac_dum[fac] ] - other_dums = reduce(set.union, [ fac_dum[fac] for fac in dumstruct ], set()) + other_dums = reduce( + set.union, [ fac_dum[fac] for fac in dumstruct ], set()) fac = dumstruct[-1] if other_dums is fac_dum[fac]: other_dums = fac_dum[fac].copy() @@ -2576,13 +2608,14 @@ for d2 in other_dums: masked_facs = [ fac.replace(dum_repr[d2], mask[d2]) for fac in masked_facs ] - all_masked = [ fac.replace(dum_repr[d], mask[d]) for fac in masked_facs ] + all_masked = [ fac.replace(dum_repr[d], mask[d]) + for fac in masked_facs ] masked_facs = dict(list(zip(dumstruct, masked_facs))) # dummies for which the ordering cannot be determined if has_dups(all_masked): all_masked.sort() - return mask[d], tuple(all_masked) # positions are ambiguous + return mask[d], tuple(all_masked) # positions are ambiguous # sort factors according to fully masked strings keydict = dict(list(zip(dumstruct, all_masked))) @@ -2591,7 +2624,7 @@ pos_val = [] for fac in dumstruct: - if isinstance(fac,AntiSymmetricTensor): + if isinstance(fac, AntiSymmetricTensor): if d in fac.upper: pos_val.append('u') if d in fac.lower: @@ -2611,7 +2644,7 @@ # fallback to position in string representation facpos = -1 while 1: - facpos = masked_facs[fac].find(dum_repr[d], facpos+1) + facpos = masked_facs[fac].find(dum_repr[d], facpos + 1) if facpos == -1: break pos_val.append(facpos) @@ -2630,6 +2663,7 @@ result = _determine_ambiguous(mul, result, unordered) return result + def _determine_ambiguous(term, ordered, ambiguous_groups): # We encountered a term for which the dummy substitution is ambiguous. # This happens for terms with 2 or more contractions between factors that @@ -2686,6 +2720,7 @@ ordered = result return ordered + class _SymbolFactory(object): def __init__(self, label): self._counterVar = 0 @@ -2711,7 +2746,7 @@ s = Symbol("%s%i" % (self._label, self._counterVar)) self._counterVar += 1 return s -_symbol_factory = _SymbolFactory('_]"]_') # most certainly a unique label +_symbol_factory = _SymbolFactory('_]"]_') # most certainly a unique label @cacheit @@ -2732,15 +2767,15 @@ else: result = [NO(Mul(*string1))] - for i in range(len(string1)-1): - for j in range(i+1,len(string1)): + for i in range(len(string1) - 1): + for j in range(i + 1, len(string1)): - c = contraction(string1[i],string1[j]) + c = contraction(string1[i], string1[j]) if c: # print "found contraction",c - sign = (j-i+1) %2 + sign = (j - i + 1) % 2 if sign: coeff = S.NegativeOne*c else: @@ -2760,7 +2795,7 @@ # and string1[:i] <---> string1[j+1:]. # # This leaves the case: - oplist = string1[i+1:j] + string1[j+1:] + oplist = string1[i + 1:j] + string1[j + 1:] if oplist: @@ -2771,7 +2806,6 @@ else: result.append(coeff*NO( Mul(*string1[:i]))) - if keep_only_fully_contracted: break # next iteration over i leaves leftmost operator string1[0] uncontracted @@ -2796,7 +2830,8 @@ By default, the expression is expanded: >>> wicks(F(p)*(F(q)+F(r))) # doctest: +SKIP - NO(AnnihilateFermion(p)*AnnihilateFermion(q)) + NO(AnnihilateFermion(p)*AnnihilateFermion(r)) + NO(AnnihilateFermion(p)*AnnihilateFermion(q)) + NO( + AnnihilateFermion(p)*AnnihilateFermion(r)) With the keyword 'keep_only_fully_contracted=True', only fully contracted terms are returned. @@ -2807,30 +2842,29 @@ >>> p, q, r = symbols('p q r', cls=Dummy) >>> wicks(Fd(p)*(F(q)+F(r)), keep_only_fully_contracted=True) # doctest: +SKIP - KroneckerDelta(_i, _q)*KroneckerDelta(_p, _q) + KroneckerDelta(_i, _r)*KroneckerDelta(_p, _r) + KroneckerDelta(_i, _q)*KroneckerDelta( + _p, _q) + KroneckerDelta(_i, _r)*KroneckerDelta(_p, _r) """ - if not e: return S.Zero - opts={ - 'simplify_kronecker_deltas':False, - 'expand':True, - 'simplify_dummies':False, - 'keep_only_fully_contracted':False - } + opts = { + 'simplify_kronecker_deltas': False, + 'expand': True, + 'simplify_dummies': False, + 'keep_only_fully_contracted': False + } opts.update(kw_args) - # check if we are already normally ordered - if isinstance(e,NO): + if isinstance(e, NO): if opts['keep_only_fully_contracted']: return S.Zero else: return e - elif isinstance(e,FermionicOperator): + elif isinstance(e, FermionicOperator): if opts['keep_only_fully_contracted']: return S.Zero else: @@ -2847,7 +2881,6 @@ else: return Add(*[ wicks(term, **kw_args) for term in e.args]) - # For Mul-objects we can actually do something if isinstance(e, Mul): @@ -2862,17 +2895,16 @@ string1.append(factor) n = len(string1) - # catch trivial cases if n == 0: - result= e - elif n==1: + result = e + elif n == 1: if opts['keep_only_fully_contracted']: return S.Zero else: result = e - else: # non-trivial + else: # non-trivial if isinstance(string1[0], BosonicOperator): raise NotImplementedError @@ -2882,7 +2914,7 @@ # recursion over higher order contractions result = _get_contractions(string1, keep_only_fully_contracted=opts['keep_only_fully_contracted'] ) - result = Mul(*c_part)*result + result = Mul(*c_part)*result if opts['expand']: result = result.expand() @@ -2894,6 +2926,7 @@ # there was nothing to do return e + class PermutationOperator(Expr): """ Represents the index permutation operator P(ij). @@ -2901,17 +2934,16 @@ P(ij)*f(i)*g(j) = f(i)*g(j) - f(j)*g(i) """ is_commutative = True - def __new__(cls, i,j): - i,j = list(map(sympify,(i,j))) - if (i>j): - obj = Basic.__new__(cls,j,i) + + def __new__(cls, i, j): + i, j = list(map(sympify, (i, j))) + if (i > j): + obj = Basic.__new__(cls, j, i) else: - obj = Basic.__new__(cls,i,j) + obj = Basic.__new__(cls, i, j) return obj - - - def get_permuted(self,expr): + def get_permuted(self, expr): """ Returns -expr with permuted indices. @@ -2927,16 +2959,15 @@ j = self.args[1] if expr.has(i) and expr.has(j): tmp = Dummy() - expr = expr.subs(i,tmp) - expr = expr.subs(j,i) - expr = expr.subs(tmp,j) + expr = expr.subs(i, tmp) + expr = expr.subs(j, i) + expr = expr.subs(tmp, j) return S.NegativeOne*expr else: return expr def _latex(self, printer): - return "P(%s%s)"%self.args - + return "P(%s%s)" % self.args def simplify_index_permutations(expr, permutation_operators): @@ -2981,19 +3012,18 @@ result.append(arg) else: if arg.args: - result.extend(_get_indices(arg,ind)) + result.extend(_get_indices(arg, ind)) return result - def _choose_one_to_keep(a,b,ind): + def _choose_one_to_keep(a, b, ind): # we keep the one where indices in ind are in order ind[0] < ind[1] - if _get_indices(a,ind) < _get_indices(b,ind): + if _get_indices(a, ind) < _get_indices(b, ind): return a else: return b - expr = expr.expand() - if isinstance(expr,Add): + if isinstance(expr, Add): terms = set(expr.args) for P in permutation_operators: diff -Nru python3-sympy-0.7.2/sympy/physics/sho.py python3-sympy-0.7.3/sympy/physics/sho.py --- python3-sympy-0.7.2/sympy/physics/sho.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/physics/sho.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,6 +1,7 @@ from sympy.core import S, pi, Rational from sympy.functions import assoc_laguerre, sqrt, exp, factorial, factorial2 + def R_nl(n, l, nu, r): """ Returns the radial wavefunction R_{nl} for a 3d isotropic harmonic @@ -35,7 +36,7 @@ >>> R_nl(0, 0, nu, r) 2*2**(3/4)*sqrt(nu**(3/2))*exp(-nu*r**2)/pi**(1/4) >>> R_nl(0, l, 1, r) - r**l*sqrt(2**(l + 3/2)*2**(l + 2)/(2*l + 1)!!)*exp(-r**2)/pi**(1/4) + r**l*sqrt(2**(l + 3/2)*2**(l + 2)/factorial2(2*l + 1))*exp(-r**2)/pi**(1/4) The normalization of the radial wavefunction is: @@ -53,10 +54,11 @@ # formula uses n >= 1 (instead of nodal n >= 0) n = n + 1 C = sqrt( - ((2*nu)**(l + Rational(3, 2))*2**(n+l+1)*factorial(n-1))/ + ((2*nu)**(l + Rational(3, 2))*2**(n + l + 1)*factorial(n - 1))/ (sqrt(pi)*(factorial2(2*n + 2*l - 1))) - ) - return C*r**(l)*exp(-nu*r**2)*assoc_laguerre(n-1, l + S(1)/2, 2*nu*r**2) + ) + return C*r**(l)*exp(-nu*r**2)*assoc_laguerre(n - 1, l + S(1)/2, 2*nu*r**2) + def E_nl(n, l, hw): """ diff -Nru python3-sympy-0.7.2/sympy/physics/tests/test_clebsch_gordan.py python3-sympy-0.7.3/sympy/physics/tests/test_clebsch_gordan.py --- python3-sympy-0.7.2/sympy/physics/tests/test_clebsch_gordan.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/physics/tests/test_clebsch_gordan.py 2013-07-13 17:53:32.000000000 +0000 @@ -5,10 +5,12 @@ # Todo: more tests should be added from: # http://en.wikipedia.org/wiki/Table_of_Clebsch-Gordan_coefficients + def test_clebsch_gordan_docs(): - assert clebsch_gordan(S(3)/2,S(1)/2,2, S(3)/2,S(1)/2,2) == 1 - assert clebsch_gordan(S(3)/2,S(1)/2,1, S(3)/2,-S(1)/2,1) == sqrt(3)/2 - assert clebsch_gordan(S(3)/2,S(1)/2,1, -S(1)/2,S(1)/2,0) == -sqrt(2)/2 + assert clebsch_gordan(S(3)/2, S(1)/2, 2, S(3)/2, S(1)/2, 2) == 1 + assert clebsch_gordan(S(3)/2, S(1)/2, 1, S(3)/2, -S(1)/2, 1) == sqrt(3)/2 + assert clebsch_gordan(S(3)/2, S(1)/2, 1, -S(1)/2, S(1)/2, 0) == -sqrt(2)/2 + def test_clebsch_gordan1(): j_1 = S(1)/2 @@ -59,6 +61,7 @@ m_2 = S(1)/2 assert clebsch_gordan(j_1, j_2, j, m_1, m_2, m) == -sqrt(2)/2 + def test_clebsch_gordan2(): j_1 = S(1) j_2 = S(1)/2 @@ -100,16 +103,20 @@ m_2 = S(1)/2 assert clebsch_gordan(j_1, j_2, j, m_1, m_2, m) == sqrt(2)/sqrt(3) + def test_wigner(): def tn(a, b): return abs((a - b).n(64) < S('1e-64')) - assert tn(wigner_9j(1,1,1, 1,1,1, 1,1,0 ,prec=64), S(1)/18) - assert wigner_9j(3,3,2, 3,3,2, 3,3,2) == 3221*sqrt(70)/(246960*sqrt(105)) - 365/(3528*sqrt(70)*sqrt(105)) - assert wigner_6j(5,5,5,5,5,5) == Rational(1,52) - assert tn(wigner_6j(8,8,8,8,8,8, prec=64), -S(12219)/965770) + assert tn(wigner_9j(1, 1, 1, 1, 1, 1, 1, 1, 0, prec=64), S(1)/18) + assert wigner_9j(3, 3, 2, 3, 3, 2, 3, 3, 2) == 3221*sqrt( + 70)/(246960*sqrt(105)) - 365/(3528*sqrt(70)*sqrt(105)) + assert wigner_6j(5, 5, 5, 5, 5, 5) == Rational(1, 52) + assert tn(wigner_6j(8, 8, 8, 8, 8, 8, prec=64), -S(12219)/965770) + def test_gaunt(): def tn(a, b): return abs((a - b).n(64) < S('1e-64')) - assert gaunt(1,0,1,1,0,-1) == -1/(2*sqrt(pi)) - assert tn(gaunt(10,10,12,9,3,-12, prec=64), (-S(98)/62031) * sqrt(6279)/sqrt(pi)) + assert gaunt(1, 0, 1, 1, 0, -1) == -1/(2*sqrt(pi)) + assert tn(gaunt( + 10, 10, 12, 9, 3, -12, prec=64), (-S(98)/62031) * sqrt(6279)/sqrt(pi)) diff -Nru python3-sympy-0.7.2/sympy/physics/tests/test_gaussopt.py python3-sympy-0.7.3/sympy/physics/tests/test_gaussopt.py --- python3-sympy-0.7.2/sympy/physics/tests/test_gaussopt.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/physics/tests/test_gaussopt.py 2013-07-13 17:53:32.000000000 +0000 @@ -3,16 +3,18 @@ from sympy.physics.gaussopt import (BeamParameter, CurvedMirror, CurvedRefraction, FlatMirror, FlatRefraction, FreeSpace, GeometricRay, RayTransferMatrix, ThinLens, conjugate_gauss_beams, - gaussian_conj , geometric_conj_ab, geometric_conj_af, geometric_conj_bf, + gaussian_conj, geometric_conj_ab, geometric_conj_af, geometric_conj_bf, rayleigh2waist, waist2rayleigh) + def streq(a, b): return str(a) == str(b) + def test_gauss_opt(): - mat = RayTransferMatrix(1,2,3,4) - assert mat == Matrix([[1, 2],[3, 4]]) - assert mat == RayTransferMatrix( Matrix([[1,2],[3,4]]) ) + mat = RayTransferMatrix(1, 2, 3, 4) + assert mat == Matrix([[1, 2], [3, 4]]) + assert mat == RayTransferMatrix( Matrix([[1, 2], [3, 4]]) ) assert [mat.A, mat.B, mat.C, mat.D] == [1, 2, 3, 4] d, f, h, n1, n2, R = symbols('d f h n1 n2 R') @@ -20,25 +22,27 @@ assert lens == Matrix([[ 1, 0], [-1/f, 1]]) assert lens.C == -1/f assert FreeSpace(d) == Matrix([[ 1, d], [0, 1]]) - assert FlatRefraction(n1, n2) == Matrix([[1, 0], [0, n1/n2]]) - assert CurvedRefraction(R, n1, n2) == Matrix([[1, 0], [(n1 - n2)/(R*n2), n1/n2]]) + assert FlatRefraction(n1, n2) == Matrix([[1, 0], [0, n1/n2]]) + assert CurvedRefraction( + R, n1, n2) == Matrix([[1, 0], [(n1 - n2)/(R*n2), n1/n2]]) assert FlatMirror() == Matrix([[1, 0], [0, 1]]) assert CurvedMirror(R) == Matrix([[ 1, 0], [-2/R, 1]]) assert ThinLens(f) == Matrix([[ 1, 0], [-1/f, 1]]) mul = CurvedMirror(R)*FreeSpace(d) mul_mat = Matrix([[ 1, 0], [-2/R, 1]])*Matrix([[ 1, d], [0, 1]]) - assert mul.A == mul_mat[0,0] - assert mul.B == mul_mat[0,1] - assert mul.C == mul_mat[1,0] - assert mul.D == mul_mat[1,1] + assert mul.A == mul_mat[0, 0] + assert mul.B == mul_mat[0, 1] + assert mul.C == mul_mat[1, 0] + assert mul.D == mul_mat[1, 1] angle = symbols('angle') - assert GeometricRay(h,angle) == Matrix([[ h], [angle]]) - assert FreeSpace(d)*GeometricRay(h,angle) == Matrix([[angle*d + h], [angle]]) - assert GeometricRay( Matrix( ((h,),(angle,)) ) ) == Matrix([[h], [angle]]) - assert (FreeSpace(d)*GeometricRay(h,angle)).height == angle*d + h - assert (FreeSpace(d)*GeometricRay(h,angle)).angle == angle + assert GeometricRay(h, angle) == Matrix([[ h], [angle]]) + assert FreeSpace( + d)*GeometricRay(h, angle) == Matrix([[angle*d + h], [angle]]) + assert GeometricRay( Matrix( ((h,), (angle,)) ) ) == Matrix([[h], [angle]]) + assert (FreeSpace(d)*GeometricRay(h, angle)).height == angle*d + h + assert (FreeSpace(d)*GeometricRay(h, angle)).angle == angle p = BeamParameter(530e-9, 1, w=1e-3) assert streq(p.q, 1 + 1.88679245283019*I*pi) @@ -63,13 +67,18 @@ assert geometric_conj_ab(a, oo) == a s_in, z_r_in, f = symbols('s_in z_r_in f') - assert gaussian_conj(s_in, z_r_in, f)[0] == 1/(-1/(s_in + z_r_in**2/(-f + s_in)) + 1/f) - assert gaussian_conj(s_in, z_r_in, f)[1] == z_r_in/(1 - s_in**2/f**2 + z_r_in**2/f**2) - assert gaussian_conj(s_in, z_r_in, f)[2] == 1/sqrt(1 - s_in**2/f**2 + z_r_in**2/f**2) + assert gaussian_conj( + s_in, z_r_in, f)[0] == 1/(-1/(s_in + z_r_in**2/(-f + s_in)) + 1/f) + assert gaussian_conj( + s_in, z_r_in, f)[1] == z_r_in/(1 - s_in**2/f**2 + z_r_in**2/f**2) + assert gaussian_conj( + s_in, z_r_in, f)[2] == 1/sqrt(1 - s_in**2/f**2 + z_r_in**2/f**2) l, w_i, w_o, f = symbols('l w_i w_o f') - assert conjugate_gauss_beams(l, w_i, w_o, f=f)[0] == f*(-sqrt(w_i**2/w_o**2 - pi**2*w_i**4/(f**2*l**2)) + 1) - assert factor(conjugate_gauss_beams(l, w_i, w_o, f=f)[1]) == f*w_o**2*(w_i**2/w_o**2 - sqrt(w_i**2/w_o**2 - pi**2*w_i**4/(f**2*l**2)))/w_i**2 + assert conjugate_gauss_beams(l, w_i, w_o, f=f)[0] == f*( + -sqrt(w_i**2/w_o**2 - pi**2*w_i**4/(f**2*l**2)) + 1) + assert factor(conjugate_gauss_beams(l, w_i, w_o, f=f)[1]) == f*w_o**2*( + w_i**2/w_o**2 - sqrt(w_i**2/w_o**2 - pi**2*w_i**4/(f**2*l**2)))/w_i**2 assert conjugate_gauss_beams(l, w_i, w_o, f=f)[2] == f z, l, w = symbols('z l r', positive=True) diff -Nru python3-sympy-0.7.2/sympy/physics/tests/test_hydrogen.py python3-sympy-0.7.3/sympy/physics/tests/test_hydrogen.py --- python3-sympy-0.7.2/sympy/physics/tests/test_hydrogen.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/physics/tests/test_hydrogen.py 2013-07-13 17:53:32.000000000 +0000 @@ -4,50 +4,54 @@ n, r, Z = symbols('n r Z') + def feq(a, b, max_relative_error=1e-12, max_absolute_error=1e-12): a = float(a) b = float(b) # if the numbers are close enough (absolutely), then they are equal - if abs(a-b) < max_absolute_error: + if abs(a - b) < max_absolute_error: return True # if not, they can still be equal if their relative error is small if abs(b) > abs(a): - relative_error = abs((a-b)/b) + relative_error = abs((a - b)/b) else: - relative_error = abs((a-b)/a) + relative_error = abs((a - b)/a) return relative_error <= max_relative_error + def test_wavefunction(): a = 1/Z R = { - (1, 0): 2*sqrt(1/a**3) * exp(-r/a), - (2, 0): sqrt(1/(2*a**3)) * exp(-r/(2*a)) * (1-r/(2*a)), - (2, 1): S(1)/2 * sqrt(1/(6*a**3)) * exp(-r/(2*a)) * r/a, - (3, 0): S(2)/3 * sqrt(1/(3*a**3)) * exp(-r/(3*a)) * \ - (1-2*r/(3*a) + S(2)/27 * (r/a)**2), - (3, 1): S(4)/27 * sqrt(2/(3*a**3)) * exp(-r/(3*a)) * \ - (1-r/(6*a)) * r/a, - (3, 2): S(2)/81 * sqrt(2/(15*a**3)) * exp(-r/(3*a)) * (r/a)**2, - (4, 0): S(1)/4 * sqrt(1/a**3) * exp(-r/(4*a)) * \ - (1-3*r/(4*a)+S(1)/8 * (r/a)**2-S(1)/192 * (r/a)**3), - (4, 1): S(1)/16 * sqrt(5/(3*a**3)) * exp(-r/(4*a)) * \ - (1-r/(4*a)+S(1)/80 * (r/a)**2) * (r/a), - (4, 2): S(1)/64 * sqrt(1/(5*a**3)) * exp(-r/(4*a)) * \ - (1-r/(12*a)) * (r/a)**2, - (4, 3): S(1)/768 * sqrt(1/(35*a**3)) * exp(-r/(4*a)) * (r/a)**3, - } + (1, 0): 2*sqrt(1/a**3) * exp(-r/a), + (2, 0): sqrt(1/(2*a**3)) * exp(-r/(2*a)) * (1 - r/(2*a)), + (2, 1): S(1)/2 * sqrt(1/(6*a**3)) * exp(-r/(2*a)) * r/a, + (3, 0): S(2)/3 * sqrt(1/(3*a**3)) * exp(-r/(3*a)) * + (1 - 2*r/(3*a) + S(2)/27 * (r/a)**2), + (3, 1): S(4)/27 * sqrt(2/(3*a**3)) * exp(-r/(3*a)) * + (1 - r/(6*a)) * r/a, + (3, 2): S(2)/81 * sqrt(2/(15*a**3)) * exp(-r/(3*a)) * (r/a)**2, + (4, 0): S(1)/4 * sqrt(1/a**3) * exp(-r/(4*a)) * + (1 - 3*r/(4*a) + S(1)/8 * (r/a)**2 - S(1)/192 * (r/a)**3), + (4, 1): S(1)/16 * sqrt(5/(3*a**3)) * exp(-r/(4*a)) * + (1 - r/(4*a) + S(1)/80 * (r/a)**2) * (r/a), + (4, 2): S(1)/64 * sqrt(1/(5*a**3)) * exp(-r/(4*a)) * + (1 - r/(12*a)) * (r/a)**2, + (4, 3): S(1)/768 * sqrt(1/(35*a**3)) * exp(-r/(4*a)) * (r/a)**3, + } for n, l in R: assert simplify(R_nl(n, l, r, Z) - R[(n, l)]) == 0 + def test_norm(): # Maximum "n" which is tested: n_max = 2 # you can test any n and it works, but it's slow, so it's commented out: #n_max = 4 - for n in range(n_max+1): + for n in range(n_max + 1): for l in range(n): assert integrate(R_nl(n, l, r)**2 * r**2, (r, 0, oo)) == 1 + def test_hydrogen_energies(): assert E_nl(n, Z) == -Z**2/(2*n**2) assert E_nl(n) == -1/(2*n**2) @@ -63,22 +67,21 @@ raises(ValueError, lambda: E_nl(0)) + def test_hydrogen_energies_relat(): # First test exact formulas for small "c" so that we get nice expressions: assert E_nl_dirac(2, 0, Z=1, c=1) == 1/sqrt(2) - 1 - assert simplify(E_nl_dirac(2, 0, Z=1, c=2) - ( (8*sqrt(3) + 16) \ + assert simplify(E_nl_dirac(2, 0, Z=1, c=2) - ( (8*sqrt(3) + 16) / sqrt(16*sqrt(3) + 32) - 4)) == 0 - assert simplify(E_nl_dirac(2, 0, Z=1, c=3) - ( (54*sqrt(2) + 81) \ + assert simplify(E_nl_dirac(2, 0, Z=1, c=3) - ( (54*sqrt(2) + 81) / sqrt(108*sqrt(2) + 162) - 9)) == 0 # Now test for almost the correct speed of light, without floating point # numbers: - assert simplify(E_nl_dirac(2, 0, Z=1, c=137) - ( (352275361 + 10285412 * \ - sqrt(1173)) / sqrt(704550722 + 20570824 * sqrt(1173)) - \ - 18769)) == 0 - assert simplify(E_nl_dirac(2, 0, Z=82, c=137) - ( (352275361 + \ - 2571353*sqrt(12045)) / sqrt(704550722 + 5142706*sqrt(12045)) \ - - 18769)) == 0 + assert simplify(E_nl_dirac(2, 0, Z=1, c=137) - ( (352275361 + 10285412 * + sqrt(1173)) / sqrt(704550722 + 20570824 * sqrt(1173)) - 18769)) == 0 + assert simplify(E_nl_dirac(2, 0, Z=82, c=137) - ( (352275361 + 2571353 * + sqrt(12045)) / sqrt(704550722 + 5142706*sqrt(12045)) - 18769)) == 0 # Test using exact speed of light, and compare against the nonrelativistic # energies: @@ -102,7 +105,6 @@ if l > 0: assert feq(E_nl_dirac(n, l, False, Z), E_nl(n, Z), 1e-3, 1e-3) - # Test the exceptions: raises(ValueError, lambda: E_nl_dirac(0, 0)) raises(ValueError, lambda: E_nl_dirac(1, -1)) diff -Nru python3-sympy-0.7.2/sympy/physics/tests/test_paulialgebra.py python3-sympy-0.7.3/sympy/physics/tests/test_paulialgebra.py --- python3-sympy-0.7.2/sympy/physics/tests/test_paulialgebra.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/physics/tests/test_paulialgebra.py 2013-07-13 17:53:32.000000000 +0000 @@ -6,6 +6,7 @@ sigma2 = Pauli(2) sigma3 = Pauli(3) + def test_Pauli(): from sympy.physics.paulialgebra import evaluate_pauli_product @@ -32,6 +33,10 @@ assert sigma1*2*sigma1 == 2 + # Check bug 3372 + assert evaluate_pauli_product(-I*4*sigma1*sigma2) == 4*sigma3 + + @XFAIL def test_Pauli_should_work(): assert sigma1*sigma3*sigma1 == -sigma3 diff -Nru python3-sympy-0.7.2/sympy/physics/tests/test_physics_matrices.py python3-sympy-0.7.3/sympy/physics/tests/test_physics_matrices.py --- python3-sympy-0.7.2/sympy/physics/tests/test_physics_matrices.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/physics/tests/test_physics_matrices.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,37 +1,39 @@ from sympy.physics.matrices import msigma, mgamma, minkowski_tensor, pat_matrix from sympy import zeros, eye, I, Matrix + def test_parallel_axis_theorem(): # This tests the parallel axis theorem matrix by comparing to test # matrices. # First case, 1 in all directions. - mat1 = Matrix(((2,-1,-1),(-1,2,-1),(-1,-1,2))) - assert pat_matrix(1,1,1,1) == mat1 - assert pat_matrix(2,1,1,1) == 2*mat1 + mat1 = Matrix(((2, -1, -1), (-1, 2, -1), (-1, -1, 2))) + assert pat_matrix(1, 1, 1, 1) == mat1 + assert pat_matrix(2, 1, 1, 1) == 2*mat1 # Second case, 1 in x, 0 in all others - mat2 = Matrix(((0,0,0),(0,1,0),(0,0,1))) - assert pat_matrix(1,1,0,0) == mat2 - assert pat_matrix(2,1,0,0) == 2*mat2 + mat2 = Matrix(((0, 0, 0), (0, 1, 0), (0, 0, 1))) + assert pat_matrix(1, 1, 0, 0) == mat2 + assert pat_matrix(2, 1, 0, 0) == 2*mat2 # Third case, 1 in y, 0 in all others - mat3 = Matrix(((1,0,0),(0,0,0),(0,0,1))) - assert pat_matrix(1,0,1,0) == mat3 - assert pat_matrix(2,0,1,0) == 2*mat3 + mat3 = Matrix(((1, 0, 0), (0, 0, 0), (0, 0, 1))) + assert pat_matrix(1, 0, 1, 0) == mat3 + assert pat_matrix(2, 0, 1, 0) == 2*mat3 # Fourth case, 1 in z, 0 in all others - mat4 = Matrix(((1,0,0),(0,1,0),(0,0,0))) - assert pat_matrix(1,0,0,1) == mat4 - assert pat_matrix(2,0,0,1) == 2*mat4 + mat4 = Matrix(((1, 0, 0), (0, 1, 0), (0, 0, 0))) + assert pat_matrix(1, 0, 0, 1) == mat4 + assert pat_matrix(2, 0, 0, 1) == 2*mat4 + def test_Pauli(): #this and the following test are testing both Pauli and Dirac matrices #and also that the general Matrix class works correctly in a real world #situation - sigma1=msigma(1) - sigma2=msigma(2) - sigma3=msigma(3) + sigma1 = msigma(1) + sigma2 = msigma(2) + sigma3 = msigma(3) assert sigma1 == sigma1 assert sigma1 != sigma2 @@ -48,19 +50,20 @@ assert sigma1*2*sigma1 == 2*eye(2) assert sigma1*sigma3*sigma1 == -sigma3 + def test_Dirac(): - gamma0=mgamma(0) - gamma1=mgamma(1) - gamma2=mgamma(2) - gamma3=mgamma(3) - gamma5=mgamma(5) + gamma0 = mgamma(0) + gamma1 = mgamma(1) + gamma2 = mgamma(2) + gamma3 = mgamma(3) + gamma5 = mgamma(5) # gamma*I -> I*gamma (see #354) assert gamma5 == gamma0 * gamma1 * gamma2 * gamma3 * I assert gamma1 * gamma2 + gamma2 * gamma1 == zeros(4) - assert gamma0 * gamma0 == eye(4) * minkowski_tensor[0,0] - assert gamma2 * gamma2 != eye(4) * minkowski_tensor[0,0] - assert gamma2 * gamma2 == eye(4) * minkowski_tensor[2,2] + assert gamma0 * gamma0 == eye(4) * minkowski_tensor[0, 0] + assert gamma2 * gamma2 != eye(4) * minkowski_tensor[0, 0] + assert gamma2 * gamma2 == eye(4) * minkowski_tensor[2, 2] - assert mgamma(5,True) == \ - mgamma(0,True)*mgamma(1,True)*mgamma(2,True)*mgamma(3,True)*I + assert mgamma(5, True) == \ + mgamma(0, True)*mgamma(1, True)*mgamma(2, True)*mgamma(3, True)*I diff -Nru python3-sympy-0.7.2/sympy/physics/tests/test_qho_1d.py python3-sympy-0.7.3/sympy/physics/tests/test_qho_1d.py --- python3-sympy-0.7.2/sympy/physics/tests/test_qho_1d.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/physics/tests/test_qho_1d.py 2013-07-13 17:53:32.000000000 +0000 @@ -5,28 +5,33 @@ nu = m * omega / hbar + def test_wavefunction(): Psi = { - 0: (nu/pi)**(S(1)/4) * exp(-nu * x**2 /2), - 1: (nu/pi)**(S(1)/4) * sqrt(2*nu) * x * exp(-nu * x**2 /2), - 2: (nu/pi)**(S(1)/4) * (2 * nu * x**2 - 1)/sqrt(2) * exp(-nu * x**2 /2), - 3: (nu/pi)**(S(1)/4) * sqrt(nu/3) * (2 * nu * x**3 - 3 * x) * exp(-nu * x**2 /2) + 0: (nu/pi)**(S(1)/4) * exp(-nu * x**2 /2), + 1: (nu/pi)**(S(1)/4) * sqrt(2*nu) * x * exp(-nu * x**2 /2), + 2: (nu/pi)**(S(1)/4) * (2 * nu * x**2 - 1)/sqrt(2) * exp(-nu * x**2 /2), + 3: (nu/pi)**(S(1)/4) * sqrt(nu/3) * (2 * nu * x**3 - 3 * x) * exp(-nu * x**2 /2) } for n in Psi: assert simplify(psi_n(n, x, m, omega) - Psi[n]) == 0 + def test_norm(n=1): # Maximum "n" which is tested: - for i in range(n+1): - assert integrate(psi_n(i, x, 1, 1)**2, (x,-oo,oo)) == 1 + for i in range(n + 1): + assert integrate(psi_n(i, x, 1, 1)**2, (x, -oo, oo)) == 1 + def test_orthogonality(n=1): # Maximum "n" which is tested: - for i in range(n+1): - for j in range(i+1,n+1): - assert integrate(psi_n(i, x, 1, 1)*psi_n(j, x, 1, 1), (x,-oo,oo)) == 0 + for i in range(n + 1): + for j in range(i + 1, n + 1): + assert integrate( + psi_n(i, x, 1, 1)*psi_n(j, x, 1, 1), (x, -oo, oo)) == 0 + def test_energies(n=1): # Maximum "n" which is tested: - for i in range(n+1): - assert E_n(i,omega) == hbar * omega * (i + Rational(1,2)) + for i in range(n + 1): + assert E_n(i, omega) == hbar * omega * (i + Rational(1, 2)) diff -Nru python3-sympy-0.7.2/sympy/physics/tests/test_secondquant.py python3-sympy-0.7.3/sympy/physics/tests/test_secondquant.py --- python3-sympy-0.7.2/sympy/physics/tests/test_secondquant.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/physics/tests/test_secondquant.py 2013-07-13 17:53:32.000000000 +0000 @@ -7,38 +7,40 @@ PermutationOperator, simplify_index_permutations, _sort_anticommuting_fermions, _get_ordered_dummies, substitute_dummies - ) +) from sympy import (Dummy, expand, Function, I, Rational, simplify, sqrt, Sum, Symbol, symbols) from sympy.utilities.pytest import XFAIL + def test_PermutationOperator(): - p,q,r,s = symbols('p,q,r,s') - f,g,h,i = list(map(Function, 'fghi')) + p, q, r, s = symbols('p,q,r,s') + f, g, h, i = list(map(Function, 'fghi')) P = PermutationOperator - assert P(p,q).get_permuted(f(p)*g(q)) == -f(q)*g(p) - assert P(p,q).get_permuted(f(p, q)) == -f(q, p) - assert P(p,q).get_permuted(f(p)) == f(p) + assert P(p, q).get_permuted(f(p)*g(q)) == -f(q)*g(p) + assert P(p, q).get_permuted(f(p, q)) == -f(q, p) + assert P(p, q).get_permuted(f(p)) == f(p) expr = (f(p)*g(q)*h(r)*i(s) - f(q)*g(p)*h(r)*i(s) - f(p)*g(q)*h(s)*i(r) + f(q)*g(p)*h(s)*i(r)) - perms = [P(p,q),P(r,s)] - assert (simplify_index_permutations(expr,perms) == - P(p,q)*P(r,s)*f(p)*g(q)*h(r)*i(s)) + perms = [P(p, q), P(r, s)] + assert (simplify_index_permutations(expr, perms) == + P(p, q)*P(r, s)*f(p)*g(q)*h(r)*i(s)) + def test_index_permutations_with_dummies(): - a,b,c,d = symbols('a b c d') - p,q,r,s = symbols('p q r s', cls=Dummy) - f,g = list(map(Function, 'fg')) + a, b, c, d = symbols('a b c d') + p, q, r, s = symbols('p q r s', cls=Dummy) + f, g = list(map(Function, 'fg')) P = PermutationOperator # No dummy substitution necessary expr = f(a, b, p, q) - f(b, a, p, q) assert simplify_index_permutations( - expr, [P(a, b)]) == P(a, b)*f(a, b, p, q) + expr, [P(a, b)]) == P(a, b)*f(a, b, p, q) # Cases where dummy substitution is needed expected = P(a, b)*substitute_dummies(f(a, b, p, q)) @@ -56,22 +58,24 @@ result = simplify_index_permutations(expr, [P(a, b)]) assert expr == result + def test_dagger(): i, j, n, m = symbols('i,j,n,m') assert Dagger(1) == 1 assert Dagger(1.0) == 1.0 assert Dagger(2*I) == -2*I - assert Dagger(Rational(1,2)*I/3.0) == -Rational(1,2)*I/3.0 + assert Dagger(Rational(1, 2)*I/3.0) == -Rational(1, 2)*I/3.0 assert Dagger(BKet([n])) == BBra([n]) assert Dagger(B(0)) == Bd(0) assert Dagger(Bd(0)) == B(0) assert Dagger(B(n)) == Bd(n) assert Dagger(Bd(n)) == B(n) - assert Dagger(B(0)+B(1)) == Bd(0) + Bd(1) - assert Dagger(n*m) == Dagger(n)*Dagger(m) # n, m commute + assert Dagger(B(0) + B(1)) == Bd(0) + Bd(1) + assert Dagger(n*m) == Dagger(n)*Dagger(m) # n, m commute assert Dagger(B(n)*B(m)) == Bd(m)*Bd(n) assert Dagger(B(n)**10) == Dagger(B(n))**10 + def test_operator(): i, j = symbols('i,j') o = BosonicOperator(i) @@ -81,6 +85,7 @@ assert o.state == 1 assert not o.is_symbolic + def test_create(): i, j, n, m = symbols('i,j,n,m') o = Bd(i) @@ -88,10 +93,11 @@ o = o.subs(i, j) assert o.atoms(Symbol) == set([j]) o = Bd(0) - assert o.apply_operator(BKet([n])) == sqrt(n+1)*BKet([n+1]) + assert o.apply_operator(BKet([n])) == sqrt(n + 1)*BKet([n + 1]) o = Bd(n) assert o.apply_operator(BKet([n])) == o*BKet([n]) + def test_annihilate(): i, j, n, m = symbols('i,j,n,m') o = B(i) @@ -99,63 +105,69 @@ o = o.subs(i, j) assert o.atoms(Symbol) == set([j]) o = B(0) - assert o.apply_operator(BKet([n])) == sqrt(n)*BKet([n-1]) + assert o.apply_operator(BKet([n])) == sqrt(n)*BKet([n - 1]) o = B(n) assert o.apply_operator(BKet([n])) == o*BKet([n]) + def test_basic_state(): i, j, n, m = symbols('i,j,n,m') - s = BosonState([0,1,2,3,4]) + s = BosonState([0, 1, 2, 3, 4]) assert len(s) == 5 assert s.args[0] == tuple(range(5)) - assert s.up(0) == BosonState([1,1,2,3,4]) - assert s.down(4) == BosonState([0,1,2,3,3]) + assert s.up(0) == BosonState([1, 1, 2, 3, 4]) + assert s.down(4) == BosonState([0, 1, 2, 3, 3]) for i in range(5): assert s.up(i).down(i) == s assert s.down(0) == 0 for i in range(5): assert s[i] == i - s = BosonState([n,m]) - assert s.down(0) == BosonState([n-1,m]) - assert s.up(0) == BosonState([n+1,m]) + s = BosonState([n, m]) + assert s.down(0) == BosonState([n - 1, m]) + assert s.up(0) == BosonState([n + 1, m]) + @XFAIL -def Xtest_move1(): +def test_move1(): i, j = symbols('i,j') A, C = symbols('A,C', cls=Function) o = A(i)*C(j) # This almost works, but has a minus sign wrong assert move(o, 0, 1) == KroneckerDelta(i, j) + C(j)*A(i) + @XFAIL -def Xtest_move2(): +def test_move2(): i, j = symbols('i,j') A, C = symbols('A,C', cls=Function) o = C(j)*A(i) # This almost works, but has a minus sign wrong assert move(o, 0, 1) == -KroneckerDelta(i, j) + A(i)*C(j) + def test_basic_apply(): n = symbols("n") e = B(0)*BKet([n]) - assert apply_operators(e) == sqrt(n)*BKet([n-1]) + assert apply_operators(e) == sqrt(n)*BKet([n - 1]) e = Bd(0)*BKet([n]) - assert apply_operators(e) == sqrt(n+1)*BKet([n+1]) + assert apply_operators(e) == sqrt(n + 1)*BKet([n + 1]) def test_complex_apply(): n, m = symbols("n,m") o = Bd(0)*B(0)*Bd(1)*B(0) - e = apply_operators(o*BKet([n,m])) - answer = sqrt(n)*sqrt(m+1)*(-1+n)*BKet([-1+n,1+m]) + e = apply_operators(o*BKet([n, m])) + answer = sqrt(n)*sqrt(m + 1)*(-1 + n)*BKet([-1 + n, 1 + m]) assert expand(e) == expand(answer) + def test_number_operator(): n = symbols("n") o = Bd(0)*B(0) e = apply_operators(o*BKet([n])) assert e == n*BKet([n]) + def test_inner_product(): i, j, k, l = symbols('i,j,k,l') s1 = BBra([0]) @@ -167,30 +179,33 @@ r = InnerProduct(s1, s2) assert r == KroneckerDelta(i, k)*KroneckerDelta(j, l) + def test_symbolic_matrix_elements(): n, m = symbols('n,m') s1 = BBra([n]) s2 = BKet([m]) o = B(0) e = apply_operators(s1*o*s2) - assert e == sqrt(m)*KroneckerDelta(n, m-1) + assert e == sqrt(m)*KroneckerDelta(n, m - 1) + def test_matrix_elements(): b = VarBosonicBasis(5) o = B(0) m = matrix_rep(o, b) for i in range(4): - assert m[i, i+1] == sqrt(i+1) + assert m[i, i + 1] == sqrt(i + 1) o = Bd(0) m = matrix_rep(o, b) for i in range(4): - assert m[i+1, i] == sqrt(i+1) + assert m[i + 1, i] == sqrt(i + 1) + def test_sho(): n, m = symbols('n,m') h_n = Bd(n)*B(n)*(n + Rational(1, 2)) H = Sum(h_n, (n, 0, 5)) - o = H.doit(deep = False) + o = H.doit(deep=False) b = FixedBosonicBasis(2, 6) m = matrix_rep(o, b) # We need to double check these energy values to make sure that they @@ -199,6 +214,7 @@ for i in range(len(diag)): assert diag[i] == m[i, i] + def test_commutation(): n, m = symbols("n,m", above_fermi=True) c = Commutator(B(0), Bd(0)) @@ -206,34 +222,34 @@ c = Commutator(Bd(0), B(0)) assert c == -1 c = Commutator(B(n), Bd(0)) - assert c == KroneckerDelta(n,0) + assert c == KroneckerDelta(n, 0) c = Commutator(B(0), Bd(0)) e = simplify(apply_operators(c*BKet([n]))) assert e == BKet([n]) c = Commutator(B(0), B(1)) - e = simplify(apply_operators(c*BKet([n,m]))) + e = simplify(apply_operators(c*BKet([n, m]))) assert e == 0 - c = Commutator(F(m), Fd(m)) assert c == +1 - 2*NO(Fd(m)*F(m)) c = Commutator(Fd(m), F(m)) assert c == -1 + 2*NO(Fd(m)*F(m)) C = Commutator - X,Y,Z = symbols('X,Y,Z',commutative=False) - assert C(C(X,Y),Z) != 0 - assert C(C(X,Z),Y) != 0 - assert C(Y,C(X,Z)) != 0 - - i,j,k,l = symbols('i,j,k,l',below_fermi=True) - a,b,c,d = symbols('a,b,c,d',above_fermi=True) - p,q,r,s = symbols('p,q,r,s') - D=KroneckerDelta - - assert C(Fd(a),F(i)) == -2*NO(F(i)*Fd(a)) - assert C(Fd(j),NO(Fd(a)*F(i))).doit(wicks=True) == -D(j,i)*Fd(a) - assert C(Fd(a)*F(i),Fd(b)*F(j)).doit(wicks=True) == 0 + X, Y, Z = symbols('X,Y,Z', commutative=False) + assert C(C(X, Y), Z) != 0 + assert C(C(X, Z), Y) != 0 + assert C(Y, C(X, Z)) != 0 + + i, j, k, l = symbols('i,j,k,l', below_fermi=True) + a, b, c, d = symbols('a,b,c,d', above_fermi=True) + p, q, r, s = symbols('p,q,r,s') + D = KroneckerDelta + + assert C(Fd(a), F(i)) == -2*NO(F(i)*Fd(a)) + assert C(Fd(j), NO(Fd(a)*F(i))).doit(wicks=True) == -D(j, i)*Fd(a) + assert C(Fd(a)*F(i), Fd(b)*F(j)).doit(wicks=True) == 0 + def test_create_f(): i, j, n, m = symbols('i,j,n,m') @@ -242,21 +258,20 @@ o = o.subs(i, j) assert o.atoms(Symbol) == set([j]) o = Fd(1) - assert o.apply_operator(FKet([n])) == FKet([1,n]) - assert o.apply_operator(FKet([n])) ==-FKet([n,1]) + assert o.apply_operator(FKet([n])) == FKet([1, n]) + assert o.apply_operator(FKet([n])) == -FKet([n, 1]) o = Fd(n) assert o.apply_operator(FKet([])) == FKet([n]) - vacuum = FKet([],fermi_level=4) - assert vacuum == FKet([],fermi_level=4) - - i,j,k,l = symbols('i,j,k,l',below_fermi=True) - a,b,c,d = symbols('a,b,c,d',above_fermi=True) - p,q,r,s = symbols('p,q,r,s') + vacuum = FKet([], fermi_level=4) + assert vacuum == FKet([], fermi_level=4) - assert Fd(i).apply_operator(FKet([i,j,k],4)) == FKet([j,k],4) - assert Fd(a).apply_operator(FKet([i,b,k],4)) == FKet([a,i,b,k],4) + i, j, k, l = symbols('i,j,k,l', below_fermi=True) + a, b, c, d = symbols('a,b,c,d', above_fermi=True) + p, q, r, s = symbols('p,q,r,s') + assert Fd(i).apply_operator(FKet([i, j, k], 4)) == FKet([j, k], 4) + assert Fd(a).apply_operator(FKet([i, b, k], 4)) == FKet([a, i, b, k], 4) def test_annihilate_f(): @@ -266,18 +281,19 @@ o = o.subs(i, j) assert o.atoms(Symbol) == set([j]) o = F(1) - assert o.apply_operator(FKet([1,n])) == FKet([n]) - assert o.apply_operator(FKet([n,1])) ==-FKet([n]) + assert o.apply_operator(FKet([1, n])) == FKet([n]) + assert o.apply_operator(FKet([n, 1])) == -FKet([n]) o = F(n) assert o.apply_operator(FKet([n])) == FKet([]) - i,j,k,l = symbols('i,j,k,l',below_fermi=True) - a,b,c,d = symbols('a,b,c,d',above_fermi=True) - p,q,r,s = symbols('p,q,r,s') - assert F(i).apply_operator(FKet([i,j,k],4)) == 0 - assert F(a).apply_operator(FKet([i,b,k],4)) == 0 - assert F(l).apply_operator(FKet([i,j,k],3)) == 0 - assert F(l).apply_operator(FKet([i,j,k],4)) == FKet([l,i,j,k],4) + i, j, k, l = symbols('i,j,k,l', below_fermi=True) + a, b, c, d = symbols('a,b,c,d', above_fermi=True) + p, q, r, s = symbols('p,q,r,s') + assert F(i).apply_operator(FKet([i, j, k], 4)) == 0 + assert F(a).apply_operator(FKet([i, b, k], 4)) == 0 + assert F(l).apply_operator(FKet([i, j, k], 3)) == 0 + assert F(l).apply_operator(FKet([i, j, k], 4)) == FKet([l, i, j, k], 4) + def test_create_b(): i, j, n, m = symbols('i,j,n,m') @@ -286,10 +302,11 @@ o = o.subs(i, j) assert o.atoms(Symbol) == set([j]) o = Bd(0) - assert o.apply_operator(BKet([n])) == sqrt(n+1)*BKet([n+1]) + assert o.apply_operator(BKet([n])) == sqrt(n + 1)*BKet([n + 1]) o = Bd(n) assert o.apply_operator(BKet([n])) == o*BKet([n]) + def test_annihilate_b(): i, j, n, m = symbols('i,j,n,m') o = B(i) @@ -298,99 +315,97 @@ assert o.atoms(Symbol) == set([j]) o = B(0) + def test_wicks(): - p,q,r,s = symbols('p,q,r,s',above_fermi=True) + p, q, r, s = symbols('p,q,r,s', above_fermi=True) # Testing for particles only str = F(p)*Fd(q) - assert wicks(str) == NO(F(p)*Fd(q)) + KroneckerDelta(p,q) + assert wicks(str) == NO(F(p)*Fd(q)) + KroneckerDelta(p, q) str = Fd(p)*F(q) assert wicks(str) == NO(Fd(p)*F(q)) - str = F(p)*Fd(q)*F(r)*Fd(s) - nstr= wicks(str) + nstr = wicks(str) fasit = NO( - KroneckerDelta(p, q)*KroneckerDelta(r, s) - + KroneckerDelta(p, q)*AnnihilateFermion(r)*CreateFermion(s) - + KroneckerDelta(r, s)*AnnihilateFermion(p)*CreateFermion(q) - - KroneckerDelta(p, s)*AnnihilateFermion(r)*CreateFermion(q) - - AnnihilateFermion(p)*AnnihilateFermion(r)*CreateFermion(q)*CreateFermion(s)) + KroneckerDelta(p, q)*KroneckerDelta(r, s) + + KroneckerDelta(p, q)*AnnihilateFermion(r)*CreateFermion(s) + + KroneckerDelta(r, s)*AnnihilateFermion(p)*CreateFermion(q) + - KroneckerDelta(p, s)*AnnihilateFermion(r)*CreateFermion(q) + - AnnihilateFermion(p)*AnnihilateFermion(r)*CreateFermion(q)*CreateFermion(s)) assert nstr == fasit assert (p*q*nstr).expand() == wicks(p*q*str) assert (nstr*p*q*2).expand() == wicks(str*p*q*2) - # Testing CC equations particles and holes - i,j,k,l = symbols('i j k l',below_fermi=True,cls=Dummy) - a,b,c,d = symbols('a b c d',above_fermi=True,cls=Dummy) - p,q,r,s = symbols('p q r s',cls=Dummy) + i, j, k, l = symbols('i j k l', below_fermi=True, cls=Dummy) + a, b, c, d = symbols('a b c d', above_fermi=True, cls=Dummy) + p, q, r, s = symbols('p q r s', cls=Dummy) assert (wicks(F(a)*NO(F(i)*F(j))*Fd(b)) == NO(F(a)*F(i)*F(j)*Fd(b)) + - KroneckerDelta(a,b)*NO(F(i)*F(j))) + KroneckerDelta(a, b)*NO(F(i)*F(j))) assert (wicks(F(a)*NO(F(i)*F(j)*F(k))*Fd(b)) == NO(F(a)*F(i)*F(j)*F(k)*Fd(b)) - - KroneckerDelta(a,b)*NO(F(i)*F(j)*F(k))) - + KroneckerDelta(a, b)*NO(F(i)*F(j)*F(k))) expr = wicks(Fd(i)*NO(Fd(j)*F(k))*F(l)) assert (expr == - -KroneckerDelta(i,k)*NO(Fd(j)*F(l)) - - KroneckerDelta(j,l)*NO(Fd(i)*F(k)) - - KroneckerDelta(i,k)*KroneckerDelta(j,l)+ - KroneckerDelta(i,l)*NO(Fd(j)*F(k)) + + -KroneckerDelta(i, k)*NO(Fd(j)*F(l)) - + KroneckerDelta(j, l)*NO(Fd(i)*F(k)) - + KroneckerDelta(i, k)*KroneckerDelta(j, l) + + KroneckerDelta(i, l)*NO(Fd(j)*F(k)) + NO(Fd(i)*Fd(j)*F(k)*F(l))) expr = wicks(F(a)*NO(F(b)*Fd(c))*Fd(d)) assert (expr == - -KroneckerDelta(a,c)*NO(F(b)*Fd(d)) - - KroneckerDelta(b,d)*NO(F(a)*Fd(c)) - - KroneckerDelta(a,c)*KroneckerDelta(b,d)+ - KroneckerDelta(a,d)*NO(F(b)*Fd(c)) + + -KroneckerDelta(a, c)*NO(F(b)*Fd(d)) - + KroneckerDelta(b, d)*NO(F(a)*Fd(c)) - + KroneckerDelta(a, c)*KroneckerDelta(b, d) + + KroneckerDelta(a, d)*NO(F(b)*Fd(c)) + NO(F(a)*F(b)*Fd(c)*Fd(d))) def test_NO(): - i,j,k,l = symbols('i j k l',below_fermi=True) - a,b,c,d = symbols('a b c d',above_fermi=True) - p,q,r,s = symbols('p q r s', cls=Dummy) + i, j, k, l = symbols('i j k l', below_fermi=True) + a, b, c, d = symbols('a b c d', above_fermi=True) + p, q, r, s = symbols('p q r s', cls=Dummy) - assert (NO(Fd(p)*F(q) + Fd(a)*F(b))== + assert (NO(Fd(p)*F(q) + Fd(a)*F(b)) == NO(Fd(p)*F(q)) + NO(Fd(a)*F(b))) assert (NO(Fd(i)*NO(F(j)*Fd(a))) == NO(Fd(i)*F(j)*Fd(a))) assert NO(1) == 1 assert NO(i) == i - assert (NO(Fd(a)*Fd(b)*(F(c)+F(d))) == - NO(Fd(a)*Fd(b)*F(c)) + - NO(Fd(a)*Fd(b)*F(d))) + assert (NO(Fd(a)*Fd(b)*(F(c) + F(d))) == + NO(Fd(a)*Fd(b)*F(c)) + + NO(Fd(a)*Fd(b)*F(d))) - assert NO(Fd(a)*F(b))._remove_brackets()==Fd(a)*F(b) - assert NO(F(j)*Fd(i))._remove_brackets()==F(j)*Fd(i) + assert NO(Fd(a)*F(b))._remove_brackets() == Fd(a)*F(b) + assert NO(F(j)*Fd(i))._remove_brackets() == F(j)*Fd(i) - assert (NO(Fd(p)*F(q)).subs(Fd(p),Fd(a)+Fd(i)) == + assert (NO(Fd(p)*F(q)).subs(Fd(p), Fd(a) + Fd(i)) == NO(Fd(a)*F(q)) + NO(Fd(i)*F(q))) - assert (NO(Fd(p)*F(q)).subs(F(q),F(a)+F(i)) == + assert (NO(Fd(p)*F(q)).subs(F(q), F(a) + F(i)) == NO(Fd(p)*F(a)) + NO(Fd(p)*F(i))) - expr = NO(Fd(p)*F(q))._remove_brackets() assert wicks(expr) == NO(expr) assert NO(Fd(a)*F(b)) == - NO(F(b)*Fd(a)) - no = NO(Fd(a)*F(i)*F(b)*Fd(j)) + no = NO(Fd(a)*F(i)*F(b)*Fd(j)) l1 = [ ind for ind in no.iter_q_creators() ] - assert l1 == [0,1] + assert l1 == [0, 1] l2 = [ ind for ind in no.iter_q_annihilators() ] - assert l2 == [3,2] + assert l2 == [3, 2] + def test_sorting(): - i,j = symbols('i,j',below_fermi=True) - a,b = symbols('a,b',above_fermi=True) - p,q = symbols('p,q') + i, j = symbols('i,j', below_fermi=True) + a, b = symbols('a,b', above_fermi=True) + p, q = symbols('p,q') # p, q assert _sort_anticommuting_fermions([Fd(p), F(q)]) == ([Fd(p), F(q)], 0) @@ -424,103 +439,109 @@ assert _sort_anticommuting_fermions([F(a), F(i)]) == ([F(i), F(a)], 1) assert _sort_anticommuting_fermions([F(i), F(a)]) == ([F(i), F(a)], 0) + def test_contraction(): - i,j,k,l = symbols('i,j,k,l',below_fermi=True) - a,b,c,d = symbols('a,b,c,d',above_fermi=True) - p,q,r,s = symbols('p,q,r,s') - assert contraction(Fd(i),F(j)) == KroneckerDelta(i,j) - assert contraction(F(a),Fd(b)) == KroneckerDelta(a,b) - assert contraction(F(a),Fd(i)) == 0 - assert contraction(Fd(a),F(i)) == 0 - assert contraction(F(i),Fd(a)) == 0 - assert contraction(Fd(i),F(a)) == 0 - assert contraction(Fd(i),F(p)) == KroneckerDelta(i, p) - restr = evaluate_deltas(contraction(Fd(p),F(q))) + i, j, k, l = symbols('i,j,k,l', below_fermi=True) + a, b, c, d = symbols('a,b,c,d', above_fermi=True) + p, q, r, s = symbols('p,q,r,s') + assert contraction(Fd(i), F(j)) == KroneckerDelta(i, j) + assert contraction(F(a), Fd(b)) == KroneckerDelta(a, b) + assert contraction(F(a), Fd(i)) == 0 + assert contraction(Fd(a), F(i)) == 0 + assert contraction(F(i), Fd(a)) == 0 + assert contraction(Fd(i), F(a)) == 0 + assert contraction(Fd(i), F(p)) == KroneckerDelta(i, p) + restr = evaluate_deltas(contraction(Fd(p), F(q))) assert restr.is_only_below_fermi - restr = evaluate_deltas(contraction(F(p),Fd(q))) + restr = evaluate_deltas(contraction(F(p), Fd(q))) assert restr.is_only_above_fermi - def test_Tensors(): - i,j,k,l = symbols('i j k l',below_fermi=True,cls=Dummy) - a,b,c,d = symbols('a b c d',above_fermi=True,cls=Dummy) - p,q,r,s = symbols('p q r s') - - AT= AntiSymmetricTensor - assert AT('t',(a,b),(i,j)) == -AT('t',(b,a),(i,j)) - assert AT('t',(a,b),(i,j)) == AT('t',(b,a),(j,i)) - assert AT('t',(a,b),(i,j)) == -AT('t',(a,b),(j,i)) - assert AT('t',(a,a),(i,j)) == 0 - assert AT('t',(a,b),(i,i)) == 0 - assert AT('t',(a,b,c),(i,j)) == -AT('t',(b,a,c),(i,j)) - assert AT('t',(a,b,c),(i,j,k)) == AT('t',(b,a,c),(i,k,j)) + i, j, k, l = symbols('i j k l', below_fermi=True, cls=Dummy) + a, b, c, d = symbols('a b c d', above_fermi=True, cls=Dummy) + p, q, r, s = symbols('p q r s') + + AT = AntiSymmetricTensor + assert AT('t', (a, b), (i, j)) == -AT('t', (b, a), (i, j)) + assert AT('t', (a, b), (i, j)) == AT('t', (b, a), (j, i)) + assert AT('t', (a, b), (i, j)) == -AT('t', (a, b), (j, i)) + assert AT('t', (a, a), (i, j)) == 0 + assert AT('t', (a, b), (i, i)) == 0 + assert AT('t', (a, b, c), (i, j)) == -AT('t', (b, a, c), (i, j)) + assert AT('t', (a, b, c), (i, j, k)) == AT('t', (b, a, c), (i, k, j)) - tabij = AT('t',(a,b),(i,j)) + tabij = AT('t', (a, b), (i, j)) assert tabij.has(a) assert tabij.has(b) assert tabij.has(i) assert tabij.has(j) - assert tabij.subs(b,c) == AT('t',(a,c),(i,j)) - assert (2*tabij).subs(i,c) == 2*AT('t',(a,b),(c,j)) + assert tabij.subs(b, c) == AT('t', (a, c), (i, j)) + assert (2*tabij).subs(i, c) == 2*AT('t', (a, b), (c, j)) assert AT('t', (a, a), (i, j)).subs(a, b) == AT('t', (b, b), (i, j)) assert AT('t', (a, i), (a, j)).subs(a, b) == AT('t', (b, i), (b, j)) def test_fully_contracted(): - i,j,k,l = symbols('i j k l',below_fermi=True) - a,b,c,d = symbols('a b c d',above_fermi=True) - p,q,r,s = symbols('p q r s', cls=Dummy) + i, j, k, l = symbols('i j k l', below_fermi=True) + a, b, c, d = symbols('a b c d', above_fermi=True) + p, q, r, s = symbols('p q r s', cls=Dummy) - Fock = (AntiSymmetricTensor('f',(p,),(q,))* + Fock = (AntiSymmetricTensor('f', (p,), (q,))* NO(Fd(p)*F(q))) - V = (AntiSymmetricTensor('v',(p,q),(r,s))* - NO(Fd(p)*Fd(q)*F(s)*F(r)))/4 + V = (AntiSymmetricTensor('v', (p, q), (r, s))* + NO(Fd(p)*Fd(q)*F(s)*F(r)))/4 - Fai=wicks(NO(Fd(i)*F(a))*Fock, + Fai = wicks(NO(Fd(i)*F(a))*Fock, keep_only_fully_contracted=True, simplify_kronecker_deltas=True) - assert Fai == AntiSymmetricTensor('f',(a,),(i,)) - Vabij=wicks(NO(Fd(i)*Fd(j)*F(b)*F(a))*V, + assert Fai == AntiSymmetricTensor('f', (a,), (i,)) + Vabij = wicks(NO(Fd(i)*Fd(j)*F(b)*F(a))*V, keep_only_fully_contracted=True, simplify_kronecker_deltas=True) - assert Vabij==AntiSymmetricTensor('v',(a,b),(i,j)) + assert Vabij == AntiSymmetricTensor('v', (a, b), (i, j)) + def test_substitute_dummies_without_dummies(): - i,j = symbols('i,j') + i, j = symbols('i,j') assert substitute_dummies(att(i, j) + 2) == att(i, j) + 2 assert substitute_dummies(att(i, j) + 1) == att(i, j) + 1 + def test_substitute_dummies_NO_operator(): - i,j = symbols('i j', cls=Dummy) + i, j = symbols('i j', cls=Dummy) assert substitute_dummies(att(i, j)*NO(Fd(i)*F(j)) - att(j, i)*NO(Fd(j)*F(i))) == 0 + def test_substitute_dummies_SQ_operator(): - i,j = symbols('i j', cls=Dummy) + i, j = symbols('i j', cls=Dummy) assert substitute_dummies(att(i, j)*Fd(i)*F(j) - att(j, i)*Fd(j)*F(i)) == 0 + def test_substitute_dummies_new_indices(): - i,j = symbols('i j',below_fermi=True, cls=Dummy) - a,b = symbols('a b',above_fermi=True, cls=Dummy) - p,q = symbols('p q', cls=Dummy) + i, j = symbols('i j', below_fermi=True, cls=Dummy) + a, b = symbols('a b', above_fermi=True, cls=Dummy) + p, q = symbols('p q', cls=Dummy) f = Function('f') - assert substitute_dummies(f(i,a,p) - f(j,b,q), new_indices=True) == 0 + assert substitute_dummies(f(i, a, p) - f(j, b, q), new_indices=True) == 0 + def test_substitute_dummies_substitution_order(): - i,j,k,l = symbols('i j k l',below_fermi=True, cls=Dummy) + i, j, k, l = symbols('i j k l', below_fermi=True, cls=Dummy) f = Function('f') from sympy.utilities.iterables import variations - for permut in variations([i,j,k,l], 4): - assert substitute_dummies(f(*permut) - f(i,j,k,l)) == 0 + for permut in variations([i, j, k, l], 4): + assert substitute_dummies(f(*permut) - f(i, j, k, l)) == 0 + def test_dummy_order_inner_outer_lines_VT1T1T1(): - ii = symbols('i',below_fermi=True) - aa = symbols('a',above_fermi=True) - k, l = symbols('k l',below_fermi=True, cls=Dummy) - c, d = symbols('c d',above_fermi=True, cls=Dummy) + ii = symbols('i', below_fermi=True) + aa = symbols('a', above_fermi=True) + k, l = symbols('k l', below_fermi=True, cls=Dummy) + c, d = symbols('c d', above_fermi=True, cls=Dummy) v = Function('v') t = Function('t') @@ -529,22 +550,23 @@ # Coupled-Cluster T1 terms with V*T1*T1*T1 # t^{a}_{k} t^{c}_{i} t^{d}_{l} v^{lk}_{dc} exprs = [ - # permut v and t <=> swapping internal lines, equivalent - # irrespective of symmetries in v - v(k, l, c, d)*t(c, ii)*t(d, l)*t(aa, k), - v(l, k, c, d)*t(c, ii)*t(d, k)*t(aa, l), - v(k, l, d, c)*t(d, ii)*t(c, l)*t(aa, k), - v(l, k, d, c)*t(d, ii)*t(c, k)*t(aa, l), - ] + # permut v and t <=> swapping internal lines, equivalent + # irrespective of symmetries in v + v(k, l, c, d)*t(c, ii)*t(d, l)*t(aa, k), + v(l, k, c, d)*t(c, ii)*t(d, k)*t(aa, l), + v(k, l, d, c)*t(d, ii)*t(c, l)*t(aa, k), + v(l, k, d, c)*t(d, ii)*t(c, k)*t(aa, l), + ] for permut in exprs[1:]: assert dums(exprs[0]) != dums(permut) assert substitute_dummies(exprs[0]) == substitute_dummies(permut) + def test_dummy_order_inner_outer_lines_VT1T1T1T1(): - ii,jj = symbols('i j',below_fermi=True) - aa,bb = symbols('a b',above_fermi=True) - k, l = symbols('k l',below_fermi=True, cls=Dummy) - c, d = symbols('c d',above_fermi=True, cls=Dummy) + ii, jj = symbols('i j', below_fermi=True) + aa, bb = symbols('a b', above_fermi=True) + k, l = symbols('k l', below_fermi=True, cls=Dummy) + c, d = symbols('c d', above_fermi=True, cls=Dummy) v = Function('v') t = Function('t') @@ -552,95 +574,97 @@ # Coupled-Cluster T2 terms with V*T1*T1*T1*T1 exprs = [ - # permut t <=> swapping external lines, not equivalent - # except if v has certain symmetries. - v(k, l, c, d)*t(c, ii)*t(d, jj)*t(aa, k)*t(bb, l), - v(k, l, c, d)*t(c, jj)*t(d, ii)*t(aa, k)*t(bb, l), - v(k, l, c, d)*t(c, ii)*t(d, jj)*t(bb, k)*t(aa, l), - v(k, l, c, d)*t(c, jj)*t(d, ii)*t(bb, k)*t(aa, l), - ] + # permut t <=> swapping external lines, not equivalent + # except if v has certain symmetries. + v(k, l, c, d)*t(c, ii)*t(d, jj)*t(aa, k)*t(bb, l), + v(k, l, c, d)*t(c, jj)*t(d, ii)*t(aa, k)*t(bb, l), + v(k, l, c, d)*t(c, ii)*t(d, jj)*t(bb, k)*t(aa, l), + v(k, l, c, d)*t(c, jj)*t(d, ii)*t(bb, k)*t(aa, l), + ] for permut in exprs[1:]: assert dums(exprs[0]) != dums(permut) assert substitute_dummies(exprs[0]) != substitute_dummies(permut) exprs = [ - # permut v <=> swapping external lines, not equivalent - # except if v has certain symmetries. - # - # Note that in contrast to above, these permutations have identical - # dummy order. That is because the proximity to external indices - # has higher influence on the canonical dummy ordering than the - # position of a dummy on the factors. In fact, the terms here are - # similar in structure as the result of the dummy substitions above. - v(k, l, c, d)*t(c, ii)*t(d, jj)*t(aa, k)*t(bb, l), - v(l, k, c, d)*t(c, ii)*t(d, jj)*t(aa, k)*t(bb, l), - v(k, l, d, c)*t(c, ii)*t(d, jj)*t(aa, k)*t(bb, l), - v(l, k, d, c)*t(c, ii)*t(d, jj)*t(aa, k)*t(bb, l), - ] + # permut v <=> swapping external lines, not equivalent + # except if v has certain symmetries. + # + # Note that in contrast to above, these permutations have identical + # dummy order. That is because the proximity to external indices + # has higher influence on the canonical dummy ordering than the + # position of a dummy on the factors. In fact, the terms here are + # similar in structure as the result of the dummy substitions above. + v(k, l, c, d)*t(c, ii)*t(d, jj)*t(aa, k)*t(bb, l), + v(l, k, c, d)*t(c, ii)*t(d, jj)*t(aa, k)*t(bb, l), + v(k, l, d, c)*t(c, ii)*t(d, jj)*t(aa, k)*t(bb, l), + v(l, k, d, c)*t(c, ii)*t(d, jj)*t(aa, k)*t(bb, l), + ] for permut in exprs[1:]: assert dums(exprs[0]) == dums(permut) assert substitute_dummies(exprs[0]) != substitute_dummies(permut) exprs = [ - # permut t and v <=> swapping internal lines, equivalent. - # Canonical dummy order is different, and a consistent - # substitution reveals the equivalence. - v(k, l, c, d)*t(c, ii)*t(d, jj)*t(aa, k)*t(bb, l), - v(k, l, d, c)*t(c, jj)*t(d, ii)*t(aa, k)*t(bb, l), - v(l, k, c, d)*t(c, ii)*t(d, jj)*t(bb, k)*t(aa, l), - v(l, k, d, c)*t(c, jj)*t(d, ii)*t(bb, k)*t(aa, l), - ] + # permut t and v <=> swapping internal lines, equivalent. + # Canonical dummy order is different, and a consistent + # substitution reveals the equivalence. + v(k, l, c, d)*t(c, ii)*t(d, jj)*t(aa, k)*t(bb, l), + v(k, l, d, c)*t(c, jj)*t(d, ii)*t(aa, k)*t(bb, l), + v(l, k, c, d)*t(c, ii)*t(d, jj)*t(bb, k)*t(aa, l), + v(l, k, d, c)*t(c, jj)*t(d, ii)*t(bb, k)*t(aa, l), + ] for permut in exprs[1:]: assert dums(exprs[0]) != dums(permut) assert substitute_dummies(exprs[0]) == substitute_dummies(permut) + def test_equivalent_internal_lines_VT1T1(): - i,j,k,l = symbols('i j k l',below_fermi=True, cls=Dummy) - a,b,c,d = symbols('a b c d',above_fermi=True, cls=Dummy) + i, j, k, l = symbols('i j k l', below_fermi=True, cls=Dummy) + a, b, c, d = symbols('a b c d', above_fermi=True, cls=Dummy) v = Function('v') t = Function('t') dums = _get_ordered_dummies - exprs = [ # permute v. Different dummy order. Not equivalent. - v(i, j, a, b)*t(a, i)*t(b, j), - v(j, i, a, b)*t(a, i)*t(b, j), - v(i, j, b, a)*t(a, i)*t(b, j), - ] + exprs = [ # permute v. Different dummy order. Not equivalent. + v(i, j, a, b)*t(a, i)*t(b, j), + v(j, i, a, b)*t(a, i)*t(b, j), + v(i, j, b, a)*t(a, i)*t(b, j), + ] for permut in exprs[1:]: assert dums(exprs[0]) != dums(permut) assert substitute_dummies(exprs[0]) != substitute_dummies(permut) - exprs = [ # permute v. Different dummy order. Equivalent - v(i, j, a, b)*t(a, i)*t(b, j), - v(j, i, b, a)*t(a, i)*t(b, j), - ] + exprs = [ # permute v. Different dummy order. Equivalent + v(i, j, a, b)*t(a, i)*t(b, j), + v(j, i, b, a)*t(a, i)*t(b, j), + ] for permut in exprs[1:]: assert dums(exprs[0]) != dums(permut) assert substitute_dummies(exprs[0]) == substitute_dummies(permut) - exprs = [ # permute t. Same dummy order, not equivalent. - v(i, j, a, b)*t(a, i)*t(b, j), - v(i, j, a, b)*t(b, i)*t(a, j), - ] + exprs = [ # permute t. Same dummy order, not equivalent. + v(i, j, a, b)*t(a, i)*t(b, j), + v(i, j, a, b)*t(b, i)*t(a, j), + ] for permut in exprs[1:]: assert dums(exprs[0]) == dums(permut) assert substitute_dummies(exprs[0]) != substitute_dummies(permut) - exprs = [ # permute v and t. Different dummy order, equivalent - v(i, j, a, b)*t(a, i)*t(b, j), - v(j, i, a, b)*t(a, j)*t(b, i), - v(i, j, b, a)*t(b, i)*t(a, j), - v(j, i, b, a)*t(b, j)*t(a, i), - ] + exprs = [ # permute v and t. Different dummy order, equivalent + v(i, j, a, b)*t(a, i)*t(b, j), + v(j, i, a, b)*t(a, j)*t(b, i), + v(i, j, b, a)*t(b, i)*t(a, j), + v(j, i, b, a)*t(b, j)*t(a, i), + ] for permut in exprs[1:]: assert dums(exprs[0]) != dums(permut) assert substitute_dummies(exprs[0]) == substitute_dummies(permut) + def test_equivalent_internal_lines_VT2conjT2(): # this diagram requires special handling in TCE - i,j,k,l,m,n = symbols('i j k l m n',below_fermi=True, cls=Dummy) - a,b,c,d,e,f = symbols('a b c d e f',above_fermi=True, cls=Dummy) - p1,p2,p3,p4 = symbols('p1 p2 p3 p4',above_fermi=True, cls=Dummy) - h1,h2,h3,h4 = symbols('h1 h2 h3 h4',below_fermi=True, cls=Dummy) + i, j, k, l, m, n = symbols('i j k l m n', below_fermi=True, cls=Dummy) + a, b, c, d, e, f = symbols('a b c d e f', above_fermi=True, cls=Dummy) + p1, p2, p3, p4 = symbols('p1 p2 p3 p4', above_fermi=True, cls=Dummy) + h1, h2, h3, h4 = symbols('h1 h2 h3 h4', below_fermi=True, cls=Dummy) from sympy.utilities.iterables import variations @@ -650,7 +674,7 @@ # v(abcd)t(abij)t(ijcd) template = v(p1, p2, p3, p4)*t(p1, p2, i, j)*t(i, j, p3, p4) - permutator = variations([a,b,c,d], 4) + permutator = variations([a, b, c, d], 4) base = template.subs(list(zip([p1, p2, p3, p4], next(permutator)))) for permut in permutator: subslist = list(zip([p1, p2, p3, p4], permut)) @@ -658,7 +682,7 @@ assert dums(base) != dums(expr) assert substitute_dummies(expr) == substitute_dummies(base) template = v(p1, p2, p3, p4)*t(p1, p2, j, i)*t(j, i, p3, p4) - permutator = variations([a,b,c,d], 4) + permutator = variations([a, b, c, d], 4) base = template.subs(list(zip([p1, p2, p3, p4], next(permutator)))) for permut in permutator: subslist = list(zip([p1, p2, p3, p4], permut)) @@ -668,7 +692,7 @@ # v(abcd)t(abij)t(jicd) template = v(p1, p2, p3, p4)*t(p1, p2, i, j)*t(j, i, p3, p4) - permutator = variations([a,b,c,d], 4) + permutator = variations([a, b, c, d], 4) base = template.subs(list(zip([p1, p2, p3, p4], next(permutator)))) for permut in permutator: subslist = list(zip([p1, p2, p3, p4], permut)) @@ -676,7 +700,7 @@ assert dums(base) != dums(expr) assert substitute_dummies(expr) == substitute_dummies(base) template = v(p1, p2, p3, p4)*t(p1, p2, j, i)*t(i, j, p3, p4) - permutator = variations([a,b,c,d], 4) + permutator = variations([a, b, c, d], 4) base = template.subs(list(zip([p1, p2, p3, p4], next(permutator)))) for permut in permutator: subslist = list(zip([p1, p2, p3, p4], permut)) @@ -684,13 +708,14 @@ assert dums(base) != dums(expr) assert substitute_dummies(expr) == substitute_dummies(base) + def test_equivalent_internal_lines_VT2conjT2_ambiguous_order(): # These diagrams invokes _determine_ambiguous() because the # dummies can not be ordered unambiguously by the key alone - i,j,k,l,m,n = symbols('i j k l m n',below_fermi=True, cls=Dummy) - a,b,c,d,e,f = symbols('a b c d e f',above_fermi=True, cls=Dummy) - p1,p2,p3,p4 = symbols('p1 p2 p3 p4',above_fermi=True, cls=Dummy) - h1,h2,h3,h4 = symbols('h1 h2 h3 h4',below_fermi=True, cls=Dummy) + i, j, k, l, m, n = symbols('i j k l m n', below_fermi=True, cls=Dummy) + a, b, c, d, e, f = symbols('a b c d e f', above_fermi=True, cls=Dummy) + p1, p2, p3, p4 = symbols('p1 p2 p3 p4', above_fermi=True, cls=Dummy) + h1, h2, h3, h4 = symbols('h1 h2 h3 h4', below_fermi=True, cls=Dummy) from sympy.utilities.iterables import variations @@ -700,7 +725,7 @@ # v(abcd)t(abij)t(cdij) template = v(p1, p2, p3, p4)*t(p1, p2, i, j)*t(p3, p4, i, j) - permutator = variations([a,b,c,d], 4) + permutator = variations([a, b, c, d], 4) base = template.subs(list(zip([p1, p2, p3, p4], next(permutator)))) for permut in permutator: subslist = list(zip([p1, p2, p3, p4], permut)) @@ -708,7 +733,7 @@ assert dums(base) != dums(expr) assert substitute_dummies(expr) == substitute_dummies(base) template = v(p1, p2, p3, p4)*t(p1, p2, j, i)*t(p3, p4, i, j) - permutator = variations([a,b,c,d], 4) + permutator = variations([a, b, c, d], 4) base = template.subs(list(zip([p1, p2, p3, p4], next(permutator)))) for permut in permutator: subslist = list(zip([p1, p2, p3, p4], permut)) @@ -716,112 +741,116 @@ assert dums(base) != dums(expr) assert substitute_dummies(expr) == substitute_dummies(base) + def test_equivalent_internal_lines_VT2(): - i,j,k,l = symbols('i j k l',below_fermi=True, cls=Dummy) - a,b,c,d = symbols('a b c d',above_fermi=True, cls=Dummy) + i, j, k, l = symbols('i j k l', below_fermi=True, cls=Dummy) + a, b, c, d = symbols('a b c d', above_fermi=True, cls=Dummy) v = Function('v') t = Function('t') dums = _get_ordered_dummies exprs = [ - # permute v. Same dummy order, not equivalent. - # - # This test show that the dummy order may not be sensitive to all - # index permutations. The following expressions have identical - # structure as the resulting terms from of the dummy subsitutions - # in the test above. Here, all expressions have the same dummy - # order, so they cannot be simplified by means of dummy - # substitution. In order to simplify further, it is necessary to - # exploit symmetries in the objects, for instance if t or v is - # antisymmetric. - v(i, j, a, b)*t(a, b, i, j), - v(j, i, a, b)*t(a, b, i, j), - v(i, j, b, a)*t(a, b, i, j), - v(j, i, b, a)*t(a, b, i, j), - ] + # permute v. Same dummy order, not equivalent. + # + # This test show that the dummy order may not be sensitive to all + # index permutations. The following expressions have identical + # structure as the resulting terms from of the dummy subsitutions + # in the test above. Here, all expressions have the same dummy + # order, so they cannot be simplified by means of dummy + # substitution. In order to simplify further, it is necessary to + # exploit symmetries in the objects, for instance if t or v is + # antisymmetric. + v(i, j, a, b)*t(a, b, i, j), + v(j, i, a, b)*t(a, b, i, j), + v(i, j, b, a)*t(a, b, i, j), + v(j, i, b, a)*t(a, b, i, j), + ] for permut in exprs[1:]: assert dums(exprs[0]) == dums(permut) assert substitute_dummies(exprs[0]) != substitute_dummies(permut) exprs = [ - # permute t. - v(i, j, a, b)*t(a, b, i, j), - v(i, j, a, b)*t(b, a, i, j), - v(i, j, a, b)*t(a, b, j, i), - v(i, j, a, b)*t(b, a, j, i), - ] + # permute t. + v(i, j, a, b)*t(a, b, i, j), + v(i, j, a, b)*t(b, a, i, j), + v(i, j, a, b)*t(a, b, j, i), + v(i, j, a, b)*t(b, a, j, i), + ] for permut in exprs[1:]: assert dums(exprs[0]) != dums(permut) assert substitute_dummies(exprs[0]) != substitute_dummies(permut) - exprs = [ # permute v and t. Relabelling of dummies should be equivalent. - v(i, j, a, b)*t(a, b, i, j), - v(j, i, a, b)*t(a, b, j, i), - v(i, j, b, a)*t(b, a, i, j), - v(j, i, b, a)*t(b, a, j, i), - ] + exprs = [ # permute v and t. Relabelling of dummies should be equivalent. + v(i, j, a, b)*t(a, b, i, j), + v(j, i, a, b)*t(a, b, j, i), + v(i, j, b, a)*t(b, a, i, j), + v(j, i, b, a)*t(b, a, j, i), + ] for permut in exprs[1:]: assert dums(exprs[0]) != dums(permut) assert substitute_dummies(exprs[0]) == substitute_dummies(permut) + def test_internal_external_VT2T2(): - ii, jj = symbols('i j',below_fermi=True) - aa, bb = symbols('a b',above_fermi=True) - k, l = symbols('k l' ,below_fermi=True, cls=Dummy) - c, d = symbols('c d' ,above_fermi=True, cls=Dummy) + ii, jj = symbols('i j', below_fermi=True) + aa, bb = symbols('a b', above_fermi=True) + k, l = symbols('k l', below_fermi=True, cls=Dummy) + c, d = symbols('c d', above_fermi=True, cls=Dummy) v = Function('v') t = Function('t') dums = _get_ordered_dummies exprs = [ - v(k,l,c,d)*t(aa, c, ii, k)*t(bb, d, jj, l), - v(l,k,c,d)*t(aa, c, ii, l)*t(bb, d, jj, k), - v(k,l,d,c)*t(aa, d, ii, k)*t(bb, c, jj, l), - v(l,k,d,c)*t(aa, d, ii, l)*t(bb, c, jj, k), - ] + v(k, l, c, d)*t(aa, c, ii, k)*t(bb, d, jj, l), + v(l, k, c, d)*t(aa, c, ii, l)*t(bb, d, jj, k), + v(k, l, d, c)*t(aa, d, ii, k)*t(bb, c, jj, l), + v(l, k, d, c)*t(aa, d, ii, l)*t(bb, c, jj, k), + ] for permut in exprs[1:]: assert dums(exprs[0]) != dums(permut) assert substitute_dummies(exprs[0]) == substitute_dummies(permut) exprs = [ - v(k,l,c,d)*t(aa, c, ii, k)*t(d, bb, jj, l), - v(l,k,c,d)*t(aa, c, ii, l)*t(d, bb, jj, k), - v(k,l,d,c)*t(aa, d, ii, k)*t(c, bb, jj, l), - v(l,k,d,c)*t(aa, d, ii, l)*t(c, bb, jj, k), - ] + v(k, l, c, d)*t(aa, c, ii, k)*t(d, bb, jj, l), + v(l, k, c, d)*t(aa, c, ii, l)*t(d, bb, jj, k), + v(k, l, d, c)*t(aa, d, ii, k)*t(c, bb, jj, l), + v(l, k, d, c)*t(aa, d, ii, l)*t(c, bb, jj, k), + ] for permut in exprs[1:]: assert dums(exprs[0]) != dums(permut) assert substitute_dummies(exprs[0]) == substitute_dummies(permut) exprs = [ - v(k,l,c,d)*t(c, aa, ii, k)*t(bb, d, jj, l), - v(l,k,c,d)*t(c, aa, ii, l)*t(bb, d, jj, k), - v(k,l,d,c)*t(d, aa, ii, k)*t(bb, c, jj, l), - v(l,k,d,c)*t(d, aa, ii, l)*t(bb, c, jj, k), - ] + v(k, l, c, d)*t(c, aa, ii, k)*t(bb, d, jj, l), + v(l, k, c, d)*t(c, aa, ii, l)*t(bb, d, jj, k), + v(k, l, d, c)*t(d, aa, ii, k)*t(bb, c, jj, l), + v(l, k, d, c)*t(d, aa, ii, l)*t(bb, c, jj, k), + ] for permut in exprs[1:]: assert dums(exprs[0]) != dums(permut) assert substitute_dummies(exprs[0]) == substitute_dummies(permut) + def test_internal_external_pqrs(): ii, jj = symbols('i j') aa, bb = symbols('a b') - k, l = symbols('k l' , cls=Dummy) - c, d = symbols('c d' , cls=Dummy) + k, l = symbols('k l', cls=Dummy) + c, d = symbols('c d', cls=Dummy) v = Function('v') t = Function('t') dums = _get_ordered_dummies exprs = [ - v(k,l,c,d)*t(aa, c, ii, k)*t(bb, d, jj, l), - v(l,k,c,d)*t(aa, c, ii, l)*t(bb, d, jj, k), - v(k,l,d,c)*t(aa, d, ii, k)*t(bb, c, jj, l), - v(l,k,d,c)*t(aa, d, ii, l)*t(bb, c, jj, k), - ] + v(k, l, c, d)*t(aa, c, ii, k)*t(bb, d, jj, l), + v(l, k, c, d)*t(aa, c, ii, l)*t(bb, d, jj, k), + v(k, l, d, c)*t(aa, d, ii, k)*t(bb, c, jj, l), + v(l, k, d, c)*t(aa, d, ii, l)*t(bb, c, jj, k), + ] for permut in exprs[1:]: assert dums(exprs[0]) != dums(permut) assert substitute_dummies(exprs[0]) == substitute_dummies(permut) + def test_dummy_order_well_defined(): aa, bb = symbols('a b', above_fermi=True) k, l, m = symbols('k l m', below_fermi=True, cls=Dummy) @@ -877,15 +906,16 @@ assert dums(B(k, c, p)*A(p, c, k)) == [k, c, p] assert dums(B(k, p, c)*A(p, c, k)) == [k, c, p] + def test_dummy_order_ambiguous(): aa, bb = symbols('a b', above_fermi=True) i, j, k, l, m = symbols('i j k l m', below_fermi=True, cls=Dummy) a, b, c, d, e = symbols('a b c d e', above_fermi=True, cls=Dummy) p, q = symbols('p q', cls=Dummy) - p1,p2,p3,p4 = symbols('p1 p2 p3 p4',above_fermi=True, cls=Dummy) - p5,p6,p7,p8 = symbols('p5 p6 p7 p8',above_fermi=True, cls=Dummy) - h1,h2,h3,h4 = symbols('h1 h2 h3 h4',below_fermi=True, cls=Dummy) - h5,h6,h7,h8 = symbols('h5 h6 h7 h8',below_fermi=True, cls=Dummy) + p1, p2, p3, p4 = symbols('p1 p2 p3 p4', above_fermi=True, cls=Dummy) + p5, p6, p7, p8 = symbols('p5 p6 p7 p8', above_fermi=True, cls=Dummy) + h1, h2, h3, h4 = symbols('h1 h2 h3 h4', below_fermi=True, cls=Dummy) + h5, h6, h7, h8 = symbols('h5 h6 h7 h8', below_fermi=True, cls=Dummy) A = Function('A') B = Function('B') @@ -894,7 +924,7 @@ # A*A*A*A*B -- ordering of p5 and p4 is used to figure out the rest template = A(p1, p2)*A(p4, p1)*A(p2, p3)*A(p3, p5)*B(p5, p4) - permutator = variations([a,b,c,d,e], 5) + permutator = variations([a, b, c, d, e], 5) base = template.subs(list(zip([p1, p2, p3, p4, p5], next(permutator)))) for permut in permutator: subslist = list(zip([p1, p2, p3, p4, p5], permut)) @@ -903,7 +933,7 @@ # A*A*A*A*A -- an arbitrary index is assigned and the rest are figured out template = A(p1, p2)*A(p4, p1)*A(p2, p3)*A(p3, p5)*A(p5, p4) - permutator = variations([a,b,c,d,e], 5) + permutator = variations([a, b, c, d, e], 5) base = template.subs(list(zip([p1, p2, p3, p4, p5], next(permutator)))) for permut in permutator: subslist = list(zip([p1, p2, p3, p4, p5], permut)) @@ -912,124 +942,127 @@ # A*A*A -- ordering of p5 and p4 is used to figure out the rest template = A(p1, p2, p4, p1)*A(p2, p3, p3, p5)*A(p5, p4) - permutator = variations([a,b,c,d,e], 5) + permutator = variations([a, b, c, d, e], 5) base = template.subs(list(zip([p1, p2, p3, p4, p5], next(permutator)))) for permut in permutator: subslist = list(zip([p1, p2, p3, p4, p5], permut)) expr = template.subs(subslist) assert substitute_dummies(expr) == substitute_dummies(base) + def atv(*args): return AntiSymmetricTensor('v', args[:2], args[2:] ) + + def att(*args): if len(args) == 4: return AntiSymmetricTensor('t', args[:2], args[2:] ) elif len(args) == 2: return AntiSymmetricTensor('t', (args[0],), (args[1],)) -def test_dummy_order_inner_outer_lines_VT1T1T1_AT(): - ii = symbols('i',below_fermi=True) - aa = symbols('a',above_fermi=True) - k, l = symbols('k l',below_fermi=True, cls=Dummy) - c, d = symbols('c d',above_fermi=True, cls=Dummy) +def test_dummy_order_inner_outer_lines_VT1T1T1_AT(): + ii = symbols('i', below_fermi=True) + aa = symbols('a', above_fermi=True) + k, l = symbols('k l', below_fermi=True, cls=Dummy) + c, d = symbols('c d', above_fermi=True, cls=Dummy) # Coupled-Cluster T1 terms with V*T1*T1*T1 # t^{a}_{k} t^{c}_{i} t^{d}_{l} v^{lk}_{dc} exprs = [ - # permut v and t <=> swapping internal lines, equivalent - # irrespective of symmetries in v - atv(k, l, c, d)*att(c, ii)*att(d, l)*att(aa, k), - atv(l, k, c, d)*att(c, ii)*att(d, k)*att(aa, l), - atv(k, l, d, c)*att(d, ii)*att(c, l)*att(aa, k), - atv(l, k, d, c)*att(d, ii)*att(c, k)*att(aa, l), - ] + # permut v and t <=> swapping internal lines, equivalent + # irrespective of symmetries in v + atv(k, l, c, d)*att(c, ii)*att(d, l)*att(aa, k), + atv(l, k, c, d)*att(c, ii)*att(d, k)*att(aa, l), + atv(k, l, d, c)*att(d, ii)*att(c, l)*att(aa, k), + atv(l, k, d, c)*att(d, ii)*att(c, k)*att(aa, l), + ] for permut in exprs[1:]: assert substitute_dummies(exprs[0]) == substitute_dummies(permut) -def test_dummy_order_inner_outer_lines_VT1T1T1T1_AT(): - ii,jj = symbols('i j',below_fermi=True) - aa,bb = symbols('a b',above_fermi=True) - k, l = symbols('k l',below_fermi=True, cls=Dummy) - c, d = symbols('c d',above_fermi=True, cls=Dummy) +def test_dummy_order_inner_outer_lines_VT1T1T1T1_AT(): + ii, jj = symbols('i j', below_fermi=True) + aa, bb = symbols('a b', above_fermi=True) + k, l = symbols('k l', below_fermi=True, cls=Dummy) + c, d = symbols('c d', above_fermi=True, cls=Dummy) # Coupled-Cluster T2 terms with V*T1*T1*T1*T1 # non-equivalent substitutions (change of sign) exprs = [ - # permut t <=> swapping external lines - atv(k, l, c, d)*att(c, ii)*att(d, jj)*att(aa, k)*att(bb, l), - atv(k, l, c, d)*att(c, jj)*att(d, ii)*att(aa, k)*att(bb, l), - atv(k, l, c, d)*att(c, ii)*att(d, jj)*att(bb, k)*att(aa, l), - ] + # permut t <=> swapping external lines + atv(k, l, c, d)*att(c, ii)*att(d, jj)*att(aa, k)*att(bb, l), + atv(k, l, c, d)*att(c, jj)*att(d, ii)*att(aa, k)*att(bb, l), + atv(k, l, c, d)*att(c, ii)*att(d, jj)*att(bb, k)*att(aa, l), + ] for permut in exprs[1:]: assert substitute_dummies(exprs[0]) == -substitute_dummies(permut) # equivalent substitutions exprs = [ - atv(k, l, c, d)*att(c, ii)*att(d, jj)*att(aa, k)*att(bb, l), - # permut t <=> swapping external lines - atv(k, l, c, d)*att(c, jj)*att(d, ii)*att(bb, k)*att(aa, l), - ] + atv(k, l, c, d)*att(c, ii)*att(d, jj)*att(aa, k)*att(bb, l), + # permut t <=> swapping external lines + atv(k, l, c, d)*att(c, jj)*att(d, ii)*att(bb, k)*att(aa, l), + ] for permut in exprs[1:]: assert substitute_dummies(exprs[0]) == substitute_dummies(permut) -def test_equivalent_internal_lines_VT1T1_AT(): - i,j,k,l = symbols('i j k l',below_fermi=True, cls=Dummy) - a,b,c,d = symbols('a b c d',above_fermi=True, cls=Dummy) +def test_equivalent_internal_lines_VT1T1_AT(): + i, j, k, l = symbols('i j k l', below_fermi=True, cls=Dummy) + a, b, c, d = symbols('a b c d', above_fermi=True, cls=Dummy) - exprs = [ # permute v. Different dummy order. Not equivalent. - atv(i, j, a, b)*att(a, i)*att(b, j), - atv(j, i, a, b)*att(a, i)*att(b, j), - atv(i, j, b, a)*att(a, i)*att(b, j), - ] + exprs = [ # permute v. Different dummy order. Not equivalent. + atv(i, j, a, b)*att(a, i)*att(b, j), + atv(j, i, a, b)*att(a, i)*att(b, j), + atv(i, j, b, a)*att(a, i)*att(b, j), + ] for permut in exprs[1:]: assert substitute_dummies(exprs[0]) != substitute_dummies(permut) - exprs = [ # permute v. Different dummy order. Equivalent - atv(i, j, a, b)*att(a, i)*att(b, j), - atv(j, i, b, a)*att(a, i)*att(b, j), - ] + exprs = [ # permute v. Different dummy order. Equivalent + atv(i, j, a, b)*att(a, i)*att(b, j), + atv(j, i, b, a)*att(a, i)*att(b, j), + ] for permut in exprs[1:]: assert substitute_dummies(exprs[0]) == substitute_dummies(permut) - exprs = [ # permute t. Same dummy order, not equivalent. - atv(i, j, a, b)*att(a, i)*att(b, j), - atv(i, j, a, b)*att(b, i)*att(a, j), - ] + exprs = [ # permute t. Same dummy order, not equivalent. + atv(i, j, a, b)*att(a, i)*att(b, j), + atv(i, j, a, b)*att(b, i)*att(a, j), + ] for permut in exprs[1:]: assert substitute_dummies(exprs[0]) != substitute_dummies(permut) - exprs = [ # permute v and t. Different dummy order, equivalent - atv(i, j, a, b)*att(a, i)*att(b, j), - atv(j, i, a, b)*att(a, j)*att(b, i), - atv(i, j, b, a)*att(b, i)*att(a, j), - atv(j, i, b, a)*att(b, j)*att(a, i), - ] + exprs = [ # permute v and t. Different dummy order, equivalent + atv(i, j, a, b)*att(a, i)*att(b, j), + atv(j, i, a, b)*att(a, j)*att(b, i), + atv(i, j, b, a)*att(b, i)*att(a, j), + atv(j, i, b, a)*att(b, j)*att(a, i), + ] for permut in exprs[1:]: assert substitute_dummies(exprs[0]) == substitute_dummies(permut) + def test_equivalent_internal_lines_VT2conjT2_AT(): # this diagram requires special handling in TCE - i,j,k,l,m,n = symbols('i j k l m n',below_fermi=True, cls=Dummy) - a,b,c,d,e,f = symbols('a b c d e f',above_fermi=True, cls=Dummy) - p1,p2,p3,p4 = symbols('p1 p2 p3 p4',above_fermi=True, cls=Dummy) - h1,h2,h3,h4 = symbols('h1 h2 h3 h4',below_fermi=True, cls=Dummy) + i, j, k, l, m, n = symbols('i j k l m n', below_fermi=True, cls=Dummy) + a, b, c, d, e, f = symbols('a b c d e f', above_fermi=True, cls=Dummy) + p1, p2, p3, p4 = symbols('p1 p2 p3 p4', above_fermi=True, cls=Dummy) + h1, h2, h3, h4 = symbols('h1 h2 h3 h4', below_fermi=True, cls=Dummy) from sympy.utilities.iterables import variations - # atv(abcd)att(abij)att(ijcd) template = atv(p1, p2, p3, p4)*att(p1, p2, i, j)*att(i, j, p3, p4) - permutator = variations([a,b,c,d], 4) + permutator = variations([a, b, c, d], 4) base = template.subs(list(zip([p1, p2, p3, p4], next(permutator)))) for permut in permutator: subslist = list(zip([p1, p2, p3, p4], permut)) expr = template.subs(subslist) assert substitute_dummies(expr) == substitute_dummies(base) template = atv(p1, p2, p3, p4)*att(p1, p2, j, i)*att(j, i, p3, p4) - permutator = variations([a,b,c,d], 4) + permutator = variations([a, b, c, d], 4) base = template.subs(list(zip([p1, p2, p3, p4], next(permutator)))) for permut in permutator: subslist = list(zip([p1, p2, p3, p4], permut)) @@ -1038,121 +1071,123 @@ # atv(abcd)att(abij)att(jicd) template = atv(p1, p2, p3, p4)*att(p1, p2, i, j)*att(j, i, p3, p4) - permutator = variations([a,b,c,d], 4) + permutator = variations([a, b, c, d], 4) base = template.subs(list(zip([p1, p2, p3, p4], next(permutator)))) for permut in permutator: subslist = list(zip([p1, p2, p3, p4], permut)) expr = template.subs(subslist) assert substitute_dummies(expr) == substitute_dummies(base) template = atv(p1, p2, p3, p4)*att(p1, p2, j, i)*att(i, j, p3, p4) - permutator = variations([a,b,c,d], 4) + permutator = variations([a, b, c, d], 4) base = template.subs(list(zip([p1, p2, p3, p4], next(permutator)))) for permut in permutator: subslist = list(zip([p1, p2, p3, p4], permut)) expr = template.subs(subslist) assert substitute_dummies(expr) == substitute_dummies(base) + def test_equivalent_internal_lines_VT2conjT2_ambiguous_order_AT(): # These diagrams invokes _determine_ambiguous() because the # dummies can not be ordered unambiguously by the key alone - i,j,k,l,m,n = symbols('i j k l m n',below_fermi=True, cls=Dummy) - a,b,c,d,e,f = symbols('a b c d e f',above_fermi=True, cls=Dummy) - p1,p2,p3,p4 = symbols('p1 p2 p3 p4',above_fermi=True, cls=Dummy) - h1,h2,h3,h4 = symbols('h1 h2 h3 h4',below_fermi=True, cls=Dummy) + i, j, k, l, m, n = symbols('i j k l m n', below_fermi=True, cls=Dummy) + a, b, c, d, e, f = symbols('a b c d e f', above_fermi=True, cls=Dummy) + p1, p2, p3, p4 = symbols('p1 p2 p3 p4', above_fermi=True, cls=Dummy) + h1, h2, h3, h4 = symbols('h1 h2 h3 h4', below_fermi=True, cls=Dummy) from sympy.utilities.iterables import variations - # atv(abcd)att(abij)att(cdij) template = atv(p1, p2, p3, p4)*att(p1, p2, i, j)*att(p3, p4, i, j) - permutator = variations([a,b,c,d], 4) + permutator = variations([a, b, c, d], 4) base = template.subs(list(zip([p1, p2, p3, p4], next(permutator)))) for permut in permutator: subslist = list(zip([p1, p2, p3, p4], permut)) expr = template.subs(subslist) assert substitute_dummies(expr) == substitute_dummies(base) template = atv(p1, p2, p3, p4)*att(p1, p2, j, i)*att(p3, p4, i, j) - permutator = variations([a,b,c,d], 4) + permutator = variations([a, b, c, d], 4) base = template.subs(list(zip([p1, p2, p3, p4], next(permutator)))) for permut in permutator: subslist = list(zip([p1, p2, p3, p4], permut)) expr = template.subs(subslist) assert substitute_dummies(expr) == substitute_dummies(base) + def test_equivalent_internal_lines_VT2_AT(): - i,j,k,l = symbols('i j k l',below_fermi=True, cls=Dummy) - a,b,c,d = symbols('a b c d',above_fermi=True, cls=Dummy) + i, j, k, l = symbols('i j k l', below_fermi=True, cls=Dummy) + a, b, c, d = symbols('a b c d', above_fermi=True, cls=Dummy) exprs = [ - # permute v. Same dummy order, not equivalent. - atv(i, j, a, b)*att(a, b, i, j), - atv(j, i, a, b)*att(a, b, i, j), - atv(i, j, b, a)*att(a, b, i, j), - ] + # permute v. Same dummy order, not equivalent. + atv(i, j, a, b)*att(a, b, i, j), + atv(j, i, a, b)*att(a, b, i, j), + atv(i, j, b, a)*att(a, b, i, j), + ] for permut in exprs[1:]: assert substitute_dummies(exprs[0]) != substitute_dummies(permut) exprs = [ - # permute t. - atv(i, j, a, b)*att(a, b, i, j), - atv(i, j, a, b)*att(b, a, i, j), - atv(i, j, a, b)*att(a, b, j, i), - ] + # permute t. + atv(i, j, a, b)*att(a, b, i, j), + atv(i, j, a, b)*att(b, a, i, j), + atv(i, j, a, b)*att(a, b, j, i), + ] for permut in exprs[1:]: assert substitute_dummies(exprs[0]) != substitute_dummies(permut) - exprs = [ # permute v and t. Relabelling of dummies should be equivalent. - atv(i, j, a, b)*att(a, b, i, j), - atv(j, i, a, b)*att(a, b, j, i), - atv(i, j, b, a)*att(b, a, i, j), - atv(j, i, b, a)*att(b, a, j, i), - ] + exprs = [ # permute v and t. Relabelling of dummies should be equivalent. + atv(i, j, a, b)*att(a, b, i, j), + atv(j, i, a, b)*att(a, b, j, i), + atv(i, j, b, a)*att(b, a, i, j), + atv(j, i, b, a)*att(b, a, j, i), + ] for permut in exprs[1:]: assert substitute_dummies(exprs[0]) == substitute_dummies(permut) + def test_internal_external_VT2T2_AT(): - ii, jj = symbols('i j',below_fermi=True) - aa, bb = symbols('a b',above_fermi=True) - k, l = symbols('k l' ,below_fermi=True, cls=Dummy) - c, d = symbols('c d' ,above_fermi=True, cls=Dummy) + ii, jj = symbols('i j', below_fermi=True) + aa, bb = symbols('a b', above_fermi=True) + k, l = symbols('k l', below_fermi=True, cls=Dummy) + c, d = symbols('c d', above_fermi=True, cls=Dummy) exprs = [ - atv(k,l,c,d)*att(aa, c, ii, k)*att(bb, d, jj, l), - atv(l,k,c,d)*att(aa, c, ii, l)*att(bb, d, jj, k), - atv(k,l,d,c)*att(aa, d, ii, k)*att(bb, c, jj, l), - atv(l,k,d,c)*att(aa, d, ii, l)*att(bb, c, jj, k), - ] + atv(k, l, c, d)*att(aa, c, ii, k)*att(bb, d, jj, l), + atv(l, k, c, d)*att(aa, c, ii, l)*att(bb, d, jj, k), + atv(k, l, d, c)*att(aa, d, ii, k)*att(bb, c, jj, l), + atv(l, k, d, c)*att(aa, d, ii, l)*att(bb, c, jj, k), + ] for permut in exprs[1:]: assert substitute_dummies(exprs[0]) == substitute_dummies(permut) exprs = [ - atv(k,l,c,d)*att(aa, c, ii, k)*att(d, bb, jj, l), - atv(l,k,c,d)*att(aa, c, ii, l)*att(d, bb, jj, k), - atv(k,l,d,c)*att(aa, d, ii, k)*att(c, bb, jj, l), - atv(l,k,d,c)*att(aa, d, ii, l)*att(c, bb, jj, k), - ] + atv(k, l, c, d)*att(aa, c, ii, k)*att(d, bb, jj, l), + atv(l, k, c, d)*att(aa, c, ii, l)*att(d, bb, jj, k), + atv(k, l, d, c)*att(aa, d, ii, k)*att(c, bb, jj, l), + atv(l, k, d, c)*att(aa, d, ii, l)*att(c, bb, jj, k), + ] for permut in exprs[1:]: assert substitute_dummies(exprs[0]) == substitute_dummies(permut) exprs = [ - atv(k,l,c,d)*att(c, aa, ii, k)*att(bb, d, jj, l), - atv(l,k,c,d)*att(c, aa, ii, l)*att(bb, d, jj, k), - atv(k,l,d,c)*att(d, aa, ii, k)*att(bb, c, jj, l), - atv(l,k,d,c)*att(d, aa, ii, l)*att(bb, c, jj, k), - ] + atv(k, l, c, d)*att(c, aa, ii, k)*att(bb, d, jj, l), + atv(l, k, c, d)*att(c, aa, ii, l)*att(bb, d, jj, k), + atv(k, l, d, c)*att(d, aa, ii, k)*att(bb, c, jj, l), + atv(l, k, d, c)*att(d, aa, ii, l)*att(bb, c, jj, k), + ] for permut in exprs[1:]: assert substitute_dummies(exprs[0]) == substitute_dummies(permut) + def test_internal_external_pqrs_AT(): ii, jj = symbols('i j') aa, bb = symbols('a b') - k, l = symbols('k l' , cls=Dummy) - c, d = symbols('c d' , cls=Dummy) - + k, l = symbols('k l', cls=Dummy) + c, d = symbols('c d', cls=Dummy) exprs = [ - atv(k,l,c,d)*att(aa, c, ii, k)*att(bb, d, jj, l), - atv(l,k,c,d)*att(aa, c, ii, l)*att(bb, d, jj, k), - atv(k,l,d,c)*att(aa, d, ii, k)*att(bb, c, jj, l), - atv(l,k,d,c)*att(aa, d, ii, l)*att(bb, c, jj, k), - ] + atv(k, l, c, d)*att(aa, c, ii, k)*att(bb, d, jj, l), + atv(l, k, c, d)*att(aa, c, ii, l)*att(bb, d, jj, k), + atv(k, l, d, c)*att(aa, d, ii, k)*att(bb, c, jj, l), + atv(l, k, d, c)*att(aa, d, ii, l)*att(bb, c, jj, k), + ] for permut in exprs[1:]: assert substitute_dummies(exprs[0]) == substitute_dummies(permut) diff -Nru python3-sympy-0.7.2/sympy/physics/tests/test_sho.py python3-sympy-0.7.3/sympy/physics/tests/test_sho.py --- python3-sympy-0.7.2/sympy/physics/tests/test_sho.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/physics/tests/test_sho.py 2013-07-13 17:53:32.000000000 +0000 @@ -2,6 +2,7 @@ from sympy.physics.sho import R_nl, E_nl from sympy import simplify + def test_sho_R_nl(): omega, r = symbols('omega r') l = symbols('l', integer=True) @@ -9,11 +10,12 @@ # check that it obeys the Schrodinger equation for n in range(5): - schreq = ( -diff(u(r), r, 2)/2 + ((l*(l+1))/(2*r**2) + schreq = ( -diff(u(r), r, 2)/2 + ((l*(l + 1))/(2*r**2) + omega**2*r**2/2 - E_nl(n, l, omega))*u(r) ) result = schreq.subs(u(r), r*R_nl(n, l, omega/2, r)) assert simplify(result.doit()) == 0 + def test_energy(): n, l, hw = symbols('n l hw') assert simplify(E_nl(n, l, hw) - (2*n + l + Rational(3, 2))*hw) == 0 diff -Nru python3-sympy-0.7.2/sympy/physics/tests/test_units.py python3-sympy-0.7.3/sympy/physics/tests/test_units.py --- python3-sympy-0.7.2/sympy/physics/tests/test_units.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/physics/tests/test_units.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,7 +1,8 @@ from sympy import integrate, Rational, sqrt, Symbol from sympy.physics.units import (au, amu, charge, day, find_unit, foot, km, m, meter, minute, s, - speed_of_light, grams) + speed_of_light, grams, quart, inch) + def test_units(): assert (5*m/s * day) / km == 432 @@ -17,12 +18,16 @@ assert (sqrt(m))**2 == m t = Symbol('t') - assert integrate(t*m/s,(t, 1*s, 5*s)) == 12*m*s + assert integrate(t*m/s, (t, 1*s, 5*s)) == 12*m*s assert (t * m/s).integrate((t, 1*s, 5*s)) == 12*m*s +def test_issue_quart(): + assert 4*quart/inch**3 == 231 + def test_issue_2466(): assert (m < s).is_Relational + def test_find_unit(): assert find_unit('charge') == ['charge'] assert find_unit(charge) == ['C', 'charge', 'coulomb', 'coulombs'] diff -Nru python3-sympy-0.7.2/sympy/physics/units.py python3-sympy-0.7.3/sympy/physics/units.py --- python3-sympy-0.7.2/sympy/physics/units.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/physics/units.py 2013-07-13 17:53:32.000000000 +0000 @@ -35,7 +35,7 @@ [] >>> u.gal = 4*u.quart >>> u.gal/u.inch**3 - 924 + 231 To see a given quantity in terms of some other unit, divide by the desired unit: @@ -76,6 +76,7 @@ from sympy import Rational, pi from sympy.core import AtomicExpr + class Unit(AtomicExpr): """ Base class for base unit of physical units. @@ -100,8 +101,8 @@ def __new__(cls, name, abbrev, **assumptions): obj = AtomicExpr.__new__(cls, **assumptions) - assert isinstance(name, str),repr(type(name)) - assert isinstance(abbrev, str),repr(type(abbrev)) + assert isinstance(name, str), repr(type(name)) + assert isinstance(abbrev, str), repr(type(abbrev)) obj.name = name obj.abbrev = abbrev return obj @@ -124,28 +125,28 @@ # Dimensionless -percent = percents = Rational(1,100) -permille = permille = Rational(1,1000) +percent = percents = Rational(1, 100) +permille = permille = Rational(1, 1000) ten = Rational(10) yotta = ten**24 zetta = ten**21 -exa = ten**18 -peta = ten**15 -tera = ten**12 -giga = ten**9 -mega = ten**6 -kilo = ten**3 -deca = ten**1 -deci = ten**-1 +exa = ten**18 +peta = ten**15 +tera = ten**12 +giga = ten**9 +mega = ten**6 +kilo = ten**3 +deca = ten**1 +deci = ten**-1 centi = ten**-2 milli = ten**-3 micro = ten**-6 -nano = ten**-9 -pico = ten**-12 +nano = ten**-9 +pico = ten**-12 femto = ten**-15 -atto = ten**-18 +atto = ten**-18 zepto = ten**-21 yocto = ten**-24 @@ -233,11 +234,9 @@ ug = microgram = micrograms = micro * g - #---------------------------------------------------------------------------- # Physical constants # - c = speed_of_light = 299792458 * m/s G = gravitational_constant = Rational('6.67428') * ten**-11 * m**3 / kg / s**2 u0 = magnetic_constant = 4*pi * ten**-7 * N/A**2 @@ -256,13 +255,13 @@ kPa = kilo*Pa bar = bars = 100*kPa -pound = pounds = 0.45359237 * kg * gee #exact +pound = pounds = 0.45359237 * kg * gee # exact psi = pound / inch ** 2 -dHg0 = 13.5951 # approx value at 0 C +dHg0 = 13.5951 # approx value at 0 C mmHg = dHg0 * 9.80665 * Pa amu = amus = gram / avogadro / mol mmu = mmus = gram / mol -quart = quarts = 231 * inch**3 +quart = quarts = Rational(231, 4) * inch**3 eV = 1.602176487e-19 * J # Other convenient units and magnitudes @@ -270,6 +269,7 @@ ly = lightyear = lightyears = c*julian_year au = astronomical_unit = astronomical_units = 149597870691*m + def find_unit(quantity): """ Return a list of matching units names. diff -Nru python3-sympy-0.7.2/sympy/physics/wigner.py python3-sympy-0.7.3/sympy/physics/wigner.py --- python3-sympy-0.7.2/sympy/physics/wigner.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/physics/wigner.py 2013-07-13 17:53:32.000000000 +0000 @@ -9,12 +9,16 @@ Please see the description of the individual functions for further details and examples. -REFERENCES: +References +~~~~~~~~~~ .. [Rasch03] J. Rasch and A. C. H. Yu, 'Efficient Storage Scheme for Pre-calculated Wigner 3j, 6j and Gaunt Coefficients', SIAM J. Sci. Comput. Volume 25, Issue 4, pp. 1416-1428 (2003) +Credits and Copyright +~~~~~~~~~~~~~~~~~~~~~ + This code was taken from Sage with the permission of all authors: http://groups.google.com/group/sage-devel/browse_thread/thread/33835976efbb3b7f @@ -33,7 +37,8 @@ # This list of precomputed factorials is needed to massively # accelerate future calculations of the various coefficients -_Factlist=[1] +_Factlist = [1] + def _calc_factlist(nn): r""" @@ -175,20 +180,20 @@ if (abs(m_1) > j_1) or (abs(m_2) > j_2) or (abs(m_3) > j_3): return 0 - maxfact = max(j_1 + j_2 + j_3 + 1, j_1 + abs(m_1), j_2 + abs(m_2), \ + maxfact = max(j_1 + j_2 + j_3 + 1, j_1 + abs(m_1), j_2 + abs(m_2), j_3 + abs(m_3)) _calc_factlist(int(maxfact)) - argsqrt = Integer(_Factlist[int(j_1 + j_2 - j_3)] * \ - _Factlist[int(j_1 - j_2 + j_3)] * \ - _Factlist[int(-j_1 + j_2 + j_3)] * \ - _Factlist[int(j_1 - m_1)] * \ - _Factlist[int(j_1 + m_1)] * \ - _Factlist[int(j_2 - m_2)] * \ - _Factlist[int(j_2 + m_2)] * \ - _Factlist[int(j_3 - m_3)] * \ - _Factlist[int(j_3 + m_3)]) / \ - _Factlist[int(j_1 + j_2 + j_3 + 1)] + argsqrt = Integer(_Factlist[int(j_1 + j_2 - j_3)] * + _Factlist[int(j_1 - j_2 + j_3)] * + _Factlist[int(-j_1 + j_2 + j_3)] * + _Factlist[int(j_1 - m_1)] * + _Factlist[int(j_1 + m_1)] * + _Factlist[int(j_2 - m_2)] * + _Factlist[int(j_2 + m_2)] * + _Factlist[int(j_3 - m_3)] * + _Factlist[int(j_3 + m_3)]) / \ + _Factlist[int(j_1 + j_2 + j_3 + 1)] ressqrt = sqrt(argsqrt) if ressqrt.is_complex: @@ -305,10 +310,10 @@ maxfact = max(aa + bb - cc, aa + cc - bb, bb + cc - aa, aa + bb + cc + 1) _calc_factlist(maxfact) - argsqrt = Integer(_Factlist[int(aa + bb - cc)] * \ - _Factlist[int(aa + cc - bb)] * \ - _Factlist[int(bb + cc - aa)]) / \ - Integer(_Factlist[int(aa + bb + cc + 1)]) + argsqrt = Integer(_Factlist[int(aa + bb - cc)] * + _Factlist[int(aa + cc - bb)] * + _Factlist[int(bb + cc - aa)]) / \ + Integer(_Factlist[int(aa + bb + cc + 1)]) ressqrt = sqrt(argsqrt) if prec: @@ -372,8 +377,8 @@ imin = max(aa + bb + ee, cc + dd + ee, aa + cc + ff, bb + dd + ff) imax = min(aa + bb + cc + dd, aa + dd + ee + ff, bb + cc + ee + ff) - maxfact = max(imax + 1, aa + bb + cc + dd, aa + dd + ee + ff, \ - bb + cc + ee + ff) + maxfact = max(imax + 1, aa + bb + cc + dd, aa + dd + ee + ff, + bb + cc + ee + ff) _calc_factlist(maxfact) sumres = 0 @@ -671,10 +676,11 @@ (4*pi) ressqrt = sqrt(argsqrt) - prefac = Integer(_Factlist[bigL] * _Factlist[l_2 - l_1 + l_3] * \ + prefac = Integer(_Factlist[bigL] * _Factlist[l_2 - l_1 + l_3] * _Factlist[l_1 - l_2 + l_3] * _Factlist[l_1 + l_2 - l_3])/ \ - _Factlist[2 * bigL+1]/ \ - (_Factlist[bigL - l_1] * _Factlist[bigL - l_2] * _Factlist[bigL - l_3]) + _Factlist[2 * bigL + 1]/ \ + (_Factlist[bigL - l_1] * + _Factlist[bigL - l_2] * _Factlist[bigL - l_3]) sumres = 0 for ii in range(imin, imax + 1): @@ -684,6 +690,6 @@ sumres = sumres + Integer((-1) ** ii) / den res = ressqrt * prefac * sumres * (-1) ** (bigL + l_3 + m_1 - m_2) - if prec != None: + if prec is not None: res = res.n(prec) return res diff -Nru python3-sympy-0.7.2/sympy/plotting/__init__.py python3-sympy-0.7.3/sympy/plotting/__init__.py --- python3-sympy-0.7.2/sympy/plotting/__init__.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/plotting/__init__.py 2013-07-13 17:53:32.000000000 +0000 @@ -4,4 +4,4 @@ from .textplot import textplot from .pygletplot import PygletPlot from .plot import (plot, plot_parametric, plot3d, plot3d_parametric_surface, - plot3d_parametric_line) + plot3d_parametric_line) diff -Nru python3-sympy-0.7.2/sympy/plotting/experimental_lambdify.py python3-sympy-0.7.3/sympy/plotting/experimental_lambdify.py --- python3-sympy-0.7.2/sympy/plotting/experimental_lambdify.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/plotting/experimental_lambdify.py 2013-07-13 17:53:32.000000000 +0000 @@ -70,11 +70,11 @@ # good. from sympy.external import import_module -np = import_module('numpy') import warnings #TODO debuging output + class vectorized_lambdify(object): """ Return a sufficiently smart, vectorized and lambdified function. @@ -108,20 +108,23 @@ self.failure = False def __call__(self, *args): + np = import_module('numpy') np_old_err = np.seterr(invalid='raise') try: temp_args = (np.array(a, dtype=np.complex) for a in args) results = self.vector_func(*temp_args) - results = np.ma.masked_where(np.abs(results.imag) != 0, results.real, copy=False) + results = np.ma.masked_where( + np.abs(results.imag) > 1e-7 * np.abs(results), + results.real, copy=False) except Exception as e: #DEBUG: print 'Error', type(e), e if ((isinstance(e, TypeError) - and 'unhashable type: \'numpy.ndarray\'' in str(e)) - or - (isinstance(e, ValueError) - and ('Invalid limits given:' in str(e) - or 'negative dimensions are not allowed' in str(e) #XXX - or 'sequence too large; must be smaller than 32' in str(e)))): #XXX + and 'unhashable type: \'numpy.ndarray\'' in str(e)) + or + (isinstance(e, ValueError) + and ('Invalid limits given:' in str(e) + or 'negative dimensions are not allowed' in str(e) # XXX + or 'sequence too large; must be smaller than 32' in str(e)))): # XXX # Almost all functions were translated to numpy, but some were # left as sympy functions. They recieved an ndarray as an # argument and failed. @@ -130,10 +133,14 @@ # other ugly exceptions that are not well understood (marked with XXX) # TODO: Cleanup the ugly special cases marked with xxx above. # Solution: use cmath and vectorize the final lambda. - self.lambda_func = experimental_lambdify(self.args, self.expr, use_python_cmath=True) - self.vector_func = np.vectorize(self.lambda_func, otypes=[np.complex]) + self.lambda_func = experimental_lambdify( + self.args, self.expr, use_python_cmath=True) + self.vector_func = np.vectorize( + self.lambda_func, otypes=[np.complex]) results = self.vector_func(*args) - results = np.ma.masked_where(np.abs(results.imag) != 0, results.real, copy=False) + results = np.ma.masked_where( + np.abs(results.imag) > 1e-7 * np.abs(results), + results.real, copy=False) else: # Complete failure. One last try with no translations, only # wrapping in complex((...).evalf()) and returning the real @@ -142,12 +149,15 @@ raise e else: self.failure = True - self.lambda_func = experimental_lambdify(self.args, self.expr, - use_evalf=True, - complex_wrap_evalf=True) - self.vector_func = np.vectorize(self.lambda_func, otypes=[np.complex]) + self.lambda_func = experimental_lambdify( + self.args, self.expr, use_evalf=True, + complex_wrap_evalf=True) + self.vector_func = np.vectorize( + self.lambda_func, otypes=[np.complex]) results = self.vector_func(*args) - results = np.ma.masked_where(np.abs(results.imag) != 0, results.real, copy=False) + results = np.ma.masked_where( + np.abs(results.imag) > 1e-7 * np.abs(results), + results.real, copy=False) warnings.warn('The evaluation of the expression is' ' problematic. We are trying a failback method' ' that may still work. Please report this as a bug.') @@ -156,6 +166,7 @@ return results + class lambdify(object): """Returns the lambdified function. @@ -169,7 +180,7 @@ self.args = args self.expr = expr self.lambda_func = experimental_lambdify(args, expr, use_evalf=True, - use_python_cmath=True) + use_python_cmath=True) self.failure = False def __call__(self, args): @@ -177,7 +188,7 @@ try: #The result can be sympy.Float. Hence wrap it with complex type. result = complex(self.lambda_func(args)) - if abs(result.imag) > 0: + if abs(result.imag) > 1e-7 * abs(result): return None else: return result.real @@ -185,13 +196,22 @@ # The exceptions raised by sympy, cmath are not consistent and # hence it is not possible to specify all the exceptions that # are to be caught. Presently there are no cases for which the code - # reaches this block other than ZeroDivisionError. Also the - # exception is caught only once. If the exception repeats itself, + # reaches this block other than ZeroDivisionError and complex + # comparision. Also the exception is caught only once. If the + # exception repeats itself, # then it is not caught and the corresponding error is raised. # XXX: Remove catching all exceptions once the plotting module # is heavily tested. if isinstance(e, ZeroDivisionError): return None + elif isinstance(e, TypeError) and ('no ordering relation is' + ' defined for complex numbers' + in str(e)): + self.lambda_func = experimental_lambdify(self.args, self.expr, + use_evalf=True, + use_python_math=True) + result = self.lambda_func(args.real) + return result else: if self.failure: raise e @@ -205,7 +225,7 @@ warnings.warn('The evaluation of the expression is' ' problematic. We are trying a failback method' ' that may still work. Please report this as a bug.') - if abs(result.imag) > 0: + if abs(result.imag) > 1e-7 * abs(result): return None else: return result.real @@ -217,14 +237,10 @@ class Lambdifier(object): - def __init__(self, args, expr, print_lambda=False, - use_evalf=False, - float_wrap_evalf=False, - complex_wrap_evalf=False, - use_np=False, - use_python_math=False, - use_python_cmath=False, - use_interval=False): + def __init__(self, args, expr, print_lambda=False, use_evalf=False, + float_wrap_evalf=False, complex_wrap_evalf=False, + use_np=False, use_python_math=False, use_python_cmath=False, + use_interval=False): self.print_lambda = print_lambda self.use_evalf = use_evalf @@ -258,45 +274,45 @@ namespace.update({'sqrt': sqrt}) # End workaround. if use_python_math: - namespace.update({'math' : __import__('math')}) + namespace.update({'math': __import__('math')}) if use_python_cmath: - namespace.update({'cmath' : __import__('cmath')}) + namespace.update({'cmath': __import__('cmath')}) if use_np: try: - namespace.update({'np' : __import__('numpy')}) + namespace.update({'np': __import__('numpy')}) except ImportError: - raise ImportError('experimental_lambdify failed to import numpy.') + raise ImportError( + 'experimental_lambdify failed to import numpy.') if use_interval: - namespace.update({'imath': __import__('sympy.plotting.intervalmath', fromlist=['intervalmath'])}) + namespace.update({'imath': __import__( + 'sympy.plotting.intervalmath', fromlist=['intervalmath'])}) + namespace.update({'math': __import__('math')}) # Construct the lambda if self.print_lambda: print(newexpr) - eval_str = 'lambda %s : ( %s )' %(argstr, newexpr) + eval_str = 'lambda %s : ( %s )' % (argstr, newexpr) exec("from __future__ import division; MYNEWLAMBDA = %s" % eval_str, namespace) self.lambda_func = namespace['MYNEWLAMBDA'] - ############################################################################## # Dicts for translating from sympy to other modules ############################################################################## - ### # builtins ### - # Functions with different names in builtins builtin_functions_different = { - 'Min':'min', - 'Max':'max', - 'Abs':'abs', - } + 'Min': 'min', + 'Max': 'max', + 'Abs': 'abs', + } # Strings that should be translated builtin_not_functions = { - 'I' :'1j', - 'oo':'1e400', - } + 'I': '1j', + 'oo': '1e400', + } ### # numpy @@ -304,39 +320,35 @@ # Functions that are the same in numpy numpy_functions_same = [ - 'sin', 'cos', 'tan', - 'sinh', 'cosh', 'tanh', - 'exp', 'log', - 'sqrt', - 'floor', - 'conjugate', - ] + 'sin', 'cos', 'tan', 'sinh', 'cosh', 'tanh', 'exp', 'log', + 'sqrt', 'floor', 'conjugate', + ] # Functions with different names in numpy numpy_functions_different = { - "acos":"arccos", - "acosh":"arccosh", - "arg":"angle", - "asin":"arcsin", - "asinh":"arcsinh", - "atan":"arctan", - "atan2":"arctan2", - "atanh":"arctanh", - "ceiling":"ceil", - "im":"imag", - "ln":"log", - "Max":"amax", - "Min":"amin", - "re":"real", - "Abs":"abs", - } + "acos": "arccos", + "acosh": "arccosh", + "arg": "angle", + "asin": "arcsin", + "asinh": "arcsinh", + "atan": "arctan", + "atan2": "arctan2", + "atanh": "arctanh", + "ceiling": "ceil", + "im": "imag", + "ln": "log", + "Max": "amax", + "Min": "amin", + "re": "real", + "Abs": "abs", + } # Strings that should be translated numpy_not_functions = { - 'pi':'np.pi', - 'oo':'np.inf', - 'E' :'np.e', - } + 'pi': 'np.pi', + 'oo': 'np.inf', + 'E': 'np.e', + } ### # python math @@ -344,28 +356,23 @@ # Functions that are the same in math math_functions_same = [ - 'sin', 'cos', 'tan', - 'asin', 'acos', 'atan', 'atan2', - 'sinh', 'cosh', 'tanh', - 'asinh', 'acosh', 'atanh', - 'exp', 'log', 'erf', - 'sqrt', - 'floor', - 'factorial', 'gamma', - ] + 'sin', 'cos', 'tan', 'asin', 'acos', 'atan', 'atan2', + 'sinh', 'cosh', 'tanh', 'asinh', 'acosh', 'atanh', + 'exp', 'log', 'erf', 'sqrt', 'floor', 'factorial', 'gamma', + ] # Functions with different names in math math_functions_different = { - 'ceiling':'ceil', - 'ln':'log', - 'loggamma':'lgamma' - } + 'ceiling': 'ceil', + 'ln': 'log', + 'loggamma': 'lgamma' + } # Strings that should be translated math_not_functions = { - 'pi':'math.pi', - 'E' :'math.e', - } + 'pi': 'math.pi', + 'E': 'math.e', + } ### # python cmath @@ -373,45 +380,45 @@ # Functions that are the same in cmath cmath_functions_same = [ - 'sin', 'cos', 'tan', - 'asin', 'acos', 'atan', - 'sinh', 'cosh', 'tanh', - 'asinh', 'acosh', 'atanh', - 'exp', 'log', - 'sqrt', - ] + 'sin', 'cos', 'tan', 'asin', 'acos', 'atan', + 'sinh', 'cosh', 'tanh', 'asinh', 'acosh', 'atanh', + 'exp', 'log', 'sqrt', + ] # Functions with different names in cmath cmath_functions_different = { - 'ln':'log', - 'arg':'phase', - } + 'ln': 'log', + 'arg': 'phase', + } # Strings that should be translated cmath_not_functions = { - 'pi':'cmath.pi', - 'E' :'cmath.e', - } + 'pi': 'cmath.pi', + 'E': 'cmath.e', + } + ### # intervalmath ### + interval_not_functions = { - 'pi':'cmath.pi', - 'E':'cmath.e' - } + 'pi': 'math.pi', + 'E': 'math.e' + } + interval_functions_same = [ - 'sin' , 'cos', 'exp', 'tan', 'atan', 'log', - 'sqrt','cosh', 'sinh', 'tanh', 'floor', - 'acos', 'asin', 'acosh', 'asinh', 'atanh', - 'Abs', 'And', 'Or' - ] + 'sin', 'cos', 'exp', 'tan', 'atan', 'log', + 'sqrt', 'cosh', 'sinh', 'tanh', 'floor', + 'acos', 'asin', 'acosh', 'asinh', 'atanh', + 'Abs', 'And', 'Or' + ] interval_functions_different = { - 'Min': 'imin', - 'Max': 'imax', - 'ceiling':'ceil', + 'Min': 'imin', + 'Max': 'imax', + 'ceiling': 'ceil', - } + } ### # mpmath, etc @@ -431,6 +438,8 @@ dict_str.update(self.math_not_functions) if self.use_python_cmath: dict_str.update(self.cmath_not_functions) + if self.use_interval: + dict_str.update(self.interval_not_functions) return dict_str # For functions @@ -438,24 +447,24 @@ dict_fun = dict(self.builtin_functions_different) if self.use_np: for s in self.numpy_functions_same: - dict_fun[s] = 'np.'+s + dict_fun[s] = 'np.' + s for k, v in self.numpy_functions_different.items(): - dict_fun[k] = 'np.'+v + dict_fun[k] = 'np.' + v if self.use_python_math: for s in self.math_functions_same: - dict_fun[s] = 'math.'+s + dict_fun[s] = 'math.' + s for k, v in self.math_functions_different.items(): - dict_fun[k] = 'math.'+v + dict_fun[k] = 'math.' + v if self.use_python_cmath: for s in self.cmath_functions_same: - dict_fun[s] = 'cmath.'+s + dict_fun[s] = 'cmath.' + s for k, v in self.cmath_functions_different.items(): - dict_fun[k] = 'cmath.'+v + dict_fun[k] = 'cmath.' + v if self.use_interval: for s in self.interval_functions_same: - dict_fun[s] = 'imath.'+s + dict_fun[s] = 'imath.' + s for k, v in self.interval_functions_different.items(): - dict_fun[k] = 'imath.'+v + dict_fun[k] = 'imath.' + v return dict_fun ############################################################################## @@ -598,9 +607,10 @@ # Either one of those can be used but not all at the same time. # The code considers the sin example as the right one. regexlist = [ - r'$', # the example Integral - r'$', # the example sqrt - ] + r'$', + # the example Integral + r'$', # the example sqrt + ] for r in regexlist: m = re.match(r, funcname) if m is not None: @@ -611,11 +621,11 @@ for a in expr.args: if (isinstance(a, Symbol) or isinstance(a, NumberSymbol) or - a in [I, zoo, oo]): + a in [I, zoo, oo]): continue else: args_dict.update(cls.sympy_expression_namespace(a)) - args_dict.update({funcname : expr.func}) + args_dict.update({funcname: expr.func}) return args_dict @staticmethod diff -Nru python3-sympy-0.7.2/sympy/plotting/intervalmath/__init__.py python3-sympy-0.7.3/sympy/plotting/intervalmath/__init__.py --- python3-sympy-0.7.2/sympy/plotting/intervalmath/__init__.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/plotting/intervalmath/__init__.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,4 +1,4 @@ from .interval_arithmetic import interval from .lib_interval import (Abs, exp, log, log10, atan, sin, cos, tan, sqrt, - imin, imax, sinh, cosh, tanh, acosh, asinh, atanh, - asin, acos, atan, ceil, floor, And, Or) + imin, imax, sinh, cosh, tanh, acosh, asinh, atanh, + asin, acos, atan, ceil, floor, And, Or) diff -Nru python3-sympy-0.7.2/sympy/plotting/intervalmath/interval_arithmetic.py python3-sympy-0.7.3/sympy/plotting/intervalmath/interval_arithmetic.py --- python3-sympy-0.7.2/sympy/plotting/intervalmath/interval_arithmetic.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/plotting/intervalmath/interval_arithmetic.py 2013-07-13 17:53:32.000000000 +0000 @@ -34,7 +34,6 @@ from sympy.external import import_module from sympy.simplify.simplify import nsimplify -np = import_module('numpy') class interval(object): @@ -81,7 +80,7 @@ self.end = float(args[0]) else: - raise ValueError("interval takes a maximum of two float values" + raise ValueError("interval takes a maximum of two float values " "as arguments") @property @@ -178,7 +177,7 @@ valid = True if self.start == other.start and self.end == other.end: return (False, valid) - if not self.__lt__(other)[0] == None: + if not self.__lt__(other)[0] is None: return (True, valid) return (None, valid) else: @@ -210,7 +209,7 @@ def __ge__(self, other): if isinstance(other, (int, float)): - if self.start >=other: + if self.start >= other: return (True, self.is_valid) elif self.end < other: return (False, self.is_valid) @@ -313,7 +312,6 @@ else: return NotImplemented - def __div__(self, other): # Both None and False are handled if not self.is_valid: @@ -368,7 +366,7 @@ if other < 0: return 1 / self.__pow__(abs(other)) else: - if int(other)==other: + if int(other) == other: return _pow_int(self, other) else: return _pow_float(self, other) @@ -400,6 +398,9 @@ else: return NotImplemented + def __hash__(self): + return hash((self.is_valid, self.start, self.end)) + def _pow_float(inter, power): """Evaluates an interval raised to a floating point.""" @@ -433,6 +434,7 @@ return interval(start, end, is_valid=inter.is_valid) + def _pow_int(inter, power): """Evaluates an interval raised to an integer power""" power = int(power) diff -Nru python3-sympy-0.7.2/sympy/plotting/intervalmath/lib_interval.py python3-sympy-0.7.3/sympy/plotting/intervalmath/lib_interval.py --- python3-sympy-0.7.2/sympy/plotting/intervalmath/lib_interval.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/plotting/intervalmath/lib_interval.py 2013-07-13 17:53:32.000000000 +0000 @@ -3,7 +3,7 @@ from functools import reduce """ The module contains implemented functions for interval arithmetic.""" -np = import_module('numpy') + def Abs(x): if isinstance(x, (int, float)): @@ -17,8 +17,11 @@ raise NotImplementedError #Monotonic + + def exp(x): """evaluates the exponential of an interval""" + np = import_module('numpy') if isinstance(x, (int, float)): return interval(np.exp(x), np.exp(x)) elif isinstance(x, interval): @@ -30,6 +33,7 @@ #Monotonic def log(x): """evaluates the natural logarithm of an interval""" + np = import_module('numpy') if isinstance(x, (int, float)): if x <= 0: return interval(-np.inf, np.inf, is_valid=False) @@ -51,6 +55,7 @@ #Monotonic def log10(x): """evaluates the logarithm to the base 10 of an interval""" + np = import_module('numpy') if isinstance(x, (int, float)): if x <= 0: return interval(-np.inf, np.inf, is_valid=False) @@ -71,6 +76,7 @@ #Monotonic def atan(x): """evaluates the tan inverse of an interval""" + np = import_module('numpy') if isinstance(x, (int, float)): return interval(np.arctan(x)) elif isinstance(x, interval): @@ -84,6 +90,7 @@ #periodic def sin(x): """evaluates the sine of an interval""" + np = import_module('numpy') if isinstance(x, (int, float)): return interval(np.sin(x)) elif isinstance(x, interval): @@ -112,6 +119,7 @@ #periodic def cos(x): """Evaluates the cos of an interval""" + np = import_module('numpy') if isinstance(x, (int, float)): return interval(np.sin(x)) elif isinstance(x, interval): @@ -147,6 +155,7 @@ #Monotonic def sqrt(x): """Evaluates the square root of an interval""" + np = import_module('numpy') if isinstance(x, (int, float)): if x > 0: return interval(np.sqrt(x)) @@ -168,6 +177,7 @@ def imin(*args): """Evaluates the minimum of a list of intervals""" + np = import_module('numpy') if not all(isinstance(arg, (int, float, interval)) for arg in args): return NotImplementedError else: @@ -179,15 +189,16 @@ else: return interval(-np.inf, np.inf, is_valid=None) start_array = [a if isinstance(a, (int, float)) else a.start - for a in new_args] + for a in new_args] end_array = [a if isinstance(a, (int, float)) else a.end - for a in new_args] + for a in new_args] return interval(min(start_array), min(end_array)) def imax(*args): """Evaluates the maximum of a list of intervals""" + np = import_module('numpy') if not all(isinstance(arg, (int, float, interval)) for arg in args): return NotImplementedError else: @@ -199,10 +210,10 @@ else: return interval(-np.inf, np.inf, is_valid=None) start_array = [a if isinstance(a, (int, float)) else a.start - for a in new_args] + for a in new_args] end_array = [a if isinstance(a, (int, float)) else a.end - for a in new_args] + for a in new_args] return interval(max(start_array), max(end_array)) @@ -210,6 +221,7 @@ #Monotonic def sinh(x): """Evaluates the hyperbolic sine of an interval""" + np = import_module('numpy') if isinstance(x, (int, float)): return interval(np.sinh(x), np.sinh(x)) elif isinstance(x, interval): @@ -220,6 +232,7 @@ def cosh(x): """Evaluates the hyperbolic cos of an interval""" + np = import_module('numpy') if isinstance(x, (int, float)): return interval(np.cosh(x), np.cosh(x)) elif isinstance(x, interval): @@ -239,6 +252,7 @@ #Monotonic def tanh(x): """Evaluates the hyperbolic tan of an interval""" + np = import_module('numpy') if isinstance(x, (int, float)): return interval(np.tanh(x), np.tanh(x)) elif isinstance(x, interval): @@ -249,6 +263,7 @@ def asin(x): """Evaluates the inverse sine of an interval""" + np = import_module('numpy') if isinstance(x, (int, float)): #Outside the domain if abs(x) > 1: @@ -257,7 +272,7 @@ return interval(np.arcsin(x), np.arcsin(x)) elif isinstance(x, interval): #Outside the domain - if x.is_valid is False or x.start > 1 or x.end < -1: + if x.is_valid is False or x.start > 1 or x.end < -1: return interval(-np.inf, np.inf, is_valid=False) #Partially outside the domain elif x.start < -1 or x.end > 1: @@ -270,6 +285,7 @@ def acos(x): """Evaluates the inverse cos of an interval""" + np = import_module('numpy') if isinstance(x, (int, float)): if abs(x) > 1: #Outside the domain @@ -278,7 +294,7 @@ return interval(np.arccos(x), np.arccos(x)) elif isinstance(x, interval): #Outside the domain - if x.is_valid is False or x.start > 1 or x.end < -1: + if x.is_valid is False or x.start > 1 or x.end < -1: return interval(-np.inf, np.inf, is_valid=False) #Partially outside the domain elif x.start < -1 or x.end > 1: @@ -291,6 +307,7 @@ def ceil(x): """Evaluates the ceiling of an interval""" + np = import_module('numpy') if isinstance(x, (int, float)): return interval(np.ceil(x)) elif isinstance(x, interval): @@ -311,6 +328,7 @@ def floor(x): """Evaluates the floor of an interval""" + np = import_module('numpy') if isinstance(x, (int, float)): return interval(np.floor(x)) elif isinstance(x, interval): @@ -331,6 +349,7 @@ def acosh(x): """Evaluates the inverse hyperbolic cosine of an interval""" + np = import_module('numpy') if isinstance(x, (int, float)): #Outside the domain if x < 1: @@ -355,6 +374,7 @@ #Monotonic def asinh(x): """Evaluates the inverse hyperbolic sine of an interval""" + np = import_module('numpy') if isinstance(x, (int, float)): return interval(np.arcsinh(x)) elif isinstance(x, interval): @@ -367,6 +387,7 @@ def atanh(x): """Evaluates the inverse hyperbolic tangent of an interval""" + np = import_module('numpy') if isinstance(x, (int, float)): #Outside the domain if abs(x) >= 1: @@ -375,7 +396,7 @@ return interval(np.arctanh(x)) elif isinstance(x, interval): #outside the domain - if x.is_valid is False or x.start >= 1 or x.end <= -1: + if x.is_valid is False or x.start >= 1 or x.end <= -1: return interval(-np.inf, np.inf, is_valid=False) #partly outside the domain elif x.start <= -1 or x.end >= 1: diff -Nru python3-sympy-0.7.2/sympy/plotting/intervalmath/tests/test_interval_functions.py python3-sympy-0.7.3/sympy/plotting/intervalmath/tests/test_interval_functions.py --- python3-sympy-0.7.2/sympy/plotting/intervalmath/tests/test_interval_functions.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/plotting/intervalmath/tests/test_interval_functions.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,25 +1,32 @@ -from sympy.plotting.intervalmath import * + from sympy.external import import_module +from sympy.plotting.intervalmath import ( + Abs, acos, acosh, And, asin, asinh, atan, atanh, ceil, cos, cosh, + exp, floor, imax, imin, interval, log, log10, Or, sin, sinh, sqrt, + tan, tanh, +) np = import_module('numpy') if not np: disabled = True #requires Numpy. Hence included in interval_functions + + def test_interval_pow(): a = 2**interval(1, 2) == interval(2, 4) assert a == (True, True) a = interval(1, 2)**interval(1, 2) == interval(1, 4) assert a == (True, True) a = interval(-1, 1)**interval(0.5, 2) - assert a.is_valid == None + assert a.is_valid is None a = interval(-2, -1) ** interval(1, 2) - assert a.is_valid == False + assert a.is_valid is False a = interval(-2, -1) ** (1 / 2) - assert a.is_valid == False + assert a.is_valid is False a = interval(-1, 1)**(1 / 2) - assert a.is_valid == None + assert a.is_valid is None a = interval(-1, 1)**(1 / 3) == interval(-1, 1) assert a == (True, True) a = interval(-1, 1)**2 == interval(0, 1) @@ -30,20 +37,22 @@ assert a == (True, True) a = interval(1, 2, is_valid=False)**2 - assert a.is_valid == False + assert a.is_valid is False a = (-3)**interval(1, 2) - assert a.is_valid == False + assert a.is_valid is False a = (-4)**interval(0.5, 0.5) - assert a.is_valid == False + assert a.is_valid is False assert ((-3)**interval(1, 1) == interval(-3, -3)) == (True, True) a = interval(8, 64)**(2 / 3) - assert abs(a.start - 4) < 1e-10 #eps + assert abs(a.start - 4) < 1e-10 # eps assert abs(a.end - 16) < 1e-10 a = interval(-8, 64)**(2 / 3) - assert abs(a.start - 4) < 1e-10 #eps + assert abs(a.start - 4) < 1e-10 # eps assert abs(a.end - 16) < 1e-10 + + def test_exp(): a = exp(interval(-np.inf, 0)) assert a.start == np.exp(-np.inf) @@ -70,6 +79,7 @@ assert a.start == np.log(2) assert a.end == np.log(2) + def test_log10(): a = log10(interval(1, 2)) assert a.start == 0 @@ -85,7 +95,6 @@ assert a.end == np.log10(2) - def test_atan(): a = atan(interval(0, 1)) assert a.start == np.arctan(0) @@ -125,7 +134,7 @@ assert a.end == np.sin(np.pi / 4) a = sin(interval(1, 2, is_valid=False)) - assert a.is_valid == False + assert a.is_valid is False def test_cos(): @@ -154,7 +163,7 @@ assert a.end == 1 a = cos(interval(1, 2, is_valid=False)) - assert a.is_valid == False + assert a.is_valid is False def test_tan(): @@ -275,8 +284,7 @@ assert a.end == np.arcsin(0.5) a = asin(1.5) - assert a.is_valid == False - + assert a.is_valid is False def test_acos(): @@ -300,7 +308,7 @@ assert a.end == np.arccos(0.5) a = acos(1.5) - assert a.is_valid == False + assert a.is_valid is False def test_ceil(): @@ -360,7 +368,7 @@ assert a.is_valid is False a = acosh(0.5) - assert a.is_valid == False + assert a.is_valid is False a = acosh(2) assert a.start == np.arccosh(2) diff -Nru python3-sympy-0.7.2/sympy/plotting/intervalmath/tests/test_intervalmath.py python3-sympy-0.7.3/sympy/plotting/intervalmath/tests/test_intervalmath.py --- python3-sympy-0.7.2/sympy/plotting/intervalmath/tests/test_intervalmath.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/plotting/intervalmath/tests/test_intervalmath.py 2013-07-13 17:53:32.000000000 +0000 @@ -2,6 +2,8 @@ from sympy.plotting.intervalmath import interval from sympy.utilities.pytest import raises from sympy.external import import_module + + def test_interval(): assert (interval(1, 1) == interval(1, 1, is_valid=True)) == (True, True) assert (interval(1, 1) == interval(1, 1, is_valid=False)) == (True, False) @@ -12,7 +14,8 @@ assert (interval(1, 2) != interval(1, 2)) == (False, True) assert (interval(1, 3) != interval(2, 3)) == (None, True) assert (interval(1, 3) != interval(-5, -3)) == (True, True) - assert (interval(1, 3, is_valid=False) != interval(-5, -3)) == (True, False) + assert ( + interval(1, 3, is_valid=False) != interval(-5, -3)) == (True, False) assert (interval(1, 3, is_valid=None) != interval(-5, 3)) == (None, None) assert (interval(4, 4) != 4) == (False, True) assert (interval(1, 1) == 1) == (True, True) @@ -34,7 +37,8 @@ assert interval(0, float('inf')) in interb assert interval(-float('inf'), 5) in interb assert interval(-1e50, 1e50) in interb - assert (-interval(-1, -2, is_valid=False) == interval(1, 2)) == (True, False) + assert ( + -interval(-1, -2, is_valid=False) == interval(1, 2)) == (True, False) raises(ValueError, lambda: interval(1, 2, 3)) @@ -45,15 +49,15 @@ compare = (1 + interval(0, float('inf')) == interval(1, float('inf'))) assert compare == (True, True) a = 1 + interval(2, 5, is_valid=False) - assert a.is_valid == False + assert a.is_valid is False a = 1 + interval(2, 5, is_valid=None) - assert a.is_valid == None + assert a.is_valid is None a = interval(2, 5, is_valid=False) + interval(3, 5, is_valid=None) - assert a.is_valid == False + assert a.is_valid is False a = interval(3, 5) + interval(-1, 1, is_valid=None) - assert a.is_valid == None + assert a.is_valid is None a = interval(2, 5, is_valid=False) + 1 - assert a.is_valid == False + assert a.is_valid is False def test_interval_sub(): @@ -61,13 +65,13 @@ assert (interval(1, 2) - 1 == interval(0, 1)) == (True, True) assert (1 - interval(1, 2) == interval(-1, 0)) == (True, True) a = 1 - interval(1, 2, is_valid=False) - assert a.is_valid == False + assert a.is_valid is False a = interval(1, 4, is_valid=None) - 1 assert a.is_valid is None a = interval(1, 3, is_valid=False) - interval(1, 3) - assert a.is_valid == False + assert a.is_valid is False a = interval(1, 3, is_valid=None) - interval(1, 3) - assert a.is_valid == None + assert a.is_valid is None def test_interval_inequality(): @@ -78,7 +82,8 @@ assert (interval(1, 2) <= interval(1.5, 6)) == (None, True) assert (interval(2, 3) <= interval(1, 2)) == (None, True) assert (interval(2, 3) <= interval(1, 1.5)) == (False, True) - assert (interval(1, 2, is_valid=False) <= interval(-2, 0)) == (False, False) + assert ( + interval(1, 2, is_valid=False) <= interval(-2, 0)) == (False, False) assert (interval(1, 2, is_valid=None) <= interval(-2, 0)) == (False, None) assert (interval(1, 2) <= 1.5) == (None, True) assert (interval(1, 2) <= 3) == (True, True) @@ -113,7 +118,8 @@ def test_interval_mul(): - assert (interval(1, 5) * interval(2, 10) == interval(2, 50)) == (True, True) + assert ( + interval(1, 5) * interval(2, 10) == interval(2, 50)) == (True, True) a = interval(-1, 1) * interval(2, 10) == interval(-10, 10) assert a == (True, True) @@ -143,14 +149,14 @@ div = 3 / interval(1, 2, is_valid=None) assert div == interval(-float('inf'), float('inf'), is_valid=None) a = interval(1, 2) / 0 - assert a.is_valid == False + assert a.is_valid is False a = interval(0.5, 1) / interval(-1, 0) - assert a.is_valid == None + assert a.is_valid is None a = interval(0, 1) / interval(0, 1) - assert a.is_valid == None + assert a.is_valid is None a = interval(-1, 1) / interval(-1, 1) - assert a.is_valid == None + assert a.is_valid is None a = interval(-1, 2) / interval(0.5, 1) == interval(-2.0, 4.0) assert a == (True, True) @@ -185,4 +191,19 @@ a = interval(-4, -0.5) / interval(-2, -0.5) == interval(0.25, 8.0) assert a == (True, True) a = interval(-5, 5, is_valid=False) / 2 - assert a.is_valid == False + assert a.is_valid is False + +def test_hashable(): + ''' + test that interval objects are hashable. + this is required in order to be able to put them into the cache, which + appears to be necessary for plotting in py3k. For details, see: + + https://github.com/sympy/sympy/pull/2101 + https://code.google.com/p/sympy/issues/detail?id=3434 + ''' + hash(interval(1, 1)) + hash(interval(1, 1, is_valid=True)) + hash(interval(-4, -0.5)) + hash(interval(-2, -0.5)) + hash(interval(0.25, 8.0)) diff -Nru python3-sympy-0.7.2/sympy/plotting/plot.py python3-sympy-0.7.3/sympy/plotting/plot.py --- python3-sympy-0.7.2/sympy/plotting/plot.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/plotting/plot.py 2013-07-13 17:53:32.000000000 +0000 @@ -27,44 +27,32 @@ from sympy import sympify, Expr, Tuple, Dummy from sympy.external import import_module from sympy.core.compatibility import set_union +from sympy.utilities.decorator import doctest_depends_on import warnings from .experimental_lambdify import (vectorized_lambdify, lambdify) -import collections -#TODO probably all of the imports after this line can be put inside function to -# speed up the `from sympy import *` command. -np = import_module('numpy') - -# Backend specific imports - matplotlib -matplotlib = import_module('matplotlib', - __import__kwargs={'fromlist':['pyplot', 'cm', 'collections']}, - min_module_version='1.0.0', catch=(RuntimeError,)) -if matplotlib: - plt = matplotlib.pyplot - cm = matplotlib.cm - LineCollection = matplotlib.collections.LineCollection - mpl_toolkits = import_module('mpl_toolkits', - __import__kwargs={'fromlist':['mplot3d']}) - Axes3D = mpl_toolkits.mplot3d.Axes3D - art3d = mpl_toolkits.mplot3d.art3d - ListedColormap = matplotlib.colors.ListedColormap +# N.B. +# When changing the minimum module version for matplotlib, please change +# the same in the `SymPyDocTestFinder`` in `sympy/utilities/runtests.py` # Backend specific imports - textplot from sympy.plotting.textplot import textplot +import collections # Global variable -# Set to False when running tests / doctests so that the plots don't -# show. -_show=True +# Set to False when running tests / doctests so that the plots don't show. +_show = True + def unset_show(): global _show - _show=False + _show = False ############################################################################## # The public interface ############################################################################## + class Plot(object): """The central class of the plotting module. @@ -201,14 +189,14 @@ def __str__(self): series_strs = [('[%d]: ' % i) + str(s) - for i, s in enumerate(self._series)] + for i, s in enumerate(self._series)] return 'Plot object containing:\n' + '\n'.join(series_strs) def __getitem__(self, index): return self._series[index] def __setitem__(self, index, *args): - if len(args)==1 and isinstance(args[0], BaseSeries): + if len(args) == 1 and isinstance(args[0], BaseSeries): self._series[index] = args def __delitem__(self, index): @@ -332,8 +320,9 @@ self.line_color = None def get_segments(self): + np = import_module('numpy') points = self.get_points() - if self.steps == True: + if self.steps is True: x = np.array((points[0], points[0])).T.flatten()[1:] y = np.array((points[1], points[1])).T.flatten()[:-1] points = (x, y) @@ -341,6 +330,7 @@ return np.ma.concatenate([points[:-1], points[1:]], axis=1) def get_color_array(self): + np = import_module('numpy') c = self.line_color if hasattr(c, '__call__'): f = np.vectorize(c) @@ -354,7 +344,7 @@ return f(variables[0]) elif arity == 2: return f(*variables[:2]) - else: # only if the line is 3D (otherwise raises an error) + else: # only if the line is 3D (otherwise raises an error) return f(*variables) else: return c*np.ones(self.nb_of_points) @@ -364,6 +354,7 @@ """Representation for a line consisting of list of points.""" def __init__(self, list_x, list_y): + np = import_module('numpy') super(List2DSeries, self).__init__() self.list_x = np.array(list_x) self.list_y = np.array(list_y) @@ -391,12 +382,9 @@ self.depth = kwargs.get('depth', 12) self.line_color = kwargs.get('line_color', None) - def __str__(self): return 'cartesian line: %s for %s over %s' % ( - str(self.expr), - str(self.var), - str((self.start, self.end))) + str(self.expr), str(self.var), str((self.start, self.end))) def get_segments(self): """ @@ -417,12 +405,14 @@ else: f = lambdify([self.var], self.expr) list_segments = [] + def sample(p, q, depth): """ Samples recursively if three points are almost collinear. For depth < 6, points are added irrespective of whether they satisfy the collinearity condition or not. The maximum depth allowed is 12. """ + np = import_module('numpy') #Randomly sample to avoid aliasing. random = 0.45 + np.random.rand() * 0.1 xnew = p[0] + random * (q[0] - p[0]) @@ -447,13 +437,14 @@ yarray = list(map(f, xarray)) if any(y is not None for y in yarray): for i in len(yarray) - 1: - if yarray[i] is None or yarray[i + 1] is None: + if yarray[i] is not None or yarray[i + 1] is not None: sample([xarray[i], yarray[i]], [xarray[i + 1], yarray[i + 1]], depth + 1) #Sample further if one of the end points in None( i.e. a complex #value) or the three points are not almost collinear. - elif p[1] is None or q[1] is None or not flat(p, new_point, q): + elif (p[1] is None or q[1] is None or new_point[1] is None + or not flat(p, new_point, q)): sample(p, new_point, depth + 1) sample(new_point, q, depth + 1) else: @@ -465,9 +456,10 @@ return list_segments def get_points(self): - if self.only_integers == True: + np = import_module('numpy') + if self.only_integers is True: list_x = np.linspace(int(self.start), int(self.end), - num=int(self.end)-int(self.start)+1) + num=int(self.end) - int(self.start) + 1) else: list_x = np.linspace(self.start, self.end, num=self.nb_of_points) f = vectorized_lambdify([self.var], self.expr) @@ -496,12 +488,11 @@ def __str__(self): return 'parametric cartesian line: (%s, %s) for %s over %s' % ( - str(self.expr_x), - str(self.expr_y), - str(self.var), - str((self.start, self.end))) + str(self.expr_x), str(self.expr_y), str(self.var), + str((self.start, self.end))) def get_parameter_points(self): + np = import_module('numpy') return np.linspace(self.start, self.end, num=self.nb_of_points) def get_points(self): @@ -532,6 +523,7 @@ f_x = lambdify([self.var], self.expr_x) f_y = lambdify([self.var], self.expr_y) list_segments = [] + def sample(param_p, param_q, p, q, depth): """ Samples recursively if three points are almost collinear. For depth < 6, points are added irrespective of whether they @@ -539,6 +531,7 @@ allowed is 12. """ #Randomly sample to avoid aliasing. + np = import_module('numpy') random = 0.45 + np.random.rand() * 0.1 param_new = param_p + random * (param_q - param_p) xnew = f_x(param_new) @@ -567,11 +560,11 @@ for x, y in zip(x_array, y_array)): for i in len(y_array) - 1: if ((x_array[i] is not None and y_array[i] is not None) or - (x_array[i+1] is not None and y_array[i] is not None)): + (x_array[i + 1] is not None and y_array[i + 1] is not None)): point_a = [x_array[i], y_array[i]] point_b = [x_array[i + 1], y_array[i + 1]] sample(param_array[i], param_array[i], point_a, - point_b, depth + 1) + point_b, depth + 1) #Sample further if one of the end points in None( ie a complex #value) or the three points are not almost collinear. @@ -625,13 +618,11 @@ def __str__(self): return '3D parametric cartesian line: (%s, %s, %s) for %s over %s' % ( - str(self.expr_x), - str(self.expr_y), - str(self.expr_z), - str(self.var), - str((self.start, self.end))) + str(self.expr_x), str(self.expr_y), str(self.expr_z), + str(self.var), str((self.start, self.end))) def get_parameter_points(self): + np = import_module('numpy') return np.linspace(self.start, self.end, num=self.nb_of_points) def get_points(self): @@ -656,6 +647,7 @@ self.surface_color = None def get_color_array(self): + np = import_module('numpy') c = self.surface_color if isinstance(c, collections.Callable): f = np.vectorize(c) @@ -696,13 +688,14 @@ def __str__(self): return ('cartesian surface: %s for' ' %s over %s and %s over %s') % ( - str(self.expr), - str(self.var_x), - str((self.start_x, self.end_x)), - str(self.var_y), - str((self.start_y, self.end_y))) + str(self.expr), + str(self.var_x), + str((self.start_x, self.end_x)), + str(self.var_y), + str((self.start_y, self.end_y))) def get_meshes(self): + np = import_module('numpy') mesh_x, mesh_y = np.meshgrid(np.linspace(self.start_x, self.end_x, num=self.nb_of_points_x), np.linspace(self.start_y, self.end_y, @@ -717,8 +710,9 @@ is_parametric = True - def __init__(self, expr_x, expr_y, expr_z, var_start_end_u, var_start_end_v, - **kwargs): + def __init__( + self, expr_x, expr_y, expr_z, var_start_end_u, var_start_end_v, + **kwargs): super(ParametricSurfaceSeries, self).__init__() self.expr_x = sympify(expr_x) self.expr_y = sympify(expr_y) @@ -736,15 +730,16 @@ def __str__(self): return ('parametric cartesian surface: (%s, %s, %s) for' ' %s over %s and %s over %s') % ( - str(self.expr_x), - str(self.expr_y), - str(self.expr_z), - str(self.var_u), - str((self.start_u, self.end_u)), - str(self.var_v), - str((self.start_v, self.end_v))) + str(self.expr_x), + str(self.expr_y), + str(self.expr_z), + str(self.var_u), + str((self.start_u, self.end_u)), + str(self.var_v), + str((self.start_v, self.end_v))) def get_parameter_meshes(self): + np = import_module('numpy') return np.meshgrid(np.linspace(self.start_u, self.end_u, num=self.nb_of_points_u), np.linspace(self.start_v, self.end_v, @@ -784,13 +779,14 @@ def __str__(self): return ('contour: %s for ' '%s over %s and %s over %s') % ( - str(self.expr), - str(self.var_x), - str((self.start_x, self.end_x)), - str(self.var_y), - str((self.start_y, self.end_y))) + str(self.expr), + str(self.var_x), + str((self.start_x, self.end_x)), + str(self.var_y), + str((self.start_y, self.end_y))) def get_meshes(self): + np = import_module('numpy') mesh_x, mesh_y = np.meshgrid(np.linspace(self.start_x, self.end_x, num=self.nb_of_points_x), np.linspace(self.start_y, self.end_y, @@ -809,14 +805,22 @@ self.parent = parent +## don't have to check for the success of importing matplotlib in each case; +## we will only be using this backend if we can successfully import matploblib class MatplotlibBackend(BaseBackend): def __init__(self, parent): super(MatplotlibBackend, self).__init__(parent) are_3D = [s.is_3D for s in self.parent._series] + self.matplotlib = import_module('matplotlib', + __import__kwargs={'fromlist': ['pyplot', 'cm', 'collections']}, + min_module_version='1.1.0', catch=(RuntimeError,)) + self.plt = self.matplotlib.pyplot + self.cm = self.matplotlib.cm + self.LineCollection = self.matplotlib.collections.LineCollection if any(are_3D) and not all(are_3D): raise ValueError('The matplotlib backend can not mix 2D and 3D.') elif not any(are_3D): - self.fig = plt.figure() + self.fig = self.plt.figure() self.ax = self.fig.add_subplot(111) self.ax.spines['left'].set_position('zero') self.ax.spines['right'].set_color('none') @@ -827,7 +831,11 @@ self.ax.xaxis.set_ticks_position('bottom') self.ax.yaxis.set_ticks_position('left') elif all(are_3D): - self.fig = plt.figure() + ## mpl_toolkits.mplot3d is necessary for + ## projection='3d' + mpl_toolkits = import_module('mpl_toolkits', + __import__kwargs={'fromlist': ['mplot3d']}) + self.fig = self.plt.figure() self.ax = self.fig.add_subplot(111, projection='3d') def process_series(self): @@ -836,12 +844,15 @@ for s in self.parent._series: # Create the collections if s.is_2Dline: - collection = LineCollection(s.get_segments()) + collection = self.LineCollection(s.get_segments()) self.ax.add_collection(collection) elif s.is_contour: self.ax.contour(*s.get_meshes()) elif s.is_3Dline: # TODO too complicated, I blame matplotlib + mpl_toolkits = import_module('mpl_toolkits', + __import__kwargs={'fromlist': ['mplot3d']}) + art3d = mpl_toolkits.mplot3d.art3d collection = art3d.Line3DCollection(s.get_segments()) self.ax.add_collection(collection) x, y, z = s.get_points() @@ -850,7 +861,7 @@ self.ax.set_zlim((min(z), max(z))) elif s.is_3Dsurface: x, y, z = s.get_meshes() - collection = self.ax.plot_surface(x, y, z, cmap=cm.jet, + collection = self.ax.plot_surface(x, y, z, cmap=self.cm.jet, rstride=1, cstride=1, linewidth=0.1) elif s.is_implicit: @@ -866,6 +877,7 @@ # use contourf or contour depending on whether it is # an inequality or equality. #XXX: ``contour`` plots multiple lines. Should be fixed. + ListedColormap = self.matplotlib.colors.ListedColormap colormap = ListedColormap(["white", "blue"]) xarray, yarray, zarray, plot_type = points if plot_type == 'contour': @@ -889,7 +901,7 @@ else: collection.set_color(s.line_color) if s.is_3Dsurface and s.surface_color: - if matplotlib.__version__ < "1.2.0": #TODO in the distant future remove this check + if self.matplotlib.__version__ < "1.2.0": # TODO in the distant future remove this check warnings.warn('The version of matplotlib is too old to use surface coloring.') elif isinstance(s.surface_color, (float, int)) or isinstance(s.surface_color, collections.Callable): color_array = s.get_color_array() @@ -901,15 +913,19 @@ # Set global options. # TODO The 3D stuff # XXX The order of those is important. + + mpl_toolkits = import_module('mpl_toolkits', + __import__kwargs={'fromlist': ['mplot3d']}) + Axes3D = mpl_toolkits.mplot3d.Axes3D if parent.xscale and not isinstance(self.ax, Axes3D): self.ax.set_xscale(parent.xscale) - if parent.yscale and not isinstance(self.ax, Axes3D): + if parent.yscale and not isinstance(self.ax, Axes3D): self.ax.set_yscale(parent.yscale) if parent.xlim: self.ax.set_xlim(parent.xlim) if parent.ylim: self.ax.set_ylim(parent.ylim) - if not isinstance(self.ax, Axes3D) or matplotlib.__version__ >= '1.2.0': #XXX in the distant future remove this check + if not isinstance(self.ax, Axes3D) or self.matplotlib.__version__ >= '1.2.0': # XXX in the distant future remove this check self.ax.set_autoscale_on(parent.autoscale) if parent.axis_center: val = parent.axis_center @@ -949,14 +965,14 @@ # you can uncomment the next line and remove the pyplot.show() call #self.fig.show() if _show: - plt.show() + self.plt.show() def save(self, path): self.process_series() self.fig.savefig(path) def close(self): - plt.close(self.fig) + self.plt.close(self.fig) class TextBackend(BaseBackend): @@ -965,9 +981,11 @@ def show(self): if len(self.parent._series) != 1: - raise ValueError('The TextBackend supports only one graph per Plot.') + raise ValueError( + 'The TextBackend supports only one graph per Plot.') elif not isinstance(self.parent._series[0], LineOver1DRangeSeries): - raise ValueError('The TextBackend supports only expressions over a 1D range') + raise ValueError( + 'The TextBackend supports only expressions over a 1D range') else: ser = self.parent._series[0] textplot(ser.expr, ser.start, ser.end) @@ -978,6 +996,7 @@ class DefaultBackend(BaseBackend): def __new__(cls, parent): + matplotlib = import_module('matplotlib', min_module_version='1.1.0', catch=(RuntimeError,)) if matplotlib: return MatplotlibBackend(parent) else: @@ -985,10 +1004,10 @@ plot_backends = { - 'matplotlib' : MatplotlibBackend, - 'text' : TextBackend, - 'default': DefaultBackend - } + 'matplotlib': MatplotlibBackend, + 'text': TextBackend, + 'default': DefaultBackend +} ############################################################################## @@ -996,17 +1015,22 @@ ############################################################################## def centers_of_segments(array): + np = import_module('numpy') return np.average(np.vstack((array[:-1], array[1:])), 0) + def centers_of_faces(array): + np = import_module('numpy') return np.average(np.dstack((array[:-1, :-1], - array[1: , :-1], + array[1:, :-1], array[:-1, 1: ], array[:-1, :-1], )), 2) + def flat(x, y, z, eps=1e-3): """Checks whether three points are almost collinear""" + np = import_module('numpy') vector_a = x - y vector_b = z - y dot_product = np.dot(vector_a, vector_b) @@ -1015,6 +1039,7 @@ cos_theta = dot_product / (vector_a_norm * vector_b_norm) return abs(cos_theta + 1) < eps + def _matplotlib_list(interval_list): """ Returns lists for matplotlib ``fill`` command from a list of bounding @@ -1027,9 +1052,9 @@ intervalx = intervals[0] intervaly = intervals[1] xlist.extend([intervalx.start, intervalx.start, - intervalx.end, intervalx.end, None]) + intervalx.end, intervalx.end, None]) ylist.extend([intervaly.start, intervaly.end, - intervaly.end, intervaly.start, None]) + intervaly.end, intervaly.start, None]) else: #XXX Ugly hack. Matplotlib does not accept empty lists for ``fill`` xlist.extend([None, None, None, None]) @@ -1043,6 +1068,7 @@ # TODO: Add more plotting options for 3d plots. # TODO: Adaptive sampling for 3D plots. +@doctest_depends_on(modules=('numpy', 'matplotlib',)) def plot(*args, **kwargs): """ Plots a function of a single variable. @@ -1135,19 +1161,31 @@ Single Plot - >>> plot(x**2, (x, -5, 5))# doctest: +SKIP + >>> plot(x**2, (x, -5, 5)) + Plot object containing: + [0]: cartesian line: x**2 for x over (-5.0, 5.0) Multiple plots with single range. - >>> plot(x, x**2, x**3, (x, -5, 5))# doctest: +SKIP + >>> plot(x, x**2, x**3, (x, -5, 5)) + Plot object containing: + [0]: cartesian line: x for x over (-5.0, 5.0) + [1]: cartesian line: x**2 for x over (-5.0, 5.0) + [2]: cartesian line: x**3 for x over (-5.0, 5.0) + Multiple plots with different ranges. - >>> plot((x**2, (x, -6, 6)), (x, (x, -5, 5)))# doctest: +SKIP + >>> plot((x**2, (x, -6, 6)), (x, (x, -5, 5))) + Plot object containing: + [0]: cartesian line: x**2 for x over (-6.0, 6.0) + [1]: cartesian line: x for x over (-5.0, 5.0) No adaptive sampling. - >>> plot(x**2, adaptive=False, nb_of_points=400)# doctest: +SKIP + >>> plot(x**2, adaptive=False, nb_of_points=400) + Plot object containing: + [0]: cartesian line: x**2 for x over (-10.0, 10.0) See Also ======== @@ -1155,7 +1193,7 @@ Plot, LineOver1DRangeSeries. """ - args = sympify([arg for arg in args]) + args = list(map(sympify, args)) show = kwargs.pop('show', True) series = [] plot_expr = check_arguments(args, 1, 1) @@ -1167,6 +1205,7 @@ return plots +@doctest_depends_on(modules=('numpy', 'matplotlib',)) def plot_parametric(*args, **kwargs): """ Plots a 2D parametric plot. @@ -1244,8 +1283,8 @@ ``yscale``: {'linear', 'log'} Sets the scaling if the y - axis. - ``axis_center``: tuple of two floats denoting the coordinates of the center or - {'center', 'auto'} + ``axis_center``: tuple of two floats denoting the coordinates of the center + or {'center', 'auto'} ``xlim`` : tuple of two floats, denoting the x - axis limits. @@ -1253,28 +1292,40 @@ Examples ======== + >>> from sympy import symbols, cos, sin >>> from sympy.plotting import plot_parametric >>> u = symbols('u') Single Parametric plot - >>> plot_parametric(cos(u), sin(u), (u, -5, 5))# doctest: +SKIP + >>> plot_parametric(cos(u), sin(u), (u, -5, 5)) + Plot object containing: + [0]: parametric cartesian line: (cos(u), sin(u)) for u over (-5.0, 5.0) + Multiple parametric plot with single range. - >>> plot_parametric((cos(u), sin(u)), (u, cos(u)))# doctest: +SKIP + >>> plot_parametric((cos(u), sin(u)), (u, cos(u))) + Plot object containing: + [0]: parametric cartesian line: (cos(u), sin(u)) for u over (-10.0, 10.0) + [1]: parametric cartesian line: (u, cos(u)) for u over (-10.0, 10.0) Multiple parametric plots. - >>> plot_parametric((cos(u), sin(u), (u, -5, 5)), (cos(u), u, (u, -5, 5)))# doctest: +SKIP + >>> plot_parametric((cos(u), sin(u), (u, -5, 5)), + ... (cos(u), u, (u, -5, 5))) + Plot object containing: + [0]: parametric cartesian line: (cos(u), sin(u)) for u over (-5.0, 5.0) + [1]: parametric cartesian line: (cos(u), u) for u over (-5.0, 5.0) + See Also ======== Plot, Parametric2DLineSeries """ - args = sympify([arg for arg in args]) + args = list(map(sympify, args)) show = kwargs.pop('show', True) series = [] plot_expr = check_arguments(args, 2, 1) @@ -1284,6 +1335,8 @@ plots.show() return plots + +@doctest_depends_on(modules=('numpy', 'matplotlib',)) def plot3d_parametric_line(*args, **kwargs): """ Plots a 3D parametric line plot. @@ -1348,11 +1401,19 @@ Single plot. - >>> plot3d_parametric_line(cos(u), sin(u), u, (u, -5, 5))# doctest: +SKIP + >>> plot3d_parametric_line(cos(u), sin(u), u, (u, -5, 5)) + Plot object containing: + [0]: 3D parametric cartesian line: (cos(u), sin(u), u) for u over (-5.0, 5.0) + Multiple plots. - >>> plot3d_parametric_line((cos(u), sin(u), u, (u, -5, 5)), (sin(u), u**2, u, (u, -5, 5)))# doctest: +SKIP + >>> plot3d_parametric_line((cos(u), sin(u), u, (u, -5, 5)), + ... (sin(u), u**2, u, (u, -5, 5))) + Plot object containing: + [0]: 3D parametric cartesian line: (cos(u), sin(u), u) for u over (-5.0, 5.0) + [1]: 3D parametric cartesian line: (sin(u), u**2, u) for u over (-5.0, 5.0) + See Also ======== @@ -1360,7 +1421,7 @@ Plot, Parametric3DLineSeries """ - args = sympify([arg for arg in args]) + args = list(map(sympify, args)) show = kwargs.pop('show', True) series = [] plot_expr = check_arguments(args, 3, 1) @@ -1370,6 +1431,8 @@ plots.show() return plots + +@doctest_depends_on(modules=('numpy', 'matplotlib',)) def plot3d(*args, **kwargs): """ Plots a 3D surface plot. @@ -1442,15 +1505,27 @@ Single plot - >>> plot3d(x*y, (x, -5, 5), (y, -5, 5)) # doctest: +SKIP + >>> plot3d(x*y, (x, -5, 5), (y, -5, 5)) + Plot object containing: + [0]: cartesian surface: x*y for x over (-5.0, 5.0) and y over (-5.0, 5.0) + Multiple plots with same range - >>> plot3d(x*y, -x*y, (x, -5, 5), (y, -5, 5))# doctest: +SKIP + >>> plot3d(x*y, -x*y, (x, -5, 5), (y, -5, 5)) + Plot object containing: + [0]: cartesian surface: x*y for x over (-5.0, 5.0) and y over (-5.0, 5.0) + [1]: cartesian surface: -x*y for x over (-5.0, 5.0) and y over (-5.0, 5.0) + Multiple plots with different ranges. - >>> plot3d((x**2 + y**2, (x, -5, 5), (y, -5, 5)), (x*y, (x, -3, 3), (y, -3, 3)))# doctest: +SKIP + >>> plot3d((x**2 + y**2, (x, -5, 5), (y, -5, 5)), + ... (x*y, (x, -3, 3), (y, -3, 3))) + Plot object containing: + [0]: cartesian surface: x**2 + y**2 for x over (-5.0, 5.0) and y over (-5.0, 5.0) + [1]: cartesian surface: x*y for x over (-3.0, 3.0) and y over (-3.0, 3.0) + See Also ======== @@ -1458,7 +1533,7 @@ """ - args = sympify([arg for arg in args]) + args = list(map(sympify, args)) show = kwargs.pop('show', True) series = [] plot_expr = check_arguments(args, 1, 2) @@ -1469,6 +1544,7 @@ return plots +@doctest_depends_on(modules=('numpy', 'matplotlib',)) def plot3d_parametric_surface(*args, **kwargs): """ Plots a 3D parametric surface plot. @@ -1540,7 +1616,11 @@ Single plot. - >>> plot3d_parametric_surface(cos(u + v), sin(u - v), u - v, (u, -5, 5), (v, -5, 5)) # doctest: +SKIP + >>> plot3d_parametric_surface(cos(u + v), sin(u - v), u - v, + ... (u, -5, 5), (v, -5, 5)) + Plot object containing: + [0]: parametric cartesian surface: (cos(u + v), sin(u - v), u - v) for u over (-5.0, 5.0) and v over (-5.0, 5.0) + See Also ======== @@ -1548,7 +1628,7 @@ """ - args = sympify([arg for arg in args]) + args = list(map(sympify, args)) show = kwargs.pop('show', True) series = [] plot_expr = check_arguments(args, 3, 2) @@ -1558,6 +1638,7 @@ plots.show() return plots + def check_arguments(args, expr_len, nb_of_free_symbols): """ Checks the arguments and converts into tuples of the @@ -1600,8 +1681,8 @@ return plots if isinstance(args[0], Expr) or (isinstance(args[0], Tuple) and - len(args[0]) == expr_len and - expr_len != 3): + len(args[0]) == expr_len and + expr_len != 3): # Cannot handle expressions with number of expression = 3. It is # not possible to differentiate between expressions and ranges. #Series of plots with same range @@ -1619,10 +1700,11 @@ for e in expr])) if len(free_symbols) > nb_of_free_symbols: - raise ValueError("The number of free_symbols in the expression" - "is greater than %d" % nb_of_free_symbols) + raise ValueError("The number of free_symbols in the expression " + "is greater than %d" % nb_of_free_symbols) if len(args) == i + nb_of_free_symbols and isinstance(args[i], Tuple): - ranges = Tuple(*[range_expr for range_expr in args[i:i + nb_of_free_symbols]]) + ranges = Tuple(*[range_expr for range_expr in args[ + i:i + nb_of_free_symbols]]) plots = [expr + ranges for expr in exprs] return plots else: @@ -1644,9 +1726,9 @@ for i in range(expr_len): if not isinstance(arg[i], Expr): raise ValueError("Expected an expression, given %s" % - str(arg[i])) + str(arg[i])) for i in range(nb_of_free_symbols): if not len(arg[i + expr_len]) == 3: - raise ValueError("The ranges should be a tuple of" + raise ValueError("The ranges should be a tuple of " "length 3, got %s" % str(arg[i + expr_len])) return args diff -Nru python3-sympy-0.7.2/sympy/plotting/plot_implicit.py python3-sympy-0.7.3/sympy/plotting/plot_implicit.py --- python3-sympy-0.7.2/sympy/plotting/plot_implicit.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/plotting/plot_implicit.py 2013-07-13 17:53:32.000000000 +0000 @@ -29,14 +29,13 @@ from .intervalmath import interval from sympy.core.relational import (Equality, GreaterThan, LessThan, Relational, StrictLessThan, StrictGreaterThan) -from sympy import Eq, Tuple, sympify, Expr, Dummy +from sympy import Eq, Tuple, sympify, Dummy from sympy.external import import_module from sympy.core.compatibility import set_union from sympy.logic.boolalg import BooleanFunction +from sympy.utilities.decorator import doctest_depends_on import warnings -np = import_module('numpy') - class ImplicitSeries(BaseSeries): """ Representation for Implicit plot """ @@ -53,7 +52,7 @@ self.start_y = float(var_start_end_y[1]) self.end_y = float(var_start_end_y[2]) self.get_points = self.get_raster - self.has_equality = has_equality #If the expression has equality, i.e. + self.has_equality = has_equality # If the expression has equality, i.e. #Eq, Greaterthan, LessThan. self.nb_of_points = nb_of_points self.use_interval_math = use_interval_math @@ -62,11 +61,11 @@ def __str__(self): return ('Implicit equation: %s for ' '%s over %s and %s over %s') % ( - str(self.expr), - str(self.var_x), - str((self.start_x, self.end_x)), - str(self.var_y), - str((self.start_y, self.end_y))) + str(self.expr), + str(self.var_x), + str((self.start_x, self.end_x)), + str(self.var_y), + str((self.start_y, self.end_y))) def get_raster(self): func = experimental_lambdify((self.var_x, self.var_y), self.expr, @@ -91,19 +90,24 @@ k = self.depth interval_list = [] #Create initial 32 divisions + np = import_module('numpy') xsample = np.linspace(self.start_x, self.end_x, 33) ysample = np.linspace(self.start_y, self.end_y, 33) #Add a small jitter so that there are no false positives for equality. # Ex: y==x becomes True for x interval(1, 2) and y interval(1, 2) #which will draw a rectangle. - jitterx = (np.random.rand(len(xsample)) * 2 - 1) * (self.end_x - self.start_x) / 2**20 - jittery = (np.random.rand(len(ysample)) * 2 - 1) * (self.end_y - self.start_y) / 2**20 + jitterx = (np.random.rand( + len(xsample)) * 2 - 1) * (self.end_x - self.start_x) / 2**20 + jittery = (np.random.rand( + len(ysample)) * 2 - 1) * (self.end_y - self.start_y) / 2**20 xsample += jitterx ysample += jittery - xinter = [interval(x1, x2) for x1, x2 in zip(xsample[:-1], xsample[1:])] - yinter = [interval(y1, y2) for y1, y2 in zip(ysample[:-1], ysample[1:])] + xinter = [interval(x1, x2) for x1, x2 in zip(xsample[:-1], + xsample[1:])] + yinter = [interval(y1, y2) for y1, y2 in zip(ysample[:-1], + ysample[1:])] interval_list = [[x, y] for x in xinter for y in yinter] plot_list = [] @@ -174,22 +178,24 @@ elif isinstance(self.expr, (LessThan, StrictLessThan)): expr = self.expr.rhs - self.expr.lhs else: - raise NotImplementedError("The expression is not supported for" + raise NotImplementedError("The expression is not supported for " "plotting in uniform meshed plot.") + np = import_module('numpy') xarray = np.linspace(self.start_x, self.end_x, self.nb_of_points) yarray = np.linspace(self.start_y, self.end_y, self.nb_of_points) x_grid, y_grid = np.meshgrid(xarray, yarray) func = vectorized_lambdify((self.var_x, self.var_y), expr) z_grid = func(x_grid, y_grid) - z_grid[np.ma.where(z_grid<0)] = -1 - z_grid[np.ma.where(z_grid>0)] = 1 + z_grid[np.ma.where(z_grid < 0)] = -1 + z_grid[np.ma.where(z_grid > 0)] = 1 if equal: return xarray, yarray, z_grid, 'contour' else: return xarray, yarray, z_grid, 'contourf' +@doctest_depends_on(modules=('matplotlib',)) def plot_implicit(expr, *args, **kwargs): """A plot function to plot implicit equations / inequalities. @@ -231,40 +237,43 @@ Plot expressions: - >>> from sympy import plot_implicit, cos, sin, symbols, Eq + >>> from sympy import plot_implicit, cos, sin, symbols, Eq, And >>> x, y = symbols('x y') Without any ranges for the symbols in the expression - >>> p1 = plot_implicit(Eq(x**2 + y**2, 5)) #doctest: +SKIP + >>> p1 = plot_implicit(Eq(x**2 + y**2, 5)) With the range for the symbols - >>> p2 = plot_implicit(Eq(x**2 + y**2, 3), (x, -3, 3), (y, -3, 3)) #doctest: +SKIP + >>> p2 = plot_implicit(Eq(x**2 + y**2, 3), + ... (x, -3, 3), (y, -3, 3)) With depth of recursion as argument. - >>> p3 = plot_implicit(Eq(x**2 + y**2, 5), (x, -4, 4), (y, -4, 4), depth = 2) #doctest: +SKIP + >>> p3 = plot_implicit(Eq(x**2 + y**2, 5), + ... (x, -4, 4), (y, -4, 4), depth = 2) Using mesh grid and not using adaptive meshing. - >>> p4 = plot_implicit(Eq(x**2 + y**2, 5), (x, -5, 5), (y, -2, 2), adaptive=False) #doctest: +SKIP + >>> p4 = plot_implicit(Eq(x**2 + y**2, 5), + ... (x, -5, 5), (y, -2, 2), adaptive=False) Using mesh grid with number of points as input. - >>> p5 = plot_implicit(Eq(x**2 + y**2, 5), (x, -5, 5), (y, -2, 2), adaptive=False, points=400) #doctest: +SKIP + >>> p5 = plot_implicit(Eq(x**2 + y**2, 5), + ... (x, -5, 5), (y, -2, 2), + ... adaptive=False, points=400) Plotting regions. - >>> p6 = plot_implicit(y > x**2) #doctest: +SKIP + >>> p6 = plot_implicit(y > x**2) Plotting Using boolean conjunctions. - >>> p7 = plot_implicit(And(y > x, y > -x)) #doctest: +SKIP + >>> p7 = plot_implicit(And(y > x, y > -x)) """ - - assert isinstance(expr, Expr) - has_equality = False #Represents whether the expression contains an Equality, + has_equality = False # Represents whether the expression contains an Equality, #GreaterThan or LessThan def arg_expand(bool_expr): @@ -283,7 +292,7 @@ #Check whether there is an equality in the expression provided. if any(isinstance(e, (Equality, GreaterThan, LessThan)) - for e in arg_list): + for e in arg_list): has_equality = True elif not isinstance(expr, Relational): @@ -297,7 +306,7 @@ symbols = set_union(free_symbols, range_symbols) if len(symbols) > 2: raise NotImplementedError("Implicit plotting is not implemented for " - "more than 2 variables") + "more than 2 variables") #Create default ranges if the range is not provided. default_range = Tuple(-5, 5) diff -Nru python3-sympy-0.7.2/sympy/plotting/proxy_pyglet.py python3-sympy-0.7.3/sympy/plotting/proxy_pyglet.py --- python3-sympy-0.7.2/sympy/plotting/proxy_pyglet.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/plotting/proxy_pyglet.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,7 +1,7 @@ -from warnings import warn from sympy.utilities.exceptions import SymPyDeprecationWarning from .pygletplot import PygletPlot + def Plot(*args, **kwargs): """ A temporary proxy for an interface under deprecation. @@ -25,7 +25,7 @@ change. The new location is sympy.plotting.pygletplot. """ SymPyDeprecationWarning(value="This interface will change in future " - "versions of SymPy. As a precatuion use the plot() function " + "versions of SymPy. As a precaution use the plot() function " "(lowercase), or use sympy.plotting.pygletplot.PygletPlot to " "continue using Pyglet. See the docstring of this function for " "details.", feature="Plot as an interface to Pyglet", diff -Nru python3-sympy-0.7.2/sympy/plotting/pygletplot/__init__.py python3-sympy-0.7.3/sympy/plotting/pygletplot/__init__.py --- python3-sympy-0.7.2/sympy/plotting/pygletplot/__init__.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/plotting/pygletplot/__init__.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,18 +1,24 @@ """Plotting module that can plot 2D and 3D functions """ + +from sympy.utilities.decorator import doctest_depends_on + try: + @doctest_depends_on(modules=('pyglet',)) def PygletPlot(*args, **kwargs): """ Plot Examples ============= - See examples/plotting.py for many more examples. + See examples/advanced/pyglet_plotting.py for many more examples. - >>> from sympy import symbols, Plot + >>> from sympy.plotting.pygletplot import PygletPlot as Plot + >>> from sympy import symbols >>> from sympy.abc import x, y, z >>> Plot(x*y**3-y*x**3) + [0]: -x**3*y + x*y**3, 'mode=cartesian' >>> p = Plot() >>> p[1] = x*y @@ -31,13 +37,21 @@ from the defaults for the current coordinate mode: >>> Plot(x**2) # implies [x,-5,5,100] + [0]: x**2, 'mode=cartesian' + >>> Plot(x**2, [], []) # [x,-1,1,40], [y,-1,1,40] + [0]: x**2, 'mode=cartesian' >>> Plot(x**2-y**2, [100], [100]) # [x,-1,1,100], [y,-1,1,100] + [0]: x**2 - y**2, 'mode=cartesian' >>> Plot(x**2, [x,-13,13,100]) + [0]: x**2, 'mode=cartesian' >>> Plot(x**2, [-13,13]) # [x,-13,13,100] + [0]: x**2, 'mode=cartesian' >>> Plot(x**2, [x,-13,13]) # [x,-13,13,100] + [0]: x**2, 'mode=cartesian' >>> Plot(1*x, [], [x], mode='cylindrical') ... # [unbound_theta,0,2*Pi,40], [x,-1,1,20] + [0]: x, 'mode=cartesian' Coordinate Modes @@ -62,7 +76,7 @@ 1: parametric, cartesian, polar 2: parametric, cartesian, cylindrical = polar, spherical - >>> Plot(1, mode='spherical') + >>> Plot(1, mode='spherical') # doctest: +SKIP Calculator-like Interface @@ -72,8 +86,8 @@ >>> f = x**2 >>> p[1] = f >>> p[2] = f.diff(x) - >>> p[3] = f.diff(x).diff(x) - >>> p + >>> p[3] = f.diff(x).diff(x) # doctest: +SKIP + >>> p # doctest: +SKIP [1]: x**2, 'mode=cartesian' [2]: 2*x, 'mode=cartesian' [3]: 2, 'mode=cartesian' diff -Nru python3-sympy-0.7.2/sympy/plotting/pygletplot/color_scheme.py python3-sympy-0.7.3/sympy/plotting/pygletplot/color_scheme.py --- python3-sympy-0.7.2/sympy/plotting/pygletplot/color_scheme.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/plotting/pygletplot/color_scheme.py 2013-07-13 17:53:32.000000000 +0000 @@ -4,6 +4,7 @@ from sympy.core.compatibility import callable import collections + class ColorGradient(object): colors = [0.4, 0.4, 0.4], [0.9, 0.9, 0.9] intervals = 0.0, 1.0 @@ -27,20 +28,21 @@ def _find_interval(self, v): m = len(self.intervals) i = 0 - while i < m-1 and self.intervals[i] <= v: + while i < m - 1 and self.intervals[i] <= v: i += 1 return i def _interpolate_axis(self, axis, v): i = self._find_interval(v) - v = rinterpolate(self.intervals[i-1], self.intervals[i], v) - return interpolate(self.colors[i-1][axis], self.colors[i][axis], v) + v = rinterpolate(self.intervals[i - 1], self.intervals[i], v) + return interpolate(self.colors[i - 1][axis], self.colors[i][axis], v) def __call__(self, r, g, b): c = self._interpolate_axis return c(0, r), c(1, g), c(2, b) -default_color_schemes = {} # defined at the bottom of this file +default_color_schemes = {} # defined at the bottom of this file + class ColorScheme(object): @@ -170,7 +172,7 @@ # when vars are given explicitly, any vars # not given are marked 'unbound' as to not # be accidentally used in an expression - vars = [Symbol('unbound%i'%(i)) for i in range(1,6)] + vars = [Symbol('unbound%i' % (i)) for i in range(1, 6)] # interpret as t if len(args) == 1: vars[3] = args[0] @@ -219,7 +221,7 @@ except AssertionError as ae: raise ValueError("Color function needs to return 3-tuple r,g,b.") except Exception as ie: - pass # color function probably not valid at 0,0,0,0,0 + pass # color function probably not valid at 0,0,0,0,0 def __call__(self, x, y, z, u, v): try: @@ -328,9 +330,9 @@ 1.00, (1.0, 0.2, 0.2)]) default_color_schemes['zfade4'] = ColorScheme(z, (None, None, z), - [0.0, (0.3, 0.3, 1.0), + [0.0, (0.3, 0.3, 1.0), 0.30, (0.3, 1.0, 0.3), - 0.55, (0.95,1.0, 0.2), - 0.65, (1.0,0.95, 0.2), + 0.55, (0.95, 1.0, 0.2), + 0.65, (1.0, 0.95, 0.2), 0.85, (1.0, 0.7, 0.2), - 1.0, (1.0, 0.3, 0.2)]) + 1.0, (1.0, 0.3, 0.2)]) diff -Nru python3-sympy-0.7.2/sympy/plotting/pygletplot/managed_window.py python3-sympy-0.7.3/sympy/plotting/pygletplot/managed_window.py --- python3-sympy-0.7.2/sympy/plotting/pygletplot/managed_window.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/plotting/pygletplot/managed_window.py 2013-07-13 17:53:32.000000000 +0000 @@ -6,6 +6,7 @@ gl_lock = Lock() + class ManagedWindow(Window): """ A pyglet window with an event loop which executes automatically @@ -24,8 +25,13 @@ class, unless you need to take additional arguments. Do any OpenGL initialization calls in setup(). """ + + # check if this is run from the doctester + if win_args.get('runfromdoctester', False): + return + self.win_args = dict(self.default_win_args, **win_args) - self.Thread=Thread(target=self.__event_loop__) + self.Thread = Thread(target=self.__event_loop__) self.Thread.start() def __event_loop__(self, **win_args): diff -Nru python3-sympy-0.7.2/sympy/plotting/pygletplot/plot.py python3-sympy-0.7.3/sympy/plotting/pygletplot/plot.py --- python3-sympy-0.7.2/sympy/plotting/pygletplot/plot.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/plotting/pygletplot/plot.py 2013-07-13 17:53:32.000000000 +0000 @@ -22,18 +22,22 @@ from sympy.geometry.entity import GeometryEntity + +from sympy.utilities.decorator import doctest_depends_on, no_attrs_in_subclass + class PygletPlot(object): """ Plot Examples ============= - See examples/plotting.py for many more examples. + See examples/advaned/pyglet_plotting.py for many more examples. - >>> from sympy import Plot + >>> from sympy.plotting.pygletplot import PygletPlot as Plot >>> from sympy.abc import x, y, z >>> Plot(x*y**3-y*x**3) + [0]: -x**3*y + x*y**3, 'mode=cartesian' >>> p = Plot() >>> p[1] = x*y @@ -52,13 +56,20 @@ from the defaults for the current coordinate mode: >>> Plot(x**2) # implies [x,-5,5,100] + [0]: x**2, 'mode=cartesian' >>> Plot(x**2, [], []) # [x,-1,1,40], [y,-1,1,40] + [0]: x**2, 'mode=cartesian' >>> Plot(x**2-y**2, [100], [100]) # [x,-1,1,100], [y,-1,1,100] + [0]: x**2 - y**2, 'mode=cartesian' >>> Plot(x**2, [x,-13,13,100]) + [0]: x**2, 'mode=cartesian' >>> Plot(x**2, [-13,13]) # [x,-13,13,100] - >>> Plot(x**2, [x,-13,13]) # [x,-13,13,100] + [0]: x**2, 'mode=cartesian' + >>> Plot(x**2, [x,-13,13]) # [x,-13,13,10] + [0]: x**2, 'mode=cartesian' >>> Plot(1*x, [], [x], mode='cylindrical') ... # [unbound_theta,0,2*Pi,40], [x,-1,1,20] + [0]: x, 'mode=cartesian' Coordinate Modes @@ -83,7 +94,7 @@ 1: parametric, cartesian, polar 2: parametric, cartesian, cylindrical = polar, spherical - >>> Plot(1, mode='spherical') + >>> Plot(1, mode='spherical') # doctest: +SKIP Calculator-like Interface @@ -93,8 +104,8 @@ >>> f = x**2 >>> p[1] = f >>> p[2] = f.diff(x) - >>> p[3] = f.diff(x).diff(x) - >>> p + >>> p[3] = f.diff(x).diff(x) # doctest: +SKIP + >>> p # doctest: +SKIP [1]: x**2, 'mode=cartesian' [2]: 2*x, 'mode=cartesian' [3]: 2, 'mode=cartesian' @@ -143,7 +154,10 @@ ============================= """ + #python 2.5 does not support class decorators so use this workaround + _doctest_depends_on = {'modules': ('pyglet',)} + @doctest_depends_on(modules=('pyglet',)) def __init__(self, *fargs, **win_args): """ Positional Arguments @@ -153,6 +167,7 @@ initialize a plot function at index 1. In other words... + >>> from sympy.plotting.pygletplot import PygletPlot as Plot >>> from sympy.core import Symbol >>> from sympy.abc import x >>> p = Plot(x**2, visible=False) @@ -241,6 +256,10 @@ else: self._win_args['visible'] = True self.axes.reset_resources() + + if hasattr(self, '_doctest_depends_on'): + self._win_args['runfromdoctester'] = True + self._window = PlotWindow(self, **self._win_args) def close(self): @@ -296,7 +315,7 @@ if (not is_sequence(args)) or isinstance(args, GeometryEntity): args = [args] if len(args) == 0: - return # no arguments given + return # no arguments given kwargs = dict(bounds_callback=self.adjust_all_bounds) f = PlotMode(*args, **kwargs) @@ -362,7 +381,7 @@ else: self._render_lock.acquire() s += "\n".join(["%s[%i]: %s" % ("", i, str(self._functions[i])) - for i in self._functions]) + for i in self._functions]) self._render_lock.release() return s @@ -382,7 +401,9 @@ while a() or b(): sleep(0) self._render_lock.release() - +#python 2.5 does not support class decorators so use this workaround +PygletPlot._doctest_depends_on = no_attrs_in_subclass( + PygletPlot, PygletPlot._doctest_depends_on) class ScreenShot: def __init__(self, plot): @@ -399,7 +420,7 @@ return 0 def _execute_saving(self): - if self.flag <3: + if self.flag < 3: self.flag += 1 return @@ -417,7 +438,6 @@ if self.invisibleMode: self._plot._window.close() - def save(self, outfile=None, format='', size=(600, 500)): self.outfile = outfile self.format = format diff -Nru python3-sympy-0.7.2/sympy/plotting/pygletplot/plot_axes.py python3-sympy-0.7.3/sympy/plotting/pygletplot/plot_axes.py --- python3-sympy-0.7.2/sympy/plotting/pygletplot/plot_axes.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/plotting/pygletplot/plot_axes.py 2013-07-13 17:53:32.000000000 +0000 @@ -8,6 +8,7 @@ from sympy.core import S from sympy.core.compatibility import is_sequence + class PlotAxes(PlotObject): def __init__(self, *args, **kwargs): @@ -53,9 +54,9 @@ def flexible_boolean(input, default): if input in [True, False]: return input - if input in ['f','F','false','False']: + if input in ['f', 'F', 'false', 'False']: return False - if input in ['t','T','true','True']: + if input in ['t', 'T', 'true', 'True']: return True return default @@ -63,8 +64,10 @@ self.visible = flexible_boolean(kwargs.pop('visible', ''), True) self._overlay = flexible_boolean(kwargs.pop('overlay', ''), True) self._colored = flexible_boolean(kwargs.pop('colored', ''), False) - self._label_axes = flexible_boolean(kwargs.pop('label_axes', ''), False) - self._label_ticks = flexible_boolean(kwargs.pop('label_ticks', ''), True) + self._label_axes = flexible_boolean( + kwargs.pop('label_axes', ''), False) + self._label_ticks = flexible_boolean( + kwargs.pop('label_ticks', ''), True) # setup label font self.font_face = kwargs.pop('font_face', 'Arial') @@ -79,7 +82,7 @@ def reset_bounding_box(self): self._bounding_box = [[None, None], [None, None], [None, None]] - self._axis_ticks = [[],[],[]] + self._axis_ticks = [[], [], []] def draw(self): if self._render_object: @@ -113,6 +116,7 @@ def toggle_colors(self): self._colored = not self._colored + class PlotAxesBase(PlotObject): def __init__(self, parent_axes): @@ -127,7 +131,7 @@ self.draw_axis(0, color[0]) def draw_background(self, color): - pass # optional + pass # optional def draw_axis(self, axis, color): raise NotImplementedError() @@ -159,10 +163,11 @@ o = self._p._origin glBegin(GL_LINES) glColor3f(*color) - glVertex3f(v[0][0]+o[0], v[0][1]+o[1], v[0][2]+o[2]) - glVertex3f(v[1][0]+o[0], v[1][1]+o[1], v[1][2]+o[2]) + glVertex3f(v[0][0] + o[0], v[0][1] + o[1], v[0][2] + o[2]) + glVertex3f(v[1][0] + o[0], v[1][1] + o[1], v[1][2] + o[2]) glEnd() + class PlotAxesOrdinate(PlotAxesBase): def __init__(self, parent_axes): @@ -185,7 +190,7 @@ d = d / vec_mag(axis_vector) # don't draw labels if we're looking down the axis - labels_visible = abs(d-1.0) > 0.02 + labels_visible = abs(d - 1.0) > 0.02 # draw the ticks and labels for tick in ticks: @@ -208,8 +213,8 @@ axis_labels[0][axis] -= 0.3 axis_labels[1][axis] += 0.3 a_str = ['X', 'Y', 'Z'][axis] - self.draw_text("-"+a_str, axis_labels[0], color) - self.draw_text("+"+a_str, axis_labels[1], color) + self.draw_text("-" + a_str, axis_labels[0], color) + self.draw_text("+" + a_str, axis_labels[1], color) def draw_tick_line(self, axis, color, radius, tick, labels_visible): tick_axis = {0: 1, 1: 0, 2: 1}[axis] @@ -225,9 +230,11 @@ return tick_label_vector = [0, 0, 0] tick_label_vector[axis] = tick - tick_label_vector[{0: 1, 1: 0, 2: 1}[axis]] = [-1,1,1][axis] * radius * 3.5 + tick_label_vector[{0: 1, 1: 0, 2: 1}[axis]] = [-1, 1, 1][ + axis] * radius * 3.5 self.draw_text(str(tick), tick_label_vector, color, scale=0.5) + class PlotAxesFrame(PlotAxesBase): def __init__(self, parent_axes): diff -Nru python3-sympy-0.7.2/sympy/plotting/pygletplot/plot_camera.py python3-sympy-0.7.3/sympy/plotting/pygletplot/plot_camera.py --- python3-sympy-0.7.2/sympy/plotting/pygletplot/plot_camera.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/plotting/pygletplot/plot_camera.py 2013-07-13 17:53:32.000000000 +0000 @@ -4,6 +4,7 @@ from .util import screen_to_model, model_to_screen from .util import vec_subs + class PlotCamera(object): min_dist = 0.05 @@ -39,7 +40,8 @@ try: r = self.rot_presets[preset_name] except AttributeError: - raise ValueError("%s is not a valid rotation preset." % preset_name) + raise ValueError( + "%s is not a valid rotation preset." % preset_name) try: self.euler_rotate(r[0], 1, 0, 0) self.euler_rotate(r[1], 0, 1, 0) @@ -69,11 +71,13 @@ glLoadIdentity() if self.ortho: # yep, this is pseudo ortho (don't tell anyone) - gluPerspective(0.3, float(self.window.width)/float(self.window.height), - self.min_ortho_dist-0.01, self.max_ortho_dist+0.01) + gluPerspective( + 0.3, float(self.window.width)/float(self.window.height), + self.min_ortho_dist - 0.01, self.max_ortho_dist + 0.01) else: - gluPerspective(30.0, float(self.window.width)/float(self.window.height), - self.min_dist-0.01, self.max_dist+0.01) + gluPerspective( + 30.0, float(self.window.width)/float(self.window.height), + self.min_dist - 0.01, self.max_dist + 0.01) glMatrixMode(GL_MODELVIEW) def _get_scale(self): @@ -110,7 +114,7 @@ min_dist = self.min_dist max_dist = self.max_dist - new_dist = (self._dist-dist_d) + new_dist = (self._dist - dist_d) if (clicks < 0 and new_dist < max_dist) or new_dist > min_dist: self._dist = new_dist @@ -119,7 +123,7 @@ glLoadIdentity() glTranslatef(0, 0, -self._dist) z = model_to_screen(0, 0, 0)[2] - d = vec_subs(screen_to_model(x, y, z), screen_to_model(x-dx, y-dy, z)) + d = vec_subs(screen_to_model(x, y, z), screen_to_model(x - dx, y - dy, z)) glPopMatrix() self._x += d[0] self._y += d[1] diff -Nru python3-sympy-0.7.2/sympy/plotting/pygletplot/plot_controller.py python3-sympy-0.7.3/sympy/plotting/pygletplot/plot_controller.py --- python3-sympy-0.7.2/sympy/plotting/pygletplot/plot_controller.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/plotting/pygletplot/plot_controller.py 2013-07-13 17:53:32.000000000 +0000 @@ -2,6 +2,7 @@ from pyglet.window.mouse import LEFT, RIGHT, MIDDLE from .util import get_direction_vectors, get_basis_vectors + class PlotController(object): normal_mouse_sensitivity = 4.0 @@ -11,93 +12,93 @@ modified_key_sensitivity = 40.0 keymap = { - key.LEFT: 'left', - key.A: 'left', - key.NUM_4: 'left', + key.LEFT: 'left', + key.A: 'left', + key.NUM_4: 'left', - key.RIGHT: 'right', - key.D: 'right', - key.NUM_6: 'right', + key.RIGHT: 'right', + key.D: 'right', + key.NUM_6: 'right', - key.UP: 'up', - key.W: 'up', - key.NUM_8: 'up', + key.UP: 'up', + key.W: 'up', + key.NUM_8: 'up', - key.DOWN: 'down', - key.S: 'down', - key.NUM_2: 'down', + key.DOWN: 'down', + key.S: 'down', + key.NUM_2: 'down', - key.Z: 'rotate_z_neg', - key.NUM_1: 'rotate_z_neg', + key.Z: 'rotate_z_neg', + key.NUM_1: 'rotate_z_neg', - key.C: 'rotate_z_pos', - key.NUM_3: 'rotate_z_pos', + key.C: 'rotate_z_pos', + key.NUM_3: 'rotate_z_pos', - key.Q: 'spin_left', - key.NUM_7: 'spin_left', - key.E: 'spin_right', - key.NUM_9: 'spin_right', + key.Q: 'spin_left', + key.NUM_7: 'spin_left', + key.E: 'spin_right', + key.NUM_9: 'spin_right', - key.X: 'reset_camera', - key.NUM_5: 'reset_camera', + key.X: 'reset_camera', + key.NUM_5: 'reset_camera', - key.NUM_ADD: 'zoom_in', - key.PAGEUP: 'zoom_in', - key.R: 'zoom_in', + key.NUM_ADD: 'zoom_in', + key.PAGEUP: 'zoom_in', + key.R: 'zoom_in', - key.NUM_SUBTRACT: 'zoom_out', - key.PAGEDOWN: 'zoom_out', - key.F: 'zoom_out', + key.NUM_SUBTRACT: 'zoom_out', + key.PAGEDOWN: 'zoom_out', + key.F: 'zoom_out', - key.RSHIFT: 'modify_sensitivity', - key.LSHIFT: 'modify_sensitivity', + key.RSHIFT: 'modify_sensitivity', + key.LSHIFT: 'modify_sensitivity', - key.F1: 'rot_preset_xy', - key.F2: 'rot_preset_xz', - key.F3: 'rot_preset_yz', - key.F4: 'rot_preset_perspective', + key.F1: 'rot_preset_xy', + key.F2: 'rot_preset_xz', + key.F3: 'rot_preset_yz', + key.F4: 'rot_preset_perspective', - key.F5: 'toggle_axes', - key.F6: 'toggle_axe_colors', + key.F5: 'toggle_axes', + key.F6: 'toggle_axe_colors', - key.F8: 'save_image' - } + key.F8: 'save_image' + } def __init__(self, window, **kwargs): self.invert_mouse_zoom = kwargs.pop('invert_mouse_zoom', False) self.window = window self.camera = window.camera self.action = { - # Rotation around the view Y (up) vector - 'left': False, - 'right': False, - # Rotation around the view X vector - 'up': False, - 'down': False, - # Rotation around the view Z vector - 'spin_left': False, - 'spin_right': False, - # Rotation around the model Z vector - 'rotate_z_neg': False, - 'rotate_z_pos': False, - # Reset to the default rotation - 'reset_camera': False, - # Performs camera z-translation - 'zoom_in': False, - 'zoom_out': False, - # Use alternative sensitivity (speed) - 'modify_sensitivity': False, - # Rotation presets - 'rot_preset_xy': False, - 'rot_preset_xz': False, - 'rot_preset_yz': False, - 'rot_preset_perspective': False, - # axes - 'toggle_axes': False, - 'toggle_axe_colors': False, - # screenshot - 'save_image': False - } + # Rotation around the view Y (up) vector + 'left': False, + 'right': False, + # Rotation around the view X vector + 'up': False, + 'down': False, + # Rotation around the view Z vector + 'spin_left': False, + 'spin_right': False, + # Rotation around the model Z vector + 'rotate_z_neg': False, + 'rotate_z_pos': False, + # Reset to the default rotation + 'reset_camera': False, + # Performs camera z-translation + 'zoom_in': False, + 'zoom_out': False, + # Use alternative sensitivity (speed) + 'modify_sensitivity': False, + # Rotation presets + 'rot_preset_xy': False, + 'rot_preset_xz': False, + 'rot_preset_yz': False, + 'rot_preset_perspective': False, + # axes + 'toggle_axes': False, + 'toggle_axe_colors': False, + # screenshot + 'save_image': False + } def update(self, dt): z = 0 @@ -197,7 +198,7 @@ if self.is_2D(): self.camera.mouse_translate(x, y, dx, dy) else: - self.camera.spherical_rotate((x-dx, y-dy), (x, y), + self.camera.spherical_rotate((x - dx, y - dy), (x, y), self.get_mouse_sensitivity()) if buttons & MIDDLE: self.camera.zoom_relative([1, -1][self.invert_mouse_zoom]*dy, diff -Nru python3-sympy-0.7.2/sympy/plotting/pygletplot/plot_curve.py python3-sympy-0.7.3/sympy/plotting/pygletplot/plot_curve.py --- python3-sympy-0.7.2/sympy/plotting/pygletplot/plot_curve.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/plotting/pygletplot/plot_curve.py 2013-07-13 17:53:32.000000000 +0000 @@ -2,6 +2,7 @@ from .plot_mode_base import PlotModeBase from sympy.core import S + class PlotCurve(PlotModeBase): style_override = 'wireframe' @@ -41,8 +42,10 @@ def _on_calculate_cverts(self): if not self.verts or not self.color: return + def set_work_len(n): self._calculating_cverts_len = float(n) + def inc_work_pos(): self._calculating_cverts_pos += 1.0 set_work_len(1) diff -Nru python3-sympy-0.7.2/sympy/plotting/pygletplot/plot_interval.py python3-sympy-0.7.3/sympy/plotting/pygletplot/plot_interval.py --- python3-sympy-0.7.2/sympy/plotting/pygletplot/plot_interval.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/plotting/pygletplot/plot_interval.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,5 +1,6 @@ from sympy import Symbol, Integer, sympify + class PlotInterval(object): """ """ @@ -56,6 +57,7 @@ def get_v_min(self): return self._v_min + def set_v_min(self, v_min): if v_min is None: self._v_min = None @@ -68,6 +70,7 @@ def get_v_max(self): return self._v_max + def set_v_max(self, v_max): if v_max is None: self._v_max = None @@ -153,7 +156,7 @@ v_min to v_max. """ d = (self.v_max - self.v_min) / self.v_steps - for i in range(self.v_steps+1): + for i in range(self.v_steps + 1): a = self.v_min + (d * Integer(i)) yield a @@ -166,7 +169,7 @@ d = (self.v_max - self.v_min) / self.v_steps a = self.v_min + (d * Integer(0)) for i in range(self.v_steps): - b = self.v_min + (d * Integer(i+1)) + b = self.v_min + (d * Integer(i + 1)) yield a, b a = b diff -Nru python3-sympy-0.7.2/sympy/plotting/pygletplot/plot_mode.py python3-sympy-0.7.3/sympy/plotting/pygletplot/plot_mode.py --- python3-sympy-0.7.2/sympy/plotting/pygletplot/plot_mode.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/plotting/pygletplot/plot_mode.py 2013-07-13 17:53:32.000000000 +0000 @@ -5,6 +5,7 @@ from sympy.geometry.entity import GeometryEntity from sympy.core.compatibility import is_sequence + class PlotMode(PlotObject): """ Grandparent class for plotting @@ -47,12 +48,12 @@ 1: {1: {}, 2: {}}, 2: {1: {}, 2: {}}, 3: {1: {}, 2: {}}, - } # [d][i][alias_str]: class + } # [d][i][alias_str]: class _mode_default_map = { 1: {}, 2: {}, 3: {}, - } # [d][i]: class + } # [d][i]: class _i_var_max, _d_var_max = 2, 3 def __new__(cls, *args, **kwargs): @@ -127,17 +128,17 @@ if not m._was_initialized: raise ValueError(("To use unregistered plot mode %s " "you must first call %s._init_mode().") - % (m.__name__, m.__name__)) + % (m.__name__, m.__name__)) if d_var_count != m.d_var_count: raise ValueError(("%s can only plot functions " "with %i dependent variables.") - % (m.__name__, + % (m.__name__, m.d_var_count)) if i_var_count > m.i_var_count: raise ValueError(("%s cannot plot functions " "with more than %i independent " "variables.") - % (m.__name__, + % (m.__name__, m.i_var_count)) return m # If it is a string, there are two possibilities. @@ -170,7 +171,7 @@ # which support the given d var count until we # reach the max i_var count. if i < PlotMode._i_var_max: - return PlotMode._get_default_mode(i+1, d, i_vars) + return PlotMode._get_default_mode(i + 1, d, i_vars) else: raise ValueError(("Couldn't find a default mode " "for %i independent and %i " @@ -183,7 +184,7 @@ if alias not in PlotMode._mode_alias_list: raise ValueError(("Couldn't find a mode called" " %s. Known modes: %s.") - % (alias, ", ".join(PlotMode._mode_alias_list))) + % (alias, ", ".join(PlotMode._mode_alias_list))) try: return PlotMode._mode_map[d][i][alias] except TypeError: @@ -191,12 +192,12 @@ # which support the given d var count and alias # until we reach the max i_var count. if i < PlotMode._i_var_max: - return PlotMode._get_aliased_mode(alias, i+1, d, i_vars) + return PlotMode._get_aliased_mode(alias, i + 1, d, i_vars) else: raise ValueError(("Couldn't find a %s mode " "for %i independent and %i " "dependent variables.") - % (alias, i_vars, d)) + % (alias, i_vars, d)) @classmethod def _register(cls): @@ -384,6 +385,7 @@ nkwargs = dict(nkwargs, **kwargs) return nargs, nkwargs + def var_count_error(is_independent, is_plotting): """ Used to format an error message which differs diff -Nru python3-sympy-0.7.2/sympy/plotting/pygletplot/plot_mode_base.py python3-sympy-0.7.3/sympy/plotting/pygletplot/plot_mode_base.py --- python3-sympy-0.7.2/sympy/plotting/pygletplot/plot_mode_base.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/plotting/pygletplot/plot_mode_base.py 2013-07-13 17:53:32.000000000 +0000 @@ -5,10 +5,12 @@ from sympy.core import S from sympy.core.compatibility import is_sequence from time import sleep +import warnings from sympy.core.compatibility import callable import collections + class PlotModeBase(PlotMode): """ Intended parent class for plotting @@ -113,7 +115,7 @@ e = self._get_lambda_evaluator() return e except: - print ("\nWarning: creating lambda evaluator failed. " + warnings.warn("\nWarning: creating lambda evaluator failed. " "Falling back on sympy subs evaluator.") return self._get_sympy_evaluator() @@ -142,7 +144,7 @@ self._draw_lock = RLock() - self._calculating_verts = Event() + self._calculating_verts = Event() self._calculating_cverts = Event() self._calculating_verts_pos = 0.0 self._calculating_verts_len = 0.0 @@ -186,7 +188,7 @@ assert isinstance(function, collections.Callable) self._draw_wireframe.append(function) if len(self._draw_wireframe) > self._max_render_stack_size: - del self._draw_wireframe[1] # leave marker element + del self._draw_wireframe[1] # leave marker element @synchronized def push_solid(self, function): @@ -198,7 +200,7 @@ assert isinstance(function, collections.Callable) self._draw_solid.append(function) if len(self._draw_solid) > self._max_render_stack_size: - del self._draw_solid[1] # leave marker element + del self._draw_solid[1] # leave marker element def _create_display_list(self, function): dl = glGenLists(1) @@ -210,17 +212,17 @@ def _render_stack_top(self, render_stack): top = render_stack[-1] if top == -1: - return -1 # nothing to display + return -1 # nothing to display elif isinstance(top, collections.Callable): dl = self._create_display_list(top) render_stack[-1] = (dl, top) - return dl # display newly added list + return dl # display newly added list elif len(top) == 2: if GL_TRUE == glIsList(top[0]): - return top[0] # display stored list + return top[0] # display stored list dl = self._create_display_list(top[1]) render_stack[-1] = (dl, top[1]) - return dl # display regenerated list + return dl # display regenerated list def _draw_solid_display_list(self, dl): glPushAttrib(GL_ENABLE_BIT | GL_POLYGON_BIT) @@ -284,7 +286,7 @@ if self._calculating_verts.isSet(): return while self._calculating_cverts.isSet(): - sleep(0) # wait for previous calculation + sleep(0) # wait for previous calculation self._calculating_cverts.set() try: self._on_calculate_cverts() diff -Nru python3-sympy-0.7.2/sympy/plotting/pygletplot/plot_modes.py python3-sympy-0.7.3/sympy/plotting/pygletplot/plot_modes.py --- python3-sympy-0.7.2/sympy/plotting/pygletplot/plot_modes.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/plotting/pygletplot/plot_modes.py 2013-07-13 17:53:32.000000000 +0000 @@ -6,12 +6,14 @@ from math import sin as p_sin from math import cos as p_cos + def float_vec3(f): def inner(*args): v = f(*args) return float(v[0]), float(v[1]), float(v[2]) return inner + class Cartesian2D(PlotCurve): i_vars, d_vars = 'x', 'y' intervals = [[-5, 5, 100]] @@ -21,6 +23,7 @@ def _get_sympy_evaluator(self): fy = self.d_vars[0] x = self.t_interval.v + @float_vec3 def e(_x): return (_x, fy.subs(x, _x), 0.0) @@ -31,6 +34,7 @@ x = self.t_interval.v return lambdify([x], [x, fy, 0.0]) + class Cartesian3D(PlotSurface): i_vars, d_vars = 'xy', 'z' intervals = [[-1, 1, 40], [-1, 1, 40]] @@ -41,6 +45,7 @@ fz = self.d_vars[0] x = self.u_interval.v y = self.v_interval.v + @float_vec3 def e(_x, _y): return (_x, _y, fz.subs(x, _x).subs(y, _y)) @@ -52,6 +57,7 @@ y = self.v_interval.v return lambdify([x, y], [x, y, fz]) + class ParametricCurve2D(PlotCurve): i_vars, d_vars = 't', 'xy' intervals = [[0, 2*pi, 100]] @@ -61,6 +67,7 @@ def _get_sympy_evaluator(self): fx, fy = self.d_vars t = self.t_interval.v + @float_vec3 def e(_t): return (fx.subs(t, _t), fy.subs(t, _t), 0.0) @@ -71,6 +78,7 @@ t = self.t_interval.v return lambdify([t], [fx, fy, 0.0]) + class ParametricCurve3D(PlotCurve): i_vars, d_vars = 't', 'xyz' intervals = [[0, 2*pi, 100]] @@ -80,6 +88,7 @@ def _get_sympy_evaluator(self): fx, fy, fz = self.d_vars t = self.t_interval.v + @float_vec3 def e(_t): return (fx.subs(t, _t), fy.subs(t, _t), fz.subs(t, _t)) @@ -90,6 +99,7 @@ t = self.t_interval.v return lambdify([t], [fx, fy, fz]) + class ParametricSurface(PlotSurface): i_vars, d_vars = 'uv', 'xyz' intervals = [[-1, 1, 40], [-1, 1, 40]] @@ -100,6 +110,7 @@ fx, fy, fz = self.d_vars u = self.u_interval.v v = self.v_interval.v + @float_vec3 def e(_u, _v): return (fx.subs(u, _u).subs(v, _v), @@ -113,6 +124,7 @@ v = self.v_interval.v return lambdify([u, v], [fx, fy, fz]) + class Polar(PlotCurve): i_vars, d_vars = 't', 'r' intervals = [[0, 2*pi, 100]] @@ -122,6 +134,7 @@ def _get_sympy_evaluator(self): fr = self.d_vars[0] t = self.t_interval.v + def e(_t): _r = float(fr.subs(t, _t)) return (_r*p_cos(_t), _r*p_sin(_t), 0.0) @@ -133,6 +146,7 @@ fx, fy = fr*cos(t), fr*sin(t) return lambdify([t], [fx, fy, 0.0]) + class Cylindrical(PlotSurface): i_vars, d_vars = 'th', 'r' intervals = [[0, 2*pi, 40], [-1, 1, 20]] @@ -141,8 +155,9 @@ def _get_sympy_evaluator(self): fr = self.d_vars[0] - t = self.u_interval.v - h = self.v_interval.v + t = self.u_interval.v + h = self.v_interval.v + def e(_t, _h): _r = float(fr.subs(t, _t).subs(h, _h)) return (_r*p_cos(_t), _r*p_sin(_t), _h) @@ -150,11 +165,12 @@ def _get_lambda_evaluator(self): fr = self.d_vars[0] - t = self.u_interval.v - h = self.v_interval.v + t = self.u_interval.v + h = self.v_interval.v fx, fy = fr*cos(t), fr*sin(t) return lambdify([t, h], [fx, fy, h]) + class Spherical(PlotSurface): i_vars, d_vars = 'tp', 'r' intervals = [[0, 2*pi, 40], [0, pi, 20]] @@ -163,8 +179,9 @@ def _get_sympy_evaluator(self): fr = self.d_vars[0] - t = self.u_interval.v - p = self.v_interval.v + t = self.u_interval.v + p = self.v_interval.v + def e(_t, _p): _r = float(fr.subs(t, _t).subs(p, _p)) return (_r*p_cos(_t)*p_sin(_p), @@ -174,8 +191,8 @@ def _get_lambda_evaluator(self): fr = self.d_vars[0] - t = self.u_interval.v - p = self.v_interval.v + t = self.u_interval.v + p = self.v_interval.v fx = fr * cos(t) * sin(p) fy = fr * sin(t) * sin(p) fz = fr * cos(p) diff -Nru python3-sympy-0.7.2/sympy/plotting/pygletplot/plot_rotation.py python3-sympy-0.7.3/sympy/plotting/pygletplot/plot_rotation.py --- python3-sympy-0.7.2/sympy/plotting/pygletplot/plot_rotation.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/plotting/pygletplot/plot_rotation.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,26 +1,31 @@ from pyglet.gl import * from math import sqrt as _sqrt, acos as _acos + def cross(a, b): return (a[1] * b[2] - a[2] * b[1], a[2] * b[0] - a[0] * b[2], a[0] * b[1] - a[1] * b[0]) + def dot(a, b): return a[0] * b[0] + a[1] * b[1] + a[2] * b[2] + def mag(a): - return _sqrt(a[0]**2+a[1]**2+a[2]**2) + return _sqrt(a[0]**2 + a[1]**2 + a[2]**2) + def norm(a): m = mag(a) return (a[0] / m, a[1] / m, a[2] / m) + def get_sphere_mapping(x, y, width, height): - x = min([max([x,0]), width]) - y = min([max([y,0]), height]) + x = min([max([x, 0]), width]) + y = min([max([y, 0]), height]) - sr = _sqrt((width/2)**2+(height/2)**2) + sr = _sqrt((width/2)**2 + (height/2)**2) #sr *= 1.5 sx = ((x - width / 2) / sr) sy = ((y - height / 2) / sr) @@ -36,13 +41,14 @@ rad2deg = 180.0 / 3.141592 + def get_spherical_rotatation(p1, p2, width, height, theta_multiplier): v1 = get_sphere_mapping(p1[0], p1[1], width, height) v2 = get_sphere_mapping(p2[0], p2[1], width, height) d = min(max([dot(v1, v2), -1]), 1) - if abs(d-1.0) < 0.000001: + if abs(d - 1.0) < 0.000001: return None raxis = norm( cross(v1, v2) ) diff -Nru python3-sympy-0.7.2/sympy/plotting/pygletplot/plot_surface.py python3-sympy-0.7.3/sympy/plotting/pygletplot/plot_surface.py --- python3-sympy-0.7.2/sympy/plotting/pygletplot/plot_surface.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/plotting/pygletplot/plot_surface.py 2013-07-13 17:53:32.000000000 +0000 @@ -2,6 +2,7 @@ from .plot_mode_base import PlotModeBase from sympy.core import S + class PlotSurface(PlotModeBase): default_rot_preset = 'perspective' @@ -18,7 +19,7 @@ self._calculating_verts_pos = 0.0 self._calculating_verts_len = float( - self.u_interval.v_len*self.v_interval.v_len) + self.u_interval.v_len*self.v_interval.v_len) verts = list() b = self.bounds @@ -26,7 +27,7 @@ column = list() for v in self.v_set: try: - _e = evaluate(u, v) # calculate vertex + _e = evaluate(u, v) # calculate vertex except ZeroDivisionError: _e = None if _e is not None: # update bounding box @@ -49,8 +50,10 @@ def _on_calculate_cverts(self): if not self.verts or not self.color: return + def set_work_len(n): self._calculating_cverts_len = float(n) + def inc_work_pos(): self._calculating_cverts_pos += 1.0 set_work_len(1) @@ -72,14 +75,14 @@ for u in range(1, len(self.u_set)): glBegin(GL_QUAD_STRIP) for v in range(len(self.v_set)): - pa = self.verts[u-1][v] + pa = self.verts[u - 1][v] pb = self.verts[u][v] if pa is None or pb is None: glEnd() glBegin(GL_QUAD_STRIP) continue if use_cverts: - ca = self.cverts[u-1][v] + ca = self.cverts[u - 1][v] cb = self.cverts[u][v] if ca is None: ca = (0, 0, 0) diff -Nru python3-sympy-0.7.2/sympy/plotting/pygletplot/plot_window.py python3-sympy-0.7.3/sympy/plotting/pygletplot/plot_window.py --- python3-sympy-0.7.2/sympy/plotting/pygletplot/plot_window.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/plotting/pygletplot/plot_window.py 2013-07-13 17:53:32.000000000 +0000 @@ -6,6 +6,7 @@ from time import clock + class PlotWindow(ManagedWindow): def __init__(self, plot, **kwargs): @@ -79,7 +80,7 @@ calc_verts_pos, calc_verts_len = 0, 0 calc_cverts_pos, calc_cverts_len = 0, 0 - should_update_caption = (clock()-self.last_caption_update > + should_update_caption = (clock() - self.last_caption_update > self.caption_update_interval) if len(list(self.plot._functions.values())) == 0: diff -Nru python3-sympy-0.7.2/sympy/plotting/pygletplot/tests/test_plotting.py python3-sympy-0.7.3/sympy/plotting/pygletplot/tests/test_plotting.py --- python3-sympy-0.7.2/sympy/plotting/pygletplot/tests/test_plotting.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/plotting/pygletplot/tests/test_plotting.py 2013-07-13 17:53:32.000000000 +0000 @@ -8,6 +8,7 @@ if not pyglet_gl or not pyglet_window: disabled = True + def setup_module(module): """py.test support""" if module.disabled: @@ -17,61 +18,76 @@ from sympy import symbols, sin, cos x, y, z = symbols('x, y, z') + def test_import(): from sympy.plotting.pygletplot import PygletPlot + def test_plot_2d(): from sympy.plotting.pygletplot import PygletPlot p = PygletPlot(x, [x, -5, 5, 4], visible=False) p.wait_for_calculations() + def test_plot_2d_discontinuous(): from sympy.plotting.pygletplot import PygletPlot p = PygletPlot(1/x, [x, -1, 1, 2], visible=False) p.wait_for_calculations() + def test_plot_3d(): from sympy.plotting.pygletplot import PygletPlot p = PygletPlot(x*y, [x, -5, 5, 5], [y, -5, 5, 5], visible=False) p.wait_for_calculations() + def test_plot_3d_discontinuous(): from sympy.plotting.pygletplot import PygletPlot p = PygletPlot(1/x, [x, -3, 3, 6], [y, -1, 1, 1], visible=False) p.wait_for_calculations() + def test_plot_2d_polar(): from sympy.plotting.pygletplot import PygletPlot - p = PygletPlot(1/x, [x,-1,1,4], 'mode=polar', visible=False) + p = PygletPlot(1/x, [x, -1, 1, 4], 'mode=polar', visible=False) p.wait_for_calculations() + def test_plot_3d_cylinder(): from sympy.plotting.pygletplot import PygletPlot - p = PygletPlot(1/y, [x,0,6.282,4], [y,-1,1,4], 'mode=polar;style=solid', - visible=False) + p = PygletPlot( + 1/y, [x, 0, 6.282, 4], [y, -1, 1, 4], 'mode=polar;style=solid', + visible=False) p.wait_for_calculations() + def test_plot_3d_spherical(): from sympy.plotting.pygletplot import PygletPlot - p = PygletPlot(1, [x,0,6.282,4], [y,0,3.141,4], 'mode=spherical;style=wireframe', - visible=False) + p = PygletPlot( + 1, [x, 0, 6.282, 4], [y, 0, 3.141, + 4], 'mode=spherical;style=wireframe', + visible=False) p.wait_for_calculations() + def test_plot_2d_parametric(): from sympy.plotting.pygletplot import PygletPlot p = PygletPlot(sin(x), cos(x), [x, 0, 6.282, 4], visible=False) p.wait_for_calculations() + def test_plot_3d_parametric(): from sympy.plotting.pygletplot import PygletPlot p = PygletPlot(sin(x), cos(x), x/5.0, [x, 0, 6.282, 4], visible=False) p.wait_for_calculations() + def _test_plot_log(): from sympy.plotting.pygletplot import PygletPlot - p = PygletPlot(log(x), [x,0,6.282,4], 'mode=polar', visible=False) + p = PygletPlot(log(x), [x, 0, 6.282, 4], 'mode=polar', visible=False) p.wait_for_calculations() + def test_plot_integral(): # Make sure it doesn't treat x as an independent variable from sympy.plotting.pygletplot import PygletPlot diff -Nru python3-sympy-0.7.2/sympy/plotting/pygletplot/util.py python3-sympy-0.7.3/sympy/plotting/pygletplot/util.py --- python3-sympy-0.7.2/sympy/plotting/pygletplot/util.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/plotting/pygletplot/util.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,6 +1,7 @@ from pyglet.gl import * from sympy.core import S + def get_model_matrix(array_type=c_float, glGetMethod=glGetFloatv): """ Returns the current modelview matrix. @@ -9,6 +10,7 @@ glGetMethod(GL_MODELVIEW_MATRIX, m) return m + def get_projection_matrix(array_type=c_float, glGetMethod=glGetFloatv): """ Returns the current modelview matrix. @@ -17,6 +19,7 @@ glGetMethod(GL_PROJECTION_MATRIX, m) return m + def get_viewport(): """ Returns the current viewport. @@ -25,22 +28,26 @@ glGetIntegerv(GL_VIEWPORT, m) return m + def get_direction_vectors(): m = get_model_matrix() return ((m[0], m[4], m[8]), (m[1], m[5], m[9]), (m[2], m[6], m[10])) + def get_view_direction_vectors(): m = get_model_matrix() return ((m[0], m[1], m[2]), (m[4], m[5], m[6]), (m[8], m[9], m[10])) + def get_basis_vectors(): return ((1, 0, 0), (0, 1, 0), (0, 0, 1)) -def screen_to_model(x,y,z): + +def screen_to_model(x, y, z): m = get_model_matrix(c_double, glGetDoublev) p = get_projection_matrix(c_double, glGetDoublev) w = get_viewport() @@ -48,7 +55,8 @@ gluUnProject(x, y, z, m, p, w, mx, my, mz) return float(mx.value), float(my.value), float(mz.value) -def model_to_screen(x,y,z): + +def model_to_screen(x, y, z): m = get_model_matrix(c_double, glGetDoublev) p = get_projection_matrix(c_double, glGetDoublev) w = get_viewport() @@ -56,8 +64,10 @@ gluProject(x, y, z, m, p, w, mx, my, mz) return float(mx.value), float(my.value), float(mz.value) -def vec_subs(a,b): - return tuple(a[i]-b[i] for i in range(len(a))) + +def vec_subs(a, b): + return tuple(a[i] - b[i] for i in range(len(a))) + def billboard_matrix(): """ @@ -83,11 +93,13 @@ m[10] = 1 glLoadMatrixf(m) + def create_bounds(): return [[S.Infinity, -S.Infinity, 0], [S.Infinity, -S.Infinity, 0], [S.Infinity, -S.Infinity, 0]] + def update_bounds(b, v): if v is None: return @@ -95,45 +107,52 @@ b[axis][0] = min([b[axis][0], v[axis]]) b[axis][1] = max([b[axis][1], v[axis]]) + def interpolate(a_min, a_max, a_ratio): return a_min + a_ratio * (a_max - a_min) + def rinterpolate(a_min, a_max, a_value): - a_range = a_max-a_min + a_range = a_max - a_min if a_range == 0: a_range = 1.0 return (a_value - a_min) / float(a_range) + def interpolate_color(color1, color2, ratio): return tuple(interpolate(color1[i], color2[i], ratio) for i in range(3)) + def scale_value(v, v_min, v_len): return (v - v_min) / v_len + def scale_value_list(flist): v_min, v_max = min(flist), max(flist) - v_len = v_max-v_min + v_len = v_max - v_min return list(scale_value(f, v_min, v_len) for f in flist) + def strided_range(r_min, r_max, stride, max_steps=50): o_min, o_max = r_min, r_max - if abs(r_min-r_max) < 0.001: + if abs(r_min - r_max) < 0.001: return [] try: - range(int(r_min-r_max)) + range(int(r_min - r_max)) except TypeError: return [] assert r_min < r_max r_min_s = (r_min % stride) r_max_s = stride - (r_max % stride) - if abs(r_max_s-stride) < 0.001: + if abs(r_max_s - stride) < 0.001: r_max_s = 0.0 r_min -= r_min_s r_max += r_max_s - r_steps = int((r_max-r_min)/stride) + r_steps = int((r_max - r_min)/stride) if max_steps and r_steps > max_steps: return strided_range(o_min, o_max, stride*2) - return [r_min] + list(r_min+e*stride for e in range(1, r_steps+1)) + [r_max] + return [r_min] + list(r_min + e*stride for e in range(1, r_steps + 1)) + [r_max] + def parse_option_string(s): if not isinstance(s, str): @@ -150,11 +169,14 @@ options[option.strip()] = value.strip() return options + def dot_product(v1, v2): return sum(v1[i]*v2[i] for i in range(3)) + def vec_sub(v1, v2): - return tuple(v1[i]-v2[i] for i in range(3)) + return tuple(v1[i] - v2[i] for i in range(3)) + def vec_mag(v): return sum(v[i]**2 for i in range(3))**(0.5) diff -Nru python3-sympy-0.7.2/sympy/plotting/tests/test_plot.py python3-sympy-0.7.3/sympy/plotting/tests/test_plot.py --- python3-sympy-0.7.2/sympy/plotting/tests/test_plot.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/plotting/tests/test_plot.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,17 +1,22 @@ from sympy import (pi, sin, cos, Symbol, Integral, summation, sqrt, log, - oo, LambertW, I) + oo, LambertW, I, meijerg, exp_polar, Max) from sympy.plotting import (plot, plot_parametric, plot3d_parametric_line, plot3d, plot3d_parametric_surface) -from sympy.plotting.plot import matplotlib, unset_show +from sympy.plotting.plot import unset_show from sympy.utilities.pytest import skip +from sympy.plotting.experimental_lambdify import lambdify +from sympy.external import import_module + from tempfile import NamedTemporaryFile import warnings unset_show() + def tmp_file(name=''): return NamedTemporaryFile(suffix='.png').name + def plot_and_save(name): x = Symbol('x') y = Symbol('y') @@ -22,26 +27,26 @@ ### p = plot(x) - p = plot(x*sin(x),x*cos(x)) + p = plot(x*sin(x), x*cos(x)) p.extend(p) - p[0].line_color = lambda a : a - p[1].line_color='b' + p[0].line_color = lambda a: a + p[1].line_color = 'b' p.title = 'Big title' p.xlabel = 'the x axis' p[1].label = 'straight line' p.legend = True - p.aspect_ratio = (1,1) - p.xlim = (-15,20) + p.aspect_ratio = (1, 1) + p.xlim = (-15, 20) p.save(tmp_file('%s_basic_options_and_colors.png' % name)) - p.extend(plot(x+1)) - p.append(plot(x+3,x**2)[1]) + p.extend(plot(x + 1)) + p.append(plot(x + 3, x**2)[1]) p.save(tmp_file('%s_plot_extend_append.png' % name)) p[2] = plot(x**2, (x, -2, 3)) p.save(tmp_file('%s_plot_setitem.png' % name)) - p = plot(sin(x),(x,-2*pi,4*pi)) + p = plot(sin(x), (x, -2*pi, 4*pi)) p.save(tmp_file('%s_line_explicit.png' % name)) p = plot(sin(x)) @@ -50,7 +55,6 @@ p = plot((x**2, (x, -5, 5)), (x**3, (x, -3, 3))) p.save(tmp_file('%s_line_multiple_range.png' % name)) - #parametric 2d plots. #Single plot with default range. plot_parametric(sin(x), cos(x)).save(tmp_file()) @@ -76,10 +80,11 @@ p.save(tmp_file('%s_adaptive' % name)) #3d parametric plots - p = plot3d_parametric_line(sin(x),cos(x),x) + p = plot3d_parametric_line(sin(x), cos(x), x) p.save(tmp_file('%s_3d_line.png' % name)) - p = plot3d_parametric_line((sin(x), cos(x), x, (x, -5, 5)), (cos(x), sin(x), x, (x, -3, 3))) + p = plot3d_parametric_line( + (sin(x), cos(x), x, (x, -5, 5)), (cos(x), sin(x), x, (x, -3, 3))) p.save(tmp_file('%s_3d_line_multiple' % name)) p = plot3d_parametric_line(sin(x), cos(x), x, nb_of_points=30) @@ -94,7 +99,8 @@ p.save(tmp_file('%s_surface_multiple' % name)) # Multiple 3D plots with different ranges. - p = plot3d((x * y, (x, -3, 3), (y, -3, 3)), (-x * y, (x, -3, 3), (y, -3, 3))) + p = plot3d( + (x * y, (x, -3, 3), (y, -3, 3)), (-x * y, (x, -3, 3), (y, -3, 3))) p.save(tmp_file('%s_surface_multiple_ranges' % name)) # Single Parametric 3D plot @@ -102,8 +108,9 @@ p.save(tmp_file('%s_parametric_surface' % name)) # Multiple Parametric 3D plots. - p = plot3d_parametric_surface((x*sin(z),x*cos(z),z, (x, -5, 5), (z, -5, 5)), - (sin(x + y), cos(x - y), x - y, (x, -5, 5), (y, -5, 5))) + p = plot3d_parametric_surface( + (x*sin(z), x*cos(z), z, (x, -5, 5), (z, -5, 5)), + (sin(x + y), cos(x - y), x - y, (x, -5, 5), (y, -5, 5))) p.save(tmp_file('%s_parametric_surface.png' % name)) ### @@ -111,84 +118,95 @@ ### p = plot(sin(x)) - p[0].line_color = lambda a : a + p[0].line_color = lambda a: a p.save(tmp_file('%s_colors_line_arity1.png' % name)) - p[0].line_color = lambda a, b : b + p[0].line_color = lambda a, b: b p.save(tmp_file('%s_colors_line_arity2.png' % name)) p = plot(x*sin(x), x*cos(x), (x, 0, 10)) - p[0].line_color = lambda a : a + p[0].line_color = lambda a: a p.save(tmp_file('%s_colors_param_line_arity1.png' % name)) - p[0].line_color = lambda a, b : a + p[0].line_color = lambda a, b: a p.save(tmp_file('%s_colors_param_line_arity2a.png' % name)) - p[0].line_color = lambda a, b : b + p[0].line_color = lambda a, b: b p.save(tmp_file('%s_colors_param_line_arity2b.png' % name)) - p = plot3d_parametric_line(sin(x)+0.1*sin(x)*cos(7*x), - cos(x)+0.1*cos(x)*cos(7*x), - 0.1*sin(7*x), - (x, 0 , 2*pi)) - p[0].line_color = lambda a : sin(4*a) + p = plot3d_parametric_line(sin(x) + 0.1*sin(x)*cos(7*x), + cos(x) + 0.1*cos(x)*cos(7*x), + 0.1*sin(7*x), + (x, 0, 2*pi)) + p[0].line_color = lambda a: sin(4*a) p.save(tmp_file('%s_colors_3d_line_arity1.png' % name)) - p[0].line_color = lambda a, b : b + p[0].line_color = lambda a, b: b p.save(tmp_file('%s_colors_3d_line_arity2.png' % name)) - p[0].line_color = lambda a, b, c : c + p[0].line_color = lambda a, b, c: c p.save(tmp_file('%s_colors_3d_line_arity3.png' % name)) p = plot3d(sin(x)*y, (x, 0, 6*pi), (y, -5, 5)) - p[0].surface_color = lambda a : a + p[0].surface_color = lambda a: a p.save(tmp_file('%s_colors_surface_arity1.png' % name)) - p[0].surface_color = lambda a, b : b + p[0].surface_color = lambda a, b: b p.save(tmp_file('%s_colors_surface_arity2.png' % name)) - p[0].surface_color = lambda a, b, c : c + p[0].surface_color = lambda a, b, c: c p.save(tmp_file('%s_colors_surface_arity3a.png' % name)) - p[0].surface_color = lambda a, b, c : sqrt((a-3*pi)**2+b**2) + p[0].surface_color = lambda a, b, c: sqrt((a - 3*pi)**2 + b**2) p.save(tmp_file('%s_colors_surface_arity3b.png' % name)) p = plot3d_parametric_surface(x * cos(4 * y), x * sin(4 * y), y, (x, -1, 1), (y, -1, 1)) - p[0].surface_color = lambda a : a + p[0].surface_color = lambda a: a p.save(tmp_file('%s_colors_param_surf_arity1.png' % name)) - p[0].surface_color = lambda a, b : a*b + p[0].surface_color = lambda a, b: a*b p.save(tmp_file('%s_colors_param_surf_arity2.png' % name)) - p[0].surface_color = lambda a, b, c : sqrt(a**2+b**2+c**2) + p[0].surface_color = lambda a, b, c: sqrt(a**2 + b**2 + c**2) p.save(tmp_file('%s_colors_param_surf_arity3.png' % name)) ### # Examples from the 'advanced' notebook ### - i = Integral(log((sin(x)**2+1)*sqrt(x**2+1)),(x,0,y)) - p = plot(i,(y, 1, 5)) + i = Integral(log((sin(x)**2 + 1)*sqrt(x**2 + 1)), (x, 0, y)) + p = plot(i, (y, 1, 5)) p.save(tmp_file('%s_advanced_integral.png' % name)) - s = summation(1/x**y,(x, 1, oo)) + s = summation(1/x**y, (x, 1, oo)) p = plot(s, (y, 2, 10)) p.save(tmp_file('%s_advanced_inf_sum.png' % name)) - p = plot(summation(1/x,(x,1,y)), (y, 2,10), show=False) + p = plot(summation(1/x, (x, 1, y)), (y, 2, 10), show=False) p[0].only_integers = True p[0].steps = True p.save(tmp_file('%s_advanced_fin_sum.png' % name)) - ### # Test expressions that can not be translated to np and generate complex # results. ### - - - plot(sin(x)+I*cos(x)).save(tmp_file()) + plot(sin(x) + I*cos(x)).save(tmp_file()) plot(sqrt(sqrt(-x))).save(tmp_file()) plot(LambertW(x)).save(tmp_file()) plot(sqrt(LambertW(x))).save(tmp_file()) + #Characteristic function of a StudentT distribution with nu=10 + plot((meijerg(((1 / 2,), ()), ((5, 0, 1 / 2), ()), 5 * x**2 * exp_polar(-I*pi)/2) + + meijerg(((1/2,), ()), ((5, 0, 1/2), ()), + 5*x**2 * exp_polar(I*pi)/2)) / (48 * pi), (x, 1e-6, 1e-2)).save(tmp_file()) + def test_matplotlib(): + matplotlib = import_module('matplotlib', min_module_version='1.1.0', catch=(RuntimeError,)) if matplotlib: plot_and_save('test') else: skip("Matplotlib not the default backend") + + +# Tests for exceptiion handling in experimental_lambdify +def test_experimental_lambify(): + x = Symbol('x') + lambdify([x], Max(x, 5)) + assert Max(2, 5) == 5 + assert Max(7, 5) == 7 diff -Nru python3-sympy-0.7.2/sympy/plotting/tests/test_plot_implicit.py python3-sympy-0.7.3/sympy/plotting/tests/test_plot_implicit.py --- python3-sympy-0.7.2/sympy/plotting/tests/test_plot_implicit.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/plotting/tests/test_plot_implicit.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,53 +1,59 @@ from sympy import (plot_implicit, cos, Symbol, Eq, sin, re, And, Or, exp, I, - tan) -from sympy.plotting.plot import matplotlib, unset_show + tan, pi) +from sympy.plotting.plot import unset_show from tempfile import NamedTemporaryFile from sympy.utilities.pytest import skip +from sympy.external import import_module #Set plots not to show unset_show() + def tmp_file(name=''): return NamedTemporaryFile(suffix='.png').name -def plot_and_save(): + +def plot_and_save(name): x = Symbol('x') y = Symbol('y') z = Symbol('z') #implicit plot tests - plot_implicit(Eq(y, cos(x)), (x, -5, 5), (y, -2, 2)).save(tmp_file()) + plot_implicit(Eq(y, cos(x)), (x, -5, 5), (y, -2, 2)).save(tmp_file(name)) plot_implicit(Eq(y**2, x**3 - x), (x, -5, 5), - (y, -4, 4)).save(tmp_file()) + (y, -4, 4)).save(tmp_file(name)) plot_implicit(y > 1 / x, (x, -5, 5), - (y, -2, 2)).save(tmp_file()) + (y, -2, 2)).save(tmp_file(name)) plot_implicit(y < 1 / tan(x), (x, -5, 5), - (y, -2, 2)).save(tmp_file()) + (y, -2, 2)).save(tmp_file(name)) plot_implicit(y >= 2 * sin(x) * cos(x), (x, -5, 5), - (y, -2, 2)).save(tmp_file()) + (y, -2, 2)).save(tmp_file(name)) plot_implicit(y <= x**2, (x, -3, 3), - (y, -1, 5)).save(tmp_file()) + (y, -1, 5)).save(tmp_file(name)) #Test all input args for plot_implicit plot_implicit(Eq(y**2, x**3 - x)).save(tmp_file()) plot_implicit(Eq(y**2, x**3 - x), adaptive=False).save(tmp_file()) - plot_implicit(Eq(y**2, x**3 - x), adaptive=False, points = 500).save(tmp_file()) + plot_implicit(Eq(y**2, x**3 - x), adaptive=False, points=500).save(tmp_file()) plot_implicit(y > x, (x, -5, 5)).save(tmp_file()) plot_implicit(And(y > exp(x), y > x + 2)).save(tmp_file()) plot_implicit(Or(y > x, y > -x)).save(tmp_file()) plot_implicit(x**2 - 1, (x, -5, 5)).save(tmp_file()) plot_implicit(x**2 - 1).save(tmp_file()) - plot_implicit(y > x, depth = -5).save(tmp_file()) - plot_implicit(y > x, depth = 5).save(tmp_file()) + plot_implicit(y > x, depth=-5).save(tmp_file()) + plot_implicit(y > x, depth=5).save(tmp_file()) plot_implicit(y > cos(x), adaptive=False).save(tmp_file()) plot_implicit(y < cos(x), adaptive=False).save(tmp_file()) plot_implicit(And(y > cos(x), Or(y > x, Eq(y, x)))).save(tmp_file()) + plot_implicit(y - cos(pi / x)).save(tmp_file()) #Test plots which cannot be rendered using the adaptive algorithm #TODO: catch the warning. - plot_implicit(Eq(y, re(cos(x) + I*sin(x)))).save(tmp_file()) + plot_implicit(Eq(y, re(cos(x) + I*sin(x)))).save(tmp_file(name)) + def test_matplotlib(): + matplotlib = import_module('matplotlib', min_module_version='1.1.0', catch=(RuntimeError,)) if matplotlib: - plot_and_save() + plot_and_save('test') else: skip("Matplotlib not the default backend") diff -Nru python3-sympy-0.7.2/sympy/plotting/textplot.py python3-sympy-0.7.3/sympy/plotting/textplot.py --- python3-sympy-0.7.2/sympy/plotting/textplot.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/plotting/textplot.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,5 +1,6 @@ from sympy import * + def textplot(expr, a, b, W=55, H=18): """ Print a crude ASCII art plot of the SymPy expression 'expr' (which @@ -23,8 +24,8 @@ y = [0] * W for x in range(W): try: - y[x] = f(a+(b-a)/float(W)*x) - except TypeError: + y[x] = f(a + (b - a)/float(W)*x) + except (TypeError, ValueError): y[x] = 0 # Normalize height to screen space @@ -36,21 +37,21 @@ else: mi, ma = -1, 1 for x in range(W): - y[x] = int(float(H)*(y[x]-mi)/(ma-mi)) + y[x] = int(float(H)*(y[x] - mi)/(ma - mi)) margin = 7 print() - for h in range(H-1, -1, -1): + for h in range(H - 1, -1, -1): s = [' '] * W for x in range(W): if y[x] == h: s[x] = '.' # Print y values - if h == H-1: + if h == H - 1: prefix = ("%g" % ma).rjust(margin)[:margin] elif h == H//2: - prefix = ("%g" % ((mi+ma)/2)).rjust(margin)[:margin] + prefix = ("%g" % ((mi + ma)/2)).rjust(margin)[:margin] elif h == 0: prefix = ("%g" % mi).rjust(margin)[:margin] else: @@ -62,7 +63,7 @@ # Print x values bottom = " " * (margin + 3) - bottom += ("%g" % a).ljust(W//2-4) - bottom += ("%g" % ((a+b)/2)).ljust(W//2) + bottom += ("%g" % a).ljust(W//2 - 4) + bottom += ("%g" % ((a + b)/2)).ljust(W//2) bottom += "%g" % b print(bottom) diff -Nru python3-sympy-0.7.2/sympy/polys/__init__.py python3-sympy-0.7.3/sympy/polys/__init__.py --- python3-sympy-0.7.2/sympy/polys/__init__.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/polys/__init__.py 2013-07-13 17:53:32.000000000 +0000 @@ -99,7 +99,7 @@ ) from .partfrac import ( - apart, + apart, apart_list, assemble_partfrac_list ) from .polyoptions import Options @@ -108,3 +108,6 @@ from .agca import ( homomorphism ) + +from .rings import ring +from .fields import field diff -Nru python3-sympy-0.7.2/sympy/polys/agca/homomorphisms.py python3-sympy-0.7.3/sympy/polys/agca/homomorphisms.py --- python3-sympy-0.7.2/sympy/polys/agca/homomorphisms.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/polys/agca/homomorphisms.py 2013-07-13 17:53:32.000000000 +0000 @@ -13,6 +13,7 @@ # The main computational task for module homomorphisms is kernels. # For this reason, the concrete classes are organised by domain module type. + class ModuleHomomorphism(object): """ Abstract base class for module homomoprhisms. Do not instantiate. @@ -23,8 +24,9 @@ >>> from sympy.abc import x >>> F = QQ[x].free_module(2) >>> homomorphism(F, F, [[1, 0], [0, 1]]) - [1, 0] - [0, 1] : QQ[x]**2 -> QQ[x]**2 + Matrix([ + [1, 0], : QQ[x]**2 -> QQ[x]**2 + [0, 1]]) Attributes: @@ -113,11 +115,11 @@ raise NotImplementedError def _quotient_domain(self, sm): - """Implementation of domain quotienting.""" + """Implementation of domain quotient.""" raise NotImplementedError def _quotient_codomain(self, sm): - """Implementation of codomain quotienting.""" + """Implementation of codomain quotient.""" raise NotImplementedError def restrict_domain(self, sm): @@ -131,18 +133,21 @@ >>> F = QQ[x].free_module(2) >>> h = homomorphism(F, F, [[1, 0], [x, 0]]) >>> h - [1, x] - [0, 0] : QQ[x]**2 -> QQ[x]**2 + Matrix([ + [1, x], : QQ[x]**2 -> QQ[x]**2 + [0, 0]]) >>> h.restrict_domain(F.submodule([1, 0])) - [1, x] - [0, 0] : <[1, 0]> -> QQ[x]**2 + Matrix([ + [1, x], : <[1, 0]> -> QQ[x]**2 + [0, 0]]) This is the same as just composing on the right with the submodule inclusion: >>> h * F.submodule([1, 0]).inclusion_hom() - [1, x] - [0, 0] : <[1, 0]> -> QQ[x]**2 + Matrix([ + [1, x], : <[1, 0]> -> QQ[x]**2 + [0, 0]]) """ if not self.domain.is_submodule(sm): raise ValueError('sm must be a submodule of %s, got %s' @@ -163,11 +168,13 @@ >>> F = QQ[x].free_module(2) >>> h = homomorphism(F, F, [[1, 0], [x, 0]]) >>> h - [1, x] - [0, 0] : QQ[x]**2 -> QQ[x]**2 + Matrix([ + [1, x], : QQ[x]**2 -> QQ[x]**2 + [0, 0]]) >>> h.restrict_codomain(F.submodule([1, 0])) - [1, x] - [0, 0] : QQ[x]**2 -> <[1, 0]> + Matrix([ + [1, x], : QQ[x]**2 -> <[1, 0]> + [0, 0]]) """ if not sm.is_submodule(self.image()): raise ValueError('the image %s must contain sm, got %s' @@ -187,11 +194,13 @@ >>> F = QQ[x].free_module(2) >>> h = homomorphism(F, F, [[1, 0], [x, 0]]) >>> h - [1, x] - [0, 0] : QQ[x]**2 -> QQ[x]**2 + Matrix([ + [1, x], : QQ[x]**2 -> QQ[x]**2 + [0, 0]]) >>> h.quotient_domain(F.submodule([-x, 1])) - [1, x] - [0, 0] : QQ[x]**2/<[-x, 1]> -> QQ[x]**2 + Matrix([ + [1, x], : QQ[x]**2/<[-x, 1]> -> QQ[x]**2 + [0, 0]]) """ if not self.kernel().is_submodule(sm): raise ValueError('kernel %s must contain sm, got %s' % @@ -211,17 +220,20 @@ >>> F = QQ[x].free_module(2) >>> h = homomorphism(F, F, [[1, 0], [x, 0]]) >>> h - [1, x] - [0, 0] : QQ[x]**2 -> QQ[x]**2 + Matrix([ + [1, x], : QQ[x]**2 -> QQ[x]**2 + [0, 0]]) >>> h.quotient_codomain(F.submodule([1, 1])) - [1, x] - [0, 0] : QQ[x]**2 -> QQ[x]**2/<[1, 1]> + Matrix([ + [1, x], : QQ[x]**2 -> QQ[x]**2/<[1, 1]> + [0, 0]]) This is the same as composing with the quotient map on the left: >>> (F/[(1, 1)]).quotient_hom() * h - [1, x] - [0, 0] : QQ[x]**2 -> QQ[x]**2/<[1, 1]> + Matrix([ + [1, x], : QQ[x]**2 -> QQ[x]**2/<[1, 1]> + [0, 0]]) """ if not self.codomain.is_submodule(sm): raise ValueError('sm must be a submodule of codomain %s, got %s' @@ -377,6 +389,7 @@ def __ne__(self, oth): return not (self == oth) + class MatrixHomomorphism(ModuleHomomorphism): """ Helper class for all homomoprhisms which are expressed via a matrix. @@ -427,16 +440,16 @@ return Matrix([[self.ring.to_sympy(y) for y in c(x)] for x in self.matrix]).T def __repr__(self): - lines = repr(self._sympy_matrix()).split('\n') - t = " : %s -> %s" % (self.domain, self.codomain) - s = ' '*len(t) - n = len(lines) - for i in range(n // 2): - lines[i] += s - lines[n // 2] += t - for i in range(n//2 + 1, n): - lines[i] += s - return '\n'.join(lines) + lines = repr(self._sympy_matrix()).split('\n') + t = " : %s -> %s" % (self.domain, self.codomain) + s = ' '*len(t) + n = len(lines) + for i in range(n // 2): + lines[i] += s + lines[n // 2] += t + for i in range(n//2 + 1, n): + lines[i] += s + return '\n'.join(lines) def _restrict_domain(self, sm): """Implementation of domain restriction.""" @@ -447,11 +460,11 @@ return self.__class__(self.domain, sm, self.matrix) def _quotient_domain(self, sm): - """Implementation of domain quotienting.""" + """Implementation of domain quotient.""" return self.__class__(self.domain/sm, self.codomain, self.matrix) def _quotient_codomain(self, sm): - """Implementation of codomain quotienting.""" + """Implementation of codomain quotient.""" Q = self.codomain/sm converter = Q.convert if isinstance(self.codomain, SubModule): @@ -469,6 +482,7 @@ def _compose(self, oth): return self.__class__(self.domain, oth.codomain, [oth(x) for x in self.matrix]) + class FreeModuleHomomorphism(MatrixHomomorphism): """ Concrete class for homomorphisms with domain a free module or a quotient @@ -481,8 +495,9 @@ >>> from sympy.abc import x >>> F = QQ[x].free_module(2) >>> homomorphism(F, F, [[1, 0], [0, 1]]) - [1, 0] - [0, 1] : QQ[x]**2 -> QQ[x]**2 + Matrix([ + [1, 0], : QQ[x]**2 -> QQ[x]**2 + [0, 1]]) """ def _apply(self, elem): @@ -502,6 +517,7 @@ syz = self.image().syzygy_module() return self.domain.submodule(*syz.gens) + class SubModuleHomomorphism(MatrixHomomorphism): """ Concrete class for homomorphism with domain a submodule of a free module @@ -514,8 +530,9 @@ >>> from sympy.abc import x >>> M = QQ[x].free_module(2)*x >>> homomorphism(M, M, [[1, 0], [0, 1]]) - [1, 0] - [0, 1] : <[x, 0], [0, x]> -> <[x, 0], [0, x]> + Matrix([ + [1, 0], : <[x, 0], [0, x]> -> <[x, 0], [0, x]> + [0, 1]]) """ def _apply(self, elem): @@ -532,6 +549,7 @@ *[sum(xi*gi for xi, gi in zip(s, self.domain.gens)) for s in syz.gens]) + def homomorphism(domain, codomain, matrix): r""" Create a homomorphism object. @@ -555,8 +573,9 @@ >>> F = R.free_module(2) >>> h = homomorphism(F, T, [[1, x], [x**2, 0]]) >>> h - [1, x**2] - [x, 0] : QQ[x]**2 -> QQ[x]**2 + Matrix([ + [1, x**2], : QQ[x]**2 -> QQ[x]**2 + [x, 0]]) >>> h([1, 0]) [1, x] >>> h([0, 1]) @@ -570,8 +589,9 @@ >>> S = F.submodule([1, 0], [0, x]) >>> homomorphism(S, T, [[1, x], [x**2, 0]]) - [1, x**2] - [x, 0] : <[1, 0], [0, x]> -> QQ[x]**2 + Matrix([ + [1, x**2], : <[1, 0], [0, x]> -> QQ[x]**2 + [x, 0]]) If ``domain`` is a (sub)quotient `N/K`, then ``matrix`` determines a homomorphism from `N` to ``codomain``. If the kernel contains `K`, this @@ -579,8 +599,9 @@ is raised. >>> homomorphism(S/[(1, 0)], T, [0, [x**2, 0]]) - [0, x**2] - [0, 0] : <[1, 0] + <[1, 0]>, [0, x] + <[1, 0]>, [1, 0] + <[1, 0]>> -> QQ[x]**2 + Matrix([ + [0, x**2], : <[1, 0] + <[1, 0]>, [0, x] + <[1, 0]>, [1, 0] + <[1, 0]>> -> QQ[x]**2 + [0, 0]]) >>> homomorphism(S/[(0, x)], T, [0, [x**2, 0]]) Traceback (most recent call last): ... diff -Nru python3-sympy-0.7.2/sympy/polys/agca/ideals.py python3-sympy-0.7.3/sympy/polys/agca/ideals.py --- python3-sympy-0.7.2/sympy/polys/agca/ideals.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/polys/agca/ideals.py 2013-07-13 17:53:32.000000000 +0000 @@ -3,6 +3,7 @@ from sympy.polys.polyerrors import CoercionFailed from functools import reduce + class Ideal(object): """ Abstract base class for ideals. @@ -108,7 +109,8 @@ def _check_ideal(self, J): """Helper to check ``J`` is an ideal of our ring.""" if not isinstance(J, Ideal) or J.ring != self.ring: - raise ValueError('J must be an ideal of %s, got %s' % (self.ring, J)) + raise ValueError( + 'J must be an ideal of %s, got %s' % (self.ring, J)) def contains(self, elem): """ @@ -256,6 +258,7 @@ def __ne__(self, e): return not (self == e) + class ModuleImplementedIdeal(Ideal): """ Ideal implementation relying on the modules code. @@ -341,7 +344,7 @@ if not isinstance(J, ModuleImplementedIdeal): raise NotImplementedError return self.__class__(self.ring, self._module.submodule( - *[[x*y] for [x] in self._module.gens for [y] in J._module.gens])) + *[[x*y] for [x] in self._module.gens for [y] in J._module.gens])) def in_terms_of_generators(self, e): """ diff -Nru python3-sympy-0.7.2/sympy/polys/agca/modules.py python3-sympy-0.7.3/sympy/polys/agca/modules.py --- python3-sympy-0.7.2/sympy/polys/agca/modules.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/polys/agca/modules.py 2013-07-13 17:53:32.000000000 +0000 @@ -38,6 +38,7 @@ ## Abstract base classes ################################################# ########################################################################## + class Module(object): """ Abstract base class for modules. @@ -152,6 +153,7 @@ """Return the identity homomorphism on ``self``.""" raise NotImplementedError + class ModuleElement(object): """ Base class for module element wrappers. @@ -253,6 +255,7 @@ ## Free Modules ########################################################## ########################################################################## + class FreeModuleElement(ModuleElement): """Element of a free module. Data stored as a tuple.""" @@ -275,6 +278,7 @@ def __getitem__(self, idx): return self.data[idx] + class FreeModule(Module): """ Abstract base class for free modules. @@ -414,12 +418,14 @@ >>> from sympy.abc import x >>> from sympy import QQ >>> QQ[x].free_module(2).identity_hom() - [1, 0] - [0, 1] : QQ[x]**2 -> QQ[x]**2 + Matrix([ + [1, 0], : QQ[x]**2 -> QQ[x]**2 + [0, 1]]) """ from sympy.polys.agca.homomorphisms import homomorphism return homomorphism(self, self, self.basis()) + class FreeModulePolyRing(FreeModule): """ Free module over a generalized polynomial ring. @@ -438,7 +444,7 @@ """ def __init__(self, ring, rank): - from sympy.polys.domains.polynomialring import PolynomialRingBase + from sympy.polys.domains.old_polynomialring import PolynomialRingBase FreeModule.__init__(self, ring, rank) if not isinstance(ring, PolynomialRingBase): raise NotImplementedError('This implementation only works over ' @@ -463,6 +469,7 @@ """ return SubModulePolyRing(gens, self, **opts) + class FreeModuleQuotientRing(FreeModule): """ Free module over a quotient ring. @@ -552,6 +559,7 @@ ## Submodules and subquotients ########################################### ########################################################################## + class SubModule(Module): """ Base class for submodules. @@ -657,7 +665,8 @@ if not isinstance(other, SubModule): raise TypeError('%s is not a SubModule' % other) if other.container != self.container: - raise ValueError('%s is contained in a different free module' % other) + raise ValueError( + '%s is contained in a different free module' % other) return self._intersect(other, **options) def module_quotient(self, other, **options): @@ -693,7 +702,8 @@ if not isinstance(other, SubModule): raise TypeError('%s is not a SubModule' % other) if other.container != self.container: - raise ValueError('%s is contained in a different free module' % other) + raise ValueError( + '%s is contained in a different free module' % other) return self._module_quotient(other, **options) def union(self, other): @@ -711,7 +721,8 @@ if not isinstance(other, SubModule): raise TypeError('%s is not a SubModule' % other) if other.container != self.container: - raise ValueError('%s is contained in a different free module' % other) + raise ValueError( + '%s is contained in a different free module' % other) return self.__class__(self.gens + other.gens, self.container) def is_zero(self): @@ -774,7 +785,7 @@ """ if isinstance(other, SubModule): return self.container == other.container and \ - all(self.contains(x) for x in other.gens) + all(self.contains(x) for x in other.gens) if isinstance(other, (FreeModule, QuotientModule)): return self.container == other and self.is_full_module() return False @@ -888,8 +899,9 @@ >>> from sympy.abc import x >>> from sympy import QQ >>> QQ[x].free_module(2).submodule([x, x]).inclusion_hom() - [1, 0] - [0, 1] : <[x, x]> -> QQ[x]**2 + Matrix([ + [1, 0], : <[x, x]> -> QQ[x]**2 + [0, 1]]) """ return self.container.identity_hom().restrict_domain(self) @@ -900,12 +912,14 @@ >>> from sympy.abc import x >>> from sympy import QQ >>> QQ[x].free_module(2).submodule([x, x]).identity_hom() - [1, 0] - [0, 1] : <[x, x]> -> <[x, x]> + Matrix([ + [1, 0], : <[x, x]> -> <[x, x]> + [0, 1]]) """ return self.container.identity_hom().restrict_domain( self).restrict_codomain(self) + class SubQuotientModule(SubModule): """ Submodule of a quotient module. @@ -926,7 +940,7 @@ Attributes: - base - base module we are quotient of - - killed_module - submodule we are quotienting by + - killed_module - submodule used to form the quotient """ def __init__(self, gens, container, **opts): SubModule.__init__(self, gens, container) @@ -934,7 +948,7 @@ # XXX it is important for some code below that the generators of base # are in this particular order! self.base = self.container.base.submodule( - *[x.data for x in self.gens], **opts).union(self.killed_module) + *[x.data for x in self.gens], **opts).union(self.killed_module) def _contains(self, elem): return self.base.contains(elem.data) @@ -980,14 +994,17 @@ >>> from sympy import QQ >>> M = (QQ[x].free_module(2) / [(1, x)]).submodule([1, 0]) >>> M.quotient_hom() - [1, 0] - [0, 1] : <[1, 0], [1, x]> -> <[1, 0] + <[1, x]>, [1, x] + <[1, x]>> + Matrix([ + [1, 0], : <[1, 0], [1, x]> -> <[1, 0] + <[1, x]>, [1, x] + <[1, x]>> + [0, 1]]) """ return self.base.identity_hom().quotient_codomain(self.killed_module) _subs0 = lambda x: x[0] _subs1 = lambda x: x[1:] + + class ModuleOrder(ProductOrder): """A product monomial order with a zeroth term as module index.""" @@ -997,6 +1014,7 @@ else: ProductOrder.__init__(self, (o1, _subs0), (o2, _subs1)) + class SubModulePolyRing(SubModule): """ Submodule of a free module over a generalized polynomial ring. @@ -1036,12 +1054,12 @@ from sympy.polys.distributedmodules import sdm_groebner, sdm_nf_mora if self._gbe is None and extended: gb, gbe = sdm_groebner( - [self.ring._vector_to_sdm(x, self.order) for x in self.gens], - sdm_nf_mora, self.order, self.ring.dom, extended=True) + [self.ring._vector_to_sdm(x, self.order) for x in self.gens], + sdm_nf_mora, self.order, self.ring.dom, extended=True) self._gb, self._gbe = tuple(gb), tuple(gbe) if self._gb is None: self._gb = tuple(sdm_groebner( - [self.ring._vector_to_sdm(x, self.order) for x in self.gens], + [self.ring._vector_to_sdm(x, self.order) for x in self.gens], sdm_nf_mora, self.order, self.ring.dom)) if extended: return self._gb, self._gbe @@ -1058,12 +1076,11 @@ for x in gb], [self.ring._sdm_to_vector(x, len(self.gens)) for x in gbe]) - def _contains(self, x): from sympy.polys.distributedmodules import sdm_zero, sdm_nf_mora return sdm_nf_mora(self.ring._vector_to_sdm(x, self.order), self._groebner(), self.order, self.ring.dom) == \ - sdm_zero() + sdm_zero() def _syzygies(self): """Compute syzygies. See [SCA, algorithm 2.5.4].""" @@ -1078,7 +1095,7 @@ Rkr = self.ring.free_module(r + k) newgens = [] for j, f in enumerate(self.gens): - m = [0]*(r+k) + m = [0]*(r + k) for i, v in enumerate(f): m[i] = f[i] for i in range(k): @@ -1092,7 +1109,8 @@ G = F._groebner_vec() # Third bullet point: G0 = G intersect the new k components - G0 = [x[r:] for x in G if all(y == self.ring.convert(0) for y in x[:r])] + G0 = [x[r:] for x in G if all(y == self.ring.convert(0) + for y in x[:r])] # Fourth and fifth bullet points: we are done return G0 @@ -1101,7 +1119,8 @@ """Expression in terms of generators. See [SCA, 2.8.1].""" # NOTE: if gens is a standard basis, this can be done more efficiently M = self.ring.free_module(self.rank).submodule(*((e,) + self.gens)) - S = M.syzygy_module(order="ilex", TOP=False) # We want decreasing order! + S = M.syzygy_module( + order="ilex", TOP=False) # We want decreasing order! G = S._groebner_vec() # This list cannot not be empty since e is an element e = list([x for x in G if self.ring.is_unit(x[0])])[0] @@ -1118,15 +1137,15 @@ if NF is None: NF = sdm_nf_mora return self.container.convert(self.ring._sdm_to_vector(NF( - self.ring._vector_to_sdm(x, self.order), self._groebner(), - self.order, self.ring.dom), - self.rank)) + self.ring._vector_to_sdm(x, self.order), self._groebner(), + self.order, self.ring.dom), + self.rank)) def _intersect(self, other, relations=False): # See: [SCA, section 2.8.2] fi = self.gens hi = other.gens - r = self.rank + r = self.rank ci = [[0]*(2*r) for _ in range(r)] for k in range(r): ci[k][k] = 1 @@ -1136,8 +1155,8 @@ syz = self.ring.free_module(2*r).submodule(*(ci + di + ei))._syzygies() nonzero = [x for x in syz if any(y != self.ring.zero for y in x[:r])] res = self.container.submodule(*([-y for y in x[:r]] for x in nonzero)) - reln1 = [x[r:r+len(fi)] for x in nonzero] - reln2 = [x[r+len(fi):] for x in nonzero] + reln1 = [x[r:r + len(fi)] for x in nonzero] + reln2 = [x[r + len(fi):] for x in nonzero] if relations: return res, reln1, reln2 return res @@ -1174,6 +1193,7 @@ return reduce(lambda x, y: x.intersect(y), (self._module_quotient(self.container.submodule(x)) for x in other.gens)) + class SubModuleQuotientRing(SubModule): """ Class for submodules of free modules over quotient rings. @@ -1205,16 +1225,17 @@ def _syzygies(self): return [tuple(self.ring.convert(y, self.quot.ring) for y in x) - for x in self.quot._syzygies()] + for x in self.quot._syzygies()] def _in_terms_of_generators(self, elem): - return [self.ring.convert(x, self.quot.ring) for x in \ + return [self.ring.convert(x, self.quot.ring) for x in self.quot._in_terms_of_generators(self.container.lift(elem))] ########################################################################## ## Quotient Modules ###################################################### ########################################################################## + class QuotientModuleElement(ModuleElement): """Element of a quotient module.""" @@ -1226,6 +1247,7 @@ from sympy import sstr return repr(self.data) + " + " + repr(self.module.killed_module) + class QuotientModule(Module): """ Class for quotient modules. @@ -1236,7 +1258,7 @@ Attributes: - base - the base module we are a quotient of - - killed_module - the submodule we are quotienting by + - killed_module - the submodule used to form the quotient - rank of the base """ @@ -1285,7 +1307,7 @@ """ if isinstance(other, QuotientModule): return self.killed_module == other.killed_module and \ - self.base.is_submodule(other.base) + self.base.is_submodule(other.base) if isinstance(other, SubQuotientModule): return other.container == self return False @@ -1334,8 +1356,9 @@ >>> from sympy import QQ >>> M = QQ[x].free_module(2) / [(1, 2), (1, x)] >>> M.identity_hom() - [1, 0] - [0, 1] : QQ[x]**2/<[1, 2], [1, x]> -> QQ[x]**2/<[1, 2], [1, x]> + Matrix([ + [1, 0], : QQ[x]**2/<[1, 2], [1, x]> -> QQ[x]**2/<[1, 2], [1, x]> + [0, 1]]) """ return self.base.identity_hom().quotient_codomain( self.killed_module).quotient_domain(self.killed_module) @@ -1351,8 +1374,9 @@ >>> from sympy import QQ >>> M = QQ[x].free_module(2) / [(1, 2), (1, x)] >>> M.quotient_hom() - [1, 0] - [0, 1] : QQ[x]**2 -> QQ[x]**2/<[1, 2], [1, x]> + Matrix([ + [1, 0], : QQ[x]**2 -> QQ[x]**2/<[1, 2], [1, x]> + [0, 1]]) """ return self.base.identity_hom().quotient_codomain( self.killed_module) diff -Nru python3-sympy-0.7.2/sympy/polys/agca/tests/test_homomorphisms.py python3-sympy-0.7.3/sympy/polys/agca/tests/test_homomorphisms.py --- python3-sympy-0.7.2/sympy/polys/agca/tests/test_homomorphisms.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/polys/agca/tests/test_homomorphisms.py 2013-07-13 17:53:32.000000000 +0000 @@ -4,16 +4,17 @@ from sympy.abc import x, y from sympy.utilities.pytest import raises + def test_printing(): R = QQ[x] assert str(homomorphism(R.free_module(1), R.free_module(1), [0])) == \ - '[0] : QQ[x]**1 -> QQ[x]**1' + 'Matrix([[0]]) : QQ[x]**1 -> QQ[x]**1' assert str(homomorphism(R.free_module(2), R.free_module(2), [0, 0])) == \ - '[0, 0] \n[0, 0] : QQ[x]**2 -> QQ[x]**2' + 'Matrix([ \n[0, 0], : QQ[x]**2 -> QQ[x]**2\n[0, 0]]) ' assert str(homomorphism(R.free_module(1), R.free_module(1) / [[x]], [0])) == \ - '[0] : QQ[x]**1 -> QQ[x]**1/<[x]>' - assert str(R.free_module(0).identity_hom()) == '[] : QQ[x]**0 -> QQ[x]**0' + 'Matrix([[0]]) : QQ[x]**1 -> QQ[x]**1/<[x]>' + assert str(R.free_module(0).identity_hom()) == 'Matrix(0, 0, []) : QQ[x]**0 -> QQ[x]**0' def test_operations(): F = QQ[x].free_module(2) @@ -49,6 +50,7 @@ raises(TypeError, lambda: f - 1) raises(TypeError, lambda: f*i) + def test_creation(): F = QQ[x].free_module(3) G = QQ[x].free_module(2) @@ -75,15 +77,21 @@ assert SQ.quotient_hom() == homomorphism(SQ.base, SQ, im) class conv(object): - def convert(x, y=None): return x + def convert(x, y=None): + return x + class dummy(object): container = conv() - def submodule(*args): return None + + def submodule(*args): + return None raises(TypeError, lambda: homomorphism(dummy(), G, matrix)) raises(TypeError, lambda: homomorphism(F, dummy(), matrix)) - raises(ValueError, lambda: homomorphism(QQ[x, y].free_module(3), G, matrix)) + raises( + ValueError, lambda: homomorphism(QQ[x, y].free_module(3), G, matrix)) raises(ValueError, lambda: homomorphism(F, G, [0, 0])) + def test_properties(): R = QQ[x, y] F = R.free_module(2) @@ -94,7 +102,8 @@ assert not h.is_surjective() assert h.restrict_codomain(h.image()).is_surjective() assert h.restrict_domain(F.submodule([1, 0])).is_injective() - assert h.quotient_domain(h.kernel()).restrict_codomain(h.image()).is_isomorphism() + assert h.quotient_domain( + h.kernel()).restrict_codomain(h.image()).is_isomorphism() R2 = QQ.poly_ring(x, y, order=(("lex", x), ("ilex", y))) / [x**2 + 1] F = R2.free_module(2) diff -Nru python3-sympy-0.7.2/sympy/polys/agca/tests/test_ideals.py python3-sympy-0.7.3/sympy/polys/agca/tests/test_ideals.py --- python3-sympy-0.7.2/sympy/polys/agca/tests/test_ideals.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/polys/agca/tests/test_ideals.py 2013-07-13 17:53:32.000000000 +0000 @@ -4,12 +4,13 @@ from sympy.abc import x, y, z from sympy.utilities.pytest import raises + def test_ideal_operations(): R = QQ[x, y] I = R.ideal(x) J = R.ideal(y) S = R.ideal(x*y) - T = R.ideal(x,y) + T = R.ideal(x, y) assert not (I == J) assert I == I @@ -45,6 +46,7 @@ assert T**2 == R.ideal(x**2, y**2, x*y) assert I**5 == R.ideal(x**5) + def test_exceptions(): I = QQ[x].ideal(x) J = QQ[y].ideal(1) @@ -55,8 +57,10 @@ assert (I == J) is False assert I != J + def test_nontriv_global(): R = QQ[x, y, z] + def contains(I, f): return R.ideal(*I).contains(f) @@ -65,24 +69,28 @@ assert not contains([x, y], 1) assert not contains([x, y], z) assert contains([x**2 + y, x**2 + x], x - y) - assert not contains([x+y+z, x*y+x*z+y*z, x*y*z], x**2) - assert contains([x+y+z, x*y+x*z+y*z, x*y*z], x**3) - assert contains([x+y+z, x*y+x*z+y*z, x*y*z], x**4) - assert not contains([x+y+z, x*y+x*z+y*z, x*y*z], x*y**2) - assert contains([x+y+z, x*y+x*z+y*z, x*y*z], x**4 + y**3 + 2*z*y*x) - assert contains([x+y+z, x*y+x*z+y*z, x*y*z], x*y*z) - assert contains([x, 1+x+y, 5-7*y], 1) - assert contains([x**3+y**3, y**3+z**3, z**3+x**3, x**2*y + x**2*z + y**2*z], - x**3) - assert not contains([x**3+y**3, y**3+z**3, z**3+x**3, x**2*y + x**2*z + y**2*z], - x**2 + y**2) + assert not contains([x + y + z, x*y + x*z + y*z, x*y*z], x**2) + assert contains([x + y + z, x*y + x*z + y*z, x*y*z], x**3) + assert contains([x + y + z, x*y + x*z + y*z, x*y*z], x**4) + assert not contains([x + y + z, x*y + x*z + y*z, x*y*z], x*y**2) + assert contains([x + y + z, x*y + x*z + y*z, x*y*z], x**4 + y**3 + 2*z*y*x) + assert contains([x + y + z, x*y + x*z + y*z, x*y*z], x*y*z) + assert contains([x, 1 + x + y, 5 - 7*y], 1) + assert contains( + [x**3 + y**3, y**3 + z**3, z**3 + x**3, x**2*y + x**2*z + y**2*z], + x**3) + assert not contains( + [x**3 + y**3, y**3 + z**3, z**3 + x**3, x**2*y + x**2*z + y**2*z], + x**2 + y**2) # compare local order - assert not contains([x*(1+x+y), y*(1+z)], x) - assert not contains([x*(1+x+y), y*(1+z)], x + y) + assert not contains([x*(1 + x + y), y*(1 + z)], x) + assert not contains([x*(1 + x + y), y*(1 + z)], x + y) + def test_nontriv_local(): R = QQ.poly_ring(x, y, z, order=ilex) + def contains(I, f): return R.ideal(*I).contains(f) @@ -91,9 +99,10 @@ assert not contains([x, y], 1) assert not contains([x, y], z) assert contains([x**2 + y, x**2 + x], x - y) - assert not contains([x+y+z, x*y+x*z+y*z, x*y*z], x**2) - assert contains([x*(1+x+y), y*(1+z)], x) - assert contains([x*(1+x+y), y*(1+z)], x + y) + assert not contains([x + y + z, x*y + x*z + y*z, x*y*z], x**2) + assert contains([x*(1 + x + y), y*(1 + z)], x) + assert contains([x*(1 + x + y), y*(1 + z)], x + y) + def test_intersection(): R = QQ[x, y, z] @@ -104,13 +113,15 @@ R = QQ.poly_ring(x, y, z, order="ilex") assert R.ideal(x, y).intersect(R.ideal(y**2 + y**2*z, z + z*x**3*y)) == \ - R.ideal(y**2, y*z, x*z) + R.ideal(y**2, y*z, x*z) + def test_quotient(): # SCA, example 1.8.13 R = QQ[x, y, z] assert R.ideal(x, y).quotient(R.ideal(y**2, z)) == R.ideal(x, y) + def test_reduction(): from sympy.polys.distributedmodules import sdm_nf_buchberger_reduced R = QQ[x, y] diff -Nru python3-sympy-0.7.2/sympy/polys/agca/tests/test_modules.py python3-sympy-0.7.3/sympy/polys/agca/tests/test_modules.py --- python3-sympy-0.7.2/sympy/polys/agca/tests/test_modules.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/polys/agca/tests/test_modules.py 2013-07-13 17:53:32.000000000 +0000 @@ -6,6 +6,7 @@ from sympy.utilities.pytest import raises from sympy import S + def test_FreeModuleElement(): M = QQ[x].free_module(3) e = M.convert([1, x, x**2]) @@ -27,6 +28,7 @@ R = QQ.poly_ring(x, order="ilex") assert R.free_module(1).convert([x]) / R.convert(x) == [1] + def test_FreeModule(): M1 = FreeModule(QQ[x], 2) assert M1 == FreeModule(QQ[x], 2) @@ -77,9 +79,11 @@ raises(NotImplementedError, lambda: ZZ[x].free_module(2)) raises(NotImplementedError, lambda: FreeModulePolyRing(ZZ, 2)) - raises(CoercionFailed, lambda: M1.convert(QQ[x].free_module(3).convert([1, 2, 3]))) + raises(CoercionFailed, lambda: M1.convert(QQ[x].free_module(3) + .convert([1, 2, 3]))) raises(CoercionFailed, lambda: M3.convert(1)) + def test_ModuleOrder(): o1 = ModuleOrder(lex, grlex, False) o2 = ModuleOrder(ilex, lex, False) @@ -91,6 +95,7 @@ assert o1((1, 2, 3)) == (1, (5, (2, 3))) assert o2((1, 2, 3)) == (-1, (2, 3)) + def test_SubModulePolyRing_global(): R = QQ[x, y] F = R.free_module(3) @@ -130,10 +135,11 @@ assert F.submodule([x, x, x]) != F.submodule([x, x, x], order="ilex") + def test_SubModulePolyRing_local(): R = QQ.poly_ring(x, y, order=ilex) F = R.free_module(3) - Fd = F.submodule([1+x, 0, 0], [1+y, 2+2*y, 0], [1, 2, 3]) + Fd = F.submodule([1 + x, 0, 0], [1 + y, 2 + 2*y, 0], [1, 2, 3]) M = F.submodule([x**2 + y**2, 1, 0], [x, y, 1]) assert F == Fd @@ -155,13 +161,16 @@ assert M.contains([y**2, 1 - x*y, -x]) assert F.submodule([1 + x, 0, 0]) == F.submodule([1, 0, 0]) - assert F.submodule([1, 0, 0], [0, 1, 0]).union(F.submodule([0, 0, 1 + x*y])) == F + assert F.submodule( + [1, 0, 0], [0, 1, 0]).union(F.submodule([0, 0, 1 + x*y])) == F raises(ValueError, lambda: M.submodule([1, 0, 0])) + def test_SubModulePolyRing_nontriv_global(): R = QQ[x, y, z] F = R.free_module(1) + def contains(I, f): return F.submodule(*[[g] for g in I]).contains([f]) @@ -170,25 +179,29 @@ assert not contains([x, y], 1) assert not contains([x, y], z) assert contains([x**2 + y, x**2 + x], x - y) - assert not contains([x+y+z, x*y+x*z+y*z, x*y*z], x**2) - assert contains([x+y+z, x*y+x*z+y*z, x*y*z], x**3) - assert contains([x+y+z, x*y+x*z+y*z, x*y*z], x**4) - assert not contains([x+y+z, x*y+x*z+y*z, x*y*z], x*y**2) - assert contains([x+y+z, x*y+x*z+y*z, x*y*z], x**4 + y**3 + 2*z*y*x) - assert contains([x+y+z, x*y+x*z+y*z, x*y*z], x*y*z) - assert contains([x, 1+x+y, 5-7*y], 1) - assert contains([x**3+y**3, y**3+z**3, z**3+x**3, x**2*y + x**2*z + y**2*z], - x**3) - assert not contains([x**3+y**3, y**3+z**3, z**3+x**3, x**2*y + x**2*z + y**2*z], - x**2 + y**2) + assert not contains([x + y + z, x*y + x*z + y*z, x*y*z], x**2) + assert contains([x + y + z, x*y + x*z + y*z, x*y*z], x**3) + assert contains([x + y + z, x*y + x*z + y*z, x*y*z], x**4) + assert not contains([x + y + z, x*y + x*z + y*z, x*y*z], x*y**2) + assert contains([x + y + z, x*y + x*z + y*z, x*y*z], x**4 + y**3 + 2*z*y*x) + assert contains([x + y + z, x*y + x*z + y*z, x*y*z], x*y*z) + assert contains([x, 1 + x + y, 5 - 7*y], 1) + assert contains( + [x**3 + y**3, y**3 + z**3, z**3 + x**3, x**2*y + x**2*z + y**2*z], + x**3) + assert not contains( + [x**3 + y**3, y**3 + z**3, z**3 + x**3, x**2*y + x**2*z + y**2*z], + x**2 + y**2) # compare local order - assert not contains([x*(1+x+y), y*(1+z)], x) - assert not contains([x*(1+x+y), y*(1+z)], x + y) + assert not contains([x*(1 + x + y), y*(1 + z)], x) + assert not contains([x*(1 + x + y), y*(1 + z)], x + y) + def test_SubModulePolyRing_nontriv_local(): R = QQ.poly_ring(x, y, z, order=ilex) F = R.free_module(1) + def contains(I, f): return F.submodule(*[[g] for g in I]).contains([f]) @@ -197,9 +210,10 @@ assert not contains([x, y], 1) assert not contains([x, y], z) assert contains([x**2 + y, x**2 + x], x - y) - assert not contains([x+y+z, x*y+x*z+y*z, x*y*z], x**2) - assert contains([x*(1+x+y), y*(1+z)], x) - assert contains([x*(1+x+y), y*(1+z)], x + y) + assert not contains([x + y + z, x*y + x*z + y*z, x*y*z], x**2) + assert contains([x*(1 + x + y), y*(1 + z)], x) + assert contains([x*(1 + x + y), y*(1 + z)], x + y) + def test_syzygy(): R = QQ[x, y, z] @@ -219,10 +233,12 @@ S3 = R2.free_module(3).submodule([z, 0, 0], [0, x, 0], [0, 0, y]) assert M3.syzygy_module() == S3 + def test_in_terms_of_generators(): R = QQ.poly_ring(x, order="ilex") M = R.free_module(2).submodule([2*x, 0], [1, 2]) - assert M.in_terms_of_generators([x, x]) == [R.convert(S(1)/4), R.convert(x/2)] + assert M.in_terms_of_generators( + [x, x]) == [R.convert(S(1)/4), R.convert(x/2)] raises(ValueError, lambda: M.in_terms_of_generators([1, 0])) M = R.free_module(2) / ([x, 0], [1, 1]) @@ -232,7 +248,9 @@ R = QQ[x, y] / [x**2 - y**2] M = R.free_module(2) SM = M.submodule([x, 0], [0, y]) - assert SM.in_terms_of_generators([x**2, x**2]) == [R.convert(x), R.convert(y)] + assert SM.in_terms_of_generators( + [x**2, x**2]) == [R.convert(x), R.convert(y)] + def test_QuotientModuleElement(): R = QQ[x] @@ -241,18 +259,18 @@ M = F/N e = M.convert([x**2, 2, 0]) - assert M.convert([x+1, x**2+x, x**3+x**2]) == 0 + assert M.convert([x + 1, x**2 + x, x**3 + x**2]) == 0 assert e == [x**2, 2, 0] + N == F.convert([x**2, 2, 0]) + N == \ - M.convert(F.convert([x**2, 2, 0])) + M.convert(F.convert([x**2, 2, 0])) assert M.convert([x**2 + 1, 2*x + 2, x**2]) == e + [0, x, 0] == \ - e + M.convert([0, x, 0]) == e + F.convert([0, x, 0]) + e + M.convert([0, x, 0]) == e + F.convert([0, x, 0]) assert M.convert([x**2 + 1, 2, x**2]) == e - [0, x, 0] == \ - e - M.convert([0, x, 0]) == e - F.convert([0, x, 0]) + e - M.convert([0, x, 0]) == e - F.convert([0, x, 0]) assert M.convert([0, 2, 0]) == M.convert([x**2, 4, 0]) - e == \ - [x**2, 4, 0] - e == F.convert([x**2, 4, 0]) - e + [x**2, 4, 0] - e == F.convert([x**2, 4, 0]) - e assert M.convert([x**3 + x**2, 2*x + 2, 0]) == (1 + x)*e == \ - R.convert(1 + x)*e == e*(1 + x) == e*R.convert(1 + x) + R.convert(1 + x)*e == e*(1 + x) == e*R.convert(1 + x) assert -e == [-x**2, -2, 0] f = [x, x, 0] + N @@ -268,6 +286,7 @@ assert M2.convert(M.convert([2, x, x**2])) == [2, x, 0] assert M.convert(M4.convert([2, 0, 0])) == [2, 0, 0] + def test_QuotientModule(): R = QQ[x] F = R.free_module(3) @@ -296,6 +315,7 @@ M2 = M1.submodule([1, 0, 0], [0, 1, 0]) assert M1 == M2 + def test_ModulesQuotientRing(): R = QQ.poly_ring(x, y, order=(("lex", x), ("ilex", y))) / [x**2 + 1] M1 = R.free_module(2) @@ -338,6 +358,7 @@ assert F.submodule([1, 0, 0], [0, 1, 0]).union(F.submodule([0, 0, 1])) == F assert not M.is_submodule(0) + def test_module_mul(): R = QQ[x] M = R.free_module(2) @@ -348,6 +369,7 @@ assert I*M == M*I == S1 == x*M == M*x assert I*S1 == S2 == x*S1 + def test_intersection(): # SCA, example 2.8.5 F = QQ[x, y].free_module(2) @@ -362,12 +384,13 @@ assert F.submodule([x, y]).intersect(F.submodule([y, x])).is_zero() + def test_quotient(): # SCA, example 2.8.6 R = QQ[x, y, z] F = R.free_module(2) assert F.submodule([x*y, x*z], [y*z, x*y]).module_quotient( - F.submodule([y,z], [z,y])) == QQ[x, y, z].ideal(x**2*y**2 - x*y*z**2) + F.submodule([y, z], [z, y])) == QQ[x, y, z].ideal(x**2*y**2 - x*y*z**2) assert F.submodule([x, y]).module_quotient(F.submodule()).is_whole_ring() M = F.submodule([x**2, x**2], [y**2, y**2]) @@ -377,8 +400,9 @@ for i, g in enumerate(q.gens): assert g*N.gens[0] == sum(c*x for c, x in zip(rel[i], M.gens)) + def test_groebner_extendend(): - M = QQ[x,y,z].free_module(3).submodule([x + 1, y, 1], [x*y, z, z**2]) + M = QQ[x, y, z].free_module(3).submodule([x + 1, y, 1], [x*y, z, z**2]) G, R = M._groebner_vec(extended=True) for i, g in enumerate(G): assert g == sum(c*gen for c, gen in zip(R[i], M.gens)) diff -Nru python3-sympy-0.7.2/sympy/polys/compatibility.py python3-sympy-0.7.3/sympy/polys/compatibility.py --- python3-sympy-0.7.2/sympy/polys/compatibility.py 1970-01-01 00:00:00.000000000 +0000 +++ python3-sympy-0.7.3/sympy/polys/compatibility.py 2013-07-13 17:53:32.000000000 +0000 @@ -0,0 +1,1106 @@ +"""Compatibility interface between dense and sparse polys. """ + +from sympy.polys.densearith import dup_add_term +from sympy.polys.densearith import dmp_add_term +from sympy.polys.densearith import dup_sub_term +from sympy.polys.densearith import dmp_sub_term +from sympy.polys.densearith import dup_mul_term +from sympy.polys.densearith import dmp_mul_term +from sympy.polys.densearith import dup_add_ground +from sympy.polys.densearith import dmp_add_ground +from sympy.polys.densearith import dup_sub_ground +from sympy.polys.densearith import dmp_sub_ground +from sympy.polys.densearith import dup_mul_ground +from sympy.polys.densearith import dmp_mul_ground +from sympy.polys.densearith import dup_quo_ground +from sympy.polys.densearith import dmp_quo_ground +from sympy.polys.densearith import dup_exquo_ground +from sympy.polys.densearith import dmp_exquo_ground +from sympy.polys.densearith import dup_lshift +from sympy.polys.densearith import dup_rshift +from sympy.polys.densearith import dup_abs +from sympy.polys.densearith import dmp_abs +from sympy.polys.densearith import dup_neg +from sympy.polys.densearith import dmp_neg +from sympy.polys.densearith import dup_add +from sympy.polys.densearith import dmp_add +from sympy.polys.densearith import dup_sub +from sympy.polys.densearith import dmp_sub +from sympy.polys.densearith import dup_add_mul +from sympy.polys.densearith import dmp_add_mul +from sympy.polys.densearith import dup_sub_mul +from sympy.polys.densearith import dmp_sub_mul +from sympy.polys.densearith import dup_mul +from sympy.polys.densearith import dmp_mul +from sympy.polys.densearith import dup_sqr +from sympy.polys.densearith import dmp_sqr +from sympy.polys.densearith import dup_pow +from sympy.polys.densearith import dmp_pow +from sympy.polys.densearith import dup_pdiv +from sympy.polys.densearith import dup_prem +from sympy.polys.densearith import dup_pquo +from sympy.polys.densearith import dup_pexquo +from sympy.polys.densearith import dmp_pdiv +from sympy.polys.densearith import dmp_prem +from sympy.polys.densearith import dmp_pquo +from sympy.polys.densearith import dmp_pexquo +from sympy.polys.densearith import dup_rr_div +from sympy.polys.densearith import dmp_rr_div +from sympy.polys.densearith import dup_ff_div +from sympy.polys.densearith import dmp_ff_div +from sympy.polys.densearith import dup_div +from sympy.polys.densearith import dup_rem +from sympy.polys.densearith import dup_quo +from sympy.polys.densearith import dup_exquo +from sympy.polys.densearith import dmp_div +from sympy.polys.densearith import dmp_rem +from sympy.polys.densearith import dmp_quo +from sympy.polys.densearith import dmp_exquo +from sympy.polys.densearith import dup_max_norm +from sympy.polys.densearith import dmp_max_norm +from sympy.polys.densearith import dup_l1_norm +from sympy.polys.densearith import dmp_l1_norm +from sympy.polys.densearith import dup_expand +from sympy.polys.densearith import dmp_expand +from sympy.polys.densebasic import dup_LC +from sympy.polys.densebasic import dmp_LC +from sympy.polys.densebasic import dup_TC +from sympy.polys.densebasic import dmp_TC +from sympy.polys.densebasic import dmp_ground_LC +from sympy.polys.densebasic import dmp_ground_TC +from sympy.polys.densebasic import dup_degree +from sympy.polys.densebasic import dmp_degree +from sympy.polys.densebasic import dmp_degree_in +from sympy.polys.densebasic import dmp_to_dict +from sympy.polys.densetools import dup_integrate +from sympy.polys.densetools import dmp_integrate +from sympy.polys.densetools import dmp_integrate_in +from sympy.polys.densetools import dup_diff +from sympy.polys.densetools import dmp_diff +from sympy.polys.densetools import dmp_diff_in +from sympy.polys.densetools import dup_eval +from sympy.polys.densetools import dmp_eval +from sympy.polys.densetools import dmp_eval_in +from sympy.polys.densetools import dmp_eval_tail +from sympy.polys.densetools import dmp_diff_eval_in +from sympy.polys.densetools import dup_trunc +from sympy.polys.densetools import dmp_trunc +from sympy.polys.densetools import dmp_ground_trunc +from sympy.polys.densetools import dup_monic +from sympy.polys.densetools import dmp_ground_monic +from sympy.polys.densetools import dup_content +from sympy.polys.densetools import dmp_ground_content +from sympy.polys.densetools import dup_primitive +from sympy.polys.densetools import dmp_ground_primitive +from sympy.polys.densetools import dup_extract +from sympy.polys.densetools import dmp_ground_extract +from sympy.polys.densetools import dup_real_imag +from sympy.polys.densetools import dup_mirror +from sympy.polys.densetools import dup_scale +from sympy.polys.densetools import dup_shift +from sympy.polys.densetools import dup_transform +from sympy.polys.densetools import dup_compose +from sympy.polys.densetools import dmp_compose +from sympy.polys.densetools import dup_decompose +from sympy.polys.densetools import dmp_lift +from sympy.polys.densetools import dup_sign_variations +from sympy.polys.densetools import dup_clear_denoms +from sympy.polys.densetools import dmp_clear_denoms +from sympy.polys.densetools import dup_revert +from sympy.polys.euclidtools import dup_half_gcdex +from sympy.polys.euclidtools import dmp_half_gcdex +from sympy.polys.euclidtools import dup_gcdex +from sympy.polys.euclidtools import dmp_gcdex +from sympy.polys.euclidtools import dup_invert +from sympy.polys.euclidtools import dmp_invert +from sympy.polys.euclidtools import dup_euclidean_prs +from sympy.polys.euclidtools import dmp_euclidean_prs +from sympy.polys.euclidtools import dup_primitive_prs +from sympy.polys.euclidtools import dmp_primitive_prs +from sympy.polys.euclidtools import dup_inner_subresultants +from sympy.polys.euclidtools import dup_subresultants +from sympy.polys.euclidtools import dup_prs_resultant +from sympy.polys.euclidtools import dup_resultant +from sympy.polys.euclidtools import dmp_inner_subresultants +from sympy.polys.euclidtools import dmp_subresultants +from sympy.polys.euclidtools import dmp_prs_resultant +from sympy.polys.euclidtools import dmp_zz_modular_resultant +from sympy.polys.euclidtools import dmp_zz_collins_resultant +from sympy.polys.euclidtools import dmp_qq_collins_resultant +from sympy.polys.euclidtools import dmp_resultant +from sympy.polys.euclidtools import dup_discriminant +from sympy.polys.euclidtools import dmp_discriminant +from sympy.polys.euclidtools import dup_rr_prs_gcd +from sympy.polys.euclidtools import dup_ff_prs_gcd +from sympy.polys.euclidtools import dmp_rr_prs_gcd +from sympy.polys.euclidtools import dmp_ff_prs_gcd +from sympy.polys.euclidtools import dup_zz_heu_gcd +from sympy.polys.euclidtools import dmp_zz_heu_gcd +from sympy.polys.euclidtools import dup_qq_heu_gcd +from sympy.polys.euclidtools import dmp_qq_heu_gcd +from sympy.polys.euclidtools import dup_inner_gcd +from sympy.polys.euclidtools import dmp_inner_gcd +from sympy.polys.euclidtools import dup_gcd +from sympy.polys.euclidtools import dmp_gcd +from sympy.polys.euclidtools import dup_rr_lcm +from sympy.polys.euclidtools import dup_ff_lcm +from sympy.polys.euclidtools import dup_lcm +from sympy.polys.euclidtools import dmp_rr_lcm +from sympy.polys.euclidtools import dmp_ff_lcm +from sympy.polys.euclidtools import dmp_lcm +from sympy.polys.euclidtools import dmp_content +from sympy.polys.euclidtools import dmp_primitive +from sympy.polys.euclidtools import dup_cancel +from sympy.polys.euclidtools import dmp_cancel +from sympy.polys.factortools import dup_trial_division +from sympy.polys.factortools import dmp_trial_division +from sympy.polys.factortools import dup_zz_mignotte_bound +from sympy.polys.factortools import dmp_zz_mignotte_bound +from sympy.polys.factortools import dup_zz_hensel_step +from sympy.polys.factortools import dup_zz_hensel_lift +from sympy.polys.factortools import dup_zz_zassenhaus +from sympy.polys.factortools import dup_zz_irreducible_p +from sympy.polys.factortools import dup_cyclotomic_p +from sympy.polys.factortools import dup_zz_cyclotomic_poly +from sympy.polys.factortools import dup_zz_cyclotomic_factor +from sympy.polys.factortools import dup_zz_factor_sqf +from sympy.polys.factortools import dup_zz_factor +from sympy.polys.factortools import dmp_zz_wang_non_divisors +from sympy.polys.factortools import dmp_zz_wang_lead_coeffs +from sympy.polys.factortools import dup_zz_diophantine +from sympy.polys.factortools import dmp_zz_diophantine +from sympy.polys.factortools import dmp_zz_wang_hensel_lifting +from sympy.polys.factortools import dmp_zz_wang +from sympy.polys.factortools import dmp_zz_factor +from sympy.polys.factortools import dup_ext_factor +from sympy.polys.factortools import dmp_ext_factor +from sympy.polys.factortools import dup_gf_factor +from sympy.polys.factortools import dmp_gf_factor +from sympy.polys.factortools import dup_factor_list +from sympy.polys.factortools import dup_factor_list_include +from sympy.polys.factortools import dmp_factor_list +from sympy.polys.factortools import dmp_factor_list_include +from sympy.polys.factortools import dup_irreducible_p +from sympy.polys.factortools import dmp_irreducible_p +from sympy.polys.rootisolation import dup_sturm +from sympy.polys.rootisolation import dup_root_upper_bound +from sympy.polys.rootisolation import dup_root_lower_bound +from sympy.polys.rootisolation import dup_step_refine_real_root +from sympy.polys.rootisolation import dup_inner_refine_real_root +from sympy.polys.rootisolation import dup_outer_refine_real_root +from sympy.polys.rootisolation import dup_refine_real_root +from sympy.polys.rootisolation import dup_inner_isolate_real_roots +from sympy.polys.rootisolation import dup_inner_isolate_positive_roots +from sympy.polys.rootisolation import dup_inner_isolate_negative_roots +from sympy.polys.rootisolation import dup_isolate_real_roots_sqf +from sympy.polys.rootisolation import dup_isolate_real_roots +from sympy.polys.rootisolation import dup_isolate_real_roots_list +from sympy.polys.rootisolation import dup_count_real_roots +from sympy.polys.rootisolation import dup_count_complex_roots +from sympy.polys.rootisolation import dup_isolate_complex_roots_sqf +from sympy.polys.rootisolation import dup_isolate_all_roots_sqf +from sympy.polys.rootisolation import dup_isolate_all_roots + +from sympy.polys.sqfreetools import ( + dup_sqf_p, dmp_sqf_p, dup_sqf_norm, dmp_sqf_norm, dup_gf_sqf_part, dmp_gf_sqf_part, + dup_sqf_part, dmp_sqf_part, dup_gf_sqf_list, dmp_gf_sqf_list, dup_sqf_list, + dup_sqf_list_include, dmp_sqf_list, dmp_sqf_list_include, dup_gff_list, dmp_gff_list) + +from sympy.polys.galoistools import ( + gf_degree, gf_LC, gf_TC, gf_strip, gf_trunc, gf_normal, gf_from_dict, + gf_to_dict, gf_from_int_poly, gf_to_int_poly, gf_neg, gf_add_ground, gf_sub_ground, + gf_mul_ground, gf_quo_ground, gf_add, gf_sub, gf_mul, gf_sqr, gf_add_mul, gf_sub_mul, + gf_expand, gf_div, gf_rem, gf_quo, gf_exquo, gf_lshift, gf_rshift, gf_pow, gf_pow_mod, + gf_gcd, gf_lcm, gf_cofactors, gf_gcdex, gf_monic, gf_diff, gf_eval, gf_multi_eval, + gf_compose, gf_compose_mod, gf_trace_map, gf_random, gf_irreducible, gf_irred_p_ben_or, + gf_irred_p_rabin, gf_irreducible_p, gf_sqf_p, gf_sqf_part, gf_sqf_list, gf_Qmatrix, + gf_Qbasis, gf_berlekamp, gf_ddf_zassenhaus, gf_edf_zassenhaus, gf_ddf_shoup, gf_edf_shoup, + gf_zassenhaus, gf_shoup, gf_factor_sqf, gf_factor, gf_value, gf_csolve) + + +class IPolys(object): + symbols = None + ngens = None + domain = None + order = None + gens = None + + def drop(self, gen): + pass + + def clone(self, symbols=None, domain=None, order=None): + pass + + def to_ground(self): + pass + + def ground_new(self, element): + pass + + def domain_new(self, element): + pass + + def from_dict(self, d): + pass + + def wrap(self, element): + from sympy.polys.rings import PolyElement + if isinstance(element, PolyElement): + if element.ring == self: + return element + else: + raise NotImplementedError("domain conversions") + else: + return self.ground_new(element) + + def to_dense(self, element): + return self.wrap(element).to_dense() + + def from_dense(self, element): + return self.from_dict(dmp_to_dict(element, self.ngens-1, self.domain)) + + def dup_add_term(self, f, c, i): + return self.from_dense(dup_add_term(self.to_dense(f), c, i, self.domain)) + def dmp_add_term(self, f, c, i): + return self.from_dense(dmp_add_term(self.to_dense(f), self.wrap(c).drop(0).to_dense(), i, self.ngens-1, self.domain)) + def dup_sub_term(self, f, c, i): + return self.from_dense(dup_sub_term(self.to_dense(f), c, i, self.domain)) + def dmp_sub_term(self, f, c, i): + return self.from_dense(dmp_sub_term(self.to_dense(f), self.wrap(c).drop(0).to_dense(), i, self.ngens-1, self.domain)) + def dup_mul_term(self, f, c, i): + return self.from_dense(dup_mul_term(self.to_dense(f), c, i, self.domain)) + def dmp_mul_term(self, f, c, i): + return self.from_dense(dmp_mul_term(self.to_dense(f), self.wrap(c).drop(0).to_dense(), i, self.ngens-1, self.domain)) + + def dup_add_ground(self, f, c): + return self.from_dense(dup_add_ground(self.to_dense(f), c, self.domain)) + def dmp_add_ground(self, f, c): + return self.from_dense(dmp_add_ground(self.to_dense(f), c, self.ngens-1, self.domain)) + def dup_sub_ground(self, f, c): + return self.from_dense(dup_sub_ground(self.to_dense(f), c, self.domain)) + def dmp_sub_ground(self, f, c): + return self.from_dense(dmp_sub_ground(self.to_dense(f), c, self.ngens-1, self.domain)) + def dup_mul_ground(self, f, c): + return self.from_dense(dup_mul_ground(self.to_dense(f), c, self.domain)) + def dmp_mul_ground(self, f, c): + return self.from_dense(dmp_mul_ground(self.to_dense(f), c, self.ngens-1, self.domain)) + def dup_quo_ground(self, f, c): + return self.from_dense(dup_quo_ground(self.to_dense(f), c, self.domain)) + def dmp_quo_ground(self, f, c): + return self.from_dense(dmp_quo_ground(self.to_dense(f), c, self.ngens-1, self.domain)) + def dup_exquo_ground(self, f, c): + return self.from_dense(dup_exquo_ground(self.to_dense(f), c, self.domain)) + def dmp_exquo_ground(self, f, c): + return self.from_dense(dmp_exquo_ground(self.to_dense(f), c, self.ngens-1, self.domain)) + + def dup_lshift(self, f, n): + return self.from_dense(dup_lshift(self.to_dense(f), n, self.domain)) + def dup_rshift(self, f, n): + return self.from_dense(dup_rshift(self.to_dense(f), n, self.domain)) + + def dup_abs(self, f): + return self.from_dense(dup_abs(self.to_dense(f), self.domain)) + def dmp_abs(self, f): + return self.from_dense(dmp_abs(self.to_dense(f), self.ngens-1, self.domain)) + + def dup_neg(self, f): + return self.from_dense(dup_neg(self.to_dense(f), self.domain)) + def dmp_neg(self, f): + return self.from_dense(dmp_neg(self.to_dense(f), self.ngens-1, self.domain)) + + def dup_add(self, f, g): + return self.from_dense(dup_add(self.to_dense(f), self.to_dense(g), self.domain)) + def dmp_add(self, f, g): + return self.from_dense(dmp_add(self.to_dense(f), self.to_dense(g), self.ngens-1, self.domain)) + + def dup_sub(self, f, g): + return self.from_dense(dup_sub(self.to_dense(f), self.to_dense(g), self.domain)) + def dmp_sub(self, f, g): + return self.from_dense(dmp_sub(self.to_dense(f), self.to_dense(g), self.ngens-1, self.domain)) + + def dup_add_mul(self, f, g, h): + return self.from_dense(dup_add_mul(self.to_dense(f), self.to_dense(g), self.to_dense(h), self.domain)) + def dmp_add_mul(self, f, g, h): + return self.from_dense(dmp_add_mul(self.to_dense(f), self.to_dense(g), self.to_dense(h), self.ngens-1, self.domain)) + def dup_sub_mul(self, f, g, h): + return self.from_dense(dup_sub_mul(self.to_dense(f), self.to_dense(g), self.to_dense(h), self.domain)) + def dmp_sub_mul(self, f, g, h): + return self.from_dense(dmp_sub_mul(self.to_dense(f), self.to_dense(g), self.to_dense(h), self.ngens-1, self.domain)) + + def dup_mul(self, f, g): + return self.from_dense(dup_mul(self.to_dense(f), self.to_dense(g), self.domain)) + def dmp_mul(self, f, g): + return self.from_dense(dmp_mul(self.to_dense(f), self.to_dense(g), self.ngens-1, self.domain)) + + def dup_sqr(self, f): + return self.from_dense(dup_sqr(self.to_dense(f), self.domain)) + def dmp_sqr(self, f): + return self.from_dense(dmp_sqr(self.to_dense(f), self.ngens-1, self.domain)) + def dup_pow(self, f, n): + return self.from_dense(dup_pow(self.to_dense(f), n, self.domain)) + def dmp_pow(self, f, n): + return self.from_dense(dmp_pow(self.to_dense(f), n, self.ngens-1, self.domain)) + + def dup_pdiv(self, f, g): + q, r = dup_pdiv(self.to_dense(f), self.to_dense(g), self.domain) + return (self.from_dense(q), self.from_dense(r)) + def dup_prem(self, f, g): + return self.from_dense(dup_prem(self.to_dense(f), self.to_dense(g), self.domain)) + def dup_pquo(self, f, g): + return self.from_dense(dup_pquo(self.to_dense(f), self.to_dense(g), self.domain)) + def dup_pexquo(self, f, g): + return self.from_dense(dup_pexquo(self.to_dense(f), self.to_dense(g), self.domain)) + + def dmp_pdiv(self, f, g): + q, r = dmp_pdiv(self.to_dense(f), self.to_dense(g), self.ngens-1, self.domain) + return (self.from_dense(q), self.from_dense(r)) + def dmp_prem(self, f, g): + return self.from_dense(dmp_prem(self.to_dense(f), self.to_dense(g), self.ngens-1, self.domain)) + def dmp_pquo(self, f, g): + return self.from_dense(dmp_pquo(self.to_dense(f), self.to_dense(g), self.ngens-1, self.domain)) + def dmp_pexquo(self, f, g): + return self.from_dense(dmp_pexquo(self.to_dense(f), self.to_dense(g), self.ngens-1, self.domain)) + + def dup_rr_div(self, f, g): + q, r = dup_rr_div(self.to_dense(f), self.to_dense(g), self.domain) + return (self.from_dense(q), self.from_dense(r)) + def dmp_rr_div(self, f, g): + q, r = dmp_rr_div(self.to_dense(f), self.to_dense(g), self.ngens-1, self.domain) + return (self.from_dense(q), self.from_dense(r)) + def dup_ff_div(self, f, g): + q, r = dup_ff_div(self.to_dense(f), self.to_dense(g), self.domain) + return (self.from_dense(q), self.from_dense(r)) + def dmp_ff_div(self, f, g): + q, r = dmp_ff_div(self.to_dense(f), self.to_dense(g), self.ngens-1, self.domain) + return (self.from_dense(q), self.from_dense(r)) + + def dup_div(self, f, g): + q, r = dup_div(self.to_dense(f), self.to_dense(g), self.domain) + return (self.from_dense(q), self.from_dense(r)) + def dup_rem(self, f, g): + return self.from_dense(dup_rem(self.to_dense(f), self.to_dense(g), self.domain)) + def dup_quo(self, f, g): + return self.from_dense(dup_quo(self.to_dense(f), self.to_dense(g), self.domain)) + def dup_exquo(self, f, g): + return self.from_dense(dup_exquo(self.to_dense(f), self.to_dense(g), self.domain)) + + def dmp_div(self, f, g): + q, r = dmp_div(self.to_dense(f), self.to_dense(g), self.ngens-1, self.domain) + return (self.from_dense(q), self.from_dense(r)) + def dmp_rem(self, f, g): + return self.from_dense(dmp_rem(self.to_dense(f), self.to_dense(g), self.ngens-1, self.domain)) + def dmp_quo(self, f, g): + return self.from_dense(dmp_quo(self.to_dense(f), self.to_dense(g), self.ngens-1, self.domain)) + def dmp_exquo(self, f, g): + return self.from_dense(dmp_exquo(self.to_dense(f), self.to_dense(g), self.ngens-1, self.domain)) + + def dup_max_norm(self, f): + return dup_max_norm(self.to_dense(f), self.domain) + def dmp_max_norm(self, f): + return dmp_max_norm(self.to_dense(f), self.ngens-1, self.domain) + + def dup_l1_norm(self, f): + return dup_l1_norm(self.to_dense(f), self.domain) + def dmp_l1_norm(self, f): + return dmp_l1_norm(self.to_dense(f), self.ngens-1, self.domain) + + def dup_expand(self, polys): + return self.from_dense(dup_expand(list(map(self.to_dense, polys)), self.domain)) + def dmp_expand(self, polys): + return self.from_dense(dmp_expand(list(map(self.to_dense, polys)), self.ngens-1, self.domain)) + + def dup_LC(self, f): + return dup_LC(self.to_dense(f), self.domain) + def dmp_LC(self, f): + LC = dmp_LC(self.to_dense(f), self.domain) + if isinstance(LC, list): + return self[1:].from_dense(LC) + else: + return LC + def dup_TC(self, f): + return dup_TC(self.to_dense(f), self.domain) + def dmp_TC(self, f): + TC = dmp_TC(self.to_dense(f), self.domain) + if isinstance(TC, list): + return self[1:].from_dense(TC) + else: + return TC + + def dmp_ground_LC(self, f): + return dmp_ground_LC(self.to_dense(f), self.ngens-1, self.domain) + def dmp_ground_TC(self, f): + return dmp_ground_TC(self.to_dense(f), self.ngens-1, self.domain) + + def dup_degree(self, f): + return dup_degree(self.to_dense(f)) + def dmp_degree(self, f): + return dmp_degree(self.to_dense(f), self.ngens-1) + def dmp_degree_in(self, f, j): + return dmp_degree_in(self.to_dense(f), j, self.ngens-1) + def dup_integrate(self, f, m): + return self.from_dense(dup_integrate(self.to_dense(f), m, self.domain)) + def dmp_integrate(self, f, m): + return self.from_dense(dmp_integrate(self.to_dense(f), m, self.ngens-1, self.domain)) + + def dup_diff(self, f, m): + return self.from_dense(dup_diff(self.to_dense(f), m, self.domain)) + def dmp_diff(self, f, m): + return self.from_dense(dmp_diff(self.to_dense(f), m, self.ngens-1, self.domain)) + + def dmp_diff_in(self, f, m, j): + return self.from_dense(dmp_diff_in(self.to_dense(f), m, j, self.ngens-1, self.domain)) + def dmp_integrate_in(self, f, m, j): + return self.from_dense(dmp_integrate_in(self.to_dense(f), m, j, self.ngens-1, self.domain)) + + def dup_eval(self, f, a): + return dup_eval(self.to_dense(f), a, self.domain) + def dmp_eval(self, f, a): + result = dmp_eval(self.to_dense(f), a, self.ngens-1, self.domain) + return self[1:].from_dense(result) + + def dmp_eval_in(self, f, a, j): + result = dmp_eval_in(self.to_dense(f), a, j, self.ngens-1, self.domain) + return self.drop(j).from_dense(result) + def dmp_diff_eval_in(self, f, m, a, j): + result = dmp_diff_eval_in(self.to_dense(f), m, a, j, self.ngens-1, self.domain) + return self.drop(j).from_dense(result) + + def dmp_eval_tail(self, f, A): + result = dmp_eval_tail(self.to_dense(f), A, self.ngens-1, self.domain) + if isinstance(result, list): + return self[:-len(A)].from_dense(result) + else: + return result + + def dup_trunc(self, f, p): + return self.from_dense(dup_trunc(self.to_dense(f), p, self.domain)) + def dmp_trunc(self, f, g): + return self.from_dense(dmp_trunc(self.to_dense(f), self[1:].to_dense(g), self.ngens-1, self.domain)) + def dmp_ground_trunc(self, f, p): + return self.from_dense(dmp_ground_trunc(self.to_dense(f), p, self.ngens-1, self.domain)) + + def dup_monic(self, f): + return self.from_dense(dup_monic(self.to_dense(f), self.domain)) + def dmp_ground_monic(self, f): + return self.from_dense(dmp_ground_monic(self.to_dense(f), self.ngens-1, self.domain)) + + def dup_extract(self, f, g): + c, F, G = dup_extract(self.to_dense(f), self.to_dense(g), self.domain) + return (c, self.from_dense(F), self.from_dense(G)) + def dmp_ground_extract(self, f, g): + c, F, G = dmp_ground_extract(self.to_dense(f), self.to_dense(g), self.ngens-1, self.domain) + return (c, self.from_dense(F), self.from_dense(G)) + + def dup_real_imag(self, f): + p, q = dup_real_imag(self.wrap(f).drop(1).to_dense(), self.domain) + return (self.from_dense(p), self.from_dense(q)) + + def dup_mirror(self, f): + return self.from_dense(dup_mirror(self.to_dense(f), self.domain)) + def dup_scale(self, f, a): + return self.from_dense(dup_scale(self.to_dense(f), a, self.domain)) + def dup_shift(self, f, a): + return self.from_dense(dup_shift(self.to_dense(f), a, self.domain)) + def dup_transform(self, f, p, q): + return self.from_dense(dup_transform(self.to_dense(f), self.to_dense(p), self.to_dense(q), self.domain)) + + def dup_compose(self, f, g): + return self.from_dense(dup_compose(self.to_dense(f), self.to_dense(g), self.domain)) + def dmp_compose(self, f, g): + return self.from_dense(dmp_compose(self.to_dense(f), self.to_dense(g), self.ngens-1, self.domain)) + + def dup_decompose(self, f): + components = dup_decompose(self.to_dense(f), self.domain) + return list(map(self.from_dense, components)) + + def dmp_lift(self, f): + result = dmp_lift(self.to_dense(f), self.ngens-1, self.domain) + return self.to_ground().from_dense(result) + + def dup_sign_variations(self, f): + return dup_sign_variations(self.to_dense(f), self.domain) + + def dup_clear_denoms(self, f, convert=False): + c, F = dup_clear_denoms(self.to_dense(f), self.domain, convert=convert) + if convert: + ring = self.clone(domain=self.domain.get_ring()) + else: + ring = self + return (c, ring.from_dense(F)) + def dmp_clear_denoms(self, f, convert=False): + c, F = dmp_clear_denoms(self.to_dense(f), self.ngens-1, self.domain, convert=convert) + if convert: + ring = self.clone(domain=self.domain.get_ring()) + else: + ring = self + return (c, ring.from_dense(F)) + + def dup_revert(self, f, n): + return self.from_dense(dup_revert(self.to_dense(f), n, self.domain)) + + def dup_half_gcdex(self, f, g): + s, h = dup_half_gcdex(self.to_dense(f), self.to_dense(g), self.domain) + return (self.from_dense(s), self.from_dense(h)) + def dmp_half_gcdex(self, f, g): + s, h = dmp_half_gcdex(self.to_dense(f), self.to_dense(g), self.ngens-1, self.domain) + return (self.from_dense(s), self.from_dense(h)) + def dup_gcdex(self, f, g): + s, t, h = dup_gcdex(self.to_dense(f), self.to_dense(g), self.domain) + return (self.from_dense(s), self.from_dense(t), self.from_dense(h)) + def dmp_gcdex(self, f, g): + s, t, h = dmp_gcdex(self.to_dense(f), self.to_dense(g), self.ngens-1, self.domain) + return (self.from_dense(s), self.from_dense(t), self.from_dense(h)) + + def dup_invert(self, f, g): + return self.from_dense(dup_invert(self.to_dense(f), self.to_dense(g), self.domain)) + def dmp_invert(self, f, g): + return self.from_dense(dmp_invert(self.to_dense(f), self.to_dense(g), self.ngens-1, self.domain)) + + def dup_euclidean_prs(self, f, g): + prs = dup_euclidean_prs(self.to_dense(f), self.to_dense(g), self.domain) + return list(map(self.from_dense, prs)) + def dmp_euclidean_prs(self, f, g): + prs = dmp_euclidean_prs(self.to_dense(f), self.to_dense(g), self.ngens-1, self.domain) + return list(map(self.from_dense, prs)) + def dup_primitive_prs(self, f, g): + prs = dup_primitive_prs(self.to_dense(f), self.to_dense(g), self.domain) + return list(map(self.from_dense, prs)) + def dmp_primitive_prs(self, f, g): + prs = dmp_primitive_prs(self.to_dense(f), self.to_dense(g), self.ngens-1, self.domain) + return list(map(self.from_dense, prs)) + + def dup_inner_subresultants(self, f, g): + prs, beta, delta = dup_inner_subresultants(self.to_dense(f), self.to_dense(g), self.domain) + return (list(map(self.from_dense, prs)), beta, delta) + def dmp_inner_subresultants(self, f, g): + prs, beta, delta = dmp_inner_subresultants(self.to_dense(f), self.to_dense(g), self.ngens-1, self.domain) + return (list(map(self.from_dense, prs)), beta, delta) + + def dup_subresultants(self, f, g): + prs = dup_subresultants(self.to_dense(f), self.to_dense(g), self.domain) + return list(map(self.from_dense, prs)) + def dmp_subresultants(self, f, g): + prs = dmp_subresultants(self.to_dense(f), self.to_dense(g), self.ngens-1, self.domain) + return list(map(self.from_dense, prs)) + + def dup_prs_resultant(self, f, g): + res, prs = dup_prs_resultant(self.to_dense(f), self.to_dense(g), self.domain) + return (res, list(map(self.from_dense, prs))) + def dmp_prs_resultant(self, f, g): + res, prs = dmp_prs_resultant(self.to_dense(f), self.to_dense(g), self.ngens-1, self.domain) + return (self[1:].from_dense(res), list(map(self.from_dense, prs))) + + def dmp_zz_modular_resultant(self, f, g, p): + res = dmp_zz_modular_resultant(self.to_dense(f), self.to_dense(g), self.domain_new(p), self.ngens-1, self.domain) + return self[1:].from_dense(res) + def dmp_zz_collins_resultant(self, f, g): + res = dmp_zz_collins_resultant(self.to_dense(f), self.to_dense(g), self.ngens-1, self.domain) + return self[1:].from_dense(res) + def dmp_qq_collins_resultant(self, f, g): + res = dmp_qq_collins_resultant(self.to_dense(f), self.to_dense(g), self.ngens-1, self.domain) + return self[1:].from_dense(res) + + def dup_resultant(self, f, g): #, includePRS=False): + return dup_resultant(self.to_dense(f), self.to_dense(g), self.domain) #, includePRS=includePRS) + def dmp_resultant(self, f, g): #, includePRS=False): + res = dmp_resultant(self.to_dense(f), self.to_dense(g), self.ngens-1, self.domain) #, includePRS=includePRS) + if isinstance(res, list): + return self[1:].from_dense(res) + else: + return res + + def dup_discriminant(self, f): + return dup_discriminant(self.to_dense(f), self.domain) + def dmp_discriminant(self, f): + disc = dmp_discriminant(self.to_dense(f), self.ngens-1, self.domain) + if isinstance(disc, list): + return self[1:].from_dense(disc) + else: + return disc + + def dup_rr_prs_gcd(self, f, g): + H, F, G = dup_rr_prs_gcd(self.to_dense(f), self.to_dense(g), self.domain) + return (self.from_dense(H), self.from_dense(F), self.from_dense(G)) + def dup_ff_prs_gcd(self, f, g): + H, F, G = dup_ff_prs_gcd(self.to_dense(f), self.to_dense(g), self.domain) + return (self.from_dense(H), self.from_dense(F), self.from_dense(G)) + def dmp_rr_prs_gcd(self, f, g): + H, F, G = dmp_rr_prs_gcd(self.to_dense(f), self.to_dense(g), self.ngens-1, self.domain) + return (self.from_dense(H), self.from_dense(F), self.from_dense(G)) + def dmp_ff_prs_gcd(self, f, g): + H, F, G = dmp_ff_prs_gcd(self.to_dense(f), self.to_dense(g), self.ngens-1, self.domain) + return (self.from_dense(H), self.from_dense(F), self.from_dense(G)) + def dup_zz_heu_gcd(self, f, g): + H, F, G = dup_zz_heu_gcd(self.to_dense(f), self.to_dense(g), self.domain) + return (self.from_dense(H), self.from_dense(F), self.from_dense(G)) + def dmp_zz_heu_gcd(self, f, g): + H, F, G = dmp_zz_heu_gcd(self.to_dense(f), self.to_dense(g), self.ngens-1, self.domain) + return (self.from_dense(H), self.from_dense(F), self.from_dense(G)) + def dup_qq_heu_gcd(self, f, g): + H, F, G = dup_qq_heu_gcd(self.to_dense(f), self.to_dense(g), self.domain) + return (self.from_dense(H), self.from_dense(F), self.from_dense(G)) + def dmp_qq_heu_gcd(self, f, g): + H, F, G = dmp_qq_heu_gcd(self.to_dense(f), self.to_dense(g), self.ngens-1, self.domain) + return (self.from_dense(H), self.from_dense(F), self.from_dense(G)) + def dup_inner_gcd(self, f, g): + H, F, G = dup_inner_gcd(self.to_dense(f), self.to_dense(g), self.domain) + return (self.from_dense(H), self.from_dense(F), self.from_dense(G)) + def dmp_inner_gcd(self, f, g): + H, F, G = dmp_inner_gcd(self.to_dense(f), self.to_dense(g), self.ngens-1, self.domain) + return (self.from_dense(H), self.from_dense(F), self.from_dense(G)) + def dup_gcd(self, f, g): + H = dup_gcd(self.to_dense(f), self.to_dense(g), self.domain) + return self.from_dense(H) + def dmp_gcd(self, f, g): + H = dmp_gcd(self.to_dense(f), self.to_dense(g), self.ngens-1, self.domain) + return self.from_dense(H) + def dup_rr_lcm(self, f, g): + H = dup_rr_lcm(self.to_dense(f), self.to_dense(g), self.domain) + return self.from_dense(H) + def dup_ff_lcm(self, f, g): + H = dup_ff_lcm(self.to_dense(f), self.to_dense(g), self.domain) + return self.from_dense(H) + def dup_lcm(self, f, g): + H = dup_lcm(self.to_dense(f), self.to_dense(g), self.domain) + return self.from_dense(H) + def dmp_rr_lcm(self, f, g): + H = dmp_rr_lcm(self.to_dense(f), self.to_dense(g), self.ngens-1, self.domain) + return self.from_dense(H) + def dmp_ff_lcm(self, f, g): + H = dmp_ff_lcm(self.to_dense(f), self.to_dense(g), self.ngens-1, self.domain) + return self.from_dense(H) + def dmp_lcm(self, f, g): + H = dmp_lcm(self.to_dense(f), self.to_dense(g), self.ngens-1, self.domain) + return self.from_dense(H) + + def dup_content(self, f): + cont = dup_content(self.to_dense(f), self.domain) + return cont + def dup_primitive(self, f): + cont, prim = dup_primitive(self.to_dense(f), self.domain) + return cont, self.from_dense(prim) + + def dmp_content(self, f): + cont = dmp_content(self.to_dense(f), self.ngens-1, self.domain) + if isinstance(cont, list): + return self[1:].from_dense(cont) + else: + return cont + def dmp_primitive(self, f): + cont, prim = dmp_primitive(self.to_dense(f), self.ngens-1, self.domain) + if isinstance(cont, list): + return (self[1:].from_dense(cont), self.from_dense(prim)) + else: + return (cont, self.from_dense(prim)) + + def dmp_ground_content(self, f): + cont = dmp_ground_content(self.to_dense(f), self.ngens-1, self.domain) + return cont + def dmp_ground_primitive(self, f): + cont, prim = dmp_ground_primitive(self.to_dense(f), self.ngens-1, self.domain) + return (cont, self.from_dense(prim)) + + def dup_cancel(self, f, g, include=True): + result = dup_cancel(self.to_dense(f), self.to_dense(g), self.domain, include=include) + if not include: + cf, cg, F, G = result + return (cf, cg, self.from_dense(F), self.from_dense(G)) + else: + F, G = result + return (self.from_dense(F), self.from_dense(G)) + def dmp_cancel(self, f, g, include=True): + result = dmp_cancel(self.to_dense(f), self.to_dense(g), self.ngens-1, self.domain, include=include) + if not include: + cf, cg, F, G = result + return (cf, cg, self.from_dense(F), self.from_dense(G)) + else: + F, G = result + return (self.from_dense(F), self.from_dense(G)) + + def dup_trial_division(self, f, factors): + factors = dup_trial_division(self.to_dense(f), list(map(self.to_dense, factors)), self.domain) + return [ (self.from_dense(g), k) for g, k in factors ] + def dmp_trial_division(self, f, factors): + factors = dmp_trial_division(self.to_dense(f), list(map(self.to_dense, factors)), self.ngens-1, self.domain) + return [ (self.from_dense(g), k) for g, k in factors ] + + def dup_zz_mignotte_bound(self, f): + return dup_zz_mignotte_bound(self.to_dense(f), self.domain) + def dmp_zz_mignotte_bound(self, f): + return dmp_zz_mignotte_bound(self.to_dense(f), self.ngens-1, self.domain) + + def dup_zz_hensel_step(self, m, f, g, h, s, t): + D = self.to_dense + G, H, S, T = dup_zz_hensel_step(m, D(f), D(g), D(h), D(s), D(t), self.domain) + return (self.from_dense(G), self.from_dense(H), self.from_dense(S), self.from_dense(T)) + def dup_zz_hensel_lift(self, p, f, f_list, l): + D = self.to_dense + polys = dup_zz_hensel_lift(p, D(f), list(map(D, f_list)), l, self.domain) + return list(map(self.from_dense, polys)) + + def dup_zz_zassenhaus(self, f): + factors = dup_zz_zassenhaus(self.to_dense(f), self.domain) + return [ (self.from_dense(g), k) for g, k in factors ] + + def dup_zz_irreducible_p(self, f): + return dup_zz_irreducible_p(self.to_dense(f), self.domain) + def dup_cyclotomic_p(self, f, irreducible=False): + return dup_cyclotomic_p(self.to_dense(f), self.domain, irreducible=irreducible) + def dup_zz_cyclotomic_poly(self, n): + F = dup_zz_cyclotomic_poly(n, self.domain) + return self.from_dense(F) + def dup_zz_cyclotomic_factor(self, f): + result = dup_zz_cyclotomic_factor(self.to_dense(f), self.domain) + if result is None: + return result + else: + return list(map(self.from_dense, result)) + + # E: List[ZZ], cs: ZZ, ct: ZZ + def dmp_zz_wang_non_divisors(self, E, cs, ct): + return dmp_zz_wang_non_divisors(E, cs, ct, self.domain) + + # f: Poly, T: List[(Poly, int)], ct: ZZ, A: List[ZZ] + #def dmp_zz_wang_test_points(f, T, ct, A): + # dmp_zz_wang_test_points(self.to_dense(f), T, ct, A, self.ngens-1, self.domain) + + # f: Poly, T: List[(Poly, int)], cs: ZZ, E: List[ZZ], H: List[Poly], A: List[ZZ] + def dmp_zz_wang_lead_coeffs(self, f, T, cs, E, H, A): + mv = self[1:] + T = [ (mv.to_dense(t), k) for t, k in T ] + uv = self[:1] + H = list(map(uv.to_dense, H)) + f, HH, CC = dmp_zz_wang_lead_coeffs(self.to_dense(f), T, cs, E, H, A, self.ngens-1, self.domain) + return self.from_dense(f), list(map(uv.from_dense, HH)), list(map(mv.from_dense, CC)) + + # f: List[Poly], m: int, p: ZZ + def dup_zz_diophantine(self, F, m, p): + result = dup_zz_diophantine(list(map(self.to_dense, F)), m, p, self.domain) + return list(map(self.from_dense, result)) + + # f: List[Poly], c: List[Poly], A: List[ZZ], d: int, p: ZZ + def dmp_zz_diophantine(self, F, c, A, d, p): + result = dmp_zz_diophantine(list(map(self.to_dense, F)), self.to_dense(c), A, d, p, self.ngens-1, self.domain) + return list(map(self.from_dense, result)) + + # f: Poly, H: List[Poly], LC: List[Poly], A: List[ZZ], p: ZZ + def dmp_zz_wang_hensel_lifting(self, f, H, LC, A, p): + uv = self[:1] + mv = self[1:] + H = list(map(uv.to_dense, H)) + LC = list(map(mv.to_dense, LC)) + result = dmp_zz_wang_hensel_lifting(self.to_dense(f), H, LC, A, p, self.ngens-1, self.domain) + return list(map(self.from_dense, result)) + + def dmp_zz_wang(self, f, mod=None, seed=None): + factors = dmp_zz_wang(self.to_dense(f), self.ngens-1, self.domain, mod=mod, seed=seed) + return [ self.from_dense(g) for g in factors ] + + def dup_zz_factor_sqf(self, f): + coeff, factors = dup_zz_factor_sqf(self.to_dense(f), self.domain) + return (coeff, [ self.from_dense(g) for g in factors ]) + + def dup_zz_factor(self, f): + coeff, factors = dup_zz_factor(self.to_dense(f), self.domain) + return (coeff, [ (self.from_dense(g), k) for g, k in factors ]) + def dmp_zz_factor(self, f): + coeff, factors = dmp_zz_factor(self.to_dense(f), self.ngens-1, self.domain) + return (coeff, [ (self.from_dense(g), k) for g, k in factors ]) + + def dup_ext_factor(self, f): + coeff, factors = dup_ext_factor(self.to_dense(f), self.domain) + return (coeff, [ (self.from_dense(g), k) for g, k in factors ]) + def dmp_ext_factor(self, f): + coeff, factors = dmp_ext_factor(self.to_dense(f), self.ngens-1, self.domain) + return (coeff, [ (self.from_dense(g), k) for g, k in factors ]) + + def dup_gf_factor(self, f): + coeff, factors = dup_gf_factor(self.to_dense(f), self.domain) + return (coeff, [ (self.from_dense(g), k) for g, k in factors ]) + def dmp_gf_factor(self, f): + coeff, factors = dmp_gf_factor(self.to_dense(f), self.ngens-1, self.domain) + return (coeff, [ (self.from_dense(g), k) for g, k in factors ]) + + def dup_factor_list(self, f): + coeff, factors = dup_factor_list(self.to_dense(f), self.domain) + return (coeff, [ (self.from_dense(g), k) for g, k in factors ]) + def dup_factor_list_include(self, f): + factors = dup_factor_list_include(self.to_dense(f), self.domain) + return [ (self.from_dense(g), k) for g, k in factors ] + + def dmp_factor_list(self, f): + coeff, factors = dmp_factor_list(self.to_dense(f), self.ngens-1, self.domain) + return (coeff, [ (self.from_dense(g), k) for g, k in factors ]) + def dmp_factor_list_include(self, f): + factors = dmp_factor_list_include(self.to_dense(f), self.ngens-1, self.domain) + return [ (self.from_dense(g), k) for g, k in factors ] + + def dup_irreducible_p(self, f): + return dup_irreducible_p(self.to_dense(f), self.domain) + def dmp_irreducible_p(self, f): + return dmp_irreducible_p(self.to_dense(f), self.ngens-1, self.domain) + + def dup_sturm(self, f): + seq = dup_sturm(self.to_dense(f), self.domain) + return list(map(self.from_dense, seq)) + + def dup_sqf_p(self, f): + return dup_sqf_p(self.to_dense(f), self.domain) + def dmp_sqf_p(self, f): + return dmp_sqf_p(self.to_dense(f), self.ngens-1, self.domain) + + def dup_sqf_norm(self, f): + s, F, R = dup_sqf_norm(self.to_dense(f), self.domain) + return (s, self.from_dense(F), self.to_ground().from_dense(R)) + def dmp_sqf_norm(self, f): + s, F, R = dmp_sqf_norm(self.to_dense(f), self.ngens-1, self.domain) + return (s, self.from_dense(F), self.to_ground().from_dense(R)) + + def dup_gf_sqf_part(self, f): + return self.from_dense(dup_gf_sqf_part(self.to_dense(f), self.domain)) + def dmp_gf_sqf_part(self, f): + return self.from_dense(dmp_gf_sqf_part(self.to_dense(f), self.domain)) + def dup_sqf_part(self, f): + return self.from_dense(dup_sqf_part(self.to_dense(f), self.domain)) + def dmp_sqf_part(self, f): + return self.from_dense(dmp_sqf_part(self.to_dense(f), self.ngens-1, self.domain)) + + def dup_gf_sqf_list(self, f, all=False): + coeff, factors = dup_gf_sqf_list(self.to_dense(f), self.domain, all=all) + return (coeff, [ (self.from_dense(g), k) for g, k in factors ]) + def dmp_gf_sqf_list(self, f, all=False): + coeff, factors = dmp_gf_sqf_list(self.to_dense(f), self.ngens-1, self.domain, all=all) + return (coeff, [ (self.from_dense(g), k) for g, k in factors ]) + + def dup_sqf_list(self, f, all=False): + coeff, factors = dup_sqf_list(self.to_dense(f), self.domain, all=all) + return (coeff, [ (self.from_dense(g), k) for g, k in factors ]) + def dup_sqf_list_include(self, f, all=False): + factors = dup_sqf_list_include(self.to_dense(f), self.domain, all=all) + return [ (self.from_dense(g), k) for g, k in factors ] + def dmp_sqf_list(self, f, all=False): + coeff, factors = dmp_sqf_list(self.to_dense(f), self.ngens-1, self.domain, all=all) + return (coeff, [ (self.from_dense(g), k) for g, k in factors ]) + def dmp_sqf_list_include(self, f, all=False): + factors = dmp_sqf_list_include(self.to_dense(f), self.ngens-1, self.domain, all=all) + return [ (self.from_dense(g), k) for g, k in factors ] + + def dup_gff_list(self, f): + factors = dup_gff_list(self.to_dense(f), self.domain) + return [ (self.from_dense(g), k) for g, k in factors ] + def dmp_gff_list(self, f): + factors = dmp_gff_list(self.to_dense(f), self.ngens-1, self.domain) + return [ (self.from_dense(g), k) for g, k in factors ] + + def dup_root_upper_bound(self, f): + return dup_root_upper_bound(self.to_dense(f), self.domain) + def dup_root_lower_bound(self, f): + return dup_root_lower_bound(self.to_dense(f), self.domain) + + def dup_step_refine_real_root(self, f, M, fast=False): + return dup_step_refine_real_root(self.to_dense(f), M, self.domain, fast=fast) + def dup_inner_refine_real_root(self, f, M, eps=None, steps=None, disjoint=None, fast=False, mobius=False): + return dup_inner_refine_real_root(self.to_dense(f), M, self.domain, eps=eps, steps=steps, disjoint=disjoint, fast=fast, mobius=mobius) + def dup_outer_refine_real_root(self, f, s, t, eps=None, steps=None, disjoint=None, fast=False): + return dup_outer_refine_real_root(self.to_dense(f), s, t, self.domain, eps=eps, steps=steps, disjoint=disjoint, fast=fast) + def dup_refine_real_root(self, f, s, t, eps=None, steps=None, disjoint=None, fast=False): + return dup_refine_real_root(self.to_dense(f), s, t, self.domain, eps=eps, steps=steps, disjoint=disjoint, fast=fast) + def dup_inner_isolate_real_roots(self, f, eps=None, fast=False): + return dup_inner_isolate_real_roots(self.to_dense(f), self.domain, eps=eps, fast=fast) + def dup_inner_isolate_positive_roots(self, f, eps=None, inf=None, sup=None, fast=False, mobius=False): + return dup_inner_isolate_positive_roots(self.to_dense(f), self.domain, eps=eps, inf=inf, sup=sup, fast=fast, mobius=mobius) + def dup_inner_isolate_negative_roots(self, f, inf=None, sup=None, eps=None, fast=False, mobius=False): + return dup_inner_isolate_negative_roots(self.to_dense(f), self.domain, inf=inf, sup=sup, eps=eps, fast=fast, mobius=mobius) + def dup_isolate_real_roots_sqf(self, f, eps=None, inf=None, sup=None, fast=False, blackbox=False): + return dup_isolate_real_roots_sqf(self.to_dense(f), self.domain, eps=eps, inf=inf, sup=sup, fast=fast, blackbox=blackbox) + def dup_isolate_real_roots(self, f, eps=None, inf=None, sup=None, basis=False, fast=False): + return dup_isolate_real_roots(self.to_dense(f), self.domain, eps=eps, inf=inf, sup=sup, basis=basis, fast=fast) + def dup_isolate_real_roots_list(self, polys, eps=None, inf=None, sup=None, strict=False, basis=False, fast=False): + return dup_isolate_real_roots_list(list(map(self.to_dense, polys)), self.domain, eps=eps, inf=inf, sup=sup, strict=strict, basis=basis, fast=fast) + def dup_count_real_roots(self, f, inf=None, sup=None): + return dup_count_real_roots(self.to_dense(f), self.domain, inf=inf, sup=sup) + def dup_count_complex_roots(self, f, inf=None, sup=None, exclude=None): + return dup_count_complex_roots(self.to_dense(f), self.domain, inf=inf, sup=sup, exclude=exclude) + def dup_isolate_complex_roots_sqf(self, f, eps=None, inf=None, sup=None, blackbox=False): + return dup_isolate_complex_roots_sqf(self.to_dense(f), self.domain, eps=eps, inf=inf, sup=sup, blackbox=blackbox) + def dup_isolate_all_roots_sqf(self, f, eps=None, inf=None, sup=None, fast=False, blackbox=False): + return dup_isolate_all_roots_sqf(self.to_dense(f), self.domain, eps=eps, inf=inf, sup=sup, fast=fast, blackbox=blackbox) + def dup_isolate_all_roots(self, f, eps=None, inf=None, sup=None, fast=False): + return dup_isolate_all_roots(self.to_dense(f), self.domain, eps=eps, inf=inf, sup=sup, fast=fast) + + def fateman_poly_F_1(self): + from sympy.polys.specialpolys import dmp_fateman_poly_F_1 + return tuple(map(self.from_dense, dmp_fateman_poly_F_1(self.ngens-1, self.domain))) + def fateman_poly_F_2(self): + from sympy.polys.specialpolys import dmp_fateman_poly_F_2 + return tuple(map(self.from_dense, dmp_fateman_poly_F_2(self.ngens-1, self.domain))) + def fateman_poly_F_3(self): + from sympy.polys.specialpolys import dmp_fateman_poly_F_3 + return tuple(map(self.from_dense, dmp_fateman_poly_F_3(self.ngens-1, self.domain))) + + def to_gf_dense(self, element): + return gf_strip([ self.domain.dom.convert(c, self.domain) for c in self.wrap(element).to_dense() ]) + + def from_gf_dense(self, element): + return self.from_dict(dmp_to_dict(element, self.ngens-1, self.domain.dom)) + + def gf_degree(self, f): + return gf_degree(self.to_gf_dense(f)) + + def gf_LC(self, f): + return gf_LC(self.to_gf_dense(f), self.domain.dom) + def gf_TC(self, f): + return gf_TC(self.to_gf_dense(f), self.domain.dom) + + def gf_strip(self, f): + return self.from_gf_dense(gf_strip(self.to_gf_dense(f))) + def gf_trunc(self, f): + return self.from_gf_dense(gf_strip(self.to_gf_dense(f), self.domain.mod)) + def gf_normal(self, f): + return self.from_gf_dense(gf_strip(self.to_gf_dense(f), self.domain.mod, self.domain.dom)) + + def gf_from_dict(self, f): + return self.from_gf_dense(gf_from_dict(f, self.domain.mod, self.domain.dom)) + def gf_to_dict(self, f, symmetric=True): + return gf_to_dict(self.to_gf_dense(f), self.domain.mod, symmetric=symmetric) + + def gf_from_int_poly(self, f): + return self.from_gf_dense(gf_from_int_poly(f, self.domain.mod)) + def gf_to_int_poly(self, f, symmetric=True): + return gf_to_int_poly(self.to_gf_dense(f), self.domain.mod, symmetric=symmetric) + + def gf_neg(self, f): + return self.from_gf_dense(gf_neg(self.to_gf_dense(f), self.domain.mod, self.domain.dom)) + + def gf_add_ground(self, f, a): + return self.from_gf_dense(gf_add_ground(self.to_gf_dense(f), a, self.domain.mod, self.domain.dom)) + def gf_sub_ground(self, f, a): + return self.from_gf_dense(gf_sub_ground(self.to_gf_dense(f), a, self.domain.mod, self.domain.dom)) + def gf_mul_ground(self, f, a): + return self.from_gf_dense(gf_mul_ground(self.to_gf_dense(f), a, self.domain.mod, self.domain.dom)) + def gf_quo_ground(self, f, a): + return self.from_gf_dense(gf_quo_ground(self.to_gf_dense(f), a, self.domain.mod, self.domain.dom)) + + def gf_add(self, f, g): + return self.from_gf_dense(gf_add(self.to_gf_dense(f), self.to_gf_dense(g), self.domain.mod, self.domain.dom)) + def gf_sub(self, f, g): + return self.from_gf_dense(gf_sub(self.to_gf_dense(f), self.to_gf_dense(g), self.domain.mod, self.domain.dom)) + def gf_mul(self, f, g): + return self.from_gf_dense(gf_mul(self.to_gf_dense(f), self.to_gf_dense(g), self.domain.mod, self.domain.dom)) + def gf_sqr(self, f): + return self.from_gf_dense(gf_sqr(self.to_gf_dense(f), self.domain.mod, self.domain.dom)) + + def gf_add_mul(self, f, g, h): + return self.from_gf_dense(gf_add_mul(self.to_gf_dense(f), self.to_gf_dense(g), self.to_gf_dense(h), self.domain.mod, self.domain.dom)) + def gf_sub_mul(self, f, g, h): + return self.from_gf_dense(gf_sub_mul(self.to_gf_dense(f), self.to_gf_dense(g), self.to_gf_dense(h), self.domain.mod, self.domain.dom)) + + def gf_expand(self, F): + return self.from_gf_dense(gf_expand(list(map(self.to_gf_dense, F)), self.domain.mod, self.domain.dom)) + + def gf_div(self, f, g): + q, r = gf_div(self.to_gf_dense(f), self.to_gf_dense(g), self.domain.mod, self.domain.dom) + return self.from_gf_dense(q), self.from_gf_dense(r) + def gf_rem(self, f, g): + return self.from_gf_dense(gf_rem(self.to_gf_dense(f), self.to_gf_dense(g), self.domain.mod, self.domain.dom)) + def gf_quo(self, f, g): + return self.from_gf_dense(gf_quo(self.to_gf_dense(f), self.to_gf_dense(g), self.domain.mod, self.domain.dom)) + def gf_exquo(self, f, g): + return self.from_gf_dense(gf_exquo(self.to_gf_dense(f), self.to_gf_dense(g), self.domain.mod, self.domain.dom)) + + def gf_lshift(self, f, n): + return self.from_gf_dense(gf_lshift(self.to_gf_dense(f), n, self.domain.dom)) + def gf_rshift(self, f, n): + return self.from_gf_dense(gf_rshift(self.to_gf_dense(f), n, self.domain.dom)) + + def gf_pow(self, f, n): + return self.from_gf_dense(gf_pow(self.to_gf_dense(f), n, self.domain.mod, self.domain.dom)) + def gf_pow_mod(self, f, n, g): + return self.from_gf_dense(gf_pow_mod(self.to_gf_dense(f), n, self.to_gf_dense(g), self.domain.mod, self.domain.dom)) + + def gf_cofactors(self, f, g): + h, cff, cfg = gf_cofactors(self.to_gf_dense(f), self.to_gf_dense(g), self.domain.mod, self.domain.dom) + return self.from_gf_dense(h), self.from_gf_dense(cff), self.from_gf_dense(cfg) + def gf_gcd(self, f, g): + return self.from_gf_dense(gf_gcd(self.to_gf_dense(f), self.to_gf_dense(g), self.domain.mod, self.domain.dom)) + def gf_lcm(self, f, g): + return self.from_gf_dense(gf_lcm(self.to_gf_dense(f), self.to_gf_dense(g), self.domain.mod, self.domain.dom)) + def gf_gcdex(self, f, g): + return self.from_gf_dense(gf_gcdex(self.to_gf_dense(f), self.to_gf_dense(g), self.domain.mod, self.domain.dom)) + + def gf_monic(self, f): + return self.from_gf_dense(gf_monic(self.to_gf_dense(f), self.domain.mod, self.domain.dom)) + def gf_diff(self, f): + return self.from_gf_dense(gf_diff(self.to_gf_dense(f), self.domain.mod, self.domain.dom)) + + def gf_eval(self, f, a): + return gf_eval(self.to_gf_dense(f), a, self.domain.mod, self.domain.dom) + def gf_multi_eval(self, f, A): + return gf_multi_eval(self.to_gf_dense(f), A, self.domain.mod, self.domain.dom) + + def gf_compose(self, f, g): + return self.from_gf_dense(gf_compose(self.to_gf_dense(f), self.to_gf_dense(g), self.domain.mod, self.domain.dom)) + def gf_compose_mod(self, g, h, f): + return self.from_gf_dense(gf_compose_mod(self.to_gf_dense(g), self.to_gf_dense(h), self.to_gf_dense(f), self.domain.mod, self.domain.dom)) + + def gf_trace_map(self, a, b, c, n, f): + a = self.to_gf_dense(a) + b = self.to_gf_dense(b) + c = self.to_gf_dense(c) + f = self.to_gf_dense(f) + U, V = gf_trace_map(a, b, c, n, f, self.domain.mod, self.domain.dom) + return self.from_gf_dense(U), self.from_gf_dense(V) + + def gf_random(self, n): + return self.from_gf_dense(gf_random(n, self.domain.mod, self.domain.dom)) + def gf_irreducible(self, n): + return self.from_gf_dense(gf_irreducible(n, self.domain.mod, self.domain.dom)) + + def gf_irred_p_ben_or(self, f): + return gf_irred_p_ben_or(self.to_gf_dense(f), self.domain.mod, self.domain.dom) + def gf_irred_p_rabin(self, f): + return gf_irred_p_rabin(self.to_gf_dense(f), self.domain.mod, self.domain.dom) + def gf_irreducible_p(self, f): + return gf_irreducible_p(self.to_gf_dense(f), self.domain.mod, self.domain.dom) + def gf_sqf_p(self, f): + return gf_sqf_p(self.to_gf_dense(f), self.domain.mod, self.domain.dom) + + def gf_sqf_part(self, f): + return self.from_gf_dense(gf_sqf_part(self.to_gf_dense(f), self.domain.mod, self.domain.dom)) + def gf_sqf_list(self, f, all=False): + coeff, factors = gf_sqf_part(self.to_gf_dense(f), self.domain.mod, self.domain.dom, all=all) + return coeff, [ (self.from_gf_dense(g), k) for g, k in factors ] + + def gf_Qmatrix(self, f): + return gf_Qmatrix(self.to_gf_dense(f), self.domain.mod, self.domain.dom) + def gf_berlekamp(self, f): + factors = gf_berlekamp(self.to_gf_dense(f), self.domain.mod, self.domain.dom) + return [ self.from_gf_dense(g) for g in factors ] + + def gf_ddf_zassenhaus(self, f): + factors = gf_ddf_zassenhaus(self.to_gf_dense(f), self.domain.mod, self.domain.dom) + return [ (self.from_gf_dense(g), k) for g, k in factors ] + def gf_edf_zassenhaus(self, f, n): + factors = gf_edf_zassenhaus(self.to_gf_dense(f), self.domain.mod, self.domain.dom) + return [ self.from_gf_dense(g) for g in factors ] + + def gf_ddf_shoup(self, f): + factors = gf_ddf_shoup(self.to_gf_dense(f), self.domain.mod, self.domain.dom) + return [ (self.from_gf_dense(g), k) for g, k in factors ] + def gf_edf_shoup(self, f, n): + factors = gf_edf_shoup(self.to_gf_dense(f), self.domain.mod, self.domain.dom) + return [ self.from_gf_dense(g) for g in factors ] + + def gf_zassenhaus(self, f): + factors = gf_zassenhaus(self.to_gf_dense(f), self.domain.mod, self.domain.dom) + return [ self.from_gf_dense(g) for g in factors ] + def gf_shoup(self, f): + factors = gf_shoup(self.to_gf_dense(f), self.domain.mod, self.domain.dom) + return [ self.from_gf_dense(g) for g in factors ] + + def gf_factor_sqf(self, f, method=None): + coeff, factors = gf_factor_sqf(self.to_gf_dense(f), self.domain.mod, self.domain.dom, method=method) + return coeff, [ self.from_gf_dense(g) for g in factors ] + def gf_factor(self, f): + coeff, factors = gf_factor(self.to_gf_dense(f), self.domain.mod, self.domain.dom) + return coeff, [ (self.from_gf_dense(g), k) for g, k in factors ] diff -Nru python3-sympy-0.7.2/sympy/polys/constructor.py python3-sympy-0.7.3/sympy/polys/constructor.py --- python3-sympy-0.7.2/sympy/polys/constructor.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/polys/constructor.py 2013-07-13 17:53:32.000000000 +0000 @@ -7,6 +7,7 @@ from sympy.assumptions import ask, Q from sympy.core import sympify + def _construct_simple(coeffs, opt): """Handle simple domains, e.g.: ZZ, QQ, RR and algebraic domains. """ result, rationals, reals, algebraics = {}, False, False, False @@ -55,6 +56,7 @@ return domain, result + def _construct_algebraic(coeffs, opt): """We know that coefficients are algebraic so construct the extension. """ from sympy.polys.numberfields import primitive_element @@ -97,6 +99,7 @@ return domain, result + def _construct_composite(coeffs, opt): """Handle composite domains, e.g.: ZZ[X], QQ[X], ZZ(X), QQ(X). """ numers, denoms = [], [] @@ -108,12 +111,12 @@ denoms.append(denom) try: - polys, gens = parallel_dict_from_basic(numers + denoms) # XXX: sorting + polys, gens = parallel_dict_from_basic(numers + denoms) # XXX: sorting except GeneratorsNeeded: return None if any(gen.is_number for gen in gens): - return None # generators are number-like so lets better use EX + return None # generators are number-like so lets better use EX n = len(gens) k = len(polys)//2 @@ -187,6 +190,7 @@ return domain, result + def _construct_expression(coeffs, opt): """The last resort case, i.e. use the expression domain. """ domain, result = EX, [] @@ -196,13 +200,17 @@ return domain, result + def construct_domain(obj, **args): """Construct a minimal domain for the list of coefficients. """ opt = build_options(args) if hasattr(obj, '__iter__'): if isinstance(obj, dict): - monoms, coeffs = list(zip(*list(obj.items()))) + if not obj: + monoms, coeffs = [], [] + else: + monoms, coeffs = list(zip(*list(obj.items()))) else: coeffs = obj else: diff -Nru python3-sympy-0.7.2/sympy/polys/densearith.py python3-sympy-0.7.3/sympy/polys/densearith.py --- python3-sympy-0.7.2/sympy/polys/densearith.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/polys/densearith.py 2013-07-13 17:53:32.000000000 +0000 @@ -14,6 +14,7 @@ from sympy.utilities import cythonized + @cythonized("i,n,m") def dup_add_term(f, c, i, K): """ @@ -22,28 +23,27 @@ Examples ======== - >>> from sympy.polys.domains import ZZ - >>> from sympy.polys.densearith import dup_add_term - - >>> f = ZZ.map([1, 0, -1]) + >>> from sympy.polys import ring, ZZ + >>> R, x = ring("x", ZZ) - >>> dup_add_term(f, ZZ(2), 4, ZZ) - [2, 0, 1, 0, -1] + >>> R.dup_add_term(x**2 - 1, ZZ(2), 4) + 2*x**4 + x**2 - 1 """ if not c: return f n = len(f) - m = n-i-1 + m = n - i - 1 - if i == n-1: - return dup_strip([f[0]+c] + f[1:]) + if i == n - 1: + return dup_strip([f[0] + c] + f[1:]) else: if i >= n: - return [c] + [K.zero]*(i-n) + f + return [c] + [K.zero]*(i - n) + f else: - return f[:m] + [f[m]+c] + f[m+1:] + return f[:m] + [f[m] + c] + f[m + 1:] + @cythonized("i,u,v,n,m") def dmp_add_term(f, c, i, u, K): @@ -53,34 +53,32 @@ Examples ======== - >>> from sympy.polys.domains import ZZ - >>> from sympy.polys.densearith import dmp_add_term + >>> from sympy.polys import ring, ZZ + >>> R, x,y = ring("x,y", ZZ) - >>> f = ZZ.map([[1, 0], [1]]) - >>> c = ZZ.map([2]) - - >>> dmp_add_term(f, c, 2, 1, ZZ) - [[2], [1, 0], [1]] + >>> R.dmp_add_term(x*y + 1, 2, 2) + 2*x**2 + x*y + 1 """ if not u: return dup_add_term(f, c, i, K) - v = u-1 + v = u - 1 if dmp_zero_p(c, v): return f n = len(f) - m = n-i-1 + m = n - i - 1 - if i == n-1: + if i == n - 1: return dmp_strip([dmp_add(f[0], c, v, K)] + f[1:], u) else: if i >= n: - return [c] + dmp_zeros(i-n, v, K) + f + return [c] + dmp_zeros(i - n, v, K) + f else: - return f[:m] + [dmp_add(f[m], c, v, K)] + f[m+1:] + return f[:m] + [dmp_add(f[m], c, v, K)] + f[m + 1:] + @cythonized("i,n,m") def dup_sub_term(f, c, i, K): @@ -90,28 +88,27 @@ Examples ======== - >>> from sympy.polys.domains import ZZ - >>> from sympy.polys.densearith import dup_sub_term + >>> from sympy.polys import ring, ZZ + >>> R, x = ring("x", ZZ) - >>> f = ZZ.map([2, 0, 1, 0, -1]) - - >>> dup_sub_term(f, ZZ(2), 4, ZZ) - [1, 0, -1] + >>> R.dup_sub_term(2*x**4 + x**2 - 1, ZZ(2), 4) + x**2 - 1 """ if not c: return f n = len(f) - m = n-i-1 + m = n - i - 1 - if i == n-1: - return dup_strip([f[0]-c] + f[1:]) + if i == n - 1: + return dup_strip([f[0] - c] + f[1:]) else: if i >= n: - return [-c] + [K.zero]*(i-n) + f + return [-c] + [K.zero]*(i - n) + f else: - return f[:m] + [f[m]-c] + f[m+1:] + return f[:m] + [f[m] - c] + f[m + 1:] + @cythonized("i,u,v,n,m") def dmp_sub_term(f, c, i, u, K): @@ -121,34 +118,32 @@ Examples ======== - >>> from sympy.polys.domains import ZZ - >>> from sympy.polys.densearith import dmp_sub_term + >>> from sympy.polys import ring, ZZ + >>> R, x,y = ring("x,y", ZZ) - >>> f = ZZ.map([[2], [1, 0], [1]]) - >>> c = ZZ.map([2]) - - >>> dmp_sub_term(f, c, 2, 1, ZZ) - [[1, 0], [1]] + >>> R.dmp_sub_term(2*x**2 + x*y + 1, 2, 2) + x*y + 1 """ if not u: return dup_add_term(f, -c, i, K) - v = u-1 + v = u - 1 if dmp_zero_p(c, v): return f n = len(f) - m = n-i-1 + m = n - i - 1 - if i == n-1: + if i == n - 1: return dmp_strip([dmp_sub(f[0], c, v, K)] + f[1:], u) else: if i >= n: - return [dmp_neg(c, v, K)] + dmp_zeros(i-n, v, K) + f + return [dmp_neg(c, v, K)] + dmp_zeros(i - n, v, K) + f else: - return f[:m] + [dmp_sub(f[m], c, v, K)] + f[m+1:] + return f[:m] + [dmp_sub(f[m], c, v, K)] + f[m + 1:] + @cythonized("i") def dup_mul_term(f, c, i, K): @@ -158,13 +153,11 @@ Examples ======== - >>> from sympy.polys.domains import ZZ - >>> from sympy.polys.densearith import dup_mul_term + >>> from sympy.polys import ring, ZZ + >>> R, x = ring("x", ZZ) - >>> f = ZZ.map([1, 0, -1]) - - >>> dup_mul_term(f, ZZ(3), 2, ZZ) - [3, 0, -3, 0, 0] + >>> R.dup_mul_term(x**2 - 1, ZZ(3), 2) + 3*x**4 - 3*x**2 """ if not c or not f: @@ -172,6 +165,7 @@ else: return [ cf * c for cf in f ] + [K.zero]*i + @cythonized("i,u,v") def dmp_mul_term(f, c, i, u, K): """ @@ -180,20 +174,17 @@ Examples ======== - >>> from sympy.polys.domains import ZZ - >>> from sympy.polys.densearith import dmp_mul_term - - >>> f = ZZ.map([[1, 0], [1], []]) - >>> c = ZZ.map([3, 0]) + >>> from sympy.polys import ring, ZZ + >>> R, x,y = ring("x,y", ZZ) - >>> dmp_mul_term(f, c, 2, 1, ZZ) - [[3, 0, 0], [3, 0], [], [], []] + >>> R.dmp_mul_term(x**2*y + x, 3*y, 2) + 3*x**4*y**2 + 3*x**3*y """ if not u: return dup_mul_term(f, c, i, K) - v = u-1 + v = u - 1 if dmp_zero_p(f, u): return f @@ -202,6 +193,7 @@ else: return [ dmp_mul(cf, c, v, K) for cf in f ] + dmp_zeros(i, v, K) + def dup_add_ground(f, c, K): """ Add an element of the ground domain to ``f``. @@ -209,17 +201,16 @@ Examples ======== - >>> from sympy.polys.domains import ZZ - >>> from sympy.polys.densearith import dup_add_ground - - >>> f = ZZ.map([1, 2, 3, 4]) + >>> from sympy.polys import ring, ZZ + >>> R, x = ring("x", ZZ) - >>> dup_add_ground(f, ZZ(4), ZZ) - [1, 2, 3, 8] + >>> R.dup_add_ground(x**3 + 2*x**2 + 3*x + 4, ZZ(4)) + x**3 + 2*x**2 + 3*x + 8 """ return dup_add_term(f, c, 0, K) + def dmp_add_ground(f, c, u, K): """ Add an element of the ground domain to ``f``. @@ -227,16 +218,15 @@ Examples ======== - >>> from sympy.polys.domains import ZZ - >>> from sympy.polys.densearith import dmp_add_ground - - >>> f = ZZ.map([[1], [2], [3], [4]]) + >>> from sympy.polys import ring, ZZ + >>> R, x,y = ring("x,y", ZZ) - >>> dmp_add_ground(f, ZZ(4), 1, ZZ) - [[1], [2], [3], [8]] + >>> R.dmp_add_ground(x**3 + 2*x**2 + 3*x + 4, ZZ(4)) + x**3 + 2*x**2 + 3*x + 8 """ - return dmp_add_term(f, dmp_ground(c, u-1), 0, u, K) + return dmp_add_term(f, dmp_ground(c, u - 1), 0, u, K) + def dup_sub_ground(f, c, K): """ @@ -245,17 +235,16 @@ Examples ======== - >>> from sympy.polys.domains import ZZ - >>> from sympy.polys.densearith import dup_sub_ground - - >>> f = ZZ.map([1, 2, 3, 4]) + >>> from sympy.polys import ring, ZZ + >>> R, x = ring("x", ZZ) - >>> dup_sub_ground(f, ZZ(4), ZZ) - [1, 2, 3, 0] + >>> R.dup_sub_ground(x**3 + 2*x**2 + 3*x + 4, ZZ(4)) + x**3 + 2*x**2 + 3*x """ return dup_sub_term(f, c, 0, K) + def dmp_sub_ground(f, c, u, K): """ Subtract an element of the ground domain from ``f``. @@ -263,16 +252,15 @@ Examples ======== - >>> from sympy.polys.domains import ZZ - >>> from sympy.polys.densearith import dmp_sub_ground - - >>> f = ZZ.map([[1], [2], [3], [4]]) + >>> from sympy.polys import ring, ZZ + >>> R, x,y = ring("x,y", ZZ) - >>> dmp_sub_ground(f, ZZ(4), 1, ZZ) - [[1], [2], [3], []] + >>> R.dmp_sub_ground(x**3 + 2*x**2 + 3*x + 4, ZZ(4)) + x**3 + 2*x**2 + 3*x """ - return dmp_sub_term(f, dmp_ground(c, u-1), 0, u, K) + return dmp_sub_term(f, dmp_ground(c, u - 1), 0, u, K) + def dup_mul_ground(f, c, K): """ @@ -281,13 +269,11 @@ Examples ======== - >>> from sympy.polys.domains import ZZ - >>> from sympy.polys.densearith import dup_mul_ground + >>> from sympy.polys import ring, ZZ + >>> R, x = ring("x", ZZ) - >>> f = ZZ.map([1, 2, -1]) - - >>> dup_mul_ground(f, ZZ(3), ZZ) - [3, 6, -3] + >>> R.dup_mul_ground(x**2 + 2*x - 1, ZZ(3)) + 3*x**2 + 6*x - 3 """ if not c or not f: @@ -295,6 +281,7 @@ else: return [ cf * c for cf in f ] + @cythonized("u,v") def dmp_mul_ground(f, c, u, K): """ @@ -303,22 +290,21 @@ Examples ======== - >>> from sympy.polys.domains import ZZ - >>> from sympy.polys.densearith import dmp_mul_ground + >>> from sympy.polys import ring, ZZ + >>> R, x,y = ring("x,y", ZZ) - >>> f = ZZ.map([[2], [2, 0]]) - - >>> dmp_mul_ground(f, ZZ(3), 1, ZZ) - [[6], [6, 0]] + >>> R.dmp_mul_ground(2*x + 2*y, ZZ(3)) + 6*x + 6*y """ if not u: return dup_mul_ground(f, c, K) - v = u-1 + v = u - 1 return [ dmp_mul_ground(cf, c, v, K) for cf in f ] + def dup_quo_ground(f, c, K): """ Quotient by a constant in ``K[x]``. @@ -326,17 +312,15 @@ Examples ======== - >>> from sympy.polys.domains import ZZ, QQ - >>> from sympy.polys.densearith import dup_quo_ground - - >>> f = ZZ.map([3, 0, 2]) - >>> g = QQ.map([3, 0, 2]) - - >>> dup_quo_ground(f, ZZ(2), ZZ) - [1, 0, 1] + >>> from sympy.polys import ring, ZZ, QQ - >>> dup_quo_ground(g, QQ(2), QQ) - [3/2, 0/1, 1/1] + >>> R, x = ring("x", ZZ) + >>> R.dup_quo_ground(3*x**2 + 2, ZZ(2)) + x**2 + 1 + + >>> R, x = ring("x", QQ) + >>> R.dup_quo_ground(3*x**2 + 2, QQ(2)) + 3/2*x**2 + 1 """ if not c: @@ -349,6 +333,7 @@ else: return [ cf // c for cf in f ] + @cythonized("u,v") def dmp_quo_ground(f, c, u, K): """ @@ -357,26 +342,25 @@ Examples ======== - >>> from sympy.polys.domains import ZZ, QQ - >>> from sympy.polys.densearith import dmp_quo_ground - - >>> f = ZZ.map([[2, 0], [3], []]) - >>> g = QQ.map([[2, 0], [3], []]) + >>> from sympy.polys import ring, ZZ, QQ - >>> dmp_quo_ground(f, ZZ(2), 1, ZZ) - [[1, 0], [1], []] - - >>> dmp_quo_ground(g, QQ(2), 1, QQ) - [[1/1, 0/1], [3/2], []] + >>> R, x,y = ring("x,y", ZZ) + >>> R.dmp_quo_ground(2*x**2*y + 3*x, ZZ(2)) + x**2*y + x + + >>> R, x,y = ring("x,y", QQ) + >>> R.dmp_quo_ground(2*x**2*y + 3*x, QQ(2)) + x**2*y + 3/2*x """ if not u: return dup_quo_ground(f, c, K) - v = u-1 + v = u - 1 return [ dmp_quo_ground(cf, c, v, K) for cf in f ] + def dup_exquo_ground(f, c, K): """ Exact quotient by a constant in ``K[x]``. @@ -384,13 +368,11 @@ Examples ======== - >>> from sympy.polys.domains import ZZ, QQ - >>> from sympy.polys.densearith import dup_exquo_ground + >>> from sympy.polys import ring, QQ + >>> R, x = ring("x", QQ) - >>> f = QQ.map([1, 0, 2]) - - >>> dup_exquo_ground(f, QQ(2), QQ) - [1/2, 0/1, 1/1] + >>> R.dup_exquo_ground(x**2 + 2, QQ(2)) + 1/2*x**2 + 1 """ if not c: @@ -400,6 +382,7 @@ return [ K.exquo(cf, c) for cf in f ] + @cythonized("u,v") def dmp_exquo_ground(f, c, u, K): """ @@ -408,22 +391,21 @@ Examples ======== - >>> from sympy.polys.domains import ZZ, QQ - >>> from sympy.polys.densearith import dmp_exquo_ground + >>> from sympy.polys import ring, QQ + >>> R, x,y = ring("x,y", QQ) - >>> f = QQ.map([[1, 0], [2], []]) - - >>> dmp_exquo_ground(f, QQ(2), 1, QQ) - [[1/2, 0/1], [1/1], []] + >>> R.dmp_exquo_ground(x**2*y + 2*x, QQ(2)) + 1/2*x**2*y + x """ if not u: return dup_exquo_ground(f, c, K) - v = u-1 + v = u - 1 return [ dmp_exquo_ground(cf, c, v, K) for cf in f ] + @cythonized("n") def dup_lshift(f, n, K): """ @@ -432,13 +414,11 @@ Examples ======== - >>> from sympy.polys.domains import ZZ - >>> from sympy.polys.densearith import dup_lshift + >>> from sympy.polys import ring, ZZ + >>> R, x = ring("x", ZZ) - >>> f = ZZ.map([1, 0, 1]) - - >>> dup_lshift(f, 2, ZZ) - [1, 0, 1, 0, 0] + >>> R.dup_lshift(x**2 + 1, 2) + x**4 + x**2 """ if not f: @@ -446,6 +426,7 @@ else: return f + [K.zero]*n + @cythonized("n") def dup_rshift(f, n, K): """ @@ -454,21 +435,18 @@ Examples ======== - >>> from sympy.polys.domains import ZZ - >>> from sympy.polys.densearith import dup_rshift - - >>> f = ZZ.map([1, 0, 1, 0, 0]) - >>> g = ZZ.map([1, 0, 1, 0, 2]) + >>> from sympy.polys import ring, ZZ + >>> R, x = ring("x", ZZ) - >>> dup_rshift(f, 2, ZZ) - [1, 0, 1] - - >>> dup_rshift(g, 2, ZZ) - [1, 0, 1] + >>> R.dup_rshift(x**4 + x**2, 2) + x**2 + 1 + >>> R.dup_rshift(x**4 + x**2 + 2, 2) + x**2 + 1 """ return f[:-n] + def dup_abs(f, K): """ Make all coefficients positive in ``K[x]``. @@ -476,17 +454,16 @@ Examples ======== - >>> from sympy.polys.domains import ZZ - >>> from sympy.polys.densearith import dup_abs + >>> from sympy.polys import ring, ZZ + >>> R, x = ring("x", ZZ) - >>> f = ZZ.map([1, 0, -1]) - - >>> dup_abs(f, ZZ) - [1, 0, 1] + >>> R.dup_abs(x**2 - 1) + x**2 + 1 """ return [ K.abs(coeff) for coeff in f ] + @cythonized("u,v") def dmp_abs(f, u, K): """ @@ -495,22 +472,21 @@ Examples ======== - >>> from sympy.polys.domains import ZZ - >>> from sympy.polys.densearith import dmp_abs + >>> from sympy.polys import ring, ZZ + >>> R, x,y = ring("x,y", ZZ) - >>> f = ZZ.map([[1, 0], [-1], []]) - - >>> dmp_abs(f, 1, ZZ) - [[1, 0], [1], []] + >>> R.dmp_abs(x**2*y - x) + x**2*y + x """ if not u: return dup_abs(f, K) - v = u-1 + v = u - 1 return [ dmp_abs(cf, v, K) for cf in f ] + def dup_neg(f, K): """ Negate a polynomial in ``K[x]``. @@ -518,17 +494,16 @@ Examples ======== - >>> from sympy.polys.domains import ZZ - >>> from sympy.polys.densearith import dup_neg + >>> from sympy.polys import ring, ZZ + >>> R, x = ring("x", ZZ) - >>> f = ZZ.map([1, 0, -1]) - - >>> dup_neg(f, ZZ) - [-1, 0, 1] + >>> R.dup_neg(x**2 - 1) + -x**2 + 1 """ return [ -coeff for coeff in f ] + @cythonized("u,v") def dmp_neg(f, u, K): """ @@ -537,22 +512,21 @@ Examples ======== - >>> from sympy.polys.domains import ZZ - >>> from sympy.polys.densearith import dmp_neg - - >>> f = ZZ.map([[1, 0], [-1], []]) + >>> from sympy.polys import ring, ZZ + >>> R, x,y = ring("x,y", ZZ) - >>> dmp_neg(f, 1, ZZ) - [[-1, 0], [1], []] + >>> R.dmp_neg(x**2*y - x) + -x**2*y + x """ if not u: return dup_neg(f, K) - v = u-1 + v = u - 1 return [ dmp_neg(cf, v, K) for cf in f ] + @cythonized("df,dg,k") def dup_add(f, g, K): """ @@ -561,14 +535,11 @@ Examples ======== - >>> from sympy.polys.domains import ZZ - >>> from sympy.polys.densearith import dup_add - - >>> f = ZZ.map([1, 0, -1]) - >>> g = ZZ.map([1, -2]) + >>> from sympy.polys import ring, ZZ + >>> R, x = ring("x", ZZ) - >>> dup_add(f, g, ZZ) - [1, 1, -3] + >>> R.dup_add(x**2 - 1, x - 2) + x**2 + x - 3 """ if not f: @@ -591,6 +562,7 @@ return h + [ a + b for a, b in zip(f, g) ] + @cythonized("u,v,df,dg,k") def dmp_add(f, g, u, K): """ @@ -599,14 +571,11 @@ Examples ======== - >>> from sympy.polys.domains import ZZ - >>> from sympy.polys.densearith import dmp_add - - >>> f = ZZ.map([[1], [], [1, 0]]) - >>> g = ZZ.map([[1, 0], [1], []]) + >>> from sympy.polys import ring, ZZ + >>> R, x,y = ring("x,y", ZZ) - >>> dmp_add(f, g, 1, ZZ) - [[1, 1], [1], [1, 0]] + >>> R.dmp_add(x**2 + y, x**2*y + x) + x**2*y + x**2 + x + y """ if not u: @@ -622,7 +591,7 @@ if dg < 0: return f - v = u-1 + v = u - 1 if df == dg: return dmp_strip([ dmp_add(a, b, v, K) for a, b in zip(f, g) ], u) @@ -636,6 +605,7 @@ return h + [ dmp_add(a, b, v, K) for a, b in zip(f, g) ] + @cythonized("df,dg,k") def dup_sub(f, g, K): """ @@ -644,14 +614,11 @@ Examples ======== - >>> from sympy.polys.domains import ZZ - >>> from sympy.polys.densearith import dup_sub - - >>> f = ZZ.map([1, 0, -1]) - >>> g = ZZ.map([1, -2]) + >>> from sympy.polys import ring, ZZ + >>> R, x = ring("x", ZZ) - >>> dup_sub(f, g, ZZ) - [1, -1, 1] + >>> R.dup_sub(x**2 - 1, x - 2) + x**2 - x + 1 """ if not f: @@ -674,6 +641,7 @@ return h + [ a - b for a, b in zip(f, g) ] + @cythonized("u,v,df,dg,k") def dmp_sub(f, g, u, K): """ @@ -682,14 +650,11 @@ Examples ======== - >>> from sympy.polys.domains import ZZ - >>> from sympy.polys.densearith import dmp_sub - - >>> f = ZZ.map([[1], [], [1, 0]]) - >>> g = ZZ.map([[1, 0], [1], []]) + >>> from sympy.polys import ring, ZZ + >>> R, x,y = ring("x,y", ZZ) - >>> dmp_sub(f, g, 1, ZZ) - [[-1, 1], [-1], [1, 0]] + >>> R.dmp_sub(x**2 + y, x**2*y + x) + -x**2*y + x**2 - x + y """ if not u: @@ -705,7 +670,7 @@ if dg < 0: return f - v = u-1 + v = u - 1 if df == dg: return dmp_strip([ dmp_sub(a, b, v, K) for a, b in zip(f, g) ], u) @@ -719,6 +684,7 @@ return h + [ dmp_sub(a, b, v, K) for a, b in zip(f, g) ] + def dup_add_mul(f, g, h, K): """ Returns ``f + g*h`` where ``f, g, h`` are in ``K[x]``. @@ -726,19 +692,16 @@ Examples ======== - >>> from sympy.polys.domains import ZZ - >>> from sympy.polys.densearith import dup_add_mul + >>> from sympy.polys import ring, ZZ + >>> R, x = ring("x", ZZ) - >>> f = ZZ.map([1, 0, -1]) - >>> g = ZZ.map([1, -2]) - >>> h = ZZ.map([1, 2]) - - >>> dup_add_mul(f, g, h, ZZ) - [2, 0, -5] + >>> R.dup_add_mul(x**2 - 1, x - 2, x + 2) + 2*x**2 - 5 """ return dup_add(f, dup_mul(g, h, K), K) + @cythonized("u") def dmp_add_mul(f, g, h, u, K): """ @@ -747,19 +710,16 @@ Examples ======== - >>> from sympy.polys.domains import ZZ - >>> from sympy.polys.densearith import dmp_add_mul + >>> from sympy.polys import ring, ZZ + >>> R, x,y = ring("x,y", ZZ) - >>> f = ZZ.map([[1], [], [1, 0]]) - >>> g = ZZ.map([[1], []]) - >>> h = ZZ.map([[1], [2]]) - - >>> dmp_add_mul(f, g, h, 1, ZZ) - [[2], [2], [1, 0]] + >>> R.dmp_add_mul(x**2 + y, x, x + 2) + 2*x**2 + 2*x + y """ return dmp_add(f, dmp_mul(g, h, u, K), u, K) + def dup_sub_mul(f, g, h, K): """ Returns ``f - g*h`` where ``f, g, h`` are in ``K[x]``. @@ -767,19 +727,16 @@ Examples ======== - >>> from sympy.polys.domains import ZZ - >>> from sympy.polys.densearith import dup_sub_mul + >>> from sympy.polys import ring, ZZ + >>> R, x = ring("x", ZZ) - >>> f = ZZ.map([1, 0, -1]) - >>> g = ZZ.map([1, -2]) - >>> h = ZZ.map([1, 2]) - - >>> dup_sub_mul(f, g, h, ZZ) - [3] + >>> R.dup_sub_mul(x**2 - 1, x - 2, x + 2) + 3 """ return dup_sub(f, dup_mul(g, h, K), K) + @cythonized("u") def dmp_sub_mul(f, g, h, u, K): """ @@ -788,19 +745,16 @@ Examples ======== - >>> from sympy.polys.domains import ZZ - >>> from sympy.polys.densearith import dmp_sub_mul - - >>> f = ZZ.map([[1], [], [1, 0]]) - >>> g = ZZ.map([[1], []]) - >>> h = ZZ.map([[1], [2]]) + >>> from sympy.polys import ring, ZZ + >>> R, x,y = ring("x,y", ZZ) - >>> dmp_sub_mul(f, g, h, 1, ZZ) - [[-2], [1, 0]] + >>> R.dmp_sub_mul(x**2 + y, x, x + 2) + -2*x + y """ return dmp_sub(f, dmp_mul(g, h, u, K), u, K) + @cythonized("df,dg,i,j") def dup_mul(f, g, K): """ @@ -809,14 +763,11 @@ Examples ======== - >>> from sympy.polys.domains import ZZ - >>> from sympy.polys.densearith import dup_mul - - >>> f = ZZ.map([1, -2]) - >>> g = ZZ.map([1, 2]) + >>> from sympy.polys import ring, ZZ + >>> R, x = ring("x", ZZ) - >>> dup_mul(f, g, ZZ) - [1, 0, -4] + >>> R.dup_mul(x - 2, x + 2) + x**2 - 4 """ if f == g: @@ -830,16 +781,17 @@ h = [] - for i in range(0, df+dg+1): + for i in range(0, df + dg + 1): coeff = K.zero - for j in range(max(0, i-dg), min(df, i)+1): - coeff += f[j]*g[i-j] + for j in range(max(0, i - dg), min(df, i) + 1): + coeff += f[j]*g[i - j] h.append(coeff) return dup_strip(h) + @cythonized("u,v,df,dg,i,j") def dmp_mul(f, g, u, K): """ @@ -848,14 +800,11 @@ Examples ======== - >>> from sympy.polys.domains import ZZ - >>> from sympy.polys.densearith import dmp_mul - - >>> f = ZZ.map([[1, 0], [1]]) - >>> g = ZZ.map([[1], []]) + >>> from sympy.polys import ring, ZZ + >>> R, x,y = ring("x,y", ZZ) - >>> dmp_mul(f, g, 1, ZZ) - [[1, 0], [1], []] + >>> R.dmp_mul(x*y + 1, x) + x**2*y + x """ if not u: @@ -874,18 +823,19 @@ if dg < 0: return g - h, v = [], u-1 + h, v = [], u - 1 - for i in range(0, df+dg+1): + for i in range(0, df + dg + 1): coeff = dmp_zero(v) - for j in range(max(0, i-dg), min(df, i)+1): - coeff = dmp_add(coeff, dmp_mul(f[j], g[i-j], v, K), v, K) + for j in range(max(0, i - dg), min(df, i) + 1): + coeff = dmp_add(coeff, dmp_mul(f[j], g[i - j], v, K), v, K) h.append(coeff) return dmp_strip(h, u) + @cythonized("df,jmin,jmax,n,i,j") def dup_sqr(f, K): """ @@ -894,40 +844,39 @@ Examples ======== - >>> from sympy.polys.domains import ZZ - >>> from sympy.polys.densearith import dup_sqr - - >>> f = ZZ.map([1, 0, 1]) + >>> from sympy.polys import ring, ZZ + >>> R, x = ring("x", ZZ) - >>> dup_sqr(f, ZZ) - [1, 0, 2, 0, 1] + >>> R.dup_sqr(x**2 + 1) + x**4 + 2*x**2 + 1 """ df, h = dup_degree(f), [] - for i in range(0, 2*df+1): + for i in range(0, 2*df + 1): c = K.zero - jmin = max(0, i-df) + jmin = max(0, i - df) jmax = min(i, df) n = jmax - jmin + 1 jmax = jmin + n // 2 - 1 - for j in range(jmin, jmax+1): - c += f[j]*f[i-j] + for j in range(jmin, jmax + 1): + c += f[j]*f[i - j] c += c if n & 1: - elem = f[jmax+1] + elem = f[jmax + 1] c += elem**2 h.append(c) return dup_strip(h) + @cythonized("u,v,df,jmin,jmax,n,i,j") def dmp_sqr(f, u, K): """ @@ -936,13 +885,11 @@ Examples ======== - >>> from sympy.polys.domains import ZZ - >>> from sympy.polys.densearith import dmp_sqr - - >>> f = ZZ.map([[1], [1, 0], [1, 0, 0]]) + >>> from sympy.polys import ring, ZZ + >>> R, x,y = ring("x,y", ZZ) - >>> dmp_sqr(f, 1, ZZ) - [[1], [2, 0], [3, 0, 0], [2, 0, 0, 0], [1, 0, 0, 0, 0]] + >>> R.dmp_sqr(x**2 + x*y + y**2) + x**4 + 2*x**3*y + 3*x**2*y**2 + 2*x*y**3 + y**4 """ if not u: @@ -953,31 +900,32 @@ if df < 0: return f - h, v = [], u-1 + h, v = [], u - 1 - for i in range(0, 2*df+1): + for i in range(0, 2*df + 1): c = dmp_zero(v) - jmin = max(0, i-df) + jmin = max(0, i - df) jmax = min(i, df) n = jmax - jmin + 1 jmax = jmin + n // 2 - 1 - for j in range(jmin, jmax+1): - c = dmp_add(c, dmp_mul(f[j], f[i-j], v, K), v, K) + for j in range(jmin, jmax + 1): + c = dmp_add(c, dmp_mul(f[j], f[i - j], v, K), v, K) c = dmp_mul_ground(c, K(2), v, K) if n & 1: - elem = dmp_sqr(f[jmax+1], v, K) + elem = dmp_sqr(f[jmax + 1], v, K) c = dmp_add(c, elem, v, K) h.append(c) return dmp_strip(h, u) + @cythonized("n,m") def dup_pow(f, n, K): """ @@ -986,11 +934,11 @@ Examples ======== - >>> from sympy.polys.domains import ZZ - >>> from sympy.polys.densearith import dup_pow + >>> from sympy.polys import ring, ZZ + >>> R, x = ring("x", ZZ) - >>> dup_pow([ZZ(1), -ZZ(2)], 3, ZZ) - [1, -6, 12, -8] + >>> R.dup_pow(x - 2, 3) + x**3 - 6*x**2 + 12*x - 8 """ if not n: @@ -1015,6 +963,7 @@ return g + @cythonized("u,n,m") def dmp_pow(f, n, u, K): """ @@ -1023,13 +972,11 @@ Examples ======== - >>> from sympy.polys.domains import ZZ - >>> from sympy.polys.densearith import dmp_pow - - >>> f = ZZ.map([[1, 0], [1]]) + >>> from sympy.polys import ring, ZZ + >>> R, x,y = ring("x,y", ZZ) - >>> dmp_pow(f, 3, 1, ZZ) - [[1, 0, 0, 0], [3, 0, 0], [3, 0], [1]] + >>> R.dmp_pow(x*y + 1, 3) + x**3*y**3 + 3*x**2*y**2 + 3*x*y + 1 """ if not u: @@ -1057,6 +1004,7 @@ return g + @cythonized("df,dg,dr,N,j") def dup_pdiv(f, g, K): """ @@ -1065,14 +1013,11 @@ Examples ======== - >>> from sympy.polys.domains import ZZ - >>> from sympy.polys.densearith import dup_pdiv - - >>> f = ZZ.map([1, 0, 1]) - >>> g = ZZ.map([2, -4]) + >>> from sympy.polys import ring, ZZ + >>> R, x = ring("x", ZZ) - >>> dup_pdiv(f, g, ZZ) - ([2, 4], [20]) + >>> R.dup_pdiv(x**2 + 1, 2*x - 4) + (2*x + 4, 20) """ df = dup_degree(f) @@ -1095,7 +1040,7 @@ break lc_r = dup_LC(r, K) - j, N = dr-dg, N-1 + j, N = dr - dg, N - 1 Q = dup_mul_ground(q, lc_g, K) q = dup_add_term(Q, lc_r, j, K) @@ -1111,6 +1056,7 @@ return q, r + @cythonized("df,dg,dr,N,j") def dup_prem(f, g, K): """ @@ -1119,14 +1065,11 @@ Examples ======== - >>> from sympy.polys.domains import ZZ - >>> from sympy.polys.densearith import dup_prem - - >>> f = ZZ.map([1, 0, 1]) - >>> g = ZZ.map([2, -4]) + >>> from sympy.polys import ring, ZZ + >>> R, x = ring("x", ZZ) - >>> dup_prem(f, g, ZZ) - [20] + >>> R.dup_prem(x**2 + 1, 2*x - 4) + 20 """ df = dup_degree(f) @@ -1149,7 +1092,7 @@ break lc_r = dup_LC(r, K) - j, N = dr-dg, N-1 + j, N = dr - dg, N - 1 R = dup_mul_ground(r, lc_g, K) G = dup_mul_term(g, lc_r, j, K) @@ -1157,6 +1100,7 @@ return dup_mul_ground(r, lc_g**N, K) + def dup_pquo(f, g, K): """ Polynomial exact pseudo-quotient in ``K[X]``. @@ -1164,24 +1108,19 @@ Examples ======== - >>> from sympy.polys.domains import ZZ - >>> from sympy.polys.densearith import dup_pquo - - >>> f = ZZ.map([1, 0, -1]) - >>> g = ZZ.map([2, -2]) - - >>> dup_pquo(f, g, ZZ) - [2, 2] + >>> from sympy.polys import ring, ZZ + >>> R, x = ring("x", ZZ) - >>> f = ZZ.map([1, 0, 1]) - >>> g = ZZ.map([2, -4]) + >>> R.dup_pquo(x**2 - 1, 2*x - 2) + 2*x + 2 - >>> dup_pquo(f, g, ZZ) - [2, 4] + >>> R.dup_pquo(x**2 + 1, 2*x - 4) + 2*x + 4 """ return dup_pdiv(f, g, K)[0] + def dup_pexquo(f, g, K): """ Polynomial pseudo-quotient in ``K[x]``. @@ -1189,19 +1128,13 @@ Examples ======== - >>> from sympy.polys.domains import ZZ - >>> from sympy.polys.densearith import dup_pexquo - - >>> f = ZZ.map([1, 0, -1]) - >>> g = ZZ.map([2, -2]) + >>> from sympy.polys import ring, ZZ + >>> R, x = ring("x", ZZ) - >>> dup_pexquo(f, g, ZZ) - [2, 2] + >>> R.dup_pexquo(x**2 - 1, 2*x - 2) + 2*x + 2 - >>> f = ZZ.map([1, 0, 1]) - >>> g = ZZ.map([2, -4]) - - >>> dup_pexquo(f, g, ZZ) + >>> R.dup_pexquo(x**2 + 1, 2*x - 4) Traceback (most recent call last): ... ExactQuotientFailed: [2, -4] does not divide [1, 0, 1] @@ -1214,6 +1147,7 @@ else: raise ExactQuotientFailed(f, g) + @cythonized("u,df,dg,dr,N,j") def dmp_pdiv(f, g, u, K): """ @@ -1222,14 +1156,11 @@ Examples ======== - >>> from sympy.polys.domains import ZZ - >>> from sympy.polys.densearith import dmp_pdiv + >>> from sympy.polys import ring, ZZ + >>> R, x,y = ring("x,y", ZZ) - >>> f = ZZ.map([[1], [1, 0], []]) - >>> g = ZZ.map([[2], [2]]) - - >>> dmp_pdiv(f, g, 1, ZZ) - ([[2], [2, -2]], [[-4, 4]]) + >>> R.dmp_pdiv(x**2 + x*y, 2*x + 2) + (2*x + 2*y - 2, -4*y + 4) """ if not u: @@ -1256,7 +1187,7 @@ break lc_r = dmp_LC(r, K) - j, N = dr-dg, N-1 + j, N = dr - dg, N - 1 Q = dmp_mul_term(q, lc_g, 0, u, K) q = dmp_add_term(Q, lc_r, j, u, K) @@ -1265,13 +1196,14 @@ G = dmp_mul_term(g, lc_r, j, u, K) r = dmp_sub(R, G, u, K) - c = dmp_pow(lc_g, N, u-1, K) + c = dmp_pow(lc_g, N, u - 1, K) q = dmp_mul_term(q, c, 0, u, K) r = dmp_mul_term(r, c, 0, u, K) return q, r + @cythonized("u,df,dg,dr,N,j") def dmp_prem(f, g, u, K): """ @@ -1280,14 +1212,11 @@ Examples ======== - >>> from sympy.polys.domains import ZZ - >>> from sympy.polys.densearith import dmp_prem + >>> from sympy.polys import ring, ZZ + >>> R, x,y = ring("x,y", ZZ) - >>> f = ZZ.map([[1], [1, 0], []]) - >>> g = ZZ.map([[2], [2]]) - - >>> dmp_prem(f, g, 1, ZZ) - [[-4, 4]] + >>> R.dmp_prem(x**2 + x*y, 2*x + 2) + -4*y + 4 """ if not u: @@ -1314,16 +1243,17 @@ break lc_r = dmp_LC(r, K) - j, N = dr-dg, N-1 + j, N = dr - dg, N - 1 R = dmp_mul_term(r, lc_g, 0, u, K) G = dmp_mul_term(g, lc_r, j, u, K) r = dmp_sub(R, G, u, K) - c = dmp_pow(lc_g, N, u-1, K) + c = dmp_pow(lc_g, N, u - 1, K) return dmp_mul_term(r, c, 0, u, K) + def dmp_pquo(f, g, u, K): """ Polynomial exact pseudo-quotient in ``K[X]``. @@ -1331,22 +1261,23 @@ Examples ======== - >>> from sympy.polys.domains import ZZ - >>> from sympy.polys.densearith import dmp_pquo + >>> from sympy.polys import ring, ZZ + >>> R, x,y = ring("x,y", ZZ) - >>> f = ZZ.map([[1], [1, 0], []]) - >>> g = ZZ.map([[2], [2, 0]]) - >>> h = ZZ.map([[2], [2]]) + >>> f = x**2 + x*y + >>> g = 2*x + 2*y + >>> h = 2*x + 2 - >>> dmp_pquo(f, g, 1, ZZ) - [[2], []] + >>> R.dmp_pquo(f, g) + 2*x - >>> dmp_pquo(f, h, 1, ZZ) - [[2], [2, -2]] + >>> R.dmp_pquo(f, h) + 2*x + 2*y - 2 """ return dmp_pdiv(f, g, u, K)[0] + def dmp_pexquo(f, g, u, K): """ Polynomial pseudo-quotient in ``K[X]``. @@ -1354,17 +1285,17 @@ Examples ======== - >>> from sympy.polys.domains import ZZ - >>> from sympy.polys.densearith import dmp_pexquo + >>> from sympy.polys import ring, ZZ + >>> R, x,y = ring("x,y", ZZ) - >>> f = ZZ.map([[1], [1, 0], []]) - >>> g = ZZ.map([[2], [2, 0]]) - >>> h = ZZ.map([[2], [2]]) + >>> f = x**2 + x*y + >>> g = 2*x + 2*y + >>> h = 2*x + 2 - >>> dmp_pexquo(f, g, 1, ZZ) - [[2], []] + >>> R.dmp_pexquo(f, g) + 2*x - >>> dmp_pexquo(f, h, 1, ZZ) + >>> R.dmp_pexquo(f, h) Traceback (most recent call last): ... ExactQuotientFailed: [[2], [2]] does not divide [[1], [1, 0], []] @@ -1377,6 +1308,7 @@ else: raise ExactQuotientFailed(f, g) + @cythonized("df,dg,dr,j") def dup_rr_div(f, g, K): """ @@ -1385,14 +1317,11 @@ Examples ======== - >>> from sympy.polys.domains import ZZ - >>> from sympy.polys.densearith import dup_rr_div - - >>> f = ZZ.map([1, 0, 1]) - >>> g = ZZ.map([2, -4]) + >>> from sympy.polys import ring, ZZ + >>> R, x = ring("x", ZZ) - >>> dup_rr_div(f, g, ZZ) - ([], [1, 0, 1]) + >>> R.dup_rr_div(x**2 + 1, 2*x - 4) + (0, x**2 + 1) """ df = dup_degree(f) @@ -1428,6 +1357,7 @@ return q, r + @cythonized("u,df,dg,dr,j") def dmp_rr_div(f, g, u, K): """ @@ -1436,14 +1366,11 @@ Examples ======== - >>> from sympy.polys.domains import ZZ - >>> from sympy.polys.densearith import dmp_rr_div - - >>> f = ZZ.map([[1], [1, 0], []]) - >>> g = ZZ.map([[2], [2]]) + >>> from sympy.polys import ring, ZZ + >>> R, x,y = ring("x,y", ZZ) - >>> dmp_rr_div(f, g, 1, ZZ) - ([[]], [[1], [1, 0], []]) + >>> R.dmp_rr_div(x**2 + x*y, 2*x + 2) + (0, x**2 + x*y) """ if not u: @@ -1460,7 +1387,7 @@ if df < dg: return q, r - lc_g, v = dmp_LC(g, K), u-1 + lc_g, v = dmp_LC(g, K), u - 1 while True: dr = dmp_degree(r, u) @@ -1484,6 +1411,7 @@ return q, r + @cythonized("df,dg,dr,j") def dup_ff_div(f, g, K): """ @@ -1492,14 +1420,11 @@ Examples ======== - >>> from sympy.polys.domains import QQ - >>> from sympy.polys.densearith import dup_ff_div - - >>> f = QQ.map([1, 0, 1]) - >>> g = QQ.map([2, -4]) + >>> from sympy.polys import ring, QQ + >>> R, x = ring("x", QQ) - >>> dup_ff_div(f, g, QQ) - ([1/2, 1/1], [5/1]) + >>> R.dup_ff_div(x**2 + 1, 2*x - 4) + (1/2*x + 1, 5) """ df = dup_degree(f) @@ -1535,6 +1460,7 @@ return q, r + @cythonized("u,df,dg,dr,j") def dmp_ff_div(f, g, u, K): """ @@ -1543,14 +1469,11 @@ Examples ======== - >>> from sympy.polys.domains import QQ - >>> from sympy.polys.densearith import dmp_ff_div - - >>> f = QQ.map([[1], [1, 0], []]) - >>> g = QQ.map([[2], [2]]) + >>> from sympy.polys import ring, QQ + >>> R, x,y = ring("x,y", QQ) - >>> dmp_ff_div(f, g, 1, QQ) - ([[1/2], [1/2, -1/2]], [[-1/1, 1/1]]) + >>> R.dmp_ff_div(x**2 + x*y, 2*x + 2) + (1/2*x + 1/2*y - 1/2, -y + 1) """ if not u: @@ -1567,7 +1490,7 @@ if df < dg: return q, r - lc_g, v = dmp_LC(g, K), u-1 + lc_g, v = dmp_LC(g, K), u - 1 while True: dr = dmp_degree(r, u) @@ -1591,6 +1514,7 @@ return q, r + def dup_div(f, g, K): """ Polynomial division with remainder in ``K[x]``. @@ -1598,20 +1522,15 @@ Examples ======== - >>> from sympy.polys.domains import ZZ, QQ - >>> from sympy.polys.densearith import dup_div - - >>> f = ZZ.map([1, 0, 1]) - >>> g = ZZ.map([2, -4]) + >>> from sympy.polys import ring, ZZ, QQ - >>> dup_div(f, g, ZZ) - ([], [1, 0, 1]) - - >>> f = QQ.map([1, 0, 1]) - >>> g = QQ.map([2, -4]) - - >>> dup_div(f, g, QQ) - ([1/2, 1/1], [5/1]) + >>> R, x = ring("x", ZZ) + >>> R.dup_div(x**2 + 1, 2*x - 4) + (0, x**2 + 1) + + >>> R, x = ring("x", QQ) + >>> R.dup_div(x**2 + 1, 2*x - 4) + (1/2*x + 1, 5) """ if K.has_Field or not K.is_Exact: @@ -1619,6 +1538,7 @@ else: return dup_rr_div(f, g, K) + def dup_rem(f, g, K): """ Returns polynomial remainder in ``K[x]``. @@ -1626,24 +1546,20 @@ Examples ======== - >>> from sympy.polys.domains import ZZ, QQ - >>> from sympy.polys.densearith import dup_rem - - >>> f = ZZ.map([1, 0, 1]) - >>> g = ZZ.map([2, -4]) + >>> from sympy.polys import ring, ZZ, QQ - >>> dup_rem(f, g, ZZ) - [1, 0, 1] - - >>> f = QQ.map([1, 0, 1]) - >>> g = QQ.map([2, -4]) - - >>> dup_rem(f, g, QQ) - [5/1] + >>> R, x = ring("x", ZZ) + >>> R.dup_rem(x**2 + 1, 2*x - 4) + x**2 + 1 + + >>> R, x = ring("x", QQ) + >>> R.dup_rem(x**2 + 1, 2*x - 4) + 5 """ return dup_div(f, g, K)[1] + def dup_quo(f, g, K): """ Returns exact polynomial quotient in ``K[x]``. @@ -1651,24 +1567,20 @@ Examples ======== - >>> from sympy.polys.domains import ZZ, QQ - >>> from sympy.polys.densearith import dup_quo - - >>> f = ZZ.map([1, 0, 1]) - >>> g = ZZ.map([2, -4]) - - >>> dup_quo(f, g, ZZ) - [] + >>> from sympy.polys import ring, ZZ, QQ - >>> f = QQ.map([1, 0, 1]) - >>> g = QQ.map([2, -4]) - - >>> dup_quo(f, g, QQ) - [1/2, 1/1] + >>> R, x = ring("x", ZZ) + >>> R.dup_quo(x**2 + 1, 2*x - 4) + 0 + + >>> R, x = ring("x", QQ) + >>> R.dup_quo(x**2 + 1, 2*x - 4) + 1/2*x + 1 """ return dup_div(f, g, K)[0] + def dup_exquo(f, g, K): """ Returns polynomial quotient in ``K[x]``. @@ -1676,19 +1588,13 @@ Examples ======== - >>> from sympy.polys.domains import ZZ - >>> from sympy.polys.densearith import dup_exquo - - >>> f = ZZ.map([1, 0, -1]) - >>> g = ZZ.map([1, -1]) - - >>> dup_exquo(f, g, ZZ) - [1, 1] + >>> from sympy.polys import ring, ZZ + >>> R, x = ring("x", ZZ) - >>> f = ZZ.map([1, 0, 1]) - >>> g = ZZ.map([2, -4]) + >>> R.dup_exquo(x**2 - 1, x - 1) + x + 1 - >>> dup_exquo(f, g, ZZ) + >>> R.dup_exquo(x**2 + 1, 2*x - 4) Traceback (most recent call last): ... ExactQuotientFailed: [2, -4] does not divide [1, 0, 1] @@ -1701,6 +1607,7 @@ else: raise ExactQuotientFailed(f, g) + @cythonized("u") def dmp_div(f, g, u, K): """ @@ -1709,20 +1616,15 @@ Examples ======== - >>> from sympy.polys.domains import ZZ, QQ - >>> from sympy.polys.densearith import dmp_div - - >>> f = ZZ.map([[1], [1, 0], []]) - >>> g = ZZ.map([[2], [2]]) - - >>> dmp_div(f, g, 1, ZZ) - ([[]], [[1], [1, 0], []]) - - >>> f = QQ.map([[1], [1, 0], []]) - >>> g = QQ.map([[2], [2]]) + >>> from sympy.polys import ring, ZZ, QQ - >>> dmp_div(f, g, 1, QQ) - ([[1/2], [1/2, -1/2]], [[-1/1, 1/1]]) + >>> R, x,y = ring("x,y", ZZ) + >>> R.dmp_div(x**2 + x*y, 2*x + 2) + (0, x**2 + x*y) + + >>> R, x,y = ring("x,y", QQ) + >>> R.dmp_div(x**2 + x*y, 2*x + 2) + (1/2*x + 1/2*y - 1/2, -y + 1) """ if K.has_Field or not K.is_Exact: @@ -1730,6 +1632,7 @@ else: return dmp_rr_div(f, g, u, K) + @cythonized("u") def dmp_rem(f, g, u, K): """ @@ -1738,24 +1641,20 @@ Examples ======== - >>> from sympy.polys.domains import ZZ, QQ - >>> from sympy.polys.densearith import dmp_rem - - >>> f = ZZ.map([[1], [1, 0], []]) - >>> g = ZZ.map([[2], [2]]) - - >>> dmp_rem(f, g, 1, ZZ) - [[1], [1, 0], []] - - >>> f = QQ.map([[1], [1, 0], []]) - >>> g = QQ.map([[2], [2]]) + >>> from sympy.polys import ring, ZZ, QQ - >>> dmp_rem(f, g, 1, QQ) - [[-1/1, 1/1]] + >>> R, x,y = ring("x,y", ZZ) + >>> R.dmp_rem(x**2 + x*y, 2*x + 2) + x**2 + x*y + + >>> R, x,y = ring("x,y", QQ) + >>> R.dmp_rem(x**2 + x*y, 2*x + 2) + -y + 1 """ return dmp_div(f, g, u, K)[1] + @cythonized("u") def dmp_quo(f, g, u, K): """ @@ -1764,24 +1663,20 @@ Examples ======== - >>> from sympy.polys.domains import ZZ, QQ - >>> from sympy.polys.densearith import dmp_quo - - >>> f = ZZ.map([[1], [1, 0], []]) - >>> g = ZZ.map([[2], [2]]) - - >>> dmp_quo(f, g, 1, ZZ) - [[]] + >>> from sympy.polys import ring, ZZ, QQ - >>> f = QQ.map([[1], [1, 0], []]) - >>> g = QQ.map([[2], [2]]) - - >>> dmp_quo(f, g, 1, QQ) - [[1/2], [1/2, -1/2]] + >>> R, x,y = ring("x,y", ZZ) + >>> R.dmp_quo(x**2 + x*y, 2*x + 2) + 0 + + >>> R, x,y = ring("x,y", QQ) + >>> R.dmp_quo(x**2 + x*y, 2*x + 2) + 1/2*x + 1/2*y - 1/2 """ return dmp_div(f, g, u, K)[0] + @cythonized("u") def dmp_exquo(f, g, u, K): """ @@ -1790,17 +1685,17 @@ Examples ======== - >>> from sympy.polys.domains import ZZ - >>> from sympy.polys.densearith import dmp_exquo + >>> from sympy.polys import ring, ZZ + >>> R, x,y = ring("x,y", ZZ) - >>> f = ZZ.map([[1], [1, 0], []]) - >>> g = ZZ.map([[1], [1, 0]]) - >>> h = ZZ.map([[2], [2]]) + >>> f = x**2 + x*y + >>> g = x + y + >>> h = 2*x + 2 - >>> dmp_exquo(f, g, 1, ZZ) - [[1], []] + >>> R.dmp_exquo(f, g) + x - >>> dmp_exquo(f, h, 1, ZZ) + >>> R.dmp_exquo(f, h) Traceback (most recent call last): ... ExactQuotientFailed: [[2], [2]] does not divide [[1], [1, 0], []] @@ -1813,6 +1708,7 @@ else: raise ExactQuotientFailed(f, g) + def dup_max_norm(f, K): """ Returns maximum norm of a polynomial in ``K[x]``. @@ -1820,12 +1716,10 @@ Examples ======== - >>> from sympy.polys.domains import ZZ - >>> from sympy.polys.densearith import dup_max_norm - - >>> f = ZZ.map([-1, 2, -3]) + >>> from sympy.polys import ring, ZZ + >>> R, x = ring("x", ZZ) - >>> dup_max_norm(f, ZZ) + >>> R.dup_max_norm(-x**2 + 2*x - 3) 3 """ @@ -1834,6 +1728,7 @@ else: return max(dup_abs(f, K)) + @cythonized("u,v") def dmp_max_norm(f, u, K): """ @@ -1842,22 +1737,21 @@ Examples ======== - >>> from sympy.polys.domains import ZZ - >>> from sympy.polys.densearith import dmp_max_norm - - >>> f = ZZ.map([[2, -1], [-3]]) + >>> from sympy.polys import ring, ZZ + >>> R, x,y = ring("x,y", ZZ) - >>> dmp_max_norm(f, 1, ZZ) + >>> R.dmp_max_norm(2*x*y - x - 3) 3 """ if not u: return dup_max_norm(f, K) - v = u-1 + v = u - 1 return max([ dmp_max_norm(c, v, K) for c in f ]) + def dup_l1_norm(f, K): """ Returns l1 norm of a polynomial in ``K[x]``. @@ -1865,12 +1759,10 @@ Examples ======== - >>> from sympy.polys.domains import ZZ - >>> from sympy.polys.densearith import dup_l1_norm - - >>> f = ZZ.map([2, -3, 0, 1]) + >>> from sympy.polys import ring, ZZ + >>> R, x = ring("x", ZZ) - >>> dup_l1_norm(f, ZZ) + >>> R.dup_l1_norm(2*x**3 - 3*x**2 + 1) 6 """ @@ -1879,6 +1771,7 @@ else: return sum(dup_abs(f, K)) + @cythonized("u,v") def dmp_l1_norm(f, u, K): """ @@ -1887,22 +1780,21 @@ Examples ======== - >>> from sympy.polys.domains import ZZ - >>> from sympy.polys.densearith import dmp_l1_norm - - >>> f = ZZ.map([[2, -1], [-3]]) + >>> from sympy.polys import ring, ZZ + >>> R, x,y = ring("x,y", ZZ) - >>> dmp_l1_norm(f, 1, ZZ) + >>> R.dmp_l1_norm(2*x*y - x - 3) 6 """ if not u: return dup_l1_norm(f, K) - v = u-1 + v = u - 1 return sum([ dmp_l1_norm(c, v, K) for c in f ]) + def dup_expand(polys, K): """ Multiply together several polynomials in ``K[x]``. @@ -1910,15 +1802,11 @@ Examples ======== - >>> from sympy.polys.domains import ZZ - >>> from sympy.polys.densearith import dup_expand - - >>> f = ZZ.map([1, 0, -1]) - >>> g = ZZ.map([1, 0]) - >>> h = ZZ.map([2]) + >>> from sympy.polys import ring, ZZ + >>> R, x = ring("x", ZZ) - >>> dup_expand([f, g, h], ZZ) - [2, 0, -2, 0] + >>> R.dup_expand([x**2 - 1, x, 2]) + 2*x**3 - 2*x """ if not polys: @@ -1931,6 +1819,7 @@ return f + @cythonized("u") def dmp_expand(polys, u, K): """ @@ -1939,14 +1828,11 @@ Examples ======== - >>> from sympy.polys.domains import ZZ - >>> from sympy.polys.densearith import dmp_expand - - >>> f = ZZ.map([[1], [], [1, 0, 0]]) - >>> g = ZZ.map([[1], [1]]) + >>> from sympy.polys import ring, ZZ + >>> R, x,y = ring("x,y", ZZ) - >>> dmp_expand([f, g], 1, ZZ) - [[1], [1], [1, 0, 0], [1, 0, 0]] + >>> R.dmp_expand([x**2 + y**2, x + 1]) + x**3 + x**2 + x*y**2 + y**2 """ if not polys: diff -Nru python3-sympy-0.7.2/sympy/polys/densebasic.py python3-sympy-0.7.3/sympy/polys/densebasic.py --- python3-sympy-0.7.2/sympy/polys/densebasic.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/polys/densebasic.py 2013-07-13 17:53:32.000000000 +0000 @@ -6,12 +6,11 @@ monomial_key, monomial_min, monomial_div ) -from sympy.polys.distributedpolys import sdp_sort - from sympy.utilities import cythonized import random + def poly_LC(f, K): """ Return leading coefficient of ``f``. @@ -33,6 +32,7 @@ else: return f[0] + def poly_TC(f, K): """ Return trailing coefficient of ``f``. @@ -57,10 +57,11 @@ dup_LC = dmp_LC = poly_LC dup_TC = dmp_TC = poly_TC + @cythonized("u") def dmp_ground_LC(f, u, K): """ - Return ground leading coefficient. + Return the ground leading coefficient. Examples ======== @@ -80,10 +81,11 @@ return dup_LC(f, K) + @cythonized("u") def dmp_ground_TC(f, u, K): """ - Return ground trailing coefficient. + Return the ground trailing coefficient. Examples ======== @@ -103,10 +105,11 @@ return dup_TC(f, K) + @cythonized("u") def dmp_true_LT(f, u, K): """ - Return leading term ``c * x_1**n_1 ... x_k**n_k``. + Return the leading term ``c * x_1**n_1 ... x_k**n_k``. Examples ======== @@ -133,9 +136,10 @@ return tuple(monom), dup_LC(f, K) + def dup_degree(f): """ - Return leading degree of ``f`` in ``K[x]``. + Return the leading degree of ``f`` in ``K[x]``. Examples ======== @@ -151,10 +155,11 @@ """ return len(f) - 1 + @cythonized("u") def dmp_degree(f, u): """ - Return leading degree of ``f`` in ``x_0`` in ``K[X]``. + Return the leading degree of ``f`` in ``x_0`` in ``K[X]``. Examples ======== @@ -176,20 +181,22 @@ else: return len(f) - 1 + @cythonized("v,i,j") def _rec_degree_in(g, v, i, j): """Recursive helper function for :func:`dmp_degree_in`.""" if i == j: return dmp_degree(g, v) - v, i = v-1, i+1 + v, i = v - 1, i + 1 return max([ _rec_degree_in(c, v, i, j) for c in g ]) + @cythonized("j,u") def dmp_degree_in(f, j, u): """ - Return leading degree of ``f`` in ``x_j`` in ``K[X]``. + Return the leading degree of ``f`` in ``x_j`` in ``K[X]``. Examples ======== @@ -208,21 +215,23 @@ if not j: return dmp_degree(f, u) if j < 0 or j > u: - raise IndexError("-%s <= j < %s expected, got %s" % (u, u, j)) + raise IndexError("0 <= j <= %s expected, got %s" % (u, j)) return _rec_degree_in(f, u, 0, j) + @cythonized("v,i") def _rec_degree_list(g, v, i, degs): """Recursive helper for :func:`dmp_degree_list`.""" degs[i] = max(degs[i], dmp_degree(g, v)) if v > 0: - v, i = v-1, i+1 + v, i = v - 1, i + 1 for c in g: _rec_degree_list(c, v, i, degs) + @cythonized("u") def dmp_degree_list(f, u): """ @@ -240,10 +249,11 @@ (1, 2) """ - degs = [-1]*(u+1) + degs = [-1]*(u + 1) _rec_degree_list(f, u, 0, degs) return tuple(degs) + @cythonized("i") def dup_strip(f): """ @@ -271,6 +281,7 @@ return f[i:] + @cythonized("u,v,i") def dmp_strip(f, u): """ @@ -291,7 +302,7 @@ if dmp_zero_p(f, u): return f - i, v = 0, u-1 + i, v = 0, u - 1 for c in f: if not dmp_zero_p(c, v): @@ -304,6 +315,7 @@ else: return f[i:] + @cythonized("i,j") def _rec_validate(f, g, i, K): """Recursive helper for :func:`dmp_validate`.""" @@ -311,31 +323,33 @@ if K is not None and not K.of_type(g): raise TypeError("%s in %s in not of type %s" % (g, f, K.dtype)) - return set([i-1]) + return set([i - 1]) elif not g: return set([i]) else: - j, levels = i+1, set([]) + j, levels = i + 1, set([]) for c in g: - levels |= _rec_validate(f, c, i+1, K) + levels |= _rec_validate(f, c, i + 1, K) return levels + @cythonized("v,w") def _rec_strip(g, v): """Recursive helper for :func:`_rec_strip`.""" if not v: return dup_strip(g) - w = v-1 + w = v - 1 return dmp_strip([ _rec_strip(c, w) for c in g ], v) + @cythonized("u") def dmp_validate(f, K=None): """ - Return number of levels in ``f`` and recursively strips it. + Return the number of levels in ``f`` and recursively strip it. Examples ======== @@ -358,7 +372,9 @@ if not levels: return _rec_strip(f, u), u else: - raise ValueError("invalid data structure for a multivariate polynomial") + raise ValueError( + "invalid data structure for a multivariate polynomial") + def dup_reverse(f): """ @@ -378,6 +394,7 @@ """ return dup_strip(list(reversed(f))) + def dup_copy(f): """ Create a new copy of a polynomial ``f`` in ``K[x]``. @@ -396,6 +413,7 @@ """ return list(f) + @cythonized("u,v") def dmp_copy(f, u): """ @@ -416,10 +434,11 @@ if not u: return list(f) - v = u-1 + v = u - 1 return [ dmp_copy(c, v) for c in f ] + def dup_to_tuple(f): """ Convert `f` into a tuple. @@ -440,6 +459,7 @@ """ return tuple(f) + @cythonized("u,v") def dmp_to_tuple(f, u): """ @@ -465,6 +485,7 @@ return tuple(dmp_to_tuple(c, v) for c in f) + def dup_normal(f, K): """ Normalize univariate polynomial in the given domain. @@ -481,10 +502,11 @@ """ return dup_strip([ K.normal(c) for c in f ]) + @cythonized("u,v") def dmp_normal(f, u, K): """ - Normalize multivariate polynomial in the given domain. + Normalize a multivariate polynomial in the given domain. Examples ======== @@ -499,13 +521,14 @@ if not u: return dup_normal(f, K) - v = u-1 + v = u - 1 return dmp_strip([ dmp_normal(c, v, K) for c in f ], u) + def dup_convert(f, K0, K1): """ - Convert ground domain of ``f`` from ``K0`` to ``K1``. + Convert the ground domain of ``f`` from ``K0`` to ``K1``. Examples ======== @@ -526,10 +549,11 @@ else: return dup_strip([ K1.convert(c, K0) for c in f ]) + @cythonized("u,v") def dmp_convert(f, u, K0, K1): """ - Convert ground domain of ``f`` from ``K0`` to ``K1``. + Convert the ground domain of ``f`` from ``K0`` to ``K1``. Examples ======== @@ -553,13 +577,14 @@ if K0 is not None and K0 == K1: return f - v = u-1 + v = u - 1 return dmp_strip([ dmp_convert(c, v, K0, K1) for c in f ], u) + def dup_from_sympy(f, K): """ - Convert ground domain of ``f`` from SymPy to ``K``. + Convert the ground domain of ``f`` from SymPy to ``K``. Examples ======== @@ -574,10 +599,11 @@ """ return dup_strip([ K.from_sympy(c) for c in f ]) + @cythonized("u,v") def dmp_from_sympy(f, u, K): """ - Convert ground domain of ``f`` from SymPy to ``K``. + Convert the ground domain of ``f`` from SymPy to ``K``. Examples ======== @@ -593,14 +619,15 @@ if not u: return dup_from_sympy(f, K) - v = u-1 + v = u - 1 return dmp_strip([ dmp_from_sympy(c, v, K) for c in f ], u) + @cythonized("n") def dup_nth(f, n, K): """ - Return ``n``-th coefficient of ``f`` in ``K[x]``. + Return the ``n``-th coefficient of ``f`` in ``K[x]``. Examples ======== @@ -621,12 +648,13 @@ elif n >= len(f): return K.zero else: - return f[dup_degree(f)-n] + return f[dup_degree(f) - n] + @cythonized("n,u") def dmp_nth(f, n, u, K): """ - Return ``n``-th coefficient of ``f`` in ``K[x]``. + Return the ``n``-th coefficient of ``f`` in ``K[x]``. Examples ======== @@ -645,14 +673,15 @@ if n < 0: raise IndexError("'n' must be non-negative, got %i" % n) elif n >= len(f): - return dmp_zero(u-1) + return dmp_zero(u - 1) else: - return f[dmp_degree(f, u)-n] + return f[dmp_degree(f, u) - n] + @cythonized("n,u,v") def dmp_ground_nth(f, N, u, K): """ - Return ground ``n``-th coefficient of ``f`` in ``K[x]``. + Return the ground ``n``-th coefficient of ``f`` in ``K[x]``. Examples ======== @@ -674,10 +703,11 @@ elif n >= len(f): return K.zero else: - f, v = f[dmp_degree(f, v)-n], v-1 + f, v = f[dmp_degree(f, v) - n], v - 1 return f + @cythonized("u") def dmp_zero_p(f, u): """ @@ -703,6 +733,7 @@ return not f + @cythonized("u") def dmp_zero(u): """ @@ -724,6 +755,7 @@ return r + @cythonized("u") def dmp_one_p(f, u, K): """ @@ -741,6 +773,7 @@ """ return dmp_ground_p(f, K.one, u) + @cythonized("u") def dmp_one(u, K): """ @@ -758,6 +791,7 @@ """ return dmp_ground(K.one, u) + @cythonized("u") def dmp_ground_p(f, c, u): """ @@ -788,6 +822,7 @@ else: return f == [c] + @cythonized("i,u") def dmp_ground(c, u): """ @@ -807,11 +842,12 @@ if not c: return dmp_zero(u) - for i in range(u+1): + for i in range(u + 1): c = [c] return c + @cythonized("n,u") def dmp_zeros(n, u, K): """ @@ -837,6 +873,7 @@ else: return [ dmp_zero(u) for i in range(n) ] + @cythonized("n,u") def dmp_grounds(c, n, u): """ @@ -862,6 +899,7 @@ else: return [ dmp_ground(c, u) for i in range(n) ] + @cythonized("u") def dmp_negative_p(f, u, K): """ @@ -881,6 +919,7 @@ """ return K.is_negative(dmp_ground_LC(f, u, K)) + @cythonized("u") def dmp_positive_p(f, u, K): """ @@ -900,10 +939,11 @@ """ return K.is_positive(dmp_ground_LC(f, u, K)) + @cythonized("n,k") def dup_from_dict(f, K): """ - Create ``K[x]`` polynomial from a ``dict``. + Create a ``K[x]`` polynomial from a ``dict``. Examples ======== @@ -933,10 +973,11 @@ return dup_strip(h) + @cythonized("n,k") def dup_from_raw_dict(f, K): """ - Create ``K[x]`` polynomial from a raw ``dict``. + Create a ``K[x]`` polynomial from a raw ``dict``. Examples ======== @@ -958,10 +999,11 @@ return dup_strip(h) + @cythonized("u,v,n,k") def dmp_from_dict(f, u, K): """ - Create ``K[X]`` polynomial from a ``dict``. + Create a ``K[X]`` polynomial from a ``dict``. Examples ======== @@ -988,9 +1030,9 @@ if head in coeffs: coeffs[head][tail] = coeff else: - coeffs[head] = { tail : coeff } + coeffs[head] = { tail: coeff } - n, v, h = max(coeffs.keys()), u-1, [] + n, v, h = max(coeffs.keys()), u - 1, [] for k in range(n, -1, -1): coeff = coeffs.get(k) @@ -1002,6 +1044,7 @@ return dmp_strip(h, u) + @cythonized("n,k") def dup_to_dict(f, K=None, zero=False): """ @@ -1023,16 +1066,17 @@ n, result = dup_degree(f), {} - for k in range(0, n+1): - if f[n-k]: - result[(k,)] = f[n-k] + for k in range(0, n + 1): + if f[n - k]: + result[(k,)] = f[n - k] return result + @cythonized("n,k") def dup_to_raw_dict(f, K=None, zero=False): """ - Convert ``K[x]`` polynomial to a raw ``dict``. + Convert a ``K[x]`` polynomial to a raw ``dict``. Examples ======== @@ -1048,16 +1092,17 @@ n, result = dup_degree(f), {} - for k in range(0, n+1): - if f[n-k]: - result[k] = f[n-k] + for k in range(0, n + 1): + if f[n - k]: + result[k] = f[n - k] return result + @cythonized("u,v,n,k") def dmp_to_dict(f, u, K=None, zero=False): """ - Convert ``K[X]`` polynomial to a ``dict````. + Convert a ``K[X]`` polynomial to a ``dict````. Examples ======== @@ -1076,16 +1121,17 @@ if dmp_zero_p(f, u) and zero: return {(0,)*(u + 1): K.zero} - n, v, result = dmp_degree(f, u), u-1, {} + n, v, result = dmp_degree(f, u), u - 1, {} - for k in range(0, n+1): - h = dmp_to_dict(f[n-k], v) + for k in range(0, n + 1): + h = dmp_to_dict(f[n - k], v) for exp, coeff in h.items(): - result[(k,)+exp] = coeff + result[(k,) + exp] = coeff return result + @cythonized("u,i,j") def dmp_swap(f, i, j, u, K): """ @@ -1115,12 +1161,13 @@ F, H = dmp_to_dict(f, u), {} for exp, coeff in F.items(): - H[exp[:i] + (exp[j],) + - exp[i+1:j] + - (exp[i],) + exp[j+1:]] = coeff + H[exp[:i] + (exp[j],) + + exp[i + 1:j] + + (exp[i],) + exp[j + 1:]] = coeff return dmp_from_dict(H, u, K) + @cythonized("u") def dmp_permute(f, P, u, K): """ @@ -1152,10 +1199,11 @@ return dmp_from_dict(H, u, K) + @cythonized("i,l") def dmp_nest(f, l, K): """ - Return multivariate value nested ``l``-levels. + Return a multivariate value nested ``l``-levels. Examples ======== @@ -1175,10 +1223,11 @@ return f + @cythonized("l,k,u,v") def dmp_raise(f, l, u, K): """ - Return multivariate polynomial raised ``l``-levels. + Return a multivariate polynomial raised ``l``-levels. Examples ======== @@ -1199,14 +1248,15 @@ if not f: return dmp_zero(l) - k = l-1 + k = l - 1 return [ dmp_ground(c, k) for c in f ] - v = u-1 + v = u - 1 return [ dmp_raise(c, l, v, K) for c in f ] + @cythonized("g,i") def dup_deflate(f, K): """ @@ -1230,7 +1280,7 @@ g = 0 for i in range(len(f)): - if not f[-i-1]: + if not f[-i - 1]: continue g = igcd(g, i) @@ -1240,6 +1290,7 @@ return g, f[::g] + @cythonized("u,i,m,a,b") def dmp_deflate(f, u, K): """ @@ -1258,10 +1309,10 @@ """ if dmp_zero_p(f, u): - return (1,)*(u+1), f + return (1,)*(u + 1), f F = dmp_to_dict(f, u) - B = [0]*(u+1) + B = [0]*(u + 1) for M in F.keys(): for i, m in enumerate(M): @@ -1284,6 +1335,7 @@ return B, dmp_from_dict(H, u, K) + @cythonized("G,g,i") def dup_multi_deflate(polys, K): """ @@ -1311,7 +1363,7 @@ g = 0 for i in range(len(p)): - if not p[-i-1]: + if not p[-i - 1]: continue g = igcd(g, i) @@ -1323,6 +1375,7 @@ return G, tuple([ p[::G] for p in polys ]) + @cythonized("u,G,g,m,a,b") def dmp_multi_deflate(polys, u, K): """ @@ -1345,7 +1398,7 @@ M, H = dup_multi_deflate(polys, K) return (M,), H - F, B = [], [0]*(u+1) + F, B = [], [0]*(u + 1) for p in polys: f = dmp_to_dict(p, u) @@ -1379,6 +1432,7 @@ return B, tuple(H) + @cythonized("m") def dup_inflate(f, m, K): """ @@ -1404,11 +1458,12 @@ result = [f[0]] for coeff in f[1:]: - result.extend([K.zero]*(m-1)) + result.extend([K.zero]*(m - 1)) result.append(coeff) return result + @cythonized("u,v,i,j") def _rec_inflate(g, M, v, i, K): """Recursive helper for :func:`dmp_inflate`.""" @@ -1417,7 +1472,7 @@ if M[i] <= 0: raise IndexError("all M[i] must be positive, got %s" % M[i]) - w, j = v-1, i+1 + w, j = v - 1, i + 1 g = [ _rec_inflate(c, M, w, j, K) for c in g ] @@ -1431,6 +1486,7 @@ return result + @cythonized("u,m") def dmp_inflate(f, M, u, K): """ @@ -1456,6 +1512,7 @@ else: return _rec_inflate(f, M, u, 0, K) + @cythonized("u,j") def dmp_exclude(f, u, K): """ @@ -1480,7 +1537,7 @@ J, F = [], dmp_to_dict(f, u) - for j in range(0, u+1): + for j in range(0, u + 1): for monom in F.keys(): if monom[j]: break @@ -1504,6 +1561,7 @@ return J, dmp_from_dict(f, u, K), u + @cythonized("u,j") def dmp_include(f, J, u, K): """ @@ -1538,6 +1596,7 @@ return dmp_from_dict(f, u, K) + @cythonized("u,v,w") def dmp_inject(f, u, K, front=False): """ @@ -1574,6 +1633,7 @@ return dmp_from_dict(h, w, K.dom), w + @cythonized("u,v") def dmp_eject(f, u, K, front=False): """ @@ -1593,13 +1653,14 @@ """ f, h = dmp_to_dict(f, u), {} + n = len(K.gens) v = u - len(K.gens) + 1 for monom, c in f.items(): if front: - g_monom, f_monom = monom[:v], monom[v:] + g_monom, f_monom = monom[:n], monom[n:] else: - f_monom, g_monom = monom[:v], monom[v:] + g_monom, f_monom = monom[-n:], monom[:-n] if f_monom in h: h[f_monom][g_monom] = c @@ -1609,7 +1670,8 @@ for monom, c in h.items(): h[monom] = K(c) - return dmp_from_dict(h, v-1, K) + return dmp_from_dict(h, v - 1, K) + @cythonized("i") def dup_terms_gcd(f, K): @@ -1641,6 +1703,7 @@ return i, f[:-i] + @cythonized("u,g") def dmp_terms_gcd(f, u, K): """ @@ -1659,7 +1722,7 @@ """ if dmp_ground_TC(f, u, K) or dmp_zero_p(f, u): - return (0,)*(u+1), f + return (0,)*(u + 1), f F = dmp_to_dict(f, u) G = monomial_min(*list(F.keys())) @@ -1674,6 +1737,7 @@ return G, dmp_from_dict(f, u, K) + @cythonized("v,w,d,i") def _rec_list_terms(g, v, monom): """Recursive helper for :func:`dmp_list_terms`.""" @@ -1684,15 +1748,16 @@ if not c: continue - terms.append((monom + (d-i,), c)) + terms.append((monom + (d - i,), c)) else: - w = v-1 + w = v - 1 for i, c in enumerate(g): - terms.extend(_rec_list_terms(c, w, monom + (d-i,))) + terms.extend(_rec_list_terms(c, w, monom + (d - i,))) return terms + @cythonized("u") def dmp_list_terms(f, u, K, order=None): """ @@ -1712,15 +1777,19 @@ [((1, 1), 1), ((1, 0), 1), ((0, 1), 2), ((0, 0), 3)] """ + def sort(terms, O): + return sorted(terms, key=lambda term: O(term[0]), reverse=True) + terms = _rec_list_terms(f, u, ()) if not terms: - return [((0,)*(u+1), K.zero)] + return [((0,)*(u + 1), K.zero)] if order is None: return terms else: - return sdp_sort(terms, monomial_key(order)) + return sort(terms, monomial_key(order)) + @cythonized("n,m") def dup_apply_pairs(f, g, h, args, K): @@ -1743,9 +1812,9 @@ if n != m: if n > m: - g = [K.zero]*(n-m) + g + g = [K.zero]*(n - m) + g else: - f = [K.zero]*(m-n) + f + f = [K.zero]*(m - n) + f result = [] @@ -1754,6 +1823,7 @@ return dup_strip(result) + @cythonized("u,v,n,m") def dmp_apply_pairs(f, g, h, args, u, K): """ @@ -1774,13 +1844,13 @@ if not u: return dup_apply_pairs(f, g, h, args, K) - n, m, v = len(f), len(g), u-1 + n, m, v = len(f), len(g), u - 1 if n != m: if n > m: - g = dmp_zeros(n-m, v, K) + g + g = dmp_zeros(n - m, v, K) + g else: - f = dmp_zeros(m-n, v, K) + f + f = dmp_zeros(m - n, v, K) + f result = [] @@ -1789,13 +1859,20 @@ return dmp_strip(result, u) + @cythonized("m,n,k,M,N") def dup_slice(f, m, n, K): """Take a continuous subsequence of terms of ``f`` in ``K[x]``. """ k = len(f) - M = k - m - N = k - n + if k >= m: + M = k - m + else: + M = 0 + if k >= n: + N = k - n + else: + N = 0 f = f[N:M] @@ -1804,11 +1881,13 @@ else: return f + [K.zero]*m + @cythonized("m,n,u") def dmp_slice(f, m, n, u, K): """Take a continuous subsequence of terms of ``f`` in ``K[X]``. """ return dmp_slice_in(f, m, n, 0, u, K) + @cythonized("m,n,j,u,k") def dmp_slice_in(f, m, n, j, u, K): """Take a continuous subsequence of terms of ``f`` in ``x_j`` in ``K[X]``. """ @@ -1824,7 +1903,7 @@ k = monom[j] if k < m or k >= n: - monom = monom[:j] + (0,) + monom[j+1:] + monom = monom[:j] + (0,) + monom[j + 1:] if monom in g: g[monom] += coeff @@ -1833,6 +1912,7 @@ return dmp_from_dict(g, u, K) + def dup_random(n, a, b, K): """ Return a polynomial of degree ``n`` with coefficients in ``[a, b]``. @@ -1847,7 +1927,7 @@ [-2, -8, 9, -4] """ - f = [ K.convert(random.randint(a, b)) for _ in range(0, n+1) ] + f = [ K.convert(random.randint(a, b)) for _ in range(0, n + 1) ] while not f[0]: f[0] = K.convert(random.randint(a, b)) diff -Nru python3-sympy-0.7.2/sympy/polys/densetools.py python3-sympy-0.7.3/sympy/polys/densetools.py --- python3-sympy-0.7.2/sympy/polys/densetools.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/polys/densetools.py 2013-07-13 17:53:32.000000000 +0000 @@ -40,21 +40,22 @@ from math import ceil as _ceil, log as _log + @cythonized("m,n,i,j") def dup_integrate(f, m, K): """ - Computes indefinite integral of ``f`` in ``K[x]``. + Computes the indefinite integral of ``f`` in ``K[x]``. Examples ======== - >>> from sympy.polys.domains import QQ - >>> from sympy.polys.densetools import dup_integrate + >>> from sympy.polys import ring, QQ + >>> R, x = ring("x", QQ) - >>> dup_integrate([QQ(1), QQ(2), QQ(0)], 1, QQ) - [1/3, 1/1, 0/1, 0/1] - >>> dup_integrate([QQ(1), QQ(2), QQ(0)], 2, QQ) - [1/12, 1/3, 0/1, 0/1, 0/1] + >>> R.dup_integrate(x**2 + 2*x, 1) + 1/3*x**3 + x**2 + >>> R.dup_integrate(x**2 + 2*x, 2) + 1/12*x**4 + 1/3*x**3 """ if m <= 0 or not f: @@ -63,30 +64,31 @@ g = [K.zero]*m for i, c in enumerate(reversed(f)): - n = i+1 + n = i + 1 for j in range(1, m): - n *= i+j+1 + n *= i + j + 1 - g.insert(0, K.quo(c, K(n))) + g.insert(0, K.exquo(c, K(n))) return g + @cythonized("m,u,v,n,i,j") def dmp_integrate(f, m, u, K): """ - Computes indefinite integral of ``f`` in ``x_0`` in ``K[X]``. + Computes the indefinite integral of ``f`` in ``x_0`` in ``K[X]``. Examples ======== - >>> from sympy.polys.domains import QQ - >>> from sympy.polys.densetools import dmp_integrate + >>> from sympy.polys import ring, QQ + >>> R, x,y = ring("x,y", QQ) - >>> dmp_integrate([[QQ(1)], [QQ(2), QQ(0)]], 1, 1, QQ) - [[1/2], [2/1, 0/1], []] - >>> dmp_integrate([[QQ(1)], [QQ(2), QQ(0)]], 2, 1, QQ) - [[1/6], [1/1, 0/1], [], []] + >>> R.dmp_integrate(x + 2*y, 1) + 1/2*x**2 + 2*x*y + >>> R.dmp_integrate(x + 2*y, 2) + 1/6*x**3 + x**2*y """ if not u: @@ -95,50 +97,53 @@ if m <= 0 or dmp_zero_p(f, u): return f - g, v = dmp_zeros(m, u-1, K), u-1 + g, v = dmp_zeros(m, u - 1, K), u - 1 for i, c in enumerate(reversed(f)): - n = i+1 + n = i + 1 for j in range(1, m): - n *= i+j+1 + n *= i + j + 1 g.insert(0, dmp_quo_ground(c, K(n), v, K)) return g + @cythonized("m,v,w,i,j") def _rec_integrate_in(g, m, v, i, j, K): """Recursive helper for :func:`dmp_integrate_in`.""" if i == j: return dmp_integrate(g, m, v, K) - w, i = v-1, i+1 + w, i = v - 1, i + 1 return dmp_strip([ _rec_integrate_in(c, m, w, i, j, K) for c in g ], v) + @cythonized("m,j,u") def dmp_integrate_in(f, m, j, u, K): """ - Computes indefinite integral of ``f`` in ``x_j`` in ``K[X]``. + Computes the indefinite integral of ``f`` in ``x_j`` in ``K[X]``. Examples ======== - >>> from sympy.polys.domains import QQ - >>> from sympy.polys.densetools import dmp_integrate_in + >>> from sympy.polys import ring, QQ + >>> R, x,y = ring("x,y", QQ) - >>> dmp_integrate_in([[QQ(1)], [QQ(2), QQ(0)]], 1, 0, 1, QQ) - [[1/2], [2/1, 0/1], []] - >>> dmp_integrate_in([[QQ(1)], [QQ(2), QQ(0)]], 1, 1, 1, QQ) - [[1/1, 0/1], [1/1, 0/1, 0/1]] + >>> R.dmp_integrate_in(x + 2*y, 1, 0) + 1/2*x**2 + 2*x*y + >>> R.dmp_integrate_in(x + 2*y, 1, 1) + x*y + y**2 """ if j < 0 or j > u: - raise IndexError("-%s <= j < %s expected, got %s" % (u, u, j)) + raise IndexError("0 <= j <= u expected, got %s" % (u, j)) return _rec_integrate_in(f, m, u, 0, j, K) + @cythonized("m,n,k,i") def dup_diff(f, m, K): """ @@ -147,13 +152,13 @@ Examples ======== - >>> from sympy.polys.domains import ZZ - >>> from sympy.polys.densetools import dup_diff + >>> from sympy.polys import ring, ZZ + >>> R, x = ring("x", ZZ) - >>> dup_diff([ZZ(1), ZZ(2), ZZ(3), ZZ(4)], 1, ZZ) - [3, 4, 3] - >>> dup_diff([ZZ(1), ZZ(2), ZZ(3), ZZ(4)], 2, ZZ) - [6, 4] + >>> R.dup_diff(x**3 + 2*x**2 + 3*x + 4, 1) + 3*x**2 + 4*x + 3 + >>> R.dup_diff(x**3 + 2*x**2 + 3*x + 4, 2) + 6*x + 4 """ if m <= 0: @@ -174,7 +179,7 @@ for coeff in f[:-m]: k = n - for i in range(n-1, n-m, -1): + for i in range(n - 1, n - m, -1): k *= i deriv.append(K(k)*coeff) @@ -182,6 +187,7 @@ return dup_strip(deriv) + @cythonized("u,v,m,n,k,i") def dmp_diff(f, m, u, K): """ @@ -190,15 +196,15 @@ Examples ======== - >>> from sympy.polys.domains import ZZ - >>> from sympy.polys.densetools import dmp_diff + >>> from sympy.polys import ring, ZZ + >>> R, x,y = ring("x,y", ZZ) - >>> f = ZZ.map([[1, 2, 3], [2, 3, 1]]) + >>> f = x*y**2 + 2*x*y + 3*x + 2*y**2 + 3*y + 1 - >>> dmp_diff(f, 1, 1, ZZ) - [[1, 2, 3]] - >>> dmp_diff(f, 2, 1, ZZ) - [[]] + >>> R.dmp_diff(f, 1) + y**2 + 2*y + 3 + >>> R.dmp_diff(f, 2) + 0 """ if not u: @@ -211,7 +217,7 @@ if n < m: return dmp_zero(u) - deriv, v = [], u-1 + deriv, v = [], u - 1 if m == 1: for coeff in f[:-m]: @@ -221,7 +227,7 @@ for coeff in f[:-m]: k = n - for i in range(n-1, n-m, -1): + for i in range(n - 1, n - m, -1): k *= i deriv.append(dmp_mul_ground(coeff, K(k), v, K)) @@ -229,16 +235,18 @@ return dmp_strip(deriv, u) + @cythonized("m,v,w,i,j") def _rec_diff_in(g, m, v, i, j, K): """Recursive helper for :func:`dmp_diff_in`.""" if i == j: return dmp_diff(g, m, v, K) - w, i = v-1, i+1 + w, i = v - 1, i + 1 return dmp_strip([ _rec_diff_in(c, m, w, i, j, K) for c in g ], v) + @cythonized("m,j,u") def dmp_diff_in(f, m, j, u, K): """ @@ -247,22 +255,23 @@ Examples ======== - >>> from sympy.polys.domains import ZZ - >>> from sympy.polys.densetools import dmp_diff_in + >>> from sympy.polys import ring, ZZ + >>> R, x,y = ring("x,y", ZZ) - >>> f = ZZ.map([[1, 2, 3], [2, 3, 1]]) + >>> f = x*y**2 + 2*x*y + 3*x + 2*y**2 + 3*y + 1 - >>> dmp_diff_in(f, 1, 0, 1, ZZ) - [[1, 2, 3]] - >>> dmp_diff_in(f, 1, 1, 1, ZZ) - [[2, 2], [4, 3]] + >>> R.dmp_diff_in(f, 1, 0) + y**2 + 2*y + 3 + >>> R.dmp_diff_in(f, 1, 1) + 2*x*y + 2*x + 4*y + 3 """ if j < 0 or j > u: - raise IndexError("-%s <= j < %s expected, got %s" % (u, u, j)) + raise IndexError("0 <= j <= %s expected, got %s" % (u, j)) return _rec_diff_in(f, m, u, 0, j, K) + def dup_eval(f, a, K): """ Evaluate a polynomial at ``x = a`` in ``K[x]`` using Horner scheme. @@ -270,10 +279,10 @@ Examples ======== - >>> from sympy.polys.domains import ZZ - >>> from sympy.polys.densetools import dup_eval + >>> from sympy.polys import ring, ZZ + >>> R, x = ring("x", ZZ) - >>> dup_eval([ZZ(1), ZZ(2), ZZ(3)], 2, ZZ) + >>> R.dup_eval(x**2 + 2*x + 3, 2) 11 """ @@ -288,6 +297,7 @@ return result + @cythonized("u,v") def dmp_eval(f, a, u, K): """ @@ -296,13 +306,11 @@ Examples ======== - >>> from sympy.polys.domains import ZZ - >>> from sympy.polys.densetools import dmp_eval - - >>> f = ZZ.map([[2, 3], [1, 2]]) + >>> from sympy.polys import ring, ZZ + >>> R, x,y = ring("x,y", ZZ) - >>> dmp_eval(f, 2, 1, ZZ) - [5, 8] + >>> R.dmp_eval(2*x*y + 3*x + y + 2, 2) + 5*y + 8 """ if not u: @@ -311,7 +319,7 @@ if not a: return dmp_TC(f, K) - result, v = dmp_LC(f, K), u-1 + result, v = dmp_LC(f, K), u - 1 for coeff in f[1:]: result = dmp_mul_ground(result, a, v, K) @@ -319,16 +327,18 @@ return result + @cythonized("v,i,j") def _rec_eval_in(g, a, v, i, j, K): """Recursive helper for :func:`dmp_eval_in`.""" if i == j: return dmp_eval(g, a, v, K) - v, i = v-1, i+1 + v, i = v - 1, i + 1 return dmp_strip([ _rec_eval_in(c, a, v, i, j, K) for c in g ], v) + @cythonized("u") def dmp_eval_in(f, a, j, u, K): """ @@ -337,34 +347,36 @@ Examples ======== - >>> from sympy.polys.domains import ZZ - >>> from sympy.polys.densetools import dmp_eval_in + >>> from sympy.polys import ring, ZZ + >>> R, x,y = ring("x,y", ZZ) - >>> f = ZZ.map([[2, 3], [1, 2]]) + >>> f = 2*x*y + 3*x + y + 2 - >>> dmp_eval_in(f, 2, 0, 1, ZZ) - [5, 8] - >>> dmp_eval_in(f, 2, 1, 1, ZZ) - [7, 4] + >>> R.dmp_eval_in(f, 2, 0) + 5*y + 8 + >>> R.dmp_eval_in(f, 2, 1) + 7*x + 4 """ if j < 0 or j > u: - raise IndexError("-%s <= j < %s expected, got %s" % (u, u, j)) + raise IndexError("0 <= j <= %s expected, got %s" % (u, j)) return _rec_eval_in(f, a, u, 0, j, K) + @cythonized("i,u") def _rec_eval_tail(g, i, A, u, K): """Recursive helper for :func:`dmp_eval_tail`.""" if i == u: return dup_eval(g, A[-1], K) else: - h = [ _rec_eval_tail(c, i+1, A, u, K) for c in g ] + h = [ _rec_eval_tail(c, i + 1, A, u, K) for c in g ] if i < u - len(A) + 1: return h else: - return dup_eval(h, A[-u+i-1], K) + return dup_eval(h, A[-u + i - 1], K) + @cythonized("u") def dmp_eval_tail(f, A, u, K): @@ -374,15 +386,15 @@ Examples ======== - >>> from sympy.polys.domains import ZZ - >>> from sympy.polys.densetools import dmp_eval_tail + >>> from sympy.polys import ring, ZZ + >>> R, x,y = ring("x,y", ZZ) - >>> f = ZZ.map([[2, 3], [1, 2]]) + >>> f = 2*x*y + 3*x + y + 2 - >>> dmp_eval_tail(f, (2, 2), 1, ZZ) + >>> R.dmp_eval_tail(f, [2]) + 7*x + 4 + >>> R.dmp_eval_tail(f, [2, 2]) 18 - >>> dmp_eval_tail(f, (2,), 1, ZZ) - [7, 4] """ if not A: @@ -393,21 +405,23 @@ e = _rec_eval_tail(f, 0, A, u, K) - if u == len(A)-1: + if u == len(A) - 1: return e else: return dmp_strip(e, u - len(A)) + @cythonized("m,v,i,j") def _rec_diff_eval(g, m, a, v, i, j, K): """Recursive helper for :func:`dmp_diff_eval`.""" if i == j: return dmp_eval(dmp_diff(g, m, v, K), a, v, K) - v, i = v-1, i+1 + v, i = v - 1, i + 1 return dmp_strip([ _rec_diff_eval(c, m, a, v, i, j, K) for c in g ], v) + @cythonized("m,j,u") def dmp_diff_eval_in(f, m, a, j, u, K): """ @@ -416,15 +430,15 @@ Examples ======== - >>> from sympy.polys.domains import ZZ - >>> from sympy.polys.densetools import dmp_diff_eval_in + >>> from sympy.polys import ring, ZZ + >>> R, x,y = ring("x,y", ZZ) - >>> f = ZZ.map([[1, 2, 3], [2, 3, 1]]) + >>> f = x*y**2 + 2*x*y + 3*x + 2*y**2 + 3*y + 1 - >>> dmp_diff_eval_in(f, 1, 2, 0, 1, ZZ) - [1, 2, 3] - >>> dmp_diff_eval_in(f, 1, 2, 1, 1, ZZ) - [6, 11] + >>> R.dmp_diff_eval_in(f, 1, 2, 0) + y**2 + 2*y + 3 + >>> R.dmp_diff_eval_in(f, 1, 2, 1) + 6*x + 11 """ if j > u: @@ -434,20 +448,19 @@ return _rec_diff_eval(f, m, a, u, 0, j, K) + def dup_trunc(f, p, K): """ - Reduce ``K[x]`` polynomial modulo a constant ``p`` in ``K``. + Reduce a ``K[x]`` polynomial modulo a constant ``p`` in ``K``. Examples ======== - >>> from sympy.polys.domains import ZZ - >>> from sympy.polys.densetools import dup_trunc - - >>> f = ZZ.map([2, 3, 5, 7]) + >>> from sympy.polys import ring, ZZ + >>> R, x = ring("x", ZZ) - >>> dup_trunc(f, ZZ(3), ZZ) - [-1, 0, -1, 1] + >>> R.dup_trunc(2*x**3 + 3*x**2 + 5*x + 7, ZZ(3)) + -x**3 - x + 1 """ if K.is_ZZ: @@ -465,65 +478,69 @@ return dup_strip(g) + @cythonized("u") def dmp_trunc(f, p, u, K): """ - Reduce ``K[X]`` polynomial modulo a polynomial ``p`` in ``K[Y]``. + Reduce a ``K[X]`` polynomial modulo a polynomial ``p`` in ``K[Y]``. Examples ======== - >>> from sympy.polys.domains import ZZ - >>> from sympy.polys.densetools import dmp_trunc + >>> from sympy.polys import ring, ZZ + >>> R, x,y = ring("x,y", ZZ) - >>> f = ZZ.map([[3, 8], [5, 6], [2, 3]]) - >>> g = ZZ.map([1, -1]) + >>> f = 3*x**2*y + 8*x**2 + 5*x*y + 6*x + 2*y + 3 + >>> g = (y - 1).drop(x) - >>> dmp_trunc(f, g, 1, ZZ) - [[11], [11], [5]] + >>> R.dmp_trunc(f, g) + 11*x**2 + 11*x + 5 """ - return dmp_strip([ dmp_rem(c, p, u-1, K) for c in f ], u) + return dmp_strip([ dmp_rem(c, p, u - 1, K) for c in f ], u) + @cythonized("u,v") def dmp_ground_trunc(f, p, u, K): """ - Reduce ``K[X]`` polynomial modulo a constant ``p`` in ``K``. + Reduce a ``K[X]`` polynomial modulo a constant ``p`` in ``K``. Examples ======== - >>> from sympy.polys.domains import ZZ - >>> from sympy.polys.densetools import dmp_ground_trunc + >>> from sympy.polys import ring, ZZ + >>> R, x,y = ring("x,y", ZZ) - >>> f = ZZ.map([[3, 8], [5, 6], [2, 3]]) + >>> f = 3*x**2*y + 8*x**2 + 5*x*y + 6*x + 2*y + 3 - >>> dmp_ground_trunc(f, ZZ(3), 1, ZZ) - [[-1], [-1, 0], [-1, 0]] + >>> R.dmp_ground_trunc(f, ZZ(3)) + -x**2 - x*y - y """ if not u: return dup_trunc(f, p, K) - v = u-1 + v = u - 1 return dmp_strip([ dmp_ground_trunc(c, p, v, K) for c in f ], u) + def dup_monic(f, K): """ - Divides all coefficients by ``LC(f)`` in ``K[x]``. + Divide all coefficients by ``LC(f)`` in ``K[x]``. Examples ======== - >>> from sympy.polys.domains import ZZ, QQ - >>> from sympy.polys.densetools import dup_monic + >>> from sympy.polys import ring, ZZ, QQ - >>> dup_monic([ZZ(3), ZZ(6), ZZ(9)], ZZ) - [1, 2, 3] + >>> R, x = ring("x", ZZ) + >>> R.dup_monic(3*x**2 + 6*x + 9) + x**2 + 2*x + 3 - >>> dup_monic([QQ(3), QQ(4), QQ(2)], QQ) - [1/1, 4/3, 2/3] + >>> R, x = ring("x", QQ) + >>> R.dup_monic(3*x**2 + 4*x + 2) + x**2 + 4/3*x + 2/3 """ if not f: @@ -536,25 +553,28 @@ else: return dup_exquo_ground(f, lc, K) + @cythonized("u") def dmp_ground_monic(f, u, K): """ - Divides all coefficients by ``LC(f)`` in ``K[X]``. + Divide all coefficients by ``LC(f)`` in ``K[X]``. Examples ======== - >>> from sympy.polys.domains import ZZ, QQ - >>> from sympy.polys.densetools import dmp_ground_monic + >>> from sympy.polys import ring, ZZ, QQ - >>> f = ZZ.map([[3, 6], [3, 0], [9, 3]]) - >>> g = QQ.map([[3, 8], [5, 6], [2, 3]]) + >>> R, x,y = ring("x,y", ZZ) + >>> f = 3*x**2*y + 6*x**2 + 3*x*y + 9*y + 3 - >>> dmp_ground_monic(f, 1, ZZ) - [[1, 2], [1, 0], [3, 1]] + >>> R.dmp_ground_monic(f) + x**2*y + 2*x**2 + x*y + 3*y + 1 - >>> dmp_ground_monic(g, 1, QQ) - [[1/1, 8/3], [5/3, 2/1], [2/3, 1/1]] + >>> R, x,y = ring("x,y", QQ) + >>> f = 3*x**2*y + 8*x**2 + 5*x*y + 6*x + 2*y + 3 + + >>> R.dmp_ground_monic(f) + x**2*y + 8/3*x**2 + 5/3*x*y + 2*x + 2/3*y + 1 """ if not u: @@ -570,6 +590,7 @@ else: return dmp_exquo_ground(f, lc, u, K) + def dup_content(f, K): """ Compute the GCD of coefficients of ``f`` in ``K[x]``. @@ -577,16 +598,19 @@ Examples ======== - >>> from sympy.polys.domains import ZZ, QQ - >>> from sympy.polys.densetools import dup_content + >>> from sympy.polys import ring, ZZ, QQ - >>> f = ZZ.map([6, 8, 12]) - >>> g = QQ.map([6, 8, 12]) + >>> R, x = ring("x", ZZ) + >>> f = 6*x**2 + 8*x + 12 - >>> dup_content(f, ZZ) + >>> R.dup_content(f) + 2 + + >>> R, x = ring("x", QQ) + >>> f = 6*x**2 + 8*x + 12 + + >>> R.dup_content(f) 2 - >>> dup_content(g, QQ) - 2/1 """ from sympy.polys.domains import QQ @@ -608,6 +632,7 @@ return cont + @cythonized("u,v") def dmp_ground_content(f, u, K): """ @@ -616,16 +641,19 @@ Examples ======== - >>> from sympy.polys.domains import ZZ, QQ - >>> from sympy.polys.densetools import dmp_ground_content + >>> from sympy.polys import ring, ZZ, QQ - >>> f = ZZ.map([[2, 6], [4, 12]]) - >>> g = QQ.map([[2, 6], [4, 12]]) + >>> R, x,y = ring("x,y", ZZ) + >>> f = 2*x*y + 6*x + 4*y + 12 - >>> dmp_ground_content(f, 1, ZZ) + >>> R.dmp_ground_content(f) + 2 + + >>> R, x,y = ring("x,y", QQ) + >>> f = 2*x*y + 6*x + 4*y + 12 + + >>> R.dmp_ground_content(f) 2 - >>> dmp_ground_content(g, 1, QQ) - 2/1 """ from sympy.polys.domains import QQ @@ -650,6 +678,7 @@ return cont + def dup_primitive(f, K): """ Compute content and the primitive form of ``f`` in ``K[x]``. @@ -657,16 +686,19 @@ Examples ======== - >>> from sympy.polys.domains import ZZ, QQ - >>> from sympy.polys.densetools import dup_primitive + >>> from sympy.polys import ring, ZZ, QQ + + >>> R, x = ring("x", ZZ) + >>> f = 6*x**2 + 8*x + 12 - >>> f = ZZ.map([6, 8, 12]) - >>> g = QQ.map([6, 8, 12]) + >>> R.dup_primitive(f) + (2, 3*x**2 + 4*x + 6) - >>> dup_primitive(f, ZZ) - (2, [3, 4, 6]) - >>> dup_primitive(g, QQ) - (2/1, [3/1, 4/1, 6/1]) + >>> R, x = ring("x", QQ) + >>> f = 6*x**2 + 8*x + 12 + + >>> R.dup_primitive(f) + (2, 3*x**2 + 4*x + 6) """ if not f: @@ -679,6 +711,7 @@ else: return cont, dup_quo_ground(f, cont, K) + @cythonized("u") def dmp_ground_primitive(f, u, K): """ @@ -687,16 +720,19 @@ Examples ======== - >>> from sympy.polys.domains import ZZ, QQ - >>> from sympy.polys.densetools import dmp_ground_primitive + >>> from sympy.polys import ring, ZZ, QQ + + >>> R, x,y = ring("x,y", ZZ) + >>> f = 2*x*y + 6*x + 4*y + 12 - >>> f = ZZ.map([[2, 6], [4, 12]]) - >>> g = QQ.map([[2, 6], [4, 12]]) + >>> R.dmp_ground_primitive(f) + (2, x*y + 3*x + 2*y + 6) - >>> dmp_ground_primitive(f, 1, ZZ) - (2, [[1, 3], [2, 6]]) - >>> dmp_ground_primitive(g, 1, QQ) - (2/1, [[1/1, 3/1], [2/1, 6/1]]) + >>> R, x,y = ring("x,y", QQ) + >>> f = 2*x*y + 6*x + 4*y + 12 + + >>> R.dmp_ground_primitive(f) + (2, x*y + 3*x + 2*y + 6) """ if not u: @@ -712,6 +748,7 @@ else: return cont, dmp_quo_ground(f, cont, u, K) + def dup_extract(f, g, K): """ Extract common content from a pair of polynomials in ``K[x]``. @@ -719,14 +756,11 @@ Examples ======== - >>> from sympy.polys.domains import ZZ - >>> from sympy.polys.densetools import dup_extract + >>> from sympy.polys import ring, ZZ + >>> R, x = ring("x", ZZ) - >>> f = ZZ.map([6, 12, 18]) - >>> g = ZZ.map([4, 8, 12]) - - >>> dup_extract(f, g, ZZ) - (2, [3, 6, 9], [2, 4, 6]) + >>> R.dup_extract(6*x**2 + 12*x + 18, 4*x**2 + 8*x + 12) + (2, 3*x**2 + 6*x + 9, 2*x**2 + 4*x + 6) """ fc = dup_content(f, K) @@ -740,6 +774,7 @@ return gcd, f, g + @cythonized("u") def dmp_ground_extract(f, g, u, K): """ @@ -748,14 +783,11 @@ Examples ======== - >>> from sympy.polys.domains import ZZ - >>> from sympy.polys.densetools import dmp_ground_extract + >>> from sympy.polys import ring, ZZ + >>> R, x,y = ring("x,y", ZZ) - >>> f = ZZ.map([[6, 12], [18]]) - >>> g = ZZ.map([[4, 8], [12]]) - - >>> dmp_ground_extract(f, g, 1, ZZ) - (2, [[3, 6], [9]], [[2, 4], [6]]) + >>> R.dmp_ground_extract(6*x*y + 12*x + 18, 4*x*y + 8*x + 12) + (2, 3*x*y + 6*x + 9, 2*x*y + 4*x + 6) """ fc = dmp_ground_content(f, u, K) @@ -769,6 +801,7 @@ return gcd, f, g + def dup_real_imag(f, K): """ Return bivariate polynomials ``f1`` and ``f2``, such that ``f = f1 + f2*I``. @@ -776,11 +809,11 @@ Examples ======== - >>> from sympy.polys.domains import ZZ - >>> from sympy.polys.densetools import dup_real_imag + >>> from sympy.polys import ring, ZZ + >>> R, x,y = ring("x,y", ZZ) - >>> dup_real_imag([ZZ(1), ZZ(1), ZZ(1), ZZ(1)], ZZ) - ([[1], [1], [-3, 0, 1], [-1, 0, 1]], [[3, 0], [2, 0], [-1, 0, 1, 0]]) + >>> R.dup_real_imag(x**3 + x**2 + x + 1) + (x**3 + x**2 - 3*x*y**2 + x - y**2 + 1, 3*x**2*y + 2*x*y - y**3 + y) """ if not K.is_ZZ and not K.is_QQ: @@ -815,6 +848,7 @@ return f1, f2 + @cythonized('i,n') def dup_mirror(f, K): """ @@ -823,20 +857,21 @@ Examples ======== - >>> from sympy.polys.domains import ZZ - >>> from sympy.polys.densetools import dup_mirror + >>> from sympy.polys import ring, ZZ + >>> R, x = ring("x", ZZ) - >>> dup_mirror([ZZ(1), ZZ(2), -ZZ(4), ZZ(2)], ZZ) - [-1, 2, 4, 2] + >>> R.dup_mirror(x**3 + 2*x**2 - 4*x + 2) + -x**3 + 2*x**2 + 4*x + 2 """ f, n, a = list(f), dup_degree(f), -K.one - for i in range(n-1, -1, -1): + for i in range(n - 1, -1, -1): f[i], a = a*f[i], -a return f + @cythonized('i,n') def dup_scale(f, a, K): """ @@ -845,20 +880,21 @@ Examples ======== - >>> from sympy.polys.domains import ZZ - >>> from sympy.polys.densetools import dup_scale + >>> from sympy.polys import ring, ZZ + >>> R, x = ring("x", ZZ) - >>> dup_scale([ZZ(1), -ZZ(2), ZZ(1)], ZZ(2), ZZ) - [4, -4, 1] + >>> R.dup_scale(x**2 - 2*x + 1, ZZ(2)) + 4*x**2 - 4*x + 1 """ f, n, b = list(f), dup_degree(f), a - for i in range(n-1, -1, -1): + for i in range(n - 1, -1, -1): f[i], b = b*f[i], b*a return f + @cythonized('i,j,n') def dup_shift(f, a, K): """ @@ -867,21 +903,22 @@ Examples ======== - >>> from sympy.polys.domains import ZZ - >>> from sympy.polys.densetools import dup_shift + >>> from sympy.polys import ring, ZZ + >>> R, x = ring("x", ZZ) - >>> dup_shift([ZZ(1), -ZZ(2), ZZ(1)], ZZ(2), ZZ) - [1, 2, 1] + >>> R.dup_shift(x**2 - 2*x + 1, ZZ(2)) + x**2 + 2*x + 1 """ f, n = list(f), dup_degree(f) for i in range(n, 0, -1): for j in range(0, i): - f[j+1] += a*f[j] + f[j + 1] += a*f[j] return f + @cythonized('i,n') def dup_transform(f, p, q, K): """ @@ -890,15 +927,11 @@ Examples ======== - >>> from sympy.polys.domains import ZZ - >>> from sympy.polys.densetools import dup_transform - - >>> f = ZZ.map([1, -2, 1]) - >>> p = ZZ.map([1, 0, 1]) - >>> q = ZZ.map([1, -1]) + >>> from sympy.polys import ring, ZZ + >>> R, x = ring("x", ZZ) - >>> dup_transform(f, p, q, ZZ) - [1, -2, 5, -4, 4] + >>> R.dup_transform(x**2 - 2*x + 1, x**2 + 1, x - 1) + x**4 - 2*x**3 + 5*x**2 - 4*x + 4 """ if not f: @@ -917,6 +950,7 @@ return h + def dup_compose(f, g, K): """ Evaluate functional composition ``f(g)`` in ``K[x]``. @@ -924,14 +958,11 @@ Examples ======== - >>> from sympy.polys.domains import ZZ - >>> from sympy.polys.densetools import dup_compose - - >>> f = ZZ.map([1, 1, 0]) - >>> g = ZZ.map([1, -1]) + >>> from sympy.polys import ring, ZZ + >>> R, x = ring("x", ZZ) - >>> dup_compose(f, g, ZZ) - [1, -1, 0] + >>> R.dup_compose(x**2 + x, x - 1) + x**2 - x """ if len(g) <= 1: @@ -948,6 +979,7 @@ return h + @cythonized("u") def dmp_compose(f, g, u, K): """ @@ -956,14 +988,11 @@ Examples ======== - >>> from sympy.polys.domains import ZZ - >>> from sympy.polys.densetools import dmp_compose - - >>> f = ZZ.map([[1, 2], [1, 0]]) - >>> g = ZZ.map([[1, 0]]) + >>> from sympy.polys import ring, ZZ + >>> R, x,y = ring("x,y", ZZ) - >>> dmp_compose(f, g, 1, ZZ) - [[1, 3, 0]] + >>> R.dmp_compose(x*y + 2*x + y, y) + y**2 + 3*y """ if not u: @@ -980,6 +1009,7 @@ return h + @cythonized("s,n,r,i,j") def _dup_right_decompose(f, s, K): """Helper function for :func:`_dup_decompose`.""" @@ -987,7 +1017,7 @@ lc = dup_LC(f, K) f = dup_to_raw_dict(f) - g = { s : K.one } + g = { s: K.one } r = n // s @@ -995,19 +1025,20 @@ coeff = K.zero for j in range(0, i): - if not n+j-i in f: + if not n + j - i in f: continue - if not s-j in g: + if not s - j in g: continue - fc, gc = f[n+j-i], g[s-j] + fc, gc = f[n + j - i], g[s - j] coeff += (i - r*j)*fc*gc - g[s-i] = K.quo(coeff, i*r*lc) + g[s - i] = K.quo(coeff, i*r*lc) return dup_from_raw_dict(g, K) + @cythonized("i") def _dup_left_decompose(f, h, K): """Helper function for :func:`_dup_decompose`.""" @@ -1024,6 +1055,7 @@ return dup_from_raw_dict(g, K) + @cythonized("df,s") def _dup_decompose(f, K): """Helper function for :func:`dup_decompose`.""" @@ -1043,6 +1075,7 @@ return None + def dup_decompose(f, K): """ Computes functional decomposition of ``f`` in ``K[x]``. @@ -1067,13 +1100,11 @@ Examples ======== - >>> from sympy.polys.domains import ZZ - >>> from sympy.polys.densetools import dup_decompose - - >>> f = ZZ.map([1, -2, 1, 0, 0]) + >>> from sympy.polys import ring, ZZ + >>> R, x = ring("x", ZZ) - >>> dup_decompose(f, ZZ) - [[1, 0, 0], [1, -1, 0]] + >>> R.dup_decompose(x**4 - 2*x**3 + x**2) + [x**2, x**2 - x] References ========== @@ -1094,6 +1125,7 @@ return [f] + F + @cythonized("u") def dmp_lift(f, u, K): """ @@ -1102,19 +1134,21 @@ Examples ======== + >>> from sympy.polys import ring, QQ >>> from sympy import I - >>> from sympy.polys.domains import QQ - >>> from sympy.polys.densetools import dmp_lift >>> K = QQ.algebraic_field(I) - >>> f = [K(1), K([QQ(1), QQ(0)]), K([QQ(2), QQ(0)])] + >>> R, x = ring("x", K) + + >>> f = x**2 + K([QQ(1), QQ(0)])*x + K([QQ(2), QQ(0)]) - >>> dmp_lift(f, 0, K) - [1/1, 0/1, 2/1, 0/1, 9/1, 0/1, -8/1, 0/1, 16/1] + >>> R.dmp_lift(f) + x**8 + 2*x**6 + 9*x**4 - 8*x**2 + 16 """ if not K.is_Algebraic: - raise DomainError('computation can be done only in an algebraic domain') + raise DomainError( + 'computation can be done only in an algebraic domain') F, monoms, polys = dmp_to_dict(f, u), [], [] @@ -1135,6 +1169,7 @@ return dmp_convert(dmp_expand(polys, u, K), u, K, K.dom) + def dup_sign_variations(f, K): """ Compute the number of sign variations of ``f`` in ``K[x]``. @@ -1142,12 +1177,10 @@ Examples ======== - >>> from sympy.polys.domains import ZZ - >>> from sympy.polys.densetools import dup_sign_variations - - >>> f = ZZ.map([1, 0, -1, -1, 1]) + >>> from sympy.polys import ring, ZZ + >>> R, x = ring("x", ZZ) - >>> dup_sign_variations(f, ZZ) + >>> R.dup_sign_variations(x**4 - x**2 - x + 1) 2 """ @@ -1162,6 +1195,7 @@ return k + def dup_clear_denoms(f, K0, K1=None, convert=False): """ Clear denominators, i.e. transform ``K_0`` to ``K_1``. @@ -1169,20 +1203,22 @@ Examples ======== - >>> from sympy.polys.domains import QQ, ZZ - >>> from sympy.polys.densetools import dup_clear_denoms + >>> from sympy.polys import ring, QQ + >>> R, x = ring("x", QQ) + + >>> f = QQ(1,2)*x + QQ(1,3) - >>> f = [QQ(1,2), QQ(1,3)] - >>> dup_clear_denoms(f, QQ, convert=False) - (6, [3/1, 2/1]) - - >>> f = [QQ(1,2), QQ(1,3)] - >>> dup_clear_denoms(f, QQ, convert=True) - (6, [3, 2]) + >>> R.dup_clear_denoms(f, convert=False) + (6, 3*x + 2) + >>> R.dup_clear_denoms(f, convert=True) + (6, 3*x + 2) """ if K1 is None: - K1 = K0.get_ring() + if K0.has_assoc_Ring: + K1 = K0.get_ring() + else: + K1 = K0 common = K1.one @@ -1197,6 +1233,7 @@ else: return common, dup_convert(f, K0, K1) + @cythonized("v,w") def _rec_clear_denoms(g, v, K0, K1): """Recursive helper for :func:`dmp_clear_denoms`.""" @@ -1206,13 +1243,14 @@ for c in g: common = K1.lcm(common, K0.denom(c)) else: - w = v-1 + w = v - 1 for c in g: common = K1.lcm(common, _rec_clear_denoms(c, w, K0, K1)) return common + @cythonized("u") def dmp_clear_denoms(f, u, K0, K1=None, convert=False): """ @@ -1221,23 +1259,25 @@ Examples ======== - >>> from sympy.polys.domains import QQ, ZZ - >>> from sympy.polys.densetools import dmp_clear_denoms + >>> from sympy.polys import ring, QQ + >>> R, x,y = ring("x,y", QQ) - >>> f = [[QQ(1,2)], [QQ(1,3), QQ(1)]] - >>> dmp_clear_denoms(f, 1, QQ, convert=False) - (6, [[3/1], [2/1, 6/1]]) - - >>> f = [[QQ(1,2)], [QQ(1,3), QQ(1)]] - >>> dmp_clear_denoms(f, 1, QQ, convert=True) - (6, [[3], [2, 6]]) + >>> f = QQ(1,2)*x + QQ(1,3)*y + 1 + + >>> R.dmp_clear_denoms(f, convert=False) + (6, 3*x + 2*y + 6) + >>> R.dmp_clear_denoms(f, convert=True) + (6, 3*x + 2*y + 6) """ if not u: return dup_clear_denoms(f, K0, K1, convert=convert) if K1 is None: - K1 = K0.get_ring() + if K0.has_assoc_Ring: + K1 = K0.get_ring() + else: + K1 = K0 common = _rec_clear_denoms(f, u, K0, K1) @@ -1249,6 +1289,7 @@ else: return common, dmp_convert(f, u, K0, K1) + @cythonized('i,n') def dup_revert(f, n, K): """ @@ -1261,13 +1302,13 @@ Examples ======== - >>> from sympy.polys.domains import QQ - >>> from sympy.polys.densetools import dup_revert + >>> from sympy.polys import ring, QQ + >>> R, x = ring("x", QQ) - >>> f = [-QQ(1,720), QQ(0), QQ(1,24), QQ(0), -QQ(1,2), QQ(0), QQ(1)] + >>> f = -QQ(1,720)*x**6 + QQ(1,24)*x**4 - QQ(1,2)*x**2 + 1 - >>> dup_revert(f, 8, QQ) - [61/720, 0/1, 5/24, 0/1, 1/2, 0/1, 1/1] + >>> R.dup_revert(f, 8) + 61/720*x**6 + 5/24*x**4 + 1/2*x**2 + 1 """ g = [K.revert(dup_TC(f, K))] @@ -1283,6 +1324,7 @@ return g + def dmp_revert(f, g, u, K): """ Compute ``f**(-1)`` mod ``x**n`` using Newton iteration. @@ -1290,8 +1332,8 @@ Examples ======== - >>> from sympy.polys.domains import QQ - >>> from sympy.polys.densetools import dmp_revert + >>> from sympy.polys import ring, QQ + >>> R, x,y = ring("x,y", QQ) """ if not u: diff -Nru python3-sympy-0.7.2/sympy/polys/distributedmodules.py python3-sympy-0.7.3/sympy/polys/distributedmodules.py --- python3-sympy-0.7.2/sympy/polys/distributedmodules.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/polys/distributedmodules.py 2013-07-13 17:53:32.000000000 +0000 @@ -3,7 +3,7 @@ polynomial rings. This code and its data structures are very much like the distributed -polynomials ``sdp_...``, except that the first "exponent" of the monomial is +polynomials, except that the first "exponent" of the monomial is a module generator index. That is, the multi-exponent ``(i, e_1, ..., e_n)`` represents the "monomial" `x_1^{e_1} \dots x_n^{e_n} f_i` of the free module `F` generated by `f_1, \dots, f_r` over (a localization of) the ring @@ -32,10 +32,6 @@ monomial_mul, monomial_lcm, monomial_div, monomial_deg, monomial_divides ) -from sympy.polys.distributedpolys import ( - sdp_LC, sdp_from_dict, sdp_to_dict, sdp_add, sdp_strip -) - from sympy.polys.polytools import Poly from sympy.polys.polyutils import parallel_dict_from_expr from sympy import S, sympify @@ -43,6 +39,7 @@ # Additional monomial tools. + def sdm_monomial_mul(M, X): """ Multiply tuple ``X`` representing a monomial of `K[X]` into the tuple @@ -59,6 +56,7 @@ """ return (M[0],) + monomial_mul(X, M[1:]) + def sdm_monomial_deg(M): """ Return the total degree of ``M``. @@ -74,6 +72,7 @@ """ return monomial_deg(M[1:]) + def sdm_monomial_lcm(A, B): """ Return the "least common multiple" of ``A`` and ``B``. @@ -90,6 +89,7 @@ """ return (A[0],) + monomial_lcm(A[1:], B[1:]) + def sdm_monomial_divides(A, B): """ Does there exist a (polynomial) monomial X such that XA = B? @@ -144,9 +144,18 @@ # The actual distributed modules code. -# These can be re-used without change: -sdm_LC = sdp_LC -sdm_to_dict = sdp_to_dict +def sdm_LC(f, K): + """Returns the leading coeffcient of ``f``. """ + if not f: + return K.zero + else: + return f[0][1] + + +def sdm_to_dict(f): + """Make a dictionary from a distributed polynomial. """ + return dict(f) + def sdm_from_dict(d, O): """ @@ -158,9 +167,20 @@ >>> from sympy.polys import QQ, lex >>> dic = {(1, 1, 0): QQ(1), (1, 0, 0): QQ(2), (0, 1, 0): QQ(0)} >>> sdm_from_dict(dic, lex) - [((1, 1, 0), 1/1), ((1, 0, 0), 2/1)] + [((1, 1, 0), 1), ((1, 0, 0), 2)] """ - return sdp_strip(sdp_from_dict(d, O)) + return sdm_strip(sdm_sort(list(d.items()), O)) + + +def sdm_sort(f, O): + """Sort terms in ``f`` using the given monomial order ``O``. """ + return sorted(f, key=lambda term: O(term[0]), reverse=True) + + +def sdm_strip(f): + """Remove terms with zero coefficients from ``f`` in ``K[X]``. """ + return [ (monom, coeff) for monom, coeff in f if coeff ] + def sdm_add(f, g, O, K): """ @@ -179,7 +199,7 @@ >>> from sympy.polys.distributedmodules import sdm_add >>> from sympy.polys import lex, QQ >>> sdm_add([((1, 1, 1), QQ(1))], [((2, 0, 0), QQ(1))], lex, QQ) - [((2, 0, 0), 1/1), ((1, 1, 1), 1/1)] + [((2, 0, 0), 1), ((1, 1, 1), 1)] `(xy f_1) + (-xy f_1)` = 0` @@ -189,15 +209,28 @@ `(f_1) + (2f_1) = 3f_1` >>> sdm_add([((1, 0, 0), QQ(1))], [((1, 0, 0), QQ(2))], lex, QQ) - [((1, 0, 0), 3/1)] + [((1, 0, 0), 3)] `(yf_1) + (xf_1) = xf_1 + yf_1` >>> sdm_add([((1, 0, 1), QQ(1))], [((1, 1, 0), QQ(1))], lex, QQ) - [((1, 1, 0), 1/1), ((1, 0, 1), 1/1)] + [((1, 1, 0), 1), ((1, 0, 1), 1)] """ - # send 0 for u (3rd parameter) since it is not needed - return sdp_add(f, g, 0, O, K) + h = dict(f) + + for monom, c in g: + if monom in h: + coeff = h[monom] + c + + if not coeff: + del h[monom] + else: + h[monom] = coeff + else: + h[monom] = c + + return sdm_from_dict(h, O) + def sdm_LM(f): r""" @@ -216,6 +249,7 @@ """ return f[0][0] + def sdm_LT(f): r""" Returns the leading term of ``f``. @@ -229,10 +263,11 @@ >>> from sympy.polys import QQ, lex >>> dic = {(1, 2, 3): QQ(1), (4, 0, 0): QQ(2), (4, 0, 1): QQ(3)} >>> sdm_LT(sdm_from_dict(dic, lex)) - ((4, 0, 1), 3/1) + ((4, 0, 1), 3) """ return f[0] + def sdm_mul_term(f, term, O, K): """ Multiply a distributed module element ``f`` by a (polynomial) term ``term``. @@ -258,16 +293,14 @@ `(x) (f_1) = xf_1` >>> sdm_mul_term([((1, 0, 0), QQ(1))], ((1, 0), QQ(1)), lex, QQ) - [((1, 1, 0), 1/1)] + [((1, 1, 0), 1)] `(2xy) (3x f_1 + 4y f_2) = 8xy^2 f_2 + 6x^2y f_1` >>> f = [((2, 0, 1), QQ(4)), ((1, 1, 0), QQ(3))] >>> sdm_mul_term(f, ((1, 1), QQ(2)), lex, QQ) - [((2, 1, 2), 8/1), ((1, 2, 1), 6/1)] + [((2, 1, 2), 8), ((1, 2, 1), 6)] """ - # Note O is not used in this implementation - # This is an almost-verbatim copy of sdp_mul_term X, c = term if not f or not c: @@ -278,10 +311,12 @@ else: return [ (sdm_monomial_mul(f_M, X), f_c * c) for f_M, f_c in f ] + def sdm_zero(): """Return the zero module element.""" return [] + def sdm_deg(f): """ Degree of ``f``. @@ -316,7 +351,7 @@ >>> from sympy.abc import x, y, z >>> from sympy.polys import QQ, lex >>> sdm_from_vector([x**2+y**2, 2*z], lex, QQ) - [((1, 0, 0, 1), 2/1), ((0, 2, 0, 0), 1/1), ((0, 0, 2, 0), 1/1)] + [((1, 0, 0, 1), 2), ((0, 2, 0, 0), 1), ((0, 0, 2, 0), 1)] """ dics, gens = parallel_dict_from_expr(sympify(vec), **opts) dic = {} @@ -325,6 +360,7 @@ dic[(i,) + k] = K.convert(v) return sdm_from_dict(dic, O) + def sdm_to_vector(f, gens, K, n=None): """ Convert sdm ``f`` into a list of polynomial expressions. @@ -358,6 +394,7 @@ # Algorithms. + def sdm_spoly(f, g, O, K, phantom=None): """ Compute the generalized s-polynomial of ``f`` and ``g``. @@ -387,7 +424,7 @@ >>> sdm_spoly(f, h, lex, QQ) [] >>> sdm_spoly(f, g, lex, QQ) - [((1, 2, 1), 1/1)] + [((1, 2, 1), 1)] """ if not f or not g: return sdm_zero() @@ -409,6 +446,7 @@ sdm_mul_term(phantom[1], (m2, c), O, K), O, K) return r1, r2 + def sdm_ecart(f): """ Compute the ecart of ``f``. @@ -429,6 +467,7 @@ """ return sdm_deg(f) - sdm_monomial_deg(sdm_LM(f)) + def sdm_nf_mora(f, G, O, K, phantom=None): r""" Compute a weak normal form of ``f`` with respect to ``G`` and order ``O``. @@ -467,7 +506,7 @@ phantom = False while h: # TODO better data structure!!! - Th = [(g, sdm_ecart(g), gp) for g, gp in zip(T, Tp) \ + Th = [(g, sdm_ecart(g), gp) for g, gp in zip(T, Tp) if sdm_monomial_divides(sdm_LM(g), sdm_LM(h))] if not Th: break @@ -484,6 +523,7 @@ return h, hp return h + def sdm_nf_buchberger(f, G, O, K, phantom=None): r""" Compute a weak normal form of ``f`` with respect to ``G`` and order ``O``. @@ -523,6 +563,7 @@ return h, hp return h + def sdm_nf_buchberger_reduced(f, G, O, K): r""" Compute a reduced normal form of ``f`` with respect to ``G`` and order ``O``. @@ -548,6 +589,7 @@ g = g[1:] return h + def sdm_groebner(G, NF, O, K, extended=False): """ Compute a minimal standard basis of ``G`` with respect to order ``O``. @@ -595,7 +637,7 @@ LMj = sdm_LM(S[j]) return max(Sugars[i] - sdm_monomial_deg(LMi), Sugars[j] - sdm_monomial_deg(LMj)) \ - + sdm_monomial_deg(sdm_monomial_lcm(LMi, LMj)) + + sdm_monomial_deg(sdm_monomial_lcm(LMi, LMj)) ourkey = lambda p: (p[2], O(p[3]), p[1]) @@ -608,6 +650,7 @@ Sugars.append(sugar) LMf = sdm_LM(f) + def removethis(pair): i, j, s, t = pair if LMf[0] != t[0]: @@ -615,7 +658,7 @@ tik = sdm_monomial_lcm(LMf, sdm_LM(S[i])) tjk = sdm_monomial_lcm(LMf, sdm_LM(S[j])) return tik != t and tjk != t and sdm_monomial_divides(tik, t) and \ - sdm_monomial_divides(tjk, t) + sdm_monomial_divides(tjk, t) # apply the chain criterion P = [p for p in P if not removethis(p)] diff -Nru python3-sympy-0.7.2/sympy/polys/distributedpolys.py python3-sympy-0.7.3/sympy/polys/distributedpolys.py --- python3-sympy-0.7.2/sympy/polys/distributedpolys.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/polys/distributedpolys.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,532 +0,0 @@ -"""Sparse distributed multivariate polynomials. """ - -from sympy.polys.monomialtools import ( - monomial_mul, monomial_div, monomial_lcm, lex, -) - -from sympy.polys.polyerrors import ( - ExactQuotientFailed, -) - -def sdp_LC(f, K): - """Returns the leading coeffcient of `f`. """ - if not f: - return K.zero - else: - return f[0][1] - -def sdp_LM(f, u): - """Returns the leading monomial of `f`. """ - if not f: - return (0,) * (u + 1) - else: - return f[0][0] - -def sdp_LT(f, u, K): - """Returns the leading term of `f`. """ - if f: - return f[0] - else: - return (0,) * (u + 1), K.zero - -def sdp_del_LT(f): - """Removes the leading from `f`. """ - return f[1:] - -def sdp_coeffs(f): - """Returns a list of monomials in `f`. """ - return [ coeff for _, coeff in f ] - -def sdp_monoms(f): - """Returns a list of monomials in `f`. """ - return [ monom for monom, _ in f ] - -def sdp_sort(f, O): - """Sort terms in `f` using the given monomial order `O`. """ - return sorted(f, key=lambda term: O(term[0]), reverse=True) - -def sdp_strip(f): - """Remove terms with zero coefficients from `f` in `K[X]`. """ - return [ (monom, coeff) for monom, coeff in f if coeff ] - -def sdp_normal(f, K): - """Normalize distributed polynomial in the given domain. """ - return [ (monom, K.convert(coeff)) for monom, coeff in f if coeff ] - -def sdp_from_dict(f, O): - """Make a distributed polynomial from a dictionary. """ - return sdp_sort(list(f.items()), O) - -def sdp_to_dict(f): - """Make a dictionary from a distributed polynomial. """ - return dict(f) - -def sdp_indep_p(f, j, u): - """Returns `True` if a polynomial is independent of `x_j`. """ - if j < 0 or j > u: - raise IndexError("-%s <= j < %s expected, got %s" % (u, u, j)) - else: - return all(not monom[j] for monom in sdp_monoms(h)) - -def sdp_one_p(f, u, K): - """Returns True if `f` is a multivariate one in `K[X]`. """ - return f == sdp_one(u, K) - -def sdp_one(u, K): - """Returns a multivariate one in `K[X]`. """ - return (((0,) * (u + 1), K.one),) - -def sdp_term_p(f): - """Returns True if `f` has a single term or is zero. """ - return len(f) <= 1 - -def sdp_abs(f, u, O, K): - """Make all coefficients positive in `K[X]`. """ - return [ (monom, K.abs(coeff)) for monom, coeff in f ] - -def sdp_neg(f, u, O, K): - """Negate a polynomial in `K[X]`. """ - return [ (monom, -coeff) for monom, coeff in f ] - -def sdp_add_term(f, term, u, O, K): - """Add a single term using bisection method. """ - M, c = term - - if not c: - return f - if not f: - return [(M, c)] - - monoms = sdp_monoms(f) - - if O(M) > O(monoms[ 0]): - return [(M, c)] + f - if O(M) < O(monoms[-1]): - return f + [(M, c)] - - lo, hi = 0, len(monoms) - 1 - - while lo <= hi: - i = (lo + hi) // 2 - - if O(M) == O(monoms[i]): - coeff = f[i][1] + c - - if not coeff: - return f[:i] + f[i + 1:] - else: - return f[:i] + [(M, coeff)] + f[i + 1:] - else: - if O(M) > O(monoms[i]): - hi = i - 1 - else: - lo = i + 1 - else: - return f[:i] + [(M, c)] + f[i + 1:] - -def sdp_sub_term(f, term, u, O, K): - """Sub a single term using bisection method. """ - M, c = term - - if not c: - return f - if not f: - return [(M, -c)] - - monoms = sdp_monoms(f) - - if O(M) > O(monoms[ 0]): - return [(M, -c)] + f - if O(M) < O(monoms[-1]): - return f + [(M, -c)] - - lo, hi = 0, len(monoms) - 1 - - while lo <= hi: - i = (lo + hi) // 2 - - if O(M) == O(monoms[i]): - coeff = f[i][1] - c - - if not coeff: - return f[:i] + f[i + 1:] - else: - return f[:i] + [(M, coeff)] + f[i + 1:] - else: - if O(M) > O(monoms[i]): - hi = i - 1 - else: - lo = i + 1 - else: - return f[:i] + [(M, -c)] + f[i + 1:] - -def sdp_mul_term(f, term, u, O, K): - """Multiply a distributed polynomial by a term. """ - M, c = term - - if not f or not c: - return [] - else: - if K.is_one(c): - return [ (monomial_mul(f_M, M), f_c) for f_M, f_c in f ] - else: - return [ (monomial_mul(f_M, M), f_c * c) for f_M, f_c in f ] - -def sdp_add(f, g, u, O, K): - """Add distributed polynomials in `K[X]`. """ - h = dict(f) - - for monom, c in g: - if monom in h: - coeff = h[monom] + c - - if not coeff: - del h[monom] - else: - h[monom] = coeff - else: - h[monom] = c - - return sdp_from_dict(h, O) - -def sdp_sub(f, g, u, O, K): - """Subtract distributed polynomials in `K[X]`. """ - h = dict(f) - - for monom, c in g: - if monom in h: - coeff = h[monom] - c - - if not coeff: - del h[monom] - else: - h[monom] = coeff - else: - h[monom] = -c - - return sdp_from_dict(h, O) - -def sdp_mul(f, g, u, O, K): - """Multiply distributed polynomials in `K[X]`. """ - if sdp_term_p(f): - if not f: - return f - else: - return sdp_mul_term(g, f[0], u, O, K) - - if sdp_term_p(g): - if not g: - return g - else: - return sdp_mul_term(f, g[0], u, O, K) - - h = {} - - for fm, fc in f: - for gm, gc in g: - monom = monomial_mul(fm, gm) - coeff = fc * gc - - if monom in h: - coeff += h[monom] - - if not coeff: - del h[monom] - continue - - h[monom] = coeff - - return sdp_from_dict(h, O) - -def sdp_sqr(f, u, O, K): - """Square a distributed polynomial in `K[X]`. """ - h = {} - - for fm, fc in f: - for Fm, Fc in f: - monom = monomial_mul(fm, Fm) - coeff = fc * Fc - - if monom in h: - coeff += h[monom] - - if not coeff: - del h[monom] - continue - - h[monom] = coeff - - return sdp_from_dict(h, O) - -def sdp_pow(f, n, u, O, K): - """Raise `f` to the n-th power in `K[X]`. """ - if not n: - return sdp_one(u, K) - if n < 0: - raise ValueError("can't raise a polynomial to negative power") - if n == 1 or not f or sdp_one_p(f, u, K): - return f - - g = sdp_one(u, K) - - while True: - n, m = n // 2, n - - if m & 1: - g = sdp_mul(g, f, u, O, K) - - if not n: - break - - f = sdp_sqr(f, u, O, K) - - return g - -def sdp_monic(f, K): - """Divides all coefficients by `LC(f)` in `K[X]`. """ - if not f: - return f - - lc_f = sdp_LC(f, K) - - if K.is_one(lc_f): - return f - else: - return [ (m, K.quo(c, lc_f)) for m, c in f ] - -def sdp_content(f, K): - """Returns GCD of coefficients in `K[X]`. """ - from sympy.polys.domains import QQ - - if K.has_Field: - return K.one - else: - cont = K.zero - - if K == QQ: - for c in f: - cont = K.gcd(cont, c) - else: - for c in f: - cont = K.gcd(cont, c) - - if K.is_one(cont) and i: - break - - return cont - -def sdp_primitive(f, K): - """Returns content and a primitive polynomial in `K[X]`. """ - if K.has_Field: - return K.one, f - else: - cont = sdp_content(f, K) - - if K.is_one(cont): - return cont, f - else: - return cont, [ (m, K.quo(c, cont)) for m, c in f ] - -def _term_rr_div(a, b, K): - """Division of two terms in over a ring. """ - a_lm, a_lc = a - b_lm, b_lc = b - - monom = monomial_div(a_lm, b_lm) - - if not (monom is None or a_lc % b_lc): - return monom, K.quo(a_lc, b_lc) - else: - return None - -def _term_ff_div(a, b, K): - """Division of two terms in over a field. """ - a_lm, a_lc = a - b_lm, b_lc = b - - monom = monomial_div(a_lm, b_lm) - - if monom is not None: - return monom, K.quo(a_lc, b_lc) - else: - return None - -def sdp_div(f, G, u, O, K): - """ - Generalized polynomial division with remainder in `K[X]`. - - Given polynomial `f` and a set of polynomials `g = (g_1, ..., g_n)` - compute a set of quotients `q = (q_1, ..., q_n)` and remainder `r` - such that `f = q_1*f_1 + ... + q_n*f_n + r`, where `r = 0` or `r` - is a completely reduced polynomial with respect to `g`. - - References - ========== - - 1. [Cox97]_ - 2. [Ajwa95]_ - - """ - Q, r = [ [] for _ in range(len(G)) ], [] - - if K.has_Field: - term_div = _term_ff_div - else: - term_div = _term_rr_div - - while f: - for i, g in enumerate(G): - tq = term_div(sdp_LT(f, u, K), sdp_LT(g, u, K), K) - - if tq is not None: - Q[i] = sdp_add_term(Q[i], tq, u, O, K) - f = sdp_sub(f, sdp_mul_term(g, tq, u, O, K), u, O, K) - - break - else: - r = sdp_add_term(r, sdp_LT(f, u, K), u, O, K) - f = sdp_del_LT(f) - - return Q, r - - - -def sdp_rem(f, G, u, O, K): - """Returns polynomial remainder in `K[X]`. """ - r = {} - - if K.has_Field: - term_div = _term_ff_div - else: - term_div = _term_rr_div - - ltf = sdp_LT(f, u, K) - f = dict(f) - get = f.get - while f: - for g in G: - tq = term_div(ltf, sdp_LT(g, u, K), K) - - if tq is not None: - m, c = tq - for mg, cg in g: - m1 = monomial_mul(mg, m) - c1 = get(m1, 0) - c*cg - if not c1: - del f[m1] - else: - f[m1] = c1 - if f: - if O == lex: - ltm = max(f) - else: - ltm = max(f, key=lambda mx: O(mx)) - ltf = ltm, f[ltm] - - break - else: - ltm, ltc = ltf - if ltm in r: - r[ltm] += ltc - else: - r[ltm] = ltc - del f[ltm] - if f: - if O == lex: - ltm = max(f) - else: - ltm = max(f, key=lambda mx: O(mx)) - ltf = ltm, f[ltm] - return sdp_from_dict(r, O) - - -def sdp_quo(f, g, u, O, K): - """Returns polynomial quotient in `K[x]`. """ - return sdp_div(f, g, u, O, K)[0] - -def sdp_exquo(f, g, u, O, K): - """Returns exact polynomial quotient in `K[X]`. """ - q, r = sdp_div(f, g, u, O, K) - - if not r: - return q - else: - raise ExactQuotientFailed(f, g) - -def sdp_lcm(f, g, u, O, K): - """ - Computes LCM of two polynomials in `K[X]`. - - The LCM is computed as the unique generater of the intersection - of the two ideals generated by `f` and `g`. The approach is to - compute a Groebner basis with respect to lexicographic ordering - of `t*f` and `(1 - t)*g`, where `t` is an unrelated variable and - then filtering out the solution that doesn't contain `t`. - - References - ========== - - 1. [Cox97]_ - - """ - from sympy.polys.groebnertools import sdp_groebner - - if not f or not g: - return [] - - if sdp_term_p(f) and sdp_term_p(g): - monom = monomial_lcm(sdp_LM(f, u), sdp_LM(g, u)) - - fc, gc = sdp_LC(f, K), sdp_LC(g, K) - - if K.has_Field: - coeff = K.one - else: - coeff = K.lcm(fc, gc) - - return [(monom, coeff)] - - if not K.has_Field: - lcm = K.one - else: - fc, f = sdp_primitive(f, K) - gc, g = sdp_primitive(g, K) - - lcm = K.lcm(fc, gc) - - f_terms = tuple( ((1,) + m, c) for m, c in f ) - g_terms = tuple( ((0,) + m, c) for m, c in g ) \ - + tuple( ((1,) + m, -c) for m, c in g ) - - F = sdp_sort(f_terms, lex) - G = sdp_sort(g_terms, lex) - - basis = sdp_groebner([F, G], u, lex, K) - - H = [ h for h in basis if sdp_indep_p(h, 0, u) ] - - if K.is_one(lcm): - h = [ (m[1:], c) for m, c in H[0] ] - else: - h = [ (m[1:], c * lcm) for m, c in H[0] ] - - return sdp_sort(h, O) - -def sdp_gcd(f, g, u, O, K): - """Compute GCD of two polynomials in `K[X]` via LCM. """ - if not K.has_Field: - fc, f = sdp_primitive(f, K) - gc, g = sdp_primitive(g, K) - - gcd = K.gcd(fc, gc) - - h = sdp_quo(sdp_mul(f, g, u, O, K), - sdp_lcm(f, g, u, O, K), u, O, K) - - if not K.has_Field: - if K.is_one(gcd): - return h - else: - return [ (m, c * gcd) for m, c in h ] - else: - return sdp_monic(h, K) diff -Nru python3-sympy-0.7.2/sympy/polys/domains/__init__.py python3-sympy-0.7.3/sympy/polys/domains/__init__.py --- python3-sympy-0.7.2/sympy/polys/domains/__init__.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/polys/domains/__init__.py 2013-07-13 17:53:32.000000000 +0000 @@ -14,76 +14,42 @@ from .realdomain import RealDomain from .pythonfinitefield import PythonFiniteField -from .sympyfinitefield import SymPyFiniteField from .gmpyfinitefield import GMPYFiniteField from .pythonintegerring import PythonIntegerRing -from .sympyintegerring import SymPyIntegerRing from .gmpyintegerring import GMPYIntegerRing from .pythonrationalfield import PythonRationalField -from .sympyrationalfield import SymPyRationalField from .gmpyrationalfield import GMPYRationalField -from .sympyrealdomain import SymPyRealDomain -from .pythonrealdomain import PythonRealDomain from .mpmathrealdomain import MPmathRealDomain -from .pythoncomplexdomain import PythonComplexDomain -from .mpmathcomplexdomain import MPmathComplexDomain - from .algebraicfield import AlgebraicField -from .polynomialring import PolynomialRing -from .fractionfield import FractionField +from .old_polynomialring import PolynomialRing +from .old_fractionfield import FractionField from .expressiondomain import ExpressionDomain from .quotientring import QuotientRing FF_python = PythonFiniteField -FF_sympy = SymPyFiniteField FF_gmpy = GMPYFiniteField ZZ_python = PythonIntegerRing -ZZ_sympy = SymPyIntegerRing ZZ_gmpy = GMPYIntegerRing QQ_python = PythonRationalField -QQ_sympy = SymPyRationalField QQ_gmpy = GMPYRationalField -RR_sympy = SymPyRealDomain -RR_python = PythonRealDomain RR_mpmath = MPmathRealDomain -CC_python = PythonComplexDomain -CC_mpmath = MPmathComplexDomain - -from .pythonrationaltype import PythonRationalType - -from .groundtypes import HAS_GMPY - -def _getenv(key, default=None): - from os import getenv - return getenv(key, default) - -GROUND_TYPES = _getenv('SYMPY_GROUND_TYPES', 'auto').lower() - -if GROUND_TYPES == 'auto': - if HAS_GMPY: - GROUND_TYPES = 'gmpy' - else: - GROUND_TYPES = 'python' +from .pythonrational import PythonRational -if GROUND_TYPES == 'gmpy' and not HAS_GMPY: - from warnings import warn - warn("gmpy library is not installed, switching to 'python' ground types") - GROUND_TYPES = 'python' +from sympy.core.compatibility import GROUND_TYPES _GROUND_TYPES_MAP = { 'gmpy': (FF_gmpy, ZZ_gmpy(), QQ_gmpy()), - 'sympy': (FF_sympy, ZZ_sympy(), QQ_sympy()), 'python': (FF_python, ZZ_python(), QQ_python()), } @@ -95,6 +61,5 @@ GF = FF RR = RR_mpmath() -CC = CC_mpmath() EX = ExpressionDomain() diff -Nru python3-sympy-0.7.2/sympy/polys/domains/algebraicfield.py python3-sympy-0.7.3/sympy/polys/domains/algebraicfield.py --- python3-sympy-0.7.2/sympy/polys/domains/algebraicfield.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/polys/domains/algebraicfield.py 2013-07-13 17:53:32.000000000 +0000 @@ -7,15 +7,16 @@ from sympy.polys.polyclasses import ANP from sympy.polys.polyerrors import CoercionFailed, DomainError, NotAlgebraic, IsomorphismFailed + class AlgebraicField(Field, CharacteristicZero, SimpleDomain): """A class for representing algebraic number fields. """ - dtype = ANP + dtype = ANP is_Numerical = True is_Algebraic = True - has_assoc_Ring = False + has_assoc_Ring = False has_assoc_Field = True def __init__(self, dom, *ext): @@ -24,15 +25,18 @@ from sympy.polys.numberfields import to_number_field - self.ext = to_number_field(ext) - self.mod = self.ext.minpoly.rep - self.dom = dom + self.ext = to_number_field(ext) + self.mod = self.ext.minpoly.rep + self.dom = dom self.gens = (self.ext,) self.unit = self([dom(1), dom(0)]) self.zero = self.dtype.zero(self.mod.rep, dom) - self.one = self.dtype.one(self.mod.rep, dom) + self.one = self.dtype.one(self.mod.rep, dom) + + def new(self, element): + return self.dtype(element, self.mod.rep, self.dom) def __str__(self): return str(self.dom) + '<' + str(self.ext) + '>' @@ -40,23 +44,10 @@ def __hash__(self): return hash((self.__class__.__name__, self.dtype, self.dom, self.ext)) - def __call__(self, a): - """Construct an element of ``self`` domain from ``a``. """ - return ANP(a, self.mod.rep, self.dom) - def __eq__(self, other): """Returns ``True`` if two domains are equivalent. """ - if self.dtype == other.dtype: - return self.ext == other.ext - else: - return False - - def __ne__(self, other): - """Returns ``False`` if two domains are equivalent. """ - if self.dtype == other.dtype: - return self.ext != other.ext - else: - return True + return isinstance(other, AlgebraicField) and \ + self.dtype == other.dtype and self.ext == other.ext def algebraic_field(self, *extension): r"""Returns an algebraic field, i.e. `\mathbb{Q}(\alpha, \dots)`. """ @@ -79,7 +70,8 @@ try: return self(to_number_field(a, self.ext).native_coeffs()) except (NotAlgebraic, IsomorphismFailed): - raise CoercionFailed("%s is not a valid algebraic number in %s" % (a, self)) + raise CoercionFailed( + "%s is not a valid algebraic number in %s" % (a, self)) def from_ZZ_python(K1, a, K0): """Convert a Python ``int`` object to ``dtype``. """ @@ -89,14 +81,6 @@ """Convert a Python ``Fraction`` object to ``dtype``. """ return K1(K1.dom.convert(a, K0)) - def from_ZZ_sympy(K1, a, K0): - """Convert a SymPy ``Integer`` object to ``dtype``. """ - return K1(K1.dom.convert(a, K0)) - - def from_QQ_sympy(K1, a, K0): - """Convert a SymPy ``Rational`` object to ``dtype``. """ - return K1(K1.dom.convert(a, K0)) - def from_ZZ_gmpy(K1, a, K0): """Convert a GMPY ``mpz`` object to ``dtype``. """ return K1(K1.dom.convert(a, K0)) @@ -105,10 +89,6 @@ """Convert a GMPY ``mpq`` object to ``dtype``. """ return K1(K1.dom.convert(a, K0)) - def from_RR_sympy(K1, a, K0): - """Convert a SymPy ``Float`` object to ``dtype``. """ - return K1(K1.dom.convert(a, K0)) - def from_RR_mpmath(K1, a, K0): """Convert a mpmath ``mpf`` object to ``dtype``. """ return K1(K1.dom.convert(a, K0)) diff -Nru python3-sympy-0.7.2/sympy/polys/domains/characteristiczero.py python3-sympy-0.7.3/sympy/polys/domains/characteristiczero.py --- python3-sympy-0.7.2/sympy/polys/domains/characteristiczero.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/polys/domains/characteristiczero.py 2013-07-13 17:53:32.000000000 +0000 @@ -2,6 +2,7 @@ from sympy.polys.domains.domain import Domain + class CharacteristicZero(Domain): """Domain that has infinite number of elements. """ diff -Nru python3-sympy-0.7.2/sympy/polys/domains/compositedomain.py python3-sympy-0.7.3/sympy/polys/domains/compositedomain.py --- python3-sympy-0.7.2/sympy/polys/domains/compositedomain.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/polys/domains/compositedomain.py 2013-07-13 17:53:32.000000000 +0000 @@ -3,6 +3,7 @@ from sympy.polys.domains.domain import Domain from sympy.polys.polyerrors import GeneratorsError + class CompositeDomain(Domain): """Base class for composite domains, e.g. ZZ[x], ZZ(X). """ @@ -13,4 +14,5 @@ if not (set(self.gens) & set(gens)): return self.__class__(self.dom, *(self.gens + gens)) else: - raise GeneratorsError("common generators in %s and %s" % (self.gens, gens)) + raise GeneratorsError( + "common generators in %s and %s" % (self.gens, gens)) diff -Nru python3-sympy-0.7.2/sympy/polys/domains/domain.py python3-sympy-0.7.3/sympy/polys/domains/domain.py --- python3-sympy-0.7.2/sympy/polys/domains/domain.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/polys/domains/domain.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,6 +1,9 @@ """Implementation of :class:`Domain` class. """ +from sympy.polys.domains.domainelement import DomainElement + from sympy.core import Basic, sympify +from sympy.core.compatibility import SYMPY_INTS, is_sequence from sympy.polys.polyerrors import ( UnificationFailed, @@ -8,23 +11,24 @@ DomainError, ) + class Domain(object): """Represents an abstract domain. """ dtype = None - zero = None - one = None + zero = None + one = None - has_Ring = False + has_Ring = False has_Field = False - has_assoc_Ring = False + has_assoc_Ring = False has_assoc_Field = False is_ZZ = False is_QQ = False - is_FF = False + is_FiniteField = is_FF = False is_CC = False is_Poly = False @@ -35,14 +39,14 @@ is_Numerical = False is_Algebraic = False - is_Simple = False + is_Simple = False is_Composite = False has_CharacteristicZero = False is_EX = False - rep = None + rep = None alias = None def __init__(self): @@ -57,52 +61,61 @@ def __hash__(self): return hash((self.__class__.__name__, self.dtype)) + def new(self, *args): + return self.dtype(*args) + def __call__(self, *args): """Construct an element of ``self`` domain from ``args``. """ - return self.dtype(*args) + return self.new(*args) def normal(self, *args): return self.dtype(*args) - def convert(K1, a, K0=None): - """Convert an object `a` from `K_0` to `K_1`. """ - if K0 is not None: - if K0.alias is not None: - method = "from_" + K0.alias - else: - method = "from_" + K0.__class__.__name__ + def convert_from(self, element, base): + """Convert ``element`` to ``self.dtype`` given the base domain. """ + if base.alias is not None: + method = "from_" + base.alias + else: + method = "from_" + base.__class__.__name__ - _convert = getattr(K1, method) + _convert = getattr(self, method) - if _convert is not None: - result = _convert(a, K0) + if _convert is not None: + result = _convert(element, base) - if result is not None: - return result + if result is not None: + return result - raise CoercionFailed("can't convert %s of type %s to %s" % (a, K0, K1)) - else: - try: - if K1.of_type(a): - return a + raise CoercionFailed("can't convert %s of type %s from %s to %s" % (element, type(element), base, self)) + + def convert(self, element, base=None): + """Convert ``element`` to ``self.dtype``. """ + if base is not None: + return self.convert_from(element, base) - if type(a) is int: - return K1(a) + if self.of_type(element): + return element - if type(a) is int: - return K1(a) + if isinstance(element, SYMPY_INTS): + return self.new(element) - if K1.is_Numerical and getattr(a, 'is_ground', False): - return K1.convert(a.LC()) + if isinstance(element, DomainElement): + return self.convert_from(element, element.parent()) - a = sympify(a) + # TODO: implement this in from_ methods + if self.is_Numerical and getattr(element, 'is_ground', False): + return self.convert(element.LC()) + + if not is_sequence(element): + try: + element = sympify(element) - if isinstance(a, Basic): - return K1.from_sympy(a) + if isinstance(element, Basic): + return self.from_sympy(element) except (TypeError, ValueError): pass - raise CoercionFailed("can't convert %s to type %s" % (a, K1)) + raise CoercionFailed("can't convert %s of type %s to %s" % (element, type(element), self)) def of_type(self, a): """Check if ``a`` is of type ``dtype``. """ @@ -137,18 +150,6 @@ """Convert a Python ``Fraction`` object to ``dtype``. """ return None - def from_FF_sympy(K1, a, K0): - """Convert ``ModularInteger(Integer)`` to ``dtype``. """ - return None - - def from_ZZ_sympy(K1, a, K0): - """Convert a SymPy ``Integer`` object to ``dtype``. """ - return None - - def from_QQ_sympy(K1, a, K0): - """Convert a SymPy ``Rational`` object to ``dtype``. """ - return None - def from_FF_gmpy(K1, a, K0): """Convert ``ModularInteger(mpz)`` to ``dtype``. """ return None @@ -161,31 +162,32 @@ """Convert a GMPY ``mpq`` object to ``dtype``. """ return None - def from_RR_sympy(K1, a, K0): - """Convert a SymPy ``Float`` object to ``dtype``. """ - return None - def from_RR_mpmath(K1, a, K0): """Convert a mpmath ``mpf`` object to ``dtype``. """ return None def from_AlgebraicField(K1, a, K0): - """Convert a ``ANP`` object to ``dtype``. """ + """Convert an algebraic number to ``dtype``. """ return None - def from_GlobalPolynomialRing(K1, a, K0): - """Convert a ``DMP`` object to ``dtype``. """ - if a.degree() <= 0: - return K1.convert(a.LC(), K0.dom) + def from_PolynomialRing(K1, a, K0): + """Convert a polynomial to ``dtype``. """ + if a.is_ground: + return K1.convert(a.LC, K0.dom) def from_FractionField(K1, a, K0): - """Convert a ``DMF`` object to ``dtype``. """ + """Convert a rational function to ``dtype``. """ return None def from_ExpressionDomain(K1, a, K0): """Convert a ``EX`` object to ``dtype``. """ return K1.from_sympy(a.ex) + def from_GlobalPolynomialRing(K1, a, K0): + """Convert a polynomial to ``dtype``. """ + if a.degree() <= 0: + return K1.convert(a.LC(), K0.dom) + def from_GeneralizedPolynomialRing(K1, a, K0): return K1.from_FractionField(a, K0) @@ -198,8 +200,8 @@ if K0 == K1: return K0 - if not K0.has_CharacteristicZero: - if not K1.has_CharacteristicZero: + if K0.is_FiniteField: + if K1.is_FiniteField: if K0.mod == K1.mod and K0.dom == K1.dom: return K0 elif K1.is_ZZ: @@ -207,7 +209,7 @@ raise UnificationFailed("can't unify %s with %s" % (K0, K1)) - if not K1.has_CharacteristicZero: + if K1.is_FiniteField: if K0.is_ZZ: return K1 else: @@ -281,7 +283,8 @@ if K1.is_Composite: return K1.__class__(K0.unify(K1.dom), *K1.gens) elif K1.is_Algebraic: - raise NotImplementedError("unification of different algebraic extensions") + raise NotImplementedError( + "unification of different algebraic extensions") elif K1.is_ZZ or K1.is_QQ: return K0 else: @@ -300,7 +303,8 @@ if K0.is_ZZ or K0.is_QQ: return K1 else: - raise UnificationFailed("can't unify %s with %s" % (K0, K1)) + raise UnificationFailed( + "can't unify %s with %s" % (K0, K1)) else: if K0.has_Field: return K0 @@ -312,11 +316,11 @@ def __eq__(self, other): """Returns ``True`` if two domains are equivalent. """ - return self.dtype == other.dtype + return isinstance(other, Domain) and self.dtype == other.dtype def __ne__(self, other): """Returns ``False`` if two domains are equivalent. """ - return self.dtype != other.dtype + return not self.__eq__(other) def map(self, seq): """Rersively apply ``self`` to all elements of ``seq``. """ @@ -458,10 +462,22 @@ """Returns denominator of ``a``. """ raise NotImplementedError + def half_gcdex(self, a, b): + """Half extended GCD of ``a`` and ``b``. """ + s, t, h = self.gcdex(a, b) + return s, h + def gcdex(self, a, b): """Extended GCD of ``a`` and ``b``. """ raise NotImplementedError + def cofactors(self, a, b): + """Returns GCD and cofactors of ``a`` and ``b``. """ + gcd = self.gcd(a, b) + cfa = self.quo(a, gcd) + cfb = self.quo(b, gcd) + return gcd, cfa, cfb + def gcd(self, a, b): """Returns GCD of ``a`` and ``b``. """ raise NotImplementedError diff -Nru python3-sympy-0.7.2/sympy/polys/domains/domainelement.py python3-sympy-0.7.3/sympy/polys/domains/domainelement.py --- python3-sympy-0.7.2/sympy/polys/domains/domainelement.py 1970-01-01 00:00:00.000000000 +0000 +++ python3-sympy-0.7.3/sympy/polys/domains/domainelement.py 2013-07-13 17:53:32.000000000 +0000 @@ -0,0 +1,13 @@ +"""Trait for implementing domain elements. """ + +class DomainElement(object): + """ + Represents an element of a domain. + + Mix in this trait into a class which instances should be recognized as + elements of a domain. Method ``parent()`` gives that domain. + + """ + + def parent(self): + raise NotImplementedError("abstract method") diff -Nru python3-sympy-0.7.2/sympy/polys/domains/expressiondomain.py python3-sympy-0.7.3/sympy/polys/domains/expressiondomain.py --- python3-sympy-0.7.2/sympy/polys/domains/expressiondomain.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/polys/domains/expressiondomain.py 2013-07-13 17:53:32.000000000 +0000 @@ -8,6 +8,7 @@ from sympy.polys.polyutils import PicklableWithSlots from sympy.polys.polyerrors import DomainError + class ExpressionDomain(Field, CharacteristicZero, SimpleDomain): """A class for arbitrary expressions. """ @@ -52,16 +53,16 @@ return f.__class__(-f.ex) def __add__(f, g): - return f.simplify(f.ex+f.__class__(g).ex) + return f.simplify(f.ex + f.__class__(g).ex) def __radd__(f, g): - return f.simplify(f.__class__(g).ex+f.ex) + return f.simplify(f.__class__(g).ex + f.ex) def __sub__(f, g): - return f.simplify(f.ex-f.__class__(g).ex) + return f.simplify(f.ex - f.__class__(g).ex) def __rsub__(f, g): - return f.simplify(f.__class__(g).ex-f.ex) + return f.simplify(f.__class__(g).ex - f.ex) def __mul__(f, g): return f.simplify(f.ex*f.__class__(g).ex) @@ -87,27 +88,29 @@ def __eq__(f, g): return f.ex == f.__class__(g).ex - def __req__(f, g): - return f.__class__(g).ex == f.ex - def __ne__(f, g): - return f.ex != f.__class__(g).ex - - def __rne__(f, g): - return f.__class__(g).ex != f.ex + return not f.__eq__(g) def __bool__(f): return f.ex != 0 + def gcd(f, g): + from sympy.polys import gcd + return f.__class__(gcd(f.ex, f.__class__(g).ex)) + + def lcm(f, g): + from sympy.polys import lcm + return f.__class__(lcm(f.ex, f.__class__(g).ex)) + dtype = Expression - zero = Expression(0) - one = Expression(1) + zero = Expression(0) + one = Expression(1) - rep = 'EX' + rep = 'EX' - has_assoc_Ring = False - has_assoc_Field = True + has_assoc_Ring = False + has_assoc_Field = True def __init__(self): pass @@ -128,14 +131,6 @@ """Convert a Python ``Fraction`` object to ``dtype``. """ return K1(K0.to_sympy(a)) - def from_ZZ_sympy(K1, a, K0): - """Convert a SymPy ``Integer`` object to ``dtype``. """ - return K1(K0.to_sympy(a)) - - def from_QQ_sympy(K1, a, K0): - """Convert a SymPy ``Rational`` object to ``dtype``. """ - return K1(K0.to_sympy(a)) - def from_ZZ_gmpy(K1, a, K0): """Convert a GMPY ``mpz`` object to ``dtype``. """ return K1(K0.to_sympy(a)) @@ -144,10 +139,6 @@ """Convert a GMPY ``mpq`` object to ``dtype``. """ return K1(K0.to_sympy(a)) - def from_RR_sympy(K1, a, K0): - """Convert a SymPy ``Float`` object to ``dtype``. """ - return K1(K0.to_sympy(a)) - def from_RR_mpmath(K1, a, K0): """Convert a mpmath ``mpf`` object to ``dtype``. """ return K1(K0.to_sympy(a)) @@ -166,7 +157,7 @@ def get_ring(self): """Returns a ring associated with ``self``. """ - raise DomainError('there is no ring associated with %s' % self) + return self # XXX: EX is not a ring but we don't have much choice here. def get_field(self): """Returns a field associated with ``self``. """ @@ -195,3 +186,9 @@ def denom(self, a): """Returns denominator of ``a``. """ return a.denom() + + def gcd(self, a, b): + return a.gcd(b) + + def lcm(self, a, b): + return a.lcm(b) diff -Nru python3-sympy-0.7.2/sympy/polys/domains/field.py python3-sympy-0.7.3/sympy/polys/domains/field.py --- python3-sympy-0.7.2/sympy/polys/domains/field.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/polys/domains/field.py 2013-07-13 17:53:32.000000000 +0000 @@ -3,6 +3,7 @@ from sympy.polys.domains.ring import Ring from sympy.polys.polyerrors import NotReversible, DomainError + class Field(Ring): """Represents a field domain. """ @@ -33,18 +34,21 @@ return a / b, self.zero def gcd(self, a, b): - """Returns GCD of ``a`` and ``b`` that is consistent with the core - implementation. In addition, this allows the primitive of an - expression to be cleared of Rationals. + """ + Returns GCD of ``a`` and ``b``. + + This definition of GCD over fields allows to clear denominators + in `primitive()`. >>> from sympy.polys.domains import QQ - >>> from sympy import gcd, Rational, primitive + >>> from sympy import S, gcd, primitive >>> from sympy.abc import x + >>> QQ.gcd(QQ(2, 3), QQ(4, 9)) 2/9 - >>> gcd(Rational(2, 3), Rational(4, 9)) + >>> gcd(S(2)/3, S(4)/9) 2/9 - >>> primitive(2*x/3 + Rational(4, 9)) + >>> primitive(2*x/3 + S(4)/9) (2/9, 3*x + 2) """ @@ -59,16 +63,17 @@ return self.convert(p, ring)/q def lcm(self, a, b): - """Returns LCM of ``a`` and ``b`` that is consistent with the core - implementation. + """ + Returns LCM of ``a`` and ``b``. >>> from sympy.polys.domains import QQ - >>> from sympy import lcm, Rational, primitive - >>> from sympy.abc import x + >>> from sympy import S, lcm + >>> QQ.lcm(QQ(2, 3), QQ(4, 9)) 4/3 - >>> lcm(Rational(2, 3), Rational(4, 9)) + >>> lcm(S(2)/3, S(4)/9) 4/3 + """ try: diff -Nru python3-sympy-0.7.2/sympy/polys/domains/finitefield.py python3-sympy-0.7.3/sympy/polys/domains/finitefield.py --- python3-sympy-0.7.2/sympy/polys/domains/finitefield.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/polys/domains/finitefield.py 2013-07-13 17:53:32.000000000 +0000 @@ -2,32 +2,35 @@ from sympy.polys.domains.field import Field from sympy.polys.domains.simpledomain import SimpleDomain -from sympy.polys.domains.groundtypes import SymPyIntegerType +from sympy.polys.domains.groundtypes import SymPyInteger from sympy.polys.domains.modularinteger import ModularIntegerFactory from sympy.polys.polyerrors import CoercionFailed + class FiniteField(Field, SimpleDomain): """General class for finite fields. """ rep = 'FF' + is_FiniteField = is_FF = True is_Numerical = True - has_assoc_Ring = False - has_assoc_Field = True + has_assoc_Ring = False + has_assoc_Field = True dom = None mod = None def __init__(self, mod, symmetric=True): if mod <= 0: - raise ValueError('modulus must be a positive integer, got %s' % mod) + raise ValueError( + 'modulus must be a positive integer, got %s' % mod) self.dtype = ModularIntegerFactory(mod, self.dom, symmetric) - self.zero = self.dtype(0) - self.one = self.dtype(1) - self.mod = mod + self.zero = self.dtype(0) + self.one = self.dtype(1) + self.mod = mod def __str__(self): return 'GF(%s)' % self.mod @@ -40,11 +43,6 @@ return isinstance(other, FiniteField) and \ self.mod == other.mod and self.dom == other.dom - def __ne__(self, other): - """Returns ``False`` if two domains are equivalent. """ - return not isinstance(other, FiniteField) or \ - self.mod != other.mod or self.dom != other.dom - def characteristic(self): """Return the characteristic of this domain. """ return self.mod @@ -55,7 +53,7 @@ def to_sympy(self, a): """Convert ``a`` to a SymPy object. """ - return SymPyIntegerType(int(a)) + return SymPyInteger(int(a)) def from_sympy(self, a): """Convert SymPy's Integer to SymPy's ``Integer``. """ @@ -79,19 +77,6 @@ if a.denominator == 1: return K1.from_ZZ_python(a.numerator) - def from_FF_sympy(K1, a, K0=None): - """Convert ``ModularInteger(Integer)`` to ``dtype``. """ - return K1.dtype(K1.dom.from_ZZ_sympy(a.val, K0.dom)) - - def from_ZZ_sympy(K1, a, K0=None): - """Convert SymPy's ``Integer`` to ``dtype``. """ - return K1.dtype(K1.dom.from_ZZ_sympy(a, K0)) - - def from_QQ_sympy(K1, a, K0=None): - """Convert SymPy's ``Rational`` to ``dtype``. """ - if a.q == 1: - return K1.from_ZZ_python(a.p) - def from_FF_gmpy(K1, a, K0=None): """Convert ``ModularInteger(mpz)`` to ``dtype``. """ return K1.dtype(K1.dom.from_ZZ_gmpy(a.val, K0.dom)) @@ -102,15 +87,8 @@ def from_QQ_gmpy(K1, a, K0=None): """Convert GMPY's ``mpq`` to ``dtype``. """ - if a.denom() == 1: - return K1.from_ZZ_gmpy(a.numer()) - - def from_RR_sympy(K1, a, K0=None): - """Convert SymPy's ``Float`` to ``dtype``. """ - p, q = K0.as_integer_ratio(a) - - if q == 1: - return K1.dtype(self.dom.dtype(p)) + if a.denominator == 1: + return K1.from_ZZ_gmpy(a.numerator) def from_RR_mpmath(K1, a, K0): """Convert mpmath's ``mpf`` to ``dtype``. """ diff -Nru python3-sympy-0.7.2/sympy/polys/domains/fractionfield.py python3-sympy-0.7.3/sympy/polys/domains/fractionfield.py --- python3-sympy-0.7.2/sympy/polys/domains/fractionfield.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/polys/domains/fractionfield.py 2013-07-13 17:53:32.000000000 +0000 @@ -2,32 +2,29 @@ from sympy.polys.domains.field import Field from sympy.polys.domains.compositedomain import CompositeDomain -from sympy.polys.domains.characteristiczero import CharacteristicZero +from sympy.polys.polyerrors import CoercionFailed, GeneratorsError -from sympy.polys.polyclasses import DMF -from sympy.polys.polyerrors import GeneratorsNeeded -from sympy.polys.polyutils import dict_from_basic, basic_from_dict, _dict_reorder +class FractionField(Field, CompositeDomain): + """A class for representing multivariate rational function fields. """ -class FractionField(Field, CharacteristicZero, CompositeDomain): - """A class for representing rational function fields. """ - - dtype = DMF is_Frac = True has_assoc_Ring = True has_assoc_Field = True - def __init__(self, dom, *gens): - if not gens: - raise GeneratorsNeeded("generators not specified") + def __init__(self, field): + self.dtype = field.dtype + self.field = field + + self.dom = field.domain + self.gens = field.symbols - lev = len(gens) - 1 + self.zero = field.zero + self.one = field.one - self.zero = self.dtype.zero(lev, dom, ring=self) - self.one = self.dtype.one(lev, dom, ring=self) - self.dom = dom - self.gens = gens + def new(self, element): + return self.field.field_new(element) def __str__(self): return str(self.dom) + '(' + ','.join(map(str, self.gens)) + ')' @@ -35,160 +32,96 @@ def __hash__(self): return hash((self.__class__.__name__, self.dtype, self.dom, self.gens)) - def __call__(self, a): - """Construct an element of ``self`` domain from ``a``. """ - return DMF(a, self.dom, len(self.gens)-1, ring=self) - def __eq__(self, other): - """Returns ``True`` if two domains are equivalent. """ - if not isinstance(other, FractionField): - return False - return self.dtype == other.dtype and self.dom == other.dom and self.gens == other.gens - - def __ne__(self, other): - """Returns ``False`` if two domains are equivalent. """ - return not self.__eq__(other) + """Returns `True` if two domains are equivalent. """ + return isinstance(other, FractionField) and \ + self.dtype == other.dtype and self.field == other.field def to_sympy(self, a): - """Convert ``a`` to a SymPy object. """ - return (basic_from_dict(a.numer().to_sympy_dict(), *self.gens) / - basic_from_dict(a.denom().to_sympy_dict(), *self.gens)) + """Convert `a` to a SymPy object. """ + return a.as_expr() def from_sympy(self, a): - """Convert SymPy's expression to ``dtype``. """ - p, q = a.as_numer_denom() - - num, _ = dict_from_basic(p, gens=self.gens) - den, _ = dict_from_basic(q, gens=self.gens) - - for k, v in num.items(): - num[k] = self.dom.from_sympy(v) - - for k, v in den.items(): - den[k] = self.dom.from_sympy(v) - - return self((num, den)).cancel() + """Convert SymPy's expression to `dtype`. """ + return self.field.from_expr(a) def from_ZZ_python(K1, a, K0): - """Convert a Python ``int`` object to ``dtype``. """ + """Convert a Python `int` object to `dtype`. """ return K1(K1.dom.convert(a, K0)) def from_QQ_python(K1, a, K0): - """Convert a Python ``Fraction`` object to ``dtype``. """ - return K1(K1.dom.convert(a, K0)) - - def from_ZZ_sympy(K1, a, K0): - """Convert a SymPy ``Integer`` object to ``dtype``. """ - return K1(K1.dom.convert(a, K0)) - - def from_QQ_sympy(K1, a, K0): - """Convert a SymPy ``Rational`` object to ``dtype``. """ + """Convert a Python `Fraction` object to `dtype`. """ return K1(K1.dom.convert(a, K0)) def from_ZZ_gmpy(K1, a, K0): - """Convert a GMPY ``mpz`` object to ``dtype``. """ + """Convert a GMPY `mpz` object to `dtype`. """ return K1(K1.dom.convert(a, K0)) def from_QQ_gmpy(K1, a, K0): - """Convert a GMPY ``mpq`` object to ``dtype``. """ - return K1(K1.dom.convert(a, K0)) - - def from_RR_sympy(K1, a, K0): - """Convert a SymPy ``Float`` object to ``dtype``. """ + """Convert a GMPY `mpq` object to `dtype`. """ return K1(K1.dom.convert(a, K0)) def from_RR_mpmath(K1, a, K0): - """Convert a mpmath ``mpf`` object to ``dtype``. """ + """Convert a mpmath `mpf` object to `dtype`. """ return K1(K1.dom.convert(a, K0)) - def from_GlobalPolynomialRing(K1, a, K0): - """Convert a ``DMF`` object to ``dtype``. """ - if K1.gens == K0.gens: - if K1.dom == K0.dom: - return K1(a.rep) - else: - return K1(a.convert(K1.dom).rep) - else: - monoms, coeffs = _dict_reorder(a.to_dict(), K0.gens, K1.gens) - - if K1.dom != K0.dom: - coeffs = [ K1.dom.convert(c, K0.dom) for c in coeffs ] - - return K1(dict(list(zip(monoms, coeffs)))) + def from_AlgebraicField(K1, a, K0): + """Convert an algebraic number to ``dtype``. """ + if K1.dom == K0: + return K1.new(a) + + def from_PolynomialRing(K1, a, K0): + """Convert a polynomial to ``dtype``. """ + try: + return K1.new(a.set_ring(K1.field.ring)) + except (CoercionFailed, GeneratorsError): + return None def from_FractionField(K1, a, K0): - """ - Convert a fraction field element to another fraction field. - - Examples - ======== - - >>> from sympy.polys.polyclasses import DMF - >>> from sympy.polys.domains import ZZ, QQ - >>> from sympy.abc import x - - >>> f = DMF(([ZZ(1), ZZ(2)], [ZZ(1), ZZ(1)]), ZZ) - - >>> QQx = QQ.frac_field(x) - >>> ZZx = ZZ.frac_field(x) - - >>> QQx.from_FractionField(f, ZZx) - (x + 2)/(x + 1) - - """ - if K1.gens == K0.gens: - if K1.dom == K0.dom: - return a - else: - return K1((a.numer().convert(K1.dom).rep, - a.denom().convert(K1.dom).rep)) - elif set(K0.gens).issubset(K1.gens): - nmonoms, ncoeffs = _dict_reorder(a.numer().to_dict(), K0.gens, K1.gens) - dmonoms, dcoeffs = _dict_reorder(a.denom().to_dict(), K0.gens, K1.gens) - - if K1.dom != K0.dom: - ncoeffs = [ K1.dom.convert(c, K0.dom) for c in ncoeffs ] - dcoeffs = [ K1.dom.convert(c, K0.dom) for c in dcoeffs ] - - return K1((dict(list(zip(nmonoms, ncoeffs))), dict(list(zip(dmonoms, dcoeffs))))) + """Convert a rational function to ``dtype``. """ + try: + return a.set_field(K1.field) + except (CoercionFailed, GeneratorsError): + return None def get_ring(self): - """Returns a ring associated with ``self``. """ - from sympy.polys.domains import PolynomialRing - return PolynomialRing(self.dom, *self.gens) + """Returns a field associated with `self`. """ + return self.field.to_ring().to_domain() - def poly_ring(self, *gens): + def poly_ring(self, *symbols): # TODO:, order=lex): """Returns a polynomial ring, i.e. `K[X]`. """ - raise NotImplementedError('nested domains not allowed') + from sympy.polys.rings import PolyRing + return PolyRing(symbols, self.field, order).to_domain() - def frac_field(self, *gens): + def frac_field(self, *symbols): # TODO:, order=lex): """Returns a fraction field, i.e. `K(X)`. """ - raise NotImplementedError('nested domains not allowed') + from sympy.polys.fields import FracField + return FracField(symbols, self.field, order).to_domain() def is_positive(self, a): - """Returns True if ``a`` is positive. """ - return self.dom.is_positive(a.numer().LC()) + """Returns True if `LC(a)` is positive. """ + return self.dom.is_positive(a.numer.LC) def is_negative(self, a): - """Returns True if ``a`` is negative. """ - return self.dom.is_negative(a.numer().LC()) + """Returns True if `LC(a)` is negative. """ + return self.dom.is_negative(a.numer.LC) def is_nonpositive(self, a): - """Returns True if ``a`` is non-positive. """ - return self.dom.is_nonpositive(a.numer().LC()) + """Returns True if `LC(a)` is non-positive. """ + return self.dom.is_nonpositive(a.numer.LC) def is_nonnegative(self, a): - """Returns True if ``a`` is non-negative. """ - return self.dom.is_nonnegative(a.numer().LC()) + """Returns True if `LC(a)` is non-negative. """ + return self.dom.is_nonnegative(a.numer.LC) def numer(self, a): """Returns numerator of ``a``. """ - return a.numer() + return a.numer def denom(self, a): """Returns denominator of ``a``. """ - return a.denom() + return a.denom def factorial(self, a): - """Returns factorial of ``a``. """ + """Returns factorial of `a`. """ return self.dtype(self.dom.factorial(a)) diff -Nru python3-sympy-0.7.2/sympy/polys/domains/gmpyfinitefield.py python3-sympy-0.7.3/sympy/polys/domains/gmpyfinitefield.py --- python3-sympy-0.7.2/sympy/polys/domains/gmpyfinitefield.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/polys/domains/gmpyfinitefield.py 2013-07-13 17:53:32.000000000 +0000 @@ -3,6 +3,7 @@ from sympy.polys.domains.finitefield import FiniteField from sympy.polys.domains.gmpyintegerring import GMPYIntegerRing + class GMPYFiniteField(FiniteField): """Finite field based on Python's integers. """ diff -Nru python3-sympy-0.7.2/sympy/polys/domains/gmpyintegerring.py python3-sympy-0.7.3/sympy/polys/domains/gmpyintegerring.py --- python3-sympy-0.7.2/sympy/polys/domains/gmpyintegerring.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/polys/domains/gmpyintegerring.py 2013-07-13 17:53:32.000000000 +0000 @@ -3,19 +3,20 @@ from sympy.polys.domains.integerring import IntegerRing from sympy.polys.domains.groundtypes import ( - GMPYIntegerType, SymPyIntegerType, + GMPYInteger, SymPyInteger, gmpy_factorial, gmpy_gcdex, gmpy_gcd, gmpy_lcm, gmpy_sqrt, ) from sympy.polys.polyerrors import CoercionFailed + class GMPYIntegerRing(IntegerRing): """Integer ring based on GMPY's ``mpz`` type. """ - dtype = GMPYIntegerType - zero = dtype(0) - one = dtype(1) + dtype = GMPYInteger + zero = dtype(0) + one = dtype(1) alias = 'ZZ_gmpy' def __init__(self): @@ -23,42 +24,29 @@ def to_sympy(self, a): """Convert ``a`` to a SymPy object. """ - return SymPyIntegerType(int(a)) + return SymPyInteger(int(a)) def from_sympy(self, a): """Convert SymPy's Integer to ``dtype``. """ if a.is_Integer: - return GMPYIntegerType(a.p) + return GMPYInteger(a.p) elif a.is_Float and int(a) == a: - return GMPYIntegerType(int(a)) + return GMPYInteger(int(a)) else: raise CoercionFailed("expected an integer, got %s" % a) def from_FF_python(K1, a, K0): """Convert ``ModularInteger(int)`` to GMPY's ``mpz``. """ - return GMPYIntegerType(a.to_int()) + return GMPYInteger(a.to_int()) def from_ZZ_python(K1, a, K0): """Convert Python's ``int`` to GMPY's ``mpz``. """ - return GMPYIntegerType(a) + return GMPYInteger(a) def from_QQ_python(K1, a, K0): """Convert Python's ``Fraction`` to GMPY's ``mpz``. """ if a.denominator == 1: - return GMPYIntegerType(a.numerator) - - def from_FF_sympy(K1, a, K0): - """Convert ``ModularInteger(Integer)`` to GMPY's ``mpz``. """ - return GMPYIntegerType(a.to_int().p) - - def from_ZZ_sympy(K1, a, K0): - """Convert SymPy's ``Integer`` to GMPY's ``mpz``. """ - return GMPYIntegerType(a.p) - - def from_QQ_sympy(K1, a, K0): - """Convert SymPy's ``Rational`` to GMPY's ``mpz``. """ - if a.q == 1: - return GMPYIntegerType(a.p) + return GMPYInteger(a.numerator) def from_FF_gmpy(K1, a, K0): """Convert ``ModularInteger(mpz)`` to GMPY's ``mpz``. """ @@ -70,22 +58,15 @@ def from_QQ_gmpy(K1, a, K0): """Convert GMPY ``mpq`` to GMPY's ``mpz``. """ - if a.denom() == 1: - return a.numer() - - def from_RR_sympy(K1, a, K0): - """Convert SymPy's ``Float`` to GMPY's ``mpz``. """ - p, q = K0.as_integer_ratio(a) - - if q == 1: - return GMPYIntegerType(p) + if a.denominator == 1: + return a.numerator def from_RR_mpmath(K1, a, K0): """Convert mpmath's ``mpf`` to GMPY's ``mpz``. """ p, q = K0.as_integer_ratio(a) if q == 1: - return GMPYIntegerType(p) + return GMPYInteger(p) def gcdex(self, a, b): """Compute extended GCD of ``a`` and ``b``. """ diff -Nru python3-sympy-0.7.2/sympy/polys/domains/gmpyrationalfield.py python3-sympy-0.7.3/sympy/polys/domains/gmpyrationalfield.py --- python3-sympy-0.7.2/sympy/polys/domains/gmpyrationalfield.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/polys/domains/gmpyrationalfield.py 2013-07-13 17:53:32.000000000 +0000 @@ -3,77 +3,71 @@ from sympy.polys.domains.rationalfield import RationalField from sympy.polys.domains.groundtypes import ( - GMPYRationalType, SymPyRationalType, - gmpy_numer, gmpy_denom, gmpy_factorial, + GMPYRational, SymPyRational, + gmpy_numer, gmpy_denom, gmpy_factorial, gmpy_qdiv, ) from sympy.polys.polyerrors import CoercionFailed + class GMPYRationalField(RationalField): """Rational field based on GMPY mpq class. """ - dtype = GMPYRationalType - zero = dtype(0) - one = dtype(1) + dtype = GMPYRational + zero = dtype(0) + one = dtype(1) alias = 'QQ_gmpy' def __init__(self): pass + def get_ring(self): + """Returns ring associated with ``self``. """ + from sympy.polys.domains import GMPYIntegerRing + return GMPYIntegerRing() + def to_sympy(self, a): """Convert `a` to a SymPy object. """ - return SymPyRationalType(int(gmpy_numer(a)), - int(gmpy_denom(a))) + return SymPyRational(int(gmpy_numer(a)), + int(gmpy_denom(a))) def from_sympy(self, a): """Convert SymPy's Integer to `dtype`. """ if a.is_Rational: - return GMPYRationalType(a.p, a.q) + return GMPYRational(a.p, a.q) elif a.is_Float: from sympy.polys.domains import RR - return GMPYRationalType(*RR.as_integer_ratio(a)) + return GMPYRational(*RR.as_integer_ratio(a)) else: raise CoercionFailed("expected `Rational` object, got %s" % a) def from_ZZ_python(K1, a, K0): """Convert a Python `int` object to `dtype`. """ - return GMPYRationalType(a) + return GMPYRational(a) def from_QQ_python(K1, a, K0): """Convert a Python `Fraction` object to `dtype`. """ - return GMPYRationalType(a.numerator, a.denominator) - - def from_ZZ_sympy(K1, a, K0): - """Convert a SymPy `Integer` object to `dtype`. """ - return GMPYRationalType(a.p) - - def from_QQ_sympy(K1, a, K0): - """Convert a SymPy `Rational` object to `dtype`. """ - return GMPYRationalType(a.p, a.q) + return GMPYRational(a.numerator, a.denominator) def from_ZZ_gmpy(K1, a, K0): """Convert a GMPY `mpz` object to `dtype`. """ - return GMPYRationalType(a) + return GMPYRational(a) def from_QQ_gmpy(K1, a, K0): """Convert a GMPY `mpq` object to `dtype`. """ return a - def from_RR_sympy(K1, a, K0): - """Convert a SymPy `Float` object to `dtype`. """ - return GMPYRationalType(*K0.as_integer_ratio(a)) - def from_RR_mpmath(K1, a, K0): """Convert a mpmath `mpf` object to `dtype`. """ - return GMPYRationalType(*K0.as_integer_ratio(a)) + return GMPYRational(*K0.as_integer_ratio(a)) def exquo(self, a, b): """Exact quotient of `a` and `b`, implies `__div__`. """ - return GMPYRationalType(a.qdiv(b)) + return GMPYRational(gmpy_qdiv(a, b)) def quo(self, a, b): """Quotient of `a` and `b`, implies `__div__`. """ - return GMPYRationalType(a.qdiv(b)) + return GMPYRational(gmpy_qdiv(a, b)) def rem(self, a, b): """Remainder of `a` and `b`, implies nothing. """ @@ -81,16 +75,16 @@ def div(self, a, b): """Division of `a` and `b`, implies `__div__`. """ - return GMPYRationalType(a.qdiv(b)), self.zero + return GMPYRational(gmpy_qdiv(a, b)), self.zero def numer(self, a): """Returns numerator of `a`. """ - return gmpy_numer(a) + return a.numerator def denom(self, a): """Returns denominator of `a`. """ - return gmpy_denom(a) + return a.denominator def factorial(self, a): """Returns factorial of `a`. """ - return GMPYRationalType(gmpy_factorial(int(a))) + return GMPYRational(gmpy_factorial(int(a))) diff -Nru python3-sympy-0.7.2/sympy/polys/domains/groundtypes.py python3-sympy-0.7.3/sympy/polys/domains/groundtypes.py --- python3-sympy-0.7.2/sympy/polys/domains/groundtypes.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/polys/domains/groundtypes.py 2013-07-13 17:53:32.000000000 +0000 @@ -2,77 +2,87 @@ from sympy.external import import_module -HAS_GMPY = True +# The logic for detecting if a compatible version of gmpy/gmpy2 is present is +# done in sympy.core.compatibility. -# Versions of gmpy prior to 1.03 do not work correctly with int(largempz) -# For example, int(gmpy.mpz(2**256)) would raise OverflowError. -# See issue 1881. - -gmpy = import_module('gmpy', min_module_version='1.03', - module_version_attr='version', module_version_attr_call_args=()) - -HAS_GMPY = bool(gmpy) +from sympy.core.compatibility import HAS_GMPY from builtins import ( - int as PythonIntegerType, - float as PythonRealType, - complex as PythonComplexType, + int as PythonInteger, + float as PythonReal, + complex as PythonComplex, ) -from .pythonrationaltype import PythonRationalType - -def python_factorial(n): - from sympy.functions.combinatorial.factorials import factorial - return int(factorial(n)) +from .pythonrational import PythonRational from sympy.core.numbers import ( - igcdex as python_gcdex, - igcd as python_gcd, - ilcm as python_lcm, + igcdex as python_gcdex, + igcd as python_gcd, + ilcm as python_lcm, ) from sympy import ( - Float as SymPyRealType, - Integer as SymPyIntegerType, - Rational as SymPyRationalType, + Float as SymPyReal, + Integer as SymPyInteger, + Rational as SymPyRational, ) -if HAS_GMPY: +if HAS_GMPY == 1: from gmpy import ( - mpz as GMPYIntegerType, - mpq as GMPYRationalType, - fac as gmpy_factorial, - numer as gmpy_numer, - denom as gmpy_denom, + mpz as GMPYInteger, + mpq as GMPYRational, + fac as gmpy_factorial, + numer as gmpy_numer, + denom as gmpy_denom, + gcdext as gmpy_gcdex, + gcd as gmpy_gcd, + lcm as gmpy_lcm, + sqrt as gmpy_sqrt, + qdiv as gmpy_qdiv, + ) +elif HAS_GMPY == 2: + from gmpy2 import ( + mpz as GMPYInteger, + mpq as GMPYRational, + fac as gmpy_factorial, + numer as gmpy_numer, + denom as gmpy_denom, gcdext as gmpy_gcdex, - gcd as gmpy_gcd, - lcm as gmpy_lcm, - sqrt as gmpy_sqrt, + gcd as gmpy_gcd, + lcm as gmpy_lcm, + isqrt as gmpy_sqrt, + qdiv as gmpy_qdiv, ) else: - class GMPYIntegerType(object): + class GMPYInteger(object): def __init__(self, obj): pass - class GMPYRationalType(object): + class GMPYRational(object): def __init__(self, obj): pass - gmpy_factorial = None - gmpy_numer = None - gmpy_denom = None - gmpy_gcdex = None - gmpy_gcd = None - gmpy_lcm = None - gmpy_sqrt = None + gmpy_factorial = None + gmpy_numer = None + gmpy_denom = None + gmpy_gcdex = None + gmpy_gcd = None + gmpy_lcm = None + gmpy_sqrt = None + gmpy_qdiv = None from sympy.mpmath import ( - mpf as MPmathRealType, - mpc as MPmathComplexType, - mpi as MPmathIntervalType, + mpf as MPmathReal, + mpc as MPmathComplex, + mpi as MPmathInterval, ) -from sympy.mpmath.libmp.libmpf import isqrt +import sympy.mpmath.libmp as mlib + + +def python_sqrt(n): + return int(mlib.isqrt(n)) -def python_sqrt(a): - return int(isqrt(a)) + +def python_factorial(n): + return int(mlib.ifac(n)) diff -Nru python3-sympy-0.7.2/sympy/polys/domains/integerring.py python3-sympy-0.7.3/sympy/polys/domains/integerring.py --- python3-sympy-0.7.2/sympy/polys/domains/integerring.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/polys/domains/integerring.py 2013-07-13 17:53:32.000000000 +0000 @@ -6,16 +6,17 @@ import math + class IntegerRing(Ring, CharacteristicZero, SimpleDomain): """General class for integer rings. """ is_ZZ = True - rep = 'ZZ' + rep = 'ZZ' is_Numerical = True - has_assoc_Ring = True - has_assoc_Field = True + has_assoc_Ring = True + has_assoc_Field = True def get_field(self): """Returns a field associated with ``self``. """ diff -Nru python3-sympy-0.7.2/sympy/polys/domains/modularinteger.py python3-sympy-0.7.3/sympy/polys/domains/modularinteger.py --- python3-sympy-0.7.2/sympy/polys/domains/modularinteger.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/polys/domains/modularinteger.py 2013-07-13 17:53:32.000000000 +0000 @@ -5,6 +5,7 @@ from sympy.polys.polyutils import PicklableWithSlots from sympy.polys.polyerrors import CoercionFailed + class ModularInteger(PicklableWithSlots): """A class representing a modular integer. """ @@ -167,6 +168,7 @@ _modular_integer_cache = {} + def ModularIntegerFactory(_mod, _dom=None, _sym=True): """Create custom class for specific integer modulus.""" if _dom is None: diff -Nru python3-sympy-0.7.2/sympy/polys/domains/mpmathcomplexdomain.py python3-sympy-0.7.3/sympy/polys/domains/mpmathcomplexdomain.py --- python3-sympy-0.7.2/sympy/polys/domains/mpmathcomplexdomain.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/polys/domains/mpmathcomplexdomain.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,11 +0,0 @@ -"""Implementation of :class:`MPmathComplexDomain` class. """ - -from sympy.polys.domains.realdomain import RealDomain - -class MPmathComplexDomain(RealDomain): # XXX: tmp solution - """Complex domain. """ - - alias = 'CC_mpmath' - - def __init__(self): - pass diff -Nru python3-sympy-0.7.2/sympy/polys/domains/mpmathrealdomain.py python3-sympy-0.7.3/sympy/polys/domains/mpmathrealdomain.py --- python3-sympy-0.7.2/sympy/polys/domains/mpmathrealdomain.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/polys/domains/mpmathrealdomain.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,14 +1,15 @@ """Implementation of :class:`MPmathRealDomain` class. """ from sympy.polys.domains.realdomain import RealDomain -from sympy.polys.domains.groundtypes import MPmathRealType +from sympy.polys.domains.groundtypes import MPmathReal + class MPmathRealDomain(RealDomain): """Domain for real numbers based on mpmath mpf type. """ - dtype = MPmathRealType - zero = dtype(0) - one = dtype(1) + dtype = MPmathReal + zero = dtype(0) + one = dtype(1) alias = 'RR_mpmath' def __init__(self): @@ -16,31 +17,19 @@ def from_ZZ_python(K1, a, K0): """Convert a Python `int` object to `dtype`. """ - return MPmathRealType(a) + return MPmathReal(a) def from_QQ_python(K1, a, K0): """Convert a Python `Fraction` object to `dtype`. """ - return MPmathRealType(a.numerator) / a.denominator - - def from_ZZ_sympy(K1, a, K0): - """Convert a SymPy `Integer` object to `dtype`. """ - return MPmathRealType(a.p) - - def from_QQ_sympy(K1, a, K0): - """Convert a SymPy `Rational` object to `dtype`. """ - return MPmathRealType(a.p) / a.q + return MPmathReal(a.numerator) / a.denominator def from_ZZ_gmpy(K1, a, K0): """Convert a GMPY `mpz` object to `dtype`. """ - return MPmathRealType(int(a)) + return MPmathReal(int(a)) def from_QQ_gmpy(K1, a, K0): """Convert a GMPY `mpq` object to `dtype`. """ - return MPmathRealType(int(a.numer())) / int(a.denom()) - - def from_RR_sympy(K1, a, K0): - """Convert a SymPy `Float` object to `dtype`. """ - return MPmathRealType(a) + return MPmathReal(int(a.numerator)) / int(a.denominator) def from_RR_mpmath(K1, a, K0): """Convert a mpmath `mpf` object to `dtype`. """ diff -Nru python3-sympy-0.7.2/sympy/polys/domains/old_fractionfield.py python3-sympy-0.7.3/sympy/polys/domains/old_fractionfield.py --- python3-sympy-0.7.2/sympy/polys/domains/old_fractionfield.py 1970-01-01 00:00:00.000000000 +0000 +++ python3-sympy-0.7.3/sympy/polys/domains/old_fractionfield.py 2013-07-13 17:53:32.000000000 +0000 @@ -0,0 +1,179 @@ +"""Implementation of :class:`FractionField` class. """ + +from sympy.polys.domains.field import Field +from sympy.polys.domains.compositedomain import CompositeDomain +from sympy.polys.domains.characteristiczero import CharacteristicZero + +from sympy.polys.polyclasses import DMF +from sympy.polys.polyerrors import GeneratorsNeeded +from sympy.polys.polyutils import dict_from_basic, basic_from_dict, _dict_reorder + + +class FractionField(Field, CharacteristicZero, CompositeDomain): + """A class for representing rational function fields. """ + + dtype = DMF + is_Frac = True + + has_assoc_Ring = True + has_assoc_Field = True + + def __init__(self, dom, *gens): + if not gens: + raise GeneratorsNeeded("generators not specified") + + lev = len(gens) - 1 + + self.zero = self.dtype.zero(lev, dom, ring=self) + self.one = self.dtype.one(lev, dom, ring=self) + + self.dom = dom + self.gens = gens + + def new(self, element): + return self.dtype(element, self.dom, len(self.gens) - 1, ring=self) + + def __str__(self): + return str(self.dom) + '(' + ','.join(map(str, self.gens)) + ')' + + def __hash__(self): + return hash((self.__class__.__name__, self.dtype, self.dom, self.gens)) + + def __eq__(self, other): + """Returns ``True`` if two domains are equivalent. """ + return isinstance(other, FractionField) and \ + self.dtype == other.dtype and self.dom == other.dom and self.gens == other.gens + + def to_sympy(self, a): + """Convert ``a`` to a SymPy object. """ + return (basic_from_dict(a.numer().to_sympy_dict(), *self.gens) / + basic_from_dict(a.denom().to_sympy_dict(), *self.gens)) + + def from_sympy(self, a): + """Convert SymPy's expression to ``dtype``. """ + p, q = a.as_numer_denom() + + num, _ = dict_from_basic(p, gens=self.gens) + den, _ = dict_from_basic(q, gens=self.gens) + + for k, v in num.items(): + num[k] = self.dom.from_sympy(v) + + for k, v in den.items(): + den[k] = self.dom.from_sympy(v) + + return self((num, den)).cancel() + + def from_ZZ_python(K1, a, K0): + """Convert a Python ``int`` object to ``dtype``. """ + return K1(K1.dom.convert(a, K0)) + + def from_QQ_python(K1, a, K0): + """Convert a Python ``Fraction`` object to ``dtype``. """ + return K1(K1.dom.convert(a, K0)) + + def from_ZZ_gmpy(K1, a, K0): + """Convert a GMPY ``mpz`` object to ``dtype``. """ + return K1(K1.dom.convert(a, K0)) + + def from_QQ_gmpy(K1, a, K0): + """Convert a GMPY ``mpq`` object to ``dtype``. """ + return K1(K1.dom.convert(a, K0)) + + def from_RR_mpmath(K1, a, K0): + """Convert a mpmath ``mpf`` object to ``dtype``. """ + return K1(K1.dom.convert(a, K0)) + + def from_GlobalPolynomialRing(K1, a, K0): + """Convert a ``DMF`` object to ``dtype``. """ + if K1.gens == K0.gens: + if K1.dom == K0.dom: + return K1(a.rep) + else: + return K1(a.convert(K1.dom).rep) + else: + monoms, coeffs = _dict_reorder(a.to_dict(), K0.gens, K1.gens) + + if K1.dom != K0.dom: + coeffs = [ K1.dom.convert(c, K0.dom) for c in coeffs ] + + return K1(dict(list(zip(monoms, coeffs)))) + + def from_FractionField(K1, a, K0): + """ + Convert a fraction field element to another fraction field. + + Examples + ======== + + >>> from sympy.polys.polyclasses import DMF + >>> from sympy.polys.domains import ZZ, QQ + >>> from sympy.abc import x + + >>> f = DMF(([ZZ(1), ZZ(2)], [ZZ(1), ZZ(1)]), ZZ) + + >>> QQx = QQ.frac_field(x) + >>> ZZx = ZZ.frac_field(x) + + >>> QQx.from_FractionField(f, ZZx) + (x + 2)/(x + 1) + + """ + if K1.gens == K0.gens: + if K1.dom == K0.dom: + return a + else: + return K1((a.numer().convert(K1.dom).rep, + a.denom().convert(K1.dom).rep)) + elif set(K0.gens).issubset(K1.gens): + nmonoms, ncoeffs = _dict_reorder( + a.numer().to_dict(), K0.gens, K1.gens) + dmonoms, dcoeffs = _dict_reorder( + a.denom().to_dict(), K0.gens, K1.gens) + + if K1.dom != K0.dom: + ncoeffs = [ K1.dom.convert(c, K0.dom) for c in ncoeffs ] + dcoeffs = [ K1.dom.convert(c, K0.dom) for c in dcoeffs ] + + return K1((dict(list(zip(nmonoms, ncoeffs))), dict(list(zip(dmonoms, dcoeffs))))) + + def get_ring(self): + """Returns a ring associated with ``self``. """ + from sympy.polys.domains import PolynomialRing + return PolynomialRing(self.dom, *self.gens) + + def poly_ring(self, *gens): + """Returns a polynomial ring, i.e. `K[X]`. """ + raise NotImplementedError('nested domains not allowed') + + def frac_field(self, *gens): + """Returns a fraction field, i.e. `K(X)`. """ + raise NotImplementedError('nested domains not allowed') + + def is_positive(self, a): + """Returns True if ``a`` is positive. """ + return self.dom.is_positive(a.numer().LC()) + + def is_negative(self, a): + """Returns True if ``a`` is negative. """ + return self.dom.is_negative(a.numer().LC()) + + def is_nonpositive(self, a): + """Returns True if ``a`` is non-positive. """ + return self.dom.is_nonpositive(a.numer().LC()) + + def is_nonnegative(self, a): + """Returns True if ``a`` is non-negative. """ + return self.dom.is_nonnegative(a.numer().LC()) + + def numer(self, a): + """Returns numerator of ``a``. """ + return a.numer() + + def denom(self, a): + """Returns denominator of ``a``. """ + return a.denom() + + def factorial(self, a): + """Returns factorial of ``a``. """ + return self.dtype(self.dom.factorial(a)) diff -Nru python3-sympy-0.7.2/sympy/polys/domains/old_polynomialring.py python3-sympy-0.7.3/sympy/polys/domains/old_polynomialring.py --- python3-sympy-0.7.2/sympy/polys/domains/old_polynomialring.py 1970-01-01 00:00:00.000000000 +0000 +++ python3-sympy-0.7.3/sympy/polys/domains/old_polynomialring.py 2013-07-13 17:53:32.000000000 +0000 @@ -0,0 +1,425 @@ +"""Implementation of :class:`PolynomialRing` class. """ + +from sympy.polys.domains.ring import Ring +from sympy.polys.domains.compositedomain import CompositeDomain +from sympy.polys.domains.characteristiczero import CharacteristicZero +from sympy.polys.domains.old_fractionfield import FractionField + +from sympy.polys.polyclasses import DMP, DMF +from sympy.polys.polyerrors import (GeneratorsNeeded, PolynomialError, + CoercionFailed, ExactQuotientFailed, NotReversible) +from sympy.polys.polyutils import dict_from_basic, basic_from_dict, _dict_reorder + +from sympy.polys.monomialtools import monomial_key, build_product_order + +from sympy.polys.agca.modules import FreeModulePolyRing + +from sympy.core.compatibility import iterable + +# XXX why does this derive from CharacteristicZero??? + + +class PolynomialRingBase(Ring, CharacteristicZero, CompositeDomain): + """ + Base class for generalized polynomial rings. + + This base class should be used for uniform access to generalized polynomial + rings. Subclasses only supply information about the element storage etc. + + Do not instantiate. + """ + + has_assoc_Ring = True + has_assoc_Field = True + + default_order = "grevlex" + + def __init__(self, dom, *gens, **opts): + if not gens: + raise GeneratorsNeeded("generators not specified") + + lev = len(gens) - 1 + + self.zero = self.dtype.zero(lev, dom, ring=self) + self.one = self.dtype.one(lev, dom, ring=self) + + self.dom = dom + self.gens = gens + # NOTE 'order' may not be set if inject was called through CompositeDomain + self.order = opts.get('order', monomial_key(self.default_order)) + + def new(self, element): + return self.dtype(element, self.dom, len(self.gens) - 1, ring=self) + + def __str__(self): + s_order = str(self.order) + orderstr = ( + " order=" + s_order) if s_order != self.default_order else "" + return str(self.dom) + '[' + ','.join(map(str, self.gens)) + orderstr + ']' + + def __hash__(self): + return hash((self.__class__.__name__, self.dtype, self.dom, + self.gens, self.order)) + + def __eq__(self, other): + """Returns `True` if two domains are equivalent. """ + return isinstance(other, PolynomialRingBase) and \ + self.dtype == other.dtype and self.dom == other.dom and \ + self.gens == other.gens and self.order == other.order + + def from_ZZ_python(K1, a, K0): + """Convert a Python `int` object to `dtype`. """ + return K1(K1.dom.convert(a, K0)) + + def from_QQ_python(K1, a, K0): + """Convert a Python `Fraction` object to `dtype`. """ + return K1(K1.dom.convert(a, K0)) + + def from_ZZ_gmpy(K1, a, K0): + """Convert a GMPY `mpz` object to `dtype`. """ + return K1(K1.dom.convert(a, K0)) + + def from_QQ_gmpy(K1, a, K0): + """Convert a GMPY `mpq` object to `dtype`. """ + return K1(K1.dom.convert(a, K0)) + + def from_RR_mpmath(K1, a, K0): + """Convert a mpmath `mpf` object to `dtype`. """ + return K1(K1.dom.convert(a, K0)) + + def from_AlgebraicField(K1, a, K0): + """Convert a `ANP` object to `dtype`. """ + if K1.dom == K0: + return K1(a) + + def from_GlobalPolynomialRing(K1, a, K0): + """Convert a `DMP` object to `dtype`. """ + if K1.gens == K0.gens: + if K1.dom == K0.dom: + return K1(a.rep) # set the correct ring + else: + return K1(a.convert(K1.dom).rep) + else: + monoms, coeffs = _dict_reorder(a.to_dict(), K0.gens, K1.gens) + + if K1.dom != K0.dom: + coeffs = [ K1.dom.convert(c, K0.dom) for c in coeffs ] + + return K1(dict(list(zip(monoms, coeffs)))) + + def get_field(self): + """Returns a field associated with `self`. """ + return FractionField(self.dom, *self.gens) + + def poly_ring(self, *gens): + """Returns a polynomial ring, i.e. `K[X]`. """ + raise NotImplementedError('nested domains not allowed') + + def frac_field(self, *gens): + """Returns a fraction field, i.e. `K(X)`. """ + raise NotImplementedError('nested domains not allowed') + + def revert(self, a): + try: + return 1/a + except (ExactQuotientFailed, ZeroDivisionError): + raise NotReversible('%s is not a unit' % a) + + def gcdex(self, a, b): + """Extended GCD of `a` and `b`. """ + return a.gcdex(b) + + def gcd(self, a, b): + """Returns GCD of `a` and `b`. """ + return a.gcd(b) + + def lcm(self, a, b): + """Returns LCM of `a` and `b`. """ + return a.lcm(b) + + def factorial(self, a): + """Returns factorial of `a`. """ + return self.dtype(self.dom.factorial(a)) + + def _vector_to_sdm(self, v, order): + """ + For internal use by the modules class. + + Convert an iterable of elements of this ring into a sparse distributed + module element. + """ + raise NotImplementedError + + def _sdm_to_dics(self, s, n): + """Helper for _sdm_to_vector.""" + from sympy.polys.distributedmodules import sdm_to_dict + dic = sdm_to_dict(s) + res = [{} for _ in range(n)] + for k, v in dic.items(): + res[k[0]][k[1:]] = v + return res + + def _sdm_to_vector(self, s, n): + """ + For internal use by the modules class. + + Convert a sparse distributed module into a list of length ``n``. + + >>> from sympy import QQ, ilex + >>> from sympy.abc import x, y + >>> R = QQ.poly_ring(x, y, order=ilex) + >>> L = [((1, 1, 1), QQ(1)), ((0, 1, 0), QQ(1)), ((0, 0, 1), QQ(2))] + >>> R._sdm_to_vector(L, 2) + [x + 2*y, x*y] + """ + dics = self._sdm_to_dics(s, n) + # NOTE this works for global and local rings! + return [self(x) for x in dics] + + def free_module(self, rank): + """ + Generate a free module of rank ``rank`` over ``self``. + + >>> from sympy.abc import x + >>> from sympy import QQ + >>> QQ[x].free_module(2) + QQ[x]**2 + """ + return FreeModulePolyRing(self, rank) + + +def _vector_to_sdm_helper(v, order): + """Helper method for common code in Global and Local poly rings.""" + from sympy.polys.distributedmodules import sdm_from_dict + d = {} + for i, e in enumerate(v): + for key, value in e.to_dict().items(): + d[(i,) + key] = value + return sdm_from_dict(d, order) + + +class GlobalPolynomialRing(PolynomialRingBase): + """A true polynomial ring, with objects DMP. """ + + is_Poly = True + dtype = DMP + + def from_FractionField(K1, a, K0): + """ + Convert a ``DMF`` object to ``DMP``. + + Examples + ======== + + >>> from sympy.polys.polyclasses import DMP, DMF + >>> from sympy.polys.domains import ZZ + >>> from sympy.abc import x + + >>> f = DMF(([ZZ(1), ZZ(1)], [ZZ(1)]), ZZ) + >>> K = ZZ.frac_field(x) + + >>> F = ZZ[x].from_FractionField(f, K) + + >>> F == DMP([ZZ(1), ZZ(1)], ZZ) + True + >>> type(F) + + + """ + if a.denom().is_one: + return K1.from_GlobalPolynomialRing(a.numer(), K0) + + def to_sympy(self, a): + """Convert `a` to a SymPy object. """ + return basic_from_dict(a.to_sympy_dict(), *self.gens) + + def from_sympy(self, a): + """Convert SymPy's expression to `dtype`. """ + try: + rep, _ = dict_from_basic(a, gens=self.gens) + except PolynomialError: + raise CoercionFailed("can't convert %s to type %s" % (a, self)) + + for k, v in rep.items(): + rep[k] = self.dom.from_sympy(v) + + return self(rep) + + def is_positive(self, a): + """Returns True if `LC(a)` is positive. """ + return self.dom.is_positive(a.LC()) + + def is_negative(self, a): + """Returns True if `LC(a)` is negative. """ + return self.dom.is_negative(a.LC()) + + def is_nonpositive(self, a): + """Returns True if `LC(a)` is non-positive. """ + return self.dom.is_nonpositive(a.LC()) + + def is_nonnegative(self, a): + """Returns True if `LC(a)` is non-negative. """ + return self.dom.is_nonnegative(a.LC()) + + def _vector_to_sdm(self, v, order): + """ + >>> from sympy import lex, QQ + >>> from sympy.abc import x, y + >>> R = QQ[x, y] + >>> f = R.convert(x + 2*y) + >>> g = R.convert(x * y) + >>> R._vector_to_sdm([f, g], lex) + [((1, 1, 1), 1), ((0, 1, 0), 1), ((0, 0, 1), 2)] + """ + return _vector_to_sdm_helper(v, order) + + +class GeneralizedPolynomialRing(PolynomialRingBase): + """A generalized polynomial ring, with objects DMF. """ + + dtype = DMF + + def new(self, a): + """Construct an element of `self` domain from `a`. """ + res = self.dtype(a, self.dom, len(self.gens) - 1, ring=self) + + # make sure res is actually in our ring + if res.denom().terms(order=self.order)[0][0] != (0,)*len(self.gens): + from sympy.printing.str import sstr + raise CoercionFailed("denominator %s not allowed in %s" + % (sstr(res), self)) + return res + + def __contains__(self, a): + try: + a = self.convert(a) + except CoercionFailed: + return False + return a.denom().terms(order=self.order)[0][0] == (0,)*len(self.gens) + + def from_FractionField(K1, a, K0): + dmf = K1.get_field().from_FractionField(a, K0) + return K1((dmf.num, dmf.den)) + + def to_sympy(self, a): + """Convert `a` to a SymPy object. """ + return (basic_from_dict(a.numer().to_sympy_dict(), *self.gens) / + basic_from_dict(a.denom().to_sympy_dict(), *self.gens)) + + def from_sympy(self, a): + """Convert SymPy's expression to `dtype`. """ + p, q = a.as_numer_denom() + + num, _ = dict_from_basic(p, gens=self.gens) + den, _ = dict_from_basic(q, gens=self.gens) + + for k, v in num.items(): + num[k] = self.dom.from_sympy(v) + + for k, v in den.items(): + den[k] = self.dom.from_sympy(v) + + return self((num, den)).cancel() + + def _vector_to_sdm(self, v, order): + """ + Turn an iterable into a sparse distributed module. + + Note that the vector is multiplied by a unit first to make all entries + polynomials. + + >>> from sympy import ilex, QQ + >>> from sympy.abc import x, y + >>> R = QQ.poly_ring(x, y, order=ilex) + >>> f = R.convert((x + 2*y) / (1 + x)) + >>> g = R.convert(x * y) + >>> R._vector_to_sdm([f, g], ilex) + [((0, 0, 1), 2), ((0, 1, 0), 1), ((1, 1, 1), 1), ((1, + 2, 1), 1)] + """ + # NOTE this is quite inefficient... + u = self.one.numer() + for x in v: + u *= x.denom() + return _vector_to_sdm_helper([x.numer()*u/x.denom() for x in v], order) + + +def PolynomialRing(dom, *gens, **opts): + r""" + Create a generalized multivariate polynomial ring. + + A generalized polynomial ring is defined by a ground field `K`, a set + of generators (typically `x_1, \dots, x_n`) and a monomial order `<`. + The monomial order can be global, local or mixed. In any case it induces + a total ordering on the monomials, and there exists for every (non-zero) + polynomial `f \in K[x_1, \dots, x_n]` a well-defined "leading monomial" + `LM(f) = LM(f, >)`. One can then define a multiplicative subset + `S = S_> = \{f \in K[x_1, \dots, x_n] | LM(f) = 1\}`. The generalized + polynomial ring corresponding to the monomial order is + `R = S^{-1}K[x_1, \dots, x_n]`. + + If `>` is a so-called global order, that is `1` is the smallest monomial, + then we just have `S = K` and `R = K[x_1, \dots, x_n]`. + + Examples + ======== + + A few examples may make this clearer. + + >>> from sympy.abc import x, y + >>> from sympy import QQ + + Our first ring uses global lexicographic order. + + >>> R1 = QQ.poly_ring(x, y, order=(("lex", x, y),)) + + The second ring uses local lexicographic order. Note that when using a + single (non-product) order, you can just specify the name and omit the + variables: + + >>> R2 = QQ.poly_ring(x, y, order="ilex") + + The third and fourth rings use a mixed orders: + + >>> o1 = (("ilex", x), ("lex", y)) + >>> o2 = (("lex", x), ("ilex", y)) + >>> R3 = QQ.poly_ring(x, y, order=o1) + >>> R4 = QQ.poly_ring(x, y, order=o2) + + We will investigate what elements of `K(x, y)` are contained in the various + rings. + + >>> L = [x, 1/x, y/(1 + x), 1/(1 + y), 1/(1 + x*y)] + >>> test = lambda R: [f in R for f in L] + + The first ring is just `K[x, y]`: + + >>> test(R1) + [True, False, False, False, False] + + The second ring is R1 localised at the maximal ideal (x, y): + + >>> test(R2) + [True, False, True, True, True] + + The third ring is R1 localised at the prime ideal (x): + + >>> test(R3) + [True, False, True, False, True] + + Finally the fourth ring is R1 localised at `S = K[x, y] \setminus yK[y]`: + + >>> test(R4) + [True, False, False, True, False] + """ + + order = opts.get("order", GeneralizedPolynomialRing.default_order) + if iterable(order): + order = build_product_order(order, gens) + order = monomial_key(order) + opts['order'] = order + + if order.is_global: + return GlobalPolynomialRing(dom, *gens, **opts) + else: + return GeneralizedPolynomialRing(dom, *gens, **opts) diff -Nru python3-sympy-0.7.2/sympy/polys/domains/polynomialring.py python3-sympy-0.7.3/sympy/polys/domains/polynomialring.py --- python3-sympy-0.7.2/sympy/polys/domains/polynomialring.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/polys/domains/polynomialring.py 2013-07-13 17:53:32.000000000 +0000 @@ -2,73 +2,48 @@ from sympy.polys.domains.ring import Ring from sympy.polys.domains.compositedomain import CompositeDomain -from sympy.polys.domains.characteristiczero import CharacteristicZero -from sympy.polys.domains.fractionfield import FractionField +from sympy.polys.polyerrors import CoercionFailed, GeneratorsError -from sympy.polys.polyclasses import DMP, DMF -from sympy.polys.polyerrors import (GeneratorsNeeded, PolynomialError, - CoercionFailed, ExactQuotientFailed, NotReversible) -from sympy.polys.polyutils import dict_from_basic, basic_from_dict, _dict_reorder +class PolynomialRing(Ring, CompositeDomain): + """A class for representing multivariate polynomial rings. """ -from sympy.polys.monomialtools import monomial_key, build_product_order - -from sympy.polys.agca.modules import FreeModulePolyRing - -from sympy.core.compatibility import iterable - -# XXX why does this derive from CharacteristicZero??? -class PolynomialRingBase(Ring, CharacteristicZero, CompositeDomain): - """ - Base class for generalized polynomial rings. - - This base class should be used for uniform access to generalized polynomial - rings. Subclasses only supply information about the element storage etc. - - Do not instantiate. - """ + is_Poly = True has_assoc_Ring = True has_assoc_Field = True - default_order = "grevlex" + def __init__(self, ring): + self.dtype = ring.dtype + self.ring = ring - def __init__(self, dom, *gens, **opts): - if not gens: - raise GeneratorsNeeded("generators not specified") + self.dom = ring.domain + self.gens = ring.symbols - lev = len(gens) - 1 + self.zero = ring.zero + self.one = ring.one - self.zero = self.dtype.zero(lev, dom, ring=self) - self.one = self.dtype.one(lev, dom, ring=self) - self.dom = dom - self.gens = gens - # NOTE 'order' may not be set if inject was called through CompositeDomain - self.order = opts.get('order', monomial_key(self.default_order)) + def new(self, element): + return self.ring.ring_new(element) def __str__(self): - s_order = str(self.order) - orderstr = (" order=" + s_order) if s_order != self.default_order else "" - return str(self.dom) + '[' + ','.join(map(str, self.gens)) + orderstr + ']' + return str(self.dom) + '[' + ','.join(map(str, self.gens)) + ']' def __hash__(self): - return hash((self.__class__.__name__, self.dtype, self.dom, - self.gens, self.order)) - - def __call__(self, a): - """Construct an element of `self` domain from `a`. """ - return self.dtype(a, self.dom, len(self.gens)-1, ring=self) + return hash((self.__class__.__name__, self.dtype, self.dom, self.gens)) def __eq__(self, other): """Returns `True` if two domains are equivalent. """ - if not isinstance(other, PolynomialRingBase): - return False - return self.dtype == other.dtype and self.dom == other.dom and \ - self.gens == other.gens and self.order == other.order - - def __ne__(self, other): - """Returns `False` if two domains are equivalent. """ - return not self.__eq__(other) + return isinstance(other, PolynomialRing) and \ + self.dtype == other.dtype and self.ring == other.ring + + def to_sympy(self, a): + """Convert `a` to a SymPy object. """ + return a.as_expr() + + def from_sympy(self, a): + """Convert SymPy's expression to `dtype`. """ + return self.ring.from_expr(a) def from_ZZ_python(K1, a, K0): """Convert a Python `int` object to `dtype`. """ @@ -78,14 +53,6 @@ """Convert a Python `Fraction` object to `dtype`. """ return K1(K1.dom.convert(a, K0)) - def from_ZZ_sympy(K1, a, K0): - """Convert a SymPy `Integer` object to `dtype`. """ - return K1(K1.dom.convert(a, K0)) - - def from_QQ_sympy(K1, a, K0): - """Convert a SymPy `Rational` object to `dtype`. """ - return K1(K1.dom.convert(a, K0)) - def from_ZZ_gmpy(K1, a, K0): """Convert a GMPY `mpz` object to `dtype`. """ return K1(K1.dom.convert(a, K0)) @@ -94,51 +61,58 @@ """Convert a GMPY `mpq` object to `dtype`. """ return K1(K1.dom.convert(a, K0)) - def from_RR_sympy(K1, a, K0): - """Convert a SymPy `Real` object to `dtype`. """ - return K1(K1.dom.convert(a, K0)) - def from_RR_mpmath(K1, a, K0): """Convert a mpmath `mpf` object to `dtype`. """ return K1(K1.dom.convert(a, K0)) def from_AlgebraicField(K1, a, K0): - """Convert a `ANP` object to `dtype`. """ + """Convert an algebraic number to ``dtype``. """ if K1.dom == K0: - return K1(a) + return K1.new(a) - def from_GlobalPolynomialRing(K1, a, K0): - """Convert a `DMP` object to `dtype`. """ - if K1.gens == K0.gens: - if K1.dom == K0.dom: - return K1(a.rep) # set the correct ring - else: - return K1(a.convert(K1.dom).rep) - else: - monoms, coeffs = _dict_reorder(a.to_dict(), K0.gens, K1.gens) - - if K1.dom != K0.dom: - coeffs = [ K1.dom.convert(c, K0.dom) for c in coeffs ] + def from_PolynomialRing(K1, a, K0): + """Convert a polynomial to ``dtype``. """ + try: + return a.set_ring(K1.ring) + except (CoercionFailed, GeneratorsError): + return None - return K1(dict(list(zip(monoms, coeffs)))) + def from_FractionField(K1, a, K0): + """Convert a rational function to ``dtype``. """ + if K0.denom(a) == 1: + return K1.from_PolynomialRing(K0.numer(a), K0.field.ring.to_domain()) + else: + return None def get_field(self): """Returns a field associated with `self`. """ - return FractionField(self.dom, *self.gens) + return self.ring.to_field().to_domain() - def poly_ring(self, *gens): + def poly_ring(self, *symbols): # TODO:, order=lex): """Returns a polynomial ring, i.e. `K[X]`. """ - raise NotImplementedError('nested domains not allowed') + from sympy.polys.rings import PolyRing + return PolyRing(symbols, self.ring, order).to_domain() - def frac_field(self, *gens): + def frac_field(self, *symbols): # TODO:, order=lex): """Returns a fraction field, i.e. `K(X)`. """ - raise NotImplementedError('nested domains not allowed') + from sympy.polys.fields import FracField + return FracField(symbols, self.ring, order).to_domain() - def revert(self, a): - try: - return 1/a - except (ExactQuotientFailed, ZeroDivisionError): - raise NotReversible('%s is not a unit' % a) + def is_positive(self, a): + """Returns True if `LC(a)` is positive. """ + return self.dom.is_positive(a.LC) + + def is_negative(self, a): + """Returns True if `LC(a)` is negative. """ + return self.dom.is_negative(a.LC) + + def is_nonpositive(self, a): + """Returns True if `LC(a)` is non-positive. """ + return self.dom.is_nonpositive(a.LC) + + def is_nonnegative(self, a): + """Returns True if `LC(a)` is non-negative. """ + return self.dom.is_nonnegative(a.LC) def gcdex(self, a, b): """Extended GCD of `a` and `b`. """ @@ -155,281 +129,3 @@ def factorial(self, a): """Returns factorial of `a`. """ return self.dtype(self.dom.factorial(a)) - - def _vector_to_sdm(self, v, order): - """ - For internal use by the modules class. - - Convert an iterable of elements of this ring into a sparse distributed - module element. - """ - raise NotImplementedError - - def _sdm_to_dics(self, s, n): - """Helper for _sdm_to_vector.""" - from sympy.polys.distributedmodules import sdm_to_dict - dic = sdm_to_dict(s) - res = [{} for _ in range(n)] - for k, v in dic.items(): - res[k[0]][k[1:]] = v - return res - - def _sdm_to_vector(self, s, n): - """ - For internal use by the modules class. - - Convert a sparse distributed module into a list of length ``n``. - - >>> from sympy import QQ, ilex - >>> from sympy.abc import x, y - >>> R = QQ.poly_ring(x, y, order=ilex) - >>> L = [((1, 1, 1), QQ(1)), ((0, 1, 0), QQ(1)), ((0, 0, 1), QQ(2))] - >>> R._sdm_to_vector(L, 2) - [x + 2*y, x*y] - """ - dics = self._sdm_to_dics(s, n) - # NOTE this works for global and local rings! - return [self(x) for x in dics] - - def free_module(self, rank): - """ - Generate a free module of rank ``rank`` over ``self``. - - >>> from sympy.abc import x - >>> from sympy import QQ - >>> QQ[x].free_module(2) - QQ[x]**2 - """ - return FreeModulePolyRing(self, rank) - -def _vector_to_sdm_helper(v, order): - """Helper method for common code in Global and Local poly rings.""" - from sympy.polys.distributedmodules import sdm_from_dict - d = {} - for i, e in enumerate(v): - for key, value in e.to_dict().items(): - d[(i,) + key] = value - return sdm_from_dict(d, order) - -class GlobalPolynomialRing(PolynomialRingBase): - """A true polynomial ring, with objects DMP. """ - - is_Poly = True - dtype = DMP - - def from_FractionField(K1, a, K0): - """ - Convert a ``DMF`` object to ``DMP``. - - Examples - ======== - - >>> from sympy.polys.polyclasses import DMP, DMF - >>> from sympy.polys.domains import ZZ - >>> from sympy.abc import x - - >>> f = DMF(([ZZ(1), ZZ(1)], [ZZ(1)]), ZZ) - >>> K = ZZ.frac_field(x) - - >>> F = ZZ[x].from_FractionField(f, K) - - >>> F == DMP([ZZ(1), ZZ(1)], ZZ) - True - >>> type(F) - - - """ - if a.denom().is_one: - return K1.from_GlobalPolynomialRing(a.numer(), K0) - - def to_sympy(self, a): - """Convert `a` to a SymPy object. """ - return basic_from_dict(a.to_sympy_dict(), *self.gens) - - def from_sympy(self, a): - """Convert SymPy's expression to `dtype`. """ - try: - rep, _ = dict_from_basic(a, gens=self.gens) - except PolynomialError: - raise CoercionFailed("can't convert %s to type %s" % (a, self)) - - for k, v in rep.items(): - rep[k] = self.dom.from_sympy(v) - - return self(rep) - - def is_positive(self, a): - """Returns True if `LC(a)` is positive. """ - return self.dom.is_positive(a.LC()) - - def is_negative(self, a): - """Returns True if `LC(a)` is negative. """ - return self.dom.is_negative(a.LC()) - - def is_nonpositive(self, a): - """Returns True if `LC(a)` is non-positive. """ - return self.dom.is_nonpositive(a.LC()) - - def is_nonnegative(self, a): - """Returns True if `LC(a)` is non-negative. """ - return self.dom.is_nonnegative(a.LC()) - - def _vector_to_sdm(self, v, order): - """ - >>> from sympy import lex, QQ - >>> from sympy.abc import x, y - >>> R = QQ[x, y] - >>> f = R.convert(x + 2*y) - >>> g = R.convert(x * y) - >>> R._vector_to_sdm([f, g], lex) - [((1, 1, 1), 1/1), ((0, 1, 0), 1/1), ((0, 0, 1), 2/1)] - """ - return _vector_to_sdm_helper(v, order) - -class GeneralizedPolynomialRing(PolynomialRingBase): - """A generalized polynomial ring, with objects DMF. """ - - dtype = DMF - - def __call__(self, a): - """Construct an element of `self` domain from `a`. """ - res = self.dtype(a, self.dom, len(self.gens)-1, ring=self) - - # make sure res is actually in our ring - if res.denom().terms(order=self.order)[0][0] != (0,)*len(self.gens): - from sympy.printing.str import sstr - raise CoercionFailed("denominator %s not allowed in %s" \ - % (sstr(res), self)) - return res - - def __contains__(self, a): - try: - a = self.convert(a) - except CoercionFailed: - return False - return a.denom().terms(order=self.order)[0][0] == (0,)*len(self.gens) - - def from_FractionField(K1, a, K0): - dmf = K1.get_field().from_FractionField(a, K0) - return K1((dmf.num, dmf.den)) - - def to_sympy(self, a): - """Convert `a` to a SymPy object. """ - return (basic_from_dict(a.numer().to_sympy_dict(), *self.gens) / - basic_from_dict(a.denom().to_sympy_dict(), *self.gens)) - - def from_sympy(self, a): - """Convert SymPy's expression to `dtype`. """ - p, q = a.as_numer_denom() - - num, _ = dict_from_basic(p, gens=self.gens) - den, _ = dict_from_basic(q, gens=self.gens) - - for k, v in num.items(): - num[k] = self.dom.from_sympy(v) - - for k, v in den.items(): - den[k] = self.dom.from_sympy(v) - - return self((num, den)).cancel() - - def _vector_to_sdm(self, v, order): - """ - Turn an iterable into a sparse distributed module. - - Note that the vector is multiplied by a unit first to make all entries - polynomials. - - >>> from sympy import ilex, QQ - >>> from sympy.abc import x, y - >>> R = QQ.poly_ring(x, y, order=ilex) - >>> f = R.convert((x + 2*y) / (1 + x)) - >>> g = R.convert(x * y) - >>> R._vector_to_sdm([f, g], ilex) - [((0, 0, 1), 2/1), ((0, 1, 0), 1/1), ((1, 1, 1), 1/1), ((1, 2, 1), 1/1)] - """ - # NOTE this is quite inefficient... - u = self.one.numer() - for x in v: - u *= x.denom() - return _vector_to_sdm_helper([x.numer()*u/x.denom() for x in v], order) - -def PolynomialRing(dom, *gens, **opts): - r""" - Create a generalized multivariate polynomial ring. - - A generalized polynomial ring is defined by a ground field `K`, a set - of generators (typically `x_1, \dots, x_n`) and a monomial order `<`. - The monomial order can be global, local or mixed. In any case it induces - a total ordering on the monomials, and there exists for every (non-zero) - polynomial `f \in K[x_1, \dots, x_n]` a well-defined "leading monomial" - `LM(f) = LM(f, >)`. One can then define a multiplicative subset - `S = S_> = \{f \in K[x_1, \dots, x_n] | LM(f) = 1\}`. The generalized - polynomial ring corresponding to the monomial order is - `R = S^{-1}K[x_1, \dots, x_n]`. - - If `>` is a so-called global order, that is `1` is the smallest monomial, - then we just have `S = K` and `R = K[x_1, \dots, x_n]`. - - Examples - ======== - - A few examples may make this clearer. - - >>> from sympy.abc import x, y - >>> from sympy import QQ - - Our first ring uses global lexicographic order. - - >>> R1 = QQ.poly_ring(x, y, order=(("lex", x, y),)) - - The second ring uses local lexicographic order. Note that when using a - single (non-product) order, you can just specify the name and omit the - variables: - - >>> R2 = QQ.poly_ring(x, y, order="ilex") - - The third and fourth rings use a mixed orders: - - >>> o1 = (("ilex", x), ("lex", y)) - >>> o2 = (("lex", x), ("ilex", y)) - >>> R3 = QQ.poly_ring(x, y, order=o1) - >>> R4 = QQ.poly_ring(x, y, order=o2) - - We will investigate what elements of `K(x, y)` are contained in the various - rings. - - >>> L = [x, 1/x, y/(1 + x), 1/(1 + y), 1/(1 + x*y)] - >>> test = lambda R: [f in R for f in L] - - The first ring is just `K[x, y]`: - - >>> test(R1) - [True, False, False, False, False] - - The second ring is R1 localised at the maximal ideal (x, y): - - >>> test(R2) - [True, False, True, True, True] - - The third ring is R1 localised at the prime ideal (x): - - >>> test(R3) - [True, False, True, False, True] - - Finally the fourth ring is R1 localised at `S = K[x, y] \setminus yK[y]`: - - >>> test(R4) - [True, False, False, True, False] - """ - - order = opts.get("order", GeneralizedPolynomialRing.default_order) - if iterable(order): - order = build_product_order(order, gens) - order = monomial_key(order) - opts['order'] = order - - if order.is_global: - return GlobalPolynomialRing(dom, *gens, **opts) - else: - return GeneralizedPolynomialRing(dom, *gens, **opts) diff -Nru python3-sympy-0.7.2/sympy/polys/domains/pythoncomplexdomain.py python3-sympy-0.7.3/sympy/polys/domains/pythoncomplexdomain.py --- python3-sympy-0.7.2/sympy/polys/domains/pythoncomplexdomain.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/polys/domains/pythoncomplexdomain.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,72 +0,0 @@ -"""Implementation of :class:`PythonComplexDomain` class. """ - -from sympy.polys.domains.realdomain import RealDomain - -from sympy.polys.polyerrors import CoercionFailed - -class PythonComplexDomain(RealDomain): # XXX: tmp solution - """Complex domain. """ - - rep = 'CC' - - dtype = complex - zero = dtype(0) - one = dtype(1) - alias = 'CC_python' - - def __init__(self): - pass - - def to_sympy(self, a): - """Convert `a` to a SymPy object. """ - return sympy_mpf(a) - - def from_sympy(self, a): - """Convert SymPy's Integer to `dtype`. """ - b = a.evalf() - - if b.is_Float and b not in [S.Infinity, S.NegativeInfinity]: - return float(b) - else: - raise CoercionFailed("expected Float object, got %s" % a) - - def from_ZZ_python(K1, a, K0): - """Convert a Python `int` object to `dtype`. """ - return K1.dtype(a) - - def from_QQ_python(K1, a, K0): - """Convert a Python `Fraction` object to `dtype`. """ - return K1.dtype(a.numerator) / a.denominator - - def from_ZZ_sympy(K1, a, K0): - """Convert a SymPy `Integer` object to `dtype`. """ - return K1.dtype(a.p) - - def from_QQ_sympy(K1, a, K0): - """Convert a SymPy `Rational` object to `dtype`. """ - return K1.dtype(a.p) / a.q - - def from_ZZ_gmpy(K1, a, K0): - """Convert a GMPY `mpz` object to `dtype`. """ - return K1.dtype(int(a)) - - def from_QQ_gmpy(K1, a, K0): - """Convert a GMPY `mpq` object to `dtype`. """ - return K1.dtype(int(a.numer())) / int(a.denom) - - def from_RR_sympy(K1, a, K0): - """Convert a SymPy `Float` object to `dtype`. """ - return K1.dtype(a) - - def from_RR_mpmath(K1, a, K0): - """Convert a mpmath `mpf` object to `dtype`. """ - return K1.dtype(a) - - def from_FF_float(K1, a, K0): - return K1.dtype(a) - - def real(self, a): - return a.real - - def imag(self, a): - return a.imag diff -Nru python3-sympy-0.7.2/sympy/polys/domains/pythonfinitefield.py python3-sympy-0.7.3/sympy/polys/domains/pythonfinitefield.py --- python3-sympy-0.7.2/sympy/polys/domains/pythonfinitefield.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/polys/domains/pythonfinitefield.py 2013-07-13 17:53:32.000000000 +0000 @@ -3,6 +3,7 @@ from sympy.polys.domains.finitefield import FiniteField from sympy.polys.domains.pythonintegerring import PythonIntegerRing + class PythonFiniteField(FiniteField): """Finite field based on Python's integers. """ diff -Nru python3-sympy-0.7.2/sympy/polys/domains/pythonintegerring.py python3-sympy-0.7.3/sympy/polys/domains/pythonintegerring.py --- python3-sympy-0.7.2/sympy/polys/domains/pythonintegerring.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/polys/domains/pythonintegerring.py 2013-07-13 17:53:32.000000000 +0000 @@ -3,18 +3,19 @@ from sympy.polys.domains.integerring import IntegerRing from sympy.polys.domains.groundtypes import ( - PythonIntegerType, SymPyIntegerType, python_sqrt, + PythonInteger, SymPyInteger, python_sqrt, python_factorial, python_gcdex, python_gcd, python_lcm, ) from sympy.polys.polyerrors import CoercionFailed + class PythonIntegerRing(IntegerRing): """Integer ring based on Python's ``int`` type. """ - dtype = PythonIntegerType - zero = dtype(0) - one = dtype(1) + dtype = PythonInteger + zero = dtype(0) + one = dtype(1) alias = 'ZZ_python' def __init__(self): @@ -22,14 +23,14 @@ def to_sympy(self, a): """Convert ``a`` to a SymPy object. """ - return SymPyIntegerType(a) + return SymPyInteger(a) def from_sympy(self, a): """Convert SymPy's Integer to ``dtype``. """ if a.is_Integer: - return PythonIntegerType(a.p) + return PythonInteger(a.p) elif a.is_Float and int(a) == a: - return PythonIntegerType(int(a)) + return PythonInteger(int(a)) else: raise CoercionFailed("expected an integer, got %s" % a) @@ -46,45 +47,25 @@ if a.denominator == 1: return a.numerator - def from_FF_sympy(K1, a, K0): - """Convert ``ModularInteger(Integer)`` to Python's ``int``. """ - return a.to_int().p - - def from_ZZ_sympy(K1, a, K0): - """Convert SymPy's ``Integer`` to Python's ``int``. """ - return a.p - - def from_QQ_sympy(K1, a, K0): - """Convert SymPy's ``Rational`` to Python's ``int``. """ - if a.q == 1: - return a.p - def from_FF_gmpy(K1, a, K0): """Convert ``ModularInteger(mpz)`` to Python's ``int``. """ - return PythonIntegerType(a.to_int()) + return PythonInteger(a.to_int()) def from_ZZ_gmpy(K1, a, K0): """Convert GMPY's ``mpz`` to Python's ``int``. """ - return PythonIntegerType(a) + return PythonInteger(a) def from_QQ_gmpy(K1, a, K0): """Convert GMPY's ``mpq`` to Python's ``int``. """ if a.denom() == 1: - return PythonIntegerType(a.numer()) - - def from_RR_sympy(K1, a, K0): - """Convert SymPy's ``Float`` to Python's ``int``. """ - p, q = K0.as_integer_ratio(a) - - if q == 1: - return PythonIntegerType(p) + return PythonInteger(a.numer()) def from_RR_mpmath(K1, a, K0): """Convert mpmath's ``mpf`` to Python's ``int``. """ p, q = K0.as_integer_ratio(a) if q == 1: - return PythonIntegerType(p) + return PythonInteger(p) def gcdex(self, a, b): """Compute extended GCD of ``a`` and ``b``. """ diff -Nru python3-sympy-0.7.2/sympy/polys/domains/pythonrational.py python3-sympy-0.7.3/sympy/polys/domains/pythonrational.py --- python3-sympy-0.7.2/sympy/polys/domains/pythonrational.py 1970-01-01 00:00:00.000000000 +0000 +++ python3-sympy-0.7.3/sympy/polys/domains/pythonrational.py 2013-07-13 17:53:32.000000000 +0000 @@ -0,0 +1,226 @@ +"""Rational number type based on Python integers. """ + +from sympy.core.numbers import igcd +from sympy.printing.defaults import DefaultPrinting +from sympy.polys.polyutils import PicklableWithSlots +from sympy.polys.domains.domainelement import DomainElement + +import operator + +class PythonRational(DefaultPrinting, PicklableWithSlots, DomainElement): + """ + Rational number type based on Python integers. + + This was supposed to be needed for compatibility with older Python + versions which don't support Fraction. However, Fraction is very + slow so we don't use it anyway. + + Examples + ======== + + >>> from sympy.polys.domains import PythonRational + + >>> PythonRational(1) + 1 + >>> PythonRational(2, 3) + 2/3 + >>> PythonRational(14, 10) + 7/5 + + """ + + __slots__ = ['p', 'q'] + + def parent(self): + from sympy.polys.domains import PythonRationalField + return PythonRationalField() + + def __init__(self, p, q=None): + if q is None: + self.p = p + self.q = 1 + else: + if not q: + raise ZeroDivisionError('rational number') + elif q < 0: + p, q = -p, -q + + g = igcd(p, q) + + self.p = p//g + self.q = q//g + + @classmethod + def new(cls, p, q): + obj = object.__new__(cls) + obj.p = p + obj.q = q + return obj + + def __hash__(self): + if self.q == 1: + return hash(self.p) + else: + return hash((self.p, self.q)) + + def __int__(self): + return int(float(self.p)/self.q) + + def __float__(self): + return float(self.p)/self.q + + def __abs__(self): + return self.new(abs(self.p), self.q) + + def __pos__(self): + return self.new(+self.p, self.q) + + def __neg__(self): + return self.new(-self.p, self.q) + + def __add__(self, other): + if isinstance(other, PythonRational): + p = self.p*other.q + self.q*other.p + q = self.q*other.q + elif isinstance(other, int): + p = self.p + self.q*other + q = self.q + else: + return NotImplemented + + return self.__class__(p, q) + + def __radd__(self, other): + if not isinstance(other, int): + return NotImplemented + + p = self.p + self.q*other + q = self.q + + return self.__class__(p, q) + + def __sub__(self, other): + if isinstance(other, PythonRational): + p = self.p*other.q - self.q*other.p + q = self.q*other.q + elif isinstance(other, int): + p = self.p - self.q*other + q = self.q + else: + return NotImplemented + + return self.__class__(p, q) + + def __rsub__(self, other): + if not isinstance(other, int): + return NotImplemented + + p = self.q*other - self.p + q = self.q + + return self.__class__(p, q) + + def __mul__(self, other): + if isinstance(other, PythonRational): + p = self.p*other.p + q = self.q*other.q + elif isinstance(other, int): + p = self.p*other + q = self.q + else: + return NotImplemented + + return self.__class__(p, q) + + def __rmul__(self, other): + if not isinstance(other, int): + return NotImplemented + + p = self.p*other + q = self.q + + return self.__class__(p, q) + + def __div__(self, other): + if isinstance(other, PythonRational): + p = self.p*other.q + q = self.q*other.p + elif isinstance(other, int): + p = self.p + q = self.q*other + else: + return NotImplemented + + return self.__class__(p, q) + + __truediv__ = __div__ + + def __rdiv__(self, other): + if not isinstance(other, int): + return NotImplemented + + p = self.q*other + q = self.p + + return self.__class__(p, q) + + __rtruediv__ = __rdiv__ + + def __mod__(self, other): + return self.__class__(0) + + def __divmod__(self, other): + return (self//other, self % other) + + def __pow__(self, exp): + p, q = self.p, self.q + + if exp < 0: + p, q, exp = q, p, -exp + + return self.new(p**exp, q**exp) + + def __bool__(self): + return self.p != 0 + + def __eq__(self, other): + if isinstance(other, PythonRational): + return self.q == other.q and self.p == other.p + elif isinstance(other, int): + return self.q == 1 and self.p == other + else: + return False + + def __ne__(self, other): + return not self.__eq__(other) + + def _cmp(self, other, op): + try: + diff = self - other + except TypeError: + return NotImplemented + else: + return op(diff.p, 0) + + def __lt__(self, other): + return self._cmp(other, operator.lt) + + def __le__(self, other): + return self._cmp(other, operator.le) + + def __gt__(self, other): + return self._cmp(other, operator.gt) + + def __ge__(self, other): + return self._cmp(other, operator.ge) + + @property + def numer(self): + return self.p + + @property + def denom(self): + return self.q + + numerator = numer + denominator = denom diff -Nru python3-sympy-0.7.2/sympy/polys/domains/pythonrationalfield.py python3-sympy-0.7.3/sympy/polys/domains/pythonrationalfield.py --- python3-sympy-0.7.2/sympy/polys/domains/pythonrationalfield.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/polys/domains/pythonrationalfield.py 2013-07-13 17:53:32.000000000 +0000 @@ -2,69 +2,62 @@ from sympy.polys.domains.rationalfield import RationalField -from sympy.polys.domains.groundtypes import PythonIntegerType -from sympy.polys.domains.groundtypes import PythonRationalType -from sympy.polys.domains.groundtypes import SymPyRationalType +from sympy.polys.domains.groundtypes import PythonInteger +from sympy.polys.domains.groundtypes import PythonRational +from sympy.polys.domains.groundtypes import SymPyRational from sympy.polys.polyerrors import CoercionFailed class PythonRationalField(RationalField): """Rational field based on Python rational number type. """ - dtype = PythonRationalType - zero = dtype(0) - one = dtype(1) + dtype = PythonRational + zero = dtype(0) + one = dtype(1) alias = 'QQ_python' def __init__(self): pass + def get_ring(self): + """Returns ring associated with ``self``. """ + from sympy.polys.domains import PythonIntegerRing + return PythonIntegerRing() + def to_sympy(self, a): """Convert `a` to a SymPy object. """ - return SymPyRationalType(a.numerator, a.denominator) + return SymPyRational(a.numerator, a.denominator) def from_sympy(self, a): """Convert SymPy's Rational to `dtype`. """ if a.is_Rational: - return PythonRationalType(a.p, a.q) + return PythonRational(a.p, a.q) elif a.is_Float: from sympy.polys.domains import RR - return PythonRationalType(*RR.as_integer_ratio(a)) + return PythonRational(*RR.as_integer_ratio(a)) else: raise CoercionFailed("expected `Rational` object, got %s" % a) def from_ZZ_python(K1, a, K0): """Convert a Python `int` object to `dtype`. """ - return PythonRationalType(a) + return PythonRational(a) def from_QQ_python(K1, a, K0): """Convert a Python `Fraction` object to `dtype`. """ return a - def from_ZZ_sympy(K1, a, K0): - """Convert a SymPy `Integer` object to `dtype`. """ - return PythonRationalType(a.p) - - def from_QQ_sympy(K1, a, K0): - """Convert a SymPy `Rational` object to `dtype`. """ - return PythonRationalType(a.p, a.q) - def from_ZZ_gmpy(K1, a, K0): """Convert a GMPY `mpz` object to `dtype`. """ - return PythonRationalType(PythonIntegerType(a)) + return PythonRational(PythonInteger(a)) def from_QQ_gmpy(K1, a, K0): """Convert a GMPY `mpq` object to `dtype`. """ - return PythonRationalType(PythonIntegerType(a.numer()), - PythonIntegerType(a.denom())) - - def from_RR_sympy(K1, a, K0): - """Convert a SymPy `Float` object to `dtype`. """ - return PythonRationalType(*K0.as_integer_ratio(a)) + return PythonRational(PythonInteger(a.numer()), + PythonInteger(a.denom())) def from_RR_mpmath(K1, a, K0): """Convert a mpmath `mpf` object to `dtype`. """ - return PythonRationalType(*K0.as_integer_ratio(a)) + return PythonRational(*K0.as_integer_ratio(a)) def numer(self, a): """Returns numerator of `a`. """ diff -Nru python3-sympy-0.7.2/sympy/polys/domains/pythonrationaltype.py python3-sympy-0.7.3/sympy/polys/domains/pythonrationaltype.py --- python3-sympy-0.7.2/sympy/polys/domains/pythonrationaltype.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/polys/domains/pythonrationaltype.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,222 +0,0 @@ -"""Rational number type based on Python integers. """ - -from sympy.core.numbers import igcd -from sympy.polys.polyutils import PicklableWithSlots - -import operator - -class PythonRationalType(PicklableWithSlots): - """ - Rational number type based on Python integers. - - Examples - ======== - - >>> from sympy.polys.domains import PythonRationalType - - >>> PythonRationalType(1) - 1/1 - >>> PythonRationalType(2, 3) - 2/3 - >>> PythonRationalType(14, 10) - 7/5 - - """ - - __slots__ = ['p', 'q'] - - def __init__(self, p, q=None): - if q is None: - self.p = p - self.q = 1 - else: - if not q: - raise ZeroDivisionError('rational number') - elif q < 0: - p, q = -p, -q - - g = igcd(p, q) - - self.p = p//g - self.q = q//g - - @classmethod - def new(cls, p, q): - obj = object.__new__(cls) - obj.p = p - obj.q = q - return obj - - def __hash__(self): - if self.q == 1: - return hash(self.p) - else: - return hash((self.p, self.q)) - - def __repr__(self): - return "%s(%d, %d)" % (self.__class__.__name__, self.p, self.q) - - def __str__(self): - return "%d/%d" % (self.p, self.q) - - def __int__(self): - return int(float(self.p)/self.q) - - def __float__(self): - return float(self.p)/self.q - - def __abs__(self): - return self.new(abs(self.p), self.q) - - def __pos__(self): - return self.new(+self.p, self.q) - - def __neg__(self): - return self.new(-self.p, self.q) - - def __add__(self, other): - if isinstance(other, PythonRationalType): - p = self.p*other.q + self.q*other.p - q = self.q*other.q - elif isinstance(other, int): - p = self.p + self.q*other - q = self.q - else: - return NotImplemented - - return self.__class__(p, q) - - def __radd__(self, other): - if not isinstance(other, int): - return NotImplemented - - p = self.p + self.q*other - q = self.q - - return self.__class__(p, q) - - def __sub__(self, other): - if isinstance(other, PythonRationalType): - p = self.p*other.q - self.q*other.p - q = self.q*other.q - elif isinstance(other, int): - p = self.p - self.q*other - q = self.q - else: - return NotImplemented - - return self.__class__(p, q) - - def __rsub__(self, other): - if not isinstance(other, int): - return NotImplemented - - p = self.q*other - self.p - q = self.q - - return self.__class__(p, q) - - def __mul__(self, other): - if isinstance(other, PythonRationalType): - p = self.p*other.p - q = self.q*other.q - elif isinstance(other, int): - p = self.p*other - q = self.q - else: - return NotImplemented - - return self.__class__(p, q) - - def __rmul__(self, other): - if not isinstance(other, int): - return NotImplemented - - p = self.p*other - q = self.q - - return self.__class__(p, q) - - def __div__(self, other): - if isinstance(other, PythonRationalType): - p = self.p*other.q - q = self.q*other.p - elif isinstance(other, int): - p = self.p - q = self.q*other - else: - return NotImplemented - - return self.__class__(p, q) - - __truediv__ = __div__ - - def __rdiv__(self, other): - if not isinstance(other, int): - return NotImplemented - - p = self.q*other - q = self.p - - return self.__class__(p, q) - - __rtruediv__ = __rdiv__ - - def __mod__(self, other): - return self.__class__(0) - - def __divmod__(self, other): - return (self//other, self%other) - - def __pow__(self, exp): - p, q = self.p, self.q - - if exp < 0: - p, q, exp = q, p, -exp - - return self.new(p**exp, q**exp) - - def __bool__(self): - return self.p != 0 - - def __eq__(self, other): - if isinstance(other, PythonRationalType): - return self.q == other.q and self.p == other.p - elif isinstance(other, int): - return self.q == 1 and self.p == other - else: - return False - - def __ne__(self, other): - return not self.__eq__(other) - - def _cmp(self, other, op): - try: - diff = self - other - except TypeError: - return NotImplemented - else: - return op(diff.p, 0) - - def __lt__(self, other): - return self._cmp(other, operator.lt) - - def __le__(self, other): - return self._cmp(other, operator.le) - - def __gt__(self, other): - return self._cmp(other, operator.gt) - - def __ge__(self, other): - return self._cmp(other, operator.ge) - - @property - def numer(self): - return self.p - - @property - def denom(self): - return self.q - - numerator = numer - denominator = denom diff -Nru python3-sympy-0.7.2/sympy/polys/domains/pythonrealdomain.py python3-sympy-0.7.3/sympy/polys/domains/pythonrealdomain.py --- python3-sympy-0.7.2/sympy/polys/domains/pythonrealdomain.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/polys/domains/pythonrealdomain.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,75 +0,0 @@ -"""Implementation of :class:`PythonRealDomain` class. """ - -from sympy.polys.domains.realdomain import RealDomain -from sympy.polys.polyerrors import CoercionFailed - -from sympy.core import S - -class PythonRealDomain(RealDomain): # XXX: tmp solution - """Float domain. """ - - rep = 'RR' - - is_FF = True - - dtype = float - zero = dtype(0) - one = dtype(1) - alias = 'RR_python' - - def __init__(self): - pass - - def normal(self, a): - if abs(a) < 1e-15: - return self.zero - else: - return self.dtype(a) - - def to_sympy(self, a): - """Convert `a` to a SymPy object. """ - return sympy_mpf(a) - - def from_sympy(self, a): - """Convert SymPy's Integer to `dtype`. """ - b = a.evalf() - - if b.is_Float and b not in [S.Infinity, S.NegativeInfinity]: - return float(b) - else: - raise CoercionFailed("expected Float object, got %s" % a) - - def from_ZZ_python(K1, a, K0): - """Convert a Python `int` object to `dtype`. """ - return K1.dtype(a) - - def from_QQ_python(K1, a, K0): - """Convert a Python `Fraction` object to `dtype`. """ - return K1.dtype(a.numerator) / a.denominator - - def from_ZZ_sympy(K1, a, K0): - """Convert a SymPy `Integer` object to `dtype`. """ - return K1.dtype(a.p) - - def from_QQ_sympy(K1, a, K0): - """Convert a SymPy `Rational` object to `dtype`. """ - return K1.dtype(a.p) / a.q - - def from_ZZ_gmpy(K1, a, K0): - """Convert a GMPY `mpz` object to `dtype`. """ - return K1.dtype(int(a)) - - def from_QQ_gmpy(K1, a, K0): - """Convert a GMPY `mpq` object to `dtype`. """ - return K1.dtype(int(a.numer())) / int(a.denom) - - def from_RR_sympy(K1, a, K0): - """Convert a SymPy `Float` object to `dtype`. """ - return K1.dtype(a) - - def from_RR_mpmath(K1, a, K0): - """Convert a mpmath `mpf` object to `dtype`. """ - return K1.dtype(a) - - def complex_domain(self): - return CC diff -Nru python3-sympy-0.7.2/sympy/polys/domains/quotientring.py python3-sympy-0.7.3/sympy/polys/domains/quotientring.py --- python3-sympy-0.7.2/sympy/polys/domains/quotientring.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/polys/domains/quotientring.py 2013-07-13 17:53:32.000000000 +0000 @@ -9,6 +9,7 @@ # - poly rings over quotients? # - division by non-units in integral domains? + class QuotientRingElement(object): """ Class representing elements of (commutative) quotient rings. @@ -82,12 +83,13 @@ def __ne__(self, om): return not self.__eq__(om) + class QuotientRing(Ring): """ Class representing (commutative) quotient rings. - You should not usually instatiate this by hand, instead use the constructor - from the ring you are quotienting out by: + You should not usually instantiate this by hand, instead use the constructor + from the base ring in the construction. >>> from sympy.abc import x >>> from sympy import QQ @@ -106,10 +108,10 @@ Attributes: - ring - the base ring - - base_ideal - the ideal we are quotienting by + - base_ideal - the ideal used to form the quotient """ - has_assoc_Ring = True + has_assoc_Ring = True has_assoc_Field = False dtype = QuotientRingElement @@ -127,7 +129,7 @@ def __hash__(self): return hash((self.__class__.__name__, self.dtype, self.ring, self.base_ideal)) - def __call__(self, a): + def new(self, a): """Construct an element of `self` domain from `a`. """ if not isinstance(a, self.ring.dtype): a = self.ring(a) @@ -136,24 +138,16 @@ def __eq__(self, other): """Returns `True` if two domains are equivalent. """ - if not isinstance(other, QuotientRing): - return False - return self.ring == other.ring and self.base_ideal == other.base_ideal - - def __ne__(self, other): - """Returns `False` if two domains are equivalent. """ - return not self.__eq__(other) + return isinstance(other, QuotientRing) and \ + self.ring == other.ring and self.base_ideal == other.base_ideal def from_ZZ_python(K1, a, K0): """Convert a Python `int` object to `dtype`. """ return K1(K1.ring.convert(a, K0)) from_QQ_python = from_ZZ_python - from_ZZ_sympy = from_ZZ_python - from_QQ_sympy = from_ZZ_python from_ZZ_gmpy = from_ZZ_python from_QQ_gmpy = from_ZZ_python - from_RR_sympy = from_ZZ_python from_RR_mpmath = from_ZZ_python from_GlobalPolynomialRing = from_ZZ_python from_FractionField = from_ZZ_python @@ -183,7 +177,7 @@ I = self.ring.ideal(a.data) + self.base_ideal try: return self(I.in_terms_of_generators(1)[0]) - except ValueError: # 1 not in I + except ValueError: # 1 not in I raise NotReversible('%s not a unit in %r' % (a, self)) def is_zero(self, a): diff -Nru python3-sympy-0.7.2/sympy/polys/domains/rationalfield.py python3-sympy-0.7.3/sympy/polys/domains/rationalfield.py --- python3-sympy-0.7.2/sympy/polys/domains/rationalfield.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/polys/domains/rationalfield.py 2013-07-13 17:53:32.000000000 +0000 @@ -4,21 +4,17 @@ from sympy.polys.domains.simpledomain import SimpleDomain from sympy.polys.domains.characteristiczero import CharacteristicZero + class RationalField(Field, CharacteristicZero, SimpleDomain): """General class for rational fields. """ is_QQ = True - rep = 'QQ' + rep = 'QQ' is_Numerical = True - has_assoc_Ring = True - has_assoc_Field = True - - def get_ring(self): - """Returns a ring associated with ``self``. """ - from sympy.polys.domains import ZZ - return ZZ + has_assoc_Ring = True + has_assoc_Field = True def algebraic_field(self, *extension): r"""Returns an algebraic field, i.e. `\mathbb{Q}(\alpha, \dots)`. """ diff -Nru python3-sympy-0.7.2/sympy/polys/domains/realdomain.py python3-sympy-0.7.3/sympy/polys/domains/realdomain.py --- python3-sympy-0.7.2/sympy/polys/domains/realdomain.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/polys/domains/realdomain.py 2013-07-13 17:53:32.000000000 +0000 @@ -2,32 +2,33 @@ from sympy.polys.domains.characteristiczero import CharacteristicZero from sympy.polys.domains.simpledomain import SimpleDomain -from sympy.polys.domains.groundtypes import SymPyRealType +from sympy.polys.domains.groundtypes import SymPyReal from sympy.polys.polyerrors import DomainError, CoercionFailed import math -class RealDomain(CharacteristicZero, SimpleDomain): # XXX: should be a field + +class RealDomain(CharacteristicZero, SimpleDomain): # XXX: should be a field """Abstract domain for real numbers. """ - rep = 'RR' + rep = 'RR' - is_Exact = False + is_Exact = False is_Numerical = True _convert_excludes = [ - SymPyRealType('+inf'), - SymPyRealType('-inf'), + SymPyReal('+inf'), + SymPyReal('-inf'), ] def as_integer_ratio(self, a, **args): """Convert real number to a (numer, denom) pair. """ - v, n = math.frexp(a) # XXX: hack, will work only for floats + v, n = math.frexp(a) # XXX: hack, will work only for floats for i in range(300): if v != math.floor(v): - v, n = 2*v, n-1 + v, n = 2*v, n - 1 else: break @@ -60,7 +61,7 @@ p0, q0, p1, q1 = 0, 1, 1, 0 while True: - a = n//d + a = n//d q2 = q0 + a*q1 if q2 > max_denom: @@ -95,19 +96,20 @@ return QQ def exquo(self, a, b): - """Exact quotient of ``a`` and ``b``, implies ``__div__``. """ + """Exact quotient of ``a`` and ``b``. """ return a / b def quo(self, a, b): - """Quotient of ``a`` and ``b``, implies ``__div__``. """ + """Quotient of ``a`` and ``b``. """ return a / b def rem(self, a, b): - """Remainder of ``a`` and ``b``, implies nothing. """ - return self.zero + """Remainder of ``a`` and ``b``. """ + return a % b def div(self, a, b): - """Division of ``a`` and ``b``, implies ``__div__``. """ + """Division of ``a`` and ``b``. """ + return (a / b, a % b) def gcd(self, a, b): """Returns GCD of ``a`` and ``b``. """ @@ -119,7 +121,7 @@ def to_sympy(self, a): """Convert ``a`` to SymPy number. """ - return SymPyRealType(a) + return SymPyReal(a) def from_sympy(self, a): """Convert SymPy's number to ``dtype``. """ diff -Nru python3-sympy-0.7.2/sympy/polys/domains/ring.py python3-sympy-0.7.3/sympy/polys/domains/ring.py --- python3-sympy-0.7.2/sympy/polys/domains/ring.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/polys/domains/ring.py 2013-07-13 17:53:32.000000000 +0000 @@ -3,6 +3,7 @@ from sympy.polys.domains.domain import Domain from sympy.polys.polyerrors import ExactQuotientFailed, NotInvertible, NotReversible + class Ring(Domain): """Represents a ring domain. """ @@ -84,7 +85,7 @@ """ from sympy.polys.agca.ideals import ModuleImplementedIdeal return ModuleImplementedIdeal(self, self.free_module(1).submodule( - *[[x] for x in gens])) + *[[x] for x in gens])) def quotient_ring(self, e): """ diff -Nru python3-sympy-0.7.2/sympy/polys/domains/simpledomain.py python3-sympy-0.7.3/sympy/polys/domains/simpledomain.py --- python3-sympy-0.7.2/sympy/polys/domains/simpledomain.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/polys/domains/simpledomain.py 2013-07-13 17:53:32.000000000 +0000 @@ -2,6 +2,7 @@ from sympy.polys.domains.domain import Domain + class SimpleDomain(Domain): """Base class for simple domains, e.g. ZZ, QQ. """ diff -Nru python3-sympy-0.7.2/sympy/polys/domains/sympyfinitefield.py python3-sympy-0.7.3/sympy/polys/domains/sympyfinitefield.py --- python3-sympy-0.7.2/sympy/polys/domains/sympyfinitefield.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/polys/domains/sympyfinitefield.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,10 +0,0 @@ -"""Implementation of :class:`SymPyFiniteField` class. """ - -from sympy.polys.domains.finitefield import FiniteField -from sympy.polys.domains.sympyintegerring import SymPyIntegerRing - -class SymPyFiniteField(FiniteField): - """Finite field based on SymPy's integers. """ - - dom = SymPyIntegerRing() - alias = 'FF_sympy' diff -Nru python3-sympy-0.7.2/sympy/polys/domains/sympyintegerring.py python3-sympy-0.7.3/sympy/polys/domains/sympyintegerring.py --- python3-sympy-0.7.2/sympy/polys/domains/sympyintegerring.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/polys/domains/sympyintegerring.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,124 +0,0 @@ -"""Implementaton of :class:`SymPyIntegerRing` class. """ - -from sympy.polys.domains.integerring import IntegerRing -from sympy.polys.domains.groundtypes import SymPyIntegerType - -from sympy.polys.polyerrors import CoercionFailed - -class SymPyIntegerRing(IntegerRing): - """Integer ring based on SymPy's ``Integer`` type. """ - - dtype = SymPyIntegerType - zero = dtype(0) - one = dtype(1) - alias = 'ZZ_sympy' - - def __init__(self): - """Allow instantiation of this domain. """ - - def of_type(self, a): - """ - Check if ``a`` is of type ``dtype`` (``sympy``). - - Examples - ======== - - >>> from sympy import S, Integer, Rational - >>> from sympy.polys.domains import ZZ_sympy - - >>> ZZ_sympy().of_type(S.One) - True - >>> ZZ_sympy().of_type(Integer(3)) - True - >>> ZZ_sympy().of_type(Rational(3, 2)) - False - - """ - return type(a) in [type(self.one), type(self.zero), - type(self.dtype(-1)), type(self.dtype(2))] - - def to_sympy(self, a): - """Convert ``a`` to a SymPy object. """ - return a - - def from_sympy(self, a): - """Convert SymPy's Integer to SymPy's ``Integer``. """ - if a.is_Integer: - return a - elif a.is_Float and int(a) == a: - return SymPyIntegerType(int(a)) - else: - raise CoercionFailed("expected an integer, got %s" % a) - - def from_FF_python(K1, a, K0): - """Convert ``ModularInteger(int)`` to SymPy's ``Integer``. """ - return SymPyIntegerType(a.to_int()) - - def from_ZZ_python(K1, a, K0): - """Convert Python's ``int`` to SymPy's ``Integer``. """ - return SymPyIntegerType(a) - - def from_QQ_python(K1, a, K0): - """Convert Python's ``Fraction`` to SymPy's ``Integer``. """ - if a.denominator == 1: - return SymPyIntegerType(a.numerator) - - def from_FF_sympy(K1, a, K0): - """Convert ``ModularInteger(Integer)`` to SymPy's ``Integer``. """ - return a.to_int() - - def from_ZZ_sympy(K1, a, K0): - """Convert SymPy's ``Integer`` to SymPy's ``Integer``. """ - return a - - def from_QQ_sympy(K1, a, K0): - """Convert SymPy's ``Rational`` to SymPy's ``Integer``. """ - if a.q == 1: - return SymPyIntegerType(a.p) - - def from_FF_gmpy(K1, a, K0): - """Convert ``ModularInteger(mpz)`` to SymPy's ``Integer``. """ - return SymPyIntegerType(int(a.to_int())) - - def from_ZZ_gmpy(K1, a, K0): - """Convert GMPY's ``mpz`` to SymPy's ``Integer``. """ - return SymPyIntegerType(int(a)) - - def from_QQ_gmpy(K1, a, K0): - """Convert GMPY's ``mpq`` to SymPy's ``Integer``. """ - if a.denom() == 1: - return SymPyIntegerType(int(a.numer())) - - def from_RR_sympy(K1, a, K0): - """Convert SymPy's ``Float`` to SymPy's ``Integer``. """ - p, q = K0.as_integer_ratio(a) - - if q == 1: - return SymPyIntegerType(p) - - def from_RR_mpmath(K1, a, K0): - """Convert mpmath's ``mpf`` to SymPy's ``Integer``. """ - p, q = K0.as_integer_ratio(a) - - if q == 1: - return SymPyIntegerType(p) - - def gcdex(self, a, b): - """Compute extended GCD of ``a`` and ``b``. """ - return a.gcdex(b) - - def gcd(self, a, b): - """Compute GCD of ``a`` and ``b``. """ - return a.gcd(b) - - def lcm(self, a, b): - """Compute LCM of ``a`` and ``b``. """ - return a.lcm(b) - - def sqrt(self, a): - """Compute square root of ``a``. """ - return a.isqrt() - - def factorial(self, a): - """Compute factorial of ``a``. """ - return a.factorial() diff -Nru python3-sympy-0.7.2/sympy/polys/domains/sympyrationalfield.py python3-sympy-0.7.3/sympy/polys/domains/sympyrationalfield.py --- python3-sympy-0.7.2/sympy/polys/domains/sympyrationalfield.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/polys/domains/sympyrationalfield.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,95 +0,0 @@ -"""Implementaton of :class:`SymPyRationalField` class. """ - -from sympy.polys.domains.rationalfield import RationalField -from sympy.polys.domains.groundtypes import SymPyIntegerType -from sympy.polys.domains.groundtypes import SymPyRationalType - -from sympy.polys.polyerrors import CoercionFailed - -from sympy import ( - Rational as sympy_rat, -) - -class SymPyRationalField(RationalField): - """Rational field based on SymPy Rational class. """ - - dtype = SymPyRationalType - zero = dtype(0) - one = dtype(1) - alias = 'QQ_sympy' - - def __init__(self): - pass - - def of_type(self, a): - """ - Check if ``a`` is of type ``Rational``. - - Examples - ======= - - >>> from sympy import Rational, Real - >>> from sympy.polys.domains import QQ_sympy - >>> QQ_sympy().of_type(Rational(3, 2)) - True - >>> QQ_sympy().of_type(2) - False - """ - return type(a) in [type(self.one), type(self.zero), type(sympy_rat(-1)), - type(sympy_rat(2)), type(sympy_rat(1, 2)), - type(sympy_rat(3, 2))] - - def to_sympy(self, a): - """Convert `a` to a SymPy object. """ - return a - - def from_sympy(self, a): - """Convert SymPy's Rational to `dtype`. """ - if a.is_Rational: - return a - elif a.is_Float: - from sympy.polys.domains import RR - return SymPyRationalType(*RR.as_integer_ratio(a)) - else: - raise CoercionFailed("expected `Rational` object, got %s" % a) - - def from_ZZ_python(K1, a, K0): - """Convert a Python `int` object to `dtype`. """ - return SymPyRationalType(a) - - def from_QQ_python(K1, a, K0): - """Convert a Python `Fraction` object to `dtype`. """ - return SymPyRationalType(a.numerator, a.denominator) - - def from_ZZ_sympy(K1, a, K0): - """Convert a SymPy `Integer` object to `dtype`. """ - return SymPyRationalType(a.p) - - def from_QQ_sympy(K1, a, K0): - """Convert a SymPy `Rational` object to `dtype`. """ - return a - - def from_ZZ_gmpy(K1, a, K0): - """Convert a GMPY `mpz` object to `dtype`. """ - return SymPyRationalType(int(a)) - - def from_QQ_gmpy(K1, a, K0): - """Convert a GMPY `mpq` object to `dtype`. """ - return SymPyRationalType(int(a.numer()), - int(a.denom())) - - def from_RR_sympy(K1, a, K0): - """Convert a SymPy `Float` object to `dtype`. """ - return SymPyRationalType(*K0.as_integer_ratio(a)) - - def from_RR_mpmath(K1, a, K0): - """Convert a mpmath `mpf` object to `dtype`. """ - return SymPyRationalType(*K0.as_integer_ratio(a)) - - def numer(self, a): - """Returns numerator of `a`. """ - return SymPyIntegerType(a.p) - - def denom(self, a): - """Returns denominator of `a`. """ - return SymPyIntegerType(a.q) diff -Nru python3-sympy-0.7.2/sympy/polys/domains/sympyrealdomain.py python3-sympy-0.7.3/sympy/polys/domains/sympyrealdomain.py --- python3-sympy-0.7.2/sympy/polys/domains/sympyrealdomain.py 2012-10-17 03:02:21.000000000 +0000 +++ python3-sympy-0.7.3/sympy/polys/domains/sympyrealdomain.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,47 +0,0 @@ -"""Implementation of :class:`SymPyRealDomain` class. """ - -from sympy.polys.domains.realdomain import RealDomain -from sympy.polys.domains.groundtypes import SymPyRealType - -class SymPyRealDomain(RealDomain): - """Domain for real numbers based on SymPy Float type. """ - - dtype = SymPyRealType - zero = dtype(0) - one = dtype(1) - alias = 'RR_sympy' - - def __init__(self): - pass - - def from_ZZ_python(K1, a, K0): - """Convert a Python `int` object to `dtype`. """ - return SymPyRealType(a) - - def from_QQ_python(K1, a, K0): - """Convert a Python `Fraction` object to `dtype`. """ - return SymPyRealType(a.numerator) / a.denominator - - def from_ZZ_sympy(K1, a, K0): - """Convert a SymPy `Integer` object to `dtype`. """ - return SymPyRealType(a.p) - - def from_QQ_sympy(K1, a, K0): - """Convert a SymPy `Rational` object to `dtype`. """ - return SymPyRealType(a.p) / a.q - - def from_ZZ_gmpy(K1, a, K0): - """Convert a GMPY `mpz` object to `dtype`. """ - return SymPyRealType(int(a)) - - def from_QQ_gmpy(K1, a, K0): - """Convert a GMPY `mpq` object to `dtype`. """ - return SymPyRealType(int(a.numer())) / int(a.denom()) - - def from_RR_sympy(K1, a, K0): - """Convert a SymPy `Float` object to `dtype`. """ - return a - - def from_RR_mpmath(K1, a, K0): - """Convert a mpmath `mpf` object to `dtype`. """ - return SymPyRealType(a) diff -Nru python3-sympy-0.7.2/sympy/polys/domains/tests/test_domains.py python3-sympy-0.7.3/sympy/polys/domains/tests/test_domains.py --- python3-sympy-0.7.2/sympy/polys/domains/tests/test_domains.py 1970-01-01 00:00:00.000000000 +0000 +++ python3-sympy-0.7.3/sympy/polys/domains/tests/test_domains.py 2013-07-13 17:53:32.000000000 +0000 @@ -0,0 +1,641 @@ +"""Tests for classes defining properties of ground domains, e.g. ZZ, QQ, ZZ[x] ... """ + +from sympy import S, sqrt, sin, oo, nan, Poly, Integer, Rational +from sympy.abc import x, y, z + +from sympy.polys.domains import (ZZ, QQ, RR, FF, + RR_mpmath, PolynomialRing, FractionField, EX) + +from sympy.polys.domains.modularinteger import ModularIntegerFactory + +from sympy.polys.polyerrors import ( + UnificationFailed, + GeneratorsNeeded, + GeneratorsError, + CoercionFailed, + NotInvertible, + DomainError) + +from sympy.polys.polyclasses import DMP, DMF +from sympy.utilities.pytest import raises, XFAIL + +ALG = QQ.algebraic_field(sqrt(2) + sqrt(3)) + +def test_Domain__unify(): + assert ZZ.unify(ZZ) == ZZ + assert QQ.unify(QQ) == QQ + + assert ZZ.unify(QQ) == QQ + assert QQ.unify(ZZ) == QQ + + assert EX.unify(EX) == EX + + assert ZZ.unify(EX) == EX + assert QQ.unify(EX) == EX + assert EX.unify(ZZ) == EX + assert EX.unify(QQ) == EX + + assert ZZ.poly_ring(x).unify(EX) == EX + assert ZZ.frac_field(x).unify(EX) == EX + assert EX.unify(ZZ.poly_ring(x)) == EX + assert EX.unify(ZZ.frac_field(x)) == EX + + assert ZZ.poly_ring(x, y).unify(EX) == EX + assert ZZ.frac_field(x, y).unify(EX) == EX + assert EX.unify(ZZ.poly_ring(x, y)) == EX + assert EX.unify(ZZ.frac_field(x, y)) == EX + + assert QQ.poly_ring(x).unify(EX) == EX + assert QQ.frac_field(x).unify(EX) == EX + assert EX.unify(QQ.poly_ring(x)) == EX + assert EX.unify(QQ.frac_field(x)) == EX + + assert QQ.poly_ring(x, y).unify(EX) == EX + assert QQ.frac_field(x, y).unify(EX) == EX + assert EX.unify(QQ.poly_ring(x, y)) == EX + assert EX.unify(QQ.frac_field(x, y)) == EX + + assert ZZ.poly_ring(x).unify(ZZ) == ZZ.poly_ring(x) + assert ZZ.poly_ring(x).unify(QQ) == QQ.poly_ring(x) + assert QQ.poly_ring(x).unify(ZZ) == QQ.poly_ring(x) + assert QQ.poly_ring(x).unify(QQ) == QQ.poly_ring(x) + + assert ZZ.unify(ZZ.poly_ring(x)) == ZZ.poly_ring(x) + assert QQ.unify(ZZ.poly_ring(x)) == QQ.poly_ring(x) + assert ZZ.unify(QQ.poly_ring(x)) == QQ.poly_ring(x) + assert QQ.unify(QQ.poly_ring(x)) == QQ.poly_ring(x) + + assert ZZ.poly_ring(x, y).unify(ZZ) == ZZ.poly_ring(x, y) + assert ZZ.poly_ring(x, y).unify(QQ) == QQ.poly_ring(x, y) + assert QQ.poly_ring(x, y).unify(ZZ) == QQ.poly_ring(x, y) + assert QQ.poly_ring(x, y).unify(QQ) == QQ.poly_ring(x, y) + + assert ZZ.unify(ZZ.poly_ring(x, y)) == ZZ.poly_ring(x, y) + assert QQ.unify(ZZ.poly_ring(x, y)) == QQ.poly_ring(x, y) + assert ZZ.unify(QQ.poly_ring(x, y)) == QQ.poly_ring(x, y) + assert QQ.unify(QQ.poly_ring(x, y)) == QQ.poly_ring(x, y) + + assert ZZ.frac_field(x).unify(ZZ) == ZZ.frac_field(x) + assert ZZ.frac_field(x).unify(QQ) == EX # QQ.frac_field(x) + assert QQ.frac_field(x).unify(ZZ) == EX # QQ.frac_field(x) + assert QQ.frac_field(x).unify(QQ) == QQ.frac_field(x) + + assert ZZ.unify(ZZ.frac_field(x)) == ZZ.frac_field(x) + assert QQ.unify(ZZ.frac_field(x)) == EX # QQ.frac_field(x) + assert ZZ.unify(QQ.frac_field(x)) == EX # QQ.frac_field(x) + assert QQ.unify(QQ.frac_field(x)) == QQ.frac_field(x) + + assert ZZ.frac_field(x, y).unify(ZZ) == ZZ.frac_field(x, y) + assert ZZ.frac_field(x, y).unify(QQ) == EX # QQ.frac_field(x,y) + assert QQ.frac_field(x, y).unify(ZZ) == EX # QQ.frac_field(x,y) + assert QQ.frac_field(x, y).unify(QQ) == QQ.frac_field(x, y) + + assert ZZ.unify(ZZ.frac_field(x, y)) == ZZ.frac_field(x, y) + assert QQ.unify(ZZ.frac_field(x, y)) == EX # QQ.frac_field(x,y) + assert ZZ.unify(QQ.frac_field(x, y)) == EX # QQ.frac_field(x,y) + assert QQ.unify(QQ.frac_field(x, y)) == QQ.frac_field(x, y) + + assert ZZ.poly_ring(x).unify(ZZ.poly_ring(x)) == ZZ.poly_ring(x) + assert ZZ.poly_ring(x).unify(QQ.poly_ring(x)) == QQ.poly_ring(x) + assert QQ.poly_ring(x).unify(ZZ.poly_ring(x)) == QQ.poly_ring(x) + assert QQ.poly_ring(x).unify(QQ.poly_ring(x)) == QQ.poly_ring(x) + + assert ZZ.poly_ring(x, y).unify(ZZ.poly_ring(x)) == ZZ.poly_ring(x, y) + assert ZZ.poly_ring(x, y).unify(QQ.poly_ring(x)) == QQ.poly_ring(x, y) + assert QQ.poly_ring(x, y).unify(ZZ.poly_ring(x)) == QQ.poly_ring(x, y) + assert QQ.poly_ring(x, y).unify(QQ.poly_ring(x)) == QQ.poly_ring(x, y) + + assert ZZ.poly_ring(x).unify(ZZ.poly_ring(x, y)) == ZZ.poly_ring(x, y) + assert ZZ.poly_ring(x).unify(QQ.poly_ring(x, y)) == QQ.poly_ring(x, y) + assert QQ.poly_ring(x).unify(ZZ.poly_ring(x, y)) == QQ.poly_ring(x, y) + assert QQ.poly_ring(x).unify(QQ.poly_ring(x, y)) == QQ.poly_ring(x, y) + + assert ZZ.poly_ring(x, y).unify(ZZ.poly_ring(x, z)) == ZZ.poly_ring(x, y, z) + assert ZZ.poly_ring(x, y).unify(QQ.poly_ring(x, z)) == QQ.poly_ring(x, y, z) + assert QQ.poly_ring(x, y).unify(ZZ.poly_ring(x, z)) == QQ.poly_ring(x, y, z) + assert QQ.poly_ring(x, y).unify(QQ.poly_ring(x, z)) == QQ.poly_ring(x, y, z) + + assert ZZ.frac_field(x).unify(ZZ.frac_field(x)) == ZZ.frac_field(x) + assert ZZ.frac_field(x).unify(QQ.frac_field(x)) == QQ.frac_field(x) + assert QQ.frac_field(x).unify(ZZ.frac_field(x)) == QQ.frac_field(x) + assert QQ.frac_field(x).unify(QQ.frac_field(x)) == QQ.frac_field(x) + + assert ZZ.frac_field(x, y).unify(ZZ.frac_field(x)) == ZZ.frac_field(x, y) + assert ZZ.frac_field(x, y).unify(QQ.frac_field(x)) == QQ.frac_field(x, y) + assert QQ.frac_field(x, y).unify(ZZ.frac_field(x)) == QQ.frac_field(x, y) + assert QQ.frac_field(x, y).unify(QQ.frac_field(x)) == QQ.frac_field(x, y) + + assert ZZ.frac_field(x).unify(ZZ.frac_field(x, y)) == ZZ.frac_field(x, y) + assert ZZ.frac_field(x).unify(QQ.frac_field(x, y)) == QQ.frac_field(x, y) + assert QQ.frac_field(x).unify(ZZ.frac_field(x, y)) == QQ.frac_field(x, y) + assert QQ.frac_field(x).unify(QQ.frac_field(x, y)) == QQ.frac_field(x, y) + + assert ZZ.frac_field(x, y).unify(ZZ.frac_field(x, z)) == ZZ.frac_field(x, y, z) + assert ZZ.frac_field(x, y).unify(QQ.frac_field(x, z)) == QQ.frac_field(x, y, z) + assert QQ.frac_field(x, y).unify(ZZ.frac_field(x, z)) == QQ.frac_field(x, y, z) + assert QQ.frac_field(x, y).unify(QQ.frac_field(x, z)) == QQ.frac_field(x, y, z) + + assert ZZ.poly_ring(x).unify(ZZ.frac_field(x)) == ZZ.frac_field(x) + assert ZZ.poly_ring(x).unify(QQ.frac_field(x)) == EX # QQ.frac_field(x) + assert QQ.poly_ring(x).unify(ZZ.frac_field(x)) == EX # QQ.frac_field(x) + assert QQ.poly_ring(x).unify(QQ.frac_field(x)) == QQ.frac_field(x) + + assert ZZ.poly_ring(x, y).unify(ZZ.frac_field(x)) == ZZ.frac_field(x, y) + assert ZZ.poly_ring(x, y).unify(QQ.frac_field(x)) == EX # QQ.frac_field(x,y) + assert QQ.poly_ring(x, y).unify(ZZ.frac_field(x)) == EX # QQ.frac_field(x,y) + assert QQ.poly_ring(x, y).unify(QQ.frac_field(x)) == QQ.frac_field(x, y) + + assert ZZ.poly_ring(x).unify(ZZ.frac_field(x, y)) == ZZ.frac_field(x, y) + assert ZZ.poly_ring(x).unify(QQ.frac_field(x, y)) == EX # QQ.frac_field(x,y) + assert QQ.poly_ring(x).unify(ZZ.frac_field(x, y)) == EX # QQ.frac_field(x,y) + assert QQ.poly_ring(x).unify(QQ.frac_field(x, y)) == QQ.frac_field(x, y) + + assert ZZ.poly_ring(x, y).unify(ZZ.frac_field(x, z)) == ZZ.frac_field(x, y, z) + assert ZZ.poly_ring(x, y).unify(QQ.frac_field(x, z)) == EX # QQ.frac_field(x,y,z) + assert QQ.poly_ring(x, y).unify(ZZ.frac_field(x, z)) == EX # QQ.frac_field(x,y,z) + assert QQ.poly_ring(x, y).unify(QQ.frac_field(x, z)) == QQ.frac_field(x, y, z) + + assert ZZ.frac_field(x).unify(ZZ.poly_ring(x)) == ZZ.frac_field(x) + assert ZZ.frac_field(x).unify(QQ.poly_ring(x)) == EX # QQ.frac_field(x) + assert QQ.frac_field(x).unify(ZZ.poly_ring(x)) == EX # QQ.frac_field(x) + assert QQ.frac_field(x).unify(QQ.poly_ring(x)) == QQ.frac_field(x) + + assert ZZ.frac_field(x, y).unify(ZZ.poly_ring(x)) == ZZ.frac_field(x, y) + assert ZZ.frac_field(x, y).unify(QQ.poly_ring(x)) == EX # QQ.frac_field(x,y) + assert QQ.frac_field(x, y).unify(ZZ.poly_ring(x)) == EX # QQ.frac_field(x,y) + assert QQ.frac_field(x, y).unify(QQ.poly_ring(x)) == QQ.frac_field(x, y) + + assert ZZ.frac_field(x).unify(ZZ.poly_ring(x, y)) == ZZ.frac_field(x, y) + assert ZZ.frac_field(x).unify(QQ.poly_ring(x, y)) == EX # QQ.frac_field(x,y) + assert QQ.frac_field(x).unify(ZZ.poly_ring(x, y)) == EX # QQ.frac_field(x,y) + assert QQ.frac_field(x).unify(QQ.poly_ring(x, y)) == QQ.frac_field(x, y) + + assert ZZ.frac_field(x, y).unify(ZZ.poly_ring(x, z)) == ZZ.frac_field(x, y, z) + assert ZZ.frac_field(x, y).unify(QQ.poly_ring(x, z)) == EX # QQ.frac_field(x,y,z) + assert QQ.frac_field(x, y).unify(ZZ.poly_ring(x, z)) == EX # QQ.frac_field(x,y,z) + assert QQ.frac_field(x, y).unify(QQ.poly_ring(x, z)) == QQ.frac_field(x, y, z) + + alg = QQ.algebraic_field(sqrt(5)) + + assert alg.unify(alg[x, y]) == alg[x, y] + assert alg[x, y].unify(alg) == alg[x, y] + + assert alg.unify(alg.frac_field(x, y)) == alg.frac_field(x, y) + assert alg.frac_field(x, y).unify(alg) == alg.frac_field(x, y) + + ext = QQ.algebraic_field(sqrt(7)) + + raises(NotImplementedError, lambda: alg.unify(ext)) + + raises(UnificationFailed, lambda: ZZ.poly_ring(x, y).unify(ZZ, gens=(y, z))) + raises(UnificationFailed, lambda: ZZ.unify(ZZ.poly_ring(x, y), gens=(y, z))) + + +def test_Domain__contains__(): + assert (0 in EX) is True + assert (0 in ZZ) is True + assert (0 in QQ) is True + assert (0 in RR) is True + assert (0 in ALG) is True + assert (0 in ZZ[x, y]) is True + assert (0 in QQ[x, y]) is True + assert (0 in RR[x, y]) is True + + assert (-7 in EX) is True + assert (-7 in ZZ) is True + assert (-7 in QQ) is True + assert (-7 in RR) is True + assert (-7 in ALG) is True + assert (-7 in ZZ[x, y]) is True + assert (-7 in QQ[x, y]) is True + assert (-7 in RR[x, y]) is True + + assert (17 in EX) is True + assert (17 in ZZ) is True + assert (17 in QQ) is True + assert (17 in RR) is True + assert (17 in ALG) is True + assert (17 in ZZ[x, y]) is True + assert (17 in QQ[x, y]) is True + assert (17 in RR[x, y]) is True + + assert (-S(1)/7 in EX) is True + assert (-S(1)/7 in ZZ) is False + assert (-S(1)/7 in QQ) is True + assert (-S(1)/7 in RR) is True + assert (-S(1)/7 in ALG) is True + assert (-S(1)/7 in ZZ[x, y]) is False + assert (-S(1)/7 in QQ[x, y]) is True + assert (-S(1)/7 in RR[x, y]) is True + + assert (S(3)/5 in EX) is True + assert (S(3)/5 in ZZ) is False + assert (S(3)/5 in QQ) is True + assert (S(3)/5 in RR) is True + assert (S(3)/5 in ALG) is True + assert (S(3)/5 in ZZ[x, y]) is False + assert (S(3)/5 in QQ[x, y]) is True + assert (S(3)/5 in RR[x, y]) is True + + assert (3.0 in EX) is True + assert (3.0 in ZZ) is True + assert (3.0 in QQ) is True + assert (3.0 in RR) is True + assert (3.0 in ALG) is True + assert (3.0 in ZZ[x, y]) is True + assert (3.0 in QQ[x, y]) is True + assert (3.0 in RR[x, y]) is True + + assert (3.14 in EX) is True + assert (3.14 in ZZ) is False + assert (3.14 in QQ) is True + assert (3.14 in RR) is True + assert (3.14 in ALG) is True + assert (3.14 in ZZ[x, y]) is False + assert (3.14 in QQ[x, y]) is True + assert (3.14 in RR[x, y]) is True + + assert (oo in EX) is True + assert (oo in ZZ) is False + assert (oo in QQ) is False + assert (oo in RR) is False + assert (oo in ALG) is False + assert (oo in ZZ[x, y]) is False + assert (oo in QQ[x, y]) is False + assert (oo in RR[x, y]) is False + + assert (-oo in EX) is True + assert (-oo in ZZ) is False + assert (-oo in QQ) is False + assert (-oo in RR) is False + assert (-oo in ALG) is False + assert (-oo in ZZ[x, y]) is False + assert (-oo in QQ[x, y]) is False + assert (-oo in RR[x, y]) is False + + assert (sqrt(7) in EX) is True + assert (sqrt(7) in ZZ) is False + assert (sqrt(7) in QQ) is False + assert (sqrt(7) in RR) is True + assert (sqrt(7) in ALG) is False + assert (sqrt(7) in ZZ[x, y]) is False + assert (sqrt(7) in QQ[x, y]) is False + assert (sqrt(7) in RR[x, y]) is True + + assert (2*sqrt(3) + 1 in EX) is True + assert (2*sqrt(3) + 1 in ZZ) is False + assert (2*sqrt(3) + 1 in QQ) is False + assert (2*sqrt(3) + 1 in RR) is True + assert (2*sqrt(3) + 1 in ALG) is True + assert (2*sqrt(3) + 1 in ZZ[x, y]) is False + assert (2*sqrt(3) + 1 in QQ[x, y]) is False + assert (2*sqrt(3) + 1 in RR[x, y]) is True + + assert (sin(1) in EX) is True + assert (sin(1) in ZZ) is False + assert (sin(1) in QQ) is False + assert (sin(1) in RR) is True + assert (sin(1) in ALG) is False + assert (sin(1) in ZZ[x, y]) is False + assert (sin(1) in QQ[x, y]) is False + assert (sin(1) in RR[x, y]) is True + + assert (x**2 + 1 in EX) is True + assert (x**2 + 1 in ZZ) is False + assert (x**2 + 1 in QQ) is False + assert (x**2 + 1 in RR) is False + assert (x**2 + 1 in ALG) is False + assert (x**2 + 1 in ZZ[x]) is True + assert (x**2 + 1 in QQ[x]) is True + assert (x**2 + 1 in RR[x]) is True + assert (x**2 + 1 in ZZ[x, y]) is True + assert (x**2 + 1 in QQ[x, y]) is True + assert (x**2 + 1 in RR[x, y]) is True + + assert (x**2 + y**2 in EX) is True + assert (x**2 + y**2 in ZZ) is False + assert (x**2 + y**2 in QQ) is False + assert (x**2 + y**2 in RR) is False + assert (x**2 + y**2 in ALG) is False + assert (x**2 + y**2 in ZZ[x]) is False + assert (x**2 + y**2 in QQ[x]) is False + assert (x**2 + y**2 in RR[x]) is False + assert (x**2 + y**2 in ZZ[x, y]) is True + assert (x**2 + y**2 in QQ[x, y]) is True + assert (x**2 + y**2 in RR[x, y]) is True + + assert (S(3)/2*x/(y + 1) - z in QQ[x, y, z]) is False + + +def test_Domain_get_ring(): + assert ZZ.has_assoc_Ring is True + assert QQ.has_assoc_Ring is True + assert ZZ[x].has_assoc_Ring is True + assert QQ[x].has_assoc_Ring is True + assert ZZ[x, y].has_assoc_Ring is True + assert QQ[x, y].has_assoc_Ring is True + assert ZZ.frac_field(x).has_assoc_Ring is True + assert QQ.frac_field(x).has_assoc_Ring is True + assert ZZ.frac_field(x, y).has_assoc_Ring is True + assert QQ.frac_field(x, y).has_assoc_Ring is True + + assert EX.has_assoc_Ring is False + assert RR.has_assoc_Ring is False + assert ALG.has_assoc_Ring is False + + assert ZZ.get_ring() == ZZ + assert QQ.get_ring() == ZZ + assert ZZ[x].get_ring() == ZZ[x] + assert QQ[x].get_ring() == QQ[x] + assert ZZ[x, y].get_ring() == ZZ[x, y] + assert QQ[x, y].get_ring() == QQ[x, y] + assert ZZ.frac_field(x).get_ring() == ZZ[x] + assert QQ.frac_field(x).get_ring() == QQ[x] + assert ZZ.frac_field(x, y).get_ring() == ZZ[x, y] + assert QQ.frac_field(x, y).get_ring() == QQ[x, y] + + assert EX.get_ring() == EX + + raises(DomainError, lambda: RR.get_ring()) + raises(DomainError, lambda: ALG.get_ring()) + + +def test_Domain_get_field(): + assert EX.has_assoc_Field is True + assert ZZ.has_assoc_Field is True + assert QQ.has_assoc_Field is True + assert RR.has_assoc_Field is False + assert ALG.has_assoc_Field is True + assert ZZ[x].has_assoc_Field is True + assert QQ[x].has_assoc_Field is True + assert ZZ[x, y].has_assoc_Field is True + assert QQ[x, y].has_assoc_Field is True + + assert EX.get_field() == EX + assert ZZ.get_field() == QQ + assert QQ.get_field() == QQ + raises(DomainError, lambda: RR.get_field()) + assert ALG.get_field() == ALG + assert ZZ[x].get_field() == ZZ.frac_field(x) + assert QQ[x].get_field() == QQ.frac_field(x) + assert ZZ[x, y].get_field() == ZZ.frac_field(x, y) + assert QQ[x, y].get_field() == QQ.frac_field(x, y) + + +def test_Domain_get_exact(): + assert EX.get_exact() == EX + assert ZZ.get_exact() == ZZ + assert QQ.get_exact() == QQ + assert RR.get_exact() == QQ + assert ALG.get_exact() == ALG + assert ZZ[x].get_exact() == ZZ[x] + assert QQ[x].get_exact() == QQ[x] + assert ZZ[x, y].get_exact() == ZZ[x, y] + assert QQ[x, y].get_exact() == QQ[x, y] + assert ZZ.frac_field(x).get_exact() == ZZ.frac_field(x) + assert QQ.frac_field(x).get_exact() == QQ.frac_field(x) + assert ZZ.frac_field(x, y).get_exact() == ZZ.frac_field(x, y) + assert QQ.frac_field(x, y).get_exact() == QQ.frac_field(x, y) + + +def test_Domain_convert(): + assert QQ.convert(10e-52) != QQ(0) + assert ZZ.convert(DMP([[ZZ(1)]], ZZ)) == ZZ(1) + + +def test_PolynomialRing__init(): + raises(GeneratorsNeeded, lambda: ZZ.poly_ring()) + + +def test_PolynomialRing_from_FractionField(): + x = DMF(([1, 0, 1], [1, 1]), ZZ) + y = DMF(([1, 0, 1], [1]), ZZ) + + assert ZZ['x'].from_FractionField(x, ZZ['x']) is None + assert ZZ['x'].from_FractionField(y, ZZ['x']) == DMP([ZZ(1), ZZ(0), + ZZ(1)], ZZ) + + +def test_FractionField__init(): + raises(GeneratorsNeeded, lambda: ZZ.frac_field()) + + +def test_inject(): + assert ZZ.inject(x, y, z) == ZZ[x, y, z] + assert ZZ[x].inject(y, z) == ZZ[x, y, z] + assert ZZ.frac_field(x).inject(y, z) == ZZ.frac_field(x, y, z) + raises(GeneratorsError, lambda: ZZ[x].inject(x)) + + +def test_Domain_map(): + seq = ZZ.map([1, 2, 3, 4]) + + assert all(ZZ.of_type(elt) for elt in seq) + + seq = ZZ.map([[1, 2, 3, 4]]) + + assert all(ZZ.of_type(elt) for elt in seq[0]) and len(seq) == 1 + + +def test_Domain___eq__(): + assert (ZZ[x, y] == ZZ[x, y]) is True + assert (QQ[x, y] == QQ[x, y]) is True + + assert (ZZ[x, y] == QQ[x, y]) is False + assert (QQ[x, y] == ZZ[x, y]) is False + + assert (ZZ.frac_field(x, y) == ZZ.frac_field(x, y)) is True + assert (QQ.frac_field(x, y) == QQ.frac_field(x, y)) is True + + assert (ZZ.frac_field(x, y) == QQ.frac_field(x, y)) is False + assert (QQ.frac_field(x, y) == ZZ.frac_field(x, y)) is False + + +def test_Domain__algebraic_field(): + alg = ZZ.algebraic_field(sqrt(2)) + assert alg.ext.minpoly == Poly(x**2 - 2) + assert alg.dom == QQ + + alg = QQ.algebraic_field(sqrt(2)) + assert alg.ext.minpoly == Poly(x**2 - 2) + assert alg.dom == QQ + + alg = alg.algebraic_field(sqrt(3)) + assert alg.ext.minpoly == Poly(x**4 - 10*x**2 + 1) + assert alg.dom == QQ + + +def test_PolynomialRing__from_FractionField(): + f = DMF(([1, 0, 1], [1, 1]), ZZ) + g = DMF(([1, 0, 1], [1]), ZZ) + + assert ZZ[x].from_FractionField(f, ZZ[x]) is None + assert ZZ[x].from_FractionField(g, ZZ[x]) == DMP([ZZ(1), ZZ(0), ZZ(1)], ZZ) + + +def test_FF_of_type(): + assert FF(3).of_type(FF(3)(1)) is True + assert FF(5).of_type(FF(5)(3)) is True + assert FF(5).of_type(FF(7)(3)) is False + + +def test___eq__(): + assert not QQ[x] == ZZ[x] + assert not QQ.frac_field(x) == ZZ.frac_field(x) + + +def test_RealDomain_from_sympy(): + RR = RR_mpmath() + + assert RR.convert(S(0)) == RR.dtype(0) + assert RR.convert(S(0.0)) == RR.dtype(0.0) + assert RR.convert(S(1)) == RR.dtype(1) + assert RR.convert(S(1.0)) == RR.dtype(1.0) + assert RR.convert(sin(1)) == RR.dtype(sin(1).evalf()) + raises(CoercionFailed, lambda: RR.convert(x)) + raises(CoercionFailed, lambda: RR.convert(oo)) + raises(CoercionFailed, lambda: RR.convert(-oo)) + + +def test_ModularInteger(): + GF = ModularIntegerFactory(3) + + a = GF(0) + assert isinstance(a, GF) and a == 0 + a = GF(1) + assert isinstance(a, GF) and a == 1 + a = GF(2) + assert isinstance(a, GF) and a == 2 + a = GF(3) + assert isinstance(a, GF) and a == 0 + a = GF(4) + assert isinstance(a, GF) and a == 1 + + a = GF(GF(0)) + assert isinstance(a, GF) and a == 0 + a = GF(GF(1)) + assert isinstance(a, GF) and a == 1 + a = GF(GF(2)) + assert isinstance(a, GF) and a == 2 + a = GF(GF(3)) + assert isinstance(a, GF) and a == 0 + a = GF(GF(4)) + assert isinstance(a, GF) and a == 1 + + a = -GF(1) + assert isinstance(a, GF) and a == 2 + a = -GF(2) + assert isinstance(a, GF) and a == 1 + + a = 2 + GF(2) + assert isinstance(a, GF) and a == 1 + a = GF(2) + 2 + assert isinstance(a, GF) and a == 1 + a = GF(2) + GF(2) + assert isinstance(a, GF) and a == 1 + a = GF(2) + GF(2) + assert isinstance(a, GF) and a == 1 + + a = 3 - GF(2) + assert isinstance(a, GF) and a == 1 + a = GF(3) - 2 + assert isinstance(a, GF) and a == 1 + a = GF(3) - GF(2) + assert isinstance(a, GF) and a == 1 + a = GF(3) - GF(2) + assert isinstance(a, GF) and a == 1 + + a = 2*GF(2) + assert isinstance(a, GF) and a == 1 + a = GF(2)*2 + assert isinstance(a, GF) and a == 1 + a = GF(2)*GF(2) + assert isinstance(a, GF) and a == 1 + a = GF(2)*GF(2) + assert isinstance(a, GF) and a == 1 + + a = 2/GF(2) + assert isinstance(a, GF) and a == 1 + a = GF(2)/2 + assert isinstance(a, GF) and a == 1 + a = GF(2)/GF(2) + assert isinstance(a, GF) and a == 1 + a = GF(2)/GF(2) + assert isinstance(a, GF) and a == 1 + + a = 1 % GF(2) + assert isinstance(a, GF) and a == 1 + a = GF(1) % 2 + assert isinstance(a, GF) and a == 1 + a = GF(1) % GF(2) + assert isinstance(a, GF) and a == 1 + a = GF(1) % GF(2) + assert isinstance(a, GF) and a == 1 + + a = GF(2)**0 + assert isinstance(a, GF) and a == 1 + a = GF(2)**1 + assert isinstance(a, GF) and a == 2 + a = GF(2)**2 + assert isinstance(a, GF) and a == 1 + + assert bool(GF(3)) is False + assert bool(GF(4)) is True + + GF = ModularIntegerFactory(5) + + a = GF(1)**(-1) + assert isinstance(a, GF) and a == 1 + a = GF(2)**(-1) + assert isinstance(a, GF) and a == 3 + a = GF(3)**(-1) + assert isinstance(a, GF) and a == 2 + a = GF(4)**(-1) + assert isinstance(a, GF) and a == 4 + + assert (GF(1) < GF(2)) is True + assert (GF(1) <= GF(2)) is True + assert (GF(1) > GF(2)) is False + assert (GF(1) >= GF(2)) is False + + assert (GF(3) < GF(2)) is False + assert (GF(3) <= GF(2)) is False + assert (GF(3) > GF(2)) is True + assert (GF(3) >= GF(2)) is True + + assert (GF(1) < GF(7)) is True + assert (GF(1) <= GF(7)) is True + assert (GF(1) > GF(7)) is False + assert (GF(1) >= GF(7)) is False + + assert (GF(3) < GF(7)) is False + assert (GF(3) <= GF(7)) is False + assert (GF(3) > GF(7)) is True + assert (GF(3) >= GF(7)) is True + + assert (GF(1) < 2) is True + assert (GF(1) <= 2) is True + assert (GF(1) > 2) is False + assert (GF(1) >= 2) is False + + assert (GF(3) < 2) is False + assert (GF(3) <= 2) is False + assert (GF(3) > 2) is True + assert (GF(3) >= 2) is True + + assert (GF(1) < 7) is True + assert (GF(1) <= 7) is True + assert (GF(1) > 7) is False + assert (GF(1) >= 7) is False + + assert (GF(3) < 7) is False + assert (GF(3) <= 7) is False + assert (GF(3) > 7) is True + assert (GF(3) >= 7) is True + + raises(NotInvertible, lambda: GF(0)**(-1)) + raises(NotInvertible, lambda: GF(5)**(-1)) + + raises(ValueError, lambda: ModularIntegerFactory(0)) + raises(ValueError, lambda: ModularIntegerFactory(2.1)) + raises(TypeError, lambda: ModularIntegerFactory(3, QQ)) diff -Nru python3-sympy-0.7.2/sympy/polys/domains/tests/test_polynomialring.py python3-sympy-0.7.3/sympy/polys/domains/tests/test_polynomialring.py --- python3-sympy-0.7.2/sympy/polys/domains/tests/test_polynomialring.py 1970-01-01 00:00:00.000000000 +0000 +++ python3-sympy-0.7.3/sympy/polys/domains/tests/test_polynomialring.py 2013-07-13 17:53:32.000000000 +0000 @@ -0,0 +1,102 @@ +"""Tests for the PolynomialRing classes. """ + +from sympy.polys.domains import QQ, ZZ, PolynomialRing +from sympy.polys.polyerrors import ExactQuotientFailed, CoercionFailed, NotReversible + +from sympy.abc import x, y + +from sympy.utilities.pytest import raises + + +def test_build_order(): + R = QQ.poly_ring(x, y, order=(("lex", x), ("ilex", y))) + assert R.order((1, 5)) == ((1,), (-5,)) + + +def test_globalring(): + Qxy = QQ.frac_field(x, y) + R = QQ[x, y] + X = R.convert(x) + Y = R.convert(y) + + assert x in R + assert 1/x not in R + assert 1/(1 + x) not in R + assert Y in R + assert X.ring == R + assert X * (Y**2 + 1) == R.convert(x * (y**2 + 1)) + assert X * y == X * Y == R.convert(x * y) == x * Y + assert X + y == X + Y == R.convert(x + y) == x + Y + assert X - y == X - Y == R.convert(x - y) == x - Y + assert X + 1 == R.convert(x + 1) + raises(ExactQuotientFailed, lambda: X/Y) + raises(ExactQuotientFailed, lambda: x/Y) + raises(ExactQuotientFailed, lambda: X/y) + assert X**2 / X == X + + assert R.from_GlobalPolynomialRing(ZZ[x, y].convert(x), ZZ[x, y]) == X + assert R.from_FractionField(Qxy.convert(x), Qxy) == X + assert R.from_FractionField(Qxy.convert(x)/y, Qxy) is None + + assert R._sdm_to_vector(R._vector_to_sdm([X, Y], R.order), 2) == [X, Y] + + +def test_localring(): + Qxy = QQ.frac_field(x, y) + R = QQ.poly_ring(x, y, order="ilex") + X = R.convert(x) + Y = R.convert(y) + + assert x in R + assert 1/x not in R + assert 1/(1 + x) in R + assert Y in R + assert X.ring == R + assert X*(Y**2 + 1)/(1 + X) == R.convert(x*(y**2 + 1)/(1 + x)) + assert X*y == X*Y + raises(ExactQuotientFailed, lambda: X/Y) + raises(ExactQuotientFailed, lambda: x/Y) + raises(ExactQuotientFailed, lambda: X/y) + assert X + y == X + Y == R.convert(x + y) == x + Y + assert X - y == X - Y == R.convert(x - y) == x - Y + assert X + 1 == R.convert(x + 1) + assert X**2 / X == X + + assert R.from_GlobalPolynomialRing(ZZ[x, y].convert(x), ZZ[x, y]) == X + assert R.from_FractionField(Qxy.convert(x), Qxy) == X + raises(CoercionFailed, lambda: R.from_FractionField(Qxy.convert(x)/y, Qxy)) + raises(ExactQuotientFailed, lambda: X/Y) + raises(NotReversible, lambda: X.invert()) + + assert R._sdm_to_vector( + R._vector_to_sdm([X/(X + 1), Y/(1 + X*Y)], R.order), 2) == \ + [X*(1 + X*Y), Y*(1 + X)] + + +def test_conversion(): + L = QQ.poly_ring(x, y, order="ilex") + G = QQ[x, y] + + assert L.convert(x) == L.convert(G.convert(x), G) + assert G.convert(x) == G.convert(L.convert(x), L) + raises(CoercionFailed, lambda: G.convert(L.convert(1/(1 + x)), L)) + + +def test_units(): + R = QQ[x] + assert R.is_unit(R.convert(1)) + assert R.is_unit(R.convert(2)) + assert not R.is_unit(R.convert(x)) + assert not R.is_unit(R.convert(1 + x)) + + R = QQ.poly_ring(x, order='ilex') + assert R.is_unit(R.convert(1)) + assert R.is_unit(R.convert(2)) + assert not R.is_unit(R.convert(x)) + assert R.is_unit(R.convert(1 + x)) + + R = ZZ[x] + assert R.is_unit(R.convert(1)) + assert not R.is_unit(R.convert(2)) + assert not R.is_unit(R.convert(x)) + assert not R.is_unit(R.convert(1 + x)) diff -Nru python3-sympy-0.7.2/sympy/polys/domains/tests/test_quotientring.py python3-sympy-0.7.3/sympy/polys/domains/tests/test_quotientring.py --- python3-sympy-0.7.2/sympy/polys/domains/tests/test_quotientring.py 1970-01-01 00:00:00.000000000 +0000 +++ python3-sympy-0.7.3/sympy/polys/domains/tests/test_quotientring.py 2013-07-13 17:53:32.000000000 +0000 @@ -0,0 +1,51 @@ +"""Tests for quotient rings.""" + +from sympy import QQ, ZZ +from sympy.abc import x, y + +from sympy.polys.polyerrors import NotReversible + +from sympy.utilities.pytest import raises + + +def test_QuotientRingElement(): + R = QQ[x]/[x**10] + X = R.convert(x) + + assert X*(X + 1) == R.convert(x**2 + x) + assert X*x == R.convert(x**2) + assert x*X == R.convert(x**2) + assert X + x == R.convert(2*x) + assert x + X == 2*X + assert X**2 == R.convert(x**2) + assert 1/(1 - X) == R.convert(sum(x**i for i in range(10))) + assert X**10 == R.zero + assert X != x + + raises(NotReversible, lambda: 1/X) + + +def test_QuotientRing(): + I = QQ[x].ideal(x**2 + 1) + R = QQ[x]/I + + assert R == QQ[x]/[x**2 + 1] + assert R == QQ[x]/QQ[x].ideal(x**2 + 1) + assert R != QQ[x] + + assert R.convert(1)/x == -x + I + assert -1 + I == x**2 + I + assert R.convert(ZZ(1), ZZ) == 1 + I + assert R.convert(R.convert(x), R) == R.convert(x) + + X = R.convert(x) + Y = QQ[x].convert(x) + assert -1 + I == X**2 + I + assert -1 + I == Y**2 + I + assert R.to_sympy(X) == x + + raises(ValueError, lambda: QQ[x]/QQ[x, y].ideal(x)) + + R = QQ.poly_ring(x, order="ilex") + I = R.ideal(x) + assert R.convert(1) + I == (R/I).convert(1) diff -Nru python3-sympy-0.7.2/sympy/polys/euclidtools.py python3-sympy-0.7.3/sympy/polys/euclidtools.py --- python3-sympy-0.7.2/sympy/polys/euclidtools.py 2012-10-17 03:02:22.000000000 +0000 +++ python3-sympy-0.7.3/sympy/polys/euclidtools.py 2013-07-13 17:53:32.000000000 +0000 @@ -52,6 +52,7 @@ from sympy.ntheory import nextprime + def dup_half_gcdex(f, g, K): """ Half extended Euclidean algorithm in `F[x]`. @@ -61,14 +62,14 @@ Examples ======== - >>> from sympy.polys.domains import QQ - >>> from sympy.polys.euclidtools import dup_half_gcdex + >>> from sympy.polys import ring, QQ + >>> R, x = ring("x", QQ) - >>> f = QQ.map([1, -2, -6, 12, 15]) - >>> g = QQ.map([1, 1, -4, -4]) + >>> f = x**4 - 2*x**3 - 6*x**2 + 12*x + 15 + >>> g = x**3 + x**2 - 4*x - 4 - >>> dup_half_gcdex(f, g, QQ) - ([-1/5, 3/5], [1/1, 1/1]) + >>> R.dup_half_gcdex(f, g) + (-1/5*x + 3/5, x + 1) """ if not (K.has_Field or not K.is_Exact): @@ -86,6 +87,7 @@ return a, f + def dmp_half_gcdex(f, g, u, K): """ Half extended Euclidean algorithm in `F[X]`. @@ -93,8 +95,8 @@ Examples ======== - >>> from sympy.polys.domains import QQ - >>> from sympy.polys.euclidtools import dmp_half_gcdex + >>> from sympy.polys import ring, ZZ + >>> R, x,y = ring("x,y", ZZ) """ if not u: @@ -102,6 +104,7 @@ else: raise MultivariatePolynomialError(f, g) + def dup_gcdex(f, g, K): """ Extended Euclidean algorithm in `F[x]`. @@ -111,14 +114,14 @@ Examples ======== - >>> from sympy.polys.domains import QQ - >>> from sympy.polys.euclidtools import dup_gcdex + >>> from sympy.polys import ring, QQ + >>> R, x = ring("x", QQ) - >>> f = QQ.map([1, -2, -6, 12, 15]) - >>> g = QQ.map([1, 1, -4, -4]) + >>> f = x**4 - 2*x**3 - 6*x**2 + 12*x + 15 + >>> g = x**3 + x**2 - 4*x - 4 - >>> dup_gcdex(f, g, QQ) - ([-1/5, 3/5], [1/5, -6/5, 2/1], [1/1, 1/1]) + >>> R.dup_gcdex(f, g) + (-1/5*x + 3/5, 1/5*x**2 - 6/5*x + 2, x + 1) """ s, h = dup_half_gcdex(f, g, K) @@ -128,6 +131,7 @@ return s, t, h + def dmp_gcdex(f, g, u, K): """ Extended Euclidean algorithm in `F[X]`. @@ -135,8 +139,8 @@ Examples ======== - >>> from sympy.polys.domains import QQ - >>> from sympy.polys.euclidtools import dmp_gcdex + >>> from sympy.polys import ring, ZZ + >>> R, x,y = ring("x,y", ZZ) """ if not u: @@ -144,6 +148,7 @@ else: raise MultivariatePolynomialError(f, g) + def dup_invert(f, g, K): """ Compute multiplicative inverse of `f` modulo `g` in `F[x]`. @@ -151,17 +156,17 @@ Examples ======== - >>> from sympy.polys.domains import QQ - >>> from sympy.polys.euclidtools import dup_invert + >>> from sympy.polys import ring, QQ + >>> R, x = ring("x", QQ) - >>> f = QQ.map([1, 0, -1]) - >>> g = QQ.map([2, -1]) - >>> h = QQ.map([1, -1]) + >>> f = x**2 - 1 + >>> g = 2*x - 1 + >>> h = x - 1 - >>> dup_invert(f, g, QQ) - [-4/3] + >>> R.dup_invert(f, g) + -4/3 - >>> dup_invert(f, h, QQ) + >>> R.dup_invert(f, h) Traceback (most recent call last): ... NotInvertible: zero divisor @@ -174,6 +179,7 @@ else: raise NotInvertible("zero divisor") + def dmp_invert(f, g, u, K): """ Compute multiplicative inverse of `f` modulo `g` in `F[X]`. @@ -181,8 +187,8 @@ Examples ======== - >>> from sympy.polys.domains import QQ - >>> from sympy.polys.euclidtools import dmp_invert + >>> from sympy.polys import ring, QQ + >>> R, x = ring("x", QQ) """ if not u: @@ -190,6 +196,7 @@ else: raise MultivariatePolynomialError(f, g) + def dup_euclidean_prs(f, g, K): """ Euclidean polynomial remainder sequence (PRS) in `K[x]`. @@ -197,26 +204,26 @@ Examples ======== - >>> from sympy.polys.domains import QQ - >>> from sympy.polys.euclidtools import dup_euclidean_prs + >>> from sympy.polys import ring, QQ + >>> R, x = ring("x", QQ) - >>> f = QQ.map([1, 0, 1, 0, -3, -3, 8, 2, -5]) - >>> g = QQ.map([3, 0, 5, 0, -4, -9, 21]) + >>> f = x**8 + x**6 - 3*x**4 - 3*x**3 + 8*x**2 + 2*x - 5 + >>> g = 3*x**6 + 5*x**4 - 4*x**2 - 9*x + 21 - >>> prs = dup_euclidean_prs(f, g, QQ) + >>> prs = R.dup_euclidean_prs(f, g) >>> prs[0] - [1/1, 0/1, 1/1, 0/1, -3/1, -3/1, 8/1, 2/1, -5/1] + x**8 + x**6 - 3*x**4 - 3*x**3 + 8*x**2 + 2*x - 5 >>> prs[1] - [3/1, 0/1, 5/1, 0/1, -4/1, -9/1, 21/1] + 3*x**6 + 5*x**4 - 4*x**2 - 9*x + 21 >>> prs[2] - [-5/9, 0/1, 1/9, 0/1, -1/3] + -5/9*x**4 + 1/9*x**2 - 1/3 >>> prs[3] - [-117/25, -9/1, 441/25] + -117/25*x**2 - 9*x + 441/25 >>> prs[4] - [233150/19773, -102500/6591] + 233150/19773*x - 102500/6591 >>> prs[5] - [-1288744821/543589225] + -1288744821/543589225 """ prs = [f, g] @@ -229,6 +236,7 @@ return prs + def dmp_euclidean_prs(f, g, u, K): """ Euclidean polynomial remainder sequence (PRS) in `K[X]`. @@ -236,8 +244,8 @@ Examples ======== - >>> from sympy.polys.domains import QQ - >>> from sympy.polys.euclidtools import dmp_euclidean_prs + >>> from sympy.polys import ring, ZZ + >>> R, x,y = ring("x,y", ZZ) """ if not u: @@ -245,6 +253,7 @@ else: raise MultivariatePolynomialError(f, g) + def dup_primitive_prs(f, g, K): """ Primitive polynomial remainder sequence (PRS) in `K[x]`. @@ -252,26 +261,26 @@ Examples ======== - >>> from sympy.polys.domains import ZZ - >>> from sympy.polys.euclidtools import dup_primitive_prs + >>> from sympy.polys import ring, ZZ + >>> R, x = ring("x", ZZ) - >>> f = ZZ.map([1, 0, 1, 0, -3, -3, 8, 2, -5]) - >>> g = ZZ.map([3, 0, 5, 0, -4, -9, 21]) + >>> f = x**8 + x**6 - 3*x**4 - 3*x**3 + 8*x**2 + 2*x - 5 + >>> g = 3*x**6 + 5*x**4 - 4*x**2 - 9*x + 21 - >>> prs = dup_primitive_prs(f, g, ZZ) + >>> prs = R.dup_primitive_prs(f, g) >>> prs[0] - [1, 0, 1, 0, -3, -3, 8, 2, -5] + x**8 + x**6 - 3*x**4 - 3*x**3 + 8*x**2 + 2*x - 5 >>> prs[1] - [3, 0, 5, 0, -4, -9, 21] + 3*x**6 + 5*x**4 - 4*x**2 - 9*x + 21 >>> prs[2] - [-5, 0, 1, 0, -3] + -5*x**4 + x**2 - 3 >>> prs[3] - [13, 25, -49] + 13*x**2 + 25*x - 49 >>> prs[4] - [4663, -6150] + 4663*x - 6150 >>> prs[5] - [1] + 1 """ prs = [f, g] @@ -284,6 +293,7 @@ return prs + def dmp_primitive_prs(f, g, u, K): """ Primitive polynomial remainder sequence (PRS) in `K[X]`. @@ -291,8 +301,8 @@ Examples ======== - >>> from sympy.polys.domains import ZZ - >>> from sympy.polys.euclidtools import dmp_primitive_prs + >>> from sympy.polys import ring, ZZ + >>> R, x,y = ring("x,y", ZZ) """ if not u: @@ -300,6 +310,7 @@ else: raise MultivariatePolynomialError(f, g) + @cythonized("n,m,d,k") def dup_inner_subresultants(f, g, K): """ @@ -313,14 +324,11 @@ Examples ======== - >>> from sympy.polys.domains import ZZ - >>> from sympy.polys.euclidtools import dup_inner_subresultants - - >>> f = ZZ.map([1, 0, 1]) - >>> g = ZZ.map([1, 0, -1]) + >>> from sympy.polys import ring, ZZ + >>> R, x = ring("x", ZZ) - >>> dup_inner_subresultants(f, g, ZZ) - ([[1, 0, 1], [1, 0, -1], [-2]], [-1, -1], [0, 2]) + >>> R.dup_inner_subresultants(x**2 + 1, x**2 - 1) + ([x**2 + 1, x**2 - 1, -2], [-1, -1], [0, 2]) """ n = dup_degree(f) @@ -333,8 +341,8 @@ R = [f, g] d = n - m - b = (-K.one)**(d+1) - c = -K.one + b = (-K.one)**(d + 1) + c = -K.one B, D = [b], [d] @@ -353,21 +361,23 @@ if not d: q = c else: - q = c**(d-1) + q = c**(d - 1) c = K.quo((-lc)**d, q) - b = -lc * c**(m-k) + b = -lc * c**(m - k) - f, g, m, d = g, h, k, m-k + f, g, m, d = g, h, k, m - k B.append(b) D.append(d) h = dup_prem(f, g, K) + h = dup_quo_ground(h, b, K) return R, B, D + def dup_subresultants(f, g, K): """ Computes subresultant PRS of two polynomials in `K[x]`. @@ -375,18 +385,16 @@ Examples ======== - >>> from sympy.polys.domains import ZZ - >>> from sympy.polys.euclidtools import dup_subresultants - - >>> f = ZZ.map([1, 0, 1]) - >>> g = ZZ.map([1, 0, -1]) + >>> from sympy.polys import ring, ZZ + >>> R, x = ring("x", ZZ) - >>> dup_subresultants(f, g, ZZ) - [[1, 0, 1], [1, 0, -1], [-2]] + >>> R.dup_subresultants(x**2 + 1, x**2 - 1) + [x**2 + 1, x**2 - 1, -2] """ return dup_inner_subresultants(f, g, K)[0] + @cythonized("s,i,du,dv,dw") def dup_prs_resultant(f, g, K): """ @@ -395,14 +403,11 @@ Examples ======== - >>> from sympy.polys.domains import ZZ - >>> from sympy.polys.euclidtools import dup_prs_resultant - - >>> f = ZZ.map([1, 0, 1]) - >>> g = ZZ.map([1, 0, -1]) + >>> from sympy.polys import ring, ZZ + >>> R, x = ring("x", ZZ) - >>> dup_prs_resultant(f, g, ZZ) - (4, [[1, 0, 1], [1, 0, -1], [-2]]) + >>> R.dup_prs_resultant(x**2 + 1, x**2 - 1) + (4, [x**2 + 1, x**2 - 1, -2]) """ if not f or not g: @@ -419,17 +424,17 @@ p, q = K.one, K.one for b, d in list(zip(B, D))[:-1]: - du = dup_degree(R[i-1]) + du = dup_degree(R[i - 1]) dv = dup_degree(R[i ]) - dw = dup_degree(R[i+1]) + dw = dup_degree(R[i + 1]) if du % 2 and dv % 2: s = -s - lc, i = dup_LC(R[i], K), i+1 + lc, i = dup_LC(R[i], K), i + 1 - p *= b**dv * lc**(du-dw) - q *= lc**(dv*(1+d)) + p *= b**dv * lc**(du - dw) + q *= lc**(dv*(1 + d)) if s < 0: p = -p @@ -437,29 +442,31 @@ i = dup_degree(R[-2]) res = dup_LC(R[-1], K)**i + res = K.quo(res*p, q) return res, R -def dup_resultant(f, g, K): + +def dup_resultant(f, g, K, includePRS=False): """ Computes resultant of two polynomials in `K[x]`. Examples ======== - >>> from sympy.polys.domains import ZZ - >>> from sympy.polys.euclidtools import dup_resultant - - >>> f = ZZ.map([1, 0, 1]) - >>> g = ZZ.map([1, 0, -1]) + >>> from sympy.polys import ring, ZZ + >>> R, x = ring("x", ZZ) - >>> dup_resultant(f, g, ZZ) + >>> R.dup_resultant(x**2 + 1, x**2 - 1) 4 """ + if includePRS: + return dup_prs_resultant(f, g, K) return dup_prs_resultant(f, g, K)[0] + @cythonized("u,v,n,m,d,k") def dmp_inner_subresultants(f, g, u, K): """ @@ -468,20 +475,20 @@ Examples ======== - >>> from sympy.polys.domains import ZZ - >>> from sympy.polys.euclidtools import dmp_inner_subresultants + >>> from sympy.polys import ring, ZZ + >>> R, x,y = ring("x,y", ZZ) - >>> f = ZZ.map([[3, 0], [], [-1, 0, 0, -4]]) - >>> g = ZZ.map([[1], [1, 0, 0, 0], [-9]]) + >>> f = 3*x**2*y - y**3 - 4 + >>> g = x**2 + x*y**3 - 9 - >>> a = [[3, 0, 0, 0, 0], [1, 0, -27, 4]] - >>> b = [[-3, 0, 0, -12, 1, 0, -54, 8, 729, -216, 16]] + >>> a = 3*x*y**4 + y**3 - 27*y + 4 + >>> b = -3*y**10 - 12*y**7 + y**6 - 54*y**4 + 8*y**3 + 729*y**2 - 216*y + 16 - >>> R = ZZ.map([f, g, a, b]) - >>> B = ZZ.map([[-1], [1], [9, 0, 0, 0, 0, 0, 0, 0, 0]]) - >>> D = ZZ.map([0, 1, 1]) + >>> prs = [f, g, a, b] + >>> beta = [[-1], [1], [9, 0, 0, 0, 0, 0, 0, 0, 0]] + >>> delta = [0, 1, 1] - >>> dmp_inner_subresultants(f, g, 1, ZZ) == (R, B, D) + >>> R.dmp_inner_subresultants(f, g) == (prs, beta, delta) True """ @@ -499,7 +506,7 @@ d = n - m v = u - 1 - b = dmp_pow(dmp_ground(-K.one, v), d+1, v, K) + b = dmp_pow(dmp_ground(-K.one, v), d + 1, v, K) c = dmp_ground(-K.one, v) B, D = [b], [d] @@ -521,22 +528,24 @@ if not d: q = c else: - q = dmp_pow(c, d-1, v, K) + q = dmp_pow(c, d - 1, v, K) c = dmp_quo(p, q, v, K) b = dmp_mul(dmp_neg(lc, v, K), - dmp_pow(c, m-k, v, K), v, K) + dmp_pow(c, m - k, v, K), v, K) - f, g, m, d = g, h, k, m-k + f, g, m, d = g, h, k, m - k B.append(b) D.append(d) h = dmp_prem(f, g, u, K) + h = [ dmp_quo(ch, b, v, K) for ch in h ] return R, B, D + @cythonized("u") def dmp_subresultants(f, g, u, K): """ @@ -545,21 +554,22 @@ Examples ======== - >>> from sympy.polys.domains import ZZ - >>> from sympy.polys.euclidtools import dmp_subresultants + >>> from sympy.polys import ring, ZZ + >>> R, x,y = ring("x,y", ZZ) - >>> f = [[3, 0], [], [-1, 0, 0, -4]] - >>> g = [[1], [1, 0, 0, 0], [-9]] + >>> f = 3*x**2*y - y**3 - 4 + >>> g = x**2 + x*y**3 - 9 - >>> a = [[3, 0, 0, 0, 0], [1, 0, -27, 4]] - >>> b = [[-3, 0, 0, -12, 1, 0, -54, 8, 729, -216, 16]] + >>> a = 3*x*y**4 + y**3 - 27*y + 4 + >>> b = -3*y**10 - 12*y**7 + y**6 - 54*y**4 + 8*y**3 + 729*y**2 - 216*y + 16 - >>> dmp_subresultants(f, g, 1, ZZ) == [f, g, a, b] + >>> R.dmp_subresultants(f, g) == [f, g, a, b] True """ return dmp_inner_subresultants(f, g, u, K)[0] + @cythonized("u,v,s,i,d,du,dv,dw") def dmp_prs_resultant(f, g, u, K): """ @@ -568,16 +578,22 @@ Examples ======== - >>> from sympy.polys.domains import ZZ - >>> from sympy.polys.euclidtools import dmp_prs_resultant + >>> from sympy.polys import ring, ZZ + >>> R, x,y = ring("x,y", ZZ) - >>> f = ZZ.map([[3, 0], [], [-1, 0, 0, -4]]) - >>> g = ZZ.map([[1], [1, 0, 0, 0], [-9]]) + >>> f = 3*x**2*y - y**3 - 4 + >>> g = x**2 + x*y**3 - 9 - >>> a = ZZ.map([[3, 0, 0, 0, 0], [1, 0, -27, 4]]) - >>> b = ZZ.map([[-3, 0, 0, -12, 1, 0, -54, 8, 729, -216, 16]]) + >>> a = 3*x*y**4 + y**3 - 27*y + 4 + >>> b = -3*y**10 - 12*y**7 + y**6 - 54*y**4 + 8*y**3 + 729*y**2 - 216*y + 16 - >>> dmp_prs_resultant(f, g, 1, ZZ) == (b[0], [f, g, a, b]) + >>> res, prs = R.dmp_prs_resultant(f, g) + + >>> res == b # resultant has n-1 variables + False + >>> res == b.drop(x) + True + >>> prs == [f, g, a, b] True """ @@ -585,33 +601,33 @@ return dup_prs_resultant(f, g, K) if dmp_zero_p(f, u) or dmp_zero_p(g, u): - return (dmp_zero(u-1), []) + return (dmp_zero(u - 1), []) R, B, D = dmp_inner_subresultants(f, g, u, K) if dmp_degree(R[-1], u) > 0: - return (dmp_zero(u-1), R) + return (dmp_zero(u - 1), R) if dmp_one_p(R[-2], u, K): return (dmp_LC(R[-1], K), R) - s, i, v = 1, 1, u-1 + s, i, v = 1, 1, u - 1 p = dmp_one(v, K) q = dmp_one(v, K) for b, d in list(zip(B, D))[:-1]: - du = dmp_degree(R[i-1], u) + du = dmp_degree(R[i - 1], u) dv = dmp_degree(R[i ], u) - dw = dmp_degree(R[i+1], u) + dw = dmp_degree(R[i + 1], u) if du % 2 and dv % 2: s = -s - lc, i = dmp_LC(R[i], K), i+1 + lc, i = dmp_LC(R[i], K), i + 1 p = dmp_mul(dmp_mul(p, dmp_pow(b, dv, v, K), v, K), - dmp_pow(lc, du-dw, v, K), v, K) - q = dmp_mul(q, dmp_pow(lc, dv*(1+d), v, K), v, K) + dmp_pow(lc, du - dw, v, K), v, K) + q = dmp_mul(q, dmp_pow(lc, dv*(1 + d), v, K), v, K) _, p, q = dmp_inner_gcd(p, q, v, K) @@ -625,6 +641,7 @@ return res, R + @cythonized("u,v,n,m,N,M,B") def dmp_zz_modular_resultant(f, g, p, u, K): """ @@ -633,14 +650,14 @@ Examples ======== - >>> from sympy.polys.domains import ZZ - >>> from sympy.polys.euclidtools import dmp_zz_modular_resultant + >>> from sympy.polys import ring, ZZ + >>> R, x,y = ring("x,y", ZZ) - >>> f = ZZ.map([[1], [1, 2]]) - >>> g = ZZ.map([[2, 1], [3]]) + >>> f = x + y + 2 + >>> g = 2*x*y + x + 3 - >>> dmp_zz_modular_resultant(f, g, ZZ(5), 1, ZZ) - [-2, 0, 1] + >>> R.dmp_zz_modular_resultant(f, g, 5) + -2*y**2 + 1 """ if not u: @@ -698,10 +715,12 @@ return r + def _collins_crt(r, R, P, p, K): """Wrapper of CRT for Collins's resultant algorithm. """ return gf_int(gf_crt([r, R], [P, p], K), P*p) + @cythonized("u,v,n,m") def dmp_zz_collins_resultant(f, g, u, K): """ @@ -710,14 +729,14 @@ Examples ======== - >>> from sympy.polys.domains import ZZ - >>> from sympy.polys.euclidtools import dmp_zz_collins_resultant + >>> from sympy.polys import ring, ZZ + >>> R, x,y = ring("x,y", ZZ) - >>> f = ZZ.map([[1], [1, 2]]) - >>> g = ZZ.map([[2, 1], [3]]) + >>> f = x + y + 2 + >>> g = 2*x*y + x + 3 - >>> dmp_zz_collins_resultant(f, g, 1, ZZ) - [-2, -5, 1] + >>> R.dmp_zz_collins_resultant(f, g) + -2*y**2 - 5*y + 1 """ @@ -725,7 +744,7 @@ m = dmp_degree(g, u) if n < 0 or m < 0: - return dmp_zero(u-1) + return dmp_zero(u - 1) A = dmp_max_norm(f, u, K) B = dmp_max_norm(g, u, K) @@ -735,7 +754,7 @@ v = u - 1 - B = K(2)*K.factorial(n+m)*A**m*B**n + B = K(2)*K.factorial(K(n + m))*A**m*B**n r, p, P = dmp_zero(v), K.one, K.one while P <= B: @@ -761,6 +780,7 @@ return r + @cythonized("u,n,m") def dmp_qq_collins_resultant(f, g, u, K0): """ @@ -769,21 +789,21 @@ Examples ======== - >>> from sympy.polys.domains import QQ - >>> from sympy.polys.euclidtools import dmp_qq_collins_resultant + >>> from sympy.polys import ring, QQ + >>> R, x,y = ring("x,y", QQ) - >>> f = [[QQ(1,2)], [QQ(1), QQ(2,3)]] - >>> g = [[QQ(2), QQ(1)], [QQ(3)]] + >>> f = QQ(1,2)*x + y + QQ(2,3) + >>> g = 2*x*y + x + 3 - >>> dmp_qq_collins_resultant(f, g, 1, QQ) - [-2/1, -7/3, 5/6] + >>> R.dmp_qq_collins_resultant(f, g) + -2*y**2 - 7/3*y + 5/6 """ n = dmp_degree(f, u) m = dmp_degree(g, u) if n < 0 or m < 0: - return dmp_zero(u-1) + return dmp_zero(u - 1) K1 = K0.get_ring() @@ -794,32 +814,36 @@ g = dmp_convert(g, u, K0, K1) r = dmp_zz_collins_resultant(f, g, u, K1) - r = dmp_convert(r, u-1, K1, K0) + r = dmp_convert(r, u - 1, K1, K0) c = K0.convert(cf**m * cg**n, K1) - return dmp_quo_ground(r, c, u-1, K0) + return dmp_quo_ground(r, c, u - 1, K0) + @cythonized("u") -def dmp_resultant(f, g, u, K): +def dmp_resultant(f, g, u, K, includePRS=False): """ Computes resultant of two polynomials in `K[X]`. Examples ======== - >>> from sympy.polys.domains import ZZ - >>> from sympy.polys.euclidtools import dmp_resultant + >>> from sympy.polys import ring, ZZ + >>> R, x,y = ring("x,y", ZZ) - >>> f = ZZ.map([[3, 0], [], [-1, 0, 0, -4]]) - >>> g = ZZ.map([[1], [1, 0, 0, 0], [-9]]) + >>> f = 3*x**2*y - y**3 - 4 + >>> g = x**2 + x*y**3 - 9 - >>> dmp_resultant(f, g, 1, ZZ) - [-3, 0, 0, -12, 1, 0, -54, 8, 729, -216, 16] + >>> R.dmp_resultant(f, g) + -3*y**10 - 12*y**7 + y**6 - 54*y**4 + 8*y**3 + 729*y**2 - 216*y + 16 """ if not u: - return dup_resultant(f, g, K) + return dup_resultant(f, g, K, includePRS=includePRS) + + if includePRS: + return dmp_prs_resultant(f, g, u, K) if K.has_Field: if K.is_QQ and query('USE_COLLINS_RESULTANT'): @@ -830,6 +854,7 @@ return dmp_prs_resultant(f, g, u, K)[0] + @cythonized("d,s") def dup_discriminant(f, K): """ @@ -838,10 +863,10 @@ Examples ======== - >>> from sympy.polys.domains import ZZ - >>> from sympy.polys.euclidtools import dup_discriminant + >>> from sympy.polys import ring, ZZ + >>> R, x = ring("x", ZZ) - >>> dup_discriminant([ZZ(1), ZZ(2), ZZ(3)], ZZ) + >>> R.dup_discriminant(x**2 + 2*x + 3) -8 """ @@ -850,13 +875,14 @@ if d <= 0: return K.zero else: - s = (-1)**((d*(d-1)) // 2) + s = (-1)**((d*(d - 1)) // 2) c = dup_LC(f, K) r = dup_resultant(f, dup_diff(f, 1, K), K) return K.quo(r, c*K(s)) + @cythonized("u,v,d,s") def dmp_discriminant(f, u, K): """ @@ -865,24 +891,22 @@ Examples ======== - >>> from sympy.polys.domains import ZZ - >>> from sympy.polys.euclidtools import dmp_discriminant + >>> from sympy.polys import ring, ZZ + >>> R, x,y,z,t = ring("x,y,z,t", ZZ) - >>> f = ZZ.map([[[[1]], [[]]], [[[1], []]], [[[1, 0]]]]) - - >>> dmp_discriminant(f, 3, ZZ) - [[[-4, 0]], [[1], [], []]] + >>> R.dmp_discriminant(x**2*y + x*z + t) + -4*y*t + z**2 """ if not u: return dup_discriminant(f, K) - d, v = dmp_degree(f, u), u-1 + d, v = dmp_degree(f, u), u - 1 if d <= 0: return dmp_zero(v) else: - s = (-1)**((d*(d-1)) // 2) + s = (-1)**((d*(d - 1)) // 2) c = dmp_LC(f, K) r = dmp_resultant(f, dmp_diff(f, 1, u, K), u, K) @@ -890,6 +914,7 @@ return dmp_quo(r, c, v, K) + def _dup_rr_trivial_gcd(f, g, K): """Handle trivial cases in GCD algorithm over a ring. """ if not (f or g): @@ -907,6 +932,7 @@ return None + def _dup_ff_trivial_gcd(f, g, K): """Handle trivial cases in GCD algorithm over a field. """ if not (f or g): @@ -918,6 +944,7 @@ else: return None + @cythonized("u") def _dmp_rr_trivial_gcd(f, g, u, K): """Handle trivial cases in GCD algorithm over a ring. """ @@ -941,6 +968,7 @@ else: return None + @cythonized("u") def _dmp_ff_trivial_gcd(f, g, u, K): """Handle trivial cases in GCD algorithm over a field. """ @@ -962,6 +990,7 @@ else: return None + @cythonized("u,v,df,dg") def _dmp_simplify_gcd(f, g, u, K): """Try to eliminate `x_0` from GCD computation in `K[X]`. """ @@ -990,6 +1019,7 @@ return [h], cff, cfg + def dup_rr_prs_gcd(f, g, K): """ Computes polynomial GCD using subresultants over a ring. @@ -1000,14 +1030,11 @@ Examples ======== - >>> from sympy.polys.domains import ZZ - >>> from sympy.polys.euclidtools import dup_rr_prs_gcd + >>> from sympy.polys import ring, ZZ + >>> R, x = ring("x", ZZ) - >>> f = ZZ.map([1, 0, -1]) - >>> g = ZZ.map([1, -3, 2]) - - >>> dup_rr_prs_gcd(f, g, ZZ) - ([1, -1], [1, 1], [1, -2]) + >>> R.dup_rr_prs_gcd(x**2 - 1, x**2 - 3*x + 2) + (x - 1, x + 1, x - 2) """ result = _dup_rr_trivial_gcd(f, g, K) @@ -1033,6 +1060,7 @@ return h, cff, cfg + def dup_ff_prs_gcd(f, g, K): """ Computes polynomial GCD using subresultants over a field. @@ -1043,14 +1071,11 @@ Examples ======== - >>> from sympy.polys.domains import QQ - >>> from sympy.polys.euclidtools import dup_ff_prs_gcd + >>> from sympy.polys import ring, QQ + >>> R, x = ring("x", QQ) - >>> f = QQ.map([1, 0, -1]) - >>> g = QQ.map([1, -3, 2]) - - >>> dup_ff_prs_gcd(f, g, QQ) - ([1/1, -1/1], [1/1, 1/1], [1/1, -2/1]) + >>> R.dup_ff_prs_gcd(x**2 - 1, x**2 - 3*x + 2) + (x - 1, x + 1, x - 2) """ result = _dup_ff_trivial_gcd(f, g, K) @@ -1066,6 +1091,7 @@ return h, cff, cfg + @cythonized("u") def dmp_rr_prs_gcd(f, g, u, K): """ @@ -1077,14 +1103,14 @@ Examples ======== - >>> from sympy.polys.domains import ZZ - >>> from sympy.polys.euclidtools import dmp_rr_prs_gcd + >>> from sympy.polys import ring, ZZ + >>> R, x,y, = ring("x,y", ZZ) - >>> f = ZZ.map([[1], [2, 0], [1, 0, 0]]) - >>> g = ZZ.map([[1], [1, 0], []]) + >>> f = x**2 + 2*x*y + y**2 + >>> g = x**2 + x*y - >>> dmp_rr_prs_gcd(f, g, 1, ZZ) - ([[1], [1, 0]], [[1], [1, 0]], [[1], []]) + >>> R.dmp_rr_prs_gcd(f, g) + (x + y, x + y, x) """ if not u: @@ -1099,7 +1125,7 @@ gc, G = dmp_primitive(g, u, K) h = dmp_subresultants(F, G, u, K)[-1] - c, _, _ = dmp_rr_prs_gcd(fc, gc, u-1, K) + c, _, _ = dmp_rr_prs_gcd(fc, gc, u - 1, K) if K.is_negative(dmp_ground_LC(h, u, K)): h = dmp_neg(h, u, K) @@ -1112,6 +1138,7 @@ return h, cff, cfg + @cythonized("u") def dmp_ff_prs_gcd(f, g, u, K): """ @@ -1123,14 +1150,14 @@ Examples ======== - >>> from sympy.polys.domains import QQ - >>> from sympy.polys.euclidtools import dmp_ff_prs_gcd + >>> from sympy.polys import ring, QQ + >>> R, x,y, = ring("x,y", QQ) - >>> f = [[QQ(1,2)], [QQ(1), QQ(0)], [QQ(1,2), QQ(0), QQ(0)]] - >>> g = [[QQ(1)], [QQ(1), QQ(0)], []] + >>> f = QQ(1,2)*x**2 + x*y + QQ(1,2)*y**2 + >>> g = x**2 + x*y - >>> dmp_ff_prs_gcd(f, g, 1, QQ) - ([[1/1], [1/1, 0/1]], [[1/2], [1/2, 0/1]], [[1/1], []]) + >>> R.dmp_ff_prs_gcd(f, g) + (x + y, 1/2*x + 1/2*y, x) """ if not u: @@ -1145,7 +1172,7 @@ gc, G = dmp_primitive(g, u, K) h = dmp_subresultants(F, G, u, K)[-1] - c, _, _ = dmp_ff_prs_gcd(fc, gc, u-1, K) + c, _, _ = dmp_ff_prs_gcd(fc, gc, u - 1, K) _, h = dmp_primitive(h, u, K) h = dmp_mul_term(h, c, 0, u, K) @@ -1158,6 +1185,7 @@ HEU_GCD_MAX = 6 + def _dup_zz_gcd_interpolate(h, x, K): """Interpolate polynomial GCD from integer GCD. """ f = [] @@ -1169,10 +1197,11 @@ g -= x f.insert(0, g) - h = (h-g) // x + h = (h - g) // x return f + @cythonized("i,df,dg") def dup_zz_heu_gcd(f, g, K): """ @@ -1197,14 +1226,11 @@ Examples ======== - >>> from sympy.polys.domains import ZZ - >>> from sympy.polys.euclidtools import dup_zz_heu_gcd + >>> from sympy.polys import ring, ZZ + >>> R, x = ring("x", ZZ) - >>> f = ZZ.map([1, 0, -1]) - >>> g = ZZ.map([1, -3, 2]) - - >>> dup_zz_heu_gcd(f, g, ZZ) - ([1, -1], [1, 1], [1, -2]) + >>> R.dup_zz_heu_gcd(x**2 - 1, x**2 - 3*x + 2) + (x - 1, x + 1, x - 2) References ========== @@ -1228,7 +1254,7 @@ f_norm = dup_max_norm(f, K) g_norm = dup_max_norm(g, K) - B = 2*min(f_norm, g_norm) + 29 + B = K(2*min(f_norm, g_norm) + 29) x = max(min(B, 99*K.sqrt(B)), 2*min(f_norm // abs(dup_LC(f, K)), @@ -1282,6 +1308,7 @@ raise HeuristicGCDFailed('no luck') + @cythonized("v") def _dmp_zz_gcd_interpolate(h, x, v, K): """Interpolate polynomial GCD from integer GCD. """ @@ -1294,11 +1321,12 @@ h = dmp_sub(h, g, v, K) h = dmp_quo_ground(h, x, v, K) - if K.is_negative(dmp_ground_LC(f, v+1, K)): - return dmp_neg(f, v+1, K) + if K.is_negative(dmp_ground_LC(f, v + 1, K)): + return dmp_neg(f, v + 1, K) else: return f + @cythonized("u,v,i,dg,df") def dmp_zz_heu_gcd(f, g, u, K): """ @@ -1325,14 +1353,14 @@ Examples ======== - >>> from sympy.polys.domains import ZZ - >>> from sympy.polys.euclidtools import dmp_zz_heu_gcd + >>> from sympy.polys import ring, ZZ + >>> R, x,y, = ring("x,y", ZZ) - >>> f = ZZ.map([[1], [2, 0], [1, 0, 0]]) - >>> g = ZZ.map([[1], [1, 0], []]) + >>> f = x**2 + 2*x*y + y**2 + >>> g = x**2 + x*y - >>> dmp_zz_heu_gcd(f, g, 1, ZZ) - ([[1], [1, 0]], [[1], [1, 0]], [[1], []]) + >>> R.dmp_zz_heu_gcd(f, g) + (x + y, x + y, x) References ========== @@ -1353,7 +1381,7 @@ f_norm = dmp_max_norm(f, u, K) g_norm = dmp_max_norm(g, u, K) - B = 2*min(f_norm, g_norm) + 29 + B = K(2*min(f_norm, g_norm) + 29) x = max(min(B, 99*K.sqrt(B)), 2*min(f_norm // abs(dmp_ground_LC(f, u, K)), @@ -1406,6 +1434,7 @@ raise HeuristicGCDFailed('no luck') + def dup_qq_heu_gcd(f, g, K0): """ Heuristic polynomial GCD in `Q[x]`. @@ -1416,14 +1445,14 @@ Examples ======== - >>> from sympy.polys.domains import QQ - >>> from sympy.polys.euclidtools import dup_qq_heu_gcd + >>> from sympy.polys import ring, QQ + >>> R, x = ring("x", QQ) - >>> f = [QQ(1,2), QQ(7,4), QQ(3,2)] - >>> g = [QQ(1,2), QQ(1), QQ(0)] + >>> f = QQ(1,2)*x**2 + QQ(7,4)*x + QQ(3,2) + >>> g = QQ(1,2)*x**2 + x - >>> dup_qq_heu_gcd(f, g, QQ) - ([1/1, 2/1], [1/2, 3/4], [1/2, 0/1]) + >>> R.dup_qq_heu_gcd(f, g) + (x + 2, 1/2*x + 3/4, 1/2*x) """ result = _dup_ff_trivial_gcd(f, g, K0) @@ -1454,6 +1483,7 @@ return h, cff, cfg + @cythonized("u") def dmp_qq_heu_gcd(f, g, u, K0): """ @@ -1465,14 +1495,14 @@ Examples ======== - >>> from sympy.polys.domains import QQ - >>> from sympy.polys.euclidtools import dmp_qq_heu_gcd + >>> from sympy.polys import ring, QQ + >>> R, x,y, = ring("x,y", QQ) - >>> f = [[QQ(1,4)], [QQ(1), QQ(0)], [QQ(1), QQ(0), QQ(0)]] - >>> g = [[QQ(1,2)], [QQ(1), QQ(0)], []] + >>> f = QQ(1,4)*x**2 + x*y + y**2 + >>> g = QQ(1,2)*x**2 + x*y - >>> dmp_qq_heu_gcd(f, g, 1, QQ) - ([[1/1], [2/1, 0/1]], [[1/4], [1/2, 0/1]], [[1/2], []]) + >>> R.dmp_qq_heu_gcd(f, g) + (x + 2*y, 1/4*x + 1/2*y, 1/2*x) """ result = _dmp_ff_trivial_gcd(f, g, u, K0) @@ -1503,6 +1533,7 @@ return h, cff, cfg + def dup_inner_gcd(f, g, K): """ Computes polynomial GCD and cofactors of `f` and `g` in `K[x]`. @@ -1513,14 +1544,11 @@ Examples ======== - >>> from sympy.polys.domains import ZZ - >>> from sympy.polys.euclidtools import dup_inner_gcd - - >>> f = ZZ.map([1, 0, -1]) - >>> g = ZZ.map([1, -3, 2]) + >>> from sympy.polys import ring, ZZ + >>> R, x = ring("x", ZZ) - >>> dup_inner_gcd(f, g, ZZ) - ([1, -1], [1, 1], [1, -2]) + >>> R.dup_inner_gcd(x**2 - 1, x**2 - 3*x + 2) + (x - 1, x + 1, x - 2) """ if K.has_Field or not K.is_Exact: @@ -1540,6 +1568,7 @@ return dup_rr_prs_gcd(f, g, K) + @cythonized("u") def _dmp_inner_gcd(f, g, u, K): """Helper function for `dmp_inner_gcd()`. """ @@ -1560,6 +1589,7 @@ return dmp_rr_prs_gcd(f, g, u, K) + @cythonized("u") def dmp_inner_gcd(f, g, u, K): """ @@ -1571,14 +1601,14 @@ Examples ======== - >>> from sympy.polys.domains import ZZ - >>> from sympy.polys.euclidtools import dmp_inner_gcd + >>> from sympy.polys import ring, ZZ + >>> R, x,y, = ring("x,y", ZZ) - >>> f = ZZ.map([[1], [2, 0], [1, 0, 0]]) - >>> g = ZZ.map([[1], [1, 0], []]) + >>> f = x**2 + 2*x*y + y**2 + >>> g = x**2 + x*y - >>> dmp_inner_gcd(f, g, 1, ZZ) - ([[1], [1, 0]], [[1], [1, 0]], [[1], []]) + >>> R.dmp_inner_gcd(f, g) + (x + y, x + y, x) """ if not u: @@ -1591,6 +1621,7 @@ dmp_inflate(cff, J, u, K), dmp_inflate(cfg, J, u, K)) + def dup_gcd(f, g, K): """ Computes polynomial GCD of `f` and `g` in `K[x]`. @@ -1598,18 +1629,16 @@ Examples ======== - >>> from sympy.polys.domains import ZZ - >>> from sympy.polys.euclidtools import dup_gcd - - >>> f = ZZ.map([1, 0, -1]) - >>> g = ZZ.map([1, -3, 2]) + >>> from sympy.polys import ring, ZZ + >>> R, x = ring("x", ZZ) - >>> dup_gcd(f, g, ZZ) - [1, -1] + >>> R.dup_gcd(x**2 - 1, x**2 - 3*x + 2) + x - 1 """ return dup_inner_gcd(f, g, K)[0] + @cythonized("u") def dmp_gcd(f, g, u, K): """ @@ -1618,18 +1647,19 @@ Examples ======== - >>> from sympy.polys.domains import ZZ - >>> from sympy.polys.euclidtools import dmp_gcd + >>> from sympy.polys import ring, ZZ + >>> R, x,y, = ring("x,y", ZZ) - >>> f = ZZ.map([[1], [2, 0], [1, 0, 0]]) - >>> g = ZZ.map([[1], [1, 0], []]) + >>> f = x**2 + 2*x*y + y**2 + >>> g = x**2 + x*y - >>> dmp_gcd(f, g, 1, ZZ) - [[1], [1, 0]] + >>> R.dmp_gcd(f, g) + x + y """ return dmp_inner_gcd(f, g, u, K)[0] + def dup_rr_lcm(f, g, K): """ Computes polynomial LCM over a ring in `K[x]`. @@ -1637,14 +1667,11 @@ Examples ======== - >>> from sympy.polys.domains import ZZ - >>> from sympy.polys.euclidtools import dup_rr_lcm - - >>> f = ZZ.map([1, 0, -1]) - >>> g = ZZ.map([1, -3, 2]) + >>> from sympy.polys import ring, ZZ + >>> R, x = ring("x", ZZ) - >>> dup_rr_lcm(f, g, ZZ) - [1, -2, -1, 2] + >>> R.dup_rr_lcm(x**2 - 1, x**2 - 3*x + 2) + x**3 - 2*x**2 - x + 2 """ fc, f = dup_primitive(f, K) @@ -1657,6 +1684,7 @@ return dup_mul_ground(h, c, K) + def dup_ff_lcm(f, g, K): """ Computes polynomial LCM over a field in `K[x]`. @@ -1664,14 +1692,14 @@ Examples ======== - >>> from sympy.polys.domains import QQ - >>> from sympy.polys.euclidtools import dup_ff_lcm + >>> from sympy.polys import ring, QQ + >>> R, x = ring("x", QQ) - >>> f = [QQ(1,2), QQ(7,4), QQ(3,2)] - >>> g = [QQ(1,2), QQ(1), QQ(0)] + >>> f = QQ(1,2)*x**2 + QQ(7,4)*x + QQ(3,2) + >>> g = QQ(1,2)*x**2 + x - >>> dup_ff_lcm(f, g, QQ) - [1/1, 7/2, 3/1, 0/1] + >>> R.dup_ff_lcm(f, g) + x**3 + 7/2*x**2 + 3*x """ h = dup_quo(dup_mul(f, g, K), @@ -1679,6 +1707,7 @@ return dup_monic(h, K) + def dup_lcm(f, g, K): """ Computes polynomial LCM of `f` and `g` in `K[x]`. @@ -1686,14 +1715,11 @@ Examples ======== - >>> from sympy.polys.domains import ZZ - >>> from sympy.polys.euclidtools import dup_lcm - - >>> f = ZZ.map([1, 0, -1]) - >>> g = ZZ.map([1, -3, 2]) + >>> from sympy.polys import ring, ZZ + >>> R, x = ring("x", ZZ) - >>> dup_lcm(f, g, ZZ) - [1, -2, -1, 2] + >>> R.dup_lcm(x**2 - 1, x**2 - 3*x + 2) + x**3 - 2*x**2 - x + 2 """ if K.has_Field or not K.is_Exact: @@ -1701,6 +1727,7 @@ else: return dup_rr_lcm(f, g, K) + @cythonized("u") def dmp_rr_lcm(f, g, u, K): """ @@ -1709,14 +1736,14 @@ Examples ======== - >>> from sympy.polys.domains import ZZ - >>> from sympy.polys.euclidtools import dmp_rr_lcm + >>> from sympy.polys import ring, ZZ + >>> R, x,y, = ring("x,y", ZZ) - >>> f = ZZ.map([[1], [2, 0], [1, 0, 0]]) - >>> g = ZZ.map([[1], [1, 0], []]) + >>> f = x**2 + 2*x*y + y**2 + >>> g = x**2 + x*y - >>> dmp_rr_lcm(f, g, 1, ZZ) - [[1], [2, 0], [1, 0, 0], []] + >>> R.dmp_rr_lcm(f, g) + x**3 + 2*x**2*y + x*y**2 """ fc, f = dmp_ground_primitive(f, u, K) @@ -1729,6 +1756,7 @@ return dmp_mul_ground(h, c, u, K) + @cythonized("u") def dmp_ff_lcm(f, g, u, K): """ @@ -1737,14 +1765,14 @@ Examples ======== - >>> from sympy.polys.domains import QQ - >>> from sympy.polys.euclidtools import dmp_ff_lcm + >>> from sympy.polys import ring, QQ + >>> R, x,y, = ring("x,y", QQ) - >>> f = [[QQ(1,4)], [QQ(1), QQ(0)], [QQ(1), QQ(0), QQ(0)]] - >>> g = [[QQ(1,2)], [QQ(1), QQ(0)], []] + >>> f = QQ(1,4)*x**2 + x*y + y**2 + >>> g = QQ(1,2)*x**2 + x*y - >>> dmp_ff_lcm(f, g, 1, QQ) - [[1/1], [4/1, 0/1], [4/1, 0/1, 0/1], []] + >>> R.dmp_ff_lcm(f, g) + x**3 + 4*x**2*y + 4*x*y**2 """ h = dmp_quo(dmp_mul(f, g, u, K), @@ -1752,6 +1780,7 @@ return dmp_ground_monic(h, u, K) + @cythonized("u") def dmp_lcm(f, g, u, K): """ @@ -1760,14 +1789,14 @@ Examples ======== - >>> from sympy.polys.domains import ZZ - >>> from sympy.polys.euclidtools import dmp_lcm + >>> from sympy.polys import ring, ZZ + >>> R, x,y, = ring("x,y", ZZ) - >>> f = ZZ.map([[1], [2, 0], [1, 0, 0]]) - >>> g = ZZ.map([[1], [1, 0], []]) + >>> f = x**2 + 2*x*y + y**2 + >>> g = x**2 + x*y - >>> dmp_lcm(f, g, 1, ZZ) - [[1], [2, 0], [1, 0, 0], []] + >>> R.dmp_lcm(f, g) + x**3 + 2*x**2*y + x*y**2 """ if not u: @@ -1778,6 +1807,7 @@ else: return dmp_rr_lcm(f, g, u, K) + @cythonized("u,v") def dmp_content(f, u, K): """ @@ -1786,16 +1816,14 @@ Examples ======== - >>> from sympy.polys.domains import ZZ - >>> from sympy.polys.euclidtools import dmp_content - - >>> f = ZZ.map([[2, 6], [4, 12]]) + >>> from sympy.polys import ring, ZZ + >>> R, x,y, = ring("x,y", ZZ) - >>> dmp_content(f, 1, ZZ) - [2, 6] + >>> R.dmp_content(2*x*y + 6*x + 4*y + 12) + 2*y + 6 """ - cont, v = dmp_LC(f, K), u-1 + cont, v = dmp_LC(f, K), u - 1 if dmp_zero_p(f, u): return cont @@ -1811,6 +1839,7 @@ else: return cont + @cythonized("u,v") def dmp_primitive(f, u, K): """ @@ -1819,22 +1848,21 @@ Examples ======== - >>> from sympy.polys.domains import ZZ - >>> from sympy.polys.euclidtools import dmp_primitive - - >>> f = ZZ.map([[2, 6], [4, 12]]) + >>> from sympy.polys import ring, ZZ + >>> R, x,y, = ring("x,y", ZZ) - >>> dmp_primitive(f, 1, ZZ) - ([2, 6], [[1], [2]]) + >>> R.dmp_primitive(2*x*y + 6*x + 4*y + 12) + (2*y + 6, x + 2) """ - cont, v = dmp_content(f, u, K), u-1 + cont, v = dmp_content(f, u, K), u - 1 if dmp_zero_p(f, u) or dmp_one_p(cont, v, K): return cont, f else: return cont, [ dmp_quo(c, cont, v, K) for c in f ] + def dup_cancel(f, g, K, include=True): """ Cancel common factors in a rational function `f/g`. @@ -1842,18 +1870,16 @@ Examples ======== - >>> from sympy.polys.domains import ZZ - >>> from sympy.polys.euclidtools import dup_cancel - - >>> f = ZZ.map([2, 0, -2]) - >>> g = ZZ.map([1, -2, 1]) + >>> from sympy.polys import ring, ZZ + >>> R, x = ring("x", ZZ) - >>> dup_cancel(f, g, ZZ) - ([2, 2], [1, -1]) + >>> R.dup_cancel(2*x**2 - 2, x**2 - 2*x + 1) + (2*x + 2, x - 1) """ return dmp_cancel(f, g, 0, K, include=include) + def dmp_cancel(f, g, u, K, include=True): """ Cancel common factors in a rational function `f/g`. @@ -1861,14 +1887,11 @@ Examples ======== - >>> from sympy.polys.domains import ZZ - >>> from sympy.polys.euclidtools import dmp_cancel - - >>> f = ZZ.map([[2], [0], [-2]]) - >>> g = ZZ.map([[1], [-2], [1]]) + >>> from sympy.polys import ring, ZZ + >>> R, x,y = ring("x,y", ZZ) - >>> dmp_cancel(f, g, 1, ZZ) - ([[2], [2]], [[1], [-1]]) + >>> R.dmp_cancel(2*x**2 - 2, x**2 - 2*x + 1) + (2*x + 2, x - 1) """ K0 = None diff -Nru python3-sympy-0.7.2/sympy/polys/factortools.py python3-sympy-0.7.3/sympy/polys/factortools.py --- python3-sympy-0.7.2/sympy/polys/factortools.py 2012-10-17 03:02:22.000000000 +0000 +++ python3-sympy-0.7.3/sympy/polys/factortools.py 2013-07-13 17:53:32.000000000 +0000 @@ -74,6 +74,7 @@ from math import ceil as _ceil, log as _log + @cythonized("k") def dup_trial_division(f, factors, K): """Determine multiplicities of factors using trial division. """ @@ -86,7 +87,7 @@ q, r = dup_div(f, factor, K) if not r: - f, k = q, k+1 + f, k = q, k + 1 else: break @@ -94,6 +95,7 @@ return _sort_factors(result) + @cythonized("u,k") def dmp_trial_division(f, factors, u, K): """Determine multiplicities of factors using trial division. """ @@ -106,7 +108,7 @@ q, r = dmp_div(f, factor, u, K) if dmp_zero_p(r, u): - f, k = q, k+1 + f, k = q, k + 1 else: break @@ -114,13 +116,15 @@ return _sort_factors(result) + def dup_zz_mignotte_bound(f, K): """Mignotte bound for univariate polynomials in `K[x]`. """ a = dup_max_norm(f, K) b = abs(dup_LC(f, K)) n = dup_degree(f) - return K.sqrt(K(n+1))*2**n*a*b + return K.sqrt(K(n + 1))*2**n*a*b + def dmp_zz_mignotte_bound(f, u, K): """Mignotte bound for multivariate polynomials in `K[X]`. """ @@ -128,7 +132,8 @@ b = abs(dmp_ground_LC(f, u, K)) n = sum(dmp_degree_list(f, u)) - return K.sqrt(K(n+1))*2**n*a*b + return K.sqrt(K(n + 1))*2**n*a*b + def dup_zz_hensel_step(m, f, g, h, s, t, K): """ @@ -186,6 +191,7 @@ return G, H, S, T + @cythonized("l,r,k,d") def dup_zz_hensel_lift(p, f, f_list, l, K): """ @@ -228,7 +234,7 @@ h = gf_from_int_poly(f_list[k], p) - for f_i in f_list[k+1:]: + for f_i in f_list[k + 1:]: h = gf_mul(h, gf_from_int_poly(f_i, p), p, K) s, t, _ = gf_gcdex(g, h, p, K) @@ -238,11 +244,18 @@ s = gf_to_int_poly(s, p) t = gf_to_int_poly(t, p) - for _ in range(1, d+1): + for _ in range(1, d + 1): (g, h, s, t), m = dup_zz_hensel_step(m, f, g, h, s, t, K), m**2 return dup_zz_hensel_lift(p, g, f_list[:k], l, K) \ - + dup_zz_hensel_lift(p, h, f_list[k:], l, K) + + dup_zz_hensel_lift(p, h, f_list[k:], l, K) + +def _test_pl(fc, q, pl): + if q > pl // 2: + q = q - pl + if not q: + return True + return fc % q == 0 @cythonized("l,s") def dup_zz_zassenhaus(f, K): @@ -252,52 +265,81 @@ if n == 1: return [f] + fc = f[-1] A = dup_max_norm(f, K) b = dup_LC(f, K) - B = int(abs(K.sqrt(K(n+1))*2**n*A*b)) - C = int((n+1)**(2*n)*A**(2*n-1)) + B = int(abs(K.sqrt(K(n + 1))*2**n*A*b)) + C = int((n + 1)**(2*n)*A**(2*n - 1)) gamma = int(_ceil(2*_log(C, 2))) bound = int(2*gamma*_log(gamma)) - - for p in range(3, bound+1): - if not isprime(p) or b % p == 0: + a = [] + # choose a prime number `p` such that `f` be square free in Z_p + # if there are many factors in Z_p, choose among a few different `p` + # the one with fewer factors + for px in range(3, bound + 1): + if not isprime(px) or b % px == 0: continue - p = K.convert(p) + px = K.convert(px) - F = gf_from_int_poly(f, p) + F = gf_from_int_poly(f, px) - if gf_sqf_p(F, p, K): + if not gf_sqf_p(F, px, K): + continue + fsqfx = gf_factor_sqf(F, px, K)[1] + a.append((px, fsqfx)) + if len(fsqfx) < 15 or len(a) > 4: break + p, fsqf = min(a, key=lambda x: len(x[1])) l = int(_ceil(_log(2*B + 1, p))) - modular = [] - - for ff in gf_factor_sqf(F, p, K)[1]: - modular.append(gf_to_int_poly(ff, p)) + modular = [gf_to_int_poly(ff, p) for ff in fsqf] g = dup_zz_hensel_lift(p, f, modular, l, K) sorted_T = list(range(len(g))) T = set(sorted_T) factors, s = [], 1 + pl = p**l while 2*s <= len(T): for S in subsets(sorted_T, s): - G, H = [b], [b] + # lift the constant coefficient of the product `G` of the factors + # in the subset `S`; if it is does not divide `fc`, `G` does + # not divide the input polynomial + + if b == 1: + q = 1 + for i in S: + q = q*g[i][-1] + q = q % pl + if not _test_pl(fc, q, pl): + continue + else: + G = [b] + for i in S: + G = dup_mul(G, g[i], K) + G = dup_trunc(G, pl, K) + G1 = dup_primitive(G, K)[1] + q = G1[-1] + if q and fc % q != 0: + continue + H = [b] S = set(S) T_S = T - S - for i in S: - G = dup_mul(G, g[i], K) + if b == 1: + G = [b] + for i in S: + G = dup_mul(G, g[i], K) + G = dup_trunc(G, pl, K) for i in T_S: H = dup_mul(H, g[i], K) - G = dup_trunc(G, p**l, K) - H = dup_trunc(H, p**l, K) + H = dup_trunc(H, pl, K) G_norm = dup_l1_norm(G, K) H_norm = dup_l1_norm(H, K) @@ -306,7 +348,6 @@ T = T_S sorted_T = [i for i in sorted_T if i not in S] - G = dup_primitive(G, K)[1] f = dup_primitive(H, K)[1] @@ -319,6 +360,7 @@ return factors + [f] + def dup_zz_irreducible_p(f, K): """Test irreducibility using Eisenstein's criterion. """ lc = dup_LC(f, K) @@ -333,6 +375,7 @@ if (lc % p) and (tc % p**2): return True + @cythonized("n,i") def dup_cyclotomic_p(f, K, irreducible=False): """ @@ -341,15 +384,15 @@ Examples ======== - >>> from sympy.polys.factortools import dup_cyclotomic_p - >>> from sympy.polys.domains import ZZ + >>> from sympy.polys import ring, ZZ + >>> R, x = ring("x", ZZ) - >>> f = [1, 0, 1, 0, 0, 0,-1, 0, 1, 0,-1, 0, 0, 0, 1, 0, 1] - >>> dup_cyclotomic_p(f, ZZ) + >>> f = x**16 + x**14 - x**10 + x**8 - x**6 + x**2 + 1 + >>> R.dup_cyclotomic_p(f) False - >>> g = [1, 0, 1, 0, 0, 0,-1, 0,-1, 0,-1, 0, 0, 0, 1, 0, 1] - >>> dup_cyclotomic_p(g, ZZ) + >>> g = x**16 + x**14 - x**10 - x**8 - x**6 + x**2 + 1 + >>> R.dup_cyclotomic_p(g) True """ @@ -380,7 +423,7 @@ for i in range(n, -1, -2): g.insert(0, f[i]) - for i in range(n-1, -1, -2): + for i in range(n - 1, -1, -2): h.insert(0, f[i]) g = dup_sqr(dup_strip(g), K) @@ -409,20 +452,22 @@ return False + @cythonized("n,p,k") def dup_zz_cyclotomic_poly(n, K): """Efficiently generate n-th cyclotomic polnomial. """ - h = [K.one,-K.one] + h = [K.one, -K.one] for p, k in factorint(n).items(): h = dup_quo(dup_inflate(h, p, K), h, K) - h = dup_inflate(h, p**(k-1), K) + h = dup_inflate(h, p**(k - 1), K) return h + @cythonized("n,p,k,i") def _dup_cyclotomic_decompose(n, K): - H = [[K.one,-K.one]] + H = [[K.one, -K.one]] for p, k in factorint(n).items(): Q = [ dup_quo(dup_inflate(h, p, K), h, K) for h in H ] @@ -434,6 +479,7 @@ return H + @cythonized("n") def dup_zz_cyclotomic_factor(f, K): """ @@ -478,6 +524,7 @@ return H + @cythonized("n") def dup_zz_factor_sqf(f, K): """Factor square-free (non-primitive) polyomials in `Z[x]`. """ @@ -491,11 +538,11 @@ if n <= 0: return cont, [] elif n == 1: - return cont, [(g, 1)] + return cont, [g] if query('USE_IRREDUCIBLE_IN_FACTOR'): if dup_zz_irreducible_p(g, K): - return cont, [(g, 1)] + return cont, [g] factors = None @@ -507,6 +554,7 @@ return cont, _sort_factors(factors, multiple=False) + @cythonized("n,k") def dup_zz_factor(f, K): """ @@ -528,11 +576,11 @@ Consider polynomial `f = 2*x**4 - 2`:: - >>> from sympy.polys.factortools import dup_zz_factor - >>> from sympy.polys.domains import ZZ + >>> from sympy.polys import ring, ZZ + >>> R, x = ring("x", ZZ) - >>> dup_zz_factor([2, 0, 0, 0, -2], ZZ) - (2, [([1, -1], 1), ([1, 1], 1), ([1, 0, 1], 1)]) + >>> R.dup_zz_factor(2*x**4 - 2) + (2, [(x - 1, 1), (x + 1, 1), (x**2 + 1, 1)]) In result we got the following factorization:: @@ -583,7 +631,7 @@ q, r = dup_div(f, h, K) if not r: - f, k = q, k+1 + f, k = q, k + 1 else: break @@ -591,6 +639,7 @@ return cont, _sort_factors(factors) + def dmp_zz_wang_non_divisors(E, cs, ct, K): """Wang/EEZ: Compute a set of valid divisors. """ result = [ cs*ct ] @@ -610,10 +659,11 @@ return result[1:] + @cythonized("u,v") def dmp_zz_wang_test_points(f, T, ct, A, u, K): """Wang/EEZ: Test evaluation points for suitability. """ - if not dmp_eval_tail(dmp_LC(f, K), A, u-1, K): + if not dmp_eval_tail(dmp_LC(f, K), A, u - 1, K): raise EvaluationFailed('no luck') g = dmp_eval_tail(f, A, u, K) @@ -626,7 +676,7 @@ if K.is_negative(dup_LC(h, K)): c, h = -c, dup_neg(h, K) - v = u-1 + v = u - 1 E = [ dmp_eval_tail(t, A, v, K) for t, _ in T ] D = dmp_zz_wang_non_divisors(E, c, ct, K) @@ -636,10 +686,11 @@ else: raise EvaluationFailed('no luck') + @cythonized("u,v,i,j,k") def dmp_zz_wang_lead_coeffs(f, T, cs, E, H, A, u, K): """Wang/EEZ: Compute correct leading coefficients. """ - C, J, v = [], [0]*len(E), u-1 + C, J, v = [], [0]*len(E), u - 1 for h in H: c = dmp_one(v, K) @@ -649,7 +700,7 @@ k, e, (t, _) = 0, E[i], T[i] while not (d % e): - d, k = d//e, k+1 + d, k = d//e, k + 1 if k != 0: c, J[i] = dmp_mul(c, dmp_pow(t, k, v, K), v, K), 1 @@ -657,7 +708,7 @@ C.append(c) if any(not j for j in J): - raise ExtraneousFactors # pragma: no cover + raise ExtraneousFactors # pragma: no cover CC, HH = [], [] @@ -686,10 +737,11 @@ CCC.append(dmp_mul_ground(c, cs, v, K)) HHH.append(dmp_mul_ground(h, cs, 0, K)) - f = dmp_mul_ground(f, cs**(len(H)-1), u, K) + f = dmp_mul_ground(f, cs**(len(H) - 1), u, K) return f, HHH, CCC + @cythonized("m") def dup_zz_diophantine(F, m, p, K): """Wang/EEZ: Solve univariate Diophantine equations. """ @@ -738,6 +790,7 @@ return result + @cythonized("u,v,d,n,i,j,k") def dmp_zz_diophantine(F, c, A, d, p, u, K): """Wang/EEZ: Solve multivariate Diophantine equations. """ @@ -749,7 +802,7 @@ if not coeff: continue - T = dup_zz_diophantine(F, n-i, p, K) + T = dup_zz_diophantine(F, n - i, p, K) for j, (s, t) in enumerate(list(zip(S, T))): t = dup_mul_ground(t, coeff, K) @@ -780,15 +833,15 @@ m = dmp_nest([K.one, -a], n, K) M = dmp_one(n, K) - for k in range(0, d): + for k in K.map(range(0, d)): if dmp_zero_p(c, u): break M = dmp_mul(M, m, u, K) - C = dmp_diff_eval_in(c, k+1, a, n, u, K) + C = dmp_diff_eval_in(c, k + 1, a, n, u, K) if not dmp_zero_p(C, v): - C = dmp_quo_ground(C, K.factorial(k+1), v, K) + C = dmp_quo_ground(C, K.factorial(k + 1), v, K) T = dmp_zz_diophantine(G, C, A, d, p, v, K) for i, t in enumerate(T): @@ -806,27 +859,28 @@ return S + @cythonized("u,v,d,dj,n,i,j,k,w") def dmp_zz_wang_hensel_lifting(f, H, LC, A, p, u, K): """Wang/EEZ: Parallel Hensel lifting algorithm. """ - S, n, v = [f], len(A), u-1 + S, n, v = [f], len(A), u - 1 H = list(H) for i, a in enumerate(reversed(A[1:])): - s = dmp_eval_in(S[0], a, n-i, u-i, K) - S.insert(0, dmp_ground_trunc(s, p, v-i, K)) + s = dmp_eval_in(S[0], a, n - i, u - i, K) + S.insert(0, dmp_ground_trunc(s, p, v - i, K)) d = max(dmp_degree_list(f, u)[1:]) - for j, s, a in zip(range(2, n+2), S, A): - G, w = list(H), j-1 + for j, s, a in zip(range(2, n + 2), S, A): + G, w = list(H), j - 1 - I, J = A[:j-2], A[j-1:] + I, J = A[:j - 2], A[j - 1:] for i, (h, lc) in enumerate(list(zip(H, LC))): - lc = dmp_ground_trunc(dmp_eval_tail(lc, J, v, K), p, w-1, K) - H[i] = [lc] + dmp_raise(h[1:], 1, w-1, K) + lc = dmp_ground_trunc(dmp_eval_tail(lc, J, v, K), p, w - 1, K) + H[i] = [lc] + dmp_raise(h[1:], 1, w - 1, K) m = dmp_nest([K.one, -a], w, K) M = dmp_one(w, K) @@ -835,29 +889,30 @@ dj = dmp_degree_in(s, w, w) - for k in range(0, dj): + for k in K.map(range(0, dj)): if dmp_zero_p(c, w): break M = dmp_mul(M, m, w, K) - C = dmp_diff_eval_in(c, k+1, a, w, w, K) + C = dmp_diff_eval_in(c, k + 1, a, w, w, K) - if not dmp_zero_p(C, w-1): - C = dmp_quo_ground(C, K.factorial(k+1), w-1, K) - T = dmp_zz_diophantine(G, C, I, d, p, w-1, K) + if not dmp_zero_p(C, w - 1): + C = dmp_quo_ground(C, K.factorial(k + 1), w - 1, K) + T = dmp_zz_diophantine(G, C, I, d, p, w - 1, K) for i, (h, t) in enumerate(list(zip(H, T))): - h = dmp_add_mul(h, dmp_raise(t, 1, w-1, K), M, w, K) + h = dmp_add_mul(h, dmp_raise(t, 1, w - 1, K), M, w, K) H[i] = dmp_ground_trunc(h, p, w, K) h = dmp_sub(s, dmp_expand(H, w, K), w, K) c = dmp_ground_trunc(h, p, w, K) if dmp_expand(H, u, K) != f: - raise ExtraneousFactors # pragma: no cover + raise ExtraneousFactors # pragma: no cover else: return H + @cythonized("u,mod,i,j,s_arg,negative") def dmp_zz_wang(f, u, K, mod=None, seed=None): """ @@ -893,7 +948,7 @@ randint = _randint(seed) - ct, T = dmp_zz_factor(dmp_LC(f, K), u-1, K) + ct, T = dmp_zz_factor(dmp_LC(f, K), u - 1, K) b = dmp_zz_mignotte_bound(f, u, K) p = K(nextprime(b)) @@ -943,7 +998,7 @@ rr = len(H) if r is not None: - if rr != r: # pragma: no cover + if rr != r: # pragma: no cover if rr < r: configs, r = [], rr else: @@ -981,11 +1036,12 @@ try: f, H, LC = dmp_zz_wang_lead_coeffs(f, T, cs, E, H, A, u, K) factors = dmp_zz_wang_hensel_lifting(f, H, LC, A, p, u, K) - except ExtraneousFactors: # pragma: no cover + except ExtraneousFactors: # pragma: no cover if query('EEZ_RESTART_IF_NEEDED'): - return dmp_zz_wang(orig_f, u, K, mod+1) + return dmp_zz_wang(orig_f, u, K, mod + 1) else: - raise ExtraneousFactors("we need to restart algorithm with better parameters") + raise ExtraneousFactors( + "we need to restart algorithm with better parameters") negative, result = 0, [] @@ -999,6 +1055,7 @@ return result + @cythonized("u,d,k") def dmp_zz_factor(f, u, K): """ @@ -1020,11 +1077,11 @@ Consider polynomial `f = 2*(x**2 - y**2)`:: - >>> from sympy.polys.factortools import dmp_zz_factor - >>> from sympy.polys.domains import ZZ + >>> from sympy.polys import ring, ZZ + >>> R, x,y = ring("x,y", ZZ) - >>> dmp_zz_factor([[2], [], [-2, 0, 0]], 1, ZZ) - (2, [([[1], [-1, 0]], 1), ([[1], [1, 0]], 1)]) + >>> R.dmp_zz_factor(2*x**2 - 2*y**2) + (2, [(x - y, 1), (x + y, 1)]) In result we got the following factorization:: @@ -1065,17 +1122,18 @@ q, r = dmp_div(f, h, u, K) if dmp_zero_p(r, u): - f, k = q, k+1 + f, k = q, k + 1 else: break factors.append((h, k)) - for g, k in dmp_zz_factor(G, u-1, K)[1]: + for g, k in dmp_zz_factor(G, u - 1, K)[1]: factors.insert(0, ([g], k)) return cont, _sort_factors(factors) + def dup_ext_factor(f, K): """Factor univariate polynomials over algebraic number fields. """ n, lc = dup_degree(f), dup_LC(f, K) @@ -1107,6 +1165,7 @@ return lc, factors + @cythonized("u") def dmp_ext_factor(f, u, K): """Factor multivariate polynomials over algebraic number fields. """ @@ -1137,6 +1196,7 @@ return lc, dmp_trial_division(F, factors, u, K) + @cythonized("i") def dup_gf_factor(f, K): """Factor univariate polynomials over finite fields. """ @@ -1149,16 +1209,18 @@ return K.convert(coeff, K.dom), factors + def dmp_gf_factor(f, u, K): """Factor multivariate polynomials over finite fields. """ - raise DomainError('multivariate polynomials over %s' % K) + raise NotImplementedError('multivariate polynomials over finite fields') + @cythonized("i,k,u") def dup_factor_list(f, K0): """Factor polynomials into irreducibles in `K[x]`. """ j, f = dup_terms_gcd(f, K0) - if not K0.has_CharacteristicZero: + if K0.is_FiniteField: coeff, factors = dup_gf_factor(f, K0) elif K0.is_Algebraic: coeff, factors = dup_ext_factor(f, K0) @@ -1188,7 +1250,7 @@ factors[i] = (dmp_eject(f, u, K), k) coeff = K.convert(coeff, K.dom) - else: # pragma: no cover + else: # pragma: no cover raise DomainError('factorization not supported over %s' % K0) if K0.has_Field: @@ -1211,6 +1273,7 @@ return coeff, _sort_factors(factors) + def dup_factor_list_include(f, K): """Factor polynomials into irreducibles in `K[x]`. """ coeff, factors = dup_factor_list(f, K) @@ -1221,6 +1284,7 @@ g = dup_mul_ground(factors[0][0], coeff, K) return [(g, factors[0][1])] + factors[1:] + @cythonized("u,v,i,k") def dmp_factor_list(f, u, K0): """Factor polynomials into irreducibles in `K[X]`. """ @@ -1229,7 +1293,7 @@ J, f = dmp_terms_gcd(f, u, K0) - if not K0.has_CharacteristicZero: # pragma: no cover + if K0.is_FiniteField: # pragma: no cover coeff, factors = dmp_gf_factor(f, u, K0) elif K0.is_Algebraic: coeff, factors = dmp_ext_factor(f, u, K0) @@ -1263,7 +1327,7 @@ factors[i] = (dmp_eject(f, v, K), k) coeff = K.convert(coeff, K.dom) - else: # pragma: no cover + else: # pragma: no cover raise DomainError('factorization not supported over %s' % K0) if K0.has_Field: @@ -1285,11 +1349,12 @@ if not j: continue - term = {(0,)*(u-i) + (1,) + (0,)*i: K0.one} + term = {(0,)*(u - i) + (1,) + (0,)*i: K0.one} factors.insert(0, (dmp_from_dict(term, u, K0), j)) return coeff, _sort_factors(factors) + @cythonized("u") def dmp_factor_list_include(f, u, K): """Factor polynomials into irreducibles in `K[X]`. """ @@ -1304,10 +1369,12 @@ g = dmp_mul_ground(factors[0][0], coeff, u, K) return [(g, factors[0][1])] + factors[1:] + def dup_irreducible_p(f, K): """Returns ``True`` if ``f`` has no factors over its domain. """ return dmp_irreducible_p(f, 0, K) + def dmp_irreducible_p(f, u, K): """Returns ``True`` if ``f`` has no factors over its domain. """ _, factors = dmp_factor_list(f, u, K) diff -Nru python3-sympy-0.7.2/sympy/polys/fglmtools.py python3-sympy-0.7.3/sympy/polys/fglmtools.py --- python3-sympy-0.7.2/sympy/polys/fglmtools.py 1970-01-01 00:00:00.000000000 +0000 +++ python3-sympy-0.7.3/sympy/polys/fglmtools.py 2013-07-13 17:53:32.000000000 +0000 @@ -0,0 +1,152 @@ +"Implementation of matrix FGLM Groebner basis conversion algorithm. """ + +from sympy.polys.monomialtools import monomial_mul, monomial_div + +def matrix_fglm(F, ring, O_to): + """ + Converts the reduced Groebner basis ``F`` of a zero-dimensional + ideal w.r.t. ``O_from`` to a reduced Groebner basis + w.r.t. ``O_to``. + + References + ========== + + J.C. Faugere, P. Gianni, D. Lazard, T. Mora (1994). Efficient + Computation of Zero-dimensional Groebner Bases by Change of + Ordering + """ + domain = ring.domain + ngens = ring.ngens + + ring_to = ring.clone(order=O_to) + + old_basis = _basis(F, ring) + M = _representing_matrices(old_basis, F, ring) + + # V contains the normalforms (wrt O_from) of S + S = [ring.zero_monom] + V = [[domain.one] + [domain.zero] * (len(old_basis) - 1)] + G = [] + + L = [(i, 0) for i in range(ngens)] # (i, j) corresponds to x_i * S[j] + L.sort(key=lambda k_l1: O_to(_incr_k(S[k_l1[1]], k_l1[0])), reverse=True) + t = L.pop() + + P = _identity_matrix(len(old_basis), domain) + + while True: + s = len(S) + v = _matrix_mul(M[t[0]], V[t[1]]) + _lambda = _matrix_mul(P, v) + + if all(_lambda[i] == domain.zero for i in range(s, len(old_basis))): + # there is a linear combination of v by V + lt = ring.term_new(_incr_k(S[t[1]], t[0]), domain.one) + rest = ring.from_dict(dict([ (S[i], _lambda[i]) for i in range(s) ])) + + g = (lt - rest).set_ring(ring_to) + if g: + G.append(g) + else: + # v is linearly independant from V + P = _update(s, _lambda, P) + S.append(_incr_k(S[t[1]], t[0])) + V.append(v) + + L.extend([(i, s) for i in range(ngens)]) + L = list(set(L)) + L.sort(key=lambda k_l: O_to(_incr_k(S[k_l[1]], k_l[0])), reverse=True) + + L = [(k, l) for (k, l) in L if all(monomial_div(_incr_k(S[l], k), g.LM) is None for g in G)] + + if not L: + G = [ g.monic() for g in G ] + return sorted(G, key=lambda g: O_to(g.LM), reverse=True) + + t = L.pop() + + +def _incr_k(m, k): + return tuple(list(m[:k]) + [m[k] + 1] + list(m[k + 1:])) + + +def _identity_matrix(n, domain): + M = [[domain.zero]*n for _ in range(n)] + + for i in range(n): + M[i][i] = domain.one + + return M + + +def _matrix_mul(M, v): + return [sum([row[i] * v[i] for i in range(len(v))]) for row in M] + + +def _update(s, _lambda, P): + """ + Update ``P`` such that for the updated `P'` `P' v = e_{s}`. + """ + k = min([j for j in range(s, len(_lambda)) if _lambda[j] != 0]) + + for r in range(len(_lambda)): + if r != k: + P[r] = [P[r][j] - (P[k][j] * _lambda[r]) / _lambda[k] for j in range(len(P[r]))] + + P[k] = [P[k][j] / _lambda[k] for j in range(len(P[k]))] + P[k], P[s] = P[s], P[k] + + return P + + +def _representing_matrices(basis, G, ring): + """ + Compute the matrices corresponding to the linear maps `m \mapsto + x_i m` for all variables `x_i`. + """ + domain = ring.domain + u = ring.ngens-1 + + def var(i): + return tuple([0] * i + [1] + [0] * (u - i)) + + def representing_matrix(m): + M = [[domain.zero] * len(basis) for _ in range(len(basis))] + + for i, v in enumerate(basis): + r = ring.term_new(monomial_mul(m, v), domain.one).rem(G) + + for monom, coeff in r.terms(): + j = basis.index(monom) + M[j][i] = coeff + + return M + + return [representing_matrix(var(i)) for i in range(u + 1)] + + +def _basis(G, ring): + """ + Computes a list of monomials which are not divisible by the leading + monomials wrt to ``O`` of ``G``. These monomials are a basis of + `K[X_1, \ldots, X_n]/(G)`. + """ + order = ring.order + + leading_monomials = [g.LM for g in G] + candidates = [ring.zero_monom] + basis = [] + + while candidates: + t = candidates.pop() + basis.append(t) + + new_candidates = [_incr_k(t, k) for k in range(ring.ngens) + if all(monomial_div(_incr_k(t, k), lmg) is None + for lmg in leading_monomials)] + candidates.extend(new_candidates) + candidates.sort(key=lambda m: order(m), reverse=True) + + basis = list(set(basis)) + + return sorted(basis, key=lambda m: order(m)) diff -Nru python3-sympy-0.7.2/sympy/polys/fields.py python3-sympy-0.7.3/sympy/polys/fields.py --- python3-sympy-0.7.2/sympy/polys/fields.py 1970-01-01 00:00:00.000000000 +0000 +++ python3-sympy-0.7.3/sympy/polys/fields.py 2013-07-13 17:53:32.000000000 +0000 @@ -0,0 +1,433 @@ +"""Sparse rational function fields. """ + +from operator import add, mul + +from sympy.core.expr import Expr +from sympy.core.sympify import CantSympify, sympify +from sympy.polys.rings import PolyElement +from sympy.polys.monomialtools import lex +from sympy.polys.polyerrors import ExactQuotientFailed, CoercionFailed +from sympy.polys.domains.domainelement import DomainElement +from sympy.polys.domains.fractionfield import FractionField +from sympy.printing.defaults import DefaultPrinting +from functools import reduce + +def field(symbols, domain, order=lex): + """Construct new rational function field returning (field, x1, ..., xn). """ + _field = FracField(symbols, domain, order) + return (_field,) + _field.gens + +def xfield(symbols, domain, order=lex): + """Construct new rational function field returning (field, (x1, ..., xn)). """ + _field = FracField(symbols, domain, order) + return (_field, _field.gens) + +def vfield(symbols, domain, order=lex): + """Construct new rational function field and inject generators into global namespace. """ + from inspect import currentframe + frame = currentframe().f_back + + try: + _field = FracField(symbols, domain, order) + + for sym, gen in zip(_field.symbols, _field.gens): + frame.f_globals[sym.name] = gen + finally: + del frame # break cyclic dependencies as stated in inspect docs + + return _field + +class FracField(DefaultPrinting): + + def __init__(self, symbols, domain, order): + from sympy.polys.rings import PolyRing + self.ring = PolyRing(symbols, domain, order) + self.dtype = FracElement + self.symbols = self.ring.symbols + self.ngens = len(self.symbols) + self.domain = self.ring.domain + self.order = self.ring.order + self.gens = self._gens() + + def _gens(self): + """Return a list of polynomial generators. """ + return tuple([ self.dtype(self, gen) for gen in self.ring.gens ]) + + _hash = None + + def __hash__(self): + _hash = self._hash + if _hash is None: + self._hash = _hash = hash((self.symbols, self.domain, self.order)) + return _hash + + def __eq__(self, other): + return isinstance(other, FracField) and self.ring == other.ring + + def __ne__(self, other): + return not self.__eq__(other) + + def new(self, numer, denom=None): + return self.dtype(self, numer, denom) + + def domain_new(self, element): + return self.domain.convert(element) + + def ground_new(self, element): + try: + return self.new(self.ring.ground_new(element)) + except CoercionFailed: + domain = self.domain + + if domain.has_Ring and domain.has_assoc_Field: + ground_field = domain.get_field() + element = ground_field.convert(element) + numer = ground_field.numer(element) + denom = ground_field.denom(element) + return self.new(numer, denom) + else: + raise + + def field_new(self, element): + if isinstance(element, FracElement): + if self == element.field: + return element + else: + raise NotImplementedError("conversion") + elif isinstance(element, PolyElement): + if self.ring == element.ring: + return self.new(element) + else: + raise NotImplementedError("conversion") + elif isinstance(element, tuple) and len(element) == 2: + numer, denom = list(map(self.ring.ring_new, element)) + return self.new(numer, denom) + elif isinstance(element, str): + raise NotImplementedError("parsing") + elif isinstance(element, Expr): + return self.from_expr(element) + else: + return self.ground_new(element) + + __call__ = field_new + + def _rebuild_expr(self, expr, mapping): + domain = self.domain + + def _rebuild(expr): + generator = mapping.get(expr) + + if generator is not None: + return generator + elif expr.is_Add: + return reduce(add, list(map(_rebuild, expr.args))) + elif expr.is_Mul: + return reduce(mul, list(map(_rebuild, expr.args))) + elif expr.is_Pow and expr.exp.is_Integer: + return _rebuild(expr.base)**int(expr.exp) + else: + try: + return domain.convert(expr) + except CoercionFailed: + if domain.has_Ring and domain.has_assoc_Field: + return domain.get_field().convert(expr) + else: + raise + + return _rebuild(sympify(expr)) + + def from_expr(self, expr): + mapping = dict(list(zip(self.symbols, self.gens))) + + try: + frac = self._rebuild_expr(expr, mapping) + except CoercionFailed: + raise ValueError("expected an expression convertible to a rational function in %s, got %s" % (self, expr)) + else: + return self.field_new(frac) + + @property + def zero(self): + return self.new(self.ring.zero) + + @property + def one(self): + return self.new(self.ring.one) + + def to_domain(self): + from sympy.polys.domains.fractionfield import FractionField + return FractionField(self) + + def to_ring(self): + from sympy.polys.rings import PolyRing + return PolyRing(self.symbols, self.domain, self.order) + +class FracElement(DomainElement, DefaultPrinting, CantSympify): + """Sparse rational function. """ + + def __init__(self, field, numer, denom=None): + if denom is not None: + if not denom: + raise ZeroDivisionError + else: + denom = numer.ring.one + + self.field = field + self.numer = field.ring(numer) + self.denom = field.ring(denom) + + def raw_new(f, numer, denom): + return f.__class__(f.field, numer, denom) + def new(f, numer, denom): + return f.raw_new(*numer.cancel(denom)) + + def to_poly(f): + assert f.denom == 1 + return f.numer + + def parent(self): + return self.field.to_domain() + + _hash = None + + def __hash__(self): + _hash = self._hash + if _hash is None: + self._hash = _hash = hash((self.field, self.numer, self.denom)) + return _hash + + def copy(self): + return self.raw_new(self.numer.copy(), self.denom.copy()) + + def set_field(self, new_field): + if self.field == new_field: + return self + else: + new_ring = new_field.ring + numer = self.numer.set_ring(new_ring) + denom = self.denom.set_ring(new_ring) + return new_field.new(numer, denom) + + def as_expr(self, *symbols): + return self.numer.as_expr(*symbols)/self.denom.as_expr(*symbols) + + def __eq__(f, g): + if isinstance(g, FracElement): + return f.numer == g.numer and f.denom == g.denom + else: + return f.numer == g and f.denom == 1 + + def __ne__(f, g): + return not f.__eq__(g) + + def __bool__(f): + return bool(f.numer) + + __nonzero__ = __bool__ + + def __pos__(f): + """Negate all cefficients in ``f``. """ + return f.raw_new(f.numer, f.denom) + + def __neg__(f): + """Negate all cefficients in ``f``. """ + return f.raw_new(-f.numer, f.denom) + + def _extract_ground(self, element): + domain = self.field.domain + + try: + element = domain.convert(element) + except CoercionFailed: + if domain.has_Ring and domain.has_assoc_Field: + ground_field = domain.get_field() + + try: + element = ground_field.convert(element) + except CoercionFailed: + pass + else: + return -1, ground_field.numer(element), ground_field.denom(element) + + return 0, None, None + else: + return 1, element, None + + def __add__(f, g): + """Add rational functions ``f`` and ``g``. """ + field = f.field + + if isinstance(g, FracElement): + if f.field == g.field: + return f.new(f.numer*g.denom + f.denom*g.numer, f.denom*g.denom) + elif isinstance(field.domain, FractionField) and field.domain.field == g.field: + pass + elif isinstance(g.field.domain, FractionField) and g.field.domain.field == field: + return g.__radd__(f) + else: + return NotImplemented + elif isinstance(g, PolyElement): + if field.ring == g.ring: + return f.new(f.numer + f.denom*g, f.denom) + else: + return g.__radd__(f) + + return f.__radd__(g) + + def __radd__(f, c): + if isinstance(c, PolyElement) and f.field.ring == c.ring: + return f.new(f.numer + f.denom*c, f.denom) + + op, g_numer, g_denom = f._extract_ground(c) + + if op == 1: + return f.new(f.numer + f.denom*g_numer, f.denom) + elif not op: + return NotImplemented + else: + return f.new(f.numer*g_denom + f.denom*g_numer, f.denom*g_denom) + + def __sub__(f, g): + """Subtract rational functions ``f`` and ``g``. """ + field = f.field + + if isinstance(g, FracElement): + if f.field == g.field: + return f.new(f.numer*g.denom - f.denom*g.numer, f.denom*g.denom) + elif isinstance(field.domain, FractionField) and field.domain.field == g.field: + pass + elif isinstance(g.field.domain, FractionField) and g.field.domain.field == field: + return g.__rsub__(f) + else: + return NotImplemented + elif isinstance(g, PolyElement): + if field.ring == g.ring: + return f.new(f.numer - f.denom*g, f.denom) + else: + return g.__rsub__(f) + + op, g_numer, g_denom = f._extract_ground(g) + + if op == 1: + return f.new(f.numer - f.denom*g_numer, f.denom) + elif not op: + return NotImplemented + else: + return f.new(f.numer*g_denom - f.denom*g_numer, f.denom*g_denom) + + def __rsub__(f, c): + if isinstance(c, PolyElement) and f.field.ring == c.ring: + return f.new(-f.numer + f.denom*c, f.denom) + + op, g_numer, g_denom = f._extract_ground(c) + + if op == 1: + return f.new(-f.numer + f.denom*g_numer, f.denom) + elif not op: + return NotImplemented + else: + return f.new(-f.numer*g_denom + f.denom*g_numer, f.denom*g_denom) + + def __mul__(f, g): + """Multiply rational functions ``f`` and ``g``. """ + field = f.field + + if isinstance(g, FracElement): + if field == g.field: + return f.new(f.numer*g.numer, f.denom*g.denom) + elif isinstance(field.domain, FractionField) and field.domain.field == g.field: + pass + elif isinstance(g.field.domain, FractionField) and g.field.domain.field == field: + return g.__rmul__(f) + else: + return NotImplemented + elif isinstance(g, PolyElement): + if field.ring == g.ring: + return f.new(f.numer*g, f.denom) + else: + return g.__rmul__(f) + + return f.__rmul__(g) + + def __rmul__(f, c): + if isinstance(c, PolyElement) and f.field.ring == c.ring: + return f.new(f.numer*c, f.denom) + + op, g_numer, g_denom = f._extract_ground(c) + + if op == 1: + return f.new(f.numer*g_numer, f.denom) + elif not op: + return NotImplemented + else: + return f.new(f.numer*g_numer, f.denom*g_denom) + + def __truediv__(f, g): + """Computes quotient of fractions ``f`` and ``g``. """ + field = f.field + + if isinstance(g, FracElement): + if field == g.field: + return f.new(f.numer*g.denom, f.denom*g.numer) + elif isinstance(field.domain, FractionField) and field.domain.field == g.field: + pass + elif isinstance(g.field.domain, FractionField) and g.field.domain.field == field: + return g.__rtruediv__(f) + else: + return NotImplemented + elif isinstance(g, PolyElement): + if field.ring == g.ring: + return f.new(f.numer, f.denom*g) + else: + return g.__rtruediv__(f) + + op, g_numer, g_denom = f._extract_ground(g) + + if op == 1: + return f.new(f.numer, f.denom*g_numer) + elif not op: + return NotImplemented + else: + return f.new(f.numer*g_denom, f.denom*g_numer) + + __div__ = __truediv__ + + def __rtruediv__(f, c): + if isinstance(c, PolyElement) and f.field.ring == c.ring: + return f.new(f.denom*c, f.numer) + + op, g_numer, g_denom = f._extract_ground(c) + + if op == 1: + return f.new(f.denom*g_numer, f.numer) + elif not op: + return NotImplemented + else: + return f.new(f.denom*g_numer, f.numer*g_denom) + + __rdiv__ = __rtruediv__ + + def __pow__(f, n): + """Raise ``f`` to a non-negative power ``n``. """ + if isinstance(n, int): + if n >= 0: + return f.raw_new(f.numer**n, f.denom**n) + else: + return f.raw_new(f.denom**-n, f.numer**-n) + else: + return NotImplemented + + def diff(f, x): + if isinstance(x, list) and a is None: + x = [ X.to_poly() for X in x ] + else: + x = x.to_poly() + return f.new(f.numer.diff(x)*f.denom - f.numer*f.denom.diff(x), f.denom**2) + + def subs(f, x, a=None): + if isinstance(x, list) and a is None: + x = [ (X.to_poly(), a) for X, a in x ] + return f.new(f.numer.subs(x), f.denom.subs(x)) + else: + x = x.to_poly() + return f.new(f.numer.subs(x, a), f.denom.subs(x, a)) diff -Nru python3-sympy-0.7.2/sympy/polys/galoistools.py python3-sympy-0.7.3/sympy/polys/galoistools.py --- python3-sympy-0.7.2/sympy/polys/galoistools.py 2012-10-17 03:02:22.000000000 +0000 +++ python3-sympy-0.7.3/sympy/polys/galoistools.py 2013-07-13 17:53:32.000000000 +0000 @@ -3,6 +3,7 @@ from random import uniform from math import ceil as _ceil, sqrt as _sqrt +from sympy.core.compatibility import SYMPY_INTS from sympy.core.mul import prod from sympy.polys.polyutils import _sort_factors from sympy.polys.polyconfig import query @@ -14,7 +15,6 @@ from sympy.ntheory import factorint - def gf_crt(U, M, K=None): """ Chinese Remainder Theorem. @@ -57,6 +57,7 @@ return v % p + def gf_crt1(M, K): """ First part of the Chinese Remainder Theorem. @@ -80,6 +81,7 @@ return p, E, S + def gf_crt2(U, M, p, E, S, K): """ Second part of the Chinese Remainder Theorem. @@ -107,9 +109,10 @@ return v % p + def gf_int(a, p): """ - Coerce ``a mod p`` to an integer in ``[-p/2, p/2]`` range. + Coerce ``a mod p`` to an integer in the range ``[-p/2, p/2]``. Examples ======== @@ -127,9 +130,10 @@ else: return a - p + def gf_degree(f): """ - Return leading degree of ``f``. + Return the leading degree of ``f``. Examples ======== @@ -142,11 +146,12 @@ -1 """ - return len(f)-1 + return len(f) - 1 + def gf_LC(f, K): """ - Return leading coefficient of ``f``. + Return the leading coefficient of ``f``. Examples ======== @@ -163,9 +168,10 @@ else: return f[0] + def gf_TC(f, K): """ - Return trailing coefficient of ``f``. + Return the trailing coefficient of ``f``. Examples ======== @@ -182,6 +188,7 @@ else: return f[-1] + @cythonized("k") def gf_strip(f): """ @@ -210,6 +217,7 @@ return f[k:] + def gf_trunc(f, p): """ Reduce all coefficients modulo ``p``. @@ -225,6 +233,7 @@ """ return gf_strip([ a % p for a in f ]) + def gf_normal(f, p, K): """ Normalize all coefficients in ``K``. @@ -241,27 +250,11 @@ """ return gf_trunc(list(map(K, f)), p) -def gf_convert(f, p, K0, K1): - """ - Normalize all coefficients in ``K``. - - - Examples - ======== - - >>> from sympy.polys.domains import ZZ, QQ - >>> from sympy.polys.galoistools import gf_convert - - >>> gf_convert([QQ(1), QQ(4), QQ(0)], 3, QQ, ZZ) - [1, 1, 0] - - """ - return gf_trunc([ K1.convert(c, K0) for c in f ], p) @cythonized("k,n") def gf_from_dict(f, p, K): """ - Create ``GF(p)[x]`` polynomial from a dict. + Create a ``GF(p)[x]`` polynomial from a dict. Examples ======== @@ -269,13 +262,13 @@ >>> from sympy.polys.domains import ZZ >>> from sympy.polys.galoistools import gf_from_dict - >>> gf_from_dict({10: 4, 4: 33, 0: -1}, 5, ZZ) + >>> gf_from_dict({10: ZZ(4), 4: ZZ(33), 0: ZZ(-1)}, 5, ZZ) [4, 0, 0, 0, 0, 0, 3, 0, 0, 0, 4] """ n, h = max(f.keys()), [] - if type(n) is int: + if isinstance(n, SYMPY_INTS): for k in range(n, -1, -1): h.append(f.get(k, K.zero) % p) else: @@ -286,10 +279,11 @@ return gf_trunc(h, p) + @cythonized("k,n") def gf_to_dict(f, p, symmetric=True): """ - Convert ``GF(p)[x]`` polynomial to a dict. + Convert a ``GF(p)[x]`` polynomial to a dict. Examples ======== @@ -304,19 +298,21 @@ """ n, result = gf_degree(f), {} - for k in range(0, n+1): + for k in range(0, n + 1): if symmetric: - a = gf_int(f[n-k], p) + a = gf_int(f[n - k], p) else: - a = f[n-k] + a = f[n - k] - if a: result[k] = a + if a: + result[k] = a return result + def gf_from_int_poly(f, p): """ - Create ``GF(p)[x]`` polynomial from ``Z[x]``. + Create a ``GF(p)[x]`` polynomial from ``Z[x]``. Examples ======== @@ -330,9 +326,10 @@ """ return gf_trunc(f, p) + def gf_to_int_poly(f, p, symmetric=True): """ - Convert ``GF(p)[x]`` polynomial to ``Z[x]``. + Convert a ``GF(p)[x]`` polynomial to ``Z[x]``. Examples @@ -351,6 +348,7 @@ else: return f + def gf_neg(f, p, K): """ Negate a polynomial in ``GF(p)[x]``. @@ -367,6 +365,7 @@ """ return [ -coeff % p for coeff in f ] + def gf_add_ground(f, a, p, K): """ Compute ``f + a`` where ``f`` in ``GF(p)[x]`` and ``a`` in ``GF(p)``. @@ -394,6 +393,7 @@ else: return [a] + def gf_sub_ground(f, a, p, K): """ Compute ``f - a`` where ``f`` in ``GF(p)[x]`` and ``a`` in ``GF(p)``. @@ -421,6 +421,7 @@ else: return [a] + def gf_mul_ground(f, a, p, K): """ Compute ``f * a`` where ``f`` in ``GF(p)[x]`` and ``a`` in ``GF(p)``. @@ -440,6 +441,7 @@ else: return [ (a*b) % p for b in f ] + def gf_quo_ground(f, a, p, K): """ Compute ``f/a`` where ``f`` in ``GF(p)[x]`` and ``a`` in ``GF(p)``. @@ -450,12 +452,13 @@ >>> from sympy.polys.domains import ZZ >>> from sympy.polys.galoistools import gf_quo_ground - >>> gf_quo_ground([3, 2, 4], 2, 5, ZZ) + >>> gf_quo_ground(ZZ.map([3, 2, 4]), ZZ(2), 5, ZZ) [4, 1, 2] """ return gf_mul_ground(f, K.invert(a, p), p, K) + @cythonized("df,dg,k") def gf_add(f, g, p, K): """ @@ -491,6 +494,7 @@ return h + [ (a + b) % p for a, b in zip(f, g) ] + @cythonized("df,dg,k") def gf_sub(f, g, p, K): """ @@ -526,6 +530,7 @@ return h + [ (a - b) % p for a, b in zip(f, g) ] + @cythonized("df,dg,dh,i,j") def gf_mul(f, g, p, K): """ @@ -545,18 +550,19 @@ dg = gf_degree(g) dh = df + dg - h = [0]*(dh+1) + h = [0]*(dh + 1) - for i in range(0, dh+1): + for i in range(0, dh + 1): coeff = K.zero - for j in range(max(0, i-dg), min(i, df)+1): - coeff += f[j]*g[i-j] + for j in range(max(0, i - dg), min(i, df) + 1): + coeff += f[j]*g[i - j] h[i] = coeff % p return gf_strip(h) + @cythonized("df,dh,i,j,jmin,jmax,n") def gf_sqr(f, p, K): """ @@ -575,31 +581,32 @@ df = gf_degree(f) dh = 2*df - h = [0]*(dh+1) + h = [0]*(dh + 1) - for i in range(0, dh+1): + for i in range(0, dh + 1): coeff = K.zero - jmin = max(0, i-df) + jmin = max(0, i - df) jmax = min(i, df) n = jmax - jmin + 1 jmax = jmin + n // 2 - 1 - for j in range(jmin, jmax+1): - coeff += f[j]*f[i-j] + for j in range(jmin, jmax + 1): + coeff += f[j]*f[i - j] coeff += coeff if n & 1: - elem = f[jmax+1] + elem = f[jmax + 1] coeff += elem**2 h[i] = coeff % p return gf_strip(h) + def gf_add_mul(f, g, h, p, K): """ Returns ``f + g*h`` where ``f``, ``g``, ``h`` in ``GF(p)[x]``. @@ -614,6 +621,7 @@ """ return gf_add(f, gf_mul(g, h, p, K), p, K) + def gf_sub_mul(f, g, h, p, K): """ Compute ``f - g*h`` where ``f``, ``g``, ``h`` in ``GF(p)[x]``. @@ -630,6 +638,7 @@ """ return gf_sub(f, gf_mul(g, h, p, K), p, K) + @cythonized("k") def gf_expand(F, p, K): """ @@ -658,6 +667,7 @@ return g + @cythonized("df,dg,dq,dr,i,j") def gf_div(f, g, p, K): """ @@ -672,12 +682,12 @@ >>> from sympy.polys.domains import ZZ >>> from sympy.polys.galoistools import gf_div, gf_add_mul - >>> gf_div([1, 0, 1, 1], [1, 1, 0], 2, ZZ) + >>> gf_div(ZZ.map([1, 0, 1, 1]), ZZ.map([1, 1, 0]), 2, ZZ) ([1, 1], [1]) As result we obtained quotient ``x + 1`` and remainder ``1``, thus:: - >>> gf_add_mul([1], [1, 1], [1, 1, 0], 2, ZZ) + >>> gf_add_mul(ZZ.map([1]), ZZ.map([1, 1]), ZZ.map([1, 1, 0]), 2, ZZ) [1, 0, 1, 1] References @@ -697,20 +707,21 @@ inv = K.invert(g[0], p) - h, dq, dr = list(f), df-dg, dg-1 + h, dq, dr = list(f), df - dg, dg - 1 - for i in range(0, df+1): + for i in range(0, df + 1): coeff = h[i] - for j in range(max(0, dg-i), min(df-i, dr)+1): - coeff -= h[i+j-dg] * g[dg-j] + for j in range(max(0, dg - i), min(df - i, dr) + 1): + coeff -= h[i + j - dg] * g[dg - j] if i <= dq: coeff *= inv h[i] = coeff % p - return h[:dq+1], gf_strip(h[dq+1:]) + return h[:dq + 1], gf_strip(h[dq + 1:]) + def gf_rem(f, g, p, K): """ @@ -722,12 +733,13 @@ >>> from sympy.polys.domains import ZZ >>> from sympy.polys.galoistools import gf_rem - >>> gf_rem([1, 0, 1, 1], [1, 1, 0], 2, ZZ) + >>> gf_rem(ZZ.map([1, 0, 1, 1]), ZZ.map([1, 1, 0]), 2, ZZ) [1] """ return gf_div(f, g, p, K)[1] + @cythonized("df,dg,dq,dr,i,j") def gf_quo(f, g, p, K): """ @@ -739,9 +751,9 @@ >>> from sympy.polys.domains import ZZ >>> from sympy.polys.galoistools import gf_quo - >>> gf_quo([1, 0, 1, 1], [1, 1, 0], 2, ZZ) + >>> gf_quo(ZZ.map([1, 0, 1, 1]), ZZ.map([1, 1, 0]), 2, ZZ) [1, 1] - >>> gf_quo([1, 0, 3, 2, 3], [2, 2, 2], 5, ZZ) + >>> gf_quo(ZZ.map([1, 0, 3, 2, 3]), ZZ.map([2, 2, 2]), 5, ZZ) [3, 2, 4] """ @@ -755,17 +767,18 @@ inv = K.invert(g[0], p) - h, dq, dr = f[:], df-dg, dg-1 + h, dq, dr = f[:], df - dg, dg - 1 - for i in range(0, dq+1): + for i in range(0, dq + 1): coeff = h[i] - for j in range(max(0, dg-i), min(df-i, dr)+1): - coeff -= h[i+j-dg] * g[dg-j] + for j in range(max(0, dg - i), min(df - i, dr) + 1): + coeff -= h[i + j - dg] * g[dg - j] h[i] = (coeff * inv) % p - return h[:dq+1] + return h[:dq + 1] + def gf_exquo(f, g, p, K): """ @@ -777,10 +790,10 @@ >>> from sympy.polys.domains import ZZ >>> from sympy.polys.galoistools import gf_exquo - >>> gf_exquo([1, 0, 3, 2, 3], [2, 2, 2], 5, ZZ) + >>> gf_exquo(ZZ.map([1, 0, 3, 2, 3]), ZZ.map([2, 2, 2]), 5, ZZ) [3, 2, 4] - >>> gf_exquo([1, 0, 1, 1], [1, 1, 0], 2, ZZ) + >>> gf_exquo(ZZ.map([1, 0, 1, 1]), ZZ.map([1, 1, 0]), 2, ZZ) Traceback (most recent call last): ... ExactQuotientFailed: [1, 1, 0] does not divide [1, 0, 1, 1] @@ -793,6 +806,7 @@ else: raise ExactQuotientFailed(f, g) + @cythonized("n") def gf_lshift(f, n, K): """ @@ -813,6 +827,7 @@ else: return f + [K.zero]*n + @cythonized("n") def gf_rshift(f, n, K): """ @@ -833,6 +848,7 @@ else: return f[:-n], f[-n:] + def gf_pow(f, n, p, K): """ Compute ``f**n`` in ``GF(p)[x]`` using repeated squaring. @@ -870,13 +886,14 @@ return h + def gf_pow_mod(f, n, g, p, K): """ Compute ``f**n`` in ``GF(p)[x]/(g)`` using repeated squaring. Given polynomials ``f`` and ``g`` in ``GF(p)[x]`` and a non-negative - integer ``n``, efficiently computes ``f**n (mod g)`` i.e. remainder - from division ``f**n`` by ``g`` using repeated squaring algorithm. + integer ``n``, efficiently computes ``f**n (mod g)`` i.e. the remainder + of ``f**n`` from division by ``g``, using the repeated squaring algorithm. Examples ======== @@ -884,7 +901,7 @@ >>> from sympy.polys.domains import ZZ >>> from sympy.polys.galoistools import gf_pow_mod - >>> gf_pow_mod([3, 2, 4], 3, [1, 1], 5, ZZ) + >>> gf_pow_mod(ZZ.map([3, 2, 4]), 3, ZZ.map([1, 1]), 5, ZZ) [] References @@ -918,6 +935,7 @@ return h + def gf_gcd(f, g, p, K): """ Euclidean Algorithm in ``GF(p)[x]``. @@ -928,7 +946,7 @@ >>> from sympy.polys.domains import ZZ >>> from sympy.polys.galoistools import gf_gcd - >>> gf_gcd([3, 2, 4], [2, 2, 3], 5, ZZ) + >>> gf_gcd(ZZ.map([3, 2, 4]), ZZ.map([2, 2, 3]), 5, ZZ) [1, 3] """ @@ -937,6 +955,7 @@ return gf_monic(f, p, K)[1] + def gf_lcm(f, g, p, K): """ Compute polynomial LCM in ``GF(p)[x]``. @@ -947,7 +966,7 @@ >>> from sympy.polys.domains import ZZ >>> from sympy.polys.galoistools import gf_lcm - >>> gf_lcm([3, 2, 4], [2, 2, 3], 5, ZZ) + >>> gf_lcm(ZZ.map([3, 2, 4]), ZZ.map([2, 2, 3]), 5, ZZ) [1, 2, 0, 4] """ @@ -959,6 +978,7 @@ return gf_monic(h, p, K)[1] + def gf_cofactors(f, g, p, K): """ Compute polynomial GCD and cofactors in ``GF(p)[x]``. @@ -969,7 +989,7 @@ >>> from sympy.polys.domains import ZZ >>> from sympy.polys.galoistools import gf_cofactors - >>> gf_cofactors([3, 2, 4], [2, 2, 3], 5, ZZ) + >>> gf_cofactors(ZZ.map([3, 2, 4]), ZZ.map([2, 2, 3]), 5, ZZ) ([1, 3], [3, 3], [2, 1]) """ @@ -979,7 +999,8 @@ h = gf_gcd(f, g, p, K) return (h, gf_quo(f, h, p, K), - gf_quo(g, h, p, K)) + gf_quo(g, h, p, K)) + def gf_gcdex(f, g, p, K): """ @@ -995,15 +1016,15 @@ >>> from sympy.polys.domains import ZZ >>> from sympy.polys.galoistools import gf_gcdex, gf_mul, gf_add - >>> s, t, g = gf_gcdex([1,8,7], [1,7,1,7], 11, ZZ) + >>> s, t, g = gf_gcdex(ZZ.map([1, 8, 7]), ZZ.map([1, 7, 1, 7]), 11, ZZ) >>> s, t, g ([5, 6], [6], [1, 7]) As result we obtained polynomials ``s = 5*x + 6`` and ``t = 6``, and additionally ``gcd(f, g) = x + 7``. This is correct because:: - >>> S = gf_mul(s, [1,8,7], 11, ZZ) - >>> T = gf_mul(t, [1,7,1,7], 11, ZZ) + >>> S = gf_mul(s, ZZ.map([1, 8, 7]), 11, ZZ) + >>> T = gf_mul(t, ZZ.map([1, 7, 1, 7]), 11, ZZ) >>> gf_add(S, T, 11, ZZ) == [1, 7] True @@ -1046,6 +1067,7 @@ return s1, t1, r1 + def gf_monic(f, p, K): """ Compute LC and a monic polynomial in ``GF(p)[x]``. @@ -1056,7 +1078,7 @@ >>> from sympy.polys.domains import ZZ >>> from sympy.polys.galoistools import gf_monic - >>> gf_monic([3, 2, 4], 5, ZZ) + >>> gf_monic(ZZ.map([3, 2, 4]), 5, ZZ) (3, [1, 4, 3]) """ @@ -1070,6 +1092,7 @@ else: return lc, gf_quo_ground(f, lc, p, K) + @cythonized("df,n") def gf_diff(f, p, K): """ @@ -1094,12 +1117,13 @@ coeff %= p if coeff: - h[df-n] = coeff + h[df - n] = coeff n -= 1 return gf_strip(h) + def gf_eval(f, a, p, K): """ Evaluate ``f(a)`` in ``GF(p)`` using Horner scheme. @@ -1123,6 +1147,7 @@ return result + def gf_multi_eval(f, A, p, K): """ Evaluate ``f(a)`` for ``a`` in ``[a_1, ..., a_n]``. @@ -1139,6 +1164,7 @@ """ return [ gf_eval(f, a, p, K) for a in A ] + def gf_compose(f, g, p, K): """ Compute polynomial composition ``f(g)`` in ``GF(p)[x]``. @@ -1167,6 +1193,7 @@ return h + def gf_compose_mod(g, h, f, p, K): """ Compute polynomial composition ``g(h)`` in ``GF(p)[x]/(f)``. @@ -1177,7 +1204,7 @@ >>> from sympy.polys.domains import ZZ >>> from sympy.polys.galoistools import gf_compose_mod - >>> gf_compose_mod([3, 2, 4], [2, 2, 2], [4, 3], 5, ZZ) + >>> gf_compose_mod(ZZ.map([3, 2, 4]), ZZ.map([2, 2, 2]), ZZ.map([4, 3]), 5, ZZ) [4] """ @@ -1193,6 +1220,7 @@ return comp + @cythonized("n") def gf_trace_map(a, b, c, n, f, p, K): """ @@ -1249,6 +1277,7 @@ return gf_compose_mod(a, V, f, p, K), U + @cythonized("i,n") def gf_random(n, p, K): """ @@ -1265,6 +1294,7 @@ """ return [K.one] + [ K(int(uniform(0, p))) for i in range(0, n) ] + @cythonized("i,n") def gf_irreducible(n, p, K): """ @@ -1285,6 +1315,7 @@ if gf_irreducible_p(f, p, K): return f + @cythonized("i,n") def gf_irred_p_ben_or(f, p, K): """ @@ -1296,9 +1327,9 @@ >>> from sympy.polys.domains import ZZ >>> from sympy.polys.galoistools import gf_irred_p_ben_or - >>> gf_irred_p_ben_or([1, 4, 2, 2, 3, 2, 4, 1, 4, 0, 4], 5, ZZ) + >>> gf_irred_p_ben_or(ZZ.map([1, 4, 2, 2, 3, 2, 4, 1, 4, 0, 4]), 5, ZZ) True - >>> gf_irred_p_ben_or([3, 2, 4], 5, ZZ) + >>> gf_irred_p_ben_or(ZZ.map([3, 2, 4]), 5, ZZ) False """ @@ -1321,6 +1352,7 @@ return True + @cythonized("i,n,d") def gf_irred_p_rabin(f, p, K): """ @@ -1332,9 +1364,9 @@ >>> from sympy.polys.domains import ZZ >>> from sympy.polys.galoistools import gf_irred_p_rabin - >>> gf_irred_p_rabin([1, 4, 2, 2, 3, 2, 4, 1, 4, 0, 4], 5, ZZ) + >>> gf_irred_p_rabin(ZZ.map([1, 4, 2, 2, 3, 2, 4, 1, 4, 0, 4]), 5, ZZ) True - >>> gf_irred_p_rabin([3, 2, 4], 5, ZZ) + >>> gf_irred_p_rabin(ZZ.map([3, 2, 4]), 5, ZZ) False """ @@ -1363,10 +1395,11 @@ return h == x _irred_methods = { - 'ben-or' : gf_irred_p_ben_or, - 'rabin' : gf_irred_p_rabin, + 'ben-or': gf_irred_p_ben_or, + 'rabin': gf_irred_p_rabin, } + def gf_irreducible_p(f, p, K): """ Test irreducibility of a polynomial ``f`` in ``GF(p)[x]``. @@ -1377,9 +1410,9 @@ >>> from sympy.polys.domains import ZZ >>> from sympy.polys.galoistools import gf_irreducible_p - >>> gf_irreducible_p([1, 4, 2, 2, 3, 2, 4, 1, 4, 0, 4], 5, ZZ) + >>> gf_irreducible_p(ZZ.map([1, 4, 2, 2, 3, 2, 4, 1, 4, 0, 4]), 5, ZZ) True - >>> gf_irreducible_p([3, 2, 4], 5, ZZ) + >>> gf_irreducible_p(ZZ.map([3, 2, 4]), 5, ZZ) False """ @@ -1392,6 +1425,7 @@ return irred + def gf_sqf_p(f, p, K): """ Return ``True`` if ``f`` is square-free in ``GF(p)[x]``. @@ -1402,9 +1436,9 @@ >>> from sympy.polys.domains import ZZ >>> from sympy.polys.galoistools import gf_sqf_p - >>> gf_sqf_p([3, 2, 4], 5, ZZ) + >>> gf_sqf_p(ZZ.map([3, 2, 4]), 5, ZZ) True - >>> gf_sqf_p([2, 4, 4, 2, 2, 1, 4], 5, ZZ) + >>> gf_sqf_p(ZZ.map([2, 4, 4, 2, 2, 1, 4]), 5, ZZ) False """ @@ -1415,6 +1449,7 @@ else: return gf_gcd(f, gf_diff(f, p, K), p, K) == [K.one] + def gf_sqf_part(f, p, K): """ Return square-free part of a ``GF(p)[x]`` polynomial. @@ -1425,7 +1460,7 @@ >>> from sympy.polys.domains import ZZ >>> from sympy.polys.galoistools import gf_sqf_part - >>> gf_sqf_part([1, 1, 3, 0, 1, 0, 2, 2, 1], 5, ZZ) + >>> gf_sqf_part(ZZ.map([1, 1, 3, 0, 1, 0, 2, 2, 1]), 5, ZZ) [1, 4, 3] """ @@ -1438,10 +1473,11 @@ return g + @cythonized("i,n,d,r") def gf_sqf_list(f, p, K, all=False): """ - Return square-free decomposition of a ``GF(p)[x]`` polynomial. + Return the square-free decomposition of a ``GF(p)[x]`` polynomial. Given a polynomial ``f`` in ``GF(p)[x]``, returns the leading coefficient of ``f`` and a square-free decomposition ``f_1**e_1 f_2**e_2 ... f_k**e_k`` @@ -1458,7 +1494,7 @@ ... ) ... # doctest: +NORMALIZE_WHITESPACE - >>> f = gf_from_dict({11: 1, 0: 1}, 11, ZZ) + >>> f = gf_from_dict({11: ZZ(1), 0: ZZ(1)}, 11, ZZ) Note that ``f'(x) = 0``:: @@ -1505,7 +1541,7 @@ if gf_degree(H) > 0: factors.append((H, i*n)) - g, h, i = gf_quo(g, G, p, K), G, i+1 + g, h, i = gf_quo(g, G, p, K), G, i + 1 if g == [K.one]: sqf = True @@ -1515,10 +1551,10 @@ if not sqf: d = gf_degree(f) // r - for i in range(0, d+1): + for i in range(0, d + 1): f[i] = f[i*r] - f, n = f[:d+1], n*r + f, n = f[:d + 1], n*r else: break @@ -1527,6 +1563,7 @@ return lc, factors + @cythonized("n,i,j,r") def gf_Qmatrix(f, p, K): """ @@ -1551,14 +1588,14 @@ """ n, r = gf_degree(f), int(p) - q = [K.one] + [K.zero]*(n-1) - Q = [list(q)] + [[]]*(n-1) + q = [K.one] + [K.zero]*(n - 1) + Q = [list(q)] + [[]]*(n - 1) - for i in range(1, (n-1)*r + 1): + for i in range(1, (n - 1)*r + 1): qq, c = [(-q[-1]*f[-1]) % p], q[-1] for j in range(1, n): - qq.append((q[j-1] - c*f[-j-1]) % p) + qq.append((q[j - 1] - c*f[-j - 1]) % p) if not (i % r): Q[i//r] = list(qq) @@ -1567,6 +1604,7 @@ return Q + @cythonized("n,i,j,k") def gf_Qbasis(Q, p, K): """ @@ -1629,6 +1667,7 @@ return basis + @cythonized("i,k") def gf_berlekamp(f, p, K): """ @@ -1673,6 +1712,7 @@ return _sort_factors(factors, multiple=False) + @cythonized("i") def gf_ddf_zassenhaus(f, p, K): """ @@ -1689,7 +1729,7 @@ >>> from sympy.polys.domains import ZZ >>> from sympy.polys.galoistools import gf_from_dict - >>> f = gf_from_dict({15: 1, 0: -1}, 11, ZZ) + >>> f = gf_from_dict({15: ZZ(1), 0: ZZ(-1)}, 11, ZZ) Distinct degree factorization gives:: @@ -1728,6 +1768,7 @@ else: return factors + @cythonized("n,N,i") def gf_edf_zassenhaus(f, n, p, K): """ @@ -1762,26 +1803,27 @@ N = gf_degree(f) // n while len(factors) < N: - r = gf_random(2*n-1, p, K) + r = gf_random(2*n - 1, p, K) if p == 2: h = r - for i in range(0, 2**(n*N-1)): + for i in range(0, 2**(n*N - 1)): r = gf_pow_mod(r, 2, f, p, K) h = gf_add(h, r, p, K) g = gf_gcd(f, h, p, K) else: - h = gf_pow_mod(r, (q**n-1) // 2, f, p, K) + h = gf_pow_mod(r, (q**n - 1) // 2, f, p, K) g = gf_gcd(f, gf_sub_ground(h, K.one, p, K), p, K) if g != [K.one] and g != f: factors = gf_edf_zassenhaus(g, n, p, K) \ - + gf_edf_zassenhaus(gf_quo(f, g, p, K), n, p, K) + + gf_edf_zassenhaus(gf_quo(f, g, p, K), n, p, K) return _sort_factors(factors, multiple=False) + @cythonized("n,k,i,j") def gf_ddf_shoup(f, p, K): """ @@ -1802,7 +1844,7 @@ >>> from sympy.polys.domains import ZZ >>> from sympy.polys.galoistools import gf_ddf_shoup, gf_from_dict - >>> f = gf_from_dict({6: 1, 5: -1, 4: 1, 3: 1, 1: -1}, 3, ZZ) + >>> f = gf_from_dict({6: ZZ(1), 5: ZZ(-1), 4: ZZ(1), 3: ZZ(1), 1: ZZ(-1)}, 3, ZZ) >>> gf_ddf_shoup(f, 3, ZZ) [([1, 1, 0], 1), ([1, 1, 0, 1, 2], 2)] @@ -1820,21 +1862,21 @@ h = gf_pow_mod([K.one, K.zero], int(p), f, p, K) - U = [[K.one,K.zero], h] + [K.zero]*(k-1) + U = [[K.one, K.zero], h] + [K.zero]*(k - 1) - for i in range(2, k+1): - U[i] = gf_compose_mod(U[i-1], h, f, p, K) + for i in range(2, k + 1): + U[i] = gf_compose_mod(U[i - 1], h, f, p, K) h, U = U[k], U[:k] - V = [h] + [K.zero]*(k-1) + V = [h] + [K.zero]*(k - 1) for i in range(1, k): - V[i] = gf_compose_mod(V[i-1], h, f, p, K) + V[i] = gf_compose_mod(V[i - 1], h, f, p, K) factors = [] for i, v in enumerate(V): - h, j = [K.one], k-1 + h, j = [K.one], k - 1 for u in U: g = gf_sub(v, u, p, K) @@ -1849,15 +1891,16 @@ F = gf_gcd(g, h, p, K) if F != [K.one]: - factors.append((F, k*(i+1)-j)) + factors.append((F, k*(i + 1) - j)) - g, j = gf_quo(g, F, p, K), j-1 + g, j = gf_quo(g, F, p, K), j - 1 if f != [K.one]: factors.append((f, gf_degree(f))) return factors + @cythonized("n,N,q") def gf_edf_shoup(f, n, p, K): """ @@ -1877,7 +1920,7 @@ >>> from sympy.polys.domains import ZZ >>> from sympy.polys.galoistools import gf_edf_shoup - >>> gf_edf_shoup([1, 2837, 2277], 1, 2917, ZZ) + >>> gf_edf_shoup(ZZ.map([1, 2837, 2277]), 1, 2917, ZZ) [[1, 852], [1, 1985]] References @@ -1896,30 +1939,31 @@ factors, x = [f], [K.one, K.zero] - r = gf_random(N-1, p, K) + r = gf_random(N - 1, p, K) h = gf_pow_mod(x, q, f, p, K) - H = gf_trace_map(r, h, x, n-1, f, p, K)[1] + H = gf_trace_map(r, h, x, n - 1, f, p, K)[1] if p == 2: h1 = gf_gcd(f, H, p, K) h2 = gf_quo(f, h1, p, K) factors = gf_edf_shoup(h1, n, p, K) \ - + gf_edf_shoup(h2, n, p, K) + + gf_edf_shoup(h2, n, p, K) else: - h = gf_pow_mod(H, (q-1)//2, f, p, K) + h = gf_pow_mod(H, (q - 1)//2, f, p, K) h1 = gf_gcd(f, h, p, K) h2 = gf_gcd(f, gf_sub_ground(h, K.one, p, K), p, K) h3 = gf_quo(f, gf_mul(h1, h2, p, K), p, K) factors = gf_edf_shoup(h1, n, p, K) \ - + gf_edf_shoup(h2, n, p, K) \ - + gf_edf_shoup(h3, n, p, K) + + gf_edf_shoup(h2, n, p, K) \ + + gf_edf_shoup(h3, n, p, K) return _sort_factors(factors, multiple=False) + @cythonized("n") def gf_zassenhaus(f, p, K): """ @@ -1931,7 +1975,7 @@ >>> from sympy.polys.domains import ZZ >>> from sympy.polys.galoistools import gf_zassenhaus - >>> gf_zassenhaus([1, 4, 3], 5, ZZ) + >>> gf_zassenhaus(ZZ.map([1, 4, 3]), 5, ZZ) [[1, 1], [1, 3]] """ @@ -1942,6 +1986,7 @@ return _sort_factors(factors, multiple=False) + @cythonized("n") def gf_shoup(f, p, K): """ @@ -1953,7 +1998,7 @@ >>> from sympy.polys.domains import ZZ >>> from sympy.polys.galoistools import gf_shoup - >>> gf_shoup([1, 4, 3], 5, ZZ) + >>> gf_shoup(ZZ.map([1, 4, 3]), 5, ZZ) [[1, 1], [1, 3]] """ @@ -1965,11 +2010,12 @@ return _sort_factors(factors, multiple=False) _factor_methods = { - 'berlekamp' : gf_berlekamp, # ``p`` : small - 'zassenhaus' : gf_zassenhaus, # ``p`` : medium - 'shoup' : gf_shoup, # ``p`` : large + 'berlekamp': gf_berlekamp, # ``p`` : small + 'zassenhaus': gf_zassenhaus, # ``p`` : medium + 'shoup': gf_shoup, # ``p`` : large } + def gf_factor_sqf(f, p, K, method=None): """ Factor a square-free polynomial ``f`` in ``GF(p)[x]``. @@ -1980,7 +2026,7 @@ >>> from sympy.polys.domains import ZZ >>> from sympy.polys.galoistools import gf_factor_sqf - >>> gf_factor_sqf([3, 2, 4], 5, ZZ) + >>> gf_factor_sqf(ZZ.map([3, 2, 4]), 5, ZZ) (3, [[1, 1], [1, 3]]) """ @@ -1998,6 +2044,7 @@ return lc, factors + @cythonized("n") def gf_factor(f, p, K): """ @@ -2022,7 +2069,7 @@ >>> from sympy.polys.domains import ZZ >>> from sympy.polys.galoistools import gf_factor - >>> gf_factor([5, 2, 7, 2], 11, ZZ) + >>> gf_factor(ZZ.map([5, 2, 7, 2]), 11, ZZ) (5, [([1, 2], 1), ([1, 8], 2)]) We arrived with factorization ``f = 5 (x + 2) (x + 8)**2``. We didn't @@ -2082,6 +2129,7 @@ result += c return result + def linear_congruence(a, b, m): """ Returns the values of x satisfying a*x congruent b mod(m) @@ -2112,7 +2160,8 @@ r, _, g = gcdex(a, m) if b % g != 0: return [] - return [(r * b // g + t * m // g) % m for t in range (g)] + return [(r * b // g + t * m // g) % m for t in range(g)] + def _raise_mod_power(x, s, p, f): """ @@ -2153,6 +2202,7 @@ beta = - gf_value(f, x) // p**s return linear_congruence(alpha, beta, p) + def csolve_prime(f, p, e=1): """ Solutions of f(x) congruent 0 mod(p**e). @@ -2186,6 +2236,7 @@ S.extend([(x + v*ps, s1) for v in _raise_mod_power(x, s, p, f)]) return sorted(X) + def gf_csolve(f, n): """ To solve f(x) congruent 0 mod(n). diff -Nru python3-sympy-0.7.2/sympy/polys/groebnertools.py python3-sympy-0.7.3/sympy/polys/groebnertools.py --- python3-sympy-0.7.2/sympy/polys/groebnertools.py 2012-10-17 03:02:22.000000000 +0000 +++ python3-sympy-0.7.3/sympy/polys/groebnertools.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,23 +1,11 @@ """Groebner bases algorithms. """ -from sympy.polys.monomialtools import ( - monomial_mul, monomial_div, monomial_lcm, -) - -from sympy.polys.distributedpolys import ( - sdp_LC, sdp_LM, sdp_LT, sdp_mul_term, - sdp_sub, sdp_mul_term, sdp_monic, - sdp_rem, sdp_strip, sdp_sort, - _term_ff_div, _term_rr_div, -) - -from sympy.polys.polyerrors import ( - DomainError, -) - +from sympy.polys.monomialtools import monomial_mul, monomial_div, monomial_lcm, monomial_divides, term_div, lex +from sympy.polys.polyerrors import DomainError from sympy.polys.polyconfig import query +from sympy.core.symbol import Dummy -def sdp_groebner(f, u, O, K, gens='', verbose=False, method=None): +def groebner(seq, ring, method=None): """ Computes Groebner basis for a set of polynomials in `K[X]`. @@ -28,23 +16,36 @@ """ if method is None: - method = query('GB_METHOD') + method = query('groebner') _groebner_methods = { - 'buchberger': buchberger, - 'f5b': f5b, + 'buchberger': _buchberger, + 'f5b': _f5b, } try: - func = _groebner_methods[method] + _groebner = _groebner_methods[method] except KeyError: raise ValueError("'%s' is not a valid Groebner bases algorithm (valid are 'buchberger' and 'f5b')" % method) - else: - return func(f, u, O, K, gens, verbose) -# Buchberger algorithm + domain, orig = ring.domain, None + + if not domain.has_Field or not domain.has_assoc_Field: + try: + orig, ring = ring, ring.clone(domain=domain.get_field()) + except DomainError: + raise DomainError("can't compute a Groebner basis over %s" % domain) + else: + seq = [ s.set_ring(ring) for s in seq ] + + G = _groebner(seq, ring) + + if orig is not None: + G = [ g.clear_denoms()[1].set_ring(orig) for g in G ] -def buchberger(f, u, O, K, gens='', verbose=False): + return G + +def _buchberger(f, ring): """ Computes Groebner basis for a set of polynomials in `K[X]`. @@ -81,39 +82,35 @@ Computational Approach to Commutative Algebra, Springer, 1993, page 232. - Added optional ``gens`` argument to apply :func:`sdp_str` for - the purpose of debugging the algorithm. - """ - if not K.has_Field: - raise DomainError("can't compute a Groebner basis over %s" % K) + order = ring.order + domain = ring.domain def select(P): # normal selection strategy # select the pair with minimum LCM(LM(f), LM(g)) - pr = min(P, key=lambda pair: O(monomial_lcm(sdp_LM(f[pair[0]], u), sdp_LM(f[pair[1]], u)))) + pr = min(P, key=lambda pair: order(monomial_lcm(f[pair[0]].LM, f[pair[1]].LM))) return pr def normal(g, J): - h = sdp_rem(g, [ f[j] for j in J ], u, O, K) + h = g.rem([ f[j] for j in J ]) if not h: return None else: - h = sdp_monic(h, K) - h = tuple(h) + h = h.monic() if not h in I: I[h] = len(f) f.append(h) - return sdp_LM(h, u), I[h] + return h.LM, I[h] def update(G, B, ih): # update G using the set of critical pairs B and h # [BW] page 230 h = f[ih] - mh = sdp_LM(h, u) + mh = h.LM # filter new pairs (h, g), g in G C = G.copy() @@ -123,18 +120,18 @@ # select a pair (h, g) by popping an element from C ig = C.pop() g = f[ig] - mg = sdp_LM(g, u) + mg = g.LM LCMhg = monomial_lcm(mh, mg) def lcm_divides(ip): # LCM(LM(h), LM(p)) divides LCM(LM(h), LM(g)) - m = monomial_lcm(mh, sdp_LM(f[ip], u)) + m = monomial_lcm(mh, f[ip].LM) return monomial_div(LCMhg, m) # HT(h) and HT(g) disjoint: mh*mg == LCMhg if monomial_mul(mh, mg) == LCMhg or ( not any(lcm_divides(ipx) for ipx in C) and - not any(lcm_divides(pr[1]) for pr in D)): + not any(lcm_divides(pr[1]) for pr in D)): D.add((ih, ig)) E = set() @@ -142,7 +139,7 @@ while D: # select h, g from D (h the same as above) ih, ig = D.pop() - mg = sdp_LM(f[ig], u) + mg = f[ig].LM LCMhg = monomial_lcm(mh, mg) if not monomial_mul(mh, mg) == LCMhg: @@ -154,14 +151,14 @@ while B: # select g1, g2 from B (-> CP) ig1, ig2 = B.pop() - mg1 = sdp_LM(f[ig1], u) - mg2 = sdp_LM(f[ig2], u) + mg1 = f[ig1].LM + mg2 = f[ig2].LM LCM12 = monomial_lcm(mg1, mg2) # if HT(h) does not divide lcm(HT(g1), HT(g2)) if not monomial_div(LCM12, mh) or \ monomial_lcm(mg1, mh) == LCM12 or \ - monomial_lcm(mg2, mh) == LCM12: + monomial_lcm(mg2, mh) == LCM12: B_new.add((ig1, ig2)) B_new |= E @@ -171,7 +168,7 @@ while G: ig = G.pop() - mg = sdp_LM(f[ig], u) + mg = f[ig].LM if not monomial_div(mg, mh): G_new.add(ig) @@ -193,15 +190,14 @@ for i in range(len(f)): p = f[i] - r = sdp_rem(p, f[:i], u, O, K) + r = p.rem(f[:i]) if r: - f1.append(sdp_monic(r, K)) + f1.append(r.monic()) if f == f1: break - f = [tuple(p) for p in f] I = {} # ip = I[p]; p = f[ip] F = set() # set of indices of polynomials G = set() # set of indices of intermediate would-be Groebner basis @@ -213,9 +209,10 @@ ##################################### # algorithm GROEBNERNEWS2 in [BW] page 232 + while F: - # select p with minimum monomial according to the monomial ordering O - h = min([f[x] for x in F], key=lambda f: O(sdp_LM(f, u))) + # select p with minimum monomial according to the monomial ordering + h = min([f[x] for x in F], key=lambda f: order(f.LM)) ih = I[h] F.remove(ih) G, CP = update(G, CP, ih) @@ -227,9 +224,9 @@ ig1, ig2 = select(CP) CP.remove((ig1, ig2)) - h = sdp_spoly(f[ig1], f[ig2], u, O, K) + h = spoly(f[ig1], f[ig2]) # ordering divisors is on average more efficient [Cox] page 111 - G1 = sorted(G, key=lambda g: O(sdp_LM(f[g], u))) + G1 = sorted(G, key=lambda g: order(f[g].LM)) ht = normal(h, G1) if ht: @@ -247,59 +244,27 @@ if ht: Gr.add(ht[1]) - Gr = [list(f[ig]) for ig in Gr] + Gr = [f[ig] for ig in Gr] # order according to the monomial ordering - Gr = sorted(Gr, key=lambda f: O(sdp_LM(f, u)), reverse=True) - - if verbose: - print('reductions_to_zero = %d' % reductions_to_zero) + Gr = sorted(Gr, key=lambda f: order(f.LM), reverse=True) return Gr -def sdp_str(f, gens): - if isinstance(gens, str): - gens = gens.split(',') - ngens = len(gens) - s = '' - for expv, c in f: - if c > 0: - s += ' +' - else: - s += ' -' - if c < 0: - c = -c - if c != 1: # and expv != z: - cnt1 = str(c) - else: - cnt1 = '' - sa = [] - for i in range(ngens): - exp = expv[i] - if exp > 1: - sa.append('%s^%d' % (gens[i], exp)) - if exp == 1: - sa.append('%s' % gens[i]) - if cnt1: - sa = [cnt1] + sa - s += '*'.join(sa) - return s - - -def sdp_spoly(p1, p2, u, O, K): +def spoly(p1, p2): """ Compute LCM(LM(p1), LM(p2))/LM(p1)*p1 - LCM(LM(p1), LM(p2))/LM(p2)*p2 This is the S-poly provided p1 and p2 are monic """ - LM1 = sdp_LM(p1, u) - LM2 = sdp_LM(p2, u) + LM1 = p1.LM + LM2 = p2.LM LCM12 = monomial_lcm(LM1, LM2) m1 = monomial_div(LCM12, LM1) m2 = monomial_div(LCM12, LM2) - s1 = sdp_mul_term(p1, (m1, K.one), u, O, K) - s2 = sdp_mul_term(p2, (m2, K.one), u, O, K) - s = sdp_sub(s1, s2, u, O, K) + s1 = p1.mul_monom(m1) + s2 = p2.mul_monom(m2) + s = s1 - s2 return s # F5B @@ -329,14 +294,14 @@ # signature functions -def sig_cmp(u, v, O): +def sig_cmp(u, v, order): """ Compare two signatures by extending the term order to K[X]^n. u < v iff - the index of v is greater than the index of u or - - the index of v is equal to the index of u and u[0] < v[0] w.r.t. O + - the index of v is equal to the index of u and u[0] < v[0] w.r.t. order u > v otherwise """ @@ -345,12 +310,12 @@ if u[1] == v[1]: #if u[0] == v[0]: # return 0 - if O(u[0]) < O(v[0]): + if order(u[0]) < order(v[0]): return -1 return 1 -def sig_key(s, O): +def sig_key(s, order): """ Key for comparing two signatures. @@ -359,7 +324,7 @@ s < t iff [k > l] or [k == l and m < n] s > t otherwise """ - return (-s[1], O(s[0])) + return (-s[1], order(s[0])) def sig_mult(s, m): @@ -374,34 +339,34 @@ # labeled polynomial functions -def lbp_sub(f, g, u, O, K): +def lbp_sub(f, g): """ Subtract labeled polynomial g from f. The signature and number of the difference of f and g are signature and number of the maximum of f and g, w.r.t. lbp_cmp. """ - if sig_cmp(Sign(f), Sign(g), O) < 0: + if sig_cmp(Sign(f), Sign(g), Polyn(f).ring.order) < 0: max_poly = g else: max_poly = f - ret = sdp_sub(Polyn(f), Polyn(g), u, O, K) + ret = Polyn(f) - Polyn(g) return lbp(Sign(max_poly), ret, Num(max_poly)) -def lbp_mul_term(f, cx, u, O, K): +def lbp_mul_term(f, cx): """ Multiply a labeled polynomial with a term. The product of a labeled polynomial (s, p, k) by a monomial is defined as (m * s, m * p, k). """ - return lbp(sig_mult(Sign(f), cx[0]), sdp_mul_term(Polyn(f), cx, u, O, K), Num(f)) + return lbp(sig_mult(Sign(f), cx[0]), Polyn(f).mul_term(cx), Num(f)) -def lbp_cmp(f, g, O): +def lbp_cmp(f, g): """ Compare two labeled polynomials. @@ -412,7 +377,7 @@ f > g otherwise """ - if sig_cmp(Sign(f), Sign(g), O) == -1: + if sig_cmp(Sign(f), Sign(g), Polyn(f).ring.order) == -1: return -1 if Sign(f) == Sign(g): if Num(f) > Num(g): @@ -422,16 +387,16 @@ return 1 -def lbp_key(f, O): +def lbp_key(f): """ Key for comparing two labeled polynomials. """ - return (sig_key(Sign(f), O), -Num(f)) + return (sig_key(Sign(f), Polyn(f).ring.order), -Num(f)) # algorithm and helper functions -def critical_pair(f, g, u, O, K): +def critical_pair(f, g, ring): """ Compute the critical pair corresponding to two labeled polynomials. @@ -444,32 +409,29 @@ f) and um are lightweight and f (in the tuple) is a reference to an already existing object in memory. """ - ltf = sdp_LT(Polyn(f), u, K) - ltg = sdp_LT(Polyn(g), u, K) - lt = (monomial_lcm(ltf[0], ltg[0]), K.one) + domain = ring.domain - if K.has_Field: - term_div = _term_ff_div - else: - term_div = _term_rr_div + ltf = Polyn(f).LT + ltg = Polyn(g).LT + lt = (monomial_lcm(ltf[0], ltg[0]), domain.one) - um = term_div(lt, ltf, K) - vm = term_div(lt, ltg, K) + um = term_div(lt, ltf, domain) + vm = term_div(lt, ltg, domain) # The full information is not needed (now), so only the product # with the leading term is considered: - fr = lbp_mul_term(lbp(Sign(f), [sdp_LT(Polyn(f), u, K)], Num(f)), um, u, O, K) - gr = lbp_mul_term(lbp(Sign(g), [sdp_LT(Polyn(g), u, K)], Num(g)), vm, u, O, K) + fr = lbp_mul_term(lbp(Sign(f), Polyn(f).leading_term, Num(f)), um) + gr = lbp_mul_term(lbp(Sign(g), Polyn(g).leading_term, Num(g)), vm) # return in proper order, such that the S-polynomial is just # u_first * f_first - u_second * f_second: - if lbp_cmp(fr, gr, O) == -1: + if lbp_cmp(fr, gr) == -1: return (Sign(gr), vm, g, Sign(fr), um, f) else: return (Sign(fr), um, f, Sign(gr), vm, g) -def cp_cmp(c, d, O): +def cp_cmp(c, d): """ Compare two critical pairs c and d. @@ -483,18 +445,20 @@ c > d otherwise """ - c0 = lbp(c[0], [], Num(c[2])) - d0 = lbp(d[0], [], Num(d[2])) + zero = Polyn(c[2]).ring.zero + + c0 = lbp(c[0], zero, Num(c[2])) + d0 = lbp(d[0], zero, Num(d[2])) - r = lbp_cmp(c0, d0, O) + r = lbp_cmp(c0, d0) if r == -1: return -1 if r == 0: - c1 = lbp(c[3], [], Num(c[5])) - d1 = lbp(d[3], [], Num(d[5])) + c1 = lbp(c[3], zero, Num(c[5])) + d1 = lbp(d[3], zero, Num(d[5])) - r = lbp_cmp(c1, d1, O) + r = lbp_cmp(c1, d1) if r == -1: return -1 @@ -503,23 +467,23 @@ return 1 -def cp_key(c, O): +def cp_key(c, ring): """ Key for comparing critical pairs. """ - return (lbp_key(lbp(c[0], [], Num(c[2])), O), lbp_key(lbp(c[3], [], Num(c[5])), O)) + return (lbp_key(lbp(c[0], ring.zero, Num(c[2]))), lbp_key(lbp(c[3], ring.zero, Num(c[5])))) -def s_poly(cp, u, O, K): +def s_poly(cp): """ Compute the S-polynomial of a critical pair. The S-polynomial of a critical pair cp is cp[1] * cp[2] - cp[4] * cp[5]. """ - return lbp_sub(lbp_mul_term(cp[2], cp[1], u, O, K), lbp_mul_term(cp[5], cp[4], u, O, K), u, O, K) + return lbp_sub(lbp_mul_term(cp[2], cp[1]), lbp_mul_term(cp[5], cp[4])) -def is_rewritable_or_comparable(sign, num, B, u, K): +def is_rewritable_or_comparable(sign, num, B): """ Check if a labeled polynomial is redundant by checking if its signature and number imply rewritability or comparability. @@ -535,18 +499,18 @@ for h in B: # comparable if sign[1] < Sign(h)[1]: - if monomial_divides(sign[0], sdp_LM(Polyn(h), u)): + if monomial_divides(Polyn(h).LM, sign[0]): return True # rewritable if sign[1] == Sign(h)[1]: if num < Num(h): - if monomial_divides(sign[0], Sign(h)[0]): + if monomial_divides(Sign(h)[0], sign[0]): return True return False -def f5_reduce(f, B, u, O, K): +def f5_reduce(f, B): """ F5-reduce a labeled polynomial f by B. @@ -556,50 +520,49 @@ found, f gets replaced by f - lt_f / lt_h * h. If no such h can be found or f is 0, f is no further F5-reducible and f gets returned. - A polynomial that is reducible in the usual sense (sdp_rem) - need not be F5-reducible, e.g.: + A polynomial that is reducible in the usual sense need not be + F5-reducible, e.g.: >>> from sympy.polys.groebnertools import lbp, sig, f5_reduce, Polyn - >>> from sympy.polys.distributedpolys import sdp_rem >>> from sympy.polys.monomialtools import lex - >>> from sympy import QQ + >>> from sympy.polys import ring, QQ - >>> f = lbp(sig((1, 1, 1), 4), [((1, 0, 0), QQ(1))], 3) - >>> g = lbp(sig((0, 0, 0), 2), [((1, 0, 0), QQ(1))], 2) + >>> R, x,y,z = ring("x,y,z", QQ) - >>> sdp_rem(Polyn(f), [Polyn(g)], 2, lex, QQ) - [] - >>> f5_reduce(f, [g], 2, lex, QQ) - (((1, 1, 1), 4), [((1, 0, 0), 1/1)], 3) + >>> f = lbp(sig((1, 1, 1), 4), x, 3) + >>> g = lbp(sig((0, 0, 0), 2), x, 2) + + >>> Polyn(f).rem([Polyn(g)]) + 0 + >>> f5_reduce(f, [g]) + (((1, 1, 1), 4), x, 3) """ - if Polyn(f) == []: - return f + order = Polyn(f).ring.order + domain = Polyn(f).ring.domain - if K.has_Field: - term_div = _term_ff_div - else: - term_div = _term_rr_div + if not Polyn(f): + return f while True: g = f for h in B: - if Polyn(h) != []: - if monomial_divides(sdp_LM(Polyn(f), u), sdp_LM(Polyn(h), u)): - t = term_div(sdp_LT(Polyn(f), u, K), sdp_LT(Polyn(h), u, K), K) - if sig_cmp(sig_mult(Sign(h), t[0]), Sign(f), O) < 0: + if Polyn(h): + if monomial_divides(Polyn(h).LM, Polyn(f).LM): + t = term_div(Polyn(f).LT, Polyn(h).LT, domain) + if sig_cmp(sig_mult(Sign(h), t[0]), Sign(f), order) < 0: # The following check need not be done and is in general slower than without. - #if not is_rewritable_or_comparable(Sign(gp), Num(gp), B, u, K): - hp = lbp_mul_term(h, t, u, O, K) - f = lbp_sub(f, hp, u, O, K) + #if not is_rewritable_or_comparable(Sign(gp), Num(gp), B): + hp = lbp_mul_term(h, t) + f = lbp_sub(f, hp) break - if g == f or Polyn(f) == []: + if g == f or not Polyn(f): return f -def f5b(F, u, O, K, gens='', verbose=False): +def _f5b(F, ring): """ Computes a reduced Groebner basis for the ideal generated by F. @@ -631,8 +594,8 @@ Thomas Becker, Volker Weispfenning, Groebner bases: A computational approach to commutative algebra, 1993, p. 203, 216 """ - if not K.has_Field: - raise DomainError("can't compute a Groebner basis over %s" % K) + order = ring.order + domain = ring.domain # reduce polynomials (like in Mario Pernici's implementation) (Becker, Weispfenning, p. 203) B = F @@ -642,21 +605,21 @@ for i in range(len(F)): p = F[i] - r = sdp_rem(p, F[:i], u, O, K) + r = p.rem(F[:i]) - if r != []: + if r: B.append(r) if F == B: break # basis - B = [lbp(sig((0,) * (u + 1), i + 1), F[i], i + 1) for i in range(len(F))] - B.sort(key=lambda f: O(sdp_LM(Polyn(f), u)), reverse=True) + B = [lbp(sig(ring.zero_monom, i + 1), F[i], i + 1) for i in range(len(F))] + B.sort(key=lambda f: order(Polyn(f).LM), reverse=True) # critical pairs - CP = [critical_pair(B[i], B[j], u, O, K) for i in range(len(B)) for j in range(i + 1, len(B))] - CP.sort(key=lambda cp: cp_key(cp, O), reverse=True) + CP = [critical_pair(B[i], B[j], ring) for i in range(len(B)) for j in range(i + 1, len(B))] + CP.sort(key=lambda cp: cp_key(cp, ring), reverse=True) k = len(B) @@ -666,24 +629,24 @@ cp = CP.pop() # discard redundant critical pairs: - if is_rewritable_or_comparable(cp[0], Num(cp[2]), B, u, K): + if is_rewritable_or_comparable(cp[0], Num(cp[2]), B): continue - if is_rewritable_or_comparable(cp[3], Num(cp[5]), B, u, K): + if is_rewritable_or_comparable(cp[3], Num(cp[5]), B): continue - s = s_poly(cp, u, O, K) + s = s_poly(cp) - p = f5_reduce(s, B, u, O, K) + p = f5_reduce(s, B) - p = lbp(Sign(p), sdp_monic(Polyn(p), K), k + 1) + p = lbp(Sign(p), Polyn(p).monic(), k + 1) - if Polyn(p) != []: + if Polyn(p): # remove old critical pairs, that become redundant when adding p: indices = [] for i, cp in enumerate(CP): - if is_rewritable_or_comparable(cp[0], Num(cp[2]), [p], u, K): + if is_rewritable_or_comparable(cp[0], Num(cp[2]), [p]): indices.append(i) - elif is_rewritable_or_comparable(cp[3], Num(cp[5]), [p], u, K): + elif is_rewritable_or_comparable(cp[3], Num(cp[5]), [p]): indices.append(i) for i in reversed(indices): @@ -691,25 +654,25 @@ # only add new critical pairs that are not made redundant by p: for g in B: - if Polyn(g) != []: - cp = critical_pair(p, g, u, O, K) - if is_rewritable_or_comparable(cp[0], Num(cp[2]), [p], u, K): + if Polyn(g): + cp = critical_pair(p, g, ring) + if is_rewritable_or_comparable(cp[0], Num(cp[2]), [p]): continue - elif is_rewritable_or_comparable(cp[3], Num(cp[5]), [p], u, K): + elif is_rewritable_or_comparable(cp[3], Num(cp[5]), [p]): continue CP.append(cp) # sort (other sorting methods/selection strategies were not as successful) - CP.sort(key=lambda cp: cp_key(cp, O), reverse=True) + CP.sort(key=lambda cp: cp_key(cp, ring), reverse=True) # insert p into B: - m = sdp_LM(Polyn(p), u) - if O(m) <= O(sdp_LM(Polyn(B[-1]), u)): + m = Polyn(p).LM + if order(m) <= order(Polyn(B[-1]).LM): B.append(p) else: for i, q in enumerate(B): - if O(m) > O(sdp_LM(Polyn(q), u)): + if order(m) > order(Polyn(q).LM): B.insert(i, p) break @@ -719,34 +682,31 @@ else: reductions_to_zero += 1 - if verbose: - print(("%d reductions to zero" % reductions_to_zero)) - # reduce Groebner basis: - H = [sdp_monic(Polyn(g), K) for g in B] - H = red_groebner(H, u, O, K) + H = [Polyn(g).monic() for g in B] + H = red_groebner(H, ring) - return sorted(H, key=lambda f: O(sdp_LM(f, u)), reverse=True) + return sorted(H, key=lambda f: order(f.LM), reverse=True) -def red_groebner(G, u, O, K): +def red_groebner(G, ring): """ Compute reduced Groebner basis, from BeckerWeispfenning93, p. 216 Selects a subset of generators, that already generate the ideal and computes a reduced Groebner basis for them. """ - def reduction(P, u, O, K): + def reduction(P): """ The actual reduction algorithm. """ Q = [] for i, p in enumerate(P): - h = sdp_rem(p, P[:i] + P[i + 1:], u, O, K) - if h != []: + h = p.rem(P[:i] + P[i + 1:]) + if h: Q.append(h) - return [sdp_monic(p, K) for p in Q] + return [p.monic() for p in Q] F = G H = [] @@ -754,215 +714,139 @@ while F: f0 = F.pop() - if not any(monomial_divides(sdp_LM(f0, u), sdp_LM(f, u)) for f in F + H): + if not any(monomial_divides(f.LM, f0.LM) for f in F + H): H.append(f0) # Becker, Weispfenning, p. 217: H is Groebner basis of the ideal generated by G. - return reduction(H, u, O, K) + return reduction(H) -def is_groebner(G, u, O, K): +def is_groebner(G, ring): """ Check if G is a Groebner basis. """ for i in range(len(G)): for j in range(i + 1, len(G)): - s = sdp_spoly(G[i], G[j], u, O, K) - s = sdp_rem(s, G, u, O, K) - if s != []: + s = spoly(G[i], G[j]) + s = s.rem(G) + if s: return False return True -def is_minimal(G, u, O, K): +def is_minimal(G, ring): """ Checks if G is a minimal Groebner basis. """ - G.sort(key=lambda g: O(sdp_LM(g, u))) + order = ring.order + domain = ring.domain + + G.sort(key=lambda g: order(g.LM)) + for i, g in enumerate(G): - if sdp_LC(g, K) != K.one: + if g.LC != domain.one: return False for h in G[:i] + G[i + 1:]: - if monomial_divides(sdp_LM(g, u), sdp_LM(h, u)): + if monomial_divides(h.LM, g.LM): return False return True -def is_reduced(G, u, O, K): +def is_reduced(G, ring): """ Checks if G is a reduced Groebner basis. """ - G.sort(key=lambda g: O(sdp_LM(g, u))) + order = ring.order + domain = ring.domain + + G.sort(key=lambda g: order(g.LM)) + for i, g in enumerate(G): - if sdp_LC(g, K) != K.one: + if g.LC != domain.one: return False for term in g: for h in G[:i] + G[i + 1:]: - if monomial_divides(term[0], sdp_LM(h, u)): + if monomial_divides(h.LM, term[0]): return False return True - -def monomial_divides(m1, m2): - """ - Returns True if m2 divides m1, False otherwise. Does not create - the quotient. Does not check if both are have the same length. +def groebner_lcm(f, g): """ - for i in range(len(m1)): - if m1[i] < m2[i]: - return False + Computes LCM of two polynomials using Groebner bases. - return True - -# FGLM - -def matrix_fglm(F, u, O_from, O_to, K): - """ - Converts the reduced Groebner basis ``F`` of a zero-dimensional - ideal w.r.t. ``O_from`` to a reduced Groebner basis - w.r.t. ``O_to``. + The LCM is computed as the unique generater of the intersection + of the two ideals generated by `f` and `g`. The approach is to + compute a Groebner basis with respect to lexicographic ordering + of `t*f` and `(1 - t)*g`, where `t` is an unrelated variable and + then filtering out the solution that doesn't contain `t`. References ========== - J.C. Faugere, P. Gianni, D. Lazard, T. Mora (1994). Efficient - Computation of Zero-dimensional Groebner Bases by Change of - Ordering - - J.C. Faugere's lecture notes: - http://www-salsa.lip6.fr/~jcf/Papers/2010_MPRI5e.pdf - """ - old_basis = _basis(F, u, O_from, K) - M = _representing_matrices(old_basis, F, u, O_from, K) - - # V contains the normalforms (wrt O_from) of S - S = [(0,) * (u + 1)] - V = [[K.one] + [K.zero] * (len(old_basis) - 1)] - G = [] - - L = [(i, 0) for i in range(u + 1)] # (i, j) corresponds to x_i * S[j] - L.sort(key=lambda k_l1: O_to(_incr_k(S[k_l1[1]], k_l1[0])), reverse=True) - t = L.pop() - - P = _identity_matrix(len(old_basis), K) - - while True: - s = len(S) - v = _matrix_mul(M[t[0]], V[t[1]], K) - _lambda = _matrix_mul(P, v, K) - - if all(_lambda[i] == K.zero for i in range(s, len(old_basis))): - # there is a linear combination of v by V - - lt = [(_incr_k(S[t[1]], t[0]), K.one)] - rest = sdp_strip(sdp_sort([(S[i], _lambda[i]) for i in range(s)], O_to)) - g = sdp_sub(lt, rest, u, O_to, K) - - if g != []: - G.append(g) - - else: - # v is linearly independant from V - P = _update(s, _lambda, P, K) - S.append(_incr_k(S[t[1]], t[0])) - V.append(v) - - L.extend([(i, s) for i in range(u + 1)]) - L = list(set(L)) - L.sort(key=lambda k_l: O_to(_incr_k(S[k_l[1]], k_l[0])), reverse=True) - - L = [(k, l) for (k, l) in L if \ - all(monomial_div(_incr_k(S[l], k), sdp_LM(g, u)) is None for g in G)] - - if not L: - G = [ sdp_monic(g, K) for g in G ] - return sorted(G, key=lambda g: O_to(sdp_LM(g, u)), reverse=True) - - t = L.pop() - + 1. [Cox97]_ -def _incr_k(m, k): - return tuple(list(m[:k]) + [m[k] + 1] + list(m[k + 1:])) - - -def _identity_matrix(n, K): - M = [[K.zero] * n for _ in range(n)] - - for i in range(n): - M[i][i] = K.one - - return M - - -def _matrix_mul(M, v, K): - return [sum([row[i] * v[i] for i in range(len(v))]) for row in M] - - -def _update(s, _lambda, P, K): """ - Update ``P`` such that for the updated `P'` `P' v = e_{s}`. - """ - k = min([j for j in range(s, len(_lambda)) if _lambda[j] != 0]) + assert f.ring == g.ring - for r in range(len(_lambda)): - if r != k: - P[r] = [P[r][j] - (P[k][j] * _lambda[r]) / _lambda[k] for j in range(len(P[r]))] + ring = f.ring + domain = ring.domain - P[k] = [P[k][j] / _lambda[k] for j in range(len(P[k]))] + if not f or not g: + return ring.zero - P[k], P[s] = P[s], P[k] + if len(f) <= 1 and len(g) <= 1: + monom = monomial_lcm(f.LM, g.LM) + coeff = domain.lcm(f.LC, g.LC) + return ring.term_new(monom, coeff) - return P + fc, f = f.primitive() + gc, g = g.primitive() + lcm = domain.lcm(fc, gc) -def _representing_matrices(basis, G, u, O, K): - """ - Compute the matrices corresponding to the linear maps `m \mapsto - x_i m` for all variables `x_i`. - """ - def var(i): - return tuple([0] * i + [1] + [0] * (u - i)) + f_terms = [ ((1,) + monom, coeff) for monom, coeff in f.terms() ] + g_terms = [ ((0,) + monom, coeff) for monom, coeff in g.terms() ] \ + + [ ((1,) + monom,-coeff) for monom, coeff in g.terms() ] - def representing_matrix(m): - M = [[K.zero] * len(basis) for _ in range(len(basis))] + t = Dummy("t") + t_ring = ring.clone(symbols=(t,) + ring.symbols, order=lex) - for i, v in enumerate(basis): - r = sdp_rem([(monomial_mul(m, v), K.one)], G, u, O, K) + F = t_ring.from_terms(f_terms) + G = t_ring.from_terms(g_terms) - for term in r: - j = basis.index(term[0]) - M[j][i] = term[1] + basis = groebner([F, G], t_ring) - return M + def is_independent(h, j): + return all(not monom[j] for monom in h.monoms()) - return [representing_matrix(var(i)) for i in range(u + 1)] + H = [ h for h in basis if is_independent(h, 0) ] + h_terms = [ (monom[1:], coeff*lcm) for monom, coeff in H[0].terms() ] + h = ring.from_terms(h_terms) -def _basis(G, u, O, K): - """ - Computes a list of monomials which are not divisible by the leading - monomials wrt to ``O`` of ``G``. These monomials are a basis of - `K[X_1, \ldots, X_n]/(G)`. - """ - leading_monomials = [sdp_LM(g, u) for g in G] - candidates = [(0,) * (u + 1)] - basis = [] + return h + +def groebner_gcd(f, g): + """Computes GCD of two polynomials using Groebner bases. """ + assert f.ring == g.ring + domain = f.ring.domain - while candidates: - t = candidates.pop() - basis.append(t) + if not domain.has_Field: + fc, f = f.primitive() + gc, g = g.primitive() + gcd = domain.gcd(fc, gc) - new_candidates = [_incr_k(t, k) for k in range(u + 1) \ - if all(monomial_div(_incr_k(t, k), lmg) is None \ - for lmg in leading_monomials)] - candidates.extend(new_candidates) - candidates.sort(key=lambda m: O(m), reverse=True) + H = (f*g).quo([groebner_lcm(f, g)]) - basis = list(set(basis)) + assert len(H) == 1 + h = H[0] - return sorted(basis, key=lambda m: O(m)) + if not domain.has_Field: + return gcd*h + else: + return h.monic() diff -Nru python3-sympy-0.7.2/sympy/polys/heuristicgcd.py python3-sympy-0.7.3/sympy/polys/heuristicgcd.py --- python3-sympy-0.7.2/sympy/polys/heuristicgcd.py 1970-01-01 00:00:00.000000000 +0000 +++ python3-sympy-0.7.3/sympy/polys/heuristicgcd.py 2013-07-13 17:53:32.000000000 +0000 @@ -0,0 +1,147 @@ +"""Heuristic polynomial GCD algorithm (HEUGCD). """ + +HEU_GCD_MAX = 6 + +def heugcd(f, g): + """ + Heuristic polynomial GCD in ``Z[X]``. + + Given univariate polynomials ``f`` and ``g`` in ``Z[X]``, returns + their GCD and cofactors, i.e. polynomials ``h``, ``cff`` and ``cfg`` + such that:: + + h = gcd(f, g), cff = quo(f, h) and cfg = quo(g, h) + + The algorithm is purely heuristic which means it may fail to compute + the GCD. This will be signaled by raising an exception. In this case + you will need to switch to another GCD method. + + The algorithm computes the polynomial GCD by evaluating polynomials + ``f`` and ``g`` at certain points and computing (fast) integer GCD + of those evaluations. The polynomial GCD is recovered from the integer + image by interpolation. The evaluation proces reduces f and g variable + by variable into a large integer. The final step is to verify if the + interpolated polynomial is the correct GCD. This gives cofactors of + the input polynomials as a side effect. + + Examples + ======== + + >>> from sympy.polys.heuristicgcd import heugcd + >>> from sympy.polys import ring, ZZ + + >>> R, x,y, = ring("x,y", ZZ) + + >>> f = x**2 + 2*x*y + y**2 + >>> g = x**2 + x*y + + >>> h, cff, cfg = heugcd(f, g) + >>> h, cff, cfg + (x + y, x + y, x) + + >>> cff*h == f + True + >>> cfg*h == g + True + + References + ========== + + 1. [Liao95]_ + + """ + assert f.ring == g.ring and f.ring.domain.is_ZZ + + ring = f.ring + x0 = ring.gens[0] + domain = ring.domain + + gcd, f, g = f.extract_ground(g) + + f_norm = f.max_norm() + g_norm = g.max_norm() + + B = domain(2*min(f_norm, g_norm) + 29) + + x = max(min(B, 99*domain.sqrt(B)), + 2*min(f_norm // abs(f.LC), + g_norm // abs(g.LC)) + 2) + + for i in range(0, HEU_GCD_MAX): + ff = f.evaluate(x0, x) + gg = g.evaluate(x0, x) + + if ff and gg: + if ring.ngens == 1: + h, cff, cfg = domain.cofactors(ff, gg) + else: + h, cff, cfg = heugcd(ff, gg) + + h = _gcd_interpolate(h, x, ring) + h = h.primitive()[1] + + cff_, r = f.div(h) + + if not r: + cfg_, r = g.div(h) + + if not r: + h = h.mul_ground(gcd) + return h, cff_, cfg_ + + cff = _gcd_interpolate(cff, x, ring) + + h, r = f.div(cff) + + if not r: + cfg_, r = g.div(h) + + if not r: + h = h.mul_ground(gcd) + return h, cff, cfg_ + + cfg = _gcd_interpolate(cfg, x, ring) + + h, r = g.div(cfg) + + if not r: + cff_, r = f.div(h) + + if not r: + h = h.mul_ground(gcd) + return h, cff_, cfg + + x = 73794*x * domain.sqrt(domain.sqrt(x)) // 27011 + + raise HeuristicGCDFailed('no luck') + +def _gcd_interpolate(h, x, ring): + """Interpolate polynomial GCD from integer GCD. """ + f, i = ring.zero, 0 + + # TODO: don't expose poly repr implementation details + if ring.ngens == 1: + while h: + g = h % x + if g > x // 2: g -= x + h = (h - g) // x + + # f += X**i*g + if g: + f[(i,)] = g + i += 1 + else: + while h: + g = h.trunc_ground(x) + h = (h - g).quo_ground(x) + + # f += X**i*g + if g: + for monom, coeff in g.terms(): + f[(i,) + monom] = coeff + i += 1 + + if f.LC < 0: + return -f + else: + return f diff -Nru python3-sympy-0.7.2/sympy/polys/monomialtools.py python3-sympy-0.7.3/sympy/polys/monomialtools.py --- python3-sympy-0.7.2/sympy/polys/monomialtools.py 2012-10-17 03:02:22.000000000 +0000 +++ python3-sympy-0.7.3/sympy/polys/monomialtools.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,10 +1,12 @@ """Tools and arithmetics for monomials of distributed polynomials. """ -from sympy.core import S, C, Symbol, Mul, Tuple -from sympy.polys.polyutils import PicklableWithSlots +from sympy.core import S, C, Symbol, Mul, Tuple, Expr, sympify +from sympy.core.compatibility import iterable +from sympy.polys.polyutils import PicklableWithSlots, dict_from_expr from sympy.utilities import cythonized from sympy.polys.polyerrors import ExactQuotientFailed + def monomials(variables, degree): r""" Generate a set of monomials of the given total degree or less. @@ -45,11 +47,12 @@ monoms = monomials(tail, degree) - for i in range(1, degree+1): - monoms |= set([ x**i * m for m in monomials(tail, degree-i) ]) + for i in range(1, degree + 1): + monoms |= set([ x**i * m for m in monomials(tail, degree - i) ]) return monoms + def monomial_count(V, N): r""" Computes the number of monomials. @@ -81,20 +84,21 @@ """ return C.factorial(V + N) / C.factorial(V) / C.factorial(N) + class MonomialOrder(object): """Base class for monomial orderings. """ alias = None is_global = None - def key(self, monomial): - raise NotImplementedError + def __repr__(self): + return self.__class__.__name__ + "()" def __str__(self): return self.alias def __call__(self, monomial): - return self.key(monomial) + raise NotImplementedError def __eq__(self, other): return self.__class__ == other.__class__ @@ -105,33 +109,37 @@ def __ne__(self, other): return not (self == other) + class LexOrder(MonomialOrder): """Lexicographic order of monomials. """ alias = 'lex' is_global = True - def key(self, monomial): + def __call__(self, monomial): return monomial + class GradedLexOrder(MonomialOrder): """Graded lexicographic order of monomials. """ alias = 'grlex' is_global = True - def key(self, monomial): + def __call__(self, monomial): return (sum(monomial), monomial) + class ReversedGradedLexOrder(MonomialOrder): """Reversed graded lexicographic order of monomials. """ alias = 'grevlex' is_global = True - def key(self, monomial): + def __call__(self, monomial): return (sum(monomial), tuple(reversed([-m for m in monomial]))) + class ProductOrder(MonomialOrder): """ A product order built from other monomial orders. @@ -179,12 +187,16 @@ def __init__(self, *args): self.args = args - def key(self, monomial): + def __call__(self, monomial): return tuple(O(lamda(monomial)) for (O, lamda) in self.args) + def __repr__(self): + from sympy.core import Tuple + return self.__class__.__name__ + repr(Tuple(*[x[0] for x in self.args])) + def __str__(self): from sympy.core import Tuple - return "ProductOrder" + str(Tuple(*[x[0] for x in self.args])) + return self.__class__.__name__ + str(Tuple(*[x[0] for x in self.args])) def __eq__(self, other): if not isinstance(other, ProductOrder): @@ -202,6 +214,7 @@ return False return None + class InverseOrder(MonomialOrder): """ The "inverse" of another monomial order. @@ -227,13 +240,14 @@ def __str__(self): return "i" + str(self.O) - def key(self, monomial): + def __call__(self, monomial): from sympy.core.compatibility import iterable + def inv(l): if iterable(l): return tuple(inv(x) for x in l) return -l - return inv(self.O.key(monomial)) + return inv(self.O(monomial)) @property def is_global(self): @@ -257,14 +271,15 @@ igrevlex = InverseOrder(grevlex) _monomial_key = { - 'lex' : lex, - 'grlex' : grlex, - 'grevlex' : grevlex, - 'ilex' : ilex, - 'igrlex' : igrlex, - 'igrevlex' : igrevlex + 'lex': lex, + 'grlex': grlex, + 'grevlex': grevlex, + 'ilex': ilex, + 'igrlex': igrlex, + 'igrevlex': igrevlex } + def monomial_key(order=None): """ Return a function defining admissible order on monomials. @@ -301,6 +316,7 @@ else: raise ValueError("monomial ordering specification must be a string or a callable, got %s" % order) + class _ItemGetter(object): """Helper class to return a subsequence of values.""" @@ -315,6 +331,7 @@ return False return self.seq == other.seq + def build_product_order(arg, gens): """ Build a monomial order on ``gens``. @@ -339,11 +356,13 @@ for expr in arg: name = expr[0] var = expr[1:] + def makelambda(var): return _ItemGetter(gens2idx[g] for g in var) order.append((monomial_key(name), makelambda(var))) return ProductOrder(*order) + @cythonized("a,b") def monomial_mul(A, B): """ @@ -361,6 +380,7 @@ """ return tuple([ a + b for a, b in zip(A, B) ]) + @cythonized("a,b,c") def monomial_div(A, B): """ @@ -381,13 +401,38 @@ `x*y**2*z**2` does not divide `x**3*y**4*z`. """ - C = [ a - b for a, b in zip(A, B) ] + C = monomial_ldiv(A, B) if all(c >= 0 for c in C): return tuple(C) else: return None +def monomial_ldiv(A, B): + """ + Division of tuples representing monomials. + + Lets divide `x**3*y**4*z` by `x*y**2`:: + + >>> from sympy.polys.monomialtools import monomial_ldiv + + >>> monomial_ldiv((3, 4, 1), (1, 2, 0)) + (2, 2, 1) + + which gives `x**2*y**2*z`. + + >>> monomial_ldiv((3, 4, 1), (1, 2, 2)) + (2, 2, -1) + + which gives `x**2*y**2*z**-1`. + + """ + return tuple([ a - b for a, b in zip(A, B) ]) + +def monomial_pow(A, n): + """Return the n-th pow of the monomial. """ + return tuple([ a*n for a in A ]) + @cythonized("a,b") def monomial_gcd(A, B): """ @@ -405,6 +450,7 @@ """ return tuple([ min(a, b) for a, b in zip(A, B) ]) + @cythonized("a,b") def monomial_lcm(A, B): """ @@ -423,6 +469,8 @@ return tuple([ max(a, b) for a, b in zip(A, B) ]) # TODO cythonize + + def monomial_divides(A, B): """ Does there exist a monomial X such that XA == B? @@ -435,6 +483,7 @@ """ return all(a <= b for a, b in zip(A, B)) + @cythonized("i,n") def monomial_max(*monoms): """ @@ -458,6 +507,7 @@ return tuple(M) + @cythonized("i,n") def monomial_min(*monoms): """ @@ -481,6 +531,7 @@ return tuple(M) + def monomial_deg(M): """ Returns the total degree of a monomial. @@ -493,13 +544,38 @@ """ return sum(M) +def term_div(a, b, domain): + """Division of two terms in over a ring/field. """ + a_lm, a_lc = a + b_lm, b_lc = b + + monom = monomial_div(a_lm, b_lm) + + if domain.has_Field: + if monom is not None: + return monom, domain.quo(a_lc, b_lc) + else: + return None + else: + if not (monom is None or a_lc % b_lc): + return monom, domain.quo(a_lc, b_lc) + else: + return None + class Monomial(PicklableWithSlots): """Class representing a monomial, i.e. a product of powers. """ __slots__ = ['exponents', 'gens'] - def __init__(self, exponents, gens=None): - self.exponents = tuple(exponents) + def __init__(self, monom, gens=None): + if not iterable(monom): + rep, gens = dict_from_expr(sympify(monom), gens=gens) + if len(rep) == 1 and list(rep.values())[0] == 1: + monom = list(rep.keys())[0] + else: + raise ValueError("Expected a monomial got %s" % monom) + + self.exponents = tuple(map(int, monom)) self.gens = gens def rebuild(self, exponents, gens=None): @@ -528,7 +604,8 @@ gens = gens or self.gens if not gens: - raise ValueError("can't convert %s to an expression without generators" % self) + raise ValueError( + "can't convert %s to an expression without generators" % self) return Mul(*[ gen**exp for gen, exp in zip(gens, self.exponents) ]) @@ -594,7 +671,8 @@ elif isinstance(other, (tuple, Tuple)): exponents = other else: - raise TypeError("an instance of Monomial class expected, got %s" % other) + raise TypeError( + "an instance of Monomial class expected, got %s" % other) return self.rebuild(monomial_gcd(self.exponents, exponents)) @@ -605,6 +683,7 @@ elif isinstance(other, (tuple, Tuple)): exponents = other else: - raise TypeError("an instance of Monomial class expected, got %s" % other) + raise TypeError( + "an instance of Monomial class expected, got %s" % other) return self.rebuild(monomial_lcm(self.exponents, exponents)) diff -Nru python3-sympy-0.7.2/sympy/polys/numberfields.py python3-sympy-0.7.3/sympy/polys/numberfields.py --- python3-sympy-0.7.2/sympy/polys/numberfields.py 2012-10-17 03:02:22.000000000 +0000 +++ python3-sympy-0.7.3/sympy/polys/numberfields.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,12 +1,13 @@ """Computational algebraic number field theory. """ from sympy import ( - S, Expr, Rational, - Symbol, Add, Mul, sympify, Q, ask, Dummy, Tuple + S, C, Expr, Rational, + Symbol, Add, Mul, sympify, Q, ask, Dummy, Tuple, expand_mul, I, pi ) from sympy.polys.polytools import ( - Poly, PurePoly, sqf_norm, invert, factor_list, groebner, + Poly, PurePoly, sqf_norm, invert, factor_list, groebner, resultant, + degree, poly_from_expr, parallel_poly_from_expr ) from sympy.polys.polyclasses import ( @@ -19,41 +20,570 @@ NotAlgebraic, ) +from sympy.polys.rootoftools import RootOf + +from sympy.polys.specialpolys import cyclotomic_poly + +from sympy.polys.polyutils import dict_from_expr, expr_from_dict + +from sympy.polys.domains import ZZ + +from sympy.polys.orthopolys import dup_chebyshevt + from sympy.printing.lambdarepr import LambdaPrinter from sympy.utilities import ( numbered_symbols, variations, lambdify, ) +from sympy.simplify.simplify import _mexpand, _is_sum_surds from sympy.ntheory import sieve +from sympy.ntheory.factor_ import divisors from sympy.mpmath import pslq, mp + +def _choose_factor(factors, x, v, prec=200): + """ + Return a factor having root ``v`` + It is assumed that one of the factors has root ``v``. + """ + if isinstance(factors[0], tuple): + factors = [xx[0] for xx in factors] + if len(factors) == 1: + return factors[0] + prec1 = 10 + reps = {x: v} + eps = 1./10**prec1 + while 1: + candidates = [] + for f in factors: + if abs(f.evalf(prec1, subs=reps)) < eps: + candidates.append(f) + if candidates: + factors = candidates + if len(factors) == 1: + return factors[0] + if prec1 > prec: + raise NotImplementedError("multiple candidates for the minimal polynomial of %s" % v) + prec1 *= 2 + +def _separate_sq(p): + """ + helper function for ``_minimal_polynomial_sq`` + + It selects a rational ``g`` such that the polynomial ``p`` + consists of a sum of terms whose surds squared have gcd equal to ``g`` + and a sum of terms with surds squared prime with ``g``; + then it takes the field norm to eliminate ``sqrt(g)`` + + See simplify.simplify.split_surds and polytools.sqf_norm. + + Examples + ======== + + >>> from sympy import sqrt + >>> from sympy.abc import x + >>> from sympy.polys.numberfields import _separate_sq + >>> p= -x + sqrt(2) + sqrt(3) + sqrt(7) + >>> p = _separate_sq(p); p + -x**2 + 2*sqrt(3)*x + 2*sqrt(7)*x - 2*sqrt(21) - 8 + >>> p = _separate_sq(p); p + -x**4 + 4*sqrt(7)*x**3 - 32*x**2 + 8*sqrt(7)*x + 20 + >>> p = _separate_sq(p); p + -x**8 + 48*x**6 - 536*x**4 + 1728*x**2 - 400 + + """ + from sympy.simplify.simplify import _split_gcd, _mexpand + from sympy.utilities.iterables import sift + def is_sqrt(expr): + return expr.is_Pow and expr.exp is S.Half + # p = c1*sqrt(q1) + ... + cn*sqrt(qn) -> a = [(c1, q1), .., (cn, qn)] + a = [] + for y in p.args: + if not y.is_Mul: + if is_sqrt(y): + a.append((S.One, y**2)) + elif y.is_Atom: + a.append((y, S.One)) + elif y.is_Pow and y.exp.is_integer: + a.append((y, S.One)) + else: + raise NotImplementedError + continue + sifted = sift(y.args, is_sqrt) + a.append((Mul(*sifted[False]), Mul(*sifted[True])**2)) + a.sort(key=lambda z: z[1]) + if a[-1][1] is S.One: + # there are no surds + return p + surds = [z for y, z in a] + for i in range(len(surds)): + if surds[i] != 1: + break + g, b1, b2 = _split_gcd(*surds[i:]) + a1 = [] + a2 = [] + for y, z in a: + if z in b1: + a1.append(y*z**S.Half) + else: + a2.append(y*z**S.Half) + p1 = Add(*a1) + p2 = Add(*a2) + p = _mexpand(p1**2) - _mexpand(p2**2) + return p + +def _minimal_polynomial_sq(p, n, x): + """ + Returns the minimal polynomial for the ``nth-root`` of a sum of surds + or ``None`` if it fails. + + Parameters + ========== + + p : sum of surds + n : positive integer + x : variable of the returned polynomial + + Examples + ======== + + >>> from sympy.polys.numberfields import _minimal_polynomial_sq + >>> from sympy import sqrt + >>> from sympy.abc import x + >>> q = 1 + sqrt(2) + sqrt(3) + >>> _minimal_polynomial_sq(q, 3, x) + x**12 - 4*x**9 - 4*x**6 + 16*x**3 - 8 + + """ + from sympy.simplify.simplify import _is_sum_surds + + p = sympify(p) + n = sympify(n) + r = _is_sum_surds(p) + if not n.is_Integer or not n > 0 or not _is_sum_surds(p): + return None + pn = p**Rational(1, n) + # eliminate the square roots + p -= x + while 1: + p1 = _separate_sq(p) + if p1 is p: + p = p1.subs({x:x**n}) + break + else: + p = p1 + + # _separate_sq eliminates field extensions in a minimal way, so that + # if n = 1 then `p = constant*(minimal_polynomial(p))` + # if n > 1 it contains the minimal polynomial as a factor. + if n == 1: + p1 = Poly(p) + if p.coeff(x**p1.degree(x)) < 0: + p = -p + p = p.primitive()[1] + return p + # by construction `p` has root `pn` + # the minimal polynomial is the factor vanishing in x = pn + factors = factor_list(p)[1] + + result = _choose_factor(factors, x, pn) + return result + +def _minpoly_op_algebraic_number(ex1, ex2, x, mp1=None, mp2=None, op=Add): + """ + return the minimal polinomial for ``op(ex1, ex2)`` + + Parameters + ========== + + ex1, ex2 : expressions for the algebraic numbers + x : indeterminate of the polynomials + mp1, mp2 : minimal polynomials for ``ex1`` and ``ex2`` or None + op : operation ``Add`` or ``Mul`` + + Examples + ======== + + >>> from sympy import sqrt, Mul + >>> from sympy.polys.numberfields import _minpoly_op_algebraic_number + >>> from sympy.abc import x + >>> p1 = sqrt(sqrt(2) + 1) + >>> p2 = sqrt(sqrt(2) - 1) + >>> _minpoly_op_algebraic_number(p1, p2, x, op=Mul) + x - 1 + + References + ========== + + [1] http://en.wikipedia.org/wiki/Resultant + [2] I.M. Isaacs, Proc. Amer. Math. Soc. 25 (1970), 638 + "Degrees of sums in a separable field extension". + """ + from sympy import gcd + y = Dummy(str(x)) + if mp1 is None: + mp1 = _minpoly1(ex1, x) + if mp2 is None: + mp2 = _minpoly1(ex2, y) + else: + mp2 = mp2.subs({x:y}) + + if op is Add: + # mp1a = mp1.subs({x:x - y}) + (p1, p2), _ = parallel_poly_from_expr((mp1, x - y), x, y) + r = p1.compose(p2) + mp1a = r.as_expr() + elif op is Mul: + mp1a = _muly(mp1, x, y) + else: + raise NotImplementedError('option not available') + r = resultant(mp1a, mp2, gens=[y, x]) + + deg1 = degree(mp1, x) + deg2 = degree(mp2, y) + if op is Add and gcd(deg1, deg2) == 1: + # `r` is irreducible, see [2] + return r + if op is Mul and deg1 == 1 or deg2 == 1: + # if deg1 = 1, then mp1 = x - a; mp1a = x - y - a; + # r = mp2(x - a), so that `r` is irreducible + return r + _, factors = factor_list(r) + if op in [Add, Mul]: + ex = op(ex1, ex2) + res = _choose_factor(factors, x, ex) + return res + +def _invertx(p, x): + """ + Returns ``expand_mul(x**degree(p, x)*p.subs(x, 1/x))`` + """ + p1 = poly_from_expr(p, x)[0] + + terms = p1.terms() + n = terms[0][0][0] + a = [c*x**(n - i[0]) for i, c in terms] + return Add(*a) + +def _muly(p, x, y): + """ + Returns ``_mexpand(y**deg*p.subs({x:x / y}))`` + """ + d = dict_from_expr(p)[0] + n = max(d.keys())[0] + d1 = {} + for monom, coeff in d.items(): + i = monom[0] + expv = (i, n - i) + d1[expv] = coeff + p1 = expr_from_dict(d1, x, y) + return p1 + + +def _minpoly_pow(ex, pw, x, mp=None): + """ + Returns ``minpoly(ex**pw, x)`` + + Parameters + ========== + + p : algebraic number + mp : minimal polynomial of ``p`` + pw : rational number + x : indeterminate of the polynomial + + Examples + ======== + + >>> from sympy import sqrt + >>> from sympy.polys.numberfields import _minpoly_pow, minpoly + >>> from sympy.abc import x + >>> p = sqrt(1 + sqrt(2)) + >>> _minpoly_pow(p, 2, x) + x**2 - 2*x - 1 + >>> minpoly(p**2, x) + x**2 - 2*x - 1 + """ + pw = sympify(pw) + if not mp: + mp = _minpoly1(ex, x) + if not pw.is_rational: + raise NotAlgebraic("%s doesn't seem to be an algebraic number" % ex) + if pw < 0: + if mp == x: + raise ZeroDivisionError('%s is zero' % ex) + mp = _invertx(mp, x) + if pw == -1: + return mp + pw = -pw + ex = 1/ex + y = Dummy(str(x)) + mp = mp.subs({x:y}) + n, d = pw.as_numer_denom() + res = resultant(mp, x**d - y**n, gens=[y]) + _, factors = factor_list(res) + res = _choose_factor(factors, x, ex**pw) + return res + +def _minpoly_add(x, *a): + """ + returns ``minpoly(Add(*a), x)`` + """ + mp = _minpoly_op_algebraic_number(a[0], a[1], x, op=Add) + p = a[0] + a[1] + for px in a[2:]: + mp = _minpoly_op_algebraic_number(p, px, x, mp1=mp, op=Add) + p = p + px + return mp + +def _minpoly_mul(x, *a): + """ + returns ``minpoly(Mul(*a), x)`` + """ + mp = _minpoly_op_algebraic_number(a[0], a[1], x, op=Mul) + p = a[0] * a[1] + for px in a[2:]: + mp = _minpoly_op_algebraic_number(p, px, x, mp1=mp, op=Mul) + p = p * px + return mp + +def _minpoly_sin(ex, x): + """ + Returns the minimal polynomial of ``sin(ex)`` + see http://mathworld.wolfram.com/TrigonometryAngles.html + """ + from sympy.functions.combinatorial.factorials import binomial + c, a = ex.args[0].as_coeff_Mul() + if a is pi: + if c.is_rational: + n = c.q + q = sympify(n) + if q.is_prime: + # for a = pi*p/q with q odd prime, using chebyshevt + # write sin(q*a) = mp(sin(a))*sin(a); + # the roots of mp(x) are sin(pi*p/q) for p = 1,..., q - 1 + a = dup_chebyshevt(n, ZZ) + return Add(*[x**(n - i - 1)*a[i] for i in range(n)]) + if c.p == 1: + if q == 9: + return 64*x**6 - 96*x**4 + 36*x**2 - 3 + + if n % 2 == 1: + # for a = pi*p/q with q odd, use + # sin(q*a) = 0 to see that the minimal polynomial must be + # a factor of dup_chebyshevt(n, ZZ) + a = dup_chebyshevt(n, ZZ) + a = [x**(n - i)*a[i] for i in range(n + 1)] + r = Add(*a) + _, factors = factor_list(r) + res = _choose_factor(factors, x, ex) + return res + + expr = ((1 - C.cos(2*c*pi))/2)**S.Half + res = _minpoly1(expr, x) + return res + + raise NotAlgebraic("%s doesn't seem to be an algebraic number" % ex) + +def _minpoly_cos(ex, x): + """ + Returns the minimal polynomial of ``cos(ex)`` + see http://mathworld.wolfram.com/TrigonometryAngles.html + """ + from sympy import sqrt + c, a = ex.args[0].as_coeff_Mul() + if a is pi: + if c.is_rational: + if c.p == 1: + if c.q == 7: + return 8*x**3 - 4*x**2 - 4*x + 1 + if c.q == 9: + return 8*x**3 - 6*x + 1 + elif c.p == 2: + q = sympify(c.q) + if q.is_prime: + s = _minpoly_sin(ex, x) + return _mexpand(s.subs({x:sqrt((1 - x)/2)})) + + # for a = pi*p/q, cos(q*a) =T_q(cos(a)) = (-1)**p + n = int(c.q) + a = dup_chebyshevt(n, ZZ) + a = [x**(n - i)*a[i] for i in range(n + 1)] + r = Add(*a) - (-1)**c.p + _, factors = factor_list(r) + res = _choose_factor(factors, x, ex) + return res + + raise NotAlgebraic("%s doesn't seem to be an algebraic number" % ex) + +def _minpoly_exp(ex, x): + """ + Returns the minimal polynomial of ``exp(ex)`` + """ + c, a = ex.args[0].as_coeff_Mul() + p = sympify(c.p) + q = sympify(c.q) + if a == I*pi: + if c.is_rational: + if c.p == 1 or c.p == -1: + if q == 3: + return x**2 - x + 1 + if q == 4: + return x**4 + 1 + if q == 6: + return x**4 - x**2 + 1 + if q == 8: + return x**8 + 1 + if q == 9: + return x**6 - x**3 + 1 + if q == 10: + return x**8 - x**6 + x**4 - x**2 + 1 + if q.is_prime: + s = 0 + for i in range(q): + s += (-x)**i + return s + + # x**(2*q) = product(factors) + factors = [cyclotomic_poly(i, x) for i in divisors(2*q)] + mp = _choose_factor(factors, x, ex) + return mp + else: + raise NotAlgebraic("%s doesn't seem to be an algebraic number" % ex) + raise NotAlgebraic("%s doesn't seem to be an algebraic number" % ex) + +def _minpoly_rootof(ex, x): + """ + Returns the minimal polynomial of a ``RootOf`` object. + """ + p = ex.expr + p = p.subs({ex.poly.gens[0]:x}) + _, factors = factor_list(p, x) + result = _choose_factor(factors, x, ex) + return result + + +def _minpoly1(ex, x): + """ + Computes the minimal polynomial of an algebraic number + using operations on minimal polynomials + + Examples + ======== + + >>> from sympy import minimal_polynomial, sqrt, Rational + >>> from sympy.abc import x + >>> minimal_polynomial(sqrt(2) + 3*Rational(1, 3), x, compose=True) + x**2 - 2*x - 1 + """ + if ex.is_Rational: + return ex.q*x - ex.p + if ex is I: + return x**2 + 1 + + if _is_sum_surds(ex): + # eliminate the square roots + ex -= x + while 1: + ex1 = _separate_sq(ex) + if ex1 is ex: + return ex + else: + ex = ex1 + + if ex.is_Add: + res = _minpoly_add(x, *ex.args) + elif ex.is_Mul: + res = _minpoly_mul(x, *ex.args) + elif ex.is_Pow: + res = _minpoly_pow(ex.base, ex.exp, x) + elif ex.__class__ is C.sin: + res = _minpoly_sin(ex, x) + elif ex.__class__ is C.cos: + res = _minpoly_cos(ex, x) + elif ex.__class__ is C.exp: + res = _minpoly_exp(ex, x) + elif ex.__class__ is RootOf: + res = _minpoly_rootof(ex, x) + else: + raise NotAlgebraic("%s doesn't seem to be an algebraic number" % ex) + return res + + def minimal_polynomial(ex, x=None, **args): """ Computes the minimal polynomial of an algebraic number. + Parameters + ========== + + ex : algebraic number expression + + x : indipendent variable of the minimal polynomial + + Options + ======= + + compose : if ``True`` _minpoly1`` is used, else the ``groebner`` algorithm + + polys : if ``True`` returns a ``Poly`` object + + Notes + ===== + + By default ``compose=True``, the minimal polynomial of the subexpressions of ``ex`` + are computed, then the arithmetic operations on them are performed using the resultant + and factorization. + If ``compose=False``, a bottom-up algorithm is used with ``groebner``. + The default algorithm stalls less frequently. + Examples ======== - >>> from sympy import minimal_polynomial, sqrt + >>> from sympy import minimal_polynomial, sqrt, solve >>> from sympy.abc import x >>> minimal_polynomial(sqrt(2), x) x**2 - 2 >>> minimal_polynomial(sqrt(2) + sqrt(3), x) x**4 - 10*x**2 + 1 + >>> minimal_polynomial(solve(x**3 + x + 3)[0], x) + x**3 + x + 3 """ - generator = numbered_symbols('a', cls=Dummy) - mapping, symbols, replace = {}, {}, [] + from sympy.polys.polytools import degree + from sympy.core.function import expand_multinomial + from sympy.core.basic import preorder_traversal + compose = args.get('compose', True) + polys = args.get('polys', False) ex = sympify(ex) + for expr in preorder_traversal(ex): + if expr.is_AlgebraicNumber: + compose = False + break + + if ex.is_AlgebraicNumber: + compose = False if x is not None: x, cls = sympify(x), Poly else: x, cls = Dummy('x'), PurePoly + if compose: + result = _minpoly1(ex, x) + result = result.primitive()[1] + c = result.coeff(x**degree(result, x)) + if c < 0: + result = expand_mul(-result) + c = -c + return cls(result, x, field=True) if polys else result + + generator = numbered_symbols('a', cls=Dummy) + mapping, symbols, replace = {}, {}, [] + def update_mapping(ex, exp, base=None): a = next(generator) symbols[ex] = a @@ -94,12 +624,11 @@ return bottom_up_scan(base) else: ex = base**(-ex.exp) - if not ex.exp.is_Integer: - base, exp = (ex.base**ex.exp.p).expand(), Rational(1, ex.exp.q) + base, exp = ( + ex.base**ex.exp.p).expand(), Rational(1, ex.exp.q) else: base, exp = ex.base, ex.exp - base = bottom_up_scan(base) expr = base**exp @@ -115,8 +644,31 @@ raise NotAlgebraic("%s doesn't seem to be an algebraic number" % ex) - polys = args.get('polys', False) + def simpler_inverse(ex): + """ + Returns True if it is more likely that the minimal polynomial + algorithm works better with the inverse + """ + if ex.is_Pow: + if (1/ex.exp).is_integer and ex.exp < 0: + if ex.base.is_Add: + return True + if ex.is_Mul: + hit = True + a = [] + for p in ex.args: + if p.is_Add: + return False + if p.is_Pow: + if p.base.is_Add and p.exp > 0: + return False + + if hit: + return True + return False + inverted = False + ex = expand_multinomial(ex) if ex.is_AlgebraicNumber: if not polys: return ex.minpoly.as_expr(x) @@ -125,20 +677,32 @@ elif ex.is_Rational: result = ex.q*x - ex.p else: - F = [x - bottom_up_scan(ex)] + list(mapping.values()) - G = groebner(F, list(symbols.values()) + [x], order='lex') - - _, factors = factor_list(G[-1]) - - if len(factors) == 1: - ((result, _),) = factors - else: - for result, _ in factors: - if result.subs(x, ex).evalf(chop=True) == 0: - break - else: # pragma: no cover - raise NotImplementedError("multiple candidates for the minimal polynomial of %s" % ex) - + inverted = simpler_inverse(ex) + if inverted: + ex = ex**-1 + res = None + if ex.is_Pow and (1/ex.exp).is_Integer: + n = 1/ex.exp + res = _minimal_polynomial_sq(ex.base, n, x) + + elif _is_sum_surds(ex): + res = _minimal_polynomial_sq(ex, S.One, x) + + if res is not None: + result = res + + if res is None: + bus = bottom_up_scan(ex) + F = [x - bus] + list(mapping.values()) + G = groebner(F, list(symbols.values()) + [x], order='lex') + + _, factors = factor_list(G[-1]) + # by construction G[-1] has root `ex` + result = _choose_factor(factors, x, ex) + if inverted: + result = _invertx(result, x) + if result.coeff(x**degree(result, x)) < 0: + result = expand_mul(-result) if polys: return cls(result, x, field=True) else: @@ -146,11 +710,13 @@ minpoly = minimal_polynomial + def _coeffs_generator(n): """Generate coefficients for `primitive_element()`. """ - for coeffs in variations([1,-1], n, repetition=True): + for coeffs in variations([1, -1], n, repetition=True): yield list(coeffs) + def primitive_element(extension, x=None, **args): """Construct a common number field for all extensions. """ if not extension: @@ -160,7 +726,6 @@ x, cls = sympify(x), Poly else: x, cls = Dummy('x'), PurePoly - if not args.get('ex', False): extension = [ AlgebraicNumber(ext, gen=x) for ext in extension ] @@ -203,12 +768,13 @@ for i, (h, y) in enumerate(list(zip(H, Y))): try: - H[i] = Poly(y - h, x, domain='QQ').all_coeffs() # XXX: composite=False - except CoercionFailed: # pragma: no cover - break # G is not a triangular set + H[i] = Poly(y - h, x, + domain='QQ').all_coeffs() # XXX: composite=False + except CoercionFailed: # pragma: no cover + break # G is not a triangular set else: break - else: # pragma: no cover + else: # pragma: no cover raise RuntimeError("run out of coefficient configurations") _, g = g.clear_denoms() @@ -218,6 +784,7 @@ else: return g, coeffs, H + def is_isomorphism_possible(a, b): """Returns `True` if there is a chance for isomorphism. """ n = a.minpoly.degree() @@ -248,6 +815,7 @@ return True + def field_isomorphism_pslq(a, b): """Construct field isomorphism using PSLQ algorithm. """ if not a.root.is_real or not b.root.is_real: @@ -285,10 +853,10 @@ h = Poly(coeffs, f.gen, domain='QQ') if f.compose(h).rem(g).is_zero: - d, approx = len(coeffs)-1, 0 + d, approx = len(coeffs) - 1, 0 for i, coeff in enumerate(coeffs): - approx += coeff*B**(d-i) + approx += coeff*B**(d - i) if A*approx < 0: return [ -c for c in coeffs ] @@ -301,6 +869,7 @@ return None + def field_isomorphism_factor(a, b): """Construct field isomorphism via factorization. """ _, factors = factor_list(a.minpoly, extension=b) @@ -308,10 +877,10 @@ for f, _ in factors: if f.degree() == 1: coeffs = f.rep.TC().to_sympy_list() - d, terms = len(coeffs)-1, [] + d, terms = len(coeffs) - 1, [] for i, coeff in enumerate(coeffs): - terms.append(coeff*b.root**(d-i)) + terms.append(coeff*b.root**(d - i)) root = Add(*terms) @@ -323,6 +892,7 @@ else: return None + def field_isomorphism(a, b, **args): """Construct an isomorphism between two number fields. """ a, b = sympify(a), sympify(b) @@ -356,6 +926,7 @@ return field_isomorphism_factor(a, b) + def to_number_field(extension, theta=None, **args): """Express `extension` in the field generated by `theta`. """ gen = args.get('gen') @@ -384,7 +955,9 @@ if coeffs is not None: return AlgebraicNumber(theta, coeffs) else: - raise IsomorphismFailed("%s is not in a subfield of %s" % (root, theta.root)) + raise IsomorphismFailed( + "%s is not in a subfield of %s" % (root, theta.root)) + class AlgebraicNumber(Expr): """Class for representing algebraic numbers in SymPy. """ @@ -405,7 +978,8 @@ elif expr.is_AlgebraicNumber: minpoly, root = expr.minpoly, expr.root else: - minpoly, root = minimal_polynomial(expr, args.get('gen'), polys=True), expr + minpoly, root = minimal_polynomial( + expr, args.get('gen'), polys=True), expr dom = minpoly.get_domain() @@ -444,7 +1018,6 @@ return obj - def __hash__(self): return super(AlgebraicNumber, self).__hash__() @@ -485,14 +1058,15 @@ if f.LC() == 1: return self - coeff = f.LC()**(f.degree()-1) - poly = f.compose(Poly(f.gen/f.LC())) + coeff = f.LC()**(f.degree() - 1) + poly = f.compose(Poly(f.gen/f.LC())) minpoly = poly*coeff - root = f.LC()*self.root + root = f.LC()*self.root return AlgebraicNumber((minpoly, root), self.coeffs()) + class IntervalPrinter(LambdaPrinter): """Use ``lambda`` printer but print numbers as ``mpi`` intervals. """ @@ -505,6 +1079,7 @@ def _print_Pow(self, expr): return super(IntervalPrinter, self)._print_Pow(expr, rational=True) + def isolate(alg, eps=None, fast=False): """Give a rational isolating interval for an algebraic number. """ alg = sympify(alg) @@ -512,8 +1087,8 @@ if alg.is_Rational: return (alg, alg) elif not ask(Q.real(alg)): - raise NotImplementedError("complex algebraic numbers are not supported") - + raise NotImplementedError( + "complex algebraic numbers are not supported") func = lambdify((), alg, modules="mpmath", printer=IntervalPrinter()) diff -Nru python3-sympy-0.7.2/sympy/polys/orthopolys.py python3-sympy-0.7.3/sympy/polys/orthopolys.py --- python3-sympy-0.7.2/sympy/polys/orthopolys.py 2012-10-17 03:02:22.000000000 +0000 +++ python3-sympy-0.7.3/sympy/polys/orthopolys.py 2013-07-13 17:53:32.000000000 +0000 @@ -14,16 +14,17 @@ from sympy.polys.domains import ZZ, QQ + @cythonized("n,i") def dup_jacobi(n, a, b, K): """Low-level implementation of Jacobi polynomials. """ - seq = [[K.one], [(a+b+K(2))/K(2), (a-b)/K(2)]] + seq = [[K.one], [(a + b + K(2))/K(2), (a - b)/K(2)]] - for i in range(2, n+1): - den = K(i)*(a+b+i)*(a+b+K(2)*i-K(2)) - f0 = (a+b+K(2)*i-K.one) * (a*a-b*b) / (K(2)*den) - f1 = (a+b+K(2)*i-K.one) * (a+b+K(2)*i-K(2)) * (a+b+K(2)*i) / (K(2)*den) - f2 = (a+i-K.one)*(b+i-K.one)*(a+b+K(2)*i) / den + for i in range(2, n + 1): + den = K(i)*(a + b + i)*(a + b + K(2)*i - K(2)) + f0 = (a + b + K(2)*i - K.one) * (a*a - b*b) / (K(2)*den) + f1 = (a + b + K(2)*i - K.one) * (a + b + K(2)*i - K(2)) * (a + b + K(2)*i) / (K(2)*den) + f2 = (a + i - K.one)*(b + i - K.one)*(a + b + K(2)*i) / den p0 = dup_mul_ground(seq[-1], f0, K) p1 = dup_mul_ground(dup_lshift(seq[-1], 1, K), f1, K) p2 = dup_mul_ground(seq[-2], f2, K) @@ -31,6 +32,7 @@ return seq[n] + def jacobi_poly(n, a, b, x=None, **args): """Generates Jacobi polynomial of degree `n` in `x`. """ if n < 0: @@ -49,12 +51,13 @@ else: return poly + @cythonized("n,i") def dup_gegenbauer(n, a, K): """Low-level implementation of Gegenbauer polynomials. """ seq = [[K.one], [K(2)*a, K.zero]] - for i in range(2, n+1): + for i in range(2, n + 1): f1 = K(2) * (i + a - K.one) / i f2 = (i + K(2)*a - K(2)) / i p1 = dup_mul_ground(dup_lshift(seq[-1], 1, K), f1, K) @@ -63,10 +66,12 @@ return seq[n] + def gegenbauer_poly(n, a, x=None, **args): """Generates Gegenbauer polynomial of degree `n` in `x`. """ if n < 0: - raise ValueError("can't generate Gegenbauer polynomial of degree %s" % n) + raise ValueError( + "can't generate Gegenbauer polynomial of degree %s" % n) K, a = construct_domain(a, field=True) poly = DMP(dup_gegenbauer(int(n), a, K), K) @@ -81,21 +86,24 @@ else: return poly + @cythonized("n,i") def dup_chebyshevt(n, K): """Low-level implementation of Chebyshev polynomials of the 1st kind. """ seq = [[K.one], [K.one, K.zero]] - for i in range(2, n+1): + for i in range(2, n + 1): a = dup_mul_ground(dup_lshift(seq[-1], 1, K), K(2), K) seq.append(dup_sub(a, seq[-2], K)) return seq[n] + def chebyshevt_poly(n, x=None, **args): """Generates Chebyshev polynomial of the first kind of degree `n` in `x`. """ if n < 0: - raise ValueError("can't generate 1st kind Chebyshev polynomial of degree %s" % n) + raise ValueError( + "can't generate 1st kind Chebyshev polynomial of degree %s" % n) poly = DMP(dup_chebyshevt(int(n), ZZ), ZZ) @@ -109,21 +117,24 @@ else: return poly + @cythonized("n,i") def dup_chebyshevu(n, K): """Low-level implementation of Chebyshev polynomials of the 2nd kind. """ seq = [[K.one], [K(2), K.zero]] - for i in range(2, n+1): + for i in range(2, n + 1): a = dup_mul_ground(dup_lshift(seq[-1], 1, K), K(2), K) seq.append(dup_sub(a, seq[-2], K)) return seq[n] + def chebyshevu_poly(n, x=None, **args): """Generates Chebyshev polynomial of the second kind of degree `n` in `x`. """ if n < 0: - raise ValueError("can't generate 2nd kind Chebyshev polynomial of degree %s" % n) + raise ValueError( + "can't generate 2nd kind Chebyshev polynomial of degree %s" % n) poly = DMP(dup_chebyshevu(int(n), ZZ), ZZ) @@ -137,14 +148,15 @@ else: return poly + @cythonized("n,i") def dup_hermite(n, K): """Low-level implementation of Hermite polynomials. """ seq = [[K.one], [K(2), K.zero]] - for i in range(2, n+1): + for i in range(2, n + 1): a = dup_lshift(seq[-1], 1, K) - b = dup_mul_ground(seq[-2], K(i-1), K) + b = dup_mul_ground(seq[-2], K(i - 1), K) c = dup_mul_ground(dup_sub(a, b, K), K(2), K) @@ -152,6 +164,7 @@ return seq[n] + def hermite_poly(n, x=None, **args): """Generates Hermite polynomial of degree `n` in `x`. """ if n < 0: @@ -169,19 +182,21 @@ else: return poly + @cythonized("n,i") def dup_legendre(n, K): """Low-level implementation of Legendre polynomials. """ seq = [[K.one], [K.one, K.zero]] - for i in range(2, n+1): - a = dup_mul_ground(dup_lshift(seq[-1], 1, K), K(2*i-1, i), K) - b = dup_mul_ground(seq[-2], K(i-1, i), K) + for i in range(2, n + 1): + a = dup_mul_ground(dup_lshift(seq[-1], 1, K), K(2*i - 1, i), K) + b = dup_mul_ground(seq[-2], K(i - 1, i), K) seq.append(dup_sub(a, b, K)) return seq[n] + def legendre_poly(n, x=None, **args): """Generates Legendre polynomial of degree `n` in `x`. """ if n < 0: @@ -199,26 +214,29 @@ else: return poly + @cythonized("n,i") def dup_laguerre(n, alpha, K): """Low-level implementation of Laguerre polynomials. """ seq = [[K.zero], [K.one]] - for i in range(1, n+1): - a = dup_mul(seq[-1], [-K.one/i, alpha/i + K(2*i-1)/i], K) - b = dup_mul_ground(seq[-2], alpha/i + K(i-1)/i, K) + for i in range(1, n + 1): + a = dup_mul(seq[-1], [-K.one/i, alpha/i + K(2*i - 1)/i], K) + b = dup_mul_ground(seq[-2], alpha/i + K(i - 1)/i, K) seq.append(dup_sub(a, b, K)) return seq[-1] + def laguerre_poly(n, x=None, alpha=None, **args): """Generates Laguerre polynomial of degree `n` in `x`. """ if n < 0: raise ValueError("can't generate Laguerre polynomial of degree %s" % n) if alpha is not None: - K, alpha = construct_domain(alpha, field=True) # XXX: ground_field=True + K, alpha = construct_domain( + alpha, field=True) # XXX: ground_field=True else: K, alpha = QQ, QQ(0) @@ -234,28 +252,31 @@ else: return poly + @cythonized("n,i") def dup_spherical_bessel_fn(n, K): """ Low-level implementation of fn(n, x) """ seq = [[K.one], [K.one, K.zero]] - for i in range(2, n+1): - a = dup_mul_ground(dup_lshift(seq[-1], 1, K), K(2*i-1), K) + for i in range(2, n + 1): + a = dup_mul_ground(dup_lshift(seq[-1], 1, K), K(2*i - 1), K) seq.append(dup_sub(a, seq[-2], K)) return dup_lshift(seq[n], 1, K) + @cythonized("n,i") def dup_spherical_bessel_fn_minus(n, K): """ Low-level implementation of fn(-n, x) """ seq = [[K.one, K.zero], [K.zero]] - for i in range(2, n+1): + for i in range(2, n + 1): a = dup_mul_ground(dup_lshift(seq[-1], 1, K), K(3 - 2*i), K) seq.append(dup_sub(a, seq[-2], K)) return seq[n] + def spherical_bessel_fn(n, x=None, **args): """ Coefficients for the spherical Bessel functions. diff -Nru python3-sympy-0.7.2/sympy/polys/partfrac.py python3-sympy-0.7.3/sympy/polys/partfrac.py --- python3-sympy-0.7.2/sympy/polys/partfrac.py 2012-10-17 03:02:22.000000000 +0000 +++ python3-sympy-0.7.3/sympy/polys/partfrac.py 2013-07-13 17:53:32.000000000 +0000 @@ -3,11 +3,14 @@ from sympy.polys import Poly, RootSum, cancel, factor from sympy.polys.polytools import parallel_poly_from_expr from sympy.polys.polyoptions import allowed_flags, set_defaults +from sympy.polys.polyerrors import PolynomialError -from sympy.core import S, Add, sympify, Function, Lambda, Dummy -from sympy.utilities import numbered_symbols, take, threaded +from sympy.core import S, Add, sympify, Function, Lambda, Dummy, Mul, Expr +from sympy.core.basic import preorder_traversal +from sympy.utilities import numbered_symbols, take, xthreaded -@threaded + +@xthreaded def apart(f, x=None, full=False, **options): """ Compute partial fraction decomposition of a rational function. @@ -23,9 +26,22 @@ >>> from sympy.polys.partfrac import apart >>> from sympy.abc import x, y + By default, using the undetermined coefficients method: + >>> apart(y/(x + 2)/(x + 1), x) -y/(x + 2) + y/(x + 1) + You can choose Bronstein's algorithm by setting ``full=True``: + + >>> apart(y/(x**2 + x + 1), x) + y/(x**2 + x + 1) + >>> apart(y/(x**2 + x + 1), x, full=True) + RootSum(_w**2 + _w + 1, Lambda(_a, (-2*_a*y/3 - y/3)/(-_a + x))) + + See Also + ======== + + apart_list, assemble_partfrac_list """ allowed_flags(options, []) @@ -36,11 +52,53 @@ else: P, Q = f.as_numer_denom() + _options = options.copy() options = set_defaults(options, extension=True) - (P, Q), opt = parallel_poly_from_expr((P, Q), x, **options) + try: + (P, Q), opt = parallel_poly_from_expr((P, Q), x, **options) + except PolynomialError as msg: + if f.is_commutative: + raise PolynomialError(msg) + # non-commutative + if f.is_Mul: + c, nc = f.args_cnc(split_1=False) + nc = Mul(*[apart(i, x=x, full=full, **_options) for i in nc]) + if c: + c = apart(Mul._from_args(c), x=x, full=full, **_options) + return c*nc + else: + return nc + elif f.is_Add: + c = [] + nc = [] + for i in f.args: + if i.is_commutative: + c.append(i) + else: + try: + nc.append(apart(i, x=x, full=full, **_options)) + except NotImplementedError: + nc.append(i) + return apart(Add(*c), x=x, full=full, **_options) + Add(*nc) + else: + reps = [] + pot = preorder_traversal(f) + next(pot) + for e in pot: + try: + reps.append((e, apart(e, x=x, full=full, **_options))) + pot.skip() # this was handled successfully + except NotImplementedError: + pass + return f.xreplace(dict(reps)) if P.is_multivariate: - raise NotImplementedError("multivariate partial fraction decomposition") + fc = f.cancel() + if fc != f: + return apart(fc, x=x, full=full, **_options) + + raise NotImplementedError( + "multivariate partial fraction decomposition") common, P, Q = P.cancel(Q) @@ -65,6 +123,7 @@ return common*(poly.as_expr() + terms) + def apart_undetermined_coeffs(P, Q): """Partial fractions via method of undetermined coefficients. """ X = numbered_symbols(cls=Dummy) @@ -75,7 +134,7 @@ for f, k in factors: n, q = f.degree(), Q - for i in range(1, k+1): + for i in range(1, k + 1): coeffs, q = take(X, n), q.quo(f) partial.append((coeffs, q, f, i)) symbols.extend(coeffs) @@ -103,6 +162,7 @@ return result + def apart_full_decomposition(P, Q): """ Bronstein's full partial fraction decomposition algorithm. @@ -122,16 +182,178 @@ 1. [Bronstein93]_ """ + return assemble_partfrac_list(apart_list(P/Q, P.gens[0])) + + +def apart_list(f, x=None, dummies=None, **options): + """ + Compute partial fraction decomposition of a rational function + and return the result in structured form. + + Given a rational function ``f`` compute the partial fraction decomposition + of ``f``. Only Bronstein's full partial fraction decomposition algorithm + is supported by this method. The return value is highly structured and + perfectly suited for further algorithmic treatment rather than being + human-readable. The function returns a tuple holding three elements: + + * The first item is the common coefficient, free of the variable `x` used + for decomposition. (It is an element of the base field `K`.) + + * The second item is the polynomial part of the decomposition. This can be + the zero polynomial. (It is an element of `K[x]`.) + + * The third part itself is a list of quadruples. Each quadruple + has the following elements in this order: + + - The (not necessarily irreducible) polynomial `D` whose roots `w_i` appear + in the linear denominator of a bunch of related fraction terms. (This item + can also be a list of explicit roots. However, at the moment ``apart_list`` + never returns a result this way, but the related ``assemble_partfrac_list`` + function accepts this format as input.) + + - The numerator of the fraction, written as a function of the root `w` + + - The linear denominator of the fraction *excluding its power exponent*, + written as a function of the root `w`. + + - The power to which the denominator has to be raised. + + On can always rebuild a plain expression by using the function ``assemble_partfrac_list``. + + Examples + ======== + + A first example: + + >>> from sympy.polys.partfrac import apart_list, assemble_partfrac_list + >>> from sympy.abc import x, t + + >>> f = (2*x**3 - 2*x) / (x**2 - 2*x + 1) + >>> pfd = apart_list(f) + >>> pfd + (1, + Poly(2*x + 4, x, domain='ZZ'), + [(Poly(_w - 1, _w, domain='ZZ'), Lambda(_a, 4), Lambda(_a, -_a + x), 1)]) + + >>> assemble_partfrac_list(pfd) + 2*x + 4 + 4/(x - 1) + + Second example: + + >>> f = (-2*x - 2*x**2) / (3*x**2 - 6*x) + >>> pfd = apart_list(f) + >>> pfd + (-1, + Poly(2/3, x, domain='QQ'), + [(Poly(_w - 2, _w, domain='ZZ'), Lambda(_a, 2), Lambda(_a, -_a + x), 1)]) + + >>> assemble_partfrac_list(pfd) + -2/3 - 2/(x - 2) + + Another example, showing symbolic parameters: + + >>> pfd = apart_list(t/(x**2 + x + t), x) + >>> pfd + (1, + Poly(0, x, domain='ZZ[t]'), + [(Poly(_w**2 + _w + t, _w, domain='ZZ[t]'), + Lambda(_a, -2*_a*t/(4*t - 1) - t/(4*t - 1)), + Lambda(_a, -_a + x), + 1)]) + + >>> assemble_partfrac_list(pfd) + RootSum(_w**2 + _w + t, Lambda(_a, (-2*_a*t/(4*t - 1) - t/(4*t - 1))/(-_a + x))) + + This example is taken from Bronstein's original paper: + + >>> f = 36 / (x**5 - 2*x**4 - 2*x**3 + 4*x**2 + x - 2) + >>> pfd = apart_list(f) + >>> pfd + (1, + Poly(0, x, domain='ZZ'), + [(Poly(_w - 2, _w, domain='ZZ'), Lambda(_a, 4), Lambda(_a, -_a + x), 1), + (Poly(_w**2 - 1, _w, domain='ZZ'), Lambda(_a, -3*_a - 6), Lambda(_a, -_a + x), 2), + (Poly(_w + 1, _w, domain='ZZ'), Lambda(_a, -4), Lambda(_a, -_a + x), 1)]) + + >>> assemble_partfrac_list(pfd) + -4/(x + 1) - 3/(x + 1)**2 - 9/(x - 1)**2 + 4/(x - 2) + + See also + ======== + + apart, assemble_partfrac_list + + References + ========== + + 1. [Bronstein93]_ + + """ + allowed_flags(options, []) + + f = sympify(f) + + if f.is_Atom: + return f + else: + P, Q = f.as_numer_denom() + + options = set_defaults(options, extension=True) + (P, Q), opt = parallel_poly_from_expr((P, Q), x, **options) + + if P.is_multivariate: + raise NotImplementedError( + "multivariate partial fraction decomposition") + + common, P, Q = P.cancel(Q) + + poly, P = P.div(Q, auto=True) + P, Q = P.rat_clear_denoms(Q) + + polypart = poly + + if dummies is None: + def dummies(name): + d = Dummy(name) + while True: + yield d + + dummies = dummies("w") + + rationalpart = apart_list_full_decomposition(P, Q, dummies) + + return (common, polypart, rationalpart) + + +def apart_list_full_decomposition(P, Q, dummygen): + """ + Bronstein's full partial fraction decomposition algorithm. + + Given a univariate rational function ``f``, performing only GCD + operations over the algebraic closure of the initial ground domain + of definition, compute full partial fraction decomposition with + fractions having linear denominators. + + Note that no factorization of the initial denominator of ``f`` is + performed. The final decomposition is formed in terms of a sum of + :class:`RootSum` instances. + + References + ========== + + 1. [Bronstein93]_ + + """ f, x, U = P/Q, P.gen, [] u = Function('u')(x) a = Dummy('a') - partial = S(0) + partial = [] for d, n in Q.sqf_list_include(all=True): b = d.as_expr() - U += [ u.diff(x, n-1) ] + U += [ u.diff(x, n - 1) ] h = cancel(f*b**n) / u**n @@ -140,14 +362,14 @@ for j in range(1, n): H += [ H[-1].diff(x) / j ] - for j in range(1, n+1): - subs += [ (U[j-1], b.diff(x, j) / j) ] + for j in range(1, n + 1): + subs += [ (U[j - 1], b.diff(x, j) / j) ] for j in range(0, n): P, Q = cancel(H[j]).as_numer_denom() - for i in range(0, j+1): - P = P.subs(*subs[j-i]) + for i in range(0, j + 1): + P = P.subs(*subs[j - i]) Q = Q.subs(*subs[0]) @@ -160,10 +382,90 @@ B, g = Q.half_gcdex(D) b = (P * B.quo(g)).rem(D) - numer = b.as_expr() - denom = (x-a)**(n-j) + Dw = D.subs(x, next(dummygen)) + numer = Lambda(a, b.as_expr().subs(x, a)) + denom = Lambda(a, (x - a)) + exponent = n-j - func = Lambda(a, numer.subs(x, a)/denom) - partial += RootSum(D, func, auto=False) + partial.append((Dw, numer, denom, exponent)) return partial + + +def assemble_partfrac_list(partial_list): + r"""Reassemble a full partial fraction decomposition + from a structured result obtained by the function ``apart_list``. + + Examples + ======== + + This example is taken from Bronstein's original paper: + + >>> from sympy.polys.partfrac import apart_list, assemble_partfrac_list + >>> from sympy.abc import x, y + + >>> f = 36 / (x**5 - 2*x**4 - 2*x**3 + 4*x**2 + x - 2) + >>> pfd = apart_list(f) + >>> pfd + (1, + Poly(0, x, domain='ZZ'), + [(Poly(_w - 2, _w, domain='ZZ'), Lambda(_a, 4), Lambda(_a, -_a + x), 1), + (Poly(_w**2 - 1, _w, domain='ZZ'), Lambda(_a, -3*_a - 6), Lambda(_a, -_a + x), 2), + (Poly(_w + 1, _w, domain='ZZ'), Lambda(_a, -4), Lambda(_a, -_a + x), 1)]) + + >>> assemble_partfrac_list(pfd) + -4/(x + 1) - 3/(x + 1)**2 - 9/(x - 1)**2 + 4/(x - 2) + + If we happen to know some roots we can provide them easily inside the structure: + + >>> pfd = apart_list(2/(x**2-2)) + >>> pfd + (1, + Poly(0, x, domain='ZZ'), + [(Poly(_w**2 - 2, _w, domain='ZZ'), + Lambda(_a, _a/2), + Lambda(_a, -_a + x), + 1)]) + + >>> pfda = assemble_partfrac_list(pfd) + >>> pfda + RootSum(_w**2 - 2, Lambda(_a, _a/(-_a + x)))/2 + + >>> pfda.doit() + -sqrt(2)/(2*(x + sqrt(2))) + sqrt(2)/(2*(x - sqrt(2))) + + >>> from sympy import Dummy, Poly, Lambda, sqrt + >>> a = Dummy("a") + >>> pfd = (1, Poly(0, x, domain='ZZ'), [([sqrt(2),-sqrt(2)], Lambda(a, a/2), Lambda(a, -a + x), 1)]) + + >>> assemble_partfrac_list(pfd) + -sqrt(2)/(2*(x + sqrt(2))) + sqrt(2)/(2*(x - sqrt(2))) + + See also + ======== + + apart, apart_list + """ + # Common factor + common = partial_list[0] + + # Polynomial part + polypart = partial_list[1] + pfd = polypart.as_expr() + + # Rational parts + for r, nf, df, ex in partial_list[2]: + if isinstance(r, Poly): + # Assemble in case the roots are given implicitly by a polynomials + an, nu = nf.variables, nf.expr + ad, de = df.variables, df.expr + # Hack to make dummies equal because Lambda created new Dummies + de = de.subs(ad[0], an[0]) + func = Lambda(an, nu/de**ex) + pfd += RootSum(r, func, auto=False, quadratic=False) + else: + # Assemble in case the roots are given explicitely by a list of algebraic numbers + for root in r: + pfd += nf(root)/df(root)**ex + + return common*pfd diff -Nru python3-sympy-0.7.2/sympy/polys/polyclasses.py python3-sympy-0.7.3/sympy/polys/polyclasses.py --- python3-sympy-0.7.2/sympy/polys/polyclasses.py 2012-10-17 03:02:22.000000000 +0000 +++ python3-sympy-0.7.3/sympy/polys/polyclasses.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,5 +1,7 @@ """OO layer for several polynomial representations. """ +from sympy.core.sympify import CantSympify + from sympy.polys.polyutils import PicklableWithSlots from sympy.polys.polyerrors import CoercionFailed, NotReversible @@ -130,10 +132,12 @@ UnificationFailed, PolynomialError) + def init_normal_DMP(rep, lev, dom): return DMP(dmp_normal(rep, lev, dom), dom, lev) -class DMP(PicklableWithSlots): + +class DMP(PicklableWithSlots, CantSympify): """Dense Multivariate Polynomials over `K`. """ __slots__ = ['rep', 'lev', 'dom', 'ring'] @@ -255,7 +259,7 @@ return DMP(dict(list(zip(monoms, coeffs))), dom, lev, ring) def to_ring(f): - """Make the ground domain a field. """ + """Make the ground domain a ring. """ return f.convert(f.dom.get_ring()) def to_field(f): @@ -307,7 +311,7 @@ if n < 0: return [(0,)] else: - return [ (n-i,) for i, c in enumerate(f.rep) ] + return [ (n - i,) for i, c in enumerate(f.rep) ] else: raise PolynomialError('multivariate polynomials not supported') @@ -319,7 +323,7 @@ if n < 0: return [((0,), f.dom.zero)] else: - return [ ((n-i,), c) for i, c in enumerate(f.rep) ] + return [ ((n - i,), c) for i, c in enumerate(f.rep) ] else: raise PolynomialError('multivariate polynomials not supported') @@ -437,7 +441,7 @@ if isinstance(n, int): return f.per(dmp_pow(f.rep, n, f.lev, f.dom)) else: - raise TypeError("`int` expected, got %s" % type(n)) + raise TypeError("``int`` expected, got %s" % type(n)) def pdiv(f, g): """Polynomial pseudo-division of ``f`` and ``g``. """ @@ -486,11 +490,11 @@ return res def degree(f, j=0): - """Returns the leading degree of `f` in `x_j`. """ + """Returns the leading degree of ``f`` in ``x_j``. """ if isinstance(j, int): return dmp_degree_in(f.rep, j, f.lev) else: - raise TypeError("`int` expected, got %s" % type(j)) + raise TypeError("``int`` expected, got %s" % type(j)) def degree_list(f): """Returns a list of degrees of ``f``. """ @@ -545,29 +549,29 @@ return coeff, f.per(F) def integrate(f, m=1, j=0): - """Computes indefinite integral of ``f``. """ + """Computes the ``m``-th order indefinite integral of ``f`` in ``x_j``. """ if not isinstance(m, int): - raise TypeError("`int` expected, got %s" % type(m)) + raise TypeError("``int`` expected, got %s" % type(m)) if not isinstance(j, int): - raise TypeError("`int` expected, got %s" % type(j)) + raise TypeError("``int`` expected, got %s" % type(j)) return f.per(dmp_integrate_in(f.rep, m, j, f.lev, f.dom)) def diff(f, m=1, j=0): - """Computes `m`-th order derivative of `f` in `x_j`. """ + """Computes the ``m``-th order derivative of ``f`` in ``x_j``. """ if not isinstance(m, int): - raise TypeError("`int` expected, got %s" % type(m)) + raise TypeError("``int`` expected, got %s" % type(m)) if not isinstance(j, int): - raise TypeError("`int` expected, got %s" % type(j)) + raise TypeError("``int`` expected, got %s" % type(j)) return f.per(dmp_diff_in(f.rep, m, j, f.lev, f.dom)) def eval(f, a, j=0): - """Evaluates `f` at the given point `a` in `x_j`. """ + """Evaluates ``f`` at the given point ``a`` in ``x_j``. """ if not isinstance(j, int): - raise TypeError("`int` expected, got %s" % type(j)) + raise TypeError("``int`` expected, got %s" % type(j)) return f.per(dmp_eval_in(f.rep, f.dom.convert(a), j, f.lev, f.dom), kill=True) @@ -614,9 +618,12 @@ R = dmp_subresultants(F, G, lev, dom) return list(map(per, R)) - def resultant(f, g): + def resultant(f, g, includePRS=False): """Computes resultant of ``f`` and ``g`` via PRS. """ lev, dom, per, F, G = f.unify(g) + if includePRS: + res, R = dmp_resultant(F, G, lev, dom, includePRS=includePRS) + return per(res, kill=True), list(map(per, R)) return per(dmp_resultant(F, G, lev, dom), kill=True) def discriminant(f): @@ -660,7 +667,7 @@ return f.per(dmp_ground_trunc(f.rep, f.dom.convert(p), f.lev, f.dom)) def monic(f): - """Divides all coefficients by `LC(f)`. """ + """Divides all coefficients by ``LC(f)``. """ return f.per(dmp_ground_monic(f.rep, f.lev, f.dom)) def content(f): @@ -748,14 +755,21 @@ else: return dup_isolate_all_roots_sqf(f.rep, f.dom, eps=eps, inf=inf, sup=sup, fast=fast) else: - raise PolynomialError("can't isolate roots of a multivariate polynomial") + raise PolynomialError( + "can't isolate roots of a multivariate polynomial") def refine_root(f, s, t, eps=None, steps=None, fast=False): - """Refine an isolating interval to the given precision. """ + """ + Refine an isolating interval to the given precision. + + ``eps`` should be a rational number. + + """ if not f.lev: return dup_refine_real_root(f.rep, s, t, f.dom, eps=eps, steps=steps, fast=fast) else: - raise PolynomialError("can't refine a root of a multivariate polynomial") + raise PolynomialError( + "can't refine a root of a multivariate polynomial") def count_real_roots(f, inf=None, sup=None): """Return the number of real roots of ``f`` in ``[inf, sup]``. """ @@ -792,7 +806,7 @@ @property def is_primitive(f): - """Returns ``True`` if GCD of coefficients of ``f`` is one. """ + """Returns ``True`` if the GCD of the coefficients of ``f`` is one. """ return f.dom.is_one(dmp_ground_content(f.rep, f.lev, f.dom)) @property @@ -961,8 +975,8 @@ def _strict_eq(f, g): return isinstance(g, f.__class__) and f.lev == g.lev \ - and f.dom == g.dom \ - and f.rep == g.rep + and f.dom == g.dom \ + and f.rep == g.rep def __lt__(f, g): _, _, _, F, G = f.unify(g) @@ -983,11 +997,13 @@ def __bool__(f): return not dmp_zero_p(f.rep, f.lev) + def init_normal_DMF(num, den, lev, dom): return DMF(dmp_normal(num, lev, dom), dmp_normal(den, lev, dom), dom, lev) -class DMF(PicklableWithSlots): + +class DMF(PicklableWithSlots, CantSympify): """Dense Multivariate Fractions over `K`. """ __slots__ = ['num', 'den', 'lev', 'dom', 'ring'] @@ -1179,11 +1195,11 @@ return cls.new(1, dom, lev, ring=ring) def numer(f): - """Returns numerator of ``f``. """ + """Returns the numerator of ``f``. """ return f.half_per(f.num) def denom(f): - """Returns denominator of ``f``. """ + """Returns the denominator of ``f``. """ return f.half_per(f.den) def cancel(f): @@ -1244,7 +1260,7 @@ return f.per(dmp_pow(f.num, n, f.lev, f.dom), dmp_pow(f.den, n, f.lev, f.dom), cancel=False) else: - raise TypeError("`int` expected, got %s" % type(n)) + raise TypeError("``int`` expected, got %s" % type(n)) def quo(f, g): """Computes quotient of fractions ``f`` and ``g``. """ @@ -1282,7 +1298,7 @@ def is_one(f): """Returns ``True`` if ``f`` is a unit fraction. """ return dmp_one_p(f.num, f.lev, f.dom) and \ - dmp_one_p(f.den, f.lev, f.dom) + dmp_one_p(f.den, f.lev, f.dom) def __neg__(f): return f.neg() @@ -1426,11 +1442,13 @@ def __bool__(f): return not dmp_zero_p(f.num, f.lev) + def init_normal_ANP(rep, mod, dom): return ANP(dup_normal(rep, dom), dup_normal(mod, dom), dom) -class ANP(PicklableWithSlots): + +class ANP(PicklableWithSlots, CantSympify): """Dense Algebraic Number Polynomials over a field. """ __slots__ = ['rep', 'mod', 'dom'] @@ -1554,7 +1572,7 @@ return f.per(dup_rem(dup_pow(F, n, f.dom), f.mod, f.dom)) else: - raise TypeError("`int` expected, got %s" % type(n)) + raise TypeError("``int`` expected, got %s" % type(n)) def div(f, g): dom, per, F, G, mod = f.unify(g) @@ -1602,7 +1620,7 @@ else: try: return f.add(f.per(g)) - except TypeError: + except (CoercionFailed, TypeError): return NotImplemented def __radd__(f, g): @@ -1614,7 +1632,7 @@ else: try: return f.sub(f.per(g)) - except TypeError: + except (CoercionFailed, TypeError): return NotImplemented def __rsub__(f, g): @@ -1626,7 +1644,7 @@ else: try: return f.mul(f.per(g)) - except TypeError: + except (CoercionFailed, TypeError): return NotImplemented def __rmul__(f, g): @@ -1647,7 +1665,7 @@ else: try: return f.quo(f.per(g)) - except TypeError: + except (CoercionFailed, TypeError): return NotImplemented __truediv__ = __div__ diff -Nru python3-sympy-0.7.2/sympy/polys/polyconfig.py python3-sympy-0.7.3/sympy/polys/polyconfig.py --- python3-sympy-0.7.2/sympy/polys/polyconfig.py 2012-10-17 03:02:22.000000000 +0000 +++ python3-sympy-0.7.3/sympy/polys/polyconfig.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,36 +1,52 @@ """Configuration utilities for polynomial manipulation algorithms. """ +from contextlib import contextmanager + _default_config = { - 'USE_COLLINS_RESULTANT' : False, - 'USE_SIMPLIFY_GCD' : True, - 'USE_HEU_GCD' : True, - - 'USE_IRREDUCIBLE_IN_FACTOR' : False, - 'USE_CYCLOTOMIC_FACTOR' : True, - - 'EEZ_RESTART_IF_NEEDED' : True, - 'EEZ_NUMBER_OF_CONFIGS' : 3, - 'EEZ_NUMBER_OF_TRIES' : 5, - 'EEZ_MODULUS_STEP' : 2, + 'USE_COLLINS_RESULTANT': False, + 'USE_SIMPLIFY_GCD': True, + 'USE_HEU_GCD': True, + + 'USE_IRREDUCIBLE_IN_FACTOR': False, + 'USE_CYCLOTOMIC_FACTOR': True, + + 'EEZ_RESTART_IF_NEEDED': True, + 'EEZ_NUMBER_OF_CONFIGS': 3, + 'EEZ_NUMBER_OF_TRIES': 5, + 'EEZ_MODULUS_STEP': 2, - 'GF_IRRED_METHOD' : 'rabin', - 'GF_FACTOR_METHOD' : 'zassenhaus', + 'GF_IRRED_METHOD': 'rabin', + 'GF_FACTOR_METHOD': 'zassenhaus', - 'GB_METHOD' : 'buchberger', + 'GROEBNER': 'buchberger', } _current_config = {} +@contextmanager +def using(**kwargs): + for k, v in list(kwargs.items()): + setup(k, v) + + yield + + for k in list(kwargs.keys()): + setup(k) + def setup(key, value=None): """Assign a value to (or reset) a configuration item. """ + key = key.upper() + if value is not None: _current_config[key] = value else: _current_config[key] = _default_config[key] + def query(key): """Ask for a value of the given configuration item. """ - return _current_config.get(key, None) + return _current_config.get(key.upper(), None) + def configure(): """Initialized configuration of polys module. """ diff -Nru python3-sympy-0.7.2/sympy/polys/polycontext.py python3-sympy-0.7.3/sympy/polys/polycontext.py --- python3-sympy-0.7.2/sympy/polys/polycontext.py 2012-10-17 03:02:22.000000000 +0000 +++ python3-sympy-0.7.3/sympy/polys/polycontext.py 2013-07-13 17:53:32.000000000 +0000 @@ -16,6 +16,7 @@ for option in __known_options__: exec(__template__ % { 'option': option }) + class Context(PicklableWithSlots): __slots__ = ['__options__'] @@ -51,6 +52,7 @@ def __exit__(self, exc_type, exc_val, exc_tb): raise NotImplementedError('global context') + def register_context(func): def wrapper(self, *args, **kwargs): return func(*args, **dict_merge(self.__options__, kwargs)) diff -Nru python3-sympy-0.7.2/sympy/polys/polyerrors.py python3-sympy-0.7.3/sympy/polys/polyerrors.py --- python3-sympy-0.7.2/sympy/polys/polyerrors.py 2012-10-17 03:02:22.000000000 +0000 +++ python3-sympy-0.7.3/sympy/polys/polyerrors.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,17 +1,19 @@ """Definitions of common exceptions for `polys` module. """ + class BasePolynomialError(Exception): """Base class for polynomial related exceptions. """ def new(self, *args): raise NotImplementedError("abstract base class") + class ExactQuotientFailed(BasePolynomialError): def __init__(self, f, g, dom=None): self.f, self.g, self.dom = f, g, dom - def __str__(self): # pragma: no cover + def __str__(self): # pragma: no cover from sympy.printing.str import sstr if self.dom is None: @@ -22,57 +24,77 @@ def new(self, f, g): return self.__class__(f, g, self.dom) + class OperationNotSupported(BasePolynomialError): def __init__(self, poly, func): self.poly = poly self.func = func - def __str__(self): # pragma: no cover + def __str__(self): # pragma: no cover return "`%s` operation not supported by %s representation" % (self.func, self.poly.rep.__class__.__name__) + class HeuristicGCDFailed(BasePolynomialError): pass + class HomomorphismFailed(BasePolynomialError): pass + class IsomorphismFailed(BasePolynomialError): pass + class ExtraneousFactors(BasePolynomialError): pass + class EvaluationFailed(BasePolynomialError): pass + class RefinementFailed(BasePolynomialError): pass + class CoercionFailed(BasePolynomialError): pass + class NotInvertible(BasePolynomialError): pass + class NotReversible(BasePolynomialError): pass + class NotAlgebraic(BasePolynomialError): pass + class DomainError(BasePolynomialError): pass + class PolynomialError(BasePolynomialError): pass + class UnificationFailed(BasePolynomialError): pass -class GeneratorsNeeded(BasePolynomialError): + +class GeneratorsError(BasePolynomialError): + pass + + +class GeneratorsNeeded(GeneratorsError): pass + class ComputationFailed(BasePolynomialError): def __init__(self, func, nargs, exc): @@ -83,15 +105,15 @@ def __str__(self): return "%s(%s) failed without generators" % (self.func, ', '.join(map(str, self.exc.exprs[:self.nargs]))) -class GeneratorsError(BasePolynomialError): - pass class UnivariatePolynomialError(PolynomialError): pass + class MultivariatePolynomialError(PolynomialError): pass + class PolificationFailed(PolynomialError): def __init__(self, opt, origs, exprs, seq=False): @@ -107,14 +129,16 @@ self.opt = opt self.seq = seq - def __str__(self): # pragma: no cover + def __str__(self): # pragma: no cover if not self.seq: return "can't construct a polynomial from %s" % str(self.orig) else: return "can't construct polynomials from %s" % ', '.join(map(str, self.origs)) + class OptionError(BasePolynomialError): pass + class FlagError(OptionError): pass diff -Nru python3-sympy-0.7.2/sympy/polys/polyfuncs.py python3-sympy-0.7.3/sympy/polys/polyfuncs.py --- python3-sympy-0.7.2/sympy/polys/polyfuncs.py 2012-10-17 03:02:22.000000000 +0000 +++ python3-sympy-0.7.3/sympy/polys/polyfuncs.py 2013-07-13 17:53:32.000000000 +0000 @@ -15,10 +15,20 @@ from sympy.core import S, Basic, Add, Mul + def symmetrize(F, *gens, **args): """ Rewrite a polynomial in terms of elementary symmetric polynomials. + A symmetric polynomial is a multivariate polynomial that remains invariant + under any variable permutation, i.e., if ``f = f(x_1, x_2, ..., x_n)``, + then ``f = f(x_{i_1}, x_{i_2}, ..., x_{i_n})``, where + ``(i_1, i_2, ..., i_n)`` is a permutation of ``(1, 2, ..., n)`` (an + element of the group ``S_n``). + + Returns a tuple of symmetric polynomials ``(f1, f2, ..., fn)`` such that + ``f = f1 + f2 + ... + fn``. + Examples ======== @@ -72,7 +82,7 @@ gens, dom = opt.gens, opt.domain for i in range(0, len(gens)): - poly = symmetric_poly(i+1, gens, polys=True) + poly = symmetric_poly(i + 1, gens, polys=True) polys.append((next(symbols), poly.set_domain(dom))) indices = list(range(0, len(gens) - 1)) @@ -91,7 +101,7 @@ _height, _monom, _coeff = -1, None, None for i, (monom, coeff) in enumerate(f.terms()): - if all(monom[i] >= monom[i+1] for i in indices): + if all(monom[i] >= monom[i + 1] for i in indices): height = max([ n*m for n, m in zip(weights, monom) ]) if height > _height: @@ -137,10 +147,14 @@ else: return result + (polys,) + def horner(f, *gens, **args): """ Rewrite a polynomial in Horner form. + Among other applications, evaluation of a polynomial at a point is optimal + when it is applied using the Horner scheme ([1]). + Examples ======== @@ -161,6 +175,10 @@ >>> horner(f, wrt=y) y*(x*y*(4*x + 2) + x*(2*x + 1)) + References + ========== + [1] - http://en.wikipedia.org/wiki/Horner_scheme + """ allowed_flags(args, []) @@ -182,6 +200,7 @@ return form + def interpolate(data, x): """ Construct an interpolating polynomial for the data points. @@ -192,13 +211,23 @@ >>> from sympy.polys.polyfuncs import interpolate >>> from sympy.abc import x + A list is interpreted as though it were paired with a range starting + from 1: + >>> interpolate([1, 4, 9, 16], x) x**2 + + This can be made explicit by giving a list of coordinates: + >>> interpolate([(1, 1), (2, 4), (3, 9)], x) x**2 - >>> interpolate([(1, 2), (2, 5), (3, 10)], x) + + The (x, y) coordinates can also be given as keys and values of a + dictionary (and the points need not be equispaced): + + >>> interpolate([(-1, 2), (1, 2), (2, 5)], x) x**2 + 1 - >>> interpolate({1: 2, 2: 5, 3: 10}, x) + >>> interpolate({-1: 2, 1: 2, 2: 5}, x) x**2 + 1 """ @@ -210,13 +239,14 @@ if isinstance(data[0], tuple): X, Y = list(zip(*data)) else: - X = list(range(1, n+1)) + X = list(range(1, n + 1)) Y = list(data) poly = interpolating_poly(n, x, X, Y) return poly.expand() + def viete(f, roots=None, *gens, **args): """ Generate Viete's formulas for ``f``. @@ -244,12 +274,14 @@ raise ComputationFailed('viete', 1, exc) if f.is_multivariate: - raise MultivariatePolynomialError("multivariate polynomials are not allowed") + raise MultivariatePolynomialError( + "multivariate polynomials are not allowed") n = f.degree() if n < 1: - raise ValueError("can't derive Viete's formulas for a constant polynomial") + raise ValueError( + "can't derive Viete's formulas for a constant polynomial") if roots is None: roots = numbered_symbols('r', start=1) @@ -263,7 +295,7 @@ result, sign = [], -1 for i, coeff in enumerate(coeffs[1:]): - poly = symmetric_poly(i+1, roots) + poly = symmetric_poly(i + 1, roots) coeff = sign*(coeff/lc) result.append((poly, coeff)) sign = -sign diff -Nru python3-sympy-0.7.2/sympy/polys/polyoptions.py python3-sympy-0.7.3/sympy/polys/polyoptions.py --- python3-sympy-0.7.2/sympy/polys/polyoptions.py 2012-10-17 03:02:22.000000000 +0000 +++ python3-sympy-0.7.3/sympy/polys/polyoptions.py 2013-07-13 17:53:32.000000000 +0000 @@ -14,6 +14,7 @@ import re + class Option(object): """Base class for all kinds of options. """ @@ -39,11 +40,13 @@ def postprocess(cls, options): pass + class Flag(Option): """Base class for all kinds of flags. """ is_Flag = True + class BooleanOption(Option): """An option that must have a boolean value or equivalent assigned. """ @@ -54,6 +57,7 @@ else: raise OptionError("'%s' must have a boolean value assigned, got %s" % (cls.option, value)) + class OptionType(type): """Base type for all options that does registers options. """ @@ -68,6 +72,7 @@ setattr(Options, cls.option, getter) Options.__options__[cls.option] = cls + class Options(dict): """ Options manager for polynomial manipulation module. @@ -122,7 +127,8 @@ dict.__init__(self) if gens and args.get('gens', ()): - raise OptionError("both '*gens' and keyword argument 'gens' supplied") + raise OptionError( + "both '*gens' and keyword argument 'gens' supplied") elif gens: args = dict(args) args['gens'] = gens @@ -191,7 +197,8 @@ try: cls.__order__ = topological_sort((vertices, list(edges))) except ValueError: - raise RuntimeError("cycle detected in sympy.polys options framework") + raise RuntimeError( + "cycle detected in sympy.polys options framework") def clone(self, updates={}): """Clone ``self`` and update specified options. """ @@ -244,6 +251,7 @@ return flags + class Expand(BooleanOption, metaclass=OptionType): """``expand`` option to polynomial manipulation functions. """ @@ -256,6 +264,7 @@ def default(cls): return True + class Gens(Option, metaclass=OptionType): """``gens`` option to polynomial manipulation functions. """ @@ -284,6 +293,7 @@ return tuple(gens) + class Wrt(Option, metaclass=OptionType): """``wrt`` option to polynomial manipulation functions. """ @@ -310,6 +320,7 @@ else: raise OptionError("invalid argument for 'wrt' option") + class Sort(Option, metaclass=OptionType): """``sort`` option to polynomial manipulation functions. """ @@ -331,6 +342,7 @@ else: raise OptionError("invalid argument for 'sort' option") + class Order(Option, metaclass=OptionType): """``order`` option to polynomial manipulation functions. """ @@ -347,6 +359,7 @@ def preprocess(cls, order): return sympy.polys.monomialtools.monomial_key(order) + class Field(BooleanOption, metaclass=OptionType): """``field`` option to polynomial manipulation functions. """ @@ -355,13 +368,16 @@ requires = [] excludes = ['domain', 'split', 'gaussian'] + class Greedy(BooleanOption, metaclass=OptionType): """``greedy`` option to polynomial manipulation functions. """ option = 'greedy' requires = [] - excludes = ['domain', 'split', 'gaussian', 'extension', 'modulus', 'symmetric'] + excludes = ['domain', 'split', 'gaussian', 'extension', 'modulus', + 'symmetric'] + class Composite(BooleanOption, metaclass=OptionType): """ """ @@ -373,7 +389,9 @@ return True requires = [] - excludes = ['domain', 'split', 'gaussian', 'extension', 'modulus', 'symmetric'] + excludes = ['domain', 'split', 'gaussian', 'extension', 'modulus', + 'symmetric'] + class Domain(Option, metaclass=OptionType): """``domain`` option to polynomial manipulation functions. """ @@ -383,10 +401,12 @@ requires = [] excludes = ['field', 'greedy', 'split', 'gaussian', 'extension'] + after = ['gens'] + _re_finitefield = re.compile("^(FF|GF)\((\d+)\)$") - _re_polynomial = re.compile("^(Z|ZZ|Q|QQ)\[(.+)\]$") - _re_fraction = re.compile("^(Z|ZZ|Q|QQ)\((.+)\)$") - _re_algebraic = re.compile("^(Q|QQ)\<(.+)\>$") + _re_polynomial = re.compile("^(Z|ZZ|Q|QQ)\[(.+)\]$") + _re_fraction = re.compile("^(Z|ZZ|Q|QQ)\((.+)\)$") + _re_algebraic = re.compile("^(Q|QQ)\<(.+)\>$") @classmethod def preprocess(cls, domain): @@ -440,13 +460,19 @@ gens = list(map(sympify, r.groups()[1].split(','))) return sympy.polys.domains.QQ.algebraic_field(*gens) - raise OptionError('expected a valid domain specification, got %s' % domain) + raise OptionError( + 'expected a valid domain specification, got %s' % domain) @classmethod def postprocess(cls, options): if 'gens' in options and 'domain' in options and options['domain'].is_Composite and \ (set(options['domain'].gens) & set(options['gens'])): - raise GeneratorsError("ground domain and generators interferes together") + raise GeneratorsError( + "ground domain and generators interfere together") + elif ('gens' not in options or not options['gens']) and \ + 'domain' in options and options['domain'] == sympy.polys.domains.EX: + raise GeneratorsError("you have to provide generators because EX domain was requested") + class Split(BooleanOption, metaclass=OptionType): """``split`` option to polynomial manipulation functions. """ @@ -454,20 +480,23 @@ option = 'split' requires = [] - excludes = ['field', 'greedy', 'domain', 'gaussian', 'extension', 'modulus', 'symmetric'] + excludes = ['field', 'greedy', 'domain', 'gaussian', 'extension', + 'modulus', 'symmetric'] @classmethod def postprocess(cls, options): if 'split' in options: raise NotImplementedError("'split' option is not implemented yet") + class Gaussian(BooleanOption, metaclass=OptionType): """``gaussian`` option to polynomial manipulation functions. """ option = 'gaussian' requires = [] - excludes = ['field', 'greedy', 'domain', 'split', 'extension', 'modulus', 'symmetric'] + excludes = ['field', 'greedy', 'domain', 'split', 'extension', + 'modulus', 'symmetric'] @classmethod def postprocess(cls, options): @@ -475,13 +504,15 @@ options['extension'] = set([S.ImaginaryUnit]) Extension.postprocess(options) + class Extension(Option, metaclass=OptionType): """``extension`` option to polynomial manipulation functions. """ option = 'extension' requires = [] - excludes = ['greedy', 'domain', 'split', 'gaussian', 'modulus', 'symmetric'] + excludes = ['greedy', 'domain', 'split', 'gaussian', 'modulus', + 'symmetric'] @classmethod def preprocess(cls, extension): @@ -503,7 +534,9 @@ @classmethod def postprocess(cls, options): if 'extension' in options and options['extension'] is not True: - options['domain'] = sympy.polys.domains.QQ.algebraic_field(*options['extension']) + options['domain'] = sympy.polys.domains.QQ.algebraic_field( + *options['extension']) + class Modulus(Option, metaclass=OptionType): """``modulus`` option to polynomial manipulation functions. """ @@ -520,7 +553,8 @@ if modulus.is_Integer and modulus > 0: return int(modulus) else: - raise OptionError("'modulus' must a positive integer, got %s" % modulus) + raise OptionError( + "'modulus' must a positive integer, got %s" % modulus) @classmethod def postprocess(cls, options): @@ -529,6 +563,7 @@ symmetric = options.get('symmetric', True) options['domain'] = sympy.polys.domains.FF(modulus, symmetric) + class Symmetric(BooleanOption, metaclass=OptionType): """``symmetric`` option to polynomial manipulation functions. """ @@ -537,6 +572,7 @@ requires = ['modulus'] excludes = ['greedy', 'domain', 'split', 'gaussian', 'extension'] + class Strict(BooleanOption, metaclass=OptionType): """``strict`` option to polynomial manipulation functions. """ @@ -546,6 +582,7 @@ def default(cls): return True + class Auto(BooleanOption, Flag, metaclass=OptionType): """``auto`` flag to polynomial manipulation functions. """ @@ -562,6 +599,7 @@ if ('domain' in options or 'field' in options) and 'auto' not in options: options['auto'] = False + class Frac(BooleanOption, Flag, metaclass=OptionType): """``auto`` option to polynomial manipulation functions. """ @@ -571,6 +609,7 @@ def default(cls): return False + class Formal(BooleanOption, Flag, metaclass=OptionType): """``formal`` flag to polynomial manipulation functions. """ @@ -580,11 +619,13 @@ def default(cls): return False + class Polys(BooleanOption, Flag, metaclass=OptionType): """``polys`` flag to polynomial manipulation functions. """ option = 'polys' + class Include(BooleanOption, Flag, metaclass=OptionType): """``include`` flag to polynomial manipulation functions. """ @@ -594,6 +635,7 @@ def default(cls): return False + class All(BooleanOption, Flag, metaclass=OptionType): """``all`` flag to polynomial manipulation functions. """ @@ -603,6 +645,7 @@ def default(cls): return False + class Gen(Flag, metaclass=OptionType): """``gen`` flag to polynomial manipulation functions. """ @@ -619,6 +662,7 @@ else: raise OptionError("invalid argument for 'gen' option") + class Symbols(Flag, metaclass=OptionType): """``symbols`` flag to polynomial manipulation functions. """ @@ -635,6 +679,7 @@ else: raise OptionError("expected an iterator or iterable container, got %s" % symbols) + class Method(Flag, metaclass=OptionType): """``method`` flag to polynomial manipulation functions. """ @@ -647,6 +692,7 @@ else: raise OptionError("expected a string, got %s" % method) + def build_options(gens, args=None): """Construct options from keyword arguments or ... options. """ if args is None: @@ -657,6 +703,7 @@ else: return args['opt'] + def allowed_flags(args, flags): """ Allow specified flags to be used in the given context. @@ -682,10 +729,12 @@ for arg in args.keys(): try: if Options.__options__[arg].is_Flag and not arg in flags: - raise FlagError("'%s' flag is not allowed in this context" % arg) + raise FlagError( + "'%s' flag is not allowed in this context" % arg) except KeyError: raise OptionError("'%s' is not a valid option" % arg) + def set_defaults(options, **defaults): """Update options with default values. """ if 'defaults' not in options: diff -Nru python3-sympy-0.7.2/sympy/polys/polyquinticconst.py python3-sympy-0.7.3/sympy/polys/polyquinticconst.py --- python3-sympy-0.7.2/sympy/polys/polyquinticconst.py 1970-01-01 00:00:00.000000000 +0000 +++ python3-sympy-0.7.3/sympy/polys/polyquinticconst.py 2013-07-13 17:53:32.000000000 +0000 @@ -0,0 +1,184 @@ +""" +Solving solvable quintics - An implementation of DS Dummit's paper + +Paper : +http://www.ams.org/journals/mcom/1991-57-195/S0025-5718-1991-1079014-X/S0025-5718-1991-1079014-X.pdf + +Mathematica notebook: +http://www.emba.uvm.edu/~ddummit/quintics/quintics.nb + +""" + +from sympy.core import S, Symbol +from sympy.core.numbers import I +from sympy.polys.polytools import Poly +from sympy.core.evalf import N +from sympy.functions import sqrt + +x = Symbol('x') + +class PolyQuintic(object): + """Special functions for solvable quintics""" + def __init__(self, poly): + _, _, self.p, self.q, self.r, self.s = poly.all_coeffs() + self.zeta1 = S(-1)/4 + (sqrt(5)/4) + I*sqrt((sqrt(5)/8) + S(5)/8) + self.zeta2 = (-sqrt(5)/4) - S(1)/4 + I*sqrt((-sqrt(5)/8) + S(5)/8) + self.zeta3 = (-sqrt(5)/4) - S(1)/4 - I*sqrt((-sqrt(5)/8) + S(5)/8) + self.zeta4 = S(-1)/4 + (sqrt(5)/4) - I*sqrt((sqrt(5)/8) + S(5)/8) + + @property + def f20(self): + p, q, r, s = self.p, self.q, self.r, self.s + f20 = q**8 - 13*p*q**6*r + p**5*q**2*r**2 + 65*p**2*q**4*r**2 - 4*p**6*r**3 - 128*p**3*q**2*r**3 + 17*q**4*r**3 + 48*p**4*r**4 - 16*p*q**2*r**4 - 192*p**2*r**5 + 256*r**6 - 4*p**5*q**3*s - 12*p**2*q**5*s + 18*p**6*q*r*s + 12*p**3*q**3*r*s - 124*q**5*r*s + 196*p**4*q*r**2*s + 590*p*q**3*r**2*s - 160*p**2*q*r**3*s - 1600*q*r**4*s - 27*p**7*s**2 - 150*p**4*q**2*s**2 - 125*p*q**4*s**2 - 99*p**5*r*s**2 - 725*p**2*q**2*r*s**2 + 1200*p**3*r**2*s**2 + 3250*q**2*r**2*s**2 - 2000*p*r**3*s**2 - 1250*p*q*r*s**3 + 3125*p**2*s**4 - 9375*r*s**4-(2*p*q**6 - 19*p**2*q**4*r + 51*p**3*q**2*r**2 - 3*q**4*r**2 - 32*p**4*r**3 - 76*p*q**2*r**3 + 256*p**2*r**4 - 512*r**5 + 31*p**3*q**3*s + 58*q**5*s - 117*p**4*q*r*s - 105*p*q**3*r*s - 260*p**2*q*r**2*s + 2400*q*r**3*s + 108*p**5*s**2 + 325*p**2*q**2*s**2 - 525*p**3*r*s**2 - 2750*q**2*r*s**2 + 500*p*r**2*s**2 - 625*p*q*s**3 + 3125*s**4)*x+(p**2*q**4 - 6*p**3*q**2*r - 8*q**4*r + 9*p**4*r**2 + 76*p*q**2*r**2 - 136*p**2*r**3 + 400*r**4 - 50*p*q**3*s + 90*p**2*q*r*s - 1400*q*r**2*s + 625*q**2*s**2 + 500*p*r*s**2)*x**2-(2*q**4 - 21*p*q**2*r + 40*p**2*r**2 - 160*r**3 + 15*p**2*q*s + 400*q*r*s - 125*p*s**2)*x**3+(2*p*q**2 - 6*p**2*r + 40*r**2 - 50*q*s)*x**4 + 8*r*x**5 + x**6 + return Poly(f20, x) + + @property + def b(self): + p, q, r, s = self.p, self.q, self.r, self.s + b = ( [], [0,0,0,0,0,0], [0,0,0,0,0,0], [0,0,0,0,0,0], [0,0,0,0,0,0],) + + b[1][5] = 100*p**7*q**7 + 2175*p**4*q**9 + 10500*p*q**11 - 1100*p**8*q**5*r - 27975*p**5*q**7*r - 152950*p**2*q**9*r + 4125*p**9*q**3*r**2 + 128875*p**6*q**5*r**2 + 830525*p**3*q**7*r**2 - 59450*q**9*r**2 - 5400*p**10*q*r**3 - 243800*p**7*q**3*r**3 - 2082650*p**4*q**5*r**3 + 333925*p*q**7*r**3 + 139200*p**8*q*r**4 + 2406000*p**5*q**3*r**4 + 122600*p**2*q**5*r**4 - 1254400*p**6*q*r**5 - 3776000*p**3*q**3*r**5 - 1832000*q**5*r**5 + 4736000*p**4*q*r**6 + 6720000*p*q**3*r**6 - 6400000*p**2*q*r**7 + 900*p**9*q**4*s + 37400*p**6*q**6*s + 281625*p**3*q**8*s + 435000*q**10*s - 6750*p**10*q**2*r*s - 322300*p**7*q**4*r*s - 2718575*p**4*q**6*r*s - 4214250*p*q**8*r*s + 16200*p**11*r**2*s + 859275*p**8*q**2*r**2*s + 8925475*p**5*q**4*r**2*s + 14427875*p**2*q**6*r**2*s - 453600*p**9*r**3*s - 10038400*p**6*q**2*r**3*s - 17397500*p**3*q**4*r**3*s + 11333125*q**6*r**3*s + 4451200*p**7*r**4*s + 15850000*p**4*q**2*r**4*s - 34000000*p*q**4*r**4*s - 17984000*p**5*r**5*s + 10000000*p**2*q**2*r**5*s + 25600000*p**3*r**6*s + 8000000*q**2*r**6*s - 6075*p**11*q*s**2 + 83250*p**8*q**3*s**2 + 1282500*p**5*q**5*s**2 + 2862500*p**2*q**7*s**2 - 724275*p**9*q*r*s**2 - 9807250*p**6*q**3*r*s**2 - 28374375*p**3*q**5*r*s**2 - 22212500*q**7*r*s**2 + 8982000*p**7*q*r**2*s**2 + 39600000*p**4*q**3*r**2*s**2 + 61746875*p*q**5*r**2*s**2 + 1010000*p**5*q*r**3*s**2 + 1000000*p**2*q**3*r**3*s**2 - 78000000*p**3*q*r**4*s**2 - 30000000*q**3*r**4*s**2 - 80000000*p*q*r**5*s**2 + 759375*p**10*s**3 + 9787500*p**7*q**2*s**3 + 39062500*p**4*q**4*s**3 + 52343750*p*q**6*s**3 - 12301875*p**8*r*s**3 - 98175000*p**5*q**2*r*s**3 - 225078125*p**2*q**4*r*s**3 + 54900000*p**6*r**2*s**3 + 310000000*p**3*q**2*r**2*s**3 + 7890625*q**4*r**2*s**3 - 51250000*p**4*r**3*s**3 + 420000000*p*q**2*r**3*s**3 - 110000000*p**2*r**4*s**3 + 200000000*r**5*s**3 - 2109375*p**6*q*s**4 + 21093750*p**3*q**3*s**4 + 89843750*q**5*s**4 - 182343750*p**4*q*r*s**4 - 733203125*p*q**3*r*s**4 + 196875000*p**2*q*r**2*s**4 - 1125000000*q*r**3*s**4 + 158203125*p**5*s**5 + 566406250*p**2*q**2*s**5 - 101562500*p**3*r*s**5 + 1669921875*q**2*r*s**5 - 1250000000*p*r**2*s**5 + 1220703125*p*q*s**6 - 6103515625*s**7 + + b[1][4] = -1000*p**5*q**7 - 7250*p**2*q**9 + 10800*p**6*q**5*r + 96900*p**3*q**7*r + 52500*q**9*r - 37400*p**7*q**3*r**2 - 470850*p**4*q**5*r**2 - 640600*p*q**7*r**2 + 39600*p**8*q*r**3 + 983600*p**5*q**3*r**3 + 2848100*p**2*q**5*r**3 - 814400*p**6*q*r**4 - 6076000*p**3*q**3*r**4 - 2308000*q**5*r**4 + 5024000*p**4*q*r**5 + 9680000*p*q**3*r**5 - 9600000*p**2*q*r**6 - 13800*p**7*q**4*s - 94650*p**4*q**6*s + 26500*p*q**8*s + 86400*p**8*q**2*r*s + 816500*p**5*q**4*r*s + 257500*p**2*q**6*r*s - 91800*p**9*r**2*s - 1853700*p**6*q**2*r**2*s - 630000*p**3*q**4*r**2*s + 8971250*q**6*r**2*s + 2071200*p**7*r**3*s + 7240000*p**4*q**2*r**3*s - 29375000*p*q**4*r**3*s - 14416000*p**5*r**4*s + 5200000*p**2*q**2*r**4*s + 30400000*p**3*r**5*s + 12000000*q**2*r**5*s - 64800*p**9*q*s**2 - 567000*p**6*q**3*s**2 - 1655000*p**3*q**5*s**2 - 6987500*q**7*s**2 - 337500*p**7*q*r*s**2 - 8462500*p**4*q**3*r*s**2 + 5812500*p*q**5*r*s**2 + 24930000*p**5*q*r**2*s**2 + 69125000*p**2*q**3*r**2*s**2 - 103500000*p**3*q*r**3*s**2 - 30000000*q**3*r**3*s**2 - 90000000*p*q*r**4*s**2 + 708750*p**8*s**3 + 5400000*p**5*q**2*s**3 - 8906250*p**2*q**4*s**3 - 18562500*p**6*r*s**3 + 625000*p**3*q**2*r*s**3 - 29687500*q**4*r*s**3 + 75000000*p**4*r**2*s**3 + 416250000*p*q**2*r**2*s**3 - 60000000*p**2*r**3*s**3 + 300000000*r**4*s**3 - 71718750*p**4*q*s**4 - 189062500*p*q**3*s**4 - 210937500*p**2*q*r*s**4 - 1187500000*q*r**2*s**4 + 187500000*p**3*s**5 + 800781250*q**2*s**5 + 390625000*p*r*s**5 + + b[1][3] = 500*p**6*q**5 + 6350*p**3*q**7 + 19800*q**9 - 3750*p**7*q**3*r - 65100*p**4*q**5*r - 264950*p*q**7*r + 6750*p**8*q*r**2 + 209050*p**5*q**3*r**2 + 1217250*p**2*q**5*r**2 - 219000*p**6*q*r**3 - 2510000*p**3*q**3*r**3 - 1098500*q**5*r**3 + 2068000*p**4*q*r**4 + 5060000*p*q**3*r**4 - 5200000*p**2*q*r**5 + 6750*p**8*q**2*s + 96350*p**5*q**4*s + 346000*p**2*q**6*s - 20250*p**9*r*s - 459900*p**6*q**2*r*s - 1828750*p**3*q**4*r*s + 2930000*q**6*r*s + 594000*p**7*r**2*s + 4301250*p**4*q**2*r**2*s - 10906250*p*q**4*r**2*s - 5252000*p**5*r**3*s + 1450000*p**2*q**2*r**3*s + 12800000*p**3*r**4*s + 6500000*q**2*r**4*s - 74250*p**7*q*s**2 - 1418750*p**4*q**3*s**2 - 5956250*p*q**5*s**2 + 4297500*p**5*q*r*s**2 + 29906250*p**2*q**3*r*s**2 - 31500000*p**3*q*r**2*s**2 - 12500000*q**3*r**2*s**2 - 35000000*p*q*r**3*s**2 - 1350000*p**6*s**3 - 6093750*p**3*q**2*s**3 - 17500000*q**4*s**3 + 7031250*p**4*r*s**3 + 127812500*p*q**2*r*s**3 - 18750000*p**2*r**2*s**3 + 162500000*r**3*s**3 - 107812500*p**2*q*s**4 - 460937500*q*r*s**4 + 214843750*p*s**5 + + b[1][2] = -1950*p**4*q**5 - 14100*p*q**7 + 14350*p**5*q**3*r + 125600*p**2*q**5*r - 27900*p**6*q*r**2 - 402250*p**3*q**3*r**2 - 288250*q**5*r**2 + 436000*p**4*q*r**3 + 1345000*p*q**3*r**3 - 1400000*p**2*q*r**4 - 9450*p**6*q**2*s + 1250*p**3*q**4*s + 465000*q**6*s + 49950*p**7*r*s + 302500*p**4*q**2*r*s - 1718750*p*q**4*r*s - 834000*p**5*r**2*s - 437500*p**2*q**2*r**2*s + 3100000*p**3*r**3*s + 1750000*q**2*r**3*s + 292500*p**5*q*s**2 + 1937500*p**2*q**3*s**2 - 3343750*p**3*q*r*s**2 - 1875000*q**3*r*s**2 - 8125000*p*q*r**2*s**2 + 1406250*p**4*s**3 + 12343750*p*q**2*s**3 - 5312500*p**2*r*s**3 + 43750000*r**2*s**3 - 74218750*q*s**4 + + b[1][1] = 300*p**5*q**3 + 2150*p**2*q**5 - 1350*p**6*q*r - 21500*p**3*q**3*r - 61500*q**5*r + 42000*p**4*q*r**2 + 290000*p*q**3*r**2 - 300000*p**2*q*r**3 + 4050*p**7*s + 45000*p**4*q**2*s + 125000*p*q**4*s - 108000*p**5*r*s - 643750*p**2*q**2*r*s + 700000*p**3*r**2*s + 375000*q**2*r**2*s + 93750*p**3*q*s**2 + 312500*q**3*s**2 - 1875000*p*q*r*s**2 + 1406250*p**2*s**3 + 9375000*r*s**3 + + b[1][0] = -1250*p**3*q**3 - 9000*q**5 + 4500*p**4*q*r + 46250*p*q**3*r - 50000*p**2*q*r**2 - 6750*p**5*s - 43750*p**2*q**2*s + 75000*p**3*r*s + 62500*q**2*r*s - 156250*p*q*s**2 + 1562500*s**3 + + b[2][5] = 200*p**6*q**11 - 250*p**3*q**13 - 10800*q**15 - 3900*p**7*q**9*r - 3325*p**4*q**11*r + 181800*p*q**13*r + 26950*p**8*q**7*r**2 + 69625*p**5*q**9*r**2 - 1214450*p**2*q**11*r**2 - 78725*p**9*q**5*r**3 - 368675*p**6*q**7*r**3 + 4166325*p**3*q**9*r**3 + 1131100*q**11*r**3 + 73400*p**10*q**3*r**4 + 661950*p**7*q**5*r**4 - 9151950*p**4*q**7*r**4 - 16633075*p*q**9*r**4 + 36000*p**11*q*r**5 + 135600*p**8*q**3*r**5 + 17321400*p**5*q**5*r**5 + 85338300*p**2*q**7*r**5 - 832000*p**9*q*r**6 - 21379200*p**6*q**3*r**6 - 176044000*p**3*q**5*r**6 - 1410000*q**7*r**6 + 6528000*p**7*q*r**7 + 129664000*p**4*q**3*r**7 + 47344000*p*q**5*r**7 - 21504000*p**5*q*r**8 - 115200000*p**2*q**3*r**8 + 25600000*p**3*q*r**9 + 64000000*q**3*r**9 + 15700*p**8*q**8*s + 120525*p**5*q**10*s + 113250*p**2*q**12*s - 196900*p**9*q**6*r*s - 1776925*p**6*q**8*r*s - 3062475*p**3*q**10*r*s - 4153500*q**12*r*s + 857925*p**10*q**4*r**2*s + 10562775*p**7*q**6*r**2*s + 34866250*p**4*q**8*r**2*s + 73486750*p*q**10*r**2*s - 1333800*p**11*q**2*r**3*s - 29212625*p**8*q**4*r**3*s - 168729675*p**5*q**6*r**3*s - 427230750*p**2*q**8*r**3*s + 108000*p**12*r**4*s + 30384200*p**9*q**2*r**4*s + 324535100*p**6*q**4*r**4*s + 952666750*p**3*q**6*r**4*s - 38076875*q**8*r**4*s - 4296000*p**10*r**5*s - 213606400*p**7*q**2*r**5*s - 842060000*p**4*q**4*r**5*s - 95285000*p*q**6*r**5*s + 61184000*p**8*r**6*s + 567520000*p**5*q**2*r**6*s + 547000000*p**2*q**4*r**6*s - 390912000*p**6*r**7*s - 812800000*p**3*q**2*r**7*s - 924000000*q**4*r**7*s + 1152000000*p**4*r**8*s + 800000000*p*q**2*r**8*s - 1280000000*p**2*r**9*s + 141750*p**10*q**5*s**2 - 31500*p**7*q**7*s**2 - 11325000*p**4*q**9*s**2 - 31687500*p*q**11*s**2 - 1293975*p**11*q**3*r*s**2 - 4803800*p**8*q**5*r*s**2 + 71398250*p**5*q**7*r*s**2 + 227625000*p**2*q**9*r*s**2 + 3256200*p**12*q*r**2*s**2 + 43870125*p**9*q**3*r**2*s**2 + 64581500*p**6*q**5*r**2*s**2 + 56090625*p**3*q**7*r**2*s**2 + 260218750*q**9*r**2*s**2 - 74610000*p**10*q*r**3*s**2 - 662186500*p**7*q**3*r**3*s**2 - 1987747500*p**4*q**5*r**3*s**2 - 811928125*p*q**7*r**3*s**2 + 471286000*p**8*q*r**4*s**2 + 2106040000*p**5*q**3*r**4*s**2 + 792687500*p**2*q**5*r**4*s**2 - 135120000*p**6*q*r**5*s**2 + 2479000000*p**3*q**3*r**5*s**2 + 5242250000*q**5*r**5*s**2 - 6400000000*p**4*q*r**6*s**2 - 8620000000*p*q**3*r**6*s**2 + 13280000000*p**2*q*r**7*s**2 + 1600000000*q*r**8*s**2 + 273375*p**12*q**2*s**3 - 13612500*p**9*q**4*s**3 - 177250000*p**6*q**6*s**3 - 511015625*p**3*q**8*s**3 - 320937500*q**10*s**3 - 2770200*p**13*r*s**3 + 12595500*p**10*q**2*r*s**3 + 543950000*p**7*q**4*r*s**3 + 1612281250*p**4*q**6*r*s**3 + 968125000*p*q**8*r*s**3 + 77031000*p**11*r**2*s**3 + 373218750*p**8*q**2*r**2*s**3 + 1839765625*p**5*q**4*r**2*s**3 + 1818515625*p**2*q**6*r**2*s**3 - 776745000*p**9*r**3*s**3 - 6861075000*p**6*q**2*r**3*s**3 - 20014531250*p**3*q**4*r**3*s**3 - 13747812500*q**6*r**3*s**3 + 3768000000*p**7*r**4*s**3 + 35365000000*p**4*q**2*r**4*s**3 + 34441875000*p*q**4*r**4*s**3 - 9628000000*p**5*r**5*s**3 - 63230000000*p**2*q**2*r**5*s**3 + 13600000000*p**3*r**6*s**3 - 15000000000*q**2*r**6*s**3 - 10400000000*p*r**7*s**3 - 45562500*p**11*q*s**4 - 525937500*p**8*q**3*s**4 - 1364218750*p**5*q**5*s**4 - 1382812500*p**2*q**7*s**4 + 572062500*p**9*q*r*s**4 + 2473515625*p**6*q**3*r*s**4 + 13192187500*p**3*q**5*r*s**4 + 12703125000*q**7*r*s**4 - 451406250*p**7*q*r**2*s**4 - 18153906250*p**4*q**3*r**2*s**4 - 36908203125*p*q**5*r**2*s**4 - 9069375000*p**5*q*r**3*s**4 + 79957812500*p**2*q**3*r**3*s**4 + 5512500000*p**3*q*r**4*s**4 + 50656250000*q**3*r**4*s**4 + 74750000000*p*q*r**5*s**4 + 56953125*p**10*s**5 + 1381640625*p**7*q**2*s**5 - 781250000*p**4*q**4*s**5 + 878906250*p*q**6*s**5 - 2655703125*p**8*r*s**5 - 3223046875*p**5*q**2*r*s**5 - 35117187500*p**2*q**4*r*s**5 + 26573437500*p**6*r**2*s**5 + 14785156250*p**3*q**2*r**2*s**5 - 52050781250*q**4*r**2*s**5 - 103062500000*p**4*r**3*s**5 - 281796875000*p*q**2*r**3*s**5 + 146875000000*p**2*r**4*s**5 - 37500000000*r**5*s**5 - 8789062500*p**6*q*s**6 - 3906250000*p**3*q**3*s**6 + 1464843750*q**5*s**6 + 102929687500*p**4*q*r*s**6 + 297119140625*p*q**3*r*s**6 - 217773437500*p**2*q*r**2*s**6 + 167968750000*q*r**3*s**6 + 10986328125*p**5*s**7 + 98876953125*p**2*q**2*s**7 - 188964843750*p**3*r*s**7 - 278320312500*q**2*r*s**7 + 517578125000*p*r**2*s**7 - 610351562500*p*q*s**8 + 762939453125*s**9 + + b[2][4] = -200*p**7*q**9 + 1850*p**4*q**11 + 21600*p*q**13 + 3200*p**8*q**7*r - 19200*p**5*q**9*r - 316350*p**2*q**11*r - 19050*p**9*q**5*r**2 + 37400*p**6*q**7*r**2 + 1759250*p**3*q**9*r**2 + 440100*q**11*r**2 + 48750*p**10*q**3*r**3 + 190200*p**7*q**5*r**3 - 4604200*p**4*q**7*r**3 - 6072800*p*q**9*r**3 - 43200*p**11*q*r**4 - 834500*p**8*q**3*r**4 + 4916000*p**5*q**5*r**4 + 27926850*p**2*q**7*r**4 + 969600*p**9*q*r**5 + 2467200*p**6*q**3*r**5 - 45393200*p**3*q**5*r**5 - 5399500*q**7*r**5 - 7283200*p**7*q*r**6 + 10536000*p**4*q**3*r**6 + 41656000*p*q**5*r**6 + 22784000*p**5*q*r**7 - 35200000*p**2*q**3*r**7 - 25600000*p**3*q*r**8 + 96000000*q**3*r**8 - 3000*p**9*q**6*s + 40400*p**6*q**8*s + 136550*p**3*q**10*s - 1647000*q**12*s + 40500*p**10*q**4*r*s - 173600*p**7*q**6*r*s - 126500*p**4*q**8*r*s + 23969250*p*q**10*r*s - 153900*p**11*q**2*r**2*s - 486150*p**8*q**4*r**2*s - 4115800*p**5*q**6*r**2*s - 112653250*p**2*q**8*r**2*s + 129600*p**12*r**3*s + 2683350*p**9*q**2*r**3*s + 10906650*p**6*q**4*r**3*s + 187289500*p**3*q**6*r**3*s + 44098750*q**8*r**3*s - 4384800*p**10*r**4*s - 35660800*p**7*q**2*r**4*s - 175420000*p**4*q**4*r**4*s - 426538750*p*q**6*r**4*s + 60857600*p**8*r**5*s + 349436000*p**5*q**2*r**5*s + 900600000*p**2*q**4*r**5*s - 429568000*p**6*r**6*s - 1511200000*p**3*q**2*r**6*s - 1286000000*q**4*r**6*s + 1472000000*p**4*r**7*s + 1440000000*p*q**2*r**7*s - 1920000000*p**2*r**8*s - 36450*p**11*q**3*s**2 - 188100*p**8*q**5*s**2 - 5504750*p**5*q**7*s**2 - 37968750*p**2*q**9*s**2 + 255150*p**12*q*r*s**2 + 2754000*p**9*q**3*r*s**2 + 49196500*p**6*q**5*r*s**2 + 323587500*p**3*q**7*r*s**2 - 83250000*q**9*r*s**2 - 465750*p**10*q*r**2*s**2 - 31881500*p**7*q**3*r**2*s**2 - 415585000*p**4*q**5*r**2*s**2 + 1054775000*p*q**7*r**2*s**2 - 96823500*p**8*q*r**3*s**2 - 701490000*p**5*q**3*r**3*s**2 - 2953531250*p**2*q**5*r**3*s**2 + 1454560000*p**6*q*r**4*s**2 + 7670500000*p**3*q**3*r**4*s**2 + 5661062500*q**5*r**4*s**2 - 7785000000*p**4*q*r**5*s**2 - 9450000000*p*q**3*r**5*s**2 + 14000000000*p**2*q*r**6*s**2 + 2400000000*q*r**7*s**2 - 437400*p**13*s**3 - 10145250*p**10*q**2*s**3 - 121912500*p**7*q**4*s**3 - 576531250*p**4*q**6*s**3 - 528593750*p*q**8*s**3 + 12939750*p**11*r*s**3 + 313368750*p**8*q**2*r*s**3 + 2171812500*p**5*q**4*r*s**3 + 2381718750*p**2*q**6*r*s**3 - 124638750*p**9*r**2*s**3 - 3001575000*p**6*q**2*r**2*s**3 - 12259375000*p**3*q**4*r**2*s**3 - 9985312500*q**6*r**2*s**3 + 384000000*p**7*r**3*s**3 + 13997500000*p**4*q**2*r**3*s**3 + 20749531250*p*q**4*r**3*s**3 - 553500000*p**5*r**4*s**3 - 41835000000*p**2*q**2*r**4*s**3 + 5420000000*p**3*r**5*s**3 - 16300000000*q**2*r**5*s**3 - 17600000000*p*r**6*s**3 - 7593750*p**9*q*s**4 + 289218750*p**6*q**3*s**4 + 3591406250*p**3*q**5*s**4 + 5992187500*q**7*s**4 + 658125000*p**7*q*r*s**4 - 269531250*p**4*q**3*r*s**4 - 15882812500*p*q**5*r*s**4 - 4785000000*p**5*q*r**2*s**4 + 54375781250*p**2*q**3*r**2*s**4 - 5668750000*p**3*q*r**3*s**4 + 35867187500*q**3*r**3*s**4 + 113875000000*p*q*r**4*s**4 - 544218750*p**8*s**5 - 5407031250*p**5*q**2*s**5 - 14277343750*p**2*q**4*s**5 + 5421093750*p**6*r*s**5 - 24941406250*p**3*q**2*r*s**5 - 25488281250*q**4*r*s**5 - 11500000000*p**4*r**2*s**5 - 231894531250*p*q**2*r**2*s**5 - 6250000000*p**2*r**3*s**5 - 43750000000*r**4*s**5 + 35449218750*p**4*q*s**6 + 137695312500*p*q**3*s**6 + 34667968750*p**2*q*r*s**6 + 202148437500*q*r**2*s**6 - 33691406250*p**3*s**7 - 214843750000*q**2*s**7 - 31738281250*p*r*s**7 + + b[2][3] = -800*p**5*q**9 - 5400*p**2*q**11 + 5800*p**6*q**7*r + 48750*p**3*q**9*r + 16200*q**11*r - 3000*p**7*q**5*r**2 - 108350*p**4*q**7*r**2 - 263250*p*q**9*r**2 - 60700*p**8*q**3*r**3 - 386250*p**5*q**5*r**3 + 253100*p**2*q**7*r**3 + 127800*p**9*q*r**4 + 2326700*p**6*q**3*r**4 + 6565550*p**3*q**5*r**4 - 705750*q**7*r**4 - 2903200*p**7*q*r**5 - 21218000*p**4*q**3*r**5 + 1057000*p*q**5*r**5 + 20368000*p**5*q*r**6 + 33000000*p**2*q**3*r**6 - 43200000*p**3*q*r**7 + 52000000*q**3*r**7 + 6200*p**7*q**6*s + 188250*p**4*q**8*s + 931500*p*q**10*s - 73800*p**8*q**4*r*s - 1466850*p**5*q**6*r*s - 6894000*p**2*q**8*r*s + 315900*p**9*q**2*r**2*s + 4547000*p**6*q**4*r**2*s + 20362500*p**3*q**6*r**2*s + 15018750*q**8*r**2*s - 653400*p**10*r**3*s - 13897550*p**7*q**2*r**3*s - 76757500*p**4*q**4*r**3*s - 124207500*p*q**6*r**3*s + 18567600*p**8*r**4*s + 175911000*p**5*q**2*r**4*s + 253787500*p**2*q**4*r**4*s - 183816000*p**6*r**5*s - 706900000*p**3*q**2*r**5*s - 665750000*q**4*r**5*s + 740000000*p**4*r**6*s + 890000000*p*q**2*r**6*s - 1040000000*p**2*r**7*s - 763000*p**6*q**5*s**2 - 12375000*p**3*q**7*s**2 - 40500000*q**9*s**2 + 364500*p**10*q*r*s**2 + 15537000*p**7*q**3*r*s**2 + 154392500*p**4*q**5*r*s**2 + 372206250*p*q**7*r*s**2 - 25481250*p**8*q*r**2*s**2 - 386300000*p**5*q**3*r**2*s**2 - 996343750*p**2*q**5*r**2*s**2 + 459872500*p**6*q*r**3*s**2 + 2943937500*p**3*q**3*r**3*s**2 + 2437781250*q**5*r**3*s**2 - 2883750000*p**4*q*r**4*s**2 - 4343750000*p*q**3*r**4*s**2 + 5495000000*p**2*q*r**5*s**2 + 1300000000*q*r**6*s**2 - 364500*p**11*s**3 - 13668750*p**8*q**2*s**3 - 113406250*p**5*q**4*s**3 - 159062500*p**2*q**6*s**3 + 13972500*p**9*r*s**3 + 61537500*p**6*q**2*r*s**3 - 1622656250*p**3*q**4*r*s**3 - 2720625000*q**6*r*s**3 - 201656250*p**7*r**2*s**3 + 1949687500*p**4*q**2*r**2*s**3 + 4979687500*p*q**4*r**2*s**3 + 497125000*p**5*r**3*s**3 - 11150625000*p**2*q**2*r**3*s**3 + 2982500000*p**3*r**4*s**3 - 6612500000*q**2*r**4*s**3 - 10450000000*p*r**5*s**3 + 126562500*p**7*q*s**4 + 1443750000*p**4*q**3*s**4 + 281250000*p*q**5*s**4 - 1648125000*p**5*q*r*s**4 + 11271093750*p**2*q**3*r*s**4 - 4785156250*p**3*q*r**2*s**4 + 8808593750*q**3*r**2*s**4 + 52390625000*p*q*r**3*s**4 - 611718750*p**6*s**5 - 13027343750*p**3*q**2*s**5 - 1464843750*q**4*s**5 + 6492187500*p**4*r*s**5 - 65351562500*p*q**2*r*s**5 - 13476562500*p**2*r**2*s**5 - 24218750000*r**3*s**5 + 41992187500*p**2*q*s**6 + 69824218750*q*r*s**6 - 34179687500*p*s**7 + + b[2][2] = -1000*p**6*q**7 - 5150*p**3*q**9 + 10800*q**11 + 11000*p**7*q**5*r + 66450*p**4*q**7*r - 127800*p*q**9*r - 41250*p**8*q**3*r**2 - 368400*p**5*q**5*r**2 + 204200*p**2*q**7*r**2 + 54000*p**9*q*r**3 + 1040950*p**6*q**3*r**3 + 2096500*p**3*q**5*r**3 + 200000*q**7*r**3 - 1140000*p**7*q*r**4 - 7691000*p**4*q**3*r**4 - 2281000*p*q**5*r**4 + 7296000*p**5*q*r**5 + 13300000*p**2*q**3*r**5 - 14400000*p**3*q*r**6 + 14000000*q**3*r**6 - 9000*p**8*q**4*s + 52100*p**5*q**6*s + 710250*p**2*q**8*s + 67500*p**9*q**2*r*s - 256100*p**6*q**4*r*s - 5753000*p**3*q**6*r*s + 292500*q**8*r*s - 162000*p**10*r**2*s - 1432350*p**7*q**2*r**2*s + 5410000*p**4*q**4*r**2*s - 7408750*p*q**6*r**2*s + 4401000*p**8*r**3*s + 24185000*p**5*q**2*r**3*s + 20781250*p**2*q**4*r**3*s - 43012000*p**6*r**4*s - 146300000*p**3*q**2*r**4*s - 165875000*q**4*r**4*s + 182000000*p**4*r**5*s + 250000000*p*q**2*r**5*s - 280000000*p**2*r**6*s + 60750*p**10*q*s**2 + 2414250*p**7*q**3*s**2 + 15770000*p**4*q**5*s**2 + 15825000*p*q**7*s**2 - 6021000*p**8*q*r*s**2 - 62252500*p**5*q**3*r*s**2 - 74718750*p**2*q**5*r*s**2 + 90888750*p**6*q*r**2*s**2 + 471312500*p**3*q**3*r**2*s**2 + 525875000*q**5*r**2*s**2 - 539375000*p**4*q*r**3*s**2 - 1030000000*p*q**3*r**3*s**2 + 1142500000*p**2*q*r**4*s**2 + 350000000*q*r**5*s**2 - 303750*p**9*s**3 - 35943750*p**6*q**2*s**3 - 331875000*p**3*q**4*s**3 - 505937500*q**6*s**3 + 8437500*p**7*r*s**3 + 530781250*p**4*q**2*r*s**3 + 1150312500*p*q**4*r*s**3 - 154500000*p**5*r**2*s**3 - 2059062500*p**2*q**2*r**2*s**3 + 1150000000*p**3*r**3*s**3 - 1343750000*q**2*r**3*s**3 - 2900000000*p*r**4*s**3 + 30937500*p**5*q*s**4 + 1166406250*p**2*q**3*s**4 - 1496875000*p**3*q*r*s**4 + 1296875000*q**3*r*s**4 + 10640625000*p*q*r**2*s**4 - 281250000*p**4*s**5 - 9746093750*p*q**2*s**5 + 1269531250*p**2*r*s**5 - 7421875000*r**2*s**5 + 15625000000*q*s**6 + + b[2][1] = -1600*p**4*q**7 - 10800*p*q**9 + 9800*p**5*q**5*r + 80550*p**2*q**7*r - 4600*p**6*q**3*r**2 - 112700*p**3*q**5*r**2 + 40500*q**7*r**2 - 34200*p**7*q*r**3 - 279500*p**4*q**3*r**3 - 665750*p*q**5*r**3 + 632000*p**5*q*r**4 + 3200000*p**2*q**3*r**4 - 2800000*p**3*q*r**5 + 3000000*q**3*r**5 - 18600*p**6*q**4*s - 51750*p**3*q**6*s + 405000*q**8*s + 21600*p**7*q**2*r*s - 122500*p**4*q**4*r*s - 2891250*p*q**6*r*s + 156600*p**8*r**2*s + 1569750*p**5*q**2*r**2*s + 6943750*p**2*q**4*r**2*s - 3774000*p**6*r**3*s - 27100000*p**3*q**2*r**3*s - 30187500*q**4*r**3*s + 28000000*p**4*r**4*s + 52500000*p*q**2*r**4*s - 60000000*p**2*r**5*s - 81000*p**8*q*s**2 - 240000*p**5*q**3*s**2 + 937500*p**2*q**5*s**2 + 3273750*p**6*q*r*s**2 + 30406250*p**3*q**3*r*s**2 + 55687500*q**5*r*s**2 - 42187500*p**4*q*r**2*s**2 - 112812500*p*q**3*r**2*s**2 + 152500000*p**2*q*r**3*s**2 + 75000000*q*r**4*s**2 - 4218750*p**4*q**2*s**3 + 15156250*p*q**4*s**3 + 5906250*p**5*r*s**3 - 206562500*p**2*q**2*r*s**3 + 107500000*p**3*r**2*s**3 - 159375000*q**2*r**2*s**3 - 612500000*p*r**3*s**3 + 135937500*p**3*q*s**4 + 46875000*q**3*s**4 + 1175781250*p*q*r*s**4 - 292968750*p**2*s**5 - 1367187500*r*s**5 + + b[2][0] = -800*p**5*q**5 - 5400*p**2*q**7 + 6000*p**6*q**3*r + 51700*p**3*q**5*r + 27000*q**7*r - 10800*p**7*q*r**2 - 163250*p**4*q**3*r**2 - 285750*p*q**5*r**2 + 192000*p**5*q*r**3 + 1000000*p**2*q**3*r**3 - 800000*p**3*q*r**4 + 500000*q**3*r**4 - 10800*p**7*q**2*s - 57500*p**4*q**4*s + 67500*p*q**6*s + 32400*p**8*r*s + 279000*p**5*q**2*r*s - 131250*p**2*q**4*r*s - 729000*p**6*r**2*s - 4100000*p**3*q**2*r**2*s - 5343750*q**4*r**2*s + 5000000*p**4*r**3*s + 10000000*p*q**2*r**3*s - 10000000*p**2*r**4*s + 641250*p**6*q*s**2 + 5812500*p**3*q**3*s**2 + 10125000*q**5*s**2 - 7031250*p**4*q*r*s**2 - 20625000*p*q**3*r*s**2 + 17500000*p**2*q*r**2*s**2 + 12500000*q*r**3*s**2 - 843750*p**5*s**3 - 19375000*p**2*q**2*s**3 + 30000000*p**3*r*s**3 - 20312500*q**2*r*s**3 - 112500000*p*r**2*s**3 + 183593750*p*q*s**4 - 292968750*s**5 + + b[3][5] = 500*p**11*q**6 + 9875*p**8*q**8 + 42625*p**5*q**10 - 35000*p**2*q**12 - 4500*p**12*q**4*r - 108375*p**9*q**6*r - 516750*p**6*q**8*r + 1110500*p**3*q**10*r + 2730000*q**12*r + 10125*p**13*q**2*r**2 + 358250*p**10*q**4*r**2 + 1908625*p**7*q**6*r**2 - 11744250*p**4*q**8*r**2 - 43383250*p*q**10*r**2 - 313875*p**11*q**2*r**3 - 2074875*p**8*q**4*r**3 + 52094750*p**5*q**6*r**3 + 264567500*p**2*q**8*r**3 + 796125*p**9*q**2*r**4 - 92486250*p**6*q**4*r**4 - 757957500*p**3*q**6*r**4 - 29354375*q**8*r**4 + 60970000*p**7*q**2*r**5 + 1112462500*p**4*q**4*r**5 + 571094375*p*q**6*r**5 - 685290000*p**5*q**2*r**6 - 2037800000*p**2*q**4*r**6 + 2279600000*p**3*q**2*r**7 + 849000000*q**4*r**7 - 1480000000*p*q**2*r**8 + 13500*p**13*q**3*s + 363000*p**10*q**5*s + 2861250*p**7*q**7*s + 8493750*p**4*q**9*s + 17031250*p*q**11*s - 60750*p**14*q*r*s - 2319750*p**11*q**3*r*s - 22674250*p**8*q**5*r*s - 74368750*p**5*q**7*r*s - 170578125*p**2*q**9*r*s + 2760750*p**12*q*r**2*s + 46719000*p**9*q**3*r**2*s + 163356375*p**6*q**5*r**2*s + 360295625*p**3*q**7*r**2*s - 195990625*q**9*r**2*s - 37341750*p**10*q*r**3*s - 194739375*p**7*q**3*r**3*s - 105463125*p**4*q**5*r**3*s - 415825000*p*q**7*r**3*s + 90180000*p**8*q*r**4*s - 990552500*p**5*q**3*r**4*s + 3519212500*p**2*q**5*r**4*s + 1112220000*p**6*q*r**5*s - 4508750000*p**3*q**3*r**5*s - 8159500000*q**5*r**5*s - 4356000000*p**4*q*r**6*s + 14615000000*p*q**3*r**6*s - 2160000000*p**2*q*r**7*s + 91125*p**15*s**2 + 3290625*p**12*q**2*s**2 + 35100000*p**9*q**4*s**2 + 175406250*p**6*q**6*s**2 + 629062500*p**3*q**8*s**2 + 910937500*q**10*s**2 - 5710500*p**13*r*s**2 - 100423125*p**10*q**2*r*s**2 - 604743750*p**7*q**4*r*s**2 - 2954843750*p**4*q**6*r*s**2 - 4587578125*p*q**8*r*s**2 + 116194500*p**11*r**2*s**2 + 1280716250*p**8*q**2*r**2*s**2 + 7401190625*p**5*q**4*r**2*s**2 + 11619937500*p**2*q**6*r**2*s**2 - 952173125*p**9*r**3*s**2 - 6519712500*p**6*q**2*r**3*s**2 - 10238593750*p**3*q**4*r**3*s**2 + 29984609375*q**6*r**3*s**2 + 2558300000*p**7*r**4*s**2 + 16225000000*p**4*q**2*r**4*s**2 - 64994140625*p*q**4*r**4*s**2 + 4202250000*p**5*r**5*s**2 + 46925000000*p**2*q**2*r**5*s**2 - 28950000000*p**3*r**6*s**2 - 1000000000*q**2*r**6*s**2 + 37000000000*p*r**7*s**2 - 48093750*p**11*q*s**3 - 673359375*p**8*q**3*s**3 - 2170312500*p**5*q**5*s**3 - 2466796875*p**2*q**7*s**3 + 647578125*p**9*q*r*s**3 + 597031250*p**6*q**3*r*s**3 - 7542578125*p**3*q**5*r*s**3 - 41125000000*q**7*r*s**3 - 2175828125*p**7*q*r**2*s**3 - 7101562500*p**4*q**3*r**2*s**3 + 100596875000*p*q**5*r**2*s**3 - 8984687500*p**5*q*r**3*s**3 - 120070312500*p**2*q**3*r**3*s**3 + 57343750000*p**3*q*r**4*s**3 + 9500000000*q**3*r**4*s**3 - 342875000000*p*q*r**5*s**3 + 400781250*p**10*s**4 + 8531250000*p**7*q**2*s**4 + 34033203125*p**4*q**4*s**4 + 42724609375*p*q**6*s**4 - 6289453125*p**8*r*s**4 - 24037109375*p**5*q**2*r*s**4 - 62626953125*p**2*q**4*r*s**4 + 17299218750*p**6*r**2*s**4 + 108357421875*p**3*q**2*r**2*s**4 - 55380859375*q**4*r**2*s**4 + 105648437500*p**4*r**3*s**4 + 1204228515625*p*q**2*r**3*s**4 - 365000000000*p**2*r**4*s**4 + 184375000000*r**5*s**4 - 32080078125*p**6*q*s**5 - 98144531250*p**3*q**3*s**5 + 93994140625*q**5*s**5 - 178955078125*p**4*q*r*s**5 - 1299804687500*p*q**3*r*s**5 + 332421875000*p**2*q*r**2*s**5 - 1195312500000*q*r**3*s**5 + 72021484375*p**5*s**6 + 323486328125*p**2*q**2*s**6 + 682373046875*p**3*r*s**6 + 2447509765625*q**2*r*s**6 - 3011474609375*p*r**2*s**6 + 3051757812500*p*q*s**7 - 7629394531250*s**8 + + b[3][4] = 1500*p**9*q**6 + 69625*p**6*q**8 + 590375*p**3*q**10 + 1035000*q**12 - 13500*p**10*q**4*r - 760625*p**7*q**6*r - 7904500*p**4*q**8*r - 18169250*p*q**10*r + 30375*p**11*q**2*r**2 + 2628625*p**8*q**4*r**2 + 37879000*p**5*q**6*r**2 + 121367500*p**2*q**8*r**2 - 2699250*p**9*q**2*r**3 - 76776875*p**6*q**4*r**3 - 403583125*p**3*q**6*r**3 - 78865625*q**8*r**3 + 60907500*p**7*q**2*r**4 + 735291250*p**4*q**4*r**4 + 781142500*p*q**6*r**4 - 558270000*p**5*q**2*r**5 - 2150725000*p**2*q**4*r**5 + 2015400000*p**3*q**2*r**6 + 1181000000*q**4*r**6 - 2220000000*p*q**2*r**7 + 40500*p**11*q**3*s + 1376500*p**8*q**5*s + 9953125*p**5*q**7*s + 9765625*p**2*q**9*s - 182250*p**12*q*r*s - 8859000*p**9*q**3*r*s - 82854500*p**6*q**5*r*s - 71511250*p**3*q**7*r*s + 273631250*q**9*r*s + 10233000*p**10*q*r**2*s + 179627500*p**7*q**3*r**2*s + 25164375*p**4*q**5*r**2*s - 2927290625*p*q**7*r**2*s - 171305000*p**8*q*r**3*s - 544768750*p**5*q**3*r**3*s + 7583437500*p**2*q**5*r**3*s + 1139860000*p**6*q*r**4*s - 6489375000*p**3*q**3*r**4*s - 9625375000*q**5*r**4*s - 1838000000*p**4*q*r**5*s + 19835000000*p*q**3*r**5*s - 3240000000*p**2*q*r**6*s + 273375*p**13*s**2 + 9753750*p**10*q**2*s**2 + 82575000*p**7*q**4*s**2 + 202265625*p**4*q**6*s**2 + 556093750*p*q**8*s**2 - 11552625*p**11*r*s**2 - 115813125*p**8*q**2*r*s**2 + 630590625*p**5*q**4*r*s**2 + 1347015625*p**2*q**6*r*s**2 + 157578750*p**9*r**2*s**2 - 689206250*p**6*q**2*r**2*s**2 - 4299609375*p**3*q**4*r**2*s**2 + 23896171875*q**6*r**2*s**2 - 1022437500*p**7*r**3*s**2 + 6648125000*p**4*q**2*r**3*s**2 - 52895312500*p*q**4*r**3*s**2 + 4401750000*p**5*r**4*s**2 + 26500000000*p**2*q**2*r**4*s**2 - 22125000000*p**3*r**5*s**2 - 1500000000*q**2*r**5*s**2 + 55500000000*p*r**6*s**2 - 137109375*p**9*q*s**3 - 1955937500*p**6*q**3*s**3 - 6790234375*p**3*q**5*s**3 - 16996093750*q**7*s**3 + 2146218750*p**7*q*r*s**3 + 6570312500*p**4*q**3*r*s**3 + 39918750000*p*q**5*r*s**3 - 7673281250*p**5*q*r**2*s**3 - 52000000000*p**2*q**3*r**2*s**3 + 50796875000*p**3*q*r**3*s**3 + 18750000000*q**3*r**3*s**3 - 399875000000*p*q*r**4*s**3 + 780468750*p**8*s**4 + 14455078125*p**5*q**2*s**4 + 10048828125*p**2*q**4*s**4 - 15113671875*p**6*r*s**4 + 39298828125*p**3*q**2*r*s**4 - 52138671875*q**4*r*s**4 + 45964843750*p**4*r**2*s**4 + 914414062500*p*q**2*r**2*s**4 + 1953125000*p**2*r**3*s**4 + 334375000000*r**4*s**4 - 149169921875*p**4*q*s**5 - 459716796875*p*q**3*s**5 - 325585937500*p**2*q*r*s**5 - 1462890625000*q*r**2*s**5 + 296630859375*p**3*s**6 + 1324462890625*q**2*s**6 + 307617187500*p*r*s**6 + + b[3][3] = -20750*p**7*q**6 - 290125*p**4*q**8 - 993000*p*q**10 + 146125*p**8*q**4*r + 2721500*p**5*q**6*r + 11833750*p**2*q**8*r - 237375*p**9*q**2*r**2 - 8167500*p**6*q**4*r**2 - 54605625*p**3*q**6*r**2 - 23802500*q**8*r**2 + 8927500*p**7*q**2*r**3 + 131184375*p**4*q**4*r**3 + 254695000*p*q**6*r**3 - 121561250*p**5*q**2*r**4 - 728003125*p**2*q**4*r**4 + 702550000*p**3*q**2*r**5 + 597312500*q**4*r**5 - 1202500000*p*q**2*r**6 - 194625*p**9*q**3*s - 1568875*p**6*q**5*s + 9685625*p**3*q**7*s + 74662500*q**9*s + 327375*p**10*q*r*s + 1280000*p**7*q**3*r*s - 123703750*p**4*q**5*r*s - 850121875*p*q**7*r*s - 7436250*p**8*q*r**2*s + 164820000*p**5*q**3*r**2*s + 2336659375*p**2*q**5*r**2*s + 32202500*p**6*q*r**3*s - 2429765625*p**3*q**3*r**3*s - 4318609375*q**5*r**3*s + 148000000*p**4*q*r**4*s + 9902812500*p*q**3*r**4*s - 1755000000*p**2*q*r**5*s + 1154250*p**11*s**2 + 36821250*p**8*q**2*s**2 + 372825000*p**5*q**4*s**2 + 1170921875*p**2*q**6*s**2 - 38913750*p**9*r*s**2 - 797071875*p**6*q**2*r*s**2 - 2848984375*p**3*q**4*r*s**2 + 7651406250*q**6*r*s**2 + 415068750*p**7*r**2*s**2 + 3151328125*p**4*q**2*r**2*s**2 - 17696875000*p*q**4*r**2*s**2 - 725968750*p**5*r**3*s**2 + 5295312500*p**2*q**2*r**3*s**2 - 8581250000*p**3*r**4*s**2 - 812500000*q**2*r**4*s**2 + 30062500000*p*r**5*s**2 - 110109375*p**7*q*s**3 - 1976562500*p**4*q**3*s**3 - 6329296875*p*q**5*s**3 + 2256328125*p**5*q*r*s**3 + 8554687500*p**2*q**3*r*s**3 + 12947265625*p**3*q*r**2*s**3 + 7984375000*q**3*r**2*s**3 - 167039062500*p*q*r**3*s**3 + 1181250000*p**6*s**4 + 17873046875*p**3*q**2*s**4 - 20449218750*q**4*s**4 - 16265625000*p**4*r*s**4 + 260869140625*p*q**2*r*s**4 + 21025390625*p**2*r**2*s**4 + 207617187500*r**3*s**4 - 207177734375*p**2*q*s**5 - 615478515625*q*r*s**5 + 301513671875*p*s**6 + + b[3][2] = 53125*p**5*q**6 + 425000*p**2*q**8 - 394375*p**6*q**4*r - 4301875*p**3*q**6*r - 3225000*q**8*r + 851250*p**7*q**2*r**2 + 16910625*p**4*q**4*r**2 + 44210000*p*q**6*r**2 - 20474375*p**5*q**2*r**3 - 147190625*p**2*q**4*r**3 + 163975000*p**3*q**2*r**4 + 156812500*q**4*r**4 - 323750000*p*q**2*r**5 - 99375*p**7*q**3*s - 6395000*p**4*q**5*s - 49243750*p*q**7*s - 1164375*p**8*q*r*s + 4465625*p**5*q**3*r*s + 205546875*p**2*q**5*r*s + 12163750*p**6*q*r**2*s - 315546875*p**3*q**3*r**2*s - 946453125*q**5*r**2*s - 23500000*p**4*q*r**3*s + 2313437500*p*q**3*r**3*s - 472500000*p**2*q*r**4*s + 1316250*p**9*s**2 + 22715625*p**6*q**2*s**2 + 206953125*p**3*q**4*s**2 + 1220000000*q**6*s**2 - 20953125*p**7*r*s**2 - 277656250*p**4*q**2*r*s**2 - 3317187500*p*q**4*r*s**2 + 293734375*p**5*r**2*s**2 + 1351562500*p**2*q**2*r**2*s**2 - 2278125000*p**3*r**3*s**2 - 218750000*q**2*r**3*s**2 + 8093750000*p*r**4*s**2 - 9609375*p**5*q*s**3 + 240234375*p**2*q**3*s**3 + 2310546875*p**3*q*r*s**3 + 1171875000*q**3*r*s**3 - 33460937500*p*q*r**2*s**3 + 2185546875*p**4*s**4 + 32578125000*p*q**2*s**4 - 8544921875*p**2*r*s**4 + 58398437500*r**2*s**4 - 114013671875*q*s**5 + + b[3][1] = -16250*p**6*q**4 - 191875*p**3*q**6 - 495000*q**8 + 73125*p**7*q**2*r + 1437500*p**4*q**4*r + 5866250*p*q**6*r - 2043125*p**5*q**2*r**2 - 17218750*p**2*q**4*r**2 + 19106250*p**3*q**2*r**3 + 34015625*q**4*r**3 - 69375000*p*q**2*r**4 - 219375*p**8*q*s - 2846250*p**5*q**3*s - 8021875*p**2*q**5*s + 3420000*p**6*q*r*s - 1640625*p**3*q**3*r*s - 152468750*q**5*r*s + 3062500*p**4*q*r**2*s + 381171875*p*q**3*r**2*s - 101250000*p**2*q*r**3*s + 2784375*p**7*s**2 + 43515625*p**4*q**2*s**2 + 115625000*p*q**4*s**2 - 48140625*p**5*r*s**2 - 307421875*p**2*q**2*r*s**2 - 25781250*p**3*r**2*s**2 - 46875000*q**2*r**2*s**2 + 1734375000*p*r**3*s**2 - 128906250*p**3*q*s**3 + 339843750*q**3*s**3 - 4583984375*p*q*r*s**3 + 2236328125*p**2*s**4 + 12255859375*r*s**4 + + b[3][0] = 31875*p**4*q**4 + 255000*p*q**6 - 82500*p**5*q**2*r - 1106250*p**2*q**4*r + 1653125*p**3*q**2*r**2 + 5187500*q**4*r**2 - 11562500*p*q**2*r**3 - 118125*p**6*q*s - 3593750*p**3*q**3*s - 23812500*q**5*s + 4656250*p**4*q*r*s + 67109375*p*q**3*r*s - 16875000*p**2*q*r**2*s - 984375*p**5*s**2 - 19531250*p**2*q**2*s**2 - 37890625*p**3*r*s**2 - 7812500*q**2*r*s**2 + 289062500*p*r**2*s**2 - 529296875*p*q*s**3 + 2343750000*s**4 + + b[4][5] = 600*p**10*q**10 + 13850*p**7*q**12 + 106150*p**4*q**14 + 270000*p*q**16 - 9300*p**11*q**8*r - 234075*p**8*q**10*r - 1942825*p**5*q**12*r - 5319900*p**2*q**14*r + 52050*p**12*q**6*r**2 + 1481025*p**9*q**8*r**2 + 13594450*p**6*q**10*r**2 + 40062750*p**3*q**12*r**2 - 3569400*q**14*r**2 - 122175*p**13*q**4*r**3 - 4260350*p**10*q**6*r**3 - 45052375*p**7*q**8*r**3 - 142634900*p**4*q**10*r**3 + 54186350*p*q**12*r**3 + 97200*p**14*q**2*r**4 + 5284225*p**11*q**4*r**4 + 70389525*p**8*q**6*r**4 + 232732850*p**5*q**8*r**4 - 318849400*p**2*q**10*r**4 - 2046000*p**12*q**2*r**5 - 43874125*p**9*q**4*r**5 - 107411850*p**6*q**6*r**5 + 948310700*p**3*q**8*r**5 - 34763575*q**10*r**5 + 5915600*p**10*q**2*r**6 - 115887800*p**7*q**4*r**6 - 1649542400*p**4*q**6*r**6 + 224468875*p*q**8*r**6 + 120252800*p**8*q**2*r**7 + 1779902000*p**5*q**4*r**7 - 288250000*p**2*q**6*r**7 - 915200000*p**6*q**2*r**8 - 1164000000*p**3*q**4*r**8 - 444200000*q**6*r**8 + 2502400000*p**4*q**2*r**9 + 1984000000*p*q**4*r**9 - 2880000000*p**2*q**2*r**10 + 20700*p**12*q**7*s + 551475*p**9*q**9*s + 5194875*p**6*q**11*s + 18985000*p**3*q**13*s + 16875000*q**15*s - 218700*p**13*q**5*r*s - 6606475*p**10*q**7*r*s - 69770850*p**7*q**9*r*s - 285325500*p**4*q**11*r*s - 292005000*p*q**13*r*s + 694575*p**14*q**3*r**2*s + 26187750*p**11*q**5*r**2*s + 328992825*p**8*q**7*r**2*s + 1573292400*p**5*q**9*r**2*s + 1930043875*p**2*q**11*r**2*s - 583200*p**15*q*r**3*s - 37263225*p**12*q**3*r**3*s - 638579425*p**9*q**5*r**3*s - 3920212225*p**6*q**7*r**3*s - 6327336875*p**3*q**9*r**3*s + 440969375*q**11*r**3*s + 13446000*p**13*q*r**4*s + 462330325*p**10*q**3*r**4*s + 4509088275*p**7*q**5*r**4*s + 11709795625*p**4*q**7*r**4*s - 3579565625*p*q**9*r**4*s - 85033600*p**11*q*r**5*s - 2136801600*p**8*q**3*r**5*s - 12221575800*p**5*q**5*r**5*s + 9431044375*p**2*q**7*r**5*s + 10643200*p**9*q*r**6*s + 4565594000*p**6*q**3*r**6*s - 1778590000*p**3*q**5*r**6*s + 4842175000*q**7*r**6*s + 712320000*p**7*q*r**7*s - 16182000000*p**4*q**3*r**7*s - 21918000000*p*q**5*r**7*s - 742400000*p**5*q*r**8*s + 31040000000*p**2*q**3*r**8*s + 1280000000*p**3*q*r**9*s + 4800000000*q**3*r**9*s + 230850*p**14*q**4*s**2 + 7373250*p**11*q**6*s**2 + 85045625*p**8*q**8*s**2 + 399140625*p**5*q**10*s**2 + 565031250*p**2*q**12*s**2 - 1257525*p**15*q**2*r*s**2 - 52728975*p**12*q**4*r*s**2 - 743466375*p**9*q**6*r*s**2 - 4144915000*p**6*q**8*r*s**2 - 7102690625*p**3*q**10*r*s**2 - 1389937500*q**12*r*s**2 + 874800*p**16*r**2*s**2 + 89851275*p**13*q**2*r**2*s**2 + 1897236775*p**10*q**4*r**2*s**2 + 14144163000*p**7*q**6*r**2*s**2 + 31942921875*p**4*q**8*r**2*s**2 + 13305118750*p*q**10*r**2*s**2 - 23004000*p**14*r**3*s**2 - 1450715475*p**11*q**2*r**3*s**2 - 19427105000*p**8*q**4*r**3*s**2 - 70634028750*p**5*q**6*r**3*s**2 - 47854218750*p**2*q**8*r**3*s**2 + 204710400*p**12*r**4*s**2 + 10875135000*p**9*q**2*r**4*s**2 + 83618806250*p**6*q**4*r**4*s**2 + 62744500000*p**3*q**6*r**4*s**2 - 19806718750*q**8*r**4*s**2 - 757094800*p**10*r**5*s**2 - 37718030000*p**7*q**2*r**5*s**2 - 22479500000*p**4*q**4*r**5*s**2 + 91556093750*p*q**6*r**5*s**2 + 2306320000*p**8*r**6*s**2 + 55539600000*p**5*q**2*r**6*s**2 - 112851250000*p**2*q**4*r**6*s**2 - 10720000000*p**6*r**7*s**2 - 64720000000*p**3*q**2*r**7*s**2 - 59925000000*q**4*r**7*s**2 + 28000000000*p**4*r**8*s**2 + 28000000000*p*q**2*r**8*s**2 - 24000000000*p**2*r**9*s**2 + 820125*p**16*q*s**3 + 36804375*p**13*q**3*s**3 + 552225000*p**10*q**5*s**3 + 3357593750*p**7*q**7*s**3 + 7146562500*p**4*q**9*s**3 + 3851562500*p*q**11*s**3 - 92400750*p**14*q*r*s**3 - 2350175625*p**11*q**3*r*s**3 - 19470640625*p**8*q**5*r*s**3 - 52820593750*p**5*q**7*r*s**3 - 45447734375*p**2*q**9*r*s**3 + 1824363000*p**12*q*r**2*s**3 + 31435234375*p**9*q**3*r**2*s**3 + 141717537500*p**6*q**5*r**2*s**3 + 228370781250*p**3*q**7*r**2*s**3 + 34610078125*q**9*r**2*s**3 - 17591825625*p**10*q*r**3*s**3 - 188927187500*p**7*q**3*r**3*s**3 - 502088984375*p**4*q**5*r**3*s**3 - 187849296875*p*q**7*r**3*s**3 + 75577750000*p**8*q*r**4*s**3 + 342800000000*p**5*q**3*r**4*s**3 + 295384296875*p**2*q**5*r**4*s**3 - 107681250000*p**6*q*r**5*s**3 + 53330000000*p**3*q**3*r**5*s**3 + 271586875000*q**5*r**5*s**3 - 26410000000*p**4*q*r**6*s**3 - 188200000000*p*q**3*r**6*s**3 + 92000000000*p**2*q*r**7*s**3 + 120000000000*q*r**8*s**3 + 47840625*p**15*s**4 + 1150453125*p**12*q**2*s**4 + 9229453125*p**9*q**4*s**4 + 24954687500*p**6*q**6*s**4 + 22978515625*p**3*q**8*s**4 + 1367187500*q**10*s**4 - 1193737500*p**13*r*s**4 - 20817843750*p**10*q**2*r*s**4 - 98640000000*p**7*q**4*r*s**4 - 225767187500*p**4*q**6*r*s**4 - 74707031250*p*q**8*r*s**4 + 13431318750*p**11*r**2*s**4 + 188709843750*p**8*q**2*r**2*s**4 + 875157656250*p**5*q**4*r**2*s**4 + 593812890625*p**2*q**6*r**2*s**4 - 69869296875*p**9*r**3*s**4 - 854811093750*p**6*q**2*r**3*s**4 - 1730658203125*p**3*q**4*r**3*s**4 - 570867187500*q**6*r**3*s**4 + 162075625000*p**7*r**4*s**4 + 1536375000000*p**4*q**2*r**4*s**4 + 765156250000*p*q**4*r**4*s**4 - 165988750000*p**5*r**5*s**4 - 728968750000*p**2*q**2*r**5*s**4 + 121500000000*p**3*r**6*s**4 - 1039375000000*q**2*r**6*s**4 - 100000000000*p*r**7*s**4 - 379687500*p**11*q*s**5 - 11607421875*p**8*q**3*s**5 - 20830078125*p**5*q**5*s**5 - 33691406250*p**2*q**7*s**5 - 41491406250*p**9*q*r*s**5 - 419054687500*p**6*q**3*r*s**5 - 129511718750*p**3*q**5*r*s**5 + 311767578125*q**7*r*s**5 + 620116015625*p**7*q*r**2*s**5 + 1154687500000*p**4*q**3*r**2*s**5 + 36455078125*p*q**5*r**2*s**5 - 2265953125000*p**5*q*r**3*s**5 - 1509521484375*p**2*q**3*r**3*s**5 + 2530468750000*p**3*q*r**4*s**5 + 3259765625000*q**3*r**4*s**5 + 93750000000*p*q*r**5*s**5 + 23730468750*p**10*s**6 + 243603515625*p**7*q**2*s**6 + 341552734375*p**4*q**4*s**6 - 12207031250*p*q**6*s**6 - 357099609375*p**8*r*s**6 - 298193359375*p**5*q**2*r*s**6 + 406738281250*p**2*q**4*r*s**6 + 1615683593750*p**6*r**2*s**6 + 558593750000*p**3*q**2*r**2*s**6 - 2811035156250*q**4*r**2*s**6 - 2960937500000*p**4*r**3*s**6 - 3802246093750*p*q**2*r**3*s**6 + 2347656250000*p**2*r**4*s**6 - 671875000000*r**5*s**6 - 651855468750*p**6*q*s**7 - 1458740234375*p**3*q**3*s**7 - 152587890625*q**5*s**7 + 1628417968750*p**4*q*r*s**7 + 3948974609375*p*q**3*r*s**7 - 916748046875*p**2*q*r**2*s**7 + 1611328125000*q*r**3*s**7 + 640869140625*p**5*s**8 + 1068115234375*p**2*q**2*s**8 - 2044677734375*p**3*r*s**8 - 3204345703125*q**2*r*s**8 + 1739501953125*p*r**2*s**8 + + b[4][4] = -600*p**11*q**8 - 14050*p**8*q**10 - 109100*p**5*q**12 - 280800*p**2*q**14 + 7200*p**12*q**6*r + 188700*p**9*q**8*r + 1621725*p**6*q**10*r + 4577075*p**3*q**12*r + 5400*q**14*r - 28350*p**13*q**4*r**2 - 910600*p**10*q**6*r**2 - 9237975*p**7*q**8*r**2 - 30718900*p**4*q**10*r**2 - 5575950*p*q**12*r**2 + 36450*p**14*q**2*r**3 + 1848125*p**11*q**4*r**3 + 25137775*p**8*q**6*r**3 + 109591450*p**5*q**8*r**3 + 70627650*p**2*q**10*r**3 - 1317150*p**12*q**2*r**4 - 32857100*p**9*q**4*r**4 - 219125575*p**6*q**6*r**4 - 327565875*p**3*q**8*r**4 - 13011875*q**10*r**4 + 16484150*p**10*q**2*r**5 + 222242250*p**7*q**4*r**5 + 642173750*p**4*q**6*r**5 + 101263750*p*q**8*r**5 - 79345000*p**8*q**2*r**6 - 433180000*p**5*q**4*r**6 - 93731250*p**2*q**6*r**6 - 74300000*p**6*q**2*r**7 - 1057900000*p**3*q**4*r**7 - 591175000*q**6*r**7 + 1891600000*p**4*q**2*r**8 + 2796000000*p*q**4*r**8 - 4320000000*p**2*q**2*r**9 - 16200*p**13*q**5*s - 359500*p**10*q**7*s - 2603825*p**7*q**9*s - 4590375*p**4*q**11*s + 12352500*p*q**13*s + 121500*p**14*q**3*r*s + 3227400*p**11*q**5*r*s + 27301725*p**8*q**7*r*s + 59480975*p**5*q**9*r*s - 137308875*p**2*q**11*r*s - 218700*p**15*q*r**2*s - 8903925*p**12*q**3*r**2*s - 100918225*p**9*q**5*r**2*s - 325291300*p**6*q**7*r**2*s + 365705000*p**3*q**9*r**2*s + 94342500*q**11*r**2*s + 7632900*p**13*q*r**3*s + 162995400*p**10*q**3*r**3*s + 974558975*p**7*q**5*r**3*s + 930991250*p**4*q**7*r**3*s - 495368750*p*q**9*r**3*s - 97344900*p**11*q*r**4*s - 1406739250*p**8*q**3*r**4*s - 5572526250*p**5*q**5*r**4*s - 1903987500*p**2*q**7*r**4*s + 678550000*p**9*q*r**5*s + 8176215000*p**6*q**3*r**5*s + 18082050000*p**3*q**5*r**5*s + 5435843750*q**7*r**5*s - 2979800000*p**7*q*r**6*s - 29163500000*p**4*q**3*r**6*s - 27417500000*p*q**5*r**6*s + 6282400000*p**5*q*r**7*s + 48690000000*p**2*q**3*r**7*s - 2880000000*p**3*q*r**8*s + 7200000000*q**3*r**8*s - 109350*p**15*q**2*s**2 - 2405700*p**12*q**4*s**2 - 16125250*p**9*q**6*s**2 - 4930000*p**6*q**8*s**2 + 201150000*p**3*q**10*s**2 - 243000000*q**12*s**2 + 328050*p**16*r*s**2 + 10552275*p**13*q**2*r*s**2 + 88019100*p**10*q**4*r*s**2 - 4208625*p**7*q**6*r*s**2 - 1920390625*p**4*q**8*r*s**2 + 1759537500*p*q**10*r*s**2 - 11955600*p**14*r**2*s**2 - 196375050*p**11*q**2*r**2*s**2 - 555196250*p**8*q**4*r**2*s**2 + 4213270000*p**5*q**6*r**2*s**2 - 157468750*p**2*q**8*r**2*s**2 + 162656100*p**12*r**3*s**2 + 1880870000*p**9*q**2*r**3*s**2 + 753684375*p**6*q**4*r**3*s**2 - 25423062500*p**3*q**6*r**3*s**2 - 14142031250*q**8*r**3*s**2 - 1251948750*p**10*r**4*s**2 - 12524475000*p**7*q**2*r**4*s**2 + 18067656250*p**4*q**4*r**4*s**2 + 60531875000*p*q**6*r**4*s**2 + 6827725000*p**8*r**5*s**2 + 57157000000*p**5*q**2*r**5*s**2 - 75844531250*p**2*q**4*r**5*s**2 - 24452500000*p**6*r**6*s**2 - 144950000000*p**3*q**2*r**6*s**2 - 82109375000*q**4*r**6*s**2 + 46950000000*p**4*r**7*s**2 + 60000000000*p*q**2*r**7*s**2 - 36000000000*p**2*r**8*s**2 + 1549125*p**14*q*s**3 + 51873750*p**11*q**3*s**3 + 599781250*p**8*q**5*s**3 + 2421156250*p**5*q**7*s**3 - 1693515625*p**2*q**9*s**3 - 104884875*p**12*q*r*s**3 - 1937437500*p**9*q**3*r*s**3 - 11461053125*p**6*q**5*r*s**3 + 10299375000*p**3*q**7*r*s**3 + 10551250000*q**9*r*s**3 + 1336263750*p**10*q*r**2*s**3 + 23737250000*p**7*q**3*r**2*s**3 + 57136718750*p**4*q**5*r**2*s**3 - 8288906250*p*q**7*r**2*s**3 - 10907218750*p**8*q*r**3*s**3 - 160615000000*p**5*q**3*r**3*s**3 - 111134687500*p**2*q**5*r**3*s**3 + 46743125000*p**6*q*r**4*s**3 + 570509375000*p**3*q**3*r**4*s**3 + 274839843750*q**5*r**4*s**3 - 73312500000*p**4*q*r**5*s**3 - 145437500000*p*q**3*r**5*s**3 + 8750000000*p**2*q*r**6*s**3 + 180000000000*q*r**7*s**3 + 15946875*p**13*s**4 + 1265625*p**10*q**2*s**4 - 3282343750*p**7*q**4*s**4 - 38241406250*p**4*q**6*s**4 - 40136718750*p*q**8*s**4 - 113146875*p**11*r*s**4 - 2302734375*p**8*q**2*r*s**4 + 68450156250*p**5*q**4*r*s**4 + 177376562500*p**2*q**6*r*s**4 + 3164062500*p**9*r**2*s**4 + 14392890625*p**6*q**2*r**2*s**4 - 543781250000*p**3*q**4*r**2*s**4 - 319769531250*q**6*r**2*s**4 - 21048281250*p**7*r**3*s**4 - 240687500000*p**4*q**2*r**3*s**4 - 228164062500*p*q**4*r**3*s**4 + 23062500000*p**5*r**4*s**4 + 300410156250*p**2*q**2*r**4*s**4 + 93437500000*p**3*r**5*s**4 - 1141015625000*q**2*r**5*s**4 - 187500000000*p*r**6*s**4 + 1761328125*p**9*q*s**5 - 3177734375*p**6*q**3*s**5 + 60019531250*p**3*q**5*s**5 + 108398437500*q**7*s**5 + 24106640625*p**7*q*r*s**5 + 429589843750*p**4*q**3*r*s**5 + 410371093750*p*q**5*r*s**5 - 23582031250*p**5*q*r**2*s**5 + 202441406250*p**2*q**3*r**2*s**5 - 383203125000*p**3*q*r**3*s**5 + 2232910156250*q**3*r**3*s**5 + 1500000000000*p*q*r**4*s**5 - 13710937500*p**8*s**6 - 202832031250*p**5*q**2*s**6 - 531738281250*p**2*q**4*s**6 + 73330078125*p**6*r*s**6 - 3906250000*p**3*q**2*r*s**6 - 1275878906250*q**4*r*s**6 - 121093750000*p**4*r**2*s**6 - 3308593750000*p*q**2*r**2*s**6 + 18066406250*p**2*r**3*s**6 - 244140625000*r**4*s**6 + 327148437500*p**4*q*s**7 + 1672363281250*p*q**3*s**7 + 446777343750*p**2*q*r*s**7 + 1232910156250*q*r**2*s**7 - 274658203125*p**3*s**8 - 1068115234375*q**2*s**8 - 61035156250*p*r*s**8 + + b[4][3] = 200*p**9*q**8 + 7550*p**6*q**10 + 78650*p**3*q**12 + 248400*q**14 - 4800*p**10*q**6*r - 164300*p**7*q**8*r - 1709575*p**4*q**10*r - 5566500*p*q**12*r + 31050*p**11*q**4*r**2 + 1116175*p**8*q**6*r**2 + 12674650*p**5*q**8*r**2 + 45333850*p**2*q**10*r**2 - 60750*p**12*q**2*r**3 - 2872725*p**9*q**4*r**3 - 40403050*p**6*q**6*r**3 - 173564375*p**3*q**8*r**3 - 11242250*q**10*r**3 + 2174100*p**10*q**2*r**4 + 54010000*p**7*q**4*r**4 + 331074875*p**4*q**6*r**4 + 114173750*p*q**8*r**4 - 24858500*p**8*q**2*r**5 - 300875000*p**5*q**4*r**5 - 319430625*p**2*q**6*r**5 + 69810000*p**6*q**2*r**6 - 23900000*p**3*q**4*r**6 - 294662500*q**6*r**6 + 524200000*p**4*q**2*r**7 + 1432000000*p*q**4*r**7 - 2340000000*p**2*q**2*r**8 + 5400*p**11*q**5*s + 310400*p**8*q**7*s + 3591725*p**5*q**9*s + 11556750*p**2*q**11*s - 105300*p**12*q**3*r*s - 4234650*p**9*q**5*r*s - 49928875*p**6*q**7*r*s - 174078125*p**3*q**9*r*s + 18000000*q**11*r*s + 364500*p**13*q*r**2*s + 15763050*p**10*q**3*r**2*s + 220187400*p**7*q**5*r**2*s + 929609375*p**4*q**7*r**2*s - 43653125*p*q**9*r**2*s - 13427100*p**11*q*r**3*s - 346066250*p**8*q**3*r**3*s - 2287673375*p**5*q**5*r**3*s - 1403903125*p**2*q**7*r**3*s + 184586000*p**9*q*r**4*s + 2983460000*p**6*q**3*r**4*s + 8725818750*p**3*q**5*r**4*s + 2527734375*q**7*r**4*s - 1284480000*p**7*q*r**5*s - 13138250000*p**4*q**3*r**5*s - 14001625000*p*q**5*r**5*s + 4224800000*p**5*q*r**6*s + 27460000000*p**2*q**3*r**6*s - 3760000000*p**3*q*r**7*s + 3900000000*q**3*r**7*s + 36450*p**13*q**2*s**2 + 2765475*p**10*q**4*s**2 + 34027625*p**7*q**6*s**2 + 97375000*p**4*q**8*s**2 - 88275000*p*q**10*s**2 - 546750*p**14*r*s**2 - 21961125*p**11*q**2*r*s**2 - 273059375*p**8*q**4*r*s**2 - 761562500*p**5*q**6*r*s**2 + 1869656250*p**2*q**8*r*s**2 + 20545650*p**12*r**2*s**2 + 473934375*p**9*q**2*r**2*s**2 + 1758053125*p**6*q**4*r**2*s**2 - 8743359375*p**3*q**6*r**2*s**2 - 4154375000*q**8*r**2*s**2 - 296559000*p**10*r**3*s**2 - 4065056250*p**7*q**2*r**3*s**2 - 186328125*p**4*q**4*r**3*s**2 + 19419453125*p*q**6*r**3*s**2 + 2326262500*p**8*r**4*s**2 + 21189375000*p**5*q**2*r**4*s**2 - 26301953125*p**2*q**4*r**4*s**2 - 10513250000*p**6*r**5*s**2 - 69937500000*p**3*q**2*r**5*s**2 - 42257812500*q**4*r**5*s**2 + 23375000000*p**4*r**6*s**2 + 40750000000*p*q**2*r**6*s**2 - 19500000000*p**2*r**7*s**2 + 4009500*p**12*q*s**3 + 36140625*p**9*q**3*s**3 - 335459375*p**6*q**5*s**3 - 2695312500*p**3*q**7*s**3 - 1486250000*q**9*s**3 + 102515625*p**10*q*r*s**3 + 4006812500*p**7*q**3*r*s**3 + 27589609375*p**4*q**5*r*s**3 + 20195312500*p*q**7*r*s**3 - 2792812500*p**8*q*r**2*s**3 - 44115156250*p**5*q**3*r**2*s**3 - 72609453125*p**2*q**5*r**2*s**3 + 18752500000*p**6*q*r**3*s**3 + 218140625000*p**3*q**3*r**3*s**3 + 109940234375*q**5*r**3*s**3 - 21893750000*p**4*q*r**4*s**3 - 65187500000*p*q**3*r**4*s**3 - 31000000000*p**2*q*r**5*s**3 + 97500000000*q*r**6*s**3 - 86568750*p**11*s**4 - 1955390625*p**8*q**2*s**4 - 8960781250*p**5*q**4*s**4 - 1357812500*p**2*q**6*s**4 + 1657968750*p**9*r*s**4 + 10467187500*p**6*q**2*r*s**4 - 55292968750*p**3*q**4*r*s**4 - 60683593750*q**6*r*s**4 - 11473593750*p**7*r**2*s**4 - 123281250000*p**4*q**2*r**2*s**4 - 164912109375*p*q**4*r**2*s**4 + 13150000000*p**5*r**3*s**4 + 190751953125*p**2*q**2*r**3*s**4 + 61875000000*p**3*r**4*s**4 - 467773437500*q**2*r**4*s**4 - 118750000000*p*r**5*s**4 + 7583203125*p**7*q*s**5 + 54638671875*p**4*q**3*s**5 + 39423828125*p*q**5*s**5 + 32392578125*p**5*q*r*s**5 + 278515625000*p**2*q**3*r*s**5 - 298339843750*p**3*q*r**2*s**5 + 560791015625*q**3*r**2*s**5 + 720703125000*p*q*r**3*s**5 - 19687500000*p**6*s**6 - 159667968750*p**3*q**2*s**6 - 72265625000*q**4*s**6 + 116699218750*p**4*r*s**6 - 924072265625*p*q**2*r*s**6 - 156005859375*p**2*r**2*s**6 - 112304687500*r**3*s**6 + 349121093750*p**2*q*s**7 + 396728515625*q*r*s**7 - 213623046875*p*s**8 + + b[4][2] = -600*p**10*q**6 - 18450*p**7*q**8 - 174000*p**4*q**10 - 518400*p*q**12 + 5400*p**11*q**4*r + 197550*p**8*q**6*r + 2147775*p**5*q**8*r + 7219800*p**2*q**10*r - 12150*p**12*q**2*r**2 - 662200*p**9*q**4*r**2 - 9274775*p**6*q**6*r**2 - 38330625*p**3*q**8*r**2 - 5508000*q**10*r**2 + 656550*p**10*q**2*r**3 + 16233750*p**7*q**4*r**3 + 97335875*p**4*q**6*r**3 + 58271250*p*q**8*r**3 - 9845500*p**8*q**2*r**4 - 119464375*p**5*q**4*r**4 - 194431875*p**2*q**6*r**4 + 49465000*p**6*q**2*r**5 + 166000000*p**3*q**4*r**5 - 80793750*q**6*r**5 + 54400000*p**4*q**2*r**6 + 377750000*p*q**4*r**6 - 630000000*p**2*q**2*r**7 - 16200*p**12*q**3*s - 459300*p**9*q**5*s - 4207225*p**6*q**7*s - 10827500*p**3*q**9*s + 13635000*q**11*s + 72900*p**13*q*r*s + 2877300*p**10*q**3*r*s + 33239700*p**7*q**5*r*s + 107080625*p**4*q**7*r*s - 114975000*p*q**9*r*s - 3601800*p**11*q*r**2*s - 75214375*p**8*q**3*r**2*s - 387073250*p**5*q**5*r**2*s + 55540625*p**2*q**7*r**2*s + 53793000*p**9*q*r**3*s + 687176875*p**6*q**3*r**3*s + 1670018750*p**3*q**5*r**3*s + 665234375*q**7*r**3*s - 391570000*p**7*q*r**4*s - 3420125000*p**4*q**3*r**4*s - 3609625000*p*q**5*r**4*s + 1365600000*p**5*q*r**5*s + 7236250000*p**2*q**3*r**5*s - 1220000000*p**3*q*r**6*s + 1050000000*q**3*r**6*s - 109350*p**14*s**2 - 3065850*p**11*q**2*s**2 - 26908125*p**8*q**4*s**2 - 44606875*p**5*q**6*s**2 + 269812500*p**2*q**8*s**2 + 5200200*p**12*r*s**2 + 81826875*p**9*q**2*r*s**2 + 155378125*p**6*q**4*r*s**2 - 1936203125*p**3*q**6*r*s**2 - 998437500*q**8*r*s**2 - 77145750*p**10*r**2*s**2 - 745528125*p**7*q**2*r**2*s**2 + 683437500*p**4*q**4*r**2*s**2 + 4083359375*p*q**6*r**2*s**2 + 593287500*p**8*r**3*s**2 + 4799375000*p**5*q**2*r**3*s**2 - 4167578125*p**2*q**4*r**3*s**2 - 2731125000*p**6*r**4*s**2 - 18668750000*p**3*q**2*r**4*s**2 - 10480468750*q**4*r**4*s**2 + 6200000000*p**4*r**5*s**2 + 11750000000*p*q**2*r**5*s**2 - 5250000000*p**2*r**6*s**2 + 26527500*p**10*q*s**3 + 526031250*p**7*q**3*s**3 + 3160703125*p**4*q**5*s**3 + 2650312500*p*q**7*s**3 - 448031250*p**8*q*r*s**3 - 6682968750*p**5*q**3*r*s**3 - 11642812500*p**2*q**5*r*s**3 + 2553203125*p**6*q*r**2*s**3 + 37234375000*p**3*q**3*r**2*s**3 + 21871484375*q**5*r**2*s**3 + 2803125000*p**4*q*r**3*s**3 - 10796875000*p*q**3*r**3*s**3 - 16656250000*p**2*q*r**4*s**3 + 26250000000*q*r**5*s**3 - 75937500*p**9*s**4 - 704062500*p**6*q**2*s**4 - 8363281250*p**3*q**4*s**4 - 10398437500*q**6*s**4 + 197578125*p**7*r*s**4 - 16441406250*p**4*q**2*r*s**4 - 24277343750*p*q**4*r*s**4 - 5716015625*p**5*r**2*s**4 + 31728515625*p**2*q**2*r**2*s**4 + 27031250000*p**3*r**3*s**4 - 92285156250*q**2*r**3*s**4 - 33593750000*p*r**4*s**4 + 10394531250*p**5*q*s**5 + 38037109375*p**2*q**3*s**5 - 48144531250*p**3*q*r*s**5 + 74462890625*q**3*r*s**5 + 121093750000*p*q*r**2*s**5 - 2197265625*p**4*s**6 - 92529296875*p*q**2*s**6 + 15380859375*p**2*r*s**6 - 31738281250*r**2*s**6 + 54931640625*q*s**7 + + b[4][1] = 200*p**8*q**6 + 2950*p**5*q**8 + 10800*p**2*q**10 - 1800*p**9*q**4*r - 49650*p**6*q**6*r - 403375*p**3*q**8*r - 999000*q**10*r + 4050*p**10*q**2*r**2 + 236625*p**7*q**4*r**2 + 3109500*p**4*q**6*r**2 + 11463750*p*q**8*r**2 - 331500*p**8*q**2*r**3 - 7818125*p**5*q**4*r**3 - 41411250*p**2*q**6*r**3 + 4782500*p**6*q**2*r**4 + 47475000*p**3*q**4*r**4 - 16728125*q**6*r**4 - 8700000*p**4*q**2*r**5 + 81750000*p*q**4*r**5 - 135000000*p**2*q**2*r**6 + 5400*p**10*q**3*s + 144200*p**7*q**5*s + 939375*p**4*q**7*s + 1012500*p*q**9*s - 24300*p**11*q*r*s - 1169250*p**8*q**3*r*s - 14027250*p**5*q**5*r*s - 44446875*p**2*q**7*r*s + 2011500*p**9*q*r**2*s + 49330625*p**6*q**3*r**2*s + 272009375*p**3*q**5*r**2*s + 104062500*q**7*r**2*s - 34660000*p**7*q*r**3*s - 455062500*p**4*q**3*r**3*s - 625906250*p*q**5*r**3*s + 210200000*p**5*q*r**4*s + 1298750000*p**2*q**3*r**4*s - 240000000*p**3*q*r**5*s + 225000000*q**3*r**5*s + 36450*p**12*s**2 + 1231875*p**9*q**2*s**2 + 10712500*p**6*q**4*s**2 + 21718750*p**3*q**6*s**2 + 16875000*q**8*s**2 - 2814750*p**10*r*s**2 - 67612500*p**7*q**2*r*s**2 - 345156250*p**4*q**4*r*s**2 - 283125000*p*q**6*r*s**2 + 51300000*p**8*r**2*s**2 + 734531250*p**5*q**2*r**2*s**2 + 1267187500*p**2*q**4*r**2*s**2 - 384312500*p**6*r**3*s**2 - 3912500000*p**3*q**2*r**3*s**2 - 1822265625*q**4*r**3*s**2 + 1112500000*p**4*r**4*s**2 + 2437500000*p*q**2*r**4*s**2 - 1125000000*p**2*r**5*s**2 - 72578125*p**5*q**3*s**3 - 189296875*p**2*q**5*s**3 + 127265625*p**6*q*r*s**3 + 1415625000*p**3*q**3*r*s**3 + 1229687500*q**5*r*s**3 + 1448437500*p**4*q*r**2*s**3 + 2218750000*p*q**3*r**2*s**3 - 4031250000*p**2*q*r**3*s**3 + 5625000000*q*r**4*s**3 - 132890625*p**7*s**4 - 529296875*p**4*q**2*s**4 - 175781250*p*q**4*s**4 - 401953125*p**5*r*s**4 - 4482421875*p**2*q**2*r*s**4 + 4140625000*p**3*r**2*s**4 - 10498046875*q**2*r**2*s**4 - 7031250000*p*r**3*s**4 + 1220703125*p**3*q*s**5 + 1953125000*q**3*s**5 + 14160156250*p*q*r*s**5 - 1708984375*p**2*s**6 - 3662109375*r*s**6 + + b[4][0] = -4600*p**6*q**6 - 67850*p**3*q**8 - 248400*q**10 + 38900*p**7*q**4*r + 679575*p**4*q**6*r + 2866500*p*q**8*r - 81900*p**8*q**2*r**2 - 2009750*p**5*q**4*r**2 - 10783750*p**2*q**6*r**2 + 1478750*p**6*q**2*r**3 + 14165625*p**3*q**4*r**3 - 2743750*q**6*r**3 - 5450000*p**4*q**2*r**4 + 12687500*p*q**4*r**4 - 22500000*p**2*q**2*r**5 - 101700*p**8*q**3*s - 1700975*p**5*q**5*s - 7061250*p**2*q**7*s + 423900*p**9*q*r*s + 9292375*p**6*q**3*r*s + 50438750*p**3*q**5*r*s + 20475000*q**7*r*s - 7852500*p**7*q*r**2*s - 87765625*p**4*q**3*r**2*s - 121609375*p*q**5*r**2*s + 47700000*p**5*q*r**3*s + 264687500*p**2*q**3*r**3*s - 65000000*p**3*q*r**4*s + 37500000*q**3*r**4*s - 534600*p**10*s**2 - 10344375*p**7*q**2*s**2 - 54859375*p**4*q**4*s**2 - 40312500*p*q**6*s**2 + 10158750*p**8*r*s**2 + 117778125*p**5*q**2*r*s**2 + 192421875*p**2*q**4*r*s**2 - 70593750*p**6*r**2*s**2 - 685312500*p**3*q**2*r**2*s**2 - 334375000*q**4*r**2*s**2 + 193750000*p**4*r**3*s**2 + 500000000*p*q**2*r**3*s**2 - 187500000*p**2*r**4*s**2 + 8437500*p**6*q*s**3 + 159218750*p**3*q**3*s**3 + 220625000*q**5*s**3 + 353828125*p**4*q*r*s**3 + 412500000*p*q**3*r*s**3 - 1023437500*p**2*q*r**2*s**3 + 937500000*q*r**3*s**3 - 206015625*p**5*s**4 - 701171875*p**2*q**2*s**4 + 998046875*p**3*r*s**4 - 1308593750*q**2*r*s**4 - 1367187500*p*r**2*s**4 + 1708984375*p*q*s**5 - 976562500*s**6 + + return b + + @property + def o(self): + p, q, r, s = self.p, self.q, self.r, self.s + o = [0]*6 + + o[5] = -1600*p**10*q**10 - 23600*p**7*q**12 - 86400*p**4*q**14 + 24800*p**11*q**8*r + 419200*p**8*q**10*r + 1850450*p**5*q**12*r + 896400*p**2*q**14*r - 138800*p**12*q**6*r**2 - 2921900*p**9*q**8*r**2 - 17295200*p**6*q**10*r**2 - 27127750*p**3*q**12*r**2 - 26076600*q**14*r**2 + 325800*p**13*q**4*r**3 + 9993850*p**10*q**6*r**3 + 88010500*p**7*q**8*r**3 + 274047650*p**4*q**10*r**3 + 410171400*p*q**12*r**3 - 259200*p**14*q**2*r**4 - 17147100*p**11*q**4*r**4 - 254289150*p**8*q**6*r**4 - 1318548225*p**5*q**8*r**4 - 2633598475*p**2*q**10*r**4 + 12636000*p**12*q**2*r**5 + 388911000*p**9*q**4*r**5 + 3269704725*p**6*q**6*r**5 + 8791192300*p**3*q**8*r**5 + 93560575*q**10*r**5 - 228361600*p**10*q**2*r**6 - 3951199200*p**7*q**4*r**6 - 16276981100*p**4*q**6*r**6 - 1597227000*p*q**8*r**6 + 1947899200*p**8*q**2*r**7 + 17037648000*p**5*q**4*r**7 + 8919740000*p**2*q**6*r**7 - 7672160000*p**6*q**2*r**8 - 15496000000*p**3*q**4*r**8 + 4224000000*q**6*r**8 + 9968000000*p**4*q**2*r**9 - 8640000000*p*q**4*r**9 + 4800000000*p**2*q**2*r**10 - 55200*p**12*q**7*s - 685600*p**9*q**9*s + 1028250*p**6*q**11*s + 37650000*p**3*q**13*s + 111375000*q**15*s + 583200*p**13*q**5*r*s + 9075600*p**10*q**7*r*s - 883150*p**7*q**9*r*s - 506830750*p**4*q**11*r*s - 1793137500*p*q**13*r*s - 1852200*p**14*q**3*r**2*s - 41435250*p**11*q**5*r**2*s - 80566700*p**8*q**7*r**2*s + 2485673600*p**5*q**9*r**2*s + 11442286125*p**2*q**11*r**2*s + 1555200*p**15*q*r**3*s + 80846100*p**12*q**3*r**3*s + 564906800*p**9*q**5*r**3*s - 4493012400*p**6*q**7*r**3*s - 35492391250*p**3*q**9*r**3*s - 789931875*q**11*r**3*s - 71766000*p**13*q*r**4*s - 1551149200*p**10*q**3*r**4*s - 1773437900*p**7*q**5*r**4*s + 51957593125*p**4*q**7*r**4*s + 14964765625*p*q**9*r**4*s + 1231569600*p**11*q*r**5*s + 12042977600*p**8*q**3*r**5*s - 27151011200*p**5*q**5*r**5*s - 88080610000*p**2*q**7*r**5*s - 9912995200*p**9*q*r**6*s - 29448104000*p**6*q**3*r**6*s + 144954840000*p**3*q**5*r**6*s - 44601300000*q**7*r**6*s + 35453760000*p**7*q*r**7*s - 63264000000*p**4*q**3*r**7*s + 60544000000*p*q**5*r**7*s - 30048000000*p**5*q*r**8*s + 37040000000*p**2*q**3*r**8*s - 60800000000*p**3*q*r**9*s - 48000000000*q**3*r**9*s - 615600*p**14*q**4*s**2 - 10524500*p**11*q**6*s**2 - 33831250*p**8*q**8*s**2 + 222806250*p**5*q**10*s**2 + 1099687500*p**2*q**12*s**2 + 3353400*p**15*q**2*r*s**2 + 74269350*p**12*q**4*r*s**2 + 276445750*p**9*q**6*r*s**2 - 2618600000*p**6*q**8*r*s**2 - 14473243750*p**3*q**10*r*s**2 + 1383750000*q**12*r*s**2 - 2332800*p**16*r**2*s**2 - 132750900*p**13*q**2*r**2*s**2 - 900775150*p**10*q**4*r**2*s**2 + 8249244500*p**7*q**6*r**2*s**2 + 59525796875*p**4*q**8*r**2*s**2 - 40292868750*p*q**10*r**2*s**2 + 128304000*p**14*r**3*s**2 + 3160232100*p**11*q**2*r**3*s**2 + 8329580000*p**8*q**4*r**3*s**2 - 45558458750*p**5*q**6*r**3*s**2 + 297252890625*p**2*q**8*r**3*s**2 - 2769854400*p**12*r**4*s**2 - 37065970000*p**9*q**2*r**4*s**2 - 90812546875*p**6*q**4*r**4*s**2 - 627902000000*p**3*q**6*r**4*s**2 + 181347421875*q**8*r**4*s**2 + 30946932800*p**10*r**5*s**2 + 249954680000*p**7*q**2*r**5*s**2 + 802954812500*p**4*q**4*r**5*s**2 - 80900000000*p*q**6*r**5*s**2 - 192137320000*p**8*r**6*s**2 - 932641600000*p**5*q**2*r**6*s**2 - 943242500000*p**2*q**4*r**6*s**2 + 658412000000*p**6*r**7*s**2 + 1930720000000*p**3*q**2*r**7*s**2 + 593800000000*q**4*r**7*s**2 - 1162800000000*p**4*r**8*s**2 - 280000000000*p*q**2*r**8*s**2 + 840000000000*p**2*r**9*s**2 - 2187000*p**16*q*s**3 - 47418750*p**13*q**3*s**3 - 180618750*p**10*q**5*s**3 + 2231250000*p**7*q**7*s**3 + 17857734375*p**4*q**9*s**3 + 29882812500*p*q**11*s**3 + 24664500*p**14*q*r*s**3 - 853368750*p**11*q**3*r*s**3 - 25939693750*p**8*q**5*r*s**3 - 177541562500*p**5*q**7*r*s**3 - 297978828125*p**2*q**9*r*s**3 - 153468000*p**12*q*r**2*s**3 + 30188125000*p**9*q**3*r**2*s**3 + 344049821875*p**6*q**5*r**2*s**3 + 534026875000*p**3*q**7*r**2*s**3 - 340726484375*q**9*r**2*s**3 - 9056190000*p**10*q*r**3*s**3 - 322314687500*p**7*q**3*r**3*s**3 - 769632109375*p**4*q**5*r**3*s**3 - 83276875000*p*q**7*r**3*s**3 + 164061000000*p**8*q*r**4*s**3 + 1381358750000*p**5*q**3*r**4*s**3 + 3088020000000*p**2*q**5*r**4*s**3 - 1267655000000*p**6*q*r**5*s**3 - 7642630000000*p**3*q**3*r**5*s**3 - 2759877500000*q**5*r**5*s**3 + 4597760000000*p**4*q*r**6*s**3 + 1846200000000*p*q**3*r**6*s**3 - 7006000000000*p**2*q*r**7*s**3 - 1200000000000*q*r**8*s**3 + 18225000*p**15*s**4 + 1328906250*p**12*q**2*s**4 + 24729140625*p**9*q**4*s**4 + 169467187500*p**6*q**6*s**4 + 413281250000*p**3*q**8*s**4 + 223828125000*q**10*s**4 + 710775000*p**13*r*s**4 - 18611015625*p**10*q**2*r*s**4 - 314344375000*p**7*q**4*r*s**4 - 828439843750*p**4*q**6*r*s**4 + 460937500000*p*q**8*r*s**4 - 25674975000*p**11*r**2*s**4 - 52223515625*p**8*q**2*r**2*s**4 - 387160000000*p**5*q**4*r**2*s**4 - 4733680078125*p**2*q**6*r**2*s**4 + 343911875000*p**9*r**3*s**4 + 3328658359375*p**6*q**2*r**3*s**4 + 16532406250000*p**3*q**4*r**3*s**4 + 5980613281250*q**6*r**3*s**4 - 2295497500000*p**7*r**4*s**4 - 14809820312500*p**4*q**2*r**4*s**4 - 6491406250000*p*q**4*r**4*s**4 + 7768470000000*p**5*r**5*s**4 + 34192562500000*p**2*q**2*r**5*s**4 - 11859000000000*p**3*r**6*s**4 + 10530000000000*q**2*r**6*s**4 + 6000000000000*p*r**7*s**4 + 11453906250*p**11*q*s**5 + 149765625000*p**8*q**3*s**5 + 545537109375*p**5*q**5*s**5 + 527343750000*p**2*q**7*s**5 - 371313281250*p**9*q*r*s**5 - 3461455078125*p**6*q**3*r*s**5 - 7920878906250*p**3*q**5*r*s**5 - 4747314453125*q**7*r*s**5 + 2417815625000*p**7*q*r**2*s**5 + 5465576171875*p**4*q**3*r**2*s**5 + 5937128906250*p*q**5*r**2*s**5 - 10661156250000*p**5*q*r**3*s**5 - 63574218750000*p**2*q**3*r**3*s**5 + 24059375000000*p**3*q*r**4*s**5 - 33023437500000*q**3*r**4*s**5 - 43125000000000*p*q*r**5*s**5 + 94394531250*p**10*s**6 + 1097167968750*p**7*q**2*s**6 + 2829833984375*p**4*q**4*s**6 - 1525878906250*p*q**6*s**6 + 2724609375*p**8*r*s**6 + 13998535156250*p**5*q**2*r*s**6 + 57094482421875*p**2*q**4*r*s**6 - 8512509765625*p**6*r**2*s**6 - 37941406250000*p**3*q**2*r**2*s**6 + 33191894531250*q**4*r**2*s**6 + 50534179687500*p**4*r**3*s**6 + 156656250000000*p*q**2*r**3*s**6 - 85023437500000*p**2*r**4*s**6 + 10125000000000*r**5*s**6 - 2717285156250*p**6*q*s**7 - 11352539062500*p**3*q**3*s**7 - 2593994140625*q**5*s**7 - 47154541015625*p**4*q*r*s**7 - 160644531250000*p*q**3*r*s**7 + 142500000000000*p**2*q*r**2*s**7 - 26757812500000*q*r**3*s**7 - 4364013671875*p**5*s**8 - 94604492187500*p**2*q**2*s**8 + 114379882812500*p**3*r*s**8 + 51116943359375*q**2*r*s**8 - 346435546875000*p*r**2*s**8 + 476837158203125*p*q*s**9 - 476837158203125*s**10 + + o[4] = 1600*p**11*q**8 + 20800*p**8*q**10 + 45100*p**5*q**12 - 151200*p**2*q**14 - 19200*p**12*q**6*r - 293200*p**9*q**8*r - 794600*p**6*q**10*r + 2634675*p**3*q**12*r + 2640600*q**14*r + 75600*p**13*q**4*r**2 + 1529100*p**10*q**6*r**2 + 6233350*p**7*q**8*r**2 - 12013350*p**4*q**10*r**2 - 29069550*p*q**12*r**2 - 97200*p**14*q**2*r**3 - 3562500*p**11*q**4*r**3 - 26984900*p**8*q**6*r**3 - 15900325*p**5*q**8*r**3 + 76267100*p**2*q**10*r**3 + 3272400*p**12*q**2*r**4 + 59486850*p**9*q**4*r**4 + 221270075*p**6*q**6*r**4 + 74065250*p**3*q**8*r**4 - 300564375*q**10*r**4 - 45569400*p**10*q**2*r**5 - 438666000*p**7*q**4*r**5 - 444821250*p**4*q**6*r**5 + 2448256250*p*q**8*r**5 + 290640000*p**8*q**2*r**6 + 855850000*p**5*q**4*r**6 - 5741875000*p**2*q**6*r**6 - 644000000*p**6*q**2*r**7 + 5574000000*p**3*q**4*r**7 + 4643000000*q**6*r**7 - 1696000000*p**4*q**2*r**8 - 12660000000*p*q**4*r**8 + 7200000000*p**2*q**2*r**9 + 43200*p**13*q**5*s + 572000*p**10*q**7*s - 59800*p**7*q**9*s - 24174625*p**4*q**11*s - 74587500*p*q**13*s - 324000*p**14*q**3*r*s - 5531400*p**11*q**5*r*s - 3712100*p**8*q**7*r*s + 293009275*p**5*q**9*r*s + 1115548875*p**2*q**11*r*s + 583200*p**15*q*r**2*s + 18343800*p**12*q**3*r**2*s + 77911100*p**9*q**5*r**2*s - 957488825*p**6*q**7*r**2*s - 5449661250*p**3*q**9*r**2*s + 960120000*q**11*r**2*s - 23684400*p**13*q*r**3*s - 373761900*p**10*q**3*r**3*s - 27944975*p**7*q**5*r**3*s + 10375740625*p**4*q**7*r**3*s - 4649093750*p*q**9*r**3*s + 395816400*p**11*q*r**4*s + 2910968000*p**8*q**3*r**4*s - 9126162500*p**5*q**5*r**4*s - 11696118750*p**2*q**7*r**4*s - 3028640000*p**9*q*r**5*s - 3251550000*p**6*q**3*r**5*s + 47914250000*p**3*q**5*r**5*s - 30255625000*q**7*r**5*s + 9304000000*p**7*q*r**6*s - 42970000000*p**4*q**3*r**6*s + 31475000000*p*q**5*r**6*s + 2176000000*p**5*q*r**7*s + 62100000000*p**2*q**3*r**7*s - 43200000000*p**3*q*r**8*s - 72000000000*q**3*r**8*s + 291600*p**15*q**2*s**2 + 2702700*p**12*q**4*s**2 - 38692250*p**9*q**6*s**2 - 538903125*p**6*q**8*s**2 - 1613112500*p**3*q**10*s**2 + 320625000*q**12*s**2 - 874800*p**16*r*s**2 - 14166900*p**13*q**2*r*s**2 + 193284900*p**10*q**4*r*s**2 + 3688520500*p**7*q**6*r*s**2 + 11613390625*p**4*q**8*r*s**2 - 15609881250*p*q**10*r*s**2 + 44031600*p**14*r**2*s**2 + 482345550*p**11*q**2*r**2*s**2 - 2020881875*p**8*q**4*r**2*s**2 - 7407026250*p**5*q**6*r**2*s**2 + 136175750000*p**2*q**8*r**2*s**2 - 1000884600*p**12*r**3*s**2 - 8888950000*p**9*q**2*r**3*s**2 - 30101703125*p**6*q**4*r**3*s**2 - 319761000000*p**3*q**6*r**3*s**2 + 51519218750*q**8*r**3*s**2 + 12622395000*p**10*r**4*s**2 + 97032450000*p**7*q**2*r**4*s**2 + 469929218750*p**4*q**4*r**4*s**2 + 291342187500*p*q**6*r**4*s**2 - 96382000000*p**8*r**5*s**2 - 598070000000*p**5*q**2*r**5*s**2 - 1165021875000*p**2*q**4*r**5*s**2 + 446500000000*p**6*r**6*s**2 + 1651500000000*p**3*q**2*r**6*s**2 + 789375000000*q**4*r**6*s**2 - 1152000000000*p**4*r**7*s**2 - 600000000000*p*q**2*r**7*s**2 + 1260000000000*p**2*r**8*s**2 - 24786000*p**14*q*s**3 - 660487500*p**11*q**3*s**3 - 5886356250*p**8*q**5*s**3 - 18137187500*p**5*q**7*s**3 - 5120546875*p**2*q**9*s**3 + 827658000*p**12*q*r*s**3 + 13343062500*p**9*q**3*r*s**3 + 39782068750*p**6*q**5*r*s**3 - 111288437500*p**3*q**7*r*s**3 - 15438750000*q**9*r*s**3 - 14540782500*p**10*q*r**2*s**3 - 135889750000*p**7*q**3*r**2*s**3 - 176892578125*p**4*q**5*r**2*s**3 - 934462656250*p*q**7*r**2*s**3 + 171669250000*p**8*q*r**3*s**3 + 1164538125000*p**5*q**3*r**3*s**3 + 3192346406250*p**2*q**5*r**3*s**3 - 1295476250000*p**6*q*r**4*s**3 - 6540712500000*p**3*q**3*r**4*s**3 - 2957828125000*q**5*r**4*s**3 + 5366750000000*p**4*q*r**5*s**3 + 3165000000000*p*q**3*r**5*s**3 - 8862500000000*p**2*q*r**6*s**3 - 1800000000000*q*r**7*s**3 + 236925000*p**13*s**4 + 8895234375*p**10*q**2*s**4 + 106180781250*p**7*q**4*s**4 + 474221875000*p**4*q**6*s**4 + 616210937500*p*q**8*s**4 - 6995868750*p**11*r*s**4 - 184190625000*p**8*q**2*r*s**4 - 1299254453125*p**5*q**4*r*s**4 - 2475458593750*p**2*q**6*r*s**4 + 63049218750*p**9*r**2*s**4 + 1646791484375*p**6*q**2*r**2*s**4 + 9086886718750*p**3*q**4*r**2*s**4 + 4673421875000*q**6*r**2*s**4 - 215665000000*p**7*r**3*s**4 - 7864589843750*p**4*q**2*r**3*s**4 - 5987890625000*p*q**4*r**3*s**4 + 594843750000*p**5*r**4*s**4 + 27791171875000*p**2*q**2*r**4*s**4 - 3881250000000*p**3*r**5*s**4 + 12203125000000*q**2*r**5*s**4 + 10312500000000*p*r**6*s**4 - 34720312500*p**9*q*s**5 - 545126953125*p**6*q**3*s**5 - 2176425781250*p**3*q**5*s**5 - 2792968750000*q**7*s**5 - 1395703125*p**7*q*r*s**5 - 1957568359375*p**4*q**3*r*s**5 + 5122636718750*p*q**5*r*s**5 + 858210937500*p**5*q*r**2*s**5 - 42050097656250*p**2*q**3*r**2*s**5 + 7088281250000*p**3*q*r**3*s**5 - 25974609375000*q**3*r**3*s**5 - 69296875000000*p*q*r**4*s**5 + 384697265625*p**8*s**6 + 6403320312500*p**5*q**2*s**6 + 16742675781250*p**2*q**4*s**6 - 3467080078125*p**6*r*s**6 + 11009765625000*p**3*q**2*r*s**6 + 16451660156250*q**4*r*s**6 + 6979003906250*p**4*r**2*s**6 + 145403320312500*p*q**2*r**2*s**6 + 4076171875000*p**2*r**3*s**6 + 22265625000000*r**4*s**6 - 21915283203125*p**4*q*s**7 - 86608886718750*p*q**3*s**7 - 22785644531250*p**2*q*r*s**7 - 103466796875000*q*r**2*s**7 + 18798828125000*p**3*s**8 + 106048583984375*q**2*s**8 + 17761230468750*p*r*s**8 + + o[3] = 2800*p**9*q**8 + 55700*p**6*q**10 + 363600*p**3*q**12 + 777600*q**14 - 27200*p**10*q**6*r - 700200*p**7*q**8*r - 5726550*p**4*q**10*r - 15066000*p*q**12*r + 74700*p**11*q**4*r**2 + 2859575*p**8*q**6*r**2 + 31175725*p**5*q**8*r**2 + 103147650*p**2*q**10*r**2 - 40500*p**12*q**2*r**3 - 4274400*p**9*q**4*r**3 - 76065825*p**6*q**6*r**3 - 365623750*p**3*q**8*r**3 - 132264000*q**10*r**3 + 2192400*p**10*q**2*r**4 + 92562500*p**7*q**4*r**4 + 799193875*p**4*q**6*r**4 + 1188193125*p*q**8*r**4 - 41231500*p**8*q**2*r**5 - 914210000*p**5*q**4*r**5 - 3318853125*p**2*q**6*r**5 + 398850000*p**6*q**2*r**6 + 3944000000*p**3*q**4*r**6 + 2211312500*q**6*r**6 - 1817000000*p**4*q**2*r**7 - 6720000000*p*q**4*r**7 + 3900000000*p**2*q**2*r**8 + 75600*p**11*q**5*s + 1823100*p**8*q**7*s + 14534150*p**5*q**9*s + 38265750*p**2*q**11*s - 394200*p**12*q**3*r*s - 11453850*p**9*q**5*r*s - 101213000*p**6*q**7*r*s - 223565625*p**3*q**9*r*s + 415125000*q**11*r*s + 243000*p**13*q*r**2*s + 13654575*p**10*q**3*r**2*s + 163811725*p**7*q**5*r**2*s + 173461250*p**4*q**7*r**2*s - 3008671875*p*q**9*r**2*s - 2016900*p**11*q*r**3*s - 86576250*p**8*q**3*r**3*s - 324146625*p**5*q**5*r**3*s + 3378506250*p**2*q**7*r**3*s - 89211000*p**9*q*r**4*s - 55207500*p**6*q**3*r**4*s + 1493950000*p**3*q**5*r**4*s - 12573609375*q**7*r**4*s + 1140100000*p**7*q*r**5*s + 42500000*p**4*q**3*r**5*s + 21511250000*p*q**5*r**5*s - 4058000000*p**5*q*r**6*s + 6725000000*p**2*q**3*r**6*s - 1400000000*p**3*q*r**7*s - 39000000000*q**3*r**7*s + 510300*p**13*q**2*s**2 + 4814775*p**10*q**4*s**2 - 70265125*p**7*q**6*s**2 - 1016484375*p**4*q**8*s**2 - 3221100000*p*q**10*s**2 - 364500*p**14*r*s**2 + 30314250*p**11*q**2*r*s**2 + 1106765625*p**8*q**4*r*s**2 + 10984203125*p**5*q**6*r*s**2 + 33905812500*p**2*q**8*r*s**2 - 37980900*p**12*r**2*s**2 - 2142905625*p**9*q**2*r**2*s**2 - 26896125000*p**6*q**4*r**2*s**2 - 95551328125*p**3*q**6*r**2*s**2 + 11320312500*q**8*r**2*s**2 + 1743781500*p**10*r**3*s**2 + 35432262500*p**7*q**2*r**3*s**2 + 177855859375*p**4*q**4*r**3*s**2 + 121260546875*p*q**6*r**3*s**2 - 25943162500*p**8*r**4*s**2 - 249165500000*p**5*q**2*r**4*s**2 - 461739453125*p**2*q**4*r**4*s**2 + 177823750000*p**6*r**5*s**2 + 726225000000*p**3*q**2*r**5*s**2 + 404195312500*q**4*r**5*s**2 - 565875000000*p**4*r**6*s**2 - 407500000000*p*q**2*r**6*s**2 + 682500000000*p**2*r**7*s**2 - 59140125*p**12*q*s**3 - 1290515625*p**9*q**3*s**3 - 8785071875*p**6*q**5*s**3 - 15588281250*p**3*q**7*s**3 + 17505000000*q**9*s**3 + 896062500*p**10*q*r*s**3 + 2589750000*p**7*q**3*r*s**3 - 82700156250*p**4*q**5*r*s**3 - 347683593750*p*q**7*r*s**3 + 17022656250*p**8*q*r**2*s**3 + 320923593750*p**5*q**3*r**2*s**3 + 1042116875000*p**2*q**5*r**2*s**3 - 353262812500*p**6*q*r**3*s**3 - 2212664062500*p**3*q**3*r**3*s**3 - 1252408984375*q**5*r**3*s**3 + 1967362500000*p**4*q*r**4*s**3 + 1583343750000*p*q**3*r**4*s**3 - 3560625000000*p**2*q*r**5*s**3 - 975000000000*q*r**6*s**3 + 462459375*p**11*s**4 + 14210859375*p**8*q**2*s**4 + 99521718750*p**5*q**4*s**4 + 114955468750*p**2*q**6*s**4 - 17720859375*p**9*r*s**4 - 100320703125*p**6*q**2*r*s**4 + 1021943359375*p**3*q**4*r*s**4 + 1193203125000*q**6*r*s**4 + 171371250000*p**7*r**2*s**4 - 1113390625000*p**4*q**2*r**2*s**4 - 1211474609375*p*q**4*r**2*s**4 - 274056250000*p**5*r**3*s**4 + 8285166015625*p**2*q**2*r**3*s**4 - 2079375000000*p**3*r**4*s**4 + 5137304687500*q**2*r**4*s**4 + 6187500000000*p*r**5*s**4 - 135675000000*p**7*q*s**5 - 1275244140625*p**4*q**3*s**5 - 28388671875*p*q**5*s**5 + 1015166015625*p**5*q*r*s**5 - 10584423828125*p**2*q**3*r*s**5 + 3559570312500*p**3*q*r**2*s**5 - 6929931640625*q**3*r**2*s**5 - 32304687500000*p*q*r**3*s**5 + 430576171875*p**6*s**6 + 9397949218750*p**3*q**2*s**6 + 575195312500*q**4*s**6 - 4086425781250*p**4*r*s**6 + 42183837890625*p*q**2*r*s**6 + 8156494140625*p**2*r**2*s**6 + 12612304687500*r**3*s**6 - 25513916015625*p**2*q*s**7 - 37017822265625*q*r*s**7 + 18981933593750*p*s**8 + + o[2] = 1600*p**10*q**6 + 9200*p**7*q**8 - 126000*p**4*q**10 - 777600*p*q**12 - 14400*p**11*q**4*r - 119300*p**8*q**6*r + 1203225*p**5*q**8*r + 9412200*p**2*q**10*r + 32400*p**12*q**2*r**2 + 417950*p**9*q**4*r**2 - 4543725*p**6*q**6*r**2 - 49008125*p**3*q**8*r**2 - 24192000*q**10*r**2 - 292050*p**10*q**2*r**3 + 8760000*p**7*q**4*r**3 + 137506625*p**4*q**6*r**3 + 225438750*p*q**8*r**3 - 4213250*p**8*q**2*r**4 - 173595625*p**5*q**4*r**4 - 653003125*p**2*q**6*r**4 + 82575000*p**6*q**2*r**5 + 838125000*p**3*q**4*r**5 + 578562500*q**6*r**5 - 421500000*p**4*q**2*r**6 - 1796250000*p*q**4*r**6 + 1050000000*p**2*q**2*r**7 + 43200*p**12*q**3*s + 807300*p**9*q**5*s + 5328225*p**6*q**7*s + 16946250*p**3*q**9*s + 29565000*q**11*s - 194400*p**13*q*r*s - 5505300*p**10*q**3*r*s - 49886700*p**7*q**5*r*s - 178821875*p**4*q**7*r*s - 222750000*p*q**9*r*s + 6814800*p**11*q*r**2*s + 120525625*p**8*q**3*r**2*s + 526694500*p**5*q**5*r**2*s + 84065625*p**2*q**7*r**2*s - 123670500*p**9*q*r**3*s - 1106731875*p**6*q**3*r**3*s - 669556250*p**3*q**5*r**3*s - 2869265625*q**7*r**3*s + 1004350000*p**7*q*r**4*s + 3384375000*p**4*q**3*r**4*s + 5665625000*p*q**5*r**4*s - 3411000000*p**5*q*r**5*s - 418750000*p**2*q**3*r**5*s + 1700000000*p**3*q*r**6*s - 10500000000*q**3*r**6*s + 291600*p**14*s**2 + 9829350*p**11*q**2*s**2 + 114151875*p**8*q**4*s**2 + 522169375*p**5*q**6*s**2 + 716906250*p**2*q**8*s**2 - 18625950*p**12*r*s**2 - 387703125*p**9*q**2*r*s**2 - 2056109375*p**6*q**4*r*s**2 - 760203125*p**3*q**6*r*s**2 + 3071250000*q**8*r*s**2 + 512419500*p**10*r**2*s**2 + 5859053125*p**7*q**2*r**2*s**2 + 12154062500*p**4*q**4*r**2*s**2 + 15931640625*p*q**6*r**2*s**2 - 6598393750*p**8*r**3*s**2 - 43549625000*p**5*q**2*r**3*s**2 - 82011328125*p**2*q**4*r**3*s**2 + 43538125000*p**6*r**4*s**2 + 160831250000*p**3*q**2*r**4*s**2 + 99070312500*q**4*r**4*s**2 - 141812500000*p**4*r**5*s**2 - 117500000000*p*q**2*r**5*s**2 + 183750000000*p**2*r**6*s**2 - 154608750*p**10*q*s**3 - 3309468750*p**7*q**3*s**3 - 20834140625*p**4*q**5*s**3 - 34731562500*p*q**7*s**3 + 5970375000*p**8*q*r*s**3 + 68533281250*p**5*q**3*r*s**3 + 142698281250*p**2*q**5*r*s**3 - 74509140625*p**6*q*r**2*s**3 - 389148437500*p**3*q**3*r**2*s**3 - 270937890625*q**5*r**2*s**3 + 366696875000*p**4*q*r**3*s**3 + 400031250000*p*q**3*r**3*s**3 - 735156250000*p**2*q*r**4*s**3 - 262500000000*q*r**5*s**3 + 371250000*p**9*s**4 + 21315000000*p**6*q**2*s**4 + 179515625000*p**3*q**4*s**4 + 238406250000*q**6*s**4 - 9071015625*p**7*r*s**4 - 268945312500*p**4*q**2*r*s**4 - 379785156250*p*q**4*r*s**4 + 140262890625*p**5*r**2*s**4 + 1486259765625*p**2*q**2*r**2*s**4 - 806484375000*p**3*r**3*s**4 + 1066210937500*q**2*r**3*s**4 + 1722656250000*p*r**4*s**4 - 125648437500*p**5*q*s**5 - 1236279296875*p**2*q**3*s**5 + 1267871093750*p**3*q*r*s**5 - 1044677734375*q**3*r*s**5 - 6630859375000*p*q*r**2*s**5 + 160888671875*p**4*s**6 + 6352294921875*p*q**2*s**6 - 708740234375*p**2*r*s**6 + 3901367187500*r**2*s**6 - 8050537109375*q*s**7 + + o[1] = 2800*p**8*q**6 + 41300*p**5*q**8 + 151200*p**2*q**10 - 25200*p**9*q**4*r - 542600*p**6*q**6*r - 3397875*p**3*q**8*r - 5751000*q**10*r + 56700*p**10*q**2*r**2 + 1972125*p**7*q**4*r**2 + 18624250*p**4*q**6*r**2 + 50253750*p*q**8*r**2 - 1701000*p**8*q**2*r**3 - 32630625*p**5*q**4*r**3 - 139868750*p**2*q**6*r**3 + 18162500*p**6*q**2*r**4 + 177125000*p**3*q**4*r**4 + 121734375*q**6*r**4 - 100500000*p**4*q**2*r**5 - 386250000*p*q**4*r**5 + 225000000*p**2*q**2*r**6 + 75600*p**10*q**3*s + 1708800*p**7*q**5*s + 12836875*p**4*q**7*s + 32062500*p*q**9*s - 340200*p**11*q*r*s - 10185750*p**8*q**3*r*s - 97502750*p**5*q**5*r*s - 301640625*p**2*q**7*r*s + 7168500*p**9*q*r**2*s + 135960625*p**6*q**3*r**2*s + 587471875*p**3*q**5*r**2*s - 384750000*q**7*r**2*s - 29325000*p**7*q*r**3*s - 320625000*p**4*q**3*r**3*s + 523437500*p*q**5*r**3*s - 42000000*p**5*q*r**4*s + 343750000*p**2*q**3*r**4*s + 150000000*p**3*q*r**5*s - 2250000000*q**3*r**5*s + 510300*p**12*s**2 + 12808125*p**9*q**2*s**2 + 107062500*p**6*q**4*s**2 + 270312500*p**3*q**6*s**2 - 168750000*q**8*s**2 - 2551500*p**10*r*s**2 - 5062500*p**7*q**2*r*s**2 + 712343750*p**4*q**4*r*s**2 + 4788281250*p*q**6*r*s**2 - 256837500*p**8*r**2*s**2 - 3574812500*p**5*q**2*r**2*s**2 - 14967968750*p**2*q**4*r**2*s**2 + 4040937500*p**6*r**3*s**2 + 26400000000*p**3*q**2*r**3*s**2 + 17083984375*q**4*r**3*s**2 - 21812500000*p**4*r**4*s**2 - 24375000000*p*q**2*r**4*s**2 + 39375000000*p**2*r**5*s**2 - 127265625*p**5*q**3*s**3 - 680234375*p**2*q**5*s**3 - 2048203125*p**6*q*r*s**3 - 18794531250*p**3*q**3*r*s**3 - 25050000000*q**5*r*s**3 + 26621875000*p**4*q*r**2*s**3 + 37007812500*p*q**3*r**2*s**3 - 105468750000*p**2*q*r**3*s**3 - 56250000000*q*r**4*s**3 + 1124296875*p**7*s**4 + 9251953125*p**4*q**2*s**4 - 8007812500*p*q**4*s**4 - 4004296875*p**5*r*s**4 + 179931640625*p**2*q**2*r*s**4 - 75703125000*p**3*r**2*s**4 + 133447265625*q**2*r**2*s**4 + 363281250000*p*r**3*s**4 - 91552734375*p**3*q*s**5 - 19531250000*q**3*s**5 - 751953125000*p*q*r*s**5 + 157958984375*p**2*s**6 + 748291015625*r*s**6 + + o[0] = -14400*p**6*q**6 - 212400*p**3*q**8 - 777600*q**10 + 92100*p**7*q**4*r + 1689675*p**4*q**6*r + 7371000*p*q**8*r - 122850*p**8*q**2*r**2 - 3735250*p**5*q**4*r**2 - 22432500*p**2*q**6*r**2 + 2298750*p**6*q**2*r**3 + 29390625*p**3*q**4*r**3 + 18000000*q**6*r**3 - 17750000*p**4*q**2*r**4 - 62812500*p*q**4*r**4 + 37500000*p**2*q**2*r**5 - 51300*p**8*q**3*s - 768025*p**5*q**5*s - 2801250*p**2*q**7*s - 275400*p**9*q*r*s - 5479875*p**6*q**3*r*s - 35538750*p**3*q**5*r*s - 68850000*q**7*r*s + 12757500*p**7*q*r**2*s + 133640625*p**4*q**3*r**2*s + 222609375*p*q**5*r**2*s - 108500000*p**5*q*r**3*s - 290312500*p**2*q**3*r**3*s + 275000000*p**3*q*r**4*s - 375000000*q**3*r**4*s + 1931850*p**10*s**2 + 40213125*p**7*q**2*s**2 + 253921875*p**4*q**4*s**2 + 464062500*p*q**6*s**2 - 71077500*p**8*r*s**2 - 818746875*p**5*q**2*r*s**2 - 1882265625*p**2*q**4*r*s**2 + 826031250*p**6*r**2*s**2 + 4369687500*p**3*q**2*r**2*s**2 + 3107812500*q**4*r**2*s**2 - 3943750000*p**4*r**3*s**2 - 5000000000*p*q**2*r**3*s**2 + 6562500000*p**2*r**4*s**2 - 295312500*p**6*q*s**3 - 2938906250*p**3*q**3*s**3 - 4848750000*q**5*s**3 + 3791484375*p**4*q*r*s**3 + 7556250000*p*q**3*r*s**3 - 11960937500*p**2*q*r**2*s**3 - 9375000000*q*r**3*s**3 + 1668515625*p**5*s**4 + 20447265625*p**2*q**2*s**4 - 21955078125*p**3*r*s**4 + 18984375000*q**2*r*s**4 + 67382812500*p*r**2*s**4 - 120849609375*p*q*s**5 + 157226562500*s**6 + + return o + + @property + def a(self): + p, q, r, s = self.p, self.q, self.r, self.s + a = [0]*6 + + a[5] = -100*p**7*q**7 - 2175*p**4*q**9 - 10500*p*q**11 + 1100*p**8*q**5*r + 27975*p**5*q**7*r + 152950*p**2*q**9*r - 4125*p**9*q**3*r**2 - 128875*p**6*q**5*r**2 - 830525*p**3*q**7*r**2 + 59450*q**9*r**2 + 5400*p**10*q*r**3 + 243800*p**7*q**3*r**3 + 2082650*p**4*q**5*r**3 - 333925*p*q**7*r**3 - 139200*p**8*q*r**4 - 2406000*p**5*q**3*r**4 - 122600*p**2*q**5*r**4 + 1254400*p**6*q*r**5 + 3776000*p**3*q**3*r**5 + 1832000*q**5*r**5 - 4736000*p**4*q*r**6 - 6720000*p*q**3*r**6 + 6400000*p**2*q*r**7 - 900*p**9*q**4*s - 37400*p**6*q**6*s - 281625*p**3*q**8*s - 435000*q**10*s + 6750*p**10*q**2*r*s + 322300*p**7*q**4*r*s + 2718575*p**4*q**6*r*s + 4214250*p*q**8*r*s - 16200*p**11*r**2*s - 859275*p**8*q**2*r**2*s - 8925475*p**5*q**4*r**2*s - 14427875*p**2*q**6*r**2*s + 453600*p**9*r**3*s + 10038400*p**6*q**2*r**3*s + 17397500*p**3*q**4*r**3*s - 11333125*q**6*r**3*s - 4451200*p**7*r**4*s - 15850000*p**4*q**2*r**4*s + 34000000*p*q**4*r**4*s + 17984000*p**5*r**5*s - 10000000*p**2*q**2*r**5*s - 25600000*p**3*r**6*s - 8000000*q**2*r**6*s + 6075*p**11*q*s**2 - 83250*p**8*q**3*s**2 - 1282500*p**5*q**5*s**2 - 2862500*p**2*q**7*s**2 + 724275*p**9*q*r*s**2 + 9807250*p**6*q**3*r*s**2 + 28374375*p**3*q**5*r*s**2 + 22212500*q**7*r*s**2 - 8982000*p**7*q*r**2*s**2 - 39600000*p**4*q**3*r**2*s**2 - 61746875*p*q**5*r**2*s**2 - 1010000*p**5*q*r**3*s**2 - 1000000*p**2*q**3*r**3*s**2 + 78000000*p**3*q*r**4*s**2 + 30000000*q**3*r**4*s**2 + 80000000*p*q*r**5*s**2 - 759375*p**10*s**3 - 9787500*p**7*q**2*s**3 - 39062500*p**4*q**4*s**3 - 52343750*p*q**6*s**3 + 12301875*p**8*r*s**3 + 98175000*p**5*q**2*r*s**3 + 225078125*p**2*q**4*r*s**3 - 54900000*p**6*r**2*s**3 - 310000000*p**3*q**2*r**2*s**3 - 7890625*q**4*r**2*s**3 + 51250000*p**4*r**3*s**3 - 420000000*p*q**2*r**3*s**3 + 110000000*p**2*r**4*s**3 - 200000000*r**5*s**3 + 2109375*p**6*q*s**4 - 21093750*p**3*q**3*s**4 - 89843750*q**5*s**4 + 182343750*p**4*q*r*s**4 + 733203125*p*q**3*r*s**4 - 196875000*p**2*q*r**2*s**4 + 1125000000*q*r**3*s**4 - 158203125*p**5*s**5 - 566406250*p**2*q**2*s**5 + 101562500*p**3*r*s**5 - 1669921875*q**2*r*s**5 + 1250000000*p*r**2*s**5 - 1220703125*p*q*s**6 + 6103515625*s**7 + + a[4] = 1000*p**5*q**7 + 7250*p**2*q**9 - 10800*p**6*q**5*r - 96900*p**3*q**7*r - 52500*q**9*r + 37400*p**7*q**3*r**2 + 470850*p**4*q**5*r**2 + 640600*p*q**7*r**2 - 39600*p**8*q*r**3 - 983600*p**5*q**3*r**3 - 2848100*p**2*q**5*r**3 + 814400*p**6*q*r**4 + 6076000*p**3*q**3*r**4 + 2308000*q**5*r**4 - 5024000*p**4*q*r**5 - 9680000*p*q**3*r**5 + 9600000*p**2*q*r**6 + 13800*p**7*q**4*s + 94650*p**4*q**6*s - 26500*p*q**8*s - 86400*p**8*q**2*r*s - 816500*p**5*q**4*r*s - 257500*p**2*q**6*r*s + 91800*p**9*r**2*s + 1853700*p**6*q**2*r**2*s + 630000*p**3*q**4*r**2*s - 8971250*q**6*r**2*s - 2071200*p**7*r**3*s - 7240000*p**4*q**2*r**3*s + 29375000*p*q**4*r**3*s + 14416000*p**5*r**4*s - 5200000*p**2*q**2*r**4*s - 30400000*p**3*r**5*s - 12000000*q**2*r**5*s + 64800*p**9*q*s**2 + 567000*p**6*q**3*s**2 + 1655000*p**3*q**5*s**2 + 6987500*q**7*s**2 + 337500*p**7*q*r*s**2 + 8462500*p**4*q**3*r*s**2 - 5812500*p*q**5*r*s**2 - 24930000*p**5*q*r**2*s**2 - 69125000*p**2*q**3*r**2*s**2 + 103500000*p**3*q*r**3*s**2 + 30000000*q**3*r**3*s**2 + 90000000*p*q*r**4*s**2 - 708750*p**8*s**3 - 5400000*p**5*q**2*s**3 + 8906250*p**2*q**4*s**3 + 18562500*p**6*r*s**3 - 625000*p**3*q**2*r*s**3 + 29687500*q**4*r*s**3 - 75000000*p**4*r**2*s**3 - 416250000*p*q**2*r**2*s**3 + 60000000*p**2*r**3*s**3 - 300000000*r**4*s**3 + 71718750*p**4*q*s**4 + 189062500*p*q**3*s**4 + 210937500*p**2*q*r*s**4 + 1187500000*q*r**2*s**4 - 187500000*p**3*s**5 - 800781250*q**2*s**5 - 390625000*p*r*s**5 + + a[3] = -500*p**6*q**5 - 6350*p**3*q**7 - 19800*q**9 + 3750*p**7*q**3*r + 65100*p**4*q**5*r + 264950*p*q**7*r - 6750*p**8*q*r**2 - 209050*p**5*q**3*r**2 - 1217250*p**2*q**5*r**2 + 219000*p**6*q*r**3 + 2510000*p**3*q**3*r**3 + 1098500*q**5*r**3 - 2068000*p**4*q*r**4 - 5060000*p*q**3*r**4 + 5200000*p**2*q*r**5 - 6750*p**8*q**2*s - 96350*p**5*q**4*s - 346000*p**2*q**6*s + 20250*p**9*r*s + 459900*p**6*q**2*r*s + 1828750*p**3*q**4*r*s - 2930000*q**6*r*s - 594000*p**7*r**2*s - 4301250*p**4*q**2*r**2*s + 10906250*p*q**4*r**2*s + 5252000*p**5*r**3*s - 1450000*p**2*q**2*r**3*s - 12800000*p**3*r**4*s - 6500000*q**2*r**4*s + 74250*p**7*q*s**2 + 1418750*p**4*q**3*s**2 + 5956250*p*q**5*s**2 - 4297500*p**5*q*r*s**2 - 29906250*p**2*q**3*r*s**2 + 31500000*p**3*q*r**2*s**2 + 12500000*q**3*r**2*s**2 + 35000000*p*q*r**3*s**2 + 1350000*p**6*s**3 + 6093750*p**3*q**2*s**3 + 17500000*q**4*s**3 - 7031250*p**4*r*s**3 - 127812500*p*q**2*r*s**3 + 18750000*p**2*r**2*s**3 - 162500000*r**3*s**3 + 107812500*p**2*q*s**4 + 460937500*q*r*s**4 - 214843750*p*s**5 + + a[2] = 1950*p**4*q**5 + 14100*p*q**7 - 14350*p**5*q**3*r - 125600*p**2*q**5*r + 27900*p**6*q*r**2 + 402250*p**3*q**3*r**2 + 288250*q**5*r**2 - 436000*p**4*q*r**3 - 1345000*p*q**3*r**3 + 1400000*p**2*q*r**4 + 9450*p**6*q**2*s - 1250*p**3*q**4*s - 465000*q**6*s - 49950*p**7*r*s - 302500*p**4*q**2*r*s + 1718750*p*q**4*r*s + 834000*p**5*r**2*s + 437500*p**2*q**2*r**2*s - 3100000*p**3*r**3*s - 1750000*q**2*r**3*s - 292500*p**5*q*s**2 - 1937500*p**2*q**3*s**2 + 3343750*p**3*q*r*s**2 + 1875000*q**3*r*s**2 + 8125000*p*q*r**2*s**2 - 1406250*p**4*s**3 - 12343750*p*q**2*s**3 + 5312500*p**2*r*s**3 - 43750000*r**2*s**3 + 74218750*q*s**4 + + a[1] = -300*p**5*q**3 - 2150*p**2*q**5 + 1350*p**6*q*r + 21500*p**3*q**3*r + 61500*q**5*r - 42000*p**4*q*r**2 - 290000*p*q**3*r**2 + 300000*p**2*q*r**3 - 4050*p**7*s - 45000*p**4*q**2*s - 125000*p*q**4*s + 108000*p**5*r*s + 643750*p**2*q**2*r*s - 700000*p**3*r**2*s - 375000*q**2*r**2*s - 93750*p**3*q*s**2 - 312500*q**3*s**2 + 1875000*p*q*r*s**2 - 1406250*p**2*s**3 - 9375000*r*s**3 + + a[0] = 1250*p**3*q**3 + 9000*q**5 - 4500*p**4*q*r - 46250*p*q**3*r + 50000*p**2*q*r**2 + 6750*p**5*s + 43750*p**2*q**2*s - 75000*p**3*r*s - 62500*q**2*r*s + 156250*p*q*s**2 - 1562500*s**3 + + return a + + @property + def c(self): + p, q, r, s = self.p, self.q, self.r, self.s + c = [0]*6 + + c[5] = -40*p**5*q**11 - 270*p**2*q**13 + 700*p**6*q**9*r + 5165*p**3*q**11*r + 540*q**13*r - 4230*p**7*q**7*r**2 - 31845*p**4*q**9*r**2 + 20880*p*q**11*r**2 + 9645*p**8*q**5*r**3 + 57615*p**5*q**7*r**3 - 358255*p**2*q**9*r**3 - 1880*p**9*q**3*r**4 + 114020*p**6*q**5*r**4 + 2012190*p**3*q**7*r**4 - 26855*q**9*r**4 - 14400*p**10*q*r**5 - 470400*p**7*q**3*r**5 - 5088640*p**4*q**5*r**5 + 920*p*q**7*r**5 + 332800*p**8*q*r**6 + 5797120*p**5*q**3*r**6 + 1608000*p**2*q**5*r**6 - 2611200*p**6*q*r**7 - 7424000*p**3*q**3*r**7 - 2323200*q**5*r**7 + 8601600*p**4*q*r**8 + 9472000*p*q**3*r**8 - 10240000*p**2*q*r**9 - 3060*p**7*q**8*s - 39085*p**4*q**10*s - 132300*p*q**12*s + 36580*p**8*q**6*r*s + 520185*p**5*q**8*r*s + 1969860*p**2*q**10*r*s - 144045*p**9*q**4*r**2*s - 2438425*p**6*q**6*r**2*s - 10809475*p**3*q**8*r**2*s + 518850*q**10*r**2*s + 182520*p**10*q**2*r**3*s + 4533930*p**7*q**4*r**3*s + 26196770*p**4*q**6*r**3*s - 4542325*p*q**8*r**3*s + 21600*p**11*r**4*s - 2208080*p**8*q**2*r**4*s - 24787960*p**5*q**4*r**4*s + 10813900*p**2*q**6*r**4*s - 499200*p**9*r**5*s + 3827840*p**6*q**2*r**5*s + 9596000*p**3*q**4*r**5*s + 22662000*q**6*r**5*s + 3916800*p**7*r**6*s - 29952000*p**4*q**2*r**6*s - 90800000*p*q**4*r**6*s - 12902400*p**5*r**7*s + 87040000*p**2*q**2*r**7*s + 15360000*p**3*r**8*s + 12800000*q**2*r**8*s - 38070*p**9*q**5*s**2 - 566700*p**6*q**7*s**2 - 2574375*p**3*q**9*s**2 - 1822500*q**11*s**2 + 292815*p**10*q**3*r*s**2 + 5170280*p**7*q**5*r*s**2 + 27918125*p**4*q**7*r*s**2 + 21997500*p*q**9*r*s**2 - 573480*p**11*q*r**2*s**2 - 14566350*p**8*q**3*r**2*s**2 - 104851575*p**5*q**5*r**2*s**2 - 96448750*p**2*q**7*r**2*s**2 + 11001240*p**9*q*r**3*s**2 + 147798600*p**6*q**3*r**3*s**2 + 158632750*p**3*q**5*r**3*s**2 - 78222500*q**7*r**3*s**2 - 62819200*p**7*q*r**4*s**2 - 136160000*p**4*q**3*r**4*s**2 + 317555000*p*q**5*r**4*s**2 + 160224000*p**5*q*r**5*s**2 - 267600000*p**2*q**3*r**5*s**2 - 153600000*p**3*q*r**6*s**2 - 120000000*q**3*r**6*s**2 - 32000000*p*q*r**7*s**2 - 127575*p**11*q**2*s**3 - 2148750*p**8*q**4*s**3 - 13652500*p**5*q**6*s**3 - 19531250*p**2*q**8*s**3 + 495720*p**12*r*s**3 + 11856375*p**9*q**2*r*s**3 + 107807500*p**6*q**4*r*s**3 + 222334375*p**3*q**6*r*s**3 + 105062500*q**8*r*s**3 - 11566800*p**10*r**2*s**3 - 216787500*p**7*q**2*r**2*s**3 - 633437500*p**4*q**4*r**2*s**3 - 504484375*p*q**6*r**2*s**3 + 90918000*p**8*r**3*s**3 + 567080000*p**5*q**2*r**3*s**3 + 692937500*p**2*q**4*r**3*s**3 - 326640000*p**6*r**4*s**3 - 339000000*p**3*q**2*r**4*s**3 + 369250000*q**4*r**4*s**3 + 560000000*p**4*r**5*s**3 + 508000000*p*q**2*r**5*s**3 - 480000000*p**2*r**6*s**3 + 320000000*r**7*s**3 - 455625*p**10*q*s**4 - 27562500*p**7*q**3*s**4 - 120593750*p**4*q**5*s**4 - 60312500*p*q**7*s**4 + 110615625*p**8*q*r*s**4 + 662984375*p**5*q**3*r*s**4 + 528515625*p**2*q**5*r*s**4 - 541687500*p**6*q*r**2*s**4 - 1262343750*p**3*q**3*r**2*s**4 - 466406250*q**5*r**2*s**4 + 633000000*p**4*q*r**3*s**4 - 1264375000*p*q**3*r**3*s**4 + 1085000000*p**2*q*r**4*s**4 - 2700000000*q*r**5*s**4 - 68343750*p**9*s**5 - 478828125*p**6*q**2*s**5 - 355468750*p**3*q**4*s**5 - 11718750*q**6*s**5 + 718031250*p**7*r*s**5 + 1658593750*p**4*q**2*r*s**5 + 2212890625*p*q**4*r*s**5 - 2855625000*p**5*r**2*s**5 - 4273437500*p**2*q**2*r**2*s**5 + 4537500000*p**3*r**3*s**5 + 8031250000*q**2*r**3*s**5 - 1750000000*p*r**4*s**5 + 1353515625*p**5*q*s**6 + 1562500000*p**2*q**3*s**6 - 3964843750*p**3*q*r*s**6 - 7226562500*q**3*r*s**6 + 1953125000*p*q*r**2*s**6 - 1757812500*p**4*s**7 - 3173828125*p*q**2*s**7 + 6445312500*p**2*r*s**7 - 3906250000*r**2*s**7 + 6103515625*q*s**8 + + c[4] = 40*p**6*q**9 + 110*p**3*q**11 - 1080*q**13 - 560*p**7*q**7*r - 1780*p**4*q**9*r + 17370*p*q**11*r + 2850*p**8*q**5*r**2 + 10520*p**5*q**7*r**2 - 115910*p**2*q**9*r**2 - 6090*p**9*q**3*r**3 - 25330*p**6*q**5*r**3 + 448740*p**3*q**7*r**3 + 128230*q**9*r**3 + 4320*p**10*q*r**4 + 16960*p**7*q**3*r**4 - 1143600*p**4*q**5*r**4 - 1410310*p*q**7*r**4 + 3840*p**8*q*r**5 + 1744480*p**5*q**3*r**5 + 5619520*p**2*q**5*r**5 - 1198080*p**6*q*r**6 - 10579200*p**3*q**3*r**6 - 2940800*q**5*r**6 + 8294400*p**4*q*r**7 + 13568000*p*q**3*r**7 - 15360000*p**2*q*r**8 + 840*p**8*q**6*s + 7580*p**5*q**8*s + 24420*p**2*q**10*s - 8100*p**9*q**4*r*s - 94100*p**6*q**6*r*s - 473000*p**3*q**8*r*s - 473400*q**10*r*s + 22680*p**10*q**2*r**2*s + 374370*p**7*q**4*r**2*s + 2888020*p**4*q**6*r**2*s + 5561050*p*q**8*r**2*s - 12960*p**11*r**3*s - 485820*p**8*q**2*r**3*s - 6723440*p**5*q**4*r**3*s - 23561400*p**2*q**6*r**3*s + 190080*p**9*r**4*s + 5894880*p**6*q**2*r**4*s + 50882000*p**3*q**4*r**4*s + 22411500*q**6*r**4*s - 258560*p**7*r**5*s - 46248000*p**4*q**2*r**5*s - 103800000*p*q**4*r**5*s - 3737600*p**5*r**6*s + 119680000*p**2*q**2*r**6*s + 10240000*p**3*r**7*s + 19200000*q**2*r**7*s + 7290*p**10*q**3*s**2 + 117360*p**7*q**5*s**2 + 691250*p**4*q**7*s**2 - 198750*p*q**9*s**2 - 36450*p**11*q*r*s**2 - 854550*p**8*q**3*r*s**2 - 7340700*p**5*q**5*r*s**2 - 2028750*p**2*q**7*r*s**2 + 995490*p**9*q*r**2*s**2 + 18896600*p**6*q**3*r**2*s**2 + 5026500*p**3*q**5*r**2*s**2 - 52272500*q**7*r**2*s**2 - 16636800*p**7*q*r**3*s**2 - 43200000*p**4*q**3*r**3*s**2 + 223426250*p*q**5*r**3*s**2 + 112068000*p**5*q*r**4*s**2 - 177000000*p**2*q**3*r**4*s**2 - 244000000*p**3*q*r**5*s**2 - 156000000*q**3*r**5*s**2 + 43740*p**12*s**3 + 1032750*p**9*q**2*s**3 + 8602500*p**6*q**4*s**3 + 15606250*p**3*q**6*s**3 + 39625000*q**8*s**3 - 1603800*p**10*r*s**3 - 26932500*p**7*q**2*r*s**3 - 19562500*p**4*q**4*r*s**3 - 152000000*p*q**6*r*s**3 + 25555500*p**8*r**2*s**3 + 16230000*p**5*q**2*r**2*s**3 + 42187500*p**2*q**4*r**2*s**3 - 165660000*p**6*r**3*s**3 + 373500000*p**3*q**2*r**3*s**3 + 332937500*q**4*r**3*s**3 + 465000000*p**4*r**4*s**3 + 586000000*p*q**2*r**4*s**3 - 592000000*p**2*r**5*s**3 + 480000000*r**6*s**3 - 1518750*p**8*q*s**4 - 62531250*p**5*q**3*s**4 + 7656250*p**2*q**5*s**4 + 184781250*p**6*q*r*s**4 - 15781250*p**3*q**3*r*s**4 - 135156250*q**5*r*s**4 - 1148250000*p**4*q*r**2*s**4 - 2121406250*p*q**3*r**2*s**4 + 1990000000*p**2*q*r**3*s**4 - 3150000000*q*r**4*s**4 - 2531250*p**7*s**5 + 660937500*p**4*q**2*s**5 + 1339843750*p*q**4*s**5 - 33750000*p**5*r*s**5 - 679687500*p**2*q**2*r*s**5 + 6250000*p**3*r**2*s**5 + 6195312500*q**2*r**2*s**5 + 1125000000*p*r**3*s**5 - 996093750*p**3*q*s**6 - 3125000000*q**3*s**6 - 3222656250*p*q*r*s**6 + 1171875000*p**2*s**7 + 976562500*r*s**7 + + c[3] = 80*p**4*q**9 + 540*p*q**11 - 600*p**5*q**7*r - 4770*p**2*q**9*r + 1230*p**6*q**5*r**2 + 20900*p**3*q**7*r**2 + 47250*q**9*r**2 - 710*p**7*q**3*r**3 - 84950*p**4*q**5*r**3 - 526310*p*q**7*r**3 + 720*p**8*q*r**4 + 216280*p**5*q**3*r**4 + 2068020*p**2*q**5*r**4 - 198080*p**6*q*r**5 - 3703200*p**3*q**3*r**5 - 1423600*q**5*r**5 + 2860800*p**4*q*r**6 + 7056000*p*q**3*r**6 - 8320000*p**2*q*r**7 - 2720*p**6*q**6*s - 46350*p**3*q**8*s - 178200*q**10*s + 25740*p**7*q**4*r*s + 489490*p**4*q**6*r*s + 2152350*p*q**8*r*s - 61560*p**8*q**2*r**2*s - 1568150*p**5*q**4*r**2*s - 9060500*p**2*q**6*r**2*s + 24840*p**9*r**3*s + 1692380*p**6*q**2*r**3*s + 18098250*p**3*q**4*r**3*s + 9387750*q**6*r**3*s - 382560*p**7*r**4*s - 16818000*p**4*q**2*r**4*s - 49325000*p*q**4*r**4*s + 1212800*p**5*r**5*s + 64840000*p**2*q**2*r**5*s - 320000*p**3*r**6*s + 10400000*q**2*r**6*s - 36450*p**8*q**3*s**2 - 588350*p**5*q**5*s**2 - 2156250*p**2*q**7*s**2 + 123930*p**9*q*r*s**2 + 2879700*p**6*q**3*r*s**2 + 12548000*p**3*q**5*r*s**2 - 14445000*q**7*r*s**2 - 3233250*p**7*q*r**2*s**2 - 28485000*p**4*q**3*r**2*s**2 + 72231250*p*q**5*r**2*s**2 + 32093000*p**5*q*r**3*s**2 - 61275000*p**2*q**3*r**3*s**2 - 107500000*p**3*q*r**4*s**2 - 78500000*q**3*r**4*s**2 + 22000000*p*q*r**5*s**2 - 72900*p**10*s**3 - 1215000*p**7*q**2*s**3 - 2937500*p**4*q**4*s**3 + 9156250*p*q**6*s**3 + 2612250*p**8*r*s**3 + 16560000*p**5*q**2*r*s**3 - 75468750*p**2*q**4*r*s**3 - 32737500*p**6*r**2*s**3 + 169062500*p**3*q**2*r**2*s**3 + 121718750*q**4*r**2*s**3 + 160250000*p**4*r**3*s**3 + 219750000*p*q**2*r**3*s**3 - 317000000*p**2*r**4*s**3 + 260000000*r**5*s**3 + 2531250*p**6*q*s**4 + 22500000*p**3*q**3*s**4 + 39843750*q**5*s**4 - 266343750*p**4*q*r*s**4 - 776406250*p*q**3*r*s**4 + 789062500*p**2*q*r**2*s**4 - 1368750000*q*r**3*s**4 + 67500000*p**5*s**5 + 441406250*p**2*q**2*s**5 - 311718750*p**3*r*s**5 + 1785156250*q**2*r*s**5 + 546875000*p*r**2*s**5 - 1269531250*p*q*s**6 + 488281250*s**7 + + c[2] = 120*p**5*q**7 + 810*p**2*q**9 - 1280*p**6*q**5*r - 9160*p**3*q**7*r + 3780*q**9*r + 4530*p**7*q**3*r**2 + 36640*p**4*q**5*r**2 - 45270*p*q**7*r**2 - 5400*p**8*q*r**3 - 60920*p**5*q**3*r**3 + 200050*p**2*q**5*r**3 + 31200*p**6*q*r**4 - 476000*p**3*q**3*r**4 - 378200*q**5*r**4 + 521600*p**4*q*r**5 + 1872000*p*q**3*r**5 - 2240000*p**2*q*r**6 + 1440*p**7*q**4*s + 15310*p**4*q**6*s + 59400*p*q**8*s - 9180*p**8*q**2*r*s - 115240*p**5*q**4*r*s - 589650*p**2*q**6*r*s + 16200*p**9*r**2*s + 316710*p**6*q**2*r**2*s + 2547750*p**3*q**4*r**2*s + 2178000*q**6*r**2*s - 259200*p**7*r**3*s - 4123000*p**4*q**2*r**3*s - 11700000*p*q**4*r**3*s + 937600*p**5*r**4*s + 16340000*p**2*q**2*r**4*s - 640000*p**3*r**5*s + 2800000*q**2*r**5*s - 2430*p**9*q*s**2 - 54450*p**6*q**3*s**2 - 285500*p**3*q**5*s**2 - 2767500*q**7*s**2 + 43200*p**7*q*r*s**2 - 916250*p**4*q**3*r*s**2 + 14482500*p*q**5*r*s**2 + 4806000*p**5*q*r**2*s**2 - 13212500*p**2*q**3*r**2*s**2 - 25400000*p**3*q*r**3*s**2 - 18750000*q**3*r**3*s**2 + 8000000*p*q*r**4*s**2 + 121500*p**8*s**3 + 2058750*p**5*q**2*s**3 - 6656250*p**2*q**4*s**3 - 6716250*p**6*r*s**3 + 24125000*p**3*q**2*r*s**3 + 23875000*q**4*r*s**3 + 43125000*p**4*r**2*s**3 + 45750000*p*q**2*r**2*s**3 - 87500000*p**2*r**3*s**3 + 70000000*r**4*s**3 - 44437500*p**4*q*s**4 - 107968750*p*q**3*s**4 + 159531250*p**2*q*r*s**4 - 284375000*q*r**2*s**4 + 7031250*p**3*s**5 + 265625000*q**2*s**5 + 31250000*p*r*s**5 + + c[1] = 160*p**3*q**7 + 1080*q**9 - 1080*p**4*q**5*r - 8730*p*q**7*r + 1510*p**5*q**3*r**2 + 20420*p**2*q**5*r**2 + 720*p**6*q*r**3 - 23200*p**3*q**3*r**3 - 79900*q**5*r**3 + 35200*p**4*q*r**4 + 404000*p*q**3*r**4 - 480000*p**2*q*r**5 + 960*p**5*q**4*s + 2850*p**2*q**6*s + 540*p**6*q**2*r*s + 63500*p**3*q**4*r*s + 319500*q**6*r*s - 7560*p**7*r**2*s - 253500*p**4*q**2*r**2*s - 1806250*p*q**4*r**2*s + 91200*p**5*r**3*s + 2600000*p**2*q**2*r**3*s - 80000*p**3*r**4*s + 600000*q**2*r**4*s - 4050*p**7*q*s**2 - 120000*p**4*q**3*s**2 - 273750*p*q**5*s**2 + 425250*p**5*q*r*s**2 + 2325000*p**2*q**3*r*s**2 - 5400000*p**3*q*r**2*s**2 - 2875000*q**3*r**2*s**2 + 1500000*p*q*r**3*s**2 - 303750*p**6*s**3 - 843750*p**3*q**2*s**3 - 812500*q**4*s**3 + 5062500*p**4*r*s**3 + 13312500*p*q**2*r*s**3 - 14500000*p**2*r**2*s**3 + 15000000*r**3*s**3 - 3750000*p**2*q*s**4 - 35937500*q*r*s**4 + 11718750*p*s**5 + + c[0] = 80*p**4*q**5 + 540*p*q**7 - 600*p**5*q**3*r - 4770*p**2*q**5*r + 1080*p**6*q*r**2 + 11200*p**3*q**3*r**2 - 12150*q**5*r**2 - 4800*p**4*q*r**3 + 64000*p*q**3*r**3 - 80000*p**2*q*r**4 + 1080*p**6*q**2*s + 13250*p**3*q**4*s + 54000*q**6*s - 3240*p**7*r*s - 56250*p**4*q**2*r*s - 337500*p*q**4*r*s + 43200*p**5*r**2*s + 560000*p**2*q**2*r**2*s - 80000*p**3*r**3*s + 100000*q**2*r**3*s + 6750*p**5*q*s**2 + 225000*p**2*q**3*s**2 - 900000*p**3*q*r*s**2 - 562500*q**3*r*s**2 + 500000*p*q*r**2*s**2 + 843750*p**4*s**3 + 1937500*p*q**2*s**3 - 3000000*p**2*r*s**3 + 2500000*r**2*s**3 - 5468750*q*s**4 + + return c + + @property + def F(self): + p, q, r, s = self.p, self.q, self.r, self.s + F = 4*p**6*q**6 + 59*p**3*q**8 + 216*q**10 - 36*p**7*q**4*r - 623*p**4*q**6*r - 2610*p*q**8*r + 81*p**8*q**2*r**2 + 2015*p**5*q**4*r**2 + 10825*p**2*q**6*r**2 - 1800*p**6*q**2*r**3 - 17500*p**3*q**4*r**3 + 625*q**6*r**3 + 10000*p**4*q**2*r**4 + 108*p**8*q**3*s + 1584*p**5*q**5*s + 5700*p**2*q**7*s - 486*p**9*q*r*s - 9720*p**6*q**3*r*s - 45050*p**3*q**5*r*s - 9000*q**7*r*s + 10800*p**7*q*r**2*s + 92500*p**4*q**3*r**2*s + 32500*p*q**5*r**2*s - 60000*p**5*q*r**3*s - 50000*p**2*q**3*r**3*s + 729*p**10*s**2 + 12150*p**7*q**2*s**2 + 60000*p**4*q**4*s**2 + 93750*p*q**6*s**2 - 18225*p**8*r*s**2 - 175500*p**5*q**2*r*s**2 - 478125*p**2*q**4*r*s**2 + 135000*p**6*r**2*s**2 + 850000*p**3*q**2*r**2*s**2 + 15625*q**4*r**2*s**2 - 250000*p**4*r**3*s**2 + 225000*p**3*q**3*s**3 + 175000*q**5*s**3 - 1012500*p**4*q*r*s**3 - 1187500*p*q**3*r*s**3 + 1250000*p**2*q*r**2*s**3 + 928125*p**5*s**4 + 1875000*p**2*q**2*s**4 - 2812500*p**3*r*s**4 - 390625*q**2*r*s**4 - 9765625*s**6 + return F + + def l0(self, theta): + p, q, r, s, F = self.p, self.q, self.r, self.s, self.F + a = self.a + l0 = Poly(a, x).eval(theta)/F + return l0 + + def T(self, theta, d): + p, q, r, s, F = self.p, self.q, self.r, self.s, self.F + T = [0]*5 + b = self.b + # Note that the order of sublists of the b's has been reversed compared to the paper + T[1] = -Poly(b[1], x).eval(theta)/(2*F) + T[2] = Poly(b[2], x).eval(theta)/(2*d*F) + T[3] = Poly(b[3], x).eval(theta)/(2*F) + T[4] = Poly(b[4], x).eval(theta)/(2*d*F) + return T + + def order(self, theta, d): + p, q, r, s, F = self.p, self.q, self.r, self.s, self.F + o = self.o + order = Poly(o, x).eval(theta)/(d*F) + return N(order) + + def uv(self, theta, d): + c = self.c + u = S(-25*self.q/2) + v = Poly(c, x).eval(theta)/(2*d*self.F) + return N(u), N(v) + + @property + def zeta(self): + return [self.zeta1, self.zeta2, self.zeta3, self.zeta4] diff -Nru python3-sympy-0.7.2/sympy/polys/polyroots.py python3-sympy-0.7.3/sympy/polys/polyroots.py --- python3-sympy-0.7.2/sympy/polys/polyroots.py 2012-10-17 03:02:22.000000000 +0000 +++ python3-sympy-0.7.3/sympy/polys/polyroots.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,25 +1,29 @@ """Algorithms for computing symbolic roots of polynomials. """ -from sympy.core.symbol import Dummy -from sympy.core import S, I +import math + +from sympy.core.symbol import Dummy, Symbol, symbols +from sympy.core import S, I, pi +from sympy.core.mul import expand_2arg from sympy.core.sympify import sympify from sympy.core.numbers import Rational, igcd from sympy.ntheory import divisors, isprime, nextprime -from sympy.functions import exp, sqrt +from sympy.functions import exp, sqrt, re, im, Abs, cos, sin -from sympy.polys.polytools import Poly, cancel, factor, gcd_list +from sympy.polys.polytools import Poly, cancel, factor, gcd_list, discriminant from sympy.polys.specialpolys import cyclotomic_poly from sympy.polys.polyerrors import PolynomialError, GeneratorsNeeded, DomainError +from sympy.polys.polyquinticconst import PolyQuintic +from sympy.polys.rationaltools import together -from sympy.simplify import simplify +from sympy.simplify import simplify, powsimp from sympy.utilities import default_sort_key from sympy.core.compatibility import reduce - -import math from functools import reduce + def roots_linear(f): """Returns a list of roots of a linear polynomial.""" r = -f.nth(0)/f.nth(1) @@ -33,6 +37,7 @@ return [r] + def roots_quadratic(f): """Returns a list of roots of a quadratic polynomial.""" a, b, c = f.all_coeffs() @@ -57,7 +62,7 @@ else: R = sqrt(r) - r0 = R + r0 = R r1 = -R else: d = b**2 - 4*a*c @@ -77,14 +82,15 @@ r0 = E + F r1 = E - F - return sorted([r0, r1], key=default_sort_key) + return sorted([expand_2arg(i) for i in (r0, r1)], key=default_sort_key) + def roots_cubic(f): """Returns a list of roots of a cubic polynomial.""" _, a, b, c = f.monic().all_coeffs() if c is S.Zero: - x1, x2 = roots([1,a,b], multiple = True) + x1, x2 = roots([1, a, b], multiple=True) return [x1, S.Zero, x2] p = b - a**2/3 @@ -97,7 +103,13 @@ if q is S.Zero: return [-aon3]*3 else: - u1 = q**Rational(1, 3) + if q.is_real: + if q > 0: + u1 = -q**Rational(1, 3) + else: + u1 = (-q)**Rational(1, 3) + else: + u1 = (-q)**Rational(1, 3) elif q is S.Zero: y1, y2 = roots([1, 0, p], multiple=True) return [tmp - aon3 for tmp in [y1, S.Zero, y2]] @@ -109,6 +121,9 @@ u2 = u1*(-S.Half + coeff) u3 = u1*(-S.Half - coeff) + if p is S.Zero: + return [u1 - aon3, u2 - aon3, u3 - aon3] + soln = [ -u1 + pon3/u1 - aon3, -u2 + pon3/u2 - aon3, @@ -117,6 +132,63 @@ return soln +def _roots_quartic_euler(p, q, r, a): + """ + Descartes-Euler solution of the quartic equation + + Parameters + ========== + + p, q, r: coefficients of ``x**4 + p*x**2 + q*x + r`` + a: shift of the roots + + Notes + ===== + + This is a helper function for ``roots_quartic``. + + Look for solutions of the form :: + + ``x1 = sqrt(R) - sqrt(A + B*sqrt(R))`` + ``x2 = -sqrt(R) - sqrt(A - B*sqrt(R))`` + ``x3 = -sqrt(R) + sqrt(A - B*sqrt(R))`` + ``x4 = sqrt(R) + sqrt(A + B*sqrt(R))`` + + To satisfy the quartic equation one must have + ``p = -2*(R + A); q = -4*B*R; r = (R - A)**2 - B**2*R`` + so that ``R`` must satisfy the Descartes-Euler resolvent equation + ``64*R**3 + 32*p*R**2 + (4*p**2 - 16*r)*R - q**2 = 0`` + + If the resolvent does not have a rational solution, return None; + in that case it is likely that the Ferrari method gives a simpler + solution. + + Examples + ======== + + >>> from sympy import S + >>> from sympy.polys.polyroots import _roots_quartic_euler + >>> p, q, r = -S(64)/5, -S(512)/125, -S(1024)/3125 + >>> _roots_quartic_euler(p, q, r, S(0))[0] + -sqrt(32*sqrt(5)/125 + 16/5) + 4*sqrt(5)/5 + """ + from sympy.solvers import solve + # solve the resolvent equation + x = Symbol('x') + eq = 64*x**3 + 32*p*x**2 + (4*p**2 - 16*r)*x - q**2 + xsols = list(roots(Poly(eq, x), cubics=False).keys()) + xsols = [sol for sol in xsols if sol.is_rational] + if not xsols: + return None + R = max(xsols) + c1 = sqrt(R) + B = -q*c1/(4*R) + A = -R - p/2 + c2 = sqrt(A + B) + c3 = sqrt(A - B) + return [c1 - c2 - a, -c1 - c3 - a, -c1 + c3 - a, c1 + c2 - a] + + def roots_quartic(f): r""" Returns a list of roots of a quartic polynomial. @@ -161,7 +233,7 @@ 4. http://staff.bath.ac.uk/masjhd/JHD-CA.pdf 5. http://www.albmath.org/files/Math_5713.pdf 6. http://www.statemaster.com/encyclopedia/Quartic-equation - + 7. eqworld.ipmnet.ru/en/solutions/ae/ae0108.pdf """ _, a, b, c, d = f.monic().all_coeffs() @@ -187,36 +259,47 @@ f = c + a*(a2/8 - b/2) g = d - a*(a*(3*a2/256 - b/16) + c/4) aon4 = a/4 - ans = [] if f is S.Zero: y1, y2 = [sqrt(tmp) for tmp in - roots([1, e, g], multiple = True)] + roots([1, e, g], multiple=True)] return [tmp - aon4 for tmp in [-y1, -y2, y1, y2]] if g is S.Zero: - y = [S.Zero] + roots([1, 0, e, f], multiple = True) + y = [S.Zero] + roots([1, 0, e, f], multiple=True) return [tmp - aon4 for tmp in y] else: + # Descartes-Euler method, see [7] + sols = _roots_quartic_euler(e, f, g, aon4) + if sols: + return sols + # Ferrari method, see [1, 2] + a2 = a**2 + e = b - 3*a2/8 + f = c + a*(a2/8 - b/2) + g = d - a*(a*(3*a2/256 - b/16) + c/4) p = -e**2/12 - g q = -e**3/108 + e*g/3 - f**2/8 TH = Rational(1, 3) - if p is S.Zero: + if p.is_zero: y = -5*e/6 - q**TH - else: - # with p !=0 then u below is not 0 + elif p.is_number and p.is_comparable: + # with p != 0 then u below is not 0 root = sqrt(q**2/4 + p**3/27) - r = -q/2 + root # or -q/2 - root - u = r**TH # primary root of solve(x**3-r, x) + r = -q/2 + root # or -q/2 - root + u = r**TH # primary root of solve(x**3-r, x) y = -5*e/6 + u - p/u/3 + else: + raise PolynomialError('cannot return general quartic solution') w = sqrt(e + 2*y) arg1 = 3*e + 2*y arg2 = 2*f/w + ans = [] for s in [-1, 1]: root = sqrt(-(arg1 + s*arg2)) for t in [-1, 1]: ans.append((s*w - t*root)/2 - aon4) - return ans + return ans def roots_binomial(f): """Returns a list of roots of a binomial polynomial.""" @@ -236,6 +319,7 @@ return sorted(roots, key=default_sort_key) + def _inv_totient_estimate(m): """ Find ``(L, U)`` such that ``L <= phi^-1(m) <= U``. @@ -280,22 +364,23 @@ return L, U + def roots_cyclotomic(f, factor=False): """Compute roots of cyclotomic polynomials. """ L, U = _inv_totient_estimate(f.degree()) - for n in range(L, U+1): + for n in range(L, U + 1): g = cyclotomic_poly(n, f.gen, polys=True) if f == g: break - else: # pragma: no cover + else: # pragma: no cover raise RuntimeError("failed to find index of a cyclotomic polynomial") roots = [] if not factor: - for k in range(1, n+1): + for k in range(1, n + 1): if igcd(k, n) == 1: roots.append(exp(2*k*S.Pi*I/n).expand(complex=True)) else: @@ -306,39 +391,198 @@ return sorted(roots, key=default_sort_key) -def roots_rational(f): - """Returns a list of rational roots of a polynomial.""" - domain = f.get_domain() - - if domain.is_QQ: - _, f = f.clear_denoms() - elif domain.is_ZZ: - f = f.set_domain('QQ') - else: - return [] - LC_divs = divisors(int(f.LC())) - EC_divs = divisors(int(f.EC())) +def roots_quintic(f): + """ + Calulate exact roots of a solvable quintic + """ + result = [] + coeff_5, coeff_4, p, q, r, s = f.all_coeffs() - if not f.eval(S.Zero): - zeros = [S.Zero] - else: - zeros = [] + # Eqn must be of the form x^5 + px^3 + qx^2 + rx + s + if coeff_4: + return result + + if coeff_5 != 1: + l = [p/coeff_5, q/coeff_5, r/coeff_5, s/coeff_5] + if not all(coeff.is_Rational for coeff in l): + return result + f = Poly(f/coeff_5) + quintic = PolyQuintic(f) - for p in LC_divs: - for q in EC_divs: - zero = Rational(p, q) + # Eqn standardised. Algo for solving starts here + if not f.is_irreducible: + return result - if not f.eval(zero): - zeros.append(zero) + f20 = quintic.f20 + # Check if f20 has linear factors over domain Z + if f20.is_irreducible: + return result - if not f.eval(-zero): - zeros.append(-zero) + # Now, we know that f is solvable + for _factor in f20.factor_list()[1]: + if _factor[0].is_linear: + theta = _factor[0].root(0) + break + d = discriminant(f) + delta = sqrt(d) + # zeta = a fifth root of unity + zeta1, zeta2, zeta3, zeta4 = quintic.zeta + T = quintic.T(theta, d) + tol = S(1e-10) + alpha = T[1] + T[2]*delta + alpha_bar = T[1] - T[2]*delta + beta = T[3] + T[4]*delta + beta_bar = T[3] - T[4]*delta + + disc = alpha**2 - 4*beta + disc_bar = alpha_bar**2 - 4*beta_bar + + l0 = quintic.l0(theta) + + l1 = _quintic_simplify((-alpha + sqrt(disc)) / S(2)) + l4 = _quintic_simplify((-alpha - sqrt(disc)) / S(2)) + + l2 = _quintic_simplify((-alpha_bar + sqrt(disc_bar)) / S(2)) + l3 = _quintic_simplify((-alpha_bar - sqrt(disc_bar)) / S(2)) + + order = quintic.order(theta, d) + test = (order*delta.n()) - ( (l1.n() - l4.n())*(l2.n() - l3.n()) ) + # Comparing floats + # Problems importing on top + from sympy.utilities.randtest import comp + if not comp(test, 0, tol): + l2, l3 = l3, l2 + + # Now we have correct order of l's + R1 = l0 + l1*zeta1 + l2*zeta2 + l3*zeta3 + l4*zeta4 + R2 = l0 + l3*zeta1 + l1*zeta2 + l4*zeta3 + l2*zeta4 + R3 = l0 + l2*zeta1 + l4*zeta2 + l1*zeta3 + l3*zeta4 + R4 = l0 + l4*zeta1 + l3*zeta2 + l2*zeta3 + l1*zeta4 + + Res = [None, [None]*5, [None]*5, [None]*5, [None]*5] + Res_n = [None, [None]*5, [None]*5, [None]*5, [None]*5] + sol = Symbol('sol') + + # Simplifying improves performace a lot for exact expressions + R1 = _quintic_simplify(R1) + R2 = _quintic_simplify(R2) + R3 = _quintic_simplify(R3) + R4 = _quintic_simplify(R4) + + # Solve imported here. Causing problems if imported as 'solve' + # and hence the changed name + from sympy.solvers.solvers import solve as _solve + a, b = symbols('a b', cls=Dummy) + _sol = _solve( sol**5 - a - I*b, sol) + for i in range(5): + _sol[i] = factor(_sol[i]) + R1 = R1.as_real_imag() + R2 = R2.as_real_imag() + R3 = R3.as_real_imag() + R4 = R4.as_real_imag() + + for i, root in enumerate(_sol): + Res[1][i] = _quintic_simplify(root.subs({ a: R1[0], b: R1[1] })) + Res[2][i] = _quintic_simplify(root.subs({ a: R2[0], b: R2[1] })) + Res[3][i] = _quintic_simplify(root.subs({ a: R3[0], b: R3[1] })) + Res[4][i] = _quintic_simplify(root.subs({ a: R4[0], b: R4[1] })) + + for i in range(1, 5): + for j in range(5): + Res_n[i][j] = Res[i][j].n() + Res[i][j] = _quintic_simplify(Res[i][j]) + r1 = Res[1][0] + r1_n = Res_n[1][0] + + for i in range(5): + if comp(im(r1_n*Res_n[4][i]), 0, tol): + r4 = Res[4][i] + break + + u, v = quintic.uv(theta, d) + sqrt5 = math.sqrt(5) + + # Now we have various Res values. Each will be a list of five + # values. We have to pick one r value from those five for each Res + u, v = quintic.uv(theta, d) + testplus = (u + v*delta*sqrt(5)).n() + testminus = (u - v*delta*sqrt(5)).n() + + # Evaluated numbers suffixed with _n + # We will use evaluated numbers for calculation. Much faster. + r4_n = r4.n() + r2 = r3 = None + + for i in range(5): + r2temp_n = Res_n[2][i] + for j in range(5): + # Again storing away the exact number and using + # evaluated numbers in computations + r3temp_n = Res_n[3][j] + + if( comp( r1_n*r2temp_n**2 + r4_n*r3temp_n**2 - testplus, 0, tol) and + comp( r3temp_n*r1_n**2 + r2temp_n*r4_n**2 - testminus, 0, tol ) ): + r2 = Res[2][i] + r3 = Res[3][j] + break + if r2: + break + + # Now, we have r's so we can get roots + x1 = (r1 + r2 + r3 + r4)/5 + x2 = (r1*zeta4 + r2*zeta3 + r3*zeta2 + r4*zeta1)/5 + x3 = (r1*zeta3 + r2*zeta1 + r3*zeta4 + r4*zeta2)/5 + x4 = (r1*zeta2 + r2*zeta4 + r3*zeta1 + r4*zeta3)/5 + x5 = (r1*zeta1 + r2*zeta2 + r3*zeta3 + r4*zeta4)/5 + result = [x1, x2, x3, x4, x5] + + # Now check if solutions are distinct + + result_n = [] + for root in result: + result_n.append(root.n(5)) + result_n = sorted(result_n) + + prev_entry = None + for r in result_n: + if r == prev_entry: + # Roots are identical. Abort. Return [] + # and fall back to usual solve + return [] + prev_entry = r + + return result + + +def _quintic_simplify(expr): + expr = powsimp(expr) + expr = cancel(expr) + return together(expr) - return sorted(zeros, key=default_sort_key) def _integer_basis(poly): - """Compute coefficient basis for a polynomial over integers. """ + """Compute coefficient basis for a polynomial over integers. + + Returns the integer ``div`` such that substituting ``x = div*y`` + ``p(x) = m*q(y)`` where the coefficients of ``q`` are smaller + than those of ``p``. + + For example ``x**5 + 512*x + 1024 = 0`` + with ``div = 4`` becomes ``y**5 + 2*y + 1 = 0`` + + Returns the integer ``div`` or ``None`` if there is no possible scaling. + + Examples + ======== + + >>> from sympy.polys import Poly + >>> from sympy.abc import x + >>> from sympy.polys.polyroots import _integer_basis + >>> p = Poly(x**5 + 512*x + 1024, x, domain='ZZ') + >>> _integer_basis(p) + 4 + """ monoms, coeffs = list(zip(*poly.terms())) monoms, = list(zip(*monoms)) @@ -346,6 +590,8 @@ if coeffs[0] < coeffs[-1]: coeffs = list(reversed(coeffs)) + n = monoms[0] + monoms = [n - i for i in reversed(monoms)] else: return None @@ -371,6 +617,7 @@ else: return div + def preprocess_roots(poly): """Try to get rid of symbolic coefficients from ``poly``. """ coeff = S.One @@ -432,13 +679,14 @@ n = poly.degree() def func(k, coeff): - return coeff//basis**(n-k[0]) + return coeff//basis**(n - k[0]) poly = poly.termwise(func) coeff *= basis return coeff, poly + def roots(f, *gens, **flags): """ Computes symbolic roots of a univariate polynomial. @@ -486,11 +734,13 @@ {-1: 1, 1: 1} """ + from sympy.polys.polytools import to_rational_coeffs flags = dict(flags) auto = flags.pop('auto', True) cubics = flags.pop('cubics', True) quartics = flags.pop('quartics', True) + quintics = flags.pop('quintics', False) multiple = flags.pop('multiple', False) filter = flags.pop('filter', None) predicate = flags.pop('predicate', None) @@ -501,10 +751,10 @@ x = Dummy('x') - poly, i = {}, len(f)-1 + poly, i = {}, len(f) - 1 for coeff in f: - poly[i], i = sympify(coeff), i-1 + poly[i], i = sympify(coeff), i - 1 f = Poly(poly, x, field=True) else: @@ -576,6 +826,8 @@ result += roots_cubic(f) elif n == 4 and quartics: result += roots_quartic(f) + elif n == 5 and quintics: + result += roots_quintic(f) return result @@ -584,13 +836,16 @@ if not k: zeros = {} else: - zeros = {S(0) : k} + zeros = {S(0): k} coeff, f = preprocess_roots(f) if auto and f.get_domain().has_Ring: f = f.to_field() + rescale_x = None + translate_x = None + result = {} if not f.is_ground: @@ -609,8 +864,20 @@ _, factors = Poly(f.as_expr()).factor_list() if len(factors) == 1 and factors[0][1] == 1: - for root in _try_decompose(f): - _update_dict(result, root, 1) + if f.get_domain().is_EX: + res = to_rational_coeffs(f) + if res: + if res[0] is None: + translate_x, f = res[2:] + else: + rescale_x, f = res[1], res[-1] + result = roots(f) + if not result: + for root in _try_decompose(f): + _update_dict(result, root, 1) + else: + for root in _try_decompose(f): + _update_dict(result, root, 1) else: for factor, k in factors: for r in _try_heuristics(Poly(factor, f.gen, field=True)): @@ -626,10 +893,10 @@ if filter not in [None, 'C']: handlers = { - 'Z' : lambda r: r.is_Integer, - 'Q' : lambda r: r.is_Rational, - 'R' : lambda r: r.is_real, - 'I' : lambda r: r.is_imaginary, + 'Z': lambda r: r.is_Integer, + 'Q': lambda r: r.is_Rational, + 'R': lambda r: r.is_real, + 'I': lambda r: r.is_imaginary, } try: @@ -645,6 +912,16 @@ for zero in dict(result).keys(): if not predicate(zero): del result[zero] + if rescale_x: + result1 = {} + for k, v in list(result.items()): + result1[k*rescale_x] = v + result = result1 + if translate_x: + result1 = {} + for k, v in list(result.items()): + result1[k + translate_x] = v + result = result1 if not multiple: return result @@ -656,6 +933,7 @@ return sorted(zeros, key=default_sort_key) + def root_factors(f, *gens, **args): """ Returns all factors of a univariate polynomial. @@ -691,10 +969,10 @@ factors, N = [], 0 for r, n in zeros.items(): - factors, N = factors + [Poly(x-r, x)]*n, N + n + factors, N = factors + [Poly(x - r, x)]*n, N + n if N < F.degree(): - G = reduce(lambda p,q: p*q, factors) + G = reduce(lambda p, q: p*q, factors) factors.append(F.quo(G)) if not isinstance(f, Poly): diff -Nru python3-sympy-0.7.2/sympy/polys/polytools.py python3-sympy-0.7.3/sympy/polys/polytools.py --- python3-sympy-0.7.2/sympy/polys/polytools.py 2012-10-17 03:02:22.000000000 +0000 +++ python3-sympy-0.7.3/sympy/polys/polytools.py 2013-07-13 17:53:32.000000000 +0000 @@ -6,6 +6,8 @@ from sympy.core.mul import _keep_coeff +from sympy.core.basic import preorder_traversal + from sympy.core.sympify import ( sympify, SympifyError, ) @@ -33,13 +35,8 @@ dup_isolate_real_roots_list, ) -from sympy.polys.distributedpolys import ( - sdp_from_dict, sdp_div, -) - -from sympy.polys.groebnertools import ( - sdp_groebner, matrix_fglm, -) +from sympy.polys.groebnertools import groebner as _groebner +from sympy.polys.fglmtools import matrix_fglm from sympy.polys.monomialtools import ( Monomial, monomial_key, @@ -68,11 +65,13 @@ from sympy.core.compatibility import iterable + class Poly(Expr): """Generic class for representing polynomial expressions. """ __slots__ = ['rep', 'gens'] + is_commutative = True is_Poly = True def __new__(cls, rep, *gens, **args): @@ -99,8 +98,9 @@ def new(cls, rep, *gens): """Construct :class:`Poly` instance from raw representation. """ if not isinstance(rep, DMP): - raise PolynomialError("invalid polynomial representation: %s" % rep) - elif rep.lev != len(gens)-1: + raise PolynomialError( + "invalid polynomial representation: %s" % rep) + elif rep.lev != len(gens) - 1: raise PolynomialError("invalid arguments: %s, %s" % (rep, gens)) obj = Basic.__new__(cls) @@ -140,9 +140,10 @@ gens = opt.gens if not gens: - raise GeneratorsNeeded("can't initialize from 'dict' without generators") + raise GeneratorsNeeded( + "can't initialize from 'dict' without generators") - level = len(gens)-1 + level = len(gens) - 1 domain = opt.domain if domain is None: @@ -159,11 +160,13 @@ gens = opt.gens if not gens: - raise GeneratorsNeeded("can't initialize from 'list' without generators") + raise GeneratorsNeeded( + "can't initialize from 'list' without generators") elif len(gens) != 1: - raise MultivariatePolynomialError("'list' representation not supported") + raise MultivariatePolynomialError( + "'list' representation not supported") - level = len(gens)-1 + level = len(gens) - 1 domain = opt.domain if domain is None: @@ -359,10 +362,11 @@ if isinstance(f.rep, DMP) and isinstance(g.rep, DMP): gens = _unify_gens(f.gens, g.gens) - dom, lev = f.rep.dom.unify(g.rep.dom, gens), len(gens)-1 + dom, lev = f.rep.dom.unify(g.rep.dom, gens), len(gens) - 1 if f.gens != gens: - f_monoms, f_coeffs = _dict_reorder(f.rep.to_dict(), f.gens, gens) + f_monoms, f_coeffs = _dict_reorder( + f.rep.to_dict(), f.gens, gens) if f.rep.dom != dom: f_coeffs = [ dom.convert(c, f.rep.dom) for c in f_coeffs ] @@ -372,7 +376,8 @@ F = f.rep.convert(dom) if g.gens != gens: - g_monoms, g_coeffs = _dict_reorder(g.rep.to_dict(), g.gens, gens) + g_monoms, g_coeffs = _dict_reorder( + g.rep.to_dict(), g.gens, gens) if g.rep.dom != dom: g_coeffs = [ dom.convert(c, g.rep.dom) for c in g_coeffs ] @@ -387,7 +392,7 @@ def per(rep, dom=dom, gens=gens, remove=None): if remove is not None: - gens = gens[:remove]+gens[remove+1:] + gens = gens[:remove] + gens[remove + 1:] if not gens: return dom.to_sympy(rep) @@ -418,7 +423,7 @@ gens = f.gens if remove is not None: - gens = gens[:remove]+gens[remove+1:] + gens = gens[:remove] + gens[remove + 1:] if not gens: return f.rep.dom.to_sympy(rep) @@ -467,7 +472,7 @@ """ domain = f.get_domain() - if not domain.has_CharacteristicZero: + if domain.is_FiniteField: return Integer(domain.characteristic()) else: raise PolynomialError("not a polynomial over a Galois field") @@ -526,7 +531,8 @@ if f.is_univariate: x, y = f.gen, x else: - raise PolynomialError("syntax supported only in univariate case") + raise PolynomialError( + "syntax supported only in univariate case") if x == y: return f @@ -560,11 +566,12 @@ if not gens: gens = _sort_gens(f.gens, opt=opt) elif set(f.gens) != set(gens): - raise PolynomialError("generators list can differ only up to order of elements") + raise PolynomialError( + "generators list can differ only up to order of elements") rep = dict(list(zip(*_dict_reorder(f.rep.to_dict(), f.gens, gens)))) - return f.per(DMP(rep, f.rep.dom, len(gens)-1), gens=gens) + return f.per(DMP(rep, f.rep.dom, len(gens) - 1), gens=gens) def ltrim(f, gen): """ @@ -594,7 +601,7 @@ gens = f.gens[j:] - return f.new(DMP.from_dict(terms, len(gens)-1, f.rep.dom), *gens) + return f.new(DMP.from_dict(terms, len(gens) - 1, f.rep.dom), *gens) def has_only_gens(f, *gens): """ @@ -619,7 +626,8 @@ try: index = f_gens.index(gen) except ValueError: - raise GeneratorsError("%s doesn't have %s as generator" % (f, gen)) + raise GeneratorsError( + "%s doesn't have %s as generator" % (f, gen)) else: indices.add(index) @@ -646,7 +654,7 @@ """ if hasattr(f.rep, 'to_ring'): result = f.rep.to_ring() - else: # pragma: no cover + else: # pragma: no cover raise OperationNotSupported(f, 'to_ring') return f.per(result) @@ -667,7 +675,7 @@ """ if hasattr(f.rep, 'to_field'): result = f.rep.to_field() - else: # pragma: no cover + else: # pragma: no cover raise OperationNotSupported(f, 'to_field') return f.per(result) @@ -688,7 +696,7 @@ """ if hasattr(f.rep, 'to_exact'): result = f.rep.to_exact() - else: # pragma: no cover + else: # pragma: no cover raise OperationNotSupported(f, 'to_exact') return f.per(result) @@ -727,7 +735,7 @@ if hasattr(f.rep, 'slice'): result = f.rep.slice(m, n, j) - else: # pragma: no cover + else: # pragma: no cover raise OperationNotSupported(f, 'slice') return f.per(result) @@ -745,6 +753,12 @@ >>> Poly(x**3 + 2*x + 3, x).coeffs() [1, 2, 3] + See Also + ======== + all_coeffs + coeff_monomial + nth + """ return [ f.rep.dom.to_sympy(c) for c in f.rep.coeffs(order=order) ] @@ -761,6 +775,10 @@ >>> Poly(x**2 + 2*x*y**2 + x*y + 3*y, x, y).monoms() [(2, 0), (1, 2), (1, 1), (0, 1)] + See Also + ======== + all_monoms + """ return f.rep.monoms(order=order) @@ -777,6 +795,10 @@ >>> Poly(x**2 + 2*x*y**2 + x*y + 3*y, x, y).terms() [((2, 0), 1), ((1, 2), 2), ((1, 1), 1), ((0, 1), 3)] + See Also + ======== + all_terms + """ return [ (m, f.rep.dom.to_sympy(c)) for m, c in f.rep.terms(order=order) ] @@ -809,6 +831,10 @@ >>> Poly(x**3 + 2*x - 1, x).all_monoms() [(3,), (2,), (1,), (0,)] + See Also + ======== + all_terms + """ return f.rep.all_monoms() @@ -860,7 +886,8 @@ if monom not in terms: terms[monom] = coeff else: - raise PolynomialError("%s monomial was generated twice" % monom) + raise PolynomialError( + "%s monomial was generated twice" % monom) return f.from_dict(terms, *(gens or f.gens), **args) @@ -908,7 +935,7 @@ def as_expr(f, *gens): """ - Convert a polynomial an expression. + Convert a Poly instance to an Expr instance. Examples ======== @@ -936,7 +963,8 @@ try: index = gens.index(gen) except ValueError: - raise GeneratorsError("%s doesn't have %s as generator" % (f, gen)) + raise GeneratorsError( + "%s doesn't have %s as generator" % (f, gen)) else: gens[index] = value @@ -958,7 +986,7 @@ """ if hasattr(f.rep, 'lift'): result = f.rep.lift() - else: # pragma: no cover + else: # pragma: no cover raise OperationNotSupported(f, 'lift') return f.per(result) @@ -979,7 +1007,7 @@ """ if hasattr(f.rep, 'deflate'): J, result = f.rep.deflate() - else: # pragma: no cover + else: # pragma: no cover raise OperationNotSupported(f, 'deflate') return J, f.per(result) @@ -1011,7 +1039,7 @@ if hasattr(f.rep, 'inject'): result = f.rep.inject(front=front) - else: # pragma: no cover + else: # pragma: no cover raise OperationNotSupported(f, 'inject') if front: @@ -1047,17 +1075,18 @@ n, k = len(f.gens), len(gens) if f.gens[:k] == gens: - _gens, front = f.gens[n-k:], True + _gens, front = f.gens[k:], True elif f.gens[-k:] == gens: - _gens, front = f.gens[:n-k], False + _gens, front = f.gens[:-k], False else: - raise NotImplementedError("can only eject front or back generators") + raise NotImplementedError( + "can only eject front or back generators") dom = dom.inject(*gens) if hasattr(f.rep, 'eject'): result = f.rep.eject(dom, front=front) - else: # pragma: no cover + else: # pragma: no cover raise OperationNotSupported(f, 'eject') return f.new(result, *_gens) @@ -1078,7 +1107,7 @@ """ if hasattr(f.rep, 'terms_gcd'): J, result = f.rep.terms_gcd() - else: # pragma: no cover + else: # pragma: no cover raise OperationNotSupported(f, 'terms_gcd') return J, f.per(result) @@ -1099,7 +1128,7 @@ """ if hasattr(f.rep, 'add_ground'): result = f.rep.add_ground(coeff) - else: # pragma: no cover + else: # pragma: no cover raise OperationNotSupported(f, 'add_ground') return f.per(result) @@ -1120,7 +1149,7 @@ """ if hasattr(f.rep, 'sub_ground'): result = f.rep.sub_ground(coeff) - else: # pragma: no cover + else: # pragma: no cover raise OperationNotSupported(f, 'sub_ground') return f.per(result) @@ -1141,7 +1170,7 @@ """ if hasattr(f.rep, 'mul_ground'): result = f.rep.mul_ground(coeff) - else: # pragma: no cover + else: # pragma: no cover raise OperationNotSupported(f, 'mul_ground') return f.per(result) @@ -1165,7 +1194,7 @@ """ if hasattr(f.rep, 'quo_ground'): result = f.rep.quo_ground(coeff) - else: # pragma: no cover + else: # pragma: no cover raise OperationNotSupported(f, 'quo_ground') return f.per(result) @@ -1191,7 +1220,7 @@ """ if hasattr(f.rep, 'exquo_ground'): result = f.rep.exquo_ground(coeff) - else: # pragma: no cover + else: # pragma: no cover raise OperationNotSupported(f, 'exquo_ground') return f.per(result) @@ -1212,7 +1241,7 @@ """ if hasattr(f.rep, 'abs'): result = f.rep.abs() - else: # pragma: no cover + else: # pragma: no cover raise OperationNotSupported(f, 'abs') return f.per(result) @@ -1236,7 +1265,7 @@ """ if hasattr(f.rep, 'neg'): result = f.rep.neg() - else: # pragma: no cover + else: # pragma: no cover raise OperationNotSupported(f, 'neg') return f.per(result) @@ -1267,7 +1296,7 @@ if hasattr(f.rep, 'add'): result = F.add(G) - else: # pragma: no cover + else: # pragma: no cover raise OperationNotSupported(f, 'add') return per(result) @@ -1298,7 +1327,7 @@ if hasattr(f.rep, 'sub'): result = F.sub(G) - else: # pragma: no cover + else: # pragma: no cover raise OperationNotSupported(f, 'sub') return per(result) @@ -1329,7 +1358,7 @@ if hasattr(f.rep, 'mul'): result = F.mul(G) - else: # pragma: no cover + else: # pragma: no cover raise OperationNotSupported(f, 'mul') return per(result) @@ -1353,7 +1382,7 @@ """ if hasattr(f.rep, 'sqr'): result = f.rep.sqr() - else: # pragma: no cover + else: # pragma: no cover raise OperationNotSupported(f, 'sqr') return f.per(result) @@ -1379,7 +1408,7 @@ if hasattr(f.rep, 'pow'): result = f.rep.pow(n) - else: # pragma: no cover + else: # pragma: no cover raise OperationNotSupported(f, 'pow') return f.per(result) @@ -1402,7 +1431,7 @@ if hasattr(f.rep, 'pdiv'): q, r = F.pdiv(G) - else: # pragma: no cover + else: # pragma: no cover raise OperationNotSupported(f, 'pdiv') return per(q), per(r) @@ -1425,7 +1454,7 @@ if hasattr(f.rep, 'prem'): result = F.prem(G) - else: # pragma: no cover + else: # pragma: no cover raise OperationNotSupported(f, 'prem') return per(result) @@ -1451,7 +1480,7 @@ if hasattr(f.rep, 'pquo'): result = F.pquo(G) - else: # pragma: no cover + else: # pragma: no cover raise OperationNotSupported(f, 'pquo') return per(result) @@ -1482,7 +1511,7 @@ result = F.pexquo(G) except ExactQuotientFailed as exc: raise exc.new(f.as_expr(), g.as_expr()) - else: # pragma: no cover + else: # pragma: no cover raise OperationNotSupported(f, 'pexquo') return per(result) @@ -1513,7 +1542,7 @@ if hasattr(f.rep, 'div'): q, r = F.div(G) - else: # pragma: no cover + else: # pragma: no cover raise OperationNotSupported(f, 'div') if retract: @@ -1552,7 +1581,7 @@ if hasattr(f.rep, 'rem'): r = F.rem(G) - else: # pragma: no cover + else: # pragma: no cover raise OperationNotSupported(f, 'rem') if retract: @@ -1589,7 +1618,7 @@ if hasattr(f.rep, 'quo'): q = F.quo(G) - else: # pragma: no cover + else: # pragma: no cover raise OperationNotSupported(f, 'quo') if retract: @@ -1631,7 +1660,7 @@ q = F.exquo(G) except ExactQuotientFailed as exc: raise exc.new(f.as_expr(), g.as_expr()) - else: # pragma: no cover + else: # pragma: no cover raise OperationNotSupported(f, 'exquo') if retract: @@ -1653,12 +1682,14 @@ else: return gen else: - raise PolynomialError("-%s <= gen < %s expected, got %s" % (length, length, gen)) + raise PolynomialError("-%s <= gen < %s expected, got %s" % + (length, length, gen)) else: try: return list(f.gens).index(sympify(gen)) except ValueError: - raise PolynomialError("a valid generator expected, got %s" % gen) + raise PolynomialError( + "a valid generator expected, got %s" % gen) def degree(f, gen=0): """ @@ -1680,7 +1711,7 @@ if hasattr(f.rep, 'degree'): return f.rep.degree(j) - else: # pragma: no cover + else: # pragma: no cover raise OperationNotSupported(f, 'degree') def degree_list(f): @@ -1699,7 +1730,7 @@ """ if hasattr(f.rep, 'degree_list'): return f.rep.degree_list() - else: # pragma: no cover + else: # pragma: no cover raise OperationNotSupported(f, 'degree_list') def total_degree(f): @@ -1720,7 +1751,7 @@ """ if hasattr(f.rep, 'total_degree'): return f.rep.total_degree() - else: # pragma: no cover + else: # pragma: no cover raise OperationNotSupported(f, 'total_degree') def homogeneous_order(f): @@ -1745,7 +1776,7 @@ """ if hasattr(f.rep, 'homogeneous_order'): return f.rep.homogeneous_order() - else: # pragma: no cover + else: # pragma: no cover raise OperationNotSupported(f, 'homogeneous_order') def LC(f, order=None): @@ -1767,7 +1798,7 @@ if hasattr(f.rep, 'LC'): result = f.rep.LC() - else: # pragma: no cover + else: # pragma: no cover raise OperationNotSupported(f, 'LC') return f.rep.dom.to_sympy(result) @@ -1788,7 +1819,7 @@ """ if hasattr(f.rep, 'TC'): result = f.rep.TC() - else: # pragma: no cover + else: # pragma: no cover raise OperationNotSupported(f, 'TC') return f.rep.dom.to_sympy(result) @@ -1809,32 +1840,90 @@ """ if hasattr(f.rep, 'coeffs'): return f.coeffs(order)[-1] - else: # pragma: no cover + else: # pragma: no cover raise OperationNotSupported(f, 'EC') + def coeff_monomial(f, monom): + """ + Returns the coefficient of ``monom`` in ``f`` if there, else None. + + Examples + ======== + + >>> from sympy import Poly, exp + >>> from sympy.abc import x, y + + >>> p = Poly(24*x*y*exp(8) + 23*x, x, y) + + >>> p.coeff_monomial(x) + 23 + >>> p.coeff_monomial(y) + 0 + >>> p.coeff_monomial(x*y) + 24*exp(8) + + Note that ``Expr.coeff()`` behaves differently, collecting terms + if possible; the Poly must be converted to an Expr to use that + method, however: + + >>> p.as_expr().coeff(x) + 24*y*exp(8) + 23 + >>> p.as_expr().coeff(y) + 24*x*exp(8) + >>> p.as_expr().coeff(x*y) + 24*exp(8) + + See Also + ======== + nth: more efficient query using exponents of the monomial's generators + + """ + return f.nth(*Monomial(monom, f.gens).exponents) + def nth(f, *N): """ - Returns the ``n``-th coefficient of ``f``. + Returns the ``n``-th coefficient of ``f`` where ``N`` are the + exponents of the generators in the term of interest. Examples ======== - >>> from sympy import Poly + >>> from sympy import Poly, sqrt >>> from sympy.abc import x, y >>> Poly(x**3 + 2*x**2 + 3*x, x).nth(2) 2 >>> Poly(x**3 + 2*x*y**2 + y**2, x, y).nth(1, 2) 2 + >>> Poly(4*sqrt(x)*y) + Poly(4*y*sqrt(x), y, sqrt(x), domain='ZZ') + >>> _.nth(1, 1) + 4 + + See Also + ======== + coeff_monomial """ if hasattr(f.rep, 'nth'): result = f.rep.nth(*list(map(int, N))) - else: # pragma: no cover + else: # pragma: no cover raise OperationNotSupported(f, 'nth') return f.rep.dom.to_sympy(result) + def coeff(f, x, n=1, right=False): + # the semantics of coeff_monomial and Expr.coeff are different; + # if someone is working with a Poly, they should be aware of the + # differences and chose the method best suited for the query. + # Alternatively, a pure-polys method could be written here but + # at this time the ``right`` keyword would be ignored because Poly + # doesn't work with non-commutatives. + raise NotImplementedError( + 'Either convert to Expr with `as_expr` method ' + 'to use Expr\'s coeff method or else use the ' + '`coeff_monomial` method of Polys.') + def LM(f, order=None): """ Returns the leading monomial of ``f``. @@ -1917,7 +2006,7 @@ """ if hasattr(f.rep, 'max_norm'): result = f.rep.max_norm() - else: # pragma: no cover + else: # pragma: no cover raise OperationNotSupported(f, 'max_norm') return f.rep.dom.to_sympy(result) @@ -1938,7 +2027,7 @@ """ if hasattr(f.rep, 'l1_norm'): result = f.rep.l1_norm() - else: # pragma: no cover + else: # pragma: no cover raise OperationNotSupported(f, 'l1_norm') return f.rep.dom.to_sympy(result) @@ -1964,11 +2053,13 @@ if not f.rep.dom.has_Field: return S.One, f - dom = f.rep.dom.get_ring() + dom = f.get_domain() + if dom.has_assoc_Ring: + dom = f.rep.dom.get_ring() if hasattr(f.rep, 'clear_denoms'): coeff, result = f.rep.clear_denoms() - else: # pragma: no cover + else: # pragma: no cover raise OperationNotSupported(f, 'clear_denoms') coeff, f = dom.to_sympy(coeff), f.per(result) @@ -2050,7 +2141,7 @@ rep = rep.integrate(int(m), f._gen_to_level(gen)) return f.per(rep) - else: # pragma: no cover + else: # pragma: no cover raise OperationNotSupported(f, 'integrate') def diff(f, *specs): @@ -2085,7 +2176,7 @@ rep = rep.diff(int(m), f._gen_to_level(gen)) return f.per(rep) - else: # pragma: no cover + else: # pragma: no cover raise OperationNotSupported(f, 'diff') def eval(f, x, a=None, auto=True): @@ -2142,7 +2233,7 @@ else: j = f._gen_to_level(x) - if not hasattr(f.rep, 'eval'): # pragma: no cover + if not hasattr(f.rep, 'eval'): # pragma: no cover raise OperationNotSupported(f, 'eval') try: @@ -2151,8 +2242,12 @@ if not auto: raise DomainError("can't evaluate at %s in %s" % (a, f.rep.dom)) else: - domain, [a] = construct_domain([a]) - f = f.set_domain(domain) + a_domain, [a] = construct_domain([a]) + new_domain = f.get_domain().unify(a_domain, gens=f.gens) + + f = f.set_domain(new_domain) + a = new_domain.convert(a, a_domain) + result = f.rep.eval(a, j) return f.per(result, remove=j) @@ -2205,7 +2300,7 @@ if hasattr(f.rep, 'half_gcdex'): s, h = F.half_gcdex(G) - else: # pragma: no cover + else: # pragma: no cover raise OperationNotSupported(f, 'half_gcdex') return per(s), per(h) @@ -2238,7 +2333,7 @@ if hasattr(f.rep, 'gcdex'): s, t, h = F.gcdex(G) - else: # pragma: no cover + else: # pragma: no cover raise OperationNotSupported(f, 'gcdex') return per(s), per(t), per(h) @@ -2269,7 +2364,7 @@ if hasattr(f.rep, 'invert'): result = F.invert(G) - else: # pragma: no cover + else: # pragma: no cover raise OperationNotSupported(f, 'invert') return per(result) @@ -2278,14 +2373,14 @@ """Compute ``f**(-1)`` mod ``x**n``. """ if hasattr(f.rep, 'revert'): result = f.rep.revert(int(n)) - else: # pragma: no cover + else: # pragma: no cover raise OperationNotSupported(f, 'revert') return f.per(result) def subresultants(f, g): """ - Computes the subresultant PRS sequence of ``f`` and ``g``. + Computes the subresultant PRS of ``f`` and ``g``. Examples ======== @@ -2303,32 +2398,46 @@ if hasattr(f.rep, 'subresultants'): result = F.subresultants(G) - else: # pragma: no cover + else: # pragma: no cover raise OperationNotSupported(f, 'subresultants') return list(map(per, result)) - def resultant(f, g): + def resultant(f, g, includePRS=False): """ Computes the resultant of ``f`` and ``g`` via PRS. + If includePRS=True, it includes the subresultant PRS in the result. + Because the PRS is used to calculate the resultant, this is more + efficient than calling :func:`subresultants` separately. + Examples ======== >>> from sympy import Poly >>> from sympy.abc import x - >>> Poly(x**2 + 1, x).resultant(Poly(x**2 - 1, x)) + >>> f = Poly(x**2 + 1, x) + + >>> f.resultant(Poly(x**2 - 1, x)) 4 + >>> f.resultant(Poly(x**2 - 1, x), includePRS=True) + (4, [Poly(x**2 + 1, x, domain='ZZ'), Poly(x**2 - 1, x, domain='ZZ'), + Poly(-2, x, domain='ZZ')]) """ _, per, F, G = f._unify(g) if hasattr(f.rep, 'resultant'): - result = F.resultant(G) - else: # pragma: no cover + if includePRS: + result, R = F.resultant(G, includePRS=includePRS) + else: + result = F.resultant(G) + else: # pragma: no cover raise OperationNotSupported(f, 'resultant') + if includePRS: + return (per(result, remove=0), list(map(per, R))) return per(result, remove=0) def discriminant(f): @@ -2347,7 +2456,7 @@ """ if hasattr(f.rep, 'discriminant'): result = f.rep.discriminant() - else: # pragma: no cover + else: # pragma: no cover raise OperationNotSupported(f, 'discriminant') return f.per(result, remove=0) @@ -2376,7 +2485,7 @@ if hasattr(f.rep, 'cofactors'): h, cff, cfg = F.cofactors(G) - else: # pragma: no cover + else: # pragma: no cover raise OperationNotSupported(f, 'cofactors') return per(h), per(cff), per(cfg) @@ -2399,7 +2508,7 @@ if hasattr(f.rep, 'gcd'): result = F.gcd(G) - else: # pragma: no cover + else: # pragma: no cover raise OperationNotSupported(f, 'gcd') return per(result) @@ -2422,7 +2531,7 @@ if hasattr(f.rep, 'lcm'): result = F.lcm(G) - else: # pragma: no cover + else: # pragma: no cover raise OperationNotSupported(f, 'lcm') return per(result) @@ -2445,7 +2554,7 @@ if hasattr(f.rep, 'trunc'): result = f.rep.trunc(p) - else: # pragma: no cover + else: # pragma: no cover raise OperationNotSupported(f, 'trunc') return f.per(result) @@ -2472,7 +2581,7 @@ if hasattr(f.rep, 'monic'): result = f.rep.monic() - else: # pragma: no cover + else: # pragma: no cover raise OperationNotSupported(f, 'monic') return f.per(result) @@ -2493,7 +2602,7 @@ """ if hasattr(f.rep, 'content'): result = f.rep.content() - else: # pragma: no cover + else: # pragma: no cover raise OperationNotSupported(f, 'content') return f.rep.dom.to_sympy(result) @@ -2514,7 +2623,7 @@ """ if hasattr(f.rep, 'primitive'): cont, result = f.rep.primitive() - else: # pragma: no cover + else: # pragma: no cover raise OperationNotSupported(f, 'primitive') return f.rep.dom.to_sympy(cont), f.per(result) @@ -2537,7 +2646,7 @@ if hasattr(f.rep, 'compose'): result = F.compose(G) - else: # pragma: no cover + else: # pragma: no cover raise OperationNotSupported(f, 'compose') return per(result) @@ -2558,7 +2667,7 @@ """ if hasattr(f.rep, 'decompose'): result = f.rep.decompose() - else: # pragma: no cover + else: # pragma: no cover raise OperationNotSupported(f, 'decompose') return list(map(f.per, result)) @@ -2579,7 +2688,7 @@ """ if hasattr(f.rep, 'shift'): result = f.rep.shift(a) - else: # pragma: no cover + else: # pragma: no cover raise OperationNotSupported(f, 'shift') return f.per(result) @@ -2606,7 +2715,7 @@ if hasattr(f.rep, 'sturm'): result = f.rep.sturm() - else: # pragma: no cover + else: # pragma: no cover raise OperationNotSupported(f, 'sturm') return list(map(f.per, result)) @@ -2629,7 +2738,7 @@ """ if hasattr(f.rep, 'gff_list'): result = f.rep.gff_list() - else: # pragma: no cover + else: # pragma: no cover raise OperationNotSupported(f, 'gff_list') return [ (f.per(g), k) for g, k in result ] @@ -2660,7 +2769,7 @@ """ if hasattr(f.rep, 'sqf_norm'): s, g, r = f.rep.sqf_norm() - else: # pragma: no cover + else: # pragma: no cover raise OperationNotSupported(f, 'sqf_norm') return s, f.per(g), f.per(r) @@ -2681,7 +2790,7 @@ """ if hasattr(f.rep, 'sqf_part'): result = f.rep.sqf_part() - else: # pragma: no cover + else: # pragma: no cover raise OperationNotSupported(f, 'sqf_part') return f.per(result) @@ -2710,7 +2819,7 @@ """ if hasattr(f.rep, 'sqf_list'): coeff, factors = f.rep.sqf_list(all) - else: # pragma: no cover + else: # pragma: no cover raise OperationNotSupported(f, 'sqf_list') return f.rep.dom.to_sympy(coeff), [ (f.per(g), k) for g, k in factors ] @@ -2743,7 +2852,7 @@ """ if hasattr(f.rep, 'sqf_list_include'): factors = f.rep.sqf_list_include(all) - else: # pragma: no cover + else: # pragma: no cover raise OperationNotSupported(f, 'sqf_list_include') return [ (f.per(g), k) for g, k in factors ] @@ -2770,7 +2879,7 @@ coeff, factors = f.rep.factor_list() except DomainError: return S.One, [(f, 1)] - else: # pragma: no cover + else: # pragma: no cover raise OperationNotSupported(f, 'factor_list') return f.rep.dom.to_sympy(coeff), [ (f.per(g), k) for g, k in factors ] @@ -2797,7 +2906,7 @@ factors = f.rep.factor_list_include() except DomainError: return [(f, 1)] - else: # pragma: no cover + else: # pragma: no cover raise OperationNotSupported(f, 'factor_list_include') return [ (f.per(g), k) for g, k in factors ] @@ -2830,8 +2939,9 @@ sup = QQ.convert(sup) if hasattr(f.rep, 'intervals'): - result = f.rep.intervals(all=all, eps=eps, inf=inf, sup=sup, fast=fast, sqf=sqf) - else: # pragma: no cover + result = f.rep.intervals( + all=all, eps=eps, inf=inf, sup=sup, fast=fast, sqf=sqf) + else: # pragma: no cover raise OperationNotSupported(f, 'intervals') if sqf: @@ -2899,7 +3009,7 @@ if hasattr(f.rep, 'refine_root'): S, T = f.rep.refine_root(s, t, eps=eps, steps=steps, fast=fast) - else: # pragma: no cover + else: # pragma: no cover raise OperationNotSupported(f, 'refine_root') return QQ.to_sympy(S), QQ.to_sympy(T) @@ -2951,7 +3061,7 @@ if inf_real and sup_real: if hasattr(f.rep, 'count_real_roots'): count = f.rep.count_real_roots(inf=inf, sup=sup) - else: # pragma: no cover + else: # pragma: no cover raise OperationNotSupported(f, 'count_real_roots') else: if inf_real and inf is not None: @@ -2962,7 +3072,7 @@ if hasattr(f.rep, 'count_complex_roots'): count = f.rep.count_complex_roots(inf=inf, sup=sup) - else: # pragma: no cover + else: # pragma: no cover raise OperationNotSupported(f, 'count_complex_roots') return Integer(count) @@ -3032,7 +3142,9 @@ >>> Poly(2*x**3 - 7*x**2 + 4*x + 4).all_roots() [-1/2, 2, 2] >>> Poly(x**3 + x + 1).all_roots() - [RootOf(x**3 + x + 1, 0), RootOf(x**3 + x + 1, 1), RootOf(x**3 + x + 1, 2)] + [RootOf(x**3 + x + 1, 0), + RootOf(x**3 + x + 1, 1), + RootOf(x**3 + x + 1, 2)] """ roots = sympy.polys.rootoftools.RootOf.all_roots(f, radicals=radicals) @@ -3059,12 +3171,14 @@ """ if f.is_multivariate: - raise MultivariatePolynomialError("can't compute numerical roots of %s" % f) + raise MultivariatePolynomialError( + "can't compute numerical roots of %s" % f) if f.degree() <= 0: return [] - coeffs = [ coeff.evalf(n=n).as_real_imag() for coeff in f.all_coeffs() ] + coeffs = [ coeff.evalf(n=n).as_real_imag() + for coeff in f.all_coeffs() ] dps = sympy.mpmath.mp.dps sympy.mpmath.mp.dps = n @@ -3073,9 +3187,11 @@ try: coeffs = [ sympy.mpmath.mpc(*coeff) for coeff in coeffs ] except TypeError: - raise DomainError("numerical domain expected, got %s" % f.rep.dom) + raise DomainError( + "numerical domain expected, got %s" % f.rep.dom) - result = sympy.mpmath.polyroots(coeffs, maxsteps=maxsteps, cleanup=cleanup, error=error) + result = sympy.mpmath.polyroots( + coeffs, maxsteps=maxsteps, cleanup=cleanup, error=error) if error: roots, error = result @@ -3106,7 +3222,8 @@ """ if f.is_multivariate: - raise MultivariatePolynomialError("can't compute ground roots of %s" % f) + raise MultivariatePolynomialError( + "can't compute ground roots of %s" % f) roots = {} @@ -3140,7 +3257,8 @@ """ if f.is_multivariate: - raise MultivariatePolynomialError("must be a univariate polynomial") + raise MultivariatePolynomialError( + "must be a univariate polynomial") N = sympify(n) @@ -3177,7 +3295,7 @@ if hasattr(F, 'cancel'): result = F.cancel(G, include=include) - else: # pragma: no cover + else: # pragma: no cover raise OperationNotSupported(f, 'cancel') if not include: @@ -3646,6 +3764,7 @@ def _strict_eq(f, g): return isinstance(g, f.__class__) and f.gens == g.gens and f.rep.eq(g.rep, strict=True) + class PurePoly(Poly): """Class for representing pure polynomials. """ @@ -3727,7 +3846,7 @@ def per(rep, dom=dom, gens=gens, remove=None): if remove is not None: - gens = gens[:remove]+gens[remove+1:] + gens = gens[:remove] + gens[remove + 1:] if not gens: return dom.to_sympy(rep) @@ -3736,11 +3855,13 @@ return dom, per, F, G + def poly_from_expr(expr, *gens, **args): """Construct a polynomial from an expression. """ opt = options.build_options(gens, args) return _poly_from_expr(expr, opt) + def _poly_from_expr(expr, opt): """Construct a polynomial from an expression. """ orig, expr = expr, sympify(expr) @@ -3773,9 +3894,10 @@ else: coeffs = list(map(domain.from_sympy, coeffs)) - level = len(opt.gens)-1 + level = len(opt.gens) - 1 - poly = Poly.new(DMP.from_monoms_coeffs(monoms, coeffs, level, domain), *opt.gens) + poly = Poly.new( + DMP.from_monoms_coeffs(monoms, coeffs, level, domain), *opt.gens) opt['domain'] = domain @@ -3784,11 +3906,13 @@ return poly, opt + def parallel_poly_from_expr(exprs, *gens, **args): """Construct polynomials from expressions. """ opt = options.build_options(gens, args) return _parallel_poly_from_expr(exprs, opt) + def _parallel_poly_from_expr(exprs, opt): """Construct polynomials from expressions. """ if len(exprs) == 2: @@ -3866,7 +3990,7 @@ all_coeffs.append(coeffs_list[:k]) coeffs_list = coeffs_list[k:] - polys, level = [], len(opt.gens)-1 + polys, level = [], len(opt.gens) - 1 for monoms, coeffs in zip(all_monoms, all_coeffs): rep = DMP.from_monoms_coeffs(monoms, coeffs, level, domain) @@ -3879,6 +4003,7 @@ return polys, opt + def _update_args(args, key, value): """Add a new ``(key, value)`` pair to arguments ``dict``. """ args = dict(args) @@ -3888,6 +4013,7 @@ return args + def degree(f, *gens, **args): """ Return the degree of ``f`` in the given variable. @@ -3913,6 +4039,7 @@ return Integer(F.degree(opt.gen)) + def degree_list(f, *gens, **args): """ Return a list of degrees of ``f`` in all variables. @@ -3938,6 +4065,7 @@ return tuple(map(Integer, degrees)) + def LC(f, *gens, **args): """ Return the leading coefficient of ``f``. @@ -3961,6 +4089,7 @@ return F.LC(order=opt.order) + def LM(f, *gens, **args): """ Return the leading monomial of ``f``. @@ -3985,6 +4114,7 @@ monom = F.LM(order=opt.order) return monom.as_expr() + def LT(f, *gens, **args): """ Return the leading term of ``f``. @@ -4009,6 +4139,7 @@ monom, coeff = F.LT(order=opt.order) return coeff*monom.as_expr() + def pdiv(f, g, *gens, **args): """ Compute polynomial pseudo-division of ``f`` and ``g``. @@ -4037,6 +4168,7 @@ else: return q, r + def prem(f, g, *gens, **args): """ Compute polynomial pseudo-remainder of ``f`` and ``g``. @@ -4065,6 +4197,7 @@ else: return r + def pquo(f, g, *gens, **args): """ Compute polynomial pseudo-quotient of ``f`` and ``g``. @@ -4088,13 +4221,17 @@ except PolificationFailed as exc: raise ComputationFailed('pquo', 2, exc) - q = F.pquo(G) + try: + q = F.pquo(G) + except ExactQuotientFailed: + raise ExactQuotientFailed(f, g) if not opt.polys: return q.as_expr() else: return q + def pexquo(f, g, *gens, **args): """ Compute polynomial exact pseudo-quotient of ``f`` and ``g``. @@ -4128,6 +4265,7 @@ else: return q + def div(f, g, *gens, **args): """ Compute polynomial division of ``f`` and ``g``. @@ -4158,6 +4296,7 @@ else: return q, r + def rem(f, g, *gens, **args): """ Compute polynomial remainder of ``f`` and ``g``. @@ -4188,6 +4327,7 @@ else: return r + def quo(f, g, *gens, **args): """ Compute polynomial quotient of ``f`` and ``g``. @@ -4218,6 +4358,7 @@ else: return q + def exquo(f, g, *gens, **args): """ Compute polynomial exact quotient of ``f`` and ``g``. @@ -4251,6 +4392,7 @@ else: return q + def half_gcdex(f, g, *gens, **args): """ Half extended Euclidean algorithm of ``f`` and ``g``. @@ -4272,15 +4414,14 @@ try: (F, G), opt = parallel_poly_from_expr((f, g), *gens, **args) except PolificationFailed as exc: - f, g = exc.exprs - - if hasattr(f, 'half_gcdex'): - try: - return f.half_gcdex(g) - except (SympifyError, ValueError): - pass + domain, (a, b) = construct_domain(exc.exprs) - raise ComputationFailed('half_gcdex', 2, exc) + try: + s, h = domain.half_gcdex(a, b) + except NotImplementedError: + raise ComputationFailed('half_gcdex', 2, exc) + else: + return domain.to_sympy(s), domain.to_sympy(h) s, h = F.half_gcdex(G, auto=opt.auto) @@ -4289,6 +4430,7 @@ else: return s, h + def gcdex(f, g, *gens, **args): """ Extended Euclidean algorithm of ``f`` and ``g``. @@ -4310,15 +4452,14 @@ try: (F, G), opt = parallel_poly_from_expr((f, g), *gens, **args) except PolificationFailed as exc: - f, g = exc.exprs + domain, (a, b) = construct_domain(exc.exprs) - if hasattr(f, 'gcdex'): - try: - return f.gcdex(g) - except (SympifyError, ValueError): - pass - - raise ComputationFailed('gcdex', 2, exc) + try: + s, t, h = domain.gcdex(a, b) + except NotImplementedError: + raise ComputationFailed('gcdex', 2, exc) + else: + return domain.to_sympy(s), domain.to_sympy(t), domain.to_sympy(h) s, t, h = F.gcdex(G, auto=opt.auto) @@ -4327,6 +4468,7 @@ else: return s, t, h + def invert(f, g, *gens, **args): """ Invert ``f`` modulo ``g`` when possible. @@ -4351,15 +4493,12 @@ try: (F, G), opt = parallel_poly_from_expr((f, g), *gens, **args) except PolificationFailed as exc: - f, g = exc.exprs - - if hasattr(f, 'invert'): - try: - return f.invert(g) - except (SympifyError, ValueError): - pass + domain, (a, b) = construct_domain(exc.exprs) - raise ComputationFailed('invert', 2, exc) + try: + return domain.to_sympy(domain.invert(a, b)) + except NotImplementedError: + raise ComputationFailed('invert', 2, exc) h = F.invert(G, auto=opt.auto) @@ -4368,6 +4507,7 @@ else: return h + def subresultants(f, g, *gens, **args): """ Compute subresultant PRS of ``f`` and ``g``. @@ -4396,6 +4536,7 @@ else: return result + def resultant(f, g, *gens, **args): """ Compute resultant of ``f`` and ``g``. @@ -4410,6 +4551,7 @@ 4 """ + includePRS = args.pop('includePRS', False) options.allowed_flags(args, ['polys']) try: @@ -4417,13 +4559,21 @@ except PolificationFailed as exc: raise ComputationFailed('resultant', 2, exc) - result = F.resultant(G) + if includePRS: + result, R = F.resultant(G, includePRS=includePRS) + else: + result = F.resultant(G) if not opt.polys: + if includePRS: + return result.as_expr(), [r.as_expr() for r in R] return result.as_expr() else: + if includePRS: + return result, R return result + def discriminant(f, *gens, **args): """ Compute discriminant of ``f``. @@ -4452,6 +4602,7 @@ else: return result + def cofactors(f, g, *gens, **args): """ Compute GCD and cofactors of ``f`` and ``g``. @@ -4475,15 +4626,14 @@ try: (F, G), opt = parallel_poly_from_expr((f, g), *gens, **args) except PolificationFailed as exc: - f, g = exc.exprs - - if hasattr(f, 'cofactors'): - try: - return f.cofactors(g) - except (SympifyError, ValueError): - pass + domain, (a, b) = construct_domain(exc.exprs) - raise ComputationFailed('cofactors', 2, exc) + try: + h, cff, cfg = domain.cofactors(a, b) + except NotImplementedError: + raise ComputationFailed('cofactors', 2, exc) + else: + return domain.to_sympy(h), domain.to_sympy(cff), domain.to_sympy(cfg) h, cff, cfg = F.cofactors(G) @@ -4492,6 +4642,7 @@ else: return h, cff, cfg + def gcd_list(seq, *gens, **args): """ Compute GCD of a list of polynomials. @@ -4506,22 +4657,23 @@ x - 1 """ - if not gens and not args: - if not seq: - return S.Zero + seq = sympify(seq) - seq = sympify(seq) + if not gens and not args: + domain, numbers = construct_domain(seq) - if all(s.is_Number for s in seq): - result, numbers = seq[0], seq[1:] + if not numbers: + return domain.zero + elif domain.is_Numerical: + result, numbers = numbers[0], numbers[1:] for number in numbers: - result = result.gcd(number) + result = domain.gcd(result, number) - if result is S.One: + if domain.is_one(result): break - return result + return domain.to_sympy(result) options.allowed_flags(args, ['polys']) @@ -4549,6 +4701,7 @@ else: return result + def gcd(f, g=None, *gens, **args): """ Compute GCD of ``f`` and ``g``. @@ -4568,25 +4721,20 @@ gens = (g,) + gens return gcd_list(f, *gens, **args) + elif g is None: + raise TypeError("gcd() takes 2 arguments or a sequence of arguments") options.allowed_flags(args, ['polys']) try: (F, G), opt = parallel_poly_from_expr((f, g), *gens, **args) except PolificationFailed as exc: - f, g = exc.exprs - - if hasattr(f, 'gcd'): - try: - if f.is_Float: - f = Rational(str(f)) - if g.is_Float: - g = Rational(str(g)) - return f.gcd(g) - except (SympifyError, ValueError): - pass + domain, (a, b) = construct_domain(exc.exprs) - raise ComputationFailed('gcd', 2, exc) + try: + return domain.to_sympy(domain.gcd(a, b)) + except NotImplementedError: + raise ComputationFailed('gcd', 2, exc) result = F.gcd(G) @@ -4595,6 +4743,7 @@ else: return result + def lcm_list(seq, *gens, **args): """ Compute LCM of a list of polynomials. @@ -4609,19 +4758,20 @@ x**5 - x**4 - 2*x**3 - x**2 + x + 2 """ - if not gens and not args: - if not seq: - return S.One + seq = sympify(seq) - seq = sympify(seq) + if not gens and not args: + domain, numbers = construct_domain(seq) - if all(s.is_Number for s in seq): - result, numbers = seq[0], seq[1:] + if not numbers: + return domain.one + elif domain.is_Numerical: + result, numbers = numbers[0], numbers[1:] for number in numbers: - result = result.lcm(number) + result = domain.lcm(result, number) - return result + return domain.to_sympy(result) options.allowed_flags(args, ['polys']) @@ -4646,6 +4796,7 @@ else: return result + def lcm(f, g=None, *gens, **args): """ Compute LCM of ``f`` and ``g``. @@ -4665,21 +4816,20 @@ gens = (g,) + gens return lcm_list(f, *gens, **args) + elif g is None: + raise TypeError("lcm() takes 2 arguments or a sequence of arguments") options.allowed_flags(args, ['polys']) try: (F, G), opt = parallel_poly_from_expr((f, g), *gens, **args) except PolificationFailed as exc: - f, g = exc.exprs - - if hasattr(f, 'lcm'): - try: - return f.lcm(g) - except (SympifyError, ValueError): - pass + domain, (a, b) = construct_domain(exc.exprs) - raise ComputationFailed('lcm', 2, exc) + try: + return domain.to_sympy(domain.lcm(a, b)) + except NotImplementedError: + raise ComputationFailed('lcm', 2, exc) result = F.lcm(G) @@ -4688,6 +4838,7 @@ else: return result + def terms_gcd(f, *gens, **args): """ Remove GCD of terms from ``f``. @@ -4740,6 +4891,8 @@ >>> terms_gcd(x + y/2, clear=False) x + y/2 + >>> terms_gcd(x*y/2 + y**2, clear=False) + y*(x/2 + y) The ``clear`` flag is ignored if all coefficients are fractions: @@ -4783,7 +4936,13 @@ term = Mul(*[ x**j for x, j in zip(f.gens, J) ]) - return _keep_coeff(coeff, term*f.as_expr(), clear=clear) + if clear: + return _keep_coeff(coeff, term*f.as_expr()) + # base the clearing on the form of the original expression, not + # the (perhaps) Mul that we have now + coeff, f = _keep_coeff(coeff, f.as_expr(), clear=False).as_coeff_Mul() + return _keep_coeff(coeff, term*f, clear=False) + def trunc(f, p, *gens, **args): """ @@ -4813,6 +4972,7 @@ else: return result + def monic(f, *gens, **args): """ Divide all coefficients of ``f`` by ``LC(f)``. @@ -4841,6 +5001,7 @@ else: return result + def content(f, *gens, **args): """ Compute GCD of coefficients of ``f``. @@ -4864,6 +5025,7 @@ return F.content() + def primitive(f, *gens, **args): """ Compute content and the primitive form of ``f``. @@ -4908,6 +5070,7 @@ else: return cont, result + def compose(f, g, *gens, **args): """ Compute functional composition ``f(g)``. @@ -4936,6 +5099,7 @@ else: return result + def decompose(f, *gens, **args): """ Compute functional decomposition of ``f``. @@ -4964,6 +5128,7 @@ else: return result + def sturm(f, *gens, **args): """ Compute Sturm sequence of ``f``. @@ -4992,6 +5157,7 @@ else: return result + def gff_list(f, *gens, **args): """ Compute a list of greatest factorial factors of ``f``. @@ -5025,10 +5191,12 @@ else: return factors + def gff(f, *gens, **args): """Compute greatest factorial factorization of ``f``. """ raise NotImplementedError('symbolic falling factorial') + def sqf_norm(f, *gens, **args): """ Compute square-free norm of ``f``. @@ -5061,6 +5229,7 @@ else: return Integer(s), g, r + def sqf_part(f, *gens, **args): """ Compute square-free part of ``f``. @@ -5089,6 +5258,7 @@ else: return result + def _sorted_factors(factors, method): """Sort a list of ``(expr, exp)`` pairs. """ if method == 'sqf': @@ -5104,10 +5274,12 @@ return sorted(factors, key=key) + def _factors_product(factors): """Multiply a list of ``(expr, exp)`` pairs. """ return Mul(*[ f.as_expr()**k for f, k in factors ]) + def _symbolic_factor_list(expr, opt, method): """Helper function for :func:`_symbolic_factor`. """ coeff, factors = S.One, [] @@ -5163,6 +5335,7 @@ return coeff, factors + def _symbolic_factor(expr, opt, method): """Helper function for :func:`_factor`. """ if isinstance(expr, Expr) and not expr.is_Relational: @@ -5175,6 +5348,7 @@ else: return expr + def _generic_factor_list(expr, gens, args, method): """Helper function for :func:`sqf_list` and :func:`factor_list`. """ options.allowed_flags(args, ['frac', 'polys']) @@ -5215,12 +5389,190 @@ else: raise PolynomialError("a polynomial expected, got %s" % expr) + def _generic_factor(expr, gens, args, method): """Helper function for :func:`sqf` and :func:`factor`. """ options.allowed_flags(args, []) opt = options.build_options(gens, args) return _symbolic_factor(sympify(expr), opt, method) +def to_rational_coeffs(f): + """ + try to transform a polynomial to have rational coefficients + + try to find a transformation ``x = alpha*y`` + + ``f(x) = lc*alpha**n * g(y)`` where ``g`` is a polynomial with + rational coefficients, ``lc`` the leading coefficient. + + If this fails, try ``x = y + beta`` + ``f(x) = g(y)`` + + Returns ``None`` if ``g`` not found; + ``(lc, alpha, None, g)`` in case of rescaling + ``(None, None, beta, g)`` in case of translation + + Notes + ===== + + Currently it transforms only polynomials without roots larger than 2. + + Examples + ======== + + >>> from sympy import sqrt, Poly, simplify, expand + >>> from sympy.polys.polytools import to_rational_coeffs + >>> from sympy.abc import x + >>> p = Poly(((x**2-1)*(x-2)).subs({x:x*(1 + sqrt(2))}), x, domain='EX') + >>> lc, r, _, g = to_rational_coeffs(p) + >>> lc, r + (7 + 5*sqrt(2), -2*sqrt(2) + 2) + >>> g + Poly(x**3 + x**2 - 1/4*x - 1/4, x, domain='QQ') + >>> r1 = simplify(1/r) + >>> Poly(lc*r**3*(g.as_expr()).subs({x:x*r1}), x, domain='EX') == p + True + + """ + from sympy.simplify.simplify import simplify + + def _try_rescale(f): + """ + try rescaling ``x -> alpha*x`` to convert f to a polynomial + with rational coefficients. + Returns ``alpha, f``; if the rescaling is successful, + ``alpha`` is the rescaling factor, and ``f`` is the rescaled + polynomial; else ``alpha`` is ``None``. + """ + from sympy.core.add import Add + if not len(f.gens) == 1 or not (f.gens[0]).is_Atom: + return None, f + n = f.degree() + lc = f.LC() + coeffs = f.monic().all_coeffs()[1:] + coeffs = [simplify(coeffx) for coeffx in coeffs] + if coeffs[-2] and not all(coeffx.is_rational for coeffx in coeffs): + rescale1_x = simplify(coeffs[-2]/coeffs[-1]) + coeffs1 = [] + for i in range(len(coeffs)): + coeffx = simplify(coeffs[i]*rescale1_x**(i + 1)) + if not coeffx.is_rational: + break + coeffs1.append(coeffx) + else: + rescale_x = simplify(1/rescale1_x) + x = f.gens[0] + v = [x**n] + for i in range(1, n + 1): + v.append(coeffs1[i - 1]*x**(n - i)) + f = Add(*v) + f = Poly(f) + return lc, rescale_x, f + return None + + def _try_translate(f): + """ + try translating ``x -> x + alpha`` to convert f to a polynomial + with rational coefficients. + Returns ``alpha, f``; if the translating is successful, + ``alpha`` is the translating factor, and ``f`` is the shifted + polynomial; else ``alpha`` is ``None``. + """ + from sympy.core.add import Add + from sympy.utilities.iterables import sift + if not len(f.gens) == 1 or not (f.gens[0]).is_Atom: + return None, f + n = f.degree() + f1 = f.monic() + coeffs = f1.all_coeffs()[1:] + c = simplify(coeffs[0]) + if c and not c.is_rational: + if c.is_Add: + args = c.args + else: + args = [c] + sifted = sift(args, lambda z: z.is_rational) + c1, c2 = sifted[True], sifted[False] + alpha = -Add(*c2)/n + f2 = f1.shift(alpha) + return alpha, f2 + return None + + def _has_square_roots(p): + """ + Return True if ``f`` is a sum with square roots but no other root + """ + from sympy.core.exprtools import Factors + coeffs = p.coeffs() + has_sq = False + for y in coeffs: + for x in Add.make_args(y): + f = Factors(x).factors + r = [wx.q for wx in list(f.values()) if wx.is_Rational and wx.q >= 2] + if not r: + continue + if min(r) == 2: + has_sq = True + if max(r) > 2: + return False + return has_sq + + if f.get_domain().is_EX and _has_square_roots(f): + rescale_x = None + translate_x = None + r = _try_rescale(f) + if r: + return r[0], r[1], None, r[2] + else: + r = _try_translate(f) + if r: + return None, None, r[0], r[1] + return None + +def _torational_factor_list(p, x): + """ + helper function to factor polynomial using to_rational_coeffs + + Examples + ======== + + >>> from sympy.polys.polytools import _torational_factor_list + >>> from sympy.abc import x + >>> from sympy import sqrt, expand, Mul + >>> p = expand(((x**2-1)*(x-2)).subs({x:x*(1 + sqrt(2))})) + >>> factors = _torational_factor_list(p, x); factors + (-2, [(-x*(1 + sqrt(2))/2 + 1, 1), (-x*(1 + sqrt(2)) - 1, 1), (-x*(1 + sqrt(2)) + 1, 1)]) + >>> expand(factors[0]*Mul(*[z[0] for z in factors[1]])) == p + True + >>> p = expand(((x**2-1)*(x-2)).subs({x:x + sqrt(2)})) + >>> factors = _torational_factor_list(p, x); factors + (1, [(x - 2 + sqrt(2), 1), (x - 1 + sqrt(2), 1), (x + 1 + sqrt(2), 1)]) + >>> expand(factors[0]*Mul(*[z[0] for z in factors[1]])) == p + True + + """ + from sympy.simplify.simplify import simplify + p1 = Poly(p, x, domain='EX') + n = p1.degree() + res = to_rational_coeffs(p1) + if not res: + return None + lc, r, t, g = res + factors = factor_list(g.as_expr()) + if lc: + c = simplify(factors[0]*lc*r**n) + r1 = simplify(1/r) + a = [] + for z in factors[1:][0]: + a.append((simplify(z[0].subs({x:x*r1})), z[1])) + else: + c = factors[0] + a = [] + for z in factors[1:][0]: + a.append((z[0].subs({x:x - t}), z[1])) + return (c, a) + + def sqf_list(f, *gens, **args): """ Compute a list of square-free factors of ``f``. @@ -5237,6 +5589,7 @@ """ return _generic_factor_list(f, gens, args, method='sqf') + def sqf(f, *gens, **args): """ Compute square-free factorization of ``f``. @@ -5253,6 +5606,7 @@ """ return _generic_factor(f, gens, args, method='sqf') + def factor_list(f, *gens, **args): """ Compute a list of irreducible factors of ``f``. @@ -5269,10 +5623,11 @@ """ return _generic_factor_list(f, gens, args, method='factor') + def factor(f, *gens, **args): """ - Compute the factorization of ``f`` into irreducibles. (Use factorint to - factor an integer.) + Compute the factorization of expression, ``f``, into irreducibles. (To + factor an integer into primes, use ``factorint``.) There two modes implemented: symbolic and formal. If ``f`` is not an instance of :class:`Poly` and generators are not specified, then the @@ -5311,7 +5666,33 @@ >>> factor((x**2 + 4*x + 4)**10000000*(x**2 + 1)) (x + 2)**20000000*(x**2 + 1) + By default, factor deals with an expression as a whole: + + >>> eq = 2**(x**2 + 2*x + 1) + >>> factor(eq) + 2**(x**2 + 2*x + 1) + + If the ``deep`` flag is True then subexpressions will + be factored: + + >>> factor(eq, deep=True) + 2**((x + 1)**2) + + See Also + ======== + sympy.ntheory.factor_.factorint + """ + f = sympify(f) + if args.pop('deep', False): + partials = {} + muladd = f.atoms(Mul, Add) + for p in muladd: + fac = factor(p, *gens, **args) + if (fac.is_Mul or fac.is_Pow) and fac != p: + partials[p] = fac + return f.xreplace(partials) + try: return _generic_factor(f, gens, args, method='factor') except PolynomialError as msg: @@ -5321,6 +5702,7 @@ else: raise PolynomialError(msg) + def intervals(F, all=False, eps=None, inf=None, sup=None, strict=False, fast=False, sqf=False): """ Compute isolating intervals for roots of ``f``. @@ -5375,6 +5757,7 @@ return result + def refine_root(f, s, t, eps=None, steps=None, fast=False, check_sqf=False): """ Refine an isolating interval of a root to the given precision. @@ -5392,10 +5775,12 @@ try: F = Poly(f) except GeneratorsNeeded: - raise PolynomialError("can't refine a root of %s, not a polynomial" % f) + raise PolynomialError( + "can't refine a root of %s, not a polynomial" % f) return F.refine_root(s, t, eps=eps, steps=steps, fast=fast, check_sqf=check_sqf) + def count_roots(f, inf=None, sup=None): """ Return the number of roots of ``f`` in ``[inf, sup]`` interval. @@ -5422,6 +5807,7 @@ return F.count_roots(inf=inf, sup=sup) + def real_roots(f, multiple=True): """ Return a list of real roots with multiplicities of ``f``. @@ -5439,10 +5825,12 @@ try: F = Poly(f, greedy=False) except GeneratorsNeeded: - raise PolynomialError("can't compute real roots of %s, not a polynomial" % f) + raise PolynomialError( + "can't compute real roots of %s, not a polynomial" % f) return F.real_roots(multiple=multiple) + def nroots(f, n=15, maxsteps=50, cleanup=True, error=False): """ Compute numerical approximations of roots of ``f``. @@ -5462,10 +5850,12 @@ try: F = Poly(f, greedy=False) except GeneratorsNeeded: - raise PolynomialError("can't compute numerical roots of %s, not a polynomial" % f) + raise PolynomialError( + "can't compute numerical roots of %s, not a polynomial" % f) return F.nroots(n=n, maxsteps=maxsteps, cleanup=cleanup, error=error) + def ground_roots(f, *gens, **args): """ Compute roots of ``f`` by factorization in the ground domain. @@ -5489,6 +5879,7 @@ return F.ground_roots() + def nth_power_roots_poly(f, n, *gens, **args): """ Construct a polynomial with n-th powers of roots of ``f``. @@ -5526,6 +5917,7 @@ else: return result + def cancel(f, *gens, **args): """ Cancel common factors in a rational function ``f``. @@ -5533,13 +5925,16 @@ Examples ======== - >>> from sympy import cancel + >>> from sympy import cancel, sqrt, Symbol >>> from sympy.abc import x + >>> A = Symbol('A', commutative=False) >>> cancel((2*x**2 - 2)/(x**2 - 2*x + 1)) (2*x + 2)/(x - 1) - + >>> cancel((sqrt(3) + sqrt(15)*A)/(sqrt(2) + sqrt(10)*A)) + sqrt(6)/2 """ + from sympy.core.exprtools import factor_terms options.allowed_flags(args, ['polys']) f = sympify(f) @@ -5547,11 +5942,15 @@ if not isinstance(f, (tuple, Tuple)): if f.is_Number: return f - else: - p, q = f.as_numer_denom() + f = factor_terms(f, radical=True) + p, q = f.as_numer_denom() - else: + elif len(f) == 2: p, q = f + elif isinstance(f, Tuple): + return factor_terms(f) + else: + raise ValueError('unexpected argument: %s' % f) try: (F, G), opt = parallel_poly_from_expr((p, q), *gens, **args) @@ -5560,6 +5959,36 @@ return f else: return S.One, p, q + except PolynomialError as msg: + if f.is_commutative: + raise PolynomialError(msg) + # non-commutative + if f.is_Mul: + c, nc = f.args_cnc(split_1=False) + nc = [cancel(i) for i in nc] + return cancel(Mul._from_args(c))*Mul(*nc) + elif f.is_Add: + c = [] + nc = [] + for i in f.args: + if i.is_commutative: + c.append(i) + else: + nc.append(cancel(i)) + return cancel(Add(*c)) + Add(*nc) + else: + reps = [] + pot = preorder_traversal(f) + next(pot) + for e in pot: + if isinstance(e, (tuple, Tuple)): + continue + try: + reps.append((e, cancel(e))) + pot.skip() # this was handled successfully + except NotImplementedError: + pass + return f.xreplace(dict(reps)) c, P, Q = F.cancel(G) @@ -5571,6 +6000,7 @@ else: return c, P, Q + def reduced(f, G, *gens, **args): """ Reduces a polynomial ``f`` modulo a set of polynomials ``G``. @@ -5601,19 +6031,20 @@ retract = False if opt.auto and domain.has_Ring and not domain.has_Field: - opt = opt.clone(dict(domain = domain.get_field())) + opt = opt.clone(dict(domain=domain.get_field())) retract = True + from sympy.polys.rings import xring + _ring, _ = xring(opt.gens, opt.domain, opt.order) + for i, poly in enumerate(polys): poly = poly.set_domain(opt.domain).rep.to_dict() - polys[i] = sdp_from_dict(poly, opt.order) - - level = len(opt.gens)-1 + polys[i] = _ring.from_dict(poly) - Q, r = sdp_div(polys[0], polys[1:], level, opt.order, opt.domain) + Q, r = polys[0].div(polys[1:]) Q = [ Poly._from_dict(dict(q), opt) for q in Q ] - r = Poly._from_dict(dict(r), opt) + r = Poly._from_dict(dict(r), opt) if retract: try: @@ -5628,6 +6059,7 @@ else: return Q, r + def groebner(F, *gens, **args): """ Computes the reduced Groebner basis for a set of polynomials. @@ -5636,20 +6068,28 @@ used to compute the basis. Allowed orders are ``lex``, ``grlex`` and ``grevlex``. If no order is specified, it defaults to ``lex``. + For more information on Groebner bases, see the references and the docstring + of `solve_poly_system()`. + Examples ======== + Example taken from [1]. + >>> from sympy import groebner >>> from sympy.abc import x, y >>> F = [x*y - 2*y, 2*y**2 - x**2] >>> groebner(F, x, y, order='lex') - GroebnerBasis([x**2 - 2*y**2, x*y - 2*y, y**3 - 2*y], x, y, domain='ZZ', order='lex') + GroebnerBasis([x**2 - 2*y**2, x*y - 2*y, y**3 - 2*y], x, y, + domain='ZZ', order='lex') >>> groebner(F, x, y, order='grlex') - GroebnerBasis([y**3 - 2*y, x**2 - 2*y**2, x*y - 2*y], x, y, domain='ZZ', order='grlex') + GroebnerBasis([y**3 - 2*y, x**2 - 2*y**2, x*y - 2*y], x, y, + domain='ZZ', order='grlex') >>> groebner(F, x, y, order='grevlex') - GroebnerBasis([y**3 - 2*y, x**2 - 2*y**2, x*y - 2*y], x, y, domain='ZZ', order='grevlex') + GroebnerBasis([y**3 - 2*y, x**2 - 2*y**2, x*y - 2*y], x, y, + domain='ZZ', order='grevlex') By default, an improved implementation of the Buchberger algorithm is used. Optionally, an implementation of the F5B algorithm can be used. @@ -5672,6 +6112,7 @@ """ return GroebnerBasis(F, *gens, **args) + def is_zero_dimensional(F, *gens, **args): """ Checks if the ideal generated by a Groebner basis is zero-dimensional. @@ -5688,6 +6129,7 @@ """ return GroebnerBasis(F, *gens, **args).is_zero_dimensional + class GroebnerBasis(Basic): """Represents a reduced Groebner basis. """ @@ -5709,14 +6151,15 @@ else: raise DomainError("can't compute a Groebner basis over %s" % opt.domain) + from sympy.polys.rings import xring + _ring, _ = xring(opt.gens, opt.domain, opt.order) + for i, poly in enumerate(polys): poly = poly.set_domain(opt.domain).rep.to_dict() - polys[i] = sdp_from_dict(poly, opt.order) - - level = len(opt.gens) - 1 + polys[i] = _ring.from_dict(poly) - G = sdp_groebner(polys, level, opt.order, opt.domain, method=opt.method) - G = [ Poly._from_dict(dict(g), opt) for g in G ] + G = _groebner(polys, _ring, method=opt.method) + G = [ Poly._from_dict(g, opt) for g in G ] if not domain.has_Field: G = [ g.clear_denoms(convert=True)[1] for g in G ] @@ -5850,9 +6293,6 @@ Computation of Zero-dimensional Groebner Bases by Change of Ordering - J.C. Faugere's lecture notes: - http://www-salsa.lip6.fr/~jcf/Papers/2010_MPRI5e.pdf - """ opt = self._options @@ -5869,17 +6309,18 @@ domain = opt.domain opt = opt.clone(dict( - domain = domain.get_field(), - order = dst_order, + domain=domain.get_field(), + order=dst_order, )) + from sympy.polys.rings import xring + _ring, _ = xring(opt.gens, opt.domain, src_order) + for i, poly in enumerate(polys): poly = poly.set_domain(opt.domain).rep.to_dict() - polys[i] = sdp_from_dict(poly, src_order) - - level = len(opt.gens) - 1 + polys[i] = _ring.from_dict(poly) - G = matrix_fglm(polys, level, src_order, dst_order, opt.domain) + G = matrix_fglm(polys, _ring, dst_order) G = [ Poly._from_dict(dict(g), opt) for g in G ] if not domain.has_Field: @@ -5925,19 +6366,20 @@ retract = False if auto and domain.has_Ring and not domain.has_Field: - opt = opt.clone(dict(domain = domain.get_field())) + opt = opt.clone(dict(domain=domain.get_field())) retract = True + from sympy.polys.rings import xring + _ring, _ = xring(opt.gens, opt.domain, opt.order) + for i, poly in enumerate(polys): poly = poly.set_domain(opt.domain).rep.to_dict() - polys[i] = sdp_from_dict(poly, opt.order) - - level = len(opt.gens) - 1 + polys[i] = _ring.from_dict(poly) - Q, r = sdp_div(polys[0], polys[1:], level, opt.order, opt.domain) + Q, r = polys[0].div(polys[1:]) Q = [ Poly._from_dict(dict(q), opt) for q in Q ] - r = Poly._from_dict(dict(r), opt) + r = Poly._from_dict(dict(r), opt) if retract: try: @@ -5973,6 +6415,7 @@ """ return self.reduce(poly)[1] == 0 + def poly(expr, *gens, **args): """ Efficiently transform an expression into a polynomial. @@ -5999,7 +6442,8 @@ if factor.is_Add: poly_factors.append(_poly(factor, opt)) elif factor.is_Pow and factor.base.is_Add and factor.exp.is_Integer: - poly_factors.append(_poly(factor.base, opt).pow(factor.exp)) + poly_factors.append( + _poly(factor.base, opt).pow(factor.exp)) else: factors.append(factor) diff -Nru python3-sympy-0.7.2/sympy/polys/polyutils.py python3-sympy-0.7.3/sympy/polys/polyutils.py --- python3-sympy-0.7.2/sympy/polys/polyutils.py 2012-10-17 03:02:22.000000000 +0000 +++ python3-sympy-0.7.3/sympy/polys/polyutils.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,6 +1,6 @@ """Useful utilities for higher level polynomial classes. """ -from sympy.polys.polyerrors import PolynomialError, GeneratorsNeeded +from sympy.polys.polyerrors import PolynomialError, GeneratorsNeeded, GeneratorsError from sympy.polys.polyoptions import build_options from sympy.core.exprtools import decompose_power @@ -23,6 +23,7 @@ _max_order = 1000 _re_gen = re.compile(r"^(.+?)(\d*)$") + def _sort_gens(gens, **args): """Sort generators in a reasonably intelligent way. """ opt = build_options(args) @@ -33,7 +34,7 @@ gens_order, wrt = {}, opt.wrt for i, gen in enumerate(opt.sort): - gens_order[gen] = i+1 + gens_order[gen] = i + 1 def order_key(gen): gen = str(gen) @@ -65,11 +66,12 @@ try: gens = sorted(gens, key=order_key) - except TypeError: # pragma: no cover + except TypeError: # pragma: no cover pass return tuple(gens) + def _unify_gens(f_gens, g_gens): """Unify generators in a reasonably intelligent way. """ f_gens = list(f_gens) @@ -86,18 +88,18 @@ for i, gen in enumerate(g_gens): if gen in common: - g_gens[i], k = common[k], k+1 + g_gens[i], k = common[k], k + 1 for gen in common: i = f_gens.index(gen) gens.extend(f_gens[:i]) - f_gens = f_gens[i+1:] + f_gens = f_gens[i + 1:] i = g_gens.index(gen) gens.extend(g_gens[:i]) - g_gens = g_gens[i+1:] + g_gens = g_gens[i + 1:] gens.append(gen) @@ -106,6 +108,7 @@ return tuple(gens) + def _analyze_gens(gens): """Support for passing generators as `*gens` and `[gens]`. """ if len(gens) == 1 and hasattr(gens[0], '__iter__'): @@ -113,6 +116,7 @@ else: return tuple(gens) + def _sort_factors(factors, **args): """Sort low-level factors in increasing 'complexity' order. """ def order_if_multiple_key(factor): @@ -127,10 +131,12 @@ else: return sorted(factors, key=order_no_multiple_key) + def _not_a_coeff(expr): """Do not treat NaN and infinities as valid polynomial coefficients. """ return expr in [S.NaN, S.Infinity, S.NegativeInfinity, S.ComplexInfinity] + def _parallel_dict_from_expr_if_gens(exprs, opt): """Transform expressions into a multinomial form given generators. """ k, indices = len(opt.gens), {} @@ -177,6 +183,7 @@ return polys, opt.gens + def _parallel_dict_from_expr_no_gens(exprs, opt): """Transform expressions into a multinomial form and figure out generators. """ if opt.domain is not None: @@ -255,21 +262,25 @@ return polys, tuple(gens) + def _dict_from_expr_if_gens(expr, opt): """Transform an expression into a multinomial form given generators. """ (poly,), gens = _parallel_dict_from_expr_if_gens((expr,), opt) return poly, gens + def _dict_from_expr_no_gens(expr, opt): """Transform an expression into a multinomial form and figure out generators. """ (poly,), gens = _parallel_dict_from_expr_no_gens((expr,), opt) return poly, gens + def parallel_dict_from_expr(exprs, **args): """Transform expressions into a multinomial form. """ reps, opt = _parallel_dict_from_expr(exprs, build_options(args)) return reps, opt.gens + def _parallel_dict_from_expr(exprs, opt): """Transform expressions into a multinomial form. """ if opt.expand is not False: @@ -285,11 +296,13 @@ return reps, opt.clone({'gens': gens}) + def dict_from_expr(expr, **args): """Transform an expression into a multinomial form. """ rep, opt = _dict_from_expr(expr, build_options(args)) return rep, opt.gens + def _dict_from_expr(expr, opt): """Transform an expression into a multinomial form. """ if expr.is_commutative is False: @@ -304,7 +317,7 @@ # TODO: Integrate this into expand() itself while any(_is_expandable_pow(i) or i.is_Mul and any(_is_expandable_pow(j) for j in i.args) for i in - Add.make_args(expr)): + Add.make_args(expr)): expr = expand_multinomial(expr) while any(i.is_Mul and any(j.is_Add for j in i.args) for i in Add.make_args(expr)): @@ -317,6 +330,7 @@ return rep, opt.clone({'gens': gens}) + def expr_from_dict(rep, *gens): """Convert a multinomial form into an expression. """ result = [] @@ -335,6 +349,7 @@ dict_from_basic = dict_from_expr basic_from_dict = expr_from_dict + def _dict_reorder(rep, gens, new_gens): """Reorder levels using dict representation. """ gens = list(gens) @@ -343,10 +358,12 @@ coeffs = list(rep.values()) new_monoms = [ [] for _ in range(len(rep)) ] + used_indices = set() for gen in new_gens: try: j = gens.index(gen) + used_indices.add(j) for M, new_M in zip(monoms, new_monoms): new_M.append(M[j]) @@ -354,8 +371,15 @@ for new_M in new_monoms: new_M.append(0) + for i, _ in enumerate(gens): + if i not in used_indices: + for monom in monoms: + if monom[i]: + raise GeneratorsError("unable to drop generators") + return list(map(tuple, new_monoms)), coeffs + class PicklableWithSlots(object): """ Mixin class that allows to pickle objects with ``__slots__``. diff -Nru python3-sympy-0.7.2/sympy/polys/rationaltools.py python3-sympy-0.7.3/sympy/polys/rationaltools.py --- python3-sympy-0.7.2/sympy/polys/rationaltools.py 2012-10-17 03:02:22.000000000 +0000 +++ python3-sympy-0.7.3/sympy/polys/rationaltools.py 2013-07-13 17:53:32.000000000 +0000 @@ -3,6 +3,7 @@ from sympy.core import Basic, Add, sympify from sympy.core.exprtools import gcd_terms + def together(expr, deep=False): """ Denest and combine rational expressions using symbolic methods. @@ -57,10 +58,7 @@ """ def _together(expr): if isinstance(expr, Basic): - if expr.is_commutative is False: - numer, denom = expr.as_numer_denom() - return numer/denom - elif expr.is_Atom or (expr.is_Function and not deep): + if expr.is_Atom or (expr.is_Function and not deep): return expr elif expr.is_Add: return gcd_terms(list(map(_together, Add.make_args(expr)))) diff -Nru python3-sympy-0.7.2/sympy/polys/rings.py python3-sympy-0.7.3/sympy/polys/rings.py --- python3-sympy-0.7.2/sympy/polys/rings.py 1970-01-01 00:00:00.000000000 +0000 +++ python3-sympy-0.7.3/sympy/polys/rings.py 2013-07-13 17:53:32.000000000 +0000 @@ -0,0 +1,1631 @@ +"""Sparse polynomial rings. """ + +from operator import add, mul + +from sympy.core.expr import Expr +from sympy.core.symbol import symbols as _symbols +from sympy.core.numbers import igcd +from sympy.core.sympify import CantSympify, sympify +from sympy.core.compatibility import is_sequence +from sympy.ntheory.multinomial import multinomial_coefficients +from sympy.polys.monomialtools import (monomial_mul, monomial_div, + monomial_ldiv, monomial_pow, monomial_min, monomial_gcd, lex) +from sympy.polys.heuristicgcd import heugcd +from sympy.polys.compatibility import IPolys +from sympy.polys.polyutils import expr_from_dict, _dict_reorder +from sympy.polys.polyerrors import CoercionFailed, GeneratorsError, GeneratorsNeeded +from sympy.polys.domains.domainelement import DomainElement +from sympy.polys.domains.polynomialring import PolynomialRing +from sympy.printing.defaults import DefaultPrinting +from functools import reduce + +def ring(symbols, domain, order=lex): + """Construct new polynomial ring returning (ring, x1, ..., xn). """ + _ring = PolyRing(symbols, domain, order) + return (_ring,) + _ring.gens + +def xring(symbols, domain, order=lex): + """Construct new polynomial ring returning (ring, (x1, ..., xn)). """ + _ring = PolyRing(symbols, domain, order) + return (_ring, _ring.gens) + +def vring(symbols, domain, order=lex): + """Construct new polynomial ring and inject generators into global namespace. """ + from inspect import currentframe + frame = currentframe().f_back + + try: + _ring = PolyRing(symbols, domain, order) + + for sym, gen in zip(_ring.symbols, _ring.gens): + frame.f_globals[sym.name] = gen + finally: + del frame # break cyclic dependencies as stated in inspect docs + + return _ring + +def _parse_symbols(symbols): + if not symbols: + raise GeneratorsNeeded("generators weren't specified") + + if isinstance(symbols, str): + return _symbols(symbols, seq=True) + elif isinstance(symbols, Expr): + return (symbols,) + elif is_sequence(symbols): + if all(isinstance(s, str) for s in symbols): + return _symbols(symbols) + elif all(isinstance(s, Expr) for s in symbols): + return symbols + + raise GeneratorsError("expected a string, Symbol or expression or a non-empty sequence of strings, Symbols or expressions") + +class PolyRing(DefaultPrinting, IPolys): + + def __init__(self, symbols, domain, order): + self.dtype = PolyElement + self.symbols = tuple(_parse_symbols(symbols)) + self.ngens = len(self.symbols) + self.domain = domain + self.order = order + + self.zero_monom = (0,)*self.ngens + self.gens = self._gens() + + def _gens(self): + """Return a list of polynomial generators. """ + one = self.domain.one + _gens = [] + for i in range(self.ngens): + expv = self.monomial_basis(i) + poly = self.zero + poly[expv] = one + _gens.append(poly) + return tuple(_gens) + + _hash = None + + def __hash__(self): + _hash = self._hash + if _hash is None: + self._hash = _hash = hash((self.symbols, self.domain, self.order)) + return _hash + + def __eq__(self, other): + return isinstance(other, PolyRing) and \ + self.symbols == other.symbols and \ + self.domain == other.domain and \ + self.order == other.order + + def __ne__(self, other): + return not self.__eq__(other) + + def clone(self, symbols=None, domain=None, order=None): + return self.__class__(symbols or self.symbols, domain or self.domain, order or self.order) + + def monomial_basis(self, i): + """Return the ith-basis element. """ + basis = [0]*self.ngens + basis[i] = 1 + return tuple(basis) + + def domain_new(self, element, orig_domain=None): + return self.domain.convert(element, orig_domain) + + def ground_new(self, coeff): + return self.term_new(self.zero_monom, coeff) + + def term_new(self, monom, coeff): + coeff = self.domain_new(coeff) + poly = self.zero + if coeff: + poly[monom] = coeff + return poly + + def ring_new(self, element): + if isinstance(element, PolyElement): + if self == element.ring: + return element + else: + raise NotImplementedError("conversion") + elif isinstance(element, str): + raise NotImplementedError("parsing") + elif isinstance(element, dict): + return self.from_dict(element) + elif isinstance(element, list): + return self.from_terms(element) + elif isinstance(element, Expr): + return self.from_expr(element) + else: + return self.ground_new(element) + + __call__ = ring_new + + def _rebuild_expr(self, expr, mapping): + domain = self.domain + + def _rebuild(expr): + generator = mapping.get(expr) + + if generator is not None: + return generator + elif expr.is_Add: + return reduce(add, list(map(_rebuild, expr.args))) + elif expr.is_Mul: + return reduce(mul, list(map(_rebuild, expr.args))) + elif expr.is_Pow and expr.exp.is_Integer and expr.exp >= 0: + return _rebuild(expr.base)**int(expr.exp) + else: + return domain.convert(expr) + + return _rebuild(sympify(expr)) + + def from_expr(self, expr): + mapping = dict(list(zip(self.symbols, self.gens))) + + try: + poly = self._rebuild_expr(expr, mapping) + except CoercionFailed: + raise ValueError("expected an expression convertible to a polynomial in %s, got %s" % (self, expr)) + else: + return self.ring_new(poly) + + @property + def zero(self): + return self.dtype(self) + + @property + def one(self): + poly = self.zero + poly[self.zero_monom] = self.domain.one + return poly + + def from_dict(self, d): + domain_new = self.domain_new + poly = self.zero + + for monom, coeff in d.items(): + coeff = domain_new(coeff) + if coeff: + poly[monom] = coeff + + return poly + + def from_terms(self, terms): + return self.from_dict(dict(terms)) + + def _drop(self, gen): + if isinstance(gen, int): + i = gen + if not (0 <= i and i < self.ngens): + raise ValueError("invalid generator index") + else: + if gen not in self.gens: + raise ValueError("invalid generator") + else: + i = list(self.gens).index(gen) + + if self.ngens == 1: + raise ValueError("univariate polynomial") # TODO: return ground domain + else: + symbols = list(self.symbols) + del symbols[i] + return i, self.__class__(symbols, self.domain, self.order) + + def drop(self, gen): + return self._drop(gen)[1] + + def __getitem__(self, key): + return self.__class__(self.symbols[key], self.domain, self.order) + + def to_ground(self): + ground = getattr(self.domain, "dom", None) # TODO: use CompositeDomain + if ground is not None: + return self.__class__(self.symbols, ground, self.order) + else: + raise ValueError("%s is not a composite domain" % self.domain) + + def to_domain(self): + return PolynomialRing(self) + + def to_field(self): + from sympy.polys.fields import FracField + return FracField(self.symbols, self.domain, self.order) + +class PolyElement(DomainElement, DefaultPrinting, CantSympify, dict): + def __init__(self, ring, init=[]): + self.ring = ring + dict.__init__(self, init) + + def new(self, init): + return self.__class__(self.ring, init) + + def parent(self): + return self.ring.to_domain() + + _hash = None + + def __hash__(self): + # XXX: This computes a hash of a dictionary, but currently we don't + # protect dictionary from being changed so any use site modifications + # will make hashing go wrong. Use this feature with caution until we + # figure out how to make a safe API without compromising speed of this + # low-level class. + _hash = self._hash + if _hash is None: + self._hash = _hash = hash((self.ring, frozenset(list(self.items())))) + return _hash + + def copy(self): + """Return a copy of polynomial self. + + Polynomials are mutable; if one is interested in preserving + a polynomial, and one plans to use inplace operations, one + can copy the polynomial. This method makes a shallow copy. + + Examples + ======== + + >>> from sympy.polys.domains import ZZ + >>> from sympy.polys.rings import ring + >>> R, x, y = ring('x, y', ZZ) + >>> p = (x + y)**2 + >>> p1 = p.copy() + >>> p2 = p + >>> p[R.zero_monom] = 3 + >>> p + x**2 + 2*x*y + y**2 + 3 + >>> p1 + x**2 + 2*x*y + y**2 + >>> p2 + x**2 + 2*x*y + y**2 + 3 + + """ + return self.new(self) + + def set_ring(self, new_ring): + if self.ring == new_ring: + return self + elif self.ring.symbols != new_ring.symbols: + terms = list(zip(*_dict_reorder(self, self.ring.symbols, new_ring.symbols))) + return new_ring.from_terms(terms) + else: + return new_ring.from_dict(self) + + def as_expr(self, *symbols): + if symbols and len(symbols) != self.ring.ngens: + raise ValueError("not enough symbols, expected %s got %s" % (self.ring.ngens, len(symbols))) + else: + symbols = self.ring.symbols + + return expr_from_dict(self.as_expr_dict(), *symbols) + + def as_expr_dict(self): + to_sympy = self.ring.domain.to_sympy + return dict([ (monom, to_sympy(coeff)) for monom, coeff in self.terms() ]) + + def clear_denoms(self): + domain = self.ring.domain + denom = domain.denom + + ground_ring = domain.get_ring() + common = ground_ring.one + lcm = ground_ring.lcm + + for coeff in list(self.values()): + common = lcm(common, denom(coeff)) + + poly = self.new([ (k, v*common) for k, v in list(self.items()) ]) + return common, poly + + def strip_zero(self): + """Eliminate monomials with zero coefficient. """ + for k, v in list(self.items()): + if not v: + del self[k] + + def variables(self): + """Return the tuple of the indices of the variables in self. + + Examples + ======== + + >>> from sympy.polys.domains import ZZ + >>> from sympy.polys.rings import ring + >>> _, x, y, z = ring('x, y, z', ZZ) + >>> p = x + y**2 + x*y + >>> p.variables() + (0, 1) + + """ + indices = [] + for expv in self: + for i, e in enumerate(expv): + if e and i not in indices: + indices.append(i) + indices.sort() + return tuple(indices) + + def __eq__(p1, p2): + """Equality test for polynomials. + + Examples + ======== + + >>> from sympy.polys.domains import ZZ + >>> from sympy.polys.rings import ring + >>> _, x, y = ring('x, y', ZZ) + >>> p1 = (x + y)**2 + (x - y)**2 + >>> p1 == 4*x*y + False + >>> p1 == 2*(x**2 + y**2) + True + + """ + if not p2: + return not p1 + elif isinstance(p2, PolyElement) and p1.ring == p2.ring: + return dict.__eq__(p1, p2) + else: + if len(p1) > 1: + return False + else: + return p1.get(p1.ring.zero_monom) == p2 + + def __ne__(p1, p2): + return not p1.__eq__(p2) + + def drop(self, gen): + i, ring = self.ring._drop(gen) + poly = ring.zero + for k, v in self.items(): + if k[i] == 0: + K = list(k) + del K[i] + poly[tuple(K)] = v + else: + raise ValueError("can't drop %s" % gen) + return poly + + def to_dense(self): + from sympy.polys.densebasic import dmp_from_dict + return dmp_from_dict(self, self.ring.ngens-1, self.ring.domain) + + def to_dict(self): + return dict(self) + + @property + def is_generator(self): + return self in self.ring.gens + + @property + def is_ground(self): + return not self or (len(self) == 1 and self.ring.zero_monom in self) + + @property + def is_monomial(self): + return not self or (len(self) == 1 and self.LC == 1) + + @property + def is_term(self): + return len(self) <= 1 + + @property + def is_negative(self): + return self.ring.domain.is_negative(self.LC) + + @property + def is_positive(self): + return self.ring.domain.is_positive(self.LC) + + @property + def is_nonnegative(self): + return self.ring.domain.is_nonnegative(self.LC) + + @property + def is_nonpositive(self): + return self.ring.domain.is_nonpositive(self.LC) + + def __neg__(self): + return self*(-1) + + def __pos__(self): + return self + + def __add__(p1, p2): + """Add two polynomials. + + Examples + ======== + + >>> from sympy.polys.domains import ZZ + >>> from sympy.polys.rings import ring + >>> _, x, y = ring('x, y', ZZ) + >>> (x + y)**2 + (x - y)**2 + 2*x**2 + 2*y**2 + + """ + if not p2: + return p1.copy() + ring = p1.ring + if isinstance(p2, PolyElement): + if ring == p2.ring: + if len(p2) == 1: + p = p1.copy() + [(m, c)] = list(p2.items()) + nc = p.get(m, ring.domain.zero) + c + if nc: + p[m] = nc + else: + del p[m] + return p + else: + p = ring.zero + for k, v in p1.items(): + if k in p2: + r = v + p2[k] + if r: + p[k] = r + else: + p[k] = v + for k, v in p2.items(): + if k not in p1: + p[k] = v + return p + elif isinstance(ring.domain, PolynomialRing) and ring.domain.ring == p2.ring: + pass + elif isinstance(p2.ring.domain, PolynomialRing) and p2.ring.domain.ring == ring: + return p2.__radd__(p1) + else: + return NotImplemented + + try: + cp2 = ring.domain_new(p2) + except CoercionFailed: + return NotImplemented + else: + p = p1.copy() + if not cp2: + return p + zm = ring.zero_monom + if zm not in list(p1.keys()): + p[zm] = cp2 + else: + if p2 == -p[zm]: + del p[zm] + else: + p[zm] += cp2 + return p + + def __radd__(p1, n): + p = p1.copy() + if not n: + return p + ring = p1.ring + zm = ring.zero_monom + if zm not in list(p1.keys()): + p[zm] = ring.domain_new(n) + else: + if n == -p[zm]: + del p[zm] + else: + p[zm] += n + return p + + def __sub__(p1, p2): + """Subtract polynomial p2 from p1. + + Examples + ======== + + >>> from sympy.polys.domains import ZZ + >>> from sympy.polys.rings import ring + >>> _, x, y = ring('x, y', ZZ) + >>> p1 = x + y**2 + >>> p2 = x*y + y**2 + >>> p1 - p2 + -x*y + x + + """ + if not p2: + return p1.copy() + ring = p1.ring + if isinstance(p2, PolyElement): + if ring == p2.ring: + if len(p2) == 1: + p = p1.copy() + [(m, c)] = list(p2.items()) + nc = p.get(m, ring.domain.zero) - c + if nc: + p[m] = nc + else: + del p[m] + return p + else: + p = ring.zero + for k, v in p1.items(): + if k in p2: + r = v - p2[k] + if r: + p[k] = r + else: + p[k] = v + for k, v in p2.items(): + if k not in p1: + p[k] = -v + return p + elif isinstance(ring.domain, PolynomialRing) and ring.domain.ring == p2.ring: + pass + elif isinstance(p2.ring.domain, PolynomialRing) and p2.ring.domain.ring == ring: + return p2.__rsub__(p1) + else: + return NotImplemented + + try: + p2 = ring.domain_new(p2) + except CoercionFailed: + return NotImplemented + else: + p = p1.copy() + zm = ring.zero_monom + if zm not in list(p1.keys()): + p[zm] = -p2 + else: + if p2 == p[zm]: + del p[zm] + else: + p[zm] -= p2 + return p + + def __rsub__(p1, n): + """n - p1 with n convertible to the coefficient domain. + + Examples + ======== + + >>> from sympy.polys.domains import ZZ + >>> from sympy.polys.rings import ring + >>> _, x, y = ring('x, y', ZZ) + >>> p = x + y + >>> 4 - p + -x - y + 4 + + """ + p = p1.ring.zero + for expv in p1: + p[expv] = -p1[expv] + p += n + return p + + def __mul__(p1, p2): + """Multiply two polynomials. + + Examples + ======== + + >>> from sympy.polys.domains import QQ + >>> from sympy.polys.rings import ring + >>> _, x, y = ring('x, y', QQ) + >>> p1 = x + y + >>> p2 = x - y + >>> p1*p2 + x**2 - y**2 + + """ + ring = p1.ring + p = ring.zero + if not p2: + return p + if isinstance(p2, PolyElement): + if ring == p2.ring: + get = p.get + p2it = list(p2.items()) + for exp1, v1 in p1.items(): + for exp2, v2 in p2it: + exp = monomial_mul(exp1, exp2) + p[exp] = get(exp, 0) + v1*v2 + p.strip_zero() + return p + elif isinstance(ring.domain, PolynomialRing) and ring.domain.ring == p2.ring: + pass + elif isinstance(p2.ring.domain, PolynomialRing) and p2.ring.domain.ring == ring: + return p2.__rmul__(p1) + else: + return NotImplemented + + try: + p2 = ring.domain_new(p2) + except CoercionFailed: + return NotImplemented + else: + for exp1, v1 in p1.items(): + v = v1*p2 + if v: + p[exp1] = v + return p + + def __rmul__(p1, p2): + """p2 * p1 with p2 in the coefficient domain of p1. + + Examples + ======== + + >>> from sympy.polys.domains import ZZ + >>> from sympy.polys.rings import ring + >>> _, x, y = ring('x, y', ZZ) + >>> p = x + y + >>> 4 * p + 4*x + 4*y + + """ + p = p1.ring.zero + if not isinstance(p2, PolyElement): + if not p2: + return p + p2 = p.ring.domain_new(p2) + for exp1, v1 in p1.items(): + v = p2*v1 + if v: + p[exp1] = v + return p + + def __pow__(self, n): + """raise polynomial to power `n` + + Examples + ======== + + >>> from sympy.polys.domains import ZZ + >>> from sympy.polys.rings import ring + >>> _, x, y = ring('x, y', ZZ) + >>> p = x + y**2 + >>> p**3 + x**3 + 3*x**2*y**2 + 3*x*y**4 + y**6 + + """ + ring = self.ring + n = int(n) + if n < 0: + if (len(self) == 1): + p = ring.zero + k, v = list(self.items())[0] + kn = monomial_pow(k, n) + p[kn] = v**n + return p + raise ValueError('n >= 0 is required') + if n == 0: + if self: + return ring(1) + else: + raise ValueError + elif len(self) == 1: + p = ring.zero + k, v = list(self.items())[0] + # treat case abs(v) = 1 separately to deal with the case + # in which n is too large to be allowed in v**n + kn = monomial_pow(k, n) + if v == 1: + p[kn] = v + elif v == -1: + if n % 2 == 0: + p[kn] = -v + else: + p[kn] = v + else: + p[kn] = v**n + return p + elif n == 1: + return self.copy() + elif n == 2: + return self.square() + elif n == 3: + return self*self.square() + elif len(self) <= 5: # TODO: use an actuall density measure + return self._pow_multinomial(n) + else: + return self._pow_generic(n) + + def _pow_generic(self, n): + p = self.ring.one + + while True: + if n & 1: + p = p*self + n -= 1 + if not n: + break + + self = self.square() + n = n // 2 + + return p + + def _pow_multinomial(self, n): + multinomials = list(multinomial_coefficients(len(self), n).items()) + zero_monom = self.ring.zero_monom + terms = list(self.terms()) + poly = self.ring.zero + + for multinomial, multinomial_coeff in multinomials: + product_monom = zero_monom + product_coeff = multinomial_coeff + + for exp, (monom, coeff) in zip(multinomial, terms): + if exp: + product_monom = [ a + b*exp for a, b in zip(product_monom, monom) ] + product_coeff *= coeff**exp + + poly[tuple(product_monom)] = product_coeff + + return poly + + def square(self): + """square of a polynomial + + Examples + ======== + + >>> from sympy.polys.rings import ring + >>> from sympy.polys.domains import ZZ + >>> _, x, y = ring('x, y', ZZ) + >>> p = x + y**2 + >>> p.square() + x**2 + 2*x*y**2 + y**4 + """ + ring = self.ring + p = ring.zero + get = p.get + keys = list(self.keys()) + for i in range(len(keys)): + k1 = keys[i] + pk = self[k1] + for j in range(i): + k2 = keys[j] + exp = monomial_mul(k1, k2) + p[exp] = get(exp, 0) + pk*self[k2] + p = p.imul_num(2) + get = p.get + for k, v in self.items(): + k2 = monomial_mul(k, k) + p[k2] = get(k2, 0) + v**2 + p.strip_zero() + return p + + def __truediv__(p1, p2): + """division by a term in the coefficient domain or + exact division by a polynomial + + Examples + ======== + + >>> from sympy.polys.domains import QQ + >>> from sympy.polys.rings import ring + >>> _, x, y = ring('x, y', QQ) + >>> p1 = (x**2 + x + y)*(x**2 - y**2) + >>> p2 = x + y + >>> p3 = p1/p2 + >>> p4 = (x**2 + x + y)*(x - y) + >>> p3 == p4 + True + + """ + ring = p1.ring + if isinstance(p2, PolyElement) and ring == p2.ring: + if len(p2) == 1: + term = list(p2.terms())[0] + return p1.quo_term(term) + else: + return p1.quo(p2) + elif not p2: + raise ZeroDivisionError + else: + try: + p2 = ring.domain.convert(p2) + except CoercionFailed: + return NotImplemented + else: + return p1.quo_ground(p2) + + __floordiv__ = __div__ = __truediv__ + + def __mod__(self, other): + return self.rem(other) + + def __divmod__(self, other): + return self.div(other) + + def _term_div(self): + zm = self.ring.zero_monom + domain = self.ring.domain + domain_quo = domain.quo + + if domain.has_Field or not domain.is_Exact: + def term_div(xxx_todo_changeme, xxx_todo_changeme1): + (a_lm, a_lc) = xxx_todo_changeme + (b_lm, b_lc) = xxx_todo_changeme1 + if b_lm == zm: # apparently this is a very common case + monom = a_lm + else: + monom = monomial_div(a_lm, b_lm) + if monom is not None: + return monom, domain_quo(a_lc, b_lc) + else: + return None + else: + def term_div(xxx_todo_changeme2, xxx_todo_changeme3): + (a_lm, a_lc) = xxx_todo_changeme2 + (b_lm, b_lc) = xxx_todo_changeme3 + if b_lm == zm: # apparently this is a very common case + monom = a_lm + else: + monom = monomial_div(a_lm, b_lm) + if not (monom is None or a_lc % b_lc): + return monom, domain_quo(a_lc, b_lc) + else: + return None + + return term_div + + def div(self, fv): + """Division algorithm, see [CLO] p64. + + fv array of polynomials + return qv, r such that + self = sum(fv[i]*qv[i]) + r + + All polynomials are required not to be Laurent polynomials. + + Examples + ======== + + >>> from sympy.polys.rings import ring + >>> from sympy.polys.domains import ZZ + >>> _, x, y = ring('x, y', ZZ) + >>> f = x**3 + >>> f0 = x - y**2 + >>> f1 = x - y + >>> qv, r = f.div((f0, f1)) + >>> qv[0] + x**2 + x*y**2 + y**4 + >>> qv[1] + 0 + >>> r + y**6 + + TODO restrict to positive exponents + """ + ring = self.ring + domain = ring.domain + ret_single = False + if isinstance(fv, PolyElement): + ret_single = True + fv = [fv] + if not self: + if ret_single: + return ring.zero, ring.zero + else: + return [], ring.zero + for f in fv: + if f.ring != ring: + raise ValueError('self and f must have the same ring') + gens = ring.gens + s = len(fv) + qv = [ring.zero for i in range(s)] + p = self.copy() + r = ring.zero + term_div = self._term_div() + expvs = [fx.leading_expv() for fx in fv] + while p: + i = 0 + divoccurred = 0 + while i < s and divoccurred == 0: + expv = p.leading_expv() + term = term_div((expv, p[expv]), (expvs[i], fv[i][expvs[i]])) + if term is not None: + expv1, c = term + qv[i] = qv[i]._iadd_monom((expv1, c)) + p = p._iadd_poly_monom(fv[i], (expv1, -c)) + divoccurred = 1 + else: + i += 1 + if not divoccurred: + expv = p.leading_expv() + r = r._iadd_monom((expv, p[expv])) + del p[expv] + if expv == ring.zero_monom: + r += p + if ret_single: + if not qv: + return ring.zero, r + else: + return qv[0], r + else: + return qv, r + + def quo(f, G): + return f.div(G)[0] + + def rem(f, G): + if isinstance(G, PolyElement): + G = [G] + domain = f.ring.domain + order = f.ring.order + r = f.ring.zero + term_div = f._term_div() + ltf = f.LT + f = f.copy() + get = f.get + while f: + for g in G: + tq = term_div(ltf, g.LT) + if tq is not None: + m, c = tq + for mg, cg in g.terms(): + m1 = monomial_mul(mg, m) + c1 = get(m1, 0) - c*cg + if not c1: + del f[m1] + else: + f[m1] = c1 + if f: + if order is lex: + ltm = max(f) + else: + ltm = max(f, key=order) + ltf = ltm, f[ltm] + + break + else: + ltm, ltc = ltf + if ltm in r: + r[ltm] += ltc + else: + r[ltm] = ltc + del f[ltm] + if f: + if order is lex: + ltm = max(f) + else: + ltm = max(f, key=order) + ltf = ltm, f[ltm] + return r + + def _iadd_monom(self, mc): + """add to self the monomial coeff*x0**i0*x1**i1*... + unless self is a generator -- then just return the sum of the two. + + mc is a tuple, (monom, coeff), where monomial is (i0, i1, ...) + + Examples + ======== + + >>> from sympy.polys.rings import ring + >>> from sympy.polys.domains import ZZ + + >>> _, x, y = ring('x, y', ZZ) + >>> p = x**4 + 2*y + >>> m = (1, 2) + >>> p1 = p._iadd_monom((m, 5)) + >>> p1 + x**4 + 5*x*y**2 + 2*y + >>> p1 is p + True + >>> p = x + >>> p1 = p._iadd_monom((m, 5)) + >>> p1 + 5*x*y**2 + x + >>> p1 is p + False + + """ + if self in self.ring.gens: + self = self.copy() + expv, coeff = mc + c = self.get(expv) + if c is None: + self[expv] = coeff + else: + c += coeff + if c: + self[expv] = c + else: + del self[expv] + return self + + def _iadd_poly_monom(p1, p2, mc): + """add to self the product of (p)*(coeff*x0**i0*x1**i1*...) + unless self is a generator -- then just return the sum of the two. + + mc is a tuple, (monom, coeff), where monomial is (i0, i1, ...) + + Examples + ======== + + >>> from sympy.polys.rings import ring + >>> from sympy.polys.domains import ZZ + + >>> _, x, y, z = ring('x, y, z', ZZ) + >>> p1 = x**4 + 2*y + >>> p2 = y + z + >>> m = (1, 2, 3) + >>> p1 = p1._iadd_poly_monom(p2, (m, 3)) + >>> p1 + x**4 + 3*x*y**3*z**3 + 3*x*y**2*z**4 + 2*y + + """ + if p1 in p1.ring.gens: + p1 = p1.copy() + (m, c) = mc + get = p1.get + zero = p1.ring.domain.zero + for k, v in p2.items(): + ka = monomial_mul(k, m) + coeff = get(ka, zero) + v*c + if coeff: + p1[ka] = coeff + else: + del p1[ka] + return p1 + + def leading_expv(self): + """leading monomial tuple according to the monomial ordering + + Examples + ======== + + >>> from sympy.polys.rings import ring + >>> from sympy.polys.domains import QQ + >>> _, x, y, z = ring('x, y, z', QQ) + >>> p = x**4 + x**3*y + x**2*z**2 + z**7 + >>> p.leading_expv() + (4, 0, 0) + + """ + if self: + order = self.ring.order + if order is lex: + return max(self) + else: + return max(self, key=order) + else: + return None + + @property + def LM(self): + expv = self.leading_expv() + if expv is None: + return self.ring.zero_monom + else: + return expv + + @property + def LT(self): + expv = self.leading_expv() + if expv is None: + return (self.ring.zero_monom, self.ring.domain.zero) + else: + return (expv, self._get_coeff(expv)) + + @property + def LC(self): + return self._get_coeff(self.leading_expv()) + + def _get_coeff(self, expv): + return self.get(expv, self.ring.domain.zero) + + def coeff(self, element): + if element == 1: + return self._get_coeff(self.ring.zero_monom) + elif isinstance(element, PolyElement): + terms = list(element.terms()) + if len(terms) == 1: + monom, coeff = terms[0] + if coeff == self.ring.domain.one: + return self._get_coeff(monom) + + raise ValueError("expected a monomial, got %s" % element) + + @property + def leading_monom(self): + p = self.ring.zero + expv = self.leading_expv() + if expv: + p[expv] = self.ring.one + return p + + @property + def leading_term(self): + """Leading term according to the monomial ordering. + + Examples + ======== + + >>> from sympy.polys.rings import ring + >>> from sympy.polys.domains import QQ + + >>> _, x, y = ring('x, y', QQ) + >>> p = (x + y)**4 + >>> p.leading_term + x**4 + + """ + p = self.ring.zero + expv = self.leading_expv() + if expv: + p[expv] = self[expv] + return p + + def coeffs(self): + return iter(self.values()) + + def monoms(self): + return iter(self.keys()) + + def terms(self): + return iter(self.items()) + + def imul_num(p, c): + """multiply inplace the polynomial p by an element in the + coefficient ring, provided p is not one of the generators; + else multiply not inplace + + Examples + ======== + + >>> from sympy.polys.rings import ring + >>> from sympy.polys.domains import ZZ + + >>> _, x, y = ring('x, y', ZZ) + >>> p = x + y**2 + >>> p1 = p.imul_num(3) + >>> p1 + 3*x + 3*y**2 + >>> p1 is p + True + >>> p = x + >>> p1 = p.imul_num(3) + >>> p1 + 3*x + >>> p1 is p + False + + """ + if p in p.ring.gens: + return p*c + if not c: + p.clear() + return + for exp in p: + p[exp] *= c + return p + + def mul_term(f, term): + monom, coeff = term + + if not f or not coeff: + return f.ring.zero + elif monom == f.ring.zero_monom: + return f.mul_ground(coeff) + + terms = [ (monomial_mul(f_monom, monom), f_coeff*coeff) for f_monom, f_coeff in f.items() ] + return f.new(terms) + + def mul_monom(f, monom): + terms = [ (monomial_mul(f_monom, monom), f_coeff) for f_monom, f_coeff in f.items() ] + return f.new(terms) + + def monic(f): + """Divides all coefficients by the leading coefficient. """ + if not f: + return f + else: + return f.quo_ground(f.LC) + + def primitive(f): + """Returns content and a primitive polynomial. """ + cont = f.content() + return cont, f.quo_ground(cont) + + def content(f): + """Returns GCD of polynomial's coefficients. """ + domain = f.ring.domain + cont = domain.zero + gcd = domain.gcd + + for coeff in f.coeffs(): + cont = gcd(cont, coeff) + + return cont + + def mul_ground(f, x): + if not x: + return f.ring.zero + + terms = [ (monom, coeff*x) for monom, coeff in f.terms() ] + return f.new(terms) + + def quo_ground(f, x): + domain = f.ring.domain + + if not x: + raise ZeroDivisionError('polynomial division') + if not f or x == domain.one: + return f + + if domain.has_Field or not domain.is_Exact: + quo = domain.quo + terms = [ (monom, quo(coeff, x)) for monom, coeff in f.terms() ] + else: + terms = [ (monom, coeff // x) for monom, coeff in f.terms() if not (coeff % x) ] + + return f.new(terms) + + def quo_term(f, term): + monom, coeff = term + + if not coeff: + raise ZeroDivisionError + elif not f: + return f.ring.zero + elif monom == f.ring.zero_monom: + return f.quo_ground(coeff) + + term_div = f._term_div() + + terms = [ term_div(t, term) for t in f.terms() ] + return f.new([ t for t in terms if t is not None ]) + + def trunc_ground(f, p): + if f.ring.domain.is_ZZ: + terms = [] + + for monom, coeff in f.terms(): + coeff = coeff % p + + if coeff > p // 2: + coeff = coeff - p + + terms.append((monom, coeff)) + else: + terms = [ (monom, coeff % p) for monom, coeff in f.terms() ] + + poly = f.new(terms) + poly.strip_zero() + return poly + + def extract_ground(f, g): + fc = f.content() + gc = g.content() + + gcd = f.ring.domain.gcd(fc, gc) + + f = f.quo_ground(gcd) + g = g.quo_ground(gcd) + + return gcd, f, g + + def max_norm(f): + if not f: + return f.ring.domain.zero + else: + ground_abs = f.ring.domain.abs + return max([ ground_abs(coeff) for coeff in f.coeffs() ]) + + def deflate(f, *G): + ring = f.ring + polys = [f] + list(G) + + J = [0]*ring.ngens + + for p in polys: + for monom in p.monoms(): + for i, m in enumerate(monom): + J[i] = igcd(J[i], m) + + for i, b in enumerate(J): + if not b: + J[i] = 1 + + J = tuple(J) + + if all(b == 1 for b in J): + return J, polys + + H = [] + + for p in polys: + h = ring.zero + + for I, coeff in p.terms(): + N = [ i // j for i, j in zip(I, J) ] + h[tuple(N)] = coeff + + H.append(h) + + return J, H + + def inflate(f, J): + poly = f.ring.zero + + for I, coeff in f.terms(): + N = [ i*j for i, j in zip(I, J) ] + poly[tuple(N)] = coeff + + return poly + + def lcm(f, g): + domain = f.ring.domain + + if not domain.has_Field: + fc, f = f.primitive() + gc, g = g.primitive() + c = domain.lcm(fc, gc) + + h = (f*g).quo(f.gcd(g)) + + if not domain.has_Field: + return h.mul_ground(c) + else: + return h.monic() + + def gcd(f, g): + return f.cofactors(g)[0] + + def cofactors(f, g): + if not f and not g: + zero = f.ring.zero + return zero, zero, zero + elif not f: + h, cff, cfg = f._gcd_zero(g) + return h, cff, cfg + elif not g: + h, cfg, cff = g._gcd_zero(f) + return h, cff, cfg + elif len(f) == 1: + h, cff, cfg = f._gcd_monom(g) + return h, cff, cfg + elif len(g) == 1: + h, cfg, cff = g._gcd_monom(f) + return h, cff, cfg + + J, (f, g) = f.deflate(g) + h, cff, cfg = f._gcd(g) + + return (h.inflate(J), cff.inflate(J), cfg.inflate(J)) + + def _gcd_zero(f, g): + one, zero = f.ring.one, f.ring.zero + if g.is_nonnegative: + return g, zero, one + else: + return -g, zero, -one + + def _gcd_monom(f, g): + ring = f.ring + ground_gcd = ring.domain.gcd + ground_quo = ring.domain.quo + mf, cf = list(f.terms())[0] + _mgcd, _cgcd = mf, cf + for mg, cg in g.terms(): + _mgcd = monomial_gcd(_mgcd, mg) + _cgcd = ground_gcd(_cgcd, cg) + h = f.new([(_mgcd, _cgcd)]) + cff = f.new([(monomial_ldiv(mf, _mgcd), ground_quo(cf, _cgcd))]) + cfg = f.new([(monomial_ldiv(mg, _mgcd), ground_quo(cg, _cgcd)) for mg, cg in g.terms()]) + return h, cff, cfg + + def _gcd(f, g): + ring = f.ring + + if ring.domain.is_QQ: + return f._gcd_QQ(g) + elif ring.domain.is_ZZ: + return f._gcd_ZZ(g) + else: # TODO: don't use dense representation (port PRS algorithms) + return ring.dmp_inner_gcd(f, g) + + def _gcd_ZZ(f, g): + return heugcd(f, g) + + def _gcd_QQ(f, g): + ring = f.ring + new_ring = ring.clone(domain=ring.domain.get_ring()) + + cf, f = f.clear_denoms() + cg, g = g.clear_denoms() + + f = f.set_ring(new_ring) + g = g.set_ring(new_ring) + + h, cff, cfg = f._gcd_ZZ(g) + + h = h.set_ring(ring) + c, h = h.LC, h.monic() + + cff = cff.set_ring(ring).mul_ground(ring.domain.quo(c, cf)) + cfg = cfg.set_ring(ring).mul_ground(ring.domain.quo(c, cg)) + + return h, cff, cfg + + def cancel(f, g): + """ + Cancel common factors in a rational function ``f/g``. + + Examples + ======== + + >>> from sympy.polys import ring, ZZ + >>> R, x,y = ring("x,y", ZZ) + + >>> (2*x**2 - 2).cancel(x**2 - 2*x + 1) + (2*x + 2, x - 1) + + """ + ring = f.ring + new_ring = None + domain = ring.domain + + if domain.has_Field and domain.has_assoc_Ring: + new_ring = ring.clone(domain=domain.get_ring()) + + cq, f = f.clear_denoms() + cp, g = g.clear_denoms() + + f = f.set_ring(new_ring) + g = g.set_ring(new_ring) + else: + cp = cq = domain.one + + _, p, q = f.cofactors(g) + + if new_ring is not None: + p = p.set_ring(ring) + q = q.set_ring(ring) + + p_neg = p.is_negative + q_neg = q.is_negative + + if p_neg and q_neg: + p, q = -p, -q + elif p_neg: + cp, p = -cp, -p + elif q_neg: + cp, q = -cp, -q + + p = p.mul_ground(cp) + q = q.mul_ground(cq) + + return p, q + + def diff(f, x): + """Computes partial derivative in ``x``. + + Examples + ======== + + >>> from sympy.polys.rings import ring + >>> from sympy.polys.domains import ZZ + + >>> _, x, y = ring("x,y", ZZ) + >>> p = x + x**2*y**3 + >>> p.diff(x) + 2*x*y**3 + 1 + + """ + ring = f.ring + i = list(ring.gens).index(x) + m = ring.monomial_basis(i) + g = ring.zero + for expv, coeff in f.terms(): + if expv[i]: + e = monomial_ldiv(expv, m) + g[e] = coeff*expv[i] + return g + + def evaluate(f, x, a=None): + if isinstance(x, list) and a is None: + (X, a), x = x[0], x[1:] + f = f.evaluate(X, a) + if not x: + return f + else: + x = [ (Y.drop(X), a) for (Y, a) in x ] + return f.evaluate(x) + + ring = f.ring + i = list(ring.gens).index(x) + + if ring.ngens == 1: + result = ring.domain.zero + + for (n,), coeff in f.terms(): + result += coeff*a**n + + return result + else: + poly = ring[1:].zero + + for monom, coeff in f.terms(): + n, monom = monom[i], monom[:i] + monom[i+1:] + coeff = coeff*a**n + + if monom in poly: + coeff = coeff + poly[monom] + + if coeff: + poly[monom] = coeff + else: + del poly[monom] + else: + if coeff: + poly[monom] = coeff + + return poly + + def subs(f, x, a=None): + if isinstance(x, list) and a is None: + for X, a in x: + f = f.subs(X, a) + return f + + ring = f.ring + i = list(ring.gens).index(x) + + if ring.ngens == 1: + result = ring.domain.zero + + for (n,), coeff in f.terms(): + result += coeff*a**n + + return ring.ground_new(result) + else: + poly = ring.zero + + for monom, coeff in f.terms(): + n, monom = monom[i], monom[:i] + (0,) + monom[i+1:] + coeff = coeff*a**n + + if monom in poly: + coeff = coeff + poly[monom] + + if coeff: + poly[monom] = coeff + else: + del poly[monom] + else: + if coeff: + poly[monom] = coeff + + return poly + + def compose(f, x, a=None): + ring = f.ring + poly = ring.zero + gens_map = dict(list(zip(ring.gens, list(range(ring.ngens))))) + + if a is not None: + replacements = [(x, a)] + else: + if isinstance(x, list): + replacements = list(x) + elif isinstance(x, dict): + replacements = sorted(list(x.items()), key=lambda k__: gens_map[k__[0]]) + else: + raise ValueError("expected a generator, value pair a sequence of such pairs") + + for k, (x, g) in enumerate(replacements): + replacements[k] = (gens_map[x], g) + + for monom, coeff in f.terms(): + monom = list(monom) + subpoly = ring.one + + for i, g in replacements: + n, monom[i] = monom[i], 0 + if n: + subpoly *= g**n + + subpoly = subpoly.mul_term((tuple(monom), coeff)) + poly += subpoly + + return poly diff -Nru python3-sympy-0.7.2/sympy/polys/rootisolation.py python3-sympy-0.7.3/sympy/polys/rootisolation.py --- python3-sympy-0.7.2/sympy/polys/rootisolation.py 2012-10-17 03:02:22.000000000 +0000 +++ python3-sympy-0.7.3/sympy/polys/rootisolation.py 2013-07-13 17:53:32.000000000 +0000 @@ -28,6 +28,7 @@ RefinementFailed, DomainError) + def dup_sturm(f, K): """ Computes the Sturm sequence of ``f`` in ``F[x]``. @@ -41,13 +42,11 @@ Examples ======== - >>> from sympy.polys.domains import QQ - >>> from sympy.polys.rootisolation import dup_sturm - - >>> f = QQ.map([1, -2, 1, -3]) + >>> from sympy.polys import ring, QQ + >>> R, x = ring("x", QQ) - >>> dup_sturm(f, QQ) - [[1/1, -2/1, 1/1, -3/1], [3/1, -4/1, 1/1], [2/9, 25/9], [-2079/4]] + >>> R.dup_sturm(x**3 - 2*x**2 + x - 3) + [x**3 - 2*x**2 + x - 3, 3*x**2 - 4*x + 1, 2/9*x + 25/9, -2079/4] References ========== @@ -68,6 +67,7 @@ return sturm[:-1] + def dup_root_upper_bound(f, K): """Compute LMQ upper bound for `f`'s positive roots. """ n, t, P = len(f), K.one, [] @@ -83,7 +83,7 @@ a, Q = K.log(-f[i], 2), [] - for j in range(i+1, n): + for j in range(i + 1, n): if f[j] <= 0: continue @@ -101,7 +101,8 @@ if not P: return None else: - return 2.0**(max(P)+1) + return 2.0**(max(P) + 1) + def dup_root_lower_bound(f, K): """Compute LMQ lower bound for `f`'s positive roots. """ @@ -112,6 +113,7 @@ else: return None + def _mobius_from_interval(I, field): """Convert an open interval to a Mobius transform. """ s, t = I @@ -121,6 +123,7 @@ return a, b, c, d + def _mobius_to_interval(M, field): """Convert a Mobius transform to an open interval. """ a, b, c, d = M @@ -132,6 +135,7 @@ else: return (t, s) + def dup_step_refine_real_root(f, M, K, fast=False): """One step of positive real root refinement algorithm. """ a, b, c, d = M @@ -159,7 +163,7 @@ f, g = dup_shift(f, K.one, K), f - a1, b1, c1, d1 = a, a+b, c, c+d + a1, b1, c1, d1 = a, a + b, c, c + d if not dup_eval(f, K.zero, K): return f, (b1, b1, d1, d1) @@ -174,10 +178,11 @@ if not dup_eval(f, K.zero, K): f = dup_rshift(f, 1, K) - a, b, c, d = b, a+b, d, c+d + a, b, c, d = b, a + b, d, c + d return f, (a, b, c, d) + def dup_inner_refine_real_root(f, M, K, eps=None, steps=None, disjoint=None, fast=False, mobius=False): """Refine a positive root of `f` given a Mobius transform or an interval. """ F = K.get_field() @@ -188,22 +193,26 @@ a, b, c, d = M while not c: - f, (a, b, c, d) = dup_step_refine_real_root(f, (a, b, c, d), K, fast=fast) + f, (a, b, c, d) = dup_step_refine_real_root(f, (a, b, c, + d), K, fast=fast) if eps is not None and steps is not None: for i in range(0, steps): if abs(F(a, c) - F(b, d)) >= eps: - f, (a, b, c, d) = dup_step_refine_real_root(f, (a, b, c, d), K, fast=fast) + f, (a, b, c, d) = dup_step_refine_real_root( + f, (a, b, c, d), K, fast=fast) else: break else: if eps is not None: while abs(F(a, c) - F(b, d)) >= eps: - f, (a, b, c, d) = dup_step_refine_real_root(f, (a, b, c, d), K, fast=fast) + f, (a, b, c, d) = dup_step_refine_real_root( + f, (a, b, c, d), K, fast=fast) if steps is not None: for i in range(0, steps): - f, (a, b, c, d) = dup_step_refine_real_root(f, (a, b, c, d), K, fast=fast) + f, (a, b, c, d) = dup_step_refine_real_root( + f, (a, b, c, d), K, fast=fast) if disjoint is not None: while True: @@ -212,25 +221,29 @@ if v <= disjoint or disjoint <= u: break else: - f, (a, b, c, d) = dup_step_refine_real_root(f, (a, b, c, d), K, fast=fast) + f, (a, b, c, d) = dup_step_refine_real_root( + f, (a, b, c, d), K, fast=fast) if not mobius: return _mobius_to_interval((a, b, c, d), F) else: return f, (a, b, c, d) + def dup_outer_refine_real_root(f, s, t, K, eps=None, steps=None, disjoint=None, fast=False): """Refine a positive root of `f` given an interval `(s, t)`. """ a, b, c, d = _mobius_from_interval((s, t), K.get_field()) f = dup_transform(f, dup_strip([a, b]), - dup_strip([c, d]), K) + dup_strip([c, d]), K) if dup_sign_variations(f, K) != 1: - raise RefinementFailed("there should be exactly one root in (%s, %s) interval" % (s, t)) + raise RefinementFailed( + "there should be exactly one root in (%s, %s) interval" % (s, t)) return dup_inner_refine_real_root(f, (a, b, c, d), K, eps=eps, steps=steps, disjoint=disjoint, fast=fast) + def dup_refine_real_root(f, s, t, K, eps=None, steps=None, disjoint=None, fast=False): """Refine real root's approximating interval to the given precision. """ if K.is_QQ: @@ -258,12 +271,14 @@ else: disjoint = None - s, t = dup_outer_refine_real_root(f, s, t, K, eps=eps, steps=steps, disjoint=disjoint, fast=fast) + s, t = dup_outer_refine_real_root( + f, s, t, K, eps=eps, steps=steps, disjoint=disjoint, fast=fast) if negative: return (-t, -s) else: - return ( s, t) + return ( s, t) + def dup_inner_isolate_real_roots(f, K, eps=None, fast=False): """Internal function for isolation positive roots up to given precision. """ @@ -274,7 +289,8 @@ if k == 0: return [] if k == 1: - roots = [dup_inner_refine_real_root(f, (a, b, c, d), K, eps=eps, fast=fast, mobius=True)] + roots = [dup_inner_refine_real_root( + f, (a, b, c, d), K, eps=eps, fast=fast, mobius=True)] else: roots, stack = [], [(a, b, c, d, f, k)] @@ -305,12 +321,13 @@ if k == 0: continue if k == 1: - roots.append(dup_inner_refine_real_root(f, (a, b, c, d), K, eps=eps, fast=fast, mobius=True)) + roots.append(dup_inner_refine_real_root( + f, (a, b, c, d), K, eps=eps, fast=fast, mobius=True)) continue f1 = dup_shift(f, K.one, K) - a1, b1, c1, d1, r = a, a+b, c, c+d, 0 + a1, b1, c1, d1, r = a, a + b, c, c + d, 0 if not dup_TC(f1, K): roots.append((f1, (b1, b1, d1, d1))) @@ -319,7 +336,7 @@ k1 = dup_sign_variations(f1, K) k2 = k - k1 - r - a2, b2, c2, d2 = b, a+b, d, c+d + a2, b2, c2, d2 = b, a + b, d, c + d if k2 > 1: f2 = dup_shift(dup_reverse(f), K.one, K) @@ -346,7 +363,8 @@ f1 = dup_rshift(f1, 1, K) if k1 == 1: - roots.append(dup_inner_refine_real_root(f1, (a1, b1, c1, d1), K, eps=eps, fast=fast, mobius=True)) + roots.append(dup_inner_refine_real_root( + f1, (a1, b1, c1, d1), K, eps=eps, fast=fast, mobius=True)) else: stack.append((a1, b1, c1, d1, f1, k1)) @@ -360,12 +378,14 @@ f2 = dup_rshift(f2, 1, K) if k2 == 1: - roots.append(dup_inner_refine_real_root(f2, (a2, b2, c2, d2), K, eps=eps, fast=fast, mobius=True)) + roots.append(dup_inner_refine_real_root( + f2, (a2, b2, c2, d2), K, eps=eps, fast=fast, mobius=True)) else: stack.append((a2, b2, c2, d2, f2, k2)) return roots + def _discard_if_outside_interval(f, M, inf, sup, K, negative, fast, mobius): """Discard an isolating interval if outside ``(inf, sup)``. """ F = K.get_field() @@ -386,6 +406,7 @@ else: f, M = dup_step_refine_real_root(f, M, K, fast=fast) + def dup_inner_isolate_positive_roots(f, K, eps=None, inf=None, sup=None, fast=False, mobius=False): """Iteratively compute disjoint positive root isolation intervals. """ if sup is not None and sup < 0: @@ -397,7 +418,8 @@ if inf is not None or sup is not None: for f, M in roots: - result = _discard_if_outside_interval(f, M, inf, sup, K, False, fast, mobius) + result = _discard_if_outside_interval( + f, M, inf, sup, K, False, fast, mobius) if result is not None: results.append(result) @@ -410,18 +432,21 @@ return results + def dup_inner_isolate_negative_roots(f, K, inf=None, sup=None, eps=None, fast=False, mobius=False): """Iteratively compute disjoint negative root isolation intervals. """ if inf is not None and inf >= 0: return [] - roots = dup_inner_isolate_real_roots(dup_mirror(f, K), K, eps=eps, fast=fast) + roots = dup_inner_isolate_real_roots( + dup_mirror(f, K), K, eps=eps, fast=fast) F, results = K.get_field(), [] if inf is not None or sup is not None: for f, M in roots: - result = _discard_if_outside_interval(f, M, inf, sup, K, True, fast, mobius) + result = _discard_if_outside_interval( + f, M, inf, sup, K, True, fast, mobius) if result is not None: results.append(result) @@ -434,6 +459,7 @@ return results + def _isolate_zero(f, K, inf, sup, basis=False, sqf=False): """Handle special case of CF algorithm when ``f`` is homogeneous. """ j, f = dup_terms_gcd(f, K) @@ -452,6 +478,7 @@ return [], f + def dup_isolate_real_roots_sqf(f, K, eps=None, inf=None, sup=None, fast=False, blackbox=False): """Isolate real roots of a square-free polynomial using CF approach. """ if K.is_QQ: @@ -464,8 +491,10 @@ I_zero, f = _isolate_zero(f, K, inf, sup, basis=False, sqf=True) - I_neg = dup_inner_isolate_negative_roots(f, K, eps=eps, inf=inf, sup=sup, fast=fast) - I_pos = dup_inner_isolate_positive_roots(f, K, eps=eps, inf=inf, sup=sup, fast=fast) + I_neg = dup_inner_isolate_negative_roots( + f, K, eps=eps, inf=inf, sup=sup, fast=fast) + I_pos = dup_inner_isolate_positive_roots( + f, K, eps=eps, inf=inf, sup=sup, fast=fast) roots = sorted(I_neg + I_zero + I_pos) @@ -474,6 +503,7 @@ else: return [ RealInterval((a, b), f, K) for (a, b) in roots ] + def dup_isolate_real_roots(f, K, eps=None, inf=None, sup=None, basis=False, fast=False): """Isolate real roots using continued fractions approach. """ if K.is_QQ: @@ -491,8 +521,10 @@ if len(factors) == 1: ((f, k),) = factors - I_neg = dup_inner_isolate_negative_roots(f, K, eps=eps, inf=inf, sup=sup, fast=fast) - I_pos = dup_inner_isolate_positive_roots(f, K, eps=eps, inf=inf, sup=sup, fast=fast) + I_neg = dup_inner_isolate_negative_roots( + f, K, eps=eps, inf=inf, sup=sup, fast=fast) + I_pos = dup_inner_isolate_positive_roots( + f, K, eps=eps, inf=inf, sup=sup, fast=fast) I_neg = [ ((u, v), k) for u, v in I_neg ] I_pos = [ ((u, v), k) for u, v in I_pos ] @@ -502,6 +534,7 @@ return sorted(I_neg + I_zero + I_pos) + def dup_isolate_real_roots_list(polys, K, eps=None, inf=None, sup=None, strict=False, basis=False, fast=False): """Isolate real roots of a list of square-free polynomial using CF approach. """ if K.is_QQ: @@ -551,6 +584,7 @@ return sorted(I_neg + I_zero + I_pos) + def _disjoint_p(M, N, strict=False): """Check if Mobius transforms define disjoint intervals. """ a1, b1, c1, d1 = M @@ -571,7 +605,8 @@ if not strict: return a2*d1 >= c2*b1 or b2*c1 <= d2*a1 else: - return a2*d1 > c2*b1 or b2*c1 < d2*a1 + return a2*d1 > c2*b1 or b2*c1 < d2*a1 + def _real_isolate_and_disjoin(factors, K, eps=None, inf=None, sup=None, strict=False, basis=False, fast=False): """Isolate real roots of a list of polynomials and disjoin intervals. """ @@ -587,22 +622,26 @@ I_neg.append((G, N, k, f)) for i, (f, M, k, F) in enumerate(I_pos): - for j, (g, N, m, G) in enumerate(I_pos[i+1:]): + for j, (g, N, m, G) in enumerate(I_pos[i + 1:]): while not _disjoint_p(M, N, strict=strict): - f, M = dup_inner_refine_real_root(f, M, K, steps=1, fast=fast, mobius=True) - g, N = dup_inner_refine_real_root(g, N, K, steps=1, fast=fast, mobius=True) + f, M = dup_inner_refine_real_root( + f, M, K, steps=1, fast=fast, mobius=True) + g, N = dup_inner_refine_real_root( + g, N, K, steps=1, fast=fast, mobius=True) - I_pos[i+j+1] = (g, N, m, G) + I_pos[i + j + 1] = (g, N, m, G) I_pos[i] = (f, M, k, F) for i, (f, M, k, F) in enumerate(I_neg): - for j, (g, N, m, G) in enumerate(I_neg[i+1:]): + for j, (g, N, m, G) in enumerate(I_neg[i + 1:]): while not _disjoint_p(M, N, strict=strict): - f, M = dup_inner_refine_real_root(f, M, K, steps=1, fast=fast, mobius=True) - g, N = dup_inner_refine_real_root(g, N, K, steps=1, fast=fast, mobius=True) + f, M = dup_inner_refine_real_root( + f, M, K, steps=1, fast=fast, mobius=True) + g, N = dup_inner_refine_real_root( + g, N, K, steps=1, fast=fast, mobius=True) - I_neg[i+j+1] = (g, N, m, G) + I_neg[i + j + 1] = (g, N, m, G) I_neg[i] = (f, M, k, F) @@ -610,7 +649,8 @@ for i, (f, M, k, F) in enumerate(I_neg): if not M[0]: while not M[0]: - f, M = dup_inner_refine_real_root(f, M, K, steps=1, fast=fast, mobius=True) + f, M = dup_inner_refine_real_root( + f, M, K, steps=1, fast=fast, mobius=True) I_neg[i] = (f, M, k, F) break @@ -618,7 +658,8 @@ for j, (g, N, m, G) in enumerate(I_pos): if not N[0]: while not N[0]: - g, N = dup_inner_refine_real_root(g, N, K, steps=1, fast=fast, mobius=True) + g, N = dup_inner_refine_real_root( + g, N, K, steps=1, fast=fast, mobius=True) I_pos[j] = (g, N, m, G) break @@ -630,13 +671,14 @@ if not basis: I_neg = [ ((-v, -u), k) for ((u, v), k, _) in I_neg ] - I_pos = [ (( u, v), k) for ((u, v), k, _) in I_pos ] + I_pos = [ (( u, v), k) for ((u, v), k, _) in I_pos ] else: I_neg = [ ((-v, -u), k, f) for ((u, v), k, f) in I_neg ] - I_pos = [ (( u, v), k, f) for ((u, v), k, f) in I_pos ] + I_pos = [ (( u, v), k, f) for ((u, v), k, f) in I_pos ] return I_neg, I_pos + def dup_count_real_roots(f, K, inf=None, sup=None): """Returns the number of distinct real roots of ``f`` in ``[inf, sup]``. """ if dup_degree(f) <= 0: @@ -649,14 +691,17 @@ sturm = dup_sturm(f, K) if inf is None: - signs_inf = dup_sign_variations([ dup_LC(s, K)*(-1)**dup_degree(s) for s in sturm ], K) + signs_inf = dup_sign_variations( + [ dup_LC(s, K)*(-1)**dup_degree(s) for s in sturm ], K) else: - signs_inf = dup_sign_variations([ dup_eval(s, inf, K) for s in sturm ], K) + signs_inf = dup_sign_variations( + [ dup_eval(s, inf, K) for s in sturm ], K) if sup is None: signs_sup = dup_sign_variations([ dup_LC(s, K) for s in sturm ], K) else: - signs_sup = dup_sign_variations([ dup_eval(s, sup, K) for s in sturm ], K) + signs_sup = dup_sign_variations( + [ dup_eval(s, sup, K) for s in sturm ], K) count = abs(signs_inf - signs_sup) @@ -665,17 +710,17 @@ return count -OO = 'OO' # Origin of (re, im) coordinate system +OO = 'OO' # Origin of (re, im) coordinate system -Q1 = 'Q1' # Quadrant #1 (++): re > 0 and im > 0 -Q2 = 'Q2' # Quadrant #2 (-+): re < 0 and im > 0 -Q3 = 'Q3' # Quadrant #3 (--): re < 0 and im < 0 -Q4 = 'Q4' # Quadrant #4 (+-): re > 0 and im < 0 - -A1 = 'A1' # Axis #1 (+0): re > 0 and im = 0 -A2 = 'A2' # Axis #2 (0+): re = 0 and im > 0 -A3 = 'A3' # Axis #3 (-0): re < 0 and im = 0 -A4 = 'A4' # Axis #4 (0-): re = 0 and im < 0 +Q1 = 'Q1' # Quadrant #1 (++): re > 0 and im > 0 +Q2 = 'Q2' # Quadrant #2 (-+): re < 0 and im > 0 +Q3 = 'Q3' # Quadrant #3 (--): re < 0 and im < 0 +Q4 = 'Q4' # Quadrant #4 (+-): re > 0 and im < 0 + +A1 = 'A1' # Axis #1 (+0): re > 0 and im = 0 +A2 = 'A2' # Axis #2 (0+): re = 0 and im > 0 +A3 = 'A3' # Axis #3 (-0): re < 0 and im = 0 +A4 = 'A4' # Axis #4 (0-): re = 0 and im < 0 _rules_simple = { # A -- CCW --> Q => +1/4 (CCW) @@ -740,7 +785,7 @@ (Q3, OO, A3): -4, (Q4, OO, A4): -4, - # A -- OO --> A => { +1/1 (CCW), -1/1 (CW) } + # A -- OO --> A => { +1 (CCW), -1 (CW) } (A1, A3): 7, (A2, A4): 7, (A3, A1): 7, @@ -751,7 +796,7 @@ (A3, OO, A1): 7, (A4, OO, A2): 7, - # Q -- DIA --> Q => { +1/1 (CCW), -1/1 (CW) } + # Q -- DIA --> Q => { +1 (CCW), -1 (CW) } (Q1, Q3): 8, (Q2, Q4): 8, (Q3, Q1): 8, @@ -840,13 +885,13 @@ (Q3, OO, Q2): 16, (Q4, OO, Q3): 16, - # A --> OO --> A => { +2/1 (CCW), 0 (CW) } + # A --> OO --> A => { +2 (CCW), 0 (CW) } (A1, OO, A1): 17, (A2, OO, A2): 17, (A3, OO, A3): 17, (A4, OO, A4): 17, - # Q --> OO --> Q => { +2/1 (CCW), 0 (CW) } + # Q --> OO --> Q => { +2 (CCW), 0 (CW) } (Q1, OO, Q1): 18, (Q2, OO, Q2): 18, (Q3, OO, Q3): 18, @@ -854,19 +899,19 @@ } _values = { - 1: [(+1, 4)], - 2: [(-1, 4)], - 3: [(+1, 4)], - 4: [(-1, 4)], + 1: [(+1, 4)], + 2: [(-1, 4)], + 3: [(+1, 4)], + 4: [(-1, 4)], -1: [(+9, 4), (+1, 4)], -2: [(+7, 4), (-1, 4)], -3: [(+9, 4), (+1, 4)], -4: [(+7, 4), (-1, 4)], +5: [(+1, 2)], -5: [(-1, 2)], - 7: [(+1, 1), (-1, 1)], - 8: [(+1, 1), (-1, 1)], - 9: [(+1, 2), (-3, 2)], + 7: [(+1, 1), (-1, 1)], + 8: [(+1, 1), (-1, 1)], + 9: [(+1, 2), (-3, 2)], 10: [(+3, 2), (-1, 2)], 11: [(+3, 4), (-5, 4)], 12: [(+5, 4), (-3, 4)], @@ -878,6 +923,7 @@ 18: [(+2, 1), ( 0, 1)], } + def _classify_point(re, im): """Return the half-axis (or origin) on which (re, im) point is located. """ if not re and not im: @@ -894,6 +940,7 @@ else: return A3 + def _intervals_to_quadrants(intervals, f1, f2, s, t, F): """Generate a sequence of extended quadrants from a list of critical points. """ if not intervals: @@ -913,7 +960,7 @@ else: (a, _), _, _ = intervals[1] - if dup_eval(f2, (s+a)/2, F) > 0: + if dup_eval(f2, (s + a)/2, F) > 0: Q.extend([OO, A2]) f2_sgn = +1 else: @@ -955,7 +1002,7 @@ else: (a, _), _, _ = intervals[1] - if dup_eval(f1, (s+a)/2, F) > 0: + if dup_eval(f1, (s + a)/2, F) > 0: Q.extend([OO, A1]) f1_sgn = +1 else: @@ -997,8 +1044,8 @@ else: (a, _), _, _ = intervals[1] - re = dup_eval(f1, (s+a)/2, F) - im = dup_eval(f2, (s+a)/2, F) + re = dup_eval(f1, (s + a)/2, F) + im = dup_eval(f2, (s + a)/2, F) intervals = intervals[1:] @@ -1044,6 +1091,7 @@ return Q + def _traverse_quadrants(Q_L1, Q_L2, Q_L3, Q_L4, exclude=None): """Transform sequences of quadrants to a sequence of rules. """ if exclude is True: @@ -1092,12 +1140,13 @@ if qq in _rules_ambiguous: rules.append((_rules_ambiguous[qq], corners[(j, i)])) else: - raise NotImplementedError("3 element rule (corner): " + str(qq)) + raise NotImplementedError( + "3 element rule (corner): " + str(qq)) q1, k = Q[0], 1 while k < len(Q): - q2, k = Q[k], k+1 + q2, k = Q[k], k + 1 if q2 != OO: qq = (q1, q2) @@ -1107,27 +1156,32 @@ elif qq in _rules_ambiguous: rules.append((_rules_ambiguous[qq], edges[i])) else: - raise NotImplementedError("2 element rule (inside): " + str(qq)) + raise NotImplementedError( + "2 element rule (inside): " + str(qq)) else: - qq, k = (q1, q2, Q[k]), k+1 + qq, k = (q1, q2, Q[k]), k + 1 if qq in _rules_ambiguous: rules.append((_rules_ambiguous[qq], edges[i])) else: - raise NotImplementedError("3 element rule (edge): " + str(qq)) + raise NotImplementedError( + "3 element rule (edge): " + str(qq)) q1 = qq[-1] return rules + def _reverse_intervals(intervals): """Reverse intervals for traversal from right to left and from top to bottom. """ return [ ((b, a), indices, f) for (a, b), indices, f in reversed(intervals) ] + def _winding_number(T, field): """Compute the winding number of the input polynomial, i.e. the number of roots. """ return int(sum([ field(*_values[t][i]) for t, i in T ]) / field(2)) + def dup_count_complex_roots(f, K, inf=None, sup=None, exclude=None): """Count all roots in [u + v*I, s + t*I] rectangle using Collins-Krandick algorithm. """ if not K.is_ZZ and not K.is_QQ: @@ -1185,10 +1239,14 @@ S_L3 = [f1L3R, f2L3R] S_L4 = [f1L4R, f2L4R] - I_L1 = dup_isolate_real_roots_list(S_L1, R, inf=u, sup=s, fast=True, basis=True, strict=True) - I_L2 = dup_isolate_real_roots_list(S_L2, R, inf=v, sup=t, fast=True, basis=True, strict=True) - I_L3 = dup_isolate_real_roots_list(S_L3, R, inf=u, sup=s, fast=True, basis=True, strict=True) - I_L4 = dup_isolate_real_roots_list(S_L4, R, inf=v, sup=t, fast=True, basis=True, strict=True) + I_L1 = dup_isolate_real_roots_list( + S_L1, R, inf=u, sup=s, fast=True, basis=True, strict=True) + I_L2 = dup_isolate_real_roots_list( + S_L2, R, inf=v, sup=t, fast=True, basis=True, strict=True) + I_L3 = dup_isolate_real_roots_list( + S_L3, R, inf=u, sup=s, fast=True, basis=True, strict=True) + I_L4 = dup_isolate_real_roots_list( + S_L4, R, inf=v, sup=t, fast=True, basis=True, strict=True) I_L3 = _reverse_intervals(I_L3) I_L4 = _reverse_intervals(I_L4) @@ -1202,6 +1260,7 @@ return _winding_number(T, F) + def _vertical_bisection(N, a, b, I, Q, F1, F2, f1, f2, F): """Vertical bisection step in Collins-Krandick root isolation algorithm. """ (u, v), (s, t) = a, b @@ -1217,7 +1276,8 @@ f1V = dmp_eval_in(f1, x, 0, 1, F) f2V = dmp_eval_in(f2, x, 0, 1, F) - I_V = dup_isolate_real_roots_list([f1V, f2V], F, inf=v, sup=t, fast=True, strict=True, basis=True) + I_V = dup_isolate_real_roots_list( + [f1V, f2V], F, inf=v, sup=t, fast=True, strict=True, basis=True) I_L1_L, I_L1_R = [], [] I_L2_L, I_L2_R = I_V, I_L2 @@ -1241,7 +1301,8 @@ elif a >= x: I_L1_R.append(I) else: - a, b = dup_refine_real_root(h, a, b, F.get_ring(), disjoint=x, fast=True) + a, b = dup_refine_real_root( + h, a, b, F.get_ring(), disjoint=x, fast=True) if b <= x: I_L1_L.append(((a, b), indices, h)) @@ -1265,7 +1326,8 @@ elif a >= x: I_L3_R.append(I) else: - a, b = dup_refine_real_root(h, a, b, F.get_ring(), disjoint=x, fast=True) + a, b = dup_refine_real_root( + h, a, b, F.get_ring(), disjoint=x, fast=True) if b <= x: I_L3_L.append(((b, a), indices, h)) @@ -1273,14 +1335,14 @@ I_L3_R.append(((b, a), indices, h)) Q_L1_L = _intervals_to_quadrants(I_L1_L, f1L1F, f2L1F, u, x, F) - Q_L2_L = _intervals_to_quadrants(I_L2_L, f1V, f2V, v, t, F) + Q_L2_L = _intervals_to_quadrants(I_L2_L, f1V, f2V, v, t, F) Q_L3_L = _intervals_to_quadrants(I_L3_L, f1L3F, f2L3F, x, u, F) Q_L4_L = Q_L4 Q_L1_R = _intervals_to_quadrants(I_L1_R, f1L1F, f2L1F, x, s, F) Q_L2_R = Q_L2 Q_L3_R = _intervals_to_quadrants(I_L3_R, f1L3F, f2L3F, s, x, F) - Q_L4_R = _intervals_to_quadrants(I_L4_R, f1V, f2V, t, v, F) + Q_L4_R = _intervals_to_quadrants(I_L4_R, f1V, f2V, t, v, F) T_L = _traverse_quadrants(Q_L1_L, Q_L2_L, Q_L3_L, Q_L4_L, exclude=True) T_R = _traverse_quadrants(Q_L1_R, Q_L2_R, Q_L3_R, Q_L4_R, exclude=True) @@ -1308,6 +1370,7 @@ return D_L, D_R + def _horizontal_bisection(N, a, b, I, Q, F1, F2, f1, f2, F): """Horizontal bisection step in Collins-Krandick root isolation algorithm. """ (u, v), (s, t) = a, b @@ -1323,7 +1386,8 @@ f1H = dmp_eval_in(f1, y, 1, 1, F) f2H = dmp_eval_in(f2, y, 1, 1, F) - I_H = dup_isolate_real_roots_list([f1H, f2H], F, inf=u, sup=s, fast=True, strict=True, basis=True) + I_H = dup_isolate_real_roots_list( + [f1H, f2H], F, inf=u, sup=s, fast=True, strict=True, basis=True) I_L1_B, I_L1_U = I_L1, I_H I_L2_B, I_L2_U = [], [] @@ -1347,7 +1411,8 @@ elif a >= y: I_L2_U.append(I) else: - a, b = dup_refine_real_root(h, a, b, F.get_ring(), disjoint=y, fast=True) + a, b = dup_refine_real_root( + h, a, b, F.get_ring(), disjoint=y, fast=True) if b <= y: I_L2_B.append(((a, b), indices, h)) @@ -1371,7 +1436,8 @@ elif a >= y: I_L4_U.append(I) else: - a, b = dup_refine_real_root(h, a, b, F.get_ring(), disjoint=y, fast=True) + a, b = dup_refine_real_root( + h, a, b, F.get_ring(), disjoint=y, fast=True) if b <= y: I_L4_B.append(((b, a), indices, h)) @@ -1380,10 +1446,10 @@ Q_L1_B = Q_L1 Q_L2_B = _intervals_to_quadrants(I_L2_B, f1L2F, f2L2F, v, y, F) - Q_L3_B = _intervals_to_quadrants(I_L3_B, f1H, f2H, s, u, F) + Q_L3_B = _intervals_to_quadrants(I_L3_B, f1H, f2H, s, u, F) Q_L4_B = _intervals_to_quadrants(I_L4_B, f1L4F, f2L4F, y, v, F) - Q_L1_U = _intervals_to_quadrants(I_L1_U, f1H, f2H, u, s, F) + Q_L1_U = _intervals_to_quadrants(I_L1_U, f1H, f2H, u, s, F) Q_L2_U = _intervals_to_quadrants(I_L2_U, f1L2F, f2L2F, y, t, F) Q_L3_U = Q_L3 Q_L4_U = _intervals_to_quadrants(I_L4_U, f1L4F, f2L4F, t, y, F) @@ -1414,6 +1480,7 @@ return D_B, D_U + def _depth_first_select(rectangles): """Find a rectangle of minimum area for bisection. """ min_area, j = None, None @@ -1426,6 +1493,7 @@ return rectangles.pop(j) + def _rectangle_small_p(a, b, eps): """Return ``True`` if the given rectangle is small enough. """ (u, v), (s, t) = a, b @@ -1435,10 +1503,12 @@ else: return True + def dup_isolate_complex_roots_sqf(f, K, eps=None, inf=None, sup=None, blackbox=False): """Isolate complex roots of a square-free polynomial using Collins-Krandick algorithm. """ if not K.is_ZZ and not K.is_QQ: - raise DomainError("isolation of complex roots is not supported over %s" % K) + raise DomainError( + "isolation of complex roots is not supported over %s" % K) if dup_degree(f) <= 0: return [] @@ -1483,10 +1553,14 @@ S_L3 = [f1L3, f2L3] S_L4 = [f1L4, f2L4] - I_L1 = dup_isolate_real_roots_list(S_L1, F, inf=u, sup=s, fast=True, strict=True, basis=True) - I_L2 = dup_isolate_real_roots_list(S_L2, F, inf=v, sup=t, fast=True, strict=True, basis=True) - I_L3 = dup_isolate_real_roots_list(S_L3, F, inf=u, sup=s, fast=True, strict=True, basis=True) - I_L4 = dup_isolate_real_roots_list(S_L4, F, inf=v, sup=t, fast=True, strict=True, basis=True) + I_L1 = dup_isolate_real_roots_list( + S_L1, F, inf=u, sup=s, fast=True, strict=True, basis=True) + I_L2 = dup_isolate_real_roots_list( + S_L2, F, inf=v, sup=t, fast=True, strict=True, basis=True) + I_L3 = dup_isolate_real_roots_list( + S_L3, F, inf=u, sup=s, fast=True, strict=True, basis=True) + I_L4 = dup_isolate_real_roots_list( + S_L4, F, inf=v, sup=t, fast=True, strict=True, basis=True) I_L3 = _reverse_intervals(I_L3) I_L4 = _reverse_intervals(I_L4) @@ -1514,37 +1588,43 @@ N, (u, v), (s, t), I, Q, F1, F2 = _depth_first_select(rectangles) if s - u > t - v: - D_L, D_R = _vertical_bisection(N, (u, v), (s, t), I, Q, F1, F2, f1, f2, F) + D_L, D_R = _vertical_bisection( + N, (u, v), (s, t), I, Q, F1, F2, f1, f2, F) N_L, a, b, I_L, Q_L, F1_L, F2_L = D_L N_R, c, d, I_R, Q_R, F1_R, F2_R = D_R if N_L >= 1: if N_L == 1 and _rectangle_small_p(a, b, eps): - roots.append(ComplexInterval(a, b, I_L, Q_L, F1_L, F2_L, f1, f2, F)) + roots.append(ComplexInterval( + a, b, I_L, Q_L, F1_L, F2_L, f1, f2, F)) else: rectangles.append(D_L) if N_R >= 1: if N_R == 1 and _rectangle_small_p(c, d, eps): - roots.append(ComplexInterval(c, d, I_R, Q_R, F1_R, F2_R, f1, f2, F)) + roots.append(ComplexInterval( + c, d, I_R, Q_R, F1_R, F2_R, f1, f2, F)) else: rectangles.append(D_R) else: - D_B, D_U = _horizontal_bisection(N, (u, v), (s, t), I, Q, F1, F2, f1, f2, F) + D_B, D_U = _horizontal_bisection( + N, (u, v), (s, t), I, Q, F1, F2, f1, f2, F) N_B, a, b, I_B, Q_B, F1_B, F2_B = D_B N_U, c, d, I_U, Q_U, F1_U, F2_U = D_U if N_B >= 1: if N_B == 1 and _rectangle_small_p(a, b, eps): - roots.append(ComplexInterval(a, b, I_B, Q_B, F1_B, F2_B, f1, f2, F)) + roots.append(ComplexInterval( + a, b, I_B, Q_B, F1_B, F2_B, f1, f2, F)) else: rectangles.append(D_B) if N_U >= 1: if N_U == 1 and _rectangle_small_p(c, d, eps): - roots.append(ComplexInterval(c, d, I_U, Q_U, F1_U, F2_U, f1, f2, F)) + roots.append(ComplexInterval( + c, d, I_U, Q_U, F1_U, F2_U, f1, f2, F)) else: rectangles.append(D_U) @@ -1558,10 +1638,14 @@ else: return [ r.as_tuple() for r in roots ] + def dup_isolate_all_roots_sqf(f, K, eps=None, inf=None, sup=None, fast=False, blackbox=False): """Isolate real and complex roots of a square-free polynomial ``f``. """ - return (dup_isolate_real_roots_sqf(f, K, eps=eps, inf=inf, sup=sup, fast=fast, blackbox=blackbox), - dup_isolate_complex_roots_sqf(f, K, eps=eps, inf=inf, sup=sup, blackbox=blackbox)) + return ( + dup_isolate_real_roots_sqf( + f, K, eps=eps, inf=inf, sup=sup, fast=fast, blackbox=blackbox), + dup_isolate_complex_roots_sqf(f, K, eps=eps, inf=inf, sup=sup, blackbox=blackbox)) + def dup_isolate_all_roots(f, K, eps=None, inf=None, sup=None, fast=False): """Isolate real and complex roots of a non-square-free polynomial ``f``. """ @@ -1573,14 +1657,17 @@ if len(factors) == 1: ((f, k),) = factors - real_part, complex_part = dup_isolate_all_roots_sqf(f, K, eps=eps, inf=inf, sup=sup, fast=fast) + real_part, complex_part = dup_isolate_all_roots_sqf( + f, K, eps=eps, inf=inf, sup=sup, fast=fast) real_part = [ ((a, b), k) for (a, b) in real_part ] complex_part = [ ((a, b), k) for (a, b) in complex_part ] return real_part, complex_part else: - raise NotImplementedError("only trivial square-free polynomials are supported") + raise NotImplementedError( + "only trivial square-free polynomials are supported") + class RealInterval(object): """A fully qualified representation of a real isolation interval. """ @@ -1596,12 +1683,13 @@ if t <= 0: f, s, t, self.neg = dup_mirror(f, dom), -t, -s, True else: - raise ValueError("can't refine a real root in (%s, %s)" % (s, t)) + raise ValueError( + "can't refine a real root in (%s, %s)" % (s, t)) a, b, c, d = _mobius_from_interval((s, t), dom.get_field()) f = dup_transform(f, dup_strip([a, b]), - dup_strip([c, d]), dom) + dup_strip([c, d]), dom) self.mobius = a, b, c, d else: @@ -1658,7 +1746,8 @@ if self.mobius is None: return self - f, mobius = dup_inner_refine_real_root(self.f, self.mobius, self.dom, steps=1, mobius=True) + f, mobius = dup_inner_refine_real_root( + self.f, self.mobius, self.dom, steps=1, mobius=True) return RealInterval(mobius + (self.neg,), f, self.dom) @@ -1687,6 +1776,7 @@ """Perform one step of real root refinement algorithm. """ return self._inner_refine() + class ComplexInterval(object): """A fully qualified representation of a complex isolation interval. """ @@ -1771,14 +1861,16 @@ dom = self.dom if s - u > t - v: - D_L, D_R = _vertical_bisection(1, (u, v), (s, t), I, Q, F1, F2, f1, f2, dom) + D_L, D_R = _vertical_bisection( + 1, (u, v), (s, t), I, Q, F1, F2, f1, f2, dom) if D_L[0] == 1: _, a, b, I, Q, F1, F2 = D_L else: _, a, b, I, Q, F1, F2 = D_R else: - D_B, D_U = _horizontal_bisection(1, (u, v), (s, t), I, Q, F1, F2, f1, f2, dom) + D_B, D_U = _horizontal_bisection( + 1, (u, v), (s, t), I, Q, F1, F2, f1, f2, dom) if D_B[0] == 1: _, a, b, I, Q, F1, F2 = D_B diff -Nru python3-sympy-0.7.2/sympy/polys/rootoftools.py python3-sympy-0.7.3/sympy/polys/rootoftools.py --- python3-sympy-0.7.2/sympy/polys/rootoftools.py 2012-10-17 03:02:22.000000000 +0000 +++ python3-sympy-0.7.3/sympy/polys/rootoftools.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,6 +1,7 @@ """Implementation of RootOf class and related tools. """ -from sympy.core import S, Expr, Integer, Float, I, Add, Lambda, symbols, sympify +from sympy.core import (S, Expr, Integer, Float, I, Add, Lambda, symbols, + sympify, Rational) from sympy.polys.polytools import Poly, PurePoly, factor from sympy.polys.rationaltools import together @@ -30,10 +31,12 @@ _reals_cache = {} _complexes_cache = {} + class RootOf(Expr): """Represents ``k``-th root of a univariate polynomial. """ __slots__ = ['poly', 'index'] + is_complex = True def __new__(cls, f, x, index=None, radicals=True, expand=True): """Construct a new ``RootOf`` object for ``k``-th root of ``f``. """ @@ -60,7 +63,8 @@ raise PolynomialError("can't construct RootOf object for %s" % f) if index < -degree or index >= degree: - raise IndexError("root index out of [%d, %d] range, got %d" % (-degree, degree-1, index)) + raise IndexError("root index out of [%d, %d] range, got %d" % + (-degree, degree - 1, index)) elif index < 0: index += degree @@ -106,22 +110,15 @@ @property def free_symbols(self): - return self.poly.free_symbols - - @property - def is_commutative(self): - return True + # RootOf currently only works with univariate expressions and although + # the poly attribute is often a PurePoly, sometimes it is a Poly. In + # either case no free symbols should be reported. + return set() - @property - def is_real(self): + def _eval_is_real(self): """Return ``True`` if the root is real. """ return self.index < len(_reals_cache[self.poly]) - @property - def is_complex(self): - """Return ``True`` if the root is complex. """ - return not self.is_real - @classmethod def real_roots(cls, poly, radicals=True): """Get real roots of a polynomial. """ @@ -139,7 +136,8 @@ real_part = _reals_cache[factor] else: _reals_cache[factor] = real_part = \ - dup_isolate_real_roots_sqf(factor.rep.rep, factor.rep.dom, blackbox=True) + dup_isolate_real_roots_sqf( + factor.rep.rep, factor.rep.dom, blackbox=True) return real_part @@ -150,7 +148,8 @@ complex_part = _complexes_cache[factor] else: _complexes_cache[factor] = complex_part = \ - dup_isolate_complex_roots_sqf(factor.rep.rep, factor.rep.dom, blackbox=True) + dup_isolate_complex_roots_sqf( + factor.rep.rep, factor.rep.dom, blackbox=True) return complex_part @@ -182,9 +181,9 @@ cache = {} for i, (u, f, k) in enumerate(reals): - for j, (v, g, m) in enumerate(reals[i+1:]): + for j, (v, g, m) in enumerate(reals[i + 1:]): u, v = u.refine_disjoint(v) - reals[i+j+1] = (v, g, m) + reals[i + j + 1] = (v, g, m) reals[i] = (u, f, k) @@ -207,9 +206,9 @@ cache = {} for i, (u, f, k) in enumerate(complexes): - for j, (v, g, m) in enumerate(complexes[i+1:]): + for j, (v, g, m) in enumerate(complexes[i + 1:]): u, v = u.refine_disjoint(v) - complexes[i+j+1] = (v, g, m) + complexes[i + j + 1] = (v, g, m) complexes[i] = (u, f, k) @@ -281,7 +280,7 @@ else: complexes = cls._get_complexes(factors) complexes = cls._complexes_sorted(complexes) - return cls._complexes_index(complexes, index-reals_count) + return cls._complexes_index(complexes, index - reals_count) @classmethod def _real_roots(cls, poly): @@ -403,7 +402,14 @@ func = lambdify(self.poly.gen, self.expr) interval = self._get_interval() - refined = False + if not self.is_real: + # For complex intervals, we need to keep refining until the + # imaginary interval is disjunct with other roots, that is, + # until both ends get refined. + ay = interval.ay + by = interval.by + while interval.ay == ay or interval.by == by: + interval = interval.refine() while True: if self.is_real: @@ -413,20 +419,71 @@ try: root = findroot(func, x0) + # If the (real or complex) root is not in the 'interval', + # then keep refining the interval. This happens if findroot + # accidentally finds a different root outside of this + # interval because our initial estimate 'x0' was not close + # enough. + if self.is_real: + a = mpf(str(interval.a)) + b = mpf(str(interval.b)) + # This is needed due to the bug #3364: + a, b = min(a, b), max(a, b) + if not (a < root < b): + raise ValueError("Root not in the interval.") + else: + ax = mpf(str(interval.ax)) + bx = mpf(str(interval.bx)) + ay = mpf(str(interval.ay)) + by = mpf(str(interval.by)) + # This is needed due to the bug #3364: + ax, bx = min(ax, bx), max(ax, bx) + ay, by = min(ay, by), max(ay, by) + if not (ax < root.real < bx and ay < root.imag < by): + raise ValueError("Root not in the interval.") except ValueError: interval = interval.refine() - refined = True continue else: - if refined: - self._set_interval(interval) - break finally: mp.prec = _prec return Float._new(root.real._mpf_, prec) + I*Float._new(root.imag._mpf_, prec) + def eval_rational(self, tol): + """ + Returns a Rational approximation to ``self`` with the tolerance ``tol``. + + This method uses bisection, which is very robust and it will always + converge. The returned Rational instance will be at most 'tol' from the + exact root. + + The following example first obtains Rational approximation to 1e-7 + accuracy for all roots of the 4-th order Legendre polynomial, and then + evaluates it to 5 decimal digits (so all digits will be correct + including rounding): + + >>> from sympy import S, legendre_poly, Symbol + >>> x = Symbol("x") + >>> p = legendre_poly(4, x, polys=True) + >>> roots = [r.eval_rational(S(1)/10**7) for r in p.real_roots()] + >>> roots = [str(r.n(5)) for r in roots] + >>> roots + ['-0.86114', '-0.33998', '0.33998', '0.86114'] + + """ + + if not self.is_real: + raise NotImplementedError("eval_rational() only works for real polynomials so far") + func = lambdify(self.poly.gen, self.expr) + interval = self._get_interval() + a = Rational(str(interval.a)) + b = Rational(str(interval.b)) + # This is needed due to the bug #3364: + a, b = min(a, b), max(a, b) + return bisect(func, a, b, tol) + class RootSum(Expr): """Represents a sum of all roots of a univariate polynomial. """ @@ -437,7 +494,8 @@ coeff, poly = cls._transform(expr, x) if not poly.is_univariate: - raise MultivariatePolynomialError("only univariate polynomials are allowed") + raise MultivariatePolynomialError( + "only univariate polynomials are allowed") if func is None: func = Lambda(poly.gen, poly.gen) @@ -451,7 +509,8 @@ if not isinstance(func, Lambda): func = Lambda(poly.gen, func(poly.gen)) else: - raise ValueError("expected a univariate function, got %s" % func) + raise ValueError( + "expected a univariate function, got %s" % func) var, expr = func.variables[0], func.expr @@ -499,7 +558,7 @@ obj = Expr.__new__(cls) obj.poly = poly - obj.fun = func + obj.fun = func obj.auto = auto return obj @@ -625,3 +684,37 @@ var, expr = self.fun.args func = Lambda(var, expr.diff(x)) return self.new(self.poly, func, self.auto) + +def bisect(f, a, b, tol): + """ + Implements bisection. This function is used in RootOf.eval_rational() and + it needs to be robust. + + Examples + ======== + + >>> from sympy import S + >>> from sympy.polys.rootoftools import bisect + >>> bisect(lambda x: x**2-1, -10, 0, S(1)/10**2) + -1025/1024 + >>> bisect(lambda x: x**2-1, -10, 0, S(1)/10**4) + -131075/131072 + + """ + a = sympify(a) + b = sympify(b) + fa = f(a) + fb = f(b) + if fa * fb >= 0: + raise ValueError("bisect: f(a) and f(b) must have opposite signs") + while (b-a > tol): + c = (a+b)/2 + fc = f(c) + if (fc == 0): return c # We need to make sure f(c) is not zero below + if (fa * fc < 0): + b = c + fb = fc + else: + a = c + fa = fc + return (a+b)/2 diff -Nru python3-sympy-0.7.2/sympy/polys/solvers.py python3-sympy-0.7.3/sympy/polys/solvers.py --- python3-sympy-0.7.2/sympy/polys/solvers.py 1970-01-01 00:00:00.000000000 +0000 +++ python3-sympy-0.7.3/sympy/polys/solvers.py 2013-07-13 17:53:32.000000000 +0000 @@ -0,0 +1,38 @@ +"""Low-level linear systems solver. """ + +from sympy.matrices import Matrix, zeros + +class RawMatrix(Matrix): + _sympify = staticmethod(lambda x: x) + +def solve_lin_sys(eqs, ring): + """Solve a system of linear equations. """ + assert ring.domain.has_Field + + # transform from equations to matrix form + xs = ring.gens + M = zeros(len(eqs), len(xs)+1, cls=RawMatrix) + + for j, e_j in enumerate(eqs): + for i, x_i in enumerate(xs): + M[j, i] = e_j.coeff(x_i) + M[j, -1] = -e_j.coeff(1) + + eqs = M + + # solve by row-reduction + echelon, pivots = eqs.rref(iszerofunc=lambda x: not x, simplify=lambda x: x) + + # construct the returnable form of the solutions + if pivots[-1] == len(xs): + return None + elif len(pivots) == len(xs): + sol = [ ring.ground_new(s) for s in echelon[:, -1] ] + return dict(list(zip(xs, sol))) + else: + sols = {} + for i, p in enumerate(pivots): + vect = RawMatrix([ [-x] for x in xs[p+1:] ] + [[ring.one]]) + sols[xs[p]] = (echelon[i, p+1:]*vect)[0] + + return sols diff -Nru python3-sympy-0.7.2/sympy/polys/specialpolys.py python3-sympy-0.7.3/sympy/polys/specialpolys.py --- python3-sympy-0.7.2/sympy/polys/specialpolys.py 2012-10-17 03:02:22.000000000 +0000 +++ python3-sympy-0.7.3/sympy/polys/specialpolys.py 2013-07-13 17:53:32.000000000 +0000 @@ -28,46 +28,43 @@ from sympy.utilities import cythonized, subsets -@cythonized("n,i") + def swinnerton_dyer_poly(n, x=None, **args): """Generates n-th Swinnerton-Dyer polynomial in `x`. """ + from .numberfields import minimal_polynomial if n <= 0: - raise ValueError("can't generate Swinnerton-Dyer polynomial of order %s" % n) + raise ValueError( + "can't generate Swinnerton-Dyer polynomial of order %s" % n) if x is not None: - x, cls = sympify(x), Poly + sympify(x) else: - x, cls = Dummy('x'), PurePoly - - p, elts = 2, [[x, -sqrt(2)], - [x, sqrt(2)]] - - for i in range(2, n+1): - p, _elts = nextprime(p), [] - - neg_sqrt = -sqrt(p) - pos_sqrt = +sqrt(p) - - for elt in elts: - _elts.append(elt + [neg_sqrt]) - _elts.append(elt + [pos_sqrt]) - - elts = _elts - - poly = [] - - for elt in elts: - poly.append(Add(*elt)) + x = Dummy('x') + if n > 3: + p = 2 + a = [sqrt(2)] + for i in range(2, n + 1): + p = nextprime(p) + a.append(sqrt(p)) + return minimal_polynomial(Add(*a), x, polys=args.get('polys', False)) + + if n == 1: + ex = x**2 - 2 + elif n == 2: + ex = x**4 - 10*x**2 + 1 + elif n == 3: + ex = x**8 - 40*x**6 + 352*x**4 - 960*x**2 + 576 if not args.get('polys', False): - return Mul(*poly).expand() + return ex else: - return PurePoly(Mul(*poly), x) + return PurePoly(ex, x) def cyclotomic_poly(n, x=None, **args): """Generates cyclotomic polynomial of order `n` in `x`. """ if n <= 0: - raise ValueError("can't generate cyclotomic polynomial of order %s" % n) + raise ValueError( + "can't generate cyclotomic polynomial of order %s" % n) poly = DMP(dup_zz_cyclotomic_poly(int(n), ZZ), ZZ) @@ -81,6 +78,7 @@ else: return poly + def symmetric_poly(n, *gens, **args): """Generates symmetric polynomial of order `n`. """ gens = _analyze_gens(gens) @@ -97,6 +95,7 @@ else: return Poly(poly, *gens) + def random_poly(x, n, inf, sup, domain=ZZ, polys=False): """Return a polynomial of degree ``n`` with coefficients in ``[inf, sup]``. """ poly = Poly(dup_random(n, inf, sup, domain), x, domain=domain) @@ -106,6 +105,7 @@ else: return poly + @cythonized("n,i,j") def interpolating_poly(n, x, X='x', Y='y'): """Construct Lagrange interpolating polynomial for ``n`` data points. """ @@ -125,7 +125,7 @@ if i == j: continue - numer.append(x - X[j]) + numer.append(x - X[j]) denom.append(X[i] - X[j]) numer = Mul(*numer) @@ -135,14 +135,15 @@ return Add(*[ coeff*y for coeff, y in zip(coeffs, Y) ]) + @cythonized("n,i") def fateman_poly_F_1(n): """Fateman's GCD benchmark: trivial GCD """ - Y = [ Symbol('y_' + str(i)) for i in range(0, n+1) ] + Y = [ Symbol('y_' + str(i)) for i in range(0, n + 1) ] y_0, y_1 = Y[0], Y[1] - u = y_0 + Add(*[ y for y in Y[1:] ]) + u = y_0 + Add(*[ y for y in Y[1:] ]) v = y_0**2 + Add(*[ y**2 for y in Y[1:] ]) F = ((u + 1)*(u + 2)).as_poly(*Y) @@ -152,6 +153,7 @@ return F, G, H + @cythonized("n,m,i") def dmp_fateman_poly_F_1(n, K): """Fateman's GCD benchmark: trivial GCD """ @@ -165,7 +167,7 @@ for i in range(0, n): v = [dmp_one(i, K), dmp_zero(i), v] - m = n-1 + m = n - 1 U = dmp_add_term(u, dmp_ground(K(1), m), 0, n, K) V = dmp_add_term(u, dmp_ground(K(2), m), 0, n, K) @@ -182,10 +184,11 @@ return F, G, H + @cythonized("n,i") def fateman_poly_F_2(n): """Fateman's GCD benchmark: linearly dense quartic inputs """ - Y = [ Symbol('y_' + str(i)) for i in range(0, n+1) ] + Y = [ Symbol('y_' + str(i)) for i in range(0, n + 1) ] y_0 = Y[0] @@ -198,146 +201,108 @@ return H*F, H*G, H + @cythonized("n,m,i") def dmp_fateman_poly_F_2(n, K): """Fateman's GCD benchmark: linearly dense quartic inputs """ u = [K(1), K(0)] - for i in range(0, n-1): + for i in range(0, n - 1): u = [dmp_one(i, K), u] - m = n-1 + m = n - 1 - v = dmp_add_term(u, dmp_ground(K(2), m-1), 0, n, K) + v = dmp_add_term(u, dmp_ground(K(2), m - 1), 0, n, K) f = dmp_sqr([dmp_one(m, K), dmp_neg(v, m, K)], n, K) g = dmp_sqr([dmp_one(m, K), v], n, K) - v = dmp_add_term(u, dmp_one(m-1, K), 0, n, K) + v = dmp_add_term(u, dmp_one(m - 1, K), 0, n, K) h = dmp_sqr([dmp_one(m, K), v], n, K) return dmp_mul(f, h, n, K), dmp_mul(g, h, n, K), h + @cythonized("n,i") def fateman_poly_F_3(n): """Fateman's GCD benchmark: sparse inputs (deg f ~ vars f) """ - Y = [ Symbol('y_' + str(i)) for i in range(0, n+1) ] + Y = [ Symbol('y_' + str(i)) for i in range(0, n + 1) ] y_0 = Y[0] - u = Add(*[ y**(n+1) for y in Y[1:] ]) + u = Add(*[ y**(n + 1) for y in Y[1:] ]) - H = Poly((y_0**(n+1) + u + 1)**2, *Y) + H = Poly((y_0**(n + 1) + u + 1)**2, *Y) - F = Poly((y_0**(n+1) - u - 2)**2, *Y) - G = Poly((y_0**(n+1) + u + 2)**2, *Y) + F = Poly((y_0**(n + 1) - u - 2)**2, *Y) + G = Poly((y_0**(n + 1) + u + 2)**2, *Y) return H*F, H*G, H + @cythonized("n,i") def dmp_fateman_poly_F_3(n, K): """Fateman's GCD benchmark: sparse inputs (deg f ~ vars f) """ - u = dup_from_raw_dict({n+1: K.one}, K) + u = dup_from_raw_dict({n + 1: K.one}, K) - for i in range(0, n-1): - u = dmp_add_term([u], dmp_one(i, K), n+1, i+1, K) + for i in range(0, n - 1): + u = dmp_add_term([u], dmp_one(i, K), n + 1, i + 1, K) - v = dmp_add_term(u, dmp_ground(K(2), n-2), 0, n, K) + v = dmp_add_term(u, dmp_ground(K(2), n - 2), 0, n, K) - f = dmp_sqr(dmp_add_term([dmp_neg(v, n-1, K)], dmp_one(n-1, K), n+1, n, K), n, K) - g = dmp_sqr(dmp_add_term([v], dmp_one(n-1, K), n+1, n, K), n, K) + f = dmp_sqr( + dmp_add_term([dmp_neg(v, n - 1, K)], dmp_one(n - 1, K), n + 1, n, K), n, K) + g = dmp_sqr(dmp_add_term([v], dmp_one(n - 1, K), n + 1, n, K), n, K) - v = dmp_add_term(u, dmp_one(n-2, K), 0, n-1, K) + v = dmp_add_term(u, dmp_one(n - 2, K), 0, n - 1, K) - h = dmp_sqr(dmp_add_term([v], dmp_one(n-1, K), n+1, n, K), n, K) + h = dmp_sqr(dmp_add_term([v], dmp_one(n - 1, K), n + 1, n, K), n, K) return dmp_mul(f, h, n, K), dmp_mul(g, h, n, K), h # A few useful polynomials from Wang's paper ('78). -f_0 = dmp_normal([ - [[1,2,3], [2]], - [[3]], - [[4,5,6], [1,2,1], [1]] -], 2, ZZ) - -f_1 = dmp_normal([ - [[1, 0], []], - [[1, 0, 1], [20, 30], [1, 10, 0]], - [[1, 0], [30, 20], [1, 10, 1, 610], [20, 230, 300]], - [[1, 10, 0], [30, 320, 200], [600, 6000]] -], 2, ZZ) - -f_2 = dmp_normal([ - [[1], [1, 0], [1, 0, 0], [1, 0, 0, 0]], - [[]], - [[1], [1, 90], [90, 0]], - [[1, -11], [], [1, -11, 0, 0]], - [[]], - [[1, -11], [90, -990]] -], 2, ZZ) - -f_3 = dmp_normal([ - [[1], [], []], - [[1, 0, 0, 0, 1]], - [[1, 0], [], [], [1, 0]], - [[1], [1, 0, 0, 0], [], [1, 0, 0, 0, 1, 0], []], - [[1, 0, 0, 0, 1], [1, 0, 0, 0, 1, 1, 0, 0], []], - [[1, 0], [1, 0, 0, 0, 0], []] -], 2, ZZ) - -f_4 = dmp_normal([ - [[-1, 0], [], [], [], [], [], [], [], []], - [[-1, 0, 0, 0], [], [], [], [], []], - [[-1, 0, 0], [], [], [], [-5], [], [], [], [], [], [], [], []], - [[-1, 0, 0, 0, 0], [], [1, 0, 3, 0], [], [-5, 0, 0], [-1, 0, 0, 0], [], [], [], []], - [[1, 0, 3, 0, 0, 0], [], [], [-1, 0, 0, 0, 0, 0], []], - [[1, 0, 3, 0, 0], [], [], [-1, 0, 0, 0, 0], [5, 0, 15], [], [], [-5, 0, 0], [], [], [], []], - [[1, 0, 3, 0, 0, 0, 0], [], [], [-1, 0, 0, 0, 0, 0, 0], [5, 0, 15, 0, 0], [1, 0, 3, 0, 0, 0], [], [-5, 0, 0, 0, 0], []], - [[1, 0, 3, 0, 0, 0, 0, 0]], - [[1, 0, 3, 0, 0, 0, 0], [], [], [], [5, 0, 15, 0, 0], [], [], []], - [[1, 0, 3, 0, 0, 0, 0, 0, 0], [], [], [], [5, 0, 15, 0, 0, 0, 0]] -], 2, ZZ) - -f_5 = dmp_normal([ - [[-1]], - [[-3], [3, 0]], - [[-3], [6, 0], [-3, 0, 0]], - [[-1], [3, 0], [-3, 0, 0], [1, 0, 0, 0]] -], 2, ZZ) - -f_6 = dmp_normal([ - [[[2115]], [[]]], - [[[45, 0, 0], [], [], [-45, 0, 0]]], - [[[]]], - [[[-423]], [[-47]], [[]], [[141], [], [94, 0], []], [[]]], - [[[-9, 0, 0], [], [], [9, 0, 0]], - [[-1, 0, 0], [], [], [1, 0, 0]], - [[]], - [[3, 0, 0], [], [2, 0, 0, 0], [-3, 0, 0], [], [-2, 0, 0, 0], []] - ] -], 3, ZZ) - - -w_1 = dmp_normal([ - [[4, 0, 0], [4, 0, 0, 0], [-4, 0, 0, 0, 0], [-4, 0, 0, 0, 0, 0], []], - [[1, 0, 0, 0], [12, 0], [-1, 0, 0, 12, 0, 0], [-12, 0, 0, 0], [-12, 0, 0, 0, 0]], - [[8], [6, 8, 0], [-4, 4, -8, 0, 0], [-4, -2, -8, 0, 0, 0], []], - [[2, 0], [1, 0, 0, 0], [-1, 0, -2 , 0, 9, 0], [-12, 12, 0, 0], [-12, 3, 0, 0, 0]], - [[6], [-6, 8, 0], [-2, -8, 2, 0, 0], []], - [[2, 0], [-2, 0, 0, 0], [-3, 0], [3, 0, 0, 0]], - [[-2], [2, 0, 0], []] -], 2, ZZ) - -w_2 = dmp_normal([ - [24, 48, 0, 0], - [24, 0, 0, -72, 0, 0], - [25, 2, 0, 4, 8], - [1, 0, 0, 1, 0, 0, -12], - [1, -1, -2, 292, 0, 0], - [-1, 0, 0, 3, 0, 0, 0], - [-1, 0, 12, 0, 0, 48], - [], - [-12, 0, 0, 0] -], 1, ZZ) +from sympy.polys.rings import ring + +def _f_0(): + R, x, y, z = ring("x,y,z", ZZ) + return x**2*y*z**2 + 2*x**2*y*z + 3*x**2*y + 2*x**2 + 3*x + 4*y**2*z**2 + 5*y**2*z + 6*y**2 + y*z**2 + 2*y*z + y + 1 + +def _f_1(): + R, x, y, z = ring("x,y,z", ZZ) + return x**3*y*z + x**2*y**2*z**2 + x**2*y**2 + 20*x**2*y*z + 30*x**2*y + x**2*z**2 + 10*x**2*z + x*y**3*z + 30*x*y**2*z + 20*x*y**2 + x*y*z**3 + 10*x*y*z**2 + x*y*z + 610*x*y + 20*x*z**2 + 230*x*z + 300*x + y**2*z**2 + 10*y**2*z + 30*y*z**2 + 320*y*z + 200*y + 600*z + 6000 + +def _f_2(): + R, x, y, z = ring("x,y,z", ZZ) + return x**5*y**3 + x**5*y**2*z + x**5*y*z**2 + x**5*z**3 + x**3*y**2 + x**3*y*z + 90*x**3*y + 90*x**3*z + x**2*y**2*z - 11*x**2*y**2 + x**2*z**3 - 11*x**2*z**2 + y*z - 11*y + 90*z - 990 + +def _f_3(): + R, x, y, z = ring("x,y,z", ZZ) + return x**5*y**2 + x**4*z**4 + x**4 + x**3*y**3*z + x**3*z + x**2*y**4 + x**2*y**3*z**3 + x**2*y*z**5 + x**2*y*z + x*y**2*z**4 + x*y**2 + x*y*z**7 + x*y*z**3 + x*y*z**2 + y**2*z + y*z**4 + +def _f_4(): + R, x, y, z = ring("x,y,z", ZZ) + return -x**9*y**8*z - x**8*y**5*z**3 - x**7*y**12*z**2 - 5*x**7*y**8 - x**6*y**9*z**4 + x**6*y**7*z**3 + 3*x**6*y**7*z - 5*x**6*y**5*z**2 - x**6*y**4*z**3 + x**5*y**4*z**5 + 3*x**5*y**4*z**3 - x**5*y*z**5 + x**4*y**11*z**4 + 3*x**4*y**11*z**2 - x**4*y**8*z**4 + 5*x**4*y**7*z**2 + 15*x**4*y**7 - 5*x**4*y**4*z**2 + x**3*y**8*z**6 + 3*x**3*y**8*z**4 - x**3*y**5*z**6 + 5*x**3*y**4*z**4 + 15*x**3*y**4*z**2 + x**3*y**3*z**5 + 3*x**3*y**3*z**3 - 5*x**3*y*z**4 + x**2*z**7 + 3*x**2*z**5 + x*y**7*z**6 + 3*x*y**7*z**4 + 5*x*y**3*z**4 + 15*x*y**3*z**2 + y**4*z**8 + 3*y**4*z**6 + 5*z**6 + 15*z**4 + +def _f_5(): + R, x, y, z = ring("x,y,z", ZZ) + return -x**3 - 3*x**2*y + 3*x**2*z - 3*x*y**2 + 6*x*y*z - 3*x*z**2 - y**3 + 3*y**2*z - 3*y*z**2 + z**3 + +def _f_6(): + R, x, y, z, t = ring("x,y,z,t", ZZ) + return 2115*x**4*y + 45*x**3*z**3*t**2 - 45*x**3*t**2 - 423*x*y**4 - 47*x*y**3 + 141*x*y*z**3 + 94*x*y*z*t - 9*y**3*z**3*t**2 + 9*y**3*t**2 - y**2*z**3*t**2 + y**2*t**2 + 3*z**6*t**2 + 2*z**4*t**3 - 3*z**3*t**2 - 2*z*t**3 + +def _w_1(): + R, x, y, z = ring("x,y,z", ZZ) + return 4*x**6*y**4*z**2 + 4*x**6*y**3*z**3 - 4*x**6*y**2*z**4 - 4*x**6*y*z**5 + x**5*y**4*z**3 + 12*x**5*y**3*z - x**5*y**2*z**5 + 12*x**5*y**2*z**2 - 12*x**5*y*z**3 - 12*x**5*z**4 + 8*x**4*y**4 + 6*x**4*y**3*z**2 + 8*x**4*y**3*z - 4*x**4*y**2*z**4 + 4*x**4*y**2*z**3 - 8*x**4*y**2*z**2 - 4*x**4*y*z**5 - 2*x**4*y*z**4 - 8*x**4*y*z**3 + 2*x**3*y**4*z + x**3*y**3*z**3 - x**3*y**2*z**5 - 2*x**3*y**2*z**3 + 9*x**3*y**2*z - 12*x**3*y*z**3 + 12*x**3*y*z**2 - 12*x**3*z**4 + 3*x**3*z**3 + 6*x**2*y**3 - 6*x**2*y**2*z**2 + 8*x**2*y**2*z - 2*x**2*y*z**4 - 8*x**2*y*z**3 + 2*x**2*y*z**2 + 2*x*y**3*z - 2*x*y**2*z**3 - 3*x*y*z + 3*x*z**3 - 2*y**2 + 2*y*z**2 + +def _w_2(): + R, x, y = ring("x,y", ZZ) + return 24*x**8*y**3 + 48*x**8*y**2 + 24*x**7*y**5 - 72*x**7*y**2 + 25*x**6*y**4 + 2*x**6*y**3 + 4*x**6*y + 8*x**6 + x**5*y**6 + x**5*y**3 - 12*x**5 + x**4*y**5 - x**4*y**4 - 2*x**4*y**3 + 292*x**4*y**2 - x**3*y**6 + 3*x**3*y**3 - x**2*y**5 + 12*x**2*y**3 + 48*x**2 - 12*y**3 + +def f_polys(): + return _f_0(), _f_1(), _f_2(), _f_3(), _f_4(), _f_5(), _f_6() + +def w_polys(): + return _w_1(), _w_2() diff -Nru python3-sympy-0.7.2/sympy/polys/sqfreetools.py python3-sympy-0.7.3/sympy/polys/sqfreetools.py --- python3-sympy-0.7.2/sympy/polys/sqfreetools.py 2012-10-17 03:02:22.000000000 +0000 +++ python3-sympy-0.7.3/sympy/polys/sqfreetools.py 2013-07-13 17:53:32.000000000 +0000 @@ -36,6 +36,7 @@ from sympy.utilities import cythonized + def dup_sqf_p(f, K): """ Return ``True`` if ``f`` is a square-free polynomial in ``K[x]``. @@ -43,12 +44,12 @@ Examples ======== - >>> from sympy.polys.domains import ZZ - >>> from sympy.polys.sqfreetools import dup_sqf_p + >>> from sympy.polys import ring, ZZ + >>> R, x = ring("x", ZZ) - >>> dup_sqf_p([ZZ(1),-ZZ(2), ZZ(1)], ZZ) + >>> R.dup_sqf_p(x**2 - 2*x + 1) False - >>> dup_sqf_p([ZZ(1), ZZ(0),-ZZ(1)], ZZ) + >>> R.dup_sqf_p(x**2 - 1) True """ @@ -57,6 +58,7 @@ else: return not dup_degree(dup_gcd(f, dup_diff(f, 1, K), K)) + @cythonized("u") def dmp_sqf_p(f, u, K): """ @@ -65,15 +67,12 @@ Examples ======== - >>> from sympy.polys.domains import ZZ - >>> from sympy.polys.sqfreetools import dmp_sqf_p + >>> from sympy.polys import ring, ZZ + >>> R, x,y = ring("x,y", ZZ) - >>> f = ZZ.map([[1], [2, 0], [1, 0, 0]]) - >>> dmp_sqf_p(f, 1, ZZ) + >>> R.dmp_sqf_p(x**2 + 2*x*y + y**2) False - - >>> f = ZZ.map([[1], [], [1, 0, 0]]) - >>> dmp_sqf_p(f, 1, ZZ) + >>> R.dmp_sqf_p(x**2 + y**2) True """ @@ -82,6 +81,7 @@ else: return not dmp_degree(dmp_gcd(f, dmp_diff(f, 1, u, K), u, K), u) + @cythonized("s") def dup_sqf_norm(f, K): """ @@ -93,19 +93,20 @@ Examples ======== + >>> from sympy.polys import ring, QQ >>> from sympy import sqrt - >>> from sympy.polys.domains import QQ - >>> from sympy.polys.sqfreetools import dup_sqf_norm >>> K = QQ.algebraic_field(sqrt(3)) + >>> R, x = ring("x", K) + >>> _, X = ring("x", QQ) - >>> s, f, r = dup_sqf_norm([K(1), K(0), K(-2)], K) + >>> s, f, r = R.dup_sqf_norm(x**2 - 2) >>> s == 1 True - >>> f == [K(1), K([QQ(-2), QQ(0)]), K(1)] + >>> f == x**2 + K([QQ(-2), QQ(0)])*x + 1 True - >>> r == [1, 0, -10, 0, 1] + >>> r == X**4 - 10*X**2 + 1 True """ @@ -121,10 +122,11 @@ if dup_sqf_p(r, K.dom): break else: - f, s = dup_shift(f, -K.unit, K), s+1 + f, s = dup_shift(f, -K.unit, K), s + 1 return s, f, r + @cythonized("s,u") def dmp_sqf_norm(f, u, K): """ @@ -136,19 +138,20 @@ Examples ======== + >>> from sympy.polys import ring, QQ >>> from sympy import I - >>> from sympy.polys.domains import QQ - >>> from sympy.polys.sqfreetools import dmp_sqf_norm >>> K = QQ.algebraic_field(I) + >>> R, x, y = ring("x,y", K) + >>> _, X, Y = ring("x,y", QQ) - >>> s, f, r = dmp_sqf_norm([[K(1), K(0)], [K(1), K(0), K(0)]], 1, K) + >>> s, f, r = R.dmp_sqf_norm(x*y + y**2) >>> s == 1 True - >>> f == [[K(1), K(0)], [K(1), K([QQ(-1), QQ(0)]), K(0)]] + >>> f == x*y + y**2 + K([QQ(-1), QQ(0)])*y True - >>> r == [[1, 0, 0], [2, 0, 0, 0], [1, 0, 1, 0, 0]] + >>> r == X**2*Y**2 + 2*X*Y**3 + Y**4 + Y**2 True """ @@ -158,22 +161,23 @@ if not K.is_Algebraic: raise DomainError("ground domain must be algebraic") - g = dmp_raise(K.mod.rep, u+1, 0, K.dom) - F = dmp_raise([K.one,-K.unit], u, 0, K) + g = dmp_raise(K.mod.rep, u + 1, 0, K.dom) + F = dmp_raise([K.one, -K.unit], u, 0, K) s = 0 while True: h, _ = dmp_inject(f, u, K, front=True) - r = dmp_resultant(g, h, u+1, K.dom) + r = dmp_resultant(g, h, u + 1, K.dom) if dmp_sqf_p(r, u, K.dom): break else: - f, s = dmp_compose(f, F, u, K), s+1 + f, s = dmp_compose(f, F, u, K), s + 1 return s, f, r + @cythonized("i") def dup_gf_sqf_part(f, K): """Compute square-free part of ``f`` in ``GF(p)[x]``. """ @@ -181,9 +185,11 @@ g = gf_sqf_part(f, K.mod, K.dom) return dup_convert(g, K.dom, K) + def dmp_gf_sqf_part(f, K): """Compute square-free part of ``f`` in ``GF(p)[X]``. """ - raise DomainError('multivariate polynomials over %s' % K) + raise NotImplementedError('multivariate polynomials over finite fields') + def dup_sqf_part(f, K): """ @@ -192,14 +198,14 @@ Examples ======== - >>> from sympy.polys.domains import ZZ - >>> from sympy.polys.sqfreetools import dup_sqf_part + >>> from sympy.polys import ring, ZZ + >>> R, x = ring("x", ZZ) - >>> dup_sqf_part([ZZ(1), ZZ(0), -ZZ(3), -ZZ(2)], ZZ) - [1, -1, -2] + >>> R.dup_sqf_part(x**3 - 3*x - 2) + x**2 - x - 2 """ - if not K.has_CharacteristicZero: + if K.is_FiniteField: return dup_gf_sqf_part(f, K) if not f: @@ -216,6 +222,7 @@ else: return dup_primitive(sqf, K)[1] + @cythonized("u") def dmp_sqf_part(f, u, K): """ @@ -224,19 +231,17 @@ Examples ======== - >>> from sympy.polys.domains import ZZ - >>> from sympy.polys.sqfreetools import dmp_sqf_part + >>> from sympy.polys import ring, ZZ + >>> R, x,y = ring("x,y", ZZ) - >>> f = ZZ.map([[1], [2, 0], [1, 0, 0], []]) - - >>> dmp_sqf_part(f, 1, ZZ) - [[1], [1, 0], []] + >>> R.dmp_sqf_part(x**3 + 2*x**2*y + x*y**2) + x**2 + x*y """ if not u: return dup_sqf_part(f, K) - if not K.has_CharacteristicZero: + if K.is_FiniteField: return dmp_gf_sqf_part(f, u, K) if dmp_zero_p(f, u): @@ -253,6 +258,7 @@ else: return dmp_ground_primitive(sqf, u, K)[1] + @cythonized("i") def dup_gf_sqf_list(f, K, all=False): """Compute square-free decomposition of ``f`` in ``GF(p)[x]``. """ @@ -265,9 +271,11 @@ return K.convert(coeff, K.dom), factors + def dmp_gf_sqf_list(f, u, K, all=False): """Compute square-free decomposition of ``f`` in ``GF(p)[X]``. """ - raise DomainError('multivariate polynomials over %s' % K) + raise NotImplementedError('multivariate polynomials over finite fields') + @cythonized("i") def dup_sqf_list(f, K, all=False): @@ -277,19 +285,18 @@ Examples ======== - >>> from sympy.polys.domains import ZZ - >>> from sympy.polys.sqfreetools import dup_sqf_list - - >>> f = ZZ.map([2, 16, 50, 76, 56, 16]) + >>> from sympy.polys import ring, ZZ + >>> R, x = ring("x", ZZ) - >>> dup_sqf_list(f, ZZ) - (2, [([1, 1], 2), ([1, 2], 3)]) + >>> f = 2*x**5 + 16*x**4 + 50*x**3 + 76*x**2 + 56*x + 16 - >>> dup_sqf_list(f, ZZ, all=True) - (2, [([1], 1), ([1, 1], 2), ([1, 2], 3)]) + >>> R.dup_sqf_list(f) + (2, [(x + 1, 2), (x + 2, 3)]) + >>> R.dup_sqf_list(f, all=True) + (2, [(1, 1), (x + 1, 2), (x + 2, 3)]) """ - if not K.has_CharacteristicZero: + if K.is_FiniteField: return dup_gf_sqf_list(f, K, all=all) if K.has_Field or not K.is_Exact: @@ -327,6 +334,7 @@ return coeff, result + def dup_sqf_list_include(f, K, all=False): """ Return square-free decomposition of a polynomial in ``K[x]``. @@ -334,16 +342,15 @@ Examples ======== - >>> from sympy.polys.domains import ZZ - >>> from sympy.polys.sqfreetools import dup_sqf_list_include + >>> from sympy.polys import ring, ZZ + >>> R, x = ring("x", ZZ) - >>> f = ZZ.map([2, 16, 50, 76, 56, 16]) + >>> f = 2*x**5 + 16*x**4 + 50*x**3 + 76*x**2 + 56*x + 16 - >>> dup_sqf_list_include(f, ZZ) - [([2], 1), ([1, 1], 2), ([1, 2], 3)] - - >>> dup_sqf_list_include(f, ZZ, all=True) - [([2], 1), ([1, 1], 2), ([1, 2], 3)] + >>> R.dup_sqf_list_include(f) + [(2, 1), (x + 1, 2), (x + 2, 3)] + >>> R.dup_sqf_list_include(f, all=True) + [(2, 1), (x + 1, 2), (x + 2, 3)] """ coeff, factors = dup_sqf_list(f, K, all=all) @@ -355,6 +362,7 @@ g = dup_strip([coeff]) return [(g, 1)] + factors + @cythonized("u,i") def dmp_sqf_list(f, u, K, all=False): """ @@ -363,22 +371,21 @@ Examples ======== - >>> from sympy.polys.domains import ZZ - >>> from sympy.polys.sqfreetools import dmp_sqf_list - - >>> f = ZZ.map([[1], [2, 0], [1, 0, 0], [], [], []]) + >>> from sympy.polys import ring, ZZ + >>> R, x,y = ring("x,y", ZZ) - >>> dmp_sqf_list(f, 1, ZZ) - (1, [([[1], [1, 0]], 2), ([[1], []], 3)]) + >>> f = x**5 + 2*x**4*y + x**3*y**2 - >>> dmp_sqf_list(f, 1, ZZ, all=True) - (1, [([[1]], 1), ([[1], [1, 0]], 2), ([[1], []], 3)]) + >>> R.dmp_sqf_list(f) + (1, [(x + y, 2), (x, 3)]) + >>> R.dmp_sqf_list(f, all=True) + (1, [(1, 1), (x + y, 2), (x, 3)]) """ if not u: return dup_sqf_list(f, K, all=all) - if not K.has_CharacteristicZero: + if K.is_FiniteField: return dmp_gf_sqf_list(f, u, K, all=all) if K.has_Field or not K.is_Exact: @@ -416,6 +423,7 @@ return coeff, result + @cythonized("u") def dmp_sqf_list_include(f, u, K, all=False): """ @@ -424,16 +432,15 @@ Examples ======== - >>> from sympy.polys.domains import ZZ - >>> from sympy.polys.sqfreetools import dmp_sqf_list_include - - >>> f = ZZ.map([[1], [2, 0], [1, 0, 0], [], [], []]) + >>> from sympy.polys import ring, ZZ + >>> R, x,y = ring("x,y", ZZ) - >>> dmp_sqf_list_include(f, 1, ZZ) - [([[1]], 1), ([[1], [1, 0]], 2), ([[1], []], 3)] + >>> f = x**5 + 2*x**4*y + x**3*y**2 - >>> dmp_sqf_list_include(f, 1, ZZ, all=True) - [([[1]], 1), ([[1], [1, 0]], 2), ([[1], []], 3)] + >>> R.dmp_sqf_list_include(f) + [(1, 1), (x + y, 2), (x, 3)] + >>> R.dmp_sqf_list_include(f, all=True) + [(1, 1), (x + y, 2), (x, 3)] """ if not u: @@ -448,6 +455,7 @@ g = dmp_ground(coeff, u) return [(g, 1)] + factors + def dup_gff_list(f, K): """ Compute greatest factorial factorization of ``f`` in ``K[x]``. @@ -455,13 +463,11 @@ Examples ======== - >>> from sympy.polys.domains import ZZ - >>> from sympy.polys.sqfreetools import dup_gff_list + >>> from sympy.polys import ring, ZZ + >>> R, x = ring("x", ZZ) - >>> f = ZZ.map([1, 2, -1, -2, 0, 0]) - - >>> dup_gff_list(f, ZZ) - [([1, 0], 1), ([1, 2], 4)] + >>> R.dup_gff_list(x**5 + 2*x**4 - x**3 - 2*x**2) + [(x, 1), (x + 2, 4)] """ if not f: @@ -486,6 +492,7 @@ else: return [(f, 1)] + H + def dmp_gff_list(f, u, K): """ Compute greatest factorial factorization of ``f`` in ``K[X]``. @@ -493,8 +500,8 @@ Examples ======== - >>> from sympy.polys.domains import ZZ - >>> from sympy.polys.sqfreetools import dmp_gff_list + >>> from sympy.polys import ring, ZZ + >>> R, x,y = ring("x,y", ZZ) """ if not u: diff -Nru python3-sympy-0.7.2/sympy/polys/tests/test_constructor.py python3-sympy-0.7.3/sympy/polys/tests/test_constructor.py --- python3-sympy-0.7.2/sympy/polys/tests/test_constructor.py 2012-10-17 03:02:22.000000000 +0000 +++ python3-sympy-0.7.3/sympy/polys/tests/test_constructor.py 2013-07-13 17:53:32.000000000 +0000 @@ -6,27 +6,34 @@ from sympy import S, sqrt, sin from sympy.abc import x, y + def test_construct_domain(): assert construct_domain([1, 2, 3]) == (ZZ, [ZZ(1), ZZ(2), ZZ(3)]) - assert construct_domain([1, 2, 3], field=True) == (QQ, [QQ(1), QQ(2), QQ(3)]) + assert construct_domain( + [1, 2, 3], field=True) == (QQ, [QQ(1), QQ(2), QQ(3)]) assert construct_domain([S(1), S(2), S(3)]) == (ZZ, [ZZ(1), ZZ(2), ZZ(3)]) - assert construct_domain([S(1), S(2), S(3)], field=True) == (QQ, [QQ(1), QQ(2), QQ(3)]) - - assert construct_domain([S(1)/2, S(2)]) == (QQ, [QQ(1,2), QQ(2)]) - assert construct_domain([3.14, 1, S(1)/2]) == (RR, [RR(3.14), RR(1.0), RR(0.5)]) + assert construct_domain( + [S(1), S(2), S(3)], field=True) == (QQ, [QQ(1), QQ(2), QQ(3)]) - assert construct_domain([3.14, sqrt(2)], extension=None) == (EX, [EX(3.14), EX(sqrt(2))]) - assert construct_domain([3.14, sqrt(2)], extension=True) == (EX, [EX(3.14), EX(sqrt(2))]) + assert construct_domain([S(1)/2, S(2)]) == (QQ, [QQ(1, 2), QQ(2)]) + assert construct_domain( + [3.14, 1, S(1)/2]) == (RR, [RR(3.14), RR(1.0), RR(0.5)]) + + assert construct_domain( + [3.14, sqrt(2)], extension=None) == (EX, [EX(3.14), EX(sqrt(2))]) + assert construct_domain( + [3.14, sqrt(2)], extension=True) == (EX, [EX(3.14), EX(sqrt(2))]) - assert construct_domain([1, sqrt(2)], extension=None) == (EX, [EX(1), EX(sqrt(2))]) + assert construct_domain( + [1, sqrt(2)], extension=None) == (EX, [EX(1), EX(sqrt(2))]) alg = QQ.algebraic_field(sqrt(2)) assert construct_domain([7, S(1)/2, sqrt(2)], extension=True) == \ (alg, [alg.convert(7), alg.convert(S(1)/2), alg.convert(sqrt(2))]) - alg = QQ.algebraic_field(sqrt(2)+sqrt(3)) + alg = QQ.algebraic_field(sqrt(2) + sqrt(3)) assert construct_domain([7, sqrt(2), sqrt(3)], extension=True) == \ (alg, [alg.convert(7), alg.convert(sqrt(2)), alg.convert(sqrt(3))]) @@ -36,7 +43,7 @@ assert construct_domain([2*x, 3]) == \ (dom, [dom.convert(2*x), dom.convert(3)]) - dom = ZZ[x,y] + dom = ZZ[x, y] assert construct_domain([2*x, 3*y]) == \ (dom, [dom.convert(2*x), dom.convert(3*y)]) @@ -46,7 +53,7 @@ assert construct_domain([x/2, 3]) == \ (dom, [dom.convert(x/2), dom.convert(3)]) - dom = QQ[x,y] + dom = QQ[x, y] assert construct_domain([x/2, 3*y]) == \ (dom, [dom.convert(x/2), dom.convert(3*y)]) @@ -56,7 +63,7 @@ assert construct_domain([x/2, 3.5]) == \ (dom, [dom.convert(x/2), dom.convert(3.5)]) - dom = RR[x,y] + dom = RR[x, y] assert construct_domain([x/2, 3.5*y]) == \ (dom, [dom.convert(x/2), dom.convert(3.5*y)]) @@ -66,7 +73,7 @@ assert construct_domain([2/x, 3]) == \ (dom, [dom.convert(2/x), dom.convert(3)]) - dom = ZZ.frac_field(x,y) + dom = ZZ.frac_field(x, y) assert construct_domain([2/x, 3*y]) == \ (dom, [dom.convert(2/x), dom.convert(3*y)]) @@ -76,7 +83,7 @@ assert construct_domain([2/x, 3.5]) == \ (dom, [dom.convert(2/x), dom.convert(3.5)]) - dom = RR.frac_field(x,y) + dom = RR.frac_field(x, y) assert construct_domain([2/x, 3.5*y]) == \ (dom, [dom.convert(2/x), dom.convert(3.5*y)]) @@ -84,6 +91,8 @@ assert construct_domain(2) == (ZZ, ZZ(2)) assert construct_domain(S(2)/3) == (QQ, QQ(2, 3)) + assert construct_domain({}) == (ZZ, {}) + def test_composite_option(): assert construct_domain({(1,): sin(y)}, composite=False) == \ (EX, {(1,): EX(sin(y))}) diff -Nru python3-sympy-0.7.2/sympy/polys/tests/test_densearith.py python3-sympy-0.7.3/sympy/polys/tests/test_densearith.py --- python3-sympy-0.7.2/sympy/polys/tests/test_densearith.py 2012-10-17 03:02:22.000000000 +0000 +++ python3-sympy-0.7.3/sympy/polys/tests/test_densearith.py 2013-07-13 17:53:32.000000000 +0000 @@ -38,12 +38,13 @@ ExactQuotientFailed, ) -from sympy.polys.specialpolys import f_0 +from sympy.polys.specialpolys import f_polys from sympy.polys.domains import FF, ZZ, QQ from sympy.utilities.pytest import raises -F_0 = dmp_mul_ground(dmp_normal(f_0, 2, QQ), QQ(1,7), 2, QQ) +f_0, f_1, f_2, f_3, f_4, f_5, f_6 = [ f.to_dense() for f in f_polys() ] +F_0 = dmp_mul_ground(dmp_normal(f_0, 2, QQ), QQ(1, 7), 2, QQ) def test_dup_add_term(): f = dup_normal([], ZZ) @@ -54,7 +55,7 @@ assert dup_add_term(f, ZZ(1), 1, ZZ) == dup_normal([1, 0], ZZ) assert dup_add_term(f, ZZ(1), 2, ZZ) == dup_normal([1, 0, 0], ZZ) - f = dup_normal([1,1,1], ZZ) + f = dup_normal([1, 1, 1], ZZ) assert dup_add_term(f, ZZ(1), 0, ZZ) == dup_normal([1, 1, 2], ZZ) assert dup_add_term(f, ZZ(1), 1, ZZ) == dup_normal([1, 2, 1], ZZ) @@ -63,16 +64,19 @@ assert dup_add_term(f, ZZ(1), 3, ZZ) == dup_normal([1, 1, 1, 1], ZZ) assert dup_add_term(f, ZZ(1), 4, ZZ) == dup_normal([1, 0, 1, 1, 1], ZZ) assert dup_add_term(f, ZZ(1), 5, ZZ) == dup_normal([1, 0, 0, 1, 1, 1], ZZ) - assert dup_add_term(f, ZZ(1), 6, ZZ) == dup_normal([1, 0, 0, 0, 1, 1, 1], ZZ) + assert dup_add_term( + f, ZZ(1), 6, ZZ) == dup_normal([1, 0, 0, 0, 1, 1, 1], ZZ) + + assert dup_add_term(f, ZZ(-1), 2, ZZ) == dup_normal([1, 1], ZZ) - assert dup_add_term(f,ZZ(-1), 2, ZZ) == dup_normal([1, 1], ZZ) def test_dmp_add_term(): - assert dmp_add_term([ZZ(1),ZZ(1),ZZ(1)], ZZ(1), 2, 0, ZZ) == \ - dup_add_term([ZZ(1),ZZ(1),ZZ(1)], ZZ(1), 2, ZZ) + assert dmp_add_term([ZZ(1), ZZ(1), ZZ(1)], ZZ(1), 2, 0, ZZ) == \ + dup_add_term([ZZ(1), ZZ(1), ZZ(1)], ZZ(1), 2, ZZ) assert dmp_add_term(f_0, [[]], 3, 2, ZZ) == f_0 assert dmp_add_term(F_0, [[]], 3, 2, QQ) == F_0 + def test_dup_sub_term(): f = dup_normal([], ZZ) @@ -82,210 +86,240 @@ assert dup_sub_term(f, ZZ(1), 1, ZZ) == dup_normal([-1, 0], ZZ) assert dup_sub_term(f, ZZ(1), 2, ZZ) == dup_normal([-1, 0, 0], ZZ) - f = dup_normal([1,1,1], ZZ) + f = dup_normal([1, 1, 1], ZZ) - assert dup_sub_term(f, ZZ(2), 0, ZZ) == dup_normal([ 1, 1,-1], ZZ) - assert dup_sub_term(f, ZZ(2), 1, ZZ) == dup_normal([ 1,-1, 1], ZZ) + assert dup_sub_term(f, ZZ(2), 0, ZZ) == dup_normal([ 1, 1, -1], ZZ) + assert dup_sub_term(f, ZZ(2), 1, ZZ) == dup_normal([ 1, -1, 1], ZZ) assert dup_sub_term(f, ZZ(2), 2, ZZ) == dup_normal([-1, 1, 1], ZZ) assert dup_sub_term(f, ZZ(1), 3, ZZ) == dup_normal([-1, 1, 1, 1], ZZ) assert dup_sub_term(f, ZZ(1), 4, ZZ) == dup_normal([-1, 0, 1, 1, 1], ZZ) assert dup_sub_term(f, ZZ(1), 5, ZZ) == dup_normal([-1, 0, 0, 1, 1, 1], ZZ) - assert dup_sub_term(f, ZZ(1), 6, ZZ) == dup_normal([-1, 0, 0, 0, 1, 1, 1], ZZ) + assert dup_sub_term( + f, ZZ(1), 6, ZZ) == dup_normal([-1, 0, 0, 0, 1, 1, 1], ZZ) assert dup_sub_term(f, ZZ(1), 2, ZZ) == dup_normal([1, 1], ZZ) + def test_dmp_sub_term(): - assert dmp_sub_term([ZZ(1),ZZ(1),ZZ(1)], ZZ(1), 2, 0, ZZ) == \ - dup_sub_term([ZZ(1),ZZ(1),ZZ(1)], ZZ(1), 2, ZZ) + assert dmp_sub_term([ZZ(1), ZZ(1), ZZ(1)], ZZ(1), 2, 0, ZZ) == \ + dup_sub_term([ZZ(1), ZZ(1), ZZ(1)], ZZ(1), 2, ZZ) assert dmp_sub_term(f_0, [[]], 3, 2, ZZ) == f_0 assert dmp_sub_term(F_0, [[]], 3, 2, QQ) == F_0 + def test_dup_mul_term(): f = dup_normal([], ZZ) assert dup_mul_term(f, ZZ(2), 3, ZZ) == dup_normal([], ZZ) - f = dup_normal([1,1], ZZ) + f = dup_normal([1, 1], ZZ) assert dup_mul_term(f, ZZ(0), 3, ZZ) == dup_normal([], ZZ) - f = dup_normal([1,2,3], ZZ) + f = dup_normal([1, 2, 3], ZZ) + + assert dup_mul_term(f, ZZ(2), 0, ZZ) == dup_normal([2, 4, 6], ZZ) + assert dup_mul_term(f, ZZ(2), 1, ZZ) == dup_normal([2, 4, 6, 0], ZZ) + assert dup_mul_term(f, ZZ(2), 2, ZZ) == dup_normal([2, 4, 6, 0, 0], ZZ) + assert dup_mul_term(f, ZZ(2), 3, ZZ) == dup_normal([2, 4, 6, 0, 0, 0], ZZ) - assert dup_mul_term(f, ZZ(2), 0, ZZ) == dup_normal([2,4,6], ZZ) - assert dup_mul_term(f, ZZ(2), 1, ZZ) == dup_normal([2,4,6,0], ZZ) - assert dup_mul_term(f, ZZ(2), 2, ZZ) == dup_normal([2,4,6,0,0], ZZ) - assert dup_mul_term(f, ZZ(2), 3, ZZ) == dup_normal([2,4,6,0,0,0], ZZ) def test_dmp_mul_term(): - assert dmp_mul_term([ZZ(1),ZZ(2),ZZ(3)], ZZ(2), 1, 0, ZZ) == \ - dup_mul_term([ZZ(1),ZZ(2),ZZ(3)], ZZ(2), 1, ZZ) + assert dmp_mul_term([ZZ(1), ZZ(2), ZZ(3)], ZZ(2), 1, 0, ZZ) == \ + dup_mul_term([ZZ(1), ZZ(2), ZZ(3)], ZZ(2), 1, ZZ) assert dmp_mul_term([[]], [ZZ(2)], 3, 1, ZZ) == [[]] assert dmp_mul_term([[ZZ(1)]], [], 3, 1, ZZ) == [[]] - assert dmp_mul_term([[ZZ(1),ZZ(2)], [ZZ(3)]], [ZZ(2)], 2, 1, ZZ) == \ - [[ZZ(2),ZZ(4)], [ZZ(6)], [], []] + assert dmp_mul_term([[ZZ(1), ZZ(2)], [ZZ(3)]], [ZZ(2)], 2, 1, ZZ) == \ + [[ZZ(2), ZZ(4)], [ZZ(6)], [], []] + + assert dmp_mul_term([[]], [QQ(2, 3)], 3, 1, QQ) == [[]] + assert dmp_mul_term([[QQ(1, 2)]], [], 3, 1, QQ) == [[]] - assert dmp_mul_term([[]], [QQ(2,3)], 3, 1, QQ) == [[]] - assert dmp_mul_term([[QQ(1,2)]], [], 3, 1, QQ) == [[]] + assert dmp_mul_term([[QQ(1, 5), QQ(2, 5)], [QQ(3, 5)]], [QQ(2, 3)], 2, 1, QQ) == \ + [[QQ(2, 15), QQ(4, 15)], [QQ(6, 15)], [], []] - assert dmp_mul_term([[QQ(1,5),QQ(2,5)], [QQ(3,5)]], [QQ(2,3)], 2, 1, QQ) == \ - [[QQ(2,15),QQ(4,15)], [QQ(6,15)], [], []] -def dup_add_ground(): +def test_dup_add_ground(): f = ZZ.map([1, 2, 3, 4]) g = ZZ.map([1, 2, 3, 8]) assert dup_add_ground(f, ZZ(4), ZZ) == g -def dmp_add_ground(): + +def test_dmp_add_ground(): f = ZZ.map([[1], [2], [3], [4]]) g = ZZ.map([[1], [2], [3], [8]]) assert dmp_add_ground(f, ZZ(4), 1, ZZ) == g -def dup_sub_ground(): + +def test_dup_sub_ground(): f = ZZ.map([1, 2, 3, 4]) g = ZZ.map([1, 2, 3, 0]) assert dup_sub_ground(f, ZZ(4), ZZ) == g -def dmp_sub_ground(): + +def test_dmp_sub_ground(): f = ZZ.map([[1], [2], [3], [4]]) g = ZZ.map([[1], [2], [3], []]) assert dmp_sub_ground(f, ZZ(4), 1, ZZ) == g + def test_dup_mul_ground(): f = dup_normal([], ZZ) assert dup_mul_ground(f, ZZ(2), ZZ) == dup_normal([], ZZ) - f = dup_normal([1,2,3], ZZ) + f = dup_normal([1, 2, 3], ZZ) assert dup_mul_ground(f, ZZ(0), ZZ) == dup_normal([], ZZ) - assert dup_mul_ground(f, ZZ(2), ZZ) == dup_normal([2,4,6], ZZ) + assert dup_mul_ground(f, ZZ(2), ZZ) == dup_normal([2, 4, 6], ZZ) + def test_dmp_mul_ground(): assert dmp_mul_ground(f_0, ZZ(2), 2, ZZ) == [ - [[ZZ(2),ZZ(4),ZZ(6)], [ZZ(4)]], + [[ZZ(2), ZZ(4), ZZ(6)], [ZZ(4)]], [[ZZ(6)]], - [[ZZ(8),ZZ(10),ZZ(12)], [ZZ(2),ZZ(4),ZZ(2)], [ZZ(2)]] + [[ZZ(8), ZZ(10), ZZ(12)], [ZZ(2), ZZ(4), ZZ(2)], [ZZ(2)]] ] - assert dmp_mul_ground(F_0, QQ(1,2), 2, QQ) == [ - [[QQ(1,14),QQ(2,14),QQ(3,14)], [QQ(2,14)]], - [[QQ(3,14)]], - [[QQ(4,14),QQ(5,14),QQ(6,14)], [QQ(1,14),QQ(2,14),QQ(1,14)], [QQ(1,14)]] + assert dmp_mul_ground(F_0, QQ(1, 2), 2, QQ) == [ + [[QQ(1, 14), QQ(2, 14), QQ(3, 14)], [QQ(2, 14)]], + [[QQ(3, 14)]], + [[QQ(4, 14), QQ(5, 14), QQ(6, 14)], [QQ(1, 14), QQ(2, 14), + QQ(1, 14)], [QQ(1, 14)]] ] + def test_dup_quo_ground(): - raises(ZeroDivisionError, lambda: dup_quo_ground(dup_normal([1,2,3], ZZ), ZZ(0), ZZ)) + raises(ZeroDivisionError, lambda: dup_quo_ground(dup_normal([1, 2, + 3], ZZ), ZZ(0), ZZ)) f = dup_normal([], ZZ) assert dup_quo_ground(f, ZZ(3), ZZ) == dup_normal([], ZZ) - f = dup_normal([6,2,8], ZZ) + f = dup_normal([6, 2, 8], ZZ) assert dup_quo_ground(f, ZZ(1), ZZ) == f - assert dup_quo_ground(f, ZZ(2), ZZ) == dup_normal([3,1,4], ZZ) + assert dup_quo_ground(f, ZZ(2), ZZ) == dup_normal([3, 1, 4], ZZ) - assert dup_quo_ground(f, ZZ(3), ZZ) == dup_normal([2,0,2], ZZ) + assert dup_quo_ground(f, ZZ(3), ZZ) == dup_normal([2, 0, 2], ZZ) - f = dup_normal([6,2,8], QQ) + f = dup_normal([6, 2, 8], QQ) assert dup_quo_ground(f, QQ(1), QQ) == f - assert dup_quo_ground(f, QQ(2), QQ) == [QQ(3),QQ(1),QQ(4)] - assert dup_quo_ground(f, QQ(7), QQ) == [QQ(6,7),QQ(2,7),QQ(8,7)] + assert dup_quo_ground(f, QQ(2), QQ) == [QQ(3), QQ(1), QQ(4)] + assert dup_quo_ground(f, QQ(7), QQ) == [QQ(6, 7), QQ(2, 7), QQ(8, 7)] + def test_dup_exquo_ground(): - raises(ZeroDivisionError, lambda: dup_exquo_ground(dup_normal([1,2,3], ZZ), ZZ(0), ZZ)) - raises(ExactQuotientFailed, lambda: dup_exquo_ground(dup_normal([1,2,3], ZZ), ZZ(3), ZZ)) + raises(ZeroDivisionError, lambda: dup_exquo_ground(dup_normal([1, + 2, 3], ZZ), ZZ(0), ZZ)) + raises(ExactQuotientFailed, lambda: dup_exquo_ground(dup_normal([1, + 2, 3], ZZ), ZZ(3), ZZ)) f = dup_normal([], ZZ) assert dup_exquo_ground(f, ZZ(3), ZZ) == dup_normal([], ZZ) - f = dup_normal([6,2,8], ZZ) + f = dup_normal([6, 2, 8], ZZ) assert dup_exquo_ground(f, ZZ(1), ZZ) == f - assert dup_exquo_ground(f, ZZ(2), ZZ) == dup_normal([3,1,4], ZZ) + assert dup_exquo_ground(f, ZZ(2), ZZ) == dup_normal([3, 1, 4], ZZ) - f = dup_normal([6,2,8], QQ) + f = dup_normal([6, 2, 8], QQ) assert dup_exquo_ground(f, QQ(1), QQ) == f - assert dup_exquo_ground(f, QQ(2), QQ) == [QQ(3),QQ(1),QQ(4)] - assert dup_exquo_ground(f, QQ(7), QQ) == [QQ(6,7),QQ(2,7),QQ(8,7)] + assert dup_exquo_ground(f, QQ(2), QQ) == [QQ(3), QQ(1), QQ(4)] + assert dup_exquo_ground(f, QQ(7), QQ) == [QQ(6, 7), QQ(2, 7), QQ(8, 7)] + def test_dmp_quo_ground(): - f = dmp_normal([[6],[2],[8]], 1, ZZ) + f = dmp_normal([[6], [2], [8]], 1, ZZ) assert dmp_quo_ground(f, ZZ(1), 1, ZZ) == f - assert dmp_quo_ground(f, ZZ(2), 1, ZZ) == dmp_normal([[3],[1],[4]], 1, ZZ) + assert dmp_quo_ground( + f, ZZ(2), 1, ZZ) == dmp_normal([[3], [1], [4]], 1, ZZ) + + assert dmp_normal(dmp_quo_ground( + f, ZZ(3), 1, ZZ), 1, ZZ) == dmp_normal([[2], [], [2]], 1, ZZ) - assert dmp_normal(dmp_quo_ground(f, ZZ(3), 1, ZZ), 1, ZZ) == dmp_normal([[2],[],[2]], 1, ZZ) def test_dmp_exquo_ground(): - f = dmp_normal([[6],[2],[8]], 1, ZZ) + f = dmp_normal([[6], [2], [8]], 1, ZZ) assert dmp_exquo_ground(f, ZZ(1), 1, ZZ) == f - assert dmp_exquo_ground(f, ZZ(2), 1, ZZ) == dmp_normal([[3],[1],[4]], 1, ZZ) + assert dmp_exquo_ground( + f, ZZ(2), 1, ZZ) == dmp_normal([[3], [1], [4]], 1, ZZ) + def test_dup_lshift(): assert dup_lshift([], 3, ZZ) == [] - assert dup_lshift([1], 3, ZZ) == [1,0,0,0] + assert dup_lshift([1], 3, ZZ) == [1, 0, 0, 0] + def test_dup_rshift(): assert dup_rshift([], 3, ZZ) == [] - assert dup_rshift([1,0,0,0], 3, ZZ) == [1] + assert dup_rshift([1, 0, 0, 0], 3, ZZ) == [1] + def test_dup_abs(): assert dup_abs([], ZZ) == [] assert dup_abs([ZZ( 1)], ZZ) == [ZZ(1)] assert dup_abs([ZZ(-7)], ZZ) == [ZZ(7)] - assert dup_abs([ZZ(-1),ZZ(2),ZZ(3)], ZZ) == [ZZ(1),ZZ(2),ZZ(3)] + assert dup_abs([ZZ(-1), ZZ(2), ZZ(3)], ZZ) == [ZZ(1), ZZ(2), ZZ(3)] assert dup_abs([], QQ) == [] - assert dup_abs([QQ( 1,2)], QQ) == [QQ(1,2)] - assert dup_abs([QQ(-7,3)], QQ) == [QQ(7,3)] - assert dup_abs([QQ(-1,7),QQ(2,7),QQ(3,7)], QQ) == [QQ(1,7),QQ(2,7),QQ(3,7)] + assert dup_abs([QQ( 1, 2)], QQ) == [QQ(1, 2)] + assert dup_abs([QQ(-7, 3)], QQ) == [QQ(7, 3)] + assert dup_abs( + [QQ(-1, 7), QQ(2, 7), QQ(3, 7)], QQ) == [QQ(1, 7), QQ(2, 7), QQ(3, 7)] + def test_dmp_abs(): assert dmp_abs([ZZ(-1)], 0, ZZ) == [ZZ(1)] - assert dmp_abs([QQ(-1,2)], 0, QQ) == [QQ(1,2)] + assert dmp_abs([QQ(-1, 2)], 0, QQ) == [QQ(1, 2)] assert dmp_abs([[[]]], 2, ZZ) == [[[]]] assert dmp_abs([[[ZZ(1)]]], 2, ZZ) == [[[ZZ(1)]]] assert dmp_abs([[[ZZ(-7)]]], 2, ZZ) == [[[ZZ(7)]]] assert dmp_abs([[[]]], 2, QQ) == [[[]]] - assert dmp_abs([[[QQ(1,2)]]], 2, QQ) == [[[QQ(1,2)]]] - assert dmp_abs([[[QQ(-7,9)]]], 2, QQ) == [[[QQ(7,9)]]] + assert dmp_abs([[[QQ(1, 2)]]], 2, QQ) == [[[QQ(1, 2)]]] + assert dmp_abs([[[QQ(-7, 9)]]], 2, QQ) == [[[QQ(7, 9)]]] + def test_dup_neg(): assert dup_neg([], ZZ) == [] assert dup_neg([ZZ(1)], ZZ) == [ZZ(-1)] assert dup_neg([ZZ(-7)], ZZ) == [ZZ(7)] - assert dup_neg([ZZ(-1),ZZ(2),ZZ(3)], ZZ) == [ZZ(1),ZZ(-2),ZZ(-3)] + assert dup_neg([ZZ(-1), ZZ(2), ZZ(3)], ZZ) == [ZZ(1), ZZ(-2), ZZ(-3)] assert dup_neg([], QQ) == [] - assert dup_neg([QQ(1,2)], QQ) == [QQ(-1,2)] - assert dup_neg([QQ(-7,9)], QQ) == [QQ(7,9)] - assert dup_neg([QQ(-1,7),QQ(2,7),QQ(3,7)], QQ) == [QQ(1,7),QQ(-2,7),QQ(-3,7)] + assert dup_neg([QQ(1, 2)], QQ) == [QQ(-1, 2)] + assert dup_neg([QQ(-7, 9)], QQ) == [QQ(7, 9)] + assert dup_neg([QQ( + -1, 7), QQ(2, 7), QQ(3, 7)], QQ) == [QQ(1, 7), QQ(-2, 7), QQ(-3, 7)] + def test_dmp_neg(): assert dmp_neg([ZZ(-1)], 0, ZZ) == [ZZ(1)] - assert dmp_neg([QQ(-1,2)], 0, QQ) == [QQ(1,2)] + assert dmp_neg([QQ(-1, 2)], 0, QQ) == [QQ(1, 2)] assert dmp_neg([[[]]], 2, ZZ) == [[[]]] assert dmp_neg([[[ZZ(1)]]], 2, ZZ) == [[[ZZ(-1)]]] assert dmp_neg([[[ZZ(-7)]]], 2, ZZ) == [[[ZZ(7)]]] assert dmp_neg([[[]]], 2, QQ) == [[[]]] - assert dmp_neg([[[QQ(1,9)]]], 2, QQ) == [[[QQ(-1,9)]]] - assert dmp_neg([[[QQ(-7,9)]]], 2, QQ) == [[[QQ(7,9)]]] + assert dmp_neg([[[QQ(1, 9)]]], 2, QQ) == [[[QQ(-1, 9)]]] + assert dmp_neg([[[QQ(-7, 9)]]], 2, QQ) == [[[QQ(7, 9)]]] + def test_dup_add(): assert dup_add([], [], ZZ) == [] @@ -294,27 +328,30 @@ assert dup_add([ZZ(1)], [ZZ(1)], ZZ) == [ZZ(2)] assert dup_add([ZZ(1)], [ZZ(2)], ZZ) == [ZZ(3)] - assert dup_add([ZZ(1),ZZ(2)], [ZZ(1)], ZZ) == [ZZ(1),ZZ(3)] - assert dup_add([ZZ(1)], [ZZ(1),ZZ(2)], ZZ) == [ZZ(1),ZZ(3)] + assert dup_add([ZZ(1), ZZ(2)], [ZZ(1)], ZZ) == [ZZ(1), ZZ(3)] + assert dup_add([ZZ(1)], [ZZ(1), ZZ(2)], ZZ) == [ZZ(1), ZZ(3)] - assert dup_add([ZZ(1),ZZ(2),ZZ(3)], [ZZ(8),ZZ(9),ZZ(10)], ZZ) == [ZZ(9),ZZ(11),ZZ(13)] + assert dup_add([ZZ(1), ZZ( + 2), ZZ(3)], [ZZ(8), ZZ(9), ZZ(10)], ZZ) == [ZZ(9), ZZ(11), ZZ(13)] assert dup_add([], [], QQ) == [] - assert dup_add([QQ(1,2)], [], QQ) == [QQ(1,2)] - assert dup_add([], [QQ(1,2)], QQ) == [QQ(1,2)] - assert dup_add([QQ(1,4)], [QQ(1,4)], QQ) == [QQ(1,2)] - assert dup_add([QQ(1,4)], [QQ(1,2)], QQ) == [QQ(3,4)] + assert dup_add([QQ(1, 2)], [], QQ) == [QQ(1, 2)] + assert dup_add([], [QQ(1, 2)], QQ) == [QQ(1, 2)] + assert dup_add([QQ(1, 4)], [QQ(1, 4)], QQ) == [QQ(1, 2)] + assert dup_add([QQ(1, 4)], [QQ(1, 2)], QQ) == [QQ(3, 4)] - assert dup_add([QQ(1,2),QQ(2,3)], [QQ(1)], QQ) == [QQ(1,2),QQ(5,3)] - assert dup_add([QQ(1)], [QQ(1,2),QQ(2,3)], QQ) == [QQ(1,2),QQ(5,3)] + assert dup_add([QQ(1, 2), QQ(2, 3)], [QQ(1)], QQ) == [QQ(1, 2), QQ(5, 3)] + assert dup_add([QQ(1)], [QQ(1, 2), QQ(2, 3)], QQ) == [QQ(1, 2), QQ(5, 3)] + + assert dup_add([QQ(1, 7), QQ(2, 7), QQ(3, 7)], [QQ( + 8, 7), QQ(9, 7), QQ(10, 7)], QQ) == [QQ(9, 7), QQ(11, 7), QQ(13, 7)] - assert dup_add([QQ(1,7),QQ(2,7),QQ(3,7)], [QQ(8,7),QQ(9,7),QQ(10,7)], QQ) == [QQ(9,7),QQ(11,7),QQ(13,7)] def test_dmp_add(): - assert dmp_add([ZZ(1),ZZ(2)], [ZZ(1)], 0, ZZ) == \ - dup_add([ZZ(1),ZZ(2)], [ZZ(1)], ZZ) - assert dmp_add([QQ(1,2),QQ(2,3)], [QQ(1)], 0, QQ) == \ - dup_add([QQ(1,2),QQ(2,3)], [QQ(1)], QQ) + assert dmp_add([ZZ(1), ZZ(2)], [ZZ(1)], 0, ZZ) == \ + dup_add([ZZ(1), ZZ(2)], [ZZ(1)], ZZ) + assert dmp_add([QQ(1, 2), QQ(2, 3)], [QQ(1)], 0, QQ) == \ + dup_add([QQ(1, 2), QQ(2, 3)], [QQ(1)], QQ) assert dmp_add([[[]]], [[[]]], 2, ZZ) == [[[]]] assert dmp_add([[[ZZ(1)]]], [[[]]], 2, ZZ) == [[[ZZ(1)]]] @@ -323,10 +360,11 @@ assert dmp_add([[[ZZ(1)]]], [[[ZZ(2)]]], 2, ZZ) == [[[ZZ(3)]]] assert dmp_add([[[]]], [[[]]], 2, QQ) == [[[]]] - assert dmp_add([[[QQ(1,2)]]], [[[]]], 2, QQ) == [[[QQ(1,2)]]] - assert dmp_add([[[]]], [[[QQ(1,2)]]], 2, QQ) == [[[QQ(1,2)]]] - assert dmp_add([[[QQ(2,7)]]], [[[QQ(1,7)]]], 2, QQ) == [[[QQ(3,7)]]] - assert dmp_add([[[QQ(1,7)]]], [[[QQ(2,7)]]], 2, QQ) == [[[QQ(3,7)]]] + assert dmp_add([[[QQ(1, 2)]]], [[[]]], 2, QQ) == [[[QQ(1, 2)]]] + assert dmp_add([[[]]], [[[QQ(1, 2)]]], 2, QQ) == [[[QQ(1, 2)]]] + assert dmp_add([[[QQ(2, 7)]]], [[[QQ(1, 7)]]], 2, QQ) == [[[QQ(3, 7)]]] + assert dmp_add([[[QQ(1, 7)]]], [[[QQ(2, 7)]]], 2, QQ) == [[[QQ(3, 7)]]] + def test_dup_sub(): assert dup_sub([], [], ZZ) == [] @@ -335,27 +373,30 @@ assert dup_sub([ZZ(1)], [ZZ(1)], ZZ) == [] assert dup_sub([ZZ(1)], [ZZ(2)], ZZ) == [ZZ(-1)] - assert dup_sub([ZZ(1),ZZ(2)], [ZZ(1)], ZZ) == [ZZ(1),ZZ(1)] - assert dup_sub([ZZ(1)], [ZZ(1),ZZ(2)], ZZ) == [ZZ(-1),ZZ(-1)] + assert dup_sub([ZZ(1), ZZ(2)], [ZZ(1)], ZZ) == [ZZ(1), ZZ(1)] + assert dup_sub([ZZ(1)], [ZZ(1), ZZ(2)], ZZ) == [ZZ(-1), ZZ(-1)] - assert dup_sub([ZZ(3),ZZ(2),ZZ(1)], [ZZ(8),ZZ(9),ZZ(10)], ZZ) == [ZZ(-5),ZZ(-7),ZZ(-9)] + assert dup_sub([ZZ(3), ZZ( + 2), ZZ(1)], [ZZ(8), ZZ(9), ZZ(10)], ZZ) == [ZZ(-5), ZZ(-7), ZZ(-9)] assert dup_sub([], [], QQ) == [] - assert dup_sub([QQ(1,2)], [], QQ) == [QQ(1,2)] - assert dup_sub([], [QQ(1,2)], QQ) == [QQ(-1,2)] - assert dup_sub([QQ(1,3)], [QQ(1,3)], QQ) == [] - assert dup_sub([QQ(1,3)], [QQ(2,3)], QQ) == [QQ(-1,3)] + assert dup_sub([QQ(1, 2)], [], QQ) == [QQ(1, 2)] + assert dup_sub([], [QQ(1, 2)], QQ) == [QQ(-1, 2)] + assert dup_sub([QQ(1, 3)], [QQ(1, 3)], QQ) == [] + assert dup_sub([QQ(1, 3)], [QQ(2, 3)], QQ) == [QQ(-1, 3)] + + assert dup_sub([QQ(1, 7), QQ(2, 7)], [QQ(1)], QQ) == [QQ(1, 7), QQ(-5, 7)] + assert dup_sub([QQ(1)], [QQ(1, 7), QQ(2, 7)], QQ) == [QQ(-1, 7), QQ(5, 7)] - assert dup_sub([QQ(1,7),QQ(2,7)], [QQ(1)], QQ) == [QQ(1,7),QQ(-5,7)] - assert dup_sub([QQ(1)], [QQ(1,7),QQ(2,7)], QQ) == [QQ(-1,7),QQ(5,7)] + assert dup_sub([QQ(3, 7), QQ(2, 7), QQ(1, 7)], [QQ( + 8, 7), QQ(9, 7), QQ(10, 7)], QQ) == [QQ(-5, 7), QQ(-7, 7), QQ(-9, 7)] - assert dup_sub([QQ(3,7),QQ(2,7),QQ(1,7)], [QQ(8,7),QQ(9,7),QQ(10,7)], QQ) == [QQ(-5,7),QQ(-7,7),QQ(-9,7)] def test_dmp_sub(): - assert dmp_sub([ZZ(1),ZZ(2)], [ZZ(1)], 0, ZZ) == \ - dup_sub([ZZ(1),ZZ(2)], [ZZ(1)], ZZ) - assert dmp_sub([QQ(1,2),QQ(2,3)], [QQ(1)], 0, QQ) == \ - dup_sub([QQ(1,2),QQ(2,3)], [QQ(1)], QQ) + assert dmp_sub([ZZ(1), ZZ(2)], [ZZ(1)], 0, ZZ) == \ + dup_sub([ZZ(1), ZZ(2)], [ZZ(1)], ZZ) + assert dmp_sub([QQ(1, 2), QQ(2, 3)], [QQ(1)], 0, QQ) == \ + dup_sub([QQ(1, 2), QQ(2, 3)], [QQ(1)], QQ) assert dmp_sub([[[]]], [[[]]], 2, ZZ) == [[[]]] assert dmp_sub([[[ZZ(1)]]], [[[]]], 2, ZZ) == [[[ZZ(1)]]] @@ -364,26 +405,31 @@ assert dmp_sub([[[ZZ(1)]]], [[[ZZ(2)]]], 2, ZZ) == [[[ZZ(-1)]]] assert dmp_sub([[[]]], [[[]]], 2, QQ) == [[[]]] - assert dmp_sub([[[QQ(1,2)]]], [[[]]], 2, QQ) == [[[QQ(1,2)]]] - assert dmp_sub([[[]]], [[[QQ(1,2)]]], 2, QQ) == [[[QQ(-1,2)]]] - assert dmp_sub([[[QQ(2,7)]]], [[[QQ(1,7)]]], 2, QQ) == [[[QQ(1,7)]]] - assert dmp_sub([[[QQ(1,7)]]], [[[QQ(2,7)]]], 2, QQ) == [[[QQ(-1,7)]]] + assert dmp_sub([[[QQ(1, 2)]]], [[[]]], 2, QQ) == [[[QQ(1, 2)]]] + assert dmp_sub([[[]]], [[[QQ(1, 2)]]], 2, QQ) == [[[QQ(-1, 2)]]] + assert dmp_sub([[[QQ(2, 7)]]], [[[QQ(1, 7)]]], 2, QQ) == [[[QQ(1, 7)]]] + assert dmp_sub([[[QQ(1, 7)]]], [[[QQ(2, 7)]]], 2, QQ) == [[[QQ(-1, 7)]]] + def test_dup_add_mul(): - assert dup_add_mul([ZZ(1),ZZ(2),ZZ(3)], [ZZ(3),ZZ(2),ZZ(1)], - [ZZ(1),ZZ(2)], ZZ) == [ZZ(3), ZZ(9), ZZ(7), ZZ(5)] + assert dup_add_mul([ZZ(1), ZZ(2), ZZ(3)], [ZZ(3), ZZ(2), ZZ(1)], + [ZZ(1), ZZ(2)], ZZ) == [ZZ(3), ZZ(9), ZZ(7), ZZ(5)] + def test_dup_add_mul(): - assert dmp_add_mul([[ZZ(1),ZZ(2)],[ZZ(3)]], [[ZZ(3)],[ZZ(2),ZZ(1)]], - [[ZZ(1)],[ZZ(2)]], 1, ZZ) == [[ZZ(3)], [ZZ(3), ZZ(9)], [ZZ(4), ZZ(5)]] + assert dmp_add_mul([[ZZ(1), ZZ(2)], [ZZ(3)]], [[ZZ(3)], [ZZ(2), ZZ(1)]], + [[ZZ(1)], [ZZ(2)]], 1, ZZ) == [[ZZ(3)], [ZZ(3), ZZ(9)], [ZZ(4), ZZ(5)]] + def test_dup_sub_mul(): - assert dup_sub_mul([ZZ(1),ZZ(2),ZZ(3)], [ZZ(3),ZZ(2),ZZ(1)], - [ZZ(1),ZZ(2)], ZZ) == [ZZ(-3),ZZ(-7),ZZ(-3), ZZ(1)] + assert dup_sub_mul([ZZ(1), ZZ(2), ZZ(3)], [ZZ(3), ZZ(2), ZZ(1)], + [ZZ(1), ZZ(2)], ZZ) == [ZZ(-3), ZZ(-7), ZZ(-3), ZZ(1)] + def test_dup_sub_mul(): - assert dmp_sub_mul([[ZZ(1),ZZ(2)],[ZZ(3)]], [[ZZ(3)],[ZZ(2),ZZ(1)]], - [[ZZ(1)],[ZZ(2)]], 1, ZZ) == [[ZZ(-3)], [ZZ(-1), ZZ(-5)], [ZZ(-4), ZZ(1)]] + assert dmp_sub_mul([[ZZ(1), ZZ(2)], [ZZ(3)]], [[ZZ(3)], [ZZ(2), ZZ(1)]], + [[ZZ(1)], [ZZ(2)]], 1, ZZ) == [[ZZ(-3)], [ZZ(-1), ZZ(-5)], [ZZ(-4), ZZ(1)]] + def test_dup_mul(): assert dup_mul([], [], ZZ) == [] @@ -393,32 +439,33 @@ assert dup_mul([ZZ(5)], [ZZ(7)], ZZ) == [ZZ(35)] assert dup_mul([], [], QQ) == [] - assert dup_mul([], [QQ(1,2)], QQ) == [] - assert dup_mul([QQ(1,2)], [], QQ) == [] - assert dup_mul([QQ(1,2)], [QQ(4,7)], QQ) == [QQ(2,7)] - assert dup_mul([QQ(5,7)], [QQ(3,7)], QQ) == [QQ(15,49)] - - f = dup_normal([3,0,0,6,1,2], ZZ) - g = dup_normal([4,0,1,0], ZZ) - h = dup_normal([12,0,3,24,4,14,1,2,0], ZZ) + assert dup_mul([], [QQ(1, 2)], QQ) == [] + assert dup_mul([QQ(1, 2)], [], QQ) == [] + assert dup_mul([QQ(1, 2)], [QQ(4, 7)], QQ) == [QQ(2, 7)] + assert dup_mul([QQ(5, 7)], [QQ(3, 7)], QQ) == [QQ(15, 49)] + + f = dup_normal([3, 0, 0, 6, 1, 2], ZZ) + g = dup_normal([4, 0, 1, 0], ZZ) + h = dup_normal([12, 0, 3, 24, 4, 14, 1, 2, 0], ZZ) assert dup_mul(f, g, ZZ) == h assert dup_mul(g, f, ZZ) == h - f = dup_normal([2,0,0,1,7], ZZ) - h = dup_normal([4,0,0,4,28,0,1,14,49], ZZ) + f = dup_normal([2, 0, 0, 1, 7], ZZ) + h = dup_normal([4, 0, 0, 4, 28, 0, 1, 14, 49], ZZ) assert dup_mul(f, f, ZZ) == h K = FF(6) - assert dup_mul([K(2),K(1)], [K(3),K(4)], K) == [K(5),K(4)] + assert dup_mul([K(2), K(1)], [K(3), K(4)], K) == [K(5), K(4)] + def test_dmp_mul(): assert dmp_mul([ZZ(5)], [ZZ(7)], 0, ZZ) == \ - dup_mul([ZZ(5)], [ZZ(7)], ZZ) - assert dmp_mul([QQ(5,7)], [QQ(3,7)], 0, QQ) == \ - dup_mul([QQ(5,7)], [QQ(3,7)], QQ) + dup_mul([ZZ(5)], [ZZ(7)], ZZ) + assert dmp_mul([QQ(5, 7)], [QQ(3, 7)], 0, QQ) == \ + dup_mul([QQ(5, 7)], [QQ(3, 7)], QQ) assert dmp_mul([[[]]], [[[]]], 2, ZZ) == [[[]]] assert dmp_mul([[[ZZ(1)]]], [[[]]], 2, ZZ) == [[[]]] @@ -427,45 +474,49 @@ assert dmp_mul([[[ZZ(1)]]], [[[ZZ(2)]]], 2, ZZ) == [[[ZZ(2)]]] assert dmp_mul([[[]]], [[[]]], 2, QQ) == [[[]]] - assert dmp_mul([[[QQ(1,2)]]], [[[]]], 2, QQ) == [[[]]] - assert dmp_mul([[[]]], [[[QQ(1,2)]]], 2, QQ) == [[[]]] - assert dmp_mul([[[QQ(2,7)]]], [[[QQ(1,3)]]], 2, QQ) == [[[QQ(2,21)]]] - assert dmp_mul([[[QQ(1,7)]]], [[[QQ(2,3)]]], 2, QQ) == [[[QQ(2,21)]]] + assert dmp_mul([[[QQ(1, 2)]]], [[[]]], 2, QQ) == [[[]]] + assert dmp_mul([[[]]], [[[QQ(1, 2)]]], 2, QQ) == [[[]]] + assert dmp_mul([[[QQ(2, 7)]]], [[[QQ(1, 3)]]], 2, QQ) == [[[QQ(2, 21)]]] + assert dmp_mul([[[QQ(1, 7)]]], [[[QQ(2, 3)]]], 2, QQ) == [[[QQ(2, 21)]]] K = FF(6) - assert dmp_mul([[K(2)],[K(1)]], [[K(3)],[K(4)]], 1, K) == [[K(5)],[K(4)]] + assert dmp_mul( + [[K(2)], [K(1)]], [[K(3)], [K(4)]], 1, K) == [[K(5)], [K(4)]] + def test_dup_sqr(): assert dup_sqr([], ZZ) == [] assert dup_sqr([ZZ(2)], ZZ) == [ZZ(4)] - assert dup_sqr([ZZ(1),ZZ(2)], ZZ) == [ZZ(1),ZZ(4),ZZ(4)] + assert dup_sqr([ZZ(1), ZZ(2)], ZZ) == [ZZ(1), ZZ(4), ZZ(4)] assert dup_sqr([], QQ) == [] - assert dup_sqr([QQ(2,3)], QQ) == [QQ(4,9)] - assert dup_sqr([QQ(1,3),QQ(2,3)], QQ) == [QQ(1,9),QQ(4,9),QQ(4,9)] + assert dup_sqr([QQ(2, 3)], QQ) == [QQ(4, 9)] + assert dup_sqr([QQ(1, 3), QQ(2, 3)], QQ) == [QQ(1, 9), QQ(4, 9), QQ(4, 9)] - f = dup_normal([2,0,0,1,7], ZZ) + f = dup_normal([2, 0, 0, 1, 7], ZZ) - assert dup_sqr(f, ZZ) == dup_normal([4,0,0,4,28,0,1,14,49], ZZ) + assert dup_sqr(f, ZZ) == dup_normal([4, 0, 0, 4, 28, 0, 1, 14, 49], ZZ) K = FF(9) - assert dup_sqr([K(3),K(4)], K) == [K(6),K(7)] + assert dup_sqr([K(3), K(4)], K) == [K(6), K(7)] + def test_dmp_sqr(): - assert dmp_sqr([ZZ(1),ZZ(2)], 0, ZZ) == \ - dup_sqr([ZZ(1),ZZ(2)], ZZ) + assert dmp_sqr([ZZ(1), ZZ(2)], 0, ZZ) == \ + dup_sqr([ZZ(1), ZZ(2)], ZZ) assert dmp_sqr([[[]]], 2, ZZ) == [[[]]] assert dmp_sqr([[[ZZ(2)]]], 2, ZZ) == [[[ZZ(4)]]] assert dmp_sqr([[[]]], 2, QQ) == [[[]]] - assert dmp_sqr([[[QQ(2,3)]]], 2, QQ) == [[[QQ(4,9)]]] + assert dmp_sqr([[[QQ(2, 3)]]], 2, QQ) == [[[QQ(4, 9)]]] K = FF(9) - assert dmp_sqr([[K(3)],[K(4)]], 1, K) == [[K(6)],[K(7)]] + assert dmp_sqr([[K(3)], [K(4)]], 1, K) == [[K(6)], [K(7)]] + def test_dup_pow(): assert dup_pow([], 0, ZZ) == [ZZ(1)] @@ -482,20 +533,22 @@ assert dup_pow([ZZ(3)], 1, ZZ) == [ZZ(3)] assert dup_pow([ZZ(3)], 7, ZZ) == [ZZ(2187)] - assert dup_pow([QQ(1,1)], 0, QQ) == [QQ(1,1)] - assert dup_pow([QQ(1,1)], 1, QQ) == [QQ(1,1)] - assert dup_pow([QQ(1,1)], 7, QQ) == [QQ(1,1)] - - assert dup_pow([QQ(3,7)], 0, QQ) == [QQ(1,1)] - assert dup_pow([QQ(3,7)], 1, QQ) == [QQ(3,7)] - assert dup_pow([QQ(3,7)], 7, QQ) == [QQ(2187,823543)] + assert dup_pow([QQ(1, 1)], 0, QQ) == [QQ(1, 1)] + assert dup_pow([QQ(1, 1)], 1, QQ) == [QQ(1, 1)] + assert dup_pow([QQ(1, 1)], 7, QQ) == [QQ(1, 1)] + + assert dup_pow([QQ(3, 7)], 0, QQ) == [QQ(1, 1)] + assert dup_pow([QQ(3, 7)], 1, QQ) == [QQ(3, 7)] + assert dup_pow([QQ(3, 7)], 7, QQ) == [QQ(2187, 823543)] - f = dup_normal([2,0,0,1,7], ZZ) + f = dup_normal([2, 0, 0, 1, 7], ZZ) assert dup_pow(f, 0, ZZ) == dup_normal([1], ZZ) - assert dup_pow(f, 1, ZZ) == dup_normal([2,0,0,1,7], ZZ) - assert dup_pow(f, 2, ZZ) == dup_normal([4,0,0,4,28,0,1,14,49], ZZ) - assert dup_pow(f, 3, ZZ) == dup_normal([8,0,0,12,84,0,6,84,294,1,21,147,343], ZZ) + assert dup_pow(f, 1, ZZ) == dup_normal([2, 0, 0, 1, 7], ZZ) + assert dup_pow(f, 2, ZZ) == dup_normal([4, 0, 0, 4, 28, 0, 1, 14, 49], ZZ) + assert dup_pow(f, 3, ZZ) == dup_normal( + [8, 0, 0, 12, 84, 0, 6, 84, 294, 1, 21, 147, 343], ZZ) + def test_dmp_pow(): assert dmp_pow([[]], 0, 1, ZZ) == [[ZZ(1)]] @@ -508,17 +561,18 @@ assert dmp_pow([[ZZ(1)]], 1, 1, ZZ) == [[ZZ(1)]] assert dmp_pow([[ZZ(1)]], 7, 1, ZZ) == [[ZZ(1)]] - assert dmp_pow([[QQ(3,7)]], 0, 1, QQ) == [[QQ(1,1)]] - assert dmp_pow([[QQ(3,7)]], 1, 1, QQ) == [[QQ(3,7)]] - assert dmp_pow([[QQ(3,7)]], 7, 1, QQ) == [[QQ(2187,823543)]] + assert dmp_pow([[QQ(3, 7)]], 0, 1, QQ) == [[QQ(1, 1)]] + assert dmp_pow([[QQ(3, 7)]], 1, 1, QQ) == [[QQ(3, 7)]] + assert dmp_pow([[QQ(3, 7)]], 7, 1, QQ) == [[QQ(2187, 823543)]] - f = dup_normal([2,0,0,1,7], ZZ) + f = dup_normal([2, 0, 0, 1, 7], ZZ) assert dmp_pow(f, 2, 0, ZZ) == dup_pow(f, 2, ZZ) + def test_dup_pdiv(): - f = dup_normal([3,1,1,5], ZZ) - g = dup_normal([5,-3,1], ZZ) + f = dup_normal([3, 1, 1, 5], ZZ) + g = dup_normal([5, -3, 1], ZZ) q = dup_normal([15, 14], ZZ) r = dup_normal([52, 111], ZZ) @@ -529,8 +583,8 @@ raises(ExactQuotientFailed, lambda: dup_pexquo(f, g, ZZ)) - f = dup_normal([3,1,1,5], QQ) - g = dup_normal([5,-3,1], QQ) + f = dup_normal([3, 1, 1, 5], QQ) + g = dup_normal([5, -3, 1], QQ) q = dup_normal([15, 14], QQ) r = dup_normal([52, 111], QQ) @@ -541,9 +595,10 @@ raises(ExactQuotientFailed, lambda: dup_pexquo(f, g, QQ)) + def test_dmp_pdiv(): - f = dmp_normal([[1], [], [1,0,0]], 1, ZZ) - g = dmp_normal([[1], [-1,0]], 1, ZZ) + f = dmp_normal([[1], [], [1, 0, 0]], 1, ZZ) + g = dmp_normal([[1], [-1, 0]], 1, ZZ) q = dmp_normal([[1], [1, 0]], 1, ZZ) r = dmp_normal([[2, 0, 0]], 1, ZZ) @@ -554,8 +609,8 @@ raises(ExactQuotientFailed, lambda: dmp_pexquo(f, g, 1, ZZ)) - f = dmp_normal([[1], [], [1,0,0]], 1, ZZ) - g = dmp_normal([[2], [-2,0]], 1, ZZ) + f = dmp_normal([[1], [], [1, 0, 0]], 1, ZZ) + g = dmp_normal([[2], [-2, 0]], 1, ZZ) q = dmp_normal([[2], [2, 0]], 1, ZZ) r = dmp_normal([[8, 0, 0]], 1, ZZ) @@ -566,82 +621,87 @@ raises(ExactQuotientFailed, lambda: dmp_pexquo(f, g, 1, ZZ)) + def test_dup_rr_div(): - raises(ZeroDivisionError, lambda: dup_rr_div([1,2,3], [], ZZ)) + raises(ZeroDivisionError, lambda: dup_rr_div([1, 2, 3], [], ZZ)) - f = dup_normal([3,1,1,5], ZZ) - g = dup_normal([5,-3,1], ZZ) + f = dup_normal([3, 1, 1, 5], ZZ) + g = dup_normal([5, -3, 1], ZZ) q, r = [], f assert dup_rr_div(f, g, ZZ) == (q, r) + def test_dmp_rr_div(): - raises(ZeroDivisionError, lambda: dmp_rr_div([[1,2],[3]], [[]], 1, ZZ)) + raises(ZeroDivisionError, lambda: dmp_rr_div([[1, 2], [3]], [[]], 1, ZZ)) - f = dmp_normal([[1], [], [1,0,0]], 1, ZZ) - g = dmp_normal([[1], [-1,0]], 1, ZZ) + f = dmp_normal([[1], [], [1, 0, 0]], 1, ZZ) + g = dmp_normal([[1], [-1, 0]], 1, ZZ) q = dmp_normal([[1], [1, 0]], 1, ZZ) r = dmp_normal([[2, 0, 0]], 1, ZZ) assert dmp_rr_div(f, g, 1, ZZ) == (q, r) - f = dmp_normal([[1], [], [1,0,0]], 1, ZZ) - g = dmp_normal([[-1], [1,0]], 1, ZZ) + f = dmp_normal([[1], [], [1, 0, 0]], 1, ZZ) + g = dmp_normal([[-1], [1, 0]], 1, ZZ) q = dmp_normal([[-1], [-1, 0]], 1, ZZ) r = dmp_normal([[2, 0, 0]], 1, ZZ) assert dmp_rr_div(f, g, 1, ZZ) == (q, r) - f = dmp_normal([[1], [], [1,0,0]], 1, ZZ) - g = dmp_normal([[2], [-2,0]], 1, ZZ) + f = dmp_normal([[1], [], [1, 0, 0]], 1, ZZ) + g = dmp_normal([[2], [-2, 0]], 1, ZZ) q, r = [[]], f assert dmp_rr_div(f, g, 1, ZZ) == (q, r) + def test_dup_ff_div(): - raises(ZeroDivisionError, lambda: dup_ff_div([1,2,3], [], QQ)) + raises(ZeroDivisionError, lambda: dup_ff_div([1, 2, 3], [], QQ)) - f = dup_normal([3,1,1,5], QQ) - g = dup_normal([5,-3,1], QQ) + f = dup_normal([3, 1, 1, 5], QQ) + g = dup_normal([5, -3, 1], QQ) - q = [QQ(3,5), QQ(14,25)] - r = [QQ(52,25), QQ(111,25)] + q = [QQ(3, 5), QQ(14, 25)] + r = [QQ(52, 25), QQ(111, 25)] assert dup_ff_div(f, g, QQ) == (q, r) + def test_dmp_ff_div(): - raises(ZeroDivisionError, lambda: dmp_ff_div([[1,2],[3]], [[]], 1, QQ)) + raises(ZeroDivisionError, lambda: dmp_ff_div([[1, 2], [3]], [[]], 1, QQ)) - f = dmp_normal([[1], [], [1,0,0]], 1, QQ) - g = dmp_normal([[1], [-1,0]], 1, QQ) + f = dmp_normal([[1], [], [1, 0, 0]], 1, QQ) + g = dmp_normal([[1], [-1, 0]], 1, QQ) q = [[QQ(1, 1)], [QQ(1, 1), QQ(0, 1)]] r = [[QQ(2, 1), QQ(0, 1), QQ(0, 1)]] assert dmp_ff_div(f, g, 1, QQ) == (q, r) - f = dmp_normal([[1], [], [1,0,0]], 1, QQ) - g = dmp_normal([[-1], [1,0]], 1, QQ) + f = dmp_normal([[1], [], [1, 0, 0]], 1, QQ) + g = dmp_normal([[-1], [1, 0]], 1, QQ) q = [[QQ(-1, 1)], [QQ(-1, 1), QQ(0, 1)]] r = [[QQ(2, 1), QQ(0, 1), QQ(0, 1)]] assert dmp_ff_div(f, g, 1, QQ) == (q, r) - f = dmp_normal([[1], [], [1,0,0]], 1, QQ) - g = dmp_normal([[2], [-2,0]], 1, QQ) + f = dmp_normal([[1], [], [1, 0, 0]], 1, QQ) + g = dmp_normal([[2], [-2, 0]], 1, QQ) q = [[QQ(1, 2)], [QQ(1, 2), QQ(0, 1)]] r = [[QQ(2, 1), QQ(0, 1), QQ(0, 1)]] assert dmp_ff_div(f, g, 1, QQ) == (q, r) + def test_dup_div(): - f, g, q, r = [5,4,3,2,1], [1,2,3], [5,-6,0], [20,1] + f, g, q, r = [5, 4, 3, 2, 1], [1, 2, 3], [5, -6, 0], [20, 1] assert dup_div(f, g, ZZ) == (q, r) assert dup_quo(f, g, ZZ) == q @@ -649,7 +709,7 @@ raises(ExactQuotientFailed, lambda: dup_exquo(f, g, ZZ)) - f, g, q, r = [5,4,3,2,1,0], [1,2,0,0,9], [5,-6], [15,2,-44,54] + f, g, q, r = [5, 4, 3, 2, 1, 0], [1, 2, 0, 0, 9], [5, -6], [15, 2, -44, 54] assert dup_div(f, g, ZZ) == (q, r) assert dup_quo(f, g, ZZ) == q @@ -657,8 +717,9 @@ raises(ExactQuotientFailed, lambda: dup_exquo(f, g, ZZ)) + def test_dmp_div(): - f, g, q, r = [5,4,3,2,1], [1,2,3], [5,-6,0], [20,1] + f, g, q, r = [5, 4, 3, 2, 1], [1, 2, 3], [5, -6, 0], [20, 1] assert dmp_div(f, g, 0, ZZ) == (q, r) assert dmp_quo(f, g, 0, ZZ) == q @@ -666,7 +727,7 @@ raises(ExactQuotientFailed, lambda: dmp_exquo(f, g, 0, ZZ)) - f, g, q, r = [[[1]]], [[[2]],[1]], [[[]]], [[[1]]] + f, g, q, r = [[[1]]], [[[2]], [1]], [[[]]], [[[1]]] assert dmp_div(f, g, 2, ZZ) == (q, r) assert dmp_quo(f, g, 2, ZZ) == q @@ -674,11 +735,13 @@ raises(ExactQuotientFailed, lambda: dmp_exquo(f, g, 2, ZZ)) + def test_dup_max_norm(): assert dup_max_norm([], ZZ) == 0 assert dup_max_norm([1], ZZ) == 1 - assert dup_max_norm([1,4,2,3], ZZ) == 4 + assert dup_max_norm([1, 4, 2, 3], ZZ) == 4 + def test_dmp_max_norm(): assert dmp_max_norm([[[]]], 2, ZZ) == 0 @@ -686,10 +749,12 @@ assert dmp_max_norm(f_0, 2, ZZ) == 6 + def test_dup_l1_norm(): assert dup_l1_norm([], ZZ) == 0 assert dup_l1_norm([1], ZZ) == 1 - assert dup_l1_norm([1,4,2,3], ZZ) == 10 + assert dup_l1_norm([1, 4, 2, 3], ZZ) == 10 + def test_dmp_l1_norm(): assert dmp_l1_norm([[[]]], 2, ZZ) == 0 @@ -697,12 +762,15 @@ assert dmp_l1_norm(f_0, 2, ZZ) == 31 + def test_dup_expand(): assert dup_expand((), ZZ) == [1] - assert dup_expand(([1,2,3], [1,2], [7,5,4,3]), ZZ) == \ - dup_mul([1,2,3], dup_mul([1,2], [7,5,4,3], ZZ), ZZ) + assert dup_expand(([1, 2, 3], [1, 2], [7, 5, 4, 3]), ZZ) == \ + dup_mul([1, 2, 3], dup_mul([1, 2], [7, 5, 4, 3], ZZ), ZZ) + def test_dmp_expand(): assert dmp_expand((), 1, ZZ) == [[1]] - assert dmp_expand(([[1],[2],[3]], [[1],[2]], [[7],[5],[4],[3]]), 1, ZZ) == \ - dmp_mul([[1],[2],[3]], dmp_mul([[1],[2]], [[7],[5],[4],[3]], 1, ZZ), 1, ZZ) + assert dmp_expand(([[1], [2], [3]], [[1], [2]], [[7], [5], [4], [3]]), 1, ZZ) == \ + dmp_mul([[1], [2], [3]], dmp_mul([[1], [2]], [[7], [5], [ + 4], [3]], 1, ZZ), 1, ZZ) diff -Nru python3-sympy-0.7.2/sympy/polys/tests/test_densebasic.py python3-sympy-0.7.3/sympy/polys/tests/test_densebasic.py --- python3-sympy-0.7.2/sympy/polys/tests/test_densebasic.py 2012-10-17 03:02:22.000000000 +0000 +++ python3-sympy-0.7.3/sympy/polys/tests/test_densebasic.py 2013-07-13 17:53:32.000000000 +0000 @@ -36,69 +36,76 @@ dup_random, ) -from sympy.polys.specialpolys import ( - f_0, f_1, f_2, f_3, f_4, f_5, f_6 -) - +from sympy.polys.specialpolys import f_polys from sympy.polys.polyclasses import DMP - from sympy.polys.domains import ZZ, QQ from sympy.core.singleton import S from sympy.utilities.pytest import raises +f_0, f_1, f_2, f_3, f_4, f_5, f_6 = [ f.to_dense() for f in f_polys() ] + def test_dup_LC(): assert dup_LC([], ZZ) == 0 - assert dup_LC([2,3,4,5], ZZ) == 2 + assert dup_LC([2, 3, 4, 5], ZZ) == 2 + def test_dup_TC(): assert dup_TC([], ZZ) == 0 - assert dup_TC([2,3,4,5], ZZ) == 5 + assert dup_TC([2, 3, 4, 5], ZZ) == 5 + def test_dmp_LC(): assert dmp_LC([[]], ZZ) == [] - assert dmp_LC([[2,3,4],[5]], ZZ) == [2,3,4] + assert dmp_LC([[2, 3, 4], [5]], ZZ) == [2, 3, 4] assert dmp_LC([[[]]], ZZ) == [[]] - assert dmp_LC([[[2],[3,4]],[[5]]], ZZ) == [[2],[3,4]] + assert dmp_LC([[[2], [3, 4]], [[5]]], ZZ) == [[2], [3, 4]] + def test_dmp_TC(): assert dmp_TC([[]], ZZ) == [] - assert dmp_TC([[2,3,4],[5]], ZZ) == [5] + assert dmp_TC([[2, 3, 4], [5]], ZZ) == [5] assert dmp_TC([[[]]], ZZ) == [[]] - assert dmp_TC([[[2],[3,4]],[[5]]], ZZ) == [[5]] + assert dmp_TC([[[2], [3, 4]], [[5]]], ZZ) == [[5]] + def test_dmp_ground_LC(): assert dmp_ground_LC([[]], 1, ZZ) == 0 - assert dmp_ground_LC([[2,3,4],[5]], 1, ZZ) == 2 + assert dmp_ground_LC([[2, 3, 4], [5]], 1, ZZ) == 2 assert dmp_ground_LC([[[]]], 2, ZZ) == 0 - assert dmp_ground_LC([[[2],[3,4]],[[5]]], 2, ZZ) == 2 + assert dmp_ground_LC([[[2], [3, 4]], [[5]]], 2, ZZ) == 2 + def test_dmp_ground_TC(): assert dmp_ground_TC([[]], 1, ZZ) == 0 - assert dmp_ground_TC([[2,3,4],[5]], 1, ZZ) == 5 + assert dmp_ground_TC([[2, 3, 4], [5]], 1, ZZ) == 5 assert dmp_ground_TC([[[]]], 2, ZZ) == 0 - assert dmp_ground_TC([[[2],[3,4]],[[5]]], 2, ZZ) == 5 + assert dmp_ground_TC([[[2], [3, 4]], [[5]]], 2, ZZ) == 5 + def test_dmp_true_LT(): assert dmp_true_LT([[]], 1, ZZ) == ((0, 0), 0) assert dmp_true_LT([[7]], 1, ZZ) == ((0, 0), 7) - assert dmp_true_LT([[1,0]], 1, ZZ) == ((0, 1), 1) - assert dmp_true_LT([[1],[]], 1, ZZ) == ((1, 0), 1) - assert dmp_true_LT([[1,0],[]], 1, ZZ) == ((1, 1), 1) + assert dmp_true_LT([[1, 0]], 1, ZZ) == ((0, 1), 1) + assert dmp_true_LT([[1], []], 1, ZZ) == ((1, 0), 1) + assert dmp_true_LT([[1, 0], []], 1, ZZ) == ((1, 1), 1) + def test_dup_degree(): assert dup_degree([]) == -1 assert dup_degree([1]) == 0 - assert dup_degree([1,0]) == 1 - assert dup_degree([1,0,0,0,1]) == 4 + assert dup_degree([1, 0]) == 1 + assert dup_degree([1, 0, 0, 0, 1]) == 4 + def test_dmp_degree(): assert dmp_degree([[]], 1) == -1 assert dmp_degree([[[]]], 2) == -1 assert dmp_degree([[1]], 1) == 0 - assert dmp_degree([[2],[1]], 1) == 1 + assert dmp_degree([[2], [1]], 1) == 1 + def test_dmp_degree_in(): assert dmp_degree_in([[[]]], 0, 2) == -1 @@ -120,8 +127,9 @@ raises(IndexError, lambda: dmp_degree_in([[1]], -5, 1)) + def test_dmp_degree_list(): - assert dmp_degree_list([[[[ ]]]], 3) == (-1,-1,-1,-1) + assert dmp_degree_list([[[[ ]]]], 3) == (-1, -1, -1, -1) assert dmp_degree_list([[[[1]]]], 3) == ( 0, 0, 0, 0) assert dmp_degree_list(f_0, 2) == (2, 2, 2) @@ -132,21 +140,23 @@ assert dmp_degree_list(f_5, 2) == (3, 3, 3) assert dmp_degree_list(f_6, 3) == (4, 4, 6, 3) + def test_dup_strip(): assert dup_strip([]) == [] assert dup_strip([0]) == [] - assert dup_strip([0,0,0]) == [] + assert dup_strip([0, 0, 0]) == [] assert dup_strip([1]) == [1] - assert dup_strip([0,1]) == [1] - assert dup_strip([0,0,0,1]) == [1] + assert dup_strip([0, 1]) == [1] + assert dup_strip([0, 0, 0, 1]) == [1] + + assert dup_strip([1, 2, 0]) == [1, 2, 0] + assert dup_strip([0, 1, 2, 0]) == [1, 2, 0] + assert dup_strip([0, 0, 0, 1, 2, 0]) == [1, 2, 0] - assert dup_strip([1,2,0]) == [1,2,0] - assert dup_strip([0,1,2,0]) == [1,2,0] - assert dup_strip([0,0,0,1,2,0]) == [1,2,0] def test_dmp_strip(): - assert dmp_strip([0,1,0], 0) == [1,0] + assert dmp_strip([0, 1, 0], 0) == [1, 0] assert dmp_strip([[]], 1) == [[]] assert dmp_strip([[], []], 1) == [[]] @@ -160,58 +170,67 @@ assert dmp_strip([[[]], [[1]]], 2) == [[[1]]] assert dmp_strip([[[]], [[1]], [[]]], 2) == [[[1]], [[]]] + def test_dmp_validate(): assert dmp_validate([]) == ([], 0) - assert dmp_validate([0,0,0,1,0]) == ([1,0], 0) + assert dmp_validate([0, 0, 0, 1, 0]) == ([1, 0], 0) assert dmp_validate([[[]]]) == ([[[]]], 2) - assert dmp_validate([[0],[],[0],[1],[0]]) == ([[1],[]], 1) + assert dmp_validate([[0], [], [0], [1], [0]]) == ([[1], []], 1) + + raises(ValueError, lambda: dmp_validate([[0], 0, [0], [1], [0]])) - raises(ValueError, lambda: dmp_validate([[0],0,[0],[1],[0]])) def test_dup_reverse(): - assert dup_reverse([1,2,0,3]) == [3,0,2,1] - assert dup_reverse([1,2,3,0]) == [3,2,1] + assert dup_reverse([1, 2, 0, 3]) == [3, 0, 2, 1] + assert dup_reverse([1, 2, 3, 0]) == [3, 2, 1] + def test_dup_copy(): - f = [ZZ(1),ZZ(0),ZZ(2)] + f = [ZZ(1), ZZ(0), ZZ(2)] g = dup_copy(f) g[0], g[2] = ZZ(7), ZZ(0) assert f != g + def test_dmp_copy(): - f = [[ZZ(1)],[ZZ(2),ZZ(0)]] + f = [[ZZ(1)], [ZZ(2), ZZ(0)]] g = dmp_copy(f, 1) g[0][0], g[1][1] = ZZ(7), ZZ(1) assert f != g + def test_dup_normal(): - assert dup_normal([0,0,2,1,0,11,0], ZZ) == \ - [ZZ(2),ZZ(1),ZZ(0),ZZ(11),ZZ(0)] + assert dup_normal([0, 0, 2, 1, 0, 11, 0], ZZ) == \ + [ZZ(2), ZZ(1), ZZ(0), ZZ(11), ZZ(0)] + def test_dmp_normal(): - assert dmp_normal([[0],[],[0,2,1],[0],[11],[]], 1, ZZ) == \ - [[ZZ(2),ZZ(1)],[],[ZZ(11)],[]] + assert dmp_normal([[0], [], [0, 2, 1], [0], [11], []], 1, ZZ) == \ + [[ZZ(2), ZZ(1)], [], [ZZ(11)], []] + def test_dup_convert(): K0, K1 = ZZ['x'], ZZ - f = [DMP([1], ZZ),DMP([2], ZZ),DMP([], ZZ),DMP([3], ZZ)] + f = [DMP([1], ZZ), DMP([2], ZZ), DMP([], ZZ), DMP([3], ZZ)] assert dup_convert(f, K0, K1) == \ - [ZZ(1),ZZ(2),ZZ(0),ZZ(3)] + [ZZ(1), ZZ(2), ZZ(0), ZZ(3)] + def test_dmp_convert(): K0, K1 = ZZ['x'], ZZ - f = [[DMP([1], ZZ)],[DMP([2], ZZ)],[],[DMP([3], ZZ)]] + f = [[DMP([1], ZZ)], [DMP([2], ZZ)], [], [DMP([3], ZZ)]] assert dmp_convert(f, 1, K0, K1) == \ - [[ZZ(1)],[ZZ(2)],[],[ZZ(3)]] + [[ZZ(1)], [ZZ(2)], [], [ZZ(3)]] + def test_dup_from_sympy(): assert dup_from_sympy([S(1), S(2)], ZZ) == \ @@ -219,87 +238,98 @@ assert dup_from_sympy([S(1)/2, S(3)], QQ) == \ [QQ(1, 2), QQ(3, 1)] + def test_dmp_from_sympy(): assert dmp_from_sympy([[S(1), S(2)], [S(0)]], 1, ZZ) == \ [[ZZ(1), ZZ(2)], []] assert dmp_from_sympy([[S(1)/2, S(2)]], 1, QQ) == \ [[QQ(1, 2), QQ(2, 1)]] + def test_dup_nth(): - assert dup_nth([1,2,3], 0, ZZ) == 3 - assert dup_nth([1,2,3], 1, ZZ) == 2 - assert dup_nth([1,2,3], 2, ZZ) == 1 + assert dup_nth([1, 2, 3], 0, ZZ) == 3 + assert dup_nth([1, 2, 3], 1, ZZ) == 2 + assert dup_nth([1, 2, 3], 2, ZZ) == 1 + + assert dup_nth([1, 2, 3], 9, ZZ) == 0 - assert dup_nth([1,2,3], 9, ZZ) == 0 + raises(IndexError, lambda: dup_nth([3, 4, 5], -1, ZZ)) - raises(IndexError, lambda: dup_nth([3,4,5], -1, ZZ)) def test_dmp_nth(): - assert dmp_nth([[1],[2],[3]], 0, 1, ZZ) == [3] - assert dmp_nth([[1],[2],[3]], 1, 1, ZZ) == [2] - assert dmp_nth([[1],[2],[3]], 2, 1, ZZ) == [1] + assert dmp_nth([[1], [2], [3]], 0, 1, ZZ) == [3] + assert dmp_nth([[1], [2], [3]], 1, 1, ZZ) == [2] + assert dmp_nth([[1], [2], [3]], 2, 1, ZZ) == [1] - assert dmp_nth([[1],[2],[3]], 9, 1, ZZ) == [] + assert dmp_nth([[1], [2], [3]], 9, 1, ZZ) == [] + + raises(IndexError, lambda: dmp_nth([[3], [4], [5]], -1, 1, ZZ)) - raises(IndexError, lambda: dmp_nth([[3],[4],[5]], -1, 1, ZZ)) def test_dmp_ground_nth(): - assert dmp_ground_nth([[1],[2],[3]], (0,0), 1, ZZ) == 3 - assert dmp_ground_nth([[1],[2],[3]], (1,0), 1, ZZ) == 2 - assert dmp_ground_nth([[1],[2],[3]], (2,0), 1, ZZ) == 1 + assert dmp_ground_nth([[1], [2], [3]], (0, 0), 1, ZZ) == 3 + assert dmp_ground_nth([[1], [2], [3]], (1, 0), 1, ZZ) == 2 + assert dmp_ground_nth([[1], [2], [3]], (2, 0), 1, ZZ) == 1 + + assert dmp_ground_nth([[1], [2], [3]], (2, 1), 1, ZZ) == 0 + assert dmp_ground_nth([[1], [2], [3]], (3, 0), 1, ZZ) == 0 - assert dmp_ground_nth([[1],[2],[3]], (2,1), 1, ZZ) == 0 - assert dmp_ground_nth([[1],[2],[3]], (3,0), 1, ZZ) == 0 + raises(IndexError, lambda: dmp_ground_nth([[3], [4], [5]], (2, -1), 1, ZZ)) - raises(IndexError, lambda: dmp_ground_nth([[3],[4],[5]], (2,-1), 1, ZZ)) def test_dmp_zero_p(): - assert dmp_zero_p([], 0) == True - assert dmp_zero_p([[]], 1) == True + assert dmp_zero_p([], 0) is True + assert dmp_zero_p([[]], 1) is True + + assert dmp_zero_p([[[]]], 2) is True + assert dmp_zero_p([[[1]]], 2) is False - assert dmp_zero_p([[[]]], 2) == True - assert dmp_zero_p([[[1]]], 2) == False def test_dmp_zero(): assert dmp_zero(0) == [] assert dmp_zero(2) == [[[]]] + def test_dmp_one_p(): - assert dmp_one_p([1], 0, ZZ) == True - assert dmp_one_p([[1]], 1, ZZ) == True - assert dmp_one_p([[[1]]], 2, ZZ) == True - assert dmp_one_p([[[12]]], 2, ZZ) == False + assert dmp_one_p([1], 0, ZZ) is True + assert dmp_one_p([[1]], 1, ZZ) is True + assert dmp_one_p([[[1]]], 2, ZZ) is True + assert dmp_one_p([[[12]]], 2, ZZ) is False + def test_dmp_one(): assert dmp_one(0, ZZ) == [ZZ(1)] assert dmp_one(2, ZZ) == [[[ZZ(1)]]] + def test_dmp_ground_p(): - assert dmp_ground_p([], 0, 0) == True - assert dmp_ground_p([[]], 0, 1) == True - assert dmp_ground_p([[]], 1, 1) == False + assert dmp_ground_p([], 0, 0) is True + assert dmp_ground_p([[]], 0, 1) is True + assert dmp_ground_p([[]], 1, 1) is False + + assert dmp_ground_p([[ZZ(1)]], 1, 1) is True + assert dmp_ground_p([[[ZZ(2)]]], 2, 2) is True - assert dmp_ground_p([[ZZ(1)]], 1, 1) == True - assert dmp_ground_p([[[ZZ(2)]]], 2, 2) == True + assert dmp_ground_p([[[ZZ(2)]]], 3, 2) is False + assert dmp_ground_p([[[ZZ(3)], []]], 3, 2) is False - assert dmp_ground_p([[[ZZ(2)]]], 3, 2) == False - assert dmp_ground_p([[[ZZ(3)], []]], 3, 2) == False + assert dmp_ground_p([], None, 0) is True + assert dmp_ground_p([[]], None, 1) is True - assert dmp_ground_p([], None, 0) == True - assert dmp_ground_p([[]], None, 1) == True + assert dmp_ground_p([ZZ(1)], None, 0) is True + assert dmp_ground_p([[[ZZ(1)]]], None, 2) is True - assert dmp_ground_p([ZZ(1)], None, 0) == True - assert dmp_ground_p([[[ZZ(1)]]], None, 2) == True + assert dmp_ground_p([[[ZZ(3)], []]], None, 2) is False - assert dmp_ground_p([[[ZZ(3)], []]], None, 2) == False def test_dmp_ground(): assert dmp_ground(ZZ(0), 2) == [[[]]] - assert dmp_ground(ZZ(7),-1) == ZZ(7) + assert dmp_ground(ZZ(7), -1) == ZZ(7) assert dmp_ground(ZZ(7), 0) == [ZZ(7)] assert dmp_ground(ZZ(7), 2) == [[[ZZ(7)]]] + def test_dmp_zeros(): assert dmp_zeros(4, 0, ZZ) == [[], [], [], []] @@ -310,6 +340,7 @@ assert dmp_zeros(3, -1, ZZ) == [0, 0, 0] + def test_dmp_grounds(): assert dmp_grounds(ZZ(7), 0, 2) == [] @@ -319,15 +350,18 @@ assert dmp_grounds(ZZ(7), 3, -1) == [7, 7, 7] + def test_dmp_negative_p(): - assert dmp_negative_p([[[]]], 2, ZZ) == False - assert dmp_negative_p([[[1], [2]]], 2, ZZ) == False - assert dmp_negative_p([[[-1], [2]]], 2, ZZ) == True + assert dmp_negative_p([[[]]], 2, ZZ) is False + assert dmp_negative_p([[[1], [2]]], 2, ZZ) is False + assert dmp_negative_p([[[-1], [2]]], 2, ZZ) is True + def test_dmp_positive_p(): - assert dmp_positive_p([[[]]], 2, ZZ) == False - assert dmp_positive_p([[[1], [2]]], 2, ZZ) == True - assert dmp_positive_p([[[-1], [2]]], 2, ZZ) == False + assert dmp_positive_p([[[]]], 2, ZZ) is False + assert dmp_positive_p([[[1], [2]]], 2, ZZ) is True + assert dmp_positive_p([[[-1], [2]]], 2, ZZ) is False + def test_dup_from_to_dict(): assert dup_from_raw_dict({}, ZZ) == [] @@ -339,7 +373,7 @@ assert dup_to_raw_dict([], ZZ, zero=True) == {0: ZZ(0)} assert dup_to_dict([], ZZ, zero=True) == {(0,): ZZ(0)} - f = [3,0,0,2,0,0,0,0,8] + f = [3, 0, 0, 2, 0, 0, 0, 0, 8] g = {8: 3, 5: 2, 0: 8} h = {(8,): 3, (5,): 2, (0,): 8} @@ -349,9 +383,9 @@ assert dup_to_raw_dict(f) == g assert dup_to_dict(f) == h - K = ZZ['x','y'] + K = ZZ['x', 'y'] - f = [K([[3]]),K([[]]),K([[2]]),K([[]]),K([[]]),K([[8]])] + f = [K([[3]]), K([[]]), K([[2]]), K([[]]), K([[]]), K([[8]])] g = {5: K([[3]]), 3: K([[2]]), 0: K([[8]])} h = {(5,): K([[3]]), (3,): K([[2]]), (0,): K([[8]])} @@ -361,22 +395,24 @@ assert dup_to_raw_dict(f) == g assert dup_to_dict(f) == h + def test_dmp_from_to_dict(): assert dmp_from_dict({}, 1, ZZ) == [[]] assert dmp_to_dict([[]], 1) == {} assert dmp_to_dict([], 0, ZZ, zero=True) == {(0,): ZZ(0)} - assert dmp_to_dict([[]], 1, ZZ, zero=True) == {(0,0): ZZ(0)} + assert dmp_to_dict([[]], 1, ZZ, zero=True) == {(0, 0): ZZ(0)} - f = [[3],[],[],[2],[],[],[],[],[8]] - g = {(8,0): 3, (5,0): 2, (0,0): 8} + f = [[3], [], [], [2], [], [], [], [], [8]] + g = {(8, 0): 3, (5, 0): 2, (0, 0): 8} assert dmp_from_dict(g, 1, ZZ) == f assert dmp_to_dict(f, 1) == g + def test_dmp_swap(): - f = dmp_normal([[1,0,0],[],[1,0],[],[1]], 1, ZZ) - g = dmp_normal([[1,0,0,0,0],[1,0,0],[1]], 1, ZZ) + f = dmp_normal([[1, 0, 0], [], [1, 0], [], [1]], 1, ZZ) + g = dmp_normal([[1, 0, 0, 0, 0], [1, 0, 0], [1]], 1, ZZ) assert dmp_swap(f, 1, 1, 1, ZZ) == f @@ -385,9 +421,10 @@ raises(IndexError, lambda: dmp_swap(f, -1, -7, 1, ZZ)) + def test_dmp_permute(): - f = dmp_normal([[1,0,0],[],[1,0],[],[1]], 1, ZZ) - g = dmp_normal([[1,0,0,0,0],[1,0,0],[1]], 1, ZZ) + f = dmp_normal([[1, 0, 0], [], [1, 0], [], [1]], 1, ZZ) + g = dmp_normal([[1, 0, 0, 0, 0], [1, 0, 0], [1]], 1, ZZ) assert dmp_permute(f, [0, 1], 1, ZZ) == f assert dmp_permute(g, [0, 1], 1, ZZ) == g @@ -395,6 +432,7 @@ assert dmp_permute(f, [1, 0], 1, ZZ) == g assert dmp_permute(g, [1, 0], 1, ZZ) == f + def test_dmp_nest(): assert dmp_nest(ZZ(1), 2, ZZ) == [[[1]]] @@ -402,38 +440,41 @@ assert dmp_nest([[1]], 1, ZZ) == [[[1]]] assert dmp_nest([[1]], 2, ZZ) == [[[[1]]]] + def test_dmp_raise(): assert dmp_raise([], 2, 0, ZZ) == [[[]]] assert dmp_raise([[1]], 0, 1, ZZ) == [[1]] - assert dmp_raise([[1,2,3], [], [2,3]], 2, 1, ZZ) == \ - [[[[1]],[[2]],[[3]]], [[[]]], [[[2]],[[3]]]] + assert dmp_raise([[1, 2, 3], [], [2, 3]], 2, 1, ZZ) == \ + [[[[1]], [[2]], [[3]]], [[[]]], [[[2]], [[3]]]] + def test_dup_deflate(): assert dup_deflate([], ZZ) == (1, []) assert dup_deflate([2], ZZ) == (1, [2]) - assert dup_deflate([1,2,3], ZZ) == (1, [1,2,3]) - assert dup_deflate([1,0,2,0,3], ZZ) == (2, [1,2,3]) + assert dup_deflate([1, 2, 3], ZZ) == (1, [1, 2, 3]) + assert dup_deflate([1, 0, 2, 0, 3], ZZ) == (2, [1, 2, 3]) - assert dup_deflate(dup_from_raw_dict({7:1,1:1}, ZZ), ZZ) == \ + assert dup_deflate(dup_from_raw_dict({7: 1, 1: 1}, ZZ), ZZ) == \ (1, [1, 0, 0, 0, 0, 0, 1, 0]) - assert dup_deflate(dup_from_raw_dict({7:1,0:1}, ZZ), ZZ) == \ + assert dup_deflate(dup_from_raw_dict({7: 1, 0: 1}, ZZ), ZZ) == \ (7, [1, 1]) - assert dup_deflate(dup_from_raw_dict({7:1,3:1}, ZZ), ZZ) == \ + assert dup_deflate(dup_from_raw_dict({7: 1, 3: 1}, ZZ), ZZ) == \ (1, [1, 0, 0, 0, 1, 0, 0, 0]) - assert dup_deflate(dup_from_raw_dict({7:1,4:1}, ZZ), ZZ) == \ + assert dup_deflate(dup_from_raw_dict({7: 1, 4: 1}, ZZ), ZZ) == \ (1, [1, 0, 0, 1, 0, 0, 0, 0]) - assert dup_deflate(dup_from_raw_dict({8:1,4:1}, ZZ), ZZ) == \ + assert dup_deflate(dup_from_raw_dict({8: 1, 4: 1}, ZZ), ZZ) == \ (4, [1, 1, 0]) - assert dup_deflate(dup_from_raw_dict({8:1}, ZZ), ZZ) == \ + assert dup_deflate(dup_from_raw_dict({8: 1}, ZZ), ZZ) == \ (8, [1, 0]) - assert dup_deflate(dup_from_raw_dict({7:1}, ZZ), ZZ) == \ + assert dup_deflate(dup_from_raw_dict({7: 1}, ZZ), ZZ) == \ (7, [1, 0]) - assert dup_deflate(dup_from_raw_dict({1:1}, ZZ), ZZ) == \ + assert dup_deflate(dup_from_raw_dict({1: 1}, ZZ), ZZ) == \ (1, [1, 0]) + def test_dmp_deflate(): assert dmp_deflate([[]], 1, ZZ) == ((1, 1), [[]]) assert dmp_deflate([[2]], 1, ZZ) == ((1, 1), [[2]]) @@ -442,17 +483,19 @@ assert dmp_deflate(f, 1, ZZ) == ((2, 1), [[1, 0, 0], [1, 0], [1]]) + def test_dup_multi_deflate(): assert dup_multi_deflate(([2],), ZZ) == (1, ([2],)) assert dup_multi_deflate(([], []), ZZ) == (1, ([], [])) - assert dup_multi_deflate(([1,2,3],), ZZ) == (1, ([1,2,3],)) - assert dup_multi_deflate(([1,0,2,0,3],), ZZ) == (2, ([1,2,3],)) + assert dup_multi_deflate(([1, 2, 3],), ZZ) == (1, ([1, 2, 3],)) + assert dup_multi_deflate(([1, 0, 2, 0, 3],), ZZ) == (2, ([1, 2, 3],)) + + assert dup_multi_deflate(([1, 0, 2, 0, 3], [2, 0, 0]), ZZ) == \ + (2, ([1, 2, 3], [2, 0])) + assert dup_multi_deflate(([1, 0, 2, 0, 3], [2, 1, 0]), ZZ) == \ + (1, ([1, 0, 2, 0, 3], [2, 1, 0])) - assert dup_multi_deflate(([1,0,2,0,3], [2,0,0]), ZZ) == \ - (2, ([1,2,3], [2,0])) - assert dup_multi_deflate(([1,0,2,0,3], [2,1,0]), ZZ) == \ - (1, ([1,0,2,0,3], [2,1,0])) def test_dmp_multi_deflate(): assert dmp_multi_deflate(([[]],), 1, ZZ) == \ @@ -464,16 +507,18 @@ ((1, 1), ([[1]], [[]])) assert dmp_multi_deflate(([[1]], [[2]]), 1, ZZ) == \ ((1, 1), ([[1]], [[2]])) - assert dmp_multi_deflate(([[1]], [[2,0]]), 1, ZZ) == \ + assert dmp_multi_deflate(([[1]], [[2, 0]]), 1, ZZ) == \ ((1, 1), ([[1]], [[2, 0]])) - assert dmp_multi_deflate(([[2,0]], [[2,0]]), 1, ZZ) == \ + assert dmp_multi_deflate(([[2, 0]], [[2, 0]]), 1, ZZ) == \ ((1, 1), ([[2, 0]], [[2, 0]])) - assert dmp_multi_deflate(([[2]], [[2,0,0]]), 1, ZZ) == ((1, 2), ([[2]], [[2, 0]])) - assert dmp_multi_deflate(([[2,0,0]], [[2,0,0]]), 1, ZZ) == ((1, 2), ([[2, 0]], [[2, 0]])) + assert dmp_multi_deflate( + ([[2]], [[2, 0, 0]]), 1, ZZ) == ((1, 2), ([[2]], [[2, 0]])) + assert dmp_multi_deflate( + ([[2, 0, 0]], [[2, 0, 0]]), 1, ZZ) == ((1, 2), ([[2, 0]], [[2, 0]])) - assert dmp_multi_deflate(([2,0,0], [1,0,4,0,1]), 0, ZZ) == \ + assert dmp_multi_deflate(([2, 0, 0], [1, 0, 4, 0, 1]), 0, ZZ) == \ ((2,), ([2, 0], [1, 4, 1])) f = [[1, 0, 0], [], [1, 0], [], [1]] @@ -486,15 +531,17 @@ ((2, 1), ([[1, 0, 0], [1, 0], [1]], [[1, 0, 1, 0], [1]])) + def test_dup_inflate(): assert dup_inflate([], 17, ZZ) == [] - assert dup_inflate([1,2,3], 1, ZZ) == [1,2,3] - assert dup_inflate([1,2,3], 2, ZZ) == [1,0,2,0,3] - assert dup_inflate([1,2,3], 3, ZZ) == [1,0,0,2,0,0,3] - assert dup_inflate([1,2,3], 4, ZZ) == [1,0,0,0,2,0,0,0,3] + assert dup_inflate([1, 2, 3], 1, ZZ) == [1, 2, 3] + assert dup_inflate([1, 2, 3], 2, ZZ) == [1, 0, 2, 0, 3] + assert dup_inflate([1, 2, 3], 3, ZZ) == [1, 0, 0, 2, 0, 0, 3] + assert dup_inflate([1, 2, 3], 4, ZZ) == [1, 0, 0, 0, 2, 0, 0, 0, 3] + + raises(IndexError, lambda: dup_inflate([1, 2, 3], 0, ZZ)) - raises(IndexError, lambda: dup_inflate([1,2,3], 0, ZZ)) def test_dmp_inflate(): assert dmp_inflate([1], (3,), 0, ZZ) == [1] @@ -502,39 +549,42 @@ assert dmp_inflate([[]], (3, 7), 1, ZZ) == [[]] assert dmp_inflate([[2]], (1, 2), 1, ZZ) == [[2]] - assert dmp_inflate([[2,0]], (1, 1), 1, ZZ) == [[2,0]] - assert dmp_inflate([[2,0]], (1, 2), 1, ZZ) == [[2,0,0]] - assert dmp_inflate([[2,0]], (1, 3), 1, ZZ) == [[2,0,0,0]] + assert dmp_inflate([[2, 0]], (1, 1), 1, ZZ) == [[2, 0]] + assert dmp_inflate([[2, 0]], (1, 2), 1, ZZ) == [[2, 0, 0]] + assert dmp_inflate([[2, 0]], (1, 3), 1, ZZ) == [[2, 0, 0, 0]] assert dmp_inflate([[1, 0, 0], [1], [1, 0]], (2, 1), 1, ZZ) == \ [[1, 0, 0], [], [1], [], [1, 0]] raises(IndexError, lambda: dmp_inflate([[]], (-3, 7), 1, ZZ)) + def test_dmp_exclude(): assert dmp_exclude([[[]]], 2, ZZ) == ([], [[[]]], 2) assert dmp_exclude([[[7]]], 2, ZZ) == ([], [[[7]]], 2) - assert dmp_exclude([1,2,3], 0, ZZ) == ([], [1,2,3], 0) - assert dmp_exclude([[1],[2,3]], 1, ZZ) == ([], [[1],[2,3]], 1) + assert dmp_exclude([1, 2, 3], 0, ZZ) == ([], [1, 2, 3], 0) + assert dmp_exclude([[1], [2, 3]], 1, ZZ) == ([], [[1], [2, 3]], 1) + + assert dmp_exclude([[1, 2, 3]], 1, ZZ) == ([0], [1, 2, 3], 0) + assert dmp_exclude([[1], [2], [3]], 1, ZZ) == ([1], [1, 2, 3], 0) - assert dmp_exclude([[1,2,3]], 1, ZZ) == ([0], [1,2,3], 0) - assert dmp_exclude([[1],[2],[3]], 1, ZZ) == ([1], [1,2,3], 0) + assert dmp_exclude([[[1, 2, 3]]], 2, ZZ) == ([0, 1], [1, 2, 3], 0) + assert dmp_exclude([[[1]], [[2]], [[3]]], 2, ZZ) == ([1, 2], [1, 2, 3], 0) - assert dmp_exclude([[[1,2,3]]], 2, ZZ) == ([0,1], [1,2,3], 0) - assert dmp_exclude([[[1]],[[2]],[[3]]], 2, ZZ) == ([1,2], [1,2,3], 0) def test_dmp_include(): - assert dmp_include([1,2,3], [], 0, ZZ) == [1,2,3] + assert dmp_include([1, 2, 3], [], 0, ZZ) == [1, 2, 3] - assert dmp_include([1,2,3], [0], 0, ZZ) == [[1,2,3]] - assert dmp_include([1,2,3], [1], 0, ZZ) == [[1],[2],[3]] + assert dmp_include([1, 2, 3], [0], 0, ZZ) == [[1, 2, 3]] + assert dmp_include([1, 2, 3], [1], 0, ZZ) == [[1], [2], [3]] + + assert dmp_include([1, 2, 3], [0, 1], 0, ZZ) == [[[1, 2, 3]]] + assert dmp_include([1, 2, 3], [1, 2], 0, ZZ) == [[[1]], [[2]], [[3]]] - assert dmp_include([1,2,3], [0,1], 0, ZZ) == [[[1,2,3]]] - assert dmp_include([1,2,3], [1,2], 0, ZZ) == [[[1]],[[2]],[[3]]] def test_dmp_inject(): - K = ZZ['x','y'] + K = ZZ['x', 'y'] assert dmp_inject([], 0, K) == ([[[]]], 2) assert dmp_inject([[]], 1, K) == ([[[[]]]], 3) @@ -542,15 +592,18 @@ assert dmp_inject([K([[1]])], 0, K) == ([[[1]]], 2) assert dmp_inject([[K([[1]])]], 1, K) == ([[[[1]]]], 3) - assert dmp_inject([K([[1]]),K([[2],[3,4]])], 0, K) == ([[[1]],[[2],[3,4]]], 2) + assert dmp_inject( + [K([[1]]), K([[2], [3, 4]])], 0, K) == ([[[1]], [[2], [3, 4]]], 2) - f = [K([[3],[7,0],[5,0,0]]),K([[2],[]]),K([[]]),K([[1,0,0],[11]])] - g = [[[3],[7,0],[5,0,0]],[[2],[]],[[]],[[1,0,0],[11]]] + f = [K([[3], [7, 0], [5, 0, 0]]), K([[2], []]), K([[]]), K([[1, 0, + 0], [11]])] + g = [[[3], [7, 0], [5, 0, 0]], [[2], []], [[]], [[1, 0, 0], [11]]] assert dmp_inject(f, 0, K) == (g, 2) + def test_dmp_eject(): - K = ZZ['x','y'] + K = ZZ['x', 'y'] assert dmp_eject([[[]]], 2, K) == [] assert dmp_eject([[[[]]]], 3, K) == [[]] @@ -558,77 +611,94 @@ assert dmp_eject([[[1]]], 2, K) == [K([[1]])] assert dmp_eject([[[[1]]]], 3, K) == [[K([[1]])]] - assert dmp_eject([[[1]],[[2],[3,4]]], 2, K) == [K([[1]]),K([[2],[3,4]])] + assert dmp_eject( + [[[1]], [[2], [3, 4]]], 2, K) == [K([[1]]), K([[2], [3, 4]])] - f = [K([[3],[7,0],[5,0,0]]),K([[2],[]]),K([[]]),K([[1,0,0],[11]])] - g = [[[3],[7,0],[5,0,0]],[[2],[]],[[]],[[1,0,0],[11]]] + f = [K([[3], [7, 0], [5, 0, 0]]), K([[2], []]), K([[]]), K([[1, 0, + 0], [11]])] + g = [[[3], [7, 0], [5, 0, 0]], [[2], []], [[]], [[1, 0, 0], [11]]] assert dmp_eject(g, 2, K) == f + def test_dup_terms_gcd(): assert dup_terms_gcd([], ZZ) == (0, []) - assert dup_terms_gcd([1,0,1], ZZ) == (0, [1,0,1]) - assert dup_terms_gcd([1,0,1,0], ZZ) == (1, [1,0,1]) + assert dup_terms_gcd([1, 0, 1], ZZ) == (0, [1, 0, 1]) + assert dup_terms_gcd([1, 0, 1, 0], ZZ) == (1, [1, 0, 1]) + def test_dmp_terms_gcd(): - assert dmp_terms_gcd([[]], 1, ZZ) == ((0,0), [[]]) + assert dmp_terms_gcd([[]], 1, ZZ) == ((0, 0), [[]]) - assert dmp_terms_gcd([1,0,1,0], 0, ZZ) == ((1,), [1,0,1]) - assert dmp_terms_gcd([[1],[],[1],[]], 1, ZZ) == ((1,0), [[1],[],[1]]) + assert dmp_terms_gcd([1, 0, 1, 0], 0, ZZ) == ((1,), [1, 0, 1]) + assert dmp_terms_gcd([[1], [], [1], []], 1, ZZ) == ((1, 0), [[1], [], [1]]) + + assert dmp_terms_gcd( + [[1, 0], [], [1]], 1, ZZ) == ((0, 0), [[1, 0], [], [1]]) + assert dmp_terms_gcd( + [[1, 0], [1, 0, 0], [], []], 1, ZZ) == ((2, 1), [[1], [1, 0]]) - assert dmp_terms_gcd([[1,0],[],[1]], 1, ZZ) == ((0,0), [[1,0],[],[1]]) - assert dmp_terms_gcd([[1,0],[1,0,0],[],[]], 1, ZZ) == ((2,1), [[1],[1,0]]) def test_dmp_list_terms(): - assert dmp_list_terms([[[]]], 2, ZZ) == [((0,0,0), 0)] - assert dmp_list_terms([[[1]]], 2, ZZ) == [((0,0,0), 1)] + assert dmp_list_terms([[[]]], 2, ZZ) == [((0, 0, 0), 0)] + assert dmp_list_terms([[[1]]], 2, ZZ) == [((0, 0, 0), 1)] - assert dmp_list_terms([1,2,4,3,5], 0, ZZ) == \ + assert dmp_list_terms([1, 2, 4, 3, 5], 0, ZZ) == \ [((4,), 1), ((3,), 2), ((2,), 4), ((1,), 3), ((0,), 5)] - assert dmp_list_terms([[1],[2,4],[3,5,0]], 1, ZZ) == \ + assert dmp_list_terms([[1], [2, 4], [3, 5, 0]], 1, ZZ) == \ [((2, 0), 1), ((1, 1), 2), ((1, 0), 4), ((0, 2), 3), ((0, 1), 5)] f = [[2, 0, 0, 0], [1, 0, 0], []] assert dmp_list_terms(f, 1, ZZ, order='lex') == [((2, 3), 2), ((1, 2), 1)] - assert dmp_list_terms(f, 1, ZZ, order='grlex') == [((2, 3), 2), ((1, 2), 1)] + assert dmp_list_terms( + f, 1, ZZ, order='grlex') == [((2, 3), 2), ((1, 2), 1)] f = [[2, 0, 0, 0], [1, 0, 0, 0, 0, 0], []] assert dmp_list_terms(f, 1, ZZ, order='lex') == [((2, 3), 2), ((1, 5), 1)] - assert dmp_list_terms(f, 1, ZZ, order='grlex') == [((1, 5), 1), ((2, 3), 2)] + assert dmp_list_terms( + f, 1, ZZ, order='grlex') == [((1, 5), 1), ((2, 3), 2)] + def test_dmp_apply_pairs(): h = lambda a, b: a*b - assert dmp_apply_pairs([1,2,3], [4,5,6], h, [], 0, ZZ) == [4,10,18] + assert dmp_apply_pairs([1, 2, 3], [4, 5, 6], h, [], 0, ZZ) == [4, 10, 18] - assert dmp_apply_pairs([2,3], [4,5,6], h, [], 0, ZZ) == [10,18] - assert dmp_apply_pairs([1,2,3], [5,6], h, [], 0, ZZ) == [10,18] + assert dmp_apply_pairs([2, 3], [4, 5, 6], h, [], 0, ZZ) == [10, 18] + assert dmp_apply_pairs([1, 2, 3], [5, 6], h, [], 0, ZZ) == [10, 18] - assert dmp_apply_pairs([[1,2],[3]], [[4,5],[6]], h, [], 1, ZZ) == [[4,10],[18]] + assert dmp_apply_pairs( + [[1, 2], [3]], [[4, 5], [6]], h, [], 1, ZZ) == [[4, 10], [18]] + + assert dmp_apply_pairs( + [[1, 2], [3]], [[4], [5, 6]], h, [], 1, ZZ) == [[8], [18]] + assert dmp_apply_pairs( + [[1], [2, 3]], [[4, 5], [6]], h, [], 1, ZZ) == [[5], [18]] - assert dmp_apply_pairs([[1,2],[3]], [[4],[5,6]], h, [], 1, ZZ) == [[8],[18]] - assert dmp_apply_pairs([[1],[2,3]], [[4,5],[6]], h, [], 1, ZZ) == [[5],[18]] def test_dup_slice(): f = [1, 2, 3, 4] assert dup_slice(f, 0, 0, ZZ) == [] assert dup_slice(f, 0, 1, ZZ) == [4] - assert dup_slice(f, 0, 2, ZZ) == [3,4] - assert dup_slice(f, 0, 3, ZZ) == [2,3,4] - assert dup_slice(f, 0, 4, ZZ) == [1,2,3,4] + assert dup_slice(f, 0, 2, ZZ) == [3, 4] + assert dup_slice(f, 0, 3, ZZ) == [2, 3, 4] + assert dup_slice(f, 0, 4, ZZ) == [1, 2, 3, 4] assert dup_slice(f, 0, 4, ZZ) == f assert dup_slice(f, 0, 9, ZZ) == f assert dup_slice(f, 1, 0, ZZ) == [] assert dup_slice(f, 1, 1, ZZ) == [] - assert dup_slice(f, 1, 2, ZZ) == [3,0] - assert dup_slice(f, 1, 3, ZZ) == [2,3,0] - assert dup_slice(f, 1, 4, ZZ) == [1,2,3,0] + assert dup_slice(f, 1, 2, ZZ) == [3, 0] + assert dup_slice(f, 1, 3, ZZ) == [2, 3, 0] + assert dup_slice(f, 1, 4, ZZ) == [1, 2, 3, 0] + + assert dup_slice([1, 2], 0, 3, ZZ) == [1, 2] + def test_dup_random(): f = dup_random(0, -10, 10, ZZ) diff -Nru python3-sympy-0.7.2/sympy/polys/tests/test_densetools.py python3-sympy-0.7.3/sympy/polys/tests/test_densetools.py --- python3-sympy-0.7.2/sympy/polys/tests/test_densetools.py 2012-10-17 03:02:22.000000000 +0000 +++ python3-sympy-0.7.3/sympy/polys/tests/test_densetools.py 2013-07-13 17:53:32.000000000 +0000 @@ -42,7 +42,7 @@ ) from sympy.polys.specialpolys import ( - f_0, f_1, f_2, f_3, f_4, f_5, f_6, + f_polys, dmp_fateman_poly_F_1, dmp_fateman_poly_F_2, dmp_fateman_poly_F_3, @@ -50,86 +50,100 @@ from sympy.polys.domains import FF, ZZ, QQ, EX -from sympy import I +from sympy import S, I, sin + +from sympy.abc import x from sympy.utilities.pytest import raises +f_0, f_1, f_2, f_3, f_4, f_5, f_6 = [ f.to_dense() for f in f_polys() ] + def test_dup_integrate(): assert dup_integrate([], 1, QQ) == [] assert dup_integrate([], 2, QQ) == [] - assert dup_integrate([QQ(1)], 1, QQ) == [QQ(1),QQ(0)] - assert dup_integrate([QQ(1)], 2, QQ) == [QQ(1,2),QQ(0),QQ(0)] + assert dup_integrate([QQ(1)], 1, QQ) == [QQ(1), QQ(0)] + assert dup_integrate([QQ(1)], 2, QQ) == [QQ(1, 2), QQ(0), QQ(0)] - assert dup_integrate([QQ(1),QQ(2),QQ(3)], 0, QQ) == \ - [QQ(1),QQ(2),QQ(3)] - assert dup_integrate([QQ(1),QQ(2),QQ(3)], 1, QQ) == \ - [QQ(1,3),QQ(1),QQ(3),QQ(0)] - assert dup_integrate([QQ(1),QQ(2),QQ(3)], 2, QQ) == \ - [QQ(1,12),QQ(1,3),QQ(3,2),QQ(0),QQ(0)] - assert dup_integrate([QQ(1),QQ(2),QQ(3)], 3, QQ) == \ - [QQ(1,60),QQ(1,12),QQ(1,2),QQ(0),QQ(0),QQ(0)] + assert dup_integrate([QQ(1), QQ(2), QQ(3)], 0, QQ) == \ + [QQ(1), QQ(2), QQ(3)] + assert dup_integrate([QQ(1), QQ(2), QQ(3)], 1, QQ) == \ + [QQ(1, 3), QQ(1), QQ(3), QQ(0)] + assert dup_integrate([QQ(1), QQ(2), QQ(3)], 2, QQ) == \ + [QQ(1, 12), QQ(1, 3), QQ(3, 2), QQ(0), QQ(0)] + assert dup_integrate([QQ(1), QQ(2), QQ(3)], 3, QQ) == \ + [QQ(1, 60), QQ(1, 12), QQ(1, 2), QQ(0), QQ(0), QQ(0)] assert dup_integrate(dup_from_raw_dict({29: QQ(17)}, QQ), 3, QQ) == \ - dup_from_raw_dict({32: QQ(17,29760)}, QQ) + dup_from_raw_dict({32: QQ(17, 29760)}, QQ) + + assert dup_integrate(dup_from_raw_dict({29: QQ(17), 5: QQ(1, 2)}, QQ), 3, QQ) == \ + dup_from_raw_dict({32: QQ(17, 29760), 8: QQ(1, 672)}, QQ) - assert dup_integrate(dup_from_raw_dict({29: QQ(17), 5: QQ(1,2)}, QQ), 3, QQ) == \ - dup_from_raw_dict({32: QQ(17,29760), 8: QQ(1, 672)}, QQ) def test_dmp_integrate(): assert dmp_integrate([[[]]], 1, 2, QQ) == [[[]]] assert dmp_integrate([[[]]], 2, 2, QQ) == [[[]]] - assert dmp_integrate([[[QQ(1)]]], 1, 2, QQ) == [[[QQ(1)]],[[]]] - assert dmp_integrate([[[QQ(1)]]], 2, 2, QQ) == [[[QQ(1,2)]],[[]],[[]]] + assert dmp_integrate([[[QQ(1)]]], 1, 2, QQ) == [[[QQ(1)]], [[]]] + assert dmp_integrate([[[QQ(1)]]], 2, 2, QQ) == [[[QQ(1, 2)]], [[]], [[]]] + + assert dmp_integrate([[QQ(1)], [QQ(2)], [QQ(3)]], 0, 1, QQ) == \ + [[QQ(1)], [QQ(2)], [QQ(3)]] + assert dmp_integrate([[QQ(1)], [QQ(2)], [QQ(3)]], 1, 1, QQ) == \ + [[QQ(1, 3)], [QQ(1)], [QQ(3)], []] + assert dmp_integrate([[QQ(1)], [QQ(2)], [QQ(3)]], 2, 1, QQ) == \ + [[QQ(1, 12)], [QQ(1, 3)], [QQ(3, 2)], [], []] + assert dmp_integrate([[QQ(1)], [QQ(2)], [QQ(3)]], 3, 1, QQ) == \ + [[QQ(1, 60)], [QQ(1, 12)], [QQ(1, 2)], [], [], []] - assert dmp_integrate([[QQ(1)],[QQ(2)],[QQ(3)]], 0, 1, QQ) == \ - [[QQ(1)],[QQ(2)],[QQ(3)]] - assert dmp_integrate([[QQ(1)],[QQ(2)],[QQ(3)]], 1, 1, QQ) == \ - [[QQ(1,3)],[QQ(1)],[QQ(3)],[]] - assert dmp_integrate([[QQ(1)],[QQ(2)],[QQ(3)]], 2, 1, QQ) == \ - [[QQ(1,12)],[QQ(1,3)],[QQ(3,2)],[],[]] - assert dmp_integrate([[QQ(1)],[QQ(2)],[QQ(3)]], 3, 1, QQ) == \ - [[QQ(1,60)],[QQ(1,12)],[QQ(1,2)],[],[],[]] def test_dmp_integrate_in(): f = dmp_convert(f_6, 3, ZZ, QQ) assert dmp_integrate_in(f, 2, 1, 3, QQ) == \ - dmp_swap(dmp_integrate(dmp_swap(f, 0, 1, 3, QQ), 2, 3, QQ), 0, 1, 3, QQ) + dmp_swap( + dmp_integrate(dmp_swap(f, 0, 1, 3, QQ), 2, 3, QQ), 0, 1, 3, QQ) assert dmp_integrate_in(f, 3, 1, 3, QQ) == \ - dmp_swap(dmp_integrate(dmp_swap(f, 0, 1, 3, QQ), 3, 3, QQ), 0, 1, 3, QQ) + dmp_swap( + dmp_integrate(dmp_swap(f, 0, 1, 3, QQ), 3, 3, QQ), 0, 1, 3, QQ) assert dmp_integrate_in(f, 2, 2, 3, QQ) == \ - dmp_swap(dmp_integrate(dmp_swap(f, 0, 2, 3, QQ), 2, 3, QQ), 0, 2, 3, QQ) + dmp_swap( + dmp_integrate(dmp_swap(f, 0, 2, 3, QQ), 2, 3, QQ), 0, 2, 3, QQ) assert dmp_integrate_in(f, 3, 2, 3, QQ) == \ - dmp_swap(dmp_integrate(dmp_swap(f, 0, 2, 3, QQ), 3, 3, QQ), 0, 2, 3, QQ) + dmp_swap( + dmp_integrate(dmp_swap(f, 0, 2, 3, QQ), 3, 3, QQ), 0, 2, 3, QQ) + def test_dup_diff(): assert dup_diff([], 1, ZZ) == [] assert dup_diff([7], 1, ZZ) == [] - assert dup_diff([2,7], 1, ZZ) == [2] - assert dup_diff([1,2,1], 1, ZZ) == [2,2] - assert dup_diff([1,2,3,4], 1, ZZ) == [3,4,3] - assert dup_diff([1,-1,0,0,2], 1, ZZ) == [4,-3,0,0] - - f = dup_normal([17,34,56,-345,23,76,0,0,12,3,7], ZZ) - - assert dup_diff(f, 0, ZZ) == f - assert dup_diff(f, 1, ZZ) == dup_diff(f, 1, ZZ) - assert dup_diff(f, 2, ZZ) == dup_diff(dup_diff(f, 1, ZZ), 1, ZZ) - assert dup_diff(f, 3, ZZ) == dup_diff(dup_diff(dup_diff(f, 1, ZZ), 1, ZZ), 1, ZZ) + assert dup_diff([2, 7], 1, ZZ) == [2] + assert dup_diff([1, 2, 1], 1, ZZ) == [2, 2] + assert dup_diff([1, 2, 3, 4], 1, ZZ) == [3, 4, 3] + assert dup_diff([1, -1, 0, 0, 2], 1, ZZ) == [4, -3, 0, 0] + + f = dup_normal([17, 34, 56, -345, 23, 76, 0, 0, 12, 3, 7], ZZ) + + assert dup_diff(f, 0, ZZ) == f + assert dup_diff(f, 1, ZZ) == dup_diff(f, 1, ZZ) + assert dup_diff(f, 2, ZZ) == dup_diff(dup_diff(f, 1, ZZ), 1, ZZ) + assert dup_diff( + f, 3, ZZ) == dup_diff(dup_diff(dup_diff(f, 1, ZZ), 1, ZZ), 1, ZZ) K = FF(3) - f = dup_normal([17,34,56,-345,23,76,0,0,12,3,7], K) + f = dup_normal([17, 34, 56, -345, 23, 76, 0, 0, 12, 3, 7], K) - assert dup_diff(f, 1, K) == dup_normal([2,0,1,0,0,2,0,0,0,0], K) - assert dup_diff(f, 2, K) == dup_normal([1,0,0,2,0,0,0], K) + assert dup_diff(f, 1, K) == dup_normal([2, 0, 1, 0, 0, 2, 0, 0, 0, 0], K) + assert dup_diff(f, 2, K) == dup_normal([1, 0, 0, 2, 0, 0, 0], K) assert dup_diff(f, 3, K) == dup_normal([], K) - assert dup_diff(f, 0, K) == f - assert dup_diff(f, 1, K) == dup_diff(f, 1, K) - assert dup_diff(f, 2, K) == dup_diff(dup_diff(f, 1, K), 1, K) - assert dup_diff(f, 3, K) == dup_diff(dup_diff(dup_diff(f, 1, K), 1, K), 1, K) + assert dup_diff(f, 0, K) == f + assert dup_diff(f, 1, K) == dup_diff(f, 1, K) + assert dup_diff(f, 2, K) == dup_diff(dup_diff(f, 1, K), 1, K) + assert dup_diff( + f, 3, K) == dup_diff(dup_diff(dup_diff(f, 1, K), 1, K), 1, K) + def test_dmp_diff(): assert dmp_diff([], 1, 0, ZZ) == [] @@ -141,21 +155,25 @@ assert dmp_diff([[[1]], [[]]], 1, 2, ZZ) == [[[1]]] assert dmp_diff([[[3]], [[1]], [[]]], 1, 2, ZZ) == [[[6]], [[1]]] - assert dmp_diff([1,-1,0,0,2], 1, 0, ZZ) == \ - dup_diff([1,-1,0,0,2], 1, ZZ) + assert dmp_diff([1, -1, 0, 0, 2], 1, 0, ZZ) == \ + dup_diff([1, -1, 0, 0, 2], 1, ZZ) - assert dmp_diff(f_6, 0, 3, ZZ) == f_6 - assert dmp_diff(f_6, 1, 3, ZZ) == dmp_diff(f_6, 1, 3, ZZ) - assert dmp_diff(f_6, 2, 3, ZZ) == dmp_diff(dmp_diff(f_6, 1, 3, ZZ), 1, 3, ZZ) - assert dmp_diff(f_6, 3, 3, ZZ) == dmp_diff(dmp_diff(dmp_diff(f_6, 1, 3, ZZ), 1, 3, ZZ), 1, 3, ZZ) + assert dmp_diff(f_6, 0, 3, ZZ) == f_6 + assert dmp_diff(f_6, 1, 3, ZZ) == dmp_diff(f_6, 1, 3, ZZ) + assert dmp_diff( + f_6, 2, 3, ZZ) == dmp_diff(dmp_diff(f_6, 1, 3, ZZ), 1, 3, ZZ) + assert dmp_diff(f_6, 3, 3, ZZ) == dmp_diff( + dmp_diff(dmp_diff(f_6, 1, 3, ZZ), 1, 3, ZZ), 1, 3, ZZ) K = FF(23) F_6 = dmp_normal(f_6, 3, K) - assert dmp_diff(F_6, 0, 3, K) == F_6 - assert dmp_diff(F_6, 1, 3, K) == dmp_diff(F_6, 1, 3, K) - assert dmp_diff(F_6, 2, 3, K) == dmp_diff(dmp_diff(F_6, 1, 3, K), 1, 3, K) - assert dmp_diff(F_6, 3, 3, K) == dmp_diff(dmp_diff(dmp_diff(F_6, 1, 3, K), 1, 3, K), 1, 3, K) + assert dmp_diff(F_6, 0, 3, K) == F_6 + assert dmp_diff(F_6, 1, 3, K) == dmp_diff(F_6, 1, 3, K) + assert dmp_diff(F_6, 2, 3, K) == dmp_diff(dmp_diff(F_6, 1, 3, K), 1, 3, K) + assert dmp_diff(F_6, 3, 3, K) == dmp_diff( + dmp_diff(dmp_diff(F_6, 1, 3, K), 1, 3, K), 1, 3, K) + def test_dmp_diff_in(): assert dmp_diff_in(f_6, 2, 1, 3, ZZ) == \ @@ -167,10 +185,12 @@ assert dmp_diff_in(f_6, 3, 2, 3, ZZ) == \ dmp_swap(dmp_diff(dmp_swap(f_6, 0, 2, 3, ZZ), 3, 3, ZZ), 0, 2, 3, ZZ) + def test_dup_eval(): assert dup_eval([], 7, ZZ) == 0 - assert dup_eval([1,2], 0, ZZ) == 2 - assert dup_eval([1,2,3], 7, ZZ) == 66 + assert dup_eval([1, 2], 0, ZZ) == 2 + assert dup_eval([1, 2, 3], 7, ZZ) == 66 + def test_dmp_eval(): assert dmp_eval([], 3, 0, ZZ) == 0 @@ -178,7 +198,7 @@ assert dmp_eval([[]], 3, 1, ZZ) == [] assert dmp_eval([[[]]], 3, 2, ZZ) == [[]] - assert dmp_eval([[1,2]], 0, 1, ZZ) == [1,2] + assert dmp_eval([[1, 2]], 0, 1, ZZ) == [1, 2] assert dmp_eval([[[1]]], 3, 2, ZZ) == [[1]] assert dmp_eval([[[1, 2]]], 3, 2, ZZ) == [[1, 2]] @@ -186,17 +206,23 @@ assert dmp_eval([[3, 2], [1, 2]], 3, 1, ZZ) == [10, 8] assert dmp_eval([[[3, 2]], [[1, 2]]], 3, 2, ZZ) == [[10, 8]] + def test_dmp_eval_in(): - assert dmp_eval_in(f_6,-2, 1, 3, ZZ) == dmp_eval(dmp_swap(f_6, 0, 1, 3, ZZ),-2, 3, ZZ) - assert dmp_eval_in(f_6, 7, 1, 3, ZZ) == dmp_eval(dmp_swap(f_6, 0, 1, 3, ZZ), 7, 3, ZZ) - assert dmp_eval_in(f_6,-2, 2, 3, ZZ) == dmp_swap(dmp_eval(dmp_swap(f_6, 0, 2, 3, ZZ),-2, 3, ZZ), 0, 1, 2, ZZ) - assert dmp_eval_in(f_6, 7, 2, 3, ZZ) == dmp_swap(dmp_eval(dmp_swap(f_6, 0, 2, 3, ZZ), 7, 3, ZZ), 0, 1, 2, ZZ) + assert dmp_eval_in( + f_6, -2, 1, 3, ZZ) == dmp_eval(dmp_swap(f_6, 0, 1, 3, ZZ), -2, 3, ZZ) + assert dmp_eval_in( + f_6, 7, 1, 3, ZZ) == dmp_eval(dmp_swap(f_6, 0, 1, 3, ZZ), 7, 3, ZZ) + assert dmp_eval_in(f_6, -2, 2, 3, ZZ) == dmp_swap( + dmp_eval(dmp_swap(f_6, 0, 2, 3, ZZ), -2, 3, ZZ), 0, 1, 2, ZZ) + assert dmp_eval_in(f_6, 7, 2, 3, ZZ) == dmp_swap( + dmp_eval(dmp_swap(f_6, 0, 2, 3, ZZ), 7, 3, ZZ), 0, 1, 2, ZZ) f = [[[45]], [[]], [[]], [[-9], [-1], [], [3, 0, 10, 0]]] assert dmp_eval_in(f, -2, 2, 2, ZZ) == \ [[45], [], [], [-9, -1, 0, -44]] + def test_dmp_eval_tail(): assert dmp_eval_tail([[]], [1], 1, ZZ) == [] assert dmp_eval_tail([[[]]], [1], 2, ZZ) == [[]] @@ -204,164 +230,205 @@ assert dmp_eval_tail(f_0, [], 2, ZZ) == f_0 - assert dmp_eval_tail(f_0, [1,-17,8], 2, ZZ) == 84496 + assert dmp_eval_tail(f_0, [1, -17, 8], 2, ZZ) == 84496 assert dmp_eval_tail(f_0, [-17, 8], 2, ZZ) == [-1409, 3, 85902] assert dmp_eval_tail(f_0, [8], 2, ZZ) == [[83, 2], [3], [302, 81, 1]] assert dmp_eval_tail(f_1, [-17, 8], 2, ZZ) == [-136, 15699, 9166, -27144] - assert dmp_eval_tail(f_2, [-12, 3], 2, ZZ) == [-1377, 0, -702, -1224, 0, -624] - assert dmp_eval_tail(f_3, [-12, 3], 2, ZZ) == [144, 82, -5181, -28872, -14868, -540] + assert dmp_eval_tail( + f_2, [-12, 3], 2, ZZ) == [-1377, 0, -702, -1224, 0, -624] + assert dmp_eval_tail( + f_3, [-12, 3], 2, ZZ) == [144, 82, -5181, -28872, -14868, -540] - assert dmp_eval_tail(f_4, [25, -1], 2, ZZ) == [152587890625, 9765625, -59605407714843750, + assert dmp_eval_tail( + f_4, [25, -1], 2, ZZ) == [152587890625, 9765625, -59605407714843750, -3839159765625, -1562475, 9536712644531250, 610349546750, -4, 24414375000, 1562520] assert dmp_eval_tail(f_5, [25, -1], 2, ZZ) == [-1, -78, -2028, -17576] assert dmp_eval_tail(f_6, [0, 2, 4], 3, ZZ) == [5040, 0, 0, 4480] + def test_dmp_diff_eval_in(): assert dmp_diff_eval_in(f_6, 2, 7, 1, 3, ZZ) == \ dmp_eval(dmp_diff(dmp_swap(f_6, 0, 1, 3, ZZ), 2, 3, ZZ), 7, 3, ZZ) + def test_dup_revert(): - f = [-QQ(1,720),QQ(0),QQ(1,24),QQ(0),-QQ(1,2),QQ(0),QQ(1)] - g = [QQ(61,720),QQ(0),QQ(5,24),QQ(0), QQ(1,2),QQ(0),QQ(1)] + f = [-QQ(1, 720), QQ(0), QQ(1, 24), QQ(0), -QQ(1, 2), QQ(0), QQ(1)] + g = [QQ(61, 720), QQ(0), QQ(5, 24), QQ(0), QQ(1, 2), QQ(0), QQ(1)] assert dup_revert(f, 8, QQ) == g raises(NotReversible, lambda: dup_revert([QQ(1), QQ(0)], 3, QQ)) + def test_dmp_revert(): - f = [-QQ(1,720),QQ(0),QQ(1,24),QQ(0),-QQ(1,2),QQ(0),QQ(1)] - g = [QQ(61,720),QQ(0),QQ(5,24),QQ(0), QQ(1,2),QQ(0),QQ(1)] + f = [-QQ(1, 720), QQ(0), QQ(1, 24), QQ(0), -QQ(1, 2), QQ(0), QQ(1)] + g = [QQ(61, 720), QQ(0), QQ(5, 24), QQ(0), QQ(1, 2), QQ(0), QQ(1)] assert dmp_revert(f, 8, 0, QQ) == g raises(MultivariatePolynomialError, lambda: dmp_revert([[1]], 2, 1, QQ)) + def test_dup_trunc(): - assert dup_trunc([1,2,3,4,5,6], ZZ(3), ZZ) == [1, -1, 0, 1, -1, 0] - assert dup_trunc([6,5,4,3,2,1], ZZ(3), ZZ) == [-1, 1, 0, -1, 1] + assert dup_trunc([1, 2, 3, 4, 5, 6], ZZ(3), ZZ) == [1, -1, 0, 1, -1, 0] + assert dup_trunc([6, 5, 4, 3, 2, 1], ZZ(3), ZZ) == [-1, 1, 0, -1, 1] + def test_dmp_trunc(): - assert dmp_trunc([[]], [1,2], 2, ZZ) == [[]] - assert dmp_trunc([[1,2], [1,4,1], [1]], [1,2], 1, ZZ) == [[-3], [1]] + assert dmp_trunc([[]], [1, 2], 2, ZZ) == [[]] + assert dmp_trunc([[1, 2], [1, 4, 1], [1]], [1, 2], 1, ZZ) == [[-3], [1]] + def test_dmp_ground_trunc(): assert dmp_ground_trunc(f_0, ZZ(3), 2, ZZ) == \ - dmp_normal([[[1, -1, 0], [-1]], [[]], [[1, -1, 0], [1, -1, 1], [1]]], 2, ZZ) + dmp_normal( + [[[1, -1, 0], [-1]], [[]], [[1, -1, 0], [1, -1, 1], [1]]], 2, ZZ) + def test_dup_monic(): - assert dup_monic([3,6,9], ZZ) == [1,2,3] + assert dup_monic([3, 6, 9], ZZ) == [1, 2, 3] - raises(ExactQuotientFailed, lambda: dup_monic([3,4,5], ZZ)) + raises(ExactQuotientFailed, lambda: dup_monic([3, 4, 5], ZZ)) assert dup_monic([], QQ) == [] assert dup_monic([QQ(1)], QQ) == [QQ(1)] - assert dup_monic([QQ(7),QQ(1),QQ(21)], QQ) == [QQ(1),QQ(1,7),QQ(3)] + assert dup_monic([QQ(7), QQ(1), QQ(21)], QQ) == [QQ(1), QQ(1, 7), QQ(3)] + def test_dmp_ground_monic(): - assert dmp_ground_monic([[3],[6],[9]], 1, ZZ) == [[1],[2],[3]] + assert dmp_ground_monic([[3], [6], [9]], 1, ZZ) == [[1], [2], [3]] - raises(ExactQuotientFailed, lambda: dmp_ground_monic([[3],[4],[5]], 1, ZZ)) + raises( + ExactQuotientFailed, lambda: dmp_ground_monic([[3], [4], [5]], 1, ZZ)) assert dmp_ground_monic([[]], 1, QQ) == [[]] assert dmp_ground_monic([[QQ(1)]], 1, QQ) == [[QQ(1)]] - assert dmp_ground_monic([[QQ(7)],[QQ(1)],[QQ(21)]], 1, QQ) == [[QQ(1)],[QQ(1,7)],[QQ(3)]] + assert dmp_ground_monic( + [[QQ(7)], [QQ(1)], [QQ(21)]], 1, QQ) == [[QQ(1)], [QQ(1, 7)], [QQ(3)]] + def test_dup_content(): assert dup_content([], ZZ) == ZZ(0) assert dup_content([1], ZZ) == ZZ(1) assert dup_content([-1], ZZ) == ZZ(1) - assert dup_content([1,1], ZZ) == ZZ(1) - assert dup_content([2,2], ZZ) == ZZ(2) - assert dup_content([1,2,1], ZZ) == ZZ(1) - assert dup_content([2,4,2], ZZ) == ZZ(2) + assert dup_content([1, 1], ZZ) == ZZ(1) + assert dup_content([2, 2], ZZ) == ZZ(2) + assert dup_content([1, 2, 1], ZZ) == ZZ(1) + assert dup_content([2, 4, 2], ZZ) == ZZ(2) + + assert dup_content([QQ(2, 3), QQ(4, 9)], QQ) == QQ(2, 9) + assert dup_content([QQ(2, 3), QQ(4, 5)], QQ) == QQ(2, 15) - assert dup_content([QQ(2,3),QQ(4,9)], QQ) == QQ(2,9) - assert dup_content([QQ(2,3),QQ(4,5)], QQ) == QQ(2,15) def test_dmp_ground_content(): assert dmp_ground_content([[]], 1, ZZ) == ZZ(0) assert dmp_ground_content([[]], 1, QQ) == QQ(0) assert dmp_ground_content([[1]], 1, ZZ) == ZZ(1) assert dmp_ground_content([[-1]], 1, ZZ) == ZZ(1) - assert dmp_ground_content([[1],[1]], 1, ZZ) == ZZ(1) - assert dmp_ground_content([[2],[2]], 1, ZZ) == ZZ(2) - assert dmp_ground_content([[1],[2],[1]], 1, ZZ) == ZZ(1) - assert dmp_ground_content([[2],[4],[2]], 1, ZZ) == ZZ(2) + assert dmp_ground_content([[1], [1]], 1, ZZ) == ZZ(1) + assert dmp_ground_content([[2], [2]], 1, ZZ) == ZZ(2) + assert dmp_ground_content([[1], [2], [1]], 1, ZZ) == ZZ(1) + assert dmp_ground_content([[2], [4], [2]], 1, ZZ) == ZZ(2) - assert dmp_ground_content([[QQ(2,3)],[QQ(4,9)]], 1, QQ) == QQ(2,9) - assert dmp_ground_content([[QQ(2,3)],[QQ(4,5)]], 1, QQ) == QQ(2,15) + assert dmp_ground_content([[QQ(2, 3)], [QQ(4, 9)]], 1, QQ) == QQ(2, 9) + assert dmp_ground_content([[QQ(2, 3)], [QQ(4, 5)]], 1, QQ) == QQ(2, 15) assert dmp_ground_content(f_0, 2, ZZ) == ZZ(1) - assert dmp_ground_content(dmp_mul_ground(f_0, ZZ(2), 2, ZZ), 2, ZZ) == ZZ(2) + assert dmp_ground_content( + dmp_mul_ground(f_0, ZZ(2), 2, ZZ), 2, ZZ) == ZZ(2) assert dmp_ground_content(f_1, 2, ZZ) == ZZ(1) - assert dmp_ground_content(dmp_mul_ground(f_1, ZZ(3), 2, ZZ), 2, ZZ) == ZZ(3) + assert dmp_ground_content( + dmp_mul_ground(f_1, ZZ(3), 2, ZZ), 2, ZZ) == ZZ(3) assert dmp_ground_content(f_2, 2, ZZ) == ZZ(1) - assert dmp_ground_content(dmp_mul_ground(f_2, ZZ(4), 2, ZZ), 2, ZZ) == ZZ(4) + assert dmp_ground_content( + dmp_mul_ground(f_2, ZZ(4), 2, ZZ), 2, ZZ) == ZZ(4) assert dmp_ground_content(f_3, 2, ZZ) == ZZ(1) - assert dmp_ground_content(dmp_mul_ground(f_3, ZZ(5), 2, ZZ), 2, ZZ) == ZZ(5) + assert dmp_ground_content( + dmp_mul_ground(f_3, ZZ(5), 2, ZZ), 2, ZZ) == ZZ(5) assert dmp_ground_content(f_4, 2, ZZ) == ZZ(1) - assert dmp_ground_content(dmp_mul_ground(f_4, ZZ(6), 2, ZZ), 2, ZZ) == ZZ(6) + assert dmp_ground_content( + dmp_mul_ground(f_4, ZZ(6), 2, ZZ), 2, ZZ) == ZZ(6) assert dmp_ground_content(f_5, 2, ZZ) == ZZ(1) - assert dmp_ground_content(dmp_mul_ground(f_5, ZZ(7), 2, ZZ), 2, ZZ) == ZZ(7) + assert dmp_ground_content( + dmp_mul_ground(f_5, ZZ(7), 2, ZZ), 2, ZZ) == ZZ(7) assert dmp_ground_content(f_6, 3, ZZ) == ZZ(1) - assert dmp_ground_content(dmp_mul_ground(f_6, ZZ(8), 3, ZZ), 3, ZZ) == ZZ(8) + assert dmp_ground_content( + dmp_mul_ground(f_6, ZZ(8), 3, ZZ), 3, ZZ) == ZZ(8) + def test_dup_primitive(): assert dup_primitive([], ZZ) == (ZZ(0), []) assert dup_primitive([ZZ(1)], ZZ) == (ZZ(1), [ZZ(1)]) - assert dup_primitive([ZZ(1),ZZ(1)], ZZ) == (ZZ(1), [ZZ(1),ZZ(1)]) - assert dup_primitive([ZZ(2),ZZ(2)], ZZ) == (ZZ(2), [ZZ(1),ZZ(1)]) - assert dup_primitive([ZZ(1),ZZ(2),ZZ(1)], ZZ) == (ZZ(1), [ZZ(1),ZZ(2),ZZ(1)]) - assert dup_primitive([ZZ(2),ZZ(4),ZZ(2)], ZZ) == (ZZ(2), [ZZ(1),ZZ(2),ZZ(1)]) + assert dup_primitive([ZZ(1), ZZ(1)], ZZ) == (ZZ(1), [ZZ(1), ZZ(1)]) + assert dup_primitive([ZZ(2), ZZ(2)], ZZ) == (ZZ(2), [ZZ(1), ZZ(1)]) + assert dup_primitive( + [ZZ(1), ZZ(2), ZZ(1)], ZZ) == (ZZ(1), [ZZ(1), ZZ(2), ZZ(1)]) + assert dup_primitive( + [ZZ(2), ZZ(4), ZZ(2)], ZZ) == (ZZ(2), [ZZ(1), ZZ(2), ZZ(1)]) assert dup_primitive([], QQ) == (QQ(0), []) assert dup_primitive([QQ(1)], QQ) == (QQ(1), [QQ(1)]) - assert dup_primitive([QQ(1),QQ(1)], QQ) == (QQ(1), [QQ(1),QQ(1)]) - assert dup_primitive([QQ(2),QQ(2)], QQ) == (QQ(2), [QQ(1),QQ(1)]) - assert dup_primitive([QQ(1),QQ(2),QQ(1)], QQ) == (QQ(1), [QQ(1),QQ(2),QQ(1)]) - assert dup_primitive([QQ(2),QQ(4),QQ(2)], QQ) == (QQ(2), [QQ(1),QQ(2),QQ(1)]) + assert dup_primitive([QQ(1), QQ(1)], QQ) == (QQ(1), [QQ(1), QQ(1)]) + assert dup_primitive([QQ(2), QQ(2)], QQ) == (QQ(2), [QQ(1), QQ(1)]) + assert dup_primitive( + [QQ(1), QQ(2), QQ(1)], QQ) == (QQ(1), [QQ(1), QQ(2), QQ(1)]) + assert dup_primitive( + [QQ(2), QQ(4), QQ(2)], QQ) == (QQ(2), [QQ(1), QQ(2), QQ(1)]) + + assert dup_primitive( + [QQ(2, 3), QQ(4, 9)], QQ) == (QQ(2, 9), [QQ(3), QQ(2)]) + assert dup_primitive( + [QQ(2, 3), QQ(4, 5)], QQ) == (QQ(2, 15), [QQ(5), QQ(6)]) - assert dup_primitive([QQ(2,3),QQ(4,9)], QQ) == (QQ(2,9), [QQ(3),QQ(2)]) - assert dup_primitive([QQ(2,3),QQ(4,5)], QQ) == (QQ(2,15), [QQ(5),QQ(6)]) def test_dmp_ground_primitive(): assert dmp_ground_primitive([[]], 1, ZZ) == (ZZ(0), [[]]) assert dmp_ground_primitive(f_0, 2, ZZ) == (ZZ(1), f_0) - assert dmp_ground_primitive(dmp_mul_ground(f_0, ZZ(2), 2, ZZ), 2, ZZ) == (ZZ(2), f_0) + assert dmp_ground_primitive( + dmp_mul_ground(f_0, ZZ(2), 2, ZZ), 2, ZZ) == (ZZ(2), f_0) assert dmp_ground_primitive(f_1, 2, ZZ) == (ZZ(1), f_1) - assert dmp_ground_primitive(dmp_mul_ground(f_1, ZZ(3), 2, ZZ), 2, ZZ) == (ZZ(3), f_1) + assert dmp_ground_primitive( + dmp_mul_ground(f_1, ZZ(3), 2, ZZ), 2, ZZ) == (ZZ(3), f_1) assert dmp_ground_primitive(f_2, 2, ZZ) == (ZZ(1), f_2) - assert dmp_ground_primitive(dmp_mul_ground(f_2, ZZ(4), 2, ZZ), 2, ZZ) == (ZZ(4), f_2) + assert dmp_ground_primitive( + dmp_mul_ground(f_2, ZZ(4), 2, ZZ), 2, ZZ) == (ZZ(4), f_2) assert dmp_ground_primitive(f_3, 2, ZZ) == (ZZ(1), f_3) - assert dmp_ground_primitive(dmp_mul_ground(f_3, ZZ(5), 2, ZZ), 2, ZZ) == (ZZ(5), f_3) + assert dmp_ground_primitive( + dmp_mul_ground(f_3, ZZ(5), 2, ZZ), 2, ZZ) == (ZZ(5), f_3) assert dmp_ground_primitive(f_4, 2, ZZ) == (ZZ(1), f_4) - assert dmp_ground_primitive(dmp_mul_ground(f_4, ZZ(6), 2, ZZ), 2, ZZ) == (ZZ(6), f_4) + assert dmp_ground_primitive( + dmp_mul_ground(f_4, ZZ(6), 2, ZZ), 2, ZZ) == (ZZ(6), f_4) assert dmp_ground_primitive(f_5, 2, ZZ) == (ZZ(1), f_5) - assert dmp_ground_primitive(dmp_mul_ground(f_5, ZZ(7), 2, ZZ), 2, ZZ) == (ZZ(7), f_5) + assert dmp_ground_primitive( + dmp_mul_ground(f_5, ZZ(7), 2, ZZ), 2, ZZ) == (ZZ(7), f_5) assert dmp_ground_primitive(f_6, 3, ZZ) == (ZZ(1), f_6) - assert dmp_ground_primitive(dmp_mul_ground(f_6, ZZ(8), 3, ZZ), 3, ZZ) == (ZZ(8), f_6) + assert dmp_ground_primitive( + dmp_mul_ground(f_6, ZZ(8), 3, ZZ), 3, ZZ) == (ZZ(8), f_6) assert dmp_ground_primitive([[ZZ(2)]], 1, ZZ) == (ZZ(2), [[ZZ(1)]]) assert dmp_ground_primitive([[QQ(2)]], 1, QQ) == (QQ(2), [[QQ(1)]]) - assert dmp_ground_primitive([[QQ(2,3)], [QQ(4,9)]], 1, QQ) == (QQ(2,9), [[QQ(3)], [QQ(2)]]) - assert dmp_ground_primitive([[QQ(2,3)], [QQ(4,5)]], 1, QQ) == (QQ(2,15), [[QQ(5)], [QQ(6)]]) + assert dmp_ground_primitive( + [[QQ(2, 3)], [QQ(4, 9)]], 1, QQ) == (QQ(2, 9), [[QQ(3)], [QQ(2)]]) + assert dmp_ground_primitive( + [[QQ(2, 3)], [QQ(4, 5)]], 1, QQ) == (QQ(2, 15), [[QQ(5)], [QQ(6)]]) + def test_dup_extract(): f = dup_normal([2930944, 0, 2198208, 0, 549552, 0, 45796], ZZ) @@ -372,8 +439,10 @@ assert dup_extract(f, g, ZZ) == (45796, F, G) + def test_dmp_ground_extract(): - f = dmp_normal([[2930944], [], [2198208], [], [549552], [], [45796]], 1, ZZ) + f = dmp_normal( + [[2930944], [], [2198208], [], [549552], [], [45796]], 1, ZZ) g = dmp_normal([[17585664], [], [8792832], [], [1099104], []], 1, ZZ) F = dmp_normal([[64], [], [48], [], [12], [], [1]], 1, ZZ) @@ -381,152 +450,166 @@ assert dmp_ground_extract(f, g, 1, ZZ) == (45796, F, G) + def test_dup_real_imag(): assert dup_real_imag([], ZZ) == ([[]], [[]]) assert dup_real_imag([1], ZZ) == ([[1]], [[]]) - assert dup_real_imag([1,1], ZZ) == ([[1], [1]], [[1,0]]) - assert dup_real_imag([1,2], ZZ) == ([[1], [2]], [[1,0]]) + assert dup_real_imag([1, 1], ZZ) == ([[1], [1]], [[1, 0]]) + assert dup_real_imag([1, 2], ZZ) == ([[1], [2]], [[1, 0]]) - assert dup_real_imag([1,2,3], ZZ) == ([[1], [2], [-1,0,3]], [[2,0], [2,0]]) + assert dup_real_imag( + [1, 2, 3], ZZ) == ([[1], [2], [-1, 0, 3]], [[2, 0], [2, 0]]) raises(DomainError, lambda: dup_real_imag([EX(1), EX(2)], EX)) + def test_dup_mirror(): assert dup_mirror([], ZZ) == [] assert dup_mirror([1], ZZ) == [1] - assert dup_mirror([1,2,3,4,5], ZZ) == [1,-2,3,-4,5] - assert dup_mirror([1,2,3,4,5,6], ZZ) == [-1,2,-3,4,-5,6] + assert dup_mirror([1, 2, 3, 4, 5], ZZ) == [1, -2, 3, -4, 5] + assert dup_mirror([1, 2, 3, 4, 5, 6], ZZ) == [-1, 2, -3, 4, -5, 6] + def test_dup_scale(): assert dup_scale([], -1, ZZ) == [] assert dup_scale([1], -1, ZZ) == [1] - assert dup_scale([1,2,3,4,5], -1, ZZ) == [1,-2,3,-4,5] - assert dup_scale([1,2,3,4,5], -7, ZZ) == [2401,-686,147,-28,5] + assert dup_scale([1, 2, 3, 4, 5], -1, ZZ) == [1, -2, 3, -4, 5] + assert dup_scale([1, 2, 3, 4, 5], -7, ZZ) == [2401, -686, 147, -28, 5] + def test_dup_shift(): assert dup_shift([], 1, ZZ) == [] assert dup_shift([1], 1, ZZ) == [1] - assert dup_shift([1,2,3,4,5], 1, ZZ) == [1,6,15,20,15] - assert dup_shift([1,2,3,4,5], 7, ZZ) == [1,30,339,1712,3267] + assert dup_shift([1, 2, 3, 4, 5], 1, ZZ) == [1, 6, 15, 20, 15] + assert dup_shift([1, 2, 3, 4, 5], 7, ZZ) == [1, 30, 339, 1712, 3267] + def test_dup_transform(): - assert dup_transform([], [], [1,1], ZZ) == [] - assert dup_transform([], [1], [1,1], ZZ) == [] - assert dup_transform([], [1,2], [1,1], ZZ) == [] + assert dup_transform([], [], [1, 1], ZZ) == [] + assert dup_transform([], [1], [1, 1], ZZ) == [] + assert dup_transform([], [1, 2], [1, 1], ZZ) == [] + + assert dup_transform([6, -5, 4, -3, 17], [1, -3, 4], [2, -3], ZZ) == \ + [6, -82, 541, -2205, 6277, -12723, 17191, -13603, 4773] - assert dup_transform([6,-5,4,-3,17], [1,-3,4], [2,-3], ZZ) == \ - [6,-82,541,-2205,6277,-12723,17191,-13603,4773] def test_dup_compose(): assert dup_compose([], [], ZZ) == [] assert dup_compose([], [1], ZZ) == [] - assert dup_compose([], [1,2], ZZ) == [] + assert dup_compose([], [1, 2], ZZ) == [] assert dup_compose([1], [], ZZ) == [1] - assert dup_compose([1,2,0], [], ZZ) == [] - assert dup_compose([1,2,1], [], ZZ) == [1] + assert dup_compose([1, 2, 0], [], ZZ) == [] + assert dup_compose([1, 2, 1], [], ZZ) == [1] - assert dup_compose([1,2,1], [1], ZZ) == [4] - assert dup_compose([1,2,1], [7], ZZ) == [64] + assert dup_compose([1, 2, 1], [1], ZZ) == [4] + assert dup_compose([1, 2, 1], [7], ZZ) == [64] + + assert dup_compose([1, 2, 1], [1, -1], ZZ) == [1, 0, 0] + assert dup_compose([1, 2, 1], [1, 1], ZZ) == [1, 4, 4] + assert dup_compose([1, 2, 1], [1, 2, 1], ZZ) == [1, 4, 8, 8, 4] - assert dup_compose([1,2,1], [1,-1], ZZ) == [1,0,0] - assert dup_compose([1,2,1], [1, 1], ZZ) == [1,4,4] - assert dup_compose([1,2,1], [1, 2, 1], ZZ) == [1,4,8,8,4] def test_dmp_compose(): - assert dmp_compose([1,2,1], [1,2,1], 0, ZZ) == [1,4,8,8,4] + assert dmp_compose([1, 2, 1], [1, 2, 1], 0, ZZ) == [1, 4, 8, 8, 4] assert dmp_compose([[[]]], [[[]]], 2, ZZ) == [[[]]] assert dmp_compose([[[]]], [[[1]]], 2, ZZ) == [[[]]] - assert dmp_compose([[[]]], [[[1]],[[2]]], 2, ZZ) == [[[]]] + assert dmp_compose([[[]]], [[[1]], [[2]]], 2, ZZ) == [[[]]] assert dmp_compose([[[1]]], [], 2, ZZ) == [[[1]]] - assert dmp_compose([[1],[2],[ ]], [[]], 1, ZZ) == [[]] - assert dmp_compose([[1],[2],[1]], [[]], 1, ZZ) == [[1]] + assert dmp_compose([[1], [2], [ ]], [[]], 1, ZZ) == [[]] + assert dmp_compose([[1], [2], [1]], [[]], 1, ZZ) == [[1]] + + assert dmp_compose([[1], [2], [1]], [[1]], 1, ZZ) == [[4]] + assert dmp_compose([[1], [2], [1]], [[7]], 1, ZZ) == [[64]] - assert dmp_compose([[1],[2],[1]], [[1]], 1, ZZ) == [[4]] - assert dmp_compose([[1],[2],[1]], [[7]], 1, ZZ) == [[64]] + assert dmp_compose([[1], [2], [1]], [[1], [-1]], 1, ZZ) == [[1], [ ], [ ]] + assert dmp_compose([[1], [2], [1]], [[1], [ 1]], 1, ZZ) == [[1], [4], [4]] - assert dmp_compose([[1],[2],[1]], [[1],[-1]], 1, ZZ) == [[1],[ ],[ ]] - assert dmp_compose([[1],[2],[1]], [[1],[ 1]], 1, ZZ) == [[1],[4],[4]] + assert dmp_compose( + [[1], [2], [1]], [[1], [2], [1]], 1, ZZ) == [[1], [4], [8], [8], [4]] - assert dmp_compose([[1],[2],[1]], [[1], [2], [1]], 1, ZZ) == [[1],[4],[8],[8],[4]] def test_dup_decompose(): assert dup_decompose([1], ZZ) == [[1]] - assert dup_decompose([1,0], ZZ) == [[1,0]] - assert dup_decompose([1,0,0,0], ZZ) == [[1,0,0,0]] + assert dup_decompose([1, 0], ZZ) == [[1, 0]] + assert dup_decompose([1, 0, 0, 0], ZZ) == [[1, 0, 0, 0]] - assert dup_decompose([1,0,0,0,0], ZZ) == [[1,0,0], [1,0,0]] - assert dup_decompose([1,0,0,0,0,0,0], ZZ) == [[1,0,0,0], [1,0,0]] + assert dup_decompose([1, 0, 0, 0, 0], ZZ) == [[1, 0, 0], [1, 0, 0]] + assert dup_decompose( + [1, 0, 0, 0, 0, 0, 0], ZZ) == [[1, 0, 0, 0], [1, 0, 0]] - assert dup_decompose([7,0,0,0,1], ZZ) == [[7,0,1], [1,0,0]] - assert dup_decompose([4,0,3,0,2], ZZ) == [[4,3,2], [1,0,0]] + assert dup_decompose([7, 0, 0, 0, 1], ZZ) == [[7, 0, 1], [1, 0, 0]] + assert dup_decompose([4, 0, 3, 0, 2], ZZ) == [[4, 3, 2], [1, 0, 0]] - f = [1,0,20,0,150,0,500,0,625,-2,0,-10,9] + f = [1, 0, 20, 0, 150, 0, 500, 0, 625, -2, 0, -10, 9] - assert dup_decompose(f, ZZ) == [[1,0,0,-2,9], [1,0,5,0]] + assert dup_decompose(f, ZZ) == [[1, 0, 0, -2, 9], [1, 0, 5, 0]] - f = [2,0,40,0,300,0,1000,0,1250,-4,0,-20,18] + f = [2, 0, 40, 0, 300, 0, 1000, 0, 1250, -4, 0, -20, 18] - assert dup_decompose(f, ZZ) == [[2,0,0,-4,18], [1,0,5,0]] + assert dup_decompose(f, ZZ) == [[2, 0, 0, -4, 18], [1, 0, 5, 0]] - f = [1,0,20,-8,150,-120,524,-600,865,-1034,600,-170,29] + f = [1, 0, 20, -8, 150, -120, 524, -600, 865, -1034, 600, -170, 29] - assert dup_decompose(f, ZZ) == [[1,-8,24,-34,29], [1,0,5,0]] + assert dup_decompose(f, ZZ) == [[1, -8, 24, -34, 29], [1, 0, 5, 0]] - f = [DMP([6,0,-42], ZZ), DMP([48,0,96], ZZ), DMP([144,648,288], ZZ), - DMP([624,864,384], ZZ), DMP([108,312,432,192], ZZ)] + f = [DMP([6, 0, -42], ZZ), DMP([48, 0, 96], ZZ), DMP([144, 648, 288], ZZ), + DMP([624, 864, 384], ZZ), DMP([108, 312, 432, 192], ZZ)] assert dup_decompose(f, ZZ['a']) == [f] + def test_dmp_lift(): - q = [QQ(1,1),QQ(0,1),QQ(1,1)] + q = [QQ(1, 1), QQ(0, 1), QQ(1, 1)] - f = [ANP([QQ(1,1)], q, QQ), ANP([], q, QQ), ANP([], q, QQ), - ANP([QQ(1,1),QQ(0,1)], q, QQ), ANP([QQ(17,1),QQ(0,1)], q, QQ)] + f = [ANP([QQ(1, 1)], q, QQ), ANP([], q, QQ), ANP([], q, QQ), + ANP([QQ(1, 1), QQ(0, 1)], q, QQ), ANP([QQ(17, 1), QQ(0, 1)], q, QQ)] assert dmp_lift(f, 0, QQ.algebraic_field(I)) == \ - [QQ(1),QQ(0),QQ(0),QQ(0),QQ(0),QQ(0),QQ(2),QQ(0),QQ(578), - QQ(0),QQ(0),QQ(0),QQ(1),QQ(0),QQ(-578),QQ(0),QQ(83521)] + [QQ(1), QQ(0), QQ(0), QQ(0), QQ(0), QQ(0), QQ(2), QQ(0), QQ(578), + QQ(0), QQ(0), QQ(0), QQ(1), QQ(0), QQ(-578), QQ(0), QQ(83521)] raises(DomainError, lambda: dmp_lift([EX(1), EX(2)], 0, EX)) + def test_dup_sign_variations(): assert dup_sign_variations([], ZZ) == 0 - assert dup_sign_variations([1,0], ZZ) == 0 - assert dup_sign_variations([1,0,2], ZZ) == 0 - assert dup_sign_variations([1,0,3,0], ZZ) == 0 - assert dup_sign_variations([1,0,4,0,5], ZZ) == 0 - - assert dup_sign_variations([-1,0,2], ZZ) == 1 - assert dup_sign_variations([-1,0,3,0], ZZ) == 1 - assert dup_sign_variations([-1,0,4,0,5], ZZ) == 1 - - assert dup_sign_variations([-1,-4,-5], ZZ) == 0 - assert dup_sign_variations([ 1,-4,-5], ZZ) == 1 - assert dup_sign_variations([ 1, 4,-5], ZZ) == 1 - assert dup_sign_variations([ 1,-4, 5], ZZ) == 2 - assert dup_sign_variations([-1, 4,-5], ZZ) == 2 + assert dup_sign_variations([1, 0], ZZ) == 0 + assert dup_sign_variations([1, 0, 2], ZZ) == 0 + assert dup_sign_variations([1, 0, 3, 0], ZZ) == 0 + assert dup_sign_variations([1, 0, 4, 0, 5], ZZ) == 0 + + assert dup_sign_variations([-1, 0, 2], ZZ) == 1 + assert dup_sign_variations([-1, 0, 3, 0], ZZ) == 1 + assert dup_sign_variations([-1, 0, 4, 0, 5], ZZ) == 1 + + assert dup_sign_variations([-1, -4, -5], ZZ) == 0 + assert dup_sign_variations([ 1, -4, -5], ZZ) == 1 + assert dup_sign_variations([ 1, 4, -5], ZZ) == 1 + assert dup_sign_variations([ 1, -4, 5], ZZ) == 2 + assert dup_sign_variations([-1, 4, -5], ZZ) == 2 assert dup_sign_variations([-1, 4, 5], ZZ) == 1 - assert dup_sign_variations([-1,-4, 5], ZZ) == 1 + assert dup_sign_variations([-1, -4, 5], ZZ) == 1 assert dup_sign_variations([ 1, 4, 5], ZZ) == 0 - assert dup_sign_variations([-1,0,-4,0,-5], ZZ) == 0 - assert dup_sign_variations([ 1,0,-4,0,-5], ZZ) == 1 - assert dup_sign_variations([ 1,0, 4,0,-5], ZZ) == 1 - assert dup_sign_variations([ 1,0,-4,0, 5], ZZ) == 2 - assert dup_sign_variations([-1,0, 4,0,-5], ZZ) == 2 - assert dup_sign_variations([-1,0, 4,0, 5], ZZ) == 1 - assert dup_sign_variations([-1,0,-4,0, 5], ZZ) == 1 - assert dup_sign_variations([ 1,0, 4,0, 5], ZZ) == 0 + assert dup_sign_variations([-1, 0, -4, 0, -5], ZZ) == 0 + assert dup_sign_variations([ 1, 0, -4, 0, -5], ZZ) == 1 + assert dup_sign_variations([ 1, 0, 4, 0, -5], ZZ) == 1 + assert dup_sign_variations([ 1, 0, -4, 0, 5], ZZ) == 2 + assert dup_sign_variations([-1, 0, 4, 0, -5], ZZ) == 2 + assert dup_sign_variations([-1, 0, 4, 0, 5], ZZ) == 1 + assert dup_sign_variations([-1, 0, -4, 0, 5], ZZ) == 1 + assert dup_sign_variations([ 1, 0, 4, 0, 5], ZZ) == 0 + def test_dup_clear_denoms(): assert dup_clear_denoms([], QQ, ZZ) == (ZZ(1), []) @@ -534,16 +617,25 @@ assert dup_clear_denoms([QQ(1)], QQ, ZZ) == (ZZ(1), [QQ(1)]) assert dup_clear_denoms([QQ(7)], QQ, ZZ) == (ZZ(1), [QQ(7)]) - assert dup_clear_denoms([QQ(7,3)], QQ) == (ZZ(3), [QQ(7)]) - assert dup_clear_denoms([QQ(7,3)], QQ, ZZ) == (ZZ(3), [QQ(7)]) + assert dup_clear_denoms([QQ(7, 3)], QQ) == (ZZ(3), [QQ(7)]) + assert dup_clear_denoms([QQ(7, 3)], QQ, ZZ) == (ZZ(3), [QQ(7)]) - assert dup_clear_denoms([QQ(3),QQ(1),QQ(0)], QQ, ZZ) == (ZZ(1), [QQ(3),QQ(1),QQ(0)]) - assert dup_clear_denoms([QQ(1),QQ(1,2),QQ(0)], QQ, ZZ) == (ZZ(2), [QQ(2),QQ(1),QQ(0)]) + assert dup_clear_denoms( + [QQ(3), QQ(1), QQ(0)], QQ, ZZ) == (ZZ(1), [QQ(3), QQ(1), QQ(0)]) + assert dup_clear_denoms( + [QQ(1), QQ(1, 2), QQ(0)], QQ, ZZ) == (ZZ(2), [QQ(2), QQ(1), QQ(0)]) + + assert dup_clear_denoms([QQ(3), QQ( + 1), QQ(0)], QQ, ZZ, convert=True) == (ZZ(1), [ZZ(3), ZZ(1), ZZ(0)]) + assert dup_clear_denoms([QQ(1), QQ( + 1, 2), QQ(0)], QQ, ZZ, convert=True) == (ZZ(2), [ZZ(2), ZZ(1), ZZ(0)]) - assert dup_clear_denoms([QQ(3),QQ(1),QQ(0)], QQ, ZZ, convert=True) == (ZZ(1), [ZZ(3),ZZ(1),ZZ(0)]) - assert dup_clear_denoms([QQ(1),QQ(1,2),QQ(0)], QQ, ZZ, convert=True) == (ZZ(2), [ZZ(2),ZZ(1),ZZ(0)]) + assert dup_clear_denoms( + [EX(S(3)/2), EX(S(9)/4)], EX) == (EX(4), [EX(6), EX(9)]) + + assert dup_clear_denoms([EX(7)], EX) == (EX(1), [EX(7)]) + assert dup_clear_denoms([EX(sin(x)/x), EX(0)], EX) == (EX(x), [EX(sin(x)), EX(0)]) - raises(DomainError, lambda: dup_clear_denoms([EX(7)], EX)) def test_dmp_clear_denoms(): assert dmp_clear_denoms([[]], 1, QQ, ZZ) == (ZZ(1), [[]]) @@ -551,16 +643,25 @@ assert dmp_clear_denoms([[QQ(1)]], 1, QQ, ZZ) == (ZZ(1), [[QQ(1)]]) assert dmp_clear_denoms([[QQ(7)]], 1, QQ, ZZ) == (ZZ(1), [[QQ(7)]]) - assert dmp_clear_denoms([[QQ(7,3)]], 1, QQ) == (ZZ(3), [[QQ(7)]]) - assert dmp_clear_denoms([[QQ(7,3)]], 1, QQ, ZZ) == (ZZ(3), [[QQ(7)]]) - - assert dmp_clear_denoms([[QQ(3)],[QQ(1)],[]], 1, QQ, ZZ) == (ZZ(1), [[QQ(3)],[QQ(1)],[]]) - assert dmp_clear_denoms([[QQ(1)],[QQ(1,2)],[]], 1, QQ, ZZ) == (ZZ(2), [[QQ(2)],[QQ(1)],[]]) - - assert dmp_clear_denoms([QQ(3),QQ(1),QQ(0)], 0, QQ, ZZ, convert=True) == (ZZ(1), [ZZ(3),ZZ(1),ZZ(0)]) - assert dmp_clear_denoms([QQ(1),QQ(1,2),QQ(0)], 0, QQ, ZZ, convert=True) == (ZZ(2), [ZZ(2),ZZ(1),ZZ(0)]) - - assert dmp_clear_denoms([[QQ(3)],[QQ(1)],[]], 1, QQ, ZZ, convert=True) == (ZZ(1), [[QQ(3)],[QQ(1)],[]]) - assert dmp_clear_denoms([[QQ(1)],[QQ(1,2)],[]], 1, QQ, ZZ, convert=True) == (ZZ(2), [[QQ(2)],[QQ(1)],[]]) + assert dmp_clear_denoms([[QQ(7, 3)]], 1, QQ) == (ZZ(3), [[QQ(7)]]) + assert dmp_clear_denoms([[QQ(7, 3)]], 1, QQ, ZZ) == (ZZ(3), [[QQ(7)]]) - raises(DomainError, lambda: dmp_clear_denoms([[EX(7)]], 1, EX)) + assert dmp_clear_denoms( + [[QQ(3)], [QQ(1)], []], 1, QQ, ZZ) == (ZZ(1), [[QQ(3)], [QQ(1)], []]) + assert dmp_clear_denoms([[QQ( + 1)], [QQ(1, 2)], []], 1, QQ, ZZ) == (ZZ(2), [[QQ(2)], [QQ(1)], []]) + + assert dmp_clear_denoms([QQ(3), QQ( + 1), QQ(0)], 0, QQ, ZZ, convert=True) == (ZZ(1), [ZZ(3), ZZ(1), ZZ(0)]) + assert dmp_clear_denoms([QQ(1), QQ(1, 2), QQ( + 0)], 0, QQ, ZZ, convert=True) == (ZZ(2), [ZZ(2), ZZ(1), ZZ(0)]) + + assert dmp_clear_denoms([[QQ(3)], [QQ( + 1)], []], 1, QQ, ZZ, convert=True) == (ZZ(1), [[QQ(3)], [QQ(1)], []]) + assert dmp_clear_denoms([[QQ(1)], [QQ(1, 2)], []], 1, QQ, ZZ, + convert=True) == (ZZ(2), [[QQ(2)], [QQ(1)], []]) + + assert dmp_clear_denoms( + [[EX(S(3)/2)], [EX(S(9)/4)]], 1, EX) == (EX(4), [[EX(6)], [EX(9)]]) + assert dmp_clear_denoms([[EX(7)]], 1, EX) == (EX(1), [[EX(7)]]) + assert dmp_clear_denoms([[EX(sin(x)/x), EX(0)]], 1, EX) == (EX(x), [[EX(sin(x)), EX(0)]]) diff -Nru python3-sympy-0.7.2/sympy/polys/tests/test_distributedmodules.py python3-sympy-0.7.3/sympy/polys/tests/test_distributedmodules.py --- python3-sympy-0.7.2/sympy/polys/tests/test_distributedmodules.py 2012-10-17 03:02:22.000000000 +0000 +++ python3-sympy-0.7.3/sympy/polys/tests/test_distributedmodules.py 2013-07-13 17:53:32.000000000 +0000 @@ -16,15 +16,19 @@ from sympy.abc import x, y, z + def test_sdm_monomial_mul(): assert sdm_monomial_mul((1, 1, 0), (1, 3)) == (1, 2, 3) + def test_sdm_monomial_deg(): assert sdm_monomial_deg((5, 2, 1)) == 3 + def test_sdm_monomial_lcm(): assert sdm_monomial_lcm((1, 2, 3), (1, 5, 0)) == (1, 5, 3) + def test_sdm_monomial_divides(): assert sdm_monomial_divides((1, 0, 0), (1, 0, 0)) is True assert sdm_monomial_divides((1, 0, 0), (1, 2, 1)) is True @@ -34,9 +38,11 @@ assert sdm_monomial_divides((1, 1, 0), (1, 0, 0)) is False assert sdm_monomial_divides((5, 1, 2), (5, 0, 1)) is False + def test_sdm_LC(): assert sdm_LC([((1, 2, 3), QQ(5))], QQ) == QQ(5) + def test_sdm_from_dict(): dic = {(1, 2, 1, 1): QQ(1), (1, 1, 2, 1): QQ(1), (1, 0, 2, 1): QQ(1), (1, 0, 0, 3): QQ(1), (1, 1, 1, 0): QQ(1)} @@ -46,6 +52,7 @@ # TODO test to_dict? + def test_sdm_add(): assert sdm_add([((1, 1, 1), QQ(1))], [((2, 0, 0), QQ(1))], lex, QQ) == \ [((2, 0, 0), QQ(1)), ((1, 1, 1), QQ(1))] @@ -55,14 +62,17 @@ assert sdm_add([((1, 0, 1), QQ(1))], [((1, 1, 0), QQ(1))], lex, QQ) == \ [((1, 1, 0), QQ(1)), ((1, 0, 1), QQ(1))] + def test_sdm_LM(): dic = {(1, 2, 3): QQ(1), (4, 0, 0): QQ(1), (4, 0, 1): QQ(1)} assert sdm_LM(sdm_from_dict(dic, lex)) == (4, 0, 1) + def test_sdm_LT(): dic = {(1, 2, 3): QQ(1), (4, 0, 0): QQ(2), (4, 0, 1): QQ(3)} assert sdm_LT(sdm_from_dict(dic, lex)) == ((4, 0, 1), QQ(3)) + def test_sdm_mul_term(): assert sdm_mul_term([((1, 0, 0), QQ(1))], ((0, 0), QQ(0)), lex, QQ) == [] assert sdm_mul_term([], ((1, 0), QQ(1)), lex, QQ) == [] @@ -72,12 +82,15 @@ assert sdm_mul_term(f, ((1, 1), QQ(2)), lex, QQ) == \ [((2, 1, 2), QQ(8)), ((1, 2, 1), QQ(6))] + def test_sdm_zero(): assert sdm_zero() == [] + def test_sdm_deg(): assert sdm_deg([((1, 2, 3), 1), ((10, 0, 1), 1), ((2, 3, 4), 4)]) == 7 + def test_sdm_spoly(): f = [((2, 1, 1), QQ(1)), ((1, 0, 1), QQ(1))] g = [((2, 3, 0), QQ(1))] @@ -85,14 +98,16 @@ assert sdm_spoly(f, h, lex, QQ) == [] assert sdm_spoly(f, g, lex, QQ) == [((1, 2, 1), QQ(1))] + def test_sdm_ecart(): assert sdm_ecart([((1, 2, 3), 1), ((1, 0, 1), 1)]) == 0 assert sdm_ecart([((2, 2, 1), 1), ((1, 5, 1), 1)]) == 3 + def test_sdm_nf_mora(): f = sdm_from_dict({(1, 2, 1, 1): QQ(1), (1, 1, 2, 1): QQ(1), (1, 0, 2, 1): QQ(1), (1, 0, 0, 3): QQ(1), (1, 1, 1, 0): QQ(1)}, - grlex) + grlex) f1 = sdm_from_dict({(1, 1, 1, 0): QQ(1), (1, 0, 2, 0): QQ(1), (1, 0, 0, 0): QQ(-1)}, grlex) f2 = sdm_from_dict({(1, 1, 1, 0): QQ(1)}, grlex) @@ -111,21 +126,25 @@ f1 = sdm_from_vector([x, y, 1], lex, QQ, gens=[x, y, z]) f2 = sdm_from_vector([x*y, z, z**2], lex, QQ, gens=[x, y, z]) assert sdm_nf_mora(f, [f1, f2], lex, QQ) == \ - sdm_nf_mora(f, [f2, f1], lex, QQ) == \ + sdm_nf_mora(f, [f2, f1], lex, QQ) == \ [((1, 0, 1, 1), QQ(1)), ((1, 0, 0, 1), QQ(-1)), ((0, 1, 1, 0), QQ(-1)), ((0, 1, 0, 1), QQ(1))] + def test_conversion(): f = [x**2 + y**2, 2*z] g = [((1, 0, 0, 1), QQ(2)), ((0, 2, 0, 0), QQ(1)), ((0, 0, 2, 0), QQ(1))] assert sdm_to_vector(g, [x, y, z], QQ) == f assert sdm_from_vector(f, lex, QQ) == g - assert sdm_from_vector([x, 1], lex, QQ) == [((1, 0), QQ(1)), ((0, 1), QQ(1))] + assert sdm_from_vector( + [x, 1], lex, QQ) == [((1, 0), QQ(1)), ((0, 1), QQ(1))] assert sdm_to_vector([((1, 1, 0, 0), 1)], [x, y, z], QQ, n=3) == [0, x, 0] assert sdm_from_vector([0, 0], lex, QQ, gens=[x, y]) == sdm_zero() + def test_nontrivial(): gens = [x, y, z] + def contains(I, f): S = [sdm_from_vector([g], lex, QQ, gens=gens) for g in I] G = sdm_groebner(S, sdm_nf_mora, lex, QQ) @@ -137,25 +156,29 @@ assert not contains([x, y], 1) assert not contains([x, y], z) assert contains([x**2 + y, x**2 + x], x - y) - assert not contains([x+y+z, x*y+x*z+y*z, x*y*z], x**2) - assert contains([x+y+z, x*y+x*z+y*z, x*y*z], x**3) - assert contains([x+y+z, x*y+x*z+y*z, x*y*z], x**4) - assert not contains([x+y+z, x*y+x*z+y*z, x*y*z], x*y**2) - assert contains([x+y+z, x*y+x*z+y*z, x*y*z], x**4 + y**3 + 2*z*y*x) - assert contains([x+y+z, x*y+x*z+y*z, x*y*z], x*y*z) - assert contains([x, 1+x+y, 5-7*y], 1) - assert contains([x**3+y**3, y**3+z**3, z**3+x**3, x**2*y + x**2*z + y**2*z], - x**3) - assert not contains([x**3+y**3, y**3+z**3, z**3+x**3, x**2*y + x**2*z + y**2*z], - x**2 + y**2) + assert not contains([x + y + z, x*y + x*z + y*z, x*y*z], x**2) + assert contains([x + y + z, x*y + x*z + y*z, x*y*z], x**3) + assert contains([x + y + z, x*y + x*z + y*z, x*y*z], x**4) + assert not contains([x + y + z, x*y + x*z + y*z, x*y*z], x*y**2) + assert contains([x + y + z, x*y + x*z + y*z, x*y*z], x**4 + y**3 + 2*z*y*x) + assert contains([x + y + z, x*y + x*z + y*z, x*y*z], x*y*z) + assert contains([x, 1 + x + y, 5 - 7*y], 1) + assert contains( + [x**3 + y**3, y**3 + z**3, z**3 + x**3, x**2*y + x**2*z + y**2*z], + x**3) + assert not contains( + [x**3 + y**3, y**3 + z**3, z**3 + x**3, x**2*y + x**2*z + y**2*z], + x**2 + y**2) # compare local order - assert not contains([x*(1+x+y), y*(1+z)], x) - assert not contains([x*(1+x+y), y*(1+z)], x + y) + assert not contains([x*(1 + x + y), y*(1 + z)], x) + assert not contains([x*(1 + x + y), y*(1 + z)], x + y) + def test_local(): igrlex = InverseOrder(grlex) gens = [x, y, z] + def contains(I, f): S = [sdm_from_vector([g], igrlex, QQ, gens=gens) for g in I] G = sdm_groebner(S, sdm_nf_mora, igrlex, QQ) @@ -166,9 +189,10 @@ assert not contains([x, y], 1) assert not contains([x, y], z) assert contains([x**2 + y, x**2 + x], x - y) - assert not contains([x+y+z, x*y+x*z+y*z, x*y*z], x**2) - assert contains([x*(1+x+y), y*(1+z)], x) - assert contains([x*(1+x+y), y*(1+z)], x + y) + assert not contains([x + y + z, x*y + x*z + y*z, x*y*z], x**2) + assert contains([x*(1 + x + y), y*(1 + z)], x) + assert contains([x*(1 + x + y), y*(1 + z)], x + y) + def test_uncovered_line(): gens = [x, y] @@ -179,6 +203,7 @@ assert sdm_spoly(f1, f2, lex, QQ) == sdm_zero() assert sdm_spoly(f3, f2, lex, QQ) == sdm_zero() + def test_chain_criterion(): gens = [x] f1 = sdm_from_vector([1, x], grlex, QQ, gens=gens) diff -Nru python3-sympy-0.7.2/sympy/polys/tests/test_distributedpolys.py python3-sympy-0.7.3/sympy/polys/tests/test_distributedpolys.py --- python3-sympy-0.7.2/sympy/polys/tests/test_distributedpolys.py 2012-10-17 03:02:22.000000000 +0000 +++ python3-sympy-0.7.3/sympy/polys/tests/test_distributedpolys.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,255 +0,0 @@ -"""Tests for sparse distributed polynomials. """ - -from sympy.polys.distributedpolys import ( - sdp_LC, sdp_LM, sdp_LT, sdp_del_LT, - sdp_coeffs, sdp_monoms, - sdp_sort, sdp_strip, sdp_normal, - sdp_from_dict, sdp_to_dict, - sdp_indep_p, sdp_one_p, sdp_one, sdp_term_p, - sdp_abs, sdp_neg, - sdp_add_term, sdp_sub_term, sdp_mul_term, - sdp_add, sdp_sub, sdp_mul, sdp_sqr, sdp_pow, - sdp_monic, sdp_content, sdp_primitive, - _term_rr_div, _term_ff_div, - sdp_div, sdp_quo, sdp_rem, - sdp_lcm, sdp_gcd, -) - -from sympy.polys.monomialtools import ( - lex, grlex, grevlex, -) - -from sympy.polys.polyerrors import ( - ExactQuotientFailed, DomainError, -) - -from sympy.polys.domains import ZZ, QQ - -from sympy import S, Symbol, symbols - -from sympy.utilities.pytest import raises, skip, XFAIL - -def test_sdp_LC(): - assert sdp_LC([], QQ) == QQ(0) - assert sdp_LC([((1,0), QQ(1,2))], QQ) == QQ(1,2) - assert sdp_LC([((1,1), QQ(1,4)), ((1,0), QQ(1,2))], QQ) == QQ(1,4) - -def test_sdp_LM(): - assert sdp_LM([], 1) == (0, 0) - assert sdp_LM([((1,0), QQ(1,2))], 1) == (1, 0) - assert sdp_LM([((1,1), QQ(1,4)), ((1,0), QQ(1,2))], 1) == (1, 1) - -def test_sdp_LT(): - assert sdp_LT([], 1, QQ) == ((0, 0), QQ(0)) - assert sdp_LT([((1,0), QQ(1,2))], 1, QQ) == ((1, 0), QQ(1,2)) - assert sdp_LT([((1,1), QQ(1,4)), ((1,0), QQ(1,2))], 1, QQ) == ((1, 1), QQ(1,4)) - -def test_sdp_del_LT(): - assert sdp_del_LT([]) == [] - assert sdp_del_LT([((1,0), QQ(1,2))]) == [] - assert sdp_del_LT([((1,1), QQ(1,4)), ((1,0), QQ(1,2))]) == [((1,0), QQ(1,2))] - -def test_sdp_coeffs(): - assert sdp_coeffs([]) == [] - assert sdp_coeffs([((1,0), QQ(1,2))]) == [QQ(1,2)] - assert sdp_coeffs([((1,1), QQ(1,4)), ((1,0), QQ(1,2))]) == [QQ(1,4), QQ(1,2)] - -def test_sdp_monoms(): - assert sdp_monoms([]) == [] - assert sdp_monoms([((1,0), QQ(1,2))]) == [(1,0)] - assert sdp_monoms([((1,1), QQ(1,4)), ((1,0), QQ(1,2))]) == [(1,1), (1,0)] - -def test_sdp_sort(): - pass - -def test_sdp_strip(): - assert sdp_strip([((2,2), 0), ((1,1), 1), ((0,0), 0)]) == [((1,1), 1)] - -def test_sdp_normal(): - pass - -def test_sdp_from_dict(): - pass - -def test_sdp_indep_p(): - pass - -def test_sdp_one_p(): - pass - -def test_sdp_one(): - pass - -def test_sdp_term_p(): - pass - -def test_sdp_abs(): - pass - -def test_sdp_neg(): - pass - -def test_sdp_add_term(): - pass - -def test_sdp_sub_term(): - pass - -def test_sdp_mul_term(): - pass - -def test_sdp_add(): - pass - -def test_sdp_sub(): - pass - -def test_sdp_mul(): - pass - -def test_sdp_sqr(): - pass - -def test_sdp_pow(): - f = sdp_from_dict({(1,): 2, (0,): 3}, grlex) - - assert sdp_pow(f, 0, 0, grlex, ZZ) == sdp_one(0, ZZ) - assert sdp_pow(f, 1, 0, grlex, ZZ) == f - - assert sdp_pow(f, 2, 0, grlex, ZZ) == \ - sdp_from_dict({(2,): 4, (1,): 12, (0,): 9}, grlex) - assert sdp_pow(f, 3, 0, grlex, ZZ) == \ - sdp_from_dict({(3,): 8, (2,): 36, (1,): 54, (0,): 27}, grlex) - assert sdp_pow(f, 4, 0, grlex, ZZ) == \ - sdp_from_dict({(4,): 16, (3,): 96, (2,): 216, (1,): 216, (0,): 81}, grlex) - assert sdp_pow(f, 5, 0, grlex, ZZ) == \ - sdp_from_dict({(5,): 32, (4,): 240, (3,): 720, (2,): 1080, (1,): 810, (0,): 243}, grlex) - - f = sdp_from_dict({(3,1,0): 1, (1,2,0): -2, (0,0,1): -3, (0,0,0): 1}, grlex) - g = sdp_from_dict({(6,2,0): 1, (4,3,0): -4, (2,4,0): 4, (3,1,1): -6, (3,1,0): 2, - (1,2,1): 12, (1,2,0): -4, (0,0,2): 9, (0,0,1): -6, (0,0,0): 1}, grlex) - - assert sdp_pow(f, 2, 2, grlex, ZZ) == g - - raises(ValueError, lambda: sdp_pow(f, -2, 2, grlex, ZZ)) - -def test_sdp_monic(): - pass - -def test_sdp_content(): - pass - -def test_sdp_primitive(): - pass - -def test_sdp_div(): - f = sdp_from_dict({(2,1): 4, (1,1): -2, (1,0): 4, (0,1): -2, (0,0): 8}, grlex) - - assert sdp_div(f, [sdp_from_dict({(0,0): 2}, grlex)], 1, grlex, ZZ) == \ - ([sdp_from_dict({(2,1): 2, (1,1): -1, (1,0): 2, (0,1): -1, (0,0): 4}, grlex)], []) - - assert sdp_div(f, [sdp_from_dict({(0,1): 2}, grlex)], 1, grlex, ZZ) == \ - ([sdp_from_dict({(2,0): 2, (1,0): -1, (0,0): -1}, grlex)], - sdp_from_dict({(1,0): 4, (0,0): 8}, grlex)) - - f = sdp_from_dict({(1,0): 1, (0,0): -1}, grlex) - g = sdp_from_dict({(0,1): 1, (0,0): -1}, grlex) - - assert sdp_div(f, [g], 1, grlex, ZZ) == ([[]], f) - - f = sdp_from_dict({(3,): 1, (2,): -12, (0,): -42}, grlex) - g = sdp_from_dict({(1,): 1, (0,): -3}, grlex) - - q = sdp_from_dict({(2,): 1, (1,): -9, (0,): -27}, grlex) - r = sdp_from_dict({(0,): -123}, grlex) - - assert sdp_div(f, [g], 0, grlex, ZZ) == ([q], r) - - f = sdp_from_dict({(2,): QQ(1), (1,): QQ(2), (0,): QQ(2)}, grlex) - - g = sdp_from_dict({(0,): QQ(1)}, grlex) - h = sdp_from_dict({(0,): QQ(2)}, grlex) - - q = sdp_from_dict({(2,): QQ(1,2), (1,): QQ(1), (0,): QQ(1)}, grlex) - - assert sdp_div(f, [g], 0, grlex, QQ) == ([f], []) - assert sdp_div(f, [h], 0, grlex, QQ) == ([q], []) - - f = sdp_from_dict({(1,2): 1, (0,0): 1}, grlex) - G = [sdp_from_dict({(1,1): 1, (0,0): 1}, grlex), - sdp_from_dict({(0,1): 1, (0,0): 1}, grlex)] - - Q = [sdp_from_dict({(0,1): 1}, grlex), - sdp_from_dict({(0,0): -1}, grlex)] - r = sdp_from_dict({(0,0): 2}, grlex) - - assert sdp_div(f, G, 1, grlex, ZZ) == (Q, r) - - f = sdp_from_dict({(2,1): 1, (1,2): 1, (0,2): 1}, grlex) - - G = [sdp_from_dict({(1,1): 1, (0,0): -1}, grlex), - sdp_from_dict({(0,2): 1, (0,0): -1}, grlex)] - - Q = [sdp_from_dict({(1,0): 1, (0,1): 1}, grlex), - sdp_from_dict({(0,0): 1}, grlex)] - r = sdp_from_dict({(1,0): 1, (0,1): 1, (0,0): 1}, grlex) - - assert sdp_div(f, G, 1, grlex, ZZ) == (Q, r) - - G = [sdp_from_dict({(0,2): 1, (0,0): -1}, grlex), - sdp_from_dict({(1,1): 1, (0,0): -1}, grlex)] - - Q = [sdp_from_dict({(1,0): 1, (0,0): 1}, grlex), - sdp_from_dict({(1,0): 1}, grlex)] - r = sdp_from_dict({(1,0): 2, (0,0): 1}, grlex) - - assert sdp_div(f, G, 1, grlex, ZZ) == (Q, r) - -def test_sdp_rem(): - f = sdp_from_dict({(2,1): 4, (1,1): -2, (1,0): 4, (0,1): -2, (0,0): 8}, grlex) - - assert sdp_rem(f, [sdp_from_dict({(0,0): 2}, grlex)], 1, grlex, ZZ) == [] - assert sdp_rem(f, [sdp_from_dict({(0,1): 2}, grlex)], 1, grlex, ZZ) == \ - sdp_from_dict({(1,0): 4, (0,0): 8}, grlex) - - f = sdp_from_dict({(1,0): 1, (0,0): -1}, grlex) - g = sdp_from_dict({(0,1): 1, (0,0): -1}, grlex) - - assert sdp_rem(f, [g], 1, grlex, ZZ) == f - - f = sdp_from_dict({(3,): 1, (2,): -12, (0,): -42}, grlex) - g = sdp_from_dict({(1,): 1, (0,): -3}, grlex) - - r = sdp_from_dict({(0,): -123}, grlex) - - assert sdp_rem(f, [g], 0, grlex, ZZ) == r - - f = sdp_from_dict({(1,2): 1, (0,0): 1}, grlex) - G = [sdp_from_dict({(1,1): 1, (0,0): 1}, grlex), - sdp_from_dict({(0,1): 1, (0,0): 1}, grlex)] - - r = sdp_from_dict({(0,0): 2}, grlex) - - assert sdp_rem(f, G, 1, grlex, ZZ) == r - - f = sdp_from_dict({(2,1): 1, (1,2): 1, (0,2): 1}, grlex) - - G = [sdp_from_dict({(1,1): 1, (0,0): -1}, grlex), - sdp_from_dict({(0,2): 1, (0,0): -1}, grlex)] - - r = sdp_from_dict({(1,0): 1, (0,1): 1, (0,0): 1}, grlex) - - assert sdp_rem(f, G, 1, grlex, ZZ) == r - - G = [sdp_from_dict({(0,2): 1, (0,0): -1}, grlex), - sdp_from_dict({(1,1): 1, (0,0): -1}, grlex)] - - r = sdp_from_dict({(1,0): 2, (0,0): 1}, grlex) - - assert sdp_rem(f, G, 1, grlex, ZZ) == r - -def test_sdp_lcm(): - pass - -def test_sdp_gcd(): - pass diff -Nru python3-sympy-0.7.2/sympy/polys/tests/test_domains.py python3-sympy-0.7.3/sympy/polys/tests/test_domains.py --- python3-sympy-0.7.2/sympy/polys/tests/test_domains.py 2012-10-17 03:02:22.000000000 +0000 +++ python3-sympy-0.7.3/sympy/polys/tests/test_domains.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,784 +0,0 @@ -"""Tests for classes defining properties of ground domains, e.g. ZZ, QQ, -ZZ[x] ... """ - -from sympy import S, sqrt, sin, oo, nan, Poly, Integer, Rational -from sympy.abc import x, y, z - -from sympy.polys.domains import ( - ZZ, QQ, RR, FF, PythonRationalType as Q, ZZ_sympy, QQ_sympy, - RR_mpmath, RR_sympy, PolynomialRing, FractionField, EX) - -from sympy.polys.domains.modularinteger import ModularIntegerFactory - -from sympy.polys.polyerrors import ( - UnificationFailed, - GeneratorsNeeded, - GeneratorsError, - CoercionFailed, - NotInvertible, - DomainError) - -from sympy.polys.polyclasses import DMP, DMF -from sympy.utilities.pytest import raises - -ALG = QQ.algebraic_field(sqrt(2) + sqrt(3)) - -def test_Domain__unify(): - assert ZZ.unify(ZZ) == ZZ - assert QQ.unify(QQ) == QQ - - assert ZZ.unify(QQ) == QQ - assert QQ.unify(ZZ) == QQ - - assert EX.unify(EX) == EX - - assert ZZ.unify(EX) == EX - assert QQ.unify(EX) == EX - assert EX.unify(ZZ) == EX - assert EX.unify(QQ) == EX - - assert ZZ.poly_ring('x').unify(EX) == EX - assert ZZ.frac_field('x').unify(EX) == EX - assert EX.unify(ZZ.poly_ring('x')) == EX - assert EX.unify(ZZ.frac_field('x')) == EX - - assert ZZ.poly_ring('x','y').unify(EX) == EX - assert ZZ.frac_field('x','y').unify(EX) == EX - assert EX.unify(ZZ.poly_ring('x','y')) == EX - assert EX.unify(ZZ.frac_field('x','y')) == EX - - assert QQ.poly_ring('x').unify(EX) == EX - assert QQ.frac_field('x').unify(EX) == EX - assert EX.unify(QQ.poly_ring('x')) == EX - assert EX.unify(QQ.frac_field('x')) == EX - - assert QQ.poly_ring('x','y').unify(EX) == EX - assert QQ.frac_field('x','y').unify(EX) == EX - assert EX.unify(QQ.poly_ring('x','y')) == EX - assert EX.unify(QQ.frac_field('x','y')) == EX - - assert ZZ.poly_ring('x').unify(ZZ) == ZZ.poly_ring('x') - assert ZZ.poly_ring('x').unify(QQ) == QQ.poly_ring('x') - assert QQ.poly_ring('x').unify(ZZ) == QQ.poly_ring('x') - assert QQ.poly_ring('x').unify(QQ) == QQ.poly_ring('x') - - assert ZZ.unify(ZZ.poly_ring('x')) == ZZ.poly_ring('x') - assert QQ.unify(ZZ.poly_ring('x')) == QQ.poly_ring('x') - assert ZZ.unify(QQ.poly_ring('x')) == QQ.poly_ring('x') - assert QQ.unify(QQ.poly_ring('x')) == QQ.poly_ring('x') - - assert ZZ.poly_ring('x','y').unify(ZZ) == ZZ.poly_ring('x','y') - assert ZZ.poly_ring('x','y').unify(QQ) == QQ.poly_ring('x','y') - assert QQ.poly_ring('x','y').unify(ZZ) == QQ.poly_ring('x','y') - assert QQ.poly_ring('x','y').unify(QQ) == QQ.poly_ring('x','y') - - assert ZZ.unify(ZZ.poly_ring('x','y')) == ZZ.poly_ring('x','y') - assert QQ.unify(ZZ.poly_ring('x','y')) == QQ.poly_ring('x','y') - assert ZZ.unify(QQ.poly_ring('x','y')) == QQ.poly_ring('x','y') - assert QQ.unify(QQ.poly_ring('x','y')) == QQ.poly_ring('x','y') - - assert ZZ.frac_field('x').unify(ZZ) == ZZ.frac_field('x') - assert ZZ.frac_field('x').unify(QQ) == EX # QQ.frac_field('x') - assert QQ.frac_field('x').unify(ZZ) == EX # QQ.frac_field('x') - assert QQ.frac_field('x').unify(QQ) == QQ.frac_field('x') - - assert ZZ.unify(ZZ.frac_field('x')) == ZZ.frac_field('x') - assert QQ.unify(ZZ.frac_field('x')) == EX # QQ.frac_field('x') - assert ZZ.unify(QQ.frac_field('x')) == EX # QQ.frac_field('x') - assert QQ.unify(QQ.frac_field('x')) == QQ.frac_field('x') - - assert ZZ.frac_field('x','y').unify(ZZ) == ZZ.frac_field('x','y') - assert ZZ.frac_field('x','y').unify(QQ) == EX # QQ.frac_field('x','y') - assert QQ.frac_field('x','y').unify(ZZ) == EX # QQ.frac_field('x','y') - assert QQ.frac_field('x','y').unify(QQ) == QQ.frac_field('x','y') - - assert ZZ.unify(ZZ.frac_field('x','y')) == ZZ.frac_field('x','y') - assert QQ.unify(ZZ.frac_field('x','y')) == EX # QQ.frac_field('x','y') - assert ZZ.unify(QQ.frac_field('x','y')) == EX # QQ.frac_field('x','y') - assert QQ.unify(QQ.frac_field('x','y')) == QQ.frac_field('x','y') - - assert ZZ.poly_ring('x').unify(ZZ.poly_ring('x')) == ZZ.poly_ring('x') - assert ZZ.poly_ring('x').unify(QQ.poly_ring('x')) == QQ.poly_ring('x') - assert QQ.poly_ring('x').unify(ZZ.poly_ring('x')) == QQ.poly_ring('x') - assert QQ.poly_ring('x').unify(QQ.poly_ring('x')) == QQ.poly_ring('x') - - assert ZZ.poly_ring('x','y').unify(ZZ.poly_ring('x')) == ZZ.poly_ring('x','y') - assert ZZ.poly_ring('x','y').unify(QQ.poly_ring('x')) == QQ.poly_ring('x','y') - assert QQ.poly_ring('x','y').unify(ZZ.poly_ring('x')) == QQ.poly_ring('x','y') - assert QQ.poly_ring('x','y').unify(QQ.poly_ring('x')) == QQ.poly_ring('x','y') - - assert ZZ.poly_ring('x').unify(ZZ.poly_ring('x','y')) == ZZ.poly_ring('x','y') - assert ZZ.poly_ring('x').unify(QQ.poly_ring('x','y')) == QQ.poly_ring('x','y') - assert QQ.poly_ring('x').unify(ZZ.poly_ring('x','y')) == QQ.poly_ring('x','y') - assert QQ.poly_ring('x').unify(QQ.poly_ring('x','y')) == QQ.poly_ring('x','y') - - assert ZZ.poly_ring('x','y').unify(ZZ.poly_ring('x','z')) == ZZ.poly_ring('x','y','z') - assert ZZ.poly_ring('x','y').unify(QQ.poly_ring('x','z')) == QQ.poly_ring('x','y','z') - assert QQ.poly_ring('x','y').unify(ZZ.poly_ring('x','z')) == QQ.poly_ring('x','y','z') - assert QQ.poly_ring('x','y').unify(QQ.poly_ring('x','z')) == QQ.poly_ring('x','y','z') - - assert ZZ.frac_field('x').unify(ZZ.frac_field('x')) == ZZ.frac_field('x') - assert ZZ.frac_field('x').unify(QQ.frac_field('x')) == QQ.frac_field('x') - assert QQ.frac_field('x').unify(ZZ.frac_field('x')) == QQ.frac_field('x') - assert QQ.frac_field('x').unify(QQ.frac_field('x')) == QQ.frac_field('x') - - assert ZZ.frac_field('x','y').unify(ZZ.frac_field('x')) == ZZ.frac_field('x','y') - assert ZZ.frac_field('x','y').unify(QQ.frac_field('x')) == QQ.frac_field('x','y') - assert QQ.frac_field('x','y').unify(ZZ.frac_field('x')) == QQ.frac_field('x','y') - assert QQ.frac_field('x','y').unify(QQ.frac_field('x')) == QQ.frac_field('x','y') - - assert ZZ.frac_field('x').unify(ZZ.frac_field('x','y')) == ZZ.frac_field('x','y') - assert ZZ.frac_field('x').unify(QQ.frac_field('x','y')) == QQ.frac_field('x','y') - assert QQ.frac_field('x').unify(ZZ.frac_field('x','y')) == QQ.frac_field('x','y') - assert QQ.frac_field('x').unify(QQ.frac_field('x','y')) == QQ.frac_field('x','y') - - assert ZZ.frac_field('x','y').unify(ZZ.frac_field('x','z')) == ZZ.frac_field('x','y','z') - assert ZZ.frac_field('x','y').unify(QQ.frac_field('x','z')) == QQ.frac_field('x','y','z') - assert QQ.frac_field('x','y').unify(ZZ.frac_field('x','z')) == QQ.frac_field('x','y','z') - assert QQ.frac_field('x','y').unify(QQ.frac_field('x','z')) == QQ.frac_field('x','y','z') - - assert ZZ.poly_ring('x').unify(ZZ.frac_field('x')) == ZZ.frac_field('x') - assert ZZ.poly_ring('x').unify(QQ.frac_field('x')) == EX # QQ.frac_field('x') - assert QQ.poly_ring('x').unify(ZZ.frac_field('x')) == EX # QQ.frac_field('x') - assert QQ.poly_ring('x').unify(QQ.frac_field('x')) == QQ.frac_field('x') - - assert ZZ.poly_ring('x','y').unify(ZZ.frac_field('x')) == ZZ.frac_field('x','y') - assert ZZ.poly_ring('x','y').unify(QQ.frac_field('x')) == EX # QQ.frac_field('x','y') - assert QQ.poly_ring('x','y').unify(ZZ.frac_field('x')) == EX # QQ.frac_field('x','y') - assert QQ.poly_ring('x','y').unify(QQ.frac_field('x')) == QQ.frac_field('x','y') - - assert ZZ.poly_ring('x').unify(ZZ.frac_field('x','y')) == ZZ.frac_field('x','y') - assert ZZ.poly_ring('x').unify(QQ.frac_field('x','y')) == EX # QQ.frac_field('x','y') - assert QQ.poly_ring('x').unify(ZZ.frac_field('x','y')) == EX # QQ.frac_field('x','y') - assert QQ.poly_ring('x').unify(QQ.frac_field('x','y')) == QQ.frac_field('x','y') - - assert ZZ.poly_ring('x','y').unify(ZZ.frac_field('x','z')) == ZZ.frac_field('x','y','z') - assert ZZ.poly_ring('x','y').unify(QQ.frac_field('x','z')) == EX # QQ.frac_field('x','y','z') - assert QQ.poly_ring('x','y').unify(ZZ.frac_field('x','z')) == EX # QQ.frac_field('x','y','z') - assert QQ.poly_ring('x','y').unify(QQ.frac_field('x','z')) == QQ.frac_field('x','y','z') - - assert ZZ.frac_field('x').unify(ZZ.poly_ring('x')) == ZZ.frac_field('x') - assert ZZ.frac_field('x').unify(QQ.poly_ring('x')) == EX # QQ.frac_field('x') - assert QQ.frac_field('x').unify(ZZ.poly_ring('x')) == EX # QQ.frac_field('x') - assert QQ.frac_field('x').unify(QQ.poly_ring('x')) == QQ.frac_field('x') - - assert ZZ.frac_field('x','y').unify(ZZ.poly_ring('x')) == ZZ.frac_field('x','y') - assert ZZ.frac_field('x','y').unify(QQ.poly_ring('x')) == EX # QQ.frac_field('x','y') - assert QQ.frac_field('x','y').unify(ZZ.poly_ring('x')) == EX # QQ.frac_field('x','y') - assert QQ.frac_field('x','y').unify(QQ.poly_ring('x')) == QQ.frac_field('x','y') - - assert ZZ.frac_field('x').unify(ZZ.poly_ring('x','y')) == ZZ.frac_field('x','y') - assert ZZ.frac_field('x').unify(QQ.poly_ring('x','y')) == EX # QQ.frac_field('x','y') - assert QQ.frac_field('x').unify(ZZ.poly_ring('x','y')) == EX # QQ.frac_field('x','y') - assert QQ.frac_field('x').unify(QQ.poly_ring('x','y')) == QQ.frac_field('x','y') - - assert ZZ.frac_field('x','y').unify(ZZ.poly_ring('x','z')) == ZZ.frac_field('x','y','z') - assert ZZ.frac_field('x','y').unify(QQ.poly_ring('x','z')) == EX # QQ.frac_field('x','y','z') - assert QQ.frac_field('x','y').unify(ZZ.poly_ring('x','z')) == EX # QQ.frac_field('x','y','z') - assert QQ.frac_field('x','y').unify(QQ.poly_ring('x','z')) == QQ.frac_field('x','y','z') - - alg = QQ.algebraic_field(sqrt(5)) - - assert alg.unify(alg['x','y']) == alg['x','y'] - assert alg['x','y'].unify(alg) == alg['x','y'] - - assert alg.unify(alg.frac_field('x','y')) == alg.frac_field('x','y') - assert alg.frac_field('x','y').unify(alg) == alg.frac_field('x','y') - - ext = QQ.algebraic_field(sqrt(7)) - - raises(NotImplementedError, lambda: alg.unify(ext)) - - raises(UnificationFailed, lambda: ZZ.poly_ring('x','y').unify(ZZ, gens=('y', 'z'))) - raises(UnificationFailed, lambda: ZZ.unify(ZZ.poly_ring('x','y'), gens=('y', 'z'))) - -def test_Domain__contains__(): - assert (0 in EX) == True - assert (0 in ZZ) == True - assert (0 in QQ) == True - assert (0 in RR) == True - assert (0 in ALG) == True - assert (0 in ZZ[x,y]) == True - assert (0 in QQ[x,y]) == True - assert (0 in RR[x,y]) == True - - assert (-7 in EX) == True - assert (-7 in ZZ) == True - assert (-7 in QQ) == True - assert (-7 in RR) == True - assert (-7 in ALG) == True - assert (-7 in ZZ[x,y]) == True - assert (-7 in QQ[x,y]) == True - assert (-7 in RR[x,y]) == True - - assert (17 in EX) == True - assert (17 in ZZ) == True - assert (17 in QQ) == True - assert (17 in RR) == True - assert (17 in ALG) == True - assert (17 in ZZ[x,y]) == True - assert (17 in QQ[x,y]) == True - assert (17 in RR[x,y]) == True - - assert (-S(1)/7 in EX) == True - assert (-S(1)/7 in ZZ) == False - assert (-S(1)/7 in QQ) == True - assert (-S(1)/7 in RR) == True - assert (-S(1)/7 in ALG) == True - assert (-S(1)/7 in ZZ[x,y]) == False - assert (-S(1)/7 in QQ[x,y]) == True - assert (-S(1)/7 in RR[x,y]) == True - - assert (S(3)/5 in EX) == True - assert (S(3)/5 in ZZ) == False - assert (S(3)/5 in QQ) == True - assert (S(3)/5 in RR) == True - assert (S(3)/5 in ALG) == True - assert (S(3)/5 in ZZ[x,y]) == False - assert (S(3)/5 in QQ[x,y]) == True - assert (S(3)/5 in RR[x,y]) == True - - assert (3.0 in EX) == True - assert (3.0 in ZZ) == True - assert (3.0 in QQ) == True - assert (3.0 in RR) == True - assert (3.0 in ALG) == True - assert (3.0 in ZZ[x,y]) == True - assert (3.0 in QQ[x,y]) == True - assert (3.0 in RR[x,y]) == True - - assert (3.14 in EX) == True - assert (3.14 in ZZ) == False - assert (3.14 in QQ) == True - assert (3.14 in RR) == True - assert (3.14 in ALG) == True - assert (3.14 in ZZ[x,y]) == False - assert (3.14 in QQ[x,y]) == True - assert (3.14 in RR[x,y]) == True - - assert (oo in EX) == True - assert (oo in ZZ) == False - assert (oo in QQ) == False - assert (oo in RR) == False - assert (oo in ALG) == False - assert (oo in ZZ[x,y]) == False - assert (oo in QQ[x,y]) == False - assert (oo in RR[x,y]) == False - - assert (-oo in EX) == True - assert (-oo in ZZ) == False - assert (-oo in QQ) == False - assert (-oo in RR) == False - assert (-oo in ALG) == False - assert (-oo in ZZ[x,y]) == False - assert (-oo in QQ[x,y]) == False - assert (-oo in RR[x,y]) == False - - assert (sqrt(7) in EX) == True - assert (sqrt(7) in ZZ) == False - assert (sqrt(7) in QQ) == False - assert (sqrt(7) in RR) == True - assert (sqrt(7) in ALG) == False - assert (sqrt(7) in ZZ[x,y]) == False - assert (sqrt(7) in QQ[x,y]) == False - assert (sqrt(7) in RR[x,y]) == True - - assert (2*sqrt(3)+1 in EX) == True - assert (2*sqrt(3)+1 in ZZ) == False - assert (2*sqrt(3)+1 in QQ) == False - assert (2*sqrt(3)+1 in RR) == True - assert (2*sqrt(3)+1 in ALG) == True - assert (2*sqrt(3)+1 in ZZ[x,y]) == False - assert (2*sqrt(3)+1 in QQ[x,y]) == False - assert (2*sqrt(3)+1 in RR[x,y]) == True - - assert (sin(1) in EX) == True - assert (sin(1) in ZZ) == False - assert (sin(1) in QQ) == False - assert (sin(1) in RR) == True - assert (sin(1) in ALG) == False - assert (sin(1) in ZZ[x,y]) == False - assert (sin(1) in QQ[x,y]) == False - assert (sin(1) in RR[x,y]) == True - - assert (x**2 + 1 in EX) == True - assert (x**2 + 1 in ZZ) == False - assert (x**2 + 1 in QQ) == False - assert (x**2 + 1 in RR) == False - assert (x**2 + 1 in ALG) == False - assert (x**2 + 1 in ZZ[x]) == True - assert (x**2 + 1 in QQ[x]) == True - assert (x**2 + 1 in RR[x]) == True - assert (x**2 + 1 in ZZ[x,y]) == True - assert (x**2 + 1 in QQ[x,y]) == True - assert (x**2 + 1 in RR[x,y]) == True - - assert (x**2 + y**2 in EX) == True - assert (x**2 + y**2 in ZZ) == False - assert (x**2 + y**2 in QQ) == False - assert (x**2 + y**2 in RR) == False - assert (x**2 + y**2 in ALG) == False - assert (x**2 + y**2 in ZZ[x]) == False - assert (x**2 + y**2 in QQ[x]) == False - assert (x**2 + y**2 in RR[x]) == False - assert (x**2 + y**2 in ZZ[x,y]) == True - assert (x**2 + y**2 in QQ[x,y]) == True - assert (x**2 + y**2 in RR[x,y]) == True - - assert (S(3)/2*x/(y + 1) - z in QQ[x, y, z]) == False - -def test_Domain_get_ring(): - assert ZZ.has_assoc_Ring == True - assert QQ.has_assoc_Ring == True - assert ZZ[x].has_assoc_Ring == True - assert QQ[x].has_assoc_Ring == True - assert ZZ[x,y].has_assoc_Ring == True - assert QQ[x,y].has_assoc_Ring == True - assert ZZ.frac_field(x).has_assoc_Ring == True - assert QQ.frac_field(x).has_assoc_Ring == True - assert ZZ.frac_field(x,y).has_assoc_Ring == True - assert QQ.frac_field(x,y).has_assoc_Ring == True - - assert EX.has_assoc_Ring == False - assert RR.has_assoc_Ring == False - assert ALG.has_assoc_Ring == False - - assert ZZ.get_ring() == ZZ - assert QQ.get_ring() == ZZ - assert ZZ[x].get_ring() == ZZ[x] - assert QQ[x].get_ring() == QQ[x] - assert ZZ[x,y].get_ring() == ZZ[x,y] - assert QQ[x,y].get_ring() == QQ[x,y] - assert ZZ.frac_field(x).get_ring() == ZZ[x] - assert QQ.frac_field(x).get_ring() == QQ[x] - assert ZZ.frac_field(x,y).get_ring() == ZZ[x,y] - assert QQ.frac_field(x,y).get_ring() == QQ[x,y] - - raises(DomainError, lambda: EX.get_ring()) - raises(DomainError, lambda: RR.get_ring()) - raises(DomainError, lambda: ALG.get_ring()) - -def test_Domain_get_field(): - assert EX.has_assoc_Field == True - assert ZZ.has_assoc_Field == True - assert QQ.has_assoc_Field == True - assert RR.has_assoc_Field == False - assert ALG.has_assoc_Field == True - assert ZZ[x].has_assoc_Field == True - assert QQ[x].has_assoc_Field == True - assert ZZ[x,y].has_assoc_Field == True - assert QQ[x,y].has_assoc_Field == True - - assert EX.get_field() == EX - assert ZZ.get_field() == QQ - assert QQ.get_field() == QQ - raises(DomainError, lambda: RR.get_field()) - assert ALG.get_field() == ALG - assert ZZ[x].get_field() == ZZ.frac_field(x) - assert QQ[x].get_field() == QQ.frac_field(x) - assert ZZ[x,y].get_field() == ZZ.frac_field(x,y) - assert QQ[x,y].get_field() == QQ.frac_field(x,y) - -def test_Domain_get_exact(): - assert EX.get_exact() == EX - assert ZZ.get_exact() == ZZ - assert QQ.get_exact() == QQ - assert RR.get_exact() == QQ - assert ALG.get_exact() == ALG - assert ZZ[x].get_exact() == ZZ[x] - assert QQ[x].get_exact() == QQ[x] - assert ZZ[x,y].get_exact() == ZZ[x,y] - assert QQ[x,y].get_exact() == QQ[x,y] - assert ZZ.frac_field(x).get_exact() == ZZ.frac_field(x) - assert QQ.frac_field(x).get_exact() == QQ.frac_field(x) - assert ZZ.frac_field(x,y).get_exact() == ZZ.frac_field(x,y) - assert QQ.frac_field(x,y).get_exact() == QQ.frac_field(x,y) - -def test_Domain_convert(): - assert QQ.convert(10e-52) != QQ(0) - assert ZZ.convert(DMP([[ZZ(1)]], ZZ)) == ZZ(1) - -def test_PolynomialRing__init(): - raises(GeneratorsNeeded, lambda: ZZ.poly_ring()) - -def test_PolynomialRing_from_FractionField(): - x = DMF(([1, 0, 1], [1, 1]), ZZ) - y = DMF(([1, 0, 1], [1]), ZZ) - - assert ZZ['x'].from_FractionField(x, ZZ['x']) is None - assert ZZ['x'].from_FractionField(y, ZZ['x']) == DMP([ZZ(1), ZZ(0), ZZ(1)], ZZ) - -def test_FractionField__init(): - raises(GeneratorsNeeded, lambda: ZZ.frac_field()) - -def test_inject(): - assert ZZ.inject(x, y, z) == ZZ[x, y, z] - assert ZZ[x].inject(y, z) == ZZ[x, y, z] - assert ZZ.frac_field(x).inject(y, z) == ZZ.frac_field(x, y, z) - raises(GeneratorsError, lambda: ZZ[x].inject(x)) - -def test_Domain_map(): - seq = ZZ.map([1, 2, 3, 4]) - - assert all(ZZ.of_type(elt) for elt in seq) - - seq = ZZ.map([[1, 2, 3, 4]]) - - assert all(ZZ.of_type(elt) for elt in seq[0]) and len(seq) == 1 - -def test_Domain___eq__(): - assert (ZZ[x,y] == ZZ[x,y]) == True - assert (QQ[x,y] == QQ[x,y]) == True - - assert (ZZ[x,y] == QQ[x,y]) == False - assert (QQ[x,y] == ZZ[x,y]) == False - - assert (ZZ.frac_field(x,y) == ZZ.frac_field(x,y)) == True - assert (QQ.frac_field(x,y) == QQ.frac_field(x,y)) == True - - assert (ZZ.frac_field(x,y) == QQ.frac_field(x,y)) == False - assert (QQ.frac_field(x,y) == ZZ.frac_field(x,y)) == False - -def test_Domain__algebraic_field(): - alg = ZZ.algebraic_field(sqrt(2)) - assert alg.ext.minpoly == Poly(x**2 - 2) - assert alg.dom == QQ - - alg = QQ.algebraic_field(sqrt(2)) - assert alg.ext.minpoly == Poly(x**2 - 2) - assert alg.dom == QQ - - alg = alg.algebraic_field(sqrt(3)) - assert alg.ext.minpoly == Poly(x**4 - 10*x**2 + 1) - assert alg.dom == QQ - -def test_PolynomialRing__from_FractionField(): - f = DMF(([1, 0, 1], [1, 1]), ZZ) - g = DMF(([1, 0, 1], [1]), ZZ) - - assert ZZ[x].from_FractionField(f, ZZ[x]) is None - assert ZZ[x].from_FractionField(g, ZZ[x]) == DMP([ZZ(1), ZZ(0), ZZ(1)], ZZ) - -def test_PythonRationalType__init__(): - assert Q(0).p == 0 - assert Q(0).q == 1 - assert Q(0, 1).p == 0 - assert Q(0, 1).q == 1 - assert Q(0,-1).p == 0 - assert Q(0,-1).q == 1 - - assert Q(1).p == 1 - assert Q(1).q == 1 - assert Q(1, 1).p == 1 - assert Q(1, 1).q == 1 - assert Q(-1,-1).p == 1 - assert Q(-1,-1).q == 1 - - assert Q(-1).p == -1 - assert Q(-1).q == 1 - assert Q(-1, 1).p == -1 - assert Q(-1, 1).q == 1 - assert Q( 1,-1).p == -1 - assert Q( 1,-1).q == 1 - - assert Q(1, 2).p == 1 - assert Q(1, 2).q == 2 - assert Q(3, 4).p == 3 - assert Q(3, 4).q == 4 - - assert Q(2, 2).p == 1 - assert Q(2, 2).q == 1 - assert Q(2, 4).p == 1 - assert Q(2, 4).q == 2 - -def test_PythonRationalType__hash__(): - assert hash(Q(0)) == hash(0) - assert hash(Q(1)) == hash(1) - assert hash(Q(117)) == hash(117) - -def test_PythonRationalType__int__(): - assert int(Q(-1, 4)) == 0 - assert int(Q( 1, 4)) == 0 - assert int(Q(-5, 4)) == -1 - assert int(Q( 5, 4)) == 1 - -def test_PythonRationalType__float__(): - assert float(Q(-1, 2)) == -0.5 - assert float(Q( 1, 2)) == 0.5 - -def test_PythonRationalType__abs__(): - assert abs(Q(-1, 2)) == Q(1, 2) - assert abs(Q( 1, 2)) == Q(1, 2) - -def test_PythonRationalType__pos__(): - assert +Q(-1, 2) == Q(-1, 2) - assert +Q( 1, 2) == Q( 1, 2) - -def test_PythonRationalType__neg__(): - assert -Q(-1, 2) == Q( 1, 2) - assert -Q( 1, 2) == Q(-1, 2) - -def test_PythonRationalType__add__(): - assert Q(-1, 2) + Q( 1, 2) == Q(0) - assert Q( 1, 2) + Q(-1, 2) == Q(0) - - assert Q(1, 2) + Q(1, 2) == Q(1) - assert Q(1, 2) + Q(3, 2) == Q(2) - assert Q(3, 2) + Q(1, 2) == Q(2) - assert Q(3, 2) + Q(3, 2) == Q(3) - - assert 1 + Q(1, 2) == Q(3, 2) - assert Q(1, 2) + 1 == Q(3, 2) - -def test_PythonRationalType__sub__(): - assert Q(-1, 2) - Q( 1, 2) == Q(-1) - assert Q( 1, 2) - Q(-1, 2) == Q( 1) - - assert Q(1, 2) - Q(1, 2) == Q( 0) - assert Q(1, 2) - Q(3, 2) == Q(-1) - assert Q(3, 2) - Q(1, 2) == Q( 1) - assert Q(3, 2) - Q(3, 2) == Q( 0) - - assert 1 - Q(1, 2) == Q( 1, 2) - assert Q(1, 2) - 1 == Q(-1, 2) - -def test_PythonRationalType__mul__(): - assert Q(-1, 2) * Q( 1, 2) == Q(-1, 4) - assert Q( 1, 2) * Q(-1, 2) == Q(-1, 4) - - assert Q(1, 2) * Q(1, 2) == Q(1, 4) - assert Q(1, 2) * Q(3, 2) == Q(3, 4) - assert Q(3, 2) * Q(1, 2) == Q(3, 4) - assert Q(3, 2) * Q(3, 2) == Q(9, 4) - - assert 2 * Q(1, 2) == Q(1) - assert Q(1, 2) * 2 == Q(1) - -def test_PythonRationalType__div__(): - assert Q(-1, 2) / Q( 1, 2) == Q(-1) - assert Q( 1, 2) / Q(-1, 2) == Q(-1) - - assert Q(1, 2) / Q(1, 2) == Q(1) - assert Q(1, 2) / Q(3, 2) == Q(1, 3) - assert Q(3, 2) / Q(1, 2) == Q(3) - assert Q(3, 2) / Q(3, 2) == Q(1) - - assert 2 / Q(1, 2) == Q(4) - assert Q(1, 2) / 2 == Q(1, 4) - - raises(ZeroDivisionError, lambda: Q(1, 2) / Q(0)) - raises(ZeroDivisionError, lambda: Q(1, 2) / 0) - -def test_PythonRationalType__pow__(): - assert Q(1)**10 == Q(1) - assert Q(2)**10 == Q(1024) - - assert Q(1)**(-10) == Q(1) - assert Q(2)**(-10) == Q(1, 1024) - -def test_PythonRationalType__eq__(): - assert (Q(1, 2) == Q(1, 2)) is True - assert (Q(1, 2) != Q(1, 2)) is False - - assert (Q(1, 2) == Q(1, 3)) is False - assert (Q(1, 2) != Q(1, 3)) is True - -def test_PythonRationalType__lt_le_gt_ge__(): - assert (Q(1, 2) < Q(1, 4)) is False - assert (Q(1, 2) <= Q(1, 4)) is False - assert (Q(1, 2) > Q(1, 4)) is True - assert (Q(1, 2) >= Q(1, 4)) is True - - assert (Q(1, 4) < Q(1, 2)) is True - assert (Q(1, 4) <= Q(1, 2)) is True - assert (Q(1, 4) > Q(1, 2)) is False - assert (Q(1, 4) >= Q(1, 2)) is False - -def test_sympy_of_type(): - assert ZZ_sympy().of_type(Integer(1)) - assert ZZ_sympy().of_type(Integer(0)) - assert ZZ_sympy().of_type(Integer(-1)) - assert ZZ_sympy().of_type(Integer(2)) - assert not ZZ_sympy().of_type(Rational(1, 2)) - assert QQ_sympy().of_type(Rational(1)) - assert QQ_sympy().of_type(Rational(-1)) - assert QQ_sympy().of_type(Rational(0)) - assert QQ_sympy().of_type(Rational(2)) - assert QQ_sympy().of_type(Rational(1, 2)) - assert QQ_sympy().of_type(Rational(3, 2)) - -def test_FF_of_type(): - assert FF(3).of_type(FF(3)(1)) is True - assert FF(5).of_type(FF(5)(3)) is True - assert FF(5).of_type(FF(7)(3)) is False - -def test___eq__(): - assert not QQ['x'] == ZZ['x'] - assert not QQ.frac_field(x) == ZZ.frac_field(x) - -def test_RealDomain_from_sympy(): - RR = RR_mpmath() - - assert RR.convert(S(0)) == RR.dtype(0) - assert RR.convert(S(0.0)) == RR.dtype(0.0) - assert RR.convert(S(1)) == RR.dtype(1) - assert RR.convert(S(1.0)) == RR.dtype(1.0) - assert RR.convert(sin(1)) == RR.dtype(sin(1).evalf()) - raises(CoercionFailed, lambda: RR.convert(x)) - raises(CoercionFailed, lambda: RR.convert(oo)) - raises(CoercionFailed, lambda: RR.convert(-oo)) - - RR = RR_sympy() - - assert RR.convert(S(0)) == RR.dtype(0) - assert RR.convert(S(0.0)) == RR.dtype(0.0) - assert RR.convert(S(1)) == RR.dtype(1) - assert RR.convert(S(1.0)) == RR.dtype(1.0) - assert RR.convert(sin(1)) == RR.dtype(sin(1).evalf()) - assert RR.n(3, 2) == RR.evalf(3, 2) == Rational(3).n(2) - raises(CoercionFailed, lambda: RR.convert(x)) - raises(CoercionFailed, lambda: RR.convert(oo)) - raises(CoercionFailed, lambda: RR.convert(-oo)) - -def test_ModularInteger(): - GF = ModularIntegerFactory(3) - - a = GF(0) - assert isinstance(a, GF) and a == 0 - a = GF(1) - assert isinstance(a, GF) and a == 1 - a = GF(2) - assert isinstance(a, GF) and a == 2 - a = GF(3) - assert isinstance(a, GF) and a == 0 - a = GF(4) - assert isinstance(a, GF) and a == 1 - - a = GF(GF(0)) - assert isinstance(a, GF) and a == 0 - a = GF(GF(1)) - assert isinstance(a, GF) and a == 1 - a = GF(GF(2)) - assert isinstance(a, GF) and a == 2 - a = GF(GF(3)) - assert isinstance(a, GF) and a == 0 - a = GF(GF(4)) - assert isinstance(a, GF) and a == 1 - - a = -GF(1) - assert isinstance(a, GF) and a == 2 - a = -GF(2) - assert isinstance(a, GF) and a == 1 - - a = 2 + GF(2) - assert isinstance(a, GF) and a == 1 - a = GF(2) + 2 - assert isinstance(a, GF) and a == 1 - a = GF(2) + GF(2) - assert isinstance(a, GF) and a == 1 - a = GF(2) + GF(2) - assert isinstance(a, GF) and a == 1 - - a = 3 - GF(2) - assert isinstance(a, GF) and a == 1 - a = GF(3) - 2 - assert isinstance(a, GF) and a == 1 - a = GF(3) - GF(2) - assert isinstance(a, GF) and a == 1 - a = GF(3) - GF(2) - assert isinstance(a, GF) and a == 1 - - a = 2*GF(2) - assert isinstance(a, GF) and a == 1 - a = GF(2)*2 - assert isinstance(a, GF) and a == 1 - a = GF(2)*GF(2) - assert isinstance(a, GF) and a == 1 - a = GF(2)*GF(2) - assert isinstance(a, GF) and a == 1 - - a = 2/GF(2) - assert isinstance(a, GF) and a == 1 - a = GF(2)/2 - assert isinstance(a, GF) and a == 1 - a = GF(2)/GF(2) - assert isinstance(a, GF) and a == 1 - a = GF(2)/GF(2) - assert isinstance(a, GF) and a == 1 - - a = 1 % GF(2) - assert isinstance(a, GF) and a == 1 - a = GF(1) % 2 - assert isinstance(a, GF) and a == 1 - a = GF(1) % GF(2) - assert isinstance(a, GF) and a == 1 - a = GF(1) % GF(2) - assert isinstance(a, GF) and a == 1 - - a = GF(2)**0 - assert isinstance(a, GF) and a == 1 - a = GF(2)**1 - assert isinstance(a, GF) and a == 2 - a = GF(2)**2 - assert isinstance(a, GF) and a == 1 - - assert bool(GF(3)) is False - assert bool(GF(4)) is True - - GF = ModularIntegerFactory(5) - - a = GF(1)**(-1) - assert isinstance(a, GF) and a == 1 - a = GF(2)**(-1) - assert isinstance(a, GF) and a == 3 - a = GF(3)**(-1) - assert isinstance(a, GF) and a == 2 - a = GF(4)**(-1) - assert isinstance(a, GF) and a == 4 - - assert (GF(1) < GF(2)) == True - assert (GF(1) <= GF(2)) == True - assert (GF(1) > GF(2)) == False - assert (GF(1) >= GF(2)) == False - - assert (GF(3) < GF(2)) == False - assert (GF(3) <= GF(2)) == False - assert (GF(3) > GF(2)) == True - assert (GF(3) >= GF(2)) == True - - assert (GF(1) < GF(7)) == True - assert (GF(1) <= GF(7)) == True - assert (GF(1) > GF(7)) == False - assert (GF(1) >= GF(7)) == False - - assert (GF(3) < GF(7)) == False - assert (GF(3) <= GF(7)) == False - assert (GF(3) > GF(7)) == True - assert (GF(3) >= GF(7)) == True - - assert (GF(1) < 2) == True - assert (GF(1) <= 2) == True - assert (GF(1) > 2) == False - assert (GF(1) >= 2) == False - - assert (GF(3) < 2) == False - assert (GF(3) <= 2) == False - assert (GF(3) > 2) == True - assert (GF(3) >= 2) == True - - assert (GF(1) < 7) == True - assert (GF(1) <= 7) == True - assert (GF(1) > 7) == False - assert (GF(1) >= 7) == False - - assert (GF(3) < 7) == False - assert (GF(3) <= 7) == False - assert (GF(3) > 7) == True - assert (GF(3) >= 7) == True - - raises(NotInvertible, lambda: GF(0)**(-1)) - raises(NotInvertible, lambda: GF(5)**(-1)) - - raises(ValueError, lambda: ModularIntegerFactory(0)) - raises(ValueError, lambda: ModularIntegerFactory(2.1)) - raises(TypeError, lambda: ModularIntegerFactory(3, QQ)) diff -Nru python3-sympy-0.7.2/sympy/polys/tests/test_euclidtools.py python3-sympy-0.7.3/sympy/polys/tests/test_euclidtools.py --- python3-sympy-0.7.2/sympy/polys/tests/test_euclidtools.py 2012-10-17 03:02:22.000000000 +0000 +++ python3-sympy-0.7.3/sympy/polys/tests/test_euclidtools.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,649 +1,704 @@ -"""Tests for Euclidean algorithms, GCDs, LCMs and polynomial remainder -sequences. """ +"""Tests for Euclidean algorithms, GCDs, LCMs and polynomial remainder sequences. """ -from sympy.polys.euclidtools import ( - dup_gcdex, dup_half_gcdex, dup_invert, - dup_euclidean_prs, dmp_euclidean_prs, - dup_primitive_prs, dmp_primitive_prs, - dup_subresultants, dmp_subresultants, - dup_prs_resultant, dmp_prs_resultant, - dmp_zz_collins_resultant, - dmp_qq_collins_resultant, - dup_resultant, dmp_resultant, - dup_discriminant, dmp_discriminant, - dup_zz_heu_gcd, dmp_zz_heu_gcd, - dup_qq_heu_gcd, dmp_qq_heu_gcd, - dup_rr_prs_gcd, dmp_rr_prs_gcd, - dup_ff_prs_gcd, dmp_ff_prs_gcd, - dup_inner_gcd, dmp_inner_gcd, - dup_lcm, dmp_lcm, - dmp_content, dmp_primitive, - dup_cancel, dmp_cancel) - -from sympy.polys.densebasic import ( - dmp_one_p, - dup_LC, dmp_LC, - dup_normal, dmp_normal) - -from sympy.polys.densearith import ( - dup_add, - dup_mul, dmp_mul, - dup_exquo) - -from sympy.polys.densetools import ( - dup_diff) +from sympy.polys.rings import ring +from sympy.polys.domains import ZZ, QQ, RR from sympy.polys.specialpolys import ( - f_4, f_5, f_6, + f_polys, dmp_fateman_poly_F_1, dmp_fateman_poly_F_2, dmp_fateman_poly_F_3) -from sympy.polys.domains import ZZ, QQ, RR +f_0, f_1, f_2, f_3, f_4, f_5, f_6 = f_polys() def test_dup_gcdex(): - f = dup_normal([1,-2,-6,12,15], QQ) - g = dup_normal([1,1,-4,-4], QQ) + R, x = ring("x", QQ) + + f = x**4 - 2*x**3 - 6*x**2 + 12*x + 15 + g = x**3 + x**2 - 4*x - 4 + + s = -QQ(1,5)*x + QQ(3,5) + t = QQ(1,5)*x**2 - QQ(6,5)*x + 2 + h = x + 1 - s = [QQ(-1,5),QQ(3,5)] - t = [QQ(1,5),QQ(-6,5),QQ(2)] - h = [QQ(1),QQ(1)] + assert R.dup_half_gcdex(f, g) == (s, h) + assert R.dup_gcdex(f, g) == (s, t, h) - assert dup_half_gcdex(f, g, QQ) == (s, h) - assert dup_gcdex(f, g, QQ) == (s, t, h) + f = x**4 + 4*x**3 - x + 1 + g = x**3 - x + 1 - f = dup_normal([1,4,0,-1,1], QQ) - g = dup_normal([1,0,-1,1], QQ) + s, t, h = R.dup_gcdex(f, g) + S, T, H = R.dup_gcdex(g, f) - s, t, h = dup_gcdex(f, g, QQ) - S, T, H = dup_gcdex(g, f, QQ) + assert R.dup_add(R.dup_mul(s, f), + R.dup_mul(t, g)) == h + assert R.dup_add(R.dup_mul(S, g), + R.dup_mul(T, f)) == H - assert dup_add(dup_mul(s, f, QQ), - dup_mul(t, g, QQ), QQ) == h - assert dup_add(dup_mul(S, g, QQ), - dup_mul(T, f, QQ), QQ) == H + f = 2*x + g = x**2 - 16 - f = dup_normal([2,0], QQ) - g = dup_normal([1,0,-16], QQ) + s = QQ(1,32)*x + t = -QQ(1,16) + h = 1 - s = [QQ(1,32),QQ(0)] - t = [QQ(-1,16)] - h = [QQ(1)] + assert R.dup_half_gcdex(f, g) == (s, h) + assert R.dup_gcdex(f, g) == (s, t, h) - assert dup_half_gcdex(f, g, QQ) == (s, h) - assert dup_gcdex(f, g, QQ) == (s, t, h) def test_dup_invert(): - assert dup_invert([QQ(2),QQ(0)], [QQ(1),QQ(0),QQ(-16)], QQ) == [QQ(1,32),QQ(0)] + R, x = ring("x", QQ) + assert R.dup_invert(2*x, x**2 - 16) == QQ(1,32)*x + def test_dup_euclidean_prs(): - f = QQ.map([1, 0, 1, 0, -3, -3, 8, 2, -5]) - g = QQ.map([3, 0, 5, 0, -4, -9, 21]) + R, x = ring("x", QQ) + + f = x**8 + x**6 - 3*x**4 - 3*x**3 + 8*x**2 + 2*x - 5 + g = 3*x**6 + 5*x**4 - 4*x**2 - 9*x + 21 + + assert R.dup_euclidean_prs(f, g) == [ + f, + g, + -QQ(5,9)*x**4 + QQ(1,9)*x**2 - QQ(1,3), + -QQ(117,25)*x**2 - 9*x + QQ(441,25), + QQ(233150,19773)*x - QQ(102500,6591), + -QQ(1288744821,543589225)] - assert dup_euclidean_prs(f, g, QQ) == [f, g, - [-QQ(5,9), QQ(0,1), QQ(1,9), QQ(0,1), -QQ(1,3)], - [-QQ(117,25), -QQ(9,1), QQ(441,25)], - [QQ(233150,19773), -QQ(102500,6591)], - [-QQ(1288744821,543589225)]] def test_dup_primitive_prs(): - f = ZZ.map([1, 0, 1, 0, -3, -3, 8, 2, -5]) - g = ZZ.map([3, 0, 5, 0, -4, -9, 21]) + R, x = ring("x", ZZ) + + f = x**8 + x**6 - 3*x**4 - 3*x**3 + 8*x**2 + 2*x - 5 + g = 3*x**6 + 5*x**4 - 4*x**2 - 9*x + 21 + + assert R.dup_primitive_prs(f, g) == [ + f, + g, + -5*x**4 + x**2 - 3, + 13*x**2 + 25*x - 49, + 4663*x - 6150, + 1] - assert dup_primitive_prs(f, g, ZZ) == [f, g, - [-ZZ(5), ZZ(0), ZZ(1), ZZ(0), -ZZ(3)], - [ZZ(13), ZZ(25), -ZZ(49)], - [ZZ(4663), -ZZ(6150)], - [ZZ(1)]] def test_dup_subresultants(): - assert dup_resultant([], [], ZZ) == ZZ(0) + R, x = ring("x", ZZ) + + assert R.dup_resultant(0, 0) == 0 - assert dup_resultant([ZZ(1)], [], ZZ) == ZZ(0) - assert dup_resultant([], [ZZ(1)], ZZ) == ZZ(0) + assert R.dup_resultant(1, 0) == 0 + assert R.dup_resultant(0, 1) == 0 - f = dup_normal([1,0,1,0,-3,-3,8,2,-5], ZZ) - g = dup_normal([3,0,5,0,-4,-9,21], ZZ) + f = x**8 + x**6 - 3*x**4 - 3*x**3 + 8*x**2 + 2*x - 5 + g = 3*x**6 + 5*x**4 - 4*x**2 - 9*x + 21 - a = dup_normal([15,0,-3,0,9], ZZ) - b = dup_normal([65,125,-245], ZZ) - c = dup_normal([9326,-12300], ZZ) - d = dup_normal([260708], ZZ) + a = 15*x**4 - 3*x**2 + 9 + b = 65*x**2 + 125*x - 245 + c = 9326*x - 12300 + d = 260708 - assert dup_subresultants(f, g, ZZ) == [f, g, a, b, c, d] - assert dup_resultant(f, g, ZZ) == dup_LC(d, ZZ) + assert R.dup_subresultants(f, g) == [f, g, a, b, c, d] + assert R.dup_resultant(f, g) == R.dup_LC(d) - f = dup_normal([1,-2,1], ZZ) - g = dup_normal([1,0,-1], ZZ) + f = x**2 - 2*x + 1 + g = x**2 - 1 - a = dup_normal([2,-2], ZZ) + a = 2*x - 2 - assert dup_subresultants(f, g, ZZ) == [f, g, a] - assert dup_resultant(f, g, ZZ) == 0 + assert R.dup_subresultants(f, g) == [f, g, a] + assert R.dup_resultant(f, g) == 0 - f = dup_normal([1,0, 1], ZZ) - g = dup_normal([1,0,-1], ZZ) + f = x**2 + 1 + g = x**2 - 1 - a = dup_normal([-2], ZZ) + a = -2 - assert dup_subresultants(f, g, ZZ) == [f, g, a] - assert dup_resultant(f, g, ZZ) == 4 + assert R.dup_subresultants(f, g) == [f, g, a] + assert R.dup_resultant(f, g) == 4 - f = dup_normal([1,0,-1], ZZ) - g = dup_normal([1,-1,0,2], ZZ) + f = x**2 - 1 + g = x**3 - x**2 + 2 - assert dup_resultant(f, g, ZZ) == 0 + assert R.dup_resultant(f, g) == 0 - f = dup_normal([3,0,-1,0], ZZ) - g = dup_normal([5,0,1], ZZ) + f = 3*x**3 - x + g = 5*x**2 + 1 - assert dup_resultant(f, g, ZZ) == 64 + assert R.dup_resultant(f, g) == 64 - f = dup_normal([1,-2,7], ZZ) - g = dup_normal([1,0,-1,5], ZZ) + f = x**2 - 2*x + 7 + g = x**3 - x + 5 - assert dup_resultant(f, g, ZZ) == 265 + assert R.dup_resultant(f, g) == 265 - f = dup_normal([1,-6,11,-6], ZZ) - g = dup_normal([1,-15,74,-120], ZZ) + f = x**3 - 6*x**2 + 11*x - 6 + g = x**3 - 15*x**2 + 74*x - 120 - assert dup_resultant(f, g, ZZ) == -8640 + assert R.dup_resultant(f, g) == -8640 - f = dup_normal([1,-6,11,-6], ZZ) - g = dup_normal([1,-10,29,-20], ZZ) + f = x**3 - 6*x**2 + 11*x - 6 + g = x**3 - 10*x**2 + 29*x - 20 - assert dup_resultant(f, g, ZZ) == 0 + assert R.dup_resultant(f, g) == 0 - f = dup_normal([1,0,0,-1], ZZ) - g = dup_normal([1,2,2,-1], ZZ) + f = x**3 - 1 + g = x**3 + 2*x**2 + 2*x - 1 - assert dup_resultant(f, g, ZZ) == 16 + assert R.dup_resultant(f, g) == 16 - f = dup_normal([1,0,0,0,0,0,0,0,-2], ZZ) - g = dup_normal([1,-1], ZZ) + f = x**8 - 2 + g = x - 1 + + assert R.dup_resultant(f, g) == -1 - assert dup_resultant(f, g, ZZ) == -1 def test_dmp_subresultants(): - assert dmp_resultant([[]], [[]], 1, ZZ) == [] - assert dmp_prs_resultant([[]], [[]], 1, ZZ)[0] == [] - assert dmp_zz_collins_resultant([[]], [[]], 1, ZZ) == [] - assert dmp_qq_collins_resultant([[]], [[]], 1, ZZ) == [] + R, x, y = ring("x,y", ZZ) + + assert R.dmp_resultant(0, 0) == 0 + assert R.dmp_prs_resultant(0, 0)[0] == 0 + assert R.dmp_zz_collins_resultant(0, 0) == 0 + assert R.dmp_qq_collins_resultant(0, 0) == 0 - assert dmp_resultant([[ZZ(1)]], [[]], 1, ZZ) == [] - assert dmp_resultant([[ZZ(1)]], [[]], 1, ZZ) == [] - assert dmp_resultant([[ZZ(1)]], [[]], 1, ZZ) == [] + assert R.dmp_resultant(1, 0) == 0 + assert R.dmp_resultant(1, 0) == 0 + assert R.dmp_resultant(1, 0) == 0 - assert dmp_resultant([[]], [[ZZ(1)]], 1, ZZ) == [] - assert dmp_prs_resultant([[]], [[ZZ(1)]], 1, ZZ)[0] == [] - assert dmp_zz_collins_resultant([[]], [[ZZ(1)]], 1, ZZ) == [] - assert dmp_qq_collins_resultant([[]], [[ZZ(1)]], 1, ZZ) == [] + assert R.dmp_resultant(0, 1) == 0 + assert R.dmp_prs_resultant(0, 1)[0] == 0 + assert R.dmp_zz_collins_resultant(0, 1) == 0 + assert R.dmp_qq_collins_resultant(0, 1) == 0 - f = dmp_normal([[3,0],[],[-1,0,0,-4]], 1, ZZ) - g = dmp_normal([[1],[1,0,0,0],[-9]], 1, ZZ) + f = 3*x**2*y - y**3 - 4 + g = x**2 + x*y**3 - 9 - a = dmp_normal([[3,0,0,0,0],[1,0,-27,4]], 1, ZZ) - b = dmp_normal([[-3,0,0,-12,1,0,-54,8,729,-216,16]], 1, ZZ) + a = 3*x*y**4 + y**3 - 27*y + 4 + b = -3*y**10 - 12*y**7 + y**6 - 54*y**4 + 8*y**3 + 729*y**2 - 216*y + 16 - r = dmp_LC(b, ZZ) + r = R.dmp_LC(b) - assert dmp_subresultants(f, g, 1, ZZ) == [f, g, a, b] + assert R.dmp_subresultants(f, g) == [f, g, a, b] - assert dmp_resultant(f, g, 1, ZZ) == r - assert dmp_prs_resultant(f, g, 1, ZZ)[0] == r - assert dmp_zz_collins_resultant(f, g, 1, ZZ) == r - assert dmp_qq_collins_resultant(f, g, 1, ZZ) == r + assert R.dmp_resultant(f, g) == r + assert R.dmp_prs_resultant(f, g)[0] == r + assert R.dmp_zz_collins_resultant(f, g) == r + assert R.dmp_qq_collins_resultant(f, g) == r - f = dmp_normal([[-1],[],[],[5]], 1, ZZ) - g = dmp_normal([[3,1],[],[]], 1, ZZ) + f = -x**3 + 5 + g = 3*x**2*y + x**2 - a = dmp_normal([[45,30,5]], 1, ZZ) - b = dmp_normal([[675,675,225,25]], 1, ZZ) + a = 45*y**2 + 30*y + 5 + b = 675*y**3 + 675*y**2 + 225*y + 25 - r = dmp_LC(b, ZZ) + r = R.dmp_LC(b) - assert dmp_subresultants(f, g, 1, ZZ) == [f, g, a] - assert dmp_resultant(f, g, 1, ZZ) == r - assert dmp_prs_resultant(f, g, 1, ZZ)[0] == r - assert dmp_zz_collins_resultant(f, g, 1, ZZ) == r - assert dmp_qq_collins_resultant(f, g, 1, ZZ) == r + assert R.dmp_subresultants(f, g) == [f, g, a] + assert R.dmp_resultant(f, g) == r + assert R.dmp_prs_resultant(f, g)[0] == r + assert R.dmp_zz_collins_resultant(f, g) == r + assert R.dmp_qq_collins_resultant(f, g) == r - f = [[[[[6]]]], [[[[-3]]], [[[-2]], [[]]]], [[[[1]], [[]]], [[[]]]]] - g = [[[[[1]]]], [[[[-1], [-1, 0]]]], [[[[1, 0], []]]]] + R, x, y, z, u, v = ring("x,y,z,u,v", ZZ) - r = [[[[1]], [[-3], [-3, 0]], [[9, 0], []]], [[[-2], [-2, 0]], [[6], - [12, 0], [6, 0, 0]], [[-18, 0], [-18, 0, 0], []]], [[[4, 0], - []], [[-12, 0], [-12, 0, 0], []], [[36, 0, 0], [], []]]] + f = 6*x**2 - 3*x*y - 2*x*z + y*z + g = x**2 - x*u - x*v + u*v - assert dmp_zz_collins_resultant(f, g, 4, ZZ) == r + r = y**2*z**2 - 3*y**2*z*u - 3*y**2*z*v + 9*y**2*u*v - 2*y*z**2*u \ + - 2*y*z**2*v + 6*y*z*u**2 + 12*y*z*u*v + 6*y*z*v**2 - 18*y*u**2*v \ + - 18*y*u*v**2 + 4*z**2*u*v - 12*z*u**2*v - 12*z*u*v**2 + 36*u**2*v**2 - f = [[[[[QQ(1,1)]]]], [[[[QQ(-1,2)]]], [[[QQ(-1,3)]], [[]]]], [[[[QQ(1,6)]], [[]]], [[[]]]]] - g = [[[[[QQ(1,1)]]]], [[[[QQ(-1,1)], [QQ(-1,1), QQ(0, 1)]]]], [[[[QQ(1,1), QQ(0,1)], []]]]] + assert R.dmp_zz_collins_resultant(f, g) == r.drop(x) - r = [[[[QQ(1,36)]], [[QQ(-1,12)], [QQ(-1,12), QQ(0,1)]], [[QQ(1,4), QQ(0,1)], []]], - [[[QQ(-1,18)], [QQ(-1,18), QQ(0,1)]], [[QQ(1,6)], [QQ(1,3), QQ(0,1)], [QQ(1,6), - QQ(0,1), QQ(0,1)]], [[QQ(-1,2), QQ(0,1)], [QQ(-1,2), QQ(0,1), QQ(0,1)], []]], - [[[QQ(1,9), QQ(0,1)], []], [[QQ(-1,3), QQ(0,1)], [QQ(-1,3), QQ(0,1), QQ(0,1)], []], - [[QQ(1,1), QQ(0,1), QQ(0,1)], [], []]]] + R, x, y, z, u, v = ring("x,y,z,u,v", QQ) + + f = x**2 - QQ(1,2)*x*y - QQ(1,3)*x*z + QQ(1,6)*y*z + g = x**2 - x*u - x*v + u*v + + r = QQ(1,36)*y**2*z**2 - QQ(1,12)*y**2*z*u - QQ(1,12)*y**2*z*v + QQ(1,4)*y**2*u*v \ + - QQ(1,18)*y*z**2*u - QQ(1,18)*y*z**2*v + QQ(1,6)*y*z*u**2 + QQ(1,3)*y*z*u*v \ + + QQ(1,6)*y*z*v**2 - QQ(1,2)*y*u**2*v - QQ(1,2)*y*u*v**2 + QQ(1,9)*z**2*u*v \ + - QQ(1,3)*z*u**2*v - QQ(1,3)*z*u*v**2 + u**2*v**2 + + assert R.dmp_qq_collins_resultant(f, g) == r.drop(x) - assert dmp_qq_collins_resultant(f, g, 4, QQ) == r def test_dup_discriminant(): - assert dup_discriminant([], ZZ) == 0 - assert dup_discriminant([1,0], ZZ) == 1 + R, x = ring("x", ZZ) + + assert R.dup_discriminant(0) == 0 + assert R.dup_discriminant(x) == 1 + + assert R.dup_discriminant(x**3 + 3*x**2 + 9*x - 13) == -11664 + assert R.dup_discriminant(5*x**5 + x**3 + 2) == 31252160 + assert R.dup_discriminant(x**4 + 2*x**3 + 6*x**2 - 22*x + 13) == 0 + assert R.dup_discriminant(12*x**7 + 15*x**4 + 30*x**3 + x**2 + 1) == -220289699947514112 - assert dup_discriminant([1,3,9,-13], ZZ) == -11664 - assert dup_discriminant([5,0,1,0,0,2], ZZ) == 31252160 - assert dup_discriminant([1,2,6,-22,13], ZZ) == 0 - assert dup_discriminant([12,0,0,15,30,1,0,1], ZZ) == -220289699947514112 def test_dmp_discriminant(): - assert dmp_discriminant([], 0, ZZ) == 0 - assert dmp_discriminant([[]], 1, ZZ) == [] + R, x = ring("x", ZZ) + + assert R.dmp_discriminant(0) == 0 + + R, x, y = ring("x,y", ZZ) + + assert R.dmp_discriminant(0) == 0 + assert R.dmp_discriminant(y) == 0 - assert dmp_discriminant([[1,0]], 1, ZZ) == [] + assert R.dmp_discriminant(x**3 + 3*x**2 + 9*x - 13) == -11664 + assert R.dmp_discriminant(5*x**5 + x**3 + 2) == 31252160 + assert R.dmp_discriminant(x**4 + 2*x**3 + 6*x**2 - 22*x + 13) == 0 + assert R.dmp_discriminant(12*x**7 + 15*x**4 + 30*x**3 + x**2 + 1) == -220289699947514112 - assert dmp_discriminant([1,3,9,-13], 0, ZZ) == -11664 - assert dmp_discriminant([5,0,1,0,0,2], 0, ZZ) == 31252160 - assert dmp_discriminant([1,2,6,-22,13], 0, ZZ) == 0 - assert dmp_discriminant([12,0,0,15,30,1,0,1], 0, ZZ) == -220289699947514112 + assert R.dmp_discriminant(x**2*y + 2*y) == (-8*y**2).drop(x) + assert R.dmp_discriminant(x*y**2 + 2*x) == 1 - assert dmp_discriminant([[1,0],[],[2,0]], 1, ZZ) == [-8,0,0] - assert dmp_discriminant([[1,0,2],[]], 1, ZZ) == [1] + R, x, y, z = ring("x,y,z", ZZ) + assert R.dmp_discriminant(x*y + z) == 1 - assert dmp_discriminant([[[1],[]],[[1,0]]], 2, ZZ) == [[1]] + R, x, y, z, u = ring("x,y,z,u", ZZ) + assert R.dmp_discriminant(x**2*y + x*z + u) == (-4*y*u + z**2).drop(x) + + R, x, y, z, u, v = ring("x,y,z,u,v", ZZ) + assert R.dmp_discriminant(x**3*y + x**2*z + x*u + v) == \ + (-27*y**2*v**2 + 18*y*z*u*v - 4*y*u**3 - 4*z**3*v + z**2*u**2).drop(x) - assert dmp_discriminant([[[[1]],[[]]],[[[1],[]]],[[[1,0]]]], 3, ZZ) == \ - [[[-4, 0]], [[1], [], []]] - assert dmp_discriminant([[[[[1]]],[[[]]]],[[[[1]],[[]]]],[[[[1],[]]]],[[[[1,0]]]]], 4, ZZ) == \ - [[[[-27,0,0]]],[[[18,0],[]],[[-4],[],[],[]]],[[[-4,0]],[[1],[],[]],[[]],[[]]]] def test_dup_gcd(): - assert dup_zz_heu_gcd([], [], ZZ) == ([], [], []) - assert dup_rr_prs_gcd([], [], ZZ) == ([], [], []) + R, x = ring("x", ZZ) + + f, g = 0, 0 + assert R.dup_zz_heu_gcd(f, g) == R.dup_rr_prs_gcd(f, g) == (0, 0, 0) + + f, g = 2, 0 + assert R.dup_zz_heu_gcd(f, g) == R.dup_rr_prs_gcd(f, g) == (2, 1, 0) + + f, g = -2, 0 + assert R.dup_zz_heu_gcd(f, g) == R.dup_rr_prs_gcd(f, g) == (2, -1, 0) - assert dup_zz_heu_gcd([2], [], ZZ) == ([2], [1], []) - assert dup_rr_prs_gcd([2], [], ZZ) == ([2], [1], []) + f, g = 0, -2 + assert R.dup_zz_heu_gcd(f, g) == R.dup_rr_prs_gcd(f, g) == (2, 0, -1) - assert dup_zz_heu_gcd([-2], [], ZZ) == ([2], [-1], []) - assert dup_rr_prs_gcd([-2], [], ZZ) == ([2], [-1], []) + f, g = 0, 2*x + 4 + assert R.dup_zz_heu_gcd(f, g) == R.dup_rr_prs_gcd(f, g) == (2*x + 4, 0, 1) - assert dup_zz_heu_gcd([], [-2], ZZ) == ([2], [], [-1]) - assert dup_rr_prs_gcd([], [-2], ZZ) == ([2], [], [-1]) + f, g = 2*x + 4, 0 + assert R.dup_zz_heu_gcd(f, g) == R.dup_rr_prs_gcd(f, g) == (2*x + 4, 1, 0) - assert dup_zz_heu_gcd([], [2,4], ZZ) == ([2,4], [], [1]) - assert dup_rr_prs_gcd([], [2,4], ZZ) == ([2,4], [], [1]) + f, g = 2, 2 + assert R.dup_zz_heu_gcd(f, g) == R.dup_rr_prs_gcd(f, g) == (2, 1, 1) - assert dup_zz_heu_gcd([2,4], [], ZZ) == ([2,4], [1], []) - assert dup_rr_prs_gcd([2,4], [], ZZ) == ([2,4], [1], []) + f, g = -2, 2 + assert R.dup_zz_heu_gcd(f, g) == R.dup_rr_prs_gcd(f, g) == (2, -1, 1) - assert dup_zz_heu_gcd([2], [2], ZZ) == ([2], [1], [1]) - assert dup_rr_prs_gcd([2], [2], ZZ) == ([2], [1], [1]) + f, g = 2, -2 + assert R.dup_zz_heu_gcd(f, g) == R.dup_rr_prs_gcd(f, g) == (2, 1, -1) - assert dup_zz_heu_gcd([-2], [2], ZZ) == ([2], [-1], [1]) - assert dup_rr_prs_gcd([-2], [2], ZZ) == ([2], [-1], [1]) + f, g = -2, -2 + assert R.dup_zz_heu_gcd(f, g) == R.dup_rr_prs_gcd(f, g) == (2, -1, -1) - assert dup_zz_heu_gcd([2], [-2], ZZ) == ([2], [1], [-1]) - assert dup_rr_prs_gcd([2], [-2], ZZ) == ([2], [1], [-1]) + f, g = x**2 + 2*x + 1, 1 + assert R.dup_zz_heu_gcd(f, g) == R.dup_rr_prs_gcd(f, g) == (1, x**2 + 2*x + 1, 1) - assert dup_zz_heu_gcd([-2], [-2], ZZ) == ([2], [-1], [-1]) - assert dup_rr_prs_gcd([-2], [-2], ZZ) == ([2], [-1], [-1]) + f, g = x**2 + 2*x + 1, 2 + assert R.dup_zz_heu_gcd(f, g) == R.dup_rr_prs_gcd(f, g) == (1, x**2 + 2*x + 1, 2) - assert dup_zz_heu_gcd([1,2,1], [1], ZZ) == ([1], [1, 2, 1], [1]) - assert dup_rr_prs_gcd([1,2,1], [1], ZZ) == ([1], [1, 2, 1], [1]) + f, g = 2*x**2 + 4*x + 2, 2 + assert R.dup_zz_heu_gcd(f, g) == R.dup_rr_prs_gcd(f, g) == (2, x**2 + 2*x + 1, 1) - assert dup_zz_heu_gcd([1,2,1], [2], ZZ) == ([1], [1, 2, 1], [2]) - assert dup_rr_prs_gcd([1,2,1], [2], ZZ) == ([1], [1, 2, 1], [2]) + f, g = 2, 2*x**2 + 4*x + 2 + assert R.dup_zz_heu_gcd(f, g) == R.dup_rr_prs_gcd(f, g) == (2, 1, x**2 + 2*x + 1) - assert dup_zz_heu_gcd([2,4,2], [2], ZZ) == ([2], [1, 2, 1], [1]) - assert dup_rr_prs_gcd([2,4,2], [2], ZZ) == ([2], [1, 2, 1], [1]) + f, g = 2*x**2 + 4*x + 2, x + 1 + assert R.dup_zz_heu_gcd(f, g) == R.dup_rr_prs_gcd(f, g) == (x + 1, 2*x + 2, 1) - assert dup_zz_heu_gcd([2], [2,4,2], ZZ) == ([2], [1], [1, 2, 1]) - assert dup_rr_prs_gcd([2], [2,4,2], ZZ) == ([2], [1], [1, 2, 1]) + f, g = x + 1, 2*x**2 + 4*x + 2 + assert R.dup_zz_heu_gcd(f, g) == R.dup_rr_prs_gcd(f, g) == (x + 1, 1, 2*x + 2) - assert dup_zz_heu_gcd([2,4,2], [1,1], ZZ) == ([1, 1], [2, 2], [1]) - assert dup_rr_prs_gcd([2,4,2], [1,1], ZZ) == ([1, 1], [2, 2], [1]) + f, g = x - 31, x + assert R.dup_zz_heu_gcd(f, g) == R.dup_rr_prs_gcd(f, g) == (1, f, g) - assert dup_zz_heu_gcd([1,1], [2,4,2], ZZ) == ([1, 1], [1], [2, 2]) - assert dup_rr_prs_gcd([1,1], [2,4,2], ZZ) == ([1, 1], [1], [2, 2]) + f = x**4 + 8*x**3 + 21*x**2 + 22*x + 8 + g = x**3 + 6*x**2 + 11*x + 6 - f, g = [1, -31], [1, 0] + h = x**2 + 3*x + 2 - assert dup_zz_heu_gcd(f, g, ZZ) == ([1], f, g) - assert dup_rr_prs_gcd(f, g, ZZ) == ([1], f, g) + cff = x**2 + 5*x + 4 + cfg = x + 3 - f = [1,8,21,22,8] - g = [1,6,11,6] + assert R.dup_zz_heu_gcd(f, g) == (h, cff, cfg) + assert R.dup_rr_prs_gcd(f, g) == (h, cff, cfg) - h = [1,3,2] + f = x**4 - 4 + g = x**4 + 4*x**2 + 4 - cff = [1,5,4] - cfg = [1,3] + h = x**2 + 2 - assert dup_zz_heu_gcd(f, g, ZZ) == (h, cff, cfg) - assert dup_rr_prs_gcd(f, g, ZZ) == (h, cff, cfg) + cff = x**2 - 2 + cfg = x**2 + 2 - f = [1,0,0,0,-4] - g = [1,0,4,0, 4] + assert R.dup_zz_heu_gcd(f, g) == (h, cff, cfg) + assert R.dup_rr_prs_gcd(f, g) == (h, cff, cfg) - h = [1,0,2] + f = x**8 + x**6 - 3*x**4 - 3*x**3 + 8*x**2 + 2*x - 5 + g = 3*x**6 + 5*x**4 - 4*x**2 - 9*x + 21 - cff = [1,0,-2] - cfg = [1,0, 2] + h = 1 - assert dup_zz_heu_gcd(f, g, ZZ) == (h, cff, cfg) - assert dup_rr_prs_gcd(f, g, ZZ) == (h, cff, cfg) + cff = f + cfg = g + + assert R.dup_zz_heu_gcd(f, g) == (h, cff, cfg) + assert R.dup_rr_prs_gcd(f, g) == (h, cff, cfg) + + R, x = ring("x", QQ) - f = [1,0,1,0,-3,-3,8,2,-5] - g = [3,0,5,-0,-4,-9,21] + f = x**8 + x**6 - 3*x**4 - 3*x**3 + 8*x**2 + 2*x - 5 + g = 3*x**6 + 5*x**4 - 4*x**2 - 9*x + 21 - h = [1] + h = 1 cff = f cfg = g - assert dup_zz_heu_gcd(f, g, ZZ) == (h, cff, cfg) - assert dup_rr_prs_gcd(f, g, ZZ) == (h, cff, cfg) + assert R.dup_qq_heu_gcd(f, g) == (h, cff, cfg) + assert R.dup_ff_prs_gcd(f, g) == (h, cff, cfg) + + R, x = ring("x", ZZ) + + f = - 352518131239247345597970242177235495263669787845475025293906825864749649589178600387510272*x**49 \ + + 46818041807522713962450042363465092040687472354933295397472942006618953623327997952*x**42 \ + + 378182690892293941192071663536490788434899030680411695933646320291525827756032*x**35 \ + + 112806468807371824947796775491032386836656074179286744191026149539708928*x**28 \ + - 12278371209708240950316872681744825481125965781519138077173235712*x**21 \ + + 289127344604779611146960547954288113529690984687482920704*x**14 \ + + 19007977035740498977629742919480623972236450681*x**7 \ + + 311973482284542371301330321821976049 + + g = 365431878023781158602430064717380211405897160759702125019136*x**21 \ + + 197599133478719444145775798221171663643171734081650688*x**14 \ + - 9504116979659010018253915765478924103928886144*x**7 \ + - 311973482284542371301330321821976049 + + assert R.dup_zz_heu_gcd(f, R.dup_diff(f, 1))[0] == g + assert R.dup_rr_prs_gcd(f, R.dup_diff(f, 1))[0] == g - f = dup_normal([1,0,1,0,-3,-3,8,2,-5], QQ) - g = dup_normal([3,0,5,-0,-4,-9,21], QQ) + R, x = ring("x", QQ) - h = dup_normal([1], QQ) + f = QQ(1,2)*x**2 + x + QQ(1,2) + g = QQ(1,2)*x + QQ(1,2) - assert dup_qq_heu_gcd(f, g, QQ) == (h, cff, cfg) - assert dup_ff_prs_gcd(f, g, QQ) == (h, cff, cfg) - - f = [-352518131239247345597970242177235495263669787845475025293906825864749649589178600387510272, - 0, 0, 0, 0, 0, 0, - 46818041807522713962450042363465092040687472354933295397472942006618953623327997952, - 0, 0, 0, 0, 0, 0, - 378182690892293941192071663536490788434899030680411695933646320291525827756032, - 0, 0, 0, 0, 0, 0, - 112806468807371824947796775491032386836656074179286744191026149539708928, - 0, 0, 0, 0, 0, 0, - -12278371209708240950316872681744825481125965781519138077173235712, - 0, 0, 0, 0, 0, 0, - 289127344604779611146960547954288113529690984687482920704, - 0, 0, 0, 0, 0, 0, - 19007977035740498977629742919480623972236450681, - 0, 0, 0, 0, 0, 0, - 311973482284542371301330321821976049] - - g = [365431878023781158602430064717380211405897160759702125019136, - 0, 0, 0, 0, 0, 0, - 197599133478719444145775798221171663643171734081650688, - 0, 0, 0, 0, 0, 0, - -9504116979659010018253915765478924103928886144, - 0, 0, 0, 0, 0, 0, - -311973482284542371301330321821976049] - - f = dup_normal(f, ZZ) - g = dup_normal(g, ZZ) - - assert dup_zz_heu_gcd(f, dup_diff(f, 1, ZZ), ZZ)[0] == g - assert dup_rr_prs_gcd(f, dup_diff(f, 1, ZZ), ZZ)[0] == g - - f = [QQ(1,2),QQ(1),QQ(1,2)] - g = [QQ(1,2),QQ(1,2)] - - h = [QQ(1), QQ(1)] - - assert dup_qq_heu_gcd(f, g, QQ) == (h, g, [QQ(1,2)]) - assert dup_ff_prs_gcd(f, g, QQ) == (h, g, [QQ(1,2)]) - - f = ZZ.map([1317378933230047068160, 2945748836994210856960]) - g = ZZ.map([120352542776360960, 269116466014453760]) - - h = ZZ.map([120352542776360960, 269116466014453760]) - cff = ZZ.map([10946]) - cfg = ZZ.map([1]) + h = x + 1 + + assert R.dup_qq_heu_gcd(f, g) == (h, g, QQ(1,2)) + assert R.dup_ff_prs_gcd(f, g) == (h, g, QQ(1,2)) + + R, x = ring("x", ZZ) + + f = 1317378933230047068160*x + 2945748836994210856960 + g = 120352542776360960*x + 269116466014453760 + + h = 120352542776360960*x + 269116466014453760 + cff = 10946 + cfg = 1 + + assert R.dup_zz_heu_gcd(f, g) == (h, cff, cfg) - assert dup_zz_heu_gcd(f, g, ZZ) == (h, cff, cfg) def test_dmp_gcd(): - assert dmp_zz_heu_gcd([[]], [[]], 1, ZZ) == ([[]], [[]], [[]]) - assert dmp_rr_prs_gcd([[]], [[]], 1, ZZ) == ([[]], [[]], [[]]) + R, x, y = ring("x,y", ZZ) + + f, g = 0, 0 + assert R.dmp_zz_heu_gcd(f, g) == R.dmp_rr_prs_gcd(f, g) == (0, 0, 0) + + f, g = 2, 0 + assert R.dmp_zz_heu_gcd(f, g) == R.dmp_rr_prs_gcd(f, g) == (2, 1, 0) + + f, g = -2, 0 + assert R.dmp_zz_heu_gcd(f, g) == R.dmp_rr_prs_gcd(f, g) == (2, -1, 0) + + f, g = 0, -2 + assert R.dmp_zz_heu_gcd(f, g) == R.dmp_rr_prs_gcd(f, g) == (2, 0, -1) - assert dmp_zz_heu_gcd([[2]], [[]], 1, ZZ) == ([[2]], [[1]], [[]]) - assert dmp_rr_prs_gcd([[2]], [[]], 1, ZZ) == ([[2]], [[1]], [[]]) + f, g = 0, 2*x + 4 + assert R.dmp_zz_heu_gcd(f, g) == R.dmp_rr_prs_gcd(f, g) == (2*x + 4, 0, 1) - assert dmp_zz_heu_gcd([[-2]], [[]], 1, ZZ) == ([[2]], [[-1]], [[]]) - assert dmp_rr_prs_gcd([[-2]], [[]], 1, ZZ) == ([[2]], [[-1]], [[]]) + f, g = 2*x + 4, 0 + assert R.dmp_zz_heu_gcd(f, g) == R.dmp_rr_prs_gcd(f, g) == (2*x + 4, 1, 0) - assert dmp_zz_heu_gcd([[]], [[-2]], 1, ZZ) == ([[2]], [[]], [[-1]]) - assert dmp_rr_prs_gcd([[]], [[-2]], 1, ZZ) == ([[2]], [[]], [[-1]]) + f, g = 2, 2 + assert R.dmp_zz_heu_gcd(f, g) == R.dmp_rr_prs_gcd(f, g) == (2, 1, 1) - assert dmp_zz_heu_gcd([[]], [[2],[4]], 1, ZZ) == ([[2],[4]], [[]], [[1]]) - assert dmp_rr_prs_gcd([[]], [[2],[4]], 1, ZZ) == ([[2],[4]], [[]], [[1]]) + f, g = -2, 2 + assert R.dmp_zz_heu_gcd(f, g) == R.dmp_rr_prs_gcd(f, g) == (2, -1, 1) - assert dmp_zz_heu_gcd([[2],[4]], [[]], 1, ZZ) == ([[2],[4]], [[1]], [[]]) - assert dmp_rr_prs_gcd([[2],[4]], [[]], 1, ZZ) == ([[2],[4]], [[1]], [[]]) + f, g = 2, -2 + assert R.dmp_zz_heu_gcd(f, g) == R.dmp_rr_prs_gcd(f, g) == (2, 1, -1) - assert dmp_zz_heu_gcd([[2]], [[2]], 1, ZZ) == ([[2]], [[1]], [[1]]) - assert dmp_rr_prs_gcd([[2]], [[2]], 1, ZZ) == ([[2]], [[1]], [[1]]) + f, g = -2, -2 + assert R.dmp_zz_heu_gcd(f, g) == R.dmp_rr_prs_gcd(f, g) == (2, -1, -1) - assert dmp_zz_heu_gcd([[-2]], [[2]], 1, ZZ) == ([[2]], [[-1]], [[1]]) - assert dmp_rr_prs_gcd([[-2]], [[2]], 1, ZZ) == ([[2]], [[-1]], [[1]]) + f, g = x**2 + 2*x + 1, 1 + assert R.dmp_zz_heu_gcd(f, g) == R.dmp_rr_prs_gcd(f, g) == (1, x**2 + 2*x + 1, 1) - assert dmp_zz_heu_gcd([[2]], [[-2]], 1, ZZ) == ([[2]], [[1]], [[-1]]) - assert dmp_rr_prs_gcd([[2]], [[-2]], 1, ZZ) == ([[2]], [[1]], [[-1]]) + f, g = x**2 + 2*x + 1, 2 + assert R.dmp_zz_heu_gcd(f, g) == R.dmp_rr_prs_gcd(f, g) == (1, x**2 + 2*x + 1, 2) - assert dmp_zz_heu_gcd([[-2]], [[-2]], 1, ZZ) == ([[2]], [[-1]], [[-1]]) - assert dmp_rr_prs_gcd([[-2]], [[-2]], 1, ZZ) == ([[2]], [[-1]], [[-1]]) + f, g = 2*x**2 + 4*x + 2, 2 + assert R.dmp_zz_heu_gcd(f, g) == R.dmp_rr_prs_gcd(f, g) == (2, x**2 + 2*x + 1, 1) - assert dmp_zz_heu_gcd([[1],[2],[1]], [[1]], 1, ZZ) == ([[1]], [[1], [2], [1]], [[1]]) - assert dmp_rr_prs_gcd([[1],[2],[1]], [[1]], 1, ZZ) == ([[1]], [[1], [2], [1]], [[1]]) + f, g = 2, 2*x**2 + 4*x + 2 + assert R.dmp_zz_heu_gcd(f, g) == R.dmp_rr_prs_gcd(f, g) == (2, 1, x**2 + 2*x + 1) - assert dmp_zz_heu_gcd([[1],[2],[1]], [[2]], 1, ZZ) == ([[1]], [[1], [2], [1]], [[2]]) - assert dmp_rr_prs_gcd([[1],[2],[1]], [[2]], 1, ZZ) == ([[1]], [[1], [2], [1]], [[2]]) + f, g = 2*x**2 + 4*x + 2, x + 1 + assert R.dmp_zz_heu_gcd(f, g) == R.dmp_rr_prs_gcd(f, g) == (x + 1, 2*x + 2, 1) - assert dmp_zz_heu_gcd([[2],[4],[2]], [[2]], 1, ZZ) == ([[2]], [[1], [2], [1]], [[1]]) - assert dmp_rr_prs_gcd([[2],[4],[2]], [[2]], 1, ZZ) == ([[2]], [[1], [2], [1]], [[1]]) + f, g = x + 1, 2*x**2 + 4*x + 2 + assert R.dmp_zz_heu_gcd(f, g) == R.dmp_rr_prs_gcd(f, g) == (x + 1, 1, 2*x + 2) - assert dmp_zz_heu_gcd([[2]], [[2],[4],[2]], 1, ZZ) == ([[2]], [[1]], [[1], [2], [1]]) - assert dmp_rr_prs_gcd([[2]], [[2],[4],[2]], 1, ZZ) == ([[2]], [[1]], [[1], [2], [1]]) + R, x, y, z, u = ring("x,y,z,u", ZZ) - assert dmp_zz_heu_gcd([[2],[4],[2]], [[1],[1]], 1, ZZ) == ([[1], [1]], [[2], [2]], [[1]]) - assert dmp_rr_prs_gcd([[2],[4],[2]], [[1],[1]], 1, ZZ) == ([[1], [1]], [[2], [2]], [[1]]) + f, g = u**2 + 2*u + 1, 2*u + 2 + assert R.dmp_zz_heu_gcd(f, g) == R.dmp_rr_prs_gcd(f, g) == (u + 1, u + 1, 2) - assert dmp_zz_heu_gcd([[1],[1]], [[2],[4],[2]], 1, ZZ) == ([[1], [1]], [[1]], [[2], [2]]) - assert dmp_rr_prs_gcd([[1],[1]], [[2],[4],[2]], 1, ZZ) == ([[1], [1]], [[1]], [[2], [2]]) + f, g = z**2*u**2 + 2*z**2*u + z**2 + z*u + z, u**2 + 2*u + 1 + h, cff, cfg = u + 1, z**2*u + z**2 + z, u + 1 - assert dmp_zz_heu_gcd([[[[1,2,1]]]], [[[[2,2]]]], 3, ZZ) == ([[[[1,1]]]], [[[[1,1]]]], [[[[2]]]]) - assert dmp_rr_prs_gcd([[[[1,2,1]]]], [[[[2,2]]]], 3, ZZ) == ([[[[1,1]]]], [[[[1,1]]]], [[[[2]]]]) + assert R.dmp_zz_heu_gcd(f, g) == (h, cff, cfg) + assert R.dmp_rr_prs_gcd(f, g) == (h, cff, cfg) - f, g = [[[[1,2,1],[1,1],[]]]], [[[[1,2,1]]]] - h, cff, cfg = [[[[1,1]]]], [[[[1,1],[1],[]]]], [[[[1,1]]]] + assert R.dmp_zz_heu_gcd(g, f) == (h, cfg, cff) + assert R.dmp_rr_prs_gcd(g, f) == (h, cfg, cff) - assert dmp_zz_heu_gcd(f, g, 3, ZZ) == (h, cff, cfg) - assert dmp_rr_prs_gcd(f, g, 3, ZZ) == (h, cff, cfg) + R, x, y, z = ring("x,y,z", ZZ) - assert dmp_zz_heu_gcd(g, f, 3, ZZ) == (h, cfg, cff) - assert dmp_rr_prs_gcd(g, f, 3, ZZ) == (h, cfg, cff) + f, g, h = list(map(R.from_dense, dmp_fateman_poly_F_1(2, ZZ))) + H, cff, cfg = R.dmp_zz_heu_gcd(f, g) - f, g, h = dmp_fateman_poly_F_1(2, ZZ) - H, cff, cfg = dmp_zz_heu_gcd(f, g, 2, ZZ) + assert H == h and R.dmp_mul(H, cff) == f \ + and R.dmp_mul(H, cfg) == g - assert H == h and dmp_mul(H, cff, 2, ZZ) == f \ - and dmp_mul(H, cfg, 2, ZZ) == g + H, cff, cfg = R.dmp_rr_prs_gcd(f, g) - H, cff, cfg = dmp_rr_prs_gcd(f, g, 2, ZZ) + assert H == h and R.dmp_mul(H, cff) == f \ + and R.dmp_mul(H, cfg) == g - assert H == h and dmp_mul(H, cff, 2, ZZ) == f \ - and dmp_mul(H, cfg, 2, ZZ) == g + R, x, y, z, u, v = ring("x,y,z,u,v", ZZ) - f, g, h = dmp_fateman_poly_F_1(4, ZZ) - H, cff, cfg = dmp_zz_heu_gcd(f, g, 4, ZZ) + f, g, h = list(map(R.from_dense, dmp_fateman_poly_F_1(4, ZZ))) + H, cff, cfg = R.dmp_zz_heu_gcd(f, g) - assert H == h and dmp_mul(H, cff, 4, ZZ) == f \ - and dmp_mul(H, cfg, 4, ZZ) == g + assert H == h and R.dmp_mul(H, cff) == f \ + and R.dmp_mul(H, cfg) == g - f, g, h = dmp_fateman_poly_F_1(6, ZZ) - H, cff, cfg = dmp_zz_heu_gcd(f, g, 6, ZZ) + R, x, y, z, u, v, a, b = ring("x,y,z,u,v,a,b", ZZ) - assert H == h and dmp_mul(H, cff, 6, ZZ) == f \ - and dmp_mul(H, cfg, 6, ZZ) == g + f, g, h = list(map(R.from_dense, dmp_fateman_poly_F_1(6, ZZ))) + H, cff, cfg = R.dmp_zz_heu_gcd(f, g) - f, g, h = dmp_fateman_poly_F_1(8, ZZ) + assert H == h and R.dmp_mul(H, cff) == f \ + and R.dmp_mul(H, cfg) == g - H, cff, cfg = dmp_zz_heu_gcd(f, g, 8, ZZ) + R, x, y, z, u, v, a, b, c, d = ring("x,y,z,u,v,a,b,c,d", ZZ) - assert H == h and dmp_mul(H, cff, 8, ZZ) == f \ - and dmp_mul(H, cfg, 8, ZZ) == g + f, g, h = list(map(R.from_dense, dmp_fateman_poly_F_1(8, ZZ))) + H, cff, cfg = R.dmp_zz_heu_gcd(f, g) - f, g, h = dmp_fateman_poly_F_2(2, ZZ) - H, cff, cfg = dmp_zz_heu_gcd(f, g, 2, ZZ) + assert H == h and R.dmp_mul(H, cff) == f \ + and R.dmp_mul(H, cfg) == g - assert H == h and dmp_mul(H, cff, 2, ZZ) == f \ - and dmp_mul(H, cfg, 2, ZZ) == g + R, x, y, z = ring("x,y,z", ZZ) - H, cff, cfg = dmp_rr_prs_gcd(f, g, 2, ZZ) + f, g, h = list(map(R.from_dense, dmp_fateman_poly_F_2(2, ZZ))) + H, cff, cfg = R.dmp_zz_heu_gcd(f, g) - assert H == h and dmp_mul(H, cff, 2, ZZ) == f \ - and dmp_mul(H, cfg, 2, ZZ) == g + assert H == h and R.dmp_mul(H, cff) == f \ + and R.dmp_mul(H, cfg) == g - f, g, h = dmp_fateman_poly_F_3(2, ZZ) - H, cff, cfg = dmp_zz_heu_gcd(f, g, 2, ZZ) + H, cff, cfg = R.dmp_rr_prs_gcd(f, g) - assert H == h and dmp_mul(H, cff, 2, ZZ) == f \ - and dmp_mul(H, cfg, 2, ZZ) == g + assert H == h and R.dmp_mul(H, cff) == f \ + and R.dmp_mul(H, cfg) == g - H, cff, cfg = dmp_rr_prs_gcd(f, g, 2, ZZ) + f, g, h = list(map(R.from_dense, dmp_fateman_poly_F_3(2, ZZ))) + H, cff, cfg = R.dmp_zz_heu_gcd(f, g) - assert H == h and dmp_mul(H, cff, 2, ZZ) == f \ - and dmp_mul(H, cfg, 2, ZZ) == g + assert H == h and R.dmp_mul(H, cff) == f \ + and R.dmp_mul(H, cfg) == g - f, g, h = dmp_fateman_poly_F_3(4, ZZ) - H, cff, cfg = dmp_inner_gcd(f, g, 4, ZZ) + H, cff, cfg = R.dmp_rr_prs_gcd(f, g) - assert H == h and dmp_mul(H, cff, 4, ZZ) == f \ - and dmp_mul(H, cfg, 4, ZZ) == g + assert H == h and R.dmp_mul(H, cff) == f \ + and R.dmp_mul(H, cfg) == g - f = [[QQ(1,2)],[QQ(1)],[QQ(1,2)]] - g = [[QQ(1,2)],[QQ(1,2)]] + R, x, y, z, u, v = ring("x,y,z,u,v", ZZ) - h = [[QQ(1)],[QQ(1)]] + f, g, h = list(map(R.from_dense, dmp_fateman_poly_F_3(4, ZZ))) + H, cff, cfg = R.dmp_inner_gcd(f, g) - assert dmp_qq_heu_gcd(f, g, 1, QQ) == (h, g, [[QQ(1,2)]]) - assert dmp_ff_prs_gcd(f, g, 1, QQ) == (h, g, [[QQ(1,2)]]) + assert H == h and R.dmp_mul(H, cff) == f \ + and R.dmp_mul(H, cfg) == g - f = [[RR(2.1), RR(-2.2), RR(2.1)], []] - g = [[RR(1.0)], [], [], []] + R, x, y = ring("x,y", QQ) + + f = QQ(1,2)*x**2 + x + QQ(1,2) + g = QQ(1,2)*x + QQ(1,2) + + h = x + 1 + + assert R.dmp_qq_heu_gcd(f, g) == (h, g, QQ(1,2)) + assert R.dmp_ff_prs_gcd(f, g) == (h, g, QQ(1,2)) + + R, x, y = ring("x,y", RR) + + f = 2.1*x*y**2 - 2.2*x*y + 2.1*x + g = 1.0*x**3 + + assert R.dmp_ff_prs_gcd(f, g) == \ + (1.0*x, 2.1*y**2 - 2.2*y + 2.1, 1.0*x**2) - assert dmp_ff_prs_gcd(f, g, 1, RR) == \ - ([[RR(1.0)], []], [[RR(2.1), RR(-2.2), RR(2.1)]], [[RR(1.0)], [], []]) def test_dup_lcm(): - assert dup_lcm([2], [6], ZZ) == [6] + R, x = ring("x", ZZ) + + assert R.dup_lcm(2, 6) == 6 + + assert R.dup_lcm(2*x**3, 6*x) == 6*x**3 + assert R.dup_lcm(2*x**3, 3*x) == 6*x**3 - assert dup_lcm([2,0,0,0], [6,0], ZZ) == [6,0,0,0] - assert dup_lcm([2,0,0,0], [3,0], ZZ) == [6,0,0,0] + assert R.dup_lcm(x**2 + x, x) == x**2 + x + assert R.dup_lcm(x**2 + x, 2*x) == 2*x**2 + 2*x + assert R.dup_lcm(x**2 + 2*x, x) == x**2 + 2*x + assert R.dup_lcm(2*x**2 + x, x) == 2*x**2 + x + assert R.dup_lcm(2*x**2 + x, 2*x) == 4*x**2 + 2*x - assert dup_lcm([1,1,0], [1,0], ZZ) == [1,1,0] - assert dup_lcm([1,1,0], [2,0], ZZ) == [2,2,0] - assert dup_lcm([1,2,0], [1,0], ZZ) == [1,2,0] - assert dup_lcm([2,1,0], [1,0], ZZ) == [2,1,0] - assert dup_lcm([2,1,0], [2,0], ZZ) == [4,2,0] def test_dmp_lcm(): - assert dmp_lcm([[2]], [[6]], 1, ZZ) == [[6]] - assert dmp_lcm([[1],[]], [[1,0]], 1, ZZ) == [[1,0],[]] + R, x, y = ring("x,y", ZZ) - assert dmp_lcm([[2],[],[],[]], [[6,0,0],[]], 1, ZZ) == [[6,0,0],[],[],[]] - assert dmp_lcm([[2],[],[],[]], [[3,0,0],[]], 1, ZZ) == [[6,0,0],[],[],[]] + assert R.dmp_lcm(2, 6) == 6 + assert R.dmp_lcm(x, y) == x*y - assert dmp_lcm([[1,0],[],[]], [[1,0,0],[]], 1, ZZ) == [[1,0,0],[],[]] + assert R.dmp_lcm(2*x**3, 6*x*y**2) == 6*x**3*y**2 + assert R.dmp_lcm(2*x**3, 3*x*y**2) == 6*x**3*y**2 - f = [[2,-3,-2,3,0,0],[]] - g = [[1,0,-2,0,1,0]] - h = [[2,-3,-4,6,2,-3,0,0],[]] + assert R.dmp_lcm(x**2*y, x*y**2) == x**2*y**2 - assert dmp_lcm(f, g, 1, ZZ) == h + f = 2*x*y**5 - 3*x*y**4 - 2*x*y**3 + 3*x*y**2 + g = y**5 - 2*y**3 + y + h = 2*x*y**7 - 3*x*y**6 - 4*x*y**5 + 6*x*y**4 + 2*x*y**3 - 3*x*y**2 - f = [[1],[-3,0],[-9,0,0],[-5,0,0,0]] - g = [[1],[6,0],[12,0,0],[10,0,0,0],[3,0,0,0,0]] - h = [[1],[1,0],[-18,0,0],[-50,0,0,0],[-47,0,0,0,0],[-15,0,0,0,0,0]] + assert R.dmp_lcm(f, g) == h + + f = x**3 - 3*x**2*y - 9*x*y**2 - 5*y**3 + g = x**4 + 6*x**3*y + 12*x**2*y**2 + 10*x*y**3 + 3*y**4 + h = x**5 + x**4*y - 18*x**3*y**2 - 50*x**2*y**3 - 47*x*y**4 - 15*y**5 + + assert R.dmp_lcm(f, g) == h - assert dmp_lcm(f, g, 1, ZZ) == h def test_dmp_content(): - assert dmp_content([[-2]], 1, ZZ) == [2] + R, x,y = ring("x,y", ZZ) - f, g, F = [ZZ(3),ZZ(2),ZZ(1)], [ZZ(1)], [] + assert R.dmp_content(-2) == 2 + + f, g, F = 3*y**2 + 2*y + 1, 1, 0 for i in range(0, 5): - g = dup_mul(g, f, ZZ) - F.insert(0, g) + g *= f + F += x**i*g + + assert R.dmp_content(F) == f.drop(x) - assert dmp_content(F, 1, ZZ) == f + R, x,y,z = ring("x,y,z", ZZ) + + assert R.dmp_content(f_4) == 1 + assert R.dmp_content(f_5) == 1 + + R, x,y,z,t = ring("x,y,z,t", ZZ) + assert R.dmp_content(f_6) == 1 - assert dmp_one_p(dmp_content(f_4, 2, ZZ), 1, ZZ) - assert dmp_one_p(dmp_content(f_5, 2, ZZ), 1, ZZ) - assert dmp_one_p(dmp_content(f_6, 3, ZZ), 2, ZZ) def test_dmp_primitive(): - assert dmp_primitive([[]], 1, ZZ) == ([], [[]]) - assert dmp_primitive([[1]], 1, ZZ) == ([1], [[1]]) + R, x,y = ring("x,y", ZZ) - f, g, F = [ZZ(3),ZZ(2),ZZ(1)], [ZZ(1)], [] + assert R.dmp_primitive(0) == (0, 0) + assert R.dmp_primitive(1) == (1, 1) + + f, g, F = 3*y**2 + 2*y + 1, 1, 0 for i in range(0, 5): - g = dup_mul(g, f, ZZ) - F.insert(0, g) + g *= f + F += x**i*g + + assert R.dmp_primitive(F) == (f.drop(x), F / f) - assert dmp_primitive(F, 1, ZZ) == (f, - [ dup_exquo(c, f, ZZ) for c in F ]) + R, x,y,z = ring("x,y,z", ZZ) + + cont, f = R.dmp_primitive(f_4) + assert cont == 1 and f == f_4 + cont, f = R.dmp_primitive(f_5) + assert cont == 1 and f == f_5 + + R, x,y,z,t = ring("x,y,z,t", ZZ) + + cont, f = R.dmp_primitive(f_6) + assert cont == 1 and f == f_6 - cont, f = dmp_primitive(f_4, 2, ZZ) - assert dmp_one_p(cont, 1, ZZ) and f == f_4 - cont, f = dmp_primitive(f_5, 2, ZZ) - assert dmp_one_p(cont, 1, ZZ) and f == f_5 - cont, f = dmp_primitive(f_6, 3, ZZ) - assert dmp_one_p(cont, 2, ZZ) and f == f_6 def test_dup_cancel(): - f = ZZ.map([2, 0, -2]) - g = ZZ.map([1, -2, 1]) + R, x = ring("x", ZZ) + + f = 2*x**2 - 2 + g = x**2 - 2*x + 1 - p = [ZZ(2), ZZ(2)] - q = [ZZ(1), -ZZ(1)] + p = 2*x + 2 + q = x - 1 - assert dup_cancel(f, g, ZZ) == (p, q) - assert dup_cancel(f, g, ZZ, include=False) == (ZZ(1), ZZ(1), p, q) + assert R.dup_cancel(f, g) == (p, q) + assert R.dup_cancel(f, g, include=False) == (1, 1, p, q) - f = [-ZZ(1),-ZZ(2)] - g = [ ZZ(3),-ZZ(4)] + f = -x - 2 + g = 3*x - 4 - F = [ ZZ(1), ZZ(2)] - G = [-ZZ(3), ZZ(4)] + F = x + 2 + G = -3*x + 4 - assert dup_cancel(f, g, ZZ) == (f, g) - assert dup_cancel(F, G, ZZ) == (f, g) + assert R.dup_cancel(f, g) == (f, g) + assert R.dup_cancel(F, G) == (f, g) - assert dup_cancel([], [], ZZ) == ([], []) - assert dup_cancel([], [], ZZ, include=False) == (ZZ(1), ZZ(1), [], []) + assert R.dup_cancel(0, 0) == (0, 0) + assert R.dup_cancel(0, 0, include=False) == (1, 1, 0, 0) - assert dup_cancel([ZZ(1), ZZ(0)], [], ZZ) == ([ZZ(1)], []) - assert dup_cancel([ZZ(1), ZZ(0)], [], ZZ, include=False) == (ZZ(1), ZZ(1), [ZZ(1)], []) + assert R.dup_cancel(x, 0) == (1, 0) + assert R.dup_cancel(x, 0, include=False) == (1, 1, 1, 0) + + assert R.dup_cancel(0, x) == (0, 1) + assert R.dup_cancel(0, x, include=False) == (1, 1, 0, 1) + + f = 0 + g = x + one = 1 + + assert R.dup_cancel(f, g, include=True) == (f, one) - assert dup_cancel([], [ZZ(1), ZZ(0)], ZZ) == ([], [ZZ(1)]) - assert dup_cancel([], [ZZ(1), ZZ(0)], ZZ, include=False) == (ZZ(1), ZZ(1), [], [ZZ(1)]) def test_dmp_cancel(): - f = ZZ.map([[2], [0], [-2]]) - g = ZZ.map([[1], [-2], [1]]) + R, x, y = ring("x,y", ZZ) + + f = 2*x**2 - 2 + g = x**2 - 2*x + 1 - p = [[ZZ(2)], [ZZ(2)]] - q = [[ZZ(1)], [-ZZ(1)]] + p = 2*x + 2 + q = x - 1 - assert dmp_cancel(f, g, 1, ZZ) == (p, q) - assert dmp_cancel(f, g, 1, ZZ, include=False) == (ZZ(1), ZZ(1), p, q) + assert R.dmp_cancel(f, g) == (p, q) + assert R.dmp_cancel(f, g, include=False) == (1, 1, p, q) - assert dmp_cancel([[]], [[]], 1, ZZ) == ([[]], [[]]) - assert dmp_cancel([[]], [[]], 1, ZZ, include=False) == (ZZ(1), ZZ(1), [[]], [[]]) + assert R.dmp_cancel(0, 0) == (0, 0) + assert R.dmp_cancel(0, 0, include=False) == (1, 1, 0, 0) - assert dmp_cancel([[ZZ(1), ZZ(0)]], [[]], 1, ZZ) == ([[ZZ(1)]], [[]]) - assert dmp_cancel([[ZZ(1), ZZ(0)]], [[]], 1, ZZ, include=False) == (ZZ(1), ZZ(1), [[ZZ(1)]], [[]]) + assert R.dmp_cancel(y, 0) == (1, 0) + assert R.dmp_cancel(y, 0, include=False) == (1, 1, 1, 0) - assert dmp_cancel([[]], [[ZZ(1), ZZ(0)]], 1, ZZ) == ([[]], [[ZZ(1)]]) - assert dmp_cancel([[]], [[ZZ(1), ZZ(0)]], 1, ZZ, include=False) == (ZZ(1), ZZ(1), [[]], [[ZZ(1)]]) + assert R.dmp_cancel(0, y) == (0, 1) + assert R.dmp_cancel(0, y, include=False) == (1, 1, 0, 1) diff -Nru python3-sympy-0.7.2/sympy/polys/tests/test_factortools.py python3-sympy-0.7.3/sympy/polys/tests/test_factortools.py --- python3-sympy-0.7.2/sympy/polys/tests/test_factortools.py 2012-10-17 03:02:22.000000000 +0000 +++ python3-sympy-0.7.3/sympy/polys/tests/test_factortools.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,724 +1,654 @@ """Tools for polynomial factorization routines in characteristic zero. """ -from sympy.polys.densearith import ( - dup_mul_ground, dmp_mul_ground, - dup_pow, dmp_pow, - dmp_expand) - -from sympy.polys.densebasic import ( - dup_degree, dmp_degree, - dup_normal, dmp_normal, - dup_from_raw_dict, dup_to_raw_dict, - dmp_from_dict, dmp_to_dict, - dmp_nest, dmp_raise) - -from sympy.polys.densetools import ( - dup_primitive, dmp_eval_tail) - -from sympy.polys.sqfreetools import ( - dup_sqf_p) - -from sympy.polys.factortools import ( - dup_trial_division, dmp_trial_division, - dup_zz_mignotte_bound, dmp_zz_mignotte_bound, - dup_zz_hensel_step, dup_zz_hensel_lift, - dup_zz_irreducible_p, - dup_zz_zassenhaus, dmp_zz_wang, - dmp_zz_wang_non_divisors, - dmp_zz_wang_test_points, - dmp_zz_wang_lead_coeffs, - dmp_zz_wang_hensel_lifting, - dup_zz_diophantine, dmp_zz_diophantine, - dup_cyclotomic_p, dup_zz_cyclotomic_poly, dup_zz_cyclotomic_factor, - dup_zz_factor, dup_zz_factor_sqf, dmp_zz_factor, - dup_ext_factor, dmp_ext_factor, - dup_factor_list, dmp_factor_list, - dup_factor_list_include, dmp_factor_list_include, - dup_irreducible_p, dmp_irreducible_p) - -from sympy.polys.specialpolys import ( - f_1, f_2, f_3, f_4, f_5, f_6, w_1, w_2) +from sympy.polys.rings import ring, xring +from sympy.polys.domains import FF, ZZ, QQ, RR, EX from sympy.polys import polyconfig as config from sympy.polys.polyerrors import DomainError from sympy.polys.polyclasses import DMP, DMF, ANP -from sympy.polys.domains import FF, ZZ, QQ, RR, EX +from sympy.polys.specialpolys import f_polys, w_polys from sympy import nextprime, sin, sqrt, I - from sympy.utilities.pytest import raises +f_0, f_1, f_2, f_3, f_4, f_5, f_6 = f_polys() +w_1, w_2 = w_polys() + def test_dup_trial_division(): - assert dup_trial_division([1,8,25,38,28,8], - ([1,1], [1,2]), ZZ) == [([1,1], 2), ([1,2], 3)] + R, x = ring("x", ZZ) + assert R.dup_trial_division(x**5 + 8*x**4 + 25*x**3 + 38*x**2 + 28*x + 8, (x + 1, x + 2)) == [(x + 1, 2), (x + 2, 3)] + def test_dmp_trial_division(): - assert dmp_trial_division([[1],[8],[25],[38],[28],[8]], - ([[1],[1]], [[1],[2]]), 1, ZZ) == [([[1],[1]], 2), ([[1],[2]], 3)] + R, x, y = ring("x,y", ZZ) + assert R.dmp_trial_division(x**5 + 8*x**4 + 25*x**3 + 38*x**2 + 28*x + 8, (x + 1, x + 2)) == [(x + 1, 2), (x + 2, 3)] + def test_dup_zz_mignotte_bound(): - assert dup_zz_mignotte_bound([2,3,4], ZZ) == 32 + R, x = ring("x", ZZ) + assert R.dup_zz_mignotte_bound(2*x**2 + 3*x + 4) == 32 + def test_dmp_zz_mignotte_bound(): - assert dmp_zz_mignotte_bound([[2],[3],[4]], 1, ZZ) == 32 + R, x, y = ring("x,y", ZZ) + assert R.dmp_zz_mignotte_bound(2*x**2 + 3*x + 4) == 32 + def test_dup_zz_hensel_step(): - f = dup_from_raw_dict({4:1, 0:-1}, ZZ) + R, x = ring("x", ZZ) + + f = x**4 - 1 + g = x**3 + 2*x**2 - x - 2 + h = x - 2 + s = -2 + t = 2*x**2 - 2*x - 1 + + G, H, S, T = R.dup_zz_hensel_step(5, f, g, h, s, t) + + assert G == x**3 + 7*x**2 - x - 7 + assert H == x - 7 + assert S == 8 + assert T == -8*x**2 - 12*x - 1 - g = dup_from_raw_dict({3:1, 2:2, 1:-1, 0:-2}, ZZ) - h = dup_from_raw_dict({1:1, 0:-2}, ZZ) - s = dup_from_raw_dict({0:-2}, ZZ) - t = dup_from_raw_dict({2:2, 1:-2, 0:-1}, ZZ) - - G, H, S, T = dup_zz_hensel_step(5, f, g, h, s, t, ZZ) - - assert G == dup_from_raw_dict({3:1, 2:7, 1:-1, 0:-7}, ZZ) - assert H == dup_from_raw_dict({1:1, 0:-7}, ZZ) - assert S == dup_from_raw_dict({0:8}, ZZ) - assert T == dup_from_raw_dict({2:-8, 1:-12, 0:-1}, ZZ) def test_dup_zz_hensel_lift(): - f = dup_from_raw_dict({4:1, 0:-1}, ZZ) + R, x = ring("x", ZZ) + + f = x**4 - 1 + F = [x - 1, x - 2, x + 2, x + 1] + + assert R.dup_zz_hensel_lift(ZZ(5), f, F, 4) == \ + [x - 1, x - 182, x + 182, x + 1] - f1 = dup_from_raw_dict({1:1, 0:-1}, ZZ) - f2 = dup_from_raw_dict({1:1, 0:-2}, ZZ) - f3 = dup_from_raw_dict({1:1, 0: 2}, ZZ) - f4 = dup_from_raw_dict({1:1, 0: 1}, ZZ) - - ff_list = dup_zz_hensel_lift(5, f, [f1, f2, f3, f4], 4, ZZ) - - assert dup_to_raw_dict(ff_list[0]) == {0: -1, 1: 1} - assert dup_to_raw_dict(ff_list[1]) == {0: -182, 1: 1} - assert dup_to_raw_dict(ff_list[2]) == {0: 182, 1: 1} - assert dup_to_raw_dict(ff_list[3]) == {0: 1, 1: 1} def test_dup_zz_irreducible_p(): - assert dup_zz_irreducible_p([3, 2, 6, 8, 7], ZZ) is None - assert dup_zz_irreducible_p([3, 2, 6, 8, 4], ZZ) is None + R, x = ring("x", ZZ) + + assert R.dup_zz_irreducible_p(3*x**4 + 2*x**3 + 6*x**2 + 8*x + 7) is None + assert R.dup_zz_irreducible_p(3*x**4 + 2*x**3 + 6*x**2 + 8*x + 4) is None + + assert R.dup_zz_irreducible_p(3*x**4 + 2*x**3 + 6*x**2 + 8*x + 10) is True + assert R.dup_zz_irreducible_p(3*x**4 + 2*x**3 + 6*x**2 + 8*x + 14) is True - assert dup_zz_irreducible_p([3, 2, 6, 8, 10], ZZ) == True - assert dup_zz_irreducible_p([3, 2, 6, 8, 14], ZZ) == True def test_dup_cyclotomic_p(): - assert dup_cyclotomic_p([1,-1], ZZ) == True - assert dup_cyclotomic_p([1,1], ZZ) == True - assert dup_cyclotomic_p([1,1,1], ZZ) == True - assert dup_cyclotomic_p([1,0,1], ZZ) == True - assert dup_cyclotomic_p([1,1,1,1,1], ZZ) == True - assert dup_cyclotomic_p([1,-1,1], ZZ) == True - assert dup_cyclotomic_p([1,1,1,1,1,1,1], ZZ) == True - assert dup_cyclotomic_p([1,0,0,0,1], ZZ) == True - assert dup_cyclotomic_p([1,0,0,1,0,0,1], ZZ) == True - - assert dup_cyclotomic_p([], ZZ) == False - assert dup_cyclotomic_p([1], ZZ) == False - assert dup_cyclotomic_p([1, 0], ZZ) == False - assert dup_cyclotomic_p([1, 2], ZZ) == False - assert dup_cyclotomic_p([3, 1], ZZ) == False - assert dup_cyclotomic_p([1, 0, -1], ZZ) == False - - f = [1, 0, 1, 0, 0, 0,-1, 0, 1, 0,-1, 0, 0, 0, 1, 0, 1] - assert dup_cyclotomic_p(f, ZZ) == False - - g = [1, 0, 1, 0, 0, 0,-1, 0,-1, 0,-1, 0, 0, 0, 1, 0, 1] - assert dup_cyclotomic_p(g, ZZ) == True + R, x = ring("x", ZZ) - assert dup_cyclotomic_p([QQ(1),QQ(1),QQ(1)], QQ) == True - assert dup_cyclotomic_p([QQ(1,2),QQ(1),QQ(1)], QQ) == False + assert R.dup_cyclotomic_p(x - 1) is True + assert R.dup_cyclotomic_p(x + 1) is True + assert R.dup_cyclotomic_p(x**2 + x + 1) is True + assert R.dup_cyclotomic_p(x**2 + 1) is True + assert R.dup_cyclotomic_p(x**4 + x**3 + x**2 + x + 1) is True + assert R.dup_cyclotomic_p(x**2 - x + 1) is True + assert R.dup_cyclotomic_p(x**6 + x**5 + x**4 + x**3 + x**2 + x + 1) is True + assert R.dup_cyclotomic_p(x**4 + 1) is True + assert R.dup_cyclotomic_p(x**6 + x**3 + 1) is True + + assert R.dup_cyclotomic_p(0) is False + assert R.dup_cyclotomic_p(1) is False + assert R.dup_cyclotomic_p(x) is False + assert R.dup_cyclotomic_p(x + 2) is False + assert R.dup_cyclotomic_p(3*x + 1) is False + assert R.dup_cyclotomic_p(x**2 - 1) is False + + f = x**16 + x**14 - x**10 + x**8 - x**6 + x**2 + 1 + assert R.dup_cyclotomic_p(f) is False + + g = x**16 + x**14 - x**10 - x**8 - x**6 + x**2 + 1 + assert R.dup_cyclotomic_p(g) is True + + R, x = ring("x", QQ) + assert R.dup_cyclotomic_p(x**2 + x + 1) is True + assert R.dup_cyclotomic_p(QQ(1,2)*x**2 + x + 1) is False - K = ZZ['y'] + R, x = ring("x", ZZ["y"]) + assert R.dup_cyclotomic_p(x**2 + x + 1) is False - assert dup_cyclotomic_p([K([ZZ(1)]),K([ZZ(1)]),K([ZZ(1)])], K) == False def test_dup_zz_cyclotomic_poly(): - assert dup_zz_cyclotomic_poly(1, ZZ) == [1,-1] - assert dup_zz_cyclotomic_poly(2, ZZ) == [1,1] - assert dup_zz_cyclotomic_poly(3, ZZ) == [1,1,1] - assert dup_zz_cyclotomic_poly(4, ZZ) == [1,0,1] - assert dup_zz_cyclotomic_poly(5, ZZ) == [1,1,1,1,1] - assert dup_zz_cyclotomic_poly(6, ZZ) == [1,-1,1] - assert dup_zz_cyclotomic_poly(7, ZZ) == [1,1,1,1,1,1,1] - assert dup_zz_cyclotomic_poly(8, ZZ) == [1,0,0,0,1] - assert dup_zz_cyclotomic_poly(9, ZZ) == [1,0,0,1,0,0,1] + R, x = ring("x", ZZ) + + assert R.dup_zz_cyclotomic_poly(1) == x - 1 + assert R.dup_zz_cyclotomic_poly(2) == x + 1 + assert R.dup_zz_cyclotomic_poly(3) == x**2 + x + 1 + assert R.dup_zz_cyclotomic_poly(4) == x**2 + 1 + assert R.dup_zz_cyclotomic_poly(5) == x**4 + x**3 + x**2 + x + 1 + assert R.dup_zz_cyclotomic_poly(6) == x**2 - x + 1 + assert R.dup_zz_cyclotomic_poly(7) == x**6 + x**5 + x**4 + x**3 + x**2 + x + 1 + assert R.dup_zz_cyclotomic_poly(8) == x**4 + 1 + assert R.dup_zz_cyclotomic_poly(9) == x**6 + x**3 + 1 + def test_dup_zz_cyclotomic_factor(): - assert dup_zz_cyclotomic_factor([], ZZ) is None - assert dup_zz_cyclotomic_factor([1], ZZ) is None + R, x = ring("x", ZZ) + + assert R.dup_zz_cyclotomic_factor(0) is None + assert R.dup_zz_cyclotomic_factor(1) is None + + assert R.dup_zz_cyclotomic_factor(2*x**10 - 1) is None + assert R.dup_zz_cyclotomic_factor(x**10 - 3) is None + assert R.dup_zz_cyclotomic_factor(x**10 + x**5 - 1) is None + + assert R.dup_zz_cyclotomic_factor(x + 1) == [x + 1] + assert R.dup_zz_cyclotomic_factor(x - 1) == [x - 1] + + assert R.dup_zz_cyclotomic_factor(x**2 + 1) == [x**2 + 1] + assert R.dup_zz_cyclotomic_factor(x**2 - 1) == [x - 1, x + 1] + + assert R.dup_zz_cyclotomic_factor(x**27 + 1) == \ + [x + 1, x**2 - x + 1, x**6 - x**3 + 1, x**18 - x**9 + 1] + assert R.dup_zz_cyclotomic_factor(x**27 - 1) == \ + [x - 1, x**2 + x + 1, x**6 + x**3 + 1, x**18 + x**9 + 1] - f = dup_from_raw_dict({10:2, 0:-1}, ZZ) - assert dup_zz_cyclotomic_factor(f, ZZ) is None - f = dup_from_raw_dict({10:1, 0:-3}, ZZ) - assert dup_zz_cyclotomic_factor(f, ZZ) is None - f = dup_from_raw_dict({10:1, 5:1, 0:-1}, ZZ) - assert dup_zz_cyclotomic_factor(f, ZZ) is None - - f = dup_from_raw_dict({1:1,0:1}, ZZ) - assert dup_zz_cyclotomic_factor(f, ZZ) == \ - [[1, 1]] - - f = dup_from_raw_dict({1:1,0:-1}, ZZ) - assert dup_zz_cyclotomic_factor(f, ZZ) == \ - [[1, -1]] - - f = dup_from_raw_dict({2:1,0:1}, ZZ) - assert dup_zz_cyclotomic_factor(f, ZZ) == \ - [[1, 0, 1]] - - f = dup_from_raw_dict({2:1,0:-1}, ZZ) - assert dup_zz_cyclotomic_factor(f, ZZ) == \ - [[1,-1], - [1, 1]] - - f = dup_from_raw_dict({27:1,0:1}, ZZ) - assert dup_zz_cyclotomic_factor(f, ZZ) == \ - [[1, 1], - [1, -1, 1], - [1, 0, 0, -1, 0, 0, 1], - [1, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 1]] - - f = dup_from_raw_dict({27:1,0:-1}, ZZ) - assert dup_zz_cyclotomic_factor(f, ZZ) == \ - [[1, -1], - [1, 1, 1], - [1, 0, 0, 1, 0, 0, 1], - [1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1]] def test_dup_zz_factor(): - assert dup_zz_factor([], ZZ) == (0, []) - assert dup_zz_factor([7], ZZ) == (7, []) - assert dup_zz_factor([-7], ZZ) == (-7, []) - - assert dup_zz_factor_sqf([], ZZ) == (0, []) - assert dup_zz_factor_sqf([7], ZZ) == (7, []) - assert dup_zz_factor_sqf([-7], ZZ) == (-7, []) - - assert dup_zz_factor([2,4], ZZ) == \ - (2, [([1, 2], 1)]) - assert dup_zz_factor_sqf([2,4], ZZ) == \ - (2, [([1, 2], 1)]) + R, x = ring("x", ZZ) + + assert R.dup_zz_factor(0) == (0, []) + assert R.dup_zz_factor(7) == (7, []) + assert R.dup_zz_factor(-7) == (-7, []) + + assert R.dup_zz_factor_sqf(0) == (0, []) + assert R.dup_zz_factor_sqf(7) == (7, []) + assert R.dup_zz_factor_sqf(-7) == (-7, []) + + assert R.dup_zz_factor(2*x + 4) == (2, [(x + 2, 1)]) + assert R.dup_zz_factor_sqf(2*x + 4) == (2, [x + 2]) - f = [1,0,0,1,1] + f = x**4 + x + 1 for i in range(0, 20): - assert dup_zz_factor(f, ZZ) == (1, [(f, 1)]) + assert R.dup_zz_factor(f) == (1, [(f, 1)]) - assert dup_zz_factor([1,2,2], ZZ) == \ - (1, [([1,2,2], 1)]) + assert R.dup_zz_factor(x**2 + 2*x + 2) == \ + (1, [(x**2 + 2*x + 2, 1)]) - assert dup_zz_factor([18,12,2], ZZ) == \ - (2, [([3, 1], 2)]) + assert R.dup_zz_factor(18*x**2 + 12*x + 2) == \ + (2, [(3*x + 1, 2)]) - assert dup_zz_factor([-9,0,1], ZZ) == \ - (-1, [([3,-1], 1), - ([3, 1], 1)]) - - assert dup_zz_factor_sqf([-9,0,1], ZZ) == \ - (-1, [[3,-1], - [3, 1]]) - - assert dup_zz_factor([1,-6,11,-6], ZZ) == \ - (1, [([1,-3], 1), - ([1,-2], 1), - ([1,-1], 1)]) - - assert dup_zz_factor_sqf([1,-6,11,-6], ZZ) == \ - (1, [[1,-3], - [1,-2], - [1,-1]]) - - assert dup_zz_factor([3,10,13,10], ZZ) == \ - (1, [([1,2], 1), - ([3,4,5], 1)]) - - assert dup_zz_factor_sqf([3,10,13,10], ZZ) == \ - (1, [[1,2], - [3,4,5]]) - - assert dup_zz_factor([-1,0,0,0,1,0,0], ZZ) == \ - (-1, [([1,-1], 1), - ([1, 1], 1), - ([1, 0], 2), - ([1, 0, 1], 1)]) - - f = [1080, 5184, 2099, 744, 2736, -648, 129, 0, -324] - - assert dup_zz_factor(f, ZZ) == \ - (1, [([5, 24, 9, 0, 12], 1), - ([216, 0, 31, 0, -27], 1)]) - - f = [-29802322387695312500000000000000000000, - 0, 0, 0, 0, - 2980232238769531250000000000000000, - 0, 0, 0, 0, - 1743435859680175781250000000000, - 0, 0, 0, 0, - 114142894744873046875000000, - 0, 0, 0, 0, - -210106372833251953125, - 0, 0, 0, 0, - 95367431640625] - - assert dup_zz_factor(f, ZZ) == \ - (-95367431640625, [([5, -1], 1), - ([100, 10, -1], 2), - ([625, 125, 25, 5, 1], 1), - ([10000, -3000, 400, -20, 1], 2), - ([10000, 2000, 400, 30, 1], 2)]) + assert R.dup_zz_factor(-9*x**2 + 1) == \ + (-1, [(3*x - 1, 1), + (3*x + 1, 1)]) + + assert R.dup_zz_factor_sqf(-9*x**2 + 1) == \ + (-1, [3*x - 1, + 3*x + 1]) + + assert R.dup_zz_factor(x**3 - 6*x**2 + 11*x - 6) == \ + (1, [(x - 3, 1), + (x - 2, 1), + (x - 1, 1)]) + + assert R.dup_zz_factor_sqf(x**3 - 6*x**2 + 11*x - 6) == \ + (1, [x - 3, + x - 2, + x - 1]) + + assert R.dup_zz_factor(3*x**3 + 10*x**2 + 13*x + 10) == \ + (1, [(x + 2, 1), + (3*x**2 + 4*x + 5, 1)]) + + assert R.dup_zz_factor_sqf(3*x**3 + 10*x**2 + 13*x + 10) == \ + (1, [x + 2, + 3*x**2 + 4*x + 5]) + + assert R.dup_zz_factor(-x**6 + x**2) == \ + (-1, [(x - 1, 1), + (x + 1, 1), + (x, 2), + (x**2 + 1, 1)]) + + f = 1080*x**8 + 5184*x**7 + 2099*x**6 + 744*x**5 + 2736*x**4 - 648*x**3 + 129*x**2 - 324 + + assert R.dup_zz_factor(f) == \ + (1, [(5*x**4 + 24*x**3 + 9*x**2 + 12, 1), + (216*x**4 + 31*x**2 - 27, 1)]) + + f = -29802322387695312500000000000000000000*x**25 \ + + 2980232238769531250000000000000000*x**20 \ + + 1743435859680175781250000000000*x**15 \ + + 114142894744873046875000000*x**10 \ + - 210106372833251953125*x**5 \ + + 95367431640625 + + assert R.dup_zz_factor(f) == \ + (-95367431640625, [(5*x - 1, 1), + (100*x**2 + 10*x - 1, 2), + (625*x**4 + 125*x**3 + 25*x**2 + 5*x + 1, 1), + (10000*x**4 - 3000*x**3 + 400*x**2 - 20*x + 1, 2), + (10000*x**4 + 2000*x**3 + 400*x**2 + 30*x + 1, 2)]) - f = dup_from_raw_dict({10:1, 0:-1}, ZZ) + f = x**10 - 1 config.setup('USE_CYCLOTOMIC_FACTOR', True) - F_0 = dup_zz_factor(f, ZZ) + F_0 = R.dup_zz_factor(f) config.setup('USE_CYCLOTOMIC_FACTOR', False) - F_1 = dup_zz_factor(f, ZZ) + F_1 = R.dup_zz_factor(f) assert F_0 == F_1 == \ - (1, [([1,-1], 1), - ([1, 1], 1), - ([1,-1, 1,-1, 1], 1), - ([1, 1, 1, 1, 1], 1)]) + (1, [(x - 1, 1), + (x + 1, 1), + (x**4 - x**3 + x**2 - x + 1, 1), + (x**4 + x**3 + x**2 + x + 1, 1)]) config.setup('USE_CYCLOTOMIC_FACTOR') - f = dup_from_raw_dict({10:1, 0:1}, ZZ) + f = x**10 + 1 config.setup('USE_CYCLOTOMIC_FACTOR', True) - F_0 = dup_zz_factor(f, ZZ) + F_0 = R.dup_zz_factor(f) config.setup('USE_CYCLOTOMIC_FACTOR', False) - F_1 = dup_zz_factor(f, ZZ) + F_1 = R.dup_zz_factor(f) assert F_0 == F_1 == \ - (1, [([1, 0, 1], 1), - ([1, 0, -1, 0, 1, 0, -1, 0, 1], 1)]) + (1, [(x**2 + 1, 1), + (x**8 - x**6 + x**4 - x**2 + 1, 1)]) config.setup('USE_CYCLOTOMIC_FACTOR') def test_dmp_zz_wang(): - p = ZZ(nextprime(dmp_zz_mignotte_bound(w_1, 2, ZZ))) + R, x,y,z = ring("x,y,z", ZZ) + UV, _x = ring("x", ZZ) - assert p == ZZ(6291469) + p = ZZ(nextprime(R.dmp_zz_mignotte_bound(w_1))) + assert p == 6291469 - t_1, k_1, e_1 = dmp_normal([[1],[]], 1, ZZ), 1, ZZ(-14) - t_2, k_2, e_2 = dmp_normal([[1, 0]], 1, ZZ), 2, ZZ(3) - t_3, k_3, e_3 = dmp_normal([[1],[ 1, 0]], 1, ZZ), 2, ZZ(-11) - t_4, k_4, e_4 = dmp_normal([[1],[-1, 0]], 1, ZZ), 1, ZZ(-17) + t_1, k_1, e_1 = y, 1, ZZ(-14) + t_2, k_2, e_2 = z, 2, ZZ(3) + t_3, k_3, e_3 = y + z, 2, ZZ(-11) + t_4, k_4, e_4 = y - z, 1, ZZ(-17) T = [t_1, t_2, t_3, t_4] K = [k_1, k_2, k_3, k_4] E = [e_1, e_2, e_3, e_4] - T = list(zip(T, K)) + T = list(zip([ t.drop(x) for t in T ], K)) A = [ZZ(-14), ZZ(3)] - S = dmp_eval_tail(w_1, A, 2, ZZ) - cs, s = dup_primitive(S, ZZ) + S = R.dmp_eval_tail(w_1, A) + cs, s = UV.dup_primitive(S) assert cs == 1 and s == S == \ - dup_normal([1036728, 915552, 55748, 105621, -17304, -26841, -644], ZZ) + 1036728*_x**6 + 915552*_x**5 + 55748*_x**4 + 105621*_x**3 - 17304*_x**2 - 26841*_x - 644 - assert dmp_zz_wang_non_divisors(E, cs, 4, ZZ) == [7, 3, 11, 17] - assert dup_sqf_p(s, ZZ) and dup_degree(s) == dmp_degree(w_1, 2) + assert R.dmp_zz_wang_non_divisors(E, cs, ZZ(4)) == [7, 3, 11, 17] + assert UV.dup_sqf_p(s) and UV.dup_degree(s) == R.dmp_degree(w_1) - _, H = dup_zz_factor_sqf(s, ZZ) + _, H = UV.dup_zz_factor_sqf(s) - h_1 = dup_normal([44, 42, 1], ZZ) - h_2 = dup_normal([126, -9, 28], ZZ) - h_3 = dup_normal([187, 0, -23], ZZ) + h_1 = 44*_x**2 + 42*_x + 1 + h_2 = 126*_x**2 - 9*_x + 28 + h_3 = 187*_x**2 - 23 assert H == [h_1, h_2, h_3] - lc_1 = dmp_normal([[-4], [-4,0]], 1, ZZ) - lc_2 = dmp_normal([[-1,0,0], []], 1, ZZ) - lc_3 = dmp_normal([[1], [], [-1,0,0]], 1, ZZ) + LC = [ lc.drop(x) for lc in [-4*y - 4*z, -y*z**2, y**2 - z**2] ] - LC = [lc_1, lc_2, lc_3] + assert R.dmp_zz_wang_lead_coeffs(w_1, T, cs, E, H, A) == (w_1, H, LC) - assert dmp_zz_wang_lead_coeffs(w_1, T, cs, E, H, A, 2, ZZ) == (w_1, H, LC) + H_1 = [44*x**2 + 42*x + 1, 126*x**2 - 9*x + 28, 187*x**2 - 23] + H_2 = [-4*x**2*y - 12*x**2 - 3*x*y + 1, -9*x**2*y - 9*x - 2*y, x**2*y**2 - 9*x**2 + y - 9] + H_3 = [-4*x**2*y - 12*x**2 - 3*x*y + 1, -9*x**2*y - 9*x - 2*y, x**2*y**2 - 9*x**2 + y - 9] - H_1 = [ dmp_normal(t, 0, ZZ) for t in [[44,42,1],[126,-9,28],[187,0,-23]] ] - H_2 = [ dmp_normal(t, 1, ZZ) for t in [[[-4,-12],[-3,0],[1]],[[-9,0],[-9],[-2,0]],[[1,0,-9],[],[1,-9]]] ] - H_3 = [ dmp_normal(t, 1, ZZ) for t in [[[-4,-12],[-3,0],[1]],[[-9,0],[-9],[-2,0]],[[1,0,-9],[],[1,-9]]] ] + c_1 = -70686*x**5 - 5863*x**4 - 17826*x**3 + 2009*x**2 + 5031*x + 74 + c_2 = 9*x**5*y**4 + 12*x**5*y**3 - 45*x**5*y**2 - 108*x**5*y - 324*x**5 + 18*x**4*y**3 - 216*x**4*y**2 - 810*x**4*y + 2*x**3*y**4 + 9*x**3*y**3 - 252*x**3*y**2 - 288*x**3*y - 945*x**3 - 30*x**2*y**2 - 414*x**2*y + 2*x*y**3 - 54*x*y**2 - 3*x*y + 81*x + 12*y + c_3 = -36*x**4*y**2 - 108*x**4*y - 27*x**3*y**2 - 36*x**3*y - 108*x**3 - 8*x**2*y**2 - 42*x**2*y - 6*x*y**2 + 9*x + 2*y - c_1 = dmp_normal([-70686,-5863,-17826,2009,5031,74], 0, ZZ) - c_2 = dmp_normal([[9,12,-45,-108,-324],[18,-216,-810,0],[2,9,-252,-288,-945],[-30,-414,0],[2,-54,-3,81],[12,0]], 1, ZZ) - c_3 = dmp_normal([[-36,-108,0],[-27,-36,-108],[-8,-42,0],[-6,0,9],[2,0]], 1, ZZ) + # TODO + #assert R.dmp_zz_diophantine(H_1, c_1, [], 5, p) == [-3*x, -2, 1] + #assert R.dmp_zz_diophantine(H_2, c_2, [ZZ(-14)], 5, p) == [-x*y, -3*x, -6] + #assert R.dmp_zz_diophantine(H_3, c_3, [ZZ(-14)], 5, p) == [0, 0, -1] - T_1 = [ dmp_normal(t, 0, ZZ) for t in [[-3,0],[-2],[1]] ] - T_2 = [ dmp_normal(t, 1, ZZ) for t in [[[-1,0],[]],[[-3],[]],[[-6]]] ] - T_3 = [ dmp_normal(t, 1, ZZ) for t in [[[]],[[]],[[-1]]] ] + factors = R.dmp_zz_wang_hensel_lifting(w_1, H, LC, A, p) + assert R.dmp_expand(factors) == w_1 - assert dmp_zz_diophantine(H_1, c_1, [], 5, p, 0, ZZ) == T_1 - assert dmp_zz_diophantine(H_2, c_2, [ZZ(-14)], 5, p, 1, ZZ) == T_2 - assert dmp_zz_diophantine(H_3, c_3, [ZZ(-14)], 5, p, 1, ZZ) == T_3 - - factors = dmp_zz_wang_hensel_lifting(w_1, H, LC, A, p, 2, ZZ) - - assert dmp_expand(factors, 2, ZZ) == w_1 def test_issue_3256(): # This tests a bug in the Wang algorithm that occured only with a very # specific set of random numbers. random_sequence = [-1, -1, 0, 0, 0, 0, -1, -1, 0, -1, 3, -1, 3, 3, 3, 3, -1, 3] - f = [[[ZZ(2)]], [[]], [[ZZ(1), ZZ(-1)], [ZZ(-1), ZZ(1), ZZ(0)]]] - u = 2 - K = ZZ - assert dmp_zz_wang(f, u, K, seed=random_sequence) == [f] -def test_dmp_zz_factor(): - assert dmp_zz_factor([], 0, ZZ) == (0, []) - assert dmp_zz_factor([7], 0, ZZ) == (7, []) - assert dmp_zz_factor([-7], 0, ZZ) == (-7, []) - - assert dmp_zz_factor([[]], 1, ZZ) == (0, []) - assert dmp_zz_factor([[7]], 1, ZZ) == (7, []) - assert dmp_zz_factor([[-7]], 1, ZZ) == (-7, []) - - assert dmp_zz_factor([[1], []], 1, ZZ) == \ - (1, [([[1], []], 1)]) - - assert dmp_zz_factor([[4], []], 1, ZZ) == \ - (4, [([[1], []], 1)]) - - assert dmp_zz_factor([[4], [2]], 1, ZZ) == \ - (2, [([[2], [1]], 1)]) - - assert dmp_zz_factor([[1, 0], [1]], 1, ZZ) == \ - (1, [([[1, 0], [1]], 1)]) - - assert dmp_zz_factor([[1,0,1]], 1, ZZ) == \ - (1, [([[1, 0, 1]], 1)]) - - assert dmp_zz_factor([[1,0,-1]], 1, ZZ) == \ - (1, [([[1,-1]], 1), - ([[1, 1]], 1)]) - - assert dmp_zz_factor([[1, 6, 9], [], [-1]], 1, ZZ) == \ - (1, [([[1, 3], [-1]], 1), ([[1, 3], [1]], 1)]) - - assert dmp_zz_factor([1, 0, -9], 0, ZZ) == \ - (1, [([1, -3], 1), ([1, 3], 1)]) - - assert dmp_zz_factor([[1, 0, 0], [], [-9]], 1, ZZ) == \ - (1, [([[1, 0], [-3]], 1), ([[1, 0], [3]], 1)]) - - assert dmp_zz_factor([[[1, 0, 0], [], []], [[]], [[-9]]], 2, ZZ) == \ - (1, [([[[1, 0], []], [[-3]]], 1), ([[[1, 0], []], [[3]]], 1)]) - - assert dmp_zz_factor([[[[1, 0, 0], [], []], [[]], [[]]], [[[]]], [[[-9]]]], 3, ZZ) == \ - (1, [([[[[1, 0], []], [[]]], [[[-3]]]], 1), ([[[[1, 0], []], [[]]], [[[3]]]], 1)]) - - assert dmp_zz_factor(f_1, 2, ZZ) == \ - (1, [([[[1]], [[1, 0], [20]]], 1), - ([[[1], []], [[1, 10]]], 1), - ([[[1, 0]], [[1], [30]]], 1)]) - - assert dmp_zz_factor(f_2, 2, ZZ) == \ - (1, [([[[1], [], [1, 0, 0]], [[]], [[1], [90]]], 1), - ([[[1], [1, 0]], [[]], [[]], [[1, -11]]], 1)]) - - assert dmp_zz_factor(f_3, 2, ZZ) == \ - (1, [([[[1], [], []], [[1, 0, 0, 0, 1]], [[1, 0]]], 1), - ([[[1]], [[]], [[1, 0], []], [[1], [1, 0, 0, 0], []]], 1)]) - - assert dmp_zz_factor(f_4, 2, ZZ) == \ - (-1, [([[[1], [], [], []], [[1, 0, 0]]], 1), - ([[[1, 0]], [[]], [[1, 0, 0], [], [], [], [5]]], 1), - ([[[1], []], [[]], [[]], [[-1, 0, -3]]], 1), - ([[[1], [], [], [], []], [[]], [[]], [[1, 0, 0]]], 1)]) - - assert dmp_zz_factor(f_5, 2, ZZ) == \ - (-1, [([[[1]], [[1], [-1, 0]]], 3)]) - - assert dmp_zz_factor(f_6, 3, ZZ) == \ - (1, [([[[[47]], [[]]], [[[1, 0, 0], [], [], [-1, 0, 0]]]], 1), - ([[[[45]]], [[[]]], [[[]]], [[[-9]], [[-1]], [[]], [[3], [], [2, 0], []]]], 1)]) - - assert dmp_zz_factor(w_1, 2, ZZ) == \ - (1, [([[[1], [], [-1, 0, 0]], [[]], [[1], [-1, 0, 0]]], 1), - ([[[1, 0, 0], []], [[3, 0]], [[2], []]], 1), - ([[[4], [4, 0]], [[1, 0], []], [[-1]]], 1)]) - - f = [[-12, 0], [], - [], [], - [240, 0, 0, 0], [], - [-768, 0, 0, 0, 0], [], - [1080, 0, 0, 0, 0, 0], [], - [-768, 0, 0, 0, 0, 0, 0], [], - [240, 0, 0, 0, 0, 0, 0, 0], [], - [], [], - [-12, 0, 0, 0, 0, 0, 0, 0, 0, 0]] - - assert dmp_zz_factor(f, 1, ZZ) == \ - (-12, [([[1, 0]], 1), - ([[1], [], [-1, 0]], 6), - ([[1], [], [6, 0], [], [1, 0, 0]], 1)]) + R, x, y, z = ring("x,y,z", ZZ) + f = 2*x**2 + y*z - y - z**2 + z -def test_dup_ext_factor(): - h = [QQ(1),QQ(0),QQ(1)] - K = QQ.algebraic_field(I) + assert R.dmp_zz_wang(f, seed=random_sequence) == [f] - assert dup_ext_factor([], K) == (ANP([], h, QQ), []) - f = [ANP([QQ(1)], h, QQ), ANP([QQ(1)], h, QQ)] +def test_dmp_zz_factor(): + R, x = ring("x", ZZ) + assert R.dmp_zz_factor(0) == (0, []) + assert R.dmp_zz_factor(7) == (7, []) + assert R.dmp_zz_factor(-7) == (-7, []) + + assert R.dmp_zz_factor(x**2 - 9) == (1, [(x - 3, 1), (x + 3, 1)]) + + R, x, y = ring("x,y", ZZ) + assert R.dmp_zz_factor(0) == (0, []) + assert R.dmp_zz_factor(7) == (7, []) + assert R.dmp_zz_factor(-7) == (-7, []) + + assert R.dmp_zz_factor(x) == (1, [(x, 1)]) + assert R.dmp_zz_factor(4*x) == (4, [(x, 1)]) + assert R.dmp_zz_factor(4*x + 2) == (2, [(2*x + 1, 1)]) + assert R.dmp_zz_factor(x*y + 1) == (1, [(x*y + 1, 1)]) + assert R.dmp_zz_factor(y**2 + 1) == (1, [(y**2 + 1, 1)]) + assert R.dmp_zz_factor(y**2 - 1) == (1, [(y - 1, 1), (y + 1, 1)]) + + assert R.dmp_zz_factor(x**2*y**2 + 6*x**2*y + 9*x**2 - 1) == (1, [(x*y + 3*x - 1, 1), (x*y + 3*x + 1, 1)]) + assert R.dmp_zz_factor(x**2*y**2 - 9) == (1, [(x*y - 3, 1), (x*y + 3, 1)]) + + R, x, y, z = ring("x,y,z", ZZ) + assert R.dmp_zz_factor(x**2*y**2*z**2 - 9) == \ + (1, [(x*y*z - 3, 1), + (x*y*z + 3, 1)]) + + R, x, y, z, u = ring("x,y,z,u", ZZ) + assert R.dmp_zz_factor(x**2*y**2*z**2*u**2 - 9) == \ + (1, [(x*y*z*u - 3, 1), + (x*y*z*u + 3, 1)]) + + R, x, y, z = ring("x,y,z", ZZ) + assert R.dmp_zz_factor(f_1) == \ + (1, [(x + y*z + 20, 1), + (x*y + z + 10, 1), + (x*z + y + 30, 1)]) + + assert R.dmp_zz_factor(f_2) == \ + (1, [(x**2*y**2 + x**2*z**2 + y + 90, 1), + (x**3*y + x**3*z + z - 11, 1)]) + + assert R.dmp_zz_factor(f_3) == \ + (1, [(x**2*y**2 + x*z**4 + x + z, 1), + (x**3 + x*y*z + y**2 + y*z**3, 1)]) + + assert R.dmp_zz_factor(f_4) == \ + (-1, [(x*y**3 + z**2, 1), + (x**2*z + y**4*z**2 + 5, 1), + (x**3*y - z**2 - 3, 1), + (x**3*y**4 + z**2, 1)]) + + assert R.dmp_zz_factor(f_5) == \ + (-1, [(x + y - z, 3)]) + + R, x, y, z, t = ring("x,y,z,t", ZZ) + assert R.dmp_zz_factor(f_6) == \ + (1, [(47*x*y + z**3*t**2 - t**2, 1), + (45*x**3 - 9*y**3 - y**2 + 3*z**3 + 2*z*t, 1)]) + + R, x, y, z = ring("x,y,z", ZZ) + assert R.dmp_zz_factor(w_1) == \ + (1, [(x**2*y**2 - x**2*z**2 + y - z**2, 1), + (x**2*y*z**2 + 3*x*z + 2*y, 1), + (4*x**2*y + 4*x**2*z + x*y*z - 1, 1)]) + + R, x, y = ring("x,y", ZZ) + f = -12*x**16*y + 240*x**12*y**3 - 768*x**10*y**4 + 1080*x**8*y**5 - 768*x**6*y**6 + 240*x**4*y**7 - 12*y**9 + + assert R.dmp_zz_factor(f) == \ + (-12, [(y, 1), + (x**2 - y, 6), + (x**4 + 6*x**2*y + y**2, 1)]) + - assert dup_ext_factor(f, K) == (ANP([QQ(1)], h, QQ), [(f, 1)]) +def test_dup_ext_factor(): + R, x = ring("x", QQ.algebraic_field(I)) + def anp(element): + return ANP(element, [QQ(1), QQ(0), QQ(1)], QQ) - g = [ANP([QQ(2)], h, QQ), ANP([QQ(2)], h, QQ)] + assert R.dup_ext_factor(0) == (anp([]), []) - assert dup_ext_factor(g, K) == (ANP([QQ(2)], h, QQ), [(f, 1)]) + f = anp([QQ(1)])*x + anp([QQ(1)]) - f = [ANP([QQ(7)], h, QQ), ANP([], h, QQ), ANP([], h, QQ), ANP([], h, QQ), ANP([QQ(1,1)], h, QQ)] - g = [ANP([QQ(1)], h, QQ), ANP([], h, QQ), ANP([], h, QQ), ANP([], h, QQ), ANP([QQ(1,7)], h, QQ)] + assert R.dup_ext_factor(f) == (anp([QQ(1)]), [(f, 1)]) - assert dup_ext_factor(f, K) == (ANP([QQ(7)], h, QQ), [(g, 1)]) + g = anp([QQ(2)])*x + anp([QQ(2)]) - f = [ANP([QQ(1)], h, QQ), ANP([], h, QQ), ANP([], h, QQ), ANP([], h, QQ), ANP([QQ(1)], h, QQ)] + assert R.dup_ext_factor(g) == (anp([QQ(2)]), [(f, 1)]) - assert dup_ext_factor(f, K) == \ - (ANP([QQ(1,1)], h, QQ), [ - ([ANP([QQ(1)], h, QQ), ANP([], h, QQ), ANP([QQ(-1),QQ(0)], h, QQ)], 1), - ([ANP([QQ(1)], h, QQ), ANP([], h, QQ), ANP([QQ( 1),QQ(0)], h, QQ)], 1), - ]) + f = anp([QQ(7)])*x**4 + anp([QQ(1, 1)]) + g = anp([QQ(1)])*x**4 + anp([QQ(1, 7)]) - f = [ANP([QQ(1)], h, QQ), ANP([], h, QQ), ANP([], h, QQ), ANP([], h, QQ), ANP([QQ(1)], h, QQ)] + assert R.dup_ext_factor(f) == (anp([QQ(7)]), [(g, 1)]) - assert dup_ext_factor(f, K) == \ - (ANP([QQ(1,1)], h, QQ), [ - ([ANP([QQ(1)], h, QQ), ANP([], h, QQ), ANP([QQ(-1),QQ(0)], h, QQ)], 1), - ([ANP([QQ(1)], h, QQ), ANP([], h, QQ), ANP([QQ( 1),QQ(0)], h, QQ)], 1), - ]) + f = anp([QQ(1)])*x**4 + anp([QQ(1)]) - h = [QQ(1),QQ(0),QQ(-2)] - K = QQ.algebraic_field(sqrt(2)) + assert R.dup_ext_factor(f) == \ + (anp([QQ(1, 1)]), [(anp([QQ(1)])*x**2 + anp([QQ(-1), QQ(0)]), 1), + (anp([QQ(1)])*x**2 + anp([QQ( 1), QQ(0)]), 1)]) - f = [ANP([QQ(1)], h, QQ), ANP([], h, QQ), ANP([], h, QQ), ANP([], h, QQ), ANP([QQ(1,1)], h, QQ)] + f = anp([QQ(4, 1)])*x**2 + anp([QQ(9, 1)]) - assert dup_ext_factor(f, K) == \ - (ANP([QQ(1)], h, QQ), [ - ([ANP([QQ(1)], h, QQ), ANP([QQ(-1),QQ(0)], h, QQ), ANP([QQ(1)], h, QQ)], 1), - ([ANP([QQ(1)], h, QQ), ANP([QQ( 1),QQ(0)], h, QQ), ANP([QQ(1)], h, QQ)], 1), - ]) + assert R.dup_ext_factor(f) == \ + (anp([QQ(4, 1)]), [(anp([QQ(1, 1)])*x + anp([-QQ(3, 2), QQ(0, 1)]), 1), + (anp([QQ(1, 1)])*x + anp([ QQ(3, 2), QQ(0, 1)]), 1)]) - f = [ANP([QQ(1,1)], h, QQ), ANP([2,0], h, QQ), ANP([QQ(2,1)], h, QQ)] + f = anp([QQ(4, 1)])*x**4 + anp([QQ(8, 1)])*x**3 + anp([QQ(77, 1)])*x**2 + anp([QQ(18, 1)])*x + anp([QQ(153, 1)]) - assert dup_ext_factor(f, K) == \ - (ANP([QQ(1,1)], h, QQ), [ - ([ANP([1], h, QQ), ANP([1,0], h, QQ)], 2), - ]) + assert R.dup_ext_factor(f) == \ + (anp([QQ(4, 1)]), [(anp([QQ(1, 1)])*x + anp([-QQ(4, 1), QQ(1, 1)]), 1), + (anp([QQ(1, 1)])*x + anp([-QQ(3, 2), QQ(0, 1)]), 1), + (anp([QQ(1, 1)])*x + anp([ QQ(3, 2), QQ(0, 1)]), 1), + (anp([QQ(1, 1)])*x + anp([ QQ(4, 1), QQ(1, 1)]), 1)]) - assert dup_ext_factor(dup_pow(f, 3, K), K) == \ - (ANP([QQ(1,1)], h, QQ), [ - ([ANP([1], h, QQ), ANP([1,0], h, QQ)], 6), - ]) + R, x = ring("x", QQ.algebraic_field(sqrt(2))) + def anp(element): + return ANP(element, [QQ(1), QQ(0), QQ(-2)], QQ) - f = dup_mul_ground(f, ANP([QQ(2,1)], h, QQ), K) + f = anp([QQ(1)])*x**4 + anp([QQ(1, 1)]) - assert dup_ext_factor(f, K) == \ - (ANP([QQ(2,1)], h, QQ), [ - ([ANP([1], h, QQ), ANP([1,0], h, QQ)], 2), - ]) + assert R.dup_ext_factor(f) == \ + (anp([QQ(1)]), [(anp([QQ(1)])*x**2 + anp([QQ(-1), QQ(0)])*x + anp([QQ(1)]), 1), + (anp([QQ(1)])*x**2 + anp([QQ( 1), QQ(0)])*x + anp([QQ(1)]), 1)]) - assert dup_ext_factor(dup_pow(f, 3, K), K) == \ - (ANP([QQ(8,1)], h, QQ), [ - ([ANP([1], h, QQ), ANP([1,0], h, QQ)], 6), - ]) + f = anp([QQ(1, 1)])*x**2 + anp([QQ(2), QQ(0)])*x + anp([QQ(2, 1)]) - h = [QQ(1,1), QQ(0,1), QQ(1,1)] - K = QQ.algebraic_field(I) + assert R.dup_ext_factor(f) == \ + (anp([QQ(1, 1)]), [(anp([1])*x + anp([1, 0]), 2)]) - f = [ANP([QQ(4,1)], h, QQ), ANP([], h, QQ), ANP([QQ(9,1)], h, QQ)] + assert R.dup_ext_factor(f**3) == \ + (anp([QQ(1, 1)]), [(anp([1])*x + anp([1, 0]), 6)]) - assert dup_ext_factor(f, K) == \ - (ANP([QQ(4,1)], h, QQ), [ - ([ANP([QQ(1,1)], h, QQ), ANP([-QQ(3,2), QQ(0,1)], h, QQ)], 1), - ([ANP([QQ(1,1)], h, QQ), ANP([ QQ(3,2), QQ(0,1)], h, QQ)], 1), - ]) + f *= anp([QQ(2, 1)]) - f = [ANP([QQ(4,1)], h, QQ), ANP([QQ(8,1)], h, QQ), ANP([QQ(77,1)], h, QQ), ANP([QQ(18,1)], h, QQ), ANP([QQ(153,1)], h, QQ)] + assert R.dup_ext_factor(f) == \ + (anp([QQ(2, 1)]), [(anp([1])*x + anp([1, 0]), 2)]) + + assert R.dup_ext_factor(f**3) == \ + (anp([QQ(8, 1)]), [(anp([1])*x + anp([1, 0]), 6)]) - assert dup_ext_factor(f, K) == \ - (ANP([QQ(4,1)], h, QQ), [ - ([ANP([QQ(1,1)], h, QQ), ANP([-QQ(4,1), QQ(1,1)], h, QQ)], 1), - ([ANP([QQ(1,1)], h, QQ), ANP([-QQ(3,2), QQ(0,1)], h, QQ)], 1), - ([ANP([QQ(1,1)], h, QQ), ANP([ QQ(3,2), QQ(0,1)], h, QQ)], 1), - ([ANP([QQ(1,1)], h, QQ), ANP([ QQ(4,1), QQ(1,1)], h, QQ)], 1), - ]) def test_dmp_ext_factor(): - h = [QQ(1),QQ(0),QQ(-2)] - K = QQ.algebraic_field(sqrt(2)) + R, x,y = ring("x,y", QQ.algebraic_field(sqrt(2))) + def anp(x): + return ANP(x, [QQ(1), QQ(0), QQ(-2)], QQ) - assert dmp_ext_factor([], 0, K) == (ANP([], h, QQ), []) - assert dmp_ext_factor([[]], 1, K) == (ANP([], h, QQ), []) + assert R.dmp_ext_factor(0) == (anp([]), []) - f = [[ANP([QQ(1)], h, QQ)], [ANP([QQ(1)], h, QQ)]] + f = anp([QQ(1)])*x + anp([QQ(1)]) - assert dmp_ext_factor(f, 1, K) == (ANP([QQ(1)], h, QQ), [(f, 1)]) + assert R.dmp_ext_factor(f) == (anp([QQ(1)]), [(f, 1)]) - g = [[ANP([QQ(2)], h, QQ)], [ANP([QQ(2)], h, QQ)]] + g = anp([QQ(2)])*x + anp([QQ(2)]) - assert dmp_ext_factor(g, 1, K) == (ANP([QQ(2)], h, QQ), [(f, 1)]) + assert R.dmp_ext_factor(g) == (anp([QQ(2)]), [(f, 1)]) - f = [[ANP([QQ(1)], h, QQ)], [], [ANP([QQ(-2)], h, QQ), ANP([], h, QQ), ANP([], h, QQ)]] + f = anp([QQ(1)])*x**2 + anp([QQ(-2)])*y**2 - assert dmp_ext_factor(f, 1, K) == \ - (ANP([QQ(1)], h, QQ), [ - ([[ANP([QQ(1)], h, QQ)], [ANP([QQ(-1),QQ(0)], h, QQ), ANP([], h, QQ)]], 1), - ([[ANP([QQ(1)], h, QQ)], [ANP([QQ( 1),QQ(0)], h, QQ), ANP([], h, QQ)]], 1), - ]) + assert R.dmp_ext_factor(f) == \ + (anp([QQ(1)]), [(anp([QQ(1)])*x + anp([QQ(-1), QQ(0)])*y, 1), + (anp([QQ(1)])*x + anp([QQ( 1), QQ(0)])*y, 1)]) - f = [[ANP([QQ(2)], h, QQ)], [], [ANP([QQ(-4)], h, QQ), ANP([], h, QQ), ANP([], h, QQ)]] + f = anp([QQ(2)])*x**2 + anp([QQ(-4)])*y**2 - assert dmp_ext_factor(f, 1, K) == \ - (ANP([QQ(2)], h, QQ), [ - ([[ANP([QQ(1)], h, QQ)], [ANP([QQ(-1),QQ(0)], h, QQ), ANP([], h, QQ)]], 1), - ([[ANP([QQ(1)], h, QQ)], [ANP([QQ( 1),QQ(0)], h, QQ), ANP([], h, QQ)]], 1), - ]) + assert R.dmp_ext_factor(f) == \ + (anp([QQ(2)]), [(anp([QQ(1)])*x + anp([QQ(-1), QQ(0)])*y, 1), + (anp([QQ(1)])*x + anp([QQ( 1), QQ(0)])*y, 1)]) -def test_dup_factor_list(): - assert dup_factor_list([], ZZ) == (ZZ(0), []) - assert dup_factor_list([], QQ) == (QQ(0), []) - assert dup_factor_list([], ZZ['y']) == (DMP([],ZZ), []) - assert dup_factor_list([], QQ['y']) == (DMP([],QQ), []) - assert dup_factor_list_include([], ZZ) == [([], 1)] +def test_dup_factor_list(): + R, x = ring("x", ZZ) + assert R.dup_factor_list(0) == (0, []) + assert R.dup_factor_list(7) == (7, []) - assert dup_factor_list([ZZ(7)], ZZ) == (ZZ(7), []) - assert dup_factor_list([QQ(1,7)], QQ) == (QQ(1,7), []) - assert dup_factor_list([DMP([ZZ(7)],ZZ)], ZZ['y']) == (DMP([ZZ(7)],ZZ), []) - assert dup_factor_list([DMP([QQ(1,7)],QQ)], QQ['y']) == (DMP([QQ(1,7)],QQ), []) + R, x = ring("x", QQ) + assert R.dup_factor_list(0) == (0, []) + assert R.dup_factor_list(QQ(1, 7)) == (QQ(1, 7), []) - assert dup_factor_list_include([ZZ(7)], ZZ) == [([ZZ(7)], 1)] + R, x = ring("x", ZZ['t']) + assert R.dup_factor_list(0) == (DMP([], ZZ), []) + assert R.dup_factor_list(DMP([ZZ(7)], ZZ)) == (DMP([ZZ(7)], ZZ), []) - assert dup_factor_list([ZZ(1),ZZ(2),ZZ(1)], ZZ) == \ - (ZZ(1), [([ZZ(1), ZZ(1)], 2)]) - assert dup_factor_list([QQ(1,2),QQ(1),QQ(1,2)], QQ) == \ - (QQ(1,2), [([QQ(1),QQ(1)], 2)]) + R, x = ring("x", QQ['t']) + assert R.dup_factor_list(0) == (DMP([], QQ), []) + assert R.dup_factor_list(DMP([QQ(1, 7)], QQ)) == (DMP([QQ(1, 7)], QQ), []) - assert dup_factor_list_include([ZZ(1),ZZ(2),ZZ(1)], ZZ) == \ - [([ZZ(1), ZZ(1)], 2)] + R, x = ring("x", ZZ) + assert R.dup_factor_list_include(0) == [(0, 1)] + assert R.dup_factor_list_include(7) == [(7, 1)] - K = FF(2) + assert R.dup_factor_list(x**2 + 2*x + 1) == (1, [(x + 1, 2)]) + assert R.dup_factor_list_include(x**2 + 2*x + 1) == [(x + 1, 2)] - assert dup_factor_list([K(1),K(0),K(1)], K) == \ - (K(1), [([K(1), K(1)], 2)]) + R, x = ring("x", QQ) + assert R.dup_factor_list(QQ(1,2)*x**2 + x + QQ(1,2)) == (QQ(1, 2), [(x + 1, 2)]) - assert dup_factor_list([RR(1.0),RR(2.0),RR(1.0)], RR) == \ - (RR(1.0), [([RR(1.0),RR(1.0)], 2)]) - assert dup_factor_list([RR(2.0),RR(4.0),RR(2.0)], RR) == \ - (RR(2.0), [([RR(1.0),RR(1.0)], 2)]) + R, x = ring("x", FF(2)) + assert R.dup_factor_list(x**2 + 1) == (1, [(x + 1, 2)]) + R, x = ring("x", RR) + assert R.dup_factor_list(1.0*x**2 + 2.0*x + 1.0) == (1.0, [(1.0*x + 1.0, 2)]) + assert R.dup_factor_list(2.0*x**2 + 4.0*x + 2.0) == (2.0, [(1.0*x + 1.0, 2)]) - f = [DMP([ZZ(4),ZZ(0)],ZZ),DMP([ZZ(4),ZZ(0),ZZ(0)],ZZ),DMP([],ZZ)] + R, x = ring("x", ZZ['t']) + f = DMP([ZZ(4), ZZ(0)], ZZ)*x**2 + DMP([ZZ(4), ZZ(0), ZZ(0)], ZZ)*x - assert dup_factor_list(f, ZZ['y']) == \ - (DMP([ZZ(4)],ZZ), [([DMP([ZZ(1),ZZ(0)],ZZ)], 1), - ([DMP([ZZ(1)],ZZ),DMP([],ZZ)], 1), - ([DMP([ZZ(1)],ZZ),DMP([ZZ(1),ZZ(0)],ZZ)], 1)]) + assert R.dup_factor_list(f) == \ + (DMP([ZZ(4)], ZZ), [(DMP([ZZ(1), ZZ(0)], ZZ), 1), + (DMP([ZZ(1)], ZZ)*x, 1), + (DMP([ZZ(1)], ZZ)*x + DMP([ZZ(1), ZZ(0)], ZZ), 1)]) + R, x = ring("x", QQ['t']) + f = DMP([QQ(1, 2), QQ(0)], QQ)*x**2 + DMP([QQ(1, 2), QQ(0), QQ(0)], QQ)*x - f = [DMP([QQ(1,2),QQ(0)],ZZ),DMP([QQ(1,2),QQ(0),QQ(0)],ZZ),DMP([],ZZ)] + assert R.dup_factor_list(f) == \ + (DMP([QQ(1, 2)], QQ), [(DMP([QQ(1), QQ(0)], QQ), 1), + (DMP([QQ(1)], QQ)*x + DMP([], QQ), 1), + (DMP([QQ(1)], QQ)*x + DMP([QQ(1), QQ(0)], QQ), 1)]) - assert dup_factor_list(f, QQ['y']) == \ - (DMP([QQ(1,2)],QQ), [([DMP([QQ(1),QQ(0)],QQ)], 1), - ([DMP([QQ(1)],QQ),DMP([],QQ)], 1), - ([DMP([QQ(1)],QQ),DMP([QQ(1),QQ(0)],QQ)], 1)]) + R, x = ring("x", QQ.algebraic_field(I)) + def anp(element): + return ANP(element, [QQ(1), QQ(0), QQ(1)], QQ) - K = QQ.algebraic_field(I) - h = [QQ(1,1), QQ(0,1), QQ(1,1)] + f = anp([QQ(1, 1)])*x**4 + anp([QQ(2, 1)])*x**2 - f = [ANP([QQ(1,1)], h, QQ), ANP([], h, QQ), ANP([QQ(2,1)], h, QQ), ANP([], h, QQ), ANP([], h, QQ)] + assert R.dup_factor_list(f) == \ + (anp([QQ(1, 1)]), [(anp([QQ(1, 1)])*x, 2), + (anp([QQ(1, 1)])*x**2 + anp([])*x + anp([QQ(2, 1)]), 1)]) - assert dup_factor_list(f, K) == \ - (ANP([QQ(1,1)], h, QQ), [([ANP([QQ(1,1)], h, QQ), ANP([], h, QQ)], 2), - ([ANP([QQ(1,1)], h, QQ), ANP([], h, QQ), ANP([QQ(2,1)], h, QQ)], 1)]) + R, x = ring("x", EX) + raises(DomainError, lambda: R.dup_factor_list(EX(sin(1)))) - raises(DomainError, lambda: dup_factor_list([EX(sin(1))], EX)) def test_dmp_factor_list(): - assert dmp_factor_list([[]], 1, ZZ) == (ZZ(0), []) - assert dmp_factor_list([[]], 1, QQ) == (QQ(0), []) - assert dmp_factor_list([[]], 1, ZZ['y']) == (DMP([],ZZ), []) - assert dmp_factor_list([[]], 1, QQ['y']) == (DMP([],QQ), []) + R, x, y = ring("x,y", ZZ) + assert R.dmp_factor_list(0) == (ZZ(0), []) + assert R.dmp_factor_list(7) == (7, []) + + R, x, y = ring("x,y", QQ) + assert R.dmp_factor_list(0) == (QQ(0), []) + assert R.dmp_factor_list(QQ(1, 7)) == (QQ(1, 7), []) - assert dmp_factor_list_include([[]], 1, ZZ) == [([[]], 1)] + R, x, y = ring("x,y", ZZ['y']) + assert R.dmp_factor_list(0) == (DMP([], ZZ), []) + assert R.dmp_factor_list(DMP([ZZ(7)], ZZ)) == (DMP([ZZ(7)], ZZ), []) - assert dmp_factor_list([[ZZ(7)]], 1, ZZ) == (ZZ(7), []) - assert dmp_factor_list([[QQ(1,7)]], 1, QQ) == (QQ(1,7), []) - assert dmp_factor_list([[DMP([ZZ(7)],ZZ)]], 1, ZZ['y']) == (DMP([ZZ(7)],ZZ), []) - assert dmp_factor_list([[DMP([QQ(1,7)],QQ)]], 1, QQ['y']) == (DMP([QQ(1,7)],QQ), []) + R, x, y = ring("x,y", QQ['y']) + assert R.dmp_factor_list(0) == (DMP([], QQ), []) + assert R.dmp_factor_list(DMP([QQ(1, 7)], QQ)) == (DMP([QQ(1, 7)], QQ), []) - assert dmp_factor_list_include([[ZZ(7)]], 1, ZZ) == [([[ZZ(7)]], 1)] + R, x, y = ring("x,y", ZZ) + assert R.dmp_factor_list_include(0) == [(0, 1)] + assert R.dmp_factor_list_include(7) == [(7, 1)] - f, g = [ZZ(1),ZZ(2),ZZ(1)], [ZZ(1),ZZ(1)] + R, X = xring("x:200", ZZ) - assert dmp_factor_list(dmp_nest(f, 200, ZZ), 200, ZZ) == \ - (ZZ(1), [(dmp_nest(g, 200, ZZ), 2)]) + f, g = X[0]**2 + 2*X[0] + 1, X[0] + 1 + assert R.dmp_factor_list(f) == (1, [(g, 2)]) - assert dmp_factor_list(dmp_raise(f, 200, 0, ZZ), 200, ZZ) == \ - (ZZ(1), [(dmp_raise(g, 200, 0, ZZ), 2)]) + f, g = X[-1]**2 + 2*X[-1] + 1, X[-1] + 1 + assert R.dmp_factor_list(f) == (1, [(g, 2)]) - assert dmp_factor_list([ZZ(1),ZZ(2),ZZ(1)], 0, ZZ) == \ - (ZZ(1), [([ZZ(1), ZZ(1)], 2)]) - assert dmp_factor_list([QQ(1,2),QQ(1),QQ(1,2)], 0, QQ) == \ - (QQ(1,2), [([QQ(1),QQ(1)], 2)]) + R, x = ring("x", ZZ) + assert R.dmp_factor_list(x**2 + 2*x + 1) == (1, [(x + 1, 2)]) + R, x = ring("x", QQ) + assert R.dmp_factor_list(QQ(1,2)*x**2 + x + QQ(1,2)) == (QQ(1,2), [(x + 1, 2)]) - assert dmp_factor_list([[ZZ(1)],[ZZ(2)],[ZZ(1)]], 1, ZZ) == \ - (ZZ(1), [([[ZZ(1)], [ZZ(1)]], 2)]) - assert dmp_factor_list([[QQ(1,2)],[QQ(1)],[QQ(1,2)]], 1, QQ) == \ - (QQ(1,2), [([[QQ(1)],[QQ(1)]], 2)]) + R, x, y = ring("x,y", ZZ) + assert R.dmp_factor_list(x**2 + 2*x + 1) == (1, [(x + 1, 2)]) + R, x, y = ring("x,y", QQ) + assert R.dmp_factor_list(QQ(1,2)*x**2 + x + QQ(1,2)) == (QQ(1,2), [(x + 1, 2)]) - f = [[ZZ(4),ZZ(0)],[ZZ(4),ZZ(0),ZZ(0)],[]] + R, x, y = ring("x,y", ZZ) + f = 4*x**2*y + 4*x*y**2 - assert dmp_factor_list(f, 1, ZZ) == \ - (ZZ(4), [([[ZZ(1),ZZ(0)]], 1), - ([[ZZ(1)],[]], 1), - ([[ZZ(1)],[ZZ(1),ZZ(0)]], 1)]) + assert R.dmp_factor_list(f) == \ + (4, [(y, 1), + (x, 1), + (x + y, 1)]) - assert dmp_factor_list_include(f, 1, ZZ) == \ - [([[ZZ(4),ZZ(0)]], 1), - ([[ZZ(1)],[]], 1), - ([[ZZ(1)],[ZZ(1),ZZ(0)]], 1)] + assert R.dmp_factor_list_include(f) == \ + [(4*y, 1), + (x, 1), + (x + y, 1)] - f = [[QQ(1,2),QQ(0)],[QQ(1,2),QQ(0),QQ(0)],[]] + R, x, y = ring("x,y", QQ) + f = QQ(1,2)*x**2*y + QQ(1,2)*x*y**2 - assert dmp_factor_list(f, 1, QQ) == \ - (QQ(1,2), [([[QQ(1),QQ(0)]], 1), - ([[QQ(1)],[]], 1), - ([[QQ(1)],[QQ(1),QQ(0)]], 1)]) + assert R.dmp_factor_list(f) == \ + (QQ(1,2), [(y, 1), + (x, 1), + (x + y, 1)]) - f = [[RR(2.0)],[],[-RR(8.0),RR(0.0),RR(0.0)]] + R, x, y = ring("x,y", RR) + f = 2.0*x**2 - 8.0*y**2 - assert dmp_factor_list(f, 1, RR) == \ - (RR(2.0), [([[RR(1.0)],[-RR(2.0),RR(0.0)]], 1), - ([[RR(1.0)],[ RR(2.0),RR(0.0)]], 1)]) + assert R.dmp_factor_list(f) == \ + (RR(2.0), [(1.0*x - 2.0*y, 1), + (1.0*x + 2.0*y, 1)]) - f = [[DMP([ZZ(4),ZZ(0)],ZZ)],[DMP([ZZ(4),ZZ(0),ZZ(0)],ZZ)],[DMP([],ZZ)]] + R, x, y = ring("x,y", ZZ['t']) + f = DMP([ZZ(4), ZZ(0)], ZZ)*x**2 + DMP([ZZ(4), ZZ(0), ZZ(0)], ZZ)*x - assert dmp_factor_list(f, 1, ZZ['y']) == \ - (DMP([ZZ(4)],ZZ), [([[DMP([ZZ(1),ZZ(0)],ZZ)]], 1), - ([[DMP([ZZ(1)],ZZ)],[]], 1), - ([[DMP([ZZ(1)],ZZ)],[DMP([ZZ(1),ZZ(0)],ZZ)]], 1)]) + assert R.dmp_factor_list(f) == \ + (DMP([ZZ(4)], ZZ), [(DMP([ZZ(1), ZZ(0)], ZZ), 1), + (DMP([ZZ(1)], ZZ)*x, 1), + (DMP([ZZ(1)], ZZ)*x + DMP([ZZ(1), ZZ(0)], ZZ), 1)]) - f = [[DMP([QQ(1,2),QQ(0)],ZZ)],[DMP([QQ(1,2),QQ(0),QQ(0)],ZZ)],[DMP([],ZZ)]] + R, x, y = ring("x,y", QQ['t']) + f = DMP([QQ(1, 2), QQ(0)], QQ)*x**2 + DMP([QQ(1, 2), QQ(0), QQ(0)], QQ)*x - assert dmp_factor_list(f, 1, QQ['y']) == \ - (DMP([QQ(1,2)],QQ), [([[DMP([QQ(1),QQ(0)],QQ)]], 1), - ([[DMP([QQ(1)],QQ)],[]], 1), - ([[DMP([QQ(1)],QQ)],[DMP([QQ(1),QQ(0)],QQ)]], 1)]) + assert R.dmp_factor_list(f) == \ + (DMP([QQ(1, 2)], QQ), [(DMP([QQ(1), QQ(0)], QQ), 1), + (DMP([QQ(1)], QQ)*x, 1), + (DMP([QQ(1)], QQ)*x + DMP([QQ(1), QQ(0)], QQ), 1)]) - K = FF(2) + R, x, y = ring("x,y", FF(2)) + raises(NotImplementedError, lambda: R.dmp_factor_list(x**2 + y**2)) + + R, x, y = ring("x,y", EX) + raises(DomainError, lambda: R.dmp_factor_list(EX(sin(1)))) - raises(DomainError, lambda: dmp_factor_list([[K(1)],[],[K(1),K(0),K(0)]], 1, K)) - raises(DomainError, lambda: dmp_factor_list([[EX(sin(1))]], 1, EX)) def test_dup_irreducible_p(): - assert dup_irreducible_p([ZZ(1),ZZ(1),ZZ(1)], ZZ) == True - assert dup_irreducible_p([ZZ(1),ZZ(2),ZZ(1)], ZZ) == False + R, x = ring("x", ZZ) + assert R.dup_irreducible_p(x**2 + x + 1) is True + assert R.dup_irreducible_p(x**2 + 2*x + 1) is False + def test_dmp_irreducible_p(): - assert dmp_irreducible_p([[ZZ(1)],[ZZ(1)],[ZZ(1)]], 1, ZZ) == True - assert dmp_irreducible_p([[ZZ(1)],[ZZ(2)],[ZZ(1)]], 1, ZZ) == False + R, x, y = ring("x,y", ZZ) + assert R.dmp_irreducible_p(x**2 + x + 1) is True + assert R.dmp_irreducible_p(x**2 + 2*x + 1) is False diff -Nru python3-sympy-0.7.2/sympy/polys/tests/test_fields.py python3-sympy-0.7.3/sympy/polys/tests/test_fields.py --- python3-sympy-0.7.2/sympy/polys/tests/test_fields.py 1970-01-01 00:00:00.000000000 +0000 +++ python3-sympy-0.7.3/sympy/polys/tests/test_fields.py 2013-07-13 17:53:32.000000000 +0000 @@ -0,0 +1,157 @@ +"""Test sparse rational functions. """ + +from sympy.polys.fields import field +from sympy.polys.domains import ZZ, QQ, RR +from sympy.polys.monomialtools import lex, grlex + +from sympy.utilities.pytest import raises +from sympy.core import Symbol, symbols +from sympy import sqrt, Rational + +def test_FracField___hash__(): + F, x, y, z = field("x,y,z", QQ) + assert hash(F) + +def test_FracElement___hash__(): + F, x, y, z = field("x,y,z", QQ) + assert hash(x*y/z) + +def test_FracElement_copy(): + F, x, y, z = field("x,y,z", ZZ) + + f = x*y/3*z + g = f.copy() + + assert f == g + g.numer[(1, 1, 1)] = 7 + assert f != g + +def test_FracElement_as_expr(): + F, x, y, z = field("x,y,z", ZZ) + f = (3*x**2*y - x*y*z)/(7*z**3 + 1) + + X, Y, Z = F.symbols + g = (3*X**2*Y - X*Y*Z)/(7*Z**3 + 1) + + assert f != g + assert f.as_expr() == g + + X, Y, Z = symbols("x,y,z") + g = (3*X**2*Y - X*Y*Z)/(7*Z**3 + 1) + + assert f != g + assert f.as_expr(X, Y, Z) == g + + raises(ValueError, lambda: f.as_expr(X)) + +def test_FracElement_from_expr(): + x, y, z = symbols("x,y,z") + F, X, Y, Z = field((x, y, z), ZZ) + + f = F.from_expr(1) + assert f == 1 and isinstance(f, F.dtype) + + f = F.from_expr(Rational(3, 7)) + assert f == F(3)/7 and isinstance(f, F.dtype) + + f = F.from_expr(x) + assert f == X and isinstance(f, F.dtype) + + f = F.from_expr(Rational(3,7)*x) + assert f == 3*X/7 and isinstance(f, F.dtype) + + f = F.from_expr(1/x) + assert f == 1/X and isinstance(f, F.dtype) + + f = F.from_expr(x*y*z) + assert f == X*Y*Z and isinstance(f, F.dtype) + + f = F.from_expr(x*y/z) + assert f == X*Y/Z and isinstance(f, F.dtype) + + f = F.from_expr(x*y*z + x*y + x) + assert f == X*Y*Z + X*Y + X and isinstance(f, F.dtype) + + f = F.from_expr((x*y*z + x*y + x)/(x*y + 7)) + assert f == (X*Y*Z + X*Y + X)/(X*Y + 7) and isinstance(f, F.dtype) + + f = F.from_expr(x**3*y*z + x**2*y**7 + 1) + assert f == X**3*Y*Z + X**2*Y**7 + 1 and isinstance(f, F.dtype) + + raises(ValueError, lambda: F.from_expr(2**x)) + raises(ValueError, lambda: F.from_expr(7*x + sqrt(2))) + +def test_FracElement___neg__(): + F, x,y = field("x,y", QQ) + + f = (7*x - 9)/y + g = (-7*x + 9)/y + + assert -f == g + assert -g == f + +def test_FracElement___add__(): + F, x,y = field("x,y", QQ) + + f, g = 1/x, 1/y + assert f + g == g + f == (x + y)/(x*y) + + assert x + F.ring.gens[0] == F.ring.gens[0] + x == 2*x + + F, x,y = field("x,y", ZZ) + assert x + 3 == 3 + x + assert x + QQ(3,7) == QQ(3,7) + x == (7*x + 3)/7 + +def test_FracElement___sub__(): + F, x,y = field("x,y", QQ) + + f, g = 1/x, 1/y + assert f - g == (-x + y)/(x*y) + + assert x - F.ring.gens[0] == F.ring.gens[0] - x == 0 + + F, x,y = field("x,y", ZZ) + assert x - 3 == -(3 - x) + assert x - QQ(3,7) == -(QQ(3,7) - x) == (7*x - 3)/7 + +def test_FracElement___mul__(): + F, x,y = field("x,y", QQ) + + f, g = 1/x, 1/y + assert f*g == g*f == 1/(x*y) + + assert x*F.ring.gens[0] == F.ring.gens[0]*x == x**2 + + F, x,y = field("x,y", ZZ) + assert x*3 == 3*x + assert x*QQ(3,7) == QQ(3,7)*x == 3*x/7 + + Fuv, u,v = field("u,v", ZZ); + Fxyzt, x,y,z,t = field("x,y,z,t", Fuv.to_domain()) + + f = ((u + 1)*x*y + 1)/((v - 1)*z - t*u*v - 1) + assert dict(f.numer) == {(1, 1, 0, 0): u + 1, (0, 0, 0, 0): 1} + assert dict(f.denom) == {(0, 0, 1, 0): v - 1, (0, 0, 0, 1): -u*v, (0, 0, 0, 0): -1} + +def test_FracElement___div__(): + F, x,y = field("x,y", QQ) + + f, g = 1/x, 1/y + assert f/g == y/x + + assert x/F.ring.gens[0] == F.ring.gens[0]/x == 1 + + F, x,y = field("x,y", ZZ) + assert x*3 == 3*x + assert x/QQ(3,7) == (QQ(3,7)/x)**-1 == 7*x/3 + +def test_FracElement___pow__(): + F, x,y = field("x,y", QQ) + + f, g = 1/x, 1/y + + assert f**3 == 1/x**3 + assert g**3 == 1/y**3 + + assert (f*g)**3 == 1/(x**3*y**3) + assert (f*g)**-3 == (x*y)**3 diff -Nru python3-sympy-0.7.2/sympy/polys/tests/test_galoistools.py python3-sympy-0.7.3/sympy/polys/tests/test_galoistools.py --- python3-sympy-0.7.2/sympy/polys/tests/test_galoistools.py 2012-10-17 03:02:22.000000000 +0000 +++ python3-sympy-0.7.3/sympy/polys/tests/test_galoistools.py 2013-07-13 17:53:32.000000000 +0000 @@ -36,6 +36,7 @@ from sympy import pi, nextprime from sympy.utilities.pytest import raises + def test_gf_crt(): U = [49, 76, 65] M = [99, 97, 95] @@ -51,32 +52,36 @@ assert gf_crt1(M, ZZ) == (p, E, S) assert gf_crt2(U, M, p, E, S, ZZ) == u + def test_gf_int(): assert gf_int(0, 5) == 0 assert gf_int(1, 5) == 1 assert gf_int(2, 5) == 2 - assert gf_int(3, 5) ==-2 - assert gf_int(4, 5) ==-1 + assert gf_int(3, 5) == -2 + assert gf_int(4, 5) == -1 assert gf_int(5, 5) == 0 + def test_gf_degree(): assert gf_degree([]) == -1 assert gf_degree([1]) == 0 - assert gf_degree([1,0]) == 1 - assert gf_degree([1,0,0,0,1]) == 4 + assert gf_degree([1, 0]) == 1 + assert gf_degree([1, 0, 0, 0, 1]) == 4 + def test_gf_strip(): assert gf_strip([]) == [] assert gf_strip([0]) == [] - assert gf_strip([0,0,0]) == [] + assert gf_strip([0, 0, 0]) == [] assert gf_strip([1]) == [1] - assert gf_strip([0,1]) == [1] - assert gf_strip([0,0,0,1]) == [1] + assert gf_strip([0, 1]) == [1] + assert gf_strip([0, 0, 0, 1]) == [1] + + assert gf_strip([1, 2, 0]) == [1, 2, 0] + assert gf_strip([0, 1, 2, 0]) == [1, 2, 0] + assert gf_strip([0, 0, 0, 1, 2, 0]) == [1, 2, 0] - assert gf_strip([1,2,0]) == [1,2,0] - assert gf_strip([0,1,2,0]) == [1,2,0] - assert gf_strip([0,0,0,1,2,0]) == [1,2,0] def test_gf_trunc(): assert gf_trunc([], 11) == [] @@ -84,23 +89,25 @@ assert gf_trunc([22], 11) == [] assert gf_trunc([12], 11) == [1] - assert gf_trunc([11,22,17,1,0], 11) == [6,1,0] - assert gf_trunc([12,23,17,1,0], 11) == [1,1,6,1,0] + assert gf_trunc([11, 22, 17, 1, 0], 11) == [6, 1, 0] + assert gf_trunc([12, 23, 17, 1, 0], 11) == [1, 1, 6, 1, 0] + def test_gf_normal(): - assert gf_normal([11,22,17,1,0], 11, ZZ) == [6,1,0] + assert gf_normal([11, 22, 17, 1, 0], 11, ZZ) == [6, 1, 0] + def test_gf_from_to_dict(): f = {11: 12, 6: 2, 0: 25} F = {11: 1, 6: 2, 0: 3} - g = [1,0,0,0,0,2,0,0,0,0,0,3] + g = [1, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 3] assert gf_from_dict(f, 11, ZZ) == g assert gf_to_dict(g, 11) == F f = {11: -5, 4: 0, 3: 1, 0: 12} F = {11: -5, 3: 1, 0: 1} - g = [6,0,0,0,0,0,0,0,1,0,0,1] + g = [6, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1] assert gf_from_dict(f, 11, ZZ) == g assert gf_to_dict(g, 11) == F @@ -108,36 +115,41 @@ assert gf_to_dict([10], 11, symmetric=True) == {0: -1} assert gf_to_dict([10], 11, symmetric=False) == {0: 10} + def test_gf_from_to_int_poly(): - assert gf_from_int_poly([1,0,7,2,20], 5) == [1,0,2,2,0] - assert gf_to_int_poly([1,0,4,2,3], 5) == [1,0,-1,2,-2] + assert gf_from_int_poly([1, 0, 7, 2, 20], 5) == [1, 0, 2, 2, 0] + assert gf_to_int_poly([1, 0, 4, 2, 3], 5) == [1, 0, -1, 2, -2] assert gf_to_int_poly([10], 11, symmetric=True) == [-1] assert gf_to_int_poly([10], 11, symmetric=False) == [10] + def test_gf_LC(): assert gf_LC([], ZZ) == 0 assert gf_LC([1], ZZ) == 1 - assert gf_LC([1,2], ZZ) == 1 + assert gf_LC([1, 2], ZZ) == 1 + def test_gf_TC(): assert gf_TC([], ZZ) == 0 assert gf_TC([1], ZZ) == 1 - assert gf_TC([1,2], ZZ) == 2 + assert gf_TC([1, 2], ZZ) == 2 + def test_gf_monic(): - assert gf_monic([], 11, ZZ) == (0, []) + assert gf_monic(ZZ.map([]), 11, ZZ) == (0, []) + + assert gf_monic(ZZ.map([1]), 11, ZZ) == (1, [1]) + assert gf_monic(ZZ.map([2]), 11, ZZ) == (2, [1]) - assert gf_monic([1], 11, ZZ) == (1, [1]) - assert gf_monic([2], 11, ZZ) == (2, [1]) + assert gf_monic(ZZ.map([1, 2, 3, 4]), 11, ZZ) == (1, [1, 2, 3, 4]) + assert gf_monic(ZZ.map([2, 3, 4, 5]), 11, ZZ) == (2, [1, 7, 2, 8]) - assert gf_monic([1,2,3,4], 11, ZZ) == (1, [1,2,3,4]) - assert gf_monic([2,3,4,5], 11, ZZ) == (2, [1,7,2,8]) def test_gf_arith(): assert gf_neg([], 11, ZZ) == [] assert gf_neg([1], 11, ZZ) == [10] - assert gf_neg([1,2,3], 11, ZZ) == [10,9,8] + assert gf_neg([1, 2, 3], 11, ZZ) == [10, 9, 8] assert gf_add_ground([], 0, 11, ZZ) == [] assert gf_sub_ground([], 0, 11, ZZ) == [] @@ -151,8 +163,8 @@ assert gf_add_ground([8], 3, 11, ZZ) == [] assert gf_sub_ground([3], 3, 11, ZZ) == [] - assert gf_add_ground([1,2,3], 3, 11, ZZ) == [1,2,6] - assert gf_sub_ground([1,2,3], 3, 11, ZZ) == [1,2,0] + assert gf_add_ground([1, 2, 3], 3, 11, ZZ) == [1, 2, 6] + assert gf_sub_ground([1, 2, 3], 3, 11, ZZ) == [1, 2, 0] assert gf_mul_ground([], 0, 11, ZZ) == [] assert gf_mul_ground([], 1, 11, ZZ) == [] @@ -160,9 +172,9 @@ assert gf_mul_ground([1], 0, 11, ZZ) == [] assert gf_mul_ground([1], 1, 11, ZZ) == [1] - assert gf_mul_ground([1,2,3], 0, 11, ZZ) == [] - assert gf_mul_ground([1,2,3], 1, 11, ZZ) == [1,2,3] - assert gf_mul_ground([1,2,3], 7, 11, ZZ) == [7,3,10] + assert gf_mul_ground([1, 2, 3], 0, 11, ZZ) == [] + assert gf_mul_ground([1, 2, 3], 1, 11, ZZ) == [1, 2, 3] + assert gf_mul_ground([1, 2, 3], 7, 11, ZZ) == [7, 3, 10] assert gf_add([], [], 11, ZZ) == [] assert gf_add([1], [], 11, ZZ) == [1] @@ -170,10 +182,10 @@ assert gf_add([1], [1], 11, ZZ) == [2] assert gf_add([1], [2], 11, ZZ) == [3] - assert gf_add([1,2], [1], 11, ZZ) == [1,3] - assert gf_add([1], [1,2], 11, ZZ) == [1,3] + assert gf_add([1, 2], [1], 11, ZZ) == [1, 3] + assert gf_add([1], [1, 2], 11, ZZ) == [1, 3] - assert gf_add([1,2,3], [8,9,10], 11, ZZ) == [9,0,2] + assert gf_add([1, 2, 3], [8, 9, 10], 11, ZZ) == [9, 0, 2] assert gf_sub([], [], 11, ZZ) == [] assert gf_sub([1], [], 11, ZZ) == [1] @@ -181,13 +193,15 @@ assert gf_sub([1], [1], 11, ZZ) == [] assert gf_sub([1], [2], 11, ZZ) == [10] - assert gf_sub([1,2], [1], 11, ZZ) == [1,1] - assert gf_sub([1], [1,2], 11, ZZ) == [10,10] + assert gf_sub([1, 2], [1], 11, ZZ) == [1, 1] + assert gf_sub([1], [1, 2], 11, ZZ) == [10, 10] - assert gf_sub([3,2,1], [8,9,10], 11, ZZ) == [6,4,2] + assert gf_sub([3, 2, 1], [8, 9, 10], 11, ZZ) == [6, 4, 2] - assert gf_add_mul([1,5,6], [7,3], [8,0,6,1], 11, ZZ) == [1,2,10,8,9] - assert gf_sub_mul([1,5,6], [7,3], [8,0,6,1], 11, ZZ) == [10,9,3,2,3] + assert gf_add_mul( + [1, 5, 6], [7, 3], [8, 0, 6, 1], 11, ZZ) == [1, 2, 10, 8, 9] + assert gf_sub_mul( + [1, 5, 6], [7, 3], [8, 0, 6, 1], 11, ZZ) == [10, 9, 3, 2, 3] assert gf_mul([], [], 11, ZZ) == [] assert gf_mul([], [1], 11, ZZ) == [] @@ -195,28 +209,35 @@ assert gf_mul([1], [1], 11, ZZ) == [1] assert gf_mul([5], [7], 11, ZZ) == [2] - assert gf_mul([3,0,0,6,1,2], [4,0,1,0], 11, ZZ) == [1,0,3,2,4,3,1,2,0] - assert gf_mul([4,0,1,0], [3,0,0,6,1,2], 11, ZZ) == [1,0,3,2,4,3,1,2,0] + assert gf_mul([3, 0, 0, 6, 1, 2], [4, 0, 1, 0], 11, ZZ) == [1, 0, + 3, 2, 4, 3, 1, 2, 0] + assert gf_mul([4, 0, 1, 0], [3, 0, 0, 6, 1, 2], 11, ZZ) == [1, 0, + 3, 2, 4, 3, 1, 2, 0] - assert gf_mul([2,0,0,1,7], [2,0,0,1,7], 11, ZZ) == [4,0,0,4,6,0,1,3,5] + assert gf_mul([2, 0, 0, 1, 7], [2, 0, 0, 1, 7], 11, ZZ) == [4, 0, + 0, 4, 6, 0, 1, 3, 5] assert gf_sqr([], 11, ZZ) == [] assert gf_sqr([2], 11, ZZ) == [4] - assert gf_sqr([1,2], 11, ZZ) == [1,4,4] + assert gf_sqr([1, 2], 11, ZZ) == [1, 4, 4] - assert gf_sqr([2,0,0,1,7], 11, ZZ) == [4,0,0,4,6,0,1,3,5] + assert gf_sqr([2, 0, 0, 1, 7], 11, ZZ) == [4, 0, 0, 4, 6, 0, 1, 3, 5] -def test_gf_division(): - raises(ZeroDivisionError, lambda: gf_div([1,2,3], [], 11, ZZ)) - raises(ZeroDivisionError, lambda: gf_rem([1,2,3], [], 11, ZZ)) - raises(ZeroDivisionError, lambda: gf_quo([1,2,3], [], 11, ZZ)) - raises(ZeroDivisionError, lambda: gf_quo([1,2,3], [], 11, ZZ)) - - assert gf_div([1], [1,2,3], 7, ZZ) == ([], [1]) - assert gf_rem([1], [1,2,3], 7, ZZ) == [1] - assert gf_quo([1], [1,2,3], 7, ZZ) == [] - f, g, q, r = [5,4,3,2,1,0], [1,2,3], [5,1,0,6], [3,3] +def test_gf_division(): + raises(ZeroDivisionError, lambda: gf_div([1, 2, 3], [], 11, ZZ)) + raises(ZeroDivisionError, lambda: gf_rem([1, 2, 3], [], 11, ZZ)) + raises(ZeroDivisionError, lambda: gf_quo([1, 2, 3], [], 11, ZZ)) + raises(ZeroDivisionError, lambda: gf_quo([1, 2, 3], [], 11, ZZ)) + + assert gf_div([1], [1, 2, 3], 7, ZZ) == ([], [1]) + assert gf_rem([1], [1, 2, 3], 7, ZZ) == [1] + assert gf_quo([1], [1, 2, 3], 7, ZZ) == [] + + f = ZZ.map([5, 4, 3, 2, 1, 0]) + g = ZZ.map([1, 2, 3]) + q = [5, 1, 0, 6] + r = [3, 3] assert gf_div(f, g, 7, ZZ) == (q, r) assert gf_rem(f, g, 7, ZZ) == r @@ -224,7 +245,10 @@ raises(ExactQuotientFailed, lambda: gf_exquo(f, g, 7, ZZ)) - f, g, q, r = [5,4,3,2,1,0], [1,2,3,0], [5,1,0], [6,1,0] + f = ZZ.map([5, 4, 3, 2, 1, 0]) + g = ZZ.map([1, 2, 3, 0]) + q = [5, 1, 0] + r = [6, 1, 0] assert gf_div(f, g, 7, ZZ) == (q, r) assert gf_rem(f, g, 7, ZZ) == r @@ -232,115 +256,126 @@ raises(ExactQuotientFailed, lambda: gf_exquo(f, g, 7, ZZ)) - assert gf_quo([1,2,1], [1,1], 11, ZZ) == [1,1] + assert gf_quo(ZZ.map([1, 2, 1]), ZZ.map([1, 1]), 11, ZZ) == [1, 1] + def test_gf_shift(): - f = [1,2,3,4,5] + f = [1, 2, 3, 4, 5] assert gf_lshift([], 5, ZZ) == [] assert gf_rshift([], 5, ZZ) == ([], []) - assert gf_lshift(f, 1, ZZ) == [1,2,3,4,5,0] - assert gf_lshift(f, 2, ZZ) == [1,2,3,4,5,0,0] + assert gf_lshift(f, 1, ZZ) == [1, 2, 3, 4, 5, 0] + assert gf_lshift(f, 2, ZZ) == [1, 2, 3, 4, 5, 0, 0] assert gf_rshift(f, 0, ZZ) == (f, []) - assert gf_rshift(f, 1, ZZ) == ([1,2,3,4], [5]) - assert gf_rshift(f, 3, ZZ) == ([1,2], [3,4,5]) + assert gf_rshift(f, 1, ZZ) == ([1, 2, 3, 4], [5]) + assert gf_rshift(f, 3, ZZ) == ([1, 2], [3, 4, 5]) assert gf_rshift(f, 5, ZZ) == ([], f) + def test_gf_expand(): - F = [([1,1], 2), ([1,2], 3)] + F = [([1, 1], 2), ([1, 2], 3)] + + assert gf_expand(F, 11, ZZ) == [1, 8, 3, 5, 6, 8] + assert gf_expand((4, F), 11, ZZ) == [4, 10, 1, 9, 2, 10] - assert gf_expand(F, 11, ZZ) == [1,8,3,5,6,8] - assert gf_expand((4, F), 11, ZZ) == [4,10,1,9,2,10] def test_gf_powering(): - assert gf_pow([1,0,0,1,8], 0, 11, ZZ) == [1] - assert gf_pow([1,0,0,1,8], 1, 11, ZZ) == [1, 0, 0, 1, 8] - assert gf_pow([1,0,0,1,8], 2, 11, ZZ) == [1, 0, 0, 2, 5, 0, 1, 5, 9] + assert gf_pow([1, 0, 0, 1, 8], 0, 11, ZZ) == [1] + assert gf_pow([1, 0, 0, 1, 8], 1, 11, ZZ) == [1, 0, 0, 1, 8] + assert gf_pow([1, 0, 0, 1, 8], 2, 11, ZZ) == [1, 0, 0, 2, 5, 0, 1, 5, 9] - assert gf_pow([1,0,0,1,8], 5, 11, ZZ) == \ + assert gf_pow([1, 0, 0, 1, 8], 5, 11, ZZ) == \ [1, 0, 0, 5, 7, 0, 10, 6, 2, 10, 9, 6, 10, 6, 6, 0, 5, 2, 5, 9, 10] - assert gf_pow([1,0,0,1,8], 8, 11, ZZ) == \ + assert gf_pow([1, 0, 0, 1, 8], 8, 11, ZZ) == \ [1, 0, 0, 8, 9, 0, 6, 8, 10, 1, 2, 5, 10, 7, 7, 9, 1, 2, 0, 0, 6, 2, 5, 2, 5, 7, 7, 9, 10, 10, 7, 5, 5] - assert gf_pow([1,0,0,1,8], 45, 11, ZZ) == \ - [ 1, 0, 0, 1, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 4, 10, 0, 0, 0, 0, 0, 0, - 10, 0, 0, 10, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 6, 0, 0, 6, 4, 0, 0, 0, 0, 0, 0, 8, 0, 0, 8, 9, 0, 0, 0, 0, 0, 0, - 10, 0, 0, 10, 3, 0, 0, 0, 0, 0, 0, 4, 0, 0, 4, 10, 0, 0, 0, 0, 0, 0, - 8, 0, 0, 8, 9, 0, 0, 0, 0, 0, 0, 9, 0, 0, 9, 6, 0, 0, 0, 0, 0, 0, - 3, 0, 0, 3, 2, 0, 0, 0, 0, 0, 0, 10, 0, 0, 10, 3, 0, 0, 0, 0, 0, 0, - 10, 0, 0, 10, 3, 0, 0, 0, 0, 0, 0, 2, 0, 0, 2, 5, 0, 0, 0, 0, 0, 0, - 4, 0, 0, 4, 10] - - assert gf_pow_mod([1,0,0,1,8], 0, [2,0,7], 11, ZZ) == [1] - assert gf_pow_mod([1,0,0,1,8], 1, [2,0,7], 11, ZZ) == [1,1] - assert gf_pow_mod([1,0,0,1,8], 2, [2,0,7], 11, ZZ) == [2,3] - assert gf_pow_mod([1,0,0,1,8], 5, [2,0,7], 11, ZZ) == [7,8] - assert gf_pow_mod([1,0,0,1,8], 8, [2,0,7], 11, ZZ) == [1,5] - assert gf_pow_mod([1,0,0,1,8], 45, [2,0,7], 11, ZZ) == [5,4] + assert gf_pow([1, 0, 0, 1, 8], 45, 11, ZZ) == \ + [ 1, 0, 0, 1, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 4, 10, 0, 0, 0, 0, 0, 0, + 10, 0, 0, 10, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 6, 0, 0, 6, 4, 0, 0, 0, 0, 0, 0, 8, 0, 0, 8, 9, 0, 0, 0, 0, 0, 0, + 10, 0, 0, 10, 3, 0, 0, 0, 0, 0, 0, 4, 0, 0, 4, 10, 0, 0, 0, 0, 0, 0, + 8, 0, 0, 8, 9, 0, 0, 0, 0, 0, 0, 9, 0, 0, 9, 6, 0, 0, 0, 0, 0, 0, + 3, 0, 0, 3, 2, 0, 0, 0, 0, 0, 0, 10, 0, 0, 10, 3, 0, 0, 0, 0, 0, 0, + 10, 0, 0, 10, 3, 0, 0, 0, 0, 0, 0, 2, 0, 0, 2, 5, 0, 0, 0, 0, 0, 0, + 4, 0, 0, 4, 10] + + assert gf_pow_mod(ZZ.map([1, 0, 0, 1, 8]), 0, ZZ.map([2, 0, 7]), 11, ZZ) == [1] + assert gf_pow_mod(ZZ.map([1, 0, 0, 1, 8]), 1, ZZ.map([2, 0, 7]), 11, ZZ) == [1, 1] + assert gf_pow_mod(ZZ.map([1, 0, 0, 1, 8]), 2, ZZ.map([2, 0, 7]), 11, ZZ) == [2, 3] + assert gf_pow_mod(ZZ.map([1, 0, 0, 1, 8]), 5, ZZ.map([2, 0, 7]), 11, ZZ) == [7, 8] + assert gf_pow_mod(ZZ.map([1, 0, 0, 1, 8]), 8, ZZ.map([2, 0, 7]), 11, ZZ) == [1, 5] + assert gf_pow_mod(ZZ.map([1, 0, 0, 1, 8]), 45, ZZ.map([2, 0, 7]), 11, ZZ) == [5, 4] + def test_gf_gcdex(): - assert gf_gcdex([], [], 11, ZZ) == ([1], [], []) - assert gf_gcdex([2], [], 11, ZZ) == ([6], [], [1]) - assert gf_gcdex([], [2], 11, ZZ) == ([], [6], [1]) - assert gf_gcdex([2], [2], 11, ZZ) == ([], [6], [1]) + assert gf_gcdex(ZZ.map([]), ZZ.map([]), 11, ZZ) == ([1], [], []) + assert gf_gcdex(ZZ.map([2]), ZZ.map([]), 11, ZZ) == ([6], [], [1]) + assert gf_gcdex(ZZ.map([]), ZZ.map([2]), 11, ZZ) == ([], [6], [1]) + assert gf_gcdex(ZZ.map([2]), ZZ.map([2]), 11, ZZ) == ([], [6], [1]) - assert gf_gcdex([], [3,0], 11, ZZ) == ([], [4], [1,0]) - assert gf_gcdex([3,0], [], 11, ZZ) == ([4], [], [1,0]) + assert gf_gcdex(ZZ.map([]), ZZ.map([3, 0]), 11, ZZ) == ([], [4], [1, 0]) + assert gf_gcdex(ZZ.map([3, 0]), ZZ.map([]), 11, ZZ) == ([4], [], [1, 0]) - assert gf_gcdex([3,0], [3,0], 11, ZZ) == ([], [4], [1,0]) + assert gf_gcdex(ZZ.map([3, 0]), ZZ.map([3, 0]), 11, ZZ) == ([], [4], [1, 0]) + + assert gf_gcdex(ZZ.map([1, 8, 7]), ZZ.map([1, 7, 1, 7]), 11, ZZ) == ([5, 6], [6], [1, 7]) - assert gf_gcdex([1,8,7], [1,7,1,7], 11, ZZ) == ([5,6], [6], [1,7]) def test_gf_gcd(): - assert gf_gcd([], [], 11, ZZ) == [] - assert gf_gcd([2], [], 11, ZZ) == [1] - assert gf_gcd([], [2], 11, ZZ) == [1] - assert gf_gcd([2], [2], 11, ZZ) == [1] + assert gf_gcd(ZZ.map([]), ZZ.map([]), 11, ZZ) == [] + assert gf_gcd(ZZ.map([2]), ZZ.map([]), 11, ZZ) == [1] + assert gf_gcd(ZZ.map([]), ZZ.map([2]), 11, ZZ) == [1] + assert gf_gcd(ZZ.map([2]), ZZ.map([2]), 11, ZZ) == [1] + + assert gf_gcd(ZZ.map([]), ZZ.map([1, 0]), 11, ZZ) == [1, 0] + assert gf_gcd(ZZ.map([1, 0]), ZZ.map([]), 11, ZZ) == [1, 0] - assert gf_gcd([], [1,0], 11, ZZ) == [1,0] - assert gf_gcd([1,0], [], 11, ZZ) == [1,0] + assert gf_gcd(ZZ.map([3, 0]), ZZ.map([3, 0]), 11, ZZ) == [1, 0] + assert gf_gcd(ZZ.map([1, 8, 7]), ZZ.map([1, 7, 1, 7]), 11, ZZ) == [1, 7] - assert gf_gcd([3,0], [3,0], 11, ZZ) == [1,0] - assert gf_gcd([1,8,7], [1,7,1,7], 11, ZZ) == [1,7] def test_gf_lcm(): - assert gf_lcm([], [], 11, ZZ) == [] - assert gf_lcm([2], [], 11, ZZ) == [] - assert gf_lcm([], [2], 11, ZZ) == [] - assert gf_lcm([2], [2], 11, ZZ) == [1] + assert gf_lcm(ZZ.map([]), ZZ.map([]), 11, ZZ) == [] + assert gf_lcm(ZZ.map([2]), ZZ.map([]), 11, ZZ) == [] + assert gf_lcm(ZZ.map([]), ZZ.map([2]), 11, ZZ) == [] + assert gf_lcm(ZZ.map([2]), ZZ.map([2]), 11, ZZ) == [1] - assert gf_lcm([], [1,0], 11, ZZ) == [] - assert gf_lcm([1,0], [], 11, ZZ) == [] + assert gf_lcm(ZZ.map([]), ZZ.map([1, 0]), 11, ZZ) == [] + assert gf_lcm(ZZ.map([1, 0]), ZZ.map([]), 11, ZZ) == [] - assert gf_lcm([3,0], [3,0], 11, ZZ) == [1,0] - assert gf_lcm([1,8,7], [1,7,1,7], 11, ZZ) == [1,8,8,8,7] + assert gf_lcm(ZZ.map([3, 0]), ZZ.map([3, 0]), 11, ZZ) == [1, 0] + assert gf_lcm(ZZ.map([1, 8, 7]), ZZ.map([1, 7, 1, 7]), 11, ZZ) == [1, 8, 8, 8, 7] -def test_gf_cofactors(): - assert gf_cofactors([], [], 11, ZZ) == ([], [], []) - assert gf_cofactors([2], [], 11, ZZ) == ([1], [2], []) - assert gf_cofactors([], [2], 11, ZZ) == ([1], [], [2]) - assert gf_cofactors([2], [2], 11, ZZ) == ([1], [2], [2]) - assert gf_cofactors([], [1,0], 11, ZZ) == ([1,0], [], [1]) - assert gf_cofactors([1,0], [], 11, ZZ) == ([1,0], [1], []) +def test_gf_cofactors(): + assert gf_cofactors(ZZ.map([]), ZZ.map([]), 11, ZZ) == ([], [], []) + assert gf_cofactors(ZZ.map([2]), ZZ.map([]), 11, ZZ) == ([1], [2], []) + assert gf_cofactors(ZZ.map([]), ZZ.map([2]), 11, ZZ) == ([1], [], [2]) + assert gf_cofactors(ZZ.map([2]), ZZ.map([2]), 11, ZZ) == ([1], [2], [2]) + + assert gf_cofactors(ZZ.map([]), ZZ.map([1, 0]), 11, ZZ) == ([1, 0], [], [1]) + assert gf_cofactors(ZZ.map([1, 0]), ZZ.map([]), 11, ZZ) == ([1, 0], [1], []) + + assert gf_cofactors(ZZ.map([3, 0]), ZZ.map([3, 0]), 11, ZZ) == ( + [1, 0], [3], [3]) + assert gf_cofactors(ZZ.map([1, 8, 7]), ZZ.map([1, 7, 1, 7]), 11, ZZ) == ( + ([1, 7], [1, 1], [1, 0, 1])) - assert gf_cofactors([3,0], [3,0], 11, ZZ) == ([1,0], [3], [3]) - assert gf_cofactors([1,8,7], [1,7,1,7], 11, ZZ) == (([1,7], [1,1], [1,0,1])) def test_gf_diff(): assert gf_diff([], 11, ZZ) == [] assert gf_diff([7], 11, ZZ) == [] - assert gf_diff([7,3], 11, ZZ) == [7] - assert gf_diff([7,3,1], 11, ZZ) == [3,3] + assert gf_diff([7, 3], 11, ZZ) == [7] + assert gf_diff([7, 3, 1], 11, ZZ) == [3, 3] + + assert gf_diff([1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], 11, ZZ) == [] - assert gf_diff([1,0,0,0,0,0,0,0,0,0,0,1], 11, ZZ) == [] def test_gf_eval(): assert gf_eval([], 4, 11, ZZ) == 0 @@ -348,31 +383,37 @@ assert gf_eval([7], 4, 11, ZZ) == 7 assert gf_eval([7], 27, 11, ZZ) == 7 - assert gf_eval([1,0,3,2,4,3,1,2,0], 0, 11, ZZ) == 0 - assert gf_eval([1,0,3,2,4,3,1,2,0], 4, 11, ZZ) == 9 - assert gf_eval([1,0,3,2,4,3,1,2,0], 27, 11, ZZ) == 5 - - assert gf_eval([4,0,0,4,6,0,1,3,5], 0, 11, ZZ) == 5 - assert gf_eval([4,0,0,4,6,0,1,3,5], 4, 11, ZZ) == 3 - assert gf_eval([4,0,0,4,6,0,1,3,5], 27, 11, ZZ) == 9 + assert gf_eval([1, 0, 3, 2, 4, 3, 1, 2, 0], 0, 11, ZZ) == 0 + assert gf_eval([1, 0, 3, 2, 4, 3, 1, 2, 0], 4, 11, ZZ) == 9 + assert gf_eval([1, 0, 3, 2, 4, 3, 1, 2, 0], 27, 11, ZZ) == 5 + + assert gf_eval([4, 0, 0, 4, 6, 0, 1, 3, 5], 0, 11, ZZ) == 5 + assert gf_eval([4, 0, 0, 4, 6, 0, 1, 3, 5], 4, 11, ZZ) == 3 + assert gf_eval([4, 0, 0, 4, 6, 0, 1, 3, 5], 27, 11, ZZ) == 9 + + assert gf_multi_eval([3, 2, 1], [0, 1, 2, 3], 11, ZZ) == [1, 6, 6, 1] - assert gf_multi_eval([3,2,1], [0,1,2,3], 11, ZZ) == [1,6,6,1] def test_gf_compose(): - assert gf_compose([], [1,0], 11, ZZ) == [] - assert gf_compose_mod([], [1,0], [1,0], 11, ZZ) == [] + assert gf_compose([], [1, 0], 11, ZZ) == [] + assert gf_compose_mod([], [1, 0], [1, 0], 11, ZZ) == [] assert gf_compose([1], [], 11, ZZ) == [1] - assert gf_compose([1,0], [], 11, ZZ) == [] - assert gf_compose([1,0], [1,0], 11, ZZ) == [1,0] + assert gf_compose([1, 0], [], 11, ZZ) == [] + assert gf_compose([1, 0], [1, 0], 11, ZZ) == [1, 0] + + f = ZZ.map([1, 1, 4, 9, 1]) + g = ZZ.map([1, 1, 1]) + h = ZZ.map([1, 0, 0, 2]) - f, g, h = [1, 1, 4, 9, 1], [1,1,1], [1,0,0,2] + assert gf_compose(g, h, 11, ZZ) == [1, 0, 0, 5, 0, 0, 7] + assert gf_compose_mod(g, h, f, 11, ZZ) == [3, 9, 6, 10] - assert gf_compose(g, h, 11, ZZ) == [1,0,0,5,0,0,7] - assert gf_compose_mod(g, h, f, 11, ZZ) == [3,9,6,10] def test_gf_trace_map(): - f, a, c = [1, 1, 4, 9, 1], [1,1,1], [1,0] + f = ZZ.map([1, 1, 4, 9, 1]) + a = [1, 1, 1] + c = ZZ.map([1, 0]) b = gf_pow_mod(c, 11, f, 11, ZZ) assert gf_trace_map(a, b, c, 0, f, 11, ZZ) == \ @@ -390,74 +431,77 @@ assert gf_trace_map(a, b, c, 11, f, 11, ZZ) == \ ([1, 10, 6, 0], [10]) + def test_gf_irreducible(): - assert gf_irreducible_p(gf_irreducible(1, 11, ZZ), 11, ZZ) == True - assert gf_irreducible_p(gf_irreducible(2, 11, ZZ), 11, ZZ) == True - assert gf_irreducible_p(gf_irreducible(3, 11, ZZ), 11, ZZ) == True - assert gf_irreducible_p(gf_irreducible(4, 11, ZZ), 11, ZZ) == True - assert gf_irreducible_p(gf_irreducible(5, 11, ZZ), 11, ZZ) == True - assert gf_irreducible_p(gf_irreducible(6, 11, ZZ), 11, ZZ) == True - assert gf_irreducible_p(gf_irreducible(7, 11, ZZ), 11, ZZ) == True + assert gf_irreducible_p(gf_irreducible(1, 11, ZZ), 11, ZZ) is True + assert gf_irreducible_p(gf_irreducible(2, 11, ZZ), 11, ZZ) is True + assert gf_irreducible_p(gf_irreducible(3, 11, ZZ), 11, ZZ) is True + assert gf_irreducible_p(gf_irreducible(4, 11, ZZ), 11, ZZ) is True + assert gf_irreducible_p(gf_irreducible(5, 11, ZZ), 11, ZZ) is True + assert gf_irreducible_p(gf_irreducible(6, 11, ZZ), 11, ZZ) is True + assert gf_irreducible_p(gf_irreducible(7, 11, ZZ), 11, ZZ) is True + def test_gf_irreducible_p(): - assert gf_irred_p_ben_or([7], 11, ZZ) == True - assert gf_irred_p_ben_or([7,3], 11, ZZ) == True - assert gf_irred_p_ben_or([7,3,1], 11, ZZ) == False - - assert gf_irred_p_rabin([7], 11, ZZ) == True - assert gf_irred_p_rabin([7,3], 11, ZZ) == True - assert gf_irred_p_rabin([7,3,1], 11, ZZ) == False + assert gf_irred_p_ben_or(ZZ.map([7]), 11, ZZ) is True + assert gf_irred_p_ben_or(ZZ.map([7, 3]), 11, ZZ) is True + assert gf_irred_p_ben_or(ZZ.map([7, 3, 1]), 11, ZZ) is False + + assert gf_irred_p_rabin(ZZ.map([7]), 11, ZZ) is True + assert gf_irred_p_rabin(ZZ.map([7, 3]), 11, ZZ) is True + assert gf_irred_p_rabin(ZZ.map([7, 3, 1]), 11, ZZ) is False config.setup('GF_IRRED_METHOD', 'ben-or') - assert gf_irreducible_p([7], 11, ZZ) == True - assert gf_irreducible_p([7,3], 11, ZZ) == True - assert gf_irreducible_p([7,3,1], 11, ZZ) == False + assert gf_irreducible_p(ZZ.map([7]), 11, ZZ) is True + assert gf_irreducible_p(ZZ.map([7, 3]), 11, ZZ) is True + assert gf_irreducible_p(ZZ.map([7, 3, 1]), 11, ZZ) is False config.setup('GF_IRRED_METHOD', 'rabin') - assert gf_irreducible_p([7], 11, ZZ) == True - assert gf_irreducible_p([7,3], 11, ZZ) == True - assert gf_irreducible_p([7,3,1], 11, ZZ) == False + assert gf_irreducible_p(ZZ.map([7]), 11, ZZ) is True + assert gf_irreducible_p(ZZ.map([7, 3]), 11, ZZ) is True + assert gf_irreducible_p(ZZ.map([7, 3, 1]), 11, ZZ) is False config.setup('GF_IRRED_METHOD', 'other') raises(KeyError, lambda: gf_irreducible_p([7], 11, ZZ)) config.setup('GF_IRRED_METHOD') - f = [1, 9, 9, 13, 16, 15, 6, 7, 7, 7, 10] - g = [1, 7, 16, 7, 15, 13, 13, 11, 16, 10, 9] + f = ZZ.map([1, 9, 9, 13, 16, 15, 6, 7, 7, 7, 10]) + g = ZZ.map([1, 7, 16, 7, 15, 13, 13, 11, 16, 10, 9]) h = gf_mul(f, g, 17, ZZ) - assert gf_irred_p_ben_or(f, 17, ZZ) == True - assert gf_irred_p_ben_or(g, 17, ZZ) == True + assert gf_irred_p_ben_or(f, 17, ZZ) is True + assert gf_irred_p_ben_or(g, 17, ZZ) is True - assert gf_irred_p_ben_or(h, 17, ZZ) == False + assert gf_irred_p_ben_or(h, 17, ZZ) is False - assert gf_irred_p_rabin(f, 17, ZZ) == True - assert gf_irred_p_rabin(g, 17, ZZ) == True + assert gf_irred_p_rabin(f, 17, ZZ) is True + assert gf_irred_p_rabin(g, 17, ZZ) is True + + assert gf_irred_p_rabin(h, 17, ZZ) is False - assert gf_irred_p_rabin(h, 17, ZZ) == False def test_gf_squarefree(): assert gf_sqf_list([], 11, ZZ) == (0, []) assert gf_sqf_list([1], 11, ZZ) == (1, []) - assert gf_sqf_list([1,1], 11, ZZ) == (1, [([1, 1], 1)]) + assert gf_sqf_list([1, 1], 11, ZZ) == (1, [([1, 1], 1)]) - assert gf_sqf_p([], 11, ZZ) == True - assert gf_sqf_p([1], 11, ZZ) == True - assert gf_sqf_p([1,1], 11, ZZ) == True + assert gf_sqf_p([], 11, ZZ) is True + assert gf_sqf_p([1], 11, ZZ) is True + assert gf_sqf_p([1, 1], 11, ZZ) is True f = gf_from_dict({11: 1, 0: 1}, 11, ZZ) - assert gf_sqf_p(f, 11, ZZ) == False + assert gf_sqf_p(f, 11, ZZ) is False assert gf_sqf_list(f, 11, ZZ) == \ - (1, [([1, 1], 11)]) + (1, [([1, 1], 11)]) f = [1, 5, 8, 4] - assert gf_sqf_p(f, 11, ZZ) == False + assert gf_sqf_p(f, 11, ZZ) is False assert gf_sqf_list(f, 11, ZZ) == \ (1, [([1, 1], 1), @@ -465,22 +509,23 @@ assert gf_sqf_part(f, 11, ZZ) == [1, 3, 2] - f = [1,0,0,2,0,0,2,0,0,1,0] + f = [1, 0, 0, 2, 0, 0, 2, 0, 0, 1, 0] assert gf_sqf_list(f, 3, ZZ) == \ (1, [([1, 0], 1), ([1, 1], 3), ([1, 2], 6)]) + def test_gf_berlekamp(): - f = gf_from_int_poly([1,-3,1,-3,-1,-3,1], 11) + f = gf_from_int_poly([1, -3, 1, -3, -1, -3, 1], 11) Q = [[1, 0, 0, 0, 0, 0], [3, 5, 8, 8, 6, 5], - [3, 6, 6, 1,10, 0], - [9, 4,10, 3, 7, 9], - [7, 8,10, 0, 0, 8], - [8,10, 7, 8,10, 8]] + [3, 6, 6, 1, 10, 0], + [9, 4, 10, 3, 7, 9], + [7, 8, 10, 0, 0, 8], + [8, 10, 7, 8, 10, 8]] V = [[1, 0, 0, 0, 0, 0], [0, 1, 1, 1, 1, 0], @@ -492,20 +537,20 @@ assert gf_berlekamp(f, 11, ZZ) == \ [[1, 1], [1, 5, 3], [1, 2, 3, 4]] - f = [1,0,1,0,10,10,8,2,8] + f = ZZ.map([1, 0, 1, 0, 10, 10, 8, 2, 8]) - Q = [[1, 0, 0, 0, 0, 0, 0, 0], - [2, 1, 7,11,10,12, 5,11], + Q = ZZ.map([[1, 0, 0, 0, 0, 0, 0, 0], + [2, 1, 7, 11, 10, 12, 5, 11], [3, 6, 4, 3, 0, 4, 7, 2], [4, 3, 6, 5, 1, 6, 2, 3], - [2,11, 8, 8, 3, 1, 3,11], - [6,11, 8, 6, 2, 7,10, 9], - [5,11, 7,10, 0,11, 7,12], - [3, 3,12, 5, 0,11, 9,12]] + [2, 11, 8, 8, 3, 1, 3, 11], + [6, 11, 8, 6, 2, 7, 10, 9], + [5, 11, 7, 10, 0, 11, 7, 12], + [3, 3, 12, 5, 0, 11, 9, 12]]) V = [[1, 0, 0, 0, 0, 0, 0, 0], [0, 5, 5, 0, 9, 5, 1, 0], - [0, 9,11, 9,10,12, 0, 1]] + [0, 9, 11, 9, 10, 12, 0, 1]] assert gf_Qmatrix(f, 13, ZZ) == Q assert gf_Qbasis(Q, 13, ZZ) == V @@ -513,15 +558,16 @@ assert gf_berlekamp(f, 13, ZZ) == \ [[1, 3], [1, 8, 4, 12], [1, 2, 3, 4, 6]] + def test_gf_ddf(): - f = gf_from_dict({15: 1, 0: -1}, 11, ZZ) + f = gf_from_dict({15: ZZ(1), 0: ZZ(-1)}, 11, ZZ) g = [([1, 0, 0, 0, 0, 10], 1), ([1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1], 2)] assert gf_ddf_zassenhaus(f, 11, ZZ) == g assert gf_ddf_shoup(f, 11, ZZ) == g - f = gf_from_dict({63: 1, 0: 1}, 2, ZZ) + f = gf_from_dict({63: ZZ(1), 0: ZZ(1)}, 2, ZZ) g = [([1, 1], 1), ([1, 1, 1], 2), ([1, 1, 1, 1, 1, 1, 1], 3), @@ -532,14 +578,14 @@ assert gf_ddf_zassenhaus(f, 2, ZZ) == g assert gf_ddf_shoup(f, 2, ZZ) == g - f = gf_from_dict({6: 1, 5: -1, 4: 1, 3: 1, 1: -1}, 3, ZZ) + f = gf_from_dict({6: ZZ(1), 5: ZZ(-1), 4: ZZ(1), 3: ZZ(1), 1: ZZ(-1)}, 3, ZZ) g = [([1, 1, 0], 1), ([1, 1, 0, 1, 2], 2)] assert gf_ddf_zassenhaus(f, 3, ZZ) == g assert gf_ddf_shoup(f, 3, ZZ) == g - f = [1, 2, 5, 26, 677, 436, 791, 325, 456, 24, 577] + f = ZZ.map([1, 2, 5, 26, 677, 436, 791, 325, 456, 24, 577]) g = [([1, 701], 1), ([1, 110, 559, 532, 694, 151, 110, 70, 735, 122], 9)] @@ -555,41 +601,43 @@ assert gf_ddf_zassenhaus(f, p, ZZ) == g assert gf_ddf_shoup(f, p, ZZ) == g + def test_gf_edf(): - f = [1, 1, 0, 1, 2] - g = [[1, 0, 1], [1, 1, 2]] + f = ZZ.map([1, 1, 0, 1, 2]) + g = ZZ.map([[1, 0, 1], [1, 1, 2]]) assert gf_edf_zassenhaus(f, 2, 3, ZZ) == g assert gf_edf_shoup(f, 2, 3, ZZ) == g + def test_gf_factor(): assert gf_factor([], 11, ZZ) == (0, []) assert gf_factor([1], 11, ZZ) == (1, []) - assert gf_factor([1,1], 11, ZZ) == (1, [([1, 1], 1)]) + assert gf_factor([1, 1], 11, ZZ) == (1, [([1, 1], 1)]) assert gf_factor_sqf([], 11, ZZ) == (0, []) assert gf_factor_sqf([1], 11, ZZ) == (1, []) - assert gf_factor_sqf([1,1], 11, ZZ) == (1, [[1, 1]]) + assert gf_factor_sqf([1, 1], 11, ZZ) == (1, [[1, 1]]) config.setup('GF_FACTOR_METHOD', 'berlekamp') assert gf_factor_sqf([], 11, ZZ) == (0, []) assert gf_factor_sqf([1], 11, ZZ) == (1, []) - assert gf_factor_sqf([1,1], 11, ZZ) == (1, [[1, 1]]) + assert gf_factor_sqf([1, 1], 11, ZZ) == (1, [[1, 1]]) config.setup('GF_FACTOR_METHOD', 'zassenhaus') assert gf_factor_sqf([], 11, ZZ) == (0, []) assert gf_factor_sqf([1], 11, ZZ) == (1, []) - assert gf_factor_sqf([1,1], 11, ZZ) == (1, [[1, 1]]) + assert gf_factor_sqf([1, 1], 11, ZZ) == (1, [[1, 1]]) config.setup('GF_FACTOR_METHOD', 'shoup') - assert gf_factor_sqf([], 11, ZZ) == (0, []) - assert gf_factor_sqf([1], 11, ZZ) == (1, []) - assert gf_factor_sqf([1,1], 11, ZZ) == (1, [[1, 1]]) + assert gf_factor_sqf(ZZ.map([]), 11, ZZ) == (0, []) + assert gf_factor_sqf(ZZ.map([1]), 11, ZZ) == (1, []) + assert gf_factor_sqf(ZZ.map([1, 1]), 11, ZZ) == (1, [[1, 1]]) - f, p = [1,0,0,1,0], 2 + f, p = ZZ.map([1, 0, 0, 1, 0]), 2 g = (1, [([1, 0], 1), ([1, 1], 1), @@ -617,7 +665,7 @@ config.setup('GF_FACTOR_METHOD', 'shoup') assert gf_factor_sqf(f, p, ZZ) == g - f, p = gf_from_int_poly([1,-3,1,-3,-1,-3,1], 11), 11 + f, p = gf_from_int_poly([1, -3, 1, -3, -1, -3, 1], 11), 11 g = (1, [([1, 1], 1), ([1, 5, 3], 1), @@ -672,7 +720,7 @@ config.setup('GF_FACTOR_METHOD', 'shoup') assert gf_factor(f, p, ZZ) == g - f, p = gf_from_dict({32: 8, 0: 5}, 11, ZZ), 11 + f, p = gf_from_dict({32: ZZ(8), 0: ZZ(5)}, 11, ZZ), 11 g = (8, [([1, 3], 1), ([1, 8], 1), @@ -693,7 +741,7 @@ config.setup('GF_FACTOR_METHOD', 'shoup') assert gf_factor(f, p, ZZ) == g - f, p = gf_from_dict({63: 8, 0: 5}, 11, ZZ), 11 + f, p = gf_from_dict({63: ZZ(8), 0: ZZ(5)}, 11, ZZ), 11 g = (8, [([1, 7], 1), ([1, 4, 5], 1), @@ -723,7 +771,7 @@ p = ZZ(nextprime(int((2**15 * pi).evalf()))) f = gf_from_dict({15: 1, 1: 1, 0: 1}, p, ZZ) - assert gf_sqf_p(f, p, ZZ) == True + assert gf_sqf_p(f, p, ZZ) is True g = (1, [([1, 22730, 68144], 1), ([1, 81553, 77449, 86810, 4724], 1), @@ -751,9 +799,9 @@ # (mod p > 2**(n-2) * pi), where a_n = a_{n-1}**2 + 1, a_0 = 1 p = ZZ(nextprime(int((2**4 * pi).evalf()))) - f = [1, 2, 5, 26, 41, 39, 38] + f = ZZ.map([1, 2, 5, 26, 41, 39, 38]) - assert gf_sqf_p(f, p, ZZ) == True + assert gf_sqf_p(f, p, ZZ) is True g = (1, [([1, 44, 26], 1), ([1, 11, 25, 18, 30], 1)]) @@ -774,9 +822,10 @@ assert gf_factor_sqf(f, p, ZZ) == g config.setup('GF_FACTOR_METHOD', 'other') - raises(KeyError, lambda: gf_factor([1,1], 11, ZZ)) + raises(KeyError, lambda: gf_factor([1, 1], 11, ZZ)) config.setup('GF_FACTOR_METHOD') + def test_gf_csolve(): assert gf_value([1, 7, 2, 4], 11) == 2204 @@ -791,10 +840,11 @@ assert csolve_prime([1, 3, 1, 5], 5) == [0, 1] assert csolve_prime([3, 6, 9, 3], 3) == [0, 1, 2] # with power > 1 - assert csolve_prime([1, 1, 223], 3, 4) == [4, 13, 22, 31, 40, 49, 58, 67, 76] + assert csolve_prime( + [1, 1, 223], 3, 4) == [4, 13, 22, 31, 40, 49, 58, 67, 76] assert csolve_prime([3, 5, 2, 25], 5, 3) == [16, 50, 99] assert csolve_prime([3, 2, 2, 49], 7, 3) == [147, 190, 234] assert gf_csolve([1, 1, 7], 189) == [13, 49, 76, 112, 139, 175] - assert gf_csolve([1, 3, 4, 1, 30], 60) == [10, 30] + assert gf_csolve([1, 3, 4, 1, 30], 60) == [10, 30] assert gf_csolve([1, 1, 7], 15) == [] diff -Nru python3-sympy-0.7.2/sympy/polys/tests/test_groebnertools.py python3-sympy-0.7.3/sympy/polys/tests/test_groebnertools.py --- python3-sympy-0.7.2/sympy/polys/tests/test_groebnertools.py 2012-10-17 03:02:22.000000000 +0000 +++ python3-sympy-0.7.3/sympy/polys/tests/test_groebnertools.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,223 +1,166 @@ """Tests for Groebner bases. """ -from sympy.polys.distributedpolys import ( - sdp_from_dict, -) + from sympy.polys.groebnertools import ( - sdp_groebner, sig, sig_key, sig_cmp, + groebner, sig, sig_key, sig_cmp, lbp, lbp_cmp, lbp_key, critical_pair, cp_cmp, cp_key, is_rewritable_or_comparable, Sign, Polyn, Num, s_poly, f5_reduce, - _basis, _representing_matrices, - matrix_fglm, -) - -from sympy.polys.monomialtools import ( - lex, grlex, grevlex, + groebner_lcm, groebner_gcd, ) -from sympy.polys.polyerrors import ( - ExactQuotientFailed, DomainError, -) +from sympy.polys.fglmtools import _representing_matrices +from sympy.polys.monomialtools import lex, grlex, grevlex +from sympy.polys.polyerrors import ExactQuotientFailed, DomainError +from sympy.polys.rings import ring, xring from sympy.polys.domains import ZZ, QQ -from sympy import S, Symbol, symbols, groebner -from sympy.utilities.pytest import raises, skip, XFAIL +from sympy.utilities.pytest import raises, slow from sympy.polys import polyconfig as config -def helper_test_sdp_groebner(): - f = sdp_from_dict({(1,2): QQ(2,), (2,0): QQ(1)}, lex) - g = sdp_from_dict({(0,3): QQ(2), (1,1): QQ(1), (0,0): QQ(-1)}, lex) +def _do_test_groebner(): + R, x,y = ring("x,y", QQ, lex) + f = x**2 + 2*x*y**2 + g = x*y + 2*y**3 - 1 - a = sdp_from_dict({(1,0): QQ(1,1)}, lex) - b = sdp_from_dict({(0,3): QQ(1,1), (0,0): QQ(-1,2)}, lex) + assert groebner([f, g], R) == [x, y**3 - QQ(1,2)] - assert sdp_groebner((f, g), 1, lex, QQ) == [a, b] + R, y,x = ring("y,x", QQ, lex) + f = 2*x**2*y + y**2 + g = 2*x**3 + x*y - 1 - f = sdp_from_dict({(2,1): QQ(2,), (0,2): QQ(1)}, lex) - g = sdp_from_dict({(3,0): QQ(2), (1,1): QQ(1), (0,0): QQ(-1)}, lex) + assert groebner([f, g], R) == [y, x**3 - QQ(1,2)] - a = sdp_from_dict({(0,1): QQ(1,1)}, lex) - b = sdp_from_dict({(3,0): QQ(1,1), (0,0): QQ(-1,2)}, lex) + R, x,y,z = ring("x,y,z", QQ, lex) + f = x - z**2 + g = y - z**3 - assert sdp_groebner((f, g), 1, lex, QQ) == [b, a] + assert groebner([f, g], R) == [f, g] - f = sdp_from_dict({(0,0,2): QQ(-1), (1,0,0): QQ(1)}, lex) - g = sdp_from_dict({(0,0,3): QQ(-1), (0,1,0): QQ(1)}, lex) + R, x,y = ring("x,y", QQ, grlex) + f = x**3 - 2*x*y + g = x**2*y + x - 2*y**2 - assert sdp_groebner((f, g), 1, lex, QQ) == [f, g] + assert groebner([f, g], R) == [x**2, x*y, -QQ(1,2)*x + y**2] - f = sdp_from_dict({(3,0): QQ(1), (1,1): QQ(-2)}, grlex) - g = sdp_from_dict({(2,1): QQ(1), (0,2): QQ(-2), (1,0): QQ(1)}, grlex) + R, x,y,z = ring("x,y,z", QQ, lex) + f = -x**2 + y + g = -x**3 + z - a = sdp_from_dict({(2,0): QQ(1)}, grlex) - b = sdp_from_dict({(1,1): QQ(1)}, grlex) - c = sdp_from_dict({(0,2): QQ(1), (1, 0): QQ(-1,2)}, grlex) + assert groebner([f, g], R) == [x**2 - y, x*y - z, x*z - y**2, y**3 - z**2] - assert sdp_groebner((f, g), 1, grlex, QQ) == [a, b, c] + R, x,y,z = ring("x,y,z", QQ, grlex) + f = -x**2 + y + g = -x**3 + z - f = sdp_from_dict({(2,0,0): -QQ(1), (0,1,0): QQ(1)}, lex) - g = sdp_from_dict({(3,0,0): -QQ(1), (0,0,1): QQ(1)}, lex) + assert groebner([f, g], R) == [y**3 - z**2, x**2 - y, x*y - z, x*z - y**2] - assert sdp_groebner((f, g), 2, lex, QQ) == [ - sdp_from_dict({(2,0,0): QQ(1), (0,1,0): -QQ(1)}, lex), - sdp_from_dict({(1,1,0): QQ(1), (0,0,1): -QQ(1)}, lex), - sdp_from_dict({(1,0,1): QQ(1), (0,2,0): -QQ(1)}, lex), - sdp_from_dict({(0,3,0): QQ(1), (0,0,2): -QQ(1)}, lex), - ] + R, x,y,z = ring("x,y,z", QQ, lex) + f = -x**2 + z + g = -x**3 + y - f = sdp_from_dict({(2,0,0): -QQ(1), (0,1,0): QQ(1)}, grlex) - g = sdp_from_dict({(3,0,0): -QQ(1), (0,0,1): QQ(1)}, grlex) + assert groebner([f, g], R) == [x**2 - z, x*y - z**2, x*z - y, y**2 - z**3] - assert sdp_groebner((f, g), 2, grlex, QQ) == [ - sdp_from_dict({(0,3,0): QQ(1), (0,0,2): -QQ(1)}, grlex), - sdp_from_dict({(2,0,0): QQ(1), (0,1,0): -QQ(1)}, grlex), - sdp_from_dict({(1,1,0): QQ(1), (0,0,1): -QQ(1)}, grlex), - sdp_from_dict({(1,0,1): QQ(1), (0,2,0): -QQ(1)}, grlex), - ] + R, x,y,z = ring("x,y,z", QQ, grlex) + f = -x**2 + z + g = -x**3 + y - f = sdp_from_dict({(2,0,0): -QQ(1), (0,0,1): QQ(1)}, lex) - g = sdp_from_dict({(3,0,0): -QQ(1), (0,1,0): QQ(1)}, lex) + assert groebner([f, g], R) == [-y**2 + z**3, x**2 - z, x*y - z**2, x*z - y] - assert sdp_groebner((f, g), 2, lex, QQ) == [ - sdp_from_dict({(2,0,0): QQ(1), (0,0,1): -QQ(1)}, lex), - sdp_from_dict({(1,1,0): QQ(1), (0,0,2): -QQ(1)}, lex), - sdp_from_dict({(1,0,1): QQ(1), (0,1,0): -QQ(1)}, lex), - sdp_from_dict({(0,2,0): QQ(1), (0,0,3): -QQ(1)}, lex), - ] + R, x,y,z = ring("x,y,z", QQ, lex) + f = x - y**2 + g = -y**3 + z - f = sdp_from_dict({(2,0,0): -QQ(1), (0,0,1): QQ(1)}, grlex) - g = sdp_from_dict({(3,0,0): -QQ(1), (0,1,0): QQ(1)}, grlex) + assert groebner([f, g], R) == [x - y**2, y**3 - z] - assert sdp_groebner((f, g), 2, grlex, QQ) == [ - sdp_from_dict({(0,0,3): QQ(1), (0,2,0): -QQ(1)}, grlex), - sdp_from_dict({(2,0,0): QQ(1), (0,0,1): -QQ(1)}, grlex), - sdp_from_dict({(1,1,0): QQ(1), (0,0,2): -QQ(1)}, grlex), - sdp_from_dict({(1,0,1): QQ(1), (0,1,0): -QQ(1)}, grlex), - ] + R, x,y,z = ring("x,y,z", QQ, grlex) + f = x - y**2 + g = -y**3 + z - f = sdp_from_dict({(0,2,0): -QQ(1), (1,0,0): QQ(1)}, lex) - g = sdp_from_dict({(0,3,0): -QQ(1), (0,0,1): QQ(1)}, lex) + assert groebner([f, g], R) == [x**2 - y*z, x*y - z, -x + y**2] - assert sdp_groebner((f, g), 2, lex, QQ) == [ - sdp_from_dict({(1,0,0): QQ(1), (0,2,0): -QQ(1)}, lex), - sdp_from_dict({(0,3,0): QQ(1), (0,0,1): -QQ(1)}, lex), - ] + R, x,y,z = ring("x,y,z", QQ, lex) + f = x - z**2 + g = y - z**3 - f = sdp_from_dict({(0,2,0): -QQ(1), (1,0,0): QQ(1)}, grlex) - g = sdp_from_dict({(0,3,0): -QQ(1), (0,0,1): QQ(1)}, grlex) + assert groebner([f, g], R) == [x - z**2, y - z**3] - assert sdp_groebner((f, g), 2, grlex, QQ) == [ - sdp_from_dict({(2,0,0): QQ(1), (0,1,1): -QQ(1)}, grlex), - sdp_from_dict({(1,1,0): QQ(1), (0,0,1): -QQ(1)}, grlex), - sdp_from_dict({(0,2,0): QQ(1), (1,0,0): -QQ(1)}, grlex), - ] + R, x,y,z = ring("x,y,z", QQ, grlex) + f = x - z**2 + g = y - z**3 - f = sdp_from_dict({(0,0,2): -QQ(1), (1,0,0): QQ(1)}, lex) - g = sdp_from_dict({(0,0,3): -QQ(1), (0,1,0): QQ(1)}, lex) + assert groebner([f, g], R) == [x**2 - y*z, x*z - y, -x + z**2] - assert sdp_groebner((f, g), 2, lex, QQ) == [ - sdp_from_dict({(1,0,0): QQ(1), (0,0,2): -QQ(1)}, lex), - sdp_from_dict({(0,1,0): QQ(1), (0,0,3): -QQ(1)}, lex), - ] + R, x,y,z = ring("x,y,z", QQ, lex) + f = -y**2 + z + g = x - y**3 - f = sdp_from_dict({(0,0,2): -QQ(1), (1,0,0): QQ(1)}, grlex) - g = sdp_from_dict({(0,0,3): -QQ(1), (0,1,0): QQ(1)}, grlex) + assert groebner([f, g], R) == [x - y*z, y**2 - z] - assert sdp_groebner((f, g), 2, grlex, QQ) == [ - sdp_from_dict({(2,0,0): QQ(1), (0,1,1): -QQ(1)}, grlex), - sdp_from_dict({(1,0,1): QQ(1), (0,1,0): -QQ(1)}, grlex), - sdp_from_dict({(0,0,2): QQ(1), (1,0,0): -QQ(1)}, grlex), - ] + R, x,y,z = ring("x,y,z", QQ, grlex) + f = -y**2 + z + g = x - y**3 - f = sdp_from_dict({(0,2,0): -QQ(1), (0,0,1): QQ(1)}, lex) - g = sdp_from_dict({(0,3,0): -QQ(1), (1,0,0): QQ(1)}, lex) + assert groebner([f, g], R) == [-x**2 + z**3, x*y - z**2, y**2 - z, -x + y*z] - assert sdp_groebner((f, g), 2, lex, QQ) == [ - sdp_from_dict({(1,0,0): QQ(1), (0,1,1): -QQ(1)}, lex), - sdp_from_dict({(0,2,0): QQ(1), (0,0,1): -QQ(1)}, lex), - ] + R, x,y,z = ring("x,y,z", QQ, lex) + f = y - z**2 + g = x - z**3 - f = sdp_from_dict({(0,2,0): -QQ(1), (0,0,1): QQ(1)}, grlex) - g = sdp_from_dict({(0,3,0): -QQ(1), (1,0,0): QQ(1)}, grlex) + assert groebner([f, g], R) == [x - z**3, y - z**2] - assert sdp_groebner((f, g), 2, grlex, QQ) == [ - sdp_from_dict({(0,0,3): QQ(1), (2,0,0): -QQ(1)}, grlex), - sdp_from_dict({(1,1,0): QQ(1), (0,0,2): -QQ(1)}, grlex), - sdp_from_dict({(0,2,0): QQ(1), (0,0,1): -QQ(1)}, grlex), - sdp_from_dict({(0,1,1): QQ(1), (1,0,0): -QQ(1)}, grlex), - ] + R, x,y,z = ring("x,y,z", QQ, grlex) + f = y - z**2 + g = x - z**3 - f = sdp_from_dict({(0,0,2): -QQ(1), (0,1,0): QQ(1)}, lex) - g = sdp_from_dict({(0,0,3): -QQ(1), (1,0,0): QQ(1)}, lex) + assert groebner([f, g], R) == [-x**2 + y**3, x*z - y**2, -x + y*z, -y + z**2] - assert sdp_groebner((f, g), 2, lex, QQ) == [ - sdp_from_dict({(1,0,0): QQ(1), (0,0,3): -QQ(1)}, lex), - sdp_from_dict({(0,1,0): QQ(1), (0,0,2): -QQ(1)}, lex), - ] - - f = sdp_from_dict({(0,0,2): -QQ(1), (0,1,0): QQ(1)}, grlex) - g = sdp_from_dict({(0,0,3): -QQ(1), (1,0,0): QQ(1)}, grlex) + R, x,y,z = ring("x,y,z", QQ, lex) + f = 4*x**2*y**2 + 4*x*y + 1 + g = x**2 + y**2 - 1 - assert sdp_groebner((f, g), 2, grlex, QQ) == [ - sdp_from_dict({(0,3,0): QQ(1), (2,0,0): -QQ(1)}, grlex), - sdp_from_dict({(1,0,1): QQ(1), (0,2,0): -QQ(1)}, grlex), - sdp_from_dict({(0,1,1): QQ(1), (1,0,0): -QQ(1)}, grlex), - sdp_from_dict({(0,0,2): QQ(1), (0,1,0): -QQ(1)}, grlex), + assert groebner([f, g], R) == [ + x - 4*y**7 + 8*y**5 - 7*y**3 + 3*y, + y**8 - 2*y**6 + QQ(3,2)*y**4 - QQ(1,2)*y**2 + QQ(1,16), ] - f = sdp_from_dict({(2,2): QQ(4), (1,1): QQ(4), (0,0): QQ(1)}, lex) - g = sdp_from_dict({(2,0): QQ(1), (0,2): QQ(1), (0,0):-QQ(1)}, lex) +def test_groebner_buchberger(): + with config.using(groebner='buchberger'): + _do_test_groebner() - assert sdp_groebner((f, g), 1, lex, QQ) == [ - sdp_from_dict({(1,0): QQ(1,1), (0,7): QQ(-4,1), (0,5): QQ(8,1), (0,3): QQ(-7,1), (0,1): QQ(3,1)}, lex), - sdp_from_dict({(0,8): QQ(1,1), (0,6): QQ(-2,1), (0,4): QQ(3,2), (0,2): QQ(-1,2), (0,0): QQ(1,16)}, lex), - ] +def test_groebner_f5b(): + with config.using(groebner='f5b'): + _do_test_groebner() - raises(DomainError, lambda: sdp_groebner([], 1, lex, ZZ)) +def _do_test_benchmark_minpoly(): + R, x,y,z = ring("x,y,z", QQ, lex) -def test_sdp_groebner(): - config.setup('GB_METHOD', 'f5b') - helper_test_sdp_groebner() - config.setup('GB_METHOD', 'buchberger') - helper_test_sdp_groebner() - -def helper_test_benchmark_minpoly(): - x, y, z = symbols('x,y,z') - - I = [x**3 + x + 1, y**2 + y + 1, (x + y) * z - (x**2 + y)] - - assert groebner(I, x, y, z, order='lex') == [ - -975 + 2067*x + 6878*z - 11061*z**2 + 6062*z**3 - 1065*z**4 + 155*z**5, - -308 + 159*y + 1043*z - 1161*z**2 + 523*z**3 - 91*z**4 + 12*z**5, - 13 - 46*z + 89*z**2 - 82*z**3 + 41*z**4 - 7*z**5 + z**6, - ] + F = [x**3 + x + 1, y**2 + y + 1, (x + y) * z - (x**2 + y)] + G = [x + QQ(155,2067)*z**5 - QQ(355,689)*z**4 + QQ(6062,2067)*z**3 - QQ(3687,689)*z**2 + QQ(6878,2067)*z - QQ(25,53), + y + QQ(4,53)*z**5 - QQ(91,159)*z**4 + QQ(523,159)*z**3 - QQ(387,53)*z**2 + QQ(1043,159)*z - QQ(308,159), + z**6 - 7*z**5 + 41*z**4 - 82*z**3 + 89*z**2 - 46*z + 13] - assert groebner(I, x, y, z, order='lex', field=True) == [ - -S(25)/53 + x + 6878*z/2067 - 3687*z**2/689 + 6062*z**3/2067 - 355*z**4/689 + 155*z**5/2067, - -S(308)/159 + y + 1043*z/159 - 387*z**2/53 + 523*z**3/159 - 91*z**4/159 + 4*z**5/53, - 13 - 46*z + 89*z**2 - 82*z**3 + 41*z**4 - 7*z**5 + z**6, - ] + assert groebner(F, R) == G -def test_benchmark_minpoly(): - config.setup('GB_METHOD', 'f5b') - helper_test_benchmark_minpoly() - config.setup('GB_METHOD', 'buchberger') - helper_test_benchmark_minpoly() +def test_benchmark_minpoly_buchberger(): + with config.using(groebner='buchberger'): + _do_test_benchmark_minpoly() -@XFAIL -def test_benchmark_coloring(): - skip('takes too much time') +def test_benchmark_minpoly_f5b(): + with config.using(groebner='f5b'): + _do_test_benchmark_minpoly() - V = list(range(1, 12+1)) - E = [(1,2),(2,3),(1,4),(1,6),(1,12),(2,5),(2,7),(3,8),(3,10), - (4,11),(4,9),(5,6),(6,7),(7,8),(8,9),(9,10),(10,11), - (11,12),(5,12),(5,9),(6,10),(7,11),(8,12),(3,4)] +@slow +def test_benchmark_coloring(): + V = list(range(1, 12 + 1)) + E = [(1, 2), (2, 3), (1, 4), (1, 6), (1, 12), (2, 5), (2, 7), (3, 8), (3, 10), + (4, 11), (4, 9), (5, 6), (6, 7), (7, 8), (8, 9), (9, 10), (10, 11), + (11, 12), (5, 12), (5, 9), (6, 10), (7, 11), (8, 12), (3, 4)] - V = [Symbol('x' + str(i)) for i in V] - E = [(V[i-1], V[j-1]) for i, j in E] + R, V = xring([ "x%d" % v for v in V ], QQ, lex) + E = [(V[i - 1], V[j - 1]) for i, j in E] x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12 = V @@ -226,7 +169,7 @@ I = I3 + Ig - assert groebner(I[:-1], V, order='lex') == [ + assert groebner(I[:-1], R) == [ x1 + x11 + x12, x2 - x11, x3 - x12, @@ -241,50 +184,58 @@ x12**3 - 1, ] - assert groebner(I, V, order='lex') == [1] + assert groebner(I, R) == [1] -def helper_test_benchmark_katsura_3(): - x0, x1, x2 = symbols('x:3') +def _do_test_benchmark_katsura_3(): + R, x0,x1,x2 = ring("x:3", ZZ, lex) I = [x0 + 2*x1 + 2*x2 - 1, x0**2 + 2*x1**2 + 2*x2**2 - x0, 2*x0*x1 + 2*x1*x2 - x1] - assert groebner(I, x0, x1, x2, order='lex') == [ + assert groebner(I, R) == [ -7 + 7*x0 + 8*x2 + 158*x2**2 - 420*x2**3, 7*x1 + 3*x2 - 79*x2**2 + 210*x2**3, x2 + x2**2 - 40*x2**3 + 84*x2**4, ] - assert groebner(I, x0, x1, x2, order='grlex') == [ + R, x0,x1,x2 = ring("x:3", ZZ, grlex) + I = [ i.set_ring(R) for i in I ] + + assert groebner(I, R) == [ 7*x1 + 3*x2 - 79*x2**2 + 210*x2**3, -x1 + x2 - 3*x2**2 + 5*x1**2, -x1 - 4*x2 + 10*x1*x2 + 12*x2**2, -1 + x0 + 2*x1 + 2*x2, ] -def test_benchmark_katsura3(): - config.setup('GB_METHOD', 'f5b') - helper_test_benchmark_katsura_3() - config.setup('GB_METHOD', 'buchberger') - helper_test_benchmark_katsura_3() - -def helper_test_benchmark_katsura_4(): - x0, x1, x2, x3 = symbols('x:4') +def test_benchmark_katsura3_buchberger(): + with config.using(groebner='buchberger'): + _do_test_benchmark_katsura_3() + +def test_benchmark_katsura3_f5b(): + with config.using(groebner='f5b'): + _do_test_benchmark_katsura_3() +def _do_test_benchmark_katsura_4(): + R, x0,x1,x2,x3 = ring("x:4", ZZ, lex) I = [x0 + 2*x1 + 2*x2 + 2*x3 - 1, x0**2 + 2*x1**2 + 2*x2**2 + 2*x3**2 - x0, 2*x0*x1 + 2*x1*x2 + 2*x2*x3 - x1, x1**2 + 2*x0*x2 + 2*x1*x3 - x2] - assert groebner(I, x0, x1, x2, x3, order='lex') == [ + assert groebner(I, R) == [ 5913075*x0 - 159690237696*x3**7 + 31246269696*x3**6 + 27439610544*x3**5 - 6475723368*x3**4 - 838935856*x3**3 + 275119624*x3**2 + 4884038*x3 - 5913075, 1971025*x1 - 97197721632*x3**7 + 73975630752*x3**6 - 12121915032*x3**5 - 2760941496*x3**4 + 814792828*x3**3 - 1678512*x3**2 - 9158924*x3, 5913075*x2 + 371438283744*x3**7 - 237550027104*x3**6 + 22645939824*x3**5 + 11520686172*x3**4 - 2024910556*x3**3 - 132524276*x3**2 + 30947828*x3, - 128304*x3**8 - 93312*x3**7 + 15552*x3**6 + 3144*x3**5 - 1120*x3**4 + 36*x3**3 + 15*x3**2 - x3, + 128304*x3**8 - 93312*x3**7 + 15552*x3**6 + 3144*x3**5 - + 1120*x3**4 + 36*x3**3 + 15*x3**2 - x3, ] - assert groebner(I, x0, x1, x2, x3, order='grlex') == [ + R, x0,x1,x2,x3 = ring("x:4", ZZ, grlex) + I = [ i.set_ring(R) for i in I ] + + assert groebner(I, R) == [ 393*x1 - 4662*x2**2 + 4462*x2*x3 - 59*x2 + 224532*x3**4 - 91224*x3**3 - 678*x3**2 + 2046*x3, -x1 + 196*x2**3 - 21*x2**2 + 60*x2*x3 - 18*x2 - 168*x3**3 + 83*x3**2 - 9*x3, -6*x1 + 1134*x2**2*x3 - 189*x2**2 - 466*x2*x3 + 32*x2 - 630*x3**3 + 57*x3**2 + 51*x3, @@ -295,51 +246,111 @@ x0 + 2*x1 + 2*x2 + 2*x3 - 1, ] -def test_benchmark_kastura_4(): - config.setup('GB_METHOD', 'f5b') - helper_test_benchmark_katsura_4() - config.setup('GB_METHOD', 'buchberger') - helper_test_benchmark_katsura_4() - -def helper_test_benchmark_czichowski(): - x, t = symbols('x t') - - I = [9*x**8 + 36*x**7 - 32*x**6 - 252*x**5 - 78*x**4 + 468*x**3 + 288*x**2 - 108*x + 9, (-72 - 72*t)*x**7 + (-256 - 252*t)*x**6 + (192 + 192*t)*x**5 + (1280 + 1260*t)*x**4 + (312 + 312*t)*x**3 + (-404*t)*x**2 + (-576 - 576*t)*x + 96 + 108*t] - - assert groebner(I, x, t, order='lex') == [ - -160420835591776763325581422211936558925462474417709511019228211783493866564923546661604487873*t**7 - 1406108495478033395547109582678806497509499966197028487131115097902188374051595011248311352864*t**6 - 5241326875850889518164640374668786338033653548841427557880599579174438246266263602956254030352*t**5 - 10758917262823299139373269714910672770004760114329943852726887632013485035262879510837043892416*t**4 - 13119383576444715672578819534846747735372132018341964647712009275306635391456880068261130581248*t**3 - 9491412317016197146080450036267011389660653495578680036574753839055748080962214787557853941760*t**2 - 3767520915562795326943800040277726397326609797172964377014046018280260848046603967211258368000*t + 3725588592068034903797967297424801242396746870413359539263038139343329273586196480000*x - 632314652371226552085897259159210286886724229880266931574701654721512325555116066073245696000, - 610733380717522355121*t**8 + 6243748742141230639968*t**7 + 27761407182086143225024*t**6 + 70066148869420956398592*t**5 + 109701225644313784229376*t**4 + 109009005495588442152960*t**3 + 67072101084384786432000*t**2 + 23339979742629593088000*t + 3513592776846090240000 - ] - - assert groebner(I, x, t, order='grlex') == [ - 16996618586000601590732959134095643086442*t**3*x - 32936701459297092865176560282688198064839*t**3 + 78592411049800639484139414821529525782364*t**2*x - 120753953358671750165454009478961405619916*t**2 + 120988399875140799712152158915653654637280*t*x - 144576390266626470824138354942076045758736*t + 60017634054270480831259316163620768960*x**2 + 61976058033571109604821862786675242894400*x - 56266268491293858791834120380427754600960, - 576689018321912327136790519059646508441672750656050290242749*t**4 + 2326673103677477425562248201573604572527893938459296513327336*t**3 + 110743790416688497407826310048520299245819959064297990236000*t**2*x + 3308669114229100853338245486174247752683277925010505284338016*t**2 + 323150205645687941261103426627818874426097912639158572428800*t*x + 1914335199925152083917206349978534224695445819017286960055680*t + 861662882561803377986838989464278045397192862768588480000*x**2 + 235296483281783440197069672204341465480107019878814196672000*x + 361850798943225141738895123621685122544503614946436727532800, - -117584925286448670474763406733005510014188341867*t**3 + 68566565876066068463853874568722190223721653044*t**2*x - 435970731348366266878180788833437896139920683940*t**2 + 196297602447033751918195568051376792491869233408*t*x - 525011527660010557871349062870980202067479780112*t + 517905853447200553360289634770487684447317120*x**3 + 569119014870778921949288951688799397569321920*x**2 + 138877356748142786670127389526667463202210102080*x - 205109210539096046121625447192779783475018619520, - -3725142681462373002731339445216700112264527*t**3 + 583711207282060457652784180668273817487940*t**2*x - 12381382393074485225164741437227437062814908*t**2 + 151081054097783125250959636747516827435040*t*x**2 + 1814103857455163948531448580501928933873280*t*x - 13353115629395094645843682074271212731433648*t + 236415091385250007660606958022544983766080*x**2 + 1390443278862804663728298060085399578417600*x - 4716885828494075789338754454248931750698880 - ] - -@XFAIL -def test_benchmark_czichowski(): - skip('This takes too much time (without gmpy)') +def test_benchmark_kastura_4_buchberger(): + with config.using(groebner='buchberger'): + _do_test_benchmark_katsura_4() + +def test_benchmark_kastura_4_f5b(): + with config.using(groebner='f5b'): + _do_test_benchmark_katsura_4() + +def _do_test_benchmark_czichowski(): + R, x,t = ring("x,t", ZZ, lex) + I = [9*x**8 + 36*x**7 - 32*x**6 - 252*x**5 - 78*x**4 + 468*x**3 + 288*x**2 - 108*x + 9, + (-72 - 72*t)*x**7 + (-256 - 252*t)*x**6 + (192 + 192*t)*x**5 + (1280 + 1260*t)*x**4 + (312 + 312*t)*x**3 + (-404*t)*x**2 + (-576 - 576*t)*x + 96 + 108*t] + + assert groebner(I, R) == [ + 3725588592068034903797967297424801242396746870413359539263038139343329273586196480000*x - + 160420835591776763325581422211936558925462474417709511019228211783493866564923546661604487873*t**7 - + 1406108495478033395547109582678806497509499966197028487131115097902188374051595011248311352864*t**6 - + 5241326875850889518164640374668786338033653548841427557880599579174438246266263602956254030352*t**5 - + 10758917262823299139373269714910672770004760114329943852726887632013485035262879510837043892416*t**4 - + 13119383576444715672578819534846747735372132018341964647712009275306635391456880068261130581248*t**3 - + 9491412317016197146080450036267011389660653495578680036574753839055748080962214787557853941760*t**2 - + 3767520915562795326943800040277726397326609797172964377014046018280260848046603967211258368000*t - + 632314652371226552085897259159210286886724229880266931574701654721512325555116066073245696000, + 610733380717522355121*t**8 + + 6243748742141230639968*t**7 + + 27761407182086143225024*t**6 + + 70066148869420956398592*t**5 + + 109701225644313784229376*t**4 + + 109009005495588442152960*t**3 + + 67072101084384786432000*t**2 + + 23339979742629593088000*t + + 3513592776846090240000, + ] + + R, x,t = ring("x,t", ZZ, grlex) + I = [ i.set_ring(R) for i in I ] + + assert groebner(I, R) == [ + 16996618586000601590732959134095643086442*t**3*x - + 32936701459297092865176560282688198064839*t**3 + + 78592411049800639484139414821529525782364*t**2*x - + 120753953358671750165454009478961405619916*t**2 + + 120988399875140799712152158915653654637280*t*x - + 144576390266626470824138354942076045758736*t + + 60017634054270480831259316163620768960*x**2 + + 61976058033571109604821862786675242894400*x - + 56266268491293858791834120380427754600960, + 576689018321912327136790519059646508441672750656050290242749*t**4 + + 2326673103677477425562248201573604572527893938459296513327336*t**3 + + 110743790416688497407826310048520299245819959064297990236000*t**2*x + + 3308669114229100853338245486174247752683277925010505284338016*t**2 + + 323150205645687941261103426627818874426097912639158572428800*t*x + + 1914335199925152083917206349978534224695445819017286960055680*t + + 861662882561803377986838989464278045397192862768588480000*x**2 + + 235296483281783440197069672204341465480107019878814196672000*x + + 361850798943225141738895123621685122544503614946436727532800, + -117584925286448670474763406733005510014188341867*t**3 + + 68566565876066068463853874568722190223721653044*t**2*x - + 435970731348366266878180788833437896139920683940*t**2 + + 196297602447033751918195568051376792491869233408*t*x - + 525011527660010557871349062870980202067479780112*t + + 517905853447200553360289634770487684447317120*x**3 + + 569119014870778921949288951688799397569321920*x**2 + + 138877356748142786670127389526667463202210102080*x - + 205109210539096046121625447192779783475018619520, + -3725142681462373002731339445216700112264527*t**3 + + 583711207282060457652784180668273817487940*t**2*x - + 12381382393074485225164741437227437062814908*t**2 + + 151081054097783125250959636747516827435040*t*x**2 + + 1814103857455163948531448580501928933873280*t*x - + 13353115629395094645843682074271212731433648*t + + 236415091385250007660606958022544983766080*x**2 + + 1390443278862804663728298060085399578417600*x - + 4716885828494075789338754454248931750698880, + ] + +@slow +def test_benchmark_czichowski_buchberger(): + with config.using(groebner='buchberger'): + _do_test_benchmark_czichowski() + +@slow +def test_benchmark_czichowski_f5b(): + with config.using(groebner='f5b'): + _do_test_benchmark_czichowski() + +def _do_test_benchmark_cyclic_4(): + R, a,b,c,d = ring("a,b,c,d", ZZ, lex) + + I = [a + b + c + d, + a*b + a*d + b*c + b*d, + a*b*c + a*b*d + a*c*d + b*c*d, + a*b*c*d - 1] - config.setup('GB_METHOD', 'f5b') - helper_test_benchmark_czichowski() - config.setup('GB_METHOD', 'buchberger') - helper_test_benchmark_czichowski() - -def helper_test_benchmark_cyclic_4(): - a, b, c, d = symbols('a b c d') - - I = [a + b + c + d, a*b + a*d + b*c + b*d, a*b*c + a*b*d + a*c*d + b*c*d, a*b*c*d - 1] - - assert groebner(I, a, b, c, d, order='lex') == [ + assert groebner(I, R) == [ 4*a + 3*d**9 - 4*d**5 - 3*d, 4*b + 4*c - 3*d**9 + 4*d**5 + 7*d, 4*c**2 + 3*d**10 - 4*d**6 - 3*d**2, 4*c*d**4 + 4*c - d**9 + 4*d**5 + 5*d, d**12 - d**8 - d**4 + 1 ] - assert groebner(I, a, b, c, d, order='grlex') == [ + R, a,b,c,d = ring("a,b,c,d", ZZ, grlex) + I = [ i.set_ring(R) for i in I ] + + assert groebner(I, R) == [ 3*b*c - c**2 + d**6 - 3*d**2, -b + 3*c**2*d**3 - c - d**5 - 4*d, -b + 3*c*d**4 + 2*c + 2*d**5 + 2*d, @@ -350,11 +361,13 @@ a + b + c + d ] -def test_benchmark_cyclic_4(): - config.setup('GB_METHOD', 'f5b') - helper_test_benchmark_cyclic_4() - config.setup('GB_METHOD', 'buchberger') - helper_test_benchmark_cyclic_4() +def test_benchmark_cyclic_4_buchberger(): + with config.using(groebner='buchberger'): + _do_test_benchmark_cyclic_4() + +def test_benchmark_cyclic_4_f5b(): + with config.using(groebner='f5b'): + _do_test_benchmark_cyclic_4() def test_sig_key(): s1 = sig((0,) * 3, 2) @@ -364,82 +377,144 @@ assert sig_key(s1, lex) > sig_key(s2, lex) assert sig_key(s2, lex) < sig_key(s3, lex) + def test_lbp_key(): - p1 = lbp(sig((0,) * 4, 3), [], 12) - p2 = lbp(sig((0,) * 4, 4), [], 13) - p3 = lbp(sig((0,) * 4, 4), [], 12) + R, x,y,z,t = ring("x,y,z,t", ZZ, lex) + + p1 = lbp(sig((0,) * 4, 3), R.zero, 12) + p2 = lbp(sig((0,) * 4, 4), R.zero, 13) + p3 = lbp(sig((0,) * 4, 4), R.zero, 12) + + assert lbp_key(p1) > lbp_key(p2) + assert lbp_key(p2) < lbp_key(p3) - assert lbp_key(p1, lex) > lbp_key(p2, lex) - assert lbp_key(p2, lex) < lbp_key(p3, lex) def test_critical_pair(): # from cyclic4 with grlex - p1 = (((0, 0, 0, 0), 4), [((0, 1, 1, 2), QQ(1,1)), ((0, 0, 2, 2), QQ(1,1)), ((0, 0, 0, 4), QQ(-1,1)), ((0, 0, 0, 0), QQ(-1,1))], 4) - q1 = (((0, 0, 0, 0), 2), [((0, 2, 0, 0), QQ(-1,1)), ((0, 1, 0, 1), QQ(-1,1)), ((0, 0, 1, 1), QQ(-1,1)), ((0, 0, 0, 2), QQ(-1,1))], 2) + R, x,y,z,t = ring("x,y,z,t", QQ, grlex) + + p1 = (((0, 0, 0, 0), 4), y*z*t**2 + z**2*t**2 - t**4 - 1, 4) + q1 = (((0, 0, 0, 0), 2), -y**2 - y*t - z*t - t**2, 2) - p2 = (((0, 0, 0, 2), 3), [((0, 0, 3, 2), QQ(1,1)), ((0, 0, 2, 3), QQ(1,1)), ((0, 0, 1, 0), QQ(-1,1)), ((0, 0, 0, 1), QQ(-1,1))], 5) - q2 = (((0, 0, 2, 2), 2), [((0, 0, 1, 5), QQ(1,1)), ((0, 0, 0, 6), QQ(1,1)), ((0, 1, 1, 0), QQ(1,1)), ((0, 0, 1, 1), QQ(1,1))], 13) + p2 = (((0, 0, 0, 2), 3), z**3*t**2 + z**2*t**3 - z - t, 5) + q2 = (((0, 0, 2, 2), 2), y*z + z*t**5 + z*t + t**6, 13) - assert critical_pair(p1, q1, 3, grlex, QQ) == (((0, 0, 1, 2), 2), ((0, 0, 1, 2), QQ(-1,1)), (((0, 0, 0, 0), 2), [((0, 2, 0, 0), QQ(-1,1)), ((0, 1, 0, 1), QQ(-1,1)), ((0, 0, 1, 1), QQ(-1,1)), ((0, 0, 0, 2), QQ(-1,1))], 2), ((0, 1, 0, 0), 4), ((0, 1, 0, 0), QQ(1,1)), (((0, 0, 0, 0), 4), [((0, 1, 1, 2), QQ(1,1)), ((0, 0, 2, 2), QQ(1,1)), ((0, 0, 0, 4), QQ(-1,1)), ((0, 0, 0, 0), QQ(-1,1))], 4)) - assert critical_pair(p2, q2, 3, grlex, QQ) == (((0, 0, 4, 2), 2), ((0, 0, 2, 0), QQ(1,1)), (((0, 0, 2, 2), 2), [((0, 0, 1, 5), QQ(1,1)), ((0, 0, 0, 6), QQ(1,1)), ((0, 1, 1, 0), QQ(1,1)), ((0, 0, 1, 1), QQ(1,1))], 13), ((0, 0, 0, 5), 3), ((0, 0, 0, 3), QQ(1,1)), (((0, 0, 0, 2), 3), [((0, 0, 3, 2), QQ(1,1)), ((0, 0, 2, 3), QQ(1,1)), ((0, 0, 1, 0), QQ(-1,1)), ((0, 0, 0, 1), QQ(-1,1))], 5)) + assert critical_pair(p1, q1, R) == ( + ((0, 0, 1, 2), 2), ((0, 0, 1, 2), QQ(-1, 1)), (((0, 0, 0, 0), 2), -y**2 - y*t - z*t - t**2, 2), + ((0, 1, 0, 0), 4), ((0, 1, 0, 0), QQ(1, 1)), (((0, 0, 0, 0), 4), y*z*t**2 + z**2*t**2 - t**4 - 1, 4) + ) + assert critical_pair(p2, q2, R) == ( + ((0, 0, 4, 2), 2), ((0, 0, 2, 0), QQ(1, 1)), (((0, 0, 2, 2), 2), y*z + z*t**5 + z*t + t**6, 13), + ((0, 0, 0, 5), 3), ((0, 0, 0, 3), QQ(1, 1)), (((0, 0, 0, 2), 3), z**3*t**2 + z**2*t**3 - z - t, 5) + ) def test_cp_key(): # from cyclic4 with grlex - p1 = (((0, 0, 0, 0), 4), [((0, 1, 1, 2), QQ(1,1)), ((0, 0, 2, 2), QQ(1,1)), ((0, 0, 0, 4), QQ(-1,1)), ((0, 0, 0, 0), QQ(-1,1))], 4) - q1 = (((0, 0, 0, 0), 2), [((0, 2, 0, 0), QQ(-1,1)), ((0, 1, 0, 1), QQ(-1,1)), ((0, 0, 1, 1), QQ(-1,1)), ((0, 0, 0, 2), QQ(-1,1))], 2) + R, x,y,z,t = ring("x,y,z,t", QQ, grlex) - p2 = (((0, 0, 0, 2), 3), [((0, 0, 3, 2), QQ(1,1)), ((0, 0, 2, 3), QQ(1,1)), ((0, 0, 1, 0), QQ(-1,1)), ((0, 0, 0, 1), QQ(-1,1))], 5) - q2 = (((0, 0, 2, 2), 2), [((0, 0, 1, 5), QQ(1,1)), ((0, 0, 0, 6), QQ(1,1)), ((0, 1, 1, 0), QQ(1,1)), ((0, 0, 1, 1), QQ(1,1))], 13) + p1 = (((0, 0, 0, 0), 4), y*z*t**2 + z**2*t**2 - t**4 - 1, 4) + q1 = (((0, 0, 0, 0), 2), -y**2 - y*t - z*t - t**2, 2) - cp1 = critical_pair(p1, q1, 3, grlex, QQ) - cp2 = critical_pair(p2, q2, 3, grlex, QQ) + p2 = (((0, 0, 0, 2), 3), z**3*t**2 + z**2*t**3 - z - t, 5) + q2 = (((0, 0, 2, 2), 2), y*z + z*t**5 + z*t + t**6, 13) - assert cp_key(cp1, grlex) < cp_key(cp2, grlex) + cp1 = critical_pair(p1, q1, R) + cp2 = critical_pair(p2, q2, R) - cp1 = critical_pair(p1, p2, 3, grlex, QQ) - cp2 = critical_pair(q1, q2, 3, grlex, QQ) + assert cp_key(cp1, R) < cp_key(cp2, R) + + cp1 = critical_pair(p1, p2, R) + cp2 = critical_pair(q1, q2, R) + + assert cp_key(cp1, R) < cp_key(cp2, R) - assert cp_key(cp1, grlex) < cp_key(cp2, grlex) def test_is_rewritable_or_comparable(): # from katsura4 with grlex - p = lbp(sig((0, 0, 2, 1), 2), [], 2) - B = [lbp(sig((0, 0, 0, 1), 2), [((0, 0, 2, 1), QQ(1,1)), ((0, 0, 1, 2), QQ(76,35)), ((0, 0, 0, 3), QQ(13,7)), ((0, 2, 0, 0), QQ(2,45)), ((0, 1, 1, 0), QQ(1,5)), ((0, 1, 0, 1), QQ(5,63)), ((0, 0, 2, 0), QQ(4,45)), ((0, 0, 1, 1), QQ(-32,105)), ((0, 0, 0, 2), QQ(-13,21))], 6)] + R, x,y,z,t = ring("x,y,z,t", QQ, grlex) + + p = lbp(sig((0, 0, 2, 1), 2), R.zero, 2) + B = [lbp(sig((0, 0, 0, 1), 2), QQ(2,45)*y**2 + QQ(1,5)*y*z + QQ(5,63)*y*t + z**2*t + QQ(4,45)*z**2 + QQ(76,35)*z*t**2 - QQ(32,105)*z*t + QQ(13,7)*t**3 - QQ(13,21)*t**2, 6)] # rewritable: - assert is_rewritable_or_comparable(Sign(p), Num(p), B, 3, QQ) == True + assert is_rewritable_or_comparable(Sign(p), Num(p), B) is True + + p = lbp(sig((0, 1, 1, 0), 2), R.zero, 7) + B = [lbp(sig((0, 0, 0, 0), 3), QQ(10,3)*y*z + QQ(4,3)*y*t - QQ(1,3)*y + 4*z**2 + QQ(22,3)*z*t - QQ(4,3)*z + 4*t**2 - QQ(4,3)*t, 3)] - p = lbp(sig((0, 1, 1, 0), 2), [], 7) - B = [lbp(sig((0, 0, 0, 0), 3), [((0, 1, 1, 0), QQ(10,3)), ((0, 1, 0, 1), QQ(4,3)), ((0, 0, 2, 0), QQ(4,1)), ((0, 0, 1, 1), QQ(22,3)), ((0, 0, 0, 2), QQ(4,1)), ((0, 1, 0, 0), QQ(-1,3)), ((0, 0, 1, 0), QQ(-4,3)), ((0, 0, 0, 1), QQ(-4,3))], 3)] # comparable: - assert is_rewritable_or_comparable(Sign(p), Num(p), B, 3, QQ) == True + assert is_rewritable_or_comparable(Sign(p), Num(p), B) is True + def test_f5_reduce(): # katsura3 with lex - F = [(((0, 0, 0), 1), [((1, 0, 0), QQ(1,1)), ((0, 1, 0), QQ(2,1)), ((0, 0, 1), QQ(2,1)), ((0, 0, 0), QQ(-1,1))], 1), (((0, 0, 0), 2), [((0, 2, 0), QQ(6,1)), ((0, 1, 1), QQ(8,1)), ((0, 1, 0), QQ(-2,1)), ((0, 0, 2), QQ(6,1)), ((0, 0, 1), QQ(-2,1))], 2), (((0, 0, 0), 3), [((0, 1, 1), QQ(10,3)), ((0, 1, 0), QQ(-1,3)), ((0, 0, 2), QQ(4,1)), ((0, 0, 1), QQ(-4,3))], 3), (((0, 0, 1), 2), [((0, 1, 0), QQ(1,1)), ((0, 0, 3), QQ(30,1)), ((0, 0, 2), QQ(-79,7)), ((0, 0, 1), QQ(3,7))], 4), (((0, 0, 2), 2), [((0, 0, 4), QQ(1,1)), ((0, 0, 3), QQ(-10,21)), ((0, 0, 2), QQ(1,84)), ((0, 0, 1), QQ(1,84))], 5)] + R, x,y,z = ring("x,y,z", QQ, lex) + + F = [(((0, 0, 0), 1), x + 2*y + 2*z - 1, 1), + (((0, 0, 0), 2), 6*y**2 + 8*y*z - 2*y + 6*z**2 - 2*z, 2), + (((0, 0, 0), 3), QQ(10,3)*y*z - QQ(1,3)*y + 4*z**2 - QQ(4,3)*z, 3), + (((0, 0, 1), 2), y + 30*z**3 - QQ(79,7)*z**2 + QQ(3,7)*z, 4), + (((0, 0, 2), 2), z**4 - QQ(10,21)*z**3 + QQ(1,84)*z**2 + QQ(1,84)*z, 5)] - cp = critical_pair(F[0], F[1], 2, lex, QQ) - s = s_poly(cp, 2, lex, QQ) + cp = critical_pair(F[0], F[1], R) + s = s_poly(cp) - assert f5_reduce(s, F, 2, lex, QQ) == (((0, 2, 0), 1), [], 1) + assert f5_reduce(s, F) == (((0, 2, 0), 1), R.zero, 1) s = lbp(sig(Sign(s)[0], 100), Polyn(s), Num(s)) - assert f5_reduce(s, F, 2, lex, QQ) == s + assert f5_reduce(s, F) == s -def test_matrix_fglm(): - pass # see test_polytools.py def test_representing_matrices(): + R, x,y = ring("x,y", QQ, grlex) + basis = [(0, 0), (0, 1), (1, 0), (1, 1)] - F = [[((2, 0), QQ(1,1)), ((1, 0), QQ(-1,1)), ((0, 1), QQ(-3,1)), ((0, 0), QQ(1,1))], - [((0, 2), QQ(1,1)), ((1, 0), QQ(-2,1)), ((0, 1), QQ(1,1)), ((0, 0), QQ(-1,1))]] + F = [x**2 - x - 3*y + 1, -2*x + y**2 + y - 1] + + assert _representing_matrices(basis, F, R) == [ + [[QQ(0, 1), QQ(0, 1),-QQ(1, 1), QQ(3, 1)], + [QQ(0, 1), QQ(0, 1), QQ(3, 1),-QQ(4, 1)], + [QQ(1, 1), QQ(0, 1), QQ(1, 1), QQ(6, 1)], + [QQ(0, 1), QQ(1, 1), QQ(0, 1), QQ(1, 1)]], + [[QQ(0, 1), QQ(1, 1), QQ(0, 1),-QQ(2, 1)], + [QQ(1, 1),-QQ(1, 1), QQ(0, 1), QQ(6, 1)], + [QQ(0, 1), QQ(2, 1), QQ(0, 1), QQ(3, 1)], + [QQ(0, 1), QQ(0, 1), QQ(1, 1),-QQ(1, 1)]]] + +def test_groebner_lcm(): + R, x,y,z = ring("x,y,z", ZZ) + + assert groebner_lcm(x**2 - y**2, x - y) == x**2 - y**2 + assert groebner_lcm(2*x**2 - 2*y**2, 2*x - 2*y) == 2*x**2 - 2*y**2 + + R, x,y,z = ring("x,y,z", QQ) + + assert groebner_lcm(x**2 - y**2, x - y) == x**2 - y**2 + assert groebner_lcm(2*x**2 - 2*y**2, 2*x - 2*y) == 2*x**2 - 2*y**2 + + R, x,y = ring("x,y", ZZ) + + assert groebner_lcm(x**2*y, x*y**2) == x**2*y**2 + + f = 2*x*y**5 - 3*x*y**4 - 2*x*y**3 + 3*x*y**2 + g = y**5 - 2*y**3 + y + h = 2*x*y**7 - 3*x*y**6 - 4*x*y**5 + 6*x*y**4 + 2*x*y**3 - 3*x*y**2 + + assert groebner_lcm(f, g) == h + + f = x**3 - 3*x**2*y - 9*x*y**2 - 5*y**3 + g = x**4 + 6*x**3*y + 12*x**2*y**2 + 10*x*y**3 + 3*y**4 + h = x**5 + x**4*y - 18*x**3*y**2 - 50*x**2*y**3 - 47*x*y**4 - 15*y**5 + + assert groebner_lcm(f, g) == h + +def test_groebner_gcd(): + R, x,y,z = ring("x,y,z", ZZ) + + assert groebner_gcd(x**2 - y**2, x - y) == x - y + assert groebner_gcd(2*x**2 - 2*y**2, 2*x - 2*y) == 2*x - 2*y + + R, x,y,z = ring("x,y,z", QQ) - assert _representing_matrices(basis, F, 1, grlex, QQ) ==[ \ - [[QQ(0,1), QQ(0,1), QQ(-1,1), QQ(3,1)], - [QQ(0,1), QQ(0,1), QQ(3,1), QQ(-4,1)], - [QQ(1,1), QQ(0,1), QQ(1,1), QQ(6,1)], - [QQ(0,1), QQ(1,1), QQ(0,1), QQ(1,1)]], - [[QQ(0,1), QQ(1,1), QQ(0,1), QQ(-2,1)], - [QQ(1,1), QQ(-1,1), QQ(0,1), QQ(6,1)], - [QQ(0,1), QQ(2,1), QQ(0,1), QQ(3,1)], - [QQ(0,1), QQ(0,1), QQ(1,1), QQ(-1,1)]]] + assert groebner_gcd(x**2 - y**2, x - y) == x - y + assert groebner_gcd(2*x**2 - 2*y**2, 2*x - 2*y) == x - y diff -Nru python3-sympy-0.7.2/sympy/polys/tests/test_heuristicgcd.py python3-sympy-0.7.3/sympy/polys/tests/test_heuristicgcd.py --- python3-sympy-0.7.2/sympy/polys/tests/test_heuristicgcd.py 1970-01-01 00:00:00.000000000 +0000 +++ python3-sympy-0.7.3/sympy/polys/tests/test_heuristicgcd.py 2013-07-13 17:53:32.000000000 +0000 @@ -0,0 +1,128 @@ +from sympy.polys.rings import ring +from sympy.polys.domains import ZZ +from sympy.polys.heuristicgcd import heugcd + +def test_heugcd_univariate_integers(): + R, x = ring("x", ZZ) + + f = x**4 + 8*x**3 + 21*x**2 + 22*x + 8 + g = x**3 + 6*x**2 + 11*x + 6 + + h = x**2 + 3*x + 2 + + cff = x**2 + 5*x + 4 + cfg = x + 3 + + assert heugcd(f, g) == (h, cff, cfg) + + f = x**4 - 4 + g = x**4 + 4*x**2 + 4 + + h = x**2 + 2 + + cff = x**2 - 2 + cfg = x**2 + 2 + + assert heugcd(f, g) == (h, cff, cfg) + + f = x**8 + x**6 - 3*x**4 - 3*x**3 + 8*x**2 + 2*x - 5 + g = 3*x**6 + 5*x**4 - 4*x**2 - 9*x + 21 + + h = 1 + + cff = f + cfg = g + + assert heugcd(f, g) == (h, cff, cfg) + + f = - 352518131239247345597970242177235495263669787845475025293906825864749649589178600387510272*x**49 \ + + 46818041807522713962450042363465092040687472354933295397472942006618953623327997952*x**42 \ + + 378182690892293941192071663536490788434899030680411695933646320291525827756032*x**35 \ + + 112806468807371824947796775491032386836656074179286744191026149539708928*x**28 \ + - 12278371209708240950316872681744825481125965781519138077173235712*x**21 \ + + 289127344604779611146960547954288113529690984687482920704*x**14 \ + + 19007977035740498977629742919480623972236450681*x**7 \ + + 311973482284542371301330321821976049 + + g = 365431878023781158602430064717380211405897160759702125019136*x**21 \ + + 197599133478719444145775798221171663643171734081650688*x**14 \ + - 9504116979659010018253915765478924103928886144*x**7 \ + - 311973482284542371301330321821976049 + + # TODO: assert heugcd(f, f.diff(x))[0] == g + + f = 1317378933230047068160*x + 2945748836994210856960 + g = 120352542776360960*x + 269116466014453760 + + h = 120352542776360960*x + 269116466014453760 + cff = 10946 + cfg = 1 + + assert heugcd(f, g) == (h, cff, cfg) + +def test_heugcd_multivariate_integers(): + R, x, y = ring("x,y", ZZ) + + f, g = 2*x**2 + 4*x + 2, x + 1 + assert heugcd(f, g) == (x + 1, 2*x + 2, 1) + + f, g = x + 1, 2*x**2 + 4*x + 2 + assert heugcd(f, g) == (x + 1, 1, 2*x + 2) + + R, x, y, z, u = ring("x,y,z,u", ZZ) + + f, g = u**2 + 2*u + 1, 2*u + 2 + assert heugcd(f, g) == (u + 1, u + 1, 2) + + f, g = z**2*u**2 + 2*z**2*u + z**2 + z*u + z, u**2 + 2*u + 1 + h, cff, cfg = u + 1, z**2*u + z**2 + z, u + 1 + + assert heugcd(f, g) == (h, cff, cfg) + assert heugcd(g, f) == (h, cfg, cff) + + R, x, y, z = ring("x,y,z", ZZ) + + f, g, h = R.fateman_poly_F_1() + H, cff, cfg = heugcd(f, g) + + assert H == h and H*cff == f and H*cfg == g + + R, x, y, z, u, v = ring("x,y,z,u,v", ZZ) + + f, g, h = R.fateman_poly_F_1() + H, cff, cfg = heugcd(f, g) + + assert H == h and H*cff == f and H*cfg == g + + R, x, y, z, u, v, a, b = ring("x,y,z,u,v,a,b", ZZ) + + f, g, h = R.fateman_poly_F_1() + H, cff, cfg = heugcd(f, g) + + assert H == h and H*cff == f and H*cfg == g + + R, x, y, z, u, v, a, b, c, d = ring("x,y,z,u,v,a,b,c,d", ZZ) + + f, g, h = R.fateman_poly_F_1() + H, cff, cfg = heugcd(f, g) + + assert H == h and H*cff == f and H*cfg == g + + R, x, y, z = ring("x,y,z", ZZ) + + f, g, h = R.fateman_poly_F_2() + H, cff, cfg = heugcd(f, g) + + assert H == h and H*cff == f and H*cfg == g + + f, g, h = R.fateman_poly_F_3() + H, cff, cfg = heugcd(f, g) + + assert H == h and H*cff == f and H*cfg == g + + R, x, y, z, t = ring("x,y,z,t", ZZ) + + f, g, h = R.fateman_poly_F_3() + H, cff, cfg = heugcd(f, g) + + assert H == h and H*cff == f and H*cfg == g diff -Nru python3-sympy-0.7.2/sympy/polys/tests/test_injections.py python3-sympy-0.7.3/sympy/polys/tests/test_injections.py --- python3-sympy-0.7.2/sympy/polys/tests/test_injections.py 1970-01-01 00:00:00.000000000 +0000 +++ python3-sympy-0.7.3/sympy/polys/tests/test_injections.py 2013-07-13 17:53:32.000000000 +0000 @@ -0,0 +1,82 @@ +"""Tests for functions that inject symbols into the global namespace. """ + +from sympy.polys.rings import vring +from sympy.polys.fields import vfield +from sympy.polys.domains import QQ +from sympy.utilities.pytest import raises + +# make r1 with call-depth = 1 + +def _make_r1(): + return vring("r1", QQ) + +# make r2 with call-depth = 2 + +def __make_r2(): + return vring("r2", QQ) + +def _make_r2(): + return __make_r2() + +def test_vring(): + R = vring("r", QQ) + assert r == R.gens[0] + + R = vring("rb rbb rcc rzz _rx", QQ) + assert rb == R.gens[0] + assert rbb == R.gens[1] + assert rcc == R.gens[2] + assert rzz == R.gens[3] + assert _rx == R.gens[4] + + R = vring(['rd', 're', 'rfg'], QQ) + assert rd == R.gens[0] + assert re == R.gens[1] + assert rfg == R.gens[2] + + # see if vring() really injects into global namespace + raises(NameError, lambda: r1) + R = _make_r1() + assert r1 == R.gens[0] + + raises(NameError, lambda: r2) + R = _make_r2() + assert r2 == R.gens[0] + +# make f1 with call-depth = 1 + +def _make_f1(): + return vfield("f1", QQ) + +# make f2 with call-depth = 2 + +def __make_f2(): + return vfield("f2", QQ) + +def _make_f2(): + return __make_f2() + +def test_vfield(): + F = vfield("f", QQ) + assert f == F.gens[0] + + F = vfield("fb fbb fcc fzz _fx", QQ) + assert fb == F.gens[0] + assert fbb == F.gens[1] + assert fcc == F.gens[2] + assert fzz == F.gens[3] + assert _fx == F.gens[4] + + F = vfield(['fd', 'fe', 'ffg'], QQ) + assert fd == F.gens[0] + assert fe == F.gens[1] + assert ffg == F.gens[2] + + # see if vfield() really injects into global namespace + raises(NameError, lambda: f1) + F = _make_f1() + assert f1 == F.gens[0] + + raises(NameError, lambda: f2) + F = _make_f2() + assert f2 == F.gens[0] diff -Nru python3-sympy-0.7.2/sympy/polys/tests/test_monomialtools.py python3-sympy-0.7.3/sympy/polys/tests/test_monomialtools.py --- python3-sympy-0.7.2/sympy/polys/tests/test_monomialtools.py 2012-10-17 03:02:22.000000000 +0000 +++ python3-sympy-0.7.3/sympy/polys/tests/test_monomialtools.py 2013-07-13 17:53:32.000000000 +0000 @@ -17,6 +17,7 @@ from sympy.abc import a, b, c, x, y, z from sympy.utilities.pytest import raises + def test_monomials(): assert sorted(monomials([], 0)) == [1] assert sorted(monomials([], 1)) == [1] @@ -31,82 +32,88 @@ assert sorted(monomials([x, y], 0)) == [1] assert sorted(monomials([x, y], 1)) == [1, x, y] assert sorted(monomials([x, y], 2)) == [1, x, y, x**2, y**2, x*y] - assert sorted(monomials([x, y], 3)) == [1, x, y, x**2, x**3, y**2, y**3, x*y, x*y**2, y*x**2] + assert sorted(monomials( + [x, y], 3)) == [1, x, y, x**2, x**3, y**2, y**3, x*y, x*y**2, y*x**2] + def test_monomial_count(): assert monomial_count(2, 2) == 6 assert monomial_count(2, 3) == 10 + def test_lex_order(): - assert lex((1,2,3)) == (1,2,3) + assert lex((1, 2, 3)) == (1, 2, 3) assert str(lex) == 'lex' - assert lex((1,2,3)) == lex((1,2,3)) + assert lex((1, 2, 3)) == lex((1, 2, 3)) - assert lex((2,2,3)) > lex((1,2,3)) - assert lex((1,3,3)) > lex((1,2,3)) - assert lex((1,2,4)) > lex((1,2,3)) - - assert lex((0,2,3)) < lex((1,2,3)) - assert lex((1,1,3)) < lex((1,2,3)) - assert lex((1,2,2)) < lex((1,2,3)) + assert lex((2, 2, 3)) > lex((1, 2, 3)) + assert lex((1, 3, 3)) > lex((1, 2, 3)) + assert lex((1, 2, 4)) > lex((1, 2, 3)) + + assert lex((0, 2, 3)) < lex((1, 2, 3)) + assert lex((1, 1, 3)) < lex((1, 2, 3)) + assert lex((1, 2, 2)) < lex((1, 2, 3)) assert lex.is_global is True assert lex == LexOrder() assert lex != grlex + def test_grlex_order(): - assert grlex((1,2,3)) == (6, (1,2,3)) + assert grlex((1, 2, 3)) == (6, (1, 2, 3)) assert str(grlex) == 'grlex' - assert grlex((1,2,3)) == grlex((1,2,3)) + assert grlex((1, 2, 3)) == grlex((1, 2, 3)) - assert grlex((2,2,3)) > grlex((1,2,3)) - assert grlex((1,3,3)) > grlex((1,2,3)) - assert grlex((1,2,4)) > grlex((1,2,3)) + assert grlex((2, 2, 3)) > grlex((1, 2, 3)) + assert grlex((1, 3, 3)) > grlex((1, 2, 3)) + assert grlex((1, 2, 4)) > grlex((1, 2, 3)) - assert grlex((0,2,3)) < grlex((1,2,3)) - assert grlex((1,1,3)) < grlex((1,2,3)) - assert grlex((1,2,2)) < grlex((1,2,3)) + assert grlex((0, 2, 3)) < grlex((1, 2, 3)) + assert grlex((1, 1, 3)) < grlex((1, 2, 3)) + assert grlex((1, 2, 2)) < grlex((1, 2, 3)) - assert grlex((2,2,3)) > grlex((1,2,4)) - assert grlex((1,3,3)) > grlex((1,2,4)) + assert grlex((2, 2, 3)) > grlex((1, 2, 4)) + assert grlex((1, 3, 3)) > grlex((1, 2, 4)) - assert grlex((0,2,3)) < grlex((1,2,2)) - assert grlex((1,1,3)) < grlex((1,2,2)) + assert grlex((0, 2, 3)) < grlex((1, 2, 2)) + assert grlex((1, 1, 3)) < grlex((1, 2, 2)) assert grlex.is_global is True + def test_grevlex_order(): - assert grevlex((1,2,3)) == (6, (-3,-2,-1)) + assert grevlex((1, 2, 3)) == (6, (-3, -2, -1)) assert str(grevlex) == 'grevlex' - assert grevlex((1,2,3)) == grevlex((1,2,3)) + assert grevlex((1, 2, 3)) == grevlex((1, 2, 3)) - assert grevlex((2,2,3)) > grevlex((1,2,3)) - assert grevlex((1,3,3)) > grevlex((1,2,3)) - assert grevlex((1,2,4)) > grevlex((1,2,3)) + assert grevlex((2, 2, 3)) > grevlex((1, 2, 3)) + assert grevlex((1, 3, 3)) > grevlex((1, 2, 3)) + assert grevlex((1, 2, 4)) > grevlex((1, 2, 3)) - assert grevlex((0,2,3)) < grevlex((1,2,3)) - assert grevlex((1,1,3)) < grevlex((1,2,3)) - assert grevlex((1,2,2)) < grevlex((1,2,3)) + assert grevlex((0, 2, 3)) < grevlex((1, 2, 3)) + assert grevlex((1, 1, 3)) < grevlex((1, 2, 3)) + assert grevlex((1, 2, 2)) < grevlex((1, 2, 3)) - assert grevlex((2,2,3)) > grevlex((1,2,4)) - assert grevlex((1,3,3)) > grevlex((1,2,4)) + assert grevlex((2, 2, 3)) > grevlex((1, 2, 4)) + assert grevlex((1, 3, 3)) > grevlex((1, 2, 4)) - assert grevlex((0,2,3)) < grevlex((1,2,2)) - assert grevlex((1,1,3)) < grevlex((1,2,2)) + assert grevlex((0, 2, 3)) < grevlex((1, 2, 2)) + assert grevlex((1, 1, 3)) < grevlex((1, 2, 2)) - assert grevlex((0,1,1)) > grevlex((0,0,2)) - assert grevlex((0,3,1)) < grevlex((2,2,1)) + assert grevlex((0, 1, 1)) > grevlex((0, 0, 2)) + assert grevlex((0, 3, 1)) < grevlex((2, 2, 1)) assert grevlex.is_global is True + def test_InverseOrder(): ilex = InverseOrder(lex) igrlex = InverseOrder(grlex) - assert ilex((1,2,3)) > ilex((2, 0, 3)) + assert ilex((1, 2, 3)) > ilex((2, 0, 3)) assert igrlex((1, 2, 3)) < igrlex((0, 2, 3)) assert str(ilex) == "ilex" assert str(igrlex) == "igrlex" @@ -115,6 +122,7 @@ assert ilex != igrlex assert ilex == InverseOrder(LexOrder()) + def test_ProductOrder(): P = ProductOrder((grlex, lambda m: m[:2]), (grlex, lambda m: m[2:])) assert P((1, 3, 3, 4, 5)) > P((2, 1, 5, 5, 5)) @@ -123,6 +131,7 @@ assert ProductOrder((grlex, None), (ilex, None)).is_global is None assert ProductOrder((igrlex, None), (ilex, None)).is_global is False + def test_monomial_key(): assert monomial_key() == lex @@ -133,38 +142,48 @@ raises(ValueError, lambda: monomial_key('foo')) raises(ValueError, lambda: monomial_key(1)) + def test_build_product_order(): from sympy.abc import x, y, z, t - assert build_product_order((("grlex", x, y), ("grlex", z, t)), [x, y, z, t]) \ - ((4, 5, 6, 7)) == ((9, (4, 5)), (13, (6, 7))) + assert build_product_order((("grlex", x, y), ("grlex", z, t)), [x, y, z, t] + )((4, 5, 6, 7)) == ((9, (4, 5)), (13, (6, 7))) assert build_product_order((("grlex", x, y), ("grlex", z, t)), [x, y, z, t]) == \ - build_product_order((("grlex", x, y), ("grlex", z, t)), [x, y, z, t]) - assert (build_product_order((("grlex", x, y), ("grlex", z, t)), [x, y, z, t]) != \ - build_product_order((("grlex", x, y), ("grlex", z, t)), [x, y, z, t])) \ - is False + build_product_order( + (("grlex", x, y), ("grlex", z, t)), [x, y, z, t]) + assert (build_product_order((("grlex", x, y), ("grlex", z, t)), [x, y, z, t]) != + build_product_order((("grlex", x, y), ("grlex", z, t)), [x, y, z, t])) \ + is False + def test_monomial_mul(): - assert monomial_mul((3,4,1), (1,2,0)) == (4,6,1) + assert monomial_mul((3, 4, 1), (1, 2, 0)) == (4, 6, 1) + def test_monomial_div(): - assert monomial_div((3,4,1), (1,2,0)) == (2,2,1) + assert monomial_div((3, 4, 1), (1, 2, 0)) == (2, 2, 1) + def test_monomial_gcd(): - assert monomial_gcd((3,4,1), (1,2,0)) == (1,2,0) + assert monomial_gcd((3, 4, 1), (1, 2, 0)) == (1, 2, 0) + def test_monomial_lcm(): - assert monomial_lcm((3,4,1), (1,2,0)) == (3,4,1) + assert monomial_lcm((3, 4, 1), (1, 2, 0)) == (3, 4, 1) + def test_monomial_max(): - assert monomial_max((3,4,5), (0,5,1), (6,3,9)) == (6,5,9) + assert monomial_max((3, 4, 5), (0, 5, 1), (6, 3, 9)) == (6, 5, 9) + def test_monomial_min(): - assert monomial_min((3,4,5), (0,5,1), (6,3,9)) == (0,3,1) + assert monomial_min((3, 4, 5), (0, 5, 1), (6, 3, 9)) == (0, 3, 1) + def test_monomial_divides(): - assert monomial_divides((1,2,3), (4,5,6)) is True - assert monomial_divides((1,2,3), (0,5,6)) is False + assert monomial_divides((1, 2, 3), (4, 5, 6)) is True + assert monomial_divides((1, 2, 3), (0, 5, 6)) is False + def test_Monomial(): m = Monomial((3, 4, 1), (x, y, z)) @@ -213,6 +232,6 @@ assert m**0 == Monomial((0, 0, 0)) assert m**1 == m assert m**2 == Monomial((6, 8, 2)) - assert m**3 == Monomial((9,12, 3)) + assert m**3 == Monomial((9, 12, 3)) raises(ExactQuotientFailed, lambda: m/Monomial((5, 2, 0))) diff -Nru python3-sympy-0.7.2/sympy/polys/tests/test_numberfields.py python3-sympy-0.7.3/sympy/polys/tests/test_numberfields.py --- python3-sympy-0.7.2/sympy/polys/tests/test_numberfields.py 2012-10-17 03:02:22.000000000 +0000 +++ python3-sympy-0.7.3/sympy/polys/tests/test_numberfields.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,6 +1,8 @@ """Tests for computational algebraic number field theory. """ -from sympy import S, Rational, Symbol, Poly, sin, sqrt, I, oo, Tuple +from sympy import (S, Rational, Symbol, Poly, sin, sqrt, I, oo, Tuple, expand, + Add, Mul, pi, cos, sin, exp) + from sympy.utilities.pytest import raises from sympy.polys.numberfields import ( @@ -21,11 +23,16 @@ from sympy.polys.polyclasses import DMP from sympy.polys.domains import QQ +from sympy.polys.polytools import degree +from sympy.solvers import solve + +from sympy.utilities.pytest import skip from sympy.abc import x, y Q = Rational + def test_minimal_polynomial(): assert minimal_polynomial(-7, x) == x + 7 assert minimal_polynomial(-1, x) == x + 1 @@ -41,26 +48,29 @@ assert minimal_polynomial(3*sqrt(5), x) == x**2 - 45 assert minimal_polynomial(4*sqrt(6), x) == x**2 - 96 - assert minimal_polynomial(2*sqrt(2) + 3, x) == x**2 - 6*x + 1 - assert minimal_polynomial(3*sqrt(5) + 6, x) == x**2 - 12*x - 9 + assert minimal_polynomial(2*sqrt(2) + 3, x) == x**2 - 6*x + 1 + assert minimal_polynomial(3*sqrt(5) + 6, x) == x**2 - 12*x - 9 assert minimal_polynomial(4*sqrt(6) + 7, x) == x**2 - 14*x - 47 - assert minimal_polynomial(2*sqrt(2) - 3, x) == x**2 + 6*x + 1 - assert minimal_polynomial(3*sqrt(5) - 6, x) == x**2 + 12*x - 9 + assert minimal_polynomial(2*sqrt(2) - 3, x) == x**2 + 6*x + 1 + assert minimal_polynomial(3*sqrt(5) - 6, x) == x**2 + 12*x - 9 assert minimal_polynomial(4*sqrt(6) - 7, x) == x**2 + 14*x - 47 - assert minimal_polynomial(sqrt(1 + sqrt(6)), x) == x**4 - 2*x**2 - 5 + assert minimal_polynomial(sqrt(1 + sqrt(6)), x) == x**4 - 2*x**2 - 5 assert minimal_polynomial(sqrt(I + sqrt(6)), x) == x**8 - 10*x**4 + 49 assert minimal_polynomial(2*I + sqrt(2 + I), x) == x**4 + 4*x**2 + 8*x + 37 assert minimal_polynomial(sqrt(2) + sqrt(3), x) == x**4 - 10*x**2 + 1 - assert minimal_polynomial(sqrt(2) + sqrt(3) + sqrt(6), x) == x**4 - 22*x**2 - 48*x - 23 + assert minimal_polynomial( + sqrt(2) + sqrt(3) + sqrt(6), x) == x**4 - 22*x**2 - 48*x - 23 a = 1 - 9*sqrt(2) + 7*sqrt(3) - assert minimal_polynomial(1/a, x) == 392*x**4 - 1232*x**3 + 612*x**2 + 4*x - 1 - assert minimal_polynomial(1/sqrt(a), x) == 392*x**8 - 1232*x**6 + 612*x**4 + 4*x**2 - 1 + assert minimal_polynomial( + 1/a, x) == 392*x**4 - 1232*x**3 + 612*x**2 + 4*x - 1 + assert minimal_polynomial( + 1/sqrt(a), x) == 392*x**8 - 1232*x**6 + 612*x**4 + 4*x**2 - 1 raises(NotAlgebraic, lambda: minimal_polynomial(y, x)) raises(NotAlgebraic, lambda: minimal_polynomial(oo, x)) @@ -72,6 +82,7 @@ assert minimal_polynomial(sqrt(2), polys=True) == Poly(x**2 - 2) assert minimal_polynomial(sqrt(2), x, polys=True) == Poly(x**2 - 2) + assert minimal_polynomial(sqrt(2), x, polys=True, compose=False) == Poly(x**2 - 2) a = AlgebraicNumber(sqrt(2)) b = AlgebraicNumber(sqrt(3)) @@ -82,38 +93,182 @@ assert minimal_polynomial(a, x, polys=True) == Poly(x**2 - 2) assert minimal_polynomial(b, x, polys=True) == Poly(x**2 - 3) - assert minimal_polynomial(sqrt(a/2 + 17), x) == 2*x**4 - 68*x**2 + 577 + assert minimal_polynomial(sqrt(a/2 + 17), x) == 2*x**4 - 68*x**2 + 577 assert minimal_polynomial(sqrt(b/2 + 17), x) == 4*x**4 - 136*x**2 + 1153 a, b = sqrt(2)/3 + 7, AlgebraicNumber(sqrt(2)/3 + 7) - f = 81*x**8 - 2268*x**6 - 4536*x**5 + 22644*x**4 + 63216*x**3 - 31608*x**2 - 189648*x + 141358 + f = 81*x**8 - 2268*x**6 - 4536*x**5 + 22644*x**4 + 63216*x**3 - \ + 31608*x**2 - 189648*x + 141358 assert minimal_polynomial(sqrt(a) + sqrt(sqrt(a)), x) == f assert minimal_polynomial(sqrt(b) + sqrt(sqrt(b)), x) == f - assert minimal_polynomial(a**Q(3, 2), x) == 729*x**4 - 506898*x**2 + 84604519 + assert minimal_polynomial( + a**Q(3, 2), x) == 729*x**4 - 506898*x**2 + 84604519 + + # issue 2895 + eq = S(''' + -1/(800*sqrt(-1/240 + 1/(18000*(-1/17280000 + + sqrt(15)*I/28800000)**(1/3)) + 2*(-1/17280000 + + sqrt(15)*I/28800000)**(1/3)))''') + assert minimal_polynomial(eq, x) == 8000*x**2 - 1 + + ex = 1 + sqrt(2) + sqrt(3) + mp = minimal_polynomial(ex, x) + assert mp == x**4 - 4*x**3 - 4*x**2 + 16*x - 8 + + ex = 1/(1 + sqrt(2) + sqrt(3)) + mp = minimal_polynomial(ex, x) + assert mp == 8*x**4 - 16*x**3 + 4*x**2 + 4*x - 1 + + p = (expand((1 + sqrt(2) - 2*sqrt(3) + sqrt(7))**3))**Rational(1, 3) + mp = minimal_polynomial(p, x) + assert mp == x**8 - 8*x**7 - 56*x**6 + 448*x**5 + 480*x**4 - 5056*x**3 + 1984*x**2 + 7424*x - 3008 + p = expand((1 + sqrt(2) - 2*sqrt(3) + sqrt(7))**3) + mp = minimal_polynomial(p, x) + assert mp == x**8 - 512*x**7 - 118208*x**6 + 31131136*x**5 + 647362560*x**4 - 56026611712*x**3 + 116994310144*x**2 + 404854931456*x - 27216576512 + + assert minimal_polynomial(S("-sqrt(5)/2 - 1/2 + (-sqrt(5)/2 - 1/2)**2"), x) == x - 1 + a = 1 + sqrt(2) + assert minimal_polynomial((a*sqrt(2) + a)**3, x) == x**2 - 198*x + 1 + + p = 1/(1 + sqrt(2) + sqrt(3)) + assert minimal_polynomial(p, x, compose=False) == 8*x**4 - 16*x**3 + 4*x**2 + 4*x - 1 + + p = 2/(1 + sqrt(2) + sqrt(3)) + assert minimal_polynomial(p, x, compose=False) == x**4 - 4*x**3 + 2*x**2 + 4*x - 2 + + assert minimal_polynomial(1 + sqrt(2)*I, x, compose=False) == x**2 - 2*x + 3 + assert minimal_polynomial(1/(1 + sqrt(2)) + 1, x, compose=False) == x**2 - 2 + assert minimal_polynomial(sqrt(2)*I + I*(1 + sqrt(2)), x, + compose=False) == x**4 + 18*x**2 + 49 + +def test_minimal_polynomial_hi_prec(): + p = 1/sqrt(1 - 9*sqrt(2) + 7*sqrt(3) + S(1)/10**30) + mp = minimal_polynomial(p, x) + # checked with Wolfram Alpha + assert mp.coeff(x**6) == -1232000000000000000000000000001223999999999999999999999999999987999999999999999999999999999996000000000000000000000000000000 + + +def test_minimal_polynomial_sq(): + from sympy import Add, expand_multinomial + p = expand_multinomial((1 + 5*sqrt(2) + 2*sqrt(3))**3) + mp = minimal_polynomial(p**Rational(1, 3), x) + assert mp == x**4 - 4*x**3 - 118*x**2 + 244*x + 1321 + p = expand_multinomial((1 + sqrt(2) - 2*sqrt(3) + sqrt(7))**3) + mp = minimal_polynomial(p**Rational(1, 3), x) + assert mp == x**8 - 8*x**7 - 56*x**6 + 448*x**5 + 480*x**4 - 5056*x**3 + 1984*x**2 + 7424*x - 3008 + p = Add(*[sqrt(i) for i in range(1, 12)]) + mp = minimal_polynomial(p, x) + assert mp.subs({x: 0}) == -71965773323122507776 + + +def test_minpoly_compose(): + # issue 3769 + eq = S(''' + -1/(800*sqrt(-1/240 + 1/(18000*(-1/17280000 + + sqrt(15)*I/28800000)**(1/3)) + 2*(-1/17280000 + + sqrt(15)*I/28800000)**(1/3)))''') + mp = minimal_polynomial(eq + 3, x) + assert mp == 8000*x**2 - 48000*x + 71999 + + # issue 2789 + assert minimal_polynomial(exp(I*pi/8), x) == x**8 + 1 + + mp = minimal_polynomial(sin(pi/7) + sqrt(2), x) + assert mp == 4096*x**12 - 63488*x**10 + 351488*x**8 - 826496*x**6 + \ + 770912*x**4 - 268432*x**2 + 28561 + mp = minimal_polynomial(cos(pi/7) + sqrt(2), x) + assert mp == 64*x**6 - 64*x**5 - 432*x**4 + 304*x**3 + 712*x**2 - \ + 232*x - 239 + mp = minimal_polynomial(exp(I*pi/7) + sqrt(2), x) + assert mp == x**12 - 2*x**11 - 9*x**10 + 16*x**9 + 43*x**8 - 70*x**7 - 97*x**6 + 126*x**5 + 211*x**4 - 212*x**3 - 37*x**2 + 142*x + 127 + + mp = minimal_polynomial(sin(pi/7) + sqrt(2), x) + assert mp == 4096*x**12 - 63488*x**10 + 351488*x**8 - 826496*x**6 + \ + 770912*x**4 - 268432*x**2 + 28561 + mp = minimal_polynomial(cos(pi/7) + sqrt(2), x) + assert mp == 64*x**6 - 64*x**5 - 432*x**4 + 304*x**3 + 712*x**2 - \ + 232*x - 239 + mp = minimal_polynomial(exp(I*pi/7) + sqrt(2), x) + assert mp == x**12 - 2*x**11 - 9*x**10 + 16*x**9 + 43*x**8 - 70*x**7 - 97*x**6 + 126*x**5 + 211*x**4 - 212*x**3 - 37*x**2 + 142*x + 127 + + mp = minimal_polynomial(exp(2*I*pi/7), x) + assert mp == x**6 + x**5 + x**4 + x**3 + x**2 + x + 1 + mp = minimal_polynomial(exp(2*I*pi/15), x) + assert mp == x**8 - x**7 + x**5 - x**4 + x**3 - x + 1 + mp = minimal_polynomial(cos(2*pi/7), x) + assert mp == 8*x**3 + 4*x**2 - 4*x - 1 + mp = minimal_polynomial(sin(2*pi/7), x) + ex = (5*cos(2*pi/7) - 7)/(9*cos(pi/7) - 5*cos(3*pi/7)) + mp = minimal_polynomial(ex, x) + assert mp == x**3 + 2*x**2 - x - 1 + assert minimal_polynomial(-1/(2*cos(pi/7)), x) == x**3 + 2*x**2 - x - 1 + assert minimal_polynomial(sin(2*pi/15), x) == \ + 256*x**8 - 448*x**6 + 224*x**4 - 32*x**2 + 1 + assert minimal_polynomial(sin(5*pi/14), x) == 8*x**3 - 4*x**2 - 4*x + 1 + assert minimal_polynomial(cos(pi/15), x) == 16*x**4 + 8*x**3 - 16*x**2 - 8*x + 1 + + eq = expand((x**5 + 3*x + 1)*(x**3 + 4*x + 1)) + ex = solve(eq, x)[0] + mp = minimal_polynomial(ex, x) + assert mp == x**3 + 4*x + 1 + mp = minimal_polynomial(ex + 1, x) + assert mp == x**3 - 3*x**2 + 7*x - 4 + assert minimal_polynomial(exp(I*pi/3), x) == x**2 - x + 1 + assert minimal_polynomial(exp(I*pi/4), x) == x**4 + 1 + assert minimal_polynomial(exp(I*pi/6), x) == x**4 - x**2 + 1 + assert minimal_polynomial(exp(I*pi/9), x) == x**6 - x**3 + 1 + assert minimal_polynomial(exp(I*pi/10), x) == x**8 - x**6 + x**4 - x**2 + 1 + assert minimal_polynomial(sin(pi/9), x) == 64*x**6 - 96*x**4 + 36*x**2 - 3 + assert minimal_polynomial(sin(pi/11), x) == 1024*x**10 - 2816*x**8 + \ + 2816*x**6 - 1232*x**4 + 220*x**2 - 11 + + ex = 2**Rational(1, 3)*exp(Rational(2, 3)*I*pi) + assert minimal_polynomial(ex, x) == x**3 - 2 + + raises(NotAlgebraic, lambda: minimal_polynomial(cos(pi*sqrt(2)), x)) + raises(NotAlgebraic, lambda: minimal_polynomial(sin(pi*sqrt(2)), x)) + raises(NotAlgebraic, lambda: minimal_polynomial(exp(I*pi*sqrt(2)), x)) + + # issue 2835 + ex = 1/(-36000 - 7200*sqrt(5) + (12*sqrt(10)*sqrt(sqrt(5) + 5) + + 24*sqrt(10)*sqrt(-sqrt(5) + 5))**2) + 1 + raises(ZeroDivisionError, lambda: minimal_polynomial(ex, x)) + + ex = sqrt(1 + 2**Rational(1,3)) + sqrt(1 + 2**Rational(1,4)) + sqrt(2) + mp = minimal_polynomial(ex, x) + assert degree(mp) == 48 and mp.subs({x:0}) == -16630256576 + def test_primitive_element(): assert primitive_element([sqrt(2)], x) == (x**2 - 2, [1]) - assert primitive_element([sqrt(2), sqrt(3)], x) == (x**4 - 10*x**2 + 1, [1, 1]) + assert primitive_element( + [sqrt(2), sqrt(3)], x) == (x**4 - 10*x**2 + 1, [1, 1]) assert primitive_element([sqrt(2)], x, polys=True) == (Poly(x**2 - 2), [1]) - assert primitive_element([sqrt(2), sqrt(3)], x, polys=True) == (Poly(x**4 - 10*x**2 + 1), [1, 1]) + assert primitive_element([sqrt( + 2), sqrt(3)], x, polys=True) == (Poly(x**4 - 10*x**2 + 1), [1, 1]) - assert primitive_element([sqrt(2)], x, ex=True) == (x**2 - 2, [1], [[1, 0]]) + assert primitive_element( + [sqrt(2)], x, ex=True) == (x**2 - 2, [1], [[1, 0]]) assert primitive_element([sqrt(2), sqrt(3)], x, ex=True) == \ - (x**4 - 10*x**2 + 1, [1, 1], [[Q(1,2), 0, -Q(9,2), 0], [-Q(1,2), 0, Q(11,2), 0]]) + (x**4 - 10*x**2 + 1, [1, 1], [[Q(1, 2), 0, -Q(9, 2), 0], [- + Q(1, 2), 0, Q(11, 2), 0]]) - assert primitive_element([sqrt(2)], x, ex=True, polys=True) == (Poly(x**2 - 2), [1], [[1, 0]]) + assert primitive_element( + [sqrt(2)], x, ex=True, polys=True) == (Poly(x**2 - 2), [1], [[1, 0]]) assert primitive_element([sqrt(2), sqrt(3)], x, ex=True, polys=True) == \ - (Poly(x**4 - 10*x**2 + 1), [1, 1], [[Q(1,2), 0, -Q(9,2), 0], [-Q(1,2), 0, Q(11,2), 0]]) + (Poly(x**4 - 10*x**2 + 1), [1, 1], [[Q(1, 2), 0, -Q(9, 2), + 0], [-Q(1, 2), 0, Q(11, 2), 0]]) assert primitive_element([sqrt(2)], polys=True) == (Poly(x**2 - 2), [1]) raises(ValueError, lambda: primitive_element([], x, ex=False)) raises(ValueError, lambda: primitive_element([], x, ex=True)) + def test_field_isomorphism_pslq(): a = AlgebraicNumber(I) b = AlgebraicNumber(I*sqrt(3)) @@ -123,42 +278,48 @@ a = AlgebraicNumber(sqrt(2)) b = AlgebraicNumber(sqrt(3)) c = AlgebraicNumber(sqrt(7)) - d = AlgebraicNumber(sqrt(2)+sqrt(3)) - e = AlgebraicNumber(sqrt(2)+sqrt(3)+sqrt(7)) + d = AlgebraicNumber(sqrt(2) + sqrt(3)) + e = AlgebraicNumber(sqrt(2) + sqrt(3) + sqrt(7)) assert field_isomorphism_pslq(a, a) == [1, 0] - assert field_isomorphism_pslq(a, b) == None - assert field_isomorphism_pslq(a, c) == None - assert field_isomorphism_pslq(a, d) == [Q(1,2), 0, -Q(9,2), 0] - assert field_isomorphism_pslq(a, e) == [Q(1,80), 0, -Q(1,2), 0, Q(59,20), 0] + assert field_isomorphism_pslq(a, b) is None + assert field_isomorphism_pslq(a, c) is None + assert field_isomorphism_pslq(a, d) == [Q(1, 2), 0, -Q(9, 2), 0] + assert field_isomorphism_pslq( + a, e) == [Q(1, 80), 0, -Q(1, 2), 0, Q(59, 20), 0] - assert field_isomorphism_pslq(b, a) == None + assert field_isomorphism_pslq(b, a) is None assert field_isomorphism_pslq(b, b) == [1, 0] - assert field_isomorphism_pslq(b, c) == None - assert field_isomorphism_pslq(b, d) == [-Q(1,2), 0, Q(11,2), 0] - assert field_isomorphism_pslq(b, e) == [-Q(3,640), 0, Q(67,320), 0, -Q(297,160), 0, Q(313,80), 0] + assert field_isomorphism_pslq(b, c) is None + assert field_isomorphism_pslq(b, d) == [-Q(1, 2), 0, Q(11, 2), 0] + assert field_isomorphism_pslq(b, e) == [-Q( + 3, 640), 0, Q(67, 320), 0, -Q(297, 160), 0, Q(313, 80), 0] - assert field_isomorphism_pslq(c, a) == None - assert field_isomorphism_pslq(c, b) == None + assert field_isomorphism_pslq(c, a) is None + assert field_isomorphism_pslq(c, b) is None assert field_isomorphism_pslq(c, c) == [1, 0] - assert field_isomorphism_pslq(c, d) == None - assert field_isomorphism_pslq(c, e) == [Q(3,640), 0, -Q(71,320), 0, Q(377,160), 0, -Q(469,80), 0] - - assert field_isomorphism_pslq(d, a) == None - assert field_isomorphism_pslq(d, b) == None - assert field_isomorphism_pslq(d, c) == None + assert field_isomorphism_pslq(c, d) is None + assert field_isomorphism_pslq(c, e) == [Q( + 3, 640), 0, -Q(71, 320), 0, Q(377, 160), 0, -Q(469, 80), 0] + + assert field_isomorphism_pslq(d, a) is None + assert field_isomorphism_pslq(d, b) is None + assert field_isomorphism_pslq(d, c) is None assert field_isomorphism_pslq(d, d) == [1, 0] - assert field_isomorphism_pslq(d, e) == [-Q(3,640), 0, Q(71,320), 0, -Q(377,160), 0, Q(549,80), 0] + assert field_isomorphism_pslq(d, e) == [-Q( + 3, 640), 0, Q(71, 320), 0, -Q(377, 160), 0, Q(549, 80), 0] - assert field_isomorphism_pslq(e, a) == None - assert field_isomorphism_pslq(e, b) == None - assert field_isomorphism_pslq(e, c) == None - assert field_isomorphism_pslq(e, d) == None + assert field_isomorphism_pslq(e, a) is None + assert field_isomorphism_pslq(e, b) is None + assert field_isomorphism_pslq(e, c) is None + assert field_isomorphism_pslq(e, d) is None assert field_isomorphism_pslq(e, e) == [1, 0] - f = AlgebraicNumber(3*sqrt(2)+8*sqrt(7)-5) + f = AlgebraicNumber(3*sqrt(2) + 8*sqrt(7) - 5) + + assert field_isomorphism_pslq( + f, e) == [Q(3, 80), 0, -Q(139, 80), 0, Q(347, 20), 0, -Q(761, 20), -5] - assert field_isomorphism_pslq(f, e) == [Q(3,80), 0, -Q(139,80), 0, Q(347,20), 0, -Q(761,20), -5] def test_field_isomorphism(): assert field_isomorphism(3, sqrt(2)) == [3] @@ -166,20 +327,24 @@ assert field_isomorphism( I*sqrt(3), I*sqrt(3)/2) == [ 2, 0] assert field_isomorphism(-I*sqrt(3), I*sqrt(3)/2) == [-2, 0] - assert field_isomorphism( I*sqrt(3),-I*sqrt(3)/2) == [-2, 0] - assert field_isomorphism(-I*sqrt(3),-I*sqrt(3)/2) == [ 2, 0] + assert field_isomorphism( I*sqrt(3), -I*sqrt(3)/2) == [-2, 0] + assert field_isomorphism(-I*sqrt(3), -I*sqrt(3)/2) == [ 2, 0] assert field_isomorphism( 2*I*sqrt(3)/7, 5*I*sqrt(3)/3) == [ S(6)/35, 0] assert field_isomorphism(-2*I*sqrt(3)/7, 5*I*sqrt(3)/3) == [-S(6)/35, 0] - assert field_isomorphism( 2*I*sqrt(3)/7,-5*I*sqrt(3)/3) == [-S(6)/35, 0] - assert field_isomorphism(-2*I*sqrt(3)/7,-5*I*sqrt(3)/3) == [ S(6)/35, 0] + assert field_isomorphism( 2*I*sqrt(3)/7, -5*I*sqrt(3)/3) == [-S(6)/35, 0] + assert field_isomorphism(-2*I*sqrt(3)/7, -5*I*sqrt(3)/3) == [ S(6)/35, 0] - assert field_isomorphism( 2*I*sqrt(3)/7+27, 5*I*sqrt(3)/3) == [ S(6)/35, 27] - assert field_isomorphism(-2*I*sqrt(3)/7+27, 5*I*sqrt(3)/3) == [-S(6)/35, 27] - - assert field_isomorphism( 2*I*sqrt(3)/7+27,-5*I*sqrt(3)/3) == [-S(6)/35, 27] - assert field_isomorphism(-2*I*sqrt(3)/7+27,-5*I*sqrt(3)/3) == [ S(6)/35, 27] + assert field_isomorphism( + 2*I*sqrt(3)/7 + 27, 5*I*sqrt(3)/3) == [ S(6)/35, 27] + assert field_isomorphism( + -2*I*sqrt(3)/7 + 27, 5*I*sqrt(3)/3) == [-S(6)/35, 27] + + assert field_isomorphism( + 2*I*sqrt(3)/7 + 27, -5*I*sqrt(3)/3) == [-S(6)/35, 27] + assert field_isomorphism( + -2*I*sqrt(3)/7 + 27, -5*I*sqrt(3)/3) == [ S(6)/35, 27] p = AlgebraicNumber( sqrt(2) + sqrt(3)) q = AlgebraicNumber(-sqrt(2) + sqrt(3)) @@ -187,14 +352,14 @@ s = AlgebraicNumber(-sqrt(2) - sqrt(3)) pos_coeffs = [ S(1)/2, S(0), -S(9)/2, S(0)] - neg_coeffs = [-S(1)/2, S(0), S(9)/2, S(0)] + neg_coeffs = [-S(1)/2, S(0), S(9)/2, S(0)] a = AlgebraicNumber(sqrt(2)) - assert is_isomorphism_possible(a, p) == True - assert is_isomorphism_possible(a, q) == True - assert is_isomorphism_possible(a, r) == True - assert is_isomorphism_possible(a, s) == True + assert is_isomorphism_possible(a, p) is True + assert is_isomorphism_possible(a, q) is True + assert is_isomorphism_possible(a, r) is True + assert is_isomorphism_possible(a, s) is True assert field_isomorphism(a, p, fast=True) == pos_coeffs assert field_isomorphism(a, q, fast=True) == neg_coeffs @@ -208,10 +373,10 @@ a = AlgebraicNumber(-sqrt(2)) - assert is_isomorphism_possible(a, p) == True - assert is_isomorphism_possible(a, q) == True - assert is_isomorphism_possible(a, r) == True - assert is_isomorphism_possible(a, s) == True + assert is_isomorphism_possible(a, p) is True + assert is_isomorphism_possible(a, q) is True + assert is_isomorphism_possible(a, r) is True + assert is_isomorphism_possible(a, s) is True assert field_isomorphism(a, p, fast=True) == neg_coeffs assert field_isomorphism(a, q, fast=True) == pos_coeffs @@ -224,14 +389,14 @@ assert field_isomorphism(a, s, fast=False) == pos_coeffs pos_coeffs = [ S(1)/2, S(0), -S(11)/2, S(0)] - neg_coeffs = [-S(1)/2, S(0), S(11)/2, S(0)] + neg_coeffs = [-S(1)/2, S(0), S(11)/2, S(0)] a = AlgebraicNumber(sqrt(3)) - assert is_isomorphism_possible(a, p) == True - assert is_isomorphism_possible(a, q) == True - assert is_isomorphism_possible(a, r) == True - assert is_isomorphism_possible(a, s) == True + assert is_isomorphism_possible(a, p) is True + assert is_isomorphism_possible(a, q) is True + assert is_isomorphism_possible(a, r) is True + assert is_isomorphism_possible(a, s) is True assert field_isomorphism(a, p, fast=True) == neg_coeffs assert field_isomorphism(a, q, fast=True) == neg_coeffs @@ -245,10 +410,10 @@ a = AlgebraicNumber(-sqrt(3)) - assert is_isomorphism_possible(a, p) == True - assert is_isomorphism_possible(a, q) == True - assert is_isomorphism_possible(a, r) == True - assert is_isomorphism_possible(a, s) == True + assert is_isomorphism_possible(a, p) is True + assert is_isomorphism_possible(a, q) is True + assert is_isomorphism_possible(a, r) is True + assert is_isomorphism_possible(a, s) is True assert field_isomorphism(a, p, fast=True) == pos_coeffs assert field_isomorphism(a, q, fast=True) == pos_coeffs @@ -261,14 +426,14 @@ assert field_isomorphism(a, s, fast=False) == neg_coeffs pos_coeffs = [ S(3)/2, S(0), -S(33)/2, -S(8)] - neg_coeffs = [-S(3)/2, S(0), S(33)/2, -S(8)] + neg_coeffs = [-S(3)/2, S(0), S(33)/2, -S(8)] - a = AlgebraicNumber(3*sqrt(3)-8) + a = AlgebraicNumber(3*sqrt(3) - 8) - assert is_isomorphism_possible(a, p) == True - assert is_isomorphism_possible(a, q) == True - assert is_isomorphism_possible(a, r) == True - assert is_isomorphism_possible(a, s) == True + assert is_isomorphism_possible(a, p) is True + assert is_isomorphism_possible(a, q) is True + assert is_isomorphism_possible(a, r) is True + assert is_isomorphism_possible(a, s) is True assert field_isomorphism(a, p, fast=True) == neg_coeffs assert field_isomorphism(a, q, fast=True) == neg_coeffs @@ -280,17 +445,17 @@ assert field_isomorphism(a, r, fast=False) == pos_coeffs assert field_isomorphism(a, s, fast=False) == pos_coeffs - a = AlgebraicNumber(3*sqrt(2)+2*sqrt(3)+1) + a = AlgebraicNumber(3*sqrt(2) + 2*sqrt(3) + 1) - pos_1_coeffs = [ S(1)/2, S(0), -S(5)/2, S(1)] - neg_5_coeffs = [-S(5)/2, S(0), S(49)/2, S(1)] + pos_1_coeffs = [ S(1)/2, S(0), -S(5)/2, S(1)] + neg_5_coeffs = [-S(5)/2, S(0), S(49)/2, S(1)] pos_5_coeffs = [ S(5)/2, S(0), -S(49)/2, S(1)] - neg_1_coeffs = [-S(1)/2, S(0), S(5)/2, S(1)] + neg_1_coeffs = [-S(1)/2, S(0), S(5)/2, S(1)] - assert is_isomorphism_possible(a, p) == True - assert is_isomorphism_possible(a, q) == True - assert is_isomorphism_possible(a, r) == True - assert is_isomorphism_possible(a, s) == True + assert is_isomorphism_possible(a, p) is True + assert is_isomorphism_possible(a, q) is True + assert is_isomorphism_possible(a, r) is True + assert is_isomorphism_possible(a, s) is True assert field_isomorphism(a, p, fast=True) == pos_1_coeffs assert field_isomorphism(a, q, fast=True) == neg_5_coeffs @@ -306,10 +471,10 @@ b = AlgebraicNumber(sqrt(3)) c = AlgebraicNumber(sqrt(7)) - assert is_isomorphism_possible(a, b) == True - assert is_isomorphism_possible(b, a) == True + assert is_isomorphism_possible(a, b) is True + assert is_isomorphism_possible(b, a) is True - assert is_isomorphism_possible(c, p) == False + assert is_isomorphism_possible(c, p) is False assert field_isomorphism(sqrt(2), sqrt(3), fast=True) is None assert field_isomorphism(sqrt(3), sqrt(2), fast=True) is None @@ -317,92 +482,96 @@ assert field_isomorphism(sqrt(2), sqrt(3), fast=False) is None assert field_isomorphism(sqrt(3), sqrt(2), fast=False) is None + def test_to_number_field(): assert to_number_field(sqrt(2)) == AlgebraicNumber(sqrt(2)) - assert to_number_field([sqrt(2), sqrt(3)]) == AlgebraicNumber(sqrt(2)+sqrt(3)) + assert to_number_field( + [sqrt(2), sqrt(3)]) == AlgebraicNumber(sqrt(2) + sqrt(3)) - a = AlgebraicNumber(sqrt(2)+sqrt(3), [S(1)/2, S(0), -S(9)/2, S(0)]) + a = AlgebraicNumber(sqrt(2) + sqrt(3), [S(1)/2, S(0), -S(9)/2, S(0)]) - assert to_number_field(sqrt(2), sqrt(2)+sqrt(3)) == a - assert to_number_field(sqrt(2), AlgebraicNumber(sqrt(2)+sqrt(3))) == a + assert to_number_field(sqrt(2), sqrt(2) + sqrt(3)) == a + assert to_number_field(sqrt(2), AlgebraicNumber(sqrt(2) + sqrt(3))) == a raises(IsomorphismFailed, lambda: to_number_field(sqrt(2), sqrt(3))) + def test_AlgebraicNumber(): minpoly, root = x**2 - 2, sqrt(2) a = AlgebraicNumber(root, gen=x) - assert a.rep == DMP([QQ(1),QQ(0)], QQ) + assert a.rep == DMP([QQ(1), QQ(0)], QQ) assert a.root == root assert a.alias is None assert a.minpoly == minpoly - assert a.is_aliased == False + assert a.is_aliased is False assert a.coeffs() == [S(1), S(0)] assert a.native_coeffs() == [QQ(1), QQ(0)] a = AlgebraicNumber(root, gen=x, alias='y') - assert a.rep == DMP([QQ(1),QQ(0)], QQ) + assert a.rep == DMP([QQ(1), QQ(0)], QQ) assert a.root == root assert a.alias == Symbol('y') assert a.minpoly == minpoly - assert a.is_aliased == True + assert a.is_aliased is True a = AlgebraicNumber(root, gen=x, alias=Symbol('y')) - assert a.rep == DMP([QQ(1),QQ(0)], QQ) + assert a.rep == DMP([QQ(1), QQ(0)], QQ) assert a.root == root assert a.alias == Symbol('y') assert a.minpoly == minpoly - assert a.is_aliased == True + assert a.is_aliased is True assert AlgebraicNumber(sqrt(2), []).rep == DMP([], QQ) assert AlgebraicNumber(sqrt(2), [8]).rep == DMP([QQ(8)], QQ) - assert AlgebraicNumber(sqrt(2), [S(8)/3]).rep == DMP([QQ(8,3)], QQ) + assert AlgebraicNumber(sqrt(2), [S(8)/3]).rep == DMP([QQ(8, 3)], QQ) - assert AlgebraicNumber(sqrt(2), [7, 3]).rep == DMP([QQ(7),QQ(3)], QQ) - assert AlgebraicNumber(sqrt(2), [S(7)/9, S(3)/2]).rep == DMP([QQ(7,9),QQ(3,2)], QQ) + assert AlgebraicNumber(sqrt(2), [7, 3]).rep == DMP([QQ(7), QQ(3)], QQ) + assert AlgebraicNumber( + sqrt(2), [S(7)/9, S(3)/2]).rep == DMP([QQ(7, 9), QQ(3, 2)], QQ) - assert AlgebraicNumber(sqrt(2), [1, 2, 3]).rep == DMP([QQ(2),QQ(5)], QQ) + assert AlgebraicNumber(sqrt(2), [1, 2, 3]).rep == DMP([QQ(2), QQ(5)], QQ) - a = AlgebraicNumber(AlgebraicNumber(root, gen=x), [1,2]) + a = AlgebraicNumber(AlgebraicNumber(root, gen=x), [1, 2]) - assert a.rep == DMP([QQ(1),QQ(2)], QQ) + assert a.rep == DMP([QQ(1), QQ(2)], QQ) assert a.root == root assert a.alias is None assert a.minpoly == minpoly - assert a.is_aliased == False + assert a.is_aliased is False assert a.coeffs() == [S(1), S(2)] assert a.native_coeffs() == [QQ(1), QQ(2)] - a = AlgebraicNumber((minpoly, root), [1,2]) + a = AlgebraicNumber((minpoly, root), [1, 2]) - assert a.rep == DMP([QQ(1),QQ(2)], QQ) + assert a.rep == DMP([QQ(1), QQ(2)], QQ) assert a.root == root assert a.alias is None assert a.minpoly == minpoly - assert a.is_aliased == False + assert a.is_aliased is False - a = AlgebraicNumber((Poly(minpoly), root), [1,2]) + a = AlgebraicNumber((Poly(minpoly), root), [1, 2]) - assert a.rep == DMP([QQ(1),QQ(2)], QQ) + assert a.rep == DMP([QQ(1), QQ(2)], QQ) assert a.root == root assert a.alias is None assert a.minpoly == minpoly - assert a.is_aliased == False + assert a.is_aliased is False - assert AlgebraicNumber( sqrt(3)).rep == DMP([ QQ(1),QQ(0)], QQ) - assert AlgebraicNumber(-sqrt(3)).rep == DMP([-QQ(1),QQ(0)], QQ) + assert AlgebraicNumber( sqrt(3)).rep == DMP([ QQ(1), QQ(0)], QQ) + assert AlgebraicNumber(-sqrt(3)).rep == DMP([-QQ(1), QQ(0)], QQ) a = AlgebraicNumber(sqrt(2)) b = AlgebraicNumber(sqrt(2)) @@ -415,38 +584,38 @@ assert a == b assert a == c - a = AlgebraicNumber(sqrt(2), [1,2]) - b = AlgebraicNumber(sqrt(2), [1,3]) + a = AlgebraicNumber(sqrt(2), [1, 2]) + b = AlgebraicNumber(sqrt(2), [1, 3]) - assert a != b and a != sqrt(2)+3 + assert a != b and a != sqrt(2) + 3 - assert (a == x) == False and (a != x) == True + assert (a == x) is False and (a != x) is True - a = AlgebraicNumber(sqrt(2), [1,0]) - b = AlgebraicNumber(sqrt(2), [1,0], alias=y) + a = AlgebraicNumber(sqrt(2), [1, 0]) + b = AlgebraicNumber(sqrt(2), [1, 0], alias=y) assert a.as_poly(x) == Poly(x) - assert b.as_poly() == Poly(y) + assert b.as_poly() == Poly(y) - assert a.as_expr() == sqrt(2) + assert a.as_expr() == sqrt(2) assert a.as_expr(x) == x - assert b.as_expr() == sqrt(2) + assert b.as_expr() == sqrt(2) assert b.as_expr(x) == x - a = AlgebraicNumber(sqrt(2), [2,3]) - b = AlgebraicNumber(sqrt(2), [2,3], alias=y) + a = AlgebraicNumber(sqrt(2), [2, 3]) + b = AlgebraicNumber(sqrt(2), [2, 3], alias=y) p = a.as_poly() - assert p == Poly(2*p.gen+3) + assert p == Poly(2*p.gen + 3) - assert a.as_poly(x) == Poly(2*x+3) - assert b.as_poly() == Poly(2*y+3) + assert a.as_poly(x) == Poly(2*x + 3) + assert b.as_poly() == Poly(2*y + 3) - assert a.as_expr() == 2*sqrt(2)+3 - assert a.as_expr(x) == 2*x+3 - assert b.as_expr() == 2*sqrt(2)+3 - assert b.as_expr(x) == 2*x+3 + assert a.as_expr() == 2*sqrt(2) + 3 + assert a.as_expr(x) == 2*x + 3 + assert b.as_expr() == 2*sqrt(2) + 3 + assert b.as_expr(x) == 2*x + 3 a = AlgebraicNumber(sqrt(2)) b = to_number_field(sqrt(2)) @@ -457,36 +626,38 @@ a = AlgebraicNumber(sqrt(2), [1, 2, 3]) assert a.args == (sqrt(2), Tuple(1, 2, 3)) + def test_to_algebraic_integer(): a = AlgebraicNumber(sqrt(3), gen=x).to_algebraic_integer() assert a.minpoly == x**2 - 3 - assert a.root == sqrt(3) - assert a.rep == DMP([QQ(1),QQ(0)], QQ) + assert a.root == sqrt(3) + assert a.rep == DMP([QQ(1), QQ(0)], QQ) a = AlgebraicNumber(2*sqrt(3), gen=x).to_algebraic_integer() - assert a.minpoly == x**2 - 12 - assert a.root == 2*sqrt(3) - assert a.rep == DMP([QQ(1),QQ(0)], QQ) + assert a.root == 2*sqrt(3) + assert a.rep == DMP([QQ(1), QQ(0)], QQ) a = AlgebraicNumber(sqrt(3)/2, gen=x).to_algebraic_integer() assert a.minpoly == x**2 - 12 - assert a.root == 2*sqrt(3) - assert a.rep == DMP([QQ(1),QQ(0)], QQ) + assert a.root == 2*sqrt(3) + assert a.rep == DMP([QQ(1), QQ(0)], QQ) a = AlgebraicNumber(sqrt(3)/2, [S(7)/19, 3], gen=x).to_algebraic_integer() assert a.minpoly == x**2 - 12 - assert a.root == 2*sqrt(3) - assert a.rep == DMP([QQ(7,19),QQ(3)], QQ) + assert a.root == 2*sqrt(3) + assert a.rep == DMP([QQ(7, 19), QQ(3)], QQ) + def test_IntervalPrinter(): ip = IntervalPrinter() assert ip.doprint(x**Q(1, 3)) == "x**(mpi('1/3'))" assert ip.doprint(sqrt(x)) == "x**(mpi('1/2'))" + def test_isolate(): assert isolate(1) == (1, 1) assert isolate(S(1)/2) == (S(1)/2, S(1)/2) diff -Nru python3-sympy-0.7.2/sympy/polys/tests/test_orthopolys.py python3-sympy-0.7.3/sympy/polys/tests/test_orthopolys.py --- python3-sympy-0.7.2/sympy/polys/tests/test_orthopolys.py 2012-10-17 03:02:22.000000000 +0000 +++ python3-sympy-0.7.3/sympy/polys/tests/test_orthopolys.py 2013-07-13 17:53:32.000000000 +0000 @@ -15,31 +15,38 @@ from sympy.abc import x, a, b + def test_jacobi_poly(): raises(ValueError, lambda: jacobi_poly(-1, a, b, x)) - assert jacobi_poly(1, a, b, x, polys=True) == Poly((a/2 + b/2 + 1)*x + a/2 - b/2, x, domain='ZZ(a,b)') + assert jacobi_poly(1, a, b, x, polys=True) == Poly( + (a/2 + b/2 + 1)*x + a/2 - b/2, x, domain='ZZ(a,b)') assert jacobi_poly(0, a, b, x) == 1 assert jacobi_poly(1, a, b, x) == a/2 - b/2 + x*(a/2 + b/2 + 1) assert jacobi_poly(2, a, b, x) == (a**2/8 - a*b/4 - a/8 + b**2/8 - b/8 + x**2*(a**2/8 + a*b/4 + 7*a/8 + b**2/8 + 7*b/8 + S(3)/2) + x*(a**2/4 + 3*a/4 - b**2/4 - 3*b/4) - S(1)/2) - assert jacobi_poly(1, a, b, polys=True) == Poly((a/2 + b/2 + 1)*x + a/2 - b/2, x, domain='ZZ(a,b)') + assert jacobi_poly(1, a, b, polys=True) == Poly( + (a/2 + b/2 + 1)*x + a/2 - b/2, x, domain='ZZ(a,b)') + def test_gegenbauer_poly(): raises(ValueError, lambda: gegenbauer_poly(-1, a, x)) - assert gegenbauer_poly(1, a, x, polys=True) == Poly(2*a*x, x, domain='ZZ(a)') + assert gegenbauer_poly( + 1, a, x, polys=True) == Poly(2*a*x, x, domain='ZZ(a)') assert gegenbauer_poly(0, a, x) == 1 assert gegenbauer_poly(1, a, x) == 2*a*x assert gegenbauer_poly(2, a, x) == -a + x**2*(2*a**2 + 2*a) - assert gegenbauer_poly(3, a, x) == x**3*(4*a**3/3 + 4*a**2 + 8*a/3) + x*(-2*a**2 - 2*a) + assert gegenbauer_poly( + 3, a, x) == x**3*(4*a**3/3 + 4*a**2 + 8*a/3) + x*(-2*a**2 - 2*a) assert gegenbauer_poly(1, S.Half).dummy_eq(x) assert gegenbauer_poly(1, a, polys=True) == Poly(2*a*x, x, domain='ZZ(a)') + def test_chebyshevt_poly(): raises(ValueError, lambda: chebyshevt_poly(-1, x)) @@ -56,6 +63,7 @@ assert chebyshevt_poly(1).dummy_eq(x) assert chebyshevt_poly(1, polys=True) == Poly(x) + def test_chebyshevu_poly(): raises(ValueError, lambda: chebyshevu_poly(-1, x)) @@ -72,6 +80,7 @@ assert chebyshevu_poly(1).dummy_eq(2*x) assert chebyshevu_poly(1, polys=True) == Poly(2*x) + def test_hermite_poly(): raises(ValueError, lambda: hermite_poly(-1, x)) @@ -88,6 +97,7 @@ assert hermite_poly(1).dummy_eq(2*x) assert hermite_poly(1, polys=True) == Poly(2*x) + def test_legendre_poly(): raises(ValueError, lambda: legendre_poly(-1, x)) @@ -95,15 +105,17 @@ assert legendre_poly(0, x) == 1 assert legendre_poly(1, x) == x - assert legendre_poly(2, x) == Q(3,2)*x**2 - Q(1,2) - assert legendre_poly(3, x) == Q(5,2)*x**3 - Q(3,2)*x - assert legendre_poly(4, x) == Q(35,8)*x**4 - Q(30,8)*x**2 + Q(3,8) - assert legendre_poly(5, x) == Q(63,8)*x**5 - Q(70,8)*x**3 + Q(15,8)*x - assert legendre_poly(6, x) == Q(231,16)*x**6 - Q(315,16)*x**4 + Q(105,16)*x**2 - Q(5,16) + assert legendre_poly(2, x) == Q(3, 2)*x**2 - Q(1, 2) + assert legendre_poly(3, x) == Q(5, 2)*x**3 - Q(3, 2)*x + assert legendre_poly(4, x) == Q(35, 8)*x**4 - Q(30, 8)*x**2 + Q(3, 8) + assert legendre_poly(5, x) == Q(63, 8)*x**5 - Q(70, 8)*x**3 + Q(15, 8)*x + assert legendre_poly(6, x) == Q( + 231, 16)*x**6 - Q(315, 16)*x**4 + Q(105, 16)*x**2 - Q(5, 16) assert legendre_poly(1).dummy_eq(x) assert legendre_poly(1, polys=True) == Poly(x) + def test_laguerre_poly(): raises(ValueError, lambda: laguerre_poly(-1, x)) @@ -111,16 +123,19 @@ assert laguerre_poly(0, x) == 1 assert laguerre_poly(1, x) == -x + 1 - assert laguerre_poly(2, x) == Q(1,2)*x**2 - Q(4,2)*x + 1 - assert laguerre_poly(3, x) == -Q(1,6)*x**3 + Q(9,6)*x**2 - Q(18,6)*x + 1 - assert laguerre_poly(4, x) == Q(1,24)*x**4 - Q(16,24)*x**3 + Q(72,24)*x**2 - Q(96,24)*x + 1 - assert laguerre_poly(5, x) == -Q(1,120)*x**5 + Q(25,120)*x**4 - Q(200,120)*x**3 + Q(600,120)*x**2 - Q(600,120)*x + 1 - assert laguerre_poly(6, x) == Q(1,720)*x**6 - Q(36,720)*x**5 + Q(450,720)*x**4 - Q(2400,720)*x**3 + Q(5400,720)*x**2 - Q(4320,720)*x + 1 + assert laguerre_poly(2, x) == Q(1, 2)*x**2 - Q(4, 2)*x + 1 + assert laguerre_poly(3, x) == -Q(1, 6)*x**3 + Q(9, 6)*x**2 - Q(18, 6)*x + 1 + assert laguerre_poly(4, x) == Q( + 1, 24)*x**4 - Q(16, 24)*x**3 + Q(72, 24)*x**2 - Q(96, 24)*x + 1 + assert laguerre_poly(5, x) == -Q(1, 120)*x**5 + Q(25, 120)*x**4 - Q( + 200, 120)*x**3 + Q(600, 120)*x**2 - Q(600, 120)*x + 1 + assert laguerre_poly(6, x) == Q(1, 720)*x**6 - Q(36, 720)*x**5 + Q(450, 720)*x**4 - Q(2400, 720)*x**3 + Q(5400, 720)*x**2 - Q(4320, 720)*x + 1 assert laguerre_poly(0, x, a) == 1 assert laguerre_poly(1, x, a) == -x + a + 1 assert laguerre_poly(2, x, a) == x**2/2 + (-a - 2)*x + a**2/2 + 3*a/2 + 1 - assert laguerre_poly(3, x, a) == -x**3/6 + (a/2 + Q(3)/2)*x**2 + (-a**2/2 - 5*a/2 - 3)*x + a**3/6 + a**2 + 11*a/6 + 1 + assert laguerre_poly(3, x, a) == -x**3/6 + (a/2 + Q( + 3)/2)*x**2 + (-a**2/2 - 5*a/2 - 3)*x + a**3/6 + a**2 + 11*a/6 + 1 assert laguerre_poly(1).dummy_eq(-x + 1) assert laguerre_poly(1, polys=True) == Poly(-x + 1) diff -Nru python3-sympy-0.7.2/sympy/polys/tests/test_partfrac.py python3-sympy-0.7.3/sympy/polys/tests/test_partfrac.py --- python3-sympy-0.7.2/sympy/polys/tests/test_partfrac.py 2012-10-17 03:02:22.000000000 +0000 +++ python3-sympy-0.7.3/sympy/polys/tests/test_partfrac.py 2013-07-13 17:53:32.000000000 +0000 @@ -5,12 +5,16 @@ apart_undetermined_coeffs, apart_full_decomposition, apart, + apart_list_full_decomposition, + apart_list, assemble_partfrac_list ) -from sympy import S, Poly, E, pi, I, Matrix, Eq, RootSum, Lambda, factor, together +from sympy import (S, Poly, E, pi, I, Matrix, Eq, RootSum, Lambda, + Symbol, Dummy, factor, together, sqrt, Expr) from sympy.utilities.pytest import raises from sympy.abc import x, y, a, b, c + def test_apart(): assert apart(1) == 1 assert apart(1, x) == 1 @@ -20,39 +24,45 @@ assert apart(f, full=False) == g assert apart(f, full=True) == g - f, g = 1/(x+2)/(x+1), 1/(1 + x) - 1/(2 + x) + f, g = 1/(x + 2)/(x + 1), 1/(1 + x) - 1/(2 + x) assert apart(f, full=False) == g assert apart(f, full=True) == g - f, g = 1/(x+1)/(x+5), -1/(5 + x)/4 + 1/(1 + x)/4 + f, g = 1/(x + 1)/(x + 5), -1/(5 + x)/4 + 1/(1 + x)/4 assert apart(f, full=False) == g assert apart(f, full=True) == g - assert apart((E*x+2)/(x-pi)*(x-1), x) == \ + assert apart((E*x + 2)/(x - pi)*(x - 1), x) == \ 2 - E + E*pi + E*x + (E*pi + 2)*(pi - 1)/(x - pi) assert apart(Eq((x**2 + 1)/(x + 1), x), x) == Eq(x - 1 + 2/(x + 1), x) raises(NotImplementedError, lambda: apart(1/(x + 1)/(y + 2))) + def test_apart_matrix(): M = Matrix(2, 2, lambda i, j: 1/(x + i + 1)/(x + j)) assert apart(M) == Matrix([ - [1/x - 1/(x + 1), (x + 1)**(-2) ], + [1/x - 1/(x + 1), (x + 1)**(-2)], [1/(2*x) - (S(1)/2)/(x + 2), 1/(x + 1) - 1/(x + 2)], ]) + def test_apart_symbolic(): - f = a*x**4 + (2*b + 2*a*c)*x**3 + (4*b*c - a**2 + a*c**2)*x**2 + (-2*a*b + 2*b*c**2)*x - b**2 - g = a**2*x**4 + (2*a*b + 2*c*a**2)*x**3 + (4*a*b*c + b**2 + a**2*c**2)*x**2 + (2*c*b**2 + 2*a*b*c**2)*x + b**2*c**2 + f = a*x**4 + (2*b + 2*a*c)*x**3 + (4*b*c - a**2 + a*c**2)*x**2 + \ + (-2*a*b + 2*b*c**2)*x - b**2 + g = a**2*x**4 + (2*a*b + 2*c*a**2)*x**3 + (4*a*b*c + b**2 + + a**2*c**2)*x**2 + (2*c*b**2 + 2*a*b*c**2)*x + b**2*c**2 assert apart(f/g, x) == 1/a - 1/(x + c)**2 - b**2/(a*(a*x + b)**2) assert apart(1/((x + a)*(x + b)*(x + c)), x) == \ - 1/((a - c)*(b - c)*(c + x)) - 1/((a - b)*(b - c)*(b + x)) + 1/((a - b)*(a - c)*(a + x)) + 1/((a - c)*(b - c)*(c + x)) - 1/((a - b)*(b - c)*(b + x)) + \ + 1/((a - b)*(a - c)*(a + x)) + def test_apart_extension(): f = 2/(x**2 + 1) @@ -65,23 +75,30 @@ assert factor(together(apart(f))) == f + def test_apart_full(): f = 1/(x**2 + 1) assert apart(f, full=False) == f - assert apart(f, full=True) == -RootSum(x**2 + 1, Lambda(a, a/(x - a)), auto=False)/2 + assert apart(f, full=True) == \ + -RootSum(x**2 + 1, Lambda(a, a/(x - a)), auto=False)/2 f = 1/(x**3 + x + 1) assert apart(f, full=False) == f - assert apart(f, full=True) == RootSum(x**3 + x + 1, Lambda(a, (6*a**2/31 - 9*a/31 + S(4)/31)/(x - a)), auto=False) + assert apart(f, full=True) == \ + RootSum(x**3 + x + 1, + Lambda(a, (6*a**2/31 - 9*a/31 + S(4)/31)/(x - a)), auto=False) f = 1/(x**5 + 1) assert apart(f, full=False) == \ - (-S(1)/5)*((x**3 - 2*x**2 + 3*x - 4)/(x**4 - x**3 + x**2 - x + 1)) + (S(1)/5)/(x + 1) + (-S(1)/5)*((x**3 - 2*x**2 + 3*x - 4)/(x**4 - x**3 + x**2 - + x + 1)) + (S(1)/5)/(x + 1) assert apart(f, full=True) == \ - -RootSum(x**4 - x**3 + x**2 - x + 1, Lambda(a, a/(x - a)), auto=False)/5 + (S(1)/5)/(x + 1) + -RootSum(x**4 - x**3 + x**2 - x + 1, + Lambda(a, a/(x - a)), auto=False)/5 + (S(1)/5)/(x + 1) + def test_apart_undetermined_coeffs(): p = Poly(2*x - 3) @@ -92,6 +109,56 @@ p = Poly(1, x, domain='ZZ[a,b]') q = Poly((x + a)*(x + b), x, domain='ZZ[a,b]') - r = 1/((x + b)*(a - b)) + 1/((x + a)*(b - a)) + r = 1/((a - b)*(b + x)) - 1/((a - b)*(a + x)) assert apart_undetermined_coeffs(p, q) == r + + +def test_apart_list(): + from sympy.utilities.iterables import numbered_symbols + + w0, w1, w2 = Symbol("w0"), Symbol("w1"), Symbol("w2") + _a = Dummy("a") + + f = (-2*x - 2*x**2) / (3*x**2 - 6*x) + assert apart_list(f, x, dummies=numbered_symbols("w")) == (-1, + Poly(S(2)/3, x, domain='QQ'), + [(Poly(w0 - 2, w0, domain='ZZ'), Lambda(_a, 2), Lambda(_a, -_a + x), 1)]) + + assert apart_list(2/(x**2-2), x, dummies=numbered_symbols("w")) == (1, + Poly(0, x, domain='ZZ'), + [(Poly(w0**2 - 2, w0, domain='ZZ'), + Lambda(_a, _a/2), + Lambda(_a, -_a + x), 1)]) + + f = 36 / (x**5 - 2*x**4 - 2*x**3 + 4*x**2 + x - 2) + assert apart_list(f, x, dummies=numbered_symbols("w")) == (1, + Poly(0, x, domain='ZZ'), + [(Poly(w0 - 2, w0, domain='ZZ'), Lambda(_a, 4), Lambda(_a, -_a + x), 1), + (Poly(w1**2 - 1, w1, domain='ZZ'), Lambda(_a, -3*_a - 6), Lambda(_a, -_a + x), 2), + (Poly(w2 + 1, w2, domain='ZZ'), Lambda(_a, -4), Lambda(_a, -_a + x), 1)]) + + +def test_assemble_partfrac_list(): + f = 36 / (x**5 - 2*x**4 - 2*x**3 + 4*x**2 + x - 2) + pfd = apart_list(f) + assert assemble_partfrac_list(pfd) == -4/(x + 1) - 3/(x + 1)**2 - 9/(x - 1)**2 + 4/(x - 2) + + a = Dummy("a") + pfd = (1, Poly(0, x, domain='ZZ'), [([sqrt(2),-sqrt(2)], Lambda(a, a/2), Lambda(a, -a + x), 1)]) + assert assemble_partfrac_list(pfd) == -1/(sqrt(2)*(x + sqrt(2))) + 1/(sqrt(2)*(x - sqrt(2))) + + +def test_noncommutative_pseudomultivariate(): + class foo(Expr): + is_commutative=False + e = x/(x + x*y) + c = 1/(1 + y) + assert apart(e + foo(e)) == c + foo(c) + assert apart(e*foo(e)) == c*foo(c) + + +def test_issue_2699(): + assert apart( + 2*x/(x**2 + 1) - (x - 1)/(2*(x**2 + 1)) + 1/(2*(x + 1)) - 2/x) == \ + (3*x + 1)/(x**2 + 1)/2 + 1/(x + 1)/2 - 2/x diff -Nru python3-sympy-0.7.2/sympy/polys/tests/test_polyclasses.py python3-sympy-0.7.3/sympy/polys/tests/test_polyclasses.py --- python3-sympy-0.7.2/sympy/polys/tests/test_polyclasses.py 2012-10-17 03:02:22.000000000 +0000 +++ python3-sympy-0.7.3/sympy/polys/tests/test_polyclasses.py 2013-07-13 17:53:32.000000000 +0000 @@ -7,81 +7,87 @@ ) from sympy.polys.domains import ZZ, QQ -from sympy.polys.specialpolys import f_4 +from sympy.polys.specialpolys import f_polys -from sympy.polys.polyerrors import ( - ExactQuotientFailed, -) +from sympy.polys.polyerrors import ExactQuotientFailed from sympy.utilities.pytest import raises +f_0, f_1, f_2, f_3, f_4, f_5, f_6 = [ f.to_dense() for f in f_polys() ] + def test_DMP___init__(): - f = DMP([[0],[],[0,1,2],[3]], ZZ) + f = DMP([[0], [], [0, 1, 2], [3]], ZZ) - assert f.rep == [[1,2],[3]] + assert f.rep == [[1, 2], [3]] assert f.dom == ZZ assert f.lev == 1 - f = DMP([[1,2],[3]], ZZ, 1) + f = DMP([[1, 2], [3]], ZZ, 1) - assert f.rep == [[1,2],[3]] + assert f.rep == [[1, 2], [3]] assert f.dom == ZZ assert f.lev == 1 - f = DMP({(1,1): 1, (0,0): 2}, ZZ, 1) + f = DMP({(1, 1): 1, (0, 0): 2}, ZZ, 1) - assert f.rep == [[1,0],[2]] + assert f.rep == [[1, 0], [2]] assert f.dom == ZZ assert f.lev == 1 + def test_DMP___eq__(): - assert DMP([[ZZ(1),ZZ(2)],[ZZ(3)]], ZZ) == \ - DMP([[ZZ(1),ZZ(2)],[ZZ(3)]], ZZ) + assert DMP([[ZZ(1), ZZ(2)], [ZZ(3)]], ZZ) == \ + DMP([[ZZ(1), ZZ(2)], [ZZ(3)]], ZZ) - assert DMP([[ZZ(1),ZZ(2)],[ZZ(3)]], ZZ) == \ - DMP([[QQ(1),QQ(2)],[QQ(3)]], QQ) - assert DMP([[QQ(1),QQ(2)],[QQ(3)]], QQ) == \ - DMP([[ZZ(1),ZZ(2)],[ZZ(3)]], ZZ) + assert DMP([[ZZ(1), ZZ(2)], [ZZ(3)]], ZZ) == \ + DMP([[QQ(1), QQ(2)], [QQ(3)]], QQ) + assert DMP([[QQ(1), QQ(2)], [QQ(3)]], QQ) == \ + DMP([[ZZ(1), ZZ(2)], [ZZ(3)]], ZZ) assert DMP([[[ZZ(1)]]], ZZ) != DMP([[ZZ(1)]], ZZ) assert DMP([[ZZ(1)]], ZZ) != DMP([[[ZZ(1)]]], ZZ) + def test_DMP___bool__(): - assert bool(DMP([[]], ZZ)) == False - assert bool(DMP([[1]], ZZ)) == True + assert bool(DMP([[]], ZZ)) is False + assert bool(DMP([[1]], ZZ)) is True + def test_DMP_to_dict(): - f = DMP([[3],[],[2],[],[8]], ZZ) + f = DMP([[3], [], [2], [], [8]], ZZ) assert f.to_dict() == \ {(4, 0): 3, (2, 0): 2, (0, 0): 8} assert f.to_sympy_dict() == \ - {(4, 0): ZZ.to_sympy(3), (2, 0): ZZ.to_sympy(2), (0, 0): ZZ.to_sympy(8)} + {(4, 0): ZZ.to_sympy(3), (2, 0): ZZ.to_sympy(2), (0, 0): + ZZ.to_sympy(8)} + def test_DMP_properties(): - assert DMP([[]], ZZ).is_zero == True - assert DMP([[1]], ZZ).is_zero == False + assert DMP([[]], ZZ).is_zero is True + assert DMP([[1]], ZZ).is_zero is False + + assert DMP([[1]], ZZ).is_one is True + assert DMP([[2]], ZZ).is_one is False - assert DMP([[1]], ZZ).is_one == True - assert DMP([[2]], ZZ).is_one == False + assert DMP([[1]], ZZ).is_ground is True + assert DMP([[1], [2], [1]], ZZ).is_ground is False - assert DMP([[1]], ZZ).is_ground == True - assert DMP([[1],[2],[1]], ZZ).is_ground == False + assert DMP([[1], [2, 0], [1, 0]], ZZ).is_sqf is True + assert DMP([[1], [2, 0], [1, 0, 0]], ZZ).is_sqf is False - assert DMP([[1],[2,0],[1,0]], ZZ).is_sqf == True - assert DMP([[1],[2,0],[1,0,0]], ZZ).is_sqf == False + assert DMP([[1, 2], [3]], ZZ).is_monic is True + assert DMP([[2, 2], [3]], ZZ).is_monic is False - assert DMP([[1,2],[3]], ZZ).is_monic == True - assert DMP([[2,2],[3]], ZZ).is_monic == False + assert DMP([[1, 2], [3]], ZZ).is_primitive is True + assert DMP([[2, 4], [6]], ZZ).is_primitive is False - assert DMP([[1,2],[3]], ZZ).is_primitive == True - assert DMP([[2,4],[6]], ZZ).is_primitive == False def test_DMP_arithmetics(): - f = DMP([[2],[2,0]], ZZ) + f = DMP([[2], [2, 0]], ZZ) - assert f.mul_ground(2) == DMP([[4],[4,0]], ZZ) - assert f.quo_ground(2) == DMP([[1],[1,0]], ZZ) + assert f.mul_ground(2) == DMP([[4], [4, 0]], ZZ) + assert f.quo_ground(2) == DMP([[1], [1, 0]], ZZ) raises(ExactQuotientFailed, lambda: f.exquo_ground(3)) @@ -105,9 +111,9 @@ h = DMP([[-10]], ZZ) assert f.sub(g) == h - assert f - g == h + assert f - g == h assert g - f == -h - assert f - 5 == h + assert f - 5 == h assert 5 - f == -h h = DMP([[-25]], ZZ) @@ -126,11 +132,11 @@ raises(TypeError, lambda: f.pow('x')) - f = DMP([[1],[],[1,0,0]], ZZ) - g = DMP([[2],[-2,0]], ZZ) + f = DMP([[1], [], [1, 0, 0]], ZZ) + g = DMP([[2], [-2, 0]], ZZ) - q = DMP([[2],[2,0]], ZZ) - r = DMP([[8,0,0]], ZZ) + q = DMP([[2], [2, 0]], ZZ) + r = DMP([[8, 0, 0]], ZZ) assert f.pdiv(g) == (q, r) assert f.pquo(g) == q @@ -138,11 +144,11 @@ raises(ExactQuotientFailed, lambda: f.pexquo(g)) - f = DMP([[1],[],[1,0,0]], ZZ) - g = DMP([[1],[-1,0]], ZZ) + f = DMP([[1], [], [1, 0, 0]], ZZ) + g = DMP([[1], [-1, 0]], ZZ) - q = DMP([[1],[1,0]], ZZ) - r = DMP([[2,0,0]], ZZ) + q = DMP([[1], [1, 0]], ZZ) + r = DMP([[2, 0, 0]], ZZ) assert f.div(g) == (q, r) assert f.quo(g) == q @@ -154,9 +160,10 @@ raises(ExactQuotientFailed, lambda: f.exquo(g)) + def test_DMP_functionality(): - f = DMP([[1],[2,0],[1,0,0]], ZZ) - g = DMP([[1],[1,0]], ZZ) + f = DMP([[1], [2, 0], [1, 0, 0]], ZZ) + g = DMP([[1], [1, 0]], ZZ) h = DMP([[1]], ZZ) assert f.degree() == 2 @@ -172,15 +179,15 @@ assert f.max_norm() == 2 assert f.l1_norm() == 4 - u = DMP([[2],[2,0]], ZZ) + u = DMP([[2], [2, 0]], ZZ) assert f.diff(m=1, j=0) == u assert f.diff(m=1, j=1) == u raises(TypeError, lambda: f.diff(m='x', j=0)) - u = DMP([1,2,1], ZZ) - v = DMP([1,2,1], ZZ) + u = DMP([1, 2, 1], ZZ) + v = DMP([1, 2, 1], ZZ) assert f.eval(a=1, j=0) == u assert f.eval(a=1, j=1) == v @@ -191,41 +198,41 @@ assert f.gcd(g) == g assert f.lcm(g) == f - u = DMP([[QQ(45),QQ(30),QQ(5)]], QQ) - v = DMP([[QQ(1),QQ(2,3),QQ(1,9)]], QQ) + u = DMP([[QQ(45), QQ(30), QQ(5)]], QQ) + v = DMP([[QQ(1), QQ(2, 3), QQ(1, 9)]], QQ) assert u.monic() == v assert (4*f).content() == ZZ(4) assert (4*f).primitive() == (ZZ(4), f) - f = DMP([[1],[2],[3],[4],[5],[6]], ZZ) + f = DMP([[1], [2], [3], [4], [5], [6]], ZZ) - assert f.trunc(3) == DMP([[1],[-1],[],[1],[-1],[]], ZZ) + assert f.trunc(3) == DMP([[1], [-1], [], [1], [-1], []], ZZ) f = DMP(f_4, ZZ) assert f.sqf_part() == -f assert f.sqf_list() == (ZZ(-1), [(-f, 1)]) - f = DMP([[-1],[],[],[5]], ZZ) - g = DMP([[3,1],[],[]], ZZ) - h = DMP([[45,30,5]], ZZ) + f = DMP([[-1], [], [], [5]], ZZ) + g = DMP([[3, 1], [], []], ZZ) + h = DMP([[45, 30, 5]], ZZ) - r = DMP([675,675,225,25], ZZ) + r = DMP([675, 675, 225, 25], ZZ) assert f.subresultants(g) == [f, g, h] assert f.resultant(g) == r - f = DMP([1,3,9,-13], ZZ) + f = DMP([1, 3, 9, -13], ZZ) assert f.discriminant() == -11664 - f = DMP([QQ(2),QQ(0)], QQ) - g = DMP([QQ(1),QQ(0),QQ(-16)], QQ) + f = DMP([QQ(2), QQ(0)], QQ) + g = DMP([QQ(1), QQ(0), QQ(-16)], QQ) - s = DMP([QQ(1,32),QQ(0)], QQ) - t = DMP([QQ(-1,16)], QQ) + s = DMP([QQ(1, 32), QQ(0)], QQ) + t = DMP([QQ(-1, 16)], QQ) h = DMP([QQ(1)], QQ) assert f.half_gcdex(g) == (s, h) @@ -233,69 +240,72 @@ assert f.invert(g) == s - f = DMP([[1],[2],[3]], QQ) + f = DMP([[1], [2], [3]], QQ) raises(ValueError, lambda: f.half_gcdex(f)) raises(ValueError, lambda: f.gcdex(f)) raises(ValueError, lambda: f.invert(f)) - f = DMP([1,0,20,0,150,0,500,0,625,-2,0,-10,9], ZZ) - g = DMP([1,0,0,-2,9], ZZ) - h = DMP([1,0,5,0], ZZ) + f = DMP([1, 0, 20, 0, 150, 0, 500, 0, 625, -2, 0, -10, 9], ZZ) + g = DMP([1, 0, 0, -2, 9], ZZ) + h = DMP([1, 0, 5, 0], ZZ) assert g.compose(h) == f assert f.decompose() == [g, h] - f = DMP([[1],[2],[3]], QQ) + f = DMP([[1], [2], [3]], QQ) raises(ValueError, lambda: f.decompose()) raises(ValueError, lambda: f.sturm()) + def test_DMP_exclude(): f = [[[[[[[[[[[[[[[[[[[[[[[[[[1]], [[]]]]]]]]]]]]]]]]]]]]]]]]]] - J = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 24, 25] + J = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, + 18, 19, 20, 21, 22, 24, 25] assert DMP(f, ZZ).exclude() == (J, DMP([1, 0], ZZ)) assert DMP([[1], [1, 0]], ZZ).exclude() == ([], DMP([[1], [1, 0]], ZZ)) + def test_DMF__init__(): - f = DMF(([[0],[],[0,1,2],[3]], [[1,2,3]]), ZZ) + f = DMF(([[0], [], [0, 1, 2], [3]], [[1, 2, 3]]), ZZ) - assert f.num == [[1,2],[3]] - assert f.den == [[1,2,3]] + assert f.num == [[1, 2], [3]] + assert f.den == [[1, 2, 3]] assert f.lev == 1 assert f.dom == ZZ - f = DMF(([[1,2],[3]], [[1,2,3]]), ZZ, 1) + f = DMF(([[1, 2], [3]], [[1, 2, 3]]), ZZ, 1) - assert f.num == [[1,2],[3]] - assert f.den == [[1,2,3]] + assert f.num == [[1, 2], [3]] + assert f.den == [[1, 2, 3]] assert f.lev == 1 assert f.dom == ZZ - f = DMF(([[-1],[-2]],[[3],[-4]]), ZZ) + f = DMF(([[-1], [-2]], [[3], [-4]]), ZZ) - assert f.num == [[-1],[-2]] - assert f.den == [[3],[-4]] + assert f.num == [[-1], [-2]] + assert f.den == [[3], [-4]] assert f.lev == 1 assert f.dom == ZZ - f = DMF(([[1],[2]],[[-3],[4]]), ZZ) + f = DMF(([[1], [2]], [[-3], [4]]), ZZ) - assert f.num == [[-1],[-2]] - assert f.den == [[3],[-4]] + assert f.num == [[-1], [-2]] + assert f.den == [[3], [-4]] assert f.lev == 1 assert f.dom == ZZ - f = DMF(([[1],[2]],[[-3],[4]]), ZZ) + f = DMF(([[1], [2]], [[-3], [4]]), ZZ) - assert f.num == [[-1],[-2]] - assert f.den == [[3],[-4]] + assert f.num == [[-1], [-2]] + assert f.den == [[3], [-4]] assert f.lev == 1 assert f.dom == ZZ - f = DMF(([[]],[[-3],[4]]), ZZ) + f = DMF(([[]], [[-3], [4]]), ZZ) assert f.num == [[]] assert f.den == [[1]] @@ -309,103 +319,104 @@ assert f.lev == 1 assert f.dom == ZZ - f = DMF(([[1],[2]]), ZZ) + f = DMF(([[1], [2]]), ZZ) - assert f.num == [[1],[2]] + assert f.num == [[1], [2]] assert f.den == [[1]] assert f.lev == 1 assert f.dom == ZZ - f = DMF([[0],[],[0,1,2],[3]], ZZ) + f = DMF([[0], [], [0, 1, 2], [3]], ZZ) - assert f.num == [[1,2],[3]] + assert f.num == [[1, 2], [3]] assert f.den == [[1]] assert f.lev == 1 assert f.dom == ZZ - f = DMF({(1,1): 1, (0,0): 2}, ZZ, 1) + f = DMF({(1, 1): 1, (0, 0): 2}, ZZ, 1) - assert f.num == [[1,0],[2]] + assert f.num == [[1, 0], [2]] assert f.den == [[1]] assert f.lev == 1 assert f.dom == ZZ - f = DMF(([[QQ(1)],[QQ(2)]], [[-QQ(3)],[QQ(4)]]), QQ) + f = DMF(([[QQ(1)], [QQ(2)]], [[-QQ(3)], [QQ(4)]]), QQ) - assert f.num == [[-QQ(1)],[-QQ(2)]] - assert f.den == [[QQ(3)],[-QQ(4)]] + assert f.num == [[-QQ(1)], [-QQ(2)]] + assert f.den == [[QQ(3)], [-QQ(4)]] assert f.lev == 1 assert f.dom == QQ - f = DMF(([[QQ(1,5)],[QQ(2,5)]], [[-QQ(3,7)],[QQ(4,7)]]), QQ) + f = DMF(([[QQ(1, 5)], [QQ(2, 5)]], [[-QQ(3, 7)], [QQ(4, 7)]]), QQ) - assert f.num == [[-QQ(7)],[-QQ(14)]] - assert f.den == [[QQ(15)],[-QQ(20)]] + assert f.num == [[-QQ(7)], [-QQ(14)]] + assert f.den == [[QQ(15)], [-QQ(20)]] assert f.lev == 1 assert f.dom == QQ raises(ValueError, lambda: DMF(([1], [[1]]), ZZ)) raises(ZeroDivisionError, lambda: DMF(([1], []), ZZ)) -def test_DMF__eq__(): - pass def test_DMF__bool__(): - assert bool(DMF([[]], ZZ)) == False - assert bool(DMF([[1]], ZZ)) == True + assert bool(DMF([[]], ZZ)) is False + assert bool(DMF([[1]], ZZ)) is True + def test_DMF_properties(): - assert DMF([[]], ZZ).is_zero == True - assert DMF([[]], ZZ).is_one == False + assert DMF([[]], ZZ).is_zero is True + assert DMF([[]], ZZ).is_one is False + + assert DMF([[1]], ZZ).is_zero is False + assert DMF([[1]], ZZ).is_one is True - assert DMF([[1]], ZZ).is_zero == False - assert DMF([[1]], ZZ).is_one == True + assert DMF(([[1]], [[2]]), ZZ).is_one is False - assert DMF(([[1]], [[2]]), ZZ).is_one == False def test_DMF_arithmetics(): - f = DMF([[7],[-9]], ZZ) - g = DMF([[-7],[9]], ZZ) + f = DMF([[7], [-9]], ZZ) + g = DMF([[-7], [9]], ZZ) assert f.neg() == -f == g - f = DMF(([[1]], [[1],[]]), ZZ) - g = DMF(([[1]], [[1,0]]), ZZ) + f = DMF(([[1]], [[1], []]), ZZ) + g = DMF(([[1]], [[1, 0]]), ZZ) - h = DMF(([[1],[1,0]], [[1,0],[]]), ZZ) + h = DMF(([[1], [1, 0]], [[1, 0], []]), ZZ) assert f.add(g) == f + g == h assert g.add(f) == g + f == h - h = DMF(([[-1],[1,0]], [[1,0],[]]), ZZ) + h = DMF(([[-1], [1, 0]], [[1, 0], []]), ZZ) assert f.sub(g) == f - g == h - h = DMF(([[1]], [[1,0],[]]), ZZ) + h = DMF(([[1]], [[1, 0], []]), ZZ) assert f.mul(g) == f*g == h assert g.mul(f) == g*f == h - h = DMF(([[1,0]], [[1],[]]), ZZ) + h = DMF(([[1, 0]], [[1], []]), ZZ) assert f.quo(g) == f/g == h - h = DMF(([[1]], [[1],[],[],[]]), ZZ) + h = DMF(([[1]], [[1], [], [], []]), ZZ) assert f.pow(3) == f**3 == h - h = DMF(([[1]], [[1,0,0,0]]), ZZ) + h = DMF(([[1]], [[1, 0, 0, 0]]), ZZ) assert g.pow(3) == g**3 == h + def test_ANP___init__(): - rep = [QQ(1),QQ(1)] - mod = [QQ(1),QQ(0),QQ(1)] + rep = [QQ(1), QQ(1)] + mod = [QQ(1), QQ(0), QQ(1)] f = ANP(rep, mod, QQ) - assert f.rep == [QQ(1),QQ(1)] - assert f.mod == [QQ(1),QQ(0),QQ(1)] + assert f.rep == [QQ(1), QQ(1)] + assert f.mod == [QQ(1), QQ(0), QQ(1)] assert f.dom == QQ rep = {1: QQ(1), 0: QQ(1)} @@ -413,49 +424,53 @@ f = ANP(rep, mod, QQ) - assert f.rep == [QQ(1),QQ(1)] - assert f.mod == [QQ(1),QQ(0),QQ(1)] + assert f.rep == [QQ(1), QQ(1)] + assert f.mod == [QQ(1), QQ(0), QQ(1)] assert f.dom == QQ f = ANP(1, mod, QQ) assert f.rep == [QQ(1)] - assert f.mod == [QQ(1),QQ(0),QQ(1)] + assert f.mod == [QQ(1), QQ(0), QQ(1)] assert f.dom == QQ + def test_ANP___eq__(): - a = ANP([QQ(1), QQ(1)], [QQ(1),QQ(0),QQ(1)], QQ) - b = ANP([QQ(1), QQ(1)], [QQ(1),QQ(0),QQ(2)], QQ) + a = ANP([QQ(1), QQ(1)], [QQ(1), QQ(0), QQ(1)], QQ) + b = ANP([QQ(1), QQ(1)], [QQ(1), QQ(0), QQ(2)], QQ) + + assert (a == a) is True + assert (a != a) is False - assert (a == a) == True - assert (a != a) == False + assert (a == b) is False + assert (a != b) is True - assert (a == b) == False - assert (a != b) == True + b = ANP([QQ(1), QQ(2)], [QQ(1), QQ(0), QQ(1)], QQ) - b = ANP([QQ(1), QQ(2)], [QQ(1),QQ(0),QQ(1)], QQ) + assert (a == b) is False + assert (a != b) is True - assert (a == b) == False - assert (a != b) == True def test_ANP___bool__(): - assert bool(ANP([], [QQ(1),QQ(0),QQ(1)], QQ)) == False - assert bool(ANP([QQ(1)], [QQ(1),QQ(0),QQ(1)], QQ)) == True + assert bool(ANP([], [QQ(1), QQ(0), QQ(1)], QQ)) is False + assert bool(ANP([QQ(1)], [QQ(1), QQ(0), QQ(1)], QQ)) is True + def test_ANP_properties(): - mod = [QQ(1),QQ(0),QQ(1)] + mod = [QQ(1), QQ(0), QQ(1)] + + assert ANP([QQ(0)], mod, QQ).is_zero is True + assert ANP([QQ(1)], mod, QQ).is_zero is False - assert ANP([QQ(0)], mod, QQ).is_zero == True - assert ANP([QQ(1)], mod, QQ).is_zero == False + assert ANP([QQ(1)], mod, QQ).is_one is True + assert ANP([QQ(2)], mod, QQ).is_one is False - assert ANP([QQ(1)], mod, QQ).is_one == True - assert ANP([QQ(2)], mod, QQ).is_one == False def test_ANP_arithmetics(): - mod = [QQ(1),QQ(0),QQ(0),QQ(-2)] + mod = [QQ(1), QQ(0), QQ(0), QQ(-2)] - a = ANP([QQ(2),QQ(-1),QQ(1)], mod, QQ) - b = ANP([QQ(1),QQ(2)], mod, QQ) + a = ANP([QQ(2), QQ(-1), QQ(1)], mod, QQ) + b = ANP([QQ(1), QQ(2)], mod, QQ) c = ANP([QQ(-2), QQ(1), QQ(-1)], mod, QQ) @@ -463,23 +478,23 @@ c = ANP([QQ(2), QQ(0), QQ(3)], mod, QQ) - assert a.add(b) == a+b == c - assert b.add(a) == b+a == c + assert a.add(b) == a + b == c + assert b.add(a) == b + a == c c = ANP([QQ(2), QQ(-2), QQ(-1)], mod, QQ) - assert a.sub(b) == a-b == c + assert a.sub(b) == a - b == c c = ANP([QQ(-2), QQ(2), QQ(1)], mod, QQ) - assert b.sub(a) == b-a == c + assert b.sub(a) == b - a == c c = ANP([QQ(3), QQ(-1), QQ(6)], mod, QQ) assert a.mul(b) == a*b == c assert b.mul(a) == b*a == c - c = ANP([QQ(-1,43), QQ(9,43), QQ(5,43)], mod, QQ) + c = ANP([QQ(-1, 43), QQ(9, 43), QQ(5, 43)], mod, QQ) assert a.pow(0) == a**(0) == ANP(1, mod, QQ) assert a.pow(1) == a**(1) == a @@ -488,6 +503,7 @@ assert a.quo(a) == a.mul(a.pow(-1)) == a*a**(-1) == ANP(1, mod, QQ) + def test_ANP_unify(): mod = [QQ(1), QQ(0), QQ(-2)] @@ -499,12 +515,16 @@ assert a.unify(a)[0] == QQ assert b.unify(b)[0] == ZZ + def test___hash__(): # Issue 2472 # Make sure int vs. long doesn't affect hashing with Python ground types assert DMP([[1, 2], [3]], ZZ) == DMP([[1, 2], [3]], ZZ) assert hash(DMP([[1, 2], [3]], ZZ)) == hash(DMP([[1, 2], [3]], ZZ)) - assert DMF(([[1, 2], [3]], [[1]]), ZZ) == DMF(([[1, 2], [3]], [[1]]), ZZ) - assert hash(DMF(([[1, 2], [3]], [[1]]), ZZ)) == hash(DMF(([[1, 2], [3]], [[1]]), ZZ)) + assert DMF( + ([[1, 2], [3]], [[1]]), ZZ) == DMF(([[1, 2], [3]], [[1]]), ZZ) + assert hash(DMF(([[1, 2], [3]], [[1]]), ZZ)) == hash(DMF(([[1, + 2], [3]], [[1]]), ZZ)) assert ANP([1, 1], [1, 0, 1], ZZ) == ANP([1, 1], [1, 0, 1], ZZ) - assert hash(ANP([1, 1], [1, 0, 1], ZZ)) == hash(ANP([1, 1], [1, 0, 1], ZZ)) + assert hash( + ANP([1, 1], [1, 0, 1], ZZ)) == hash(ANP([1, 1], [1, 0, 1], ZZ)) diff -Nru python3-sympy-0.7.2/sympy/polys/tests/test_polyfuncs.py python3-sympy-0.7.3/sympy/polys/tests/test_polyfuncs.py --- python3-sympy-0.7.2/sympy/polys/tests/test_polyfuncs.py 2012-10-17 03:02:22.000000000 +0000 +++ python3-sympy-0.7.3/sympy/polys/tests/test_polyfuncs.py 2013-07-13 17:53:32.000000000 +0000 @@ -13,6 +13,7 @@ from sympy.abc import a, b, c, d, e, x, y, z + def test_symmetrize(): assert symmetrize(0, x, y, z) == (0, 0) assert symmetrize(1, x, y, z) == (1, 0) @@ -39,7 +40,8 @@ assert symmetrize(x**2 - y**2) == (-2*x*y + (x + y)**2, -2*y**2) assert symmetrize(x**3 + y**2 + a*x**2 + b*y**3, x, y) == \ - (-3*x*y*(x + y) - 2*a*x*y + a*(x + y)**2 + (x + y)**3, y**2*(1 - a) + y**3*(b - 1)) + (-3*x*y*(x + y) - 2*a*x*y + a*(x + y)**2 + (x + y)**3, + y**2*(1 - a) + y**3*(b - 1)) U = [u0, u1, u2] = symbols('u:3') @@ -51,6 +53,7 @@ assert symmetrize([x + y, x - y]) == [(x + y, 0), (x + y, -2*y)] + def test_horner(): assert horner(0) == 0 assert horner(1) == 1 @@ -61,22 +64,29 @@ assert horner(x**2 + x) == (x + 1)*x assert horner(x**2 + x + 1) == (x + 1)*x + 1 - assert horner(9*x**4 + 8*x**3 + 7*x**2 + 6*x + 5) == (((9*x + 8)*x + 7)*x + 6)*x + 5 - assert horner(a*x**4 + b*x**3 + c*x**2 + d*x + e) == (((a*x + b)*x + c)*x + d)*x + e + assert horner( + 9*x**4 + 8*x**3 + 7*x**2 + 6*x + 5) == (((9*x + 8)*x + 7)*x + 6)*x + 5 + assert horner( + a*x**4 + b*x**3 + c*x**2 + d*x + e) == (((a*x + b)*x + c)*x + d)*x + e + + assert horner(4*x**2*y**2 + 2*x**2*y + 2*x*y**2 + x*y, wrt=x) == (( + 4*y + 2)*x*y + (2*y + 1)*y)*x + assert horner(4*x**2*y**2 + 2*x**2*y + 2*x*y**2 + x*y, wrt=y) == (( + 4*x + 2)*y*x + (2*x + 1)*x)*y - assert horner(4*x**2*y**2 + 2*x**2*y + 2*x*y**2 + x*y, wrt=x) == ((4*y + 2)*x*y + (2*y + 1)*y)*x - assert horner(4*x**2*y**2 + 2*x**2*y + 2*x*y**2 + x*y, wrt=y) == ((4*x + 2)*y*x + (2*x + 1)*x)*y def test_interpolate(): - assert interpolate([1,4,9,16], x) == x**2 + assert interpolate([1, 4, 9, 16], x) == x**2 assert interpolate([(1, 1), (2, 4), (3, 9)], x) == x**2 assert interpolate([(1, 2), (2, 5), (3, 10)], x) == 1 + x**2 assert interpolate({1: 2, 2: 5, 3: 10}, x) == 1 + x**2 + def test_viete(): r1, r2 = symbols('r1, r2') - assert viete(a*x**2 + b*x + c, [r1, r2], x) == [(r1 + r2, -b/a), (r1*r2, c/a)] + assert viete( + a*x**2 + b*x + c, [r1, r2], x) == [(r1 + r2, -b/a), (r1*r2, c/a)] raises(ValueError, lambda: viete(1, [], x)) raises(ValueError, lambda: viete(x**2 + 1, [r1])) diff -Nru python3-sympy-0.7.2/sympy/polys/tests/test_polynomialring.py python3-sympy-0.7.3/sympy/polys/tests/test_polynomialring.py --- python3-sympy-0.7.2/sympy/polys/tests/test_polynomialring.py 2012-10-17 03:02:22.000000000 +0000 +++ python3-sympy-0.7.3/sympy/polys/tests/test_polynomialring.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,97 +0,0 @@ -"""Tests for the PolynomialRing classes. """ - -from sympy.polys.domains import QQ, ZZ, PolynomialRing -from sympy.polys.polyerrors import ExactQuotientFailed, CoercionFailed, NotReversible - -from sympy.abc import x, y - -from sympy.utilities.pytest import raises - -def test_build_order(): - R = QQ.poly_ring(x, y, order=(("lex", x), ("ilex", y))) - assert R.order((1, 5)) == ((1,), (-5,)) - -def test_globalring(): - Qxy = QQ.frac_field(x, y) - R = QQ[x, y] - X = R.convert(x) - Y = R.convert(y) - - assert x in R - assert 1/x not in R - assert 1/(1 + x) not in R - assert Y in R - assert X.ring == R - assert X * (Y**2 + 1) == R.convert(x * (y**2 + 1)) - assert X * y == X * Y == R.convert(x * y) == x * Y - assert X + y == X + Y == R.convert(x + y) == x + Y - assert X - y == X - Y == R.convert(x - y) == x - Y - assert X + 1 == R.convert(x + 1) - raises(ExactQuotientFailed, lambda: X/Y) - raises(ExactQuotientFailed, lambda: x/Y) - raises(ExactQuotientFailed, lambda: X/y) - assert X**2 / X == X - - assert R.from_GlobalPolynomialRing(ZZ[x, y].convert(x), ZZ[x, y]) == X - assert R.from_FractionField(Qxy.convert(x), Qxy) == X - assert R.from_FractionField(Qxy.convert(x)/y, Qxy) is None - - assert R._sdm_to_vector(R._vector_to_sdm([X, Y], R.order), 2) == [X, Y] - -def test_localring(): - Qxy = QQ.frac_field(x, y) - R = QQ.poly_ring(x, y, order="ilex") - X = R.convert(x) - Y = R.convert(y) - - assert x in R - assert 1/x not in R - assert 1/(1 + x) in R - assert Y in R - assert X.ring == R - assert X*(Y**2+1)/(1 + X) == R.convert(x*(y**2 + 1)/(1 + x)) - assert X*y == X*Y - raises(ExactQuotientFailed, lambda: X/Y) - raises(ExactQuotientFailed, lambda: x/Y) - raises(ExactQuotientFailed, lambda: X/y) - assert X + y == X + Y == R.convert(x + y) == x + Y - assert X - y == X - Y == R.convert(x - y) == x - Y - assert X + 1 == R.convert(x + 1) - assert X**2 / X == X - - assert R.from_GlobalPolynomialRing(ZZ[x, y].convert(x), ZZ[x, y]) == X - assert R.from_FractionField(Qxy.convert(x), Qxy) == X - raises(CoercionFailed, lambda: R.from_FractionField(Qxy.convert(x)/y, Qxy)) - raises(ExactQuotientFailed, lambda: X/Y) - raises(NotReversible, lambda: X.invert()) - - assert R._sdm_to_vector(R._vector_to_sdm([X/(X + 1), Y/(1 + X*Y)], R.order), - 2) == \ - [X*(1 + X*Y), Y*(1 + X)] - -def test_conversion(): - L = QQ.poly_ring(x, y, order="ilex") - G = QQ[x, y] - - assert L.convert(x) == L.convert(G.convert(x), G) - assert G.convert(x) == G.convert(L.convert(x), L) - raises(CoercionFailed, lambda: G.convert(L.convert(1/(1+x)), L)) - -def test_units(): - R = QQ[x] - assert R.is_unit(R.convert(1)) - assert R.is_unit(R.convert(2)) - assert not R.is_unit(R.convert(x)) - assert not R.is_unit(R.convert(1 + x)) - - R = QQ.poly_ring(x, order='ilex') - assert R.is_unit(R.convert(1)) - assert R.is_unit(R.convert(2)) - assert not R.is_unit(R.convert(x)) - assert R.is_unit(R.convert(1 + x)) - - R = ZZ[x] - assert R.is_unit(R.convert(1)) - assert not R.is_unit(R.convert(2)) - assert not R.is_unit(R.convert(x)) - assert not R.is_unit(R.convert(1 + x)) diff -Nru python3-sympy-0.7.2/sympy/polys/tests/test_polyoptions.py python3-sympy-0.7.3/sympy/polys/tests/test_polyoptions.py --- python3-sympy-0.7.2/sympy/polys/tests/test_polyoptions.py 2012-10-17 03:02:22.000000000 +0000 +++ python3-sympy-0.7.3/sympy/polys/tests/test_polyoptions.py 2013-07-13 17:53:32.000000000 +0000 @@ -15,22 +15,24 @@ from sympy.utilities.pytest import raises from sympy.abc import x, y, z + def test_Options_clone(): opt = Options((x, y, z), {'domain': 'ZZ'}) assert opt.gens == (x, y, z) assert opt.domain == ZZ - assert ('order' in opt) == False + assert ('order' in opt) is False - new_opt = opt.clone({'gens': (x,y), 'order': 'lex'}) + new_opt = opt.clone({'gens': (x, y), 'order': 'lex'}) assert opt.gens == (x, y, z) assert opt.domain == ZZ - assert ('order' in opt) == False + assert ('order' in opt) is False assert new_opt.gens == (x, y) assert new_opt.domain == ZZ - assert ('order' in new_opt) == True + assert ('order' in new_opt) is True + def test_Expand_preprocess(): assert Expand.preprocess(False) is False @@ -41,12 +43,14 @@ raises(OptionError, lambda: Expand.preprocess(x)) + def test_Expand_postprocess(): opt = {'expand': True} Expand.postprocess(opt) assert opt == {'expand': True} + def test_Gens_preprocess(): assert Gens.preprocess((None,)) == () assert Gens.preprocess((x, y, z)) == (x, y, z) @@ -57,12 +61,14 @@ raises(GeneratorsError, lambda: Gens.preprocess((x, x, y))) raises(GeneratorsError, lambda: Gens.preprocess((x, y, a))) + def test_Gens_postprocess(): opt = {'gens': (x, y)} Gens.postprocess(opt) assert opt == {'gens': (x, y)} + def test_Wrt_preprocess(): assert Wrt.preprocess(x) == ['x'] assert Wrt.preprocess('') == [] @@ -78,12 +84,14 @@ raises(OptionError, lambda: Wrt.preprocess(',')) raises(OptionError, lambda: Wrt.preprocess(0)) + def test_Wrt_postprocess(): opt = {'wrt': ['x']} Wrt.postprocess(opt) assert opt == {'wrt': ['x']} + def test_Sort_preprocess(): assert Sort.preprocess([x, y, z]) == ['x', 'y', 'z'] assert Sort.preprocess((x, y, z)) == ['x', 'y', 'z'] @@ -94,21 +102,25 @@ raises(OptionError, lambda: Sort.preprocess(0)) raises(OptionError, lambda: Sort.preprocess(set([x, y, z]))) + def test_Sort_postprocess(): opt = {'sort': 'x > y'} Sort.postprocess(opt) assert opt == {'sort': 'x > y'} + def test_Order_preprocess(): assert Order.preprocess('lex') == lex + def test_Order_postprocess(): opt = {'order': True} Order.postprocess(opt) assert opt == {'order': True} + def test_Field_preprocess(): assert Field.preprocess(False) is False assert Field.preprocess(True) is True @@ -118,12 +130,14 @@ raises(OptionError, lambda: Field.preprocess(x)) + def test_Field_postprocess(): opt = {'field': True} Field.postprocess(opt) assert opt == {'field': True} + def test_Greedy_preprocess(): assert Greedy.preprocess(False) is False assert Greedy.preprocess(True) is True @@ -133,18 +147,20 @@ raises(OptionError, lambda: Greedy.preprocess(x)) + def test_Greedy_postprocess(): opt = {'greedy': True} Greedy.postprocess(opt) assert opt == {'greedy': True} + def test_Domain_preprocess(): assert Domain.preprocess(ZZ) == ZZ assert Domain.preprocess(QQ) == QQ assert Domain.preprocess(EX) == EX assert Domain.preprocess(FF(2)) == FF(2) - assert Domain.preprocess(ZZ[x,y]) == ZZ[x,y] + assert Domain.preprocess(ZZ[x, y]) == ZZ[x, y] assert Domain.preprocess('Z') == ZZ assert Domain.preprocess('Q') == QQ @@ -165,11 +181,11 @@ assert Domain.preprocess('ZZ[x]') == ZZ[x] assert Domain.preprocess('QQ[x]') == QQ[x] - assert Domain.preprocess('Z[x,y]') == ZZ[x,y] - assert Domain.preprocess('Q[x,y]') == QQ[x,y] + assert Domain.preprocess('Z[x,y]') == ZZ[x, y] + assert Domain.preprocess('Q[x,y]') == QQ[x, y] - assert Domain.preprocess('ZZ[x,y]') == ZZ[x,y] - assert Domain.preprocess('QQ[x,y]') == QQ[x,y] + assert Domain.preprocess('ZZ[x,y]') == ZZ[x, y] + assert Domain.preprocess('QQ[x,y]') == QQ[x, y] raises(OptionError, lambda: Domain.preprocess('Z()')) @@ -179,22 +195,30 @@ assert Domain.preprocess('ZZ(x)') == ZZ.frac_field(x) assert Domain.preprocess('QQ(x)') == QQ.frac_field(x) - assert Domain.preprocess('Z(x,y)') == ZZ.frac_field(x,y) - assert Domain.preprocess('Q(x,y)') == QQ.frac_field(x,y) + assert Domain.preprocess('Z(x,y)') == ZZ.frac_field(x, y) + assert Domain.preprocess('Q(x,y)') == QQ.frac_field(x, y) - assert Domain.preprocess('ZZ(x,y)') == ZZ.frac_field(x,y) - assert Domain.preprocess('QQ(x,y)') == QQ.frac_field(x,y) + assert Domain.preprocess('ZZ(x,y)') == ZZ.frac_field(x, y) + assert Domain.preprocess('QQ(x,y)') == QQ.frac_field(x, y) assert Domain.preprocess('Q') == QQ.algebraic_field(I) assert Domain.preprocess('QQ') == QQ.algebraic_field(I) assert Domain.preprocess('Q') == QQ.algebraic_field(sqrt(2), I) - assert Domain.preprocess('QQ') == QQ.algebraic_field(sqrt(2), I) + assert Domain.preprocess( + 'QQ') == QQ.algebraic_field(sqrt(2), I) raises(OptionError, lambda: Domain.preprocess('abc')) + def test_Domain_postprocess(): - raises(GeneratorsError, lambda: Domain.postprocess({'gens': (x, y), 'domain': ZZ[y, z]})) + raises(GeneratorsError, lambda: Domain.postprocess({'gens': (x, y), + 'domain': ZZ[y, z]})) + + raises(GeneratorsError, lambda: Domain.postprocess({'gens': (), + 'domain': EX})) + raises(GeneratorsError, lambda: Domain.postprocess({'domain': EX})) + def test_Split_preprocess(): assert Split.preprocess(False) is False @@ -205,9 +229,11 @@ raises(OptionError, lambda: Split.preprocess(x)) + def test_Split_postprocess(): raises(NotImplementedError, lambda: Split.postprocess({'split': True})) + def test_Gaussian_preprocess(): assert Gaussian.preprocess(False) is False assert Gaussian.preprocess(True) is True @@ -217,6 +243,7 @@ raises(OptionError, lambda: Gaussian.preprocess(x)) + def test_Gaussian_postprocess(): opt = {'gaussian': True} Gaussian.postprocess(opt) @@ -227,6 +254,7 @@ 'domain': QQ.algebraic_field(I), } + def test_Extension_preprocess(): assert Extension.preprocess(True) is True assert Extension.preprocess(1) is True @@ -241,6 +269,7 @@ raises(OptionError, lambda: Extension.preprocess(False)) raises(OptionError, lambda: Extension.preprocess(0)) + def test_Extension_postprocess(): opt = {'extension': set([sqrt(2)])} Extension.postprocess(opt) @@ -255,6 +284,7 @@ assert opt == {'extension': True} + def test_Modulus_preprocess(): assert Modulus.preprocess(23) == 23 assert Modulus.preprocess(Integer(23)) == 23 @@ -262,6 +292,7 @@ raises(OptionError, lambda: Modulus.preprocess(0)) raises(OptionError, lambda: Modulus.preprocess(x)) + def test_Modulus_postprocess(): opt = {'modulus': 5} Modulus.postprocess(opt) @@ -280,6 +311,7 @@ 'symmetric': False, } + def test_Symmetric_preprocess(): assert Symmetric.preprocess(False) is False assert Symmetric.preprocess(True) is True @@ -289,12 +321,14 @@ raises(OptionError, lambda: Symmetric.preprocess(x)) + def test_Symmetric_postprocess(): opt = {'symmetric': True} Symmetric.postprocess(opt) assert opt == {'symmetric': True} + def test_Strict_preprocess(): assert Strict.preprocess(False) is False assert Strict.preprocess(True) is True @@ -304,12 +338,14 @@ raises(OptionError, lambda: Strict.preprocess(x)) + def test_Strict_postprocess(): opt = {'strict': True} Strict.postprocess(opt) assert opt == {'strict': True} + def test_Auto_preprocess(): assert Auto.preprocess(False) is False assert Auto.preprocess(True) is True @@ -319,12 +355,14 @@ raises(OptionError, lambda: Auto.preprocess(x)) + def test_Auto_postprocess(): opt = {'auto': True} Auto.postprocess(opt) assert opt == {'auto': True} + def test_Frac_preprocess(): assert Frac.preprocess(False) is False assert Frac.preprocess(True) is True @@ -334,12 +372,14 @@ raises(OptionError, lambda: Frac.preprocess(x)) + def test_Frac_postprocess(): opt = {'frac': True} Frac.postprocess(opt) assert opt == {'frac': True} + def test_Formal_preprocess(): assert Formal.preprocess(False) is False assert Formal.preprocess(True) is True @@ -349,12 +389,14 @@ raises(OptionError, lambda: Formal.preprocess(x)) + def test_Formal_postprocess(): opt = {'formal': True} Formal.postprocess(opt) assert opt == {'formal': True} + def test_Polys_preprocess(): assert Polys.preprocess(False) is False assert Polys.preprocess(True) is True @@ -364,12 +406,14 @@ raises(OptionError, lambda: Polys.preprocess(x)) + def test_Polys_postprocess(): opt = {'polys': True} Polys.postprocess(opt) assert opt == {'polys': True} + def test_Include_preprocess(): assert Include.preprocess(False) is False assert Include.preprocess(True) is True @@ -379,12 +423,14 @@ raises(OptionError, lambda: Include.preprocess(x)) + def test_Include_postprocess(): opt = {'include': True} Include.postprocess(opt) assert opt == {'include': True} + def test_All_preprocess(): assert All.preprocess(False) is False assert All.preprocess(True) is True @@ -394,14 +440,13 @@ raises(OptionError, lambda: All.preprocess(x)) + def test_All_postprocess(): opt = {'all': True} All.postprocess(opt) assert opt == {'all': True} -def test_Gen_preprocess(): - pass def test_Gen_postprocess(): opt = {'gen': x} @@ -409,18 +454,22 @@ assert opt == {'gen': x} + def test_Symbols_preprocess(): raises(OptionError, lambda: Symbols.preprocess(x)) + def test_Symbols_postprocess(): opt = {'symbols': [x, y, z]} Symbols.postprocess(opt) assert opt == {'symbols': [x, y, z]} + def test_Method_preprocess(): raises(OptionError, lambda: Method.preprocess(10)) + def test_Method_postprocess(): opt = {'method': 'f5b'} Method.postprocess(opt) diff -Nru python3-sympy-0.7.2/sympy/polys/tests/test_polyroots.py python3-sympy-0.7.3/sympy/polys/tests/test_polyroots.py --- python3-sympy-0.7.2/sympy/polys/tests/test_polyroots.py 2012-10-17 03:02:22.000000000 +0000 +++ python3-sympy-0.7.3/sympy/polys/tests/test_polyroots.py 2013-07-13 17:53:32.000000000 +0000 @@ -2,51 +2,62 @@ from sympy import (S, symbols, Symbol, Wild, Integer, Rational, sqrt, powsimp, Lambda, sin, cos, pi, I, Interval, re, im) -from sympy.utilities.pytest import raises -from sympy.polys import Poly, cyclotomic_poly, intervals, nroots +from sympy.polys import (Poly, cyclotomic_poly, intervals, nroots, + PolynomialError) from sympy.polys.polyroots import (root_factors, roots_linear, roots_quadratic, roots_cubic, roots_quartic, roots_cyclotomic, - roots_binomial, roots_rational, preprocess_roots, roots) + roots_binomial, preprocess_roots, roots) + +from sympy.utilities.pytest import raises +from sympy.utilities.randtest import test_numerically + + +a, b, c, d, e, q, t, x, y, z = symbols('a,b,c,d,e,q,t,x,y,z') -a, b, c, d, e, t, x, y, z = symbols('a,b,c,d,e,t,x,y,z') def test_roots_linear(): - assert roots_linear(Poly(2*x+1, x)) == [-Rational(1, 2)] + assert roots_linear(Poly(2*x + 1, x)) == [-Rational(1, 2)] + def test_roots_quadratic(): assert roots_quadratic(Poly(2*x**2, x)) == [0, 0] assert roots_quadratic(Poly(2*x**2 + 3*x, x)) == [-Rational(3, 2), 0] assert roots_quadratic(Poly(2*x**2 + 3, x)) == [-I*sqrt(6)/2, I*sqrt(6)/2] - assert roots_quadratic(Poly(2*x**2 + 4*x+3, x)) == [-1 - I*sqrt(2)/2, -1 + I*sqrt(2)/2] + assert roots_quadratic( + Poly(2*x**2 + 4*x + 3, x)) == [-1 - I*sqrt(2)/2, -1 + I*sqrt(2)/2] f = x**2 + (2*a*e + 2*c*e)/(a - c)*x + (d - b + a*e**2 - c*e**2)/(a - c) assert roots_quadratic(Poly(f, x)) == \ - [-e*(a + c)/(a - c) - sqrt((a*b + c*d - a*d - b*c + 4*a*c*e**2)/(a - c)**2), + [-e*( + a + c)/( + a - c) - sqrt((a*b + c*d - a*d - b*c + 4*a*c*e**2)/(a - c)**2), -e*(a + c)/(a - c) + sqrt((a*b + c*d - a*d - b*c + 4*a*c*e**2)/(a - c)**2)] + def test_roots_cubic(): assert roots_cubic(Poly(2*x**3, x)) == [0, 0, 0] - assert roots_cubic(Poly(x**3-3*x**2+3*x-1, x)) == [1, 1, 1] + assert roots_cubic(Poly(x**3 - 3*x**2 + 3*x - 1, x)) == [1, 1, 1] - assert roots_cubic(Poly(x**3+1, x)) == \ + assert roots_cubic(Poly(x**3 + 1, x)) == \ [-1, S.Half - I*sqrt(3)/2, S.Half + I*sqrt(3)/2] + def test_roots_quartic(): assert roots_quartic(Poly(x**4, x)) == [0, 0, 0, 0] assert roots_quartic(Poly(x**4 + x**3, x)) in [ - [-1,0,0,0], - [0,-1,0,0], - [0,0,-1,0], - [0,0,0,-1] + [-1, 0, 0, 0], + [0, -1, 0, 0], + [0, 0, -1, 0], + [0, 0, 0, -1] ] assert roots_quartic(Poly(x**4 - x**3, x)) in [ - [1,0,0,0], - [0,1,0,0], - [0,0,1,0], - [0,0,0,1] + [1, 0, 0, 0], + [0, 1, 0, 0], + [0, 0, 1, 0], + [0, 0, 0, 1] ] lhs = roots_quartic(Poly(x**4 + x, x)) @@ -60,7 +71,8 @@ (1, 2, 3, 4), (1, 2, 3, 4), (-7, -3, 3, -6), - (-3, 5, -6, -4)]): + (-3, 5, -6, -4), + (6, -5, -10, -3)]): if i == 2: c = -a*(a**2/S(8) - b/S(2)) elif i == 3: @@ -69,18 +81,28 @@ ans = roots_quartic(Poly(eq, x)) assert all(eq.subs(x, ai).n(chop=True) == 0 for ai in ans) + # not all symbolic quartics are unresolvable + eq = Poly(q*x + q/4 + x**4 + x**3 + 2*x**2 - Rational(1, 3), x) + sol = roots_quartic(eq) + assert all(test_numerically(eq.subs(x, i), 0) for i in sol) + # but some are (see also iss 1890) + raises(PolynomialError, lambda: roots_quartic(Poly(y*x**4 + x + z, x))) + + def test_roots_cyclotomic(): assert roots_cyclotomic(cyclotomic_poly(1, x, polys=True)) == [1] assert roots_cyclotomic(cyclotomic_poly(2, x, polys=True)) == [-1] - assert roots_cyclotomic(cyclotomic_poly(3, x, polys=True)) == [-S(1)/2 - I*sqrt(3)/2, -S(1)/2 + I*sqrt(3)/2] + assert roots_cyclotomic(cyclotomic_poly( + 3, x, polys=True)) == [-S(1)/2 - I*sqrt(3)/2, -S(1)/2 + I*sqrt(3)/2] assert roots_cyclotomic(cyclotomic_poly(4, x, polys=True)) == [-I, I] - assert roots_cyclotomic(cyclotomic_poly(6, x, polys=True)) == [S(1)/2 - I*sqrt(3)/2, S(1)/2 + I*sqrt(3)/2] + assert roots_cyclotomic(cyclotomic_poly( + 6, x, polys=True)) == [S(1)/2 - I*sqrt(3)/2, S(1)/2 + I*sqrt(3)/2] assert roots_cyclotomic(cyclotomic_poly(7, x, polys=True)) == [ - -cos(pi/7) - I*sin(pi/7), - -cos(pi/7) + I*sin(pi/7), - cos(2*pi/7) - I*sin(2*pi/7), - cos(2*pi/7) + I*sin(2*pi/7), + -cos(pi/7) - I*sin(pi/7), + -cos(pi/7) + I*sin(pi/7), + cos(2*pi/7) - I*sin(2*pi/7), + cos(2*pi/7) + I*sin(2*pi/7), -cos(3*pi/7) - I*sin(3*pi/7), -cos(3*pi/7) + I*sin(3*pi/7), ] @@ -88,37 +110,41 @@ assert roots_cyclotomic(cyclotomic_poly(8, x, polys=True)) == [ -sqrt(2)/2 - I*sqrt(2)/2, -sqrt(2)/2 + I*sqrt(2)/2, - sqrt(2)/2 - I*sqrt(2)/2, - sqrt(2)/2 + I*sqrt(2)/2, + sqrt(2)/2 - I*sqrt(2)/2, + sqrt(2)/2 + I*sqrt(2)/2, ] assert roots_cyclotomic(cyclotomic_poly(12, x, polys=True)) == [ -sqrt(3)/2 - I/2, -sqrt(3)/2 + I/2, - sqrt(3)/2 - I/2, - sqrt(3)/2 + I/2, + sqrt(3)/2 - I/2, + sqrt(3)/2 + I/2, ] - assert roots_cyclotomic(cyclotomic_poly(1, x, polys=True), factor=True) == [1] - assert roots_cyclotomic(cyclotomic_poly(2, x, polys=True), factor=True) == [-1] + assert roots_cyclotomic( + cyclotomic_poly(1, x, polys=True), factor=True) == [1] + assert roots_cyclotomic( + cyclotomic_poly(2, x, polys=True), factor=True) == [-1] assert roots_cyclotomic(cyclotomic_poly(3, x, polys=True), factor=True) == \ [-(-1)**(S(1)/3), -1 + (-1)**(S(1)/3)] assert roots_cyclotomic(cyclotomic_poly(4, x, polys=True), factor=True) == \ [-I, I] assert roots_cyclotomic(cyclotomic_poly(5, x, polys=True), factor=True) == \ - [-(-1)**(S(1)/5), (-1)**(S(2)/5), -(-1)**(S(3)/5), -1 + (-1)**(S(1)/5) - (-1)**(S(2)/5) + (-1)**(S(3)/5)] + [-(-1)**(S(1)/5), (-1)**(S(2)/5), -(-1)**(S(3)/5), + -1 + (-1)**(S(1)/5) - (-1)**(S(2)/5) + (-1)**(S(3)/5)] assert roots_cyclotomic(cyclotomic_poly(6, x, polys=True), factor=True) == \ [(-1)**(S(1)/3), 1 - (-1)**(S(1)/3)] + def test_roots_binomial(): assert roots_binomial(Poly(5*x, x)) == [0] assert roots_binomial(Poly(5*x**4, x)) == [0, 0, 0, 0] - assert roots_binomial(Poly(5*x+2, x)) == [-Rational(2, 5)] + assert roots_binomial(Poly(5*x + 2, x)) == [-Rational(2, 5)] A = 10**Rational(3, 4)/10 - assert roots_binomial(Poly(5*x**4+2, x)) == \ + assert roots_binomial(Poly(5*x**4 + 2, x)) == \ [-A - A*I, -A + A*I, A - A*I, A + A*I] a1 = Symbol('a1', nonnegative=True) @@ -130,15 +156,6 @@ assert powsimp(r0[0]) == powsimp(r1[0]) assert powsimp(r0[1]) == powsimp(r1[1]) -def test_roots_rational(): - assert roots_rational(Poly(x**2-1, x)) == [-S.One, S.One] - assert roots_rational(Poly(x**2-x, x)) == [S.Zero, S.One] - - assert roots_rational(Poly(x**2-x/2, x)) == [S.Zero] - assert roots_rational(Poly(2*x**2-x, x)) == [S.Zero] - - assert roots_rational(Poly(t*x**2-x, x)) == [] - def test_roots_preprocessing(): f = a*y*x**2 + y - b @@ -178,93 +195,99 @@ E, F, J, L = symbols("E,F,J,L") f = -21601054687500000000*E**8*J**8/L**16 + \ - 508232812500000000*F*x*E**7*J**7/L**14 - \ - 4269543750000000*E**6*F**2*J**6*x**2/L**12 + \ - 16194716250000*E**5*F**3*J**5*x**3/L**10 - \ - 27633173750*E**4*F**4*J**4*x**4/L**8 + \ - 14840215*E**3*F**5*J**3*x**5/L**6 + \ - 54794*E**2*F**6*J**2*x**6/(5*L**4) - \ - 1153*E*J*F**7*x**7/(80*L**2) + \ - 633*F**8*x**8/160000 + 508232812500000000*F*x*E**7*J**7/L**14 - \ + 4269543750000000*E**6*F**2*J**6*x**2/L**12 + \ + 16194716250000*E**5*F**3*J**5*x**3/L**10 - \ + 27633173750*E**4*F**4*J**4*x**4/L**8 + \ + 14840215*E**3*F**5*J**3*x**5/L**6 + \ + 54794*E**2*F**6*J**2*x**6/(5*L**4) - \ + 1153*E*J*F**7*x**7/(80*L**2) + \ + 633*F**8*x**8/160000 coeff, poly = preprocess_roots(Poly(f, x)) assert coeff == 20*E*J/(F*L**2) assert poly == 633*x**8 - 115300*x**7 + 4383520*x**6 + 296804300*x**5 - 27633173750*x**4 + \ - 809735812500*x**3 - 10673859375000*x**2 + 63529101562500*x - 135006591796875 + 809735812500*x**3 - 10673859375000*x**2 + 63529101562500* \ + x - 135006591796875 + def test_roots(): assert roots(1, x) == {} assert roots(x, x) == {S.Zero: 1} assert roots(x**9, x) == {S.Zero: 9} - assert roots(((x-2)*(x+3)*(x-4)).expand(), x) == {-S(3): 1, S(2): 1, S(4): 1} + assert roots( + ((x - 2)*(x + 3)*(x - 4)).expand(), x) == {-S(3): 1, S(2): 1, S(4): 1} - assert roots(2*x+1, x) == {-S.Half: 1} - assert roots((2*x+1)**2, x) == {-S.Half: 2} - assert roots((2*x+1)**5, x) == {-S.Half: 5} - assert roots((2*x+1)**10, x) == {-S.Half: 10} + assert roots(2*x + 1, x) == {-S.Half: 1} + assert roots((2*x + 1)**2, x) == {-S.Half: 2} + assert roots((2*x + 1)**5, x) == {-S.Half: 5} + assert roots((2*x + 1)**10, x) == {-S.Half: 10} assert roots(x**4 - 1, x) == {I: 1, S.One: 1, -S.One: 1, -I: 1} assert roots((x**4 - 1)**2, x) == {I: 2, S.One: 2, -S.One: 2, -I: 2} - assert roots(((2*x-3)**2).expand(), x) == { Rational(3,2): 2} - assert roots(((2*x+3)**2).expand(), x) == {-Rational(3,2): 2} + assert roots(((2*x - 3)**2).expand(), x) == { Rational(3, 2): 2} + assert roots(((2*x + 3)**2).expand(), x) == {-Rational(3, 2): 2} - assert roots(((2*x-3)**3).expand(), x) == { Rational(3,2): 3} - assert roots(((2*x+3)**3).expand(), x) == {-Rational(3,2): 3} + assert roots(((2*x - 3)**3).expand(), x) == { Rational(3, 2): 3} + assert roots(((2*x + 3)**3).expand(), x) == {-Rational(3, 2): 3} - assert roots(((2*x-3)**5).expand(), x) == { Rational(3,2): 5} - assert roots(((2*x+3)**5).expand(), x) == {-Rational(3,2): 5} + assert roots(((2*x - 3)**5).expand(), x) == { Rational(3, 2): 5} + assert roots(((2*x + 3)**5).expand(), x) == {-Rational(3, 2): 5} - assert roots(((a*x-b)**5).expand(), x) == { b/a: 5} - assert roots(((a*x+b)**5).expand(), x) == {-b/a: 5} + assert roots(((a*x - b)**5).expand(), x) == { b/a: 5} + assert roots(((a*x + b)**5).expand(), x) == {-b/a: 5} - assert roots(x**4-2*x**2+1, x) == {S.One: 2, -S.One: 2} + assert roots(x**4 - 2*x**2 + 1, x) == {S.One: 2, -S.One: 2} - assert roots(x**6-4*x**4+4*x**3-x**2, x) == \ + assert roots(x**6 - 4*x**4 + 4*x**3 - x**2, x) == \ {S.One: 2, -1 - sqrt(2): 1, S.Zero: 2, -1 + sqrt(2): 1} - assert roots(x**8-1, x) == { - sqrt(2)/2 + I*sqrt(2)/2: 1, - sqrt(2)/2 - I*sqrt(2)/2: 1, + assert roots(x**8 - 1, x) == { + sqrt(2)/2 + I*sqrt(2)/2: 1, + sqrt(2)/2 - I*sqrt(2)/2: 1, -sqrt(2)/2 + I*sqrt(2)/2: 1, -sqrt(2)/2 - I*sqrt(2)/2: 1, S.One: 1, -S.One: 1, I: 1, -I: 1 } - f = -2016*x**2 - 5616*x**3 - 2056*x**4 + 3324*x**5 + 2176*x**6 - 224*x**7 - 384*x**8 - 64*x**9 + f = -2016*x**2 - 5616*x**3 - 2056*x**4 + 3324*x**5 + 2176*x**6 - \ + 224*x**7 - 384*x**8 - 64*x**9 - assert roots(f) == {S(0): 2, -S(2): 2, S(2): 1, -S(7)/2: 1, -S(3)/2: 1, -S(1)/2: 1, S(3)/2: 1} + assert roots(f) == {S(0): 2, -S( + 2): 2, S(2): 1, -S(7)/2: 1, -S(3)/2: 1, -S(1)/2: 1, S(3)/2: 1} - assert roots((a+b+c)*x - (a+b+c+d), x) == {(a+b+c+d)/(a+b+c): 1} + assert roots((a + b + c)*x - (a + b + c + d), x) == {(a + b + c + d)/(a + b + c): 1} - assert roots(x**3+x**2-x+1, x, cubics=False) == {} - assert roots(((x-2)*(x+3)*(x-4)).expand(), x, cubics=False) == {-S(3): 1, S(2): 1, S(4): 1} - assert roots(((x-2)*(x+3)*(x-4)*(x-5)).expand(), x, cubics=False) == \ - {-S(3): 1, S(2): 1, S(4): 1, S(5): 1} + assert roots(x**3 + x**2 - x + 1, x, cubics=False) == {} + assert roots(((x - 2)*( + x + 3)*(x - 4)).expand(), x, cubics=False) == {-S(3): 1, S(2): 1, S(4): 1} + assert roots(((x - 2)*(x + 3)*(x - 4)*(x - 5)).expand(), x, cubics=False) == \ + {-S(3): 1, S(2): 1, S(4): 1, S(5): 1} assert roots(x**3 + 2*x**2 + 4*x + 8, x) == {-S(2): 1, -2*I: 1, 2*I: 1} assert roots(x**3 + 2*x**2 + 4*x + 8, x, cubics=True) == \ - {-2*I: 1, 2*I: 1, -S(2): 1} + {-2*I: 1, 2*I: 1, -S(2): 1} assert roots((x**2 - x)*(x**3 + 2*x**2 + 4*x + 8), x ) == \ - {S(1): 1, S(0): 1, -S(2): 1, -2*I: 1, 2*I: 1} + {S(1): 1, S(0): 1, -S(2): 1, -2*I: 1, 2*I: 1} - r1_2, r1_3, r1_9, r4_9, r19_27 = [ Rational(*r) \ - for r in ((1,2), (1,3), (1,9), (4,9), (19,27)) ] + r1_2, r1_3, r1_9, r4_9, r19_27 = [ Rational(*r) + for r in ((1, 2), (1, 3), (1, 9), (4, 9), (19, 27)) ] U = -r1_2 - r1_2*I*3**r1_2 V = -r1_2 + r1_2*I*3**r1_2 W = (r19_27 + r1_9*33**r1_2)**r1_3 - assert roots(x**3+x**2-x+1, x, cubics=True) == { + assert roots(x**3 + x**2 - x + 1, x, cubics=True) == { -r1_3 - U*W - r4_9*(U*W)**(-1): 1, -r1_3 - V*W - r4_9*(V*W)**(-1): 1, - -r1_3 - W - r4_9*( W)**(-1): 1, + -r1_3 - W - r4_9*( W)**(-1): 1, } - f = (x**2+2*x+3).subs(x, 2*x**2 + 3*x).subs(x, 5*x-4) + f = (x**2 + 2*x + 3).subs(x, 2*x**2 + 3*x).subs(x, 5*x - 4) - r13_20, r1_20 = [ Rational(*r) \ - for r in ((13,20), (1,20)) ] + r13_20, r1_20 = [ Rational(*r) + for r in ((13, 20), (1, 20)) ] s2 = sqrt(2) assert roots(f, x) == { @@ -276,7 +299,7 @@ f = x**4 + x**3 + x**2 + x + 1 - r1_4, r1_8, r5_8 = [ Rational(*r) for r in ((1,4), (1,8), (5,8)) ] + r1_4, r1_8, r5_8 = [ Rational(*r) for r in ((1, 4), (1, 8), (5, 8)) ] assert roots(f, x) == { -r1_4 + r1_4*5**r1_2 + I*(r5_8 + r1_8*5**r1_2)**r1_2: 1, @@ -296,14 +319,15 @@ assert roots(a*b*c*x**3 + 2*x**2 + 4*x + 8, x, cubics=False) == {} assert roots(a*b*c*x**3 + 2*x**2 + 4*x + 8, x, cubics=True) != {} - assert roots(x**4-1, x, filter='Z') == {S.One: 1, -S.One: 1} - assert roots(x**4-1, x, filter='I') == {I: 1, -I: 1} + assert roots(x**4 - 1, x, filter='Z') == {S.One: 1, -S.One: 1} + assert roots(x**4 - 1, x, filter='I') == {I: 1, -I: 1} - assert roots((x-1)*(x+1), x) == {S.One: 1, -S.One: 1} - assert roots((x-1)*(x+1), x, predicate=lambda r: r.is_positive) == {S.One: 1} + assert roots((x - 1)*(x + 1), x) == {S.One: 1, -S.One: 1} + assert roots( + (x - 1)*(x + 1), x, predicate=lambda r: r.is_positive) == {S.One: 1} - assert roots(x**4-1, x, filter='Z', multiple=True) == [-S.One, S.One] - assert roots(x**4-1, x, filter='I', multiple=True) == [-I, I] + assert roots(x**4 - 1, x, filter='Z', multiple=True) == [-S.One, S.One] + assert roots(x**4 - 1, x, filter='I', multiple=True) == [-I, I] assert roots(x**3, x, multiple=True) == [S.Zero, S.Zero, S.Zero] assert roots(1234, x, multiple=True) == [] @@ -311,40 +335,63 @@ f = x**6 - x**5 + x**4 - x**3 + x**2 - x + 1 assert roots(f) == { - -I*sin(pi/7) + cos(pi/7): 1, + -I*sin(pi/7) + cos(pi/7): 1, -I*sin(2*pi/7) - cos(2*pi/7): 1, -I*sin(3*pi/7) + cos(3*pi/7): 1, - I*sin(pi/7) + cos(pi/7): 1, - I*sin(2*pi/7) - cos(2*pi/7): 1, - I*sin(3*pi/7) + cos(3*pi/7): 1, + I*sin(pi/7) + cos(pi/7): 1, + I*sin(2*pi/7) - cos(2*pi/7): 1, + I*sin(3*pi/7) + cos(3*pi/7): 1, } g = ((x**2 + 1)*f**2).expand() assert roots(g) == { - -I*sin(pi/7) + cos(pi/7): 2, + -I*sin(pi/7) + cos(pi/7): 2, -I*sin(2*pi/7) - cos(2*pi/7): 2, -I*sin(3*pi/7) + cos(3*pi/7): 2, - I*sin(pi/7) + cos(pi/7): 2, - I*sin(2*pi/7) - cos(2*pi/7): 2, - I*sin(3*pi/7) + cos(3*pi/7): 2, + I*sin(pi/7) + cos(pi/7): 2, + I*sin(2*pi/7) - cos(2*pi/7): 2, + I*sin(3*pi/7) + cos(3*pi/7): 2, -I: 1, I: 1, } + r = roots(x**3 + 40*x + 64) + real_root = [rx for rx in r if rx.is_real][0] + cr = 4 + 2*sqrt(1074)/9 + assert real_root == -2*cr**(S(1)/3) + 20/(3*cr**(S(1)/3)) + + eq = Poly((7 + 5*sqrt(2))*x**3 + (-6 - 4*sqrt(2))*x**2 + (-sqrt(2) - 1)*x + 2, x, domain='EX') + assert roots(eq) == {-1 + sqrt(2): 1, -2 + 2*sqrt(2): 1, -sqrt(2) + 1: 1} + + eq = Poly(41*x**5 + 29*sqrt(2)*x**5 - 153*x**4 - 108*sqrt(2)*x**4 + + 175*x**3 + 125*sqrt(2)*x**3 - 45*x**2 - 30*sqrt(2)*x**2 - 26*sqrt(2)*x - + 26*x + 24, x, domain='EX') + assert roots(eq) == {-sqrt(2) + 1: 1, -2 + 2*sqrt(2): 1, -1 + sqrt(2): 1, + -4 + 4*sqrt(2): 1, -3 + 3*sqrt(2): 1} + + eq = Poly(x**3 - 2*x**2 + 6*sqrt(2)*x**2 - 8*sqrt(2)*x + 23*x - 14 + + 14*sqrt(2), x, domain='EX') + assert roots(eq) == {-2*sqrt(2) + 2: 1, -2*sqrt(2) + 1: 1, -2*sqrt(2) - 1: 1} + + assert roots(Poly((x + sqrt(2))**3 - 7, x, domain='EX')) == \ + {-sqrt(2) - 7**(S(1)/3)/2 - sqrt(3)*7**(S(1)/3)*I/2: 1, + -sqrt(2) - 7**(S(1)/3)/2 + sqrt(3)*7**(S(1)/3)*I/2: 1, + -sqrt(2) + 7**(S(1)/3): 1} + def test_roots_slow(): """Just test that calculating these roots does not hang. """ a, b, c, d, x = symbols("a,b,c,d,x") f1 = x**2*c + (a/b) + x*c*d - a - f2 = x**2*(a + b*(c-d)*a) + x*a*b*c/(b*d-d) + (a*d-c/d) + f2 = x**2*(a + b*(c - d)*a) + x*a*b*c/(b*d - d) + (a*d - c/d) assert list(roots(f1, x).values()) == [1, 1] assert list(roots(f2, x).values()) == [1, 1] (zz, yy, xx, zy, zx, yx, k) = symbols("zz,yy,xx,zy,zx,yx,k") - e1 = (zz-k)*(yy-k)*(xx-k) + zy*yx*zx + zx-zy-yx - e2 = (zz-k)*yx*yx + zx*(yy-k)*zx + zy*zy*(xx-k) + e1 = (zz - k)*(yy - k)*(xx - k) + zy*yx*zx + zx - zy - yx + e2 = (zz - k)*yx*yx + zx*(yy - k)*zx + zy*zy*(xx - k) assert list(roots(e1 - e2, k).values()) == [1, 1, 1] @@ -355,39 +402,43 @@ assert f.subs(x, R[1]).simplify() == 0 assert f.subs(x, R[2]).simplify() == 0 + def test_roots_inexact(): - R1 = sorted([ r.evalf() for r in roots(x**2 + x + 1, x) ]) - R2 = sorted([ r for r in roots(x**2 + x + 1.0, x) ]) + R1 = sorted([ r.evalf() for r in roots(x**2 + x + 1, x) ]) + R2 = sorted([ r for r in roots(x**2 + x + 1.0, x) ]) for r1, r2 in zip(R1, R2): assert abs(r1 - r2) < 1e-12 - f = x**4 + 3.0*sqrt(2.0)*x**3 - (78.0 + 24.0*sqrt(3.0))*x**2 + 144.0*(2*sqrt(3.0) + 9.0) + f = x**4 + 3.0*sqrt( + 2.0)*x**3 - (78.0 + 24.0*sqrt(3.0))*x**2 + 144.0*(2*sqrt(3.0) + 9.0) R1 = sorted(roots(f, multiple=True)) - R2 = sorted([-12.7530479110482, -3.85012393732929, 4.89897948556636, 7.46155167569183]) + R2 = sorted([-12.7530479110482, -3.85012393732929, + 4.89897948556636, 7.46155167569183]) for r1, r2 in zip(R1, R2): assert abs(r1 - r2) < 1e-10 + def test_roots_preprocessed(): E, F, J, L = symbols("E,F,J,L") f = -21601054687500000000*E**8*J**8/L**16 + \ - 508232812500000000*F*x*E**7*J**7/L**14 - \ - 4269543750000000*E**6*F**2*J**6*x**2/L**12 + \ - 16194716250000*E**5*F**3*J**5*x**3/L**10 - \ - 27633173750*E**4*F**4*J**4*x**4/L**8 + \ - 14840215*E**3*F**5*J**3*x**5/L**6 + \ - 54794*E**2*F**6*J**2*x**6/(5*L**4) - \ - 1153*E*J*F**7*x**7/(80*L**2) + \ - 633*F**8*x**8/160000 + 508232812500000000*F*x*E**7*J**7/L**14 - \ + 4269543750000000*E**6*F**2*J**6*x**2/L**12 + \ + 16194716250000*E**5*F**3*J**5*x**3/L**10 - \ + 27633173750*E**4*F**4*J**4*x**4/L**8 + \ + 14840215*E**3*F**5*J**3*x**5/L**6 + \ + 54794*E**2*F**6*J**2*x**6/(5*L**4) - \ + 1153*E*J*F**7*x**7/(80*L**2) + \ + 633*F**8*x**8/160000 assert roots(f, x) == {} R1 = roots(f.evalf(), x, multiple=True) R2 = [-1304.88375606366, 97.1168816800648, 186.946430171876, 245.526792947065, - 503.441004174773, 791.549343830097, 1273.16678129348, 1850.10650616851] + 503.441004174773, 791.549343830097, 1273.16678129348, 1850.10650616851] w = Wild('w') p = w*E*J/(F*L**2) @@ -398,6 +449,7 @@ match = r1.match(p) assert match is not None and abs(match[w] - r2) < 1e-10 + def test_roots_mixed(): f = -1936 - 5056*x - 7592*x**2 + 2704*x**3 - 49*x**4 @@ -406,7 +458,8 @@ _sroots = roots(f, multiple=True) _re = [ Interval(a, b) for (a, b), _ in _re ] - _im = [ Interval(re(a), re(b))*Interval(im(a), im(b)) for (a, b), _ in _im ] + _im = [ Interval(re(a), re(b))*Interval(im(a), im(b)) for (a, b), + _ in _im ] _intervals = _re + _im _sroots = [ r.evalf() for r in _sroots ] @@ -421,6 +474,7 @@ else: assert (re(r), im(r)) in i + def test_root_factors(): assert root_factors(Poly(1, x)) == [Poly(1, x)] assert root_factors(Poly(x, x)) == [Poly(x, x)] diff -Nru python3-sympy-0.7.2/sympy/polys/tests/test_polytools.py python3-sympy-0.7.3/sympy/polys/tests/test_polytools.py --- python3-sympy-0.7.2/sympy/polys/tests/test_polytools.py 2012-10-17 03:02:22.000000000 +0000 +++ python3-sympy-0.7.3/sympy/polys/tests/test_polytools.py 2013-07-13 17:53:32.000000000 +0000 @@ -24,7 +24,8 @@ real_roots, nroots, ground_roots, nth_power_roots_poly, cancel, reduced, groebner, - GroebnerBasis, is_zero_dimensional) + GroebnerBasis, is_zero_dimensional, + _torational_factor_list) from sympy.polys.polyerrors import ( MultivariatePolynomialError, @@ -49,21 +50,24 @@ from sympy.polys.monomialtools import lex, grlex, grevlex from sympy import ( - S, Integer, Rational, Float, Mul, Symbol, symbols, sqrt, - exp, sin, expand, oo, I, pi, re, im, RootOf, Eq, Tuple) + S, Integer, Rational, Float, Mul, Symbol, symbols, sqrt, Piecewise, + exp, sin, expand, oo, I, pi, re, im, RootOf, Eq, Tuple, Expr) from sympy.core.compatibility import iterable from sympy.core.mul import _keep_coeff from sympy.utilities.pytest import raises, XFAIL -x,y,z,p,q,r,s,t,u,v,w,a,b,c,d,e = symbols('x,y,z,p,q,r,s,t,u,v,w,a,b,c,d,e') +x, y, z, p, q, r, s, t, u, v, w, a, b, c, d, e = symbols( + 'x,y,z,p,q,r,s,t,u,v,w,a,b,c,d,e') + def _epsilon_eq(a, b): for x, y in zip(a, b): - if abs(x-y) > 1e-10: + if abs(x - y) > 1e-10: return False return True + def _strict_eq(a, b): if type(a) == type(b): if iterable(a): @@ -76,118 +80,165 @@ else: return False + def test_Poly_from_dict(): K = FF(3) - assert Poly.from_dict({0: 1, 1: 2}, gens=x, domain=K).rep == DMP([K(2),K(1)], K) - assert Poly.from_dict({0: 1, 1: 5}, gens=x, domain=K).rep == DMP([K(2),K(1)], K) - - assert Poly.from_dict({(0,): 1, (1,): 2}, gens=x, domain=K).rep == DMP([K(2),K(1)], K) - assert Poly.from_dict({(0,): 1, (1,): 5}, gens=x, domain=K).rep == DMP([K(2),K(1)], K) - - assert Poly.from_dict({(0, 0): 1, (1, 1): 2}, gens=(x,y), domain=K).rep == DMP([[K(2),K(0)],[K(1)]], K) - - assert Poly.from_dict({0: 1, 1: 2}, gens=x).rep == DMP([ZZ(2),ZZ(1)], ZZ) - assert Poly.from_dict({0: 1, 1: 2}, gens=x, field=True).rep == DMP([QQ(2),QQ(1)], QQ) + assert Poly.from_dict( + {0: 1, 1: 2}, gens=x, domain=K).rep == DMP([K(2), K(1)], K) + assert Poly.from_dict( + {0: 1, 1: 5}, gens=x, domain=K).rep == DMP([K(2), K(1)], K) + + assert Poly.from_dict( + {(0,): 1, (1,): 2}, gens=x, domain=K).rep == DMP([K(2), K(1)], K) + assert Poly.from_dict( + {(0,): 1, (1,): 5}, gens=x, domain=K).rep == DMP([K(2), K(1)], K) + + assert Poly.from_dict({(0, 0): 1, (1, 1): 2}, gens=( + x, y), domain=K).rep == DMP([[K(2), K(0)], [K(1)]], K) + + assert Poly.from_dict({0: 1, 1: 2}, gens=x).rep == DMP([ZZ(2), ZZ(1)], ZZ) + assert Poly.from_dict( + {0: 1, 1: 2}, gens=x, field=True).rep == DMP([QQ(2), QQ(1)], QQ) + + assert Poly.from_dict( + {0: 1, 1: 2}, gens=x, domain=ZZ).rep == DMP([ZZ(2), ZZ(1)], ZZ) + assert Poly.from_dict( + {0: 1, 1: 2}, gens=x, domain=QQ).rep == DMP([QQ(2), QQ(1)], QQ) + + assert Poly.from_dict( + {(0,): 1, (1,): 2}, gens=x).rep == DMP([ZZ(2), ZZ(1)], ZZ) + assert Poly.from_dict( + {(0,): 1, (1,): 2}, gens=x, field=True).rep == DMP([QQ(2), QQ(1)], QQ) + + assert Poly.from_dict( + {(0,): 1, (1,): 2}, gens=x, domain=ZZ).rep == DMP([ZZ(2), ZZ(1)], ZZ) + assert Poly.from_dict( + {(0,): 1, (1,): 2}, gens=x, domain=QQ).rep == DMP([QQ(2), QQ(1)], QQ) + + assert Poly.from_dict({(1,): sin(y)}, gens=x, composite=False) == \ + Poly(sin(y)*x, x, domain='EX') + assert Poly.from_dict({(1,): y}, gens=x, composite=False) == \ + Poly(y*x, x, domain='EX') + assert Poly.from_dict({(1, 1): 1}, gens=(x, y), composite=False) == \ + Poly(x*y, x, y, domain='ZZ') + assert Poly.from_dict({(1, 0): y}, gens=(x, z), composite=False) == \ + Poly(y*x, x, z, domain='EX') - assert Poly.from_dict({0: 1, 1: 2}, gens=x, domain=ZZ).rep == DMP([ZZ(2),ZZ(1)], ZZ) - assert Poly.from_dict({0: 1, 1: 2}, gens=x, domain=QQ).rep == DMP([QQ(2),QQ(1)], QQ) - - assert Poly.from_dict({(0,): 1, (1,): 2}, gens=x).rep == DMP([ZZ(2),ZZ(1)], ZZ) - assert Poly.from_dict({(0,): 1, (1,): 2}, gens=x, field=True).rep == DMP([QQ(2),QQ(1)], QQ) - - assert Poly.from_dict({(0,): 1, (1,): 2}, gens=x, domain=ZZ).rep == DMP([ZZ(2),ZZ(1)], ZZ) - assert Poly.from_dict({(0,): 1, (1,): 2}, gens=x, domain=QQ).rep == DMP([QQ(2),QQ(1)], QQ) def test_Poly_from_list(): K = FF(3) - assert Poly.from_list([2,1], gens=x, domain=K).rep == DMP([K(2),K(1)], K) - assert Poly.from_list([5,1], gens=x, domain=K).rep == DMP([K(2),K(1)], K) - - assert Poly.from_list([2,1], gens=x).rep == DMP([ZZ(2),ZZ(1)], ZZ) - assert Poly.from_list([2,1], gens=x, field=True).rep == DMP([QQ(2),QQ(1)], QQ) + assert Poly.from_list([2, 1], gens=x, domain=K).rep == DMP([K(2), K(1)], K) + assert Poly.from_list([5, 1], gens=x, domain=K).rep == DMP([K(2), K(1)], K) - assert Poly.from_list([2,1], gens=x, domain=ZZ).rep == DMP([ZZ(2),ZZ(1)], ZZ) - assert Poly.from_list([2,1], gens=x, domain=QQ).rep == DMP([QQ(2),QQ(1)], QQ) + assert Poly.from_list([2, 1], gens=x).rep == DMP([ZZ(2), ZZ(1)], ZZ) + assert Poly.from_list( + [2, 1], gens=x, field=True).rep == DMP([QQ(2), QQ(1)], QQ) + + assert Poly.from_list( + [2, 1], gens=x, domain=ZZ).rep == DMP([ZZ(2), ZZ(1)], ZZ) + assert Poly.from_list( + [2, 1], gens=x, domain=QQ).rep == DMP([QQ(2), QQ(1)], QQ) assert Poly.from_list([0, 1.0], gens=x).rep == DMP([RR(1.0)], RR) assert Poly.from_list([1.0, 0], gens=x).rep == DMP([RR(1.0), RR(0.0)], RR) - raises(MultivariatePolynomialError, lambda: Poly.from_list([[]], gens=(x,y))) + raises(MultivariatePolynomialError, lambda: Poly.from_list([[]], + gens=(x, y))) + def test_Poly_from_poly(): - f = Poly(x+7, x, domain=ZZ) - g = Poly(x+2, x, modulus=3) - h = Poly(x+y, x, y, domain=ZZ) + f = Poly(x + 7, x, domain=ZZ) + g = Poly(x + 2, x, modulus=3) + h = Poly(x + y, x, y, domain=ZZ) K = FF(3) assert Poly.from_poly(f) == f - assert Poly.from_poly(f, domain=K).rep == DMP([K(1),K(1)], K) - assert Poly.from_poly(f, domain=ZZ).rep == DMP([1,7], ZZ) - assert Poly.from_poly(f, domain=QQ).rep == DMP([1,7], QQ) + assert Poly.from_poly(f, domain=K).rep == DMP([K(1), K(1)], K) + assert Poly.from_poly(f, domain=ZZ).rep == DMP([1, 7], ZZ) + assert Poly.from_poly(f, domain=QQ).rep == DMP([1, 7], QQ) assert Poly.from_poly(f, gens=x) == f - assert Poly.from_poly(f, gens=x, domain=K).rep == DMP([K(1),K(1)], K) - assert Poly.from_poly(f, gens=x, domain=ZZ).rep == DMP([1,7], ZZ) - assert Poly.from_poly(f, gens=x, domain=QQ).rep == DMP([1,7], QQ) + assert Poly.from_poly(f, gens=x, domain=K).rep == DMP([K(1), K(1)], K) + assert Poly.from_poly(f, gens=x, domain=ZZ).rep == DMP([1, 7], ZZ) + assert Poly.from_poly(f, gens=x, domain=QQ).rep == DMP([1, 7], QQ) assert Poly.from_poly(f, gens=y) == Poly(x + 7, y, domain='ZZ[x]') raises(CoercionFailed, lambda: Poly.from_poly(f, gens=y, domain=K)) raises(CoercionFailed, lambda: Poly.from_poly(f, gens=y, domain=ZZ)) raises(CoercionFailed, lambda: Poly.from_poly(f, gens=y, domain=QQ)) - assert Poly.from_poly(f, gens=(x,y)) == Poly(x + 7, x, y, domain='ZZ') - assert Poly.from_poly(f, gens=(x,y), domain=ZZ) == Poly(x + 7, x, y, domain='ZZ') - assert Poly.from_poly(f, gens=(x,y), domain=QQ) == Poly(x + 7, x, y, domain='QQ') - assert Poly.from_poly(f, gens=(x,y), modulus=3) == Poly(x + 7, x, y, domain='FF(3)') + assert Poly.from_poly(f, gens=(x, y)) == Poly(x + 7, x, y, domain='ZZ') + assert Poly.from_poly( + f, gens=(x, y), domain=ZZ) == Poly(x + 7, x, y, domain='ZZ') + assert Poly.from_poly( + f, gens=(x, y), domain=QQ) == Poly(x + 7, x, y, domain='QQ') + assert Poly.from_poly( + f, gens=(x, y), modulus=3) == Poly(x + 7, x, y, domain='FF(3)') K = FF(2) assert Poly.from_poly(g) == g - assert Poly.from_poly(g, domain=ZZ).rep == DMP([1,-1], ZZ) + assert Poly.from_poly(g, domain=ZZ).rep == DMP([1, -1], ZZ) raises(CoercionFailed, lambda: Poly.from_poly(g, domain=QQ)) - assert Poly.from_poly(g, domain=K).rep == DMP([K(1),K(0)], K) + assert Poly.from_poly(g, domain=K).rep == DMP([K(1), K(0)], K) assert Poly.from_poly(g, gens=x) == g - assert Poly.from_poly(g, gens=x, domain=ZZ).rep == DMP([1,-1], ZZ) + assert Poly.from_poly(g, gens=x, domain=ZZ).rep == DMP([1, -1], ZZ) raises(CoercionFailed, lambda: Poly.from_poly(g, gens=x, domain=QQ)) - assert Poly.from_poly(g, gens=x, domain=K).rep == DMP([K(1),K(0)], K) + assert Poly.from_poly(g, gens=x, domain=K).rep == DMP([K(1), K(0)], K) K = FF(3) assert Poly.from_poly(h) == h - assert Poly.from_poly(h, domain=ZZ).rep == DMP([[ZZ(1)],[ZZ(1),ZZ(0)]], ZZ) - assert Poly.from_poly(h, domain=QQ).rep == DMP([[QQ(1)],[QQ(1),QQ(0)]], QQ) - assert Poly.from_poly(h, domain=K).rep == DMP([[K(1)],[K(1),K(0)]], K) + assert Poly.from_poly( + h, domain=ZZ).rep == DMP([[ZZ(1)], [ZZ(1), ZZ(0)]], ZZ) + assert Poly.from_poly( + h, domain=QQ).rep == DMP([[QQ(1)], [QQ(1), QQ(0)]], QQ) + assert Poly.from_poly(h, domain=K).rep == DMP([[K(1)], [K(1), K(0)]], K) - assert Poly.from_poly(h, gens=x) == Poly(x+y, x, domain=ZZ[y]) + assert Poly.from_poly(h, gens=x) == Poly(x + y, x, domain=ZZ[y]) raises(CoercionFailed, lambda: Poly.from_poly(h, gens=x, domain=ZZ)) - assert Poly.from_poly(h, gens=x, domain=ZZ[y]) == Poly(x+y, x, domain=ZZ[y]) + assert Poly.from_poly( + h, gens=x, domain=ZZ[y]) == Poly(x + y, x, domain=ZZ[y]) raises(CoercionFailed, lambda: Poly.from_poly(h, gens=x, domain=QQ)) - assert Poly.from_poly(h, gens=x, domain=QQ[y]) == Poly(x+y, x, domain=QQ[y]) + assert Poly.from_poly( + h, gens=x, domain=QQ[y]) == Poly(x + y, x, domain=QQ[y]) raises(CoercionFailed, lambda: Poly.from_poly(h, gens=x, modulus=3)) - assert Poly.from_poly(h, gens=y) == Poly(x+y, y, domain=ZZ[x]) + assert Poly.from_poly(h, gens=y) == Poly(x + y, y, domain=ZZ[x]) raises(CoercionFailed, lambda: Poly.from_poly(h, gens=y, domain=ZZ)) - assert Poly.from_poly(h, gens=y, domain=ZZ[x]) == Poly(x+y, y, domain=ZZ[x]) + assert Poly.from_poly( + h, gens=y, domain=ZZ[x]) == Poly(x + y, y, domain=ZZ[x]) raises(CoercionFailed, lambda: Poly.from_poly(h, gens=y, domain=QQ)) - assert Poly.from_poly(h, gens=y, domain=QQ[x]) == Poly(x+y, y, domain=QQ[x]) + assert Poly.from_poly( + h, gens=y, domain=QQ[x]) == Poly(x + y, y, domain=QQ[x]) raises(CoercionFailed, lambda: Poly.from_poly(h, gens=y, modulus=3)) - assert Poly.from_poly(h, gens=(x,y)) == h - assert Poly.from_poly(h, gens=(x,y), domain=ZZ).rep == DMP([[ZZ(1)],[ZZ(1),ZZ(0)]], ZZ) - assert Poly.from_poly(h, gens=(x,y), domain=QQ).rep == DMP([[QQ(1)],[QQ(1),QQ(0)]], QQ) - assert Poly.from_poly(h, gens=(x,y), domain=K).rep == DMP([[K(1)],[K(1),K(0)]], K) - - assert Poly.from_poly(h, gens=(y,x)).rep == DMP([[ZZ(1)],[ZZ(1),ZZ(0)]], ZZ) - assert Poly.from_poly(h, gens=(y,x), domain=ZZ).rep == DMP([[ZZ(1)],[ZZ(1),ZZ(0)]], ZZ) - assert Poly.from_poly(h, gens=(y,x), domain=QQ).rep == DMP([[QQ(1)],[QQ(1),QQ(0)]], QQ) - assert Poly.from_poly(h, gens=(y,x), domain=K).rep == DMP([[K(1)],[K(1),K(0)]], K) + assert Poly.from_poly(h, gens=(x, y)) == h + assert Poly.from_poly( + h, gens=(x, y), domain=ZZ).rep == DMP([[ZZ(1)], [ZZ(1), ZZ(0)]], ZZ) + assert Poly.from_poly( + h, gens=(x, y), domain=QQ).rep == DMP([[QQ(1)], [QQ(1), QQ(0)]], QQ) + assert Poly.from_poly( + h, gens=(x, y), domain=K).rep == DMP([[K(1)], [K(1), K(0)]], K) + + assert Poly.from_poly( + h, gens=(y, x)).rep == DMP([[ZZ(1)], [ZZ(1), ZZ(0)]], ZZ) + assert Poly.from_poly( + h, gens=(y, x), domain=ZZ).rep == DMP([[ZZ(1)], [ZZ(1), ZZ(0)]], ZZ) + assert Poly.from_poly( + h, gens=(y, x), domain=QQ).rep == DMP([[QQ(1)], [QQ(1), QQ(0)]], QQ) + assert Poly.from_poly( + h, gens=(y, x), domain=K).rep == DMP([[K(1)], [K(1), K(0)]], K) + + assert Poly.from_poly( + h, gens=(x, y), field=True).rep == DMP([[QQ(1)], [QQ(1), QQ(0)]], QQ) + assert Poly.from_poly( + h, gens=(x, y), field=True).rep == DMP([[QQ(1)], [QQ(1), QQ(0)]], QQ) - assert Poly.from_poly(h, gens=(x,y), field=True).rep == DMP([[QQ(1)],[QQ(1),QQ(0)]], QQ) - assert Poly.from_poly(h, gens=(x,y), field=True).rep == DMP([[QQ(1)],[QQ(1),QQ(0)]], QQ) def test_Poly_from_expr(): raises(GeneratorsNeeded, lambda: Poly.from_expr(S(0))) @@ -195,56 +246,59 @@ K = FF(3) - assert Poly.from_expr(x + 5, domain=K).rep == DMP([K(1),K(2)], K) - assert Poly.from_expr(y + 5, domain=K).rep == DMP([K(1),K(2)], K) + assert Poly.from_expr(x + 5, domain=K).rep == DMP([K(1), K(2)], K) + assert Poly.from_expr(y + 5, domain=K).rep == DMP([K(1), K(2)], K) + + assert Poly.from_expr(x + 5, x, domain=K).rep == DMP([K(1), K(2)], K) + assert Poly.from_expr(y + 5, y, domain=K).rep == DMP([K(1), K(2)], K) - assert Poly.from_expr(x + 5, x, domain=K).rep == DMP([K(1),K(2)], K) - assert Poly.from_expr(y + 5, y, domain=K).rep == DMP([K(1),K(2)], K) + assert Poly.from_expr( + x + y, domain=K).rep == DMP([[K(1)], [K(1), K(0)]], K) + assert Poly.from_expr( + x + y, x, y, domain=K).rep == DMP([[K(1)], [K(1), K(0)]], K) - assert Poly.from_expr(x + y, domain=K).rep == DMP([[K(1)],[K(1),K(0)]], K) - assert Poly.from_expr(x + y, x, y, domain=K).rep == DMP([[K(1)],[K(1),K(0)]], K) + assert Poly.from_expr(x + 5).rep == DMP([1, 5], ZZ) + assert Poly.from_expr(y + 5).rep == DMP([1, 5], ZZ) - assert Poly.from_expr(x + 5).rep == DMP([1,5], ZZ) - assert Poly.from_expr(y + 5).rep == DMP([1,5], ZZ) + assert Poly.from_expr(x + 5, x).rep == DMP([1, 5], ZZ) + assert Poly.from_expr(y + 5, y).rep == DMP([1, 5], ZZ) - assert Poly.from_expr(x + 5, x).rep == DMP([1,5], ZZ) - assert Poly.from_expr(y + 5, y).rep == DMP([1,5], ZZ) + assert Poly.from_expr(x + 5, domain=ZZ).rep == DMP([1, 5], ZZ) + assert Poly.from_expr(y + 5, domain=ZZ).rep == DMP([1, 5], ZZ) - assert Poly.from_expr(x + 5, domain=ZZ).rep == DMP([1,5], ZZ) - assert Poly.from_expr(y + 5, domain=ZZ).rep == DMP([1,5], ZZ) + assert Poly.from_expr(x + 5, x, domain=ZZ).rep == DMP([1, 5], ZZ) + assert Poly.from_expr(y + 5, y, domain=ZZ).rep == DMP([1, 5], ZZ) - assert Poly.from_expr(x + 5, x, domain=ZZ).rep == DMP([1,5], ZZ) - assert Poly.from_expr(y + 5, y, domain=ZZ).rep == DMP([1,5], ZZ) + assert Poly.from_expr(x + 5, x, y, domain=ZZ).rep == DMP([[1], [5]], ZZ) + assert Poly.from_expr(y + 5, x, y, domain=ZZ).rep == DMP([[1, 5]], ZZ) - assert Poly.from_expr(x + 5, x, y, domain=ZZ).rep == DMP([[1],[5]], ZZ) - assert Poly.from_expr(y + 5, x, y, domain=ZZ).rep == DMP([[1,5]], ZZ) def test_Poly__new__(): - raises(GeneratorsError, lambda: Poly(x+1, x, x)) + raises(GeneratorsError, lambda: Poly(x + 1, x, x)) - raises(GeneratorsError, lambda: Poly(x+y, x, y, domain=ZZ[x])) - raises(GeneratorsError, lambda: Poly(x+y, x, y, domain=ZZ[y])) + raises(GeneratorsError, lambda: Poly(x + y, x, y, domain=ZZ[x])) + raises(GeneratorsError, lambda: Poly(x + y, x, y, domain=ZZ[y])) raises(OptionError, lambda: Poly(x, x, symmetric=True)) - raises(OptionError, lambda: Poly(x+2, x, modulus=3, domain=QQ)) + raises(OptionError, lambda: Poly(x + 2, x, modulus=3, domain=QQ)) - raises(OptionError, lambda: Poly(x+2, x, domain=ZZ, gaussian=True)) - raises(OptionError, lambda: Poly(x+2, x, modulus=3, gaussian=True)) + raises(OptionError, lambda: Poly(x + 2, x, domain=ZZ, gaussian=True)) + raises(OptionError, lambda: Poly(x + 2, x, modulus=3, gaussian=True)) - raises(OptionError, lambda: Poly(x+2, x, domain=ZZ, extension=[sqrt(3)])) - raises(OptionError, lambda: Poly(x+2, x, modulus=3, extension=[sqrt(3)])) + raises(OptionError, lambda: Poly(x + 2, x, domain=ZZ, extension=[sqrt(3)])) + raises(OptionError, lambda: Poly(x + 2, x, modulus=3, extension=[sqrt(3)])) - raises(OptionError, lambda: Poly(x+2, x, domain=ZZ, extension=True)) - raises(OptionError, lambda: Poly(x+2, x, modulus=3, extension=True)) + raises(OptionError, lambda: Poly(x + 2, x, domain=ZZ, extension=True)) + raises(OptionError, lambda: Poly(x + 2, x, modulus=3, extension=True)) - raises(OptionError, lambda: Poly(x+2, x, domain=ZZ, greedy=True)) - raises(OptionError, lambda: Poly(x+2, x, domain=QQ, field=True)) + raises(OptionError, lambda: Poly(x + 2, x, domain=ZZ, greedy=True)) + raises(OptionError, lambda: Poly(x + 2, x, domain=QQ, field=True)) - raises(OptionError, lambda: Poly(x+2, x, domain=ZZ, greedy=False)) - raises(OptionError, lambda: Poly(x+2, x, domain=QQ, field=False)) + raises(OptionError, lambda: Poly(x + 2, x, domain=ZZ, greedy=False)) + raises(OptionError, lambda: Poly(x + 2, x, domain=QQ, field=False)) - raises(NotImplementedError, lambda: Poly(x+1, x, modulus=3, order='grlex')) - raises(NotImplementedError, lambda: Poly(x+1, x, order='grlex')) + raises(NotImplementedError, lambda: Poly(x + 1, x, modulus=3, order='grlex')) + raises(NotImplementedError, lambda: Poly(x + 1, x, order='grlex')) raises(GeneratorsNeeded, lambda: Poly({1: 2, 0: 1})) raises(GeneratorsNeeded, lambda: Poly([2, 1])) @@ -259,6 +313,10 @@ assert Poly([a, b, c], x) == f assert Poly((a, b, c), x) == f + f = Poly({}, x, y, z) + + assert f.gens == (x, y, z) and f.as_expr() == 0 + assert Poly(Poly(a*x + b*y, x, y), x) == Poly(a*x + b*y, x) assert Poly(3*x**2 + 2*x + 1, domain='ZZ').all_coeffs() == [3, 2, 1] @@ -266,18 +324,23 @@ assert Poly(3*x**2 + 2*x + 1, domain='RR').all_coeffs() == [3.0, 2.0, 1.0] raises(CoercionFailed, lambda: Poly(3*x**2/5 + 2*x/5 + 1, domain='ZZ')) - assert Poly(3*x**2/5 + 2*x/5 + 1, domain='QQ').all_coeffs() == [S(3)/5, S(2)/5, 1] - assert _epsilon_eq(Poly(3*x**2/5 + 2*x/5 + 1, domain='RR').all_coeffs(), [0.6, 0.4, 1.0]) + assert Poly( + 3*x**2/5 + 2*x/5 + 1, domain='QQ').all_coeffs() == [S(3)/5, S(2)/5, 1] + assert _epsilon_eq( + Poly(3*x**2/5 + 2*x/5 + 1, domain='RR').all_coeffs(), [0.6, 0.4, 1.0]) assert Poly(3.0*x**2 + 2.0*x + 1, domain='ZZ').all_coeffs() == [3, 2, 1] assert Poly(3.0*x**2 + 2.0*x + 1, domain='QQ').all_coeffs() == [3, 2, 1] - assert Poly(3.0*x**2 + 2.0*x + 1, domain='RR').all_coeffs() == [3.0, 2.0, 1.0] + assert Poly( + 3.0*x**2 + 2.0*x + 1, domain='RR').all_coeffs() == [3.0, 2.0, 1.0] raises(CoercionFailed, lambda: Poly(3.1*x**2 + 2.1*x + 1, domain='ZZ')) - assert Poly(3.1*x**2 + 2.1*x + 1, domain='QQ').all_coeffs() == [S(31)/10, S(21)/10, 1] - assert Poly(3.1*x**2 + 2.1*x + 1, domain='RR').all_coeffs() == [3.1, 2.1, 1.0] + assert Poly(3.1*x**2 + 2.1*x + 1, domain='QQ').all_coeffs() == [S( + 31)/10, S(21)/10, 1] + assert Poly( + 3.1*x**2 + 2.1*x + 1, domain='RR').all_coeffs() == [3.1, 2.1, 1.0] - assert Poly({(2,1): 1, (1,2): 2, (1,1): 3}, x, y) == \ + assert Poly({(2, 1): 1, (1, 2): 2, (1, 1): 3}, x, y) == \ Poly(x**2*y + 2*x*y**2 + 3*x*y, x, y) assert Poly(x**2 + 1, extension=I).get_domain() == QQ.algebraic_field(I) @@ -285,108 +348,149 @@ f = 3*x**5 - x**4 + x**3 - x** 2 + 65538 assert Poly(f, x, modulus=65537, symmetric=True) == \ - Poly(3*x**5 - x**4 + x**3 - x** 2 + 1, x, modulus=65537, symmetric=True) + Poly(3*x**5 - x**4 + x**3 - x** 2 + 1, x, modulus=65537, + symmetric=True) assert Poly(f, x, modulus=65537, symmetric=False) == \ - Poly(3*x**5 + 65536*x**4 + x**3 + 65536*x** 2 + 1, x, modulus=65537, symmetric=False) + Poly(3*x**5 + 65536*x**4 + x**3 + 65536*x** 2 + 1, x, + modulus=65537, symmetric=False) assert Poly(x**2 + x + 1.0).get_domain() == RR + def test_Poly__args(): assert Poly(x**2 + 1).args == (x**2 + 1,) + def test_Poly__gens(): - assert Poly((x-p)*(x-q), x).gens == (x,) - assert Poly((x-p)*(x-q), p).gens == (p,) - assert Poly((x-p)*(x-q), q).gens == (q,) + assert Poly((x - p)*(x - q), x).gens == (x,) + assert Poly((x - p)*(x - q), p).gens == (p,) + assert Poly((x - p)*(x - q), q).gens == (q,) - assert Poly((x-p)*(x-q), x, p).gens == (x, p) - assert Poly((x-p)*(x-q), x, q).gens == (x, q) + assert Poly((x - p)*(x - q), x, p).gens == (x, p) + assert Poly((x - p)*(x - q), x, q).gens == (x, q) - assert Poly((x-p)*(x-q), x, p, q).gens == (x, p, q) - assert Poly((x-p)*(x-q), p, x, q).gens == (p, x, q) - assert Poly((x-p)*(x-q), p, q, x).gens == (p, q, x) + assert Poly((x - p)*(x - q), x, p, q).gens == (x, p, q) + assert Poly((x - p)*(x - q), p, x, q).gens == (p, x, q) + assert Poly((x - p)*(x - q), p, q, x).gens == (p, q, x) - assert Poly((x-p)*(x-q)).gens == (x, p, q) + assert Poly((x - p)*(x - q)).gens == (x, p, q) - assert Poly((x-p)*(x-q), sort='x > p > q').gens == (x, p, q) - assert Poly((x-p)*(x-q), sort='p > x > q').gens == (p, x, q) - assert Poly((x-p)*(x-q), sort='p > q > x').gens == (p, q, x) + assert Poly((x - p)*(x - q), sort='x > p > q').gens == (x, p, q) + assert Poly((x - p)*(x - q), sort='p > x > q').gens == (p, x, q) + assert Poly((x - p)*(x - q), sort='p > q > x').gens == (p, q, x) - assert Poly((x-p)*(x-q), x, p, q, sort='p > q > x').gens == (x, p, q) + assert Poly((x - p)*(x - q), x, p, q, sort='p > q > x').gens == (x, p, q) - assert Poly((x-p)*(x-q), wrt='x').gens == (x, p, q) - assert Poly((x-p)*(x-q), wrt='p').gens == (p, x, q) - assert Poly((x-p)*(x-q), wrt='q').gens == (q, x, p) + assert Poly((x - p)*(x - q), wrt='x').gens == (x, p, q) + assert Poly((x - p)*(x - q), wrt='p').gens == (p, x, q) + assert Poly((x - p)*(x - q), wrt='q').gens == (q, x, p) - assert Poly((x-p)*(x-q), wrt=x).gens == (x, p, q) - assert Poly((x-p)*(x-q), wrt=p).gens == (p, x, q) - assert Poly((x-p)*(x-q), wrt=q).gens == (q, x, p) + assert Poly((x - p)*(x - q), wrt=x).gens == (x, p, q) + assert Poly((x - p)*(x - q), wrt=p).gens == (p, x, q) + assert Poly((x - p)*(x - q), wrt=q).gens == (q, x, p) - assert Poly((x-p)*(x-q), x, p, q, wrt='p').gens == (x, p, q) + assert Poly((x - p)*(x - q), x, p, q, wrt='p').gens == (x, p, q) + + assert Poly((x - p)*(x - q), wrt='p', sort='q > x').gens == (p, q, x) + assert Poly((x - p)*(x - q), wrt='q', sort='p > x').gens == (q, p, x) - assert Poly((x-p)*(x-q), wrt='p', sort='q > x').gens == (p, q, x) - assert Poly((x-p)*(x-q), wrt='q', sort='p > x').gens == (q, p, x) def test_Poly_zero(): assert Poly(x).zero == Poly(0, x, domain=ZZ) assert Poly(x/2).zero == Poly(0, x, domain=QQ) + def test_Poly_one(): assert Poly(x).one == Poly(1, x, domain=ZZ) assert Poly(x/2).one == Poly(1, x, domain=QQ) + def test_Poly__unify(): raises(UnificationFailed, lambda: Poly(x)._unify(y)) K = FF(3) - raises(UnificationFailed, lambda: Poly(x, x, modulus=3)._unify(Poly(x, x, modulus=5))) - assert Poly(x, x, modulus=3)._unify(Poly(y, y, modulus=3))[2:] == (DMP([[K(1)],[]], K), DMP([[K(1),K(0)]], K)) - - assert Poly(y, x, y)._unify(Poly(x, x, modulus=3))[2:] == (DMP([[K(1),K(0)]], K), DMP([[K(1)],[]], K)) - assert Poly(x, x, modulus=3)._unify(Poly(y, x, y))[2:] == (DMP([[K(1)],[]], K), DMP([[K(1),K(0)]], K)) - - assert Poly(x+1, x)._unify(Poly(x+2, x))[2:] == (DMP([1, 1], ZZ), DMP([1, 2], ZZ)) - assert Poly(x+1, x, domain='QQ')._unify(Poly(x+2, x))[2:] == (DMP([1, 1], QQ), DMP([1, 2], QQ)) - assert Poly(x+1, x)._unify(Poly(x+2, x, domain='QQ'))[2:] == (DMP([1, 1], QQ), DMP([1, 2], QQ)) - - assert Poly(x+1, x)._unify(Poly(x+2, x, y))[2:] == (DMP([[1], [1]], ZZ), DMP([[1], [2]], ZZ)) - assert Poly(x+1, x, domain='QQ')._unify(Poly(x+2, x, y))[2:] == (DMP([[1], [1]], QQ), DMP([[1], [2]], QQ)) - assert Poly(x+1, x)._unify(Poly(x+2, x, y, domain='QQ'))[2:] == (DMP([[1], [1]], QQ), DMP([[1], [2]], QQ)) - - assert Poly(x+1, x, y)._unify(Poly(x+2, x))[2:] == (DMP([[1], [1]], ZZ), DMP([[1], [2]], ZZ)) - assert Poly(x+1, x, y, domain='QQ')._unify(Poly(x+2, x))[2:] == (DMP([[1], [1]], QQ), DMP([[1], [2]], QQ)) - assert Poly(x+1, x, y)._unify(Poly(x+2, x, domain='QQ'))[2:] == (DMP([[1], [1]], QQ), DMP([[1], [2]], QQ)) - - assert Poly(x+1, x, y)._unify(Poly(x+2, x, y))[2:] == (DMP([[1], [1]], ZZ), DMP([[1], [2]], ZZ)) - assert Poly(x+1, x, y, domain='QQ')._unify(Poly(x+2, x, y))[2:] == (DMP([[1], [1]], QQ), DMP([[1], [2]], QQ)) - assert Poly(x+1, x, y)._unify(Poly(x+2, x, y, domain='QQ'))[2:] == (DMP([[1], [1]], QQ), DMP([[1], [2]], QQ)) - - assert Poly(x+1, x)._unify(Poly(x+2, y, x))[2:] == (DMP([[1, 1]], ZZ), DMP([[1, 2]], ZZ)) - assert Poly(x+1, x, domain='QQ')._unify(Poly(x+2, y, x))[2:] == (DMP([[1, 1]], QQ), DMP([[1, 2]], QQ)) - assert Poly(x+1, x)._unify(Poly(x+2, y, x, domain='QQ'))[2:] == (DMP([[1, 1]], QQ), DMP([[1, 2]], QQ)) - - assert Poly(x+1, y, x)._unify(Poly(x+2, x))[2:] == (DMP([[1, 1]], ZZ), DMP([[1, 2]], ZZ)) - assert Poly(x+1, y, x, domain='QQ')._unify(Poly(x+2, x))[2:] == (DMP([[1, 1]], QQ), DMP([[1, 2]], QQ)) - assert Poly(x+1, y, x)._unify(Poly(x+2, x, domain='QQ'))[2:] == (DMP([[1, 1]], QQ), DMP([[1, 2]], QQ)) - - assert Poly(x+1, x, y)._unify(Poly(x+2, y, x))[2:] == (DMP([[1], [1]], ZZ), DMP([[1], [2]], ZZ)) - assert Poly(x+1, x, y, domain='QQ')._unify(Poly(x+2, y, x))[2:] == (DMP([[1], [1]], QQ), DMP([[1], [2]], QQ)) - assert Poly(x+1, x, y)._unify(Poly(x+2, y, x, domain='QQ'))[2:] == (DMP([[1], [1]], QQ), DMP([[1], [2]], QQ)) - - assert Poly(x+1, y, x)._unify(Poly(x+2, x, y))[2:] == (DMP([[1, 1]], ZZ), DMP([[1, 2]], ZZ)) - assert Poly(x+1, y, x, domain='QQ')._unify(Poly(x+2, x, y))[2:] == (DMP([[1, 1]], QQ), DMP([[1, 2]], QQ)) - assert Poly(x+1, y, x)._unify(Poly(x+2, x, y, domain='QQ'))[2:] == (DMP([[1, 1]], QQ), DMP([[1, 2]], QQ)) + raises(UnificationFailed, lambda: Poly(x, x, modulus=3)._unify( + Poly(x, x, modulus=5))) + assert Poly(x, x, modulus=3)._unify(Poly(y, y, modulus=3))[2:] == ( + DMP([[K(1)], []], K), DMP([[K(1), K(0)]], K)) + + assert Poly(y, x, y)._unify(Poly(x, x, modulus=3))[2:] == (DMP([[K( + 1), K(0)]], K), DMP([[K(1)], []], K)) + assert Poly(x, x, modulus=3)._unify( + Poly(y, x, y))[2:] == (DMP([[K(1)], []], K), DMP([[K(1), K(0)]], K)) + + assert Poly( + x + 1, x)._unify(Poly(x + 2, x))[2:] == (DMP([1, 1], ZZ), DMP([1, 2], ZZ)) + assert Poly(x + 1, x, domain='QQ')._unify( + Poly(x + 2, x))[2:] == (DMP([1, 1], QQ), DMP([1, 2], QQ)) + assert Poly(x + 1, x)._unify( + Poly(x + 2, x, domain='QQ'))[2:] == (DMP([1, 1], QQ), DMP([1, 2], QQ)) + + assert Poly(x + 1, x)._unify( + Poly(x + 2, x, y))[2:] == (DMP([[1], [1]], ZZ), DMP([[1], [2]], ZZ)) + assert Poly(x + 1, x, domain='QQ')._unify( + Poly(x + 2, x, y))[2:] == (DMP([[1], [1]], QQ), DMP([[1], [2]], QQ)) + assert Poly(x + 1, x)._unify(Poly(x + 2, x, y, domain='QQ'))[2:] == ( + DMP([[1], [1]], QQ), DMP([[1], [2]], QQ)) + + assert Poly(x + 1, x, y)._unify( + Poly(x + 2, x))[2:] == (DMP([[1], [1]], ZZ), DMP([[1], [2]], ZZ)) + assert Poly(x + 1, x, y, domain='QQ')._unify( + Poly(x + 2, x))[2:] == (DMP([[1], [1]], QQ), DMP([[1], [2]], QQ)) + assert Poly(x + 1, x, y)._unify(Poly(x + 2, x, domain='QQ'))[2:] == ( + DMP([[1], [1]], QQ), DMP([[1], [2]], QQ)) + + assert Poly(x + 1, x, y)._unify( + Poly(x + 2, x, y))[2:] == (DMP([[1], [1]], ZZ), DMP([[1], [2]], ZZ)) + assert Poly(x + 1, x, y, domain='QQ')._unify( + Poly(x + 2, x, y))[2:] == (DMP([[1], [1]], QQ), DMP([[1], [2]], QQ)) + assert Poly(x + 1, x, y)._unify(Poly(x + 2, x, y, domain='QQ'))[2: + ] == (DMP([[1], [1]], QQ), DMP([[1], [2]], QQ)) + + assert Poly(x + 1, x)._unify( + Poly(x + 2, y, x))[2:] == (DMP([[1, 1]], ZZ), DMP([[1, 2]], ZZ)) + assert Poly(x + 1, x, domain='QQ')._unify( + Poly(x + 2, y, x))[2:] == (DMP([[1, 1]], QQ), DMP([[1, 2]], QQ)) + assert Poly(x + 1, x)._unify(Poly( + x + 2, y, x, domain='QQ'))[2:] == (DMP([[1, 1]], QQ), DMP([[1, 2]], QQ)) + + assert Poly(x + 1, y, x)._unify( + Poly(x + 2, x))[2:] == (DMP([[1, 1]], ZZ), DMP([[1, 2]], ZZ)) + assert Poly(x + 1, y, x, domain='QQ')._unify( + Poly(x + 2, x))[2:] == (DMP([[1, 1]], QQ), DMP([[1, 2]], QQ)) + assert Poly(x + 1, y, x)._unify(Poly( + x + 2, x, domain='QQ'))[2:] == (DMP([[1, 1]], QQ), DMP([[1, 2]], QQ)) + + assert Poly(x + 1, x, y)._unify( + Poly(x + 2, y, x))[2:] == (DMP([[1], [1]], ZZ), DMP([[1], [2]], ZZ)) + assert Poly(x + 1, x, y, domain='QQ')._unify( + Poly(x + 2, y, x))[2:] == (DMP([[1], [1]], QQ), DMP([[1], [2]], QQ)) + assert Poly(x + 1, x, y)._unify(Poly(x + 2, y, x, domain='QQ'))[2: + ] == (DMP([[1], [1]], QQ), DMP([[1], [2]], QQ)) + + assert Poly(x + 1, y, x)._unify( + Poly(x + 2, x, y))[2:] == (DMP([[1, 1]], ZZ), DMP([[1, 2]], ZZ)) + assert Poly(x + 1, y, x, domain='QQ')._unify( + Poly(x + 2, x, y))[2:] == (DMP([[1, 1]], QQ), DMP([[1, 2]], QQ)) + assert Poly(x + 1, y, x)._unify(Poly( + x + 2, x, y, domain='QQ'))[2:] == (DMP([[1, 1]], QQ), DMP([[1, 2]], QQ)) assert Poly(a*x, x, domain='ZZ[a]')._unify(Poly(a*b*x, x, domain='ZZ(a,b)'))[2:] == \ - (DMP([DMF(([[1], []], [[1]]), ZZ), DMF(([[]], [[1]]), ZZ)], ZZ.frac_field(a,b)), - DMP([DMF(([[1, 0], []], [[1]]), ZZ), DMF(([[]], [[1]]), ZZ)], ZZ.frac_field(a,b))) + ( + DMP([DMF(([[1], []], [[1]]), ZZ), DMF(([[]], [[1]] + ), ZZ)], ZZ.frac_field(a, b)), + DMP([DMF(([[1, 0], []], [[1]]), ZZ), DMF(([[]], [[1]]), ZZ)], ZZ.frac_field(a, b))) assert Poly(a*x, x, domain='ZZ(a)')._unify(Poly(a*b*x, x, domain='ZZ(a,b)'))[2:] == \ - (DMP([DMF(([[1], []], [[1]]), ZZ), DMF(([[]], [[1]]), ZZ)], ZZ.frac_field(a,b)), - DMP([DMF(([[1, 0], []], [[1]]), ZZ), DMF(([[]], [[1]]), ZZ)], ZZ.frac_field(a,b))) + ( + DMP([DMF(([[1], []], [[1]]), ZZ), DMF(([[]], [[1]] + ), ZZ)], ZZ.frac_field(a, b)), + DMP([DMF(([[1, 0], []], [[1]]), ZZ), DMF(([[]], [[1]]), ZZ)], ZZ.frac_field(a, b))) + + raises(CoercionFailed, lambda: Poly(Poly(x**2 + x**2*z, y, + field=True), domain='ZZ(x)')) - raises(CoercionFailed, lambda: Poly(Poly(x**2 + x**2*z, y, field=True), domain='ZZ(x)')) def test_Poly_free_symbols(): assert Poly(x**2 + 1).free_symbols == set([x]) @@ -396,6 +500,7 @@ assert Poly(x**2 + sin(y*z), x).free_symbols == set([x, y, z]) assert Poly(x**2 + sin(y*z), x, domain=EX).free_symbols == set([x, y, z]) + def test_PurePoly_free_symbols(): assert PurePoly(x**2 + 1).free_symbols == set([]) assert PurePoly(x**2 + y*z).free_symbols == set([]) @@ -404,68 +509,72 @@ assert PurePoly(x**2 + sin(y*z), x).free_symbols == set([y, z]) assert PurePoly(x**2 + sin(y*z), x, domain=EX).free_symbols == set([y, z]) + def test_Poly__eq__(): - assert (Poly(x, x) == Poly(x, x)) == True - assert (Poly(x, x, domain=QQ) == Poly(x, x)) == True - assert (Poly(x, x) == Poly(x, x, domain=QQ)) == True + assert (Poly(x, x) == Poly(x, x)) is True + assert (Poly(x, x, domain=QQ) == Poly(x, x)) is True + assert (Poly(x, x) == Poly(x, x, domain=QQ)) is True - assert (Poly(x, x, domain=ZZ[a]) == Poly(x, x)) == True - assert (Poly(x, x) == Poly(x, x, domain=ZZ[a])) == True + assert (Poly(x, x, domain=ZZ[a]) == Poly(x, x)) is True + assert (Poly(x, x) == Poly(x, x, domain=ZZ[a])) is True - assert (Poly(x*y, x, y) == Poly(x, x)) == False + assert (Poly(x*y, x, y) == Poly(x, x)) is False - assert (Poly(x, x, y) == Poly(x, x)) == False - assert (Poly(x, x) == Poly(x, x, y)) == False + assert (Poly(x, x, y) == Poly(x, x)) is False + assert (Poly(x, x) == Poly(x, x, y)) is False - assert (Poly(x**2 + 1, x) == Poly(y**2 + 1, y)) == False - assert (Poly(y**2 + 1, y) == Poly(x**2 + 1, x)) == False + assert (Poly(x**2 + 1, x) == Poly(y**2 + 1, y)) is False + assert (Poly(y**2 + 1, y) == Poly(x**2 + 1, x)) is False f = Poly(x, x, domain=ZZ) g = Poly(x, x, domain=QQ) - assert f.eq(g) == True - assert f.ne(g) == False + assert f.eq(g) is True + assert f.ne(g) is False + + assert f.eq(g, strict=True) is False + assert f.ne(g, strict=True) is True - assert f.eq(g, strict=True) == False - assert f.ne(g, strict=True) == True def test_PurePoly__eq__(): - assert (PurePoly(x, x) == PurePoly(x, x)) == True - assert (PurePoly(x, x, domain=QQ) == PurePoly(x, x)) == True - assert (PurePoly(x, x) == PurePoly(x, x, domain=QQ)) == True + assert (PurePoly(x, x) == PurePoly(x, x)) is True + assert (PurePoly(x, x, domain=QQ) == PurePoly(x, x)) is True + assert (PurePoly(x, x) == PurePoly(x, x, domain=QQ)) is True - assert (PurePoly(x, x, domain=ZZ[a]) == PurePoly(x, x)) == True - assert (PurePoly(x, x) == PurePoly(x, x, domain=ZZ[a])) == True + assert (PurePoly(x, x, domain=ZZ[a]) == PurePoly(x, x)) is True + assert (PurePoly(x, x) == PurePoly(x, x, domain=ZZ[a])) is True - assert (PurePoly(x*y, x, y) == PurePoly(x, x)) == False + assert (PurePoly(x*y, x, y) == PurePoly(x, x)) is False - assert (PurePoly(x, x, y) == PurePoly(x, x)) == False - assert (PurePoly(x, x) == PurePoly(x, x, y)) == False + assert (PurePoly(x, x, y) == PurePoly(x, x)) is False + assert (PurePoly(x, x) == PurePoly(x, x, y)) is False - assert (PurePoly(x**2 + 1, x) == PurePoly(y**2 + 1, y)) == True - assert (PurePoly(y**2 + 1, y) == PurePoly(x**2 + 1, x)) == True + assert (PurePoly(x**2 + 1, x) == PurePoly(y**2 + 1, y)) is True + assert (PurePoly(y**2 + 1, y) == PurePoly(x**2 + 1, x)) is True f = PurePoly(x, x, domain=ZZ) g = PurePoly(x, x, domain=QQ) - assert f.eq(g) == True - assert f.ne(g) == False + assert f.eq(g) is True + assert f.ne(g) is False - assert f.eq(g, strict=True) == False - assert f.ne(g, strict=True) == True + assert f.eq(g, strict=True) is False + assert f.ne(g, strict=True) is True f = PurePoly(x, x, domain=ZZ) g = PurePoly(y, y, domain=QQ) - assert f.eq(g) == True - assert f.ne(g) == False + assert f.eq(g) is True + assert f.ne(g) is False + + assert f.eq(g, strict=True) is False + assert f.ne(g, strict=True) is True - assert f.eq(g, strict=True) == False - assert f.ne(g, strict=True) == True def test_PurePoly_Poly(): - assert isinstance(PurePoly(Poly(x**2 + 1)), PurePoly) == True - assert isinstance(Poly(PurePoly(x**2 + 1)), Poly) == True + assert isinstance(PurePoly(Poly(x**2 + 1)), PurePoly) is True + assert isinstance(Poly(PurePoly(x**2 + 1)), Poly) is True + def test_Poly_get_domain(): assert Poly(2*x).get_domain() == ZZ @@ -480,6 +589,7 @@ assert Poly(0.2*x).get_domain() == RR + def test_Poly_set_domain(): assert Poly(2*x + 1).set_domain(ZZ) == Poly(2*x + 1) assert Poly(2*x + 1).set_domain('ZZ') == Poly(2*x + 1) @@ -495,40 +605,52 @@ raises(GeneratorsError, lambda: Poly(x*y, x, y).set_domain(ZZ[y])) + def test_Poly_get_modulus(): assert Poly(x**2 + 1, modulus=2).get_modulus() == 2 raises(PolynomialError, lambda: Poly(x**2 + 1).get_modulus()) + def test_Poly_set_modulus(): - assert Poly(x**2 + 1, modulus=2).set_modulus(7) == Poly(x**2 + 1, modulus=7) - assert Poly(x**2 + 5, modulus=7).set_modulus(2) == Poly(x**2 + 1, modulus=2) + assert Poly( + x**2 + 1, modulus=2).set_modulus(7) == Poly(x**2 + 1, modulus=7) + assert Poly( + x**2 + 5, modulus=7).set_modulus(2) == Poly(x**2 + 1, modulus=2) assert Poly(x**2 + 1).set_modulus(2) == Poly(x**2 + 1, modulus=2) raises(CoercionFailed, lambda: Poly(x/2 + 1).set_modulus(2)) + def test_Poly_add_ground(): assert Poly(x + 1).add_ground(2) == Poly(x + 3) + def test_Poly_sub_ground(): assert Poly(x + 1).sub_ground(2) == Poly(x - 1) + def test_Poly_mul_ground(): assert Poly(x + 1).mul_ground(2) == Poly(2*x + 2) + def test_Poly_quo_ground(): assert Poly(2*x + 4).quo_ground(2) == Poly(x + 2) assert Poly(2*x + 3).quo_ground(2) == Poly(x + 1) + def test_Poly_exquo_ground(): assert Poly(2*x + 4).exquo_ground(2) == Poly(x + 2) raises(ExactQuotientFailed, lambda: Poly(2*x + 3).exquo_ground(2)) + def test_Poly_abs(): - assert Poly(-x+1, x).abs() == abs(Poly(-x+1, x)) == Poly(x+1, x) + assert Poly(-x + 1, x).abs() == abs(Poly(-x + 1, x)) == Poly(x + 1, x) + def test_Poly_neg(): - assert Poly(-x+1, x).neg() == -Poly(-x+1, x) == Poly(x-1, x) + assert Poly(-x + 1, x).neg() == -Poly(-x + 1, x) == Poly(x - 1, x) + def test_Poly_add(): assert Poly(0, x).add(Poly(0, x)) == Poly(0, x) @@ -539,11 +661,12 @@ assert Poly(0, x).add(Poly(1, x, y)) == Poly(1, x, y) assert Poly(0, x, y) + Poly(1, x, y) == Poly(1, x, y) - assert Poly(1, x) + x == Poly(x+1, x) - assert Poly(1, x) + sin(x) == 1+sin(x) + assert Poly(1, x) + x == Poly(x + 1, x) + assert Poly(1, x) + sin(x) == 1 + sin(x) + + assert Poly(x, x) + 1 == Poly(x + 1, x) + assert 1 + Poly(x, x) == Poly(x + 1, x) - assert Poly(x, x) + 1 == Poly(x+1, x) - assert 1 + Poly(x, x) == Poly(x+1, x) def test_Poly_sub(): assert Poly(0, x).sub(Poly(0, x)) == Poly(0, x) @@ -554,11 +677,12 @@ assert Poly(0, x).sub(Poly(1, x, y)) == Poly(-1, x, y) assert Poly(0, x, y) - Poly(1, x, y) == Poly(-1, x, y) - assert Poly(1, x) - x == Poly(1-x, x) - assert Poly(1, x) - sin(x) == 1-sin(x) + assert Poly(1, x) - x == Poly(1 - x, x) + assert Poly(1, x) - sin(x) == 1 - sin(x) + + assert Poly(x, x) - 1 == Poly(x - 1, x) + assert 1 - Poly(x, x) == Poly(1 - x, x) - assert Poly(x, x) - 1 == Poly(x-1, x) - assert 1 - Poly(x, x) == Poly(1-x, x) def test_Poly_mul(): assert Poly(0, x).mul(Poly(0, x)) == Poly(0, x) @@ -575,9 +699,11 @@ assert Poly(x, x) * 2 == Poly(2*x, x) assert 2 * Poly(x, x) == Poly(2*x, x) + def test_Poly_sqr(): assert Poly(x*y, x, y).sqr() == Poly(x**2*y**2, x, y) + def test_Poly_pow(): assert Poly(x, x).pow(10) == Poly(x**10, x) assert Poly(x, x).pow(Integer(10)) == Poly(x**10, x) @@ -587,8 +713,9 @@ assert Poly(7*x*y, x, y)**3 == Poly(343*x**3*y**3, x, y) - assert Poly(x*y+1, x, y)**(-1) == (x*y+1)**(-1) - assert Poly(x*y+1, x, y)**x == (x*y+1)**x + assert Poly(x*y + 1, x, y)**(-1) == (x*y + 1)**(-1) + assert Poly(x*y + 1, x, y)**x == (x*y + 1)**x + def test_Poly_divmod(): f, g = Poly(x**2), Poly(x) @@ -612,84 +739,91 @@ assert Poly(x**2)/Poly(x) == x assert Poly(x)/Poly(x**2) == 1/x + def test_Poly_eq_ne(): - assert (Poly(x+y, x, y) == Poly(x+y, x, y)) == True - assert (Poly(x+y, x) == Poly(x+y, x, y)) == False - assert (Poly(x+y, x, y) == Poly(x+y, x)) == False - assert (Poly(x+y, x) == Poly(x+y, x)) == True - assert (Poly(x+y, y) == Poly(x+y, y)) == True - - assert (Poly(x+y, x, y) == x+y) == True - assert (Poly(x+y, x) == x+y) == True - assert (Poly(x+y, x, y) == x+y) == True - assert (Poly(x+y, x) == x+y) == True - assert (Poly(x+y, y) == x+y) == True - - assert (Poly(x+y, x, y) != Poly(x+y, x, y)) == False - assert (Poly(x+y, x) != Poly(x+y, x, y)) == True - assert (Poly(x+y, x, y) != Poly(x+y, x)) == True - assert (Poly(x+y, x) != Poly(x+y, x)) == False - assert (Poly(x+y, y) != Poly(x+y, y)) == False - - assert (Poly(x+y, x, y) != x+y) == False - assert (Poly(x+y, x) != x+y) == False - assert (Poly(x+y, x, y) != x+y) == False - assert (Poly(x+y, x) != x+y) == False - assert (Poly(x+y, y) != x+y) == False + assert (Poly(x + y, x, y) == Poly(x + y, x, y)) is True + assert (Poly(x + y, x) == Poly(x + y, x, y)) is False + assert (Poly(x + y, x, y) == Poly(x + y, x)) is False + assert (Poly(x + y, x) == Poly(x + y, x)) is True + assert (Poly(x + y, y) == Poly(x + y, y)) is True + + assert (Poly(x + y, x, y) == x + y) is True + assert (Poly(x + y, x) == x + y) is True + assert (Poly(x + y, x, y) == x + y) is True + assert (Poly(x + y, x) == x + y) is True + assert (Poly(x + y, y) == x + y) is True + + assert (Poly(x + y, x, y) != Poly(x + y, x, y)) is False + assert (Poly(x + y, x) != Poly(x + y, x, y)) is True + assert (Poly(x + y, x, y) != Poly(x + y, x)) is True + assert (Poly(x + y, x) != Poly(x + y, x)) is False + assert (Poly(x + y, y) != Poly(x + y, y)) is False + + assert (Poly(x + y, x, y) != x + y) is False + assert (Poly(x + y, x) != x + y) is False + assert (Poly(x + y, x, y) != x + y) is False + assert (Poly(x + y, x) != x + y) is False + assert (Poly(x + y, y) != x + y) is False + + assert (Poly(x, x) == sin(x)) is False + assert (Poly(x, x) != sin(x)) is True - assert (Poly(x, x) == sin(x)) == False - assert (Poly(x, x) != sin(x)) == True def test_Poly_nonzero(): - assert not bool(Poly(0, x)) == True - assert not bool(Poly(1, x)) == False + assert not bool(Poly(0, x)) is True + assert not bool(Poly(1, x)) is False + def test_Poly_properties(): - assert Poly(0, x).is_zero == True - assert Poly(1, x).is_zero == False + assert Poly(0, x).is_zero is True + assert Poly(1, x).is_zero is False - assert Poly(1, x).is_one == True - assert Poly(2, x).is_one == False + assert Poly(1, x).is_one is True + assert Poly(2, x).is_one is False - assert Poly(x-1, x).is_sqf == True - assert Poly((x-1)**2, x).is_sqf == False + assert Poly(x - 1, x).is_sqf is True + assert Poly((x - 1)**2, x).is_sqf is False - assert Poly(x-1, x).is_monic == True - assert Poly(2*x-1, x).is_monic == False + assert Poly(x - 1, x).is_monic is True + assert Poly(2*x - 1, x).is_monic is False - assert Poly(3*x+2, x).is_primitive == True - assert Poly(4*x+2, x).is_primitive == False + assert Poly(3*x + 2, x).is_primitive is True + assert Poly(4*x + 2, x).is_primitive is False - assert Poly(1, x).is_ground == True - assert Poly(x, x).is_ground == False + assert Poly(1, x).is_ground is True + assert Poly(x, x).is_ground is False - assert Poly(x+y+z+1).is_linear == True - assert Poly(x*y*z+1).is_linear == False + assert Poly(x + y + z + 1).is_linear is True + assert Poly(x*y*z + 1).is_linear is False - assert Poly(x*y+z+1).is_quadratic == True - assert Poly(x*y*z+1).is_quadratic == False + assert Poly(x*y + z + 1).is_quadratic is True + assert Poly(x*y*z + 1).is_quadratic is False - assert Poly(x*y).is_monomial == True - assert Poly(x*y+1).is_monomial == False + assert Poly(x*y).is_monomial is True + assert Poly(x*y + 1).is_monomial is False - assert Poly(x**2 + x*y).is_homogeneous == True - assert Poly(x**3 + x*y).is_homogeneous == False + assert Poly(x**2 + x*y).is_homogeneous is True + assert Poly(x**3 + x*y).is_homogeneous is False - assert Poly(x).is_univariate == True - assert Poly(x*y).is_univariate == False + assert Poly(x).is_univariate is True + assert Poly(x*y).is_univariate is False - assert Poly(x*y).is_multivariate == True - assert Poly(x).is_multivariate == False + assert Poly(x*y).is_multivariate is True + assert Poly(x).is_multivariate is False + + assert Poly( + x**16 + x**14 - x**10 + x**8 - x**6 + x**2 + 1).is_cyclotomic is False + assert Poly( + x**16 + x**14 - x**10 - x**8 - x**6 + x**2 + 1).is_cyclotomic is True - assert Poly(x**16 + x**14 - x**10 + x**8 - x**6 + x**2 + 1).is_cyclotomic == False - assert Poly(x**16 + x**14 - x**10 - x**8 - x**6 + x**2 + 1).is_cyclotomic == True def test_Poly_is_irreducible(): - assert Poly(x**2 + x + 1).is_irreducible == True - assert Poly(x**2 + 2*x + 1).is_irreducible == False + assert Poly(x**2 + x + 1).is_irreducible is True + assert Poly(x**2 + 2*x + 1).is_irreducible is False + + assert Poly(7*x + 3, modulus=11).is_irreducible is True + assert Poly(7*x**2 + 3*x + 1, modulus=11).is_irreducible is False - assert Poly(7*x + 3, modulus=11).is_irreducible == True - assert Poly(7*x**2 + 3*x + 1, modulus=11).is_irreducible == False def test_Poly_subs(): assert Poly(x + 1).subs(x, 0) == 1 @@ -700,6 +834,7 @@ assert Poly(x*y, x).subs(y, x) == x**2 assert Poly(x*y, x).subs(x, y) == y**2 + def test_Poly_replace(): assert Poly(x + 1).replace(x) == Poly(x + 1) assert Poly(x + 1).replace(y) == Poly(y + 1) @@ -724,8 +859,9 @@ raises(PolynomialError, lambda: Poly(x + y, x).replace(x, y)) raises(PolynomialError, lambda: Poly(x + y, y).replace(y, x)) + def test_Poly_reorder(): - raises(PolynomialError, lambda: Poly(x+y).reorder(x, z)) + raises(PolynomialError, lambda: Poly(x + y).reorder(x, z)) assert Poly(x + y, x, y).reorder(x, y) == Poly(x + y, x, y) assert Poly(x + y, x, y).reorder(y, x) == Poly(x + y, y, x) @@ -736,40 +872,46 @@ assert Poly(x + y, x, y).reorder(wrt=x) == Poly(x + y, x, y) assert Poly(x + y, x, y).reorder(wrt=y) == Poly(x + y, y, x) + def test_Poly_ltrim(): f = Poly(y**2 + y*z**2, x, y, z).ltrim(y) assert f.as_expr() == y**2 + y*z**2 and f.gens == (y, z) raises(PolynomialError, lambda: Poly(x*y**2 + y**2, x, y).ltrim(y)) + def test_Poly_has_only_gens(): - assert Poly(x*y + 1, x, y, z).has_only_gens(x, y) == True - assert Poly(x*y + z, x, y, z).has_only_gens(x, y) == False + assert Poly(x*y + 1, x, y, z).has_only_gens(x, y) is True + assert Poly(x*y + z, x, y, z).has_only_gens(x, y) is False raises(GeneratorsError, lambda: Poly(x*y**2 + y**2, x, y).has_only_gens(t)) + def test_Poly_to_ring(): - assert Poly(2*x+1, domain='ZZ').to_ring() == Poly(2*x+1, domain='ZZ') - assert Poly(2*x+1, domain='QQ').to_ring() == Poly(2*x+1, domain='ZZ') + assert Poly(2*x + 1, domain='ZZ').to_ring() == Poly(2*x + 1, domain='ZZ') + assert Poly(2*x + 1, domain='QQ').to_ring() == Poly(2*x + 1, domain='ZZ') + + raises(CoercionFailed, lambda: Poly(x/2 + 1).to_ring()) + raises(DomainError, lambda: Poly(2*x + 1, modulus=3).to_ring()) - raises(CoercionFailed, lambda: Poly(x/2+1).to_ring()) - raises(DomainError, lambda: Poly(2*x+1, modulus=3).to_ring()) def test_Poly_to_field(): - assert Poly(2*x+1, domain='ZZ').to_field() == Poly(2*x+1, domain='QQ') - assert Poly(2*x+1, domain='QQ').to_field() == Poly(2*x+1, domain='QQ') + assert Poly(2*x + 1, domain='ZZ').to_field() == Poly(2*x + 1, domain='QQ') + assert Poly(2*x + 1, domain='QQ').to_field() == Poly(2*x + 1, domain='QQ') - assert Poly(x/2+1, domain='QQ').to_field() == Poly(x/2+1, domain='QQ') - assert Poly(2*x+1, modulus=3).to_field() == Poly(2*x+1, modulus=3) + assert Poly(x/2 + 1, domain='QQ').to_field() == Poly(x/2 + 1, domain='QQ') + assert Poly(2*x + 1, modulus=3).to_field() == Poly(2*x + 1, modulus=3) raises(DomainError, lambda: Poly(2.0*x + 1.0).to_field()) + def test_Poly_to_exact(): assert Poly(2*x).to_exact() == Poly(2*x) assert Poly(x/2).to_exact() == Poly(x/2) assert Poly(0.1*x).to_exact() == Poly(x/10) + def test_Poly_retract(): f = Poly(x**2 + 1, x, domain=QQ[y]) @@ -778,6 +920,7 @@ assert Poly(0, x, y).retract() == Poly(0, x, y) + def test_Poly_slice(): f = Poly(x**3 + 2*x**2 + 3*x + 4) @@ -793,68 +936,79 @@ assert f.slice(x, 0, 3) == Poly(2*x**2 + 3*x + 4, x) assert f.slice(x, 0, 4) == Poly(x**3 + 2*x**2 + 3*x + 4, x) + def test_Poly_coeffs(): assert Poly(0, x).coeffs() == [0] assert Poly(1, x).coeffs() == [1] - assert Poly(2*x+1, x).coeffs() == [2,1] + assert Poly(2*x + 1, x).coeffs() == [2, 1] - assert Poly(7*x**2+2*x+1, x).coeffs() == [7,2,1] - assert Poly(7*x**4+2*x+1, x).coeffs() == [7,2,1] + assert Poly(7*x**2 + 2*x + 1, x).coeffs() == [7, 2, 1] + assert Poly(7*x**4 + 2*x + 1, x).coeffs() == [7, 2, 1] assert Poly(x*y**7 + 2*x**2*y**3).coeffs('lex') == [2, 1] assert Poly(x*y**7 + 2*x**2*y**3).coeffs('grlex') == [1, 2] + def test_Poly_monoms(): assert Poly(0, x).monoms() == [(0,)] assert Poly(1, x).monoms() == [(0,)] - assert Poly(2*x+1, x).monoms() == [(1,),(0,)] + assert Poly(2*x + 1, x).monoms() == [(1,), (0,)] - assert Poly(7*x**2+2*x+1, x).monoms() == [(2,),(1,),(0,)] - assert Poly(7*x**4+2*x+1, x).monoms() == [(4,),(1,),(0,)] + assert Poly(7*x**2 + 2*x + 1, x).monoms() == [(2,), (1,), (0,)] + assert Poly(7*x**4 + 2*x + 1, x).monoms() == [(4,), (1,), (0,)] assert Poly(x*y**7 + 2*x**2*y**3).monoms('lex') == [(2, 3), (1, 7)] assert Poly(x*y**7 + 2*x**2*y**3).monoms('grlex') == [(1, 7), (2, 3)] + def test_Poly_terms(): assert Poly(0, x).terms() == [((0,), 0)] assert Poly(1, x).terms() == [((0,), 1)] - assert Poly(2*x+1, x).terms() == [((1,), 2),((0,), 1)] + assert Poly(2*x + 1, x).terms() == [((1,), 2), ((0,), 1)] - assert Poly(7*x**2+2*x+1, x).terms() == [((2,), 7),((1,), 2),((0,), 1)] - assert Poly(7*x**4+2*x+1, x).terms() == [((4,), 7),((1,), 2),((0,), 1)] + assert Poly(7*x**2 + 2*x + 1, x).terms() == [((2,), 7), ((1,), 2), ((0,), 1)] + assert Poly(7*x**4 + 2*x + 1, x).terms() == [((4,), 7), ((1,), 2), ((0,), 1)] + + assert Poly( + x*y**7 + 2*x**2*y**3).terms('lex') == [((2, 3), 2), ((1, 7), 1)] + assert Poly( + x*y**7 + 2*x**2*y**3).terms('grlex') == [((1, 7), 1), ((2, 3), 2)] - assert Poly(x*y**7 + 2*x**2*y**3).terms('lex') == [((2, 3), 2), ((1, 7), 1)] - assert Poly(x*y**7 + 2*x**2*y**3).terms('grlex') == [((1, 7), 1), ((2, 3), 2)] def test_Poly_all_coeffs(): assert Poly(0, x).all_coeffs() == [0] assert Poly(1, x).all_coeffs() == [1] - assert Poly(2*x+1, x).all_coeffs() == [2,1] + assert Poly(2*x + 1, x).all_coeffs() == [2, 1] + + assert Poly(7*x**2 + 2*x + 1, x).all_coeffs() == [7, 2, 1] + assert Poly(7*x**4 + 2*x + 1, x).all_coeffs() == [7, 0, 0, 2, 1] - assert Poly(7*x**2+2*x+1, x).all_coeffs() == [7,2,1] - assert Poly(7*x**4+2*x+1, x).all_coeffs() == [7,0,0,2,1] def test_Poly_all_monoms(): assert Poly(0, x).all_monoms() == [(0,)] assert Poly(1, x).all_monoms() == [(0,)] - assert Poly(2*x+1, x).all_monoms() == [(1,),(0,)] + assert Poly(2*x + 1, x).all_monoms() == [(1,), (0,)] + + assert Poly(7*x**2 + 2*x + 1, x).all_monoms() == [(2,), (1,), (0,)] + assert Poly(7*x**4 + 2*x + 1, x).all_monoms() == [(4,), (3,), (2,), (1,), (0,)] - assert Poly(7*x**2+2*x+1, x).all_monoms() == [(2,),(1,),(0,)] - assert Poly(7*x**4+2*x+1, x).all_monoms() == [(4,),(3,),(2,),(1,),(0,)] def test_Poly_all_terms(): assert Poly(0, x).all_terms() == [((0,), 0)] assert Poly(1, x).all_terms() == [((0,), 1)] - assert Poly(2*x+1, x).all_terms() == [((1,), 2),((0,), 1)] + assert Poly(2*x + 1, x).all_terms() == [((1,), 2), ((0,), 1)] + + assert Poly(7*x**2 + 2*x + 1, x).all_terms() == \ + [((2,), 7), ((1,), 2), ((0,), 1)] + assert Poly(7*x**4 + 2*x + 1, x).all_terms() == \ + [((4,), 7), ((3,), 0), ((2,), 0), ((1,), 2), ((0,), 1)] - assert Poly(7*x**2+2*x+1, x).all_terms() == [((2,), 7),((1,), 2),((0,), 1)] - assert Poly(7*x**4+2*x+1, x).all_terms() == [((4,), 7),((3,),0),((2,),0),((1,), 2),((0,), 1)] def test_Poly_termwise(): f = Poly(x**2 + 20*x + 400) @@ -862,36 +1016,40 @@ def func(monom, coeff): (k,) = monom - return coeff//10**(2-k) + return coeff//10**(2 - k) assert f.termwise(func) == g def func(monom, coeff): (k,) = monom - return (k,), coeff//10**(2-k) + return (k,), coeff//10**(2 - k) assert f.termwise(func) == g + def test_Poly_length(): assert Poly(0, x).length() == 0 assert Poly(1, x).length() == 1 assert Poly(x, x).length() == 1 - assert Poly(x+1, x).length() == 2 - assert Poly(x**2+1, x).length() == 2 - assert Poly(x**2+x+1, x).length() == 3 + assert Poly(x + 1, x).length() == 2 + assert Poly(x**2 + 1, x).length() == 2 + assert Poly(x**2 + x + 1, x).length() == 3 + def test_Poly_as_dict(): assert Poly(0, x).as_dict() == {} assert Poly(0, x, y, z).as_dict() == {} assert Poly(1, x).as_dict() == {(0,): 1} - assert Poly(1, x, y, z).as_dict() == {(0,0,0): 1} + assert Poly(1, x, y, z).as_dict() == {(0, 0, 0): 1} - assert Poly(x**2+3, x).as_dict() == {(2,): 1, (0,): 3} - assert Poly(x**2+3, x, y, z).as_dict() == {(2,0,0): 1, (0,0,0): 3} + assert Poly(x**2 + 3, x).as_dict() == {(2,): 1, (0,): 3} + assert Poly(x**2 + 3, x, y, z).as_dict() == {(2, 0, 0): 1, (0, 0, 0): 3} + + assert Poly(3*x**2*y*z**3 + 4*x*y + 5*x*z).as_dict() == {(2, 1, 3): 3, + (1, 1, 0): 4, (1, 0, 1): 5} - assert Poly(3*x**2*y*z**3+4*x*y+5*x*z).as_dict() == {(2,1,3): 3, (1,1,0): 4, (1,0,1): 5} def test_Poly_as_expr(): assert Poly(0, x).as_expr() == 0 @@ -900,10 +1058,11 @@ assert Poly(1, x).as_expr() == 1 assert Poly(1, x, y, z).as_expr() == 1 - assert Poly(x**2+3, x).as_expr() == x**2 + 3 - assert Poly(x**2+3, x, y, z).as_expr() == x**2 + 3 + assert Poly(x**2 + 3, x).as_expr() == x**2 + 3 + assert Poly(x**2 + 3, x, y, z).as_expr() == x**2 + 3 - assert Poly(3*x**2*y*z**3+4*x*y+5*x*z).as_expr() == 3*x**2*y*z**3 + 4*x*y + 5*x*z + assert Poly( + 3*x**2*y*z**3 + 4*x*y + 5*x*z).as_expr() == 3*x**2*y*z**3 + 4*x*y + 5*x*z f = Poly(x**2 + 2*x*y**2 - y, x, y) @@ -917,9 +1076,12 @@ raises(GeneratorsError, lambda: f.as_expr({z: 7})) + def test_Poly_lift(): assert Poly(x**4 - I*x + 17*I, x, gaussian=True).lift() == \ - Poly(x**16 + 2*x**10 + 578*x**8 + x**4 - 578*x**2 + 83521, x, domain='QQ') + Poly(x**16 + 2*x**10 + 578*x**8 + x**4 - 578*x**2 + 83521, + x, domain='QQ') + def test_Poly_deflate(): assert Poly(0, x).deflate() == ((1,), Poly(0, x)) @@ -929,7 +1091,9 @@ assert Poly(x**2, x).deflate() == ((2,), Poly(x, x)) assert Poly(x**17, x).deflate() == ((17,), Poly(x, x)) - assert Poly(x**2*y*z**11+x**4*z**11).deflate() == ((2,1,11), Poly(x*y*z+x**2*z)) + assert Poly( + x**2*y*z**11 + x**4*z**11).deflate() == ((2, 1, 11), Poly(x*y*z + x**2*z)) + def test_Poly_inject(): f = Poly(x**2*y + x*y**3 + x*y + 1, x) @@ -937,20 +1101,33 @@ assert f.inject() == Poly(x**2*y + x*y**3 + x*y + 1, x, y) assert f.inject(front=True) == Poly(y**3*x + y*x**2 + y*x + 1, y, x) + def test_Poly_eject(): f = Poly(x**2*y + x*y**3 + x*y + 1, x, y) assert f.eject(x) == Poly(x*y**3 + (x**2 + x)*y + 1, y, domain='ZZ[x]') assert f.eject(y) == Poly(y*x**2 + (y**3 + y)*x + 1, x, domain='ZZ[y]') + ex = x + y + z + t + w + g = Poly(ex, x, y, z, t, w) + + assert g.eject(x) == Poly(ex, y, z, t, w, domain='ZZ[x]') + assert g.eject(x, y) == Poly(ex, z, t, w, domain='ZZ[x, y]') + assert g.eject(x, y, z) == Poly(ex, t, w, domain='ZZ[x, y, z]') + assert g.eject(w) == Poly(ex, x, y, z, t, domain='ZZ[w]') + assert g.eject(t, w) == Poly(ex, x, y, z, domain='ZZ[w, t]') + assert g.eject(z, t, w) == Poly(ex, x, y, domain='ZZ[w, t, z]') + raises(DomainError, lambda: Poly(x*y, x, y, domain=ZZ[z]).eject(y)) raises(NotImplementedError, lambda: Poly(x*y, x, y, z).eject(y)) + def test_Poly_exclude(): assert Poly(x, x, y).exclude() == Poly(x, x) assert Poly(x*y, x, y).exclude() == Poly(x*y, x, y) assert Poly(1, x, y).exclude() == Poly(1, x, y) + def test_Poly__gen_to_level(): assert Poly(1, x, y)._gen_to_level(-2) == 0 assert Poly(1, x, y)._gen_to_level(-1) == 1 @@ -969,20 +1146,21 @@ raises(PolynomialError, lambda: Poly(1, x, y)._gen_to_level(z)) raises(PolynomialError, lambda: Poly(1, x, y)._gen_to_level('z')) + def test_Poly_degree(): - assert Poly(0, x).degree() ==-1 + assert Poly(0, x).degree() == -1 assert Poly(1, x).degree() == 0 assert Poly(x, x).degree() == 1 - assert Poly(0, x).degree(gen=0) ==-1 + assert Poly(0, x).degree(gen=0) == -1 assert Poly(1, x).degree(gen=0) == 0 assert Poly(x, x).degree(gen=0) == 1 - assert Poly(0, x).degree(gen=x) ==-1 + assert Poly(0, x).degree(gen=x) == -1 assert Poly(1, x).degree(gen=x) == 0 assert Poly(x, x).degree(gen=x) == 1 - assert Poly(0, x).degree(gen='x') ==-1 + assert Poly(0, x).degree(gen='x') == -1 assert Poly(1, x).degree(gen='x') == 0 assert Poly(x, x).degree(gen='x') == 1 @@ -1013,30 +1191,33 @@ raises(ComputationFailed, lambda: degree(1)) + def test_Poly_degree_list(): assert Poly(0, x).degree_list() == (-1,) - assert Poly(0, x, y).degree_list() == (-1,-1) - assert Poly(0, x, y, z).degree_list() == (-1,-1,-1) + assert Poly(0, x, y).degree_list() == (-1, -1) + assert Poly(0, x, y, z).degree_list() == (-1, -1, -1) assert Poly(1, x).degree_list() == (0,) - assert Poly(1, x, y).degree_list() == (0,0) - assert Poly(1, x, y, z).degree_list() == (0,0,0) + assert Poly(1, x, y).degree_list() == (0, 0) + assert Poly(1, x, y, z).degree_list() == (0, 0, 0) - assert Poly(x**2*y+x**3*z**2+1).degree_list() == (3,1,2) + assert Poly(x**2*y + x**3*z**2 + 1).degree_list() == (3, 1, 2) assert degree_list(1, x) == (0,) assert degree_list(x, x) == (1,) - assert degree_list(x*y**2) == (1,2) + assert degree_list(x*y**2) == (1, 2) raises(ComputationFailed, lambda: degree_list(1)) + def test_Poly_total_degree(): - assert Poly(x**2*y+x**3*z**2+1).total_degree() == 5 + assert Poly(x**2*y + x**3*z**2 + 1).total_degree() == 5 assert Poly(x**2 + z**3).total_degree() == 3 assert Poly(x*y*z + z**4).total_degree() == 4 assert Poly(x**3 + x + 1).total_degree() == 3 + def test_Poly_homogeneous_order(): assert Poly(0, x, y).homogeneous_order() == -1 assert Poly(1, x, y).homogeneous_order() == 0 @@ -1049,10 +1230,11 @@ assert Poly(x**5 + 2*x**3*y**2 + 9*x*y**4).homogeneous_order() == 5 assert Poly(x**5 + 2*x**3*y**3 + 9*x*y**4).homogeneous_order() is None + def test_Poly_LC(): assert Poly(0, x).LC() == 0 assert Poly(1, x).LC() == 1 - assert Poly(2*x**2+x, x).LC() == 2 + assert Poly(2*x**2 + x, x).LC() == 2 assert Poly(x*y**7 + 2*x**2*y**3).LC('lex') == 2 assert Poly(x*y**7 + 2*x**2*y**3).LC('grlex') == 1 @@ -1060,19 +1242,51 @@ assert LC(x*y**7 + 2*x**2*y**3, order='lex') == 2 assert LC(x*y**7 + 2*x**2*y**3, order='grlex') == 1 + def test_Poly_TC(): assert Poly(0, x).TC() == 0 assert Poly(1, x).TC() == 1 - assert Poly(2*x**2+x, x).TC() == 0 + assert Poly(2*x**2 + x, x).TC() == 0 + def test_Poly_EC(): assert Poly(0, x).EC() == 0 assert Poly(1, x).EC() == 1 - assert Poly(2*x**2+x, x).EC() == 1 + assert Poly(2*x**2 + x, x).EC() == 1 assert Poly(x*y**7 + 2*x**2*y**3).EC('lex') == 1 assert Poly(x*y**7 + 2*x**2*y**3).EC('grlex') == 2 + +def test_Poly_coeff(): + assert Poly(0, x).coeff_monomial(1) == 0 + assert Poly(0, x).coeff_monomial(x) == 0 + + assert Poly(1, x).coeff_monomial(1) == 1 + assert Poly(1, x).coeff_monomial(x) == 0 + + assert Poly(x**8, x).coeff_monomial(1) == 0 + assert Poly(x**8, x).coeff_monomial(x**7) == 0 + assert Poly(x**8, x).coeff_monomial(x**8) == 1 + assert Poly(x**8, x).coeff_monomial(x**9) == 0 + + assert Poly(3*x*y**2 + 1, x, y).coeff_monomial(1) == 1 + assert Poly(3*x*y**2 + 1, x, y).coeff_monomial(x*y**2) == 3 + + p = Poly(24*x*y*exp(8) + 23*x, x, y) + + assert p.coeff_monomial(x) == 23 + assert p.coeff_monomial(y) == 0 + assert p.coeff_monomial(x*y) == 24*exp(8) + + assert p.as_expr().coeff(x) == 24*y*exp(8) + 23 + raises(NotImplementedError, lambda: p.coeff(x)) + + raises(ValueError, lambda: Poly(x + 1).coeff_monomial(0)) + raises(ValueError, lambda: Poly(x + 1).coeff_monomial(3*x)) + raises(ValueError, lambda: Poly(x + 1).coeff_monomial(3*x*y)) + + def test_Poly_nth(): assert Poly(0, x).nth(0) == 0 assert Poly(0, x).nth(1) == 0 @@ -1085,13 +1299,14 @@ assert Poly(x**8, x).nth(8) == 1 assert Poly(x**8, x).nth(9) == 0 - assert Poly(3*x*y**2 + 1).nth(0, 0) == 1 - assert Poly(3*x*y**2 + 1).nth(1, 2) == 3 + assert Poly(3*x*y**2 + 1, x, y).nth(0, 0) == 1 + assert Poly(3*x*y**2 + 1, x, y).nth(1, 2) == 3 + def test_Poly_LM(): assert Poly(0, x).LM() == (0,) assert Poly(1, x).LM() == (0,) - assert Poly(2*x**2+x, x).LM() == (2,) + assert Poly(2*x**2 + x, x).LM() == (2,) assert Poly(x*y**7 + 2*x**2*y**3).LM('lex') == (2, 3) assert Poly(x*y**7 + 2*x**2*y**3).LM('grlex') == (1, 7) @@ -1099,6 +1314,7 @@ assert LM(x*y**7 + 2*x**2*y**3, order='lex') == x**2*y**3 assert LM(x*y**7 + 2*x**2*y**3, order='grlex') == x*y**7 + def test_Poly_LM_custom_order(): f = Poly(x**2*y**3*z + x**2*y*z**3 + x*y*z + 1) rev_lex = lambda monom: tuple(reversed(monom)) @@ -1106,18 +1322,20 @@ assert f.LM(order='lex') == (2, 3, 1) assert f.LM(order=rev_lex) == (2, 1, 3) + def test_Poly_EM(): assert Poly(0, x).EM() == (0,) assert Poly(1, x).EM() == (0,) - assert Poly(2*x**2+x, x).EM() == (1,) + assert Poly(2*x**2 + x, x).EM() == (1,) assert Poly(x*y**7 + 2*x**2*y**3).EM('lex') == (1, 7) assert Poly(x*y**7 + 2*x**2*y**3).EM('grlex') == (2, 3) + def test_Poly_LT(): assert Poly(0, x).LT() == ((0,), 0) assert Poly(1, x).LT() == ((0,), 1) - assert Poly(2*x**2+x, x).LT() == ((2,), 2) + assert Poly(2*x**2 + x, x).LT() == ((2,), 2) assert Poly(x*y**7 + 2*x**2*y**3).LT('lex') == ((2, 3), 2) assert Poly(x*y**7 + 2*x**2*y**3).LT('grlex') == ((1, 7), 1) @@ -1125,40 +1343,54 @@ assert LT(x*y**7 + 2*x**2*y**3, order='lex') == 2*x**2*y**3 assert LT(x*y**7 + 2*x**2*y**3, order='grlex') == x*y**7 + def test_Poly_ET(): assert Poly(0, x).ET() == ((0,), 0) assert Poly(1, x).ET() == ((0,), 1) - assert Poly(2*x**2+x, x).ET() == ((1,), 1) + assert Poly(2*x**2 + x, x).ET() == ((1,), 1) assert Poly(x*y**7 + 2*x**2*y**3).ET('lex') == ((1, 7), 1) assert Poly(x*y**7 + 2*x**2*y**3).ET('grlex') == ((2, 3), 2) + def test_Poly_max_norm(): assert Poly(-1, x).max_norm() == 1 assert Poly( 0, x).max_norm() == 0 assert Poly( 1, x).max_norm() == 1 + def test_Poly_l1_norm(): assert Poly(-1, x).l1_norm() == 1 assert Poly( 0, x).l1_norm() == 0 assert Poly( 1, x).l1_norm() == 1 + def test_Poly_clear_denoms(): coeff, poly = Poly(x + 2, x).clear_denoms() - - assert coeff == 1 and poly == Poly(x + 2, x, domain='ZZ') and poly.get_domain() == ZZ + assert coeff == 1 and poly == Poly( + x + 2, x, domain='ZZ') and poly.get_domain() == ZZ coeff, poly = Poly(x/2 + 1, x).clear_denoms() - - assert coeff == 2 and poly == Poly(x + 2, x, domain='QQ') and poly.get_domain() == QQ + assert coeff == 2 and poly == Poly( + x + 2, x, domain='QQ') and poly.get_domain() == QQ coeff, poly = Poly(x/2 + 1, x).clear_denoms(convert=True) - - assert coeff == 2 and poly == Poly(x + 2, x, domain='ZZ') and poly.get_domain() == ZZ + assert coeff == 2 and poly == Poly( + x + 2, x, domain='ZZ') and poly.get_domain() == ZZ coeff, poly = Poly(x/y + 1, x).clear_denoms(convert=True) + assert coeff == y and poly == Poly( + x + y, x, domain='ZZ[y]') and poly.get_domain() == ZZ[y] + + coeff, poly = Poly(x/3 + sqrt(2), x, domain='EX').clear_denoms() + assert coeff == 3 and poly == Poly( + x + 3*sqrt(2), x, domain='EX') and poly.get_domain() == EX + + coeff, poly = Poly( + x/3 + sqrt(2), x, domain='EX').clear_denoms(convert=True) + assert coeff == 3 and poly == Poly( + x + 3*sqrt(2), x, domain='EX') and poly.get_domain() == EX - assert coeff == y and poly == Poly(x + y, x, domain='ZZ[y]') and poly.get_domain() == ZZ[y] def test_Poly_rat_clear_denoms(): f = Poly(x**2/y + 1, x) @@ -1172,6 +1404,7 @@ assert f.rat_clear_denoms(g) == (f, g) + def test_Poly_integrate(): assert Poly(x + 1).integrate() == Poly(x**2/2 + x) assert Poly(x + 1).integrate(x) == Poly(x**2/2 + x) @@ -1189,6 +1422,7 @@ assert Poly(x*y + 1).integrate(x, y) == Poly(x**2*y**2/4 + x*y) assert Poly(x*y + 1).integrate(y, x) == Poly(x**2*y**2/4 + x*y) + def test_Poly_diff(): assert Poly(x**2 + x).diff() == Poly(2*x + 1) assert Poly(x**2 + x).diff(x) == Poly(2*x + 1) @@ -1206,6 +1440,7 @@ assert Poly(x**2*y**2 + x*y).diff(x, y) == Poly(4*x*y + 1) assert Poly(x**2*y**2 + x*y).diff(y, x) == Poly(4*x*y + 1) + def test_Poly_eval(): assert Poly(0, x).eval(7) == 0 assert Poly(1, x).eval(7) == 1 @@ -1252,7 +1487,17 @@ Poly(x + 1, domain='ZZ').eval(sqrt(2)) == sqrt(2) + 1 raises(ValueError, lambda: Poly(x*y + y, x, y).eval((6, 7, 8))) - raises(DomainError, lambda: Poly(x+1, domain='ZZ').eval(S(1)/2, auto=False)) + raises(DomainError, lambda: Poly(x + 1, domain='ZZ').eval(S(1)/2, auto=False)) + + # issue 3245 + alpha = Symbol('alpha') + result = (2*alpha*z - 2*alpha + z**2 + 3)/(z**2 - 2*z + 1) + + f = Poly(x**2 + (alpha - 1)*x - alpha + 1, x, domain='ZZ[alpha]') + assert f.eval((z + 1)/(z - 1)) == result + + g = Poly(x**2 + (alpha - 1)*x - alpha + 1, x, y, domain='ZZ[alpha]') + assert g.eval((z + 1)/(z - 1)) == Poly(result, y, domain='ZZ(alpha,z)') def test_Poly___call__(): f = Poly(2*x*y + 3*x + y + 2*z) @@ -1261,37 +1506,59 @@ assert f(2, 5) == Poly(2*z + 31) assert f(2, 5, 7) == 45 + def test_parallel_poly_from_expr(): - assert parallel_poly_from_expr([x-1, x**2-1], x)[0] == [Poly(x-1, x), Poly(x**2-1, x)] - assert parallel_poly_from_expr([Poly(x-1, x), x**2-1], x)[0] == [Poly(x-1, x), Poly(x**2-1, x)] - assert parallel_poly_from_expr([x-1, Poly(x**2-1, x)], x)[0] == [Poly(x-1, x), Poly(x**2-1, x)] - assert parallel_poly_from_expr([Poly(x-1, x), Poly(x**2-1, x)], x)[0] == [Poly(x-1, x), Poly(x**2-1, x)] - - assert parallel_poly_from_expr([x-1, x**2-1], x, y)[0] == [Poly(x-1, x, y), Poly(x**2-1, x, y)] - assert parallel_poly_from_expr([Poly(x-1, x), x**2-1], x, y)[0] == [Poly(x-1, x, y), Poly(x**2-1, x, y)] - assert parallel_poly_from_expr([x-1, Poly(x**2-1, x)], x, y)[0] == [Poly(x-1, x, y), Poly(x**2-1, x, y)] - assert parallel_poly_from_expr([Poly(x-1, x), Poly(x**2-1, x)], x, y)[0] == [Poly(x-1, x, y), Poly(x**2-1, x, y)] - - assert parallel_poly_from_expr([x-1, x**2-1])[0] == [Poly(x-1, x), Poly(x**2-1, x)] - assert parallel_poly_from_expr([Poly(x-1, x), x**2-1])[0] == [Poly(x-1, x), Poly(x**2-1, x)] - assert parallel_poly_from_expr([x-1, Poly(x**2-1, x)])[0] == [Poly(x-1, x), Poly(x**2-1, x)] - assert parallel_poly_from_expr([Poly(x-1, x), Poly(x**2-1, x)])[0] == [Poly(x-1, x), Poly(x**2-1, x)] - - assert parallel_poly_from_expr([1, x**2-1])[0] == [Poly(1, x), Poly(x**2-1, x)] - assert parallel_poly_from_expr([1, x**2-1])[0] == [Poly(1, x), Poly(x**2-1, x)] - assert parallel_poly_from_expr([1, Poly(x**2-1, x)])[0] == [Poly(1, x), Poly(x**2-1, x)] - assert parallel_poly_from_expr([1, Poly(x**2-1, x)])[0] == [Poly(1, x), Poly(x**2-1, x)] - - assert parallel_poly_from_expr([x**2-1, 1])[0] == [Poly(x**2-1, x), Poly(1, x)] - assert parallel_poly_from_expr([x**2-1, 1])[0] == [Poly(x**2-1, x), Poly(1, x)] - assert parallel_poly_from_expr([Poly(x**2-1, x), 1])[0] == [Poly(x**2-1, x), Poly(1, x)] - assert parallel_poly_from_expr([Poly(x**2-1, x), 1])[0] == [Poly(x**2-1, x), Poly(1, x)] + assert parallel_poly_from_expr( + [x - 1, x**2 - 1], x)[0] == [Poly(x - 1, x), Poly(x**2 - 1, x)] + assert parallel_poly_from_expr( + [Poly(x - 1, x), x**2 - 1], x)[0] == [Poly(x - 1, x), Poly(x**2 - 1, x)] + assert parallel_poly_from_expr( + [x - 1, Poly(x**2 - 1, x)], x)[0] == [Poly(x - 1, x), Poly(x**2 - 1, x)] + assert parallel_poly_from_expr([Poly( + x - 1, x), Poly(x**2 - 1, x)], x)[0] == [Poly(x - 1, x), Poly(x**2 - 1, x)] + + assert parallel_poly_from_expr( + [x - 1, x**2 - 1], x, y)[0] == [Poly(x - 1, x, y), Poly(x**2 - 1, x, y)] + assert parallel_poly_from_expr([Poly( + x - 1, x), x**2 - 1], x, y)[0] == [Poly(x - 1, x, y), Poly(x**2 - 1, x, y)] + assert parallel_poly_from_expr([x - 1, Poly( + x**2 - 1, x)], x, y)[0] == [Poly(x - 1, x, y), Poly(x**2 - 1, x, y)] + assert parallel_poly_from_expr([Poly(x - 1, x), Poly( + x**2 - 1, x)], x, y)[0] == [Poly(x - 1, x, y), Poly(x**2 - 1, x, y)] + + assert parallel_poly_from_expr( + [x - 1, x**2 - 1])[0] == [Poly(x - 1, x), Poly(x**2 - 1, x)] + assert parallel_poly_from_expr( + [Poly(x - 1, x), x**2 - 1])[0] == [Poly(x - 1, x), Poly(x**2 - 1, x)] + assert parallel_poly_from_expr( + [x - 1, Poly(x**2 - 1, x)])[0] == [Poly(x - 1, x), Poly(x**2 - 1, x)] + assert parallel_poly_from_expr( + [Poly(x - 1, x), Poly(x**2 - 1, x)])[0] == [Poly(x - 1, x), Poly(x**2 - 1, x)] + + assert parallel_poly_from_expr( + [1, x**2 - 1])[0] == [Poly(1, x), Poly(x**2 - 1, x)] + assert parallel_poly_from_expr( + [1, x**2 - 1])[0] == [Poly(1, x), Poly(x**2 - 1, x)] + assert parallel_poly_from_expr( + [1, Poly(x**2 - 1, x)])[0] == [Poly(1, x), Poly(x**2 - 1, x)] + assert parallel_poly_from_expr( + [1, Poly(x**2 - 1, x)])[0] == [Poly(1, x), Poly(x**2 - 1, x)] + + assert parallel_poly_from_expr( + [x**2 - 1, 1])[0] == [Poly(x**2 - 1, x), Poly(1, x)] + assert parallel_poly_from_expr( + [x**2 - 1, 1])[0] == [Poly(x**2 - 1, x), Poly(1, x)] + assert parallel_poly_from_expr( + [Poly(x**2 - 1, x), 1])[0] == [Poly(x**2 - 1, x), Poly(1, x)] + assert parallel_poly_from_expr( + [Poly(x**2 - 1, x), 1])[0] == [Poly(x**2 - 1, x), Poly(1, x)] assert parallel_poly_from_expr([Poly(x, x, y), Poly(y, x, y)], x, y, order='lex')[0] == \ [Poly(x, x, y, domain='ZZ'), Poly(y, x, y, domain='ZZ')] raises(PolificationFailed, lambda: parallel_poly_from_expr([0, 1])) + def test_pdiv(): f, g = x**2 - y**2, x - y q, r = x + y, 0 @@ -1313,10 +1580,10 @@ assert pquo(f, g, x, y) == q assert pexquo(f, g, x, y) == q - assert pdiv(f, g, (x,y)) == (q, r) - assert prem(f, g, (x,y)) == r - assert pquo(f, g, (x,y)) == q - assert pexquo(f, g, (x,y)) == q + assert pdiv(f, g, (x, y)) == (q, r) + assert prem(f, g, (x, y)) == r + assert pquo(f, g, (x, y)) == q + assert pexquo(f, g, (x, y)) == q assert pdiv(F, G) == (Q, R) assert prem(F, G) == R @@ -1338,6 +1605,7 @@ raises(ComputationFailed, lambda: pquo(4, 2)) raises(ComputationFailed, lambda: pexquo(4, 2)) + def test_div(): f, g = x**2 - y**2, x - y q, r = x + y, 0 @@ -1359,10 +1627,10 @@ assert quo(f, g, x, y) == q assert exquo(f, g, x, y) == q - assert div(f, g, (x,y)) == (q, r) - assert rem(f, g, (x,y)) == r - assert quo(f, g, (x,y)) == q - assert exquo(f, g, (x,y)) == q + assert div(f, g, (x, y)) == (q, r) + assert rem(f, g, (x, y)) == r + assert quo(f, g, (x, y)) == q + assert exquo(f, g, (x, y)) == q assert div(F, G) == (Q, R) assert rem(F, G) == R @@ -1442,9 +1710,10 @@ q = f.exquo(g) assert q.get_domain().is_ZZ + def test_gcdex(): f, g = 2*x, x**2 - 16 - s, t, h = x/32, -Rational(1,16), 1 + s, t, h = x/32, -Rational(1, 16), 1 F, G, S, T, H = [ Poly(u, x, domain='QQ') for u in (f, g, s, t, h) ] @@ -1484,12 +1753,14 @@ raises(DomainError, lambda: gcdex(x + 1, 2*x + 1, auto=False)) raises(DomainError, lambda: invert(x + 1, 2*x + 1, auto=False)) + def test_revert(): f = Poly(1 - x**2/2 + x**4/24 - x**6/720) g = Poly(61*x**6/720 + 5*x**4/24 + x**2/2 + 1) assert f.revert(8) == g + def test_subresultants(): f, g, h = x**2 - 2*x + 1, x**2 - 1, 2*x - 2 F, G, H = Poly(f), Poly(g), Poly(h) @@ -1504,6 +1775,7 @@ raises(ComputationFailed, lambda: subresultants(4, 2)) + def test_resultant(): f, g, h = x**2 - 2*x + 1, x**2 - 1, 0 F, G = Poly(f), Poly(g) @@ -1515,6 +1787,7 @@ assert resultant(F, G) == h assert resultant(f, g, polys=True) == h assert resultant(F, G, polys=False) == h + assert resultant(f, g, includePRS=True) == (h, [f, g, 2*x - 2]) f, g, h = x - a, x - b, a - b F, G, H = Poly(f), Poly(g), Poly(h) @@ -1529,6 +1802,7 @@ raises(ComputationFailed, lambda: resultant(4, 2)) + def test_discriminant(): f, g = x**3 + 3*x**2 + 9*x - 13, -11664 F = Poly(f) @@ -1554,6 +1828,7 @@ raises(ComputationFailed, lambda: discriminant(4)) + def test_gcd_list(): F = [x**3 - 1, x**2 - 1, x**2 - 3*x + 2] @@ -1572,6 +1847,7 @@ raises(ComputationFailed, lambda: gcd_list([], polys=True)) + def test_lcm_list(): F = [x**3 - 1, x**2 - 1, x**2 - 3*x + 2] @@ -1590,6 +1866,7 @@ raises(ComputationFailed, lambda: lcm_list([], polys=True)) + def test_gcd(): f, g = x**3 - 1, x**2 - 1 s, t = x**2 + x + 1, x + 1 @@ -1659,6 +1936,30 @@ assert gcd(f, g, modulus=11, symmetric=False) == h assert lcm(f, g, modulus=11, symmetric=False) == l + raises(TypeError, lambda: gcd(x)) + raises(TypeError, lambda: lcm(x)) + + +def test_gcd_numbers_vs_polys(): + assert isinstance(gcd(3, 9), Integer) + assert isinstance(gcd(3*x, 9), Integer) + + assert gcd(3, 9) == 3 + assert gcd(3*x, 9) == 3 + + assert isinstance(gcd(S(3)/2, S(9)/4), Rational) + assert isinstance(gcd(S(3)/2*x, S(9)/4), Rational) + + assert gcd(S(3)/2, S(9)/4) == S(3)/4 + assert gcd(S(3)/2*x, S(9)/4) == 1 + + assert isinstance(gcd(3.0, 9.0), Float) + assert isinstance(gcd(3.0*x, 9.0), Float) + + assert gcd(3.0, 9.0) == 1.0 + assert gcd(3.0*x, 9.0) == 1.0 + + def test_terms_gcd(): assert terms_gcd(1) == 1 assert terms_gcd(1, x) == 1 @@ -1679,13 +1980,14 @@ assert terms_gcd(2.0*x**3*y + 4.1*x*y**3) == x*y*(2.0*x**2 + 4.1*y**2) - assert terms_gcd((3+3*x)*(x+x*y), expand=False) == \ + assert terms_gcd((3 + 3*x)*(x + x*y), expand=False) == \ (3*x + 3)*(x*y + x) assert terms_gcd((3 + 3*x)*(x + x*sin(3 + 3*y)), expand=False, deep=True) == \ 3*x*(x + 1)*(sin(Mul(3, y + 1, evaluate=False)) + 1) assert terms_gcd(sin(x + x*y), deep=True) == \ sin(x*(y + 1)) + def test_trunc(): f, g = x**5 + 2*x**4 + 3*x**3 + 4*x**2 + 5*x + 6, x**5 - x**4 + x**2 - x F, G = Poly(f), Poly(g) @@ -1713,6 +2015,7 @@ assert f.trunc(2) == Poly(x**2 + 1, modulus=5) + def test_monic(): f, g = 2*x - 1, x - S(1)/2 F, G = Poly(f, domain='QQ'), Poly(g) @@ -1733,6 +2036,7 @@ assert monic(2.0*x**2 + 6.0*x + 4.0) == 1.0*x**2 + 3.0*x + 2.0 assert monic(2*x**2 + 3*x + 4, modulus=5) == x**2 - x + 2 + def test_content(): f, F = 4*x + 2, Poly(4*x + 2) @@ -1745,6 +2049,7 @@ assert f.content() == 1 + def test_primitive(): f, g = 4*x + 2, 2*x + 1 F, G = Poly(f), Poly(g) @@ -1768,8 +2073,9 @@ assert primitive(S('-3*x/4 + y + 11/8')) == \ S('(1/8, -6*x + 8*y + 11)') + def test_compose(): - f = x**12+20*x**10+150*x**8+500*x**6+625*x**4-2*x**3-10*x+9 + f = x**12 + 20*x**10 + 150*x**8 + 500*x**6 + 625*x**4 - 2*x**3 - 10*x + 9 g = x**4 - 2*x + 9 h = x**3 + 5*x @@ -1794,12 +2100,14 @@ raises(ComputationFailed, lambda: compose(4, 2)) raises(ComputationFailed, lambda: decompose(4)) - assert compose(x**2 - y**2, x - y, x, y) == x**2 - 2*x*y + assert compose(x**2 - y**2, x - y, x, y) == x**2 - 2*x*y assert compose(x**2 - y**2, x - y, y, x) == -y**2 + 2*x*y + def test_shift(): assert Poly(x**2 - 2*x + 1, x).shift(2) == Poly(x**2 + 2*x + 1, x) + def test_sturm(): f, F = x, Poly(x, domain='QQ') g, G = 1, Poly(1, x, domain='QQ') @@ -1815,11 +2123,11 @@ raises(ComputationFailed, lambda: sturm(4)) raises(DomainError, lambda: sturm(f, auto=False)) - f = Poly(S(1024)/(15625*pi**8)*x**5 \ - - S(4096)/(625*pi**8)*x**4 \ - + S(32)/(15625*pi**4)*x**3 \ - - S(128)/(625*pi**4)*x**2 \ - + S(1)/62500*x \ + f = Poly(S(1024)/(15625*pi**8)*x**5 + - S(4096)/(625*pi**8)*x**4 + + S(32)/(15625*pi**4)*x**3 + - S(128)/(625*pi**4)*x**2 + + S(1)/62500*x - S(1)/625, x, domain='ZZ(pi)') assert sturm(f) == \ @@ -1828,6 +2136,7 @@ Poly((S(20000)/9 - pi**4/96)*x + 25*pi**4/18, x, domain='ZZ(pi)'), Poly((-3686400000000*pi**4 - 11520000*pi**8 - 9*pi**12)/(26214400000000 - 245760000*pi**4 + 576*pi**8), x, domain='ZZ(pi)')] + def test_gff(): f = x**5 + 2*x**4 - x**3 - 2*x**2 @@ -1838,25 +2147,28 @@ f = x*(x - 1)**3*(x - 2)**2*(x - 4)**2*(x - 5) - assert Poly(f).gff_list() == [(Poly(x**2 - 5*x + 4), 1), (Poly(x**2 - 5*x + 4), 2), (Poly(x), 3)] + assert Poly(f).gff_list() == [( + Poly(x**2 - 5*x + 4), 1), (Poly(x**2 - 5*x + 4), 2), (Poly(x), 3)] assert gff_list(f) == [(x**2 - 5*x + 4, 1), (x**2 - 5*x + 4, 2), (x, 3)] raises(NotImplementedError, lambda: gff(f)) + def test_sqf_norm(): - assert sqf_norm(x**2-2, extension=sqrt(3)) == \ + assert sqf_norm(x**2 - 2, extension=sqrt(3)) == \ (1, x**2 - 2*sqrt(3)*x + 1, x**4 - 10*x**2 + 1) - assert sqf_norm(x**2-3, extension=sqrt(2)) == \ + assert sqf_norm(x**2 - 3, extension=sqrt(2)) == \ (1, x**2 - 2*sqrt(2)*x - 1, x**4 - 10*x**2 + 1) - assert Poly(x**2-2, extension=sqrt(3)).sqf_norm() == \ + assert Poly(x**2 - 2, extension=sqrt(3)).sqf_norm() == \ (1, Poly(x**2 - 2*sqrt(3)*x + 1, x, extension=sqrt(3)), Poly(x**4 - 10*x**2 + 1, x, domain='QQ')) - assert Poly(x**2-3, extension=sqrt(2)).sqf_norm() == \ + assert Poly(x**2 - 3, extension=sqrt(2)).sqf_norm() == \ (1, Poly(x**2 - 2*sqrt(2)*x - 1, x, extension=sqrt(2)), Poly(x**4 - 10*x**2 + 1, x, domain='QQ')) + def test_sqf(): f = x**5 - x**3 - x**2 + 1 g = x**3 + 2*x**2 + 2*x + 1 @@ -1919,6 +2231,7 @@ assert sqf(f) == (x + 1)**40000000000 assert sqf_list(f) == (1, [(x + 1, 40000000000)]) + def test_factor(): f = x**5 - x**3 - x**2 + 1 @@ -1943,10 +2256,9 @@ assert factor_list(sqrt(3), x) == (1, [(3, S.Half)]) assert factor_list((-1)**x, x) == (1, [(-1, x)]) assert factor_list((2*x)**y, x) == (1, [(2, y), (x, y)]) - assert factor_list(sqrt(x*y),x) == (1, [(x*y, S.Half)]) + assert factor_list(sqrt(x*y), x) == (1, [(x*y, S.Half)]) - assert factor(1) == 1 - assert factor(6) == 6 + assert factor(6) == 6 and factor(6).is_Integer assert factor_list(3*x) == (3, [(x, 1)]) assert factor_list(3*x**2) == (3, [(x, 2)]) @@ -1970,7 +2282,7 @@ i = Symbol('i', integer=True) r = Symbol('r', real=True) - assert factor(sqrt(x*y)).is_Pow == True + assert factor(sqrt(x*y)).is_Pow is True assert factor(sqrt(3*x**2 - 3)) == sqrt(3)*sqrt((x - 1)*(x + 1)) assert factor(sqrt(3*x**2 + 3)) == sqrt(3)*sqrt(x**2 + 1) @@ -2002,7 +2314,8 @@ assert factor(f) == f assert factor(f, extension=I) == (x**2 - I)*(x**2 + I) assert factor(f, gaussian=True) == (x**2 - I)*(x**2 + I) - assert factor(f, extension=sqrt(2)) == (x**2 + sqrt(2)*x + 1)*(x**2 - sqrt(2)*x + 1) + assert factor( + f, extension=sqrt(2)) == (x**2 + sqrt(2)*x + 1)*(x**2 - sqrt(2)*x + 1) f = x**2 + 2*sqrt(2)*x + 2 @@ -2017,10 +2330,15 @@ assert factor(x - 1) == x - 1 assert factor(-x - 1) == -x - 1 + assert factor(x - 1) == x - 1 + + assert factor(6*x - 10) == Mul(2, 3*x - 5, evaluate=False) + assert factor(x**11 + x + 1, modulus=65537, symmetric=True) == \ (x**2 + x + 1)*(x**9 - x**8 + x**6 - x**5 + x**3 - x** 2 + 1) assert factor(x**11 + x + 1, modulus=65537, symmetric=False) == \ - (x**2 + x + 1)*(x**9 + 65536*x**8 + x**6 + 65536*x**5 + x**3 + 65536*x** 2 + 1) + (x**2 + x + 1)*(x**9 + 65536*x**8 + x**6 + 65536*x**5 + + x**3 + 65536*x** 2 + 1) f = x/pi + x*sin(x)/pi g = y/(pi**2 + 2*pi + 1) + y*sin(x)/(pi**2 + 2*pi + 1) @@ -2028,7 +2346,8 @@ assert factor(f) == x*(sin(x) + 1)/pi assert factor(g) == y*(sin(x) + 1)/(pi + 1)**2 - assert factor(Eq(x**2 + 2*x + 1, x**3 + 1)) == Eq((x + 1)**2, (x + 1)*(x**2 - x + 1)) + assert factor(Eq( + x**2 + 2*x + 1, x**3 + 1)) == Eq((x + 1)**2, (x + 1)*(x**2 - x + 1)) f = (x**2 - 1)/(x**2 + 4*x + 4) @@ -2040,7 +2359,8 @@ assert factor(f) == 3 assert factor(f, x) == 3 - assert factor(1/(x**2 + 2*x + 1/x) - 1) == -((1 - x + 2*x**2 + x**3)/(1 + 2*x**2 + x**3)) + assert factor(1/(x**2 + 2*x + 1/x) - 1) == -((1 - x + 2*x**2 + + x**3)/(1 + 2*x**2 + x**3)) assert factor(f, expand=False) == f raises(PolynomialError, lambda: factor(f, x, expand=False)) @@ -2050,8 +2370,10 @@ assert factor([x, Eq(x**2 - y**2, Tuple(x**2 - z**2, 1/x + 1/y))]) == \ [x, Eq((x - y)*(x + y), Tuple((x - z)*(x + z), (x + y)/x/y))] - assert not isinstance(Poly(x**3 + x + 1).factor_list()[1][0][0], PurePoly) == True - assert isinstance(PurePoly(x**3 + x + 1).factor_list()[1][0][0], PurePoly) == True + assert not isinstance( + Poly(x**3 + x + 1).factor_list()[1][0][0], PurePoly) is True + assert isinstance( + PurePoly(x**3 + x + 1).factor_list()[1][0][0], PurePoly) is True assert factor(sqrt(-x)) == sqrt(-x) @@ -2061,34 +2383,46 @@ x*(x - 1)))*(x**2*(x - 1)**4 - x*(-x*(-x + 1)*(x - 1) - x*(x - 1)**2))) assert factor(e) == 0 + # deep option + assert factor(sin(x**2 + x) + x, deep=True) == sin(x*(x + 1)) + x + + def test_factor_large(): f = (x**2 + 4*x + 4)**10000000*(x**2 + 1)*(x**2 + 2*x + 1)**1234567 - g = ((x**2 + 2*x + 1)**3000*y**2 + (x**2 + 2*x + 1)**3000*2*y + (x**2 + 2*x + 1)**3000) + g = ((x**2 + 2*x + 1)**3000*y**2 + (x**2 + 2*x + 1)**3000*2*y + ( + x**2 + 2*x + 1)**3000) assert factor(f) == (x + 2)**20000000*(x**2 + 1)*(x + 1)**2469134 assert factor(g) == (x + 1)**6000*(y + 1)**2 - assert factor_list(f) == (1, [(x + 1, 2469134), (x + 2, 20000000), (x**2 + 1, 1)]) + assert factor_list( + f) == (1, [(x + 1, 2469134), (x + 2, 20000000), (x**2 + 1, 1)]) assert factor_list(g) == (1, [(y + 1, 2), (x + 1, 6000)]) f = (x**2 - y**2)**200000*(x**7 + 1) g = (x**2 + y**2)**200000*(x**7 + 1) assert factor(f) == \ - (x + 1)*(x - y)**200000*(x + y)**200000*(x**6 - x**5 + x**4 - x**3 + x**2 - x + 1) + (x + 1)*(x - y)**200000*(x + y)**200000*(x**6 - x**5 + + x**4 - x**3 + x**2 - x + 1) assert factor(g, gaussian=True) == \ - (x + 1)*(x - I*y)**200000*(x + I*y)**200000*(x**6 - x**5 + x**4 - x**3 + x**2 - x + 1) + (x + 1)*(x - I*y)**200000*(x + I*y)**200000*(x**6 - x**5 + + x**4 - x**3 + x**2 - x + 1) assert factor_list(f) == \ - (1, [(x + 1, 1), (x - y, 200000), (x + y, 200000), (x**6 - x**5 + x**4 - x**3 + x**2 - x + 1, 1)]) + (1, [(x + 1, 1), (x - y, 200000), (x + y, 200000), (x**6 - + x**5 + x**4 - x**3 + x**2 - x + 1, 1)]) assert factor_list(g, gaussian=True) == \ - (1, [(x + 1, 1), (x - I*y, 200000), (x + I*y, 200000), (x**6 - x**5 + x**4 - x**3 + x**2 - x + 1, 1)]) + (1, [(x + 1, 1), (x - I*y, 200000), (x + I*y, 200000), ( + x**6 - x**5 + x**4 - x**3 + x**2 - x + 1, 1)]) + @XFAIL def test_factor_noeval(): assert factor(6*x - 10) == 2*(3*x - 5) assert factor((6*x - 10)/(3*x - 6)) == S(2)/3*((3*x - 5)/(x - 2)) + def test_intervals(): assert intervals(0) == [] assert intervals(1) == [] @@ -2130,7 +2464,7 @@ assert intervals(f, eps=S(1)/10000) == intervals(f, eps=0.0001) == \ [((-S(1)/1028, -S(1)/1028), 1), ((S(85)/6, S(85)/6), 1)] - f = Poly((x**2 - 2)*(x**2-3)**7*(x+1)*(7*x+3)**3) + f = Poly((x**2 - 2)*(x**2 - 3)**7*(x + 1)*(7*x + 3)**3) assert f.intervals() == \ [((-2, -S(3)/2), 7), ((-S(3)/2, -1), 1), @@ -2144,10 +2478,12 @@ [((S(75)/26, S(101)/35), {0: 1}), ((S(283)/98, S(26)/9), {1: 1})] assert intervals([x**2 - 200, x**2 - 201]) == \ - [((-S(71)/5, -S(85)/6), {1: 1}), ((-S(85)/6, -14), {0: 1}), ((14, S(85)/6), {0: 1}), ((S(85)/6, S(71)/5), {1: 1})] + [((-S(71)/5, -S(85)/6), {1: 1}), ((-S(85)/6, -14), {0: 1}), + ((14, S(85)/6), {0: 1}), ((S(85)/6, S(71)/5), {1: 1})] - assert intervals([x+1, x+2, x-1, x+1, 1, x-1, x-1, (x-2)**2]) == \ - [((-2, -2), {1: 1}), ((-1, -1), {0: 1, 3: 1}), ((1, 1), {2: 1, 5: 1, 6: 1}), ((2, 2), {7: 2})] + assert intervals([x + 1, x + 2, x - 1, x + 1, 1, x - 1, x - 1, (x - 2)**2]) == \ + [((-2, -2), {1: 1}), ((-1, -1), {0: 1, 3: 1}), ((1, 1), {2: + 1, 5: 1, 6: 1}), ((2, 2), {7: 2})] f, g, h = x**2 - 2, x**4 - 4*x**2 + 4, x - 1 @@ -2163,12 +2499,14 @@ assert intervals([g, h], inf=S(7)/4) == [] assert intervals([g, h], inf=S(7)/5) == [((S(7)/5, S(3)/2), {0: 2})] - assert intervals([g, h], sup=S(7)/4) == [((-2, -1), {0: 2}), ((1, 1), {1: 1}), ((1, S(3)/2), {0: 2})] - assert intervals([g, h], sup=S(7)/5) == [((-2, -1), {0: 2}), ((1, 1), {1: 1})] + assert intervals([g, h], sup=S( + 7)/4) == [((-2, -1), {0: 2}), ((1, 1), {1: 1}), ((1, S(3)/2), {0: 2})] + assert intervals( + [g, h], sup=S(7)/5) == [((-2, -1), {0: 2}), ((1, 1), {1: 1})] - assert intervals([x+2, x**2 - 2]) == \ + assert intervals([x + 2, x**2 - 2]) == \ [((-2, -2), {0: 1}), ((-2, -1), {1: 1}), ((1, 2), {1: 1})] - assert intervals([x+2, x**2 - 2], strict=True) == \ + assert intervals([x + 2, x**2 - 2], strict=True) == \ [((-2, -2), {0: 1}), ((-S(3)/2, -1), {1: 1}), ((1, 2), {1: 1})] f = 7*z**4 - 19*z**3 + 20*z**2 + 17*z + 20 @@ -2178,7 +2516,8 @@ real_part, complex_part = intervals(f, all=True, sqf=True) assert real_part == [] - assert all(re(a) < re(r) < re(b) and im(a) < im(r) < im(b) for (a, b), r in zip(complex_part, nroots(f))) + assert all(re(a) < re(r) < re(b) and im( + a) < im(r) < im(b) for (a, b), r in zip(complex_part, nroots(f))) assert complex_part == [(-S(40)/7 - 40*I/7, 0), (-S(40)/7, 40*I/7), (-40*I/7, S(40)/7), (0, S(40)/7 + 40*I/7)] @@ -2186,11 +2525,14 @@ real_part, complex_part = intervals(f, all=True, sqf=True, eps=S(1)/10) assert real_part == [] - assert all(re(a) < re(r) < re(b) and im(a) < im(r) < im(b) for (a, b), r in zip(complex_part, nroots(f))) + assert all(re(a) < re(r) < re(b) and im( + a) < im(r) < im(b) for (a, b), r in zip(complex_part, nroots(f))) raises(ValueError, lambda: intervals(x**2 - 2, eps=10**-100000)) raises(ValueError, lambda: Poly(x**2 - 2).intervals(eps=10**-100000)) - raises(ValueError, lambda: intervals([x**2 - 2, x**2 - 3], eps=10**-100000)) + raises( + ValueError, lambda: intervals([x**2 - 2, x**2 - 3], eps=10**-100000)) + def test_refine_root(): f = Poly(x**2 - 2) @@ -2231,6 +2573,7 @@ raises(ValueError, lambda: Poly(f).refine_root(1, 2, eps=10**-100000)) raises(ValueError, lambda: refine_root(f, 1, 2, eps=10**-100000)) + def test_count_roots(): assert count_roots(x**2 - 2) == 2 @@ -2266,6 +2609,7 @@ raises(PolynomialError, lambda: count_roots(1)) + def test_Poly_root(): f = Poly(2*x**3 - 7*x**2 + 4*x + 4) @@ -2276,6 +2620,7 @@ assert Poly(x**5 + x + 1).root(0) == RootOf(x**3 - x**2 + 1, 0) + def test_real_roots(): assert real_roots(x) == [0] assert real_roots(x, multiple=False) == [(0, 1)] @@ -2284,10 +2629,13 @@ assert real_roots(x**3, multiple=False) == [(0, 3)] assert real_roots(x*(x**3 + x + 3)) == [RootOf(x**3 + x + 3, 0), 0] - assert real_roots(x*(x**3 + x + 3), multiple=False) == [(RootOf(x**3 + x + 3, 0), 1), (0, 1)] + assert real_roots(x*(x**3 + x + 3), multiple=False) == [(RootOf( + x**3 + x + 3, 0), 1), (0, 1)] - assert real_roots(x**3*(x**3 + x + 3)) == [RootOf(x**3 + x + 3, 0), 0, 0, 0] - assert real_roots(x**3*(x**3 + x + 3), multiple=False) == [(RootOf(x**3 + x + 3, 0), 1), (0, 3)] + assert real_roots( + x**3*(x**3 + x + 3)) == [RootOf(x**3 + x + 3, 0), 0, 0, 0] + assert real_roots(x**3*(x**3 + x + 3), multiple=False) == [(RootOf( + x**3 + x + 3, 0), 1), (0, 3)] f = 2*x**3 - 7*x**2 + 4*x + 4 g = x**3 + x + 1 @@ -2295,6 +2643,7 @@ assert Poly(f).real_roots() == [-S(1)/2, 2, 2] assert Poly(g).real_roots() == [RootOf(g, 0)] + def test_all_roots(): f = 2*x**3 - 7*x**2 + 4*x + 4 g = x**3 + x + 1 @@ -2302,6 +2651,7 @@ assert Poly(f).all_roots() == [-S(1)/2, 2, 2] assert Poly(g).all_roots() == [RootOf(g, 0), RootOf(g, 1), RootOf(g, 2)] + def test_nroots(): assert Poly(0, x).nroots() == [] assert Poly(1, x).nroots() == [] @@ -2310,19 +2660,20 @@ assert Poly(x**2 + 1, x).nroots() == [-1.0*I, 1.0*I] roots, error = Poly(x**2 - 1, x).nroots(error=True) - assert roots == [-1.0, 1.0] and error < 1e25; + assert roots == [-1.0, 1.0] and error < 1e25 roots, error = Poly(x**2 + 1, x).nroots(error=True) - assert roots == [-1.0*I, 1.0*I] and error < 1e25; + assert roots == [-1.0*I, 1.0*I] and error < 1e25 roots, error = Poly(x**2/3 - S(1)/3, x).nroots(error=True) - assert roots == [-1.0, 1.0] and error < 1e25; + assert roots == [-1.0, 1.0] and error < 1e25 roots, error = Poly(x**2/3 + S(1)/3, x).nroots(error=True) - assert roots == [-1.0*I, 1.0*I] and error < 1e25; + assert roots == [-1.0*I, 1.0*I] and error < 1e25 assert Poly(x**2 + 2*I, x).nroots() == [-1.0 + 1.0*I, 1.0 - 1.0*I] - assert Poly(x**2 + 2*I, x, extension=I).nroots() == [-1.0 + 1.0*I, 1.0 - 1.0*I] + assert Poly( + x**2 + 2*I, x, extension=I).nroots() == [-1.0 + 1.0*I, 1.0 - 1.0*I] assert Poly(0.2*x + 0.1).nroots() == [-0.5] @@ -2330,7 +2681,7 @@ eps = Float("1e-5") assert re(roots[0]).epsilon_eq(-0.75487, eps) is True - assert im(roots[0]) == 0.0 + assert im(roots[0]) == 0.0 assert re(roots[1]) == -0.5 assert im(roots[1]).epsilon_eq(-0.86602, eps) is True assert re(roots[2]) == -0.5 @@ -2343,7 +2694,7 @@ eps = Float("1e-6") assert re(roots[0]).epsilon_eq(-0.75487, eps) is False - assert im(roots[0]) == 0.0 + assert im(roots[0]) == 0.0 assert re(roots[1]) == -0.5 assert im(roots[1]).epsilon_eq(-0.86602, eps) is False assert re(roots[2]) == -0.5 @@ -2359,19 +2710,21 @@ assert nroots(x**2 - 1) == [-1.0, 1.0] roots, error = nroots(x**2 - 1, error=True) - assert roots == [-1.0, 1.0] and error < 1e25; + assert roots == [-1.0, 1.0] and error < 1e25 assert nroots(x + I) == [-1.0*I] assert nroots(x + 2*I) == [-2.0*I] raises(PolynomialError, lambda: nroots(0)) + def test_ground_roots(): f = x**6 - 4*x**4 + 4*x**3 - x**2 assert Poly(f).ground_roots() == {S(1): 2, S(0): 2} assert ground_roots(f) == {S(1): 2, S(0): 2} + def test_nth_power_roots_poly(): f = x**4 - x**2 + 1 @@ -2390,7 +2743,19 @@ assert factor(nth_power_roots_poly(f, 4)) == f_4 assert factor(nth_power_roots_poly(f, 12)) == f_12 - raises(MultivariatePolynomialError, lambda: nth_power_roots_poly(x + y, 2, x, y)) + raises(MultivariatePolynomialError, lambda: nth_power_roots_poly( + x + y, 2, x, y)) + +def test_torational_factor_list(): + p = expand(((x**2-1)*(x-2)).subs({x:x*(1 + sqrt(2))})) + assert _torational_factor_list(p, x) == (-2, [ + (-x*(1 + sqrt(2))/2 + 1, 1), + (-x*(1 + sqrt(2)) - 1, 1), + (-x*(1 + sqrt(2)) + 1, 1)]) + + + p = expand(((x**2-1)*(x-2)).subs({x:x*(1 + 2**Rational(1, 4))})) + assert _torational_factor_list(p, x) is None def test_cancel(): assert cancel(0) == 0 @@ -2404,7 +2769,7 @@ assert cancel((1, 0), x) == (1, 1, 0) assert cancel((0, 1), x) == (1, 0, 1) - f, g, p, q = 4*x**2-4, 2*x-2, 2*x+2, 1 + f, g, p, q = 4*x**2 - 4, 2*x - 2, 2*x + 2, 1 F, G, P, Q = [ Poly(u, x) for u in (f, g, p, q) ] assert F.cancel(G) == (1, P, Q) @@ -2427,14 +2792,14 @@ assert cancel((x**2/4 - 1, x/2 - 1)) == (S(1)/2, x + 2, 1) - assert cancel((x**2-y)/(x-y)) == 1/(x - y)*(x**2 - y) + assert cancel((x**2 - y)/(x - y)) == 1/(x - y)*(x**2 - y) - assert cancel((x**2-y**2)/(x-y), x) == x + y - assert cancel((x**2-y**2)/(x-y), y) == x + y - assert cancel((x**2-y**2)/(x-y)) == x + y + assert cancel((x**2 - y**2)/(x - y), x) == x + y + assert cancel((x**2 - y**2)/(x - y), y) == x + y + assert cancel((x**2 - y**2)/(x - y)) == x + y - assert cancel((x**3-1)/(x**2-1)) == (x**2+x+1)/(x+1) - assert cancel((x**3/2-S(1)/2)/(x**2-1)) == (x**2+x+1)/(2*x+2) + assert cancel((x**3 - 1)/(x**2 - 1)) == (x**2 + x + 1)/(x + 1) + assert cancel((x**3/2 - S(1)/2)/(x**2 - 1)) == (x**2 + x + 1)/(2*x + 2) assert cancel((exp(2*x) + 2*exp(x) + 1)/(exp(x) + 1)) == exp(x) + 1 @@ -2459,13 +2824,30 @@ f = Poly(y, y, domain='ZZ(x)') g = Poly(1, y, domain='ZZ[x]') - assert f.cancel(g) == (1, Poly(y, y, domain='ZZ(x)'), Poly(1, y, domain='ZZ(x)')) - assert f.cancel(g, include=True) == (Poly(y, y, domain='ZZ(x)'), Poly(1, y, domain='ZZ(x)')) + assert f.cancel( + g) == (1, Poly(y, y, domain='ZZ(x)'), Poly(1, y, domain='ZZ(x)')) + assert f.cancel(g, include=True) == ( + Poly(y, y, domain='ZZ(x)'), Poly(1, y, domain='ZZ(x)')) f = Poly(5*x*y + x, y, domain='ZZ(x)') g = Poly(2*x**2*y, y, domain='ZZ(x)') - assert f.cancel(g, include=True) == (Poly(5*y + 1, y, domain='ZZ(x)'), Poly(2*x*y, y, domain='ZZ(x)')) + assert f.cancel(g, include=True) == ( + Poly(5*y + 1, y, domain='ZZ(x)'), Poly(2*x*y, y, domain='ZZ(x)')) + + # issue 3923 + A = Symbol('A', commutative=False) + p1 = Piecewise((A*(x**2 - 1)/(x + 1), x > 1), (0, True)) + p2 = Piecewise((A*(x - 1), x > 1), (0, True)) + assert cancel(p1) == p2 + + +@XFAIL +def test_cancel_xfail(): + p3 = Piecewise(((x**2 - 1)/(x + 1), x > 1), (0, True)) + p4 = Piecewise(((x - 1), x > 1), (0, True)) + assert cancel(p3) == p4 + def test_reduced(): f = 2*x**4 + y**2 - x**2 + y**3 @@ -2503,12 +2885,13 @@ assert reduced(f, G, auto=False)[1] != 0 assert G.reduce(f, auto=False)[1] != 0 - assert G.contains(f) == True - assert G.contains(f + 1) == False + assert G.contains(f) is True + assert G.contains(f + 1) is False assert reduced(1, [1], x) == ([1], 0) raises(ComputationFailed, lambda: reduced(1, [1])) + def test_groebner(): assert groebner([], x, y, z) == [] @@ -2520,7 +2903,8 @@ assert groebner([x**2 + 1, y**4*x + x**3], x, y, order='lex', polys=True) == \ [Poly(1 + x**2, x, y), Poly(-1 + y**4, x, y)] assert groebner([x**2 + 1, y**4*x + x**3, x*y*z**3], x, y, z, order='grevlex', polys=True) == \ - [Poly(-1 + y**4, x, y, z), Poly(z**3, x, y, z), Poly(1 + x**2, x, y, z)] + [Poly( + -1 + y**4, x, y, z), Poly(z**3, x, y, z), Poly(1 + x**2, x, y, z)] assert groebner([x**3 - 1, x**2 - 1]) == [x - 1] assert groebner([Eq(x**3, 1), Eq(x**2, 1)]) == [x - 1] @@ -2558,11 +2942,12 @@ raises(ValueError, lambda: groebner([x, y], method='unknown')) + def test_fglm(): F = [a + b + c + d, a*b + a*d + b*c + b*d, a*b*c + a*b*d + a*c*d + b*c*d, a*b*c*d - 1] - G = groebner(F, a, b, c, d, order='grlex') + G = groebner(F, a, b, c, d, order=grlex) - assert G.fglm('lex') == [ + B = [ 4*a + 3*d**9 - 4*d**5 - 3*d, 4*b + 4*c - 3*d**9 + 4*d**5 + 7*d, 4*c**2 + 3*d**10 - 4*d**6 - 3*d**2, @@ -2570,38 +2955,49 @@ d**12 - d**8 - d**4 + 1, ] + assert groebner(F, a, b, c, d, order=lex) == B + assert G.fglm(lex) == B + F = [9*x**8 + 36*x**7 - 32*x**6 - 252*x**5 - 78*x**4 + 468*x**3 + 288*x**2 - 108*x + 9, -72*t*x**7 - 252*t*x**6 + 192*t*x**5 + 1260*t*x**4 + 312*t*x**3 - 404*t*x**2 - 576*t*x + \ 108*t - 72*x**7 - 256*x**6 + 192*x**5 + 1280*x**4 + 312*x**3 - 576*x + 96] - G = groebner(F, t, x, order='grlex') + G = groebner(F, t, x, order=grlex) - assert G.fglm('lex') == [ + B = [ 203577793572507451707*t + 627982239411707112*x**7 - 666924143779443762*x**6 - \ 10874593056632447619*x**5 + 5119998792707079562*x**4 + 72917161949456066376*x**3 + \ 20362663855832380362*x**2 - 142079311455258371571*x + 183756699868981873194, 9*x**8 + 36*x**7 - 32*x**6 - 252*x**5 - 78*x**4 + 468*x**3 + 288*x**2 - 108*x + 9, ] + assert groebner(F, t, x, order=lex) == B + assert G.fglm(lex) == B + F = [x**2 - x - 3*y + 1, -2*x + y**2 + y - 1] - G = groebner(F, x, y, order='lex') + G = groebner(F, x, y, order=lex) - assert G.fglm('grlex') == [ + B = [ x**2 - x - 3*y + 1, y**2 - 2*x + y - 1, ] + assert groebner(F, x, y, order=grlex) == B + assert G.fglm(grlex) == B + + def test_is_zero_dimensional(): - assert is_zero_dimensional([x, y], x, y) == True - assert is_zero_dimensional([x**3 + y**2], x, y) == False + assert is_zero_dimensional([x, y], x, y) is True + assert is_zero_dimensional([x**3 + y**2], x, y) is False - assert is_zero_dimensional([x, y, z], x, y, z) == True - assert is_zero_dimensional([x, y, z], x, y, z, t) == False + assert is_zero_dimensional([x, y, z], x, y, z) is True + assert is_zero_dimensional([x, y, z], x, y, z, t) is False F = [x*y - z, y*z - x, x*y - y] - assert is_zero_dimensional(F, x, y, z) == True + assert is_zero_dimensional(F, x, y, z) is True F = [x**2 - 2*x*z + 5, x*y**2 + y*z**3, 3*y**2 - 8*z**2] - assert is_zero_dimensional(F, x, y, z) == True + assert is_zero_dimensional(F, x, y, z) is True + def test_GroebnerBasis(): F = [x*y - 2*y, 2*y**2 - x**2] @@ -2610,7 +3006,7 @@ H = [y**3 - 2*y, x**2 - 2*y**2, x*y - 2*y] P = [ Poly(h, x, y) for h in H ] - assert isinstance(G, GroebnerBasis) == True + assert isinstance(G, GroebnerBasis) is True assert len(G) == 3 @@ -2643,6 +3039,7 @@ assert G[1:] == P[1:] and all(g.is_Poly for g in G[1:]) assert G[:2] == P[:2] and all(g.is_Poly for g in G[1:]) + def test_poly(): assert poly(x) == Poly(x, x) assert poly(y) == Poly(y, y) @@ -2656,17 +3053,23 @@ assert poly(x*y + 2*x*z**2 + 17) == Poly(x*y + 2*x*z**2 + 17, x, y, z) assert poly(2*(y + z)**2 - 1) == Poly(2*y**2 + 4*y*z + 2*z**2 - 1, y, z) - assert poly(x*(y + z)**2 - 1) == Poly(x*y**2 + 2*x*y*z + x*z**2 - 1, x, y, z) - assert poly(2*x*(y + z)**2 - 1) == Poly(2*x*y**2 + 4*x*y*z + 2*x*z**2 - 1, x, y, z) - - assert poly(2*(y + z)**2 - x - 1) == Poly(2*y**2 + 4*y*z + 2*z**2 - x - 1, x, y, z) - assert poly(x*(y + z)**2 - x - 1) == Poly(x*y**2 + 2*x*y*z + x*z**2 - x - 1, x, y, z) - assert poly(2*x*(y + z)**2 - x - 1) == Poly(2*x*y**2 + 4*x*y*z + 2*x*z**2 - x - 1, x, y, z) + assert poly( + x*(y + z)**2 - 1) == Poly(x*y**2 + 2*x*y*z + x*z**2 - 1, x, y, z) + assert poly(2*x*( + y + z)**2 - 1) == Poly(2*x*y**2 + 4*x*y*z + 2*x*z**2 - 1, x, y, z) + + assert poly(2*( + y + z)**2 - x - 1) == Poly(2*y**2 + 4*y*z + 2*z**2 - x - 1, x, y, z) + assert poly(x*( + y + z)**2 - x - 1) == Poly(x*y**2 + 2*x*y*z + x*z**2 - x - 1, x, y, z) + assert poly(2*x*(y + z)**2 - x - 1) == Poly(2*x*y**2 + 4*x*y*z + 2* + x*z**2 - x - 1, x, y, z) assert poly(x*y + (x + y)**2 + (x + z)**2) == \ Poly(2*x*z + 3*x*y + y**2 + z**2 + 2*x**2, x, y, z) assert poly(x*y*(x + y)*(x + z)**2) == \ - Poly(x**3*y**2 + x*y**2*z**2 + y*x**2*z**2 + 2*z*x**2*y**2 + 2*y*z*x**3 + y*x**4, x, y, z) + Poly(x**3*y**2 + x*y**2*z**2 + y*x**2*z**2 + 2*z*x**2* + y**2 + 2*y*z*x**3 + y*x**4, x, y, z) assert poly(Poly(x + y + z, y, x, z)) == Poly(x + y + z, y, x, z) @@ -2680,6 +3083,7 @@ assert poly(x + y, x, y) == Poly(x + y, x, y) assert poly(x + y, y, x) == Poly(x + y, y, x) + def test_keep_coeff(): u = Mul(2, x + 1, evaluate=False) assert _keep_coeff(S(1), x) == x @@ -2691,6 +3095,7 @@ assert _keep_coeff(x, 1/x) == 1 assert _keep_coeff(x + 1, S(2)) == u + @XFAIL def test_poly_matching_consistency(): # Test for this issue: @@ -2698,6 +3103,18 @@ assert I * Poly(x, x) == Poly(I*x, x) assert Poly(x, x) * I == Poly(I*x, x) + @XFAIL def test_issue_2687(): - assert expand(factor(expand((x - I*y)*(z - I*t)), extension=[I])) == -I*t*x - t*y + x*z - I*y*z + assert expand(factor(expand( + (x - I*y)*(z - I*t)), extension=[I])) == -I*t*x - t*y + x*z - I*y*z + + +def test_noncommutative(): + class foo(Expr): + is_commutative=False + e = x/(x + x*y) + c = 1/( 1 + y) + assert cancel(foo(e)) == foo(c) + assert cancel(e + foo(e)) == c + foo(c) + assert cancel(e*foo(c)) == c*foo(c) diff -Nru python3-sympy-0.7.2/sympy/polys/tests/test_polyutils.py python3-sympy-0.7.3/sympy/polys/tests/test_polyutils.py --- python3-sympy-0.7.2/sympy/polys/tests/test_polyutils.py 2012-10-17 03:02:22.000000000 +0000 +++ python3-sympy-0.7.3/sympy/polys/tests/test_polyutils.py 2013-07-13 17:53:32.000000000 +0000 @@ -24,9 +24,10 @@ from sympy.polys.domains import ZZ, QQ, EX -x,y,z,p,q,r,s,t,u,v,w = symbols('x,y,z,p,q,r,s,t,u,v,w') +x, y, z, p, q, r, s, t, u, v, w = symbols('x,y,z,p,q,r,s,t,u,v,w') A, B = symbols('A,B', commutative=False) + def test__sort_gens(): assert _sort_gens([]) == () @@ -34,157 +35,177 @@ assert _sort_gens([p]) == (p,) assert _sort_gens([q]) == (q,) - assert _sort_gens([x,p]) == (x,p) - assert _sort_gens([p,x]) == (x,p) - assert _sort_gens([q,p]) == (p,q) - - assert _sort_gens([q,p,x]) == (x,p,q) - - assert _sort_gens([x,p,q], wrt=x) == (x,p,q) - assert _sort_gens([x,p,q], wrt=p) == (p,x,q) - assert _sort_gens([x,p,q], wrt=q) == (q,x,p) - - assert _sort_gens([x,p,q], wrt='x') == (x,p,q) - assert _sort_gens([x,p,q], wrt='p') == (p,x,q) - assert _sort_gens([x,p,q], wrt='q') == (q,x,p) - - assert _sort_gens([x,p,q], wrt='x,q') == (x,q,p) - assert _sort_gens([x,p,q], wrt='q,x') == (q,x,p) - assert _sort_gens([x,p,q], wrt='p,q') == (p,q,x) - assert _sort_gens([x,p,q], wrt='q,p') == (q,p,x) - - assert _sort_gens([x,p,q], wrt='x, q') == (x,q,p) - assert _sort_gens([x,p,q], wrt='q, x') == (q,x,p) - assert _sort_gens([x,p,q], wrt='p, q') == (p,q,x) - assert _sort_gens([x,p,q], wrt='q, p') == (q,p,x) - - assert _sort_gens([x,p,q], wrt=[x, 'q']) == (x,q,p) - assert _sort_gens([x,p,q], wrt=[q, 'x']) == (q,x,p) - assert _sort_gens([x,p,q], wrt=[p, 'q']) == (p,q,x) - assert _sort_gens([x,p,q], wrt=[q, 'p']) == (q,p,x) - - assert _sort_gens([x,p,q], wrt=['x', 'q']) == (x,q,p) - assert _sort_gens([x,p,q], wrt=['q', 'x']) == (q,x,p) - assert _sort_gens([x,p,q], wrt=['p', 'q']) == (p,q,x) - assert _sort_gens([x,p,q], wrt=['q', 'p']) == (q,p,x) - - assert _sort_gens([x,p,q], sort='x > p > q') == (x, p, q) - assert _sort_gens([x,p,q], sort='p > x > q') == (p, x, q) - assert _sort_gens([x,p,q], sort='p > q > x') == (p, q, x) - - assert _sort_gens([x,p,q], wrt='x', sort='q > p') == (x, q, p) - assert _sort_gens([x,p,q], wrt='p', sort='q > x') == (p, q, x) - assert _sort_gens([x,p,q], wrt='q', sort='p > x') == (q, p, x) + assert _sort_gens([x, p]) == (x, p) + assert _sort_gens([p, x]) == (x, p) + assert _sort_gens([q, p]) == (p, q) + + assert _sort_gens([q, p, x]) == (x, p, q) + + assert _sort_gens([x, p, q], wrt=x) == (x, p, q) + assert _sort_gens([x, p, q], wrt=p) == (p, x, q) + assert _sort_gens([x, p, q], wrt=q) == (q, x, p) + + assert _sort_gens([x, p, q], wrt='x') == (x, p, q) + assert _sort_gens([x, p, q], wrt='p') == (p, x, q) + assert _sort_gens([x, p, q], wrt='q') == (q, x, p) + + assert _sort_gens([x, p, q], wrt='x,q') == (x, q, p) + assert _sort_gens([x, p, q], wrt='q,x') == (q, x, p) + assert _sort_gens([x, p, q], wrt='p,q') == (p, q, x) + assert _sort_gens([x, p, q], wrt='q,p') == (q, p, x) + + assert _sort_gens([x, p, q], wrt='x, q') == (x, q, p) + assert _sort_gens([x, p, q], wrt='q, x') == (q, x, p) + assert _sort_gens([x, p, q], wrt='p, q') == (p, q, x) + assert _sort_gens([x, p, q], wrt='q, p') == (q, p, x) + + assert _sort_gens([x, p, q], wrt=[x, 'q']) == (x, q, p) + assert _sort_gens([x, p, q], wrt=[q, 'x']) == (q, x, p) + assert _sort_gens([x, p, q], wrt=[p, 'q']) == (p, q, x) + assert _sort_gens([x, p, q], wrt=[q, 'p']) == (q, p, x) + + assert _sort_gens([x, p, q], wrt=['x', 'q']) == (x, q, p) + assert _sort_gens([x, p, q], wrt=['q', 'x']) == (q, x, p) + assert _sort_gens([x, p, q], wrt=['p', 'q']) == (p, q, x) + assert _sort_gens([x, p, q], wrt=['q', 'p']) == (q, p, x) + + assert _sort_gens([x, p, q], sort='x > p > q') == (x, p, q) + assert _sort_gens([x, p, q], sort='p > x > q') == (p, x, q) + assert _sort_gens([x, p, q], sort='p > q > x') == (p, q, x) + + assert _sort_gens([x, p, q], wrt='x', sort='q > p') == (x, q, p) + assert _sort_gens([x, p, q], wrt='p', sort='q > x') == (p, q, x) + assert _sort_gens([x, p, q], wrt='q', sort='p > x') == (q, p, x) X = symbols('x0,x1,x2,x10,x11,x12,x20,x21,x22') assert _sort_gens(X) == X + def test__unify_gens(): assert _unify_gens([], []) == () assert _unify_gens([x], [x]) == (x,) assert _unify_gens([y], [y]) == (y,) - assert _unify_gens([x,y], [x]) == (x,y) - assert _unify_gens([x], [x,y]) == (x,y) + assert _unify_gens([x, y], [x]) == (x, y) + assert _unify_gens([x], [x, y]) == (x, y) + + assert _unify_gens([x, y], [x, y]) == (x, y) + assert _unify_gens([y, x], [y, x]) == (y, x) - assert _unify_gens([x,y], [x,y]) == (x,y) - assert _unify_gens([y,x], [y,x]) == (y,x) + assert _unify_gens([x], [y]) == (x, y) + assert _unify_gens([y], [x]) == (y, x) - assert _unify_gens([x], [y]) == (x,y) - assert _unify_gens([y], [x]) == (y,x) + assert _unify_gens([x], [y, x]) == (y, x) + assert _unify_gens([y, x], [x]) == (y, x) - assert _unify_gens([x], [y,x]) == (y,x) - assert _unify_gens([y,x], [x]) == (y,x) + assert _unify_gens([x, y, z], [x, y, z]) == (x, y, z) + assert _unify_gens([z, y, x], [x, y, z]) == (z, y, x) + assert _unify_gens([x, y, z], [z, y, x]) == (x, y, z) + assert _unify_gens([z, y, x], [z, y, x]) == (z, y, x) - assert _unify_gens([x,y,z], [x,y,z]) == (x,y,z) - assert _unify_gens([z,y,x], [x,y,z]) == (z,y,x) - assert _unify_gens([x,y,z], [z,y,x]) == (x,y,z) - assert _unify_gens([z,y,x], [z,y,x]) == (z,y,x) + assert _unify_gens([x, y, z], [t, x, p, q, z]) == (t, x, y, p, q, z) - assert _unify_gens([x,y,z], [t,x,p,q,z]) == (t,x,y,p,q,z) def test__analyze_gens(): - assert _analyze_gens((x,y,z)) == (x,y,z) - assert _analyze_gens([x,y,z]) == (x,y,z) + assert _analyze_gens((x, y, z)) == (x, y, z) + assert _analyze_gens([x, y, z]) == (x, y, z) + + assert _analyze_gens(([x, y, z],)) == (x, y, z) + assert _analyze_gens(((x, y, z),)) == (x, y, z) - assert _analyze_gens(([x,y,z],)) == (x,y,z) - assert _analyze_gens(((x,y,z),)) == (x,y,z) def test__sort_factors(): assert _sort_factors([], multiple=True) == [] assert _sort_factors([], multiple=False) == [] - F = [[1,2,3], [1,2], [1]] - G = [[1], [1,2], [1,2,3]] + F = [[1, 2, 3], [1, 2], [1]] + G = [[1], [1, 2], [1, 2, 3]] assert _sort_factors(F, multiple=False) == G - F = [[1,2], [1,2,3], [1,2], [1]] - G = [[1], [1,2], [1,2], [1,2,3]] + F = [[1, 2], [1, 2, 3], [1, 2], [1]] + G = [[1], [1, 2], [1, 2], [1, 2, 3]] assert _sort_factors(F, multiple=False) == G - F = [[2,2], [1,2,3], [1,2], [1]] - G = [[1], [1,2], [2,2], [1,2,3]] + F = [[2, 2], [1, 2, 3], [1, 2], [1]] + G = [[1], [1, 2], [2, 2], [1, 2, 3]] assert _sort_factors(F, multiple=False) == G - F = [([1,2,3], 1), ([1,2], 1), ([1], 1)] - G = [([1], 1), ([1,2], 1), ([1,2,3], 1)] + F = [([1, 2, 3], 1), ([1, 2], 1), ([1], 1)] + G = [([1], 1), ([1, 2], 1), ([1, 2, 3], 1)] assert _sort_factors(F, multiple=True) == G - F = [([1,2], 1), ([1,2,3], 1), ([1,2], 1), ([1], 1)] - G = [([1], 1), ([1,2], 1), ([1,2], 1), ([1,2,3], 1)] + F = [([1, 2], 1), ([1, 2, 3], 1), ([1, 2], 1), ([1], 1)] + G = [([1], 1), ([1, 2], 1), ([1, 2], 1), ([1, 2, 3], 1)] assert _sort_factors(F, multiple=True) == G - F = [([2,2], 1), ([1,2,3], 1), ([1,2], 1), ([1], 1)] - G = [([1], 1), ([1,2], 1), ([2,2], 1), ([1,2,3], 1)] + F = [([2, 2], 1), ([1, 2, 3], 1), ([1, 2], 1), ([1], 1)] + G = [([1], 1), ([1, 2], 1), ([2, 2], 1), ([1, 2, 3], 1)] assert _sort_factors(F, multiple=True) == G - F = [([2,2], 1), ([1,2,3], 1), ([1,2], 2), ([1], 1)] - G = [([1], 1), ([2,2], 1), ([1,2], 2), ([1,2,3], 1)] + F = [([2, 2], 1), ([1, 2, 3], 1), ([1, 2], 2), ([1], 1)] + G = [([1], 1), ([2, 2], 1), ([1, 2], 2), ([1, 2, 3], 1)] assert _sort_factors(F, multiple=True) == G + def test__dict_from_expr_if_gens(): - assert dict_from_expr(Integer(17), gens=(x,)) == ({(0,): Integer(17)}, (x,)) - assert dict_from_expr(Integer(17), gens=(x,y)) == ({(0,0): Integer(17)}, (x,y)) - assert dict_from_expr(Integer(17), gens=(x,y,z)) == ({(0,0,0): Integer(17)}, (x,y,z)) - - assert dict_from_expr(Integer(-17), gens=(x,)) == ({(0,): Integer(-17)}, (x,)) - assert dict_from_expr(Integer(-17), gens=(x,y)) == ({(0,0): Integer(-17)}, (x,y)) - assert dict_from_expr(Integer(-17), gens=(x,y,z)) == ({(0,0,0): Integer(-17)}, (x,y,z)) - - assert dict_from_expr(Integer(17)*x, gens=(x,)) == ({(1,): Integer(17)}, (x,)) - assert dict_from_expr(Integer(17)*x, gens=(x,y)) == ({(1,0): Integer(17)}, (x,y)) - assert dict_from_expr(Integer(17)*x, gens=(x,y,z)) == ({(1,0,0): Integer(17)}, (x,y,z)) - - assert dict_from_expr(Integer(17)*x**7, gens=(x,)) == ({(7,): Integer(17)}, (x,)) - assert dict_from_expr(Integer(17)*x**7*y, gens=(x,y)) == ({(7,1): Integer(17)}, (x,y)) - assert dict_from_expr(Integer(17)*x**7*y*z**12, gens=(x,y,z)) == ({(7,1,12): Integer(17)}, (x,y,z)) - - assert dict_from_expr(x+2*y+3*z, gens=(x,)) == \ - ({(1,): Integer(1), (0,): 2*y+3*z}, (x,)) - assert dict_from_expr(x+2*y+3*z, gens=(x,y)) == \ - ({(1,0): Integer(1), (0,1): Integer(2), (0,0): 3*z}, (x,y)) - assert dict_from_expr(x+2*y+3*z, gens=(x,y,z)) == \ - ({(1,0,0): Integer(1), (0,1,0): Integer(2), (0,0,1): Integer(3)}, (x,y,z)) - - assert dict_from_expr(x*y+2*x*z+3*y*z, gens=(x,)) == \ - ({(1,): y+2*z, (0,): 3*y*z}, (x,)) - assert dict_from_expr(x*y+2*x*z+3*y*z, gens=(x,y)) == \ - ({(1,1): Integer(1), (1,0): 2*z, (0,1): 3*z}, (x,y)) - assert dict_from_expr(x*y+2*x*z+3*y*z, gens=(x,y,z)) == \ - ({(1,1,0): Integer(1), (1,0,1): Integer(2), (0,1,1): Integer(3)}, (x,y,z)) + assert dict_from_expr( + Integer(17), gens=(x,)) == ({(0,): Integer(17)}, (x,)) + assert dict_from_expr( + Integer(17), gens=(x, y)) == ({(0, 0): Integer(17)}, (x, y)) + assert dict_from_expr( + Integer(17), gens=(x, y, z)) == ({(0, 0, 0): Integer(17)}, (x, y, z)) + + assert dict_from_expr( + Integer(-17), gens=(x,)) == ({(0,): Integer(-17)}, (x,)) + assert dict_from_expr( + Integer(-17), gens=(x, y)) == ({(0, 0): Integer(-17)}, (x, y)) + assert dict_from_expr(Integer( + -17), gens=(x, y, z)) == ({(0, 0, 0): Integer(-17)}, (x, y, z)) + + assert dict_from_expr( + Integer(17)*x, gens=(x,)) == ({(1,): Integer(17)}, (x,)) + assert dict_from_expr( + Integer(17)*x, gens=(x, y)) == ({(1, 0): Integer(17)}, (x, y)) + assert dict_from_expr(Integer( + 17)*x, gens=(x, y, z)) == ({(1, 0, 0): Integer(17)}, (x, y, z)) + + assert dict_from_expr( + Integer(17)*x**7, gens=(x,)) == ({(7,): Integer(17)}, (x,)) + assert dict_from_expr( + Integer(17)*x**7*y, gens=(x, y)) == ({(7, 1): Integer(17)}, (x, y)) + assert dict_from_expr(Integer(17)*x**7*y*z**12, gens=( + x, y, z)) == ({(7, 1, 12): Integer(17)}, (x, y, z)) + + assert dict_from_expr(x + 2*y + 3*z, gens=(x,)) == \ + ({(1,): Integer(1), (0,): 2*y + 3*z}, (x,)) + assert dict_from_expr(x + 2*y + 3*z, gens=(x, y)) == \ + ({(1, 0): Integer(1), (0, 1): Integer(2), (0, 0): 3*z}, (x, y)) + assert dict_from_expr(x + 2*y + 3*z, gens=(x, y, z)) == \ + ({(1, 0, 0): Integer( + 1), (0, 1, 0): Integer(2), (0, 0, 1): Integer(3)}, (x, y, z)) + + assert dict_from_expr(x*y + 2*x*z + 3*y*z, gens=(x,)) == \ + ({(1,): y + 2*z, (0,): 3*y*z}, (x,)) + assert dict_from_expr(x*y + 2*x*z + 3*y*z, gens=(x, y)) == \ + ({(1, 1): Integer(1), (1, 0): 2*z, (0, 1): 3*z}, (x, y)) + assert dict_from_expr(x*y + 2*x*z + 3*y*z, gens=(x, y, z)) == \ + ({(1, 1, 0): Integer( + 1), (1, 0, 1): Integer(2), (0, 1, 1): Integer(3)}, (x, y, z)) assert dict_from_expr(2**y*x, gens=(x,)) == ({(1,): 2**y}, (x,)) - assert dict_from_expr(Integral(x, (x, 1, 2)) + x) == ({(0, 1): 1, (1, 0): 1}, (x, Integral(x, (x, 1, 2)))) - raises(PolynomialError, lambda: dict_from_expr(2**y*x, gens=(x,y))) + assert dict_from_expr(Integral(x, (x, 1, 2)) + x) == ( + {(0, 1): 1, (1, 0): 1}, (x, Integral(x, (x, 1, 2)))) + raises(PolynomialError, lambda: dict_from_expr(2**y*x, gens=(x, y))) + def test__dict_from_expr_no_gens(): raises(GeneratorsNeeded, lambda: dict_from_expr(Integer(17))) @@ -192,8 +213,9 @@ assert dict_from_expr(x) == ({(1,): Integer(1)}, (x,)) assert dict_from_expr(y) == ({(1,): Integer(1)}, (y,)) - assert dict_from_expr(x*y) == ({(1,1): Integer(1)}, (x,y)) - assert dict_from_expr(x+y) == ({(1,0): Integer(1), (0,1): Integer(1)}, (x,y)) + assert dict_from_expr(x*y) == ({(1, 1): Integer(1)}, (x, y)) + assert dict_from_expr( + x + y) == ({(1, 0): Integer(1), (0, 1): Integer(1)}, (x, y)) assert dict_from_expr(sqrt(2)) == ({(1,): Integer(1)}, (sqrt(2),)) raises(GeneratorsNeeded, lambda: dict_from_expr(sqrt(2), greedy=False)) @@ -201,30 +223,39 @@ assert dict_from_expr(x*y, domain=ZZ[x]) == ({(1,): x}, (y,)) assert dict_from_expr(x*y, domain=ZZ[y]) == ({(1,): y}, (x,)) - assert dict_from_expr(3*sqrt(2)*pi*x*y, extension=None) == ({(1, 1, 1, 1): 3}, (x, y, pi, sqrt(2))) - assert dict_from_expr(3*sqrt(2)*pi*x*y, extension=True) == ({(1,1,1): 3*sqrt(2)}, (x,y,pi)) + assert dict_from_expr(3*sqrt( + 2)*pi*x*y, extension=None) == ({(1, 1, 1, 1): 3}, (x, y, pi, sqrt(2))) + assert dict_from_expr(3*sqrt( + 2)*pi*x*y, extension=True) == ({(1, 1, 1): 3*sqrt(2)}, (x, y, pi)) - assert dict_from_expr(3*sqrt(2)*pi*x*y, extension=True) == ({(1,1,1): 3*sqrt(2)}, (x,y,pi)) + assert dict_from_expr(3*sqrt( + 2)*pi*x*y, extension=True) == ({(1, 1, 1): 3*sqrt(2)}, (x, y, pi)) f = cos(x)*sin(x) + cos(x)*sin(y) + cos(y)*sin(x) + cos(y)*sin(y) assert dict_from_expr(f) == ({(0, 1, 0, 1): 1, (0, 1, 1, 0): 1, (1, 0, 0, 1): 1, (1, 0, 1, 0): 1}, (cos(x), cos(y), sin(x), sin(y))) + def test__parallel_dict_from_expr_if_gens(): - assert parallel_dict_from_expr([x+2*y+3*z, Integer(7)], gens=(x,)) == \ - ([{(1,): Integer(1), (0,): 2*y+3*z}, {(0,): Integer(7)}], (x,)) + assert parallel_dict_from_expr([x + 2*y + 3*z, Integer(7)], gens=(x,)) == \ + ([{(1,): Integer(1), (0,): 2*y + 3*z}, {(0,): Integer(7)}], (x,)) + def test__parallel_dict_from_expr_no_gens(): assert parallel_dict_from_expr([x*y, Integer(3)]) == \ - ([{(1,1): Integer(1)}, {(0,0): Integer(3)}], (x,y)) + ([{(1, 1): Integer(1)}, {(0, 0): Integer(3)}], (x, y)) assert parallel_dict_from_expr([x*y, 2*z, Integer(3)]) == \ - ([{(1,1,0): Integer(1)}, {(0,0,1): Integer(2)}, {(0,0,0): Integer(3)}], (x,y,z)) + ([{(1, 1, 0): Integer( + 1)}, {(0, 0, 1): Integer(2)}, {(0, 0, 0): Integer(3)}], (x, y, z)) + def test_parallel_dict_from_expr(): - parallel_dict_from_expr([Eq(x, 1), Eq(x**2, 2)]) == ([{(1,): Integer(1)}, {(2,): Integer(2)}], (x,)) + parallel_dict_from_expr([Eq(x, 1), Eq( + x**2, 2)]) == ([{(1,): Integer(1)}, {(2,): Integer(2)}], (x,)) raises(PolynomialError, lambda: parallel_dict_from_expr([A*B - B*A])) + def test_dict_from_expr(): dict_from_expr(Eq(x, 1)) == ({(1,): Integer(1)}, (x,)) raises(PolynomialError, lambda: dict_from_expr(A*B - B*A)) diff -Nru python3-sympy-0.7.2/sympy/polys/tests/test_pythonrational.py python3-sympy-0.7.3/sympy/polys/tests/test_pythonrational.py --- python3-sympy-0.7.2/sympy/polys/tests/test_pythonrational.py 1970-01-01 00:00:00.000000000 +0000 +++ python3-sympy-0.7.3/sympy/polys/tests/test_pythonrational.py 2013-07-13 17:53:32.000000000 +0000 @@ -0,0 +1,139 @@ +"""Tests for PythonRational type. """ + +from sympy.polys.domains import PythonRational as QQ +from sympy.utilities.pytest import raises + +def test_PythonRational__init__(): + assert QQ(0).p == 0 + assert QQ(0).q == 1 + assert QQ(0, 1).p == 0 + assert QQ(0, 1).q == 1 + assert QQ(0, -1).p == 0 + assert QQ(0, -1).q == 1 + + assert QQ(1).p == 1 + assert QQ(1).q == 1 + assert QQ(1, 1).p == 1 + assert QQ(1, 1).q == 1 + assert QQ(-1, -1).p == 1 + assert QQ(-1, -1).q == 1 + + assert QQ(-1).p == -1 + assert QQ(-1).q == 1 + assert QQ(-1, 1).p == -1 + assert QQ(-1, 1).q == 1 + assert QQ( 1, -1).p == -1 + assert QQ( 1, -1).q == 1 + + assert QQ(1, 2).p == 1 + assert QQ(1, 2).q == 2 + assert QQ(3, 4).p == 3 + assert QQ(3, 4).q == 4 + + assert QQ(2, 2).p == 1 + assert QQ(2, 2).q == 1 + assert QQ(2, 4).p == 1 + assert QQ(2, 4).q == 2 + +def test_PythonRational__hash__(): + assert hash(QQ(0)) == hash(0) + assert hash(QQ(1)) == hash(1) + assert hash(QQ(117)) == hash(117) + +def test_PythonRational__int__(): + assert int(QQ(-1, 4)) == 0 + assert int(QQ( 1, 4)) == 0 + assert int(QQ(-5, 4)) == -1 + assert int(QQ( 5, 4)) == 1 + +def test_PythonRational__float__(): + assert float(QQ(-1, 2)) == -0.5 + assert float(QQ( 1, 2)) == 0.5 + +def test_PythonRational__abs__(): + assert abs(QQ(-1, 2)) == QQ(1, 2) + assert abs(QQ( 1, 2)) == QQ(1, 2) + +def test_PythonRational__pos__(): + assert +QQ(-1, 2) == QQ(-1, 2) + assert +QQ( 1, 2) == QQ( 1, 2) + +def test_PythonRational__neg__(): + assert -QQ(-1, 2) == QQ( 1, 2) + assert -QQ( 1, 2) == QQ(-1, 2) + +def test_PythonRational__add__(): + assert QQ(-1, 2) + QQ( 1, 2) == QQ(0) + assert QQ( 1, 2) + QQ(-1, 2) == QQ(0) + + assert QQ(1, 2) + QQ(1, 2) == QQ(1) + assert QQ(1, 2) + QQ(3, 2) == QQ(2) + assert QQ(3, 2) + QQ(1, 2) == QQ(2) + assert QQ(3, 2) + QQ(3, 2) == QQ(3) + + assert 1 + QQ(1, 2) == QQ(3, 2) + assert QQ(1, 2) + 1 == QQ(3, 2) + +def test_PythonRational__sub__(): + assert QQ(-1, 2) - QQ( 1, 2) == QQ(-1) + assert QQ( 1, 2) - QQ(-1, 2) == QQ( 1) + + assert QQ(1, 2) - QQ(1, 2) == QQ( 0) + assert QQ(1, 2) - QQ(3, 2) == QQ(-1) + assert QQ(3, 2) - QQ(1, 2) == QQ( 1) + assert QQ(3, 2) - QQ(3, 2) == QQ( 0) + + assert 1 - QQ(1, 2) == QQ( 1, 2) + assert QQ(1, 2) - 1 == QQ(-1, 2) + +def test_PythonRational__mul__(): + assert QQ(-1, 2) * QQ( 1, 2) == QQ(-1, 4) + assert QQ( 1, 2) * QQ(-1, 2) == QQ(-1, 4) + + assert QQ(1, 2) * QQ(1, 2) == QQ(1, 4) + assert QQ(1, 2) * QQ(3, 2) == QQ(3, 4) + assert QQ(3, 2) * QQ(1, 2) == QQ(3, 4) + assert QQ(3, 2) * QQ(3, 2) == QQ(9, 4) + + assert 2 * QQ(1, 2) == QQ(1) + assert QQ(1, 2) * 2 == QQ(1) + +def test_PythonRational__div__(): + assert QQ(-1, 2) / QQ( 1, 2) == QQ(-1) + assert QQ( 1, 2) / QQ(-1, 2) == QQ(-1) + + assert QQ(1, 2) / QQ(1, 2) == QQ(1) + assert QQ(1, 2) / QQ(3, 2) == QQ(1, 3) + assert QQ(3, 2) / QQ(1, 2) == QQ(3) + assert QQ(3, 2) / QQ(3, 2) == QQ(1) + + assert 2 / QQ(1, 2) == QQ(4) + assert QQ(1, 2) / 2 == QQ(1, 4) + + raises(ZeroDivisionError, lambda: QQ(1, 2) / QQ(0)) + raises(ZeroDivisionError, lambda: QQ(1, 2) / 0) + +def test_PythonRational__pow__(): + assert QQ(1)**10 == QQ(1) + assert QQ(2)**10 == QQ(1024) + + assert QQ(1)**(-10) == QQ(1) + assert QQ(2)**(-10) == QQ(1, 1024) + +def test_PythonRational__eq__(): + assert (QQ(1, 2) == QQ(1, 2)) is True + assert (QQ(1, 2) != QQ(1, 2)) is False + + assert (QQ(1, 2) == QQ(1, 3)) is False + assert (QQ(1, 2) != QQ(1, 3)) is True + +def test_PythonRational__lt_le_gt_ge__(): + assert (QQ(1, 2) < QQ(1, 4)) is False + assert (QQ(1, 2) <= QQ(1, 4)) is False + assert (QQ(1, 2) > QQ(1, 4)) is True + assert (QQ(1, 2) >= QQ(1, 4)) is True + + assert (QQ(1, 4) < QQ(1, 2)) is True + assert (QQ(1, 4) <= QQ(1, 2)) is True + assert (QQ(1, 4) > QQ(1, 2)) is False + assert (QQ(1, 4) >= QQ(1, 2)) is False diff -Nru python3-sympy-0.7.2/sympy/polys/tests/test_quotientring.py python3-sympy-0.7.3/sympy/polys/tests/test_quotientring.py --- python3-sympy-0.7.2/sympy/polys/tests/test_quotientring.py 2012-10-17 03:02:22.000000000 +0000 +++ python3-sympy-0.7.3/sympy/polys/tests/test_quotientring.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,49 +0,0 @@ -"""Tests for quotient rings.""" - -from sympy import QQ, ZZ -from sympy.abc import x, y - -from sympy.polys.polyerrors import NotReversible - -from sympy.utilities.pytest import raises - -def test_QuotientRingElement(): - R = QQ[x]/[x**10] - X = R.convert(x) - - assert X*(X+1) == R.convert(x**2 + x) - assert X*x == R.convert(x**2) - assert x*X == R.convert(x**2) - assert X+x == R.convert(2*x) - assert x+X == 2*X - assert X**2 == R.convert(x**2) - assert 1/(1 - X) == R.convert(sum(x**i for i in range(10))) - assert X**10 == R.zero - assert X != x - - raises(NotReversible, lambda: 1/X) - -def test_QuotientRing(): - I = QQ[x].ideal(x**2 + 1) - R = QQ[x]/I - - assert R == QQ[x]/[x**2 + 1] - assert R == QQ[x]/QQ[x].ideal(x**2 + 1) - assert R != QQ[x] - - assert R.convert(1)/x == -x + I - assert -1 + I == x**2 + I - assert R.convert(1, ZZ) == 1 + I - assert R.convert(R.convert(x), R) == R.convert(x) - - X = R.convert(x) - Y = QQ[x].convert(x) - assert -1 + I == X**2 + I - assert -1 + I == Y**2 + I - assert R.to_sympy(X) == x - - raises(ValueError, lambda: QQ[x]/QQ[x, y].ideal(x)) - - R = QQ.poly_ring(x, order="ilex") - I = R.ideal(x) - assert R.convert(1) + I == (R/I).convert(1) diff -Nru python3-sympy-0.7.2/sympy/polys/tests/test_rationaltools.py python3-sympy-0.7.3/sympy/polys/tests/test_rationaltools.py --- python3-sympy-0.7.2/sympy/polys/tests/test_rationaltools.py 2012-10-17 03:02:22.000000000 +0000 +++ python3-sympy-0.7.3/sympy/polys/tests/test_rationaltools.py 2013-07-13 17:53:32.000000000 +0000 @@ -7,6 +7,7 @@ A, B = symbols('A,B', commutative=False) + def test_together(): assert together(0) == 0 assert together(1) == 1 @@ -35,18 +36,19 @@ assert together(1/(x**7*y) + 1/(x*y)**4) == y**(-4)*x**(-7)*(x**3 + y**3) assert together(5/(2 + 6/(3 + 7/(4 + 8/(5 + 9/x))))) == \ - (S(5)/2)*((171 + 119*x)/(279 + 203*x)) + (S(5)/2)*((171 + 119*x)/(279 + 203*x)) assert together(1 + 1/(x + 1)**2) == (1 + (x + 1)**2)/(x + 1)**2 assert together(1 + 1/(x*(1 + x))) == (1 + x*(1 + x))/(x*(1 + x)) - assert together(1/(x*(x + 1)) + 1/(x*(x + 2))) == (3 + 2*x)/(x*(1 + x)*(2 + x)) + assert together( + 1/(x*(x + 1)) + 1/(x*(x + 2))) == (3 + 2*x)/(x*(1 + x)*(2 + x)) assert together(1 + 1/(2*x + 2)**2) == (4*(x + 1)**2 + 1)/(4*(x + 1)**2) assert together(sin(1/x + 1/y)) == sin(1/x + 1/y) assert together(sin(1/x + 1/y), deep=True) == sin((x + y)/(x*y)) - assert together(1/exp(x) + 1/(x*exp(x))) == (1+x)/(x*exp(x)) - assert together(1/exp(2*x) + 1/(x*exp(3*x))) == (1+exp(x)*x)/(x*exp(3*x)) + assert together(1/exp(x) + 1/(x*exp(x))) == (1 + x)/(x*exp(x)) + assert together(1/exp(2*x) + 1/(x*exp(3*x))) == (1 + exp(x)*x)/(x*exp(3*x)) assert together(Integral(1/x + 1/y, x)) == Integral((x + y)/(x*y), x) assert together(Eq(1/x + 1/y, 1 + 1/z)) == Eq((x + y)/(x*y), (z + 1)/z) diff -Nru python3-sympy-0.7.2/sympy/polys/tests/test_rings.py python3-sympy-0.7.3/sympy/polys/tests/test_rings.py --- python3-sympy-0.7.2/sympy/polys/tests/test_rings.py 1970-01-01 00:00:00.000000000 +0000 +++ python3-sympy-0.7.3/sympy/polys/tests/test_rings.py 2013-07-13 17:53:32.000000000 +0000 @@ -0,0 +1,685 @@ +"""Test sparse polynomials. """ + +from sympy.polys.rings import ring, xring, PolyRing, PolyElement +from sympy.polys.fields import field +from sympy.polys.domains import ZZ, QQ, RR +from sympy.polys.monomialtools import lex, grlex +from sympy.polys.polyerrors import GeneratorsError, GeneratorsNeeded + +from sympy.utilities.pytest import raises +from sympy.core import Symbol, symbols +from sympy import sqrt + +def test_PolyRing___init__(): + x, y, z = list(map(Symbol, "xyz")) + + assert len(PolyRing("x,y,z", ZZ, lex).gens) == 3 + assert len(PolyRing(x, ZZ, lex).gens) == 1 + assert len(PolyRing(("x", "y", "z"), ZZ, lex).gens) == 3 + assert len(PolyRing((x, y, z), ZZ, lex).gens) == 3 + + raises(GeneratorsNeeded, lambda: PolyRing([], ZZ, lex)) + raises(GeneratorsError, lambda: PolyRing(0, ZZ, lex)) + +def test_PolyRing___hash__(): + R, x, y, z = ring("x,y,z", QQ) + assert hash(R) + +def test_PolyRing___eq__(): + assert ring("x,y,z", QQ)[0] == ring("x,y,z", QQ)[0] + assert ring("x,y,z", QQ)[0] != ring("x,y,z", ZZ)[0] + assert ring("x,y,z", ZZ)[0] != ring("x,y,z", QQ)[0] + assert ring("x,y,z", QQ)[0] != ring("x,y", QQ)[0] + assert ring("x,y", QQ)[0] != ring("x,y,z", QQ)[0] + +def test_PolyElement___hash__(): + R, x, y, z = ring("x,y,z", QQ) + assert hash(x*y*z) + +def test_PolyElement___eq__(): + R, x, y = ring("x,y", ZZ, lex) + + assert ((x*y + 5*x*y) == 6) == False + assert ((x*y + 5*x*y) == 6*x*y) == True + assert (6 == (x*y + 5*x*y)) == False + assert (6*x*y == (x*y + 5*x*y)) == True + + assert ((x*y - x*y) == 0) == True + assert (0 == (x*y - x*y)) == True + + assert ((x*y - x*y) == 1) == False + assert (1 == (x*y - x*y)) == False + + assert ((x*y - x*y) == 1) == False + assert (1 == (x*y - x*y)) == False + + assert ((x*y + 5*x*y) != 6) == True + assert ((x*y + 5*x*y) != 6*x*y) == False + assert (6 != (x*y + 5*x*y)) == True + assert (6*x*y != (x*y + 5*x*y)) == False + + assert ((x*y - x*y) != 0) == False + assert (0 != (x*y - x*y)) == False + + assert ((x*y - x*y) != 1) == True + assert (1 != (x*y - x*y)) == True + + Rt, t = ring("t", ZZ) + R, x, y = ring("x,y", Rt.to_domain()) + + assert (t**3*x/x == t**3) == True + assert (t**3*x/x == t**4) == False + +def test_PolyElement_copy(): + R, x, y, z = ring("x,y,z", ZZ) + + f = x*y + 3*z + g = f.copy() + + assert f == g + g[(1, 1, 1)] = 7 + assert f != g + +def test_PolyElement_as_expr(): + R, x, y, z = ring("x,y,z", ZZ) + f = 3*x**2*y - x*y*z + 7*z**3 + 1 + + X, Y, Z = R.symbols + g = 3*X**2*Y - X*Y*Z + 7*Z**3 + 1 + + assert f != g + assert f.as_expr() == g + + X, Y, Z = symbols("x,y,z") + g = 3*X**2*Y - X*Y*Z + 7*Z**3 + 1 + + assert f != g + assert f.as_expr(X, Y, Z) == g + + raises(ValueError, lambda: f.as_expr(X)) + +def test_PolyElement_from_expr(): + x, y, z = symbols("x,y,z") + R, X, Y, Z = ring((x, y, z), ZZ) + + f = R.from_expr(1) + assert f == 1 and isinstance(f, R.dtype) + + f = R.from_expr(x) + assert f == X and isinstance(f, R.dtype) + + f = R.from_expr(x*y*z) + assert f == X*Y*Z and isinstance(f, R.dtype) + + f = R.from_expr(x*y*z + x*y + x) + assert f == X*Y*Z + X*Y + X and isinstance(f, R.dtype) + + f = R.from_expr(x**3*y*z + x**2*y**7 + 1) + assert f == X**3*Y*Z + X**2*Y**7 + 1 and isinstance(f, R.dtype) + + raises(ValueError, lambda: R.from_expr(1/x)) + raises(ValueError, lambda: R.from_expr(2**x)) + raises(ValueError, lambda: R.from_expr(7*x + sqrt(2))) + +def test_PolyElement_coeff(): + R, x, y, z = ring("x,y,z", ZZ, lex) + f = 3*x**2*y - x*y*z + 7*z**3 + 23 + + assert f.coeff(1) == 23 + raises(ValueError, lambda: f.coeff(3)) + + assert f.coeff(x) == 0 + assert f.coeff(y) == 0 + assert f.coeff(z) == 0 + + assert f.coeff(x**2*y) == 3 + assert f.coeff(x*y*z) == -1 + assert f.coeff(z**3) == 7 + + raises(ValueError, lambda: f.coeff(3*x**2*y)) + raises(ValueError, lambda: f.coeff(-x*y*z)) + raises(ValueError, lambda: f.coeff(7*z**3)) + +def test_PolyElement_LC(): + R, x, y = ring("x,y", QQ, lex) + assert R(0).LC == QQ(0) + assert (QQ(1,2)*x).LC == QQ(1, 2) + assert (QQ(1,4)*x*y + QQ(1,2)*x).LC == QQ(1, 4) + +def test_PolyElement_LM(): + R, x, y = ring("x,y", QQ, lex) + assert R(0).LM == (0, 0) + assert (QQ(1,2)*x).LM == (1, 0) + assert (QQ(1,4)*x*y + QQ(1,2)*x).LM == (1, 1) + +def test_PolyElement_LT(): + R, x, y = ring("x,y", QQ, lex) + assert R(0).LT == ((0, 0), QQ(0)) + assert (QQ(1,2)*x).LT == ((1, 0), QQ(1, 2)) + assert (QQ(1,4)*x*y + QQ(1,2)*x).LT == ((1, 1), QQ(1, 4)) + +def test_PolyElement_leading_monom(): + R, x, y = ring("x,y", QQ, lex) + assert R(0).leading_monom == 0 + assert (QQ(1,2)*x).leading_monom == x + assert (QQ(1,4)*x*y + QQ(1,2)*x).leading_monom == x*y + +def test_PolyElement_leading_term(): + R, x, y = ring("x,y", QQ, lex) + assert R(0).leading_term == 0 + assert (QQ(1,2)*x).leading_term == QQ(1,2)*x + assert (QQ(1,4)*x*y + QQ(1,2)*x).leading_term == QQ(1,4)*x*y + +def test_PolyElement_terms(): + R, x,y,z = ring("x,y,z", QQ) + terms = list((x**2/3 + y**3/4 + z**4/5).terms()) + assert set(terms) == set([((2,0,0), QQ(1,3)), ((0,3,0), QQ(1,4)), ((0,0,4), QQ(1,5))]) + +def test_PolyElement_monoms(): + R, x,y,z = ring("x,y,z", QQ) + monoms = list((x**2/3 + y**3/4 + z**4/5).monoms()) + assert set(monoms) == set([(2,0,0), (0,3,0), (0,0,4)]) + +def test_PolyElement_coeffs(): + R, x,y,z = ring("x,y,z", QQ) + coeffs = list((x**2/3 + y**3/4 + z**4/5).coeffs()) + assert set(coeffs) == set([QQ(1,3), QQ(1,4), QQ(1,5)]) + +def test_PolyElement___add__(): + Rt, t = ring("t", ZZ) + Ruv, u,v = ring("u,v", ZZ) + Rxyz, x,y,z = ring("x,y,z", Ruv.to_domain()) + + assert dict(x + 3*y) == {(1, 0, 0): 1, (0, 1, 0): 3} + + assert dict(u + x) == dict(x + u) == {(1, 0, 0): 1, (0, 0, 0): u} + assert dict(u + x*y) == dict(x*y + u) == {(1, 1, 0): 1, (0, 0, 0): u} + assert dict(u + x*y + z) == dict(x*y + z + u) == {(1, 1, 0): 1, (0, 0, 1): 1, (0, 0, 0): u} + + assert dict(u*x + x) == dict(x + u*x) == {(1, 0, 0): u + 1} + assert dict(u*x + x*y) == dict(x*y + u*x) == {(1, 1, 0): 1, (1, 0, 0): u} + assert dict(u*x + x*y + z) == dict(x*y + z + u*x) == {(1, 1, 0): 1, (0, 0, 1): 1, (1, 0, 0): u} + + raises(TypeError, lambda: t + x) + raises(TypeError, lambda: x + t) + raises(TypeError, lambda: t + u) + raises(TypeError, lambda: u + t) + + Fuv, u,v = field("u,v", ZZ) + Rxyz, x,y,z = ring("x,y,z", Fuv.to_domain()) + + assert dict(u + x) == dict(x + u) == {(1, 0, 0): 1, (0, 0, 0): u} + +def test_PolyElement___sub__(): + Rt, t = ring("t", ZZ) + Ruv, u,v = ring("u,v", ZZ) + Rxyz, x,y,z = ring("x,y,z", Ruv.to_domain()) + + assert dict(x - 3*y) == {(1, 0, 0): 1, (0, 1, 0): -3} + + assert dict(-u + x) == dict(x - u) == {(1, 0, 0): 1, (0, 0, 0): -u} + assert dict(-u + x*y) == dict(x*y - u) == {(1, 1, 0): 1, (0, 0, 0): -u} + assert dict(-u + x*y + z) == dict(x*y + z - u) == {(1, 1, 0): 1, (0, 0, 1): 1, (0, 0, 0): -u} + + assert dict(-u*x + x) == dict(x - u*x) == {(1, 0, 0): -u + 1} + assert dict(-u*x + x*y) == dict(x*y - u*x) == {(1, 1, 0): 1, (1, 0, 0): -u} + assert dict(-u*x + x*y + z) == dict(x*y + z - u*x) == {(1, 1, 0): 1, (0, 0, 1): 1, (1, 0, 0): -u} + + raises(TypeError, lambda: t - x) + raises(TypeError, lambda: x - t) + raises(TypeError, lambda: t - u) + raises(TypeError, lambda: u - t) + + Fuv, u,v = field("u,v", ZZ) + Rxyz, x,y,z = ring("x,y,z", Fuv.to_domain()) + + assert dict(-u + x) == dict(x - u) == {(1, 0, 0): 1, (0, 0, 0): -u} + +def test_PolyElement___mul__(): + Rt, t = ring("t", ZZ) + Ruv, u,v = ring("u,v", ZZ) + Rxyz, x,y,z = ring("x,y,z", Ruv.to_domain()) + + assert dict(u*x) == dict(x*u) == {(1, 0, 0): u} + + assert dict(2*u*x + z) == dict(x*2*u + z) == {(1, 0, 0): 2*u, (0, 0, 1): 1} + assert dict(u*2*x + z) == dict(2*x*u + z) == {(1, 0, 0): 2*u, (0, 0, 1): 1} + assert dict(2*u*x + z) == dict(x*2*u + z) == {(1, 0, 0): 2*u, (0, 0, 1): 1} + assert dict(u*x*2 + z) == dict(x*u*2 + z) == {(1, 0, 0): 2*u, (0, 0, 1): 1} + + assert dict(2*u*x*y + z) == dict(x*y*2*u + z) == {(1, 1, 0): 2*u, (0, 0, 1): 1} + assert dict(u*2*x*y + z) == dict(2*x*y*u + z) == {(1, 1, 0): 2*u, (0, 0, 1): 1} + assert dict(2*u*x*y + z) == dict(x*y*2*u + z) == {(1, 1, 0): 2*u, (0, 0, 1): 1} + assert dict(u*x*y*2 + z) == dict(x*y*u*2 + z) == {(1, 1, 0): 2*u, (0, 0, 1): 1} + + assert dict(2*u*y*x + z) == dict(y*x*2*u + z) == {(1, 1, 0): 2*u, (0, 0, 1): 1} + assert dict(u*2*y*x + z) == dict(2*y*x*u + z) == {(1, 1, 0): 2*u, (0, 0, 1): 1} + assert dict(2*u*y*x + z) == dict(y*x*2*u + z) == {(1, 1, 0): 2*u, (0, 0, 1): 1} + assert dict(u*y*x*2 + z) == dict(y*x*u*2 + z) == {(1, 1, 0): 2*u, (0, 0, 1): 1} + + assert dict(3*u*(x + y) + z) == dict((x + y)*3*u + z) == {(1, 0, 0): 3*u, (0, 1, 0): 3*u, (0, 0, 1): 1} + + raises(TypeError, lambda: t*x + z) + raises(TypeError, lambda: x*t + z) + raises(TypeError, lambda: t*u + z) + raises(TypeError, lambda: u*t + z) + + Fuv, u,v = field("u,v", ZZ) + Rxyz, x,y,z = ring("x,y,z", Fuv.to_domain()) + + assert dict(u*x) == dict(x*u) == {(1, 0, 0): u} + +def test_PolyElement___div__(): + R, x,y,z = ring("x,y,z", ZZ) + + assert (2*x**2 - 4)/2 == x**2 - 2 + assert (2*x**2 - 3)/2 == x**2 + + assert (x**2 - 1)/x == (x**2 - 1).quo(x) == x + assert (x**2 - x)/x == (x**2 - x).quo(x) == x - 1 + + assert (x**2 - 1)/(2*x) == (x**2 - 1).quo(2*x)== 0 + assert (x**2 - x)/(x - 1) == (x**2 - x).quo(x - 1) == x + + R, x,y,z = ring("x,y,z", ZZ) + assert len(list((x**2/3 + y**3/4 + z**4/5).terms())) == 0 + + R, x,y,z = ring("x,y,z", QQ) + assert len(list((x**2/3 + y**3/4 + z**4/5).terms())) == 3 + + Rt, t = ring("t", ZZ) + Ruv, u,v = ring("u,v", ZZ) + Rxyz, x,y,z = ring("x,y,z", Ruv.to_domain()) + + assert dict((u**2*x + u)/u) == {(1, 0, 0): u, (0, 0, 0): 1} + raises(TypeError, lambda: u/(u**2*x + u)) + + raises(TypeError, lambda: t/x) + # TODO: raises(TypeError, lambda: x/t) + raises(TypeError, lambda: t/u) + raises(TypeError, lambda: u/t) + +def test_PolyElement_pow(): + R, x = ring("x", ZZ, grlex) + f = 2*x + 3 + + assert f**0 == 1 + assert f**1 == f + + assert f**2 == f._pow_generic(2) == f._pow_multinomial(2) == 4*x**2 + 12*x + 9 + assert f**3 == f._pow_generic(3) == f._pow_multinomial(3) == 8*x**3 + 36*x**2 + 54*x + 27 + assert f**4 == f._pow_generic(4) == f._pow_multinomial(4) == 16*x**4 + 96*x**3 + 216*x**2 + 216*x + 81 + assert f**5 == f._pow_generic(5) == f._pow_multinomial(5) == 32*x**5 + 240*x**4 + 720*x**3 + 1080*x**2 + 810*x + 243 + + R, x,y,z = ring("x,y,z", ZZ, grlex) + f = x**3*y - 2*x*y**2 - 3*z + 1 + g = x**6*y**2 - 4*x**4*y**3 - 6*x**3*y*z + 2*x**3*y + 4*x**2*y**4 + 12*x*y**2*z - 4*x*y**2 + 9*z**2 - 6*z + 1 + + assert f**2 == f._pow_generic(2) == f._pow_multinomial(2) == g + + raises(ValueError, lambda: f**-2) + +def test_PolyElement_div(): + R, x = ring("x", ZZ, grlex) + + f = x**3 - 12*x**2 - 42 + g = x - 3 + + q = x**2 - 9*x - 27 + r = -123 + + assert f.div([g]) == ([q], r) + + R, x = ring("x", ZZ, grlex) + f = x**2 + 2*x + 2 + assert f.div([R(1)]) == ([f], 0) + + R, x = ring("x", QQ, grlex) + f = x**2 + 2*x + 2 + assert f.div([R(2)]) == ([QQ(1,2)*x**2 + x + 1], 0) + + R, x,y = ring("x,y", ZZ, grlex) + f = 4*x**2*y - 2*x*y + 4*x - 2*y + 8 + + assert f.div([R(2)]) == ([2*x**2*y - x*y + 2*x - y + 4], 0) + assert f.div([2*y]) == ([2*x**2 - x - 1], 4*x + 8) + + f = x - 1 + g = y - 1 + + assert f.div([g]) == ([0], f) + + f = x*y**2 + 1 + G = [x*y + 1, y + 1] + + Q = [y, -1] + r = 2 + + assert f.div(G) == (Q, r) + + f = x**2*y + x*y**2 + y**2 + G = [x*y - 1, y**2 - 1] + + Q = [x + y, 1] + r = x + y + 1 + + assert f.div(G) == (Q, r) + + G = [y**2 - 1, x*y - 1] + + Q = [x + 1, x] + r = 2*x + 1 + + assert f.div(G) == (Q, r) + +def test_PolyElement_rem(): + R, x = ring("x", ZZ, grlex) + + f = x**3 - 12*x**2 - 42 + g = x - 3 + r = -123 + + assert f.rem([g]) == f.div([g])[1] == r + + R, x,y = ring("x,y", ZZ, grlex) + + f = 4*x**2*y - 2*x*y + 4*x - 2*y + 8 + + assert f.rem([R(2)]) == f.div([R(2)])[1] == 0 + assert f.rem([2*y]) == f.div([2*y])[1] == 4*x + 8 + + f = x - 1 + g = y - 1 + + assert f.rem([g]) == f.div([g])[1] == f + + f = x*y**2 + 1 + G = [x*y + 1, y + 1] + r = 2 + + assert f.rem(G) == f.div(G)[1] == r + + f = x**2*y + x*y**2 + y**2 + G = [x*y - 1, y**2 - 1] + r = x + y + 1 + + assert f.rem(G) == f.div(G)[1] == r + + G = [y**2 - 1, x*y - 1] + r = 2*x + 1 + + assert f.rem(G) == f.div(G)[1] == r + +def test_PolyElement_deflate(): + R, x = ring("x", ZZ) + + assert (2*x**2).deflate(x**4 + 4*x**2 + 1) == ((2,), [2*x, x**2 + 4*x + 1]) + + R, x,y = ring("x,y", ZZ) + + assert R(0).deflate(R(0)) == ((1, 1), [0, 0]) + assert R(1).deflate(R(0)) == ((1, 1), [1, 0]) + assert R(1).deflate(R(2)) == ((1, 1), [1, 2]) + assert R(1).deflate(2*y) == ((1, 1), [1, 2*y]) + assert (2*y).deflate(2*y) == ((1, 1), [2*y, 2*y]) + assert R(2).deflate(2*y**2) == ((1, 2), [2, 2*y]) + assert (2*y**2).deflate(2*y**2) == ((1, 2), [2*y, 2*y]) + + f = x**4*y**2 + x**2*y + 1 + g = x**2*y**3 + x**2*y + 1 + + assert f.deflate(g) == ((2, 1), [x**2*y**2 + x*y + 1, x*y**3 + x*y + 1]) + +def test_PolyElement_diff(): + R, X = xring("x:11", QQ) + + f = QQ(288,5)*X[0]**8*X[1]**6*X[4]**3*X[10]**2 + 8*X[0]**2*X[2]**3*X[4]**3 +2*X[0]**2 - 2*X[1]**2 + + assert f.diff(X[0]) == QQ(2304,5)*X[0]**7*X[1]**6*X[4]**3*X[10]**2 + 16*X[0]*X[2]**3*X[4]**3 + 4*X[0] + assert f.diff(X[4]) == QQ(864,5)*X[0]**8*X[1]**6*X[4]**2*X[10]**2 + 24*X[0]**2*X[2]**3*X[4]**2 + assert f.diff(X[10]) == QQ(576,5)*X[0]**8*X[1]**6*X[4]**3*X[10] + +def test_PolyElement_clear_denoms(): + R, x,y = ring("x,y", QQ) + + assert R(1).clear_denoms() == (ZZ(1), 1) + assert R(7).clear_denoms() == (ZZ(1), 7) + + assert R(QQ(7,3)).clear_denoms() == (3, 7) + assert R(QQ(7,3)).clear_denoms() == (3, 7) + + assert (3*x**2 + x).clear_denoms() == (1, 3*x**2 + x) + assert (x**2 + QQ(1,2)*x).clear_denoms() == (2, 2*x**2 + x) + + rQQ, x,t = ring("x,t", QQ, lex) + rZZ, X,T = ring("x,t", ZZ, lex) + + F = [x - QQ(17824537287975195925064602467992950991718052713078834557692023531499318507213727406844943097,413954288007559433755329699713866804710749652268151059918115348815925474842910720000)*t**7 + - QQ(4882321164854282623427463828745855894130208215961904469205260756604820743234704900167747753,12936071500236232304854053116058337647210926633379720622441104650497671088840960000)*t**6 + - QQ(36398103304520066098365558157422127347455927422509913596393052633155821154626830576085097433,25872143000472464609708106232116675294421853266759441244882209300995342177681920000)*t**5 + - QQ(168108082231614049052707339295479262031324376786405372698857619250210703675982492356828810819,58212321751063045371843239022262519412449169850208742800984970927239519899784320000)*t**4 + - QQ(5694176899498574510667890423110567593477487855183144378347226247962949388653159751849449037,1617008937529529038106756639507292205901365829172465077805138081312208886105120000)*t**3 + - QQ(154482622347268833757819824809033388503591365487934245386958884099214649755244381307907779,60637835157357338929003373981523457721301218593967440417692678049207833228942000)*t**2 + - QQ(2452813096069528207645703151222478123259511586701148682951852876484544822947007791153163,2425513406294293557160134959260938308852048743758697616707707121968313329157680)*t + - QQ(34305265428126440542854669008203683099323146152358231964773310260498715579162112959703,202126117191191129763344579938411525737670728646558134725642260164026110763140), + t**8 + QQ(693749860237914515552,67859264524169150569)*t**7 + + QQ(27761407182086143225024,610733380717522355121)*t**6 + + QQ(7785127652157884044288,67859264524169150569)*t**5 + + QQ(36567075214771261409792,203577793572507451707)*t**4 + + QQ(36336335165196147384320,203577793572507451707)*t**3 + + QQ(7452455676042754048000,67859264524169150569)*t**2 + + QQ(2593331082514399232000,67859264524169150569)*t + + QQ(390399197427343360000,67859264524169150569)] + + G = [3725588592068034903797967297424801242396746870413359539263038139343329273586196480000*X - + 160420835591776763325581422211936558925462474417709511019228211783493866564923546661604487873*T**7 - + 1406108495478033395547109582678806497509499966197028487131115097902188374051595011248311352864*T**6 - + 5241326875850889518164640374668786338033653548841427557880599579174438246266263602956254030352*T**5 - + 10758917262823299139373269714910672770004760114329943852726887632013485035262879510837043892416*T**4 - + 13119383576444715672578819534846747735372132018341964647712009275306635391456880068261130581248*T**3 - + 9491412317016197146080450036267011389660653495578680036574753839055748080962214787557853941760*T**2 - + 3767520915562795326943800040277726397326609797172964377014046018280260848046603967211258368000*T - + 632314652371226552085897259159210286886724229880266931574701654721512325555116066073245696000, + 610733380717522355121*T**8 + + 6243748742141230639968*T**7 + + 27761407182086143225024*T**6 + + 70066148869420956398592*T**5 + + 109701225644313784229376*T**4 + + 109009005495588442152960*T**3 + + 67072101084384786432000*T**2 + + 23339979742629593088000*T + + 3513592776846090240000] + + assert [ f.clear_denoms()[1].set_ring(rZZ) for f in F ] == G + +def test_PolyElement_cofactors(): + R, x, y = ring("x,y", ZZ) + + f, g = R(0), R(0) + assert f.cofactors(g) == (0, 0, 0) + + f, g = R(2), R(0) + assert f.cofactors(g) == (2, 1, 0) + + f, g = R(-2), R(0) + assert f.cofactors(g) == (2, -1, 0) + + f, g = R(0), R(-2) + assert f.cofactors(g) == (2, 0, -1) + + f, g = R(0), 2*x + 4 + assert f.cofactors(g) == (2*x + 4, 0, 1) + + f, g = 2*x + 4, R(0) + assert f.cofactors(g) == (2*x + 4, 1, 0) + + f, g = R(2), R(2) + assert f.cofactors(g) == (2, 1, 1) + + f, g = R(-2), R(2) + assert f.cofactors(g) == (2, -1, 1) + + f, g = R(2), R(-2) + assert f.cofactors(g) == (2, 1, -1) + + f, g = R(-2), R(-2) + assert f.cofactors(g) == (2, -1, -1) + + f, g = x**2 + 2*x + 1, R(1) + assert f.cofactors(g) == (1, x**2 + 2*x + 1, 1) + + f, g = x**2 + 2*x + 1, R(2) + assert f.cofactors(g) == (1, x**2 + 2*x + 1, 2) + + f, g = 2*x**2 + 4*x + 2, R(2) + assert f.cofactors(g) == (2, x**2 + 2*x + 1, 1) + + f, g = R(2), 2*x**2 + 4*x + 2 + assert f.cofactors(g) == (2, 1, x**2 + 2*x + 1) + + f, g = 2*x**2 + 4*x + 2, x + 1 + assert f.cofactors(g) == (x + 1, 2*x + 2, 1) + + f, g = x + 1, 2*x**2 + 4*x + 2 + assert f.cofactors(g) == (x + 1, 1, 2*x + 2) + + R, x, y, z, t = ring("x,y,z,t", ZZ) + + f, g = t**2 + 2*t + 1, 2*t + 2 + assert f.cofactors(g) == (t + 1, t + 1, 2) + + f, g = z**2*t**2 + 2*z**2*t + z**2 + z*t + z, t**2 + 2*t + 1 + h, cff, cfg = t + 1, z**2*t + z**2 + z, t + 1 + + assert f.cofactors(g) == (h, cff, cfg) + assert g.cofactors(f) == (h, cfg, cff) + + R, x, y = ring("x,y", QQ) + + f = QQ(1,2)*x**2 + x + QQ(1,2) + g = QQ(1,2)*x + QQ(1,2) + + h = x + 1 + + assert f.cofactors(g) == (h, g, QQ(1,2)) + assert g.cofactors(f) == (h, QQ(1,2), g) + + R, x, y = ring("x,y", RR) + + f = 2.1*x*y**2 - 2.1*x*y + 2.1*x + g = 2.1*x**3 + h = 1.0*x + + assert f.cofactors(g) == (h, f/h, g/h) + assert g.cofactors(f) == (h, g/h, f/h) + +def test_PolyElement_gcd(): + R, x, y = ring("x,y", QQ) + + f = QQ(1,2)*x**2 + x + QQ(1,2) + g = QQ(1,2)*x + QQ(1,2) + + assert f.gcd(g) == x + 1 + +def test_PolyElement_cancel(): + R, x, y = ring("x,y", ZZ) + + f = 2*x**3 + 4*x**2 + 2*x + g = 3*x**2 + 3*x + F = 2*x + 2 + G = 3 + + assert f.cancel(g) == (F, G) + + assert (-f).cancel(g) == (-F, G) + assert f.cancel(-g) == (-F, G) + + R, x, y = ring("x,y", QQ) + + f = QQ(1,2)*x**3 + x**2 + QQ(1,2)*x + g = QQ(1,3)*x**2 + QQ(1,3)*x + F = 3*x + 3 + G = 2 + + assert f.cancel(g) == (F, G) + + assert (-f).cancel(g) == (-F, G) + assert f.cancel(-g) == (-F, G) + +def test_PolyElement_max_norm(): + R, x, y = ring("x,y", ZZ) + + assert R(0).max_norm() == 0 + assert R(1).max_norm() == 1 + + assert (x**3 + 4*x**2 + 2*x + 3).max_norm() == 4 + +def test_PolyElement_evaluate(): + R, x = ring("x", ZZ) + r = (x**3 + 4*x**2 + 2*x + 3).evaluate(x, 0) + assert r == 3 and not isinstance(r, PolyElement) + + R, x, y, z = ring("x,y,z", ZZ) + r = (x**3 + 4*x**2 + 2*x + 3).evaluate(x, 0) + assert r == 3 and isinstance(r, PolyElement) and r.ring == R[1:] + r = (x**3 + 4*x**2 + 2*x + 3).evaluate([(x, 0), (y, 0)]) + assert r == 3 and isinstance(r, PolyElement) and r.ring == R[2:] + +def test_PolyElement_subs(): + R, x = ring("x", ZZ) + r = (x**3 + 4*x**2 + 2*x + 3).subs(x, 0) + assert r == 3 and isinstance(r, PolyElement) and r.ring == R + + R, x, y, z = ring("x,y,z", ZZ) + r = (x**3 + 4*x**2 + 2*x + 3).subs(x, 0) + assert r == 3 and isinstance(r, PolyElement) and r.ring == R + r = (x**3 + 4*x**2 + 2*x + 3).subs([(x, 0), (y, 0)]) + assert r == 3 and isinstance(r, PolyElement) and r.ring == R + +def test_PolyElement_compose(): + R, x = ring("x", ZZ) + r = (x**3 + 4*x**2 + 2*x + 3).compose(x, 0) + assert r == 3 and isinstance(r, PolyElement) and r.ring == R + + R, x, y, z = ring("x,y,z", ZZ) + r = (x**3 + 4*x**2 + 2*x + 3).compose(x, 0) + assert r == 3 and isinstance(r, PolyElement) and r.ring == R + r = (x**3 + 4*x**2 + 2*x + 3).compose([(x, 0), (y, 0)]) + assert r == 3 and isinstance(r, PolyElement) and r.ring == R + + r = (x**3 + 4*x**2 + 2*x*y*z + 3).compose(x, y*z**2 - 1) + q = (y*z**2 - 1)**3 + 4*(y*z**2 - 1)**2 + 2*(y*z**2 - 1)*y*z + 3 + assert r == q and isinstance(r, PolyElement) and r.ring == R + +def test_PolyElement_is_(): + R, x,y = ring("x,y", QQ) + + assert (x - x).is_generator == False + assert (x - x).is_ground == True + assert (x - x).is_monomial == True + assert (x - x).is_term == True + + assert (x - x + 1).is_generator == False + assert (x - x + 1).is_ground == True + assert (x - x + 1).is_monomial == True + assert (x - x + 1).is_term == True + + assert x.is_generator == True + assert x.is_ground == False + assert x.is_monomial == True + assert x.is_term == True + + assert (x*y).is_generator == False + assert (x*y).is_ground == False + assert (x*y).is_monomial == True + assert (x*y).is_term == True + + assert (3*x).is_generator == False + assert (3*x).is_ground == False + assert (3*x).is_monomial == False + assert (3*x).is_term == True + + assert (3*x + 1).is_generator == False + assert (3*x + 1).is_ground == False + assert (3*x + 1).is_monomial == False + assert (3*x + 1).is_term == False diff -Nru python3-sympy-0.7.2/sympy/polys/tests/test_rootisolation.py python3-sympy-0.7.3/sympy/polys/tests/test_rootisolation.py --- python3-sympy-0.7.2/sympy/polys/tests/test_rootisolation.py 2012-10-17 03:02:22.000000000 +0000 +++ python3-sympy-0.7.3/sympy/polys/tests/test_rootisolation.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,685 +1,788 @@ """Tests for real and complex root isolation and refinement algorithms. """ -from sympy.polys.rootisolation import ( - dup_sturm, - dup_refine_real_root, - dup_isolate_real_roots, - dup_isolate_real_roots_sqf, - dup_isolate_real_roots_list, - dup_count_real_roots, - dup_count_complex_roots, - dup_isolate_complex_roots_sqf, - dup_isolate_all_roots, - dup_isolate_all_roots_sqf) - -from sympy.polys.densebasic import ( - dup_from_raw_dict) - -from sympy.polys.sqfreetools import ( - dup_sqf_part) - -from sympy.polys.polyerrors import ( - RefinementFailed, - DomainError) - +from sympy.polys.rings import ring from sympy.polys.domains import ZZ, QQ, EX - +from sympy.polys.polyerrors import DomainError, RefinementFailed from sympy.utilities.pytest import raises def test_dup_sturm(): - assert dup_sturm([QQ(5)], QQ) == [[QQ(1)]] - assert dup_sturm([QQ(1),QQ(0)], QQ) == [[QQ(1),QQ(0)], [QQ(1)]] + R, x = ring("x", QQ) - f = QQ.map([1,-2,3,-5]) + assert R.dup_sturm(5) == [1] + assert R.dup_sturm(x) == [x, 1] + + f = x**3 - 2*x**2 + 3*x - 5 + assert R.dup_sturm(f) == [f, 3*x**2 - 4*x + 3, -QQ(10,9)*x + QQ(13,3), -QQ(3303,100)] - assert dup_sturm(f, QQ) == \ - [f, [QQ(3),QQ(-4),QQ(3)], [QQ(-10,9),QQ(13,3)], [QQ(-3303,100)]] def test_dup_refine_real_root(): - f = [1,0,-2] + R, x = ring("x", ZZ) + f = x**2 - 2 + + assert R.dup_refine_real_root(f, QQ(1), QQ(1), steps=1) == (QQ(1), QQ(1)) + assert R.dup_refine_real_root(f, QQ(1), QQ(1), steps=9) == (QQ(1), QQ(1)) - assert dup_refine_real_root(f, QQ(1), QQ(1), ZZ, steps=1) == (QQ(1), QQ(1)) - assert dup_refine_real_root(f, QQ(1), QQ(1), ZZ, steps=9) == (QQ(1), QQ(1)) + raises(ValueError, lambda: R.dup_refine_real_root(f, QQ(-2), QQ(2))) - raises(ValueError, lambda: dup_refine_real_root(f, QQ(-2), QQ(2), ZZ)) + s, t = QQ(1, 1), QQ(2, 1) - s, t = QQ(1,1), QQ(2,1) + assert R.dup_refine_real_root(f, s, t, steps=0) == (QQ(1, 1), QQ(2, 1)) + assert R.dup_refine_real_root(f, s, t, steps=1) == (QQ(1, 1), QQ(3, 2)) + assert R.dup_refine_real_root(f, s, t, steps=2) == (QQ(4, 3), QQ(3, 2)) + assert R.dup_refine_real_root(f, s, t, steps=3) == (QQ(7, 5), QQ(3, 2)) + assert R.dup_refine_real_root(f, s, t, steps=4) == (QQ(7, 5), QQ(10, 7)) - assert dup_refine_real_root(f, s, t, ZZ, steps=0) == (QQ(1, 1), QQ(2, 1)) - assert dup_refine_real_root(f, s, t, ZZ, steps=1) == (QQ(1, 1), QQ(3, 2)) - assert dup_refine_real_root(f, s, t, ZZ, steps=2) == (QQ(4, 3), QQ(3, 2)) - assert dup_refine_real_root(f, s, t, ZZ, steps=3) == (QQ(7, 5), QQ(3, 2)) - assert dup_refine_real_root(f, s, t, ZZ, steps=4) == (QQ(7, 5), QQ(10, 7)) + s, t = QQ(1, 1), QQ(3, 2) - s, t = QQ(1,1), QQ(3,2) + assert R.dup_refine_real_root(f, s, t, steps=0) == (QQ(1, 1), QQ(3, 2)) + assert R.dup_refine_real_root(f, s, t, steps=1) == (QQ(4, 3), QQ(3, 2)) + assert R.dup_refine_real_root(f, s, t, steps=2) == (QQ(7, 5), QQ(3, 2)) + assert R.dup_refine_real_root(f, s, t, steps=3) == (QQ(7, 5), QQ(10, 7)) + assert R.dup_refine_real_root(f, s, t, steps=4) == (QQ(7, 5), QQ(17, 12)) - assert dup_refine_real_root(f, s, t, ZZ, steps=0) == (QQ(1, 1), QQ(3, 2)) - assert dup_refine_real_root(f, s, t, ZZ, steps=1) == (QQ(4, 3), QQ(3, 2)) - assert dup_refine_real_root(f, s, t, ZZ, steps=2) == (QQ(7, 5), QQ(3, 2)) - assert dup_refine_real_root(f, s, t, ZZ, steps=3) == (QQ(7, 5), QQ(10, 7)) - assert dup_refine_real_root(f, s, t, ZZ, steps=4) == (QQ(7, 5), QQ(17, 12)) + s, t = QQ(1, 1), QQ(5, 3) - s, t = QQ(1,1), QQ(5,3) + assert R.dup_refine_real_root(f, s, t, steps=0) == (QQ(1, 1), QQ(5, 3)) + assert R.dup_refine_real_root(f, s, t, steps=1) == (QQ(1, 1), QQ(3, 2)) + assert R.dup_refine_real_root(f, s, t, steps=2) == (QQ(7, 5), QQ(3, 2)) + assert R.dup_refine_real_root(f, s, t, steps=3) == (QQ(7, 5), QQ(13, 9)) + assert R.dup_refine_real_root(f, s, t, steps=4) == (QQ(7, 5), QQ(10, 7)) - assert dup_refine_real_root(f, s, t, ZZ, steps=0) == (QQ(1, 1), QQ(5, 3)) - assert dup_refine_real_root(f, s, t, ZZ, steps=1) == (QQ(1, 1), QQ(3, 2)) - assert dup_refine_real_root(f, s, t, ZZ, steps=2) == (QQ(7, 5), QQ(3, 2)) - assert dup_refine_real_root(f, s, t, ZZ, steps=3) == (QQ(7, 5), QQ(13, 9)) - assert dup_refine_real_root(f, s, t, ZZ, steps=4) == (QQ(7, 5), QQ(10, 7)) + s, t = QQ(-1, 1), QQ(-2, 1) - s, t = QQ(-1,1), QQ(-2,1) + assert R.dup_refine_real_root(f, s, t, steps=0) == (-QQ(2, 1), -QQ(1, 1)) + assert R.dup_refine_real_root(f, s, t, steps=1) == (-QQ(3, 2), -QQ(1, 1)) + assert R.dup_refine_real_root(f, s, t, steps=2) == (-QQ(3, 2), -QQ(4, 3)) + assert R.dup_refine_real_root(f, s, t, steps=3) == (-QQ(3, 2), -QQ(7, 5)) + assert R.dup_refine_real_root(f, s, t, steps=4) == (-QQ(10, 7), -QQ(7, 5)) - assert dup_refine_real_root(f, s, t, ZZ, steps=0) == (-QQ(2, 1), -QQ(1, 1)) - assert dup_refine_real_root(f, s, t, ZZ, steps=1) == (-QQ(3, 2), -QQ(1, 1)) - assert dup_refine_real_root(f, s, t, ZZ, steps=2) == (-QQ(3, 2), -QQ(4, 3)) - assert dup_refine_real_root(f, s, t, ZZ, steps=3) == (-QQ(3, 2), -QQ(7, 5)) - assert dup_refine_real_root(f, s, t, ZZ, steps=4) == (-QQ(10, 7), -QQ(7, 5)) + raises(RefinementFailed, lambda: R.dup_refine_real_root(f, QQ(0), QQ(1))) - raises(RefinementFailed, lambda: dup_refine_real_root(f, QQ(0), QQ(1), ZZ)) + s, t, u, v, w = QQ(1), QQ(2), QQ(24, 17), QQ(17, 12), QQ(7, 5) - s, t, u, v, w = QQ(1), QQ(2), QQ(24,17), QQ(17,12), QQ(7,5) + assert R.dup_refine_real_root(f, s, t, eps=QQ(1, 100)) == (u, v) + assert R.dup_refine_real_root(f, s, t, steps=6) == (u, v) - assert dup_refine_real_root(f, s, t, ZZ, eps=QQ(1,100)) == (u, v) - assert dup_refine_real_root(f, s, t, ZZ, steps=6) == (u, v) + assert R.dup_refine_real_root(f, s, t, eps=QQ(1, 100), steps=5) == (w, v) + assert R.dup_refine_real_root(f, s, t, eps=QQ(1, 100), steps=6) == (u, v) + assert R.dup_refine_real_root(f, s, t, eps=QQ(1, 100), steps=7) == (u, v) - assert dup_refine_real_root(f, s, t, ZZ, eps=QQ(1,100), steps=5) == (w, v) - assert dup_refine_real_root(f, s, t, ZZ, eps=QQ(1,100), steps=6) == (u, v) - assert dup_refine_real_root(f, s, t, ZZ, eps=QQ(1,100), steps=7) == (u, v) + s, t, u, v = QQ(-2), QQ(-1), QQ(-3, 2), QQ(-4, 3) - s, t, u, v = QQ(-2), QQ(-1), QQ(-3,2), QQ(-4,3) + assert R.dup_refine_real_root(f, s, t, disjoint=QQ(-5)) == (s, t) + assert R.dup_refine_real_root(f, s, t, disjoint=-v) == (s, t) + assert R.dup_refine_real_root(f, s, t, disjoint=v) == (u, v) - assert dup_refine_real_root([1,0,-2], s, t, ZZ, disjoint=QQ(-5)) == (s, t) - assert dup_refine_real_root([1,0,-2], s, t, ZZ, disjoint=-v) == (s, t) - assert dup_refine_real_root([1,0,-2], s, t, ZZ, disjoint=v) == (u, v) + s, t, u, v = QQ(1), QQ(2), QQ(4, 3), QQ(3, 2) - s, t, u, v = QQ(1), QQ(2), QQ(4,3), QQ(3,2) + assert R.dup_refine_real_root(f, s, t, disjoint=QQ(5)) == (s, t) + assert R.dup_refine_real_root(f, s, t, disjoint=-u) == (s, t) + assert R.dup_refine_real_root(f, s, t, disjoint=u) == (u, v) - assert dup_refine_real_root([1,0,-2], s, t, ZZ, disjoint=QQ(5)) == (s, t) - assert dup_refine_real_root([1,0,-2], s, t, ZZ, disjoint=-u) == (s, t) - assert dup_refine_real_root([1,0,-2], s, t, ZZ, disjoint=u) == (u, v) def test_dup_isolate_real_roots_sqf(): - assert dup_isolate_real_roots_sqf([], ZZ) == [] - assert dup_isolate_real_roots_sqf([5], ZZ) == [] + R, x = ring("x", ZZ) - assert dup_isolate_real_roots_sqf([1, 1,0], ZZ) == [(-QQ(1), -QQ(1)), (QQ(0), QQ(0))] - assert dup_isolate_real_roots_sqf([1,-1,0], ZZ) == [( QQ(0), QQ(0)), (QQ(1), QQ(1))] + assert R.dup_isolate_real_roots_sqf(0) == [] + assert R.dup_isolate_real_roots_sqf(5) == [] - assert dup_isolate_real_roots_sqf([1,0,0,1,1], ZZ) == [] + assert R.dup_isolate_real_roots_sqf(x**2 + x) == [(-1, -1), (0, 0)] + assert R.dup_isolate_real_roots_sqf(x**2 - x) == [( 0, 0), (1, 1)] - I = [ (-QQ(2), -QQ(1)), (QQ(1), QQ(2))] - - assert dup_isolate_real_roots_sqf([1,0,-2], ZZ) == I - assert dup_isolate_real_roots_sqf([-1,0,2], ZZ) == I - - assert dup_isolate_real_roots_sqf([1,-1], ZZ) == \ - [(QQ(1), QQ(1))] - assert dup_isolate_real_roots_sqf([1,-3,2], ZZ) == \ - [(QQ(1), QQ(1)), (QQ(2), QQ(2))] - assert dup_isolate_real_roots_sqf([1,-6,11,-6], ZZ) == \ - [(QQ(1), QQ(1)), (QQ(2), QQ(2)), (QQ(3), QQ(3))] - assert dup_isolate_real_roots_sqf([1,-10,35,-50,24], ZZ) == \ - [(QQ(1), QQ(1)), (QQ(2), QQ(2)), (QQ(3), QQ(3)), (QQ(4), QQ(4))] - assert dup_isolate_real_roots_sqf([1,-15,85,-225,274,-120], ZZ) == \ - [(QQ(1), QQ(1)), (QQ(2), QQ(2)), (QQ(3), QQ(3)), (QQ(4), QQ(4)), (QQ(5), QQ(5))] - - assert dup_isolate_real_roots_sqf([1,-10], ZZ) == \ - [(QQ(10), QQ(10))] - assert dup_isolate_real_roots_sqf([1,-30,200], ZZ) == \ - [(QQ(10), QQ(10)), (QQ(20), QQ(20))] - assert dup_isolate_real_roots_sqf([1,-60,1100,-6000], ZZ) == \ - [(QQ(10), QQ(10)), (QQ(20), QQ(20)), (QQ(30), QQ(30))] - assert dup_isolate_real_roots_sqf([1,-100,3500,-50000,240000], ZZ) == \ - [(QQ(10), QQ(10)), (QQ(20), QQ(20)), (QQ(30), QQ(30)), (QQ(40), QQ(40))] - assert dup_isolate_real_roots_sqf([1,-150,8500,-225000,2740000,-12000000], ZZ) == \ - [(QQ(10), QQ(10)), (QQ(20), QQ(20)), (QQ(30), QQ(30)), (QQ(40), QQ(40)), (QQ(50), QQ(50))] - - assert dup_isolate_real_roots_sqf([1,1], ZZ) == \ - [(-QQ(1), -QQ(1))] - assert dup_isolate_real_roots_sqf([1,3,2], ZZ) == \ - [(-QQ(2), -QQ(2)), (-QQ(1), -QQ(1))] - assert dup_isolate_real_roots_sqf([1,6,11,6], ZZ) == \ - [(-QQ(3), -QQ(3)), (-QQ(2), -QQ(2)), (-QQ(1), -QQ(1))] - assert dup_isolate_real_roots_sqf([1,10,35,50,24], ZZ) == \ - [(-QQ(4), -QQ(4)), (-QQ(3), -QQ(3)), (-QQ(2), -QQ(2)), (-QQ(1), -QQ(1))] - assert dup_isolate_real_roots_sqf([1,15,85,225,274,120], ZZ) == \ - [(-QQ(5), -QQ(5)), (-QQ(4), -QQ(4)), (-QQ(3), -QQ(3)), (-QQ(2), -QQ(2)), (-QQ(1), -QQ(1))] - - assert dup_isolate_real_roots_sqf([1,10], ZZ) == \ - [(-QQ(10), -QQ(10))] - assert dup_isolate_real_roots_sqf([1,30,200], ZZ) == \ - [(-QQ(20), -QQ(20)), (-QQ(10), -QQ(10))] - assert dup_isolate_real_roots_sqf([1,60,1100,6000], ZZ) == \ - [(-QQ(30), -QQ(30)), (-QQ(20), -QQ(20)), (-QQ(10), -QQ(10))] - assert dup_isolate_real_roots_sqf([1,100,3500,50000,240000], ZZ) == \ - [(-QQ(40), -QQ(40)), (-QQ(30), -QQ(30)), (-QQ(20), -QQ(20)), (-QQ(10), -QQ(10))] - assert dup_isolate_real_roots_sqf([1,150,8500,225000,2740000,12000000], ZZ) == \ - [(-QQ(50), -QQ(50)), (-QQ(40), -QQ(40)), (-QQ(30), -QQ(30)), (-QQ(20), -QQ(20)), (-QQ(10), -QQ(10))] - - assert dup_isolate_real_roots_sqf([1,0,-5], ZZ) == \ - [(QQ(-3), QQ(-2)), (QQ(2), QQ(3))] - assert dup_isolate_real_roots_sqf([1,0,0,-5], ZZ) == \ - [(QQ(1), QQ(2))] - assert dup_isolate_real_roots_sqf([1,0,0,0,-5], ZZ) == \ - [(QQ(-2), QQ(-1)), (QQ(1), QQ(2))] - assert dup_isolate_real_roots_sqf([1,0,0,0,0,-5], ZZ) == \ - [(QQ(1), QQ(2))] - assert dup_isolate_real_roots_sqf([1,0,0,0,0,0,-5], ZZ) == \ - [(QQ(-2), QQ(-1)), (QQ(1), QQ(2))] - assert dup_isolate_real_roots_sqf([1,0,0,0,0,0,0,-5], ZZ) == \ - [(QQ(1), QQ(2))] - assert dup_isolate_real_roots_sqf([1,0,0,0,0,0,0,0,-5], ZZ) == \ - [(QQ(-2), QQ(-1)), (QQ(1), QQ(2))] - assert dup_isolate_real_roots_sqf([1,0,0,0,0,0,0,0,0,-5], ZZ) == \ - [(QQ(1), QQ(2))] - - assert dup_isolate_real_roots_sqf([1,0,-1], ZZ) == \ - [(-QQ(1), -QQ(1)), (QQ(1), QQ(1))] - assert dup_isolate_real_roots_sqf([1,2,-1,-2], ZZ) == \ - [(-QQ(2), -QQ(2)), (-QQ(1), -QQ(1)), (QQ(1), QQ(1))] - assert dup_isolate_real_roots_sqf([1,0,-5,0,4], ZZ) == \ - [(-QQ(2), -QQ(2)), (-QQ(1), -QQ(1)), (QQ(1), QQ(1)), (QQ(2), QQ(2))] - assert dup_isolate_real_roots_sqf([1,3,-5,-15,4,12], ZZ) == \ - [(-QQ(3), -QQ(3)), (-QQ(2), -QQ(2)), (-QQ(1), -QQ(1)), (QQ(1), QQ(1)), - ( QQ(2), QQ(2))] - assert dup_isolate_real_roots_sqf([1,0,-14,0,49,0,-36], ZZ) == \ - [(-QQ(3), -QQ(3)), (-QQ(2), -QQ(2)), (-QQ(1), -QQ(1)), (QQ(1), QQ(1)), - ( QQ(2), QQ(2)), ( QQ(3), QQ(3))] - assert dup_isolate_real_roots_sqf([2,1,-28,-14,98,49,-72,-36], ZZ) == \ - [(-QQ(3), -QQ(3)), (-QQ(2), -QQ(2)), (-QQ(1), -QQ(1)), (-QQ(1), QQ(0)), - ( QQ(1), QQ(1)), ( QQ(2), QQ(2)), ( QQ(3), QQ(3))] - assert dup_isolate_real_roots_sqf([4,0,-57,0,210,0,-193,0,36], ZZ) == \ - [(-QQ(3), -QQ(3)), (-QQ(2), -QQ(2)), (-QQ(1), -QQ(1)), (-QQ(1), QQ(0)), - ( QQ(0), QQ(1)), ( QQ(1), QQ(1)), ( QQ(2), QQ(2)), ( QQ(3), QQ(3))] - - f = [9,0,-2] - - assert dup_isolate_real_roots_sqf(f, ZZ) == \ - [(QQ(-1), QQ(0)), (QQ(0), QQ(1))] - - assert dup_isolate_real_roots_sqf(f, ZZ, eps=QQ(1,10)) == \ - [(QQ(-1,2), QQ(-3,7)), (QQ(3,7), QQ(1,2))] - assert dup_isolate_real_roots_sqf(f, ZZ, eps=QQ(1,100)) == \ - [(QQ(-9,19), QQ(-8,17)), (QQ(8,17), QQ(9,19))] - assert dup_isolate_real_roots_sqf(f, ZZ, eps=QQ(1,1000)) == \ - [(QQ(-33,70), QQ(-8,17)), (QQ(8,17), QQ(33,70))] - assert dup_isolate_real_roots_sqf(f, ZZ, eps=QQ(1,10000)) == \ - [(QQ(-33,70), QQ(-107,227)), (QQ(107,227), QQ(33,70))] - assert dup_isolate_real_roots_sqf(f, ZZ, eps=QQ(1,100000)) == \ - [(QQ(-305,647), QQ(-272,577)), (QQ(272,577), QQ(305,647))] - assert dup_isolate_real_roots_sqf(f, ZZ, eps=QQ(1,1000000)) == \ - [(QQ(-1121,2378), QQ(-272,577)), (QQ(272,577), QQ(1121,2378))] + assert R.dup_isolate_real_roots_sqf(x**4 + x + 1) == [] - f = [200100012, -700390052, 700490079, -200240054, 40017, -2] + I = [(-2, -1), (1, 2)] - assert dup_isolate_real_roots_sqf(f, ZZ) == \ - [(QQ(0), QQ(1,10002)), (QQ(1,10002), QQ(1,10002)), (QQ(1,2), QQ(1,2)), (QQ(1), QQ(1)), (QQ(2), QQ(2))] + assert R.dup_isolate_real_roots_sqf(x**2 - 2) == I + assert R.dup_isolate_real_roots_sqf(-x**2 + 2) == I - assert dup_isolate_real_roots_sqf(f, ZZ, eps=QQ(1,100000)) == \ - [(QQ(1,10003), QQ(1,10003)), (QQ(1,10002), QQ(1,10002)), (QQ(1,2), QQ(1,2)), (QQ(1), QQ(1)), (QQ(2), QQ(2))] + assert R.dup_isolate_real_roots_sqf(x - 1) == \ + [(1, 1)] + assert R.dup_isolate_real_roots_sqf(x**2 - 3*x + 2) == \ + [(1, 1), (2, 2)] + assert R.dup_isolate_real_roots_sqf(x**3 - 6*x**2 + 11*x - 6) == \ + [(1, 1), (2, 2), (3, 3)] + assert R.dup_isolate_real_roots_sqf(x**4 - 10*x**3 + 35*x**2 - 50*x + 24) == \ + [(1, 1), (2, 2), (3, 3), (4, 4)] + assert R.dup_isolate_real_roots_sqf(x**5 - 15*x**4 + 85*x**3 - 225*x**2 + 274*x - 120) == \ + [(1, 1), (2, 2), (3, 3), (4, 4), (5, 5)] + + assert R.dup_isolate_real_roots_sqf(x - 10) == \ + [(10, 10)] + assert R.dup_isolate_real_roots_sqf(x**2 - 30*x + 200) == \ + [(10, 10), (20, 20)] + assert R.dup_isolate_real_roots_sqf(x**3 - 60*x**2 + 1100*x - 6000) == \ + [(10, 10), (20, 20), (30, 30)] + assert R.dup_isolate_real_roots_sqf(x**4 - 100*x**3 + 3500*x**2 - 50000*x + 240000) == \ + [(10, 10), (20, 20), (30, 30), (40, 40)] + assert R.dup_isolate_real_roots_sqf(x**5 - 150*x**4 + 8500*x**3 - 225000*x**2 + 2740000*x - 12000000) == \ + [(10, 10), (20, 20), (30, 30), (40, 40), (50, 50)] + + assert R.dup_isolate_real_roots_sqf(x + 1) == \ + [(-1, -1)] + assert R.dup_isolate_real_roots_sqf(x**2 + 3*x + 2) == \ + [(-2, -2), (-1, -1)] + assert R.dup_isolate_real_roots_sqf(x**3 + 6*x**2 + 11*x + 6) == \ + [(-3, -3), (-2, -2), (-1, -1)] + assert R.dup_isolate_real_roots_sqf(x**4 + 10*x**3 + 35*x**2 + 50*x + 24) == \ + [(-4, -4), (-3, -3), (-2, -2), (-1, -1)] + assert R.dup_isolate_real_roots_sqf(x**5 + 15*x**4 + 85*x**3 + 225*x**2 + 274*x + 120) == \ + [(-5, -5), (-4, -4), (-3, -3), (-2, -2), (-1, -1)] + + assert R.dup_isolate_real_roots_sqf(x + 10) == \ + [(-10, -10)] + assert R.dup_isolate_real_roots_sqf(x**2 + 30*x + 200) == \ + [(-20, -20), (-10, -10)] + assert R.dup_isolate_real_roots_sqf(x**3 + 60*x**2 + 1100*x + 6000) == \ + [(-30, -30), (-20, -20), (-10, -10)] + assert R.dup_isolate_real_roots_sqf(x**4 + 100*x**3 + 3500*x**2 + 50000*x + 240000) == \ + [(-40, -40), (-30, -30), (-20, -20), (-10, -10)] + assert R.dup_isolate_real_roots_sqf(x**5 + 150*x**4 + 8500*x**3 + 225000*x**2 + 2740000*x + 12000000) == \ + [(-50, -50), (-40, -40), (-30, -30), (-20, -20), (-10, -10)] + + assert R.dup_isolate_real_roots_sqf(x**2 - 5) == [(-3, -2), (2, 3)] + assert R.dup_isolate_real_roots_sqf(x**3 - 5) == [(1, 2)] + assert R.dup_isolate_real_roots_sqf(x**4 - 5) == [(-2, -1), (1, 2)] + assert R.dup_isolate_real_roots_sqf(x**5 - 5) == [(1, 2)] + assert R.dup_isolate_real_roots_sqf(x**6 - 5) == [(-2, -1), (1, 2)] + assert R.dup_isolate_real_roots_sqf(x**7 - 5) == [(1, 2)] + assert R.dup_isolate_real_roots_sqf(x**8 - 5) == [(-2, -1), (1, 2)] + assert R.dup_isolate_real_roots_sqf(x**9 - 5) == [(1, 2)] + + assert R.dup_isolate_real_roots_sqf(x**2 - 1) == \ + [(-1, -1), (1, 1)] + assert R.dup_isolate_real_roots_sqf(x**3 + 2*x**2 - x - 2) == \ + [(-2, -2), (-1, -1), (1, 1)] + assert R.dup_isolate_real_roots_sqf(x**4 - 5*x**2 + 4) == \ + [(-2, -2), (-1, -1), (1, 1), (2, 2)] + assert R.dup_isolate_real_roots_sqf(x**5 + 3*x**4 - 5*x**3 - 15*x**2 + 4*x + 12) == \ + [(-3, -3), (-2, -2), (-1, -1), (1, 1), (2, 2)] + assert R.dup_isolate_real_roots_sqf(x**6 - 14*x**4 + 49*x**2 - 36) == \ + [(-3, -3), (-2, -2), (-1, -1), (1, 1), (2, 2), (3, 3)] + assert R.dup_isolate_real_roots_sqf(2*x**7 + x**6 - 28*x**5 - 14*x**4 + 98*x**3 + 49*x**2 - 72*x - 36) == \ + [(-3, -3), (-2, -2), (-1, -1), (-1, 0), (1, 1), (2, 2), (3, 3)] + assert R.dup_isolate_real_roots_sqf(4*x**8 - 57*x**6 + 210*x**4 - 193*x**2 + 36) == \ + [(-3, -3), (-2, -2), (-1, -1), (-1, 0), (0, 1), (1, 1), (2, 2), (3, 3)] + + f = 9*x**2 - 2 + + assert R.dup_isolate_real_roots_sqf(f) == \ + [(-1, 0), (0, 1)] + + assert R.dup_isolate_real_roots_sqf(f, eps=QQ(1, 10)) == \ + [(QQ(-1, 2), QQ(-3, 7)), (QQ(3, 7), QQ(1, 2))] + assert R.dup_isolate_real_roots_sqf(f, eps=QQ(1, 100)) == \ + [(QQ(-9, 19), QQ(-8, 17)), (QQ(8, 17), QQ(9, 19))] + assert R.dup_isolate_real_roots_sqf(f, eps=QQ(1, 1000)) == \ + [(QQ(-33, 70), QQ(-8, 17)), (QQ(8, 17), QQ(33, 70))] + assert R.dup_isolate_real_roots_sqf(f, eps=QQ(1, 10000)) == \ + [(QQ(-33, 70), QQ(-107, 227)), (QQ(107, 227), QQ(33, 70))] + assert R.dup_isolate_real_roots_sqf(f, eps=QQ(1, 100000)) == \ + [(QQ(-305, 647), QQ(-272, 577)), (QQ(272, 577), QQ(305, 647))] + assert R.dup_isolate_real_roots_sqf(f, eps=QQ(1, 1000000)) == \ + [(QQ(-1121, 2378), QQ(-272, 577)), (QQ(272, 577), QQ(1121, 2378))] + + f = 200100012*x**5 - 700390052*x**4 + 700490079*x**3 - 200240054*x**2 + 40017*x - 2 + + assert R.dup_isolate_real_roots_sqf(f) == \ + [(QQ(0), QQ(1, 10002)), (QQ(1, 10002), QQ(1, 10002)), + (QQ(1, 2), QQ(1, 2)), (QQ(1), QQ(1)), (QQ(2), QQ(2))] + + assert R.dup_isolate_real_roots_sqf(f, eps=QQ(1, 100000)) == \ + [(QQ(1, 10003), QQ(1, 10003)), (QQ(1, 10002), QQ(1, 10002)), + (QQ(1, 2), QQ(1, 2)), (QQ(1), QQ(1)), (QQ(2), QQ(2))] a, b, c, d = 10000090000001, 2000100003, 10000300007, 10000005000008 - f = [ 20001600074001600021, - 1700135866278935491773999857, - -2000179008931031182161141026995283662899200197, - -800027600594323913802305066986600025, - 100000950000540000725000008] + f = 20001600074001600021*x**4 \ + + 1700135866278935491773999857*x**3 \ + - 2000179008931031182161141026995283662899200197*x**2 \ + - 800027600594323913802305066986600025*x \ + + 100000950000540000725000008 - assert dup_isolate_real_roots_sqf(f, ZZ) == \ - [(-QQ(a), -QQ(a)), (-QQ(1,1), QQ(0,1)), (QQ(0,1), QQ(1,1)), (QQ(d), QQ(d))] + assert R.dup_isolate_real_roots_sqf(f) == \ + [(-a, -a), (-1, 0), (0, 1), (d, d)] - assert dup_isolate_real_roots_sqf(f, ZZ, eps=QQ(1,100000000000)) == \ - [(-QQ(a), -QQ(a)), (-QQ(1,b), -QQ(1,b)), (QQ(1,c), QQ(1,c)), (QQ(d), QQ(d))] + assert R.dup_isolate_real_roots_sqf(f, eps=QQ(1, 100000000000)) == \ + [(-QQ(a), -QQ(a)), (-QQ(1, b), -QQ(1, b)), (QQ(1, c), QQ(1, c)), (QQ(d), QQ(d))] - (u, v), B, C, (s, t) = dup_isolate_real_roots_sqf(f, ZZ, fast=True) + (u, v), B, C, (s, t) = R.dup_isolate_real_roots_sqf(f, fast=True) assert u < -a < v and B == (-QQ(1), QQ(0)) and C == (QQ(0), QQ(1)) and s < d < t - assert dup_isolate_real_roots_sqf(f, ZZ, fast=True, eps=QQ(1,100000000000000000000000000000)) == \ - [(-QQ(a), -QQ(a)), (-QQ(1,b), -QQ(1,b)), (QQ(1,c), QQ(1,c)), (QQ(d), QQ(d))] + assert R.dup_isolate_real_roots_sqf(f, fast=True, eps=QQ(1, 100000000000000000000000000000)) == \ + [(-QQ(a), -QQ(a)), (-QQ(1, b), -QQ(1, b)), (QQ(1, c), QQ(1, c)), (QQ(d), QQ(d))] + + f = -10*x**4 + 8*x**3 + 80*x**2 - 32*x - 160 + + assert R.dup_isolate_real_roots_sqf(f) == \ + [(-2, -2), (-2, -1), (2, 2), (2, 3)] + + assert R.dup_isolate_real_roots_sqf(f, eps=QQ(1, 100)) == \ + [(-QQ(2), -QQ(2)), (-QQ(23, 14), -QQ(18, 11)), (QQ(2), QQ(2)), (QQ(39, 16), QQ(22, 9))] - assert dup_isolate_real_roots_sqf([QQ(8,5), QQ(-87374,3855), QQ(-17,771)], QQ) == \ - [(QQ(-1), QQ(0)), (QQ(14), QQ(15))] + f = x - 1 - f = [-10, 8, 80, -32, -160] + assert R.dup_isolate_real_roots_sqf(f, inf=2) == [] + assert R.dup_isolate_real_roots_sqf(f, sup=0) == [] - assert dup_isolate_real_roots_sqf(f, ZZ) == \ - [(-QQ(2), -QQ(2)), (-QQ(2), -QQ(1)), (QQ(2), QQ(2)), (QQ(2), QQ(3))] - - assert dup_isolate_real_roots_sqf(f, ZZ, eps=QQ(1,100)) == \ - [(-QQ(2), -QQ(2)), (-QQ(23,14), -QQ(18,11)), (QQ(2), QQ(2)), (QQ(39,16), QQ(22,9))] - - assert dup_isolate_real_roots_sqf([1, -1], ZZ, inf=2) == [] - assert dup_isolate_real_roots_sqf([1, -1], ZZ, sup=0) == [] - - assert dup_isolate_real_roots_sqf([1, -1], ZZ) == [(1, 1)] - assert dup_isolate_real_roots_sqf([1, -1], ZZ, inf=1) == [(1, 1)] - assert dup_isolate_real_roots_sqf([1, -1], ZZ, sup=1) == [(1, 1)] - assert dup_isolate_real_roots_sqf([1, -1], ZZ, inf=1, sup=1) == [(1, 1)] - - f = [1, 0, -2] - - assert dup_isolate_real_roots_sqf(f, ZZ, inf=QQ(7,4)) == [] - assert dup_isolate_real_roots_sqf(f, ZZ, inf=QQ(7,5)) == [(QQ(7,5), QQ(3,2))] - assert dup_isolate_real_roots_sqf(f, ZZ, sup=QQ(7,5)) == [(-2, -1)] - assert dup_isolate_real_roots_sqf(f, ZZ, sup=QQ(7,4)) == [(-2, -1), (1, QQ(3,2))] - assert dup_isolate_real_roots_sqf(f, ZZ, sup=-QQ(7,4)) == [] - assert dup_isolate_real_roots_sqf(f, ZZ, sup=-QQ(7,5)) == [(-QQ(3,2), -QQ(7,5))] - assert dup_isolate_real_roots_sqf(f, ZZ, inf=-QQ(7,5)) == [(1, 2)] - assert dup_isolate_real_roots_sqf(f, ZZ, inf=-QQ(7,4)) == [(-QQ(3,2), -1), (1, 2)] + assert R.dup_isolate_real_roots_sqf(f) == [(1, 1)] + assert R.dup_isolate_real_roots_sqf(f, inf=1) == [(1, 1)] + assert R.dup_isolate_real_roots_sqf(f, sup=1) == [(1, 1)] + assert R.dup_isolate_real_roots_sqf(f, inf=1, sup=1) == [(1, 1)] + + f = x**2 - 2 + + assert R.dup_isolate_real_roots_sqf(f, inf=QQ(7, 4)) == [] + assert R.dup_isolate_real_roots_sqf(f, inf=QQ(7, 5)) == [(QQ(7, 5), QQ(3, 2))] + assert R.dup_isolate_real_roots_sqf(f, sup=QQ(7, 5)) == [(-2, -1)] + assert R.dup_isolate_real_roots_sqf(f, sup=QQ(7, 4)) == [(-2, -1), (1, QQ(3, 2))] + assert R.dup_isolate_real_roots_sqf(f, sup=-QQ(7, 4)) == [] + assert R.dup_isolate_real_roots_sqf(f, sup=-QQ(7, 5)) == [(-QQ(3, 2), -QQ(7, 5))] + assert R.dup_isolate_real_roots_sqf(f, inf=-QQ(7, 5)) == [(1, 2)] + assert R.dup_isolate_real_roots_sqf(f, inf=-QQ(7, 4)) == [(-QQ(3, 2), -1), (1, 2)] I = [(-2, -1), (1, 2)] - assert dup_isolate_real_roots_sqf(f, ZZ, inf=-2) == I - assert dup_isolate_real_roots_sqf(f, ZZ, sup=+2) == I + assert R.dup_isolate_real_roots_sqf(f, inf=-2) == I + assert R.dup_isolate_real_roots_sqf(f, sup=+2) == I + + assert R.dup_isolate_real_roots_sqf(f, inf=-2, sup=2) == I + + R, x = ring("x", QQ) + f = QQ(8, 5)*x**2 - QQ(87374, 3855)*x - QQ(17, 771) - assert dup_isolate_real_roots_sqf(f, ZZ, inf=-2, sup=2) == I + assert R.dup_isolate_real_roots_sqf(f) == [(-1, 0), (14, 15)] - raises(DomainError, lambda: dup_isolate_real_roots_sqf([EX(1), EX(2)], EX)) + R, x = ring("x", EX) + raises(DomainError, lambda: R.dup_isolate_real_roots_sqf(x + 3)) def test_dup_isolate_real_roots(): - assert dup_isolate_real_roots([], ZZ) == [] - assert dup_isolate_real_roots([3], ZZ) == [] + R, x = ring("x", ZZ) + + assert R.dup_isolate_real_roots(0) == [] + assert R.dup_isolate_real_roots(3) == [] + + assert R.dup_isolate_real_roots(5*x) == [((0, 0), 1)] + assert R.dup_isolate_real_roots(7*x**4) == [((0, 0), 4)] + + assert R.dup_isolate_real_roots(x**2 + x) == [((-1, -1), 1), ((0, 0), 1)] + assert R.dup_isolate_real_roots(x**2 - x) == [((0, 0), 1), ((1, 1), 1)] - assert dup_isolate_real_roots([5,0], ZZ) == [((QQ(0), QQ(0)), 1)] - assert dup_isolate_real_roots([7,0,0,0,0], ZZ) == [((QQ(0), QQ(0)), 4)] + assert R.dup_isolate_real_roots(x**4 + x + 1) == [] - assert dup_isolate_real_roots([1, 1,0], ZZ) == [((-QQ(1), -QQ(1)), 1), ((QQ(0), QQ(0)), 1)] - assert dup_isolate_real_roots([1,-1,0], ZZ) == [(( QQ(0), QQ(0)), 1), ((QQ(1), QQ(1)), 1)] + I = [((-2, -1), 1), ((1, 2), 1)] - assert dup_isolate_real_roots([1,0,0,1,1], ZZ) == [] - - I = [((-QQ(2), -QQ(1)), 1), ((QQ(1), QQ(2)), 1)] - - assert dup_isolate_real_roots([1,0,-2], ZZ) == I - assert dup_isolate_real_roots([-1,0,2], ZZ) == I - - f = [16,-96,24,936,-1599,-2880,9196,552,-21831,13968,21690,-26784,-2916,15552,-5832] - g = dup_sqf_part(f, ZZ) - - assert dup_isolate_real_roots(f, ZZ) == \ - [((-QQ(2), -QQ(3,2)), 2), ((-QQ(3,2), -QQ(1,1)), 3), - (( QQ(1), QQ(3,2)), 3), (( QQ(3,2), QQ(3,2)), 4), ((QQ(5,3), QQ(2)), 2)] - - assert dup_isolate_real_roots_sqf(g, ZZ) == \ - [(-QQ(2), -QQ(3,2)), (-QQ(3,2), -QQ(1,1)), - ( QQ(1), QQ(3,2)), ( QQ(3,2), QQ(3,2)), (QQ(3,2), QQ(2))] - assert dup_isolate_real_roots(g, ZZ) == \ - [((-QQ(2), -QQ(3,2)), 1), ((-QQ(3,2), -QQ(1,1)), 1), - (( QQ(1), QQ(3,2)), 1), (( QQ(3,2), QQ(3,2)), 1), ((QQ(3,2), QQ(2)), 1)] - - assert dup_isolate_real_roots([1, -1], ZZ, inf=2) == [] - assert dup_isolate_real_roots([1, -1], ZZ, sup=0) == [] - - assert dup_isolate_real_roots([1, -1], ZZ) == [((1, 1), 1)] - assert dup_isolate_real_roots([1, -1], ZZ, inf=1) == [((1, 1), 1)] - assert dup_isolate_real_roots([1, -1], ZZ, sup=1) == [((1, 1), 1)] - assert dup_isolate_real_roots([1, -1], ZZ, inf=1, sup=1) == [((1, 1), 1)] - - f = [1, 0, -4, 0, 4] - - assert dup_isolate_real_roots(f, ZZ, inf=QQ(7,4)) == [] - assert dup_isolate_real_roots(f, ZZ, inf=QQ(7,5)) == [((QQ(7,5), QQ(3,2)), 2)] - assert dup_isolate_real_roots(f, ZZ, sup=QQ(7,5)) == [((-2, -1), 2)] - assert dup_isolate_real_roots(f, ZZ, sup=QQ(7,4)) == [((-2, -1), 2), ((1, QQ(3,2)), 2)] - assert dup_isolate_real_roots(f, ZZ, sup=-QQ(7,4)) == [] - assert dup_isolate_real_roots(f, ZZ, sup=-QQ(7,5)) == [((-QQ(3,2), -QQ(7,5)), 2)] - assert dup_isolate_real_roots(f, ZZ, inf=-QQ(7,5)) == [((1, 2), 2)] - assert dup_isolate_real_roots(f, ZZ, inf=-QQ(7,4)) == [((-QQ(3,2), -1), 2), ((1, 2), 2)] + assert R.dup_isolate_real_roots(x**2 - 2) == I + assert R.dup_isolate_real_roots(-x**2 + 2) == I + + f = 16*x**14 - 96*x**13 + 24*x**12 + 936*x**11 - 1599*x**10 - 2880*x**9 + 9196*x**8 \ + + 552*x**7 - 21831*x**6 + 13968*x**5 + 21690*x**4 - 26784*x**3 - 2916*x**2 + 15552*x - 5832 + g = R.dup_sqf_part(f) + + assert R.dup_isolate_real_roots(f) == \ + [((-QQ(2), -QQ(3, 2)), 2), ((-QQ(3, 2), -QQ(1, 1)), 3), ((QQ(1), QQ(3, 2)), 3), + ((QQ(3, 2), QQ(3, 2)), 4), ((QQ(5, 3), QQ(2)), 2)] + + assert R.dup_isolate_real_roots_sqf(g) == \ + [(-QQ(2), -QQ(3, 2)), (-QQ(3, 2), -QQ(1, 1)), (QQ(1), QQ(3, 2)), + (QQ(3, 2), QQ(3, 2)), (QQ(3, 2), QQ(2))] + assert R.dup_isolate_real_roots(g) == \ + [((-QQ(2), -QQ(3, 2)), 1), ((-QQ(3, 2), -QQ(1, 1)), 1), ((QQ(1), QQ(3, 2)), 1), + ((QQ(3, 2), QQ(3, 2)), 1), ((QQ(3, 2), QQ(2)), 1)] + + f = x - 1 + + assert R.dup_isolate_real_roots(f, inf=2) == [] + assert R.dup_isolate_real_roots(f, sup=0) == [] + + assert R.dup_isolate_real_roots(f) == [((1, 1), 1)] + assert R.dup_isolate_real_roots(f, inf=1) == [((1, 1), 1)] + assert R.dup_isolate_real_roots(f, sup=1) == [((1, 1), 1)] + assert R.dup_isolate_real_roots(f, inf=1, sup=1) == [((1, 1), 1)] + + f = x**4 - 4*x**2 + 4 + + assert R.dup_isolate_real_roots(f, inf=QQ(7, 4)) == [] + assert R.dup_isolate_real_roots(f, inf=QQ(7, 5)) == [((QQ(7, 5), QQ(3, 2)), 2)] + assert R.dup_isolate_real_roots(f, sup=QQ(7, 5)) == [((-2, -1), 2)] + assert R.dup_isolate_real_roots(f, sup=QQ(7, 4)) == [((-2, -1), 2), ((1, QQ(3, 2)), 2)] + assert R.dup_isolate_real_roots(f, sup=-QQ(7, 4)) == [] + assert R.dup_isolate_real_roots(f, sup=-QQ(7, 5)) == [((-QQ(3, 2), -QQ(7, 5)), 2)] + assert R.dup_isolate_real_roots(f, inf=-QQ(7, 5)) == [((1, 2), 2)] + assert R.dup_isolate_real_roots(f, inf=-QQ(7, 4)) == [((-QQ(3, 2), -1), 2), ((1, 2), 2)] I = [((-2, -1), 2), ((1, 2), 2)] - assert dup_isolate_real_roots(f, ZZ, inf=-2) == I - assert dup_isolate_real_roots(f, ZZ, sup=+2) == I + assert R.dup_isolate_real_roots(f, inf=-2) == I + assert R.dup_isolate_real_roots(f, sup=+2) == I - assert dup_isolate_real_roots(f, ZZ, inf=-2, sup=2) == I + assert R.dup_isolate_real_roots(f, inf=-2, sup=2) == I - f = [1, -3, -1, 11, -8, -8, 12, -4, 0, 0, 0, 0] + f = x**11 - 3*x**10 - x**9 + 11*x**8 - 8*x**7 - 8*x**6 + 12*x**5 - 4*x**4 - assert dup_isolate_real_roots(f, ZZ, basis=False) == \ + assert R.dup_isolate_real_roots(f, basis=False) == \ [((-2, -1), 2), ((0, 0), 4), ((1, 1), 3), ((1, 2), 2)] - assert dup_isolate_real_roots(f, ZZ, basis=True) == \ + assert R.dup_isolate_real_roots(f, basis=True) == \ [((-2, -1), 2, [1, 0, -2]), ((0, 0), 4, [1, 0]), ((1, 1), 3, [1, -1]), ((1, 2), 2, [1, 0, -2])] - raises(DomainError, lambda: dup_isolate_real_roots([EX(1), EX(2)], EX)) + R, x = ring("x", EX) + raises(DomainError, lambda: R.dup_isolate_real_roots(x + 3)) -def test_dup_isolate_real_roots_list(): - assert dup_isolate_real_roots_list([[1, 1,0], [1,0]], ZZ) == \ - [((-QQ(1), -QQ(1)), {0: 1}), ((QQ(0), QQ(0)), {0: 1, 1: 1})] - assert dup_isolate_real_roots_list([[1,-1,0], [1,0]], ZZ) == \ - [((QQ(0), QQ(0)), {0: 1, 1: 1}), ((QQ(1), QQ(1)), {0: 1})] - - f = dup_from_raw_dict({5: ZZ(1), 0: -ZZ(200)}, ZZ) - g = dup_from_raw_dict({5: ZZ(1), 0: -ZZ(201)}, ZZ) - assert dup_isolate_real_roots_list([f, g], ZZ) == \ - [((QQ(75,26), QQ(101,35)), {0: 1}), ((QQ(283,98), QQ(26,9)), {1: 1})] - - f = dup_from_raw_dict({5: -QQ(1,200), 0: QQ(1)}, QQ) - g = dup_from_raw_dict({5: -QQ(1,201), 0: QQ(1)}, QQ) +def test_dup_isolate_real_roots_list(): + R, x = ring("x", ZZ) - assert dup_isolate_real_roots_list([f, g], QQ) == \ - [((QQ(75,26), QQ(101,35)), {0: 1}), ((QQ(283,98), QQ(26,9)), {1: 1})] + assert R.dup_isolate_real_roots_list([x**2 + x, x]) == \ + [((-1, -1), {0: 1}), ((0, 0), {0: 1, 1: 1})] + assert R.dup_isolate_real_roots_list([x**2 - x, x]) == \ + [((0, 0), {0: 1, 1: 1}), ((1, 1), {0: 1})] - assert dup_isolate_real_roots_list([[1,1], [1,2], [1,-1], [1,1], [1,-1], [1,-1]], ZZ) == \ + assert R.dup_isolate_real_roots_list([x + 1, x + 2, x - 1, x + 1, x - 1, x - 1]) == \ [((-QQ(2), -QQ(2)), {1: 1}), ((-QQ(1), -QQ(1)), {0: 1, 3: 1}), ((QQ(1), QQ(1)), {2: 1, 4: 1, 5: 1})] - assert dup_isolate_real_roots_list([[1,1], [1,2], [1,-1], [1,1], [1,-1], [1,2]], ZZ) == \ + assert R.dup_isolate_real_roots_list([x + 1, x + 2, x - 1, x + 1, x - 1, x + 2]) == \ [((-QQ(2), -QQ(2)), {1: 1, 5: 1}), ((-QQ(1), -QQ(1)), {0: 1, 3: 1}), ((QQ(1), QQ(1)), {2: 1, 4: 1})] - f, g = [1, 0, -4, 0, 4], [1, -1] + f, g = x**4 - 4*x**2 + 4, x - 1 - assert dup_isolate_real_roots_list([f, g], ZZ, inf=QQ(7,4)) == [] - assert dup_isolate_real_roots_list([f, g], ZZ, inf=QQ(7,5)) == [((QQ(7,5), QQ(3,2)), {0: 2})] - assert dup_isolate_real_roots_list([f, g], ZZ, sup=QQ(7,5)) == [((-2, -1), {0: 2}), ((1, 1), {1: 1})] - assert dup_isolate_real_roots_list([f, g], ZZ, sup=QQ(7,4)) == [((-2, -1), {0: 2}), ((1, 1), {1: 1}), ((1, QQ(3,2)), {0: 2})] - assert dup_isolate_real_roots_list([f, g], ZZ, sup=-QQ(7,4)) == [] - assert dup_isolate_real_roots_list([f, g], ZZ, sup=-QQ(7,5)) == [((-QQ(3,2), -QQ(7,5)), {0: 2})] - assert dup_isolate_real_roots_list([f, g], ZZ, inf=-QQ(7,5)) == [((1, 1), {1: 1}), ((1, 2), {0: 2})] - assert dup_isolate_real_roots_list([f, g], ZZ, inf=-QQ(7,4)) == [((-QQ(3,2), -1), {0: 2}), ((1, 1), {1: 1}), ((1, 2), {0: 2})] - - f, g = [2, 0, -1], [1, 0, -2] - - assert dup_isolate_real_roots_list([f, g], ZZ) == \ - [((-QQ(2), -QQ(1)), {1: 1}), ((-QQ(1), QQ(0)), {0: 1}), ((QQ(0), QQ(1)), {0: 1}), ((QQ(1), QQ(2)), {1: 1})] - assert dup_isolate_real_roots_list([f, g], ZZ, strict=True) == \ - [((-QQ(3,2), -QQ(4,3)), {1: 1}), ((-QQ(1), -QQ(2,3)), {0: 1}), ((QQ(2,3), QQ(1)), {0: 1}), ((QQ(4,3), QQ(3,2)), {1: 1})] + assert R.dup_isolate_real_roots_list([f, g], inf=QQ(7, 4)) == [] + assert R.dup_isolate_real_roots_list([f, g], inf=QQ(7, 5)) == \ + [((QQ(7, 5), QQ(3, 2)), {0: 2})] + assert R.dup_isolate_real_roots_list([f, g], sup=QQ(7, 5)) == \ + [((-2, -1), {0: 2}), ((1, 1), {1: 1})] + assert R.dup_isolate_real_roots_list([f, g], sup=QQ(7, 4)) == \ + [((-2, -1), {0: 2}), ((1, 1), {1: 1}), ((1, QQ(3, 2)), {0: 2})] + assert R.dup_isolate_real_roots_list([f, g], sup=-QQ(7, 4)) == [] + assert R.dup_isolate_real_roots_list([f, g], sup=-QQ(7, 5)) == \ + [((-QQ(3, 2), -QQ(7, 5)), {0: 2})] + assert R.dup_isolate_real_roots_list([f, g], inf=-QQ(7, 5)) == \ + [((1, 1), {1: 1}), ((1, 2), {0: 2})] + assert R.dup_isolate_real_roots_list([f, g], inf=-QQ(7, 4)) == \ + [((-QQ(3, 2), -1), {0: 2}), ((1, 1), {1: 1}), ((1, 2), {0: 2})] + + f, g = 2*x**2 - 1, x**2 - 2 + + assert R.dup_isolate_real_roots_list([f, g]) == \ + [((-QQ(2), -QQ(1)), {1: 1}), ((-QQ(1), QQ(0)), {0: 1}), + ((QQ(0), QQ(1)), {0: 1}), ((QQ(1), QQ(2)), {1: 1})] + assert R.dup_isolate_real_roots_list([f, g], strict=True) == \ + [((-QQ(3, 2), -QQ(4, 3)), {1: 1}), ((-QQ(1), -QQ(2, 3)), {0: 1}), + ((QQ(2, 3), QQ(1)), {0: 1}), ((QQ(4, 3), QQ(3, 2)), {1: 1})] - f, g = [1, 0, -2], [1, -1, -2, 2] + f, g = x**2 - 2, x**3 - x**2 - 2*x + 2 - assert dup_isolate_real_roots_list([f, g], ZZ) == \ + assert R.dup_isolate_real_roots_list([f, g]) == \ [((-QQ(2), -QQ(1)), {1: 1, 0: 1}), ((QQ(1), QQ(1)), {1: 1}), ((QQ(1), QQ(2)), {1: 1, 0: 1})] - f, g = [1, 0, -2, 0], [1, -1, -2, 2, 0, 0] + f, g = x**3 - 2*x, x**5 - x**4 - 2*x**3 + 2*x**2 - assert dup_isolate_real_roots_list([f, g], ZZ) == \ - [((-QQ(2), -QQ(1)), {1: 1, 0: 1}), ((QQ(0), QQ(0)), {0: 1, 1: 2}), ((QQ(1), QQ(1)), {1: 1}), ((QQ(1), QQ(2)), {1: 1, 0: 1})] + assert R.dup_isolate_real_roots_list([f, g]) == \ + [((-QQ(2), -QQ(1)), {1: 1, 0: 1}), ((QQ(0), QQ(0)), {0: 1, 1: 2}), + ((QQ(1), QQ(1)), {1: 1}), ((QQ(1), QQ(2)), {1: 1, 0: 1})] - f, g = [1, -3, -1, 11, -8, -8, 12, -4, 0, 0], [1, -2, 3, -4, 2, 0] + f, g = x**9 - 3*x**8 - x**7 + 11*x**6 - 8*x**5 - 8*x**4 + 12*x**3 - 4*x**2, x**5 - 2*x**4 + 3*x**3 - 4*x**2 + 2*x - assert dup_isolate_real_roots_list([f, g], ZZ, basis=False) == \ + assert R.dup_isolate_real_roots_list([f, g], basis=False) == \ [((-2, -1), {0: 2}), ((0, 0), {0: 2, 1: 1}), ((1, 1), {0: 3, 1: 2}), ((1, 2), {0: 2})] - assert dup_isolate_real_roots_list([f, g], ZZ, basis=True) == \ - [((-2, -1), {0: 2}, [1, 0, -2]), ((0, 0), {0: 2, 1: 1}, [1, 0]), ((1, 1), {0: 3, 1: 2}, [1, -1]), ((1, 2), {0: 2}, [1, 0, -2])] + assert R.dup_isolate_real_roots_list([f, g], basis=True) == \ + [((-2, -1), {0: 2}, [1, 0, -2]), ((0, 0), {0: 2, 1: 1}, [1, 0]), + ((1, 1), {0: 3, 1: 2}, [1, -1]), ((1, 2), {0: 2}, [1, 0, -2])] + + R, x = ring("x", EX) + raises(DomainError, lambda: R.dup_isolate_real_roots_list([x + 3])) + + +def test_dup_isolate_real_roots_list_QQ(): + R, x = ring("x", ZZ) + + f = x**5 - 200 + g = x**5 - 201 + + assert R.dup_isolate_real_roots_list([f, g]) == \ + [((QQ(75, 26), QQ(101, 35)), {0: 1}), ((QQ(283, 98), QQ(26, 9)), {1: 1})] + + R, x = ring("x", QQ) + + f = -QQ(1, 200)*x**5 + 1 + g = -QQ(1, 201)*x**5 + 1 + + assert R.dup_isolate_real_roots_list([f, g]) == \ + [((QQ(75, 26), QQ(101, 35)), {0: 1}), ((QQ(283, 98), QQ(26, 9)), {1: 1})] - raises(DomainError, lambda: dup_isolate_real_roots_list([[EX(1), EX(2)]], EX)) def test_dup_count_real_roots(): - assert dup_count_real_roots([], ZZ) == 0 - assert dup_count_real_roots([7], ZZ) == 0 + R, x = ring("x", ZZ) + + assert R.dup_count_real_roots(0) == 0 + assert R.dup_count_real_roots(7) == 0 - assert dup_count_real_roots([1,-1], ZZ) == 1 - assert dup_count_real_roots([1,-1], ZZ, inf=1) == 1 - assert dup_count_real_roots([1,-1], ZZ, sup=0) == 0 - assert dup_count_real_roots([1,-1], ZZ, sup=1) == 1 - assert dup_count_real_roots([1,-1], ZZ, inf=0, sup=1) == 1 - assert dup_count_real_roots([1,-1], ZZ, inf=0, sup=2) == 1 - assert dup_count_real_roots([1,-1], ZZ, inf=1, sup=2) == 1 - - assert dup_count_real_roots([1,0,-2], ZZ) == 2 - assert dup_count_real_roots([1,0,-2], ZZ, sup=0) == 1 - assert dup_count_real_roots([1,0,-2], ZZ, inf=-1, sup=1) == 0 + f = x - 1 + assert R.dup_count_real_roots(f) == 1 + assert R.dup_count_real_roots(f, inf=1) == 1 + assert R.dup_count_real_roots(f, sup=0) == 0 + assert R.dup_count_real_roots(f, sup=1) == 1 + assert R.dup_count_real_roots(f, inf=0, sup=1) == 1 + assert R.dup_count_real_roots(f, inf=0, sup=2) == 1 + assert R.dup_count_real_roots(f, inf=1, sup=2) == 1 + + f = x**2 - 2 + assert R.dup_count_real_roots(f) == 2 + assert R.dup_count_real_roots(f, sup=0) == 1 + assert R.dup_count_real_roots(f, inf=-1, sup=1) == 0 + +# parameters for test_dup_count_complex_roots_n(): n = 1..8 a, b = (-QQ(1), -QQ(1)), (QQ(1), QQ(1)) c, d = ( QQ(0), QQ(0)), (QQ(1), QQ(1)) def test_dup_count_complex_roots_1(): + R, x = ring("x", ZZ) + # z-1 - assert dup_count_complex_roots([1,-1], ZZ, a, b) == 1 - assert dup_count_complex_roots([1,-1], ZZ, c, d) == 1 + f = x - 1 + assert R.dup_count_complex_roots(f, a, b) == 1 + assert R.dup_count_complex_roots(f, c, d) == 1 # z+1 - assert dup_count_complex_roots([1,1], ZZ, a, b) == 1 - assert dup_count_complex_roots([1,1], ZZ, c, d) == 0 + f = x + 1 + assert R.dup_count_complex_roots(f, a, b) == 1 + assert R.dup_count_complex_roots(f, c, d) == 0 + def test_dup_count_complex_roots_2(): + R, x = ring("x", ZZ) + # (z-1)*(z) - assert dup_count_complex_roots([1,-1,0], ZZ, a, b) == 2 - assert dup_count_complex_roots([1,-1,0], ZZ, c, d) == 2 + f = x**2 - x + assert R.dup_count_complex_roots(f, a, b) == 2 + assert R.dup_count_complex_roots(f, c, d) == 2 # (z-1)*(-z) - assert dup_count_complex_roots([-1,1,0], ZZ, a, b) == 2 - assert dup_count_complex_roots([-1,1,0], ZZ, c, d) == 2 + f = -x**2 + x + assert R.dup_count_complex_roots(f, a, b) == 2 + assert R.dup_count_complex_roots(f, c, d) == 2 # (z+1)*(z) - assert dup_count_complex_roots([1,1,0], ZZ, a, b) == 2 - assert dup_count_complex_roots([1,1,0], ZZ, c, d) == 1 + f = x**2 + x + assert R.dup_count_complex_roots(f, a, b) == 2 + assert R.dup_count_complex_roots(f, c, d) == 1 # (z+1)*(-z) - assert dup_count_complex_roots([-1,-1,0], ZZ, a, b) == 2 - assert dup_count_complex_roots([-1,-1,0], ZZ, c, d) == 1 + f = -x**2 - x + assert R.dup_count_complex_roots(f, a, b) == 2 + assert R.dup_count_complex_roots(f, c, d) == 1 + def test_dup_count_complex_roots_3(): + R, x = ring("x", ZZ) + # (z-1)*(z+1) - assert dup_count_complex_roots([1,0,-1], ZZ, a, b) == 2 - assert dup_count_complex_roots([1,0,-1], ZZ, c, d) == 1 + f = x**2 - 1 + assert R.dup_count_complex_roots(f, a, b) == 2 + assert R.dup_count_complex_roots(f, c, d) == 1 # (z-1)*(z+1)*(z) - assert dup_count_complex_roots([1,0,-1,0], ZZ, a, b) == 3 - assert dup_count_complex_roots([1,0,-1,0], ZZ, c, d) == 2 + f = x**3 - x + assert R.dup_count_complex_roots(f, a, b) == 3 + assert R.dup_count_complex_roots(f, c, d) == 2 # (z-1)*(z+1)*(-z) - assert dup_count_complex_roots([-1,0,1,0], ZZ, a, b) == 3 - assert dup_count_complex_roots([-1,0,1,0], ZZ, c, d) == 2 + f = -x**3 + x + assert R.dup_count_complex_roots(f, a, b) == 3 + assert R.dup_count_complex_roots(f, c, d) == 2 + def test_dup_count_complex_roots_4(): + R, x = ring("x", ZZ) + # (z-I)*(z+I) - assert dup_count_complex_roots([1,0,1], ZZ, a, b) == 2 - assert dup_count_complex_roots([1,0,1], ZZ, c, d) == 1 + f = x**2 + 1 + assert R.dup_count_complex_roots(f, a, b) == 2 + assert R.dup_count_complex_roots(f, c, d) == 1 # (z-I)*(z+I)*(z) - assert dup_count_complex_roots([1,0,1,0], ZZ, a, b) == 3 - assert dup_count_complex_roots([1,0,1,0], ZZ, c, d) == 2 + f = x**3 + x + assert R.dup_count_complex_roots(f, a, b) == 3 + assert R.dup_count_complex_roots(f, c, d) == 2 # (z-I)*(z+I)*(-z) - assert dup_count_complex_roots([-1,0,-1,0], ZZ, a, b) == 3 - assert dup_count_complex_roots([-1,0,-1,0], ZZ, c, d) == 2 + f = -x**3 - x + assert R.dup_count_complex_roots(f, a, b) == 3 + assert R.dup_count_complex_roots(f, c, d) == 2 # (z-I)*(z+I)*(z-1) - assert dup_count_complex_roots([1,-1,1,-1], ZZ, a, b) == 3 - assert dup_count_complex_roots([1,-1,1,-1], ZZ, c, d) == 2 + f = x**3 - x**2 + x - 1 + assert R.dup_count_complex_roots(f, a, b) == 3 + assert R.dup_count_complex_roots(f, c, d) == 2 # (z-I)*(z+I)*(z-1)*(z) - assert dup_count_complex_roots([1,-1,1,-1,0], ZZ, a, b) == 4 - assert dup_count_complex_roots([1,-1,1,-1,0], ZZ, c, d) == 3 + f = x**4 - x**3 + x**2 - x + assert R.dup_count_complex_roots(f, a, b) == 4 + assert R.dup_count_complex_roots(f, c, d) == 3 # (z-I)*(z+I)*(z-1)*(-z) - assert dup_count_complex_roots([-1,1,-1,1,0], ZZ, a, b) == 4 - assert dup_count_complex_roots([-1,1,-1,1,0], ZZ, c, d) == 3 + f = -x**4 + x**3 - x**2 + x + assert R.dup_count_complex_roots(f, a, b) == 4 + assert R.dup_count_complex_roots(f, c, d) == 3 # (z-I)*(z+I)*(z-1)*(z+1) - assert dup_count_complex_roots([1,0,0,0,-1], ZZ, a, b) == 4 - assert dup_count_complex_roots([1,0,0,0,-1], ZZ, c, d) == 2 + f = x**4 - 1 + assert R.dup_count_complex_roots(f, a, b) == 4 + assert R.dup_count_complex_roots(f, c, d) == 2 # (z-I)*(z+I)*(z-1)*(z+1)*(z) - assert dup_count_complex_roots([1,0,0,0,-1,0], ZZ, a, b) == 5 - assert dup_count_complex_roots([1,0,0,0,-1,0], ZZ, c, d) == 3 + f = x**5 - x + assert R.dup_count_complex_roots(f, a, b) == 5 + assert R.dup_count_complex_roots(f, c, d) == 3 # (z-I)*(z+I)*(z-1)*(z+1)*(-z) - assert dup_count_complex_roots([-1,0,0,0,1,0], ZZ, a, b) == 5 - assert dup_count_complex_roots([-1,0,0,0,1,0], ZZ, c, d) == 3 + f = -x**5 + x + assert R.dup_count_complex_roots(f, a, b) == 5 + assert R.dup_count_complex_roots(f, c, d) == 3 + def test_dup_count_complex_roots_5(): + R, x = ring("x", ZZ) + # (z-I+1)*(z+I+1) - assert dup_count_complex_roots([1,2,2], ZZ, a, b) == 2 - assert dup_count_complex_roots([1,2,2], ZZ, c, d) == 0 + f = x**2 + 2*x + 2 + assert R.dup_count_complex_roots(f, a, b) == 2 + assert R.dup_count_complex_roots(f, c, d) == 0 # (z-I+1)*(z+I+1)*(z-1) - assert dup_count_complex_roots([1,1,0,-2], ZZ, a, b) == 3 - assert dup_count_complex_roots([1,1,0,-2], ZZ, c, d) == 1 + f = x**3 + x**2 - 2 + assert R.dup_count_complex_roots(f, a, b) == 3 + assert R.dup_count_complex_roots(f, c, d) == 1 # (z-I+1)*(z+I+1)*(z-1)*z - assert dup_count_complex_roots([1,1,0,-2,0], ZZ, a, b) == 4 - assert dup_count_complex_roots([1,1,0,-2,0], ZZ, c, d) == 2 + f = x**4 + x**3 - 2*x + assert R.dup_count_complex_roots(f, a, b) == 4 + assert R.dup_count_complex_roots(f, c, d) == 2 # (z-I+1)*(z+I+1)*(z+1) - assert dup_count_complex_roots([1,3,4,2], ZZ, a, b) == 3 - assert dup_count_complex_roots([1,3,4,2], ZZ, c, d) == 0 + f = x**3 + 3*x**2 + 4*x + 2 + assert R.dup_count_complex_roots(f, a, b) == 3 + assert R.dup_count_complex_roots(f, c, d) == 0 # (z-I+1)*(z+I+1)*(z+1)*z - assert dup_count_complex_roots([1,3,4,2,0], ZZ, a, b) == 4 - assert dup_count_complex_roots([1,3,4,2,0], ZZ, c, d) == 1 + f = x**4 + 3*x**3 + 4*x**2 + 2*x + assert R.dup_count_complex_roots(f, a, b) == 4 + assert R.dup_count_complex_roots(f, c, d) == 1 # (z-I+1)*(z+I+1)*(z-1)*(z+1) - assert dup_count_complex_roots([1,2,1,-2,-2], ZZ, a, b) == 4 - assert dup_count_complex_roots([1,2,1,-2,-2], ZZ, c, d) == 1 + f = x**4 + 2*x**3 + x**2 - 2*x - 2 + assert R.dup_count_complex_roots(f, a, b) == 4 + assert R.dup_count_complex_roots(f, c, d) == 1 # (z-I+1)*(z+I+1)*(z-1)*(z+1)*z - assert dup_count_complex_roots([1,2,1,-2,-2,0], ZZ, a, b) == 5 - assert dup_count_complex_roots([1,2,1,-2,-2,0], ZZ, c, d) == 2 + f = x**5 + 2*x**4 + x**3 - 2*x**2 - 2*x + assert R.dup_count_complex_roots(f, a, b) == 5 + assert R.dup_count_complex_roots(f, c, d) == 2 + def test_dup_count_complex_roots_6(): + R, x = ring("x", ZZ) + # (z-I-1)*(z+I-1) - assert dup_count_complex_roots([1,-2,2], ZZ, a, b) == 2 - assert dup_count_complex_roots([1,-2,2], ZZ, c, d) == 1 + f = x**2 - 2*x + 2 + assert R.dup_count_complex_roots(f, a, b) == 2 + assert R.dup_count_complex_roots(f, c, d) == 1 # (z-I-1)*(z+I-1)*(z-1) - assert dup_count_complex_roots([1,-3,4,-2], ZZ, a, b) == 3 - assert dup_count_complex_roots([1,-3,4,-2], ZZ, c, d) == 2 + f = x**3 - 3*x**2 + 4*x - 2 + assert R.dup_count_complex_roots(f, a, b) == 3 + assert R.dup_count_complex_roots(f, c, d) == 2 # (z-I-1)*(z+I-1)*(z-1)*z - assert dup_count_complex_roots([1,-3,4,-2,0], ZZ, a, b) == 4 - assert dup_count_complex_roots([1,-3,4,-2,0], ZZ, c, d) == 3 + f = x**4 - 3*x**3 + 4*x**2 - 2*x + assert R.dup_count_complex_roots(f, a, b) == 4 + assert R.dup_count_complex_roots(f, c, d) == 3 # (z-I-1)*(z+I-1)*(z+1) - assert dup_count_complex_roots([1,-1,0,2], ZZ, a, b) == 3 - assert dup_count_complex_roots([1,-1,0,2], ZZ, c, d) == 1 + f = x**3 - x**2 + 2 + assert R.dup_count_complex_roots(f, a, b) == 3 + assert R.dup_count_complex_roots(f, c, d) == 1 # (z-I-1)*(z+I-1)*(z+1)*z - assert dup_count_complex_roots([1,-1,0,2,0], ZZ, a, b) == 4 - assert dup_count_complex_roots([1,-1,0,2,0], ZZ, c, d) == 2 + f = x**4 - x**3 + 2*x + assert R.dup_count_complex_roots(f, a, b) == 4 + assert R.dup_count_complex_roots(f, c, d) == 2 # (z-I-1)*(z+I-1)*(z-1)*(z+1) - assert dup_count_complex_roots([1,-2,1,2,-2], ZZ, a, b) == 4 - assert dup_count_complex_roots([1,-2,1,2,-2], ZZ, c, d) == 2 + f = x**4 - 2*x**3 + x**2 + 2*x - 2 + assert R.dup_count_complex_roots(f, a, b) == 4 + assert R.dup_count_complex_roots(f, c, d) == 2 # (z-I-1)*(z+I-1)*(z-1)*(z+1)*z - assert dup_count_complex_roots([1,-2,1,2,-2,0], ZZ, a, b) == 5 - assert dup_count_complex_roots([1,-2,1,2,-2,0], ZZ, c, d) == 3 + f = x**5 - 2*x**4 + x**3 + 2*x**2 - 2*x + assert R.dup_count_complex_roots(f, a, b) == 5 + assert R.dup_count_complex_roots(f, c, d) == 3 + def test_dup_count_complex_roots_7(): + R, x = ring("x", ZZ) + # (z-I-1)*(z+I-1)*(z-I+1)*(z+I+1) - assert dup_count_complex_roots([1,0,0,0,4], ZZ, a, b) == 4 - assert dup_count_complex_roots([1,0,0,0,4], ZZ, c, d) == 1 + f = x**4 + 4 + assert R.dup_count_complex_roots(f, a, b) == 4 + assert R.dup_count_complex_roots(f, c, d) == 1 # (z-I-1)*(z+I-1)*(z-I+1)*(z+I+1)*(z-2) - assert dup_count_complex_roots([1,-2,0,0,4,-8], ZZ, a, b) == 4 - assert dup_count_complex_roots([1,-2,0,0,4,-8], ZZ, c, d) == 1 + f = x**5 - 2*x**4 + 4*x - 8 + assert R.dup_count_complex_roots(f, a, b) == 4 + assert R.dup_count_complex_roots(f, c, d) == 1 # (z-I-1)*(z+I-1)*(z-I+1)*(z+I+1)*(z**2-2) - assert dup_count_complex_roots([1,0,-2,0,4,0,-8], ZZ, a, b) == 4 - assert dup_count_complex_roots([1,0,-2,0,4,0,-8], ZZ, c, d) == 1 + f = x**6 - 2*x**4 + 4*x**2 - 8 + assert R.dup_count_complex_roots(f, a, b) == 4 + assert R.dup_count_complex_roots(f, c, d) == 1 # (z-I-1)*(z+I-1)*(z-I+1)*(z+I+1)*(z-1) - assert dup_count_complex_roots([1,-1,0,0,4,-4], ZZ, a, b) == 5 - assert dup_count_complex_roots([1,-1,0,0,4,-4], ZZ, c, d) == 2 + f = x**5 - x**4 + 4*x - 4 + assert R.dup_count_complex_roots(f, a, b) == 5 + assert R.dup_count_complex_roots(f, c, d) == 2 # (z-I-1)*(z+I-1)*(z-I+1)*(z+I+1)*(z-1)*z - assert dup_count_complex_roots([1,-1,0,0,4,-4,0], ZZ, a, b) == 6 - assert dup_count_complex_roots([1,-1,0,0,4,-4,0], ZZ, c, d) == 3 + f = x**6 - x**5 + 4*x**2 - 4*x + assert R.dup_count_complex_roots(f, a, b) == 6 + assert R.dup_count_complex_roots(f, c, d) == 3 # (z-I-1)*(z+I-1)*(z-I+1)*(z+I+1)*(z+1) - assert dup_count_complex_roots([1,1,0,0,4,4], ZZ, a, b) == 5 - assert dup_count_complex_roots([1,1,0,0,4,4], ZZ, c, d) == 1 + f = x**5 + x**4 + 4*x + 4 + assert R.dup_count_complex_roots(f, a, b) == 5 + assert R.dup_count_complex_roots(f, c, d) == 1 # (z-I-1)*(z+I-1)*(z-I+1)*(z+I+1)*(z+1)*z - assert dup_count_complex_roots([1,1,0,0,4,4,0], ZZ, a, b) == 6 - assert dup_count_complex_roots([1,1,0,0,4,4,0], ZZ, c, d) == 2 + f = x**6 + x**5 + 4*x**2 + 4*x + assert R.dup_count_complex_roots(f, a, b) == 6 + assert R.dup_count_complex_roots(f, c, d) == 2 # (z-I-1)*(z+I-1)*(z-I+1)*(z+I+1)*(z-1)*(z+1) - assert dup_count_complex_roots([1,0,-1,0,4,0,-4], ZZ, a, b) == 6 - assert dup_count_complex_roots([1,0,-1,0,4,0,-4], ZZ, c, d) == 2 + f = x**6 - x**4 + 4*x**2 - 4 + assert R.dup_count_complex_roots(f, a, b) == 6 + assert R.dup_count_complex_roots(f, c, d) == 2 # (z-I-1)*(z+I-1)*(z-I+1)*(z+I+1)*(z-1)*(z+1)*z - assert dup_count_complex_roots([1,0,-1,0,4,0,-4,0], ZZ, a, b) == 7 - assert dup_count_complex_roots([1,0,-1,0,4,0,-4,0], ZZ, c, d) == 3 + f = x**7 - x**5 + 4*x**3 - 4*x + assert R.dup_count_complex_roots(f, a, b) == 7 + assert R.dup_count_complex_roots(f, c, d) == 3 # (z-I-1)*(z+I-1)*(z-I+1)*(z+I+1)*(z-1)*(z+1)*(z-I)*(z+I) - assert dup_count_complex_roots([1,0,0,0,3,0,0,0,-4], ZZ, a, b) == 8 - assert dup_count_complex_roots([1,0,0,0,3,0,0,0,-4], ZZ, c, d) == 3 + f = x**8 + 3*x**4 - 4 + assert R.dup_count_complex_roots(f, a, b) == 8 + assert R.dup_count_complex_roots(f, c, d) == 3 + def test_dup_count_complex_roots_8(): + R, x = ring("x", ZZ) + # (z-I-1)*(z+I-1)*(z-I+1)*(z+I+1)*(z-1)*(z+1)*(z-I)*(z+I)*z - assert dup_count_complex_roots([1,0,0,0,3,0,0,0,-4,0], ZZ, a, b) == 9 - assert dup_count_complex_roots([1,0,0,0,3,0,0,0,-4,0], ZZ, c, d) == 4 + f = x**9 + 3*x**5 - 4*x + assert R.dup_count_complex_roots(f, a, b) == 9 + assert R.dup_count_complex_roots(f, c, d) == 4 # (z-I-1)*(z+I-1)*(z-I+1)*(z+I+1)*(z-1)*(z+1)*(z-I)*(z+I)*(z**2-2)*z - assert dup_count_complex_roots([1,0,-2,0,3,0,-6,0,-4,0,8,0], ZZ, a, b) == 9 - assert dup_count_complex_roots([1,0,-2,0,3,0,-6,0,-4,0,8,0], ZZ, c, d) == 4 + f = x**11 - 2*x**9 + 3*x**7 - 6*x**5 - 4*x**3 + 8*x + assert R.dup_count_complex_roots(f, a, b) == 9 + assert R.dup_count_complex_roots(f, c, d) == 4 + def test_dup_count_complex_roots_implicit(): - f = [1,0,0,0,-1,0] # z*(z-1)*(z+1)*(z-I)*(z+I) + R, x = ring("x", ZZ) + + # z*(z-1)*(z+1)*(z-I)*(z+I) + f = x**5 - x - assert dup_count_complex_roots(f, ZZ) == 5 + assert R.dup_count_complex_roots(f) == 5 + + assert R.dup_count_complex_roots(f, sup=(0, 0)) == 3 + assert R.dup_count_complex_roots(f, inf=(0, 0)) == 3 - assert dup_count_complex_roots(f, ZZ, sup=(0, 0)) == 3 - assert dup_count_complex_roots(f, ZZ, inf=(0, 0)) == 3 def test_dup_count_complex_roots_exclude(): - f = [1,0,0,0,-1,0] # z*(z-1)*(z+1)*(z-I)*(z+I) + R, x = ring("x", ZZ) + + # z*(z-1)*(z+1)*(z-I)*(z+I) + f = x**5 - x a, b = (-QQ(1), QQ(0)), (QQ(1), QQ(1)) - assert dup_count_complex_roots(f, ZZ, a, b) == 4 + assert R.dup_count_complex_roots(f, a, b) == 4 - assert dup_count_complex_roots(f, ZZ, a, b, exclude=['S']) == 3 - assert dup_count_complex_roots(f, ZZ, a, b, exclude=['N']) == 3 + assert R.dup_count_complex_roots(f, a, b, exclude=['S']) == 3 + assert R.dup_count_complex_roots(f, a, b, exclude=['N']) == 3 - assert dup_count_complex_roots(f, ZZ, a, b, exclude=['S', 'N']) == 2 + assert R.dup_count_complex_roots(f, a, b, exclude=['S', 'N']) == 2 - assert dup_count_complex_roots(f, ZZ, a, b, exclude=['E']) == 4 - assert dup_count_complex_roots(f, ZZ, a, b, exclude=['W']) == 4 + assert R.dup_count_complex_roots(f, a, b, exclude=['E']) == 4 + assert R.dup_count_complex_roots(f, a, b, exclude=['W']) == 4 - assert dup_count_complex_roots(f, ZZ, a, b, exclude=['E', 'W']) == 4 + assert R.dup_count_complex_roots(f, a, b, exclude=['E', 'W']) == 4 - assert dup_count_complex_roots(f, ZZ, a, b, exclude=['N', 'S', 'E', 'W']) == 2 + assert R.dup_count_complex_roots(f, a, b, exclude=['N', 'S', 'E', 'W']) == 2 - assert dup_count_complex_roots(f, ZZ, a, b, exclude=['SW']) == 3 - assert dup_count_complex_roots(f, ZZ, a, b, exclude=['SE']) == 3 + assert R.dup_count_complex_roots(f, a, b, exclude=['SW']) == 3 + assert R.dup_count_complex_roots(f, a, b, exclude=['SE']) == 3 - assert dup_count_complex_roots(f, ZZ, a, b, exclude=['SW', 'SE']) == 2 - assert dup_count_complex_roots(f, ZZ, a, b, exclude=['SW', 'SE', 'S']) == 1 - assert dup_count_complex_roots(f, ZZ, a, b, exclude=['SW', 'SE', 'S', 'N']) == 0 + assert R.dup_count_complex_roots(f, a, b, exclude=['SW', 'SE']) == 2 + assert R.dup_count_complex_roots(f, a, b, exclude=['SW', 'SE', 'S']) == 1 + assert R.dup_count_complex_roots(f, a, b, exclude=['SW', 'SE', 'S', 'N']) == 0 a, b = (QQ(0), QQ(0)), (QQ(1), QQ(1)) - assert dup_count_complex_roots(f, ZZ, a, b, exclude=True) == 1 + assert R.dup_count_complex_roots(f, a, b, exclude=True) == 1 + def test_dup_isolate_complex_roots_sqf(): - f = [1, -2, 3] + R, x = ring("x", ZZ) + f = x**2 - 2*x + 3 - assert dup_isolate_complex_roots_sqf(f, ZZ) == \ + assert R.dup_isolate_complex_roots_sqf(f) == \ [((0, -6), (6, 0)), ((0, 0), (6, 6))] - assert [ r.as_tuple() for r in dup_isolate_complex_roots_sqf(f, ZZ, blackbox=True) ] == \ + assert [ r.as_tuple() for r in R.dup_isolate_complex_roots_sqf(f, blackbox=True) ] == \ [((0, -6), (6, 0)), ((0, 0), (6, 6))] - assert dup_isolate_complex_roots_sqf(f, ZZ, eps=QQ(1,10)) == \ - [((QQ(15,16), -QQ(3,2)), (QQ(33,32), -QQ(45,32))), ((QQ(15,16), QQ(45,32)), (QQ(33,32), QQ(3,2)))] - assert dup_isolate_complex_roots_sqf(f, ZZ, eps=QQ(1,100)) == \ - [((QQ(255,256), -QQ(363,256)), (QQ(513,512), -QQ(723,512))), ((QQ(255,256), QQ(723,512)), (QQ(513,512), QQ(363,256)))] - - f = [7, -19, 20, 17, 20] + assert R.dup_isolate_complex_roots_sqf(f, eps=QQ(1, 10)) == \ + [((QQ(15, 16), -QQ(3, 2)), (QQ(33, 32), -QQ(45, 32))), + ((QQ(15, 16), QQ(45, 32)), (QQ(33, 32), QQ(3, 2)))] + assert R.dup_isolate_complex_roots_sqf(f, eps=QQ(1, 100)) == \ + [((QQ(255, 256), -QQ(363, 256)), (QQ(513, 512), -QQ(723, 512))), + ((QQ(255, 256), QQ(723, 512)), (QQ(513, 512), QQ(363, 256)))] + + f = 7*x**4 - 19*x**3 + 20*x**2 + 17*x + 20 + + assert R.dup_isolate_complex_roots_sqf(f) == \ + [((-QQ(40, 7), -QQ(40, 7)), (0, 0)), ((-QQ(40, 7), 0), (0, QQ(40, 7))), + ((0, -QQ(40, 7)), (QQ(40, 7), 0)), ((0, 0), (QQ(40, 7), QQ(40, 7)))] - assert dup_isolate_complex_roots_sqf(f, ZZ) == \ - [((-QQ(40,7), -QQ(40,7)), (0, 0)), ((-QQ(40,7), 0), (0, QQ(40,7))), ((0, -QQ(40,7)), (QQ(40,7), 0)), ((0, 0), (QQ(40,7), QQ(40,7)))] def test_dup_isolate_all_roots_sqf(): - f = [4, -1, 2, 5, 0] + R, x = ring("x", ZZ) + f = 4*x**4 - x**3 + 2*x**2 + 5*x - assert dup_isolate_all_roots_sqf(f, ZZ) == \ - ([(-1, 0), (0, 0)], [((0, -QQ(5,2)), (QQ(5,2), 0)), ((0, 0), (QQ(5,2), QQ(5,2)))]) + assert R.dup_isolate_all_roots_sqf(f) == \ + ([(-1, 0), (0, 0)], + [((0, -QQ(5, 2)), (QQ(5, 2), 0)), ((0, 0), (QQ(5, 2), QQ(5, 2)))]) + + assert R.dup_isolate_all_roots_sqf(f, eps=QQ(1, 10)) == \ + ([(QQ(-7, 8), QQ(-6, 7)), (0, 0)], + [((QQ(35, 64), -QQ(35, 32)), (QQ(5, 8), -QQ(65, 64))), ((QQ(35, 64), QQ(65, 64)), (QQ(5, 8), QQ(35, 32)))]) - assert dup_isolate_all_roots_sqf(f, ZZ, eps=QQ(1,10)) == \ - ([(QQ(-7,8), QQ(-6,7)), (0, 0)], [((QQ(35,64), -QQ(35,32)), (QQ(5,8), -QQ(65,64))), ((QQ(35,64), QQ(65,64)), (QQ(5,8), QQ(35,32)))]) def test_dup_isolate_all_roots(): - f = [4, -1, 2, 5, 0] - - assert dup_isolate_all_roots(f, ZZ) == \ - ([((-1, 0), 1), ((0, 0), 1)], [(((0, -QQ(5,2)), (QQ(5,2), 0)), 1), (((0, 0), (QQ(5,2), QQ(5,2))), 1)]) + R, x = ring("x", ZZ) + f = 4*x**4 - x**3 + 2*x**2 + 5*x - assert dup_isolate_all_roots(f, ZZ, eps=QQ(1,10)) == \ - ([((QQ(-7,8), QQ(-6,7)), 1), ((0, 0), 1)], [(((QQ(35,64), -QQ(35,32)), (QQ(5,8), -QQ(65,64))), 1), (((QQ(35,64), QQ(65,64)), (QQ(5,8), QQ(35,32))), 1)]) + assert R.dup_isolate_all_roots(f) == \ + ([((-1, 0), 1), ((0, 0), 1)], + [(((0, -QQ(5, 2)), (QQ(5, 2), 0)), 1), + (((0, 0), (QQ(5, 2), QQ(5, 2))), 1)]) + + assert R.dup_isolate_all_roots(f, eps=QQ(1, 10)) == \ + ([((QQ(-7, 8), QQ(-6, 7)), 1), ((0, 0), 1)], + [(((QQ(35, 64), -QQ(35, 32)), (QQ(5, 8), -QQ(65, 64))), 1), + (((QQ(35, 64), QQ(65, 64)), (QQ(5, 8), QQ(35, 32))), 1)]) - raises(NotImplementedError, lambda: dup_isolate_all_roots([1, 1, -2, -2, 1, 1], ZZ)) + f = x**5 + x**4 - 2*x**3 - 2*x**2 + x + 1 + raises(NotImplementedError, lambda: R.dup_isolate_all_roots(f)) diff -Nru python3-sympy-0.7.2/sympy/polys/tests/test_rootoftools.py python3-sympy-0.7.3/sympy/polys/tests/test_rootoftools.py --- python3-sympy-0.7.2/sympy/polys/tests/test_rootoftools.py 2012-10-17 03:02:22.000000000 +0000 +++ python3-sympy-0.7.3/sympy/polys/tests/test_rootoftools.py 2013-07-13 17:53:32.000000000 +0000 @@ -2,6 +2,7 @@ from sympy.polys.polytools import Poly from sympy.polys.rootoftools import RootOf, RootSum +from sympy.polys.orthopolys import legendre_poly from sympy.polys.polyerrors import ( MultivariatePolynomialError, @@ -17,55 +18,56 @@ from sympy.abc import a, b, c, d, x, y, z, r + def test_RootOf___new__(): assert RootOf(x, 0) == 0 - assert RootOf(x,-1) == 0 + assert RootOf(x, -1) == 0 assert RootOf(x, S.Zero) == 0 assert RootOf(x - 1, 0) == 1 - assert RootOf(x - 1,-1) == 1 + assert RootOf(x - 1, -1) == 1 - assert RootOf(x + 1, 0) ==-1 - assert RootOf(x + 1,-1) ==-1 + assert RootOf(x + 1, 0) == -1 + assert RootOf(x + 1, -1) == -1 assert RootOf(x**2 + 2*x + 3, 0) == -1 - I*sqrt(2) assert RootOf(x**2 + 2*x + 3, 1) == -1 + I*sqrt(2) - assert RootOf(x**2 + 2*x + 3,-1) == -1 + I*sqrt(2) - assert RootOf(x**2 + 2*x + 3,-2) == -1 - I*sqrt(2) + assert RootOf(x**2 + 2*x + 3, -1) == -1 + I*sqrt(2) + assert RootOf(x**2 + 2*x + 3, -2) == -1 - I*sqrt(2) r = RootOf(x**2 + 2*x + 3, 0, radicals=False) - assert isinstance(r, RootOf) == True + assert isinstance(r, RootOf) is True r = RootOf(x**2 + 2*x + 3, 1, radicals=False) - assert isinstance(r, RootOf) == True + assert isinstance(r, RootOf) is True - r = RootOf(x**2 + 2*x + 3,-1, radicals=False) - assert isinstance(r, RootOf) == True + r = RootOf(x**2 + 2*x + 3, -1, radicals=False) + assert isinstance(r, RootOf) is True - r = RootOf(x**2 + 2*x + 3,-2, radicals=False) - assert isinstance(r, RootOf) == True + r = RootOf(x**2 + 2*x + 3, -2, radicals=False) + assert isinstance(r, RootOf) is True - assert RootOf((x - 1)*(x + 1), 0, radicals=False) ==-1 + assert RootOf((x - 1)*(x + 1), 0, radicals=False) == -1 assert RootOf((x - 1)*(x + 1), 1, radicals=False) == 1 - assert RootOf((x - 1)*(x + 1),-1, radicals=False) == 1 - assert RootOf((x - 1)*(x + 1),-2, radicals=False) ==-1 + assert RootOf((x - 1)*(x + 1), -1, radicals=False) == 1 + assert RootOf((x - 1)*(x + 1), -2, radicals=False) == -1 - assert RootOf((x - 1)*(x + 1), 0, radicals=True) ==-1 + assert RootOf((x - 1)*(x + 1), 0, radicals=True) == -1 assert RootOf((x - 1)*(x + 1), 1, radicals=True) == 1 - assert RootOf((x - 1)*(x + 1),-1, radicals=True) == 1 - assert RootOf((x - 1)*(x + 1),-2, radicals=True) ==-1 + assert RootOf((x - 1)*(x + 1), -1, radicals=True) == 1 + assert RootOf((x - 1)*(x + 1), -2, radicals=True) == -1 assert RootOf((x - 1)*(x**3 + x + 3), 0) == RootOf(x**3 + x + 3, 0) assert RootOf((x - 1)*(x**3 + x + 3), 1) == 1 assert RootOf((x - 1)*(x**3 + x + 3), 2) == RootOf(x**3 + x + 3, 1) assert RootOf((x - 1)*(x**3 + x + 3), 3) == RootOf(x**3 + x + 3, 2) - assert RootOf((x - 1)*(x**3 + x + 3),-1) == RootOf(x**3 + x + 3, 2) - assert RootOf((x - 1)*(x**3 + x + 3),-2) == RootOf(x**3 + x + 3, 1) - assert RootOf((x - 1)*(x**3 + x + 3),-3) == 1 - assert RootOf((x - 1)*(x**3 + x + 3),-4) == RootOf(x**3 + x + 3, 0) + assert RootOf((x - 1)*(x**3 + x + 3), -1) == RootOf(x**3 + x + 3, 2) + assert RootOf((x - 1)*(x**3 + x + 3), -2) == RootOf(x**3 + x + 3, 1) + assert RootOf((x - 1)*(x**3 + x + 3), -3) == 1 + assert RootOf((x - 1)*(x**3 + x + 3), -4) == RootOf(x**3 + x + 3, 0) - assert RootOf(x**4 + 3*x**3, 0) ==-3 + assert RootOf(x**4 + 3*x**3, 0) == -3 assert RootOf(x**4 + 3*x**3, 1) == 0 assert RootOf(x**4 + 3*x**3, 2) == 0 assert RootOf(x**4 + 3*x**3, 3) == 0 @@ -81,56 +83,67 @@ raises(NotImplementedError, lambda: RootOf(x**3 - x + sqrt(2), 0)) raises(NotImplementedError, lambda: RootOf(x**3 - x + I, 0)) - raises(IndexError, lambda: RootOf(x**2 - 1,-4)) - raises(IndexError, lambda: RootOf(x**2 - 1,-3)) + raises(IndexError, lambda: RootOf(x**2 - 1, -4)) + raises(IndexError, lambda: RootOf(x**2 - 1, -3)) raises(IndexError, lambda: RootOf(x**2 - 1, 2)) raises(IndexError, lambda: RootOf(x**2 - 1, 3)) assert RootOf(Poly(x - y, x), 0) == y assert RootOf(Poly(x**2 - y, x), 0) == -sqrt(y) - assert RootOf(Poly(x**2 - y, x), 1) == sqrt(y) + assert RootOf(Poly(x**2 - y, x), 1) == sqrt(y) - assert RootOf(Poly(x**3 - y, x), 0) == y**Rational(1,3) + assert RootOf(Poly(x**3 - y, x), 0) == y**Rational(1, 3) assert RootOf(y*x**3 + y*x + 2*y, x, 0) == -1 raises(NotImplementedError, lambda: RootOf(x**3 + x + 2*y, x, 0)) - assert RootOf(x**3 + x + 1, 0).is_commutative == True + assert RootOf(x**3 + x + 1, 0).is_commutative is True + def test_RootOf_free_symbols(): assert RootOf(x**3 + x + 3, 0).free_symbols == set() + # if the following assertion fails then multivariate polynomials + # are apparently supported and the RootOf.free_symbols routine + # should be changed to return whatever symbols would not be + # the PurePoly dummy symbol + raises(NotImplementedError, lambda: RootOf(Poly(x**3 + y*x + 1, x), 0)) + + def test_RootOf___eq__(): - assert (RootOf(x**3 + x + 3, 0) == RootOf(x**3 + x + 3, 0)) == True - assert (RootOf(x**3 + x + 3, 0) == RootOf(x**3 + x + 3, 1)) == False - assert (RootOf(x**3 + x + 3, 1) == RootOf(x**3 + x + 3, 1)) == True - assert (RootOf(x**3 + x + 3, 1) == RootOf(x**3 + x + 3, 2)) == False - assert (RootOf(x**3 + x + 3, 2) == RootOf(x**3 + x + 3, 2)) == True - - assert (RootOf(x**3 + x + 3, 0) == RootOf(y**3 + y + 3, 0)) == True - assert (RootOf(x**3 + x + 3, 0) == RootOf(y**3 + y + 3, 1)) == False - assert (RootOf(x**3 + x + 3, 1) == RootOf(y**3 + y + 3, 1)) == True - assert (RootOf(x**3 + x + 3, 1) == RootOf(y**3 + y + 3, 2)) == False - assert (RootOf(x**3 + x + 3, 2) == RootOf(y**3 + y + 3, 2)) == True + assert (RootOf(x**3 + x + 3, 0) == RootOf(x**3 + x + 3, 0)) is True + assert (RootOf(x**3 + x + 3, 0) == RootOf(x**3 + x + 3, 1)) is False + assert (RootOf(x**3 + x + 3, 1) == RootOf(x**3 + x + 3, 1)) is True + assert (RootOf(x**3 + x + 3, 1) == RootOf(x**3 + x + 3, 2)) is False + assert (RootOf(x**3 + x + 3, 2) == RootOf(x**3 + x + 3, 2)) is True + + assert (RootOf(x**3 + x + 3, 0) == RootOf(y**3 + y + 3, 0)) is True + assert (RootOf(x**3 + x + 3, 0) == RootOf(y**3 + y + 3, 1)) is False + assert (RootOf(x**3 + x + 3, 1) == RootOf(y**3 + y + 3, 1)) is True + assert (RootOf(x**3 + x + 3, 1) == RootOf(y**3 + y + 3, 2)) is False + assert (RootOf(x**3 + x + 3, 2) == RootOf(y**3 + y + 3, 2)) is True + def test_RootOf_is_real(): - assert RootOf(x**3 + x + 3, 0).is_real == True - assert RootOf(x**3 + x + 3, 1).is_real == False - assert RootOf(x**3 + x + 3, 2).is_real == False + assert RootOf(x**3 + x + 3, 0).is_real is True + assert RootOf(x**3 + x + 3, 1).is_real is False + assert RootOf(x**3 + x + 3, 2).is_real is False + def test_RootOf_is_complex(): - assert RootOf(x**3 + x + 3, 0).is_complex == False - assert RootOf(x**3 + x + 3, 1).is_complex == True - assert RootOf(x**3 + x + 3, 2).is_complex == True + assert RootOf(x**3 + x + 3, 0).is_complex is True + def test_RootOf_subs(): assert RootOf(x**3 + x + 1, 0).subs(x, y) == RootOf(y**3 + y + 1, 0) + def test_RootOf_diff(): assert RootOf(x**3 + x + 1, 0).diff(x) == 0 assert RootOf(x**3 + x + 1, 0).diff(y) == 0 + def test_RootOf_evalf(): real = RootOf(x**3 + x + 3, 0).evalf(n=20) @@ -146,9 +159,48 @@ assert re.epsilon_eq(Float("0.60670583138111481707")) assert im.epsilon_eq(Float("1.45061224918844152650")) + p = legendre_poly(4, x, polys=True) + roots = [str(r.n(17)) for r in p.real_roots()] + assert roots == [ + "-0.86113631159405258", + "-0.33998104358485626", + "0.33998104358485626", + "0.86113631159405258", + ] + + re = RootOf(x**5 - 5*x + 12, 0).evalf(n=20) + assert re.epsilon_eq(Float("-1.84208596619025438271")) + + re, im = RootOf(x**5 - 5*x + 12, 1).evalf(n=20).as_real_imag() + assert re.epsilon_eq(Float("-0.351854240827371999559")) + assert im.epsilon_eq(Float("-1.709561043370328882010")) + + re, im = RootOf(x**5 - 5*x + 12, 2).evalf(n=20).as_real_imag() + assert re.epsilon_eq(Float("-0.351854240827371999559")) + assert im.epsilon_eq(Float("+1.709561043370328882010")) + + re, im = RootOf(x**5 - 5*x + 12, 3).evalf(n=20).as_real_imag() + assert re.epsilon_eq(Float("+1.272897223922499190910")) + assert im.epsilon_eq(Float("-0.719798681483861386681")) + + re, im = RootOf(x**5 - 5*x + 12, 4).evalf(n=20).as_real_imag() + assert re.epsilon_eq(Float("+1.272897223922499190910")) + assert im.epsilon_eq(Float("+0.719798681483861386681")) + +def test_RootOf_evalf_caching_bug(): + r = RootOf(x**5 - 5*x + 12, 1) + r.n() + a = r._get_interval() + r = RootOf(x**5 - 5*x + 12, 1) + r.n() + b = r._get_interval() + assert a == b + def test_RootOf_real_roots(): assert Poly(x**5 + x + 1).real_roots() == [RootOf(x**3 - x**2 + 1, 0)] - assert Poly(x**5 + x + 1).real_roots(radicals=False) == [RootOf(x**3 - x**2 + 1, 0)] + assert Poly(x**5 + x + 1).real_roots(radicals=False) == [RootOf( + x**3 - x**2 + 1, 0)] + def test_RootOf_all_roots(): assert Poly(x**5 + x + 1).all_roots() == [ @@ -167,13 +219,29 @@ RootOf(x**3 - x**2 + 1, 2), ] +def test_RootOf_eval_rational(): + p = legendre_poly(4, x, polys=True) + roots = [r.eval_rational(S(1)/10**20) for r in p.real_roots()] + for r in roots: + assert isinstance(r, Rational) + # All we know is that the Rational instance will be at most 1/10^20 from + # the exact root. So if we evaluate to 17 digits, it must be exactly equal + # to: + roots = [str(r.n(17)) for r in roots] + assert roots == [ + "-0.86113631159405258", + "-0.33998104358485626", + "0.33998104358485626", + "0.86113631159405258", + ] + def test_RootSum___new__(): f = x**3 + x + 3 g = Lambda(r, log(r*x)) s = RootSum(f, g) - assert isinstance(s, RootSum) == True + assert isinstance(s, RootSum) is True assert RootSum(f**2, g) == 2*RootSum(f, g) assert RootSum((x - 7)*f**3, g) == log(7*x) + 3*RootSum(f, g) @@ -187,7 +255,7 @@ assert RootSum(f, exp) == RootSum(f, Lambda(x, exp(x))) assert RootSum(f, log) == RootSum(f, Lambda(x, log(x))) - assert isinstance(RootSum(f, auto=False), RootSum) == True + assert isinstance(RootSum(f, auto=False), RootSum) is True assert RootSum(f) == 0 assert RootSum(f, Lambda(x, x)) == 0 @@ -196,7 +264,7 @@ assert RootSum(f, Lambda(x, 1)) == 3 assert RootSum(f, Lambda(x, 2)) == 6 - assert RootSum(f, auto=False).is_commutative == True + assert RootSum(f, auto=False).is_commutative is True assert RootSum(f, Lambda(x, 1/(x + x**2))) == S(11)/3 assert RootSum(f, Lambda(x, y/(x + x**2))) == S(11)/3*y @@ -207,54 +275,66 @@ assert RootSum(x**2 - 1, Lambda(x, z*x**2), x) == 2*z assert RootSum(x**2 - y, Lambda(x, z*x**2), x) == 2*z*y - assert RootSum(x**2 - 1, Lambda(x, exp(x)), quadratic=True) == exp(-1) + exp(1) + assert RootSum( + x**2 - 1, Lambda(x, exp(x)), quadratic=True) == exp(-1) + exp(1) + + assert RootSum(x**3 + a*x + a**3, tan, x) == \ + RootSum(x**3 + x + 1, Lambda(x, tan(a*x))) + assert RootSum(a**3*x**3 + a*x + 1, tan, x) == \ + RootSum(x**3 + x + 1, Lambda(x, tan(x/a))) - assert RootSum(x**3 + a*x + a**3, tan, x) == RootSum(x**3 + x + 1, Lambda(x, tan(a*x))) - assert RootSum(a**3*x**3 + a*x + 1, tan, x) == RootSum(x**3 + x + 1, Lambda(x, tan(x/a))) def test_RootSum_free_symbols(): assert RootSum(x**3 + x + 3, Lambda(r, exp(r))).free_symbols == set() assert RootSum(x**3 + x + 3, Lambda(r, exp(a*r))).free_symbols == set([a]) - assert RootSum(x**3 + x + y, Lambda(r, exp(a*r)), x).free_symbols == set([a, y]) + assert RootSum( + x**3 + x + y, Lambda(r, exp(a*r)), x).free_symbols == set([a, y]) + def test_RootSum___eq__(): f = Lambda(x, exp(x)) - assert (RootSum(x**3 + x + 1, f) == RootSum(x**3 + x + 1, f)) == True - assert (RootSum(x**3 + x + 1, f) == RootSum(y**3 + y + 1, f)) == True + assert (RootSum(x**3 + x + 1, f) == RootSum(x**3 + x + 1, f)) is True + assert (RootSum(x**3 + x + 1, f) == RootSum(y**3 + y + 1, f)) is True + + assert (RootSum(x**3 + x + 1, f) == RootSum(x**3 + x + 2, f)) is False + assert (RootSum(x**3 + x + 1, f) == RootSum(y**3 + y + 2, f)) is False - assert (RootSum(x**3 + x + 1, f) == RootSum(x**3 + x + 2, f)) == False - assert (RootSum(x**3 + x + 1, f) == RootSum(y**3 + y + 2, f)) == False def test_RootSum_doit(): rs = RootSum(x**2 + 1, exp) - assert isinstance(rs, RootSum) == True + assert isinstance(rs, RootSum) is True assert rs.doit() == exp(-I) + exp(I) rs = RootSum(x**2 + a, exp, x) - assert isinstance(rs, RootSum) == True + assert isinstance(rs, RootSum) is True assert rs.doit() == exp(-sqrt(-a)) + exp(sqrt(-a)) + def test_RootSum_evalf(): rs = RootSum(x**2 + 1, exp) - assert rs.evalf(n=20, chop=True).epsilon_eq(Float("1.0806046117362794348", 20), Float("1e-20")) == True - assert rs.evalf(n=15, chop=True).epsilon_eq(Float("1.08060461173628", 15), Float("1e-15")) == True + assert rs.evalf(n=20, chop=True).epsilon_eq( + Float("1.0806046117362794348", 20), Float("1e-20")) is True + assert rs.evalf(n=15, chop=True).epsilon_eq( + Float("1.08060461173628", 15), Float("1e-15")) is True rs = RootSum(x**2 + a, exp, x) assert rs.evalf() == rs + def test_RootSum_diff(): f = x**3 + x + 3 - g = Lambda(r, exp(r*x)) + g = Lambda(r, exp(r*x)) h = Lambda(r, r*exp(r*x)) assert RootSum(f, g).diff(x) == RootSum(f, h) + def test_RootSum_subs(): f = x**3 + x + 3 g = Lambda(r, exp(r*x)) @@ -265,13 +345,18 @@ assert RootSum(f, g).subs(y, 1) == RootSum(f, g) assert RootSum(f, g).subs(x, y) == RootSum(F, G) + def test_RootSum_rational(): - assert RootSum(z**5 - z + 1, Lambda(z, z/(x - z))) == (4*x - 5)/(x**5 - x + 1) + assert RootSum( + z**5 - z + 1, Lambda(z, z/(x - z))) == (4*x - 5)/(x**5 - x + 1) f = 161*z**3 + 115*z**2 + 19*z + 1 - g = Lambda(z, z*log(-3381*z**4/4 - 3381*z**3/4 - 625*z**2/2 - 125*z/2 - 5 + exp(x))) + g = Lambda(z, z*log( + -3381*z**4/4 - 3381*z**3/4 - 625*z**2/2 - 125*z/2 - 5 + exp(x))) + + assert RootSum(f, g).diff(x) == -( + (5*exp(2*x) - 6*exp(x) + 4)*exp(x)/(exp(3*x) - exp(2*x) + 1))/7 - assert RootSum(f, g).diff(x) == -((5*exp(2*x) - 6*exp(x) + 4)*exp(x)/(exp(3*x) - exp(2*x) + 1))/7 def test_RootSum_independent(): f = (x**3 - a)**2*(x**4 - b)**3 diff -Nru python3-sympy-0.7.2/sympy/polys/tests/test_solvers.py python3-sympy-0.7.3/sympy/polys/tests/test_solvers.py --- python3-sympy-0.7.2/sympy/polys/tests/test_solvers.py 1970-01-01 00:00:00.000000000 +0000 +++ python3-sympy-0.7.3/sympy/polys/tests/test_solvers.py 2013-07-13 17:53:32.000000000 +0000 @@ -0,0 +1,103 @@ +"""Tests for low-level linear systems solver. """ + +from sympy.polys.rings import ring +from sympy.polys.fields import field +from sympy.polys.domains import ZZ, QQ +from sympy.polys.solvers import solve_lin_sys + +from sympy.utilities.pytest import slow + +def test_solve_lin_sys_2x2_one(): + domain, x1,x2 = ring("x1,x2", QQ) + eqs = [x1 + x2 - 5, + 2*x1 - x2] + sol = {x1: QQ(5, 3), x2: QQ(10, 3)} + _sol = solve_lin_sys(eqs, domain) + assert _sol == sol and all(isinstance(s, domain.dtype) for s in _sol) + +def test_solve_lin_sys_2x4_none(): + domain, x1,x2 = ring("x1,x2", QQ) + eqs = [x1 - 1, + x1 - x2, + x1 - 2*x2, + x2 - 1] + assert solve_lin_sys(eqs, domain) == None + +def test_solve_lin_sys_3x4_one(): + domain, x1,x2,x3 = ring("x1,x2,x3", QQ) + eqs = [x1 + 2*x2 + 3*x3, + 2*x1 - x2 + x3, + 3*x1 + x2 + x3, + 5*x2 + 2*x3] + sol = {x1: 0, x2: 0, x3: 0} + assert solve_lin_sys(eqs, domain) == sol + +def test_solve_lin_sys_3x3_inf(): + domain, x1,x2,x3 = ring("x1,x2,x3", QQ) + eqs = [x1 - x2 + 2*x3 - 1, + 2*x1 + x2 + x3 - 8, + x1 + x2 - 5] + sol = {x1: -x3 + 3, x2: x3 + 2} + assert solve_lin_sys(eqs, domain) == sol + +def test_solve_lin_sys_3x4_none(): + domain, x1,x2,x3,x4 = ring("x1,x2,x3,x4", QQ) + eqs = [2*x1 + x2 + 7*x3 - 7*x4 - 2, + -3*x1 + 4*x2 - 5*x3 - 6*x4 - 3, + x1 + x2 + 4*x3 - 5*x4 - 2] + assert solve_lin_sys(eqs, domain) == None + +def test_solve_lin_sys_4x7_inf(): + domain, x1,x2,x3,x4,x5,x6,x7 = ring("x1,x2,x3,x4,x5,x6,x7", QQ) + eqs = [x1 + 4*x2 - x4 + 7*x6 - 9*x7 - 3, + 2*x1 + 8*x2 - x3 + 3*x4 + 9*x5 - 13*x6 + 7*x7 - 9, + 2*x3 - 3*x4 - 4*x5 + 12*x6 - 8*x7 - 1, + -x1 - 4*x2 + 2*x3 + 4*x4 + 8*x5 - 31*x6 + 37*x7 - 4] + sol = {x1: 4 - 4*x2 - 2*x5 - x6 + 3*x7, + x3: 2 - x5 + 3*x6 - 5*x7, + x4: 1 - 2*x5 + 6*x6 - 6*x7} + assert solve_lin_sys(eqs, domain) == sol + +def test_solve_lin_sys_5x5_inf(): + domain, x1,x2,x3,x4,x5 = ring("x1,x2,x3,x4,x5", QQ) + eqs = [x1 - x2 - 2*x3 + x4 + 11*x5 - 13, + x1 - x2 + x3 + x4 + 5*x5 - 16, + 2*x1 - 2*x2 + x4 + 10*x5 - 21, + 2*x1 - 2*x2 - x3 + 3*x4 + 20*x5 - 38, + 2*x1 - 2*x2 + x3 + x4 + 8*x5 - 22] + sol = {x1: 6 + x2 - 3*x5, + x3: 1 + 2*x5, + x4: 9 - 4*x5} + assert solve_lin_sys(eqs, domain) == sol + +def test_solve_lin_sys_6x6_1(): + ground, d,r,e,g,i,j,l,o,m,p,q = field("d,r,e,g,i,j,l,o,m,p,q", ZZ) + domain, c,f,h,k,n,b = ring("c,f,h,k,n,b", ground.to_domain()) + + eqs = [b + q/d - c/d, c*(1/d + 1/e + 1/g) - f/g - q/d, f*(1/g + 1/i + 1/j) - c/g - h/i, h*(1/i + 1/l + 1/m) - f/i - k/m, k*(1/m + 1/o + 1/p) - h/m - n/p, n/p - k/p] + sol = { + b: (e*i*l*q + e*i*m*q + e*i*o*q + e*j*l*q + e*j*m*q + e*j*o*q + e*l*m*q + e*l*o*q + g*i*l*q + g*i*m*q + g*i*o*q + g*j*l*q + g*j*m*q + g*j*o*q + g*l*m*q + g*l*o*q + i*j*l*q + i*j*m*q + i*j*o*q + j*l*m*q + j*l*o*q)/(-d*e*i*l - d*e*i*m - d*e*i*o - d*e*j*l - d*e*j*m - d*e*j*o - d*e*l*m - d*e*l*o - d*g*i*l - d*g*i*m - d*g*i*o - d*g*j*l - d*g*j*m - d*g*j*o - d*g*l*m - d*g*l*o - d*i*j*l - d*i*j*m - d*i*j*o - d*j*l*m - d*j*l*o - e*g*i*l - e*g*i*m - e*g*i*o - e*g*j*l - e*g*j*m - e*g*j*o - e*g*l*m - e*g*l*o - e*i*j*l - e*i*j*m - e*i*j*o - e*j*l*m - e*j*l*o), + c: (-e*g*i*l*q - e*g*i*m*q - e*g*i*o*q - e*g*j*l*q - e*g*j*m*q - e*g*j*o*q - e*g*l*m*q - e*g*l*o*q - e*i*j*l*q - e*i*j*m*q - e*i*j*o*q - e*j*l*m*q - e*j*l*o*q)/(-d*e*i*l - d*e*i*m - d*e*i*o - d*e*j*l - d*e*j*m - d*e*j*o - d*e*l*m - d*e*l*o - d*g*i*l - d*g*i*m - d*g*i*o - d*g*j*l - d*g*j*m - d*g*j*o - d*g*l*m - d*g*l*o - d*i*j*l - d*i*j*m - d*i*j*o - d*j*l*m - d*j*l*o - e*g*i*l - e*g*i*m - e*g*i*o - e*g*j*l - e*g*j*m - e*g*j*o - e*g*l*m - e*g*l*o - e*i*j*l - e*i*j*m - e*i*j*o - e*j*l*m - e*j*l*o), + f: (-e*i*j*l*q - e*i*j*m*q - e*i*j*o*q - e*j*l*m*q - e*j*l*o*q)/(-d*e*i*l - d*e*i*m - d*e*i*o - d*e*j*l - d*e*j*m - d*e*j*o - d*e*l*m - d*e*l*o - d*g*i*l - d*g*i*m - d*g*i*o - d*g*j*l - d*g*j*m - d*g*j*o - d*g*l*m - d*g*l*o - d*i*j*l - d*i*j*m - d*i*j*o - d*j*l*m - d*j*l*o - e*g*i*l - e*g*i*m - e*g*i*o - e*g*j*l - e*g*j*m - e*g*j*o - e*g*l*m - e*g*l*o - e*i*j*l - e*i*j*m - e*i*j*o - e*j*l*m - e*j*l*o), + h: (-e*j*l*m*q - e*j*l*o*q)/(-d*e*i*l - d*e*i*m - d*e*i*o - d*e*j*l - d*e*j*m - d*e*j*o - d*e*l*m - d*e*l*o - d*g*i*l - d*g*i*m - d*g*i*o - d*g*j*l - d*g*j*m - d*g*j*o - d*g*l*m - d*g*l*o - d*i*j*l - d*i*j*m - d*i*j*o - d*j*l*m - d*j*l*o - e*g*i*l - e*g*i*m - e*g*i*o - e*g*j*l - e*g*j*m - e*g*j*o - e*g*l*m - e*g*l*o - e*i*j*l - e*i*j*m - e*i*j*o - e*j*l*m - e*j*l*o), + k: e*j*l*o*q/(d*e*i*l + d*e*i*m + d*e*i*o + d*e*j*l + d*e*j*m + d*e*j*o + d*e*l*m + d*e*l*o + d*g*i*l + d*g*i*m + d*g*i*o + d*g*j*l + d*g*j*m + d*g*j*o + d*g*l*m + d*g*l*o + d*i*j*l + d*i*j*m + d*i*j*o + d*j*l*m + d*j*l*o + e*g*i*l + e*g*i*m + e*g*i*o + e*g*j*l + e*g*j*m + e*g*j*o + e*g*l*m + e*g*l*o + e*i*j*l + e*i*j*m + e*i*j*o + e*j*l*m + e*j*l*o), + n: e*j*l*o*q/(d*e*i*l + d*e*i*m + d*e*i*o + d*e*j*l + d*e*j*m + d*e*j*o + d*e*l*m + d*e*l*o + d*g*i*l + d*g*i*m + d*g*i*o + d*g*j*l + d*g*j*m + d*g*j*o + d*g*l*m + d*g*l*o + d*i*j*l + d*i*j*m + d*i*j*o + d*j*l*m + d*j*l*o + e*g*i*l + e*g*i*m + e*g*i*o + e*g*j*l + e*g*j*m + e*g*j*o + e*g*l*m + e*g*l*o + e*i*j*l + e*i*j*m + e*i*j*o + e*j*l*m + e*j*l*o), + } + + assert solve_lin_sys(eqs, domain) == sol + +def test_solve_lin_sys_6x6_2(): + ground, d,r,e,g,i,j,l,o,m,p,q = field("d,r,e,g,i,j,l,o,m,p,q", ZZ) + domain, c,f,h,k,n,b = ring("c,f,h,k,n,b", ground.to_domain()) + + eqs = [b + r/d - c/d, c*(1/d + 1/e + 1/g) - f/g - r/d, f*(1/g + 1/i + 1/j) - c/g - h/i, h*(1/i + 1/l + 1/m) - f/i - k/m, k*(1/m + 1/o + 1/p) - h/m - n/p, n*(1/p + 1/q) - k/p] + sol = { + b: -((l*q*e*o + l*q*g*o + i*m*q*e + i*l*q*e + i*l*p*e + i*j*o*q + j*e*o*q + g*j*o*q + i*e*o*q + g*i*o*q + e*l*o*p + e*l*m*p + e*l*m*o + e*i*o*p + e*i*m*p + e*i*m*o + e*i*l*o + j*e*o*p + j*e*m*q + j*e*m*p + j*e*m*o + j*l*m*q + j*l*m*p + j*l*m*o + i*j*m*p + i*j*m*o + i*j*l*q + i*j*l*o + i*j*m*q + j*l*o*p + j*e*l*o + g*j*o*p + g*j*m*q + g*j*m*p + i*j*l*p + i*j*o*p + j*e*l*q + j*e*l*p + j*l*o*q + g*j*m*o + g*j*l*q + g*j*l*p + g*j*l*o + g*l*o*p + g*l*m*p + g*l*m*o + g*i*m*o + g*i*o*p + g*i*m*q + g*i*m*p + g*i*l*q + g*i*l*p + g*i*l*o + l*m*q*e + l*m*q*g)*r)/(l*q*d*e*o + l*q*d*g*o + l*q*e*g*o + i*j*d*o*q + i*j*e*o*q + j*d*e*o*q + g*j*d*o*q + g*j*e*o*q + g*i*e*o*q + i*d*e*o*q + g*i*d*o*q + g*i*d*o*p + g*i*d*m*q + g*i*d*m*p + g*i*d*m*o + g*i*d*l*q + g*i*d*l*p + g*i*d*l*o + g*e*l*m*p + g*e*l*o*p + g*j*e*l*q + g*e*l*m*o + g*j*e*m*p + g*j*e*m*o + d*e*l*m*p + d*e*l*m*o + i*d*e*m*p + g*j*e*l*p + g*j*e*l*o + d*e*l*o*p + i*j*d*l*o + i*j*e*o*p + i*j*e*m*q + i*j*d*m*q + i*j*d*m*p + i*j*d*m*o + i*j*d*l*q + i*j*d*l*p + i*j*e*m*p + i*j*e*m*o + i*j*e*l*q + i*j*e*l*p + i*j*e*l*o + i*d*e*m*q + i*d*e*m*o + i*d*e*l*q + i*d*e*l*p + j*d*l*o*p + j*d*e*l*o + g*j*d*o*p + g*j*d*m*q + g*j*d*m*p + g*j*d*m*o + g*j*d*l*q + g*j*d*l*p + g*j*d*l*o + g*j*e*o*p + g*j*e*m*q + g*d*l*o*p + g*d*l*m*p + g*d*l*m*o + j*d*e*m*p + i*d*e*o*p + j*e*o*q*l + j*e*o*p*l + j*e*m*q*l + j*d*e*o*p + j*d*e*m*q + i*j*d*o*p + g*i*e*o*p + j*d*e*m*o + j*d*e*l*q + j*d*e*l*p + j*e*m*p*l + j*e*m*o*l + g*i*e*m*q + g*i*e*m*p + g*i*e*m*o + g*i*e*l*q + g*i*e*l*p + g*i*e*l*o + j*d*l*o*q + j*d*l*m*q + j*d*l*m*p + j*d*l*m*o + i*d*e*l*o + l*m*q*d*e + l*m*q*d*g + l*m*q*e*g), + c: (r*e*(l*q*g*o + i*j*o*q + g*j*o*q + g*i*o*q + j*l*m*q + j*l*m*p + j*l*m*o + i*j*m*p + i*j*m*o + i*j*l*q + i*j*l*o + i*j*m*q + j*l*o*p + g*j*o*p + g*j*m*q + g*j*m*p + i*j*l*p + i*j*o*p + j*l*o*q + g*j*m*o + g*j*l*q + g*j*l*p + g*j*l*o + g*l*o*p + g*l*m*p + g*l*m*o + g*i*m*o + g*i*o*p + g*i*m*q + g*i*m*p + g*i*l*q + g*i*l*p + g*i*l*o + l*m*q*g))/(l*q*d*e*o + l*q*d*g*o + l*q*e*g*o + i*j*d*o*q + i*j*e*o*q + j*d*e*o*q + g*j*d*o*q + g*j*e*o*q + g*i*e*o*q + i*d*e*o*q + g*i*d*o*q + g*i*d*o*p + g*i*d*m*q + g*i*d*m*p + g*i*d*m*o + g*i*d*l*q + g*i*d*l*p + g*i*d*l*o + g*e*l*m*p + g*e*l*o*p + g*j*e*l*q + g*e*l*m*o + g*j*e*m*p + g*j*e*m*o + d*e*l*m*p + d*e*l*m*o + i*d*e*m*p + g*j*e*l*p + g*j*e*l*o + d*e*l*o*p + i*j*d*l*o + i*j*e*o*p + i*j*e*m*q + i*j*d*m*q + i*j*d*m*p + i*j*d*m*o + i*j*d*l*q + i*j*d*l*p + i*j*e*m*p + i*j*e*m*o + i*j*e*l*q + i*j*e*l*p + i*j*e*l*o + i*d*e*m*q + i*d*e*m*o + i*d*e*l*q + i*d*e*l*p + j*d*l*o*p + j*d*e*l*o + g*j*d*o*p + g*j*d*m*q + g*j*d*m*p + g*j*d*m*o + g*j*d*l*q + g*j*d*l*p + g*j*d*l*o + g*j*e*o*p + g*j*e*m*q + g*d*l*o*p + g*d*l*m*p + g*d*l*m*o + j*d*e*m*p + i*d*e*o*p + j*e*o*q*l + j*e*o*p*l + j*e*m*q*l + j*d*e*o*p + j*d*e*m*q + i*j*d*o*p + g*i*e*o*p + j*d*e*m*o + j*d*e*l*q + j*d*e*l*p + j*e*m*p*l + j*e*m*o*l + g*i*e*m*q + g*i*e*m*p + g*i*e*m*o + g*i*e*l*q + g*i*e*l*p + g*i*e*l*o + j*d*l*o*q + j*d*l*m*q + j*d*l*m*p + j*d*l*m*o + i*d*e*l*o + l*m*q*d*e + l*m*q*d*g + l*m*q*e*g), + f: (r*e*j*(l*q*o + l*o*p + l*m*q + l*m*p + l*m*o + i*o*q + i*o*p + i*m*q + i*m*p + i*m*o + i*l*q + i*l*p + i*l*o))/(l*q*d*e*o + l*q*d*g*o + l*q*e*g*o + i*j*d*o*q + i*j*e*o*q + j*d*e*o*q + g*j*d*o*q + g*j*e*o*q + g*i*e*o*q + i*d*e*o*q + g*i*d*o*q + g*i*d*o*p + g*i*d*m*q + g*i*d*m*p + g*i*d*m*o + g*i*d*l*q + g*i*d*l*p + g*i*d*l*o + g*e*l*m*p + g*e*l*o*p + g*j*e*l*q + g*e*l*m*o + g*j*e*m*p + g*j*e*m*o + d*e*l*m*p + d*e*l*m*o + i*d*e*m*p + g*j*e*l*p + g*j*e*l*o + d*e*l*o*p + i*j*d*l*o + i*j*e*o*p + i*j*e*m*q + i*j*d*m*q + i*j*d*m*p + i*j*d*m*o + i*j*d*l*q + i*j*d*l*p + i*j*e*m*p + i*j*e*m*o + i*j*e*l*q + i*j*e*l*p + i*j*e*l*o + i*d*e*m*q + i*d*e*m*o + i*d*e*l*q + i*d*e*l*p + j*d*l*o*p + j*d*e*l*o + g*j*d*o*p + g*j*d*m*q + g*j*d*m*p + g*j*d*m*o + g*j*d*l*q + g*j*d*l*p + g*j*d*l*o + g*j*e*o*p + g*j*e*m*q + g*d*l*o*p + g*d*l*m*p + g*d*l*m*o + j*d*e*m*p + i*d*e*o*p + j*e*o*q*l + j*e*o*p*l + j*e*m*q*l + j*d*e*o*p + j*d*e*m*q + i*j*d*o*p + g*i*e*o*p + j*d*e*m*o + j*d*e*l*q + j*d*e*l*p + j*e*m*p*l + j*e*m*o*l + g*i*e*m*q + g*i*e*m*p + g*i*e*m*o + g*i*e*l*q + g*i*e*l*p + g*i*e*l*o + j*d*l*o*q + j*d*l*m*q + j*d*l*m*p + j*d*l*m*o + i*d*e*l*o + l*m*q*d*e + l*m*q*d*g + l*m*q*e*g), + h: (j*e*r*l*(o*q + o*p + m*q + m*p + m*o))/(l*q*d*e*o + l*q*d*g*o + l*q*e*g*o + i*j*d*o*q + i*j*e*o*q + j*d*e*o*q + g*j*d*o*q + g*j*e*o*q + g*i*e*o*q + i*d*e*o*q + g*i*d*o*q + g*i*d*o*p + g*i*d*m*q + g*i*d*m*p + g*i*d*m*o + g*i*d*l*q + g*i*d*l*p + g*i*d*l*o + g*e*l*m*p + g*e*l*o*p + g*j*e*l*q + g*e*l*m*o + g*j*e*m*p + g*j*e*m*o + d*e*l*m*p + d*e*l*m*o + i*d*e*m*p + g*j*e*l*p + g*j*e*l*o + d*e*l*o*p + i*j*d*l*o + i*j*e*o*p + i*j*e*m*q + i*j*d*m*q + i*j*d*m*p + i*j*d*m*o + i*j*d*l*q + i*j*d*l*p + i*j*e*m*p + i*j*e*m*o + i*j*e*l*q + i*j*e*l*p + i*j*e*l*o + i*d*e*m*q + i*d*e*m*o + i*d*e*l*q + i*d*e*l*p + j*d*l*o*p + j*d*e*l*o + g*j*d*o*p + g*j*d*m*q + g*j*d*m*p + g*j*d*m*o + g*j*d*l*q + g*j*d*l*p + g*j*d*l*o + g*j*e*o*p + g*j*e*m*q + g*d*l*o*p + g*d*l*m*p + g*d*l*m*o + j*d*e*m*p + i*d*e*o*p + j*e*o*q*l + j*e*o*p*l + j*e*m*q*l + j*d*e*o*p + j*d*e*m*q + i*j*d*o*p + g*i*e*o*p + j*d*e*m*o + j*d*e*l*q + j*d*e*l*p + j*e*m*p*l + j*e*m*o*l + g*i*e*m*q + g*i*e*m*p + g*i*e*m*o + g*i*e*l*q + g*i*e*l*p + g*i*e*l*o + j*d*l*o*q + j*d*l*m*q + j*d*l*m*p + j*d*l*m*o + i*d*e*l*o + l*m*q*d*e + l*m*q*d*g + l*m*q*e*g), + k: (j*e*r*o*l*(q + p))/(l*q*d*e*o + l*q*d*g*o + l*q*e*g*o + i*j*d*o*q + i*j*e*o*q + j*d*e*o*q + g*j*d*o*q + g*j*e*o*q + g*i*e*o*q + i*d*e*o*q + g*i*d*o*q + g*i*d*o*p + g*i*d*m*q + g*i*d*m*p + g*i*d*m*o + g*i*d*l*q + g*i*d*l*p + g*i*d*l*o + g*e*l*m*p + g*e*l*o*p + g*j*e*l*q + g*e*l*m*o + g*j*e*m*p + g*j*e*m*o + d*e*l*m*p + d*e*l*m*o + i*d*e*m*p + g*j*e*l*p + g*j*e*l*o + d*e*l*o*p + i*j*d*l*o + i*j*e*o*p + i*j*e*m*q + i*j*d*m*q + i*j*d*m*p + i*j*d*m*o + i*j*d*l*q + i*j*d*l*p + i*j*e*m*p + i*j*e*m*o + i*j*e*l*q + i*j*e*l*p + i*j*e*l*o + i*d*e*m*q + i*d*e*m*o + i*d*e*l*q + i*d*e*l*p + j*d*l*o*p + j*d*e*l*o + g*j*d*o*p + g*j*d*m*q + g*j*d*m*p + g*j*d*m*o + g*j*d*l*q + g*j*d*l*p + g*j*d*l*o + g*j*e*o*p + g*j*e*m*q + g*d*l*o*p + g*d*l*m*p + g*d*l*m*o + j*d*e*m*p + i*d*e*o*p + j*e*o*q*l + j*e*o*p*l + j*e*m*q*l + j*d*e*o*p + j*d*e*m*q + i*j*d*o*p + g*i*e*o*p + j*d*e*m*o + j*d*e*l*q + j*d*e*l*p + j*e*m*p*l + j*e*m*o*l + g*i*e*m*q + g*i*e*m*p + g*i*e*m*o + g*i*e*l*q + g*i*e*l*p + g*i*e*l*o + j*d*l*o*q + j*d*l*m*q + j*d*l*m*p + j*d*l*m*o + i*d*e*l*o + l*m*q*d*e + l*m*q*d*g + l*m*q*e*g), + n: (j*e*r*o*q*l)/(l*q*d*e*o + l*q*d*g*o + l*q*e*g*o + i*j*d*o*q + i*j*e*o*q + j*d*e*o*q + g*j*d*o*q + g*j*e*o*q + g*i*e*o*q + i*d*e*o*q + g*i*d*o*q + g*i*d*o*p + g*i*d*m*q + g*i*d*m*p + g*i*d*m*o + g*i*d*l*q + g*i*d*l*p + g*i*d*l*o + g*e*l*m*p + g*e*l*o*p + g*j*e*l*q + g*e*l*m*o + g*j*e*m*p + g*j*e*m*o + d*e*l*m*p + d*e*l*m*o + i*d*e*m*p + g*j*e*l*p + g*j*e*l*o + d*e*l*o*p + i*j*d*l*o + i*j*e*o*p + i*j*e*m*q + i*j*d*m*q + i*j*d*m*p + i*j*d*m*o + i*j*d*l*q + i*j*d*l*p + i*j*e*m*p + i*j*e*m*o + i*j*e*l*q + i*j*e*l*p + i*j*e*l*o + i*d*e*m*q + i*d*e*m*o + i*d*e*l*q + i*d*e*l*p + j*d*l*o*p + j*d*e*l*o + g*j*d*o*p + g*j*d*m*q + g*j*d*m*p + g*j*d*m*o + g*j*d*l*q + g*j*d*l*p + g*j*d*l*o + g*j*e*o*p + g*j*e*m*q + g*d*l*o*p + g*d*l*m*p + g*d*l*m*o + j*d*e*m*p + i*d*e*o*p + j*e*o*q*l + j*e*o*p*l + j*e*m*q*l + j*d*e*o*p + j*d*e*m*q + i*j*d*o*p + g*i*e*o*p + j*d*e*m*o + j*d*e*l*q + j*d*e*l*p + j*e*m*p*l + j*e*m*o*l + g*i*e*m*q + g*i*e*m*p + g*i*e*m*o + g*i*e*l*q + g*i*e*l*p + g*i*e*l*o + j*d*l*o*q + j*d*l*m*q + j*d*l*m*p + j*d*l*m*o + i*d*e*l*o + l*m*q*d*e + l*m*q*d*g + l*m*q*e*g), + } + + assert solve_lin_sys(eqs, domain) == sol diff -Nru python3-sympy-0.7.2/sympy/polys/tests/test_specialpolys.py python3-sympy-0.7.3/sympy/polys/tests/test_specialpolys.py --- python3-sympy-0.7.2/sympy/polys/tests/test_specialpolys.py 2012-10-17 03:02:22.000000000 +0000 +++ python3-sympy-0.7.3/sympy/polys/tests/test_specialpolys.py 2013-07-13 17:53:32.000000000 +0000 @@ -19,6 +19,7 @@ from sympy.abc import x, y, z + def test_swinnerton_dyer_poly(): raises(ValueError, lambda: swinnerton_dyer_poly(0, x)) @@ -26,7 +27,9 @@ assert swinnerton_dyer_poly(1, x) == x**2 - 2 assert swinnerton_dyer_poly(2, x) == x**4 - 10*x**2 + 1 - assert swinnerton_dyer_poly(3, x) == x**8 - 40*x**6 + 352*x**4 - 960*x**2 + 576 + assert swinnerton_dyer_poly( + 3, x) == x**8 - 40*x**6 + 352*x**4 - 960*x**2 + 576 + def test_cyclotomic_poly(): raises(ValueError, lambda: cyclotomic_poly(0, x)) @@ -40,6 +43,7 @@ assert cyclotomic_poly(5, x) == x**4 + x**3 + x**2 + x + 1 assert cyclotomic_poly(6, x) == x**2 - x + 1 + def test_symmetric_poly(): raises(ValueError, lambda: symmetric_poly(-1, x, y, z)) raises(ValueError, lambda: symmetric_poly(5, x, y, z)) @@ -52,6 +56,7 @@ assert symmetric_poly(2, x, y, z) == x*y + x*z + y*z assert symmetric_poly(3, x, y, z) == x*y*z + def test_random_poly(): poly = random_poly(x, 10, -100, 100, polys=False) @@ -63,8 +68,9 @@ assert poly.degree() == 10 assert all(-100 <= coeff <= 100 for coeff in poly.coeffs()) is True + def test_interpolating_poly(): - x0,x1,x2, y0,y1,y2 = symbols('x:3, y:3') + x0, x1, x2, y0, y1, y2 = symbols('x:3, y:3') assert interpolating_poly(0, x) == 0 assert interpolating_poly(1, x) == y0 @@ -77,35 +83,38 @@ y1*(x - x0)*(x - x2)/((x1 - x0)*(x1 - x2)) + \ y2*(x - x0)*(x - x1)/((x2 - x0)*(x2 - x1)) + def test_fateman_poly_F_1(): - f,g,h = fateman_poly_F_1(1) - F,G,H = dmp_fateman_poly_F_1(1, ZZ) + f, g, h = fateman_poly_F_1(1) + F, G, H = dmp_fateman_poly_F_1(1, ZZ) - assert [ t.rep.rep for t in [f,g,h] ] == [F,G,H] + assert [ t.rep.rep for t in [f, g, h] ] == [F, G, H] - f,g,h = fateman_poly_F_1(3) - F,G,H = dmp_fateman_poly_F_1(3, ZZ) + f, g, h = fateman_poly_F_1(3) + F, G, H = dmp_fateman_poly_F_1(3, ZZ) + + assert [ t.rep.rep for t in [f, g, h] ] == [F, G, H] - assert [ t.rep.rep for t in [f,g,h] ] == [F,G,H] def test_fateman_poly_F_2(): - f,g,h = fateman_poly_F_2(1) - F,G,H = dmp_fateman_poly_F_2(1, ZZ) + f, g, h = fateman_poly_F_2(1) + F, G, H = dmp_fateman_poly_F_2(1, ZZ) + + assert [ t.rep.rep for t in [f, g, h] ] == [F, G, H] - assert [ t.rep.rep for t in [f,g,h] ] == [F,G,H] + f, g, h = fateman_poly_F_2(3) + F, G, H = dmp_fateman_poly_F_2(3, ZZ) - f,g,h = fateman_poly_F_2(3) - F,G,H = dmp_fateman_poly_F_2(3, ZZ) + assert [ t.rep.rep for t in [f, g, h] ] == [F, G, H] - assert [ t.rep.rep for t in [f,g,h] ] == [F,G,H] def test_fateman_poly_F_3(): - f,g,h = fateman_poly_F_3(1) - F,G,H = dmp_fateman_poly_F_3(1, ZZ) + f, g, h = fateman_poly_F_3(1) + F, G, H = dmp_fateman_poly_F_3(1, ZZ) - assert [ t.rep.rep for t in [f,g,h] ] == [F,G,H] + assert [ t.rep.rep for t in [f, g, h] ] == [F, G, H] - f,g,h = fateman_poly_F_3(3) - F,G,H = dmp_fateman_poly_F_3(3, ZZ) + f, g, h = fateman_poly_F_3(3) + F, G, H = dmp_fateman_poly_F_3(3, ZZ) - assert [ t.rep.rep for t in [f,g,h] ] == [F,G,H] + assert [ t.rep.rep for t in [f, g, h] ] == [F, G, H] diff -Nru python3-sympy-0.7.2/sympy/polys/tests/test_sqfreetools.py python3-sympy-0.7.3/sympy/polys/tests/test_sqfreetools.py --- python3-sympy-0.7.2/sympy/polys/tests/test_sqfreetools.py 2012-10-17 03:02:22.000000000 +0000 +++ python3-sympy-0.7.3/sympy/polys/tests/test_sqfreetools.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,173 +1,150 @@ """Tests for square-free decomposition algorithms and related tools. """ -from sympy.polys.sqfreetools import ( - dup_sqf_p, dmp_sqf_p, - dup_sqf_norm, dmp_sqf_norm, - dup_sqf_part, dmp_sqf_part, - dup_sqf_list, dup_sqf_list_include, - dmp_sqf_list, dmp_sqf_list_include, - dup_gff_list, dmp_gff_list) - -from sympy.polys.euclidtools import ( - dmp_resultant) - -from sympy.polys.densearith import ( - dmp_neg, dmp_sub, dmp_mul, dmp_sqr) - -from sympy.polys.densetools import ( - dmp_diff) - -from sympy.polys.polyclasses import ( - DMP -) - -from sympy.polys.polyerrors import ( - DomainError) - -from sympy.polys.specialpolys import ( - f_0, f_1, f_2, f_3, f_4, f_5, f_6) - +from sympy.polys.rings import ring from sympy.polys.domains import FF, ZZ, QQ - -from sympy.abc import x +from sympy.polys.polyclasses import DMP +from sympy.polys.specialpolys import f_polys from sympy.utilities.pytest import raises -def test_dup_sqf(): - assert dup_sqf_part([], ZZ) == [] - assert dup_sqf_p([], ZZ) == True - - assert dup_sqf_part([7], ZZ) == [1] - assert dup_sqf_p([7], ZZ) == True - - assert dup_sqf_part([2,2], ZZ) == [1,1] - assert dup_sqf_p([2,2], ZZ) == True - - assert dup_sqf_part([1,0,1,1], ZZ) == [1,0,1,1] - assert dup_sqf_p([1,0,1,1], ZZ) == True +f_0, f_1, f_2, f_3, f_4, f_5, f_6 = f_polys() - assert dup_sqf_part([-1,0,1,1], ZZ) == [1,0,-1,-1] - assert dup_sqf_p([-1,0,1,1], ZZ) == True - - assert dup_sqf_part([2,3,0,0], ZZ) == [2,3,0] - assert dup_sqf_p([2,3,0,0], ZZ) == False - - assert dup_sqf_part([-2,3,0,0], ZZ) == [2,-3,0] - assert dup_sqf_p([-2,3,0,0], ZZ) == False - - assert dup_sqf_list([], ZZ) == (0, []) - assert dup_sqf_list([1], ZZ) == (1, []) - - assert dup_sqf_list([1,0], ZZ) == (1, [([1,0], 1)]) - assert dup_sqf_list([2,0,0], ZZ) == (2, [([1,0], 2)]) - assert dup_sqf_list([3,0,0,0], ZZ) == (3, [([1,0], 3)]) +def test_dup_sqf(): + R, x = ring("x", ZZ) - assert dup_sqf_list([ZZ(2),ZZ(4),ZZ(2)], ZZ) == \ - (ZZ(2), [([ZZ(1),ZZ(1)], 2)]) - assert dup_sqf_list([QQ(2),QQ(4),QQ(2)], QQ) == \ - (QQ(2), [([QQ(1),QQ(1)], 2)]) + assert R.dup_sqf_part(0) == 0 + assert R.dup_sqf_p(0) is True - assert dup_sqf_list([-1,1,0,0,1,-1], ZZ) == \ - (-1, [([1,1,1,1], 1), ([1,-1], 2)]) - assert dup_sqf_list([1,0,6,0,12,0,8,0,0], ZZ) == \ - (1, [([1,0], 2), ([1,0,2], 3)]) + assert R.dup_sqf_part(7) == 1 + assert R.dup_sqf_p(7) is True - K = FF(2) - f = list(map(K, [1,0,1])) + assert R.dup_sqf_part(2*x + 2) == x + 1 + assert R.dup_sqf_p(2*x + 2) is True - assert dup_sqf_list(f, K) == \ - (K(1), [([K(1),K(1)], 2)]) + assert R.dup_sqf_part(x**3 + x + 1) == x**3 + x + 1 + assert R.dup_sqf_p(x**3 + x + 1) is True - K = FF(3) - f = list(map(K, [1,0,0,2,0,0,2,0,0,1,0])) + assert R.dup_sqf_part(-x**3 + x + 1) == x**3 - x - 1 + assert R.dup_sqf_p(-x**3 + x + 1) is True - assert dup_sqf_list(f, K) == \ - (K(1), [([K(1), K(0)], 1), - ([K(1), K(1)], 3), - ([K(1), K(2)], 6)]) + assert R.dup_sqf_part(2*x**3 + 3*x**2) == 2*x**2 + 3*x + assert R.dup_sqf_p(2*x**3 + 3*x**2) is False - f = [1,0,0,1] - g = list(map(K, f)) + assert R.dup_sqf_part(-2*x**3 + 3*x**2) == 2*x**2 - 3*x + assert R.dup_sqf_p(-2*x**3 + 3*x**2) is False - assert dup_sqf_part(f, ZZ) == f - assert dup_sqf_part(g, K) == [K(1), K(1)] + assert R.dup_sqf_list(0) == (0, []) + assert R.dup_sqf_list(1) == (1, []) - assert dup_sqf_p(f, ZZ) == True - assert dup_sqf_p(g, K) == False + assert R.dup_sqf_list(x) == (1, [(x, 1)]) + assert R.dup_sqf_list(2*x**2) == (2, [(x, 2)]) + assert R.dup_sqf_list(3*x**3) == (3, [(x, 3)]) - A = [[1],[],[-3],[],[6]] - D = [[1],[],[-5],[],[5],[],[4]] + assert R.dup_sqf_list(-x**5 + x**4 + x - 1) == \ + (-1, [(x**3 + x**2 + x + 1, 1), (x - 1, 2)]) + assert R.dup_sqf_list(x**8 + 6*x**6 + 12*x**4 + 8*x**2) == \ + ( 1, [(x, 2), (x**2 + 2, 3)]) - f, g = D, dmp_sub(A, dmp_mul(dmp_diff(D, 1, 1, ZZ), [[1,0]], 1, ZZ), 1, ZZ) + assert R.dup_sqf_list(2*x**2 + 4*x + 2) == (2, [(x + 1, 2)]) - res = dmp_resultant(f, g, 1, ZZ) + R, x = ring("x", QQ) + assert R.dup_sqf_list(2*x**2 + 4*x + 2) == (2, [(x + 1, 2)]) - assert dup_sqf_list(res, ZZ) == (45796, [([4,0,1], 3)]) + R, x = ring("x", FF(2)) + assert R.dup_sqf_list(x**2 + 1) == (1, [(x + 1, 2)]) - assert dup_sqf_list_include([DMP([1, 0, 0, 0], ZZ), DMP([], ZZ), DMP([], ZZ)], ZZ[x]) == \ - [([DMP([1, 0, 0, 0], ZZ)], 1), ([DMP([1], ZZ), DMP([], ZZ)], 2)] + R, x = ring("x", FF(3)) + assert R.dup_sqf_list(x**10 + 2*x**7 + 2*x**4 + x) == \ + (1, [(x, 1), + (x + 1, 3), + (x + 2, 6)]) -def test_dmp_sqf(): - assert dmp_sqf_part([[]], 1, ZZ) == [[]] - assert dmp_sqf_p([[]], 1, ZZ) == True + R1, x = ring("x", ZZ) + R2, y = ring("y", FF(3)) - assert dmp_sqf_part([[7]], 1, ZZ) == [[1]] - assert dmp_sqf_p([[7]], 1, ZZ) == True + f = x**3 + 1 + g = y**3 + 1 - assert dmp_sqf_p(f_0, 2, ZZ) == True - assert dmp_sqf_p(dmp_sqr(f_0, 2, ZZ), 2, ZZ) == False - assert dmp_sqf_p(f_1, 2, ZZ) == True - assert dmp_sqf_p(dmp_sqr(f_1, 2, ZZ), 2, ZZ) == False - assert dmp_sqf_p(f_2, 2, ZZ) == True - assert dmp_sqf_p(dmp_sqr(f_2, 2, ZZ), 2, ZZ) == False - assert dmp_sqf_p(f_3, 2, ZZ) == True - assert dmp_sqf_p(dmp_sqr(f_3, 2, ZZ), 2, ZZ) == False - assert dmp_sqf_p(f_5, 2, ZZ) == False - assert dmp_sqf_p(dmp_sqr(f_5, 2, ZZ), 2, ZZ) == False + assert R1.dup_sqf_part(f) == f + assert R2.dup_sqf_part(g) == y + 1 - assert dmp_sqf_p(f_4, 2, ZZ) == True - assert dmp_sqf_part(f_4, 2, ZZ) == dmp_neg(f_4, 2, ZZ) - assert dmp_sqf_p(f_6, 3, ZZ) == True - assert dmp_sqf_part(f_6, 3, ZZ) == f_6 + assert R1.dup_sqf_p(f) is True + assert R2.dup_sqf_p(g) is False - assert dmp_sqf_part(f_5, 2, ZZ) == [[[1]], [[1], [-1, 0]]] + R, x, y = ring("x,y", ZZ) - assert dup_sqf_list([], ZZ) == (ZZ(0), []) - assert dup_sqf_list_include([], ZZ) == [([], 1)] + A = x**4 - 3*x**2 + 6 + D = x**6 - 5*x**4 + 5*x**2 + 4 - assert dmp_sqf_list([[ZZ(3)]], 1, ZZ) == (ZZ(3), []) - assert dmp_sqf_list_include([[ZZ(3)]], 1, ZZ) == [([[ZZ(3)]], 1)] + f, g = D, R.dmp_sub(A, R.dmp_mul(R.dmp_diff(D, 1), y)) + res = R.dmp_resultant(f, g) + h = (4*y**2 + 1).drop(x) - f = [-1,1,0,0,1,-1] + assert R.drop(x).dup_sqf_list(res) == (45796, [(h, 3)]) - assert dmp_sqf_list(f, 0, ZZ) == \ - (-1, [([1,1,1,1], 1), ([1,-1], 2)]) - assert dmp_sqf_list_include(f, 0, ZZ) == \ - [([-1,-1,-1,-1], 1), ([1,-1], 2)] + R, x = ring("x", ZZ["t"]) + assert R.dup_sqf_list_include(DMP([1, 0, 0, 0], ZZ)*x**2) == \ + [(DMP([1, 0, 0, 0], ZZ), 1), (DMP([1], ZZ)*x, 2)] - f = [[-1],[1],[],[],[1],[-1]] - assert dmp_sqf_list(f, 1, ZZ) == \ - (-1, [([[1],[1],[1],[1]], 1), ([[1],[-1]], 2)]) - assert dmp_sqf_list_include(f, 1, ZZ) == \ - [([[-1],[-1],[-1],[-1]], 1), ([[1],[-1]], 2)] +def test_dmp_sqf(): + R, x, y = ring("x,y", ZZ) + assert R.dmp_sqf_part(0) == 0 + assert R.dmp_sqf_p(0) is True + + assert R.dmp_sqf_part(7) == 1 + assert R.dmp_sqf_p(7) is True + + assert R.dmp_sqf_list(3) == (3, []) + assert R.dmp_sqf_list_include(3) == [(3, 1)] + + R, x, y, z = ring("x,y,z", ZZ) + assert R.dmp_sqf_p(f_0) is True + assert R.dmp_sqf_p(f_0**2) is False + assert R.dmp_sqf_p(f_1) is True + assert R.dmp_sqf_p(f_1**2) is False + assert R.dmp_sqf_p(f_2) is True + assert R.dmp_sqf_p(f_2**2) is False + assert R.dmp_sqf_p(f_3) is True + assert R.dmp_sqf_p(f_3**2) is False + assert R.dmp_sqf_p(f_5) is False + assert R.dmp_sqf_p(f_5**2) is False + + assert R.dmp_sqf_p(f_4) is True + assert R.dmp_sqf_part(f_4) == -f_4 + + assert R.dmp_sqf_part(f_5) == x + y - z + + R, x, y, z, t = ring("x,y,z,t", ZZ) + assert R.dmp_sqf_p(f_6) is True + assert R.dmp_sqf_part(f_6) == f_6 + + R, x = ring("x", ZZ) + f = -x**5 + x**4 + x - 1 + + assert R.dmp_sqf_list(f) == (-1, [(x**3 + x**2 + x + 1, 1), (x - 1, 2)]) + assert R.dmp_sqf_list_include(f) == [(-x**3 - x**2 - x - 1, 1), (x - 1, 2)] + + R, x, y = ring("x,y", ZZ) + f = -x**5 + x**4 + x - 1 - K = FF(2) + assert R.dmp_sqf_list(f) == (-1, [(x**3 + x**2 + x + 1, 1), (x - 1, 2)]) + assert R.dmp_sqf_list_include(f) == [(-x**3 - x**2 - x - 1, 1), (x - 1, 2)] - f = [[-1], [2], [-1]] + f = -x**2 + 2*x - 1 + assert R.dmp_sqf_list_include(f) == [(-1, 1), (x - 1, 2)] - assert dmp_sqf_list_include(f, 1, ZZ) == \ - [([[-1]], 1), ([[1], [-1]], 2)] + R, x, y = ring("x,y", FF(2)) + raises(NotImplementedError, lambda: R.dmp_sqf_list(y**2 + 1)) - raises(DomainError, lambda: dmp_sqf_list([[K(1), K(0), K(1)]], 1, K)) def test_dup_gff_list(): - f = [1, 2, -1, -2, 0, 0] - - assert dup_gff_list(f, ZZ) == [([1, 0], 1), ([1, 2], 4)] + R, x = ring("x", ZZ) - g = [1, -20, 166, -744, 1965, -3132, 2948, -1504, 320, 0] + f = x**5 + 2*x**4 - x**3 - 2*x**2 + assert R.dup_gff_list(f) == [(x, 1), (x + 2, 4)] - assert dup_gff_list(g, ZZ) == [([1, -5, 4], 1), ([1, -5, 4], 2), ([1, 0], 3)] + g = x**9 - 20*x**8 + 166*x**7 - 744*x**6 + 1965*x**5 - 3132*x**4 + 2948*x**3 - 1504*x**2 + 320*x + assert R.dup_gff_list(g) == [(x**2 - 5*x + 4, 1), (x**2 - 5*x + 4, 2), (x, 3)] - raises(ValueError, lambda: dup_gff_list([], ZZ)) + raises(ValueError, lambda: R.dup_gff_list(0)) diff -Nru python3-sympy-0.7.2/sympy/printing/__init__.py python3-sympy-0.7.3/sympy/printing/__init__.py --- python3-sympy-0.7.2/sympy/printing/__init__.py 2012-10-17 03:02:22.000000000 +0000 +++ python3-sympy-0.7.3/sympy/printing/__init__.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,13 +1,14 @@ """Printing subsystem""" -from .pretty import * +from .pretty import pager_print, pretty, pretty_print, pprint, \ + pprint_use_unicode, pprint_try_use_unicode from .latex import latex, print_latex from .mathml import mathml, print_mathml from .python import python, print_python from .ccode import ccode, print_ccode from .fcode import fcode, print_fcode from .jscode import jscode, print_jscode -from .gtk import * +from .gtk import print_gtk from .preview import preview from .repr import srepr from .tree import print_tree diff -Nru python3-sympy-0.7.2/sympy/printing/ccode.py python3-sympy-0.7.3/sympy/printing/ccode.py --- python3-sympy-0.7.2/sympy/printing/ccode.py 2012-10-17 03:02:22.000000000 +0000 +++ python3-sympy-0.7.3/sympy/printing/ccode.py 2013-07-13 17:53:32.000000000 +0000 @@ -12,14 +12,15 @@ from sympy.core import S, C from sympy.printing.codeprinter import CodePrinter from sympy.printing.precedence import precedence -from sympy.utilities.misc import default_sort_key +from sympy.core.compatibility import default_sort_key # dictionary mapping sympy function to (argument_conditions, C_function). # Used in CCodePrinter._print_Function(self) known_functions = { - "ceiling": [(lambda x: True, "ceil")], - "Abs": [(lambda x: not x.is_integer, "fabs")], - } + "ceiling": [(lambda x: True, "ceil")], + "Abs": [(lambda x: not x.is_integer, "fabs")], +} + class CCodePrinter(CodePrinter): """A printer to convert python expressions to strings of c code""" @@ -38,9 +39,9 @@ CodePrinter.__init__(self, settings) self.known_functions = dict(known_functions) userfuncs = settings.get('user_functions', {}) - for k,v in list(userfuncs.items()): - if not isinstance(v, tuple): - userfuncs[k] = (lambda *x: True, v) + for k, v in list(userfuncs.items()): + if not isinstance(v, list): + userfuncs[k] = [(lambda *x: True, v)] self.known_functions.update(userfuncs) def _rate_index_position(self, p): @@ -62,7 +63,7 @@ if isinstance(assign_to, str): assign_to = C.Symbol(assign_to) elif not isinstance(assign_to, (C.Basic, type(None))): - raise TypeError("CCodePrinter cannot assign to object of type %s"% + raise TypeError("CCodePrinter cannot assign to object of type %s" % type(assign_to)) # keep a set of expressions that are not strictly translatable to C @@ -76,7 +77,7 @@ for i, (e, c) in enumerate(expr.args): if i == 0: lines.append("if (%s) {" % self._print(c)) - elif i == len(expr.args)-1 and c == True: + elif i == len(expr.args) - 1 and c is True: lines.append("else {") else: lines.append("else if (%s) {" % self._print(c)) @@ -124,16 +125,16 @@ def _print_Pow(self, expr): PREC = precedence(expr) if expr.exp == -1: - return '1.0/%s'%(self.parenthesize(expr.base, PREC)) + return '1.0/%s' % (self.parenthesize(expr.base, PREC)) elif expr.exp == 0.5: return 'sqrt(%s)' % self._print(expr.base) else: - return 'pow(%s, %s)'%(self._print(expr.base), + return 'pow(%s, %s)' % (self._print(expr.base), self._print(expr.exp)) def _print_Rational(self, expr): p, q = int(expr.p), int(expr.q) - return '%d.0/%d.0' % (p, q) + return '%d.0L/%d.0L' % (p, q) def _print_Indexed(self, expr): # calculate index for 1d array @@ -161,17 +162,17 @@ def _print_Piecewise(self, expr): # This method is called only for inline if constructs # Top level piecewise is handled in doprint() - ecpairs = ["(%s) {\n%s\n}\n" % (self._print(c), self._print(e)) \ - for e, c in expr.args[:-1]] + 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 == True: - last_line = "else {\n%s\n}" % self._print(expr.args[-1].expr) + if expr.args[-1].cond is True: + last_line = ": (\n%s\n)" % self._print(expr.args[-1].expr) else: - ecpairs.append("(%s) {\n%s\n" % \ + ecpairs.append("(%s) ? (\n%s\n" % (self._print(expr.args[-1].cond), self._print(expr.args[-1].expr))) - code = "if %s" + last_line - return code % "else if ".join(ecpairs) + code = "%s" + last_line + return code % ": ".join(ecpairs) + " )" def _print_And(self, expr): PREC = precedence(expr) @@ -185,7 +186,7 @@ def _print_Not(self, expr): PREC = precedence(expr) - return '!'+self.parenthesize(expr.args[0], PREC) + return '!' + self.parenthesize(expr.args[0], PREC) def _print_Function(self, expr): if expr.func.__name__ in self.known_functions: @@ -212,7 +213,8 @@ code = [ line.lstrip(' \t') for line in code ] increase = [ int(any(map(line.endswith, inc_token))) for line in code ] - decrease = [ int(any(map(line.startswith, dec_token))) for line in code ] + decrease = [ int(any(map(line.startswith, dec_token))) + for line in code ] pretty = [] level = 0 @@ -238,7 +240,7 @@ the precision for numbers such as pi [default=15] user_functions : optional A dictionary where keys are FunctionClass instances and values - are there string representations. Alternatively, the + are their string representations. Alternatively, the dictionary value can be a list of tuples i.e. [(argument_test, cfunction_string)]. See below for examples. human : optional @@ -250,17 +252,25 @@ Examples ======== - >>> from sympy import ccode, symbols, Rational, sin + >>> from sympy import ccode, symbols, Rational, sin, ceiling, Abs >>> x, tau = symbols(["x", "tau"]) >>> ccode((2*tau)**Rational(7,2)) - '8*sqrt(2)*pow(tau, 7.0/2.0)' + '8*sqrt(2)*pow(tau, 7.0L/2.0L)' >>> ccode(sin(x), assign_to="s") 's = sin(x);' + >>> custom_functions = { + ... "ceiling": "CEIL", + ... "Abs": [(lambda x: not x.is_integer, "fabs"), + ... (lambda x: x.is_integer, "ABS")] + ... } + >>> ccode(Abs(x) + ceiling(x), user_functions=custom_functions) + 'fabs(x) + CEIL(x)' """ return CCodePrinter(settings).doprint(expr, assign_to) + def print_ccode(expr, **settings): """Prints C representation of the given expression.""" print(ccode(expr, **settings)) diff -Nru python3-sympy-0.7.2/sympy/printing/codeprinter.py python3-sympy-0.7.3/sympy/printing/codeprinter.py --- python3-sympy-0.7.2/sympy/printing/codeprinter.py 2012-10-17 03:02:22.000000000 +0000 +++ python3-sympy-0.7.3/sympy/printing/codeprinter.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,6 +1,8 @@ -from sympy.core import C, Add +from sympy.core import C, Add, Mul, Pow, S +from sympy.core.mul import _keep_coeff from sympy.printing.str import StrPrinter -from sympy.tensor import get_indices, get_contraction_structure +from sympy.printing.precedence import precedence + class AssignmentError(Exception): """ @@ -8,6 +10,7 @@ """ pass + class CodePrinter(StrPrinter): """ The base class for code-printing subclasses. @@ -27,6 +30,7 @@ openloop, closeloop = self._get_loop_opening_ending(indices) # Setup loops over dummy indices -- each term needs separate treatment + from sympy.tensor import get_contraction_structure d = get_contraction_structure(expr) # terms with no summations first @@ -47,7 +51,8 @@ # then terms with summations if isinstance(dummies, tuple): indices = self._sort_optimized(dummies, expr) - openloop_d, closeloop_d = self._get_loop_opening_ending(indices) + openloop_d, closeloop_d = self._get_loop_opening_ending( + indices) for term in d[dummies]: if term in d and not ([list(f.keys()) for f in d[term]] @@ -56,7 +61,7 @@ # contractions, those must be computed first. # (temporary variables?) raise NotImplementedError( - "FIXME: no support for contractions in factor yet") + "FIXME: no support for contractions in factor yet") else: # We need the lhs expression as an accumulator for @@ -71,13 +76,15 @@ # syntax is currently undefined. FIXME: What would be # a good interpretation? if assign_to is None: - raise AssignmentError("need assignment variable for loops") + raise AssignmentError( + "need assignment variable for loops") if term.has(assign_to): raise ValueError lines.extend(openloop) lines.extend(openloop_d) - text = "%s = %s" % (lhs_printed, CodePrinter.doprint(self, assign_to + term)) + text = "%s = %s" % (lhs_printed, CodePrinter.doprint( + self, assign_to + term)) lines.append(self._get_statement(text)) lines.extend(closeloop_d) lines.extend(closeloop) @@ -85,6 +92,7 @@ return lines def get_expression_indices(self, expr, assign_to): + from sympy.tensor import get_indices, get_contraction_structure rinds, junk = get_indices(expr) linds, junk = get_indices(assign_to) @@ -127,17 +135,61 @@ def _print_Dummy(self, expr): # dummies must be printed as unique symbols - return "%s_%i" %(expr.name, expr.dummy_index) # Dummy + return "%s_%i" % (expr.name, expr.dummy_index) # Dummy _print_Catalan = _print_NumberSymbol _print_EulerGamma = _print_NumberSymbol _print_GoldenRatio = _print_NumberSymbol + def _print_Mul(self, expr): + + prec = precedence(expr) + + c, e = expr.as_coeff_Mul() + if c < 0: + expr = _keep_coeff(-c, e) + sign = "-" + else: + sign = "" + + a = [] # items in the numerator + b = [] # items that are in the denominator (if any) + + if self.order not in ('old', 'none'): + args = expr.as_ordered_factors() + else: + # use make_args in case expr was something like -x -> x + args = Mul.make_args(expr) + + # Gather args for numerator/denominator + for item in args: + if item.is_commutative and item.is_Pow and item.exp.is_Rational and item.exp.is_negative: + if item.exp != -1: + b.append(Pow(item.base, -item.exp, evaluate=False)) + else: + b.append(Pow(item.base, -item.exp)) + else: + a.append(item) + + a = a or [S.One] + + a_str = [self.parenthesize(x, prec) for x in a] + b_str = [self.parenthesize(x, prec) for x in b] + + if len(b) == 0: + return sign + '*'.join(a_str) + elif len(b) == 1: + if len(a) == 1 and not (a[0].is_Atom or a[0].is_Add): + return sign + "%s/" % a_str[0] + '*'.join(b_str) + else: + return sign + '*'.join(a_str) + "/%s" % b_str[0] + else: + return sign + '*'.join(a_str) + "/(%s)" % '*'.join(b_str) + def _print_not_supported(self, expr): self._not_supported.add(expr) return self.emptyPrinter(expr) - # The following can not be simply translated into C or Fortran _print_Basic = _print_not_supported _print_ComplexInfinity = _print_not_supported diff -Nru python3-sympy-0.7.2/sympy/printing/conventions.py python3-sympy-0.7.3/sympy/printing/conventions.py --- python3-sympy-0.7.2/sympy/printing/conventions.py 2012-10-17 03:02:22.000000000 +0000 +++ python3-sympy-0.7.3/sympy/printing/conventions.py 2013-07-13 17:53:32.000000000 +0000 @@ -27,13 +27,15 @@ supers = [] subs = [] while pos < len(text): - start = pos+1 - if text[pos:pos+2] == "__": + start = pos + 1 + if text[pos:pos + 2] == "__": start += 1 pos_hat = text.find("^", start) - if pos_hat < 0: pos_hat = len(text) + if pos_hat < 0: + pos_hat = len(text) pos_usc = text.find("_", start) - if pos_usc < 0: pos_usc = len(text) + if pos_usc < 0: + pos_usc = len(text) pos_next = min(pos_hat, pos_usc) part = text[pos:pos_next] pos = pos_next @@ -56,3 +58,19 @@ subs.insert(0, sub) return name, supers, subs + +def requires_partial(expr): + """Return whether a partial derivative symbol is required for printing + + This requires checking how many free variables there are, + filtering out the ones that are integers. Some expressions don't have + free variables. In that case, check its variable list explicitly to + get the context of the expression. + """ + + ## checking for the attribute '__iter__' is Python 2.5 friendly. + ## For 2.6+, say isinstance(expr.free_symbols, collections.Iterable) + if not hasattr(expr.free_symbols, '__iter__'): + return len(set(expr.variables)) > 1 + + return sum(not s.is_integer for s in expr.free_symbols) > 1 diff -Nru python3-sympy-0.7.2/sympy/printing/defaults.py python3-sympy-0.7.3/sympy/printing/defaults.py --- python3-sympy-0.7.2/sympy/printing/defaults.py 1970-01-01 00:00:00.000000000 +0000 +++ python3-sympy-0.7.3/sympy/printing/defaults.py 2013-07-13 17:53:32.000000000 +0000 @@ -0,0 +1,18 @@ +class DefaultPrinting(object): + """ + The default implementation of printing for SymPy classes. + + This implements a hack that allows us to print elements of built-in + Python containers in a readable way. Natively Python uses ``repr()`` + even if ``str()`` was explicitly requested. Mix in this trait into + a class to get proper default printing. + + """ + + # Note, we always use the default ordering (lex) in __str__ and __repr__, + # regardless of the global setting. See issue 2388. + def __str__(self): + from sympy.printing.str import sstr + return sstr(self, order=None) + + __repr__ = __str__ diff -Nru python3-sympy-0.7.2/sympy/printing/dot.py python3-sympy-0.7.3/sympy/printing/dot.py --- python3-sympy-0.7.2/sympy/printing/dot.py 1970-01-01 00:00:00.000000000 +0000 +++ python3-sympy-0.7.3/sympy/printing/dot.py 2013-07-13 17:53:32.000000000 +0000 @@ -0,0 +1,201 @@ +from sympy import (Basic, Expr, Symbol, Integer, Rational, Float, + default_sort_key, Add, Mul) + +__all__ = ['dotprint'] + +default_styles = [(Basic, {'color': 'blue', 'shape': 'ellipse'}), + (Expr, {'color': 'black'})] + + +sort_classes = (Add, Mul) +slotClasses = (Symbol, Integer, Rational, Float) +# XXX: Why not just use srepr()? +def purestr(x): + """ A string that follows obj = type(obj)(*obj.args) exactly """ + if not isinstance(x, Basic): + return str(x) + if type(x) in slotClasses: + args = [getattr(x, slot) for slot in x.__slots__] + elif type(x) in sort_classes: + args = sorted(x.args, key=default_sort_key) + else: + args = x.args + return "%s(%s)"%(type(x).__name__, ', '.join(map(purestr, args))) + + +def styleof(expr, styles=default_styles): + """ Merge style dictionaries in order + + >>> from sympy import Symbol, Basic, Expr + >>> from sympy.printing.dot import styleof + >>> styles = [(Basic, {'color': 'blue', 'shape': 'ellipse'}), + ... (Expr, {'color': 'black'})] + + >>> styleof(Basic(1), styles) + {'color': 'blue', 'shape': 'ellipse'} + + >>> x = Symbol('x') + >>> styleof(x + 1, styles) # this is an Expr + {'color': 'black', 'shape': 'ellipse'} + """ + style = dict() + for typ, sty in styles: + if isinstance(expr, typ): + style.update(sty) + return style + +def attrprint(d, delimiter=', '): + """ Print a dictionary of attributes + + >>> from sympy.printing.dot import attrprint + >>> print(attrprint({'color': 'blue', 'shape': 'ellipse'})) + "color"="blue", "shape"="ellipse" + """ + return delimiter.join('"%s"="%s"'%item for item in sorted(d.items())) + +def dotnode(expr, styles=default_styles, labelfunc=str, pos=(), repeat=True): + """ String defining a node + + >>> from sympy.printing.dot import dotnode + >>> from sympy.abc import x + >>> print(dotnode(x)) + "Symbol(x)_()" ["color"="black", "label"="x", "shape"="ellipse"]; + """ + style = styleof(expr, styles) + + if isinstance(expr, Basic) and not expr.is_Atom: + label = str(expr.__class__.__name__) + else: + label = labelfunc(expr) + style['label'] = label + expr_str = purestr(expr) + if repeat: + expr_str += '_%s' % str(pos) + return '"%s" [%s];' % (expr_str, attrprint(style)) + + +def dotedges(expr, atom=lambda x: not isinstance(x, Basic), pos=(), repeat=True): + """ List of strings for all expr->expr.arg pairs + + See the docstring of dotprint for explanations of the options. + + >>> from sympy.printing.dot import dotedges + >>> from sympy.abc import x + >>> for e in dotedges(x+2): + ... print(e) + "Add(Integer(2), Symbol(x))_()" -> "Integer(2)_(0,)"; + "Add(Integer(2), Symbol(x))_()" -> "Symbol(x)_(1,)"; + """ + if atom(expr): + return [] + else: + # TODO: This is quadratic in complexity (purestr(expr) already + # contains [purestr(arg) for arg in expr.args]). + expr_str = purestr(expr) + arg_strs = [purestr(arg) for arg in expr.args] + if repeat: + expr_str += '_%s' % str(pos) + arg_strs = [arg_str + '_%s' % str(pos + (i,)) for i, arg_str in enumerate(arg_strs)] + return ['"%s" -> "%s";'%(expr_str, arg_str) for arg_str in arg_strs] + +template = \ +"""digraph{ + +# Graph style +%(graphstyle)s + +######### +# Nodes # +######### + +%(nodes)s + +######### +# Edges # +######### + +%(edges)s +}""" + +graphstyle = {'rankdir': 'TD', 'ordering': 'out'} + +def dotprint(expr, styles=default_styles, atom=lambda x: not isinstance(x, + Basic), maxdepth=None, repeat=True, labelfunc=str, **kwargs): + """ + DOT description of a SymPy expression tree + + Options are + + ``styles``: Styles for different classes. The default is:: + + [(Basic, {'color': 'blue', 'shape': 'ellipse'}), + (Expr, {'color': 'black'})]`` + + ``atom``: Function used to determine if an arg is an atom. The default is + ``lambda x: not isinstance(x, Basic)``. Another good choice is + ``lambda x: not x.args``. + + ``maxdepth``: The maximum depth. The default is None, meaning no limit. + + ``repeat``: Whether to different nodes for separate common subexpressions. + The default is True. For example, for ``x + x*y`` with + ``repeat=True``, it will have two nodes for ``x`` and with + ``repeat=False``, it will have one (warning: even if it appears + twice in the same object, like Pow(x, x), it will still only appear + only once. Hence, with repeat=False, the number of arrows out of an + object might not equal the number of args it has). + + ``labelfunc``: How to label leaf nodes. The default is ``str``. Another + good option is ``srepr``. For example with ``str``, the leaf nodes + of ``x + 1`` are labeled, ``x`` and ``1``. With ``srepr``, they + are labeled ``Symbol('x')`` and ``Integer(1)``. + + Additional keyword arguments are included as styles for the graph. + + Examples + ======== + + >>> from sympy.printing.dot import dotprint + >>> from sympy.abc import x + >>> print(dotprint(x+2)) # doctest: +NORMALIZE_WHITESPACE + digraph{ + + # Graph style + "ordering"="out" + "rankdir"="TD" + + ######### + # Nodes # + ######### + + "Add(Integer(2), Symbol(x))_()" ["color"="black", "label"="Add", "shape"="ellipse"]; + "Integer(2)_(0,)" ["color"="black", "label"="2", "shape"="ellipse"]; + "Symbol(x)_(1,)" ["color"="black", "label"="x", "shape"="ellipse"]; + + ######### + # Edges # + ######### + + "Add(Integer(2), Symbol(x))_()" -> "Integer(2)_(0,)"; + "Add(Integer(2), Symbol(x))_()" -> "Symbol(x)_(1,)"; + } + + """ + # repeat works by adding a signature tuple to the end of each node for its + # position in the graph. For example, for expr = Add(x, Pow(x, 2)), the x in the + # Pow will have the tuple (1, 0), meaning it is expr.args[1].args[0]. + graphstyle.update(kwargs) + + nodes = [] + edges = [] + def traverse(e, depth, pos=()): + nodes.append(dotnode(e, styles, labelfunc=labelfunc, pos=pos, repeat=repeat)) + if maxdepth and depth >= maxdepth: + return + edges.extend(dotedges(e, atom=atom, pos=pos, repeat=repeat)) + [traverse(arg, depth+1, pos + (i,)) for i, arg in enumerate(e.args) if not atom(arg)] + traverse(expr, 0) + + return template%{'graphstyle': attrprint(graphstyle, delimiter='\n'), + 'nodes': '\n'.join(nodes), + 'edges': '\n'.join(edges)} diff -Nru python3-sympy-0.7.2/sympy/printing/fcode.py python3-sympy-0.7.3/sympy/printing/fcode.py --- python3-sympy-0.7.2/sympy/printing/fcode.py 2012-10-17 03:02:22.000000000 +0000 +++ python3-sympy-0.7.3/sympy/printing/fcode.py 2013-07-13 17:53:32.000000000 +0000 @@ -18,17 +18,9 @@ """ -from sympy.core import S, C, Add, Float +from sympy.core import S, C, Add, N from sympy.printing.codeprinter import CodePrinter from sympy.printing.precedence import precedence -from sympy.functions import sin, cos, tan, asin, acos, atan, atan2, sinh, \ - cosh, tanh, sqrt, log, exp, Abs, sign, conjugate, Piecewise - -implicit_functions = set([ - sin, cos, tan, asin, acos, atan, atan2, sinh, cosh, tanh, sqrt, log, exp, - Abs, sign, conjugate -]) - class FCodePrinter(CodePrinter): """A printer to convert sympy expressions to strings of Fortran code""" @@ -43,6 +35,12 @@ 'human': True, 'source_format': 'fixed', } + + _implicit_functions = set([ + "sin", "cos", "tan", "asin", "acos", "atan", "atan2", "sinh", + "cosh", "tanh", "sqrt", "log", "exp", "erf", "Abs", "sign", "conjugate", + ]) + def __init__(self, settings=None): CodePrinter.__init__(self, settings) self._init_leading_padding() @@ -50,7 +48,7 @@ if isinstance(assign_to, str): self._settings['assign_to'] = C.Symbol(assign_to) elif not isinstance(assign_to, (C.Basic, type(None))): - raise TypeError("FCodePrinter cannot assign to object of type %s"% + raise TypeError("FCodePrinter cannot assign to object of type %s" % type(assign_to)) def _rate_index_position(self, p): @@ -76,8 +74,9 @@ self._lead_comment = "! " else: raise ValueError( - "Unknown source format: %s" % self._settings['source_format'] - ) + "Unknown source format: %s" % self._settings[ + 'source_format'] + ) def _pad_leading_columns(self, lines): result = [] @@ -96,12 +95,11 @@ for i in indices: # fortran arrays start at 1 and end at dimension var, start, stop = list(map(self._print, - [i.label, i.lower+1, i.upper+1])) + [i.label, i.lower + 1, i.upper + 1])) open_lines.append("do %s = %s, %s" % (var, start, stop)) close_lines.append("end do") return open_lines, close_lines - def doprint(self, expr): """Returns Fortran code for expr (as a string)""" # find all number symbols @@ -111,21 +109,23 @@ # Fortran. self._not_supported = set() - lines = [] + from sympy.functions import Piecewise if isinstance(expr, Piecewise): # support for top-level Piecewise function for i, (e, c) in enumerate(expr.args): if i == 0: lines.append("if (%s) then" % self._print(c)) - elif i == len(expr.args)-1 and c == True: + elif i == len(expr.args) - 1 and c is True: lines.append("else") else: lines.append("else if (%s) then" % self._print(c)) - lines.extend(self._doprint_a_piece(e, self._settings['assign_to'])) + lines.extend( + self._doprint_a_piece(e, self._settings['assign_to'])) lines.append("end if") else: - lines.extend(self._doprint_a_piece(expr, self._settings['assign_to'])) + lines.extend( + self._doprint_a_piece(expr, self._settings['assign_to'])) # format the output if self._settings["human"]: @@ -144,7 +144,8 @@ else: lines = self.indent_code(lines) lines = self._wrap_fortran(lines) - result = self._number_symbols, self._not_supported, "\n".join(lines) + result = self._number_symbols, self._not_supported, "\n".join( + lines) del self._not_supported del self._number_symbols @@ -191,7 +192,9 @@ def _print_Function(self, expr): name = self._settings["user_functions"].get(expr.__class__) + eargs = expr.args if name is None: + from sympy.functions import conjugate if expr.func == conjugate: name = "conjg" else: @@ -199,10 +202,13 @@ if hasattr(expr, '_imp_') and isinstance(expr._imp_, C.Lambda): # inlined function. # the expression is printed with _print to avoid loops - return self._print(expr._imp_(*expr.args)) - if expr.func not in implicit_functions: + return self._print(expr._imp_(*eargs)) + if expr.func.__name__ not in self._implicit_functions: self._not_supported.add(expr) - return "%s(%s)" % (name, self.stringify(expr.args, ", ")) + else: + # convert all args to floats + eargs = list(map(N, eargs)) + return "%s(%s)" % (name, self.stringify(eargs, ", ")) _print_factorial = _print_Function @@ -228,7 +234,7 @@ def _print_Pow(self, expr): PREC = precedence(expr) if expr.exp == -1: - return '1.0/%s'%(self.parenthesize(expr.base, PREC)) + return '1.0/%s' % (self.parenthesize(expr.base, PREC)) elif expr.exp == 0.5: if expr.base.is_integer: # Fortan intrinsic sqrt() does not accept integer argument @@ -249,7 +255,7 @@ printed = CodePrinter._print_Float(self, expr) e = printed.find('e') if e > -1: - return "%sd%s" % (printed[:e], printed[e+1:]) + return "%sd%s" % (printed[:e], printed[e + 1:]) return "%sd0" % printed def _print_Indexed(self, expr): @@ -271,15 +277,16 @@ # routine to find split point in a code line my_alnum = set("_+-.0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_") my_white = set(" \t()") + def split_pos_code(line, endpos): if len(line) <= endpos: return len(line) pos = endpos split = lambda pos: \ - (line[pos] in my_alnum and line[pos-1] not in my_alnum) or \ - (line[pos] not in my_alnum and line[pos-1] in my_alnum) or \ - (line[pos] in my_white and line[pos-1] not in my_white) or \ - (line[pos] not in my_white and line[pos-1] in my_white) + (line[pos] in my_alnum and line[pos - 1] not in my_alnum) or \ + (line[pos] not in my_alnum and line[pos - 1] in my_alnum) or \ + (line[pos] in my_white and line[pos - 1] not in my_white) or \ + (line[pos] not in my_white and line[pos - 1] in my_white) while not split(pos): pos -= 1 if pos == 0: @@ -315,13 +322,15 @@ pos = split_pos_code(line, 72) hunk = line[:pos].rstrip() line = line[pos:].lstrip() - if line: hunk += trailing + if line: + hunk += trailing result.append(hunk) while len(line) > 0: pos = split_pos_code(line, 65) hunk = line[:pos].rstrip() line = line[pos:].lstrip() - if line: hunk += trailing + if line: + hunk += trailing result.append("%s%s" % (self._lead_cont, hunk)) else: result.append(line) @@ -339,9 +348,12 @@ inc_keyword = ('do ', 'if(', 'if ', 'do\n', 'else') dec_keyword = ('end do', 'enddo', 'end if', 'endif', 'else') - increase = [ int(any(map(line.startswith, inc_keyword))) for line in code ] - decrease = [ int(any(map(line.startswith, dec_keyword))) for line in code ] - continuation = [ int(any(map(line.endswith, ['&', '&\n']))) for line in code ] + increase = [ int(any(map(line.startswith, inc_keyword))) + for line in code ] + decrease = [ int(any(map(line.startswith, dec_keyword))) + for line in code ] + continuation = [ int(any(map(line.endswith, ['&', '&\n']))) + for line in code ] level = 0 cont_padding = 0 @@ -374,6 +386,7 @@ return self._wrap_fortran(new_code) return new_code + def fcode(expr, **settings): """Converts an expr to a string of Fortran 77 code diff -Nru python3-sympy-0.7.2/sympy/printing/gtk.py python3-sympy-0.7.3/sympy/printing/gtk.py --- python3-sympy-0.7.2/sympy/printing/gtk.py 2012-10-17 03:02:22.000000000 +0000 +++ python3-sympy-0.7.3/sympy/printing/gtk.py 2013-07-13 17:53:32.000000000 +0000 @@ -4,13 +4,14 @@ import tempfile import os + def print_gtk(x, start_viewer=True): """Print to Gtkmathview, a gtk widget capable of rendering MathML. Needs libgtkmathview-bin""" from sympy.utilities.mathml import c2p - tmp = tempfile.mktemp() # create a temp file to store the result + tmp = tempfile.mktemp() # create a temp file to store the result with open(tmp, 'wb') as file: file.write( c2p(mathml(x), simple=True) ) diff -Nru python3-sympy-0.7.2/sympy/printing/jscode.py python3-sympy-0.7.3/sympy/printing/jscode.py --- python3-sympy-0.7.2/sympy/printing/jscode.py 2012-10-17 03:02:22.000000000 +0000 +++ python3-sympy-0.7.3/sympy/printing/jscode.py 2013-07-13 17:53:32.000000000 +0000 @@ -10,27 +10,27 @@ from sympy.core import S, C from sympy.printing.codeprinter import CodePrinter from sympy.printing.precedence import precedence -from sympy.utilities.misc import default_sort_key +from sympy.core.compatibility import default_sort_key # dictionary mapping sympy function to (argument_conditions, Javascript_function). # Used in JavascriptCodePrinter._print_Function(self) known_functions = { - } +} function_translations = { - 'Abs': 'Math.abs', - 'acos': 'Math.acos', - 'asin': 'Math.asin', - 'atan': 'Math.atan', - 'ceiling': 'Math.ceil', - 'cos': 'Math.cos', - 'exp': 'Math.exp', - 'floor': 'Math.floor', - 'log': 'Math.log', - 'sin': 'Math.sin', - 'tan': 'Math.tan', - } + 'Abs': 'Math.abs', + 'acos': 'Math.acos', + 'asin': 'Math.asin', + 'atan': 'Math.atan', + 'ceiling': 'Math.ceil', + 'cos': 'Math.cos', + 'exp': 'Math.exp', + 'floor': 'Math.floor', + 'log': 'Math.log', + 'sin': 'Math.sin', + 'tan': 'Math.tan', +} class JavascriptCodePrinter(CodePrinter): @@ -67,8 +67,6 @@ def _get_statement(self, codestring): return "%s;" % codestring - - def doprint(self, expr, assign_to=None): """ Actually format the expression as Javascript code. @@ -77,7 +75,7 @@ if isinstance(assign_to, str): assign_to = C.Symbol(assign_to) elif not isinstance(assign_to, (C.Basic, type(None))): - raise TypeError("JavascriptCodePrinter cannot assign to object of type %s"% + raise TypeError("JavascriptCodePrinter cannot assign to object of type %s" % type(assign_to)) # keep a set of expressions that are not strictly translatable to Javascript @@ -91,7 +89,7 @@ for i, (e, c) in enumerate(expr.args): if i == 0: lines.append("if (%s) {" % self._print(c)) - elif i == len(expr.args)-1 and c == True: + elif i == len(expr.args) - 1 and c is True: lines.append("else {") else: lines.append("else if (%s) {" % self._print(c)) @@ -139,11 +137,11 @@ def _print_Pow(self, expr): PREC = precedence(expr) if expr.exp == -1: - return '1/%s'%(self.parenthesize(expr.base, PREC)) + return '1/%s' % (self.parenthesize(expr.base, PREC)) elif expr.exp == 0.5: return 'Math.sqrt(%s)' % self._print(expr.base) else: - return 'Math.pow(%s, %s)'%(self._print(expr.base), + return 'Math.pow(%s, %s)' % (self._print(expr.base), self._print(expr.exp)) def _print_Rational(self, expr): @@ -176,13 +174,13 @@ def _print_Piecewise(self, expr): # This method is called only for inline if constructs # Top level piecewise is handled in doprint() - ecpairs = ["(%s) {\n%s\n}\n" % (self._print(c), self._print(e)) \ - for e, c in expr.args[:-1]] + 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 == True: + if expr.args[-1].cond is True: last_line = "else {\n%s\n}" % self._print(expr.args[-1].expr) else: - ecpairs.append("(%s) {\n%s\n" % \ + ecpairs.append("(%s) {\n%s\n" % (self._print(expr.args[-1].cond), self._print(expr.args[-1].expr))) code = "if %s" + last_line @@ -200,7 +198,7 @@ def _print_Not(self, expr): PREC = precedence(expr) - return '!'+self.parenthesize(expr.args[0], PREC) + return '!' + self.parenthesize(expr.args[0], PREC) def _print_Function(self, expr): if expr.func.__name__ in self.known_functions: @@ -230,7 +228,8 @@ code = [ line.lstrip(' \t') for line in code ] increase = [ int(any(map(line.endswith, inc_token))) for line in code ] - decrease = [ int(any(map(line.startswith, dec_token))) for line in code ] + decrease = [ int(any(map(line.startswith, dec_token))) + for line in code ] pretty = [] level = 0 @@ -244,7 +243,6 @@ return pretty - def jscode(expr, assign_to=None, **settings): """Converts an expr to a string of javascript code @@ -279,6 +277,7 @@ """ return JavascriptCodePrinter(settings).doprint(expr, assign_to) + def print_jscode(expr, **settings): """Prints the Javascript representation of the given expression. diff -Nru python3-sympy-0.7.2/sympy/printing/lambdarepr.py python3-sympy-0.7.3/sympy/printing/lambdarepr.py --- python3-sympy-0.7.2/sympy/printing/lambdarepr.py 2012-10-17 03:02:22.000000000 +0000 +++ python3-sympy-0.7.3/sympy/printing/lambdarepr.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,22 +1,32 @@ from .str import StrPrinter from sympy.utilities import default_sort_key + def _find_first_symbol(expr): for atom in expr.atoms(): if atom.is_Symbol: return atom raise ValueError('expression must contain a Symbol: %r' % expr) + class LambdaPrinter(StrPrinter): """ This printer converts expressions into strings that can be used by lambdify. """ - def _print_Matrix(self, expr): - return "Matrix([%s])"%expr._format_str(self._print, ",") + def _print_MatrixBase(self, expr): + return "%s(%s)" % (expr.__class__.__name__, str(expr.tolist())) - _print_MutableMatrix = _print_Matrix + _print_SparseMatrix = \ + _print_MutableSparseMatrix = \ + _print_ImmutableSparseMatrix = \ + _print_Matrix = \ + _print_DenseMatrix = \ + _print_MutableDenseMatrix = \ + _print_ImmutableMatrix = \ + _print_ImmutableDenseMatrix = \ + _print_MatrixBase def _print_Piecewise(self, expr): from sympy.core.sets import Interval @@ -61,6 +71,7 @@ result = ['(', 'not (', self._print(expr.args[0]), '))'] return ''.join(result) + def lambdarepr(expr, **settings): """ Returns a string usable for lambdifying. diff -Nru python3-sympy-0.7.2/sympy/printing/latex.py python3-sympy-0.7.3/sympy/printing/latex.py --- python3-sympy-0.7.2/sympy/printing/latex.py 2012-10-17 03:02:22.000000000 +0000 +++ python3-sympy-0.7.3/sympy/printing/latex.py 2013-07-13 17:53:32.000000000 +0000 @@ -4,26 +4,54 @@ from sympy.core import S, C, Add, Symbol from sympy.core.function import _coeff_isneg -from .printer import Printer -from .conventions import split_super_sub -from sympy.simplify import fraction from sympy.core.sympify import SympifyError +from .printer import Printer +from .conventions import split_super_sub, requires_partial +from .precedence import precedence, PRECEDENCE + import sympy.mpmath.libmp as mlib from sympy.mpmath.libmp import prec_to_dps -from sympy.utilities.misc import default_sort_key +from sympy.core.compatibility import default_sort_key from sympy.utilities.iterables import has_variety -import re, warnings +import re # Hand-picked functions which can be used directly in both LaTeX and MathJax # Complete list at http://www.mathjax.org/docs/1.1/tex.html#supported-latex-commands # This variable only contains those functions which sympy uses. -accepted_latex_functions = ['arcsin','arccos','arctan','sin','cos','tan', - 'theta','beta','alpha','gamma','sinh','cosh','tanh','sqrt', - 'ln','log','sec','csc','cot','coth','re','im','frac','root', - 'arg','zeta','psi'] +accepted_latex_functions = ['arcsin', 'arccos', 'arctan', 'sin', 'cos', 'tan', + 'sinh', 'cosh', 'tanh', 'sqrt', + 'ln', 'log', 'sec', 'csc', 'cot', 'coth', 're', 'im', 'frac', 'root', + 'arg'] +## 'theta', 'beta', 'alpha', 'gamma', , 'zeta', 'psi'] +greeks = set(['alpha', 'beta', 'gamma', 'delta', 'epsilon', 'zeta', 'eta', + 'theta', 'iota', 'kappa', 'lambda', 'mu', 'nu', 'xi', 'omicron', + 'pi', 'rho', 'sigma', 'tau', 'upsilon', 'phi', 'chi', 'psi', + 'omega']) + +greek_dictionary = {'Alpha': 'A', + 'Beta': 'B', + 'Epsilon': 'E', + 'Zeta': 'Z', + 'Eta': 'H', + 'Iota': 'I', + 'Kappa': 'K', + 'Mu': 'M', + 'Nu': 'N', + 'omicron': 'o', + 'Omicron': 'O', + 'Rho': 'P', + 'Tau': 'T', + 'Chi': 'X', + 'lamda': r'\lambda', + 'Lamda': r'\Lambda', + } + +other_symbols = set(['aleph', 'beth', 'daleth', 'gimel', 'ell', 'eth', 'hbar', + 'hslash', 'mho', ]) + class LatexPrinter(Printer): printmethod = "_latex" @@ -34,6 +62,8 @@ "itex": False, "fold_frac_powers": False, "fold_func_brackets": False, + "fold_short_frac": None, + "long_frac_ratio": 2, "mul_symbol": None, "inv_trig_style": "abbreviated", "mat_str": "smallmatrix", @@ -49,23 +79,36 @@ Printer.__init__(self, settings) if 'mode' in self._settings: - valid_modes = ['inline', 'plain', 'equation', \ - 'equation*'] + valid_modes = ['inline', 'plain', 'equation', + 'equation*'] if self._settings['mode'] not in valid_modes: - raise ValueError("'mode' must be one of 'inline', 'plain', " \ + raise ValueError("'mode' must be one of 'inline', 'plain', " "'equation' or 'equation*'") + if self._settings['fold_short_frac'] is None and \ + self._settings['mode'] == 'inline': + self._settings['fold_short_frac'] = True + mul_symbol_table = { - None : r" ", - "ldot" : r" \,.\, ", - "dot" : r" \cdot ", - "times" : r" \times " + None: r" ", + "ldot": r" \,.\, ", + "dot": r" \cdot ", + "times": r" \times " } self._settings['mul_symbol_latex'] = \ mul_symbol_table[self._settings['mul_symbol']] - self._delim_dict = {'(':')','[':']'} + self._settings['mul_symbol_latex_numbers'] = \ + mul_symbol_table[self._settings['mul_symbol'] or 'dot'] + + self._delim_dict = {'(': ')', '[': ']'} + + def parenthesize(self, item, level): + if precedence(item) <= level: + return r"\left(%s\right)" % self._print(item) + else: + return self._print(item) def doprint(self, expr): tex = Printer.doprint(self, expr) @@ -112,6 +155,18 @@ else: return False + def _needs_mul_brackets(self, expr, last=False): + """ + Returns True if the expression needs to be wrapped in brackets when + printed as part of a Mul, False otherwise. This is True for Add, + but also for some container objects that would not need brackets + when appearing last in a Mul, e.g. an Integral. ``last=True`` + specifies that this expr is the last to appear in a Mul. + """ + from sympy import Integral, Piecewise, Product, Sum + return expr.is_Add or (not last and + any([expr.has(x) for x in (Integral, Piecewise, Product, Sum)])) + def _mul_is_clean(self, expr): for arg in expr.args: if arg.is_Function: @@ -127,6 +182,12 @@ else: return expr + def _print_bool(self, e): + return r"\mathrm{%s}" % e + + def _print_NoneType(self, e): + return r"\mathrm{%s}" % e + def _print_Add(self, expr, order=None): if self.order == 'none': terms = list(expr.args) @@ -136,9 +197,9 @@ for term in terms[1:]: if not _coeff_isneg(term): - tex += " +" - - tex += " " + self._print(term) + tex += " + " + self._print(term) + else: + tex += " - " + self._print(-term) return tex @@ -148,10 +209,8 @@ str_real = mlib.to_str(expr._mpf_, dps, strip_zeros=True) # Must always have a mul symbol (as 2.5 10^{20} just looks odd) - separator = r" \times " - - if self._settings['mul_symbol'] is not None: - separator = self._settings['mul_symbol_latex'] + # thus we use the number separator + separator = self._settings['mul_symbol_latex_numbers'] if 'e' in str_real: (mant, exp) = str_real.split('e') @@ -168,16 +227,18 @@ return str_real def _print_Mul(self, expr): - coeff, tail = expr.as_coeff_Mul() + coeff, _ = expr.as_coeff_Mul() if not coeff.is_negative: tex = "" else: - coeff = -coeff + expr = -expr tex = "- " - numer, denom = fraction(tail, exact=True) + from sympy.simplify import fraction + numer, denom = fraction(expr, exact=True) separator = self._settings['mul_symbol_latex'] + numbersep = self._settings['mul_symbol_latex_numbers'] def convert(expr): if not expr.is_Mul: @@ -190,20 +251,16 @@ else: args = expr.args - for term in args: - pretty = self._print(term) + for i, term in enumerate(args): + term_tex = self._print(term) - if term.is_Add: - term_tex = (r"\left(%s\right)" % pretty) - else: - term_tex = str(pretty) + if self._needs_mul_brackets(term, last=(i == len(args) - 1)): + term_tex = r"\left(%s\right)" % term_tex - # between two digits, \times must always be used, - # to avoid confusion - if separator == " " and \ - re.search("[0-9][} ]*$", last_term_tex) and \ + if re.search("[0-9][} ]*$", last_term_tex) and \ re.match("[{ ]*[-+0-9]", term_tex): - _tex += r" \times " + # between two numbers + _tex += numbersep elif _tex: _tex += separator @@ -212,43 +269,45 @@ return _tex if denom is S.One: - if numer.is_Add: - _tex = r"\left(%s\right)" % convert(numer) - else: - _tex = r"%s" % convert(numer) - - if coeff is not S.One: - tex += str(self._print(coeff)) - - # between two digits, \times must always be used, to avoid - # confusion - if separator == " " and re.search("[0-9][} ]*$", tex) and \ - re.match("[{ ]*[-+0-9]", _tex): - tex += r" \times " + _tex - else: - tex += separator + _tex - else: - tex += _tex - + tex += convert(numer) else: - if numer is S.One: - if coeff.is_Integer: - numer *= coeff.p - elif coeff.is_Rational: - if coeff.p != 1: - numer *= coeff.p - - denom *= coeff.q - elif coeff is not S.One: - tex += str(self._print(coeff)) + " " + snumer = convert(numer) + sdenom = convert(denom) + ldenom = len(sdenom.split()) + ratio = self._settings['long_frac_ratio'] + if self._settings['fold_short_frac'] \ + and ldenom <= 2 and not "^" in sdenom: + # handle short fractions + if self._needs_mul_brackets(numer, last=False): + tex += r"\left(%s\right) / %s" % (snumer, sdenom) + else: + tex += r"%s / %s" % (snumer, sdenom) + elif len(snumer.split()) > ratio*ldenom: + # handle long fractions + if self._needs_mul_brackets(numer, last=True): + tex += r"\frac{1}{%s}%s\left(%s\right)" \ + % (sdenom, separator, snumer) + elif numer.is_Mul: + # split a long numerator + a = S.One + b = S.One + for x in numer.args: + if self._needs_mul_brackets(x, last=False) or \ + len(convert(a*x).split()) > ratio*ldenom or \ + (b.is_commutative is x.is_commutative is False): + b *= x + else: + a *= x + if self._needs_mul_brackets(b, last=True): + tex += r"\frac{%s}{%s}%s\left(%s\right)" \ + % (convert(a), sdenom, separator, convert(b)) + else: + tex += r"\frac{%s}{%s}%s%s" \ + % (convert(a), sdenom, separator, convert(b)) + else: + tex += r"\frac{1}{%s}%s%s" % (sdenom, separator, snumer) else: - if coeff.is_Rational and coeff.p == 1: - denom *= coeff.q - elif coeff is not S.One: - tex += str(self._print(coeff)) + " " - - tex += r"\frac{%s}{%s}" % \ - (convert(numer), convert(denom)) + tex += r"\frac{%s}{%s}" % (snumer, sdenom) return tex @@ -261,23 +320,26 @@ if expq == 2: tex = r"\sqrt{%s}" % base elif self._settings['itex']: - tex = r"\root{%d}{%s}" % (expq,base) + tex = r"\root{%d}{%s}" % (expq, base) else: - tex = r"\sqrt[%d]{%s}" % (expq,base) + tex = r"\sqrt[%d]{%s}" % (expq, base) if expr.exp.is_negative: return r"\frac{1}{%s}" % tex else: return tex elif self._settings['fold_frac_powers'] \ - and expr.exp.is_Rational \ - and expr.exp.q != 1: + and expr.exp.is_Rational \ + and expr.exp.q != 1: base, p, q = self._print(expr.base), expr.exp.p, expr.exp.q + if expr.base.is_Function: + return self._print(expr.base, "%s/%s" % (p, q)) + if self._needs_brackets(expr.base): + return r"\left(%s\right)^{%s/%s}" % (base, p, q) return r"%s^{%s/%s}" % (base, p, q) - elif expr.exp.is_Rational and expr.exp.is_negative and expr.base.is_Function: + elif expr.exp.is_Rational and expr.exp.is_negative and expr.base.is_commutative: # Things like 1/x - return r"\frac{%s}{%s}" % \ - (1, self._print(C.Pow(expr.base, -expr.exp))) + return self._print_Mul(expr) else: if expr.base.is_Function: return self._print(expr.base, self._print(expr.exp)) @@ -340,10 +402,15 @@ def _print_Derivative(self, expr): dim = len(expr.variables) + if requires_partial(expr): + diff_symbol = r'\partial' + else: + diff_symbol = r'd' + if dim == 1: - tex = r"\frac{\partial}{\partial %s}" % \ - self._print(expr.variables[0]) + tex = r"\frac{%s}{%s %s}" % (diff_symbol, diff_symbol, + self._print(expr.variables[0])) else: multiplicity, i, tex = [], 1, "" current = expr.variables[0] @@ -359,11 +426,11 @@ for x, i in multiplicity: if i == 1: - tex += r"\partial %s" % self._print(x) + tex += r"%s %s" % (diff_symbol, self._print(x)) else: - tex += r"\partial^{%s} %s" % (i, self._print(x)) + tex += r"%s %s^{%s}" % (diff_symbol, self._print(x), i) - tex = r"\frac{\partial^{%s}}{%s} " % (dim, tex) + tex = r"\frac{%s^{%s}}{%s} " % (diff_symbol, dim, tex) if isinstance(expr.expr, C.AssocOp): return r"%s\left(%s\right)" % (tex, self._print(expr.expr)) @@ -375,7 +442,8 @@ latex_expr = self._print(expr) latex_old = (self._print(e) for e in old) latex_new = (self._print(e) for e in new) - latex_subs = r'\\ '.join(e[0] + '=' + e[1] for e in zip(latex_old, latex_new)) + latex_subs = r'\\ '.join( + e[0] + '=' + e[1] for e in zip(latex_old, latex_new)) return r'\left. %s \right|_{\substack{ %s }}' % (latex_expr, latex_subs) def _print_Integral(self, expr): @@ -385,8 +453,9 @@ if len(expr.limits) <= 4 and all(len(lim) == 1 for lim in expr.limits): # Use len(expr.limits)-1 so that syntax highlighters don't think # \" is an escaped quote - tex = r"\i" + "i"*(len(expr.limits)-1) + "nt" - symbols = [r"\, d%s" % self._print(symbol[0]) for symbol in expr.limits] + tex = r"\i" + "i"*(len(expr.limits) - 1) + "nt" + symbols = [r"\, d%s" % self._print(symbol[0]) + for symbol in expr.limits] else: for lim in reversed(expr.limits): @@ -394,8 +463,8 @@ tex += r"\int" if len(lim) > 1: - if self._settings['mode'] in ['equation','equation*'] \ - and not self._settings['itex']: + if self._settings['mode'] in ['equation', 'equation*'] \ + and not self._settings['itex']: tex += r"\limits" if len(lim) == 3: @@ -420,7 +489,36 @@ else: return r"%s %s" % (tex, self._print(e)) + def _hprint_Function(self, func): + ''' + Logic to decide how to render a function to latex + - if it is a recognized latex name, use the appropriate latex command + - if it is a single letter, just use that letter + - if it is a longer name, then put \operatorname{} around it and be + mindful of undercores in the name + ''' + func = translate(func) + + if func in accepted_latex_functions: + name = r"\%s" % func + elif len(func) == 1 or func.startswith('\\'): + name = func + else: + name = r"\operatorname{%s}" % func.replace("_", r"\_") + return name + def _print_Function(self, expr, exp=None): + ''' + Render functions to LaTeX, handling functions that LaTeX knows about + e.g., sin, cos, ... by using the proper LaTeX command (\sin, \cos, ...). + For single-letter function names, render them as regular LaTeX math + symbols. For multi-letter function names that LaTeX does not know + about, (e.g., Li, sech) use \operatorname{} so that the function name + is rendered in Roman font and LaTeX handles spacing properly. + + expr is the expression involving the function + exp is an exponent + ''' func = expr.func.__name__ if hasattr(self, '_print_' + func): @@ -434,8 +532,8 @@ inv_trig_power_case = False # If it is applicable to fold the argument brackets can_fold_brackets = self._settings['fold_func_brackets'] and \ - len(args) == 1 and \ - not self._needs_function_brackets(expr.args[0]) + len(args) == 1 and \ + not self._needs_function_brackets(expr.args[0]) inv_trig_table = ["asin", "acos", "atan", "acot"] @@ -459,17 +557,9 @@ else: name = r"\operatorname{%s}^{-1}" % func elif exp is not None: - if func in accepted_latex_functions: - name = r"\%s^{%s}" % (func,exp) - else: - # If the generic function name contains an underscore, handle it - name = r"\operatorname{%s}^{%s}" % (func.replace("_", r"\_"), exp) + name = r'%s^{%s}' % (self._hprint_Function(func), exp) else: - if func in accepted_latex_functions: - name = r"\%s" % func - else: - # If the generic function name contains an underscore, handle it - name = r"\operatorname{%s}" % func.replace("_", r"\_") + name = self._hprint_Function(func) if can_fold_brackets: if func in accepted_latex_functions: @@ -486,6 +576,12 @@ return name % ",".join(args) + def _print_UndefinedFunction(self, expr): + return self._hprint_Function(str(expr)) + + def _print_FunctionClass(self, expr): + return self._hprint_Function(str(expr)) + def _print_Lambda(self, expr): symbols, expr = expr.args @@ -502,12 +598,22 @@ def _print_Min(self, expr, exp=None): args = sorted(expr.args, key=default_sort_key) texargs = [r"%s" % self._print(symbol) for symbol in args] - return r"\min\left(%s\right)" % ", ".join(texargs) + tex = r"\min\left(%s\right)" % ", ".join(texargs) + + if exp is not None: + return r"%s^{%s}" % (tex, exp) + else: + return tex def _print_Max(self, expr, exp=None): args = sorted(expr.args, key=default_sort_key) texargs = [r"%s" % self._print(symbol) for symbol in args] - return r"\max\left(%s\right)" % ", ".join(texargs) + tex = r"\max\left(%s\right)" % ", ".join(texargs) + + if exp is not None: + return r"%s^{%s}" % (tex, exp) + else: + return tex def _print_floor(self, expr, exp=None): tex = r"\lfloor{%s}\rfloor" % self._print(expr.args[0]) @@ -526,12 +632,13 @@ return tex def _print_Abs(self, expr, exp=None): - tex = r"\lvert{%s}\rvert" % self._print(expr.args[0]) + tex = r"\left\lvert{%s}\right\rvert" % self._print(expr.args[0]) if exp is not None: return r"%s^{%s}" % (tex, exp) else: return tex + _print_Determinant = _print_Abs def _print_re(self, expr, exp=None): if self._needs_brackets(expr.args[0]): @@ -607,6 +714,45 @@ tex = r"e^{%s}" % self._print(expr.args[0]) return self._do_exponent(tex, exp) + def _print_elliptic_k(self, expr, exp=None): + tex = r"\left(%s\right)" % self._print(expr.args[0]) + if exp is not None: + return r"K^{%s}%s" % (exp, tex) + else: + return r"K%s" % tex + + def _print_elliptic_f(self, expr, exp=None): + tex = r"\left(%s\middle| %s\right)" % \ + (self._print(expr.args[0]), self._print(expr.args[1])) + if exp is not None: + return r"F^{%s}%s" % (exp, tex) + else: + return r"F%s" % tex + + def _print_elliptic_e(self, expr, exp=None): + if len(expr.args) == 2: + tex = r"\left(%s\middle| %s\right)" % \ + (self._print(expr.args[0]), self._print(expr.args[1])) + else: + tex = r"\left(%s\right)" % self._print(expr.args[0]) + if exp is not None: + return r"E^{%s}%s" % (exp, tex) + else: + return r"E%s" % tex + + def _print_elliptic_pi(self, expr, exp=None): + if len(expr.args) == 3: + tex = r"\left(%s; %s\middle| %s\right)" % \ + (self._print(expr.args[0]), self._print(expr.args[1]), \ + self._print(expr.args[2])) + else: + tex = r"\left(%s\middle| %s\right)" % \ + (self._print(expr.args[0]), self._print(expr.args[1])) + if exp is not None: + return r"\Pi^{%s}%s" % (exp, tex) + else: + return r"\Pi%s" % tex + def _print_gamma(self, expr, exp=None): tex = r"\left(%s\right)" % self._print(expr.args[0]) @@ -642,6 +788,18 @@ else: return r"\operatorname{E}_{%s}%s" % (nu, tex) + def _print_subfactorial(self, expr, exp=None): + x = expr.args[0] + if self._needs_brackets(x): + tex = r"!\left(%s\right)" % self._print(x) + else: + tex = "!" + self._print(x) + + if exp is not None: + return r"%s^{%s}" % (tex, exp) + else: + return tex + def _print_factorial(self, expr, exp=None): x = expr.args[0] if self._needs_brackets(x): @@ -756,7 +914,7 @@ def _print_hyper(self, expr, exp=None): tex = r"{{}_{%s}F_{%s}\left(\begin{matrix} %s \\ %s \end{matrix}" \ r"\middle| {%s} \right)}" % \ - (self._print(len(expr.ap)), self._print(len(expr.bq)), + (self._print(len(expr.ap)), self._print(len(expr.bq)), self._hprint_vec(expr.ap), self._hprint_vec(expr.bq), self._print(expr.argument)) @@ -767,7 +925,7 @@ def _print_meijerg(self, expr, exp=None): tex = r"{G_{%s, %s}^{%s, %s}\left(\begin{matrix} %s & %s \\" \ r"%s & %s \end{matrix} \middle| {%s} \right)}" % \ - (self._print(len(expr.ap)), self._print(len(expr.bq)), + (self._print(len(expr.ap)), self._print(len(expr.bq)), self._print(len(expr.bm)), self._print(len(expr.an)), self._hprint_vec(expr.an), self._hprint_vec(expr.aother), self._hprint_vec(expr.bm), self._hprint_vec(expr.bother), @@ -868,6 +1026,20 @@ tex = r"\left(" + tex + r"\right)^{%s}" % (self._print(exp)) return tex + def _print_Ynm(self, expr, exp=None): + n, m, theta, phi = list(map(self._print, expr.args)) + tex = r"Y_{%s}^{%s}\left(%s,%s\right)" % (n, m, theta, phi) + if exp is not None: + tex = r"\left(" + tex + r"\right)^{%s}" % (self._print(exp)) + return tex + + def _print_Znm(self, expr, exp=None): + n, m, theta, phi = list(map(self._print, expr.args)) + tex = r"Z_{%s}^{%s}\left(%s,%s\right)" % (n, m, theta, phi) + if exp is not None: + tex = r"\left(" + tex + r"\right)^{%s}" % (self._print(exp)) + return tex + def _print_Rational(self, expr): if expr.q != 1: sign = "" @@ -889,7 +1061,7 @@ return r"\tilde{\infty}" def _print_ImaginaryUnit(self, expr): - return r"\mathbf{\imath}" + return r"i" def _print_NaN(self, expr): return r"\bot" @@ -913,26 +1085,6 @@ name, supers, subs = split_super_sub(expr.name) - # translate name, supers and subs to tex keywords - greek = set([ 'alpha', 'beta', 'gamma', 'delta', 'epsilon', 'zeta', - 'eta', 'theta', 'iota', 'kappa', 'lambda', 'mu', 'nu', - 'xi', 'omicron', 'pi', 'rho', 'sigma', 'tau', 'upsilon', - 'phi', 'chi', 'psi', 'omega' ]) - - greek_translated = {'lamda': 'lambda', 'Lamda': 'Lambda'} - - other = set( ['aleph', 'beth', 'daleth', 'gimel', 'ell', 'eth', - 'hbar', 'hslash', 'mho' ]) - - def translate(s): - tmp = s.lower() - if tmp in greek or tmp in other: - return "\\" + s - if s in greek_translated: - return "\\" + greek_translated[s] - else: - return s - name = translate(name) supers = [translate(sup) for sup in supers] subs = [translate(sub) for sub in subs] @@ -944,6 +1096,8 @@ name += "_{%s}" % " ".join(subs) return name + _print_RandomSymbol = _print_Symbol + _print_MatrixSymbol = _print_Symbol def _print_Relational(self, expr): if self._settings['itex']: @@ -954,25 +1108,25 @@ lt = "<" charmap = { - "==" : "=", - ">" : gt, - "<" : lt, - ">=" : r"\geq", - "<=" : r"\leq", - "!=" : r"\neq", + "==": "=", + ">": gt, + "<": lt, + ">=": r"\geq", + "<=": r"\leq", + "!=": r"\neq", } return "%s %s %s" % (self._print(expr.lhs), charmap[expr.rel_op], self._print(expr.rhs)) def _print_Piecewise(self, expr): - ecpairs = [r"%s & \text{for}\: %s" % (self._print(e), self._print(c)) \ - for e, c in expr.args[:-1]] - if expr.args[-1].cond == True: - ecpairs.append(r"%s & \text{otherwise}" % \ - self._print(expr.args[-1].expr)) + ecpairs = [r"%s & \text{for}\: %s" % (self._print(e), self._print(c)) + for e, c in expr.args[:-1]] + if expr.args[-1].cond is True: + ecpairs.append(r"%s & \text{otherwise}" % + self._print(expr.args[-1].expr)) else: - ecpairs.append(r"%s & \text{for}\: %s" % \ + ecpairs.append(r"%s & \text{for}\: %s" % (self._print(expr.args[-1].expr), self._print(expr.args[-1].cond))) tex = r"\begin{cases} %s \end{cases}" @@ -981,10 +1135,10 @@ def _print_MatrixBase(self, expr): lines = [] - for line in range(expr.rows): # horrible, should be 'rows' - lines.append(" & ".join([ self._print(i) for i in expr[line,:] ])) + for line in range(expr.rows): # horrible, should be 'rows' + lines.append(" & ".join([ self._print(i) for i in expr[line, :] ])) - out_str = r'\begin{%MATSTR%}%s\end{%MATSTR%}' + out_str = r'\begin{%MATSTR%}{}%s\end{%MATSTR%}' out_str = out_str.replace('%MATSTR%', self._settings['mat_str']) if self._settings['mat_delim']: left_delim = self._settings['mat_delim'] @@ -993,30 +1147,74 @@ r'\right' + right_delim return out_str % r"\\".join(lines) _print_ImmutableMatrix = _print_MatrixBase - _print_MutableMatrix = _print_MatrixBase + _print_Matrix = _print_MatrixBase + + def _print_MatrixElement(self, expr): + return self._print(expr.parent) + '_{%s, %s}'%(expr.i, expr.j) + + def _print_MatrixSlice(self, expr): + def latexslice(x): + x = list(x) + if x[2] == 1: + del x[2] + if x[1] == x[0] + 1: + del x[1] + if x[0] == 0: + x[0] = '' + return ':'.join(map(self._print, x)) + return (self._print(expr.parent) + r'\left[' + + latexslice(expr.rowslice) + ', ' + + latexslice(expr.colslice) + r'\right]') def _print_BlockMatrix(self, expr): - return self._print(expr.mat) + return self._print(expr.blocks) def _print_Transpose(self, expr): mat = expr.arg - if mat.is_Add or mat.is_Mul: - return r"\left(%s\right)^T"%self._print(mat) + from sympy.matrices import MatrixSymbol + if not isinstance(mat, MatrixSymbol): + return r"\left(%s\right)^T" % self._print(mat) + else: + return "%s^T" % self._print(mat) + + def _print_Adjoint(self, expr): + mat = expr.arg + from sympy.matrices import MatrixSymbol + if not isinstance(mat, MatrixSymbol): + return r"\left(%s\right)^\dag" % self._print(mat) else: - return "%s^T"%self._print(mat) + return "%s^\dag" % self._print(mat) def _print_MatAdd(self, expr): - return self._print_Add(expr) + terms = list(expr.args) + tex = " + ".join(map(self._print, terms)) + return tex def _print_MatMul(self, expr): - return self._print_Mul(expr) + from sympy import Add, MatAdd, HadamardProduct + + def parens(x): + if isinstance(x, (Add, MatAdd, HadamardProduct)): + return r"\left(%s\right)" % self._print(x) + return self._print(x) + return ' '.join(map(parens, expr.args)) + + def _print_HadamardProduct(self, expr): + from sympy import Add, MatAdd, MatMul + + def parens(x): + if isinstance(x, (Add, MatAdd, MatMul)): + return r"\left(%s\right)" % self._print(x) + return self._print(x) + return ' \circ '.join(map(parens, expr.args)) def _print_MatPow(self, expr): base, exp = expr.base, expr.exp - if base.is_Add or base.is_Mul: - return r"\left(%s\right)^{%s}"%(self._print(base), self._print(exp)) + from sympy.matrices import MatrixSymbol + if not isinstance(base, MatrixSymbol): + return r"\left(%s\right)^{%s}" % (self._print(base), self._print(exp)) else: - return "%s^{%s}"%(self._print(base), self._print(exp)) + return "%s^{%s}" % (self._print(base), self._print(exp)) def _print_ZeroMatrix(self, Z): return r"\bold{0}" @@ -1048,23 +1246,52 @@ def _print_Dict(self, expr): return self._print_dict(expr) - def _print_DiracDelta(self, expr): + def _print_DiracDelta(self, expr, exp=None): if len(expr.args) == 1 or expr.args[1] == 0: tex = r"\delta\left(%s\right)" % self._print(expr.args[0]) else: - tex = r"\delta^{\left( %s \right)}\left( %s \right)" % (\ - self._print(expr.args[1]), self._print(expr.args[0])) + tex = r"\delta^{\left( %s \right)}\left( %s \right)" % ( + self._print(expr.args[1]), self._print(expr.args[0])) + if exp: + tex = r"\left(%s\right)^{%s}" % (tex, exp) + return tex + + def _print_Heaviside(self, expr, exp=None): + tex = r"\theta\left(%s\right)" % self._print(expr.args[0]) + if exp: + tex = r"\left(%s\right)^{%s}" % (tex, exp) + return tex + + def _print_KroneckerDelta(self, expr, exp=None): + i = self._print(expr.args[0]) + j = self._print(expr.args[1]) + if expr.args[0].is_Atom and expr.args[1].is_Atom: + tex = r'\delta_{%s %s}' % (i, j) + else: + tex = r'\delta_{%s, %s}' % (i, j) + if exp: + tex = r'\left(%s\right)^{%s}' % (tex, exp) + return tex + + def _print_LeviCivita(self, expr, exp=None): + indices = list(map(self._print, expr.args)) + if all([x.is_Atom for x in expr.args]): + tex = r'\varepsilon_{%s}' % " ".join(indices) + else: + tex = r'\varepsilon_{%s}' % ", ".join(indices) + if exp: + tex = r'\left(%s\right)^{%s}' % (tex, exp) return tex def _print_ProductSet(self, p): if len(p.sets) > 1 and not has_variety(p.sets): - return self._print(p.sets[0]) + "^%d"%len(p.sets) + return self._print(p.sets[0]) + "^%d" % len(p.sets) else: return r" \times ".join(self._print(set) for set in p.sets) def _print_RandomDomain(self, d): try: - return 'Domain: '+ self._print(d.as_boolean()) + return 'Domain: ' + self._print(d.as_boolean()) except: try: return ('Domain: ' + self._print(d.symbols) + ' in ' + @@ -1131,10 +1358,10 @@ return r"\mathbb{R}" def _print_TransformationSet(self, s): - return r"\left\{%s\; |\; %s \in %s\right\}"%( - self._print(s.lamda.expr), - ', '.join([self._print(var) for var in s.lamda.variables]), - self._print(s.base_set)) + return r"\left\{%s\; |\; %s \in %s\right\}" % ( + self._print(s.lamda.expr), + ', '.join([self._print(var) for var in s.lamda.variables]), + self._print(s.base_set)) def _print_FiniteField(self, expr): return r"\mathbb{F}_{%s}" % expr.mod @@ -1187,7 +1414,6 @@ else: return r"\operatorname{%s} {\left(%s, %d\right)}" % (cls, expr, index) - def _print_RootSum(self, expr): cls = expr.__class__.__name__ args = [self._print(expr.expr)] @@ -1200,6 +1426,61 @@ else: return r"\operatorname{%s} {\left(%s\right)}" % (cls, ", ".join(args)) + def _print_PolyElement(self, poly): + if not poly: + return self._print(poly.ring.domain.zero) + mul_sym = self._settings['mul_symbol_latex'] + prec_add = PRECEDENCE["Add"] + prec_atom = PRECEDENCE["Atom"] + ring = poly.ring + symbols = ring.symbols + ngens = ring.ngens + zm = ring.zero_monom + sexpvs = [] + expvs = list(poly.keys()) + expvs.sort(key=ring.order, reverse=True) + for expv in expvs: + coeff = poly[expv] + if ring.domain.is_positive(coeff): + sexpvs.append(' + ') + else: + sexpvs.append(' - ') + if ring.domain.is_negative(coeff): + coeff = -coeff + if coeff != 1 or expv == zm: + if expv == zm: + scoeff = self._print(coeff) + else: + scoeff = self.parenthesize(coeff, prec_add) + else: + scoeff = '' + sexpv = [] + for i in range(ngens): + exp = expv[i] + if not exp: + continue + symbol = self.parenthesize(symbols[i], prec_atom-1) + if exp != 1: + sexpv.append('{%s}^{%d}' % (symbol, exp)) + else: + sexpv.append('%s' % symbol) + if scoeff: + sexpv = [scoeff] + sexpv + sexpvs.append(mul_sym.join(sexpv)) + if sexpvs[0] in [" + ", " - "]: + head = sexpvs.pop(0) + if head == " - ": + sexpvs.insert(0, "-") + return "".join(sexpvs) + + def _print_FracElement(self, frac): + if frac.denom == 1: + return self._print(frac.numer) + else: + numer = self._print(frac.numer) + denom = self._print(frac.denom) + return r"\frac{%s}{%s}" % (numer, denom) + def _print_euler(self, expr): return r"E_{%s}" % self._print(expr.args[0]) @@ -1267,11 +1548,9 @@ morphism.domain, morphism.codomain, "id")) def _print_CompositeMorphism(self, morphism): - from sympy.categories import NamedMorphism - # All components of the morphism have names and it is thus # possible to build the name of the composite. - component_names_list = [self._print(Symbol(component.name)) for \ + component_names_list = [self._print(Symbol(component.name)) for component in morphism.components] component_names_list.reverse() component_names = "\\circ ".join(component_names_list) + ":" @@ -1318,15 +1597,15 @@ def _print_FreeModuleElement(self, m): # Print as row vector for convenience, for now. return r"\left[ %s \right]" % ",".join( - '{' + self._print(x) + '}' for x in m) + '{' + self._print(x) + '}' for x in m) def _print_SubModule(self, m): return r"\left< %s \right>" % ",".join( - '{' + self._print(x) + '}' for x in m.gens) + '{' + self._print(x) + '}' for x in m.gens) def _print_ModuleImplementedIdeal(self, m): return r"\left< %s \right>" % ",".join( - '{' + self._print(x) + '}' for [x] in m._module.gens) + '{' + self._print(x) + '}' for [x] in m._module.gens) def _print_QuotientRing(self, R): # TODO nicer fractions for few generators... @@ -1360,27 +1639,46 @@ field = diff._form_field if hasattr(field, '_coord_sys'): string = field._coord_sys._names[field._index] - return r'\mathbb{d}%s' % self._print(Symbol(string)) + return r'\mathrm{d}%s' % self._print(Symbol(string)) else: - return 'd(%s)'%self._print(field) + return 'd(%s)' % self._print(field) string = self._print(field) - return r'\mathbb{d}\left(%s\right)' % string + return r'\mathrm{d}\left(%s\right)' % string def _print_Tr(self, p): #Todo: Handle indices contents = self._print(p.args[0]) return r'\mbox{Tr}\left(%s\right)' % (contents) + def _print_totient(self, expr): + return r'\phi\left( %s \right)' % self._print(expr.args[0]) + + +def translate(s): + ''' + Given a description of a Greek letter or other special character, + return the appropriate latex + + let everything else pass as given + ''' + tex = greek_dictionary.get(s) + if tex: + return tex + elif s.lower() in greeks or s in other_symbols: + return "\\" + s + else: + return s + def latex(expr, **settings): r""" Convert the given expression to LaTeX representation. - >>> from sympy import latex, sin, asin, Matrix, Rational - >>> from sympy.abc import x, y, mu, tau + >>> from sympy import latex, pi, sin, asin, Integral, Matrix, Rational + >>> from sympy.abc import x, y, mu, r, tau - >>> latex((2*tau)**Rational(7,2)) - '8 \\sqrt{2} \\tau^{\\frac{7}{2}}' + >>> print(latex((2*tau)**Rational(7,2))) + 8 \sqrt{2} \tau^{\frac{7}{2}} order: Any of the supported monomial orderings (currently "lex", "grlex", or "grevlex"), "old", and "none". This parameter does nothing for Mul objects. @@ -1397,81 +1695,100 @@ 'amsmath' for 'equation*'), unless the 'itex' option is set. In the latter case, the ``$$ $$`` syntax is used. - >>> latex((2*mu)**Rational(7,2), mode='plain') - '8 \\sqrt{2} \\mu^{\\frac{7}{2}}' + >>> print(latex((2*mu)**Rational(7,2), mode='plain')) + 8 \sqrt{2} \mu^{\frac{7}{2}} - >>> latex((2*tau)**Rational(7,2), mode='inline') - '$8 \\sqrt{2} \\tau^{\\frac{7}{2}}$' + >>> print(latex((2*tau)**Rational(7,2), mode='inline')) + $8 \sqrt{2} \tau^{\frac{7}{2}}$ - >>> latex((2*mu)**Rational(7,2), mode='equation*') - '\\begin{equation*}8 \\sqrt{2} \\mu^{\\frac{7}{2}}\\end{equation*}' + >>> print(latex((2*mu)**Rational(7,2), mode='equation*')) + \begin{equation*}8 \sqrt{2} \mu^{\frac{7}{2}}\end{equation*} - >>> latex((2*mu)**Rational(7,2), mode='equation') - '\\begin{equation}8 \\sqrt{2} \\mu^{\\frac{7}{2}}\\end{equation}' + >>> print(latex((2*mu)**Rational(7,2), mode='equation')) + \begin{equation}8 \sqrt{2} \mu^{\frac{7}{2}}\end{equation} itex: Specifies if itex-specific syntax is used, including emitting ``$$ $$``. - >>> latex((2*mu)**Rational(7,2), mode='equation', itex=True) - '$$8 \\sqrt{2} \\mu^{\\frac{7}{2}}$$' + >>> print(latex((2*mu)**Rational(7,2), mode='equation', itex=True)) + $$8 \sqrt{2} \mu^{\frac{7}{2}}$$ fold_frac_powers: Emit "^{p/q}" instead of "^{\frac{p}{q}}" for fractional powers. - >>> latex((2*tau)**Rational(7,2), fold_frac_powers=True) - '8 \\sqrt{2} \\tau^{7/2}' + >>> print(latex((2*tau)**Rational(7,2), fold_frac_powers=True)) + 8 \sqrt{2} \tau^{7/2} fold_func_brackets: Fold function brackets where applicable. - >>> latex((2*tau)**sin(Rational(7,2))) - '\\left(2 \\tau\\right)^{\\sin{\\left (\\frac{7}{2} \\right )}}' - >>> latex((2*tau)**sin(Rational(7,2)), fold_func_brackets = True) - '\\left(2 \\tau\\right)^{\\sin {\\frac{7}{2}}}' + >>> print(latex((2*tau)**sin(Rational(7,2)))) + \left(2 \tau\right)^{\sin{\left (\frac{7}{2} \right )}} + >>> print(latex((2*tau)**sin(Rational(7,2)), fold_func_brackets = True)) + \left(2 \tau\right)^{\sin {\frac{7}{2}}} + + fold_short_frac: Emit "p / q" instead of "\frac{p}{q}" when the + denominator is simple enough (at most two terms and no powers). + The default value is `True` for inline mode, False otherwise. + + >>> print(latex(3*x**2/y)) + \frac{3 x^{2}}{y} + >>> print(latex(3*x**2/y, fold_short_frac=True)) + 3 x^{2} / y + + long_frac_ratio: The allowed ratio of the width of the numerator to the + width of the denominator before we start breaking off long fractions. + The default value is 2. + + >>> print(latex(Integral(r, r)/2/pi, long_frac_ratio=2)) + \frac{\int r\, dr}{2 \pi} + >>> print(latex(Integral(r, r)/2/pi, long_frac_ratio=0)) + \frac{1}{2 \pi} \int r\, dr mul_symbol: The symbol to use for multiplication. Can be one of None, "ldot", "dot", or "times". - >>> latex((2*tau)**sin(Rational(7,2)), mul_symbol="times") - '\\left(2 \\times \\tau\\right)^{\\sin{\\left (\\frac{7}{2} \\right )}}' + >>> print(latex((2*tau)**sin(Rational(7,2)), mul_symbol="times")) + \left(2 \times \tau\right)^{\sin{\left (\frac{7}{2} \right )}} inv_trig_style: How inverse trig functions should be displayed. Can be one of "abbreviated", "full", or "power". Defaults to "abbreviated". - >>> latex(asin(Rational(7,2))) - '\\operatorname{asin}{\\left (\\frac{7}{2} \\right )}' - >>> latex(asin(Rational(7,2)), inv_trig_style="full") - '\\arcsin{\\left (\\frac{7}{2} \\right )}' - >>> latex(asin(Rational(7,2)), inv_trig_style="power") - '\\sin^{-1}{\\left (\\frac{7}{2} \\right )}' + >>> print(latex(asin(Rational(7,2)))) + \operatorname{asin}{\left (\frac{7}{2} \right )} + >>> print(latex(asin(Rational(7,2)), inv_trig_style="full")) + \arcsin{\left (\frac{7}{2} \right )} + >>> print(latex(asin(Rational(7,2)), inv_trig_style="power")) + \sin^{-1}{\left (\frac{7}{2} \right )} mat_str: Which matrix environment string to emit. "smallmatrix", "bmatrix", etc. Defaults to "smallmatrix". - >>> latex(Matrix(2, 1, [x, y]), mat_str = "array") - '\\left[\\begin{array}x\\\\y\\end{array}\\right]' + >>> print(latex(Matrix(2, 1, [x, y]), mat_str = "array")) + \left[\begin{array}{}x\\y\end{array}\right] mat_delim: The delimiter to wrap around matrices. Can be one of "[", "(", or the empty string. Defaults to "[". - >>> latex(Matrix(2, 1, [x, y]), mat_delim="(") - '\\left(\\begin{smallmatrix}x\\\\y\\end{smallmatrix}\\right)' + >>> print(latex(Matrix(2, 1, [x, y]), mat_delim="(")) + \left(\begin{smallmatrix}{}x\\y\end{smallmatrix}\right) symbol_names: Dictionary of symbols and the custom strings they should be emitted as. - >>> latex(x**2, symbol_names={x:'x_i'}) - 'x_i^{2}' + >>> print(latex(x**2, symbol_names={x:'x_i'})) + x_i^{2} Besides all Basic based expressions, you can recursively convert Python containers (lists, tuples and dicts) and also SymPy matrices: - >>> latex([2/x, y], mode='inline') - '$\\begin{bmatrix}\\frac{2}{x}, & y\\end{bmatrix}$' + >>> print(latex([2/x, y], mode='inline')) + $\begin{bmatrix}2 / x, & y\end{bmatrix}$ """ return LatexPrinter(settings).doprint(expr) + def print_latex(expr, **settings): """Prints LaTeX representation of the given expression.""" print(latex(expr, **settings)) diff -Nru python3-sympy-0.7.2/sympy/printing/mathml.py python3-sympy-0.7.3/sympy/printing/mathml.py --- python3-sympy-0.7.2/sympy/printing/mathml.py 2012-10-17 03:02:22.000000000 +0000 +++ python3-sympy-0.7.3/sympy/printing/mathml.py 2013-07-13 17:53:32.000000000 +0000 @@ -4,9 +4,8 @@ from sympy import sympify, S, Mul from sympy.core.function import _coeff_isneg -from sympy.simplify import fraction from .printer import Printer -from .conventions import split_super_sub +from .conventions import split_super_sub, requires_partial class MathMLPrinter(Printer): @@ -86,6 +85,7 @@ x.appendChild(self._print_Mul(-expr)) return x + from sympy.simplify import fraction numer, denom = fraction(expr) if denom is not S.One: @@ -95,7 +95,7 @@ x.appendChild(self._print(denom)) return x - coeff, terms = expr.as_coeff_mul() + coeff, terms = expr.as_coeff_mul() if coeff is S.One and len(terms) == 1: # XXX since the negative coefficient has been handled, I don't # thing a coeff of 1 can remain @@ -124,7 +124,7 @@ x.appendChild(lastProcessed) x.appendChild(self._print(-arg)) #invert expression since this is now minused - lastProcessed = x; + lastProcessed = x if(arg == args[-1]): plusNodes.append(lastProcessed) else: @@ -145,7 +145,7 @@ for i in range(m.lines): x_r = self.dom.createElement('matrixrow') for j in range(m.cols): - x_r.appendChild(self._print(m[i,j])) + x_r.appendChild(self._print(m[i, j])) x.appendChild(x_r) return x @@ -181,20 +181,20 @@ x.appendChild(self._print(e.args[0])) return x - def _print_ImaginaryUnit(self,e): + def _print_ImaginaryUnit(self, e): return self.dom.createElement('imaginaryi') - def _print_EulerGamma(self,e): + def _print_EulerGamma(self, e): return self.dom.createElement('eulergamma') - def _print_GoldenRatio(self,e): + def _print_GoldenRatio(self, e): """We use unicode #x3c6 for Greek letter phi as defined here http://www.w3.org/2003/entities/2007doc/isogrk1.html""" x = self.dom.createElement('cn') x.appendChild(self.dom.createTextNode("\u03c6")) return x - def _print_Exp1(self,e): + def _print_Exp1(self, e): return self.dom.createElement('exponentiale') def _print_Pi(self, e): @@ -203,7 +203,7 @@ def _print_Infinity(self, e): return self.dom.createElement('infinity') - def _print_Negative_Infinity(self,e): + def _print_Negative_Infinity(self, e): x = self.dom.createElement('apply') x.appendChild(self.dom.createElement('minus')) x.appendChild(self.dom.createElement('infinity')) @@ -250,7 +250,7 @@ if len(items) > 1: mrow = self.dom.createElement('mml:mrow') for i, item in enumerate(items): - if i>0: + if i > 0: mo = self.dom.createElement('mml:mo') mo.appendChild(self.dom.createTextNode(" ")) mrow.appendChild(mo) @@ -266,31 +266,31 @@ # translate name, supers and subs to unicode characters # taken from http://www.w3.org/2003/entities/2007doc/isogrk1.html unitr = { - 'Alpha' : '\u0391', 'Beta' : '\u0392', - 'Gamma' : '\u0393', 'Delta' : '\u0394', - 'Epsilon' : '\u0395', 'Zeta' : '\u0396', - 'Eta' : '\u0397', 'Theta' : '\u0398', - 'Iota' : '\u0399', 'Kappa' : '\u039A', - 'Lambda' : '\u039B', 'Mu' : '\u039C', - 'Nu' : '\u039D', 'Xi' : '\u039E', - 'Omicron' : '\u039F', 'Pi' : '\u03A0', - 'Rho' : '\u03A1', 'Sigma' : '\u03A3', - 'Tau' : '\u03A4', 'Upsilon' : '\u03A5', - 'Phi' : '\u03A6', 'Chi' : '\u03A7', - 'Psi' : '\u03A8', 'Omega' : '\u03A9', - 'alpha' : '\u03B1', 'beta' : '\u03B2', - 'gamma' : '\u03B3', 'delta' : '\u03B4', - 'epsilon' : '\u03B5', 'zeta' : '\u03B6', - 'eta' : '\u03B7', 'theta' : '\u03B8', - 'iota' : '\u03B9', 'kappa' : '\u03BA', - 'lambda' : '\u03BB', 'mu' : '\u03BC', - 'nu' : '\u03BD', 'xi' : '\u03BE', - 'omicron' : '\u03BF', 'pi' : '\u03C0', - 'rho' : '\u03C1', 'varsigma' : '\u03C2', - 'sigma' : '\u03C3', 'tau' : '\u03C4', - 'upsilon' : '\u03C5', 'phi' : '\u03C6', - 'chi' : '\u03C7', 'psi' : '\u03C8', - 'omega' : '\u03C9', + 'Alpha': '\u0391', 'Beta': '\u0392', + 'Gamma': '\u0393', 'Delta': '\u0394', + 'Epsilon': '\u0395', 'Zeta': '\u0396', + 'Eta': '\u0397', 'Theta': '\u0398', + 'Iota': '\u0399', 'Kappa': '\u039A', + 'Lambda': '\u039B', 'Mu': '\u039C', + 'Nu': '\u039D', 'Xi': '\u039E', + 'Omicron': '\u039F', 'Pi': '\u03A0', + 'Rho': '\u03A1', 'Sigma': '\u03A3', + 'Tau': '\u03A4', 'Upsilon': '\u03A5', + 'Phi': '\u03A6', 'Chi': '\u03A7', + 'Psi': '\u03A8', 'Omega': '\u03A9', + 'alpha': '\u03B1', 'beta': '\u03B2', + 'gamma': '\u03B3', 'delta': '\u03B4', + 'epsilon': '\u03B5', 'zeta': '\u03B6', + 'eta': '\u03B7', 'theta': '\u03B8', + 'iota': '\u03B9', 'kappa': '\u03BA', + 'lambda': '\u03BB', 'mu': '\u03BC', + 'nu': '\u03BD', 'xi': '\u03BE', + 'omicron': '\u03BF', 'pi': '\u03C0', + 'rho': '\u03C1', 'varsigma': '\u03C2', + 'sigma': '\u03C3', 'tau': '\u03C4', + 'upsilon': '\u03C5', 'phi': '\u03C6', + 'chi': '\u03C7', 'psi': '\u03C8', + 'omega': '\u03C9', } def translate(s): @@ -356,7 +356,10 @@ def _print_Derivative(self, e): x = self.dom.createElement('apply') - x.appendChild(self.dom.createElement(self.mathml_tag(e))) + diff_symbol = self.mathml_tag(e) + if requires_partial(e): + diff_symbol = 'partialdiff' + x.appendChild(self.dom.createElement(diff_symbol)) x_1 = self.dom.createElement('bvar') for sym in e.variables: @@ -421,7 +424,7 @@ # indent = current indentation # addindent = indentation to add to higher levels # newl = newline string - writer.write(indent+"<" + self.tagName) + writer.write(indent + "<" + self.tagName) attrs = self._get_attributes() a_names = list(attrs.keys()) @@ -434,21 +437,22 @@ if self.childNodes: writer.write(">") if (len(self.childNodes) == 1 and - self.childNodes[0].nodeType == Node.TEXT_NODE): + self.childNodes[0].nodeType == Node.TEXT_NODE): self.childNodes[0].writexml(writer, '', '', '') else: writer.write(newl) for node in self.childNodes: - node.writexml(writer, indent+addindent, addindent, newl) + node.writexml( + writer, indent + addindent, addindent, newl) writer.write(indent) writer.write("%s" % (self.tagName, newl)) else: - writer.write("/>%s"%(newl)) + writer.write("/>%s" % (newl)) self._Element_writexml_old = Element.writexml Element.writexml = writexml def writexml(self, writer, indent="", addindent="", newl=""): - _write_data(writer, "%s%s%s"%(indent, self.data, newl)) + _write_data(writer, "%s%s%s" % (indent, self.data, newl)) self._Text_writexml_old = Text.writexml Text.writexml = writexml @@ -462,6 +466,7 @@ """Returns the MathML representation of expr""" return MathMLPrinter(settings).doprint(expr) + def print_mathml(expr, **settings): """ Prints a pretty representation of the MathML code for expr diff -Nru python3-sympy-0.7.2/sympy/printing/precedence.py python3-sympy-0.7.3/sympy/printing/precedence.py --- python3-sympy-0.7.2/sympy/printing/precedence.py 2012-10-17 03:02:22.000000000 +0000 +++ python3-sympy-0.7.3/sympy/printing/precedence.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,35 +1,37 @@ """A module providing information about the necessity of brackets""" -from sympy import S from sympy.core.function import _coeff_isneg # Default precedence values for some basic types PRECEDENCE = { - "Lambda":1, - "Relational":20, - "Or":20, - "And":30, - "Add":40, - "Mul":50, - "Pow":60, - "Not":100, - "Atom":1000 + "Lambda": 1, + "Relational": 20, + "Or": 20, + "And": 30, + "Add": 40, + "Mul": 50, + "Pow": 60, + "Not": 100, + "Atom": 1000 } # A dictionary assigning precedence values to certain classes. These values are # treated like they were inherited, so not every single class has to be named # here. PRECEDENCE_VALUES = { - "Or" : PRECEDENCE["Or"], - "And" : PRECEDENCE["And"], - "Add" : PRECEDENCE["Add"], - "Pow" : PRECEDENCE["Pow"], - "Relational" : PRECEDENCE["Relational"], - "Sub" : PRECEDENCE["Add"], + "Or": PRECEDENCE["Or"], + "And": PRECEDENCE["And"], + "Add": PRECEDENCE["Add"], + "Pow": PRECEDENCE["Pow"], + "Relational": PRECEDENCE["Relational"], + "Sub": PRECEDENCE["Add"], "Not": PRECEDENCE["Not"], "factorial": PRECEDENCE["Pow"], "factorial2": PRECEDENCE["Pow"], "NegativeInfinity": PRECEDENCE["Add"], + "MatAdd": PRECEDENCE["Add"], + "MatMul": PRECEDENCE["Mul"], + "HadamardProduct": PRECEDENCE["Mul"] } # Sometimes it's not enough to assign a fixed precedence value to a @@ -38,31 +40,55 @@ # precedence value. # Precedence functions + + def precedence_Mul(item): if _coeff_isneg(item): return PRECEDENCE["Add"] return PRECEDENCE["Mul"] + def precedence_Rational(item): if item.p < 0: return PRECEDENCE["Add"] return PRECEDENCE["Mul"] + def precedence_Integer(item): if item.p < 0: return PRECEDENCE["Add"] return PRECEDENCE["Atom"] + def precedence_Float(item): if item < 0: return PRECEDENCE["Add"] return PRECEDENCE["Atom"] + +def precedence_PolyElement(item): + if item.is_generator: + return PRECEDENCE["Atom"] + elif item.is_term: + return PRECEDENCE["Mul"] + else: + return PRECEDENCE["Add"] + + +def precedence_FracElement(item): + if item.denom == 1: + return precedence_PolyElement(item.numer) + else: + return PRECEDENCE["Mul"] + + PRECEDENCE_FUNCTIONS = { - "Integer" : precedence_Integer, - "Mul" : precedence_Mul, - "Rational" : precedence_Rational, + "Integer": precedence_Integer, + "Mul": precedence_Mul, + "Rational": precedence_Rational, "Float": precedence_Float, + "PolyElement": precedence_PolyElement, + "FracElement": precedence_FracElement, } diff -Nru python3-sympy-0.7.2/sympy/printing/pretty/pretty.py python3-sympy-0.7.3/sympy/printing/pretty/pretty.py --- python3-sympy-0.7.2/sympy/printing/pretty/pretty.py 2012-10-17 03:02:22.000000000 +0000 +++ python3-sympy-0.7.3/sympy/printing/pretty/pretty.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,4 +1,4 @@ -from sympy.core import S, C, Basic, Interval +from sympy.core import S, C from sympy.core.function import _coeff_isneg from sympy.utilities import group from sympy.utilities.iterables import has_variety @@ -6,11 +6,12 @@ from sympy.printing.printer import Printer from sympy.printing.str import sstr +from sympy.printing.conventions import requires_partial from .stringpict import prettyForm, stringPict -from .pretty_symbology import xstr, hobj, vobj, xobj, xsym, pretty_symbol,\ - pretty_atom, pretty_use_unicode, pretty_try_use_unicode, greek, U, \ - annotated +from .pretty_symbology import xstr, hobj, vobj, xobj, xsym, pretty_symbol, \ + pretty_atom, pretty_use_unicode, pretty_try_use_unicode, greek, U, \ + annotated from sympy.utilities import default_sort_key @@ -18,6 +19,7 @@ pprint_use_unicode = pretty_use_unicode pprint_try_use_unicode = pretty_try_use_unicode + class PrettyPrinter(Printer): """Printer, which converts an expression into 2D ASCII-art figure.""" printmethod = "_pretty" @@ -59,6 +61,7 @@ def _print_Symbol(self, e): symb = pretty_symbol(e.name) return prettyForm(symb) + _print_RandomSymbol = _print_Symbol def _print_Float(self, e): # we will use StrPrinter's Float printer, but we need to handle the @@ -76,12 +79,21 @@ return self.emptyPrinter(e) # Infinity inherits from Number, so we have to override _print_XXX order - _print_Infinity = _print_Atom + _print_Infinity = _print_Atom _print_NegativeInfinity = _print_Atom - _print_EmptySet = _print_Atom - _print_Naturals = _print_Atom - _print_Integers = _print_Atom - _print_Reals = _print_Atom + _print_EmptySet = _print_Atom + _print_Naturals = _print_Atom + _print_Integers = _print_Atom + _print_Reals = _print_Atom + + def _print_subfactorial(self, e): + x = e.args[0] + pform = self._print(x) + # Add parentheses if needed + if not ((x.is_Integer and x.is_nonnegative) or x.is_Symbol): + pform = prettyForm(*pform.parens()) + pform = prettyForm(*pform.left('!')) + return pform def _print_factorial(self, e): x = e.args[0] @@ -202,12 +214,13 @@ def _print_conjugate(self, e): pform = self._print(e.args[0]) - return prettyForm( *pform.above( hobj('_',pform.width())) ) + return prettyForm( *pform.above( hobj('_', pform.width())) ) def _print_Abs(self, e): pform = self._print(e.args[0]) pform = prettyForm(*pform.parens('|', '|')) return pform + _print_Determinant = _print_Abs def _print_floor(self, e): if self._use_unicode: @@ -226,13 +239,16 @@ return self._print_Function(e) def _print_Derivative(self, deriv): - # XXX use U('PARTIAL DIFFERENTIAL') here ? + if requires_partial(deriv) and self._use_unicode: + deriv_symbol = U('PARTIAL DIFFERENTIAL') + else: + deriv_symbol = r'd' syms = list(reversed(deriv.variables)) x = None for sym, num in group(syms, multiple=False): s = self._print(sym) - ds = prettyForm(*s.left('d')) + ds = prettyForm(*s.left(deriv_symbol)) if num > 1: ds = ds**prettyForm(str(num)) @@ -243,9 +259,10 @@ x = prettyForm(*x.right(' ')) x = prettyForm(*x.right(ds)) - f = prettyForm(binding=prettyForm.FUNC, *self._print(deriv.expr).parens()) + f = prettyForm( + binding=prettyForm.FUNC, *self._print(deriv.expr).parens()) - pform = prettyForm('d') + pform = prettyForm(deriv_symbol) if len(syms) > 1: pform = pform**prettyForm(str(len(syms))) @@ -253,6 +270,7 @@ pform = prettyForm(*pform.below(stringPict.LINE, x)) pform.baseline = pform.baseline + 1 pform = prettyForm(*stringPict.next(pform, f)) + pform.binding = prettyForm.MUL return pform @@ -278,7 +296,7 @@ return pform def _print_Integral(self, integral): - f = integral.function + f = integral.function # Add parentheses if arg involves addition of terms and # create a pretty form for the argument @@ -297,7 +315,6 @@ arg = prettyForm(*arg.right(' d', prettyArg)) - # \int \int \int ... firstterm = True s = None @@ -305,20 +322,20 @@ x = lim[0] # Create bar based on the height of the argument h = arg.height() - H = h+2 + H = h + 2 # XXX hack! ascii_mode = not self._use_unicode if ascii_mode: H += 2 - vint= vobj('int', H) + vint = vobj('int', H) # Construct the pretty form with the integral sign and the argument pform = prettyForm(vint) #pform.baseline = pform.height()//2 # vcenter - pform.baseline = arg.baseline + (H-h)//2 # covering the whole argument - + pform.baseline = arg.baseline + ( + H - h)//2 # covering the whole argument if len(lim) > 1: # Create pretty forms for endpoints, if definite integral. @@ -357,6 +374,7 @@ s = prettyForm(*s.left(pform)) pform = prettyForm(*arg.left(s)) + pform.binding = prettyForm.MUL return pform def _print_Product(self, expr): @@ -381,9 +399,9 @@ for lim in expr.limits: width = (func_height + 2) * 5 // 3 - 2 sign_lines = [] - sign_lines.append(corner_chr+(horizontal_chr*width)+corner_chr) - for i in range(func_height+1): - sign_lines.append(vertical_chr+(' '*width)+vertical_chr) + sign_lines.append(corner_chr + (horizontal_chr*width) + corner_chr) + for i in range(func_height + 1): + sign_lines.append(vertical_chr + (' '*width) + vertical_chr) pretty_sign = stringPict('') pretty_sign = prettyForm(*pretty_sign.stack(*sign_lines)) @@ -405,7 +423,7 @@ height = pretty_sign.height() padding = stringPict('') - padding = prettyForm(*padding.stack(*[' ']*(height-1))) + padding = prettyForm(*padding.stack(*[' ']*(height - 1))) pretty_sign = prettyForm(*pretty_sign.right(padding)) pretty_func = prettyForm(*pretty_sign.right(pretty_func)) @@ -413,6 +431,7 @@ #pretty_func.baseline = 0 pretty_func.baseline = max_upper + sign_height//2 + pretty_func.binding = prettyForm.MUL return pretty_func def _print_Sum(self, expr): @@ -420,7 +439,7 @@ def asum(hrequired, lower, upper, use_ascii): def adjust(s, wid=None, how='<^>'): - if not wid or len(s)>wid: + if not wid or len(s) > wid: return s need = wid - len(s) if how == '<^>' or how == "<" or how not in list('<^>'): @@ -433,7 +452,6 @@ h = max(hrequired, 2) d = h//2 - wrequired = max(lower, upper) w = d + 1 more = hrequired % 2 @@ -465,7 +483,7 @@ prettyF = self._print(f) - if f.is_Add: # add parens + if f.is_Add: # add parens prettyF = prettyForm(*prettyF.parens()) H = prettyF.height() + 2 @@ -489,7 +507,8 @@ max_upper = max(max_upper, prettyUpper.height()) # Create sum sign based on the height of the argument - d, h, slines, adjustment = asum(H, prettyLower.width(), prettyUpper.width(), ascii_mode) + d, h, slines, adjustment = asum( + H, prettyLower.width(), prettyUpper.width(), ascii_mode) prettySign = stringPict('') prettySign = prettyForm(*prettySign.stack(*slines)) @@ -513,22 +532,22 @@ prettyF = prettyForm(*prettySign.right(prettyF)) prettyF.baseline = max_upper + sign_height//2 + prettyF.binding = prettyForm.MUL return prettyF def _print_Limit(self, l): # XXX we do not print dir ... e, z, z0, dir = l.args - E = self._print(e) - Lim = prettyForm('lim') - - LimArg = self._print(z) - LimArg = prettyForm(*LimArg.right('->')) - LimArg = prettyForm(*LimArg.right(self._print(z0))) + E = self._print(e) + Lim = prettyForm('lim') - Lim = prettyForm(*Lim.below(LimArg)) - Lim = prettyForm(*Lim.right(E)) + LimArg = self._print(z) + LimArg = prettyForm(*LimArg.right('->')) + LimArg = prettyForm(*LimArg.right(self._print(z0))) + Lim = prettyForm(*Lim.below(LimArg)) + Lim = prettyForm(*Lim.right(E)) return Lim @@ -540,7 +559,7 @@ Ms = {} # i,j -> pretty(M[i,j]) for i in range(M.rows): for j in range(M.cols): - Ms[i,j] = self._print(M[i,j]) + Ms[i, j] = self._print(M[i, j]) # h- and v- spacers hsep = 2 @@ -550,8 +569,7 @@ maxw = [-1] * M.cols for j in range(M.cols): - maxw[j] = max([Ms[i,j].width() for i in range(M.rows)] or [0]) - + maxw[j] = max([Ms[i, j].width() for i in range(M.rows)] or [0]) # drawing result D = None @@ -560,21 +578,21 @@ D_row = None for j in range(M.cols): - s = Ms[i,j] + s = Ms[i, j] # reshape s to maxw # XXX this should be generalized, and go to stringPict.reshape ? - assert s.width() <= maxw[j] + assert s.width() <= maxw[j] # hcenter it, +0.5 to the right 2 # ( it's better to align formula starts for say 0 and r ) # XXX this is not good in all cases -- maybe introduce vbaseline? wdelta = maxw[j] - s.width() - wleft = wdelta // 2 + wleft = wdelta // 2 wright = wdelta - wleft s = prettyForm(*s.right(' '*wright)) - s = prettyForm(*s.left (' '*wleft)) + s = prettyForm(*s.left(' '*wleft)) # we don't need vcenter cells -- this is automatically done in # a pretty way because when their baselines are taking into @@ -598,70 +616,145 @@ D = prettyForm(*D.below(D_row)) if D is None: - D = prettyForm('') # Empty Matrix + D = prettyForm('') # Empty Matrix return D def _print_MatrixBase(self, e): D = self._print_matrix_contents(e) - D = prettyForm(*D.parens('[',']')) + D = prettyForm(*D.parens('[', ']')) return D _print_ImmutableMatrix = _print_MatrixBase - _print_MutableMatrix = _print_MatrixBase + _print_Matrix = _print_MatrixBase + + + def _print_MatrixElement(self, expr): + from sympy.matrices import MatrixSymbol + from sympy import Symbol + if (isinstance(expr.parent, MatrixSymbol) + and expr.i.is_number and expr.j.is_number): + return self._print( + Symbol(expr.parent.name + '_%d%d'%(expr.i, expr.j))) + else: + prettyFunc = self._print(expr.parent) + prettyIndices = self._print_seq((expr.i, expr.j), delimiter=', ' + ).parens(left='[', right=']')[0] + pform = prettyForm(binding=prettyForm.FUNC, + *stringPict.next(prettyFunc, prettyIndices)) + + # store pform parts so it can be reassembled e.g. when powered + pform.prettyFunc = prettyFunc + pform.prettyArgs = prettyIndices + + return pform + + + def _print_MatrixSlice(self, m): + # XXX works only for applied functions + + prettyFunc = self._print(m.parent) + def ppslice(x): + x = list(x) + if x[2] == 1: + del x[2] + if x[1] == x[0] + 1: + del x[1] + if x[0] == 0: + x[0] = '' + return prettyForm(*self._print_seq(x, delimiter=':')) + prettyArgs = self._print_seq((ppslice(m.rowslice), + ppslice(m.colslice)), delimiter=', ').parens(left='[', right=']')[0] + + pform = prettyForm( + binding=prettyForm.FUNC, *stringPict.next(prettyFunc, prettyArgs)) + + # store pform parts so it can be reassembled e.g. when powered + pform.prettyFunc = prettyFunc + pform.prettyArgs = prettyArgs - def _print_Transpose(self, T): - pform = self._print(T.arg) - if (T.arg.is_Add or T.arg.is_Mul or T.arg.is_Pow): + return pform + + def _print_Transpose(self, expr): + pform = self._print(expr.arg) + from sympy.matrices import MatrixSymbol + if not isinstance(expr.arg, MatrixSymbol): pform = prettyForm(*pform.parens()) - pform = prettyForm(*pform.right("'")) + pform = pform**(prettyForm('T')) return pform - def _print_Inverse(self, I): - pform = self._print(I.arg) - if (I.arg.is_Add or I.arg.is_Mul or I.arg.is_Pow): + def _print_Adjoint(self, expr): + pform = self._print(expr.arg) + if self._use_unicode: + dag = prettyForm('\u2020') + else: + dag = prettyForm('+') + from sympy.matrices import MatrixSymbol + if not isinstance(expr.arg, MatrixSymbol): pform = prettyForm(*pform.parens()) - pform = prettyForm(*pform.right("^-1")) + pform = pform**dag return pform def _print_BlockMatrix(self, B): - if B.mat.shape == (1,1): - return self._print(B.mat[0,0]) - return self._print(B.mat) + if B.blocks.shape == (1, 1): + return self._print(B.blocks[0, 0]) + return self._print(B.blocks) + + def _print_MatAdd(self, expr): + return self._print_seq(expr.args, None, None, ' + ') def _print_MatMul(self, expr): - a = list(expr.args) - for i in range(0, len(a)): - if a[i].is_Add and len(a) > 1: - a[i] = prettyForm(*self._print(a[i]).parens()) + args = list(expr.args) + from sympy import Add, MatAdd, HadamardProduct + for i, a in enumerate(args): + if (isinstance(a, (Add, MatAdd, HadamardProduct)) + and len(expr.args) > 1): + args[i] = prettyForm(*self._print(a).parens()) else: - a[i] = self._print(a[i]) + args[i] = self._print(a) - return prettyForm.__mul__(*a) + return prettyForm.__mul__(*args) - def _print_MatAdd(self, expr): - return self._print_seq(expr.args, None, None, ' + ') + def _print_MatPow(self, expr): + pform = self._print(expr.base) + from sympy.matrices import MatrixSymbol + if not isinstance(expr.base, MatrixSymbol): + pform = prettyForm(*pform.parens()) + pform = pform**(self._print(expr.exp)) + return pform + + def _print_HadamardProduct(self, expr): + from sympy import MatAdd, MatMul + if self._use_unicode: + delim = pretty_atom('Ring') + else: + delim = '.*' + return self._print_seq(expr.args, None, None, delim, + parenthesize=lambda x: isinstance(x, (MatAdd, MatMul))) + + _print_MatrixSymbol = _print_Symbol def _print_FunctionMatrix(self, X): D = self._print(X.lamda.expr) - D = prettyForm(*D.parens('[',']')) + D = prettyForm(*D.parens('[', ']')) return D def _print_Piecewise(self, pexpr): P = {} for n, ec in enumerate(pexpr.args): - P[n,0] = self._print(ec.expr) - if ec.cond == True: - P[n,1] = prettyForm('otherwise') + P[n, 0] = self._print(ec.expr) + if ec.cond is True: + P[n, 1] = prettyForm('otherwise') else: - P[n,1] = prettyForm(*prettyForm('for ').right(self._print(ec.cond))) + P[n, 1] = prettyForm( + *prettyForm('for ').right(self._print(ec.cond))) hsep = 2 vsep = 1 len_args = len(pexpr.args) # max widths - maxw = [max([P[i,j].width() for i in range(len_args)]) \ - for j in range(2)] + maxw = [max([P[i, j].width() for i in range(len_args)]) + for j in range(2)] # FIXME: Refactor this code and matrix into some tabular environment. # drawing result @@ -670,15 +763,15 @@ for i in range(len_args): D_row = None for j in range(2): - p = P[i,j] + p = P[i, j] assert p.width() <= maxw[j] wdelta = maxw[j] - p.width() - wleft = wdelta // 2 + wleft = wdelta // 2 wright = wdelta - wleft p = prettyForm(*p.right(' '*wright)) - p = prettyForm(*p.left (' '*wleft)) + p = prettyForm(*p.left(' '*wleft)) if D_row is None: D_row = p @@ -696,7 +789,9 @@ D = prettyForm(*D.below(D_row)) - D = prettyForm(*D.parens('{','')) + D = prettyForm(*D.parens('{', '')) + D.baseline = D.height()//2 + D.binding = prettyForm.OPEN return D def _hprint_vec(self, v): @@ -754,15 +849,10 @@ above = D.height()//2 - 1 below = D.height() - above - 1 - if self._use_unicode: - pic = (2, 0, 2, '\u250c\u2500\n\u251c\u2500\n\u2575') - else: - pic = (3, 0, 3, ' _\n|_\n|\n') - sz, t, b, add, img = annotated('F') F = prettyForm('\n' * (above - t) + img + '\n' * (below - b), - baseline = above + sz) - add = (sz+1)//2 + baseline=above + sz) + add = (sz + 1)//2 F = prettyForm(*F.left(self._print(len(e.ap)))) F = prettyForm(*F.right(self._print(len(e.bq)))) @@ -801,7 +891,7 @@ D1 = prettyForm(*vp[(0, 0)].right(' ', vp[(0, 1)])) D1 = prettyForm(*D1.below(' ')) D2 = prettyForm(*vp[(1, 0)].right(' ', vp[(1, 1)])) - D = prettyForm(*D1.below(D2)) + D = prettyForm(*D1.below(D2)) # make sure that the argument `z' is centred vertically D.baseline = D.height()//2 @@ -822,12 +912,13 @@ sz, t, b, add, img = annotated('G') F = prettyForm('\n' * (above - t) + img + '\n' * (below - b), - baseline = above + sz) + baseline=above + sz) pp = self._print(len(e.ap)) pq = self._print(len(e.bq)) pm = self._print(len(e.bm)) pn = self._print(len(e.an)) + def adjust(p1, p2): diff = p1.width() - p2.width() if diff == 0: @@ -855,7 +946,6 @@ return D - def _print_ExpBase(self, e): # TODO should exp_polar be printed differently? # what about exp_polar(0), exp_polar(1)? @@ -868,14 +958,18 @@ args = e.args if sort: args = sorted(args, key=default_sort_key) - n = len(args) func_name = func.__name__ prettyFunc = self._print(C.Symbol(func_name)) prettyArgs = prettyForm(*self._print_seq(args).parens()) + #postioning func_name + mid = prettyArgs.height()//2 + if mid > 2: + prettyFunc.baseline = -mid + 1 - pform = prettyForm(binding=prettyForm.FUNC, *stringPict.next(prettyFunc, prettyArgs)) + pform = prettyForm( + binding=prettyForm.FUNC, *stringPict.next(prettyFunc, prettyArgs)) # store pform parts so it can be reassembled e.g. when powered pform.prettyFunc = prettyFunc @@ -900,7 +994,8 @@ prettyFunc = self._print(C.Symbol("Lambda")) prettyArgs = prettyForm(*self._print_seq(args).parens()) - pform = prettyForm(binding=prettyForm.FUNC, *stringPict.next(prettyFunc, prettyArgs)) + pform = prettyForm( + binding=prettyForm.FUNC, *stringPict.next(prettyFunc, prettyArgs)) # store pform parts so it can be reassembled e.g. when powered pform.prettyFunc = prettyFunc @@ -955,7 +1050,8 @@ prettyFunc = prettyForm("Chi") prettyArgs = prettyForm(*self._print_seq(e.args).parens()) - pform = prettyForm(binding=prettyForm.FUNC, *stringPict.next(prettyFunc, prettyArgs)) + pform = prettyForm( + binding=prettyForm.FUNC, *stringPict.next(prettyFunc, prettyArgs)) # store pform parts so it can be reassembled e.g. when powered pform.prettyFunc = prettyFunc @@ -963,6 +1059,46 @@ return pform + def _print_elliptic_e(self, e): + pforma0 = self._print(e.args[0]) + if len(e.args) == 1: + pform = pforma0 + else: + pforma1 = self._print(e.args[1]) + pform = self._hprint_vseparator(pforma0, pforma1) + pform = prettyForm(*pform.parens()) + pform = prettyForm(*pform.left('E')) + return pform + + def _print_elliptic_k(self, e): + pform = self._print(e.args[0]) + pform = prettyForm(*pform.parens()) + pform = prettyForm(*pform.left('K')) + return pform + + def _print_elliptic_f(self, e): + pforma0 = self._print(e.args[0]) + pforma1 = self._print(e.args[1]) + pform = self._hprint_vseparator(pforma0, pforma1) + pform = prettyForm(*pform.parens()) + pform = prettyForm(*pform.left('F')) + return pform + + def _print_elliptic_pi(self, e): + name = greek['pi'][1] if self._use_unicode else 'Pi' + pforma0 = self._print(e.args[0]) + pforma1 = self._print(e.args[1]) + if len(e.args) == 2: + pform = self._hprint_vseparator(pforma0, pforma1) + else: + pforma2 = self._print(e.args[2]) + pforma = self._hprint_vseparator(pforma1, pforma2) + pforma = prettyForm(*pforma.left('; ')) + pform = prettyForm(*pforma.left(pforma0)) + pform = prettyForm(*pform.parens()) + pform = prettyForm(*pform.left(name)) + return pform + def _print_Add(self, expr, order=None): if self.order == 'none': terms = list(expr.args) @@ -972,6 +1108,7 @@ def pretty_negative(pform, index): """Prepend a minus sign to a pretty form. """ + #TODO: Move this code to prettyForm if index == 0: if pform.height() > 1: pform_neg = '- ' @@ -980,8 +1117,14 @@ else: pform_neg = ' - ' - pform = stringPict.next(pform_neg, pform) - return prettyForm(binding=prettyForm.NEG, *pform) + if pform.binding > prettyForm.NEG: + p = stringPict(*pform.parens()) + else: + p = pform + p = stringPict.next(pform_neg, p) + # Lower the binding to NEG, even if it was higher. Otherwise, it + # will print as a + ( - (b)), instead of a - (b). + return prettyForm(binding=prettyForm.NEG, *p) for i, term in enumerate(terms): if term.is_Mul and _coeff_isneg(term): @@ -1024,8 +1167,8 @@ return prettyForm.__add__(*pforms) def _print_Mul(self, product): - a = [] # items in the numerator - b = [] # items that are in the denominator (if any) + a = [] # items in the numerator + b = [] # items that are in the denominator (if any) if self.order not in ('old', 'none'): args = product.as_ordered_factors() @@ -1044,16 +1187,20 @@ else: a.append(item) + from sympy import Integral, Piecewise, Product, Sum + # Convert to pretty forms. Add parens to Add instances if there # is more than one term in the numer/denom for i in range(0, len(a)): - if a[i].is_Add and len(a) > 1: + if (a[i].is_Add and len(a) > 1) or (i != len(a) - 1 and + isinstance(a[i], (Integral, Piecewise, Product, Sum))): a[i] = prettyForm(*self._print(a[i]).parens()) else: a[i] = self._print(a[i]) for i in range(0, len(b)): - if b[i].is_Add and len(b) > 1: + if (b[i].is_Add and len(b) > 1) or (i != len(b) - 1 and + isinstance(b[i], (Integral, Piecewise, Product, Sum))): b[i] = prettyForm(*self._print(b[i]).parens()) else: b[i] = self._print(b[i]) @@ -1067,12 +1214,12 @@ return prettyForm.__mul__(*a)/prettyForm.__mul__(*b) # A helper function for _print_Pow to print x**(1/n) - def _print_nth_root (self, base, expt): + def _print_nth_root(self, base, expt): bpretty = self._print(base) # Construct root sign, start with the \/ shape - _zZ = xobj('/',1) - rootsign = xobj('\\',1) + _zZ + _zZ = xobj('/', 1) + rootsign = xobj('\\', 1) + _zZ # Make exponent number to put above it if isinstance(expt, C.Rational): exp = str(expt.q) @@ -1091,7 +1238,7 @@ diagonal = stringPict('\n'.join( ' '*(linelength - i - 1) + _zZ + ' '*i for i in range(linelength) - )) + )) # Put baseline just below lowest line: next to exp diagonal.baseline = linelength - 1 # Make the root symbol @@ -1106,7 +1253,7 @@ return s def _print_Pow(self, power): - from sympy import fraction + from sympy.simplify.simplify import fraction b, e = power.as_base_exp() if power.is_commutative: if e is S.NegativeOne: @@ -1115,22 +1262,23 @@ if n is S.One and d.is_Atom and not e.is_Integer: return self._print_nth_root(b, e) if e.is_Rational and e < 0: - return prettyForm("1")/self._print(b)**self._print(-e) + return prettyForm("1")/self._print(C.Pow(b, -e, evaluate=False)) - # None of the above special forms, do a standard power return self._print(b)**self._print(e) def __print_numer_denom(self, p, q): if q == 1: if p < 0: - return prettyForm(str(p),binding=prettyForm.NEG) + return prettyForm(str(p), binding=prettyForm.NEG) else: return prettyForm(str(p)) elif abs(p) >= 10 and abs(q) >= 10: # If more than one digit in numer and denom, print larger fraction if p < 0: - pform = prettyForm(str(-p))/prettyForm(str(q)) - return prettyForm(binding=prettyForm.NEG, *pform.left('- ')) + return prettyForm(str(p), binding=prettyForm.NEG)/prettyForm(str(q)) + # Old printing method: + #pform = prettyForm(str(-p))/prettyForm(str(q)) + #return prettyForm(binding=prettyForm.NEG, *pform.left('- ')) else: return prettyForm(str(p))/prettyForm(str(q)) else: @@ -1158,8 +1306,8 @@ return self._print(Pow(p.sets[0], len(p.sets), evaluate=False)) else: prod_char = '\xd7' - return self._print_seq(p.sets, None, None, ' %s '%prod_char, - parenthesize = lambda set:set.is_Union or set.is_Intersection) + return self._print_seq(p.sets, None, None, ' %s ' % prod_char, + parenthesize=lambda set: set.is_Union or set.is_Intersection) def _print_FiniteSet(self, s): items = sorted(s.args, key=default_sort_key) @@ -1202,14 +1350,14 @@ delimiter = ' %s ' % pretty_atom('Intersection') return self._print_seq(u.args, None, None, delimiter, - parenthesize = lambda set:set.is_ProductSet or set.is_Union) + parenthesize=lambda set: set.is_ProductSet or set.is_Union) def _print_Union(self, u): union_delimiter = ' %s ' % pretty_atom('Union') return self._print_seq(u.args, None, None, union_delimiter, - parenthesize = lambda set:set.is_ProductSet or set.is_Intersection) + parenthesize=lambda set: set.is_ProductSet or set.is_Intersection) def _print_TransformationSet(self, ts): if self._use_unicode: @@ -1298,6 +1446,18 @@ _print_frozenset = _print_set + def _print_PolyRing(self, ring): + return prettyForm(sstr(ring)) + + def _print_FracField(self, field): + return prettyForm(sstr(field)) + + def _print_PolyElement(self, poly): + return prettyForm(sstr(poly)) + + def _print_FracElement(self, frac): + return prettyForm(sstr(frac)) + def _print_AlgebraicNumber(self, expr): if expr.is_aliased: return self._print(expr.as_poly().as_expr()) @@ -1369,15 +1529,16 @@ return pform def _print_GroebnerBasis(self, basis): - cls = basis.__class__.__name__ - - exprs = [ self._print_Add(arg, order=basis.order) for arg in basis.exprs ] + exprs = [ self._print_Add(arg, order=basis.order) + for arg in basis.exprs ] exprs = prettyForm(*self.join(", ", exprs).parens(left="[", right="]")) gens = [ self._print(gen) for gen in basis.gens ] - domain = prettyForm(*prettyForm("domain=").right(self._print(basis.domain))) - order = prettyForm(*prettyForm("order=").right(self._print(basis.order))) + domain = prettyForm( + *prettyForm("domain=").right(self._print(basis.domain))) + order = prettyForm( + *prettyForm("order=").right(self._print(basis.order))) pform = self.join(", ", [exprs] + gens + [domain, order]) @@ -1432,11 +1593,6 @@ bot = stringPict(*a.right(' '*b.width())) return prettyForm(binding=prettyForm.POW, *bot.below(top)) - def _print_atan2(self, e): - pform = prettyForm(*self._print_seq(e.args).parens()) - pform = prettyForm(*pform.left('atan2')) - return pform - def _print_RandomDomain(self, d): try: pform = self._print('Domain: ') @@ -1488,13 +1644,12 @@ NamedMorphism(morphism.domain, morphism.codomain, "id")) def _print_CompositeMorphism(self, morphism): - from sympy.categories import NamedMorphism circle = xsym(".") # All components of the morphism have names and it is thus # possible to build the name of the composite. - component_names_list = [pretty_symbol(component.name) for \ + component_names_list = [pretty_symbol(component.name) for component in morphism.components] component_names_list.reverse() component_names = circle.join(component_names_list) + ":" @@ -1516,7 +1671,8 @@ results_arrow = " %s " % xsym("==>") pretty_conclusions = self._print(diagram.conclusions)[0] - pretty_result = pretty_result.right(results_arrow, pretty_conclusions) + pretty_result = pretty_result.right( + results_arrow, pretty_conclusions) return prettyForm(pretty_result[0]) @@ -1565,14 +1721,14 @@ return self._print(pretty_symbol(string)) def _print_BaseVectorField(self, field): - s = U('PARTIAL DIFFERENTIAL')+'_'+field._coord_sys._names[field._index] + s = U('PARTIAL DIFFERENTIAL') + '_' + field._coord_sys._names[field._index] return self._print(pretty_symbol(s)) def _print_Differential(self, diff): field = diff._form_field if hasattr(field, '_coord_sys'): string = field._coord_sys._names[field._index] - return self._print('\u2146 '+pretty_symbol(string)) + return self._print('\u2146 ' + pretty_symbol(string)) else: pform = self._print(field) pform = prettyForm(*pform.parens()) @@ -1603,6 +1759,7 @@ finally: pretty_use_unicode(uflag) + def pretty_print(expr, **settings): """Prints expr in pretty form. @@ -1632,6 +1789,7 @@ pprint = pretty_print + def pager_print(expr, **settings): """Prints expr using the pager, in pretty form. @@ -1646,5 +1804,5 @@ from pydoc import pager from locale import getpreferredencoding if 'num_columns' not in settings: - settings['num_columns'] = 500000 # disable line wrap + settings['num_columns'] = 500000 # disable line wrap pager(pretty(expr, **settings).encode(getpreferredencoding())) diff -Nru python3-sympy-0.7.2/sympy/printing/pretty/pretty_symbology.py python3-sympy-0.7.3/sympy/printing/pretty/pretty_symbology.py --- python3-sympy-0.7.2/sympy/printing/pretty/pretty_symbology.py 2012-10-17 03:02:22.000000000 +0000 +++ python3-sympy-0.7.3/sympy/printing/pretty/pretty_symbology.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,7 +1,8 @@ """Symbolic primitives + unicode/ASCII abstraction for pretty.py""" import sys -warnings = '' +import warnings +unicode_warnings = '' # first, setup unicodedate environment try: @@ -14,13 +15,13 @@ except KeyError: u = None - global warnings - warnings += 'W: no \'%s\' in unocodedata\n' % name + global unicode_warnings + unicode_warnings += 'No \'%s\' in unicodedata\n' % name return u except ImportError: - warnings += 'W: no unicodedata available\n' + unicode_warnings += 'No unicodedata available\n' U = lambda name: None from sympy.printing.conventions import split_super_sub @@ -33,29 +34,30 @@ # S - SYMBOL + -__all__ = ['greek','sub','sup','xsym','vobj','hobj','pretty_symbol', +__all__ = ['greek', 'sub', 'sup', 'xsym', 'vobj', 'hobj', 'pretty_symbol', 'annotated'] _use_unicode = False -def pretty_use_unicode(flag = None): + +def pretty_use_unicode(flag=None): """Set whether pretty-printer should use unicode by default""" global _use_unicode - global warnings + global unicode_warnings if flag is None: return _use_unicode - if flag and warnings: + if flag and unicode_warnings: # print warnings (if any) on first unicode usage - print("I: pprint -- we are going to use unicode, but there are following problems:") - print(warnings) - warnings = '' + warnings.warn(unicode_warnings) + unicode_warnings = '' use_unicode_prev = _use_unicode _use_unicode = flag return use_unicode_prev + def pretty_try_use_unicode(): """See if unicode output is available and leverage it if possible""" @@ -63,7 +65,7 @@ symbols = [] # see, if we can represent greek alphabet - for g,G in greek.values(): + for g, G in greek.values(): symbols.append(g) symbols.append(G) @@ -98,8 +100,8 @@ return str(*args) # GREEK -g = lambda l: U('GREEK SMALL LETTER %s' % l.upper()) -G = lambda l: U('GREEK CAPITAL LETTER %s' % l.upper()) +g = lambda l: U('GREEK SMALL LETTER %s' % l.upper()) +G = lambda l: U('GREEK CAPITAL LETTER %s' % l.upper()) greek_letters = [ 'alpha', 'beta', 'gamma', 'delta', 'epsilon', 'zeta', 'eta', 'theta', @@ -112,31 +114,31 @@ greek['lambda'] = greek['lamda'] digit_2txt = { - '0' : 'ZERO', - '1' : 'ONE', - '2' : 'TWO', - '3' : 'THREE', - '4' : 'FOUR', - '5' : 'FIVE', - '6' : 'SIX', - '7' : 'SEVEN', - '8' : 'EIGHT', - '9' : 'NINE', + '0': 'ZERO', + '1': 'ONE', + '2': 'TWO', + '3': 'THREE', + '4': 'FOUR', + '5': 'FIVE', + '6': 'SIX', + '7': 'SEVEN', + '8': 'EIGHT', + '9': 'NINE', } symb_2txt = { - '+' : 'PLUS SIGN', - '-' : 'MINUS', - '=' : 'EQUALS SIGN', - '(' : 'LEFT PARENTHESIS', - ')' : 'RIGHT PARENTHESIS', - '[' : 'LEFT SQUARE BRACKET', - ']' : 'RIGHT SQUARE BRACKET', - '{' : 'LEFT CURLY BRACKET', - '}' : 'RIGHT CURLY BRACKET', + '+': 'PLUS SIGN', + '-': 'MINUS', + '=': 'EQUALS SIGN', + '(': 'LEFT PARENTHESIS', + ')': 'RIGHT PARENTHESIS', + '[': 'LEFT SQUARE BRACKET', + ']': 'RIGHT SQUARE BRACKET', + '{': 'LEFT CURLY BRACKET', + '}': 'RIGHT CURLY BRACKET', # non-std - '{}' : 'CURLY BRACKET', + '{}': 'CURLY BRACKET', 'sum': 'SUMMATION', 'int': 'INTEGRAL', } @@ -174,90 +176,90 @@ # VERTICAL OBJECTS -HUP = lambda symb: U('%s UPPER HOOK' % symb_2txt[symb]) -CUP = lambda symb: U('%s UPPER CORNER' % symb_2txt[symb]) -MID = lambda symb: U('%s MIDDLE PIECE' % symb_2txt[symb]) -EXT = lambda symb: U('%s EXTENSION' % symb_2txt[symb]) -HLO = lambda symb: U('%s LOWER HOOK' % symb_2txt[symb]) -CLO = lambda symb: U('%s LOWER CORNER' % symb_2txt[symb]) -TOP = lambda symb: U('%s TOP' % symb_2txt[symb]) -BOT = lambda symb: U('%s BOTTOM' % symb_2txt[symb]) +HUP = lambda symb: U('%s UPPER HOOK' % symb_2txt[symb]) +CUP = lambda symb: U('%s UPPER CORNER' % symb_2txt[symb]) +MID = lambda symb: U('%s MIDDLE PIECE' % symb_2txt[symb]) +EXT = lambda symb: U('%s EXTENSION' % symb_2txt[symb]) +HLO = lambda symb: U('%s LOWER HOOK' % symb_2txt[symb]) +CLO = lambda symb: U('%s LOWER CORNER' % symb_2txt[symb]) +TOP = lambda symb: U('%s TOP' % symb_2txt[symb]) +BOT = lambda symb: U('%s BOTTOM' % symb_2txt[symb]) # {} '(' -> (extension, start, end, middle) 1-character _xobj_unicode = { # vertical symbols - # ext top bot mid c1 - '(' : (( EXT('('), HUP('('), HLO('(') ), '('), - ')' : (( EXT(')'), HUP(')'), HLO(')') ), ')'), - '[' : (( EXT('['), CUP('['), CLO('[') ), '['), - ']' : (( EXT(']'), CUP(']'), CLO(']') ), ']'), - '{' : (( EXT('{}'), HUP('{'), HLO('{'), MID('{') ), '{'), - '}' : (( EXT('{}'), HUP('}'), HLO('}'), MID('}') ), '}'), - '|' : U('BOX DRAWINGS LIGHT VERTICAL'), - - '<': ((U('BOX DRAWINGS LIGHT VERTICAL'), - U('BOX DRAWINGS LIGHT DIAGONAL UPPER RIGHT TO LOWER LEFT'), - U('BOX DRAWINGS LIGHT DIAGONAL UPPER LEFT TO LOWER RIGHT')), '<'), - - '>': ((U('BOX DRAWINGS LIGHT VERTICAL'), - U('BOX DRAWINGS LIGHT DIAGONAL UPPER LEFT TO LOWER RIGHT'), - U('BOX DRAWINGS LIGHT DIAGONAL UPPER RIGHT TO LOWER LEFT')), '>'), - - 'lfloor' : (( EXT('['), EXT('['), CLO('[') ), U('LEFT FLOOR')), - 'rfloor' : (( EXT(']'), EXT(']'), CLO(']') ), U('RIGHT FLOOR')), - 'lceil' : (( EXT('['), CUP('['), EXT('[') ), U('LEFT CEILING')), - 'rceil' : (( EXT(']'), CUP(']'), EXT(']') ), U('RIGHT CEILING')), + # (( ext, top, bot, mid ), c1) + '(': (( EXT('('), HUP('('), HLO('(') ), '('), + ')': (( EXT(')'), HUP(')'), HLO(')') ), ')'), + '[': (( EXT('['), CUP('['), CLO('[') ), '['), + ']': (( EXT(']'), CUP(']'), CLO(']') ), ']'), + '{': (( EXT('{}'), HUP('{'), HLO('{'), MID('{') ), '{'), + '}': (( EXT('{}'), HUP('}'), HLO('}'), MID('}') ), '}'), + '|': U('BOX DRAWINGS LIGHT VERTICAL'), + + '<': ((U('BOX DRAWINGS LIGHT VERTICAL'), + U('BOX DRAWINGS LIGHT DIAGONAL UPPER RIGHT TO LOWER LEFT'), + U('BOX DRAWINGS LIGHT DIAGONAL UPPER LEFT TO LOWER RIGHT')), '<'), + + '>': ((U('BOX DRAWINGS LIGHT VERTICAL'), + U('BOX DRAWINGS LIGHT DIAGONAL UPPER LEFT TO LOWER RIGHT'), + U('BOX DRAWINGS LIGHT DIAGONAL UPPER RIGHT TO LOWER LEFT')), '>'), + + 'lfloor': (( EXT('['), EXT('['), CLO('[') ), U('LEFT FLOOR')), + 'rfloor': (( EXT(']'), EXT(']'), CLO(']') ), U('RIGHT FLOOR')), + 'lceil': (( EXT('['), CUP('['), EXT('[') ), U('LEFT CEILING')), + 'rceil': (( EXT(']'), CUP(']'), EXT(']') ), U('RIGHT CEILING')), 'int': (( EXT('int'), U('TOP HALF INTEGRAL'), U('BOTTOM HALF INTEGRAL') ), U('INTEGRAL')), 'sum': (( U('BOX DRAWINGS LIGHT DIAGONAL UPPER LEFT TO LOWER RIGHT'), '_', U('OVERLINE'), U('BOX DRAWINGS LIGHT DIAGONAL UPPER RIGHT TO LOWER LEFT')), U('N-ARY SUMMATION')), - # horizontal objects - #'-' : '-', - '-' : U('BOX DRAWINGS LIGHT HORIZONTAL'), - '_' : U('LOW LINE'), + #'-': '-', + '-': U('BOX DRAWINGS LIGHT HORIZONTAL'), + '_': U('LOW LINE'), # We used to use this, but LOW LINE looks better for roots, as it's a # little lower (i.e., it lines up with the / perfectly. But perhaps this # one would still be wanted for some cases? - # '_' : U('HORIZONTAL SCAN LINE-9'), + # '_': U('HORIZONTAL SCAN LINE-9'), # diagonal objects '\' & '/' ? - '/' : U('BOX DRAWINGS LIGHT DIAGONAL UPPER RIGHT TO LOWER LEFT'), + '/': U('BOX DRAWINGS LIGHT DIAGONAL UPPER RIGHT TO LOWER LEFT'), '\\': U('BOX DRAWINGS LIGHT DIAGONAL UPPER LEFT TO LOWER RIGHT'), } _xobj_ascii = { # vertical symbols - # ext top bot mid c1 - '(' : (( '|', '/', '\\' ), '('), - ')' : (( '|', '\\', '/' ), ')'), + # (( ext, top, bot, mid ), c1) + '(': (( '|', '/', '\\' ), '('), + ')': (( '|', '\\', '/' ), ')'), # XXX this looks ugly -# '[' : (( '|', '-', '-' ), '['), -# ']' : (( '|', '-', '-' ), ']'), +# '[': (( '|', '-', '-' ), '['), +# ']': (( '|', '-', '-' ), ']'), # XXX not so ugly :( - '[' : (( '[', '[', '[' ), '['), - ']' : (( ']', ']', ']' ), ']'), + '[': (( '[', '[', '[' ), '['), + ']': (( ']', ']', ']' ), ']'), - '{' : (( '|', '/', '\\', '<' ), '{'), - '}' : (( '|', '\\', '/', '>' ), '}'), - '|' : '|', + '{': (( '|', '/', '\\', '<' ), '{'), + '}': (( '|', '\\', '/', '>' ), '}'), + '|': '|', - '<' : (( '|', '/', '\\' ), '<'), - '>' : (( '|', '\\', '/' ), '>'), + '<': (( '|', '/', '\\' ), '<'), + '>': (( '|', '\\', '/' ), '>'), 'int': ( ' | ', ' /', '/ ' ), # horizontal objects - '-' : '-', - '_' : '_', + '-': '-', + '_': '_', # diagonal objects '\' & '/' ? - '/' : '/', + '/': '/', '\\': '\\', } + def xobj(symb, length): """Construct spatial object of given length. @@ -281,7 +283,7 @@ else: if isinstance(vinfo[0], tuple): # (vlong), c1 vlong = vinfo[0] - c1 = vinfo[1] + c1 = vinfo[1] else: # (vlong), c1 vlong = vinfo @@ -294,9 +296,12 @@ except IndexError: pass - if c1 is None: c1 = ext - if top is None: top = ext - if bot is None: bot = ext + if c1 is None: + c1 = ext + if top is None: + top = ext + if bot is None: + bot = ext if mid is not None: if (length % 2) == 0: # even height, but we have to print it somehow anyway... @@ -309,10 +314,9 @@ if length == 1: return c1 - res = [] - next= (length-2)//2 - nmid= (length-2) - next*2 + next = (length - 2)//2 + nmid = (length - 2) - next*2 res += [top] res += [ext]*next @@ -330,6 +334,7 @@ """ return '\n'.join( xobj(symb, height) ) + def hobj(symb, width): """Construct horizontal object of a given width @@ -340,50 +345,50 @@ # RADICAL # n -> symbol root = { - 2 : U('SQUARE ROOT'), # U('RADICAL SYMBOL BOTTOM') - 3 : U('CUBE ROOT'), - 4 : U('FOURTH ROOT'), + 2: U('SQUARE ROOT'), # U('RADICAL SYMBOL BOTTOM') + 3: U('CUBE ROOT'), + 4: U('FOURTH ROOT'), } # RATIONAL -VF = lambda txt: U('VULGAR FRACTION %s' % txt) +VF = lambda txt: U('VULGAR FRACTION %s' % txt) # (p,q) -> symbol frac = { - (1,2) : VF('ONE HALF'), - (1,3) : VF('ONE THIRD'), - (2,3) : VF('TWO THIRDS'), - (1,4) : VF('ONE QUARTER'), - (3,4) : VF('THREE QUARTERS'), - (1,5) : VF('ONE FIFTH'), - (2,5) : VF('TWO FIFTHS'), - (3,5) : VF('THREE FIFTHS'), - (4,5) : VF('FOUR FIFTHS'), - (1,6) : VF('ONE SIXTH'), - (5,6) : VF('FIVE SIXTHS'), - (1,8) : VF('ONE EIGHTH'), - (3,8) : VF('THREE EIGHTHS'), - (5,8) : VF('FIVE EIGHTHS'), - (7,8) : VF('SEVEN EIGHTHS'), + (1, 2): VF('ONE HALF'), + (1, 3): VF('ONE THIRD'), + (2, 3): VF('TWO THIRDS'), + (1, 4): VF('ONE QUARTER'), + (3, 4): VF('THREE QUARTERS'), + (1, 5): VF('ONE FIFTH'), + (2, 5): VF('TWO FIFTHS'), + (3, 5): VF('THREE FIFTHS'), + (4, 5): VF('FOUR FIFTHS'), + (1, 6): VF('ONE SIXTH'), + (5, 6): VF('FIVE SIXTHS'), + (1, 8): VF('ONE EIGHTH'), + (3, 8): VF('THREE EIGHTHS'), + (5, 8): VF('FIVE EIGHTHS'), + (7, 8): VF('SEVEN EIGHTHS'), } # atom symbols _xsym = { - '==' : ( '=', '='), - '<' : ( '<', '<'), - '>' : ( '>', '>'), - '<=' : ('<=', U('LESS-THAN OR EQUAL TO')), - '>=' : ('>=', U('GREATER-THAN OR EQUAL TO')), - '!=' : ('!=', U('NOT EQUAL TO')), - '*' : ('*', U('DOT OPERATOR')), - '-->' : ('-->', U('EM DASH') + U('EM DASH') + - U('BLACK RIGHT-POINTING TRIANGLE')), - '==>' : ('==>', U('BOX DRAWINGS DOUBLE HORIZONTAL') + - U('BOX DRAWINGS DOUBLE HORIZONTAL') + - U('BLACK RIGHT-POINTING TRIANGLE')), - '.' : ('*', U('RING OPERATOR')), + '==': ('=', '='), + '<': ('<', '<'), + '>': ('>', '>'), + '<=': ('<=', U('LESS-THAN OR EQUAL TO')), + '>=': ('>=', U('GREATER-THAN OR EQUAL TO')), + '!=': ('!=', U('NOT EQUAL TO')), + '*': ('*', U('DOT OPERATOR')), + '-->': ('-->', U('EM DASH') + U('EM DASH') + + U('BLACK RIGHT-POINTING TRIANGLE')), + '==>': ('==>', U('BOX DRAWINGS DOUBLE HORIZONTAL') + + U('BOX DRAWINGS DOUBLE HORIZONTAL') + + U('BLACK RIGHT-POINTING TRIANGLE')), + '.': ('*', U('RING OPERATOR')), } @@ -400,22 +405,24 @@ # SYMBOLS atoms_table = { - # class how-to-display - 'Exp1' : U('SCRIPT SMALL E'), - 'Pi' : U('GREEK SMALL LETTER PI'), - 'Infinity' : U('INFINITY'), - 'NegativeInfinity' : U('INFINITY') and ('-'+U('INFINITY')), # XXX what to do here - #'ImaginaryUnit' : U('GREEK SMALL LETTER IOTA'), - #'ImaginaryUnit' : U('MATHEMATICAL ITALIC SMALL I'), - 'ImaginaryUnit' : U('DOUBLE-STRUCK ITALIC SMALL I'), - 'EmptySet' : U('EMPTY SET'), - 'Naturals' : U('DOUBLE-STRUCK CAPITAL N'), - 'Integers' : U('DOUBLE-STRUCK CAPITAL Z'), - 'Reals' : U('DOUBLE-STRUCK CAPITAL R'), - 'Union' : U('UNION'), - 'Intersection' : U('INTERSECTION') + # class how-to-display + 'Exp1': U('SCRIPT SMALL E'), + 'Pi': U('GREEK SMALL LETTER PI'), + 'Infinity': U('INFINITY'), + 'NegativeInfinity': U('INFINITY') and ('-' + U('INFINITY')), # XXX what to do here + #'ImaginaryUnit': U('GREEK SMALL LETTER IOTA'), + #'ImaginaryUnit': U('MATHEMATICAL ITALIC SMALL I'), + 'ImaginaryUnit': U('DOUBLE-STRUCK ITALIC SMALL I'), + 'EmptySet': U('EMPTY SET'), + 'Naturals': U('DOUBLE-STRUCK CAPITAL N'), + 'Integers': U('DOUBLE-STRUCK CAPITAL Z'), + 'Reals': U('DOUBLE-STRUCK CAPITAL R'), + 'Union': U('UNION'), + 'Intersection': U('INTERSECTION'), + 'Ring': U('RING OPERATOR') } + def pretty_atom(atom_name, default=None): """return pretty representation of an atom""" if _use_unicode: @@ -426,6 +433,7 @@ raise KeyError('only unicode') # send it default printer + def pretty_symbol(symb_name): """return pretty representation of a symbol""" # let's split symb_name into symbol + index @@ -455,7 +463,7 @@ for s in l: pretty = mapping.get(s) if pretty is None: - try: # match by separate characters + try: # match by separate characters pretty = ''.join([mapping[c] for c in s]) except KeyError: return None @@ -469,7 +477,7 @@ pretty_subs = None # glue the results into one string - if pretty_subs is None: # nice formatting of sups/subs did not work + if pretty_subs is None: # nice formatting of sups/subs did not work return symb_name else: sups_result = ' '.join(pretty_sups) diff -Nru python3-sympy-0.7.2/sympy/printing/pretty/stringpict.py python3-sympy-0.7.3/sympy/printing/pretty/stringpict.py --- python3-sympy-0.7.2/sympy/printing/pretty/stringpict.py 2012-10-17 03:02:22.000000000 +0000 +++ python3-sympy-0.7.3/sympy/printing/pretty/stringpict.py 2013-07-13 17:53:32.000000000 +0000 @@ -3,7 +3,7 @@ All objects have a method that create a "stringPict", that can be used in the str method for pretty printing. -Updates by Jason gedge (email at cs mun ca) +Updates by Jason Gedge (email at cs mun ca) - terminal_string() method - minor fixes and changes (mostly to prettyForm) @@ -12,7 +12,8 @@ top/center/bottom alignment options for left/right """ -from .pretty_symbology import hobj, vobj, xsym, pretty_use_unicode +from .pretty_symbology import hobj, vobj, xsym, xobj, pretty_use_unicode + class stringPict(object): """An ASCII picture. @@ -56,25 +57,26 @@ #convert everything to stringPicts objects = [] for arg in args: - if isinstance(arg, str): arg = stringPict(arg) + if isinstance(arg, str): + arg = stringPict(arg) objects.append(arg) #make a list of pictures, with equal height and baseline newBaseline = max(obj.baseline for obj in objects) newHeightBelowBaseline = max( - obj.height()-obj.baseline + obj.height() - obj.baseline for obj in objects) newHeight = newBaseline + newHeightBelowBaseline pictures = [] for obj in objects: oneEmptyLine = [' '*obj.width()] - basePadding = newBaseline-obj.baseline - totalPadding = newHeight-obj.height() + basePadding = newBaseline - obj.baseline + totalPadding = newHeight - obj.height() pictures.append( oneEmptyLine * basePadding + obj.picture + - oneEmptyLine * (totalPadding-basePadding)) + oneEmptyLine * (totalPadding - basePadding)) result = [''.join(lines) for lines in zip(*pictures)] return '\n'.join(result), newBaseline @@ -100,7 +102,7 @@ """Put pictures (left to right) at left. Returns string, baseline arguments for stringPict. """ - return stringPict.next(*(args+(self,))) + return stringPict.next(*(args + (self,))) @staticmethod def stack(*args): @@ -138,7 +140,7 @@ for obj in objects: newPicture.extend(obj.picture) newPicture = [line.center(newWidth) for line in newPicture] - newBaseline = objects[0].height()+objects[1].baseline + newBaseline = objects[0].height() + objects[1].baseline return '\n'.join(newPicture), newBaseline def below(self, *args): @@ -150,7 +152,8 @@ ======== >>> from sympy.printing.pretty.stringpict import stringPict - >>> print(stringPict("x+3").below(stringPict.LINE, '3')[0]) #doctest: +NORMALIZE_WHITESPACE + >>> print(stringPict("x+3").below( + ... stringPict.LINE, '3')[0]) #doctest: +NORMALIZE_WHITESPACE x+3 --- 3 @@ -164,8 +167,8 @@ Returns string, baseline arguments for stringPict. Baseline is baseline of bottom picture. """ - string, baseline = stringPict.stack(*(args+(self,))) - baseline = len(string.splitlines())-self.height()+self.baseline + string, baseline = stringPict.stack(*(args + (self,))) + baseline = len(string.splitlines()) - self.height() + self.baseline return string, baseline def parens(self, left='(', right=')', ifascii_nougly=False): @@ -186,11 +189,11 @@ res = self if left: - lparen = stringPict(vobj(left, h), baseline=b) - res = stringPict(*lparen.right(self)) + lparen = stringPict(vobj(left, h), baseline=b) + res = stringPict(*lparen.right(self)) if right: rparen = stringPict(vobj(right, h), baseline=b) - res = stringPict(*res.right(rparen)) + res = stringPict(*res.right(rparen)) return ('\n'.join(res.picture), res.baseline) @@ -200,11 +203,11 @@ # XXX not used anywhere ? height = max( self.baseline, - self.height()-1-self.baseline)*2 + 1 + self.height() - 1 - self.baseline)*2 + 1 slash = '\n'.join( - ' '*(height-i-1)+xobj('/',1)+' '*i + ' '*(height - i - 1) + xobj('/', 1) + ' '*i for i in range(height) - ) + ) return self.left(stringPict(slash, height//2)) def root(self, n=None): @@ -218,18 +221,18 @@ #construct right half of root symbol height = self.height() slash = '\n'.join( - ' ' * (height-i-1) + '/' + ' ' * i + ' ' * (height - i - 1) + '/' + ' ' * i for i in range(height) - ) - slash = stringPict(slash, height-1) + ) + slash = stringPict(slash, height - 1) #left half of root symbol if height > 2: - downline = stringPict('\\ \n \\',1) + downline = stringPict('\\ \n \\', 1) else: downline = stringPict('\\') #put n on top, as low as possible - if n is not None and n.width()>downline.width(): - downline = downline.left(' '*(n.width()-downline.width())) + if n is not None and n.width() > downline.width(): + downline = downline.left(' '*(n.width() - downline.width())) downline = downline.above(n) #build root symbol root = downline.right(slash) @@ -238,7 +241,7 @@ #which is one less than result #this moves the root symbol one down #if the root became higher, the baseline has to grow too - root.baseline = result.baseline-result.height()+root.height() + root.baseline = result.baseline - result.height() + root.height() return result.left(root) def render(self, * args, **kwargs): @@ -276,18 +279,18 @@ # 4*y*x + x + y | + b*c*f + b*d*e + b | | # | | | # | *d*f - do_vspacers = (self.height() > 1) i = 0 svals = [] + do_vspacers = (self.height() > 1) while i < self.width(): - svals.extend([ sval[i:i+ncols] for sval in self.picture ]) - if (self.height() > 1): - svals.append("") # a vertical spacer + svals.extend([ sval[i:i + ncols] for sval in self.picture ]) + if do_vspacers: + svals.append("") # a vertical spacer i += ncols if svals[-1] == '': - del svals[-1] # Get rid of the last spacer + del svals[-1] # Get rid of the last spacer return "\n".join(svals) @@ -342,7 +345,7 @@ return str.join('\n', self.picture) def __repr__(self): - return "stringPict(%r,%d)"%('\n'.join(self.picture), self.baseline) + return "stringPict(%r,%d)" % ('\n'.join(self.picture), self.baseline) def __getitem__(self, index): return self.picture[index] @@ -350,9 +353,11 @@ def __len__(self): return len(self.s) + class prettyForm(stringPict): - """Extension of the stringPict class that knows about - basic math applications, optimizing double minus signs. + """ + Extension of the stringPict class that knows about basic math applications, + optimizing double minus signs. "Binding" is interpreted as follows:: @@ -362,10 +367,12 @@ POW this is a power: only parenthesize if exponent MUL this is a multiplication: parenthesize if powered ADD this is an addition: parenthesize if multiplied or powered - NEG this is a negative number: optimize if added, parenthesize if multiplied or powered - + NEG this is a negative number: optimize if added, parenthesize if + multiplied or powered + OPEN this is an open object: parenthesize if added, multiplied, or + powered (example: Piecewise) """ - ATOM, FUNC, DIV, POW, MUL, ADD, NEG = list(range(7)) + ATOM, FUNC, DIV, POW, MUL, ADD, NEG, OPEN = list(range(8)) def __init__(self, s, baseline=0, binding=0, str=None): """Initialize from stringPict and binding power.""" @@ -373,12 +380,15 @@ self.binding = binding self.str = str or s + # Note: code to handle subtraction is in _print_Add + def __add__(self, *others): """Make a pretty addition. Addition of negative numbers is simplified. """ arg = self - if arg.binding > prettyForm.NEG: arg = stringPict(*arg.parens()) + if arg.binding > prettyForm.NEG: + arg = stringPict(*arg.parens()) result = [arg] for arg in others: #add parentheses for weak binders @@ -390,13 +400,19 @@ result.append(arg) return prettyForm(binding=prettyForm.ADD, *stringPict.next(*result)) - def __div__(self, den, slashed = False): + def __div__(self, den, slashed=False): """Make a pretty division; stacked or slashed. """ - if slashed: raise NotImplementedError("Can't do slashed fraction yet") + if slashed: + raise NotImplementedError("Can't do slashed fraction yet") num = self - if num.binding==prettyForm.DIV: num = stringPict(*num.parens()) - if den.binding==prettyForm.DIV: den = stringPict(*den.parens()) + if num.binding == prettyForm.DIV: + num = stringPict(*num.parens()) + if den.binding == prettyForm.DIV: + den = stringPict(*den.parens()) + + if num.binding==prettyForm.NEG: + num = num.right(" ")[0] return prettyForm(binding=prettyForm.DIV, *stringPict.stack( num, @@ -410,30 +426,36 @@ """Make a pretty multiplication. Parentheses are needed around +, - and neg. """ + if len(others) == 0: + return self # We aren't actually multiplying... So nothing to do here. + args = self - if args.binding > prettyForm.MUL: arg = stringPict(*args.parens()) + if args.binding > prettyForm.MUL: + arg = stringPict(*args.parens()) result = [args] for arg in others: result.append(xsym('*')) #add parentheses for weak binders - if arg.binding > prettyForm.MUL: arg = stringPict(*arg.parens()) + if arg.binding > prettyForm.MUL: + arg = stringPict(*arg.parens()) result.append(arg) len_res = len(result) for i in range(len_res): - if i < len_res-1 and result[i] == '-1' and result[i+1] == xsym('*'): + if i < len_res - 1 and result[i] == '-1' and result[i + 1] == xsym('*'): # substitute -1 by -, like in -1*x -> -x result.pop(i) result.pop(i) result.insert(i, '-') if result[0][0] == '-': # if there is a - sign in front of all + # This test was failing to catch a prettyForm.__mul__(prettyForm("-1", 0, 6)) being negative bin = prettyForm.NEG else: bin = prettyForm.MUL return prettyForm(binding=bin, *stringPict.next(*result)) def __repr__(self): - return "prettyForm(%r,%d,%d)"%( + return "prettyForm(%r,%d,%d)" % ( '\n'.join(self.picture), self.baseline, self.binding) @@ -442,16 +464,17 @@ """Make a pretty power. """ a = self - if a.binding > prettyForm.FUNC: a = stringPict(*a.parens()) - if b.binding == prettyForm.POW: b = stringPict(*b.parens()) + if a.binding > prettyForm.FUNC: + a = stringPict(*a.parens()) + if b.binding == prettyForm.POW: + b = stringPict(*b.parens()) if a.binding == prettyForm.FUNC: - # 2 <-- top - # sin (x) <-- bot - top = stringPict(*b.left(' '*a.prettyFunc.width())) - top = stringPict(*top.right(' '*a.prettyArgs.width())) - bot = stringPict(*a.prettyFunc.right(' '*b.width())) - bot = stringPict(*bot.right(a.prettyArgs)) + # 2 + # sin + + (x) + b.baseline = a.prettyFunc.baseline + 1 + func = stringPict(*a.prettyFunc.right(b)) + return prettyForm(*func.right(a.prettyArgs)) else: # 2 <-- top # (x+y) <-- bot @@ -461,17 +484,19 @@ return prettyForm(binding=prettyForm.POW, *bot.above(top)) simpleFunctions = ["sin", "cos", "tan"] + @staticmethod def apply(function, *args): """Functions of one or more variables. """ if function in prettyForm.simpleFunctions: #simple function: use only space if possible - assert len(args)==1, "Simple function %s must have 1 argument"%function + assert len( + args) == 1, "Simple function %s must have 1 argument" % function arg = args[0].__pretty__() if arg.binding <= prettyForm.DIV: #optimization: no parentheses necessary - return prettyForm(binding=prettyForm.FUNC, *arg.left(function+' ')) + return prettyForm(binding=prettyForm.FUNC, *arg.left(function + ' ')) argumentList = [] for arg in args: argumentList.append(',') diff -Nru python3-sympy-0.7.2/sympy/printing/pretty/tests/test_pretty.py python3-sympy-0.7.3/sympy/printing/pretty/tests/test_pretty.py --- python3-sympy-0.7.2/sympy/printing/pretty/tests/test_pretty.py 2012-10-17 03:02:22.000000000 +0000 +++ python3-sympy-0.7.3/sympy/printing/pretty/tests/test_pretty.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,20 +1,22 @@ # -*- coding: utf-8 -*- -from sympy import (Basic, Matrix, Piecewise, Ne, symbols, sqrt, Function, - Rational, conjugate, Derivative, tan, Function, log, floor, Symbol, Tuple, - pprint, sqrt, factorial, factorial2, binomial, pi, sin, ceiling, pprint_use_unicode, - I, S, Limit, oo, cos, atan2, Pow, Integral, exp, Eq, Lt, Gt, Ge, Le, gamma, Abs, - RootOf, RootSum, Lambda, Not, And, Or, Xor, Nand, Nor, Implies, Equivalent, - Sum, Subs, FF, ZZ, QQ, RR, O, uppergamma, lowergamma, hyper, meijerg, Dict, - euler, groebner, catalan, Product, KroneckerDelta, Ei, expint, Shi, Chi, Si, - Ci, Segment, Ray, FiniteSet, homomorphism) +from sympy import ( + Abs, And, Basic, Chi, Ci, Derivative, Dict, Ei, Eq, Equivalent, FF, + FiniteSet, Function, Ge, Gt, I, Implies, Integral, KroneckerDelta, + Lambda, Le, Limit, Lt, Matrix, Mul, Nand, Ne, Nor, Not, O, Or, + Piecewise, Pow, Product, QQ, RR, Rational, Ray, RootOf, RootSum, S, + Segment, Shi, Si, Subs, Sum, Symbol, Tuple, Xor, ZZ, atan2, binomial, + catalan, ceiling, conjugate, cos, euler, exp, expint, factorial, + factorial2, floor, gamma, groebner, homomorphism, hyper, log, + lowergamma, meijerg, oo, pi, sin, sqrt, subfactorial, symbols, tan, + uppergamma, elliptic_k, elliptic_f, elliptic_e, elliptic_pi) from sympy.printing.pretty import pretty as xpretty from sympy.printing.pretty import pprint from sympy.physics.units import joule -from sympy.utilities.pytest import raises, XFAIL +from sympy.utilities.pytest import raises from sympy.core.trace import Tr a, b, x, y, z, k = symbols('a,b,x,y,z,k') @@ -81,6 +83,8 @@ Abs(1 / (y - Abs(x))) factorial(n) factorial(2*n) +subfactorial(n) +subfactorial(2*n) factorial(factorial(factorial(n))) factorial(n+1) # conjugate(x) @@ -186,6 +190,7 @@ """ + def pretty(expr, order=None): """ASCII pretty-printing""" return xpretty(expr, order=order, use_unicode=False, wrap_line=False) @@ -224,60 +229,61 @@ assert pretty( "xxx'xxx" ) in ['"xxx\'xxx"', 'xxx\'xxx'] assert pretty( "xxx\'xxx" ) in ['"xxx\'xxx"', 'xxx\'xxx'] assert pretty( "xxx\"xxx" ) in ["'xxx\"xxx'", 'xxx\"xxx'] - assert pretty( "xxx\"xxx\'xxx" ) in ['\'xxx"xxx\\\'xxx\'', 'xxx"xxx\'xxx'] + assert pretty( + "xxx\"xxx\'xxx" ) in ['\'xxx"xxx\\\'xxx\'', 'xxx"xxx\'xxx'] assert pretty( "xxx\nxxx" ) in ["'xxx\nxxx'", 'xxx\nxxx'] def test_upretty_greek(): assert upretty( oo ) == '∞' - assert upretty( Symbol('alpha^+_1') ) == 'α⁺₁' - assert upretty( Symbol('beta') ) == 'β' + assert upretty( Symbol('alpha^+_1') ) == 'α⁺₁' + assert upretty( Symbol('beta') ) == 'β' assert upretty(Symbol('lambda')) == 'λ' def test_upretty_multiindex(): - assert upretty( Symbol('beta12') ) == 'β₁₂' - assert upretty( Symbol('Y00') ) == 'Y₀₀' - assert upretty( Symbol('Y_00') ) == 'Y₀₀' - assert upretty( Symbol('F^+-') ) == 'F⁺⁻' + assert upretty( Symbol('beta12') ) == 'β₁₂' + assert upretty( Symbol('Y00') ) == 'Y₀₀' + assert upretty( Symbol('Y_00') ) == 'Y₀₀' + assert upretty( Symbol('F^+-') ) == 'F⁺⁻' def test_upretty_sub_super(): - assert upretty( Symbol('beta_1_2') ) == 'β₁ ₂' - assert upretty( Symbol('beta^1^2') ) == 'β¹ ²' - assert upretty( Symbol('beta_1^2') ) == 'β²₁' - assert upretty( Symbol('beta_10_20') ) == 'β₁₀ ₂₀' - assert upretty( Symbol('beta_ax_gamma^i') ) == 'βⁱₐₓ ᵧ' - assert upretty( Symbol("F^1^2_3_4") ) == 'F¹ ²₃ ₄' - assert upretty( Symbol("F_1_2^3^4") ) == 'F³ ⁴₁ ₂' - assert upretty( Symbol("F_1_2_3_4") ) == 'F₁ ₂ ₃ ₄' - assert upretty( Symbol("F^1^2^3^4") ) == 'F¹ ² ³ ⁴' + assert upretty( Symbol('beta_1_2') ) == 'β₁ ₂' + assert upretty( Symbol('beta^1^2') ) == 'β¹ ²' + assert upretty( Symbol('beta_1^2') ) == 'β²₁' + assert upretty( Symbol('beta_10_20') ) == 'β₁₀ ₂₀' + assert upretty( Symbol('beta_ax_gamma^i') ) == 'βⁱₐₓ ᵧ' + assert upretty( Symbol("F^1^2_3_4") ) == 'F¹ ²₃ ₄' + assert upretty( Symbol("F_1_2^3^4") ) == 'F³ ⁴₁ ₂' + assert upretty( Symbol("F_1_2_3_4") ) == 'F₁ ₂ ₃ ₄' + assert upretty( Symbol("F^1^2^3^4") ) == 'F¹ ² ³ ⁴' def test_upretty_subs_missingin_24(): - assert upretty( Symbol('F_beta') ) == 'Fᵦ' + assert upretty( Symbol('F_beta') ) == 'Fᵦ' assert upretty( Symbol('F_gamma') ) == 'Fᵧ' - assert upretty( Symbol('F_rho') ) == 'Fᵨ' - assert upretty( Symbol('F_phi') ) == 'Fᵩ' - assert upretty( Symbol('F_chi') ) == 'Fᵪ' - - assert upretty( Symbol('F_a') ) == 'Fₐ' - assert upretty( Symbol('F_e') ) == 'Fₑ' - assert upretty( Symbol('F_i') ) == 'Fᵢ' - assert upretty( Symbol('F_o') ) == 'Fₒ' - assert upretty( Symbol('F_u') ) == 'Fᵤ' - assert upretty( Symbol('F_r') ) == 'Fᵣ' - assert upretty( Symbol('F_v') ) == 'Fᵥ' - assert upretty( Symbol('F_x') ) == 'Fₓ' + assert upretty( Symbol('F_rho') ) == 'Fᵨ' + assert upretty( Symbol('F_phi') ) == 'Fᵩ' + assert upretty( Symbol('F_chi') ) == 'Fᵪ' + + assert upretty( Symbol('F_a') ) == 'Fₐ' + assert upretty( Symbol('F_e') ) == 'Fₑ' + assert upretty( Symbol('F_i') ) == 'Fᵢ' + assert upretty( Symbol('F_o') ) == 'Fₒ' + assert upretty( Symbol('F_u') ) == 'Fᵤ' + assert upretty( Symbol('F_r') ) == 'Fᵣ' + assert upretty( Symbol('F_v') ) == 'Fᵥ' + assert upretty( Symbol('F_x') ) == 'Fₓ' def test_pretty_basic(): assert pretty( -Rational(1)/2 ) == '-1/2' assert pretty( -Rational(13)/22 ) == \ """\ - 13\n\ -- --\n\ - 22\ +-13 \n\ +----\n\ + 22 \ """ expr = oo ascii_str = \ @@ -288,7 +294,7 @@ """\ ∞\ """ - assert pretty(expr) == ascii_str + assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = (x**2) @@ -302,7 +308,7 @@ 2\n\ x \ """ - assert pretty(expr) == ascii_str + assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = 1/x @@ -318,7 +324,7 @@ ─\n\ x\ """ - assert pretty(expr) == ascii_str + assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = y*x**-2 @@ -336,10 +342,10 @@ 2\n\ x \ """ - assert pretty(expr) == ascii_str + assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str - expr = x**Rational(-5,2) + expr = x**Rational(-5, 2) ascii_str = \ """\ 1 \n\ @@ -354,7 +360,7 @@ 5/2\n\ x \ """ - assert pretty(expr) == ascii_str + assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = (-2)**x @@ -368,7 +374,7 @@ x\n\ (-2) \ """ - assert pretty(expr) == ascii_str + assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str # See issue 1824 @@ -383,7 +389,7 @@ 1\n\ 3 \ """ - assert pretty(expr) == ascii_str + assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = (x**2 + x + 1) @@ -417,10 +423,10 @@ 2 \n\ x + 1 + x\ """ - assert pretty(expr) in [ascii_str_1, ascii_str_2, ascii_str_3] + assert pretty(expr) in [ascii_str_1, ascii_str_2, ascii_str_3] assert upretty(expr) in [ucode_str_1, ucode_str_2, ucode_str_3] - expr = 1-x + expr = 1 - x ascii_str_1 = \ """\ 1 - x\ @@ -437,10 +443,10 @@ """\ -x + 1\ """ - assert pretty(expr) in [ascii_str_1, ascii_str_2] + assert pretty(expr) in [ascii_str_1, ascii_str_2] assert upretty(expr) in [ucode_str_1, ucode_str_2] - expr = 1-2*x + expr = 1 - 2*x ascii_str_1 = \ """\ 1 - 2*x\ @@ -457,7 +463,7 @@ """\ -2⋅x + 1\ """ - assert pretty(expr) in [ascii_str_1, ascii_str_2] + assert pretty(expr) in [ascii_str_1, ascii_str_2] assert upretty(expr) in [ucode_str_1, ucode_str_2] expr = x/y @@ -473,26 +479,26 @@ ─\n\ y\ """ - assert pretty(expr) == ascii_str + assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = -x/y ascii_str = \ """\ --x\n\ ---\n\ -y \ +-x \n\ +---\n\ + y \ """ ucode_str = \ """\ --x\n\ -──\n\ -y \ +-x \n\ +───\n\ + y \ """ - assert pretty(expr) == ascii_str + assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str - expr = (x+2)/y + expr = (x + 2)/y ascii_str_1 = \ """\ 2 + x\n\ @@ -517,10 +523,10 @@ ─────\n\ y \ """ - assert pretty(expr) in [ascii_str_1, ascii_str_2] + assert pretty(expr) in [ascii_str_1, ascii_str_2] assert upretty(expr) in [ucode_str_1, ucode_str_2] - expr = (1+x)*y + expr = (1 + x)*y ascii_str_1 = \ """\ y*(1 + x)\ @@ -545,36 +551,36 @@ """\ y⋅(x + 1)\ """ - assert pretty(expr) in [ascii_str_1, ascii_str_2, ascii_str_3] + assert pretty(expr) in [ascii_str_1, ascii_str_2, ascii_str_3] assert upretty(expr) in [ucode_str_1, ucode_str_2, ucode_str_3] # Test for correct placement of the negative sign - expr = -5*x/(x+10) + expr = -5*x/(x + 10) ascii_str_1 = \ """\ - -5*x \n\ +-5*x \n\ ------\n\ 10 + x\ """ ascii_str_2 = \ """\ - -5*x \n\ +-5*x \n\ ------\n\ x + 10\ """ ucode_str_1 = \ """\ - -5⋅x \n\ +-5⋅x \n\ ──────\n\ 10 + x\ """ ucode_str_2 = \ """\ - -5⋅x \n\ +-5⋅x \n\ ──────\n\ x + 10\ """ - assert pretty(expr) in [ascii_str_1, ascii_str_2] + assert pretty(expr) in [ascii_str_1, ascii_str_2] assert upretty(expr) in [ucode_str_1, ucode_str_2] expr = -S(1)/2 - 3*x @@ -586,7 +592,7 @@ """\ -3⋅x - 1/2\ """ - assert pretty(expr) == ascii_str + assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = S(1)/2 - 3*x @@ -598,7 +604,7 @@ """\ -3⋅x + 1/2\ """ - assert pretty(expr) == ascii_str + assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = -S(1)/2 - 3*x/2 @@ -614,7 +620,7 @@ - ─── - ─\n\ 2 2\ """ - assert pretty(expr) == ascii_str + assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = S(1)/2 - 3*x/2 @@ -630,7 +636,172 @@ - ─── + ─\n\ 2 2\ """ - assert pretty(expr) == ascii_str + assert pretty(expr) == ascii_str + assert upretty(expr) == ucode_str + + +def test_negative_fractions(): + expr = -x/y + ascii_str =\ +"""\ +-x \n\ +---\n\ + y \ +""" + ucode_str =\ +"""\ +-x \n\ +───\n\ + y \ +""" + assert pretty(expr) == ascii_str + assert upretty(expr) == ucode_str + expr = -x*z/y + ascii_str =\ +"""\ +-x*z \n\ +-----\n\ + y \ +""" + ucode_str =\ +"""\ +-x⋅z \n\ +─────\n\ + y \ +""" + assert pretty(expr) == ascii_str + assert upretty(expr) == ucode_str + expr = x**2/y + ascii_str =\ +"""\ + 2\n\ +x \n\ +--\n\ +y \ +""" + ucode_str =\ +"""\ + 2\n\ +x \n\ +──\n\ +y \ +""" + assert pretty(expr) == ascii_str + assert upretty(expr) == ucode_str + expr = -x**2/y + ascii_str =\ +"""\ + 2 \n\ +-x \n\ +----\n\ + y \ +""" + ucode_str =\ +"""\ + 2 \n\ +-x \n\ +────\n\ + y \ +""" + assert pretty(expr) == ascii_str + assert upretty(expr) == ucode_str + expr = -x/(y*z) + ascii_str =\ +"""\ +-x \n\ +---\n\ +y*z\ +""" + ucode_str =\ +"""\ +-x \n\ +───\n\ +y⋅z\ +""" + assert pretty(expr) == ascii_str + assert upretty(expr) == ucode_str + expr = -a/y**2 + ascii_str =\ +"""\ +-a \n\ +---\n\ + 2\n\ + y \ +""" + ucode_str =\ +"""\ +-a \n\ +───\n\ + 2\n\ + y \ +""" + assert pretty(expr) == ascii_str + assert upretty(expr) == ucode_str + expr = y**(-a/b) + ascii_str =\ +"""\ + -a \n\ + ---\n\ + b \n\ +y \ +""" + ucode_str =\ +"""\ + -a \n\ + ───\n\ + b \n\ +y \ +""" + assert pretty(expr) == ascii_str + assert upretty(expr) == ucode_str + expr = -1/y**2 + ascii_str =\ +"""\ +-1 \n\ +---\n\ + 2\n\ + y \ +""" + ucode_str =\ +"""\ +-1 \n\ +───\n\ + 2\n\ + y \ +""" + assert pretty(expr) == ascii_str + assert upretty(expr) == ucode_str + expr = -10/b**2 + ascii_str =\ +"""\ +-10 \n\ +----\n\ + 2 \n\ + b \ +""" + ucode_str =\ +"""\ +-10 \n\ +────\n\ + 2 \n\ + b \ +""" + assert pretty(expr) == ascii_str + assert upretty(expr) == ucode_str + expr = Rational(-200, 37) + ascii_str =\ +"""\ +-200 \n\ +-----\n\ + 37 \ +""" + ucode_str =\ +"""\ +-200 \n\ +─────\n\ + 37 \ +""" + assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str def test_issue_2425(): @@ -646,6 +817,7 @@ (x - 5)⋅⎝-x - 2⋅╲╱ 2 + 5⎠ - (-y + 5) \ """ + def test_pretty_ordering(): assert pretty(x**2 + x + 1, order='lex') == \ """\ @@ -695,15 +867,16 @@ x - ── + ─── + O⎝x ⎠\n\ 6 120 \ """ - assert pretty(expr, order=None) == ascii_str + assert pretty(expr, order=None) == ascii_str assert upretty(expr, order=None) == ucode_str - assert pretty(expr, order='lex') == ascii_str + assert pretty(expr, order='lex') == ascii_str assert upretty(expr, order='lex') == ucode_str - assert pretty(expr, order='rev-lex') == ascii_str + assert pretty(expr, order='rev-lex') == ascii_str assert upretty(expr, order='rev-lex') == ucode_str + def test_pretty_relational(): expr = Eq(x, y) ascii_str = \ @@ -714,7 +887,7 @@ """\ x = y\ """ - assert pretty(expr) == ascii_str + assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = Lt(x, y) @@ -726,7 +899,7 @@ """\ x < y\ """ - assert pretty(expr) == ascii_str + assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = Gt(x, y) @@ -738,7 +911,7 @@ """\ x > y\ """ - assert pretty(expr) == ascii_str + assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = Le(x, y) @@ -750,7 +923,7 @@ """\ x ≤ y\ """ - assert pretty(expr) == ascii_str + assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = Ge(x, y) @@ -762,10 +935,10 @@ """\ x ≥ y\ """ - assert pretty(expr) == ascii_str + assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str - expr = Ne(x/(y+1), y**2) + expr = Ne(x/(y + 1), y**2) ascii_str_1 = \ """\ x 2\n\ @@ -790,7 +963,7 @@ ───── ≠ y \n\ y + 1 \ """ - assert pretty(expr) in [ascii_str_1, ascii_str_2] + assert pretty(expr) in [ascii_str_1, ascii_str_2] assert upretty(expr) in [ucode_str_1, ucode_str_2] @@ -810,10 +983,10 @@ 2\n\ x \ """ - assert pretty(expr) == ascii_str + assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str - expr = y**Rational(3,2) * x**Rational(-5,2) + expr = y**Rational(3, 2) * x**Rational(-5, 2) ascii_str = \ """\ 3/2\n\ @@ -830,7 +1003,7 @@ 5/2\n\ x \ """ - assert pretty(expr) == ascii_str + assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = sin(x)**3/tan(x)**2 @@ -850,7 +1023,7 @@ 2 \n\ tan (x)\ """ - assert pretty(expr) == ascii_str + assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str @@ -877,7 +1050,7 @@ x \n\ ℯ + 2⋅x\ """ - assert pretty(expr) in [ascii_str_1, ascii_str_2] + assert pretty(expr) in [ascii_str_1, ascii_str_2] assert upretty(expr) in [ucode_str_1, ucode_str_2] expr = Abs(x) @@ -889,10 +1062,10 @@ """\ │x│\ """ - assert pretty(expr) == ascii_str + assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str - expr = Abs(x/(x**2+1)) + expr = Abs(x/(x**2 + 1)) ascii_str_1 = \ """\ | x |\n\ @@ -921,7 +1094,7 @@ │ 2 │\n\ │x + 1│\ """ - assert pretty(expr) in [ascii_str_1, ascii_str_2] + assert pretty(expr) in [ascii_str_1, ascii_str_2] assert upretty(expr) in [ucode_str_1, ucode_str_2] expr = Abs(1 / (y - Abs(x))) @@ -937,7 +1110,7 @@ │───────│\n\ │y - │x││\ """ - assert pretty(expr) == ascii_str + assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str n = Symbol('n', integer=True) @@ -950,10 +1123,9 @@ """\ n!\ """ - assert pretty(expr) == ascii_str + assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str - expr = factorial(2*n) ascii_str = \ """\ @@ -963,7 +1135,7 @@ """\ (2⋅n)!\ """ - assert pretty(expr) == ascii_str + assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = factorial(factorial(factorial(n))) @@ -975,10 +1147,10 @@ """\ ((n!)!)!\ """ - assert pretty(expr) == ascii_str + assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str - expr = factorial(n+1) + expr = factorial(n + 1) ascii_str_1 = \ """\ (1 + n)!\ @@ -996,9 +1168,33 @@ (n + 1)!\ """ - assert pretty(expr) in [ascii_str_1, ascii_str_2] + assert pretty(expr) in [ascii_str_1, ascii_str_2] assert upretty(expr) in [ucode_str_1, ucode_str_2] + expr = subfactorial(n) + ascii_str = \ +"""\ +!n\ +""" + ucode_str = \ +"""\ +!n\ +""" + assert pretty(expr) == ascii_str + assert upretty(expr) == ucode_str + + expr = subfactorial(2*n) + ascii_str = \ +"""\ +!(2*n)\ +""" + ucode_str = \ +"""\ +!(2⋅n)\ +""" + assert pretty(expr) == ascii_str + assert upretty(expr) == ucode_str + n = Symbol('n', integer=True) expr = factorial2(n) ascii_str = \ @@ -1009,7 +1205,7 @@ """\ n!!\ """ - assert pretty(expr) == ascii_str + assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = factorial2(2*n) @@ -1021,7 +1217,7 @@ """\ (2⋅n)!!\ """ - assert pretty(expr) == ascii_str + assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = factorial2(factorial2(factorial2(n))) @@ -1033,10 +1229,10 @@ """\ ((n!!)!!)!!\ """ - assert pretty(expr) == ascii_str + assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str - expr = factorial2(n+1) + expr = factorial2(n + 1) ascii_str_1 = \ """\ (1 + n)!!\ @@ -1054,7 +1250,7 @@ (n + 1)!!\ """ - assert pretty(expr) in [ascii_str_1, ascii_str_2] + assert pretty(expr) in [ascii_str_1, ascii_str_2] assert upretty(expr) in [ucode_str_1, ucode_str_2] expr = 2*binomial(n, k) @@ -1071,7 +1267,7 @@ ⎝k⎠\ """ - assert pretty(expr) == ascii_str + assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = 2*binomial(2*n, k) @@ -1088,7 +1284,7 @@ ⎝ k ⎠\ """ - assert pretty(expr) == ascii_str + assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = 2*binomial(n**2, k) @@ -1107,7 +1303,7 @@ ⎝k ⎠\ """ - assert pretty(expr) == ascii_str + assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = catalan(n) @@ -1121,7 +1317,7 @@ C \n\ n\ """ - assert pretty(expr) == ascii_str + assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = conjugate(x) @@ -1135,11 +1331,11 @@ _\n\ x\ """ - assert pretty(expr) == ascii_str + assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str f = Function('f') - expr = conjugate(f(x+1)) + expr = conjugate(f(x + 1)) ascii_str_1 = \ """\ ________\n\ @@ -1160,7 +1356,7 @@ ________\n\ f(x + 1)\ """ - assert pretty(expr) in [ascii_str_1, ascii_str_2] + assert pretty(expr) in [ascii_str_1, ascii_str_2] assert upretty(expr) in [ucode_str_1, ucode_str_2] expr = f(x) @@ -1172,7 +1368,7 @@ """\ f(x)\ """ - assert pretty(expr) == ascii_str + assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = f(x, y) @@ -1184,10 +1380,10 @@ """\ f(x, y)\ """ - assert pretty(expr) == ascii_str + assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str - expr = f(x/(y+1), y) + expr = f(x/(y + 1), y) ascii_str_1 = \ """\ / x \\\n\ @@ -1212,7 +1408,7 @@ f⎜─────, y⎟\n\ ⎝y + 1 ⎠\ """ - assert pretty(expr) in [ascii_str_1, ascii_str_2] + assert pretty(expr) in [ascii_str_1, ascii_str_2] assert upretty(expr) in [ucode_str_1, ucode_str_2] expr = sin(x)**2 @@ -1226,10 +1422,10 @@ 2 \n\ sin (x)\ """ - assert pretty(expr) == ascii_str + assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str - expr = conjugate(a+b*I) + expr = conjugate(a + b*I) ascii_str = \ """\ _ _\n\ @@ -1240,10 +1436,10 @@ _ _\n\ a - ⅈ⋅b\ """ - assert pretty(expr) == ascii_str + assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str - expr = conjugate(exp(a+b*I)) + expr = conjugate(exp(a + b*I)) ascii_str = \ """\ _ _\n\ @@ -1256,7 +1452,7 @@ a - ⅈ⋅b\n\ ℯ \ """ - assert pretty(expr) == ascii_str + assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = conjugate( f(1 + conjugate(f(x))) ) @@ -1284,10 +1480,10 @@ ⎛____ ⎞\n\ f⎝f(x) + 1⎠\ """ - assert pretty(expr) in [ascii_str_1, ascii_str_2] + assert pretty(expr) in [ascii_str_1, ascii_str_2] assert upretty(expr) in [ucode_str_1, ucode_str_2] - expr = f(x/(y+1), y) + expr = f(x/(y + 1), y) ascii_str_1 = \ """\ / x \\\n\ @@ -1312,7 +1508,7 @@ f⎜─────, y⎟\n\ ⎝y + 1 ⎠\ """ - assert pretty(expr) in [ascii_str_1, ascii_str_2] + assert pretty(expr) in [ascii_str_1, ascii_str_2] assert upretty(expr) in [ucode_str_1, ucode_str_2] expr = floor(1 / (y - floor(x))) @@ -1328,7 +1524,7 @@ ⎢───────⎥\n\ ⎣y - ⌊x⌋⎦\ """ - assert pretty(expr) == ascii_str + assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = ceiling(1 / (y - ceiling(x))) @@ -1344,7 +1540,7 @@ ⎢───────⎥\n\ ⎢y - ⌈x⌉⎥\ """ - assert pretty(expr) == ascii_str + assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = euler(n) @@ -1358,7 +1554,7 @@ E \n\ n\ """ - assert pretty(expr) == ascii_str + assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = euler(1/(1 + 1/(1 + 1/n))) @@ -1385,9 +1581,10 @@ 1 + ─\n\ n\ """ - assert pretty(expr) == ascii_str + assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str + def test_pretty_sqrt(): expr = sqrt(2) ascii_str = \ @@ -1400,10 +1597,10 @@ ___\n\ ╲╱ 2 \ """ - assert pretty(expr) == ascii_str + assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str - expr = 2**Rational(1,3) + expr = 2**Rational(1, 3) ascii_str = \ """\ 3 ___\n\ @@ -1414,10 +1611,10 @@ 3 ___\n\ ╲╱ 2 \ """ - assert pretty(expr) == ascii_str + assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str - expr = 2**Rational(1,1000) + expr = 2**Rational(1, 1000) ascii_str = \ """\ 1000___\n\ @@ -1428,7 +1625,7 @@ 1000___\n\ ╲╱ 2 \ """ - assert pretty(expr) == ascii_str + assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = sqrt(x**2 + 1) @@ -1444,10 +1641,10 @@ ╱ 2 \n\ ╲╱ x + 1 \ """ - assert pretty(expr) == ascii_str + assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str - expr = (1 + sqrt(5))**Rational(1,3) + expr = (1 + sqrt(5))**Rational(1, 3) ascii_str = \ """\ ___________\n\ @@ -1460,7 +1657,7 @@ 3 ╱ ___ \n\ ╲╱ 1 + ╲╱ 5 \ """ - assert pretty(expr) == ascii_str + assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = 2**(1/x) @@ -1474,10 +1671,10 @@ x ___\n\ ╲╱ 2 \ """ - assert pretty(expr) == ascii_str + assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str - expr = sqrt(2+pi) + expr = sqrt(2 + pi) ascii_str = \ """\ ________\n\ @@ -1488,10 +1685,11 @@ _______\n\ ╲╱ 2 + π \ """ - assert pretty(expr) == ascii_str + assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str - expr = (2+(1+x**2)/(2+x))**Rational(1,4)+(1+x**Rational(1,1000))/sqrt(3+x**2) + expr = (2 + ( + 1 + x**2)/(2 + x))**Rational(1, 4) + (1 + x**Rational(1, 1000))/sqrt(3 + x**2) ascii_str = \ """\ ____________ \n\ @@ -1512,12 +1710,13 @@ ╱ 2 \n\ ╲╱ x + 3 \ """ - assert pretty(expr) == ascii_str + assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str + def test_pretty_KroneckerDelta(): - x,y = symbols("x, y") - expr = KroneckerDelta(x,y) + x, y = symbols("x, y") + expr = KroneckerDelta(x, y) ascii_str = \ """\ d \n\ @@ -1531,6 +1730,7 @@ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str + def test_pretty_product(): n, m, k, l = symbols('n m k l') f = symbols('f', cls=Function) @@ -1590,6 +1790,7 @@ assert pretty(expr) == ascii_str assert upretty(expr) == unicode_str + def test_pretty_lambda(): expr = Lambda(x, x) ascii_str = \ @@ -1601,7 +1802,7 @@ Λ(x, x)\ """ - assert pretty(expr) == ascii_str + assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = Lambda(x, x**2) @@ -1616,24 +1817,22 @@ Λ⎝x, x ⎠\ """ - assert pretty(expr) == ascii_str + assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = Lambda(x, x**2)**2 ascii_str = \ """\ - 2 \n\ - / 2\\\n\ + 2/ 2\\\n\ Lambda \\x, x /\ """ ucode_str = \ """\ - 2 \n\ - ⎛ 2⎞\n\ + 2⎛ 2⎞\n\ Λ ⎝x, x ⎠\ """ - assert pretty(expr) == ascii_str + assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = Lambda((x, y), x) @@ -1646,7 +1845,7 @@ Λ((x, y), x)\ """ - assert pretty(expr) == ascii_str + assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = Lambda((x, y), x**2) @@ -1661,7 +1860,8 @@ Λ⎝(x, y), x ⎠\ """ - assert pretty(expr) == ascii_str + assert pretty(expr) == ascii_str + def test_pretty_order(): expr = O(1) @@ -1706,6 +1906,7 @@ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str + def test_pretty_derivatives(): # Simple expr = Derivative(log(x), x, evaluate=False) @@ -1721,7 +1922,7 @@ ──(log(x))\n\ dx \ """ - assert pretty(expr) == ascii_str + assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = Derivative(log(x), x, evaluate=False) + x @@ -1749,9 +1950,38 @@ ──(log(x)) + x\n\ dx \ """ - assert pretty(expr) in [ascii_str_1, ascii_str_2] + assert pretty(expr) in [ascii_str_1, ascii_str_2] assert upretty(expr) in [ucode_str_1, ucode_str_2] + # basic partial derivatives + expr = Derivative(log(x + y) + x, x) + ascii_str_1 = \ +"""\ +d \n\ +--(log(x + y) + x)\n\ +dx \ +""" + ascii_str_2 = \ +"""\ +d \n\ +--(x + log(x + y))\n\ +dx \ +""" + ucode_str_1 = \ +"""\ +∂ \n\ +──(log(x + y) + x)\n\ +∂x \ +""" + ucode_str_2 = \ +"""\ +∂ \n\ +──(x + log(x + y))\n\ +∂x \ +""" + assert pretty(expr) in [ascii_str_1, ascii_str_2] + assert upretty(expr) in [ucode_str_1, ucode_str_2], upretty(expr) + # Multiple symbols expr = Derivative(log(x) + x**2, x, y) ascii_str_1 = \ @@ -1782,7 +2012,7 @@ ─────⎝x + log(x)⎠\n\ dy dx \ """ - assert pretty(expr) in [ascii_str_1, ascii_str_2] + assert pretty(expr) in [ascii_str_1, ascii_str_2] assert upretty(expr) in [ucode_str_1, ucode_str_2] expr = Derivative(2*x*y, y, x) + x**2 @@ -1803,18 +2033,18 @@ ucode_str_1 = \ """\ 2 \n\ - d 2\n\ + ∂ 2\n\ ─────(2⋅x⋅y) + x \n\ -dx dy \ +∂x ∂y \ """ ucode_str_2 = \ """\ 2 \n\ - 2 d \n\ + 2 ∂ \n\ x + ─────(2⋅x⋅y)\n\ - dx dy \ + ∂x ∂y \ """ - assert pretty(expr) in [ascii_str_1, ascii_str_2] + assert pretty(expr) in [ascii_str_1, ascii_str_2] assert upretty(expr) in [ucode_str_1, ucode_str_2] expr = Derivative(2*x*y, x, x) @@ -1829,12 +2059,12 @@ ucode_str = \ """\ 2 \n\ - d \n\ + ∂ \n\ ───(2⋅x⋅y)\n\ 2 \n\ -dx \ +∂x \ """ - assert pretty(expr) == ascii_str + assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = Derivative(2*x*y, x, 17) @@ -1849,12 +2079,12 @@ ucode_str = \ """\ 17 \n\ -d \n\ +∂ \n\ ────(2⋅x⋅y)\n\ 17 \n\ -dx \ +∂x \ """ - assert pretty(expr) == ascii_str + assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = Derivative(2*x*y, x, x, y) @@ -1869,17 +2099,17 @@ ucode_str = \ """\ 3 \n\ - d \n\ + ∂ \n\ ──────(2⋅x⋅y)\n\ 2 \n\ -dy dx \ +∂y ∂x \ """ - assert pretty(expr) == ascii_str + assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str # Greek letters alpha = Symbol('alpha') - beta = Function('beta') + beta = Function('beta') expr = beta(alpha).diff(alpha) ascii_str = \ """\ @@ -1893,9 +2123,10 @@ ──(β(α))\n\ dα \ """ - assert pretty(expr) == ascii_str + assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str + def test_pretty_integrals(): expr = Integral(log(x), x) ascii_str = \ @@ -1912,7 +2143,7 @@ ⎮ log(x) dx\n\ ⌡ \ """ - assert pretty(expr) == ascii_str + assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = Integral(x**2, x) @@ -1932,7 +2163,7 @@ ⎮ x dx\n\ ⌡ \ """ - assert pretty(expr) == ascii_str + assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = Integral((sin(x))**2 / (tan(x))**2) @@ -1958,7 +2189,7 @@ ⎮ tan (x) \n\ ⌡ \ """ - assert pretty(expr) == ascii_str + assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = Integral(x**(2**x), x) @@ -1980,10 +2211,10 @@ ⎮ x dx\n\ ⌡ \ """ - assert pretty(expr) == ascii_str + assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str - expr = Integral(x**2, (x,1,2)) + expr = Integral(x**2, (x, 1, 2)) ascii_str = \ """\ 2 \n\ @@ -2004,10 +2235,10 @@ ⌡ \n\ 1 \ """ - assert pretty(expr) == ascii_str + assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str - expr = Integral(x**2, (x,Rational(1,2),10)) + expr = Integral(x**2, (x, Rational(1, 2), 10)) ascii_str = \ """\ 10 \n\ @@ -2028,10 +2259,10 @@ ⌡ \n\ 1/2 \ """ - assert pretty(expr) == ascii_str + assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str - expr = Integral(x**2*y**2, x,y) + expr = Integral(x**2*y**2, x, y) ascii_str = \ """\ / / \n\ @@ -2048,10 +2279,10 @@ ⎮ ⎮ x ⋅y dx dy\n\ ⌡ ⌡ \ """ - assert pretty(expr) == ascii_str + assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str - expr = Integral(sin(th)/cos(ph), (th,0,pi), (ph, 0, 2*pi)) + expr = Integral(sin(th)/cos(ph), (th, 0, pi), (ph, 0, 2*pi)) ascii_str = \ """\ 2*pi pi \n\ @@ -2074,7 +2305,7 @@ ⌡ ⌡ \n\ 0 0 \ """ - assert pretty(expr) == ascii_str + assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str @@ -2095,7 +2326,7 @@ unicode_str = "[]" assert pretty(expr) == ascii_str assert upretty(expr) == unicode_str - expr = Matrix([[x**2+1, 1], [y, x+y]]) + expr = Matrix([[x**2 + 1, 1], [y, x + y]]) ascii_str_1 = \ """\ [ 2 ] @@ -2124,7 +2355,7 @@ ⎢ ⎥ ⎣ y x + y⎦\ """ - assert pretty(expr) in [ascii_str_1, ascii_str_2] + assert pretty(expr) in [ascii_str_1, ascii_str_2] assert upretty(expr) in [ucode_str_1, ucode_str_2] expr = Matrix([[x/y, y, th], [0, exp(I*k*ph), 1]]) @@ -2146,12 +2377,46 @@ ⎢ ⅈ⋅k⋅φ ⎥ ⎣0 ℯ 1⎦\ """ - assert pretty(expr) == ascii_str + assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str +def test_Adjoint(): + from sympy.matrices import Adjoint, Inverse, MatrixSymbol, Transpose + X = MatrixSymbol('X', 2, 2) + Y = MatrixSymbol('Y', 2, 2) + assert pretty(Adjoint(X)) == " +\nX " + assert pretty(Adjoint(X + Y)) == " +\n(X + Y) " + assert pretty(Adjoint(X) + Adjoint(Y)) == " + +\nX + Y " + assert pretty(Adjoint(X*Y)) == " +\n(X*Y) " + assert pretty(Adjoint(Y)*Adjoint(X)) == " + +\nY *X " + assert pretty(Adjoint(X**2)) == " +\n/ 2\\ \n\\X / " + assert pretty(Adjoint(X)**2) == " 2\n/ +\\ \n\\X / " + assert pretty(Adjoint(Inverse(X))) == " +\n/ -1\\ \n\\X / " + assert pretty(Inverse(Adjoint(X))) == " -1\n/ +\\ \n\\X / " + assert pretty(Adjoint(Transpose(X))) == " +\n/ T\\ \n\\X / " + assert pretty(Transpose(Adjoint(X))) == " T\n/ +\\ \n\\X / " + assert upretty(Adjoint(X)) == " \u2020\nX " + assert upretty(Adjoint(X + Y)) == " \u2020\n(X + Y) " + assert upretty(Adjoint(X) + Adjoint(Y)) == " \u2020 \u2020\nX + Y " + assert upretty(Adjoint(X*Y)) == " \u2020\n(X\u22c5Y) " + assert upretty(Adjoint(Y)*Adjoint(X)) == " \u2020 \u2020\nY \u22c5X " + assert upretty(Adjoint(X**2)) == \ + " \u2020\n\u239b 2\u239e \n\u239dX \u23a0 " + assert upretty(Adjoint(X)**2) == \ + " 2\n\u239b \u2020\u239e \n\u239dX \u23a0 " + assert upretty(Adjoint(Inverse(X))) == \ + " \u2020\n\u239b -1\u239e \n\u239dX \u23a0 " + assert upretty(Inverse(Adjoint(X))) == \ + " -1\n\u239b \u2020\u239e \n\u239dX \u23a0 " + assert upretty(Adjoint(Transpose(X))) == \ + " \u2020\n\u239b T\u239e \n\u239dX \u23a0 " + assert upretty(Transpose(Adjoint(X))) == \ + " T\n\u239b \u2020\u239e \n\u239dX \u23a0 " + + def test_pretty_piecewise(): - expr = Piecewise((x,x<1),(x**2,True)) + expr = Piecewise((x, x < 1), (x**2, True)) ascii_str = \ """\ /x for x < 1\n\ @@ -2168,9 +2433,209 @@ ⎪x otherwise\n\ ⎩ \ """ - assert pretty(expr) == ascii_str + assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str + expr = -Piecewise((x, x < 1), (x**2, True)) + ascii_str = \ +"""\ + //x for x < 1\\\n\ + || |\n\ +-|< 2 |\n\ + ||x otherwise|\n\ + \\\\ /\ +""" + ucode_str = \ +"""\ + ⎛⎧x for x < 1⎞\n\ + ⎜⎪ ⎟\n\ +-⎜⎨ 2 ⎟\n\ + ⎜⎪x otherwise⎟\n\ + ⎝⎩ ⎠\ +""" + assert pretty(expr) == ascii_str + assert upretty(expr) == ucode_str + + expr = x + Piecewise((x, x > 0), (y, True)) + Piecewise((x/y, x < 2), + (y**2, x > 2), (1, True)) + 1 + ascii_str = \ +"""\ + //x \ \n\ + ||- for x < 2| \n\ + ||y | \n\ + //x for x > 0\ || | \n\ +x + |< | + |< 2 | + 1\n\ + \\\\y otherwise/ ||y for x > 2| \n\ + || | \n\ + ||1 otherwise| \n\ + \\\\ / \ +""" + ucode_str = \ +"""\ + ⎛⎧x ⎞ \n\ + ⎜⎪─ for x < 2⎟ \n\ + ⎜⎪y ⎟ \n\ + ⎛⎧x for x > 0⎞ ⎜⎪ ⎟ \n\ +x + ⎜⎨ ⎟ + ⎜⎨ 2 ⎟ + 1\n\ + ⎝⎩y otherwise⎠ ⎜⎪y for x > 2⎟ \n\ + ⎜⎪ ⎟ \n\ + ⎜⎪1 otherwise⎟ \n\ + ⎝⎩ ⎠ \ +""" + assert pretty(expr) == ascii_str + assert upretty(expr) == ucode_str + + expr = x - Piecewise((x, x > 0), (y, True)) + Piecewise((x/y, x < 2), + (y**2, x > 2), (1, True)) + 1 + ascii_str = \ +"""\ + //x \ \n\ + ||- for x < 2| \n\ + ||y | \n\ + //x for x > 0\ || | \n\ +x - |< | + |< 2 | + 1\n\ + \\\\y otherwise/ ||y for x > 2| \n\ + || | \n\ + ||1 otherwise| \n\ + \\\\ / \ +""" + ucode_str = \ +"""\ + ⎛⎧x ⎞ \n\ + ⎜⎪─ for x < 2⎟ \n\ + ⎜⎪y ⎟ \n\ + ⎛⎧x for x > 0⎞ ⎜⎪ ⎟ \n\ +x - ⎜⎨ ⎟ + ⎜⎨ 2 ⎟ + 1\n\ + ⎝⎩y otherwise⎠ ⎜⎪y for x > 2⎟ \n\ + ⎜⎪ ⎟ \n\ + ⎜⎪1 otherwise⎟ \n\ + ⎝⎩ ⎠ \ +""" + assert pretty(expr) == ascii_str + assert upretty(expr) == ucode_str + + expr = x*Piecewise((x, x > 0), (y, True)) + ascii_str = \ +"""\ + //x for x > 0\\\n\ +x*|< |\n\ + \\\\y otherwise/\ +""" + ucode_str = \ +"""\ + ⎛⎧x for x > 0⎞\n\ +x⋅⎜⎨ ⎟\n\ + ⎝⎩y otherwise⎠\ +""" + assert pretty(expr) == ascii_str + assert upretty(expr) == ucode_str + + expr = Piecewise((x, x > 0), (y, True))*Piecewise((x/y, x < 2), (y**2, x > + 2), (1, True)) + ascii_str = \ +"""\ + //x \\\n\ + ||- for x < 2|\n\ + ||y |\n\ +//x for x > 0\ || |\n\ +|< |*|< 2 |\n\ +\\\\y otherwise/ ||y for x > 2|\n\ + || |\n\ + ||1 otherwise|\n\ + \\\\ /\ +""" + ucode_str = \ +"""\ + ⎛⎧x ⎞\n\ + ⎜⎪─ for x < 2⎟\n\ + ⎜⎪y ⎟\n\ +⎛⎧x for x > 0⎞ ⎜⎪ ⎟\n\ +⎜⎨ ⎟⋅⎜⎨ 2 ⎟\n\ +⎝⎩y otherwise⎠ ⎜⎪y for x > 2⎟\n\ + ⎜⎪ ⎟\n\ + ⎜⎪1 otherwise⎟\n\ + ⎝⎩ ⎠\ +""" + assert pretty(expr) == ascii_str + assert upretty(expr) == ucode_str + + expr = -Piecewise((x, x > 0), (y, True))*Piecewise((x/y, x < 2), (y**2, x + > 2), (1, True)) + ascii_str = \ +"""\ + //x \\\n\ + ||- for x < 2|\n\ + ||y |\n\ + //x for x > 0\ || |\n\ +-|< |*|< 2 |\n\ + \\\\y otherwise/ ||y for x > 2|\n\ + || |\n\ + ||1 otherwise|\n\ + \\\\ /\ +""" + ucode_str = \ +"""\ + ⎛⎧x ⎞\n\ + ⎜⎪─ for x < 2⎟\n\ + ⎜⎪y ⎟\n\ + ⎛⎧x for x > 0⎞ ⎜⎪ ⎟\n\ +-⎜⎨ ⎟⋅⎜⎨ 2 ⎟\n\ + ⎝⎩y otherwise⎠ ⎜⎪y for x > 2⎟\n\ + ⎜⎪ ⎟\n\ + ⎜⎪1 otherwise⎟\n\ + ⎝⎩ ⎠\ +""" + assert pretty(expr) == ascii_str + assert upretty(expr) == ucode_str + + expr = Piecewise((0, Abs(1/y) < 1), (1, Abs(y) < 1), (y*meijerg(((2, 1), + ()), ((), (1, 0)), 1/y), True)) + ascii_str = \ +"""\ +/ |1| \n\ +| 0 for |-| < 1\n\ +| |y| \n\ +| \n\ +< 1 for |y| < 1\n\ +| \n\ +| __0, 2 /2, 1 | 1\ \n\ +|y*/__ | | -| otherwise \n\ +\ \\_|2, 2 \ 1, 0 | y/ \ +""" + ucode_str = \ +"""\ +⎧ │1│ \n\ +⎪ 0 for │─│ < 1\n\ +⎪ │y│ \n\ +⎪ \n\ +⎨ 1 for │y│ < 1\n\ +⎪ \n\ +⎪ ╭─╮0, 2 ⎛2, 1 │ 1⎞ \n\ +⎪y⋅│╶┐ ⎜ │ ─⎟ otherwise \n\ +⎩ ╰─╯2, 2 ⎝ 1, 0 │ y⎠ \ +""" + assert pretty(expr) == ascii_str + assert upretty(expr) == ucode_str + + # XXX: We have to use evaluate=False here because Piecewise._eval_power + # denests the power. + expr = Pow(Piecewise((x, x > 0), (y, True)), 2, evaluate=False) + ascii_str = \ +"""\ + 2\n\ +//x for x > 0\ \n\ +|< | \n\ +\\\\y otherwise/ \ +""" + ucode_str = \ +"""\ + 2\n\ +⎛⎧x for x > 0⎞ \n\ +⎜⎨ ⎟ \n\ +⎝⎩y otherwise⎠ \ +""" + assert pretty(expr) == ascii_str + assert upretty(expr) == ucode_str def test_pretty_seq(): expr = () @@ -2182,7 +2647,7 @@ """\ ()\ """ - assert pretty(expr) == ascii_str + assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = [] @@ -2194,7 +2659,7 @@ """\ []\ """ - assert pretty(expr) == ascii_str + assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = {} @@ -2207,8 +2672,8 @@ """\ {}\ """ - assert pretty(expr) == ascii_str - assert pretty(expr_2) == ascii_str + assert pretty(expr) == ascii_str + assert pretty(expr_2) == ascii_str assert upretty(expr) == ucode_str assert upretty(expr_2) == ucode_str @@ -2225,7 +2690,7 @@ ⎜─,⎟\n\ ⎝x ⎠\ """ - assert pretty(expr) == ascii_str + assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = [x**2, 1/x, x, y, sin(th)**2/cos(ph)**2] @@ -2245,7 +2710,7 @@ ⎢ x 2 ⎥\n\ ⎣ cos (φ)⎦\ """ - assert pretty(expr) == ascii_str + assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = (x**2, 1/x, x, y, sin(th)**2/cos(ph)**2) @@ -2265,7 +2730,7 @@ ⎜ x 2 ⎟\n\ ⎝ cos (φ)⎠\ """ - assert pretty(expr) == ascii_str + assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = Tuple(x**2, 1/x, x, y, sin(th)**2/cos(ph)**2) @@ -2285,7 +2750,7 @@ ⎜ x 2 ⎟\n\ ⎝ cos (φ)⎠\ """ - assert pretty(expr) == ascii_str + assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = {x: sin(x)} @@ -2298,8 +2763,8 @@ """\ {x: sin(x)}\ """ - assert pretty(expr) == ascii_str - assert pretty(expr_2) == ascii_str + assert pretty(expr) == ascii_str + assert pretty(expr_2) == ascii_str assert upretty(expr) == ucode_str assert upretty(expr_2) == ucode_str @@ -2317,8 +2782,8 @@ ⎨─: ─, x: sin (x)⎬\n\ ⎩x y ⎭\ """ - assert pretty(expr) == ascii_str - assert pretty(expr_2) == ascii_str + assert pretty(expr) == ascii_str + assert pretty(expr_2) == ascii_str assert upretty(expr) == ucode_str assert upretty(expr_2) == ucode_str @@ -2334,7 +2799,7 @@ ⎡ 2⎤\n\ ⎣x ⎦\ """ - assert pretty(expr) == ascii_str + assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = (x**2,) @@ -2348,7 +2813,7 @@ ⎛ 2 ⎞\n\ ⎝x ,⎠\ """ - assert pretty(expr) == ascii_str + assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = Tuple(x**2) @@ -2362,7 +2827,7 @@ ⎛ 2 ⎞\n\ ⎝x ,⎠\ """ - assert pretty(expr) == ascii_str + assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = {x**2: 1} @@ -2378,11 +2843,12 @@ ⎨x : 1⎬\n\ ⎩ ⎭\ """ - assert pretty(expr) == ascii_str - assert pretty(expr_2) == ascii_str + assert pretty(expr) == ascii_str + assert pretty(expr_2) == ascii_str assert upretty(expr) == ucode_str assert upretty(expr_2) == ucode_str + def test_any_object_in_sequence(): # Cf. issue 2207 b1 = Basic() @@ -2396,12 +2862,16 @@ assert pretty(expr) == "set([Basic(), Basic(Basic())])" assert upretty(expr) == "set([Basic(), Basic(Basic())])" - expr = {b2:b1, b1:b2} - expr2 = Dict({b2:b1, b1:b2}) + expr = {b2: b1, b1: b2} + expr2 = Dict({b2: b1, b1: b2}) assert pretty(expr) == "{Basic(): Basic(Basic()), Basic(Basic()): Basic()}" - assert pretty(expr2) == "{Basic(): Basic(Basic()), Basic(Basic()): Basic()}" - assert upretty(expr) == "{Basic(): Basic(Basic()), Basic(Basic()): Basic()}" - assert upretty(expr2) == "{Basic(): Basic(Basic()), Basic(Basic()): Basic()}" + assert pretty( + expr2) == "{Basic(): Basic(Basic()), Basic(Basic()): Basic()}" + assert upretty( + expr) == "{Basic(): Basic(Basic()), Basic(Basic()): Basic()}" + assert upretty( + expr2) == "{Basic(): Basic(Basic()), Basic(Basic()): Basic()}" + def test_pretty_sets(): s = FiniteSet @@ -2422,6 +2892,7 @@ assert pretty(s(list(range(1, 13)))) == \ "%s([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12])" % s.__name__ + def test_pretty_limits(): expr = Limit(x, x, oo) ascii_str = \ @@ -2434,7 +2905,7 @@ lim x\n\ x->∞ \ """ - assert pretty(expr) == ascii_str + assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = Limit(x**2, x, 0) @@ -2450,7 +2921,7 @@ lim x \n\ x->0 \ """ - assert pretty(expr) == ascii_str + assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = Limit(1/x, x, 0) @@ -2466,7 +2937,7 @@ lim ─\n\ x->0x\ """ - assert pretty(expr) == ascii_str + assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = Limit(sin(x)/x, x, 0) @@ -2482,9 +2953,10 @@ lim ──────\n\ x->0 x \ """ - assert pretty(expr) == ascii_str + assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str + def test_pretty_RootOf(): expr = RootOf(x**5 + 11*x - 2, 0) ascii_str = \ @@ -2498,9 +2970,10 @@ RootOf⎝x + 11⋅x - 2, 0⎠\ """ - assert pretty(expr) == ascii_str + assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str + def test_pretty_RootSum(): expr = RootSum(x**5 + 11*x - 2, auto=False) ascii_str = \ @@ -2514,7 +2987,7 @@ RootSum⎝x + 11⋅x - 2⎠\ """ - assert pretty(expr) == ascii_str + assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = RootSum(x**5 + 11*x - 2, Lambda(z, exp(z))) @@ -2529,9 +3002,10 @@ RootSum⎝x + 11⋅x - 2, Λ⎝z, ℯ ⎠⎠\ """ - assert pretty(expr) == ascii_str + assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str + def test_GroebnerBasis(): expr = groebner([], x, y) @@ -2544,7 +3018,7 @@ GroebnerBasis([], x, y, domain=ℤ, order=lex)\ """ - assert pretty(expr) == ascii_str + assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str F = [x**2 - 3*y - x + 1, y**2 - 2*x + y - 1] @@ -2561,7 +3035,7 @@ GroebnerBasis⎝⎣x - x - 3⋅y + 1, y - 2⋅x + y - 1⎦, x, y, domain=ℤ, order=grlex⎠\ """ - assert pretty(expr) == ascii_str + assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = expr.fglm('lex') @@ -2577,132 +3051,147 @@ GroebnerBasis⎝⎣2⋅x - y - y + 1, y + 2⋅y - 3⋅y - 16⋅y + 7⎦, x, y, domain=ℤ, order=lex⎠\ """ - assert pretty(expr) == ascii_str + assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str + def test_pretty_Boolean(): expr = Not(x, evaluate=False) - assert pretty(expr) == "Not(x)" + assert pretty(expr) == "Not(x)" assert upretty(expr) == "¬ x" expr = And(x, y) - assert pretty(expr) == "And(x, y)" + assert pretty(expr) == "And(x, y)" assert upretty(expr) == "x ∧ y" expr = Or(x, y) - assert pretty(expr) == "Or(x, y)" + assert pretty(expr) == "Or(x, y)" assert upretty(expr) == "x ∨ y" + syms = symbols('a:f') + expr = And(*syms) + + assert pretty(expr) == "And(a, b, c, d, e, f)" + assert upretty(expr) == "a ∧ b ∧ c ∧ d ∧ e ∧ f" + + expr = Or(*syms) + + assert pretty(expr) == "Or(a, b, c, d, e, f)" + assert upretty(expr) == "a ∨ b ∨ c ∨ d ∨ e ∨ f" + expr = Xor(x, y, evaluate=False) - assert pretty(expr) == "Xor(x, y)" + assert pretty(expr) == "Xor(x, y)" assert upretty(expr) == "x ⊻ y" expr = Nand(x, y, evaluate=False) - assert pretty(expr) == "Nand(x, y)" + assert pretty(expr) == "Nand(x, y)" assert upretty(expr) == "x ⊼ y" expr = Nor(x, y, evaluate=False) - assert pretty(expr) == "Nor(x, y)" + assert pretty(expr) == "Nor(x, y)" assert upretty(expr) == "x ⊽ y" expr = Implies(x, y, evaluate=False) - assert pretty(expr) == "Implies(x, y)" + assert pretty(expr) == "Implies(x, y)" assert upretty(expr) == "x → y" # don't sort args expr = Implies(y, x, evaluate=False) - assert pretty(expr) == "Implies(y, x)" + assert pretty(expr) == "Implies(y, x)" assert upretty(expr) == "y → x" expr = Equivalent(x, y, evaluate=False) - assert pretty(expr) == "Equivalent(x, y)" + assert pretty(expr) == "Equivalent(x, y)" assert upretty(expr) == "x ≡ y" expr = Equivalent(y, x, evaluate=False) - assert pretty(expr) == "Equivalent(x, y)" + assert pretty(expr) == "Equivalent(x, y)" assert upretty(expr) == "x ≡ y" + def test_pretty_Domain(): expr = FF(23) - assert pretty(expr) == "GF(23)" + assert pretty(expr) == "GF(23)" assert upretty(expr) == "ℤ₂₃" expr = ZZ - assert pretty(expr) == "ZZ" + assert pretty(expr) == "ZZ" assert upretty(expr) == "ℤ" expr = QQ - assert pretty(expr) == "QQ" + assert pretty(expr) == "QQ" assert upretty(expr) == "ℚ" expr = RR - assert pretty(expr) == "RR" + assert pretty(expr) == "RR" assert upretty(expr) == "ℝ" expr = QQ[x] - assert pretty(expr) == "QQ[x]" + assert pretty(expr) == "QQ[x]" assert upretty(expr) == "ℚ[x]" expr = QQ[x, y] - assert pretty(expr) == "QQ[x, y]" + assert pretty(expr) == "QQ[x, y]" assert upretty(expr) == "ℚ[x, y]" expr = ZZ.frac_field(x) - assert pretty(expr) == "ZZ(x)" + assert pretty(expr) == "ZZ(x)" assert upretty(expr) == "ℤ(x)" expr = ZZ.frac_field(x, y) - assert pretty(expr) == "ZZ(x, y)" + assert pretty(expr) == "ZZ(x, y)" assert upretty(expr) == "ℤ(x, y)" expr = QQ.poly_ring(x, y, order="lex") - assert pretty(expr) == "QQ[x, y, order=lex]" + assert pretty(expr) == "QQ[x, y, order=lex]" assert upretty(expr) == "ℚ[x, y, order=lex]" expr = QQ.poly_ring(x, y, order="ilex") - assert pretty(expr) == "QQ[x, y, order=ilex]" + assert pretty(expr) == "QQ[x, y, order=ilex]" assert upretty(expr) == "ℚ[x, y, order=ilex]" + def test_pretty_prec(): assert xpretty(S("0.3"), full_prec=True) == "0.300000000000000" assert xpretty(S("0.3"), full_prec="auto") == "0.300000000000000" assert xpretty(S("0.3"), full_prec=False) == "0.3" assert xpretty(S("0.3")*x, full_prec=True, use_unicode=False) in [ - "0.300000000000000*x", - "x*0.300000000000000" - ] + "0.300000000000000*x", + "x*0.300000000000000" + ] assert xpretty(S("0.3")*x, full_prec="auto", use_unicode=False) in [ - "0.3*x", - "x*0.3" - ] + "0.3*x", + "x*0.3" + ] assert xpretty(S("0.3")*x, full_prec=False, use_unicode=False) in [ - "0.3*x", - "x*0.3" - ] + "0.3*x", + "x*0.3" + ] def test_pprint(): - import io, sys + import io + import sys fd = io.StringIO() sso = sys.stdout sys.stdout = fd @@ -2715,8 +3204,11 @@ def test_pretty_class(): """Test that the printer dispatcher correctly handles classes.""" - class C: pass # C has no .__class__ and this was causing problems - class D(object): pass + class C: + pass # C has no .__class__ and this was causing problems + + class D(object): + pass assert pretty( C ) == str( C ) assert pretty( D ) == str( D ) @@ -2725,7 +3217,7 @@ def test_pretty_no_wrap_line(): huge_expr = 0 for i in range(20): - huge_expr += i*sin(i+x) + huge_expr += i*sin(i + x) assert xpretty(huge_expr ).find('\n') != -1 assert xpretty(huge_expr, wrap_line=False).find('\n') == -1 @@ -2733,7 +3225,7 @@ def test_settings(): raises(TypeError, lambda: pretty(S(4), method="garbage")) -@XFAIL + def test_pretty_sum(): from sympy.abc import x, a, b, k, m, n @@ -2759,7 +3251,7 @@ ‾‾‾ \n\ k = 0 \ """ - assert pretty(expr) == ascii_str + assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = Sum(k**(Integral(x**n, (x, -oo, oo))), (k, 0, n**n)) @@ -2799,10 +3291,11 @@ ‾‾‾‾‾‾ \n\ k = 0 \ """ - assert pretty(expr) == ascii_str + assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str - expr = Sum(k**(Integral(x**n, (x, -oo, oo))), (k, 0, Integral(x**x, (x, -oo, oo)))) + expr = Sum(k**( + Integral(x**n, (x, -oo, oo))), (k, 0, Integral(x**x, (x, -oo, oo)))) ascii_str = \ """\ oo \n\ @@ -2849,10 +3342,11 @@ ‾‾‾‾‾‾ \n\ k = 0 \ """ - assert pretty(expr) == ascii_str + assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str - expr = Sum(k**(Integral(x**n, (x, -oo, oo))), (k, x+n+x**2 + n**2 + (x/n)+(1/x), Integral(x**x, (x, -oo, oo)))) + expr = Sum(k**(Integral(x**n, (x, -oo, oo))), ( + k, x + n + x**2 + n**2 + (x/n) + (1/x), Integral(x**x, (x, -oo, oo)))) ascii_str = \ """\ oo \n\ @@ -2903,10 +3397,11 @@ k = n + n + x + x + ─ + ─ \n\ x n \ """ - assert pretty(expr) == ascii_str + assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str - expr = Sum(k**(Integral(x**n, (x, -oo, oo))), (k, 0, x+n+x**2 + n**2 + (x/n)+(1/x))) + expr = Sum(k**( + Integral(x**n, (x, -oo, oo))), (k, 0, x + n + x**2 + n**2 + (x/n) + (1/x))) ascii_str = \ """\ 2 2 1 x \n\ @@ -2945,7 +3440,7 @@ ‾‾‾‾‾‾ \n\ k = 0 \ """ - assert pretty(expr) == ascii_str + assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = Sum(x, (x, 0, oo)) @@ -2970,7 +3465,7 @@ x = 0 \ """ - assert pretty(expr) == ascii_str + assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = Sum(x**2, (x, 0, oo)) @@ -2996,7 +3491,7 @@ x = 0 \ """ - assert pretty(expr) == ascii_str + assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = Sum(x/2, (x, 0, oo)) @@ -3025,7 +3520,7 @@ x = 0 \ """ - assert pretty(expr) == ascii_str + assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = Sum(x**3/2, (x, 0, oo)) @@ -3055,7 +3550,7 @@ x = 0 \ """ - assert pretty(expr) == ascii_str + assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = Sum((x**3*y**(x/2))**n, (x, 0, oo)) @@ -3088,7 +3583,7 @@ x = 0 \ """ - assert pretty(expr) == ascii_str + assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = Sum(1/x**2, (x, 0, oo)) @@ -3118,40 +3613,40 @@ x = 0 \ """ - assert pretty(expr) == ascii_str + assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = Sum(1/y**(a/b), (x, 0, oo)) ascii_str = \ """\ - oo \n\ -____ \n\ -\\ ` \n\ - \\ -a\n\ - \\ --\n\ - / b \n\ - / y \n\ -/___, \n\ -x = 0 \ + oo \n\ +____ \n\ +\\ ` \n\ + \\ -a \n\ + \\ ---\n\ + / b \n\ + / y \n\ +/___, \n\ +x = 0 \ """ ucode_str = \ """\ - ∞ \n\ - ____ \n\ - ╲ \n\ - ╲ -a\n\ - ╲ ──\n\ - ╱ b \n\ - ╱ y \n\ - ╱ \n\ - ‾‾‾‾ \n\ -x = 0 \ + ∞ \n\ + ____ \n\ + ╲ \n\ + ╲ -a \n\ + ╲ ───\n\ + ╱ b \n\ + ╱ y \n\ + ╱ \n\ + ‾‾‾‾ \n\ +x = 0 \ """ - assert pretty(expr) == ascii_str + assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str - expr = Sum(1/y**(a/b), (x, 0, oo), (y,1,2)) + expr = Sum(1/y**(a/b), (x, 0, oo), (y, 1, 2)) ascii_str = \ """\ 2 oo \n\ @@ -3177,7 +3672,8 @@ ‾‾‾‾ ‾‾‾‾ \n\ y = 1 x = 0 \ """ - expr = Sum(1/(1 + 1/(1 + 1/k)) + 1, (k, 111, 1 + 1/n), (k, 1/(1+m), oo)) + 1/(1 + 1/k) + expr = Sum(1/(1 + 1/( + 1 + 1/k)) + 1, (k, 111, 1 + 1/n), (k, 1/(1 + m), oo)) + 1/(1 + 1/k) ascii_str = \ """\ 1 \n\ @@ -3197,7 +3693,7 @@ k = ----- \n\ m + 1 \ """ - ucode_str =\ + ucode_str = \ """\ 1 \n\ 1 + ─ \n\ @@ -3219,9 +3715,10 @@ m + 1 \ """ - assert pretty(expr) == ascii_str + assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str + def test_units(): expr = joule ascii_str = \ @@ -3244,6 +3741,7 @@ assert upretty(expr) == unicode_str assert pretty(expr) == ascii_str + def test_pretty_Subs(): f = Function('f') expr = Subs(f(x), x, ph**2) @@ -3299,10 +3797,12 @@ assert pretty(expr) == ascii_str assert upretty(expr) == unicode_str + def test_gammas(): assert upretty(lowergamma(x, y)) == "γ(x, y)" assert upretty(uppergamma(x, y)) == "Γ(x, y)" + def test_hyper(): expr = hyper((), (), z) ucode_str = \ @@ -3376,7 +3876,7 @@ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str - expr = hyper((pi,S('2/3'),-2*k), (3,4,5,-3), x**2) + expr = hyper((pi, S('2/3'), -2*k), (3, 4, 5, -3), x**2) ucode_str = \ """\ ┌─ ⎛π, 2/3, -2⋅k │ 2⎞\n\ @@ -3393,7 +3893,7 @@ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str - expr = hyper([1,2],[3,4], 1/(1/(1/(1/x + 1) + 1) + 1)) + expr = hyper([1, 2], [3, 4], 1/(1/(1/(1/x + 1) + 1) + 1)) ucode_str = \ """\ ⎛ │ 1 ⎞\n\ @@ -3423,6 +3923,7 @@ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str + def test_meijerg(): expr = meijerg([pi, pi, x], [1], [0, 1], [1, 2, 3], z) ucode_str = \ @@ -3460,7 +3961,6 @@ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str - ucode_str = \ """\ ╭─╮ 1, 10 ⎛1, 1, 1, 1, 1, 1, 1, 1, 1, 1 1 │ ⎞\n\ @@ -3478,8 +3978,7 @@ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str - - expr = meijerg([1, 2,], [4, 3], [3], [4, 5], 1/(1/(1/(1/x + 1) + 1) + 1)) + expr = meijerg([1, 2, ], [4, 3], [3], [4, 5], 1/(1/(1/(1/x + 1) + 1) + 1)) ucode_str = \ """\ @@ -3613,10 +4112,10 @@ def test_pretty_special_functions(): - x,y = symbols("x y") + x, y = symbols("x y") # atan2 - expr = atan2(y/sqrt(200),sqrt(x)) + expr = atan2(y/sqrt(200), sqrt(x)) ascii_str = \ """\ / ___ \\\n\ @@ -3634,11 +4133,13 @@ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str + def test_pretty_geometry(): e = Segment((0, 1), (0, 2)) assert pretty(e) == 'Segment(Point(0, 1), Point(0, 2))' - e = Ray((1, 1), angle=4.2*pi) - assert pretty(e) == 'Ray(Point(1, 1), Point(2, tan(pi/5) + 1))' + e = Ray((1, 1), angle=4.05*pi) + assert pretty(e) == 'Ray(Point(1, 1), Point(2, tan(pi/20) + 1))' + def test_expint(): expr = Ei(x) @@ -3661,21 +4162,117 @@ assert upretty(Ci(x)) == 'Ci(x)' assert upretty(Chi(x)) == 'Chi(x)' + +def test_elliptic_functions(): + ascii_str = \ +"""\ + / 1 \\\n\ +K|-----|\n\ + \z + 1/\ +""" + ucode_str = \ +"""\ + ⎛ 1 ⎞\n\ +K⎜─────⎟\n\ + ⎝z + 1⎠\ +""" + expr = elliptic_k(1/(z + 1)) + assert pretty(expr) == ascii_str + assert upretty(expr) == ucode_str + + ascii_str = \ +"""\ + / | 1 \\\n\ +F|1|-----|\n\ + \ |z + 1/\ +""" + ucode_str = \ +"""\ + ⎛ │ 1 ⎞\n\ +F⎜1│─────⎟\n\ + ⎝ │z + 1⎠\ +""" + expr = elliptic_f(1, 1/(1 + z)) + assert pretty(expr) == ascii_str + assert upretty(expr) == ucode_str + + ascii_str = \ +"""\ + / 1 \\\n\ +E|-----|\n\ + \z + 1/\ +""" + ucode_str = \ +"""\ + ⎛ 1 ⎞\n\ +E⎜─────⎟\n\ + ⎝z + 1⎠\ +""" + expr = elliptic_e(1/(z + 1)) + assert pretty(expr) == ascii_str + assert upretty(expr) == ucode_str + + ascii_str = \ +"""\ + / | 1 \\\n\ +E|1|-----|\n\ + \ |z + 1/\ +""" + ucode_str = \ +"""\ + ⎛ │ 1 ⎞\n\ +E⎜1│─────⎟\n\ + ⎝ │z + 1⎠\ +""" + expr = elliptic_e(1, 1/(1 + z)) + assert pretty(expr) == ascii_str + assert upretty(expr) == ucode_str + + ascii_str = \ +"""\ + / |4\\\n\ +Pi|3|-|\n\ + \ |x/\ +""" + ucode_str = \ +"""\ + ⎛ │4⎞\n\ +Π⎜3│─⎟\n\ + ⎝ │x⎠\ +""" + expr = elliptic_pi(3, 4/x) + assert pretty(expr) == ascii_str + assert upretty(expr) == ucode_str + + ascii_str = \ +"""\ + / 4| \\\n\ +Pi|3; -|6|\n\ + \ x| /\ +""" + ucode_str = \ +"""\ + ⎛ 4│ ⎞\n\ +Π⎜3; ─│6⎟\n\ + ⎝ x│ ⎠\ +""" + expr = elliptic_pi(3, 4/x, 6) + assert pretty(expr) == ascii_str + assert upretty(expr) == ucode_str + + def test_RandomDomain(): from sympy.stats import Normal, Die, Exponential, pspace, where X = Normal('x1', 0, 1) - assert upretty(where(X>0)) == "Domain: 0 < x₁" + assert upretty(where(X > 0)) == "Domain: x₁ > 0" D = Die('d1', 6) - assert upretty(where(D>4)) == 'Domain: d₁ = 5 ∨ d₁ = 6' + assert upretty(where(D > 4)) == 'Domain: d₁ = 5 ∨ d₁ = 6' A = Exponential('a', 1) B = Exponential('b', 1) - assert upretty(pspace(Tuple(A,B)).domain) =='Domain: 0 ≤ a ∧ 0 ≤ b' + assert upretty(pspace(Tuple(A, B)).domain) == 'Domain: a ≥ 0 ∧ b ≥ 0' -def test_issue_3186(): - assert pretty(Pow(2, -5, evaluate=False)) == '1 \n--\n 5\n2 ' - assert pretty(Pow(x, (1/pi))) == 'pi___\n\\/ x ' def test_PrettyPoly(): F = QQ.frac_field(x, y) @@ -3689,18 +4286,120 @@ assert pretty(expr) == pretty(x + y) assert upretty(expr) == upretty(x + y) + def test_issue_3186(): assert pretty(Pow(2, -5, evaluate=False)) == '1 \n--\n 5\n2 ' assert pretty(Pow(x, (1/pi))) == 'pi___\n\\/ x ' + +def test_issue_3260(): + assert pretty(Integral(x**2, x)**2) == \ +"""\ + 2 +/ / \ \n\ +| | | \n\ +| | 2 | \n\ +| | x dx| \n\ +| | | \n\ +\/ / \ +""" + assert upretty(Integral(x**2, x)**2) == \ +"""\ + 2 +⎛⌠ ⎞ \n\ +⎜⎮ 2 ⎟ \n\ +⎜⎮ x dx⎟ \n\ +⎝⌡ ⎠ \ +""" + + assert pretty(Sum(x**2, (x, 0, 1))**2) == \ +"""\ + 2 +/ 1 \\ \n\ +| ___ | \n\ +| \\ ` | \n\ +| \\ 2| \n\ +| / x | \n\ +| /__, | \n\ +\\x = 0 / \ +""" + assert upretty(Sum(x**2, (x, 0, 1))**2) == \ +"""\ + 2 +⎛ 1 ⎞ \n\ +⎜ ___ ⎟ \n\ +⎜ ╲ ⎟ \n\ +⎜ ╲ 2⎟ \n\ +⎜ ╱ x ⎟ \n\ +⎜ ╱ ⎟ \n\ +⎜ ‾‾‾ ⎟ \n\ +⎝x = 0 ⎠ \ +""" + + assert pretty(Product(x**2, (x, 1, 2))**2) == \ +"""\ + 2 +/ 2 \\ \n\ +|______ | \n\ +|| | 2| \n\ +|| | x | \n\ +|| | | \n\ +\\x = 1 / \ +""" + assert upretty(Product(x**2, (x, 1, 2))**2) == \ +"""\ + 2 +⎛ 2 ⎞ \n\ +⎜┬────┬ ⎟ \n\ +⎜│ │ 2⎟ \n\ +⎜│ │ x ⎟ \n\ +⎜│ │ ⎟ \n\ +⎝x = 1 ⎠ \ +""" + + f = Function('f') + assert pretty(Derivative(f(x), x)**2) == \ +"""\ + 2 +/d \\ \n\ +|--(f(x))| \n\ +\\dx / \ +""" + assert upretty(Derivative(f(x), x)**2) == \ +"""\ + 2 +⎛d ⎞ \n\ +⎜──(f(x))⎟ \n\ +⎝dx ⎠ \ +""" + +def test_issue_3640(): + ascii_str = \ +"""\ + 1 \n\ +-----\n\ + ___\n\ +\/ x \ +""" + ucode_str = \ +"""\ + 1 \n\ +─────\n\ + ___\n\ +╲╱ x \ +""" + assert pretty(1/sqrt(x)) == ascii_str + assert upretty(1/sqrt(x)) == ucode_str + + def test_complicated_symbol_unchanged(): for symb_name in ["dexpr2_d1tau", "dexpr2^d1tau"]: assert pretty(Symbol(symb_name)) == symb_name + def test_categories(): - from sympy.categories import (Object, Morphism, IdentityMorphism, - NamedMorphism, CompositeMorphism, - Category, Diagram, DiagramGrid) + from sympy.categories import (Object, IdentityMorphism, + NamedMorphism, Category, Diagram, DiagramGrid) A1 = Object("A1") A2 = Object("A2") @@ -3731,27 +4430,28 @@ assert pretty(d) == "EmptySet()" assert upretty(d) == "∅" - d = Diagram({f1:"unique", f2:S.EmptySet}) + d = Diagram({f1: "unique", f2: S.EmptySet}) assert pretty(d) == "{f2*f1:A1-->A3: EmptySet(), id:A1-->A1: " \ - "EmptySet(), id:A2-->A2: EmptySet(), id:A3-->A3: " \ - "EmptySet(), f1:A1-->A2: {unique}, f2:A2-->A3: EmptySet()}" + "EmptySet(), id:A2-->A2: EmptySet(), id:A3-->A3: " \ + "EmptySet(), f1:A1-->A2: {unique}, f2:A2-->A3: EmptySet()}" assert upretty(d) == "{f₂∘f₁:A₁——▶A₃: ∅, id:A₁——▶A₁: ∅, " \ - "id:A₂——▶A₂: ∅, id:A₃——▶A₃: ∅, f₁:A₁——▶A₂: {unique}, f₂:A₂——▶A₃: ∅}" + "id:A₂——▶A₂: ∅, id:A₃——▶A₃: ∅, f₁:A₁——▶A₂: {unique}, f₂:A₂——▶A₃: ∅}" - d = Diagram({f1:"unique", f2:S.EmptySet}, {f2 * f1: "unique"}) + d = Diagram({f1: "unique", f2: S.EmptySet}, {f2 * f1: "unique"}) assert pretty(d) == "{f2*f1:A1-->A3: EmptySet(), id:A1-->A1: " \ - "EmptySet(), id:A2-->A2: EmptySet(), id:A3-->A3: " \ - "EmptySet(), f1:A1-->A2: {unique}, f2:A2-->A3: EmptySet()}" \ - " ==> {f2*f1:A1-->A3: {unique}}" + "EmptySet(), id:A2-->A2: EmptySet(), id:A3-->A3: " \ + "EmptySet(), f1:A1-->A2: {unique}, f2:A2-->A3: EmptySet()}" \ + " ==> {f2*f1:A1-->A3: {unique}}" assert upretty(d) == "{f₂∘f₁:A₁——▶A₃: ∅, id:A₁——▶A₁: ∅, id:A₂——▶A₂: " \ - "∅, id:A₃——▶A₃: ∅, f₁:A₁——▶A₂: {unique}, f₂:A₂——▶A₃: ∅}" \ - " ══▶ {f₂∘f₁:A₁——▶A₃: {unique}}" + "∅, id:A₃——▶A₃: ∅, f₁:A₁——▶A₂: {unique}, f₂:A₂——▶A₃: ∅}" \ + " ══▶ {f₂∘f₁:A₁——▶A₃: {unique}}" grid = DiagramGrid(d) assert pretty(grid) == "A1 A2\n \nA3 " assert upretty(grid) == "A\u2081 A\u2082\n \nA\u2083 " + def test_PrettyModules(): R = QQ[x, y] F = R.free_module(2) @@ -3769,7 +4469,7 @@ """ assert upretty(F) == ucode_str - assert pretty(F) == ascii_str + assert pretty(F) == ascii_str ucode_str = \ """\ @@ -3783,7 +4483,7 @@ """ assert upretty(M) == ucode_str - assert pretty(M) == ascii_str + assert pretty(M) == ascii_str I = R.ideal(x**2, y) @@ -3800,7 +4500,7 @@ """ assert upretty(I) == ucode_str - assert pretty(I) == ascii_str + assert pretty(I) == ascii_str Q = F / M @@ -3823,9 +4523,7 @@ """ assert upretty(Q) == ucode_str - assert pretty(Q) == ascii_str - - expr = Q.submodule([1, x**3/2], [2, y]) + assert pretty(Q) == ascii_str ucode_str = \ """\ @@ -3864,7 +4562,7 @@ """ assert upretty(R) == ucode_str - assert pretty(R) == ascii_str + assert pretty(R) == ascii_str ucode_str = \ """\ @@ -3879,7 +4577,8 @@ """ assert upretty(R.one) == ucode_str - assert pretty(R.one) == ascii_str + assert pretty(R.one) == ascii_str + def test_Homomorphism(): R = QQ[x] @@ -3899,7 +4598,7 @@ """ assert upretty(expr) == ucode_str - assert pretty(expr) == ascii_str + assert pretty(expr) == ascii_str expr = homomorphism(R.free_module(2), R.free_module(2), [0, 0]) @@ -3918,7 +4617,7 @@ """ assert upretty(expr) == ucode_str - assert pretty(expr) == ascii_str + assert pretty(expr) == ascii_str expr = homomorphism(R.free_module(1), R.free_module(1) / [[x]], [0]) @@ -3939,10 +4638,16 @@ """ assert upretty(expr) == ucode_str - assert pretty(expr) == ascii_str + assert pretty(expr) == ascii_str + def test_Tr(): A, B = symbols('A B', commutative=False) t = Tr(A*B) assert pretty(t) == r'Tr(A*B)' assert upretty(t) == 'Tr(A\u22c5B)' + + +def test_pretty_Add(): + eq = Mul(-2, x - 2, evaluate=False) + 5 + assert pretty(eq) == '-2*(x - 2) + 5' diff -Nru python3-sympy-0.7.2/sympy/printing/preview.py python3-sympy-0.7.3/sympy/printing/preview.py --- python3-sympy-0.7.2/sympy/printing/preview.py 2012-10-17 03:02:22.000000000 +0000 +++ python3-sympy-0.7.3/sympy/printing/preview.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,17 +1,32 @@ -import os -import time +from os.path import join import tempfile +import shutil +from io import StringIO +try: + from subprocess import STDOUT, CalledProcessError + from sympy.core.compatibility import check_output +except ImportError: + pass + +from sympy.utilities.exceptions import SymPyDeprecationWarning +from sympy.utilities.misc import find_executable from .latex import latex -def preview(expr, output='png', viewer=None, euler=True, packages=(), **latex_settings): +from sympy.utilities.decorator import doctest_depends_on + +@doctest_depends_on(exe=('latex', 'dvipng'), modules=('pyglet',), + disable_viewers=('evince', 'gimp', 'superior-dvi-viewer')) +def preview(expr, output='png', viewer=None, euler=True, packages=(), + filename=None, outputbuffer=None, preamble=None, dvioptions=None, + outputTexFile=None, **latex_settings): r""" View expression or LaTeX markup in PNG, DVI, PostScript or PDF form. If the expr argument is an expression, it will be exported to LaTeX and - then compiled using available the TeX distribution. The first argument, + then compiled using the available TeX distribution. The first argument, 'expr', may also be a LaTeX string. The function will then run the appropriate viewer for the given output format or use the user defined one. By default png output is generated. @@ -28,44 +43,70 @@ >>> from sympy import symbols, preview, Symbol >>> x, y = symbols("x,y") - >>> preview(x + y, output='png') # doctest: +SKIP + >>> preview(x + y, output='png') This will choose 'pyglet' by default. To select a different one, do - >>> preview(x + y, output='png', viewer='gimp') # doctest: +SKIP + >>> preview(x + y, output='png', viewer='gimp') The 'png' format is considered special. For all other formats the rules are slightly different. As an example we will take 'dvi' output format. If you would run - >>> preview(x + y, output='dvi') # doctest: +SKIP + >>> preview(x + y, output='dvi') then 'view' will look for available 'dvi' viewers on your system (predefined in the function, so it will try evince, first, then kdvi and xdvi). If nothing is found you will need to set the viewer explicitly. - >>> preview(x + y, output='dvi', viewer='superior-dvi-viewer') # doctest: +SKIP + >>> preview(x + y, output='dvi', viewer='superior-dvi-viewer') This will skip auto-detection and will run user specified 'superior-dvi-viewer'. If 'view' fails to find it on your system it will - gracefully raise an exception. You may also enter 'file' for the viewer - argument. Doing so will cause this function to return a file object in - read-only mode. + gracefully raise an exception. - Currently this depends on pexpect, which is not available for windows. + You may also enter 'file' for the viewer argument. Doing so will cause + this function to return a file object in read-only mode, if 'filename' + is unset. However, if it was set, then 'preview' writes the genereted + file to this filename instead. + + There is also support for writing to a StringIO like object, which needs + to be passed to the 'outputbuffer' argument. + + >>> from io import StringIO + >>> obj = StringIO() + >>> preview(x + y, output='png', viewer='StringIO', + ... outputbuffer=obj) + + The LaTeX preamble can be customized by setting the 'preamble' keyword + argument. This can be used, e.g., to set a different font size, use a + custom documentclass or import certain set of LaTeX packages. + + >>> preamble = "\\documentclass[10pt]{article}\n" \ + ... "\\usepackage{amsmath,amsfonts}\\begin{document}" + >>> preview(x + y, output='png', preamble=preamble) + + If the value of 'output' is different from 'dvi' then command line + options can be set ('dvioptions' argument) for the execution of the + 'dvi'+output conversion tool. These options have to be in the form of a + list of strings (see subprocess.Popen). Additional keyword args will be passed to the latex call, e.g., the symbol_names flag. >>> phidd = Symbol('phidd') - >>> preview(phidd, symbol_names={phidd:r'\ddot{\varphi}'}) # doctest: +SKIP + >>> preview(phidd, symbol_names={phidd:r'\ddot{\varphi}'}) - """ + For post-processing the generated TeX File can be written to a file by + passing the desired filename to the 'outputTexFile' keyword + argument. To write the TeX code to a file named + "sample.tex" and run the default png viewer to display the resulting + bitmap, do + + >>> preview(x + y, outputTexFile="sample.tex") - # we don't want to depend on anything not in the - # standard library with SymPy by default - import pexpect + """ special = [ 'pyglet' ] if viewer is None: @@ -74,142 +115,192 @@ else: # sorted in order from most pretty to most ugly # very discussable, but indeed 'gv' looks awful :) + # TODO add candidates for windows to list candidates = { - "dvi" : [ "evince", "okular", "kdvi", "xdvi" ], - "ps" : [ "evince", "okular", "gsview", "gv" ], - "pdf" : [ "evince", "okular", "kpdf", "acroread", "xpdf", "gv" ], + "dvi": [ "evince", "okular", "kdvi", "xdvi" ], + "ps": [ "evince", "okular", "gsview", "gv" ], + "pdf": [ "evince", "okular", "kpdf", "acroread", "xpdf", "gv" ], } try: for candidate in candidates[output]: - if pexpect.which(candidate): - viewer = candidate + path = find_executable(candidate) + if path is not None: + viewer = path break else: - raise SystemError("No viewers found for '%s' output format." % output) + raise SystemError( + "No viewers found for '%s' output format." % output) except KeyError: raise SystemError("Invalid output format: %s" % output) else: - if viewer not in special and not pexpect.which(viewer): + if viewer == "file": + if filename is None: + SymPyDeprecationWarning(feature="Using viewer=\"file\" without a " + "specified filename", deprecated_since_version="0.7.3", + useinstead="viewer=\"file\" and filename=\"desiredname\"", + issue=3919).warn() + elif viewer == "StringIO": + if outputbuffer is None: + raise ValueError("outputbuffer has to be a StringIO " + "compatible object if viewer=\"StringIO\"") + elif viewer not in special and not find_executable(viewer): raise SystemError("Unrecognized viewer: %s" % viewer) - actual_packages = packages + ("amsmath", "amsfonts") - if euler: - actual_packages += ("euler",) - package_includes = "\n".join(["\\usepackage{%s}" % p - for p in actual_packages]) - - format = r"""\documentclass[12pt]{article} - %s - \begin{document} - \pagestyle{empty} - %s - \vfill - \end{document} - """ % (package_includes, "%s") + + if preamble is None: + actual_packages = packages + ("amsmath", "amsfonts") + if euler: + actual_packages += ("euler",) + package_includes = "\n" + "\n".join(["\\usepackage{%s}" % p + for p in actual_packages]) + + preamble = r"""\documentclass[12pt]{article} +\pagestyle{empty} +%s + +\begin{document} +""" % (package_includes) + else: + if len(packages) > 0: + raise ValueError("The \"packages\" keyword must not be set if a " + "custom LaTeX preamble was specified") + latex_main = preamble + '\n%s\n\n' + r"\end{document}" if isinstance(expr, str): latex_string = expr else: latex_string = latex(expr, mode='inline', **latex_settings) + try: + workdir = tempfile.mkdtemp() - tmp = tempfile.mktemp() + with open(join(workdir, 'texput.tex'), 'w') as fh: + fh.write(latex_main % latex_string) - with open(tmp + ".tex", "w") as tex: - tex.write(format % latex_string) + if outputTexFile is not None: + shutil.copyfile(join(workdir, 'texput.tex'), outputTexFile) - cwd = os.getcwd() - os.chdir(tempfile.gettempdir()) + if not find_executable('latex'): + raise RuntimeError("latex program is not installed") - if os.system("latex -halt-on-error %s.tex" % tmp) != 0: - raise SystemError("Failed to generate DVI output.") - - os.remove(tmp + ".tex") - os.remove(tmp + ".aux") - os.remove(tmp + ".log") - - if output != "dvi": - command = { - "ps" : "dvips -o %s.ps %s.dvi", - "pdf" : "dvipdf %s.dvi %s.pdf", - "png" : "dvipng -T tight -z 9 " + \ - "--truecolor -o %s.png %s.dvi", - } - - try: - if os.system(command[output] % (tmp, tmp)) != 0: - raise SystemError("Failed to generate '%s' output." % output) - else: - os.remove(tmp + ".dvi") - except KeyError: - raise SystemError("Invalid output format: %s" % output) - - src = "%s.%s" % (tmp, output) - src_file = None - - if viewer == "file": - src_file = open(src, 'rb') - elif viewer == "pyglet": try: - from pyglet import window, image, gl - from pyglet.window import key - except ImportError: - raise ImportError("pyglet is required for plotting.\n visit http://www.pyglet.org/") + check_output(['latex', '-halt-on-error', '-interaction=nonstopmode', + 'texput.tex'], cwd=workdir, stderr=STDOUT) + except CalledProcessError as e: + raise RuntimeError( + "'latex' exited abnormally with the following output:\n%s" % + e.output) + + if output != "dvi": + defaultoptions = { + "ps": [], + "pdf": [], + "png": ["-T", "tight", "-z", "9", "--truecolor"] + } - if output == "png": - from pyglet.image.codecs.png import PNGImageDecoder - img = image.load(src, decoder=PNGImageDecoder()) - else: - raise SystemError("pyglet preview works only for 'png' files.") + commandend = { + "ps": ["-o", "texput.ps", "texput.dvi"], + "pdf": ["texput.dvi", "texput.pdf"], + "png": ["-o", "texput.png", "texput.dvi"] + } - offset = 25 + cmd = ["dvi" + output] + if not find_executable(cmd[0]): + raise RuntimeError("%s is not installed" % cmd[0]) + try: + if dvioptions is not None: + cmd.extend(dvioptions) + else: + cmd.extend(defaultoptions[output]) + cmd.extend(commandend[output]) + except KeyError: + raise SystemError("Invalid output format: %s" % output) - win = window.Window( - width = img.width + 2*offset, - height = img.height + 2*offset, - caption = "sympy", - resizable = False - ) + try: + check_output(cmd, cwd=workdir, stderr=STDOUT) + except CalledProcessError as e: + raise RuntimeError( + "'%s' exited abnormally with the following output:\n%s" % + (' '.join(cmd), e.output)) + + src = "texput.%s" % (output) + + if viewer == "file": + if filename is None: + buffer = StringIO() + with open(join(workdir, src), 'rb') as fh: + buffer.write(fh.read()) + return buffer + else: + shutil.move(join(workdir,src), filename) + elif viewer == "StringIO": + with open(join(workdir, src), 'rb') as fh: + outputbuffer.write(fh.read()) + elif viewer == "pyglet": + try: + from pyglet import window, image, gl + from pyglet.window import key + except ImportError: + raise ImportError("pyglet is required for preview.\n visit http://www.pyglet.org/") + + if output == "png": + from pyglet.image.codecs.png import PNGImageDecoder + img = image.load(join(workdir, src), decoder=PNGImageDecoder()) + else: + raise SystemError("pyglet preview works only for 'png' files.") - win.set_vsync(False) + offset = 25 - try: - def on_close(): - win.has_exit = True + win = window.Window( + width=img.width + 2*offset, + height=img.height + 2*offset, + caption="sympy", + resizable=False + ) - win.on_close = on_close + win.set_vsync(False) - def on_key_press(symbol, modifiers): - if symbol in [key.Q, key.ESCAPE]: - on_close() + try: + def on_close(): + win.has_exit = True - win.on_key_press = on_key_press + win.on_close = on_close - def on_expose(): - gl.glClearColor(1.0, 1.0, 1.0, 1.0) - gl.glClear(gl.GL_COLOR_BUFFER_BIT) + def on_key_press(symbol, modifiers): + if symbol in [key.Q, key.ESCAPE]: + on_close() - img.blit( - (win.width - img.width) / 2, - (win.height - img.height) / 2 - ) + win.on_key_press = on_key_press - win.on_expose = on_expose + def on_expose(): + gl.glClearColor(1.0, 1.0, 1.0, 1.0) + gl.glClear(gl.GL_COLOR_BUFFER_BIT) - while not win.has_exit: - win.dispatch_events() - win.flip() - except KeyboardInterrupt: - pass + img.blit( + (win.width - img.width) / 2, + (win.height - img.height) / 2 + ) - win.close() - else: - os.system("%s %s &> /dev/null &" % (viewer, src)) - time.sleep(2) # wait for the viewer to read data + win.on_expose = on_expose - os.remove(src) - os.chdir(cwd) + while not win.has_exit: + win.dispatch_events() + win.flip() + except KeyboardInterrupt: + pass - if src_file is not None: - return src_file + win.close() + else: + try: + check_output([viewer, src], cwd=workdir, stderr=STDOUT) + except CalledProcessError as e: + raise RuntimeError( + "'%s %s' exited abnormally with the following output:\n%s" % + (viewer, src, e.output)) + finally: + try: + shutil.rmtree(workdir) # delete directory + except OSError as e: + if e.errno != 2: # code 2 - no such file or directory + raise diff -Nru python3-sympy-0.7.2/sympy/printing/printer.py python3-sympy-0.7.3/sympy/printing/printer.py --- python3-sympy-0.7.2/sympy/printing/printer.py 2012-10-17 03:02:22.000000000 +0000 +++ python3-sympy-0.7.3/sympy/printing/printer.py 2013-07-13 17:53:32.000000000 +0000 @@ -73,6 +73,7 @@ from sympy.core.compatibility import cmp_to_key + class Printer(object): """Generic printer @@ -229,7 +230,7 @@ """Returns printer's representation for expr (as a string)""" return self._str(self._print(expr)) - def _print(self, expr, *args): + def _print(self, expr, *args, **kwargs): """Internal dispatcher Tries the following concepts to print an expression: @@ -244,14 +245,14 @@ # should be printed, use that method. if (self.printmethod and hasattr(expr, self.printmethod) and not isinstance(expr, BasicMeta)): - return getattr(expr, self.printmethod)(self, *args) + return getattr(expr, self.printmethod)(self, *args, **kwargs) # See if the class of expr is known, or if one of its super # classes is known, and use that print function for cls in type(expr).__mro__: printmethod = '_print_' + cls.__name__ if hasattr(self, printmethod): - return getattr(self, printmethod)(expr, *args) + return getattr(self, printmethod)(expr, *args, **kwargs) # Unknown object, fall back to the emptyPrinter. return self.emptyPrinter(expr) diff -Nru python3-sympy-0.7.2/sympy/printing/python.py python3-sympy-0.7.3/sympy/printing/python.py --- python3-sympy-0.7.2/sympy/printing/python.py 2012-10-17 03:02:22.000000000 +0000 +++ python3-sympy-0.7.3/sympy/printing/python.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,5 +1,6 @@ # -*- coding: utf-8 -*- +import keyword as kw import sympy from .repr import ReprPrinter from .str import StrPrinter @@ -8,6 +9,7 @@ STRPRINT = ("Add", "Infinity", "Integer", "Mul", "NegativeInfinity", "Pow", "Zero") + class PythonPrinter(ReprPrinter, StrPrinter): """A printer which converts an expression into its Python interpretation.""" @@ -20,7 +22,7 @@ # Create print methods for classes that should use StrPrinter instead # of ReprPrinter. for name in STRPRINT: - f_name = "_print_%s"%name + f_name = "_print_%s" % name f = getattr(StrPrinter, f_name) setattr(PythonPrinter, f_name, f) @@ -46,18 +48,43 @@ (can be passed to the exec() function without any modifications)""" printer = PythonPrinter(settings) - expr = printer.doprint(expr) + exprp = printer.doprint(expr) result = '' # Returning found symbols and functions - for symbol in printer.symbols: - result += symbol + ' = Symbol(\'' + symbol + '\')\n' - for function in printer.functions: - result += function + ' = Function(\'' + function + '\')\n' - - result += 'e = ' + printer._str(expr) + renamings = {} + for symbolname in printer.symbols: + newsymbolname = symbolname + # Escape symbol names that are reserved python keywords + if kw.iskeyword(newsymbolname): + while True: + newsymbolname += "_" + if (newsymbolname not in printer.symbols and + newsymbolname not in printer.functions): + renamings[sympy.Symbol( + symbolname)] = sympy.Symbol(newsymbolname) + break + result += newsymbolname + ' = Symbol(\'' + symbolname + '\')\n' + + for functionname in printer.functions: + newfunctionname = functionname + # Escape function names that are reserved python keywords + if kw.iskeyword(newfunctionname): + while True: + newfunctionname += "_" + if (newfunctionname not in printer.symbols and + newfunctionname not in printer.functions): + renamings[sympy.Function( + functionname)] = sympy.Function(newfunctionname) + break + result += newfunctionname + ' = Function(\'' + functionname + '\')\n' + + if not len(renamings) == 0: + exprp = expr.subs(renamings) + result += 'e = ' + printer._str(exprp) return result + def print_python(expr, **settings): """Print output of python() function""" print(python(expr, **settings)) diff -Nru python3-sympy-0.7.2/sympy/printing/repr.py python3-sympy-0.7.3/sympy/printing/repr.py --- python3-sympy-0.7.2/sympy/printing/repr.py 2012-10-17 03:02:22.000000000 +0000 +++ python3-sympy-0.7.3/sympy/printing/repr.py 2013-07-13 17:53:32.000000000 +0000 @@ -5,10 +5,12 @@ relation eval(srepr(expr))=expr holds in an appropriate environment. """ +from sympy.core.function import AppliedUndef from .printer import Printer import sympy.mpmath.libmp as mlib from sympy.mpmath.libmp import prec_to_dps, repr_dps + class ReprPrinter(Printer): printmethod = "_sympyrepr" @@ -47,11 +49,14 @@ def _print_Function(self, expr): r = self._print(expr.func) - r+= '(%s)' % ', '.join([self._print(a) for a in expr.args]) + r += '(%s)' % ', '.join([self._print(a) for a in expr.args]) return r def _print_FunctionClass(self, expr): - return 'Function(%r)'%(expr.__name__) + if issubclass(expr, AppliedUndef): + return 'Function(%r)' % (expr.__name__) + else: + return expr.__name__ def _print_Half(self, expr): return 'Rational(1, 2)' @@ -76,26 +81,22 @@ for i in range(expr.rows): l.append([]) for j in range(expr.cols): - l[-1].append(expr[i,j]) + l[-1].append(expr[i, j]) return '%s(%s)' % (expr.__class__.__name__, self._print(l)) - def _print_MutableMatrix(self, expr): - """ - Same as _print_MatrixBase except treat the name as Matrix - """ - l = [] - for i in range(expr.rows): - l.append([]) - for j in range(expr.cols): - l[-1].append(expr[i,j]) - return 'Matrix(%s)' % self._print(l) + _print_SparseMatrix = \ + _print_MutableSparseMatrix = \ + _print_ImmutableSparseMatrix = \ + _print_Matrix = \ + _print_DenseMatrix = \ + _print_MutableDenseMatrix = \ + _print_ImmutableMatrix = \ + _print_ImmutableDenseMatrix = \ + _print_MatrixBase def _print_NaN(self, expr): return "nan" - def _print_Rational(self, expr): - return 'Rational(%s, %s)' % (self._print(expr.p), self._print(expr.q)) - def _print_Mul(self, expr, order=None): terms = expr.args if self.order != 'old': @@ -106,6 +107,12 @@ args = list(map(self._print, args)) return "Mul(%s)" % ", ".join(args) + def _print_Rational(self, expr): + return 'Rational(%s, %s)' % (self._print(expr.p), self._print(expr.q)) + + def _print_PythonRational(self, expr): + return "%s(%d, %d)" % (expr.__class__.__name__, expr.p, expr.q) + def _print_Fraction(self, expr): return 'Fraction(%s, %s)' % (self._print(expr.numerator), self._print(expr.denominator)) @@ -131,7 +138,7 @@ return repr(expr) def _print_tuple(self, expr): - if len(expr)==1: + if len(expr) == 1: return "(%s,)" % self._print(expr[0]) else: return "(%s)" % self.reprify(expr, ", ") @@ -143,6 +150,28 @@ return "%s(%s, %s)" % (self.__class__.__name__, self._print(self.coeffs()), self._print(expr.root)) + def _print_PolyRing(self, ring): + return "%s(%s, %s, %s)" % (ring.__class__.__name__, + self._print(ring.symbols), self._print(ring.domain), self._print(ring.order)) + + def _print_FracField(self, field): + return "%s(%s, %s, %s)" % (field.__class__.__name__, + self._print(field.symbols), self._print(field.domain), self._print(field.order)) + + def _print_PolyElement(self, poly): + terms = list(poly.terms()) + terms.sort(key=poly.ring.order, reverse=True) + return "%s(%s, %s)" % (poly.__class__.__name__, self._print(poly.ring), self._print(terms)) + + def _print_FracElement(self, frac): + numer_terms = list(frac.numer.terms()) + numer_terms.sort(key=frac.field.order, reverse=True) + denom_terms = list(frac.denom.terms()) + denom_terms.sort(key=frac.field.order, reverse=True) + numer = self._print(numer_terms) + denom = self._print(denom_terms) + return "%s(%s, %s, %s)" % (frac.__class__.__name__, self._print(frac.field), numer, denom) + def srepr(expr, **settings): """return expr in repr form""" return ReprPrinter(settings).doprint(expr) diff -Nru python3-sympy-0.7.2/sympy/printing/str.py python3-sympy-0.7.3/sympy/printing/str.py --- python3-sympy-0.7.2/sympy/printing/str.py 2012-10-17 03:02:22.000000000 +0000 +++ python3-sympy-0.7.3/sympy/printing/str.py 2013-07-13 17:53:32.000000000 +0000 @@ -3,17 +3,17 @@ """ from sympy.core import S, Rational, Pow, Basic, Mul -from sympy.core.function import _coeff_isneg +from sympy.core.mul import _keep_coeff +from sympy.core.numbers import Integer from .printer import Printer from sympy.printing.precedence import precedence, PRECEDENCE import sympy.mpmath.libmp as mlib from sympy.mpmath.libmp import prec_to_dps -from sympy.polys.polyerrors import PolynomialError - from sympy.utilities import default_sort_key + class StrPrinter(Printer): printmethod = "_sympystr" _default_settings = { @@ -23,7 +23,7 @@ def parenthesize(self, item, level): if precedence(item) <= level: - return "(%s)"%self._print(item) + return "(%s)" % self._print(item) else: return self._print(item) @@ -57,11 +57,11 @@ else: sign = "+" if precedence(term) < PREC: - l.extend([sign, "(%s)"%t]) + l.extend([sign, "(%s)" % t]) else: l.extend([sign, t]) sign = l.pop(0) - if sign=='+': + if sign == '+': sign = "" return sign + ' '.join(l) @@ -78,12 +78,12 @@ def _print_Basic(self, expr): l = [self._print(o) for o in expr.args] - return expr.__class__.__name__ + "(%s)"%", ".join(l) + return expr.__class__.__name__ + "(%s)" % ", ".join(l) def _print_BlockMatrix(self, B): - if B.mat.shape == (1, 1): - self._print(B.mat[0,0]) - return self._print(B.mat) + if B.blocks.shape == (1, 1): + self._print(B.blocks[0, 0]) + return self._print(B.blocks) def _print_Catalan(self, expr): return 'Catalan' @@ -92,7 +92,7 @@ return 'zoo' def _print_Derivative(self, expr): - return 'Derivative(%s)'%", ".join(map(self._print, expr.args)) + return 'Derivative(%s)' % ", ".join(map(self._print, expr.args)) def _print_dict(self, d): keys = sorted(list(d.keys()), key=default_sort_key) @@ -102,14 +102,15 @@ item = "%s: %s" % (self._print(key), self._print(d[key])) items.append(item) - return "{%s}"%", ".join(items) + return "{%s}" % ", ".join(items) def _print_Dict(self, expr): return self._print_dict(expr) + def _print_RandomDomain(self, d): try: - return 'Domain: '+self._print(d.as_boolean()) + return 'Domain: ' + self._print(d.as_boolean()) except: try: return ('Domain: ' + self._print(d.symbols) + ' in ' + @@ -129,9 +130,6 @@ def _print_ExprCondPair(self, expr): return '(%s, %s)' % (expr.expr, expr.cond) - def _print_factorial(self, expr): - return "%s!" % self.parenthesize(expr.args[0], PRECEDENCE["Pow"]) - def _print_FiniteSet(self, s): s = sorted(s, key=default_sort_key) if len(s) > 10: @@ -141,7 +139,7 @@ return '{' + ', '.join(self._print(el) for el in printset) + '}' def _print_Function(self, expr): - return expr.func.__name__ + "(%s)"%self.stringify(expr.args, ", ") + return expr.func.__name__ + "(%s)" % self.stringify(expr.args, ", ") def _print_GeometryEntity(self, expr): # GeometryEntity is special -- it's base is tuple @@ -192,7 +190,7 @@ def _print_LatticeOp(self, expr): args = sorted(expr.args, key=default_sort_key) - return expr.func.__name__ + "(%s)"%", ".join(self._print(arg) for arg in args) + return expr.func.__name__ + "(%s)" % ", ".join(self._print(arg) for arg in args) def _print_Limit(self, expr): e, z, z0, dir = expr.args @@ -202,12 +200,36 @@ return "Limit(%s, %s, %s, dir='%s')" % (e, z, z0, dir) def _print_list(self, expr): - return "[%s]"%self.stringify(expr, ", ") + return "[%s]" % self.stringify(expr, ", ") def _print_MatrixBase(self, expr): - return expr._format_str(lambda elem: self._print(elem)) - _print_ImmutableMatrix = _print_MatrixBase - _print_MutableMatrix = _print_MatrixBase + return expr._format_str(self) + _print_SparseMatrix = \ + _print_MutableSparseMatrix = \ + _print_ImmutableSparseMatrix = \ + _print_Matrix = \ + _print_DenseMatrix = \ + _print_MutableDenseMatrix = \ + _print_ImmutableMatrix = \ + _print_ImmutableDenseMatrix = \ + _print_MatrixBase + + def _print_MatrixElement(self, expr): + return self._print(expr.parent) + '[%s, %s]'%(expr.i, expr.j) + + def _print_MatrixSlice(self, expr): + def strslice(x): + x = list(x) + if x[2] == 1: + del x[2] + if x[1] == x[0] + 1: + del x[1] + if x[0] == 0: + x[0] = '' + return ':'.join(map(self._print, x)) + return (self._print(expr.parent) + '[' + + strslice(expr.rowslice) + ', ' + + strslice(expr.colslice) + ']') def _print_DeferredVector(self, expr): return expr.name @@ -216,14 +238,15 @@ prec = precedence(expr) - if _coeff_isneg(expr): - expr = -expr + c, e = expr.as_coeff_Mul() + if c < 0: + expr = _keep_coeff(-c, e) sign = "-" else: sign = "" - a = [] # items in the numerator - b = [] # items that are in the denominator (if any) + a = [] # items in the numerator + b = [] # items that are in the denominator (if any) if self.order not in ('old', 'none'): args = expr.as_ordered_factors() @@ -255,16 +278,23 @@ return sign + '*'.join(a_str) elif len(b) == 1: if len(a) == 1 and not (a[0].is_Atom or a[0].is_Add): - return sign + "%s/"%a_str[0] + '*'.join(b_str) + return sign + "%s/" % a_str[0] + '*'.join(b_str) else: - return sign + '*'.join(a_str) + "/%s"%b_str[0] + return sign + '*'.join(a_str) + "/%s" % b_str[0] else: - return sign + '*'.join(a_str) + "/(%s)"%'*'.join(b_str) + return sign + '*'.join(a_str) + "/(%s)" % '*'.join(b_str) def _print_MatMul(self, expr): return '*'.join([self.parenthesize(arg, precedence(expr)) for arg in expr.args]) + def _print_HadamardProduct(self, expr): + return '.*'.join([self.parenthesize(arg, precedence(expr)) + for arg in expr.args]) + + def _print_MatAdd(self, expr): + return ' + '.join([self.parenthesize(arg, precedence(expr)) + for arg in expr.args]) def _print_NaN(self, expr): return 'nan' @@ -273,13 +303,13 @@ return '-oo' def _print_Normal(self, expr): - return "Normal(%s, %s)"%(expr.mu, expr.sigma) + return "Normal(%s, %s)" % (expr.mu, expr.sigma) def _print_Order(self, expr): if len(expr.variables) <= 1: - return 'O(%s)'%self._print(expr.expr) + return 'O(%s)' % self._print(expr.expr) else: - return 'O(%s)'%self.stringify(expr.args, ', ', 0) + return 'O(%s)' % self.stringify(expr.args, ', ', 0) def _print_Cycle(self, expr): """We want it to print as Cycle in doctests for which a repr is required. @@ -318,18 +348,92 @@ use = trim return 'Permutation(%s)' % use + def _print_TensorIndex(self, expr): + return expr._pretty() + + def _print_TensorHead(self, expr): + return expr._pretty() + + def _print_TensMul(self, expr): + return expr._pretty() + + def _print_TensAdd(self, expr): + return expr._pretty() + def _print_PermutationGroup(self, expr): p = [' %s' % str(a) for a in expr.args] return 'PermutationGroup([\n%s])' % ',\n'.join(p) def _print_PDF(self, expr): return 'PDF(%s, (%s, %s, %s))' % \ - (self._print(expr.pdf.args[1]), self._print(expr.pdf.args[0]), \ + (self._print(expr.pdf.args[1]), self._print(expr.pdf.args[0]), self._print(expr.domain[0]), self._print(expr.domain[1])) def _print_Pi(self, expr): return 'pi' + def _print_PolyRing(self, ring): + return "Polynomial ring in %s over %s with %s order" % \ + (", ".join(map(self._print, ring.symbols)), ring.domain, ring.order) + + def _print_FracField(self, field): + return "Rational function field in %s over %s with %s order" % \ + (", ".join(map(self._print, field.symbols)), field.domain, field.order) + + def _print_PolyElement(self, poly): + if not poly: + return self._print(poly.ring.domain.zero) + prec_add = PRECEDENCE["Add"] + prec_atom = PRECEDENCE["Atom"] + ring = poly.ring + symbols = ring.symbols + ngens = ring.ngens + zm = ring.zero_monom + sexpvs = [] + expvs = list(poly.keys()) + expvs.sort(key=ring.order, reverse=True) + for expv in expvs: + coeff = poly[expv] + if ring.domain.is_positive(coeff): + sexpvs.append(' + ') + else: + sexpvs.append(' - ') + if ring.domain.is_negative(coeff): + coeff = -coeff + if coeff != 1 or expv == zm: + if expv == zm: + scoeff = self._print(coeff) + else: + scoeff = self.parenthesize(coeff, prec_add) + else: + scoeff = '' + sexpv = [] + for i in range(ngens): + exp = expv[i] + if not exp: + continue + symbol = self.parenthesize(symbols[i], prec_atom-1) + if exp != 1: + sexpv.append('%s**%d' % (symbol, exp)) + else: + sexpv.append('%s' % symbol) + if scoeff: + sexpv = [scoeff] + sexpv + sexpvs.append('*'.join(sexpv)) + if sexpvs[0] in [" + ", " - "]: + head = sexpvs.pop(0) + if head == " - ": + sexpvs.insert(0, "-") + return "".join(sexpvs) + + def _print_FracElement(self, frac): + if frac.denom == 1: + return self._print(frac.numer) + else: + numer = self.parenthesize(frac.numer, PRECEDENCE["Add"]) + denom = self.parenthesize(frac.denom, PRECEDENCE["Atom"]-1) + return numer + "/" + denom + def _print_Poly(self, expr): terms, gens = [], [ self._print(s) for s in expr.gens ] @@ -380,6 +484,8 @@ format = expr.__class__.__name__ + "(%s, %s" + from sympy.polys.polyerrors import PolynomialError + try: format += ", modulus=%s" % expr.get_modulus() except PolynomialError: @@ -392,7 +498,6 @@ def _print_ProductSet(self, p): return ' x '.join(self._print(set) for set in p.sets) - def _print_AlgebraicNumber(self, expr): if expr.is_aliased: return self._print(expr.as_poly().as_expr()) @@ -423,7 +528,7 @@ def _print_MatPow(self, expr): PREC = precedence(expr) - return '%s**%s'%(self.parenthesize(expr.base, PREC), + return '%s**%s' % (self.parenthesize(expr.base, PREC), self.parenthesize(expr.exp, PREC)) def _print_Integer(self, expr): @@ -436,13 +541,28 @@ return str(expr) def _print_Rational(self, expr): - return '%s/%s' % (expr.p, expr.q) + if expr.q == 1: + return str(expr.p) + else: + return "%s/%s" % (expr.p, expr.q) + + def _print_PythonRational(self, expr): + if expr.q == 1: + return str(expr.p) + else: + return "%d/%d" % (expr.p, expr.q) def _print_Fraction(self, expr): - return '%s/%s' % (expr.numerator, expr.denominator) + if expr.denominator == 1: + return str(expr.numerator) + else: + return "%s/%s" % (expr.numerator, expr.denominator) def _print_mpq(self, expr): - return '%s/%s' % (expr.numer(), expr.denom()) + if expr.denominator == 1: + return str(expr.numerator) + else: + return "%s/%s" % (expr.numerator, expr.denominator) def _print_Float(self, expr): prec = expr._prec @@ -450,9 +570,9 @@ dps = 0 else: dps = prec_to_dps(expr._prec) - if self._settings["full_prec"] == True: + if self._settings["full_prec"] is True: strip = False - elif self._settings["full_prec"] == False: + elif self._settings["full_prec"] is False: strip = True elif self._settings["full_prec"] == "auto": strip = self._print_level > 1 @@ -464,7 +584,7 @@ return rv def _print_Relational(self, expr): - return '%s %s %s'%(self.parenthesize(expr.lhs, precedence(expr)), + return '%s %s %s' % (self.parenthesize(expr.lhs, precedence(expr)), expr.rel_op, self.parenthesize(expr.rhs, precedence(expr))) @@ -482,7 +602,8 @@ def _print_GroebnerBasis(self, basis): cls = basis.__class__.__name__ - exprs = [ self._print_Add(arg, order=basis.order) for arg in basis.exprs ] + exprs = [ self._print_Add(arg, order=basis.order) + for arg in basis.exprs ] exprs = "[%s]" % ", ".join(exprs) gens = [ self._print(gen) for gen in basis.gens ] @@ -494,7 +615,7 @@ return "%s(%s)" % (cls, ", ".join(args)) def _print_Sample(self, expr): - return "Sample([%s])"%self.stringify(expr, ", ", 0) + return "Sample([%s])" % self.stringify(expr, ", ", 0) def _print_set(self, s): items = sorted(s, key=default_sort_key) @@ -507,7 +628,8 @@ _print_frozenset = _print_set def _print_SparseMatrix(self, expr): - return self._print(expr.toMatrix()) + from sympy.matrices import Matrix + return self._print(Matrix(expr)) def _print_Sum(self, expr): def _xab_tostr(xab): @@ -520,6 +642,14 @@ def _print_Symbol(self, expr): return expr.name + _print_MatrixSymbol = _print_Symbol + _print_RandomSymbol = _print_Symbol + + def _print_Identity(self, expr): + return "I" + + def _print_ZeroMatrix(self, expr): + return "0" def _print_Predicate(self, expr): return "Q.%s" % expr.name @@ -528,10 +658,10 @@ return expr def _print_tuple(self, expr): - if len(expr)==1: - return "(%s,)"%self._print(expr[0]) + if len(expr) == 1: + return "(%s,)" % self._print(expr[0]) else: - return "(%s)"%self.stringify(expr, ", ") + return "(%s)" % self.stringify(expr, ", ") def _print_Tuple(self, expr): return self._print_tuple(expr) @@ -540,7 +670,7 @@ return "%s'" % self.parenthesize(T.arg, PRECEDENCE["Pow"]) def _print_Uniform(self, expr): - return "Uniform(%s, %s)"%(expr.a, expr.b) + return "Uniform(%s, %s)" % (expr.a, expr.b) def _print_Union(self, expr): return ' U '.join(self._print(set) for set in expr.args) @@ -593,14 +723,14 @@ return field._coord_sys._names[field._index] def _print_BaseVectorField(self, field): - return 'e_%s'%field._coord_sys._names[field._index] + return 'e_%s' % field._coord_sys._names[field._index] def _print_Differential(self, diff): field = diff._form_field if hasattr(field, '_coord_sys'): - return 'd%s'%field._coord_sys._names[field._index] + return 'd%s' % field._coord_sys._names[field._index] else: - return 'd(%s)'%self._print(field) + return 'd(%s)' % self._print(field) def _print_Tr(self, expr): #TODO : Handle indices @@ -634,6 +764,7 @@ def _print_str(self, s): return repr(s) + def sstrrepr(expr, **settings): """return expr in mixed str/repr form diff -Nru python3-sympy-0.7.2/sympy/printing/tableform.py python3-sympy-0.7.3/sympy/printing/tableform.py --- python3-sympy-0.7.2/sympy/printing/tableform.py 2012-10-17 03:02:22.000000000 +0000 +++ python3-sympy-0.7.3/sympy/printing/tableform.py 2013-07-13 17:53:32.000000000 +0000 @@ -2,6 +2,7 @@ from types import FunctionType + class TableForm(object): """ Create a nice table representation of data. @@ -156,6 +157,7 @@ allow = ('l', 'r', 'c') alignments = kwarg.get("alignments", "l") + def _std_align(a): a = a.strip().lower() if len(a) > 1: @@ -180,8 +182,8 @@ _head_align = 'r' if len(_alignments) != _w: raise ValueError( - 'wrong number of alignments: expected %s but got %s' % - (_w, len(_alignments))) + 'wrong number of alignments: expected %s but got %s' % + (_w, len(_alignments))) _column_formats = kwarg.get("formats", [None]*_w) @@ -218,9 +220,10 @@ 2 | 4 2 3 | 10 3 >>> t.as_matrix() - [ 5, 7] - [ 4, 2] - [10, 3] + Matrix([ + [ 5, 7], + [ 4, 2], + [10, 3]]) """ from sympy import Matrix return Matrix(self._lines) @@ -276,15 +279,16 @@ self._headings[1] = new_line format_str = [] + def _align(align, w): return '%%%s%ss' % ( - ("-" if align == "l" else ""), - str(w)) + ("-" if align == "l" else ""), + str(w)) format_str = [_align(align, w) for align, w in zip(self._alignments, column_widths)] if self._headings[0]: format_str.insert(0, _align(self._head_align, _head_width)) - format_str.insert(1,'|') + format_str.insert(1, '|') format_str = ' '.join(format_str) + '\n' s = [] @@ -297,14 +301,14 @@ s.append("-" * (len(first_line) - 1) + "\n") for i, line in enumerate(lines): d = [l if self._alignments[j] != 'c' else - l.center(column_widths[j]) for j,l in enumerate(line)] + l.center(column_widths[j]) for j, l in enumerate(line)] if self._headings[0]: l = self._headings[0][i] l = (l if self._head_align != 'c' else l.center(_head_width)) d = [l] + d s.append(format_str % tuple(d)) - return ''.join(s)[:-1] # don't include trailing newline + return ''.join(s)[:-1] # don't include trailing newline def _latex(self, printer): """ @@ -315,9 +319,7 @@ new_line = [] for i in range(self._w): # Format the item somehow if needed: - s = str(self._headings[1][i]) - w = len(s) - new_line.append(s) + new_line.append(str(self._headings[1][i])) self._headings[1] = new_line alignments = [] diff -Nru python3-sympy-0.7.2/sympy/printing/tests/test_ccode.py python3-sympy-0.7.3/sympy/printing/tests/test_ccode.py --- python3-sympy-0.7.2/sympy/printing/tests/test_ccode.py 2012-10-17 03:02:22.000000000 +0000 +++ python3-sympy-0.7.3/sympy/printing/tests/test_ccode.py 2013-07-13 17:53:32.000000000 +0000 @@ -11,23 +11,28 @@ x, y, z = symbols('x,y,z') g = Function('g') + def test_printmethod(): class fabs(Abs): def _ccode(self, printer): return "fabs(%s)" % printer._print(self.args[0]) assert ccode(fabs(x)) == "fabs(x)" + def test_ccode_sqrt(): assert ccode(sqrt(x)) == "sqrt(x)" assert ccode(x**0.5) == "sqrt(x)" assert ccode(sqrt(x)) == "sqrt(x)" + def test_ccode_Pow(): assert ccode(x**3) == "pow(x, 3)" assert ccode(x**(y**3)) == "pow(x, pow(y, 3))" assert ccode(1/(g(x)*3.5)**(x - y**x)/(x**2 + y)) == \ "pow(3.5*g(x), -x + pow(y, x))/(pow(x, 2) + y)" assert ccode(x**-1.0) == '1.0/x' + assert ccode(x**Rational(2, 3)) == 'pow(x, 2.0L/3.0L)' + def test_ccode_constants_mathh(): assert ccode(exp(1)) == "M_E" @@ -35,43 +40,66 @@ assert ccode(oo) == "HUGE_VAL" assert ccode(-oo) == "-HUGE_VAL" + def test_ccode_constants_other(): assert ccode(2*GoldenRatio) == "double const GoldenRatio = 1.61803398874989;\n2*GoldenRatio" - assert ccode(2*Catalan) == "double const Catalan = 0.915965594177219;\n2*Catalan" + assert ccode( + 2*Catalan) == "double const Catalan = 0.915965594177219;\n2*Catalan" assert ccode(2*EulerGamma) == "double const EulerGamma = 0.577215664901533;\n2*EulerGamma" + def test_ccode_Rational(): - assert ccode(Rational(3,7)) == "3.0/7.0" - assert ccode(Rational(18,9)) == "2" - assert ccode(Rational(3,-7)) == "-3.0/7.0" - assert ccode(Rational(-3,-7)) == "3.0/7.0" + assert ccode(Rational(3, 7)) == "3.0L/7.0L" + assert ccode(Rational(18, 9)) == "2" + assert ccode(Rational(3, -7)) == "-3.0L/7.0L" + assert ccode(Rational(-3, -7)) == "3.0L/7.0L" + assert ccode(x + Rational(3, 7)) == "x + 3.0L/7.0L" + assert ccode(Rational(3, 7)*x) == "(3.0L/7.0L)*x" + def test_ccode_Integer(): assert ccode(Integer(67)) == "67" assert ccode(Integer(-1)) == "-1" + def test_ccode_functions(): assert ccode(sin(x) ** cos(x)) == "pow(sin(x), cos(x))" + def test_ccode_inline_function(): x = symbols('x') g = implemented_function('g', Lambda(x, 2*x)) assert ccode(g(x)) == "2*x" g = implemented_function('g', Lambda(x, 2*x/Catalan)) - assert ccode(g(x)) == "double const Catalan = %s;\n2*x/Catalan" %Catalan.n() + assert ccode( + g(x)) == "double const Catalan = %s;\n2*x/Catalan" % Catalan.n() A = IndexedBase('A') i = Idx('i', symbols('n', integer=True)) g = implemented_function('g', Lambda(x, x*(1 + x)*(2 + x))) assert ccode(g(A[i]), assign_to=A[i]) == ( - "for (int i=0; i "Integer(2)";', + '"Add(Integer(2), Symbol(x))" -> "Symbol(x)";' + ] + assert sorted(dotedges(x + 2, repeat=True)) == [ + '"Add(Integer(2), Symbol(x))_()" -> "Integer(2)_(0,)";', + '"Add(Integer(2), Symbol(x))_()" -> "Symbol(x)_(1,)";' + ] + +def test_dotprint(): + text = dotprint(x+2, repeat=False) + assert all(e in text for e in dotedges(x+2, repeat=False)) + assert all(n in text for n in [dotnode(expr, repeat=False) for expr in (x, Integer(2), x+2)]) + assert 'digraph' in text + text = dotprint(x+x**2, repeat=False) + assert all(e in text for e in dotedges(x+x**2, repeat=False)) + assert all(n in text for n in [dotnode(expr, repeat=False) for expr in (x, Integer(2), x**2)]) + assert 'digraph' in text + text = dotprint(x+x**2, repeat=True) + assert all(e in text for e in dotedges(x+x**2, repeat=True)) + assert all(n in text for n in [dotnode(expr, pos=()) for expr in [x + x**2]]) + text = dotprint(x**x, repeat=True) + assert all(e in text for e in dotedges(x**x, repeat=True)) + assert all(n in text for n in [dotnode(x, pos=(0,)), dotnode(x, pos=(1,))]) + assert 'digraph' in text + +def test_dotprint_depth(): + text = dotprint(3*x+2, depth=1) + assert dotnode(3*x+2) in text + assert dotnode(x) not in text + +def test_Matrix_and_non_basics(): + from sympy import MatrixSymbol + n = Symbol('n') + assert dotprint(MatrixSymbol('X', n, n)) + +def test_labelfunc(): + text = dotprint(x + 2, labelfunc=srepr) + assert "Symbol('x')" in text + assert "Integer(2)" in text diff -Nru python3-sympy-0.7.2/sympy/printing/tests/test_fcode.py python3-sympy-0.7.3/sympy/printing/tests/test_fcode.py --- python3-sympy-0.7.2/sympy/printing/tests/test_fcode.py 2012-10-17 03:02:22.000000000 +0000 +++ python3-sympy-0.7.3/sympy/printing/tests/test_fcode.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,5 +1,5 @@ -from sympy import sin, cos, atan2, gamma, conjugate, sqrt, factorial, \ - Integral, Piecewise, Add, diff, symbols, S, Float, Dummy +from sympy import sin, cos, atan2, log, exp, gamma, conjugate, sqrt, \ + factorial, Integral, Piecewise, Add, diff, symbols, S, Float, Dummy from sympy import Catalan, EulerGamma, E, GoldenRatio, I, pi from sympy import Function, Rational, Integer, Lambda @@ -11,11 +11,13 @@ def test_printmethod(): x = symbols('x') + class nint(Function): def _fcode(self, printer): return "nint(%s)" % printer._print(self.args[0]) assert fcode(nint(x)) == " nint(x)" + def test_fcode_Pow(): x, y = symbols('x,y') n = symbols('n', integer=True) @@ -30,25 +32,49 @@ assert fcode(sqrt(x)) == ' sqrt(x)' assert fcode(sqrt(10)) == ' sqrt(10.0d0)' assert fcode(x**-1.0) == ' 1.0/x' + assert fcode(x**-2.0, + assign_to='y', + source_format='free', + human=True) == 'y = x**(-2.0d0)' # 2823 + assert fcode(x**Rational(3, 7)) == ' x**(3.0d0/7.0d0)' + def test_fcode_Rational(): - assert fcode(Rational(3,7)) == " 3.0d0/7.0d0" - assert fcode(Rational(18,9)) == " 2" - assert fcode(Rational(3,-7)) == " -3.0d0/7.0d0" - assert fcode(Rational(-3,-7)) == " 3.0d0/7.0d0" + x = symbols('x') + assert fcode(Rational(3, 7)) == " 3.0d0/7.0d0" + assert fcode(Rational(18, 9)) == " 2" + assert fcode(Rational(3, -7)) == " -3.0d0/7.0d0" + assert fcode(Rational(-3, -7)) == " 3.0d0/7.0d0" + assert fcode(x + Rational(3, 7)) == " x + 3.0d0/7.0d0" + assert fcode(Rational(3, 7)*x) == " (3.0d0/7.0d0)*x" + def test_fcode_Integer(): assert fcode(Integer(67)) == " 67" assert fcode(Integer(-1)) == " -1" + def test_fcode_Float(): assert fcode(Float(42.0)) == " 42.0000000000000d0" assert fcode(Float(-1e20)) == " -1.00000000000000d+20" + def test_fcode_functions(): x, y = symbols('x,y') assert fcode(sin(x) ** cos(y)) == " sin(x)**cos(y)" + +#issue 3715 +def test_fcode_functions_with_integers(): + x= symbols('x') + assert fcode(x * log(10)) == " x*log(10.0d0)" + assert fcode(x * log(S(10))) == " x*log(10.0d0)" + assert fcode(log(S(10))) == " log(10.0d0)" + assert fcode(exp(10)) == " exp(10.0d0)" + assert fcode(x * log(log(10))) == " x*log(2.30258509299405d0)" + assert fcode(x * log(log(S(10)))) == " x*log(2.30258509299405d0)" + + def test_fcode_NumberSymbol(): p = FCodePrinter() assert fcode(Catalan) == ' parameter (Catalan = 0.915965594177219d0)\n Catalan' @@ -56,49 +82,64 @@ assert fcode(E) == ' parameter (E = 2.71828182845905d0)\n E' assert fcode(GoldenRatio) == ' parameter (GoldenRatio = 1.61803398874989d0)\n GoldenRatio' assert fcode(pi) == ' parameter (pi = 3.14159265358979d0)\n pi' - assert fcode(pi,precision=5) == ' parameter (pi = 3.1416d0)\n pi' - assert fcode(Catalan,human=False) == (set([(Catalan, p._print(Catalan.evalf(15)))]), set([]), ' Catalan') - assert fcode(EulerGamma,human=False) == (set([(EulerGamma, p._print(EulerGamma.evalf(15)))]), set([]), ' EulerGamma') - assert fcode(E,human=False) == (set([(E, p._print(E.evalf(15)))]), set([]), ' E') - assert fcode(GoldenRatio,human=False) == (set([(GoldenRatio, p._print(GoldenRatio.evalf(15)))]), set([]), ' GoldenRatio') - assert fcode(pi,human=False) == (set([(pi, p._print(pi.evalf(15)))]), set([]), ' pi') - assert fcode(pi,precision=5,human=False) == (set([(pi, p._print(pi.evalf(5)))]), set([]), ' pi') + assert fcode( + pi, precision=5) == ' parameter (pi = 3.1416d0)\n pi' + assert fcode(Catalan, human=False) == (set( + [(Catalan, p._print(Catalan.evalf(15)))]), set([]), ' Catalan') + assert fcode(EulerGamma, human=False) == (set([(EulerGamma, p._print( + EulerGamma.evalf(15)))]), set([]), ' EulerGamma') + assert fcode(E, human=False) == ( + set([(E, p._print(E.evalf(15)))]), set([]), ' E') + assert fcode(GoldenRatio, human=False) == (set([(GoldenRatio, p._print( + GoldenRatio.evalf(15)))]), set([]), ' GoldenRatio') + assert fcode(pi, human=False) == ( + set([(pi, p._print(pi.evalf(15)))]), set([]), ' pi') + assert fcode(pi, precision=5, human=False) == ( + set([(pi, p._print(pi.evalf(5)))]), set([]), ' pi') + def test_fcode_complex(): assert fcode(I) == " cmplx(0,1)" x = symbols('x') assert fcode(4*I) == " cmplx(0,4)" - assert fcode(3+4*I) == " cmplx(3,4)" - assert fcode(3+4*I+x) == " cmplx(3,4) + x" + assert fcode(3 + 4*I) == " cmplx(3,4)" + assert fcode(3 + 4*I + x) == " cmplx(3,4) + x" assert fcode(I*x) == " cmplx(0,1)*x" - assert fcode(3+4*I-x) == " cmplx(3,4) - x" + assert fcode(3 + 4*I - x) == " cmplx(3,4) - x" x = symbols('x', imaginary=True) assert fcode(5*x) == " 5*x" assert fcode(I*x) == " cmplx(0,1)*x" - assert fcode(3+x) == " x + 3" + assert fcode(3 + x) == " x + 3" + def test_implicit(): x, y = symbols('x,y') assert fcode(sin(x)) == " sin(x)" - assert fcode(atan2(x,y)) == " atan2(x, y)" + assert fcode(atan2(x, y)) == " atan2(x, y)" assert fcode(conjugate(x)) == " conjg(x)" + def test_not_fortran(): x = symbols('x') g = Function('g') - assert fcode(gamma(x)) == "C Not Fortran:\nC gamma(x)\n gamma(x)" + assert fcode( + gamma(x)) == "C Not Fortran:\nC gamma(x)\n gamma(x)" assert fcode(Integral(sin(x))) == "C Not Fortran:\nC Integral(sin(x), x)\n Integral(sin(x), x)" assert fcode(g(x)) == "C Not Fortran:\nC g(x)\n g(x)" + def test_user_functions(): x = symbols('x') assert fcode(sin(x), user_functions={sin: "zsin"}) == " zsin(x)" x = symbols('x') - assert fcode(gamma(x), user_functions={gamma: "mygamma"}) == " mygamma(x)" + assert fcode( + gamma(x), user_functions={gamma: "mygamma"}) == " mygamma(x)" g = Function('g') assert fcode(g(x), user_functions={g: "great"}) == " great(x)" n = symbols('n', integer=True) - assert fcode(factorial(n), user_functions={factorial: "fct"}) == " fct(n)" + assert fcode( + factorial(n), user_functions={factorial: "fct"}) == " fct(n)" + def test_inline_function(): x = symbols('x') @@ -106,25 +147,27 @@ assert fcode(g(x)) == " 2*x" g = implemented_function('g', Lambda(x, 2*pi/x)) assert fcode(g(x)) == ( - " parameter (pi = 3.14159265358979d0)\n" - " 2*pi/x" - ) + " parameter (pi = 3.14159265358979d0)\n" + " 2*pi/x" + ) A = IndexedBase('A') i = Idx('i', symbols('n', integer=True)) g = implemented_function('g', Lambda(x, x*(1 + x)*(2 + x))) assert fcode(g(A[i]), assign_to=A[i]) == ( - " do i = 1, n\n" - " A(i) = (1 + A(i))*(2 + A(i))*A(i)\n" - " end do" - ) + " do i = 1, n\n" + " A(i) = A(i)*(1 + A(i))*(2 + A(i))\n" + " end do" + ) + def test_assign_to(): x = symbols('x') assert fcode(sin(x), assign_to="s") == " s = sin(x)" + def test_line_wrapping(): x, y = symbols('x,y') - assert fcode(((x+y)**10).expand(), assign_to="var") == ( + assert fcode(((x + y)**10).expand(), assign_to="var") == ( " var = x**10 + 10*x**9*y + 45*x**8*y**2 + 120*x**7*y**3 + 210*x**6*\n" " @ y**4 + 252*x**5*y**5 + 210*x**4*y**6 + 120*x**3*y**7 + 45*x**2*y\n" " @ **8 + 10*x*y**9 + y**10" @@ -135,9 +178,10 @@ " @ + 1" ) + def test_fcode_Piecewise(): x = symbols('x') - code = fcode(Piecewise((x,x<1),(x**2,True))) + code = fcode(Piecewise((x, x < 1), (x**2, True))) expected = ( " if (x < 1) then\n" " x\n" @@ -146,7 +190,7 @@ " end if" ) assert code == expected - assert fcode(Piecewise((x,x<1),(x**2,True)), assign_to="var") == ( + assert fcode(Piecewise((x, x < 1), (x**2, True)), assign_to="var") == ( " if (x < 1) then\n" " var = x\n" " else\n" @@ -171,9 +215,9 @@ " @ )/x**10 + 3628800*sin(x)/x**11\n" " end if" ) - code = fcode(Piecewise((a,x<0),(b,True)), assign_to="weird_name") + code = fcode(Piecewise((a, x < 0), (b, True)), assign_to="weird_name") assert code == expected - assert fcode(Piecewise((x,x<1),(x**2,x>1),(sin(x),True))) == ( + assert fcode(Piecewise((x, x < 1), (x**2, x > 1), (sin(x), True))) == ( " if (x < 1) then\n" " x\n" " else if (x > 1) then\n" @@ -182,7 +226,7 @@ " sin(x)\n" " end if" ) - assert fcode(Piecewise((x,x<1),(x**2,x>1),(sin(x),x>0))) == ( + assert fcode(Piecewise((x, x < 1), (x**2, x > 1), (sin(x), x > 0))) == ( " if (x < 1) then\n" " x\n" " else if (x > 1) then\n" @@ -192,6 +236,7 @@ " end if" ) + def test_wrap_fortran(): # "########################################################################" printer = FCodePrinter() @@ -251,6 +296,7 @@ assert w == e assert len(wrapped_lines) == len(expected_lines) + def test_wrap_fortran_keep_d0(): printer = FCodePrinter() lines = [ @@ -260,7 +306,7 @@ ' this_variable_is_very_long_because_we_try_to_test_line_break = 1.0d0', ' this_variable_is_very_long_because_we_try_to_test_line_break = 1.0d0', ' this_variable_is_very_long_because_we_try_to_test_line_break = 10.0d0' - ] + ] expected = [ ' this_variable_is_very_long_because_we_try_to_test_line_break=1.0d0', ' this_variable_is_very_long_because_we_try_to_test_line_break =', @@ -273,16 +319,19 @@ ' @ 1.0d0', ' this_variable_is_very_long_because_we_try_to_test_line_break =', ' @ 10.0d0' - ] + ] assert printer._wrap_fortran(lines) == expected + def test_settings(): raises(TypeError, lambda: fcode(S(4), method="garbage")) + def test_free_form_code_line(): x, y = symbols('x,y') assert fcode(cos(x) + sin(y), source_format='free') == "sin(y) + cos(x)" + def test_free_form_continuation_line(): x, y = symbols('x,y') result = fcode(((cos(x) + sin(y))**(7)).expand(), source_format='free') @@ -293,6 +342,7 @@ ) assert result == expected + def test_free_form_comment_line(): printer = FCodePrinter({ 'source_format': 'free'}) lines = [ "! This is a long comment on a single line that must be wrapped properly to produce nice output"] @@ -301,6 +351,7 @@ '! to produce nice output'] assert printer._wrap_fortran(lines) == expected + def test_loops(): n, m = symbols('n,m', integer=True) A = IndexedBase('A') @@ -310,20 +361,21 @@ j = Idx('j', n) expected = ( - 'do i = 1, m\n' - ' y(i) = 0\n' - 'end do\n' - 'do i = 1, m\n' - ' do j = 1, n\n' - ' y(i) = %(rhs)s\n' - ' end do\n' - 'end do' - ) + 'do i = 1, m\n' + ' y(i) = 0\n' + 'end do\n' + 'do i = 1, m\n' + ' do j = 1, n\n' + ' y(i) = %(rhs)s\n' + ' end do\n' + 'end do' + ) code = fcode(A[i, j]*x[j], assign_to=y[i], source_format='free') assert (code == expected % {'rhs': 'y(i) + A(i, j)*x(j)'} or code == expected % {'rhs': 'y(i) + x(j)*A(i, j)'}) + def test_dummy_loops(): # the following line could also be # [Dummy(s, integer=True) for s in 'im'] @@ -334,13 +386,14 @@ i = Idx(i, m) expected = ( - 'do i_%(icount)i = 1, m_%(mcount)i\n' - ' y(i_%(icount)i) = x(i_%(icount)i)\n' - 'end do' - ) % {'icount': i.label.dummy_index, 'mcount': m.dummy_index} + 'do i_%(icount)i = 1, m_%(mcount)i\n' + ' y(i_%(icount)i) = x(i_%(icount)i)\n' + 'end do' + ) % {'icount': i.label.dummy_index, 'mcount': m.dummy_index} code = fcode(x[i], assign_to=y[i], source_format='free') assert code == expected + def test_derived_classes(): class MyFancyFCodePrinter(FCodePrinter): _default_settings = FCodePrinter._default_settings.copy() @@ -350,65 +403,66 @@ x = symbols('x') assert printer.doprint(sin(x)) == " bork = sin(x)" + def test_indent(): codelines = ( - 'subroutine test(a)\n' - 'integer :: a, i, j\n' - '\n' - 'do\n' - 'do \n' - 'do j = 1, 5\n' - 'if (a>b) then\n' - 'if(b>0) then\n' - 'a = 3\n' - 'donot_indent_me = 2\n' - 'do_not_indent_me_either = 2\n' - 'ifIam_indented_something_went_wrong = 2\n' - 'if_I_am_indented_something_went_wrong = 2\n' - 'end should not be unindented here\n' - 'end if\n' - 'endif\n' - 'end do\n' - 'end do\n' - 'enddo\n' - 'end subroutine\n' - '\n' - 'subroutine test2(a)\n' - 'integer :: a\n' - 'do\n' - 'a = a + 1\n' - 'end do \n' - 'end subroutine\n' - ) + 'subroutine test(a)\n' + 'integer :: a, i, j\n' + '\n' + 'do\n' + 'do \n' + 'do j = 1, 5\n' + 'if (a>b) then\n' + 'if(b>0) then\n' + 'a = 3\n' + 'donot_indent_me = 2\n' + 'do_not_indent_me_either = 2\n' + 'ifIam_indented_something_went_wrong = 2\n' + 'if_I_am_indented_something_went_wrong = 2\n' + 'end should not be unindented here\n' + 'end if\n' + 'endif\n' + 'end do\n' + 'end do\n' + 'enddo\n' + 'end subroutine\n' + '\n' + 'subroutine test2(a)\n' + 'integer :: a\n' + 'do\n' + 'a = a + 1\n' + 'end do \n' + 'end subroutine\n' + ) expected = ( - 'subroutine test(a)\n' - 'integer :: a, i, j\n' - '\n' - 'do\n' - ' do \n' - ' do j = 1, 5\n' - ' if (a>b) then\n' - ' if(b>0) then\n' - ' a = 3\n' - ' donot_indent_me = 2\n' - ' do_not_indent_me_either = 2\n' - ' ifIam_indented_something_went_wrong = 2\n' - ' if_I_am_indented_something_went_wrong = 2\n' - ' end should not be unindented here\n' - ' end if\n' - ' endif\n' - ' end do\n' - ' end do\n' - 'enddo\n' - 'end subroutine\n' - '\n' - 'subroutine test2(a)\n' - 'integer :: a\n' - 'do\n' - ' a = a + 1\n' - 'end do \n' - 'end subroutine\n' - ) - p = FCodePrinter({'source_format':'free'}) + 'subroutine test(a)\n' + 'integer :: a, i, j\n' + '\n' + 'do\n' + ' do \n' + ' do j = 1, 5\n' + ' if (a>b) then\n' + ' if(b>0) then\n' + ' a = 3\n' + ' donot_indent_me = 2\n' + ' do_not_indent_me_either = 2\n' + ' ifIam_indented_something_went_wrong = 2\n' + ' if_I_am_indented_something_went_wrong = 2\n' + ' end should not be unindented here\n' + ' end if\n' + ' endif\n' + ' end do\n' + ' end do\n' + 'enddo\n' + 'end subroutine\n' + '\n' + 'subroutine test2(a)\n' + 'integer :: a\n' + 'do\n' + ' a = a + 1\n' + 'end do \n' + 'end subroutine\n' + ) + p = FCodePrinter({'source_format': 'free'}) result = p.indent_code(codelines) assert result == expected diff -Nru python3-sympy-0.7.2/sympy/printing/tests/test_gtk.py python3-sympy-0.7.3/sympy/printing/tests/test_gtk.py --- python3-sympy-0.7.2/sympy/printing/tests/test_gtk.py 2012-10-17 03:02:22.000000000 +0000 +++ python3-sympy-0.7.3/sympy/printing/tests/test_gtk.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,13 +1,16 @@ from sympy import print_gtk, sin from sympy.utilities.pytest import XFAIL, raises -# this test fails if python-libxml2 isn't installed. We don't want to depend on +# this test fails if python-lxml isn't installed. We don't want to depend on # anything with SymPy + + @XFAIL def test_1(): from sympy.abc import x print_gtk(x**2, start_viewer=False) - print_gtk(x**2+sin(x)/4, start_viewer=False) + print_gtk(x**2 + sin(x)/4, start_viewer=False) + def test_settings(): from sympy.abc import x diff -Nru python3-sympy-0.7.2/sympy/printing/tests/test_jscode.py python3-sympy-0.7.3/sympy/printing/tests/test_jscode.py --- python3-sympy-0.7.2/sympy/printing/tests/test_jscode.py 2012-10-17 03:02:22.000000000 +0000 +++ python3-sympy-0.7.3/sympy/printing/tests/test_jscode.py 2013-07-13 17:53:32.000000000 +0000 @@ -11,14 +11,17 @@ x, y, z = symbols('x,y,z') g = Function('g') + def test_printmethod(): assert jscode(Abs(x)) == "Math.abs(x)" + def test_jscode_sqrt(): assert jscode(sqrt(x)) == "Math.sqrt(x)" assert jscode(x**0.5) == "Math.sqrt(x)" assert jscode(sqrt(x)) == "Math.sqrt(x)" + def test_jscode_Pow(): assert jscode(x**3) == "Math.pow(x, 3)" assert jscode(x**(y**3)) == "Math.pow(x, Math.pow(y, 3))" @@ -26,49 +29,59 @@ "Math.pow(3.5*g(x), -x + Math.pow(y, x))/(Math.pow(x, 2) + y)" assert jscode(x**-1.0) == '1/x' + def test_jscode_constants_mathh(): assert jscode(exp(1)) == "Math.E" assert jscode(pi) == "Math.PI" assert jscode(oo) == "Number.POSITIVE_INFINITY" assert jscode(-oo) == "Number.NEGATIVE_INFINITY" + def test_jscode_constants_other(): - assert jscode(2*GoldenRatio) == "var GoldenRatio = 1.61803398874989;\n2*GoldenRatio" + assert jscode( + 2*GoldenRatio) == "var GoldenRatio = 1.61803398874989;\n2*GoldenRatio" assert jscode(2*Catalan) == "var Catalan = 0.915965594177219;\n2*Catalan" - assert jscode(2*EulerGamma) == "var EulerGamma = 0.577215664901533;\n2*EulerGamma" + assert jscode( + 2*EulerGamma) == "var EulerGamma = 0.577215664901533;\n2*EulerGamma" + def test_jscode_Rational(): - assert jscode(Rational(3,7)) == "3/7" - assert jscode(Rational(18,9)) == "2" - assert jscode(Rational(3,-7)) == "-3/7" - assert jscode(Rational(-3,-7)) == "3/7" + assert jscode(Rational(3, 7)) == "3/7" + assert jscode(Rational(18, 9)) == "2" + assert jscode(Rational(3, -7)) == "-3/7" + assert jscode(Rational(-3, -7)) == "3/7" + def test_jscode_Integer(): assert jscode(Integer(67)) == "67" assert jscode(Integer(-1)) == "-1" + def test_jscode_functions(): assert jscode(sin(x) ** cos(x)) == "Math.pow(Math.sin(x), Math.cos(x))" + def test_jscode_inline_function(): x = symbols('x') g = implemented_function('g', Lambda(x, 2*x)) assert jscode(g(x)) == "2*x" g = implemented_function('g', Lambda(x, 2*x/Catalan)) - assert jscode(g(x)) == "var Catalan = %s;\n2*x/Catalan" %Catalan.n() + assert jscode(g(x)) == "var Catalan = %s;\n2*x/Catalan" % Catalan.n() A = IndexedBase('A') i = Idx('i', symbols('n', integer=True)) g = implemented_function('g', Lambda(x, x*(1 + x)*(2 + x))) assert jscode(g(A[i]), assign_to=A[i]) == ( - "for (var i=0; i 3))) else (((0) if (True) else None)))))" + assert l == "((x) if (x < 1) else (((x**2) if (((x <= 4) and " \ + "(x > 3))) else (((0) if (True) else None)))))" p = Piecewise( (x**2, x < 0), @@ -66,8 +69,8 @@ ) l = lambdarepr(p) eval(h + l) - assert l == "((x**2) if (x < 0) else (((x) if (((x >= 0) and (x < 1))) "\ - "else (((-x + 2) if (x >= 1) else (((0) if (True) else None)))))))" + assert l == "((x**2) if (x < 0) else (((x) if (((x >= 0) and (x < 1))) " \ + "else (((-x + 2) if (x >= 1) else (((0) if (True) else None)))))))" p = Piecewise( (x**2, x < 0), @@ -76,8 +79,8 @@ ) l = lambdarepr(p) eval(h + l) - assert l == "((x**2) if (x < 0) else (((x) if (((x >= 0) and "\ - "(x < 1))) else (((-x + 2) if (x >= 1) else None)))))" + assert l == "((x**2) if (x < 0) else (((x) if (((x >= 0) and " \ + "(x < 1))) else (((-x + 2) if (x >= 1) else None)))))" p = Piecewise( (1, x >= 1), @@ -103,8 +106,8 @@ ) l = lambdarepr(p) eval(h + l) - assert l == "((1) if (x <= 1) else (((2) if (x <= 2) else (((3) if "\ - "(x <= 3) else (((4) if (x <= 4) else (((5) if (x <= 5) else (((6) if "\ + assert l == "((1) if (x <= 1) else (((2) if (x <= 2) else (((3) if " \ + "(x <= 3) else (((4) if (x <= 4) else (((5) if (x <= 5) else (((6) if " \ "(True) else None)))))))))))" p = Piecewise( @@ -131,9 +134,10 @@ ) l = lambdarepr(p) eval(h + l) - assert l == "((1) if (x < 1) else (((2) if (x < 2) else (((3) if "\ - "(x < 3) else (((4) if (x < 4) else (((5) if (x < 5) else (((6) if "\ + assert l == "((1) if (x < 1) else (((2) if (x < 2) else (((3) if " \ + "(x < 3) else (((4) if (x < 4) else (((5) if (x < 5) else (((6) if " \ "(True) else None)))))))))))" + def test_settings(): - raises(TypeError, lambda: lambdarepr(sin(x),method="garbage")) + raises(TypeError, lambda: lambdarepr(sin(x), method="garbage")) diff -Nru python3-sympy-0.7.2/sympy/printing/tests/test_latex.py python3-sympy-0.7.3/sympy/printing/tests/test_latex.py --- python3-sympy-0.7.2/sympy/printing/tests/test_latex.py 2012-10-17 03:02:22.000000000 +0000 +++ python3-sympy-0.7.3/sympy/printing/tests/test_latex.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,60 +1,93 @@ -from sympy import (symbols, Rational, Symbol, Integral, log, diff, sin, exp, - Function, factorial, factorial2, floor, ceiling, Abs, re, im, conjugate, - Order, Piecewise, Matrix, asin, Interval, EmptySet, Union, S, Sum, Product, - Limit, oo, Poly, Float, lowergamma, uppergamma, hyper, meijerg, polar_lift, - Lambda, Poly, RootOf, RootSum, sqrt, Dict, catalan, Min, Max, cot, coth, - re, im, root, arg, zeta, dirichlet_eta, binomial, RisingFactorial, - FallingFactorial, polylog, lerchphi, Ei, expint, Si, Ci, Shi, Chi, gamma, - legendre, assoc_legendre, chebyshevu, chebyshevt, chebyshevt_root, chebyshevu_root, - laguerre, assoc_laguerre, hermite, gegenbauer, jacobi, - Tuple, MellinTransform, InverseMellinTransform, LaplaceTransform, - InverseLaplaceTransform, FourierTransform, InverseFourierTransform, - SineTransform, InverseSineTransform, CosineTransform, - InverseCosineTransform, FiniteSet, TransformationSet, Range, Subs) +from sympy import ( + Abs, Chi, Ci, CosineTransform, Dict, Ei, Eq, FallingFactorial, FiniteSet, + Float, FourierTransform, Function, Integral, Interval, + InverseCosineTransform, InverseFourierTransform, + InverseLaplaceTransform, InverseMellinTransform, InverseSineTransform, + Lambda, LaplaceTransform, Limit, Matrix, Max, MellinTransform, Min, + Order, Piecewise, Poly, ring, field, ZZ, Product, Range, Rational, + RisingFactorial, RootOf, RootSum, S, Shi, Si, SineTransform, Subs, + Sum, Symbol, TransformationSet, Tuple, Union, Ynm, Znm, arg, asin, + assoc_laguerre, assoc_legendre, binomial, catalan, ceiling, + chebyshevt, chebyshevu, conjugate, cot, coth, diff, dirichlet_eta, + exp, expint, factorial, factorial2, floor, gamma, gegenbauer, hermite, + hyper, im, im, jacobi, laguerre, legendre, lerchphi, log, lowergamma, + meijerg, oo, polar_lift, polylog, re, re, root, sin, sqrt, symbols, + uppergamma, zeta, subfactorial, totient, elliptic_k, elliptic_f, + elliptic_e, elliptic_pi, cos, tan) from sympy.abc import mu, tau -from sympy.printing.latex import latex +from sympy.printing.latex import latex, translate from sympy.utilities.pytest import XFAIL, raises -from sympy.functions import DiracDelta +from sympy.functions import DiracDelta, Heaviside, KroneckerDelta, LeviCivita from sympy.logic import Implies +from sympy.logic.boolalg import And, Or from sympy.core.trace import Tr x, y, z, t, a, b = symbols('x y z t a b') -k, n = symbols('k n', integer=True) +k, m, n = symbols('k m n', integer=True) + def test_printmethod(): class R(Abs): def _latex(self, printer): return "foo(%s)" % printer._print(self.args[0]) assert latex(R(x)) == "foo(x)" + class R(Abs): def _latex(self, printer): return "foo" assert latex(R(x)) == "foo" + def test_latex_basic(): - assert latex(1+x) == "x + 1" + assert latex(1 + x) == "x + 1" assert latex(x**2) == "x^{2}" - assert latex(x**(1+x)) == "x^{x + 1}" - assert latex(x**3+x+1+x**2) == "x^{3} + x^{2} + x + 1" + assert latex(x**(1 + x)) == "x^{x + 1}" + assert latex(x**3 + x + 1 + x**2) == "x^{3} + x^{2} + x + 1" assert latex(2*x*y) == "2 x y" assert latex(2*x*y, mul_symbol='dot') == r"2 \cdot x \cdot y" + assert latex(1/x) == r"\frac{1}{x}" + assert latex(1/x, fold_short_frac=True) == "1 / x" + assert latex(1/x**2) == r"\frac{1}{x^{2}}" + assert latex(x/2) == r"\frac{x}{2}" + assert latex(x/2, fold_short_frac=True) == "x / 2" + assert latex((x + y)/(2*x)) == r"\frac{x + y}{2 x}" + assert latex((x + y)/(2*x), fold_short_frac=True) == \ + r"\left(x + y\right) / 2 x" + assert latex((x + y)/(2*x), long_frac_ratio=0) == \ + r"\frac{1}{2 x} \left(x + y\right)" + assert latex((x + y)/x) == r"\frac{1}{x} \left(x + y\right)" + assert latex((x + y)/x, long_frac_ratio=3) == r"\frac{x + y}{x}" + + assert latex(2*Integral(x, x)/3) == r"\frac{2}{3} \int x\, dx" + assert latex(2*Integral(x, x)/3, fold_short_frac=True) == \ + r"\left(2 \int x\, dx\right) / 3" + assert latex(sqrt(x)) == r"\sqrt{x}" - assert latex(x**Rational(1,3)) == r"\sqrt[3]{x}" + assert latex(x**Rational(1, 3)) == r"\sqrt[3]{x}" assert latex(sqrt(x)**3) == r"x^{\frac{3}{2}}" - assert latex(sqrt(x),itex=True) == r"\sqrt{x}" - assert latex(x**Rational(1,3),itex=True) == r"\root{3}{x}" - assert latex(sqrt(x)**3,itex=True) == r"x^{\frac{3}{2}}" - assert latex(x**Rational(3,4)) == r"x^{\frac{3}{4}}" - assert latex(x**Rational(3,4), fold_frac_powers=True) == "x^{3/4}" + assert latex(sqrt(x), itex=True) == r"\sqrt{x}" + assert latex(x**Rational(1, 3), itex=True) == r"\root{3}{x}" + assert latex(sqrt(x)**3, itex=True) == r"x^{\frac{3}{2}}" + assert latex(x**Rational(3, 4)) == r"x^{\frac{3}{4}}" + assert latex(x**Rational(3, 4), fold_frac_powers=True) == "x^{3/4}" + assert latex((x + 1)**Rational(3, 4)) == \ + r"\left(x + 1\right)^{\frac{3}{4}}" + assert latex((x + 1)**Rational(3, 4), fold_frac_powers=True) == \ + r"\left(x + 1\right)^{3/4}" - assert latex(1.5e20*x) == r"1.5 \times 10^{20} x" + assert latex(1.5e20*x) == r"1.5 \cdot 10^{20} x" assert latex(1.5e20*x, mul_symbol='dot') == r"1.5 \cdot 10^{20} \cdot x" + assert latex(1.5e20*x, mul_symbol='times') == r"1.5 \times 10^{20} \times x" assert latex(1/sin(x)) == r"\frac{1}{\sin{\left (x \right )}}" assert latex(sin(x)**-1) == r"\frac{1}{\sin{\left (x \right )}}" + assert latex(sin(x)**Rational(3, 2)) == \ + r"\sin^{\frac{3}{2}}{\left (x \right )}" + assert latex(sin(x)**Rational(3, 2), fold_frac_powers=True) == \ + r"\sin^{3/2}{\left (x \right )}" assert latex(~x) == r"\neg x" assert latex(x & y) == r"x \wedge y" @@ -62,7 +95,7 @@ assert latex(x | y) == r"x \vee y" assert latex(x | y | z) == r"x \vee y \vee z" assert latex((x & y) | z) == r"z \vee \left(x \wedge y\right)" - assert latex(Implies(x,y)) == r"x \Rightarrow y" + assert latex(Implies(x, y)) == r"x \Rightarrow y" assert latex(~(x >> ~y)) == r"\neg (x \Rightarrow \neg y)" assert latex(~x, symbol_names={x: "x_i"}) == r"\neg x_i" @@ -73,21 +106,29 @@ assert latex(x | y, symbol_names={x: "x_i", y: "y_i"}) == r"x_i \vee y_i" assert latex(x | y | z, symbol_names={x: "x_i", y: "y_i", z: "z_i"}) == \ r"x_i \vee y_i \vee z_i" - assert latex((x & y) | z, symbol_names={x: "x_i", y: "y_i", z: "z_i"}) ==\ + assert latex((x & y) | z, symbol_names={x: "x_i", y: "y_i", z: "z_i"}) == \ r"z_i \vee \left(x_i \wedge y_i\right)" - assert latex(Implies(x,y), symbol_names={x: "x_i", y: "y_i"}) == \ + assert latex(Implies(x, y), symbol_names={x: "x_i", y: "y_i"}) == \ r"x_i \Rightarrow y_i" + +def test_latex_builtins(): + assert latex(True) == r"\mathrm{True}" + assert latex(False) == r"\mathrm{False}" + assert latex(None) == r"\mathrm{None}" + + def test_latex_Float(): - assert latex(Float(1.0e100)) == r"1.0 \times 10^{100}" - assert latex(Float(1.0e-100)) == r"1.0 \times 10^{-100}" - assert latex(Float(1.0e-100), mul_symbol="dot") == r"1.0 \cdot 10^{-100}" + assert latex(Float(1.0e100)) == r"1.0 \cdot 10^{100}" + assert latex(Float(1.0e-100)) == r"1.0 \cdot 10^{-100}" + assert latex(Float(1.0e-100), mul_symbol="times") == r"1.0 \times 10^{-100}" assert latex(1.0*oo) == r"\infty" assert latex(-1.0*oo) == r"- \infty" + def test_latex_symbols(): - Gamma, lmbda, rho = list(map(Symbol, ('Gamma', 'lambda', 'rho'))) - mass, volume = list(map(Symbol, ('mass', 'volume'))) + Gamma, lmbda, rho = symbols('Gamma, lambda, rho') + mass, volume = symbols('mass, volume') assert latex(Gamma + lmbda) == r"\Gamma + \lambda" assert latex(Gamma * lmbda) == r"\Gamma \lambda" assert latex(Symbol('q21')) == r"q_{21}" @@ -95,23 +136,46 @@ assert latex(Symbol('91')) == r"91" assert latex(Symbol('alpha_new')) == r"\alpha_{new}" assert latex(Symbol('C^orig')) == r"C^{orig}" + assert latex(Symbol('x^alpha')) == r"x^{\alpha}" + assert latex(Symbol('beta^alpha')) == r"\beta^{\alpha}" + assert latex(Symbol('e^Alpha')) == r"e^{A}" + @XFAIL def test_latex_symbols_failing(): - assert latex(volume * rho == mass) == r"\rho \mathrm{volume} = \mathrm{mass}" + rho, mass, volume = symbols('rho, mass, volume') + assert latex( + volume * rho == mass) == r"\rho \mathrm{volume} = \mathrm{mass}" assert latex(volume / mass * rho == 1) == r"\rho \mathrm{volume} {\mathrm{mass}}^{(-1)} = 1" assert latex(mass**3 * volume**3) == r"{\mathrm{mass}}^{3} \cdot {\mathrm{volume}}^{3}" + def test_latex_functions(): assert latex(exp(x)) == "e^{x}" assert latex(exp(1) + exp(2)) == "e + e^{2}" f = Function('f') - assert latex(f(x)) == '\\operatorname{f}{\\left (x \\right )}' + assert latex(f(x)) == r'f{\left (x \right )}' + assert latex(f) == r'f' + + g = Function('g') + assert latex(g(x, y)) == r'g{\left (x,y \right )}' + assert latex(g) == r'g' + + h = Function('h') + assert latex(h(x, y, z)) == r'h{\left (x,y,z \right )}' + assert latex(h) == r'h' + + Li = Function('Li') + assert latex(Li) == r'\operatorname{Li}' + assert latex(Li(x)) == r'\operatorname{Li}{\left (x \right )}' beta = Function('beta') + # not to be confused with the beta function assert latex(beta(x)) == r"\beta{\left (x \right )}" + assert latex(beta) == r"\beta" + assert latex(sin(x)) == r"\sin{\left (x \right )}" assert latex(sin(x), fold_func_brackets=True) == r"\sin {x}" assert latex(sin(2*x**2), fold_func_brackets=True) == \ @@ -131,19 +195,25 @@ assert latex(factorial(k)) == r"k!" assert latex(factorial(-k)) == r"\left(- k\right)!" + assert latex(subfactorial(k)) == r"!k" + assert latex(subfactorial(-k)) == r"!\left(- k\right)" + assert latex(factorial2(k)) == r"k!!" assert latex(factorial2(-k)) == r"\left(- k\right)!!" assert latex(binomial(2, k)) == r"{\binom{2}{k}}" - assert latex(FallingFactorial(3, k)) == r"{\left(3\right)}_{\left(k\right)}" + assert latex( + FallingFactorial(3, k)) == r"{\left(3\right)}_{\left(k\right)}" assert latex(RisingFactorial(3, k)) == r"{\left(3\right)}^{\left(k\right)}" assert latex(floor(x)) == r"\lfloor{x}\rfloor" assert latex(ceiling(x)) == r"\lceil{x}\rceil" assert latex(Min(x, 2, x**3)) == r"\min\left(2, x, x^{3}\right)" + assert latex(Min(x, y)**2) == r"\min\left(x, y\right)^{2}" assert latex(Max(x, 2, x**3)) == r"\max\left(2, x, x^{3}\right)" - assert latex(Abs(x)) == r"\lvert{x}\rvert" + assert latex(Max(x, y)**2) == r"\max\left(x, y\right)^{2}" + assert latex(Abs(x)) == r"\left\lvert{x}\right\rvert" assert latex(re(x)) == r"\Re{x}" assert latex(re(x + y)) == r"\Re{x} + \Re{y}" assert latex(im(x)) == r"\Im{x}" @@ -168,57 +238,96 @@ assert latex(dirichlet_eta(x)) == r"\eta\left(x\right)" assert latex(dirichlet_eta(x)**2) == r"\eta^{2}\left(x\right)" assert latex(polylog(x, y)) == r"\operatorname{Li}_{x}\left(y\right)" - assert latex(polylog(x, y)**2) == r"\operatorname{Li}_{x}^{2}\left(y\right)" + assert latex( + polylog(x, y)**2) == r"\operatorname{Li}_{x}^{2}\left(y\right)" assert latex(lerchphi(x, y, n)) == r"\Phi\left(x, y, n\right)" assert latex(lerchphi(x, y, n)**2) == r"\Phi^{2}\left(x, y, n\right)" + assert latex(elliptic_k(z)) == r"K\left(z\right)" + assert latex(elliptic_k(z)**2) == r"K^{2}\left(z\right)" + assert latex(elliptic_f(x, y)) == r"F\left(x\middle| y\right)" + assert latex(elliptic_f(x, y)**2) == r"F^{2}\left(x\middle| y\right)" + assert latex(elliptic_e(x, y)) == r"E\left(x\middle| y\right)" + assert latex(elliptic_e(x, y)**2) == r"E^{2}\left(x\middle| y\right)" + assert latex(elliptic_e(z)) == r"E\left(z\right)" + assert latex(elliptic_e(z)**2) == r"E^{2}\left(z\right)" + assert latex(elliptic_pi(x, y, z)) == r"\Pi\left(x; y\middle| z\right)" + assert latex(elliptic_pi(x, y, z)**2) == \ + r"\Pi^{2}\left(x; y\middle| z\right)" + assert latex(elliptic_pi(x, y)) == r"\Pi\left(x\middle| y\right)" + assert latex(elliptic_pi(x, y)**2) == r"\Pi^{2}\left(x\middle| y\right)" + assert latex(Ei(x)) == r'\operatorname{Ei}{\left (x \right )}' assert latex(Ei(x)**2) == r'\operatorname{Ei}^{2}{\left (x \right )}' assert latex(expint(x, y)**2) == r'\operatorname{E}_{x}^{2}\left(y\right)' assert latex(Shi(x)**2) == r'\operatorname{Shi}^{2}{\left (x \right )}' assert latex(Si(x)**2) == r'\operatorname{Si}^{2}{\left (x \right )}' assert latex(Ci(x)**2) == r'\operatorname{Ci}^{2}{\left (x \right )}' - assert latex(Chi(x)**2) == r'\operatorname{Chi}^{2}{\left (x \right )}' + assert latex(Chi(x)**2) == r'\operatorname{Chi}^{2}{\left (x \right )}', latex(Chi(x)**2) + assert latex(Chi(x**2)**2) == r'\operatorname{Chi}^{2}{\left (x^{2} \right )}', latex(Chi(x**2)**2) - assert latex(jacobi(n, a, b, x)) == r'P_{n}^{\left(a,b\right)}\left(x\right)' + assert latex( + jacobi(n, a, b, x)) == r'P_{n}^{\left(a,b\right)}\left(x\right)' assert latex(jacobi(n, a, b, x)**2) == r'\left(P_{n}^{\left(a,b\right)}\left(x\right)\right)^{2}' - assert latex(gegenbauer(n, a, x)) == r'C_{n}^{\left(a\right)}\left(x\right)' + assert latex( + gegenbauer(n, a, x)) == r'C_{n}^{\left(a\right)}\left(x\right)' assert latex(gegenbauer(n, a, x)**2) == r'\left(C_{n}^{\left(a\right)}\left(x\right)\right)^{2}' assert latex(chebyshevt(n, x)) == r'T_{n}\left(x\right)' - assert latex(chebyshevt(n, x)**2) == r'\left(T_{n}\left(x\right)\right)^{2}' + assert latex( + chebyshevt(n, x)**2) == r'\left(T_{n}\left(x\right)\right)^{2}' assert latex(chebyshevu(n, x)) == r'U_{n}\left(x\right)' - assert latex(chebyshevu(n, x)**2) == r'\left(U_{n}\left(x\right)\right)^{2}' + assert latex( + chebyshevu(n, x)**2) == r'\left(U_{n}\left(x\right)\right)^{2}' assert latex(legendre(n, x)) == r'P_{n}\left(x\right)' assert latex(legendre(n, x)**2) == r'\left(P_{n}\left(x\right)\right)^{2}' - assert latex(assoc_legendre(n, a, x)) == r'P_{n}^{\left(a\right)}\left(x\right)' + assert latex( + assoc_legendre(n, a, x)) == r'P_{n}^{\left(a\right)}\left(x\right)' assert latex(assoc_legendre(n, a, x)**2) == r'\left(P_{n}^{\left(a\right)}\left(x\right)\right)^{2}' assert latex(laguerre(n, x)) == r'L_{n}\left(x\right)' assert latex(laguerre(n, x)**2) == r'\left(L_{n}\left(x\right)\right)^{2}' - assert latex(assoc_laguerre(n, a, x)) == r'L_{n}^{\left(a\right)}\left(x\right)' + assert latex( + assoc_laguerre(n, a, x)) == r'L_{n}^{\left(a\right)}\left(x\right)' assert latex(assoc_laguerre(n, a, x)**2) == r'\left(L_{n}^{\left(a\right)}\left(x\right)\right)^{2}' assert latex(hermite(n, x)) == r'H_{n}\left(x\right)' assert latex(hermite(n, x)**2) == r'\left(H_{n}\left(x\right)\right)^{2}' - # Test latex printing of function names with "_" - assert latex(polar_lift(0)) == r"\operatorname{polar\_lift}{\left (0 \right )}" - assert latex(polar_lift(0)**3) == r"\operatorname{polar\_lift}^{3}{\left (0 \right )}" + theta = Symbol("theta", real=True) + phi = Symbol("phi", real=True) + assert latex(Ynm(n,m,theta,phi)) == r'Y_{n}^{m}\left(\theta,\phi\right)' + assert latex(Ynm(n, m, theta, phi)**3) == r'\left(Y_{n}^{m}\left(\theta,\phi\right)\right)^{3}' + assert latex(Znm(n,m,theta,phi)) == r'Z_{n}^{m}\left(\theta,\phi\right)' + assert latex(Znm(n, m, theta, phi)**3) == r'\left(Z_{n}^{m}\left(\theta,\phi\right)\right)^{3}' + # Test latex printing of function names with "_" + assert latex( + polar_lift(0)) == r"\operatorname{polar\_lift}{\left (0 \right )}" + assert latex(polar_lift( + 0)**3) == r"\operatorname{polar\_lift}^{3}{\left (0 \right )}" + + assert latex(totient(n)) == r'\phi\left( n \right)' + + # some unknown function name should get rendered with \operatorname + fjlkd = Function('fjlkd') + assert latex(fjlkd(x)) == r'\operatorname{fjlkd}{\left (x \right )}' + # even when it is referred to without an argument + assert latex(fjlkd) == r'\operatorname{fjlkd}' def test_hyper_printing(): - from sympy import pi, Tuple + from sympy import pi from sympy.abc import x, z - assert latex(meijerg(Tuple(pi, pi, x), Tuple(1), \ - (0,1), Tuple(1, 2, 3/pi),z)) == \ - r'{G_{4, 5}^{2, 3}\left(\begin{matrix} \pi, \pi, x & 1 \\0, 1 & 1, 2, \frac{3}{\pi} \end{matrix} \middle| {z} \right)}' - assert latex(meijerg(Tuple(), Tuple(1), (0,), Tuple(),z)) == \ - r'{G_{1, 1}^{1, 0}\left(\begin{matrix} & 1 \\0 & \end{matrix} \middle| {z} \right)}' + assert latex(meijerg(Tuple(pi, pi, x), Tuple(1), + (0, 1), Tuple(1, 2, 3/pi), z)) == \ + r'{G_{4, 5}^{2, 3}\left(\begin{matrix} \pi, \pi, x & 1 \\0, 1 & 1, 2, \frac{3}{\pi} \end{matrix} \middle| {z} \right)}' + assert latex(meijerg(Tuple(), Tuple(1), (0,), Tuple(), z)) == \ + r'{G_{1, 1}^{1, 0}\left(\begin{matrix} & 1 \\0 & \end{matrix} \middle| {z} \right)}' assert latex(hyper((x, 2), (3,), z)) == \ - r'{{}_{2}F_{1}\left(\begin{matrix} x, 2 ' \ - r'\\ 3 \end{matrix}\middle| {z} \right)}' + r'{{}_{2}F_{1}\left(\begin{matrix} x, 2 ' \ + r'\\ 3 \end{matrix}\middle| {z} \right)}' assert latex(hyper(Tuple(), Tuple(1), z)) == \ - r'{{}_{0}F_{1}\left(\begin{matrix} ' \ - r'\\ 1 \end{matrix}\middle| {z} \right)}' + r'{{}_{0}F_{1}\left(\begin{matrix} ' \ + r'\\ 1 \end{matrix}\middle| {z} \right)}' + def test_latex_bessel(): from sympy.functions.special.bessel import (besselj, bessely, besseli, @@ -229,11 +338,12 @@ assert latex(besseli(n, z)) == r'I_{n}\left(z\right)' assert latex(besselk(n, z)) == r'K_{n}\left(z\right)' assert latex(hankel1(n, z**2)**2) == \ - r'\left(H^{(1)}_{n}\left(z^{2}\right)\right)^{2}' + r'\left(H^{(1)}_{n}\left(z^{2}\right)\right)^{2}' assert latex(hankel2(n, z)) == r'H^{(2)}_{n}\left(z\right)' assert latex(jn(n, z)) == r'j_{n}\left(z\right)' assert latex(yn(n, z)) == r'y_{n}\left(z\right)' + def test_latex_fresnel(): from sympy.functions.special.error_functions import (fresnels, fresnelc) from sympy.abc import z @@ -242,26 +352,58 @@ assert latex(fresnels(z)**2) == r'S^{2}\left(z\right)' assert latex(fresnelc(z)**2) == r'C^{2}\left(z\right)' + def test_latex_brackets(): assert latex((-1)**x) == r"\left(-1\right)^{x}" + def test_latex_derivatives(): + # regular "d" for ordinary derivatives assert latex(diff(x**3, x, evaluate=False)) == \ - r"\frac{\partial}{\partial x} x^{3}" - assert latex(diff(sin(x)+x**2, x, evaluate=False)) == \ - r"\frac{\partial}{\partial x}\left(x^{2} + \sin{\left (x \right )}\right)" + r"\frac{d}{d x} x^{3}" + assert latex(diff(sin(x) + x**2, x, evaluate=False)) == \ + r"\frac{d}{d x}\left(x^{2} + \sin{\left (x \right )}\right)" + assert latex(diff(diff(sin(x) + x**2, x, evaluate=False), evaluate=False)) == \ + r"\frac{d^{2}}{d x^{2}} \left(x^{2} + \sin{\left (x \right )}\right)" + assert latex(diff(diff(diff(sin(x) + x**2, x, evaluate=False), evaluate=False), evaluate=False)) == \ + r"\frac{d^{3}}{d x^{3}} \left(x^{2} + \sin{\left (x \right )}\right)" + + # \partial for partial derivatives + assert latex(diff(sin(x * y), x, evaluate=False)) == \ + r"\frac{\partial}{\partial x} \sin{\left (x y \right )}" + assert latex(diff(sin(x * y) + x**2, x, evaluate=False)) == \ + r"\frac{\partial}{\partial x}\left(x^{2} + \sin{\left (x y \right )}\right)" + assert latex(diff(diff(sin(x*y) + x**2, x, evaluate=False), x, evaluate=False)) == \ + r"\frac{\partial^{2}}{\partial x^{2}} \left(x^{2} + \sin{\left (x y \right )}\right)" + assert latex(diff(diff(diff(sin(x*y) + x**2, x, evaluate=False), x, evaluate=False), x, evaluate=False)) == \ + r"\frac{\partial^{3}}{\partial x^{3}} \left(x^{2} + \sin{\left (x y \right )}\right)" + + # mixed partial derivatives + f = Function("f") + assert latex(diff(diff(f(x,y), x, evaluate=False), y, evaluate=False)) == \ + r"\frac{\partial^{2}}{\partial x\partial y} " + latex(f(x,y)) + + assert latex(diff(diff(diff(f(x,y), x, evaluate=False), x, evaluate=False), y, evaluate=False)) == \ + r"\frac{\partial^{3}}{\partial x^{2}\partial y} " + latex(f(x,y)) + + # use ordinary d when one of the variables has been integrated out + assert latex(diff(Integral(exp(-x * y), (x, 0, oo)), y, evaluate=False)) == \ + r"\frac{d}{d y} \int_{0}^{\infty} e^{- x y}\, dx" def test_latex_subs(): - assert latex(Subs(x*y, (x, y), (1, 2))) == r'\left. x y \right|_{\substack{ x=1\\ y=2 }}' + assert latex(Subs(x*y, ( + x, y), (1, 2))) == r'\left. x y \right|_{\substack{ x=1\\ y=2 }}' + def test_latex_integrals(): assert latex(Integral(log(x), x)) == r"\int \log{\left (x \right )}\, dx" - assert latex(Integral(x**2, (x,0,1))) == r"\int_{0}^{1} x^{2}\, dx" - assert latex(Integral(x**2, (x,10,20))) == r"\int_{10}^{20} x^{2}\, dx" - assert latex(Integral(y*x**2, (x,0,1), y)) == r"\int\int_{0}^{1} x^{2} y\, dx\, dy" - assert latex(Integral(y*x**2, (x,0,1), y), mode='equation*') \ + assert latex(Integral(x**2, (x, 0, 1))) == r"\int_{0}^{1} x^{2}\, dx" + assert latex(Integral(x**2, (x, 10, 20))) == r"\int_{10}^{20} x^{2}\, dx" + assert latex(Integral( + y*x**2, (x, 0, 1), y)) == r"\int\int_{0}^{1} x^{2} y\, dx\, dy" + assert latex(Integral(y*x**2, (x, 0, 1), y), mode='equation*') \ == r"\begin{equation*}\int\int\limits_{0}^{1} x^{2} y\, dx\, dy\end{equation*}" - assert latex(Integral(y*x**2, (x,0,1), y), mode='equation*', itex=True) \ + assert latex(Integral(y*x**2, (x, 0, 1), y), mode='equation*', itex=True) \ == r"$$\int\int_{0}^{1} x^{2} y\, dx\, dy$$" assert latex(Integral(x, (x, 0))) == r"\int^{0} x\, dx" assert latex(Integral(x*y, x, y)) == r"\iint x y\, dx\, dy" @@ -273,6 +415,7 @@ assert latex(Integral(x, x, y, (z, 0, 1))) == \ r"\int_{0}^{1}\int\int x\, dx\, dy\, dz" + def test_latex_sets(): for s in (FiniteSet, frozenset, set): assert latex(s([x*y, x**2])) == r"\left\{x^{2}, x y\right\}" @@ -280,11 +423,13 @@ assert latex(s(list(range(1, 13)))) == \ r"\left\{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12\right\}" + def test_latex_Range(): - assert latex(Range(1, 51)) ==\ - r'\left\{1, 2, \ldots, 50\right\}' + assert latex(Range(1, 51)) == \ + r'\left\{1, 2, \ldots, 50\right\}' assert latex(Range(1, 4)) == r'\left\{1, 2, 3\right\}' + def test_latex_intervals(): a = Symbol('a', real=True) assert latex(Interval(0, 0)) == r"\left\{0\right\}" @@ -294,31 +439,37 @@ assert latex(Interval(0, a, False, True)) == r"\left[0, a\right)" assert latex(Interval(0, a, True, True)) == r"\left(0, a\right)" + def test_latex_emptyset(): assert latex(S.EmptySet) == r"\emptyset" + def test_latex_union(): assert latex(Union(Interval(0, 1), Interval(2, 3))) == \ r"\left[0, 1\right] \cup \left[2, 3\right]" assert latex(Union(Interval(1, 1), Interval(2, 2), Interval(3, 4))) == \ r"\left\{1, 2\right\} \cup \left[3, 4\right]" + def test_latex_productset(): - line = Interval(0,1) + line = Interval(0, 1) bigline = Interval(0, 10) fset = FiniteSet(1, 2, 3) - assert latex(line**2) == r"%s^2"%latex(line) - assert latex(line * bigline * fset) == r"%s \times %s \times %s"%( - latex(line), latex(bigline), latex(fset)) + assert latex(line**2) == r"%s^2" % latex(line) + assert latex(line * bigline * fset) == r"%s \times %s \times %s" % ( + latex(line), latex(bigline), latex(fset)) + def test_latex_Naturals(): assert latex(S.Naturals) == r"\mathbb{N}" assert latex(S.Integers) == r"\mathbb{Z}" + def test_latex_TransformationSet(): x = Symbol('x') assert latex(TransformationSet(Lambda(x, x**2), S.Naturals)) == \ - r"\left\{x^{2}\; |\; x \in \mathbb{N}\right\}" + r"\left\{x^{2}\; |\; x \in \mathbb{N}\right\}" + def test_latex_sum(): assert latex(Sum(x*y**2, (x, -2, 2), (y, -5, 5))) == \ @@ -328,6 +479,7 @@ assert latex(Sum(x**2 + y, (x, -2, 2))) == \ r"\sum_{x=-2}^{2} \left(x^{2} + y\right)" + def test_latex_product(): assert latex(Product(x*y**2, (x, -2, 2), (y, -5, 5))) == \ r"\prod_{\substack{-2 \leq x \leq 2\\-5 \leq y \leq 5}} x y^{2}" @@ -336,25 +488,28 @@ assert latex(Product(x**2 + y, (x, -2, 2))) == \ r"\prod_{x=-2}^{2} \left(x^{2} + y\right)" + def test_latex_limits(): assert latex(Limit(x, x, oo)) == r"\lim_{x \to \infty} x" + def test_issue469(): beta = Symbol(r'\beta') - y = beta+x + y = beta + x assert latex(y) in [r'\beta + x', r'x + \beta'] beta = Symbol(r'beta') - y = beta+x + y = beta + x assert latex(y) in [r'\beta + x', r'x + \beta'] + def test_latex(): - assert latex((2*tau)**Rational(7,2)) == "8 \\sqrt{2} \\tau^{\\frac{7}{2}}" - assert latex((2*mu)**Rational(7,2), mode='equation*') == \ - "\\begin{equation*}8 \\sqrt{2} \\mu^{\\frac{7}{2}}\\end{equation*}" - assert latex((2*mu)**Rational(7,2), mode='equation', itex=True) == \ - "$$8 \\sqrt{2} \\mu^{\\frac{7}{2}}$$" - assert latex([2/x, y]) =="\\begin{bmatrix}\\frac{2}{x}, & y\\end{bmatrix}" + assert latex((2*tau)**Rational(7, 2)) == "8 \\sqrt{2} \\tau^{\\frac{7}{2}}" + assert latex((2*mu)**Rational(7, 2), mode='equation*') == \ + "\\begin{equation*}8 \\sqrt{2} \\mu^{\\frac{7}{2}}\\end{equation*}" + assert latex((2*mu)**Rational(7, 2), mode='equation', itex=True) == \ + "$$8 \\sqrt{2} \\mu^{\\frac{7}{2}}$$" + assert latex([2/x, y]) == "\\begin{bmatrix}\\frac{2}{x}, & y\\end{bmatrix}" def test_latex_dict(): @@ -363,38 +518,67 @@ D = Dict(d) assert latex(D) == '\\begin{Bmatrix}1 : 1, & x : 3, & x^{2} : 2, & x^{3} : 4\\end{Bmatrix}' + def test_latex_rational(): #tests issue 874 - assert latex(-Rational(1,2)) == "- \\frac{1}{2}" - assert latex(Rational(-1,2)) == "- \\frac{1}{2}" - assert latex(Rational(1,-2)) == "- \\frac{1}{2}" - assert latex(-Rational(-1,2)) == "\\frac{1}{2}" - assert latex(-Rational(1,2)*x) == "- \\frac{1}{2} x" - assert latex(-Rational(1,2)*x+Rational(-2,3)*y) in [ - "- \\frac{1}{2} x - \\frac{2}{3} y", - "- \\frac{2}{3} y - \\frac{1}{2} x", - ] + assert latex(-Rational(1, 2)) == "- \\frac{1}{2}" + assert latex(Rational(-1, 2)) == "- \\frac{1}{2}" + assert latex(Rational(1, -2)) == "- \\frac{1}{2}" + assert latex(-Rational(-1, 2)) == "\\frac{1}{2}" + assert latex(-Rational(1, 2)*x) == "- \\frac{x}{2}" + assert latex(-Rational(1, 2)*x + Rational(-2, 3)*y) == \ + "- \\frac{x}{2} - \\frac{2 y}{3}" + def test_latex_inverse(): #tests issue 1030 assert latex(1/x) == "\\frac{1}{x}" - assert latex(1/(x+y)) in ["\\frac{1}{x + y}", "\\frac{1}{y + x}"] + assert latex(1/(x + y)) == "\\frac{1}{x + y}" + def test_latex_DiracDelta(): - assert latex(DiracDelta(x)) == "\\delta\\left(x\\right)" - assert latex(DiracDelta(x,0)) == "\\delta\\left(x\\right)" - assert latex(DiracDelta(x,5)) == "\\delta^{\\left( 5 \\right)}\\left( x \\right)" + assert latex(DiracDelta(x)) == r"\delta\left(x\right)" + assert latex(DiracDelta(x)**2) == r"\left(\delta\left(x\right)\right)^{2}" + assert latex(DiracDelta(x, 0)) == r"\delta\left(x\right)" + assert latex(DiracDelta(x, 5)) == \ + r"\delta^{\left( 5 \right)}\left( x \right)" + assert latex(DiracDelta(x, 5)**2) == \ + r"\left(\delta^{\left( 5 \right)}\left( x \right)\right)^{2}" + + +def test_latex_Heaviside(): + assert latex(Heaviside(x)) == r"\theta\left(x\right)" + assert latex(Heaviside(x)**2) == r"\left(\theta\left(x\right)\right)^{2}" + + +def test_latex_KroneckerDelta(): + assert latex(KroneckerDelta(x, y)) == r"\delta_{x y}" + assert latex(KroneckerDelta(x, y + 1)) == r"\delta_{x, y + 1}" + # issue 3479 + assert latex(KroneckerDelta(x + 1, y)) == r"\delta_{y, x + 1}" + + +def test_latex_LeviCivita(): + assert latex(LeviCivita(x, y, z)) == r"\varepsilon_{x y z}" + assert latex(LeviCivita(x, y, z)**2) == r"\left(\varepsilon_{x y z}\right)^{2}" + assert latex(LeviCivita(x, y, z + 1)) == r"\varepsilon_{x, y, z + 1}" + assert latex(LeviCivita(x, y + 1, z)) == r"\varepsilon_{x, y + 1, z}" + assert latex(LeviCivita(x + 1, y, z)) == r"\varepsilon_{x + 1, y, z}" + def test_mode(): - expr = x+y + expr = x + y assert latex(expr) == 'x + y' assert latex(expr, mode='plain') == 'x + y' assert latex(expr, mode='inline') == '$x + y$' - assert latex(expr, mode='equation*')== '\\begin{equation*}x + y\\end{equation*}' - assert latex(expr, mode='equation')== '\\begin{equation}x + y\\end{equation}' + assert latex( + expr, mode='equation*') == '\\begin{equation*}x + y\\end{equation*}' + assert latex( + expr, mode='equation') == '\\begin{equation}x + y\\end{equation}' + def test_latex_Piecewise(): - p = Piecewise((x,x<1),(x**2,True)) + p = Piecewise((x, x < 1), (x**2, True)) assert latex(p) == "\\begin{cases} x & \\text{for}\: x < 1 \\\\x^{2} &" \ " \\text{otherwise} \\end{cases}" assert latex(p, itex=True) == "\\begin{cases} x & \\text{for}\: x \\lt 1 \\\\x^{2} &" \ @@ -402,20 +586,28 @@ p = Piecewise((x, x < 0), (0, x >= 0)) assert latex(p) == "\\begin{cases} x & \\text{for}\\: x < 0 \\\\0 &" \ " \\text{for}\\: x \\geq 0 \\end{cases}" + A, B = symbols("A B", commutative=False) + p = Piecewise((A**2, Eq(A, B)), (A*B, True)) + s = r"\begin{cases} A^{2} & \text{for}\: A = B \\A B & \text{otherwise} \end{cases}" + assert latex(p) == s + assert latex(A*p) == r"A %s" % s + assert latex(p*A) == r"\left(%s\right) A" % s + def test_latex_Matrix(): - M = Matrix([[1+x, y],[y, x-1]]) - assert latex(M) == '\\left[\\begin{smallmatrix}x + 1 & y\\\\y & x -'\ - '1\\end{smallmatrix}\\right]' - settings = {'mat_str' : 'bmatrix'} - assert latex(M, **settings) == '\\left[\\begin{bmatrix}x + 1 & y\\\\y &'\ - ' x -1\\end{bmatrix}\\right]' + M = Matrix([[1 + x, y], [y, x - 1]]) + assert latex(M) == '\\left[\\begin{smallmatrix}{}x + 1 & y\\\\y & x - 1' \ + '\\end{smallmatrix}\\right]' + settings = {'mat_str': 'bmatrix'} + assert latex(M, **settings) == '\\left[\\begin{bmatrix}{}x + 1 & y\\\\y &' \ + ' x - 1\\end{bmatrix}\\right]' settings['mat_delim'] = None - assert latex(M, **settings) == '\\begin{bmatrix}x + 1 & y\\\\y & x -1'\ - '\\end{bmatrix}' - assert latex(M) == '\\left[\\begin{smallmatrix}x + 1 & y\\\\y & x -1'\ + assert latex(M, **settings) == '\\begin{bmatrix}{}x + 1 & y\\\\y & x - 1' \ + '\\end{bmatrix}' + assert latex(M) == '\\left[\\begin{smallmatrix}{}x + 1 & y\\\\y & x - 1' \ '\\end{smallmatrix}\\right]' + def test_latex_mul_symbol(): assert latex(4*4**x, mul_symbol='times') == "4 \\times 4^{x}" assert latex(4*4**x, mul_symbol='dot') == "4 \\cdot 4^{x}" @@ -425,13 +617,12 @@ assert latex(4*x, mul_symbol='dot') == "4 \\cdot x" assert latex(4*x, mul_symbol='ldot') == "4 \,.\, x" -def test_latex_Poly(): - assert latex(Poly(x**2 + 2 * x, x)) == r"x^{2} + 2 x" def test_latex_issue1282(): y = 4*4**log(2) - assert latex(y) == '4 \\times 4^{\\log{\\left (2 \\right )}}' - assert latex(1/y) == '\\frac{1}{4 \\times 4^{\\log{\\left (2 \\right )}}}' + assert latex(y) == r'4 \cdot 4^{\log{\left (2 \right )}}' + assert latex(1/y) == r'\frac{1}{4 \cdot 4^{\log{\left (2 \right )}}}' + def test_latex_issue1477(): assert latex(Symbol("beta_13_2")) == r"\beta_{13 2}" @@ -455,10 +646,11 @@ assert latex(Symbol("alpha^aleph")) == r"\alpha^{\aleph}" assert latex(Symbol("alpha__aleph")) == r"\alpha^{\aleph}" + def test_latex_pow_fraction(): x = Symbol('x') # Testing exp - assert 'e^{-x}' in latex(exp(-x)/2).replace(' ', '') # Remove Whitespace + assert 'e^{-x}' in latex(exp(-x)/2).replace(' ', '') # Remove Whitespace # Testing just e^{-x} in case future changes alter behavior of muls or fracs # In particular current output is \frac{1}{2}e^{- x} but perhaps this will @@ -467,6 +659,7 @@ # Testing general, non-exp, power assert '3^{-x}' in latex(3**-x/2).replace(' ', '') + def test_noncommutative(): A, B, C = symbols('A,B,C', commutative=False) @@ -474,11 +667,14 @@ assert latex(C**-1*A*B) == "C^{-1} A B" assert latex(A*C**-1*B) == "A C^{-1} B" + def test_latex_order(): expr = x**3 + x**2*y + 3*x*y**3 + y**4 assert latex(expr, order='lex') == "x^{3} + x^{2} y + 3 x y^{3} + y^{4}" - assert latex(expr, order='rev-lex') == "y^{4} + 3 x y^{3} + x^{2} y + x^{3}" + assert latex( + expr, order='rev-lex') == "y^{4} + 3 x y^{3} + x^{2} y + x^{3}" + def test_latex_Lambda(): assert latex(Lambda(x, x + 1)) == \ @@ -486,38 +682,86 @@ assert latex(Lambda((x, y), x + 1)) == \ r"\Lambda {\left (\begin{pmatrix}x, & y\end{pmatrix}, x + 1 \right )}" + +def test_latex_PolyElement(): + Ruv, u,v = ring("u,v", ZZ); + Rxyz, x,y,z = ring("x,y,z", Ruv.to_domain()) + + assert latex(x - x) == r"0" + assert latex(x - 1) == r"x - 1" + assert latex(x + 1) == r"x + 1" + + assert latex((u**2 + 3*u*v + 1)*x**2*y + u + 1) == r"\left({u}^{2} + 3 u v + 1\right) {x}^{2} y + u + 1" + assert latex((u**2 + 3*u*v + 1)*x**2*y + (u + 1)*x) == r"\left({u}^{2} + 3 u v + 1\right) {x}^{2} y + \left(u + 1\right) x" + assert latex((u**2 + 3*u*v + 1)*x**2*y + (u + 1)*x + 1) == r"\left({u}^{2} + 3 u v + 1\right) {x}^{2} y + \left(u + 1\right) x + 1" + assert latex((-u**2 + 3*u*v - 1)*x**2*y - (u + 1)*x - 1) == r"-\left({u}^{2} - 3 u v + 1\right) {x}^{2} y - \left(u + 1\right) x - 1" + + +def test_latex_FracElement(): + Fuv, u,v = field("u,v", ZZ); + Fxyzt, x,y,z,t = field("x,y,z,t", Fuv.to_domain()) + + assert latex(x - x) == r"0" + assert latex(x - 1) == r"x - 1" + assert latex(x + 1) == r"x + 1" + + assert latex(x/z) == r"\frac{x}{z}" + assert latex(x*y/z) == r"\frac{x y}{z}" + assert latex(x/(z*t)) == r"\frac{x}{z t}" + assert latex(x*y/(z*t)) == r"\frac{x y}{z t}" + + assert latex((x - 1)/y) == r"\frac{x - 1}{y}" + assert latex((x + 1)/y) == r"\frac{x + 1}{y}" + assert latex((-x - 1)/y) == r"\frac{-x - 1}{y}" + assert latex((x + 1)/(y*z)) == r"\frac{x + 1}{y z}" + assert latex(-y/(x + 1)) == r"\frac{-y}{x + 1}" + assert latex(y*z/(x + 1)) == r"\frac{y z}{x + 1}" + + assert latex(((u + 1)*x*y + 1)/((v - 1)*z - 1)) == r"\frac{\left(u + 1\right) x y + 1}{\left(v - 1\right) z - 1}" + assert latex(((u + 1)*x*y + 1)/((v - 1)*z - t*u*v - 1)) == r"\frac{\left(u + 1\right) x y + 1}{\left(v - 1\right) z - u v t - 1}" + + def test_latex_Poly(): + assert latex(Poly(x**2 + 2 * x, x)) == \ + r"\operatorname{Poly}{\left( x^{2} + 2 x, x, domain=\mathbb{Z} \right)}" assert latex(Poly(x/y, x)) == \ r"\operatorname{Poly}{\left( \frac{x}{y}, x, domain=\mathbb{Z}\left(y\right) \right)}" assert latex(Poly(2.0*x + y)) == \ r"\operatorname{Poly}{\left( 2.0 x + 1.0 y, x, y, domain=\mathbb{R} \right)}" + def test_latex_RootOf(): assert latex(RootOf(x**5 + x + 3, 0)) == \ r"\operatorname{RootOf} {\left(x^{5} + x + 3, 0\right)}" + def test_latex_RootSum(): assert latex(RootSum(x**5 + x + 3, sin)) == \ r"\operatorname{RootSum} {\left(x^{5} + x + 3, \Lambda {\left (x, \sin{\left (x \right )} \right )}\right)}" + def test_settings(): raises(TypeError, lambda: latex(x*y, method="garbage")) + def test_latex_numbers(): assert latex(catalan(n)) == r"C_{n}" + def test_lamda(): assert latex(Symbol('lamda')) == r"\lambda" assert latex(Symbol('Lamda')) == r"\Lambda" + def test_custom_symbol_names(): x = Symbol('x') y = Symbol('y') assert latex(x) == "x" - assert latex(x, symbol_names={x:"x_i"}) == "x_i" - assert latex(x + y, symbol_names={x:"x_i"}) == "x_i + y" - assert latex(x**2, symbol_names={x:"x_i"}) == "x_i^{2}" - assert latex(x + y, symbol_names={x:"x_i", y:"y_j"}) == "x_i + y_j" + assert latex(x, symbol_names={x: "x_i"}) == "x_i" + assert latex(x + y, symbol_names={x: "x_i"}) == "x_i + y" + assert latex(x**2, symbol_names={x: "x_i"}) == "x_i^{2}" + assert latex(x + y, symbol_names={x: "x_i", y: "y_j"}) == "x_i + y_j" + def test_matAdd(): from sympy import MatrixSymbol @@ -525,11 +769,12 @@ C = MatrixSymbol('C', 5, 5) B = MatrixSymbol('B', 5, 5) l = LatexPrinter() - assert l._print_MatAdd(C - 2*B) in ['- 2 B + C', 'C - 2 B'] + assert l._print_MatAdd(C - 2*B) in ['-2 B + C', 'C -2 B'] assert l._print_MatAdd(C + 2*B) in ['2 B + C', 'C + 2 B'] - assert l._print_MatAdd(B - 2*C) in ['B - 2 C', '- 2 C + B'] + assert l._print_MatAdd(B - 2*C) in ['B -2 C', '-2 C + B'] assert l._print_MatAdd(B + 2*C) in ['B + 2 C', '2 C + B'] + def test_matMul(): from sympy import MatrixSymbol from sympy.printing.latex import LatexPrinter @@ -539,25 +784,34 @@ l = LatexPrinter() assert l._print_MatMul(2*A) == '2 A' assert l._print_MatMul(2*x*A) == '2 x A' - assert l._print_MatMul(-2*A) == '- 2 A' - assert l._print_MatMul(1.0*A) == '1.0 A' + assert l._print_MatMul(-2*A) == '-2 A' + assert l._print_MatMul(1.5*A) == '1.5 A' assert l._print_MatMul(sqrt(2)*A) == r'\sqrt{2} A' assert l._print_MatMul(-sqrt(2)*A) == r'- \sqrt{2} A' assert l._print_MatMul(2*sqrt(2)*x*A) == r'2 \sqrt{2} x A' - assert l._print_MatMul(-2*A*(A+2*B)) in [r'- 2 A \left(A + 2 B\right)', - r'- 2 A \left(2 B + A\right)'] + assert l._print_MatMul(-2*A*(A + 2*B)) in [r'-2 A \left(A + 2 B\right)', + r'-2 A \left(2 B + A\right)'] + +def test_latex_MatrixSlice(): + from sympy.matrices.expressions import MatrixSymbol + assert latex(MatrixSymbol('X', 10, 10)[:5, 1:9:2]) == \ + r'X\left[:5, 1:9:2\right]' + assert latex(MatrixSymbol('X', 10, 10)[5, :5:2]) == \ + r'X\left[5, :5:2\right]' def test_latex_RandomDomain(): from sympy.stats import Normal, Die, Exponential, pspace, where X = Normal('x1', 0, 1) - assert latex(where(X>0)) == "Domain: 0 < x_{1}" + assert latex(where(X > 0)) == "Domain: x_{1} > 0" D = Die('d1', 6) - assert latex(where(D>4)) == r"Domain: d_{1} = 5 \vee d_{1} = 6" + assert latex(where(D > 4)) == r"Domain: d_{1} = 5 \vee d_{1} = 6" A = Exponential('a', 1) B = Exponential('b', 1) - assert latex(pspace(Tuple(A,B)).domain) =="Domain: 0 \leq a \wedge 0 \leq b" + assert latex( + pspace(Tuple(A, B)).domain) == "Domain: a \geq 0 \wedge b \geq 0" + def test_PrettyPoly(): from sympy.polys.domains import QQ @@ -567,6 +821,7 @@ assert latex(F.convert(x/(x + y))) == latex(x/(x + y)) assert latex(R.convert(x + y)) == latex(x + y) + def test_integral_transforms(): x = Symbol("x") k = Symbol("k") @@ -574,31 +829,32 @@ a = Symbol("a") b = Symbol("b") - assert latex(MellinTransform(f(x), x, k)) == r"\mathcal{M}_{x}\left[\operatorname{f}{\left (x \right )}\right]\left(k\right)" - assert latex(InverseMellinTransform(f(k), k, x, a,b)) == r"\mathcal{M}^{-1}_{k}\left[\operatorname{f}{\left (k \right )}\right]\left(x\right)" + assert latex(MellinTransform(f(x), x, k)) == r"\mathcal{M}_{x}\left[f{\left (x \right )}\right]\left(k\right)" + assert latex(InverseMellinTransform(f(k), k, x, a, b)) == r"\mathcal{M}^{-1}_{k}\left[f{\left (k \right )}\right]\left(x\right)" + + assert latex(LaplaceTransform(f(x), x, k)) == r"\mathcal{L}_{x}\left[f{\left (x \right )}\right]\left(k\right)" + assert latex(InverseLaplaceTransform(f(k), k, x, (a, b))) == r"\mathcal{L}^{-1}_{k}\left[f{\left (k \right )}\right]\left(x\right)" - assert latex(LaplaceTransform(f(x), x, k)) == r"\mathcal{L}_{x}\left[\operatorname{f}{\left (x \right )}\right]\left(k\right)" - assert latex(InverseLaplaceTransform(f(k), k, x, (a,b))) == r"\mathcal{L}^{-1}_{k}\left[\operatorname{f}{\left (k \right )}\right]\left(x\right)" + assert latex(FourierTransform(f(x), x, k)) == r"\mathcal{F}_{x}\left[f{\left (x \right )}\right]\left(k\right)" + assert latex(InverseFourierTransform(f(k), k, x)) == r"\mathcal{F}^{-1}_{k}\left[f{\left (k \right )}\right]\left(x\right)" - assert latex(FourierTransform(f(x), x, k)) == r"\mathcal{F}_{x}\left[\operatorname{f}{\left (x \right )}\right]\left(k\right)" - assert latex(InverseFourierTransform(f(k), k, x)) == r"\mathcal{F}^{-1}_{k}\left[\operatorname{f}{\left (k \right )}\right]\left(x\right)" + assert latex(CosineTransform(f(x), x, k)) == r"\mathcal{COS}_{x}\left[f{\left (x \right )}\right]\left(k\right)" + assert latex(InverseCosineTransform(f(k), k, x)) == r"\mathcal{COS}^{-1}_{k}\left[f{\left (k \right )}\right]\left(x\right)" - assert latex(CosineTransform(f(x), x, k)) == r"\mathcal{COS}_{x}\left[\operatorname{f}{\left (x \right )}\right]\left(k\right)" - assert latex(InverseCosineTransform(f(k), k, x)) == r"\mathcal{COS}^{-1}_{k}\left[\operatorname{f}{\left (k \right )}\right]\left(x\right)" + assert latex(SineTransform(f(x), x, k)) == r"\mathcal{SIN}_{x}\left[f{\left (x \right )}\right]\left(k\right)" + assert latex(InverseSineTransform(f(k), k, x)) == r"\mathcal{SIN}^{-1}_{k}\left[f{\left (k \right )}\right]\left(x\right)" - assert latex(SineTransform(f(x), x, k)) == r"\mathcal{SIN}_{x}\left[\operatorname{f}{\left (x \right )}\right]\left(k\right)" - assert latex(InverseSineTransform(f(k), k, x)) == r"\mathcal{SIN}^{-1}_{k}\left[\operatorname{f}{\left (k \right )}\right]\left(x\right)" def test_PolynomialRing(): from sympy.polys.domains import QQ assert latex(QQ[x, y]) == r"\mathbb{Q}\left[x, y\right]" assert latex(QQ.poly_ring(x, y, order="ilex")) == \ - r"S_<^{-1}\mathbb{Q}\left[x, y\right]" + r"S_<^{-1}\mathbb{Q}\left[x, y\right]" + def test_categories(): - from sympy.categories import (Object, Morphism, IdentityMorphism, - NamedMorphism, CompositeMorphism, - Category, Diagram, DiagramGrid) + from sympy.categories import (Object, IdentityMorphism, + NamedMorphism, Category, Diagram, DiagramGrid) A1 = Object("A1") A2 = Object("A2") @@ -620,24 +876,23 @@ d = Diagram() assert latex(d) == "\emptyset" - d = Diagram({f1:"unique", f2:S.EmptySet}) + d = Diagram({f1: "unique", f2: S.EmptySet}) assert latex(d) == "\\begin{Bmatrix}f_{2}\\circ f_{1}:A_{1}" \ - "\\rightarrow A_{3} : \\emptyset, & id:A_{1}\\rightarrow " \ - "A_{1} : \\emptyset, & id:A_{2}\\rightarrow A_{2} : " \ - "\\emptyset, & id:A_{3}\\rightarrow A_{3} : \\emptyset, " \ - "& f_{1}:A_{1}\\rightarrow A_{2} : \\left\\{unique\\right\\}, " \ - "& f_{2}:A_{2}\\rightarrow A_{3} : \\emptyset\\end{Bmatrix}" + "\\rightarrow A_{3} : \\emptyset, & id:A_{1}\\rightarrow " \ + "A_{1} : \\emptyset, & id:A_{2}\\rightarrow A_{2} : " \ + "\\emptyset, & id:A_{3}\\rightarrow A_{3} : \\emptyset, " \ + "& f_{1}:A_{1}\\rightarrow A_{2} : \\left\\{unique\\right\\}, " \ + "& f_{2}:A_{2}\\rightarrow A_{3} : \\emptyset\\end{Bmatrix}" - d = Diagram({f1:"unique", f2:S.EmptySet}, {f2 * f1: "unique"}) + d = Diagram({f1: "unique", f2: S.EmptySet}, {f2 * f1: "unique"}) assert latex(d) == "\\begin{Bmatrix}f_{2}\\circ f_{1}:A_{1}" \ - "\\rightarrow A_{3} : \\emptyset, & id:A_{1}\\rightarrow " \ - "A_{1} : \\emptyset, & id:A_{2}\\rightarrow A_{2} : " \ - "\\emptyset, & id:A_{3}\\rightarrow A_{3} : \\emptyset, " \ - "& f_{1}:A_{1}\\rightarrow A_{2} : \\left\\{unique\\right\\}," \ - " & f_{2}:A_{2}\\rightarrow A_{3} : \\emptyset\\end{Bmatrix}" \ - "\\Longrightarrow \\begin{Bmatrix}f_{2}\\circ f_{1}:A_{1}" \ - "\\rightarrow A_{3} : \\left\\{unique\\right\\}\\end{Bmatrix}" - + "\\rightarrow A_{3} : \\emptyset, & id:A_{1}\\rightarrow " \ + "A_{1} : \\emptyset, & id:A_{2}\\rightarrow A_{2} : " \ + "\\emptyset, & id:A_{3}\\rightarrow A_{3} : \\emptyset, " \ + "& f_{1}:A_{1}\\rightarrow A_{2} : \\left\\{unique\\right\\}," \ + " & f_{2}:A_{2}\\rightarrow A_{3} : \\emptyset\\end{Bmatrix}" \ + "\\Longrightarrow \\begin{Bmatrix}f_{2}\\circ f_{1}:A_{1}" \ + "\\rightarrow A_{3} : \\left\\{unique\\right\\}\\end{Bmatrix}" # A linear diagram. A = Object("A") @@ -649,9 +904,10 @@ grid = DiagramGrid(d) assert latex(grid) == "\\begin{array}{cc}\n" \ - "A & B \\\\\n"\ - " & C \n" \ - "\\end{array}\n" + "A & B \\\\\n" \ + " & C \n" \ + "\\end{array}\n" + def test_Modules(): from sympy.polys.domains import QQ @@ -670,21 +926,174 @@ Q = F / M assert latex(Q) == r"\frac{{\mathbb{Q}\left[x, y\right]}^{2}}{\left< {\left[ {x},{y} \right]},{\left[ {1},{x^{2}} \right]} \right>}" assert latex(Q.submodule([1, x**3/2], [2, y])) == \ - r"\left< {{\left[ {1},{\frac{1}{2} x^{3}} \right]} + {\left< {\left[ {x},{y} \right]},{\left[ {1},{x^{2}} \right]} \right>}},{{\left[ {2},{y} \right]} + {\left< {\left[ {x},{y} \right]},{\left[ {1},{x^{2}} \right]} \right>}} \right>" + r"\left< {{\left[ {1},{\frac{x^{3}}{2}} \right]} + {\left< {\left[ {x},{y} \right]},{\left[ {1},{x^{2}} \right]} \right>}},{{\left[ {2},{y} \right]} + {\left< {\left[ {x},{y} \right]},{\left[ {1},{x^{2}} \right]} \right>}} \right>" h = homomorphism(QQ[x].free_module(2), QQ[x].free_module(2), [0, 0]) - assert latex(h) == r"{\left[\begin{smallmatrix}0 & 0\\0 & 0\end{smallmatrix}\right]} : {{\mathbb{Q}\left[x\right]}^{2}} \to {{\mathbb{Q}\left[x\right]}^{2}}" + assert latex(h) == r"{\left[\begin{smallmatrix}{}0 & 0\\0 & 0\end{smallmatrix}\right]} : {{\mathbb{Q}\left[x\right]}^{2}} \to {{\mathbb{Q}\left[x\right]}^{2}}" + def test_QuotientRing(): from sympy.polys.domains import QQ R = QQ[x]/[x**2 + 1] - assert latex(R) == r"\frac{\mathbb{Q}\left[x\right]}{\left< {x^{2} + 1} \right>}" + assert latex( + R) == r"\frac{\mathbb{Q}\left[x\right]}{\left< {x^{2} + 1} \right>}" assert latex(R.one) == r"{1} + {\left< {x^{2} + 1} \right>}" + def test_Tr(): #TODO: Handle indices A, B = symbols('A B', commutative=False) t = Tr(A*B) assert latex(t) == r'\mbox{Tr}\left(A B\right)' + + +def test_Adjoint(): + from sympy.matrices import MatrixSymbol, Adjoint, Inverse, Transpose + X = MatrixSymbol('X', 2, 2) + Y = MatrixSymbol('Y', 2, 2) + assert latex(Adjoint(X)) == r'X^\dag' + assert latex(Adjoint(X + Y)) == r'\left(X + Y\right)^\dag' + assert latex(Adjoint(X) + Adjoint(Y)) == r'X^\dag + Y^\dag' + assert latex(Adjoint(X*Y)) == r'\left(X Y\right)^\dag' + assert latex(Adjoint(Y)*Adjoint(X)) == r'Y^\dag X^\dag' + assert latex(Adjoint(X**2)) == r'\left(X^{2}\right)^\dag' + assert latex(Adjoint(X)**2) == r'\left(X^\dag\right)^{2}' + assert latex(Adjoint(Inverse(X))) == r'\left(X^{-1}\right)^\dag' + assert latex(Inverse(Adjoint(X))) == r'\left(X^\dag\right)^{-1}' + assert latex(Adjoint(Transpose(X))) == r'\left(X^T\right)^\dag' + assert latex(Transpose(Adjoint(X))) == r'\left(X^\dag\right)^T' + + +def test_Hadamard(): + from sympy.matrices import MatrixSymbol, HadamardProduct + X = MatrixSymbol('X', 2, 2) + Y = MatrixSymbol('Y', 2, 2) + assert latex(HadamardProduct(X, Y*Y)) == r'X \circ \left(Y Y\right)' + assert latex(HadamardProduct(X, Y)*Y) == r'\left(X \circ Y\right) Y' + +def test_boolean_args_order(): + syms = symbols('a:f') + + expr = And(*syms) + assert latex(expr) == 'a \\wedge b \\wedge c \\wedge d \\wedge e \\wedge f' + + expr = Or(*syms) + assert latex(expr) == 'a \\vee b \\vee c \\vee d \\vee e \\vee f' + +def test_imaginary(): + i = sqrt(-1) + assert latex(i) == r'i' + +def test_builtins_without_args(): + assert latex(sin) == r'\sin' + assert latex(cos) == r'\cos' + assert latex(tan) == r'\tan' + assert latex(log) == r'\log' + assert latex(Ei) == r'\operatorname{Ei}' + assert latex(zeta) == r'\zeta' + +@XFAIL +def test_latex_greek_functions(): + # bug because capital greeks that have roman equivalents should not use + # \Alpha, \Beta, \Eta, etc. + s = Function('Alpha') + assert latex(s) == r'A' + s = Function('Beta') + assert latex(s) == r'B' + s = Function('Eta') + assert latex(s) == r'H' + + s = symbols('Alpha') + assert latex(s) == r'A' + s = symbols('Beta') + assert latex(s) == r'B' + s = symbols('Eta') + assert latex(s) == r'H' + + # bug because sympy.core.numbers.Pi is special + p = Function('Pi') + assert latex(p(x)) == r'\Pi{\left (x \right )}' + assert latex(p) == r'\Pi' + + # bug because not all greeks are included + c = Function('chi') + assert latex(c(x)) == r'\chi{\left (x \right )}' + assert latex(c) == r'\chi' + + # bug because the name is 'gamma' but the representation should be \Gamma + assert latex(gamma) == r'\Gamma' + +def test_translate(): + s = 'Alpha' + assert translate(s) == 'A' + s = 'Beta' + assert translate(s) == 'B' + s = 'Eta' + assert translate(s) == 'H' + s = 'omicron' + assert translate(s) == 'o' + s = 'Pi' + assert translate(s) == r'\Pi' + s = 'pi' + assert translate(s) == r'\pi' + +def test_greek_symbols(): + assert latex(Symbol('alpha')) == r'\alpha' + assert latex(Symbol('beta')) == r'\beta' + assert latex(Symbol('gamma')) == r'\gamma' + assert latex(Symbol('delta')) == r'\delta' + assert latex(Symbol('epsilon')) == r'\epsilon' + assert latex(Symbol('zeta')) == r'\zeta' + assert latex(Symbol('eta')) == r'\eta' + assert latex(Symbol('theta')) == r'\theta' + assert latex(Symbol('iota')) == r'\iota' + assert latex(Symbol('kappa')) == r'\kappa' + assert latex(Symbol('lambda')) == r'\lambda' + assert latex(Symbol('mu')) == r'\mu' + assert latex(Symbol('nu')) == r'\nu' + assert latex(Symbol('xi')) == r'\xi' + assert latex(Symbol('omicron')) == r'o' + assert latex(Symbol('pi')) == r'\pi' + assert latex(Symbol('rho')) == r'\rho' + assert latex(Symbol('sigma')) == r'\sigma' + assert latex(Symbol('tau')) == r'\tau' + assert latex(Symbol('upsilon')) == r'\upsilon' + assert latex(Symbol('phi')) == r'\phi' + assert latex(Symbol('chi')) == r'\chi' + assert latex(Symbol('psi')) == r'\psi' + assert latex(Symbol('omega')) == r'\omega' + + assert latex(Symbol('Alpha')) == r'A' + assert latex(Symbol('Beta')) == r'B' + assert latex(Symbol('Gamma')) == r'\Gamma' + assert latex(Symbol('Delta')) == r'\Delta' + assert latex(Symbol('Epsilon')) == r'E' + assert latex(Symbol('Zeta')) == r'Z' + assert latex(Symbol('Eta')) == r'H' + assert latex(Symbol('Theta')) == r'\Theta' + assert latex(Symbol('Iota')) == r'I' + assert latex(Symbol('Kappa')) == r'K' + assert latex(Symbol('Lambda')) == r'\Lambda' + assert latex(Symbol('Mu')) == r'M' + assert latex(Symbol('Nu')) == r'N' + assert latex(Symbol('Xi')) == r'\Xi' + assert latex(Symbol('Omicron')) == r'O' + assert latex(Symbol('Pi')) == r'\Pi' + assert latex(Symbol('Rho')) == r'P' + assert latex(Symbol('Sigma')) == r'\Sigma' + assert latex(Symbol('Tau')) == r'T' + assert latex(Symbol('Upsilon')) == r'\Upsilon' + assert latex(Symbol('Phi')) == r'\Phi' + assert latex(Symbol('Chi')) == r'X' + assert latex(Symbol('Psi')) == r'\Psi' + assert latex(Symbol('Omega')) == r'\Omega' + + +@XFAIL +def test_builtin_without_args_mismatched_names(): + assert latex(KroneckerDelta) == r'\delta' + assert latex(DiracDelta) == r'\delta' + assert latex(CosineTransform) == r'\mathcal{COS}' + assert latex(lowergamma) == r'\gamma' diff -Nru python3-sympy-0.7.2/sympy/printing/tests/test_mathml.py python3-sympy-0.7.3/sympy/printing/tests/test_mathml.py --- python3-sympy-0.7.2/sympy/printing/tests/test_mathml.py 2012-10-17 03:02:22.000000000 +0000 +++ python3-sympy-0.7.3/sympy/printing/tests/test_mathml.py 2013-07-13 17:53:32.000000000 +0000 @@ -2,7 +2,6 @@ tan, asin, acos, atan, sinh, cosh, tanh, asinh, acosh, atanh, E, I, oo, \ pi, GoldenRatio, EulerGamma, Sum, Eq, Ne, Ge, Lt, Float from sympy.printing.mathml import mathml, MathMLPrinter -from xml.dom.minidom import parseString from sympy.utilities.pytest import raises @@ -10,16 +9,18 @@ y = Symbol('y') mp = MathMLPrinter() + def test_printmethod(): - assert mp.doprint(1+x) == 'x1' + assert mp.doprint(1 + x) == 'x1' + def test_mathml_core(): - mml_1 = mp._print(1+x) + mml_1 = mp._print(1 + x) assert mml_1.nodeName == 'apply' nodes = mml_1.childNodes assert len(nodes) == 3 assert nodes[0].nodeName == 'plus' - assert nodes[0].hasChildNodes() == False + assert nodes[0].hasChildNodes() is False assert nodes[0].nodeValue is None assert nodes[1].nodeName in ['cn', 'ci'] if nodes[1].nodeName == 'cn': @@ -42,13 +43,14 @@ assert nodes[1].childNodes[0].nodeValue == '2' assert nodes[2].childNodes[0].nodeValue == 'x' - mml = mp._print(Float(1.0,2)*x) + mml = mp._print(Float(1.0, 2)*x) assert mml.nodeName == 'apply' nodes = mml.childNodes assert nodes[0].nodeName == 'times' assert nodes[1].childNodes[0].nodeValue == '1.0' assert nodes[2].childNodes[0].nodeValue == 'x' + def test_mathml_functions(): mml_1 = mp._print(sin(x)) assert mml_1.nodeName == 'apply' @@ -59,7 +61,16 @@ assert mml_2.nodeName == 'apply' assert mml_2.childNodes[0].nodeName == 'diff' assert mml_2.childNodes[1].nodeName == 'bvar' - assert mml_2.childNodes[1].childNodes[0].nodeName == 'ci' # below bvar there's x/ci> + assert mml_2.childNodes[1].childNodes[ + 0].nodeName == 'ci' # below bvar there's x/ci> + + mml_3 = mp._print(diff(cos(x*y), x, evaluate=False)) + assert mml_3.nodeName == 'apply' + assert mml_3.childNodes[0].nodeName == 'partialdiff' + assert mml_3.childNodes[1].nodeName == 'bvar' + assert mml_3.childNodes[1].childNodes[ + 0].nodeName == 'ci' # below bvar there's x/ci> + def test_mathml_limits(): # XXX No unevaluated limits @@ -70,6 +81,7 @@ assert mml_1.childNodes[2].nodeName == 'lowlimit' assert mml_1.childNodes[3].toxml() == mp._print(lim_fun).toxml() + def test_mathml_integrals(): integrand = x mml_1 = mp._print(Integral(integrand, (x, 0, 1))) @@ -79,6 +91,7 @@ assert mml_1.childNodes[3].nodeName == 'uplimit' assert mml_1.childNodes[4].toxml() == mp._print(integrand).toxml() + def test_mathml_sums(): summand = x mml_1 = mp._print(Sum(summand, (x, 1, 10))) @@ -88,6 +101,7 @@ assert mml_1.childNodes[3].nodeName == 'uplimit' assert mml_1.childNodes[4].toxml() == mp._print(summand).toxml() + def test_mathml_tuples(): mml_1 = mp._print([2]) assert mml_1.nodeName == 'list' @@ -100,8 +114,6 @@ assert mml_2.childNodes[1].nodeName == 'cn' assert len(mml_2.childNodes) == 2 -def test_mathml_matrices(): - pass #TODO def test_mathml_add(): mml = mp._print(x**5 - x**4 + x) @@ -109,14 +121,16 @@ assert mml.childNodes[1].childNodes[0].nodeName == 'minus' assert mml.childNodes[1].childNodes[1].nodeName == 'apply' + def test_mathml_Rational(): - mml_1 = mp._print(Rational(1,1)) + mml_1 = mp._print(Rational(1, 1)) """should just return a number""" assert mml_1.nodeName == 'cn' - mml_2 = mp._print(Rational(2,5)) + mml_2 = mp._print(Rational(2, 5)) assert mml_2.childNodes[0].nodeName == 'divide' + def test_mathml_constants(): mml = mp._print(I) assert mml.nodeName == 'imaginaryi' @@ -135,6 +149,7 @@ mml = mathml(EulerGamma) assert mml == '' + def test_mathml_trig(): mml = mp._print(sin(x)) assert mml.childNodes[0].nodeName == 'sin' @@ -172,8 +187,9 @@ mml = mp._print(acosh(x)) assert mml.childNodes[0].nodeName == 'arccosh' + def test_mathml_relational(): - mml_1 = mp._print(Eq(x,1)) + mml_1 = mp._print(Eq(x, 1)) assert mml_1.nodeName == 'apply' assert mml_1.childNodes[0].nodeName == 'eq' assert mml_1.childNodes[1].nodeName == 'ci' @@ -181,7 +197,7 @@ assert mml_1.childNodes[2].nodeName == 'cn' assert mml_1.childNodes[2].childNodes[0].nodeValue == '1' - mml_2 = mp._print(Ne(1,x)) + mml_2 = mp._print(Ne(1, x)) assert mml_2.nodeName == 'apply' assert mml_2.childNodes[0].nodeName == 'neq' assert mml_2.childNodes[1].nodeName == 'cn' @@ -189,7 +205,7 @@ assert mml_2.childNodes[2].nodeName == 'ci' assert mml_2.childNodes[2].childNodes[0].nodeValue == 'x' - mml_3 = mp._print(Ge(1,x)) + mml_3 = mp._print(Ge(1, x)) assert mml_3.nodeName == 'apply' assert mml_3.childNodes[0].nodeName == 'geq' assert mml_3.childNodes[1].nodeName == 'cn' @@ -197,7 +213,7 @@ assert mml_3.childNodes[2].nodeName == 'ci' assert mml_3.childNodes[2].childNodes[0].nodeValue == 'x' - mml_4 = mp._print(Lt(1,x)) + mml_4 = mp._print(Lt(1, x)) assert mml_4.nodeName == 'apply' assert mml_4.childNodes[0].nodeName == 'lt' assert mml_4.childNodes[1].nodeName == 'cn' @@ -206,14 +222,6 @@ assert mml_4.childNodes[2].childNodes[0].nodeValue == 'x' -def test_c2p(): - """This tests some optional routines that depend on libxslt1 (which is optional)""" - try: - from sympy.modules.mathml import c2p - assert c2p(f.mathml) == result - except ImportError: - pass - def test_symbol(): mml = mp._print(Symbol("x")) assert mml.nodeName == 'ci' @@ -276,11 +284,14 @@ assert mml.childNodes[0].childNodes[0].childNodes[0].nodeValue == 'x' assert mml.childNodes[0].childNodes[1].nodeName == 'mml:mrow' assert mml.childNodes[0].childNodes[1].childNodes[0].nodeName == 'mml:mi' - assert mml.childNodes[0].childNodes[1].childNodes[0].childNodes[0].nodeValue == '2' + assert mml.childNodes[0].childNodes[1].childNodes[0].childNodes[ + 0].nodeValue == '2' assert mml.childNodes[0].childNodes[1].childNodes[1].nodeName == 'mml:mo' - assert mml.childNodes[0].childNodes[1].childNodes[1].childNodes[0].nodeValue == ' ' + assert mml.childNodes[0].childNodes[1].childNodes[1].childNodes[ + 0].nodeValue == ' ' assert mml.childNodes[0].childNodes[1].childNodes[2].nodeName == 'mml:mi' - assert mml.childNodes[0].childNodes[1].childNodes[2].childNodes[0].nodeValue == 'a' + assert mml.childNodes[0].childNodes[1].childNodes[2].childNodes[ + 0].nodeValue == 'a' del mml mml = mp._print(Symbol("x^2^a")) @@ -290,11 +301,14 @@ assert mml.childNodes[0].childNodes[0].childNodes[0].nodeValue == 'x' assert mml.childNodes[0].childNodes[1].nodeName == 'mml:mrow' assert mml.childNodes[0].childNodes[1].childNodes[0].nodeName == 'mml:mi' - assert mml.childNodes[0].childNodes[1].childNodes[0].childNodes[0].nodeValue == '2' + assert mml.childNodes[0].childNodes[1].childNodes[0].childNodes[ + 0].nodeValue == '2' assert mml.childNodes[0].childNodes[1].childNodes[1].nodeName == 'mml:mo' - assert mml.childNodes[0].childNodes[1].childNodes[1].childNodes[0].nodeValue == ' ' + assert mml.childNodes[0].childNodes[1].childNodes[1].childNodes[ + 0].nodeValue == ' ' assert mml.childNodes[0].childNodes[1].childNodes[2].nodeName == 'mml:mi' - assert mml.childNodes[0].childNodes[1].childNodes[2].childNodes[0].nodeValue == 'a' + assert mml.childNodes[0].childNodes[1].childNodes[2].childNodes[ + 0].nodeValue == 'a' del mml mml = mp._print(Symbol("x__2__a")) @@ -304,13 +318,17 @@ assert mml.childNodes[0].childNodes[0].childNodes[0].nodeValue == 'x' assert mml.childNodes[0].childNodes[1].nodeName == 'mml:mrow' assert mml.childNodes[0].childNodes[1].childNodes[0].nodeName == 'mml:mi' - assert mml.childNodes[0].childNodes[1].childNodes[0].childNodes[0].nodeValue == '2' + assert mml.childNodes[0].childNodes[1].childNodes[0].childNodes[ + 0].nodeValue == '2' assert mml.childNodes[0].childNodes[1].childNodes[1].nodeName == 'mml:mo' - assert mml.childNodes[0].childNodes[1].childNodes[1].childNodes[0].nodeValue == ' ' + assert mml.childNodes[0].childNodes[1].childNodes[1].childNodes[ + 0].nodeValue == ' ' assert mml.childNodes[0].childNodes[1].childNodes[2].nodeName == 'mml:mi' - assert mml.childNodes[0].childNodes[1].childNodes[2].childNodes[0].nodeValue == 'a' + assert mml.childNodes[0].childNodes[1].childNodes[2].childNodes[ + 0].nodeValue == 'a' del mml + def test_mathml_greek(): mml = mp._print(Symbol('alpha')) assert mml.nodeName == 'ci' @@ -367,6 +385,7 @@ assert mp.doprint(Symbol('Psi')) == 'Ψ' assert mp.doprint(Symbol('Omega')) == 'Ω' + def test_mathml_order(): expr = x**3 + x**2*y + 3*x*y**3 + y**4 @@ -392,13 +411,16 @@ assert mml.childNodes[4].childNodes[1].childNodes[0].data == 'x' assert mml.childNodes[4].childNodes[2].childNodes[0].data == '3' + def test_settings(): raises(TypeError, lambda: mathml(Symbol("x"), method="garbage")) + def test_toprettyxml_hooking(): # test that the patch doesn't influence the behavior of the standard library import xml.dom.minidom - doc = xml.dom.minidom.parseString("x1") + doc = xml.dom.minidom.parseString( + "x1") prettyxml_old = doc.toprettyxml() mp.apply_patch() diff -Nru python3-sympy-0.7.2/sympy/printing/tests/test_precedence.py python3-sympy-0.7.3/sympy/printing/tests/test_precedence.py --- python3-sympy-0.7.2/sympy/printing/tests/test_precedence.py 2012-10-17 03:02:22.000000000 +0000 +++ python3-sympy-0.7.3/sympy/printing/tests/test_precedence.py 2013-07-13 17:53:32.000000000 +0000 @@ -12,65 +12,77 @@ x, y = symbols("x,y") + def test_Add(): - assert precedence(x+y) == PRECEDENCE["Add"] - assert precedence(x*y+1) == PRECEDENCE["Add"] + assert precedence(x + y) == PRECEDENCE["Add"] + assert precedence(x*y + 1) == PRECEDENCE["Add"] + def test_Function(): assert precedence(sin(x)) == PRECEDENCE["Atom"] - assert precedence(Derivative(x,y)) == PRECEDENCE["Atom"] + assert precedence(Derivative(x, y)) == PRECEDENCE["Atom"] + def test_Integral(): - assert precedence(Integral(x,y)) == PRECEDENCE["Atom"] + assert precedence(Integral(x, y)) == PRECEDENCE["Atom"] + def test_Mul(): assert precedence(x*y) == PRECEDENCE["Mul"] assert precedence(-x*y) == PRECEDENCE["Add"] + def test_Number(): assert precedence(Integer(0)) == PRECEDENCE["Atom"] assert precedence(Integer(1)) == PRECEDENCE["Atom"] assert precedence(Integer(-1)) == PRECEDENCE["Add"] assert precedence(Integer(10)) == PRECEDENCE["Atom"] - assert precedence(Rational(5,2)) == PRECEDENCE["Mul"] - assert precedence(Rational(-5,2)) == PRECEDENCE["Add"] + assert precedence(Rational(5, 2)) == PRECEDENCE["Mul"] + assert precedence(Rational(-5, 2)) == PRECEDENCE["Add"] assert precedence(Float(5)) == PRECEDENCE["Atom"] assert precedence(Float(-5)) == PRECEDENCE["Add"] assert precedence(oo) == PRECEDENCE["Atom"] assert precedence(-oo) == PRECEDENCE["Add"] + def test_Order(): assert precedence(Order(x)) == PRECEDENCE["Atom"] + def test_Pow(): assert precedence(x**y) == PRECEDENCE["Pow"] assert precedence(-x**y) == PRECEDENCE["Add"] assert precedence(x**-y) == PRECEDENCE["Pow"] + def test_Product(): - assert precedence(Product(x,(x,y,y+1))) == PRECEDENCE["Atom"] + assert precedence(Product(x, (x, y, y + 1))) == PRECEDENCE["Atom"] + def test_Relational(): - assert precedence(Rel(x+y,y,"<")) == PRECEDENCE["Relational"] + assert precedence(Rel(x + y, y, "<")) == PRECEDENCE["Relational"] + def test_Sum(): - assert precedence(Sum(x,(x,y,y+1))) == PRECEDENCE["Atom"] + assert precedence(Sum(x, (x, y, y + 1))) == PRECEDENCE["Atom"] + def test_Symbol(): assert precedence(x) == PRECEDENCE["Atom"] + def test_And_Or(): # precendence relations between logical operators, ... - assert precedence(x&y) > precedence(x|y) - assert precedence(~y) > precedence(x&y) + assert precedence(x & y) > precedence(x | y) + assert precedence(~y) > precedence(x & y) # ... and with other operators (cfr. other programming languages) - assert precedence(x+y) > precedence(x|y) - assert precedence(x+y) > precedence(x&y) - assert precedence(x*y) > precedence(x|y) - assert precedence(x*y) > precedence(x&y) + assert precedence(x + y) > precedence(x | y) + assert precedence(x + y) > precedence(x & y) + assert precedence(x*y) > precedence(x | y) + assert precedence(x*y) > precedence(x & y) assert precedence(~y) > precedence(x*y) - assert precedence(~y) > precedence(x-y) + assert precedence(~y) > precedence(x - y) # double checks - assert precedence(x&y) == PRECEDENCE["And"] - assert precedence(x|y) == PRECEDENCE["Or"] + assert precedence(x & y) == PRECEDENCE["And"] + assert precedence(x | y) == PRECEDENCE["Or"] assert precedence(~y) == PRECEDENCE["Not"] diff -Nru python3-sympy-0.7.2/sympy/printing/tests/test_python.py python3-sympy-0.7.3/sympy/printing/tests/test_python.py --- python3-sympy-0.7.2/sympy/printing/tests/test_python.py 2012-10-17 03:02:22.000000000 +0000 +++ python3-sympy-0.7.3/sympy/printing/tests/test_python.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,15 +1,17 @@ # -*- coding: utf-8 -*- from sympy import (Symbol, symbols, oo, limit, Rational, Integral, Derivative, - log, exp, sqrt, pi, Function, sin, Eq, Ge, Le, Gt, Lt, Ne, Abs) + log, exp, sqrt, pi, Function, sin, Eq, Ge, Le, Gt, Lt, Ne, Abs, conjugate, + I) from sympy.printing.python import python from sympy.utilities.pytest import raises, XFAIL x, y = symbols('x,y') -th = Symbol('theta') -ph = Symbol('phi') +th = Symbol('theta') +ph = Symbol('phi') + def test_python_basic(): # Simple numbers/symbols @@ -21,44 +23,61 @@ assert python((x**2)) == "x = Symbol(\'x\')\ne = x**2" assert python(1/x) == "x = Symbol('x')\ne = 1/x" assert python(y*x**-2) == "y = Symbol('y')\nx = Symbol('x')\ne = y/x**2" - assert python(x**Rational(-5, 2)) == "x = Symbol('x')\ne = x**Rational(-5, 2)" + assert python( + x**Rational(-5, 2)) == "x = Symbol('x')\ne = x**Rational(-5, 2)" # Sums of terms assert python((x**2 + x + 1)) in [ - "x = Symbol('x')\ne = 1 + x + x**2", - "x = Symbol('x')\ne = x + x**2 + 1", - "x = Symbol('x')\ne = x**2 + x + 1",] - assert python(1-x) in [ - "x = Symbol('x')\ne = 1 - x", - "x = Symbol('x')\ne = -x + 1"] - assert python(1-2*x) in [ - "x = Symbol('x')\ne = 1 - 2*x", - "x = Symbol('x')\ne = -2*x + 1"] - assert python(1-Rational(3,2)*y/x) in [ - "y = Symbol('y')\nx = Symbol('x')\ne = 1 - 3/2*y/x", - "y = Symbol('y')\nx = Symbol('x')\ne = -3/2*y/x + 1", - "y = Symbol('y')\nx = Symbol('x')\ne = 1 - 3*y/(2*x)"] + "x = Symbol('x')\ne = 1 + x + x**2", + "x = Symbol('x')\ne = x + x**2 + 1", + "x = Symbol('x')\ne = x**2 + x + 1", ] + assert python(1 - x) in [ + "x = Symbol('x')\ne = 1 - x", + "x = Symbol('x')\ne = -x + 1"] + assert python(1 - 2*x) in [ + "x = Symbol('x')\ne = 1 - 2*x", + "x = Symbol('x')\ne = -2*x + 1"] + assert python(1 - Rational(3, 2)*y/x) in [ + "y = Symbol('y')\nx = Symbol('x')\ne = 1 - 3/2*y/x", + "y = Symbol('y')\nx = Symbol('x')\ne = -3/2*y/x + 1", + "y = Symbol('y')\nx = Symbol('x')\ne = 1 - 3*y/(2*x)"] # Multiplication assert python(x/y) == "x = Symbol('x')\ny = Symbol('y')\ne = x/y" assert python(-x/y) == "x = Symbol('x')\ny = Symbol('y')\ne = -x/y" - assert python((x+2)/y) in [ - "y = Symbol('y')\nx = Symbol('x')\ne = 1/y*(2 + x)", - "y = Symbol('y')\nx = Symbol('x')\ne = 1/y*(x + 2)", - "x = Symbol('x')\ny = Symbol('y')\ne = 1/y*(2 + x)", - "x = Symbol('x')\ny = Symbol('y')\ne = (2 + x)/y", - "x = Symbol('x')\ny = Symbol('y')\ne = (x + 2)/y"] - assert python((1+x)*y) in [ - "y = Symbol('y')\nx = Symbol('x')\ne = y*(1 + x)", - "y = Symbol('y')\nx = Symbol('x')\ne = y*(x + 1)",] + assert python((x + 2)/y) in [ + "y = Symbol('y')\nx = Symbol('x')\ne = 1/y*(2 + x)", + "y = Symbol('y')\nx = Symbol('x')\ne = 1/y*(x + 2)", + "x = Symbol('x')\ny = Symbol('y')\ne = 1/y*(2 + x)", + "x = Symbol('x')\ny = Symbol('y')\ne = (2 + x)/y", + "x = Symbol('x')\ny = Symbol('y')\ne = (x + 2)/y"] + assert python((1 + x)*y) in [ + "y = Symbol('y')\nx = Symbol('x')\ne = y*(1 + x)", + "y = Symbol('y')\nx = Symbol('x')\ne = y*(x + 1)", ] # Check for proper placement of negative sign - assert python(-5*x/(x+10)) == "x = Symbol('x')\ne = -5*x/(x + 10)" - assert python(1 - Rational(3,2)*(x+1)) in [ - "x = Symbol('x')\ne = Rational(-3, 2)*x + Rational(-1, 2)", - "x = Symbol('x')\ne = -3*x/2 + Rational(-1, 2)", - "x = Symbol('x')\ne = -3*x/2 + Rational(-1, 2)" - ] + assert python(-5*x/(x + 10)) == "x = Symbol('x')\ne = -5*x/(x + 10)" + assert python(1 - Rational(3, 2)*(x + 1)) in [ + "x = Symbol('x')\ne = Rational(-3, 2)*x + Rational(-1, 2)", + "x = Symbol('x')\ne = -3*x/2 + Rational(-1, 2)", + "x = Symbol('x')\ne = -3*x/2 + Rational(-1, 2)" + ] + + +def test_python_keyword_symbol_name_escaping(): + # Check for escaping of keywords + assert python( + 5*Symbol("lambda")) == "lambda_ = Symbol('lambda')\ne = 5*lambda_" + assert (python(5*Symbol("lambda") + 7*Symbol("lambda_")) == + "lambda__ = Symbol('lambda')\nlambda_ = Symbol('lambda_')\ne = 7*lambda_ + 5*lambda__") + assert (python(5*Symbol("for") + Function("for_")(8)) == + "for__ = Symbol('for')\nfor_ = Function('for_')\ne = 5*for__ + for_(8)") + + +def test_python_keyword_function_name_escaping(): + assert python( + 5*Function("for")(8)) == "for_ = Function('for')\ne = 5*for_(8)" + def test_python_relational(): assert python(Eq(x, y)) == "x = Symbol('x')\ny = Symbol('y')\ne = x == y" @@ -66,9 +85,10 @@ assert python(Le(x, y)) == "x = Symbol('x')\ny = Symbol('y')\ne = x <= y" assert python(Gt(x, y)) == "x = Symbol('x')\ny = Symbol('y')\ne = x > y" assert python(Lt(x, y)) == "x = Symbol('x')\ny = Symbol('y')\ne = x < y" - assert python(Ne(x/(y+1), y**2)) in [ - "x = Symbol('x')\ny = Symbol('y')\ne = x/(1 + y) != y**2", - "x = Symbol('x')\ny = Symbol('y')\ne = x/(y + 1) != y**2"] + assert python(Ne(x/(y + 1), y**2)) in [ + "x = Symbol('x')\ny = Symbol('y')\ne = x/(1 + y) != y**2", + "x = Symbol('x')\ny = Symbol('y')\ne = x/(y + 1) != y**2"] + def test_python_functions(): # Simple @@ -79,35 +99,38 @@ assert python((2 + pi)**Rational(1, 3)) == 'e = (2 + pi)**Rational(1, 3)' assert python(2**Rational(1, 4)) == 'e = 2**Rational(1, 4)' assert python(Abs(x)) == "x = Symbol('x')\ne = Abs(x)" - assert python(Abs(x/(x**2+1))) in ["x = Symbol('x')\ne = Abs(x/(1 + x**2))", + assert python( + Abs(x/(x**2 + 1))) in ["x = Symbol('x')\ne = Abs(x/(1 + x**2))", "x = Symbol('x')\ne = Abs(x/(x**2 + 1))"] # Univariate/Multivariate functions f = Function('f') assert python(f(x)) == "x = Symbol('x')\nf = Function('f')\ne = f(x)" assert python(f(x, y)) == "x = Symbol('x')\ny = Symbol('y')\nf = Function('f')\ne = f(x, y)" - assert python(f(x/(y+1), y)) in [ + assert python(f(x/(y + 1), y)) in [ "x = Symbol('x')\ny = Symbol('y')\nf = Function('f')\ne = f(x/(1 + y), y)", "x = Symbol('x')\ny = Symbol('y')\nf = Function('f')\ne = f(x/(y + 1), y)"] # Nesting of square roots - assert python(sqrt((sqrt(x+1))+1)) in [ - "x = Symbol('x')\ne = sqrt(1 + sqrt(1 + x))", - "x = Symbol('x')\ne = sqrt(sqrt(x + 1) + 1)"] + assert python(sqrt((sqrt(x + 1)) + 1)) in [ + "x = Symbol('x')\ne = sqrt(1 + sqrt(1 + x))", + "x = Symbol('x')\ne = sqrt(sqrt(x + 1) + 1)"] # Nesting of powers - assert python((((x+1)**Rational(1, 3))+1)**Rational(1, 3)) in [ - "x = Symbol('x')\ne = (1 + (1 + x)**Rational(1, 3))**Rational(1, 3)", - "x = Symbol('x')\ne = ((x + 1)**Rational(1, 3) + 1)**Rational(1, 3)"] + assert python((((x + 1)**Rational(1, 3)) + 1)**Rational(1, 3)) in [ + "x = Symbol('x')\ne = (1 + (1 + x)**Rational(1, 3))**Rational(1, 3)", + "x = Symbol('x')\ne = ((x + 1)**Rational(1, 3) + 1)**Rational(1, 3)"] # Function powers assert python(sin(x)**2) == "x = Symbol('x')\ne = sin(x)**2" + @XFAIL def test_python_functions_conjugates(): a, b = list(map(Symbol, 'ab')) - assert python( conjugate(a+b*I) ) == '_ _\na - I*b' - assert python( conjugate(exp(a+b*I)) ) == ' _ _\n a - I*b\ne ' + assert python( conjugate(a + b*I) ) == '_ _\na - I*b' + assert python( conjugate(exp(a + b*I)) ) == ' _ _\n a - I*b\ne ' + def test_python_derivatives(): # Simple @@ -119,12 +142,14 @@ # Multiple symbols f_3 = Derivative(log(x) + x**2, x, y, evaluate=False) - #assert python(f_3) == + assert python(f_3) == \ + "x = Symbol('x')\ny = Symbol('y')\ne = Derivative(x**2 + log(x), x, y)" f_4 = Derivative(2*x*y, y, x, evaluate=False) + x**2 assert python(f_4) in [ - "x = Symbol('x')\ny = Symbol('y')\ne = x**2 + Derivative(2*x*y, y, x)", - "x = Symbol('x')\ny = Symbol('y')\ne = Derivative(2*x*y, y, x) + x**2"] + "x = Symbol('x')\ny = Symbol('y')\ne = x**2 + Derivative(2*x*y, y, x)", + "x = Symbol('x')\ny = Symbol('y')\ne = Derivative(2*x*y, y, x) + x**2"] + def test_python_integrals(): # Simple @@ -139,14 +164,15 @@ assert python(f_3) == "x = Symbol('x')\ne = Integral(x**(2**x), x)" # Definite integrals - f_4 = Integral(x**2, (x,1,2)) + f_4 = Integral(x**2, (x, 1, 2)) assert python(f_4) == "x = Symbol('x')\ne = Integral(x**2, (x, 1, 2))" - f_5 = Integral(x**2, (x,Rational(1,2),10)) - assert python(f_5) == "x = Symbol('x')\ne = Integral(x**2, (x, Rational(1, 2), 10))" + f_5 = Integral(x**2, (x, Rational(1, 2), 10)) + assert python( + f_5) == "x = Symbol('x')\ne = Integral(x**2, (x, Rational(1, 2), 10))" # Nested integrals - f_6 = Integral(x**2*y**2, x,y) + f_6 = Integral(x**2*y**2, x, y) assert python(f_6) == "x = Symbol('x')\ny = Symbol('y')\ne = Integral(x**2*y**2, x, y)" @@ -160,5 +186,6 @@ assert python(limit(x, x, oo)) == 'e = oo' assert python(limit(x**2, x, 0)) == 'e = 0' + def test_settings(): raises(TypeError, lambda: python(x, method="garbage")) diff -Nru python3-sympy-0.7.2/sympy/printing/tests/test_repr.py python3-sympy-0.7.3/sympy/printing/tests/test_repr.py --- python3-sympy-0.7.2/sympy/printing/tests/test_repr.py 2012-10-17 03:02:22.000000000 +0000 +++ python3-sympy-0.7.3/sympy/printing/tests/test_repr.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,8 +1,9 @@ from sympy.utilities.pytest import raises -from sympy import Symbol, symbols, Function, Integer, Matrix, nan, oo, Abs, \ - Rational, Float, S, WildFunction, ImmutableMatrix -from sympy.geometry import Point, Circle, Ellipse +from sympy import symbols, Function, Integer, Matrix, Abs, \ + Rational, Float, S, WildFunction, ImmutableMatrix, sin +from sympy.geometry import Point, Ellipse from sympy.printing import srepr +from sympy.polys import ring, field, ZZ, QQ, lex, grlex x, y = symbols('x,y') @@ -11,6 +12,7 @@ ENV = {} exec("from sympy import *", ENV) + def sT(expr, string): """ sT := sreprTest @@ -21,27 +23,35 @@ assert srepr(expr) == string assert eval(string, ENV) == expr + def test_printmethod(): class R(Abs): def _sympyrepr(self, printer): return "foo(%s)" % printer._print(self.args[0]) assert srepr(R(x)) == "foo(Symbol('x'))" + def test_Add(): - sT(x+y, "Add(Symbol('x'), Symbol('y'))") + sT(x + y, "Add(Symbol('x'), Symbol('y'))") assert srepr(x**2 + 1, order='lex') == "Add(Pow(Symbol('x'), Integer(2)), Integer(1))" assert srepr(x**2 + 1, order='old') == "Add(Integer(1), Pow(Symbol('x'), Integer(2)))" + def test_Function(): sT(Function("f")(x), "Function('f')(Symbol('x'))") # test unapplied Function sT(Function('f'), "Function('f')") + sT(sin(x), "sin(Symbol('x'))") + sT(sin, "sin") + def test_Geometry(): - sT(Point(0,0), "Point(Integer(0), Integer(0))") - sT(Ellipse(Point(0, 0), 5, 1), "Ellipse(Point(Integer(0), Integer(0)), Integer(5), Integer(1))") + sT(Point(0, 0), "Point(Integer(0), Integer(0))") + sT(Ellipse(Point(0, 0), 5, 1), + "Ellipse(Point(Integer(0), Integer(0)), Integer(5), Integer(1))") # TODO more tests + def test_Singletons(): sT(S.Catalan, 'Catalan') sT(S.ComplexInfinity, 'zoo') @@ -58,46 +68,79 @@ sT(S.Pi, 'pi') sT(S.Zero, 'Integer(0)') + def test_Integer(): sT(Integer(4), "Integer(4)") + def test_list(): sT([x, Integer(4)], "[Symbol('x'), Integer(4)]") + def test_Matrix(): - # Matrix is really MutableMatrix - for cls, name in [(Matrix, "Matrix"), (ImmutableMatrix, "ImmutableMatrix")]: - sT(cls([[x**+1, 1], [y, x+y]]), - "%s([[Symbol('x'), Integer(1)], [Symbol('y'), Add(Symbol('x'), Symbol('y'))]])"%name) + for cls, name in [(Matrix, "MutableDenseMatrix"), (ImmutableMatrix, "ImmutableMatrix")]: + sT(cls([[x**+1, 1], [y, x + y]]), + "%s([[Symbol('x'), Integer(1)], [Symbol('y'), Add(Symbol('x'), Symbol('y'))]])" % name) - sT(cls(), "%s([])"%name) + sT(cls(), "%s([])" % name) + + sT(cls([[x**+1, 1], [y, x + y]]), "%s([[Symbol('x'), Integer(1)], [Symbol('y'), Add(Symbol('x'), Symbol('y'))]])" % name) - sT(cls([[x**+1, 1], [y, x+y]]), "%s([[Symbol('x'), Integer(1)], [Symbol('y'), Add(Symbol('x'), Symbol('y'))]])"%name) def test_Rational(): - sT(Rational(1,3), "Rational(1, 3)") - sT(Rational(-1,3), "Rational(-1, 3)") + sT(Rational(1, 3), "Rational(1, 3)") + sT(Rational(-1, 3), "Rational(-1, 3)") + def test_Float(): sT(Float('1.23', prec=3), "Float('1.22998', prec=3)") sT(Float('1.23456789', prec=9), "Float('1.23456788994', prec=9)") - sT(Float('1.234567890123456789', prec=19), "Float('1.234567890123456789013', prec=19)") - sT(Float('0.60038617995049726', 15), "Float('0.60038617995049726', prec=15)") + sT(Float('1.234567890123456789', prec=19), + "Float('1.234567890123456789013', prec=19)") + sT(Float( + '0.60038617995049726', 15), "Float('0.60038617995049726', prec=15)") + def test_Symbol(): sT(x, "Symbol('x')") sT(y, "Symbol('y')") + def test_tuple(): sT((x,), "(Symbol('x'),)") - sT((x,y), "(Symbol('x'), Symbol('y'))") + sT((x, y), "(Symbol('x'), Symbol('y'))") + def test_WildFunction(): sT(WildFunction('w'), "WildFunction('w')") + def test_settins(): raises(TypeError, lambda: srepr(x, method="garbage")) + def test_Mul(): sT(3*x**3*y, "Mul(Integer(3), Pow(Symbol('x'), Integer(3)), Symbol('y'))") assert srepr(3*x**3*y, order='old') == "Mul(Integer(3), Symbol('y'), Pow(Symbol('x'), Integer(3)))" + + +def test_PolyRing(): + assert srepr(ring("x", ZZ, lex)[0]) == "PolyRing((Symbol('x'),), ZZ, lex)" + assert srepr(ring("x,y", QQ, grlex)[0]) == "PolyRing((Symbol('x'), Symbol('y')), QQ, grlex)" + assert srepr(ring("x,y,z", ZZ["t"], lex)[0]) == "PolyRing((Symbol('x'), Symbol('y'), Symbol('z')), ZZ[t], lex)" + + +def test_FracField(): + assert srepr(field("x", ZZ, lex)[0]) == "FracField((Symbol('x'),), ZZ, lex)" + assert srepr(field("x,y", QQ, grlex)[0]) == "FracField((Symbol('x'), Symbol('y')), QQ, grlex)" + assert srepr(field("x,y,z", ZZ["t"], lex)[0]) == "FracField((Symbol('x'), Symbol('y'), Symbol('z')), ZZ[t], lex)" + + +def test_PolyElement(): + R, x, y = ring("x,y", ZZ) + assert srepr(3*x**2*y + 1) == "PolyElement(PolyRing((Symbol('x'), Symbol('y')), ZZ, lex), [((2, 1), 3), ((0, 0), 1)])" + + +def test_FracElement(): + F, x, y = field("x,y", ZZ) + assert srepr((3*x**2*y + 1)/(x - y**2)) == "FracElement(FracField((Symbol('x'), Symbol('y')), ZZ, lex), [((2, 1), 3), ((0, 0), 1)], [((1, 0), 1), ((0, 2), -1)])" diff -Nru python3-sympy-0.7.2/sympy/printing/tests/test_str.py python3-sympy-0.7.3/sympy/printing/tests/test_str.py --- python3-sympy-0.7.2/sympy/printing/tests/test_str.py 2012-10-17 03:02:22.000000000 +0000 +++ python3-sympy-0.7.3/sympy/printing/tests/test_str.py 2013-07-13 17:53:32.000000000 +0000 @@ -2,13 +2,13 @@ from sympy import (Abs, Catalan, cos, Derivative, E, EulerGamma, exp, factorial, factorial2, Function, GoldenRatio, I, Integer, Integral, - Interval, Lambda, Limit, log, Matrix, nan, O, oo, pi, Rational, Float, Rel, + Interval, Lambda, Limit, Matrix, nan, O, oo, pi, Rational, Float, Rel, S, sin, SparseMatrix, sqrt, summation, Sum, Symbol, symbols, Wild, - WildFunction, zeta, zoo, Dummy, Dict, Tuple, FiniteSet) + WildFunction, zeta, zoo, Dummy, Dict, Tuple, FiniteSet, factor, + MatrixSymbol, subfactorial) from sympy.core import Expr from sympy.physics.units import second, joule -from sympy.polys import Poly, RootOf, RootSum, groebner -from sympy.statistics.distributions import Normal, Sample, Uniform +from sympy.polys import Poly, RootOf, RootSum, groebner, ring, field, ZZ, QQ, lex, grlex from sympy.geometry import Point, Circle from sympy.utilities.pytest import raises @@ -19,79 +19,97 @@ x, y, z, w = symbols('x,y,z,w') d = Dummy('d') + def test_printmethod(): class R(Abs): def _sympystr(self, printer): return "foo(%s)" % printer._print(self.args[0]) assert sstr(R(x)) == "foo(x)" + class R(Abs): def _sympystr(self, printer): return "foo" assert sstr(R(x)) == "foo" + def test_Abs(): assert str(Abs(x)) == "Abs(x)" - assert str(Abs(Rational(1,6))) == "1/6" - assert str(Abs(Rational(-1,6))) == "1/6" + assert str(Abs(Rational(1, 6))) == "1/6" + assert str(Abs(Rational(-1, 6))) == "1/6" + def test_Add(): - assert str(x+y) == "x + y" - assert str(x+1) == "x + 1" - assert str(x+x**2) == "x**2 + x" - assert str(5+x+y+x*y+x**2+y**2) == "x**2 + x*y + x + y**2 + y + 5" - assert str(1+x+x**2/2+x**3/3) == "x**3/3 + x**2/2 + x + 1" - assert str(2*x-7*x**2 + 2 + 3*y) == "-7*x**2 + 2*x + 3*y + 2" - assert str(x-y) == "x - y" - assert str(2-x) == "-x + 2" - assert str(x-2) == "x - 2" - assert str(x-y-z-w) == "-w + x - y - z" - assert str(x-z*y**2*z*w) == "-w*y**2*z**2 + x" - assert str(x-1*y*x*y) == "-x*y**2 + x" + assert str(x + y) == "x + y" + assert str(x + 1) == "x + 1" + assert str(x + x**2) == "x**2 + x" + assert str(5 + x + y + x*y + x**2 + y**2) == "x**2 + x*y + x + y**2 + y + 5" + assert str(1 + x + x**2/2 + x**3/3) == "x**3/3 + x**2/2 + x + 1" + assert str(2*x - 7*x**2 + 2 + 3*y) == "-7*x**2 + 2*x + 3*y + 2" + assert str(x - y) == "x - y" + assert str(2 - x) == "-x + 2" + assert str(x - 2) == "x - 2" + assert str(x - y - z - w) == "-w + x - y - z" + assert str(x - z*y**2*z*w) == "-w*y**2*z**2 + x" + assert str(x - 1*y*x*y) == "-x*y**2 + x" assert str(sin(x).series(x, 0, 15)) == "x - x**3/6 + x**5/120 - x**7/5040 + x**9/362880 - x**11/39916800 + x**13/6227020800 + O(x**15)" + def test_Catalan(): assert str(Catalan) == "Catalan" + def test_ComplexInfinity(): assert str(zoo) == "zoo" + def test_Derivative(): assert str(Derivative(x, y)) == "Derivative(x, y)" assert str(Derivative(x**2, x, evaluate=False)) == "Derivative(x**2, x)" - assert str(Derivative(x**2/y, x, y, evaluate=False)) == "Derivative(x**2/y, x, y)" + assert str(Derivative( + x**2/y, x, y, evaluate=False)) == "Derivative(x**2/y, x, y)" + def test_dict(): - assert str({1: 1+x}) == sstr({1: 1+x}) == "{1: x + 1}" + assert str({1: 1 + x}) == sstr({1: 1 + x}) == "{1: x + 1}" assert str({1: x**2, 2: y*x}) in ("{1: x**2, 2: x*y}", "{2: x*y, 1: x**2}") assert sstr({1: x**2, 2: y*x}) == "{1: x**2, 2: x*y}" + def test_Dict(): - assert str(Dict({1: 1+x})) == sstr({1: 1+x}) == "{1: x + 1}" + assert str(Dict({1: 1 + x})) == sstr({1: 1 + x}) == "{1: x + 1}" assert str(Dict({1: x**2, 2: y*x})) in ( - "{1: x**2, 2: x*y}", "{2: x*y, 1: x**2}") + "{1: x**2, 2: x*y}", "{2: x*y, 1: x**2}") assert sstr(Dict({1: x**2, 2: y*x})) == "{1: x**2, 2: x*y}" + def test_Dummy(): assert str(d) == "_d" - assert str(d+x) == "_d + x" + assert str(d + x) == "_d + x" + def test_EulerGamma(): assert str(EulerGamma) == "EulerGamma" + def test_Exp(): assert str(E) == "E" + def test_factorial(): n = Symbol('n', integer=True) assert str(factorial(-2)) == "0" assert str(factorial(0)) == "1" assert str(factorial(7)) == "5040" - assert str(factorial(n)) == "n!" - assert str(factorial(2*n)) == "(2*n)!" - assert str(factorial(factorial(n))) == '(n!)!' - assert str(factorial(factorial2(n))) == '(n!!)!' - assert str(factorial2(factorial(n))) == '(n!)!!' - assert str(factorial2(factorial2(n))) == '(n!!)!!' + assert str(factorial(n)) == "factorial(n)" + assert str(factorial(2*n)) == "factorial(2*n)" + assert str(factorial(factorial(n))) == 'factorial(factorial(n))' + assert str(factorial(factorial2(n))) == 'factorial(factorial2(n))' + assert str(factorial2(factorial(n))) == 'factorial2(factorial(n))' + assert str(factorial2(factorial2(n))) == 'factorial2(factorial2(n))' + assert str(subfactorial(3)) == "2" + assert str(subfactorial(n)) == "subfactorial(n)" + assert str(subfactorial(2*n)) == "subfactorial(2*n)" + def test_Function(): f = Function('f') @@ -101,21 +119,26 @@ assert str(fx) == "f(x)" assert str(w) == "w_" + def test_Geometry(): - assert sstr(Point(0,0)) == 'Point(0, 0)' - assert sstr(Circle(Point(0,0), 3)) == 'Circle(Point(0, 0), 3)' + assert sstr(Point(0, 0)) == 'Point(0, 0)' + assert sstr(Circle(Point(0, 0), 3)) == 'Circle(Point(0, 0), 3)' # TODO test other Geometry entities + def test_GoldenRatio(): assert str(GoldenRatio) == "GoldenRatio" + def test_ImaginaryUnit(): assert str(I) == "I" + def test_Infinity(): assert str(oo) == "oo" assert str(oo*I) == "oo*I" + def test_Integer(): assert str(Integer(-1)) == "-1" assert str(Integer(1)) == "1" @@ -123,10 +146,12 @@ assert str(Integer(0)) == "0" assert str(Integer(25)) == "25" + def test_Integral(): assert str(Integral(sin(x), y)) == "Integral(sin(x), y)" assert str(Integral(sin(x), (y, 0, 1))) == "Integral(sin(x), (y, 0, 1))" + def test_Interval(): a = Symbol('a', real=True) assert str(Interval(0, a)) == "[0, a]" @@ -135,37 +160,49 @@ assert str(Interval(0, a, False, True)) == "[0, a)" assert str(Interval(0, a, True, True)) == "(0, a)" + def test_Lambda(): assert str(Lambda(d, d**2)) == "Lambda(_d, _d**2)" + def test_Limit(): assert str(Limit(sin(x)/x, x, y)) == "Limit(sin(x)/x, x, y)" assert str(Limit(1/x, x, 0)) == "Limit(1/x, x, 0)" - assert str(Limit(sin(x)/x, x, y, dir="-")) == "Limit(sin(x)/x, x, y, dir='-')" + assert str( + Limit(sin(x)/x, x, y, dir="-")) == "Limit(sin(x)/x, x, y, dir='-')" + def test_list(): assert str([x]) == sstr([x]) == "[x]" - assert str([x**2, x*y+1]) == sstr([x**2, x*y+1]) == "[x**2, x*y + 1]" - assert str([x**2, [y+x]]) == sstr([x**2, [y+x]]) == "[x**2, [x + y]]" + assert str([x**2, x*y + 1]) == sstr([x**2, x*y + 1]) == "[x**2, x*y + 1]" + assert str([x**2, [y + x]]) == sstr([x**2, [y + x]]) == "[x**2, [x + y]]" + -def test_Matrix(): - M = Matrix([[x**+1, 1], [y, x+y]]) - assert str(M) == sstr(M) == "[x, 1]\n[y, x + y]" +def test_Matrix_str(): + M = Matrix([[x**+1, 1], [y, x + y]]) + assert str(M) == "Matrix([[x, 1], [y, x + y]])" + assert sstr(M) == "Matrix([\n[x, 1],\n[y, x + y]])" + M = Matrix([[1]]) + assert str(M) == sstr(M) == "Matrix([[1]])" + M = Matrix([[1, 2]]) + assert str(M) == sstr(M) == "Matrix([[1, 2]])" M = Matrix() - assert str(M) == sstr(M) == "[]" + assert str(M) == sstr(M) == "Matrix(0, 0, [])" M = Matrix(0, 1, lambda i, j: 0) - assert str(M) == sstr(M) == "[]" + assert str(M) == sstr(M) == "Matrix(0, 1, [])" + def test_Mul(): assert str(x/y) == "x/y" assert str(y/x) == "y/x" assert str(x/y/z) == "x/(y*z)" - assert str((x+1)/(y+2)) == "(x + 1)/(y + 2)" - assert str(2*x/3) == '2*x/3' - assert str(-2*x/3) == '-2*x/3' + assert str((x + 1)/(y + 2)) == "(x + 1)/(y + 2)" + assert str(2*x/3) == '2*x/3' + assert str(-2*x/3) == '-2*x/3' class CustomClass1(Expr): is_commutative = True + class CustomClass2(Expr): is_commutative = True cc1 = CustomClass1() @@ -177,20 +214,20 @@ assert str(cc2*Rational(2)*cc1) == '2*CustomClass1()*CustomClass2()' assert str(cc1*Rational(2)*cc2) == '2*CustomClass1()*CustomClass2()' + def test_NaN(): assert str(nan) == "nan" + def test_NegativeInfinity(): assert str(-oo) == "-oo" -def test_Normal(): - assert str(Normal(x+y, z)) == "Normal(x + y, z)" - def test_Order(): assert str(O(x)) == "O(x)" assert str(O(x**2)) == "O(x**2)" assert str(O(x*y)) == "O(x*y, x, y)" + def test_Permutation_Cycle(): from sympy.combinatorics import Permutation, Cycle @@ -198,62 +235,64 @@ # and the size of the permutation. for p, s in [ - (Cycle(), + (Cycle(), 'Cycle()'), - (Cycle(2), + (Cycle(2), 'Cycle(2)'), - (Cycle(2, 1), + (Cycle(2, 1), 'Cycle(1, 2)'), - (Cycle(1, 2)(5)(6, 7)(10), + (Cycle(1, 2)(5)(6, 7)(10), 'Cycle(1, 2)(6, 7)(10)'), - (Cycle(3, 4)(1, 2)(3, 4), + (Cycle(3, 4)(1, 2)(3, 4), 'Cycle(1, 2)(4)'), ]: assert str(p) == s Permutation.print_cyclic = False for p, s in [ - (Permutation([]), + (Permutation([]), 'Permutation([])'), - (Permutation([], size=1), + (Permutation([], size=1), 'Permutation([0])'), - (Permutation([], size=2), + (Permutation([], size=2), 'Permutation([0, 1])'), - (Permutation([], size=10), + (Permutation([], size=10), 'Permutation([], size=10)'), - (Permutation([1, 0, 2]), + (Permutation([1, 0, 2]), 'Permutation([1, 0, 2])'), - (Permutation([1, 0, 2, 3, 4, 5]), + (Permutation([1, 0, 2, 3, 4, 5]), 'Permutation([1, 0], size=6)'), - (Permutation([1, 0, 2, 3, 4, 5], size=10), + (Permutation([1, 0, 2, 3, 4, 5], size=10), 'Permutation([1, 0], size=10)'), ]: assert str(p) == s Permutation.print_cyclic = True for p, s in [ - (Permutation([]), + (Permutation([]), 'Permutation()'), - (Permutation([], size=1), + (Permutation([], size=1), 'Permutation(0)'), - (Permutation([], size=2), + (Permutation([], size=2), 'Permutation(1)'), - (Permutation([], size=10), + (Permutation([], size=10), 'Permutation(9)'), - (Permutation([1, 0, 2]), + (Permutation([1, 0, 2]), 'Permutation(2)(0, 1)'), - (Permutation([1, 0, 2, 3, 4, 5]), + (Permutation([1, 0, 2, 3, 4, 5]), 'Permutation(5)(0, 1)'), - (Permutation([1, 0, 2, 3, 4, 5], size=10), + (Permutation([1, 0, 2, 3, 4, 5], size=10), 'Permutation(9)(0, 1)'), - (Permutation([0, 1, 3, 2, 4, 5], size=10), + (Permutation([0, 1, 3, 2, 4, 5], size=10), 'Permutation(9)(2, 3)'), ]: assert str(p) == s + def test_Pi(): assert str(pi) == "pi" + def test_Poly(): assert str(Poly(0, x)) == "Poly(0, x, domain='ZZ')" assert str(Poly(1, x)) == "Poly(1, x, domain='ZZ')" @@ -270,32 +309,87 @@ assert str(Poly(x - 1, x)) == "Poly(x - 1, x, domain='ZZ')" - assert str(Poly(x**2 + 1 + y, x)) == "Poly(x**2 + y + 1, x, domain='ZZ[y]')" - assert str(Poly(x**2 - 1 + y, x)) == "Poly(x**2 + y - 1, x, domain='ZZ[y]')" + assert str( + Poly(x**2 + 1 + y, x)) == "Poly(x**2 + y + 1, x, domain='ZZ[y]')" + assert str( + Poly(x**2 - 1 + y, x)) == "Poly(x**2 + y - 1, x, domain='ZZ[y]')" assert str(Poly(x**2 + I*x, x)) == "Poly(x**2 + I*x, x, domain='EX')" assert str(Poly(x**2 - I*x, x)) == "Poly(x**2 - I*x, x, domain='EX')" - assert str(Poly(-x*y*z + x*y - 1, x, y, z)) == "Poly(-x*y*z + x*y - 1, x, y, z, domain='ZZ')" + assert str(Poly(-x*y*z + x*y - 1, x, y, z) + ) == "Poly(-x*y*z + x*y - 1, x, y, z, domain='ZZ')" assert str(Poly(-w*x**21*y**7*z + (1 + w)*z**3 - 2*x*z + 1, x, y, z)) == \ "Poly(-w*x**21*y**7*z - 2*x*z + (w + 1)*z**3 + 1, x, y, z, domain='ZZ[w]')" assert str(Poly(x**2 + 1, x, modulus=2)) == "Poly(x**2 + 1, x, modulus=2)" assert str(Poly(2*x**2 + 3*x + 4, x, modulus=17)) == "Poly(2*x**2 + 3*x + 4, x, modulus=17)" + +def test_PolyRing(): + assert str(ring("x", ZZ, lex)[0]) == "Polynomial ring in x over ZZ with lex order" + assert str(ring("x,y", QQ, grlex)[0]) == "Polynomial ring in x, y over QQ with grlex order" + assert str(ring("x,y,z", ZZ["t"], lex)[0]) == "Polynomial ring in x, y, z over ZZ[t] with lex order" + + +def test_FracField(): + assert str(field("x", ZZ, lex)[0]) == "Rational function field in x over ZZ with lex order" + assert str(field("x,y", QQ, grlex)[0]) == "Rational function field in x, y over QQ with grlex order" + assert str(field("x,y,z", ZZ["t"], lex)[0]) == "Rational function field in x, y, z over ZZ[t] with lex order" + + +def test_PolyElement(): + Ruv, u,v = ring("u,v", ZZ); + Rxyz, x,y,z = ring("x,y,z", Ruv.to_domain()) + + assert str(x - x) == "0" + assert str(x - 1) == "x - 1" + assert str(x + 1) == "x + 1" + + assert str((u**2 + 3*u*v + 1)*x**2*y + u + 1) == "(u**2 + 3*u*v + 1)*x**2*y + u + 1" + assert str((u**2 + 3*u*v + 1)*x**2*y + (u + 1)*x) == "(u**2 + 3*u*v + 1)*x**2*y + (u + 1)*x" + assert str((u**2 + 3*u*v + 1)*x**2*y + (u + 1)*x + 1) == "(u**2 + 3*u*v + 1)*x**2*y + (u + 1)*x + 1" + assert str((-u**2 + 3*u*v - 1)*x**2*y - (u + 1)*x - 1) == "-(u**2 - 3*u*v + 1)*x**2*y - (u + 1)*x - 1" + + +def test_FracElement(): + Fuv, u,v = field("u,v", ZZ); + Fxyzt, x,y,z,t = field("x,y,z,t", Fuv.to_domain()) + + assert str(x - x) == "0" + assert str(x - 1) == "x - 1" + assert str(x + 1) == "x + 1" + + assert str(x/z) == "x/z" + assert str(x*y/z) == "x*y/z" + assert str(x/(z*t)) == "x/(z*t)" + assert str(x*y/(z*t)) == "x*y/(z*t)" + + assert str((x - 1)/y) == "(x - 1)/y" + assert str((x + 1)/y) == "(x + 1)/y" + assert str((-x - 1)/y) == "(-x - 1)/y" + assert str((x + 1)/(y*z)) == "(x + 1)/(y*z)" + assert str(-y/(x + 1)) == "-y/(x + 1)" + assert str(y*z/(x + 1)) == "y*z/(x + 1)" + + assert str(((u + 1)*x*y + 1)/((v - 1)*z - 1)) == "((u + 1)*x*y + 1)/((v - 1)*z - 1)" + assert str(((u + 1)*x*y + 1)/((v - 1)*z - t*u*v - 1)) == "((u + 1)*x*y + 1)/((v - 1)*z - u*v*t - 1)" + + def test_Pow(): assert str(x**-1) == "1/x" assert str(x**-2) == "x**(-2)" assert str(x**2) == "x**2" - assert str((x+y)**-1) == "1/(x + y)" - assert str((x+y)**-2) == "(x + y)**(-2)" - assert str((x+y)**2) == "(x + y)**2" - assert str((x+y)**(1+x)) == "(x + y)**(x + 1)" + assert str((x + y)**-1) == "1/(x + y)" + assert str((x + y)**-2) == "(x + y)**(-2)" + assert str((x + y)**2) == "(x + y)**2" + assert str((x + y)**(1 + x)) == "(x + y)**(x + 1)" assert str(x**Rational(1, 3)) == "x**(1/3)" assert str(1/x**Rational(1, 3)) == "x**(-1/3)" assert str(sqrt(sqrt(x))) == "x**(1/4)" assert str(x**-1.0) == '1/x' + def test_sqrt(): assert str(sqrt(x)) == "sqrt(x)" assert str(sqrt(x**2)) == "sqrt(x**2)" @@ -305,27 +399,27 @@ assert str(x**(1/2)) == "x**0.5" assert str(1/x**(1/2)) == "x**(-0.5)" + def test_Rational(): - n1 = Rational(1,4) - n2 = Rational(1,3) - n3 = Rational(2,4) - n4 = Rational(2,-4) + n1 = Rational(1, 4) + n2 = Rational(1, 3) + n3 = Rational(2, 4) + n4 = Rational(2, -4) n5 = Rational(0) - n6 = Rational(1) n7 = Rational(3) n8 = Rational(-3) assert str(n1*n2) == "1/12" assert str(n1*n2) == "1/12" assert str(n3) == "1/2" assert str(n1*n3) == "1/8" - assert str(n1+n3) == "3/4" - assert str(n1+n2) == "7/12" - assert str(n1+n4) == "-1/4" + assert str(n1 + n3) == "3/4" + assert str(n1 + n2) == "7/12" + assert str(n1 + n4) == "-1/4" assert str(n4*n4) == "1/4" - assert str(n4+n2) == "-1/6" - assert str(n4+n5) == "-1/2" + assert str(n4 + n2) == "-1/6" + assert str(n4 + n5) == "-1/2" assert str(n4*n5) == "0" - assert str(n3+n4) == "0" + assert str(n3 + n4) == "0" assert str(n1**n7) == "1/64" assert str(n2**n7) == "1/27" assert str(n2**n8) == "27" @@ -341,46 +435,56 @@ assert str(S("0.[9]", rational=1)) == "1" assert str(S("-0.[9]", rational=1)) == "-1" - assert str(sqrt(Rational(1,4))) == "1/2" - assert str(sqrt(Rational(1,36))) == "1/6" + assert str(sqrt(Rational(1, 4))) == "1/2" + assert str(sqrt(Rational(1, 36))) == "1/6" - assert str((123**25) ** Rational(1,25)) == "123" - assert str((123**25+1)**Rational(1,25)) != "123" - assert str((123**25-1)**Rational(1,25)) != "123" - assert str((123**25-1)**Rational(1,25)) != "122" + assert str((123**25) ** Rational(1, 25)) == "123" + assert str((123**25 + 1)**Rational(1, 25)) != "123" + assert str((123**25 - 1)**Rational(1, 25)) != "123" + assert str((123**25 - 1)**Rational(1, 25)) != "122" - assert str(sqrt(Rational(81,36))**3) == "27/8" - assert str(1/sqrt(Rational(81,36))**3) == "8/27" + assert str(sqrt(Rational(81, 36))**3) == "27/8" + assert str(1/sqrt(Rational(81, 36))**3) == "8/27" assert str(sqrt(-4)) == str(2*I) - assert str(2**Rational(1,10**10)) == "2**(1/10000000000)" + assert str(2**Rational(1, 10**10)) == "2**(1/10000000000)" + def test_Float(): # NOTE prec is the whole number of decimal digits - assert str(Float('1.23', prec=1+2)) == '1.23' - assert str(Float('1.23456789', prec=1+8)) == '1.23456789' - assert str(Float('1.234567890123456789', prec=1+18)) == '1.234567890123456789' - assert str(pi.evalf(1+2)) == '3.14' - assert str(pi.evalf(1+14)) == '3.14159265358979' - assert str(pi.evalf(1+64)) == '3.1415926535897932384626433832795028841971693993751058209749445923' + assert str(Float('1.23', prec=1 + 2)) == '1.23' + assert str(Float('1.23456789', prec=1 + 8)) == '1.23456789' + assert str( + Float('1.234567890123456789', prec=1 + 18)) == '1.234567890123456789' + assert str(pi.evalf(1 + 2)) == '3.14' + assert str(pi.evalf(1 + 14)) == '3.14159265358979' + assert str(pi.evalf(1 + 64)) == ('3.141592653589793238462643383279' + '5028841971693993751058209749445923') assert str(pi.round(-1)) == '0.' assert str((pi**400 - (pi**400).round(1)).n(2)) == '-0.e+88' + def test_Relational(): assert str(Rel(x, y, "<")) == "x < y" - assert str(Rel(x+y, y, "==")) == "x + y == y" + assert str(Rel(x + y, y, "==")) == "x + y == y" + def test_RootOf(): assert str(RootOf(x**5 + 2*x - 1, 0)) == "RootOf(x**5 + 2*x - 1, 0)" + def test_RootSum(): f = x**5 + 2*x - 1 - assert str(RootSum(f, Lambda(z, z), auto=False)) == "RootSum(x**5 + 2*x - 1)" - assert str(RootSum(f, Lambda(z, z**2), auto=False)) == "RootSum(x**5 + 2*x - 1, Lambda(_z, _z**2))" + assert str( + RootSum(f, Lambda(z, z), auto=False)) == "RootSum(x**5 + 2*x - 1)" + assert str(RootSum(f, Lambda( + z, z**2), auto=False)) == "RootSum(x**5 + 2*x - 1, Lambda(z, z**2))" + def test_GroebnerBasis(): - assert str(groebner([], x, y)) == "GroebnerBasis([], x, y, domain='ZZ', order='lex')" + assert str(groebner( + [], x, y)) == "GroebnerBasis([], x, y, domain='ZZ', order='lex')" F = [x**2 - 3*y - x + 1, y**2 - 2*x + y - 1] @@ -389,108 +493,109 @@ assert str(groebner(F, order='lex')) == \ "GroebnerBasis([2*x - y**2 - y + 1, y**4 + 2*y**3 - 3*y**2 - 16*y + 7], x, y, domain='ZZ', order='lex')" -def test_Sample(): - assert str(Sample([x, y, 1])) in [ - "Sample([x, y, 1])", - "Sample([y, 1, x])", - "Sample([1, x, y])", - "Sample([y, x, 1])", - "Sample([x, 1, y])", - "Sample([1, y, x])", - ] - def test_set(): - assert sstr(set()) == 'set()' + assert sstr(set()) == 'set()' assert sstr(frozenset()) == 'frozenset()' - assert sstr(set([1,2,3]))== 'set([1, 2, 3])' - assert sstr(set([1,x,x**2,x**3,x**4])) == 'set([1, x, x**2, x**3, x**4])' + assert sstr(set([1, 2, 3])) == 'set([1, 2, 3])' + assert sstr( + set([1, x, x**2, x**3, x**4])) == 'set([1, x, x**2, x**3, x**4])' + def test_SparseMatrix(): - M = SparseMatrix([[x**+1, 1], [y, x+y]]) - assert str(M) == sstr(M) == "[x, 1]\n[y, x + y]" + M = SparseMatrix([[x**+1, 1], [y, x + y]]) + assert str(M) == "Matrix([[x, 1], [y, x + y]])" + assert sstr(M) == "Matrix([\n[x, 1],\n[y, x + y]])" + def test_Sum(): assert str(summation(cos(3*z), (z, x, y))) == "Sum(cos(3*z), (z, x, y))" assert str(Sum(x*y**2, (x, -2, 2), (y, -5, 5))) == \ "Sum(x*y**2, (x, -2, 2), (y, -5, 5))" + def test_Symbol(): assert str(y) == "y" assert str(x) == "x" e = x assert str(e) == "x" + def test_tuple(): assert str((x,)) == sstr((x,)) == "(x,)" - assert str((x+y, 1+x)) == sstr((x+y, 1+x)) == "(x + y, x + 1)" - assert str((x+y, (1+x, x**2))) == sstr((x+y, (1+x, x**2))) == "(x + y, (x + 1, x**2))" - -def test_Uniform(): - assert str(Uniform(x, y)) == "Uniform(x, y)" - assert str(Uniform(x+y, y)) == "Uniform(x + y, y)" + assert str((x + y, 1 + x)) == sstr((x + y, 1 + x)) == "(x + y, x + 1)" + assert str((x + y, ( + 1 + x, x**2))) == sstr((x + y, (1 + x, x**2))) == "(x + y, (x + 1, x**2))" def test_Unit(): assert str(second) == "s" - assert str(joule) == "kg*m**2/s**2" # issue 2461 + assert str(joule) == "kg*m**2/s**2" # issue 2461 + def test_wild_str(): # Check expressions containing Wild not causing infinite recursion w = Wild('x') - assert str(w + 1) == 'x_ + 1' - assert str(exp(2**w) + 5) == 'exp(2**x_) + 5' - assert str(3*w + 1) == '3*x_ + 1' - assert str(1/w + 1) == '1 + 1/x_' - assert str(w**2 + 1) == 'x_**2 + 1' - assert str(1/(1-w)) == '1/(-x_ + 1)' + assert str(w + 1) == 'x_ + 1' + assert str(exp(2**w) + 5) == 'exp(2**x_) + 5' + assert str(3*w + 1) == '3*x_ + 1' + assert str(1/w + 1) == '1 + 1/x_' + assert str(w**2 + 1) == 'x_**2 + 1' + assert str(1/(1 - w)) == '1/(-x_ + 1)' + def test_zeta(): assert str(zeta(3)) == "zeta(3)" + def test_bug2(): - e = x-y + e = x - y a = str(e) b = str(e) assert a == b def test_bug4(): - e = -2*sqrt(x)-y/sqrt(x)/2 + e = -2*sqrt(x) - y/sqrt(x)/2 assert str(e) not in ["(-2)*x**1/2(-1/2)*x**(-1/2)*y", - "-2*x**1/2(-1/2)*x**(-1/2)*y","-2*x**1/2-1/2*x**-1/2*w"] + "-2*x**1/2(-1/2)*x**(-1/2)*y", "-2*x**1/2-1/2*x**-1/2*w"] assert str(e) == "-2*sqrt(x) - y/(2*sqrt(x))" + def test_issue922(): - e = Integral(x,x) + 1 - assert str(e) == 'Integral(x, x) + 1' + e = Integral(x, x) + 1 + assert str(e) == 'Integral(x, x) + 1' + def test_sstrrepr(): - assert sstr('abc') == 'abc' - assert sstrrepr('abc') == "'abc'" + assert sstr('abc') == 'abc' + assert sstrrepr('abc') == "'abc'" e = ['a', 'b', 'c', x] - assert sstr(e) == "[a, b, c, x]" - assert sstrrepr(e) == "['a', 'b', 'c', x]" + assert sstr(e) == "[a, b, c, x]" + assert sstrrepr(e) == "['a', 'b', 'c', x]" + def test_infinity(): assert sstr(oo*I) == "oo*I" + def test_full_prec(): assert sstr(S("0.3"), full_prec=True) == "0.300000000000000" assert sstr(S("0.3"), full_prec="auto") == "0.300000000000000" assert sstr(S("0.3"), full_prec=False) == "0.3" assert sstr(S("0.3")*x, full_prec=True) in [ - "0.300000000000000*x", - "x*0.300000000000000" - ] + "0.300000000000000*x", + "x*0.300000000000000" + ] assert sstr(S("0.3")*x, full_prec="auto") in [ - "0.3*x", - "x*0.3" - ] + "0.3*x", + "x*0.3" + ] assert sstr(S("0.3")*x, full_prec=False) in [ - "0.3*x", - "x*0.3" - ] + "0.3*x", + "x*0.3" + ] + def test_noncommutative(): A, B, C = symbols('A,B,C', commutative=False) @@ -501,31 +606,36 @@ assert sstr(sqrt(A)) == "sqrt(A)" assert sstr(1/sqrt(A)) == "A**(-1/2)" + def test_empty_printer(): str_printer = StrPrinter() assert str_printer.emptyPrinter("foo") == "foo" assert str_printer.emptyPrinter(x*y) == "x*y" assert str_printer.emptyPrinter(32) == "32" + def test_settings(): raises(TypeError, lambda: sstr(S(4), method="garbage")) + def test_RandomDomain(): from sympy.stats import Normal, Die, Exponential, pspace, where X = Normal('x1', 0, 1) - assert str(where(X>0)) == "Domain: 0 < x1" + assert str(where(X > 0)) == "Domain: x1 > 0" D = Die('d1', 6) - assert str(where(D>4)) == "Domain: Or(d1 == 5, d1 == 6)" + assert str(where(D > 4)) == "Domain: Or(d1 == 5, d1 == 6)" A = Exponential('a', 1) B = Exponential('b', 1) - assert str(pspace(Tuple(A,B)).domain) =="Domain: And(0 <= a, 0 <= b)" + assert str(pspace(Tuple(A, B)).domain) == "Domain: And(a >= 0, b >= 0)" + def test_FiniteSet(): assert str(FiniteSet(list(range(1, 51)))) == '{1, 2, 3, ..., 48, 49, 50}' assert str(FiniteSet(list(range(1, 6)))) == '{1, 2, 3, 4, 5}' + def test_PrettyPoly(): from sympy.polys.domains import QQ F = QQ.frac_field(x, y) @@ -533,9 +643,10 @@ assert sstr(F.convert(x/(x + y))) == sstr(x/(x + y)) assert sstr(R.convert(x + y)) == sstr(x + y) + def test_categories(): - from sympy.categories import (Object, Morphism, NamedMorphism, - IdentityMorphism, Category) + from sympy.categories import (Object, NamedMorphism, + IdentityMorphism, Category) A = Object("A") B = Object("B") @@ -551,7 +662,23 @@ assert str(K) == 'Category("K")' + def test_Tr(): A, B = symbols('A B', commutative=False) t = Tr(A*B) assert str(t) == 'Tr(A*B)' + + +def test_issue3288(): + assert str(factor(-3.0*z + 3)) == '-3.0*(1.0*z - 1.0)' + + +def test_MatMul_MatAdd(): + from sympy import MatrixSymbol + assert str(2*(MatrixSymbol("X", 2, 2) + MatrixSymbol("Y", 2, 2))) == \ + "2*(X + Y)" + +def test_MatrixSlice(): + from sympy.matrices.expressions import MatrixSymbol + assert str(MatrixSymbol('X', 10, 10)[:5, 1:9:2]) == 'X[:5, 1:9:2]' + assert str(MatrixSymbol('X', 10, 10)[5, :5:2]) == 'X[5, :5:2]' diff -Nru python3-sympy-0.7.2/sympy/printing/tests/test_tableform.py python3-sympy-0.7.3/sympy/printing/tests/test_tableform.py --- python3-sympy-0.7.2/sympy/printing/tests/test_tableform.py 2012-10-17 03:02:22.000000000 +0000 +++ python3-sympy-0.7.3/sympy/printing/tests/test_tableform.py 2013-07-13 17:53:32.000000000 +0000 @@ -8,6 +8,7 @@ from textwrap import dedent + def test_TableForm(): s = str(TableForm([["a", "b"], ["c", "d"], ["e", 0]], headings="automatic")) @@ -17,7 +18,7 @@ '1 | a b\n' '2 | c d\n' '3 | e ' - ) + ) s = str(TableForm([["a", "b"], ["c", "d"], ["e", 0]], headings="automatic", wipe_zeros=False)) assert s == dedent('''\ @@ -32,7 +33,7 @@ '1 | x**2 b \n' '2 | c x**2\n' '3 | e f ' - ) + ) s = str(TableForm([["a", "b"], ["c", "d"], ["e", "f"]], headings=(None, "automatic"))) assert s == dedent('''\ @@ -49,15 +50,15 @@ 'Group A | 5 7 \n' 'Group B | 4 2 \n' 'Group C | 10 3 ' - ) + ) raises( ValueError, lambda: - TableForm( + TableForm( [[5, 7], [4, 2], [10, 3]], headings=[["Group A", "Group B", "Group C"], ["y1", "y2"]], alignments="middle") - ) + ) s = str(TableForm([[5, 7], [4, 2], [10, 3]], headings=[["Group A", "Group B", "Group C"], ["y1", "y2"]], alignments="right")) @@ -69,111 +70,113 @@ Group C | 10 3''') # other alignment permutations - d = [[1,100],[100,1]] - s = TableForm(d, headings=(('xxx', 'x'),None), alignments='l') + d = [[1, 100], [100, 1]] + s = TableForm(d, headings=(('xxx', 'x'), None), alignments='l') assert str(s) == ( - 'xxx | 1 100\n' - ' x | 100 1 ' + 'xxx | 1 100\n' + ' x | 100 1 ' ) - s = TableForm(d, headings=(('xxx', 'x'),None), alignments='lr') + s = TableForm(d, headings=(('xxx', 'x'), None), alignments='lr') assert str(s) == dedent('''\ xxx | 1 100 x | 100 1''') - s = TableForm(d, headings=(('xxx', 'x'),None), alignments='clr') + s = TableForm(d, headings=(('xxx', 'x'), None), alignments='clr') assert str(s) == dedent('''\ xxx | 1 100 x | 100 1''') - s = TableForm(d ,headings=(('xxx','x'),None)) + s = TableForm(d, headings=(('xxx', 'x'), None)) assert str(s) == ( - 'xxx | 1 100\n' - ' x | 100 1 ' + 'xxx | 1 100\n' + ' x | 100 1 ' ) raises(ValueError, lambda: TableForm(d, alignments='clr')) #pad - s = str(TableForm([[None, "-", 2],[1]], pad='?')) + s = str(TableForm([[None, "-", 2], [1]], pad='?')) assert s == dedent('''\ ? - 2 1 ? ?''') + def test_TableForm_latex(): s = latex(TableForm([[0, x**3], ["c", S(1)/4], [sqrt(x), sin(x**2)]], wipe_zeros=True, headings=("automatic", "automatic"))) assert s == ( - '\\begin{tabular}{r l l}\n' - ' & 1 & 2 \\\\\n' - '\\hline\n' - '1 & & $x^{3}$ \\\\\n' - '2 & $c$ & $\\frac{1}{4}$ \\\\\n' - '3 & $\\sqrt{x}$ & $\\sin{\\left (x^{2} \\right )}$ \\\\\n' - '\\end{tabular}' + '\\begin{tabular}{r l l}\n' + ' & 1 & 2 \\\\\n' + '\\hline\n' + '1 & & $x^{3}$ \\\\\n' + '2 & $c$ & $\\frac{1}{4}$ \\\\\n' + '3 & $\\sqrt{x}$ & $\\sin{\\left (x^{2} \\right )}$ \\\\\n' + '\\end{tabular}' ) s = latex(TableForm([[0, x**3], ["c", S(1)/4], [sqrt(x), sin(x**2)]], wipe_zeros=True, headings=("automatic", "automatic"), alignments='l')) assert s == ( - '\\begin{tabular}{r l l}\n' - ' & 1 & 2 \\\\\n' - '\\hline\n' - '1 & & $x^{3}$ \\\\\n' - '2 & $c$ & $\\frac{1}{4}$ \\\\\n' - '3 & $\\sqrt{x}$ & $\\sin{\\left (x^{2} \\right )}$ \\\\\n' - '\\end{tabular}' + '\\begin{tabular}{r l l}\n' + ' & 1 & 2 \\\\\n' + '\\hline\n' + '1 & & $x^{3}$ \\\\\n' + '2 & $c$ & $\\frac{1}{4}$ \\\\\n' + '3 & $\\sqrt{x}$ & $\\sin{\\left (x^{2} \\right )}$ \\\\\n' + '\\end{tabular}' ) s = latex(TableForm([[0, x**3], ["c", S(1)/4], [sqrt(x), sin(x**2)]], wipe_zeros=True, headings=("automatic", "automatic"), alignments='l'*3)) assert s == ( - '\\begin{tabular}{l l l}\n' - ' & 1 & 2 \\\\\n' - '\\hline\n' - '1 & & $x^{3}$ \\\\\n' - '2 & $c$ & $\\frac{1}{4}$ \\\\\n' - '3 & $\\sqrt{x}$ & $\\sin{\\left (x^{2} \\right )}$ \\\\\n' - '\\end{tabular}' + '\\begin{tabular}{l l l}\n' + ' & 1 & 2 \\\\\n' + '\\hline\n' + '1 & & $x^{3}$ \\\\\n' + '2 & $c$ & $\\frac{1}{4}$ \\\\\n' + '3 & $\\sqrt{x}$ & $\\sin{\\left (x^{2} \\right )}$ \\\\\n' + '\\end{tabular}' ) s = latex(TableForm([["a", x**3], ["c", S(1)/4], [sqrt(x), sin(x**2)]], headings=("automatic", "automatic"))) assert s == ( - '\\begin{tabular}{r l l}\n' - ' & 1 & 2 \\\\\n' - '\\hline\n' - '1 & $a$ & $x^{3}$ \\\\\n' - '2 & $c$ & $\\frac{1}{4}$ \\\\\n' - '3 & $\\sqrt{x}$ & $\\sin{\\left (x^{2} \\right )}$ \\\\\n' - '\\end{tabular}' + '\\begin{tabular}{r l l}\n' + ' & 1 & 2 \\\\\n' + '\\hline\n' + '1 & $a$ & $x^{3}$ \\\\\n' + '2 & $c$ & $\\frac{1}{4}$ \\\\\n' + '3 & $\\sqrt{x}$ & $\\sin{\\left (x^{2} \\right )}$ \\\\\n' + '\\end{tabular}' ) s = latex(TableForm([["a", x**3], ["c", S(1)/4], [sqrt(x), sin(x**2)]], formats=['(%s)', None], headings=("automatic", "automatic"))) assert s == ( - '\\begin{tabular}{r l l}\n' - ' & 1 & 2 \\\\\n' - '\\hline\n' - '1 & (a) & $x^{3}$ \\\\\n' - '2 & (c) & $\\frac{1}{4}$ \\\\\n' - '3 & (sqrt(x)) & $\\sin{\\left (x^{2} \\right )}$ \\\\\n' - '\\end{tabular}' + '\\begin{tabular}{r l l}\n' + ' & 1 & 2 \\\\\n' + '\\hline\n' + '1 & (a) & $x^{3}$ \\\\\n' + '2 & (c) & $\\frac{1}{4}$ \\\\\n' + '3 & (sqrt(x)) & $\\sin{\\left (x^{2} \\right )}$ \\\\\n' + '\\end{tabular}' ) + def neg_in_paren(x, i, j): - if i%2: + if i % 2: return ('(%s)' if x < 0 else '%s') % x else: - pass # use default print + pass # use default print s = latex(TableForm([[-1, 2], [-3, 4]], formats=[neg_in_paren]*2, headings=("automatic", "automatic"))) assert s == ( - '\\begin{tabular}{r l l}\n' - ' & 1 & 2 \\\\\n' - '\\hline\n' - '1 & -1 & 2 \\\\\n' - '2 & (-3) & 4 \\\\\n' - '\\end{tabular}' + '\\begin{tabular}{r l l}\n' + ' & 1 & 2 \\\\\n' + '\\hline\n' + '1 & -1 & 2 \\\\\n' + '2 & (-3) & 4 \\\\\n' + '\\end{tabular}' ) s = latex(TableForm([["a", x**3], ["c", S(1)/4], [sqrt(x), sin(x**2)]])) assert s == ( - '\\begin{tabular}{l l}\n' - '$a$ & $x^{3}$ \\\\\n' - '$c$ & $\\frac{1}{4}$ \\\\\n' - '$\\sqrt{x}$ & $\\sin{\\left (x^{2} \\right )}$ \\\\\n' - '\\end{tabular}' + '\\begin{tabular}{l l}\n' + '$a$ & $x^{3}$ \\\\\n' + '$c$ & $\\frac{1}{4}$ \\\\\n' + '$\\sqrt{x}$ & $\\sin{\\left (x^{2} \\right )}$ \\\\\n' + '\\end{tabular}' ) diff -Nru python3-sympy-0.7.2/sympy/printing/tests/test_theanocode.py python3-sympy-0.7.3/sympy/printing/tests/test_theanocode.py --- python3-sympy-0.7.2/sympy/printing/tests/test_theanocode.py 1970-01-01 00:00:00.000000000 +0000 +++ python3-sympy-0.7.3/sympy/printing/tests/test_theanocode.py 2013-07-13 17:53:32.000000000 +0000 @@ -0,0 +1,223 @@ +from sympy.external import import_module + +theano = import_module('theano') +if theano: + ts = theano.scalar + tt = theano.tensor + xt, yt, zt = [tt.scalar(name, 'floatX') for name in 'xyz'] +else: + #bin/test will not execute any tests now + disabled = True + +import sympy +from sympy import S +sy = sympy +from sympy.abc import x, y, z, a, b, c +from sympy.printing.theanocode import (theano_code, dim_handling, + theano_function) + +def fgraph_of(*exprs): + """ Transform SymPy expressions into Theano Computation """ + outs = list(map(theano_code, exprs)) + ins = theano.gof.graph.inputs(outs) + ins, outs = theano.gof.graph.clone(ins, outs) + return theano.gof.FunctionGraph(ins, outs) + +def theano_simplify(fgraph): + """ Simplify a Theano Computation """ + mode = theano.compile.get_default_mode().excluding("fusion") + fgraph = fgraph.clone() + mode.optimizer.optimize(fgraph) + return fgraph + + +def theq(a, b): + """ theano equality """ + astr = theano.printing.debugprint(a, file='str') + bstr = theano.printing.debugprint(b, file='str') + + if not astr == bstr: + print() + print(astr) + print(bstr) + + return astr == bstr + +def test_symbol(): + xt = theano_code(x) + assert isinstance(xt, (tt.TensorVariable, ts.ScalarVariable)) + assert xt.name == x.name + + assert theano_code(x, broadcastables={x: (False,)}).broadcastable == (False,) + assert theano_code(x, broadcastables={x: (False,)}).name == x.name + +def test_add(): + expr = x + y + comp = theano_code(expr) + assert comp.owner.op == theano.tensor.add + + comp = theano_code(expr, broadcastables={x: (False,), y: (False,)}) + assert comp.broadcastable == (False,) + + comp = theano_code(expr, broadcastables={x: (False, True), y: (False, False)}) + assert comp.broadcastable == (False, False) + + +def test_trig(): + assert theq(theano_code(sympy.sin(x)), tt.sin(xt)) + assert theq(theano_code(sympy.tan(x)), tt.tan(xt)) + +def test_many(): + expr = sy.exp(x**2 + sy.cos(y)) * sy.log(2*z) + comp = theano_code(expr) + expected = tt.exp(xt**2 + tt.cos(yt)) * tt.log(2*zt) + # assert theq(comp, expected) + +def test_dtype(): + assert theano_code(x, dtypes={x: 'float32'}).type.dtype == 'float32' + assert theano_code(x, dtypes={x: 'float64'}).type.dtype == 'float64' + assert theano_code(x+1, dtypes={x: 'float32'}).type.dtype == 'float32' + assert theano_code(x+y, dtypes={x: 'float64', y: 'float32'}).type.dtype == 'float64' + +def test_MatrixSymbol(): + X = sympy.MatrixSymbol('X', 4, 5) + Xt = theano_code(X) + assert isinstance(Xt, tt.TensorVariable) + assert Xt.broadcastable == (False, False) + +def test_MatMul(): + X = sympy.MatrixSymbol('X', 4, 4) + Y = sympy.MatrixSymbol('X', 4, 4) + Z = sympy.MatrixSymbol('X', 4, 4) + expr = X*Y*Z + assert isinstance(theano_code(expr).owner.op, tt.Dot) + +def test_Transpose(): + X = sympy.MatrixSymbol('X', 4, 4) + assert isinstance(theano_code(X.T).owner.op, tt.DimShuffle) + +def test_MatAdd(): + X = sympy.MatrixSymbol('X', 4, 4) + Y = sympy.MatrixSymbol('X', 4, 4) + Z = sympy.MatrixSymbol('X', 4, 4) + expr = X+Y+Z + assert isinstance(theano_code(expr).owner.op, tt.Elemwise) + +def test_symbols_are_created_once(): + expr = x**x + comp = theano_code(expr) + + assert theq(comp, xt**xt) + +def test_dim_handling(): + assert dim_handling([x], dim=2) == {x: (False, False)} + assert dim_handling([x, y], dims={x: 1, y: 2}) == {x: (False, True), + y: (False, False)} + assert dim_handling([x], broadcastables={x: (False,)}) == {x: (False,)} + +def test_Rationals(): + assert theq(theano_code(sympy.Integer(2) / 3), tt.true_div(2, 3)) + assert theq(theano_code(S.Half), tt.true_div(1, 2)) + +def test_Integers(): + assert theano_code(sympy.Integer(3)) == 3 + +def test_factorial(): + n = sympy.Symbol('n') + assert theano_code(sympy.factorial(n)) + +def test_Derivative(): + simp = lambda expr: theano_simplify(fgraph_of(expr)) + assert theq(simp(theano_code(sy.Derivative(sy.sin(x), x, evaluate=False))), + simp(theano.grad(tt.sin(xt), xt))) + +def test_theano_function_simple(): + f = theano_function([x, y], [x+y]) + assert f(2, 3) == 5 + + +def test_theano_function_numpy(): + import numpy as np + f = theano_function([x, y], [x+y], dim=1) + assert np.linalg.norm(f([1, 2], [3, 4]) - np.asarray([4, 6])) < 1e-9 + + f = theano_function([x, y], [x+y], dtypes={x: 'float64', y: 'float64'}, + dim=1) + xx = np.arange(3).astype('float64') + yy = 2*np.arange(3).astype('float64') + assert np.linalg.norm(f(xx, yy) - 3*np.arange(3)) < 1e-9 + +def test_slice(): + assert theano_code(slice(1, 2, 3)) == slice(1, 2, 3) + assert str(theano_code(slice(1, x, 3), dtypes={x: 'int32'})) ==\ + str(slice(1, xt, 3)) + +def test_MatrixSlice(): + n = sympy.Symbol('n', integer=True) + X = sympy.MatrixSymbol('X', n, n) + + Y = X[1:2:3, 4:5:6] + Yt = theano_code(Y) + assert tuple(Yt.owner.op.idx_list) == (slice(1,2,3), slice(4,5,6)) + assert Yt.owner.inputs[0] == theano_code(X) + + k = sympy.Symbol('k') + kt = theano_code(k, dtypes={k: 'int32'}) + start, stop, step = 4, k, 2 + Y = X[start:stop:step] + Yt = theano_code(Y, dtypes={n: 'int32', k: 'int32'}) + # assert Yt.owner.op.idx_list[0].stop == kt + +def test_BlockMatrix(): + n = sympy.Symbol('n', integer=True) + A = sympy.MatrixSymbol('A', n, n) + B = sympy.MatrixSymbol('B', n, n) + C = sympy.MatrixSymbol('C', n, n) + D = sympy.MatrixSymbol('D', n, n) + At, Bt, Ct, Dt = list(map(theano_code, (A, B, C, D))) + Block = sympy.BlockMatrix([[A, B], [C, D]]) + Blockt = theano_code(Block) + solutions = [tt.join(0, tt.join(1, At, Bt), tt.join(1, Ct, Dt)), + tt.join(1, tt.join(0, At, Ct), tt.join(0, Bt, Dt))] + assert any(theq(Blockt, solution) for solution in solutions) + +def test_BlockMatrix_Inverse_execution(): + k, n = 2, 4 + dtype = 'float32' + A = sympy.MatrixSymbol('A', n, k) + B = sympy.MatrixSymbol('B', n, n) + inputs = A, B + output = B.I*A + + cutsizes = {A: [(n/2, n/2), (k/2, k/2)], + B: [(n/2, n/2), (n/2, n/2)]} + cutinputs = [sympy.blockcut(i, *cutsizes[i]) for i in inputs] + cutoutput = output.subs(dict(list(zip(inputs, cutinputs)))) + + dtypes = dict(list(zip(inputs, [dtype]*len(inputs)))) + f = theano_function(inputs, [output], dtypes=dtypes) + fblocked = theano_function(inputs, [sympy.block_collapse(cutoutput)], + dtypes=dtypes) + + import numpy + ninputs = [numpy.random.rand(*x.shape).astype(dtype) for x in inputs] + ninputs = [numpy.arange(n*k).reshape(A.shape).astype(dtype), + numpy.eye(n).astype(dtype)] + ninputs[1] += numpy.ones(B.shape)*1e-5 + + assert numpy.allclose(f(*ninputs), fblocked(*ninputs), rtol=1e-5) + +def test_DenseMatrix(): + t = sy.Symbol('theta') + for MatrixType in [sy.Matrix, sy.ImmutableMatrix]: + X = MatrixType([[sy.cos(t), -sy.sin(t)], [sy.sin(t), sy.cos(t)]]) + tX = theano_code(X) + assert isinstance(tX, tt.TensorVariable) + assert tX.owner.op == tt.join + +def test_AppliedUndef(): + t = sy.Symbol('t') + f = sy.Function('f') + ft = theano_code(f(t)) + assert isinstance(ft, tt.TensorVariable) + assert ft.name == 'f_t' diff -Nru python3-sympy-0.7.2/sympy/printing/theanocode.py python3-sympy-0.7.3/sympy/printing/theanocode.py --- python3-sympy-0.7.2/sympy/printing/theanocode.py 1970-01-01 00:00:00.000000000 +0000 +++ python3-sympy-0.7.3/sympy/printing/theanocode.py 2013-07-13 17:53:32.000000000 +0000 @@ -0,0 +1,197 @@ +from sympy.utilities import default_sort_key +from sympy.external import import_module + +from sympy.printing.printer import Printer +import sympy +from functools import partial + +theano = import_module('theano') +if theano: + ts = theano.scalar + tt = theano.tensor + from theano import sandbox + from theano.sandbox import linalg as tlinalg + + mapping = { + sympy.Add: tt.add, + sympy.Mul: tt.mul, + sympy.Abs: tt.abs_, + sympy.sign: tt.sgn, + sympy.ceiling: tt.ceil, + sympy.floor: tt.floor, + sympy.log: tt.log, + sympy.exp: tt.exp, + sympy.sqrt: tt.sqrt, + sympy.cos: tt.cos, + sympy.acos: tt.arccos, + sympy.sin: tt.sin, + sympy.asin: tt.arcsin, + sympy.tan: tt.tan, + sympy.atan: tt.arctan, + sympy.atan2: tt.arctan2, + sympy.cosh: tt.cosh, + sympy.acosh: tt.arccosh, + sympy.sinh: tt.sinh, + sympy.asinh: tt.arcsinh, + sympy.tanh: tt.tanh, + sympy.atanh: tt.arctanh, + sympy.re: tt.real, + sympy.im: tt.imag, + sympy.arg: tt.angle, + sympy.erf: tt.erf, + sympy.gamma: tt.gamma, + sympy.loggamma: tt.gammaln, + sympy.Pow: tt.pow, + sympy.Eq: tt.eq, + sympy.Gt: tt.gt, + sympy.Lt: tt.lt, + sympy.Le: tt.le, + sympy.Ge: tt.ge, + sympy.Max: tt.maximum, # Sympy accept >2 inputs, Theano only 2 + sympy.Min: tt.minimum, # Sympy accept >2 inputs, Theano only 2 + + # Matrices + sympy.MatAdd: tt.Elemwise(ts.add), + sympy.HadamardProduct: tt.Elemwise(ts.mul), + sympy.Trace: tlinalg.trace, + sympy.Determinant : tlinalg.det, + sympy.Inverse: tlinalg.matrix_inverse, + sympy.Transpose: tt.DimShuffle((False, False), [1, 0]), + } + +class TheanoPrinter(Printer): + """ Code printer for Theano computations """ + printmethod = "_theano" + + cache = dict() + + def _print_Symbol(self, s, dtypes={}, broadcastables={}): + dtype = dtypes.get(s, 'floatX') + broadcastable = broadcastables.get(s, ()) + key = (s.name, dtype, broadcastable, type(s)) + if key in self.cache: + return self.cache[key] + else: + value = tt.tensor(name=s.name, dtype=dtype, broadcastable=broadcastable) + self.cache[key] = value + return value + + def _print_AppliedUndef(self, s, dtypes={}, broadcastables={}): + dtype = dtypes.get(s, 'floatX') + broadcastable = broadcastables.get(s, ()) + name = str(type(s)) + '_' + str(s.args[0]) + key = (name, dtype, broadcastable, type(s), s.args) + if key in self.cache: + return self.cache[key] + else: + value = tt.tensor(name=name, dtype=dtype, broadcastable=broadcastable) + self.cache[key] = value + return value + + + def _print_Basic(self, expr, **kwargs): + op = mapping[type(expr)] + children = [self._print(arg, **kwargs) for arg in expr.args] + return op(*children) + + def _print_Number(self, n, **kwargs): + return eval(str(n)) + + def _print_MatrixSymbol(self, X, dtypes={}, **kwargs): + dtype = dtypes.get(X, 'floatX') + # shape = [self._print(d, dtypes) for d in X.shape] + key = (X.name, dtype, type(X)) + if key in self.cache: + return self.cache[key] + else: + value = tt.Tensor(dtype, (False, False))(X.name) + self.cache[key] = value + return value + + def _print_DenseMatrix(self, X, **kwargs): + return tt.stacklists([[self._print(arg, **kwargs) for arg in L] + for L in X.tolist()]) + _print_ImmutableMatrix = _print_DenseMatrix + + def _print_MatMul(self, expr, **kwargs): + children = [self._print(arg, **kwargs) for arg in expr.args] + result = children[0] + for child in children[1:]: + result = tt.dot(result, child) + return result + + def _print_MatrixSlice(self, expr, **kwargs): + parent = self._print(expr.parent, **kwargs) + rowslice = self._print(slice(*expr.rowslice), **kwargs) + colslice = self._print(slice(*expr.colslice), **kwargs) + return parent[rowslice, colslice] + + def _print_BlockMatrix(self, expr, **kwargs): + nrows, ncols = expr.blocks.shape + blocks = [[self._print(expr.blocks[r, c], **kwargs) + for c in range(ncols)] + for r in range(nrows)] + return tt.join(0, *[tt.join(1, *row) for row in blocks]) + + + def _print_slice(self, expr, **kwargs): + return slice(*[self._print(i, **kwargs) + if isinstance(i, sympy.Basic) else i + for i in (expr.start, expr.stop, expr.step)]) + + def _print_Pi(self, expr, **kwargs): + return 3.141592653589793 + + def _print_Rational(self, expr, **kwargs): + return tt.true_div(self._print(expr.p, **kwargs), + self._print(expr.q, **kwargs)) + + def _print_Integer(self, expr, **kwargs): + return expr.p + + def _print_factorial(self, expr, **kwargs): + return self._print(sympy.gamma(expr.args[0] + 1), **kwargs) + + def _print_Derivative(self, deriv, **kwargs): + rv = self._print(deriv.expr, **kwargs) + for var in deriv.variables: + var = self._print(var, **kwargs) + rv = tt.Rop(rv, var, tt.ones_like(var)) + return rv + + def emptyPrinter(self, expr): + return expr + + def doprint(self, expr, **kwargs): + """Returns printer's representation for expr (as a string)""" + return self._print(expr, **kwargs) + + +def theano_code(expr, **kwargs): + return TheanoPrinter({}).doprint(expr, **kwargs) + + +def dim_handling(inputs, dim=None, dims={}, broadcastables={}, keys=()): + """ Handle various input types for dimensions in tensor_wrap + + See Also: + tensor_wrap + theano_funciton + """ + if dim: + dims = dict(list(zip(inputs, [dim]*len(inputs)))) + if dims: + maxdim = max(dims.values()) + broadcastables = dict((i, (False,)*dims[i] + (True,)*(maxdim-dims[i])) + for i in inputs) + return broadcastables + + +def theano_function(inputs, outputs, dtypes={}, **kwargs): + """ Create Theano function from SymPy expressions """ + broadcastables = dim_handling(inputs, **kwargs) + code = partial(theano_code, dtypes=dtypes, broadcastables=broadcastables) + tinputs = list(map(code, inputs)) + toutputs = list(map(code, outputs)) + toutputs = toutputs[0] if len(toutputs) == 1 else toutputs + return theano.function(tinputs, toutputs) diff -Nru python3-sympy-0.7.2/sympy/printing/tree.py python3-sympy-0.7.3/sympy/printing/tree.py --- python3-sympy-0.7.2/sympy/printing/tree.py 2012-10-17 03:02:22.000000000 +0000 +++ python3-sympy-0.7.3/sympy/printing/tree.py 2013-07-13 17:53:32.000000000 +0000 @@ -15,23 +15,26 @@ +-c """ - def indent(s,type=1): + def indent(s, type=1): x = s.split("\n") - r = "+-%s\n"%x[0] + r = "+-%s\n" % x[0] for a in x[1:]: - if a=="": continue - if type==1: - r += "| %s\n"%a + if a == "": + continue + if type == 1: + r += "| %s\n" % a else: - r += " %s\n"%a + r += " %s\n" % a return r - if len(subtrees)==0: return "" - f=""; + if len(subtrees) == 0: + return "" + f = "" for a in subtrees[:-1]: f += indent(a) - f += indent(subtrees[-1],2) + f += indent(subtrees[-1], 2) return f + def print_node(node): """ Returns an information about the "node". @@ -44,6 +47,7 @@ s += "%s: %s\n" % (a, node._assumptions[a]) return s + def tree(node): """ Returns a tree representation of "node" as a string. @@ -55,9 +59,10 @@ subtrees = [] for arg in node.args: subtrees.append(tree(arg)) - s = print_node(node)+pprint_nodes(subtrees) + s = print_node(node) + pprint_nodes(subtrees) return s + def print_tree(node): """ Prints a tree representation of "node". diff -Nru python3-sympy-0.7.2/sympy/series/acceleration.py python3-sympy-0.7.3/sympy/series/acceleration.py --- python3-sympy-0.7.2/sympy/series/acceleration.py 2012-10-17 03:02:22.000000000 +0000 +++ python3-sympy-0.7.3/sympy/series/acceleration.py 2013-07-13 17:53:32.000000000 +0000 @@ -57,9 +57,9 @@ """ s = S.Zero - for j in range(0, N+1): - s += A.subs(k, Integer(n+j)).doit() * (n+j)**N * (-1)**(j+N) / \ - (factorial(j) * factorial(N-j)) + for j in range(0, N + 1): + s += A.subs(k, Integer(n + j)).doit() * (n + j)**N * (-1)**(j + N) / \ + (factorial(j) * factorial(N - j)) return s @@ -85,12 +85,12 @@ The correct value is 0.6931471805599453094172321215. """ - table = [A.subs(k, Integer(j)).doit() for j in range(n+m+2)] + table = [A.subs(k, Integer(j)).doit() for j in range(n + m + 2)] table2 = table[:] - for i in range(1, m+1): - for j in range(i, n+m+1): - x, y, z = table[j-1], table[j], table[j+1] + for i in range(1, m + 1): + for j in range(i, n + m + 1): + x, y, z = table[j - 1], table[j], table[j + 1] table2[j] = (z*x - y**2) / (z + x - 2*y) table = table2[:] return table[n] diff -Nru python3-sympy-0.7.2/sympy/series/gruntz.py python3-sympy-0.7.3/sympy/series/gruntz.py --- python3-sympy-0.7.2/sympy/series/gruntz.py 2012-10-17 03:02:22.000000000 +0000 +++ python3-sympy-0.7.3/sympy/series/gruntz.py 2013-07-13 17:53:32.000000000 +0000 @@ -128,6 +128,7 @@ O = Order + def debug(func): """Only for debugging purposes: prints a tree @@ -150,18 +151,19 @@ from sympy.utilities.timeutils import timethis timeit = timethis('gruntz') + def tree(subtrees): """Only debugging purposes: prints a tree""" def indent(s, type=1): x = s.split("\n") - r = "+-%s\n"%x[0] + r = "+-%s\n" % x[0] for a in x[1:]: if a == "": continue if type == 1: - r += "| %s\n"%a + r += "| %s\n" % a else: - r += " %s\n"%a + r += " %s\n" % a return r if len(subtrees) == 0: return "" @@ -173,6 +175,8 @@ tmp = [] iter = 0 + + def maketree(f, *args, **kw): """Only debugging purposes: prints a tree""" global tmp @@ -199,6 +203,7 @@ tmp = [] return r + def compare(a, b, x): """Returns "<" if a" for a>b""" # log(exp(...)) must always be simplified here for termination @@ -216,6 +221,7 @@ else: return "=" + class SubsSet(dict): """ Stores (expr, dummy) pairs, and how to rewrite expr-s. @@ -286,7 +292,8 @@ tr = {} for expr, var in s2.items(): if expr in self: - if exps: exps = exps.subs(var, res[expr]) + if exps: + exps = exps.subs(var, res[expr]) tr[var] = res[expr] else: res[expr] = var @@ -301,6 +308,7 @@ r[expr] = var return r + @debug def mrv(e, x): """Returns a SubsSet of most rapidly varying (mrv) subexpressions of 'e', @@ -313,7 +321,7 @@ s = SubsSet() return s, s[x] elif e.is_Mul or e.is_Add: - i, d = e.as_independent(x) # throw away x-independent terms + i, d = e.as_independent(x) # throw away x-independent terms if d.func != e.func: s, expr = mrv(d, x) return s, e.func(i, expr) @@ -360,7 +368,9 @@ raise NotImplementedError("MRV set computation for derviatives" " not implemented yet.") return mrv(e.args[0], x) - raise NotImplementedError("Don't know how to calculate the mrv of '%s'" % e) + raise NotImplementedError( + "Don't know how to calculate the mrv of '%s'" % e) + def mrv_max3(f, expsf, g, expsg, union, expsboth, x): """Computes the maximum of two sets of expressions f and g, which @@ -387,6 +397,7 @@ assert c == "=" return union, expsboth + def mrv_max1(f, g, exps, x): """Computes the maximum of two sets of expressions f and g, which are in the same comparability class, i.e. mrv_max1() compares (two elements of) @@ -398,6 +409,7 @@ return mrv_max3(f, g.do_subs(exps), g, f.do_subs(exps), u, b, x) + @debug @cacheit @timeit @@ -447,12 +459,13 @@ if e.exp.is_Integer: return s**e.exp elif e.func is log: - return sign(e.args[0] -1, x) + return sign(e.args[0] - 1, x) # if all else fails, do it the hard way c0, e0 = mrv_leadterm(e, x) return sign(c0, x) + @debug @timeit @cacheit @@ -462,7 +475,7 @@ e = e.rewrite('tractable', deep=True) if not e.has(x): - return e #e is a constant + return e # e is a constant if not x.is_positive: # We make sure that x.is_positive is True so we # get all the correct mathematical bechavior from the expression. @@ -473,8 +486,8 @@ c0, e0 = mrv_leadterm(e, x) sig = sign(e0, x) if sig == 1: - return S.Zero # e0>0: lim f = 0 - elif sig == -1: #e0<0: lim f = +-oo (the sign depends on the sign of c0) + return S.Zero # e0>0: lim f = 0 + elif sig == -1: # e0<0: lim f = +-oo (the sign depends on the sign of c0) if c0.match(I*Wild("a", exclude=[I])): return c0*oo s = sign(c0, x) @@ -482,7 +495,8 @@ assert s != 0 return s*oo elif sig == 0: - return limitinf(c0, x) #e0=0: lim f = lim c0 + return limitinf(c0, x) # e0=0: lim f = lim c0 + def moveup2(s, x): r = SubsSet() @@ -492,6 +506,7 @@ r.rewrites[var] = s.rewrites[var].subs(x, exp(x)) return r + def moveup(l, x): return [e.subs(x, exp(x)) for e in l] @@ -515,6 +530,7 @@ return series n *= 2 + @debug @timeit @cacheit @@ -550,9 +566,10 @@ w = Dummy("w", real=True, positive=True, bounded=True) f, logw = rewrite(exps, Omega, x, w) series = calculate_series(f, w, logx=logw) - series = series.subs(log(w), logw) # this should not be necessary + series = series.subs(log(w), logw) # this should not be necessary return series.leadterm(w) + def build_expression_tree(Omega, rewrites): r""" Helper function for rewrite. @@ -589,6 +606,7 @@ return nodes + @debug @timeit def rewrite(e, Omega, x, wsym): @@ -611,10 +629,11 @@ nodes = build_expression_tree(Omega, rewrites) Omega.sort(key=lambda x: nodes[x[1]].ht(), reverse=True) - g, _ = Omega[-1] #g is going to be the "w" - the simplest one in the mrv set + g, _ = Omega[-1] + # g is going to be the "w" - the simplest one in the mrv set sig = sign(g.args[0], x) if sig == 1: - wsym = 1/wsym #if g goes to oo, substitute 1/w + wsym = 1/wsym # if g goes to oo, substitute 1/w elif sig != -1: raise NotImplementedError('Result depends on the sign of %s' % sig) #O2 is a list, which results by rewriting each item in Omega using "w" @@ -646,7 +665,7 @@ #finally compute the logarithm of w (logw). logw = g.args[0] if sig == 1: - logw = -logw #log(w)->log(1/w)=-log(w) + logw = -logw # log(w)->log(1/w)=-log(w) # Some parts of sympy have difficulty computing series expansions with # non-integral exponents. The following heuristic improves the situation: @@ -656,6 +675,7 @@ return f, logw + def gruntz(e, z, z0, dir="+"): """ Compute the limit of e(z) at the point z0 using the Gruntz algorithm. diff -Nru python3-sympy-0.7.2/sympy/series/kauers.py python3-sympy-0.7.3/sympy/series/kauers.py --- python3-sympy-0.7.2/sympy/series/kauers.py 2012-10-17 03:02:22.000000000 +0000 +++ python3-sympy-0.7.3/sympy/series/kauers.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,19 +1,19 @@ from sympy import expand from sympy import diff +from sympy import Sum -def finite_diff(expression, variable, increment = 1): +def finite_diff(expression, variable, increment=1): """ - Takes as input the expression and the variable used in constructing the expression - and returns the diffrence between function's value when the input is incremented - to 1 and the original function value. More specifically, it takes as input the - function f(x) expression and x used in function expression as variable and returns - f(x + 1)-f(x).If you want an increment other than 1, supply it as a - third argument to the finite_diff + Takes as input a polynomial expression and the variable used to construct + it and returns the difference between function's value when the input is + incremented to 1 and the original function value. If you want an increment + other than one supply it as a third argument. Examples ========= - >>> from sympy.abc import x, y, z + >>> from sympy.abc import x, y, z, k, n >>> from sympy.series.kauers import finite_diff + >>> from sympy import Sum >>> finite_diff(x**2, x) 2*x + 1 >>> finite_diff(y**3 + 2*y**2 + 3*y + 4, y) @@ -27,3 +27,28 @@ expression2 = expression.subs(variable, variable + increment) expression2 = expression2.expand() return expression2 - expression + +def finite_diff_kauers(sum): + """ + Takes as input a Sum instance and returns the difference between the sum + with the upper index incremented by 1 and the original sum. For example, + if S(n) is a sum, then finite_diff_kauers will return S(n + 1) - S(n). + + Examples + ======== + >>> from sympy.series.kauers import finite_diff_kauers + >>> from sympy import Sum + >>> from sympy.abc import x, y, m, n, k + >>> finite_diff_kauers(Sum(k, (k, 1, n))) + n + 1 + >>> finite_diff_kauers(Sum(1/k, (k, 1, n))) + 1/(n + 1) + >>> finite_diff_kauers(Sum((x*y**2), (x, 1, n), (y, 1, m))) + (m + 1)**2*(n + 1) + >>> finite_diff_kauers(Sum((x*y), (x, 1, m), (y, 1, n))) + (m + 1)*(n + 1) + """ + function = sum.function + for l in sum.limits: + function = function.subs(l[0], l[- 1] + 1) + return function diff -Nru python3-sympy-0.7.2/sympy/series/limits.py python3-sympy-0.7.3/sympy/series/limits.py --- python3-sympy-0.7.2/sympy/series/limits.py 2012-10-17 03:02:22.000000000 +0000 +++ python3-sympy-0.7.3/sympy/series/limits.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,7 +1,8 @@ from sympy.core import S, Symbol, Add, sympify, Expr, PoleError, Mul, oo, C -from sympy.functions import tan, cot +from sympy.functions import tan, cot, factorial, gamma from .gruntz import gruntz + def limit(e, z, z0, dir="+"): """ Compute the limit of e(z) at the point z0. @@ -48,6 +49,13 @@ if not e.has(z): return e + # gruntz fails on factorials but works with the gamma function + # If no factorial term is present, e should remain unchanged. + # factorial is defined to be zero for negative inputs (which + # differs from gamma) so only rewrite for positive z0. + if z0.is_positive: + e = e.rewrite(factorial, gamma) + if e.func is tan: # discontinuity at odd multiples of pi/2; 0 at even disc = S.Pi/2 @@ -81,7 +89,7 @@ if e.is_Pow: b, ex = e.args - c = None # records sign of b if b is +/-z or has a bounded value + c = None # records sign of b if b is +/-z or has a bounded value if b.is_Mul: c, b = b.as_two_terms() if c is S.NegativeOne and b == z: @@ -92,7 +100,7 @@ if ex.is_number: if c is None: base = b.subs(z, z0) - if base.is_finite and (ex.is_bounded or base is not S.One): + if base != 0 and (ex.is_bounded or base is not S.One): return base**ex else: if z0 == 0 and ex < 0: @@ -155,104 +163,15 @@ return -oo*i if e.is_Add: - if e.is_polynomial() and not z0.is_unbounded: - return Add(*[limit(term, z, z0, dir) for term in e.args]) - - # this is a case like limit(x*y+x*z, z, 2) == x*y+2*x - # but we need to make sure, that the general gruntz() algorithm is - # executed for a case like "limit(sqrt(x+1)-sqrt(x),x,oo)==0" - - unbounded = [] - unbounded_result = [] - unbounded_const = [] - unknown = [] - unknown_result = [] - finite = [] - zero = [] - def _sift(term): - if z not in term.free_symbols: - if term.is_unbounded: - unbounded_const.append(term) - else: - finite.append(term) - else: - result = term.subs(z, z0) - bounded = result.is_bounded - if bounded is False or result is S.NaN: - unbounded.append(term) - if result != S.NaN: - # take result from direction given - result = limit(term, z, z0, dir) - unbounded_result.append(result) - elif bounded: - if result: - finite.append(result) - else: - zero.append(term) - else: - unknown.append(term) - unknown_result.append(result) - - for term in e.args: - _sift(term) - - bad = bool(unknown and unbounded) - if bad or len(unknown) > 1 or len(unbounded) > 1 and not zero: - uu = unknown + unbounded - # we won't be able to resolve this with unbounded - # terms, e.g. Sum(1/k, (k, 1, n)) - log(n) as n -> oo: - # since the Sum is unevaluated it's boundedness is - # unknown and the log(n) is oo so you get Sum - oo - # which is unsatisfactory. BUT...if there are both - # unknown and unbounded terms (condition 'bad') or - # there are multiple terms that are unknown, or - # there are multiple symbolic unbounded terms they may - # respond better if they are made into a rational - # function, so give them a chance to do so before - # reporting failure. - u = Add(*uu) - f = u.normal() - if f != u: - unknown = [] - unbounded = [] - unbounded_result = [] - unknown_result = [] - _sift(limit(f, z, z0, dir)) - - # We came in with a) unknown and unbounded terms or b) had multiple - # unknown terms - - # At this point we've done one of 3 things. - # (1) We did nothing with f so we now report the error - # showing the troublesome terms which are now in uu. OR - - # (2) We did something with f but the result came back as unknown. - # Normally this wouldn't be a problem, - # but we had either multiple terms that were troublesome (unk and - # unbounded or multiple unknown terms) so if we - # weren't able to resolve the boundedness by now, that indicates a - # problem so we report the error showing the troublesome terms which are - # now in uu. - if unknown: - if bad: - msg = 'unknown and unbounded terms present in %s' - elif unknown: - msg = 'multiple terms with unknown boundedness in %s' - raise NotImplementedError(msg % uu) - # OR - # (3) the troublesome terms have been identified as finite or unbounded - # and we proceed with the non-error code since the lists have been updated. - - u = Add(*unknown_result) - if unbounded_result or unbounded_const: - unbounded.extend(zero) - inf_limit = Add(*(unbounded_result + unbounded_const)) - if inf_limit is not S.NaN: - return inf_limit + u - if finite: - return Add(*finite) + limit(Add(*unbounded), z, z0, dir) + u - else: - return Add(*finite) + u + if e.is_polynomial(): + if not z0.is_unbounded: + return Add(*[limit(term, z, z0, dir) for term in e.args]) + elif e.is_rational_function(z): + rval = Add(*[limit(term, z, z0, dir) for term in e.args]) + if rval != S.NaN: + return rval + if not any([a.is_unbounded for a in e.args]): + e = e.normal() # workaround for issue 3744 if e.is_Order: args = e.args @@ -266,6 +185,7 @@ r = heuristics(e, z, z0, dir) return r + def heuristics(e, z, z0, dir): if abs(z0) is S.Infinity: return limit(e.subs(z, 1/z), z, S.Zero, "+" if z0 is S.Infinity else "-") @@ -314,7 +234,8 @@ elif not isinstance(dir, Symbol): raise TypeError("direction must be of type basestring or Symbol, not %s" % type(dir)) if str(dir) not in ('+', '-'): - raise ValueError("direction must be either '+' or '-', not %s" % dir) + raise ValueError( + "direction must be either '+' or '-', not %s" % dir) obj = Expr.__new__(cls) obj._args = (e, z, z0, dir) return obj diff -Nru python3-sympy-0.7.2/sympy/series/order.py python3-sympy-0.7.3/sympy/series/order.py --- python3-sympy-0.7.2/sympy/series/order.py 2012-10-17 03:02:22.000000000 +0000 +++ python3-sympy-0.7.3/sympy/series/order.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,8 +1,9 @@ from sympy.core import Basic, S, sympify, Expr, Rational, Symbol -from sympy.core import Add, Mul +from sympy.core import Add, Mul, expand_power_base, expand_log from sympy.core.cache import cacheit from sympy.core.compatibility import cmp_to_key + class Order(Expr): """ Represents the limiting behavior of some function @@ -95,47 +96,80 @@ @cacheit def __new__(cls, expr, *symbols, **assumptions): - expr = sympify(expr).expand() + expr = sympify(expr) if expr is S.NaN: return S.NaN if symbols: symbols = list(map(sympify, symbols)) if not all(isinstance(s, Symbol) for s in symbols): - raise NotImplementedError('Order at points other than 0 not supported.') + raise NotImplementedError( + 'Order at points other than 0 not supported.') else: symbols = list(expr.free_symbols) if expr.is_Order: - - new_symbols = list(expr.variables) - for s in symbols: - if s not in new_symbols: - new_symbols.append(s) - if len(new_symbols) == len(expr.variables): + v = set(expr.variables) + symbols = v | set(symbols) + if symbols == v: return expr - symbols = new_symbols + symbols = list(symbols) elif symbols: + symbols = list(set(symbols)) + + if len(symbols) > 1: + # XXX: better way? We need this expand() to + # workaround e.g: expr = x*(x + y). + # (x*(x + y)).as_leading_term(x, y) currently returns + # x*y (wrong order term!). That's why we want to deal with + # expand()'ed expr (handled in "if expr.is_Add" branch below). + expr = expr.expand() + if expr.is_Add: lst = expr.extract_leading_order(*symbols) - expr = Add(*[f.expr for (e,f) in lst]) + expr = Add(*[f.expr for (e, f) in lst]) + elif expr: - if len(symbols) > 1: - # TODO - # We cannot use compute_leading_term because that only - # works in one symbol. - expr = expr.as_leading_term(*symbols) - else: - expr = expr.compute_leading_term(symbols[0]) - terms = expr.as_coeff_mul(*symbols)[1] - s = set(symbols) - expr = Mul(*[t for t in terms if s & t.free_symbols]) + expr = expr.as_leading_term(*symbols) + expr = expr.as_independent(*symbols, **dict(as_Add=False))[1] + + expr = expand_power_base(expr) + expr = expand_log(expr) + + if len(symbols) == 1: + # The definition of O(f(x)) symbol explicitly stated that + # the argument of f(x) is irrelevant. That's why we can + # combine some power exponents (only "on top" of the + # expression tree for f(x)), e.g.: + # x**p * (-x)**q -> x**(p+q) for real p, q. + x = symbols[0] + margs = list(Mul.make_args( + expr.as_independent(x, **dict(as_Add=False))[1])) + + for i, t in enumerate(margs): + if t.is_Pow: + b, q = t.args + if b in (x, -x) and q.is_real and not q.has(x): + margs[i] = x**q + elif b.is_Pow and not b.exp.has(x): + b, r = b.args + if b in (x, -x) and r.is_real: + margs[i] = x**(r*q) + elif b.is_Mul and b.args[0] is S.NegativeOne: + b = -b + if b.is_Pow and not b.exp.has(x): + b, r = b.args + if b in (x, -x) and r.is_real: + margs[i] = x**(r*q) + + expr = Mul(*margs) if expr is S.Zero: return expr - elif not expr.has(*symbols): + + if not expr.has(*symbols): expr = S.One # create Order instance: @@ -185,7 +219,6 @@ def getO(self): return self - @cacheit def contains(self, expr): """ @@ -214,18 +247,19 @@ return False if expr.is_Order: if self.variables and expr.variables: - common_symbols = tuple([s for s in self.variables if s in expr.variables]) + common_symbols = tuple( + [s for s in self.variables if s in expr.variables]) elif self.variables: common_symbols = self.variables else: common_symbols = expr.variables if not common_symbols: - if not (self.variables or expr.variables): # O(1),O(1) + if not (self.variables or expr.variables): # O(1),O(1) return True return None r = None for s in common_symbols: - l = limit(powsimp(self.expr/expr.expr, deep=True,\ + l = limit(powsimp(self.expr/expr.expr, deep=True, combine='exp'), s, 0) != 0 if r is None: r = l @@ -240,13 +274,23 @@ if old.is_Symbol and old in self.variables: i = list(self.variables).index(old) if isinstance(new, Symbol): - return Order(self.expr._subs(old, new), *(self.variables[:i]+(new,)+self.variables[i+1:])) - return Order(self.expr._subs(old, new), *(self.variables[:i]+self.variables[i+1:])) + return Order(self.expr._subs(old, new), *(self.variables[:i] + (new,) + self.variables[i + 1:])) + return Order(self.expr._subs(old, new), *(self.variables[:i] + self.variables[i + 1:])) return Order(self.expr._subs(old, new), *self.variables) + def _eval_conjugate(self): + expr = self.expr._eval_conjugate() + if expr is not None: + return self.func(expr, *self.variables) + def _eval_derivative(self, x): return self.func(self.expr.diff(x), *self.variables) or self + def _eval_transpose(self): + expr = self.expr._eval_transpose() + if expr is not None: + return self.func(expr, *self.variables) + def _sage_(self): #XXX: SAGE doesn't have Order yet. Let's return 0 instead. return Rational(0)._sage_() diff -Nru python3-sympy-0.7.2/sympy/series/residues.py python3-sympy-0.7.3/sympy/series/residues.py --- python3-sympy-0.7.2/sympy/series/residues.py 2012-10-17 03:02:22.000000000 +0000 +++ python3-sympy-0.7.3/sympy/series/residues.py 2013-07-13 17:53:32.000000000 +0000 @@ -6,6 +6,7 @@ from sympy import Wild, sympify, Integer, Add from sympy.utilities.timeutils import timethis + @timethis('residue') def residue(expr, x, x0): """ @@ -48,7 +49,7 @@ from sympy import collect, Mul, Order, S expr = sympify(expr) if x0 != 0: - expr = expr.subs(x, x+x0) + expr = expr.subs(x, x + x0) for n in [0, 1, 2, 4, 8, 16, 32]: if n == 0: s = expr.series(x, n=0) diff -Nru python3-sympy-0.7.2/sympy/series/series.py python3-sympy-0.7.3/sympy/series/series.py --- python3-sympy-0.7.2/sympy/series/series.py 2012-10-17 03:02:22.000000000 +0000 +++ python3-sympy-0.7.3/sympy/series/series.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,4 +1,6 @@ from sympy.core.sympify import sympify + + def series(expr, x=None, x0=0, n=6, dir="+"): """Series expansion of expr around point `x = x0`. diff -Nru python3-sympy-0.7.2/sympy/series/tests/test_demidovich.py python3-sympy-0.7.3/sympy/series/tests/test_demidovich.py --- python3-sympy-0.7.2/sympy/series/tests/test_demidovich.py 2012-10-17 03:02:22.000000000 +0000 +++ python3-sympy-0.7.3/sympy/series/tests/test_demidovich.py 2013-07-13 17:53:32.000000000 +0000 @@ -6,110 +6,131 @@ x = Symbol("x") + def test_leadterm(): - assert (3+2*x**(log(3)/log(2)-1)).leadterm(x)==(3,0) + assert (3 + 2*x**(log(3)/log(2) - 1)).leadterm(x) == (3, 0) + def root3(x): return root(x, 3) + def root4(x): return root(x, 4) + def test_Limits_simple_0(): - assert limit((2**(x+1)+3**(x+1))/(2**x+3**x),x,oo)==3 #175 + assert limit((2**(x + 1) + 3**(x + 1))/(2**x + 3**x), x, oo) == 3 # 175 + def test_Limits_simple_1(): - assert limit((x+1)*(x+2)*(x+3)/x**3,x, oo)==1 #172 - assert limit(sqrt(x+1)-sqrt(x),x,oo)==0 #179 - assert limit((2*x-3)*(3*x+5)*(4*x-6)/(3*x**3+x-1),x,oo)==8 #Primjer 1 - assert limit(x/root3(x**3+10),x,oo)==1 #Primjer 2 - assert limit((x+1)**2/(x**2+1),x,oo)==1 #181 + assert limit((x + 1)*(x + 2)*(x + 3)/x**3, x, oo) == 1 # 172 + assert limit(sqrt(x + 1) - sqrt(x), x, oo) == 0 # 179 + assert limit((2*x - 3)*(3*x + 5)*(4*x - 6)/(3*x**3 + x - 1), x, oo) == 8 # Primjer 1 + assert limit(x/root3(x**3 + 10), x, oo) == 1 # Primjer 2 + assert limit((x + 1)**2/(x**2 + 1), x, oo) == 1 # 181 + def test_Limits_simple_2(): - assert limit(1000*x/(x**2-1),x,oo)==0 #182 - assert limit((x**2-5*x+1)/(3*x+7),x,oo)==oo #183 - assert limit((2*x**2-x+3)/(x**3-8*x+5),x,oo)==0 #184 - assert limit((2*x**2-3*x-4)/sqrt(x**4+1),x,oo)==2 #186 - assert limit((2*x+3)/(x+root3(x)),x,oo)==2 #187 - assert limit(x**2/(10+x*sqrt(x)),x,oo)==oo #188 - assert limit(root3(x**2+1)/(x+1),x,oo)==0 #189 - assert limit(sqrt(x)/sqrt(x+sqrt(x+sqrt(x))),x,oo)==1 #190 + assert limit(1000*x/(x**2 - 1), x, oo) == 0 # 182 + assert limit((x**2 - 5*x + 1)/(3*x + 7), x, oo) == oo # 183 + assert limit((2*x**2 - x + 3)/(x**3 - 8*x + 5), x, oo) == 0 # 184 + assert limit((2*x**2 - 3*x - 4)/sqrt(x**4 + 1), x, oo) == 2 # 186 + assert limit((2*x + 3)/(x + root3(x)), x, oo) == 2 # 187 + assert limit(x**2/(10 + x*sqrt(x)), x, oo) == oo # 188 + assert limit(root3(x**2 + 1)/(x + 1), x, oo) == 0 # 189 + assert limit(sqrt(x)/sqrt(x + sqrt(x + sqrt(x))), x, oo) == 1 # 190 + def test_Limits_simple_3a(): a = Symbol('a') #issue 414 - assert together(limit((x**2-(a+1)*x+a)/(x**3-a**3),x,a)) == \ - (a-1)/(3*a**2) #196 + assert together(limit((x**2 - (a + 1)*x + a)/(x**3 - a**3), x, a)) == \ + (a - 1)/(3*a**2) # 196 + def test_Limits_simple_3b(): h = Symbol("h") - assert limit(((x+h)**3-x**3)/h,h,0)==3*x**2 #197 - assert limit((1/(1-x)-3/(1-x**3)),x,1)==-1 #198 - assert limit((sqrt(1+x)-1)/(root3(1+x)-1),x,0)==Rational(3)/2 #Primer 4 - assert limit((sqrt(x)-1)/(x-1),x,1)==Rational(1)/2 #199 - assert limit((sqrt(x)-8)/(root3(x)-4),x,64)==3 #200 - assert limit((root3(x)-1)/(root4(x)-1),x,1)==Rational(4)/3 #201 - assert limit((root3(x**2)-2*root3(x)+1)/(x-1)**2,x,1)==Rational(1)/9 #202 + assert limit(((x + h)**3 - x**3)/h, h, 0) == 3*x**2 # 197 + assert limit((1/(1 - x) - 3/(1 - x**3)), x, 1) == -1 # 198 + assert limit((sqrt(1 + x) - 1)/(root3(1 + x) - 1), x, 0) == Rational(3)/2 # Primer 4 + assert limit((sqrt(x) - 1)/(x - 1), x, 1) == Rational(1)/2 # 199 + assert limit((sqrt(x) - 8)/(root3(x) - 4), x, 64) == 3 # 200 + assert limit((root3(x) - 1)/(root4(x) - 1), x, 1) == Rational(4)/3 # 201 + assert limit( + (root3(x**2) - 2*root3(x) + 1)/(x - 1)**2, x, 1) == Rational(1)/9 # 202 + def test_Limits_simple_4a(): a = Symbol('a') - assert limit((sqrt(x)-sqrt(a))/(x-a),x,a)==1/(2*sqrt(a)) #Primer 5 - assert limit((sqrt(x)-1)/(root3(x)-1),x,1)==Rational(3)/2 #205 - assert limit((sqrt(1+x)-sqrt(1-x))/x,x,0)==1 #207 - assert limit(sqrt(x**2-5*x+6)-x,x,oo)==-Rational(5)/2 #213 + assert limit((sqrt(x) - sqrt(a))/(x - a), x, a) == 1/(2*sqrt(a)) # Primer 5 + assert limit((sqrt(x) - 1)/(root3(x) - 1), x, 1) == Rational(3)/2 # 205 + assert limit((sqrt(1 + x) - sqrt(1 - x))/x, x, 0) == 1 # 207 + assert limit(sqrt(x**2 - 5*x + 6) - x, x, oo) == -Rational(5)/2 # 213 + def test_limits_simple_4aa(): - assert limit(x*(sqrt(x**2+1)-x),x,oo)==Rational(1)/2 #214 + assert limit(x*(sqrt(x**2 + 1) - x), x, oo) == Rational(1)/2 # 214 + def test_Limits_simple_4b(): #issue 412 - assert limit(x-root3(x**3-1),x,oo)==0 #215 + assert limit(x - root3(x**3 - 1), x, oo) == 0 # 215 + def test_Limits_simple_4c(): - assert limit(log(1+exp(x))/x,x,-oo)==0 #267a - assert limit(log(1+exp(x))/x,x,oo)==1 #267b + assert limit(log(1 + exp(x))/x, x, -oo) == 0 # 267a + assert limit(log(1 + exp(x))/x, x, oo) == 1 # 267b + def test_bounded(): - assert limit(sin(x)/x, x, oo) == 0 #216b - assert limit(x*sin(1/x), x, 0) == 0 #227a + assert limit(sin(x)/x, x, oo) == 0 # 216b + assert limit(x*sin(1/x), x, 0) == 0 # 227a + def test_f1a(): h = Symbol("h") #issue 409: - assert limit((sin(2*x)/x)**(1+x),x,0) == 2 #Primer 7 + assert limit((sin(2*x)/x)**(1 + x), x, 0) == 2 # Primer 7 + def test_f1a2(): #issue 410: - assert limit(((x-1)/(x+1))**x,x,oo) == exp(-2) #Primer 9 + assert limit(((x - 1)/(x + 1))**x, x, oo) == exp(-2) # Primer 9 + def test_f1b(): m = Symbol("m") n = Symbol("n") h = Symbol("h") a = Symbol("a") - assert limit(sin(x)/x,x,2) == sin(2)/2 #216a - assert limit(sin(3*x)/x,x,0) == 3 #217 - assert limit(sin(5*x)/sin(2*x),x,0) == Rational(5)/2 #218 - assert limit(sin(pi*x)/sin(3*pi*x),x,0) == Rational(1)/3 #219 - assert limit(x*sin(pi/x),x,oo) == pi #220 - assert limit((1-cos(x))/x**2,x,0) == Rational(1,2) #221 - assert limit(x*sin(1/x),x,oo) == 1 #227b - assert limit((cos(m*x)-cos(n*x))/x**2,x,0) == ((n**2-m**2)/2) #232 - assert limit((tan(x)-sin(x))/x**3,x,0) == Rational(1,2) #233 - assert limit((x-sin(2*x))/(x+sin(3*x)),x,0) == -Rational(1,4) #237 - assert limit((1-sqrt(cos(x)))/x**2,x,0) == Rational(1,4) #239 - assert limit((sqrt(1+sin(x))-sqrt(1-sin(x)))/x,x,0) == 1 #240 - - assert limit((1+h/x)**x,x,oo) == exp(h) #Primer 9 - assert limit((sin(x)-sin(a))/(x-a),x,a) == cos(a) #222, *176 - assert limit((cos(x)-cos(a))/(x-a),x,a) == -sin(a) #223 - assert limit((sin(x+h)-sin(x))/h,h,0) == cos(x) #225 + assert limit(sin(x)/x, x, 2) == sin(2)/2 # 216a + assert limit(sin(3*x)/x, x, 0) == 3 # 217 + assert limit(sin(5*x)/sin(2*x), x, 0) == Rational(5)/2 # 218 + assert limit(sin(pi*x)/sin(3*pi*x), x, 0) == Rational(1)/3 # 219 + assert limit(x*sin(pi/x), x, oo) == pi # 220 + assert limit((1 - cos(x))/x**2, x, 0) == Rational(1, 2) # 221 + assert limit(x*sin(1/x), x, oo) == 1 # 227b + assert limit((cos(m*x) - cos(n*x))/x**2, x, 0) == ((n**2 - m**2)/2) # 232 + assert limit((tan(x) - sin(x))/x**3, x, 0) == Rational(1, 2) # 233 + assert limit((x - sin(2*x))/(x + sin(3*x)), x, 0) == -Rational(1, 4) # 237 + assert limit((1 - sqrt(cos(x)))/x**2, x, 0) == Rational(1, 4) # 239 + assert limit((sqrt(1 + sin(x)) - sqrt(1 - sin(x)))/x, x, 0) == 1 # 240 + + assert limit((1 + h/x)**x, x, oo) == exp(h) # Primer 9 + assert limit((sin(x) - sin(a))/(x - a), x, a) == cos(a) # 222, *176 + assert limit((cos(x) - cos(a))/(x - a), x, a) == -sin(a) # 223 + assert limit((sin(x + h) - sin(x))/h, h, 0) == cos(x) # 225 + def test_f2a(): - assert limit(((x+1)/(2*x+1))**(x**2),x,oo) == 0 #Primer 8 + assert limit(((x + 1)/(2*x + 1))**(x**2), x, oo) == 0 # Primer 8 + def test_f2(): - assert limit((sqrt(cos(x))-root3(cos(x)))/(sin(x)**2),x,0) == -Rational(1,12) #*184 + assert limit((sqrt( + cos(x)) - root3(cos(x)))/(sin(x)**2), x, 0) == -Rational(1, 12) # *184 + def test_f3(): a = Symbol('a') diff -Nru python3-sympy-0.7.2/sympy/series/tests/test_gruntz.py python3-sympy-0.7.3/sympy/series/tests/test_gruntz.py --- python3-sympy-0.7.2/sympy/series/tests/test_gruntz.py 2012-10-17 03:02:22.000000000 +0000 +++ python3-sympy-0.7.3/sympy/series/tests/test_gruntz.py 2013-07-13 17:53:32.000000000 +0000 @@ -20,113 +20,122 @@ runslow = False -def sskip(): - if not runslow: skip("slow") + + +def _sskip(): + if not runslow: + skip("slow") + def test_gruntz_evaluation(): # Gruntz' thesis pp. 122 to 123 # 8.1 - assert gruntz(exp(x)*(exp(1/x-exp(-x))-exp(1/x)), x, oo) == -1 + assert gruntz(exp(x)*(exp(1/x - exp(-x)) - exp(1/x)), x, oo) == -1 # 8.2 - assert gruntz(exp(x)*(exp(1/x+exp(-x)+exp(-x**2)) \ - - exp(1/x-exp(-exp(x)))), x, oo) == 1 + assert gruntz(exp(x)*(exp(1/x + exp(-x) + exp(-x**2)) + - exp(1/x - exp(-exp(x)))), x, oo) == 1 # 8.3 - assert gruntz(exp(exp(x-exp(-x))/(1-1/x)) - exp(exp(x)), x, oo) == oo + assert gruntz(exp(exp(x - exp(-x))/(1 - 1/x)) - exp(exp(x)), x, oo) == oo # 8.5 - assert gruntz(exp(exp(exp(x+exp(-x)))) / exp(exp(exp(x))), x, oo) == oo + assert gruntz(exp(exp(exp(x + exp(-x)))) / exp(exp(exp(x))), x, oo) == oo # 8.6 - assert gruntz(exp(exp(exp(x))) / exp(exp(exp(x-exp(-exp(x))))), + assert gruntz(exp(exp(exp(x))) / exp(exp(exp(x - exp(-exp(x))))), x, oo) == oo # 8.7 - assert gruntz(exp(exp(exp(x))) / exp(exp(exp(x-exp(-exp(exp(x)))))), + assert gruntz(exp(exp(exp(x))) / exp(exp(exp(x - exp(-exp(exp(x)))))), x, oo) == 1 # 8.8 - assert gruntz(exp(exp(x)) / exp(exp(x-exp(-exp(exp(x))))), x, oo) == 1 + assert gruntz(exp(exp(x)) / exp(exp(x - exp(-exp(exp(x))))), x, oo) == 1 # 8.9 assert gruntz(log(x)**2 * exp(sqrt(log(x))*(log(log(x)))**2 * exp(sqrt(log(log(x))) * (log(log(log(x))))**3)) / sqrt(x), x, oo) == 0 # 8.10 - assert gruntz((x*log(x)*(log(x*exp(x)-x**2))**2) - / (log(log(x**2+2*exp(exp(3*x**3*log(x)))))), x, oo) == S(1)/3 + assert gruntz((x*log(x)*(log(x*exp(x) - x**2))**2) + / (log(log(x**2 + 2*exp(exp(3*x**3*log(x)))))), x, oo) == S(1)/3 # 8.11 - assert gruntz((exp(x*exp(-x)/(exp(-x)+exp(-2*x**2/(x+1)))) - exp(x))/x, + assert gruntz((exp(x*exp(-x)/(exp(-x) + exp(-2*x**2/(x + 1)))) - exp(x))/x, x, oo) == -exp(2) # 8.12 assert gruntz((3**x + 5**x)**(1/x), x, oo) == 5 # 8.13 assert gruntz(x/log(x**(log(x**(log(2)/log(x))))), x, oo) == oo # 8.14 - assert gruntz(exp(exp(2*log(x**5+x)*log(log(x)))) + assert gruntz(exp(exp(2*log(x**5 + x)*log(log(x)))) / exp(exp(10*log(x)*log(log(x)))), x, oo) == oo # 8.15 - assert gruntz(exp(exp(S(5)/2*x**(-S(5)/7)+ S(21)/8*x**(S(6)/11) - +2*x**(-8)+S(54)/17*x**(S(49)/45) ))**8 + assert gruntz(exp(exp(S(5)/2*x**(-S(5)/7) + S(21)/8*x**(S(6)/11) + + 2*x**(-8) + S(54)/17*x**(S(49)/45) ))**8 / log(log(-log(S(4)/3*x**(-S(5)/14))))**(S(7)/6), x, oo) == oo # 8.16 - assert gruntz((exp(4*x*exp(-x)/(1/exp(x)+1/exp(2*x**2/(x+1)))) - exp(x)) + assert gruntz((exp(4*x*exp(-x)/(1/exp(x) + 1/exp(2*x**2/(x + 1)))) - exp(x)) / exp(x)**4, x, oo) == 1 # 8.17 - assert gruntz(exp(x*exp(-x)/(exp(-x)+exp(-2*x**2/(x+1))))/exp(x), x, oo) \ - == 1 + assert gruntz(exp(x*exp(-x)/(exp(-x) + exp(-2*x**2/(x + 1))))/exp(x), x, oo) \ + == 1 # 8.19 - assert gruntz(log(x)*(log(log(x)+log(log(x))) - log(log(x))) - / (log(log(x)+log(log(log(x))))), x, oo) == 1 + assert gruntz(log(x)*(log(log(x) + log(log(x))) - log(log(x))) + / (log(log(x) + log(log(log(x))))), x, oo) == 1 # 8.20 - assert gruntz(exp((log(log(x+exp(log(x)*log(log(x)))))) - / (log(log(log(exp(x)+x+log(x)))))), x, oo) == E + assert gruntz(exp((log(log(x + exp(log(x)*log(log(x)))))) + / (log(log(log(exp(x) + x + log(x)))))), x, oo) == E # Another - assert gruntz(exp(exp(exp(x+exp(-x)))) / exp(exp(x)), x, oo) == oo + assert gruntz(exp(exp(exp(x + exp(-x)))) / exp(exp(x)), x, oo) == oo + def test_gruntz_evaluation_slow(): - sskip() + _sskip() # 8.4 - assert gruntz(exp(exp(exp(x)/(1-1/x))) - - exp(exp(exp(x)/(1-1/x-log(x)**(-log(x))))), x, oo) == -oo + assert gruntz(exp(exp(exp(x)/(1 - 1/x))) + - exp(exp(exp(x)/(1 - 1/x - log(x)**(-log(x))))), x, oo) == -oo # 8.18 - assert gruntz((exp(exp(-x/(1+exp(-x))))*exp(-x/(1+exp(-x/(1+exp(-x))))) - *exp(exp(-x+exp(-x/(1+exp(-x)))))) - / (exp(-x/(1+exp(-x))))**2 - exp(x) + x, x, oo) == 2 + assert gruntz((exp(exp(-x/(1 + exp(-x))))*exp(-x/(1 + exp(-x/(1 + exp(-x))))) + *exp(exp(-x + exp(-x/(1 + exp(-x)))))) + / (exp(-x/(1 + exp(-x))))**2 - exp(x) + x, x, oo) == 2 + def test_gruntz_eval_special(): # Gruntz, p. 126 - assert gruntz(exp(x)*(sin(1/x+exp(-x))-sin(1/x+exp(-x**2))), x, oo) == 1 - assert gruntz((erf(x-exp(-exp(x))) - erf(x)) * exp(exp(x)) * exp(x**2), + assert gruntz(exp(x)*(sin(1/x + exp(-x)) - sin(1/x + exp(-x**2))), x, oo) == 1 + assert gruntz((erf(x - exp(-exp(x))) - erf(x)) * exp(exp(x)) * exp(x**2), x, oo) == -2/sqrt(pi) - assert gruntz(exp(exp(x)) * (exp(sin(1/x+exp(-exp(x)))) - exp(sin(1/x))), + assert gruntz(exp(exp(x)) * (exp(sin(1/x + exp(-exp(x)))) - exp(sin(1/x))), x, oo) == 1 - assert gruntz(exp(x)*(gamma(x+exp(-x)) - gamma(x)), x, oo) == oo - assert gruntz(exp(exp(digamma(digamma(x))))/x,x,oo) == exp(-S(1)/2) - assert gruntz(exp(exp(digamma(log(x))))/x,x,oo) == exp(-S(1)/2) - assert gruntz(digamma(digamma(digamma(x))),x,oo) == oo + assert gruntz(exp(x)*(gamma(x + exp(-x)) - gamma(x)), x, oo) == oo + assert gruntz(exp(exp(digamma(digamma(x))))/x, x, oo) == exp(-S(1)/2) + assert gruntz(exp(exp(digamma(log(x))))/x, x, oo) == exp(-S(1)/2) + assert gruntz(digamma(digamma(digamma(x))), x, oo) == oo assert gruntz(loggamma(loggamma(x)), x, oo) == oo - assert gruntz(((gamma(x+1/gamma(x)) - gamma(x))/log(x) - cos(1/x)) + assert gruntz(((gamma(x + 1/gamma(x)) - gamma(x))/log(x) - cos(1/x)) * x*log(x), x, oo) == -S(1)/2 - assert gruntz(x * (gamma(x-1/gamma(x)) - gamma(x) + log(x)), x, oo) \ - == S(1)/2 - assert gruntz((gamma(x+1/gamma(x)) - gamma(x)) / log(x), x, oo) == 1 + assert gruntz(x * (gamma(x - 1/gamma(x)) - gamma(x) + log(x)), x, oo) \ + == S(1)/2 + assert gruntz((gamma(x + 1/gamma(x)) - gamma(x)) / log(x), x, oo) == 1 + def test_gruntz_eval_special_slow(): - sskip() - assert gruntz(gamma(x+1)/sqrt(2*pi) - - exp(-x)*(x**(x+S(1)/2) + x**(x-S(1)/2)/12), x, oo) == oo + _sskip() + assert gruntz(gamma(x + 1)/sqrt(2*pi) + - exp(-x)*(x**(x + S(1)/2) + x**(x - S(1)/2)/12), x, oo) == oo assert gruntz(exp(exp(exp(digamma(digamma(digamma(x))))))/x, x, oo) == 0 + @XFAIL def test_grunts_eval_special_slow_sometimes_fail(): - sskip() + _sskip() # XXX This sometimes fails!!! - assert gruntz(exp(gamma(x-exp(-x))*exp(1/x)) - exp(gamma(x)), x, oo) == oo + assert gruntz(exp(gamma(x - exp(-x))*exp(1/x)) - exp(gamma(x)), x, oo) == oo + @XFAIL def test_gruntz_eval_special_fail(): # TODO exponential integral Ei - assert gruntz((Ei(x-exp(-exp(x))) - Ei(x)) *exp(-x)*exp(exp(x))*x, - x, oo) == -1 + assert gruntz( + (Ei(x - exp(-exp(x))) - Ei(x)) *exp(-x)*exp(exp(x))*x, x, oo) == -1 # TODO zeta function series - assert gruntz(exp((log(2)+1)*x) * (zeta(x+exp(-x)) - zeta(x)), x, oo) \ - == -log(2) + assert gruntz( + exp((log(2) + 1)*x) * (zeta(x + exp(-x)) - zeta(x)), x, oo) == -log(2) # TODO 8.35 - 8.37 (bessel, max-min) @@ -135,8 +144,8 @@ assert compare(2, x, x) == "<" assert compare(x, exp(x), x) == "<" assert compare(exp(x), exp(x**2), x) == "<" - assert compare(exp(x**2),exp(exp(x)), x) == "<" - assert compare(1,exp(exp(x)), x) == "<" + assert compare(exp(x**2), exp(exp(x)), x) == "<" + assert compare(1, exp(exp(x)), x) == "<" assert compare(x, 2, x) == ">" assert compare(exp(x), x, x) == ">" @@ -157,25 +166,28 @@ assert compare(exp(x), exp(-x), x) == "=" assert compare(exp(-x), exp(2*x), x) == "=" assert compare(exp(2*x), exp(x)**2, x) == "=" - assert compare(exp(x)**2, exp(x+exp(-x)), x) == "=" - assert compare(exp(x), exp(x+exp(-x)), x) == "=" + assert compare(exp(x)**2, exp(x + exp(-x)), x) == "=" + assert compare(exp(x), exp(x + exp(-x)), x) == "=" assert compare(exp(x**2), 1/exp(x**2), x) == "=" + def test_compare2(): - assert compare(exp(x),x**5,x) == ">" - assert compare(exp(x**2),exp(x)**2,x) == ">" - assert compare(exp(x),exp(x+exp(-x)),x) == "=" - assert compare(exp(x+exp(-x)),exp(x),x) == "=" - assert compare(exp(x+exp(-x)),exp(-x),x) == "=" - assert compare(exp(-x),x,x) == ">" - assert compare(x,exp(-x),x) == "<" - assert compare(exp(x+1/x),x,x) == ">" - assert compare(exp(-exp(x)),exp(x),x) == ">" - assert compare(exp(exp(-exp(x))+x),exp(-exp(x)),x) == "<" + assert compare(exp(x), x**5, x) == ">" + assert compare(exp(x**2), exp(x)**2, x) == ">" + assert compare(exp(x), exp(x + exp(-x)), x) == "=" + assert compare(exp(x + exp(-x)), exp(x), x) == "=" + assert compare(exp(x + exp(-x)), exp(-x), x) == "=" + assert compare(exp(-x), x, x) == ">" + assert compare(x, exp(-x), x) == "<" + assert compare(exp(x + 1/x), x, x) == ">" + assert compare(exp(-exp(x)), exp(x), x) == ">" + assert compare(exp(exp(-exp(x)) + x), exp(-exp(x)), x) == "<" + def test_compare3(): - assert compare(exp(exp(x)),exp(x+exp(-exp(x))),x) == ">" + assert compare(exp(exp(x)), exp(x + exp(-exp(x))), x) == ">" + def test_sign1(): assert sign(Rational(0), x) == 0 @@ -185,11 +197,12 @@ assert sign(exp(-x), x) == 1 assert sign(exp(x), x) == 1 assert sign(-exp(x), x) == -1 - assert sign(3-1/x, x) == 1 - assert sign(-3-1/x, x) == -1 + assert sign(3 - 1/x, x) == 1 + assert sign(-3 - 1/x, x) == -1 assert sign(sin(1/x), x) == 1 assert sign((x**Integer(2)), x) == 1 + def test_sign2(): assert sign(x, x) == 1 assert sign(-x, x) == -1 @@ -199,60 +212,81 @@ assert sign(y*x, x) == 1 assert sign(-y*x, x) == -1 -def mmrv(a, b): return set(mrv(a, b)[0].keys()) + +def mmrv(a, b): + return set(mrv(a, b)[0].keys()) + def test_mrv1(): assert mmrv(x, x) == set([x]) - assert mmrv(x+1/x, x) == set([x]) + assert mmrv(x + 1/x, x) == set([x]) assert mmrv(x**2, x) == set([x]) assert mmrv(log(x), x) == set([x]) assert mmrv(exp(x), x) == set([exp(x)]) assert mmrv(exp(-x), x) == set([exp(-x)]) assert mmrv(exp(x**2), x) == set([exp(x**2)]) assert mmrv(-exp(1/x), x) == set([x]) - assert mmrv(exp(x+1/x), x) == set([exp(x+1/x)]) + assert mmrv(exp(x + 1/x), x) == set([exp(x + 1/x)]) + def test_mrv2a(): - assert mmrv(exp(x+exp(-exp(x))), x) == set([exp(-exp(x))]) - assert mmrv(exp(x+exp(-x)), x) == set([exp(x+exp(-x)), exp(-x)]) - assert mmrv(exp(1/x+exp(-x)), x) == set([exp(-x)]) + assert mmrv(exp(x + exp(-exp(x))), x) == set([exp(-exp(x))]) + assert mmrv(exp(x + exp(-x)), x) == set([exp(x + exp(-x)), exp(-x)]) + assert mmrv(exp(1/x + exp(-x)), x) == set([exp(-x)]) #sometimes infinite recursion due to log(exp(x**2)) not simplifying + + def test_mrv2b(): - assert mmrv(exp(x+exp(-x**2)), x) == set([exp(-x**2)]) + assert mmrv(exp(x + exp(-x**2)), x) == set([exp(-x**2)]) #sometimes infinite recursion due to log(exp(x**2)) not simplifying + + def test_mrv2c(): - assert mmrv(exp(-x+1/x**2)-exp(x+1/x), x) == set([exp(x+1/x), exp(1/x**2-x)]) + assert mmrv( + exp(-x + 1/x**2) - exp(x + 1/x), x) == set([exp(x + 1/x), exp(1/x**2 - x)]) #sometimes infinite recursion due to log(exp(x**2)) not simplifying + + def test_mrv3(): - assert mmrv(exp(x**2)+x*exp(x)+log(x)**x/x, x) == set([exp(x**2)]) - assert mmrv(exp(x)*(exp(1/x+exp(-x))-exp(1/x)), x) == set([exp(x), exp(-x)]) - assert mmrv(log(x**2+2*exp(exp(3*x**3*log(x)))), x) == set([exp(exp(3*x**3*log(x)))]) - assert mmrv(log(x-log(x))/log(x), x) == set([x]) - assert mmrv((exp(1/x-exp(-x))-exp(1/x))*exp(x), x) == set([exp(x), exp(-x)]) - assert mmrv(1/exp(-x+exp(-x))-exp(x), x) == set([exp(x), exp(-x), exp(x-exp(-x))]) - assert mmrv(log(log(x*exp(x*exp(x))+1)), x) == set([exp(x*exp(x))]) - assert mmrv(exp(exp(log(log(x)+1/x))), x) == set([x]) + assert mmrv(exp(x**2) + x*exp(x) + log(x)**x/x, x) == set([exp(x**2)]) + assert mmrv( + exp(x)*(exp(1/x + exp(-x)) - exp(1/x)), x) == set([exp(x), exp(-x)]) + assert mmrv(log( + x**2 + 2*exp(exp(3*x**3*log(x)))), x) == set([exp(exp(3*x**3*log(x)))]) + assert mmrv(log(x - log(x))/log(x), x) == set([x]) + assert mmrv( + (exp(1/x - exp(-x)) - exp(1/x))*exp(x), x) == set([exp(x), exp(-x)]) + assert mmrv( + 1/exp(-x + exp(-x)) - exp(x), x) == set([exp(x), exp(-x), exp(x - exp(-x))]) + assert mmrv(log(log(x*exp(x*exp(x)) + 1)), x) == set([exp(x*exp(x))]) + assert mmrv(exp(exp(log(log(x) + 1/x))), x) == set([x]) + def test_mrv4(): ln = log - assert mmrv((ln(ln(x)+ln(ln(x)))-ln(ln(x)))/ln(ln(x)+ln(ln(ln(x))))*ln(x), + assert mmrv((ln(ln(x) + ln(ln(x))) - ln(ln(x)))/ln(ln(x) + ln(ln(ln(x))))*ln(x), x) == set([x]) - assert mmrv(log(log(x*exp(x*exp(x))+1)) - exp(exp(log(log(x)+1/x))), x) == \ + assert mmrv(log(log(x*exp(x*exp(x)) + 1)) - exp(exp(log(log(x) + 1/x))), x) == \ set([exp(x*exp(x))]) -def mrewrite(a, b, c): return rewrite(a[1], a[0], b, c) + +def mrewrite(a, b, c): + return rewrite(a[1], a[0], b, c) + + def test_rewrite1(): e = exp(x) assert mrewrite(mrv(e, x), x, m) == (1/m, -x) e = exp(x**2) assert mrewrite(mrv(e, x), x, m) == (1/m, -x**2) - e = exp(x+1/x) - assert mrewrite(mrv(e, x), x, m) == (1/m, -x-1/x) - e = 1/exp(-x+exp(-x))-exp(x) - assert mrewrite(mrv(e, x), x, m) == (1/(m*exp(m))-1/m, -x) + e = exp(x + 1/x) + assert mrewrite(mrv(e, x), x, m) == (1/m, -x - 1/x) + e = 1/exp(-x + exp(-x)) - exp(x) + assert mrewrite(mrv(e, x), x, m) == (1/(m*exp(m)) - 1/m, -x) + def test_rewrite2(): e = exp(x)*log(log(exp(x))) @@ -260,25 +294,33 @@ assert mrewrite(mrv(e, x), x, m) == (1/m*log(x), -x) #sometimes infinite recursion due to log(exp(x**2)) not simplifying + + def test_rewrite3(): - e = exp(-x+1/x**2)-exp(x+1/x) + e = exp(-x + 1/x**2) - exp(x + 1/x) #both of these are correct and should be equivalent: - assert mrewrite(mrv(e, x), x, m) in [(-1/m + m*exp(1/x+1/x**2), -x-1/x), (m - 1/m*exp(1/x + x**(-2)), x**(-2) - x)] + assert mrewrite(mrv(e, x), x, m) in [(-1/m + m*exp( + 1/x + 1/x**2), -x - 1/x), (m - 1/m*exp(1/x + x**(-2)), x**(-2) - x)] + def test_mrv_leadterm1(): assert mrv_leadterm(-exp(1/x), x) == (-1, 0) - assert mrv_leadterm(1/exp(-x+exp(-x))-exp(x), x) == (-1, 0) - assert mrv_leadterm((exp(1/x-exp(-x))-exp(1/x))*exp(x), x) == (-exp(1/x), 0) + assert mrv_leadterm(1/exp(-x + exp(-x)) - exp(x), x) == (-1, 0) + assert mrv_leadterm( + (exp(1/x - exp(-x)) - exp(1/x))*exp(x), x) == (-exp(1/x), 0) + def test_mrv_leadterm2(): #Gruntz: p51, 3.25 - assert mrv_leadterm((log(exp(x)+x)-x)/log(exp(x)+log(x))*exp(x), x) == \ - (1, 0) + assert mrv_leadterm((log(exp(x) + x) - x)/log(exp(x) + log(x))*exp(x), x) == \ + (1, 0) + def test_mrv_leadterm3(): #Gruntz: p56, 3.27 - assert mmrv(exp(-x+exp(-x)*exp(-x*log(x))), x) == set([exp(-x-x*log(x))]) - assert mrv_leadterm(exp(-x+exp(-x)*exp(-x*log(x))), x) == (exp(-x), 0) + assert mmrv(exp(-x + exp(-x)*exp(-x*log(x))), x) == set([exp(-x - x*log(x))]) + assert mrv_leadterm(exp(-x + exp(-x)*exp(-x*log(x))), x) == (exp(-x), 0) + def test_limit1(): assert gruntz(x, x, oo) == oo @@ -287,44 +329,48 @@ assert gruntz(x**2, x, -oo) == oo assert gruntz(-x**2, x, oo) == -oo assert gruntz(x*log(x), x, 0, dir="+") == 0 - assert gruntz(1/x,x,oo) == 0 - assert gruntz(exp(x),x,oo) == oo - assert gruntz(-exp(x),x,oo) == -oo - assert gruntz(exp(x)/x,x,oo) == oo - assert gruntz(1/x-exp(-x),x,oo) == 0 - assert gruntz(x+1/x,x,oo) == oo + assert gruntz(1/x, x, oo) == 0 + assert gruntz(exp(x), x, oo) == oo + assert gruntz(-exp(x), x, oo) == -oo + assert gruntz(exp(x)/x, x, oo) == oo + assert gruntz(1/x - exp(-x), x, oo) == 0 + assert gruntz(x + 1/x, x, oo) == oo def test_limit2(): assert gruntz(x**x, x, 0, dir="+") == 1 - assert gruntz((exp(x)-1)/x, x, 0) == 1 - assert gruntz(1+1/x,x,oo) == 1 - assert gruntz(-exp(1/x),x,oo) == -1 - assert gruntz(x+exp(-x),x,oo) == oo - assert gruntz(x+exp(-x**2),x,oo) == oo - assert gruntz(x+exp(-exp(x)),x,oo) == oo - assert gruntz(13+1/x-exp(-x),x,oo) == 13 + assert gruntz((exp(x) - 1)/x, x, 0) == 1 + assert gruntz(1 + 1/x, x, oo) == 1 + assert gruntz(-exp(1/x), x, oo) == -1 + assert gruntz(x + exp(-x), x, oo) == oo + assert gruntz(x + exp(-x**2), x, oo) == oo + assert gruntz(x + exp(-exp(x)), x, oo) == oo + assert gruntz(13 + 1/x - exp(-x), x, oo) == 13 + def test_limit3(): a = Symbol('a') - assert gruntz(x-log(1+exp(x)), x, oo) == 0 - assert gruntz(x-log(a+exp(x)), x, oo) == 0 - assert gruntz(exp(x)/(1+exp(x)), x, oo) == 1 - assert gruntz(exp(x)/(a+exp(x)), x, oo) == 1 + assert gruntz(x - log(1 + exp(x)), x, oo) == 0 + assert gruntz(x - log(a + exp(x)), x, oo) == 0 + assert gruntz(exp(x)/(1 + exp(x)), x, oo) == 1 + assert gruntz(exp(x)/(a + exp(x)), x, oo) == 1 + def test_limit4(): #issue 364 - assert gruntz((3**x+5**x)**(1/x), x, oo) == 5 + assert gruntz((3**x + 5**x)**(1/x), x, oo) == 5 #issue 364 - assert gruntz((3**(1/x)+5**(1/x))**x, x, 0) == 5 + assert gruntz((3**(1/x) + 5**(1/x))**x, x, 0) == 5 + @XFAIL def test_MrvTestCase_page47_ex3_21(): - h = exp(-x/(1+exp(-x))) - expr = exp(h)*exp(-x/(1+h))*exp(exp(-x+h))/h**2-exp(x)+x - expected = set([1/h,exp(x),exp(x-h),exp(x/(1+h))]) + h = exp(-x/(1 + exp(-x))) + expr = exp(h)*exp(-x/(1 + h))*exp(exp(-x + h))/h**2 - exp(x) + x + expected = set([1/h, exp(x), exp(x - h), exp(x/(1 + h))]) # XXX Incorrect result - assert mrv(expr,x).difference(expected) == set() + assert mrv(expr, x).difference(expected) == set() + def test_I(): y = Symbol("y") @@ -333,26 +379,38 @@ assert gruntz(y*3*I*x, x, oo) == y*I*oo assert gruntz(y*3*sin(I)*x, x, oo) == y*I*oo + def test_issue1715(): assert gruntz((x + 1)**(1/log(x + 1)), x, oo) == E + def test_intractable(): assert gruntz(1/gamma(x), x, oo) == 0 assert gruntz(1/loggamma(x), x, oo) == 0 assert gruntz(gamma(x)/loggamma(x), x, oo) == oo assert gruntz(exp(gamma(x))/gamma(x), x, oo) == oo assert gruntz(gamma(x), x, 3) == 2 - assert gruntz(gamma(S(1)/7+1/x), x, oo) == gamma(S(1)/7) + assert gruntz(gamma(S(1)/7 + 1/x), x, oo) == gamma(S(1)/7) assert gruntz(log(x**x)/log(gamma(x)), x, oo) == 1 assert gruntz(log(gamma(gamma(x)))/exp(x), x, oo) == oo + def test_aseries_trig(): - assert cancel(gruntz(1/log(atan(x)), x, oo) \ + assert cancel(gruntz(1/log(atan(x)), x, oo) - 1/(log(pi) + log(S(1)/2))) == 0 assert gruntz(1/acot(x), x, -oo) == -oo + def test_exp_log_series(): assert gruntz(x/log(log(x*exp(x))), x, oo) == oo + def test_issue545(): - assert gruntz(((x**7+x+1)/(2**x+x**2))**(-1/x), x, oo) == 2 + assert gruntz(((x**7 + x + 1)/(2**x + x**2))**(-1/x), x, oo) == 2 + + +@XFAIL +def test_issue3744(): + n = Symbol('n', integer=True, positive=True) + r = (n + 1)*x**(n + 1)/(x**(n + 1) - 1) - x/(x - 1) + assert gruntz(r, x, 1) == n/2 diff -Nru python3-sympy-0.7.2/sympy/series/tests/test_kauers.py python3-sympy-0.7.3/sympy/series/tests/test_kauers.py --- python3-sympy-0.7.2/sympy/series/tests/test_kauers.py 2012-10-17 03:02:22.000000000 +0000 +++ python3-sympy-0.7.3/sympy/series/tests/test_kauers.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,15 +1,23 @@ from sympy.series.kauers import finite_diff -from sympy.abc import x, y, z, w, n +from sympy.series.kauers import finite_diff_kauers +from sympy.abc import x, y, z, m, n, k, w from sympy import sin, cos from sympy import pi +from sympy import Sum def test_finite_diff(): assert finite_diff(x**2 + 2*x + 1, x) == 2*x + 3 - assert finite_diff(y**3 + 2*y**2 + 3*y +5, y) == 3*y**2 + 7*y + 6 + assert finite_diff(y**3 + 2*y**2 + 3*y + 5, y) == 3*y**2 + 7*y + 6 assert finite_diff(z**2 - 2*z + 3, z) == 2*z - 1 - assert finite_diff(w**2 + 3*w -2, w) == 2*w + 4 - assert finite_diff(sin(x), x, pi/6) == -sin(x) + sin(x + pi/6) - assert finite_diff(cos(y),y, pi/3) == -cos(y) + cos(y + pi/3) - assert finite_diff(x**2 - 2*x + 3, x, 2) == 4*x + assert finite_diff(w**2 + 3*w - 2, w) == 2*w + 4 + assert finite_diff(sin(x), x, pi/6) == -sin(x) + sin(x + pi/6) + assert finite_diff(cos(y), y, pi/3) == -cos(y) + cos(y + pi/3) + assert finite_diff(x**2 - 2*x + 3, x, 2) == 4*x assert finite_diff(n**2 - 2*n + 3, n, 3) == 6*n + 3 + +def test_finite_diff_kauers(): + assert finite_diff_kauers(Sum(x**2, (x, 1, n))) == (n + 1)**2 + assert finite_diff_kauers(Sum(y, (y, 1, m))) == (m + 1) + assert finite_diff_kauers(Sum((x*y), (x, 1, m), (y, 1, n))) == (m + 1)*(n + 1) + assert finite_diff_kauers(Sum((x*y**2), (x, 1, m), (y, 1, n))) == (n + 1)**2*(m + 1) diff -Nru python3-sympy-0.7.2/sympy/series/tests/test_limits.py python3-sympy-0.7.3/sympy/series/tests/test_limits.py --- python3-sympy-0.7.2/sympy/series/tests/test_limits.py 2012-10-17 03:02:22.000000000 +0000 +++ python3-sympy-0.7.3/sympy/series/tests/test_limits.py 2013-07-13 17:53:32.000000000 +0000 @@ -8,6 +8,7 @@ from sympy.utilities.pytest import XFAIL, raises from sympy.core.compatibility import product as cartes + def test_basic1(): assert limit(x, x, oo) == oo assert limit(x, x, -oo) == -oo @@ -22,25 +23,25 @@ assert limit(1/x - exp(-x), x, oo) == 0 assert limit(x + 1/x, x, oo) == oo assert limit(x - x**2, x, oo) == -oo - assert limit((1 + x)**(1 + sqrt(2)),x,0) == 1 + assert limit((1 + x)**(1 + sqrt(2)), x, 0) == 1 assert limit((1 + x)**oo, x, 0) == oo assert limit((1 + x)**oo, x, 0, dir='-') == 0 assert limit((1 + x + y)**oo, x, 0, dir='-') == (1 + y)**(oo) assert limit(y/x/log(x), x, 0) == -y*oo assert limit(cos(x + y)/x, x, 0) == sign(cos(y))*oo - raises(NotImplementedError, lambda: limit(Sum(1/x, (x, 1, y)) - log(y), y, oo)) - assert limit(Sum(1/x, (x, 1, y)) - 1/y, y, oo) == Sum(1/x, (x, 1, oo)) + raises(NotImplementedError, lambda: limit(Sum(1/x, (x, 1, y)) - + log(y), y, oo)) + raises(NotImplementedError, lambda: limit(Sum(1/x, (x, 1, y)) - 1/y, y, oo)) assert limit(gamma(1/x + 3), x, oo) == 2 assert limit(S.NaN, x, -oo) == S.NaN assert limit(Order(2)*x, x, S.NaN) == S.NaN - assert limit(Sum(1/x, (x, 1, y)) - 1/y, y, oo) == Sum(1/x, (x, 1, oo)) assert limit(gamma(1/x + 3), x, oo) == 2 assert limit(S.NaN, x, -oo) == S.NaN assert limit(Order(2)*x, x, S.NaN) == S.NaN - assert limit(1/(x-1), x, 1, dir="+") == oo - assert limit(1/(x-1), x, 1, dir="-") == -oo - assert limit(1/(5-x)**3, x, 5, dir="+") == -oo - assert limit(1/(5-x)**3, x, 5, dir="-") == oo + assert limit(1/(x - 1), x, 1, dir="+") == oo + assert limit(1/(x - 1), x, 1, dir="-") == -oo + assert limit(1/(5 - x)**3, x, 5, dir="+") == -oo + assert limit(1/(5 - x)**3, x, 5, dir="-") == oo assert limit(1/sin(x), x, pi, dir="+") == -oo assert limit(1/sin(x), x, pi, dir="-") == oo assert limit(1/cos(x), x, pi/2, dir="+") == -oo @@ -65,9 +66,10 @@ assert limit(x**-pi, x, 0, dir='-') == zoo assert limit((1 + cos(x))**oo, x, 0) == oo + def test_basic2(): assert limit(x**x, x, 0, dir="+") == 1 - assert limit((exp(x)-1)/x, x, 0) == 1 + assert limit((exp(x) - 1)/x, x, 0) == 1 assert limit(1 + 1/x, x, oo) == 1 assert limit(-exp(1/x), x, oo) == -1 assert limit(x + exp(-x), x, oo) == oo @@ -75,24 +77,29 @@ assert limit(x + exp(-exp(x)), x, oo) == oo assert limit(13 + 1/x - exp(-x), x, oo) == 13 + def test_basic3(): assert limit(1/x, x, 0, dir="+") == oo assert limit(1/x, x, 0, dir="-") == -oo + def test_basic4(): assert limit(2*x + y*x, x, 0) == 0 - assert limit(2*x + y*x, x, 1) == 2+y + assert limit(2*x + y*x, x, 1) == 2 + y assert limit(2*x**8 + y*x**(-3), x, -2) == 512 - y/8 - assert limit(sqrt(x + 1) - sqrt(x), x, oo)==0 - assert integrate(1/(x**3+1),(x,0,oo)) == 2*pi*sqrt(3)/9 + assert limit(sqrt(x + 1) - sqrt(x), x, oo) == 0 + assert integrate(1/(x**3 + 1), (x, 0, oo)) == 2*pi*sqrt(3)/9 + def test_issue786(): - assert limit(x*y + x*z, z, 2) == x*y+2*x + assert limit(x*y + x*z, z, 2) == x*y + 2*x + def test_Limit(): assert Limit(sin(x)/x, x, 0) != 1 assert Limit(sin(x)/x, x, 0).doit() == 1 + def test_floor(): assert limit(floor(x), x, -2, "+") == -2 assert limit(floor(x), x, -2, "-") == -3 @@ -107,16 +114,18 @@ assert limit(floor(x), x, 248, "+") == 248 assert limit(floor(x), x, 248, "-") == 247 + @XFAIL def test_floor_requires_robust_assumptions(): assert limit(floor(sin(x)), x, 0, "+") == 0 assert limit(floor(sin(x)), x, 0, "-") == -1 assert limit(floor(cos(x)), x, 0, "+") == 0 assert limit(floor(cos(x)), x, 0, "-") == 0 - assert limit(floor(5+sin(x)), x, 0, "+") == 5 - assert limit(floor(5+sin(x)), x, 0, "-") == 4 - assert limit(floor(5+cos(x)), x, 0, "+") == 5 - assert limit(floor(5+cos(x)), x, 0, "-") == 5 + assert limit(floor(5 + sin(x)), x, 0, "+") == 5 + assert limit(floor(5 + sin(x)), x, 0, "-") == 4 + assert limit(floor(5 + cos(x)), x, 0, "+") == 5 + assert limit(floor(5 + cos(x)), x, 0, "-") == 5 + def test_ceiling(): assert limit(ceiling(x), x, -2, "+") == -1 @@ -132,33 +141,37 @@ assert limit(ceiling(x), x, 248, "+") == 249 assert limit(ceiling(x), x, 248, "-") == 248 + @XFAIL def test_ceiling_requires_robust_assumptions(): assert limit(ceiling(sin(x)), x, 0, "+") == 1 assert limit(ceiling(sin(x)), x, 0, "-") == 0 assert limit(ceiling(cos(x)), x, 0, "+") == 1 assert limit(ceiling(cos(x)), x, 0, "-") == 1 - assert limit(ceiling(5+sin(x)), x, 0, "+") == 6 - assert limit(ceiling(5+sin(x)), x, 0, "-") == 5 - assert limit(ceiling(5+cos(x)), x, 0, "+") == 6 - assert limit(ceiling(5+cos(x)), x, 0, "-") == 6 + assert limit(ceiling(5 + sin(x)), x, 0, "+") == 6 + assert limit(ceiling(5 + sin(x)), x, 0, "-") == 5 + assert limit(ceiling(5 + cos(x)), x, 0, "+") == 6 + assert limit(ceiling(5 + cos(x)), x, 0, "-") == 6 def test_atan(): x = Symbol("x", real=True) assert limit(atan(x)*sin(1/x), x, 0) == 0 - assert limit(atan(x) + sqrt(x+1) - sqrt(x), x, oo) == pi/2 + assert limit(atan(x) + sqrt(x + 1) - sqrt(x), x, oo) == pi/2 + def test_abs(): assert limit(abs(x), x, 0) == 0 assert limit(abs(sin(x)), x, 0) == 0 assert limit(abs(cos(x)), x, 0) == 1 - assert limit(abs(sin(x+1)), x, 0) == sin(1) + assert limit(abs(sin(x + 1)), x, 0) == sin(1) + def test_heuristic(): x = Symbol("x", real=True) assert heuristics(sin(1/x) + atan(x), x, 0, '+') == sin(oo) - assert limit(log(2+sqrt(atan(x))*sqrt(sin(1/x))), x, 0) == log(2) + assert limit(log(2 + sqrt(atan(x))*sqrt(sin(1/x))), x, 0) == log(2) + def test_issue772(): z = Symbol("z", positive=True) @@ -166,48 +179,58 @@ assert limit(f, x, oo) == 0 assert f.limit(x, oo) == 0 + def test_exponential(): n = Symbol('n') x = Symbol('x', real=True) - assert limit((1+x/n)**n,n,oo) == exp(x) - assert limit((1+x/(2*n))**n,n,oo) == exp(x/2) - assert limit((1+x/(2*n+1))**n,n,oo) == exp(x/2) - assert limit(((x-1)/(x+1))**x,x,oo) == exp(-2) + assert limit((1 + x/n)**n, n, oo) == exp(x) + assert limit((1 + x/(2*n))**n, n, oo) == exp(x/2) + assert limit((1 + x/(2*n + 1))**n, n, oo) == exp(x/2) + assert limit(((x - 1)/(x + 1))**x, x, oo) == exp(-2) + assert limit(1 + (1 + 1/x)**x, x, oo) == 1 + S.Exp1 + @XFAIL def test_exponential2(): n = Symbol('n') - assert limit((1+x/(n+sin(n)))**n,n,oo) == exp(x) + assert limit((1 + x/(n + sin(n)))**n, n, oo) == exp(x) + def test_doit(): f = Integral(2 * x, x) l = Limit(f, x, oo) assert l.doit() == oo + @XFAIL def test_doit2(): f = Integral(2 * x, x) l = Limit(f, x, oo) # limit() breaks on the contained Integral. - assert l.doit(deep = False) == l + assert l.doit(deep=False) == l + def test_bug693a(): - assert sin(sin(x+1)+1).limit(x,0) == sin(sin(1)+1) + assert sin(sin(x + 1) + 1).limit(x, 0) == sin(sin(1) + 1) + def test_issue693(): - assert limit( (1-cos(x))/x**2, x, S(1)/2) == 4 - 4*cos(S(1)/2) - assert limit(sin(sin(x+1)+1), x, 0) == sin(1 + sin(1)) - assert limit(abs(sin(x+1)+1), x, 0) == 1 + sin(1) + assert limit( (1 - cos(x))/x**2, x, S(1)/2) == 4 - 4*cos(S(1)/2) + assert limit(sin(sin(x + 1) + 1), x, 0) == sin(1 + sin(1)) + assert limit(abs(sin(x + 1) + 1), x, 0) == 1 + sin(1) + def test_issue991(): - assert limit(1/(x+3), x, 2) == S(1)/5 - assert limit(1/(x+pi), x, 2) == S(1)/(2+pi) - assert limit(log(x)/(x**2+3), x, 2) == log(2)/7 - assert limit(log(x)/(x**2+pi), x, 2) == log(2)/(4+pi) + assert limit(1/(x + 3), x, 2) == S(1)/5 + assert limit(1/(x + pi), x, 2) == S(1)/(2 + pi) + assert limit(log(x)/(x**2 + 3), x, 2) == log(2)/7 + assert limit(log(x)/(x**2 + pi), x, 2) == log(2)/(4 + pi) + def test_issue1448(): - assert limit(cot(x),x,0,dir='+') == oo - assert limit(cot(x),x,pi/2,dir='+') == 0 + assert limit(cot(x), x, 0, dir='+') == oo + assert limit(cot(x), x, pi/2, dir='+') == 0 + def test_issue2065(): assert limit(x**0.5, x, oo) == oo**0.5 == oo @@ -216,6 +239,7 @@ assert limit(x**(-0.5), x, oo) == 0 assert limit(x**(-0.5), x, 4) == S(4)**(-0.5) + def test_issue2084(): # using list(...) so py.test can recalculate values tests = list(cartes([x, -x], @@ -229,16 +253,17 @@ assert len(tests) == len(results) for i, (args, res) in enumerate(list(zip(tests, results))): y, s, e, d = args - eq=y**(s*e) + eq = y**(s*e) try: assert limit(eq, x, 0, dir=d) == res except AssertionError: - if 0: # change to 1 if you want to see the failing tests + if 0: # change to 1 if you want to see the failing tests print() print(i, res, eq, d, limit(eq, x, 0, dir=d)) else: assert None + def test_issue2085(): assert limit(sin(x)/x, x, oo) == 0 assert limit(atan(x), x, oo) == pi/2 @@ -246,9 +271,11 @@ assert limit(cos(x)/x, x, oo) == 0 assert limit(gamma(x), x, Rational(1, 2)) == sqrt(pi) + @XFAIL def test_issue2130(): - assert limit((1+y)**(1/y) - S.Exp1, y, 0) == 0 + assert limit((1 + y)**(1/y) - S.Exp1, y, 0) == 0 + def test_issue1447(): # using list(...) so py.test can recalculate values @@ -259,48 +286,55 @@ oo, -oo, 0, 0, oo, -oo, 0, 0, oo, -oo) assert len(tests) == len(results) for i, (args, res) in enumerate(list(zip(tests, results))): - f, l, d= args - eq=f(x) + f, l, d = args + eq = f(x) try: assert limit(eq, x, l, dir=d) == res except AssertionError: - if 0: # change to 1 if you want to see the failing tests + if 0: # change to 1 if you want to see the failing tests print() print(i, res, eq, l, d, limit(eq, x, l, dir=d)) else: assert None + def test_issue835(): assert limit((1 + x**log(3))**(1/x), x, 0) == 1 assert limit((5**(1/x) + 3**(1/x))**x, x, 0) == 5 + def test_calculate_series(): # needs gruntz calculate_series to go to n = 32 assert limit(x**(S(77)/3)/(1 + x**(S(77)/3)), x, oo) == 1 # needs gruntz calculate_series to go to n = 128 assert limit(x**101.1/(1 + x**101.1), x, oo) == 1 + def test_issue2856(): assert limit((x**16)/(1 + x**16), x, oo) == 1 assert limit((x**100)/(1 + x**100), x, oo) == 1 assert limit((x**1885)/(1 + x**1885), x, oo) == 1 assert limit((x**1000/((x + 1)**1000 + exp(-x))), x, oo) == 1 + def test_newissue(): assert limit(exp(1/sin(x))/exp(cot(x)), x, 0) == 1 + def test_extended_real_line(): assert limit(x - oo, x, oo) == -oo assert limit(oo - x, x, -oo) == oo - assert limit(x**2/(x-5) - oo, x, oo) == -oo - assert limit(1/(x+sin(x)) - oo, x, 0) == -oo + assert limit(x**2/(x - 5) - oo, x, oo) == -oo + assert limit(1/(x + sin(x)) - oo, x, 0) == -oo assert limit(oo/x, x, oo) == oo + @XFAIL def test_extended_real_line_fail(): assert limit(x - oo + 1/x, x, oo) == -oo assert limit(x - oo + 1/x, x, 0) == -oo + @XFAIL def test_order_oo(): from sympy import C @@ -308,22 +342,54 @@ assert C.Order(x)*oo != C.Order(1, x) assert limit(oo/(x**2 - 4), x, oo) == oo + def test_issue2337(): raises(NotImplementedError, lambda: limit(exp(x*y), x, oo)) raises(NotImplementedError, lambda: limit(exp(-x*y), x, oo)) + def test_Limit_dir(): raises(TypeError, lambda: Limit(x, x, 0, dir=0)) raises(ValueError, lambda: Limit(x, x, 0, dir='0')) + def test_polynomial(): assert limit((x + 1)**1000/((x + 1)**1000 + 1), x, oo) == 1 assert limit((x + 1)**1000/((x + 1)**1000 + 1), x, -oo) == 1 +def test_rational(): + assert limit(1/y - ( 1/(y+x) + x/(y+x)/y )/z,x,oo) == 1/y - 1/(y*z) + assert limit(1/y - ( 1/(y+x) + x/(y+x)/y )/z,x,-oo) == 1/y - 1/(y*z) + + def test_issue_2641(): assert limit(log(x)/z - log(2*x)/z, x, 0) == -log(2)/z + def test_issue_3267(): n = Symbol('n', integer=True, positive=True) r = (n + 1)*x**(n + 1)/(x**(n + 1) - 1) - x/(x - 1) assert limit(r, x, 1) == n/2 + + +def test_factorial(): + from sympy import factorial, E + f = factorial(x) + assert limit(f, x, oo) == oo + assert limit(x/f, x, oo) == 0 + # see Stirling's approximation: + # http://en.wikipedia.org/wiki/Stirling's_approximation + assert limit(f/(sqrt(2*pi*x)*(x/E)**x), x, oo) == 1 + assert limit(f, x, -oo) == factorial(-oo) + assert limit(f, x, x**2) == factorial(x**2) + assert limit(f, x, -x**2) == factorial(-x**2) + + +def test_issue_3461(): + e = 5*x**3/4 - 3*x/4 + (y*(3*x**2/2 - S(1)/2) + \ + 35*x**4/8 - 15*x**2/4 + S(3)/8)/(2*(y + 1)) + assert limit(e, y, oo) == (5*x**3 + 3*x**2 - 3*x - 1)/4 + + +def test_issue_2641(): + assert limit(log(x)*z - log(2*x)*y, x, 0) == oo*sign(y - z) diff -Nru python3-sympy-0.7.2/sympy/series/tests/test_lseries.py python3-sympy-0.7.3/sympy/series/tests/test_lseries.py --- python3-sympy-0.7.2/sympy/series/tests/test_lseries.py 2012-10-17 03:02:22.000000000 +0000 +++ python3-sympy-0.7.3/sympy/series/tests/test_lseries.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,18 +1,21 @@ from sympy import sin, cos, exp, E, S, Order from sympy.abc import x, y + def test_sin(): e = sin(x).lseries(x) assert next(e) == x assert next(e) == -x**3/6 assert next(e) == x**5/120 + def test_cos(): e = cos(x).lseries(x) assert next(e) == 1 assert next(e) == -x**2/2 assert next(e) == x**4/24 + def test_exp(): e = exp(x).lseries(x) assert next(e) == 1 @@ -20,6 +23,7 @@ assert next(e) == x**2/2 assert next(e) == x**3/6 + def test_exp2(): e = exp(cos(x)).lseries(x) assert next(e) == E @@ -27,19 +31,21 @@ assert next(e) == E*x**4/6 assert next(e) == -31*E*x**6/720 + def test_simple(): assert [t for t in x.lseries()] == [x] assert [t for t in S.One.lseries(x)] == [1] assert not (next((x/(x + y)).lseries(y))).has(Order) + def test_issue_2084(): s = (x + 1/x).lseries() assert [si for si in s] == [1/x, x] assert next((x + x**2).lseries()) == x - assert next(((1+x)**7).lseries(x)) == 1 + assert next(((1 + x)**7).lseries(x)) == 1 assert next((sin(x + y)).series(x, n=3).lseries(y)) == x # it would be nice if all terms were grouped, but in the # following case that would mean that all the terms would have # to be known since, for example, every term has a constant in it. - s = ((1+x)**7).series(x, 1, n=None) + s = ((1 + x)**7).series(x, 1, n=None) assert [next(s) for i in range(2)] == [128, -448 + 448*x] diff -Nru python3-sympy-0.7.2/sympy/series/tests/test_nseries.py python3-sympy-0.7.3/sympy/series/tests/test_nseries.py --- python3-sympy-0.7.2/sympy/series/tests/test_nseries.py 2012-10-17 03:02:22.000000000 +0000 +++ python3-sympy-0.7.3/sympy/series/tests/test_nseries.py 2013-07-13 17:53:32.000000000 +0000 @@ -6,328 +6,401 @@ from sympy.utilities.pytest import raises, XFAIL + def test_simple_1(): assert x.nseries(x, n=5) == x assert y.nseries(x, n=5) == y assert (1/(x*y)).nseries(y, n=5) == 1/(x*y) - assert Rational(3,4).nseries(x, n=5) == Rational(3,4) + assert Rational(3, 4).nseries(x, n=5) == Rational(3, 4) assert x.nseries() == x + def test_mul_0(): assert (x*ln(x)).nseries(x, n=5) == x*ln(x) + def test_mul_1(): - assert (x*ln(2+x)).nseries(x, n=4) == x*log(2) + x**2/2 - x**3/8 + x**4/24 + O(x**5) # x*log(2)+x**2/2-x**3/8+O(x**4) - assert (x*ln(1+x)).nseries(x, n=4) == x**2 - x**3/2 + x**4/3 + O(x**5) # x**2- x**3/2 + O(x**4) + assert (x*ln(2 + x)).nseries(x, n=4) == x*log(2) + x**2/2 - x**3/8 + \ + x**4/24 + O(x**5) # x*log(2)+x**2/2-x**3/8+O(x**4) + assert (x*ln(1 + x)).nseries( + x, n=4) == x**2 - x**3/2 + x**4/3 + O(x**5) # x**2- x**3/2 + O(x**4) + def test_pow_0(): assert (x**2).nseries(x, n=5) == x**2 assert (1/x).nseries(x, n=5) == 1/x assert (1/x**2).nseries(x, n=5) == 1/x**2 - assert (x**Rational(2,3)).nseries(x, n=5) == (x**Rational(2,3)) + assert (x**Rational(2, 3)).nseries(x, n=5) == (x**Rational(2, 3)) assert (sqrt(x)**3).nseries(x, n=5) == (sqrt(x)**3) + def test_pow_1(): - assert ((1+x)**2).nseries(x, n=5) == 1+2*x+x**2 + assert ((1 + x)**2).nseries(x, n=5) == 1 + 2*x + x**2 + def test_geometric_1(): - assert (1/(1-x)).nseries(x, n=5) == 1+x+x**2+x**3+x**4+O(x**5) - assert (x/(1-x)).nseries(x, n=5) == x + x**2 + x**3 + x**4 + x**5 + O(x**6) # x+x**2+x**3+x**4+O(x**5) - assert (x**3/(1-x)).nseries(x, n=5) == x**3 + x**4 + x**5 + x**6 + x**7 + O(x**8) # x**3+x**4+O(x**5) + assert (1/(1 - x)).nseries(x, n=5) == 1 + x + x**2 + x**3 + x**4 + O(x**5) + assert (x/(1 - x)).nseries(x, n=5) == x + x**2 + x**3 + x**4 + x**5 + \ + O(x**6) # x+x**2+x**3+x**4+O(x**5) + assert (x**3/(1 - x)).nseries(x, n=5) == x**3 + x**4 + x**5 + x**6 + \ + x**7 + O(x**8) # x**3+x**4+O(x**5) + def test_sqrt_1(): - assert sqrt(1+x).nseries(x, n=5) == 1+x/2-x**2/8+x**3/16-5*x**4/128+O(x**5) + assert sqrt(1 + x).nseries(x, n=5) == 1 + x/2 - x**2/8 + x**3/16 - 5*x**4/128 + O(x**5) + def test_exp_1(): - assert exp(x).nseries(x, n=5) == 1+x+x**2/2+x**3/6+x**4/24 + O(x**5) - assert exp(x).nseries(x, n=12) == 1+x+x**2/2+x**3/6+x**4/24+x**5/120+ \ - x**6/720+x**7/5040+x**8/40320+x**9/362880+x**10/3628800+ \ - x**11/39916800 + O(x**12) + assert exp(x).nseries(x, n=5) == 1 + x + x**2/2 + x**3/6 + x**4/24 + O(x**5) + assert exp(x).nseries(x, n=12) == 1 + x + x**2/2 + x**3/6 + x**4/24 + x**5/120 + \ + x**6/720 + x**7/5040 + x**8/40320 + x**9/362880 + x**10/3628800 + \ + x**11/39916800 + O(x**12) assert exp(1/x).nseries(x, n=5) == exp(1/x) - assert exp(1/(1+x)).nseries(x, n=4) == \ - (E*(1-x-13*x**3/6+3*x**2/2)).expand() + O(x**4) - assert exp(2+x).nseries(x, n=5) == \ - (exp(2)*(1+x+x**2/2+x**3/6+x**4/24)).expand() + O(x**5) + assert exp(1/(1 + x)).nseries(x, n=4) == \ + (E*(1 - x - 13*x**3/6 + 3*x**2/2)).expand() + O(x**4) + assert exp(2 + x).nseries(x, n=5) == \ + (exp(2)*(1 + x + x**2/2 + x**3/6 + x**4/24)).expand() + O(x**5) + def test_exp_sqrt_1(): - assert exp(1+sqrt(x)).nseries(x, n=3) == \ - (exp(1)*(1+sqrt(x)+x/2+sqrt(x)*x/6)).expand() + O(sqrt(x)**3) + assert exp(1 + sqrt(x)).nseries(x, n=3) == \ + (exp(1)*(1 + sqrt(x) + x/2 + sqrt(x)*x/6)).expand() + O(sqrt(x)**3) + def test_power_x_x1(): assert (exp(x*ln(x))).nseries(x, n=4) == \ - 1+x*log(x)+x**2*log(x)**2/2+x**3*log(x)**3/6 + O(x**4*log(x)**4) + 1 + x*log(x) + x**2*log(x)**2/2 + x**3*log(x)**3/6 + O(x**4*log(x)**4) + def test_power_x_x2(): assert (x**x).nseries(x, n=4) == \ - 1+x*log(x)+x**2*log(x)**2/2+x**3*log(x)**3/6 + O(x**4*log(x)**4) + 1 + x*log(x) + x**2*log(x)**2/2 + x**3*log(x)**3/6 + O(x**4*log(x)**4) + def test_log_singular1(): - assert log(1+1/x).nseries(x, n=5) == x - log(x) - x**2/2 + x**3/3 - \ - x**4/4 + O(x**5) + assert log(1 + 1/x).nseries(x, n=5) == x - log(x) - x**2/2 + x**3/3 - \ + x**4/4 + O(x**5) + def test_log_power1(): e = 1 / (1/x + x ** (log(3)/log(2))) assert e.nseries(x, n=5) == x - x**(2 + log(3)/log(2)) + O(x**5) + def test_log_series(): l = Symbol('l') - e = 1/(1-log(x)) - assert e.nseries(x, n=5, logx=l) == 1/(1-l) + e = 1/(1 - log(x)) + assert e.nseries(x, n=5, logx=l) == 1/(1 - l) + def test_log2(): e = log(-1/x) assert e.nseries(x, n=5) == -log(x) + log(-1) + def test_log3(): l = Symbol('l') e = 1/log(-1/x) assert e.nseries(x, n=4, logx=l) == 1/(-l + log(-1)) + def test_series1(): x = Symbol("x") e = sin(x) - assert e.nseries(x,0,0) != 0 - assert e.nseries(x,0,0) == O(1, x) - assert e.nseries(x,0,1) == O(x, x) - assert e.nseries(x,0,2) == x + O(x**2, x) - assert e.nseries(x,0,3) == x + O(x**3, x) - assert e.nseries(x,0,4) == x-x**3/6 + O(x**4, x) + assert e.nseries(x, 0, 0) != 0 + assert e.nseries(x, 0, 0) == O(1, x) + assert e.nseries(x, 0, 1) == O(x, x) + assert e.nseries(x, 0, 2) == x + O(x**2, x) + assert e.nseries(x, 0, 3) == x + O(x**3, x) + assert e.nseries(x, 0, 4) == x - x**3/6 + O(x**4, x) - e = (exp(x)-1)/x - assert e.nseries(x,0,3) == 1+x/2+O(x**2, x) + e = (exp(x) - 1)/x + assert e.nseries(x, 0, 3) == 1 + x/2 + O(x**2, x) + + assert x.nseries(x, 0, 2) == x - assert x.nseries(x,0,2) == x @XFAIL def test_series1_failing(): - assert x.nseries(x,0,0) == O(1, x) - assert x.nseries(x,0,1) == O(x, x) + assert x.nseries(x, 0, 0) == O(1, x) + assert x.nseries(x, 0, 1) == O(x, x) + def test_seriesbug1(): x = Symbol("x") - assert (1/x).nseries(x,0,3) == 1/x - assert (x+1/x).nseries(x,0,3) == x+1/x + assert (1/x).nseries(x, 0, 3) == 1/x + assert (x + 1/x).nseries(x, 0, 3) == x + 1/x + def test_series2x(): x = Symbol("x") - assert ((x+1)**(-2)).nseries(x,0,4) == 1-2*x+3*x**2-4*x**3+O(x**4, x) - assert ((x+1)**(-1)).nseries(x,0,4) == 1-x+x**2-x**3+O(x**4, x) - assert ((x+1)**0).nseries(x,0,3) == 1 - assert ((x+1)**1).nseries(x,0,3) == 1+x - assert ((x+1)**2).nseries(x,0,3) == 1+2*x+x**2 - assert ((x+1)**3).nseries(x,0,3) == 1 + 3*x + 3*x**2 + x**3 # 1+3*x+3*x**2+O(x**3) - - assert (1/(1+x)).nseries(x,0,4) == 1-x+x**2-x**3+O(x**4, x) - assert (x+3/(1+2*x)).nseries(x,0,4) == 3-5*x+12*x**2-24*x**3+O(x**4, x) - - assert ((1/x+1)**3).nseries(x,0,3)== 1+x**(-3)+3*x**(-2)+3/x - assert (1/(1+1/x)).nseries(x,0,4) == x-x**2+x**3-O(x**4, x) - assert (1/(1+1/x**2)).nseries(x,0,6) == x**2-x**4+O(x**6, x) + assert ((x + 1)**(-2)).nseries(x, 0, 4) == 1 - 2*x + 3*x**2 - 4*x**3 + O(x**4, x) + assert ((x + 1)**(-1)).nseries(x, 0, 4) == 1 - x + x**2 - x**3 + O(x**4, x) + assert ((x + 1)**0).nseries(x, 0, 3) == 1 + assert ((x + 1)**1).nseries(x, 0, 3) == 1 + x + assert ((x + 1)**2).nseries(x, 0, 3) == 1 + 2*x + x**2 + assert ((x + 1)**3).nseries( + x, 0, 3) == 1 + 3*x + 3*x**2 + x**3 # 1+3*x+3*x**2+O(x**3) + + assert (1/(1 + x)).nseries(x, 0, 4) == 1 - x + x**2 - x**3 + O(x**4, x) + assert (x + 3/(1 + 2*x)).nseries(x, 0, 4) == 3 - 5*x + 12*x**2 - 24*x**3 + O(x**4, x) + + assert ((1/x + 1)**3).nseries(x, 0, 3) == 1 + x**(-3) + 3*x**(-2) + 3/x + assert (1/(1 + 1/x)).nseries(x, 0, 4) == x - x**2 + x**3 - O(x**4, x) + assert (1/(1 + 1/x**2)).nseries(x, 0, 6) == x**2 - x**4 + O(x**6, x) -def test_bug2(): ### 1/log(0) * log(0) problem + +def test_bug2(): # 1/log(0) * log(0) problem w = Symbol("w") - e = (w**(-1)+w**(-log(3)*log(2)**(-1)))**(-1)*(3*w**(-log(3)*log(2)**(-1))+2*w**(-1)) + e = (w**(-1) + w**( + -log(3)*log(2)**(-1)))**(-1)*(3*w**(-log(3)*log(2)**(-1)) + 2*w**(-1)) e = e.expand() assert e.nseries(w, 0, 4).subs(w, 0) == 3 + def test_exp(): x = Symbol("x") - e = (1+x)**(1/x) + e = (1 + x)**(1/x) assert e.nseries(x, n=3) == exp(1) - x*exp(1)/2 + O(x**2, x) + def test_exp2(): x = Symbol("x") w = Symbol("w") - e = w**(1-log(x)/(log(2) + log(x))) + e = w**(1 - log(x)/(log(2) + log(x))) logw = Symbol("logw") - assert e.nseries(w,0,1,logx=logw) == exp(logw - logw*log(x)/(log(2) + log(x))) + assert e.nseries( + w, 0, 1, logx=logw) == exp(logw - logw*log(x)/(log(2) + log(x))) + def test_bug3(): x = Symbol("x") - e = (2/x+3/x**2)/(1/x+1/x**2) + e = (2/x + 3/x**2)/(1/x + 1/x**2) assert e.nseries(x, n=3) == 3 + O(x) + def test_generalexponent(): x = Symbol("x") p = 2 - e = (2/x+3/x**p)/(1/x+1/x**p) - assert e.nseries(x,0,3) == 3 + O(x) - p = Rational(1,2) - e = (2/x+3/x**p)/(1/x+1/x**p) - assert e.nseries(x,0,2) == 2 + sqrt(x) + O(x) + e = (2/x + 3/x**p)/(1/x + 1/x**p) + assert e.nseries(x, 0, 3) == 3 + O(x) + p = Rational(1, 2) + e = (2/x + 3/x**p)/(1/x + 1/x**p) + assert e.nseries(x, 0, 2) == 2 + sqrt(x) + O(x) - e=1+sqrt(x) - assert e.nseries(x,0,4) == 1+sqrt(x) + e = 1 + sqrt(x) + assert e.nseries(x, 0, 4) == 1 + sqrt(x) # more complicated example + + def test_genexp_x(): x = Symbol("x") - e=1/(1+sqrt(x)) - assert e.nseries(x,0,2) == \ - 1+x-sqrt(x)-sqrt(x)**3+O(x**2, x) + e = 1/(1 + sqrt(x)) + assert e.nseries(x, 0, 2) == \ + 1 + x - sqrt(x) - sqrt(x)**3 + O(x**2, x) # more complicated example + + def test_genexp_x2(): x = Symbol("x") - p = Rational(3,2) - e = (2/x+3/x**p)/(1/x+1/x**p) - assert e.nseries(x,0,3) == 3 - sqrt(x) + x + O(sqrt(x)**3) + p = Rational(3, 2) + e = (2/x + 3/x**p)/(1/x + 1/x**p) + assert e.nseries(x, 0, 3) == 3 - sqrt(x) + x + O(sqrt(x)**3) + def test_seriesbug2(): w = Symbol("w") #simple case (1): - e = ((2*w)/w)**(1+w) - assert e.nseries(w,0,1) == 2 + O(w, w) - assert e.nseries(w,0,1).subs(w,0) == 2 + e = ((2*w)/w)**(1 + w) + assert e.nseries(w, 0, 1) == 2 + O(w, w) + assert e.nseries(w, 0, 1).subs(w, 0) == 2 + def test_seriesbug2b(): w = Symbol("w") #test sin e = sin(2*w)/w - assert e.nseries(w,0,3) == 2 + O(w**2, w) + assert e.nseries(w, 0, 3) == 2 + O(w**2, w) + def test_seriesbug2d(): w = Symbol("w", real=True) e = log(sin(2*w)/w) assert e.series(w, n=5) == log(2) - 2*w**2/3 - 4*w**4/45 + O(w**5) + def test_seriesbug2c(): w = Symbol("w", real=True) #more complicated case, but sin(x)~x, so the result is the same as in (1) - e=(sin(2*w)/w)**(1+w) - assert e.series(w,0,1) == 2 + O(w) - assert e.series(w,0,3) == 2 + 2*w*log(2) + w**2*(-Rational(4,3) + log(2)**2) + O(w**3) - assert e.series(w,0,2).subs(w,0) == 2 + e = (sin(2*w)/w)**(1 + w) + assert e.series(w, 0, 1) == 2 + O(w) + assert e.series(w, 0, 3) == 2 + 2*w*log(2) + \ + w**2*(-Rational(4, 3) + log(2)**2) + O(w**3) + assert e.series(w, 0, 2).subs(w, 0) == 2 + def test_expbug4(): x = Symbol("x", real=True) - assert (log(sin(2*x)/x)*(1+x)).series(x,0,2) == log(2) + x*log(2) + O(x**2, x) - assert exp(log(sin(2*x)/x)*(1+x)).series(x,0,2) == 2 + 2*x*log(2) + O(x**2) + assert (log( + sin(2*x)/x)*(1 + x)).series(x, 0, 2) == log(2) + x*log(2) + O(x**2, x) + assert exp( + log(sin(2*x)/x)*(1 + x)).series(x, 0, 2) == 2 + 2*x*log(2) + O(x**2) + @XFAIL def test_expbug4_failing(): x = Symbol("x", real=True) - assert exp(log(2)+O(x)).nseries(x,0,2) == 2 +O(x**2, x) - assert ((2+O(x))**(1+x)).nseries(x,0,2) == 2 + O(x**2, x) + assert exp(log(2) + O(x)).nseries(x, 0, 2) == 2 + O(x**2, x) + assert ((2 + O(x))**(1 + x)).nseries(x, 0, 2) == 2 + O(x**2, x) + def test_logbug4(): x = Symbol("x") - assert log(2+O(x)).nseries(x,0,2) == log(2) + O(x, x) + assert log(2 + O(x)).nseries(x, 0, 2) == log(2) + O(x, x) + def test_expbug5(): x = Symbol("x") - assert exp(log(1+x)/x).nseries(x, n=3) == exp(1) + -exp(1)*x/2 + O(x**2) + assert exp(log(1 + x)/x).nseries(x, n=3) == exp(1) + -exp(1)*x/2 + O(x**2) + @XFAIL def test_expbug5_failing(): - assert exp(O(x)).nseries(x,0,2) == 1 + O(x**2, x) + assert exp(O(x)).nseries(x, 0, 2) == 1 + O(x**2, x) + def test_sinsinbug(): x = Symbol("x") - assert sin(sin(x)).nseries(x,0,8) == x-x**3/3+x**5/10-8*x**7/315+O(x**8) + assert sin(sin(x)).nseries(x, 0, 8) == x - x**3/3 + x**5/10 - 8*x**7/315 + O(x**8) + def test_issue159(): x = Symbol("x") - a=x/(exp(x)-1) - assert a.nseries(x,0,6) == 1 - x/2 - x**4/720 + x**2/12 + O(x**5) + a = x/(exp(x) - 1) + assert a.nseries(x, 0, 6) == 1 - x/2 - x**4/720 + x**2/12 + O(x**5) + def test_issue105(): x = Symbol("x", nonnegative=True) - f = sin(x**3)**Rational(1,3) - assert f.nseries(x,0,17) == x - x**7/18 - x**13/3240 + O(x**17) + f = sin(x**3)**Rational(1, 3) + assert f.nseries(x, 0, 17) == x - x**7/18 - x**13/3240 + O(x**17) + def test_issue125(): y = Symbol("y") - f = sqrt(1-sqrt(y)) - assert f.nseries(y,0,2) == 1 - sqrt(y)/2-y/8-sqrt(y)**3/16+O(y**2) + f = sqrt(1 - sqrt(y)) + assert f.nseries(y, 0, 2) == 1 - sqrt(y)/2 - y/8 - sqrt(y)**3/16 + O(y**2) + def test_issue364(): from sympy import summation, symbols - w,x,i = symbols('w,x,i') + w, x, i = symbols('w,x,i') r = log(5)/log(3) p = w**(-1 + r) e = 1/x*(-log(w**(1 + r)) + log(w + w**r)) e_ser = -r*log(w)/x + p/x - p**2/(2*x) + O(p**3) assert e.nseries(w, n=3) == e_ser + def test_sin(): x = Symbol("x") y = Symbol("y") assert sin(8*x).nseries(x, n=4) == 8*x - 256*x**3/3 + O(x**4) - assert sin(x+y).nseries(x, n=1) == sin(y) + O(x) - assert sin(x+y).nseries(x, n=2) == sin(y) + cos(y)*x + O(x**2) - assert sin(x+y).nseries(x, n=5) == sin(y) + cos(y)*x - sin(y)*x**2/2 - \ + assert sin(x + y).nseries(x, n=1) == sin(y) + O(x) + assert sin(x + y).nseries(x, n=2) == sin(y) + cos(y)*x + O(x**2) + assert sin(x + y).nseries(x, n=5) == sin(y) + cos(y)*x - sin(y)*x**2/2 - \ cos(y)*x**3/6 + sin(y)*x**4/24 + O(x**5) + def test_issue416(): x = Symbol("x") e = sin(8*x)/x assert e.nseries(x, n=6) == 8 - 256*x**2/3 + 4096*x**4/15 + O(x**5) + def test_issue406(): x = Symbol("x") - e = sin(x)**(-4)*(sqrt(cos(x))*sin(x)**2 - \ - cos(x)**Rational(1,3)*sin(x)**2) + e = sin(x)**(-4)*(sqrt(cos(x))*sin(x)**2 - + cos(x)**Rational(1, 3)*sin(x)**2) assert e.nseries(x, n=8) == -Rational(1)/12 - 7*x**2/288 - \ - 43*x**4/10368 + O(x**5) + 43*x**4/10368 + O(x**5) + def test_issue402(): x = Symbol("x") a = Symbol("a") e = x**(-2)*(x*sin(a + x) - x*sin(a)) assert e.nseries(x, n=5) == cos(a) - sin(a)*x/2 - cos(a)*x**2/6 + \ - sin(a)*x**3/24 + O(x**4) + sin(a)*x**3/24 + O(x**4) e = x**(-2)*(x*cos(a + x) - x*cos(a)) assert e.nseries(x, n=5) == -sin(a) - cos(a)*x/2 + sin(a)*x**2/6 + \ - cos(a)*x**3/24 + O(x**4) + cos(a)*x**3/24 + O(x**4) + def test_issue403(): x = Symbol("x") e = sin(5*x)/sin(2*x) - assert e.nseries(x, n=2) == Rational(5,2) + O(x) - assert e.nseries(x, n=6) == Rational(5,2) - 35*x**2/4 + 329*x**4/48 + O(x**5) + assert e.nseries(x, n=2) == Rational(5, 2) + O(x) + assert e.nseries(x, n=6) == \ + Rational(5, 2) - 35*x**2/4 + 329*x**4/48 + O(x**5) + def test_issue404(): x = Symbol("x") e = sin(2 + x)/(2 + x) assert e.nseries(x, n=2) == sin(2)/2 + x*cos(2)/2 - x*sin(2)/4 + O(x**2) + def test_issue407(): x = Symbol("x") e = (x + sin(3*x))**(-2)*(x*(x + sin(3*x)) - (x + sin(3*x))*sin(2*x)) - assert e.nseries(x, n=6) == -Rational(1,4) + 5*x**2/96 + 91*x**4/768 + O(x**5) + assert e.nseries(x, n=6) == \ + -Rational(1, 4) + 5*x**2/96 + 91*x**4/768 + O(x**5) + def test_issue409(): x = Symbol("x", real=True) assert log(sin(x)).series(x, n=5) == log(x) - x**2/6 - x**4/180 + O(x**5) e = -log(x) + x*(-log(x) + log(sin(2*x))) + log(sin(2*x)) - assert e.series(x, n=5) == log(2)+log(2)*x-2*x**2/3-2*x**3/3-4*x**4/45+O(x**5) + assert e.series(x, n=5) == \ + log(2) + log(2)*x - 2*x**2/3 - 2*x**3/3 - 4*x**4/45 + O(x**5) + def test_issue408(): x = Symbol("x") e = x**(-4)*(x**2 - x**2*sqrt(cos(x))) - assert e.nseries(x, n=7) == Rational(1,4) + x**2/96 + 19*x**4/5760 + O(x**5) + assert e.nseries(x, n=7) == \ + Rational(1, 4) + x**2/96 + 19*x**4/5760 + O(x**5) + def test_issue540(): x = Symbol("x") - assert sin(cos(x)).nseries(x, n=5) == sin(1) -x**2*cos(1)/2 - x**4*sin(1)/8 + x**4*cos(1)/24 + O(x**5) + assert sin(cos(x)).nseries(x, n=5) == \ + sin(1) - x**2*cos(1)/2 - x**4*sin(1)/8 + x**4*cos(1)/24 + O(x**5) + def test_hyperbolic(): x = Symbol("x") assert sinh(x).nseries(x, n=6) == x + x**3/6 + x**5/120 + O(x**6) assert cosh(x).nseries(x, n=5) == 1 + x**2/2 + x**4/24 + O(x**5) assert tanh(x).nseries(x, n=6) == x - x**3/3 + 2*x**5/15 + O(x**6) - assert coth(x).nseries(x, n=6) == 1/x - x**3/45 + x/3 + 2*x**5/945 + O(x**6) + assert coth(x).nseries(x, n=6) == \ + 1/x - x**3/45 + x/3 + 2*x**5/945 + O(x**6) assert asinh(x).nseries(x, n=6) == x - x**3/6 + 3*x**5/40 + O(x**6) - assert acosh(x).nseries(x, n=6) == pi*I/2 - I*x - 3*I*x**5/40 - I*x**3/6 + O(x**6) + assert acosh(x).nseries(x, n=6) == \ + pi*I/2 - I*x - 3*I*x**5/40 - I*x**3/6 + O(x**6) assert atanh(x).nseries(x, n=6) == x + x**3/3 + x**5/5 + O(x**6) assert acoth(x).nseries(x, n=6) == x + x**3/3 + x**5/5 + pi*I/2 + O(x**6) + def test_series2(): w = Symbol("w", real=True) x = Symbol("x", real=True) - e = w**(-2)*(w*exp(1/x - w) - w*exp(1/x)) - assert e.nseries(w, n=3) == -exp(1/x) + w * exp(1/x) / 2 + O(w**2) + e = w**(-2)*(w*exp(1/x - w) - w*exp(1/x)) + assert e.nseries(w, n=3) == -exp(1/x) + w * exp(1/x) / 2 + O(w**2) + def test_series3(): w = Symbol("w", real=True) @@ -335,22 +408,25 @@ e = w**(-6)*(w**3*tan(w) - w**3*sin(w)) assert e.nseries(w, n=5) == Integer(1)/2 + O(w**2) + def test_bug4(): w = Symbol("w") x = Symbol("x") e = x/(w**4 + x**2*w**4 + 2*x*w**4)*w**4 - assert e.nseries(w, n=2) in [x/(1 + 2*x + x**2), 1/(1+x/2+1/x/2)/2, 1/x/(1 + 2/x + x**(-2))] + assert e.nseries(w, n=2) in [x/(1 + 2*x + x**2), + 1/(1 + x/2 + 1/x/2)/2, 1/x/(1 + 2/x + x**(-2))] + def test_bug5(): w = Symbol("w") x = Symbol("x") l = Symbol('l') - e = (-log(w) + log(1 + w*log(x)))**(-2)*w**(-2)*((-log(w) + log(1 + \ - x*w))*(-log(w) + log(1 + w*log(x)))*w - x*(-log(w) + log(1 + \ - w*log(x)))*w) + e = (-log(w) + log(1 + w*log(x)))**(-2)*w**(-2)*((-log(w) + + log(1 + x*w))*(-log(w) + log(1 + w*log(x)))*w - x*(-log(w) + + log(1 + w*log(x)))*w) assert e.nseries(w, n=1, logx=l) == x/w/l + 1/w + O(1, w) - assert e.nseries(w, n=2, logx=l) == x/w/l + 1/w - x/l + 1/l*log(x)\ - + x*log(x)/l**2 + O(w) + assert e.nseries(w, n=2, logx=l) == x/w/l + 1/w - x/l + 1/l*log(x) \ + + x*log(x)/l**2 + O(w) def test_issue1016(): @@ -358,20 +434,23 @@ assert ( sin(x)/(1 - cos(x)) ).nseries(x, n=2) == O(1/x) assert ( sin(x)**2/(1 - cos(x)) ).nseries(x, n=2) == O(1, x) + def test_pole(): x = Symbol("x") raises(PoleError, lambda: sin(1/x).series(x, 0, 5)) - raises(PoleError, lambda: sin(1+1/x).series(x, 0, 5)) + raises(PoleError, lambda: sin(1 + 1/x).series(x, 0, 5)) raises(PoleError, lambda: (x*sin(1/x)).series(x, 0, 5)) + def test_expsinbug(): x = Symbol("x") assert exp(sin(x)).series(x, 0, 0) == O(1, x) - assert exp(sin(x)).series(x, 0, 1) == 1+O(x) - assert exp(sin(x)).series(x, 0, 2) == 1+x+O(x**2) - assert exp(sin(x)).series(x, 0, 3) == 1+x+x**2/2+O(x**3) - assert exp(sin(x)).series(x, 0, 4) == 1+x+x**2/2+O(x**4) - assert exp(sin(x)).series(x, 0, 5) == 1+x+x**2/2-x**4/8+O(x**5) + assert exp(sin(x)).series(x, 0, 1) == 1 + O(x) + assert exp(sin(x)).series(x, 0, 2) == 1 + x + O(x**2) + assert exp(sin(x)).series(x, 0, 3) == 1 + x + x**2/2 + O(x**3) + assert exp(sin(x)).series(x, 0, 4) == 1 + x + x**2/2 + O(x**4) + assert exp(sin(x)).series(x, 0, 5) == 1 + x + x**2/2 - x**4/8 + O(x**5) + def test_floor(): x = Symbol('x') @@ -383,14 +462,15 @@ assert floor(-x**3).series(x) == -1 assert floor(cos(x)).series(x) == 0 assert floor(cos(-x)).series(x) == 0 - assert floor(5+sin(x)).series(x) == 5 - assert floor(5+sin(-x)).series(x) == 4 + assert floor(5 + sin(x)).series(x) == 5 + assert floor(5 + sin(-x)).series(x) == 4 assert floor(x).series(x, 2) == 2 assert floor(-x).series(x, 2) == -3 x = Symbol('x', negative=True) - assert floor(x+1.5).series(x) == 1 + assert floor(x + 1.5).series(x) == 1 + def test_ceiling(): x = Symbol('x') @@ -398,58 +478,65 @@ assert ceiling(-x).series(x) == 0 assert ceiling(sin(x)).series(x) == 1 assert ceiling(sin(-x)).series(x) == 0 - assert ceiling(1-cos(x)).series(x) == 1 - assert ceiling(1-cos(-x)).series(x) == 1 + assert ceiling(1 - cos(x)).series(x) == 1 + assert ceiling(1 - cos(-x)).series(x) == 1 assert ceiling(x).series(x, 2) == 3 assert ceiling(-x).series(x, 2) == -2 + def test_abs(): x = Symbol('x') a = Symbol('a') assert abs(x).nseries(x, n=4) == x assert abs(-x).nseries(x, n=4) == x - assert abs(x+1).nseries(x, n=4) == x+1 + assert abs(x + 1).nseries(x, n=4) == x + 1 assert abs(sin(x)).nseries(x, n=4) == x - Rational(1, 6)*x**3 + O(x**4) assert abs(sin(-x)).nseries(x, n=4) == x - Rational(1, 6)*x**3 + O(x**4) assert abs(x - a).nseries(x, 1) == Piecewise((x - 1, Eq(1 - a, 0)), ((x - a)*sign(1 - a), True)) + def test_dir(): x = Symbol('x') y = Symbol('y') assert abs(x).series(x, 0, dir="+") == x assert abs(x).series(x, 0, dir="-") == -x - assert floor(x+2).series(x,0,dir='+') == 2 - assert floor(x+2).series(x,0,dir='-') == 1 - assert floor(x+2.2).series(x,0,dir='-') == 2 - assert ceiling(x+2.2).series(x,0,dir='-') == 3 - assert sin(x+y).series(x,0,dir='-') == sin(x+y).series(x,0,dir='+') + assert floor(x + 2).series(x, 0, dir='+') == 2 + assert floor(x + 2).series(x, 0, dir='-') == 1 + assert floor(x + 2.2).series(x, 0, dir='-') == 2 + assert ceiling(x + 2.2).series(x, 0, dir='-') == 3 + assert sin(x + y).series(x, 0, dir='-') == sin(x + y).series(x, 0, dir='+') + def test_issue405(): a = Symbol("a") e = asin(a*x)/x - assert e.series(x, 4, n=2).removeO().subs(x, x - 4) == (x - 4)*(a/(4*sqrt(-16*a**2 + 1)) \ - - asin(4*a)/16) + asin(4*a)/4 + assert e.series(x, 4, n=2).removeO().subs(x, x - 4) == \ + (x - 4)*(a/(4*sqrt(-16*a**2 + 1)) - asin(4*a)/16) + asin(4*a)/4 + def test_issue1342(): x, a, b = symbols('x,a,b') - f = 1/(1+a*x) + f = 1/(1 + a*x) assert f.series(x, 0, 5) == 1 - a*x + a**2*x**2 - a**3*x**3 + \ - a**4*x**4 + O(x**5) - f = 1/(1+(a+b)*x) - assert f.series(x, 0, 3) == 1 + x*(-a - b) + x**2*(a**2 + 2*a*b + b**2) + O(x**3) + a**4*x**4 + O(x**5) + f = 1/(1 + (a + b)*x) + assert f.series(x, 0, 3) == 1 + x*(-a - b) + \ + x**2*(a**2 + 2*a*b + b**2) + O(x**3) + def test_issue1230(): assert tan(x).series(x, pi/2, n=3).removeO().subs(x, x - pi/2) == \ - -pi/6 + x/3 - 1/(x - pi/2) + -pi/6 + x/3 - 1/(x - pi/2) assert cot(x).series(x, pi, n=3).removeO().subs(x, x - pi) == \ - -x/3 + pi/3 + 1/(x - pi) + -x/3 + pi/3 + 1/(x - pi) assert limit(tan(x)**tan(2*x), x, pi/4) == exp(-1) + def test_issue2084(): assert abs(x + x**2).series(n=1) == O(x) assert abs(x + x**2).series(n=2) == x + O(x**2) - assert ((1+x)**2).series(x, n=6) == 1 + 2*x + x**2 + assert ((1 + x)**2).series(x, n=6) == 1 + 2*x + x**2 assert (1 + 1/x).series() == 1 + 1/x assert Derivative(exp(x).series(), x).doit() == \ - 1 + x + x**2/2 + x**3/6 + x**4/24 + O(x**5) + 1 + x + x**2/2 + x**3/6 + x**4/24 + O(x**5) diff -Nru python3-sympy-0.7.2/sympy/series/tests/test_order.py python3-sympy-0.7.3/sympy/series/tests/test_order.py --- python3-sympy-0.7.2/sympy/series/tests/test_order.py 2012-10-17 03:02:22.000000000 +0000 +++ python3-sympy-0.7.3/sympy/series/tests/test_order.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,72 +1,100 @@ -from sympy import (Symbol, Rational, Order, C, exp, ln, log, O, var, nan, pi, - S, Integral, sin) +from sympy import (Symbol, Rational, Order, exp, ln, log, O, nan, pi, I, + S, Integral, sin, sqrt, conjugate, expand, transpose, symbols, Function) from sympy.utilities.pytest import XFAIL, raises from sympy.abc import w, x, y, z + def test_caching_bug(): #needs to be a first test, so that all caches are clean #cache it e = O(w) #and test that this won't raise an exception - f = O(w**(-1/x/log(3)*log(5)), w) + O(w**(-1/x/log(3)*log(5)), w) + def test_simple_1(): o = Rational(0) assert Order(2*x) == Order(x) assert Order(x)*3 == Order(x) assert -28*Order(x) == Order(x) + assert Order(Order(x)) == Order(x) + assert Order(Order(x), y) == Order(Order(x), x, y) assert Order(-23) == Order(1) - assert Order(exp(x)) == Order(1,x) + assert Order(exp(x)) == Order(1, x) assert Order(exp(1/x)).expr == exp(1/x) assert Order(x*exp(1/x)).expr == x*exp(1/x) assert Order(x**(o/3)).expr == x**(o/3) assert Order(x**(5*o/3)).expr == x**(5*o/3) assert Order(x**2 + x + y, x) == O(1, x) assert Order(x**2 + x + y, y) == O(1, y) + assert Order(exp(x), x, x) == Order(1, x) raises(NotImplementedError, lambda: Order(x, 2 - x)) + def test_simple_2(): assert Order(2*x)*x == Order(x**2) - assert Order(2*x)/x == Order(1,x) + assert Order(2*x)/x == Order(1, x) assert Order(2*x)*x*exp(1/x) == Order(x**2*exp(1/x)) assert (Order(2*x)*x*exp(1/x)/ln(x)**3).expr == x**2*exp(1/x)*ln(x)**-3 + def test_simple_3(): - assert Order(x)+x == Order(x) - assert Order(x)+2 == 2+Order(x) - assert Order(x)+x**2 == Order(x) - assert Order(x)+1/x == 1/x+Order(x) - assert Order(1/x)+1/x**2 == 1/x**2+Order(1/x) - assert Order(x)+exp(1/x) == Order(x)+exp(1/x) + assert Order(x) + x == Order(x) + assert Order(x) + 2 == 2 + Order(x) + assert Order(x) + x**2 == Order(x) + assert Order(x) + 1/x == 1/x + Order(x) + assert Order(1/x) + 1/x**2 == 1/x**2 + Order(1/x) + assert Order(x) + exp(1/x) == Order(x) + exp(1/x) + def test_simple_4(): assert Order(x)**2 == Order(x**2) assert Order(x**3)**-2 == Order(x**-6) + def test_simple_5(): - assert Order(x)+Order(x**2) == Order(x) - assert Order(x)+Order(x**-2) == Order(x**-2) - assert Order(x)+Order(1/x) == Order(1/x) + assert Order(x) + Order(x**2) == Order(x) + assert Order(x) + Order(x**-2) == Order(x**-2) + assert Order(x) + Order(1/x) == Order(1/x) + def test_simple_6(): - assert Order(x)-Order(x) == Order(x) - assert Order(x)+Order(1) == Order(1) - assert Order(x)+Order(x**2) == Order(x) - assert Order(1/x)+Order(1) == Order(1/x) - assert Order(x)+Order(exp(1/x)) == Order(exp(1/x)) - assert Order(x**3)+Order(exp(2/x)) == Order(exp(2/x)) - assert Order(x**-3)+Order(exp(2/x)) == Order(exp(2/x)) + assert Order(x) - Order(x) == Order(x) + assert Order(x) + Order(1) == Order(1) + assert Order(x) + Order(x**2) == Order(x) + assert Order(1/x) + Order(1) == Order(1/x) + assert Order(x) + Order(exp(1/x)) == Order(exp(1/x)) + assert Order(x**3) + Order(exp(2/x)) == Order(exp(2/x)) + assert Order(x**-3) + Order(exp(2/x)) == Order(exp(2/x)) + def test_simple_7(): - assert 1+O(1) == O(1) - assert 2+O(1) == O(1) - assert x+O(1) == O(1) - assert 1/x+O(1) == 1/x+O(1) + assert 1 + O(1) == O(1) + assert 2 + O(1) == O(1) + assert x + O(1) == O(1) + assert 1/x + O(1) == 1/x + O(1) + + +def test_simple_8(): + assert O(sqrt(-x)) == O(sqrt(x)) + assert O(x**2*sqrt(x)) == O(x**(S(5)/2)) + assert O(x**3*sqrt(-(-x)**3)) == O(x**(S(9)/2)) + assert O(x**(S(3)/2)*sqrt((-x)**3)) == O(x**3) + assert O(x*(-2*x)**(I/2)) == O(x*(-x)**(I/2)) + + +def test_as_expr_variables(): + assert Order(x).as_expr_variables(None) == (x, (x,)) + assert Order(x).as_expr_variables((x,)) == (x, (x,)) + assert Order(y).as_expr_variables((x,)) == (y, (x, y)) + assert Order(y).as_expr_variables((x, y)) == (y, (x, y)) + def test_contains_0(): - assert Order(1,x).contains(Order(1,x)) - assert Order(1,x).contains(Order(1)) - assert Order(1).contains(Order(1,x)) + assert Order(1, x).contains(Order(1, x)) + assert Order(1, x).contains(Order(1)) + assert Order(1).contains(Order(1, x)) + def test_contains_1(): assert Order(x).contains(Order(x)) @@ -82,6 +110,7 @@ assert Order(exp(2/x)).contains(Order(exp(1/x))) assert not Order(exp(1/x)).contains(Order(exp(2/x))) + def test_contains_2(): assert Order(x).contains(Order(y)) is None assert Order(x).contains(Order(y*x)) @@ -89,60 +118,70 @@ assert Order(y).contains(Order(x*y)) assert Order(x).contains(Order(y**2*x)) + def test_contains_3(): assert Order(x*y**2).contains(Order(x**2*y)) is None assert Order(x**2*y).contains(Order(x*y**2)) is None + def test_add_1(): - assert Order(x+x) == Order(x) - assert Order(3*x-2*x**2) == Order(x) - assert Order(1+x) == Order(1,x) - assert Order(1+1/x) == Order(1/x) - assert Order(ln(x)+1/ln(x)) == Order(ln(x)) - assert Order(exp(1/x)+x) == Order(exp(1/x)) - assert Order(exp(1/x)+1/x**20) == Order(exp(1/x)) + assert Order(x + x) == Order(x) + assert Order(3*x - 2*x**2) == Order(x) + assert Order(1 + x) == Order(1, x) + assert Order(1 + 1/x) == Order(1/x) + assert Order(ln(x) + 1/ln(x)) == Order(ln(x)) + assert Order(exp(1/x) + x) == Order(exp(1/x)) + assert Order(exp(1/x) + 1/x**20) == Order(exp(1/x)) + def test_ln_args(): assert O(log(x)) + O(log(2*x)) == O(log(x)) assert O(log(x)) + O(log(x**3)) == O(log(x)) - assert O(log(x*y)) + O(log(x)+log(y)) == O(log(x*y)) + assert O(log(x*y)) + O(log(x) + log(y)) == O(log(x*y)) + def test_multivar_0(): assert Order(x*y).expr == x*y assert Order(x*y**2).expr == x*y**2 - assert Order(x*y,x).expr == x - assert Order(x*y**2,y).expr == y**2 + assert Order(x*y, x).expr == x + assert Order(x*y**2, y).expr == y**2 assert Order(x*y*z).expr == x*y*z assert Order(x/y).expr == x/y assert Order(x*exp(1/y)).expr == x*exp(1/y) assert Order(exp(x)*exp(1/y)).expr == exp(1/y) + def test_multivar_0a(): assert Order(exp(1/x)*exp(1/y)).expr == exp(1/x + 1/y) + def test_multivar_1(): - assert Order(x+y).expr == x+y - assert Order(x+2*y).expr == x+y - assert (Order(x+y)+x).expr == (x+y) - assert (Order(x+y)+x**2) == Order(x+y) - assert (Order(x+y)+1/x) == 1/x+Order(x+y) - assert Order(x**2+y*x).expr == x**2+y*x + assert Order(x + y).expr == x + y + assert Order(x + 2*y).expr == x + y + assert (Order(x + y) + x).expr == (x + y) + assert (Order(x + y) + x**2) == Order(x + y) + assert (Order(x + y) + 1/x) == 1/x + Order(x + y) + assert Order(x**2 + y*x).expr == x**2 + y*x + def test_multivar_2(): - assert Order(x**2*y+y**2*x,x,y).expr == x**2*y+y**2*x + assert Order(x**2*y + y**2*x, x, y).expr == x**2*y + y**2*x + def test_multivar_mul_1(): - assert Order(x+y)*x == Order(x**2+y*x,x,y) + assert Order(x + y)*x == Order(x**2 + y*x, x, y) + def test_multivar_3(): - assert (Order(x)+Order(y)).args in [ - (Order(x), Order(y)), - (Order(y), Order(x))] - assert Order(x)+Order(y)+Order(x+y) == Order(x+y) - assert (Order(x**2*y)+Order(y**2*x)).args in [ - (Order(x*y**2), Order(y*x**2)), - (Order(y*x**2), Order(x*y**2))] - assert (Order(x**2*y)+Order(y*x)) == Order(x*y) + assert (Order(x) + Order(y)).args in [ + (Order(x), Order(y)), + (Order(y), Order(x))] + assert Order(x) + Order(y) + Order(x + y) == Order(x + y) + assert (Order(x**2*y) + Order(y**2*x)).args in [ + (Order(x*y**2), Order(y*x**2)), + (Order(y*x**2), Order(x*y**2))] + assert (Order(x**2*y) + Order(y*x)) == Order(x*y) + def test_issue369(): x = Symbol('x') @@ -154,43 +193,51 @@ Order(y) Order(z) - assert x.is_positive == None - assert y.is_positive == False - assert z.is_positive == None - - assert x.is_infinitesimal == None - assert y.is_infinitesimal == None - assert z.is_infinitesimal == None + assert x.is_positive is None + assert y.is_positive is False + assert z.is_positive is None + + assert x.is_infinitesimal is None + assert y.is_infinitesimal is None + assert z.is_infinitesimal is None + def test_leading_order(): - assert (x+1+1/x**5).extract_leading_order(x) == ((1/x**5, O(1/x**5)),) - assert (1+1/x).extract_leading_order(x) == ((1/x, O(1/x)),) - assert (1+x).extract_leading_order(x) == ((1, O(1, x)),) - assert (1+x**2).extract_leading_order(x) == ((1, O(1, x)),) - assert (2+x**2).extract_leading_order(x) == ((2, O(1, x)),) - assert (x+x**2).extract_leading_order(x) == ((x, O(x)),) + assert (x + 1 + 1/x**5).extract_leading_order(x) == ((1/x**5, O(1/x**5)),) + assert (1 + 1/x).extract_leading_order(x) == ((1/x, O(1/x)),) + assert (1 + x).extract_leading_order(x) == ((1, O(1, x)),) + assert (1 + x**2).extract_leading_order(x) == ((1, O(1, x)),) + assert (2 + x**2).extract_leading_order(x) == ((2, O(1, x)),) + assert (x + x**2).extract_leading_order(x) == ((x, O(x)),) + def test_leading_order2(): - assert set((2+pi+x**2).extract_leading_order(x)) == set(((pi, O(1, x)), + assert set((2 + pi + x**2).extract_leading_order(x)) == set(((pi, O(1, x)), (S(2), O(1, x)))) - assert set((2*x+pi*x+x**2).extract_leading_order(x)) == set(((2*x, O(x)), + assert set((2*x + pi*x + x**2).extract_leading_order(x)) == set(((2*x, O(x)), (x*pi, O(x)))) + def test_order_leadterm(): assert O(x**2)._eval_as_leading_term(x) == O(x**2) + def test_order_symbols(): e = x*y*sin(x)*Integral(x, (x, 1, 2)) assert O(e) == O(x**2*y, x, y) assert O(e, x) == O(x**2) + def test_nan(): + assert O(nan) == nan assert not O(x).contains(nan) + def test_O1(): assert O(1, x) * x == O(x) assert O(1, y) * x == O(1, y) + def test_getn(): # other lines are tested incidentally by the suite assert O(x).getn() == 1 @@ -199,9 +246,11 @@ assert O(x*log(x)).getn() == 1 raises(NotImplementedError, lambda: (O(x) + O(y)).getn()) + def test_diff(): assert O(x**2).diff(x) == O(x) + def test_getO(): assert (x).getO() is None assert (x).removeO() == x @@ -209,32 +258,64 @@ assert (O(x)).removeO() == 0 assert (z + O(x) + O(y)).getO() == O(x) + O(y) assert (z + O(x) + O(y)).removeO() == z - raises(NotImplementedError, lambda: (O(x)+O(y)).getn()) + raises(NotImplementedError, lambda: (O(x) + O(y)).getn()) + def test_leading_term(): from sympy import digamma assert O(1/digamma(1/x)) == O(1/log(x)) + def test_eval(): y = Symbol('y') - from sympy import Basic assert Order(x).subs(Order(x), 1) == 1 assert Order(x).subs(x, y) == Order(y) + assert Order(x).subs(y, x) == Order(x) + assert Order(x).subs(x, x + y) == Order(x + y) assert (O(1)**x).is_Pow + def test_oseries(): assert Order(x).oseries(x) == Order(x) + @XFAIL def test_issue_1180(): a, b = symbols('a b') - assert O(a+b,a,b)+O(1,a,b) == O(1, a, b) + assert O(a + b, a, b) + O(1, a, b) == O(1, a, b) + @XFAIL def test_issue_1756(): x = Symbol('x') f = Function('f') - g = Function('g') assert 1/O(1) != O(1) assert 1/O(x) != O(1/x) assert 1/O(f(x)) != O(1/x) + + +def test_order_conjugate_transpose(): + x = Symbol('x', real=True) + y = Symbol('y', imaginary=True) + assert conjugate(Order(x)) == Order(conjugate(x)) + assert conjugate(Order(y)) == Order(conjugate(y)) + assert conjugate(Order(x**2)) == Order(conjugate(x)**2) + assert conjugate(Order(y**2)) == Order(conjugate(y)**2) + assert transpose(Order(x)) == Order(transpose(x)) + assert transpose(Order(y)) == Order(transpose(y)) + assert transpose(Order(x**2)) == Order(transpose(x)**2) + assert transpose(Order(y**2)) == Order(transpose(y)**2) + + +def test_order_noncommutative(): + A = Symbol('A', commutative=False) + x = Symbol('x') + assert Order(A + A*x, x) == Order(1, x) + assert (A + A*x)*Order(x) == Order(x) + assert (A*x)*Order(x) == Order(x**2, x) + assert expand((1 + Order(x))*A*A*x) == A*A*x + Order(x**2, x) + assert expand((A*A + Order(x))*x) == A*A*x + Order(x**2, x) + assert expand((A + Order(x))*A*x) == A*A*x + Order(x**2, x) + +def test_issue_3654(): + assert (1 + x**2)**10000*O(x) == O(x) diff -Nru python3-sympy-0.7.2/sympy/series/tests/test_residues.py python3-sympy-0.7.3/sympy/series/tests/test_residues.py --- python3-sympy-0.7.2/sympy/series/tests/test_residues.py 2012-10-17 03:02:22.000000000 +0000 +++ python3-sympy-0.7.3/sympy/series/tests/test_residues.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,6 +1,7 @@ from sympy import residue, Symbol, Function, sin, S, I, pi, exp, log, pi, factorial from sympy.utilities.pytest import XFAIL, raises + def test_basic1(): x = Symbol("x") assert residue(1/x, x, 0) == 1 @@ -12,6 +13,7 @@ assert residue(x, x, 0) == 0 assert residue(x**2, x, 0) == 0 + def test_basic2(): x = Symbol("x") assert residue(1/x, x, 1) == 0 @@ -23,12 +25,14 @@ assert residue(x, x, 1) == 0 assert residue(x**2, x, 5) == 0 + def _test_f(): # FIXME: we get infinite recursion here: x = Symbol("x") f = Function("f") assert residue(f(x)/x**5, x, 0) == f.diff(x, 4)/24 + def test_functions(): x = Symbol("x") assert residue(1/sin(x), x, 0) == 1 @@ -36,32 +40,36 @@ assert residue(1/sin(x)**2, x, 0) == 0 assert residue(1/sin(x)**5, x, 0) == S(3)/8 + def test_expressions(): x = Symbol("x") - assert residue(1/(x+1), x, 0) == 0 - assert residue(1/(x+1), x, -1) == 1 - assert residue(1/(x**2+1), x, -1) == 0 - assert residue(1/(x**2+1), x, I) == -I/2 - assert residue(1/(x**2+1), x, -I) == I/2 - assert residue(1/(x**4+1), x, 0) == 0 + assert residue(1/(x + 1), x, 0) == 0 + assert residue(1/(x + 1), x, -1) == 1 + assert residue(1/(x**2 + 1), x, -1) == 0 + assert residue(1/(x**2 + 1), x, I) == -I/2 + assert residue(1/(x**2 + 1), x, -I) == I/2 + assert residue(1/(x**4 + 1), x, 0) == 0 + @XFAIL def test_expressions_failing(): x = Symbol('x') - assert residue(1/(x**4+1), x, exp(I*pi/4)) == -(S(1)/4+I/4)/sqrt(2) + assert residue(1/(x**4 + 1), x, exp(I*pi/4)) == -(S(1)/4 + I/4)/sqrt(2) z = Symbol('z') n = Symbol('n', integer=True, positive=True) a = Symbol('a') assert residue(exp(z)/(z - pi*I/4*a)**n, z, I*pi*a) == \ - exp(I*pi*a/4)/factorial(n-1) + exp(I*pi*a/4)/factorial(n - 1) assert residue(1/(x**2 + a**2)**2, x, a*I) == -I/4/a**3 + def test_NotImplemented(): z = Symbol('z') raises(NotImplementedError, lambda: residue(exp(1/z), z, 0)) + def test_bug(): from sympy.abc import s, z - assert residue(2**(z)*(s+z)*(1-s-z)/z**2, z, 0) == \ - 1 + s*log(2) - s**2*log(2) - 2*s + assert residue(2**(z)*(s + z)*(1 - s - z)/z**2, z, 0) == \ + 1 + s*log(2) - s**2*log(2) - 2*s diff -Nru python3-sympy-0.7.2/sympy/series/tests/test_series.py python3-sympy-0.7.3/sympy/series/tests/test_series.py --- python3-sympy-0.7.2/sympy/series/tests/test_series.py 2012-10-17 03:02:22.000000000 +0000 +++ python3-sympy-0.7.3/sympy/series/tests/test_series.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,26 +1,31 @@ from sympy import sin, cos, exp, E, series, oo, S, Derivative, O, Integral, \ - Function, log, sqrt, Symbol + Function, log, sqrt, Symbol, Subs from sympy.abc import x, y, n, k from sympy.utilities.pytest import raises +from sympy.series.gruntz import calculate_series + def test_sin(): e1 = sin(x).series(x, 0) e2 = series(sin(x), x, 0) assert e1 == e2 + def test_cos(): e1 = cos(x).series(x, 0) e2 = series(cos(x), x, 0) assert e1 == e2 + def test_exp(): e1 = exp(x).series(x, 0) e2 = series(exp(x), x, 0) assert e1 == e2 + def test_exp2(): e1 = exp(cos(x)).series(x, 0) - e2 = series(exp(cos(x)),x,0) + e2 = series(exp(cos(x)), x, 0) assert e1 == e2 @@ -28,7 +33,7 @@ assert series(1, x) == 1 assert next(S(0).lseries(x)) == 0 assert cos(x).series() == cos(x).series(x) - raises(ValueError, lambda: cos(x+y).series()) + raises(ValueError, lambda: cos(x + y).series()) raises(ValueError, lambda: x.series(dir="")) assert (cos(x).series(x, 1).removeO().subs(x, x - 1) - @@ -40,24 +45,23 @@ # the following test is exact so no need for x -> x - 1 replacement assert abs(x).series(x, 1, dir='-') == x assert exp(x).series(x, 1, dir='-', n=3).removeO().subs(x, x - 1) == \ - E + E*(x - 1) + E*(x - 1)**2/2 + E + E*(x - 1) + E*(x - 1)**2/2 D = Derivative assert D(x**2 + x**3*y**2, x, 2, y, 1).series(x).doit() == 12*x*y assert next(D(cos(x), x).lseries()) == D(1, x) - assert D(exp(x), x).series(n=3) == D(1, x) + D(x, x) + D(x**2/2, x) + O(x**3) + assert D( + exp(x), x).series(n=3) == D(1, x) + D(x, x) + D(x**2/2, x) + O(x**3) - assert Integral(x, (x, 1, 3),(y, 1, x)).series(x) == -4 + 4*x + assert Integral(x, (x, 1, 3), (y, 1, x)).series(x) == -4 + 4*x assert (1 + x + O(x**2)).getn() == 2 - assert (1 + x).getn() == None + assert (1 + x).getn() is None assert ((1/sin(x))**oo).series() == oo logx = Symbol('logx') - assert ((sin(x))**y).nseries(x, n=1, logx = logx) \ - == exp(y*logx) + O(x*exp(y*logx), x) - - raises(NotImplementedError, lambda: series(Function("f")(x))) + assert ((sin(x))**y).nseries(x, n=1, logx=logx) == \ + exp(y*logx) + O(x*exp(y*logx), x) assert sin(1/x).series(x, oo, n=5) == 1/x - 1/(6*x**3) assert abs(x).series(x, oo, n=5, dir='+') == x @@ -66,7 +70,7 @@ assert abs(-x).series(x, -oo, n=5, dir='-') == -x assert exp(x*log(x)).series(n=3) == \ - 1 + x*log(x) + x**2*log(x)**2/2 + O(x**3*log(x)**3) + 1 + x*log(x) + x**2*log(x)**2/2 + O(x**3*log(x)**3) # XXX is this right? If not, fix "ngot > n" handling in expr. p = Symbol('p', positive=True) assert exp(sqrt(p)**3*log(p)).series(n=3) == \ @@ -74,26 +78,54 @@ assert exp(sin(x)*log(x)).series(n=2) == 1 + x*log(x) + O(x**2*log(x)**2) +def test_879(): + f = Function('f') + assert f(x).series(x, 0, 3, dir='-') == \ + f(0) + x*Subs(Derivative(f(x), x), (x,), (0,)) + \ + x**2*Subs(Derivative(f(x), x, x), (x,), (0,))/2 + O(x**3) + assert f(x).series(x, 0, 3) == \ + f(0) + x*Subs(Derivative(f(x), x), (x,), (0,)) + \ + x**2*Subs(Derivative(f(x), x, x), (x,), (0,))/2 + O(x**3) + assert f(x**2).series(x, 0, 3) == \ + f(0) + x**2*Subs(Derivative(f(x), x), (x,), (0,)) + O(x**3) + assert f(x**2+1).series(x, 0, 3) == \ + f(1) + x**2*Subs(Derivative(f(x), x), (x,), (1,)) + O(x**3) + + class TestF(Function): + pass + + assert TestF(x).series(x, 0, 3) == TestF(0) + \ + x*Subs(Derivative(TestF(x), x), (x,), (0,)) + \ + x**2*Subs(Derivative(TestF(x), x, x), (x,), (0,))/2 + O(x**3) + from sympy.series.acceleration import richardson, shanks from sympy import Sum, Integer + def test_acceleration(): e = (1 + 1/n)**n assert round(richardson(e, n, 10, 20).evalf(), 10) == round(E.evalf(), 10) - A = Sum(Integer(-1)**(k+1) / k, (k, 1, n)) + A = Sum(Integer(-1)**(k + 1) / k, (k, 1, n)) assert round(shanks(A, n, 25).evalf(), 4) == round(log(2).evalf(), 4) assert round(shanks(A, n, 25, 5).evalf(), 10) == round(log(2).evalf(), 10) + def test_1484(): - assert cos(1+x+x**2).series(x,0,5) == cos(1) - x*sin(1) + x**2*(-sin(1) - \ - cos(1)/2) + x**3*(-cos(1) + sin(1)/6) + \ - x**4*(-11*cos(1)/24 + sin(1)/2) + O(x**5) + assert cos(1 + x + x**2).series(x, 0, 5) == cos(1) - x*sin(1) + \ + x**2*(-sin(1) - cos(1)/2) + x**3*(-cos(1) + sin(1)/6) + \ + x**4*(-11*cos(1)/24 + sin(1)/2) + O(x**5) + def test_issue_3219(): eq = (1/x)**(S(2)/3) assert (eq + 1).as_leading_term(x) == eq + def test_x_is_base_detection(): eq = (x**2)**(S(2)/3) assert eq.series() == eq + +def test_sin_power(): + e = sin(x)**1.2 + assert calculate_series(e, x) == x**1.2 diff -Nru python3-sympy-0.7.2/sympy/sets/fancysets.py python3-sympy-0.7.3/sympy/sets/fancysets.py --- python3-sympy-0.7.2/sympy/sets/fancysets.py 2012-10-17 03:02:22.000000000 +0000 +++ python3-sympy-0.7.3/sympy/sets/fancysets.py 2013-07-13 17:53:32.000000000 +0000 @@ -9,6 +9,7 @@ oo = S.Infinity + class Naturals(Set, metaclass=Singleton): """ Represents the Natural Numbers. The Naturals are available as a singleton @@ -31,10 +32,12 @@ {1, 2, ..., 10} """ is_iterable = True + _inf = S.One + _sup = oo def _intersect(self, other): if other.is_Interval: - return Intersection(S.Integers, other, Interval(1, oo)) + return Intersection(S.Integers, other, Interval(self._inf, oo)) return None def _contains(self, other): @@ -43,18 +46,23 @@ return False def __iter__(self): - i = S(1) + i = self._inf while True: yield i i = i + 1 - @property - def _inf(self): - return S.One +class Naturals0(Naturals): + """ The Natural Numbers starting at 0 - @property - def _sup(self): - return oo + See also: + S.Naturals - starts at 1 + """ + _inf = S.Zero + + def _contains(self, other): + if ask(Q.negative(other)) == False and ask(Q.integer(other)): + return True + return False class Integers(Set, metaclass=Singleton): """ @@ -85,7 +93,7 @@ def _intersect(self, other): if other.is_Interval and other.measure < oo: s = Range(ceiling(other.left), floor(other.right) + 1) - return s.intersect(other) # take out endpoints if open interval + return s.intersect(other) # take out endpoints if open interval return None def _contains(self, other): @@ -109,10 +117,12 @@ def _sup(self): return oo + class Reals(Interval, metaclass=Singleton): def __new__(cls): return Interval.__new__(cls, -oo, oo) + class TransformationSet(Set): """ A set that is a transformation of another through some algebraic expression @@ -143,7 +153,7 @@ def __new__(cls, lamda, base_set): return Basic.__new__(cls, lamda, base_set) - lamda = property(lambda self: self.args[0]) + lamda = property(lambda self: self.args[0]) base_set = property(lambda self: self.args[1]) def __iter__(self): @@ -169,15 +179,18 @@ for soln in solns: try: - if soln in self.base_set: return True + if soln in self.base_set: + return True except TypeError: - if soln.evalf() in self.base_set: return True + if soln.evalf() in self.base_set: + return True return False @property def is_iterable(self): return self.base_set.is_iterable + class Range(Set): """ Represents a range of integers. @@ -206,7 +219,7 @@ try: start, stop, step = [S(as_int(w)) for w in (start, stop, step)] except ValueError: - raise ValueError("Inputs to Range must be Integer Valued\n"+ + raise ValueError("Inputs to Range must be Integer Valued\n" + "Use TransformationSets of Ranges for other cases") n = ceiling((stop - start)/step) if n <= 0: @@ -220,8 +233,8 @@ return Basic.__new__(cls, start, stop + step, step) start = property(lambda self: self.args[0]) - stop = property(lambda self: self.args[1]) - step = property(lambda self: self.args[2]) + stop = property(lambda self: self.args[1]) + step = property(lambda self: self.args[2]) def _intersect(self, other): if other.is_Interval: diff -Nru python3-sympy-0.7.2/sympy/sets/tests/test_fancysets.py python3-sympy-0.7.3/sympy/sets/tests/test_fancysets.py --- python3-sympy-0.7.2/sympy/sets/tests/test_fancysets.py 2012-10-17 03:02:22.000000000 +0000 +++ python3-sympy-0.7.3/sympy/sets/tests/test_fancysets.py 2013-07-13 17:53:32.000000000 +0000 @@ -7,14 +7,15 @@ x = Symbol('x') + def test_naturals(): N = S.Naturals assert 5 in N assert -5 not in N assert 5.5 not in N ni = iter(N) - a,b,c,d = next(ni), next(ni), next(ni), next(ni) - assert (a,b,c,d) == (1,2,3,4) + a, b, c, d = next(ni), next(ni), next(ni), next(ni) + assert (a, b, c, d) == (1, 2, 3, 4) assert isinstance(a, Basic) assert N.intersect(Interval(-5, 5)) == Range(1, 6) @@ -23,22 +24,28 @@ assert N.inf == 1 assert N.sup == oo +def test_naturals0(): + N = S.Naturals0 + assert 0 in N + assert next(iter(N)) == 0 + def test_integers(): Z = S.Integers assert 5 in Z assert -5 in Z assert 5.5 not in Z zi = iter(Z) - a,b,c,d = next(zi), next(zi), next(zi), next(zi) - assert (a,b,c,d) == (0, 1, -1, 2) + a, b, c, d = next(zi), next(zi), next(zi), next(zi) + assert (a, b, c, d) == (0, 1, -1, 2) assert isinstance(a, Basic) assert Z.intersect(Interval(-5, 5)) == Range(-5, 6) - assert Z.intersect(Interval(-5, 5, True, True)) == Range(-4,5) + assert Z.intersect(Interval(-5, 5, True, True)) == Range(-4, 5) assert Z.inf == -oo assert Z.sup == oo + def test_TransformationSet(): squares = TransformationSet(Lambda(x, x**2), S.Naturals) assert 4 in squares @@ -48,16 +55,17 @@ assert 16 not in squares.intersect(Interval(0, 10)) si = iter(squares) - a,b,c,d = next(si), next(si), next(si), next(si) - assert (a,b,c,d) == (1, 4, 9, 16) + a, b, c, d = next(si), next(si), next(si), next(si) + assert (a, b, c, d) == (1, 4, 9, 16) harmonics = TransformationSet(Lambda(x, 1/x), S.Naturals) - assert Rational(1,5) in harmonics + assert Rational(1, 5) in harmonics assert .25 in harmonics assert .3 not in harmonics assert harmonics.is_iterable + @XFAIL def test_halfcircle(): # This test sometimes works and sometimes doesn't. @@ -73,13 +81,15 @@ assert not halfcircle.is_iterable + def test_transformation_iterator_not_injetive(): - L = Lambda(x, x - x%2) # produces 0, 2, 2, 4, 4, 6, 6, ... + L = Lambda(x, x - x % 2) # produces 0, 2, 2, 4, 4, 6, 6, ... evens = TransformationSet(L, S.Naturals) i = iter(evens) # No repeats here assert (next(i), next(i), next(i), next(i)) == (0, 2, 4, 6) + def test_Range(): assert Range(5) == Range(0, 5) == Range(0, 5, 1) @@ -107,7 +117,7 @@ def test_range_interval_intersection(): # Intersection with intervals assert FiniteSet(Range(0, 10, 1).intersect(Interval(2, 6))) == \ - FiniteSet(2, 3, 4, 5, 6) + FiniteSet(2, 3, 4, 5, 6) # Open Intervals are removed assert (FiniteSet(Range(0, 10, 1).intersect(Interval(2, 6, True, True))) @@ -119,27 +129,33 @@ # Going backwards assert FiniteSet(Range(10, -9, -3).intersect(Interval(-5, 6))) == \ - FiniteSet(-5, -2, 1, 4) + FiniteSet(-5, -2, 1, 4) assert FiniteSet(Range(10, -9, -3).intersect(Interval(-5, 6, True))) == \ - FiniteSet(-2, 1, 4) + FiniteSet(-2, 1, 4) + def test_fun(): assert (FiniteSet(TransformationSet(Lambda(x, sin(pi*x/4)), - Range(-10,11))) == FiniteSet(-1, -sqrt(2)/2, 0, sqrt(2)/2, 1)) + Range(-10, 11))) == FiniteSet(-1, -sqrt(2)/2, 0, sqrt(2)/2, 1)) + def test_reals(): assert 5 in S.Reals assert S.Pi in S.Reals assert -sqrt(2) in S.Reals - assert (2,5) not in S.Reals + assert (2, 5) not in S.Reals + -@XFAIL # this is because contains is now very strict +@XFAIL # this is because contains is now very strict def test_reals_fail(): assert sqrt(-1) not in S.Reals + def take(n, iterable): "Return first n items of the iterable as a list" return list(itertools.islice(iterable, n)) + + def test_intersections(): assert 5 in S.Integers.intersect(S.Reals) assert 5 in S.Integers.intersect(S.Reals) diff -Nru python3-sympy-0.7.2/sympy/simplify/__init__.py python3-sympy-0.7.3/sympy/simplify/__init__.py --- python3-sympy-0.7.2/sympy/simplify/__init__.py 2012-10-17 03:02:22.000000000 +0000 +++ python3-sympy-0.7.3/sympy/simplify/__init__.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,4 +1,4 @@ -"""The module helps converting sympy expressions into shorter forms of them. +"""The module helps converting SymPy expressions into shorter forms of them. for example: the expression E**(pi*I) will be converted into -1 @@ -7,7 +7,10 @@ from .simplify import (collect, rcollect, separate, radsimp, ratsimp, fraction, simplify, trigsimp, powsimp, combsimp, hypersimp, hypersimilar, nsimplify, logcombine, separatevars, numer, denom, powdenest, posify, polarify, - unpolarify, collect_const, signsimp, besselsimp, ratsimpmodprime) + unpolarify, collect_const, signsimp, besselsimp, ratsimpmodprime, + exptrigsimp) + +from .fu import FU, fu from .sqrtdenest import sqrtdenest diff -Nru python3-sympy-0.7.2/sympy/simplify/cse_main.py python3-sympy-0.7.3/sympy/simplify/cse_main.py --- python3-sympy-0.7.2/sympy/simplify/cse_main.py 2012-10-17 03:02:22.000000000 +0000 +++ python3-sympy-0.7.3/sympy/simplify/cse_main.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,16 +1,13 @@ """ Tools for doing common subexpression elimination. """ -import bisect import difflib -from sympy.core import Basic, Mul, Add, Tuple, sympify +from sympy.core import Basic, Mul, Add, sympify from sympy.core.basic import preorder_traversal -from sympy.functions.elementary.complexes import sign from sympy.core.function import _coeff_isneg from sympy.core.compatibility import iterable from sympy.utilities.iterables import numbered_symbols, \ - sift, topological_sort -from sympy.utilities.misc import default_sort_key + sift, topological_sort, ordered from . import cse_opts @@ -32,6 +29,7 @@ # transformations can be put here for users # =============================================================== + def reps_toposort(r): """Sort replacements `r` so (k1, v1) appears before (k2, v2) if k2 is in v1's free symbols. This orders items in the @@ -59,6 +57,7 @@ E.append((c1, c2)) return [r[i] for i in topological_sort((list(range(len(r))), E))] + def cse_separate(r, e): """Move expressions that are in the form (symbol, expr) out of the expressions and sort them into the replacements using the reps_toposort. @@ -67,18 +66,25 @@ ======== >>> from sympy.simplify.cse_main import cse_separate >>> from sympy.abc import x, y, z - >>> from sympy import cos, exp, cse, Eq + >>> from sympy import cos, exp, cse, Eq, symbols + >>> x0, x1 = symbols('x:2') >>> eq = (x + 1 + exp((x + 1)/(y + 1)) + cos(y + 1)) - >>> cse([eq, Eq(x, z + 1), z - 2], postprocess=cse_separate) - [[(x0, y + 1), (x, z + 1), (x1, x + 1)], [x1 + exp(x1/x0) + cos(x0), z - 2]] + >>> cse([eq, Eq(x, z + 1), z - 2], postprocess=cse_separate) in [ + ... [[(x0, y + 1), (x, z + 1), (x1, x + 1)], + ... [x1 + exp(x1/x0) + cos(x0), z - 2]], + ... [[(x1, y + 1), (x, z + 1), (x0, x + 1)], + ... [x0 + exp(x0/x1) + cos(x1), z - 2]]] + ... + True """ - syms = set([k for k, v in r]) - d = sift(e, lambda w: w.is_Equality and not bool(w.free_symbols & set(syms))) - r, e = [r + [w.args for w in d[True]], d[False]] + d = sift(e, lambda w: w.is_Equality and w.lhs.is_Symbol) + r = r + [w.args for w in d[True]] + e = d[False] return [reps_toposort(r), e] # ====end of cse postprocess idioms=========================== + def preprocess_for_cse(expr, optimizations): """ Preprocess an expression to optimize for common subexpression elimination. @@ -100,6 +106,7 @@ expr = pre(expr) return expr + def postprocess_for_cse(expr, optimizations): """ Postprocess an expression after common subexpression elimination to return the expression to canonical sympy form. @@ -125,6 +132,82 @@ expr = post(expr) return expr + +def _remove_singletons(reps, exprs): + """ + Helper function for cse that will remove expressions that weren't + used more than once. + """ + u_reps = [] # the useful reps that are used more than once + for i, ui in enumerate(reps): + used = [] # where it was used + ri, ei = ui + + # keep track of whether the substitution was used more + # than once. If used is None, it was never used (yet); + # if used is an int, that is the last place where it was + # used (>=0 in the reps, <0 in the expressions) and if + # it is True, it was used more than once. + + used = None + + tot = 0 # total times used so far + + # search through the reps + for j in range(i + 1, len(reps)): + c = reps[j][1].count(ri) + if c: + tot += c + if tot > 1: + u_reps.append(ui) + used = True + break + else: + used = j + + if used is not True: + + # then search through the expressions + + for j, rj in enumerate(exprs): + c = rj.count(ri) + if c: + # append a negative so we know that it was in the + # expression that used it + tot += c + if tot > 1: + u_reps.append(ui) + used = True + break + else: + used = j - len(exprs) + + if type(used) is int: + + # undo the change + + rep = {ri: ei} + j = used + if j < 0: + exprs[j] = exprs[j].subs(rep) + else: + reps[j] = reps[j][0], reps[j][1].subs(rep) + + # reuse unused symbols so a contiguous range of symbols is returned + + if len(u_reps) != len(reps): + for i, ri in enumerate(u_reps): + if u_reps[i][0] != reps[i][0]: + rep = (u_reps[i][0], reps[i][0]) + u_reps[i] = rep[1], u_reps[i][1].subs(*rep) + for j in range(i + 1, len(u_reps)): + u_reps[j] = u_reps[j][0], u_reps[j][1].subs(*rep) + for j, rj in enumerate(exprs): + exprs[j] = exprs[j].subs(*rep) + + reps[:] = u_reps # change happens in-place + + def cse(exprs, symbols=None, optimizations=None, postprocess=None): """ Perform common subexpression elimination on an expression. @@ -156,7 +239,6 @@ The reduced expressions with all of the replacements above. """ from sympy.matrices import Matrix - from sympy.simplify.simplify import fraction if symbols is None: symbols = numbered_symbols() @@ -167,8 +249,7 @@ seen_subexp = set() muls = set() adds = set() - to_eliminate = [] - to_eliminate_ops_count = [] + to_eliminate = set() if optimizations is None: # Pull out the default here just in case there are some weird @@ -181,27 +262,12 @@ # Preprocess the expressions to give us better optimization opportunities. reduced_exprs = [preprocess_for_cse(e, optimizations) for e in exprs] - # Find all of the repeated subexpressions. - def insert(subtree): - '''This helper will insert the subtree into to_eliminate while - maintaining the ordering by op count and will skip the insertion - if subtree is already present.''' - ops_count = (subtree.count_ops(), subtree.is_Mul) # prefer non-Mul to Mul - index_to_insert = bisect.bisect(to_eliminate_ops_count, ops_count) - # all i up to this index have op count <= the current op count - # so check that subtree is not yet present from this index down - # (if necessary) to zero. - for i in range(index_to_insert - 1, -1, -1): - if to_eliminate_ops_count[i] == ops_count and \ - subtree == to_eliminate[i]: - return # already have it - to_eliminate_ops_count.insert(index_to_insert, ops_count) - to_eliminate.insert(index_to_insert, subtree) + # Find all of the repeated subexpressions. for expr in reduced_exprs: if not isinstance(expr, Basic): continue - pt = preorder_traversal(expr, key=default_sort_key) + pt = preorder_traversal(expr) for subtree in pt: inv = 1/subtree if subtree.is_Pow else None @@ -214,7 +280,7 @@ if inv and _coeff_isneg(subtree.exp): # save the form with positive exponent subtree = inv - insert(subtree) + to_eliminate.add(subtree) pt.skip() continue @@ -222,7 +288,7 @@ if _coeff_isneg(subtree.exp): # save the form with positive exponent subtree = inv - insert(subtree) + to_eliminate.add(subtree) pt.skip() continue elif subtree.is_Mul: @@ -234,12 +300,12 @@ # process adds - any adds that weren't repeated might contain # subpatterns that are repeated, e.g. x+y+z and x+y have x+y in common - adds = [set(a.args) for a in adds] + adds = [set(a.args) for a in ordered(adds)] for i in range(len(adds)): for j in range(i + 1, len(adds)): com = adds[i].intersection(adds[j]) if len(com) > 1: - insert(Add(*com)) + to_eliminate.add(Add(*com)) # remove this set of symbols so it doesn't appear again adds[i] = adds[i].difference(com) @@ -255,7 +321,7 @@ # in common between the two nc parts sm = difflib.SequenceMatcher() - muls = [a.args_cnc(cset=True) for a in muls] + muls = [a.args_cnc(cset=True) for a in ordered(muls)] for i in range(len(muls)): if muls[i][1]: sm.set_seq1(muls[i][1]) @@ -282,7 +348,7 @@ if len(com) < 2: continue - insert(Mul(*com)) + to_eliminate.add(Mul(*com)) # remove ccom from all if there was no ncom; to update the nc part # would require finding the subexpr and then replacing it with a @@ -295,6 +361,11 @@ if not ccom.difference(muls[k][0]): muls[k][0] = muls[k][0].difference(ccom) + # make to_eliminate canonical; we will prefer non-Muls to Muls + # so select them first (non-Muls will have False for is_Mul and will + # be first in the ordering. + to_eliminate = list(ordered(to_eliminate, lambda _: _.is_Mul)) + # Substitute symbols for all of the repeated subexpressions. replacements = [] reduced_exprs = list(reduced_exprs) @@ -313,7 +384,7 @@ reduced_exprs[j] = update(expr) hit = hit or (old != reduced_exprs[j]) # Make the substitution in all of the subsequent substitutions. - for j in range(i+1, len(to_eliminate)): + for j in range(i + 1, len(to_eliminate)): old = to_eliminate[j] to_eliminate[j] = update(to_eliminate[j]) hit = hit or (old != to_eliminate[j]) @@ -327,6 +398,9 @@ reduced_exprs = [postprocess_for_cse(e, optimizations) for e in reduced_exprs] + # remove replacements that weren't used more than once + _remove_singletons(replacements, reduced_exprs) + if isinstance(exprs, Matrix): reduced_exprs = [Matrix(exprs.rows, exprs.cols, reduced_exprs)] if postprocess is None: diff -Nru python3-sympy-0.7.2/sympy/simplify/cse_opts.py python3-sympy-0.7.3/sympy/simplify/cse_opts.py --- python3-sympy-0.7.2/sympy/simplify/cse_opts.py 2012-10-17 03:02:22.000000000 +0000 +++ python3-sympy-0.7.3/sympy/simplify/cse_opts.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,43 +1,47 @@ """ Optimizations of the expression tree representation for better CSE opportunities. """ -from sympy.core import Add, Basic, Expr, Mul, S -from sympy.core.exprtools import factor_terms +from sympy.core import Add, Basic, Expr, Mul from sympy.core.basic import preorder_traversal +from sympy.core.exprtools import factor_terms +from sympy.core.singleton import S +from sympy.utilities.iterables import default_sort_key -class Neg(Expr): - """ Stub to hold negated expression. - """ - __slots__ = [] def sub_pre(e): - """ Replace y - x with Neg(x - y) if -1 can be extracted from y - x. + """ Replace y - x with -(x - y) if -1 can be extracted from y - x. """ - # make canonical, first - adds = {} - for a in e.atoms(Add): - adds[a] = a.could_extract_minus_sign() - e = e.subs([(a, Mul(-1, -a, evaluate=False) - if adds[a] else a) for a in adds]) - # now replace any persisting Adds, a, that can have -1 extracted with Neg(-a) + reps = [a for a in e.atoms(Add) if a.could_extract_minus_sign()] + + # make it canonical + reps.sort(key=default_sort_key) + + e = e.subs([(a, Mul._from_args([S.NegativeOne, -a])) for a in reps]) + # repeat again for persisting Adds but mark these with a leading 1, -1 + # e.g. y - x -> 1*-1*(x - y) if isinstance(e, Basic): - reps = dict([(a, Neg(-a)) for a in e.atoms(Add) - if adds.get(a, a.could_extract_minus_sign())]) - e = e.xreplace(reps) + negs = {} + for a in sorted(e.atoms(Add), key=default_sort_key): + if a in reps or a.could_extract_minus_sign(): + negs[a] = Mul._from_args([S.One, S.NegativeOne, -a]) + e = e.xreplace(negs) return e + def sub_post(e): - """ Replace Neg(x) with -x. + """ Replace 1*-1*x with -x. """ replacements = [] for node in preorder_traversal(e): - if isinstance(node, Neg): - replacements.append((node, -node.args[0])) + if isinstance(node, Mul) and \ + node.args[0] is S.One and node.args[1] is S.NegativeOne: + replacements.append((node, -Mul._from_args(node.args[2:]))) for node, replacement in replacements: e = e.xreplace({node: replacement}) return e + default_optimizations = [ (sub_pre, sub_post), (factor_terms, None), diff -Nru python3-sympy-0.7.2/sympy/simplify/epathtools.py python3-sympy-0.7.3/sympy/simplify/epathtools.py --- python3-sympy-0.7.2/sympy/simplify/epathtools.py 2012-10-17 03:02:22.000000000 +0000 +++ python3-sympy-0.7.3/sympy/simplify/epathtools.py 2013-07-13 17:53:32.000000000 +0000 @@ -2,6 +2,7 @@ from sympy.core import Basic + class EPath(object): r""" Manipulate expressions using paths. @@ -98,7 +99,7 @@ span = slice(*span) - selector = selector[i+1:] + selector = selector[i + 1:] if selector: raise ValueError("trailing characters in selector") @@ -276,6 +277,7 @@ _select(self._epath, expr) return result + def epath(path, expr=None, func=None, args=None, kwargs=None): r""" Manipulate parts of an expression selected by a path. diff -Nru python3-sympy-0.7.2/sympy/simplify/fu.py python3-sympy-0.7.3/sympy/simplify/fu.py --- python3-sympy-0.7.2/sympy/simplify/fu.py 1970-01-01 00:00:00.000000000 +0000 +++ python3-sympy-0.7.3/sympy/simplify/fu.py 2013-07-13 17:53:32.000000000 +0000 @@ -0,0 +1,2110 @@ +""" +Implementation of the trigsimp algorithm by Fu et al. + +The idea behind the ``fu`` algorithm is to use a sequence of rules, applied +in what is heuristically known to be a smart order, to select a simpler +expression that is equivalent to the input. + +There are transform rules in which a single rule is applied to the +expression tree. The following are just mnemonic in nature; see the +docstrings for examples. + + TR0 - simplify expression + TR1 - sec-csc to cos-sin + TR2 - tan-cot to sin-cos ratio + TR2i - sin-cos ratio to tan + TR3 - angle canonicalization + TR4 - functions at special angles + TR5 - powers of sin to powers of cos + TR6 - powers of cos to powers of sin + TR7 - reduce cos power (increase angle) + TR8 - expand products of sin-cos to sums + TR9 - contract sums of sin-cos to products + TR10 - separate sin-cos arguments + TR10i - collect sin-cos arguments + TR11 - reduce double angles + TR12 - separate tan arguments + TR12i - collect tan arguments + TR13 - expand product of tan-cot + TRmorrie - prod(cos(x*2**i), (i, 0, k - 1)) -> sin(2**k*x)/(2**k*sin(x)) + TR14 - factored powers of sin or cos to cos or sin power + TR15 - negative powers of sin to cot power + TR16 - negative powers of cos to tan power + TR22 - tan-cot powers to negative powers of sec-csc functions + TR111 - negative sin-cos-tan powers to csc-sec-cot + +There are 4 combination transforms (CTR1 - CTR4) in which a seqence of +transformations are applied and the simplest expression is selected from +a few options. + +Finally, there are the 2 rule lists (RL1 and RL2), which apply a +sequence of transformations and combined transformations, and the ``fu`` +algorithm itself, which applies rules and rule lists and selects the +best expressions. There is also a function ``L`` which counts the number +of trigonometric funcions that appear in the expression. + +Other than TR0, re-writing of expressions is not done by the transformations. +e.g. TR10i finds pairs of terms in a sum that are in the form like +``cos(x)*cos(y) + sin(x)*sin(y)``. Such expression are targeted in a bottom-up +traversal of the expression, but no manipulation to make them appear is +attempted. For example, + + Set-up for examples below: + + >>> from sympy.simplify.fu import fu, L, TR9, TR10i, TR11 + >>> from sympy import factor, sin, cos, powsimp + >>> from sympy.abc import x, y, z, a + >>> from time import time + +>>> eq = cos(x + y)/cos(x) +>>> TR10i(eq.expand(trig=True)) +-sin(x)*sin(y)/cos(x) + cos(y) + +If the expression is put in "normal" form (with a common denominator) then +the transformation is successful: + +>>> TR10i(_.normal()) +cos(x + y)/cos(x) + +TR11's behavior is similar. It rewrites double angles as smaller angles but +doesn't do any simplification of the result. + +>>> TR11(sin(2)**a*cos(1)**(-a), 1) +(2*sin(1)*cos(1))**a*cos(1)**(-a) +>>> powsimp(_) +(2*sin(1))**a + +The temptation is to try make these TR rules "smarter" but that should really +be done at a higher level; the TR rules should try maintain the "do one thing +well" principle. There is one exception, however. In TR10i and TR9 terms are +recognized even when they are each multiplied by a common factor: + +>>> fu(a*cos(x)*cos(y) + a*sin(x)*sin(y)) +a*cos(x - y) + +Factoring with ``factor_terms`` is used but it it "JIT"-like, being delayed +until it is deemed necessary. Furthermore, if the factoring does not +help with the simplification, it is not retained, so +``a*cos(x)*cos(y) + a*sin(x)*sin(z)`` does not become the factored +(but unsimplified in the trigonometric sense) expression: + +>>> fu(a*cos(x)*cos(y) + a*sin(x)*sin(z)) +a*sin(x)*sin(z) + a*cos(x)*cos(y) + +In some cases factoring might be a good idea, but the user is left +to make that decision. For example: + +>>> expr=((15*sin(2*x) + 19*sin(x + y) + 17*sin(x + z) + 19*cos(x - z) + +... 25)*(20*sin(2*x) + 15*sin(x + y) + sin(y + z) + 14*cos(x - z) + +... 14*cos(y - z))*(9*sin(2*y) + 12*sin(y + z) + 10*cos(x - y) + 2*cos(y - +... z) + 18)).expand(trig=True).expand() + +In the expanded state, there are nearly 1000 trig functions: + +>>> L(expr) +932 + +If the expression where factored first, this would take time but the +resulting expression would be transformed very quickly: + +>>> def clock(f, n=2): +... t=time(); f(); return round(time()-t, n) +... +>>> clock(lambda: factor(expr)) # doctest: +SKIP +0.86 +>>> clock(lambda: TR10i(expr), 3) # doctest: +SKIP +0.016 + +If the unexpanded expression is used, the transformation takes longer but +not as long as it took to factor it and then transform it: + +>>> clock(lambda: TR10i(expr), 2) # doctest: +SKIP +0.28 + +So neither expansion nor factoring is used in ``TR10i``: if the +expression is already factored (or partially factored) then expansion +with ``trig=True`` would destroy what is already known and take +longer; if the expression is expanded, factoring may take longer than +simply applying the transformation itself. + +Although the algorithms should be canonical, always giving the same +result, they may not yield the best result. This, in general, is +the nature of simplification where searching all possible transformation +paths is very expensive. Here is a simple example. There are 6 terms +in the following sum: + +>>> expr = (sin(x)**2*cos(y)*cos(z) + sin(x)*sin(y)*cos(x)*cos(z) + +... sin(x)*sin(z)*cos(x)*cos(y) + sin(y)*sin(z)*cos(x)**2 + sin(y)*sin(z) + +... cos(y)*cos(z)) +>>> args = expr.args + +Serendipitously, fu gives the best result: + +>>> fu(expr) +3*cos(y - z)/2 - cos(2*x + y + z)/2 + +But if different terms were combined, a less-optimal result might be +obtained, requiring some additional work to get better simplification, +but still less than optimal. The following shows an alternative form +of ``expr`` that resists optimal simplification once a given step +is taken since it leads to a dead end: + +>>> TR9(-cos(x)**2*cos(y + z) + 3*cos(y - z)/2 + +... cos(y + z)/2 + cos(-2*x + y + z)/4 - cos(2*x + y + z)/4) +sin(2*x)*sin(y + z)/2 - cos(x)**2*cos(y + z) + 3*cos(y - z)/2 + cos(y + z)/2 + +Here is a smaller expression that exhibits the same behavior: + +>>> a = sin(x)*sin(z)*cos(x)*cos(y) + sin(x)*sin(y)*cos(x)*cos(z) +>>> TR10i(a) +sin(x)*sin(y + z)*cos(x) +>>> newa = _ +>>> TR10i(expr - a) # this combines two more of the remaining terms +sin(x)**2*cos(y)*cos(z) + sin(y)*sin(z)*cos(x)**2 + cos(y - z) +>>> TR10i(_ + newa) == _ + newa # but now there is no more simplification +True + +Without getting lucky or trying all possible pairings of arguments, the +final result may be less than optimal and impossible to find without +better heuristics or brute force trial of all possibilities. + +Notes +===== + +This work was started by Dimitar Vlahovski at the Technological School +"Electronic systems" (30.11.2011). + +References +========== +http://rfdz.ph-noe.ac.at/fileadmin/Mathematik_Uploads/ACDCA/ +DESTIME2006/DES_contribs/Fu/simplification.pdf + +http://www.sosmath.com/trig/Trig5/trig5/pdf/pdf.html gives a formula sheet. + +""" + +from collections import defaultdict + +from sympy.simplify.simplify import (simplify, powsimp, ratsimp, combsimp, + _mexpand, bottom_up) +from sympy.core.sympify import sympify +from sympy.functions.elementary.trigonometric import ( + cos, sin, tan, cot, sec, csc, sqrt) +from sympy.functions.elementary.hyperbolic import cosh, sinh, tanh, coth +from sympy.core.compatibility import ordered, combinations +from sympy.core.core import C +from sympy.core.mul import Mul +from sympy.core.power import Pow +from sympy.core.function import expand_mul, count_ops +from sympy.core.add import Add +from sympy.core.symbol import Dummy +from sympy.core.exprtools import Factors, gcd_terms +from sympy.core.rules import Transform +from sympy.core.basic import S +from sympy.core.numbers import Integer, pi, I +from sympy.strategies.tree import greedy +from sympy.strategies.core import identity, debug +from sympy.polys.polytools import factor +from sympy.ntheory.factor_ import perfect_power + +from sympy import SYMPY_DEBUG + + +# ================== Fu-like tools =========================== + + +def TR0(rv): + """Simplification of rational polynomials, trying to simplify + the expression, e.g. combine things like 3*x + 2*x, etc.... + """ + # although it would be nice to use cancel, it doesn't work + # with noncommutatives + return rv.normal().factor().expand() + + +def TR1(rv): + """Replace sec, csc with 1/cos, 1/sin + + Examples + ======== + + >>> from sympy.simplify.fu import TR1, sec, csc + >>> from sympy.abc import x + >>> TR1(2*csc(x) + sec(x)) + 1/cos(x) + 2/sin(x) + """ + + def f(rv): + if rv.func is sec: + a = rv.args[0] + return S.One/cos(a) + elif rv.func is csc: + a = rv.args[0] + return S.One/sin(a) + return rv + + return bottom_up(rv, f) + + +def TR2(rv): + """Replace tan and cot with sin/cos and cos/sin + + Examples + ======== + + >>> from sympy.simplify.fu import TR2 + >>> from sympy.abc import x + >>> from sympy import tan, cot, sin, cos + >>> TR2(tan(x)) + sin(x)/cos(x) + >>> TR2(cot(x)) + cos(x)/sin(x) + >>> TR2(tan(tan(x) - sin(x)/cos(x))) + 0 + + """ + + def f(rv): + if rv.func is tan: + a = rv.args[0] + return sin(a)/cos(a) + elif rv.func is cot: + a = rv.args[0] + return cos(a)/sin(a) + return rv + + return bottom_up(rv, f) + + +def TR2i(rv, half=False): + """Converts ratios involving sin and cos as follows:: + sin(x)/cos(x) -> tan(x) + sin(x)/(cos(x) + 1) -> tan(x/2) if half=True + + Examples + ======== + + >>> from sympy.simplify.fu import TR2i + >>> from sympy.abc import x, a + >>> from sympy import sin, cos + >>> TR2i(sin(x)/cos(x)) + tan(x) + + Powers of the numerator and denominator are also recognized + + >>> TR2i(sin(x)**2/(cos(x) + 1)**2, half=True) + tan(x/2)**2 + + The transformation does not take place unless assumptions allow + (i.e. the base must be positive or the exponent must be an integer + for both numerator and denominator) + + >>> TR2i(sin(x)**a/(cos(x) + 1)**a) + (cos(x) + 1)**(-a)*sin(x)**a + + """ + + def f(rv): + if not rv.is_Mul: + return rv + + n, d = rv.as_numer_denom() + if n.is_Atom or d.is_Atom: + return rv + + def ok(k, e): + # initial filtering of factors + return ( + (e.is_integer or k.is_positive) and ( + k.func in (sin, cos) or (half and + k.is_Add and + len(k.args) >= 2 and + any(any(ai.func is cos or ai.is_Pow and ai.base is cos + for ai in Mul.make_args(a)) for a in k.args)))) + + n = n.as_powers_dict() + ndone = [(k, n.pop(k)) for k in list(n.keys()) if not ok(k, n[k])] + if not n: + return rv + + d = d.as_powers_dict() + ddone = [(k, d.pop(k)) for k in list(d.keys()) if not ok(k, d[k])] + if not d: + return rv + + # factoring if necessary + + def factorize(d, ddone): + newk = [] + for k in d: + if k.is_Add and len(k.args) > 2: + knew = factor(k) if half else factor_terms(k) + if knew != k: + newk.append((k, knew)) + if newk: + for i, (k, knew) in enumerate(newk): + del d[k] + newk[i] = knew + newk = Mul(*newk).as_powers_dict() + for k in newk: + if ok(k, d[k]): + d[k] += newk[k] + else: + ddone.append((k, d[k])) + del newk + factorize(n, ndone) + factorize(d, ddone) + + # joining + t = [] + for k in n: + if k.func is sin: + a = cos(k.args[0], evaluate=False) + if a in d and d[a] == n[k]: + t.append(tan(k.args[0])**n[k]) + n[k] = d[a] = None + elif half: + a1 = 1 + a + if a1 in d and d[a1] == n[k]: + t.append((tan(k.args[0]/2))**n[k]) + n[k] = d[a1] = None + elif k.func is cos: + a = sin(k.args[0], evaluate=False) + if a in d and d[a] == n[k]: + t.append(tan(k.args[0])**-n[k]) + n[k] = d[a] = None + elif half and k.is_Add and k.args[0] is S.One and \ + k.args[1].func is cos: + a = sin(k.args[1].args[0], evaluate=False) + if a in d and d[a] == n[k] and (d[a].is_integer or \ + a.is_positive): + t.append(tan(a.args[0]/2)**-n[k]) + n[k] = d[a] = None + + if t: + rv = Mul(*(t + [b**e for b, e in n.items() if e]))/\ + Mul(*[b**e for b, e in d.items() if e]) + rv *= Mul(*[b**e for b, e in ndone])/Mul(*[b**e for b, e in ddone]) + + return rv + + return bottom_up(rv, f) + + +def TR3(rv): + """Induced formula: example sin(-a) = -sin(a) + + Examples + ======== + + >>> from sympy.simplify.fu import TR3 + >>> from sympy.abc import x, y + >>> from sympy import pi + >>> from sympy import cos + >>> TR3(cos(y - x*(y - x))) + cos(x*(x - y) + y) + >>> cos(pi/2 + x) + -sin(x) + >>> cos(30*pi/2 + x) + -cos(x) + + """ + from sympy.simplify.simplify import signsimp + + # Negative argument (already automatic for funcs like sin(-x) -> -sin(x) + # but more complicated expressions can use it, too). Also, trig angles + # between pi/4 and pi/2 are not reduced to an angle between 0 and pi/4. + # The following are automatically handled: + # Argument of type: pi/2 +/- angle + # Argument of type: pi +/- angle + # Argument of type : 2k*pi +/- angle + + def f(rv): + if not isinstance(rv, C.TrigonometricFunction): + return rv + rv = rv.func(signsimp(rv.args[0])) + if S.Pi/4 < rv.args[0] < S.Pi/2: + fmap = {cos: sin, sin: cos, tan: cot, cot: tan, sec: csc, csc: sec} + rv = fmap[rv.func](S.Pi/2 - rv.args[0]) + return rv + + return bottom_up(rv, f) + + +def TR4(rv): + """Identify values of special angles. + + a= 0 pi/6 pi/4 pi/3 pi/2 + ---------------------------------------------------- + cos(a) 0 1/2 sqrt(2)/2 sqrt(3)/2 1 + sin(a) 1 sqrt(3)/2 sqrt(2)/2 1/2 0 + tan(a) 0 sqt(3)/3 1 sqrt(3) -- + + Examples + ======== + + >>> from sympy.simplify.fu import TR4 + >>> from sympy import pi + >>> from sympy import cos, sin, tan, cot + >>> for s in (0, pi/6, pi/4, pi/3, pi/2): + ... for f in (cos, sin, tan, cot): + ... print(f(s), end=' ') + ... print() + ... + 1 0 0 zoo + sqrt(3)/2 1/2 sqrt(3)/3 sqrt(3) + sqrt(2)/2 sqrt(2)/2 1 1 + 1/2 sqrt(3)/2 sqrt(3) sqrt(3)/3 + 0 1 zoo 0 + """ + # special values at 0, pi/6, pi/4, pi/3, pi/2 already handled + return rv + + +def _TR56(rv, f, g, h, max, pow): + """Helper for TR5 and TR6 to replace f**2 with h(g**2) + + Options + ======= + + max : controls size of exponent that can appear on f + e.g. if max=4 then f**4 will be changed to h(g**2)**2. + pow : controls whether the exponent must be a perfect power of 2 + e.g. if pow=True (and max >= 6) then f**6 will not be changed + but f**8 will be changed to h(g**2)**4 + + >>> from sympy.simplify.fu import _TR56 as T + >>> from sympy.abc import x + >>> from sympy import sin, cos + >>> h = lambda x: 1 - x + >>> T(sin(x)**3, sin, cos, h, 4, False) + sin(x)**3 + >>> T(sin(x)**6, sin, cos, h, 6, False) + (-cos(x)**2 + 1)**3 + >>> T(sin(x)**6, sin, cos, h, 6, True) + sin(x)**6 + >>> T(sin(x)**8, sin, cos, h, 10, True) + (-cos(x)**2 + 1)**4 + """ + + def _f(rv): + # I'm not sure if this transformation should target all even powers + # or only those expressible as powers of 2. Also, should it only + # make the changes in powers that appear in sums -- making an isolated + # change is not going to allow a simplification as far as I can tell. + if not (rv.is_Pow and rv.base.func == f): + return rv + + if rv.exp < 0: + return rv + if rv.exp > max: + return rv + if rv.exp == 2: + return h(g(rv.base.args[0])**2) + else: + if rv.exp == 4: + e = 2 + elif not pow: + if rv.exp % 2: + return rv + e = rv.exp//2 + else: + p = perfect_power(rv.exp) + if not p: + return rv + e = rv.exp//2 + return h(g(rv.base.args[0])**2)**e + + return bottom_up(rv, _f) + + +def TR5(rv, max=4, pow=False): + """Replacement of sin**2 with 1 - cos(x)**2. + + See _TR56 docstring for advanced use of ``max`` and ``pow``. + + Examples + ======== + + >>> from sympy.simplify.fu import TR5 + >>> from sympy.abc import x + >>> from sympy import sin + >>> TR5(sin(x)**2) + -cos(x)**2 + 1 + >>> TR5(sin(x)**-2) # unchanged + sin(x)**(-2) + >>> TR5(sin(x)**4) + (-cos(x)**2 + 1)**2 + """ + return _TR56(rv, sin, cos, lambda x: 1 - x, max=max, pow=pow) + + +def TR6(rv, max=4, pow=False): + """Replacement of cos**2 with 1 - sin(x)**2. + + See _TR56 docstring for advanced use of ``max`` and ``pow``. + + Examples + ======== + + >>> from sympy.simplify.fu import TR6 + >>> from sympy.abc import x + >>> from sympy import cos + >>> TR6(cos(x)**2) + -sin(x)**2 + 1 + >>> TR6(cos(x)**-2) #unchanged + cos(x)**(-2) + >>> TR6(cos(x)**4) + (-sin(x)**2 + 1)**2 + """ + return _TR56(rv, cos, sin, lambda x: 1 - x, max=max, pow=pow) + + +def TR7(rv): + """Lowering the degree of cos(x)**2 + + Examples + ======== + + >>> from sympy.simplify.fu import TR7 + >>> from sympy.abc import x + >>> from sympy import cos + >>> TR7(cos(x)**2) + cos(2*x)/2 + 1/2 + >>> TR7(cos(x)**2 + 1) + cos(2*x)/2 + 3/2 + + """ + + def f(rv): + if not (rv.is_Pow and rv.base.func == cos and rv.exp == 2): + return rv + return (1 + cos(2*rv.base.args[0]))/2 + + return bottom_up(rv, f) + + +def TR8(rv, first=True): + """Converting products of ``cos`` and/or ``sin`` to a sum or + difference of ``cos`` and or ``sin`` terms. + + Examples + ======== + + >>> from sympy.simplify.fu import TR8, TR7 + >>> from sympy import cos, sin + >>> TR8(cos(2)*cos(3)) + cos(5)/2 + cos(1)/2 + >>> TR8(cos(2)*sin(3)) + sin(5)/2 + sin(1)/2 + >>> TR8(sin(2)*sin(3)) + -cos(5)/2 + cos(1)/2 + """ + + def f(rv): + if not ( + rv.is_Mul or + rv.is_Pow and + rv.base.func in (cos, sin) and + (rv.exp.is_integer or rv.base.is_positive)): + return rv + + if first: + n, d = [expand_mul(i) for i in rv.as_numer_denom()] + newn = TR8(n, first=False) + newd = TR8(d, first=False) + if newn != n or newd != d: + rv = gcd_terms(newn/newd) + if rv.is_Mul and rv.args[0].is_Rational and \ + len(rv.args) == 2 and rv.args[1].is_Add: + rv = Mul(*rv.as_coeff_Mul()) + return rv + + args = {cos: [], sin: [], None: []} + for a in ordered(Mul.make_args(rv)): + if a.func in (cos, sin): + args[a.func].append(a.args[0]) + elif (a.is_Pow and a.exp.is_Integer and a.exp > 0 and \ + a.base.func in (cos, sin)): + # XXX this is ok but pathological expression could be handled + # more efficiently as in TRmorrie + args[a.base.func].extend([a.base.args[0]]*a.exp) + else: + args[None].append(a) + c = args[cos] + s = args[sin] + if not (c and s or len(c) > 1 or len(s) > 1): + return rv + + args = args[None] + n = min(len(c), len(s)) + for i in range(n): + a1 = s.pop() + a2 = c.pop() + args.append((sin(a1 + a2) + sin(a1 - a2))/2) + while len(c) > 1: + a1 = c.pop() + a2 = c.pop() + args.append((cos(a1 + a2) + cos(a1 - a2))/2) + if c: + args.append(cos(c.pop())) + while len(s) > 1: + a1 = s.pop() + a2 = s.pop() + args.append((-cos(a1 + a2) + cos(a1 - a2))/2) + if s: + args.append(sin(s.pop())) + return TR8(expand_mul(Mul(*args))) + + return bottom_up(rv, f) + + +def TR9(rv): + """Sum of ``cos`` or ``sin`` terms as a product of ``cos`` or ``sin``. + + Examples + ======== + + >>> from sympy.simplify.fu import TR9 + >>> from sympy import cos, sin + >>> TR9(cos(1) + cos(2)) + 2*cos(1/2)*cos(3/2) + >>> TR9(cos(1) + 2*sin(1) + 2*sin(2)) + cos(1) + 4*sin(3/2)*cos(1/2) + + If no change is made by TR9, no re-arrangement of the + expression will be made. For example, though factoring + of common term is attempted, if the factored expression + wasn't changed, the original expression will be returned: + + >>> TR9(cos(3) + cos(3)*cos(2)) + cos(3) + cos(2)*cos(3) + + """ + + def f(rv): + if not rv.is_Add: + return rv + + def do(rv, first=True): + # cos(a)+/-cos(b) can be combined into a product of cosines and + # sin(a)+/-sin(b) can be combined into a product of cosine and + # sine. + # + # If there are more than two args, the pairs which "work" will + # have a gcd extractable and the remaining two terms will have + # the above structure -- all pairs must be checked to find the + # ones that work. args that don't have a common set of symbols + # are skipped since this doesn't lead to a simpler formula and + # also has the arbitrariness of combining, for example, the x + # and y term instead of the y and z term in something like + # cos(x) + cos(y) + cos(z). + + if not rv.is_Add: + return rv + + args = list(ordered(rv.args)) + if len(args) != 2: + hit = False + for i in range(len(args)): + ai = args[i] + if ai is None: + continue + for j in range(i + 1, len(args)): + aj = args[j] + if aj is None: + continue + was = ai + aj + new = do(was) + if new != was: + args[i] = new # update in place + args[j] = None + hit = True + break # go to next i + if hit: + rv = Add(*[_f for _f in args if _f]) + if rv.is_Add: + rv = do(rv) + + return rv + + # two-arg Add + split = trig_split(*args) + if not split: + return rv + gcd, n1, n2, a, b, iscos = split + + # application of rule if possible + if iscos: + if n1 == n2: + return gcd*n1*2*cos((a + b)/2)*cos((a - b)/2) + if n1 < 0: + a, b = b, a + return -2*gcd*sin((a + b)/2)*sin((a - b)/2) + else: + if n1 == n2: + return gcd*n1*2*sin((a + b)/2)*cos((a - b)/2) + if n1 < 0: + a, b = b, a + return 2*gcd*cos((a + b)/2)*sin((a - b)/2) + + return process_common_addends(rv, do) # DON'T sift by free symbols + + return bottom_up(rv, f) + + +def TR10(rv, first=True): + """Separate sums in ``cos`` and ``sin``. + + Examples + ======== + + >>> from sympy.simplify.fu import TR10 + >>> from sympy.abc import a, b, c + >>> from sympy import cos, sin + >>> TR10(cos(a + b)) + -sin(a)*sin(b) + cos(a)*cos(b) + >>> TR10(sin(a + b)) + sin(a)*cos(b) + sin(b)*cos(a) + >>> TR10(sin(a + b + c)) + (-sin(a)*sin(b) + cos(a)*cos(b))*sin(c) + \ + (sin(a)*cos(b) + sin(b)*cos(a))*cos(c) + """ + + def f(rv): + if not rv.func in (cos, sin): + return rv + + f = rv.func + arg = rv.args[0] + if arg.is_Add: + if first: + args = list(ordered(arg.args)) + else: + args = list(arg.args) + a = args.pop() + b = Add._from_args(args) + if b.is_Add: + if f == sin: + return sin(a)*TR10(cos(b), first=False) + \ + cos(a)*TR10(sin(b), first=False) + else: + return cos(a)*TR10(cos(b), first=False) - \ + sin(a)*TR10(sin(b), first=False) + else: + if f == sin: + return sin(a)*cos(b) + cos(a)*sin(b) + else: + return cos(a)*cos(b) - sin(a)*sin(b) + return rv + + return bottom_up(rv, f) + + +def TR10i(rv): + """Sum of products to function of sum. + + Examples + ======== + + >>> from sympy.simplify.fu import TR10i + >>> from sympy import cos, sin, pi, Add, Mul, sqrt, Symbol + >>> from sympy.abc import x, y + + >>> TR10i(cos(1)*cos(3) + sin(1)*sin(3)) + cos(2) + >>> TR10i(cos(1)*sin(3) + sin(1)*cos(3) + cos(3)) + cos(3) + sin(4) + >>> TR10i(sqrt(2)*cos(x)*x + sqrt(6)*sin(x)*x) + 2*sqrt(2)*x*sin(x + pi/6) + + """ + global _ROOT2, _ROOT3, _invROOT3 + if _ROOT2 is None: + _roots() + + def f(rv): + if not rv.is_Add: + return rv + + def do(rv, first=True): + # args which can be expressed as A*(cos(a)*cos(b)+/-sin(a)*sin(b)) + # or B*(cos(a)*sin(b)+/-cos(b)*sin(a)) can be combined into + # A*f(a+/-b) where f is either sin or cos. + # + # If there are more than two args, the pairs which "work" will have + # a gcd extractable and the remaining two terms will have the above + # structure -- all pairs must be checked to find the ones that + # work. + + if not rv.is_Add: + return rv + + args = list(ordered(rv.args)) + if len(args) != 2: + hit = False + for i in range(len(args)): + ai = args[i] + if ai is None: + continue + for j in range(i + 1, len(args)): + aj = args[j] + if aj is None: + continue + was = ai + aj + new = do(was) + if new != was: + args[i] = new # update in place + args[j] = None + hit = True + break # go to next i + if hit: + rv = Add(*[_f for _f in args if _f]) + if rv.is_Add: + rv = do(rv) + + return rv + + # two-arg Add + split = trig_split(*args, **dict(two=True)) + if not split: + return rv + gcd, n1, n2, a, b, same = split + + # identify and get c1 to be cos then apply rule if possible + if same: # coscos, sinsin + gcd = n1*gcd + if n1 == n2: + return gcd*cos(a - b) + return gcd*cos(a + b) + else: #cossin, cossin + gcd = n1*gcd + if n1 == n2: + return gcd*sin(a + b) + return gcd*sin(b - a) + + rv = process_common_addends( + rv, do, lambda x: tuple(ordered(x.free_symbols))) + + # need to check for inducible pairs in ratio of sqrt(3):1 that + # appeared in different lists when sorting by coefficient + while rv.is_Add: + byrad = defaultdict(list) + for a in rv.args: + hit = 0 + if a.is_Mul: + for ai in a.args: + if ai.is_Pow and ai.exp is S.Half and \ + ai.base.is_Integer: + byrad[ai].append(a) + hit = 1 + break + if not hit: + byrad[S.One].append(a) + + # no need to check all pairs -- just check for the onees + # that have the right ratio + args = [] + for a in byrad: + for b in [_ROOT3*a, _invROOT3]: + if b in byrad: + for i in range(len(byrad[a])): + if byrad[a][i] is None: + continue + for j in range(len(byrad[b])): + if byrad[b][j] is None: + continue + was = Add(byrad[a][i] + byrad[b][j]) + new = do(was) + if new != was: + args.append(new) + byrad[a][i] = None + byrad[b][j] = None + break + if args: + rv = Add(*(args + [Add(*[_f for _f in v if _f]) + for v in list(byrad.values())])) + else: + rv = do(rv) # final pass to resolve any new inducible pairs + break + + return rv + + return bottom_up(rv, f) + + +def TR11(rv, base=None): + """Function of double angle to product. The ``base`` argument can be used + to indicate what is the un-doubled argument, e.g. if 3*pi/7 is the base + then cosine and sine functions with argument 6*pi/7 will be replaced. + + Examples + ======== + + >>> from sympy.simplify.fu import TR11 + >>> from sympy import cos, sin, pi + >>> from sympy.abc import x + >>> TR11(sin(2*x)) + 2*sin(x)*cos(x) + >>> TR11(cos(2*x)) + -sin(x)**2 + cos(x)**2 + >>> TR11(sin(4*x)) + 4*(-sin(x)**2 + cos(x)**2)*sin(x)*cos(x) + >>> TR11(sin(4*x/3)) + 4*(-sin(x/3)**2 + cos(x/3)**2)*sin(x/3)*cos(x/3) + + If the arguments are simply integers, no change is made + unless a base is provided: + + >>> TR11(cos(2)) + cos(2) + >>> TR11(cos(4), 2) + -sin(2)**2 + cos(2)**2 + + There is a subtle issue here in that autosimplification will convert + some higher angles to lower angles + + >>> cos(6*pi/7) + cos(3*pi/7) + -cos(pi/7) + cos(3*pi/7) + + The 6*pi/7 angle is now pi/7 but can be targeted with TR11 by supplying + the 3*pi/7 base: + + >>> TR11(_, 3*pi/7) + -sin(3*pi/7)**2 + cos(3*pi/7)**2 + cos(3*pi/7) + + """ + + def f(rv): + if not rv.func in (cos, sin): + return rv + + if base: + f = rv.func + t = f(base*2) + co = S.One + if t.is_Mul: + co, t = t.as_coeff_Mul() + if not t.func in (cos, sin): + return rv + if rv.args[0] == t.args[0]: + c = cos(base) + s = sin(base) + if f is cos: + return (c**2 - s**2)/co + else: + return 2*c*s/co + return rv + + elif not rv.args[0].is_Number: + # make a change if the leading coefficient's numerator is + # divisible by 2 + c, m = rv.args[0].as_coeff_Mul(rational=True) + if c.p % 2 == 0: + arg = c.p//2*m/c.q + c = TR11(cos(arg)) + s = TR11(sin(arg)) + if rv.func == sin: + rv = 2*s*c + else: + rv = c**2 - s**2 + return rv + + return bottom_up(rv, f) + + +def TR12(rv, first=True): + """Separate sums in ``tan``. + + Examples + ======== + + >>> from sympy.simplify.fu import TR12 + >>> from sympy.abc import x, y + >>> from sympy import tan + >>> from sympy.simplify.fu import TR12 + >>> TR12(tan(x + y)) + (tan(x) + tan(y))/(-tan(x)*tan(y) + 1) + """ + + def f(rv): + if not rv.func == tan: + return rv + + arg = rv.args[0] + if arg.is_Add: + if first: + args = list(ordered(arg.args)) + else: + args = list(arg.args) + a = args.pop() + b = Add._from_args(args) + if b.is_Add: + tb = TR12(tan(b), first=False) + else: + tb = tan(b) + return (tan(a) + tb)/(1 - tan(a)*tb) + return rv + + return bottom_up(rv, f) + + +def TR12i(rv): + """Combine tan arguments as + (tan(y) + tan(x))/(tan(x)*tan(y) - 1) -> -tan(x + y) + + Examples + ======== + + >>> from sympy.simplify.fu import TR12i + >>> from sympy import tan + >>> from sympy.abc import a, b, c + >>> ta, tb, tc = [tan(i) for i in (a, b, c)] + >>> TR12i((ta + tb)/(-ta*tb + 1)) + tan(a + b) + >>> TR12i((ta + tb)/(ta*tb - 1)) + -tan(a + b) + >>> TR12i((-ta - tb)/(ta*tb - 1)) + tan(a + b) + >>> eq = (ta + tb)/(-ta*tb + 1)**2*(-3*ta - 3*tc)/(2*(ta*tc - 1)) + >>> TR12i(eq.expand()) + -3*tan(a + b)*tan(a + c)/(2*(tan(a) + tan(b) - 1)) + """ + from sympy import factor, fraction, factor_terms + + def f(rv): + if not (rv.is_Add or rv.is_Mul or rv.is_Pow): + return rv + + n, d = rv.as_numer_denom() + if not d.args or not n.args: + return rv + + dok = {} + + def ok(di): + m = as_f_sign_1(di) + if m: + g, f, s = m + if s is S.NegativeOne and f.is_Mul and len(f.args) == 2 and \ + all(fi.func is tan for fi in f.args): + return g, f + + dargs = list(Mul.make_args(d)) + for i, di in enumerate(dargs): + m = ok(di) + if m: + g, t = m + s = Add(*[_.args[0] for _ in t.args]) + dok[s] = S.One + dargs[i] = g + continue + if di.is_Add: + di = factor(di) + if di.is_Mul: + dargs.extend(di.args) + dargs[i] = S.One + elif di.is_Pow and (di.exp.is_integer or di.base.is_positive): + m = ok(di.base) + if m: + g, t = m + s = Add(*[_.args[0] for _ in t.args]) + dok[s] = di.exp + dargs[i] = g**di.exp + else: + di = factor(di) + if di.is_Mul: + dargs.extend(di.args) + dargs[i] = S.One + if not dok: + return rv + + def ok(ni): + if ni.is_Add and len(ni.args) == 2: + a, b = ni.args + if a.func is tan and b.func is tan: + return a, b + nargs = list(Mul.make_args(factor_terms(n))) + hit = False + for i, ni in enumerate(nargs): + m = ok(ni) + if not m: + m = ok(-ni) + if m: + nargs[i] = S.NegativeOne + else: + if ni.is_Add: + ni = factor(ni) + if ni.is_Mul: + nargs.extend(ni.args) + nargs[i] = S.One + continue + elif ni.is_Pow and ( + ni.exp.is_integer or ni.base.is_positive): + m = ok(ni.base) + if m: + nargs[i] = S.One + else: + ni = factor(ni) + if ni.is_Mul: + nargs.extend(ni.args) + nargs[i] = S.One + continue + else: + continue + else: + nargs[i] = S.One + hit = True + s = Add(*[_.args[0] for _ in m]) + ed = dok[s] + newed = ed.extract_additively(S.One) + if newed is not None: + if newed: + dok[s] = newed + else: + dok.pop(s) + nargs[i] *= -tan(s) + + if hit: + rv = Mul(*nargs)/Mul(*dargs)/Mul(*[(Add(*[ + tan(a) for a in i.args]) - 1)**e for i, e in dok.items()]) + + return rv + + return bottom_up(rv, f) + + +def TR13(rv): + """Change products of ``tan`` or ``cot``. + + Examples + ======== + + >>> from sympy.simplify.fu import TR13 + >>> from sympy import tan, cot, cos + >>> TR13(tan(3)*tan(2)) + -tan(2)/tan(5) - tan(3)/tan(5) + 1 + >>> TR13(cot(3)*cot(2)) + cot(2)*cot(5) + 1 + cot(3)*cot(5) + """ + + def f(rv): + if not rv.is_Mul: + return rv + + # XXX handle products of powers? or let power-reducing handle it? + args = {tan: [], cot: [], None: []} + for a in ordered(Mul.make_args(rv)): + if a.func in (tan, cot): + args[a.func].append(a.args[0]) + else: + args[None].append(a) + t = args[tan] + c = args[cot] + if len(t) < 2 and len(c) < 2: + return rv + args = args[None] + while len(t) > 1: + t1 = t.pop() + t2 = t.pop() + args.append(1 - (tan(t1)/tan(t1 + t2) + tan(t2)/tan(t1 + t2))) + if t: + args.append(tan(t.pop())) + while len(c) > 1: + t1 = c.pop() + t2 = c.pop() + args.append(1 + cot(t1)*cot(t1 + t2) + cot(t2)*cot(t1 + t2)) + if c: + args.append(cot(c.pop())) + return Mul(*args) + + return bottom_up(rv, f) + + +def TRmorrie(rv): + """Returns cos(x)*cos(2*x)*...*cos(2**(k-1)*x) -> sin(2**k*x)/(2**k*sin(x)) + + Examples + ======== + + >>> from sympy.simplify.fu import TRmorrie, TR8, TR3 + >>> from sympy.abc import x + >>> from sympy import Mul, cos, pi + >>> TRmorrie(cos(x)*cos(2*x)) + sin(4*x)/(4*sin(x)) + >>> TRmorrie(7*Mul(*[cos(x) for x in range(10)])) + 7*sin(12)*sin(16)*cos(5)*cos(7)*cos(9)/(64*sin(1)*sin(3)) + + Sometimes autosimplification will cause a power to be + not recognized. e.g. in the following, cos(4*pi/7) automatically + simplifies to -cos(3*pi/7) so only 2 of the 3 terms are + recognized: + + >>> TRmorrie(cos(pi/7)*cos(2*pi/7)*cos(4*pi/7)) + -sin(3*pi/7)*cos(3*pi/7)/(4*sin(pi/7)) + + A touch by TR8 resolves the expression to a Rational + + >>> TR8(_) + -1/8 + + In this case, if eq is unsimplified, the answer is obtained + directly: + + >>> eq = cos(pi/9)*cos(2*pi/9)*cos(3*pi/9)*cos(4*pi/9) + >>> TRmorrie(eq) + 1/16 + + But if angles are made canonical with TR3 then the answer + is not simplified without further work: + + >>> TR3(eq) + sin(pi/18)*cos(pi/9)*cos(2*pi/9)/2 + >>> TRmorrie(_) + sin(pi/18)*sin(4*pi/9)/(8*sin(pi/9)) + >>> TR8(_) + cos(7*pi/18)/(16*sin(pi/9)) + >>> TR3(_) + 1/16 + + The original expression would have resolve to 1/16 directly with TR8, + however: + + >>> TR8(eq) + 1/16 + + References + ========== + + http://en.wikipedia.org/wiki/Morrie%27s_law + + """ + + def f(rv): + if not rv.is_Mul: + return rv + + args = defaultdict(list) + coss = {} + other = [] + for c in rv.args: + b, e = c.as_base_exp() + if e.is_Integer and b.func is cos: + co, a = b.args[0].as_coeff_Mul() + args[a].append(co) + coss[b] = e + else: + other.append(c) + + new = [] + for a in args: + c = args[a] + c.sort() + no = [] + while c: + k = 0 + cc = ci = c[0] + while cc in c: + k += 1 + cc *= 2 + if k > 1: + newarg = sin(2**k*ci*a)/2**k/sin(ci*a) + # see how many times this can be taken + take = None + ccs = [] + for i in range(k): + cc /= 2 + key = cos(a*cc, evaluate=False) + ccs.append(cc) + take = min(coss[key], take or coss[key]) + # update exponent counts + for i in range(k): + cc = ccs.pop() + key = cos(a*cc, evaluate=False) + coss[key] -= take + if not coss[key]: + c.remove(cc) + new.append(newarg**take) + else: + no.append(c.pop(0)) + c[:] = no + + if new: + rv = Mul(*(new + other + [ + cos(k*a, evaluate=False) for a in args for k in args[a]])) + + return rv + + return bottom_up(rv, f) + + +def TR14(rv, first=True): + """Convert factored powers of sin and cos identities into simpler + expressions. + + Examples + ======== + + >>> from sympy.simplify.fu import TR14 + >>> from sympy.abc import x, y + >>> from sympy import cos, sin + >>> TR14((cos(x) - 1)*(cos(x) + 1)) + -sin(x)**2 + >>> TR14((sin(x) - 1)*(sin(x) + 1)) + -cos(x)**2 + >>> p1 = (cos(x) + 1)*(cos(x) - 1) + >>> p2 = (cos(y) - 1)*2*(cos(y) + 1) + >>> p3 = (3*(cos(y) - 1))*(3*(cos(y) + 1)) + >>> TR14(p1*p2*p3*(x - 1)) + -18*(x - 1)*sin(x)**2*sin(y)**4 + + """ + + def f(rv): + if not rv.is_Mul: + return rv + + if first: + # sort them by location in numerator and denominator + # so the code below can just deal with positive exponents + n, d = rv.as_numer_denom() + if d is not S.One: + newn = TR14(n, first=False) + newd = TR14(d, first=False) + if newn != n or newd != d: + rv = newn/newd + return rv + + other = [] + process = [] + for a in rv.args: + if a.is_Pow: + b, e = a.as_base_exp() + if not (e.is_integer or b.is_positive): + other.append(a) + continue + a = b + else: + e = S.One + m = as_f_sign_1(a) + if not m or m[1].func not in (cos, sin): + if e is S.One: + other.append(a) + else: + other.append(a**e) + continue + g, f, si = m + process.append((g, e.is_Number, e, f, si, a)) + + # sort them to get like terms next to each other + process = list(ordered(process)) + + # keep track of whether there was any change + nother = len(other) + + # access keys + keys = (g, t, e, f, si, a) = list(range(6)) + + while process: + A = process.pop(0) + if process: + B = process[0] + + if A[e].is_Number and B[e].is_Number: + # both exponents are numbers + if A[f] == B[f]: + if A[si] != B[si]: + B = process.pop(0) + take = min(A[e], B[e]) + + # reinsert any remainder + # the B will likely sort after A so check it first + if B[e] != take: + rem = [B[i] for i in keys] + rem[e] -= take + process.insert(0, rem) + elif A[e] != take: + rem = [A[i] for i in keys] + rem[e] -= take + process.insert(0, rem) + + if A[f].func is cos: + t = sin + else: + t = cos + other.append((-A[g]*B[g]*t(A[f].args[0])**2)**take) + continue + + elif A[e] == B[e]: + # both exponents are equal symbols + if A[f] == B[f]: + if A[si] != B[si]: + B = process.pop(0) + take = A[e] + if A[f].func is cos: + t = sin + else: + t = cos + other.append((-A[g]*B[g]*t(A[f].args[0])**2)**take) + continue + + # either we are done or neither condition above applied + other.append(A[a]**A[e]) + + if len(other) != nother: + rv = Mul(*other) + + return rv + + return bottom_up(rv, f) + + +def TR15(rv, max=4, pow=False): + """Convert sin(x)*-2 to 1 + cot(x)**2. + + See _TR56 docstring for advanced use of ``max`` and ``pow``. + + Examples + ======== + + >>> from sympy.simplify.fu import TR15 + >>> from sympy.abc import x + >>> from sympy import cos, sin + >>> TR15(1 - 1/sin(x)**2) + -cot(x)**2 + + """ + + def f(rv): + if not (isinstance(rv, Pow) and rv.base.func is sin): + return rv + + ia = 1/rv + a = _TR56(ia, sin, cot, lambda x: 1 + x, max=max, pow=pow) + if a != ia: + rv = a + return rv + + return bottom_up(rv, f) + + +def TR16(rv, max=4, pow=False): + """Convert cos(x)*-2 to 1 + tan(x)**2. + + See _TR56 docstring for advanced use of ``max`` and ``pow``. + + Examples + ======== + + >>> from sympy.simplify.fu import TR16 + >>> from sympy.abc import x + >>> from sympy import cos, sin + >>> TR16(1 - 1/cos(x)**2) + -tan(x)**2 + + """ + + def f(rv): + if not (isinstance(rv, Pow) and rv.base.func is cos): + return rv + + ia = 1/rv + a = _TR56(ia, cos, tan, lambda x: 1 + x, max=max, pow=pow) + if a != ia: + rv = a + return rv + + return bottom_up(rv, f) + + +def TR111(rv): + """Convert f(x)**-i to g(x)**i where either ``i`` is an integer + or the base is positive and f, g are: tan, cot; sin, csc; or cos, sec. + + Examples + ======== + + >>> from sympy.simplify.fu import TR111 + >>> from sympy.abc import x + >>> from sympy import tan + >>> TR111(1 - 1/tan(x)**2) + -cot(x)**2 + 1 + + """ + + def f(rv): + if not ( + isinstance(rv, Pow) and + (rv.base.is_positive or rv.exp.is_integer and rv.exp.is_negative)): + return rv + + if rv.base.func is tan: + return cot(rv.base.args[0])**-rv.exp + elif rv.base.func is sin: + return csc(rv.base.args[0])**-rv.exp + elif rv.base.func is cos: + return sec(rv.base.args[0])**-rv.exp + return rv + + return bottom_up(rv, f) + + +def TR22(rv, max=4, pow=False): + """Convert tan(x)**2 to sec(x)**2 - 1 and cot(x)**2 to csc(x)**2 - 1. + + See _TR56 docstring for advanced use of ``max`` and ``pow``. + + Examples + ======== + + >>> from sympy.simplify.fu import TR22 + >>> from sympy.abc import x + >>> from sympy import tan, cot + >>> TR22(1 + tan(x)**2) + sec(x)**2 + >>> TR22(1 + cot(x)**2) + csc(x)**2 + + """ + + def f(rv): + if not (isinstance(rv, Pow) and rv.base.func in (cot, tan)): + return rv + + rv = _TR56(rv, tan, sec, lambda x: x - 1, max=max, pow=pow) + rv = _TR56(rv, cot, csc, lambda x: x - 1, max=max, pow=pow) + return rv + + return bottom_up(rv, f) + + +def L(rv): + """Return count of trigonometric functions in expression. + + Examples + ======== + + >>> from sympy.simplify.fu import L + >>> from sympy.abc import x + >>> from sympy import cos, sin + >>> L(cos(x)+sin(x)) + 2 + """ + return S(rv.count(C.TrigonometricFunction)) + + +# ============== end of basic Fu-like tools ===================== + +if SYMPY_DEBUG: + (TR0, TR1, TR2, TR3, TR4, TR5, TR6, TR7, TR8, TR9, TR10, TR11, TR12, TR13, + TR2i, TRmorrie, TR14, TR15, TR16, TR12i, TR111, TR22 + )= list(map(debug, + (TR0, TR1, TR2, TR3, TR4, TR5, TR6, TR7, TR8, TR9, TR10, TR11, TR12, TR13, + TR2i, TRmorrie, TR14, TR15, TR16, TR12i, TR111, TR22))) + + +# tuples are chains -- (f, g) -> lambda x: g(f(x)) +# lists are choices -- [f, g] -> lambda x: min(f(x), g(x), key=objective) + +CTR1 = [(TR5, TR0), (TR6, TR0), identity] + +CTR2 = (TR11, [(TR5, TR0), (TR6, TR0), TR0]) + +CTR3 = [(TRmorrie, TR8, TR0), (TRmorrie, TR8, TR10i, TR0), identity] + +CTR4 = [(TR4, TR10i), identity] + +RL1 = (TR4, TR3, TR4, TR12, TR4, TR13, TR4, TR0) + + +# XXX it's a little unclear how this one is to be implemented +# see Fu paper of reference, page 7. What is the Union symbol refering to? +# The diagram shows all these as one chain of transformations, but the +# text refers to them being applied independently. Also, a break +# if L starts to increase has not been implemented. +RL2 = [ + (TR4, TR3, TR10, TR4, TR3, TR11), + (TR5, TR7, TR11, TR4), + (CTR3, CTR1, TR9, CTR2, TR4, TR9, TR9, CTR4), + identity, + ] + + +def fu(rv, measure=lambda x: (L(x), x.count_ops())): + """Attempt to simplify expression by using transformation rules given + in the algorithm by Fu et al. + + :func:`fu` will try to minimize the objective function ``measure``. + By default this first minimizes the number of trig terms and then minimizes + the number of total operations. + + Examples + ======== + + >>> from sympy.simplify.fu import fu + >>> from sympy import cos, sin, tan, pi, S, sqrt + >>> from sympy.abc import x, y, a, b + + >>> fu(sin(50)**2 + cos(50)**2 + sin(pi/6)) + 3/2 + >>> fu(sqrt(6)*cos(x) + sqrt(2)*sin(x)) + 2*sqrt(2)*sin(x + pi/3) + + CTR1 example + + >>> eq = sin(x)**4 - cos(y)**2 + sin(y)**2 + 2*cos(x)**2 + >>> fu(eq) + cos(x)**4 - 2*cos(y)**2 + 2 + + CTR2 example + + >>> fu(S.Half - cos(2*x)/2) + sin(x)**2 + + CTR3 example + + >>> fu(sin(a)*(cos(b) - sin(b)) + cos(a)*(sin(b) + cos(b))) + sqrt(2)*sin(a + b + pi/4) + + CTR4 example + + >>> fu(sqrt(3)*cos(x)/2 + sin(x)/2) + sin(x + pi/3) + + Example 1 + + >>> fu(1-sin(2*x)**2/4-sin(y)**2-cos(x)**4) + -cos(x)**2 + cos(y)**2 + + Example 2 + + >>> fu(cos(4*pi/9)) + sin(pi/18) + >>> fu(cos(pi/9)*cos(2*pi/9)*cos(3*pi/9)*cos(4*pi/9)) + 1/16 + + Example 3 + + >>> fu(tan(7*pi/18)+tan(5*pi/18)-sqrt(3)*tan(5*pi/18)*tan(7*pi/18)) + -sqrt(3) + + Objective function example + >>> fu(sin(x)/cos(x)) # default objective function + tan(x) + >>> fu(sin(x)/cos(x), measure=lambda x: -x.count_ops()) # maximize op count + sin(x)/cos(x) + + References + ========== + http://rfdz.ph-noe.ac.at/fileadmin/Mathematik_Uploads/ACDCA/ + DESTIME2006/DES_contribs/Fu/simplification.pdf + """ + fRL1 = greedy(RL1, measure) + fRL2 = greedy(RL2, measure) + + was = rv + rv = sympify(rv) + rv = TR1(rv) + if rv.has(tan, cot): + rv1 = fRL1(rv) + if (measure(rv1) < measure(rv)): + rv = rv1 + if rv.has(tan, cot): + rv = TR2(rv) + if rv.has(sin, cos): + rv1 = fRL2(rv) + rv2 = TR8(TRmorrie(rv1)) + rv = min([was, rv, rv1, rv2], key=measure) + return min(TR2i(rv), rv, key=measure) + + +def process_common_addends(rv, do, key2=None, key1=True): + """Apply ``do`` to addends of ``rv`` that (if key1=True) share at least + a common absolute value of their coefficient and the value of ``key2`` when + applied to the argument. If ``key1`` is False ``key2`` must be supplied and + will be the only key applied. + """ + + # collect by absolute value of coefficient and key2 + absc = defaultdict(list) + if key1: + for a in rv.args: + c, a = a.as_coeff_Mul() + if c < 0: + c = -c + a = -a # put the sign on `a` + absc[(c, key2(a) if key2 else 1)].append(a) + elif key2: + for a in rv.args: + absc[(S.One, key2(a))].append(a) + else: + raise ValueError('must have at least one key') + + args = [] + hit = False + for k in absc: + v = absc[k] + c, _ = k + if len(v) > 1: + e = Add(*v, **dict(evaluate=False)) + new = do(e) + if new != e: + e = new + hit = True + args.append(c*e) + else: + args.append(c*v[0]) + if hit: + rv = Add(*args) + + return rv + + +fufuncs = ''' + TR0 TR1 TR2 TR3 TR4 TR5 TR6 TR7 TR8 TR9 TR10 TR10i TR11 + TR12 TR13 L TR2i TRmorrie TR12i + TR14 TR15 TR16 TR111 TR22'''.split() +FU = dict(list(zip(fufuncs, list(map(locals().get, fufuncs))))) + + +def _roots(): + global _ROOT2, _ROOT3, _invROOT3 + _ROOT2, _ROOT3 = sqrt(2), sqrt(3) + _invROOT3 = 1/_ROOT3 +_ROOT2 = None + + +def trig_split(a, b, two=False): + """Return the gcd, s1, s2, a1, a2, bool where + + If two is False (default) then:: + a + b = gcd*(s1*f(a1) + s2*f(a2)) where f = cos if bool else sin + else: + if bool, a + b was +/- cos(a1)*cos(a2) +/- sin(a1)*sin(a2) and equals + n1*gcd*cos(a - b) if n1 == n2 else + n1*gcd*cos(a + b) + else a + b was +/- cos(a1)*sin(a2) +/- sin(a1)*cos(a2) and equals + n1*gcd*sin(a + b) if n1 = n2 else + n1*gcd*sin(b - a) + + Examples + ======== + >>> from sympy.simplify.fu import trig_split + >>> from sympy.abc import x, y, z + >>> from sympy import cos, sin, sqrt + + >>> trig_split(cos(x), cos(y)) + (1, 1, 1, x, y, True) + >>> trig_split(2*cos(x), -2*cos(y)) + (2, 1, -1, x, y, True) + >>> trig_split(cos(x)*sin(y), cos(y)*sin(y)) + (sin(y), 1, 1, x, y, True) + + >>> trig_split(cos(x), -sqrt(3)*sin(x), two=True) + (2, 1, -1, x, pi/6, False) + >>> trig_split(cos(x), sin(x), two=True) + (sqrt(2), 1, 1, x, pi/4, False) + >>> trig_split(cos(x), -sin(x), two=True) + (sqrt(2), 1, -1, x, pi/4, False) + >>> trig_split(sqrt(2)*cos(x), -sqrt(6)*sin(x), two=True) + (2*sqrt(2), 1, -1, x, pi/6, False) + >>> trig_split(-sqrt(6)*cos(x), -sqrt(2)*sin(x), two=True) + (-2*sqrt(2), 1, 1, x, pi/3, False) + >>> trig_split(cos(x)/sqrt(6), sin(x)/sqrt(2), two=True) + (sqrt(6)/3, 1, 1, x, pi/6, False) + >>> trig_split(-sqrt(6)*cos(x)*sin(y), -sqrt(2)*sin(x)*sin(y), two=True) + (-2*sqrt(2)*sin(y), 1, 1, x, pi/3, False) + + >>> trig_split(cos(x), sin(x)) + >>> trig_split(cos(x), sin(z)) + >>> trig_split(2*cos(x), -sin(x)) + >>> trig_split(cos(x), -sqrt(3)*sin(x)) + >>> trig_split(cos(x)*cos(y), sin(x)*sin(z)) + >>> trig_split(cos(x)*cos(y), sin(x)*sin(y)) + >>> trig_split(-sqrt(6)*cos(x), sqrt(2)*sin(x)*sin(y), two=True) + """ + global _ROOT2, _ROOT3, _invROOT3 + if _ROOT2 is None: + _roots() + + a, b = [Factors(i) for i in (a, b)] + ua, ub = a.normal(b) + gcd = a.gcd(b).as_expr() + n1 = n2 = 1 + if S.NegativeOne in ua.factors: + ua = ua.quo(S.NegativeOne) + n1 = -n1 + elif S.NegativeOne in ub.factors: + ub = ub.quo(S.NegativeOne) + n2 = -n2 + a, b = [i.as_expr() for i in (ua, ub)] + + def pow_cos_sin(a, two): + """Return ``a`` as a tuple (r, c, s) such that + ``a = (r or 1)*(c or 1)*(s or 1)``. + + Three arguments are returned (radical, c-factor, s-factor) as + long as the conditions set by ``two`` are met; otherwise None is + returned. If ``two`` is True there will be one or two non-None + values in the tuple: c and s or c and r or s and r or s or c with c + being a cosine function (if possible) else a sine, and s being a sine + function (if possible) else oosine. If ``two`` is False then there + will only be a c or s term in the tuple. + + ``two`` also require that either two cos and/or sin be present (with + the condition that if the functions are the same the arguments are + different or vice versa) or that a single cosine or a single sine + be present with an optional radical. + + If the above conditions dictated by ``two`` are not met then None + is returned. + """ + c = s = None + co = S.One + if a.is_Mul: + co, a = a.as_coeff_Mul() + if len(a.args) > 2 or not two: + return None + if a.is_Mul: + args = list(a.args) + else: + args = [a] + a = args.pop(0) + if a.func is cos: + c = a + elif a.func is sin: + s = a + elif a.is_Pow and a.exp is S.Half: # autoeval doesn't allow -1/2 + co *= a + else: + return None + if args: + b = args[0] + if b.func is cos: + if c: + s = b + else: + c = b + elif b.func is sin: + if s: + c = b + else: + s = b + elif b.is_Pow and b.exp is S.Half: + co *= b + else: + return None + return co if co is not S.One else None, c, s + elif a.func is cos: + c = a + elif a.func is sin: + s = a + if c is None and s is None: + return + co = co if co is not S.One else None + return co, c, s + + # get the parts + m = pow_cos_sin(a, two) + if m is None: + return + coa, ca, sa = m + m = pow_cos_sin(b, two) + if m is None: + return + cob, cb, sb = m + + # check them + if (not ca) and cb or ca and ca.func is sin: + coa, ca, sa, cob, cb, sb = cob, cb, sb, coa, ca, sa + n1, n2 = n2, n1 + if not two: # need cos(x) and cos(y) or sin(x) and sin(y) + c = ca or sa + s = cb or sb + if c.func is not s.func: + return None + return gcd, n1, n2, c.args[0], s.args[0], c.func is cos + else: + if not coa and not cob: + if (ca and cb and sa and sb): + if not ((ca.func is sa.func) is (cb.func is sb.func)): + return + args = set([j.args for j in (ca, sa)]) + if not all(i.args in args for i in (cb, sb)): + return + return gcd, n1, n2, ca.args[0], sa.args[0], ca.func is sa.func + if ca and sa or cb and sb or \ + two and (ca is None and sa is None or cb is None and sb is None): + return + c = ca or sa + s = cb or sb + if c.args != s.args: + return + if not coa: + coa = S.One + if not cob: + cob = S.One + if coa is cob: + gcd *= _ROOT2 + return gcd, n1, n2, c.args[0], pi/4, False + elif coa/cob == _ROOT3: + gcd *= 2*cob + return gcd, n1, n2, c.args[0], pi/3, False + elif coa/cob == _invROOT3: + gcd *= 2*coa + return gcd, n1, n2, c.args[0], pi/6, False + + +def as_f_sign_1(e): + """If ``e`` is a sum that can be written as ``g*(a + s)`` where + ``s`` is ``+/-1``, return ``g``, ``a``, and ``s`` where ``a`` does + not have a leading negative coefficient. + + Examples + ======== + + >>> from sympy.simplify.fu import as_f_sign_1 + >>> from sympy.abc import x + >>> as_f_sign_1(x + 1) + (1, x, 1) + >>> as_f_sign_1(x - 1) + (1, x, -1) + >>> as_f_sign_1(-x + 1) + (-1, x, -1) + >>> as_f_sign_1(-x - 1) + (-1, x, 1) + >>> as_f_sign_1(2*x + 2) + (2, x, 1) + """ + if not e.is_Add or len(e.args) != 2: + return + # exact match + a, b = e.args + if a in (S.NegativeOne, S.One): + g = S.One + if b.is_Mul and b.args[0].is_Number and b.args[0] < 0: + a, b = -a, -b + g = -g + return g, b, a + # gcd match + a, b = [Factors(i) for i in e.args] + ua, ub = a.normal(b) + gcd = a.gcd(b).as_expr() + if S.NegativeOne in ua.factors: + ua = ua.quo(S.NegativeOne) + n1 = -1 + n2 = 1 + elif S.NegativeOne in ub.factors: + ub = ub.quo(S.NegativeOne) + n1 = 1 + n2 = -1 + else: + n1 = n2 = 1 + a, b = [i.as_expr() for i in (ua, ub)] + if a is S.One: + a, b = b, a + n1, n2 = n2, n1 + if n1 == -1: + gcd = -gcd + n2 = -n2 + + if b is S.One: + return gcd, a, n2 + + +def _osborne(e): + """Replace all hyperbolic functions with trig functions using + the Osborne rule. + + References + ========== + + http://en.wikipedia.org/wiki/Hyperbolic_function + """ + + def f(rv): + if not isinstance(rv, C.HyperbolicFunction): + return rv + if rv.func is sinh: + return I*sin(rv.args[0]) + elif rv.func is cosh: + return cos(rv.args[0]) + elif rv.func is tanh: + return I*tan(rv.args[0]) + elif rv.func is coth: + return cot(rv.args[0])/I + else: + raise NotImplementedError('unhandled %s' % rv.func) + + return bottom_up(e, f) + + +def _osbornei(e): + """Replace all trig functions with hyperbolic functions using + the Osborne rule. + + References + ========== + + http://en.wikipedia.org/wiki/Hyperbolic_function + """ + + def f(rv): + if not isinstance(rv, C.TrigonometricFunction): + return rv + if rv.func is sin: + return sinh(rv.args[0])/I + elif rv.func is cos: + return cosh(rv.args[0]) + elif rv.func is tan: + return tanh(rv.args[0])/I + elif rv.func is cot: + return coth(rv.args[0])*I + elif rv.func is sec: + return 1/cosh(rv.args[0]) + elif rv.func is csc: + return I/sinh(rv.args[0]) + else: + raise NotImplementedError('unhandled %s' % rv.func) + + return bottom_up(e, f) + + +def hyper_as_trig(rv): + """Return an expression containing hyperbolic functions in terms + of trigonometric functions. Any trigonometric functions initially + present are replaced with Dummy symbols and the function to undo + the masking and the conversion back to hyperbolics is also returned. It + should always be true that:: + + t, f = hyper_as_trig(expr) + expr == f(t) + + Examples + ======== + + >>> from sympy.simplify.fu import hyper_as_trig, fu + >>> from sympy.abc import x + >>> from sympy import cosh, sinh + >>> eq = sinh(x)**2 + cosh(x)**2 + >>> t, f = hyper_as_trig(eq) + >>> f(fu(t)) + cosh(2*x) + + References + ========== + + http://en.wikipedia.org/wiki/Hyperbolic_function + """ + from sympy.simplify.simplify import signsimp + + # mask of trig functions + trigs = rv.atoms(C.TrigonometricFunction) + reps = [(t, Dummy()) for t in trigs] + masked = rv.xreplace(dict(reps)) + + # get inversion substitutions in place + reps = [(v, k) for k, v in reps] + + return _osborne(masked), lambda x: signsimp( + _osbornei(x).xreplace(dict(reps))) diff -Nru python3-sympy-0.7.2/sympy/simplify/hyperexpand.py python3-sympy-0.7.3/sympy/simplify/hyperexpand.py --- python3-sympy-0.7.2/sympy/simplify/hyperexpand.py 2012-10-17 03:02:22.000000000 +0000 +++ python3-sympy-0.7.3/sympy/simplify/hyperexpand.py 2013-07-13 17:53:32.000000000 +0000 @@ -56,54 +56,56 @@ # o Deciding if one index quadruple is reachable from another is tricky. For # this reason, we use hand-built routines to match and instantiate formulas. # -from sympy.core import S, Dummy, symbols, sympify, Tuple, expand, I, Mul -from sympy.core.mod import Mod -from sympy.functions.special.hyper import hyper -from sympy.utilities.misc import default_sort_key -from sympy import SYMPY_DEBUG +from collections import defaultdict -from sympy.utilities.timeutils import timethis -_timeit = timethis('meijerg') +from sympy import SYMPY_DEBUG +from sympy.core import (S, Dummy, symbols, sympify, Tuple, expand, I, pi, Mul, + EulerGamma, oo, zoo, expand_func, Add, nan, Expr) +from sympy.core.mod import Mod +from sympy.core.compatibility import default_sort_key, product +from sympy.utilities.iterables import sift +from sympy.functions import (exp, sqrt, root, log, lowergamma, cos, + besseli, gamma, uppergamma, expint, erf, sin, besselj, Ei, Ci, Si, Shi, + sinh, cosh, Chi, fresnels, fresnelc, polar_lift, exp_polar, floor, ceiling, + rf, factorial, lerchphi, Piecewise, re, elliptic_k, elliptic_e) +from sympy.functions.special.hyper import (hyper, HyperRep_atanh, + HyperRep_power1, HyperRep_power2, HyperRep_log1, HyperRep_asin1, + HyperRep_asin2, HyperRep_sqrts1, HyperRep_sqrts2, HyperRep_log2, + HyperRep_cosasin, HyperRep_sinasin, meijerg) +from sympy.simplify import powdenest, simplify, polarify, unpolarify +from sympy.polys import poly, Poly +from sympy.series import residue # leave add formulae at the top for easy reference - - def add_formulae(formulae): """ Create our knowledge base. """ + from sympy.matrices import Matrix a, b, c, z = symbols('a b c, z', cls=Dummy) def add(ap, bq, res): - formulae.append(Formula(ap, bq, z, res, (a, b, c))) + func = Hyper_Function(ap, bq) + formulae.append(Formula(func, z, res, (a, b, c))) def addb(ap, bq, B, C, M): - formulae.append(Formula(ap, bq, z, None, (a, b, c), B, C, M)) + func = Hyper_Function(ap, bq) + formulae.append(Formula(func, z, None, (a, b, c), B, C, M)) # Luke, Y. L. (1969), The Special Functions and Their Approximations, # Volume 1, section 6.2 - from sympy import (exp, sqrt, root, cosh, log, asin, atan, I, lowergamma, cos, - atanh, besseli, gamma, erf, pi, sin, besselj, Ei, - EulerGamma, Shi, sinh, cosh, Chi, diag, Matrix, - fresnels, fresnelc) - from sympy.functions.special.hyper import (HyperRep_atanh, - HyperRep_power1, HyperRep_power2, HyperRep_log1, HyperRep_asin1, - HyperRep_asin2, HyperRep_sqrts1, HyperRep_sqrts2, HyperRep_log2, - HyperRep_cosasin, HyperRep_sinasin) - from sympy import polar_lift, exp_polar - # 0F0 add((), (), exp(z)) # 1F0 - add((-a, ), (), HyperRep_power1(a, z)) + add((a, ), (), HyperRep_power1(-a, z)) # 2F1 addb((a, a - S.Half), (2*a, ), Matrix([HyperRep_power2(a, z), HyperRep_power2(a + S(1)/2, z)/2]), Matrix([[1, 0]]), - Matrix([[(a-S.Half)*z/(1 - z), (S.Half - a)*z/(1 - z)], + Matrix([[(a - S.Half)*z/(1 - z), (S.Half - a)*z/(1 - z)], [a/(1 - z), a*(z - 2)/(1 - z)]])) addb((1, 1), (2, ), Matrix([HyperRep_log1(z), 1]), Matrix([[-1/z, 0]]), @@ -116,11 +118,11 @@ Matrix([HyperRep_asin1(z), HyperRep_power1(-S(1)/2, z)]), Matrix([[1, 0]]), Matrix([[-S(1)/2, S(1)/2], [0, z/(1 - z)/2]])) - addb((-a, S.Half - a), (S.Half, ), - Matrix([HyperRep_sqrts1(a, z), -HyperRep_sqrts2(a - S(1)/2, z)]), + addb((a, S.Half + a), (S.Half, ), + Matrix([HyperRep_sqrts1(-a, z), -HyperRep_sqrts2(-a - S(1)/2, z)]), Matrix([[1, 0]]), - Matrix([[0, a], - [z*(2*a - 1)/2/(1 - z), S.Half - z*(2*a - 1)/(1 - z)]])) + Matrix([[0, -a], + [z*(-2*a - 1)/2/(1 - z), S.Half - z*(-2*a - 1)/(1 - z)]])) # A. P. Prudnikov, Yu. A. Brychkov and O. I. Marichev (1990). # Integrals and Series: More Special Functions, Vol. 3,. @@ -133,6 +135,20 @@ Matrix([HyperRep_asin2(z), 1]), Matrix([[1, 0]]), Matrix([[(z - S.Half)/(1 - z), 1/(1 - z)/2], [0, 0]])) + # Complete elliptic integrals K(z) and E(z), both a 2F1 function + #add((S.Half, S.Half), (S.One, ), 2*elliptic_k(z)/pi) + #add((-S.Half, S.Half), (S.One, ), 2*elliptic_e(z)/pi) + addb([S.Half, S.Half], [S.One], + Matrix([elliptic_k(z), elliptic_e(z)]), + Matrix([[2/pi, 0]]), + Matrix([[-S.Half, -1/(2*z-2)], + [-S.Half, S.Half]])) + addb([-S.Half, S.Half], [S.One], + Matrix([elliptic_k(z), elliptic_e(z)]), + Matrix([[0, 2/pi]]), + Matrix([[-S.Half, -1/(2*z-2)], + [-S.Half, S.Half]])) + # 3F2 addb([-S.Half, 1, 1], [S.Half, 2], Matrix([z*HyperRep_atanh(z), HyperRep_log1(z), 1]), @@ -173,17 +189,17 @@ # / (2*root(polar_lift(-1)*z,4))) # Manually tuned rule addb([1], [S(3)/4, S(5)/4], - Matrix([ sqrt(pi)*(I*sinh(2*sqrt(z))*fresnels(2*root(z,4)*exp(I*pi/4)/sqrt(pi)) - + cosh(2*sqrt(z))*fresnelc(2*root(z,4)*exp(I*pi/4)/sqrt(pi))) - * exp(-I*pi/4)/(2*root(z,4)), - sqrt(pi)*root(z,4)*(sinh(2*sqrt(z))*fresnelc(2*root(z,4)*exp(I*pi/4)/sqrt(pi)) - + I*cosh(2*sqrt(z))*fresnels(2*root(z,4)*exp(I*pi/4)/sqrt(pi))) + Matrix([ sqrt(pi)*(I*sinh(2*sqrt(z))*fresnels(2*root(z, 4)*exp(I*pi/4)/sqrt(pi)) + + cosh(2*sqrt(z))*fresnelc(2*root(z, 4)*exp(I*pi/4)/sqrt(pi))) + * exp(-I*pi/4)/(2*root(z, 4)), + sqrt(pi)*root(z, 4)*(sinh(2*sqrt(z))*fresnelc(2*root(z, 4)*exp(I*pi/4)/sqrt(pi)) + + I*cosh(2*sqrt(z))*fresnels(2*root(z, 4)*exp(I*pi/4)/sqrt(pi))) *exp(-I*pi/4)/2, 1 ]), Matrix([[1, 0, 0]]), Matrix([[-S(1)/4, 1, S(1)/4], - [ z, S(1)/4, 0], - [ 0, 0, 0]])) + [ z, S(1)/4, 0 ], + [ 0, 0, 0 ]])) # 2F2 addb([S.Half, a], [S(3)/2, a + 1], @@ -222,7 +238,7 @@ addb([], [S.Half, a, a + S.Half], Matrix([fp(2*a - 1, z), fm(2*a, z)*z**(S(1)/4), fm(2*a - 1, z)*sqrt(z), fp(2*a, z)*z**(S(3)/4)]) - * 2**(-2*a)*gamma(2*a)*z**((1 - 2*a)/4), + * 2**(-2*a)*gamma(2*a)*z**((1 - 2*a)/4), Matrix([[1, 0, 0, 0]]), Matrix([[0, 1, 0, 0], [0, S(1)/2 - a, 1, 0], @@ -247,8 +263,8 @@ addb([a], [a - S.Half, 2*a], Matrix([z**(S.Half - a)*besseli(a - S.Half, sqrt(z))**2, z**(1 - a)*besseli(a - S.Half, sqrt(z)) - *besseli(a - S(3)/2, sqrt(z)), - z**(S(3)/2 - a)*besseli(a-S(3)/2, sqrt(z))**2]), + *besseli(a - S(3)/2, sqrt(z)), + z**(S(3)/2 - a)*besseli(a - S(3)/2, sqrt(z))**2]), Matrix([[-gamma(a + S.Half)**2/4**(S.Half - a), 2*gamma(a - S.Half)*gamma(a + S.Half)/4**(1 - a), 0]]), @@ -260,7 +276,7 @@ + besseli(1 - b, sqrt(z))*besseli(b, sqrt(z))), besseli(-b, sqrt(z))*besseli(b, sqrt(z))]), Matrix([[1, 0, 0]]), - Matrix([[b-1, S(1)/2, 0], + Matrix([[b - 1, S(1)/2, 0], [z, 0, z], [0, S(1)/2, -b]])) addb([S(1)/2], [S(3)/2, S(3)/2], @@ -273,10 +289,16 @@ # Basic rule #add([S(3)/4], [S(3)/2,S(7)/4], 6*fresnels( exp(pi*I/4)*root(z,4)*2/sqrt(pi) ) / ( pi * (exp(pi*I/4)*root(z,4)*2/sqrt(pi))**3 ) ) # Manually tuned rule - addb([S(3)/4], [S(3)/2,S(7)/4], - Matrix([ fresnels( exp(pi*I/4)*root(z,4)*2/sqrt(pi) ) / ( pi * (exp(pi*I/4)*root(z,4)*2/sqrt(pi))**3 ), - sinh(2*sqrt(z))/sqrt(z), - cosh(2*sqrt(z)) ]), + addb([S(3)/4], [S(3)/2, S(7)/4], + Matrix( + [ fresnels( + exp( + pi*I/4)*root( + z, 4)*2/sqrt( + pi) ) / ( + pi * (exp(pi*I/4)*root(z, 4)*2/sqrt(pi))**3 ), + sinh(2*sqrt(z))/sqrt(z), + cosh(2*sqrt(z)) ]), Matrix([[6, 0, 0]]), Matrix([[-S(3)/4, S(1)/16, 0], [ 0, -S(1)/2, 1], @@ -286,10 +308,14 @@ # Basic rule #add([S(1)/4], [S(1)/2,S(5)/4], fresnelc( exp(pi*I/4)*root(z,4)*2/sqrt(pi) ) / ( exp(pi*I/4)*root(z,4)*2/sqrt(pi) ) ) # Manually tuned rule - addb([S(1)/4], [S(1)/2,S(5)/4], - Matrix([ sqrt(pi)*exp(-I*pi/4)*fresnelc(2*root(z,4)*exp(I*pi/4)/sqrt(pi))/(2*root(z,4)), - cosh(2*sqrt(z)), - sinh(2*sqrt(z))*sqrt(z) ]), + addb([S(1)/4], [S(1)/2, S(5)/4], + Matrix( + [ sqrt( + pi)*exp( + -I*pi/4)*fresnelc( + 2*root(z, 4)*exp(I*pi/4)/sqrt(pi))/(2*root(z, 4)), + cosh(2*sqrt(z)), + sinh(2*sqrt(z))*sqrt(z) ]), Matrix([[1, 0, 0]]), Matrix([[-S(1)/4, S(1)/4, 0 ], [ 0, 0, 1 ], @@ -321,9 +347,30 @@ [0, 0, 0, 0, 0], [0, 0, 0, 0, 0]])) + # 3F3 + # This is rule: http://functions.wolfram.com/07.31.03.0134.01 + # Initial reason to add it was a nice solution for + # integrate(erf(a*z)/z**2, z) and same for erfc and erfi. + # Basic rule + # add([1, 1, a], [2, 2, a+1], (a/(z*(a-1)**2)) * + # (1 - (-z)**(1-a) * (gamma(a) - uppergamma(a,-z)) + # - (a-1) * (EulerGamma + uppergamma(0,-z) + log(-z)) + # - exp(z))) + # Manually tuned rule + addb([1, 1, a], [2, 2, a+1], + Matrix([a*(log(-z) + expint(1, -z) + EulerGamma)/(z*(a**2 - 2*a + 1)), + a*(-z)**(-a)*(gamma(a) - uppergamma(a, -z))/(a - 1)**2, + a*exp(z)/(a**2 - 2*a + 1), + a/(z*(a**2 - 2*a + 1))]), + Matrix([[1-a, 1, -1/z, 1]]), + Matrix([[-1,0,-1/z,1], + [0,-a,1,0], + [0,0,z,0], + [0,0,0,-1]])) + def add_meijerg_formulae(formulae): - from sympy import Matrix, gamma, uppergamma, exp, Si, Ci, sin, cos, sqrt, pi + from sympy.matrices import Matrix a, b, c, z = list(map(Dummy, 'abcz')) rho = Dummy('rho') @@ -332,9 +379,9 @@ formulae.append(MeijerFormula(an, ap, bm, bq, z, [a, b, c, rho], B, C, M, matcher)) - def detect_uppergamma(iq): - x = iq.an[0] - y, z = iq.bm + def detect_uppergamma(func): + x = func.an[0] + y, z = func.bm swapped = False if not Mod((x - y).simplify(), 1): swapped = True @@ -344,19 +391,19 @@ l = [y, x] if swapped: l = [x, y] - return {rho: y, a: x - y}, IndexQuadruple([x], [], l, []) + return {rho: y, a: x - y}, G_Function([x], [], l, []) add([a + rho], [], [rho, a + rho], [], Matrix([gamma(1 - a)*z**rho*exp(z)*uppergamma(a, z), gamma(1 - a)*z**(a + rho)]), Matrix([[1, 0]]), - Matrix([[rho+z, -1], [0, a+rho]]), + Matrix([[rho + z, -1], [0, a + rho]]), detect_uppergamma) - def detect_3113(iq): + def detect_3113(func): """http://functions.wolfram.com/07.34.03.0984.01""" - x = iq.an[0] - u, v, w = iq.bm + x = func.an[0] + u, v, w = func.bm if Mod((u - v).simplify(), 1) == 0: if Mod((v - w).simplify(), 1) == 0: return @@ -373,10 +420,10 @@ if (Mod((x - x1).simplify(), 1) != 0 or Mod((x - x2).simplify(), 1) != 0 or Mod((x - y).simplify(), 1) != S(1)/2 or - x > x1 or x > x2): + x > x1 or x > x2): return - return {a: x}, IndexQuadruple([x], [], [x - S(1)/2 + t for t in sig], []) + return {a: x}, G_Function([x], [], [x - S(1)/2 + t for t in sig], []) s = sin(2*sqrt(z)) c_ = cos(2*sqrt(z)) @@ -396,7 +443,6 @@ def simp(expr): """ Efficiently simplify the rational function ``expr``. """ - from sympy import poly numer, denom = expr.as_numer_denom() c, numer, denom = poly(numer, z).cancel(poly(denom, z)) return c * numer.as_expr() / denom.as_expr() @@ -410,60 +456,44 @@ print(a, end=' ') print() +_mod1 = lambda x: Mod(x, 1) -class IndexPair(object): - """ Holds a pair of indices, and methods to compute their invariants. """ +class Hyper_Function(Expr): + """ A generalized hypergeometric function. """ - def __init__(self, ap, bq): - from sympy import expand, Tuple - self.ap = Tuple(*list(map(expand, ap))) - self.bq = Tuple(*list(map(expand, bq))) + def __new__(cls, ap, bq): + obj = super(Hyper_Function, cls).__new__(cls) + obj.ap = Tuple(*list(map(expand, ap))) + obj.bq = Tuple(*list(map(expand, bq))) + return obj + + @property + def args(self): + return (self.ap, self.bq) @property def sizes(self): return (len(self.ap), len(self.bq)) - def __repr__(self): - return 'IndexPair(%s, %s)' % (self.ap, self.bq) - - def compute_buckets(self, oabuckets=None, obbuckets=None): + @property + def gamma(self): """ - Partition ``ap`` and ``bq`` mod 1. - - Partition parameters ``ap``, ``bq`` into buckets, i.e., return two - dicts abuckets, bbuckets such that every key in (ab)buckets is a - rational in the range [0, 1) [represented either by a Rational or a Mod - object], and such that (ab)buckets[key] is a tuple of all elements of - respectively ``ap`` or ``bq`` that are congruent to ``key`` modulo 1. + Number of upper parameters that are negative integers - If oabuckets, obbuckets is specified, try to use the same Mod objects - for parameters where possible. - - >>> from sympy.simplify.hyperexpand import IndexPair - >>> from sympy import S - >>> ap = (S(1)/2, S(1)/3, S(-1)/2, -2) - >>> bq = (1, 2) - >>> IndexPair(ap, bq).compute_buckets() - ({0: (-2,), 1/3: (1/3,), 1/2: (1/2, -1/2)}, {0: (1, 2)}) + This is a transformation invariant. """ - from collections import defaultdict - - # TODO this should probably be cached somewhere - abuckets = defaultdict(tuple) - bbuckets = defaultdict(tuple) + return sum(bool(x.is_integer and x.is_negative) for x in self.ap) - # NOTE the new Mod object does so much canonization that we can ignore - # o(ab)buckets. + def _hashable_content(self): + return super(Hyper_Function, self)._hashable_content() + (self.ap, + self.bq) - for params, bucket in [(self.ap, abuckets), (self.bq, bbuckets)]: - for p in params: - bucket[Mod(p, 1)] += (p, ) - - return dict(abuckets), dict(bbuckets) + def __call__(self, arg): + return hyper(self.ap, self.bq, arg) def build_invariants(self): """ - Compute the invariant vector of (``ap``, ``bq``). + Compute the invariant vector. The invariant vector is: (gamma, ((s1, n1), ..., (sk, nk)), ((t1, m1), ..., (tr, mr))) @@ -476,7 +506,7 @@ If the index pair contains parameters, then this is not truly an invariant, since the parameters cannot be sorted uniquely mod1. - >>> from sympy.simplify.hyperexpand import IndexPair + >>> from sympy.simplify.hyperexpand import Hyper_Function >>> from sympy import S >>> ap = (S(1)/2, S(1)/3, S(-1)/2, -2) >>> bq = (1, 2) @@ -486,41 +516,34 @@ n1 = 1, n2 = 1, n2 = 2 r = 1, t1 = 0 m1 = 2: - >>> IndexPair(ap, bq).build_invariants() + >>> Hyper_Function(ap, bq).build_invariants() (1, ((0, 1), (1/3, 1), (1/2, 2)), ((0, 2),)) """ - abuckets, bbuckets = self.compute_buckets() - - gamma = 0 - if S(0) in abuckets: - gamma = len([x for x in abuckets[S(0)] if x < 0]) + abuckets, bbuckets = sift(self.ap, _mod1), sift(self.bq, _mod1) def tr(bucket): bucket = list(bucket.items()) if not any(isinstance(x[0], Mod) for x in bucket): bucket.sort(key=lambda x: x[0]) - bucket = tuple([(x[0], len(x[1])) for x in bucket]) + bucket = tuple([(mod, len(values)) for mod, values in bucket if + values]) return bucket - return (gamma, tr(abuckets), tr(bbuckets)) + return (self.gamma, tr(abuckets), tr(bbuckets)) - def difficulty(self, ip): - """ Estimate how many steps it takes to reach ``ip`` from self. + def difficulty(self, func): + """ Estimate how many steps it takes to reach ``func`` from self. Return -1 if impossible. """ - oabuckets, obbuckets = self.compute_buckets() - abuckets, bbuckets = ip.compute_buckets(oabuckets, obbuckets) - - gt0 = lambda x: (x > 0) is True - if S(0) in abuckets and (not S(0) in oabuckets or - len(list(filter(gt0, abuckets[S(0)]))) != \ - len(list(filter(gt0, oabuckets[S(0)])))): + if self.gamma != func.gamma: return -1 + oabuckets, obbuckets, abuckets, bbuckets = [sift(params, _mod1) for + params in (self.ap, self.bq, func.ap, func.bq)] diff = 0 for bucket, obucket in [(abuckets, oabuckets), (bbuckets, obbuckets)]: for mod in set(list(bucket.keys()) + list(obucket.keys())): if (not mod in bucket) or (not mod in obucket) \ - or len(bucket[mod]) != len(obucket[mod]): + or len(bucket[mod]) != len(obucket[mod]): return -1 l1 = list(bucket[mod]) l2 = list(obucket[mod]) @@ -531,19 +554,52 @@ return diff + def _is_suitable_origin(self): + """ + Decide if ``self`` is a suitable origin. + + A function is a suitable origin iff: + * none of the ai equals bj + n, with n a non-negative integer + * none of the ai is zero + * none of the bj is a non-positive integer + + Note that this gives meaningful results only when none of the indices + are symbolic. + + """ + for a in self.ap: + for b in self.bq: + if (a - b).is_integer and not a < b: + return False + for a in self.ap: + if a == 0: + return False + for b in self.bq: + if b.is_integer and b.is_nonpositive: + return False + return True -class IndexQuadruple(object): - """ Holds a quadruple of indices. """ - def __init__(self, an, ap, bm, bq): - from sympy import expand, Tuple +class G_Function(Expr): + """ A Meijer G-function. """ - def tr(l): - return Tuple(*list(map(expand, l))) - self.an = tr(an) - self.ap = tr(ap) - self.bm = tr(bm) - self.bq = tr(bq) + def __new__(cls, an, ap, bm, bq): + obj = super(G_Function, cls).__new__(cls) + obj.an = Tuple(*list(map(expand, an))) + obj.ap = Tuple(*list(map(expand, ap))) + obj.bm = Tuple(*list(map(expand, bm))) + obj.bq = Tuple(*list(map(expand, bq))) + return obj + + @property + def args(self): + return (self.an, self.ap, self.bm, self.bq) + + def _hashable_content(self): + return super(G_Function, self)._hashable_content() + self.args + + def __call__(self, z): + return meijerg(self.an, self.ap, self.bm, self.bq, z) def compute_buckets(self): """ @@ -553,18 +609,17 @@ same, and that the buckets are sorted by real part (an and bq descendending, bm and ap ascending). - >>> from sympy.simplify.hyperexpand import IndexQuadruple + >>> from sympy.simplify.hyperexpand import G_Function >>> from sympy.abc import y >>> from sympy import S >>> a, b = [1, 3, 2, S(3)/2], [1 + y, y, 2, y + 3] - >>> IndexQuadruple(a, b, [2], [y]).compute_buckets() + >>> G_Function(a, b, [2], [y]).compute_buckets() ({0: [3, 2, 1], 1/2: [3/2]}, {0: [2], Mod(y, 1): [y, y + 1, y + 3]}, {0: [2]}, {Mod(y, 1): [y]}) """ - from collections import defaultdict dicts = pan, pap, pbm, pbq = defaultdict(list), defaultdict(list), \ - defaultdict(list), defaultdict(list) + defaultdict(list), defaultdict(list) for dic, lis in zip(dicts, (self.an, self.ap, self.bm, self.bq)): for x in lis: dic[Mod(x, 1)].append(x) @@ -581,14 +636,10 @@ def signature(self): return (len(self.an), len(self.ap), len(self.bm), len(self.bq)) - def __repr__(self): - return 'IndexQuadruple(%s, %s, %s, %s)' % (self.an, self.ap, - self.bm, self.bq) # Dummy variable. _x = Dummy('x') - class Formula(object): """ This class represents hypergeometric formulae. @@ -597,30 +648,14 @@ - z, the argument - closed_form, the closed form expression - symbols, the free symbols (parameters) in the formula - - indices, the parameters + - func, the function - B, C, M (see _compute_basis) - - lcms, a dictionary which maps symbol -> lcm of denominators - - isolation, a dictonary which maps symbol -> (num, coeff) pairs >>> from sympy.abc import a, b, z - >>> from sympy.simplify.hyperexpand import Formula - >>> f = Formula((a/2, a/3 + b, (1+a)/2), (a, b, (a+b)/7), z, None, [a, b]) + >>> from sympy.simplify.hyperexpand import Formula, Hyper_Function + >>> func = Hyper_Function((a/2, a/3 + b, (1+a)/2), (a, b, (a+b)/7)) + >>> f = Formula(func, z, None, [a, b]) - The lcm of all denominators of coefficients of a is 2*3*7 - >>> f.lcms[a] - 42 - - for b it is just 7: - >>> f.lcms[b] - 7 - - We can isolate a in the (1+a)/2 term, with denominator 2: - >>> f.isolation[a] - (2, 2, 1) - - b is isolated in the b term, with coefficient one: - >>> f.isolation[b] - (4, 1, 1) """ def _compute_basis(self, closed_form): @@ -632,8 +667,8 @@ """ from sympy.matrices import Matrix, eye, zeros - afactors = [_x + a for a in self.indices.ap] - bfactors = [_x + b - 1 for b in self.indices.bq] + afactors = [_x + a for a in self.func.ap] + bfactors = [_x + b - 1 for b in self.func.bq] expr = _x*Mul(*bfactors) - self.z*Mul(*afactors) poly = Poly(expr, _x) @@ -651,54 +686,17 @@ l.reverse() self.M = m.row_insert(n, -Matrix([l])/poly.all_coeffs()[0]) - def __init__(self, ap, bq, z, res, symbols, B=None, C=None, M=None): - ap = Tuple(*list(map(expand, ap))) - bq = Tuple(*list(map(expand, bq))) + def __init__(self, func, z, res, symbols, B=None, C=None, M=None): z = sympify(z) res = sympify(res) - symbols = [x for x in sympify(symbols) if ap.has(x) or bq.has(x)] + symbols = [x for x in sympify(symbols) if func.has(x)] self.z = z self.symbols = symbols self.B = B self.C = C self.M = M - - params = list(ap) + list(bq) - lcms = {} - isolation = {} - for a in symbols: - from sympy import ilcm - l = 1 - isolating = [] - others = list(symbols[:]) - others.remove(a) - i = 0 - for p in params: - if p.has(a): - c, m = None, None - if p.is_Add: - c, m = p.as_independent(a)[1].as_coeff_mul(a) - else: - c, m = p.as_coeff_mul(a) - if m != (a, ) or not c.is_Rational: - raise NotImplementedError('?') - l = ilcm(l, c.q) - - if not p.has(*others): - isolating.append((i, c.q, c.p)) - lcms[a] = l - i += 1 - if len(isolating) == 0: - raise NotImplementedError('parameter is not isolated') - isolating.sort(key=lambda x: x[1]) - isolating.sort(key=lambda x: -x[2]) - isolation[a] = isolating[-1] - - self.lcms = lcms - self.isolation = isolation - - self.indices = IndexPair(ap, bq) + self.func = func # TODO with symbolic parameters, it could be advantageous # (for prettier answers) to compute a basis only *after* @@ -710,110 +708,66 @@ def closed_form(self): return (self.C*self.B)[0] - def find_instantiations(self, ip): + def find_instantiations(self, func): """ - Try to find instantiations of the free symbols that match - ``ip.ap``, ``ip.bq``. Return the instantiated formulae as a list. - Note that the returned instantiations need not actually match, - or be valid! - """ - ap = ip.ap - bq = ip.bq - if len(ap) != len(self.indices.ap) or len(bq) != len(self.indices.bq): - raise TypeError('Cannot instantiate other number of parameters') + Find substitutions of the free symbols that match ``func``. - from sympy import solve - from sympy.core.compatibility import permutations, product - res = [] - our_params = list(self.indices.ap) + list(self.indices.bq) - for na in permutations(ap): - for nb in permutations(bq): - all_params = list(na) + list(nb) - repl = {} - for a in self.symbols: - i, d, _ = self.isolation[a] - repl[a] = (solve(our_params[i] - all_params[i], a)[0], d) - for change in product(*[(-1, 0, 1)]*len(self.symbols)): - rep = {} - for i, a in zip(change, list(repl.keys())): - rep[a] = repl[a][0] + i*repl[a][1] - res.append(Formula(self.indices.ap.subs(rep), - self.indices.bq.subs(rep), - self.z, None, [], self.B.subs(rep), - self.C.subs(rep), self.M.subs(rep))) - # if say a = -1/2, and there is 2*a in the formula, then - # there will be a negative integer. But this origin is also - # reachable from a = 1/2 ... - # So throw this in as well. - # The code is not as general as it could be, but good enough. - if len(self.symbols) == 1: - a = self.symbols[0] - aval, d = repl[a] - if aval < 0 and d == 1: - from sympy import ceiling - aval -= ceiling(aval) - 1 - res.append(Formula(self.indices.ap.subs(a, aval), - self.indices.bq.subs(a, aval), - self.z, None, [], self.B.subs(a, aval), - self.C.subs(rep), self.M.subs(a, aval))) - return res + Return the substitution dictionaries as a list. Note that the returned + instantiations need not actually match, or be valid! - def is_suitable(self): """ - Decide if ``self`` is a suitable origin. + from sympy.solvers import solve + ap = func.ap + bq = func.bq + if len(ap) != len(self.func.ap) or len(bq) != len(self.func.bq): + raise TypeError('Cannot instantiate other number of parameters') + symbol_values = [] + for a in self.symbols: + if a in self.func.ap.args: + symbol_values.append(ap) + elif a in self.func.bq.args: + symbol_values.append(bq) + else: + raise ValueError("At least one of the parameters of the " + "formula must be equal to %s" % (a,)) + base_repl = [dict(list(zip(self.symbols, values))) + for values in product(*symbol_values)] + abuckets, bbuckets = [sift(params, _mod1) for params in [ap, bq]] + a_inv, b_inv = [dict((a, len(vals)) for a, vals in list(bucket.items())) + for bucket in [abuckets, bbuckets]] + critical_values = [[0] for _ in self.symbols] + result = [] + _n = Dummy() + for repl in base_repl: + symb_a, symb_b = [sift(params, lambda x: _mod1(x.xreplace(repl))) + for params in [self.func.ap, self.func.bq]] + for bucket, obucket in [(abuckets, symb_a), (bbuckets, symb_b)]: + for mod in set(list(bucket.keys()) + list(obucket.keys())): + if (not mod in bucket) or (not mod in obucket) \ + or len(bucket[mod]) != len(obucket[mod]): + break + for a, vals in zip(self.symbols, critical_values): + if repl[a].free_symbols: + continue + exprs = [expr for expr in obucket[mod] if expr.has(a)] + repl0 = repl.copy() + repl0[a] += _n + for expr in exprs: + for target in bucket[mod]: + n0, = solve(expr.xreplace(repl0) - target, _n) + assert not n0.free_symbols + vals.append(n0) + else: + values = [] + for a, vals in zip(self.symbols, critical_values): + a0 = repl[a] + min_ = floor(min(vals)) + max_ = ceiling(max(vals)) + values.append([a0 + n for n in range(min_, max_ + 1)]) + result.extend(dict(list(zip(self.symbols, l))) for l in product(*values)) + return result - >>> from sympy.simplify.hyperexpand import Formula - >>> from sympy import S - If ai - bq in Z and bq >= ai this is fine: - >>> Formula((S(1)/2,), (S(3)/2,), None, None, []).is_suitable() - True - - but ai = bq is not: - >>> Formula((S(1)/2,), (S(1)/2,), None, None, []).is_suitable() - False - - and ai > bq is not either: - >>> Formula((S(1)/2,), (-S(1)/2,), None, None, []).is_suitable() - False - - None of the bj can be a non-positive integer: - >>> Formula((S(1)/2,), (0,), None, None, []).is_suitable() - False - >>> Formula((S(1)/2,), (-1, 1,), None, None, []).is_suitable() - False - - None of the ai can be zero: - >>> Formula((S(1)/2, 0), (1,), None, None, []).is_suitable() - False - - - More complicated examples: - >>> Formula((S(1)/2, 1), (2, -S(2)/3), None, None, []).is_suitable() - True - >>> a, b = (S(1)/2, 1), (2, -S(2)/3, S(3)/2) - >>> Formula(a, b, None, None, []).is_suitable() - True - """ - from sympy import oo, zoo - if len(self.symbols) > 0: - return None - for a in self.indices.ap: - for b in self.indices.bq: - if (a - b).is_integer and not a < b: - return False - for a in self.indices.ap: - if a == 0: - return False - for b in self.indices.bq: - if b <= 0 and b.is_integer: - return False - for e in [self.B, self.M, self.C]: - if e is None: - continue - if e.has(S.NaN) or e.has(oo) or e.has(-oo) or e.has(zoo): - return False - return True class FormulaCollection(object): @@ -831,57 +785,62 @@ # These dicts are indexed by (p, q). for f in self.formulae: - sizes = f.indices.sizes + sizes = f.func.sizes if len(f.symbols) > 0: self.symbolic_formulae.setdefault(sizes, []).append(f) else: - inv = f.indices.build_invariants() + inv = f.func.build_invariants() self.concrete_formulae.setdefault(sizes, {})[inv] = f - def lookup_origin(self, ip): + def lookup_origin(self, func): """ - Given the suitable parameters ``ip.ap``, ``ip.bq``, try to find an - origin in our knowledge base. + Given the suitable target ``func``, try to find an origin in our + knowledge base. - >>> from sympy.simplify.hyperexpand import FormulaCollection, IndexPair + >>> from sympy.simplify.hyperexpand import (FormulaCollection, + ... Hyper_Function) >>> f = FormulaCollection() - >>> f.lookup_origin(IndexPair((), ())).closed_form + >>> f.lookup_origin(Hyper_Function((), ())).closed_form exp(_z) - >>> f.lookup_origin(IndexPair([1], ())).closed_form + >>> f.lookup_origin(Hyper_Function([1], ())).closed_form HyperRep_power1(-1, _z) >>> from sympy import S - >>> i = IndexPair([S('1/4'), S('3/4 + 4')], [S.Half]) + >>> i = Hyper_Function([S('1/4'), S('3/4 + 4')], [S.Half]) >>> f.lookup_origin(i).closed_form - HyperRep_sqrts1(-17/4, _z) + HyperRep_sqrts1(-1/4, _z) """ - inv = ip.build_invariants() - sizes = ip.sizes + inv = func.build_invariants() + sizes = func.sizes if sizes in self.concrete_formulae and \ - inv in self.concrete_formulae[sizes]: + inv in self.concrete_formulae[sizes]: return self.concrete_formulae[sizes][inv] # We don't have a concrete formula. Try to instantiate. if not sizes in self.symbolic_formulae: - return None # Too bad... + return None # Too bad... possible = [] for f in self.symbolic_formulae[sizes]: - l = f.find_instantiations(ip) - for f2 in l: - if not f2.is_suitable(): + repls = f.find_instantiations(func) + for repl in repls: + func2 = f.func.xreplace(repl) + if not func2._is_suitable_origin(): continue - diff = f2.indices.difficulty(ip) - if diff != -1: - possible.append((diff, f2)) - - if not possible: - # Give up. - return None + diff = func2.difficulty(func) + if diff == -1: + continue + possible.append((diff, repl, f, func2)) # find the nearest origin possible.sort(key=lambda x: x[0]) - return possible[0][1] + for _, repl, f, func2 in possible: + f2 = Formula(func2, f.z, None, [], f.B.subs(repl), + f.C.subs(repl), f.M.subs(repl)) + if not any(e.has(S.NaN, oo, -oo, zoo) for e in [f2.B, f2.M, f2.C]): + return f2 + else: + return None class MeijerFormula(object): @@ -891,13 +850,13 @@ Its data members are: - z, the argument - symbols, the free symbols (parameters) in the formula - - indices, the parameters + - func, the function - B, C, M (c/f ordinary Formula) """ def __init__(self, an, ap, bm, bq, z, symbols, B, C, M, matcher): an, ap, bm, bq = [Tuple(*list(map(expand, w))) for w in [an, ap, bm, bq]] - self.indices = IndexQuadruple(an, ap, bm, bq) + self.func = G_Function(an, ap, bm, bq) self.z = z self.symbols = symbols self._matcher = matcher @@ -909,17 +868,17 @@ def closed_form(self): return (self.C*self.B)[0] - def try_instantiate(self, iq): + def try_instantiate(self, func): """ - Try to instantiate the current formula to (almost) match iq. + Try to instantiate the current formula to (almost) match func. This uses the _matcher passed on init. """ - if iq.signature != self.indices.signature: + if func.signature != self.func.signature: return None - res = self._matcher(iq) + res = self._matcher(func) if res is not None: - subs, niq = res - return MeijerFormula(niq.an, niq.ap, niq.bm, niq.bq, + subs, newfunc = res + return MeijerFormula(newfunc.an, newfunc.ap, newfunc.bm, newfunc.bq, self.z, [], self.B.subs(subs), self.C.subs(subs), self.M.subs(subs), None) @@ -931,20 +890,19 @@ """ def __init__(self): - from collections import defaultdict formulae = [] add_meijerg_formulae(formulae) self.formulae = defaultdict(list) for formula in formulae: - self.formulae[formula.indices.signature].append(formula) + self.formulae[formula.func.signature].append(formula) self.formulae = dict(self.formulae) - def lookup_origin(self, iq): - """ Try to find a formula that matches iq. """ - if not iq.signature in self.formulae: + def lookup_origin(self, func): + """ Try to find a formula that matches func. """ + if not func.signature in self.formulae: return None - for formula in self.formulae[iq.signature]: - res = formula.try_instantiate(iq) + for formula in self.formulae[func.signature]: + res = formula.try_instantiate(func) if res is not None: return res @@ -1060,8 +1018,8 @@ b0 = -n.nth(0) if b0 == 0: - raise ValueError('Cannot decrement upper index: ' \ - 'cancels with lower') + raise ValueError('Cannot decrement upper index: ' + 'cancels with lower') #print b0 n = Poly(Poly(n.all_coeffs()[:-1], A).as_expr().subs(A, _x/ai + 1), _x) @@ -1091,13 +1049,13 @@ if bi == 0: raise ValueError('Cannot increment -1 lower index.') - m = Poly(_x*(bi-1), _x) + m = Poly(_x*(bi - 1), _x) for b in bq: m *= Poly(_x + b - 1, _x) #print m B = Dummy('B') - D = Poly((bi-1)*B - bi + 1, B) + D = Poly((bi - 1)*B - bi + 1, B) n = Poly(z, B) for a in ap: n *= (D + a) @@ -1106,15 +1064,14 @@ b0 = n.nth(0) #print b0 if b0 == 0: - raise ValueError('Cannot increment index: ' \ - 'cancels with upper') + raise ValueError('Cannot increment index: cancels with upper') #print b0 n = Poly(Poly(n.all_coeffs()[:-1], B).as_expr().subs( - B, _x/(bi-1) + 1), _x) + B, _x/(bi - 1) + 1), _x) #print n - self._poly = Poly((m-n)/b0, _x) + self._poly = Poly((m - n)/b0, _x) def __str__(self): return '' % (self._i, @@ -1209,7 +1166,7 @@ n = Poly(Poly(n.all_coeffs()[:-1], A).as_expr().subs(A, bi - _x), _x) #print n - self._poly = Poly((m-n)/b0, _x) + self._poly = Poly((m - n)/b0, _x) def __str__(self): return '' % (self._i, @@ -1261,7 +1218,7 @@ B, 1 - ai + _x), _x) #print n - self._poly = Poly((m-n)/b0, _x) + self._poly = Poly((m - n)/b0, _x) def __str__(self): return '' % (self._i, @@ -1317,7 +1274,7 @@ n = Poly(Poly(n.all_coeffs()[:-1], C).as_expr().subs(C, _x - bi), _x) #print n - self._poly = Poly((m-n)/b0, _x) + self._poly = Poly((m - n)/b0, _x) def __str__(self): return '' % (self._i, @@ -1352,7 +1309,7 @@ m *= Poly(a - 1 - _x, _x) #print m - B = Dummy('B') # - this is the shift operator `D_I` + B = Dummy('B') # - this is the shift operator `D_I` D = Poly(ai - 1 - B, B) n = Poly(1, B) for b in bm: @@ -1371,7 +1328,7 @@ B, ai - 1 - _x), _x) #print n - self._poly = Poly((m-n)/b0, _x) + self._poly = Poly((m - n)/b0, _x) def __str__(self): return '' % (self._i, @@ -1386,7 +1343,7 @@ ai = sympify(ai) bj = sympify(bj) n = ai - bj - if n < 0 or not n.is_Integer: + if not n.is_Integer or n < 0: return None if bj.is_integer and bj <= 0 and bj + n - 1 >= 0: return None @@ -1407,7 +1364,6 @@ def _meijer(cls, b, a, sign): """ Cancel b + sign*s and a + sign*s This is for meijer G functions. """ - from sympy import Add b = sympify(b) a = sympify(a) n = b - a @@ -1440,7 +1396,7 @@ def __str__(self): return '' % \ - (self._a, self._b) + (self._a, self._b) def _reduce_order(ap, bq, gen, key): @@ -1469,67 +1425,63 @@ return nap, bq, operators -def reduce_order(ip): +def reduce_order(func): """ - Given the hypergeometric parameters ``ip.ap``, ``ip.bq``, - find a sequence of operators to reduces order as much as possible. + Given the hypergeometric function ``func``, find a sequence of operators to + reduces order as much as possible. - Return (nip, [operators]), where applying the operators to the - hypergeometric function specified by nip.ap, nip.bq yields ap, bq. + Return (newfunc, [operators]), where applying the operators to the + hypergeometric function newfunc yields func. Examples ======== - >>> from sympy.simplify.hyperexpand import reduce_order, IndexPair - >>> reduce_order(IndexPair((1, 2), (3, 4))) - (IndexPair((1, 2), (3, 4)), []) - >>> reduce_order(IndexPair((1,), (1,))) - (IndexPair((), ()), []) - >>> reduce_order(IndexPair((2, 4), (3, 3))) - (IndexPair((2,), (3,)), [>> from sympy.simplify.hyperexpand import reduce_order, Hyper_Function + >>> reduce_order(Hyper_Function((1, 2), (3, 4))) + (Hyper_Function((1, 2), (3, 4)), []) + >>> reduce_order(Hyper_Function((1,), (1,))) + (Hyper_Function((), ()), []) + >>> reduce_order(Hyper_Function((2, 4), (3, 3))) + (Hyper_Function((2,), (3,)), []) """ - nap, nbq, operators = _reduce_order(ip.ap, ip.bq, ReduceOrder, lambda x: x) + nap, nbq, operators = _reduce_order(func.ap, func.bq, ReduceOrder, lambda x: x) - return IndexPair(Tuple(*nap), Tuple(*nbq)), operators + return Hyper_Function(Tuple(*nap), Tuple(*nbq)), operators -def reduce_order_meijer(iq): +def reduce_order_meijer(func): """ - Given the Meijer G function parameters, ``iq.am``, ``iq.ap``, ``iq.bm``, - ``iq.bq``, find a sequence of operators that reduces order as much as - possible. + Given the Meijer G function parameters, ``func``, find a sequence of + operators that reduces order as much as possible. - Return niq, [operators]. + Return newfunc, [operators]. Examples ======== >>> from sympy.simplify.hyperexpand import (reduce_order_meijer, - ... IndexQuadruple) - >>> reduce_order_meijer(IndexQuadruple([3, 4], [5, 6], [3, 4], [1, 2]))[0] - IndexQuadruple((4, 3), (5, 6), (3, 4), (2, 1)) - >>> reduce_order_meijer(IndexQuadruple([3, 4], [5, 6], [3, 4], [1, 8]))[0] - IndexQuadruple((3,), (5, 6), (3, 4), (1,)) - >>> reduce_order_meijer(IndexQuadruple([3, 4], [5, 6], [7, 5], [1, 5]))[0] - IndexQuadruple((3,), (), (), (1,)) - >>> reduce_order_meijer(IndexQuadruple([3, 4], [5, 6], [7, 5], [5, 3]))[0] - IndexQuadruple((), (), (), ()) + ... G_Function) + >>> reduce_order_meijer(G_Function([3, 4], [5, 6], [3, 4], [1, 2]))[0] + G_Function((4, 3), (5, 6), (3, 4), (2, 1)) + >>> reduce_order_meijer(G_Function([3, 4], [5, 6], [3, 4], [1, 8]))[0] + G_Function((3,), (5, 6), (3, 4), (1,)) + >>> reduce_order_meijer(G_Function([3, 4], [5, 6], [7, 5], [1, 5]))[0] + G_Function((3,), (), (), (1,)) + >>> reduce_order_meijer(G_Function([3, 4], [5, 6], [7, 5], [5, 3]))[0] + G_Function((), (), (), ()) """ - nan, nbq, ops1 = _reduce_order(iq.an, iq.bq, ReduceOrder.meijer_plus, + nan, nbq, ops1 = _reduce_order(func.an, func.bq, ReduceOrder.meijer_plus, lambda x: -x) - nbm, nap, ops2 = _reduce_order(iq.bm, iq.ap, ReduceOrder.meijer_minus, + nbm, nap, ops2 = _reduce_order(func.bm, func.ap, ReduceOrder.meijer_minus, lambda x: x) - return IndexQuadruple(*[Tuple(*w) for w in [nan, nap, nbm, nbq]]), \ - ops1 + ops2 + return G_Function(nan, nap, nbm, nbq), ops1 + ops2 def make_derivative_operator(M, z): """ Create a derivative operator, to be passed to Operator.apply. """ - from sympy import poly - def doit(C): r = z*C.diff(z) + C*M r = r.applyfunc(make_simp(z)) @@ -1548,56 +1500,55 @@ return res -def devise_plan(ip, nip, z): +def devise_plan(target, origin, z): """ Devise a plan (consisting of shift and un-shift operators) to be applied - to the hypergeometric function (``nip.ap``, ``nip.bq``) to yield - (``ip.ap``, ``ip.bq``). + to the hypergeometric function ``target`` to yield ``origin``. Returns a list of operators. - >>> from sympy.simplify.hyperexpand import devise_plan, IndexPair + >>> from sympy.simplify.hyperexpand import devise_plan, Hyper_Function >>> from sympy.abc import z Nothing to do: - >>> devise_plan(IndexPair((1, 2), ()), IndexPair((1, 2), ()), z) + >>> devise_plan(Hyper_Function((1, 2), ()), Hyper_Function((1, 2), ()), z) [] - >>> devise_plan(IndexPair((), (1, 2)), IndexPair((), (1, 2)), z) + >>> devise_plan(Hyper_Function((), (1, 2)), Hyper_Function((), (1, 2)), z) [] Very simple plans: - >>> devise_plan(IndexPair((2,), ()), IndexPair((1,), ()), z) + >>> devise_plan(Hyper_Function((2,), ()), Hyper_Function((1,), ()), z) [] - >>> devise_plan(IndexPair((), (2,)), IndexPair((), (1,)), z) + >>> devise_plan(Hyper_Function((), (2,)), Hyper_Function((), (1,)), z) [] Several buckets: >>> from sympy import S - >>> devise_plan(IndexPair((1, S.Half), ()), - ... IndexPair((2, S('3/2')), ()), z) #doctest: +NORMALIZE_WHITESPACE + >>> devise_plan(Hyper_Function((1, S.Half), ()), + ... Hyper_Function((2, S('3/2')), ()), z) #doctest: +NORMALIZE_WHITESPACE [, ] A slightly more complicated plan: - >>> devise_plan(IndexPair((1, 3), ()), IndexPair((2, 2), ()), z) + >>> devise_plan(Hyper_Function((1, 3), ()), Hyper_Function((2, 2), ()), z) [, ] Another more complicated plan: (note that the ap have to be shifted first!) - >>> devise_plan(IndexPair((1, -1), (2,)), IndexPair((3, -2), (4,)), z) + >>> devise_plan(Hyper_Function((1, -1), (2,)), Hyper_Function((3, -2), (4,)), z) [, , , , ] """ - abuckets, bbuckets = ip.compute_buckets() - nabuckets, nbbuckets = nip.compute_buckets(abuckets, bbuckets) + abuckets, bbuckets, nabuckets, nbbuckets = [sift(params, _mod1) for + params in (target.ap, target.bq, origin.ap, origin.bq)] if len(list(abuckets.keys())) != len(list(nabuckets.keys())) or \ - len(list(bbuckets.keys())) != len(list(nbbuckets.keys())): - raise ValueError('%s not reachable from %s' % (ip, nip)) + len(list(bbuckets.keys())) != len(list(nbbuckets.keys())): + raise ValueError('%s not reachable from %s' % (target, origin)) ops = [] @@ -1640,8 +1591,7 @@ bk = bbuckets[r] nbk = nbbuckets[r] if len(al) != len(nal) or len(bk) != len(nbk): - raise ValueError('%s not reachable from %s' % ( - (ip.ap, ip.bq), (nip.ap, nip.bq))) + raise ValueError('%s not reachable from %s' % (target, origin)) al, nal, bk, nbk = [sorted(list(w), key=default_sort_key) for w in [al, nal, bk, nbk]] @@ -1684,11 +1634,10 @@ return ops -def try_shifted_sum(ip, z): +def try_shifted_sum(func, z): """ Try to recognise a hypergeometric sum that starts from k > 0. """ - from sympy.functions import rf, factorial - abuckets, bbuckets = ip.compute_buckets() - if not S(0) in abuckets or len(abuckets[S(0)]) != 1: + abuckets, bbuckets = sift(func.ap, _mod1), sift(func.bq, _mod1) + if len(abuckets[S(0)]) != 1: return None r = abuckets[S(0)][0] if r <= 0: @@ -1701,9 +1650,9 @@ if k <= 0: return None - nap = list(ip.ap) + nap = list(func.ap) nap.remove(r) - nbq = list(ip.bq) + nbq = list(func.bq) nbq.remove(k) k -= 1 nap = [x - k for x in nap] @@ -1731,16 +1680,15 @@ m /= rf(b, n) p += m - return IndexPair(nap, nbq), ops, -p + return Hyper_Function(nap, nbq), ops, -p -def try_polynomial(ip, z): +def try_polynomial(func, z): """ Recognise polynomial cases. Returns None if not such a case. Requires order to be fully reduced. """ - from sympy import oo, factorial, rf, Expr - abuckets, bbuckets = ip.compute_buckets() - a0 = list(abuckets.get(S(0), [])) - b0 = list(bbuckets.get(S(0), [])) + abuckets, bbuckets = sift(func.ap, _mod1), sift(func.bq, _mod1) + a0 = abuckets[S(0)] + b0 = bbuckets[S(0)] a0.sort() b0.sort() al0 = [x for x in a0 if x <= 0] @@ -1757,17 +1705,17 @@ for n in Tuple(*list(range(-a))): fac *= z fac /= n + 1 - for a in ip.ap: + for a in func.ap: fac *= a + n - for b in ip.bq: + for b in func.bq: fac /= b + n res += fac return res -def try_lerchphi(nip): +def try_lerchphi(func): """ - Try to find an expression for IndexPair ``nip`` in terms of Lerch + Try to find an expression for Hyper_Function ``func`` in terms of Lerch Transcendents. Return None if no such expression can be found. @@ -1776,32 +1724,18 @@ # section 18. # We don't need to implement the reduction to polylog here, this # is handled by expand_func. - from sympy import (expand_func, lerchphi, apart, Dummy, rf, Poly, Matrix, - zeros, Add) + from sympy.matrices import Matrix, zeros + from sympy.polys import apart # First we need to figure out if the summation coefficient is a rational # function of the summation index, and construct that rational function. - abuckets, bbuckets = nip.compute_buckets() - # Update all the keys in bbuckets to be the same Mod objects as abuckets. - akeys = list(abuckets.keys()) - bkeys = [] - for key in list(bbuckets.keys()): - new = key - for a in akeys: - if a == key: - new = a - break - bkeys += [(new, key)] - bb = {} - for new, key in bkeys: - bb[new] = bbuckets[key] - bbuckets = bb + abuckets, bbuckets = sift(func.ap, _mod1), sift(func.bq, _mod1) paired = {} for key, value in list(abuckets.items()): if key != 0 and not key in bbuckets: return None - bvalue = bbuckets.get(key, []) + bvalue = bbuckets[key] paired[key] = (list(value), list(bvalue)) bbuckets.pop(key, None) if bbuckets != {}: @@ -1848,7 +1782,7 @@ monomials += [(a/denom, b)] continue if numer.has(t): - raise NotImplementedError('Need partial fraction decomposition' \ + raise NotImplementedError('Need partial fraction decomposition' ' with linear denominators') indep, [dep] = denom.as_coeff_mul(t) n = 1 @@ -1880,7 +1814,7 @@ coeffs = {} z = Dummy('z') monomials.sort(key=lambda x: x[1]) - mon = {0: 1/(1-z)} + mon = {0: 1/(1 - z)} if monomials: for k in range(monomials[-1][1]): mon[k + 1] = z*mon[k].diff(z) @@ -1892,7 +1826,7 @@ l.sort(key=lambda x: x[1]) for k in range(2, l[-1][1] + 1): deriv[lerchphi(z, k, a)] = [(-a, lerchphi(z, k, a)), - (1, lerchphi(z, k-1, a))] + (1, lerchphi(z, k - 1, a))] deriv[lerchphi(z, 1, a)] = [(-a, lerchphi(z, 1, a)), (1/(1 - z), S(1))] trans = {} @@ -1908,29 +1842,31 @@ for b, l in list(deriv.items()): for c, b2 in l: M[trans[b], trans[b2]] = c - return Formula(nip.ap, nip.bq, z, None, [], B, C, M) + return Formula(func, z, None, [], B, C, M) -def build_hypergeometric_formula(nip): - """ Create a formula object representing the hypergeometric function - Corresponding to nip. """ +def build_hypergeometric_formula(func): + """ + Create a formula object representing the hypergeometric function ``func``. + + """ # We know that no `ap` are negative integers, otherwise "detect poly" # would have kicked in. However, `ap` could be empty. In this case we can # use a different basis. # I'm not aware of a basis that works in all cases. - from sympy import zeros, Dummy, Matrix, hyper, eye, Mul + from sympy import zeros, Matrix, eye z = Dummy('z') - if nip.ap: - afactors = [_x + a for a in nip.ap] - bfactors = [_x + b - 1 for b in nip.bq] + if func.ap: + afactors = [_x + a for a in func.ap] + bfactors = [_x + b - 1 for b in func.bq] expr = _x*Mul(*bfactors) - z*Mul(*afactors) poly = Poly(expr, _x) n = poly.degree() basis = [] M = zeros(n) for k in range(n): - a = nip.ap[0] + k - basis += [hyper([a] + list(nip.ap[1:]), nip.bq, z)] + a = func.ap[0] + k + basis += [hyper([a] + list(func.ap[1:]), func.bq, z)] if k < n - 1: M[k, k] = -a M[k, k + 1] = a @@ -1946,13 +1882,13 @@ for r, d in enumerate(C*derivs[k]): res[r] += c*d for k, c in enumerate(res): - M[n-1, k] = -c/derivs[n-1][0, n-1]/poly.all_coeffs()[0] - return Formula(nip.ap, nip.bq, z, None, [], B, C, M) + M[n - 1, k] = -c/derivs[n - 1][0, n - 1]/poly.all_coeffs()[0] + return Formula(func, z, None, [], B, C, M) else: # Since there are no `ap`, none of the `bq` can be non-positive # integers. basis = [] - bq = list(nip.bq[:]) + bq = list(func.bq[:]) for i in range(len(bq)): basis += [hyper([], bq, z)] bq[i] += 1 @@ -1961,11 +1897,11 @@ n = len(B) C = Matrix([[1] + [0]*(n - 1)]) M = zeros(n) - M[0, n - 1] = z/Mul(*nip.bq) + M[0, n - 1] = z/Mul(*func.bq) for k in range(1, n): - M[k, k - 1] = nip.bq[k - 1] - M[k, k] = -nip.bq[k - 1] - return Formula(nip.ap, nip.bq, z, None, [], B, C, M) + M[k, k - 1] = func.bq[k - 1] + M[k, k] = -func.bq[k - 1] + return Formula(func, z, None, [], B, C, M) def hyperexpand_special(ap, bq, z): @@ -1979,7 +1915,6 @@ # This code is very ad-hoc. There are many clever algorithms # (notably Zeilberger's) related to this problem. # For now we just want a few simple cases to work. - from sympy import gamma, simplify, cos, unpolarify, pi p, q = len(ap), len(bq) z_ = z z = unpolarify(z) @@ -1997,10 +1932,10 @@ # Kummer if b.is_integer and b < 0: return 2*cos(pi*b/2)*gamma(-b)*gamma(b - a + 1) \ - /gamma(-b/2)/gamma(b/2 - a + 1) + /gamma(-b/2)/gamma(b/2 - a + 1) else: return gamma(b/2 + 1)*gamma(b - a + 1) \ - /gamma(b + 1)/gamma(b/2 - a + 1) + /gamma(b + 1)/gamma(b/2 - a + 1) # TODO tons of more formulae # investigate what algorithms exist return hyper(ap, bq, z_) @@ -2008,18 +1943,15 @@ _collection = None -@_timeit -def _hyperexpand(ip, z, ops0=[], z0=Dummy('z0'), premult=1, prem=0, +def _hyperexpand(func, z, ops0=[], z0=Dummy('z0'), premult=1, prem=0, rewrite='default'): """ - Try to find an expression for the hypergeometric function - ``ip.ap``, ``ip.bq``. + Try to find an expression for the hypergeometric function ``func``. The result is expressed in terms of a dummy variable z0. Then it is multiplied by premult. Then ops0 is applied. premult must be a*z**prem for some a independent of z. """ - from sympy.simplify import powdenest, simplify, polarify, unpolarify z = polarify(z, subs=False) if rewrite == 'default': rewrite = 'nonrepsmall' @@ -2049,17 +1981,17 @@ if _collection is None: _collection = FormulaCollection() - debug('Trying to expand hypergeometric function corresponding to', ip) + debug('Trying to expand hypergeometric function ', func) # First reduce order as much as possible. - nip, ops = reduce_order(ip) + func, ops = reduce_order(func) if ops: - debug(' Reduced order to', nip) + debug(' Reduced order to', func) else: debug(' Could not reduce order.') # Now try polynomial cases - res = try_polynomial(nip, z0) + res = try_polynomial(func, z0) if res is not None: debug(' Recognised polynomial.') p = apply_operators(res, ops, lambda f: z0*f.diff(z0)) @@ -2068,10 +2000,10 @@ # Try to recognise a shifted sum. p = S(0) - res = try_shifted_sum(nip, z0) - if res != None: - nip, nops, p = res - debug(' Recognised shifted sum, reducerd order to', nip) + res = try_shifted_sum(func, z0) + if res is not None: + func, nops, p = res + debug(' Recognised shifted sum, reduced order to', func) ops += nops # apply the plan for poly @@ -2080,84 +2012,83 @@ p = simplify(p).subs(z0, z) # Try special expansions early. - if unpolarify(z) in [1, -1] and (len(nip.ap), len(nip.bq)) == (2, 1): - f = build_hypergeometric_formula(nip) + if unpolarify(z) in [1, -1] and (len(func.ap), len(func.bq)) == (2, 1): + f = build_hypergeometric_formula(func) r = carryout_plan(f, ops).replace(hyper, hyperexpand_special) if not r.has(hyper): return r + p # Try to find a formula in our collection - f = _collection.lookup_origin(nip) + formula = _collection.lookup_origin(func) # Now try a lerch phi formula - if f is None: - f = try_lerchphi(nip) + if formula is None: + formula = try_lerchphi(func) - if f is None: + if formula is None: debug(' Could not find an origin.', - 'Will return answer in terms of '+ + 'Will return answer in terms of ' 'simpler hypergeometric functions.') - f = build_hypergeometric_formula(nip) + formula = build_hypergeometric_formula(func) - debug(' Found an origin:', f.closed_form, f.indices) + debug(' Found an origin:', formula.closed_form, formula.func) - # We need to find the operators that convert f into (nap, nbq). - ops += devise_plan(nip, f.indices, z0) + # We need to find the operators that convert formula into func. + ops += devise_plan(func, formula.func, z0) # Now carry out the plan. - r = carryout_plan(f, ops) + p + r = carryout_plan(formula, ops) + p return powdenest(r, polar=True).replace(hyper, hyperexpand_special) def devise_plan_meijer(fro, to, z): """ - Find a sequence of operators to convert index quadruple ``fro`` into - index quadruple ``to``. It is assumed that fro and to have the same - signatures, and that in fact any corresponding pair of parameters differs - by integers, and a direct path is possible. I.e. if there are parameters - a1 b1 c1 and a2 b2 c2 - it is assumed that a1 can be shifted to a2, etc. - The only thing this routine determines is the order of shifts to apply, - nothing clever will be tried. + Find operators to convert G-function ``fro`` into G-function ``to``. + + It is assumed that fro and to have the same signatures, and that in fact + any corresponding pair of parameters differs by integers, and a direct path + is possible. I.e. if there are parameters a1 b1 c1 and a2 b2 c2 it is + assumed that a1 can be shifted to a2, etc. The only thing this routine + determines is the order of shifts to apply, nothing clever will be tried. It is also assumed that fro is suitable. >>> from sympy.simplify.hyperexpand import (devise_plan_meijer, - ... IndexQuadruple) + ... G_Function) >>> from sympy.abc import z Empty plan: - >>> devise_plan_meijer(IndexQuadruple([1], [2], [3], [4]), - ... IndexQuadruple([1], [2], [3], [4]), z) + >>> devise_plan_meijer(G_Function([1], [2], [3], [4]), + ... G_Function([1], [2], [3], [4]), z) [] Very simple plans: - >>> devise_plan_meijer(IndexQuadruple([0], [], [], []), - ... IndexQuadruple([1], [], [], []), z) + >>> devise_plan_meijer(G_Function([0], [], [], []), + ... G_Function([1], [], [], []), z) [] - >>> devise_plan_meijer(IndexQuadruple([0], [], [], []), - ... IndexQuadruple([-1], [], [], []), z) + >>> devise_plan_meijer(G_Function([0], [], [], []), + ... G_Function([-1], [], [], []), z) [] - >>> devise_plan_meijer(IndexQuadruple([], [1], [], []), - ... IndexQuadruple([], [2], [], []), z) + >>> devise_plan_meijer(G_Function([], [1], [], []), + ... G_Function([], [2], [], []), z) [] Slightly more complicated plans: - >>> devise_plan_meijer(IndexQuadruple([0], [], [], []), - ... IndexQuadruple([2], [], [], []), z) + >>> devise_plan_meijer(G_Function([0], [], [], []), + ... G_Function([2], [], [], []), z) [, ] - >>> devise_plan_meijer(IndexQuadruple([0], [], [0], []), - ... IndexQuadruple([-1], [], [1], []), z) + >>> devise_plan_meijer(G_Function([0], [], [0], []), + ... G_Function([-1], [], [1], []), z) [, ] Order matters: - >>> devise_plan_meijer(IndexQuadruple([0], [], [0], []), - ... IndexQuadruple([1], [], [1], []), z) + >>> devise_plan_meijer(G_Function([0], [], [0], []), + ... G_Function([1], [], [1], []), z) [, ] """ # TODO for now, we use the following simple heuristic: inverse-shift @@ -2174,7 +2105,7 @@ for idx, (a, b) in enumerate(list(zip(f, t))): if ( (a - b).is_integer and (b - a)/diff > 0 and - all(a != x for x in counter)): + all(a != x for x in counter)): sh = shifter(idx) f[idx] += diff return sh @@ -2235,7 +2166,7 @@ change = True continue if fan != list(to.an) or fap != list(to.ap) or fbm != list(to.bm) or \ - fbq != list(to.bq): + fbq != list(to.bq): raise NotImplementedError('Could not devise plan.') ops.reverse() return ops @@ -2243,39 +2174,37 @@ _meijercollection = None -@_timeit -def _meijergexpand(iq, z0, allow_hyper=False, rewrite='default'): +def _meijergexpand(func, z0, allow_hyper=False, rewrite='default'): """ Try to find an expression for the Meijer G function specified - by the IndexQuadruple ``iq``. If ``allow_hyper`` is True, then returning + by the G_Function ``func``. If ``allow_hyper`` is True, then returning an expression in terms of hypergeometric functions is allowed. Currently this just does slater's theorem. """ - from sympy import hyper, Piecewise, meijerg, powdenest, re, polar_lift, oo global _meijercollection if _meijercollection is None: _meijercollection = MeijerFormulaCollection() if rewrite == 'default': rewrite = None - iq_ = iq - debug('Try to expand meijer G function corresponding to', iq) + func0 = func + debug('Try to expand meijer G function corresponding to', func) # We will play games with analytic continuation - rather use a fresh symbol z = Dummy('z') - iq, ops = reduce_order_meijer(iq) + func, ops = reduce_order_meijer(func) if ops: - debug(' Reduced order to', iq) + debug(' Reduced order to', func) else: debug(' Could not reduce order.') # Try to find a direct formula - f = _meijercollection.lookup_origin(iq) + f = _meijercollection.lookup_origin(func) if f is not None: - debug(' Found a Meijer G formula:', f.indices) - ops += devise_plan_meijer(f.indices, iq, z) + debug(' Found a Meijer G formula:', f.func) + ops += devise_plan_meijer(f.func, func, z) # Now carry out the plan. C = apply_operators(f.C.subs(f.z, z), ops, @@ -2308,12 +2237,10 @@ return True def do_slater(an, bm, ap, bq, z, zfinal): - from sympy import gamma, residue, factorial, rf, expand_func, \ - polar_lift # zfinal is the value that will eventually be substituted for z. # We pass it to _hyperexpand to improve performance. - iq = IndexQuadruple(an, bm, ap, bq) - _, pbm, pap, _ = iq.compute_buckets() + func = G_Function(an, bm, ap, bq) + _, pbm, pap, _ = func.compute_buckets() if not can_do(pbm, pap): return S(0), False @@ -2346,14 +2273,14 @@ # NOTE even though k "is" +-1, this has to be t/k instead of # t*k ... we are using polar numbers for consistency! premult = (t/k)**bh - hyp = _hyperexpand(IndexPair(nap, nbq), harg, ops, + hyp = _hyperexpand(Hyper_Function(nap, nbq), harg, ops, t, premult, bh, rewrite=None) res += fac * hyp else: b_ = pbm[m][0] ki = [bi - b_ for bi in pbm[m][1:]] u = len(ki) - li = [ai - b_ for ai in pap[m][:u+1]] + li = [ai - b_ for ai in pap[m][:u + 1]] bo = list(bm) for b in pbm[m]: bo.remove(b) @@ -2391,7 +2318,7 @@ nap = [1 + au - a for a in list(an) + list(ap)] + [1] nbq = [1 + au - b for b in list(bm) + list(bq)] - hyp = _hyperexpand(IndexPair(nap, nbq), harg, ops, + hyp = _hyperexpand(Hyper_Function(nap, nbq), harg, ops, t, premult, au, rewrite=None) C = S(-1)**(lu)/factorial(lu) @@ -2411,14 +2338,14 @@ return res, cond t = Dummy('t') - slater1, cond1 = do_slater(iq.an, iq.bm, iq.ap, iq.bq, z, z0) + slater1, cond1 = do_slater(func.an, func.bm, func.ap, func.bq, z, z0) def tr(l): return [1 - x for x in l] for op in ops: op._poly = Poly(op._poly.subs({z: 1/t, _x: -_x}), _x) - slater2, cond2 = do_slater(tr(iq.bm), tr(iq.an), tr(iq.bq), tr(iq.ap), + slater2, cond2 = do_slater(tr(func.bm), tr(func.an), tr(func.bq), tr(func.ap), t, 1/z0) slater1 = powdenest(slater1.subs(z, z0), polar=True) @@ -2426,10 +2353,10 @@ if not isinstance(cond2, bool): cond2 = cond2.subs(t, 1/z) - m = meijerg(iq.an, iq.ap, iq.bm, iq.bq, z) + m = func(z) if m.delta > 0 or \ - (m.delta == 0 and len(m.ap) == len(m.bq) and \ - (re(m.nu) < -1) is not False and polar_lift(z0) == polar_lift(1)): + (m.delta == 0 and len(m.ap) == len(m.bq) and + (re(m.nu) < -1) is not False and polar_lift(z0) == polar_lift(1)): # The condition delta > 0 means that the convergence region is # connected. Any expression we find can be continued analytically # to the entire convergence region. @@ -2455,7 +2382,6 @@ cond2 = cond2.subs(z, z0) def weight(expr, cond): - from sympy import oo, zoo, nan if cond is True: c0 = 0 elif cond is False: @@ -2477,21 +2403,19 @@ else: return slater2 if max(w1[0], w2[0]) <= 1 and max(w1[1], w2[1]) <= 1: - return Piecewise((slater1, cond1), (slater2, cond2), - (meijerg(iq_.an, iq_.ap, iq_.bm, iq_.bq, z0), True)) + return Piecewise((slater1, cond1), (slater2, cond2), (func0(z0), True)) # We couldn't find an expression without hypergeometric functions. # TODO it would be helpful to give conditions under which the integral # is known to diverge. - r = Piecewise((slater1, cond1), (slater2, cond2), - (meijerg(iq_.an, iq_.ap, iq_.bm, iq_.bq, z0), True)) + r = Piecewise((slater1, cond1), (slater2, cond2), (func0(z0), True)) if r.has(hyper) and not allow_hyper: - debug(' Could express using hypergeometric functions, '+ + debug(' Could express using hypergeometric functions, ' + 'but not allowed.') if not r.has(hyper) or allow_hyper: return r - return meijerg(iq_.an, iq_.ap, iq_.bm, iq_.bq, z0) + return func0(z0) def hyperexpand(f, allow_hyper=False, rewrite='default'): @@ -2515,22 +2439,18 @@ >>> hyperexpand(1 + hyper([1, 1, 1], [], z)) hyper((1, 1, 1), (), z) + 1 """ - from sympy.functions import hyper, meijerg - from sympy import nan, zoo, oo f = sympify(f) def do_replace(ap, bq, z): - r = _hyperexpand(IndexPair(ap, bq), z, rewrite=rewrite) + r = _hyperexpand(Hyper_Function(ap, bq), z, rewrite=rewrite) if r is None: return hyper(ap, bq, z) else: return r def do_meijer(ap, bq, z): - r = _meijergexpand(IndexQuadruple(ap[0], ap[1], bq[0], bq[1]), z, + r = _meijergexpand(G_Function(ap[0], ap[1], bq[0], bq[1]), z, allow_hyper, rewrite=rewrite) if not r.has(nan, zoo, oo, -oo): return r return f.replace(hyper, do_replace).replace(meijerg, do_meijer) - -from sympy.polys.polytools import Poly diff -Nru python3-sympy-0.7.2/sympy/simplify/hyperexpand_doc.py python3-sympy-0.7.3/sympy/simplify/hyperexpand_doc.py --- python3-sympy-0.7.2/sympy/simplify/hyperexpand_doc.py 2012-10-17 03:02:22.000000000 +0000 +++ python3-sympy-0.7.3/sympy/simplify/hyperexpand_doc.py 2013-07-13 17:53:32.000000000 +0000 @@ -9,7 +9,7 @@ doc = "" for f in c.formulae: - obj = Eq(hyper(f.indices.ap, f.indices.bq, f.z), + obj = Eq(hyper(f.func.ap, f.func.bq, f.z), f.closed_form.rewrite('nonrepsmall')) doc += ".. math::\n %s\n" % latex(obj) diff -Nru python3-sympy-0.7.2/sympy/simplify/simplify.py python3-sympy-0.7.3/sympy/simplify/simplify.py --- python3-sympy-0.7.2/sympy/simplify/simplify.py 2012-10-17 03:02:22.000000000 +0000 +++ python3-sympy-0.7.3/sympy/simplify/simplify.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,37 +1,44 @@ from collections import defaultdict -from operator import itemgetter from sympy import SYMPY_DEBUG from sympy.core import (Basic, S, C, Add, Mul, Pow, Rational, Integer, Derivative, Wild, Symbol, sympify, expand, expand_mul, expand_func, Function, Equality, Dummy, Atom, count_ops, Expr, factor_terms, - expand_multinomial, expand_power_base) - -from sympy.core.compatibility import iterable, reduce -from sympy.core.numbers import igcd, Float + expand_multinomial, FunctionClass, expand_power_base, symbols, igcd, + expand_power_exp, expand_log) +from sympy.core.add import _unevaluated_Add +from sympy.core.cache import cacheit +from sympy.core.compatibility import ( + iterable, reduce, default_sort_key, set_union, ordered) +from sympy.core.exprtools import Factors, gcd_terms +from sympy.core.numbers import Float, Number, I from sympy.core.function import expand_log, count_ops from sympy.core.mul import _keep_coeff, prod from sympy.core.rules import Transform +from sympy.functions import ( + gamma, exp, sqrt, log, root, exp_polar, + sin, cos, tan, cot, sinh, cosh, tanh, coth, piecewise_fold, Piecewise) +from sympy.functions.elementary.integers import ceiling -from sympy.functions import gamma, exp, sqrt, log, root, exp_polar -from sympy.utilities.misc import default_sort_key -from sympy.utilities.iterables import flatten, has_variety +from sympy.utilities.iterables import flatten, has_variety, sift from sympy.simplify.cse_main import cse from sympy.simplify.cse_opts import sub_pre, sub_post from sympy.simplify.sqrtdenest import sqrtdenest +from sympy.ntheory.factor_ import multiplicity from sympy.polys import (Poly, together, reduced, cancel, factor, - ComputationFailed, terms_gcd, lcm, gcd) -from sympy.polys.polytools import _keep_coeff + ComputationFailed, lcm, gcd) import sympy.mpmath as mpmath from functools import reduce + def _mexpand(expr): return expand_mul(expand_multinomial(expr)) + def fraction(expr, exact=False): """Returns a pair with expression's numerator and denominator. If the given expression is not a fraction then this function @@ -109,19 +116,24 @@ return Mul(*numer), Mul(*denom) + def numer(expr): return fraction(expr)[0] + def denom(expr): return fraction(expr)[1] + def fraction_expand(expr, **hints): return expr.expand(frac=True, **hints) + def numer_expand(expr, **hints): a, b = fraction(expr) return a.expand(numer=True, **hints) / b + def denom_expand(expr, **hints): a, b = fraction(expr) return a / b.expand(denom=True, **hints) @@ -130,18 +142,21 @@ expand_denom = denom_expand expand_fraction = fraction_expand + def separate(expr, deep=False, force=False): """ - Deprecated wrapper around ``expand_power_base()``. Use that function instead. + Deprecated wrapper for ``expand_power_base()``. Use that function instead. """ from sympy.utilities.exceptions import SymPyDeprecationWarning SymPyDeprecationWarning( feature="separate()", useinstead="expand_power_base()", issue=3383, deprecated_since_version="0.7.2", value="Note: in separate() deep " - "defaults to False, whereas in expand_power_base(), deep defaults to True.", + "defaults to False, whereas in expand_power_base(), " + "deep defaults to True.", ).warn() return expand_power_base(sympify(expr), deep=deep, force=force) + def collect(expr, syms, func=None, evaluate=True, exact=False, distribute_order_term=True): """ Collect additive terms of an expression. @@ -239,10 +254,11 @@ >>> collect(a*x**7 + b*x**7, x**7, exact=True) x**7*(a + b) - You can also apply this function to differential equations, where derivatives - of arbitrary order can be collected. Note that if you collect with respect - to a function or a derivative of a function, all derivatives of that function - will also be collected. Use ``exact=True`` to prevent this from happening:: + You can also apply this function to differential equations, where + derivatives of arbitrary order can be collected. Note that if you + collect with respect to a function or a derivative of a function, all + derivatives of that function will also be collected. Use + ``exact=True`` to prevent this from happening:: >>> from sympy import Derivative as D, collect, Function >>> f = Function('f') (x) @@ -275,7 +291,11 @@ .. note:: Arguments are expected to be in expanded form, so you might have to call :func:`expand` prior to calling this function. + See Also + ======== + collect_const, collect_sqrt, rcollect """ + def make_expression(terms): product = [] @@ -284,7 +304,7 @@ var, order = deriv while order > 0: - term, order = Derivative(term, var), order-1 + term, order = Derivative(term, var), order - 1 if sym is None: if rat is S.One: @@ -305,17 +325,19 @@ if s == sym: order += 1 else: - raise NotImplementedError('Improve MV Derivative support in collect') + raise NotImplementedError( + 'Improve MV Derivative support in collect') while isinstance(expr, Derivative): s0 = expr.variables[0] for s in expr.variables: if s != s0: - raise NotImplementedError('Improve MV Derivative support in collect') + raise NotImplementedError( + 'Improve MV Derivative support in collect') if s0 == sym: - expr, order = expr.expr, order+len(expr.variables) + expr, order = expr.expr, order + len(expr.variables) else: break @@ -377,7 +399,7 @@ else: pattern = [parse_term(elem) for elem in pattern] - terms = terms[:] # need a copy + terms = terms[:] # need a copy elems, common_expo, has_deriv = [], None, False for elem, e_rat, e_sym, e_ord in pattern: @@ -396,13 +418,13 @@ # a derivative or not as this will require rebuilding # the expression later if t_ord is not None: - has_deriv= True + has_deriv = True - if (term.match(elem) is not None and \ - (t_sym == e_sym or t_sym is not None and \ - e_sym is not None and \ + if (term.match(elem) is not None and + (t_sym == e_sym or t_sym is not None and + e_sym is not None and t_sym.match(e_sym) is not None)): - if exact == False: + if exact is False: # we don't have to be exact so find common exponent # for both expression's term and pattern's element expo = t_rat / e_rat @@ -437,15 +459,18 @@ if evaluate: if expr.is_Mul: - return Mul(*[ collect(term, syms, func, True, exact, distribute_order_term) for term in expr.args ]) + return Mul(*[ + collect(term, syms, func, True, exact, distribute_order_term) + for term in expr.args]) elif expr.is_Pow: - b = collect(expr.base, syms, func, True, exact, distribute_order_term) + b = collect( + expr.base, syms, func, True, exact, distribute_order_term) return Pow(b, expr.exp) if iterable(syms): syms = [expand_power_base(i, deep=False) for i in syms] else: - syms = [ expand_power_base(syms, deep=False) ] + syms = [expand_power_base(syms, deep=False)] expr = sympify(expr) order_term = None @@ -467,12 +492,13 @@ for symbol in syms: if SYMPY_DEBUG: - print("DEBUG: parsing of expression %s with symbol %s " % (str(terms), str(symbol))) + print("DEBUG: parsing of expression %s with symbol %s " % ( + str(terms), str(symbol))) result = parse_expression(terms, symbol) if SYMPY_DEBUG: - print("DEBUG: returned %s" % str(result)) + print("DEBUG: returned %s" % str(result)) if result is not None: terms, elems, common_expo, has_deriv = result @@ -506,13 +532,15 @@ collected[key] = val + order_term if func is not None: - collected = dict([ (key, func(val)) for key, val in collected.items() ]) + collected = dict( + [(key, func(val)) for key, val in collected.items()]) if evaluate: return Add(*[key*val for key, val in collected.items()]) else: return collected + def rcollect(expr, *vars): """ Recursively collect sums in an expression. @@ -528,17 +556,21 @@ >>> rcollect(expr, y) (x + y*(x**2 + x + 1))/(x + y) + See Also + ======== + collect, collect_const, collect_sqrt """ if expr.is_Atom or not expr.has(*vars): return expr else: - expr = expr.__class__(*[ rcollect(arg, *vars) for arg in expr.args ]) + expr = expr.__class__(*[rcollect(arg, *vars) for arg in expr.args]) if expr.is_Add: return collect(expr, vars) else: return expr + def separatevars(expr, symbols=[], dict=False, force=False): """ Separates variables in an expression, if possible. By @@ -608,6 +640,7 @@ else: return _separatevars(expr, force) + def _separatevars(expr, force): if len(expr.free_symbols) == 1: return expr @@ -629,10 +662,8 @@ # First try other expansion methods expr = expr.expand(mul=False, multinomial=False, force=force) - _expr = expr - if expr.is_commutative: # factor fails for nc - _expr, reps = posify(expr) if force else (expr, {}) - expr = factor(_expr).subs(reps) + _expr, reps = posify(expr) if force else (expr, {}) + expr = factor(_expr).subs(reps) if not expr.is_Add: return expr @@ -643,7 +674,7 @@ for i in args[1:]: commonc &= i.args_cnc(cset=True, warn=False)[0] commonc = Mul(*commonc) - commonc = commonc.as_coeff_Mul()[1] # ignore constants + commonc = commonc.as_coeff_Mul()[1] # ignore constants commonc_set = commonc.args_cnc(cset=True, warn=False)[0] # remove them @@ -694,6 +725,7 @@ return ret + def ratsimp(expr): """ Put an expression over a common denominator, cancel and reduce. @@ -715,6 +747,7 @@ return Add(*Q) + cancel(r/g) + def ratsimpmodprime(expr, G, *gens, **args): """ Simplifies a rational expression ``expr`` modulo the prime ideal @@ -723,11 +756,17 @@ >>> from sympy.simplify.simplify import ratsimpmodprime >>> from sympy.abc import x, y - >>> ratsimpmodprime((x + y**5 + y)/(x - y), [x*y**5 - x - y], x, y, order='lex') + >>> eq = (x + y**5 + y)/(x - y) + >>> ratsimpmodprime(eq, [x*y**5 - x - y], x, y, order='lex') (x**2 + x*y + x + y)/(x**2 - x*y) - The algorithm computes a rational simplification which minimizes - the sum of the total degrees of the numerator and the denominator. + If ``polynomial`` is False, the algorithm computes a rational + simplification which minimizes the sum of the total degrees of + the numerator and the denominator. + + If ``polynomial`` is True, this function just brings numerator and + denominator into a canonical form. This is much faster, but has + potentially worse results. References ========== @@ -737,11 +776,16 @@ http://citeseer.ist.psu.edu/viewdoc/summary?doi=10.1.1.163.6984 (specifically, the second algorithm) """ - from sympy.polys import polyoptions as options, parallel_poly_from_expr, degree_list - from sympy.polys.polyerrors import PolificationFailed - from sympy import monomials, symbols, solve, Monomial + from sympy.polys import parallel_poly_from_expr + from sympy.polys.polyerrors import PolificationFailed, DomainError + from sympy import solve, Monomial from sympy.polys.monomialtools import monomial_div - from sympy.core.compatibility import product + from sympy.core.compatibility import combinations_with_replacement + from sympy.utilities.misc import debug + + quick = args.pop('quick', True) + polynomial = args.pop('polynomial', False) + debug('ratsimpmodprime', expr) # usual preparation of polynomials: @@ -749,7 +793,7 @@ try: polys, opt = parallel_poly_from_expr([num, denom] + G, *gens, **args) - except PolificationFailed as exc: + except PolificationFailed: return expr domain = opt.domain @@ -757,25 +801,32 @@ if domain.has_assoc_Field: opt.domain = domain.get_field() else: - raise DomainError("can't compute rational simplification over %s" % domain) + raise DomainError( + "can't compute rational simplification over %s" % domain) # compute only once leading_monomials = [g.LM(opt.order) for g in polys[2:]] + tested = set() def staircase(n): """ Compute all monomials with degree less than ``n`` that are not divisible by any element of ``leading_monomials``. """ + if n == 0: + return [1] S = [] - for m in product(*([range(n + 1)] * len(opt.gens))): - if sum(m) <= n: - if all([monomial_div(m, lmg) is None for lmg in leading_monomials]): - S.append(m) + for mi in combinations_with_replacement(range(len(opt.gens)), n): + m = [0]*len(opt.gens) + for i in mi: + m[i] += 1 + if all([monomial_div(m, lmg) is None for lmg in + leading_monomials]): + S.append(m) - return [Monomial(s).as_expr(*opt.gens) for s in S] + return [Monomial(s).as_expr(*opt.gens) for s in S] + staircase(n - 1) - def _ratsimpmodprime(a, b, N=0, D=0): + def _ratsimpmodprime(a, b, allsol, N=0, D=0): """ Computes a rational simplification of ``a/b`` which minimizes the sum of the total degrees of the numerator and the denominator. @@ -795,31 +846,43 @@ After a simpler representation has been found, the algorithm tries to reduce the degree of the numerator and denominator and returns the result afterwards. + + As an extension, if quick=False, we look at all possible degrees such + that the total degree is less than *or equal to* the best current + solution. We retain a list of all solutions of minimal degree, and try + to find the best one at the end. """ c, d = a, b steps = 0 - while N + D < a.total_degree() + b.total_degree(): + maxdeg = a.total_degree() + b.total_degree() + if quick: + bound = maxdeg - 1 + else: + bound = maxdeg + while N + D <= bound: + if (N, D) in tested: + break + tested.add((N, D)) + M1 = staircase(N) M2 = staircase(D) + debug('%s / %s: %s, %s' % (N, D, M1, M2)) - Cs = symbols("c:%d" % len(M1)) - Ds = symbols("d:%d" % len(M2)) + Cs = symbols("c:%d" % len(M1), cls=Dummy) + Ds = symbols("d:%d" % len(M2), cls=Dummy) + ng = Cs + Ds + + c_hat = Poly( + sum([Cs[i] * M1[i] for i in range(len(M1))]), opt.gens + ng) + d_hat = Poly( + sum([Ds[i] * M2[i] for i in range(len(M2))]), opt.gens + ng) - c_hat = Poly(sum([Cs[i] * M1[i] for i in range(len(M1))]), opt.gens) - d_hat = Poly(sum([Ds[i] * M2[i] for i in range(len(M2))]), opt.gens) + r = reduced(a * d_hat - b * c_hat, G, opt.gens + ng, + order=opt.order, polys=True)[1] - r = reduced(a * d_hat - b * c_hat, G, opt.gens, order=opt.order, polys=True)[1] - - S = r.coeffs() - sol = solve(S, Cs + Ds) - - # If nontrivial solutions exist, solve will give them - # parametrized, i.e. the values of some keys will be - # exprs. Set these to any value different from 0 to obtain - # one nontrivial solution: - for key in list(sol.keys()): - sol[key] = sol[key].subs(dict(list(zip(Cs + Ds, [1] * (len(Cs) + len(Ds)))))) + S = Poly(r, gens=opt.gens).coeffs() + sol = solve(S, Cs + Ds, minimal=True, quick=True) if sol and not all([s == 0 for s in sol.values()]): c = c_hat.subs(sol) @@ -833,188 +896,544 @@ c = Poly(c, opt.gens) d = Poly(d, opt.gens) + if d == 0: + raise ValueError('Ideal not prime?') + + allsol.append((c_hat, d_hat, S, Cs + Ds)) + if N + D != maxdeg: + allsol = [allsol[-1]] break + steps += 1 N += 1 D += 1 - steps += 1 if steps > 0: - c, d = _ratsimpmodprime(c, d, N, D - steps) - c, d = _ratsimpmodprime(c, d, N - steps, D) + c, d, allsol = _ratsimpmodprime(c, d, allsol, N, D - steps) + c, d, allsol = _ratsimpmodprime(c, d, allsol, N - steps, D) - return c, d + return c, d, allsol # preprocessing. this improves performance a bit when deg(num) # and deg(denom) are large: num = reduced(num, G, opt.gens, order=opt.order)[1] denom = reduced(denom, G, opt.gens, order=opt.order)[1] - c, d = _ratsimpmodprime(Poly(num, opt.gens), Poly(denom, opt.gens)) + if polynomial: + return (num/denom).cancel() + + c, d, allsol = _ratsimpmodprime( + Poly(num, opt.gens), Poly(denom, opt.gens), []) + if not quick and allsol: + debug('Looking for best minimal solution. Got: %s' % len(allsol)) + newsol = [] + for c_hat, d_hat, S, ng in allsol: + sol = solve(S, ng, minimal=True, quick=False) + newsol.append((c_hat.subs(sol), d_hat.subs(sol))) + c, d = min(newsol, key=lambda x: len(x[0].terms()) + len(x[1].terms())) if not domain.has_Field: - c = c.clear_denoms(convert=True)[1] - d = d.clear_denoms(convert=True)[1] + cn, c = c.clear_denoms(convert=True) + dn, d = d.clear_denoms(convert=True) + r = Rational(cn, dn) + + return (c*r.q)/(d*r.p) + + +def trigsimp_groebner(expr, hints=[], quick=False, order="grlex", + polynomial=False): + """ + Simplify trigonometric expressions using a groebner basis algorithm. + + This routine takes a fraction involving trigonometric or hyperbolic + expressions, and tries to simplify it. The primary metric is the + total degree. Some attempts are made to choose the simplest possible + expression of the minimal degree, but this is non-rigorous, and also + very slow (see the ``quick=True`` option). + + If ``polynomial`` is set to True, instead of simplifying numerator and + denominator together, this function just brings numerator and denominator + into a canonical form. This is much faster, but has potentially worse + results. However, if the input is a polynomial, then the result is + guaranteed to be an equivalent polynomial of minimal degree. + + The most important option is hints. Its entries can be any of the + following: + + - a natural number + - a function + - an iterable of the form (func, var1, var2, ...) + - anything else, interpreted as a generator + + A number is used to indicate that the search space should be increased. + A function is used to indicate that said function is likely to occur in a + simplified expression. + An iterable is used indicate that func(var1 + var2 + ...) is likely to + occur in a simplified . + An additional generator also indicates that it is likely to occur. + (See examples below). + + This routine carries out various computationally intensive algorithms. + The option ``quick=True`` can be used to suppress one particularly slow + step (at the expense of potentially more complicated results, but never at + the expense of increased total degree). + + Examples + ======== + + >>> from sympy.abc import x, y + >>> from sympy import sin, tan, cos, sinh, cosh, tanh + >>> from sympy.simplify.simplify import trigsimp_groebner + + Suppose you want to simplify ``sin(x)*cos(x)``. Naively, nothing happens: + + >>> ex = sin(x)*cos(x) + >>> trigsimp_groebner(ex) + sin(x)*cos(x) + + This is because ``trigsimp_groebner`` only looks for a simplification + involving just ``sin(x)`` and ``cos(x)``. You can tell it to also try + ``2*x`` by passing ``hints=[2]``: + + >>> trigsimp_groebner(ex, hints=[2]) + sin(2*x)/2 + >>> trigsimp_groebner(sin(x)**2 - cos(x)**2, hints=[2]) + -cos(2*x) + + Increasing the search space this way can quickly become expensive. A much + faster way is to give a specific expression that is likely to occur: + + >>> trigsimp_groebner(ex, hints=[sin(2*x)]) + sin(2*x)/2 + + Hyperbolic expressions are similarly supported: + + >>> trigsimp_groebner(sinh(2*x)/sinh(x)) + 2*cosh(x) + + Note how no hints had to be passed, since the expression already involved + ``2*x``. + + The tangent function is also supported. You can either pass ``tan`` in the + hints, to indicate that than should be tried whenever cosine or sine are, + or you can pass a specific generator: + + >>> trigsimp_groebner(sin(x)/cos(x), hints=[tan]) + tan(x) + >>> trigsimp_groebner(sinh(x)/cosh(x), hints=[tanh(x)]) + tanh(x) + + Finally, you can use the iterable form to suggest that angle sum formulae + should be tried: + + >>> ex = (tan(x) + tan(y))/(1 - tan(x)*tan(y)) + >>> trigsimp_groebner(ex, hints=[(tan, x, y)]) + tan(x + y) + """ + # TODO + # - preprocess by replacing everything by funcs we can handle + # - optionally use cot instead of tan + # - more intelligent hinting. + # For example, if the ideal is small, and we have sin(x), sin(y), + # add sin(x + y) automatically... ? + # - algebraic numbers ... + # - expressions of lowest degree are not distinguished properly + # e.g. 1 - sin(x)**2 + # - we could try to order the generators intelligently, so as to influence + # which monomials appear in the quotient basis + + # THEORY + # ------ + # Ratsimpmodprime above can be used to "simplify" a rational function + # modulo a prime ideal. "Simplify" mainly means finding an equivalent + # expression of lower total degree. + # + # We intend to use this to simplify trigonometric functions. To do that, + # we need to decide (a) which ring to use, and (b) modulo which ideal to + # simplify. In practice, (a) means settling on a list of "generators" + # a, b, c, ..., such that the fraction we want to simplify is a rational + # function in a, b, c, ..., with coefficients in ZZ (integers). + # (2) means that we have to decide what relations to impose on the + # generators. There are two practical problems: + # (1) The ideal has to be *prime* (a technical term). + # (2) The relations have to be polynomials in the generators. + # + # We typically have two kinds of generators: + # - trigonometric expressions, like sin(x), cos(5*x), etc + # - "everything else", like gamma(x), pi, etc. + # + # Since this function is trigsimp, we will concentrate on what to do with + # trigonometric expressions. We can also simplify hyperbolic expressions, + # but the extensions should be clear. + # + # One crucial point is that all *other* generators really should behave + # like indeterminates. In particular if (say) "I" is one of them, then + # in fact I**2 + 1 = 0 and we may and will compute non-sensical + # expressions. However, we can work with a dummy and add the relation + # I**2 + 1 = 0 to our ideal, then substitute back in the end. + # + # Now regarding trigonometric generators. We split them into groups, + # according to the argument of the trigonometric functions. We want to + # organise this in such a way that most trigonometric identities apply in + # the same group. For example, given sin(x), cos(2*x) and cos(y), we would + # group as [sin(x), cos(2*x)] and [cos(y)]. + # + # Our prime ideal will be built in three steps: + # (1) For each group, compute a "geometrically prime" ideal of relations. + # Geometrically prime means that it generates a prime ideal in + # CC[gens], not just ZZ[gens]. + # (2) Take the union of all the generators of the ideals for all groups. + # By the geometric primality condition, this is still prime. + # (3) Add further inter-group relations which preserve primality. + # + # Step (1) works as follows. We will isolate common factors in the + # argument, so that all our generators are of the form sin(n*x), cos(n*x) + # or tan(n*x), with n an integer. Suppose first there are no tan terms. + # The ideal [sin(x)**2 + cos(x)**2 - 1] is geometrically prime, since + # X**2 + Y**2 - 1 is irreducible over CC. + # Now, if we have a generator sin(n*x), than we can, using trig identities, + # express sin(n*x) as a polynomial in sin(x) and cos(x). We can add this + # relation to the ideal, preserving geometric primality, since the quotient + # ring is unchanged. + # Thus we have treated all sin and cos terms. + # For tan(n*x), we add a relation tan(n*x)*cos(n*x) - sin(n*x) = 0. + # (This requires of course that we already have relations for cos(n*x) and + # sin(n*x).) It is not obvious, but it seems that this preserves geometric + # primality. + # XXX A real proof would be nice. HELP! + # Sketch that is a prime ideal of + # CC[S, C, T]: + # - it suffices to show that the projective closure in CP**3 is + # irreducible + # - using the half-angle substitutions, we can express sin(x), tan(x), + # cos(x) as rational functions in tan(x/2) + # - from this, we get a rational map from CP**1 to our curve + # - this is a morphism, hence the curve is prime + # + # Step (2) is trivial. + # + # Step (3) works by adding selected relations of the form + # sin(x + y) - sin(x)*cos(y) - sin(y)*cos(x), etc. Geometric primality is + # preserved by the same argument as before. + + from sympy.utilities.misc import debug + from sympy import symbols + from sympy.polys import parallel_poly_from_expr, groebner, ZZ + from sympy.polys.polyerrors import PolificationFailed + + sin, cos, tan = C.sin, C.cos, C.tan + sinh, cosh, tanh = C.sinh, C.cosh, C.tanh + + def parse_hints(hints): + """Split hints into (n, funcs, iterables, gens).""" + n = 1 + funcs, iterables, gens = [], [], [] + for e in hints: + if isinstance(e, (int, Integer)): + n = e + elif isinstance(e, FunctionClass): + funcs.append(e) + elif iterable(e): + iterables.append((e[0], e[1:])) + # XXX sin(x+2y)? + # Note: we go through polys so e.g. + # sin(-x) -> -sin(x) -> sin(x) + gens.extend(parallel_poly_from_expr( + [e[0](x) for x in e[1:]] + [e[0](Add(*e[1:]))])[1].gens) + else: + gens.append(e) + return n, funcs, iterables, gens + + def build_ideal(x, terms): + """ + Build generators for our ideal. Terms is an iterable with elements of + the form (fn, coeff), indicating that we have a generator fn(coeff*x). + + If any of the terms is trigonometric, sin(x) and cos(x) are guaranteed + to appear in terms. Similarly for hyperbolic functions. For tan(n*x), + sin(n*x) and cos(n*x) are guaranteed. + """ + gens = [] + I = [] + y = Dummy('y') + for fn, coeff in terms: + for c, s, t, rel in ( + [cos, sin, tan, cos(x)**2 + sin(x)**2 - 1], + [cosh, sinh, tanh, cosh(x)**2 - sinh(x)**2 - 1]): + if coeff == 1 and fn in [c, s]: + I.append(rel) + elif fn == t: + I.append(t(coeff*x)*c(coeff*x) - s(coeff*x)) + elif fn in [c, s]: + cn = fn(coeff*y).expand(trig=True).subs(y, x) + I.append(fn(coeff*x) - cn) + return list(set(I)) + + def analyse_gens(gens, hints): + """ + Analyse the generators ``gens``, using the hints ``hints``. + + The meaning of ``hints`` is described in the main docstring. + Return a new list of generators, and also the ideal we should + work with. + """ + # First parse the hints + n, funcs, iterables, extragens = parse_hints(hints) + debug('n=%s' % n, 'funcs:', funcs, 'iterables:', + iterables, 'extragens:', extragens) + + # We just add the extragens to gens and analyse them as before + gens = list(gens) + gens.extend(extragens) + + # remove duplicates + funcs = list(set(funcs)) + iterables = list(set(iterables)) + gens = list(set(gens)) + + # all the functions we can do anything with + allfuncs = set([sin, cos, tan, sinh, cosh, tanh]) + # sin(3*x) -> ((3, x), sin) + trigterms = [(g.args[0].as_coeff_mul(), g.func) for g in gens + if g.func in allfuncs] + # Our list of new generators - start with anything that we cannot + # work with (i.e. is not a trigonometric term) + freegens = [g for g in gens if g.func not in allfuncs] + newgens = [] + trigdict = {} + for (coeff, var), fn in trigterms: + trigdict.setdefault(var, []).append((coeff, fn)) + res = [] # the ideal + + for key, val in trigdict.items(): + # We have now assembeled a dictionary. Its keys are common + # arguments in trigonometric expressions, and values are lists of + # pairs (fn, coeff). x0, (fn, coeff) in trigdict means that we + # need to deal with fn(coeff*x0). We take the rational gcd of the + # coeffs, call it ``gcd``. We then use x = x0/gcd as "base symbol", + # all other arguments are integral multiples thereof. + # We will build an ideal which works with sin(x), cos(x). + # If hint tan is provided, also work with tan(x). Moreover, if + # n > 1, also work with sin(k*x) for k <= n, and similarly for cos + # (and tan if the hint is provided). Finally, any generators which + # the ideal does not work with but we need to accomodate (either + # because it was in expr or because it was provided as a hint) + # we also build into the ideal. + # This selection process is expressed in the list ``terms``. + # build_ideal then generates the actual relations in our ideal, + # from this list. + fns = [x[1] for x in val] + val = [x[0] for x in val] + gcd = reduce(igcd, val) + terms = [(fn, v/gcd) for (fn, v) in zip(fns, val)] + fs = set(funcs + fns) + for c, s, t in ([cos, sin, tan], [cosh, sinh, tanh]): + if any(x in fs for x in (c, s, t)): + fs.add(c) + fs.add(s) + for fn in fs: + for k in range(1, n + 1): + terms.append((fn, k)) + extra = [] + for fn, v in terms: + if fn == tan: + extra.append((sin, v)) + extra.append((cos, v)) + if fn in [sin, cos] and tan in fs: + extra.append((tan, v)) + if fn == tanh: + extra.append((sinh, v)) + extra.append((cosh, v)) + if fn in [sinh, cosh] and tanh in fs: + extra.append((tanh, v)) + terms.extend(extra) + x = gcd*Mul(*key) + r = build_ideal(x, terms) + res.extend(r) + newgens.extend(set(fn(v*x) for fn, v in terms)) + + # Add generators for compound expressions from iterables + for fn, args in iterables: + if fn == tan: + # Tan expressions are recovered from sin and cos. + iterables.extend([(sin, args), (cos, args)]) + elif fn == tanh: + # Tanh expressions are recovered from sihn and cosh. + iterables.extend([(sinh, args), (cosh, args)]) + else: + dummys = symbols('d:%i' % len(args), cls=Dummy) + expr = fn( + Add(*dummys)).expand(trig=True).subs(list(zip(dummys, args))) + res.append(fn(Add(*args)) - expr) + + if myI in gens: + res.append(myI**2 + 1) + freegens.remove(myI) + newgens.append(myI) + + return res, freegens, newgens + + myI = Dummy('I') + expr = expr.subs(S.ImaginaryUnit, myI) + subs = [(myI, S.ImaginaryUnit)] + + num, denom = cancel(expr).as_numer_denom() + try: + (pnum, pdenom), opt = parallel_poly_from_expr([num, denom]) + except PolificationFailed: + return expr + debug('initial gens:', opt.gens) + ideal, freegens, gens = analyse_gens(opt.gens, hints) + debug('ideal:', ideal) + debug('new gens:', gens, " -- len", len(gens)) + debug('free gens:', freegens, " -- len", len(gens)) + # NOTE we force the domain to be ZZ to stop polys from injecting generators + # (which is usually a sign of a bug in the way we build the ideal) + if not gens: + return expr + G = groebner(ideal, order=order, gens=gens, domain=ZZ) + debug('groebner basis:', list(G), " -- len", len(G)) + + # If our fraction is a polynomial in the free generators, simplify all + # coefficients separately: + if freegens and pdenom.has_only_gens(*set(gens).intersection(pdenom.gens)): + num = Poly(num, gens=gens+freegens).eject(*gens) + res = [] + for monom, coeff in num.terms(): + ourgens = set(parallel_poly_from_expr([coeff, denom])[1].gens) + # We compute the transitive closure of all generators that can + # be reached from our generators through relations in the ideal. + changed = True + while changed: + changed = False + for p in ideal: + p = Poly(p) + if not ourgens.issuperset(p.gens) and \ + not p.has_only_gens(*set(p.gens).difference(ourgens)): + changed = True + ourgens.update(p.exclude().gens) + # NOTE preserve order! + realgens = [x for x in gens if x in ourgens] + # The generators of the ideal have now been (implicitely) split + # into two groups: those involving ourgens and those that don't. + # Since we took the transitive closure above, these two groups + # live in subgrings generated by a *disjoint* set of variables. + # Any sensible groebner basis algorithm will preserve this disjoint + # structure (i.e. the elements of the groebner basis can be split + # similarly), and and the two subsets of the groebner basis then + # form groebner bases by themselves. (For the smaller generating + # sets, of course.) + ourG = [g.as_expr() for g in G.polys if + g.has_only_gens(*ourgens.intersection(g.gens))] + res.append(Mul(*[a**b for a, b in zip(freegens, monom)]) * \ + ratsimpmodprime(coeff/denom, ourG, order=order, + gens=realgens, quick=quick, domain=ZZ, + polynomial=polynomial).subs(subs)) + return Add(*res) + # NOTE The following is simpler and has less assumptions on the + # groebner basis algorithm. If the above turns out to be broken, + # use this. + return Add(*[Mul(*[a**b for a, b in zip(freegens, monom)]) * \ + ratsimpmodprime(coeff/denom, list(G), order=order, + gens=gens, quick=quick, domain=ZZ) + for monom, coeff in num.terms()]) + else: + return ratsimpmodprime( + expr, list(G), order=order, gens=freegens+gens, + quick=quick, domain=ZZ, polynomial=polynomial).subs(subs) - return c/d -def trigsimp(expr, deep=False, recursive=False): +_trigs = (C.TrigonometricFunction, C.HyperbolicFunction) + + +def trigsimp(expr, **opts): """ reduces expression by using known trig identities Notes ===== - deep: - - Apply trigsimp inside all objects with arguments + method: + - Determine the method to use. Valid choices are 'matching' (default), + 'groebner', 'combined', and 'fu'. If 'matching', simplify the + expression recursively by targeting common patterns. If 'groebner', apply + an experimental groebner basis algorithm. In this case further options + are forwarded to ``trigsimp_groebner``, please refer to its docstring. + If 'combined', first run the groebner basis algorithm with small + default parameters, then run the 'matching' algorithm. 'fu' runs the + collection of trigonometric transformations described by Fu, et al. + (see the `fu` docstring). - recursive: - - Use common subexpression elimination (cse()) and apply - trigsimp recursively (this is quite expensive if the - expression is large) Examples ======== - >>> from sympy import trigsimp, sin, cos, log, cosh, sinh + >>> from sympy import trigsimp, sin, cos, log >>> from sympy.abc import x, y >>> e = 2*sin(x)**2 + 2*cos(x)**2 >>> trigsimp(e) 2 - >>> trigsimp(log(e)) - log(2*sin(x)**2 + 2*cos(x)**2) - >>> trigsimp(log(e), deep=True) - log(2) - - """ - if not expr.has(C.TrigonometricFunction, C.HyperbolicFunction): - return expr - - if recursive: - w, g = cse(expr) - g = _trigsimp(g[0], deep) - - for sub in reversed(w): - g = g.subs(sub[0], sub[1]) - g = _trigsimp(g, deep) - result = g - else: - result = _trigsimp(expr, deep) - - return result -def _trigsimp(expr, deep=False): - """recursive helper for trigsimp""" - a, b, c = list(map(Wild, 'abc')) - sin, cos, tan, cot = C.sin, C.cos, C.tan, C.cot - sinh, cosh, tanh, coth = C.sinh, C.cosh, C.tanh, C.coth - # for the simplifications like sinh/cosh -> tanh: - matchers_division = ( - (a*sin(b)**c/cos(b)**c, a*tan(b)**c), - (a*tan(b)**c*cos(b)**c, a*sin(b)**c), - (a*cot(b)**c*sin(b)**c, a*cos(b)**c), - (a*tan(b)**c/sin(b)**c, a/cos(b)**c), - (a*cot(b)**c/cos(b)**c, a/sin(b)**c), - (a*cot(b)**c*tan(b)**c, a), - - (a*sinh(b)**c/cosh(b)**c, a*tanh(b)**c), - (a*tanh(b)**c*cosh(b)**c, a*sinh(b)**c), - (a*coth(b)**c*sinh(b)**c, a*cosh(b)**c), - (a*tanh(b)**c/sinh(b)**c, a/cosh(b)**c), - (a*coth(b)**c/cosh(b)**c, a/sinh(b)**c), - (a*coth(b)**c*tanh(b)**c, a) - ) - # for cos(x)**2 + sin(x)**2 -> 1 - matchers_identity = ( - (a*sin(b)**2, a - a*cos(b)**2), - (a*tan(b)**2, a*(1/cos(b))**2 - a), - (a*cot(b)**2, a*(1/sin(b))**2 - a), - (a*sin(b + c), a*(sin(b)*cos(c) + sin(c)*cos(b))), - (a*cos(b + c), a*(cos(b)*cos(c) - sin(b)*sin(c))), - (a*tan(b + c), a*((tan(b) + tan(c))/(1 - tan(b)*tan(c)))), + Simplification occurs wherever trigonometric functions are located. - (a*sinh(b)**2, a*cosh(b)**2 - a), - (a*tanh(b)**2, a - a*(1/cosh(b))**2), - (a*coth(b)**2, a + a*(1/sinh(b))**2), - (a*sinh(b + c), a*(sinh(b)*cosh(c) + sinh(c)*cosh(b))), - (a*cosh(b + c), a*(cosh(b)*cosh(c) + sinh(b)*sinh(c))), - (a*tanh(b + c), a*((tanh(b) + tanh(c))/(1 + tanh(b)*tanh(c)))) - ) + >>> trigsimp(log(e)) + log(2) - # Reduce any lingering artefacts, such as sin(x)**2 changing - # to 1-cos(x)**2 when sin(x)**2 was "simpler" - artifacts = ( - (a - a*cos(b)**2 + c, a*sin(b)**2 + c, cos), - (a - a*(1/cos(b))**2 + c, -a*tan(b)**2 + c, cos), - (a - a*(1/sin(b))**2 + c, -a*cot(b)**2 + c, sin), - - (a - a*cosh(b)**2 + c, -a*sinh(b)**2 + c, cosh), - (a - a*(1/cosh(b))**2 + c, a*tanh(b)**2 + c, cosh), - (a + a*(1/sinh(b))**2 + c, a*coth(b)**2 + c, sinh) - ) + Using `method="groebner"` (or `"combined"`) might lead to greater + simplification. - if expr.is_Mul: - # do some simplifications like sin/cos -> tan: - for pattern, simp in matchers_division: - res = expr.match(pattern) - if res and res.get(c, 0): - # if "a" contains any of sin("b"), cos("b"), tan("b"), cot("b"), - # sinh("b"), cosh("b"), tanh("b") or coth("b), - # skip the simplification: - if res[a].has(C.TrigonometricFunction, C.HyperbolicFunction): - continue - # simplify and finish: - expr = simp.subs(res) - break # process below + The old trigsimp routine can be accessed as with method 'old'. - if expr.is_Add: - # The types of hyper functions we are looking for - # Scan for the terms we need - args = [] - for term in expr.args: - term = _trigsimp(term, deep) - for pattern, result in matchers_identity: - res = term.match(pattern) - if res is not None: - term = result.subs(res) - break - args.append(term) - if args != expr.args: - expr = Add(*args) + >>> from sympy import coth, tanh + >>> t = 3*tanh(x)**7 - 2/coth(x)**7 + >>> trigsimp(t, method='old') == t + True + >>> trigsimp(t) + tanh(x)**7 - # Reduce any lingering artifacts, such as sin(x)**2 changing - # to 1 - cos(x)**2 when sin(x)**2 was "simpler" - for pattern, result, ex in artifacts: - if expr.is_number: - break - # Substitute a new wild that excludes some function(s) - # to help influence a better match. This is because - # sometimes, for example, 'a' would match sec(x)**2 - a_t = Wild('a', exclude=[ex]) - pattern = pattern.subs(a, a_t) - result = result.subs(a, a_t) + """ + from sympy.simplify.fu import fu - m = expr.match(pattern) - while m is not None: - if m[a_t] == 0 or -m[a_t] in m[c].args or m[a_t] + m[c] == 0: - break - expr = result.subs(m) - m = expr.match(pattern) + expr = sympify(expr) - return expr + old = opts.pop('old', False) + if not old: + opts.pop('deep', None) + recursive = opts.pop('recursive', None) + method = opts.pop('method', 'matching') + else: + method = 'old' - elif expr.is_Mul or expr.is_Pow or deep and expr.args: - return expr.func(*[_trigsimp(a, deep) for a in expr.args]) + def groebnersimp(ex, **opts): + def traverse(e): + if e.is_Atom: + return e + args = [traverse(x) for x in e.args] + if e.is_Function or e.is_Pow: + args = [trigsimp_groebner(x, **opts) for x in args] + return e.func(*args) + return trigsimp_groebner(traverse(ex), **opts) + + trigsimpfunc = { + 'fu': (lambda x: fu(x)), + 'matching': (lambda x: futrig(x)), + 'groebner': (lambda x: groebnersimp(x, **opts)), + 'combined': (lambda x: futrig(groebnersimp(x, + polynomial=True, hints=[2, tan]))), + 'old': lambda x: trigsimp_old(x, **opts), + }[method] - return expr + return trigsimpfunc(expr) def collect_sqrt(expr, evaluate=True): """Return expr with terms having common square roots collected together. If ``evaluate`` is False a count indicating the number of sqrt-containing - terms will be returned and the returned expression will be an unevaluated - Add with args ordered by default_sort_key. + terms will be returned and, if non-zero, the terms of the Add will be + returned, else the expression itself will be returned as a single term. + If ``evaluate`` is True, the expression with any collected terms will be + returned. Note: since I = sqrt(-1), it is collected, too. @@ -1038,58 +1457,63 @@ terms will be returned: >>> collect_sqrt(a*r2 + b*r2 + a*r3 + b*r5, evaluate=False) - ((sqrt(2)*(a + b), sqrt(3)*a, sqrt(5)*b), 3) + ((sqrt(3)*a, sqrt(5)*b, sqrt(2)*(a + b)), 3) >>> collect_sqrt(a*sqrt(2) + b, evaluate=False) ((b, sqrt(2)*a), 1) >>> collect_sqrt(a + b, evaluate=False) ((a + b,), 0) + See Also + ======== + collect, collect_const, rcollect """ + # this step will help to standardize any complex arguments + # of sqrts coeff, expr = expr.as_content_primitive() vars = set() for a in Add.make_args(expr): for m in a.args_cnc()[0]: - if m.is_number and (m.is_Pow and m.exp.is_Rational and m.exp.q == 2 or \ - m is S.ImaginaryUnit): + if m.is_number and ( + m.is_Pow and m.exp.is_Rational and m.exp.q == 2 or + m is S.ImaginaryUnit): vars.add(m) - vars = list(vars) - if not evaluate: - vars.sort(key=default_sort_key) - vars.reverse() # since it will be reversed below - vars.sort(key=count_ops) - vars.reverse() - d = collect_const(expr, *vars, **dict(first=False)) + + # we only want radicals, so exclude Number handling; in this case + # d will be evaluated + d = collect_const(expr, *vars, **dict(Numbers=False)) hit = expr != d - d *= coeff if not evaluate: nrad = 0 - args = list(Add.make_args(d)) - for m in args: + # make the evaluated args canonical + args = list(ordered(Add.make_args(d))) + for i, m in enumerate(args): c, nc = m.args_cnc() for ci in c: + # XXX should this be restricted to ci.is_number as above? if ci.is_Pow and ci.exp.is_Rational and ci.exp.q == 2 or \ - ci is S.ImaginaryUnit: + ci is S.ImaginaryUnit: nrad += 1 break - if hit or nrad: - args.sort(key=default_sort_key) - else: + args[i] *= coeff + if not (hit or nrad): args = [Add(*args)] return tuple(args), nrad - return d + return coeff*d + -def collect_const(expr, *vars, **first): +def collect_const(expr, *vars, **kwargs): """A non-greedy collection of terms with similar number coefficients in an Add expr. If ``vars`` is given then only those constants will be - targeted. + targeted. Although any Number can also be targeted, if this is not + desired set ``Numbers=False`` and no Float or Rational will be collected. Examples ======== >>> from sympy import sqrt - >>> from sympy.abc import a, s + >>> from sympy.abc import a, s, x, y, z >>> from sympy.simplify.simplify import collect_const >>> collect_const(sqrt(3) + sqrt(3)*(1 + sqrt(2))) sqrt(3)*(sqrt(2) + 2) @@ -1101,56 +1525,69 @@ >>> collect_const(sqrt(3)*s + sqrt(3) + sqrt(7)*s + sqrt(7), sqrt(3)) sqrt(7) + sqrt(3)*(sqrt(2) + 3) + sqrt(7)*(sqrt(2) + 2) - If no constants are provided then a leading Rational might be returned: - - >>> collect_const(2*sqrt(3) + 4*a*sqrt(5)) - 2*(2*sqrt(5)*a + sqrt(3)) - >>> collect_const(2*sqrt(3) + 4*a*sqrt(5), sqrt(3)) - 4*sqrt(5)*a + 2*sqrt(3) - """ + The collection is sign-sensitive, giving higher precedence to the + unsigned values: - if first.get('first', True): - c, p = sympify(expr).as_content_primitive() - else: - c, p = S.One, expr - if c is not S.One: - if not vars: - return _keep_coeff(c, collect_const(p, *vars, **dict(first=False))) - # else don't leave the Rational on the outside - return c*collect_const(p, *vars, **dict(first=False)) + >>> collect_const(x - y - z) + x - (y + z) + >>> collect_const(-y - z) + -(y + z) + >>> collect_const(2*x - 2*y - 2*z, 2) + 2*(x - y - z) + >>> collect_const(2*x - 2*y - 2*z, -2) + 2*x - 2*(y + z) - if not (expr.is_Add or expr.is_Mul): + See Also + ======== + collect, collect_sqrt, rcollect + """ + if not expr.is_Add: return expr + recurse = False + Numbers = kwargs.get('Numbers', True) + if not vars: recurse = True vars = set() - for a in Add.make_args(expr): + for a in expr.args: for m in Mul.make_args(a): if m.is_number: vars.add(m) - vars = sorted(vars, key=count_ops) - # Rationals get autodistributed on Add so don't bother with them - vars = [v for v in vars if not v.is_Rational] - - if not vars: - return expr + else: + vars = sympify(vars) + if not Numbers: + vars = [v for v in vars if not v.is_Number] + vars = list(ordered(vars)) for v in vars: terms = defaultdict(list) + Fv = Factors(v) for m in Add.make_args(expr): - i = [] - d = [] - for a in Mul.make_args(m): - if a == v: - d.append(a) - else: - i.append(a) - ai, ad = [Mul(*w) for w in [i, d]] - terms[ad].append(ai) + f = Factors(m) + q, r = f.div(Fv) + if r.is_one: + # only accept this as a true factor if + # it didn't change an exponent from an Integer + # to a non-Integer, e.g. 2/sqrt(2) -> sqrt(2) + # -- we aren't looking for this sort of change + fwas = f.factors.copy() + fnow = q.factors + if not any(k in fwas and fwas[k].is_Integer and not + fnow[k].is_Integer for k in fnow): + terms[v].append(q.as_expr()) + continue + terms[S.One].append(m) + args = [] hit = False - for k, v in terms.items(): + uneval = False + for k in ordered(terms): + v = terms[k] + if k is S.One: + args.extend(v) + continue + if len(v) > 1: v = Add(*v) hit = True @@ -1158,23 +1595,38 @@ vars.append(v) else: v = v[0] - args.append(k*v) + + # be careful not to let uneval become True unless + # it must be because it's going to be more expensive + # to rebuild the expression as an unevaluated one + if Numbers and k.is_Number and v.is_Add: + args.append(_keep_coeff(k, v, sign=True)) + uneval = True + else: + args.append(k*v) + if hit: - expr = Add(*args) + if uneval: + expr = _unevaluated_Add(*args) + else: + expr = Add(*args) if not expr.is_Add: break + return expr + def _split_gcd(*a): """ - split the list of integers `a` into a list of integers a1 having - g = gcd(a1) and a list a2 whose elements are not divisible by g - Returns g, a1, a2 + split the list of integers ``a`` into a list of integers, ``a1`` having + ``g = gcd(a1)``, and a list ``a2`` whose elements are not divisible by + ``g``. Returns ``g, a1, a2`` Examples ======== + >>> from sympy.simplify.simplify import _split_gcd - >>> _split_gcd(55,35,22,14,77,10) + >>> _split_gcd(55, 35, 22, 14, 77, 10) (5, [55, 35, 10], [22, 14, 77]) """ g = a[0] @@ -1189,6 +1641,98 @@ b1.append(x) return g, b1, b2 +def _is_sum_surds(p): + args = p.args if p.is_Add else [p] + for y in args: + if not ((y**2).is_Rational and y.is_real): + return False + return True + +def _nthroot_solve(p, n, prec): + """ + helper function for ``nthroot`` + It denests ``p**Rational(1, n)`` using its minimal polynomial + """ + from sympy.polys.numberfields import _minimal_polynomial_sq + from sympy.solvers import solve + while n % 2 == 0: + p = sqrtdenest(sqrt(p)) + n = n // 2 + if n == 1: + return p + pn = p**Rational(1, n) + x = Symbol('x') + f = _minimal_polynomial_sq(p, n, x) + if f is None: + return None + sols = solve(f, x) + for sol in sols: + if abs(sol - pn).n() < 1./10**prec: + sol = sqrtdenest(sol) + if _mexpand(sol**n) == p: + return sol + +def nthroot(expr, n, max_len=4, prec=15): + """ + compute a real nth-root of a sum of surds + + Parameters + ========== + + expr : sum of surds + n : integer + max_len : maximum number of surds passed as constants to ``nsimplify`` + + Algorithm + ========= + + First ``nsimplify`` is used to get a candidate root; if it is not a + root the minimal polynomial is computed; the answer is one of its + roots. + + Examples + ======== + + >>> from sympy.simplify.simplify import nthroot + >>> from sympy import Rational, sqrt + >>> nthroot(90 + 34*sqrt(7), 3) + sqrt(7) + 3 + + """ + from sympy.simplify.sqrtdenest import sqrt_depth, is_algebraic + expr = sympify(expr) + n = sympify(n) + p = expr**Rational(1, n) + if not n.is_integer: + return p + if not _is_sum_surds(expr): + return p + surds = [] + coeff_muls = [x.as_coeff_Mul() for x in expr.args] + for x, y in coeff_muls: + if not x.is_rational: + return p + if y is S.One: + continue + if not (y.is_Pow and y.exp == S.Half and y.base.is_integer): + return p + surds.append(y) + surds.sort() + surds = surds[:max_len] + if expr < 0 and n % 2 == 1: + p = (-expr)**Rational(1, n) + a = nsimplify(p, constants=surds) + res = a if _mexpand(a**n) == _mexpand(-expr) else p + return -res + a = nsimplify(p, constants=surds) + if _mexpand(a) is not _mexpand(p) and _mexpand(a**n) == _mexpand(expr): + return _mexpand(a) + expr = _nthroot_solve(expr, n, prec) + if expr is None: + return p + return expr + + def split_surds(expr): """ split an expression with terms whose squares are rationals @@ -1197,13 +1741,14 @@ Examples ======== + >>> from sympy import sqrt >>> from sympy.simplify.simplify import split_surds >>> split_surds(3*sqrt(3) + sqrt(5)/7 + sqrt(6) + sqrt(10) + sqrt(15)) (3, sqrt(2) + sqrt(5) + 3, sqrt(5)/7 + sqrt(10)) """ args = sorted(expr.args, key=default_sort_key) - coeff_muls = [x.as_coeff_Mul() for x in args] + coeff_muls = [x.as_coeff_Mul() for x in args] surds = [x[1]**2 for x in coeff_muls if x[1].is_Pow] surds.sort(key=default_sort_key) g, b1, b2 = _split_gcd(*surds) @@ -1228,6 +1773,7 @@ b = Add(*a2v) return g2, a, b + def rad_rationalize(num, den): """ Rationalize num/den by removing square roots in the denominator; @@ -1235,6 +1781,7 @@ Examples ======== + >>> from sympy import sqrt >>> from sympy.simplify.simplify import rad_rationalize >>> rad_rationalize(sqrt(3), 1 + sqrt(2)/3) @@ -1262,12 +1809,15 @@ you do not want the simplification to occur for symbolic denominators, set ``symbolic`` to False. - If there are more than ``max_terms`` radical terms do not simplify. + If there are more than ``max_terms`` radical terms then the expression is + returned unchanged. Examples ======== >>> from sympy import radsimp, sqrt, Symbol, denom, pprint, I + >>> from sympy import factor_terms, fraction, signsimp + >>> from sympy.simplify.simplify import collect_sqrt >>> from sympy.abc import a, b, c >>> radsimp(1/(I + 1)) @@ -1279,23 +1829,32 @@ >>> radsimp(e) sqrt(2)*(x + y) - Terms are collected automatically: + No simplification beyond removal of the gcd is done. One might + want to polish the result a little, however, by collecting + square root terms: >>> r2 = sqrt(2) >>> r5 = sqrt(5) - >>> pprint(radsimp(1/(y*r2 + x*r2 + a*r5 + b*r5))) - ___ ___ - \/ 5 *(-a - b) + \/ 2 *(x + y) - -------------------------------------------- - 2 2 2 2 - - 5*a - 10*a*b - 5*b + 2*x + 4*x*y + 2*y - - If radicals in the denominator cannot be removed, the original expression - will be returned. If the denominator was 1 then any square roots will also - be collected: + >>> ans = radsimp(1/(y*r2 + x*r2 + a*r5 + b*r5)); pprint(ans) + ___ ___ ___ ___ + \/ 5 *a + \/ 5 *b - \/ 2 *x - \/ 2 *y + ------------------------------------------ + 2 2 2 2 + 5*a + 10*a*b + 5*b - 2*x - 4*x*y - 2*y + + >>> n, d = fraction(ans) + >>> pprint(factor_terms(signsimp(collect_sqrt(n))/d, radical=True)) + ___ ___ + \/ 5 *(a + b) - \/ 2 *(x + y) + ------------------------------------------ + 2 2 2 2 + 5*a + 10*a*b + 5*b - 2*x - 4*x*y - 2*y + + If radicals in the denominator cannot be removed or there is no denominator, + the original expression will be returned. >>> radsimp(sqrt(2)*x + sqrt(2)) - sqrt(2)*(x + 1) + sqrt(2)*x + sqrt(2) Results with symbols will not always be valid for all substitutions: @@ -1310,101 +1869,162 @@ >>> radsimp(eq, symbolic=False) 1/(a + b*sqrt(c)) + """ + from sympy.core.mul import _unevaluated_Mul as _umul + from sympy.core.exprtools import Factors + + syms = symbols("a:d A:D") + def _num(rterms): + # return the multiplier that will simplify the expression described + # by rterms [(sqrt arg, coeff), ... ] + a, b, c, d, A, B, C, D = syms + if len(rterms) == 2: + reps = dict(list(zip([A, a, B, b], [j for i in rterms for j in i]))) + return ( + sqrt(A)*a - sqrt(B)*b).xreplace(reps) + if len(rterms) == 3: + reps = dict(list(zip([A, a, B, b, C, c], [j for i in rterms for j in i]))) + return ( + (sqrt(A)*a + sqrt(B)*b - sqrt(C)*c)*(2*sqrt(A)*sqrt(B)*a*b - A*a**2 - + B*b**2 + C*c**2)).xreplace(reps) + elif len(rterms) == 4: + reps = dict(list(zip([A, a, B, b, C, c, D, d], [j for i in rterms for j in i]))) + return ((sqrt(A)*a + sqrt(B)*b - sqrt(C)*c - sqrt(D)*d)*(2*sqrt(A)*sqrt(B)*a*b + - A*a**2 - B*b**2 - 2*sqrt(C)*sqrt(D)*c*d + C*c**2 + + D*d**2)*(-8*sqrt(A)*sqrt(B)*sqrt(C)*sqrt(D)*a*b*c*d + A**2*a**4 - + 2*A*B*a**2*b**2 - 2*A*C*a**2*c**2 - 2*A*D*a**2*d**2 + B**2*b**4 - + 2*B*C*b**2*c**2 - 2*B*D*b**2*d**2 + C**2*c**4 - 2*C*D*c**2*d**2 + + D**2*d**4)).xreplace(reps) + elif len(rterms) == 1: + return sqrt(rterms[0][0]) + else: + raise NotImplementedError def handle(expr): - if expr.is_Atom or not symbolic and expr.free_symbols: + if expr.is_Atom: return expr + n, d = fraction(expr) - if d is S.One: - nexpr = expr.func(*[handle(ai) for ai in expr.args]) - return nexpr + + if d.is_Atom: + # n can't be an Atom since expr is not an Atom + n = n.func(*[handle(a) for a in n.args]) + return _umul(n, 1/d) + elif n is not S.One: + return Mul(n, handle(1/d)) elif d.is_Mul: - nargs = [] - dargs = [] - for di in d.args: - ni, di = fraction(handle(1/di)) - nargs.append(ni) - dargs.append(di) - return n*Mul(*nargs)/Mul(*dargs) - elif d.is_Add: - d = radsimp(d) - elif d.is_Pow and d.exp.is_Rational and d.exp.q == 2: - d = sqrtdenest(sqrt(d.base))**d.exp.p + return _umul(*[handle(1/d) for d in d.args]) - changed = False - while 1: + if not symbolic and d.free_symbols: + return expr + + if d.is_Pow and d.exp.is_Rational and d.exp.q == 2: + d2 = sqrtdenest(sqrt(d.base))**d.exp.p + if d2 != d: + return handle(1/d2) + elif d.is_Pow and (d.exp.is_integer or d.base.is_positive): + # (1/d**i) = (1/d)**i + return handle(1/d.base)**d.exp + + if not (d.is_Add or d.is_Pow and d.exp.is_Rational and d.exp.q == 2): + return 1/d.func(*[handle(a) for a in d.args]) + + # handle 1/d treating d as an Add (though it may not be) + + keep = True # keep changes that are made + + # flatten it and collect radicals after checking for special + # conditions + d = _mexpand(d) + + # did it change? + if d.is_Atom: + return 1/d + + # is it a number that might be handled easily? + if d.is_number: + _d = nsimplify(d) + if _d.is_Number and _d.equals(d): + return 1/_d + + while True: # collect similar terms - d, nterms = collect_sqrt(_mexpand(d), evaluate=False) - d = Add._from_args(d) - if nterms > max_terms: + collected = defaultdict(list) + for m in Add.make_args(d): # d might have become non-Add + p2 = [] + other = [] + for i in Mul.make_args(m): + if i.is_Pow and (i.exp is S.Half or + i.exp.is_Rational and i.exp.q != 1 and + log(i.exp.q, 2).is_Integer): + p2.append(i.base if i.exp is S.Half else i.base**(2*i.exp)) + elif i is S.ImaginaryUnit: + p2.append(S.NegativeOne) + else: + other.append(i) + collected[tuple(ordered(p2))].append(Mul(*other)) + rterms = list(ordered(list(collected.items()))) + rterms = [(Mul(*i), Add(*j)) for i, j in rterms] + nrad = len(rterms) - (1 if rterms[0][0] is S.One else 0) + if nrad < 1: break - - # check to see if we are done: - # - no radical terms - # - if there are more than 3 radical terms, or - # there 3 radical terms and a constant, use rad_rationalize - if not nterms: + elif nrad > max_terms: + # there may have been invalid operations leading to this point + # so don't keep changes, e.g. this expression is troublesome + # in collecting terms so as not to raise the issue of 2834: + # r = sqrt(sqrt(5) + 5) + # eq = 1/(sqrt(5)*r + 2*sqrt(5)*sqrt(-sqrt(5) + 5) + 5*r) + keep = False break - if nterms > 3 or nterms == 3 and len(d.args) > 4: - if all([(x**2).is_Integer for x in d.args]): - nd, d = rad_rationalize(S.One, d) - n = _mexpand(n*nd) + if len(rterms) > 4: + # in general, only 4 terms can be removed with repeated squaring + # but other considerations can guide selection of radical terms + # so that radicals are removed + if all([x.is_Integer and (y**2).is_Rational for x, y in rterms]): + nd, d = rad_rationalize(S.One, Add._from_args( + [sqrt(x)*y for x, y in rterms])) + n *= nd else: - n, d = fraction(expr) + # is there anything else that might be attempted? + keep = False break - changed = True - - # now match for a radical - if d.is_Add and len(d.args) == 4: - r = d.match(a + b*sqrt(c) + D*sqrt(E)) - nmul = (a - b*sqrt(c) - D*sqrt(E)).xreplace(r) - d = (a**2 - c*b**2 - E*D**2 - 2*b*D*sqrt(c*E)).xreplace(r) - n1 = n/d - if denom(n1) is not S.One: - n = -(-n/d) - else: - n = n1 - n, d = fraction(n*nmul) - else: - r = d.match(a + b*sqrt(c)) - if not r or r[b] == 0: - r = d.match(b*sqrt(c)) - if r is None: - break - r[a] = S.Zero - va, vb, vc = r[a],r[b],r[c] + num = powsimp(_num(rterms)) + n *= num + d *= num + d = _mexpand(d) + if d.is_Atom: + break - nmul = va - vb*sqrt(vc) - d = va**2 - vc*vb**2 - n1 = n/d - if denom(n1) is not S.One: - n = -(-n/d) - else: - n = n1 - n, d = fraction(n*nmul) + if not keep: + return expr + return _umul(n, 1/d) - nexpr = collect_sqrt(expand_mul(n))/d - if changed or nexpr != expr: - expr = nexpr - return expr + coeff, expr = expr.as_coeff_Add() + expr = expr.normal() + old = fraction(expr) + n, d = fraction(handle(expr)) + if old != (n, d): + if not d.is_Atom: + was = (n, d) + n = signsimp(n, evaluate=False) + d = signsimp(d, evaluate=False) + u = Factors(_umul(n, 1/d)) + u = _umul(*[k**v for k, v in u.factors.items()]) + n, d = fraction(u) + if old == (n, d): + n, d = was + n = expand_mul(n) + if d.is_Number or d.is_Add: + n2, d2 = fraction(gcd_terms(_umul(n, 1/d))) + if d2.is_Number or (d2.count_ops() <= d.count_ops()): + n, d = [signsimp(i) for i in (n2, d2)] + if n.is_Mul and n.args[0].is_Number: + n = Mul(*n.args) - a, b, c, D, E, F, G = list(map(Wild, 'abcDEFG')) - # do this at the start in case no other change is made since - # it is done if a change is made - coeff, expr = expr.as_content_primitive() + return coeff + _umul(n, 1/d) - newe = handle(expr) - if newe != expr: - co, expr = newe.as_content_primitive() - coeff *= co - else: - nexpr, hit = collect_sqrt(expand_mul(expr), evaluate=False) - nexpr = Add._from_args(nexpr) - if hit and expr.count_ops() >= nexpr.count_ops(): - expr = Add(*Add.make_args(nexpr)) - return _keep_coeff(coeff, expr) def posify(eq): """Return eq (with generic symbols made positive) and a restore @@ -1453,6 +2073,7 @@ eq = eq.subs(reps) return eq, dict([(r, s) for s, r in reps.items()]) + def _polarify(eq, lift, pause=False): from sympy import polar_lift, Integral if eq.is_polar: @@ -1480,7 +2101,9 @@ limits.append((var,) + rest) return Integral(*((func,) + tuple(limits))) else: - return eq.func(*[_polarify(arg, lift, pause=pause) for arg in eq.args]) + return eq.func(*[_polarify(arg, lift, pause=pause) + if isinstance(arg, Expr) else arg for arg in eq.args]) + def polarify(eq, subs=True, lift=False): """ @@ -1526,7 +2149,8 @@ return eq reps = dict([(s, Dummy(s.name, polar=True)) for s in eq.atoms(Symbol)]) eq = eq.subs(reps) - return eq, dict([(r,s) for s, r in reps.items()]) + return eq, dict([(r, s) for s, r in reps.items()]) + def _unpolarify(eq, exponents_only, pause=False): from sympy import polar_lift, exp, principal_branch, pi @@ -1544,7 +2168,7 @@ eq.is_Relational and ( eq.rel_op in ('==', '!=') and 0 in eq.args or eq.rel_op not in ('==', '!=')) - ): + ): return eq.func(*[_unpolarify(x, exponents_only) for x in eq.args]) if eq.func is polar_lift: return _unpolarify(eq.args[0], exponents_only) @@ -1561,6 +2185,7 @@ return eq.func(*[_unpolarify(x, exponents_only, True) for x in eq.args]) + def unpolarify(eq, subs={}, exponents_only=False): """ If p denotes the projection from the Riemann surface of the logarithm to @@ -1598,6 +2223,7 @@ # So is polar_lift(0) -> 0. return res.subs({exp_polar(0): 1, polar_lift(0): 0}) + def _denest_pow(eq): """ Denest powers. @@ -1625,7 +2251,8 @@ b.is_positive): return eq - # denest eq which is either pos**e or Pow**e or Mul**e or Mul(b1**e1, b2**e2) + # denest eq which is either pos**e or Pow**e or Mul**e or + # Mul(b1**e1, b2**e2) # handle polar numbers specially polars, nonpolars = [], [] @@ -1638,7 +2265,7 @@ return Pow(polars[0][0], polars[0][1]*e)*powdenest(Mul(*nonpolars)**e) elif polars: return Mul(*[powdenest(bb**(ee*e)) for (bb, ee) in polars]) \ - *powdenest(Mul(*nonpolars)**e) + *powdenest(Mul(*nonpolars)**e) # see if there is a positive, non-Mul base at the very bottom exponents = [] @@ -1653,7 +2280,7 @@ else: if kernel.is_Integer: # use log to see if there is a power here - logkernel = log(kernel) + logkernel = expand_log(log(kernel)) if logkernel.is_Mul: c, logk = logkernel.args e *= c @@ -1674,6 +2301,7 @@ # fractions, terms_gcd(x+x*y/2) -> x*(y + 2)/2 and we don't want the 1/2; # gcd won't pull out numerators from a fraction: gcd(3*x, 9*x/2) -> x but # we want 3*x. Neither work with noncommutatives. + def nc_gcd(aa, bb): a, b = [i.as_coeff_Mul() for i in [aa, bb]] c = gcd(a[0], b[0]).as_numer_denom()[0] @@ -1697,7 +2325,7 @@ return eq # the log(b) was a Mul so join any adds with logcombine - add= [] + add = [] other = [] for a in glogb.args: if a.is_Add: @@ -1706,6 +2334,7 @@ other.append(a) return Pow(exp(logcombine(Mul(*add))), e*Mul(*other)) + def powdenest(eq, force=False, polar=False): r""" Collect exponents on powers as assumptions allow. @@ -1808,9 +2437,12 @@ return unpolarify(powdenest(unpolarify(eq, exponents_only=True)), rep) new = powsimp(sympify(eq)) - return new.xreplace(Transform(_denest_pow, filter=lambda m: m.is_Pow or m.func is exp)) + return new.xreplace(Transform( + _denest_pow, filter=lambda m: m.is_Pow or m.func is exp)) _y = Dummy('y') + + def powsimp(expr, deep=False, combine='all', force=False, measure=count_ops): """ reduces expression by combining powers with similar bases and exponents. @@ -1904,7 +2536,8 @@ expr = sympify(expr) - if not isinstance(expr, Basic) or expr.is_Atom or expr in (exp_polar(0), exp_polar(1)): + if not isinstance(expr, Basic) or expr.is_Atom or expr in ( + exp_polar(0), exp_polar(1)): return expr if deep or expr.is_Add or expr.is_Mul and _y not in expr.args: @@ -1917,14 +2550,19 @@ return expr # handle the Mul - if combine in ('exp', 'all'): # Collect base/exp data, while maintaining order in the # non-commutative parts of the product c_powers = defaultdict(list) nc_part = [] newexpr = [] + coeff = S.One for term in expr.args: + if term.is_Rational: + coeff *= term + continue + if term.is_Pow: + term = _denest_pow(term) if term.is_commutative: b, e = term.as_base_exp() if deep: @@ -1937,18 +2575,37 @@ b1, e1 = nc_part[-1].as_base_exp() b2, e2 = term.as_base_exp() if (b1 == b2 and - e1.is_commutative and e2.is_commutative): + e1.is_commutative and e2.is_commutative): nc_part[-1] = Pow(b1, Add(e1, e2)) continue nc_part.append(term) # add up exponents of common bases - for b, e in c_powers.items(): + for b, e in ordered(iter(c_powers.items())): + # allow 2**x/4 -> 2**(x - 2); don't do this when b and e are + # Numbers since autoevaluation will undo it, e.g. + # 2**(1/3)/4 -> 2**(1/3 - 2) -> 2**(1/3)/4 + assert 2**(S(1)/3 - 2) == 2**(S(1)/3)/4 + if (b and b.is_Number and not all(ei.is_Number for ei in e) and \ + coeff is not S.One and + b not in (S.One, S.NegativeOne)): + m = multiplicity(abs(b), abs(coeff)) + if m: + e.append(m) + coeff /= b**m c_powers[b] = Add(*e) + if coeff is not S.One: + if coeff in c_powers: + c_powers[coeff] += S.One + else: + c_powers[coeff] = S.One + + # convert to plain dictionary + c_powers = dict(c_powers) # check for base and inverted base pairs be = list(c_powers.items()) - skip = set() # skip if we already saw them + skip = set() # skip if we already saw them for b, e in be: if b in skip: continue @@ -1964,13 +2621,27 @@ e = c_powers.pop(binv) c_powers[b] -= e + # check for base and negated base pairs + be = list(c_powers.items()) + _n = S.NegativeOne + for i, (b, e) in enumerate(be): + if ((-b).is_Symbol or b.is_Add) and -b in c_powers: + if (b.is_positive in (0, 1) or e.is_integer): + c_powers[-b] += c_powers.pop(b) + if _n in c_powers: + c_powers[_n] += e + else: + c_powers[_n] = e + # filter c_powers and convert to a list c_powers = [(b, e) for b, e in c_powers.items() if e] # ============================================================== # check for Mul bases of Rational powers that can be combined with - # separated bases, e.g. x*sqrt(x*y)*sqrt(x*sqrt(x*y)) -> (x*sqrt(x*y))**(3/2) + # separated bases, e.g. x*sqrt(x*y)*sqrt(x*sqrt(x*y)) -> + # (x*sqrt(x*y))**(3/2) # ---------------- helper functions + def ratq(x): '''Return Rational part of x's exponent as it appears in the bkey. ''' @@ -1986,7 +2657,7 @@ exp(x/2) -> (exp(a), 2), 1 ''' - if e is not None: # coming from c_powers or from below + if e is not None: # coming from c_powers or from below if e.is_Integer: return (b, S.One), e elif e.is_Rational: @@ -2029,24 +2700,24 @@ common_b[b] = e if b[1] != 1 and b[0].is_Mul: bases.append(b) - bases.sort(key=default_sort_key) # this makes tie-breaking canonical - bases.sort(key=measure, reverse= True) # handle longest first + bases.sort(key=default_sort_key) # this makes tie-breaking canonical + bases.sort(key=measure, reverse=True) # handle longest first for base in bases: - if base not in common_b: # it may have been removed already + if base not in common_b: # it may have been removed already continue b, exponent = base - last = False # True when no factor of base is a radical - qlcm = 1 # the lcm of the radical denominators + last = False # True when no factor of base is a radical + qlcm = 1 # the lcm of the radical denominators while True: bstart = b qstart = qlcm - bb = [] # list of factors - ee = [] # (factor's exponent, current value of that exponent in common_b) + bb = [] # list of factors + ee = [] # (factor's expo. and it's current value in common_b) for bi in Mul.make_args(b): bib, bie = bkey(bi) if bib not in common_b or common_b[bib] < bie: - ee = bb = [] # failed + ee = bb = [] # failed break ee.append([bie, common_b[bib]]) bb.append(bib) @@ -2070,22 +2741,23 @@ # e.g. x**2*y*sqrt(x*sqrt(y)) the count of x*sqrt(y) # will increase by 4 to give bkey (x*sqrt(y), 2, 5) common_b[base] += min1*qstart*exponent - if (last # no more radicals in base - or len(common_b) == 1 # nothing left to join with - or all(k[1] == 1 for k in common_b) # no radicals left in common_b - ): + if (last # no more radicals in base + or len(common_b) == 1 # nothing left to join with + or all(k[1] == 1 for k in common_b) # no rad's in common_b + ): break # see what we can exponentiate base by to remove any radicals # so we know what to search for - # e.g. if base were x**(1/2)*y**(1/3) then we should exponentiate - # by 6 and look for powers of x and y in the ratio of 2 to 3 + # e.g. if base were x**(1/2)*y**(1/3) then we should + # exponentiate by 6 and look for powers of x and y in the ratio + # of 2 to 3 qlcm = lcm([ratq(bi) for bi in Mul.make_args(bstart)]) if qlcm == 1: - break # we are done + break # we are done b = bstart**qlcm qlcm *= qstart if all(ratq(bi) == 1 for bi in Mul.make_args(b)): - last = True # we are going to be done after this next pass + last = True # we are going to be done after this next pass # this base no longer can find anything to join with and # since it was longer than any other we are done with it b, q = base @@ -2097,7 +2769,7 @@ # identified as needing processing, so remove those, too for (b, q), e in list(common_b.items()): if (b.is_Pow or b.func is exp) and \ - q is not S.One and not b.exp.is_Rational: + q is not S.One and not b.exp.is_Rational: b, be = b.as_base_exp() b = b**(be/q) else: @@ -2105,15 +2777,16 @@ c_powers.append((b, e)) check = len(c_powers) c_powers = dict(c_powers) - assert len(c_powers) == check # there should have been no duplicates + assert len(c_powers) == check # there should have been no duplicates # ============================================================== # rebuild the expression - newexpr = Mul(*(newexpr + [Pow(b, e) for b, e in c_powers.items()])) + newexpr = Mul( + *(newexpr + [Pow(b, e) for b, e in c_powers.items()])) if combine == 'exp': return Mul(newexpr, Mul(*nc_part)) else: - return recurse(Mul(*nc_part), combine='base')*\ + return recurse(Mul(*nc_part), combine='base') * \ recurse(newexpr, combine='base') elif combine == 'base': @@ -2147,10 +2820,8 @@ if exp_c is not S.One and exp_t is not S.One: c_powers[i] = [Pow(b, exp_c), exp_t] - # Combine bases whenever they have the same exponent and # assumptions allow - # first gather the potential bases under the common exponent c_exp = defaultdict(list) for b, e in c_powers: @@ -2165,22 +2836,24 @@ bases = c_exp[e] # calculate the new base for e + if len(bases) == 1: new_base = bases[0] elif e.is_integer or force: new_base = Mul(*bases) else: # see which ones can be joined - unk=[] - nonneg=[] - neg=[] + unk = [] + nonneg = [] + neg = [] for bi in bases: if bi.is_negative: neg.append(bi) elif bi.is_nonnegative: nonneg.append(bi) elif bi.is_polar: - nonneg.append(bi) # polar can be treated like non-negative + nonneg.append( + bi) # polar can be treated like non-negative else: unk.append(bi) if len(unk) == 1 and not neg or len(neg) == 1 and not unk: @@ -2188,18 +2861,31 @@ nonneg.extend(unk + neg) unk = neg = [] elif neg: - # their negative signs cancel in pairs - neg = [-w for w in neg] - if len(neg) % 2: - unk.append(S.NegativeOne) + # their negative signs cancel in groups of 2*q if we know + # that e = p/q else we have to treat them as unknown + israt = False + if e.is_Rational: + israt = True + else: + p, d = e.as_numer_denom() + if p.is_integer and d.is_integer: + israt = True + if israt: + neg = [-w for w in neg] + unk.extend([S.NegativeOne]*len(neg)) + else: + unk.extend(neg) + neg = [] + del israt # these shouldn't be joined for b in unk: c_powers[b].append(e) # here is a new joined base new_base = Mul(*(nonneg + neg)) - # if there are positive parts they will just get separated again - # unless some change is made + # if there are positive parts they will just get separated + # again unless some change is made + def _terms(e): # return the number of terms of this expression # when multiplied out -- assuming no joining of terms @@ -2223,6 +2909,7 @@ else: raise ValueError("combine must be one of ('all', 'exp', 'base').") + def hypersimp(f, k): """Given combinatorial term f(k) simplify its consecutive term ratio i.e. f(k+1)/f(k). The input term can be composed of functions and @@ -2252,7 +2939,7 @@ """ f = sympify(f) - g = f.subs(k, k+1) / f + g = f.subs(k, k + 1) / f g = g.rewrite(gamma) g = expand_func(g) @@ -2263,6 +2950,7 @@ else: return None + def hypersimilar(f, g, k): """Returns True if 'f' and 'g' are hyper-similar. @@ -2281,6 +2969,8 @@ return h.is_rational_function(k) from sympy.utilities.timeutils import timethis + + @timethis('combsimp') def combsimp(expr): r""" @@ -2383,6 +3073,7 @@ lambda n, k: rf((n - k + 1).expand(), k.expand())/rf(1, k.expand())) expr = expr.replace(factorial, lambda n: rf(1, n.expand())) + expr = expr.rewrite(gamma) expr = expr.replace(gamma, lambda n: rf(1, (n - 1).expand())) @@ -2418,51 +3109,120 @@ expr = expr.replace(binomial, rule) - def rule_gamma(expr): + def rule_gamma(expr, level=0): """ Simplify products of gamma functions further. """ - from itertools import count - from sympy.core.compatibility import permutations if expr.is_Atom: return expr - expr = expr.func(*[rule_gamma(x) for x in expr.args]) + def gamma_rat(x): + # helper to simplify ratios of gammas + was = x.count(gamma) + xx = x.replace(gamma, lambda n: rf(1, (n - 1).expand() + ).replace(rf, lambda a, b: gamma(a + b)/gamma(a))) + if xx.count(gamma) < was: + x = xx + return x + + def gamma_factor(x): + # return True if there is a gamma factor in shallow args + if x.func is gamma: + return True + if x.is_Add or x.is_Mul: + return any(gamma_factor(xi) for xi in x.args) + if x.is_Pow and (x.exp.is_integer or x.base.is_positive): + return gamma_factor(x.base) + return False + + # recursion step + if level == 0: + expr = expr.func(*[rule_gamma(x, level + 1) for x in expr.args]) + level += 1 + if not expr.is_Mul: return expr + # non-commutative step + if level == 1: + args, nc = expr.args_cnc() + if not args: + return expr + if nc: + return rule_gamma(Mul._from_args(args), level + 1)*Mul._from_args(nc) + level += 1 + + # pure gamma handling, not factor absorbtion + if level == 2: + sifted = sift(expr.args, gamma_factor) + gamma_ind = Mul(*sifted.pop(False, [])) + d = Mul(*sifted.pop(True, [])) + assert not sifted + + nd, dd = d.as_numer_denom() + for ipass in range(2): + args = list(ordered(Mul.make_args(nd))) + for i, ni in enumerate(args): + if ni.is_Add: + ni, dd = Add(*[ + rule_gamma(gamma_rat(a/dd), level + 1) for a in ni.args] + ).as_numer_denom() + args[i] = ni + if not dd.has(gamma): + break + nd = Mul(*args) + if ipass == 0 and not gamma_factor(nd): + break + nd, dd = dd, nd # now process in reversed order + expr = gamma_ind*nd/dd + if not (expr.is_Mul and (gamma_factor(dd) or gamma_factor(nd))): + return expr + level += 1 + + # iteration until constant + if level == 3: + while True: + was = expr + expr = rule_gamma(expr, 4) + if expr == was: + return expr + numer_gammas = [] denom_gammas = [] + numer_others = [] denom_others = [] - newargs, numer_others = expr.args_cnc() - - # order newargs canonically - cexpr = expr.func(*newargs) - newargs = list(cexpr._sorted_args) if not cexpr.is_Atom else [cexpr] - del cexpr - - while newargs: - arg = newargs.pop() - b, e = arg.as_base_exp() + def explicate(p): + if p is S.One: + return None, [] + b, e = p.as_base_exp() if e.is_Integer: - n = abs(e) - if isinstance(b, gamma): - barg = b.args[0] - if e > 0: - numer_gammas.extend([barg]*n) - elif e < 0: - denom_gammas.extend([barg]*n) + if b.func is gamma: + return True, [b.args[0]]*e else: - if e > 0: - numer_others.extend([b]*n) - elif e < 0: - denom_others.extend([b]*n) + return False, [b]*e else: - numer_others.append(arg) + return False, [p] + + newargs = list(ordered(expr.args)) + while newargs: + n, d = newargs.pop().as_numer_denom() + isg, l = explicate(n) + if isg: + numer_gammas.extend(l) + elif isg is False: + numer_others.extend(l) + isg, l = explicate(d) + if isg: + denom_gammas.extend(l) + elif isg is False: + denom_others.extend(l) + + # =========== level 2 work: pure gamma manipulation ========= # Try to reduce the number of gamma factors by applying the # reflection formula gamma(x)*gamma(1-x) = pi/sin(pi*x) - for gammas, numer, denom in [(numer_gammas, numer_others, denom_others), - (denom_gammas, denom_others, numer_others)]: + for gammas, numer, denom in [( + numer_gammas, numer_others, denom_others), + (denom_gammas, denom_others, numer_others)]: new = [] while gammas: g1 = gammas.pop() @@ -2473,7 +3233,6 @@ n = g1 + g2 - 1 if not n.is_Integer: continue - append = False numer.append(S.Pi) denom.append(C.sin(S.Pi*g1)) gammas.pop(i) @@ -2489,14 +3248,60 @@ # /!\ updating IN PLACE gammas[:] = new - # Try to reduce the number of gamma factors by applying the - # multiplication theorem. + # Try to reduce the number of gammas by using the duplication + # theorem to cancel an upper and lower: gamma(2*s)/gamma(s) = + # 2**(2*s + 1)/(4*sqrt(pi))*gamma(s + 1/2). Although this could + # be done with higher argument ratios like gamma(3*x)/gamma(x), + # this would not reduce the number of gammas as in this case. + for ng, dg, no, do in [(numer_gammas, denom_gammas, numer_others, + denom_others), + (denom_gammas, numer_gammas, denom_others, + numer_others)]: + + while True: + for x in ng: + for y in dg: + n = x - 2*y + if n.is_Integer: + break + else: + continue + break + else: + break + ng.remove(x) + dg.remove(y) + if n > 0: + for k in range(n): + no.append(2*y + k) + elif n < 0: + for k in range(-n): + do.append(2*y - 1 - k) + ng.append(y + S(1)/2) + no.append(2**(2*y - 1)) + do.append(sqrt(S.Pi)) + # Try to reduce the number of gamma factors by applying the + # multiplication theorem (used when n gammas with args differing + # by 1/n mod 1 are encountered). + # + # run of 2 with args differing by 1/2 + # + # >>> combsimp(gamma(x)*gamma(x+S.Half)) + # 2*sqrt(2)*2**(-2*x - 1/2)*sqrt(pi)*gamma(2*x) + # + # run of 3 args differing by 1/3 (mod 1) + # + # >>> combsimp(gamma(x)*gamma(x+S(1)/3)*gamma(x+S(2)/3)) + # 6*3**(-3*x - 1/2)*pi*gamma(3*x) + # >>> combsimp(gamma(x)*gamma(x+S(1)/3)*gamma(x+S(5)/3)) + # 2*3**(-3*x - 1/2)*pi*(3*x + 2)*gamma(3*x) + # def _run(coeffs): # find runs in coeffs such that the difference in terms (mod 1) # of t1, t2, ..., tn is 1/n from sympy.utilities.iterables import uniq - u = uniq(coeffs) + u = list(uniq(coeffs)) for i in range(len(u)): dj = ([((u[j] - u[i]) % 1, j) for j in range(i + 1, len(u))]) for one, j in dj: @@ -2553,7 +3358,7 @@ for k in range(int(u - ui)): numer.append(con - k) - con = n*(resid + ui) # for (2) and (3) + con = n*(resid + ui) # for (2) and (3) # (2) numer.append((2*S.Pi)**(S(n - 1)/2)* @@ -2575,129 +3380,94 @@ (denom_gammas, denom_others, numer_others)]: _mult_thm(l, numer, denom) - # Try to reduce the number of gammas by using the duplication - # theorem to cancel an upper and lower. - # e.g. gamma(2*s)/gamma(s) = gamma(s)*gamma(s+1/2)*C/gamma(s) - # (in principle this can also be done with with factors other than two, - # but two is special in that we need only matching numer and denom, not - # several in numer). - for ng, dg, no, do in [(numer_gammas, denom_gammas, numer_others, - denom_others), - (denom_gammas, numer_gammas, denom_others, - numer_others)]: + # =========== level >= 2 work: factor absorbtion ========= - while True: - for x in ng: - for y in dg: - n = x - 2*y - if n.is_Integer: - break - else: + if level >= 2: + # Try to absorb factors into the gammas: x*gamma(x) -> gamma(x + 1) + # and gamma(x)/(x - 1) -> gamma(x - 1) + # This code (in particular repeated calls to find_fuzzy) can be very + # slow. + def find_fuzzy(l, x): + if not l: + return + S1, T1 = compute_ST(x) + for y in l: + S2, T2 = inv[y] + if T1 != T2 or (not S1.intersection(S2) and + (S1 != set() or S2 != set())): continue - break - else: - break - ng.remove(x) - dg.remove(y) - if n > 0: - for k in range(n): - no.append(2*y + k) - elif n < 0: - for k in range(-n): - do.append(2*y - 1 - k) - ng.append(y + S(1)/2) - no.append(2**(2*y - 1)) - do.append(sqrt(S.Pi)) - - # Try to absorb factors into the gammas. - # This code (in particular repeated calls to find_fuzzy) can be very - # slow. - def find_fuzzy(l, x): - S1, T1 = compute_ST(x) - for y in l: - S2, T2 = inv[y] - if T1 != T2 or (not S1.intersection(S2) and \ - (S1 != set() or S2 != set())): - continue - # XXX we want some simplification (e.g. cancel or - # simplify) but no matter what it's slow. - a = len(cancel(x/y).free_symbols) - b = len(x.free_symbols) - c = len(y.free_symbols) - # TODO is there a better heuristic? - if a == 0 and (b > 0 or c > 0): - return y - - # We thus try to avoid expensive calls by building the following - # "invariants": For every factor or gamma function argument - # - the set of free symbols S - # - the set of functional components T - # We will only try to absorb if T1==T2 and (S1 intersect S2 != emptyset - # or S1 == S2 == emptyset) - inv = {} - def compute_ST(expr): - from sympy import Function, Pow - if expr in inv: - return inv[expr] - return (expr.free_symbols, expr.atoms(Function).union( - set(e.exp for e in expr.atoms(Pow)))) - def update_ST(expr): - inv[expr] = compute_ST(expr) - for expr in numer_gammas + denom_gammas + numer_others + denom_others: - update_ST(expr) + # XXX we want some simplification (e.g. cancel or + # simplify) but no matter what it's slow. + a = len(cancel(x/y).free_symbols) + b = len(x.free_symbols) + c = len(y.free_symbols) + # TODO is there a better heuristic? + if a == 0 and (b > 0 or c > 0): + return y + + # We thus try to avoid expensive calls by building the following + # "invariants": For every factor or gamma function argument + # - the set of free symbols S + # - the set of functional components T + # We will only try to absorb if T1==T2 and (S1 intersect S2 != emptyset + # or S1 == S2 == emptyset) + inv = {} + + def compute_ST(expr): + from sympy import Function, Pow + if expr in inv: + return inv[expr] + return (expr.free_symbols, expr.atoms(Function).union( + set(e.exp for e in expr.atoms(Pow)))) + + def update_ST(expr): + inv[expr] = compute_ST(expr) + for expr in numer_gammas + denom_gammas + numer_others + denom_others: + update_ST(expr) + + for gammas, numer, denom in [( + numer_gammas, numer_others, denom_others), + (denom_gammas, denom_others, numer_others)]: + new = [] + while gammas: + g = gammas.pop() + cont = True + while cont: + cont = False + y = find_fuzzy(numer, g) + if y is not None: + numer.remove(y) + if y != g: + numer.append(y/g) + update_ST(y/g) + g += 1 + cont = True + y = find_fuzzy(denom, g - 1) + if y is not None: + denom.remove(y) + if y != g - 1: + numer.append((g - 1)/y) + update_ST((g - 1)/y) + g -= 1 + cont = True + new.append(g) + # /!\ updating IN PLACE + gammas[:] = new - for gammas, numer, denom in [(numer_gammas, numer_others, denom_others), - (denom_gammas, denom_others, numer_others)]: - new = [] - while gammas: - g = gammas.pop() - cont = True - while cont: - cont = False - y = find_fuzzy(numer, g) - if y is not None: - numer.remove(y) - if y != g: - numer.append(y/g) - update_ST(y/g) - g += 1 - cont = True - y = find_fuzzy(numer, 1/(g - 1)) - if y is not None: - numer.remove(y) - if y != 1/(g - 1): - numer.append((g - 1)*y) - update_ST((g - 1)*y) - g -= 1 - cont = True - y = find_fuzzy(denom, 1/g) - if y is not None: - denom.remove(y) - if y != 1/g: - denom.append(y*g) - update_ST(y*g) - g += 1 - cont = True - y = find_fuzzy(denom, g - 1) - if y is not None: - denom.remove(y) - if y != g - 1: - numer.append((g - 1)/y) - update_ST((g - 1)/y) - g -= 1 - cont = True - new.append(g) - # /!\ updating IN PLACE - gammas[:] = new + # =========== rebuild expr ================================== return C.Mul(*[gamma(g) for g in numer_gammas]) \ - / C.Mul(*[gamma(g) for g in denom_gammas]) \ - * C.Mul(*numer_others) / C.Mul(*denom_others) + / C.Mul(*[gamma(g) for g in denom_gammas]) \ + * C.Mul(*numer_others) / C.Mul(*denom_others) # (for some reason we cannot use Basic.replace in this case) - expr = rule_gamma(expr) + was = factor(expr) + expr = rule_gamma(was) + if expr != was: + expr = factor(expr) + + return expr - return factor(expr) def signsimp(expr, evaluate=True): """Make all Add sub-expressions canonical wrt sign. @@ -2750,7 +3520,8 @@ e = e.xreplace(dict([(m, -(-m)) for m in e.atoms(Mul) if -(-m) != m])) return e -def simplify(expr, ratio=1.7, measure=count_ops): + +def simplify(expr, ratio=1.7, measure=count_ops, fu=False): """ Simplifies the given expression. @@ -2779,11 +3550,9 @@ simplification functions: >>> from sympy import trigsimp, cancel - >>> b = trigsimp(a) - >>> b + >>> trigsimp(a) (x**2 + x)/x - >>> c = cancel(b) - >>> c + >>> cancel(_) x + 1 In some cases, applying :func:`simplify` may actually result in some more @@ -2826,7 +3595,8 @@ that some choices, such as ``lambda expr: len(str(expr))`` may appear to be good metrics, but have other problems (in this case, the measure function may slow down simplify too much for very large expressions). If you don't - know what a good metric would be, the default, ``count_ops``, is a good one. + know what a good metric would be, the default, ``count_ops``, is a good + one. For example: @@ -2835,22 +3605,22 @@ >>> g = log(a) + log(b) + log(a)*log(1/b) >>> h = simplify(g) >>> h - log(a*b**(log(1/a) + 1)) + log(a*b**(-log(a) + 1)) >>> count_ops(g) 8 >>> count_ops(h) - 6 + 5 So you can see that ``h`` is simpler than ``g`` using the count_ops metric. However, we may not like how ``simplify`` (in this case, using - ``logcombine``) has created the ``b**(log(1/a) + 1)`` term. A simple way to - reduce this would be to give more weight to powers as operations in + ``logcombine``) has created the ``b**(log(1/a) + 1)`` term. A simple way + to reduce this would be to give more weight to powers as operations in ``count_ops``. We can do this by using the ``visual=True`` option: >>> print(count_ops(g, visual=True)) 2*ADD + DIV + 4*LOG + MUL >>> print(count_ops(h, visual=True)) - ADD + DIV + 2*LOG + MUL + POW + 2*LOG + MUL + POW + SUB >>> from sympy import Symbol, S >>> def my_measure(expr): @@ -2863,7 +3633,7 @@ >>> my_measure(g) 8 >>> my_measure(h) - 15 + 14 >>> 15./8 > 1.7 # 1.7 is the default ratio True >>> simplify(g, measure=my_measure) @@ -2877,20 +3647,20 @@ from sympy.simplify.hyperexpand import hyperexpand from sympy.functions.special.bessel import BesselBase - original_expr = expr = sympify(expr) + original_expr = expr = signsimp(expr) - expr = signsimp(expr) + try: + return expr._eval_simplify(ratio=ratio, measure=measure) + except AttributeError: + pass - if not isinstance(expr, Basic): # XXX: temporary hack - return expr + from sympy.simplify.hyperexpand import hyperexpand + from sympy.functions.special.bessel import BesselBase + from sympy import Sum, Product - if isinstance(expr, Atom): + if not isinstance(expr, Basic) or isinstance(expr, Atom): # XXX: temporary hack return expr - if isinstance(expr, C.Relational): - return expr.__class__(simplify(expr.lhs, ratio=ratio), - simplify(expr.rhs, ratio=ratio)) - # TODO: Apply different strategies, considering expression pattern: # is it a purely rational function? Is there any trigonometric function?... # See also https://github.com/sympy/sympy/pull/185. @@ -2902,41 +3672,31 @@ return choices[0] return min(choices, key=measure) - if expr.is_commutative is False: - expr1 = factor_terms(together(powsimp(expr))) - if ratio is S.Infinity: - return expr1 - return shorter(expr1, expr) - - expr0 = powsimp(expr) - expr1 = cancel(expr0) - expr2 = together(expr1.expand(), deep=True) - - # sometimes factors in the denominators need to be allowed to join - # factors in numerators (see issue 3270) - n, d = expr.as_numer_denom() - if (n, d) != fraction(expr): - expr0b = powsimp(n)/powsimp(d) - if expr0b != expr0: - expr1b = cancel(expr0b) - expr2b = together(expr1b.expand(), deep=True) - if shorter(expr2b, expr) == expr2b: - expr1, expr2 = expr1b, expr2b + expr = bottom_up(expr, lambda w: w.normal()) + expr = Mul(*powsimp(expr).as_content_primitive()) + _e = cancel(expr) + expr1 = shorter(_e, _mexpand(_e).cancel()) # issue 3730 + expr2 = shorter(together(expr, deep=True), together(expr1, deep=True)) if ratio is S.Infinity: expr = expr2 else: expr = shorter(expr2, expr1, expr) - if not isinstance(expr, Basic): # XXX: temporary hack + if not isinstance(expr, Basic): # XXX: temporary hack return expr + expr = factor_terms(expr, sign=False) + # hyperexpand automatically only works on hypergeometric terms expr = hyperexpand(expr) + expr = piecewise_fold(expr) + if expr.has(BesselBase): expr = besselsimp(expr) - if expr.has(C.TrigonometricFunction) or expr.has(C.HyperbolicFunction): + if expr.has(C.TrigonometricFunction) and not fu or expr.has( + C.HyperbolicFunction): expr = trigsimp(expr, deep=True) if expr.has(C.log): @@ -2945,20 +3705,29 @@ if expr.has(C.CombinatorialFunction, gamma): expr = combsimp(expr) - expr = powsimp(expr, combine='exp', deep=True) - short = shorter(expr, powsimp(factor_terms(expr))) - if short != expr: - # get rid of hollow 2-arg Mul factorization - from sympy.core.rules import Transform - hollow_mul = Transform( - lambda x: Mul(*x.args), - lambda x: - x.is_Mul and - len(x.args) == 2 and - x.args[0].is_Number and - x.args[1].is_Add and - x.is_commutative) - expr = shorter(short.xreplace(hollow_mul), expr) + if expr.has(Sum): + expr = sum_simplify(expr) + + if expr.has(Product): + expr = product_simplify(expr) + + short = shorter(powsimp(expr, combine='exp', deep=True), powsimp(expr), expr) + short = shorter(short, factor_terms(short), expand_power_exp(expand_mul(short))) + if short.has(C.TrigonometricFunction, C.HyperbolicFunction, C.ExpBase): + short = exptrigsimp(short, simplify=False) + + # get rid of hollow 2-arg Mul factorization + from sympy.core.rules import Transform + hollow_mul = Transform( + lambda x: Mul(*x.args), + lambda x: + x.is_Mul and + len(x.args) == 2 and + x.args[0].is_Number and + x.args[1].is_Add and + x.is_commutative) + expr = short.xreplace(hollow_mul) + numer, denom = expr.as_numer_denom() if denom.is_Add: n, d = fraction(radsimp(1/denom, symbolic=False, max_terms=1)) @@ -2966,19 +3735,17 @@ expr = (numer*n).expand()/d if expr.could_extract_minus_sign(): - n, d = expr.as_numer_denom() + n, d = fraction(expr) if d != 0: - expr = -n/(-d) + expr = signsimp(-n/(-d)) if measure(expr) > ratio*measure(original_expr): - return original_expr - - if original_expr.is_Matrix: - expr = matrixify(expr) + expr = original_expr return expr -def _real_to_rational(expr): + +def _real_to_rational(expr, tolerance=None): """ Replace all reals in expr with rationals. @@ -2991,21 +3758,34 @@ """ p = expr reps = {} - for r in p.atoms(C.Float): - newr = nsimplify(r, rational=False) - if not newr.is_Rational or \ - r.is_finite and not newr.is_finite: - newr = r - if newr < 0: - s = -1 - newr *= s - else: - s = 1 - d = Pow(10, int((mpmath.log(newr)/mpmath.log(10)))) - newr = s*Rational(str(newr/d))*d - reps[r] = newr + reduce_num = None + if tolerance is not None and tolerance < 1: + reduce_num = ceiling(1/tolerance) + for float in p.atoms(C.Float): + key = float + if reduce_num is not None: + r = Rational(float).limit_denominator(reduce_num) + elif (tolerance is not None and tolerance >= 1 and + float.is_Integer is False): + r = Rational(tolerance*round(float/tolerance) + ).limit_denominator(int(tolerance)) + else: + r = nsimplify(float, rational=False) + # e.g. log(3).n() -> log(3) instead of a Rational + if not r.is_Rational: + if float < 0: + float = -float + d = Pow(10, int((mpmath.log(float)/mpmath.log(10)))) + r = -Rational(str(float/d))*d + elif float > 0: + d = Pow(10, int((mpmath.log(float)/mpmath.log(10)))) + r = Rational(str(float/d))*d + else: + r = Integer(0) + reps[key] = r return p.subs(reps, simultaneous=True) + def nsimplify(expr, constants=[], tolerance=None, full=False, rational=None): """ Find a simple representation for a number or, if there are free symbols or @@ -3031,15 +3811,15 @@ Examples ======== - >>> from sympy import nsimplify, sqrt, GoldenRatio, exp, I, exp, pi - >>> nsimplify(4/(1+sqrt(5)), [GoldenRatio]) - -2 + 2*GoldenRatio - >>> nsimplify((1/(exp(3*pi*I/5)+1))) - 1/2 - I*sqrt(sqrt(5)/10 + 1/4) - >>> nsimplify(I**I, [pi]) - exp(-pi/2) - >>> nsimplify(pi, tolerance=0.01) - 22/7 + >>> from sympy import nsimplify, sqrt, GoldenRatio, exp, I, exp, pi + >>> nsimplify(4/(1+sqrt(5)), [GoldenRatio]) + -2 + 2*GoldenRatio + >>> nsimplify((1/(exp(3*pi*I/5)+1))) + 1/2 - I*sqrt(sqrt(5)/10 + 1/4) + >>> nsimplify(I**I, [pi]) + exp(-pi/2) + >>> nsimplify(pi, tolerance=0.01) + 22/7 See Also ======== @@ -3048,14 +3828,15 @@ """ expr = sympify(expr) if rational or expr.free_symbols: - return _real_to_rational(expr) + return _real_to_rational(expr, tolerance) - # sympy's default tolarance for Rationals is 15; other numbers may have - # lower tolerances set, so use them to pick the largest tolerance if none + # SymPy's default tolerance for Rationals is 15; other numbers may have + # lower tolerances set, so use them to pick the largest tolerance if None # was given - tolerance = tolerance or 10**-min([15] + - [mpmath.libmp.libmpf.prec_to_dps(n._prec) - for n in expr.atoms(Float)]) + if tolerance is None: + tolerance = 10**-min([15] + + [mpmath.libmp.libmpf.prec_to_dps(n._prec) + for n in expr.atoms(Float)]) prec = 30 bprec = int(prec*3.33) @@ -3071,8 +3852,8 @@ exprval = expr.evalf(prec, chop=True) re, im = exprval.as_real_imag() - # Must be numerical - if not ((re.is_Float or re.is_Integer) and (im.is_Float or im.is_Integer)): + # safety check to make sure that this evaluated to a number + if not (re.is_Number and im.is_Number): return expr def nsimplify_real(x): @@ -3093,7 +3874,7 @@ if full: newexpr = newexpr[0] expr = sympify(newexpr) - if expr.is_finite is False and not xv in [mpmath.inf, mpmath.ninf]: + if expr.is_bounded is False and not xv in [mpmath.inf, mpmath.ninf]: raise ValueError return expr finally: @@ -3101,8 +3882,10 @@ # before leaving mpmath.mp.dps = orig try: - if re: re = nsimplify_real(re) - if im: im = nsimplify_real(im) + if re: + re = nsimplify_real(re) + if im: + im = nsimplify_real(im) except ValueError: if rational is None: return _real_to_rational(expr) @@ -3116,151 +3899,164 @@ return _real_to_rational(expr) - def logcombine(expr, force=False): """ Takes logarithms and combines them using the following rules: - - log(x)+log(y) == log(x*y) - - a*log(x) == log(x**a) + - log(x) + log(y) == log(x*y) if both are not negative + - a*log(x) == log(x**a) if x is positive and a is real - These identities are only valid if x and y are positive and if a is real, - so the function will not combine the terms unless the arguments have the - proper assumptions on them. Use logcombine(func, force=True) to - automatically assume that the arguments of logs are positive and that - coefficients are real. Note that this will not change any assumptions - already in place, so if the coefficient is imaginary or the argument - negative, combine will still not combine the equations. Change the - assumptions on the variables to make them combine. + If ``force`` is True then the assumptions above will be assumed to hold if + there is no assumption already in place on a quantity. For example, if + ``a`` is imaginary or the argument negative, force will not perform a + combination but if ``a`` is a symbol with no assumptions the change will + take place. Examples ======== - >>> from sympy import Symbol, symbols, log, logcombine + >>> from sympy import Symbol, symbols, log, logcombine, I >>> from sympy.abc import a, x, y, z - >>> logcombine(a*log(x)+log(y)-log(z)) + >>> logcombine(a*log(x) + log(y) - log(z)) a*log(x) + log(y) - log(z) - >>> logcombine(a*log(x)+log(y)-log(z), force=True) + >>> logcombine(a*log(x) + log(y) - log(z), force=True) log(x**a*y/z) >>> x,y,z = symbols('x,y,z', positive=True) >>> a = Symbol('a', real=True) - >>> logcombine(a*log(x)+log(y)-log(z)) + >>> logcombine(a*log(x) + log(y) - log(z)) log(x**a*y/z) - """ - # Try to make (a+bi)*log(x) == a*log(x)+bi*log(x). This needs to be a - # separate function call to avoid infinite recursion. - expr = expand_mul(expr) - return _logcombine(expr, force) + The transformation is limited to factors and/or terms that + contain logs, so the result depends on the initial state of + expansion: -def _logcombine(expr, force=False): - """ - Does the main work for logcombine, it's a separate function to avoid an - infinite recursion. See the docstrings of logcombine() for help. - """ - def _getlogargs(expr): - """ - Returns the arguments of the logarithm in an expression. + >>> eq = (2 + 3*I)*log(x) + >>> logcombine(eq, force=True) == eq + True + >>> logcombine(eq.expand(), force=True) + log(x**2) + I*log(x**3) - Examples - ======== + See Also + ======== + posify: replace all symbols with symbols having positive assumptions - _getlogargs(a*log(x*y)) - x*y - """ - if expr.func is log: - return [expr.args[0]] - else: - args = [] - for i in expr.args: - if i.func is log: - args.append(_getlogargs(i)) - return flatten(args) - return None + """ - if expr.is_Number or expr.is_NumberSymbol or type(expr) == C.Integral: - return expr + def f(rv): + if not (rv.is_Add or rv.is_Mul): + return rv - if isinstance(expr, Equality): - retval = Equality(_logcombine(expr.lhs-expr.rhs, force),\ - Integer(0)) - # If logcombine couldn't do much with the equality, try to make it like - # it was. Hopefully extract_additively won't become smart enough to - # take logs apart :) - right = retval.lhs.extract_additively(expr.lhs) - if right: - return Equality(expr.lhs, _logcombine(-right, force)) - else: - return retval + def gooda(a): + # bool to tell whether the leading ``a`` in ``a*log(x)`` + # could appear as log(x**a) + return (a is not S.NegativeOne and # -1 *could* go, but we disallow + (a.is_real or force and a.is_real is not False)) - if expr.is_Add: - argslist = 1 - notlogs = 0 - coeflogs = 0 - for i in expr.args: - if i.func is log: - if (i.args[0].is_positive or (force and not \ - i.args[0].is_nonpositive)): - argslist *= _logcombine(i.args[0], force) - else: - notlogs += i - elif i.is_Mul and any([getattr(t,'func', False)==log for t in i.args]): - largs = _getlogargs(i) - assert len(largs) != 0 - loglargs = 1 - for j in largs: - loglargs *= log(j) - - if all(getattr(t,'is_positive') for t in largs)\ - and getattr(i.extract_multiplicatively(loglargs),'is_real', False)\ - or (force\ - and not all(getattr(t,'is_nonpositive') for t in largs)\ - and not getattr(i.extract_multiplicatively(loglargs),\ - 'is_real')==False): + def goodlog(l): + # bool to tell whether log ``l``'s argument can combine with others + a = l.args[0] + return a.is_positive or force and a.is_nonpositive is not False - coeflogs += _logcombine(i, force) + other = [] + logs = [] + log1 = defaultdict(list) + for a in Add.make_args(rv): + if a.func is log and goodlog(a): + log1[()].append(([], a)) + elif not a.is_Mul: + other.append(a) + else: + ot = [] + co = [] + lo = [] + for ai in a.args: + if ai.is_Rational and ai < 0: + ot.append(S.NegativeOne) + co.append(-ai) + elif ai.func is log and goodlog(ai): + lo.append(ai) + elif gooda(ai): + co.append(ai) + else: + ot.append(ai) + if len(lo) > 1: + logs.append((ot, co, lo)) + elif lo: + log1[tuple(ot)].append((co, lo[0])) else: - notlogs += i - elif i.has(log): - notlogs += _logcombine(i, force) + other.append(a) + + # if there is only one log at each coefficient and none have + # an exponent to place inside the log then there is nothing to do + if not logs and all(len(log1[k]) == 1 and log1[k][0] == [] for k in log1): + return rv + + # collapse multi-logs as far as possible in a canonical way + # TODO: see if x*log(a)+x*log(a)*log(b) -> x*log(a)*(1+log(b))? + # -- in this case, it's unambiguous, but if it were were a log(c) in + # each term then it's arbitrary whether they are grouped by log(a) or + # by log(c). So for now, just leave this alone; it's probably better to + # let the user decide + for o, e, l in logs: + l = list(ordered(l)) + e = log(l.pop(0).args[0]**Mul(*e)) + while l: + li = l.pop(0) + e = log(li.args[0]**e) + c, l = Mul(*o), e + if l.func is log: # it should be, but check to be sure + log1[(c,)].append(([], l)) else: - notlogs += i - if notlogs + log(argslist) + coeflogs == expr: - return expr - else: - alllogs = _logcombine(log(argslist) + coeflogs, force) - return notlogs + alllogs + other.append(c*l) - if expr.is_Mul: - a = Wild('a') - x = Wild('x') - coef = expr.match(a*log(x)) - if coef\ - and (coef[a].is_real\ - or expr.is_Number\ - or expr.is_NumberSymbol\ - or type(coef[a]) in (int, float)\ - or (force\ - and not coef[a].is_imaginary))\ - and (coef[a].func != log\ - or force\ - or (not getattr(coef[a],'is_real')==False\ - and getattr(x, 'is_positive'))): + # logs that have the same coefficient can multiply + for k in list(log1.keys()): + log1[Mul(*k)] = log(logcombine(Mul(*[ + l.args[0]**Mul(*c) for c, l in log1.pop(k)]), + force=force)) + + # logs that have oppositely signed coefficients can divide + for k in ordered(list(log1.keys())): + if not k in log1: # already popped as -k + continue + if -k in log1: + # figure out which has the minus sign; the one with + # more op counts should be the one + num, den = k, -k + if num.count_ops() > den.count_ops(): + num, den = den, num + other.append(num*log(log1.pop(num).args[0]/log1.pop(den).args[0])) + else: + other.append(k*log1.pop(k)) - return log(coef[x]**coef[a]) - else: - return _logcombine(expr.args[0], force)*reduce(lambda x, y:\ - _logcombine(x, force)*_logcombine(y, force),\ - expr.args[1:], S.One) + return Add(*other) - if expr.is_Function: - return expr.func(*[_logcombine(t, force) for t in expr.args]) + return bottom_up(expr, f) - if expr.is_Pow: - return _logcombine(expr.args[0], force)**\ - _logcombine(expr.args[1], force) - return expr +def bottom_up(rv, F, atoms=False, nonbasic=False): + """Apply ``F`` to all expressions in an expression tree from the + bottom up. If ``atoms`` is True, apply ``F`` even if there are no args; + if ``nonbasic`` is True, try to apply ``F`` to non-Basic objects. + """ + try: + if rv.args: + args = tuple([bottom_up(a, F, atoms, nonbasic) + for a in rv.args]) + if args != rv.args: + rv = rv.func(*args) + rv = F(rv) + elif atoms: + rv = F(rv) + except AttributeError: + if nonbasic: + try: + rv = F(rv) + except TypeError: + pass + + return rv + def besselsimp(expr): """ @@ -3269,8 +4065,11 @@ This routine tries to simplify bessel-type functions. Currently it only works on the Bessel J and I functions, however. It works by looking at all such functions in turn, and eliminating factors of "I" and "-1" (actually - their polar equivalents) in front of the argument. After that, functions of - half-integer order are rewritten using trigonometric functions. + their polar equivalents) in front of the argument. Then, functions of + half-integer order are rewritten using trigonometric functions and + functions of integer order (> 1) are rewritten using functions + of low order. Finally, if the expression was changed, compute + factorization of the result with factor(). >>> from sympy import besselj, besseli, besselsimp, polar_lift, I, S >>> from sympy.abc import z, nu @@ -3280,51 +4079,875 @@ exp(-I*pi*nu/2)*besselj(nu, z) >>> besselsimp(besseli(S(-1)/2, z)) sqrt(2)*cosh(z)/(sqrt(pi)*sqrt(z)) + >>> besselsimp(z*besseli(0, z) + z*(besseli(2, z))/2 + besseli(1, z)) + 3*z*besseli(0, z)/2 """ - from sympy import besselj, besseli, jn, I, pi, Dummy + from sympy import besselj, bessely, besseli, besselk, jn, I, pi, Dummy # TODO - # - extension to more types of functions - # (at least rewriting functions of half integer order should be straight - # forward also for Y and K) # - better algorithm? # - simplify (cos(pi*b)*besselj(b,z) - besselj(-b,z))/sin(pi*b) ... # - use contiguity relations? def replacer(fro, to, factors): factors = set(factors) + def repl(nu, z): if factors.intersection(Mul.make_args(z)): return to(nu, z) return fro(nu, z) return repl + def torewrite(fro, to): def tofunc(nu, z): return fro(nu, z).rewrite(to) return tofunc + def tominus(fro): def tofunc(nu, z): return exp(I*pi*nu)*fro(nu, exp_polar(-I*pi)*z) return tofunc + orig_expr = expr + ifactors = [I, exp_polar(I*pi/2), exp_polar(-I*pi/2)] - expr = expr.replace(besselj, replacer(besselj, - torewrite(besselj, besseli), ifactors)) - expr = expr.replace(besseli, replacer(besseli, - torewrite(besseli, besselj), ifactors)) + expr = expr.replace( + besselj, replacer(besselj, + torewrite(besselj, besseli), ifactors)) + expr = expr.replace( + besseli, replacer(besseli, + torewrite(besseli, besselj), ifactors)) minusfactors = [-1, exp_polar(I*pi)] - expr = expr.replace(besselj, replacer(besselj, tominus(besselj), minusfactors)) - expr = expr.replace(besseli, replacer(besseli, tominus(besseli), minusfactors)) + expr = expr.replace( + besselj, replacer(besselj, tominus(besselj), minusfactors)) + expr = expr.replace( + besseli, replacer(besseli, tominus(besseli), minusfactors)) z0 = Dummy('z') + def expander(fro): def repl(nu, z): - if (nu % 1) != S(1)/2: - return fro(nu, z) - return unpolarify(fro(nu, z0).rewrite(besselj).rewrite(jn).expand(func=True)).subs(z0, z) + if (nu % 1) == S(1)/2: + return exptrigsimp(trigsimp(unpolarify( + fro(nu, z0).rewrite(besselj).rewrite(jn).expand( + func=True)).subs(z0, z))) + elif nu.is_Integer and nu > 1: + return fro(nu, z).expand(func=True) + return fro(nu, z) return repl expr = expr.replace(besselj, expander(besselj)) + expr = expr.replace(bessely, expander(bessely)) expr = expr.replace(besseli, expander(besseli)) + expr = expr.replace(besselk, expander(besselk)) + + if expr != orig_expr: + expr = expr.factor() + + return expr + +def exptrigsimp(expr, simplify=True): + """ + Simplifies exponential / trigonometric / hyperbolic functions. + When ``simplify`` is True (default) the expression obtained after the + simplification step will be then be passed through simplify to + precondition it so the final transformations will be applied. + + Examples + ======== + + >>> from sympy import exptrigsimp, exp, cosh, sinh + >>> from sympy.abc import z + + >>> exptrigsimp(exp(z) + exp(-z)) + 2*cosh(z) + >>> exptrigsimp(cosh(z) - sinh(z)) + exp(-z) + """ + from sympy.simplify.fu import hyper_as_trig, TR2i + + def exp_trig(e): + # select the better of e, and e rewritten in terms of exp or trig + # functions + choices = [e] + if e.has(*_trigs): + choices.append(e.rewrite(exp)) + choices.append(e.rewrite(cos)) + return min(*choices, **dict(key=count_ops)) + newexpr = bottom_up(expr, exp_trig) + + if simplify: + newexpr = newexpr.simplify() + + # conversion from exp to hyperbolic + ex = newexpr.atoms(exp, S.Exp1) + ex = [ei for ei in ex if 1/ei not in ex] + ## sinh and cosh + for ei in ex: + e2 = ei**-2 + if e2 in ex: + a = e2.args[0]/2 + newexpr = newexpr.subs((e2 + 1)*ei, 2*cosh(a)) + newexpr = newexpr.subs((e2 - 1)*ei, 2*sinh(a)) + ## exp ratios to tan and tanh + for ei in ex: + n, d = ei - 1, ei + 1 + et = n/d + etinv = d/n # not 1/et or else recursion errors arise + a = ei.args[0] if ei.func is exp else S.One + if a.is_Mul or a is S.ImaginaryUnit: + c = a.as_coefficient(I) + if c: + t = S.ImaginaryUnit*tan(c/2) + newexpr = newexpr.subs(etinv, 1/t) + newexpr = newexpr.subs(et, t) + continue + t = tanh(a/2) + newexpr = newexpr.subs(etinv, 1/t) + newexpr = newexpr.subs(et, t) + + # sin/cos and sinh/cosh ratios to tan and tanh, respectively + if newexpr.has(C.HyperbolicFunction): + e, f = hyper_as_trig(newexpr) + newexpr = f(TR2i(e)) + if newexpr.has(C.TrigonometricFunction): + newexpr = TR2i(newexpr) + + # can we ever generate an I where there was none previously? + if not (newexpr.has(I) and not expr.has(I)): + expr = newexpr + return expr + + +def _is_Expr(e): + """_eapply helper to tell whether ``e`` and all its args + are Exprs.""" + if not isinstance(e, Expr): + return False + return all(_is_Expr(i) for i in e.args) + + +def _eapply(func, e, cond=None): + """Apply ``func`` to ``e`` if all args are Exprs else only + apply it to those args that *are* Exprs.""" + if not isinstance(e, Expr): + return e + if _is_Expr(e) or not e.args: + return func(e) + return e.func(*[ + _eapply(func, ei) if (cond is None or cond(ei)) else ei + for ei in e.args]) + + +def futrig(e, **kwargs): + """Return simplified ``e`` using Fu-like transformations. + This is not the "Fu" algorithm. This is called by default + from ``trigsimp``. By default, hyperbolics subexpressions + will be simplified, but this can be disabled by setting + ``hyper=False``. + + Examples + ======== + + >>> from sympy import trigsimp, tan, sinh, tanh + >>> from sympy.simplify.simplify import futrig + >>> from sympy.abc import x + >>> trigsimp(1/tan(x)**2) + tan(x)**(-2) + + >>> futrig(sinh(x)/tanh(x)) + cosh(x) + + """ + from sympy.simplify.fu import hyper_as_trig + + e = sympify(e) + + if not isinstance(e, Basic): + return e + + if not e.args: + return e + + old = e + e = bottom_up(e, lambda x: _futrig(x, **kwargs)) + + if kwargs.pop('hyper', True) and e.has(C.HyperbolicFunction): + e, f = hyper_as_trig(e) + e = f(_futrig(e)) + + if e != old and e.is_Mul and e.args[0].is_Rational: + # redistribute leading coeff on 2-arg Add + e = Mul(*e.as_coeff_Mul()) + return e + + +def _futrig(e, **kwargs): + """Helper for futrig.""" + from sympy.strategies.tree import greedy + from sympy.strategies.core import identity + from sympy.simplify.fu import ( + TR1, TR2, TR3, TR2i, TR14, TR5, TR10, L, TR10i, + TR8, TR6, TR15, TR16, TR111, TR5, TRmorrie, TR11, TR14, TR22, + TR12) + from sympy.core.compatibility import ordered, _nodes + + if not e.has(C.TrigonometricFunction): + return e + + if e.is_Mul: + coeff, e = e.as_independent(C.TrigonometricFunction) + else: + coeff = S.One + + Lops = lambda x: (L(x), x.count_ops(), _nodes(x), len(x.args), x.is_Add) + trigs = lambda x: x.has(C.TrigonometricFunction) + + tree = [identity, + ( + TR3, # canonical angles + TR1, # sec-csc -> cos-sin + TR12, # expand tan of sum + lambda x: _eapply(factor, x, trigs), + TR2, # tan-cot -> sin-cos + [identity, lambda x: _eapply(_mexpand, x, trigs)], + TR2i, # sin-cos ratio -> tan + lambda x: _eapply(lambda i: factor(i.normal()), x, trigs), + TR14, # factored identities + TR5, # sin-pow -> cos_pow + TR10, # sin-cos of sums -> sin-cos prod + TR11, TR6, # reduce double angles and rewrite cos pows + lambda x: _eapply(factor, x, trigs), + TR14, # factored powers of identities + [identity, lambda x: _eapply(_mexpand, x, trigs)], + TRmorrie, + TR10i, # sin-cos products > sin-cos of sums + [identity, TR8], # sin-cos products -> sin-cos of sums + [identity, lambda x: TR2i(TR2(x))], # tan -> sin-cos -> tan + [ + lambda x: _eapply(expand_mul, TR5(x), trigs), + lambda x: _eapply( + expand_mul, TR15(x), trigs)], # pos/neg powers of sin + [ + lambda x: _eapply(expand_mul, TR6(x), trigs), + lambda x: _eapply( + expand_mul, TR16(x), trigs)], # pos/neg powers of cos + TR111, # tan, sin, cos to neg power -> cot, csc, sec + [identity, TR2i], # sin-cos ratio to tan + [identity, lambda x: _eapply( + expand_mul, TR22(x), trigs)], # tan-cot to sec-csc + TR1, TR2, TR2i, + [identity, lambda x: _eapply( + factor_terms, TR12(x), trigs)], # expand tan of sum + )] + e = greedy(tree, objective=Lops)(e) + + return coeff*e + + +def sum_simplify(s): + """Main function for Sum simplification""" + from sympy.concrete.summations import Sum + + terms = Add.make_args(s) + s_t = [] # Sum Terms + o_t = [] # Other Terms + + for term in terms: + if isinstance(term, Mul): + constant = 1 + other = 1 + s = 0 + n_sum_terms = 0 + for j in range(len(term.args)): + if isinstance(term.args[j], Sum): + s = term.args[j] + n_sum_terms = n_sum_terms + 1 + elif term.args[j].is_number == True: + constant = constant * term.args[j] + else: + other = other * term.args[j] + if other == 1 and n_sum_terms == 1: + # Insert the constant inside the Sum + s_t.append(Sum(constant * s.function, *s.limits)) + elif other != 1 and n_sum_terms == 1: + o_t.append(other * Sum(constant * s.function, *s.limits)) + else: + o_t.append(term) + elif isinstance(term, Sum): + s_t.append(term) + else: + o_t.append(term) + + used = [False] * len(s_t) + + for method in range(2): + for i, s_term1 in enumerate(s_t): + if not used[i]: + for j, s_term2 in enumerate(s_t): + if not used[j] and i != j: + if isinstance(sum_add(s_term1, s_term2, method), Sum): + s_t[i] = sum_add(s_term1, s_term2, method) + used[j] = True + + result = Add(*o_t) + + for i, s_term in enumerate(s_t): + if not used[i]: + result = Add(result, s_term) + + return result + + +def sum_add(self, other, method=0): + """Helper function for Sum simplification""" + from sympy.concrete.summations import Sum + + if type(self) == type(other): + if method == 0: + if self.limits == other.limits: + return Sum(self.function + other.function, *self.limits) + elif method == 1: + if simplify(self.function - other.function) == 0: + if len(self.limits) == len(other.limits) == 1: + i = self.limits[0][0] + x1 = self.limits[0][1] + y1 = self.limits[0][2] + j = other.limits[0][0] + x2 = other.limits[0][1] + y2 = other.limits[0][2] + + if i == j: + if x2 == y1 + 1: + return Sum(self.function, (i, x1, y2)) + elif x1 == y2 + 1: + return Sum(self.function, (i, x2, y1)) + + return Add(self, other) + + +def product_simplify(s): + """Main function for Product simplification""" + from sympy.concrete.products import Product + + terms = Mul.make_args(s) + p_t = [] # Product Terms + o_t = [] # Other Terms + + for term in terms: + if isinstance(term, Product): + p_t.append(term) + else: + o_t.append(term) + + used = [False] * len(p_t) + + for method in range(2): + for i, p_term1 in enumerate(p_t): + if not used[i]: + for j, p_term2 in enumerate(p_t): + if not used[j] and i != j: + if isinstance(product_mul(p_term1, p_term2, method), Product): + p_t[i] = product_mul(p_term1, p_term2, method) + used[j] = True + + result = Mul(*o_t) + + for i, p_term in enumerate(p_t): + if not used[i]: + result = Mul(result, p_term) + + return result + + +def product_mul(self, other, method=0): + """Helper function for Product simplification""" + from sympy.concrete.products import Product + + if type(self) == type(other): + if method == 0: + if self.limits == other.limits: + return Product(self.function * other.function, *self.limits) + elif method == 1: + if simplify(self.function - other.function) == 0: + if len(self.limits) == len(other.limits) == 1: + i = self.limits[0][0] + x1 = self.limits[0][1] + y1 = self.limits[0][2] + j = other.limits[0][0] + x2 = other.limits[0][1] + y2 = other.limits[0][2] + + if i == j: + if x2 == y1 + 1: + return Product(self.function, (i, x1, y2)) + elif x1 == y2 + 1: + return Product(self.function, (i, x2, y1)) + + return Mul(self, other) + +#-------------------- the old trigsimp routines --------------------- +_trigs = (C.TrigonometricFunction, C.HyperbolicFunction) + + +def trigsimp_old(expr, **opts): + """ + reduces expression by using known trig identities + + Notes + ===== + + deep: + - Apply trigsimp inside all objects with arguments + + recursive: + - Use common subexpression elimination (cse()) and apply + trigsimp recursively (this is quite expensive if the + expression is large) + + method: + - Determine the method to use. Valid choices are 'matching' (default), + 'groebner', 'combined', 'fu' and 'futrig'. If 'matching', simplify the + expression recursively by pattern matching. If 'groebner', apply an + experimental groebner basis algorithm. In this case further options + are forwarded to ``trigsimp_groebner``, please refer to its docstring. + If 'combined', first run the groebner basis algorithm with small + default parameters, then run the 'matching' algorithm. 'fu' runs the + collection of trigonometric transformations described by Fu, et al. + (see the `fu` docstring) while `futrig` runs a subset of Fu-transforms + that mimic the behavior of `trigsimp`. + + compare: + - show input and output from `trigsimp` and `futrig` when different, + but returns the `trigsimp` value. + + Examples + ======== + + >>> from sympy import trigsimp, sin, cos, log, cosh, sinh, tan, cot + >>> from sympy.abc import x, y + >>> e = 2*sin(x)**2 + 2*cos(x)**2 + >>> trigsimp(e, old=True) + 2 + >>> trigsimp(log(e), old=True) + log(2*sin(x)**2 + 2*cos(x)**2) + >>> trigsimp(log(e), deep=True, old=True) + log(2) + + Using `method="groebner"` (or `"combined"`) can sometimes lead to a lot + more simplification: + + >>> e = (-sin(x) + 1)/cos(x) + cos(x)/(-sin(x) + 1) + >>> trigsimp(e, old=True) + (-sin(x) + 1)/cos(x) - cos(x)/(sin(x) - 1) + >>> trigsimp(e, method="groebner", old=True) + 2/cos(x) + + >>> trigsimp(1/cot(x)**2, compare=True, old=True) + futrig: tan(x)**2 + cot(x)**(-2) + + """ + from sympy import tan + from sympy.simplify.fu import fu + + old = expr + first = opts.pop('first', True) + if first: + if not expr.has(*_trigs): + return expr + + trigsyms = set_union(*[t.free_symbols for t in expr.atoms(*_trigs)]) + if len(trigsyms) > 1: + d = separatevars(expr) + if d.is_Mul: + d = separatevars(d, dict=True) or d + if isinstance(d, dict): + expr = 1 + for k, v in d.items(): + # remove hollow factoring + was = v + v = expand_mul(v) + opts['first'] = False + vnew = trigsimp(v, **opts) + if vnew == v: + vnew = was + expr *= vnew + old = expr + else: + if d.is_Add: + for s in trigsyms: + r, e = expr.as_independent(s) + if r: + opts['first'] = False + expr = r + trigsimp(e, **opts) + if not expr.is_Add: + break + old = expr + + recursive = opts.pop('recursive', False) + deep = opts.pop('deep', False) + method = opts.pop('method', 'matching') + + def groebnersimp(ex, deep, **opts): + def traverse(e): + if e.is_Atom: + return e + args = [traverse(x) for x in e.args] + if e.is_Function or e.is_Pow: + args = [trigsimp_groebner(x, **opts) for x in args] + return e.func(*args) + if deep: + ex = traverse(ex) + return trigsimp_groebner(ex, **opts) + + trigsimpfunc = { + 'matching': (lambda x, d: _trigsimp(x, d)), + 'groebner': (lambda x, d: groebnersimp(x, d, **opts)), + 'combined': (lambda x, d: _trigsimp(groebnersimp(x, + d, polynomial=True, hints=[2, tan]), + d)) + }[method] + + if recursive: + w, g = cse(expr) + g = trigsimpfunc(g[0], deep) + + for sub in reversed(w): + g = g.subs(sub[0], sub[1]) + g = trigsimpfunc(g, deep) + result = g + else: + result = trigsimpfunc(expr, deep) + + if opts.get('compare', False): + f = futrig(old) + if f != result: + print('\tfutrig:', f) + + return result + + +def _dotrig(a, b): + """Helper to tell whether ``a`` and ``b`` have the same sorts + of symbols in them -- no need to test hyperbolic patterns against + expressions that have no hyperbolics in them.""" + return a.func == b.func and ( + a.has(C.TrigonometricFunction) and b.has(C.TrigonometricFunction) or + a.has(C.HyperbolicFunction) and b.has(C.HyperbolicFunction)) + + +_trigpat = None +def _trigpats(): + global _trigpat + a, b, c = symbols('a b c', cls=Wild) + d = Wild('d', commutative=False) + + # for the simplifications like sinh/cosh -> tanh: + # DO NOT REORDER THE FIRST 14 since these are assumed to be in this + # order in _match_div_rewrite. + matchers_division = ( + (a*sin(b)**c/cos(b)**c, a*tan(b)**c, sin(b), cos(b)), + (a*tan(b)**c*cos(b)**c, a*sin(b)**c, sin(b), cos(b)), + (a*cot(b)**c*sin(b)**c, a*cos(b)**c, sin(b), cos(b)), + (a*tan(b)**c/sin(b)**c, a/cos(b)**c, sin(b), cos(b)), + (a*cot(b)**c/cos(b)**c, a/sin(b)**c, sin(b), cos(b)), + (a*cot(b)**c*tan(b)**c, a, sin(b), cos(b)), + (a*(cos(b) + 1)**c*(cos(b) - 1)**c, + a*(-sin(b)**2)**c, cos(b) + 1, cos(b) - 1), + (a*(sin(b) + 1)**c*(sin(b) - 1)**c, + a*(-cos(b)**2)**c, sin(b) + 1, sin(b) - 1), + + (a*sinh(b)**c/cosh(b)**c, a*tanh(b)**c, S.One, S.One), + (a*tanh(b)**c*cosh(b)**c, a*sinh(b)**c, S.One, S.One), + (a*coth(b)**c*sinh(b)**c, a*cosh(b)**c, S.One, S.One), + (a*tanh(b)**c/sinh(b)**c, a/cosh(b)**c, S.One, S.One), + (a*coth(b)**c/cosh(b)**c, a/sinh(b)**c, S.One, S.One), + (a*coth(b)**c*tanh(b)**c, a, S.One, S.One), + + (c*(tanh(a) + tanh(b))/(1 + tanh(a)*tanh(b)), + tanh(a + b)*c, S.One, S.One), + ) + + matchers_add = ( + (c*sin(a)*cos(b) + c*cos(a)*sin(b) + d, sin(a + b)*c + d), + (c*cos(a)*cos(b) - c*sin(a)*sin(b) + d, cos(a + b)*c + d), + (c*sin(a)*cos(b) - c*cos(a)*sin(b) + d, sin(a - b)*c + d), + (c*cos(a)*cos(b) + c*sin(a)*sin(b) + d, cos(a - b)*c + d), + (c*sinh(a)*cosh(b) + c*sinh(b)*cosh(a) + d, sinh(a + b)*c + d), + (c*cosh(a)*cosh(b) + c*sinh(a)*sinh(b) + d, cosh(a + b)*c + d), + ) + + # for cos(x)**2 + sin(x)**2 -> 1 + matchers_identity = ( + (a*sin(b)**2, a - a*cos(b)**2), + (a*tan(b)**2, a*(1/cos(b))**2 - a), + (a*cot(b)**2, a*(1/sin(b))**2 - a), + (a*sin(b + c), a*(sin(b)*cos(c) + sin(c)*cos(b))), + (a*cos(b + c), a*(cos(b)*cos(c) - sin(b)*sin(c))), + (a*tan(b + c), a*((tan(b) + tan(c))/(1 - tan(b)*tan(c)))), + + (a*sinh(b)**2, a*cosh(b)**2 - a), + (a*tanh(b)**2, a - a*(1/cosh(b))**2), + (a*coth(b)**2, a + a*(1/sinh(b))**2), + (a*sinh(b + c), a*(sinh(b)*cosh(c) + sinh(c)*cosh(b))), + (a*cosh(b + c), a*(cosh(b)*cosh(c) + sinh(b)*sinh(c))), + (a*tanh(b + c), a*((tanh(b) + tanh(c))/(1 + tanh(b)*tanh(c)))), + + ) + + # Reduce any lingering artifacts, such as sin(x)**2 changing + # to 1-cos(x)**2 when sin(x)**2 was "simpler" + artifacts = ( + (a - a*cos(b)**2 + c, a*sin(b)**2 + c, cos), + (a - a*(1/cos(b))**2 + c, -a*tan(b)**2 + c, cos), + (a - a*(1/sin(b))**2 + c, -a*cot(b)**2 + c, sin), + + (a - a*cosh(b)**2 + c, -a*sinh(b)**2 + c, cosh), + (a - a*(1/cosh(b))**2 + c, a*tanh(b)**2 + c, cosh), + (a + a*(1/sinh(b))**2 + c, a*coth(b)**2 + c, sinh), + + # same as above but with noncommutative prefactor + (a*d - a*d*cos(b)**2 + c, a*d*sin(b)**2 + c, cos), + (a*d - a*d*(1/cos(b))**2 + c, -a*d*tan(b)**2 + c, cos), + (a*d - a*d*(1/sin(b))**2 + c, -a*d*cot(b)**2 + c, sin), + + (a*d - a*d*cosh(b)**2 + c, -a*d*sinh(b)**2 + c, cosh), + (a*d - a*d*(1/cosh(b))**2 + c, a*d*tanh(b)**2 + c, cosh), + (a*d + a*d*(1/sinh(b))**2 + c, a*d*coth(b)**2 + c, sinh), + ) + + _trigpat = (a, b, c, d, matchers_division, matchers_add, + matchers_identity, artifacts) + return _trigpat + + +def _replace_mul_fpowxgpow(expr, f, g, rexp, h, rexph): + """Helper for _match_div_rewrite. + + Replace f(b_)**c_*g(b_)**(rexp(c_)) with h(b)**rexph(c) if f(b_) + and g(b_) are both positive or if c_ is an integer. + """ + # assert expr.is_Mul and expr.is_commutative and f != g + fargs = defaultdict(int) + gargs = defaultdict(int) + args = [] + for x in expr.args: + if x.is_Pow or x.func in (f, g): + b, e = x.as_base_exp() + if b.is_positive or e.is_integer: + if b.func == f: + fargs[b.args[0]] += e + continue + elif b.func == g: + gargs[b.args[0]] += e + continue + args.append(x) + common = set(fargs) & set(gargs) + hit = False + while common: + key = common.pop() + fe = fargs.pop(key) + ge = gargs.pop(key) + if fe == rexp(ge): + args.append(h(key)**rexph(fe)) + hit = True + else: + fargs[key] = fe + gargs[key] = ge + if not hit: + return expr + while fargs: + key, e = fargs.popitem() + args.append(f(key)**e) + while gargs: + key, e = gargs.popitem() + args.append(g(key)**e) + return Mul(*args) + + +_idn = lambda x: x +_midn = lambda x: -x +_one = lambda x: S.One + +def _match_div_rewrite(expr, i): + """helper for __trigsimp""" + if i == 0: + expr = _replace_mul_fpowxgpow(expr, sin, cos, + _midn, tan, _idn) + elif i == 1: + expr = _replace_mul_fpowxgpow(expr, tan, cos, + _idn, sin, _idn) + elif i == 2: + expr = _replace_mul_fpowxgpow(expr, cot, sin, + _idn, cos, _idn) + elif i == 3: + expr = _replace_mul_fpowxgpow(expr, tan, sin, + _midn, cos, _midn) + elif i == 4: + expr = _replace_mul_fpowxgpow(expr, cot, cos, + _midn, sin, _midn) + elif i == 5: + expr = _replace_mul_fpowxgpow(expr, cot, tan, + _idn, _one, _idn) + # i in (6, 7) is skipped + elif i == 8: + expr = _replace_mul_fpowxgpow(expr, sinh, cosh, + _midn, tanh, _idn) + elif i == 9: + expr = _replace_mul_fpowxgpow(expr, tanh, cosh, + _idn, sinh, _idn) + elif i == 10: + expr = _replace_mul_fpowxgpow(expr, coth, sinh, + _idn, cosh, _idn) + elif i == 11: + expr = _replace_mul_fpowxgpow(expr, tanh, sinh, + _midn, cosh, _midn) + elif i == 12: + expr = _replace_mul_fpowxgpow(expr, coth, cosh, + _midn, sinh, _midn) + elif i == 13: + expr = _replace_mul_fpowxgpow(expr, coth, tanh, + _idn, _one, _idn) + else: + return None + return expr + + +def _trigsimp(expr, deep=False): + # protect the cache from non-trig patterns; we only allow + # trig patterns to enter the cache + if expr.has(*_trigs): + return __trigsimp(expr, deep) + return expr + + +@cacheit +def __trigsimp(expr, deep=False): + """recursive helper for trigsimp""" + from sympy.simplify.fu import TR10i + + if _trigpat is None: + _trigpats() + a, b, c, d, matchers_division, matchers_add, \ + matchers_identity, artifacts = _trigpat + + if expr.is_Mul: + # do some simplifications like sin/cos -> tan: + if not expr.is_commutative: + com, nc = expr.args_cnc() + expr = _trigsimp(Mul._from_args(com), deep)*Mul._from_args(nc) + else: + for i, (pattern, simp, ok1, ok2) in enumerate(matchers_division): + if not _dotrig(expr, pattern): + continue + + newexpr = _match_div_rewrite(expr, i) + if newexpr is not None: + if newexpr != expr: + expr = newexpr + break + else: + continue + + # use SymPy matching instead + res = expr.match(pattern) + if res and res.get(c, 0): + if not res[c].is_integer: + ok = ok1.subs(res) + if not ok.is_positive: + continue + ok = ok2.subs(res) + if not ok.is_positive: + continue + # if "a" contains any of trig or hyperbolic funcs with + # argument "b" then skip the simplification + if any(w.args[0] == res[b] for w in res[a].atoms( + C.TrigonometricFunction, C.HyperbolicFunction)): + continue + # simplify and finish: + expr = simp.subs(res) + break # process below + + if expr.is_Add: + args = [] + for term in expr.args: + if not term.is_commutative: + com, nc = term.args_cnc() + nc = Mul._from_args(nc) + term = Mul._from_args(com) + else: + nc = S.One + term = _trigsimp(term, deep) + for pattern, result in matchers_identity: + res = term.match(pattern) + if res is not None: + term = result.subs(res) + break + args.append(term*nc) + if args != expr.args: + expr = Add(*args) + expr = min(expr, expand(expr), key=count_ops) + if expr.is_Add: + for pattern, result in matchers_add: + if not _dotrig(expr, pattern): + continue + expr = TR10i(expr) + if expr.has(C.HyperbolicFunction): + res = expr.match(pattern) + # if "d" contains any trig or hyperbolic funcs with + # argument "a" or "b" then skip the simplification; + # this isn't perfect -- see tests + if res is None or not (a in res and b in res) or any( + w.args[0] in (res[a], res[b]) for w in res[d].atoms( + C.TrigonometricFunction, C.HyperbolicFunction)): + continue + expr = result.subs(res) + break + + # Reduce any lingering artifacts, such as sin(x)**2 changing + # to 1 - cos(x)**2 when sin(x)**2 was "simpler" + for pattern, result, ex in artifacts: + if not _dotrig(expr, pattern): + continue + # Substitute a new wild that excludes some function(s) + # to help influence a better match. This is because + # sometimes, for example, 'a' would match sec(x)**2 + a_t = Wild('a', exclude=[ex]) + pattern = pattern.subs(a, a_t) + result = result.subs(a, a_t) + + m = expr.match(pattern) + was = None + while m and was != expr: + was = expr + if m[a_t] == 0 or \ + -m[a_t] in m[c].args or m[a_t] + m[c] == 0: + break + if d in m and m[a_t]*m[d] + m[c] == 0: + break + expr = result.subs(m) + m = expr.match(pattern) + m.setdefault(c, S.Zero) + + elif expr.is_Mul or expr.is_Pow or deep and expr.args: + expr = expr.func(*[_trigsimp(a, deep) for a in expr.args]) + + try: + if not expr.has(*_trigs): + raise TypeError + e = expr.atoms(exp) + new = expr.rewrite(exp, deep=deep) + if new == e: + raise TypeError + fnew = factor(new) + if fnew != new: + new = sorted([new, factor(new)], key=count_ops)[0] + # if all exp that were introduced disappeared then accept it + if not (new.atoms(exp) - e): + expr = new + except TypeError: + pass return expr +#------------------- end of old trigsimp routines -------------------- diff -Nru python3-sympy-0.7.2/sympy/simplify/sqrtdenest.py python3-sympy-0.7.3/sympy/simplify/sqrtdenest.py --- python3-sympy-0.7.2/sympy/simplify/sqrtdenest.py 2012-10-17 03:02:22.000000000 +0000 +++ python3-sympy-0.7.3/sympy/simplify/sqrtdenest.py 2013-07-13 17:53:32.000000000 +0000 @@ -6,6 +6,7 @@ from sympy.core.function import count_ops from sympy.utilities import default_sort_key + def _mexpand(expr): return expand_mul(expand_multinomial(expr)) @@ -72,7 +73,7 @@ return False -def subsets(n): +def _subsets(n): """ Returns all possible subsets of the set (0, 1, ..., n-1) except the empty set, listed in reversed lexicographical order according to binary @@ -81,8 +82,8 @@ Examples ======== - >>> from sympy.simplify.sqrtdenest import subsets - >>> subsets(2) + >>> from sympy.simplify.sqrtdenest import _subsets + >>> _subsets(2) [[1, 0], [0, 1], [1, 1]] """ @@ -94,10 +95,10 @@ a = [[1, 0, 0], [0, 1, 0], [1, 1, 0], [0, 0, 1], [1, 0, 1], [0, 1, 1], [1, 1, 1]] else: - b = subsets(n-1) - a0 = [x+[0] for x in b] - a1 = [x+[1] for x in b] - a = a0 + [[0]*(n-1) + [1]] + a1 + b = _subsets(n - 1) + a0 = [x + [0] for x in b] + a1 = [x + [1] for x in b] + a = a0 + [[0]*(n - 1) + [1]] + a1 return a @@ -212,15 +213,17 @@ res = [] return list(res) + class SqrtdenestStopIteration(StopIteration): pass + def _sqrtdenest0(expr): """Returns expr after denesting its arguments.""" if is_sqrt(expr): n, d = expr.as_numer_denom() - if d is S.One: # n is a square root + if d is S.One: # n is a square root if n.base.is_Add: args = sorted(n.base.args, key=default_sort_key) if len(args) > 2 and all((x**2).is_Integer for x in args): @@ -239,6 +242,7 @@ return expr.func(*[_sqrtdenest0(a) for a in args]) return expr + def _sqrtdenest_rec(expr): """Helper that denests the square root of three or more surds. @@ -298,6 +302,7 @@ r = radsimp(r) return _mexpand(r) + def _sqrtdenest1(expr, denester=True): """Return denested expr after denesting with simpler methods or, that failing, using the denester.""" @@ -396,7 +401,7 @@ sqrt(sqrt(sqrt(x + 3) + 1) + 1) + 1 + sqrt(2) """ - a, b, r = sympify([a, b, r]) + a, b, r = list(map(sympify, (a, b, r))) rval = _sqrt_match(r) if not rval: return None @@ -433,6 +438,7 @@ vad1 = radsimp(1/vad) return (sqrt(vad/2) + sign(b)*sqrt((b**2*r*vad1/2).expand())).expand() + def sqrt_biquadratic_denest(expr, a, b, r, d2): """denest expr = sqrt(a + b*sqrt(r)) where a, b, r are linear combinations of square roots of @@ -503,6 +509,7 @@ return _mexpand(z) return None + def _denester(nested, av0, h, max_depth_level): """Denests a list of expressions that contain nested square roots. @@ -529,14 +536,14 @@ if av0[1] is None: return None, None if (av0[0] is None and - all(n.is_Number for n in nested)): # no arguments are nested - for f in subsets(len(nested)): # test subset 'f' of nested + all(n.is_Number for n in nested)): # no arguments are nested + for f in _subsets(len(nested)): # test subset 'f' of nested p = _mexpand(Mul(*[nested[i] for i in range(len(f)) if f[i]])) if f.count(1) > 1 and f[-1]: p = -p sqp = sqrt(p) if sqp.is_Rational: - return sqp, f # got a perfect square so return its square root. + return sqp, f # got a perfect square so return its square root. # Otherwise, return the radicand from the previous invocation. return sqrt(nested[-1]), [0]*len(nested) else: @@ -549,7 +556,7 @@ else: values = [_f for _f in [_sqrt_match(expr) for expr in nested] if _f] for v in values: - if v[2]: #Since if b=0, r is not defined + if v[2]: # Since if b=0, r is not defined if R is not None: if R != v[2]: av0[1] = None @@ -574,7 +581,7 @@ if 1 in f and f.index(1) < len(nested) - 1 and f[len(nested) - 1]: v[0] = -v[0] v[1] = -v[1] - if not f[len(nested)]: #Solution denests with square roots + if not f[len(nested)]: # Solution denests with square roots vad = _mexpand(v[0] + d) if vad <= 0: # return the radicand from the previous invocation. @@ -593,7 +600,7 @@ return res, f # sign(v[1])*sqrt(_mexpand(v[1]**2*R*vad1/2))), f - else: #Solution requires a fourth root + else: # Solution requires a fourth root s2 = _mexpand(v[1]*R) + d if s2 <= 0: return sqrt(nested[-1]), [0]*len(nested) diff -Nru python3-sympy-0.7.2/sympy/simplify/tests/test_cse.py python3-sympy-0.7.3/sympy/simplify/tests/test_cse.py --- python3-sympy-0.7.2/sympy/simplify/tests/test_cse.py 2012-10-17 03:02:22.000000000 +0000 +++ python3-sympy-0.7.3/sympy/simplify/tests/test_cse.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,61 +1,74 @@ import itertools -from sympy import (Add, Mul, Pow, Symbol, exp, sqrt, symbols, sympify, cse, - Matrix, S, cos, sin, Eq) +from sympy import (Add, Pow, Symbol, exp, sqrt, symbols, sympify, cse, + Matrix, S, cos, sin, Eq, Function, Tuple, RootOf) +from sympy.simplify.cse_opts import sub_pre, sub_post from sympy.functions.special.hyper import meijerg from sympy.simplify import cse_main, cse_opts from sympy.utilities.pytest import XFAIL -w,x,y,z = symbols('w,x,y,z') -x0,x1,x2 = list(itertools.islice(cse_main.numbered_symbols(), 0, 3)) -negone = sympify(-1) +w, x, y, z = symbols('w,x,y,z') +x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11 = symbols('x:12') def test_numbered_symbols(): ns = cse_main.numbered_symbols(prefix='y') - assert list(itertools.islice(ns, 0, 10)) == [Symbol('y%s'%i) for i in range(0, 10)] + assert list(itertools.islice( + ns, 0, 10)) == [Symbol('y%s' % i) for i in range(0, 10)] ns = cse_main.numbered_symbols(prefix='y') - assert list(itertools.islice(ns, 10, 20)) == [Symbol('y%s'%i) for i in range(10, 20)] + assert list(itertools.islice( + ns, 10, 20)) == [Symbol('y%s' % i) for i in range(10, 20)] ns = cse_main.numbered_symbols() - assert list(itertools.islice(ns, 0, 10)) == [Symbol('x%s'%i) for i in range(0, 10)] + assert list(itertools.islice( + ns, 0, 10)) == [Symbol('x%s' % i) for i in range(0, 10)] # Dummy "optimization" functions for testing. + def opt1(expr): - return expr+y + return expr + y + + def opt2(expr): return expr*z + def test_preprocess_for_cse(): - assert cse_main.preprocess_for_cse(x, [(opt1, None)]) == x+y + assert cse_main.preprocess_for_cse(x, [(opt1, None)]) == x + y assert cse_main.preprocess_for_cse(x, [(None, opt1)]) == x assert cse_main.preprocess_for_cse(x, [(None, None)]) == x - assert cse_main.preprocess_for_cse(x, [(opt1, opt2)]) == x+y - assert cse_main.preprocess_for_cse(x, [(opt1, None), (opt2, None)]) == (x+y)*z + assert cse_main.preprocess_for_cse(x, [(opt1, opt2)]) == x + y + assert cse_main.preprocess_for_cse( + x, [(opt1, None), (opt2, None)]) == (x + y)*z + def test_postprocess_for_cse(): assert cse_main.postprocess_for_cse(x, [(opt1, None)]) == x - assert cse_main.postprocess_for_cse(x, [(None, opt1)]) == x+y + assert cse_main.postprocess_for_cse(x, [(None, opt1)]) == x + y assert cse_main.postprocess_for_cse(x, [(None, None)]) == x assert cse_main.postprocess_for_cse(x, [(opt1, opt2)]) == x*z # Note the reverse order of application. - assert cse_main.postprocess_for_cse(x, [(None, opt1), (None, opt2)]) == x*z+y + assert cse_main.postprocess_for_cse( + x, [(None, opt1), (None, opt2)]) == x*z + y + def test_cse_single(): # Simple substitution. - e = Add(Pow(x+y,2), sqrt(x+y)) + e = Add(Pow(x + y, 2), sqrt(x + y)) substs, reduced = cse([e], optimizations=[]) assert substs == [(x0, x + y)] assert reduced == [sqrt(x0) + x0**2] + def test_cse_single2(): # Simple substitution, test for being able to pass the expression directly - e = Add(Pow(x+y,2), sqrt(x+y)) + e = Add(Pow(x + y, 2), sqrt(x + y)) substs, reduced = cse(e, optimizations=[]) assert substs == [(x0, x + y)] assert reduced == [sqrt(x0) + x0**2] assert isinstance(cse(Matrix([[1]]))[1][0], Matrix) + def test_cse_not_possible(): # No substitution possible. e = Add(x, y) @@ -63,23 +76,26 @@ assert substs == [] assert reduced == [x + y] # issue 3230 - eq = (meijerg((1, 2), (y, 4), (5,), [], x) + \ + eq = (meijerg((1, 2), (y, 4), (5,), [], x) + meijerg((1, 3), (y, 4), (5,), [], x)) assert cse(eq) == ([], [eq]) + def test_nested_substitution(): # Substitution within a substitution. - e = Add(Pow(w*x+y,2), sqrt(w*x+y)) + e = Add(Pow(w*x + y, 2), sqrt(w*x + y)) substs, reduced = cse([e], optimizations=[]) - assert substs == [(x0, w*x+y)] + assert substs == [(x0, w*x + y)] assert reduced == [sqrt(x0) + x0**2] + def test_subtraction_opt(): # Make sure subtraction is optimized. - e = (x-y)*(z-y) + exp((x-y)*(z-y)) - substs, reduced = cse([e], optimizations=[(cse_opts.sub_pre, cse_opts.sub_post)]) - assert substs == [(x0, x - y), (x1, y - z), (x2, x0*x1)] - assert reduced == [-x2 + exp(-x2)] + e = (x - y)*(z - y) + exp((x - y)*(z - y)) + substs, reduced = cse( + [e], optimizations=[(cse_opts.sub_pre, cse_opts.sub_post)]) + assert substs == [(x0, (x - y)*(y - z))] + assert reduced == [-x0 + exp(-x0)] assert cse(-(x - y)*(z - y) + exp(-(x - y)*(z - y))) == \ ([(x0, (x - y)*(y - z))], [x0 + exp(x0)]) # issue 978 @@ -87,11 +103,12 @@ e = n/x/(-n)**2 - 1/n/x assert cse(e) == ([], [0]) + def test_multiple_expressions(): - e1 = (x+y)*z - e2 = (x+y)*w + e1 = (x + y)*z + e2 = (x + y)*w substs, reduced = cse([e1, e2], optimizations=[]) - assert substs == [(x0, x+y)] + assert substs == [(x0, x + y)] assert reduced == [x0*z, x0*w] l = [w*x*y + z, w*y] substs, reduced = cse(l) @@ -106,62 +123,67 @@ l = [(x - z)*(y - z), x - z, y - z] substs, reduced = cse(l) rsubsts, _ = cse(reversed(l)) - substitutions = [ - [(x0, x - z), (x1, y - z)], - [(x0, y - z), (x1, x - z)], - ] - assert substs in substitutions - assert rsubsts in substitutions + substitutions = [(x0, x - z), (x1, y - z)] + assert substs == substitutions + assert rsubsts == substitutions assert reduced == [x0*x1, x0, x1] l = [w*y + w + x + y + z, w*x*y] assert cse(l) == ([(x0, w*y)], [w + x + x0 + y + z, x*x0]) assert cse([x + y, x + y + z]) == ([(x0, x + y)], [x0, z + x0]) assert cse([x + y, x + z]) == ([], [x + y, x + z]) - assert cse([x*y, z + x*y , x*y*z + 3]) == \ - ([(x0, x*y)], [x0, z + x0, 3 + x0*z]) + assert cse([x*y, z + x*y, x*y*z + 3]) == \ + ([(x0, x*y)], [x0, z + x0, 3 + x0*z]) A, B, C = symbols('A B C', commutative=False) l = [A*B*C, A*C] assert cse(l) == ([], l) l = [A*B*C, A*B] assert cse(l) == ([(x0, A*B)], [x0*C, x0]) + @XFAIL def test_powers(): assert cse(x*y**2 + x*y) == ([(x0, x*y)], [x0*y + x0]) + def test_issues_1399(): assert cse(w/(x - y) + z/(y - x)) == ([], [(w - z)/(x - y)]) + def test_issue_921(): - assert cse(x**5 + x**4 + x**3 + x**2) == ([(x0, x**2)], [x0*(x**3 + x + x0 + 1)]) + assert cse( + x**5 + x**4 + x**3 + x**2) == ([(x0, x**2)], [x0*(x**3 + x + x0 + 1)]) + def test_issue_1104(): assert cse(sin(x**x)/x**x) == ([(x0, x**x)], [sin(x0)/x0]) + def test_issue_3164(): e = Eq(x*(-x + 1) + x*(x - 1), 0) assert cse(e) == ([], [True]) + def test_dont_cse_tuples(): - from sympy import Subs, Function + from sympy import Subs f = Function("f") g = Function("g") name_val, (expr,) = cse( - Subs(f(x, y), (x, y), (0, 1)) - + Subs(g(x, y), (x, y), (0, 1))) + Subs(f(x, y), (x, y), (0, 1)) + + Subs(g(x, y), (x, y), (0, 1))) assert name_val == [] assert expr == (Subs(f(x, y), (x, y), (0, 1)) + Subs(g(x, y), (x, y), (0, 1))) name_val, (expr,) = cse( - Subs(f(x, y), (x, y), (0, x + y)) - + Subs(g(x, y), (x, y), (0, x + y))) + Subs(f(x, y), (x, y), (0, x + y)) + + Subs(g(x, y), (x, y), (0, x + y))) assert name_val == [(x0, x + y)] assert expr == Subs(f(x, y), (x, y), (0, x0)) + \ - Subs(g(x, y), (x, y), (0, x0)) + Subs(g(x, y), (x, y), (0, x0)) + def test_pow_invpow(): assert cse(1/x**2 + x**2) == \ @@ -183,8 +205,42 @@ assert cse(x**(2*y) + x**(-2*y)) == \ ([(x0, x**(2*y))], [x0 + 1/x0]) + def test_postprocess(): eq = (x + 1 + exp((x + 1)/(y + 1)) + cos(y + 1)) - assert cse([eq, Eq(x, z + 1), z - 2], - postprocess=cse_main.cse_separate) == \ - [[(x0, y + 1), (x, z + 1), (x1, x + 1)], [x1 + exp(x1/x0) + cos(x0), z - 2]] + assert cse([eq, Eq(x, z + 1), z - 2, (z + 1)*(x + 1)], + postprocess=cse_main.cse_separate) == \ + [[(x1, y + 1), (x2, z + 1), (x, x2), (x0, x + 1)], + [x0 + exp(x0/x1) + cos(x1), x2 - 3, x0*x2]] + + +def test_issue1400(): + # previously, this gave 16 constants + from sympy.abc import a, b + B = Function('B') + G = Function('G') + t = Tuple(* + (a, a + S(1)/2, 2*a, b, 2*a - b + 1, (sqrt(z)/2)**(-2*a + 1)*B(2*a - + b, sqrt(z))*B(b - 1, sqrt(z))*G(b)*G(2*a - b + 1), + sqrt(z)*(sqrt(z)/2)**(-2*a + 1)*B(b, sqrt(z))*B(2*a - b, + sqrt(z))*G(b)*G(2*a - b + 1), sqrt(z)*(sqrt(z)/2)**(-2*a + 1)*B(b - 1, + sqrt(z))*B(2*a - b + 1, sqrt(z))*G(b)*G(2*a - b + 1), + (sqrt(z)/2)**(-2*a + 1)*B(b, sqrt(z))*B(2*a - b + 1, + sqrt(z))*G(b)*G(2*a - b + 1), 1, 0, S(1)/2, z/2, -b + 1, -2*a + b, + -2*a)) + + c = cse(t) + ans = ( + [(x0, sqrt(z)), (x1, -b + 1), (x2, B(b, x0)), (x3, B(-x1, x0)), (x4, + 2*a + x1), (x5, B(x4 - 1, x0)), (x6, B(x4, x0)), (x7, (x0/2)**(-2*a + + 1)*G(b)*G(x4))], [(a, a + S(1)/2, 2*a, b, x4, x3*x5*x7, x0*x2*x5*x7, + x0*x3*x6*x7, x2*x6*x7, 1, 0, S(1)/2, z/2, x1, -x4 + 1, -2*a)]) + assert ans == c + + +def test_issue_3070(): + r = RootOf(x**6 - 4*x**5 - 2, 1) + assert cse(r) == ([], [r]) + # and a check that the right thing is done with the new + # mechanism + assert sub_post(sub_pre((-x - y)*z - x - y)) == -z*(x + y) - x - y diff -Nru python3-sympy-0.7.2/sympy/simplify/tests/test_epathtools.py python3-sympy-0.7.3/sympy/simplify/tests/test_epathtools.py --- python3-sympy-0.7.2/sympy/simplify/tests/test_epathtools.py 2012-10-17 03:02:22.000000000 +0000 +++ python3-sympy-0.7.3/sympy/simplify/tests/test_epathtools.py 2013-07-13 17:53:32.000000000 +0000 @@ -6,6 +6,7 @@ from sympy import sin, cos, E from sympy.abc import x, y, z, t + def test_epath_select(): expr = [((x, 1, t), 2), ((3, y, 4), z)] @@ -36,7 +37,8 @@ assert epath("/*/int|__iter__?", expr) == [(x, 1, t), 2, (3, y, 4)] assert epath("/*/Symbol|__iter__?", expr) == [(x, 1, t), (3, y, 4), z] - assert epath("/*/int|Symbol|__iter__?", expr) == [(x, 1, t), 2, (3, y, 4), z] + assert epath( + "/*/int|Symbol|__iter__?", expr) == [(x, 1, t), 2, (3, y, 4), z] assert epath("/*/[0]/int", expr) == [1, 3, 4] assert epath("/*/[0]/Symbol", expr) == [x, t, y] @@ -47,6 +49,7 @@ assert epath("/Symbol", x + y + z + 1) == [x, y, z] assert epath("/*/*/Symbol", t + sin(x + 1) + cos(x + y + E)) == [x, x, y] + def test_epath_apply(): expr = [((x, 1, t), 2), ((3, y, 4), z)] func = lambda expr: expr**2 @@ -58,14 +61,18 @@ assert epath("/*/[2]", expr, list) == expr assert epath("/*/[0]/int", expr, func) == [((x, 1, t), 2), ((9, y, 16), z)] - assert epath("/*/[0]/Symbol", expr, func) == [((x**2, 1, t**2), 2), ((3, y**2, 4), z)] - assert epath("/*/[0]/int[1:]", expr, func) == [((x, 1, t), 2), ((3, y, 16), z)] - assert epath("/*/[0]/Symbol[1:]", expr, func) == [((x, 1, t**2), 2), ((3, y**2, 4), z)] + assert epath("/*/[0]/Symbol", expr, func) == [((x**2, 1, t**2), 2), + ((3, y**2, 4), z)] + assert epath( + "/*/[0]/int[1:]", expr, func) == [((x, 1, t), 2), ((3, y, 16), z)] + assert epath("/*/[0]/Symbol[1:]", expr, func) == [((x, 1, t**2), + 2), ((3, y**2, 4), z)] assert epath("/Symbol", x + y + z + 1, func) == x**2 + y**2 + z**2 + 1 assert epath("/*/*/Symbol", t + sin(x + 1) + cos(x + y + E), func) == \ t + sin(x**2 + 1) + cos(x**2 + y**2 + E) + def test_EPath(): assert EPath("/*/[0]")._path == "/*/[0]" assert EPath(EPath("/*/[0]"))._path == "/*/[0]" diff -Nru python3-sympy-0.7.2/sympy/simplify/tests/test_fu.py python3-sympy-0.7.3/sympy/simplify/tests/test_fu.py --- python3-sympy-0.7.2/sympy/simplify/tests/test_fu.py 1970-01-01 00:00:00.000000000 +0000 +++ python3-sympy-0.7.3/sympy/simplify/tests/test_fu.py 2013-07-13 17:53:32.000000000 +0000 @@ -0,0 +1,413 @@ +from sympy import ( + Add, Mul, S, Symbol, cos, cot, csc, pi, I, sec, sin, sqrt, tan, root, + powsimp, symbols, sinh, cosh, tanh, coth) +from sympy.simplify.fu import ( + L, TR1, TR10, TR10i, TR11, TR12, TR12i, TR13, TR14, TR15, TR16, + TR111, TR2, TR2i, TR3, TR5, TR6, TR7, TR8, TR9, TRmorrie, _TR56 as T, + hyper_as_trig, csc, fu, process_common_addends, sec, trig_split, + as_f_sign_1) +from sympy.utilities.randtest import test_numerically +from sympy.abc import a, b, c, x, y, z + + +def test_TR1(): + assert TR1(2*csc(x) + sec(x)) == 1/cos(x) + 2/sin(x) + + +def test_TR2(): + assert TR2(tan(x)) == sin(x)/cos(x) + assert TR2(cot(x)) == cos(x)/sin(x) + assert TR2(tan(tan(x) - sin(x)/cos(x))) == 0 + + +def test_TR2i(): + # just a reminder that ratios of powers only simplify if both + # numerator and denominator satisfy the condition that each + # has a positive base or an integer exponent; e.g. the following, + # at y=-1, x=1/2 gives sqrt(2)*I != -sqrt(2)*I + assert powsimp(2**x/y**x) != (2/y)**x + + assert TR2i(sin(x)/cos(x)) == tan(x) + assert TR2i(sin(x)*sin(y)/cos(x)) == tan(x)*sin(y) + assert TR2i(1/(sin(x)/cos(x))) == 1/tan(x) + assert TR2i(1/(sin(x)*sin(y)/cos(x))) == 1/tan(x)/sin(y) + + assert TR2i(sin(1)/(cos(1) + 1), half=True) == tan(S.Half) + assert TR2i(sin(2)/(cos(2) + 1), half=True) == tan(1) + assert TR2i(sin(4)/(cos(4) + 1), half=True) == tan(2) + assert TR2i(sin(5)/(cos(5) + 1), half=True) == tan(5*S.Half) + assert TR2i((cos(1) + 1)/sin(1), half=True) == 1/tan(S.Half) + assert TR2i((cos(2) + 1)/sin(2), half=True) == 1/tan(1) + assert TR2i((cos(4) + 1)/sin(4), half=True) == 1/tan(2) + assert TR2i((cos(5) + 1)/sin(5), half=True) == 1/tan(5*S.Half) + assert TR2i((cos(1) + 1)**(-a)*sin(1)**a, half=True) == tan(S.Half)**a + assert TR2i((cos(2) + 1)**(-a)*sin(2)**a, half=True) == tan(1)**a + assert TR2i((cos(4) + 1)**(-a)*sin(4)**a, half=True) == (cos(4) + 1)**(-a)*sin(4)**a + assert TR2i((cos(5) + 1)**(-a)*sin(5)**a, half=True) == (cos(5) + 1)**(-a)*sin(5)**a + assert TR2i((cos(1) + 1)**a*sin(1)**(-a), half=True) == tan(S.Half)**(-a) + assert TR2i((cos(2) + 1)**a*sin(2)**(-a), half=True) == tan(1)**(-a) + assert TR2i((cos(4) + 1)**a*sin(4)**(-a), half=True) == (cos(4) + 1)**a*sin(4)**(-a) + assert TR2i((cos(5) + 1)**a*sin(5)**(-a), half=True) == (cos(5) + 1)**a*sin(5)**(-a) + + i = symbols('i', integer=True) + assert TR2i(((cos(5) + 1)**i*sin(5)**(-i)), half=True) == tan(5*S.Half)**(-i) + assert TR2i(1/((cos(5) + 1)**i*sin(5)**(-i)), half=True) == tan(5*S.Half)**i + + +def test_TR3(): + assert TR3(cos(y - x*(y - x))) == cos(x*(x - y) + y) + assert cos(pi/2 + x) == -sin(x) + assert cos(30*pi/2 + x) == -cos(x) + + for f in (cos, sin, tan, cot, csc, sec): + i = f(3*pi/7) + j = TR3(i) + assert test_numerically(i, j) and i.func != j.func + + +def test__TR56(): + h = lambda x: 1 - x + assert T(sin(x)**3, sin, cos, h, 4, False) == sin(x)**3 + assert T(sin(x)**10, sin, cos, h, 4, False) == sin(x)**10 + assert T(sin(x)**6, sin, cos, h, 6, False) == (-cos(x)**2 + 1)**3 + assert T(sin(x)**6, sin, cos, h, 6, True) == sin(x)**6 + assert T(sin(x)**8, sin, cos, h, 10, True) == (-cos(x)**2 + 1)**4 + + +def test_TR5(): + assert TR5(sin(x)**2) == -cos(x)**2 + 1 + assert TR5(sin(x)**-2) == sin(x)**(-2) + assert TR5(sin(x)**4) == (-cos(x)**2 + 1)**2 + + +def test_TR6(): + assert TR6(cos(x)**2) == -sin(x)**2 + 1 + assert TR6(cos(x)**-2) == cos(x)**(-2) + assert TR6(cos(x)**4) == (-sin(x)**2 + 1)**2 + + +def test_TR7(): + assert TR7(cos(x)**2) == cos(2*x)/2 + S(1)/2 + assert TR7(cos(x)**2 + 1) == cos(2*x)/2 + S(3)/2 + + +def test_TR8(): + assert TR8(cos(2)*cos(3)) == cos(5)/2 + cos(1)/2 + assert TR8(cos(2)*sin(3)) == sin(5)/2 + sin(1)/2 + assert TR8(sin(2)*sin(3)) == -cos(5)/2 + cos(1)/2 + assert TR8(sin(1)*sin(2)*sin(3)) == sin(4)/4 - sin(6)/4 + sin(2)/4 + assert TR8(cos(2)*cos(3)*cos(4)*cos(5)) == \ + cos(4)/4 + cos(10)/8 + cos(2)/8 + cos(8)/8 + cos(14)/8 + \ + cos(6)/8 + S(1)/8 + assert TR8(cos(2)*cos(3)*cos(4)*cos(5)*cos(6)) == \ + cos(10)/8 + cos(4)/8 + 3*cos(2)/16 + cos(16)/16 + cos(8)/8 + \ + cos(14)/16 + cos(20)/16 + cos(12)/16 + S(1)/16 + cos(6)/8 + assert TR8(sin(3*pi/7)**2*cos(3*pi/7)**2/(16*sin(pi/7)**2)) == S(1)/64 + +def test_TR9(): + a = S(1)/2 + b = 3*a + assert TR9(a) == a + assert TR9(cos(1) + cos(2)) == 2*cos(a)*cos(b) + assert TR9(cos(1) - cos(2)) == 2*sin(a)*sin(b) + assert TR9(sin(1) - sin(2)) == -2*sin(a)*cos(b) + assert TR9(sin(1) + sin(2)) == 2*sin(b)*cos(a) + assert TR9(cos(1) + 2*sin(1) + 2*sin(2)) == cos(1) + 4*sin(b)*cos(a) + assert TR9(cos(4) + cos(2) + 2*cos(1)*cos(3)) == 4*cos(1)*cos(3) + assert TR9((cos(4) + cos(2))/cos(3)/2 + cos(3)) == 2*cos(1)*cos(2) + assert TR9(cos(3) + cos(4) + cos(5) + cos(6)) == \ + 4*cos(S(1)/2)*cos(1)*cos(S(9)/2) + assert TR9(cos(3) + cos(3)*cos(2)) == cos(3) + cos(2)*cos(3) + assert TR9(-cos(y) + cos(x*y)) == -2*sin(x*y/2 - y/2)*sin(x*y/2 + y/2) + assert TR9(-sin(y) + sin(x*y)) == 2*sin(x*y/2 - y/2)*cos(x*y/2 + y/2) + c = cos(x) + s = sin(x) + for si in ((1, 1), (1, -1), (-1, 1), (-1, -1)): + for a in ((c, s), (s, c), (cos(x), cos(x*y)), (sin(x), sin(x*y))): + args = list(zip(si, a)) + ex = Add(*[Mul(*ai) for ai in args]) + t = TR9(ex) + assert not (a[0].func == a[1].func and ( + not test_numerically(ex, t.expand(trig=True)) or t.is_Add) + or a[1].func != a[0].func and ex != t) + + +def test_TR10(): + assert TR10(cos(a + b)) == -sin(a)*sin(b) + cos(a)*cos(b) + assert TR10(sin(a + b)) == sin(a)*cos(b) + sin(b)*cos(a) + assert TR10(sin(a + b + c)) == \ + (-sin(a)*sin(b) + cos(a)*cos(b))*sin(c) + \ + (sin(a)*cos(b) + sin(b)*cos(a))*cos(c) + assert TR10(cos(a + b + c)) == \ + (-sin(a)*sin(b) + cos(a)*cos(b))*cos(c) - \ + (sin(a)*cos(b) + sin(b)*cos(a))*sin(c) + + +def test_TR10i(): + assert TR10i(cos(1)*cos(3) + sin(1)*sin(3)) == cos(2) + assert TR10i(cos(1)*cos(3) - sin(1)*sin(3)) == cos(4) + assert TR10i(cos(1)*sin(3) - sin(1)*cos(3)) == sin(2) + assert TR10i(cos(1)*sin(3) + sin(1)*cos(3)) == sin(4) + assert TR10i(cos(1)*sin(3) + sin(1)*cos(3) + 7) == sin(4) + 7 + assert TR10i(cos(1)*sin(3) + sin(1)*cos(3) + cos(3)) == cos(3) + sin(4) + assert TR10i(2*cos(1)*sin(3) + 2*sin(1)*cos(3) + cos(3)) == \ + 2*sin(4) + cos(3) + assert TR10i(cos(2)*cos(3) + sin(2)*(cos(1)*sin(2) + cos(2)*sin(1))) == \ + cos(1) + eq = (cos(2)*cos(3) + sin(2)*( + cos(1)*sin(2) + cos(2)*sin(1)))*cos(5) + sin(1)*sin(5) + assert TR10i(eq) == TR10i(eq.expand()) == cos(4) + assert TR10i(sqrt(2)*cos(x)*x + sqrt(6)*sin(x)*x) == \ + 2*sqrt(2)*x*sin(x + pi/6) + assert TR10i(cos(x)/sqrt(6) + sin(x)/sqrt(2) + + cos(x)/sqrt(6)/3 + sin(x)/sqrt(2)/3) == 4*sqrt(6)*sin(x + pi/6)/9 + assert TR10i(cos(x)/sqrt(6) + sin(x)/sqrt(2) + + cos(y)/sqrt(6)/3 + sin(y)/sqrt(2)/3) == \ + sqrt(6)*sin(x + pi/6)/3 + sqrt(6)*sin(y + pi/6)/9 + assert TR10i(cos(x) + sqrt(3)*sin(x) + 2*sqrt(3)*cos(x + pi/6)) == 4*cos(x) + assert TR10i(cos(x) + sqrt(3)*sin(x) + + 2*sqrt(3)*cos(x + pi/6) + 4*sin(x)) == 4*sqrt(2)*sin(x + pi/4) + assert TR10i(cos(2)*sin(3) + sin(2)*cos(4)) == \ + sin(2)*cos(4) + sin(3)*cos(2) + + A = Symbol('A', commutative=False) + assert TR10i(sqrt(2)*cos(x)*A + sqrt(6)*sin(x)*A) == \ + 2*sqrt(2)*sin(x + pi/6)*A + + + c = cos(x) + s = sin(x) + h = sin(y) + r = cos(y) + for si in ((1, 1), (1, -1), (-1, 1), (-1, -1)): + for a in ((c*r, s*h), (c*h, s*r)): # explicit 2-args + args = list(zip(si, a)) + ex = Add(*[Mul(*ai) for ai in args]) + t = TR10i(ex) + assert not (ex - t.expand(trig=True) or t.is_Add) + + c = cos(x) + s = sin(x) + h = sin(pi/6) + r = cos(pi/6) + for si in ((1, 1), (1, -1), (-1, 1), (-1, -1)): + for a in ((c*r, s*h), (c*h, s*r)): # induced + args = list(zip(si, a)) + ex = Add(*[Mul(*ai) for ai in args]) + t = TR10i(ex) + assert not (ex - t.expand(trig=True) or t.is_Add) + + +def test_TR11(): + + assert TR11(sin(2*x)) == 2*sin(x)*cos(x) + assert TR11(sin(4*x)) == 4*((-sin(x)**2 + cos(x)**2)*sin(x)*cos(x)) + assert TR11(sin(4*x/3)) == \ + 4*((-sin(x/3)**2 + cos(x/3)**2)*sin(x/3)*cos(x/3)) + + assert TR11(cos(2*x)) == -sin(x)**2 + cos(x)**2 + assert TR11(cos(4*x)) == \ + (-sin(x)**2 + cos(x)**2)**2 - 4*sin(x)**2*cos(x)**2 + + assert TR11(cos(2)) == cos(2) + + assert TR11(cos(3*pi/7), 2*pi/7) == -cos(2*pi/7)**2 + sin(2*pi/7)**2 + assert TR11(cos(4), 2) == -sin(2)**2 + cos(2)**2 + assert TR11(cos(6), 2) == cos(6) + assert TR11(sin(x)/cos(x/2), x/2) == 2*sin(x/2) + + +def test_TR12(): + assert TR12(tan(x + y)) == (tan(x) + tan(y))/(-tan(x)*tan(y) + 1) + assert TR12(tan(x + y + z)) ==\ + (tan(z) + (tan(x) + tan(y))/(-tan(x)*tan(y) + 1))/( + 1 - (tan(x) + tan(y))*tan(z)/(-tan(x)*tan(y) + 1)) + assert TR12(tan(x*y)) == tan(x*y) + + +def test_TR13(): + assert TR13(tan(3)*tan(2)) == -tan(2)/tan(5) - tan(3)/tan(5) + 1 + assert TR13(cot(3)*cot(2)) == 1 + cot(3)*cot(5) + cot(2)*cot(5) + assert TR13(tan(1)*tan(2)*tan(3)) == \ + (-tan(2)/tan(5) - tan(3)/tan(5) + 1)*tan(1) + assert TR13(tan(1)*tan(2)*cot(3)) == \ + (-tan(2)/tan(3) + 1 - tan(1)/tan(3))*cot(3) + + +def test_L(): + assert L(cos(x) + sin(x)) == 2 + + +def test_fu(): + + assert fu(sin(50)**2 + cos(50)**2 + sin(pi/6)) == S(3)/2 + assert fu(sqrt(6)*cos(x) + sqrt(2)*sin(x)) == 2*sqrt(2)*sin(x + pi/3) + + + eq = sin(x)**4 - cos(y)**2 + sin(y)**2 + 2*cos(x)**2 + assert fu(eq) == cos(x)**4 - 2*cos(y)**2 + 2 + + assert fu(S.Half - cos(2*x)/2) == sin(x)**2 + + assert fu(sin(a)*(cos(b) - sin(b)) + cos(a)*(sin(b) + cos(b))) == \ + sqrt(2)*sin(a + b + pi/4) + + assert fu(sqrt(3)*cos(x)/2 + sin(x)/2) == sin(x + pi/3) + + assert fu(1 - sin(2*x)**2/4 - sin(y)**2 - cos(x)**4) == \ + -cos(x)**2 + cos(y)**2 + + assert fu(cos(4*pi/9)) == sin(pi/18) + assert fu(cos(pi/9)*cos(2*pi/9)*cos(3*pi/9)*cos(4*pi/9)) == S(1)/16 + + assert fu( + tan(7*pi/18) + tan(5*pi/18) - sqrt(3)*tan(5*pi/18)*tan(7*pi/18)) == \ + -sqrt(3) + + assert fu(tan(1)*tan(2)) == tan(1)*tan(2) + + expr = Mul(*[cos(2**i) for i in range(10)]) + assert fu(expr) == sin(1024)/(1024*sin(1)) + + +def test_objective(): + assert fu(sin(x)/cos(x), measure=lambda x: x.count_ops()) == \ + tan(x) + assert fu(sin(x)/cos(x), measure=lambda x: -x.count_ops()) == \ + sin(x)/cos(x) + + +def test_process_common_addends(): + # this tests that the args are not evaluated as they are given to do + # and that key2 works when key1 is False + do = lambda x: Add(*[i**(i%2) for i in x.args]) + process_common_addends(Add(*[1, 2, 3, 4], **dict(evaluate=False)), do, + key2=lambda x: x%2, key1=False) == 1**1 + 3**1 + 2**0 + 4**0 + + +def test_trig_split(): + assert trig_split(cos(x), cos(y)) == (1, 1, 1, x, y, True) + assert trig_split(2*cos(x), -2*cos(y)) == (2, 1, -1, x, y, True) + assert trig_split(cos(x)*sin(y), cos(y)*sin(y)) == \ + (sin(y), 1, 1, x, y, True) + + assert trig_split(cos(x), -sqrt(3)*sin(x), two=True) == \ + (2, 1, -1, x, pi/6, False) + assert trig_split(cos(x), sin(x), two=True) == \ + (sqrt(2), 1, 1, x, pi/4, False) + assert trig_split(cos(x), -sin(x), two=True) == \ + (sqrt(2), 1, -1, x, pi/4, False) + assert trig_split(sqrt(2)*cos(x), -sqrt(6)*sin(x), two=True) == \ + (2*sqrt(2), 1, -1, x, pi/6, False) + assert trig_split(-sqrt(6)*cos(x), -sqrt(2)*sin(x), two=True) == \ + (-2*sqrt(2), 1, 1, x, pi/3, False) + assert trig_split(cos(x)/sqrt(6), sin(x)/sqrt(2), two=True) == \ + (sqrt(6)/3, 1, 1, x, pi/6, False) + assert trig_split(-sqrt(6)*cos(x)*sin(y), + -sqrt(2)*sin(x)*sin(y), two=True) == \ + (-2*sqrt(2)*sin(y), 1, 1, x, pi/3, False) + + assert trig_split(cos(x), sin(x)) is None + assert trig_split(cos(x), sin(z)) is None + assert trig_split(2*cos(x), -sin(x)) is None + assert trig_split(cos(x), -sqrt(3)*sin(x)) is None + assert trig_split(cos(x)*cos(y), sin(x)*sin(z)) is None + assert trig_split(cos(x)*cos(y), sin(x)*sin(y)) is None + assert trig_split(-sqrt(6)*cos(x), sqrt(2)*sin(x)*sin(y), two=True) is \ + None + + assert trig_split(sqrt(3)*sqrt(x), cos(3), two=True) is None + assert trig_split(sqrt(3)*root(x, 3), sin(3)*cos(2), two=True) is None + assert trig_split(cos(5)*cos(6), cos(7)*sin(5), two=True) is None + + +def test_TRmorrie(): + assert TRmorrie(7*Mul(*[cos(i) for i in range(10)])) == \ + 7*sin(12)*sin(16)*cos(5)*cos(7)*cos(9)/(64*sin(1)*sin(3)) + assert TRmorrie(x) == x + assert TRmorrie(2*x) == 2*x + e = cos(pi/7)*cos(2*pi/7)*cos(4*pi/7) + assert TR8(TRmorrie(e)) == -S(1)/8 + e = Mul(*[cos(2**i*pi/17) for i in range(1, 17)]) + assert TR8(TR3(TRmorrie(e))) == S(1)/65536 + + +def test_hyper_as_trig(): + from sympy.simplify.fu import _osborne, _osbornei + + eq = sinh(x)**2 + cosh(x)**2 + t, f = hyper_as_trig(eq) + assert f(fu(t)) == cosh(2*x) + assert _osborne(cosh(x)) == cos(x) + assert _osborne(sinh(x)) == I*sin(x) + assert _osborne(tanh(x)) == I*tan(x) + assert _osborne(coth(x)) == cot(x)/I + assert _osbornei(cos(x)) == cosh(x) + assert _osbornei(sin(x)) == sinh(x)/I + assert _osbornei(tan(x)) == tanh(x)/I + assert _osbornei(cot(x)) == coth(x)*I + assert _osbornei(sec(x)) == 1/cosh(x) + assert _osbornei(csc(x)) == I/sinh(x) + + +def test_TR12i(): + ta, tb, tc = [tan(i) for i in (a, b, c)] + assert TR12i((ta + tb)/(-ta*tb + 1)) == tan(a + b) + assert TR12i((ta + tb)/(ta*tb - 1)) == -tan(a + b) + assert TR12i((-ta - tb)/(ta*tb - 1)) == tan(a + b) + eq = (ta + tb)/(-ta*tb + 1)**2*(-3*ta - 3*tc)/(2*(ta*tc - 1)) + assert TR12i(eq.expand()) == \ + -3*tan(a + b)*tan(a + c)/(tan(a) + tan(b) - 1)/2 + assert TR12i(tan(x)/sin(x)) == tan(x)/sin(x) + eq = (ta + cos(2))/(-ta*tb + 1) + assert TR12i(eq) == eq + eq = (ta + tb + 2)**2/(-ta*tb + 1) + assert TR12i(eq) == eq + eq = ta/(-ta*tb + 1) + assert TR12i(eq) == eq + eq = (((ta + tb)*(a + 1)).expand())**2/(ta*tb - 1) + assert TR12i(eq) == -(a + 1)**2*tan(a + b) + + +def test_TR14(): + eq = (cos(x) - 1)*(cos(x) + 1) + ans = -sin(x)**2 + assert TR14(eq) == ans + assert TR14(1/eq) == 1/ans + assert TR14((cos(x) - 1)**2*(cos(x) + 1)**2) == ans**2 + assert TR14((cos(x) - 1)**2*(cos(x) + 1)**3) == ans**2*(cos(x) + 1) + assert TR14((cos(x) - 1)**3*(cos(x) + 1)**2) == ans**2*(cos(x) - 1) + eq = (cos(x) - 1)**y*(cos(x) + 1)**y + assert TR14(eq) == eq + eq = (cos(x) - 2)**y*(cos(x) + 1) + assert TR14(eq) == eq + eq = (tan(x) - 2)**2*(cos(x) + 1) + assert TR14(eq) == eq + i = symbols('i', integer=True) + assert TR14((cos(x) - 1)**i*(cos(x) + 1)**i) == ans**i + assert TR14((sin(x) - 1)**i*(sin(x) + 1)**i) == (-cos(x)**2)**i + # could use extraction in this case + eq = (cos(x) - 1)**(i + 1)*(cos(x) + 1)**i + assert TR14(eq) in [(cos(x) - 1)*ans**i, eq] + + assert TR14((sin(x) - 1)*(sin(x) + 1)) == -cos(x)**2 + p1 = (cos(x) + 1)*(cos(x) - 1) + p2 = (cos(y) - 1)*2*(cos(y) + 1) + p3 = (3*(cos(y) - 1))*(3*(cos(y) + 1)) + assert TR14(p1*p2*p3*(x - 1)) == -18*((x - 1)*sin(x)**2*sin(y)**4) + + +def test_TR15_16_17(): + assert TR15(1 - 1/sin(x)**2) == -cot(x)**2 + assert TR16(1 - 1/cos(x)**2) == -tan(x)**2 + assert TR111(1 - 1/tan(x)**2) == 1 - cot(x)**2 + + +def test_as_f_sign_1(): + assert as_f_sign_1(x + 1) == (1, x, 1) + assert as_f_sign_1(x - 1) == (1, x, -1) + assert as_f_sign_1(-x + 1) == (-1, x, -1) + assert as_f_sign_1(-x - 1) == (-1, x, 1) + assert as_f_sign_1(2*x + 2) == (2, x, 1) + assert as_f_sign_1(x*y - y) == (y, x, -1) + assert as_f_sign_1(-x*y + y) == (-y, x, -1) diff -Nru python3-sympy-0.7.2/sympy/simplify/tests/test_function.py python3-sympy-0.7.3/sympy/simplify/tests/test_function.py --- python3-sympy-0.7.2/sympy/simplify/tests/test_function.py 1970-01-01 00:00:00.000000000 +0000 +++ python3-sympy-0.7.3/sympy/simplify/tests/test_function.py 2013-07-13 17:53:32.000000000 +0000 @@ -0,0 +1,54 @@ +""" Unit tests for Hyper_Function""" +from sympy.core import symbols, Dummy, Tuple, S +from sympy.functions import hyper + +from sympy.simplify.hyperexpand import Hyper_Function + +def test_attrs(): + a, b = symbols('a, b', cls=Dummy) + f = Hyper_Function([2, a], [b]) + assert f.ap == Tuple(2, a) + assert f.bq == Tuple(b) + assert f.args == (Tuple(2, a), Tuple(b)) + assert f.sizes == (2, 1) + +def test_call(): + a, b, x = symbols('a, b, x', cls=Dummy) + f = Hyper_Function([2, a], [b]) + assert f(x) == hyper([2, a], [b], x) + +def test_has(): + a, b, c = symbols('a, b, c', cls=Dummy) + f = Hyper_Function([2, -a], [b]) + assert f.has(a) + assert f.has(Tuple(b)) + assert not f.has(c) + +def test_eq(): + assert Hyper_Function([1], []) == Hyper_Function([1], []) + assert (Hyper_Function([1], []) != Hyper_Function([1], [])) is False + assert Hyper_Function([1], []) != Hyper_Function([2], []) + assert Hyper_Function([1], []) != Hyper_Function([1, 2], []) + assert Hyper_Function([1], []) != Hyper_Function([1], [2]) + +def test_gamma(): + assert Hyper_Function([2, 3], [-1]).gamma == 0 + assert Hyper_Function([-2, -3], [-1]).gamma == 2 + n = Dummy(integer=True) + assert Hyper_Function([-1, n, 1], []).gamma == 1 + assert Hyper_Function([-1, -n, 1], []).gamma == 1 + p = Dummy(integer=True, positive=True) + assert Hyper_Function([-1, p, 1], []).gamma == 1 + assert Hyper_Function([-1, -p, 1], []).gamma == 2 + +def test_suitable_origin(): + assert Hyper_Function((S(1)/2,), (S(3)/2,))._is_suitable_origin() is True + assert Hyper_Function((S(1)/2,), (S(1)/2,))._is_suitable_origin() is False + assert Hyper_Function((S(1)/2,), (-S(1)/2,))._is_suitable_origin() is False + assert Hyper_Function((S(1)/2,), (0,))._is_suitable_origin() is False + assert Hyper_Function((S(1)/2,), (-1, 1,))._is_suitable_origin() is False + assert Hyper_Function((S(1)/2, 0), (1,))._is_suitable_origin() is False + assert Hyper_Function((S(1)/2, 1), + (2, -S(2)/3))._is_suitable_origin() is True + assert Hyper_Function((S(1)/2, 1), + (2, -S(2)/3, S(3)/2))._is_suitable_origin() is True diff -Nru python3-sympy-0.7.2/sympy/simplify/tests/test_hyperexpand.py python3-sympy-0.7.3/sympy/simplify/tests/test_hyperexpand.py --- python3-sympy-0.7.2/sympy/simplify/tests/test_hyperexpand.py 2012-10-17 03:02:22.000000000 +0000 +++ python3-sympy-0.7.3/sympy/simplify/tests/test_hyperexpand.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,10 +1,14 @@ + + +from random import randrange + from sympy.simplify.hyperexpand import (ShiftA, ShiftB, UnShiftA, UnShiftB, MeijerShiftA, MeijerShiftB, MeijerShiftC, MeijerShiftD, MeijerUnShiftA, MeijerUnShiftB, MeijerUnShiftC, MeijerUnShiftD, ReduceOrder, reduce_order, apply_operators, devise_plan, make_derivative_operator, Formula, - hyperexpand, IndexPair, IndexQuadruple, + hyperexpand, Hyper_Function, G_Function, reduce_order_meijer, build_hypergeometric_formula) from sympy import hyper, I, S, meijerg, Piecewise, exp_polar @@ -12,17 +16,19 @@ from sympy.abc import z, a, b, c from sympy.utilities.randtest import test_numerically as tn from sympy.utilities.pytest import XFAIL, skip, slow -from random import randrange from sympy import (cos, sin, log, exp, asin, lowergamma, atanh, besseli, gamma, sqrt, pi, erf, exp_polar) + def test_branch_bug(): assert hyperexpand(hyper((-S(1)/3, S(1)/2), (S(2)/3, S(3)/2), -z)) == \ - -z**S('1/3')*lowergamma(exp_polar(I*pi)/3, z)/5 \ - + sqrt(pi)*erf(sqrt(z))/(5*sqrt(z)) + -z**S('1/3')*lowergamma(exp_polar(I*pi)/3, z)/5 \ + + sqrt(pi)*erf(sqrt(z))/(5*sqrt(z)) assert hyperexpand(meijerg([S(7)/6, 1], [], [S(2)/3], [S(1)/6, 0], z)) == \ - 2*z**S('2/3')*(2*sqrt(pi)*erf(sqrt(z))/sqrt(z) - 2*lowergamma(S(2)/3, z)/z**S('2/3'))*gamma(S(2)/3)/gamma(S(5)/3) + 2*z**S('2/3')*(2*sqrt(pi)*erf(sqrt(z))/sqrt(z) - 2*lowergamma( + S(2)/3, z)/z**S('2/3'))*gamma(S(2)/3)/gamma(S(5)/3) + def test_hyperexpand(): # Luke, Y. L. (1969), The Special Functions and Their Approximations, @@ -33,25 +39,27 @@ assert hyperexpand(hyper([], [S.Half], -z**2/4)) == cos(z) assert hyperexpand(z*hyper([], [S('3/2')], -z**2/4)) == sin(z) assert hyperexpand(hyper([S('1/2'), S('1/2')], [S('3/2')], z**2)*z) \ - == asin(z) + == asin(z) + def can_do(ap, bq, numerical=True, div=1, lowerplane=False): from sympy import exp_polar, exp r = hyperexpand(hyper(ap, bq, z)) if r.has(hyper): return False - if not numerical: return True - repl = {} for n, a in enumerate(r.free_symbols - set([z])): repl[a] = randcplx(n)/div [a, b, c, d] = [2, -1, 3, 1] if lowerplane: [a, b, c, d] = [2, -2, 3, -1] - return tn(hyper(ap, bq, z).subs(repl), r.replace(exp_polar, exp).subs(repl), z, - a=a, b=b, c=c, d=d) + return tn( + hyper(ap, bq, z).subs(repl), + r.replace(exp_polar, exp).subs(repl), + z, a=a, b=b, c=c, d=d) + def test_roach(): # Kelly B. Roach. Meijer G Function Representations. @@ -61,19 +69,21 @@ assert can_do([-S.Half, 1, 2], [3, 4]) assert can_do([S(1)/3], [-S(2)/3, -S(1)/2, S(1)/2, 1]) assert can_do([-S(3)/2, -S(1)/2], [-S(5)/2, 1]) - assert can_do([-S(3)/2,], [-S(1)/2, S(1)/2]) # shine-integral + assert can_do([-S(3)/2, ], [-S(1)/2, S(1)/2]) # shine-integral + assert can_do([-S(3)/2, -S(1)/2], [2]) # elliptic integrals + @XFAIL def test_roach_fail(): - assert can_do([-S(3)/2, -S(1)/2], [2]) # elliptic integrals - assert can_do([-S(1)/2, 1], [S(1)/4, S(1)/2, S(3)/4]) # PFDD - assert can_do([S(3)/2], [S(5)/2, 5]) # struve function - assert can_do([-S(1)/2, S(1)/2, 1], [S(3)/2, S(5)/2]) # polylog, pfdd - assert can_do([1, 2, 3], [S(1)/2, 4]) # XXX ? - assert can_do([S(1)/2], [-S(1)/3, -S(1)/2, -S(2)/3]) # PFDD ? + assert can_do([-S(1)/2, 1], [S(1)/4, S(1)/2, S(3)/4]) # PFDD + assert can_do([S(3)/2], [S(5)/2, 5]) # struve function + assert can_do([-S(1)/2, S(1)/2, 1], [S(3)/2, S(5)/2]) # polylog, pfdd + assert can_do([1, 2, 3], [S(1)/2, 4]) # XXX ? + assert can_do([S(1)/2], [-S(1)/3, -S(1)/2, -S(2)/3]) # PFDD ? # For the long table tests, see end of file + def test_polynomial(): from sympy import oo assert hyperexpand(hyper([], [-1], z)) == oo @@ -81,54 +91,61 @@ assert hyperexpand(hyper([0, 0], [-1], z)) == 1 assert can_do([-5, -2, randcplx(), randcplx()], [-10, randcplx()]) + def test_hyperexpand_bases(): assert hyperexpand(hyper([2], [a], z)) == \ - a + z**(-a + 1)*(-a**2 + 3*a + z*(a - 1) - 2)*exp(z)*lowergamma(a - 1, z) - 1 + a + z**(-a + 1)*(-a**2 + 3*a + z*(a - 1) - 2)*exp(z)* \ + lowergamma(a - 1, z) - 1 # TODO [a+1, a-S.Half], [2*a] assert hyperexpand(hyper([1, 2], [3], z)) == -2/z - 2*log(-z + 1)/z**2 assert hyperexpand(hyper([S.Half, 2], [S(3)/2], z)) == \ - -1/(2*z - 2) + atanh(sqrt(z))/sqrt(z)/2 + -1/(2*z - 2) + atanh(sqrt(z))/sqrt(z)/2 assert hyperexpand(hyper([S(1)/2, S(1)/2], [S(5)/2], z)) == \ - (-3*z + 3)/4/(z*sqrt(-z + 1)) \ - + (6*z - 3)*asin(sqrt(z))/(4*z**(S(3)/2)) + (-3*z + 3)/4/(z*sqrt(-z + 1)) \ + + (6*z - 3)*asin(sqrt(z))/(4*z**(S(3)/2)) assert hyperexpand(hyper([1, 2], [S(3)/2], z)) == -1/(2*z - 2) \ - - asin(sqrt(z))/(sqrt(z)*(2*z - 2)*sqrt(-z + 1)) + - asin(sqrt(z))/(sqrt(z)*(2*z - 2)*sqrt(-z + 1)) assert hyperexpand(hyper([-S.Half - 1, 1, 2], [S.Half, 3], z)) == \ - sqrt(z)*(6*z/7 - S(6)/5)*atanh(sqrt(z)) \ - + (-30*z**2 + 32*z - 6)/35/z - 6*log(-z + 1)/(35*z**2) - assert hyperexpand(hyper([1+S.Half, 1, 1], [2, 2], z)) == \ - -4*log(sqrt(-z + 1)/2 + S(1)/2)/z + sqrt(z)*(6*z/7 - S(6)/5)*atanh(sqrt(z)) \ + + (-30*z**2 + 32*z - 6)/35/z - 6*log(-z + 1)/(35*z**2) + assert hyperexpand(hyper([1 + S.Half, 1, 1], [2, 2], z)) == \ + -4*log(sqrt(-z + 1)/2 + S(1)/2)/z # TODO hyperexpand(hyper([a], [2*a + 1], z)) # TODO [S.Half, a], [S(3)/2, a+1] assert hyperexpand(hyper([2], [b, 1], z)) == \ - z**(-b/2 + S(1)/2)*besseli(b - 1, 2*sqrt(z))*gamma(b) \ - + z**(-b/2 + 1)*besseli(b, 2*sqrt(z))*gamma(b) + z**(-b/2 + S(1)/2)*besseli(b - 1, 2*sqrt(z))*gamma(b) \ + + z**(-b/2 + 1)*besseli(b, 2*sqrt(z))*gamma(b) # TODO [a], [a - S.Half, 2*a] + def test_hyperexpand_parametric(): assert hyperexpand(hyper([a, S(1)/2 + a], [S(1)/2], z)) \ == (1 + sqrt(z))**(-2*a)/2 + (1 - sqrt(z))**(-2*a)/2 assert hyperexpand(hyper([a, -S(1)/2 + a], [2*a], z)) \ == 2**(2*a - 1)*((-z + 1)**(S(1)/2) + 1)**(-2*a + 1) + def test_shifted_sum(): from sympy import simplify assert simplify(hyperexpand(z**4*hyper([2], [3, S('3/2')], -z**2))) \ - == -S(1)/2 + cos(2*z)/2 + z*sin(2*z) - z**2*cos(2*z) + == z*sin(2*z) + (-z**2 + S.Half)*cos(2*z) - S.Half + -def randrat(): +def _randrat(): """ Steer clear of integers. """ return S(randrange(25) + 10)/50 + def randcplx(offset=-1): """ Polys is not good with real coefficients. """ - return randrat() + I*randrat() + I*(1 + offset) + return _randrat() + I*_randrat() + I*(1 + offset) + def test_formulae(): from sympy.simplify.hyperexpand import FormulaCollection formulae = FormulaCollection().formulae for formula in formulae: - h = hyper(formula.indices.ap, formula.indices.bq, formula.z) + h = formula.func(formula.z) rep = {} for n, sym in enumerate(formula.symbols): rep[sym] = randcplx(n) @@ -146,20 +163,23 @@ # now test the computed matrix cl = (formula.C * formula.B)[0].subs(rep).rewrite('nonrepsmall') - assert tn(closed_form.replace(exp_polar, exp), cl.replace(exp_polar, exp), z) - deriv1 = z*formula.B.applyfunc(lambda t: t.rewrite('nonrepsmall')).diff(z) + assert tn(closed_form.replace( + exp_polar, exp), cl.replace(exp_polar, exp), z) + deriv1 = z*formula.B.applyfunc(lambda t: t.rewrite( + 'nonrepsmall')).diff(z) deriv2 = formula.M * formula.B for d1, d2 in zip(deriv1, deriv2): assert tn(d1.subs(rep).replace(exp_polar, exp), d2.subs(rep).rewrite('nonrepsmall').replace(exp_polar, exp), z) + def test_meijerg_formulae(): from sympy.simplify.hyperexpand import MeijerFormulaCollection formulae = MeijerFormulaCollection().formulae for sig in formulae: for formula in formulae[sig]: - g = meijerg(formula.indices.an, formula.indices.ap, - formula.indices.bm, formula.indices.bq, + g = meijerg(formula.func.an, formula.func.ap, + formula.func.bm, formula.func.bq, formula.z) rep = {} for sym in formula.symbols: @@ -180,16 +200,20 @@ for d1, d2 in zip(deriv1, deriv2): assert tn(d1.subs(rep), d2.subs(rep), z) -def op(f): return z*f.diff(z) + +def op(f): + return z*f.diff(z) + def test_plan(): - assert devise_plan(IndexPair([0], ()), IndexPair([0], ()), z) == [] - raises(ValueError, - lambda: devise_plan(IndexPair([1], ()), IndexPair((), ()), z)) - raises(ValueError, - lambda: devise_plan(IndexPair([2], [1]), IndexPair([2], [2]), z)) - raises(KeyError, - lambda: devise_plan(IndexPair([2], []), IndexPair([S("1/2")], []), z)) + assert devise_plan(Hyper_Function([0], ()), + Hyper_Function([0], ()), z) == [] + with raises(ValueError): + devise_plan(Hyper_Function([1], ()), Hyper_Function((), ()), z) + with raises(ValueError): + devise_plan(Hyper_Function([2], [1]), Hyper_Function([2], [2]), z) + with raises(ValueError): + devise_plan(Hyper_Function([2], []), Hyper_Function([S("1/2")], []), z) # We cannot use pi/(10000 + n) because polys is insanely slow. a1, a2, b1 = [randcplx(n) for n in range(3)] @@ -197,30 +221,32 @@ h = hyper([a1, a2], [b1], z) h2 = hyper((a1 + 1, a2), [b1], z) - assert tn(apply_operators(h, devise_plan(IndexPair((a1 + 1, a2), [b1]), - IndexPair((a1, a2), [b1]), z), op), - h2, z) + assert tn(apply_operators(h, + devise_plan(Hyper_Function((a1 + 1, a2), [b1]), + Hyper_Function((a1, a2), [b1]), z), op), + h2, z) h2 = hyper((a1 + 1, a2 - 1), [b1], z) - assert tn(apply_operators(h, devise_plan(IndexPair((a1 + 1, a2 - 1), [b1]), - IndexPair((a1, a2), [b1]), z), op), - h2, z) + assert tn(apply_operators(h, + devise_plan(Hyper_Function((a1 + 1, a2 - 1), [b1]), + Hyper_Function((a1, a2), [b1]), z), op), + h2, z) + def test_plan_derivatives(): a1, a2, a3 = 1, 2, S('1/2') b1, b2 = 3, S('5/2') - h = hyper((a1, a2, a3), (b1, b2), z) - h2 = hyper((a1 + 1, a2 + 1, a3 + 2), (b1 + 1, b2 + 1), z) - ops = devise_plan(IndexPair((a1 + 1, a2 + 1, a3 + 2), (b1 + 1, b2 + 1)), - IndexPair((a1, a2, a3), (b1, b2)), z) - f = Formula((a1, a2, a3), (b1, b2), z, h, []) + h = Hyper_Function((a1, a2, a3), (b1, b2)) + h2 = Hyper_Function((a1 + 1, a2 + 1, a3 + 2), (b1 + 1, b2 + 1)) + ops = devise_plan(h2, h, z) + f = Formula(h, z, h(z), []) deriv = make_derivative_operator(f.M, z) - assert tn((apply_operators(f.C, ops, deriv)*f.B)[0], h2, z) + assert tn((apply_operators(f.C, ops, deriv)*f.B)[0], h2(z), z) + + h2 = Hyper_Function((a1, a2 - 1, a3 - 2), (b1 - 1, b2 - 1)) + ops = devise_plan(h2, h, z) + assert tn((apply_operators(f.C, ops, deriv)*f.B)[0], h2(z), z) - h2 = hyper((a1, a2 - 1, a3 - 2), (b1 - 1, b2 - 1), z) - ops = devise_plan(IndexPair((a1, a2 - 1, a3 - 2), (b1 - 1, b2 - 1)), - IndexPair((a1, a2, a3), (b1, b2)), z) - assert tn((apply_operators(f.C, ops, deriv)*f.B)[0], h2, z) def test_reduction_operators(): a1, a2, b1 = [randcplx(n) for n in range(3)] @@ -242,17 +268,18 @@ # test several step order reduction ap = (a2 + 4, a1, b1 + 1) bq = (a2, b1, b1) - nip, ops = reduce_order(IndexPair(ap, bq)) - assert nip.ap == (a1,) - assert nip.bq == (b1,) + func, ops = reduce_order(Hyper_Function(ap, bq)) + assert func.ap == (a1,) + assert func.bq == (b1,) assert tn(apply_operators(h, ops, op), hyper(ap, bq, z), z) + def test_shift_operators(): a1, a2, b1, b2, b3 = [randcplx(n) for n in range(5)] h = hyper((a1, a2), (b1, b2, b3), z) - raises(ValueError, lambda: ShiftA(0)) - raises(ValueError, lambda: ShiftB(1)) + raises(ValueError, lambda: ShiftA(0)) + raises(ValueError, lambda: ShiftB(1)) assert tn(ShiftA(a1).apply(h, op), hyper((a1 + 1, a2), (b1, b2, b3), z), z) assert tn(ShiftA(a2).apply(h, op), hyper((a1, a2 + 1), (b1, b2, b3), z), z) @@ -260,14 +287,15 @@ assert tn(ShiftB(b2).apply(h, op), hyper((a1, a2), (b1, b2 - 1, b3), z), z) assert tn(ShiftB(b3).apply(h, op), hyper((a1, a2), (b1, b2, b3 - 1), z), z) + def test_ushift_operators(): a1, a2, b1, b2, b3 = [randcplx(n) for n in range(5)] h = hyper((a1, a2), (b1, b2, b3), z) - raises(ValueError, lambda: UnShiftA((1,), (), 0, z)) - raises(ValueError, lambda: UnShiftB((), (-1,), 0, z)) - raises(ValueError, lambda: UnShiftA((1,), (0, -1, 1), 0, z)) - raises(ValueError, lambda: UnShiftB((0, 1), (1,), 0, z)) + raises(ValueError, lambda: UnShiftA((1,), (), 0, z)) + raises(ValueError, lambda: UnShiftB((), (-1,), 0, z)) + raises(ValueError, lambda: UnShiftA((1,), (0, -1, 1), 0, z)) + raises(ValueError, lambda: UnShiftB((0, 1), (1,), 0, z)) s = UnShiftA((a1, a2), (b1, b2, b3), 0, z) assert tn(s.apply(h, op), hyper((a1 - 1, a2), (b1, b2, b3), z), z) @@ -311,45 +339,47 @@ repl[a] = randcplx(n) return tn(meijerg(a1, a2, b1, b2, z).subs(repl), r.subs(repl), z) + def test_meijerg_expand(): from sympy import combsimp, simplify # from mpmath docs - assert hyperexpand(meijerg([[],[]], [[0],[]], -z)) == exp(z) + assert hyperexpand(meijerg([[], []], [[0], []], -z)) == exp(z) - assert hyperexpand(meijerg([[1,1],[]], [[1],[0]], z)) == \ + assert hyperexpand(meijerg([[1, 1], []], [[1], [0]], z)) == \ log(z + 1) - assert hyperexpand(meijerg([[1,1],[]], [[1],[1]], z)) == \ + assert hyperexpand(meijerg([[1, 1], []], [[1], [1]], z)) == \ z/(z + 1) - assert hyperexpand(meijerg([[],[]], [[S(1)/2],[0]], (z/2)**2)) \ - == sin(z)/sqrt(pi) - assert hyperexpand(meijerg([[],[]], [[0], [S(1)/2]], (z/2)**2)) \ - == cos(z)/sqrt(pi) - assert can_do_meijer([], [a], [a-1, a-S.Half], []) - assert can_do_meijer([], [], [a/2], [-a/2], False) # branches... + assert hyperexpand(meijerg([[], []], [[S(1)/2], [0]], (z/2)**2)) \ + == sin(z)/sqrt(pi) + assert hyperexpand(meijerg([[], []], [[0], [S(1)/2]], (z/2)**2)) \ + == cos(z)/sqrt(pi) + assert can_do_meijer([], [a], [a - 1, a - S.Half], []) + assert can_do_meijer([], [], [a/2], [-a/2], False) # branches... assert can_do_meijer([a], [b], [a], [b, a - 1]) # wikipedia assert hyperexpand(meijerg([1], [], [], [0], z)) == \ - Piecewise((0, abs(z) < 1), (1, abs(1/z) < 1), + Piecewise((0, abs(z) < 1), (1, abs(1/z) < 1), (meijerg([1], [], [], [0], z), True)) assert hyperexpand(meijerg([], [1], [0], [], z)) == \ - Piecewise((1, abs(z) < 1), (0, abs(1/z) < 1), + Piecewise((1, abs(z) < 1), (0, abs(1/z) < 1), (meijerg([], [1], [0], [], z), True)) # The Special Functions and their Approximations assert can_do_meijer([], [], [a + b/2], [a, a - b/2, a + S.Half]) - assert can_do_meijer([], [], [a], [b], False) # branches only agree for small z + assert can_do_meijer( + [], [], [a], [b], False) # branches only agree for small z assert can_do_meijer([], [S.Half], [a], [-a]) assert can_do_meijer([], [], [a, b], []) assert can_do_meijer([], [], [a, b], []) - assert can_do_meijer([], [], [a, a+S.Half], [b, b+S.Half]) - assert can_do_meijer([], [], [a, -a], [0, S.Half], False) # dito - assert can_do_meijer([], [], [a, a+S.Half, b, b+S.Half], []) + assert can_do_meijer([], [], [a, a + S.Half], [b, b + S.Half]) + assert can_do_meijer([], [], [a, -a], [0, S.Half], False) # dito + assert can_do_meijer([], [], [a, a + S.Half, b, b + S.Half], []) assert can_do_meijer([S.Half], [], [0], [a, -a]) - assert can_do_meijer([S.Half], [], [a], [0, -a], False) # dito + assert can_do_meijer([S.Half], [], [a], [0, -a], False) # dito assert can_do_meijer([], [a - S.Half], [a, b], [a - S.Half], False) - assert can_do_meijer([], [a+S.Half], [a+b, a-b, a], [], False) - assert can_do_meijer([a+S.Half], [], [b, 2*a-b, a], [], False) + assert can_do_meijer([], [a + S.Half], [a + b, a - b, a], [], False) + assert can_do_meijer([a + S.Half], [], [b, 2*a - b, a], [], False) # This for example is actually zero. assert can_do_meijer([], [], [], [a, b]) @@ -357,35 +387,37 @@ # Testing a bug: assert hyperexpand(meijerg([0, 2], [], [], [-1, 1], z)) == \ Piecewise((0, abs(z) < 1), - (z*(1 - 1/z**2)/2, abs(1/z) < 1), + (z/2 - 1/(2*z), abs(1/z) < 1), (meijerg([0, 2], [], [], [-1, 1], z), True)) # Test that the simplest possible answer is returned: - assert combsimp(simplify(hyperexpand(meijerg([1], [1-a], [-a/2, -a/2 + S(1)/2], - [], 1/z)))) == \ - -2*sqrt(pi)*(sqrt(z + 1) + 1)**a/a + assert combsimp(simplify(hyperexpand( + meijerg([1], [1 - a], [-a/2, -a/2 + S(1)/2], [], 1/z)))) == \ + -2*sqrt(pi)*(sqrt(z + 1) + 1)**a/a # Test that hyper is returned - assert hyperexpand(meijerg([1], [], [a], [0, 0], z)) == \ - z**a*gamma(a)*hyper((a,), (a + 1, a + 1), z*exp_polar(I*pi))/gamma(a + 1)**2 + assert hyperexpand(meijerg([1], [], [a], [0, 0], z)) == hyper( + (a,), (a + 1, a + 1), z*exp_polar(I*pi))*z**a*gamma(a)/gamma(a + 1)**2 + def test_meijerg_lookup(): from sympy import uppergamma, Si, Ci assert hyperexpand(meijerg([a], [], [b, a], [], z)) == \ - z**b*exp(z)*gamma(-a + b + 1)*uppergamma(a - b, z) + z**b*exp(z)*gamma(-a + b + 1)*uppergamma(a - b, z) assert hyperexpand(meijerg([0], [], [0, 0], [], z)) == \ - exp(z)*uppergamma(0, z) - assert can_do_meijer([a], [], [b, a+1], []) - assert can_do_meijer([a], [], [b+2, a], []) - assert can_do_meijer([a], [], [b-2, a], []) + exp(z)*uppergamma(0, z) + assert can_do_meijer([a], [], [b, a + 1], []) + assert can_do_meijer([a], [], [b + 2, a], []) + assert can_do_meijer([a], [], [b - 2, a], []) assert hyperexpand(meijerg([a], [], [a, a, a - S(1)/2], [], z)) == \ - -sqrt(pi)*z**(a - S(1)/2)*(2*cos(2*sqrt(z))*(Si(2*sqrt(z)) - pi/2) - - 2*sin(2*sqrt(z))*Ci(2*sqrt(z))) == \ - hyperexpand(meijerg([a], [], [a, a - S(1)/2, a], [], z)) == \ - hyperexpand(meijerg([a], [], [a - S(1)/2, a, a], [], z)) + -sqrt(pi)*z**(a - S(1)/2)*(2*cos(2*sqrt(z))*(Si(2*sqrt(z)) - pi/2) + - 2*sin(2*sqrt(z))*Ci(2*sqrt(z))) == \ + hyperexpand(meijerg([a], [], [a, a - S(1)/2, a], [], z)) == \ + hyperexpand(meijerg([a], [], [a - S(1)/2, a, a], [], z)) assert can_do_meijer([a - 1], [], [a + 2, a - S(3)/2, a + 1], []) + @XFAIL def test_meijerg_expand_fail(): # These basically test hyper([], [1/2 - a, 1/2 + 1, 1/2], z), @@ -400,6 +432,7 @@ assert can_do_meijer([], [], [a, b + S(1)/2, b, 2*b - a]) assert can_do_meijer([S.Half], [], [-a, a], [0]) + def test_meijerg(): # carefully set up the parameters. # NOTE: this used to fail sometimes. I believe it is fixed, but if you @@ -422,20 +455,22 @@ assert tn(ReduceOrder.meijer_plus(a2 - 1, a2 + 2).apply(g, op), g2, z) g2 = meijerg([a1], [a3, a4, b2 - 1], [b1, b2 + 2], [b3, b4], z) - assert tn(ReduceOrder.meijer_minus(b2 + 2, b2 - 1).apply(g, op), g2, z, tol=1e-6) + assert tn(ReduceOrder.meijer_minus( + b2 + 2, b2 - 1).apply(g, op), g2, z, tol=1e-6) # test several-step reduction an = [a1, a2] bq = [b3, b4, a2 + 1] ap = [a3, a4, b2 - 1] bm = [b1, b2 + 1] - niq, ops = reduce_order_meijer(IndexQuadruple(an, ap, bm, bq)) + niq, ops = reduce_order_meijer(G_Function(an, ap, bm, bq)) assert niq.an == (a1,) assert set(niq.ap) == set([a3, a4]) assert niq.bm == (b1,) assert set(niq.bq) == set([b3, b4]) assert tn(apply_operators(g, ops, op), meijerg(an, ap, bm, bq, z), z) + def test_meijerg_shift_operators(): # carefully set up the parameters. XXX this still fails sometimes a1, a2, a3, a4, a5, b1, b2, b3, b4, b5 = \ @@ -452,16 +487,21 @@ meijerg([a1], [a3 - 1, a4], [b1], [b3, b4], z), z) s = MeijerUnShiftA([a1], [a3, a4], [b1], [b3, b4], 0, z) - assert tn(s.apply(g, op), meijerg([a1], [a3, a4], [b1 - 1], [b3, b4], z), z) + assert tn( + s.apply(g, op), meijerg([a1], [a3, a4], [b1 - 1], [b3, b4], z), z) s = MeijerUnShiftC([a1], [a3, a4], [b1], [b3, b4], 0, z) - assert tn(s.apply(g, op), meijerg([a1], [a3, a4], [b1], [b3 - 1, b4], z), z) + assert tn( + s.apply(g, op), meijerg([a1], [a3, a4], [b1], [b3 - 1, b4], z), z) s = MeijerUnShiftB([a1], [a3, a4], [b1], [b3, b4], 0, z) - assert tn(s.apply(g, op), meijerg([a1 + 1], [a3, a4], [b1], [b3, b4], z), z) + assert tn( + s.apply(g, op), meijerg([a1 + 1], [a3, a4], [b1], [b3, b4], z), z) s = MeijerUnShiftD([a1], [a3, a4], [b1], [b3, b4], 0, z) - assert tn(s.apply(g, op), meijerg([a1], [a3 + 1, a4], [b1], [b3, b4], z), z) + assert tn( + s.apply(g, op), meijerg([a1], [a3 + 1, a4], [b1], [b3, b4], z), z) + def test_meijerg_confluence(): def t(m, a, b): @@ -481,9 +521,10 @@ return True assert t(meijerg([], [1, 1], [0, 0], [], z), -log(z), 0) - assert t(meijerg([], [3, 1], [0, 0], [], z), -z**2/4 + z - log(z)/2 - S(3)/4, 0) + assert t(meijerg( + [], [3, 1], [0, 0], [], z), -z**2/4 + z - log(z)/2 - S(3)/4, 0) assert t(meijerg([], [3, 1], [-1, 0], [], z), - z**2/12 -z/2 + log(z)/2 + S(1)/4 + 1/(6*z), 0) + z**2/12 - z/2 + log(z)/2 + S(1)/4 + 1/(6*z), 0) assert t(meijerg([], [1, 1, 1, 1], [0, 0, 0, 0], [], z), -log(z)**3/6, 0) assert t(meijerg([1, 1], [], [], [0, 0], z), 0, -log(1/z)) assert t(meijerg([1, 1], [2, 2], [1, 1], [0, 0], z), @@ -501,30 +542,29 @@ assert u([1, 1], [2, 2, 5], [1, 1, 6], [0, 0]) assert u([1, 1], [2, 2, 5], [1, 1, 6], [0]) + def test_lerchphi(): from sympy import combsimp, exp_polar, polylog, log, lerchphi assert hyperexpand(hyper([1, a], [a + 1], z)/a) == lerchphi(z, 1, a) - assert hyperexpand(hyper([1, a, a], [a + 1, a + 1], z)/a**2) == lerchphi(z, 2, a) + assert hyperexpand( + hyper([1, a, a], [a + 1, a + 1], z)/a**2) == lerchphi(z, 2, a) assert hyperexpand(hyper([1, a, a, a], [a + 1, a + 1, a + 1], z)/a**3) == \ - lerchphi(z, 3, a) - assert hyperexpand(hyper([1] + [a]*10, [a + 1]*10, z)/a**10) \ - == lerchphi(z, 10, a) - assert combsimp(hyperexpand(meijerg([0, 1-a], [], [0], [-a], - exp_polar(-I*pi)*z))) == \ - lerchphi(z, 1, a) - assert combsimp(hyperexpand(meijerg([0, 1-a, 1-a], [], [0], [-a, -a], - exp_polar(-I*pi)*z))) == \ - lerchphi(z, 2, a) - assert combsimp(hyperexpand(meijerg([0, 1-a, 1-a, 1-a], [], [0], [-a, -a, -a], - exp_polar(-I*pi)*z))) == \ - lerchphi(z, 3, a) + lerchphi(z, 3, a) + assert hyperexpand(hyper([1] + [a]*10, [a + 1]*10, z)/a**10) == \ + lerchphi(z, 10, a) + assert combsimp(hyperexpand(meijerg([0, 1 - a], [], [0], + [-a], exp_polar(-I*pi)*z))) == lerchphi(z, 1, a) + assert combsimp(hyperexpand(meijerg([0, 1 - a, 1 - a], [], [0], + [-a, -a], exp_polar(-I*pi)*z))) == lerchphi(z, 2, a) + assert combsimp(hyperexpand(meijerg([0, 1 - a, 1 - a, 1 - a], [], [0], + [-a, -a, -a], exp_polar(-I*pi)*z))) == lerchphi(z, 3, a) assert hyperexpand(z*hyper([1, 1], [2], z)) == -log(1 + -z) assert hyperexpand(z*hyper([1, 1, 1], [2, 2], z)) == polylog(2, z) assert hyperexpand(z*hyper([1, 1, 1, 1], [2, 2, 2], z)) == polylog(3, z) assert hyperexpand(hyper([1, a, 1 + S(1)/2], [a + 1, S(1)/2], z)) == \ - -2*a/(z - 1) + (-2*a**2 + a)*lerchphi(z, 1, a) + -2*a/(z - 1) + (-2*a**2 + a)*lerchphi(z, 1, a) # Now numerical tests. These make sure reductions etc are carried out # correctly @@ -538,7 +578,8 @@ # reduction of order for lerchphi # XXX lerchphi in mpmath is flaky - assert can_do([1, a, a, a, b + 5], [a + 1, a + 1, a + 1, b], numerical=False) + assert can_do( + [1, a, a, a, b + 5], [a + 1, a + 1, a + 1, b], numerical=False) # test a bug from sympy import Abs @@ -546,13 +587,15 @@ [S(3)/2, S(3)/2, S(3)/2], S(1)/4)) == \ Abs(-polylog(3, exp_polar(I*pi)/2) + polylog(3, S(1)/2)) + def test_partial_simp(): # First test that hypergeometric function formulae work. a, b, c, d, e = [randcplx() for _ in range(5)] - for idxp in [IndexPair([a, b, c], [d, e]), IndexPair([], [a, b, c, d, e])]: - f = build_hypergeometric_formula(idxp) + for func in [Hyper_Function([a, b, c], [d, e]), + Hyper_Function([], [a, b, c, d, e])]: + f = build_hypergeometric_formula(func) z = f.z - assert f.closed_form == hyper(idxp.ap, idxp.bq, z) + assert f.closed_form == func(z) deriv1 = f.B.diff(z)*z deriv2 = f.M*f.B for func1, func2 in zip(deriv1, deriv2): @@ -561,34 +604,39 @@ # Now test that formulae are partially simplified. from sympy.abc import a, b, z assert hyperexpand(hyper([3, a], [1, b], z)) == \ - (-a*b/2 + a*z/2 + 2*a)*hyper([a + 1], [b], z) \ - + (a*b/2 - 2*a + 1)*hyper([a], [b], z) - assert tn(hyperexpand(hyper([3, d], [1, e], z)), hyper([3, d], [1, e], z), z) + (-a*b/2 + a*z/2 + 2*a)*hyper([a + 1], [b], z) \ + + (a*b/2 - 2*a + 1)*hyper([a], [b], z) + assert tn( + hyperexpand(hyper([3, d], [1, e], z)), hyper([3, d], [1, e], z), z) assert hyperexpand(hyper([3], [1, a, b], z)) == \ - hyper((), (a, b), z) \ - + z*hyper((), (a + 1, b), z)/(2*a) \ - - z*(b - 4)*hyper((), (a + 1, b + 1), z)/(2*a*b) - assert tn(hyperexpand(hyper([3], [1, d, e], z)), hyper([3], [1, d, e], z), z) + hyper((), (a, b), z) \ + + z*hyper((), (a + 1, b), z)/(2*a) \ + - z*(b - 4)*hyper((), (a + 1, b + 1), z)/(2*a*b) + assert tn( + hyperexpand(hyper([3], [1, d, e], z)), hyper([3], [1, d, e], z), z) + def test_hyperexpand_special(): assert hyperexpand(hyper([a, b], [c], 1)) == \ - gamma(c)*gamma(c - a - b)/gamma(c - a)/gamma(c - b) + gamma(c)*gamma(c - a - b)/gamma(c - a)/gamma(c - b) assert hyperexpand(hyper([a, b], [1 + a - b], -1)) == \ - gamma(1 + a/2)*gamma(1 + a - b)/gamma(1 + a)/gamma(1 + a/2 - b) + gamma(1 + a/2)*gamma(1 + a - b)/gamma(1 + a)/gamma(1 + a/2 - b) assert hyperexpand(hyper([a, b], [1 + b - a], -1)) == \ - gamma(1 + b/2)*gamma(1 + b - a)/gamma(1 + b)/gamma(1 + b/2 - a) + gamma(1 + b/2)*gamma(1 + b - a)/gamma(1 + b)/gamma(1 + b/2 - a) assert hyperexpand(meijerg([1 - z - a/2], [1 - z + a/2], [b/2], [-b/2], 1)) == \ - gamma(1 - 2*z)*gamma(z + a/2 + b/2)/gamma(1 - z + a/2 - b/2) \ - /gamma(1 - z - a/2 + b/2)/gamma(1 - z + a/2 + b/2) + gamma(1 - 2*z)*gamma(z + a/2 + b/2)/gamma(1 - z + a/2 - b/2) \ + /gamma(1 - z - a/2 + b/2)/gamma(1 - z + a/2 + b/2) assert hyperexpand(hyper([a], [b], 0)) == 0 assert hyper([a], [b], 0) != 0 + def test_Mod1_behavior(): from sympy import Symbol, simplify, lowergamma n = Symbol('n', integer=True) # Note: this should not hang. assert simplify(hyperexpand(meijerg([1], [], [n + 1], [0], z))) == \ - lowergamma(n + 1, z) + lowergamma(n + 1, z) + @slow def test_prudnikov_misc(): @@ -603,13 +651,14 @@ assert can_do([a], [a + S.Half, 2*a]) assert can_do([a], [a + S.Half, 2*a + 1]) assert can_do([a], [a + S.Half, 2*a - 1]) - assert can_do([S.Half], [b, 2-b]) - assert can_do([S.Half], [b, 3-b]) + assert can_do([S.Half], [b, 2 - b]) + assert can_do([S.Half], [b, 3 - b]) assert can_do([1], [2, b]) - assert can_do([a, a+S.Half], [2*a, b, 2*a - b + 1]) - assert can_do([a, a+S.Half], [S.Half, 2*a, 2*a + S.Half]) - assert can_do([a], [a+1], lowerplane=True) # lowergamma + assert can_do([a, a + S.Half], [2*a, b, 2*a - b + 1]) + assert can_do([a, a + S.Half], [S.Half, 2*a, 2*a + S.Half]) + assert can_do([a], [a + 1], lowerplane=True) # lowergamma + @slow def test_prudnikov_1(): @@ -631,13 +680,14 @@ assert can_do([a, a + S(1)/2], [S(3)/2]) assert can_do([a, a/2 + 1], [a/2]) assert can_do([1, b], [2]) - assert can_do([1, b], [b + 1], numerical=False) # Lerch Phi + assert can_do([1, b], [b + 1], numerical=False) # Lerch Phi # NOTE: branches are complicated for |z| > 1 assert can_do([a], [2*a]) assert can_do([a], [2*a + 1]) assert can_do([a], [2*a - 1]) + @slow def test_prudnikov_2(): h = S.Half @@ -655,6 +705,7 @@ for m in [1, 2, 3, 4]: assert can_do([p, n], [m]) + @slow def test_prudnikov_3(): h = S.Half @@ -681,6 +732,7 @@ for m in [2, 3, 4]: assert can_do([p, m], [n]) + @slow def test_prudnikov_5(): h = S.Half @@ -704,6 +756,7 @@ for s in [1, 2, 3]: assert can_do([-h, p, q], [r, s]) + @slow def test_prudnikov_6(): h = S.Half @@ -729,6 +782,7 @@ # pages 435 to 457 contain more PFDD and stuff like this + @slow def test_prudnikov_7(): assert can_do([3], [6]) @@ -736,10 +790,11 @@ h = S.Half for n in [h, 3*h, 5*h, 7*h]: assert can_do([-h], [n]) - for m in [-h, h, 1, 3*h, 2, 5*h, 3, 7*h, 4]: # HERE + for m in [-h, h, 1, 3*h, 2, 5*h, 3, 7*h, 4]: # HERE for n in [-h, h, 3*h, 5*h, 7*h, 1, 2, 3, 4]: assert can_do([m], [n]) + @slow def test_prudnikov_8(): h = S.Half @@ -747,7 +802,7 @@ # 7.12.2 for a in [1, 2, 3]: for b in [1, 2, 3]: - for c in range(1, a+1): + for c in range(1, a + 1): for d in [h, 1, 3*h, 2, 5*h, 3]: assert can_do([a, b], [c, d]) for b in [3*h, 5*h]: @@ -766,6 +821,7 @@ if c <= b: assert can_do([a, b], [c, d]) + @slow def test_prudnikov_9(): # 7.13.1 [we have a general formula ... so this is a bit pointless] @@ -774,6 +830,7 @@ for i in range(5): assert can_do([], [-(2*S(i) + 1)/2]) + @slow def test_prudnikov_10(): # 7.14.2 @@ -796,28 +853,31 @@ for m in [h, 1, 2, 5*h, 3, 7*h, 4]: assert can_do([7*h], [5*h, m]) - assert can_do([-S(1)/2], [S(1)/2, S(1)/2]) # shine-integral shi + assert can_do([-S(1)/2], [S(1)/2, S(1)/2]) # shine-integral shi + @slow def test_prudnikov_11(): # 7.15 - assert can_do([a, a+S.Half], [2*a, b, 2*a - b]) - assert can_do([a, a+S.Half], [S(3)/2, 2*a, 2*a - S(1)/2]) + assert can_do([a, a + S.Half], [2*a, b, 2*a - b]) + assert can_do([a, a + S.Half], [S(3)/2, 2*a, 2*a - S(1)/2]) assert can_do([S(1)/4, S(3)/4], [S(1)/2, S(1)/2, 1]) assert can_do([S(5)/4, S(3)/4], [S(3)/2, S(1)/2, 2]) assert can_do([S(5)/4, S(3)/4], [S(3)/2, S(3)/2, 1]) assert can_do([S(5)/4, S(7)/4], [S(3)/2, S(5)/2, 2]) - assert can_do([1, 1], [S(3)/2, 2, 2]) # cosh-integral chi + assert can_do([1, 1], [S(3)/2, 2, 2]) # cosh-integral chi + @slow def test_prudnikov_12(): # 7.16 - assert can_do([], [a, a + S.Half, 2*a], False) # branches only agree for some z! - assert can_do([], [a, a + S.Half, 2*a+1], False) # dito - assert can_do([], [S.Half, a, a+S.Half]) - assert can_do([], [S(3)/2, a, a+S.Half]) + assert can_do( + [], [a, a + S.Half, 2*a], False) # branches only agree for some z! + assert can_do([], [a, a + S.Half, 2*a + 1], False) # dito + assert can_do([], [S.Half, a, a + S.Half]) + assert can_do([], [S(3)/2, a, a + S.Half]) assert can_do([], [S(1)/4, S(1)/2, S(3)/4]) assert can_do([], [S(1)/2, S(1)/2, 1]) @@ -829,9 +889,19 @@ assert can_do([], [S(5)/4, S(3)/2, S(7)/4]) assert can_do([], [2, S(3)/2, S(3)/2]) + +def test_prudnikov_2F1(): + h = S.Half + # Elliptic integrals + for p in [-h, h]: + for m in [h, 3*h, 5*h, 7*h]: + for n in [1, 2, 3, 4]: + assert can_do([p, m], [n]) + + @XFAIL def test_prudnikov_fail_2F1(): - assert can_do([a, b], [b + 1]) # incomplete beta function + assert can_do([a, b], [b + 1]) # incomplete beta function assert can_do([-1, b], [c]) # Poly. also -2, -3 etc # TODO polys @@ -854,13 +924,6 @@ assert can_do([1, b], [c]) assert can_do([1, b], [S(3)/2]) - h = S.Half - # Elliptic integrals - for p in [-h, h]: - for m in [h, 3*h, 5*h, 7*h]: - for n in [1, 2, 3, 4]: - assert can_do([p, m], [n]) - assert can_do([S(1)/4, S(3)/4], [1]) # PFDD @@ -890,6 +953,7 @@ assert can_do([o/6*5, 1], [o/6*17]) assert can_do([o/8*7, 1], [o/8*15]) + @XFAIL def test_prudnikov_fail_3F2(): assert can_do([a, a + S(1)/3, a + S(2)/3], [S(1)/3, S(2)/3]) @@ -897,10 +961,10 @@ assert can_do([a, a + S(1)/3, a + S(2)/3], [S(4)/3, S(5)/3]) # page 421 - assert can_do([a, a + S(1)/3, a + S(2)/3], [3*a/2, (3*a+1)/2]) + assert can_do([a, a + S(1)/3, a + S(2)/3], [3*a/2, (3*a + 1)/2]) # pages 422 ... - assert can_do([-S.Half, S.Half, S.Half], [1, 1]) # elliptic integrals + assert can_do([-S.Half, S.Half, S.Half], [1, 1]) # elliptic integrals assert can_do([-S.Half, S.Half, 1], [S(3)/2, S(3)/2]) # TODO LOTS more @@ -920,29 +984,30 @@ # 7.11.2 # 7.12.1 - assert can_do([1, a], [b, 1 - 2*a + b]) # ??? + assert can_do([1, a], [b, 1 - 2*a + b]) # ??? # 7.14.2 - assert can_do([-S(1)/2], [S(1)/2, 1]) # struve + assert can_do([-S(1)/2], [S(1)/2, 1]) # struve assert can_do([1], [S(1)/2, S(1)/2]) # struve - assert can_do([S(1)/4], [S(1)/2, S(5)/4]) # PFDD - assert can_do([S(3)/4], [S(3)/2, S(7)/4]) # PFDD - assert can_do([1], [S(1)/4, S(3)/4]) # PFDD - assert can_do([1], [S(3)/4, S(5)/4]) # PFDD - assert can_do([1], [S(5)/4, S(7)/4]) # PFDD + assert can_do([S(1)/4], [S(1)/2, S(5)/4]) # PFDD + assert can_do([S(3)/4], [S(3)/2, S(7)/4]) # PFDD + assert can_do([1], [S(1)/4, S(3)/4]) # PFDD + assert can_do([1], [S(3)/4, S(5)/4]) # PFDD + assert can_do([1], [S(5)/4, S(7)/4]) # PFDD # TODO LOTS more # 7.15.2 - assert can_do([S(1)/2, 1], [S(3)/4, S(5)/4, S(3)/2]) # PFDD - assert can_do([S(1)/2, 1], [S(7)/4, S(5)/4, S(3)/2]) # PFDD + assert can_do([S(1)/2, 1], [S(3)/4, S(5)/4, S(3)/2]) # PFDD + assert can_do([S(1)/2, 1], [S(7)/4, S(5)/4, S(3)/2]) # PFDD # 7.16.1 - assert can_do([], [S(1)/3, S(2/3)]) # PFDD - assert can_do([], [S(2)/3, S(4/3)]) # PFDD - assert can_do([], [S(5)/3, S(4/3)]) # PFDD + assert can_do([], [S(1)/3, S(2/3)]) # PFDD + assert can_do([], [S(2)/3, S(4/3)]) # PFDD + assert can_do([], [S(5)/3, S(4/3)]) # PFDD # XXX this does not *evaluate* right?? - assert can_do([], [a, a + S.Half, 2*a-1]) + assert can_do([], [a, a + S.Half, 2*a - 1]) + def test_bug(): h = hyper([-1, 1], [z], -1) diff -Nru python3-sympy-0.7.2/sympy/simplify/tests/test_rewrite.py python3-sympy-0.7.3/sympy/simplify/tests/test_rewrite.py --- python3-sympy-0.7.2/sympy/simplify/tests/test_rewrite.py 2012-10-17 03:02:22.000000000 +0000 +++ python3-sympy-0.7.3/sympy/simplify/tests/test_rewrite.py 2013-07-13 17:53:32.000000000 +0000 @@ -2,7 +2,8 @@ Matrix, Eq, RootSum, Lambda) from sympy.integrals import integrate -x,y,z,n = symbols('x,y,z,n') +x, y, z, n = symbols('x,y,z,n') + def test_has(): assert cot(x).has(x) @@ -12,12 +13,14 @@ assert sin(x).has(sin) assert not sin(x).has(cot) + def test_sin_exp_rewrite(): - assert sin(x).rewrite(sin, exp) == -I/2*(exp(I*x)-exp(-I*x)) + assert sin(x).rewrite(sin, exp) == -I/2*(exp(I*x) - exp(-I*x)) assert sin(x).rewrite(sin, exp).rewrite(exp, sin) == sin(x) assert cos(x).rewrite(cos, exp).rewrite(exp, cos) == cos(x) - assert (sin(5*y) - sin(2*x)).rewrite(sin, exp).rewrite(exp, sin) == sin(5*y) - sin(2*x) - assert sin(x+y).rewrite(sin, exp).rewrite(exp, sin) == sin(x+y) - assert cos(x+y).rewrite(cos, exp).rewrite(exp, cos) == cos(x+y) + assert (sin(5*y) - sin( + 2*x)).rewrite(sin, exp).rewrite(exp, sin) == sin(5*y) - sin(2*x) + assert sin(x + y).rewrite(sin, exp).rewrite(exp, sin) == sin(x + y) + assert cos(x + y).rewrite(cos, exp).rewrite(exp, cos) == cos(x + y) # This next test currently passes... not clear whether it should or not? assert cos(x).rewrite(cos, exp).rewrite(exp, sin) == cos(x) diff -Nru python3-sympy-0.7.2/sympy/simplify/tests/test_simplify.py python3-sympy-0.7.3/sympy/simplify/tests/test_simplify.py --- python3-sympy-0.7.2/sympy/simplify/tests/test_simplify.py 2012-10-17 03:02:22.000000000 +0000 +++ python3-sympy-0.7.3/sympy/simplify/tests/test_simplify.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,18 +1,21 @@ from sympy import ( - Add, Derivative, E, Eq, Float, Function, GoldenRatio, I, Integer, - Integral, Matrix, Mul, O, Rational, S, Symbol, Wild, acos, atan, - besselsimp, binomial, collect, collect_const, combsimp, cos, cosh, - cot, coth, count_ops, diff, erf, exp, expand, factor, factorial, - fraction, gamma, hyper, hyper, hypersimp, integrate, log, logcombine, - nsimplify, oo, pi, posify, powdenest, powsimp, radsimp, ratsimp, - ratsimpmodprime, rcollect, separatevars, signsimp, simplify, - sin, sinh, solve, sqrt, symbols, sympify, tan, tanh, trigsimp, Dummy, - Subs, polarify, exp_polar, polar_lift, Piecewise) + acos, Add, atan, besselsimp, binomial, collect, collect_const, combsimp, + cos, cosh, cot, coth, count_ops, Derivative, diff, Dummy, E, Eq, erf, exp, + exp_polar, expand, exptrigsimp, factor, factorial, FallingFactorial, Float, + fraction, Function, gamma, GoldenRatio, hyper, hyper, hypersimp, I, + Integer, Integral, integrate, log, logcombine, Matrix, Mul, nsimplify, O, + oo, pi, Piecewise, polar_lift, polarify, posify, powdenest, powsimp, + radsimp, Rational, ratsimp, ratsimpmodprime, rcollect, RisingFactorial, + root, S, separatevars, signsimp, simplify, sin, sinh, solve, sqrt, Subs, + Symbol, symbols, sympify, tan, tanh, trigsimp, Wild, Basic, ordered, + expand_multinomial, denom) from sympy.core.mul import _keep_coeff -from sympy.simplify.simplify import fraction_expand -from sympy.utilities.pytest import XFAIL +from sympy.simplify.simplify import ( + collect_sqrt, fraction_expand, _unevaluated_Add, nthroot) +from sympy.utilities.pytest import XFAIL, slow + +from sympy.abc import x, y, z, t, a, b, c, d, e, f, g, h, i, k -from sympy.abc import x, y, z, t, a, b, c, d, e, k def test_ratsimp(): f, g = 1/x + 1/y, (x + y)/(x*y) @@ -31,7 +34,8 @@ assert f != g and ratsimp(f) == g - f = (a*c*x*y + a*c*z - b*d*x*y - b*d*z - b*t*x*y - b*t*x - b*t*z + e*x)/(x*y + z) + f = (a*c*x*y + a*c*z - b*d*x*y - b*d*z - b*t*x*y - b*t*x - b*t*z + + e*x)/(x*y + z) G = [a*c - b*d - b*t + (-b*t*x + e*x)/(x*y + z), a*c - b*d - b*t - ( b*t*x - e*x)/(x*y + z)] @@ -48,6 +52,7 @@ assert ratsimp(f) == A*B/8 - A*C/8 - A/(4*erf(x) - 4) + def test_ratsimpmodprime(): a = y**5 + x + y b = x - y @@ -59,13 +64,13 @@ b = x + y**2 - y - 1 F = [x*y - 1] assert ratsimpmodprime(a/b, F, x, y, order='lex') == \ - (x - y - 1)/(x - y) + (1 + y - x)/(y - x) a = 5*x**3 + 21*x**2 + 4*x*y + 23*x + 12*y + 15 b = 7*x**3 - y*x**2 + 31*x**2 + 2*x*y + 15*y + 37*x + 21 F = [x**2 + y**2 - 1] assert ratsimpmodprime(a/b, F, x, y, order='lex') == \ - (3*x + 4*y + 5)/(5*x + 5*y + 7) + (1 + 5*y - 5*x)/(8*y - 6*x) a = x*y - x - 2*y + 4 b = x + y**2 - 2*y @@ -73,6 +78,11 @@ assert ratsimpmodprime(a/b, F, x, y, order='lex') == \ Rational(2, 5) + # Test a bug where denominators would be dropped + assert ratsimpmodprime(x, [y - 2*x], order='lex') == \ + y/2 + + def test_trigsimp1(): x, y = symbols('x,y') @@ -83,12 +93,11 @@ assert trigsimp(1/cos(x)**2 - 1) == tan(x)**2 assert trigsimp(1/cos(x)**2 - tan(x)**2) == 1 assert trigsimp(1 + cot(x)**2) == 1/sin(x)**2 - assert trigsimp(1/sin(x)**2 - 1) == cot(x)**2 + assert trigsimp(1/sin(x)**2 - 1) == 1/tan(x)**2 assert trigsimp(1/sin(x)**2 - cot(x)**2) == 1 assert trigsimp(5*cos(x)**2 + 5*sin(x)**2) == 5 - assert trigsimp(5*cos(x/2)**2 + 2*sin(x/2)**2) in \ - [2 + 3*cos(x/2)**2, 5 - 3*sin(x/2)**2] + assert trigsimp(5*cos(x/2)**2 + 2*sin(x/2)**2) == 3*cos(x)/2 + S(7)/2 assert trigsimp(sin(x)/cos(x)) == tan(x) assert trigsimp(2*tan(x)*cos(x)) == 2*sin(x) @@ -101,18 +110,34 @@ assert trigsimp(cos(x + y) + cos(x - y)) == 2*cos(x)*cos(y) assert trigsimp(cos(x + y) - cos(x - y)) == -2*sin(x)*sin(y) assert ratsimp(trigsimp(tan(x + y) - tan(x)/(1 - tan(x)*tan(y)))) == \ - -tan(y)/(tan(x)*tan(y) -1) + sin(y)/(-sin(y)*tan(x) + cos(y)) # -tan(y)/(tan(x)*tan(y) - 1) assert trigsimp(sinh(x + y) + sinh(x - y)) == 2*sinh(x)*cosh(y) assert trigsimp(sinh(x + y) - sinh(x - y)) == 2*sinh(y)*cosh(x) assert trigsimp(cosh(x + y) + cosh(x - y)) == 2*cosh(x)*cosh(y) assert trigsimp(cosh(x + y) - cosh(x - y)) == 2*sinh(x)*sinh(y) assert ratsimp(trigsimp(tanh(x + y) - tanh(x)/(1 + tanh(x)*tanh(y)))) == \ - tanh(y)/(tanh(x)*tanh(y) + 1) + sinh(y)/(sinh(y)*tanh(x) + cosh(y)) assert trigsimp(cos(0.12345)**2 + sin(0.12345)**2) == 1 e = 2*sin(x)**2 + 2*cos(x)**2 - assert trigsimp(log(e), deep=True) == log(2) + assert trigsimp(log(e)) == log(2) + + +def test_trigsimp1a(): + assert trigsimp(sin(2)**2*cos(3)*exp(2)/cos(2)**2) == tan(2)**2*cos(3)*exp(2) + assert trigsimp(tan(2)**2*cos(3)*exp(2)*cos(2)**2) == sin(2)**2*cos(3)*exp(2) + assert trigsimp(cot(2)*cos(3)*exp(2)*sin(2)) == cos(3)*exp(2)*cos(2) + assert trigsimp(tan(2)*cos(3)*exp(2)/sin(2)) == cos(3)*exp(2)/cos(2) + assert trigsimp(cot(2)*cos(3)*exp(2)/cos(2)) == cos(3)*exp(2)/sin(2) + assert trigsimp(cot(2)*cos(3)*exp(2)*tan(2)) == cos(3)*exp(2) + assert trigsimp(sinh(2)*cos(3)*exp(2)/cosh(2)) == tanh(2)*cos(3)*exp(2) + assert trigsimp(tanh(2)*cos(3)*exp(2)*cosh(2)) == sinh(2)*cos(3)*exp(2) + assert trigsimp(coth(2)*cos(3)*exp(2)*sinh(2)) == cosh(2)*cos(3)*exp(2) + assert trigsimp(tanh(2)*cos(3)*exp(2)/sinh(2)) == cos(3)*exp(2)/cosh(2) + assert trigsimp(coth(2)*cos(3)*exp(2)/cosh(2)) == cos(3)*exp(2)/sinh(2) + assert trigsimp(coth(2)*cos(3)*exp(2)*tanh(2)) == cos(3)*exp(2) + def test_trigsimp2(): x, y = symbols('x,y') @@ -120,16 +145,14 @@ recursive=True) == 1 assert trigsimp(sin(x)**2*sin(y)**2 + sin(x)**2*cos(y)**2 + cos(x)**2, recursive=True) == 1 - -def test_trigsimp_deep(): - x, y = symbols('x,y') - assert trigsimp(Subs(x, x, sin(y)**2+cos(y)**2), deep=True) == Subs(x, x, 1) - assert simplify(Subs(x, x, sin(y)**2+cos(y)**2)) == Subs(x, x, 1) + assert trigsimp( + Subs(x, x, sin(y)**2 + cos(y)**2)) == Subs(x, x, 1) def test_issue1274(): x = Symbol("x") - assert abs(trigsimp(2.0*sin(x)**2 + 2.0*cos(x)**2)-2.0) < 1e-10 + assert abs(trigsimp(2.0*sin(x)**2 + 2.0*cos(x)**2) - 2.0) < 1e-10 + def test_trigsimp3(): x, y = symbols('x,y') @@ -144,10 +167,154 @@ assert trigsimp(tan(x)) == trigsimp(sin(x)/cos(x)) + +def test_1562(): + a, x, y = symbols('a x y') + eq = -4*sin(x)**4 + 4*cos(x)**4 - 8*cos(x)**2 + assert trigsimp(eq) == -4 + n = sin(x)**6 + 4*sin(x)**4*cos(x)**2 + 5*sin(x)**2*cos(x)**4 + 2*cos(x)**6 + d = -sin(x)**2 - 2*cos(x)**2 + assert simplify(n/d) == -1 + assert trigsimp(-2*cos(x)**2 + cos(x)**4 - sin(x)**4) == -1 + eq = (- sin(x)**3/4)*cos(x) + (cos(x)**3/4)*sin(x) - sin(2*x)*cos(2*x)/8 + assert trigsimp(eq) == 0 + + +def test_1395(): + a, b = symbols('a b') + eq = sin(a)**2*sin(b)**2 + cos(a)**2*cos(b)**2*tan(a)**2 + cos(a)**2 + assert trigsimp(eq) == 1 + + +def test_2849(): + a, x, y = symbols('a x y') + assert trigsimp(diff(integrate(cos(x)/sin(x)**7, x), x)) == \ + cos(x)/sin(x)**7 + + +def test_1676(): + a, x, y = symbols('a x y') + assert trigsimp(sin(x)*cos(y)+cos(x)*sin(y)) == sin(x + y) + assert trigsimp(sin(x)*cos(y)+cos(x)*sin(y)+3) == sin(x + y) + 3 + + +def test_1181(): + a, x, y = symbols('a x y') + assert trigsimp(cos(x)**2 + cos(y)**2*sin(x)**2 + sin(y)**2*sin(x)**2) == 1 + assert trigsimp(a**2*sin(x)**2 + a**2*cos(y)**2*cos(x)**2 + a**2*cos(x)**2*sin(y)**2) == a**2 + assert trigsimp(a**2*cos(y)**2*sin(x)**2 + a**2*sin(y)**2*sin(x)**2) == a**2*sin(x)**2 + + +def test_111(): + eqs = (sin(2)*cos(3) + sin(3)*cos(2), + -sin(2)*sin(3) + cos(2)*cos(3), + sin(2)*cos(3) - sin(3)*cos(2), + sin(2)*sin(3) + cos(2)*cos(3), + sin(2)*sin(3) + cos(2)*cos(3) + cos(2), + sinh(2)*cosh(3) + sinh(3)*cosh(2), + sinh(2)*sinh(3) + cosh(2)*cosh(3), + ) + assert [trigsimp(e) for e in eqs] == [ + sin(5), + cos(5), + -sin(1), + cos(1), + cos(1) + cos(2), + sinh(5), + cosh(5), + ] + + +def test_trigsimp_issues(): + a, x, y = symbols('a x y') + + # 1526 - factor_terms works, too + assert trigsimp(sin(x)**3 + cos(x)**2*sin(x)) == sin(x) + + # issue 2849 + assert trigsimp(diff(integrate(cos(x)/sin(x)**3, x), x)) == \ + cos(x)/sin(x)**3 + assert trigsimp(diff(integrate(sin(x)/cos(x)**3, x), x)) == \ + sin(x)/cos(x)**3 + + # check integer exponents + e = sin(x)**y/cos(x)**y + assert trigsimp(e) == e + assert trigsimp(e.subs(y, 2)) == tan(x)**2 + assert trigsimp(e.subs(x, 1)) == tan(1)**y + + # check for multiple patterns + assert (cos(x)**2/sin(x)**2*cos(y)**2/sin(y)**2).trigsimp() == \ + 1/tan(x)**2/tan(y)**2 + assert trigsimp(cos(x)/sin(x)*cos(x+y)/sin(x+y)) == \ + 1/(tan(x)*tan(x + y)) + + eq = cos(2)*(cos(3) + 1)**2/(cos(3) - 1)**2 + assert trigsimp(eq) == eq.factor() # factor makes denom (-1 + cos(3))**2 + assert trigsimp(cos(2)*(cos(3) + 1)**2*(cos(3) - 1)**2) == \ + cos(2)*sin(3)**4 + + # issue 3690; this generates an expression that formerly caused + # trigsimp to hang + assert cot(x).equals(tan(x)) is False + + # nan or the unchanged expression is ok, but not sin(1) + z = cos(x)**2 + sin(x)**2 - 1 + z1 = tan(x)**2 - 1/cot(x)**2 + n = (1 + z1/z) + assert trigsimp(sin(n)) != sin(1) + eq = x*(n - 1) - x*n + assert trigsimp(eq) is S.NaN + assert trigsimp(eq, recursive=True) is S.NaN + assert trigsimp(1).is_Integer + + assert trigsimp(-sin(x)**4 - 2*sin(x)**2*cos(x)**2 - cos(x)**4) == -1 + + def test_trigsimp_issue_2515(): x = Symbol('x') assert trigsimp(x*cos(x)*tan(x)) == x*sin(x) - assert trigsimp(-sin(x)+cos(x)*tan(x)) == 0 + assert trigsimp(-sin(x) + cos(x)*tan(x)) == 0 + + +def test_issue_3826(): + assert trigsimp(tan(2*x).expand(trig=True)) == tan(2*x) + + +def test_trigsimp_noncommutative(): + x, y = symbols('x,y') + A, B = symbols('A,B', commutative=False) + + assert trigsimp(A - A*sin(x)**2) == A*cos(x)**2 + assert trigsimp(A - A*cos(x)**2) == A*sin(x)**2 + assert trigsimp(A*sin(x)**2 + A*cos(x)**2) == A + assert trigsimp(A + A*tan(x)**2) == A/cos(x)**2 + assert trigsimp(A/cos(x)**2 - A) == A*tan(x)**2 + assert trigsimp(A/cos(x)**2 - A*tan(x)**2) == A + assert trigsimp(A + A*cot(x)**2) == A/sin(x)**2 + assert trigsimp(A/sin(x)**2 - A) == A/tan(x)**2 + assert trigsimp(A/sin(x)**2 - A*cot(x)**2) == A + + assert trigsimp(y*A*cos(x)**2 + y*A*sin(x)**2) == y*A + + assert trigsimp(A*sin(x)/cos(x)) == A*tan(x) + assert trigsimp(A*tan(x)*cos(x)) == A*sin(x) + assert trigsimp(A*cot(x)**3*sin(x)**3) == A*cos(x)**3 + assert trigsimp(y*A*tan(x)**2/sin(x)**2) == y*A/cos(x)**2 + assert trigsimp(A*cot(x)/cos(x)) == A/sin(x) + + assert trigsimp(A*sin(x + y) + A*sin(x - y)) == 2*A*sin(x)*cos(y) + assert trigsimp(A*sin(x + y) - A*sin(x - y)) == 2*A*sin(y)*cos(x) + assert trigsimp(A*cos(x + y) + A*cos(x - y)) == 2*A*cos(x)*cos(y) + assert trigsimp(A*cos(x + y) - A*cos(x - y)) == -2*A*sin(x)*sin(y) + + assert trigsimp(A*sinh(x + y) + A*sinh(x - y)) == 2*A*sinh(x)*cosh(y) + assert trigsimp(A*sinh(x + y) - A*sinh(x - y)) == 2*A*sinh(y)*cosh(x) + assert trigsimp(A*cosh(x + y) + A*cosh(x - y)) == 2*A*cosh(x)*cosh(y) + assert trigsimp(A*cosh(x + y) - A*cosh(x - y)) == 2*A*sinh(x)*sinh(y) + + assert trigsimp(A*cos(0.12345)**2 + A*sin(0.12345)**2) == 1.0*A + def test_hyperbolic_simp(): x, y = symbols('x,y') @@ -159,12 +326,11 @@ assert trigsimp(1 - 1/cosh(x)**2) == tanh(x)**2 assert trigsimp(tanh(x)**2 + 1/cosh(x)**2) == 1 assert trigsimp(coth(x)**2 - 1) == 1/sinh(x)**2 - assert trigsimp(1/sinh(x)**2 + 1) == coth(x)**2 + assert trigsimp(1/sinh(x)**2 + 1) == 1/tanh(x)**2 assert trigsimp(coth(x)**2 - 1/sinh(x)**2) == 1 assert trigsimp(5*cosh(x)**2 - 5*sinh(x)**2) == 5 - assert trigsimp(5*cosh(x/2)**2 - 2*sinh(x/2)**2) in \ - [2 + 3*cosh(x/2)**2, 5 + 3*sinh(x/2)**2] + assert trigsimp(5*cosh(x/2)**2 - 2*sinh(x/2)**2) == 3*cosh(x)/2 + S(7)/2 assert trigsimp(sinh(x)/cosh(x)) == tanh(x) assert trigsimp(tanh(x)) == trigsimp(sinh(x)/cosh(x)) @@ -175,14 +341,14 @@ assert trigsimp(coth(x)/cosh(x)) == 1/sinh(x) e = 2*cosh(x)**2 - 2*sinh(x)**2 - assert trigsimp(log(e), deep=True) == log(2) + assert trigsimp(log(e)) == log(2) assert trigsimp(cosh(x)**2*cosh(y)**2 - cosh(x)**2*sinh(y)**2 - sinh(x)**2, recursive=True) == 1 assert trigsimp(sinh(x)**2*sinh(y)**2 - sinh(x)**2*cosh(y)**2 + cosh(x)**2, recursive=True) == 1 - assert abs(trigsimp(2.0*cosh(x)**2 - 2.0*sinh(x)**2)-2.0) < 1e-10 + assert abs(trigsimp(2.0*cosh(x)**2 - 2.0*sinh(x)**2) - 2.0) < 1e-10 assert trigsimp(sinh(x)**2/cosh(x)**2) == tanh(x)**2 assert trigsimp(sinh(x)**3/cosh(x)**3) == tanh(x)**3 @@ -196,109 +362,145 @@ assert trigsimp(x*cosh(x)*tanh(x)) == x*sinh(x) assert trigsimp(-sinh(x) + cosh(x)*tanh(x)) == 0 -@XFAIL -def test_tan_cot(): - x = Symbol('x') - ### ??? - assert tan(x) == 1/cot(x) + assert tan(x) != 1/cot(x) # cot doesn't auto-simplify -@XFAIL -def test_tan_cot2(): - x = Symbol('x') assert trigsimp(tan(x) - 1/cot(x)) == 0 assert trigsimp(3*tanh(x)**7 - 2/coth(x)**7) == tanh(x)**7 + +def test_trigsimp_groebner(): + from sympy.simplify.simplify import trigsimp_groebner + + c = cos(x) + s = sin(x) + ex = (4*s*c + 12*s + 5*c**3 + 21*c**2 + 23*c + 15)/( + -s*c**2 + 2*s*c + 15*s + 7*c**3 + 31*c**2 + 37*c + 21) + resnum = (5*s - 5*c + 1) + resdenom = (8*s - 6*c) + results = [resnum/resdenom, (-resnum)/(-resdenom)] + assert trigsimp_groebner(ex) in results + assert trigsimp_groebner(s/c, hints=[tan]) == tan(x) + + assert trigsimp((-s + 1)/c + c/(-s + 1), + method='groebner') == 2/c + assert trigsimp((-s + 1)/c + c/(-s + 1), + method='groebner', polynomial=True) == 2/c + + # Test quick=False works + assert trigsimp_groebner(ex, hints=[2]) in results + + # test "I" + assert trigsimp_groebner(sin(I*x)/cos(I*x), hints=[tanh]) == I*tanh(x) + + # test hyperbolic / sums + assert trigsimp_groebner((tanh(x)+tanh(y))/(1+tanh(x)*tanh(y)), + hints=[(tanh, x, y)]) == tanh(x + y) + + @XFAIL def test_factorial_simplify(): # There are more tests in test_factorials.py. These are just to # ensure that simplify() calls factorial_simplify correctly from sympy.specfun.factorials import factorial x = Symbol('x') - assert simplify(factorial(x)/x) == factorial(x-1) + assert simplify(factorial(x)/x) == factorial(x - 1) assert simplify(factorial(factorial(x))) == factorial(factorial(x)) -def test_simplify(): + +def test_simplify_expr(): x, y, z, k, n, m, w, f, s, A = symbols('x,y,z,k,n,m,w,f,s,A') assert all(simplify(tmp) == tmp for tmp in [I, E, oo, x, -x, -oo, -E, -I]) e = 1/x + 1/y - assert e != (x+y)/(x*y) - assert simplify(e) == (x+y)/(x*y) + assert e != (x + y)/(x*y) + assert simplify(e) == (x + y)/(x*y) e = A**2*s**4/(4*pi*k*m**3) assert simplify(e) == e - e = (4+4*x-2*(2+2*x))/(2+2*x) + e = (4 + 4*x - 2*(2 + 2*x))/(2 + 2*x) assert simplify(e) == 0 - e = (-4*x*y**2-2*y**3-2*x**2*y)/(x+y)**2 + e = (-4*x*y**2 - 2*y**3 - 2*x**2*y)/(x + y)**2 assert simplify(e) == -2*y - e = -x-y-(x+y)**(-1)*y**2+(x+y)**(-1)*x**2 + e = -x - y - (x + y)**(-1)*y**2 + (x + y)**(-1)*x**2 assert simplify(e) == -2*y - e = (x+x*y)/x + e = (x + x*y)/x assert simplify(e) == 1 + y - e = (f(x)+y*f(x))/f(x) + e = (f(x) + y*f(x))/f(x) assert simplify(e) == 1 + y e = (2 * (1/n - cos(n * pi)/n))/pi - assert simplify(e) == 2*((1 - 1*cos(pi*n))/(pi*n)) + assert simplify(e) == (-cos(pi*n) + 1)/(pi*n)*2 - e = integrate(1/(x**3+1), x).diff(x) - assert simplify(e) == 1/(x**3+1) + e = integrate(1/(x**3 + 1), x).diff(x) + assert simplify(e) == 1/(x**3 + 1) - e = integrate(x/(x**2+3*x+1), x).diff(x) - assert simplify(e) == x/(x**2+3*x+1) + e = integrate(x/(x**2 + 3*x + 1), x).diff(x) + assert simplify(e) == x/(x**2 + 3*x + 1) - A = Matrix([[2*k-m*w**2, -k], [-k, k-m*w**2]]).inv() - - assert simplify((A*Matrix([0,f]))[1]) == \ - f*(2*k - m*w**2)/(k**2 - 3*k*m*w**2 + m**2*w**4) - a, b, c, d, e, f, g, h, i = symbols('a,b,c,d,e,f,g,h,i') - - f_1 = x*a + y*b + z*c - 1 - f_2 = x*d + y*e + z*f - 1 - f_3 = x*g + y*h + z*i - 1 - - solutions = solve([f_1, f_2, f_3], x, y, z, simplify=False) - - assert simplify(solutions[y]) == \ - (a*i+c*d+f*g-a*f-c*g-d*i)/(a*e*i+b*f*g+c*d*h-a*f*h-b*d*i-c*e*g) + A = Matrix([[2*k - m*w**2, -k], [-k, k - m*w**2]]).inv() + assert simplify((A*Matrix([0, f]))[1]) == \ + -f*(2*k - m*w**2)/(k**2 - (k - m*w**2)*(2*k - m*w**2)) f = -x + y/(z + t) + z*x/(z + t) + z*a/(z + t) + t*x/(z + t) - assert simplify(f) == (y + a*z)/(z + t) A, B = symbols('A,B', commutative=False) assert simplify(A*B - B*A) == A*B - B*A + assert simplify(A/(1 + y/x)) == x*A/(x + y) + assert simplify(A*(1/x + 1/y)) == A/x + A/y #(x + y)*A/(x*y) assert simplify(log(2) + log(3)) == log(6) assert simplify(log(2*x) - log(2)) == log(x) assert simplify(hyper([], [], x)) == exp(x) + +def test_issue_458(): + f_1 = x*a + y*b + z*c - 1 + f_2 = x*d + y*e + z*f - 1 + f_3 = x*g + y*h + z*i - 1 + + solutions = solve([f_1, f_2, f_3], x, y, z, simplify=False) + + assert simplify(solutions[y]) == \ + (a*i + c*d + f*g - a*f - c*g - d*i)/ \ + (a*e*i + b*f*g + c*d*h - a*f*h - b*d*i - c*e*g) + + def test_simplify_other(): assert simplify(sin(x)**2 + cos(x)**2) == 1 assert simplify(gamma(x + 1)/gamma(x)) == x assert simplify(sin(x)**2 + cos(x)**2 + factorial(x)/gamma(x)) == 1 + x - assert simplify(Eq(sin(x)**2 + cos(x)**2, factorial(x)/gamma(x))) == Eq(1, x) + assert simplify( + Eq(sin(x)**2 + cos(x)**2, factorial(x)/gamma(x))) == Eq(1, x) nc = symbols('nc', commutative=False) assert simplify(x + x*nc) == x*(1 + nc) # issue 3024 # f = exp(-I*(k*sqrt(t) + x/(2*sqrt(t)))**2) # ans = integrate(f, (k, -oo, oo), conds='none') - ans = I*(-pi*x*exp(-3*I*pi/4 + I*x**2/(4*t))*erf(x*exp(-3*I*pi/4)/\ - (2*sqrt(t)))/(2*sqrt(t)) + pi*x*exp(-3*I*pi/4 + I*x**2/(4*t))/\ - (2*sqrt(t)))*exp(-I*x**2/(4*t))/(sqrt(pi)*x) - I*sqrt(pi)*\ + ans = I*(-pi*x*exp(-3*I*pi/4 + I*x**2/(4*t))*erf(x*exp(-3*I*pi/4)/ + (2*sqrt(t)))/(2*sqrt(t)) + pi*x*exp(-3*I*pi/4 + I*x**2/(4*t))/ + (2*sqrt(t)))*exp(-I*x**2/(4*t))/(sqrt(pi)*x) - I*sqrt(pi) * \ (-erf(x*exp(I*pi/4)/(2*sqrt(t))) + 1)*exp(I*pi/4)/(2*sqrt(t)) assert simplify(ans) == -(-1)**(S(3)/4)*sqrt(pi)/sqrt(t) # issue 3271 assert simplify(2**(2 + x)/4) == 2**x + +def test_simplify_complex(): + cosAsExp = cos(x)._eval_rewrite_as_exp(x) + tanAsExp = tan(x)._eval_rewrite_as_exp(x) + assert simplify(cosAsExp*tanAsExp).expand() == ( + sin(x))._eval_rewrite_as_exp(x).expand() # issue 1242 + + def test_simplify_ratio(): # roots of x**3-3*x+5 roots = ['(1/2 - sqrt(3)*I/2)*(sqrt(21)/2 + 5/2)**(1/3) + 1/((1/2 - ' @@ -313,33 +515,33 @@ # If ratio=oo, simplify() is always applied: assert simplify(r, ratio=oo) is not r + def test_simplify_measure(): measure1 = lambda expr: len(str(expr)) - measure2 = lambda expr: -count_ops(expr) # Return the most complicated result + measure2 = lambda expr: -count_ops(expr) + # Return the most complicated result expr = (x + 1)/(x + sin(x)**2 + cos(x)**2) assert measure1(simplify(expr, measure=measure1)) <= measure1(expr) assert measure2(simplify(expr, measure=measure2)) <= measure2(expr) + def test_simplify_issue_1308(): assert simplify(exp(-Rational(1, 2)) + exp(-Rational(3, 2))) == \ (1 + E)*exp(-Rational(3, 2)) + def test_issue_2553(): - assert simplify(E + exp(-E)) == E + exp(-E) + assert simplify(E + exp(-E)) == exp(-E) + E n = symbols('n', commutative=False) assert simplify(n + n**(-n)) == n + n**(-n) + def test_simplify_fail1(): x = Symbol('x') y = Symbol('y') - e = (x+y)**2/(-4*x*y**2-2*y**3-2*x**2*y) + e = (x + y)**2/(-4*x*y**2 - 2*y**3 - 2*x**2*y) assert simplify(e) == 1 / (-2*y) -def test_simplify_issue_3214(): - c, p = symbols('c p', positive=True) - s = sqrt(c**2 - p**2) - b = (c + I*p - s)/(c + I*p + s) - assert radsimp(b) == (c*p - p*s + I*(-c**2 + c*s + p**2))/(c*p) def test_fraction(): x, y, z = list(map(Symbol, 'xyz')) @@ -358,8 +560,8 @@ assert fraction(1/y**2) == (1, y**2) assert fraction(x/y**2) == (x, y**2) - assert fraction((x**2+1)/y) == (x**2+1, y) - assert fraction(x*(y+1)/y**7) == (x*(y+1), y**7) + assert fraction((x**2 + 1)/y) == (x**2 + 1, y) + assert fraction(x*(y + 1)/y**7) == (x*(y + 1), y**7) assert fraction(exp(-x), exact=True) == (exp(-x), 1) @@ -370,40 +572,54 @@ assert fraction(exp(n)) == (1, exp(-n)) assert fraction(exp(-n)) == (exp(-n), 1) + def test_powsimp(): x, y, z, n = symbols('x,y,z,n') f = Function('f') assert powsimp( 4**x * 2**(-x) * 2**(-x) ) == 1 assert powsimp( (-4)**x * (-2)**(-x) * 2**(-x) ) == 1 - assert powsimp( f(4**x * 2**(-x) * 2**(-x)) ) == f(4**x * 2**(-x) * 2**(-x)) - assert powsimp( f(4**x * 2**(-x) * 2**(-x)), deep = True ) == f(1) + assert powsimp( + f(4**x * 2**(-x) * 2**(-x)) ) == f(4**x * 2**(-x) * 2**(-x)) + assert powsimp( f(4**x * 2**(-x) * 2**(-x)), deep=True ) == f(1) assert exp(x)*exp(y) == exp(x)*exp(y) - assert powsimp(exp(x)*exp(y)) == exp(x+y) + assert powsimp(exp(x)*exp(y)) == exp(x + y) assert powsimp(exp(x)*exp(y)*2**x*2**y) == (2*E)**(x + y) - assert powsimp(exp(x)*exp(y)*2**x*2**y, combine='exp') == exp(x+y)*2**(x+y) - assert powsimp(exp(x)*exp(y)*exp(2)*sin(x)+sin(y)+2**x*2**y) == exp(2+x+y)*sin(x)+sin(y)+2**(x+y) + assert powsimp(exp(x)*exp(y)*2**x*2**y, combine='exp') == \ + exp(x + y)*2**(x + y) + assert powsimp(exp(x)*exp(y)*exp(2)*sin(x) + sin(y) + 2**x*2**y) == \ + exp(2 + x + y)*sin(x) + sin(y) + 2**(x + y) assert powsimp(sin(exp(x)*exp(y))) == sin(exp(x)*exp(y)) - assert powsimp(sin(exp(x)*exp(y)), deep=True) == sin(exp(x+y)) - assert powsimp(x**2*x**y) == x**(2+y) + assert powsimp(sin(exp(x)*exp(y)), deep=True) == sin(exp(x + y)) + assert powsimp(x**2*x**y) == x**(2 + y) # This should remain factored, because 'exp' with deep=True is supposed # to act like old automatic exponent combining. - assert powsimp((1 + E*exp(E))*exp(-E), combine='exp', deep=True) == (1 + exp(1 + E))*exp(-E) - assert powsimp((1 + E*exp(E))*exp(-E), deep=True) == (1 + exp(1 + E))*exp(-E) + assert powsimp((1 + E*exp(E))*exp(-E), combine='exp', deep=True) == \ + (1 + exp(1 + E))*exp(-E) + assert powsimp((1 + E*exp(E))*exp(-E), deep=True) == \ + (1 + exp(1 + E))*exp(-E) assert powsimp((1 + E*exp(E))*exp(-E)) == (1 + exp(1 + E))*exp(-E) - assert powsimp((1 + E*exp(E))*exp(-E), combine='exp') == (1 + exp(1 + E))*exp(-E) - assert powsimp((1 + E*exp(E))*exp(-E), combine='base') == (1 + E*exp(E))*exp(-E) - x,y = symbols('x,y', nonnegative=True) + assert powsimp((1 + E*exp(E))*exp(-E), combine='exp') == \ + (1 + exp(1 + E))*exp(-E) + assert powsimp((1 + E*exp(E))*exp(-E), combine='base') == \ + (1 + E*exp(E))*exp(-E) + x, y = symbols('x,y', nonnegative=True) n = Symbol('n', real=True) - assert powsimp( y**n * (y/x)**(-n) ) == x**n - assert powsimp(x**(x**(x*y)*y**(x*y))*y**(x**(x*y)*y**(x*y)),deep=True) == (x*y)**(x*y)**(x*y) + assert powsimp(y**n * (y/x)**(-n)) == x**n + assert powsimp(x**(x**(x*y)*y**(x*y))*y**(x**(x*y)*y**(x*y)), deep=True) \ + == (x*y)**(x*y)**(x*y) assert powsimp(2**(2**(2*x)*x), deep=False) == 2**(2**(2*x)*x) assert powsimp(2**(2**(2*x)*x), deep=True) == 2**(x*4**x) - assert powsimp(exp(-x + exp(-x)*exp(-x*log(x))), deep=False, combine='exp') == exp(-x + exp(-x)*exp(-x*log(x))) - assert powsimp(exp(-x + exp(-x)*exp(-x*log(x))), deep=False, combine='exp') == exp(-x + exp(-x)*exp(-x*log(x))) - assert powsimp((x+y)/(3*z), deep=False, combine='exp') == (x+y)/(3*z) - assert powsimp((x/3+y/3)/z, deep=True, combine='exp') == (x/3+y/3)/z - assert powsimp(exp(x)/(1 + exp(x)*exp(y)), deep=True) == exp(x)/(1 + exp(x + y)) + assert powsimp( + exp(-x + exp(-x)*exp(-x*log(x))), deep=False, combine='exp') == \ + exp(-x + exp(-x)*exp(-x*log(x))) + assert powsimp( + exp(-x + exp(-x)*exp(-x*log(x))), deep=False, combine='exp') == \ + exp(-x + exp(-x)*exp(-x*log(x))) + assert powsimp((x + y)/(3*z), deep=False, combine='exp') == (x + y)/(3*z) + assert powsimp((x/3 + y/3)/z, deep=True, combine='exp') == (x/3 + y/3)/z + assert powsimp(exp(x)/(1 + exp(x)*exp(y)), deep=True) == \ + exp(x)/(1 + exp(x + y)) assert powsimp(x*y**(z**x*z**y), deep=True) == x*y**(z**(x + y)) assert powsimp((z**x*z**y)**x, deep=True) == (z**(x + y))**x assert powsimp(x*(z**x*z**y)**x, deep=True) == x*(z**(x + y))**x @@ -420,9 +636,23 @@ # force=True overrides assumptions assert powsimp((-1)**(2*x), force=True) == 1 + # rational exponents allow combining of negative terms + w, n, m = symbols('w n m', negative=True) + e = i/a # not a rational exponent if `a` is unknown + ex = w**e*n**e*m**e + assert powsimp(ex) == m**(i/a)*n**(i/a)*w**(i/a) + e = i/3 + ex = w**e*n**e*m**e + assert powsimp(ex) == (-1)**i*(-m*n*w)**(i/3) + e = (3 + i)/i + ex = w**e*n**e*m**e + assert powsimp(ex) == (-1)**(3*e)*(-m*n*w)**e + eq = x**(2*a/3) - assert powsimp(eq).exp == eq.exp == 2*a/3 # eq != (x**a)**(2/3) (try x = -1 and a = 3 to see) - assert powsimp(2**(2*x)) == 4**x # powdenest goes the other direction + # eq != (x**a)**(2/3) (try x = -1 and a = 3 to see) + assert powsimp(eq).exp == eq.exp == 2*a/3 + # powdenest goes the other direction + assert powsimp(2**(2*x)) == 4**x assert powsimp(exp(p/2)) == exp(p/2) @@ -430,6 +660,7 @@ eq = Mul(*[sqrt(Dummy(imaginary=True)) for i in range(3)]) assert powsimp(eq) == eq and eq.is_Mul + def test_issue_3268(): z = -5*sqrt(2)/(2*sqrt(2*sqrt(29) + 29)) + sqrt(-sqrt(29)/29 + S(1)/2) assert Mul(*[powsimp(a) for a in Mul.make_args(z.normal())]) == 0 @@ -438,6 +669,22 @@ assert powsimp(sqrt(2 + sqrt(3))*sqrt(2 - sqrt(3)) + 1) == 2 assert powsimp(z) != 0 + +def test_powsimp_negated_base(): + assert powsimp((-x + y)/sqrt(x - y)) == -sqrt(x - y) + assert powsimp((-x + y)*(-z + y)/sqrt(x - y)/sqrt(z - y)) == sqrt(x - y)*sqrt(z - y) + p = symbols('p', positive=True) + assert powsimp((-p)**a/p**a) == (-1)**a + n = symbols('n', negative=True) + assert powsimp((-n)**a/n**a) == (-1)**a + # if x is 0 then the lhs is 0**a*oo**a which is not (-1)**a + assert powsimp((-x)**a/x**a) != (-1)**a + + +def test_issue_3341(): + assert powsimp(16*2**a*8**b) == 2**(a + 3*b + 4) + + def test_powsimp_polar(): from sympy import polar_lift, exp_polar x, y, z = symbols('x y z') @@ -449,22 +696,27 @@ assert (1/p)**x == p**(-x) assert exp_polar(x)*exp_polar(y) == exp_polar(x)*exp_polar(y) - assert powsimp(exp_polar(x)*exp_polar(y)) == exp_polar(x+y) - assert powsimp(exp_polar(x)*exp_polar(y)*p**x*p**y) == (p*exp_polar(1))**(x + y) - assert powsimp(exp_polar(x)*exp_polar(y)*p**x*p**y, combine='exp') \ - == exp_polar(x+y)*p**(x+y) - assert powsimp(exp_polar(x)*exp_polar(y)*exp_polar(2)*sin(x)+sin(y)+p**x*p**y) \ - == p**(x+y) + sin(x)*exp_polar(2+x+y) + sin(y) - assert powsimp(sin(exp_polar(x)*exp_polar(y))) == sin(exp_polar(x)*exp_polar(y)) - assert powsimp(sin(exp_polar(x)*exp_polar(y)), deep=True) == sin(exp_polar(x+y)) + assert powsimp(exp_polar(x)*exp_polar(y)) == exp_polar(x + y) + assert powsimp(exp_polar(x)*exp_polar(y)*p**x*p**y) == \ + (p*exp_polar(1))**(x + y) + assert powsimp(exp_polar(x)*exp_polar(y)*p**x*p**y, combine='exp') == \ + exp_polar(x + y)*p**(x + y) + assert powsimp( + exp_polar(x)*exp_polar(y)*exp_polar(2)*sin(x) + sin(y) + p**x*p**y) \ + == p**(x + y) + sin(x)*exp_polar(2 + x + y) + sin(y) + assert powsimp(sin(exp_polar(x)*exp_polar(y))) == \ + sin(exp_polar(x)*exp_polar(y)) + assert powsimp(sin(exp_polar(x)*exp_polar(y)), deep=True) == \ + sin(exp_polar(x + y)) + def test_powsimp_nc(): x, y, z = symbols('x,y,z') A, B, C = symbols('A B C', commutative=False) - assert powsimp(A**x*A**y, combine='all') == A**(x+y) + assert powsimp(A**x*A**y, combine='all') == A**(x + y) assert powsimp(A**x*A**y, combine='base') == A**x*A**y - assert powsimp(A**x*A**y, combine='exp') == A**(x+y) + assert powsimp(A**x*A**y, combine='exp') == A**(x + y) assert powsimp(A**x*B**x, combine='all') == (A*B)**x assert powsimp(A**x*B**x, combine='base') == (A*B)**x @@ -474,9 +726,9 @@ assert powsimp(B**x*A**x, combine='base') == (B*A)**x assert powsimp(B**x*A**x, combine='exp') == B**x*A**x - assert powsimp(A**x*A**y*A**z, combine='all') == A**(x+y+z) + assert powsimp(A**x*A**y*A**z, combine='all') == A**(x + y + z) assert powsimp(A**x*A**y*A**z, combine='base') == A**x*A**y*A**z - assert powsimp(A**x*A**y*A**z, combine='exp') == A**(x+y+z) + assert powsimp(A**x*A**y*A**z, combine='exp') == A**(x + y + z) assert powsimp(A**x*B**x*C**x, combine='all') == (A*B*C)**x assert powsimp(A**x*B**x*C**x, combine='base') == (A*B*C)**x @@ -486,27 +738,55 @@ assert powsimp(B**x*A**x*C**x, combine='base') == (B*A*C)**x assert powsimp(B**x*A**x*C**x, combine='exp') == B**x*A**x*C**x +def test_nthroot(): + assert nthroot(90 + 34*sqrt(7), 3) == sqrt(7) + 3 + q = 1 + sqrt(2) - 2*sqrt(3) + sqrt(6) + sqrt(7) + assert nthroot(expand_multinomial(q**3), 3) == q + assert nthroot(41 + 29*sqrt(2), 5) == 1 + sqrt(2) + assert nthroot(-41 - 29*sqrt(2), 5) == -1 - sqrt(2) + expr = 1320*sqrt(10) + 4216 + 2576*sqrt(6) + 1640*sqrt(15) + assert nthroot(expr, 5) == 1 + sqrt(6) + sqrt(15) + q = 1 + sqrt(2) + sqrt(3) + sqrt(5) + assert expand_multinomial(nthroot(expand_multinomial(q**5), 5)) == q + q = 1 + sqrt(2) + 7*sqrt(6) + 2*sqrt(10) + assert nthroot(expand_multinomial(q**5), 5, 8) == q + q = 1 + sqrt(2) - 2*sqrt(3) + 1171*sqrt(6) + assert nthroot(expand_multinomial(q**3), 3) == q + assert nthroot(expand_multinomial(q**6), 6) == q + +@slow +def test_nthroot1(): + q = 1 + sqrt(2) + sqrt(3) + S(1)/10**20 + p = expand_multinomial(q**5) + assert nthroot(p, 5) == q + q = 1 + sqrt(2) + sqrt(3) + S(1)/10**30 + p = expand_multinomial(q**5) + assert nthroot(p, 5) == p**Rational(1, 5) + def test_collect_1(): """Collect with respect to a Symbol""" x, y, z, n = symbols('x,y,z,n') assert collect( x + y*x, x ) == x * (1 + y) assert collect( x + x**2, x ) == x + x**2 - assert collect( x**2 + y*x**2, x ) == (x**2)*(1+y) + assert collect( x**2 + y*x**2, x ) == (x**2)*(1 + y) assert collect( x**2 + y*x, x ) == x*y + x**2 - assert collect( 2*x**2 + y*x**2 + 3*x*y, [x] ) == x**2*(2+y) + 3*x*y - assert collect( 2*x**2 + y*x**2 + 3*x*y, [y] ) == 2*x**2 + y*(x**2+3*x) + assert collect( 2*x**2 + y*x**2 + 3*x*y, [x] ) == x**2*(2 + y) + 3*x*y + assert collect( 2*x**2 + y*x**2 + 3*x*y, [y] ) == 2*x**2 + y*(x**2 + 3*x) assert collect( ((1 + y + x)**4).expand(), x) == ((1 + y)**4).expand() + \ - x*(4*(1 + y)**3).expand() + x**2*(6*(1 + y)**2).expand() + \ - x**3*(4*(1 + y)).expand() + x**4 + x*(4*(1 + y)**3).expand() + x**2*(6*(1 + y)**2).expand() + \ + x**3*(4*(1 + y)).expand() + x**4 # symbols can be given as any iterable expr = x + y assert collect(expr, expr.free_symbols) == expr + def test_collect_2(): """Collect with respect to a sum""" a, b, x = symbols('a,b,x') - assert collect(a*(cos(x)+sin(x)) + b*(cos(x)+sin(x)), sin(x)+cos(x)) == (a + b)*(cos(x) + sin(x)) + assert collect(a*(cos(x) + sin(x)) + b*(cos(x) + sin(x)), + sin(x) + cos(x)) == (a + b)*(cos(x) + sin(x)) + def test_collect_3(): """Collect with respect to a product""" @@ -522,10 +802,12 @@ assert collect(a*x*f(x) + b*(x*f(x)), x*f(x)) == x*(a + b)*f(x) assert collect(a*x*log(x) + b*(x*log(x)), x*log(x)) == x*(a + b)*log(x) - assert collect(a*x**2*log(x)**2 + b*(x*log(x))**2, x*log(x)) == x**2*log(x)**2*(a + b) + assert collect(a*x**2*log(x)**2 + b*(x*log(x))**2, x*log(x)) == \ + x**2*log(x)**2*(a + b) # with respect to a product of three symbols - assert collect(y*x*z+a*x*y*z, x*y*z) == (1 + a)*x*y*z + assert collect(y*x*z + a*x*y*z, x*y*z) == (1 + a)*x*y*z + def test_collect_4(): """Collect with respect to a power""" @@ -535,38 +817,44 @@ # issue 2997: 2 stays with c (unless c is integer or x is positive0 assert collect(a*x**(2*c) + b*x**(2*c), x**c) == x**(2*c)*(a + b) + def test_collect_5(): """Collect with respect to a tuple""" a, x, y, z, n = symbols('a,x,y,z,n') assert collect(x**2*y**4 + z*(x*y**2)**2 + z + a*z, [x*y**2, z]) in [ - z*(1 + a + x**2*y**4) + x**2*y**4, - z*(1 + a) + x**2*y**4*(1 + z) ] - assert collect((1+ (x+y) + (x+y)**2).expand(), - [x, y]) == 1 + y + x*(1 + 2*y) + x**2 + y**2 + z*(1 + a + x**2*y**4) + x**2*y**4, + z*(1 + a) + x**2*y**4*(1 + z) ] + assert collect((1 + (x + y) + (x + y)**2).expand(), + [x, y]) == 1 + y + x*(1 + 2*y) + x**2 + y**2 + def test_collect_D(): D = Derivative f = Function('f') x, a, b = symbols('x,a,b') - fx = D(f(x), x) + fx = D(f(x), x) fxx = D(f(x), x, x) assert collect(a*fx + b*fx, fx) == (a + b)*fx - assert collect(a*D(fx, x) + b*D(fx, x), fx) == (a + b)*D(fx, x) - assert collect(a*fxx + b*fxx , fx) == (a + b)*D(fx, x) + assert collect(a*D(fx, x) + b*D(fx, x), fx) == (a + b)*D(fx, x) + assert collect(a*fxx + b*fxx, fx) == (a + b)*D(fx, x) # 1685 - assert collect(5*f(x)+3*fx, fx) == 5*f(x) + 3*fx - assert collect(f(x) + f(x)*diff(f(x), x) + x*diff(f(x), x)*f(x), f(x).diff(x)) ==\ - (x*f(x) + f(x))*D(f(x), x) + f(x) - assert collect(f(x) + f(x)*diff(f(x), x) + x*diff(f(x), x)*f(x), f(x).diff(x), exact=True) ==\ - (x*f(x) + f(x))*D(f(x), x) + f(x) - assert collect(1/f(x) + 1/f(x)*diff(f(x), x) + x*diff(f(x), x)/f(x), f(x).diff(x), exact=True) ==\ - (1/f(x) + x/f(x))*D(f(x), x) + 1/f(x) + assert collect(5*f(x) + 3*fx, fx) == 5*f(x) + 3*fx + assert collect(f(x) + f(x)*diff(f(x), x) + x*diff(f(x), x)*f(x), f(x).diff(x)) == \ + (x*f(x) + f(x))*D(f(x), x) + f(x) + assert collect(f(x) + f(x)*diff(f(x), x) + x*diff(f(x), x)*f(x), f(x).diff(x), exact=True) == \ + (x*f(x) + f(x))*D(f(x), x) + f(x) + assert collect(1/f(x) + 1/f(x)*diff(f(x), x) + x*diff(f(x), x)/f(x), f(x).diff(x), exact=True) == \ + (1/f(x) + x/f(x))*D(f(x), x) + 1/f(x) + @XFAIL -def collect_issues(): - assert collect(1/f(x) + 1/f(x)*diff(f(x), x) + x*diff(f(x), x)/f(x), f(x).diff(x)) !=\ - (1 + x*D(f(x), x) + D(f(x), x))/f(x) +def test_collect_issues(): + D = Derivative + f = Function('f') + e = (1 + x*D(f(x), x) + D(f(x), x))/f(x) + assert collect(e.expand(), f(x).diff(x)) != e + def test_collect_D_0(): D = Derivative @@ -576,7 +864,8 @@ # collect does not distinguish nested derivatives, so it returns # -- (a + b)*D(D(f, x), x) - assert collect(a*fxx + b*fxx , fxx) == (a + b)*fxx + assert collect(a*fxx + b*fxx, fxx) == (a + b)*fxx + def test_collect_Wild(): """Collect with respect to functions with Wild argument""" @@ -590,28 +879,41 @@ assert collect(f(x, y) + a*f(x, y), f(w1, w1)) == f(x, y) + a*f(x, y) assert collect(f(x, x) + a*f(x, x), f(w1, w1)) == (1 + a)*f(x, x) assert collect(a*(x + 1)**y + (x + 1)**y, w1**y) == (1 + a)*(x + 1)**y - assert collect(a*(x + 1)**y + (x + 1)**y, w1**b) == a*(x + 1)**y + (x + 1)**y - assert collect(a*(x + 1)**y + (x + 1)**y, (x + 1)**w2) == (1 + a)*(x + 1)**y + assert collect(a*(x + 1)**y + (x + 1)**y, w1**b) == \ + a*(x + 1)**y + (x + 1)**y + assert collect(a*(x + 1)**y + (x + 1)**y, (x + 1)**w2) == \ + (1 + a)*(x + 1)**y assert collect(a*(x + 1)**y + (x + 1)**y, w1**w2) == (1 + a)*(x + 1)**y + def test_collect_func(): f = ((x + a + 1)**3).expand() - assert collect(f, x) == a**3 + 3*a**2 + 3*a + x**3 + x**2*(3*a + 3) + x*(3*a**2 + 6*a + 3) + 1 - assert collect(f, x, factor) == x**3 + 3*x**2*(a + 1) + 3*x*(a + 1)**2 + (a + 1)**3 + assert collect(f, x) == a**3 + 3*a**2 + 3*a + x**3 + x**2*(3*a + 3) + \ + x*(3*a**2 + 6*a + 3) + 1 + assert collect(f, x, factor) == x**3 + 3*x**2*(a + 1) + 3*x*(a + 1)**2 + \ + (a + 1)**3 + + assert collect(f, x, evaluate=False) == { + S.One: a**3 + 3*a**2 + 3*a + 1, + x: 3*a**2 + 6*a + 3, x**2: 3*a + 3, + x**3: 1 + } - assert collect(f, x, evaluate=False) == {S.One: a**3 + 3*a**2 + 3*a + 1, x: 3*a**2 + 6*a + 3, x**2: 3*a + 3, x**3: 1} @XFAIL def test_collect_func_xfail(): # XXX: this test will pass when automatic constant distribution is removed (#1497) - assert collect(f, x, factor, evaluate=False) == {S.One: (a + 1)**3, x: 3*(a + 1)**2, x**2: 3*(a + 1), x**3: 1} + assert collect(f, x, factor, evaluate=False) == {S.One: (a + 1)**3, + x: 3*(a + 1)**2, x**2: 3*(a + 1), x**3: 1} + def test_collect_order(): a, b, x, t = symbols('a,b,x,t') assert collect(t + t*x + t*x**2 + O(x**3), t) == t*(1 + x + x**2 + O(x**3)) - assert collect(t + t*x + x**2 + O(x**3), t) == t*(1 + x + O(x**3)) + x**2 + O(x**3) + assert collect(t + t*x + x**2 + O(x**3), t) == \ + t*(1 + x + O(x**3)) + x**2 + O(x**3) f = a*x + b*x + c*x**2 + d*x**2 + O(x**3) g = x*(a + b) + x**2*(c + d) + O(x**3) @@ -624,44 +926,56 @@ assert collect(f, [sin(a), cos(a)]) == \ sin(a)*cos(b).series(b, 0, 10) + cos(a)*sin(b).series(b, 0, 10) assert collect(f, [sin(a), cos(a)], distribute_order_term=False) == \ - sin(a)*cos(b).series(b, 0, 10).removeO() + cos(a)*sin(b).series(b, 0, 10).removeO() + O(b**10) + sin(a)*cos(b).series(b, 0, 10).removeO() + \ + cos(a)*sin(b).series(b, 0, 10).removeO() + O(b**10) + def test_rcollect(): - assert rcollect((x**2*y + x*y + x + y)/(x + y), y) == (x + y*(1 + x + x**2))/(x + y) + assert rcollect((x**2*y + x*y + x + y)/(x + y), y) == \ + (x + y*(1 + x + x**2))/(x + y) assert rcollect(sqrt(-((x + 1)*(y + 1))), z) == sqrt(-((x + 1)*(y + 1))) + def test_separatevars(): - x,y,z,n = symbols('x,y,z,n') - assert separatevars(2*n*x*z+2*x*y*z) == 2*x*z*(n+y) - assert separatevars(x*z+x*y*z) == x*z*(1+y) - assert separatevars(pi*x*z+pi*x*y*z) == pi*x*z*(1+y) - assert separatevars(x*y**2*sin(x) + x*sin(x)*sin(y)) == x*(sin(y) + y**2)*sin(x) - assert separatevars(x*exp(x+y)+x*exp(x)) == x*(1 + exp(y))*exp(x) - assert separatevars((x*(y+1))**z).is_Pow # != x**z*(1 + y)**z - assert separatevars(1+x+y+x*y) == (x+1)*(y+1) - assert separatevars(y/pi*exp(-(z - x)/cos(n))) == y*exp(x/cos(n))*exp(-z/cos(n))/pi + x, y, z, n = symbols('x,y,z,n') + assert separatevars(2*n*x*z + 2*x*y*z) == 2*x*z*(n + y) + assert separatevars(x*z + x*y*z) == x*z*(1 + y) + assert separatevars(pi*x*z + pi*x*y*z) == pi*x*z*(1 + y) + assert separatevars(x*y**2*sin(x) + x*sin(x)*sin(y)) == \ + x*(sin(y) + y**2)*sin(x) + assert separatevars(x*exp(x + y) + x*exp(x)) == x*(1 + exp(y))*exp(x) + assert separatevars((x*(y + 1))**z).is_Pow # != x**z*(1 + y)**z + assert separatevars(1 + x + y + x*y) == (x + 1)*(y + 1) + assert separatevars(y/pi*exp(-(z - x)/cos(n))) == \ + y*exp(x/cos(n))*exp(-z/cos(n))/pi assert separatevars((x + y)*(x - y) + y**2 + 2*x + 1) == (x + 1)**2 # 1759 - p=Symbol('p',positive=True) + p = Symbol('p', positive=True) assert separatevars(sqrt(p**2 + x*p**2)) == p*sqrt(1 + x) assert separatevars(sqrt(y*(p**2 + x*p**2))) == p*sqrt(y*(1 + x)) - assert separatevars(sqrt(y*(p**2 + x*p**2)), force=True) == p*sqrt(y)*sqrt(1 + x) + assert separatevars(sqrt(y*(p**2 + x*p**2)), force=True) == \ + p*sqrt(y)*sqrt(1 + x) # 1766 assert separatevars(sqrt(x*y)).is_Pow assert separatevars(sqrt(x*y), force=True) == sqrt(x)*sqrt(y) # 1858 # any type sequence for symbols is fine - assert separatevars(((2*x+2)*y), dict=True, symbols=()) == {'coeff': 1, x: 2*x + 2, y: y} + assert separatevars(((2*x + 2)*y), dict=True, symbols=()) == \ + {'coeff': 1, x: 2*x + 2, y: y} # separable - assert separatevars(((2*x+2)*y), dict=True, symbols=[x]) == {'coeff': y, x: 2*x + 2} - assert separatevars(((2*x+2)*y), dict=True, symbols=[]) == {'coeff': 1, x: 2*x + 2, y: y} - assert separatevars(((2*x+2)*y), dict=True) == {'coeff': 1, x: 2*x + 2, y: y} - assert separatevars(((2*x+2)*y), dict=True, symbols=None) == {'coeff': y*(2*x + 2)} + assert separatevars(((2*x + 2)*y), dict=True, symbols=[x]) == \ + {'coeff': y, x: 2*x + 2} + assert separatevars(((2*x + 2)*y), dict=True, symbols=[]) == \ + {'coeff': 1, x: 2*x + 2, y: y} + assert separatevars(((2*x + 2)*y), dict=True) == \ + {'coeff': 1, x: 2*x + 2, y: y} + assert separatevars(((2*x + 2)*y), dict=True, symbols=None) == \ + {'coeff': y*(2*x + 2)} # not separable assert separatevars(3, dict=True) is None - assert separatevars(2*x+y, dict=True, symbols=()) is None - assert separatevars(2*x+y, dict=True) is None - assert separatevars(2*x+y, dict=True, symbols=None) == {'coeff': 2*x + y} + assert separatevars(2*x + y, dict=True, symbols=()) is None + assert separatevars(2*x + y, dict=True) is None + assert separatevars(2*x + y, dict=True, symbols=None) == {'coeff': 2*x + y} # 1709 n, m = symbols('n,m', commutative=False) assert separatevars(m + n*m) == (1 + n)*m @@ -673,13 +987,18 @@ eq = x*(1 + hyper((), (), y*z)) assert separatevars(eq) == eq + def test_separatevars_advanced_factor(): - x,y,z = symbols('x,y,z') - assert separatevars(1 + log(x)*log(y) + log(x) + log(y)) == (log(x) + 1)*(log(y) + 1) - assert separatevars(1 + x - log(z) - x*log(z) - exp(y)*log(z) - x*exp(y)*log(z) + x*exp(y) + exp(y)) == \ + x, y, z = symbols('x,y,z') + assert separatevars(1 + log(x)*log(y) + log(x) + log(y)) == \ + (log(x) + 1)*(log(y) + 1) + assert separatevars(1 + x - log(z) - x*log(z) - exp(y)*log(z) - + x*exp(y)*log(z) + x*exp(y) + exp(y)) == \ -((x + 1)*(log(z) - 1)*(exp(y) + 1)) x, y = symbols('x,y', positive=True) - assert separatevars(1 + log(x**log(y)) + log(x*y)) == (log(x) + 1)*(log(y) + 1) + assert separatevars(1 + log(x**log(y)) + log(x*y)) == \ + (log(x) + 1)*(log(y) + 1) + def test_hypersimp(): n, k = symbols('n,k', integer=True) @@ -689,19 +1008,20 @@ assert hypersimp(1/factorial(k), k) == 1/(k + 1) - assert hypersimp(2**k/factorial(k)**2, k) == 2/(k**2 + 2*k + 1) + assert hypersimp(2**k/factorial(k)**2, k) == 2/(k + 1)**2 - assert hypersimp(binomial(n, k), k) == (n-k)/(k+1) - assert hypersimp(binomial(n+1, k), k) == (n-k+1)/(k+1) + assert hypersimp(binomial(n, k), k) == (n - k)/(k + 1) + assert hypersimp(binomial(n + 1, k), k) == (n - k + 1)/(k + 1) - term = (4*k+1)*factorial(k)/factorial(2*k+1) + term = (4*k + 1)*factorial(k)/factorial(2*k + 1) assert hypersimp(term, k) == (S(1)/2)*((4*k + 5)/(3 + 14*k + 8*k**2)) - term = 1/((2*k-1)*factorial(2*k+1)) - assert hypersimp(term, k) == (2*k - 1)/(3 + 11*k + 12*k**2 + 4*k**3)/2 + term = 1/((2*k - 1)*factorial(2*k + 1)) + assert hypersimp(term, k) == (k - S(1)/2)/((k + 1)*(2*k + 1)*(2*k + 3)) term = binomial(n, k)*(-1)**k/factorial(k) - assert hypersimp(term, k) == (k - n)/(k**2 + 2*k + 1) + assert hypersimp(term, k) == (k - n)/(k + 1)**2 + def test_nsimplify(): x = Symbol("x") @@ -711,29 +1031,49 @@ assert nsimplify(1 + x) == 1 + x assert nsimplify(2.7) == Rational(27, 10) assert nsimplify(1 - GoldenRatio) == (1 - sqrt(5))/2 - assert nsimplify((1+sqrt(5))/4, [GoldenRatio]) == GoldenRatio/2 + assert nsimplify((1 + sqrt(5))/4, [GoldenRatio]) == GoldenRatio/2 assert nsimplify(2/GoldenRatio, [GoldenRatio]) == 2*GoldenRatio - 2 - assert nsimplify(exp(5*pi*I/3, evaluate=False)) == sympify('1/2 - sqrt(3)*I/2') - assert nsimplify(sin(3*pi/5, evaluate=False)) == sympify('sqrt(sqrt(5)/8 + 5/8)') - assert nsimplify(sqrt(atan('1', evaluate=False))*(2+I), [pi]) == sqrt(pi) + sqrt(pi)/2*I + assert nsimplify(exp(5*pi*I/3, evaluate=False)) == \ + sympify('1/2 - sqrt(3)*I/2') + assert nsimplify(sin(3*pi/5, evaluate=False)) == \ + sympify('sqrt(sqrt(5)/8 + 5/8)') + assert nsimplify(sqrt(atan('1', evaluate=False))*(2 + I), [pi]) == \ + sqrt(pi) + sqrt(pi)/2*I assert nsimplify(2 + exp(2*atan('1/4')*I)) == sympify('49/17 + 8*I/17') assert nsimplify(pi, tolerance=0.01) == Rational(22, 7) assert nsimplify(pi, tolerance=0.001) == Rational(355, 113) assert nsimplify(0.33333, tolerance=1e-4) == Rational(1, 3) assert nsimplify(2.0**(1/3.), tolerance=0.001) == Rational(635, 504) - assert nsimplify(2.0**(1/3.), tolerance=0.001, full=True) == 2**Rational(1, 3) + assert nsimplify(2.0**(1/3.), tolerance=0.001, full=True) == \ + 2**Rational(1, 3) assert nsimplify(x + .5, rational=True) == Rational(1, 2) + x assert nsimplify(1/.3 + x, rational=True) == Rational(10, 3) + x assert nsimplify(log(3).n(), rational=True) == \ - sympify('109861228866811/100000000000000') - assert nsimplify(Float(0.272198261287950), [pi,log(2)]) == pi*log(2)/8 - assert nsimplify(Float(0.272198261287950).n(3), [pi,log(2)]) == \ + sympify('109861228866811/100000000000000') + assert nsimplify(Float(0.272198261287950), [pi, log(2)]) == pi*log(2)/8 + assert nsimplify(Float(0.272198261287950).n(3), [pi, log(2)]) == \ -pi/4 - log(2) + S(7)/4 assert nsimplify(x/7.0) == x/7 assert nsimplify(pi/1e2) == pi/100 assert nsimplify(pi/1e2, rational=False) == pi/100.0 assert nsimplify(pi/1e-7) == 10000000*pi - assert not nsimplify(factor(-3.0*z**2*(z**2)**(-2.5) + 3*(z**2)**(-1.5))).atoms(Float) + assert not nsimplify( + factor(-3.0*z**2*(z**2)**(-2.5) + 3*(z**2)**(-1.5))).atoms(Float) + e = x**0.0 + assert e.is_Pow and nsimplify(x**0.0) == 1 + assert nsimplify(3.333333, tolerance=0.1, rational=True) == Rational(10, 3) + assert nsimplify(3.333333, tolerance=0.01, rational=True) == Rational(10, 3) + assert nsimplify(3.666666, tolerance=0.1, rational=True) == Rational(11, 3) + assert nsimplify(3.666666, tolerance=0.01, rational=True) == Rational(11, 3) + assert nsimplify(33, tolerance=10, rational=True) == Rational(33) + assert nsimplify(33.33, tolerance=10, rational=True) == Rational(30) + assert nsimplify(37.76, tolerance=10, rational=True) == Rational(40) + assert nsimplify(-203.1) == -S(2031)/10 + assert nsimplify(.2, tolerance=0) == S.One/5 + assert nsimplify(-.2, tolerance=0) == -S.One/5 + assert nsimplify(.2222, tolerance=0) == S(1111)/5000 + assert nsimplify(-.2222, tolerance=0) == -S(1111)/5000 + def test_extract_minus_sign(): x = Symbol("x") @@ -746,63 +1086,62 @@ assert simplify(x/-y) == -x/y assert simplify(-x/0) == -oo*x assert simplify(S(-5)/0) == -oo - assert simplify(-a*x/(-y-b)) == a*x/(b + y) + assert simplify(-a*x/(-y - b)) == a*x/(b + y) + def test_diff(): x = Symbol("x") y = Symbol("y") f = Function("f") g = Function("g") - assert simplify(g(x).diff(x)*f(x).diff(x)-f(x).diff(x)*g(x).diff(x)) == 0 - assert simplify(2*f(x)*f(x).diff(x)-diff(f(x)**2, x)) == 0 - assert simplify(diff(1/f(x), x)+f(x).diff(x)/f(x)**2) == 0 - assert simplify(f(x).diff(x, y)-f(x).diff(y, x)) == 0 + assert simplify(g(x).diff(x)*f(x).diff(x) - f(x).diff(x)*g(x).diff(x)) == 0 + assert simplify(2*f(x)*f(x).diff(x) - diff(f(x)**2, x)) == 0 + assert simplify(diff(1/f(x), x) + f(x).diff(x)/f(x)**2) == 0 + assert simplify(f(x).diff(x, y) - f(x).diff(y, x)) == 0 + def test_logcombine_1(): x, y = symbols("x,y") a = Symbol("a") z, w = symbols("z,w", positive=True) b = Symbol("b", real=True) - assert logcombine(log(x)+2*log(y)) == log(x) + 2*log(y) - assert logcombine(log(x)+2*log(y), force=True) == log(x*y**2) - assert logcombine(a*log(w)+log(z)) == a*log(w) + log(z) - assert logcombine(b*log(z)+b*log(x)) == log(z**b) + b*log(x) - assert logcombine(b*log(z)-log(w)) == log(z**b/w) + assert logcombine(log(x) + 2*log(y)) == log(x) + 2*log(y) + assert logcombine(log(x) + 2*log(y), force=True) == log(x*y**2) + assert logcombine(a*log(w) + log(z)) == a*log(w) + log(z) + assert logcombine(b*log(z) + b*log(x)) == log(z**b) + b*log(x) + assert logcombine(b*log(z) - log(w)) == log(z**b/w) assert logcombine(log(x)*log(z)) == log(x)*log(z) assert logcombine(log(w)*log(x)) == log(w)*log(x) - assert logcombine(cos(-2*log(z)+b*log(w))) in [cos(log(w**b/z**2)), + assert logcombine(cos(-2*log(z) + b*log(w))) in [cos(log(w**b/z**2)), cos(log(z**2/w**b))] - assert logcombine(log(log(x)-log(y))-log(z), force=True) == \ - log(log((x/y)**(1/z))) - assert logcombine((2+I)*log(x), force=True) == I*log(x)+log(x**2) - assert logcombine((x**2+log(x)-log(y))/(x*y), force=True) == \ - log(x**(1/(x*y))*y**(-1/(x*y)))+x/y - assert logcombine(log(x)*2*log(y)+log(z), force=True) == \ + assert logcombine(log(log(x) - log(y)) - log(z), force=True) == \ + log(log(x/y)/z) + assert logcombine((2 + I)*log(x), force=True) == (2 + I)*log(x) + assert logcombine((x**2 + log(x) - log(y))/(x*y), force=True) == \ + (x**2 + log(x/y))/(x*y) + # the following could also give log(z*x**log(y**2)), what we + # are testing is that a canonical result is obtained + assert logcombine(log(x)*2*log(y) + log(z), force=True) == \ log(z*y**log(x**2)) - assert logcombine((x*y+sqrt(x**4+y**4)+log(x)-log(y))/(pi*x**Rational(2, 3)*\ - sqrt(y)**3), force=True) == \ - log(x**(1/(pi*x**Rational(2, 3)*sqrt(y)**3))*y**(-1/(pi*\ - x**Rational(2, 3)*sqrt(y)**3))) + sqrt(x**4 + y**4)/(pi*\ - x**Rational(2, 3)*sqrt(y)**3) + x**Rational(1, 3)/(pi*sqrt(y)) - assert logcombine(Eq(log(x), -2*log(y)), force=True) == \ - Eq(log(x*y**2), Integer(0)) - assert logcombine(Eq(y, x*acos(-log(x/y))), force=True) == \ - Eq(y, x*acos(log(y/x))) + assert logcombine((x*y + sqrt(x**4 + y**4) + log(x) - log(y))/(pi*x**Rational(2, 3)* + sqrt(y)**3), force=True) == ( + x*y + sqrt(x**4 + y**4) + log(x/y))/(pi*x**(S(2)/3)*y**(S(3)/2)) assert logcombine(gamma(-log(x/y))*acos(-log(x/y)), force=True) == \ - acos(log(y/x))*gamma(log(y/x)) - assert logcombine((2+3*I)*log(x), force=True) == \ - log(x**2)+3*I*log(x) - assert logcombine(Eq(y, -log(x)), force=True) == Eq(y, log(1/x)) + acos(-log(x/y))*gamma(-log(x/y)) + + assert logcombine(2*log(z)*log(w)*log(x) + log(z) + log(w)) == \ + log(z**log(w**2))*log(x) + log(w*z) + assert logcombine(3*log(w) + 3*log(z)) == log(w**3*z**3) + assert logcombine(x*(y + 1) + log(2) + log(3)) == x*(y + 1) + log(6) + assert logcombine((x + y)*log(w) + (-x - y)*log(3)) == (x + y)*log(w/3) + -@XFAIL def test_logcombine_complex_coeff(): - # TODO: Make the expand() call in logcombine smart enough so that both - # these hold. - assert logcombine(Integral((sin(x**2)+cos(x**3))/x, x), force=True) == \ - Integral((sin(x**2)+cos(x**3))/x, x) - assert logcombine(Integral((sin(x**2)+cos(x**3))/x, x)+ (2+3*I)*log(x), \ - force=True) == log(x**2)+3*I*log(x) + \ - Integral((sin(x**2)+cos(x**3))/x, x) + i = Integral((sin(x**2) + cos(x**3))/x, x) + assert logcombine(i, force=True) == i + assert logcombine(i + 2*log(x), force=True) == \ + i + log(x**2) + def test_posify(): from sympy.abc import x @@ -827,6 +1166,7 @@ assert str(modified) == '[_x, n, p]' assert [w.subs(reps) for w in modified] == orig + def test_powdenest(): from sympy import powdenest from sympy.abc import x, y, z, a, b @@ -835,20 +1175,22 @@ assert powdenest(x) == x assert powdenest(x + 2*(x**(2*a/3))**(3*x)) == (x + 2*(x**(2*a/3))**(3*x)) - assert powdenest((exp(2*a/3))**(3*x)) # -X-> (exp(a/3))**(6*x) + assert powdenest((exp(2*a/3))**(3*x)) # -X-> (exp(a/3))**(6*x) assert powdenest((x**(2*a/3))**(3*x)) == ((x**(2*a/3))**(3*x)) assert powdenest(exp(3*x*log(2))) == 2**(3*x) assert powdenest(sqrt(p**2)) == p i, j = symbols('i,j', integer=True) eq = p**(2*i)*q**(4*i) assert powdenest(eq) == (p*q**2)**(2*i) - assert powdenest((x**x)**(i + j)) # -X-> (x**x)**i*(x**x)**j == x**(x*(i + j)) + # -X-> (x**x)**i*(x**x)**j == x**(x*(i + j)) + assert powdenest((x**x)**(i + j)) assert powdenest(exp(3*y*log(x))) == x**(3*y) assert powdenest(exp(y*(log(a) + log(b)))) == (a*b)**y assert powdenest(exp(3*(log(a) + log(b)))) == a**3*b**3 assert powdenest(((x**(2*i))**(3*y))**x) == ((x**(2*i))**(3*y))**x assert powdenest(((x**(2*i))**(3*y))**x, force=True) == x**(6*i*x*y) - assert powdenest(((x**(2*a/3))**(3*y/i))**x) == (((x**(2*a/3))**(3*y/i))**x) + assert powdenest(((x**(2*a/3))**(3*y/i))**x) == \ + (((x**(2*a/3))**(3*y/i))**x) assert powdenest((x**(2*i)*y**(4*i))**z, force=True) == (x*y**2)**(2*i*z) assert powdenest((p**(2*i)*q**(4*i))**j) == (p*q**2)**(2*i*j) assert powdenest(((p**(2*a))**(3*y))**x) == p**(6*a*x*y) @@ -856,11 +1198,14 @@ assert powdenest(e) == e e = (((x**2*y**4)**a)**(x*y))**3 assert powdenest(e) == ((x**2*y**4)**a)**(3*x*y) - assert powdenest((((x**2*y**4)**a)**(x*y)), force=True) == (x*y**2)**(2*a*x*y) - assert powdenest((((x**2*y**4)**a)**(x*y))**3, force=True) == (x*y**2)**(6*a*x*y) + assert powdenest((((x**2*y**4)**a)**(x*y)), force=True) == \ + (x*y**2)**(2*a*x*y) + assert powdenest((((x**2*y**4)**a)**(x*y))**3, force=True) == \ + (x*y**2)**(6*a*x*y) assert powdenest((x**2*y**6)**i) != (x*y**3)**(2*i) x, y = symbols('x,y', positive=True) assert powdenest((x**2*y**6)**i) == (x*y**3)**(2*i) + assert powdenest((x**(2*i/3)*y**(i/2))**(2*i)) == (x**(S(4)/3)*y)**(i**2) assert powdenest(sqrt(x**(2*i)*y**(6*i))) == (x*y**3)**i @@ -868,6 +1213,7 @@ assert powdenest((4**x)**y) == 2**(2*x*y) assert powdenest(4**x*y) == 2**(2*x)*y + def test_powdenest_polar(): x, y, z = symbols('x y z', polar=True) a, b, c = symbols('a b c') @@ -875,23 +1221,27 @@ assert powdenest((x**a*y**b)**c) == x**(a*c)*y**(b*c) assert powdenest(((x**a)**b*y**c)**c) == x**(a*b*c)*y**(c**2) + def test_issue_2706(): - arg = ((gamma(x)*hyper((),(),x))*pi)**2 + arg = ((gamma(x)*hyper((), (), x))*pi)**2 assert powdenest(arg) == (pi*gamma(x)*hyper((), (), x))**2 assert arg.is_positive is None + def test_issue_1095(): # simplify should call cancel from sympy.abc import x, y f = Function('f') - assert simplify((4*x+6*f(y))/(2*x+3*f(y))) == 2 + assert simplify((4*x + 6*f(y))/(2*x + 3*f(y))) == 2 + @XFAIL def test_simplify_float_vs_integer(): # Test for issue 1374: # http://code.google.com/p/sympy/issues/detail?id=1374 - assert simplify(x**2.0-x**2) == 0 - assert simplify(x**2-x**2.0) == 0 + assert simplify(x**2.0 - x**2) == 0 + assert simplify(x**2 - x**2.0) == 0 + def test_combsimp(): from sympy.abc import n, k @@ -905,20 +1255,22 @@ assert combsimp(binomial(3*n + 4, n + 1)/binomial(3*n + 1, n)) == \ S(3)/2*((3*n + 2)*(3*n + 4)/((n + 1)*(2*n + 3))) - assert combsimp(factorial(n)**2/factorial(n - 3)) == factorial(n)*n*(-1 + n)*(-2 + n) - assert combsimp(factorial(n)*binomial(n+1, k+1)/binomial(n, k)) == factorial(n)*(1 + n)/(1 + k) + assert combsimp(factorial(n)**2/factorial(n - 3)) == \ + factorial(n)*n*(-1 + n)*(-2 + n) + assert combsimp(factorial(n)*binomial(n + 1, k + 1)/binomial(n, k)) == \ + factorial(n)*(1 + n)/(1 + k) assert combsimp(binomial(n - 1, k)) == -((-n + k)*binomial(n, k))/n - assert combsimp(binomial(n + 2, k + S(1)/2)) == \ - 4*((n + 1)*(n + 2)*binomial(n, k + S(1)/2))/((2*k - 2*n - 1)*(2*k - 2*n - 3)) + assert combsimp(binomial(n + 2, k + S(1)/2)) == 4*((n + 1)*(n + 2) * + binomial(n, k + S(1)/2))/((2*k - 2*n - 1)*(2*k - 2*n - 3)) assert combsimp(binomial(n + 2, k + 2.0)) == \ -((1.0*n + 2.0)*binomial(n + 1.0, k + 2.0))/(k - n) # coverage tests assert combsimp(factorial(n*(1 + n) - n**2 - n)) == 1 - assert combsimp(binomial(n + k - 2, n)) \ - == k*(k - 1)*binomial(n + k, n)/((n + k)*(n + k - 1)) + assert combsimp(binomial(n + k - 2, n)) == \ + k*(k - 1)*binomial(n + k, n)/((n + k)*(n + k - 1)) i = Symbol('i', integer=True) e = gamma(i + 3) assert combsimp(e) == e @@ -926,14 +1278,34 @@ assert combsimp(e) == e e = gamma(n + S(1)/3)*gamma(n + S(2)/3) assert combsimp(e) == e - assert combsimp(gamma(4*n + S(1)/2)/gamma(2*n - S(3)/4)) \ - == 2**(4*n - S(5)/2)*(8*n - 3)*gamma(2*n + S(3)/4)/sqrt(pi) + assert combsimp(gamma(4*n + S(1)/2)/gamma(2*n - S(3)/4)) == \ + 2**(4*n - S(5)/2)*(8*n - 3)*gamma(2*n + S(3)/4)/sqrt(pi) + + assert combsimp(6*FallingFactorial(-4, n)/factorial(n)) == \ + (-1)**n*(n + 1)*(n + 2)*(n + 3) + assert combsimp(6*FallingFactorial(-4, n - 1)/factorial(n - 1)) == \ + (-1)**(n - 1)*n*(n + 1)*(n + 2) + assert combsimp(6*FallingFactorial(-4, n - 3)/factorial(n - 3)) == \ + (-1)**(n - 3)*n*(n - 1)*(n - 2) + assert combsimp(6*FallingFactorial(-4, -n - 1)/factorial(-n - 1)) == \ + -(-1)**(-n - 1)*n*(n - 1)*(n - 2) + + assert combsimp(6*RisingFactorial(4, n)/factorial(n)) == \ + (n + 1)*(n + 2)*(n + 3) + assert combsimp(6*RisingFactorial(4, n - 1)/factorial(n - 1)) == \ + n*(n + 1)*(n + 2) + assert combsimp(6*RisingFactorial(4, n - 3)/factorial(n - 3)) == \ + n*(n - 1)*(n - 2) + assert combsimp(6*RisingFactorial(4, -n - 1)/factorial(-n - 1)) == \ + -n*(n - 1)*(n - 2) + def test_issue_2516(): aA, Re, a, b, D = symbols('aA Re a b D') - e=((D**3*a + b*aA**3)/Re).expand() + e = ((D**3*a + b*aA**3)/Re).expand() assert collect(e, [aA**3/Re, a]) == e + def test_issue_2629(): b = x*sqrt(y) a = sqrt(b) @@ -946,7 +1318,8 @@ assert powsimp(x*c**3*y) == x*y*c**3 assert powsimp(sqrt(x)*c**3*y) == c**5 assert powsimp(sqrt(x)*a**3*sqrt(y)) == sqrt(x)*sqrt(y)*a**3 - assert powsimp(Mul(sqrt(x)*c**3*sqrt(y), y, evaluate=False)) == sqrt(x)*sqrt(y)**3*c**3 + assert powsimp(Mul(sqrt(x)*c**3*sqrt(y), y, evaluate=False)) == \ + sqrt(x)*sqrt(y)**3*c**3 assert powsimp(a**2*a*x**2*y) == a**7 # symbolic powers work, too @@ -961,51 +1334,52 @@ assert powsimp(a**2*sqrt(a)) == sqrt(a)**5 assert powsimp(a**2*sqrt(sqrt(a))) == sqrt(sqrt(a))**9 + def test_as_content_primitive(): # although the _as_content_primitive methods do not alter the underlying structure, # the as_content_primitive function will touch up the expression and join # bases that would otherwise have not been joined. - assert ((x*(2 + 2*x)*(3*x + 3)**2)).as_content_primitive() ==\ - (18, x*(x + 1)**3) - assert (2 + 2*x + 2*y*(3 + 3*y)).as_content_primitive() ==\ - (2, x + 3*y*(y + 1) + 1) - assert ((2 + 6*x)**2).as_content_primitive() ==\ - (4, (3*x + 1)**2) - assert ((2 + 6*x)**(2*y)).as_content_primitive() ==\ - (1, (_keep_coeff(S(2), (3*x + 1)))**(2*y)) - assert (5 + 10*x + 2*y*(3+3*y)).as_content_primitive() ==\ - (1, 10*x + 6*y*(y + 1) + 5) - assert ((5*(x*(1 + y)) + 2*x*(3 + 3*y))).as_content_primitive() ==\ - (11, x*(y + 1)) - assert ((5*(x*(1 + y)) + 2*x*(3 + 3*y))**2).as_content_primitive() ==\ - (121, x**2*(y + 1)**2) - assert (y**2).as_content_primitive() ==\ - (1, y**2) + assert ((x*(2 + 2*x)*(3*x + 3)**2)).as_content_primitive() == \ + (18, x*(x + 1)**3) + assert (2 + 2*x + 2*y*(3 + 3*y)).as_content_primitive() == \ + (2, x + 3*y*(y + 1) + 1) + assert ((2 + 6*x)**2).as_content_primitive() == \ + (4, (3*x + 1)**2) + assert ((2 + 6*x)**(2*y)).as_content_primitive() == \ + (1, (_keep_coeff(S(2), (3*x + 1)))**(2*y)) + assert (5 + 10*x + 2*y*(3 + 3*y)).as_content_primitive() == \ + (1, 10*x + 6*y*(y + 1) + 5) + assert ((5*(x*(1 + y)) + 2*x*(3 + 3*y))).as_content_primitive() == \ + (11, x*(y + 1)) + assert ((5*(x*(1 + y)) + 2*x*(3 + 3*y))**2).as_content_primitive() == \ + (121, x**2*(y + 1)**2) + assert (y**2).as_content_primitive() == \ + (1, y**2) assert (S.Infinity).as_content_primitive() == (1, oo) - eq = x**(2+y) + eq = x**(2 + y) assert (eq).as_content_primitive() == (1, eq) assert (S.Half**(2 + x)).as_content_primitive() == (S(1)/4, 2**-x) assert ((-S.Half)**(2 + x)).as_content_primitive() == \ - (S(1)/4, (-S.Half)**x) + (S(1)/4, (-S.Half)**x) assert ((-S.Half)**(2 + x)).as_content_primitive() == \ - (S(1)/4, (-S.Half)**x) + (S(1)/4, (-S.Half)**x) assert (4**((1 + y)/2)).as_content_primitive() == (2, 4**(y/2)) assert (3**((1 + y)/2)).as_content_primitive() == \ - (1, 3**(Mul(S(1)/2, 1 + y, evaluate=False))) + (1, 3**(Mul(S(1)/2, 1 + y, evaluate=False))) assert (5**(S(3)/4)).as_content_primitive() == (1, 5**(S(3)/4)) assert (5**(S(7)/4)).as_content_primitive() == (5, 5**(S(3)/4)) assert Add(5*z/7, 0.5*x, 3*y/2, evaluate=False).as_content_primitive() == \ - (S(1)/14, 7.0*x + 21*y + 10*z) + (S(1)/14, 7.0*x + 21*y + 10*z) assert (2**(S(3)/4) + 2**(S(1)/4)*sqrt(3)).as_content_primitive(radical=True) == \ - (1, 2**(S(1)/4)*(sqrt(2) + sqrt(3))) + (1, 2**(S(1)/4)*(sqrt(2) + sqrt(3))) + def test_radsimp(): - r2=sqrt(2) - r3=sqrt(3) - r5=sqrt(5) - r7=sqrt(7) - assert radsimp(1/r2) == \ - sqrt(2)/2 + r2 = sqrt(2) + r3 = sqrt(3) + r5 = sqrt(5) + r7 = sqrt(7) + assert fraction(radsimp(1/r2)) == (sqrt(2), 2) assert radsimp(1/(1 + r2)) == \ -1 + sqrt(2) assert radsimp(1/(r2 + r3)) == \ @@ -1014,101 +1388,224 @@ (-sqrt(6) + sqrt(2) + 2, 4) assert fraction(radsimp(1/(r2 + r3 + r5))) == \ (-sqrt(30) + 2*sqrt(3) + 3*sqrt(2), 12) - assert fraction(radsimp(1/(1 + r2 + r3 + r5))) == \ - (-34*sqrt(10) - - 26*sqrt(15) - - 55*sqrt(3) - - 61*sqrt(2) + - 14*sqrt(30) + - 93 + - 46*sqrt(6) + - 53*sqrt(5), 71) - assert fraction(radsimp(1/(r2 + r3 + r5 + r7))) == \ - (-50*sqrt(42) - 133*sqrt(5) - 34*sqrt(70) - - 145*sqrt(3) + 22*sqrt(105) + 185*sqrt(2) + - 62*sqrt(30) + 135*sqrt(7), 215) + assert fraction(radsimp(1/(1 + r2 + r3 + r5))) == ( + (-34*sqrt(10) - 26*sqrt(15) - 55*sqrt(3) - 61*sqrt(2) + 14*sqrt(30) + + 93 + 46*sqrt(6) + 53*sqrt(5), 71)) + assert fraction(radsimp(1/(r2 + r3 + r5 + r7))) == ( + (-50*sqrt(42) - 133*sqrt(5) - 34*sqrt(70) - 145*sqrt(3) + 22*sqrt(105) + + 185*sqrt(2) + 62*sqrt(30) + 135*sqrt(7), 215)) z = radsimp(1/(1 + r2/3 + r3/5 + r5 + r7)) assert len((3616791619821680643598*z).args) == 16 assert radsimp(1/z) == 1/z assert radsimp(1/z, max_terms=20).expand() == 1 + r2/3 + r3/5 + r5 + r7 assert radsimp(1/(r2*3)) == \ sqrt(2)/6 - assert radsimp(1/(r2*a + r3 + r5 + r7)) == 1/(r2*a + r3 + r5 + r7) - assert radsimp(1/(r2*a + r2*b + r3 + r7)) == \ - ((sqrt(42)*(a + b) + - sqrt(3)*(-a**2 - 2*a*b - b**2 - 2) + - sqrt(7)*(-a**2 - 2*a*b - b**2 + 2) + - sqrt(2)*(a**3 + 3*a**2*b + 3*a*b**2 - 5*a + b**3 - 5*b))/ - ((a**4 + 4*a**3*b + 6*a**2*b**2 - 10*a**2 + - 4*a*b**3 - 20*a*b + b**4 - 10*b**2 + 4)))/2 + assert radsimp(1/(r2*a + r3 + r5 + r7)) == ( + (8*sqrt(2)*a**7 - 8*sqrt(7)*a**6 - 8*sqrt(5)*a**6 - 8*sqrt(3)*a**6 - + 180*sqrt(2)*a**5 + 8*sqrt(30)*a**5 + 8*sqrt(42)*a**5 + 8*sqrt(70)*a**5 + - 24*sqrt(105)*a**4 + 84*sqrt(3)*a**4 + 100*sqrt(5)*a**4 + + 116*sqrt(7)*a**4 - 72*sqrt(70)*a**3 - 40*sqrt(42)*a**3 - + 8*sqrt(30)*a**3 + 782*sqrt(2)*a**3 - 462*sqrt(3)*a**2 - + 302*sqrt(7)*a**2 - 254*sqrt(5)*a**2 + 120*sqrt(105)*a**2 - + 795*sqrt(2)*a - 62*sqrt(30)*a + 82*sqrt(42)*a + 98*sqrt(70)*a - + 118*sqrt(105) + 59*sqrt(7) + 295*sqrt(5) + 531*sqrt(3))/(16*a**8 - + 480*a**6 + 3128*a**4 - 6360*a**2 + 3481)) + assert radsimp(1/(r2*a + r2*b + r3 + r7)) == ( + (sqrt(2)*a*(a + b)**2 - 5*sqrt(2)*a + sqrt(42)*a + sqrt(2)*b*(a + + b)**2 - 5*sqrt(2)*b + sqrt(42)*b - sqrt(7)*(a + b)**2 - sqrt(3)*(a + + b)**2 - 2*sqrt(3) + 2*sqrt(7))/(2*a**4 + 8*a**3*b + 12*a**2*b**2 - + 20*a**2 + 8*a*b**3 - 40*a*b + 2*b**4 - 20*b**2 + 8)) assert radsimp(1/(r2*a + r2*b + r2*c + r2*d)) == \ - (sqrt(2)/(a + b + c + d))/2 - assert radsimp(1/(1 + r2*a + r2*b + r2*c + r2*d)) == \ - ((sqrt(2)*(-a - b - c - d) + 1)/ - (-2*a**2 - 4*a*b - 4*a*c - 4*a*d - 2*b**2 - - 4*b*c - 4*b*d - 2*c**2 - 4*c*d - 2*d**2 + 1)) + sqrt(2)/(2*a + 2*b + 2*c + 2*d) + assert radsimp(1/(1 + r2*a + r2*b + r2*c + r2*d)) == ( + (sqrt(2)*a + sqrt(2)*b + sqrt(2)*c + sqrt(2)*d - 1)/(2*a**2 + 4*a*b + + 4*a*c + 4*a*d + 2*b**2 + 4*b*c + 4*b*d + 2*c**2 + 4*c*d + 2*d**2 - 1)) assert radsimp((y**2 - x)/(y - sqrt(x))) == \ sqrt(x) + y assert radsimp(-(y**2 - x)/(y - sqrt(x))) == \ -(sqrt(x) + y) assert radsimp(1/(1 - I + a*I)) == \ - (I*(-a + 1) + 1)/(a**2 - 2*a + 2) - assert radsimp(1/((-x + y)*(x - sqrt(y)))) == (x + sqrt(y))/((-x + y)*(x**2 - y)) + (-I*a + 1 + I)/(a**2 - 2*a + 2) + assert radsimp(1/((-x + y)*(x - sqrt(y)))) == \ + (-x - sqrt(y))/((x - y)*(x**2 - y)) e = (3 + 3*sqrt(2))*x*(3*x - 3*sqrt(y)) - assert radsimp(e) == 9*x*(1 + sqrt(2))*(x - sqrt(y)) - assert radsimp(1/e) == (-1 + sqrt(2))*(x + sqrt(y))/(9*x*(x**2 - y)) - assert radsimp(1 + 1/(1 + sqrt(3))) == Mul(S(1)/2, 1 + sqrt(3), evaluate=False) + assert radsimp(e) == x*(3 + 3*sqrt(2))*(3*x - 3*sqrt(y)) + assert radsimp(1/e) == ( + (-9*x + 9*sqrt(2)*x - 9*sqrt(y) + 9*sqrt(2)*sqrt(y))/(9*x*(9*x**2 - + 9*y))) + assert radsimp(1 + 1/(1 + sqrt(3))) == \ + Mul(S.Half, -1 + sqrt(3), evaluate=False) + 1 A = symbols("A", commutative=False) - assert radsimp(x**2 + sqrt(2)*x**2 - sqrt(2)*x*A) == x**2 + sqrt(2)*(x**2 - x*A) + assert radsimp(x**2 + sqrt(2)*x**2 - sqrt(2)*x*A) == \ + x**2 + sqrt(2)*x**2 - sqrt(2)*x*A assert radsimp(1/sqrt(5 + 2 * sqrt(6))) == -sqrt(2) + sqrt(3) - assert radsimp(1/sqrt(5 + 2 * sqrt(6))**3) == -11*sqrt(2) + 9*sqrt(3) + assert radsimp(1/sqrt(5 + 2 * sqrt(6))**3) == -(-sqrt(3) + sqrt(2))**3 + + # issue 3433 + assert fraction(radsimp(1/sqrt(x))) == (sqrt(x), x) + assert fraction(radsimp(1/sqrt(2*x + 3))) == (sqrt(2*x + 3), 2*x + 3) + assert fraction(radsimp(1/sqrt(2*(x + 3)))) == (sqrt(2*x + 6), 2*x + 6) + + # issue 2895 + e = S('-(2 + 2*sqrt(2) + 4*2**(1/4))/' + '(1 + 2**(3/4) + 3*2**(1/4) + 3*sqrt(2))') + assert radsimp(e).expand() == -2*2**(S(3)/4) - 2*2**(S(1)/4) + 2 + 2*sqrt(2) + + # issue 2887 (modifications to radimp didn't initially recognize this so + # the test is included here) + assert radsimp(1/(-sqrt(5)/2 - S(1)/2 + (-sqrt(5)/2 - S(1)/2)**2)) == 1 + + # from issue 2835 + eq = ( + (-240*sqrt(2)*sqrt(sqrt(5) + 5)*sqrt(8*sqrt(5) + 40) - + 360*sqrt(2)*sqrt(-8*sqrt(5) + 40)*sqrt(-sqrt(5) + 5) - + 120*sqrt(10)*sqrt(-8*sqrt(5) + 40)*sqrt(-sqrt(5) + 5) + + 120*sqrt(2)*sqrt(-sqrt(5) + 5)*sqrt(8*sqrt(5) + 40) + + 120*sqrt(2)*sqrt(-8*sqrt(5) + 40)*sqrt(sqrt(5) + 5) + + 120*sqrt(10)*sqrt(-sqrt(5) + 5)*sqrt(8*sqrt(5) + 40) + + 120*sqrt(10)*sqrt(-8*sqrt(5) + 40)*sqrt(sqrt(5) + 5))/(-36000 - + 7200*sqrt(5) + (12*sqrt(10)*sqrt(sqrt(5) + 5) + + 24*sqrt(10)*sqrt(-sqrt(5) + 5))**2)) + assert radsimp(eq) is S.NaN # it's 0/0 + + # work with normal form + e = 1/sqrt(sqrt(7)/7 + 2*sqrt(2) + 3*sqrt(3) + 5*sqrt(5)) + 3 + assert radsimp(e) == ( + -sqrt(sqrt(7) + 14*sqrt(2) + 21*sqrt(3) + + 35*sqrt(5))*(-11654899*sqrt(35) - 1577436*sqrt(210) - 1278438*sqrt(15) + - 1346996*sqrt(10) + 1635060*sqrt(6) + 5709765 + 7539830*sqrt(14) + + 8291415*sqrt(21))/1300423175 + 3) + + # obey power rules + base = sqrt(3) - sqrt(2) + assert radsimp(1/base**3) == (sqrt(3) + sqrt(2))**3 + assert radsimp(1/(-base)**3) == -(sqrt(2) + sqrt(3))**3 + assert radsimp(1/(-base)**x) == (-base)**(-x) + assert radsimp(1/base**x) == (sqrt(2) + sqrt(3))**x + assert radsimp(root(1/(-1 - sqrt(2)), -x)) == (-1)**(-1/x)*(1 + sqrt(2))**(1/x) + + # recurse + e = cos(1/(1 + sqrt(2))) + assert radsimp(e) == cos(-sqrt(2) + 1) + assert radsimp(e/2) == cos(-sqrt(2) + 1)/2 + assert radsimp(1/e) == 1/cos(-sqrt(2) + 1) + assert radsimp(2/e) == 2/cos(-sqrt(2) + 1) + + # test that symbolic denominators are not processed + r = 1 + sqrt(2) + assert radsimp(x/r, symbolic=False) == -x*(-sqrt(2) + 1) + assert radsimp(x/(y + r), symbolic=False) == x/(y + 1 + sqrt(2)) + assert radsimp(x/(y + r)/r, symbolic=False) == \ + -x*(-sqrt(2) + 1)/(y + 1 + sqrt(2)) + +def test_radsimp_issue_3214(): + c, p = symbols('c p', positive=True) + s = sqrt(c**2 - p**2) + b = (c + I*p - s)/(c + I*p + s) + assert radsimp(b) == -I*(c + I*p - sqrt(c**2 - p**2))**2/(2*c*p) + + +def test_collect_const(): # coverage not provided by above tests - assert collect_const(2*sqrt(3) + 4*a*sqrt(5)) == Mul(2, (2*sqrt(5)*a + sqrt(3)), evaluate=False) - assert collect_const(2*sqrt(3) + 4*a*sqrt(5), sqrt(3)) == 2*(2*sqrt(5)*a + sqrt(3)) + assert collect_const(2*sqrt(3) + 4*a*sqrt(5)) == \ + 2*(2*sqrt(5)*a + sqrt(3)) # let the primitive reabsorb + assert collect_const(2*sqrt(3) + 4*a*sqrt(5), sqrt(3)) == \ + 2*sqrt(3) + 4*a*sqrt(5) assert collect_const(sqrt(2)*(1 + sqrt(2)) + sqrt(3) + x*sqrt(2)) == \ sqrt(2)*(x + 1 + sqrt(2)) + sqrt(3) + # issue 2191 + assert collect_const(2*x + 2*y + 1, 2) == \ + collect_const(2*x + 2*y + 1) == \ + Add(S(1), Mul(2, x + y, evaluate=False), evaluate=False) + assert collect_const(-y - z) == Mul(-1, y + z, evaluate=False) + assert collect_const(2*x - 2*y - 2*z, 2) == \ + Mul(2, x - y - z, evaluate=False) + assert collect_const(2*x - 2*y - 2*z, -2) == \ + _unevaluated_Add(2*x, Mul(-2, y + z, evaluate=False)) + + # this is why the content_primitive is used + eq = (sqrt(15 + 5*sqrt(2))*x + sqrt(3 + sqrt(2))*y)*2 + assert collect_sqrt(eq + 2) == \ + 2*sqrt(sqrt(2) + 3)*(sqrt(5)*x + y) + 2 + + def test_issue2834(): from sympy import Polygon, RegularPolygon, denom x = Polygon(*RegularPolygon((0, 0), 1, 5).vertices).centroid.x assert abs(denom(x).n()) > 1e-12 - assert abs(denom(radsimp(x))) > 1e-12 # in case simplify didn't handle it + assert abs(denom(radsimp(x))) > 1e-12 # in case simplify didn't handle it + def test_fraction_expand(): eq = (x + y)*y/x assert eq.expand(frac=True) == fraction_expand(eq) == (x*y + y**2)/x assert eq.expand() == y + y**2/x + def test_combsimp_gamma(): from sympy.abc import x, y + R = Rational + assert combsimp(gamma(x)) == gamma(x) - assert combsimp(gamma(x+1)/x) == gamma(x) - assert combsimp(gamma(x)/(x-1)) == gamma(x-1) + assert combsimp(gamma(x + 1)/x) == gamma(x) + assert combsimp(gamma(x)/(x - 1)) == gamma(x - 1) assert combsimp(x*gamma(x)) == gamma(x + 1) - assert combsimp((x+1)*gamma(x+1)) == gamma(x + 2) - assert combsimp(gamma(x+y)*(x+y)) == gamma(x + y + 1) - assert combsimp(x/gamma(x+1)) == 1/gamma(x) - assert combsimp((x+1)**2/gamma(x+2)) == (x + 1)/gamma(x + 1) - assert combsimp(x*gamma(x) + gamma(x+3)/(x+2)) == gamma(x+1) + gamma(x+2) + assert combsimp((x + 1)*gamma(x + 1)) == gamma(x + 2) + assert combsimp(gamma(x + y)*(x + y)) == gamma(x + y + 1) + assert combsimp(x/gamma(x + 1)) == 1/gamma(x) + assert combsimp((x + 1)**2/gamma(x + 2)) == (x + 1)/gamma(x + 1) + assert combsimp(x*gamma(x) + gamma(x + 3)/(x + 2)) == \ + (x + 2)*gamma(x + 1) assert combsimp(gamma(2*x)*x) == gamma(2*x + 1)/2 assert combsimp(gamma(2*x)/(x - S(1)/2)) == 2*gamma(2*x - 1) - assert combsimp(gamma(x)*gamma(1-x)) == pi/sin(pi*x) + assert combsimp(gamma(x)*gamma(1 - x)) == pi/sin(pi*x) assert combsimp(gamma(x)*gamma(-x)) == -pi/(x*sin(pi*x)) - assert combsimp(1/gamma(x+3)/gamma(1-x)) == sin(pi*x)/(pi*x*(x+1)*(x+2)) + assert combsimp(1/gamma(x + 3)/gamma(1 - x)) == \ + sin(pi*x)/(pi*x*(x + 1)*(x + 2)) - assert simplify(combsimp(gamma(x)*gamma(x+S(1)/2)*gamma(y)/gamma(x+y))) \ - == 2*4**-x*sqrt(pi)*gamma(2*x)*gamma(y)/gamma(x + y) - assert combsimp(1/gamma(x)/gamma(x-S(1)/3)/gamma(x+S(1)/3)) \ - == 3**(3*x - S(3)/2)/(2*pi*gamma(3*x - 1)) - assert simplify(gamma(S(1)/2 + x/2)*gamma(1 + x/2)/gamma(1+x)/sqrt(pi)*2**x) \ - == 1 + assert powsimp(combsimp( + gamma(x)*gamma(x + S(1)/2)*gamma(y)/gamma(x + y))) == \ + 2**(-2*x + 1)*sqrt(pi)*gamma(2*x)*gamma(y)/gamma(x + y) + assert combsimp(1/gamma(x)/gamma(x - S(1)/3)/gamma(x + S(1)/3)) == \ + 3**(3*x - S(3)/2)/(2*pi*gamma(3*x - 1)) + assert simplify( + gamma(S(1)/2 + x/2)*gamma(1 + x/2)/gamma(1 + x)/sqrt(pi)*2**x) == 1 assert combsimp(gamma(S(-1)/4)*gamma(S(-3)/4)) == 16*sqrt(2)*pi/3 - assert simplify(combsimp(gamma(2*x)/gamma(x))) == \ - 4**x*gamma(x + S(1)/2)/sqrt(pi)/2 + assert powsimp(combsimp(gamma(2*x)/gamma(x))) == \ + 2**(2*x - 1)*gamma(x + S(1)/2)/sqrt(pi) + + # issue 3693 + e = (-gamma(k)*gamma(k + 2) + gamma(k + 1)**2)/gamma(k)**2 + assert combsimp(e) == -k + assert combsimp(1/e) == -1/k + e = (gamma(x) + gamma(x + 1))/gamma(x) + assert combsimp(e) == x + 1 + assert combsimp(1/e) == 1/(x + 1) + e = (gamma(x) + gamma(x + 2))*(gamma(x - 1) + gamma(x))/gamma(x) + assert combsimp(e) == (x**2 + x + 1)*gamma(x + 1)/(x - 1) + e = (-gamma(k)*gamma(k + 2) + gamma(k + 1)**2)/gamma(k)**2 + assert combsimp(e**2) == k**2 + assert combsimp(e**2/gamma(k + 1)) == k/gamma(k) + a = R(1, 2) + R(1, 3) + b = a + R(1, 3) + assert combsimp(gamma(2*k)/gamma(k)*gamma(k + a)*gamma(k + b)) + 3*2**(2*k + 1)*3**(-3*k - 2)*sqrt(pi)*gamma(3*k + R(3, 2))/2 + + A, B = symbols('A B', commutative=False) + assert combsimp(e*B*A) == combsimp(e)*B*A + + # check iteration + assert combsimp(gamma(2*k)/gamma(k)*gamma(-k - R(1, 2))) == ( + -2**(2*k + 1)*sqrt(pi)/(2*((2*k + 1)*cos(pi*k)))) + assert combsimp( + gamma(k)*gamma(k + R(1, 3))*gamma(k + R(2, 3))/gamma(3*k/2)) == ( + 3*2**(3*k + 1)*3**(-3*k - S.Half)*sqrt(pi)*gamma(3*k/2 + S.Half)/2) + def test_polarify(): from sympy import polar_lift, polarify @@ -1138,11 +1635,13 @@ # Make sure polarify(lift=True) doesn't try to lift the integration # variable - assert polarify(Integral(sqrt(2)*x*exp(-(-mu + x)**2/(2*sigma**2))/(2*sqrt(pi)*sigma), + assert polarify( + Integral(sqrt(2)*x*exp(-(-mu + x)**2/(2*sigma**2))/(2*sqrt(pi)*sigma), (x, -oo, oo)), lift=True) == Integral(sqrt(2)*(sigma*exp_polar(0))**exp_polar(I*pi)* exp((sigma*exp_polar(0))**(2*exp_polar(I*pi))*exp_polar(I*pi)*polar_lift(-mu + x)** (2*exp_polar(0))/2)*exp_polar(0)*polar_lift(x)/(2*sqrt(pi)), (x, -oo, oo)) + def test_unpolarify(): from sympy import (exp_polar, polar_lift, exp, unpolarify, sin, principal_branch) @@ -1176,8 +1675,9 @@ assert unpolarify(uppergamma(x, p)) == uppergamma(x, p) assert unpolarify(uppergamma(sin(p), sin(p + exp_polar(0)))) == \ - uppergamma(sin(u), sin(u + 1)) - assert unpolarify(uppergamma(polar_lift(0), 2*exp_polar(0))) == uppergamma(0, 2) + uppergamma(sin(u), sin(u + 1)) + assert unpolarify(uppergamma(polar_lift(0), 2*exp_polar(0))) == \ + uppergamma(0, 2) assert unpolarify(Eq(p, 0)) == Eq(u, 0) assert unpolarify(Ne(p, 0)) == Ne(u, 0) @@ -1186,26 +1686,34 @@ # Test bools assert unpolarify(True) is True + def test_issue_2998(): - collect(a*y**(2.0*x)+b*y**(2.0*x),y**(x)) == y**(2.0*x)*(a + b) - collect(a*2**(2.0*x)+b*2**(2.0*x),2**(x)) == 2**(2.0*x)*(a + b) + assert collect(a*y**(2.0*x) + b*y**(2.0*x), y**x) == y**(2.0*x)*(a + b) + assert collect(a*2**(2.0*x) + b*2**(2.0*x), 2**x) == 2**(2.0*x)*(a + b) + def test_signsimp(): e = x*(-x + 1) + x*(x - 1) - assert signsimp(Eq(e, 0)) == True + assert signsimp(Eq(e, 0)) is True + def test_besselsimp(): - from sympy import besselj, besseli, besselk, bessely, jn, yn, exp_polar, cosh + from sympy import besselj, besseli, besselk, bessely, jn, yn, exp_polar, cosh, cosine_transform assert besselsimp(exp(-I*pi*y/2)*besseli(y, z*exp_polar(I*pi/2))) == \ - besselj(y, z) + besselj(y, z) assert besselsimp(exp(-I*pi*a/2)*besseli(a, 2*sqrt(x)*exp_polar(I*pi/2))) == \ - besselj(a, 2*sqrt(x)) - assert besselsimp(sqrt(2)*sqrt(pi)*x**(S(1)/4)*exp(I*pi/4)*exp(-I*pi*a/2) * \ - besseli(-S(1)/2, sqrt(x)*exp_polar(I*pi/2)) * \ + besselj(a, 2*sqrt(x)) + assert besselsimp(sqrt(2)*sqrt(pi)*x**(S(1)/4)*exp(I*pi/4)*exp(-I*pi*a/2) * + besseli(-S(1)/2, sqrt(x)*exp_polar(I*pi/2)) * besseli(a, sqrt(x)*exp_polar(I*pi/2))/2) == \ - besselj(a, sqrt(x)) * cos(sqrt(x)) - assert besselsimp(besseli(S(-1)/2, z)) == sqrt(2)*cosh(z)/(sqrt(pi)*sqrt(z)) - assert besselsimp(besseli(a, z*exp_polar(-I*pi/2))) == exp(-I*pi*a/2)*besselj(a, z) + besselj(a, sqrt(x)) * cos(sqrt(x)) + assert besselsimp(besseli(S(-1)/2, z)) == \ + sqrt(2)*cosh(z)/(sqrt(pi)*sqrt(z)) + assert besselsimp(besseli(a, z*exp_polar(-I*pi/2))) == \ + exp(-I*pi*a/2)*besselj(a, z) + assert cosine_transform(1/t*sin(a/t), t, y) == \ + sqrt(2)*sqrt(pi)*besselj(0, 2*sqrt(a)*sqrt(y))/2 + def test_Piecewise(): e1 = x*(x + y) - y*(x + y) @@ -1214,5 +1722,110 @@ s1 = simplify(e1) s2 = simplify(e2) s3 = simplify(e3) - assert simplify(Piecewise((e1, x < e2), (e3, True))) \ - == Piecewise((s1, x < s2), (s3, True)) + assert simplify(Piecewise((e1, x < e2), (e3, True))) == \ + Piecewise((s1, x < s2), (s3, True)) + + # trigsimp tries not to touch non-trig containing args + assert trigsimp(Piecewise((e1, e3 < e2), (e3, True))) == \ + Piecewise((e1, e3 < s2), (e3, True)) + + +def test_polymorphism(): + class A(Basic): + def _eval_simplify(x, **kwargs): + return 1 + + a = A(5, 2) + assert simplify(a) == 1 + + +def test_issue_from_PR1599(): + n1, n2, n3, n4 = symbols('n1 n2 n3 n4', negative=True) + assert simplify(I*sqrt(n1)) == -sqrt(-n1) + assert (powsimp(sqrt(n1)*sqrt(n2)*sqrt(n3)) == + -I*sqrt(-n1)*sqrt(-n2)*sqrt(-n3)) + assert (powsimp(root(n1, 3)*root(n2, 3)*root(n3, 3)*root(n4, 3)) == + -(-1)**(S(1)/3)* + (-n1)**(S(1)/3)*(-n2)**(S(1)/3)*(-n3)**(S(1)/3)*(-n4)**(S(1)/3)) + + +def test_3712(): + eq = (x + 2*y)*(2*x + 2) + assert simplify(eq) == (x + 1)*(x + 2*y)*2 + # reject the 2-arg Mul -- these are a headache for test writing + assert simplify(eq.expand()) == \ + 2*x**2 + 4*x*y + 2*x + 4*y + + +@XFAIL +def test_3712_fail(): + # from doc/src/modules/physics/mechanics/examples.rst, the current `eq` + # at Line 576 (in different variables) was formerly the equivalent and + # shorter expression given below...it would be nice to get the short one + # back again + xp, y, x, z = symbols('xp, y, x, z') + eq = 4*(-19*sin(x)*y + 5*sin(3*x)*y + 15*cos(2*x)*z - 21*z)*xp/(9*cos(x) - 5*cos(3*x)) + assert trigsimp(eq) == -2*(2*cos(x)*tan(x)*y + 3*z)*xp/cos(x) + + +def test_3821(): + e = [cos(x) + I*sin(x), cos(x) - I*sin(x), + cosh(x) - sinh(x), cosh(x) + sinh(x)] + ok = [exp(I*x), exp(-I*x), exp(-x), exp(x)] + # wrap in f to show that the change happens wherever ei occurs + f = Function('f') + assert [simplify(f(ei)).args[0] for ei in e] == ok + + +def test_3902(): + from sympy.abc import r, R + assert simplify(-(r*Piecewise((4*pi/3, r <= R), + (-8*pi*R**3/(3*r**3), True)) + 2*Piecewise((4*pi*r/3, r <= R), + (4*pi*R**3/(3*r**2), True)))/(4*pi*r)) == \ + Piecewise((-1, r <= R), (0, True)) + + +def test_exptrigsimp(): + def valid(a, b): + from sympy.utilities.randtest import test_numerically as tn + if not (tn(a, b) and a == b): + return False + return True + + assert exptrigsimp(exp(x) + exp(-x)) == 2*cosh(x) + assert exptrigsimp(exp(x) - exp(-x)) == 2*sinh(x) + e = [cos(x) + I*sin(x), cos(x) - I*sin(x), + cosh(x) - sinh(x), cosh(x) + sinh(x)] + ok = [exp(I*x), exp(-I*x), exp(-x), exp(x)] + assert all(valid(i, j) for i, j in zip( + [exptrigsimp(ei) for ei in e], ok)) + + ue = [cos(x) + sin(x), cos(x) - sin(x), + cosh(x) + I*sinh(x), cosh(x) - I*sinh(x)] + assert [exptrigsimp(ei) == ei for ei in ue] + + res = [] + ok = [y*tanh(1), 1/(y*tanh(1)), I*y*tan(1), -I/(y*tan(1)), + y*tanh(x), 1/(y*tanh(x)), I*y*tan(x), -I/(y*tan(x)), + y*tanh(1 + I), 1/(y*tanh(1 + I))] + for a in (1, I, x, I*x, 1 + I): + w = exp(a) + eq = y*(w - 1/w)/(w + 1/w) + s = simplify(eq) + assert s == exptrigsimp(eq) + res.append(s) + sinv = simplify(1/eq) + assert sinv == exptrigsimp(1/eq) + res.append(sinv) + assert all(valid(i, j) for i, j in zip(res, ok)) + + for a in range(1, 3): + w = exp(a) + e = w + 1/w + s = simplify(e) + assert s == exptrigsimp(e) + assert valid(s, 2*cosh(a)) + e = w - 1/w + s = simplify(e) + assert s == exptrigsimp(e) + assert valid(s, 2*sinh(a)) diff -Nru python3-sympy-0.7.2/sympy/simplify/tests/test_sqrtdenest.py python3-sympy-0.7.3/sympy/simplify/tests/test_sqrtdenest.py --- python3-sympy-0.7.2/sympy/simplify/tests/test_sqrtdenest.py 2012-10-17 03:02:22.000000000 +0000 +++ python3-sympy-0.7.3/sympy/simplify/tests/test_sqrtdenest.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,7 +1,8 @@ from sympy import sqrt, root, S, Symbol, sqrtdenest, Integral, cos -from sympy.simplify.sqrtdenest import subsets +from sympy.simplify.sqrtdenest import _subsets as subsets -r2, r3, r5, r6, r7, r10, r15, r29 = [sqrt(x) for x in [2,3,5,6,7,10,15,29]] +r2, r3, r5, r6, r7, r10, r15, r29 = [sqrt(x) for x in [2, 3, 5, 6, 7, 10, + 15, 29]] def test_sqrtdenest(): @@ -11,8 +12,8 @@ sqrt(r2): sqrt(r2), sqrt(5 + r7): sqrt(5 + r7), sqrt(3 + sqrt(5 + 2*r7)): - 3*r2*(5 + 2*r7)**(S(1)/4)/(2*sqrt(6 + 3*r7)) + - r2*sqrt(6 + 3*r7)/(2*(5 + 2*r7)**(S(1)/4)), + 3*r2*(5 + 2*r7)**(S(1)/4)/(2*sqrt(6 + 3*r7)) + + r2*sqrt(6 + 3*r7)/(2*(5 + 2*r7)**(S(1)/4)), sqrt(3 + 2*r3): 3**(S(3)/4)*(r6/2 + 3*r2/2)/3} for i in d: assert sqrtdenest(i) == d[i] @@ -20,7 +21,7 @@ def test_sqrtdenest2(): assert sqrtdenest(sqrt(16 - 2*r29 + 2*sqrt(55 - 10*r29))) == \ - r5 + sqrt(11 - 2*r29) + r5 + sqrt(11 - 2*r29) e = sqrt(-r5 + sqrt(-2*r29 + 2*sqrt(-10*r29 + 55) + 16)) assert sqrtdenest(e) == root(-2*r29 + 11, 4) r = sqrt(1 + r7) @@ -32,7 +33,7 @@ sqrt(2)*root(3, 4) + root(3, 4)**3 assert sqrtdenest(sqrt(((1 + r5 + sqrt(1 + r3))**2).expand())) == \ - 1 + r5 + sqrt(1 + r3) + 1 + r5 + sqrt(1 + r3) assert sqrtdenest(sqrt(((1 + r5 + r7 + sqrt(1 + r3))**2).expand())) == \ 1 + sqrt(1 + r3) + r5 + r7 @@ -44,7 +45,7 @@ assert sqrtdenest(e) == sqrt(-2*r10 - 2*r2 + 4*r5 + 14) # check that the result is not more complicated than the input - z= sqrt(-2*r29 + cos(2) + 2*sqrt(-10*r29 + 55) + 16) + z = sqrt(-2*r29 + cos(2) + 2*sqrt(-10*r29 + 55) + 16) assert sqrtdenest(z) == z assert sqrtdenest(sqrt(r6 + sqrt(15))) == sqrt(r6 + sqrt(15)) @@ -52,15 +53,16 @@ z = sqrt(15 - 2*sqrt(31) + 2*sqrt(55 - 10*r29)) assert sqrtdenest(z) == z + def test_sqrtdenest_rec(): assert sqrtdenest(sqrt(-4*sqrt(14) - 2*r6 + 4*sqrt(21) + 33)) == \ - -r2 + r3 + 2*r7 + -r2 + r3 + 2*r7 assert sqrtdenest(sqrt(-28*r7 - 14*r5 + 4*sqrt(35) + 82)) == \ - -7 + r5 + 2*r7 + -7 + r5 + 2*r7 assert sqrtdenest(sqrt(6*r2/11 + 2*sqrt(22)/11 + 6*sqrt(11)/11 + 2)) == \ - sqrt(11)*(r2 + 3 + sqrt(11))/11 + sqrt(11)*(r2 + 3 + sqrt(11))/11 assert sqrtdenest(sqrt(468*r3 + 3024*r2 + 2912*r6 + 19735)) == \ - 9*r3 + 26 + 56*r6 + 9*r3 + 26 + 56*r6 z = sqrt(-490*r3 - 98*sqrt(115) - 98*sqrt(345) - 2107) assert sqrtdenest(z) == sqrt(-1)*(7*r5 + 7*r15 + 7*sqrt(23)) z = sqrt(-4*sqrt(14) - 2*r6 + 4*sqrt(21) + 34) @@ -71,7 +73,7 @@ assert sqrtdenest(sqrt(8*r2/3 + 14*r5/3 + S(154)/9)) == \ -r10/3 + r2 + r5 + 3 assert sqrtdenest(sqrt(sqrt(2*r6 + 5) + sqrt(2*r7 + 8))) == \ - sqrt(1 + r2 + r3 + r7) + sqrt(1 + r2 + r3 + r7) assert sqrtdenest(sqrt(4*r15 + 8*r5 + 12*r3 + 24)) == 1 + r3 + r5 + r15 w = 1 + r2 + r3 + r5 + r7 @@ -82,10 +84,12 @@ z = sqrt(2*r10 + 6*r2 + 4*r5 + 12 + 10*r15 + 30*r3) assert sqrtdenest(z) == z + def test_issue3142(): z = sqrt( -320 + 32*sqrt(5) + 64*r15) assert sqrtdenest(z) == z + def test_sqrtdenest3(): z = sqrt(13 - 2*r10 + 2*r2*sqrt(-2*r10 + 11)) assert sqrtdenest(z) == -1 + r2 + r10 @@ -104,6 +108,7 @@ r = sqrt(-2*r29 + 11) assert sqrtdenest(z) == sqrt(r2*r + r3*r + r10 + r15 + 5) + def test_sqrtdenest4(): # see Denest_en.pdf in http://code.google.com/p/sympy/issues/detail?id=93 z = sqrt(8 - r2*sqrt(5 - r5) - sqrt(3)*(1 + r5)) @@ -112,7 +117,7 @@ z1 = ((-r15*c - r3*c + c + r5*c - r6 - r2 + r10 + sqrt(30))/4).expand() assert sqrtdenest(z) == z1 - z= sqrt(2*r2*sqrt(r2 + 2) + 5*r2 + 4*sqrt(r2 + 2) + 8) + z = sqrt(2*r2*sqrt(r2 + 2) + 5*r2 + 4*sqrt(r2 + 2) + 8) assert sqrtdenest(z) == r2 + sqrt(r2 + 2) + 2 w = 2 + r2 + r3 + (1 + r3)*sqrt(2 + r2 + 5*r3) @@ -159,9 +164,11 @@ def test_subsets(): assert subsets(1) == [[1]] assert subsets(4) == [ - [1, 0, 0, 0], [0, 1, 0, 0], [1, 1, 0, 0], [0, 0, 1, 0], [1, 0, 1, 0], - [0, 1, 1, 0], [1, 1, 1, 0], [0, 0, 0, 1], [1, 0, 0, 1], [0, 1, 0, 1], - [1, 1, 0, 1], [0, 0, 1, 1], [1, 0, 1, 1], [0, 1, 1, 1], [1, 1, 1, 1]] + [1, 0, 0, 0], [0, 1, 0, 0], [1, 1, 0, 0], [0, 0, 1, 0], [1, 0, 1, 0], + [0, 1, 1, 0], [1, 1, 1, 0], [0, 0, 0, 1], [1, 0, 0, 1], [0, 1, 0, 1], + [1, 1, 0, 1], [0, 0, 1, 1], [1, 0, 1, 1], [0, 1, 1, 1], [1, 1, 1, 1]] + def test_issue_2554(): - assert sqrtdenest(sqrt(2 + sqrt(2 + sqrt(2)))) == sqrt(2 + sqrt(2 + sqrt(2))) + assert sqrtdenest( + sqrt(2 + sqrt(2 + sqrt(2)))) == sqrt(2 + sqrt(2 + sqrt(2))) diff -Nru python3-sympy-0.7.2/sympy/simplify/tests/test_traversaltools.py python3-sympy-0.7.3/sympy/simplify/tests/test_traversaltools.py --- python3-sympy-0.7.2/sympy/simplify/tests/test_traversaltools.py 2012-10-17 03:02:22.000000000 +0000 +++ python3-sympy-0.7.3/sympy/simplify/tests/test_traversaltools.py 2013-07-13 17:53:32.000000000 +0000 @@ -5,6 +5,7 @@ from sympy import expand, factor, I from sympy.abc import x, y + def test_use(): assert use(0, expand) == 0 diff -Nru python3-sympy-0.7.2/sympy/simplify/traversaltools.py python3-sympy-0.7.3/sympy/simplify/traversaltools.py --- python3-sympy-0.7.2/sympy/simplify/traversaltools.py 2012-10-17 03:02:22.000000000 +0000 +++ python3-sympy-0.7.3/sympy/simplify/traversaltools.py 2013-07-13 17:53:32.000000000 +0000 @@ -2,6 +2,7 @@ from sympy.core import sympify + def use(expr, func, level=0, args=(), kwargs={}): """ Use ``func`` to transform ``expr`` at the given level. diff -Nru python3-sympy-0.7.2/sympy/solvers/__init__.py python3-sympy-0.7.3/sympy/solvers/__init__.py --- python3-sympy-0.7.2/sympy/solvers/__init__.py 2012-10-17 03:02:22.000000000 +0000 +++ python3-sympy-0.7.3/sympy/solvers/__init__.py 2013-07-13 17:53:32.000000000 +0000 @@ -12,9 +12,12 @@ from .recurr import rsolve, rsolve_poly, rsolve_ratio, rsolve_hyper -from .ode import checkodesol, classify_ode, ode_order, dsolve, \ +from .ode import checkodesol, classify_ode, dsolve, \ homogeneous_order from .polysys import solve_poly_system, solve_triangulated -from .pde import pde_separate, pde_separate_add, pde_separate_mul +from .pde import pde_separate, pde_separate_add, pde_separate_mul, \ + pdsolve, classify_pde, checkpdesol + +from .deutils import ode_order diff -Nru python3-sympy-0.7.2/sympy/solvers/bivariate.py python3-sympy-0.7.3/sympy/solvers/bivariate.py --- python3-sympy-0.7.2/sympy/solvers/bivariate.py 1970-01-01 00:00:00.000000000 +0000 +++ python3-sympy-0.7.3/sympy/solvers/bivariate.py 2013-07-13 17:53:32.000000000 +0000 @@ -0,0 +1,389 @@ +from sympy.core.add import Add +from sympy.core.compatibility import ordered +from sympy.core.function import Function, expand_log, expand_mul +from sympy.core.mul import Mul +from sympy.core.power import Pow +from sympy.core.singleton import S +from sympy.core.symbol import (Dummy, Wild) +from sympy.functions.elementary.exponential import (LambertW, exp, log) +from sympy.functions.elementary.miscellaneous import root +from sympy.polys.polytools import (Poly, primitive, factor) +from sympy.simplify.simplify import (_mexpand, collect, separatevars) +from sympy.solvers.solvers import solve, _invert + + +def _filtered_gens(poly, symbol): + """process the generators of ``poly``, returning the set of generators that + have ``symbol``. If there are two generators that are inverses of each other, + prefer the one that has no denominator. + + Examples + ======== + + >>> from sympy.solvers.bivariate import _filtered_gens + >>> from sympy import Poly, exp + >>> from sympy.abc import x + >>> _filtered_gens(Poly(x + 1/x + exp(x)), x) + set([x, exp(x)]) + + """ + gens = set([g for g in poly.gens if symbol in g.free_symbols]) + for g in list(gens): + ag = 1/g + if g in gens and ag in gens: + if ag.as_numer_denom()[1] is not S.One: + g = ag + gens.remove(g) + return gens + + +def _mostfunc(lhs, func, X=None): + """Returns the term in lhs which contains the most of the + func-type things e.g. log(log(x)) wins over log(x) if both terms appear. + + ``func`` can be a function (exp, log, etc...) or any other SymPy object, + like Pow. + + Examples + ======== + + >>> from sympy.solvers.bivariate import _mostfunc + >>> from sympy.functions.elementary.exponential import exp + >>> from sympy.utilities.pytest import raises + >>> from sympy.abc import x, y + >>> _mostfunc(exp(x) + exp(exp(x) + 2), exp) + exp(exp(x) + 2) + >>> _mostfunc(exp(x) + exp(exp(y) + 2), exp, x) + exp(x) + >>> _mostfunc(exp(x) + exp(exp(y) + 2), exp, x) + exp(x) + >>> _mostfunc(x, exp, x) is None + True + >>> _mostfunc(exp(x) + exp(x*y), exp, x) + exp(x) + """ + fterms = [tmp for tmp in lhs.atoms(func) if (not X or + X.is_Symbol and X in tmp.free_symbols or + not X.is_Symbol and tmp.has(X))] + if len(fterms) == 1: + return fterms[0] + elif fterms: + return max(list(ordered(fterms)), key=lambda x: x.count(func)) + return None + + +def _linab(arg, symbol): + """Return ``a, b, X`` assuming ``arg`` can be written as ``a*X + b`` + where ``X`` is a symbol-dependent factor and ``a`` and ``b`` are + independent of ``symbol``. + + Examples + ======== + + >>> from sympy.functions.elementary.exponential import exp + >>> from sympy.solvers.bivariate import _linab + >>> from sympy.abc import x, y + >>> from sympy import S + >>> _linab(S(2), x) + (2, 0, 1) + >>> _linab(2*x, x) + (2, 0, x) + >>> _linab(y + y*x + 2*x, x) + (y + 2, y, x) + >>> _linab(3 + 2*exp(x), x) + (2, 3, exp(x)) + """ + + arg = arg.expand() + ind, dep = arg.as_independent(symbol) + if not arg.is_Add: + b = 0 + a, x = ind, dep + else: + b = ind + a, x = separatevars(dep).as_independent(symbol, as_Add=False) + if x.could_extract_minus_sign(): + a = -a + x = -x + return a, b, x + + +def _lambert(eq, x): + """ + Given an expression assumed to be in the form + ``F(X, a..f) = a*log(b*X + c) + d*X + f = 0`` + where X = g(x) and x = g^-1(X), return the Lambert solution if possible: + ``x = g^-1(-c/b + (a/d)*W(d/(a*b)*exp(c*d/a/b)*exp(-f/a)))``. + """ + eq = _mexpand(expand_log(eq)) + mainlog = _mostfunc(eq, log, x) + if not mainlog: + return [] # violated assumptions + other = eq.subs(mainlog, 0) + if (-other).func is log: + eq = (eq - other).subs(mainlog, mainlog.args[0]) + mainlog = mainlog.args[0] + if mainlog.func is not log: + return [] # violated assumptions + other = -(-other).args[0] + eq += other + if not x in other.free_symbols: + return [] # violated assumptions + d, f, X2 = _linab(other, x) + logterm = collect(eq - other, mainlog) + a = logterm.as_coefficient(mainlog) + if a is None or x in a.free_symbols: + return [] # violated assumptions + logarg = mainlog.args[0] + b, c, X1 = _linab(logarg, x) + if X1 != X2: + return [] # violated assumptions + + u = Dummy('rhs') + rhs = -c/b + (a/d)*LambertW(d/(a*b)*exp(c*d/a/b)*exp(-f/a)) + + # if W's arg is between -1/e and 0 there is a -1 branch solution, too. + + # Check here to see if exp(W(s)) appears and return s/W(s) instead? + + solns = solve(X1 - u, x) + for i, tmp in enumerate(solns): + solns[i] = tmp.subs(u, rhs) + return solns + + +def _solve_lambert(f, symbol, gens): + """Return solution to ``f`` if it is a Lambert-type expression + else raise NotImplementedError. + + The equality, ``f(x, a..f) = a*log(b*X + c) + d*X - f = 0`` has the + solution, `X = -c/b + (a/d)*W(d/(a*b)*exp(c*d/a/b)*exp(f/a))`. There + are a variety of forms for `f(X, a..f)` as enumerated below: + + 1a1) + if B**B = R for R not [0, 1] then + log(B) + log(log(B)) = log(log(R)) + X = log(B), a = 1, b = 1, c = 0, d = 1, f = log(log(R)) + 1a2) + if B*(b*log(B) + c)**a = R then + log(B) + a*log(b*log(B) + c) = log(R) + X = log(B); d=1, f=log(R) + 1b) + if a*log(b*B + c) + d*B = R then + X = B, f = R + 2a) + if (b*B + c)*exp(d*B + g) = R then + log(b*B + c) + d*B + g = log(R) + a = 1, f = log(R) - g, X = B + 2b) + if -b*B + g*exp(d*B + h) = c then + log(g) + d*B + h - log(b*B + c) = 0 + a = -1, f = -h - log(g), X = B + 3) + if d*p**(a*B + g) - b*B = c then + log(d) + (a*B + g)*log(p) - log(c + b*B) = 0 + a = -1, d = a*log(p), f = -log(d) - g*log(p) + """ + + nrhs, lhs = f.as_independent(symbol, as_Add=True) + rhs = -nrhs + + lamcheck = [tmp for tmp in gens + if (tmp.func in [exp, log] or + (tmp.is_Pow and symbol in tmp.exp.free_symbols))] + if not lamcheck: + raise NotImplementedError() + + if lhs.is_Mul: + lhs = expand_log(log(lhs)) + rhs = log(rhs) + + lhs = factor(lhs, deep=True) + # make sure we are inverted as completely as possible + r = Dummy() + i, lhs = _invert(lhs - r, symbol) + rhs = i.xreplace({r: rhs}) + + # For the first ones: + # 1a1) B**B = R != 0 (when 0, there is only a solution if the base is 0, + # but if it is, the exp is 0 and 0**0=1 + # comes back as B*log(B) = log(R) + # 1a2) B*(a + b*log(B))**p = R or with monomial expanded or with whole + # thing expanded comes back unchanged + # log(B) + p*log(a + b*log(B)) = log(R) + # lhs is Mul: + # expand log of both sides to give: + # log(B) + log(log(B)) = log(log(R)) + # 1b) d*log(a*B + b) + c*B = R + # lhs is Add: + # isolate c*B and expand log of both sides: + # log(c) + log(B) = log(R - d*log(a*B + b)) + + soln = [] + if not soln: + mainlog = _mostfunc(lhs, log, symbol) + if mainlog: + if lhs.is_Mul and rhs != 0: + soln = _lambert(log(lhs) - log(rhs), symbol) + elif lhs.is_Add: + other = lhs.subs(mainlog, 0) + if other and not other.is_Add and [ + tmp for tmp in other.atoms(Pow) + if symbol in tmp.free_symbols]: + if not rhs: + diff = log(other) - log(other - lhs) + else: + diff = log(lhs - other) - log(rhs - other) + soln = _lambert(expand_log(diff), symbol) + else: + #it's ready to go + soln = _lambert(lhs - rhs, symbol) + + # For the next two, + # collect on main exp + # 2a) (b*B + c)*exp(d*B + g) = R + # lhs is mul: + # log to give + # log(b*B + c) + d*B = log(R) - g + # 2b) -b*B + g*exp(d*B + h) = R + # lhs is add: + # add b*B + # log and rearrange + # log(R + b*B) - d*B = log(g) + h + + if not soln: + mainexp = _mostfunc(lhs, exp, symbol) + if mainexp: + lhs = collect(lhs, mainexp) + if lhs.is_Mul and rhs != 0: + soln = _lambert(expand_log(log(lhs) - log(rhs)), symbol) + elif lhs.is_Add: + # move all but mainexp-containing term to rhs + other = lhs.subs(mainexp, 0) + mainterm = lhs - other + rhs=rhs - other + if (mainterm.could_extract_minus_sign() and + rhs.could_extract_minus_sign()): + mainterm *= -1 + rhs *= -1 + diff = log(mainterm) - log(rhs) + soln = _lambert(expand_log(diff), symbol) + + # 3) d*p**(a*B + b) + c*B = R + # collect on main pow + # log(R - c*B) - a*B*log(p) = log(d) + b*log(p) + + if not soln: + mainpow = _mostfunc(lhs, Pow, symbol) + if mainpow and symbol in mainpow.exp.free_symbols: + lhs = collect(lhs, mainpow) + if lhs.is_Mul and rhs != 0: + soln = _lambert(expand_log(log(lhs) - log(rhs)), symbol) + elif lhs.is_Add: + # move all but mainpow-containing term to rhs + other = lhs.subs(mainpow, 0) + mainterm = lhs - other + rhs = rhs - other + diff = log(mainterm) - log(rhs) + soln = _lambert(expand_log(diff), symbol) + + if not soln: + raise NotImplementedError('%s does not appear to have a solution in ' + 'terms of LambertW' % f) + + return list(ordered(soln)) + + +def bivariate_type(f, x, y, **kwargs): + """Given an expression, f, 3 tests will be done to see what type + of composite bivariate it might be, options for u(x, y) are:: + + x*y + x+y + x*y+x + x*y+y + + If it matches one of these types, ``u(x, y)``, ``P(u)`` and dummy + variable ``u`` will be returned. Solving ``P(u)`` for ``u`` and + equating the solutions to ``u(x, y)`` and then solving for ``x`` or + ``y`` is equivalent to solving the original expression for ``x`` or + ``y``. If ``x`` and ``y`` represent two functions in the same + variable, e.g. ``x = g(t)`` and ``y = h(t)``, then if ``u(x, y) - p`` + can be solved for ``t`` then these represent the solutions to + ``P(u) = 0`` when ``p`` are the solutions of ``P(u) = 0``. + + Only positive values of ``u`` are considered. + + Examples + ======== + + >>> from sympy.solvers.solvers import solve + >>> from sympy.solvers.bivariate import bivariate_type + >>> from sympy.abc import x, y + >>> eq = (x**2 - 3).subs(x, x + y) + >>> bivariate_type(eq, x, y) + (x + y, _u**2 - 3, _u) + >>> uxy, pu, u = _ + >>> usol = solve(pu, u); usol + [sqrt(3)] + >>> [solve(uxy - s) for s in solve(pu, u)] + [[{x: -y + sqrt(3)}]] + >>> all(eq.subs(s).equals(0) for sol in _ for s in sol) + True + + """ + + u = Dummy('u', positive=True) + + if kwargs.pop('first', True): + p = Poly(f, x, y) + f = p.as_expr() + _x = Dummy() + _y = Dummy() + rv = bivariate_type(Poly(f.subs({x: _x, y: _y}), _x, _y), _x, _y, first=False) + if rv: + reps = {_x: x, _y: y} + return rv[0].xreplace(reps), rv[1].xreplace(reps), rv[2] + return + + p = f + f = p.as_expr() + + # f(x*y) + args = Add.make_args(p.as_expr()) + new = [] + for a in args: + a = _mexpand(a.subs(x, u/y)) + free = a.free_symbols + if x in free or y in free: + break + new.append(a) + else: + return x*y, Add(*new), u + + def ok(f, v, c): + new = _mexpand(f.subs(v, c)) + free = new.free_symbols + return None if (x in free or y in free) else new + + # f(a*x + b*y) + new = [] + d = p.degree(x) + if p.degree(y) == d: + a = root(p.coeff_monomial(x**d), d) + b = root(p.coeff_monomial(y**d), d) + new = ok(f, x, (u - b*y)/a) + if new is not None: + return a*x + b*y, new, u + + # f(a*x*y + b*y) + new = [] + d = p.degree(x) + if p.degree(y) == d: + for itry in range(2): + a = root(p.coeff_monomial(x**d*y**d), d) + b = root(p.coeff_monomial(y**d), d) + new = ok(f, x, (u - b*y)/a/y) + if new is not None: + return a*x*y + b*y, new, u + x, y = y, x diff -Nru python3-sympy-0.7.2/sympy/solvers/deutils.py python3-sympy-0.7.3/sympy/solvers/deutils.py --- python3-sympy-0.7.2/sympy/solvers/deutils.py 1970-01-01 00:00:00.000000000 +0000 +++ python3-sympy-0.7.3/sympy/solvers/deutils.py 2013-07-13 17:53:32.000000000 +0000 @@ -0,0 +1,258 @@ +"""Utility functions for classifying and solving +ordinary and partial differential equations. + +Contains +======== +_preprocess +ode_order +_desolve + +""" +from sympy.core.compatibility import set_union +from sympy.core.function import Function, Derivative, AppliedUndef +from sympy.core.relational import Equality, Eq +from sympy.core.symbol import Wild + +def _preprocess(expr, func=None, hint='_Integral'): + """Prepare expr for solving by making sure that differentiation + is done so that only func remains in unevaluated derivatives and + (if hint doesn't end with _Integral) that doit is applied to all + other derivatives. If hint is None, don't do any differentiation. + (Currently this may cause some simple differential equations to + fail.) + + In case func is None, an attempt will be made to autodetect the + function to be solved for. + + >>> from sympy.solvers.deutils import _preprocess + >>> from sympy import Derivative, Function, Integral, sin + >>> from sympy.abc import x, y, z + >>> f, g = list(map(Function, 'fg')) + + Apply doit to derivatives that contain more than the function + of interest: + + >>> _preprocess(Derivative(f(x) + x, x)) + (Derivative(f(x), x) + 1, f(x)) + + Do others if the differentiation variable(s) intersect with those + of the function of interest or contain the function of interest: + + >>> _preprocess(Derivative(g(x), y, z), f(y)) + (0, f(y)) + >>> _preprocess(Derivative(f(y), z), f(y)) + (0, f(y)) + + Do others if the hint doesn't end in '_Integral' (the default + assumes that it does): + + >>> _preprocess(Derivative(g(x), y), f(x)) + (Derivative(g(x), y), f(x)) + >>> _preprocess(Derivative(f(x), y), f(x), hint='') + (0, f(x)) + + Don't do any derivatives if hint is None: + + >>> eq = Derivative(f(x) + 1, x) + Derivative(f(x), y) + >>> _preprocess(eq, f(x), hint=None) + (Derivative(f(x) + 1, x) + Derivative(f(x), y), f(x)) + + If it's not clear what the function of interest is, it must be given: + + >>> eq = Derivative(f(x) + g(x), x) + >>> _preprocess(eq, g(x)) + (Derivative(f(x), x) + Derivative(g(x), x), g(x)) + >>> try: _preprocess(eq) + ... except ValueError: print("A ValueError was raised.") + A ValueError was raised. + + """ + + derivs = expr.atoms(Derivative) + if not func: + funcs = set_union(*[d.atoms(AppliedUndef) for d in derivs]) + if len(funcs) != 1: + raise ValueError('The function cannot be ' + 'automatically detected for %s.' % expr) + func = funcs.pop() + fvars = set(func.args) + if hint is None: + return expr, func + reps = [(d, d.doit()) for d in derivs if not hint.endswith('_Integral') or + d.has(func) or set(d.variables) & fvars] + eq = expr.subs(reps) + return eq, func + +def ode_order(expr, func): + """ + Returns the order of a given differential + equation with respect to func. + + This function is implemented recursively. + + Examples + ======== + + >>> from sympy import Function + >>> from sympy.solvers.deutils import ode_order + >>> from sympy.abc import x + >>> f, g = list(map(Function, ['f', 'g'])) + >>> ode_order(f(x).diff(x, 2) + f(x).diff(x)**2 + + ... f(x).diff(x), f(x)) + 2 + >>> ode_order(f(x).diff(x, 2) + g(x).diff(x, 3), f(x)) + 2 + >>> ode_order(f(x).diff(x, 2) + g(x).diff(x, 3), g(x)) + 3 + + """ + a = Wild('a', exclude=[func]) + if expr.match(a): + return 0 + + if isinstance(expr, Derivative): + if expr.args[0] == func: + return len(expr.variables) + else: + order = 0 + for arg in expr.args[0].args: + order = max(order, ode_order(arg, func) + len(expr.variables)) + return order + else: + order = 0 + for arg in expr.args: + order = max(order, ode_order(arg, func)) + return order + +def _desolve(eq, func=None, hint="default", simplify=True, **kwargs): + """This is a helper function to dsolve and pdsolve in the ode + and pde modules. + + If the hint provided to the function is "default", then a dict with + the following keys are returned + + 'func' - It provides the function for which the differential equation + has to be solved. This is useful when the function + + 'default' - The default key as returned by classifier functions in ode + and pde.py + + 'hint' - The hint given by the user for which the differential equation + is to be solved. If the hint given by the user is 'default', + then the value of 'hint' and 'default' is the same. + + 'order' - The order of the function as returned by ode_order + + 'match' - It returns the match as given by the classifier functions, for + the default hint. + + If the hint provided to the function is not "default" and is not in + ('all', 'all_Integral', 'best'), then a dict with the above mentioned keys + is returned along with the keys which are returned when dict in + classify_ode or classify_pde is set True + + If the hint given is in ('all', 'all_Integral', 'best'), then this function + returns a nested dict, with the keys, being the set of classified hints + returned by classifier functions, and the values being the dict of form + as mentioned above. + + Key 'eq' is a common key to all the above mentioned hints which returns an + expression if eq given by user is an Equality. + + See Also + ======== + classify_ode(ode.py) + classify_pde(pde.py) + """ + prep = kwargs.pop('prep', True) + if isinstance(eq, Equality): + eq = eq.lhs - eq.rhs + + # preprocess the equation and find func if not given + if prep or func is None: + eq, func = _preprocess(eq, func) + prep = False + + # type is an argument passed by the solve functions in ode and pde.py + # that identifies whether the function caller is an ordinary + # or partial differential equation. Accordingly corresponding + # changes are made in the function. + type = kwargs.get('type', None) + if type == 'ode': + from sympy.solvers.ode import classify_ode, allhints + classifier = classify_ode + string = 'ODE ' + dummy = '' + + elif type == 'pde': + from sympy.solvers.pde import classify_pde, allhints + classifier = classify_pde + string = 'PDE ' + dummy = 'p' + + # Magic that should only be used internally. Prevents classify_ode from + # being called more than it needs to be by passing its results through + # recursive calls. + if kwargs.get('classify', True): + hints = classifier(eq, func, dict=True, prep=prep) + + else: + # Here is what all this means: + # + # hint: The hint method given to _desolve() by the user. + # hints: The dictionary of hints that match the DE, along with other + # information (including the internal pass-through magic). + # default: The default hint to return, the first hint from allhints + # that matches the hint; obtained from classify_ode(). + # match: Dictionary containing the match dictionary for each hint + # (the parts of the DE for solving). When going through the + # hints in "all", this holds the match string for the current + # hint. + # order: The order of the DE, as determined by ode_order(). + hints = kwargs.get('hint', + {'default': hint, + hint: kwargs['match'], + 'order': kwargs['order']}) + if hints['order'] == 0: + raise ValueError( + str(eq) + " is not a differential equation in " + str(func)) + + if not hints['default']: + # classify_ode will set hints['default'] to None if no hints match. + if hint not in allhints and hint != 'default': + raise ValueError("Hint not recognized: " + hint) + elif hint not in hints['ordered_hints'] and hint != 'default': + raise ValueError(string + str(eq) + " does not match hint " + hint) + else: + raise NotImplementedError(dummy + "solve" + ": Cannot solve " + str(eq)) + if hint == 'default': + return _desolve(eq, func, hint=hints['default'], simplify=simplify, + prep=prep, classify=False, order=hints['order'], + match=hints[hints['default']], type=type) + elif hint in ('all', 'all_Integral', 'best'): + retdict = {} + failedhints = {} + gethints = set(hints) - set(['order', 'default', 'ordered_hints']) + if hint == 'all_Integral': + for i in hints: + if i.endswith('_Integral'): + gethints.remove(i[:-len('_Integral')]) + # special case + if "1st_homogeneous_coeff_best" in gethints: + gethints.remove("1st_homogeneous_coeff_best") + for i in gethints: + sol = _desolve(eq, func, hint=i, simplify=simplify, prep=prep, + classify=False, order=hints['order'], match=hints[i], type=type) + retdict[i] = sol + retdict['all'] = True + retdict['eq'] = eq + return retdict + elif hint not in allhints: # and hint not in ('default', 'ordered_hints'): + raise ValueError("Hint not recognized: " + hint) + elif hint not in hints: + raise ValueError(string + str(eq) + " does not match hint " + hint) + else: + # Key added to identify the hint needed to solve the equation + hints['hint'] = hint + hints.update({'func': func, 'eq': eq}) + return hints diff -Nru python3-sympy-0.7.2/sympy/solvers/inequalities.py python3-sympy-0.7.3/sympy/solvers/inequalities.py --- python3-sympy-0.7.2/sympy/solvers/inequalities.py 2012-10-17 03:02:22.000000000 +0000 +++ python3-sympy-0.7.3/sympy/solvers/inequalities.py 2013-07-13 17:53:32.000000000 +0000 @@ -7,7 +7,8 @@ from sympy.assumptions import ask, AppliedPredicate, Q from sympy.functions import re, im, Abs from sympy.logic import And -from sympy.polys import Poly +from sympy.polys import Poly, PolynomialError, parallel_poly_from_expr + def solve_poly_inequality(poly, rel): """Solve a polynomial inequality with rational coefficients. @@ -70,37 +71,43 @@ for left, multiplicity in reals: if multiplicity % 2: if sign == eq_sign: - intervals.insert(0, Interval(left, right, not equal, right_open)) + intervals.insert( + 0, Interval(left, right, not equal, right_open)) sign, right, right_open = -sign, left, not equal else: if sign == eq_sign and not equal: - intervals.insert(0, Interval(left, right, True, right_open)) + intervals.insert( + 0, Interval(left, right, True, right_open)) right, right_open = left, True elif sign != eq_sign and equal: intervals.insert(0, Interval(left, left)) if sign == eq_sign: - intervals.insert(0, Interval(S.NegativeInfinity, right, True, right_open)) + intervals.insert( + 0, Interval(S.NegativeInfinity, right, True, right_open)) return intervals -def solve_poly_inequalities(polys): - """Solve a system of polynomial inequalities with rational coefficients. + +def solve_rational_inequalities(eqs): + """Solve a system of rational inequalities with rational coefficients. Examples ======== >>> from sympy.abc import x >>> from sympy import Poly - >>> from sympy.solvers.inequalities import solve_poly_inequalities + >>> from sympy.solvers.inequalities import solve_rational_inequalities - >>> solve_poly_inequalities([[(Poly(-x + 1, x, domain='ZZ'), '>='), - ... (Poly(-x + 1, x, domain='ZZ'), '<=')]]) + >>> solve_rational_inequalities([[ + ... ((Poly(-x + 1), Poly(1, x)), '>='), + ... ((Poly(-x + 1), Poly(1, x)), '<=')]]) {1} - >>> solve_poly_inequalities([[(Poly(x, x, domain='ZZ'), '!='), - ... (Poly(-x + 1, x, domain='ZZ'), '>=')]]) + >>> solve_rational_inequalities([[ + ... ((Poly(x), Poly(1, x)), '!='), + ... ((Poly(-x + 1), Poly(1, x)), '>=')]]) (-oo, 0) U (0, 1] See Also @@ -109,26 +116,38 @@ """ result = S.EmptySet - for _polys in polys: + for _eqs in eqs: global_intervals = None - for poly, rel in _polys: - local_intervals = solve_poly_inequality(poly, rel) + for (numer, denom), rel in _eqs: + numer_intervals = solve_poly_inequality(numer*denom, rel) + denom_intervals = solve_poly_inequality(denom, '==') if global_intervals is None: - global_intervals = local_intervals + global_intervals = numer_intervals else: intervals = [] - for local_interval in local_intervals: + for numer_interval in numer_intervals: for global_interval in global_intervals: - interval = local_interval.intersect(global_interval) + interval = numer_interval.intersect(global_interval) if interval is not S.EmptySet: intervals.append(interval) global_intervals = intervals + intervals = [] + + for global_interval in global_intervals: + for denom_interval in denom_intervals: + global_interval -= denom_interval + + if global_interval is not S.EmptySet: + intervals.append(global_interval) + + global_intervals = intervals + if not global_intervals: break @@ -137,28 +156,29 @@ return result -def reduce_poly_inequalities(exprs, gen, assume=True, relational=True): - """Reduce a system of polynomial inequalities with rational coefficients. + +def reduce_rational_inequalities(exprs, gen, assume=True, relational=True): + """Reduce a system of rational inequalities with rational coefficients. Examples ======== >>> from sympy import Poly, Symbol - >>> from sympy.solvers.inequalities import reduce_poly_inequalities + >>> from sympy.solvers.inequalities import reduce_rational_inequalities >>> x = Symbol('x', real=True) - >>> reduce_poly_inequalities([[x**2 <= 0]], x) + >>> reduce_rational_inequalities([[x**2 <= 0]], x) x == 0 - >>> reduce_poly_inequalities([[x + 2 > 0]], x) - -2 < x + >>> reduce_rational_inequalities([[x + 2 > 0]], x) + x > -2 """ exact = True - polys = [] + eqs = [] for _exprs in exprs: - _polys = [] + _eqs = [] for expr in _exprs: if isinstance(expr, tuple): @@ -169,21 +189,24 @@ else: expr, rel = expr, '==' - poly = Poly(expr, gen) + try: + (numer, denom), opt = parallel_poly_from_expr(expr.together().as_numer_denom(), gen) + except PolynomialError: + raise PolynomialError("only polynomials and rational functions are supported in this context") - if not poly.get_domain().is_Exact: - poly, exact = poly.to_exact(), False + if not opt.domain.is_Exact: + numer, denom, exact = numer.to_exact(), denom.to_exact(), False - domain = poly.get_domain() + domain = opt.domain.get_exact() if not (domain.is_ZZ or domain.is_QQ): - raise NotImplementedError("inequality solving is not supported over %s" % domain) + raise NotImplementedError("inequality solving is not supported over %s" % opt.domain) - _polys.append((poly, rel)) + _eqs.append(((numer, denom), rel)) - polys.append(_polys) + eqs.append(_eqs) - solution = solve_poly_inequalities(polys) + solution = solve_rational_inequalities(eqs) if not exact: solution = solution.evalf() @@ -200,6 +223,7 @@ return result + def reduce_abs_inequality(expr, rel, gen, assume=True): """Reduce an inequality with nested absolute values. @@ -246,7 +270,8 @@ n = expr.exp if not n.is_Integer or n < 0: - raise ValueError("only non-negative integer powers are allowed") + raise ValueError( + "only non-negative integer powers are allowed") _exprs = _bottom_up_scan(expr.base) @@ -276,7 +301,8 @@ inequalities.append([expr] + conds) - return reduce_poly_inequalities(inequalities, gen, assume) + return reduce_rational_inequalities(inequalities, gen, assume) + def reduce_abs_inequalities(exprs, gen, assume=True): """Reduce a system of inequalities with nested absolute values. @@ -290,7 +316,7 @@ >>> reduce_abs_inequalities([(Abs(3*x - 5) - 7, '<'), ... (Abs(x + 25) - 13, '>')], x, assume=Q.real(x)) - And(-2/3 < x, Or(-12 < x, x < -38), x < 4) + And(-2/3 < x, Or(x < -38, x > -12), x < 4) >>> reduce_abs_inequalities([(Abs(x - 4) + Abs(3*x - 5) - 7, '<')], x, ... assume=Q.real(x)) @@ -302,14 +328,17 @@ """ return And(*[ reduce_abs_inequality(expr, rel, gen, assume) for expr, rel in exprs ]) + def _solve_inequality(ie, s): """ A hacky replacement for solve, since the latter only works for univariate inequalities. """ - from sympy import Poly if not ie.rel_op in ('>', '>=', '<', '<='): raise NotImplementedError expr = ie.lhs - ie.rhs - p = Poly(expr, s) + try: + p = Poly(expr, s) + except PolynomialError: + raise NotImplementedError if p.degree() != 1: raise NotImplementedError('%s' % ie) a, b = p.all_coeffs() @@ -320,6 +349,7 @@ else: raise NotImplementedError + def reduce_inequalities(inequalities, assume=True, symbols=[]): """Reduce a system of inequalities with rational coefficients. @@ -331,7 +361,7 @@ >>> from sympy.solvers.inequalities import reduce_inequalities >>> reduce_inequalities(S(0) <= x + 3, Q.real(x), []) - -3 <= x + x >= -3 >>> reduce_inequalities(S(0) <= x + y*2 - 1, True, [x]) -2*y + 1 <= x @@ -340,7 +370,7 @@ inequalities = [inequalities] if len(inequalities) == 1 and len(symbols) == 1 \ - and inequalities[0].is_Relational: + and inequalities[0].is_Relational: try: return _solve_inequality(inequalities[0], symbols[0]) except NotImplementedError: @@ -371,7 +401,8 @@ elif len(gens) == 1: gen = gens.pop() else: - raise NotImplementedError("only univariate inequalities are supported") + raise NotImplementedError( + "only univariate inequalities are supported") components = expr.find(lambda u: u.is_Function) @@ -400,7 +431,7 @@ abs_reduced = [] for gen, exprs in poly_part.items(): - poly_reduced.append(reduce_poly_inequalities([exprs], gen, assume)) + poly_reduced.append(reduce_rational_inequalities([exprs], gen, assume)) for gen, exprs in abs_part.items(): abs_reduced.append(reduce_abs_inequalities(exprs, gen, assume)) diff -Nru python3-sympy-0.7.2/sympy/solvers/ode.py python3-sympy-0.7.3/sympy/solvers/ode.py --- python3-sympy-0.7.2/sympy/solvers/ode.py 2012-10-17 03:02:22.000000000 +0000 +++ python3-sympy-0.7.3/sympy/solvers/ode.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,331 +1,305 @@ -""" -This module contains dsolve() and different helper functions that it -uses. - -dsolve() solves ordinary differential equations. See the docstring on -the various functions for their uses. Note that partial differential -equations support is in pde.py. Note that ode_hint() functions have -docstrings describing their various methods, but they are intended for -internal use. Use dsolve(ode, func, hint=hint) to solve an ode using a -specific hint. See also the docstring on dsolve(). +r""" +This module contains :py:meth:`~sympy.solvers.ode.dsolve` and different helper +functions that it uses. + +:py:meth:`~sympy.solvers.ode.dsolve` solves ordinary differential equations. +See the docstring on the various functions for their uses. Note that partial +differential equations support is in ``pde.py``. Note that hint functions +have docstrings describing their various methods, but they are intended for +internal use. Use ``dsolve(ode, func, hint=hint)`` to solve an ODE using a +specific hint. See also the docstring on +:py:meth:`~sympy.solvers.ode.dsolve`. **Functions in this module** These are the user functions in this module: - - dsolve() - Solves ODEs. - - classify_ode() - Classifies ODEs into possible hints for dsolve(). - - checkodesol() - Checks if an equation is the solution to an ODE. - - ode_order() - Returns the order (degree) of an ODE. - - homogeneous_order() - Returns the homogeneous order of an - expression. - - These are the non-solver helper functions that are for internal use. - The user should use the various options to dsolve() to obtain the - functionality provided by these functions: - - - odesimp() - Does all forms of ODE simplification. - - ode_sol_simplicity() - A key function for comparing solutions by - simplicity. - - constantsimp() - Simplifies arbitrary constants. - - constant_renumber() - Renumber arbitrary constants - - _handle_Integral() - Evaluate unevaluated Integrals. - - preprocess - prepare the equation and detect function to solve for + - :py:meth:`~sympy.solvers.ode.dsolve` - Solves ODEs. + - :py:meth:`~sympy.solvers.ode.classify_ode` - Classifies ODEs into + possible hints for :py:meth:`~sympy.solvers.ode.dsolve`. + - :py:meth:`~sympy.solvers.ode.checkodesol` - Checks if an equation is the + solution to an ODE. + - :py:meth:`~sympy.solvers.ode.homogeneous_order` - Returns the + homogeneous order of an expression. + + These are the non-solver helper functions that are for internal use. The + user should use the various options to + :py:meth:`~sympy.solvers.ode.dsolve` to obtain the functionality provided + by these functions: + + - :py:meth:`~sympy.solvers.ode.odesimp` - Does all forms of ODE + simplification. + - :py:meth:`~sympy.solvers.ode.ode_sol_simplicity` - A key function for + comparing solutions by simplicity. + - :py:meth:`~sympy.solvers.ode.constantsimp` - Simplifies arbitrary + constants. + - :py:meth:`~sympy.solvers.ode.constant_renumber` - Renumber arbitrary + constants. + - :py:meth:`~sympy.solvers.ode._handle_Integral` - Evaluate unevaluated + Integrals. See also the docstrings of these functions. **Currently implemented solver methods** The following methods are implemented for solving ordinary differential -equations. See the docstrings of the various ode_hint() functions for -more information on each (run help(ode)): +equations. See the docstrings of the various hint functions for more +information on each (run ``help(ode)``): - - 1st order separable differential equations - - 1st order differential equations whose coefficients or dx and dy - are functions homogeneous of the same order. + - 1st order separable differential equations. + - 1st order differential equations whose coefficients or `dx` and `dy` are + functions homogeneous of the same order. - 1st order exact differential equations. - - 1st order linear differential equations + - 1st order linear differential equations. - 1st order Bernoulli differential equations. - 2nd order Liouville differential equations. - - nth order linear homogeneous differential equation with constant + - `n`\th order linear homogeneous differential equation with constant coefficients. - - nth order linear inhomogeneous differential equation with constant + - `n`\th order linear inhomogeneous differential equation with constant coefficients using the method of undetermined coefficients. - - nth order linear inhomogeneous differential equation with constant + - `n`\th order linear inhomogeneous differential equation with constant coefficients using the method of variation of parameters. **Philosophy behind this module** -This module is designed to make it easy to add new ODE solving methods -without having to mess with the solving code for other methods. The -idea is that there is a classify_ode() function, which takes in an ODE -and tells you what hints, if any, will solve the ODE. It does this -without attempting to solve the ODE, so it is fast. Each solving method -is a hint, and it has its own function, named ode_hint. That function -takes in the ODE and any match expression gathered by classify_ode and -returns a solved result. If this result has any integrals in it, the -ode_hint function will return an unevaluated Integral class. dsolve(), -which is the user wrapper function around all of this, will then call -odesimp() on the result, which, among other things, will attempt to -solve the equation for the dependent variable (the function we are -solving for), simplify the arbitrary constants in the expression, and -evaluate any integrals, if the hint allows it. +This module is designed to make it easy to add new ODE solving methods without +having to mess with the solving code for other methods. The idea is that +there is a :py:meth:`~sympy.solvers.ode.classify_ode` function, which takes in +an ODE and tells you what hints, if any, will solve the ODE. It does this +without attempting to solve the ODE, so it is fast. Each solving method is a +hint, and it has its own function, named ``ode_``. That function takes +in the ODE and any match expression gathered by +:py:meth:`~sympy.solvers.ode.classify_ode` and returns a solved result. If +this result has any integrals in it, the hint function will return an +unevaluated :py:class:`~sympy.integrals.Integral` class. +:py:meth:`~sympy.solvers.ode.dsolve`, which is the user wrapper function +around all of this, will then call :py:meth:`~sympy.solvers.ode.odesimp` on +the result, which, among other things, will attempt to solve the equation for +the dependent variable (the function we are solving for), simplify the +arbitrary constants in the expression, and evaluate any integrals, if the hint +allows it. **How to add new solution methods** -If you have an ODE that you want dsolve() to be able to solve, try to -avoid adding special case code here. Instead, try finding a general -method that will solve your ODE, as well as others. This way, the ode -module will become more robust, and unhindered by special case hacks. -WolphramAlpha and Maple's DETools[odeadvisor] function are two resources -you can use to classify a specific ODE. It is also better for a method -to work with an nth order ODE instead of only with specific orders, if -possible. - -To add a new method, there are a few things that you need to do. First, -you need a hint name for your method. Try to name your hint so that it -is unambiguous with all other methods, including ones that may not be -implemented yet. If your method uses integrals, also include a -"hint_Integral" hint. If there is more than one way to solve ODEs with -your method, include a hint for each one, as well as a "hint_best" hint. -Your ode_hint_best() function should choose the best using min with -ode_sol_simplicity as the key argument. See -ode_1st_homogeneous_coeff_best(), for example. The function that uses -your method will be called ode_hint(), so the hint must only use -characters that are allowed in a Python function name (alphanumeric -characters and the underscore '_' character). Include a function for -every hint, except for "_Integral" hints (dsolve() takes care of those -automatically). Hint names should be all lowercase, unless a word is -commonly capitalized (such as Integral or Bernoulli). If you have a hint -that you do not want to run with "all_Integral" that doesn't have an -"_Integral" counterpart (such as a best hint that would defeat the -purpose of "all_Integral"), you will need to remove it manually in the -dsolve() code. See also the classify_ode() docstring for guidelines on -writing a hint name. - -Determine *in general* how the solutions returned by your method -compare with other methods that can potentially solve the same ODEs. -Then, put your hints in the allhints tuple in the order that they should -be called. The ordering of this tuple determines which hints are -default. Note that exceptions are ok, because it is easy for the user to -choose individual hints with dsolve(). In general, "_Integral" variants -should go at the end of the list, and "_best" variants should go before -the various hints they apply to. For example, the -"undetermined_coefficients" hint comes before the -"variation_of_parameters" hint because, even though variation of -parameters is more general than undetermined coefficients, undetermined -coefficients generally returns cleaner results for the ODEs that it can -solve than variation of parameters does, and it does not require -integration, so it is much faster. - -Next, you need to have a match expression or a function that matches the -type of the ODE, which you should put in classify_ode() (if the match -function is more than just a few lines, like -_undetermined_coefficients_match(), it should go outside of -classify_ode()). It should match the ODE without solving for it as much -as possible, so that classify_ode() remains fast and is not hindered by -bugs in solving code. Be sure to consider corner cases. For example, if -your solution method involves dividing by something, make sure you -exclude the case where that division will be 0. - -In most cases, the matching of the ODE will also give you the various -parts that you need to solve it. You should put that in a dictionary -(.match() will do this for you), and add that as matching_hints['hint'] -= matchdict in the relevant part of classify_ode. classify_ode will -then send this to dsolve(), which will send it to your function as the -match argument. Your function should be named ode_hint(eq, func, order, -match). If you need to send more information, put it in the match -dictionary. For example, if you had to substitute in a dummy variable -in classify_ode to match the ODE, you will need to pass it to your -function using the match dict to access it. You can access the -independent variable using func.args[0], and the dependent variable (the -function you are trying to solve for) as func.func. If, while trying to -solve the ODE, you find that you cannot, raise NotImplementedError. -dsolve() will catch this error with the "all" meta-hint, rather than -causing the whole routine to fail. - -Add a docstring to your function that describes the method employed. -Like with anything else in SymPy, you will need to add a doctest to the -docstring, in addition to real tests in test_ode.py. Try to maintain -consistency with the other hint functions' docstrings. Add your method -to the list at the top of this docstring. Also, add your method to -ode.rst in the docs/src directory, so that the Sphinx docs will pull its -docstring into the main SymPy documentation. Be sure to make the Sphinx -documentation by running "make html" from within the doc directory to -verify that the docstring formats correctly. - -If your solution method involves integrating, use C.Integral() instead -of integrate(). This allows the user to bypass hard/slow integration by -using the "_Integral" variant of your hint. In most cases, calling -.doit() will integrate your solution. If this is not the case, you will -need to write special code in _handle_Integral(). Arbitrary constants -should be symbols named C1, C2, and so on. All solution methods should -return an equality instance. If you need an arbitrary number of -arbitrary constants, you can use constants = -numbered_symbols(prefix='C', cls=Symbol, start=1). If it is -possible to solve for the dependent function in a general way, do so. +If you have an ODE that you want :py:meth:`~sympy.solvers.ode.dsolve` to be +able to solve, try to avoid adding special case code here. Instead, try +finding a general method that will solve your ODE, as well as others. This +way, the :py:mod:`~sympy.solvers.ode` module will become more robust, and +unhindered by special case hacks. WolphramAlpha and Maple's +DETools[odeadvisor] function are two resources you can use to classify a +specific ODE. It is also better for a method to work with an `n`\th order ODE +instead of only with specific orders, if possible. + +To add a new method, there are a few things that you need to do. First, you +need a hint name for your method. Try to name your hint so that it is +unambiguous with all other methods, including ones that may not be implemented +yet. If your method uses integrals, also include a ``hint_Integral`` hint. +If there is more than one way to solve ODEs with your method, include a hint +for each one, as well as a ``_best`` hint. Your ``ode__best()`` +function should choose the best using min with ``ode_sol_simplicity`` as the +key argument. See +:py:meth:`~sympy.solvers.ode.ode_1st_homogeneous_coeff_best`, for example. +The function that uses your method will be called ``ode_()``, so the +hint must only use characters that are allowed in a Python function name +(alphanumeric characters and the underscore '``_``' character). Include a +function for every hint, except for ``_Integral`` hints +(:py:meth:`~sympy.solvers.ode.dsolve` takes care of those automatically). +Hint names should be all lowercase, unless a word is commonly capitalized +(such as Integral or Bernoulli). If you have a hint that you do not want to +run with ``all_Integral`` that doesn't have an ``_Integral`` counterpart (such +as a best hint that would defeat the purpose of ``all_Integral``), you will +need to remove it manually in the :py:meth:`~sympy.solvers.ode.dsolve` code. +See also the :py:meth:`~sympy.solvers.ode.classify_ode` docstring for +guidelines on writing a hint name. + +Determine *in general* how the solutions returned by your method compare with +other methods that can potentially solve the same ODEs. Then, put your hints +in the :py:data:`~sympy.solvers.ode.allhints` tuple in the order that they +should be called. The ordering of this tuple determines which hints are +default. Note that exceptions are ok, because it is easy for the user to +choose individual hints with :py:meth:`~sympy.solvers.ode.dsolve`. In +general, ``_Integral`` variants should go at the end of the list, and +``_best`` variants should go before the various hints they apply to. For +example, the ``undetermined_coefficients`` hint comes before the +``variation_of_parameters`` hint because, even though variation of parameters +is more general than undetermined coefficients, undetermined coefficients +generally returns cleaner results for the ODEs that it can solve than +variation of parameters does, and it does not require integration, so it is +much faster. + +Next, you need to have a match expression or a function that matches the type +of the ODE, which you should put in :py:meth:`~sympy.solvers.ode.classify_ode` +(if the match function is more than just a few lines, like +:py:meth:`~sympy.solvers.ode._undetermined_coefficients_match`, it should go +outside of :py:meth:`~sympy.solvers.ode.classify_ode`). It should match the +ODE without solving for it as much as possible, so that +:py:meth:`~sympy.solvers.ode.classify_ode` remains fast and is not hindered by +bugs in solving code. Be sure to consider corner cases. For example, if your +solution method involves dividing by something, make sure you exclude the case +where that division will be 0. + +In most cases, the matching of the ODE will also give you the various parts +that you need to solve it. You should put that in a dictionary (``.match()`` +will do this for you), and add that as ``matching_hints['hint'] = matchdict`` +in the relevant part of :py:meth:`~sympy.solvers.ode.classify_ode`. +:py:meth:`~sympy.solvers.ode.classify_ode` will then send this to +:py:meth:`~sympy.solvers.ode.dsolve`, which will send it to your function as +the ``match`` argument. Your function should be named ``ode_(eq, func, +order, match)`. If you need to send more information, put it in the ``match`` +dictionary. For example, if you had to substitute in a dummy variable in +:py:meth:`~sympy.solvers.ode.classify_ode` to match the ODE, you will need to +pass it to your function using the `match` dict to access it. You can access +the independent variable using ``func.args[0]``, and the dependent variable +(the function you are trying to solve for) as ``func.func``. If, while trying +to solve the ODE, you find that you cannot, raise ``NotImplementedError``. +:py:meth:`~sympy.solvers.ode.dsolve` will catch this error with the ``all`` +meta-hint, rather than causing the whole routine to fail. + +Add a docstring to your function that describes the method employed. Like +with anything else in SymPy, you will need to add a doctest to the docstring, +in addition to real tests in ``test_ode.py``. Try to maintain consistency +with the other hint functions' docstrings. Add your method to the list at the +top of this docstring. Also, add your method to ``ode.rst`` in the +``docs/src`` directory, so that the Sphinx docs will pull its docstring into +the main SymPy documentation. Be sure to make the Sphinx documentation by +running ``make html`` from within the doc directory to verify that the +docstring formats correctly. + +If your solution method involves integrating, use :py:meth:`C.Integral() +` instead of +:py:meth:`~sympy.core.expr.Expr.integrate`. This allows the user to bypass +hard/slow integration by using the ``_Integral`` variant of your hint. In +most cases, calling :py:meth:`sympy.core.basic.Basic.doit` will integrate your +solution. If this is not the case, you will need to write special code in +:py:meth:`~sympy.solvers.ode._handle_Integral`. Arbitrary constants should be +symbols named ``C1``, ``C2``, and so on. All solution methods should return +an equality instance. If you need an arbitrary number of arbitrary constants, +you can use ``constants = numbered_symbols(prefix='C', cls=Symbol, start=1)``. +If it is possible to solve for the dependent function in a general way, do so. Otherwise, do as best as you can, but do not call solve in your -ode_hint() function. odesimp() will attempt to solve the solution for -you, so you do not need to do that. Lastly, if your ODE has a common -simplification that can be applied to your solutions, you can add a -special case in odesimp() for it. For example, solutions returned from -the "1st_homogeneous_coeff" hints often have many log() terms, so -odesimp() calls logcombine() on them (it also helps to write the -arbitrary constant as log(C1) instead of C1 in this case). Also +``ode_()`` function. :py:meth:`~sympy.solvers.ode.odesimp` will attempt +to solve the solution for you, so you do not need to do that. Lastly, if your +ODE has a common simplification that can be applied to your solutions, you can +add a special case in :py:meth:`~sympy.solvers.ode.odesimp` for it. For +example, solutions returned from the ``1st_homogeneous_coeff`` hints often +have many :py:meth:`~sympy.functions.log` terms, so +:py:meth:`~sympy.solvers.ode.odesimp` calls +:py:meth:`~sympy.simplify.logcombine` on them (it also helps to write the +arbitrary constant as ``log(C1)`` instead of ``C1`` in this case). Also consider common ways that you can rearrange your solution to have -constantsimp() take better advantage of it. It is better to put -simplification in odesimp() than in your method, because it can then be -turned off with the simplify flag in dsolve(). If you have any -extraneous simplification in your function, be sure to only run it using -"if match.get('simplify', True):", especially if it can be slow or if it -can reduce the domain of the solution. - -Finally, as with every contribution to SymPy, your method will need to -be tested. Add a test for each method in test_ode.py. Follow the -conventions there, i.e., test the solver using dsolve(eq, f(x), -hint=your_hint), and also test the solution using checkodesol (you can -put these in a separate tests and skip/XFAIL if it runs too slow/doesn't -work). Be sure to call your hint specifically in dsolve, that way the -test won't be broken simply by the introduction of another matching -hint. If your method works for higher order (>1) ODEs, you will need to -run sol = constant_renumber(sol, 'C', 1, order), for each solution, where -order is the order of the ODE. This is because constant_renumber renumbers -the arbitrary constants by printing order, which is platform dependent. -Try to test every corner case of your solver, including a range of -orders if it is a nth order solver, but if your solver is slow, auch as -if it involves hard integration, try to keep the test run time down. - -Feel free to refactor existing hints to avoid duplicating code or -creating inconsistencies. If you can show that your method exactly -duplicates an existing method, including in the simplicity and speed of -obtaining the solutions, then you can remove the old, less general -method. The existing code is tested extensively in test_ode.py, so if -anything is broken, one of those tests will surely fail. +:py:meth:`~sympy.solvers.ode.constantsimp` take better advantage of it. It is +better to put simplification in :py:meth:`~sympy.solvers.ode.odesimp` than in +your method, because it can then be turned off with the simplify flag in +:py:meth:`~sympy.solvers.ode.dsolve`. If you have any extraneous +simplification in your function, be sure to only run it using ``if +match.get('simplify', True):``, especially if it can be slow or if it can +reduce the domain of the solution. + +Finally, as with every contribution to SymPy, your method will need to be +tested. Add a test for each method in ``test_ode.py``. Follow the +conventions there, i.e., test the solver using ``dsolve(eq, f(x), +hint=your_hint)``, and also test the solution using +:py:meth:`~sympy.solvers.ode.checkodesol` (you can put these in a separate +tests and skip/XFAIL if it runs too slow/doesn't work). Be sure to call your +hint specifically in :py:meth:`~sympy.solvers.ode.dsolve`, that way the test +won't be broken simply by the introduction of another matching hint. If your +method works for higher order (>1) ODEs, you will need to run ``sol = +constant_renumber(sol, 'C', 1, order)`` for each solution, where ``order`` is +the order of the ODE. This is because ``constant_renumber`` renumbers the +arbitrary constants by printing order, which is platform dependent. Try to +test every corner case of your solver, including a range of orders if it is a +`n`\th order solver, but if your solver is slow, such as if it involves hard +integration, try to keep the test run time down. + +Feel free to refactor existing hints to avoid duplicating code or creating +inconsistencies. If you can show that your method exactly duplicates an +existing method, including in the simplicity and speed of obtaining the +solutions, then you can remove the old, less general method. The existing +code is tested extensively in ``test_ode.py``, so if anything is broken, one +of those tests will surely fail. """ from collections import defaultdict from sympy.core import Add, C, S, Mul, Pow, oo -from sympy.core.compatibility import iterable, is_sequence, set_union +from sympy.core.compatibility import ordered, iterable, is_sequence, set_union from sympy.utilities.exceptions import SymPyDeprecationWarning -from sympy.core.function import Derivative, AppliedUndef, diff, expand_mul +from sympy.core.exprtools import factor_terms, gcd_terms +from sympy.core.function import (Function, Derivative, AppliedUndef, diff, + expand, expand_mul) from sympy.core.multidimensional import vectorize +from sympy.core.numbers import Rational, NaN from sympy.core.relational import Equality, Eq -from sympy.core.symbol import Symbol, Wild, Dummy +from sympy.core.symbol import Symbol, Wild, Dummy, symbols from sympy.core.sympify import sympify -from sympy.functions import cos, exp, im, log, re, sin, tan, sqrt, sign +from sympy.functions import cos, exp, im, log, re, sin, tan, sqrt, sign, Piecewise from sympy.matrices import wronskian -from sympy.polys import Poly, RootOf, terms_gcd +from sympy.polys import Poly, RootOf, terms_gcd, PolynomialError +from sympy.polys.polytools import cancel, degree from sympy.series import Order from sympy.simplify import collect, logcombine, powsimp, separatevars, \ - simplify, trigsimp, denom + simplify, trigsimp, denom, fraction, posify +from sympy.simplify.simplify import _mexpand from sympy.solvers import solve from sympy.utilities import numbered_symbols, default_sort_key, sift +from sympy.solvers.deutils import _preprocess, ode_order, _desolve from functools import reduce -# This is a list of hints in the order that they should be applied. That means -# that, in general, hints earlier in the list should produce simpler results -# than those later for ODEs that fit both. This is just based on my own -# empirical observations, so if you find that *in general*, a hint later in -# the list is better than one before it, fell free to modify the list. Note -# however that you can easily override the hint used in dsolve() for a specific ODE -# (see the docstring). In general, "_Integral" hints should be grouped -# at the end of the list, unless there is a method that returns an unevaluable -# integral most of the time (which should surely go near the end of the list -# anyway). -# "default", "all", "best", and "all_Integral" meta-hints should not be -# included in this list, but "_best" and "_Integral" hints should be included. -allhints = ("separable", "1st_exact", "1st_linear", "Bernoulli", "Riccati_special_minus2", -"1st_homogeneous_coeff_best", "1st_homogeneous_coeff_subs_indep_div_dep", -"1st_homogeneous_coeff_subs_dep_div_indep", "nth_linear_constant_coeff_homogeneous", -"nth_linear_constant_coeff_undetermined_coefficients", -"nth_linear_constant_coeff_variation_of_parameters", -"Liouville", "separable_Integral", "1st_exact_Integral", "1st_linear_Integral", -"Bernoulli_Integral", "1st_homogeneous_coeff_subs_indep_div_dep_Integral", -"1st_homogeneous_coeff_subs_dep_div_indep_Integral", -"nth_linear_constant_coeff_variation_of_parameters_Integral", -"Liouville_Integral") - -def preprocess(expr, func=None, hint='_Integral'): - """Prepare expr for solving by making sure that differentiation - is done so that only func remains in unevaluated derivatives and - (if hint doesn't end with _Integral) that doit is applied to all - other derivatives. If hint is None, don't do any differentiation. - (Currently this may cause some simple differential equations to - fail.) - - In case func is None, an attempt will be made to autodetect the - function to be solved for. - - >>> from sympy.solvers.ode import preprocess - >>> from sympy import Derivative, Function, Integral, sin - >>> from sympy.abc import x, y, z - >>> f, g = list(map(Function, 'fg')) - - Apply doit to derivatives that contain more than the function - of interest: - - >>> preprocess(Derivative(f(x) + x, x)) - (Derivative(f(x), x) + 1, f(x)) - - Do others if the differentiation variable(s) intersect with those - of the function of interest or contain the function of interest: - - >>> preprocess(Derivative(g(x), y, z), f(y)) - (0, f(y)) - >>> preprocess(Derivative(f(y), z), f(y)) - (0, f(y)) - - Do others if the hint doesn't end in '_Integral' (the default - assumes that it does): - - >>> preprocess(Derivative(g(x), y), f(x)) - (Derivative(g(x), y), f(x)) - >>> preprocess(Derivative(f(x), y), f(x), hint='') - (0, f(x)) - - Don't do any derivatives if hint is None: - - >>> preprocess(Derivative(f(x) + 1, x) + Derivative(f(x), y), f(x), hint=None) - (Derivative(f(x) + 1, x) + Derivative(f(x), y), f(x)) - - If it's not clear what the function of interest is, it must be given: - - >>> eq = Derivative(f(x) + g(x), x) - >>> preprocess(eq, g(x)) - (Derivative(f(x), x) + Derivative(g(x), x), g(x)) - >>> try: preprocess(eq) - ... except ValueError: print("A ValueError was raised.") - A ValueError was raised. - - """ +#: This is a list of hints in the order that they should be preferred by +#: :py:meth:`~sympy.solvers.ode.classify_ode`. In general, hints earlier in the +#: list should produce simpler solutions than those later in the list (for +#: ODEs that fit both). For now, the order of this list is based on empirical +#: observations by the developers of SymPy. +#: +#: The hint used by :py:meth:`~sympy.solvers.ode.dsolve` for a specific ODE +#: can be overridden (see the docstring). +#: +#: In general, ``_Integral`` hints are grouped at the end of the list, unless +#: there is a method that returns an unevaluable integral most of the time +#: (which go near the end of the list anyway). ``default``, ``all``, +#: ``best``, and ``all_Integral`` meta-hints should not be included in this +#: list, but ``_best`` and ``_Integral`` hints should be included. +allhints = ( + "separable", + "1st_exact", + "1st_linear", + "Bernoulli", + "Riccati_special_minus2", + "1st_homogeneous_coeff_best", + "1st_homogeneous_coeff_subs_indep_div_dep", + "1st_homogeneous_coeff_subs_dep_div_indep", + "almost_linear", + "linear_coefficients", + "separable_reduced", + "nth_linear_constant_coeff_homogeneous", + "nth_linear_euler_eq_homogeneous", + "nth_linear_constant_coeff_undetermined_coefficients", + "nth_linear_constant_coeff_variation_of_parameters", + "Liouville", + "separable_Integral", + "1st_exact_Integral", + "1st_linear_Integral", + "Bernoulli_Integral", + "1st_homogeneous_coeff_subs_indep_div_dep_Integral", + "1st_homogeneous_coeff_subs_dep_div_indep_Integral", + "almost_linear_Integral", + "linear_coefficients_Integral", + "separable_reduced_Integral", + "nth_linear_constant_coeff_variation_of_parameters_Integral", + "Liouville_Integral", + ) - derivs = expr.atoms(Derivative) - if not func: - funcs = set_union(*[d.atoms(AppliedUndef) for d in derivs]) - if len(funcs) != 1: - raise ValueError('The function cannot be automatically detected for %s.' % expr) - func = funcs.pop() - fvars = set(func.args) - if hint is None: - return expr, func - reps = [(d, d.doit()) for d in derivs if - not hint.endswith('_Integral') or - d.has(func) or - set(d.variables) & fvars] - eq = expr.subs(reps) - return eq, func def sub_func_doit(eq, func, new): - """When replacing the func with something else, we usually - want the derivative evaluated, so this function helps in - making that happen. - - To keep subs from having to look through all derivatives, we - mask them off with dummy variables, do the func sub, and then - replace masked off derivatives with their doit values. + r""" + When replacing the func with something else, we usually want the + derivative evaluated, so this function helps in making that happen. + + To keep subs from having to look through all derivatives, we mask them off + with dummy variables, do the func sub, and then replace masked-off + derivatives with their doit values. Examples ======== @@ -352,119 +326,125 @@ return eq.subs(reps).subs(func, new).subs(repu) -def dsolve(eq, func=None, hint="default", simplify=True, prep=True, **kwargs): - """ + +def dsolve(eq, func=None, hint="default", simplify=True, **kwargs): + r""" Solves any (supported) kind of ordinary differential equation. **Usage** - dsolve(eq, f(x), hint) -> Solve ordinary differential equation - eq for function f(x), using method hint. + ``dsolve(eq, f(x), hint)`` -> Solve ordinary differential equation + ``eq`` for function ``f(x)``, using method ``hint``. **Details** - ``eq`` can be any supported ordinary differential equation (see - the ode docstring for supported methods). This can either - be an Equality, or an expression, which is assumed to be - equal to 0. + ``eq`` can be any supported ordinary differential equation (see the + :py:mod:`~sympy.solvers.ode` docstring for supported methods). + This can either be an :py:class:`~sympy.core.relational.Equality`, + or an expression, which is assumed to be equal to ``0``. ``f(x)`` is a function of one variable whose derivatives in that - variable make up the ordinary differential equation eq. In many - cases it is not necessary to provide this; it will be autodetected - (and an error raised if it couldn't be detected). + variable make up the ordinary differential equation ``eq``. In + many cases it is not necessary to provide this; it will be + autodetected (and an error raised if it couldn't be detected). ``hint`` is the solving method that you want dsolve to use. Use - classify_ode(eq, f(x)) to get all of the possible hints for - an ODE. The default hint, 'default', will use whatever hint - is returned first by classify_ode(). See Hints below for - more options that you can use for hint. - - ``simplify`` enables simplification by odesimp(). See its - docstring for more information. Turn this off, for example, - to disable solving of solutions for func or simplification - of arbitrary constants. It will still integrate with this - hint. Note that the solution may contain more arbitrary - constants than the order of the ODE with this option - enabled. - - ``prep``, when False and when ``func`` is given, will skip the - preprocessing step where the equation is cleaned up so it - is ready for solving. + ``classify_ode(eq, f(x))`` to get all of the possible hints for an + ODE. The default hint, ``default``, will use whatever hint is + returned first by :py:meth:`~sympy.solvers.ode.classify_ode`. See + Hints below for more options that you can use for hint. + + ``simplify`` enables simplification by + :py:meth:`~sympy.solvers.ode.odesimp`. See its docstring for more + information. Turn this off, for example, to disable solving of + solutions for ``func`` or simplification of arbitrary constants. + It will still integrate with this hint. Note that the solution may + contain more arbitrary constants than the order of the ODE with + this option enabled. **Hints** - Aside from the various solving methods, there are also some - meta-hints that you can pass to dsolve(): + Aside from the various solving methods, there are also some meta-hints + that you can pass to :py:meth:`~sympy.solvers.ode.dsolve`: - "default": + ``default``: This uses whatever hint is returned first by - classify_ode(). This is the default argument to - dsolve(). + :py:meth:`~sympy.solvers.ode.classify_ode`. This is the + default argument to :py:meth:`~sympy.solvers.ode.dsolve`. - "all": - To make dsolve apply all relevant classification hints, - use dsolve(ODE, func, hint="all"). This will return a - dictionary of hint:solution terms. If a hint causes - dsolve to raise the NotImplementedError, value of that - hint's key will be the exception object raised. The - dictionary will also include some special keys: - - - order: The order of the ODE. See also ode_order(). - - best: The simplest hint; what would be returned by - "best" below. - - best_hint: The hint that would produce the solution - given by 'best'. If more than one hint produces the - best solution, the first one in the tuple returned by - classify_ode() is chosen. - - default: The solution that would be returned by - default. This is the one produced by the hint that - appears first in the tuple returned by classify_ode(). - - "all_Integral": - This is the same as "all", except if a hint also has a - corresponding "_Integral" hint, it only returns the - "_Integral" hint. This is useful if "all" causes - dsolve() to hang because of a difficult or impossible - integral. This meta-hint will also be much faster than - "all", because integrate() is an expensive routine. - - "best": - To have dsolve() try all methods and return the simplest - one. This takes into account whether the solution is - solvable in the function, whether it contains any - Integral classes (i.e. unevaluatable integrals), and + ``all``: + To make :py:meth:`~sympy.solvers.ode.dsolve` apply all + relevant classification hints, use ``dsolve(ODE, func, + hint="all")``. This will return a dictionary of + ``hint:solution`` terms. If a hint causes dsolve to raise the + ``NotImplementedError``, value of that hint's key will be the + exception object raised. The dictionary will also include + some special keys: + + - ``order``: The order of the ODE. See also + :py:meth:`~sympy.solvers.deutils.ode_order` in + ``deutils.py``. + - ``best``: The simplest hint; what would be returned by + ``best`` below. + - ``best_hint``: The hint that would produce the solution + given by ``best``. If more than one hint produces the best + solution, the first one in the tuple returned by + :py:meth:`~sympy.solvers.ode.classify_ode` is chosen. + - ``default``: The solution that would be returned by default. + This is the one produced by the hint that appears first in + the tuple returned by + :py:meth:`~sympy.solvers.ode.classify_ode`. + + ``all_Integral``: + This is the same as ``all``, except if a hint also has a + corresponding ``_Integral`` hint, it only returns the + ``_Integral`` hint. This is useful if ``all`` causes + :py:meth:`~sympy.solvers.ode.dsolve` to hang because of a + difficult or impossible integral. This meta-hint will also be + much faster than ``all``, because + :py:meth:`~sympy.core.expr.Expr.integrate` is an expensive + routine. + + ``best``: + To have :py:meth:`~sympy.solvers.ode.dsolve` try all methods + and return the simplest one. This takes into account whether + the solution is solvable in the function, whether it contains + any Integral classes (i.e. unevaluatable integrals), and which one is the shortest in size. - See also the classify_ode() docstring for more info on hints, - and the ode docstring for a list of all supported hints. - + See also the :py:meth:`~sympy.solvers.ode.classify_ode` docstring for + more info on hints, and the :py:mod:`~sympy.solvers.ode` docstring for + a list of all supported hints. **Tips** + - You can declare the derivative of an unknown function this way: + >>> from sympy import Function, Derivative >>> from sympy.abc import x # x is the independent variable >>> f = Function("f")(x) # f is a function of x >>> # f_ will be the derivative of f with respect to x >>> f_ = Derivative(f, x) - - See test_ode.py for many tests, which serves also as a set of - examples for how to use dsolve(). - - dsolve always returns an Equality class (except for the case - when the hint is "all" or "all_Integral"). If possible, it - solves the solution explicitly for the function being solved - for. Otherwise, it returns an implicit solution. - - Arbitrary constants are symbols named C1, C2, and so on. - - Because all solutions should be mathematically equivalent, - some hints may return the exact same result for an ODE. Often, - though, two different hints will return the same solution - formatted differently. The two should be equivalent. Also - note that sometimes the values of the arbitrary constants in - two different solutions may not be the same, because one - constant may have "absorbed" other constants into it. - - Do help(ode.ode_hintname) to get help more information on a - specific hint, where hintname is the name of a hint without - "_Integral". + - See ``test_ode.py`` for many tests, which serves also as a set of + examples for how to use :py:meth:`~sympy.solvers.ode.dsolve`. + - :py:meth:`~sympy.solvers.ode.dsolve` always returns an + :py:class:`~sympy.core.relational.Equality` class (except for the + case when the hint is ``all`` or ``all_Integral``). If possible, it + solves the solution explicitly for the function being solved for. + Otherwise, it returns an implicit solution. + - Arbitrary constants are symbols named ``C1``, ``C2``, and so on. + - Because all solutions should be mathematically equivalent, some + hints may return the exact same result for an ODE. Often, though, + two different hints will return the same solution formatted + differently. The two should be equivalent. Also note that sometimes + the values of the arbitrary constants in two different solutions may + not be the same, because one constant may have "absorbed" other + constants into it. + - Do ``help(ode.ode_)`` to get help more information on a + specific hint, where ```` is the name of a hint without + ``_Integral``. Examples ======== @@ -472,211 +452,185 @@ >>> from sympy import Function, dsolve, Eq, Derivative, sin, cos >>> from sympy.abc import x >>> f = Function('f') - >>> dsolve(Derivative(f(x),x,x)+9*f(x), f(x)) + >>> dsolve(Derivative(f(x), x, x) + 9*f(x), f(x)) f(x) == C1*sin(3*x) + C2*cos(3*x) - >>> dsolve(sin(x)*cos(f(x)) + cos(x)*sin(f(x))*f(x).diff(x), f(x), - ... hint='separable', simplify=False) - -log(sin(f(x))**2 - 1)/2 == C1 + log(sin(x)**2 - 1)/2 - >>> dsolve(sin(x)*cos(f(x)) + cos(x)*sin(f(x))*f(x).diff(x), f(x), - ... hint='1st_exact') - f(x) == acos(C1/cos(x)) - >>> dsolve(sin(x)*cos(f(x)) + cos(x)*sin(f(x))*f(x).diff(x), f(x), - ... hint='best') - f(x) == acos(C1/cos(x)) - >>> # Note that even though separable is the default, 1st_exact produces - >>> # a simpler result in this case. - - """ - # TODO: Implement initial conditions - # See issue 1621. We first need a way to represent things like f'(0). - if isinstance(eq, Equality): - eq = eq.lhs - eq.rhs - # preprocess the equation and find func if not given - if prep or func is None: - eq, func = preprocess(eq, func) - prep = False - - # Magic that should only be used internally. Prevents classify_ode from - # being called more than it needs to be by passing its results through - # recursive calls. - if kwargs.get('classify', True): - hints = classify_ode(eq, func, dict=True, prep=prep) - else: - # Here is what all this means: - # - # hint: The hint method given to dsolve() by the user. - # hints: The dictionary of hints that match the ODE, along with - # other information (including the internal pass-through magic). - # default: The default hint to return, the first hint from allhints - # that matches the hint. This is obtained from classify_ode(). - # match: The hints dictionary contains a match dictionary for each hint - # (the parts of the ODE for solving). When going through the - # hints in "all", this holds the match string for the current - # hint. - # order: The order of the ODE, as determined by ode_order(). - hints = kwargs.get('hint', - {'default': hint, - hint: kwargs['match'], - 'order': kwargs['order']}) - - - if hints['order'] == 0: - raise ValueError(str(eq) + " is not a differential equation in " + str(func)) - - if not hints['default']: - # classify_ode will set hints['default'] to None if no hints match. - raise NotImplementedError("dsolve: Cannot solve " + str(eq)) - - if hint == 'default': - return dsolve(eq, func, hint=hints['default'], simplify=simplify, - prep=prep, classify=False, order=hints['order'], - match=hints[hints['default']]) - elif hint in ('all', 'all_Integral', 'best'): + >>> eq = sin(x)*cos(f(x)) + cos(x)*sin(f(x))*f(x).diff(x) + >>> dsolve(eq, hint='separable_reduced') + f(x) == C1/(C2*x - 1) + >>> dsolve(eq, hint='1st_exact') + [f(x) == -acos(C1/cos(x)) + 2*pi, f(x) == acos(C1/cos(x))] + >>> dsolve(eq, hint='almost_linear') + [f(x) == -acos(-sqrt(C1/cos(x)**2)) + 2*pi, f(x) == -acos(sqrt(C1/cos(x)**2)) + 2*pi, + f(x) == acos(-sqrt(C1/cos(x)**2)), f(x) == acos(sqrt(C1/cos(x)**2))] + >>> dsolve(eq, hint='best') + f(x) == C1/(C2*x - 1) + + """ + given_hint = hint # hint given by the user + + # See the docstring of _desolve for more details. + hints = _desolve(eq, func=func, + hint=hint, simplify=True, type='ode', **kwargs) + + eq = hints.pop('eq', eq) + all_ = hints.pop('all', False) + if all_: retdict = {} - failedhints = {} - gethints = set(hints) - set(['order', 'default', 'ordered_hints']) - if hint == 'all_Integral': - for i in hints: - if i.endswith('_Integral'): - gethints.remove(i[:-len('_Integral')]) - # special case - if "1st_homogeneous_coeff_best" in gethints: - gethints.remove("1st_homogeneous_coeff_best") - for i in gethints: + failed_hints = {} + gethints = classify_ode(eq, dict=True) + orderedhints = gethints['ordered_hints'] + for hint in hints: try: - sol = dsolve(eq, func, hint=i, simplify=simplify, prep=prep, - classify=False, order=hints['order'], match=hints[i]) - except NotImplementedError as detail: # except NotImplementedError as detail: - failedhints[i] = detail + rv = _helper_simplify(eq, hint, hints[hint], simplify) + except NotImplementedError as detail: + failed_hints[hint] = detail else: - retdict[i] = sol + retdict[hint] = rv + func = hints[hint]['func'] retdict['best'] = min(list(retdict.values()), key=lambda x: ode_sol_simplicity(x, func, trysolving=not simplify)) - if hint == 'best': + if given_hint == 'best': return retdict['best'] - for i in hints['ordered_hints']: + for i in orderedhints: if retdict['best'] == retdict.get(i, None): retdict['best_hint'] = i break - retdict['default'] = hints['default'] - retdict['order'] = sympify(hints['order']) - retdict.update(failedhints) + retdict['default'] = gethints['default'] + retdict['order'] = gethints['order'] + retdict.update(failed_hints) return retdict - elif hint not in allhints: # and hint not in ('default', 'ordered_hints'): - raise ValueError("Hint not recognized: " + hint) - elif hint not in hints: - raise ValueError("ODE " + str(eq) + " does not match hint " + hint) - elif hint.endswith('_Integral'): + + else: + # The key 'hint' stores the hint needed to be solved for. + hint = hints['hint'] + return _helper_simplify(eq, hint, hints, simplify) + +def _helper_simplify(eq, hint, match, simplify=True): + r""" + Helper function of dsolve that calls the respective + :py:mod:`~sympy.solvers.ode` functions to solve for the ordinary + differential equations. This minimises the computation in calling + :py:meth:`~sympy.solvers.deutils._desolve` multiple times. + """ + r = match + if hint.endswith('_Integral'): solvefunc = globals()['ode_' + hint[:-len('_Integral')]] else: - solvefunc = globals()['ode_' + hint] # convert the string into a function - # odesimp() will attempt to integrate, if necessary, apply constantsimp(), - # attempt to solve for func, and apply any other hint specific simplifications + solvefunc = globals()['ode_' + hint] + func = r['func'] + order = r['order'] + match = r[hint] if simplify: - rv = odesimp(solvefunc(eq, func, order=hints['order'], - match=hints[hint]), func, hints['order'], hint) + # odesimp() will attempt to integrate, if necessary, apply constantsimp(), + # attempt to solve for func, and apply any other hint specific + # simplifications + rv = odesimp(solvefunc(eq, func, order, match), func, order, hint) + return rv else: # We still want to integrate (you can disable it separately with the hint) - r = hints[hint] - r['simplify'] = False # Some hints can take advantage of this option - rv = _handle_Integral(solvefunc(eq, func, order=hints['order'], - match=hints[hint]), func, hints['order'], hint) - return rv + match['simplify'] = False # Some hints can take advantage of this option + rv = _handle_Integral(solvefunc(eq, func, order, match), + func, order, hint) + return rv -def classify_ode(eq, func=None, dict=False, prep=True): - """ - Returns a tuple of possible dsolve() classifications for an ODE. +def classify_ode(eq, func=None, dict=False, **kwargs): + r""" + Returns a tuple of possible :py:meth:`~sympy.solvers.ode.dsolve` + classifications for an ODE. The tuple is ordered so that first item is the classification that - dsolve() uses to solve the ODE by default. In general, - classifications at the near the beginning of the list will produce - better solutions faster than those near the end, thought there are - always exceptions. To make dsolve use a different classification, - use dsolve(ODE, func, hint=). See also the dsolve() - docstring for different meta-hints you can use. - - If ``dict`` is true, classify_ode() will return a dictionary of - hint:match expression terms. This is intended for internal use by - dsolve(). Note that because dictionaries are ordered arbitrarily, - this will most likely not be in the same order as the tuple. - - If ``prep`` is False or ``func`` is None then the equation - will be preprocessed to put it in standard form for classification. - - You can get help on different hints by doing help(ode.ode_hintname), - where hintname is the name of the hint without "_Integral". - - See sympy.ode.allhints or the sympy.ode docstring for a list of all - supported hints that can be returned from classify_ode. + :py:meth:`~sympy.solvers.ode.dsolve` uses to solve the ODE by default. In + general, classifications at the near the beginning of the list will + produce better solutions faster than those near the end, thought there are + always exceptions. To make :py:meth:`~sympy.solvers.ode.dsolve` use a + different classification, use ``dsolve(ODE, func, + hint=)``. See also the + :py:meth:`~sympy.solvers.ode.dsolve` docstring for different meta-hints + you can use. + + If ``dict`` is true, :py:meth:`~sympy.solvers.ode.classify_ode` will + return a dictionary of ``hint:match`` expression terms. This is intended + for internal use by :py:meth:`~sympy.solvers.ode.dsolve`. Note that + because dictionaries are ordered arbitrarily, this will most likely not be + in the same order as the tuple. + + You can get help on different hints by executing + ``help(ode.ode_hintname)``, where ``hintname`` is the name of the hint + without ``_Integral``. + + See :py:data:`~sympy.solvers.ode.allhints` or the + :py:mod:`~sympy.solvers.ode` docstring for a list of all supported hints + that can be returned from :py:meth:`~sympy.solvers.ode.classify_ode`. Notes ===== These are remarks on hint names. - *"_Integral"* + ``_Integral`` - If a classification has "_Integral" at the end, it will return - the expression with an unevaluated Integral class in it. Note - that a hint may do this anyway if integrate() cannot do the - integral, though just using an "_Integral" will do so much - faster. Indeed, an "_Integral" hint will always be faster than - its corresponding hint without "_Integral" because integrate() - is an expensive routine. If dsolve() hangs, it is probably - because integrate() is hanging on a tough or impossible - integral. Try using an "_Integral" hint or "all_Integral" to - get it return something. - - Note that some hints do not have "_Integral" counterparts. This - is because integrate() is not used in solving the ODE for those - method. For example, nth order linear homogeneous ODEs with - constant coefficients do not require integration to solve, so - there is no "nth_linear_homogeneous_constant_coeff_Integrate" - hint. You can easily evaluate any unevaluated Integrals in an - expression by doing expr.doit(). - - *Ordinals* - - Some hints contain an ordinal such as "1st_linear". This is to - help differentiate them from other hints, as well as from other - methods that may not be implemented yet. If a hint has "nth" in - it, such as the "nth_linear" hints, this means that the method - used to applies to ODEs of any order. - - *"indep" and "dep"* - - Some hints contain the words "indep" or "dep". These reference - the independent variable and the dependent function, - respectively. For example, if an ODE is in terms of f(x), then - "indep" will refer to x and "dep" will refer to f. - - *"subs"* - - If a hints has the word "subs" in it, it means the the ODE is - solved by substituting the expression given after the word - "subs" for a single dummy variable. This is usually in terms of - "indep" and "dep" as above. The substituted expression will be - written only in characters allowed for names of Python objects, - meaning operators will be spelled out. For example, indep/dep - will be written as indep_div_dep. - - *"coeff"* - - The word "coeff" in a hint refers to the coefficients of - something in the ODE, usually of the derivative terms. See the - docstring for the individual methods for more info (help(ode)). - This is contrast to "coefficients", as in - "undetermined_coefficients", which refers to the common name of - a method. - - *"_best"* - - Methods that have more than one fundamental way to solve will - have a hint for each sub-method and a "_best" - meta-classification. This will evaluate all hints and return the - best, using the same considerations as the normal "best" - meta-hint. + If a classification has ``_Integral`` at the end, it will return the + expression with an unevaluated :py:class:`~sympy.integrals.Integral` + class in it. Note that a hint may do this anyway if + :py:meth:`~sympy.core.expr.Expr.integrate` cannot do the integral, + though just using an ``_Integral`` will do so much faster. Indeed, an + ``_Integral`` hint will always be faster than its corresponding hint + without ``_Integral`` because + :py:meth:`~sympy.core.expr.Expr.integrate` is an expensive routine. + If :py:meth:`~sympy.solvers.ode.dsolve` hangs, it is probably because + :py:meth:`~sympy.core.expr.Expr.integrate` is hanging on a tough or + impossible integral. Try using an ``_Integral`` hint or + ``all_Integral`` to get it return something. + + Note that some hints do not have ``_Integral`` counterparts. This is + because :py:meth:`~sympy.solvers.ode.integrate` is not used in solving + the ODE for those method. For example, `n`\th order linear homogeneous + ODEs with constant coefficients do not require integration to solve, + so there is no ``nth_linear_homogeneous_constant_coeff_Integrate`` + hint. You can easily evaluate any unevaluated + :py:class:`~sympy.integrals.Integral`\s in an expression by doing + ``expr.doit()``. + + Ordinals + + Some hints contain an ordinal such as ``1st_linear``. This is to help + differentiate them from other hints, as well as from other methods + that may not be implemented yet. If a hint has ``nth`` in it, such as + the ``nth_linear`` hints, this means that the method used to applies + to ODEs of any order. + + ``indep`` and ``dep`` + + Some hints contain the words ``indep`` or ``dep``. These reference + the independent variable and the dependent function, respectively. For + example, if an ODE is in terms of `f(x)`, then ``indep`` will refer to + `x` and ``dep`` will refer to `f`. + + ``subs`` + + If a hints has the word ``subs`` in it, it means the the ODE is solved + by substituting the expression given after the word ``subs`` for a + single dummy variable. This is usually in terms of ``indep`` and + ``dep`` as above. The substituted expression will be written only in + characters allowed for names of Python objects, meaning operators will + be spelled out. For example, ``indep``/``dep`` will be written as + ``indep_div_dep``. + + ``coeff`` + + The word ``coeff`` in a hint refers to the coefficients of something + in the ODE, usually of the derivative terms. See the docstring for + the individual methods for more info (``help(ode)``). This is + contrast to ``coefficients``, as in ``undetermined_coefficients``, + which refers to the common name of a method. + + ``_best`` + + Methods that have more than one fundamental way to solve will have a + hint for each sub-method and a ``_best`` meta-classification. This + will evaluate all hints and return the best, using the same + considerations as the normal ``best`` meta-hint. Examples @@ -699,13 +653,14 @@ 'nth_linear_constant_coeff_variation_of_parameters_Integral') """ + prep = kwargs.pop('prep', True) from sympy import expand if func and len(func.args) != 1: - raise ValueError("dsolve() and classify_ode() only work with functions " + \ - "of one variable") + raise ValueError("dsolve() and classify_ode() only " + "work with functions of one variable, not %s" % func) if prep or func is None: - eq, func_ = preprocess(eq, func) + eq, func_ = _preprocess(eq, func) if func is None: func = func_ x = func.args[0] @@ -713,7 +668,7 @@ y = Dummy('y') if isinstance(eq, Equality): if eq.rhs != 0: - return classify_ode(eq.lhs-eq.rhs, func, prep=False) + return classify_ode(eq.lhs - eq.rhs, func, prep=False) eq = eq.lhs order = ode_order(eq, f(x)) # hint:matchdict or hint:(tuple of matchdicts) @@ -757,7 +712,7 @@ if order == 1: - # Linear case: a(x)*y'+b(x)*y+c(x) == 0 + ## Linear case: a(x)*y'+b(x)*y+c(x) == 0 if eq.is_Add: ind, dep = reduced_eq.as_independent(f) else: @@ -768,16 +723,18 @@ b: dep.coeff(f(x)), c: ind} # double check f[a] since the preconditioning may have failed - if not r[a].has(f) and (r[a]*df + r[b]*f(x) + r[c]).expand() - reduced_eq == 0: + if not r[a].has(f) and ( + r[a]*df + r[b]*f(x) + r[c]).expand() - reduced_eq == 0: r['a'] = a r['b'] = b r['c'] = c matching_hints["1st_linear"] = r matching_hints["1st_linear_Integral"] = r - # Bernoulli case: a(x)*y'+b(x)*y+c(x)*y**n == 0 - r = collect(reduced_eq, f(x), exact = True).match(a*df + b*f(x) + c*f(x)**n) - if r and r[c] != 0 and r[n] != 1: # See issue 1577 + ## Bernoulli case: a(x)*y'+b(x)*y+c(x)*y**n == 0 + r = collect( + reduced_eq, f(x), exact=True).match(a*df + b*f(x) + c*f(x)**n) + if r and r[c] != 0 and r[n] != 1: # See issue 1577 r['a'] = a r['b'] = b r['c'] = c @@ -785,8 +742,9 @@ matching_hints["Bernoulli"] = r matching_hints["Bernoulli_Integral"] = r - # Riccati special n == -2 case: a2*y'+b2*y**2+c2*y/x+d2/x**2 == 0 - r = collect(reduced_eq, f(x), exact = True).match(a2*df + b2*f(x)**2 + c2*f(x)/x + d2/x**2) + ## Riccati special n == -2 case: a2*y'+b2*y**2+c2*y/x+d2/x**2 == 0 + r = collect(reduced_eq, + f(x), exact=True).match(a2*df + b2*f(x)**2 + c2*f(x)/x + d2/x**2) if r and r[b2] != 0 and (r[c2] != 0 or r[d2] != 0): r['a2'] = a2 r['b2'] = b2 @@ -794,19 +752,51 @@ r['d2'] = d2 matching_hints["Riccati_special_minus2"] = r - # Exact Differential Equation: P(x,y)+Q(x,y)*y'=0 where dP/dy == dQ/dx - # WITH NON-REDUCED FORM OF EQUATION - r = collect(eq, df, exact = True).match(d + e * df) + # NON-REDUCED FORM OF EQUATION matches + r = collect(eq, df, exact=True).match(d + e * df) if r: r['d'] = d r['e'] = e r['y'] = y - r[d] = r[d].subs(f(x),y) - r[e] = r[e].subs(f(x),y) + r[d] = r[d].subs(f(x), y) + r[e] = r[e].subs(f(x), y) + + ## Exact Differential Equation: P(x, y) + Q(x, y)*y' = 0 where + # dP/dy == dQ/dx try: - if r[d] != 0 and simplify(r[d].diff(y)) == simplify(r[e].diff(x)): - matching_hints["1st_exact"] = r - matching_hints["1st_exact_Integral"] = r + if r[d] != 0: + numerator = simplify(r[d].diff(y) - r[e].diff(x)) + # The following few conditions try to convert a non-exact + # differential equation into an exact one. + # References : Differential equations with applications + # and historical notes - George E. Simmons + + if numerator: + # If (dP/dy - dQ/dx) / Q = f(x) + # then exp(integral(f(x))*equation becomes exact + factor = simplify(numerator/r[e]) + variables = factor.free_symbols + if len(variables) == 1 and x == variables.pop(): + factor = exp(C.Integral(factor).doit()) + r[d] *= factor + r[e] *= factor + matching_hints["1st_exact"] = r + matching_hints["1st_exact_Integral"] = r + else: + # If (dP/dy - dQ/dx) / -P = f(y) + # then exp(integral(f(y))*equation becomes exact + factor = simplify(-numerator/r[d]) + variables = factor.free_symbols + if len(variables) == 1 and y == variables.pop(): + factor = exp(C.Integral(factor).doit()) + r[d] *= factor + r[e] *= factor + matching_hints["1st_exact"] = r + matching_hints["1st_exact_Integral"] = r + else: + matching_hints["1st_exact"] = r + matching_hints["1st_exact_Integral"] = r + except NotImplementedError: # Differentiating the coefficients might fail because of things # like f(2*x).diff(x). See issue 1525 and issue 1620. @@ -814,45 +804,126 @@ # This match is used for several cases below; we now collect on # f(x) so the matching works. - r = collect(reduced_eq, df, exact = True).match(d+e*df) + r = collect(reduced_eq, df, exact=True).match(d + e*df) if r: + # Using r[d] and r[e] without any modification for hints + # linear-coefficients and separable-reduced. + num, den = r[d], r[e] # ODE = d/e + df r['d'] = d r['e'] = e r['y'] = y - r[d] = r[d].subs(f(x),y) - r[e] = r[e].subs(f(x),y) + r[d] = num.subs(f(x), y) + r[e] = den.subs(f(x), y) - # Separable Case: y' == P(y)*Q(x) + ## Separable Case: y' == P(y)*Q(x) r[d] = separatevars(r[d]) r[e] = separatevars(r[e]) # m1[coeff]*m1[x]*m1[y] + m2[coeff]*m2[x]*m2[y]*y' m1 = separatevars(r[d], dict=True, symbols=(x, y)) m2 = separatevars(r[e], dict=True, symbols=(x, y)) if m1 and m2: - r1 = {'m1':m1, 'm2':m2, 'y':y} + r1 = {'m1': m1, 'm2': m2, 'y': y} matching_hints["separable"] = r1 matching_hints["separable_Integral"] = r1 - # First order equation with homogeneous coefficients: + ## First order equation with homogeneous coefficients: # dy/dx == F(y/x) or dy/dx == F(x/y) ordera = homogeneous_order(r[d], x, y) - orderb = homogeneous_order(r[e], x, y) - if ordera == orderb and ordera is not None: - # u1=y/x and u2=x/y - u1 = Dummy('u1') - u2 = Dummy('u2') - if simplify((r[d]+u1*r[e]).subs({x:1, y:u1})) != 0: - matching_hints["1st_homogeneous_coeff_subs_dep_div_indep"] = r - matching_hints["1st_homogeneous_coeff_subs_dep_div_indep_Integral"] = r - if simplify((r[e]+u2*r[d]).subs({x:u2, y:1})) != 0: - matching_hints["1st_homogeneous_coeff_subs_indep_div_dep"] = r - matching_hints["1st_homogeneous_coeff_subs_indep_div_dep_Integral"] = r - if "1st_homogeneous_coeff_subs_dep_div_indep" in matching_hints \ - and "1st_homogeneous_coeff_subs_indep_div_dep" in matching_hints: - matching_hints["1st_homogeneous_coeff_best"] = r + if ordera is not None: + orderb = homogeneous_order(r[e], x, y) + if ordera == orderb: + # u1=y/x and u2=x/y + u1 = Dummy('u1') + u2 = Dummy('u2') + s = "1st_homogeneous_coeff_subs" + s1 = s + "_dep_div_indep" + s2 = s + "_indep_div_dep" + if simplify((r[d] + u1*r[e]).subs({x: 1, y: u1})) != 0: + matching_hints[s1] = r + matching_hints[s1 + "_Integral"] = r + if simplify((r[e] + u2*r[d]).subs({x: u2, y: 1})) != 0: + matching_hints[s2] = r + matching_hints[s2 + "_Integral"] = r + if s1 in matching_hints and s2 in matching_hints: + matching_hints["1st_homogeneous_coeff_best"] = r + + ## Linear coefficients of the form + # y'+ F((a*x + b*y + c)/(a'*x + b'y + c')) = 0 + # that can be reduced to homogeneous form. + F = num/den + params = _linear_coeff_match(F, func) + if params: + xarg, yarg = params + u = Dummy('u') + t = Dummy('t') + # Dummy substitution for df and f(x). + dummy_eq = reduced_eq.subs(((df, t), (f(x), u))) + reps = ((x, x + xarg), (u, u + yarg), (t, df), (u, f(x))) + dummy_eq = simplify(dummy_eq.subs(reps)) + # get the re-cast values for e and d + r2 = collect(expand(dummy_eq), [df, f(x)]).match(e*df + d) + if r2: + orderd = homogeneous_order(r2[d], x, f(x)) + if orderd is not None: + ordere = homogeneous_order(r2[e], x, f(x)) + if orderd == ordere: + # Match arguments are passed in such a way that it + # is coherent with the already existing homogeneous + # functions. + r2[d] = r2[d].subs(f(x), y) + r2[e] = r2[e].subs(f(x), y) + r2.update({'xarg': xarg, 'yarg': yarg, + 'd': d, 'e': e, 'y': y}) + matching_hints["linear_coefficients"] = r2 + matching_hints["linear_coefficients_Integral"] = r2 + + ## Equation of the form y' + (y/x)*H(x^n*y) = 0 + # that can be reduced to separable form + + factor = simplify(x/f(x)*num/den) + + # Try representing factor in terms of x^n*y + # where n is lowest power of x in factor; + # first remove terms like sqrt(2)*3 from factor.atoms(Mul) + u = None + for mul in ordered(factor.atoms(Mul)): + if mul.has(x): + _, u = mul.as_independent(x, f(x)) + break + if u and u.has(f(x)): + t = Dummy('t') + r2 = {'t': t} + xpart, ypart = u.as_independent(f(x)) + test = factor.subs(((u, t), (1/u, 1/t))) + free = test.free_symbols + if len(free) == 1 and free.pop() == t: + r2.update({'power': xpart.as_base_exp()[1], 'u': test}) + matching_hints["separable_reduced"] = r2 + matching_hints["separable_reduced_Integral"] = r2 + + ## Almost-linear equation of the form f(x)*g(y)*y' + k(x)*l(y) + m(x) = 0 + r = collect(eq, [df, f(x)]).match(e*df + d) + if r: + r2 = r.copy() + r2[c] = S.Zero + if r2[d].is_Add: + # Separate the terms having f(x) to r[d] and + # remaining to r[c] + no_f, r2[d] = r2[d].as_independent(f(x)) + r2[c] += no_f + factor = simplify(r2[d].diff(f(x))/r[e]) + if factor and not factor.has(f(x)): + r2[d] = factor_terms(r2[d]) + u = r2[d].as_independent(f(x), as_Add=False)[1] + r2.update({'a': e, 'b': d, 'c': c, 'u': u}) + r2[d] /= u + r2[e] /= u.diff(f(x)) + matching_hints["almost_linear"] = r2 + matching_hints["almost_linear_Integral"] = r2 if order == 2: - # Liouville ODE f(x).diff(x, 2) + g(f(x))*(f(x).diff(x))**2 + h(x)*f(x).diff(x) + # Liouville ODE in the form + # f(x).diff(x, 2) + g(f(x))*(f(x).diff(x))**2 + h(x)*f(x).diff(x) # See Goldstein and Braun, "Advanced Methods for the Solution of # Differential Equations", pg. 98 @@ -865,11 +936,10 @@ if h.has(f(x)) or g.has(x): pass else: - r = {'g':g, 'h':h, 'y':y} + r = {'g': g, 'h': h, 'y': y} matching_hints["Liouville"] = r matching_hints["Liouville_Integral"] = r - if order > 0: # nth order linear ODE # a_n(x)y^(n) + ... + a_1(x)y' + a_0(x)y = F(x) = b @@ -881,35 +951,54 @@ # Inhomogeneous case: F(x) is not identically 0 if r[-1]: undetcoeff = _undetermined_coefficients_match(r[-1], x) - matching_hints["nth_linear_constant_coeff_variation_of_parameters"] = r - matching_hints["nth_linear_constant_coeff_variation_of_parameters" + \ - "_Integral"] = r + s = "nth_linear_constant_coeff_variation_of_parameters" + matching_hints[s] = r + matching_hints[s + "_Integral"] = r if undetcoeff['test']: r['trialset'] = undetcoeff['trialset'] - matching_hints["nth_linear_constant_coeff_undetermined_" + \ + matching_hints["nth_linear_constant_coeff_undetermined_" "coefficients"] = r # Homogeneous case: F(x) is identically 0 else: matching_hints["nth_linear_constant_coeff_homogeneous"] = r + # Euler equation case (a_i * x**i for all i) + def _test_term(coeff, order): + r""" + Linear Euler ODEs have the form K*x**order*diff(y(x),x,order), + where K is independent of x and y(x), order>= 0. + So we need to check that for each term, coeff == K*x**order from + some K. We have a few cases, since coeff may have several + different types. + """ + assert order >= 0 + if coeff == 0: + return True + if order == 0: + if x in coeff.free_symbols: + return False + return f(x) not in coeff.atoms() + if coeff.is_Mul: + if coeff.has(f(x)): + return False + return x**order in coeff.args + elif coeff.is_Pow: + return coeff.as_base_exp() == (x, order) + elif order == 1: + return x == coeff + return False + if r and not any(not _test_term(r[i], i) for i in r if i >= 0): + if not r[-1]: + matching_hints["nth_linear_euler_eq_homogeneous"] = r # Order keys based on allhints. - retlist = [] - for i in allhints: - if i in matching_hints: - retlist.append(i) - + retlist = [i for i in allhints if i in matching_hints] if dict: - # Dictionaries are ordered arbitrarily, so we need to make note of which - # hint would come first for dsolve(). In Python 3, this should be replaced - # with an ordered dictionary. - matching_hints["default"] = None + # Dictionaries are ordered arbitrarily, so make note of which + # hint would come first for dsolve(). Use an ordered dict in Py 3. + matching_hints["default"] = retlist[0] if retlist else None matching_hints["ordered_hints"] = tuple(retlist) - for i in allhints: - if i in matching_hints: - matching_hints["default"] = i - break return matching_hints else: return tuple(retlist) @@ -917,19 +1006,22 @@ @vectorize(0) def odesimp(eq, func, order, hint): r""" - Simplifies ODEs, including trying to solve for func and running - constantsimp(). + Simplifies ODEs, including trying to solve for ``func`` and running + :py:meth:`~sympy.solvers.ode.constantsimp`. - It may use knowledge of the type of solution that that hint returns - to apply additional simplifications. + It may use knowledge of the type of solution that the hint returns to + apply additional simplifications. - It also attempts to integrate any Integrals in the expression, if - the hint is not an "_Integral" hint. + It also attempts to integrate any :py:class:`~sympy.integrals.Integral`\s + in the expression, if the hint is not an ``_Integral`` hint. This function should have no effect on expressions returned by - dsolve(), as dsolve already calls odesimp(), but the individual hint - functions do not call odesimp (because the dsolve() wrapper does). - Therefore, this function is designed for mainly internal use. + :py:meth:`~sympy.solvers.ode.dsolve`, as + :py:meth:`~sympy.solvers.ode.dsolve` already calls + :py:meth:`~sympy.solvers.ode.odesimp`, but the individual hint functions + do not call :py:meth:`~sympy.solvers.ode.odesimp` (because the + :py:meth:`~sympy.solvers.ode.dsolve` wrapper does). Therefore, this + function is designed for mainly internal use. Examples ======== @@ -942,19 +1034,22 @@ >>> eq = dsolve(x*f(x).diff(x) - f(x) - x*sin(f(x)/x), f(x), ... hint='1st_homogeneous_coeff_subs_indep_div_dep_Integral', ... simplify=False) - >>> pprint(eq) - x - ---- - f(x) - / - | - /f(x)\ | / 1 1 \ - log|----| - | |- -- - -----------| d(u2) = 0 - \ C1 / | | u2 2 /1 \| - | | u2 *sin|--|| - | \ \u2// - | - / + >>> pprint(eq, wrap_line=False) + x + ---- + f(x) + / + | + | / 1 \ + | -|u2 + -------| + | | /1 \| + | | sin|--|| + | \ \u2// + log(f(x)) = log(C1) + | ---------------- d(u2) + | 2 + | u2 + | + / >>> pprint(odesimp(eq, f(x), 1, ... hint='1st_homogeneous_coeff_subs_indep_div_dep' @@ -997,8 +1092,8 @@ # special simplification of the rhs if hint.startswith("nth_linear_constant_coeff"): # Collect terms to make the solution look nice. - # This is also necessary for constantsimp to remove unnecessary terms - # from the particular solution from variation of parameters + # This is also necessary for constantsimp to remove unnecessary + # terms from the particular solution from variation of parameters global collectterms assert len(eq) == 1 and eq[0].lhs == f(x) sol = eq[0].rhs @@ -1014,10 +1109,10 @@ else: # The solution is not solved, so try to solve it try: - eqsol = solve(eq, func) + eqsol = solve(eq, func, force=True) if not eqsol: raise NotImplementedError - except NotImplementedError: + except (NotImplementedError, PolynomialError): eq = [eq] else: def _expand(expr): @@ -1038,7 +1133,7 @@ if hint.startswith("1st_homogeneous_coeff"): for j, eqi in enumerate(eq): newi = logcombine(eqi, force=True) - if newi.lhs.is_Function and newi.lhs.func is log and newi.rhs == 0: + if newi.lhs.func is log and newi.rhs == 0: newi = Eq(newi.lhs.args[0]/C1, C1) eq[j] = newi @@ -1046,52 +1141,53 @@ # a simpler expression, but the solved expression could have introduced # things like -C1, so rerun constantsimp() one last time before returning. for i, eqi in enumerate(eq): - eq[i] = constant_renumber(constantsimp(eqi, x, 2*order), 'C', 1, 2*order) + eqi = constantsimp(eqi, x, 2*order) + eq[i] = constant_renumber(eqi, 'C', 1, 2*order) # If there is only 1 solution, return it; # otherwise return the list of solutions. if len(eq) == 1: eq = eq[0] - return eq def checkodesol(ode, sol, func=None, order='auto', solve_for_func=True): - """ - Substitutes sol into the ode and checks that the result is 0. + r""" + Substitutes ``sol`` into ``ode`` and checks that the result is ``0``. - This only works when func is one function, like f(x). sol can be a - single solution or a list of solutions. Each solution may be an Equality - that the solution satisfies, e.g. Eq(f(x), C1), Eq(f(x) + C1, 0); or simply - an Expr, e.g. f(x) - C1. In most cases it will not be necessary to - explicitly identify the function, but if the function cannot be inferred - from the original equation it can be supplied through the 'func' argument. - - If a sequence of solutions is passed, the same sort of container will be used - to return the result for each solution. - - It tries the following methods, in order, until it finds zero - equivalence: - - 1. Substitute the solution for f in the original equation. This - only works if the ode is solved for f. It will attempt to solve - it first unless solve_for_func == False - 2. Take n derivatives of the solution, where n is the order of - ode, and check to see if that is equal to the solution. This - only works on exact odes. - 3. Take the 1st, 2nd, ..., nth derivatives of the solution, each - time solving for the derivative of f of that order (this will - always be possible because f is a linear operator). Then back - substitute each derivative into ode in reverse order. - - This function returns a tuple. The first item in the tuple is True - if the substitution results in 0, and False otherwise. The second - item in the tuple is what the substitution results in. It should - always be 0 if the first item is True. Note that sometimes this - function will False, but with an expression that is identically - equal to 0, instead of returning True. This is because simplify() - cannot reduce the expression to 0. If an expression returned by - this function vanishes identically, then sol really is a solution to - ode. + This only works when ``func`` is one function, like `f(x)`. ``sol`` can + be a single solution or a list of solutions. Each solution may be an + :py:class:`~sympy.core.relational.Equality` that the solution satisfies, + e.g. ``Eq(f(x), C1), Eq(f(x) + C1, 0)``; or simply an + :py:class:`~sympy.core.expr.Expr`, e.g. ``f(x) - C1``. In most cases it + will not be necessary to explicitly identify the function, but if the + function cannot be inferred from the original equation it can be supplied + through the ``func`` argument. + + If a sequence of solutions is passed, the same sort of container will be + used to return the result for each solution. + + It tries the following methods, in order, until it finds zero equivalence: + + 1. Substitute the solution for `f` in the original equation. This only + works if ``ode`` is solved for `f`. It will attempt to solve it first + unless ``solve_for_func == False``. + 2. Take `n` derivatives of the solution, where `n` is the order of + ``ode``, and check to see if that is equal to the solution. This only + works on exact ODEs. + 3. Take the 1st, 2nd, ..., `n`\th derivatives of the solution, each time + solving for the derivative of `f` of that order (this will always be + possible because `f` is a linear operator). Then back substitute each + derivative into ``ode`` in reverse order. + + This function returns a tuple. The first item in the tuple is ``True`` if + the substitution results in ``0``, and ``False`` otherwise. The second + item in the tuple is what the substitution results in. It should always + be ``0`` if the first item is ``True``. Note that sometimes this function + will ``False``, but with an expression that is identically equal to ``0``, + instead of returning ``True``. This is because + :py:meth:`~sympy.simplify.simplify.simplify` cannot reduce the expression + to ``0``. If an expression returned by this function vanishes + identically, then ``sol`` really is a solution to ``ode``. If this function seems to hang, it is probably because of a hard simplification. @@ -1116,24 +1212,27 @@ ode = Eq(ode, 0) if func is None: try: - _, func = preprocess(ode.lhs) + _, func = _preprocess(ode.lhs) except ValueError: - funcs = [s.atoms(AppliedUndef) for s in (sol if is_sequence(sol, set) else [sol])] + funcs = [s.atoms(AppliedUndef) for s in ( + sol if is_sequence(sol, set) else [sol])] funcs = reduce(set.union, funcs, set()) if len(funcs) != 1: - raise ValueError('must pass func arg to checkodesol for this case.') + raise ValueError( + 'must pass func arg to checkodesol for this case.') func = funcs.pop() # ========== deprecation handling # After the deprecation period this handling section becomes: # ---------- # if not is_unfunc(func) or len(func.args) != 1: - # raise ValueError("func must be a function of one variable, not %s" % func) + # raise ValueError( + # "func must be a function of one variable, not %s" % func) # ---------- - # assume, during deprecation that sol and func are reversed + # assume, during deprecation, that sol and func are reversed if isinstance(sol, AppliedUndef) and len(sol.args) == 1: if isinstance(func, AppliedUndef) and len(func.args) == 1: msg = "If you really do want sol to be just %s, use Eq(%s, 0) " % \ - (sol, sol) + "instead." + (sol, sol) + "instead." else: msg = "" SymPyDeprecationWarning(msg, feature="The order of the " @@ -1158,8 +1257,9 @@ testnum = 0 if order == 'auto': order = ode_order(ode, func) - if solve_for_func and not (sol.lhs == func and not sol.rhs.has(func)) and not \ - (sol.rhs == func and not sol.lhs.has(func)): + if solve_for_func and not ( + sol.lhs == func and not sol.rhs.has(func)) and not ( + sol.rhs == func and not sol.lhs.has(func)): try: solved = solve(sol, func) if not solved: @@ -1168,7 +1268,7 @@ pass else: if len(solved) == 1: - result = checkodesol(ode, Eq(func, solved[0]), \ + result = checkodesol(ode, Eq(func, solved[0]), order=order, solve_for_func=False) else: result = checkodesol(ode, [Eq(func, t) for t in solved], @@ -1178,8 +1278,8 @@ while s: if testnum == 0: - # First pass, try substituting a solved solution directly into the ode - # This has the highest chance of succeeding. + # First pass, try substituting a solved solution directly into the + # ODE. This has the highest chance of succeeding. ode_diff = ode.lhs - ode.rhs if sol.lhs == func: @@ -1193,7 +1293,7 @@ if ss: # with the new numer_denom in power.py, if we do a simple # expansion then testnum == 0 verifies all solutions. - s = ss.expand() + s = ss.expand(force=True) else: s = 0 testnum += 1 @@ -1201,38 +1301,40 @@ # Second pass. If we cannot substitute f, try seeing if the nth # derivative is equal, this will only work for odes that are exact, # by definition. - s = simplify(trigsimp(diff(sol.lhs, x, order) - diff(sol.rhs, x, order)) - \ + s = simplify( + trigsimp(diff(sol.lhs, x, order) - diff(sol.rhs, x, order)) - trigsimp(ode.lhs) + trigsimp(ode.rhs)) -# s2 = simplify(diff(sol.lhs, x, order) - diff(sol.rhs, x, order) - \ -# ode.lhs + ode.rhs) + # s2 = simplify( + # diff(sol.lhs, x, order) - diff(sol.rhs, x, order) - \ + # ode.lhs + ode.rhs) testnum += 1 elif testnum == 2: - # Third pass. Try solving for df/dx and substituting that into the ode. - # Thanks to Chris Smith for suggesting this method. Many of the - # comments below are his too. + # Third pass. Try solving for df/dx and substituting that into the + # ODE. Thanks to Chris Smith for suggesting this method. Many of + # the comments below are his too. # The method: # - Take each of 1..n derivatives of the solution. # - Solve each nth derivative for d^(n)f/dx^(n) # (the differential of that order) - # - Back substitute into the ode in decreasing order + # - Back substitute into the ODE in decreasing order # (i.e., n, n-1, ...) # - Check the result for zero equivalence if sol.lhs == func and not sol.rhs.has(func): - diffsols = {0:sol.rhs} + diffsols = {0: sol.rhs} elif sol.rhs == func and not sol.lhs.has(func): - diffsols = {0:sol.lhs} + diffsols = {0: sol.lhs} else: diffsols = {} sol = sol.lhs - sol.rhs for i in range(1, order + 1): # Differentiation is a linear operator, so there should always # be 1 solution. Nonetheless, we test just to make sure. - # We only need to solve once. After that, we will automatically + # We only need to solve once. After that, we automatically # have the solution to the differential in the order we want. if i == 1: ds = sol.diff(x) try: - sdf = solve(ds,func.diff(x, i)) + sdf = solve(ds, func.diff(x, i)) if not sdf: raise NotImplementedError except NotImplementedError: @@ -1248,7 +1350,7 @@ if testnum > 2: continue else: - # Substitute it into ode to check for self consistency. + # Substitute it into ODE to check for self consistency. lhs, rhs = ode.lhs, ode.rhs for i in range(order, -1, -1): if i == 0 and 0 not in diffsols: @@ -1257,7 +1359,7 @@ break lhs = sub_func_doit(lhs, func.diff(x, i), diffsols[i]) rhs = sub_func_doit(rhs, func.diff(x, i), diffsols[i]) - ode_or_bool = Eq(lhs,rhs) + ode_or_bool = Eq(lhs, rhs) ode_or_bool = simplify(ode_or_bool) if isinstance(ode_or_bool, bool): @@ -1266,66 +1368,85 @@ else: lhs = ode_or_bool.lhs rhs = ode_or_bool.rhs - # No sense in overworking simplify--just prove the numerator goes to zero - s = simplify(trigsimp((lhs-rhs).as_numer_denom()[0])) + # No sense in overworking simplify -- just prove that the + # numerator goes to zero + num = trigsimp((lhs - rhs).as_numer_denom()[0]) + # since solutions are obtained using force=True we test + # using the same level of assumptions + ## replace function with dummy so assumptions will work + _func = Dummy('func') + num = num.subs(func, _func) + ## posify the expression + num, reps = posify(num) + s = simplify(num).xreplace(reps).xreplace({_func: func}) testnum += 1 else: break if not s: return (True, s) - elif s is True: # The code above never was able to change s - raise NotImplementedError("Unable to test if " + str(sol) + \ + elif s is True: # The code above never was able to change s + raise NotImplementedError("Unable to test if " + str(sol) + " is a solution to " + str(ode) + ".") else: return (False, s) def ode_sol_simplicity(sol, func, trysolving=True): - """ - Returns an extended integer representing how simple a solution to an - ODE is. + r""" + Returns an extended integer representing how simple a solution to an ODE + is. - The following things are considered, in order from most simple to - least: - - sol is solved for func. - - sol is not solved for func, but can be if passed to solve (e.g., - a solution returned by dsolve(ode, func, simplify=False) - - If sol is not solved for func, then base the result on the length - of sol, as computed by len(str(sol)). - - If sol has any unevaluated Integrals, this will automatically be - considered less simple than any of the above. - - This function returns an integer such that if solution A is simpler - than solution B by above metric, then ode_sol_simplicity(sola, func) - < ode_sol_simplicity(solb, func). - - Currently, the following are the numbers returned, but if the - heuristic is ever improved, this may change. Only the ordering is - guaranteed. - - sol solved for func -2 - sol not solved for func but can be -1 - sol is not solved or solvable for func len(str(sol)) - sol contains an Integral oo + The following things are considered, in order from most simple to least: - oo here means the SymPy infinity, which should compare greater than - any integer. + - ``sol`` is solved for ``func``. + - ``sol`` is not solved for ``func``, but can be if passed to solve (e.g., + a solution returned by ``dsolve(ode, func, simplify=False``). + - If ``sol`` is not solved for ``func``, then base the result on the + length of ``sol``, as computed by ``len(str(sol))``. + - If ``sol`` has any unevaluated :py:class:`~sympy.integrals.Integral`\s, + this will automatically be considered less simple than any of the above. + + This function returns an integer such that if solution A is simpler than + solution B by above metric, then ``ode_sol_simplicity(sola, func) < + ode_sol_simplicity(solb, func)``. + + Currently, the following are the numbers returned, but if the heuristic is + ever improved, this may change. Only the ordering is guaranteed. + + +----------------------------------------------+-------------------+ + | Simplicity | Return | + +==============================================+===================+ + | ``sol`` solved for ``func`` | ``-2`` | + +----------------------------------------------+-------------------+ + | ``sol`` not solved for ``func`` but can be | ``-1`` | + +----------------------------------------------+-------------------+ + | ``sol`` is not solved nor solvable for | ``len(str(sol))`` | + | ``func`` | | + +----------------------------------------------+-------------------+ + | ``sol`` contains an | ``oo`` | + | :py:class:`~sympy.integrals.Integral` | | + +----------------------------------------------+-------------------+ - If you already know solve() cannot solve sol, you can use - trysolving=False to skip that step, which is the only potentially - slow step. For example, dsolve with the simplify=False flag should - do this. + ``oo`` here means the SymPy infinity, which should compare greater than + any integer. - If sol is a list of solutions, if the worst solution in the list - returns oo it returns that, otherwise it returns len(str(sol)), that - is, the length of the string representation of the whole list. + If you already know :py:meth:`~sympy.solvers.solvers.solve` cannot solve + ``sol``, you can use ``trysolving=False`` to skip that step, which is the + only potentially slow step. For example, + :py:meth:`~sympy.solvers.ode.dsolve` with the ``simplify=False`` flag + should do this. + + If ``sol`` is a list of solutions, if the worst solution in the list + returns ``oo`` it returns that, otherwise it returns ``len(str(sol))``, + that is, the length of the string representation of the whole list. Examples ======== - This function is designed to be passed to min as the key argument, - such as min(listofsolutions, key=lambda i: ode_sol_simplicity(i, f(x))). + This function is designed to be passed to ``min`` as the key argument, + such as ``min(listofsolutions, key=lambda i: ode_sol_simplicity(i, + f(x)))``. >>> from sympy import symbols, Function, Eq, tan, cos, sqrt, Integral >>> from sympy.solvers.ode import ode_sol_simplicity @@ -1346,7 +1467,8 @@ f(x)/tan(f(x)/(2*x)) == C1 """ - #TODO: write examples + # TODO: if two solutions are solved for f(x), we still want to be + # able to get the simpler of the two # See the docstring for the coercion rules. We check easier (faster) # things here first, to save time. @@ -1363,12 +1485,12 @@ return oo # Next, try to solve for func. This code will change slightly when RootOf - # is implemented in solve(). Probably a RootOf solution should fall somewhere - # between a normal solution and an unsolvable expression. + # is implemented in solve(). Probably a RootOf solution should fall + # somewhere between a normal solution and an unsolvable expression. # First, see if they are already solved - if sol.lhs == func and not sol.rhs.has(func) or\ - sol.rhs == func and not sol.lhs.has(func): + if sol.lhs == func and not sol.rhs.has(func) or \ + sol.rhs == func and not sol.lhs.has(func): return -2 # We are not so lucky, try solving manually if trysolving: @@ -1390,56 +1512,58 @@ # Additional ideas for simplicity heuristics are welcome, like maybe # checking if a equation has a larger domain, or if constantsimp has # introduced arbitrary constants numbered higher than the order of a - # given ode that sol is a solution of. + # given ODE that sol is a solution of. return len(str(sol)) @vectorize(0) def constantsimp(expr, independentsymbol, endnumber, startnumber=1, - symbolname='C'): - """ + symbolname='C'): + r""" Simplifies an expression with arbitrary constants in it. - This function is written specifically to work with dsolve(), and is - not intended for general use. + This function is written specifically to work with + :py:meth:`~sympy.solvers.ode.dsolve`, and is not intended for general use. - Simplification is done by "absorbing" the arbitrary constants in to - other arbitrary constants, numbers, and symbols that they are not - independent of. + Simplification is done by "absorbing" the arbitrary constants in to other + arbitrary constants, numbers, and symbols that they are not independent + of. The symbols must all have the same name with numbers after it, for - example, C1, C2, C3. The symbolname here would be 'C', the - startnumber would be 1, and the end number would be 3. If the - arbitrary constants are independent of the variable x, then the - independent symbol would be x. There is no need to specify the - dependent function, such as f(x), because it already has the - independent symbol, x, in it. + example, ``C1``, ``C2``, ``C3``. The ``symbolname`` here would be + '``C``', the ``startnumber`` would be 1, and the ``endnumber`` would be 3. + If the arbitrary constants are independent of the variable ``x``, then the + independent symbol would be ``x``. There is no need to specify the + dependent function, such as ``f(x)``, because it already has the + independent symbol, ``x``, in it. Because terms are "absorbed" into arbitrary constants and because - constants are renumbered after simplifying, the arbitrary constants - in expr are not necessarily equal to the ones of the same name in - the returned result. - - If two or more arbitrary constants are added, multiplied, or raised - to the power of each other, they are first absorbed together into a - single arbitrary constant. Then the new constant is combined into - other terms if necessary. - - Absorption is done with limited assistance: terms of Adds are collected - to try join constants and powers with exponents that are Adds are expanded - so (C1*cos(x) + C2*cos(x))*exp(x) will simplify to C1*cos(x)*exp(x) and - exp(C1 + x) will be simplified to C1*exp(x). - - Use constant_renumber() to renumber constants after simplification or else - arbitrary numbers on constants may appear, e.g. C1 + C3*x. - - In rare cases, a single constant can be "simplified" into two - constants. Every differential equation solution should have as many - arbitrary constants as the order of the differential equation. The - result here will be technically correct, but it may, for example, - have C1 and C2 in an expression, when C1 is actually equal to C2. - Use your discretion in such situations, and also take advantage of - the ability to use hints in dsolve(). + constants are renumbered after simplifying, the arbitrary constants in + expr are not necessarily equal to the ones of the same name in the + returned result. + + If two or more arbitrary constants are added, multiplied, or raised to the + power of each other, they are first absorbed together into a single + arbitrary constant. Then the new constant is combined into other terms if + necessary. + + Absorption is done with limited assistance: terms of + :py:class:`~sympy.core.add.Add`\s are collected to try join constants and + powers with exponents that are :py:class:`~sympy.core.add.Add`\s are + expanded so `e^x (C_1 \cos(x) + C_2 \cos(x))` will simplify to `e^x C_1 + \cos(x)` and `e^{C_1 + x}` will be simplified to `C_1 e^x`. + + Use :py:meth:`~sympy.solvers.ode.constant_renumber` to renumber constants + after simplification or else arbitrary numbers on constants may appear, + e.g. `C_1 + C_3 x`. + + In rare cases, a single constant can be "simplified" into two constants. + Every differential equation solution should have as many arbitrary + constants as the order of the differential equation. The result here will + be technically correct, but it may, for example, have `C_1` and `C_2` in + an expression, when `C_1` is actually equal to `C_2`. Use your discretion + in such situations, and also take advantage of the ability to use hints in + :py:meth:`~sympy.solvers.ode.dsolve`. Examples ======== @@ -1461,43 +1585,49 @@ # simplifying up. Otherwise, we can skip that part of the # expression. - constant_iter = numbered_symbols('C', start=startnumber) - constantsymbols = [next(constant_iter) for t in range(startnumber, endnumber + 1)] - constantsymbols_set = set(constantsymbols) - x = independentsymbol + if type(symbolname) is tuple: + x, endnumber, startnumber, constantsymbols = symbolname + else: + constantsymbols = symbols( + symbolname + '%i:%i' % (startnumber, endnumber + 1)) + x = independentsymbol + con_set = set(constantsymbols) + ARGS = None, None, None, ( + x, endnumber, startnumber, constantsymbols) + if isinstance(expr, Equality): # For now, only treat the special case where one side of the equation # is a constant - if expr.lhs in constantsymbols_set: - return Eq(expr.lhs, constantsimp(expr.rhs + expr.lhs, x, endnumber, - startnumber, symbolname) - expr.lhs) + if expr.lhs in con_set: + return Eq(expr.lhs, constantsimp(expr.rhs + expr.lhs, *ARGS) - expr.lhs) # this could break if expr.lhs is absorbed into another constant, # but for now, the only solutions that return Eq's with a constant # on one side are first order. At any rate, it will still be # technically correct. The expression will just have too many # constants in it - elif expr.rhs in constantsymbols_set: - return Eq(constantsimp(expr.lhs + expr.rhs, x, endnumber, - startnumber, symbolname) - expr.rhs, expr.rhs) + elif expr.rhs in con_set: + return Eq(constantsimp(expr.lhs + expr.rhs, *ARGS) - expr.rhs, expr.rhs) else: - return Eq(constantsimp(expr.lhs, x, endnumber, startnumber, - symbolname), constantsimp(expr.rhs, x, endnumber, - startnumber, symbolname)) + return Eq(constantsimp(expr.lhs, *ARGS), constantsimp(expr.rhs, *ARGS)) - if not expr.has(*constantsymbols): + if not hasattr(expr, 'has') or not expr.has(*constantsymbols): return expr else: # ================ pre-processing ================ - # collect terms to get constants together def _take(i): - t = sorted([s for s in i.atoms(Symbol) if s in constantsymbols]) - if not t: - return i - return t[0] + # return the lowest numbered constant symbol that appears in ``i`` + # else return ``i`` + c = i.free_symbols & con_set + if c: + return min(c) + return i if not (expr.has(x) and x in expr.free_symbols): return constantsymbols[0] - new_expr = terms_gcd(expr, clear=False, deep=True) + + # collect terms to get constants together + new_expr = terms_gcd(expr, clear=False, deep=True, expand=False) + if new_expr.is_Mul: # don't let C1*exp(x) + C2*exp(2*x) become exp(x)*(C1 + C2*exp(x)) infac = False @@ -1506,7 +1636,8 @@ if m.func is exp: asfac = True elif m.is_Add: - infac = any(fi.func is exp for t in m.args for fi in Mul.make_args(t)) + infac = any(fi.func is exp for t in m.args + for fi in Mul.make_args(t)) if asfac and infac: new_expr = expr break @@ -1526,19 +1657,18 @@ # in the base of a power, if all its terms have a constant # symbol in them, e.g. sqrt(2)*(C1 + C2*x) -> C1 + C2*x if expr.is_Mul: - d = sift(expr.args, lambda m: m.is_number == True) + d = sift(expr.args, lambda m: m.is_number is True) num = d[True] other = d[False] - con_set = set(constantsymbols) if num: for o in other: b, e = o.as_base_exp() if b.is_Add and \ - all(a.args_cnc(cset=True, warn=False)[0] & \ - con_set for a in b.args): + all(a.args_cnc(cset=True, warn=False)[0] & + con_set for a in b.args): expr = sign(Mul(*num))*Mul._from_args(other) break - if expr.is_Mul: # check again that it's still a Mul + if expr.is_Mul: # check again that it's still a Mul i, d = expr.as_independent(x, strict=True) newi = _take(i) if newi != i: @@ -1554,9 +1684,9 @@ expr = Add(*[k*Add(*v) for k, v in list(terms.items())]) # handle powers like exp(C0 + g(x)) -> C0*exp(g(x)) pows = [p for p in expr.atoms(C.Function, C.Pow) if - (p.is_Pow or p.func is exp) and - p.exp.is_Add and - p.exp.as_independent(x, strict=True)[1]] + (p.is_Pow or p.func is exp) and + p.exp.is_Add and + p.exp.as_independent(x, strict=True)[1]] if pows: reps = [] for p in pows: @@ -1565,7 +1695,7 @@ e = _take(ei) if e != ei or e in constantsymbols: reps.append((p, e*b**ed)) - expr = expr.subs(reps) + expr = expr.xreplace(dict(reps)) # a C1*C2 may have been introduced and the code below won't # handle that so handle it now: once to handle the C1*C2 # and once to handle any C0*f(x) + C0*f(x) @@ -1577,7 +1707,7 @@ newi = _take(i) if newi != i: reps.append((m, _take(i)*d)) - expr = expr.subs(reps) + expr = expr.xreplace(dict(reps)) # ================ end of pre-processing ================ newargs = [] hasconst = False @@ -1593,8 +1723,7 @@ isPowExp = True for i in range(len(newargs)): - isimp = constantsimp(newargs[i], x, endnumber, startnumber, - symbolname) + isimp = constantsimp(newargs[i], *ARGS) if isimp in constantsymbols: reeval = True hasconst = True @@ -1605,7 +1734,7 @@ if hasconst: newargs = [i for i in newargs if i.has(x)] if isPowExp: - newargs = newargs + [newconst] # Order matters in this case + newargs = newargs + [newconst] # Order matters in this case else: newargs = [newconst] + newargs if expr.is_Pow and len(newargs) == 1: @@ -1614,33 +1743,33 @@ if (len(newargs) == 0 or hasconst and len(newargs) == 1): return newconst else: - newfuncargs = [constantsimp(t, x, endnumber, startnumber, - symbolname) for t in expr.args] + newfuncargs = [constantsimp(t, *ARGS) for t in expr.args] return expr.func(*newfuncargs) else: newexpr = expr.func(*newargs) if reeval: - return constantsimp(newexpr, x, endnumber, startnumber, - symbolname) + return constantsimp(newexpr, *ARGS) else: return newexpr + def constant_renumber(expr, symbolname, startnumber, endnumber): - """ - Renumber arbitrary constants in expr to have numbers 1 through N - where N is ``endnumber`` - ``startnumber`` + 1 at most. + r""" + Renumber arbitrary constants in ``expr`` to have numbers 1 through `N` + where `N` is ``endnumber - startnumber + 1`` at most. - This is a simple function that goes through and renumbers any Symbol - with a name in the form symbolname + num where num is in the range - from startnumber to endnumber. + This is a simple function that goes through and renumbers any + :py:class:`~sympy.core.symbol.Symbol` with a name in the form ``symbolname + + num`` where ``num`` is in the range from ``startnumber`` to + ``endnumber``. Symbols are renumbered based on ``.sort_key()``, so they should be numbered roughly in the order that they appear in the final, printed - expression. Note that this ordering is based in part on hashes, so - it can produce different results on different machines. + expression. Note that this ordering is based in part on hashes, so it can + produce different results on different machines. The structure of this function is very similar to that of - constantsimp(). + :py:meth:`~sympy.solvers.ode.constantsimp`. Examples ======== @@ -1667,38 +1796,47 @@ """ if type(expr) in (set, list, tuple): - return type(expr)([constant_renumber(i, symbolname=symbolname, + return type( + expr)([constant_renumber(i, symbolname=symbolname, startnumber=startnumber, endnumber=endnumber) for i in expr]) global newstartnumber newstartnumber = 1 def _constant_renumber(expr, symbolname, startnumber, endnumber): - """ + r""" We need to have an internal recursive function so that newstartnumber maintains its values throughout recursive calls. """ - constantsymbols = [Symbol(symbolname+"%d" % t) for t in range(startnumber, + constantsymbols = [Symbol( + symbolname + "%d" % t) for t in range(startnumber, endnumber + 1)] global newstartnumber if isinstance(expr, Equality): - return Eq(_constant_renumber(expr.lhs, symbolname, startnumber, endnumber), - _constant_renumber(expr.rhs, symbolname, startnumber, endnumber)) - - if type(expr) not in (Mul, Add, Pow) and not expr.is_Function and\ - not expr.has(*constantsymbols): - # Base case, as above. We better hope there aren't constants inside + return Eq( + _constant_renumber( + expr.lhs, symbolname, startnumber, endnumber), + _constant_renumber( + expr.rhs, symbolname, startnumber, endnumber)) + + if type(expr) not in (Mul, Add, Pow) and not expr.is_Function and \ + not expr.has(*constantsymbols): + # Base case, as above. Hope there aren't constants inside # of some other class, because they won't be renumbered. return expr + elif expr.is_Piecewise: + return expr elif expr in constantsymbols: # Renumbering happens here newconst = Symbol(symbolname + str(newstartnumber)) newstartnumber += 1 return newconst else: - if expr.is_Function or expr.is_Pow: - return expr.func(*[_constant_renumber(x, symbolname, startnumber, + from sympy.core.containers import Tuple + if expr.is_Function or expr.is_Pow or isinstance(expr, Tuple): + return expr.func( + *[_constant_renumber(x, symbolname, startnumber, endnumber) for x in expr.args]) else: sortedargs = list(expr.args) @@ -1706,47 +1844,31 @@ # that to make sure that term ordering is not dependent on # the indexed value of C C_1 = [(ci, S.One) for ci in constantsymbols] - sortedargs.sort(key=lambda arg: default_sort_key(arg.subs(C_1))) - return expr.func(*[_constant_renumber(x, symbolname, startnumber, + sortedargs.sort( + key=lambda arg: default_sort_key(arg.subs(C_1))) + return expr.func( + *[_constant_renumber(x, symbolname, startnumber, endnumber) for x in sortedargs]) return _constant_renumber(expr, symbolname, startnumber, endnumber) def _handle_Integral(expr, func, order, hint): - """ + r""" Converts a solution with Integrals in it into an actual solution. - For most hints, this simply runs expr.doit() + For most hints, this simply runs ``expr.doit()``. """ + global y x = func.args[0] f = func.func if hint == "1st_exact": - global exactvars - x0 = exactvars['x0'] - y0 = exactvars['y0'] - y = exactvars['y'] - tmpsol = expr.lhs.doit() - sol = 0 - assert tmpsol.is_Add - for i in tmpsol.args: - if not i.has(x0) and not i.has(y0): - sol += i - assert sol != 0 - sol = Eq(sol.subs(y, f(x)),expr.rhs) # expr.rhs == C1 - del exactvars + sol = (expr.doit()).subs(y, f(x)) + del y elif hint == "1st_exact_Integral": - # FIXME: We still need to back substitute y - # y = exactvars['y'] - # sol = expr.subs(y, f(x)) - # For now, we are going to have to return an expression with f(x) replaced - # with y. Substituting results in the y's in the second integral - # becoming f(x), which prevents the integral from being evaluatable. - # For example, Integral(cos(f(x)), (x, x0, x)). If there were a way to - # do inert substitution, that could maybe be used here instead. - del exactvars - sol = expr + sol = expr.subs(y, f(x)) + del y elif hint == "nth_linear_constant_coeff_homogeneous": sol = expr elif not hint.endswith("_Integral"): @@ -1755,45 +1877,6 @@ sol = expr return sol -def ode_order(expr, func): - """ - Returns the order of a given ODE with respect to func. - - This function is implemented recursively. - - Examples - ======== - - >>> from sympy import Function, ode_order - >>> from sympy.abc import x - >>> f, g = list(map(Function, ['f', 'g'])) - >>> ode_order(f(x).diff(x, 2) + f(x).diff(x)**2 + - ... f(x).diff(x), f(x)) - 2 - >>> ode_order(f(x).diff(x, 2) + g(x).diff(x, 3), f(x)) - 2 - >>> ode_order(f(x).diff(x, 2) + g(x).diff(x, 3), g(x)) - 3 - - """ - a = Wild('a', exclude=[func]) - if expr.match(a): - return 0 - - if isinstance(expr, Derivative): - if expr.args[0] == func: - return len(expr.variables) - else: - order = 0 - for arg in expr.args[0].args: - order = max(order, ode_order(arg, func) + len(expr.variables)) - return order - else: - order = 0 - for arg in expr.args: - order = max(order, ode_order(arg, func)) - return order - # FIXME: replace the general solution in the docstring with # dsolve(equation, hint='1st_exact_Integral'). You will need to be able @@ -1804,11 +1887,14 @@ A 1st order differential equation is called exact if it is the total differential of a function. That is, the differential equation - P(x, y)dx + Q(x, y)dy = 0 is exact if there is some function F(x, y) - such that P(x, y) = dF/dx and Q(x, y) = dF/dy (d here refers to the - partial derivative). It can be shown that a necessary and - sufficient condition for a first order ODE to be exact is that - dP/dy = dQ/dx. Then, the solution will be as given below:: + + .. math:: P(x, y) \,\partial{}x + Q(x, y) \,\partial{}y = 0 + + is exact if there is some function `F(x, y)` such that `P(x, y) = + \partial{}F/\partial{}x` and `Q(x, y) = \partial{}F/\partial{}y`. It can + be shown that a necessary and sufficient condition for a first order ODE + to be exact is that `\partial{}P/\partial{}y = \partial{}Q/\partial{}x`. + Then, the solution will be as given below:: >>> from sympy import Function, Eq, Integral, symbols, pprint >>> x, y, t, x0, y0, C1= symbols('x,y,t,x0,y0,C1') @@ -1823,12 +1909,12 @@ / / x0 y0 - Where the first partials of P and Q exist and are continuous in a + Where the first partials of `P` and `Q` exist and are continuous in a simply connected region. - A note: SymPy currently has no way to represent inert substitution on - an expression, so the hint '1st_exact_Integral' will return an integral - with dy. This is supposed to represent the function that you are + A note: SymPy currently has no way to represent inert substitution on an + expression, so the hint ``1st_exact_Integral`` will return an integral + with `dy`. This is supposed to represent the function that you are solving for. Examples @@ -1853,30 +1939,31 @@ """ x = func.args[0] f = func.func - r = match # d+e*diff(f(x),x) + r = match # d+e*diff(f(x),x) + e = r[r['e']] + d = r[r['d']] + global y # This is the only way to pass dummy y to _handle_Integral + y = r['y'] C1 = Symbol('C1') - x0 = Dummy('x0') - y0 = Dummy('y0') - global exactvars # This is the only way to pass these dummy variables to - # _handle_Integral - exactvars = {'y0':y0, 'x0':x0, 'y':r['y']} - # If we ever get a Constant class, x0 and y0 should be constants, I think - sol = C.Integral(r[r['e']].subs(x,x0),(r['y'],y0,f(x)))+C.Integral(r[r['d']],(x,x0,x)) + # Refer Joel Moses, "Symbolic Integration - The Stormy Decade", + # Communications of the ACM, Volume 14, Number 8, August 1971, pp. 558 + # which gives the method to solve an exact differential equation. + sol = C.Integral(d, x) + C.Integral((e - (C.Integral(d, x).diff(y))), y) return Eq(sol, C1) def ode_1st_homogeneous_coeff_best(eq, func, order, match): r""" Returns the best solution to an ODE from the two hints - '1st_homogeneous_coeff_subs_dep_div_indep' and - '1st_homogeneous_coeff_subs_indep_div_dep'. + ``1st_homogeneous_coeff_subs_dep_div_indep`` and + ``1st_homogeneous_coeff_subs_indep_div_dep``. - This is as determined by ode_sol_simplicity(). + This is as determined by :py:meth:`~ode_sol_simplicity`. - See the ode_1st_homogeneous_coeff_subs_indep_div_dep() and - ode_1st_homogeneous_coeff_subs_dep_div_indep() docstrings for more - information on these hints. Note that there is no - '1st_homogeneous_coeff_best_Integral' hint. + See the :py:meth:`~ode_1st_homogeneous_coeff_subs_indep_div_dep` and + :py:meth:`~ode_1st_homogeneous_coeff_subs_dep_div_indep` docstrings for + more information on these hints. Note that there is no + ``1st_homogeneous_coeff_best_Integral`` hint. Examples ======== @@ -1886,13 +1973,13 @@ >>> f = Function('f') >>> pprint(dsolve(2*x*f(x) + (x**2 + f(x)**2)*f(x).diff(x), f(x), ... hint='1st_homogeneous_coeff_best', simplify=False)) - / 2 \ - | 3*x | - log|----- + 1| - | 2 | - /f(x)\ \f (x) / - log|----| + -------------- = 0 - \ C1 / 3 + / 2 \ + | 3*x | + log|----- + 1| + | 2 | + \f (x) / + log(f(x)) = log(C1) - -------------- + 3 References ========== @@ -1913,32 +2000,37 @@ func, order, match) simplify = match.get('simplify', True) if simplify: - sol1 = odesimp(sol1, func, order, "1st_homogeneous_coeff_subs_indep_div_dep") - sol2 = odesimp(sol2, func, order, "1st_homogeneous_coeff_subs_dep_div_indep") + sol1 = odesimp( + sol1, func, order, "1st_homogeneous_coeff_subs_indep_div_dep") + sol2 = odesimp( + sol2, func, order, "1st_homogeneous_coeff_subs_dep_div_indep") return min([sol1, sol2], key=lambda x: ode_sol_simplicity(x, func, trysolving=not simplify)) + def ode_1st_homogeneous_coeff_subs_dep_div_indep(eq, func, order, match): r""" Solves a 1st order differential equation with homogeneous coefficients - using the substitution - u1 = /. + using the substitution `u_1 = \frac{\text{}}{\text{}}`. + + This is a differential equation - This is a differential equation P(x, y) + Q(x, y)dy/dx = 0, that P - and Q are homogeneous of the same order. A function F(x, y) is - homogeneous of order n if F(xt, yt) = t**n*F(x, y). Equivalently, - F(x, y) can be rewritten as G(y/x) or H(x/y). See also the - docstring of homogeneous_order(). - - If the coefficients P and Q in the differential equation above are - homogeneous functions of the same order, then it can be shown that - the substitution y = u1*x (u1 = y/x) will turn the differential - equation into an equation separable in the variables x and u. If - h(u1) is the function that results from making the substitution - u1 = f(x)/x on P(x, f(x)) and g(u2) is the function that results - from the substitution on Q(x, f(x)) in the differential equation - P(x, f(x)) + Q(x, f(x))*diff(f(x), x) = 0, then the general solution - is:: + .. math:: P(x, y) + Q(x, y) dy/dx = 0 + + such that `P` and `Q` are homogeneous and of the same order. A function + `F(x, y)` is homogeneous of order `n` if `F(x t, y t) = t^n F(x, y)`. + Equivalently, `F(x, y)` can be rewritten as `G(y/x)` or `H(x/y)`. See + also the docstring of :py:meth:`~sympy.solvers.ode.homogeneous_order`. + + If the coefficients `P` and `Q` in the differential equation above are + homogeneous functions of the same order, then it can be shown that the + substitution `y = u_1 x` (i.e. `u_1 = y/x`) will turn the differential + equation into an equation separable in the variables `x` and `u`. If + `h(u_1)` is the function that results from making the substitution `u_1 = + f(x)/x` on `P(x, f(x))` and `g(u_2)` is the function that results from the + substitution on `Q(x, f(x))` in the differential equation `P(x, f(x)) + + Q(x, f(x)) f'(x) = 0`, then the general solution is:: >>> from sympy import Function, dsolve, pprint >>> from sympy.abc import x @@ -1950,21 +2042,22 @@ \ x / \ x / dx >>> pprint(dsolve(genform, f(x), ... hint='1st_homogeneous_coeff_subs_dep_div_indep_Integral')) - f(x) - ---- - x + f(x) + ---- + x + / + | + | -h(u1) + log(x) = C1 + | ---------------- d(u1) + | u1*h(u1) + g(u1) + | / - | - | -h(u1) - log(C1*x) - | ---------------- d(u1) = 0 - | u1*h(u1) + g(u1) - | - / - Where u1*h(u1) + g(u1) != 0 and x != 0. + Where `u_1 h(u_1) + g(u_1) \ne 0` and `x \ne 0`. - See also the docstrings of ode_1st_homogeneous_coeff_best() and - ode_1st_homogeneous_coeff_subs_indep_div_dep(). + See also the docstrings of + :py:meth:`~ode_1st_homogeneous_coeff_best` and + :py:meth:`~ode_1st_homogeneous_coeff_subs_indep_div_dep`. Examples ======== @@ -1974,13 +2067,13 @@ >>> f = Function('f') >>> pprint(dsolve(2*x*f(x) + (x**2 + f(x)**2)*f(x).diff(x), f(x), ... hint='1st_homogeneous_coeff_subs_dep_div_indep', simplify=False)) - / 2 \ - | f (x)| - /f(x)\ log|3 + -----| - log|----| | 2 | - /x \ \ x / \ x / - log|--| + --------- + -------------- = 0 - \C1/ 3 3 + / 3 \ + |3*f(x) f (x)| + log|------ + -----| + | x 3 | + \ x / + log(x) = log(C1) - ------------------- + 3 References ========== @@ -1994,35 +2087,43 @@ """ x = func.args[0] f = func.func - u1 = Dummy('u1') # u1 == f(x)/x - r = match # d+e*diff(f(x),x) + u = Dummy('u') + u1 = Dummy('u1') # u1 == f(x)/x + r = match # d+e*diff(f(x),x) C1 = Symbol('C1') - int = C.Integral((-r[r['e']]/(r[r['d']]+u1*r[r['e']])).subs({x:1, r['y']:u1}), + xarg = match.get('xarg', 0) + yarg = match.get('yarg', 0) + int = C.Integral( + (-r[r['e']]/(r[r['d']] + u1*r[r['e']])).subs({x: 1, r['y']: u1}), (u1, None, f(x)/x)) sol = logcombine(Eq(log(x), int + log(C1)), force=True) + sol = sol.subs(f(x), u).subs(((u, u - yarg), (x, x - xarg), (u, f(x)))) return sol + def ode_1st_homogeneous_coeff_subs_indep_div_dep(eq, func, order, match): r""" Solves a 1st order differential equation with homogeneous coefficients - using the substitution - u2 = /. + using the substitution `u_2 = \frac{\text{}}{\text{}}`. + + This is a differential equation - This is a differential equation P(x, y) + Q(x, y)dy/dx = 0, that P - and Q are homogeneous of the same order. A function F(x, y) is - homogeneous of order n if F(xt, yt) = t**n*F(x, y). Equivalently, - F(x, y) can be rewritten as G(y/x) or H(x/y). See also the - docstring of homogeneous_order(). - - If the coefficients P and Q in the differential equation above are - homogeneous functions of the same order, then it can be shown that - the substitution x = u2*y (u2 = x/y) will turn the differential - equation into an equation separable in the variables y and u2. If - h(u2) is the function that results from making the substitution - u2 = x/f(x) on P(x, f(x)) and g(u2) is the function that results - from the substitution on Q(x, f(x)) in the differential equation - P(x, f(x)) + Q(x, f(x))*diff(f(x), x) = 0, then the general solution - is: + .. math:: P(x, y) + Q(x, y) dy/dx = 0 + + such that `P` and `Q` are homogeneous and of the same order. A function + `F(x, y)` is homogeneous of order `n` if `F(x t, y t) = t^n F(x, y)`. + Equivalently, `F(x, y)` can be rewritten as `G(y/x)` or `H(x/y)`. See + also the docstring of :py:meth:`~sympy.solvers.ode.homogeneous_order`. + + If the coefficients `P` and `Q` in the differential equation above are + homogeneous functions of the same order, then it can be shown that the + substitution `x = u_2 y` (i.e. `u_2 = x/y`) will turn the differential + equation into an equation separable in the variables `y` and `u_2`. If + `h(u_2)` is the function that results from making the substitution `u_2 = + x/f(x)` on `P(x, f(x))` and `g(u_2)` is the function that results from the + substitution on `Q(x, f(x))` in the differential equation `P(x, f(x)) + + Q(x, f(x)) f'(x) = 0`, then the general solution is: >>> from sympy import Function, dsolve, pprint >>> from sympy.abc import x @@ -2039,33 +2140,36 @@ f(x) / | - | g(u2) - | ----------------- d(u2) - | -u2*g(u2) - h(u2) + | -g(u2) + | ---------------- d(u2) + | u2*g(u2) + h(u2) | / f(x) = C1*e - Where u2*g(u2) + h(u2) != 0 and f(x) != 0. + Where `u_2 g(u_2) + h(u_2) \ne 0` and `f(x) \ne 0`. - See also the docstrings of ode_1st_homogeneous_coeff_best() and - ode_1st_homogeneous_coeff_subs_dep_div_indep(). + See also the docstrings of + :py:meth:`~sympy.solvers.ode.ode_1st_homogeneous_coeff_best` and + :py:meth:`~ode_1st_homogeneous_coeff_subs_dep_div_indep`. Examples ======== - >>> from sympy import Function, pprint + >>> from sympy import Function, pprint, dsolve >>> from sympy.abc import x >>> f = Function('f') >>> pprint(dsolve(2*x*f(x) + (x**2 + f(x)**2)*f(x).diff(x), f(x), - ... hint='1st_homogeneous_coeff_subs_indep_div_dep')) - ___________ - / 2 - / 3*x - / ----- + 1 *f(x) = C1 - 3 / 2 - \/ f (x) + ... hint='1st_homogeneous_coeff_subs_indep_div_dep', + ... simplify=False)) + / 2 \ + | 3*x | + log|----- + 1| + | 2 | + \f (x) / + log(f(x)) = log(C1) - -------------- + 3 References ========== @@ -2079,37 +2183,45 @@ """ x = func.args[0] f = func.func - u2 = Dummy('u2') # u2 == x/f(x) - r = match # d+e*diff(f(x),x) + u = Dummy('u') + u2 = Dummy('u2') # u2 == x/f(x) + r = match # d+e*diff(f(x),x) C1 = Symbol('C1') - int = C.Integral(simplify((-r[r['d']]/(r[r['e']]+u2*r[r['d']])).subs({x:u2, r['y']:1})), + xarg = match.get('xarg', 0) # If xarg present take xarg, else zero + yarg = match.get('yarg', 0) # If yarg present take yarg, else zero + int = C.Integral( + simplify( + (-r[r['d']]/(r[r['e']] + u2*r[r['d']])).subs({x: u2, r['y']: 1})), (u2, None, x/f(x))) sol = logcombine(Eq(log(f(x)), int + log(C1)), force=True) + sol = sol.subs(f(x), u).subs(((u, u - yarg), (x, x - xarg), (u, f(x)))) return sol # XXX: Should this function maybe go somewhere else? + + def homogeneous_order(eq, *symbols): - """ - Returns the order n if g is homogeneous and None if it is not + r""" + Returns the order `n` if `g` is homogeneous and ``None`` if it is not homogeneous. - Determines if a function is homogeneous and if so of what order. - A function f(x,y,...) is homogeneous of order n if - f(t*x,t*y,t*...) == t**n*f(x,y,...). - - If the function is of two variables, F(x, y), then f being - homogeneous of any order is equivalent to being able to rewrite - F(x, y) as G(x/y) or H(y/x). This fact is used to solve 1st order - ordinary differential equations whose coefficients are homogeneous - of the same order (see the docstrings of - ode.ode_1st_homogeneous_coeff_subs_indep_div_dep() and - ode.ode_1st_homogeneous_coeff_subs_indep_div_dep() - - Symbols can be functions, but every argument of the function must be - a symbol, and the arguments of the function that appear in the - expression must match those given in the list of symbols. If a - declared function appears with different arguments than given in the - list of symbols, None is returned. + Determines if a function is homogeneous and if so of what order. A + function `f(x, y, \cdots)` is homogeneous of order `n` if `f(t x, t y, + \cdots) = t^n f(x, y, \cdots)`. + + If the function is of two variables, `F(x, y)`, then `f` being homogeneous + of any order is equivalent to being able to rewrite `F(x, y)` as `G(x/y)` + or `H(y/x)`. This fact is used to solve 1st order ordinary differential + equations whose coefficients are homogeneous of the same order (see the + docstrings of + :py:meth:`~solvers.ode.ode_1st_homogeneous_coeff_subs_dep_div_indep` and + :py:meth:`~solvers.ode.ode_1st_homogeneous_coeff_subs_indep_div_dep`). + + Symbols can be functions, but every argument of the function must be a + symbol, and the arguments of the function that appear in the expression + must match those given in the list of symbols. If a declared function + appears with different arguments than given in the list of symbols, + ``None`` is returned. Examples ======== @@ -2144,7 +2256,7 @@ if (eq.is_Number or eq.is_NumberSymbol or eq.is_number - ): + ): return S.Zero # Replace all functions with dummy variables @@ -2164,24 +2276,33 @@ if not eq.free_symbols & symset: return None + # assuming order of a nested function can only be equal to zero + if isinstance(eq, Function): + return None if homogeneous_order( + eq.args[0], *tuple(symset)) != 0 else S.Zero + # make the replacement of x with x*t and see if t can be factored out - t = Dummy('t', positive=True) # It is sufficient that t > 0 + t = Dummy('t', positive=True) # It is sufficient that t > 0 eqs = separatevars(eq.subs([(i, t*i) for i in symset]), [t], dict=True)[t] if eqs is S.One: - return S.Zero # there was no term with only t + return S.Zero # there was no term with only t i, d = eqs.as_independent(t, as_Add=False) b, e = d.as_base_exp() if b == t: return e + def ode_1st_linear(eq, func, order, match): r""" Solves 1st order linear differential equations. - These are differential equations of the form dy/dx _ P(x)*y = Q(x). - These kinds of differential equations can be solved in a general - way. The integrating factor exp(Integral(P(x), x)) will turn the - equation into a separable equation. The general solution is:: + These are differential equations of the form + + .. math:: dy/dx + P(x) y = Q(x)\text{.} + + These kinds of differential equations can be solved in a general way. The + integrating factor `e^{\int P(x) \,dx}` will turn the equation into a + separable equation. The general solution is:: >>> from sympy import Function, dsolve, Eq, pprint, diff, sin >>> from sympy.abc import x @@ -2224,20 +2345,25 @@ """ x = func.args[0] f = func.func - r = match # a*diff(f(x),x) + b*f(x) + c + r = match # a*diff(f(x),x) + b*f(x) + c C1 = Symbol('C1') t = exp(C.Integral(r[r['b']]/r[r['a']], x)) tt = C.Integral(t*(-r[r['c']]/r[r['a']]), x) - return Eq(f(x),(tt + C1)/t) + f = match.get('u', f(x)) # take almost-linear u if present, else f(x) + return Eq(f, (tt + C1)/t) + def ode_Bernoulli(eq, func, order, match): r""" Solves Bernoulli differential equations. - These are equations of the form dy/dx + P(x)*y = Q(x)*y**n, n != 1. - The substitution w = 1/y**(1-n) will transform an equation of this - form into one that is linear (see the docstring of - ode_1st_linear()). The general solution is:: + These are equations of the form + + .. math:: dy/dx + P(x) y = Q(x) y^n\text{, }n \ne 1`\text{.} + + The substitution `w = 1/y^{1-n}` will transform an equation of this form + into one that is linear (see the docstring of + :py:meth:`~sympy.solvers.ode.ode_1st_linear`). The general solution is:: >>> from sympy import Function, dsolve, Eq, pprint >>> from sympy.abc import x, n @@ -2263,8 +2389,8 @@ \\ / / / - Note that when n = 1, then the equation is separable (see the - docstring of ode_separable()). + Note that the equation is separable when `n = 1` (see the docstring of + :py:meth:`~sympy.solvers.ode.ode_separable`). >>> pprint(dsolve(Eq(f(x).diff(x) + P(x)*f(x), Q(x)*f(x)), f(x), ... hint='separable_Integral')) @@ -2305,20 +2431,25 @@ """ x = func.args[0] f = func.func - r = match # a*diff(f(x),x) + b*f(x) + c*f(x)**n, n != 1 + r = match # a*diff(f(x),x) + b*f(x) + c*f(x)**n, n != 1 C1 = Symbol('C1') - t = exp((1-r[r['n']])*C.Integral(r[r['b']]/r[r['a']],x)) - tt = (r[r['n']]-1)*C.Integral(t*r[r['c']]/r[r['a']],x) - return Eq(f(x),((tt + C1)/t)**(1/(1-r[r['n']]))) + t = exp((1 - r[r['n']])*C.Integral(r[r['b']]/r[r['a']], x)) + tt = (r[r['n']] - 1)*C.Integral(t*r[r['c']]/r[r['a']], x) + return Eq(f(x), ((tt + C1)/t)**(1/(1 - r[r['n']]))) + def ode_Riccati_special_minus2(eq, func, order, match): r""" - The general Riccati equation has the form dy/dx = f(x)*y**2 + g(x)*y + h(x). - While it does not have a general solution [1], the "special" form, - dy/dx = a*y**2 - b*x**c, does have solutions in many cases [2]. This routine - returns a solution for a*dy/dx = b*y**2 + c*y/x + d/x**2 that is obtained by - using a suitable change of variables to reduce it to the special form and is - valid when neither a nor b are zero and either c or d is zero. + The general Riccati equation has the form + + .. math:: dy/dx = f(x) y^2 + g(x) y + h(x)\text{.} + + While it does not have a general solution [1], the "special" form, `dy/dx + = a y^2 - b x^c`, does have solutions in many cases [2]. This routine + returns a solution for `a(dy/dx) = b y^2 + c y/x + d/x^2` that is obtained + by using a suitable change of variables to reduce it to the special form + and is valid when neither `a` nor `b` are zero and either `c` or `d` is + zero. >>> from sympy.abc import x, y, a, b, c, d >>> from sympy.solvers.ode import dsolve, checkodesol @@ -2327,13 +2458,13 @@ >>> y = f(x) >>> genform = a*y.diff(x) - (b*y**2 + c*y/x + d/x**2) >>> sol = dsolve(genform, y) - >>> pprint(sol) - / / __________________ \\ + >>> pprint(sol, wrap_line=False) + / / __________________ \\ | __________________ | / 2 || | / 2 | \/ 4*b*d - (a + c) *log(x)|| -|a + c - \/ 4*b*d - (a + c) *tan|C1 + ----------------------------|| \ \ 2*a // - f(x) = ----------------------------------------------------------------------- + f(x) = ------------------------------------------------------------------------ 2*b*x >>> checkodesol(genform, sol, order=1)[0] @@ -2349,18 +2480,24 @@ x = func.args[0] f = func.func - r = match # a2*diff(f(x),x) + b2*f(x) + c2*f(x)/x + d2/x**2 + r = match # a2*diff(f(x),x) + b2*f(x) + c2*f(x)/x + d2/x**2 a2, b2, c2, d2 = [r[r[s]] for s in 'a2 b2 c2 d2'.split()] C1 = Symbol('C1') mu = sqrt(4*d2*b2 - (a2 - c2)**2) - return Eq(f(x), (a2 - c2 - mu*tan(mu/(2*a2)*log(x)+C1))/(2*b2*x)) + return Eq(f(x), (a2 - c2 - mu*tan(mu/(2*a2)*log(x) + C1))/(2*b2*x)) + def ode_Liouville(eq, func, order, match): r""" Solves 2nd order Liouville differential equations. The general form of a Liouville ODE is - d^2y/dx^2 + g(y)*(dy/dx)**2 + h(x)*dy/dx. The general solution is: + + .. math:: \frac{d^2 y}{dx^2} + g(y) \left(\! + \frac{dy}{dx}\!\right)^2 + h(x) + \frac{dy}{dx}\text{.} + + The general solution is: >>> from sympy import Function, dsolve, Eq, pprint, diff >>> from sympy.abc import x @@ -2368,11 +2505,11 @@ >>> genform = Eq(diff(f(x),x,x) + g(f(x))*diff(f(x),x)**2 + ... h(x)*diff(f(x),x), 0) >>> pprint(genform) - 2 2 - d d d - g(f(x))*--(f(x)) + h(x)*--(f(x)) + ---(f(x)) = 0 - dx dx 2 - dx + 2 2 + /d \ d d + g(f(x))*|--(f(x))| + h(x)*--(f(x)) + ---(f(x)) = 0 + \dx / dx 2 + dx >>> pprint(dsolve(genform, f(x), hint='Liouville_Integral')) f(x) / / @@ -2400,20 +2537,21 @@ References ========== - - Goldstein and Braun, "Advanced Methods for the Solution of - Differential Equations", pp. 98 + - Goldstein and Braun, "Advanced Methods for the Solution of Differential + Equations", pp. 98 - http://www.maplesoft.com/support/help/Maple/view.aspx?path=odeadvisor/Liouville # indirect doctest """ - # Liouville ODE f(x).diff(x, 2) + g(f(x))*(f(x).diff(x, 2))**2 + h(x)*f(x).diff(x) + # Liouville ODE: + # f(x).diff(x, 2) + g(f(x))*(f(x).diff(x, 2))**2 + h(x)*f(x).diff(x) # See Goldstein and Braun, "Advanced Methods for the Solution of # Differential Equations", pg. 98, as well as # http://www.maplesoft.com/support/help/view.aspx?path=odeadvisor/Liouville x = func.args[0] f = func.func - r = match # f(x).diff(x, 2) + g*f(x).diff(x)**2 + h*f(x).diff(x) + r = match # f(x).diff(x, 2) + g*f(x).diff(x)**2 + h*f(x).diff(x) y = r['y'] C1 = Symbol('C1') C2 = Symbol('C2') @@ -2423,16 +2561,16 @@ def _nth_linear_match(eq, func, order): - """ + r""" Matches a differential equation to the linear form: - a_n(x)y^(n) + ... + a_1(x)y' + a_0(x)y + B(x) = 0 + .. math:: a_n(x) y^{(n)} + \cdots + a_1(x)y' + a_0(x) y + B(x) = 0 Returns a dict of order:coeff terms, where order is the order of the - derivative on each term, and coeff is the coefficient of that - derivative. The key -1 holds the function B(x). Returns None if - the ode is not linear. This function assumes that func has already - been checked to be good. + derivative on each term, and coeff is the coefficient of that derivative. + The key ``-1`` holds the function `B(x)`. Returns ``None`` if the ODE is + not linear. This function assumes that ``func`` has already been checked + to be good. Examples ======== @@ -2453,42 +2591,463 @@ """ x = func.args[0] one_x = set([x]) - terms = dict([(i, S.Zero) for i in range(-1, order+1)]) + terms = dict([(i, S.Zero) for i in range(-1, order + 1)]) for i in Add.make_args(eq): if not i.has(func): terms[-1] += i else: c, f = i.as_independent(func) - if not ((isinstance(f, Derivative) and set(f.variables) == one_x) or\ - f == func): + if not ((isinstance(f, Derivative) and set(f.variables) == one_x) \ + or f == func): return None else: terms[len(f.args[1:])] += c return terms -def ode_nth_linear_constant_coeff_homogeneous(eq, func, order, match, returns='sol'): + +def ode_nth_linear_euler_eq_homogeneous(eq, func, order, match, returns='sol'): r""" - Solves an nth order linear homogeneous differential equation with + Solves an `n`\th order linear homogeneous variable-coefficient + Cauchy-Euler equidimensional ordinary differential equation. + + This is an equation with form `0 = a_0 f(x) + a_1 x f'(x) + a_2 x^2 f''(x) + \cdots`. + + These equations can be solved in a general manner, by substituting + solutions of the form `f(x) = x^r`, and deriving a characteristic equation + for `r`. When there are repeated roots, we include extra terms of the + form `C_{r k} \ln^k(x) x^r`, where `C_{r k}` is an arbitrary integration + constant, `r` is a root of the characteristic equation, and `k` ranges + over the multiplicity of `r`. In the cases where the roots are complex, + solutions of the form `C_1 x^a \sin(b \log(x)) + C_2 x^a \cos(b \log(x))` + are returned, based on expansions with Eulers formula. The general + solution is the sum of the terms found. If SymPy cannot find exact roots + to the characteristic equation, a + :py:class:`~sympy.polys.rootoftools.RootOf` instance will be returned + instead. + + >>> from sympy import Function, dsolve, Eq + >>> from sympy.abc import x + >>> f = Function('f') + >>> dsolve(4*x**2*f(x).diff(x, 2) + f(x), f(x), + ... hint='nth_linear_euler_eq_homogeneous') + ... # doctest: +NORMALIZE_WHITESPACE + f(x) == sqrt(x)*(C1 + C2*log(x)) + + Note that because this method does not involve integration, there is no + ``nth_linear_euler_eq_homogeneous_Integral`` hint. + + The following is for internal use: + + - ``returns = 'sol'`` returns the solution to the ODE. + - ``returns = 'list'`` returns a list of linearly independent solutions, + corresponding to the fundamental solution set, for use with non + homogeneous solution methods like variation of parameters and + undetermined coefficients. Note that, though the solutions should be + linearly independent, this function does not explicitly check that. You + can do ``assert simplify(wronskian(sollist)) != 0`` to check for linear + independence. Also, ``assert len(sollist) == order`` will need to pass. + - ``returns = 'both'``, return a dictionary ``{'sol': , + 'list': }``. + + Examples + ======== + + >>> from sympy import Function, dsolve, pprint + >>> from sympy.abc import x + >>> f = Function('f') + >>> eq = f(x).diff(x, 2)*x**2 - 4*f(x).diff(x)*x + 6*f(x) + >>> pprint(dsolve(eq, f(x), + ... hint='nth_linear_euler_eq_homogeneous')) + 2 + f(x) = x *(C1 + C2*x) + + References + ========== + + - http://en.wikipedia.org/wiki/Cauchy%E2%80%93Euler_equation + - C. Bender & S. Orszag, "Advanced Mathematical Methods for Scientists and + Engineers", Springer 1999, pp. 12 + + # indirect doctest + + """ + global collectterms + collectterms = [] + + x = func.args[0] + f = func.func + r = match + + # A generator of constants + constants = numbered_symbols(prefix='C', cls=Symbol, start=1) + + # First, set up characteristic equation. + chareq, symbol = S.Zero, Dummy('x') + + for i in list(r.keys()): + if not isinstance(i, str) and i >= 0: + chareq += (r[i]*diff(x**symbol, x, i)*x**-symbol).expand() + + chareq = Poly(chareq, symbol) + chareqroots = [RootOf(chareq, k) for k in range(chareq.degree())] + + # Create a dict root: multiplicity or charroots + charroots = defaultdict(int) + for root in chareqroots: + charroots[root] += 1 + gsol = S(0) + # We need keep track of terms so we can run collect() at the end. + # This is necessary for constantsimp to work properly. + ln = log + for root, multiplicity in list(charroots.items()): + for i in range(multiplicity): + if isinstance(root, RootOf): + gsol += (x**root)*next(constants) + assert multiplicity == 1 + collectterms = [(0, root, 0)] + collectterms + elif root.is_real: + gsol += ln(x)**i*(x**root)*next(constants) + collectterms = [(i, root, 0)] + collectterms + else: + reroot = re(root) + imroot = im(root) + gsol += ln(x)**i*(x**reroot)*( + next(constants)*sin(abs(imroot)*ln(x)) + + next(constants)*cos(imroot*ln(x))) + # Preserve ordering (multiplicity, real part, imaginary part) + # It will be assumed implicitly when constructing + # fundamental solution sets. + collectterms = [(i, reroot, imroot)] + collectterms + if returns == 'sol': + return Eq(f(x), gsol) + elif returns in ('list' 'both'): + # HOW TO TEST THIS CODE? (dsolve does not pass 'returns' through) + # Create a list of (hopefully) linearly independent solutions + gensols = [] + # Keep track of when to use sin or cos for nonzero imroot + for i, reroot, imroot in collectterms: + if imroot == 0: + gensols.append(ln(x)**i*x**reroot) + else: + sin_form = ln(x)**i*x**reroot*sin(abs(imroot)*ln(x)) + if sin_form in gensols: + cos_form = ln(x)**i*x**reroot*cos(imroot*ln(x)) + gensols.append(cos_form) + else: + gensols.append(sin_form) + if returns == 'list': + return gensols + else: + return {'sol': Eq(f(x), gsol), 'list': gensols} + else: + raise ValueError('Unknown value for key "returns".') + +def ode_almost_linear(eq, func, order, match): + r""" + Solves an almost-linear differential equation. + + The general form of an almost linear differential equation is + + .. math:: f(x) g(y) y + k(x) l(y) + m(x) = 0 + \text{where} l'(y) = g(y)\text{.} + + This can be solved by substituting `l(y) = u(y)`. Making the given + substitution reduces it to a linear differential equation of the form `u' + + P(x) u + Q(x) = 0`. + + The general solution is + + >>> from sympy import Function, dsolve, Eq, pprint + >>> from sympy.abc import x, y, n + >>> f, g, k, l = list(map(Function, ['f', 'g', 'k', 'l'])) + >>> genform = Eq(f(x)*(l(y).diff(y)) + k(x)*l(y) + g(x)) + >>> pprint(genform) + d + f(x)*--(l(y)) + g(x) + k(x)*l(y) = 0 + dy + >>> pprint(dsolve(genform, hint = 'almost_linear')) + / // -y*g(x) \\ + | || -------- for k(x) = 0|| + | || f(x) || -y*k(x) + | || || -------- + | || y*k(x) || f(x) + l(y) = |C1 + |< ------ ||*e + | || f(x) || + | ||-g(x)*e || + | ||-------------- otherwise || + | || k(x) || + \ \\ // + + + See Also + ======== + :meth:`sympy.solvers.ode.ode_1st_linear` + + Examples + ======== + + >>> from sympy import Function, Derivative, pprint + >>> from sympy.solvers.ode import dsolve, classify_ode + >>> from sympy.abc import x + >>> f = Function('f') + >>> d = f(x).diff(x) + >>> eq = x*d + x*f(x) + 1 + >>> dsolve(eq, f(x), hint='almost_linear') + f(x) == (C1 - Ei(x))*exp(-x) + >>> pprint(dsolve(eq, f(x), hint='almost_linear')) + -x + f(x) = (C1 - Ei(x))*e + + References + ========== + + - Joel Moses, "Symbolic Integration - The Stormy Decade", Communications + of the ACM, Volume 14, Number 8, August 1971, pp. 558 + """ + + # Since ode_1st_linear has already been implemented, and the + # coefficients have been modified to the required form in + # classify_ode, just passing eq, func, order and match to + # ode_1st_linear will give the required output. + return ode_1st_linear(eq, func, order, match) + +def _linear_coeff_match(expr, func): + r""" + Helper function to match hint ``linear_coefficients``. + + Matches the expression to the form `(a_1 x + b_1 f(x) + c_1)/(a_2 x + b_2 + f(x) + c_2)` where the following conditions hold: + + 1. `a_1`, `b_1`, `c_1`, `a_2`, `b_2`, `c_2` are Rationals; + 2. `c_1` or `c_2` are not equal to zero; + 3. `a_2 b_1 - a_1 b_2` is not equal to zero. + + Return ``xarg``, ``yarg`` where + + 1. ``xarg`` = `(b_2 c_1 - b_1 c_2)/(a_2 b_1 - a_1 b_2)` + 2. ``yarg`` = `(a_1 c_2 - a_2 c_1)/(a_2 b_1 - a_1 b_2)` + + + Examples + ======== + + >>> from sympy import Function + >>> from sympy.abc import x + >>> from sympy.solvers.ode import _linear_coeff_match + >>> from sympy.functions.elementary.trigonometric import sin + >>> f = Function('f') + >>> _linear_coeff_match(( + ... (-25*f(x) - 8*x + 62)/(4*f(x) + 11*x - 11)), f(x)) + (1/9, 22/9) + >>> _linear_coeff_match( + ... sin((-5*f(x) - 8*x + 6)/(4*f(x) + x - 1)), f(x)) + (19/27, 2/27) + >>> _linear_coeff_match(sin(f(x)/x), f(x)) + + """ + f = func.func + x = func.args[0] + def abc(eq): + r''' + Internal function of _linear_coeff_match + that returns Rationals a, b, c + if eq is a*x + b*f(x) + c, else None. + ''' + eq = _mexpand(eq) + c = eq.as_independent(x, f(x), as_Add = True)[0] + if not c.is_Rational: + return + a = eq.coeff(x) + if not a.is_Rational: + return + b = eq.coeff(f(x)) + if not b.is_Rational: + return + if eq == a*x + b*f(x) + c: + return a, b, c + + def match(arg): + r''' + Internal function of _linear_coeff_match that returns Rationals a1, + b1, c1, a2, b2, c2 and a2*b1 - a1*b2 of the expression (a1*x + b1*f(x) + + c1)/(a2*x + b2*f(x) + c2) if one of c1 or c2 and a2*b1 - a1*b2 is + non-zero, else None. + ''' + n, d = arg.together().as_numer_denom() + m = abc(n) + if m is not None: + a1, b1, c1 = m + m = abc(d) + if m is not None: + a2, b2, c2 = m + d = a2*b1 - a1*b2 + if (c1 or c2) and d: + return a1, b1, c1, a2, b2, c2, d + + m = [fi.args[0] for fi in expr.atoms(Function) if fi.func != f and + fi.nargs == 1 and not fi.args[0].is_Function] or set([expr]) + m1 = match(m.pop()) + if m1 and all(match(mi) == m1 for mi in m): + a1, b1, c1, a2, b2, c2, denom = m1 + return (b2*c1 - b1*c2)/denom, (a1*c2 - a2*c1)/denom + +def ode_linear_coefficients(eq, func, order, match): + r""" + Solves a differential equation with linear coefficients. + + The general form of a differential equation with linear coefficients is + + .. math:: y' + F\left(\!\frac{a_1 x + b_1 y + c_1}{a_2 x + b_2 y + + c_2}\!\right) = 0\text{,} + + where `a_1`, `b_1`, `c_1`, `a_2`, `b_2`, `c_2` are constants and `a_1 b_2 + - a_2 b_1 \ne 0`. + + This can be solved by substituting: + + .. math:: x = x' + \frac{b_2 c_1 - b_1 c_2}{a_2 b_1 - a_1 b_2} + + y = y' + \frac{a_1 c_2 - a_2 c_1}{a_2 b_1 - a_1 + b_2}\text{.} + + This substitution reduces the equation to a homogeneous differential + equation. + + See Also + ======== + :meth:`sympy.solvers.ode.ode_1st_homogeneous_coeff_best` + :meth:`sympy.solvers.ode.ode_1st_homogeneous_coeff_subs_indep_div_dep` + :meth:`sympy.solvers.ode.ode_1st_homogeneous_coeff_subs_dep_div_indep` + + Examples + ======== + + >>> from sympy import Function, Derivative, pprint + >>> from sympy.solvers.ode import dsolve, classify_ode + >>> from sympy.abc import x + >>> f = Function('f') + >>> df = f(x).diff(x) + >>> eq = (x + f(x) + 1)*df + (f(x) - 6*x + 1) + >>> dsolve(eq, hint='linear_coefficients') + [f(x) == -x - sqrt(C1 + 7*x**2) - 1, f(x) == -x + sqrt(C1 + 7*x**2) - 1] + >>> pprint(dsolve(eq, hint='linear_coefficients')) + ___________ ___________ + / 2 / 2 + [f(x) = -x - \/ C1 + 7*x - 1, f(x) = -x + \/ C1 + 7*x - 1] + + + References + ========== + + - Joel Moses, "Symbolic Integration - The Stormy Decade", Communications + of the ACM, Volume 14, Number 8, August 1971, pp. 558 + """ + + return ode_1st_homogeneous_coeff_best(eq, func, order, match) + + +def ode_separable_reduced(eq, func, order, match): + r""" + Solves a differential equation that can be reduced to the separable form. + + The general form of this equation is + + .. math:: y' + (y/x) H(x^n y) = 0\text{}. + + This can be solved by substituting `u(y) = x^n y`. The equation then + reduces to the separable form `\frac{u'}{u (\mathrm{power} - H(u))} - + \frac{1}{x} = 0`. + + The general solution is: + + >>> from sympy import Function, dsolve, Eq, pprint + >>> from sympy.abc import x, n + >>> f, g = list(map(Function, ['f', 'g'])) + >>> genform = f(x).diff(x) + (f(x)/x)*g(x**n*f(x)) + >>> pprint(genform) + / n \ + d f(x)*g\x *f(x)/ + --(f(x)) + --------------- + dx x + >>> pprint(dsolve(genform, hint='separable_reduced')) + n + x *f(x) + / + | + | 1 + | ------------ dy = C1 + log(x) + | y*(n - g(y)) + | + / + + See Also + ======== + :meth:`sympy.solvers.ode.ode_separable` + + Examples + ======== + + >>> from sympy import Function, Derivative, pprint + >>> from sympy.solvers.ode import dsolve, classify_ode + >>> from sympy.abc import x + >>> f = Function('f') + >>> d = f(x).diff(x) + >>> eq = (x - x**2*f(x))*d - f(x) + >>> dsolve(eq, hint='separable_reduced') + [f(x) == (-sqrt(C1*x**2 + 1) + 1)/x, f(x) == (sqrt(C1*x**2 + 1) + 1)/x] + >>> pprint(dsolve(eq, hint='separable_reduced')) + ___________ ___________ + / 2 / 2 + - \/ C1*x + 1 + 1 \/ C1*x + 1 + 1 + [f(x) = --------------------, f(x) = ------------------] + x x + + References + ========== + + - Joel Moses, "Symbolic Integration - The Stormy Decade", Communications + of the ACM, Volume 14, Number 8, August 1971, pp. 558 + """ + + # Arguments are passed in a way so that they are coherent with the + # ode_separable function + x = func.args[0] + f = func.func + y = Dummy('y') + u = match['u'].subs(match['t'], y) + ycoeff = 1/(y*(match['power'] - u)) + m1 = {y: 1, x: -1/x, 'coeff': 1} + m2 = {y: ycoeff, x: 1, 'coeff': 1} + r = {'m1': m1, 'm2': m2, 'y': y, 'hint': x**match['power']*f(x)} + return ode_separable(eq, func, order, r) + +def ode_nth_linear_constant_coeff_homogeneous(eq, func, order, match, + returns='sol'): + r""" + Solves an `n`\th order linear homogeneous differential equation with constant coefficients. - This is an equation of the form a_n*f(x)^(n) + a_(n-1)*f(x)^(n-1) + - ... + a1*f'(x) + a0*f(x) = 0 + This is an equation of the form + + .. math:: a_n f^{(n)}(x) + a_{n-1} f^{(n-1)}(x) + \cdots + a_1 f'(x) + + a_0 f(x) = 0\text{.} - These equations can be solved in a general manner, by taking the - roots of the characteristic equation a_n*m**n + a_(n-1)*m**(n-1) + - ... + a1*m + a0 = 0. The solution will then be the sum of - Cn*x**i*exp(r*x) terms, for each where Cn is an arbitrary constant, - r is a root of the characteristic equation and i is is one of each - from 0 to the multiplicity of the root - 1 (for example, a root 3 of - multiplicity 2 would create the terms C1*exp(3*x) + C2*x*exp(3*x)). - The exponential is usually expanded for complex roots using Euler's - equation exp(I*x) = cos(x) + I*sin(x). Complex roots always come in - conjugate pars in polynomials with real coefficients, so the two - roots will be represented (after simplifying the constants) as - exp(a*x)*(C1*cos(b*x) + C2*sin(b*x)). + These equations can be solved in a general manner, by taking the roots of + the characteristic equation `a_n m^n + a_{n-1} m^{n-1} + \cdots + a_1 m + + a_0 = 0`. The solution will then be the sum of `C_n x^i e^{r x}` terms, + for each where `C_n` is an arbitrary constant, `r` is a root of the + characteristic equation and `i` is one of each from 0 to the multiplicity + of the root - 1 (for example, a root 3 of multiplicity 2 would create the + terms `C_1 e^{3 x} + C_2 x e^{3 x}`). The exponential is usually expanded + for complex roots using Euler's equation `e{I x} = \cos(x) + I \sin(x)`. + Complex roots always come in conjugate pairs in polynomials with real + coefficients, so the two roots will be represented (after simplifying the + constants) as `e^{a x} \left(C_1 \cos(b x) + C_2 \sin(b x)\right)`. If SymPy cannot find exact roots to the characteristic equation, a - RootOf instance will be return in its stead. + :py:class:`~sympy.polys.rootoftools.RootOf` instance will be return + instead. >>> from sympy import Function, dsolve, Eq >>> from sympy.abc import x @@ -2502,21 +3061,21 @@ C4*exp(x*RootOf(_x**5 + 10*_x - 2, 3)) + C5*exp(x*RootOf(_x**5 + 10*_x - 2, 4)) - Note that because this method does not involve integration, there is - no 'nth_linear_constant_coeff_homogeneous_Integral' hint. + Note that because this method does not involve integration, there is no + ``nth_linear_constant_coeff_homogeneous_Integral`` hint. The following is for internal use: - - returns = 'sol' returns the solution to the ODE. - - returns = 'list' returns a list of linearly independent - solutions, for use with non homogeneous solution methods like - variation of parameters and undetermined coefficients. Note that, - though the solutions should be linearly independent, this function - does not explicitly check that. You can do "assert - simplify(wronskian(sollist)) != 0" to check for linear independence. - Also, "assert len(sollist) == order" will need to pass. - - returns = 'both', return a dictionary {'sol':solution to ODE, - 'list': list of linearly independent solutions}. + - ``returns = 'sol'`` returns the solution to the ODE. + - ``returns = 'list'`` returns a list of linearly independent solutions, + for use with non homogeneous solution methods like variation of + parameters and undetermined coefficients. Note that, though the + solutions should be linearly independent, this function does not + explicitly check that. You can do ``assert simplify(wronskian(sollist)) + != 0`` to check for linear independence. Also, ``assert len(sollist) == + order`` will need to pass. + - ``returns = 'both'``, return a dictionary ``{'sol': , + 'list': }``. Examples ======== @@ -2533,8 +3092,8 @@ References ========== - - http://en.wikipedia.org/wiki/Linear_differential_equation - section: Nonhomogeneous_equation_with_constant_coefficients + - http://en.wikipedia.org/wiki/Linear_differential_equation section: + Nonhomogeneous_equation_with_constant_coefficients - M. Tenenbaum & H. Pollard, "Ordinary Differential Equations", Dover 1963, pp. 211 @@ -2578,7 +3137,7 @@ else: reroot = re(root) imroot = im(root) - gsol += x**i*exp(reroot*x)*(next(constants)*sin(abs(imroot)*x) \ + gsol += x**i*exp(reroot*x)*(next(constants)*sin(abs(imroot)*x) + next(constants)*cos(imroot*x)) # This ordering is important collectterms = [(i, reroot, imroot)] + collectterms @@ -2599,39 +3158,43 @@ if returns == 'list': return gensols else: - return {'sol':Eq(f(x), gsol), 'list':gensols} + return {'sol': Eq(f(x), gsol), 'list': gensols} else: raise ValueError('Unknown value for key "returns".') + def ode_nth_linear_constant_coeff_undetermined_coefficients(eq, func, order, match): r""" - Solves an nth order linear differential equation with constant + Solves an `n`\th order linear differential equation with constant coefficients using the method of undetermined coefficients. - This method works on differential equations of the form a_n*f(x)^(n) - + a_(n-1)*f(x)^(n-1) + ... + a1*f'(x) + a0*f(x) = P(x), where P(x) - is a function that has a finite number of linearly independent - derivatives. - - Functions that fit this requirement are finite sums functions of the - form a*x**i*exp(b*x)*sin(c*x + d) or a*x**i*exp(b*x)*cos(c*x + d), - where i is a non-negative integer and a, b, c, and d are constants. - For example any polynomial in x, functions like x**2*exp(2*x), - x*sin(x), and exp(x)*cos(x) can all be used. Products of sin's and - cos's have a finite number of derivatives, because they can be - expanded into sin(a*x) and cos(b*x) terms. However, SymPy currently - cannot do that expansion, so you will need to manually rewrite the - expression in terms of the above to use this method. So, for example, - you will need to manually convert sin(x)**2 into (1 + cos(2*x))/2 to - properly apply the method of undetermined coefficients on it. - - This method works by creating a trial function from the expression - and all of its linear independent derivatives and substituting them - into the original ODE. The coefficients for each term will be a - system of linear equations, which are be solved for and substituted, - giving the solution. If any of the trial functions are linearly - dependent on the solution to the homogeneous equation, they are - multiplied by sufficient x to make them linearly independent. + This method works on differential equations of the form + + .. math:: a_n f^{(n)}(x) + a_{n-1} f^{(n-1)}(x) + \cdots + a_1 f'(x) + + a_0 f(x) = P(x)\text{,} + + where `P(x)` is a function that has a finite number of linearly + independent derivatives. + + Functions that fit this requirement are finite sums functions of the form + `a x^i e^{b x} \sin(c x + d)` or `a x^i e^{b x} \cos(c x + d)`, where `i` + is a non-negative integer and `a`, `b`, `c`, and `d` are constants. For + example any polynomial in `x`, functions like `x^2 e^{2 x}`, `x \sin(x)`, + and `e^x \cos(x)` can all be used. Products of `\sin`'s and `\cos`'s have + a finite number of derivatives, because they can be expanded into `\sin(a + x)` and `\cos(b x)` terms. However, SymPy currently cannot do that + expansion, so you will need to manually rewrite the expression in terms of + the above to use this method. So, for example, you will need to manually + convert `\sin^2(x)` into `(1 + \cos(2 x))/2` to properly apply the method + of undetermined coefficients on it. + + This method works by creating a trial function from the expression and all + of its linear independent derivatives and substituting them into the + original ODE. The coefficients for each term will be a system of linear + equations, which are be solved for and substituted, giving the solution. + If any of the trial functions are linearly dependent on the solution to + the homogeneous equation, they are multiplied by sufficient `x` to make + them linearly independent. Examples ======== @@ -2662,21 +3225,30 @@ match.update(gensol) return _solve_undetermined_coefficients(eq, func, order, match) + def _solve_undetermined_coefficients(eq, func, order, match): - """ + r""" Helper function for the method of undetermined coefficients. - See the ode_nth_linear_constant_coeff_undetermined_coefficients() + See the + :py:meth:`~sympy.solvers.ode.ode_nth_linear_constant_coeff_undetermined_coefficients` docstring for more information on this method. - match should be a dictionary that has the following keys: - 'list' - A list of solutions to the homogeneous equation, such as - the list returned by - ode_nth_linear_constant_coeff_homogeneous(returns='list') - 'sol' - The general solution, such as the solution returned by - ode_nth_linear_constant_coeff_homogeneous(returns='sol') - 'trialset' - The set of trial functions as returned by - _undetermined_coefficients_match()['trialset'] + The parameter ``match`` should be a dictionary that has the following + keys: + + ``list`` + A list of solutions to the homogeneous equation, such as the list + returned by + ``ode_nth_linear_constant_coeff_homogeneous(returns='list')``. + + ``sol`` + The general solution, such as the solution returned by + ``ode_nth_linear_constant_coeff_homogeneous(returns='sol')``. + + ``trialset`` + The set of trial functions as returned by + ``_undetermined_coefficients_match()['trialset']``. """ x = func.args[0] @@ -2691,11 +3263,12 @@ newtrialset = set([]) global collectterms if len(gensols) != order: - raise NotImplementedError("Cannot find " + str(order) + \ - " solutions to the homogeneous equation nessesary to apply " + \ - "undetermined coefficients to " + str(eq) + " (number of terms != order)") + raise NotImplementedError("Cannot find " + str(order) + + " solutions to the homogeneous equation nessesary to apply" + + " undetermined coefficients to " + str(eq) + + " (number of terms != order)") usedsin = set([]) - mult = 0 # The multiplicity of the root + mult = 0 # The multiplicity of the root getmult = True for i, reroot, imroot in collectterms: if getmult: @@ -2714,10 +3287,11 @@ check = x**i*exp(reroot*x) if check in trialset: - # If an element of the trial function is already part of the homogeneous - # solution, we need to multiply by sufficient x to make it linearly - # independent. We also don't need to bother checking for the coefficients - # on those elements, since we already know it will be 0. + # If an element of the trial function is already part of the + # homogeneous solution, we need to multiply by sufficient x to + # make it linearly independent. We also don't need to bother + # checking for the coefficients on those elements, since we + # already know it will be 0. while True: if check*x**mult in trialset: mult += 1 @@ -2747,37 +3321,39 @@ coeffvals = solve(list(coeffsdict.values()), coefflist) if not coeffvals: - raise NotImplementedError("Could not solve " + str(eq) + " using the " + \ - " method of undetermined coefficients (unable to solve for coefficients).") + raise NotImplementedError( + "Could not solve `%s` using the " + "method of undetermined coefficients " + "(unable to solve for coefficients)." % eq) psol = trialfunc.subs(coeffvals) return Eq(f(x), gsol.rhs + psol) + def _undetermined_coefficients_match(expr, x): - """ - Returns a trial function match if undetermined coefficients can be - applied to expr, and None otherwise. + r""" + Returns a trial function match if undetermined coefficients can be applied + to ``expr``, and ``None`` otherwise. - A trial expression can be found for an expression for use with the - method of undetermined coefficients if the expression is an - additive/multiplicative combination of constants, polynomials in x - (the independent variable of expr), sin(a*x + b), cos(a*x + b), and - exp(a*x) terms (in other words, it has a finite number of linearly + A trial expression can be found for an expression for use with the method + of undetermined coefficients if the expression is an + additive/multiplicative combination of constants, polynomials in `x` (the + independent variable of expr), `\sin(a x + b)`, `\cos(a x + b)`, and + `e^{a x}` terms (in other words, it has a finite number of linearly independent derivatives). Note that you may still need to multiply each term returned here by - sufficient x to make it linearly independent with the solutions to - the homogeneous equation. + sufficient `x` to make it linearly independent with the solutions to the + homogeneous equation. - This is intended for internal use by undetermined_coefficients - hints. + This is intended for internal use by ``undetermined_coefficients`` hints. - SymPy currently has no way to convert sin(x)**n*cos(y)**m into a sum - of only sin(a*x) and cos(b*x) terms, so these are not implemented. - So, for example, you will need to manually convert sin(x)**2 into - (1 + cos(2*x))/2 to properly apply the method of undetermined - coefficients on it. + SymPy currently has no way to convert `\sin^n(x) \cos^m(y)` into a sum of + only `\sin(a x)` and `\cos(b x)` terms, so these are not implemented. So, + for example, you will need to manually convert `\sin^2(x)` into `[1 + + \cos(2 x)]/2` to properly apply the method of undetermined coefficients on + it. Examples ======== @@ -2794,11 +3370,12 @@ from sympy import S a = Wild('a', exclude=[x]) b = Wild('b', exclude=[x]) - expr = powsimp(expr, combine='exp') # exp(x)*exp(2*x + 1) => exp(3*x + 1) + expr = powsimp(expr, combine='exp') # exp(x)*exp(2*x + 1) => exp(3*x + 1) retdict = {} + def _test_term(expr, x): - """ - Test if expr fits the proper form for undetermined coefficients. + r""" + Test if ``expr`` fits the proper form for undetermined coefficients. """ if expr.is_Add: return all(_test_term(i, x) for i in expr.args) @@ -2823,7 +3400,7 @@ else: return False elif expr.is_Pow and expr.base.is_Symbol and expr.exp.is_Integer and \ - expr.exp >= 0: + expr.exp >= 0: return True elif expr.is_Pow and expr.base.is_number: if expr.exp.match(a*x + b): @@ -2836,17 +3413,16 @@ return False def _get_trial_set(expr, x, exprs=set([])): - """ + r""" Returns a set of trial terms for undetermined coefficients. - The idea behind undetermined coefficients is that the terms - expression repeat themselves after a finite number of - derivatives, except for the coefficients (they are linearly - dependent). So if we collect these, we should have the terms of - our trial function. + The idea behind undetermined coefficients is that the terms expression + repeat themselves after a finite number of derivatives, except for the + coefficients (they are linearly dependent). So if we collect these, + we should have the terms of our trial function. """ def _remove_coefficient(expr, x): - """ + r""" Returns the expression without a coefficient. Similar to expr.as_independent(x)[1], except it only works @@ -2880,7 +3456,8 @@ tmpset = exprs.union(set([term])) oldset = set([]) while tmpset != oldset: - # If you get stuck in this loop, then _test_term is probably broken + # If you get stuck in this loop, then _test_term is probably + # broken oldset = tmpset.copy() expr = expr.diff(x) term = _remove_coefficient(expr, x) @@ -2891,55 +3468,63 @@ exprs = tmpset return exprs - - retdict['test'] = _test_term(expr, x) if retdict['test']: - # Try to generate a list of trial solutions that will have the undetermined - # coefficients. Note that if any of these are not linearly independent - # with any of the solutions to the homogeneous equation, then they will - # need to be multiplied by sufficient x to make them so. This function - # DOES NOT do that (it doesn't even look at the homogeneous equation). + # Try to generate a list of trial solutions that will have the + # undetermined coefficients. Note that if any of these are not linearly + # independent with any of the solutions to the homogeneous equation, + # then they will need to be multiplied by sufficient x to make them so. + # This function DOES NOT do that (it doesn't even look at the + # homogeneous equation). retdict['trialset'] = _get_trial_set(expr, x) return retdict + def ode_nth_linear_constant_coeff_variation_of_parameters(eq, func, order, match): r""" - Solves an nth order linear differential equation with constant - coefficients using the method of undetermined coefficients. + Solves an `n`\th order linear differential equation with constant + coefficients using the method of variation of parameters. This method works on any differential equations of the form - f(x)^(n) + a_(n-1)*f(x)^(n-1) + ... + a1*f'(x) + a0*f(x) = P(x). - This method works by assuming that the particular solution takes the - form Sum(c_i(x)*y_i(x), (x, 1, n)), where y_i is the ith solution to - the homogeneous equation. The solution is then solved using - Wronskian's and Cramer's Rule. The particular solution is given by - Sum(Integral(W_i(x)/W(x), x)*y_i(x), (x, 1, n)), where W(x) is the - Wronskian of the fundamental system (the system of n linearly - independent solutions to the homogeneous equation), and W_i(x) is - the Wronskian of the fundamental system with the ith column replaced - with [0, 0, ..., 0, P(x)]. - - This method is general enough to solve any nth order inhomogeneous - linear differential equation with constant coefficients, but - sometimes SymPy cannot simplify the Wronskian well enough to - integrate it. If this method hangs, try using the - 'nth_linear_constant_coeff_variation_of_parameters_Integral' hint - and simplifying the integrals manually. Also, prefer using - 'nth_linear_constant_coeff_undetermined_coefficients' when it - applies, because it doesn't use integration, making it faster and - more reliable. + .. math:: f^{(n)}(x) + a_{n-1} f^{(n-1)}(x) + \cdots + a_1 f'(x) + a_0 + f(x) = P(x)\text{.} + + This method works by assuming that the particular solution takes the form + + .. math:: \sum_{x=1}^{n} c_i(x) y_i(x)\text{,} + + where `y_i` is the `i`\th solution to the homogeneous equation. The + solution is then solved using Wronskian's and Cramer's Rule. The + particular solution is given by + + .. math:: \sum_{x=1}^n \left( \int \frac{W_i(x)}{W(x)} \,dx + \right) y_i(x) \text{,} + + where `W(x)` is the Wronskian of the fundamental system (the system of `n` + linearly independent solutions to the homogeneous equation), and `W_i(x)` + is the Wronskian of the fundamental system with the `i`\th column replaced + with `[0, 0, \cdots, 0, P(x)]`. + + This method is general enough to solve any `n`\th order inhomogeneous + linear differential equation with constant coefficients, but sometimes + SymPy cannot simplify the Wronskian well enough to integrate it. If this + method hangs, try using the + ``nth_linear_constant_coeff_variation_of_parameters_Integral`` hint and + simplifying the integrals manually. Also, prefer using + ``nth_linear_constant_coeff_undetermined_coefficients`` when it + applies, because it doesn't use integration, making it faster and more + reliable. Warning, using simplify=False with - 'nth_linear_constant_coeff_variation_of_parameters' in dsolve() - may cause it to hang, because it will not attempt to simplify - the Wronskian before integrating. It is recommended that you only - use simplify=False with - 'nth_linear_constant_coeff_variation_of_parameters_Integral' for - this method, especially if the solution to the homogeneous - equation has trigonometric functions in it. + 'nth_linear_constant_coeff_variation_of_parameters' in + :py:meth:`~sympy.solvers.ode.dsolve` may cause it to hang, because it will + not attempt to simplify the Wronskian before integrating. It is + recommended that you only use simplify=False with + 'nth_linear_constant_coeff_variation_of_parameters_Integral' for this + method, especially if the solution to the homogeneous equation has + trigonometric functions in it. Examples ======== @@ -2972,19 +3557,26 @@ match.update(gensol) return _solve_variation_of_parameters(eq, func, order, match) + def _solve_variation_of_parameters(eq, func, order, match): - """ + r""" Helper function for the method of variation of parameters. - See the ode_nth_linear_constant_coeff_variation_of_parameters() + See the + :py:meth:`~sympy.solvers.ode.ode_nth_linear_constant_coeff_variation_of_parameters` docstring for more information on this method. - match should be a dictionary that has the following keys: - 'list' - A list of solutions to the homogeneous equation, such as - the list returned by - ode_nth_linear_constant_coeff_homogeneous(returns='list') - 'sol' - The general solution, such as the solution returned by - ode_nth_linear_constant_coeff_homogeneous(returns='sol') + The parameter ``match`` should be a dictionary that has the following + keys: + + ``list`` + A list of solutions to the homogeneous equation, such as the list + returned by + ``ode_nth_linear_constant_coeff_homogeneous(returns='list')``. + + ``sol`` + The general solution, such as the solution returned by + ``ode_nth_linear_constant_coeff_homogeneous(returns='sol')``. """ @@ -2997,20 +3589,22 @@ wr = wronskian(gensols, x) if r.get('simplify', True): - wr = simplify(wr) # We need much better simplification for some ODEs. - # See issue 1563, for example. + wr = simplify(wr) # We need much better simplification for + # some ODEs. See issue 1563, for example. # To reduce commonly occuring sin(x)**2 + cos(x)**2 to 1 wr = trigsimp(wr, deep=True, recursive=True) if not wr: - # The wronskian will be 0 iff the solutions are not linearly independent. - raise NotImplementedError("Cannot find " + str(order) + \ - " solutions to the homogeneous equation nessesary to apply " + \ + # The wronskian will be 0 iff the solutions are not linearly + # independent. + raise NotImplementedError("Cannot find " + str(order) + + " solutions to the homogeneous equation nessesary to apply " + "variation of parameters to " + str(eq) + " (Wronskian == 0)") if len(gensols) != order: - raise NotImplementedError("Cannot find " + str(order) + \ - " solutions to the homogeneous equation nessesary to apply " + \ - "variation of parameters to " + str(eq) + " (number of terms != order)") + raise NotImplementedError("Cannot find " + str(order) + + " solutions to the homogeneous equation nessesary to apply " + + "variation of parameters to " + + str(eq) + " (number of terms != order)") negoneterm = (-1)**(order) for i in gensols: psol += negoneterm*C.Integral(wronskian([x for x in gensols if x != i], x)*r[-1]/wr, x)*i/r[order] @@ -3021,20 +3615,20 @@ psol = trigsimp(psol, deep=True) return Eq(f(x), gsol.rhs + psol) + def ode_separable(eq, func, order, match): r""" - Solves separable 1st order differential equations. - This is any differential equation that can be written as - P(y)*dy/dx = Q(x). The solution can then just be found by - rearranging terms and integrating: - Integral(P(y), y) = Integral(Q(x), x). This hint uses separatevars() - as its back end, so if a separable equation is not caught by this - solver, it is most likely the fault of that function. separatevars() - is smart enough to do most expansion and factoring necessary to - convert a separable equation F(x, y) into the proper form P(x)*Q(y). - The general solution is:: + This is any differential equation that can be written as `P(y) + \tfrac{dy}{dx} = Q(x)`. The solution can then just be found by + rearranging terms and integrating: `\int P(y) \,dy = \int Q(x) \,dx`. + This hint uses :py:meth:`sympy.simplify.separatevars` as its back end, so + if a separable equation is not caught by this solver, it is most likely + the fault of that function. :py:meth:`~sympy.simplify.separatevars` is + smart enough to do most expansion and factoring necessary to convert a + separable equation `F(x, y)` into the proper form `P(x)\cdot{}Q(y)`. The + general solution is:: >>> from sympy import Function, dsolve, Eq, pprint >>> from sympy.abc import x @@ -3079,7 +3673,450 @@ x = func.args[0] f = func.func C1 = Symbol('C1') - r = match # {'m1':m1, 'm2':m2, 'y':y} + r = match # {'m1':m1, 'm2':m2, 'y':y} + u = r.get('hint', f(x)) # get u from separable_reduced else get f(x) return Eq(C.Integral(r['m2']['coeff']*r['m2'][r['y']]/r['m1'][r['y']], - (r['y'], None, f(x))), C.Integral(-r['m1']['coeff']*r['m1'][x]/ - r['m2'][x], x)+C1) + (r['y'], None, u)), C.Integral(-r['m1']['coeff']*r['m1'][x]/ + r['m2'][x], x) + C1) + + +def checkinfsol(eq, infinitesimals, func=None, order=None): + r""" + This function is used to check if the given infinitesimals are the + actual infinitesimals for the given first order differential equation. + As of now, it simply checks, by substituting the infinitesimals in the + partial differential equation. + (eta.diff(x) + (eta.diff(y) - xi.diff(x))*h - + (xi.diff(y))*h**2 - xi*(h.diff(x)) - eta*(h.diff(y))) = 0 + where eta, and xi are the infinitesimals and h(x,y) = dy/dx + + The infinitesimals should be given in the form of a list of dicts + [{xi(x, y): inf, eta(x, y): inf}], corresponding to the + output of the function infinitesimals. It returns a list + of values of the form [(True/False, sol)] where sol is the value + obtained after substituting the infinitesimals in the PDE. If it + is True, then sol would be zero. + + """ + if isinstance(eq, Equality): + eq = eq.lhs - eq.rhs + if not func: + eq, func = _preprocess(eq) + variables = func.args + if len(variables) != 1: + raise ValueError("ODE's have only one independent variable") + else: + x = variables[0] + if not order: + order = ode_order(eq, func) + if order != 1: + raise NotImplementedError("Lie groups solver has been implemented " + "only for first order differential equations") + else: + df = func.diff(x) + a = Wild('a', exclude = [df]) + b = Wild('b') + match = collect(expand(eq), df).match(a*df + b) + h = -match[b]/match[a] + y = Symbol('y') + h = h.subs(func, y) + xi = Function('xi')(x, y) + eta = Function('eta')(x, y) + dxi = Function('xi')(x, func) + deta = Function('eta')(x, func) + pde = (eta.diff(x) + (eta.diff(y) - xi.diff(x))*h - + (xi.diff(y))*h**2 - xi*(h.diff(x)) - eta*(h.diff(y))) + soltup = [] + for sol in infinitesimals: + tsol = {xi: S(sol[dxi]).subs(func, y), + eta: S(sol[deta]).subs(func, y)} + sol = simplify(pde.subs(tsol).doit()) + if sol: + soltup.append((False, sol)) + else: + soltup.append((True, 0)) + return soltup + +def infinitesimals(eq, func=None, order=None, **kwargs): + r""" + The functions xi and eta, are called the infinitesimals which help in + the process of finding a new co-ordinate system, in which a differential + equation can be simplified. They are tangents to the coordinate curves, in + which the differential equation is simplified. + + Consider the transformation (x, y) --> (X, Y) such that X and Y are + f(x, y, lambda) and g(x, y, lambda) and such that the + differential equation remains invariant. Xi and eta are the tangents to + the transformed coordinates X and Y, when lambda is the identity. + + The infinitesimals can be found by solving the following Partial Differential + Equation. + + >>> from sympy import Function, diff, Eq, pprint + >>> from sympy.abc import x, y + >>> xi, eta, h = list(map(Function, ['xi', 'eta', 'h'])) + >>> h = h(x, y) # dy/dx = h + >>> eta = eta(x, y) + >>> xi = xi(x, y) + >>> genform = Eq(eta.diff(x) + (eta.diff(y) - xi.diff(x))*h + ... - (xi.diff(y))*h**2 - xi*(h.diff(x)) - eta*(h.diff(y)), 0) + >>> pprint(genform) + /d d \ d 2 d + |--(eta(x, y)) - --(xi(x, y))|*h(x, y) - eta(x, y)*--(h(x, y)) - h (x, y)*--(x + \dy dx / dy dy + + d d + i(x, y)) - xi(x, y)*--(h(x, y)) + --(eta(x, y)) = 0 + dx dx + + Once the infinitesimals are found, the following partial differential + equations would help us find the transformed coordinates (X, Y) + + 1. X.diff(x)*xi + X.diff(y)*eta = 0 + 2. Y.diff(x)*xi + Y.diff(y)*eta = 1 + + + Examples + ======== + + >>> from sympy import Function, diff + >>> from sympy.solvers.ode import infinitesimals + >>> from sympy.abc import x + >>> f = Function('f') + >>> eq = f(x).diff(x) - x**2*f(x) + >>> infinitesimals(eq) + [{eta(x, f(x)): exp(x**3/3), xi(x, f(x)): 0}, + {eta(x, f(x)): f(x), xi(x, f(x)): 0}, + {eta(x, f(x)): 0, xi(x, f(x)): x**(-2)}, + {eta(x, f(x)): x**2*f(x) + f(x), xi(x, f(x)): 1}] + + + References + ========== + + - Solving differential equations by Symmetry Groups, + John Starrett, pp. 1 - pp. 14 + + + """ + from sympy.integrals.integrals import integrate + + if isinstance(eq, Equality): + eq = eq.lhs - eq.rhs + if not func: + eq, func = _preprocess(eq) + variables = func.args + if len(variables) != 1: + raise ValueError("ODE's have only one independent variable") + else: + x = variables[0] + if not order: + order = ode_order(eq, func) + if order != 1: + raise NotImplementedError("Infinitesimals for only " + "first order ODE's have been implemented") + else: + df = func.diff(x) + # Matching differential equation of the form a*df + b + a = Wild('a', exclude = [df]) + b = Wild('b') + match = kwargs.get('match', + collect(expand(eq), df).match(a*df + b)) + h = -simplify(match[b]/match[a]) + y = Symbol('y') + h = h.subs(func, y) + hsyms = h.free_symbols + xi = Function('xi')(x, func) + eta = Function('eta')(x, func) + hx = h.diff(x) + hy = h.diff(y) + xieta = [] + # This is the PDE that has to be solved using various + # heuristics. The purpose is to "intelligently" guess + # the functions xi and eta. All the heuristics are cited + # from the paper "Computer Algebra Solving of first order + # ODE's Using Symmetry Methods" unless otherwise specified. + # Here dy/dx = h + # [eta.diff(x) + (eta.diff(y) - xi.diff(x))*h + # - xi.diff(y)*h**2 - xi*(h.diff(x)) - eta*(h.diff(y))) = 0] + # The first heuristic uses the following four sets of + # assumptions on xi and eta + # 1. [xi = 0, eta = f(x)] + # 2. [xi = 0, eta = f(y)] + # 3. [xi = f(x), eta = 0] + # 4. [xi = f(y), eta = 0] + # Assuming xi = 0 and eta to be a function of x, the PDE + # reduces to eta.diff(x) - eta*(h.diff(y)) = 0 + # If h.diff(y) is a function of x, then this can usually + # be integrated easily. + hysym = hy.free_symbols + if y not in hysym: + try: + fx = exp(integrate(hy, x)) + except NotImplementedError: + pass + else: + inf = {xi: 0, eta: fx.subs(y, func)} + if inf not in xieta: + xieta.append(inf) + + # Assuming xi = 0 and eta to be a function of y, the PDE + # reduces to eta.diff(y)*h - eta*(h.diff(y)) = 0 + # If h.diff(y)/h is a function of y, then this can usually + # be integrated easily. + factor = hy/h + facsym = factor.free_symbols + if x not in facsym: + try: + fy = exp(integrate(factor, y)) + except NotImplementedError: + pass + else: + inf = {xi: 0, eta: fy.subs(y, func)} + if inf not in xieta: + xieta.append(inf) + + # Assuming eta = 0 and xi to be a function of x, the PDE + # reduces to - (xi.diff(x))*h - xi*(h.diff(x)) + # If -h.diff(x)/h is a function of x, then this can usually + # be integrated easily. + factor = -hx/h + facsym = factor.free_symbols + if y not in facsym: + try: + fx = exp(integrate(factor, x)) + except NotImplementedError: + pass + else: + inf = {xi: fx.subs(y, func), eta: 0} + if inf not in xieta: + xieta.append(inf) + + # Assuming eta = 0 and xi to be a function of y, the PDE + # reduces to - xi.diff(y)*h**2 - xi*(h.diff(x)) + # If -h.diff(x)/h**2 is a function of y, then this can usually + # be integrated easily. + factor = -hx/(h**2) + facsym = factor.free_symbols + if x not in facsym: + try: + fy = exp(integrate(factor, y)) + except NotImplementedError: + pass + else: + inf = {xi: fy.subs(y, func), eta: 0} + if inf not in xieta: + xieta.append(inf) + + # The second heuristic uses the following four sets of + # assumptions on xi and eta + # 1. [xi = 0, eta = f(x)*g(y)] + # 2. [xi = 0, eta = f(y)*g(x)] + # 3. [xi = f(x)*g(y), eta = 0] + # 4. [xi = f(y)*g(x), eta = 0] + # g is a function built by extracting algebraic factors from the + # numerator and denominator of the ODE to be solved and f is an + # unknown function to be determined by solving auxiliary ODE's + # after substituting g in the PDE. + # If the auxilliary ODE obtained is separable in f, it is assumed + # that this heuristic works. + argx = [] # Extracting factors containing x only + argy = [] # Extracting factors containing y only + Fx = Function('F')(x) + Fy = Function('F')(y) + c = Wild('c') + d = Wild('d', exclude=[Fx.diff(x), Fy.diff(y)]) + gcd = gcd_terms(h) + if gcd.is_Pow: + base, power = gcd.as_base_exp() + if gcd.has(y) and not gcd.has(x) and \ + gcd.is_algebraic_expr(y): + argy.append(base**power) + if gcd.has(x) and not gcd.has(y) and \ + gcd.is_algebraic_expr(x): + argx.append(base**power) + elif gcd.is_Mul: + factors = gcd.args + for arg in factors: + if arg.has(y) and not arg.has(x) and \ + arg.is_algebraic_expr(y): + if argy: + argy.extend([arg*factory for factory in argy]) + argy.append(arg) + if arg.has(x) and not arg.has(y) and \ + arg.is_algebraic_expr(x): + if argx: + argx.extend([arg*factorx for factorx in argx]) + argx.append(arg) + + if argy: + for arg in argy: + # Assuming xi = 0, and eta to be f(x)*g(y), the PDE reduces to + # (f(x).diff(x)*g(y) + f(x)*g(y).diff(y)*h - f(x)*g(y)*(hy) = 0) + eq = (Fx.diff(x))*arg + Fx*h*(arg.diff(y)) - Fx*arg*(hy) + # This means y can be successfully eliminated from eq. + # The same logic applies for the four assumptions below + var = separatevars(eq, [x, y], dict=True) + if var: + coeffx = var[x] + match = coeffx.match(c*Fx.diff(x) + d) + if match: + match = (-match[d]/match[c]).subs(Fx, y) + # This heuristic is assumed to work if the auxilliary ODE + # obtained is separable in Fx and x. The same logic + # is used for the cases below. + red = separatevars(match, [x, y], dict=True) + if red: + inty = integrate(1/(red['coeff']*red[y]), y) + intx = integrate(red[x], x) + try: + msol = solve(Eq(inty, intx), y) + except NotImplementedError: + pass + else: + for sol in msol: + if not sol is S.NaN: + inf = {xi: 0, eta: (sol*arg).subs(y, func)} + if inf not in xieta: + xieta.append(inf) + + # Assuming eta = 0, and xi to be f(x)*g(y), the PDE reduces to + # (f(x).diff(x)*g(y)*h + f(x)*g(y).diff(y)*h**2 + + # f(x)*g(y)*h.diff(x) = 0) + eq = ((Fx.diff(x))*arg*h + h**2*Fx*(arg.diff(y)) + + Fx*arg*(hx)) + var = separatevars(eq, [x, y], dict=True) + if var: + coeffx = var[x] + match = coeffx.match(c*Fx.diff(x) + d) + if match: + match = (-match[d]/match[c]).subs(Fx, y) + red = separatevars(match, [x, y], dict=True) + if red: + inty = integrate(1/(red['coeff']*red[y]), y) + intx = integrate(red[x], x) + try: + msol = solve(Eq(inty, intx), y) + except NotImplementedError: + pass + else: + for sol in msol: + if not sol is S.NaN: + inf = {xi: (sol*arg).subs(y, func), eta: 0} + if inf not in xieta: + xieta.append(inf) + + if argx: + for arg in argx: + # Assuming xi = 0, and eta to be g(x)*f(y), the PDE reduces to + # (g(x).diff(x)*f(y) + g(x)*f(y).diff(y)*h - g(x)*f(y)*hy = 0) + eq = (arg.diff(x))*Fy + arg*h*(Fy.diff(y)) - arg*hy*Fy + var = separatevars(eq, [x, y], dict=True) + if var: + coeffy = var[y] + match = coeffy.match(c*Fy.diff(y) + d) + if match: + match = (-match[d]/match[c]).subs(Fy, x) + red = separatevars(match, [x, y], dict=True) + if red: + intx = integrate(1/(red['coeff']*red[x]), x) + inty = integrate(red[y], y) + try: + msol = solve(Eq(intx, inty), x) + except NotImplementedError: + pass + else: + for sol in msol: + if not sol is S.NaN: + inf = {xi: 0, eta: (sol*arg).subs(y, func)} + if inf not in xieta: + xieta.append(inf) + + # Assuming eta = 0, and xi to be g(x)*f(y), the PDE reduces to + # (g(x).diff(x)*f(y)*h + g(x)*f(y).diff(y)*h**2 + + # g(x)*f(y)*h.diff(x) = 0) + eq = ((arg.diff(x))*h*Fy + h**2*arg*(Fy.diff(y)) + + arg*Fy*(h.diff(x))) + var = separatevars(eq, [x, y], dict=True) + if var: + coeffy = var[y] + match = coeffy.match(c*Fy.diff(y) + d) + if match: + match = (-match[d]/match[c]).subs(Fy, x) + red = separatevars(match, [x, y], dict=True) + if red: + intx = integrate(1/(red['coeff']*red[x]), x) + inty = integrate(red[y], y) + try: + msol = solve(Eq(intx, inty), x) + except NotImplementedError: + pass + else: + for sol in msol: + if not sol is S.NaN: + inf = {xi: (sol*arg).subs(y, func), eta: 0} + if inf not in xieta: + xieta.append(inf) + + # The third heuristic assumes the infinitesimals xi and eta + # to be bi-variate polynomials in x and y. The assumption made here + # for the logic below is that h is a rational function in x and y + # though that may not be necessary for the infinitesimals to be + # be bivariate polynomials. The coefficients of the infinitesimals + # are found out by substituting them in the PDE and grouping terms + # that are monomials in y. The degree of the assumed bivariates + # are increased till a certain maximum value. + + if h.is_rational_function(): + # The maximum degree that the infinitesimals can take is + # calculated by this technique. + deglist = [degree(term) for term in [h, h**2, hx, hy]] + maxdeg = max(deglist) + mindeg = min(deglist) + if mindeg < 0: + deg = maxdeg - mindeg + else: + deg = maxdeg + + deta = Function('deta')(x, y) + dxi = Function('dxi')(x, y) + ipde = (deta.diff(x) + (deta.diff(y) - dxi.diff(x))*h - (dxi.diff(y))*h**2 + - dxi*hx - deta*hy) + xieq = Symbol("xi0") + etaeq = Symbol("eta0") + + + for i in range(deg + 1): + if i: + xieq += Add(*[ + Symbol("xi" + str(power) + str(i - power))*x**power*y**(i - power) + for power in range(i + 1)]) + etaeq += Add(*[ + Symbol("eta" + str(power) + str(i - power))*x**power*y**(i - power) + for power in range(i + 1)]) + pden, denom = (ipde.subs({dxi: xieq, deta: etaeq}).doit()).as_numer_denom() + pden = expand(pden) + + # If the individual terms are monomials, the coefficients + # are grouped + if pden.is_polynomial(x, y) and pden.is_Add: + polyy = Poly(pden, x, y).as_dict() + if polyy: + symset = xieq.free_symbols.union(etaeq.free_symbols) - set([x, y]) + soldict = solve(list(polyy.values()), *symset) + if isinstance(soldict, list): + soldict = soldict[0] + if any(x for x in list(soldict.values())): + xired = xieq.subs(soldict) + etared = etaeq.subs(soldict) + # Scaling is done by substituting one for the parameters + # This can be any number except zero. + dict_ = dict((sym, 1) for sym in symset) + inf = {eta: etared.subs(dict_).subs(y, func), + xi: xired.subs(dict_).subs(y, func)} + + if inf not in xieta: + xieta.append(inf) + break + + return xieta diff -Nru python3-sympy-0.7.2/sympy/solvers/pde.py python3-sympy-0.7.3/sympy/solvers/pde.py --- python3-sympy-0.7.2/sympy/solvers/pde.py 2012-10-17 03:02:22.000000000 +0000 +++ python3-sympy-0.7.3/sympy/solvers/pde.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,18 +1,645 @@ """ -Analytical methods for solving Partial Differential Equations -Currently implemented methods: - - separation of variables - pde_separate +This module contains pdsolve() and different helper functions that it +uses. It is heavily inspired by the ode module and hence the basic +infrastructure remains the same. + +**Functions in this module** + + These are the user functions in this module: + + - pdsolve() - Solves PDE's + - classify_pde() - Classifies PDEs into possible hints for dsolve(). + - pde_separate() - Separate variables in partial differential equation either by + additive or multiplicative separation approach. + + These are the helper functions in this module: + + - pde_separate_add() - Helper function for searching additive separable solutions. + - pde_separate_mul() - Helper function for searching multiplicative + separable solutions. + +**Currently implemented solver methods** + +The following methods are implemented for solving partial differential +equations. See the docstrings of the various pde_hint() functions for +more information on each (run help(pde)): + + - 1st order linear homogeneous partial differential equations + with constant coefficients. """ +from copy import deepcopy -from sympy import Eq, Equality from sympy.simplify import simplify -from sympy.core.compatibility import reduce +from sympy.core import Add, C, S, Mul, Pow, oo +from sympy.core.compatibility import (reduce, combinations_with_replacement, + is_sequence) +from sympy.core.function import (Function, Derivative, + expand, diff, AppliedUndef, Subs) +from sympy.core.numbers import Rational +from sympy.core.relational import Equality, Eq +from sympy.core.symbol import Symbol, Wild, Dummy, symbols +from sympy.functions import exp from sympy.utilities.iterables import has_dups +from sympy.solvers.deutils import _preprocess, ode_order, _desolve +from sympy.solvers.solvers import solve import operator from functools import reduce +allhints = ( + "1st_linear_constant_coeff_homogeneous", + "1st_linear_constant_coeff", + "1st_linear_constant_coeff_Integral" + ) + +def pdsolve(eq, func=None, hint='default', dict=False, solvefun=None, **kwargs): + """ + Solves any (supported) kind of partial differential equation. + + **Usage** + + pdsolve(eq, f(x,y), hint) -> Solve partial differential equation + eq for function f(x,y), using method hint. + + **Details** + + ``eq`` can be any supported partial differential equation (see + the pde docstring for supported methods). This can either + be an Equality, or an expression, which is assumed to be + equal to 0. + + ``f(x,y)`` is a function of two variables whose derivatives in that + variable make up the partial differential equation. In many + cases it is not necessary to provide this; it will be autodetected + (and an error raised if it couldn't be detected). + + ``hint`` is the solving method that you want pdsolve to use. Use + classify_pde(eq, f(x,y)) to get all of the possible hints for + a PDE. The default hint, 'default', will use whatever hint + is returned first by classify_pde(). See Hints below for + more options that you can use for hint. + + ``solvefun`` is the convention used for arbitrary functions returned + by the PDE solver. If not set by the user, it is set by default + to be F. + + **Hints** + + Aside from the various solving methods, there are also some + meta-hints that you can pass to pdsolve(): + + "default": + This uses whatever hint is returned first by + classify_pde(). This is the default argument to + pdsolve(). + + "all": + To make pdsolve apply all relevant classification hints, + use pdsolve(PDE, func, hint="all"). This will return a + dictionary of hint:solution terms. If a hint causes + pdsolve to raise the NotImplementedError, value of that + hint's key will be the exception object raised. The + dictionary will also include some special keys: + + - order: The order of the PDE. See also ode_order() in + deutils.py + - default: The solution that would be returned by + default. This is the one produced by the hint that + appears first in the tuple returned by classify_pde(). + + "all_Integral": + This is the same as "all", except if a hint also has a + corresponding "_Integral" hint, it only returns the + "_Integral" hint. This is useful if "all" causes + pdsolve() to hang because of a difficult or impossible + integral. This meta-hint will also be much faster than + "all", because integrate() is an expensive routine. + + See also the classify_pde() docstring for more info on hints, + and the pde docstring for a list of all supported hints. + + **Tips** + - You can declare the derivative of an unknown function this way: + >>> from sympy import Function, Derivative + >>> from sympy.abc import x, y # x and y are the independent variables + >>> f = Function("f")(x, y) # f is a function of x and y + >>> # fx will be the partial derivative of f with respect to x + >>> fx = Derivative(f, x) + >>> # fy will be the partial derivative of f with respect to y + >>> fy = Derivative(f, y) + + - See test_pde.py for many tests, which serves also as a set of + examples for how to use pdsolve(). + - pdsolve always returns an Equality class (except for the case + when the hint is "all" or "all_Integral"). Note that it is not possible + to get an explicit solution for f(x, y) as in the case of ODE's + - Do help(pde.pde_hintname) to get help more information on a + specific hint + + + Examples + ======== + + >>> from sympy.solvers.pde import pdsolve + >>> from sympy import Function, diff, Eq + >>> from sympy.abc import x, y + >>> f = Function('f') + >>> u = f(x, y) + >>> ux = u.diff(x) + >>> uy = u.diff(y) + >>> eq = Eq(1 + (2*(ux/u)) + (3*(uy/u))) + >>> pdsolve(eq) + f(x, y) == F(3*x - 2*y)*exp(-2*x/13 - 3*y/13) + + """ + + given_hint = hint # hint given by the user. + + if not solvefun: + solvefun = Function('F') + + # See the docstring of _desolve for more details. + hints = _desolve(eq, func=func, + hint=hint, simplify=True, type='pde', **kwargs) + eq = hints.pop('eq', False) + all_ = hints.pop('all', False) + + if all_: + # TODO : 'best' hint should be implemented when adequate + # number of hints are added. + pdedict = {} + failed_hints = {} + gethints = classify_pde(eq, dict=True) + pdedict.update({'order': gethints['order'], + 'default': gethints['default']}) + for hint in hints: + try: + rv = _helper_simplify(eq, hint, hints[hint]['func'], + hints[hint]['order'], hints[hint][hint], solvefun) + except NotImplementedError as detail: + failed_hints[hint] = detail + else: + pdedict[hint] = rv + pdedict.update(failed_hints) + return pdedict + + else: + return _helper_simplify(eq, hints['hint'], + hints['func'], hints['order'], hints[hints['hint']], solvefun) + +def _helper_simplify(eq, hint, func, order, match, solvefun): + """Helper function of pdsolve that calls the respective + pde functions to solve for the partial differential + equations. This minimises the computation in + calling _desolve multiple times. + """ + + if hint.endswith("_Integral"): + solvefunc = globals()[ + "pde_" + hint[:-len("_Integral")]] + else: + solvefunc = globals()["pde_" + hint] + return _handle_Integral(solvefunc(eq, func, order, + match, solvefun), func, order, hint) + +def _handle_Integral(expr, func, order, hint): + r""" + Converts a solution with integrals in it into an actual solution. + + Simplifies the integral mainly using doit() + """ + if hint.endswith("_Integral"): + return expr + + elif hint == "1st_linear_constant_coeff": + return simplify(expr.doit()) + + else: + return expr + + +def classify_pde(eq, func=None, dict=False, **kwargs): + """ + Returns a tuple of possible pdsolve() classifications for a PDE. + + The tuple is ordered so that first item is the classification that + pdsolve() uses to solve the PDE by default. In general, + classifications at the near the beginning of the list will produce + better solutions faster than those near the end, thought there are + always exceptions. To make pdsolve use a different classification, + use pdsolve(PDE, func, hint=). See also the pdsolve() + docstring for different meta-hints you can use. + + If ``dict`` is true, classify_pde() will return a dictionary of + hint:match expression terms. This is intended for internal use by + pdsolve(). Note that because dictionaries are ordered arbitrarily, + this will most likely not be in the same order as the tuple. + + You can get help on different hints by doing help(pde.pde_hintname), + where hintname is the name of the hint without "_Integral". + + See sympy.pde.allhints or the sympy.pde docstring for a list of all + supported hints that can be returned from classify_pde. + + + Examples + ======== + >>> from sympy.solvers.pde import classify_pde + >>> from sympy import Function, diff, Eq + >>> from sympy.abc import x, y + >>> f = Function('f') + >>> u = f(x, y) + >>> ux = u.diff(x) + >>> uy = u.diff(y) + >>> eq = Eq(1 + (2*(ux/u)) + (3*(uy/u))) + >>> classify_pde(eq) + ('1st_linear_constant_coeff_homogeneous',) + """ + + prep = kwargs.pop('prep', True) + + if func and len(func.args) != 2: + raise NotImplementedError("Right now only partial " + "differential equations of two variables are supported") + + if prep or func is None: + prep, func_ = _preprocess(eq, func) + if func is None: + func = func_ + + if isinstance(eq, Equality): + if eq.rhs != 0: + return classify_pde(eq.lhs - eq.rhs, func) + eq = eq.lhs + + f = func.func + x = func.args[0] + y = func.args[1] + fx = f(x,y).diff(x) + fy = f(x,y).diff(y) + + # TODO : For now pde.py uses support offered by the ode_order function + # to find the order with respect to a multi-variable function. An + # improvement could be to classify the order of the PDE on the basis of + # individual variables. + order = ode_order(eq, f(x,y)) + + # hint:matchdict or hint:(tuple of matchdicts) + # Also will contain "default": and "order":order items. + matching_hints = {'order': order} + + if not order: + if dict: + matching_hints["default"] = None + return matching_hints + else: + return () + + eq = expand(eq) + + a = Wild('a', exclude = [f(x,y)]) + b = Wild('b', exclude = [f(x,y), fx, fy, x, y]) + c = Wild('c', exclude = [f(x,y), fx, fy, x, y]) + d = Wild('d', exclude = [f(x,y), fx, fy, x, y]) + e = Wild('e', exclude = [f(x,y), fx, fy]) + n = Wild('n', exclude = [x, y]) + # Try removing the smallest power of f(x,y) + # from the highest partial derivatives of f(x,y) + reduced_eq = None + if eq.is_Add: + var = set(combinations_with_replacement((x,y), order)) + dummyvar = deepcopy(var) + power = None + for i in var: + coeff = eq.coeff(f(x,y).diff(*i)) + if coeff != 1: + match = coeff.match(a*f(x,y)**n) + if match and match[a]: + power = match[n] + dummyvar.remove(i) + break + dummyvar.remove(i) + for i in dummyvar: + coeff = eq.coeff(f(x,y).diff(*i)) + if coeff != 1: + match = coeff.match(a*f(x,y)**n) + if match and match[a] and match[n] < power: + power = match[n] + if power: + den = f(x,y)**power + reduced_eq = Add(*[arg/den for arg in eq.args]) + if not reduced_eq: + reduced_eq = eq + + if order == 1: + r = reduced_eq.match(b*fx + c*fy + d*f(x,y) + e) + if r: + if not r[e]: + ## Linear first-order homogeneous partial-differential + ## equation with constant coefficients + r.update({'b': b, 'c': c, 'd': d}) + matching_hints["1st_linear_constant_coeff_homogeneous"] = r + else: + if r[b]**2 + r[c]**2 != 0: + ## Linear first-order general partial-differential + ## equation with constant coefficients + r.update({'b': b, 'c': c, 'd': d, 'e': e}) + matching_hints["1st_linear_constant_coeff"] = r + matching_hints[ + "1st_linear_constant_coeff_Integral"] = r + + # Order keys based on allhints. + retlist = [] + for i in allhints: + if i in matching_hints: + retlist.append(i) + + if dict: + # Dictionaries are ordered arbitrarily, so make note of which + # hint would come first for pdsolve(). Use an ordered dict in Py 3. + matching_hints["default"] = None + matching_hints["ordered_hints"] = tuple(retlist) + for i in allhints: + if i in matching_hints: + matching_hints["default"] = i + break + return matching_hints + else: + return tuple(retlist) + +def checkpdesol(pde, sol, func=None, solve_for_func=True): + """ + Checks if the given solution satisfies the partial differential + equation. + + pde is the partial differential equation which can be given in the + form of an equation or an expression. sol is the solution for which + the pde is to be checked. This can also be given in an equation or + an expression form. If the function is not provided, the helper + function _preprocess from deutils is used to identify the function. + + If a sequence of solutions is passed, the same sort of container will be + used to return the result for each solution. + + The following methods are currently being implemented to check if the + solution satisfies the PDE: + + 1. Directly substitute the solution in the PDE and check. If the + solution hasn't been solved for f, then it will solve for f + provided solve_for_func hasn't been set to False. + + If the solution satisfies the PDE, then a tuple (True, 0) is returned. + Otherwise a tuple (False, expr) where expr is the value obtained + after substituting the solution in the PDE. However if a known solution + returns False, it may be due to the inability of doit() to simplify it to zero. + + Examples + ======== + >>> from sympy import Function, symbols, diff + >>> from sympy.solvers.pde import checkpdesol, pdsolve + >>> x, y = symbols('x y') + >>> f = Function('f') + >>> eq = 2*f(x,y) + 3*f(x,y).diff(x) + 4*f(x,y).diff(y) + >>> sol = pdsolve(eq) + >>> assert checkpdesol(eq, sol)[0] + >>> eq = x*f(x,y) + f(x,y).diff(x) + >>> checkpdesol(eq, sol) + (False, (x*F(4*x - 3*y) - 6*F(4*x - 3*y)/25 + 4*Subs(Derivative(F(_xi_1), _xi_1), (_xi_1,), (4*x - 3*y,)))*exp(-6*x/25 - 8*y/25)) + """ + + # Converting the pde into an equation + if not isinstance(pde, Equality): + pde = Eq(pde, 0) + + # If no function is given, try finding the function present. + if func is None: + try: + _, func = _preprocess(pde.lhs) + except ValueError: + funcs = [s.atoms(AppliedUndef) for s in ( + sol if is_sequence(sol, set) else [sol])] + funcs = reduce(set.union, funcs, set()) + if len(funcs) != 1: + raise ValueError( + 'must pass func arg to checkpdesol for this case.') + func = funcs.pop() + + # If the given solution is in the form of a list or a set + # then return a list or set of tuples. + if is_sequence(sol, set): + return type(sol)([checkpdesol(pde, i, + solve_for_func=solve_for_func) for i in sol]) + + # Convert solution into an equation + if not isinstance(sol, Equality): + sol = Eq(func, sol) + + # Try solving for the function + if solve_for_func and not (sol.lhs == func and not sol.rhs.has(func)) and not \ + (sol.rhs == func and not sol.lhs.has(func)): + try: + solved = solve(sol, func) + if not solved: + raise NotImplementedError + except NotImplementedError: + pass + else: + if len(solved) == 1: + result = checkpdesol(pde, Eq(func, solved[0]), + order=order, solve_for_func=False) + else: + result = checkpdesol(pde, [Eq(func, t) for t in solved], + order=order, solve_for_func=False) + + # The first method includes direct substitution of the solution in + # the PDE and simplifying. + pde = pde.lhs - pde.rhs + if sol.lhs == func: + s = pde.subs(func, sol.rhs).doit() + elif sol.rhs == func: + s = pde.subs(func, sol.lhs).doit() + if s: + ss = simplify(s) + if ss: + return False, ss + else: + return True, 0 + else: + return True, 0 + +def pde_1st_linear_constant_coeff_homogeneous(eq, func, order, match, solvefun): + r""" + Solves a first order linear homogeneous + partial differential equation with constant coefficients. + + The general form of this partial differential equation is + a*f(x,y).diff(x) + b*f(x,y).diff(y) + c*f(x,y) = 0 + where a, b and c are constants. + + The general solution of the differential equation, can be found + by the method of characteristics. It is given by + f(x,y) = F(b*x - a*y)*exp(-c/(a**2 + b**2)*(a*x + b*y)) + + >>> from sympy.solvers import pdsolve + >>> from sympy.abc import x, y, a, b, c + >>> from sympy import Function, pprint + >>> f = Function('f') + >>> u = f(x,y) + >>> ux = u.diff(x) + >>> uy = u.diff(y) + >>> genform = a*ux + b*uy + c*u + >>> pprint(genform) + d d + a*--(f(x, y)) + b*--(f(x, y)) + c*f(x, y) + dx dy + + >>> pprint(pdsolve(genform)) + -c*(a*x + b*y) + --------------- + 2 2 + a + b + f(x, y) = F(-a*y + b*x)*e + + Examples + ======== + + >>> from sympy.solvers.pde import ( + ... pde_1st_linear_constant_coeff_homogeneous) + >>> from sympy import pdsolve + >>> from sympy import Function, diff, pprint + >>> from sympy.abc import x,y + >>> f = Function('f') + >>> pdsolve(f(x,y) + f(x,y).diff(x) + f(x,y).diff(y)) + f(x, y) == F(x - y)*exp(-x/2 - y/2) + >>> pprint(pdsolve(f(x,y) + f(x,y).diff(x) + f(x,y).diff(y))) + x y + - - - - + 2 2 + f(x, y) = F(x - y)*e + + References + ========== + + - Viktor Grigoryan, "Partial Differential Equations" + Math 124A - Fall 2010, pp.7 + + """ + # TODO : For now homogeneous first order linear PDE's having + # two variables are implemented. Once there is support for + # solving systems of ODE's, this can be extended to n variables. + + f = func.func + x = func.args[0] + y = func.args[1] + b = match[match['b']] + c = match[match['c']] + d = match[match['d']] + return Eq(f(x,y), exp(-S(d)/(b**2 + c**2)*(b*x + c*y))*solvefun(c*x - b*y)) + +def pde_1st_linear_constant_coeff(eq, func, order, match, solvefun): + r""" + Solves a first order linear partial differential equation + with constant coefficients. + + The general form of this partial differential equation is + a*f(x,y).diff(x) + b*f(x,y).diff(y) + c*f(x,y) = G(x,y) + where a, b and c are constants and G can be an arbitrary + function in x and y. + + The general solution of the PDE is + + >>> from sympy.solvers import pdsolve + >>> from sympy.abc import x, y, a, b, c + >>> from sympy import Function, pprint + >>> f = Function('f') + >>> G = Function('G') + >>> u = f(x,y) + >>> ux = u.diff(x) + >>> uy = u.diff(y) + >>> genform = a*u + b*ux + c*uy - G(x,y) + >>> pprint(genform) + d d + a*f(x, y) + b*--(f(x, y)) + c*--(f(x, y)) - G(x, y) + dx dy + >>> pprint(pdsolve(genform, hint='1st_linear_constant_coeff_Integral')) + // b*x + c*y \ + || / | + || | | + || | a*xi | + || | ------- | + || | 2 2 | + || | /b*xi + c*eta -b*eta + c*xi\ b + c | + || | G|------------, -------------|*e d(xi)| + || | | 2 2 2 2 | | + || | \ b + c b + c / | + || | | + || / | + || | + f(x, y) = ||F(eta) + -------------------------------------------------------|* + || 2 2 | + \\ b + c / + + \| + || + || + || + || + || + || + || + || + -a*xi || + -------|| + 2 2|| + b + c || + e || + || + /|eta=-b*y + c*x, xi=b*x + c*y + + + Examples + ======== + + >>> from sympy.solvers.pde import pdsolve + >>> from sympy import Function, diff, pprint, exp + >>> from sympy.abc import x,y + >>> f = Function('f') + >>> eq = -2*f(x,y).diff(x) + 4*f(x,y).diff(y) + 5*f(x,y) - exp(x + 3*y) + >>> pdsolve(eq) + f(x, y) == (F(4*x + 2*y) + exp(x/2 + 4*y)/15)*exp(x/2 - y) + + References + ========== + + - Viktor Grigoryan, "Partial Differential Equations" + Math 124A - Fall 2010, pp.7 + + """ + + # TODO : For now homogeneous first order linear PDE's having + # two variables are implemented. Once there is support for + # solving systems of ODE's, this can be extended to n variables. + + xi, eta = symbols("xi eta") + f = func.func + x = func.args[0] + y = func.args[1] + b = match[match['b']] + c = match[match['c']] + d = match[match['d']] + e = -match[match['e']] + expterm = exp(-S(d)/(b**2 + c**2)*xi) + functerm = solvefun(eta) + solvedict = solve((b*x + c*y - xi, c*x - b*y - eta), x, y) + # Integral should remain as it is in terms of xi, + # doit() should be done in _handle_Integral. + genterm = (1/S(b**2 + c**2))*C.Integral( + (1/expterm*e).subs(solvedict), (xi, b*x + c*y)) + return Eq(f(x,y), Subs(expterm*(functerm + genterm), + (eta, xi), (c*x - b*y, b*x + c*y))) + + def pde_separate(eq, fun, sep, strategy='mul'): """Separate variables in partial differential equation either by additive or multiplicative separation approach. It tries to rewrite an equation so @@ -49,7 +676,6 @@ pde_separate_add, pde_separate_mul """ - do_add = False if strategy == 'add': do_add = True @@ -99,6 +725,7 @@ dvar = subs_args[1:] return _separate(result, svar, dvar) + def pde_separate_add(eq, fun, sep): """ Helper function for searching additive separable solutions. @@ -123,6 +750,7 @@ """ return pde_separate(eq, fun, sep, strategy='add') + def pde_separate_mul(eq, fun, sep): """ Helper function for searching multiplicative separable solutions. @@ -147,6 +775,7 @@ """ return pde_separate(eq, fun, sep, strategy='mul') + def _separate(eq, dep, others): """Separate expression into two parts based on dependencies of variables.""" diff -Nru python3-sympy-0.7.2/sympy/solvers/polysys.py python3-sympy-0.7.3/sympy/solvers/polysys.py --- python3-sympy-0.7.2/sympy/solvers/polysys.py 2012-10-17 03:02:22.000000000 +0000 +++ python3-sympy-0.7.3/sympy/solvers/polysys.py 2013-07-13 17:53:32.000000000 +0000 @@ -8,9 +8,11 @@ from sympy.simplify import rcollect from sympy.core import S + class SolveFailed(Exception): """Raised when solver's conditions weren't met. """ + def solve_poly_system(seq, *gens, **args): """ Solve a system of polynomial equations. @@ -44,6 +46,7 @@ return solve_generic(polys, opt) + def solve_biquadratic(f, g, opt): """Solve a system of two bivariate quadratic polynomial equations. @@ -63,7 +66,8 @@ >>> a = Poly(y + x**2 - 3, y, x, domain='ZZ') >>> b = Poly(-y + x - 4, y, x, domain='ZZ') >>> solve_biquadratic(a, b, NewOption) - [(-sqrt(29)/2 + 7/2, -sqrt(29)/2 - 1/2), (sqrt(29)/2 + 7/2, -1/2 + sqrt(29)/2)] + [(-sqrt(29)/2 + 7/2, -sqrt(29)/2 - 1/2), (sqrt(29)/2 + 7/2, -1/2 + \ + sqrt(29)/2)] """ G = groebner([f, g]) @@ -91,6 +95,7 @@ return sorted(solutions) + def solve_generic(polys, opt): """ Solve a generic system of polynomial equations. @@ -227,6 +232,7 @@ else: return None + def solve_triangulated(polys, *gens, **args): """ Solve a polynomial system using Gianni-Kalkbrenner algorithm. diff -Nru python3-sympy-0.7.2/sympy/solvers/recurr.py python3-sympy-0.7.3/sympy/solvers/recurr.py --- python3-sympy-0.7.2/sympy/solvers/recurr.py 2012-10-17 03:02:22.000000000 +0000 +++ python3-sympy-0.7.3/sympy/solvers/recurr.py 2013-07-13 17:53:32.000000000 +0000 @@ -56,12 +56,13 @@ from sympy.simplify import simplify, hypersimp, hypersimilar from sympy.solvers import solve, solve_undetermined_coeffs from sympy.polys import Poly, quo, gcd, lcm, roots, resultant -from sympy.functions import binomial, FallingFactorial +from sympy.functions import binomial, factorial, FallingFactorial, RisingFactorial from sympy.matrices import Matrix, casoratian from sympy.concrete import product -from sympy.utilities.misc import default_sort_key +from sympy.core.compatibility import default_sort_key from sympy.utilities.iterables import numbered_symbols + def rsolve_poly(coeffs, f, n, **hints): """Given linear recurrence operator L of order 'k' with polynomial coefficients and inhomogeneous equation Ly = f, where 'f' is a @@ -118,15 +119,15 @@ homogeneous = f.is_zero - r = len(coeffs)-1 + r = len(coeffs) - 1 coeffs = [ Poly(coeff, n) for coeff in coeffs ] - polys = [ Poly(0, n) ] * (r+1) - terms = [ (S.Zero, S.NegativeInfinity) ] *(r+1) + polys = [ Poly(0, n) ] * (r + 1) + terms = [ (S.Zero, S.NegativeInfinity) ] *(r + 1) - for i in range(0, r+1): - for j in range(i, r+1): + for i in range(0, r + 1): + for j in range(i, r + 1): polys[i] += coeffs[j]*binomial(j, i) if not polys[i].is_zero: @@ -135,7 +136,7 @@ d = b = terms[0][1] - for i in range(1, r+1): + for i in range(1, r + 1): if terms[i][1] > d: d = terms[i][1] @@ -148,7 +149,7 @@ degree_poly = S.Zero - for i in range(0, r+1): + for i in range(0, r + 1): if terms[i][1] - i == b: degree_poly += terms[i][0]*FallingFactorial(x, i) @@ -161,9 +162,9 @@ N = [] if homogeneous: - N += [-b-1] + N += [-b - 1] else: - N += [f.as_poly(n).degree() - b, -b-1] + N += [f.as_poly(n).degree() - b, -b - 1] N = int(max(N)) @@ -180,23 +181,23 @@ C = [] y = E = S.Zero - for i in range(0, N+1): - C.append(Symbol('C'+str(i))) + for i in range(0, N + 1): + C.append(Symbol('C' + str(i))) y += C[i] * n**i - for i in range(0, r+1): - E += coeffs[i].as_expr()*y.subs(n, n+i) + for i in range(0, r + 1): + E += coeffs[i].as_expr()*y.subs(n, n + i) - solutions = solve_undetermined_coeffs(E-f, C, n) + solutions = solve_undetermined_coeffs(E - f, C, n) if solutions is not None: C = [ c for c in C if (c not in solutions) ] result = y.subs(solutions) else: - return None # TBD + return None # TBD else: A = r - U = N+A+b+1 + U = N + A + b + 1 nni_roots = list(roots(polys[r], filter='Z', predicate=lambda r: r >= 0).keys()) @@ -214,27 +215,27 @@ def _delta(p, k): B = S.One - D = p.subs(n, a+k) + D = p.subs(n, a + k) - for i in range(1, k+1): - B *= -Rational(k-i+1, i) - D += B * p.subs(n, a+k-i) + for i in range(1, k + 1): + B *= -Rational(k - i + 1, i) + D += B * p.subs(n, a + k - i) return D alpha = {} - for i in range(-A, d+1): - I = _one_vector(d+1) + for i in range(-A, d + 1): + I = _one_vector(d + 1) - for k in range(1, d+1): - I[k] = I[k-1] * (x+i-k+1)/k + for k in range(1, d + 1): + I[k] = I[k - 1] * (x + i - k + 1)/k alpha[i] = S.Zero - for j in range(0, A+1): - for k in range(0, d+1): - B = binomial(k, i+j) + for j in range(0, A + 1): + for k in range(0, d + 1): + B = binomial(k, i + j) D = _delta(polys[j].as_expr(), k) alpha[i] += I[k]*B*D @@ -245,14 +246,14 @@ for i in range(A, U): v = _zero_vector(A) - for k in range(1, A+b+1): + for k in range(1, A + b + 1): if i - k < 0: break - B = alpha[k-A].subs(x, i-k) + B = alpha[k - A].subs(x, i - k) for j in range(0, A): - v[j] += B * V[i-k, j] + v[j] += B * V[i - k, j] denom = alpha[-A].subs(x, i) @@ -265,43 +266,43 @@ v = _zero_vector(A) g = S.Zero - for k in range(1, A+b+1): + for k in range(1, A + b + 1): if i - k < 0: break - B = alpha[k-A].subs(x, i-k) + B = alpha[k - A].subs(x, i - k) for j in range(0, A): - v[j] += B * V[i-k, j] + v[j] += B * V[i - k, j] - g += B * G[i-k] + g += B * G[i - k] denom = alpha[-A].subs(x, i) for j in range(0, A): V[i, j] = -v[j] / denom - G[i] = (_delta(f, i-A) - g) / denom + G[i] = (_delta(f, i - A) - g) / denom P, Q = _one_vector(U), _zero_vector(A) for i in range(1, U): - P[i] = (P[i-1] * (n-a-i+1)/i).expand() + P[i] = (P[i - 1] * (n - a - i + 1)/i).expand() for i in range(0, A): - Q[i] = Add(*[ (v*p).expand() for v, p in zip(V[:,i], P) ]) + Q[i] = Add(*[ (v*p).expand() for v, p in zip(V[:, i], P) ]) if not homogeneous: h = Add(*[ (g*p).expand() for g, p in zip(G, P) ]) - C = [ Symbol('C'+str(i)) for i in range(0, A) ] + C = [ Symbol('C' + str(i)) for i in range(0, A) ] g = lambda i: Add(*[ c*_delta(q, i) for c, q in zip(C, Q) ]) if homogeneous: - E = [ g(i) for i in range(N+1, U) ] + E = [ g(i) for i in range(N + 1, U) ] else: - E = [ g(i) + _delta(h, i) for i in range(N+1, U) ] + E = [ g(i) + _delta(h, i) for i in range(N + 1, U) ] if E != []: solutions = solve(E, *C) @@ -322,7 +323,7 @@ else: result = h - for c, q in zip(C, Q): + for c, q in list(zip(C, Q)): if c in solutions: s = solutions[c]*q C.remove(c) @@ -336,6 +337,7 @@ else: return result + def rsolve_ratio(coeffs, f, n, **hints): """Given linear recurrence operator L of order 'k' with polynomial coefficients and inhomogeneous equation Ly = f, where 'f' is a @@ -389,14 +391,14 @@ coeffs = list(map(sympify, coeffs)) - r = len(coeffs)-1 + r = len(coeffs) - 1 A, B = coeffs[r], coeffs[0] - A = A.subs(n, n-r).expand() + A = A.subs(n, n - r).expand() h = Dummy('h') - res = resultant(A, B.subs(n, n+h), n) + res = resultant(A, B.subs(n, n + h), n) if not res.is_polynomial(h): p, q = res.as_numer_denom() @@ -408,26 +410,26 @@ if not nni_roots: return rsolve_poly(coeffs, f, n, **hints) else: - C, numers = S.One, [S.Zero]*(r+1) + C, numers = S.One, [S.Zero]*(r + 1) for i in range(int(max(nni_roots)), -1, -1): - d = gcd(A, B.subs(n, n+i), n) + d = gcd(A, B.subs(n, n + i), n) A = quo(A, d, n) - B = quo(B, d.subs(n, n-i), n) + B = quo(B, d.subs(n, n - i), n) - C *= Mul(*[ d.subs(n, n-j) for j in range(0, i+1) ]) + C *= Mul(*[ d.subs(n, n - j) for j in range(0, i + 1) ]) - denoms = [ C.subs(n, n+i) for i in range(0, r+1) ] + denoms = [ C.subs(n, n + i) for i in range(0, r + 1) ] - for i in range(0, r+1): + for i in range(0, r + 1): g = gcd(coeffs[i], denoms[i], n) numers[i] = quo(coeffs[i], g, n) denoms[i] = quo(denoms[i], g, n) - for i in range(0, r+1): - numers[i] *= Mul(*(denoms[:i] + denoms[i+1:])) + for i in range(0, r + 1): + numers[i] *= Mul(*(denoms[:i] + denoms[i + 1:])) result = rsolve_poly(numers, f * Mul(*denoms), n, **hints) @@ -439,6 +441,7 @@ else: return None + def rsolve_hyper(coeffs, f, n, **hints): """Given linear recurrence operator L of order 'k' with polynomial coefficients and inhomogeneous equation Ly = f we seek for all @@ -495,7 +498,7 @@ f = sympify(f) - r, kernel = len(coeffs)-1, [] + r, kernel = len(coeffs) - 1, [] if not f.is_zero: if f.is_Add: @@ -515,7 +518,7 @@ inhomogeneous = [] for g, h in similar.items(): - inhomogeneous.append(g+h) + inhomogeneous.append(g + h) elif f.is_hypergeometric(n): inhomogeneous = [f] else: @@ -523,20 +526,20 @@ for i, g in enumerate(inhomogeneous): coeff, polys = S.One, coeffs[:] - denoms = [ S.One ] * (r+1) + denoms = [ S.One ] * (r + 1) s = hypersimp(g, n) - for j in range(1, r+1): - coeff *= s.subs(n, n+j-1) + for j in range(1, r + 1): + coeff *= s.subs(n, n + j - 1) p, q = coeff.as_numer_denom() polys[j] *= p denoms[j] = q - for j in range(0, r+1): - polys[j] *= Mul(*(denoms[:j] + denoms[j+1:])) + for j in range(0, r + 1): + polys[j] *= Mul(*(denoms[:j] + denoms[j + 1:])) R = rsolve_poly(polys, Mul(*denoms), n) @@ -551,7 +554,7 @@ Z = Dummy('Z') - p, q = coeffs[0], coeffs[r].subs(n, n-r+1) + p, q = coeffs[0], coeffs[r].subs(n, n - r + 1) p_factors = [ z for z in roots(p, n).keys() ] q_factors = [ z for z in roots(q, n).keys() ] @@ -563,20 +566,20 @@ if p.is_integer and q.is_integer and p <= q: continue else: - factors += [(n-p, n-q)] + factors += [(n - p, n - q)] - p = [ (n-p, S.One) for p in p_factors ] - q = [ (S.One, n-q) for q in q_factors ] + p = [ (n - p, S.One) for p in p_factors ] + q = [ (S.One, n - q) for q in q_factors ] factors = p + factors + q for A, B in factors: polys, degrees = [], [] - D = A*B.subs(n, n+r-1) + D = A*B.subs(n, n + r - 1) - for i in range(0, r+1): - a = Mul(*[ A.subs(n, n+j) for j in range(0, i) ]) - b = Mul(*[ B.subs(n, n+j) for j in range(i, r) ]) + for i in range(0, r + 1): + a = Mul(*[ A.subs(n, n + j) for j in range(0, i) ]) + b = Mul(*[ B.subs(n, n + j) for j in range(i, r) ]) poly = quo(coeffs[i]*a*b, D, n) polys.append(poly.as_poly(n)) @@ -586,37 +589,50 @@ d, poly = max(degrees), S.Zero - for i in range(0, r+1): + for i in range(0, r + 1): coeff = polys[i].nth(d) if coeff is not S.Zero: poly += coeff * Z**i for z in roots(poly, Z).keys(): - if not z.is_real or z.is_zero: + if z.is_zero: continue - C = rsolve_poly([ polys[i]*z**i for i in range(r+1) ], 0, n) + C = rsolve_poly([ polys[i]*z**i for i in range(r + 1) ], 0, n) if C is not None and C is not S.Zero: ratio = z * A * C.subs(n, n + 1) / B / C - K = product(simplify(ratio), (n, 0, n-1)) + ratio = simplify(ratio) + # If there is a nonnegative root in the denominator of the ratio, + # this indicates that the term y(n_root) is zero, and one should + # start the product with the term y(n_root + 1). + n0 = 0 + for n_root in list(roots(ratio.as_numer_denom()[1], n).keys()): + n0 = max(n0, n_root + 1) + K = product(ratio, (n, n0, n - 1)) + if K.has(factorial, FallingFactorial, RisingFactorial): + K = simplify(K) - if casoratian(kernel+[K], n) != 0: + if casoratian(kernel + [K], n, zero=False) != 0: kernel.append(K) symbols = numbered_symbols('C') kernel.sort(key=default_sort_key) sk = list(zip(symbols, kernel)) - for C, ker in sk: - result += C * ker + if sk: + for C, ker in sk: + result += C * ker + else: + return None if hints.get('symbols', False): return (result, [s for s, k in sk]) else: return result + def rsolve(f, y, init=None): """ Solve univariate recurrence with rational coefficients. @@ -652,17 +668,21 @@ >>> f = (n-1)*y(n+2) - (n**2+3*n-2)*y(n+1) + 2*n*(n+1)*y(n) >>> rsolve(f, y(n)) - 2**n*C0 + C1*n! + 2**n*C0 + C1*factorial(n) >>> rsolve(f, y(n), { y(0):0, y(1):3 }) - 3*2**n - 3*n! + 3*2**n - 3*factorial(n) """ if isinstance(f, Equality): f = f.lhs - f.rhs - k = Wild('k') n = y.args[0] + k = Wild('k', exclude=(n,)) + + # Preprocess user input to allow things like + # y(n) + a*(y(n + 1) + y(n - 1))/2 + f = f.expand().collect(y.func(Wild('m', integer=True))) h_part = defaultdict(lambda: S.Zero) i_part = S.Zero @@ -677,9 +697,11 @@ if result is not None: kspec = int(result[k]) else: - raise ValueError("'%s(%s+k)' expected, got '%s'" % (y.func, n, h)) + raise ValueError( + "'%s(%s+k)' expected, got '%s'" % (y.func, n, h)) else: - raise ValueError("'%s' expected, got '%s'" % (y.func, h.func)) + raise ValueError( + "'%s' expected, got '%s'" % (y.func, h.func)) else: coeff *= h @@ -698,7 +720,8 @@ if not coeff.is_polynomial(n): common = lcm(common, coeff.as_numer_denom()[1], n) else: - raise ValueError("Polynomial or rational function expected, got '%s'" % coeff) + raise ValueError( + "Polynomial or rational function expected, got '%s'" % coeff) i_numer, i_denom = i_part.as_numer_denom() @@ -718,43 +741,46 @@ K = abs(K_min) H_part = defaultdict(lambda: S.Zero) - i_part = i_part.subs(n, n+K).expand() - common = common.subs(n, n+K).expand() + i_part = i_part.subs(n, n + K).expand() + common = common.subs(n, n + K).expand() for k, coeff in h_part.items(): - H_part[k+K] = coeff.subs(n, n+K).expand() + H_part[k + K] = coeff.subs(n, n + K).expand() else: H_part = h_part K_max = max(H_part.keys()) - coeffs = [H_part[i] for i in range(K_max+1)] + coeffs = [H_part[i] for i in range(K_max + 1)] - result = rsolve_hyper(coeffs, i_part, n, symbols=True) + result = rsolve_hyper(coeffs, -i_part, n, symbols=True) if result is None: return None solution, symbols = result - if symbols and init is not None: - equations = [] + if init == {} or init == []: + init = None + if symbols and init is not None: if type(init) is list: - for i in range(0, len(init)): - eq = solution.subs(n, i) - init[i] - equations.append(eq) - else: - for k, v in init.items(): - try: - i = int(k) - except TypeError: - if k.is_Function and k.func == y.func: - i = int(k.args[0]) - else: - raise ValueError("Integer or term expected, got '%s'" % k) + init = dict([(i, init[i]) for i in range(len(init))]) + equations = [] + + for k, v in init.items(): + try: + i = int(k) + except TypeError: + if k.is_Function and k.func == y.func: + i = int(k.args[0]) + else: + raise ValueError("Integer or term expected, got '%s'" % k) + try: + eq = solution.limit(n, i) - v + except NotImplementedError: eq = solution.subs(n, i) - v - equations.append(eq) + equations.append(eq) result = solve(equations, *symbols) @@ -764,4 +790,4 @@ for k, v in result.items(): solution = solution.subs(k, v) - return (solution.expand()) / common + return solution diff -Nru python3-sympy-0.7.2/sympy/solvers/solvers.py python3-sympy-0.7.3/sympy/solvers/solvers.py --- python3-sympy-0.7.2/sympy/solvers/solvers.py 2012-10-17 03:02:22.000000000 +0000 +++ python3-sympy-0.7.3/sympy/solvers/solvers.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,4 +1,4 @@ -""" +""" This module contain solvers for all kinds of equations: - algebraic or transcendental, use solve() @@ -12,13 +12,16 @@ """ -from sympy.core.compatibility import iterable, is_sequence +from sympy.core.compatibility import (iterable, is_sequence, ordered, + default_sort_key, reduce) from sympy.utilities.exceptions import SymPyDeprecationWarning from sympy.core.sympify import sympify -from sympy.core import C, S, Add, Symbol, Wild, Equality, Dummy, Basic, Expr +from sympy.core import (C, S, Add, Symbol, Wild, Equality, Dummy, Basic, + Expr, Mul, Pow) +from sympy.core.exprtools import factor_terms from sympy.core.function import (expand_mul, expand_multinomial, expand_log, Derivative, AppliedUndef, UndefinedFunction, nfloat, - count_ops) + count_ops, Function, expand_power_exp) from sympy.core.numbers import ilcm, Float from sympy.core.relational import Relational from sympy.logic.boolalg import And, Or @@ -26,47 +29,51 @@ from sympy.functions import (log, exp, LambertW, cos, sin, tan, cot, cosh, sinh, tanh, coth, acos, asin, atan, acot, acosh, - asinh, atanh, acoth, Abs) + asinh, atanh, acoth, Abs, sign, re, im, arg, + sqrt, atan2) from sympy.functions.elementary.miscellaneous import real_root from sympy.simplify import (simplify, collect, powsimp, posify, powdenest, - nsimplify) + nsimplify, denom, logcombine) from sympy.simplify.sqrtdenest import sqrt_depth, _mexpand +from sympy.simplify.fu import TR1, hyper_as_trig from sympy.matrices import Matrix, zeros -from sympy.polys import roots, cancel, Poly, together, factor +from sympy.polys import (roots, cancel, factor, Poly, together, RootOf, + degree, PolynomialError) from sympy.functions.elementary.piecewise import piecewise_fold, Piecewise -from sympy.utilities.iterables import lazyDSU_sort from sympy.utilities.lambdify import lambdify -from sympy.utilities.misc import default_sort_key, filldedent +from sympy.utilities.misc import filldedent +from sympy.utilities.iterables import uniq + from sympy.mpmath import findroot from sympy.solvers.polysys import solve_poly_system from sympy.solvers.inequalities import reduce_inequalities -from sympy.core.compatibility import reduce - from sympy.assumptions import Q, ask from types import GeneratorType from collections import defaultdict +import warnings from functools import reduce def _ispow(e): """Return True if e is a Pow or is exp.""" - return e.is_Pow or e.func is exp + return isinstance(e, Expr) and (e.is_Pow or e.func is exp) def denoms(eq, symbols=None): """Return (recursively) set of all denominators that appear in eq that contain any symbol in iterable ``symbols``; if ``symbols`` is - None (default) then all denominators with symbols will be returned. + None (default) then all denominators will be returned. Examples ======== >>> from sympy.solvers.solvers import denoms >>> from sympy.abc import x, y, z + >>> from sympy import sqrt >>> denoms(x/y) set([y]) @@ -76,21 +83,27 @@ >>> denoms(3/x + y/z) set([x, z]) + + >>> denoms(x/2 + y/z) + set([2, z]) """ - symbols = symbols or eq.free_symbols + pot = preorder_traversal(eq) dens = set() - if not symbols or not eq.has(*symbols): + for p in pot: + den = denom(p) + if den is S.One: + continue + for d in Mul.make_args(den): + dens.add(d) + if not symbols: return dens - pt = preorder_traversal(eq) - for e in pt: - if _ispow(e): - n, d = e.as_numer_denom() - if d in dens: - pt.skip() - elif d.has(*symbols): - dens.add(d.as_base_exp()[0]) - return dens + rv = [] + for d in dens: + free = d.free_symbols + if any(s in free for s in symbols): + rv.append(d) + return set(rv) def checksol(f, symbol, sol=None, **flags): @@ -107,30 +120,36 @@ Examples ======== - >>> from sympy import symbols - >>> from sympy.solvers import checksol - >>> x, y = symbols('x,y') - >>> checksol(x**4-1, x, 1) - True - >>> checksol(x**4-1, x, 0) - False - >>> checksol(x**2 + y**2 - 5**2, {x:3, y: 4}) - True + >>> from sympy import symbols + >>> from sympy.solvers import checksol + >>> x, y = symbols('x,y') + >>> checksol(x**4 - 1, x, 1) + True + >>> checksol(x**4 - 1, x, 0) + False + >>> checksol(x**2 + y**2 - 5**2, {x: 3, y: 4}) + True + + To check if an expression is zero using checksol, pass it + as ``f`` and send an empty dictionary for ``symbol``: - None is returned if checksol() could not conclude. + >>> checksol(x**2 + x - x*(x + 1), {}) + True - flags: - 'numerical=True (default)' - do a fast numerical check if ``f`` has only one symbol. - 'minimal=True (default is False)' - a very fast, minimal testing. - 'warn=True (default is False)' - print a warning if checksol() could not conclude. - 'simplify=True (default)' - simplify solution before substituting into function and - simplify the function before trying specific simplifications - 'force=True (default is False)' - make positive all symbols without assumptions regarding sign. + None is returned if checksol() could not conclude. + + flags: + 'numerical=True (default)' + do a fast numerical check if ``f`` has only one symbol. + 'minimal=True (default is False)' + a very fast, minimal testing. + 'warn=True (default is False)' + show a warning if checksol() could not conclude. + 'simplify=True (default)' + simplify solution before substituting into function and + simplify the function before trying specific simplifications + 'force=True (default is False)' + make positive all symbols without assumptions regarding sign. """ @@ -152,7 +171,7 @@ continue if check is False: return False - rv = None # don't return, wait to see if there's a False + rv = None # don't return, wait to see if there's a False return rv if isinstance(f, Poly): @@ -163,7 +182,7 @@ if not f: return True - if not f.has(*list(sol.keys())): + if sol and not f.has(*list(sol.keys())): # if f(y) == 0, x=3 does not set f(y) to zero...nor does it not return None @@ -261,11 +280,11 @@ elif val.is_Rational: return val == 0 if numerical and not val.free_symbols: - return abs(val.n(chop=True)) < 1e-9 + return abs(val.n(18).n(12, chop=True)) < 1e-9 was = val if flags.get('warn', False): - print(("\n\tWarning: could not verify solution %s." % sol)) + warnings.warn("\n\tWarning: could not verify solution %s." % sol) # returns None if it can't conclude # TODO: improve solution testing @@ -308,25 +327,12 @@ for key, expected in assumptions.items(): if expected is None: continue - if expected in [0, 1]: - expected = bool(expected) - if not isinstance(expected, bool): - raise ValueError(_filldendent(''' - A boolean is expected for %s but got %s.''' % (key, expected))) - if hasattr(Q, key): - test = ask(getattr(Q, key)(expr)) - if test is expected: - continue - elif test is not None: - return False - # ask() can't conclude. Try using old assumption system. - # XXX: remove once transition to new assumption system is finished. test = getattr(expr, 'is_' + key, None) if test is expected: continue elif test is not None: return False - result = None # Can't conclude, unless an other test fails. + result = None # Can't conclude, unless an other test fails. return result @@ -349,8 +355,8 @@ - a Relational expression or boolean - iterable of one or more of the above - * symbols (Symbol, Function or Derivative) specified as - - none given (all free symbols will be used) + * symbols (object(s) to solve for) specified as + - none given (other non-numeric objects will be used) - single symbol - denested list of symbols e.g. solve(f, x, y) @@ -375,7 +381,7 @@ 'minimal=True (default is False)' a very fast, minimal testing. 'warning=True (default is False)' - print a warning if checksol() could not conclude. + show a warning if checksol() could not conclude. 'simplify=True (default)' simplify all but cubic and quartic solutions before returning them and (if check is not False) use the @@ -398,6 +404,13 @@ other functions that contain that pattern; this is only needed if the pattern is inside of some invertible function like cos, exp, .... + 'minimal=True (default is False)' + instructs solve to try to find a particular solution to a linear + system with as many zeros as possible; this is very expensive + 'quick=True (default is False)' + when using minimal=True, use a fast heuristic instead to find a + solution with many zeros (instead of using the very slow method + guaranteed to find the largest number of zeros possible) Examples ======== @@ -435,10 +448,10 @@ [3] >>> solve(Poly(x - 3), x) [3] - >>> set(solve(x**2 - y**2, x)) - set([-y, y]) - >>> set(solve(x**4 - 1, x)) - set([-1, 1, -I, I]) + >>> solve(x**2 - y**2, x, set=True) + ([x], set([(-y,), (y,)])) + >>> solve(x**4 - 1, x, set=True) + ([x], set([(-1,), (1,), (-I,), (I,)])) * single expression with no symbol that is in the expression @@ -451,22 +464,24 @@ In this case, all free symbols will be selected as potential symbols to solve for. If the equation is univariate then a list - of solutionsis returned; otherwise -- as is the case when symbols are + of solutions is returned; otherwise -- as is the case when symbols are given as an iterable of length > 1 -- a list of mappings will be returned. >>> solve(x - 3) [3] - >>> solve(x**2 - y**2) # doctest: +SKIP - [{x: -y}, {x: y}] - >>> solve(z**2*x**2 - z**2*y**2) # doctest: +SKIP + >>> solve(x**2 - y**2) [{x: -y}, {x: y}] + >>> solve(z**2*x**2 - z**2*y**2) + [{x: -y}, {x: y}, {z: 0}] >>> solve(z**2*x - z**2*y**2) - [{x: y**2}] + [{x: y**2}, {z: 0}] - * when a Function or Derivative is given as a symbol, it is - isolated algebraically and an implicit solution may be obtained; - to obtain the solution for a function within a derivative, use - dsolve. + * when an object other than a Symbol is given as a symbol, it is + isolated algebraically and an implicit solution may be obtained. + This is mostly provided as a convenience to save one from replacing + the object with a Symbol and solving for that Symbol. It will only + work if the specified object can be replaced with a Symbol using the + subs method. >>> solve(f(x) - x, f(x)) [x] @@ -474,8 +489,14 @@ [x + f(x)] >>> solve(f(x).diff(x) - f(x) - x, f(x)) [-x + Derivative(f(x), x)] - >>> set(solve(x + exp(x)**2, exp(x))) - set([-sqrt(-x), sqrt(-x)]) + >>> solve(x + exp(x)**2, exp(x), set=True) + ([exp(x)], set([(-sqrt(-x),), (sqrt(-x),)])) + + >>> from sympy import Indexed, IndexedBase, Tuple, sqrt + >>> A = IndexedBase('A') + >>> eqs = Tuple(A[1] + A[2] - 3, A[1] - A[2] + 1) + >>> solve(eqs, eqs.atoms(Indexed)) + {A[1]: 1, A[2]: 2} * To solve for a *symbol* implicitly, use 'implicit=True': @@ -484,6 +505,36 @@ >>> solve(x + exp(x), x, implicit=True) [-exp(x)] + * It is possible to solve for anything that can be targeted with + subs: + + >>> solve(x + 2 + sqrt(3), x + 2) + [-sqrt(3)] + >>> solve((x + 2 + sqrt(3), x + 4 + y), y, x + 2) + {y: -2 + sqrt(3), x + 2: -sqrt(3)} + + * Nothing heroic is done in this implicit solving so you may end up + with a symbol still in the solution: + + >>> eqs = (x*y + 3*y + sqrt(3), x + 4 + y) + >>> solve(eqs, y, x + 2) + {y: -sqrt(3)/(x + 3), x + 2: (-2*x - 6 + sqrt(3))/(x + 3)} + >>> solve(eqs, y*x, x) + {x: -y - 4, x*y: -3*y - sqrt(3)} + + * if you attempt to solve for a number remember that the number + you have obtained does not necessarily mean that the value is + equivalent to the expression obtained: + + >>> solve(sqrt(2) - 1, 1) + [sqrt(2)] + >>> solve(x - y + 1, 1) # /!\ -1 is targeted, too + [x/(y - 1)] + >>> [_.subs(z, -1) for _ in solve((x - y + 1).subs(-1, z), 1)] + [-x + y] + + * To solve for a function within a derivative, use dsolve. + * single expression and more than 1 symbol * when there is a linear solution @@ -502,17 +553,17 @@ * that are nonlinear - >>> set(solve((a + b)*x - b**2 + 2, a, b)) - set([(-sqrt(2), sqrt(2)), (sqrt(2), -sqrt(2))]) + >>> solve((a + b)*x - b**2 + 2, a, b, set=True) + ([a, b], set([(-sqrt(2), sqrt(2)), (sqrt(2), -sqrt(2))])) * if there is no linear solution then the first successful attempt for a nonlinear solution will be returned - >>> solve(x**2 - y**2, x, y) # doctest: +SKIP + >>> solve(x**2 - y**2, x, y) [{x: -y}, {x: y}] >>> solve(x**2 - y**2/exp(x), x, y) [{x: 2*LambertW(y/2)}] - >>> solve(x**2 - y**2/exp(x), y, x) # doctest: +SKIP + >>> solve(x**2 - y**2/exp(x), y, x) [{y: -x*exp(x/2)}, {y: x*exp(x/2)}] * iterable of one or more of the above @@ -544,8 +595,8 @@ * when the system is not linear - >>> set(solve([x**2 + y -2, y**2 - 4], x, y)) - set([(-2, -2), (0, 2), (2, -2)]) + >>> solve([x**2 + y -2, y**2 - 4], x, y, set=True) + ([x, y], set([(-2, -2), (0, 2), (2, -2)])) * if no symbols are given, all free symbols will be selected and a list of mappings returned @@ -573,15 +624,15 @@ then use the check=False option: >>> from sympy import sin, limit - >>> solve(sin(x)/x) - [] + >>> solve(sin(x)/x) # 0 is excluded + [pi] If check=False then a solution to the numerator being zero is found: x = 0. In this case, this is a spurious solution since sin(x)/x has the well known limit (without dicontinuity) of 1 at x = 0: >>> solve(sin(x)/x, check=False) - [0] + [0, pi] In the following case, however, the limit exists and is equal to the the value of x = 0 that is excluded when check=True: @@ -632,18 +683,54 @@ f[i] = fi.as_expr() elif isinstance(fi, bool) or fi.is_Relational: return reduce_inequalities(f, assume=flags.get('assume'), - symbols=symbols) + symbols=symbols) + # Any embedded piecewise functions need to be brought out to the # top level so that the appropriate strategy gets selected. - f[i] = piecewise_fold(f[i]) + # However, this is necessary only if one of the piecewise + # functions depends on one of the symbols we are solving for. + def _has_piecewise(e): + if e.is_Piecewise: + return e.has(*symbols) + return any([_has_piecewise(a) for a in e.args]) + if _has_piecewise(f[i]): + f[i] = piecewise_fold(f[i]) + + # if we have a Matrix, we need to iterate over its elements again + if f[i].is_Matrix: + bare_f = False + f.extend(list(f[i])) + f[i] = S.Zero + + # if we can split it into real and imaginary parts then do so + freei = f[i].free_symbols + if freei and all(s.is_real or s.is_imaginary for s in freei): + fr, fi = f[i].as_real_imag() + if fr and fi and not any(i.has(re, im, arg) for i in (fr, fi)): + if bare_f: + bare_f = False + f[i: i + 1] = [fr, fi] # preprocess symbol(s) ########################################################################### if not symbols: - # get symbols from equations or supply dummy symbols so solve(3) - # behaves like solve(3, x). - symbols = reduce(set.union, [fi.free_symbols or set([Dummy()]) + # get symbols from equations + symbols = reduce(set.union, [fi.free_symbols for fi in f], set()) + if len(symbols) < len(f): + for fi in f: + pot = preorder_traversal(fi) + for p in pot: + if not (p.is_number or p.is_Add or p.is_Mul) or \ + isinstance(p, AppliedUndef): + flags['dict'] = True # better show symbols + symbols.add(p) + pot.skip() # don't go any deeper + symbols = list(symbols) + # supply dummy symbols so solve(3) behaves like solve(3, x) + for i in range(len(f) - len(symbols)): + symbols.append(Dummy()) + ordered_symbols = False elif len(symbols) == 1 and iterable(symbols[0]): symbols = symbols[0] @@ -656,33 +743,51 @@ exclude = reduce(set.union, [e.free_symbols for e in sympify(exclude)]) symbols = [s for s in symbols if s not in exclude] + # real/imag handling + for i, fi in enumerate(f): + _abs = [a for a in fi.atoms(Abs) if a.has(*symbols)] + fi = f[i] = fi.xreplace(dict(list(zip(_abs, + [sqrt(a.args[0]**2) for a in _abs])))) + _arg = [a for a in fi.atoms(arg) if a.has(*symbols)] + f[i] = fi.xreplace(dict(list(zip(_arg, + [atan(im(a.args[0])/re(a.args[0])) for a in _arg])))) + # see if re(s) or im(s) appear + irf = [] + for s in symbols: + # if s is real or complex then re(s) or im(s) will not appear in the equation; + if s.is_real or s.is_complex: + continue + # if re(s) or im(s) appear, the auxiliary equation must be present + irs = re(s), im(s) + if any(_f.has(i) for _f in f for i in irs): + symbols.extend(irs) + irf.append((s, re(s) + S.ImaginaryUnit*im(s))) + if irf: + for s, rhs in irf: + for i, fi in enumerate(f): + f[i] = fi.xreplace({s: rhs}) + if bare_f: + bare_f = False + flags['dict'] = True + f.extend(s - rhs for s, rhs in irf) + # end of real/imag handling + + symbols = list(uniq(symbols)) if not ordered_symbols: # we do this to make the results returned canonical in case f # contains a system of nonlinear equations; all other cases should # be unambiguous symbols = sorted(symbols, key=default_sort_key) - # we can solve for Function and Derivative instances by replacing them - # with Dummy symbols or functions + # we can solve for non-symbol entities by replacing them with Dummy symbols symbols_new = [] symbol_swapped = False - funcs = [] for i, s in enumerate(symbols): if s.is_Symbol: s_new = s - elif s.is_Function: - symbol_swapped = True - s_new = Dummy('F%d' % i) - funcs.append(s) - elif s.is_Derivative: - symbol_swapped = True - s_new = Dummy('D%d' % i) - elif s.is_Pow: - symbol_swapped = True - s_new = Dummy('P%d' % i) else: - msg = 'expected Symbol, Function, Power or Derivative but got %s' - raise TypeError(msg % type(s)) + symbol_swapped = True + s_new = Dummy('X%d' % i) symbols_new.append(s_new) if symbol_swapped: @@ -698,7 +803,7 @@ # get rid of equations that have no symbols of interest; we don't # try to solve them because the user didn't ask and they might be - # hard to solve; this means that solutions may be give in terms + # hard to solve; this means that solutions may be given in terms # of the eliminated equations e.g. solve((x-y, y-3), x) -> {x: y} newf = [] for fi in f: @@ -727,8 +832,8 @@ return [] ok = True else: - if fi.is_constant(): - ok = True + if fi.is_constant(): + ok = True if ok: newf.append(fi) if not newf: @@ -747,12 +852,11 @@ if isinstance(p, bool) or isinstance(p, Piecewise): pass elif (isinstance(p, bool) or - not p.args or - p in symset or - p.is_Add or p.is_Mul or - p.is_Pow and not implicit or - p.is_Function and not isinstance(p, AppliedUndef) and - not implicit): + not p.args or + p in symset or + p.is_Add or p.is_Mul or + p.is_Pow and not implicit or + p.is_Function and not implicit): continue elif not p in seen: seen.add(p) @@ -764,6 +868,7 @@ del seen non_inverts = dict(list(zip(non_inverts, [Dummy() for d in non_inverts]))) f = [fi.subs(non_inverts) for fi in f] + non_inverts = [(v, k.subs(swap_sym)) for k, v in non_inverts.items()] # rationalize Floats @@ -785,12 +890,12 @@ # # postprocessing ########################################################################### - # Restore masked off derivatives + # Restore masked-off objects if non_inverts: def _do_dict(solution): return dict([(k, v.subs(non_inverts)) for k, v in - solution.items()]) + solution.items()]) for i in range(1): if type(solution) is dict: solution = _do_dict(solution) @@ -812,7 +917,7 @@ raise NotImplementedError(filldedent(''' no handling of %s was implemented''' % solution)) - # Restore original Functions and Derivatives if a dictionary is returned. + # Restore original "symbols" if a dictionary is returned. # This is not necessary for # - the single univariate equation case # since the symbol will have been removed from the solution; @@ -822,13 +927,15 @@ # ** unless there were Derivatives with the symbols, but those were handled # above. if symbol_swapped: + symbols = [swap_sym[k] for k in symbols] if type(solution) is dict: solution = dict([(swap_sym[k], v.subs(swap_sym)) - for k, v in solution.items()]) + for k, v in solution.items()]) elif solution and type(solution) is list and type(solution[0]) is dict: for i, sol in enumerate(solution): solution[i] = dict([(swap_sym[k], v.subs(swap_sym)) for k, v in sol.items()]) + # undo the dictionary solutions returned when the system was only partially # solved with poly-system if all symbols are present if ( @@ -837,7 +944,7 @@ type(solution) is not dict and type(solution[0]) is dict and all(s in solution[0] for s in symbols) - ): + ): solution = [tuple([r[s].subs(r) for s in symbols]) for r in solution] # Get assumptions about symbols, to filter solutions. @@ -852,8 +959,8 @@ if check and solution: warning = flags.get('warn', False) - got_None = [] # solutions for which one or more symbols gave None - no_False = [] # solutions for which no symbols gave False + got_None = [] # solutions for which one or more symbols gave None + no_False = [] # solutions for which no symbols gave False if type(solution) is list: if type(solution[0]) is tuple: for sol in solution: @@ -879,7 +986,7 @@ no_False.append(sol) if a_None: got_None.append(sol) - else: # list of expressions + else: # list of expressions for sol in solution: test = check_assumptions(sol, **symbols[0].assumptions0) if test is False: @@ -906,20 +1013,20 @@ elif isinstance(solution, (Relational, And, Or)): assert len(symbols) == 1 if warning and symbols[0].assumptions0: - print((filldedent(""" + warnings.warn(filldedent(""" \tWarning: assumptions about variable '%s' are - not handled currently.""" %symbols[0]))) + not handled currently.""" % symbols[0])) # TODO: check also variable assumptions for inequalities else: - raise TypeError('Unrecognized solution') # improve the checker + raise TypeError('Unrecognized solution') # improve the checker solution = no_False if warning and got_None: - print((filldedent(""" + warnings.warn(filldedent(""" \tWarning: assumptions concerning following solution(s) can't be checked:""" + '\n\t' + - ', '.join(str(s) for s in got_None)))) + ', '.join(str(s) for s in got_None))) # # done @@ -935,7 +1042,7 @@ if not as_dict and not as_set: return solution or [] - # make return a list of mappings or [] + # return a list of mappings or [] if not solution: solution = [] else: @@ -979,23 +1086,36 @@ return soln # find first successful solution failed = [] + got_s = set([]) + result = [] for s in symbols: n, d = solve_linear(f, symbols=[s]) if n.is_Symbol: # no need to check but we should simplify if desired if flags.get('simplify', True): d = simplify(d) - return [{n: d}] - elif n and d: # otherwise there was no solution for s + if got_s and any([ss in d.free_symbols for ss in got_s]): + # sol depends on previously solved symbols: discard it + continue + got_s.add(n) + result.append({n: d}) + elif n and d: # otherwise there was no solution for s failed.append(s) if not failed: - return [] + return result for s in failed: try: soln = _solve(f, s, **flags) - return [{s: sol} for sol in soln] + for sol in soln: + if got_s and any([ss in sol.free_symbols for ss in got_s]): + # sol depends on previously solved symbols: discard it + continue + got_s.add(s) + result.append({s: sol}) except NotImplementedError: continue + if got_s: + return result else: msg = "No algorithms are implemented to solve equation %s" raise NotImplementedError(msg % f) @@ -1019,25 +1139,30 @@ elif f.is_Piecewise: result = set() - for expr, cond in f.args: - candidates = _solve(expr, *symbols) - if cond is True: - # Only include solutions that do not match the condition - # of any of the other pieces. - for candidate in candidates: + for n, (expr, cond) in enumerate(f.args): + candidates = _solve(expr, *symbols, **flags) + + for candidate in candidates: + if candidate in result: + continue + cond = cond is True or cond.subs(symbol, candidate) + if cond is not False: + # Only include solutions that do not match the condition + # of any previous pieces. matches_other_piece = False - for other_expr, other_cond in f.args: - if other_cond is True: + for other_n, (other_expr, other_cond) in enumerate(f.args): + if other_n == n: + break + if other_cond is False: continue - if bool(other_cond.subs(symbol, candidate)): + if other_cond.subs(symbol, candidate) is True: matches_other_piece = True break if not matches_other_piece: - result.add(candidate) - else: - for candidate in candidates: - if bool(cond.subs(symbol, candidate)): - result.add(candidate) + result.add(Piecewise( + (candidate, cond is True or cond.doit()), + (S.NaN, True) + )) check = False else: # first see if it really depends on symbol and whether there @@ -1051,160 +1176,207 @@ sol = simplify(sol) return [sol] - result = False # no solution was obtained - msg = '' # there is no failure message - dens = denoms(f, symbols) # store these for checking later + result = False # no solution was obtained + msg = '' # there is no failure message + dens = denoms(f, symbols) # store these for checking later # Poly is generally robust enough to convert anything to # a polynomial and tell us the different generators that it # contains, so we will inspect the generators identified by # polys to figure out what to do. - poly = Poly(f_num) - if poly is None: - raise ValueError('could not convert %s to Poly' % f_num) - gens = [g for g in poly.gens if g.has(symbol)] - - if len(gens) > 1: - # If there is more than one generator, it could be that the - # generators have the same base but different powers, e.g. - # >>> Poly(exp(x)+1/exp(x)) - # Poly(exp(-x) + exp(x), exp(-x), exp(x), domain='ZZ') - # >>> Poly(sqrt(x)+sqrt(sqrt(x))) - # Poly(sqrt(x) + x**(1/4), sqrt(x), x**(1/4), domain='ZZ') - # If the exponents are Rational then a change of variables - # will make this a polynomial equation in a single base. - - def _as_base_q(x): - """Return (b**e, q) for x = b**(p*e/q) where p/q is the leading - Rational of the exponent of x, e.g. exp(-2*x/3) -> (exp(x), 3) - """ - b, e = x.as_base_exp() - if e.is_Rational: - return b, e.q - if not e.is_Mul: + + # but first remove radicals as this will help Polys + if flags.pop('unrad', True): + try: + # try remove all... + u = unrad(f_num) + except ValueError: + # ...else hope for the best while letting some remain + try: + u = unrad(f, symbol) + except ValueError: + u = None # hope for best with original equation + if u: + flags['unrad'] = False # don't unrad next time + eq, cov, dens2 = u + dens.update(dens2) + if cov: + if len(cov) > 1: + raise NotImplementedError('Not sure how to handle this.') + isym, ieq = cov[0] + # since cov is written in terms of positive symbols, set + # check to False or else 0 would be excluded; the solution + # will be checked below + absent = Dummy() + check = flags.get('check', absent) + flags['check'] = False + sol = _solve(eq, isym, **flags) + inv = _solve(ieq, symbol, **flags) + result = [] + for s in sol: + for i in inv: + result.append(i.subs(isym, s)) + if check == absent: + flags.pop('check') + else: + flags['check'] = check + else: + result = _solve(eq, symbol, **flags) + + if result is False: + # rewrite hyperbolics in terms of exp + f_num = f_num.replace(lambda w: isinstance(w, C.HyperbolicFunction), + lambda w: w.rewrite(exp)) + + poly = Poly(f_num) + if poly is None: + raise ValueError('could not convert %s to Poly' % f_num) + gens = [g for g in poly.gens if g.has(symbol)] + + if len(gens) > 1: + # If there is more than one generator, it could be that the + # generators have the same base but different powers, e.g. + # >>> Poly(exp(x)+1/exp(x)) + # Poly(exp(-x) + exp(x), exp(-x), exp(x), domain='ZZ') + # >>> Poly(sqrt(x)+sqrt(sqrt(x))) + # Poly(sqrt(x) + x**(1/4), sqrt(x), x**(1/4), domain='ZZ') + # If the exponents are Rational then a change of variables + # will make this a polynomial equation in a single base. + + def _as_base_q(x): + """Return (b**e, q) for x = b**(p*e/q) where p/q is the leading + Rational of the exponent of x, e.g. exp(-2*x/3) -> (exp(x), 3) + """ + b, e = x.as_base_exp() + if e.is_Rational: + return b, e.q + if not e.is_Mul: + return x, 1 + c, ee = e.as_coeff_Mul() + if c.is_Rational and c is not S.One: # c could be a Float + return b**ee, c.q return x, 1 - c, ee = e.as_coeff_Mul() - if c.is_Rational and c is not S.One: # c could be a Float - return b**ee, c.q - return x, 1 - - bases, qs = list(zip(*[_as_base_q(g) for g in gens])) - bases = set(bases) - - if len(bases) > 1: - funcs = set(b.func for b in bases if b.is_Function) - - trig = set([cos, sin, tan, cot]) - other = funcs - trig - if not other and len(funcs.intersection(trig)) > 1: - return _solve(f_num.rewrite(tan), symbol, **flags) - - trigh = set([cosh, sinh, tanh, coth]) - other = funcs - trigh - if not other and len(funcs.intersection(trigh)) > 1: - return _solve(f_num.rewrite(tanh), symbol, **flags) - - # just a simple case - see if replacement of single function - # clears all symbol-dependent functions, e.g. - # log(x) - log(log(x) - 1) - 3 can be solved even though it has - # two generators. - - funcs = [f for f in bases if f.is_Function] - if funcs: - funcs.sort(key=count_ops) # put shallowest function first - f1 = funcs[0] - t = Dummy('t') - # perform the substitution - ftry = f_num.subs(f1, t) - # if no Functions left, we can proceed with usual solve - if not ftry.has(symbol): - cv_sols = _solve(ftry, t) - cv_inv = _solve(t - f1, symbol)[0] - sols = list() - for sol in cv_sols: - sols.append(cv_inv.subs(t, sol)) - return sols - - msg = 'multiple generators %s' % gens - - elif any(q != 1 for q in qs): - # e.g. for x**(1/2) + x**(1/4) a change of variables - # can be made using p**4 to give p**2 + p - base = bases.pop() - m = reduce(ilcm, qs) - p = Dummy('p', positive=True) - cov = p**m - fnew = f_num.subs(base, cov) - poly = Poly(fnew, p) # we now have a single generator, p - - # for cubics and quartics, if the flag wasn't set, DON'T do it - # by default since the results are quite long. Perhaps one - # could base this decision on a certain critical length of the - # roots. - if poly.degree() > 2: - flags['simplify'] = flags.get('simplify', False) - - soln = list(roots(poly, cubics=True, quartics=True).keys()) - if not soln: - soln = poly.all_roots() - check = False # RootOf instances can not be checked - - # We now know what the values of p are equal to. Now find out - # how they are related to the original x, e.g. if p**2 = cos(x) - # then x = acos(p**2) - # - inversion = _solve(cov - base, symbol, **flags) - result = [i.subs(p, s) for i in inversion for s in soln] + bases, qs = list(zip(*[_as_base_q(g) for g in gens])) + bases = set(bases) - else: # len(bases) == 1 and all(q == 1 for q in qs): - # e.g. case where gens are exp(x), exp(-x) - u = bases.pop() - t = Dummy('t') - inv = _solve(u - t, symbol) - ftry = f_num.subs(u, t) - if not ftry.has(symbol): - soln = _solve(ftry, t) - sols = list() - for sol in soln: - for i in inv: - sols.append(i.subs(t, sol)) - return sols + if len(bases) > 1: + funcs = set(b for b in bases if b.is_Function) + + trig = set([_ for _ in funcs if + isinstance(_, C.TrigonometricFunction)]) + other = funcs - trig + if not other and len(funcs.intersection(trig)) > 1: + newf = TR1(f_num).rewrite(tan) + if newf != f_num: + return _solve(newf, symbol, **flags) + + # just a simple case - see if replacement of single function + # clears all symbol-dependent functions, e.g. + # log(x) - log(log(x) - 1) - 3 can be solved even though it has + # two generators. + + if funcs: + funcs = list(ordered(funcs)) # put shallowest function first + f1 = funcs[0] + t = Dummy() + # perform the substitution + ftry = f_num.subs(f1, t) + + # if no Functions left, we can proceed with usual solve + if not ftry.has(symbol): + cv_sols = _solve(ftry, t, **flags) + cv_inv = _solve(t - f1, symbol, **flags)[0] + sols = list() + for sol in cv_sols: + sols.append(cv_inv.subs(t, sol)) + return list(ordered(sols)) + + msg = 'multiple generators %s' % gens + + else: # len(bases) == 1 and all(q == 1 for q in qs): + # e.g. case where gens are exp(x), exp(-x) + u = bases.pop() + t = Dummy('t') + inv = _solve(u - t, symbol, **flags) + if isinstance(u, (Pow, exp)): + # this will be resolved by factor in _tsolve but we might + # as well try a simple expansion here to get things in + # order so something like the following will work now without + # having to factor: + # >>> eq = (exp(I*(-x-2))+exp(I*(x+2))) + # >>> eq.subs(exp(x),y) # fails + # exp(I*(-x - 2)) + exp(I*(x + 2)) + # >>> eq.expand().subs(exp(x),y) # works + # y**I*exp(2*I) + y**(-I)*exp(-2*I) + def _expand(p): + b, e = p.as_base_exp() + e = expand_mul(e) + return expand_power_exp(b**e) + ftry = f_num.replace( + lambda w: w.is_Pow or isinstance(w, exp), + _expand).subs(u, t) + if not ftry.has(symbol): + soln = _solve(ftry, t, **flags) + sols = list() + for sol in soln: + for i in inv: + sols.append(i.subs(t, sol)) + return list(ordered(sols)) + + elif len(gens) == 1: + + # There is only one generator that we are interested in, but there + # may have been more than one generator identified by polys (e.g. + # for symbols other than the one we are interested in) so recast + # the poly in terms of our generator of interest. - elif len(gens) == 1: + if len(poly.gens) > 1: + poly = Poly(poly, gens[0]) - # There is only one generator that we are interested in, but there - # may have been more than one generator identified by polys (e.g. - # for symbols other than the one we are interested in) so recast - # the poly in terms of our generator of interest. - - if len(poly.gens) > 1: - poly = Poly(poly, gens[0]) - - # if we haven't tried tsolve yet, do so now - if not flags.pop('tsolve', False): - # for cubics and quartics, if the flag wasn't set, DON'T do it - # by default since the results are quite long. Perhaps one - # could base this decision on a certain critical length of the - # roots. - if poly.degree() > 2: - flags['simplify'] = flags.get('simplify', False) - soln = list(roots(poly, cubics=True, quartics=True).keys()) - if not soln: - soln = poly.all_roots() - check = False # RootOf instances can not be checked - gen = poly.gen - if gen != symbol: - u = Dummy() + # if we aren't on the tsolve-pass, use roots + if not flags.pop('tsolve', False): flags['tsolve'] = True - inversion = _solve(gen - u, symbol, **flags) - soln = list(set([i.subs(u, s) for i in - inversion for s in soln])) - result = soln + if poly.degree() == 1 and ( + poly.gen.is_Pow and + poly.gen.exp.is_Rational and + not poly.gen.exp.is_Integer): + pass + else: + # for cubics and quartics, if the flag wasn't set, DON'T do it + # by default since the results are quite long. Perhaps one + # could base this decision on a certain critical length of the + # roots. + deg = poly.degree() + if deg > 2: + flags['simplify'] = flags.get('simplify', False) + soln = list(roots(poly, cubics=True, quartics=True, + quintics=True).keys()) + + if len(soln) < deg: + try: + # get all_roots if possible + soln = list(ordered(uniq(poly.all_roots()))) + except NotImplementedError: + pass + gen = poly.gen + if gen != symbol: + u = Dummy() + inversion = _solve(gen - u, symbol, **flags) + soln = list(ordered(set([i.subs(u, s) for i in + inversion for s in soln]))) + result = soln + # fallback if above fails if result is False: - result = _tsolve(f_num, symbol, **flags) + + # allow tsolve to be used on next pass if needed + flags.pop('tsolve', None) + try: + result = _tsolve(f_num, symbol, **flags) + except PolynomialError: + result = None if result is None: result = False @@ -1218,15 +1390,14 @@ # False so the simplification doesn't happen again in checksol() flags['simplify'] = False - if check: # reject any result that makes any denom. affirmatively 0; # if in doubt, keep it - result = [s for s in result if - all(not checksol(den, {symbol: s}, **flags) + result = [s for s in result if isinstance(s, RootOf) or + all(not checksol(den, {symbol: s}, **flags) for den in dens)] # keep only results if the check is not False - result = [r for r in result if + result = [r for r in result if isinstance(r, RootOf) or checksol(f_num, {symbol: r}, **flags) is not False] return result @@ -1273,7 +1444,10 @@ matrix[i, m] = -coeff # returns a dictionary ({symbols: values}) or None - result = solve_linear_system(matrix, *symbols, **flags) + if flags.pop('minimal', False): + result = minsolve_linear_system(matrix, *symbols, **flags) + else: + result = solve_linear_system(matrix, *symbols, **flags) if result: # it doesn't need to be checked but we need to see # that it didn't set any denominators to 0 @@ -1286,22 +1460,35 @@ solved_syms = [] else: - if len(symbols) != len(polys): + if len(symbols) > len(polys): from sympy.utilities.iterables import subsets from sympy.core.compatibility import set_union free = set_union(*[p.free_symbols for p in polys]) free = list(free.intersection(symbols)) free.sort(key=default_sort_key) + got_s = set([]) + result = [] for syms in subsets(free, len(polys)): try: # returns [] or list of tuples of solutions for syms - result = solve_poly_system(polys, *syms) - if result: - solved_syms = syms - break + res = solve_poly_system(polys, *syms) + if res: + for r in res: + skip = False + for r1 in r: + if got_s and any([ss in r1.free_symbols + for ss in got_s]): + # sol depends on previously + # solved symbols: discard it + skip = True + if not skip: + got_s.update(syms) + result.extend([dict(list(zip(syms, r)))]) except NotImplementedError: pass + if got_s: + solved_syms = list(got_s) else: raise NotImplementedError('no valid subset found') else: @@ -1311,26 +1498,13 @@ except NotImplementedError: failed.extend([g.as_expr() for g in polys]) solved_syms = [] - - if result: - # we don't know here if the symbols provided were given - # or not, so let solve resolve that. A list of dictionaries - # is going to always be returned from here. - result = [dict(list(zip(solved_syms, r))) for r in result] - - checked = [] - warning = flags.get('warn', False) - for r in result: - check = checksol(polys, r, **flags) - if check is not False: - if check is None and warning: - print((filldedent(""" - \tWarning: could not verify solution %s.""" % - result))) - # if it's a solution to any denom then exclude - if not dens or not checksol(dens, r, **flags): - checked.append(r) - result = checked + if result: + # we don't know here if the symbols provided were given + # or not, so let solve resolve that. A list of dictionaries + # is going to always be returned from here. + # + # We do not check the solution obtained from polys, either. + result = [dict(list(zip(solved_syms, r))) for r in result] if failed: # For each failed equation, see if we can solve for one of the @@ -1351,35 +1525,39 @@ rv.sort(key=default_sort_key) return rv - solved_syms = set(solved_syms) # set of symbols we have solved for - legal = set(symbols) # what we are interested in + solved_syms = set(solved_syms) # set of symbols we have solved for + legal = set(symbols) # what we are interested in simplify_flag = flags.get('simplify', None) do_simplify = flags.get('simplify', True) - # sort so equation with the fewest potential symbols is first; - # break ties with count_ops and default_sort_key - failed = lazyDSU_sort(failed, - keys=[ - lambda x: len(_ok_syms(x)), - lambda x: x.count_ops(), - default_sort_key], - warn=False) - for eq in failed: + # sort so equation with the fewest potential symbols is first + for eq in ordered(failed, lambda _: len(_ok_syms(_))): newresult = [] - got_s = None + bad_results = [] + got_s = set([]) u = Dummy() for r in result: # update eq with everything that is known so far eq2 = eq.subs(r) - b = checksol(u, u, eq2, minimal=True) - if b is not None: - if b: - newresult.append(r) - continue + # if check is True then we see if it satisfies this + # equation, otherwise we just accept it + if check and r: + b = checksol(u, u, eq2, minimal=True) + if b is not None: + # this solution is sufficient to know whether + # it is valid or not so we either accept or + # reject it, then continue + if b: + newresult.append(r) + else: + bad_results.append(r) + continue # search for a symbol amongst those available that # can be solved for ok_syms = _ok_syms(eq2, sort=True) if not ok_syms: - break # skip as it's independent of desired symbols + if r: + newresult.append(r) + break # skip as it's independent of desired symbols for s in ok_syms: try: soln = _solve(eq2, s, **flags) @@ -1389,10 +1567,13 @@ # result in the new result list; use copy since the # solution for s in being added in-place if do_simplify: - flags['simplify'] = False # for checksol's sake + flags['simplify'] = False # for checksol's sake for sol in soln: - # check that it satisfies *other* equations + if got_s and any([ss in sol.free_symbols for ss in got_s]): + # sol depends on previously solved symbols: discard it + continue if check: + # check that it satisfies *other* equations ok = False for p in polys: if checksol(p, s, sol, **flags) is False: @@ -1401,6 +1582,7 @@ ok = True if not ok: continue + # check that it doesn't set any denominator to 0 if any(checksol(d, s, sol, **flags) for d in dens): continue # update existing solutions with this new one @@ -1412,19 +1594,19 @@ newresult.append(rnew) if simplify_flag is not None: flags['simplify'] = simplify_flag - got_s = s - break - else: + got_s.add(s) + if not got_s: raise NotImplementedError('could not solve %s' % eq2) if got_s: result = newresult - solved_syms.add(got_s) + for b in bad_results: + result.remove(b) # if there is only one result should we return just the dictionary? return result def solve_linear(lhs, rhs=0, symbols=[], exclude=[]): - r""" Return a tuple containing derived from f = lhs - rhs that is either: + r""" Return a tuple derived from f = lhs - rhs that is either: (numerator, denominator) of ``f`` If this comes back as (0, 1) it means @@ -1526,6 +1708,7 @@ ''' % (bad, eg))) symbols = free.intersection(symbols) symbols = symbols.difference(exclude) + dfree = d.free_symbols # derivatives are easy to do but tricky to analyze to see if they are going # to disallow a linear solution, so for simplicity we just evaluate the @@ -1557,24 +1740,106 @@ i.function.is_number] # do a slight bit of simplification vi = expand_mul(vi.subs(irep)) - return xi, vi + if not d.has(xi) or not (d/xi).has(xi): + return xi, vi if all_zero: return S.Zero, S.One - if n.is_Symbol: # there was no valid solution + if n.is_Symbol: # there was no valid solution n = d = S.Zero - return n, d # should we cancel now? + return n, d # should we cancel now? + + +def minsolve_linear_system(system, *symbols, **flags): + r""" + Find a particular solution to a linear system. + + In particular, try to find a solution with the minimal possible number + of non-zero variables. This is a very computationally hard prolem. + If ``quick=True``, a heuristic is used. Otherwise a naive algorithm with + exponential complexity is used. + """ + quick = flags.get('quick', False) + # Check if there are any non-zero solutions at all + s0 = solve_linear_system(system, *symbols, **flags) + if not s0 or all(v == 0 for v in s0.values()): + return s0 + if quick: + # We just solve the system and try to heuristically find a nice + # solution. + s = solve_linear_system(system, *symbols) + def update(determined, solution): + delete = [] + for k, v in solution.items(): + solution[k] = v.subs(determined) + if not solution[k].free_symbols: + delete.append(k) + determined[k] = solution[k] + for k in delete: + del solution[k] + determined = {} + update(determined, s) + while s: + # NOTE sort by default_sort_key to get deterministic result + k = max((k for k in s.values()), + key=lambda x: (len(x.free_symbols), default_sort_key(x))) + x = max(k.free_symbols, key=default_sort_key) + if len(k.free_symbols) != 1: + determined[x] = S(0) + else: + val = solve(k)[0] + if val == 0 and all(v.subs(x, val) == 0 for v in s.values()): + determined[x] = S(1) + else: + determined[x] = val + update(determined, s) + return determined + else: + # We try to select n variables which we want to be non-zero. + # All others will be assumed zero. We try to solve the modified system. + # If there is a non-trivial solution, just set the free variables to + # one. If we do this for increasing n, trying all combinations of + # variables, we will find an optimal solution. + # We speed up slightly by starting at one less than the number of + # variables the quick method manages. + from sympy.core.compatibility import combinations + from sympy.utilities.misc import debug + N = len(symbols) + bestsol = minsolve_linear_system(system, *symbols, **{'quick': True}) + n0 = len([x for x in bestsol.values() if x != 0]) + for n in range(n0 - 1, 1, -1): + debug('minsolve: %s' % n) + thissol = None + for nonzeros in combinations(list(range(N)), n): + subm = Matrix([system.col(i).T for i in nonzeros] + [system.col(-1).T]).T + s = solve_linear_system(subm, *[symbols[i] for i in nonzeros]) + if s and not all(v == 0 for v in s.values()): + subs = [(symbols[v], S(1)) for v in nonzeros] + for k, v in s.items(): + s[k] = v.subs(subs) + for sym in symbols: + if sym not in s: + if list(symbols).index(sym) in nonzeros: + s[sym] = S(1) + else: + s[sym] = S(0) + thissol = s + break + if thissol is None: + break + bestsol = thissol + return bestsol def solve_linear_system(system, *symbols, **flags): r""" Solve system of N linear equations with M variables, which means - both Cramer and over defined systems are supported. The possible + both under- and overdetermined systems are supported. The possible number of solutions is zero, one or infinite. Respectively, this - procedure will return None or dictionary with solutions. In the - case of over-defined systems all arbitrary parameters are skipped. - This may cause situation in which an empty dictionary is returned. - In this case it means all symbols can be assigned arbitrary values. + procedure will return None or a dictionary with solutions. In the + case of underdetermined systems, all arbitrary parameters are skipped. + This may cause a situation in which an empty dictionary is returned. + In that case, all symbols can be assigned arbitrary values. Input to this functions is a Nx(M+1) matrix, which means it has to be in augmented form. If you prefer to enter N equations and M @@ -1599,6 +1864,12 @@ >>> solve_linear_system(system, x, y) {x: -6, y: 2} + A degenerate system returns an empty dictionary. + + >>> system = Matrix(( (0,0,0), (0,0,0) )) + >>> solve_linear_system(system, x, y) + {} + """ matrix = system[:, :] syms = list(symbols) @@ -1630,7 +1901,7 @@ # is a constant and we assume that it does not simplify # to zero XXX are there better ways to test this? if not matrix[i, m].free_symbols: - return None # no solution + return None # no solution # zero row with non-zero rhs can only be accepted # if there is another equivalent row, so look for @@ -1663,7 +1934,9 @@ # so now we can safely skip it matrix.row_del(i) if not matrix: - return None + # every choice of variable values is a solution + # so we return an empty dict instead of None + return dict() continue # we want to change the order of colums so @@ -1674,7 +1947,7 @@ pivot_inv = S.One/matrix[i, i] # divide all elements in the current row by the pivot - matrix.row(i, lambda x, _: x * pivot_inv) + matrix.row_op(i, lambda x, _: x * pivot_inv) for k in range(i + 1, matrix.rows): if matrix[k, i]: @@ -1682,7 +1955,7 @@ # subtract from the current row the row containing # pivot and multiplied by extracted coefficient - matrix.row(k, lambda x, j: simplify(x - matrix[i, j]*coeff)) + matrix.row_op(k, lambda x, j: simplify(x - matrix[i, j]*coeff)) i += 1 @@ -1695,7 +1968,7 @@ if len(syms) == matrix.rows: # this system is Cramer equivalent so there is # exactly one solution to this system of equations - k, solutions = i-1, {} + k, solutions = i - 1, {} while k >= 0: content = matrix[k, m] @@ -1776,7 +2049,7 @@ # system using Gaussian elimination algorithm return solve(system, *coeffs, **flags) else: - return None # no solutions + return None # no solutions def solve_linear_system_LU(matrix, syms): @@ -1814,46 +2087,6 @@ solutions[syms[i]] = soln[i, 0] return solutions -_x = Dummy('x') -_a, _b, _c, _d, _e, _f, _g, _h = [Wild(t, exclude=[_x]) for t in 'abcdefgh'] -_patterns = None - - -def _generate_patterns(): - """ - Generates patterns for transcendental equations. - - This is lazily calculated (called) in the tsolve() function and stored in - the patterns global variable. - """ - - tmp1 = _f ** (_h-(_c*_g/_b)) - tmp2 = (-_e*tmp1/_a)**(1/_d) - global _patterns - _patterns = [ - (_a*_x*exp(_b*_x) - _c, - LambertW(_b*_c/_a)/_b), - (_a*_x*log(_b*_x) - _c, - exp(LambertW(_b*_c/_a))/_b), - (_a*(_b*_x+_c)**_d + _e , - ((-(_e/_a))**(1/_d)-_c)/_b), - (_b+_c*exp(_d*_x+_e) , - (log(-_b/_c)-_e)/_d), - (_a*_x+_b+_c*exp(_d*_x+_e) , - -_b/_a-LambertW(_c*_d*exp(_e-_b*_d/_a)/_a)/_d), - (_b+_c*_f**(_d*_x+_e) , - (log(-_b/_c)-_e*log(_f))/_d/log(_f)), - (_a*_x+_b+_c*_f**(_d*_x+_e) , - -_b/_a-LambertW(_c*_d*_f**(_e-_b*_d/_a)*log(_f)/_a)/_d/log(_f)), - (_b+_c*log(_d*_x+_e) , - (exp(-_b/_c)-_e)/_d), - (_a*_x+_b+_c*log(_d*_x+_e) , - -_e/_d+_c/_a*LambertW(_a/_c/_d*exp(-_b/_c+_a*_e/_c/_d))), - (_a*(_b*_x+_c)**_d + _e*_f**(_g*_x+_h) , - -_c/_b-_d*LambertW(-tmp2*_g*log(_f)/_b/_d)/_g/log(_f)) - ] - - def tsolve(eq, sym): SymPyDeprecationWarning( feature="tsolve()", @@ -1864,97 +2097,138 @@ return _tsolve(eq, sym) +# these are functions that have multiple inverse values per period +multi_inverses = { + sin: lambda x: (asin(x), S.Pi - asin(x)), + cos: lambda x: (acos(x), 2*S.Pi - acos(x)), +} + + def _tsolve(eq, sym, **flags): """ Helper for _solve that solves a transcendental equation with respect to the given symbol. Various equations containing powers and logarithms, can be solved. - Only a single solution is returned. This solution is generally - not unique. In some cases, a complex solution may be returned - even though a real solution exists. + There is currently no guarantee that all solutions will be returned or + that a real solution will be favored over a complex one. - >>> from sympy import log - >>> from sympy.solvers.solvers import _tsolve as tsolve - >>> from sympy.abc import x + Examples + ======== - >>> tsolve(3**(2*x+5)-4, x) - [(-5*log(3) + 2*log(2))/(2*log(3))] + >>> from sympy import log + >>> from sympy.solvers.solvers import _tsolve as tsolve + >>> from sympy.abc import x - >>> tsolve(log(x) + 2*x, x) - [LambertW(2)/2] + >>> tsolve(3**(2*x + 5) - 4, x) + [-5/2 + log(2)/log(3), log(-2*sqrt(3)/27)/log(3)] - """ - if _patterns is None: - _generate_patterns() - eq2 = eq.subs(sym, _x) - for p, sol in _patterns: - m = eq2.match(p) - if m: - soln = sol.subs(m).subs(_x, sym) - if sym not in soln.free_symbols: - return [soln] + >>> tsolve(log(x) + 2*x, x) + [LambertW(2)/2] - try: - u = unrad(eq, sym) - except ValueError: - raise NotImplementedError('Radicals cannot be cleared from %s' % eq) - if u: - eq, cov, dens = u - if cov: - if len(cov) > 1: - raise NotImplementedError('Not sure how to handle this.') - isym, ieq = cov[0] - # since cov is written in terms of positive symbols, set - # check to False or else 0 would be excluded; _solve will check - # the results - flags['check'] = False - sol = _solve(eq, isym, **flags) - inv = _solve(ieq, sym, **flags) - result = [] - for s in sol: - for i in inv: - result.append(i.subs(isym, s)) - return result - else: - return _solve(eq, sym, **flags) + """ + if 'tsolve_saw' not in flags: + flags['tsolve_saw'] = [] + if eq in flags['tsolve_saw']: + return None + else: + flags['tsolve_saw'].append(eq) rhs, lhs = _invert(eq, sym) - if lhs.is_Add: - # it's time to try factoring - fac = factor(lhs - rhs) - if fac.is_Mul: - return _solve(fac, sym) - - elif lhs.is_Pow: - if lhs.exp.is_Integer: - if lhs - rhs != eq: - return _solve(lhs - rhs, sym) - elif not rhs: - return _solve(lhs.base, sym) - elif sym not in lhs.exp.free_symbols: - return _solve(lhs.base - rhs**(1/lhs.exp), sym) - elif not rhs and sym in lhs.exp.free_symbols: - # f(x)**g(x) only has solutions where f(x) == 0 and g(x) != 0 at - # the same place - sol_base = _solve(lhs.base, sym) - if not sol_base: - return sol_base - return list(set(sol_base) - set(_solve(lhs.exp, sym))) - elif (rhs is not S.Zero and - lhs.base.is_positive and - lhs.exp.is_real): - return _solve(lhs.exp*log(lhs.base) - log(rhs), sym) - - elif lhs.is_Mul and rhs.is_positive: - llhs = expand_log(log(lhs)) - if llhs.is_Add: - return _solve(llhs - log(rhs), sym) - - rewrite = lhs.rewrite(exp) - if rewrite != lhs: - return _solve(rewrite - rhs, sym) + if lhs == sym: + return [rhs] + try: + if lhs.is_Add: + # it's time to try factoring; powdenest is used + # to try get powers in standard form for better factoring + f = factor(powdenest(lhs - rhs)) + if f.is_Mul: + return _solve(f, sym, **flags) + if rhs: + f = logcombine(lhs, force=flags.get('force', False)) + if f.count(log) != lhs.count(log): + if f.func is log: + return _solve(f.args[0] - exp(rhs), sym, **flags) + return _tsolve(f - rhs, sym) + + elif lhs.is_Pow: + if lhs.exp.is_Integer: + if lhs - rhs != eq: + return _solve(lhs - rhs, sym, **flags) + elif sym not in lhs.exp.free_symbols: + return _solve(lhs.base - rhs**(1/lhs.exp), sym, **flags) + elif not rhs and sym in lhs.exp.free_symbols: + # f(x)**g(x) only has solutions where f(x) == 0 and g(x) != 0 at + # the same place + sol_base = _solve(lhs.base, sym, **flags) + if not sol_base: + return sol_base # no solutions to remove so return now + return list(ordered(set(sol_base) - set( + _solve(lhs.exp, sym, **flags)))) + elif (rhs is not S.Zero and + lhs.base.is_positive and + lhs.exp.is_real): + return _solve(lhs.exp*log(lhs.base) - log(rhs), sym, **flags) + + elif lhs.is_Mul and rhs.is_positive: + llhs = expand_log(log(lhs)) + if llhs.is_Add: + return _solve(llhs - log(rhs), sym, **flags) + + elif lhs.is_Function and lhs.nargs == 1 and lhs.func in multi_inverses: + # sin(x) = 1/3 -> x - asin(1/3) & x - (pi - asin(1/3)) + soln = [] + for i in multi_inverses[lhs.func](rhs): + soln.extend(_solve(lhs.args[0] - i, sym, **flags)) + return list(ordered(soln)) + + rewrite = lhs.rewrite(exp) + if rewrite != lhs: + return _solve(rewrite - rhs, sym, **flags) + except NotImplementedError: + pass + + # maybe it is a lambert pattern + if flags.pop('bivariate', True): + # lambert forms may need some help being recognized, e.g. changing + # 2**(3*x) + x**3*log(2)**3 + 3*x**2*log(2)**2 + 3*x*log(2) + 1 + # to 2**(3*x) + (x*log(2) + 1)**3 + g = _filtered_gens(eq.as_poly(), sym) + up_or_log = set() + for gi in g: + if gi.func is exp or gi.func is log: + up_or_log.add(gi) + elif gi.is_Pow: + gisimp = powdenest(expand_power_exp(gi)) + if gisimp.is_Pow and sym in gisimp.exp.free_symbols: + up_or_log.add(gi) + down = g.difference(up_or_log) + eq_down = expand_log(expand_power_exp(eq)).subs( + dict(list(zip(up_or_log, [0]*len(up_or_log))))) + eq = expand_power_exp(factor(eq_down, deep=True) + (eq - eq_down)) + rhs, lhs = _invert(eq, sym) + if lhs.has(sym): + try: + poly = lhs.as_poly() + g = _filtered_gens(poly, sym) + return _solve_lambert(lhs - rhs, sym, g) + except NotImplementedError: + # maybe it's a convoluted function + if len(g) == 2: + try: + gpu = bivariate_type(lhs - rhs, *g) + if gpu is None: + raise NotImplementedError + g, p, u = gpu + flags['bivariate'] = False + inversion = _tsolve(g - u, sym, **flags) + if inversion: + sol = _solve(p, u, **flags) + return list(ordered([i.subs(u, s) + for i in inversion for s in sol])) + except NotImplementedError: + pass if flags.pop('force', True): flags['force'] = False @@ -1968,7 +2242,8 @@ soln = _solve(pos, u, **flags) except NotImplementedError: return - return [s.subs(reps) for s in soln] + return list(ordered([s.subs(reps) for s in soln])) + # TODO: option for calculating J numerically @@ -2074,8 +2349,8 @@ contains symbols. ``i`` and ``d`` are obtained after recursively using algebraic inversion until an uninvertible ``d`` remains. If there are no free symbols then ``d`` will be zero. Some (but not necessarily all) - solutions to the expression ``i - d`` will be related the solutions of the - original expression. + solutions to the expression ``i - d`` will be related to the solutions of + the original expression. Examples ======== @@ -2088,7 +2363,7 @@ >>> invert(3) (3, 0) >>> invert(2*cos(x) - 1) - (pi/3, x) + (1/2, cos(x)) >>> invert(sqrt(x) - 3) (3, sqrt(x)) >>> invert(sqrt(x) + y, x) @@ -2123,17 +2398,6 @@ dointpow = bool(kwargs.get('integer_power', False)) - inverses = { - asin: sin, - acos: cos, - atan: tan, - acot: cot, - asinh: sinh, - acosh: cosh, - atanh: tanh, - acoth: coth, - } - lhs = eq rhs = S.Zero while True: @@ -2176,35 +2440,52 @@ # if it's a two-term Add with rhs = 0 and two powers we can get the # dependent terms together, e.g. 3*f(x) + 2*g(x) -> f(x)/g(x) = -2/3 - if lhs.is_Add and not rhs and len(lhs.args) == 2: - a, b = lhs.as_two_terms() + if lhs.is_Add and not rhs and len(lhs.args) == 2 and \ + not lhs.is_polynomial(*symbols): + a, b = ordered(lhs.args) ai, ad = a.as_independent(*symbols) bi, bd = b.as_independent(*symbols) - if any(_ispow(i) for i in (ad, bd)) and \ - ad.as_base_exp()[0] == bd.as_base_exp()[0]: - # a = -b - lhs = powsimp(powdenest(ad/bd)) - rhs = -bi/ai + if any(_ispow(i) for i in (ad, bd)): + a_base, a_exp = ad.as_base_exp() + b_base, b_exp = bd.as_base_exp() + if a_base == b_base: + # a = -b + lhs = powsimp(powdenest(ad/bd)) + rhs = -bi/ai + else: + rat = ad/bd + _lhs = powsimp(ad/bd) + if _lhs != rat: + lhs = _lhs + rhs = -bi/ai + if ai*bi is S.NegativeOne: + if all( + isinstance(i, Function) for i in (ad, bd)) and \ + ad.func == bd.func and ad.nargs == bd.nargs: + if len(ad.args) == 1: + lhs = ad.args[0] - bd.args[0] + else: + # should be able to solve + # f(x, y) == f(2, 3) -> x == 2 + # f(x, x + y) == f(2, 3) -> x == 2 or x == 3 - y + raise NotImplementedError('equal function with more than 1 argument') elif lhs.is_Mul and any(_ispow(a) for a in lhs.args): lhs = powsimp(powdenest(lhs)) - # -1 - # f(x) = g -> x = f (g) - elif lhs.is_Function and (lhs.nargs==1 or len(lhs.args) == 1) and \ - (hasattr(lhs, 'inverse') or - lhs.func in inverses or - lhs.func is Abs): - if lhs.func in inverses: - inv = inverses[lhs.func] - elif lhs.func is Abs: - inv = lambda w: w**2 - lhs = Basic(lhs.args[0]**2) # get it ready to remove the args - else: - inv = lhs.inverse() - rhs = inv(rhs) - lhs = lhs.args[0] - + if lhs.is_Function: + if hasattr(lhs, 'inverse') and len(lhs.args) == 1: + # -1 + # f(x) = g -> x = f (g) + # + # /!\ inverse should not be defined if there are multiple values + # for the function -- these are handled in _tsolve + # + rhs = lhs.inverse()(rhs) + lhs = lhs.args[0] + elif lhs.func is atan2: + y, x = lhs.args + lhs = 2*atan(y/(sqrt(x**2 + y**2) + x)) if rhs and lhs.is_Pow and lhs.exp.is_Integer and lhs.exp < 0: lhs = 1/lhs rhs = 1/rhs @@ -2218,8 +2499,8 @@ # system is written in terms of sqrt(x + y) so it will just fail, so we # do that step here. if lhs.is_Pow and ( - lhs.exp.is_Integer and dointpow or not lhs.exp.is_Integer and - len(symbols) > 1 and len(lhs.base.free_symbols & set(symbols)) > 1): + lhs.exp.is_Integer and dointpow or not lhs.exp.is_Integer and + len(symbols) > 1 and len(lhs.base.free_symbols & set(symbols)) > 1): rhs = rhs**(1/lhs.exp) lhs = lhs.base @@ -2236,7 +2517,7 @@ ValueError is raised if there are radicals and they cannot be removed. - Otherwise + Otherwise the tuple, ``(eq, cov, dens)``, is returned where:: ``eq``, ``cov`` equation without radicals, perhaps written in terms of @@ -2257,8 +2538,15 @@ interest will be cleared. ``flags`` are used internally for communication during recursive calls. + Two options are also recognized:: + + ``take``, when defined, is interpreted as a single-argument function + that returns True if a given Pow should be handled. + ``all``, when True, will signify that an attempt should be made to + remove all radicals. ``take``, if present, has priority over ``all``. + + Radicals can be removed from an expression if:: - Radicals can be removed from an expression if: * all bases of the radicals are the same; a change of variables is done in this case. * if all radicals appear in one term of the expression @@ -2271,33 +2559,70 @@ >>> from sympy.solvers.solvers import unrad >>> from sympy.abc import x >>> from sympy import sqrt, Rational - >>> unrad(sqrt(x)*x**Rational(1,3) + 2) + >>> unrad(sqrt(x)*x**Rational(1, 3) + 2) (x**5 - 64, [], []) - >>> unrad(sqrt(x) + (x + 1)**Rational(1,3)) + >>> unrad(sqrt(x) + (x + 1)**Rational(1, 3)) (x**3 - x**2 - 2*x - 1, [], []) - >>> unrad(sqrt(x) + x**Rational(1,3) + 2) + >>> unrad(sqrt(x) + x**Rational(1, 3) + 2) (_p**3 + _p**2 + 2, [(_p, -_p**6 + x)], []) """ + def _canonical(eq): + # remove constants since these don't change the location of the root + # and expand the expression + eq = factor_terms(eq) + if eq.is_Mul: + eq = Mul(*[f for f in eq.args if not f.is_number]) + eq = _mexpand(eq) + + # make sign canonical + free = eq.free_symbols + if len(free) == 1: + if eq.coeff(free.pop()**degree(eq)) < 0: + eq = -eq + elif eq.could_extract_minus_sign(): + eq = -eq + + return eq + if eq.is_Atom: return - cov, dens, nwas = [flags.get(k, v) for k, v in - sorted(dict(dens=None, cov=None, n=None).items())] + cov, dens, nwas, rpt = [flags.get(k, v) for k, v in + sorted(dict(dens=None, cov=None, n=None, rpt=0).items())] - def _take(d): - # see if this is a term that has symbols of interest - # and merits further processing - free = d.free_symbols - if not free: - return False - return not syms or free.intersection(syms) + if flags.get('take', None): + _take = flags.pop('take') + elif flags.pop('all', None): + _rad = lambda w: w.is_Pow and w.exp.is_Rational and w.exp.q != 1 + def _take(d): + return _rad(d) or any(_rad(i) for i in d.atoms(Pow)) + if eq.has(S.ImaginaryUnit): + i = Dummy() + flags['take'] = _take + try: + rv = unrad(eq.xreplace({S.ImaginaryUnit: sqrt(i)}), *syms, **flags) + rep = {i: S.NegativeOne} + rv = (_canonical(rv[0].xreplace(rep)), + [tuple([j.xreplace(rep) for j in i]) for i in rv[1]], + [i.xreplace(rep) for i in rv[2]]) + return rv + except ValueError as msg: + raise msg + else: + def _take(d): + # see if this is a term that has symbols of interest + # and merits further processing + free = d.free_symbols + if not free: + return False + return not syms or free.intersection(syms) if dens is None: dens = set() if cov is None: cov = [] - eq = powdenest(eq) + eq = powdenest(factor_terms(eq, radical=True)) eq, d = eq.as_numer_denom() eq = _mexpand(eq) if _take(d): @@ -2308,21 +2633,26 @@ poly = eq.as_poly() - rads = set([g for g in poly.gens if _take(g) and - g.is_Pow and g.exp.as_coeff_mul()[0].q != 1]) + # if all the bases are the same or all the radicals are in one + # term, `lcm` will be the lcm of the radical's exponent + # denominators + lcm = 1 + rads = set() + bases = set() + for g in poly.gens: + if not _take(g) or not g.is_Pow: + continue + ecoeff = g.exp.as_coeff_mul()[0] # a Rational + if ecoeff.q != 1: + rads.add(g) + lcm = ilcm(lcm, ecoeff.q) + bases.add(g.base) if not rads: return depth = sqrt_depth(eq) - # if all the bases are the same or all the radicals are in one - # term, this is the lcm of the radical's exponent denominators - lcm = reduce(ilcm, [r.exp.q for r in rads]) - - # find the bases of the radicals - bases = set([r.as_base_exp()[0] for r in rads]) - # get terms together that have common generators drad = dict(list(zip(rads, list(range(len(rads)))))) rterms = {(): []} @@ -2338,7 +2668,7 @@ rterms = [Add(*rterms[k]) for k in list(rterms.keys())] # the output will depend on the order terms are processed, so # make it canonical quickly - rterms.sort(key=default_sort_key) + rterms = list(reversed(list(ordered(rterms)))) # continue handling ok = True @@ -2348,23 +2678,25 @@ elif len(rterms) == 2 and not args: eq = rterms[0]**lcm - rterms[1]**lcm - elif log(lcm, 2).is_Integer and (not args and len(rterms) == 4 or len(rterms) < 4): + elif log(lcm, 2).is_Integer and (not args and + len(rterms) == 4 or len(rterms) < 4): + def _norm2(a, b): + return a**2 + b**2 + 2*a*b + if len(rterms) == 4: # (r0+r1)**2 - (r2+r3)**2 - t1, t2, t3, t4 = [t**2 for t in rterms] - eq = t1 + t2 + 2*rterms[0]*rterms[1] - \ - (t3 + t4 + 2*rterms[2]*rterms[3]) + r0, r1, r2, r3 = rterms + eq = _norm2(r0, r1) - _norm2(r2, r3) elif len(rterms) == 3: - # (r0+r1)**2 - (r2+a)**2 - t1, t2, t3 = [t**2 for t in rterms] - eq = t1 + t2 + 2*rterms[0]*rterms[1] - \ - (t3 + args**2 + 2*args*rterms[2]) + # (r1+r2)**2 - (r0+args)**2 + r0, r1, r2 = rterms + eq = _norm2(r1, r2) - _norm2(r0, args) elif len(rterms) == 2: - t1, t2 = [t**2 for t in rterms[:2]] - # r0**2 - (r1+a)**2 - eq = t1 - (t2 + args**2 + 2*args*rterms[1]) + # r0**2 - (r1+args)**2 + r0, r1 = rterms + eq = r0**2 - _norm2(r1, args) - elif len(bases) == 1: # change of variables may work + elif len(bases) == 1: # change of variables may work ok = False covwas = len(cov) b = bases.pop() @@ -2388,13 +2720,20 @@ ok = False new_depth = sqrt_depth(eq) - if not ok or (nwas is not None and len(rterms) == nwas and new_depth and new_depth == depth): + rpt += 1 # XXX how many repeats with others unchanging is enough? + if not ok or ( + nwas is not None and len(rterms) == nwas and + new_depth is not None and new_depth == depth and + rpt > 3): # XXX: XFAIL tests indicate other cases that should be handled. raise ValueError('Cannot remove all radicals from %s' % eq) - neq = unrad(eq, *syms, **dict(cov=cov, dens=dens, n=len(rterms))) + neq = unrad(eq, *syms, **dict(cov=cov, dens=dens, n=len(rterms), rpt=rpt, take=_take)) if neq: eq = neq[0] - if eq.could_extract_minus_sign(): - eq = -eq - return (_mexpand(eq), cov, list(dens)) + + return (_canonical(eq), cov, list(dens)) + + +from sympy.solvers.bivariate import ( + bivariate_type, _solve_lambert, _filtered_gens) diff -Nru python3-sympy-0.7.2/sympy/solvers/tests/test_constantsimp.py python3-sympy-0.7.3/sympy/solvers/tests/test_constantsimp.py --- python3-sympy-0.7.2/sympy/solvers/tests/test_constantsimp.py 2012-10-17 03:02:22.000000000 +0000 +++ python3-sympy-0.7.3/sympy/solvers/tests/test_constantsimp.py 2013-07-13 17:53:32.000000000 +0000 @@ -17,6 +17,7 @@ C3 = Symbol('C3') f = Function('f') + def test_constant_mul(): # We want C1 (Constant) below to absorb the y's, but not the x's assert constant_renumber(constantsimp(y*C1, x, 1), 'C', 1, 1) == C1 @@ -41,14 +42,18 @@ assert constant_renumber(constantsimp((C1*x)*y, x, 1), 'C', 1, 1) == C1*x assert constant_renumber(constantsimp(y*(x*C1), x, 1), 'C', 1, 1) == x*C1 assert constant_renumber(constantsimp((x*C1)*y, x, 1), 'C', 1, 1) == x*C1 - assert constant_renumber(constantsimp(C1*x*y*x*y*2, x, 1), 'C', 1, 1) == C1*x**2 + assert constant_renumber( + constantsimp(C1*x*y*x*y*2, x, 1), 'C', 1, 1) == C1*x**2 assert constant_renumber(constantsimp(C1*x*y*z, x, 1), 'C', 1, 1) == C1*x - assert constant_renumber(constantsimp(C1*x*y**2*sin(z), x, 1), 'C', 1, 1) == C1*x + assert constant_renumber( + constantsimp(C1*x*y**2*sin(z), x, 1), 'C', 1, 1) == C1*x assert constant_renumber(constantsimp(C1*C1, x, 1), 'C', 1, 1) == C1 assert constant_renumber(constantsimp(C1*C2, x, 2), 'C', 1, 2) == C1 assert constant_renumber(constantsimp(C2*C2, x, 2), 'C', 1, 2) == C1 assert constant_renumber(constantsimp(C1*C1*C2, x, 2), 'C', 1, 2) == C1 - assert constant_renumber(constantsimp(C1*x*2**x, x, 1), 'C', 1, 1) == C1*x*2**x + assert constant_renumber( + constantsimp(C1*x*2**x, x, 1), 'C', 1, 1) == C1*x*2**x + def test_constant_add(): assert constant_renumber(constantsimp(C1 + C1, x, 1), 'C', 1, 1) == C1 @@ -65,9 +70,10 @@ assert constant_renumber(constantsimp(C2 + C1, x, 2), 'C', 1, 2) == C1 assert constant_renumber(constantsimp(C1 + C2 + C1, x, 2), 'C', 1, 2) == C1 + def test_constant_power_as_base(): assert constant_renumber(constantsimp(C1**C1, x, 1), 'C', 1, 1) == C1 - assert constant_renumber(constantsimp(Pow(C1,C1), x, 1), 'C', 1, 1) == C1 + assert constant_renumber(constantsimp(Pow(C1, C1), x, 1), 'C', 1, 1) == C1 assert constant_renumber(constantsimp(C1**C1, x, 1), 'C', 1, 1) == C1 assert constant_renumber(constantsimp(C1**C2, x, 2), 'C', 1, 2) == C1 assert constant_renumber(constantsimp(C2**C1, x, 2), 'C', 1, 2) == C1 @@ -75,23 +81,31 @@ assert constant_renumber(constantsimp(C1**y, x, 1), 'C', 1, 1) == C1 assert constant_renumber(constantsimp(C1**x, x, 1), 'C', 1, 1) == C1**x assert constant_renumber(constantsimp(C1**2, x, 1), 'C', 1, 1) == C1 - assert constant_renumber(constantsimp(C1**(x*y), x, 1), 'C', 1, 1) == C1**(x*y) + assert constant_renumber( + constantsimp(C1**(x*y), x, 1), 'C', 1, 1) == C1**(x*y) + def test_constant_power_as_exp(): assert constant_renumber(constantsimp(x**C1, x, 1), 'C', 1, 1) == x**C1 assert constant_renumber(constantsimp(y**C1, x, 1), 'C', 1, 1) == C1 assert constant_renumber(constantsimp(x**y**C1, x, 1), 'C', 1, 1) == x**C1 - assert constant_renumber(constantsimp((x**y)**C1, x, 1), 'C', 1, 1) == (x**y)**C1 - assert constant_renumber(constantsimp(x**(y**C1), x, 1), 'C', 1, 1) == x**C1 + assert constant_renumber( + constantsimp((x**y)**C1, x, 1), 'C', 1, 1) == (x**y)**C1 + assert constant_renumber( + constantsimp(x**(y**C1), x, 1), 'C', 1, 1) == x**C1 assert constant_renumber(constantsimp(x**C1**y, x, 1), 'C', 1, 1) == x**C1 - assert constant_renumber(constantsimp(x**(C1**y), x, 1), 'C', 1, 1) == x**C1 - assert constant_renumber(constantsimp((x**C1)**y, x, 1), 'C', 1, 1) == (x**C1)**y + assert constant_renumber( + constantsimp(x**(C1**y), x, 1), 'C', 1, 1) == x**C1 + assert constant_renumber( + constantsimp((x**C1)**y, x, 1), 'C', 1, 1) == (x**C1)**y assert constant_renumber(constantsimp(2**C1, x, 1), 'C', 1, 1) == C1 assert constant_renumber(constantsimp(S(2)**C1, x, 1), 'C', 1, 1) == C1 assert constant_renumber(constantsimp(exp(C1), x, 1), 'C', 1, 1) == C1 - assert constant_renumber(constantsimp(exp(C1+x), x, 1), 'C', 1, 1) == C1*exp(x) + assert constant_renumber( + constantsimp(exp(C1 + x), x, 1), 'C', 1, 1) == C1*exp(x) assert constant_renumber(constantsimp(Pow(2, C1), x, 1), 'C', 1, 1) == C1 + def test_constant_function(): assert constant_renumber(constantsimp(sin(C1), x, 1), 'C', 1, 1) == C1 assert constant_renumber(constantsimp(f(C1), x, 1), 'C', 1, 1) == C1 @@ -99,50 +113,60 @@ assert constant_renumber(constantsimp(f(C1, C2), x, 2), 'C', 1, 2) == C1 assert constant_renumber(constantsimp(f(C2, C1), x, 2), 'C', 1, 2) == C1 assert constant_renumber(constantsimp(f(C2, C2), x, 2), 'C', 1, 2) == C1 - assert constant_renumber(constantsimp(f(C1, x), x, 1), 'C', 1, 2) == f(C1, x) + assert constant_renumber( + constantsimp(f(C1, x), x, 1), 'C', 1, 2) == f(C1, x) assert constant_renumber(constantsimp(f(C1, y), x, 1), 'C', 1, 2) == C1 assert constant_renumber(constantsimp(f(y, C1), x, 1), 'C', 1, 2) == C1 assert constant_renumber(constantsimp(f(C1, y, C2), x, 2), 'C', 1, 2) == C1 + @XFAIL def test_constant_function_multiple(): # The rules to not renumber in this case would be too complicated, and # dsolve is not likely to ever encounter anything remotely like this. - assert constant_renumber(constantsimp(f(C1, C1, x), x, 1), 'C', 1, 1) == f(C1, C1, x) + assert constant_renumber( + constantsimp(f(C1, C1, x), x, 1), 'C', 1, 1) == f(C1, C1, x) + def test_constant_multiple(): assert constant_renumber(constantsimp(C1*2 + 2, x, 1), 'C', 1, 1) == C1 assert constant_renumber(constantsimp(x*2/C1, x, 1), 'C', 1, 1) == C1*x assert constant_renumber(constantsimp(C1**2*2 + 2, x, 1), 'C', 1, 1) == C1 - assert constant_renumber(constantsimp(sin(2*C1) + x + sqrt(2), x, 1), 'C', 1, 1) == C1 + x + assert constant_renumber( + constantsimp(sin(2*C1) + x + sqrt(2), x, 1), 'C', 1, 1) == C1 + x assert constant_renumber(constantsimp(2*C1 + C2, x, 2), 'C', 1, 2) == C1 + def test_ode_solutions(): # only a few examples here, the rest will be tested in the actual dsolve tests - assert constant_renumber(constantsimp(C1*exp(2*x)+exp(x)*(C2+C3), x, 3), 'C', 1, 3) == \ + assert constant_renumber(constantsimp(C1*exp(2*x) + exp(x)*(C2 + C3), x, 3), 'C', 1, 3) == \ constant_renumber((C1*exp(x) + C2*exp(2*x)), 'C', 1, 2) - assert constant_renumber(constantsimp(Eq(f(x),I*C1*sinh(x/3) + C2*cosh(x/3)), x, 2), + assert constant_renumber( + constantsimp(Eq(f(x), I*C1*sinh(x/3) + C2*cosh(x/3)), x, 2), 'C', 1, 2) == constant_renumber(Eq(f(x), C1*sinh(x/3) + C2*cosh(x/3)), 'C', 1, 2) - assert constant_renumber(constantsimp(Eq(f(x),acos((-C1)/cos(x))), x, 1), 'C', 1, 1) == \ - Eq(f(x),acos(C1/cos(x))) - assert constant_renumber(constantsimp(Eq(log(f(x)/C1) + 2*exp(x/f(x)), 0), x, 1), - 'C', 1, 1) == Eq(log(C1*f(x)) + 2*exp(x/f(x)), 0) - assert constant_renumber(constantsimp(Eq(log(x*sqrt(2)*sqrt(1/x)*sqrt(f(x))\ + assert constant_renumber(constantsimp(Eq(f(x), acos((-C1)/cos(x))), x, 1), 'C', 1, 1) == \ + Eq(f(x), acos(C1/cos(x))) + assert constant_renumber( + constantsimp(Eq(log(f(x)/C1) + 2*exp(x/f(x)), 0), x, 1), + 'C', 1, 1) == Eq(log(C1*f(x)) + 2*exp(x/f(x)), 0) + assert constant_renumber(constantsimp(Eq(log(x*sqrt(2)*sqrt(1/x)*sqrt(f(x)) /C1) + x**2/(2*f(x)**2), 0), x, 1), 'C', 1, 1) == \ Eq(log(C1*x*sqrt(1/x)*sqrt(f(x))) + x**2/(2*f(x)**2), 0) - assert constant_renumber(constantsimp(Eq(-exp(-f(x)/x)*sin(f(x)/x)/2 + log(x/C1) - \ + assert constant_renumber(constantsimp(Eq(-exp(-f(x)/x)*sin(f(x)/x)/2 + log(x/C1) - cos(f(x)/x)*exp(-f(x)/x)/2, 0), x, 1), 'C', 1, 1) == \ - Eq(-exp(-f(x)/x)*sin(f(x)/x)/2 + log(C1*x) - cos(f(x)/x)*exp(-f(x)/x)/2, 0) + Eq(-exp(-f(x)/x)*sin(f(x)/x)/2 + log(C1*x) - cos(f(x)/x)* + exp(-f(x)/x)/2, 0) u2 = Symbol('u2') _a = Symbol('_a') - assert constant_renumber(constantsimp(Eq(-Integral(-1/(sqrt(1 - u2**2)*u2), \ + assert constant_renumber(constantsimp(Eq(-Integral(-1/(sqrt(1 - u2**2)*u2), (u2, _a, x/f(x))) + log(f(x)/C1), 0), x, 1), 'C', 1, 1) == \ - Eq(-Integral(-1/(u2*sqrt(1 - u2**2)), (u2, _a, x/f(x))) + \ + Eq(-Integral(-1/(u2*sqrt(1 - u2**2)), (u2, _a, x/f(x))) + log(C1*f(x)), 0) assert [constant_renumber(constantsimp(i, x, 1), 'C', 1, 1) for i in [Eq(f(x), sqrt(-C1*x + x**2)), Eq(f(x), -sqrt(-C1*x + x**2))]] == \ [Eq(f(x), sqrt(x*(C1 + x))), Eq(f(x), -sqrt(x*(C1 + x)))] + def test_constant_Eq(): # C1 on the rhs is well-tested, but the lhs is only tested here - assert constantsimp(Eq(C1, 3 + f(x)*x), x, 1) == Eq(C1, f(x)*x) + assert constantsimp(Eq(C1, 3 + f(x)*x), x, 1) == Eq(C1, f(x)*x) diff -Nru python3-sympy-0.7.2/sympy/solvers/tests/test_inequalities.py python3-sympy-0.7.3/sympy/solvers/tests/test_inequalities.py --- python3-sympy-0.7.2/sympy/solvers/tests/test_inequalities.py 2012-10-17 03:02:22.000000000 +0000 +++ python3-sympy-0.7.3/sympy/solvers/tests/test_inequalities.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,135 +1,224 @@ """Tests for tools for solving inequalities and systems of inequalities. """ -from sympy import (And, Eq, FiniteSet, Ge, global_assumptions, Gt, im, - Interval, Le, Lt, Ne, oo, Or, Q, re, S, sin, sqrt, Union) + +from sympy import (And, Eq, FiniteSet, Ge, Gt, im, Interval, Le, Lt, Ne, oo, + Or, Q, re, S, sin, sqrt, Union) +from sympy.assumptions import assuming from sympy.abc import x, y from sympy.solvers.inequalities import (reduce_inequalities, - reduce_poly_inequalities) + reduce_rational_inequalities) from sympy.utilities.pytest import raises inf = oo.evalf() + def test_reduce_poly_inequalities_real_interval(): - global_assumptions.add(Q.real(x)) - global_assumptions.add(Q.real(y)) + with assuming(Q.real(x), Q.real(y)): + assert reduce_rational_inequalities( + [[Eq(x**2, 0)]], x, relational=False) == FiniteSet(0) + assert reduce_rational_inequalities( + [[Le(x**2, 0)]], x, relational=False) == FiniteSet(0) + assert reduce_rational_inequalities( + [[Lt(x**2, 0)]], x, relational=False) == S.EmptySet + assert reduce_rational_inequalities( + [[Ge(x**2, 0)]], x, relational=False) == Interval(-oo, oo) + assert reduce_rational_inequalities( + [[Gt(x**2, 0)]], x, relational=False) == FiniteSet(0).complement + assert reduce_rational_inequalities( + [[Ne(x**2, 0)]], x, relational=False) == FiniteSet(0).complement + + assert reduce_rational_inequalities( + [[Eq(x**2, 1)]], x, relational=False) == FiniteSet(-1, 1) + assert reduce_rational_inequalities( + [[Le(x**2, 1)]], x, relational=False) == Interval(-1, 1) + assert reduce_rational_inequalities( + [[Lt(x**2, 1)]], x, relational=False) == Interval(-1, 1, True, True) + assert reduce_rational_inequalities([[Ge(x**2, 1)]], x, relational=False) == Union(Interval(-oo, -1), Interval(1, oo)) + assert reduce_rational_inequalities( + [[Gt(x**2, 1)]], x, relational=False) == Interval(-1, 1).complement + assert reduce_rational_inequalities( + [[Ne(x**2, 1)]], x, relational=False) == FiniteSet(-1, 1).complement + assert reduce_rational_inequalities([[Eq( + x**2, 1.0)]], x, relational=False) == FiniteSet(-1.0, 1.0).evalf() + assert reduce_rational_inequalities( + [[Le(x**2, 1.0)]], x, relational=False) == Interval(-1.0, 1.0) + assert reduce_rational_inequalities([[Lt( + x**2, 1.0)]], x, relational=False) == Interval(-1.0, 1.0, True, True) + assert reduce_rational_inequalities([[Ge(x**2, 1.0)]], x, relational=False) == Union(Interval(-inf, -1.0), Interval(1.0, inf)) + assert reduce_rational_inequalities([[Gt(x**2, 1.0)]], x, relational=False) == Union(Interval(-inf, -1.0, right_open=True), Interval(1.0, inf, left_open=True)) + assert reduce_rational_inequalities([[Ne( + x**2, 1.0)]], x, relational=False) == FiniteSet(-1.0, 1.0).complement + + s = sqrt(2) + + assert reduce_rational_inequalities([[Lt( + x**2 - 1, 0), Gt(x**2 - 1, 0)]], x, relational=False) == S.EmptySet + assert reduce_rational_inequalities([[Le(x**2 - 1, 0), Ge( + x**2 - 1, 0)]], x, relational=False) == FiniteSet(-1, 1) + assert reduce_rational_inequalities([[Le(x**2 - 2, 0), Ge(x**2 - 1, 0)]], x, relational=False) == Union(Interval(-s, -1, False, False), Interval(1, s, False, False)) + assert reduce_rational_inequalities([[Le(x**2 - 2, 0), Gt(x**2 - 1, 0)]], x, relational=False) == Union(Interval(-s, -1, False, True), Interval(1, s, True, False)) + assert reduce_rational_inequalities([[Lt(x**2 - 2, 0), Ge(x**2 - 1, 0)]], x, relational=False) == Union(Interval(-s, -1, True, False), Interval(1, s, False, True)) + assert reduce_rational_inequalities([[Lt(x**2 - 2, 0), Gt(x**2 - 1, 0)]], x, relational=False) == Union(Interval(-s, -1, True, True), Interval(1, s, True, True)) + assert reduce_rational_inequalities([[Lt(x**2 - 2, 0), Ne(x**2 - 1, 0)]], x, relational=False) == Union(Interval(-s, -1, True, True), Interval(-1, 1, True, True), Interval(1, s, True, True)) - assert reduce_poly_inequalities([[Eq(x**2, 0)]], x, relational=False) == FiniteSet(0) - assert reduce_poly_inequalities([[Le(x**2, 0)]], x, relational=False) == FiniteSet(0) - assert reduce_poly_inequalities([[Lt(x**2, 0)]], x, relational=False) == S.EmptySet - assert reduce_poly_inequalities([[Ge(x**2, 0)]], x, relational=False) == Interval(-oo, oo) - assert reduce_poly_inequalities([[Gt(x**2, 0)]], x, relational=False) == FiniteSet(0).complement - assert reduce_poly_inequalities([[Ne(x**2, 0)]], x, relational=False) == FiniteSet(0).complement - - assert reduce_poly_inequalities([[Eq(x**2, 1)]], x, relational=False) == FiniteSet(-1, 1) - assert reduce_poly_inequalities([[Le(x**2, 1)]], x, relational=False) == Interval(-1, 1) - assert reduce_poly_inequalities([[Lt(x**2, 1)]], x, relational=False) == Interval(-1, 1, True, True) - assert reduce_poly_inequalities([[Ge(x**2, 1)]], x, relational=False) == Union(Interval(-oo, -1), Interval(1, oo)) - assert reduce_poly_inequalities([[Gt(x**2, 1)]], x, relational=False) == Interval(-1,1).complement - assert reduce_poly_inequalities([[Ne(x**2, 1)]], x, relational=False) == FiniteSet(-1,1).complement - assert reduce_poly_inequalities([[Eq(x**2, 1.0)]], x, relational=False) == FiniteSet(-1.0,1.0).evalf() - assert reduce_poly_inequalities([[Le(x**2, 1.0)]], x, relational=False) == Interval(-1.0, 1.0) - assert reduce_poly_inequalities([[Lt(x**2, 1.0)]], x, relational=False) == Interval(-1.0, 1.0, True, True) - assert reduce_poly_inequalities([[Ge(x**2, 1.0)]], x, relational=False) == Union(Interval(-inf, -1.0), Interval(1.0, inf)) - assert reduce_poly_inequalities([[Gt(x**2, 1.0)]], x, relational=False) == Union(Interval(-inf, -1.0, right_open=True), Interval(1.0, inf, left_open=True)) - assert reduce_poly_inequalities([[Ne(x**2, 1.0)]], x, relational=False) == FiniteSet(-1.0, 1.0).complement - - s = sqrt(2) - - assert reduce_poly_inequalities([[Lt(x**2 - 1, 0), Gt(x**2 - 1, 0)]], x, relational=False) == S.EmptySet - assert reduce_poly_inequalities([[Le(x**2 - 1, 0), Ge(x**2 - 1, 0)]], x, relational=False) == FiniteSet(-1,1) - assert reduce_poly_inequalities([[Le(x**2 - 2, 0), Ge(x**2 - 1, 0)]], x, relational=False) == Union(Interval(-s, -1, False, False), Interval(1, s, False, False)) - assert reduce_poly_inequalities([[Le(x**2 - 2, 0), Gt(x**2 - 1, 0)]], x, relational=False) == Union(Interval(-s, -1, False, True), Interval(1, s, True, False)) - assert reduce_poly_inequalities([[Lt(x**2 - 2, 0), Ge(x**2 - 1, 0)]], x, relational=False) == Union(Interval(-s, -1, True, False), Interval(1, s, False, True)) - assert reduce_poly_inequalities([[Lt(x**2 - 2, 0), Gt(x**2 - 1, 0)]], x, relational=False) == Union(Interval(-s, -1, True, True), Interval(1, s, True, True)) - assert reduce_poly_inequalities([[Lt(x**2 - 2, 0), Ne(x**2 - 1, 0)]], x, relational=False) == Union(Interval(-s, -1, True, True), Interval(-1, 1, True, True), Interval(1, s, True, True)) - global_assumptions.remove(Q.real(x)) - global_assumptions.remove(Q.real(y)) def test_reduce_poly_inequalities_real_relational(): - global_assumptions.add(Q.real(x)) - global_assumptions.add(Q.real(y)) + with assuming(Q.real(x), Q.real(y)): + assert reduce_rational_inequalities( + [[Eq(x**2, 0)]], x, relational=True) == Eq(x, 0) + assert reduce_rational_inequalities( + [[Le(x**2, 0)]], x, relational=True) == Eq(x, 0) + assert reduce_rational_inequalities( + [[Lt(x**2, 0)]], x, relational=True) is False + assert reduce_rational_inequalities( + [[Ge(x**2, 0)]], x, relational=True) is True + assert reduce_rational_inequalities( + [[Gt(x**2, 0)]], x, relational=True) == Or(Lt(x, 0), Gt(x, 0)) + assert reduce_rational_inequalities( + [[Ne(x**2, 0)]], x, relational=True) == Or(Lt(x, 0), Gt(x, 0)) + + assert reduce_rational_inequalities( + [[Eq(x**2, 1)]], x, relational=True) == Or(Eq(x, -1), Eq(x, 1)) + assert reduce_rational_inequalities( + [[Le(x**2, 1)]], x, relational=True) == And(Le(-1, x), Le(x, 1)) + assert reduce_rational_inequalities( + [[Lt(x**2, 1)]], x, relational=True) == And(Lt(-1, x), Lt(x, 1)) + assert reduce_rational_inequalities( + [[Ge(x**2, 1)]], x, relational=True) == Or(Le(x, -1), Ge(x, 1)) + assert reduce_rational_inequalities( + [[Gt(x**2, 1)]], x, relational=True) == Or(Lt(x, -1), Gt(x, 1)) + assert reduce_rational_inequalities([[Ne(x**2, 1)]], x, relational=True) == Or( + Lt(x, -1), And(Lt(-1, x), Lt(x, 1)), Gt(x, 1)) + + assert reduce_rational_inequalities( + [[Le(x**2, 1.0)]], x, relational=True) == And(Le(-1.0, x), Le(x, 1.0)) + assert reduce_rational_inequalities( + [[Lt(x**2, 1.0)]], x, relational=True) == And(Lt(-1.0, x), Lt(x, 1.0)) + assert reduce_rational_inequalities( + [[Ge(x**2, 1.0)]], x, relational=True) == Or(Le(x, -1.0), Ge(x, 1.0)) + assert reduce_rational_inequalities( + [[Gt(x**2, 1.0)]], x, relational=True) == Or(Lt(x, -1.0), Gt(x, 1.0)) + assert reduce_rational_inequalities([[Ne(x**2, 1.0)]], x, relational=True) == \ + Or(Lt(x, -1.0), And(Lt(-1.0, x), Lt(x, 1.0)), Gt(x, 1.0)) - assert reduce_poly_inequalities([[Eq(x**2, 0)]], x, relational=True) == Eq(x, 0) - assert reduce_poly_inequalities([[Le(x**2, 0)]], x, relational=True) == Eq(x, 0) - assert reduce_poly_inequalities([[Lt(x**2, 0)]], x, relational=True) == False - assert reduce_poly_inequalities([[Ge(x**2, 0)]], x, relational=True) == True - assert reduce_poly_inequalities([[Gt(x**2, 0)]], x, relational=True) == Or(Lt(x, 0), Lt(0, x)) - assert reduce_poly_inequalities([[Ne(x**2, 0)]], x, relational=True) == Or(Lt(x, 0), Lt(0, x)) - - assert reduce_poly_inequalities([[Eq(x**2, 1)]], x, relational=True) == Or(Eq(x, -1), Eq(x, 1)) - assert reduce_poly_inequalities([[Le(x**2, 1)]], x, relational=True) == And(Le(-1, x), Le(x, 1)) - assert reduce_poly_inequalities([[Lt(x**2, 1)]], x, relational=True) == And(Lt(-1, x), Lt(x, 1)) - assert reduce_poly_inequalities([[Ge(x**2, 1)]], x, relational=True) == Or(Le(x, -1), Le(1, x)) - assert reduce_poly_inequalities([[Gt(x**2, 1)]], x, relational=True) == Or(Lt(x, -1), Lt(1, x)) - assert reduce_poly_inequalities([[Ne(x**2, 1)]], x, relational=True) == Or(Lt(x, -1), And(Lt(-1, x), Lt(x, 1)), Lt(1, x)) - - assert reduce_poly_inequalities([[Eq(x**2, 1.0)]], x, relational=True).evalf() == Or(Eq(x, -1.0), Eq(x, 1.0)).evalf() - assert reduce_poly_inequalities([[Le(x**2, 1.0)]], x, relational=True) == And(Le(-1.0, x), Le(x, 1.0)) - assert reduce_poly_inequalities([[Lt(x**2, 1.0)]], x, relational=True) == And(Lt(-1.0, x), Lt(x, 1.0)) - assert reduce_poly_inequalities([[Ge(x**2, 1.0)]], x, relational=True) == Or(Le(x, -1.0), Le(1.0, x)) - assert reduce_poly_inequalities([[Gt(x**2, 1.0)]], x, relational=True) == Or(Lt(x, -1.0), Lt(1.0, x)) - assert reduce_poly_inequalities([[Ne(x**2, 1.0)]], x, relational=True) == Or(Lt(x, -1.0), And(Lt(-1.0, x), Lt(x, 1.0)), Lt(1.0, x)) - - global_assumptions.remove(Q.real(x)) - global_assumptions.remove(Q.real(y)) def test_reduce_poly_inequalities_complex_relational(): cond = Eq(im(x), 0) - assert reduce_poly_inequalities([[Eq(x**2, 0)]], x, relational=True) == And(Eq(re(x), 0), cond) - assert reduce_poly_inequalities([[Le(x**2, 0)]], x, relational=True) == And(Eq(re(x), 0), cond) - assert reduce_poly_inequalities([[Lt(x**2, 0)]], x, relational=True) == False - assert reduce_poly_inequalities([[Ge(x**2, 0)]], x, relational=True) == cond - assert reduce_poly_inequalities([[Gt(x**2, 0)]], x, relational=True) == And(Or(Lt(re(x), 0), Lt(0, re(x))), cond) - assert reduce_poly_inequalities([[Ne(x**2, 0)]], x, relational=True) == And(Or(Lt(re(x), 0), Lt(0, re(x))), cond) - - assert reduce_poly_inequalities([[Eq(x**2, 1)]], x, relational=True) == And(Or(Eq(re(x), -1), Eq(re(x), 1)), cond) - assert reduce_poly_inequalities([[Le(x**2, 1)]], x, relational=True) == And(And(Le(-1, re(x)), Le(re(x), 1)), cond) - assert reduce_poly_inequalities([[Lt(x**2, 1)]], x, relational=True) == And(And(Lt(-1, re(x)), Lt(re(x), 1)), cond) - assert reduce_poly_inequalities([[Ge(x**2, 1)]], x, relational=True) == And(Or(Le(re(x), -1), Le(1, re(x))), cond) - assert reduce_poly_inequalities([[Gt(x**2, 1)]], x, relational=True) == And(Or(Lt(re(x), -1), Lt(1, re(x))), cond) - assert reduce_poly_inequalities([[Ne(x**2, 1)]], x, relational=True) == And(Or(Lt(re(x), -1), And(Lt(-1, re(x)), Lt(re(x), 1)), Lt(1, re(x))), cond) - - assert reduce_poly_inequalities([[Eq(x**2, 1.0)]], x, relational=True).evalf() == And(Or(Eq(re(x), -1.0), Eq(re(x), 1.0)), cond) - assert reduce_poly_inequalities([[Le(x**2, 1.0)]], x, relational=True) == And(And(Le(-1.0, re(x)), Le(re(x), 1.0)), cond) - assert reduce_poly_inequalities([[Lt(x**2, 1.0)]], x, relational=True) == And(And(Lt(-1.0, re(x)), Lt(re(x), 1.0)), cond) - assert reduce_poly_inequalities([[Ge(x**2, 1.0)]], x, relational=True) == And(Or(Le(re(x), -1.0), Le(1.0, re(x))), cond) - assert reduce_poly_inequalities([[Gt(x**2, 1.0)]], x, relational=True) == And(Or(Lt(re(x), -1.0), Lt(1.0, re(x))), cond) - assert reduce_poly_inequalities([[Ne(x**2, 1.0)]], x, relational=True) == And(Or(Lt(re(x), -1.0), And(Lt(-1.0, re(x)), Lt(re(x), 1.0)), Lt(1.0, re(x))), cond) + assert reduce_rational_inequalities( + [[Eq(x**2, 0)]], x, relational=True) == And(Eq(re(x), 0), cond) + assert reduce_rational_inequalities( + [[Le(x**2, 0)]], x, relational=True) == And(Eq(re(x), 0), cond) + assert reduce_rational_inequalities( + [[Lt(x**2, 0)]], x, relational=True) is False + assert reduce_rational_inequalities( + [[Ge(x**2, 0)]], x, relational=True) == cond + assert reduce_rational_inequalities([[Gt(x**2, 0)]], x, relational=True) == \ + And(Or(Lt(re(x), 0), Gt(re(x), 0)), cond) + assert reduce_rational_inequalities([[Ne(x**2, 0)]], x, relational=True) == \ + And(Or(Lt(re(x), 0), Gt(re(x), 0)), cond) + + assert reduce_rational_inequalities([[Eq(x**2, 1)]], x, relational=True) == \ + And(Or(Eq(re(x), -1), Eq(re(x), 1)), cond) + assert reduce_rational_inequalities([[Le(x**2, 1)]], x, relational=True) == \ + And(And(Le(-1, re(x)), Le(re(x), 1)), cond) + assert reduce_rational_inequalities([[Lt(x**2, 1)]], x, relational=True) == \ + And(And(Lt(-1, re(x)), Lt(re(x), 1)), cond) + assert reduce_rational_inequalities([[Ge(x**2, 1)]], x, relational=True) == \ + And(Or(Le(re(x), -1), Ge(re(x), 1)), cond) + assert reduce_rational_inequalities([[Gt(x**2, 1)]], x, relational=True) == \ + And(Or(Lt(re(x), -1), Gt(re(x), 1)), cond) + assert reduce_rational_inequalities([[Ne(x**2, 1)]], x, relational=True) == \ + And(Or(Lt(re(x), -1), And(Lt(-1, re(x)), Lt(re(x), 1)), Gt(re(x), 1)), cond) + + assert reduce_rational_inequalities([[Le(x**2, 1.0)]], x, relational=True) == \ + And(And(Le(-1.0, re(x)), Le(re(x), 1.0)), cond) + assert reduce_rational_inequalities([[Lt(x**2, 1.0)]], x, relational=True) == \ + And(And(Lt(-1.0, re(x)), Lt(re(x), 1.0)), cond) + assert reduce_rational_inequalities([[Ge(x**2, 1.0)]], x, relational=True) == \ + And(Or(Le(re(x), -1.0), Ge(re(x), 1.0)), cond) + assert reduce_rational_inequalities([[Gt(x**2, 1.0)]], x, relational=True) == \ + And(Or(Lt(re(x), -1.0), Gt(re(x), 1.0)), cond) + assert reduce_rational_inequalities([[Ne(x**2, 1.0)]], x, relational=True) == \ + And(Or(Lt(re(x), -1.0), And(Lt(-1.0, re(x)), Lt(re(x), 1.0)), Gt(re(x), 1.0)), cond) + + +def test_reduce_rational_inequalities_real_relational(): + def OpenInterval(a, b): + return Interval(a, b, True, True) + def LeftOpenInterval(a, b): + return Interval(a, b, True, False) + def RightOpenInterval(a, b): + return Interval(a, b, False, True) + + with assuming(Q.real(x)): + assert reduce_rational_inequalities([[(x**2 + 3*x + 2)/(x**2 - 16) >= 0]], x, relational=False) == \ + Union(OpenInterval(-oo, -4), Interval(-2, -1), OpenInterval(4, oo)) + + assert reduce_rational_inequalities([[((-2*x - 10)*(3 - x))/((x**2 + 5)*(x - 2)**2) < 0]], x, relational=False) == \ + Union(OpenInterval(-5, 2), OpenInterval(2, 3)) + + assert reduce_rational_inequalities([[(x + 1)/(x - 5) <= 0]], x, assume=Q.real(x), relational=False) == \ + RightOpenInterval(-1, 5) + + assert reduce_rational_inequalities([[(x**2 + 4*x + 3)/(x - 1) > 0]], x, assume=Q.real(x), relational=False) == \ + Union(OpenInterval(-3, -1), OpenInterval(1, oo)) + + assert reduce_rational_inequalities([[(x**2 - 16)/(x - 1)**2 < 0]], x, assume=Q.real(x), relational=False) == \ + Union(OpenInterval(-4, 1), OpenInterval(1, 4)) + + assert reduce_rational_inequalities([[(3*x + 1)/(x + 4) >= 1]], x, assume=Q.real(x), relational=False) == \ + Union(OpenInterval(-oo, -4), RightOpenInterval(S(3)/2, oo)) + + assert reduce_rational_inequalities([[(x - 8)/x <= 3 - x]], x, assume=Q.real(x), relational=False) == \ + Union(LeftOpenInterval(-oo, -2), LeftOpenInterval(0, 4)) + def test_reduce_abs_inequalities(): real = Q.real(x) - assert reduce_inequalities(abs(x - 5) < 3, assume=real) == And(Lt(2, x), Lt(x, 8)) - assert reduce_inequalities(abs(2*x + 3) >= 8, assume=real) == Or(Le(x, -S(11)/2), Le(S(5)/2, x)) - assert reduce_inequalities(abs(x - 4) + abs(3*x - 5) < 7, assume=real) == And(Lt(S(1)/2, x), Lt(x, 4)) + assert reduce_inequalities( + abs(x - 5) < 3, assume=real) == And(Lt(2, x), Lt(x, 8)) + assert reduce_inequalities( + abs(2*x + 3) >= 8, assume=real) == Or(Le(x, -S(11)/2), Ge(x, S(5)/2)) + assert reduce_inequalities(abs(x - 4) + abs( + 3*x - 5) < 7, assume=real) == And(Lt(S(1)/2, x), Lt(x, 4)) assert reduce_inequalities(abs(x - 4) + abs(3*abs(x) - 5) < 7, assume=real) == Or(And(S(-2) < x, x < -1), And(S(1)/2 < x, x < 4)) raises(NotImplementedError, lambda: reduce_inequalities(abs(x - 5) < 3)) + def test_reduce_inequalities_boolean(): - assert reduce_inequalities([Eq(x**2, 0), True]) == And(Eq(re(x), 0), Eq(im(x), 0)) - assert reduce_inequalities([Eq(x**2, 0), False]) == False + assert reduce_inequalities( + [Eq(x**2, 0), True]) == And(Eq(re(x), 0), Eq(im(x), 0)) + assert reduce_inequalities([Eq(x**2, 0), False]) is False + def test_reduce_inequalities_assume(): - assert reduce_inequalities([Le(x**2, 1), Q.real(x)]) == And(Le(-1, x), Le(x, 1)) - assert reduce_inequalities([Le(x**2, 1)], Q.real(x)) == And(Le(-1, x), Le(x, 1)) + assert reduce_inequalities( + [Le(x**2, 1), Q.real(x)]) == And(Le(-1, x), Le(x, 1)) + assert reduce_inequalities( + [Le(x**2, 1)], Q.real(x)) == And(Le(-1, x), Le(x, 1)) + def test_reduce_inequalities_multivariate(): assert reduce_inequalities([Ge(x**2, 1), Ge(y**2, 1)]) == \ - And(And(Or(Le(re(x), -1), Le(1, re(x))), Eq(im(x), 0)), - And(Or(Le(re(y), -1), Le(1, re(y))), Eq(im(y), 0))) + And(And(Or(Le(re(x), -1), Ge(re(x), 1)), Eq(im(x), 0)), + And(Or(Le(re(y), -1), Ge(re(y), 1)), Eq(im(y), 0))) + def test_reduce_inequalities_errors(): raises(NotImplementedError, lambda: reduce_inequalities(Ge(sin(x) + x, 1))) raises(NotImplementedError, lambda: reduce_inequalities(Ge(x**2*y + y, 1))) raises(NotImplementedError, lambda: reduce_inequalities(Ge(sqrt(2)*x, 1))) + def test_hacky_inequalities(): assert reduce_inequalities(x + y < 1, symbols=[x]) == (x < 1 - y) assert reduce_inequalities(x + y >= 1, symbols=[x]) == (x >= 1 - y) + def test_issue_3244(): eq = -3*x**2/2 - 45*x/4 + S(33)/2 > 0 assert reduce_inequalities(eq, Q.real(x)) == \ diff -Nru python3-sympy-0.7.2/sympy/solvers/tests/test_numeric.py python3-sympy-0.7.3/sympy/solvers/tests/test_numeric.py --- python3-sympy-0.7.2/sympy/solvers/tests/test_numeric.py 2012-10-17 03:02:22.000000000 +0000 +++ python3-sympy-0.7.3/sympy/solvers/tests/test_numeric.py 2013-07-13 17:53:32.000000000 +0000 @@ -4,16 +4,17 @@ from sympy.utilities.lambdify import lambdify from sympy.utilities.pytest import raises, XFAIL + def test_nsolve(): # onedimensional x = Symbol('x') assert nsolve(sin(x), 2) - pi.evalf() < 1e-15 assert nsolve(Eq(2*x, 2), x, -10) == nsolve(2*x - 2, -10) # Testing checks on number of inputs - raises(TypeError, lambda: nsolve(Eq(2*x,2))) - raises(TypeError, lambda: nsolve(Eq(2*x,2),x,1,2)) + raises(TypeError, lambda: nsolve(Eq(2*x, 2))) + raises(TypeError, lambda: nsolve(Eq(2*x, 2), x, 1, 2)) # Issue 1730 - assert nsolve(x**2/(1-x)/(1-2*x)**2-100, x, 0) # doesn't fail + assert nsolve(x**2/(1 - x)/(1 - 2*x)**2 - 100, x, 0) # doesn't fail # multidimensional x1 = Symbol('x1') x2 = Symbol('x2') @@ -23,32 +24,36 @@ F = lambdify((x1, x2), f.T, modules='mpmath') for x0 in [(-1, 1), (1, -2), (4, 4), (-4, -4)]: x = nsolve(f, (x1, x2), x0, tol=1.e-8) - assert mnorm(F(*x),1) <= 1.e-10 + assert mnorm(F(*x), 1) <= 1.e-10 # The Chinese mathematician Zhu Shijie was the very first to solve this # nonlinear system 700 years ago (z was added to make it 3-dimensional) x = Symbol('x') y = Symbol('y') z = Symbol('z') f1 = -x + 2*y - f2 = (x**2 + x*(y**2 - 2) - 4*y) / (x + 4) + f2 = (x**2 + x*(y**2 - 2) - 4*y) / (x + 4) f3 = sqrt(x**2 + y**2)*z f = Matrix((f1, f2, f3)).T F = lambdify((x, y, z), f.T, modules='mpmath') + def getroot(x0): root = nsolve(f, (x, y, z), x0) - assert mnorm(F(*root),1) <= 1.e-8 + assert mnorm(F(*root), 1) <= 1.e-8 return root assert list(map(round, getroot((1, 1, 1)))) == [2.0, 1.0, 0.0] - assert nsolve([Eq(f1), Eq(f2), Eq(f3)], [x, y, z], (1, 1, 1)) # just see that it works + assert nsolve([Eq( + f1), Eq(f2), Eq(f3)], [x, y, z], (1, 1, 1)) # just see that it works a = Symbol('a') assert nsolve(1/(0.001 + a)**3 - 6/(0.9 - a)**3, a, 0.3).ae( mpf('0.31883011387318591')) + def test_issue_3309(): x = Symbol('x') - assert nsolve(Piecewise((x,x<1),(x**2,True)),x,2) == 0.0 + assert nsolve(Piecewise((x, x < 1), (x**2, True)), x, 2) == 0.0 + @XFAIL def test_issue_3309_fail(): x, y = symbols('x y') - assert nsolve(Integral(x*y,(x,0,5)),y,2) == 0.0 + assert nsolve(Integral(x*y, (x, 0, 5)), y, 2) == 0.0 diff -Nru python3-sympy-0.7.2/sympy/solvers/tests/test_ode.py python3-sympy-0.7.3/sympy/solvers/tests/test_ode.py --- python3-sympy-0.7.2/sympy/solvers/tests/test_ode.py 2012-10-17 03:02:22.000000000 +0000 +++ python3-sympy-0.7.3/sympy/solvers/tests/test_ode.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,17 +1,18 @@ -from sympy import (acos, acosh, asinh, atan, cos, Derivative, diff, dsolve, Eq, - erf, exp, Function, I, Integral, LambertW, log, O, pi, - Rational, RootOf, S, simplify, sin, sqrt, Symbol, tan, asin, - Piecewise, symbols) -x,y,z = symbols('x:z', real=True) +from sympy import (acos, acosh, asinh, atan, cos, Derivative, diff, dsolve, + Dummy, Eq, erf, erfi, exp, Function, I, Integral, LambertW, log, O, pi, + Rational, RootOf, S, simplify, sin, sqrt, Symbol, tan, asin, + Piecewise, symbols, Poly) from sympy.solvers.ode import (_undetermined_coefficients_match, checkodesol, - classify_ode, constant_renumber, constantsimp, - homogeneous_order, ode_order) + classify_ode, constant_renumber, constantsimp, + homogeneous_order, infinitesimals, checkinfsol) +from sympy.solvers.deutils import ode_order from sympy.utilities.pytest import XFAIL, skip, raises, slow C1, C2, C3, C4, C5, C6, C7, C8, C9, C10 = symbols('C1:11') +x, y, z = symbols('x:z', real=True) f = Function('f') g = Function('g') @@ -24,11 +25,13 @@ # constant_renumber because it will normalize it (constant_renumber causes # dsolve() to return different results on different machines) + def test_checkodesol(): # For the most part, checkodesol is well tested in the tests below. # These tests only handle cases not checked below. raises(ValueError, lambda: checkodesol(f(x, y).diff(x), Eq(f(x, y), x))) - raises(ValueError, lambda: checkodesol(f(x).diff(x), Eq(f(x, y), x), f(x, y))) + raises(ValueError, lambda: checkodesol(f(x).diff(x), Eq(f(x, y), + x), f(x, y))) assert checkodesol(f(x).diff(x), Eq(f(x, y), x)) == \ (False, -f(x).diff(x) + f(x, y).diff(x) - 1) assert checkodesol(f(x).diff(x), Eq(f(x), x)) is not True @@ -41,18 +44,18 @@ assert checkodesol(diff(sol1.lhs, x, 3), sol1) == (True, 0) assert checkodesol(diff(sol1.lhs, x, 3)*exp(f(x)), sol1) == (True, 0) assert checkodesol(diff(sol1.lhs, x, 3), Eq(f(x), x*log(x))) == \ - (False, -9 + 60*x**4*log(x)**2 + 240*x**4*log(x)**3 + - 235*x**4*log(x)**4 + 60*x**4*log(x)**5) + (False, 60*x**4*((log(x) + 1)**2 + log(x))*( + log(x) + 1)*log(x)**2 - 5*x**4*log(x)**4 - 9) assert checkodesol(diff(exp(f(x)) + x, x)*x, Eq(exp(f(x)) + x)) == \ (True, 0) - assert checkodesol(diff(exp(f(x)) + x, x)*x, Eq(exp(f(x)) + x), \ + assert checkodesol(diff(exp(f(x)) + x, x)*x, Eq(exp(f(x)) + x), solve_for_func=False) == (True, 0) - assert checkodesol(f(x).diff(x, 2), [Eq(f(x), C1 + C2*x), \ + assert checkodesol(f(x).diff(x, 2), [Eq(f(x), C1 + C2*x), Eq(f(x), C2 + C1*x), Eq(f(x), C1*x + C2*x**2)]) == \ - [(True, 0), (True, 0), (False, 2*C2)] - assert checkodesol(f(x).diff(x, 2), set([Eq(f(x), C1 + C2*x), \ + [(True, 0), (True, 0), (False, 2*C2)] + assert checkodesol(f(x).diff(x, 2), set([Eq(f(x), C1 + C2*x), Eq(f(x), C2 + C1*x), Eq(f(x), C1*x + C2*x**2)])) == \ - set([(True, 0), (True, 0), (False, 2*C2)]) + set([(True, 0), (True, 0), (False, 2*C2)]) assert checkodesol(f(x).diff(x) - 1/f(x)/2, Eq(f(x)**2, x)) == \ [(True, 0), (True, 0)] assert checkodesol(f(x).diff(x) - f(x), Eq(C1*exp(x), f(x))) == (True, 0) @@ -62,22 +65,27 @@ sol3 = Eq(f(x), log(log(C1/x)**(-x))) assert not checkodesol(eq3, sol3)[1].has(f(x)) + def test_dsolve_options(): eq = x*f(x).diff(x) + f(x) a = dsolve(eq, hint='all') b = dsolve(eq, hint='all', simplify=False) c = dsolve(eq, hint='all_Integral') - keys = ['1st_exact', '1st_exact_Integral', '1st_homogeneous_coeff_best', \ - '1st_homogeneous_coeff_subs_dep_div_indep', \ - '1st_homogeneous_coeff_subs_dep_div_indep_Integral', \ - '1st_homogeneous_coeff_subs_indep_div_dep', \ - '1st_homogeneous_coeff_subs_indep_div_dep_Integral', '1st_linear', \ - '1st_linear_Integral', 'best', 'best_hint', 'default', 'order', \ + keys = ['1st_exact', '1st_exact_Integral', '1st_homogeneous_coeff_best', + '1st_homogeneous_coeff_subs_dep_div_indep', + '1st_homogeneous_coeff_subs_dep_div_indep_Integral', + '1st_homogeneous_coeff_subs_indep_div_dep', + '1st_homogeneous_coeff_subs_indep_div_dep_Integral', '1st_linear', + '1st_linear_Integral', 'almost_linear', 'almost_linear_Integral', + 'best', 'best_hint', 'default', + 'nth_linear_euler_eq_homogeneous', 'order', 'separable', 'separable_Integral'] Integral_keys = ['1st_exact_Integral', - '1st_homogeneous_coeff_subs_dep_div_indep_Integral', - '1st_homogeneous_coeff_subs_indep_div_dep_Integral', '1st_linear_Integral', - 'best', 'best_hint', 'default', 'order', 'separable_Integral'] + '1st_homogeneous_coeff_subs_dep_div_indep_Integral', + '1st_homogeneous_coeff_subs_indep_div_dep_Integral', '1st_linear_Integral', + 'almost_linear_Integral', 'best', 'best_hint', 'default', + 'nth_linear_euler_eq_homogeneous', + 'order', 'separable_Integral'] assert sorted(a.keys()) == keys assert a['order'] == ode_order(eq, f(x)) assert a['best'] == Eq(f(x), C1/x) @@ -126,6 +134,8 @@ hint="1st_linear_Integral") == \ Eq(f(x), (C1 + Integral((-sin(x).diff(x) - 1)* exp(Integral(1, x)), x))*exp(-Integral(1, x))) + + def test_classify_ode(): assert classify_ode(f(x).diff(x, 2), f(x)) == \ ('nth_linear_constant_coeff_homogeneous', 'Liouville', @@ -145,61 +155,70 @@ a = classify_ode(Eq(f(x).diff(x) + f(x), x), f(x)) b = classify_ode(f(x).diff(x)*f(x) + f(x)*f(x) - x*f(x), f(x)) c = classify_ode(f(x).diff(x)/f(x) + f(x)/f(x) - x/f(x), f(x)) - assert a == b == c != () + assert a == ('1st_linear', + 'Bernoulli', + 'almost_linear', + 'nth_linear_constant_coeff_undetermined_coefficients', + 'nth_linear_constant_coeff_variation_of_parameters', + '1st_linear_Integral', + 'Bernoulli_Integral', + 'almost_linear_Integral', + 'nth_linear_constant_coeff_variation_of_parameters_Integral') + assert b == c != () assert classify_ode( 2*x*f(x)*f(x).diff(x) + (1 + x)*f(x)**2 - exp(x), f(x) - ) == ('Bernoulli', 'Bernoulli_Integral') - assert 'Riccati_special_minus2' in\ + ) == ('Bernoulli', 'almost_linear', 'Bernoulli_Integral', 'almost_linear_Integral') + assert 'Riccati_special_minus2' in \ classify_ode(2*f(x).diff(x) + f(x)**2 - f(x)/x + 3*x**(-2), f(x)) - raises(ValueError, lambda: classify_ode(x + f(x, y).diff(x).diff(y), f(x, y))) + raises(ValueError, lambda: classify_ode(x + f(x, y).diff(x).diff( + y), f(x, y))) # 2077 k = Symbol('k') - assert classify_ode(f(x).diff(x)/(k*f(x) + k*x*f(x)) + - 2*f(x)/(k*f(x) + k*x*f(x)) + - x*f(x).diff(x)/(k*f(x) + k*x*f(x)) - + z, f(x)) == ('separable', - '1st_exact', - 'separable_Integral', - '1st_exact_Integral') + assert classify_ode(f(x).diff(x)/(k*f(x) + k*x*f(x)) + 2*f(x)/(k*f(x) + + k*x*f(x)) + x*f(x).diff(x)/(k*f(x) + k*x*f(x)) + z, f(x)) == \ + ('separable', '1st_exact', 'separable_Integral', '1st_exact_Integral') # preprocessing ans = ('separable', '1st_exact', '1st_linear', 'Bernoulli', '1st_homogeneous_coeff_best', '1st_homogeneous_coeff_subs_indep_div_dep', '1st_homogeneous_coeff_subs_dep_div_indep', + 'separable_reduced', 'nth_linear_constant_coeff_undetermined_coefficients', 'nth_linear_constant_coeff_variation_of_parameters', 'separable_Integral', '1st_exact_Integral', '1st_linear_Integral', 'Bernoulli_Integral', '1st_homogeneous_coeff_subs_indep_div_dep_Integral', - '1st_homogeneous_coeff_subs_dep_div_indep_Integral', - 'nth_linear_constant_coeff_variation_of_parameters_Integral') + '1st_homogeneous_coeff_subs_dep_div_indep_Integral', + 'separable_reduced_Integral', + 'nth_linear_constant_coeff_variation_of_parameters_Integral') # w/o f(x) given assert classify_ode(diff(f(x) + x, x) + diff(f(x), x)) == ans # w/ f(x) and prep=True assert classify_ode(diff(f(x) + x, x) + diff(f(x), x), f(x), prep=True) == ans + def test_ode_order(): f = Function('f') g = Function('g') x = Symbol('x') assert ode_order(3*x*exp(f(x)), f(x)) == 0 - assert ode_order(x*diff(f(x),x)+3*x*f(x)-sin(x)/x, f(x)) == 1 - assert ode_order(x**2*f(x).diff(x,x)+x*diff(f(x),x)-f(x),f(x)) == 2 - assert ode_order(diff(x*exp(f(x)),x,x), f(x)) == 2 - assert ode_order(diff(x*diff(x*exp(f(x)), x,x), x), f(x)) == 3 + assert ode_order(x*diff(f(x), x) + 3*x*f(x) - sin(x)/x, f(x)) == 1 + assert ode_order(x**2*f(x).diff(x, x) + x*diff(f(x), x) - f(x), f(x)) == 2 + assert ode_order(diff(x*exp(f(x)), x, x), f(x)) == 2 + assert ode_order(diff(x*diff(x*exp(f(x)), x, x), x), f(x)) == 3 assert ode_order(diff(f(x), x, x), g(x)) == 0 assert ode_order(diff(f(x), x, x)*diff(g(x), x), f(x)) == 2 assert ode_order(diff(f(x), x, x)*diff(g(x), x), g(x)) == 1 - assert ode_order(diff(x*diff(x*exp(f(x)), x,x), x), g(x)) == 0 + assert ode_order(diff(x*diff(x*exp(f(x)), x, x), x), g(x)) == 0 # issue 2736: ode_order has to also work for unevaluated derivatives # (ie, without using doit()). assert ode_order(Derivative(x*f(x), x), f(x)) == 1 assert ode_order(x*sin(Derivative(x*f(x)**2, x, x)), f(x)) == 2 - assert ode_order(Derivative(x*Derivative(x*exp(f(x)), x,x), x), g(x)) == 0 + assert ode_order(Derivative(x*Derivative(x*exp(f(x)), x, x), x), g(x)) == 0 assert ode_order(Derivative(f(x), x, x), g(x)) == 0 - assert ode_order(Derivative(x*exp(f(x)),x,x), f(x)) == 2 + assert ode_order(Derivative(x*exp(f(x)), x, x), f(x)) == 2 assert ode_order(Derivative(f(x), x, x)*Derivative(g(x), x), g(x)) == 1 assert ode_order(Derivative(x*Derivative(f(x), x, x), x), f(x)) == 3 assert ode_order( @@ -219,20 +238,20 @@ eq5 = Eq(9*f(x).diff(x, x), f(x)) # Type: a(x)f'(x)+b(x)*f(x)+c(x)=0 eq6 = Eq(x**2*f(x).diff(x) + 3*x*f(x) - sin(x)/x, 0) - eq7 = Eq(f(x).diff(x,x) - 3*diff(f(x),x) + 2*f(x), 0) + eq7 = Eq(f(x).diff(x, x) - 3*diff(f(x), x) + 2*f(x), 0) # Type: 2nd order, constant coefficients (two real different roots) - eq8 = Eq(f(x).diff(x,x) - 4*diff(f(x),x) + 4*f(x), 0) + eq8 = Eq(f(x).diff(x, x) - 4*diff(f(x), x) + 4*f(x), 0) # Type: 2nd order, constant coefficients (two real equal roots) - eq9 = Eq(f(x).diff(x,x)+2*diff(f(x),x)+3*f(x), 0) + eq9 = Eq(f(x).diff(x, x) + 2*diff(f(x), x) + 3*f(x), 0) # Type: 2nd order, constant coefficients (two complex roots) - eq10 = Eq(3*f(x).diff(x) -1,0) - eq11 = Eq(x*f(x).diff(x) -1,0) + eq10 = Eq(3*f(x).diff(x) - 1, 0) + eq11 = Eq(x*f(x).diff(x) - 1, 0) sol1 = Eq(f(x), C1) - sol2 = Eq(f(x), C1+5*x/3) - sol3 = Eq(f(x), C1+5*x/3) + sol2 = Eq(f(x), C1 + 5*x/3) + sol3 = Eq(f(x), C1 + 5*x/3) sol4 = Eq(f(x), C1*sin(x/3) + C2*cos(x/3)) sol5 = Eq(f(x), C1*exp(-x/3) + C2*exp(x/3)) - sol6 = Eq(f(x), (C1-cos(x))/x**3) + sol6 = Eq(f(x), (C1 - cos(x))/x**3) sol7 = Eq(f(x), C1*exp(x) + C2*exp(2*x)) sol8 = Eq(f(x), (C1 + C2*x)*exp(2*x)) sol9 = Eq(f(x), (C1*sin(x*sqrt(2)) + C2*cos(x*sqrt(2)))*exp(-x)) @@ -262,28 +281,31 @@ assert checkodesol(eq10, sol10, order=1, solve_for_func=False)[0] assert checkodesol(eq11, sol11, order=1, solve_for_func=False)[0] + def test_1st_linear(): # Type: first order linear form f'(x)+p(x)f(x)=q(x) eq = Eq(f(x).diff(x) + x*f(x), x**2) - sol = Eq(f(x),exp(-x**2/2)*(sqrt(2)*sqrt(pi)*I*erf(I*x/sqrt(2))/2 \ - + x*exp(x**2/2) + C1)) + sol = Eq(f(x), (C1 + x*exp(x**2/2) + - sqrt(2)*sqrt(pi)*erfi(sqrt(2)*x/2)/2)*exp(-x**2/2)) assert dsolve(eq, hint='1st_linear') == sol assert checkodesol(eq, sol, order=1, solve_for_func=False)[0] def test_Bernoulli(): # Type: Bernoulli, f'(x) + p(x)*f(x) == q(x)*f(x)**n - eq = Eq(x*f(x).diff(x) + f(x) - f(x)**2,0) - sol = dsolve(eq,f(x), hint='Bernoulli') - assert sol == Eq(f(x),1/(x*(C1 + 1/x))) + eq = Eq(x*f(x).diff(x) + f(x) - f(x)**2, 0) + sol = dsolve(eq, f(x), hint='Bernoulli') + assert sol == Eq(f(x), 1/(x*(C1 + 1/x))) assert checkodesol(eq, sol, order=1, solve_for_func=False)[0] + def test_Riccati_special_minus2(): # Type: Riccati special alpha = -2, a*dy/dx + b*y**2 + c*y/x +d/x**2 eq = 2*f(x).diff(x) + f(x)**2 - f(x)/x + 3*x**(-2) - sol = dsolve(eq,f(x), hint='Riccati_special_minus2') + sol = dsolve(eq, f(x), hint='Riccati_special_minus2') assert checkodesol(eq, sol, order=1, solve_for_func=False)[0] + def test_1st_exact1(): # Type: Exact differential equation, p(x,f) + q(x,f)*f' == 0, # where dp/df == dq/dx @@ -292,22 +314,26 @@ eq3 = 2*x + f(x)*cos(x) + (2*f(x) + sin(x) - sin(f(x)))*f(x).diff(x) eq4 = cos(f(x)) - (x*sin(f(x)) - f(x)**2)*f(x).diff(x) eq5 = 2*x*f(x) + (x**2 + f(x)**2)*f(x).diff(x) - sol1 = Eq(f(x),acos((C1)/cos(x))) - sol2 = Eq(log(f(x))+x/f(x)+x**2,C1) - sol3 = Eq(f(x)*sin(x)+cos(f(x))+x**2+f(x)**2,C1) - sol4 = Eq(x*cos(f(x))+f(x)**3/3,C1) + sol1 = [Eq(f(x), -acos(C1/cos(x)) + 2*pi), Eq(f(x), acos(C1/cos(x)))] + sol2 = Eq(f(x), C1*exp(-x**2 + LambertW(C2*x*exp(x**2)))) + sol2b = Eq(log(f(x)) + x/f(x) + x**2, C1) + sol3 = Eq(f(x)*sin(x) + cos(f(x)) + x**2 + f(x)**2, C1) + sol4 = Eq(x*cos(f(x)) + f(x)**3/3, C1) sol5 = Eq(x**2*f(x) + f(x)**3/3, C1) - assert dsolve(eq1,f(x), hint='1st_exact') == sol1 - assert dsolve(eq2,f(x), hint='1st_exact') == sol2 - assert dsolve(eq3,f(x), hint='1st_exact') == sol3 + assert dsolve(eq1, f(x), hint='1st_exact') == sol1 + assert dsolve(eq2, f(x), hint='1st_exact') == sol2 + assert dsolve(eq3, f(x), hint='1st_exact') == sol3 assert dsolve(eq4, hint='1st_exact') == sol4 assert dsolve(eq5, hint='1st_exact', simplify=False) == sol5 assert checkodesol(eq1, sol1, order=1, solve_for_func=False)[0] - assert checkodesol(eq2, sol2, order=1, solve_for_func=False)[0] + # issue 1981 needs to be addressed to test these + # assert checkodesol(eq2, sol2, order=1, solve_for_func=False)[0] + assert checkodesol(eq2, sol2b, order=1, solve_for_func=False)[0] assert checkodesol(eq3, sol3, order=1, solve_for_func=False)[0] assert checkodesol(eq4, sol4, order=1, solve_for_func=False)[0] assert checkodesol(eq5, sol5, order=1, solve_for_func=False)[0] + @slow @XFAIL def test_1st_exact2(): @@ -333,6 +359,7 @@ (x*(-27*f(x)/x + 27*sqrt(1 + f(x)**2/x**2)))) assert checkodesol(eq, sol, order=1, solve_for_func=False)[0] + def test_separable1(): # test_separable1-5 are from Ordinary Differential Equations, Tenenbaum and # Pollard, pg. 55 @@ -359,6 +386,7 @@ assert checkodesol(eq4, sol4, order=1, solve_for_func=False)[0] assert checkodesol(eq5, sol5, order=1, solve_for_func=False)[0] + def test_separable2(): a = Symbol('a') eq6 = f(x)*x**2*f(x).diff(x) - f(x)**3 - 2*x**2*f(x).diff(x) @@ -370,9 +398,9 @@ # solve() messes this one up a little bit, so lets test _Integral here # We have to test strings with _Integral because y is a dummy variable. sol6str = ("Integral((_y - 2)/_y**3, (_y, f(x))) " - "== C1 + Integral(x**(-2), x)") + "== C1 + Integral(x**(-2), x)") sol7 = Eq(-log(-1 + f(x)**2)/2, C1 - log(2 + x)) - sol8 = Eq(asinh(f(x)), C1 - log(log(x))) + sol8 = Eq(asinh(f(x)), C1 + log(x) - log(x*log(x))) # integrate cannot handle the integral on the lhs (cos/tan) sol9str = ("Integral(cos(_y)/tan(_y), (_y, f(x)))" " == C1 + Integral(-E*exp(x), x)") @@ -386,19 +414,21 @@ assert checkodesol(eq8, sol8, order=1, solve_for_func=False)[0] assert checkodesol(eq10, sol10, order=1, solve_for_func=False)[0] + def test_separable3(): eq11 = f(x).diff(x) - f(x)*tan(x) eq12 = (x - 1)*cos(f(x))*f(x).diff(x) - 2*x*sin(f(x)) eq13 = f(x).diff(x) - f(x)*log(f(x))/tan(x) sol11 = Eq(f(x), C1*sqrt(1 + tan(x)**2)) sol12 = Eq(log(-1 + cos(f(x))**2)/2, C1 + 2*x + 2*log(x - 1)) - sol13 = Eq(log(log(f(x))), C1 + log(cos(x)**2 - 1)/2 ) + sol13 = Eq(log(f(x)*log(f(x))) - log(f(x)), C1 + log(cos(x)**2 - 1)/2 ) assert dsolve(eq11, hint='separable') == simplify(sol11) assert dsolve(eq12, hint='separable', simplify=False) == sol12 assert dsolve(eq13, hint='separable', simplify=False) == sol13 assert checkodesol(eq11, sol11, order=1, solve_for_func=False)[0] assert checkodesol(eq13, sol13, order=1, solve_for_func=False)[0] + def test_separable4(): # This has a slow integral (1/((1 + y**2)*atan(y))), so we isolate it. eq14 = x*f(x).diff(x) + (1 + f(x)**2)*atan(f(x)) @@ -406,6 +436,7 @@ assert dsolve(eq14, hint='separable', simplify=False) == sol14 assert checkodesol(eq14, sol14, order=1, solve_for_func=False)[0] + def test_separable5(): eq15 = f(x).diff(x) + x*(f(x) + 1) eq16 = exp(f(x)**2)*(x**2 + 2*x + 1) + (x*f(x) + f(x))*f(x).diff(x) @@ -418,147 +449,129 @@ sol16 = Eq(-exp(-f(x)**2)/2, C1 - x - x**2/2) sol17 = Eq(f(x), C1*exp(-x)) sol18 = Eq(-log(-1 + sin(2*f(x))**2)/4, C1 + log(-1 + sin(x)**2)/2) - sol19a = Eq(f(x), -(1 - x - C1*exp(-x))/(1 - x)) - sol19b = Eq(f(x), -1 + C1*exp(-x)/(-1 + x)) - sol19c = Eq(f(x), -1/(1 - x) + x/(1 - x) + C1*exp(-x)/(1 - x)) - sol19d = Eq(f(x), (C1*(1 - x) + x*(-x*exp(x) + exp(x))- exp(x) + x*exp(x))/ - ((1 - x)*(-x*exp(x) + exp(x)))) - sol19e = Eq(f(x), (C1*(1 - x) - x*(-x*exp(x) + exp(x)) - - x*exp(x) + exp(x))/((1 - x)*(-exp(x) + x*exp(x)))) - sol19f = Eq(f(x), (C1 + (x - 1)*exp(x))*exp(-x)/(-x + 1)) - sol19g = Eq(f(x), (C1*exp(-x) - x + 1)/(x - 1)) + sol19 = Eq(f(x), (C1*exp(-x) - x + 1)/(x - 1)) sol20 = Eq(log(-1 + 3*f(x)**2)/6, C1 + x**2/2) sol21 = Eq(-exp(-f(x)), C1 + exp(x)) assert dsolve(eq15, hint='separable') == sol15 assert dsolve(eq16, hint='separable', simplify=False) == sol16 assert dsolve(eq17, hint='separable') == sol17 assert dsolve(eq18, hint='separable', simplify=False) == sol18 - assert dsolve(eq19, hint='separable') in [sol19g, sol19f, sol19a, sol19b, sol19c, - sol19d, sol19e] + assert dsolve(eq19, hint='separable') == sol19 assert dsolve(eq20, hint='separable', simplify=False) == sol20 assert dsolve(eq21, hint='separable', simplify=False) == sol21 assert checkodesol(eq15, sol15, order=1, solve_for_func=False)[0] assert checkodesol(eq16, sol16, order=1, solve_for_func=False)[0] assert checkodesol(eq17, sol17, order=1, solve_for_func=False)[0] assert checkodesol(eq18, sol18, order=1, solve_for_func=False)[0] - assert checkodesol(eq19, sol19a, order=1, solve_for_func=False)[0] + assert checkodesol(eq19, sol19, order=1, solve_for_func=False)[0] assert checkodesol(eq20, sol20, order=1, solve_for_func=False)[0] assert checkodesol(eq21, sol21, order=1, solve_for_func=False)[0] + def test_separable_1_5_checkodesol(): eq12 = (x - 1)*cos(f(x))*f(x).diff(x) - 2*x*sin(f(x)) sol12 = Eq(-log(1 - cos(f(x))**2)/2, C1 - 2*x - 2*log(1 - x)) assert checkodesol(eq12, sol12, order=1, solve_for_func=False)[0] + def test_homogeneous_order(): assert homogeneous_order(exp(y/x) + tan(y/x), x, y) == 0 - assert homogeneous_order(x**2 + sin(x)*cos(y), x, y) == None + assert homogeneous_order(x**2 + sin(x)*cos(y), x, y) is None assert homogeneous_order(x - y - x*sin(y/x), x, y) == 1 - assert homogeneous_order((x*y + sqrt(x**4+y**4) + x**2*(log(x) - log(y)))/\ - (pi*x**Rational(2,3)*sqrt(y)**3), x, y) == Rational(-1,6) + assert homogeneous_order((x*y + sqrt(x**4 + y**4) + x**2*(log(x) - log(y)))/ + (pi*x**Rational(2, 3)*sqrt(y)**3), x, y) == Rational(-1, 6) assert homogeneous_order(y/x*cos(y/x) - x/y*sin(y/x) + cos(y/x), x, y) == 0 assert homogeneous_order(f(x), x, f(x)) == 1 assert homogeneous_order(f(x)**2, x, f(x)) == 2 assert homogeneous_order(x*y*z, x, y) == 2 assert homogeneous_order(x*y*z, x, y, z) == 3 - assert homogeneous_order(x**2*f(x)/sqrt(x**2 + f(x)**2), f(x)) == None - assert homogeneous_order(f(x,y)**2, x, f(x,y), y) == 2 - assert homogeneous_order(f(x,y)**2, x, f(x), y) == None - assert homogeneous_order(f(x,y)**2, x, f(x,y)) == None - assert homogeneous_order(f(y,x)**2, x, y, f(x, y)) == None - assert homogeneous_order(f(y), f(x), x) == None + assert homogeneous_order(x**2*f(x)/sqrt(x**2 + f(x)**2), f(x)) is None + assert homogeneous_order(f(x, y)**2, x, f(x, y), y) == 2 + assert homogeneous_order(f(x, y)**2, x, f(x), y) is None + assert homogeneous_order(f(x, y)**2, x, f(x, y)) is None + assert homogeneous_order(f(y, x)**2, x, y, f(x, y)) is None + assert homogeneous_order(f(y), f(x), x) is None assert homogeneous_order(-f(x)/x + 1/sin(f(x)/ x), f(x), x) == 0 - assert homogeneous_order(log(1/y) + log(x**2), x, y) == None + assert homogeneous_order(log(1/y) + log(x**2), x, y) is None assert homogeneous_order(log(1/y) + log(x), x, y) == 0 assert homogeneous_order(log(x/y), x, y) == 0 assert homogeneous_order(2*log(1/y) + 2*log(x), x, y) == 0 a = Symbol('a') assert homogeneous_order(a*log(1/y) + a*log(x), x, y) == 0 - assert homogeneous_order(f(x).diff(x), x, y) == None - assert homogeneous_order(-f(x).diff(x) + x, x, y) == None - assert homogeneous_order(O(x), x, y) == None - assert homogeneous_order(x + O(x**2), x, y) == None + assert homogeneous_order(f(x).diff(x), x, y) is None + assert homogeneous_order(-f(x).diff(x) + x, x, y) is None + assert homogeneous_order(O(x), x, y) is None + assert homogeneous_order(x + O(x**2), x, y) is None assert homogeneous_order(x**pi, x) == pi - assert homogeneous_order(x**x, x) == None + assert homogeneous_order(x**x, x) is None raises(ValueError, lambda: homogeneous_order(x*y)) + def test_1st_homogeneous_coeff_ode(): - #skip("These tests pass but take too long.") # Type: First order homogeneous, y'=f(y/x) eq1 = f(x)/x*cos(f(x)/x) - (x/f(x)*sin(f(x)/x) + cos(f(x)/x))*f(x).diff(x) eq2 = x*f(x).diff(x) - f(x) - x*sin(f(x)/x) - eq3 = f(x) + (x*log(f(x)/x) - 2*x)*diff(f(x),x) + eq3 = f(x) + (x*log(f(x)/x) - 2*x)*diff(f(x), x) eq4 = 2*f(x)*exp(x/f(x)) + f(x)*f(x).diff(x) - 2*x*exp(x/f(x))*f(x).diff(x) eq5 = 2*x**2*f(x) + f(x)**3 + (x*f(x)**2 - 2*x**3)*f(x).diff(x) eq6 = x*exp(f(x)/x) - f(x)*sin(f(x)/x) + x*sin(f(x)/x)*f(x).diff(x) eq7 = (x + sqrt(f(x)**2 - x*f(x)))*f(x).diff(x) - f(x) - eq8 = x+f(x)-(x-f(x))*f(x).diff(x) - sol1a = Eq(f(x)*sin(f(x)/x), C1) - sol1b = Eq(sqrt(cos(f(x)/x)**2 - 1)*f(x), C1) - sol2 = Eq(x*sqrt(1 + cos(f(x)/x))/sqrt(-1 + cos(f(x)/x)), C1) - sol3 = Eq(f(x), x*exp(1 - LambertW(C1*x))) - sol4 = Eq(log(C1*f(x)) + 2*exp(x/f(x)), 0) - #sol5 = Eq(log(C1*x*sqrt(1/x)*sqrt(f(x))) + x**2/(2*f(x)**2), 0) - sol5 = Eq(log(C1*x*sqrt(f(x)/x)) + x**2/(2*f(x)**2), 0) - sol6 = Eq(-exp(-f(x)/x)*sin(f(x)/x)/2 + log(C1*x) - - cos(f(x)/x)*exp(-f(x)/x)/2, 0) - sol7 = Eq(log(C1*f(x)) + 2*sqrt(1 - x/f(x)), 0) - sol8 = Eq(-atan(f(x)/x) + log(C1*x*sqrt(1 + f(x)**2/x**2)), 0) - assert dsolve(eq1, hint='1st_homogeneous_coeff_subs_dep_div_indep') in \ - [sol1a, sol1b] + eq8 = x + f(x) - (x - f(x))*f(x).diff(x) + sol1 = Eq(log(x), C1 - log(f(x)*sin(f(x)/x)/x)) + sol2 = Eq(log(x), log(C1) + log(cos(f(x)/x) - 1)/2 - log(cos(f(x)/x) + 1)/2) + sol3 = Eq(f(x), C1*LambertW(C2*x)) # Eq(f(x), x*exp(-LambertW(C1*x) + 1)) + sol4 = Eq(log(f(x)), C1 - 2*exp(x/f(x))) + sol5 = Eq(f(x), C1*exp(LambertW(C2*x**4)/2)/x) + sol6 = Eq(log(x), + C1 + exp(-f(x)/x)*sin(f(x)/x)/2 + exp(-f(x)/x)*cos(f(x)/x)/2) + sol7 = Eq(log(f(x)), C1 - 2*sqrt(-x/f(x) + 1)) + sol8 = Eq(log(x), C1 - log(sqrt(1 + f(x)**2/x**2)) + atan(f(x)/x)) + assert dsolve(eq1, hint='1st_homogeneous_coeff_subs_dep_div_indep') == \ + sol1 # indep_div_dep actually has a simpler solution for eq2, # but it runs too slow - assert dsolve(eq2, hint='1st_homogeneous_coeff_subs_dep_div_indep') == sol2 + assert dsolve(eq2, hint='1st_homogeneous_coeff_subs_dep_div_indep', + simplify=False) == sol2 assert dsolve(eq3, hint='1st_homogeneous_coeff_best') == sol3 assert dsolve(eq4, hint='1st_homogeneous_coeff_best') == sol4 assert dsolve(eq5, hint='1st_homogeneous_coeff_best') == sol5 - assert dsolve(eq6, hint='1st_homogeneous_coeff_subs_dep_div_indep') == sol6 + assert dsolve(eq6, hint='1st_homogeneous_coeff_subs_dep_div_indep') == \ + sol6 assert dsolve(eq7, hint='1st_homogeneous_coeff_best') == sol7 assert dsolve(eq8, hint='1st_homogeneous_coeff_best') == sol8 # checks are below + @slow -def test_1st_homogeneous_coeff_ode_check14568(): +def test_1st_homogeneous_coeff_ode_check134568(): # These are the checkodesols from test_homogeneous_coeff_ode1. eq1 = f(x)/x*cos(f(x)/x) - (x/f(x)*sin(f(x)/x) + cos(f(x)/x))*f(x).diff(x) + eq3 = f(x) + (x*log(f(x)/x) - 2*x)*diff(f(x), x) eq4 = 2*f(x)*exp(x/f(x)) + f(x)*f(x).diff(x) - 2*x*exp(x/f(x))*f(x).diff(x) eq5 = 2*x**2*f(x) + f(x)**3 + (x*f(x)**2 - 2*x**3)*f(x).diff(x) eq6 = x*exp(f(x)/x) - f(x)*sin(f(x)/x) + x*sin(f(x)/x)*f(x).diff(x) - eq8 = x+f(x)-(x-f(x))*f(x).diff(x) + eq8 = x + f(x) - (x - f(x))*f(x).diff(x) sol1 = Eq(f(x)*sin(f(x)/x), C1) sol4 = Eq(log(C1*f(x)) + 2*exp(x/f(x)), 0) + sol3 = Eq(-f(x)/(1 + log(x/f(x))), C1) sol5 = Eq(log(C1*x*sqrt(1/x)*sqrt(f(x))) + x**2/(2*f(x)**2), 0) sol6 = Eq(-exp(-f(x)/x)*sin(f(x)/x)/2 + log(C1*x) - cos(f(x)/x)*exp(-f(x)/x)/2, 0) sol8 = Eq(-atan(f(x)/x) + log(C1*x*sqrt(1 + f(x)**2/x**2)), 0) assert checkodesol(eq1, sol1, order=1, solve_for_func=False)[0] + assert checkodesol(eq3, sol3, order=1, solve_for_func=False)[0] assert checkodesol(eq4, sol4, order=1, solve_for_func=False)[0] assert checkodesol(eq5, sol5, order=1, solve_for_func=False)[0] assert checkodesol(eq6, sol6, order=1, solve_for_func=False)[0] assert checkodesol(eq8, sol8, order=1, solve_for_func=False)[0] -@XFAIL + def test_1st_homogeneous_coeff_ode_check2(): - skip('This is a known issue.') - # checker cannot determine that the following expression, z, is - # zero: - ''' - >>> checkodesol(eq2, sol2, order=1, solve_for_func=False) - (False, x*(-sin(f(x)/x) + 2*cos(f(x)/(2*x))**2*tan(f(x)/(2*x)))) - >>> checkodesol(eq2, sol2, order=1, solve_for_func=1) - (False, x*(-C1**2*sin(2*atan(x/C1)) + 2*C1*x - x**2*sin(2*atan(x/C1)))) - >>> z = _[1] - >>> z.subs(list(zip((x,C1),(2,3)))).n() - 0.e-124 - >>> z.subs(list(zip((x,C1),(2,.3)))).n() - 4.44089209850063e-16 - >>> z.subs(list(zip((x,C1),(12,.3)))).n() - 0 - ''' eq2 = x*f(x).diff(x) - f(x) - x*sin(f(x)/x) sol2 = Eq(x/tan(f(x)/(2*x)), C1) assert checkodesol(eq2, sol2, order=1, solve_for_func=False)[0] + @XFAIL def test_1st_homogeneous_coeff_ode_check3(): skip('This is a known issue.') @@ -566,91 +579,69 @@ # (False, # x*(log(exp(-LambertW(C1*x))) + # LambertW(C1*x))*exp(-LambertW(C1*x) + 1)) - eq3 = f(x) + (x*log(f(x)/x) - 2*x)*diff(f(x),x) - sol3 = Eq(f(x), x*exp(1 - LambertW(C1*x))) - assert checkodesol(eq3, sol3, solve_for_func=True)[0] - # and without an assumption about x and f(x), the implicit form doesn't - # resolve, either: - # (False, (log(f(x)/x) + log(x/f(x)))*f(x)) - sol3 = Eq(-f(x)/(1 + log(x/f(x))), C1) - assert checkodesol(eq3, sol3, order=1, solve_for_func=False)[0] + # This is blocked by issue 1981. + eq3 = f(x) + (x*log(f(x)/x) - 2*x)*diff(f(x), x) + sol3a = Eq(f(x), x*exp(1 - LambertW(C1*x))) + assert checkodesol(eq3, sol3a, solve_for_func=True)[0] + # Checker can't verify this form either + # (False, + # C1*(log(C1*LambertW(C2*x)/x) + LambertW(C2*x) - 1)*LambertW(C2*x)) + # It is because a = W(a)*exp(W(a)), so log(a) == log(W(a)) + W(a) and C2 = + # -E/C1 (which can be verified by solving with simplify=False). + sol3b = Eq(f(x), C1*LambertW(C2*x)) + assert checkodesol(eq3, sol3b, solve_for_func=True)[0] + -@XFAIL def test_1st_homogeneous_coeff_ode_check7(): - skip('This is a known issue.') - # checker cannot solve for the function and cannot determine that - # the result is zero: - ''' - >>> checkodesol(eq7, sol7, order=1, solve_for_func=True) - (False, (x + sqrt(-x*f(x) + f(x)**2))*(x*f(x) - - sqrt(-x/f(x) + 1)*f(x)**2)*f(x) - - (x**2*f(x) - (-x + f(x))*f(x)**2)*f(x)) - ''' eq7 = (x + sqrt(f(x)**2 - x*f(x)))*f(x).diff(x) - f(x) sol7 = Eq(log(C1*f(x)) + 2*sqrt(1 - x/f(x)), 0) assert checkodesol(eq7, sol7, order=1, solve_for_func=False)[0] -@XFAIL -def test_1st_homogeneous_coeff_ode_check9(): - skip('This is a known issue.') - # checker cannot solve for the function and cannot determine that - # the result is zero: - ''' - >>> checkodesol(eq9, sol9, order=1, solve_for_func=True) - (False, (x*sqrt(-x**2 + f(x)**2) - x*f(x))* - (x*sqrt(-x**2/f(x)**2 + 1)*f(x) + x*f(x))*f(x)**2 + - (-x**2*(-x**2 + f(x)**2) + x**2*f(x)**2)*f(x)**2) - _u2 = Dummy('u2') - __a = Dummy('a') - ''' - eq9 = f(x)**2 + (x*sqrt(f(x)**2 - x**2) - x*f(x))*f(x).diff(x) - sol9 = Eq(-Integral(-1/(-(1 - sqrt(1 - _u2**2))*_u2 + _u2), (_u2, __a, - x/f(x))) + log(C1*f(x)), 0) - assert checkodesol(eq9, sol9, order=1, solve_for_func=False)[0] -@XFAIL def test_1st_homogeneous_coeff_ode2(): - eq1 = f(x).diff(x) - f(x)/x+1/sin(f(x)/x) + eq1 = f(x).diff(x) - f(x)/x + 1/sin(f(x)/x) eq2 = x**2 + f(x)**2 - 2*x*f(x)*f(x).diff(x) eq3 = x*exp(f(x)/x) + f(x) - x*f(x).diff(x) - sol1 = Eq(f(x), x*acos(log(C1*x))) - sol2 = set([Eq(f(x), -sqrt(C1*x + x**2)), Eq(f(x), sqrt(C1*x + x**2))]) - sol3 = Eq(f(x), log((-1/log(C1*x))**x)) + sol1 = [Eq(f(x), x*(-acos(C1 + log(x)) + 2*pi)), Eq(f(x), x*acos(C1 + log(x)))] + sol2 = Eq(log(f(x)), log(C1) + log(x/f(x)) - log(x**2/f(x)**2 - 1)) + sol3 = Eq(f(x), log((1/(C1 - log(x)))**x)) # specific hints are applied for speed reasons assert dsolve(eq1, hint='1st_homogeneous_coeff_subs_dep_div_indep') == sol1 - assert set(dsolve(eq2, hint='1st_homogeneous_coeff_best')) == sol2 + assert dsolve(eq2, hint='1st_homogeneous_coeff_best', simplify=False) == sol2 assert dsolve(eq3, hint='1st_homogeneous_coeff_subs_dep_div_indep') == sol3 assert checkodesol(eq1, sol1, order=1, solve_for_func=False)[0] - assert all(i[0] for i in - checkodesol(eq2, sol2, order=1, solve_for_func=False)) - # the solution doesn't check...perhaps there is something wrong with the - # routine or the solver? - assert checkodesol(eq3, sol3, order=1, solve_for_func=False)[0] + assert checkodesol(eq2, sol2, order=1, solve_for_func=False)[0] + # test for eq3 is in test_1st_homogeneous_coeff_ode2_check3 below + -@XFAIL def test_1st_homogeneous_coeff_ode2_check3(): - # simplify() will need to get way better before it can do this one eq3 = x*exp(f(x)/x) + f(x) - x*f(x).diff(x) sol3 = Eq(f(x), log(log(C1/x)**(-x))) assert checkodesol(eq3, sol3, order=1, solve_for_func=False)[0] + +def test_1st_homogeneous_coeff_ode_check9(): + _u2 = Dummy('u2') + __a = Dummy('a') + eq9 = f(x)**2 + (x*sqrt(f(x)**2 - x**2) - x*f(x))*f(x).diff(x) + sol9 = Eq(-Integral(-1/(-(1 - sqrt(1 - _u2**2))*_u2 + _u2), (_u2, __a, + x/f(x))) + log(C1*f(x)), 0) + assert checkodesol(eq9, sol9, order=1, solve_for_func=False)[0] + + def test_1st_homogeneous_coeff_ode3(): # The standard integration engine cannot handle one of the integrals # involved (see issue 1452). meijerg code comes up with an answer, but in # unconventional form. # checkodesol fails for this equation, so its test is in - # test_homogeneous_order_ode1_sol above. It has to compare string + # test_1st_homogeneous_coeff_ode_check9 above. It has to compare string # expressions because u2 is a dummy variable. - eq = f(x)**2+(x*sqrt(f(x)**2-x**2)-x*f(x))*f(x).diff(x) - sol = Eq(Piecewise((-acosh(f(x)/x), 1 < abs(f(x)**2/x**2)), - (I*asin(f(x)/x), True)) + log(C1*f(x)), 0) + eq = f(x)**2 + (x*sqrt(f(x)**2 - x**2) - x*f(x))*f(x).diff(x) + sol = Eq(log(f(x)), C1 - Piecewise( + (-acosh(f(x)/x), abs(f(x)**2)/x**2 > 1), + (I*asin(f(x)/x), True))) assert dsolve(eq, hint='1st_homogeneous_coeff_subs_indep_div_dep') == sol -@XFAIL -def test_1st_homogeneous_coeff_ode3_check(): - eq = f(x)**2+(x*sqrt(f(x)**2-x**2)-x*f(x))*f(x).diff(x) - sol = Eq(f(x)**2 - C1*x, f(x)*sqrt(f(x)**2-x**2)) - assert checkodesol(eq, sol, solve_for_func=False)[0] def test_1st_homogeneous_coeff_corner_case(): eq1 = f(x).diff(x) - f(x)/x @@ -662,6 +653,7 @@ assert sid not in c1 and sdi not in c1 assert sid not in c2 and sdi not in c2 + def test_nth_linear_constant_coeff_homogeneous(): # From Exercise 20, in Ordinary Differential Equations, # Tenenbaum and Pollard, pg. 220 @@ -684,7 +676,7 @@ eq13 = f(x).diff(x, 4) eq14 = f(x).diff(x, 2) + 4*f(x).diff(x) + 4*f(x) eq15 = 3*f(x).diff(x, 3) + 5*f(x).diff(x, 2) + f(x).diff(x) - f(x) - eq16 = f(x).diff(x, 3) - 6*f(x).diff(x, 2) +12*f(x).diff(x) - 8*f(x) + eq16 = f(x).diff(x, 3) - 6*f(x).diff(x, 2) + 12*f(x).diff(x) - 8*f(x) eq17 = f(x).diff(x, 2) - 2*a*f(x).diff(x) + a**2*f(x) eq18 = f(x).diff(x, 4) + 3*f(x).diff(x, 3) eq19 = f(x).diff(x, 4) - 2*f(x).diff(x, 2) @@ -831,27 +823,30 @@ assert checkodesol(eq29, sol29, order=4, solve_for_func=False)[0] assert checkodesol(eq30, sol30, order=5, solve_for_func=False)[0] + def test_nth_linear_constant_coeff_homogeneous_RootOf(): eq = f(x).diff(x, 5) + 11*f(x).diff(x) - 2*f(x) sol = Eq(f(x), - C1*exp(x*RootOf(x**5 + 11*x - 2, 0)) + \ - C2*exp(x*RootOf(x**5 + 11*x - 2, 1)) + \ - C3*exp(x*RootOf(x**5 + 11*x - 2, 2)) + \ - C4*exp(x*RootOf(x**5 + 11*x - 2, 3)) + \ + C1*exp(x*RootOf(x**5 + 11*x - 2, 0)) + + C2*exp(x*RootOf(x**5 + 11*x - 2, 1)) + + C3*exp(x*RootOf(x**5 + 11*x - 2, 2)) + + C4*exp(x*RootOf(x**5 + 11*x - 2, 3)) + C5*exp(x*RootOf(x**5 + 11*x - 2, 4))) assert dsolve(eq) == sol + @XFAIL def test_nth_linear_constant_coeff_homogeneous_RootOf_sol(): eq = f(x).diff(x, 5) + 11*f(x).diff(x) - 2*f(x) sol = Eq(f(x), - C1*exp(x*RootOf(x**5 + 11*x - 2, 0)) + \ - C2*exp(x*RootOf(x**5 + 11*x - 2, 1)) + \ - C3*exp(x*RootOf(x**5 + 11*x - 2, 2)) + \ - C4*exp(x*RootOf(x**5 + 11*x - 2, 3)) + \ + C1*exp(x*RootOf(x**5 + 11*x - 2, 0)) + + C2*exp(x*RootOf(x**5 + 11*x - 2, 1)) + + C3*exp(x*RootOf(x**5 + 11*x - 2, 2)) + + C4*exp(x*RootOf(x**5 + 11*x - 2, 3)) + C5*exp(x*RootOf(x**5 + 11*x - 2, 4))) assert checkodesol(eq, sol, order=5, solve_for_func=False)[0] + def test_undetermined_coefficients_match(): assert _undetermined_coefficients_match(g(x), x) == {'test': False} assert _undetermined_coefficients_match(sin(2*x + sqrt(5)), x) == \ @@ -866,7 +861,7 @@ sin(x)*x**2 + sin(x)*x + sin(x), x) == {'test': True, 'trialset': s} assert _undetermined_coefficients_match( exp(2*x)*sin(x)*(x**2 + x + 1), x - ) == { + ) == { 'test': True, 'trialset': set([exp(2*x)*sin(x), x**2*exp(2*x)*sin(x), cos(x)*exp(2*x), x**2*cos(x)*exp(2*x), x*cos(x)*exp(2*x), x*exp(2*x)*sin(x)])} @@ -888,14 +883,14 @@ {'test': False} assert _undetermined_coefficients_match( x**2*sin(x)*exp(x) + x*sin(x) + x, x - ) == { + ) == { 'test': True, 'trialset': set([x**2*cos(x)*exp(x), x, cos(x), S(1), exp(x)*sin(x), sin(x), x*exp(x)*sin(x), x*cos(x), x*cos(x)*exp(x), x*sin(x), cos(x)*exp(x), x**2*exp(x)*sin(x)])} assert _undetermined_coefficients_match(4*x*sin(x - 2), x) == { 'trialset': set([x*cos(x - 2), x*sin(x - 2), cos(x - 2), sin(x - 2)]), 'test': True, - } + } assert _undetermined_coefficients_match(2**x*x, x) == \ {'test': True, 'trialset': set([2**x, x*2**x])} assert _undetermined_coefficients_match(2**x*exp(2*x), x) == \ @@ -947,11 +942,11 @@ {'test': True, 'trialset': set([exp(x)])} # converted from sin(x)**2 assert _undetermined_coefficients_match(S(1)/2 - cos(2*x)/2, x) == \ - {'test': True, 'trialset': set([S(1), cos(2*x), sin(2*x)])} + {'test': True, 'trialset': set([S(1), cos(2*x), sin(2*x)])} # converted from exp(2*x)*sin(x)**2 assert _undetermined_coefficients_match( exp(2*x)*(S(1)/2 + cos(2*x)/2), x - ) == { + ) == { 'test': True, 'trialset': set([exp(2*x)*sin(2*x), cos(2*x)*exp(2*x), exp(2*x)])} assert _undetermined_coefficients_match(2*x + sin(x) + cos(x), x) == \ @@ -962,6 +957,7 @@ assert _undetermined_coefficients_match(cos(x**2), x) == {'test': False} assert _undetermined_coefficients_match(2**(x**2), x) == {'test': False} + def test_nth_linear_constant_coeff_undetermined_coefficients(): hint = 'nth_linear_constant_coeff_undetermined_coefficients' g = exp(-x) @@ -1029,8 +1025,8 @@ sol22 = Eq(f(x), C1*sin(x) + (C2 - x/2)*cos(x) + exp(-x)/2) sol23 = Eq(f(x), (C1 + C2*x + C3*x**2 + x**3/6)*exp(x)) sol24 = Eq(f(x), S(1)/2 - cos(2*x)/6 + C1*sin(x) + C2*cos(x)) - sol25 = Eq(f(x), C1 + C2*exp(-x) + C3*exp(x) + \ - (-21*sin(2*x) + 27*cos(2*x) + 130)*exp(2*x)/1560) + sol25 = Eq(f(x), C1 + C2*exp(-x) + C3*exp(x) + + (-21*sin(2*x) + 27*cos(2*x) + 130)*exp(2*x)/1560) sol26 = Eq(f(x), C1 + (C2 + C3*x - x**2/8)*sin(x) + (C4 + C5*x + x**2/8)*cos(x) + x**2) sol27 = Eq(f(x), cos(3*x)/16 + C1*cos(x) + (C2 + x/4)*sin(x)) @@ -1119,19 +1115,22 @@ assert checkodesol(eq27, sol27, order=2, solve_for_func=False)[0] assert checkodesol(eq28, sol28, order=1, solve_for_func=False)[0] + @XFAIL def test_nth_linear_constant_coeff_undetermined_coefficients_imaginary_exp(): # Equivalent to eq26 in # test_nth_linear_constant_coeff_undetermined_coefficients above. # This fails because the algorithm for undetermined coefficients # doesn't know to multiply exp(I*x) by sufficient x because it is linearly - # dependent of sin(x) and cos(x). + # dependent on sin(x) and cos(x). + hint = 'nth_linear_constant_coeff_undetermined_coefficients' eq26a = f(x).diff(x, 5) + 2*f(x).diff(x, 3) + f(x).diff(x) - 2*x - exp(I*x) sol26 = Eq(f(x), C1 + (C2 + C3*x - x**2/8)*sin(x) + (C4 + C5*x + x**2/8)*cos(x) + x**2) assert dsolve(eq26a, hint=hint) == sol26 assert checkodesol(eq26a, sol26, order=5, solve_for_func=False)[0] + def test_nth_linear_constant_coeff_variation_of_parameters(): hint = 'nth_linear_constant_coeff_variation_of_parameters' g = exp(-x) @@ -1148,7 +1147,7 @@ eq9 = f(x).diff(x, 3) - 3*f2 + 3*f(x).diff(x) - f(x) - exp(x) eq10 = f2 + 2*f(x).diff(x) + f(x) - exp(-x)/x eq11 = f2 + f(x) - 1/sin(x)*1/cos(x) - eq12 = f(x).diff(x, 4) - 1/x + eq12 = f(x).diff(x, 4) - 1/x sol1 = Eq(f(x), -1 - x + (C1 + C2*x - 3*x**2/32 - x**3/24)*exp(-x) + C3*exp(x/3)) sol2 = Eq(f(x), -1 - x + (C1 + C2*x - x**2/8)*exp(-x) + C3*exp(x/3)) @@ -1160,7 +1159,7 @@ sol8 = Eq(f(x), C1*exp(x) + C2*exp(2*x) + (6*x + 5)*exp(-x)/36) sol9 = Eq(f(x), (C1 + C2*x + C3*x**2 + x**3/6)*exp(x)) sol10 = Eq(f(x), (C1 + x*(C2 + log(x)))*exp(-x)) - sol11 = Eq(f(x), cos(x)*(C2 - Integral(1/cos(x), x)) + sin(x)*(C1 + \ + sol11 = Eq(f(x), cos(x)*(C2 - Integral(1/cos(x), x)) + sin(x)*(C1 + Integral(1/sin(x), x))) sol12 = Eq(f(x), C1 + C2*x + x**3*(C3 + log(x)/6) + C4*x**2) sol1s = constant_renumber(sol1, 'C', 1, 3) @@ -1185,7 +1184,7 @@ assert dsolve(eq8, hint=hint) in (sol8, sol8s) assert dsolve(eq9, hint=hint) in (sol9, sol9s) assert dsolve(eq10, hint=hint) in (sol10, sol10s) - assert dsolve(eq11, hint=hint+'_Integral') in (sol11, sol11s) + assert dsolve(eq11, hint=hint + '_Integral') in (sol11, sol11s) assert dsolve(eq12, hint=hint) in (sol12, sol12s) assert checkodesol(eq1, sol1, order=3, solve_for_func=False)[0] assert checkodesol(eq2, sol2, order=3, solve_for_func=False)[0] @@ -1199,6 +1198,7 @@ assert checkodesol(eq10, sol10, order=2, solve_for_func=False)[0] assert checkodesol(eq12, sol12, order=4, solve_for_func=False)[0] + def test_nth_linear_constant_coeff_variation_of_parameters_simplify_False(): # solve_variation_of_parameters shouldn't attempt to simplify the # Wronskian if simplify=False. If wronskian() ever gets good enough @@ -1206,13 +1206,14 @@ hint = 'nth_linear_constant_coeff_variation_of_parameters' assert dsolve(f(x).diff(x, 5) + 2*f(x).diff(x, 3) + f(x).diff(x) - 2*x - exp(I*x), f(x), hint + "_Integral", simplify=False) != \ - dsolve(f(x).diff(x, 5) + 2*f(x).diff(x, 3) + f(x).diff(x) - + dsolve(f(x).diff(x, 5) + 2*f(x).diff(x, 3) + f(x).diff(x) - 2*x - exp(I*x), f(x), hint + "_Integral", simplify=True) + def test_Liouville_ODE(): hint = 'Liouville' # The first part here used to be test_ODE_1() from test_solvers.py - eq1 = diff(f(x),x)/x + diff(f(x),x,x)/2 - diff(f(x),x)**2/2 + eq1 = diff(f(x), x)/x + diff(f(x), x, x)/2 - diff(f(x), x)**2/2 eq1a = diff(x*exp(-f(x)), x, x) # compare to test_unexpanded_Liouville_ODE() below eq2 = (eq1*exp(-f(x))/exp(f(x))).expand() @@ -1222,7 +1223,8 @@ sol1 = Eq(f(x), log(x/(C1 + C2*x))) sol1a = Eq(C1 + C2/x - exp(-f(x)), 0) sol2 = sol1 - sol3 = set([Eq(f(x), -sqrt(C1 + C2*log(x))), Eq(f(x), sqrt(C1 + C2*log(x)))]) + sol3 = set( + [Eq(f(x), -sqrt(C1 + C2*log(x))), Eq(f(x), sqrt(C1 + C2*log(x)))]) sol4 = set([Eq(f(x), sqrt(C1 + C2*exp(x))*exp(-x/2)), Eq(f(x), -sqrt(C1 + C2*exp(x))*exp(-x/2))]) sol5 = Eq(f(x), log(C1 + C2/x)) @@ -1245,60 +1247,66 @@ assert all(i[0] for i in checkodesol(eq4, sol4, order=2, solve_for_func=False)) assert checkodesol(eq5, sol5, order=2, solve_for_func=False)[0] - not_Liouville1 = classify_ode(diff(f(x),x)/x + f(x)*diff(f(x),x,x)/2 - - diff(f(x),x)**2/2, f(x)) - not_Liouville2 = classify_ode(diff(f(x),x)/x + diff(f(x),x,x)/2 - - x*diff(f(x),x)**2/2, f(x)) + not_Liouville1 = classify_ode(diff(f(x), x)/x + f(x)*diff(f(x), x, x)/2 - + diff(f(x), x)**2/2, f(x)) + not_Liouville2 = classify_ode(diff(f(x), x)/x + diff(f(x), x, x)/2 - + x*diff(f(x), x)**2/2, f(x)) assert hint not in not_Liouville1 assert hint not in not_Liouville2 - assert hint+'_Integral' not in not_Liouville1 - assert hint+'_Integral' not in not_Liouville2 + assert hint + '_Integral' not in not_Liouville1 + assert hint + '_Integral' not in not_Liouville2 + def test_unexpanded_Liouville_ODE(): # This is the same as eq1 from test_Liouville_ODE() above. - eq1 = diff(f(x),x)/x+diff(f(x),x,x)/2- diff(f(x),x)**2/2 + eq1 = diff(f(x), x)/x + diff(f(x), x, x)/2 - diff(f(x), x)**2/2 eq2 = eq1*exp(-f(x))/exp(f(x)) sol2 = Eq(f(x), log(x/(C1 + C2*x))) sol2s = constant_renumber(sol2, 'C', 1, 2) assert dsolve(eq2) in (sol2, sol2s) assert checkodesol(eq2, sol2, order=2, solve_for_func=False)[0] + def test_1686(): from sympy.abc import A eq = x + A*(x + diff(f(x), x) + f(x)) + diff(f(x), x) + f(x) + 2 - assert classify_ode(eq, f(x)) == ('1st_linear', - 'nth_linear_constant_coeff_undetermined_coefficients', - 'nth_linear_constant_coeff_variation_of_parameters', - '1st_linear_Integral', - 'nth_linear_constant_coeff_variation_of_parameters_Integral') + assert classify_ode(eq, f(x)) == ('1st_linear', 'almost_linear', + 'nth_linear_constant_coeff_undetermined_coefficients', + 'nth_linear_constant_coeff_variation_of_parameters', + '1st_linear_Integral', 'almost_linear_Integral', + 'nth_linear_constant_coeff_variation_of_parameters_Integral') # 1765 - eq=(x**2 + f(x)**2)*f(x).diff(x) - 2*x*f(x) - assert classify_ode(eq, f(x)) == ( + eq = (x**2 + f(x)**2)*f(x).diff(x) - 2*x*f(x) + assert classify_ode(eq, f(x)) == ('1st_exact', '1st_homogeneous_coeff_best', '1st_homogeneous_coeff_subs_indep_div_dep', '1st_homogeneous_coeff_subs_dep_div_indep', + 'separable_reduced', '1st_exact_Integral', '1st_homogeneous_coeff_subs_indep_div_dep_Integral', - '1st_homogeneous_coeff_subs_dep_div_indep_Integral') + '1st_homogeneous_coeff_subs_dep_div_indep_Integral', + 'separable_reduced_Integral') def test_1726(): raises(ValueError, lambda: dsolve(f(x, y).diff(x) - y*f(x, y), f(x))) assert classify_ode(f(x, y).diff(x) - y*f(x, y), f(x), dict=True) == \ - {'default': None, 'order': 0} + {'default': None, 'order': 0} # See also issue 694, test Z13. raises(ValueError, lambda: dsolve(f(x).diff(x), f(y))) assert classify_ode(f(x).diff(x), f(y), dict=True) == \ {'default': None, 'order': 0} + def test_constant_renumber_order_issue2209(): from sympy.utilities.iterables import variations assert constant_renumber(C1*x + C2*y, "C", 1, 2) == \ - constant_renumber(C1*y + C2*x, "C", 1, 2) == \ - C1*x + C2*y + constant_renumber(C1*y + C2*x, "C", 1, 2) == \ + C1*x + C2*y e = C1*(C2 + x)*(C3 + y) for a, b, c in variations([C1, C2, C3], 3): assert constant_renumber(a*(b + x)*(c + y), "C", 1, 3) == e + def test_issue_2671(): k = Symbol("k", real=True) t = Symbol('t') @@ -1315,6 +1323,338 @@ assert constantsimp(x + C1 + y, x, 1) == C1 + x assert constantsimp(x + C1 + Integral(x, (x, 1, 2)), x, 1) == C1 + x + def test_issue_2013_2331(): assert homogeneous_order(-log(x) + acosh(x), x) is None assert homogeneous_order(y - log(x), x, y) is None + + +def test_nth_order_linear_euler_eq_homogeneous(): + x, t, a, b, c = symbols('x t a b c') + y = Function('y') + our_hint = "nth_linear_euler_eq_homogeneous" + + eq = diff(f(t), t, 4)*t**4 - 13*diff(f(t), t, 2)*t**2 + 36*f(t) + assert our_hint in classify_ode(eq) + + eq = a*y(t) + b*t*diff(y(t), t) + c*t**2*diff(y(t), t, 2) + assert our_hint in classify_ode(eq) + + eq = Eq(-3*diff(f(x), x)*x + 2*x**2*diff(f(x), x, x), 0) + sol = C1 + C2*x**Rational(5, 2) + sols = constant_renumber(sol, 'C', 1, 3) + assert our_hint in classify_ode(eq) + assert dsolve(eq, f(x), hint=our_hint).rhs in (sol, sols) + assert checkodesol(eq, sol, order=2, solve_for_func=False)[0] + + eq = Eq(3*f(x) - 5*diff(f(x), x)*x + 2*x**2*diff(f(x), x, x), 0) + sol = C1*sqrt(x) + C2*x**3 + sols = constant_renumber(sol, 'C', 1, 3) + assert our_hint in classify_ode(eq) + assert dsolve(eq, f(x), hint=our_hint).rhs in (sol, sols) + assert checkodesol(eq, sol, order=2, solve_for_func=False)[0] + + eq = Eq(4*f(x) + 5*diff(f(x), x)*x + x**2*diff(f(x), x, x), 0) + sol = (C1 + C2*log(x))/x**2 + sols = constant_renumber(sol, 'C', 1, 3) + assert our_hint in classify_ode(eq) + assert dsolve(eq, f(x), hint=our_hint).rhs in (sol, sols) + assert checkodesol(eq, sol, order=2, solve_for_func=False)[0] + + eq = Eq(6*f(x) - 6*diff(f(x), x)*x + 1*x**2*diff(f(x), x, x) + x**3*diff(f(x), x, x, x), 0) + sol = dsolve(eq, f(x), hint=our_hint) + sol = C1/x**2 + C2*x + C3*x**3 + sols = constant_renumber(sol, 'C', 1, 4) + assert our_hint in classify_ode(eq) + assert dsolve(eq, f(x), hint=our_hint).rhs in (sol, sols) + assert checkodesol(eq, sol, order=2, solve_for_func=False)[0] + + eq = Eq(-125*f(x) + 61*diff(f(x), x)*x - 12*x**2*diff(f(x), x, x) + x**3*diff(f(x), x, x, x), 0) + sol = x**5*(C1 + C2*log(x) + C3*log(x)**2) + sols = constant_renumber(sol, 'C', 1, 4) + assert our_hint in classify_ode(eq) + assert dsolve(eq, f(x), hint=our_hint).rhs in (sol, sols) + assert checkodesol(eq, sol, order=2, solve_for_func=False)[0] + + eq = t**2*diff(y(t), t, 2) + t*diff(y(t), t) - 9*y(t) + sol = C1*t**3 + C2*t**-3 + sols = constant_renumber(sol, 'C', 1, 3) + assert our_hint in classify_ode(eq) + assert dsolve(eq, y(t), hint=our_hint).rhs in (sol, sols) + assert checkodesol(eq, sol, order=2, solve_for_func=False)[0] + + +def test_issue_1996(): + f = Function('f') + raises(ValueError, lambda: dsolve(f(x).diff(x)**2, f(x), 'separable')) + raises(ValueError, lambda: dsolve(f(x).diff(x)**2, f(x), 'fdsjf')) + + +def test_almost_linear(): + from sympy import Ei + A = Symbol('A', positive=True) + our_hint = 'almost_linear' + f = Function('f') + d = f(x).diff(x) + eq = x**2*f(x)**2*d + f(x)**3 + 1 + sol = dsolve(eq, f(x), hint = 'almost_linear') + assert sol[0].rhs == (C1*exp(3/x) - 1)**(1/3) + assert checkodesol(eq, sol, order=1, solve_for_func=False)[0] + + eq = x*f(x)*d + 2*x*f(x)**2 + 1 + sol = dsolve(eq, f(x), hint = 'almost_linear') + assert sol[0].rhs == -sqrt((C1 - 2*Ei(4*x))*exp(-4*x)) + assert checkodesol(eq, sol, order=1, solve_for_func=False)[0] + + eq = x*d + x*f(x) + 1 + sol = dsolve(eq, f(x), hint = 'almost_linear') + assert sol.rhs == (C1 - Ei(x))*exp(-x) + assert checkodesol(eq, sol, order=1, solve_for_func=False)[0] + assert our_hint in classify_ode(eq, f(x)) + + eq = x*exp(f(x))*d + exp(f(x)) + 3*x + sol = dsolve(eq, f(x), hint = 'almost_linear') + assert sol.rhs == log(C1/x - 3*x/2) + assert checkodesol(eq, sol, order=1, solve_for_func=False)[0] + + eq = x + A*(x + diff(f(x), x) + f(x)) + diff(f(x), x) + f(x) + 2 + sol = dsolve(eq, f(x), hint = 'almost_linear') + assert sol.rhs == (C1 + Piecewise( + (x, Eq(A + 1, 0)), ((-A*x + A - x - 1)*exp(x)/(A + 1), True)))*exp(-x) + assert checkodesol(eq, sol, order=1, solve_for_func=False)[0] + + +def test_exact_enhancement(): + f = Function('f')(x) + df = Derivative(f, x) + eq = f/x**2 + ((f*x - 1)/x)*df + sol = dsolve(eq, f) + rhs = [eq.rhs for eq in sol] + assert rhs == [(-sqrt(C1*x**2 + 1) + 1)/x, (sqrt(C1*x**2 + 1) + 1)/x] + + eq = (x*f - 1) + df*(x**2 - x*f) + rhs = [sol.rhs for sol in dsolve(eq, f)] + assert rhs[0] == x - sqrt(C1 + x**2 - 2*log(x)) + assert rhs[1] == x + sqrt(C1 + x**2 - 2*log(x)) + + eq = (x + 2)*sin(f) + df*x*cos(f) + rhs = [sol.rhs for sol in dsolve(eq, f)] + assert rhs == [ + -acos(-sqrt(C1*exp(-2*x) + x**4)/x**2) + 2*pi, + -acos(sqrt(C1*exp(-2*x) + x**4)/x**2) + 2*pi, + acos(-sqrt(C1*exp(-2*x) + x**4)/x**2), + acos(sqrt(C1*exp(-2*x) + x**4)/x**2)] + + +def test_separable_reduced(): + f = Function('f') + df = f(x).diff(x) + eq = (x / f(x))*df + tan(x**2*f(x) / (x**2*f(x) - 1)) + assert classify_ode(eq) == ('1st_linear', 'separable_reduced', + '1st_linear_Integral', 'separable_reduced_Integral') + + eq = x* df + f(x)* (1 / (x**2*f(x) - 1)) + assert classify_ode(eq) == ('1st_linear', 'separable_reduced', + '1st_linear_Integral', 'separable_reduced_Integral') + sol = dsolve(eq, hint = 'separable_reduced', simplify=False) + assert sol.lhs == log(x**2*f(x))/3 + log(x**2*f(x) - S(3)/2)/6 + assert sol.rhs == C1 + log(x) + assert checkodesol(eq, sol, order=1, solve_for_func=False)[0] + + eq = df + (f(x) / (x**4*f(x) - x)) + assert classify_ode(eq) == ('1st_linear', 'separable_reduced', + '1st_linear_Integral', 'separable_reduced_Integral') + # generates PolynomialError in solve attempt + sol = dsolve(eq, hint = 'separable_reduced') + assert sol.lhs == log(x**3*f(x))/4 + log(x**3*f(x) - S(4)/3)/12 + assert sol.rhs == C1 + log(x) + assert checkodesol(eq, sol, order=1, solve_for_func=False)[0] + + eq = x*df + f(x)*(x**2*f(x)) + sol = dsolve(eq, hint = 'separable_reduced', simplify=False) + assert sol == Eq(log(x**2*f(x))/2 - log(x**2*f(x) - 2)/2, C1 + log(x)) + assert checkodesol(eq, sol, order=1, solve_for_func=False)[0] + + +def test_homogeneous_function(): + f = Function('f') + eq1 = tan(x + f(x)) + eq2 = sin((3*x)/(4*f(x))) + eq3 = cos(3*x/4*f(x)) + eq4 = log((3*x + 4*f(x))/(5*f(x) + 7*x)) + eq5 = exp((2*x**2)/(3*f(x)**2)) + eq6 = log((3*x + 4*f(x))/(5*f(x) + 7*x) + exp((2*x**2)/(3*f(x)**2))) + eq7 = sin((3*x)/(5*f(x) + x**2)) + assert homogeneous_order(eq1, x, f(x)) == None + assert homogeneous_order(eq2, x, f(x)) == 0 + assert homogeneous_order(eq3, x, f(x)) == None + assert homogeneous_order(eq4, x, f(x)) == 0 + assert homogeneous_order(eq5, x, f(x)) == 0 + assert homogeneous_order(eq6, x, f(x)) == 0 + assert homogeneous_order(eq7, x, f(x)) == None + + +def test_linear_coeff_match(): + from sympy.solvers.ode import _linear_coeff_match + n, d = z*(2*x + 3*f(x) + 5), z*(7*x + 9*f(x) + 11) + rat = n/d + eq1 = sin(rat) + cos(rat.expand()) + eq2 = rat + eq3 = log(sin(rat)) + ans = (4, -S(13)/3) + assert _linear_coeff_match(eq1, f(x)) == ans + assert _linear_coeff_match(eq2, f(x)) == ans + assert _linear_coeff_match(eq3, f(x)) == ans + + # no c + eq4 = (3*x)/f(x) + # not x and f(x) + eq5 = (3*x + 2)/x + # denom will be zero + eq6 = (3*x + 2*f(x) + 1)/(3*x + 2*f(x) + 5) + # not rational coefficient + eq7 = (3*x + 2*f(x) + sqrt(2))/(3*x + 2*f(x) + 5) + assert _linear_coeff_match(eq4, f(x)) is None + assert _linear_coeff_match(eq5, f(x)) is None + assert _linear_coeff_match(eq6, f(x)) is None + assert _linear_coeff_match(eq7, f(x)) is None + + +def test_linear_coefficients(): + f = Function('f') + df = f(x).diff(x) + sol = Eq(f(x), C1/(x**2 + 6*x + 9) - S(3)/2) + # XXX if force is not used in solve, the following is returned which, + # for C1 = -81/2, will satisfy the original equation. Should there be + # another free symbol so a family of solutions can be obtained, e.g. + # (C2 + C1*x + ... etc)/(...): + # Eq(f(x), (C1 + C1*x - 3*x**3/2 - 27*x**2/2)/(x**3 + 9*x**2 + 27*x + 27)) + eq = df + (3 + 2*f(x))/(x + 3) + assert dsolve(eq, hint='linear_coefficients') == sol + assert checkodesol(eq, sol, order=1, solve_for_func=False)[0] + + +@XFAIL +def test_constantsimp_take_problem(): + # should this have C1 and C2 or C1 and exp(C1) in addition to x? + # see note in test_linear_coefficients above + c = exp(C1) + 2 + assert len(Poly(constantsimp(exp(C1) + c + c*x, x, 2)).gens) > 2 + + +def test_issue_3780(): + f = Function('f') + eq = Eq(Derivative(f(x), x, 2) - 2*Derivative(f(x), x) + f(x), sin(x)) + sol = (C1 + C2*x)*exp(x) + cos(x)/S(2) + assert dsolve(eq).rhs == sol + assert checkodesol(eq, sol, order=1, solve_for_func=False)[0] + + +def test_issue_3890(): + f = Function('f') + k = Symbol('k') + assert dsolve(f(x).diff(x) - x*exp(-k*x), f(x)) == \ + Eq(f(x), C1 + Piecewise( + (x**2/2, Eq(k**3, 0)), + ((-k**2*x - k)*exp(-k*x)/k**3, True) + )) + assert dsolve(-f(x).diff(x) + x*exp(-k*x), f(x)) == \ + Eq(f(x), Piecewise((C1 + x**2/2, Eq(k**3, 0)), + (C1 - x*exp(-k*x)/k - exp(-k*x)/k**2, True) + )) + + +def test_heuristic1(): + y, a, b, c, a4, a3, a2, a1, a0 = symbols("y a b c a4 a3 a2 a1 a0") + y = Symbol('y') + f = Function('f') + xi = Function('xi') + eta = Function('eta') + df = f(x).diff(x) + eq = Eq(df, x**2*f(x)) + eq1 = f(x).diff(x) + a*f(x) - c*exp(b*x) + eq2 = f(x).diff(x) + 2*x*f(x) - x*exp(-x**2) + eq3 = (1 + 2*x)*df + 2 - 4*exp(-f(x)) + eq4 = f(x).diff(x)-(a4*x**4+a3*x**3+a2*x**2+a1*x+a0)**(S(-1)/2) + eq5 = x**2*df - f(x) + x**2*exp(x - (1/x)) + eqlist = [eq, eq1, eq2, eq3, eq4, eq5] + + i = infinitesimals(eq) + assert i == [{eta(x, f(x)): exp(x**3/3), xi(x, f(x)): 0}, + {eta(x, f(x)): f(x), xi(x, f(x)): 0}, {eta(x, f(x)): 0, xi(x, f(x)): x**(-2)}, + {eta(x, f(x)): x**2*f(x) + f(x), xi(x, f(x)): 1}] + i1 = infinitesimals(eq1) + assert i1 == [{eta(x, f(x)): exp(-a*x), xi(x, f(x)): 0}] + i2 = infinitesimals(eq2) + assert i2 == [{eta(x, f(x)): exp(-x**2), xi(x, f(x)): 0}] + i3 = infinitesimals(eq3) + assert i3 == [{eta(x, f(x)): 0, xi(x, f(x)): 2*x + 1}, + {eta(x, f(x)): 0, xi(x, f(x)): 1/(exp(f(x)) - 2)}] + i4 = infinitesimals(eq4) + assert i4 == [{eta(x, f(x)): 1, xi(x, f(x)): 0}, + {eta(x, f(x)): 0, xi(x, f(x)): sqrt(2*a0 + 2*a1*x + 2*a2*x**2 + 2*a3*x**3 + + 2*a4*x**4)}] + i5 = infinitesimals(eq5) + assert i5 == [{xi(x, f(x)): 0, eta(x, f(x)): exp(-1/x)}] + + ilist = [i, i1, i2, i3, i4, i5] + for eq, i in (list(zip(eqlist, ilist))): + check = checkinfsol(eq, i) + for sol in check: + assert sol[0] + + +@XFAIL +def test_issue_3148(): + eq = x**2*f(x)**2 + x*Derivative(f(x), x) + sol = dsolve(eq, hint = 'separable_reduced') + assert checkodesol(eq, sol, order=1)[0] + + +def test_heuristic2(): + y = Symbol('y') + xi = Function('xi') + eta = Function('eta') + df = f(x).diff(x) + eq = df -(f(x)/x)*(x*log(x**2/f(x)) + 2) + i = infinitesimals(eq) + assert i == [{eta(x, f(x)): f(x)*exp(-x), xi(x, f(x)): 0}] + assert checkinfsol(eq, i)[0] + + eq = x*(f(x).diff(x))-f(x)*(2+x*log(x**2/f(x))) + i = infinitesimals(eq) + assert i == [{eta(x, f(x)): f(x)*exp(-x), xi(x, f(x)): 0}] + assert checkinfsol(eq, i)[0] + + eq = x*(f(x).diff(x))-f(x)*log(f(x)) + i = infinitesimals(eq) + assert i == [{eta(x, f(x)): 0, xi(x, f(x)): x}, + {eta(x, f(x)): 0, xi(x, f(x)): log(f(x))}, + {eta(x, f(x)): f(x)*log(f(x))**2/x, xi(x, f(x)): 0}] + assert checkinfsol(eq, i)[-1][0] + +def test_heuristic3(): + y = Symbol('y') + xi = Function('xi') + eta = Function('eta') + a, b = symbols("a b") + df = f(x).diff(x) + eq = x**2*df - (x - 1)*f(x) + i = infinitesimals(eq) + assert i == [{eta(x, f(x)): x*exp(1/x), xi(x, f(x)): 0}, + {eta(x, f(x)): f(x), xi(x, f(x)): 0}, + {eta(x, f(x)): x*f(x) + f(x), xi(x, f(x)): x**2}] + assert checkinfsol(eq, i)[-1][0] + + eq = df - f(x)**2 + (f(x)/x) + i = infinitesimals(eq) + assert checkinfsol(eq, i)[0] + + eq = x**2*df + x*f(x) + f(x)**2 + x**2 + i = infinitesimals(eq) + assert i == [{eta(x, f(x)): f(x), xi(x, f(x)): x}] + assert checkinfsol(eq, i)[0] + + eq = x**2*(-f(x)**2 + df)- a*x**2*f(x) +2 -a*x + i = infinitesimals(eq) + assert checkinfsol(eq, i)[0] diff -Nru python3-sympy-0.7.2/sympy/solvers/tests/test_pde.py python3-sympy-0.7.3/sympy/solvers/tests/test_pde.py --- python3-sympy-0.7.2/sympy/solvers/tests/test_pde.py 2012-10-17 03:02:22.000000000 +0000 +++ python3-sympy-0.7.3/sympy/solvers/tests/test_pde.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,7 +1,11 @@ -from sympy import Derivative as D, Eq, exp, Function, Symbol, symbols -from sympy.solvers.pde import pde_separate_add, pde_separate_mul +from sympy import (Derivative as D, Eq, exp, sin, + Function, Symbol, symbols, cos, log) +from sympy.core import S +from sympy.solvers.pde import (pde_separate_add, pde_separate_mul, + pdsolve, classify_pde, checkpdesol) from sympy.utilities.pytest import raises +a, b, c, x, y = symbols('a b c x y') def test_pde_separate_add(): x, y, z, t = symbols("x,y,z,t") F, T, X, Y, Z, u = list(map(Function, 'FTXYZu')) @@ -10,6 +14,7 @@ res = pde_separate_add(eq, u(x, t), [X(x), T(t)]) assert res == [D(X(x), x)*exp(-X(x)), D(T(t), t)*exp(T(t))] + def test_pde_separate_mul(): x, y, z, t = symbols("x,y,z,t") c = Symbol("C", real=True) @@ -21,16 +26,18 @@ eq = Eq(D(F(x, y, z), x) + D(F(x, y, z), y) + D(F(x, y, z), z)) # Duplicate arguments in functions - raises (ValueError, lambda: pde_separate_mul(eq, F(x, y, z), [X(x), u(z, z)])) + raises( + ValueError, lambda: pde_separate_mul(eq, F(x, y, z), [X(x), u(z, z)])) # Wrong number of arguments - raises (ValueError, lambda: pde_separate_mul(eq, F(x, y, z), [X(x), Y(y)])) + raises(ValueError, lambda: pde_separate_mul(eq, F(x, y, z), [X(x), Y(y)])) # Wrong variables: [x, y] -> [x, z] - raises (ValueError, lambda: pde_separate_mul(eq, F(x, y, z), [X(t), Y(x, y)])) + raises( + ValueError, lambda: pde_separate_mul(eq, F(x, y, z), [X(t), Y(x, y)])) assert pde_separate_mul(eq, F(x, y, z), [Y(y), u(x, z)]) == \ - [D(Y(y), y)/Y(y), -D(u(x, z), x)/u(x, z) - D(u(x, z), z)/u(x, z)] + [D(Y(y), y)/Y(y), -D(u(x, z), x)/u(x, z) - D(u(x, z), z)/u(x, z)] assert pde_separate_mul(eq, F(x, y, z), [X(x), Y(y), Z(z)]) == \ - [D(X(x), x)/X(x), -D(Z(z), z)/Z(z) - D(Y(y), y)/Y(y)] + [D(X(x), x)/X(x), -D(Z(z), z)/Z(z) - D(Y(y), y)/Y(y)] # wave equation wave = Eq(D(u(x, t), t, t), c**2*D(u(x, t), x, x)) @@ -38,21 +45,135 @@ assert res == [D(X(x), x, x)/X(x), D(T(t), t, t)/(c**2*T(t))] # Laplace equation in cylindrical coords - eq = Eq(1/r * D(Phi(r, theta, z), r) + D(Phi(r, theta, z), r, 2) + \ + eq = Eq(1/r * D(Phi(r, theta, z), r) + D(Phi(r, theta, z), r, 2) + 1/r**2 * D(Phi(r, theta, z), theta, 2) + D(Phi(r, theta, z), z, 2)) # Separate z res = pde_separate_mul(eq, Phi(r, theta, z), [Z(z), u(theta, r)]) - assert res == [D(Z(z), z, z)/Z(z), \ - -D(u(theta, r), r, r)/u(theta, r) - \ - D(u(theta, r), r)/(r*u(theta, r)) - \ - D(u(theta, r), theta, theta)/(r**2*u(theta, r))] + assert res == [D(Z(z), z, z)/Z(z), + -D(u(theta, r), r, r)/u(theta, r) - + D(u(theta, r), r)/(r*u(theta, r)) - + D(u(theta, r), theta, theta)/(r**2*u(theta, r))] # Lets use the result to create a new equation... eq = Eq(res[1], c) # ...and separate theta... res = pde_separate_mul(eq, u(theta, r), [T(theta), R(r)]) - assert res == [D(T(theta), theta, theta)/T(theta), \ + assert res == [D(T(theta), theta, theta)/T(theta), -r*D(R(r), r)/R(r) - r**2*D(R(r), r, r)/R(r) - c*r**2] # ...or r... res = pde_separate_mul(eq, u(theta, r), [R(r), T(theta)]) - assert res == [r*D(R(r), r)/R(r) + r**2*D(R(r), r, r)/R(r) + c*r**2, \ + assert res == [r*D(R(r), r)/R(r) + r**2*D(R(r), r, r)/R(r) + c*r**2, -D(T(theta), theta, theta)/T(theta)] + +def test_pde_classify(): + # When more number of hints are added, add tests for classifying here. + f = Function('f') + eq1 = a*f(x,y) + b*f(x,y).diff(x) + c*f(x,y).diff(y) + eq2 = 3*f(x,y) + 2*f(x,y).diff(x) + f(x,y).diff(y) + eq3 = a*f(x,y) + b*f(x,y).diff(x) + 2*f(x,y).diff(y) + eq4 = x*f(x,y) + f(x,y).diff(x) + 3*f(x,y).diff(y) + eq5 = x**2*f(x,y) + x*f(x,y).diff(x) + x*y*f(x,y).diff(y) + eq6 = y*x**2*f(x,y) + y*f(x,y).diff(x) + f(x,y).diff(y) + for eq in [eq1, eq2, eq3]: + assert classify_pde(eq) == ('1st_linear_constant_coeff_homogeneous',) + for eq in [eq4, eq5, eq6]: + assert classify_pde(eq) == () + + +def test_checkpdesol(): + f, F = list(map(Function, ['f', 'F'])) + eq1 = a*f(x,y) + b*f(x,y).diff(x) + c*f(x,y).diff(y) + eq2 = 3*f(x,y) + 2*f(x,y).diff(x) + f(x,y).diff(y) + eq3 = a*f(x,y) + b*f(x,y).diff(x) + 2*f(x,y).diff(y) + for eq in [eq1, eq2, eq3]: + assert checkpdesol(eq, pdsolve(eq))[0] + eq4 = x*f(x,y) + f(x,y).diff(x) + 3*f(x,y).diff(y) + eq5 = 2*f(x,y) + 1*f(x,y).diff(x) + 3*f(x,y).diff(y) + eq6 = f(x,y) + 1*f(x,y).diff(x) + 3*f(x,y).diff(y) + assert checkpdesol(eq4, [pdsolve(eq5), pdsolve(eq6)]) == [ + (False, (x - 2)*F(3*x - y)*exp(-x/S(5) - 3*y/S(5))), + (False, (x - 1)*F(3*x - y)*exp(-x/S(10) - 3*y/S(10)))] + + +def test_solvefun(): + f, F, G, H = list(map(Function, ['f', 'F', 'G', 'H'])) + eq1 = f(x,y) + f(x,y).diff(x) + f(x,y).diff(y) + assert pdsolve(eq1) == Eq(f(x, y), F(x - y)*exp(-x/2 - y/2)) + assert pdsolve(eq1, solvefun=G) == Eq(f(x, y), G(x - y)*exp(-x/2 - y/2)) + assert pdsolve(eq1, solvefun=H) == Eq(f(x, y), H(x - y)*exp(-x/2 - y/2)) + + +def test_pde_1st_linear_constant_coeff_homogeneous(): + f, F = list(map(Function, ['f', 'F'])) + u = f(x, y) + eq = 2*u + u.diff(x) + u.diff(y) + assert classify_pde(eq) == ('1st_linear_constant_coeff_homogeneous',) + sol = pdsolve(eq) + assert sol == Eq(u, F(x - y)*exp(-x - y)) + assert checkpdesol(eq, sol)[0] + + eq = 4 + (3*u.diff(x)/u) + (2*u.diff(y)/u) + assert classify_pde(eq) == ('1st_linear_constant_coeff_homogeneous',) + sol = pdsolve(eq) + assert sol == Eq(u, F(2*x - 3*y)*exp(-S(12)*x/13 - S(8)*y/13)) + assert checkpdesol(eq, sol)[0] + + eq = u + (6*u.diff(x)) + (7*u.diff(y)) + assert classify_pde(eq) == ('1st_linear_constant_coeff_homogeneous',) + sol = pdsolve(eq) + assert sol == Eq(u, F(7*x - 6*y)*exp(-6*x/S(85) - 7*y/S(85))) + assert checkpdesol(eq, sol)[0] + + eq = a*u + b*u.diff(x) + c*u.diff(y) + sol = pdsolve(eq) + assert checkpdesol(eq, sol)[0] + +def test_pde_1st_linear_constant_coeff(): + f, F = list(map(Function, ['f', 'F'])) + u = f(x,y) + eq = -2*u.diff(x) + 4*u.diff(y) + 5*u - exp(x + 3*y) + sol = pdsolve(eq) + assert sol == Eq(f(x,y), + (F(4*x + 2*y) + exp(x/S(2) + 4*y)/S(15))*exp(x/S(2) - y)) + assert classify_pde(eq) == ('1st_linear_constant_coeff', + '1st_linear_constant_coeff_Integral') + assert checkpdesol(eq, sol)[0] + + eq = (u.diff(x)/u) + (u.diff(y)/u) + 1 - (exp(x + y)/u) + sol = pdsolve(eq) + assert sol == Eq(f(x, y), F(x - y)*exp(-x/2 - y/2) + exp(x + y)/S(3)) + assert classify_pde(eq) == ('1st_linear_constant_coeff', + '1st_linear_constant_coeff_Integral') + assert checkpdesol(eq, sol)[0] + + eq = 2*u + -u.diff(x) + 3*u.diff(y) + sin(x) + sol = pdsolve(eq) + assert sol == Eq(f(x, y), + F(3*x + y)*exp(x/S(5) - 3*y/S(5)) - 2*sin(x)/S(5) - cos(x)/S(5)) + assert classify_pde(eq) == ('1st_linear_constant_coeff', + '1st_linear_constant_coeff_Integral') + assert checkpdesol(eq, sol)[0] + + eq = u + u.diff(x) + u.diff(y) + x*y + sol = pdsolve(eq) + assert sol == Eq(f(x, y), + -x*y + x + y + F(x - y)*exp(-x/S(2) - y/S(2)) - 2) + assert classify_pde(eq) == ('1st_linear_constant_coeff', + '1st_linear_constant_coeff_Integral') + assert checkpdesol(eq, sol)[0] + + eq = u + u.diff(x) + u.diff(y) + log(x) + assert classify_pde(eq) == ('1st_linear_constant_coeff', + '1st_linear_constant_coeff_Integral') + +def test_pdsolve_all(): + f, F = list(map(Function, ['f', 'F'])) + u = f(x,y) + eq = u + u.diff(x) + u.diff(y) + x**2*y + sol = pdsolve(eq, hint = 'all') + keys = ['1st_linear_constant_coeff', + '1st_linear_constant_coeff_Integral', 'default', 'order'] + assert sorted(sol.keys()) == keys + assert sol['order'] == 1 + assert sol['default'] == '1st_linear_constant_coeff' + assert sol['1st_linear_constant_coeff'] == Eq(f(x, y), + -x**2*y + x**2 + 2*x*y - 4*x - 2*y + F(x - y)*exp(-x/S(2) - y/S(2)) + 6) diff -Nru python3-sympy-0.7.2/sympy/solvers/tests/test_polysys.py python3-sympy-0.7.3/sympy/solvers/tests/test_polysys.py --- python3-sympy-0.7.2/sympy/solvers/tests/test_polysys.py 2012-10-17 03:02:22.000000000 +0000 +++ python3-sympy-0.7.3/sympy/solvers/tests/test_polysys.py 2013-07-13 17:53:32.000000000 +0000 @@ -6,10 +6,11 @@ from sympy.solvers.polysys import solve_poly_system, solve_triangulated from sympy.utilities.pytest import raises + def test_solve_poly_system(): - assert solve_poly_system([x-1], x) == [(S.One,)] + assert solve_poly_system([x - 1], x) == [(S.One,)] - assert solve_poly_system([y - x, y - x - 1], x, y) == None + assert solve_poly_system([y - x, y - x - 1], x, y) is None assert solve_poly_system([y - x**2, y + x**2], x, y) == [(S.Zero, S.Zero)] @@ -17,10 +18,10 @@ [(Rational(3, 2), Integer(2), Integer(10))] assert solve_poly_system([x*y - 2*y, 2*y**2 - x**2], x, y) == \ - [(0, 0), (2, -sqrt(2)), (2, sqrt(2))] + [(0, 0), (2, -sqrt(2)), (2, sqrt(2))] assert solve_poly_system([y - x**2, y + x**2 + 1], x, y) == \ - [(I*sqrt(S.Half), -S.Half), (-I*sqrt(S.Half), -S.Half)] + [(I*sqrt(S.Half), -S.Half), (-I*sqrt(S.Half), -S.Half)] f_1 = x**2 + y + z - 1 f_2 = x + y**2 + z - 1 @@ -37,11 +38,13 @@ assert solve_poly_system([x**2 - y**2, x - 1], x, y) == solution assert solve_poly_system([x**2 - y**2, x - 1]) == solution - assert solve_poly_system([x + x*y - 3, y + x*y - 4], x, y) == [(-3, -2), (1, 2)] + assert solve_poly_system( + [x + x*y - 3, y + x*y - 4], x, y) == [(-3, -2), (1, 2)] - raises(NotImplementedError, lambda: solve_poly_system([x**3-y**3], x, y)) + raises(NotImplementedError, lambda: solve_poly_system([x**3 - y**3], x, y)) raises(PolynomialError, lambda: solve_poly_system([1/x], x)) + def test_solve_biquadratic(): x0, y0, x1, y1, r = symbols('x0 y0 x1 y1 r') @@ -77,6 +80,7 @@ assert len(result) == 2 and all(len(r) == 2 for r in result) assert all(len(r.find(query)) == 1 for r in flatten(result)) + def test_solve_triangualted(): f_1 = x**2 + y + z - 1 f_2 = x + y**2 + z - 1 diff -Nru python3-sympy-0.7.2/sympy/solvers/tests/test_recurr.py python3-sympy-0.7.3/sympy/solvers/tests/test_recurr.py --- python3-sympy-0.7.2/sympy/solvers/tests/test_recurr.py 2012-10-17 03:02:22.000000000 +0000 +++ python3-sympy-0.7.3/sympy/solvers/tests/test_recurr.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,104 +1,192 @@ -from sympy import factorial, Function, rf, S, sqrt, symbols +from sympy import Eq, factorial, Function, Lambda, rf, S, sqrt, symbols, I, expand_func, binomial, gamma from sympy.solvers.recurr import rsolve, rsolve_hyper, rsolve_poly, rsolve_ratio +from sympy.utilities.pytest import raises +from sympy.abc import a, b, c y = Function('y') n, k = symbols('n,k', integer=True) C0, C1, C2 = symbols('C0,C1,C2') + def test_rsolve_poly(): assert rsolve_poly([-1, -1, 1], 0, n) == 0 assert rsolve_poly([-1, -1, 1], 1, n) == -1 - assert rsolve_poly([-1, n+1], n, n) == 1 + assert rsolve_poly([-1, n + 1], n, n) == 1 assert rsolve_poly([-1, 1], n, n) == C0 + (n**2 - n)/2 - assert rsolve_poly([-n-1, n], 1, n) == C1*n - 1 - assert rsolve_poly([-4*n-2, 1], 4*n+1, n) == -1 + assert rsolve_poly([-n - 1, n], 1, n) == C1*n - 1 + assert rsolve_poly([-4*n - 2, 1], 4*n + 1, n) == -1 + + assert rsolve_poly([-1, 1], n**5 + n**3, n) == \ + C0 - n**3 / 2 - n**5 / 2 + n**2 / 6 + n**6 / 6 + 2*n**4 / 3 - assert rsolve_poly([-1, 1], n**5 + n**3, n) == C0 - n**3 / 2 - n**5 / 2 + n**2 / 6 + n**6 / 6 + 2*n**4 / 3 def test_rsolve_ratio(): - solution = rsolve_ratio([-2*n**3+n**2+2*n-1, 2*n**3+n**2-6*n, - -2*n**3-11*n**2-18*n-9, 2*n**3+13*n**2+22*n+8], 0, n) + solution = rsolve_ratio([-2*n**3 + n**2 + 2*n - 1, 2*n**3 + n**2 - 6*n, + -2*n**3 - 11*n**2 - 18*n - 9, 2*n**3 + 13*n**2 + 22*n + 8], 0, n) assert solution in [ - C1*((-2*n + 3)/(n**2 - 1))/3, + C1*((-2*n + 3)/(n**2 - 1))/3, (S(1)/2)*(C1*(-3 + 2*n)/(-1 + n**2)), (S(1)/2)*(C1*( 3 - 2*n)/( 1 - n**2)), (S(1)/2)*(C2*(-3 + 2*n)/(-1 + n**2)), (S(1)/2)*(C2*( 3 - 2*n)/( 1 - n**2)), ] + def test_rsolve_hyper(): assert rsolve_hyper([-1, -1, 1], 0, n) in [ C0*(S.Half - S.Half*sqrt(5))**n + C1*(S.Half + S.Half*sqrt(5))**n, C1*(S.Half - S.Half*sqrt(5))**n + C0*(S.Half + S.Half*sqrt(5))**n, ] - assert rsolve_hyper([n**2-2, -2*n-1, 1], 0, n) in [ + assert rsolve_hyper([n**2 - 2, -2*n - 1, 1], 0, n) in [ C0*rf(sqrt(2), n) + C1*rf(-sqrt(2), n), C1*rf(sqrt(2), n) + C0*rf(-sqrt(2), n), ] - assert rsolve_hyper([n**2-k, -2*n-1, 1], 0, n) in [ + assert rsolve_hyper([n**2 - k, -2*n - 1, 1], 0, n) in [ C0*rf(sqrt(k), n) + C1*rf(-sqrt(k), n), C1*rf(sqrt(k), n) + C0*rf(-sqrt(k), n), ] - assert rsolve_hyper([2*n*(n+1), -n**2-3*n+2, n-1], 0, n) == C1*factorial(n) + C0*2**n + assert rsolve_hyper( + [2*n*(n + 1), -n**2 - 3*n + 2, n - 1], 0, n) == C1*factorial(n) + C0*2**n - assert rsolve_hyper([n + 2, -(2*n + 3)*(17*n**2 + 51*n + 39), n + 1], 0, n) == 0 + assert rsolve_hyper( + [n + 2, -(2*n + 3)*(17*n**2 + 51*n + 39), n + 1], 0, n) == None - assert rsolve_hyper([-n-1, -1, 1], 0, n) == 0 + assert rsolve_hyper([-n - 1, -1, 1], 0, n) == None assert rsolve_hyper([-1, 1], n, n).expand() == C0 + n**2/2 - n/2 - assert rsolve_hyper([-1, 1], 1+n, n).expand() == C0 + n**2/2 + n/2 + assert rsolve_hyper([-1, 1], 1 + n, n).expand() == C0 + n**2/2 + n/2 + + assert rsolve_hyper([-1, 1], 3*(n + n**2), n).expand() == C0 + n**3 - n + + assert rsolve_hyper([-a, 1],0,n).expand() == C0*a**n + + assert rsolve_hyper([-a, 0, 1], 0, n).expand() == (-1)**n*C1*a**(n/2) + C0*a**(n/2) + + assert rsolve_hyper([1, 1, 1], 0, n).expand() == \ + C0*(-S(1)/2 - sqrt(3)*I/2)**n + C1*(-S(1)/2 + sqrt(3)*I/2)**n + + assert rsolve_hyper([1, -2*n/a - 2/a, 1], 0, n) == None - assert rsolve_hyper([-1, 1], 3*(n+n**2), n).expand() == C0 + n**3 - n def recurrence_term(c, f): """Compute RHS of recurrence in f(n) with coefficients in c.""" - return sum(c[i]*f.subs(n, n+i) for i in range(len(c))) + return sum(c[i]*f.subs(n, n + i) for i in range(len(c))) -def rsolve_bulk_checker(solver, c, q, p): - """Used by test_rsolve_bulk.""" - pp = solver(c, q, n) - assert pp == p def test_rsolve_bulk(): """Some bulk-generated tests.""" - funcs = [ n, n+1, n**2, n**3, n**4, n+n**2, 27*n + 52*n**2 - 3*n**3 + 12*n**4 - 52*n**5 ] - coeffs = [ [-2, 1], [-2, -1, 1], [-1, 1, 1, -1, 1], [-n, 1], [n**2-n+12, 1] ] + funcs = [ n, n + 1, n**2, n**3, n**4, n + n**2, 27*n + 52*n**2 - 3* + n**3 + 12*n**4 - 52*n**5 ] + coeffs = [ [-2, 1], [-2, -1, 1], [-1, 1, 1, -1, 1], [-n, 1], [n**2 - + n + 12, 1] ] for p in funcs: # compute difference for c in coeffs: q = recurrence_term(c, p) if p.is_polynomial(n): - yield rsolve_bulk_checker, rsolve_poly, c, q, p + assert rsolve_poly(c, q, n) == p #if p.is_hypergeometric(n): - # yield rsolve_bulk_checker, rsolve_hyper, c, q, p + # assert rsolve_hyper(c, q, n) == p + def test_rsolve(): - f = y(n+2) - y(n+1) - y(n) + f = y(n + 2) - y(n + 1) - y(n) h = sqrt(5)*(S.Half + S.Half*sqrt(5))**n \ - - sqrt(5)*(S.Half - S.Half*sqrt(5))**n + - sqrt(5)*(S.Half - S.Half*sqrt(5))**n assert rsolve(f, y(n)) in [ C0*(S.Half - S.Half*sqrt(5))**n + C1*(S.Half + S.Half*sqrt(5))**n, C1*(S.Half - S.Half*sqrt(5))**n + C0*(S.Half + S.Half*sqrt(5))**n, ] - assert rsolve(f, y(n), [ 0, 5 ]) == h - assert rsolve(f, y(n), { 0 :0, 1 :5 }) == h - assert rsolve(f, y(n), { y(0):0, y(1):5 }) == h - assert rsolve(y(n) - y(n-1) - y(n-2), y(n), [0, 5]) == h + assert rsolve(f, y(n), [0, 5]) == h + assert rsolve(f, y(n), {0: 0, 1: 5}) == h + assert rsolve(f, y(n), {y(0): 0, y(1): 5}) == h + assert rsolve(y(n) - y(n - 1) - y(n - 2), y(n), [0, 5]) == h + assert rsolve(Eq(y(n), y(n - 1) + y(n - 2)), y(n), [0, 5]) == h + + assert f.subs(y, Lambda(k, rsolve(f, y(n)).subs(n, k))).simplify() == 0 - f = (n-1)*y(n+2) - (n**2+3*n-2)*y(n+1) + 2*n*(n+1)*y(n) + f = (n - 1)*y(n + 2) - (n**2 + 3*n - 2)*y(n + 1) + 2*n*(n + 1)*y(n) g = C1*factorial(n) + C0*2**n h = -3*factorial(n) + 3*2**n assert rsolve(f, y(n)) == g + assert rsolve(f, y(n), []) == g + assert rsolve(f, y(n), {}) == g + + assert rsolve(f, y(n), [0, 3]) == h + assert rsolve(f, y(n), {0: 0, 1: 3}) == h + assert rsolve(f, y(n), {y(0): 0, y(1): 3}) == h + + assert f.subs(y, Lambda(k, rsolve(f, y(n)).subs(n, k))).simplify() == 0 + + f = y(n) - y(n - 1) - 2 + + assert rsolve(f, y(n), {y(0): 0}) == 2*n + assert rsolve(f, y(n), {y(0): 1}) == 2*n + 1 + assert rsolve(f, y(n), {y(0): 0, y(1): 1}) is None + + assert f.subs(y, Lambda(k, rsolve(f, y(n)).subs(n, k))).simplify() == 0 + + f = 3*y(n - 1) - y(n) - 1 + + assert rsolve(f, y(n), {y(0): 0}) == -3**n/2 + S.Half + assert rsolve(f, y(n), {y(0): 1}) == 3**n/2 + S.Half + assert rsolve(f, y(n), {y(0): 2}) == 3*3**n/2 + S.Half + + assert f.subs(y, Lambda(k, rsolve(f, y(n)).subs(n, k))).simplify() == 0 + + f = y(n) - 1/n*y(n - 1) + assert rsolve(f, y(n)) == C0/factorial(n) + assert f.subs(y, Lambda(k, rsolve(f, y(n)).subs(n, k))).simplify() == 0 + + f = y(n) - 1/n*y(n - 1) - 1 + assert rsolve(f, y(n)) is None + + f = 2*y(n - 1) + (1 - n)*y(n)/n + + assert rsolve(f, y(n), {y(1): 1}) == 2**(n - 1)*n + assert rsolve(f, y(n), {y(1): 2}) == 2**(n - 1)*n*2 + assert rsolve(f, y(n), {y(1): 3}) == 2**(n - 1)*n*3 + + assert f.subs(y, Lambda(k, rsolve(f, y(n)).subs(n, k))).simplify() == 0 + + f = (n - 1)*(n - 2)*y(n + 2) - (n + 1)*(n + 2)*y(n) + + assert rsolve(f, y(n), {y(3): 6, y(4): 24}) == n*(n - 1)*(n - 2) + assert rsolve( + f, y(n), {y(3): 6, y(4): -24}) == -n*(n - 1)*(n - 2)*(-1)**(n) + + assert f.subs(y, Lambda(k, rsolve(f, y(n)).subs(n, k))).simplify() == 0 + + assert rsolve(Eq(y(n + 1), a*y(n)), y(n), {y(1): a}).simplify() == a**n + + assert rsolve(y(n) - a*y(n-2),y(n), \ + {y(1): sqrt(a)*(a + b), y(2): a*(a - b)}).simplify() == \ + a**(n/2)*(-(-1)**n*b + a) + + f = (-16*n**2 + 32*n - 12)*y(n - 1) + (4*n**2 - 12*n + 9)*y(n) + + assert expand_func(rsolve(f, y(n), \ + {y(1): binomial(2*n + 1, 3)}).rewrite(gamma)).simplify() == \ + 2**(2*n)*n*(2*n - 1)*(4*n**2 - 1)/12 + + assert (rsolve(y(n) + a*(y(n + 1) + y(n - 1))/2, y(n)) - + (C0*((sqrt(-a**2 + 1) - 1)/a)**n + + C1*((-sqrt(-a**2 + 1) - 1)/a)**n)).simplify() == 0 + - assert rsolve(f, y(n), [ 0, 3 ]) == h - assert rsolve(f, y(n), { 0 :0, 1 :3 }) == h - assert rsolve(f, y(n), { y(0):0, y(1):3 }) == h +def test_rsolve_raises(): + x = Function('x') + raises(ValueError, lambda: rsolve(y(n) - y(k + 1), y(n))) + raises(ValueError, lambda: rsolve(y(n) - y(n + 1), x(n))) + raises(ValueError, lambda: rsolve(y(n) - x(n + 1), y(n))) + raises(ValueError, lambda: rsolve(y(n) - sqrt(n)*y(n + 1), y(n))) + raises(ValueError, lambda: rsolve(y(n) - y(n + 1), y(n), {x(0): 0})) diff -Nru python3-sympy-0.7.2/sympy/solvers/tests/test_solvers.py python3-sympy-0.7.3/sympy/solvers/tests/test_solvers.py --- python3-sympy-0.7.2/sympy/solvers/tests/test_solvers.py 2012-10-17 03:02:22.000000000 +0000 +++ python3-sympy-0.7.3/sympy/solvers/tests/test_solvers.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,26 +1,35 @@ -from sympy import (Matrix, Symbol, solve, exp, log, cos, acos, Rational, Eq, - sqrt, LambertW, pi, I, sin, asin, Function, diff, Derivative, symbols, - S, sympify, sstr, Wild, solve_linear, Integral, - And, Or, Lt, Gt, Q, re, im, expand, tan, Poly, cosh, sinh, atanh, - atan, Dummy, Float, tanh) -from sympy.abc import a, b, c, d, k, h, p, x, y, z, t +from sympy import ( + Abs, And, Derivative, Dummy, Eq, Float, Function, Gt, I, Integral, + LambertW, Lt, Matrix, Or, Piecewise, Poly, Q, Rational, S, Symbol, + Wild, acos, asin, atan, atanh, cos, cosh, diff, exp, expand, im, + log, pi, re, sec, sin, sinh, solve, solve_linear, sqrt, sstr, symbols, + sympify, tan, tanh, root, simplify, atan2, arg) from sympy.core.function import nfloat -from sympy.solvers import solve_linear_system, solve_linear_system_LU,\ - solve_undetermined_coeffs -from sympy.solvers.solvers import _invert, unrad, checksol, posify +from sympy.solvers import solve_linear_system, solve_linear_system_LU, \ + solve_undetermined_coeffs +from sympy.solvers.solvers import _invert, unrad, checksol, posify, _ispow + +from sympy.polys.rootoftools import RootOf + +from sympy.utilities.pytest import slow, XFAIL, raises, skip +from sympy.utilities.randtest import test_numerically as tn + +from sympy.abc import a, b, c, d, k, h, p, x, y, z, t, q, m -from sympy.utilities.pytest import XFAIL, raises, skip def NS(e, n=15, **options): return sstr(sympify(e).evalf(n, **options), full_prec=True) + def test_swap_back(): f, g = list(map(Function, 'fg')) fx, gx = f(x), g(x) assert solve([fx + y - 2, fx - gx - 5], fx, y, gx) == \ - {fx: gx + 5, y: -gx - 3} + {fx: gx + 5, y: -gx - 3} assert solve(fx + gx*x - 2, [fx, gx]) == {fx: 2, gx: 0} assert solve(fx + gx**2*x - y, [fx, gx]) == [{fx: y - gx**2*x}] + assert solve([f(1) - 2, x + 2]) == [{x: -2, f(1): 2}] + def guess_solve_strategy(eq, symbol): try: @@ -29,66 +38,78 @@ except (TypeError, NotImplementedError): return False + def test_guess_poly(): # polynomial equations - assert guess_solve_strategy( S(4), x ) #== GS_POLY - assert guess_solve_strategy( x, x ) #== GS_POLY - assert guess_solve_strategy( x + a, x ) #== GS_POLY - assert guess_solve_strategy( 2*x, x ) #== GS_POLY - assert guess_solve_strategy( x + sqrt(2), x) #== GS_POLY - assert guess_solve_strategy( x + 2**Rational(1,4), x) #== GS_POLY - assert guess_solve_strategy( x**2 + 1, x ) #== GS_POLY - assert guess_solve_strategy( x**2 - 1, x ) #== GS_POLY - assert guess_solve_strategy( x*y + y, x ) #== GS_POLY - assert guess_solve_strategy( x*exp(y) + y, x) #== GS_POLY - assert guess_solve_strategy( (x - y**3)/(y**2*sqrt(1 - y**2)), x) #== GS_POLY + assert guess_solve_strategy( S(4), x ) # == GS_POLY + assert guess_solve_strategy( x, x ) # == GS_POLY + assert guess_solve_strategy( x + a, x ) # == GS_POLY + assert guess_solve_strategy( 2*x, x ) # == GS_POLY + assert guess_solve_strategy( x + sqrt(2), x) # == GS_POLY + assert guess_solve_strategy( x + 2**Rational(1, 4), x) # == GS_POLY + assert guess_solve_strategy( x**2 + 1, x ) # == GS_POLY + assert guess_solve_strategy( x**2 - 1, x ) # == GS_POLY + assert guess_solve_strategy( x*y + y, x ) # == GS_POLY + assert guess_solve_strategy( x*exp(y) + y, x) # == GS_POLY + assert guess_solve_strategy( + (x - y**3)/(y**2*sqrt(1 - y**2)), x) # == GS_POLY + def test_guess_poly_cv(): # polynomial equations via a change of variable - assert guess_solve_strategy( sqrt(x) + 1, x ) #== GS_POLY_CV_1 - assert guess_solve_strategy( x**Rational(1,3) + sqrt(x) + 1, x ) #== GS_POLY_CV_1 - assert guess_solve_strategy( 4*x*(1 - sqrt(x)), x ) #== GS_POLY_CV_1 + assert guess_solve_strategy( sqrt(x) + 1, x ) # == GS_POLY_CV_1 + assert guess_solve_strategy( + x**Rational(1, 3) + sqrt(x) + 1, x ) # == GS_POLY_CV_1 + assert guess_solve_strategy( 4*x*(1 - sqrt(x)), x ) # == GS_POLY_CV_1 # polynomial equation multiplying both sides by x**n - assert guess_solve_strategy( x + 1/x + y, x ) #== GS_POLY_CV_2 + assert guess_solve_strategy( x + 1/x + y, x ) # == GS_POLY_CV_2 + def test_guess_rational_cv(): # rational functions - assert guess_solve_strategy( (x+1)/(x**2 + 2), x) #== GS_RATIONAL - assert guess_solve_strategy( (x - y**3)/(y**2*sqrt(1 - y**2)), y) #== GS_RATIONAL_CV_1 + assert guess_solve_strategy( (x + 1)/(x**2 + 2), x) # == GS_RATIONAL + assert guess_solve_strategy( + (x - y**3)/(y**2*sqrt(1 - y**2)), y) # == GS_RATIONAL_CV_1 # rational functions via the change of variable y -> x**n - assert guess_solve_strategy( (sqrt(x) + 1)/(x**Rational(1,3) + sqrt(x) + 1), x ) \ - #== GS_RATIONAL_CV_1 + assert guess_solve_strategy( (sqrt(x) + 1)/(x**Rational(1, 3) + sqrt(x) + 1), x ) \ + #== GS_RATIONAL_CV_1 + def test_guess_transcendental(): #transcendental functions - assert guess_solve_strategy( exp(x) + 1, x ) #== GS_TRANSCENDENTAL - assert guess_solve_strategy( 2*cos(x)-y, x ) #== GS_TRANSCENDENTAL - assert guess_solve_strategy( exp(x) + exp(-x) - y, x ) #== GS_TRANSCENDENTAL - assert guess_solve_strategy(3**x-10, x) #== GS_TRANSCENDENTAL - assert guess_solve_strategy(-3**x+10, x) #== GS_TRANSCENDENTAL + assert guess_solve_strategy( exp(x) + 1, x ) # == GS_TRANSCENDENTAL + assert guess_solve_strategy( 2*cos(x) - y, x ) # == GS_TRANSCENDENTAL + assert guess_solve_strategy( + exp(x) + exp(-x) - y, x ) # == GS_TRANSCENDENTAL + assert guess_solve_strategy(3**x - 10, x) # == GS_TRANSCENDENTAL + assert guess_solve_strategy(-3**x + 10, x) # == GS_TRANSCENDENTAL + + assert guess_solve_strategy(a*x**b - y, x) # == GS_TRANSCENDENTAL - assert guess_solve_strategy(a*x**b-y, x) #== GS_TRANSCENDENTAL def test_solve_args(): - #implicit symbol to solve for + # implicit symbol to solve for assert set(solve(x**2 - 4)) == set([S(2), -S(2)]) assert solve([x + y - 3, x - y - 5]) == {x: 4, y: -1} - #no symbol to solve for + assert solve(x - exp(x), x, implicit=True) == [exp(x)] + # no symbol to solve for assert solve(42) == [] assert solve([1, 2]) == [] - #unordered symbols - #only 1 + # duplicate symbols removed + assert solve((x - 3, y + 2), x, y, x) == {x: 3, y: -2} + # unordered symbols + # only 1 assert solve(y - 3, set([y])) == [3] - #more than 1 + # more than 1 assert solve(y - 3, set([x, y])) == [{y: 3}] - #multiple symbols: take the first linear solution + # multiple symbols: take the first linear solution assert solve(x + y - 3, [x, y]) == [{x: 3 - y}] # unless it is an undetermined coefficients system assert solve(a + b*x - 2, [a, b]) == {a: 2, b: 0} assert solve(a*x**2 + b*x + c - - ((x-h)**2 + 4*p*k)/4/p, + ((x - h)**2 + 4*p*k)/4/p, [h, p, k], exclude=[a, b, c], dict=True) == \ [{k: (4*a*c - b**2)/(4*a), h: -b/(2*a), p: 1/(4*a)}] # failing undetermined system @@ -96,16 +117,18 @@ [{a: (-b**2*x + 3*x**3 + 12*x**2 + 4*x + 16)/(x**2*(x + 4))}] # failed single equation assert solve(1/(1/x - y + exp(y))) == [] - raises(NotImplementedError, lambda: solve(exp(x) + sin(x) + exp(y) + sin(y))) + raises( + NotImplementedError, lambda: solve(exp(x) + sin(x) + exp(y) + sin(y))) # failed system # -- when no symbols given, 1 fails assert solve([y, exp(x) + x]) == [{x: -LambertW(1), y: 0}] # both fail - assert solve((exp(x) - x, exp(y) - y)) == [{x: -LambertW(-1), y: -LambertW(-1)}] + assert solve( + (exp(x) - x, exp(y) - y)) == [{x: -LambertW(-1), y: -LambertW(-1)}] # -- when symbols given solve([y, exp(x) + x], x, y) == [(-LambertW(1), 0)] - #symbol is not a symbol or function - raises(TypeError, lambda: solve(x**2-pi, pi)) + # symbol is a number + assert solve(x**2 - pi, pi) == [x**2] # no equations assert solve([], [x]) == [] # overdetermined system @@ -114,8 +137,9 @@ # - linear assert solve((x + y - 2, 2*x + 2*y - 4)) == {x: -y + 2} + def test_solve_polynomial1(): - assert solve(3*x-2, x) == [Rational(2, 3)] + assert solve(3*x - 2, x) == [Rational(2, 3)] assert solve(Eq(3*x, 2), x) == [Rational(2, 3)] assert set(solve(x**2 - 1, x)) == set([-S(1), S(1)]) @@ -123,36 +147,40 @@ assert solve(x - y**3, x) == [y**3] assert set(solve(x - y**3, y)) == set([ - (-x**Rational(1,3))/2 + I*sqrt(3)*x**Rational(1,3)/2, - x**Rational(1,3), - (-x**Rational(1,3))/2 - I*sqrt(3)*x**Rational(1,3)/2, + (-x**Rational(1, 3))/2 + I*sqrt(3)*x**Rational(1, 3)/2, + x**Rational(1, 3), + (-x**Rational(1, 3))/2 - I*sqrt(3)*x**Rational(1, 3)/2, ]) - a11,a12,a21,a22,b1,b2 = symbols('a11,a12,a21,a22,b1,b2') + a11, a12, a21, a22, b1, b2 = symbols('a11,a12,a21,a22,b1,b2') assert solve([a11*x + a12*y - b1, a21*x + a22*y - b2], x, y) == \ { - x : (a22*b1 - a12*b2)/(a11*a22 - a12*a21), - y : (a11*b2 - a21*b1)/(a11*a22 - a12*a21), + x: (a22*b1 - a12*b2)/(a11*a22 - a12*a21), + y: (a11*b2 - a21*b1)/(a11*a22 - a12*a21), } solution = {y: S.Zero, x: S.Zero} - assert solve((x - y, x+y), x, y ) == solution - assert solve((x - y, x+y), (x, y)) == solution - assert solve((x - y, x+y), [x, y]) == solution - - assert set(solve(x**3 - 15*x - 4, x)) == set([-2 + 3**Rational(1,2), - S(4), - -2 - 3**Rational(1,2) ]) + assert solve((x - y, x + y), x, y ) == solution + assert solve((x - y, x + y), (x, y)) == solution + assert solve((x - y, x + y), [x, y]) == solution + + assert set(solve(x**3 - 15*x - 4, x)) == set([ + -2 + 3**Rational(1, 2), + S(4), + -2 - 3**Rational(1, 2) + ]) assert set(solve((x**2 - 1)**2 - a, x)) == \ - set([sqrt(1 + sqrt(a)), -sqrt(1 + sqrt(a)), - sqrt(1 - sqrt(a)), -sqrt(1 - sqrt(a))]) + set([sqrt(1 + sqrt(a)), -sqrt(1 + sqrt(a)), + sqrt(1 - sqrt(a)), -sqrt(1 - sqrt(a))]) + def test_solve_polynomial2(): assert solve(4, x) == [] + def test_solve_polynomial_cv_1a(): """ Test for solving on equations that can be converted to a polynomial equation @@ -160,133 +188,178 @@ """ assert solve( sqrt(x) - 1, x) == [1] assert solve( sqrt(x) - 2, x) == [4] - assert solve( x**Rational(1,4) - 2, x) == [16] - assert solve( x**Rational(1,3) - 3, x) == [27] - assert solve(sqrt(x) + x**Rational(1,3) + x**Rational(1,4), x) == [0] + assert solve( x**Rational(1, 4) - 2, x) == [16] + assert solve( x**Rational(1, 3) - 3, x) == [27] + assert solve(sqrt(x) + x**Rational(1, 3) + x**Rational(1, 4), x) == [0] + def test_solve_polynomial_cv_1b(): assert set(solve(4*x*(1 - a*sqrt(x)), x)) == set([S(0), 1/a**2]) assert set(solve(x * (x**(S(1)/3) - 3), x)) == set([S(0), S(27)]) + def test_solve_polynomial_cv_2(): """ Test for solving on equations that can be converted to a polynomial equation multiplying both sides of the equation by x**m """ assert solve(x + 1/x - 1, x) in \ - [[ Rational(1,2) + I*sqrt(3)/2, Rational(1,2) - I*sqrt(3)/2], - [ Rational(1,2) - I*sqrt(3)/2, Rational(1,2) + I*sqrt(3)/2]] + [[ Rational(1, 2) + I*sqrt(3)/2, Rational(1, 2) - I*sqrt(3)/2], + [ Rational(1, 2) - I*sqrt(3)/2, Rational(1, 2) + I*sqrt(3)/2]] + + +def test_quintics_1(): + f = x**5 - 110*x**3 - 55*x**2 + 2310*x + 979 + s = solve(f, check=False) + for root in s: + res = f.subs(x, root.n()).n() + assert tn(res, 0) + + f = x**5 - 15*x**3 - 5*x**2 + 10*x + 20 + s = solve(f) + for root in s: + assert root.func == RootOf + + +def test_highorder_poly(): + # just testing that the uniq generator is unpacked + sol = solve(x**6 - 2*x + 2) + assert all(isinstance(i, RootOf) for i in sol) and len(sol) == 6 + + +@XFAIL +@slow +def test_quintics_2(): + f = x**5 + 15*x + 12 + s = solve(f, check=False) + for root in s: + res = f.subs(x, root.n()).n() + assert tn(res, 0) + + f = x**5 - 15*x**3 - 5*x**2 + 10*x + 20 + s = solve(f) + for root in s: + assert root.func == RootOf + def test_solve_rational(): """Test solve for rational functions""" assert solve( ( x - y**3 )/( (y**2)*sqrt(1 - y**2) ), x) == [y**3] + def test_linear_system(): x, y, z, t, n = symbols('x, y, z, t, n') - assert solve([x - 1, x - y, x - 2*y, y - 1], [x,y]) == [] + assert solve([x - 1, x - y, x - 2*y, y - 1], [x, y]) == [] - assert solve([x - 1, x - y, x - 2*y, x - 1], [x,y]) == [] - assert solve([x - 1, x - 1, x - y, x - 2*y], [x,y]) == [] + assert solve([x - 1, x - y, x - 2*y, x - 1], [x, y]) == [] + assert solve([x - 1, x - 1, x - y, x - 2*y], [x, y]) == [] assert solve([x + 5*y - 2, -3*x + 6*y - 15], x, y) == {x: -3, y: 1} - M = Matrix([[0,0,n*(n+1),(n+1)**2,0], - [n+1,n+1,-2*n-1,-(n+1),0], + M = Matrix([[0, 0, n*(n + 1), (n + 1)**2, 0], + [n + 1, n + 1, -2*n - 1, -(n + 1), 0], [-1, 0, 1, 0, 0]]) assert solve_linear_system(M, x, y, z, t) == \ - {y: 0, z: t*(-n - 1)/n, x: t*(-n - 1)/n} + {x: -t - t/n, z: -t - t/n, y: 0} assert solve([x + y + z + t, -z - t], x, y, z, t) == {x: -y, z: -t} + def test_linear_system_function(): a = Function('a') assert solve([a(0, 0) + a(0, 1) + a(1, 0) + a(1, 1), -a(1, 0) - a(1, 1)], a(0, 0), a(0, 1), a(1, 0), a(1, 1)) == {a(1, 0): -a(1, 1), a(0, 0): -a(0, 1)} + def test_linear_systemLU(): n = Symbol('n') - M = Matrix([[1,2,0,1],[1,3,2*n,1],[4,-1,n**2,1]]) + M = Matrix([[1, 2, 0, 1], [1, 3, 2*n, 1], [4, -1, n**2, 1]]) - assert solve_linear_system_LU(M, [x,y,z]) == {z: -3/(n**2+18*n), - x: 1-12*n/(n**2+18*n), - y: 6*n/(n**2+18*n)} + assert solve_linear_system_LU(M, [x, y, z]) == {z: -3/(n**2 + 18*n), + x: 1 - 12*n/(n**2 + 18*n), + y: 6*n/(n**2 + 18*n)} # Note: multiple solutions exist for some of these equations, so the tests # should be expected to break if the implementation of the solver changes # in such a way that a different branch is chosen + + def test_tsolve(): - assert solve(exp(x)-3, x) == [log(3)] - assert set(solve((a*x+b)*(exp(x)-3), x)) == set([-b/a, log(3)]) - assert solve(cos(x)-y, x) == [acos(y)] - assert solve(2*cos(x)-y,x)== [acos(y/2)] - assert set(solve(Eq(cos(x), sin(x)), x)) == set([-3*pi/4, pi/4]) + assert solve(exp(x) - 3, x) == [log(3)] + assert set(solve((a*x + b)*(exp(x) - 3), x)) == set([-b/a, log(3)]) + assert solve(cos(x) - y, x) == [-acos(y) + 2*pi, acos(y)] + assert solve(2*cos(x) - y, x) == [-acos(y/2) + 2*pi, acos(y/2)] + assert solve(Eq(cos(x), sin(x)), x) == [-3*pi/4, pi/4] assert set(solve(exp(x) + exp(-x) - y, x)) in [set([ - log(y/2 - sqrt(y**2 - 4)/2), - log(y/2 + sqrt(y**2 - 4)/2), - ]), set([ - log(y - sqrt(y**2 - 4)) - log(2), - log(y + sqrt(y**2 - 4)) - log(2)])] - assert solve(exp(x)-3, x) == [log(3)] + log(y/2 - sqrt(y**2 - 4)/2), + log(y/2 + sqrt(y**2 - 4)/2), + ]), set([ + log(y - sqrt(y**2 - 4)) - log(2), + log(y + sqrt(y**2 - 4)) - log(2)]), + set([ + log(y/2 - sqrt((y - 2)*(y + 2))/2), + log(y/2 + sqrt((y - 2)*(y + 2))/2)])] + assert solve(exp(x) - 3, x) == [log(3)] assert solve(Eq(exp(x), 3), x) == [log(3)] - assert solve(log(x)-3, x) == [exp(3)] - assert solve(sqrt(3*x)-4, x) == [Rational(16,3)] - assert solve(3**(x+2), x) == [] - assert solve(3**(2-x), x) == [] - assert solve(x+2**x, x) == [-LambertW(log(2))/log(2)] - assert solve(3*x+5+2**(-5*x+3), x) in [ - [-((25*log(2) - 3*LambertW(-10240*2**(Rational(1, 3))*log(2)/3))/(15*log(2)))], - [-Rational(5, 3) + LambertW(log(2**(-10240*2**(Rational(1, 3))/3)))/(5*log(2))], - [-Rational(5, 3) + LambertW(-10240*2**Rational(1,3)*log(2)/3)/(5*log(2))], - [(-25*log(2) + 3*LambertW(-10240*2**(Rational(1, 3))*log(2)/3))/(15*log(2))], - [-((25*log(2) - 3*LambertW(-10240*2**(Rational(1, 3))*log(2)/3)))/(15*log(2))], - [-(25*log(2) - 3*LambertW(log(2**(-10240*2**Rational(1, 3)/3))))/(15*log(2))], - [(25*log(2) - 3*LambertW(log(2**(-10240*2**Rational(1, 3)/3))))/(-15*log(2))] - ] - assert solve(5*x-1+3*exp(2-7*x), x) == \ - [Rational(1,5) + LambertW(-21*exp(Rational(3, 5))/5)/7] - assert solve(2*x+5+log(3*x-2), x) == \ - [Rational(2,3) + LambertW(2*exp(-Rational(19, 3))/3)/2] - assert solve(3*x+log(4*x), x) == [LambertW(Rational(3,4))/3] - assert set(solve((2*x+8)*(8+exp(x)), x)) == set([S(-4), log(8) + pi*I]) - eq = 2*exp(3*x+4)-3 - ans = solve(eq, x) + assert solve(log(x) - 3, x) == [exp(3)] + assert solve(sqrt(3*x) - 4, x) == [Rational(16, 3)] + assert solve(3**(x + 2), x) == [] + assert solve(3**(2 - x), x) == [] + assert solve(x + 2**x, x) == [-LambertW(log(2))/log(2)] + ans = solve(3*x + 5 + 2**(-5*x + 3), x) + assert len(ans) == 1 and ans[0].expand() == \ + -Rational(5, 3) + LambertW(-10240*2**(S(1)/3)*log(2)/3)/(5*log(2)) + assert solve(5*x - 1 + 3*exp(2 - 7*x), x) == \ + [Rational(1, 5) + LambertW(-21*exp(Rational(3, 5))/5)/7] + assert solve(2*x + 5 + log(3*x - 2), x) == \ + [Rational(2, 3) + LambertW(2*exp(-Rational(19, 3))/3)/2] + assert solve(3*x + log(4*x), x) == [LambertW(Rational(3, 4))/3] + assert set(solve((2*x + 8)*(8 + exp(x)), x)) == set([S(-4), log(8) + pi*I]) + eq = 2*exp(3*x + 4) - 3 + ans = solve(eq, x) # this generated a failure in flatten assert len(ans) == 3 and all(eq.subs(x, a).n(chop=True) == 0 for a in ans) - assert solve(2*log(3*x+4)-3, x) == [(exp(Rational(3,2))-4)/3] - assert solve(exp(x)+1, x) == [pi*I] - assert solve(x**2 - 2**x, x) == [2] - assert solve(x**3 - 3**x, x) == [-3*LambertW(-log(3)/3)/log(3)] + assert solve(2*log(3*x + 4) - 3, x) == [(exp(Rational(3, 2)) - 4)/3] + assert solve(exp(x) + 1, x) == [pi*I] - A = -7*2**Rational(4, 5)*6**Rational(1, 5)*log(7)/10 - B = -7*3**Rational(1, 5)*log(7)/5 + eq = 2*(3*x + 4)**5 - 6*7**(3*x + 9) + result = solve(eq, x) + ans = [(log(2401) + 5*LambertW(-log(7**(7*3**Rational(1, 5)/5))))/(3*log(7))/-1] + assert result == ans + # it works if expanded, too + assert solve(eq.expand(), x) == result + + assert solve(z*cos(x) - y, x) == [-acos(y/z) + 2*pi, acos(y/z)] + assert solve(z*cos(2*x) - y, x) == [-acos(y/z)/2 + pi, acos(y/z)/2] + assert solve(z*cos(sin(x)) - y, x) == [ + asin(acos(y/z) - 2*pi) + pi, -asin(acos(y/z)) + pi, + -asin(acos(y/z) - 2*pi), asin(acos(y/z))] - result = solve(2*(3*x + 4)**5 - 6*7**(3*x + 9), x) - - assert len(result) == 1 and expand(result[0]) in [ - Rational(-4, 3) - 5/log(7)/3*LambertW(A), - Rational(-4, 3) - 5/log(7)/3*LambertW(B), - ] - - assert solve(z*cos(x)-y, x) == [acos(y/z)] - assert solve(z*cos(2*x)-y, x) == [acos(y/z)/2] - assert solve(z*cos(sin(x))-y, x) == [asin(acos(y/z))] - - assert solve(z*cos(x), x) == [acos(0)] + assert solve(z*cos(x), x) == [pi/2, 3*pi/2] # issue #1409 - assert solve(y - b*x/(a+x), x) in [[-a*y/(y - b)], [a*y/(b - y)]] + assert solve(y - b*x/(a + x), x) in [[-a*y/(y - b)], [a*y/(b - y)]] assert solve(y - b*exp(a/x), x) == [a/log(y/b)] # issue #1408 - assert solve(y-b/(1+a*x), x) in [[(b - y)/(a*y)], [-((y - b)/(a*y))]] + assert solve(y - b/(1 + a*x), x) in [[(b - y)/(a*y)], [-((y - b)/(a*y))]] # issue #1407 - assert solve(y-a*x**b , x) == [(y/a)**(1/b)] + assert solve(y - a*x**b, x) == [(y/a)**(1/b)] # issue #1406 assert solve(z**x - y, x) == [log(y)/log(z)] # issue #1405 assert solve(2**x - 10, x) == [log(10)/log(2)] + # issue #3645 + assert solve(x*y) == [{x: 0}, {y: 0}] + assert solve([x*y]) == [{x: 0}, {y: 0}] + assert solve(x**y - 1) == [{x: 1}, {y: 0}] + assert solve([x**y - 1]) == [{x: 1}, {y: 0}] + assert solve(x*y*(x**2 - y**2)) == [{x: 0}, {x: -y}, {x: y}, {y: 0}] + assert solve([x*y*(x**2 - y**2)]) == [{x: 0}, {x: -y}, {x: y}, {y: 0}] + #issue #1640 + assert solve(exp(log(5)*x) - 2**x, x) == [0] def test_solve_for_functions_derivatives(): t = Symbol('t') @@ -296,23 +369,23 @@ soln = solve([a11*x + a12*y - b1, a21*x + a22*y - b2], x, y) assert soln == { - x : (a22*b1 - a12*b2)/(a11*a22 - a12*a21), - y : (a11*b2 - a21*b1)/(a11*a22 - a12*a21), - } + x: (a22*b1 - a12*b2)/(a11*a22 - a12*a21), + y: (a11*b2 - a21*b1)/(a11*a22 - a12*a21), + } assert solve(x - 1, x) == [1] assert solve(3*x - 2, x) == [Rational(2, 3)] soln = solve([a11*x.diff(t) + a12*y.diff(t) - b1, a21*x.diff(t) + a22*y.diff(t) - b2], x.diff(t), y.diff(t)) - assert soln == { y.diff(t) : (a11*b2 - a21*b1)/(a11*a22 - a12*a21), - x.diff(t) : (a22*b1 - a12*b2)/(a11*a22 - a12*a21) } + assert soln == { y.diff(t): (a11*b2 - a21*b1)/(a11*a22 - a12*a21), + x.diff(t): (a22*b1 - a12*b2)/(a11*a22 - a12*a21) } - assert solve(x.diff(t)-1, x.diff(t)) == [1] - assert solve(3*x.diff(t)-2, x.diff(t)) == [Rational(2,3)] + assert solve(x.diff(t) - 1, x.diff(t)) == [1] + assert solve(3*x.diff(t) - 2, x.diff(t)) == [Rational(2, 3)] - eqns = set((3*x - 1, 2*y-4)) - assert solve(eqns, set((x,y))) == { x : Rational(1, 3), y: 2 } + eqns = set((3*x - 1, 2*y - 4)) + assert solve(eqns, set((x, y))) == { x: Rational(1, 3), y: 2 } x = Symbol('x') f = Function('f') F = x**2 + f(x)**2 - 4*x - 1 @@ -324,8 +397,9 @@ soln = solve([a11*x + a12*y.diff(t) - b1, a21*x + a22*y.diff(t) - b2], x, y.diff(t)) - assert soln == { y.diff(t) : (a11*b2 - a21*b1)/(a11*a22 - a12*a21), - x : (a22*b1 - a12*b2)/(a11*a22 - a12*a21) } + assert soln == { y.diff(t): (a11*b2 - a21*b1)/(a11*a22 - a12*a21), + x: (a22*b1 - a12*b2)/(a11*a22 - a12*a21) } + def test_issue626(): f = Function('f') @@ -333,34 +407,59 @@ e = F.diff(x) assert solve(e, f(x).diff(x)) in [[(2 - x)/f(x)], [-((x - 2)/f(x))]] + +def test_issue771(): + a, b, c, d = symbols('a b c d') + A = Matrix(2, 2, [a, b, c, d]) + B = Matrix(2, 2, [0, 2, -3, 0]) + C = Matrix(2, 2, [1, 2, 3, 4]) + + assert solve(A*B - C, [a, b, c, d]) == {a: 1, b: -S(1)/3, c: 2, d: -1} + assert solve([A*B - C], [a, b, c, d]) == {a: 1, b: -S(1)/3, c: 2, d: -1} + assert solve(Eq(A*B, C), [a, b, c, d]) == {a: 1, b: -S(1)/3, c: 2, d: -1} + + assert solve([A*B - B*A], [a, b, c, d]) == {a: d, b: -S(2)/3*c} + assert solve([A*C - C*A], [a, b, c, d]) == {a: d - c, b: S(2)/3*c} + assert solve([A*B - B*A, A*C - C*A], [a, b, c, d]) == {a: d, b: 0, c: 0} + + assert solve([Eq(A*B, B*A)], [a, b, c, d]) == {a: d, b: -S(2)/3*c} + assert solve([Eq(A*C, C*A)], [a, b, c, d]) == {a: d - c, b: S(2)/3*c} + assert solve([Eq(A*B, B*A), Eq(A*C, C*A)], [a, b, c, d]) == {a: d, b: 0, c: 0} + + def test_solve_linear(): w = Wild('w') assert solve_linear(x, x) == (0, 1) assert solve_linear(x, y - 2*x) in [(x, y/3), (y, 3*x)] - assert solve_linear(x, y - 2*x, exclude=[x]) ==(y, 3*x) + assert solve_linear(x, y - 2*x, exclude=[x]) == (y, 3*x) assert solve_linear(3*x - y, 0) in [(x, y/3), (y, 3*x)] assert solve_linear(3*x - y, 0, [x]) == (x, y/3) assert solve_linear(3*x - y, 0, [y]) == (y, 3*x) assert solve_linear(x**2/y, 1) == (y, x**2) assert solve_linear(w, x) in [(w, x), (x, w)] assert solve_linear(cos(x)**2 + sin(x)**2 + 2 + y) == \ - (y, -2 - cos(x)**2 - sin(x)**2) + (y, -2 - cos(x)**2 - sin(x)**2) assert solve_linear(cos(x)**2 + sin(x)**2 + 2 + y, symbols=[x]) == (0, 1) assert solve_linear(Eq(x, 3)) == (x, 3) assert solve_linear(1/(1/x - 2)) == (0, 0) + assert solve_linear((x + 1)*exp(-x), symbols=[x]) == (x + 1, exp(x)) + assert solve_linear((x + 1)*exp(x), symbols=[x]) == ((x + 1)*exp(x), 1) + assert solve_linear(x*exp(-x**2), symbols=[x]) == (0, 0) raises(ValueError, lambda: solve_linear(Eq(x, 3), 3)) + def test_solve_undetermined_coeffs(): - assert solve_undetermined_coeffs(a*x**2 + b*x**2 + b*x + 2*c*x + c + 1, [a, b, c], x) == \ + assert solve_undetermined_coeffs(a*x**2 + b*x**2 + b*x + 2*c*x + c + 1, [a, b, c], x) == \ {a: -2, b: 2, c: -1} # Test that rational functions work - assert solve_undetermined_coeffs(a/x + b/(x + 1) - (2*x + 1)/(x**2 + x), [a, b], x) == \ + assert solve_undetermined_coeffs(a/x + b/(x + 1) - (2*x + 1)/(x**2 + x), [a, b], x) == \ {a: 1, b: 1} # Test cancellation in rational functions assert solve_undetermined_coeffs(((c + 1)*a*x**2 + (c + 1)*b*x**2 + - (c + 1)*b*x + (c + 1)*2*c*x + (c + 1)**2)/(c + 1), [a, b, c], x) == \ + (c + 1)*b*x + (c + 1)*2*c*x + (c + 1)**2)/(c + 1), [a, b, c], x) == \ {a: -2, b: 2, c: -1} + def test_solve_inequalities(): system = [Lt(x**2 - 2, 0), Gt(x**2 - 1, 0)] @@ -370,6 +469,10 @@ assert solve(system, assume=Q.real(x)) == \ Or(And(Lt(-sqrt(2), x), Lt(x, -1)), And(Lt(1, x), Lt(x, sqrt(2)))) + # issue 3528, 3448 + assert solve((x - 3)/(x - 2) < 0, x, assume=Q.real(x)) == And(Lt(2, x), Lt(x, 3)) + assert solve(x/(x + 1) > 1, x, assume=Q.real(x)) == Lt(x, -1) + def test_issue_1694(): assert solve(1/x) == [] assert solve(x*(1 - 5/x)) == [5] @@ -377,7 +480,7 @@ assert solve(-(1 + x)/(2 + x)**2 + 1/(2 + x)) == [] assert solve(-x**2 - 2*x + (x + 1)**2 - 1) == [] assert solve((x/(x + 1) + 3)**(-2)) == [] - assert solve(x/sqrt(x**2 + 1),x) == [0] + assert solve(x/sqrt(x**2 + 1), x) == [0] assert solve(exp(x) - y, x) == [log(y)] assert solve(exp(x)) == [] assert solve(x**2 + x + sin(y)**2 + cos(y)**2 - 1, x) in [[0, -1], [-1, 0]] @@ -388,19 +491,22 @@ ([y], set([ (-sqrt(exp(x)*log(x**2)),), (sqrt(exp(x)*log(x**2)),)])) - assert solve(x**2*z**2 - z**2*y**2) in ([{x: y}, {x: -y}], [{x: -y}, {x: y}]) + assert solve(x**2*z**2 - z**2*y**2) == [{x: -y}, {x: y}, {z: 0}] assert solve((x - 1)/(1 + 1/(x - 1))) == [] assert solve(x**(y*z) - x, x) == [1] raises(NotImplementedError, lambda: solve(log(x) - exp(x), x)) + raises(NotImplementedError, lambda: solve(2**x - exp(x) - 3)) + +def test_PR1964(): # 2072 assert solve(sqrt(x)) == solve(sqrt(x**3)) == [0] assert solve(sqrt(x - 1)) == [1] # 1363 a = Symbol('a') - assert solve(-3*a/sqrt(x),x) == [] + assert solve(-3*a/sqrt(x), x) == [] # 1387 - assert solve(2*x/(x + 2) - 1,x) == [2] + assert solve(2*x/(x + 2) - 1, x) == [2] # 1397 assert set(solve((x**2/(7 - x)).diff(x))) == set([S(0), S(14)]) # 1596 @@ -411,22 +517,28 @@ assert solve(sqrt(x) + sqrt(sqrt(x)) - 4) == [-9*sqrt(17)/2 + 49*S.Half] assert set(solve(Poly(sqrt(exp(x)) + sqrt(exp(-x)) - 4))) in \ - [ + [ set([2*log(-sqrt(3) + 2), 2*log(sqrt(3) + 2)]), set([log(-4*sqrt(3) + 7), log(4*sqrt(3) + 7)]), - ] + ] assert set(solve(Poly(exp(x) + exp(-x) - 4))) == \ set([log(-sqrt(3) + 2), log(sqrt(3) + 2)]) assert set(solve(x**y + x**(2*y) - 1, x)) == \ set([(-S.Half + sqrt(5)/2)**(1/y), (-S.Half - sqrt(5)/2)**(1/y)]) assert solve(exp(x/y)*exp(-z/y) - 2, y) == [(x - z)/log(2)] - assert solve(x**z*y**z - 2, z) in [[log(2)/(log(x) + log(y))], [log(2)/(log(x*y))]] + assert solve( + x**z*y**z - 2, z) in [[log(2)/(log(x) + log(y))], [log(2)/(log(x*y))]] # if you do inversion too soon then multiple roots as for the following will # be missed, e.g. if exp(3*x) = exp(3) -> 3*x = 3 E = S.Exp1 assert set(solve(exp(3*x) - exp(3), x)) == \ - set([S(1), log(-E/2 - sqrt(3)*E*I/2), log(-E/2 + sqrt(3)*E*I/2)]) + set([S(1), log(-E/2 - sqrt(3)*E*I/2), log(-E/2 + sqrt(3)*E*I/2)]) + + # coverage test + p = Symbol('p', positive=True) + assert solve((1/p + 1)**(p + 1)) == [] + def test_issue_2098(): x = Symbol('x', real=True) @@ -435,7 +547,8 @@ assert solve((n - 1)*(n + 2)*(2*n - 1), n) == [1] x = Symbol('x', positive=True) y = Symbol('y') - assert solve([x + 5*y - 2, -3*x + 6*y - 15], x, y) == [] # not {x: -3, y: 1} b/c x is positive + assert solve([x + 5*y - 2, -3*x + 6*y - 15], x, y) == [] + # not {x: -3, y: 1} b/c x is positive # The solution following should not contain (-sqrt(2), sqrt(2)) assert solve((x + y)*n - y**2 + 2, x, y) == [(sqrt(2), -sqrt(2))] y = Symbol('y', positive=True) @@ -445,27 +558,23 @@ x, y, z = symbols('x y z', positive=True) assert solve(z**2*x**2 - z**2*y**2/exp(x), y, x, z) == [{y: x*exp(x/2)}] -@XFAIL -def test_failing(): - # better Lambert detection is needed if the expression is expanded - # this case has a double generator: (7**x, x); this will pass if the - # x-terms are factored - assert solve((2*(3*x+4)**5 - 6*7**(3*x+9)).expand(), x) def test_checking(): - assert set(solve(x*(x - y/x),x, check=False)) == set([sqrt(y), S(0), -sqrt(y)]) - assert set(solve(x*(x - y/x),x, check=True)) == set([sqrt(y), -sqrt(y)]) + assert set( + solve(x*(x - y/x), x, check=False)) == set([sqrt(y), S(0), -sqrt(y)]) + assert set(solve(x*(x - y/x), x, check=True)) == set([sqrt(y), -sqrt(y)]) # {x: 0, y: 4} sets denominator to 0 in the following so system should return None assert solve((1/(1/x + 2), 1/(y - 3) - 1)) == [] # 0 sets denominator of 1/x to zero so None is returned assert solve(1/(1/x + 2)) == [] + def test_issue_1572_1364_1368(): assert solve((sqrt(x**2 - 1) - 2)) in ([sqrt(5), -sqrt(5)], [-sqrt(5), sqrt(5)]) assert set(solve((2**exp(y**2/x) + 2)/(x**2 + 15), y)) == set([ -sqrt(x)*sqrt(-log(log(2)) + log(log(2) + I*pi)), - sqrt(x)*sqrt(-log(log(2)) + log(log(2) + I*pi))]) + sqrt(x)*sqrt(-log(log(2)) + log(log(2) + I*pi))]) C1, C2 = symbols('C1 C2') f = Function('f') @@ -473,32 +582,32 @@ a = Symbol('a') E = S.Exp1 assert solve(1 - log(a + 4*x**2), x) in ( - [-sqrt(-a + E)/2, sqrt(-a + E)/2], - [sqrt(-a + E)/2, -sqrt(-a + E)/2] - ) + [-sqrt(-a + E)/2, sqrt(-a + E)/2], + [sqrt(-a + E)/2, -sqrt(-a + E)/2] + ) assert solve(log(a**(-3) - x**2)/a, x) in ( - [-sqrt(-1 + a**(-3)), sqrt(-1 + a**(-3))], - [sqrt(-1 + a**(-3)), -sqrt(-1 + a**(-3))],) + [-sqrt(-1 + a**(-3)), sqrt(-1 + a**(-3))], + [sqrt(-1 + a**(-3)), -sqrt(-1 + a**(-3))],) assert solve(1 - log(a + 4*x**2), x) in ( - [-sqrt(-a + E)/2, sqrt(-a + E)/2], - [sqrt(-a + E)/2, -sqrt(-a + E)/2],) - assert set(solve((a**2 + 1) * (sin(a*x) + cos(a*x)), x)) == set([-pi/(4*a), 3*pi/(4*a)]) - assert solve(3 - (sinh(a*x) + cosh(a*x)), x) == [2*atanh(S.Half)/a] - assert set(solve(3-(sinh(a*x) + cosh(a*x)**2), x)) == \ - set([ - 2*atanh(-1 + sqrt(2))/a, - 2*atanh(S(1)/2 + sqrt(5)/2)/a, - 2*atanh(-sqrt(2) - 1)/a, - 2*atanh(-sqrt(5)/2 + S(1)/2)/a - ]) + [-sqrt(-a + E)/2, sqrt(-a + E)/2], + [sqrt(-a + E)/2, -sqrt(-a + E)/2],) + assert set(solve(( + a**2 + 1) * (sin(a*x) + cos(a*x)), x)) == set([-pi/(4*a), 3*pi/(4*a)]) + assert solve(3 - (sinh(a*x) + cosh(a*x)), x) == [log(3)/a] + assert set(solve(3 - (sinh(a*x) + cosh(a*x)**2), x)) == \ + set([log(-2 + sqrt(5))/a, log(-sqrt(2) + 1)/a, + log(-sqrt(5) - 2)/a, log(1 + sqrt(2))/a]) assert solve(atan(x) - 1) == [tan(1)] + def test_issue_2033(): r, t = symbols('r,t') assert set(solve([r - x**2 - y**2, tan(t) - y/x], [x, y])) == \ - set([ - (-sqrt(r*sin(t)**2)/tan(t), -sqrt(r*sin(t)**2)), - (sqrt(r*sin(t)**2)/tan(t), sqrt(r*sin(t)**2))]) + set([ + (-sqrt(r*tan(t)**2/(tan(t)**2 + 1))/tan(t), + -sqrt(r*tan(t)**2/(tan(t)**2 + 1))), + (sqrt(r*tan(t)**2/(tan(t)**2 + 1))/tan(t), + sqrt(r*tan(t)**2/(tan(t)**2 + 1)))]) assert solve([exp(x) - sin(y), 1/y - 3], [x, y]) == \ [(log(sin(S(1)/3)), S(1)/3)] assert solve([exp(x) - sin(y), 1/exp(y) - 3], [x, y]) == \ @@ -516,25 +625,25 @@ (log(sqrt(-z**2 + sin(y))),)])) assert set(solve(eqs, x, y)) == \ set([ - (log(-sqrt(-z**2 - sin(log(3)))), -log(3)), + (log(-sqrt(-z**2 - sin(log(3)))), -log(3)), (log(sqrt(-z**2 - sin(log(3)))), -log(3))]) assert set(solve(eqs, y, z)) == \ set([ - (-log(3), -sqrt(-exp(2*x) - sin(log(3)))), + (-log(3), -sqrt(-exp(2*x) - sin(log(3)))), (-log(3), sqrt(-exp(2*x) - sin(log(3))))]) eqs = [exp(x)**2 - sin(y) + z, 1/exp(y) - 3] assert solve(eqs, set=True) == ([x, y], set( [ (log(-sqrt(-z - sin(log(3)))), -log(3)), - (log(sqrt(-z - sin(log(3)))), -log(3))])) + (log(sqrt(-z - sin(log(3)))), -log(3))])) assert solve(eqs, x, z, set=True) == ([x], set( [ (log(-sqrt(-z + sin(y))),), - (log(sqrt(-z + sin(y))),)])) + (log(sqrt(-z + sin(y))),)])) assert set(solve(eqs, x, y)) == set( [ - (log(-sqrt(-z - sin(log(3)))), -log(3)), - (log(sqrt(-z - sin(log(3)))), -log(3))]) + (log(-sqrt(-z - sin(log(3)))), -log(3)), + (log(sqrt(-z - sin(log(3)))), -log(3))]) assert solve(eqs, z, y) == \ [(-exp(2*x) - sin(log(3)), -log(3))] assert solve((sqrt(x**2 + y**2) - sqrt(10), x + y - 4), set=True) == ( @@ -542,6 +651,7 @@ assert set(solve((sqrt(x**2 + y**2) - sqrt(10), x + y - 4), x, y)) == \ set([(S(1), S(3)), (S(3), S(1))]) + def test_issue_2236(): lam, a0, conc = symbols('lam a0 conc') eqs = [lam + 2*y - a0*(1 - x/2)*x - 0.005*x/2*x, @@ -551,6 +661,7 @@ # there are 4 solutions but only two are valid assert len(solve(eqs, sym, manual=True, minimal=True, simplify=False)) == 2 + def test_issue_2236_float(): skip("This test hangs.") lam, a0, conc = symbols('lam a0 conc') @@ -558,19 +669,24 @@ a0*(1 - x/2)*x - 1*y - 0.743436700916726*y, x + y - conc] sym = [x, y, a0] - assert len(solve(eqs, sym, rational=False, check=False, simplify=False)) == 2 + assert len( + solve(eqs, sym, rational=False, check=False, simplify=False)) == 2 + def test_issue_2668(): assert set(solve([x**2 + y + 4], [x])) == \ set([(-sqrt(-y - 4),), (sqrt(-y - 4),)]) + def test_polysys(): - assert set(solve([x**2 + 2/y - 2 , x + y - 3], [x, y])) == \ + assert set(solve([x**2 + 2/y - 2, x + y - 3], [x, y])) == \ set([(S(1), S(2)), (1 + sqrt(5), 2 - sqrt(5)), (1 - sqrt(5), 2 + sqrt(5))]) assert solve([x**2 + y - 2, x**2 + y]) == [] # the ordering should be whatever the user requested - assert solve([x**2 + y - 3, x - y - 4], (x, y)) != solve([x**2 + y - 3, x - y - 4], (y, x)) + assert solve([x**2 + y - 3, x - y - 4], (x, y)) != solve([x**2 + + y - 3, x - y - 4], (y, x)) + def test_unrad(): s = symbols('s', cls=Dummy) @@ -582,6 +698,7 @@ rv[0] = rv[0].expand() ans[0] = ans[0].expand() return rv[0] in [ans[0], -ans[0]] and rv[1:] == ans[1:] + def s_check(rv, ans): # get the dummy rv = list(rv) @@ -590,23 +707,23 @@ # replace s with this dummy rv = (rv[0].subs(reps).expand(), [(p[0].subs(reps), p[1].subs(reps)) for p in rv[1]], - [a.subs(reps) for a in rv[2]]) + [a.subs(reps) for a in rv[2]]) ans = (ans[0].subs(reps).expand(), [(p[0].subs(reps), p[1].subs(reps)) for p in ans[1]], - [a.subs(reps) for a in ans[2]]) + [a.subs(reps) for a in ans[2]]) return str(rv[0]) in [str(ans[0]), str(-ans[0])] and \ - str(rv[1:]) == str(ans[1:]) + str(rv[1:]) == str(ans[1:]) assert check(unrad(sqrt(x)), - (x, [], [])) + (x, [], [])) assert check(unrad(sqrt(x) + 1), - (x - 1, [], [])) - assert s_check(unrad(sqrt(x) + x**Rational(1,3) + 2), + (x - 1, [], [])) + assert s_check(unrad(sqrt(x) + x**Rational(1, 3) + 2), (2 + s**2 + s**3, [(s, x - s**6)], [])) assert check(unrad(sqrt(x)*x**Rational(1, 3) + 2), - (x**5 - 64, [], [])) - assert check(unrad(sqrt(x) + (x + 1)**Rational(1,3)), - (x**3 - (x + 1)**2, [], [])) + (x**5 - 64, [], [])) + assert check(unrad(sqrt(x) + (x + 1)**Rational(1, 3)), + (x**3 - (x + 1)**2, [], [])) assert check(unrad(sqrt(x) + sqrt(x + 1) + sqrt(2*x)), (-2*sqrt(2)*x - 2*x + 1, [], [])) assert check(unrad(sqrt(x) + sqrt(x + 1) + 2), @@ -618,7 +735,7 @@ assert check(unrad(sqrt(x) + sqrt(1 - x)), (2*x - 1, [], [])) assert check(unrad(sqrt(x) + sqrt(1 - x) - 3), - (36*x + (2*x - 10)**2 - 36, [], [])) + (9*x + (x - 5)**2 - 9, [], [])) assert check(unrad(sqrt(x) + sqrt(1 - x) + sqrt(2 + x)), (-5*x**2 + 2*x - 1, [], [])) assert check(unrad(sqrt(x) + sqrt(1 - x) + sqrt(2 + x) - 3), @@ -636,7 +753,8 @@ assert set(solve(sqrt(x) - sqrt(x + 1) + sqrt(1 - sqrt(x)))) == \ set([S.Zero, S(9)/16]) - '''real_root changes the value of the result if the solution is + '''NOTE + real_root changes the value of the result if the solution is simplified; `a` in the text below is the root that is not 4/5: >>> eq sqrt(x) + sqrt(-x + 1) + sqrt(x + 1) - 6*sqrt(5)/5 @@ -658,7 +776,7 @@ >>> sqrt(x).subs(x, real_root(simplify(a))).n() 0.49864610868139 + 1.44572604257047*I ''' - eq=(sqrt(x) + sqrt(x + 1) + sqrt(1 - x) - 6*sqrt(5)/5) + eq = (sqrt(x) + sqrt(x + 1) + sqrt(1 - x) - 6*sqrt(5)/5) ra = S('''-1484/375 - 4*(-1/2 + sqrt(3)*I/2)*(-12459439/52734375 + 114*sqrt(12657)/78125)**(1/3) - 172564/(140625*(-1/2 + sqrt(3)*I/2)*(-12459439/52734375 + 114*sqrt(12657)/78125)**(1/3))''') @@ -669,24 +787,16 @@ set([i.n(chop=True) for i in ans]) == \ set([i.n(chop=True) for i in (ra, rb)]) - ans = solve(sqrt(x) + sqrt(x + 1) - \ - sqrt(1 - x) - sqrt(2 + x)) - assert len(ans) == 1 and NS(ans[0])[:4] == '0.73' - # the fence optimization problem - # http://code.google.com/p/sympy/issues/detail?id=1694#c159 - F = Symbol('F') - eq = F - (2*x + 2*y + sqrt(x**2 + y**2)) - X = solve(eq, x, hint='minimal')[0] - Y = solve((x*y).subs(x, X).diff(y), y, simplify=False, minimal=True) - ans = 2*F/7 - sqrt(2)*F/14 - assert any((a - ans).expand().is_zero for a in Y) - - raises(ValueError, lambda: unrad(sqrt(x) + sqrt(x+1) + sqrt(1-sqrt(x)) + 3)) - raises(ValueError, lambda: unrad(sqrt(x) + (x+1)**Rational(1,3) + 2*sqrt(y))) + raises(ValueError, lambda: + unrad(-root(x,3)**2 + 2**pi*root(x,3) - x + 2**pi)) + raises(ValueError, lambda: + unrad(sqrt(x) + sqrt(x + 1) + sqrt(1 - sqrt(x)) + 3)) + raises(ValueError, lambda: + unrad(sqrt(x) + (x + 1)**Rational(1, 3) + 2*sqrt(y))) # same as last but consider only y - assert check(unrad(sqrt(x) + (x + 1)**Rational(1,3) + 2*sqrt(y), y), + assert check(unrad(sqrt(x) + (x + 1)**Rational(1, 3) + 2*sqrt(y), y), (4*y - (sqrt(x) + (x + 1)**(S(1)/3))**2, [], [])) - assert check(unrad(sqrt(x/(1 - x)) + (x + 1)**Rational(1,3)), + assert check(unrad(sqrt(x/(1 - x)) + (x + 1)**Rational(1, 3)), (x**3/(-x + 1)**3 - (x + 1)**2, [], [(-x + 1)**3])) # same as last but consider only y; no y-containing denominators now assert s_check(unrad(sqrt(x/(1 - x)) + 2*sqrt(y), y), @@ -720,7 +830,7 @@ assert solve(sqrt(17*x - sqrt(x**2 - 5)) - 7) == [3] assert solve(sqrt(x) - sqrt(x - 1) + sqrt(sqrt(x))) == [] - # don't posify the expession in unrad and use _mexpand + # don't posify the expression in unrad and use _mexpand z = sqrt(2*x + 1)/sqrt(x) - sqrt(2 + 1/x) p = posify(z)[0] assert solve(p) == [] @@ -728,16 +838,39 @@ assert solve(z + 6*I) == [-S(1)/11] assert solve(p + 6*I) == [] -@XFAIL -def test_multivariate(): - assert solve((x**2 - 2*x + 1).subs(x, log(x) + 3*x)) == [LambertW(3*S.Exp1)/3] - assert solve((x**2 - 2*x + 1).subs(x, (log(x) + 3*x)**2 - 1)) == \ - [LambertW(3*exp(-sqrt(2)))/3, LambertW(3*exp(sqrt(2)))/3] - assert solve((x**2 - 2*x - 2).subs(x, log(x) + 3*x)) == \ - [LambertW(3*exp(1 - sqrt(3)))/3, LambertW(3*exp(1 + sqrt(3)))/3] - assert solve(x*log(x) + 3*x + 1, x) == [exp(-3 + LambertW(-exp(3)))] - # symmetry - assert solve(3*sin(x) - x*sin(3), x) == [3] + eq = sqrt(2 + I) + 2*I + assert unrad(eq - x, x, all=True) == (x**4 + 4*x**2 + 8*x + 37, [], []) + ans = (81*x**8 - 2268*x**6 - 4536*x**5 + 22644*x**4 + 63216*x**3 - + 31608*x**2 - 189648*x + 141358, [], []) + r = sqrt(sqrt(2)/3 + 7) + eq = sqrt(r) + r - x + assert unrad(eq, all=1) + r2 = sqrt(sqrt(2) + 21)/sqrt(3) + assert r != r2 and r.equals(r2) + assert unrad(eq - r + r2, all=True) == ans + + +@slow +def test_unrad_slow(): + ans = solve(sqrt(x) + sqrt(x + 1) - + sqrt(1 - x) - sqrt(2 + x)) + assert len(ans) == 1 and NS(ans[0])[:4] == '0.73' + # the fence optimization problem + # http://code.google.com/p/sympy/issues/detail?id=1694#c159 + F = Symbol('F') + eq = F - (2*x + 2*y + sqrt(x**2 + y**2)) + X = solve(eq, x, hint='minimal')[0] + Y = solve((x*y).subs(x, X).diff(y), y, simplify=False, minimal=True) + ans = 2*F/7 - sqrt(2)*F/14 + assert any((a - ans).expand().is_zero for a in Y) + + eq = S(''' + -x + (1/2 - sqrt(3)*I/2)*(3*x**3/2 - x*(3*x**2 - 34)/2 + sqrt((-3*x**3 + + x*(3*x**2 - 34) + 90)**2/4 - 39304/27) - 45)**(1/3) + 34/(3*(1/2 - + sqrt(3)*I/2)*(3*x**3/2 - x*(3*x**2 - 34)/2 + sqrt((-3*x**3 + x*(3*x**2 + - 34) + 90)**2/4 - 39304/27) - 45)**(1/3))''') + raises(NotImplementedError, lambda: solve(eq)) # not other code errors + def test__invert(): assert _invert(x - 2) == (2, x) @@ -746,13 +879,16 @@ assert _invert(exp(1/x + a/x) - 3, x) == ((a + 1)/log(3), x) assert _invert(a, x) == (a, 0) + def test_issue_1364(): assert solve(-a*x + 2*x*log(x), x) == [exp(a/2)] assert solve(a/x + exp(x/2), x) == [2*LambertW(-a/2)] assert solve(x**x) == [] assert solve(x**x - 2) == [exp(LambertW(log(2)))] assert solve(((x - 3)*(x - 2))**((x - 3)*(x - 4))) == [2] - assert solve((a/x + exp(x/2)).diff(x), x) == [4*LambertW(sqrt(2)*sqrt(a)/4)] + assert solve( + (a/x + exp(x/2)).diff(x), x) == [4*LambertW(sqrt(2)*sqrt(a)/4)] + def test_issue_2015(): a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r = symbols('a:r') @@ -762,34 +898,36 @@ syms = a, b, c, f, h, k, n eqs = [b + r/d - c/d, c*(1/d + 1/e + 1/g) - f/g - r/d, - f*(1/g + 1/i + 1/j) - c/g - h/i, - h*(1/i + 1/l + 1/m) - f/i - k/m, - k*(1/m + 1/o + 1/p) - h/m - n/p, - n*(1/p + 1/q) - k/p] + f*(1/g + 1/i + 1/j) - c/g - h/i, + h*(1/i + 1/l + 1/m) - f/i - k/m, + k*(1/m + 1/o + 1/p) - h/m - n/p, + n*(1/p + 1/q) - k/p] assert len(solve(eqs, syms, manual=True, check=False, simplify=False)) == 1 + def test_misc(): # make sure that the right variables is picked up in tsolve raises(NotImplementedError, lambda: solve((exp(x) + 1)**x)) + def test_issue_2750(): I1, I2, I3, I4, I5, I6 = symbols('I1:7') dI1, dI4, dQ2, dQ4, Q2, Q4 = symbols('dI1,dI4,dQ2,dQ4,Q2,Q4') e = ( - I1 - I2 - I3, - I3 - I4 - I5, - I4 + I5 - I6, - -I1 + I2 + I6, - -2*I1 - 2*I3 - 2*I5 - 3*I6 - dI1/2 + 12, - -I4 + dQ4, - -I2 + dQ2, - 2*I3 + 2*I5 + 3*I6 - Q2, - I4 - 2*I5 + 2*Q4 + dI4 + I1 - I2 - I3, + I3 - I4 - I5, + I4 + I5 - I6, + -I1 + I2 + I6, + -2*I1 - 2*I3 - 2*I5 - 3*I6 - dI1/2 + 12, + -I4 + dQ4, + -I2 + dQ2, + 2*I3 + 2*I5 + 3*I6 - Q2, + I4 - 2*I5 + 2*Q4 + dI4 ) ans = [{ - dQ4: I3 - I5, + dQ4: I3 - I5, dI1: -4*I2 - 8*I3 - 4*I5 - 6*I6 + 24, I4: I3 - I5, dQ2: I2, @@ -799,7 +937,9 @@ assert solve(e, I1, I4, Q2, Q4, dI1, dI4, dQ2, dQ4, manual=True) == ans # the matrix solver (tested below) doesn't like this because it produces # a zero row in the matrix. Is this related to issue 1452? - assert [ei.subs(ans[0]) for ei in e] == [0, 0, I3 - I6, -I3 + I6, 0, 0, 0, 0, 0] + assert [ei.subs( + ans[0]) for ei in e] == [0, 0, I3 - I6, -I3 + I6, 0, 0, 0, 0, 0] + def test_2750_matrix(): '''Same as test_2750 but solved with the matrix solver.''' @@ -807,24 +947,25 @@ dI1, dI4, dQ2, dQ4, Q2, Q4 = symbols('dI1,dI4,dQ2,dQ4,Q2,Q4') e = ( - I1 - I2 - I3, - I3 - I4 - I5, - I4 + I5 - I6, - -I1 + I2 + I6, - -2*I1 - 2*I3 - 2*I5 - 3*I6 - dI1/2 + 12, - -I4 + dQ4, - -I2 + dQ2, - 2*I3 + 2*I5 + 3*I6 - Q2, - I4 - 2*I5 + 2*Q4 + dI4 + I1 - I2 - I3, + I3 - I4 - I5, + I4 + I5 - I6, + -I1 + I2 + I6, + -2*I1 - 2*I3 - 2*I5 - 3*I6 - dI1/2 + 12, + -I4 + dQ4, + -I2 + dQ2, + 2*I3 + 2*I5 + 3*I6 - Q2, + I4 - 2*I5 + 2*Q4 + dI4 ) assert solve(e, I1, I4, Q2, Q4, dI1, dI4, dQ2, dQ4) == { - dI4: -I3 + 3*I5 - 2*Q4, - dI1: -4*I2 - 8*I3 - 4*I5 - 6*I6 + 24, - dQ2: I2, - I1: I2 + I3, - Q2: 2*I3 + 2*I5 + 3*I6, - dQ4: I3 - I5, - I4: I3 - I5} + dI4: -I3 + 3*I5 - 2*Q4, + dI1: -4*I2 - 8*I3 - 4*I5 - 6*I6 + 24, + dQ2: I2, + I1: I2 + I3, + Q2: 2*I3 + 2*I5 + 3*I6, + dQ4: I3 - I5, + I4: I3 - I5} + def test_issue_2802(): f, g, h = list(map(Function, 'fgh')) @@ -842,7 +983,7 @@ assert solve([f(x) - 3*f(x).diff(x), f(x)**2 - y + 4], f(x), y) == \ [{f(x): 3*D, y: 9*D**2 + 4}] assert solve(-f(a)**2*g(a)**2 + f(a)**2*h(a)**2 + g(a).diff(a), - h(a), g(a), set=True) == \ + h(a), g(a), set=True) == \ ([g(a)], set([ (-sqrt(h(a)**2 + G/f(a)**2),), (sqrt(h(a)**2 + G/f(a)**2),)])) @@ -861,7 +1002,8 @@ # anything but a Mul or Add; it now raises an error if it gets anything # but a symbol and solve handles the substitutions necessary so solve_linear # won't make this error - raises(ValueError, lambda: solve_linear(f(x) + f(x).diff(x), symbols=[f(x)])) + raises( + ValueError, lambda: solve_linear(f(x) + f(x).diff(x), symbols=[f(x)])) assert solve_linear(f(x) + f(x).diff(x), symbols=[x]) == \ (f(x) + Derivative(f(x), x), 1) assert solve_linear(f(x) + Integral(x, (x, y)), symbols=[x]) == \ @@ -891,6 +1033,7 @@ assert solve(x**2 + x - 3, x**2, implicit=True) == \ [-x + 3] + def test_issue_2813(): assert set(solve(x**2 - x - 0.1, rational=True)) == \ set([S(1)/2 + sqrt(35)/10, -sqrt(35)/10 + S(1)/2]) @@ -900,6 +1043,7 @@ ans = solve(x**2 - x - 0.1) assert len(ans) == 2 and all(a.is_Number for a in ans) + def test_float_handling(): def test(e1, e2): return len(e1.atoms(Float)) == len(e2.atoms(Float)) @@ -925,51 +1069,285 @@ tot = 100 + c + z + t assert solve(((.7 + c)/tot - .6, (.2 + z)/tot - .3, t/tot - .1)) == [] + def test_check_assumptions(): - x = symbols('x', positive=1) + x = symbols('x', positive=True) assert solve(x**2 - 1) == [1] + def test_solve_abs(): assert set(solve(abs(x - 7) - 8)) == set([-S(1), S(15)]) + def test_issue_2957(): assert solve(tanh(x + 3)*tanh(x - 3) - 1) == [] - assert set(solve(tanh(x - 1)*tanh(x + 1) + 1)) == set([ + assert set([simplify(w) for w in solve(tanh(x - 1)*tanh(x + 1) + 1)]) == set([ + -log(2)/2 + log(1 - I), -log(2)/2 + log(-1 - I), - -log(2)/2 + log(-1 + I), + -log(2)/2 + log(1 + I), + -log(2)/2 + log(-1 + I),]) + assert set([simplify(w) for w in solve((tanh(x + 3)*tanh(x - 3) + 1)**2)]) == set([ -log(2)/2 + log(1 - I), - -log(2)/2 + log(1 + I)]) - assert set(solve((tanh(x + 3)*tanh(x - 3) + 1)**2)) == \ - set([-log(2)/2 + log(-1 - I), -log(2)/2 + log(-1 + I), - -log(2)/2 + log(1 - I), -log(2)/2 + log(1 + I)]) + -log(2)/2 + log(-1 - I), + -log(2)/2 + log(1 + I), + -log(2)/2 + log(-1 + I),]) + + +def test_issue_2961(): + x = Symbol('x') + absxm3 = Piecewise( + (x - 3, S(0) <= x - 3), + (3 - x, S(0) > x - 3) + ) + y = Symbol('y') + assert solve(absxm3 - y, x) == [ + Piecewise((-y + 3, S(0) > -y), (S.NaN, True)), + Piecewise((y + 3, S(0) <= y), (S.NaN, True)) + ] + y = Symbol('y', positive=True) + assert solve(absxm3 - y, x) == [-y + 3, y + 3] + def test_issue_2574(): eq = -x + exp(exp(LambertW(log(x)))*LambertW(log(x))) - assert checksol(eq, x, 2) == True + assert checksol(eq, x, 2) is True assert checksol(eq, x, 2, numerical=False) is None + def test_exclude(): R, C, Ri, Vout, V1, Vminus, Vplus, s = \ symbols('R, C, Ri, Vout, V1, Vminus, Vplus, s') - Rf = symbols('Rf', positive=True) # to eliminate Rf = 0 soln + Rf = symbols('Rf', positive=True) # to eliminate Rf = 0 soln eqs = [C*V1*s + Vplus*(-2*C*s - 1/R), Vminus*(-1/Ri - 1/Rf) + Vout/Rf, C*Vplus*s + V1*(-C*s - 1/R) + Vout/R, -Vminus + Vplus] assert solve(eqs, exclude=s*C*R) == [ { - Rf: Ri*(C*R*s + 1)**2/(C*R*s), - Vminus: Vplus, - V1: Vplus*(2*C*R*s + 1)/(C*R*s), - Vout: Vplus*(C**2*R**2*s**2 + 3*C*R*s + 1)/(C*R*s)}] + Rf: Ri*(C*R*s + 1)**2/(C*R*s), + Vminus: Vplus, + V1: Vplus*(2*C*R*s + 1)/(C*R*s), + Vout: Vplus*(C**2*R**2*s**2 + 3*C*R*s + 1)/(C*R*s)}, + { + Vplus: 0, + Vminus: 0, + V1: 0, + Vout: 0}, + ] assert solve(eqs, exclude=[Vplus, s, C]) == [ { - Rf: Ri*(V1 - Vplus)**2/(Vplus*(V1 - 2*Vplus)), - Vminus: Vplus, - Vout: (V1**2 - V1*Vplus - Vplus**2)/(V1 - 2*Vplus), - R: Vplus/(C*s*(V1 - 2*Vplus))}] + Rf: Ri*(V1 - Vplus)**2/(Vplus*(V1 - 2*Vplus)), + Vminus: Vplus, + Vout: (V1**2 - V1*Vplus - Vplus**2)/(V1 - 2*Vplus), + R: Vplus/(C*s*(V1 - 2*Vplus))}] def test_high_order_roots(): s = x**5 + 4*x**3 + 3*x**2 + S(7)/4 assert set(solve(s)) == set(Poly(s*4, domain='ZZ').all_roots()) + + +def test_minsolve_linear_system(): + def count(dic): + return len([x for x in dic.values() if x == 0]) + assert count(solve([x + y + z, y + z + a + t], minimal=True, quick=True)) \ + == 3 + assert count(solve([x + y + z, y + z + a + t], minimal=True, quick=False)) \ + == 3 + assert count(solve([x + y + z, y + z + a], minimal=True, quick=True)) == 1 + assert count(solve([x + y + z, y + z + a], minimal=True, quick=False)) == 2 + + +def test_real_roots(): + # cf. issue 3551 + x = Symbol('x', real=True) + assert len(solve(x**5 + x**3 + 1)) == 1 + + +@slow +def test_issue3429(): + eqs = [ + 327600995*x**2 - 37869137*x + 1809975124*y**2 - 9998905626, + 895613949*x**2 - 273830224*x*y + 530506983*y**2 - 10000000000] + assert len(solve(eqs, y, x)) == len(solve(eqs, y, x, manual=True)) == 4 + + +def test_overdetermined(): + eqs = [Abs(4*x - 7) - 5, Abs(3 - 8*x) - 1] + assert solve(eqs, x) == [(S.Half,)] + assert solve(eqs, x, manual=True) == [(S.Half,)] + assert solve(eqs, x, manual=True, check=False) == [(S.Half/2,), (S.Half,)] + + +def test_issue_3506(): + x = symbols('x') + assert solve(4**(x/2) - 2**(x/3)) == [0] + # while the first one passed, this one failed + x = symbols('x', real=True) + assert solve(5**(x/2) - 2**(x/3)) == [0] + b = sqrt(6)*sqrt(log(2))/sqrt(log(5)) + assert solve(5**(x/2) - 2**(3/x)) == [-b, b] + + +def test__ispow(): + assert _ispow(x**2) + assert not _ispow(x) + assert not _ispow(True) + + +def test_issue_3545(): + eq = -sqrt((m - q)**2 + (-m/(2*q) + S(1)/2)**2) + sqrt((-m**2/2 - sqrt( + 4*m**4 - 4*m**2 + 8*m + 1)/4 - S(1)/4)**2 + (m**2/2 - m - sqrt( + 4*m**4 - 4*m**2 + 8*m + 1)/4 - S(1)/4)**2) + assert solve(eq, q) == [ + m**2/2 - sqrt(4*m**4 - 4*m**2 + 8*m + 1)/4 - S(1)/4, + m**2/2 + sqrt(4*m**4 - 4*m**2 + 8*m + 1)/4 - S(1)/4] + + +def test_issue_3653(): + assert solve([a**2 + a, a - b], [a, b]) == [(-1, -1), (0, 0)] + assert solve([a**2 + a*c, a - b], [a, b]) == [(0, 0), (-c, -c)] + + +def test_issue_3693(): + assert solve(x*(x - 1)**2*(x + 1)*(x**6 - x + 1)) == [ + -1, 0, 1, RootOf(x**6 - x + 1, 0), RootOf(x**6 - x + 1, 1), + RootOf(x**6 - x + 1, 2), RootOf(x**6 - x + 1, 3), RootOf(x**6 - x + 1, 4), + RootOf(x**6 - x + 1, 5)] + + +def test_issues_3720_3721_3722_3149(): + # 3722 + x, y = symbols('x y') + assert solve(abs(x + 3) - 2*abs(x - 3)) == [1, 9] + assert solve([abs(x) - 2, arg(x) - pi], x) == [ + {re(x): -2, x: -2, im(x): 0}, {re(x): 2, x: 2, im(x): 0}] + assert solve([re(x) - 1, im(x) - 2], x) == [ + {re(x): 1, x: 1 + 2*I, im(x): 2}] + + w = symbols('w', integer=True) + assert solve(2*x**w - 4*y**w, w) == solve((x/y)**w - 2, w) + x, y = symbols('x y', real=True) + assert solve(x + y*I + 3) == {y: 0, x: -3} + x, y = symbols('x y', imaginary=True) + assert solve(x + y*I + 3 + 2*I) == {x: -2*I, y: 3*I} + x = symbols('x', real=True) + assert solve(x + y + 3 + 2*I) == {x: -3, y: -2*I} + # issue 3149 + f = Function('f') + assert solve(f(x + 1) - f(2*x - 1)) == [2] + assert solve(log(x + 1) - log(2*x - 1)) == [2] + x = symbols('x') + assert solve(2**x + 4**x) == [I*pi/log(2)] + + +def test_issue_3890(): + f = Function('f') + assert solve(Eq(-f(x), Piecewise((1, x > 0), (0, True))), f(x)) == \ + [Piecewise((-1, x > 0), (0, True))] + + +def test_lambert_multivariate(): + from sympy.abc import a, x, y + from sympy.solvers.bivariate import _filtered_gens, _lambert, _solve_lambert + + assert _filtered_gens(Poly(x + 1/x + exp(x) + y), x) == set([x, exp(x)]) + assert _lambert(x, x) == [] + assert solve((x**2 - 2*x + 1).subs(x, log(x) + 3*x)) == [LambertW(3*S.Exp1)/3] + assert solve((x**2 - 2*x + 1).subs(x, (log(x) + 3*x)**2 - 1)) == \ + [LambertW(3*exp(-sqrt(2)))/3, LambertW(3*exp(sqrt(2)))/3] + assert solve((x**2 - 2*x - 2).subs(x, log(x) + 3*x)) == \ + [LambertW(3*exp(1 + sqrt(3)))/3, LambertW(3*exp(-sqrt(3) + 1))/3] + assert solve(x*log(x) + 3*x + 1, x) == [exp(-3 + LambertW(-exp(3)))] + eq = (x*exp(x) - 3).subs(x, x*exp(x)) + assert solve(eq) == [LambertW(3*exp(-LambertW(3)))] + # coverage test + raises(NotImplementedError, lambda: solve(x - sin(x)*log(y - x), x)) + + # if sign is unknown then only this one solution is obtained + assert solve(3*log(a**(3*x + 5)) + a**(3*x + 5), x) == [ + -((log(a**5) + LambertW(S(1)/3))/(3*log(a)))] # tested numerically + p = symbols('p', positive=True) + assert solve(3*log(p**(3*x + 5)) + p**(3*x + 5), x) == [ + log((-3**(S(1)/3) - 3**(S(5)/6)*I)*LambertW(S(1)/3)**(S(1)/3)/(2*p**(S(5)/3)))/log(p), + log((-3**(S(1)/3) + 3**(S(5)/6)*I)*LambertW(S(1)/3)**(S(1)/3)/(2*p**(S(5)/3)))/log(p), + log((3*LambertW(S(1)/3)/p**5)**(1/(3*log(p)))),] # checked numerically + # check collection + assert solve(3*log(a**(3*x + 5)) + b*log(a**(3*x + 5)) + a**(3*x + 5), x) == [ + -((log(a**5) + LambertW(1/(b + 3)))/(3*log(a)))] + + eq = 4*2**(2*p + 3) - 2*p - 3 + assert _solve_lambert(eq, p, _filtered_gens(Poly(eq), p)) == [ + -S(3)/2 - LambertW(-4*log(2))/(2*log(2))] + + # issue 1172 + assert solve((a/x + exp(x/2)).diff(x, 2), x) == [ + 6*LambertW((-1)**(S(1)/3)*a**(S(1)/3)/3)] + + assert solve((log(x) + x).subs(x, x**2 + 1)) == [ + -I*sqrt(-LambertW(1) + 1), sqrt(-1 + LambertW(1))] + + # these only give one of the solutions (see XFAIL below) + assert solve(x**3 - 3**x, x) == [-3/log(3)*LambertW(-log(3)/3)] + # replacing 3 with 2 in the above solution gives 2 + assert solve(x**2 - 2**x, x) == [2] + assert solve(-x**2 + 2**x, x) == [2] + assert solve(3**cos(x) - cos(x)**3) == [ + acos(-3*LambertW(-log(3)/3)/log(3))] + + +@XFAIL +def test_other_lambert(): + from sympy.abc import x + assert solve(3*sin(x) - x*sin(3), x) == [3] + assert set(solve(3*log(x) - x*log(3))) == set( + [3, -3*LambertW(-log(3)/3)/log(3)]) + a = S(6)/5 + assert set(solve(x**a - a**x)) == set( + [a, -a*LambertW(-log(a)/a)/log(a)]) + assert set(solve(3**cos(x) - cos(x)**3)) == set( + [acos(3), acos(-3*LambertW(-log(3)/3)/log(3))]) + assert set(solve(x**2 - 2**x)) == set( + [2, -2/log(2)*LambertW(log(2)/2)]) + + +def test_rewrite_trig(): + assert solve(sin(x) + tan(x)) == [0, 2*pi] + assert solve(sin(x) + sec(x)) == [ + -2*atan(-S.Half + sqrt(2 - 2*sqrt(3)*I)/2 + sqrt(3)*I/2), + 2*atan(S.Half - sqrt(3)*I/2 + sqrt(2 - 2*sqrt(3)*I)/2), + 2*atan(S.Half - sqrt(2 + 2*sqrt(3)*I)/2 + sqrt(3)*I/2), + 2*atan(S.Half + sqrt(2 + 2*sqrt(3)*I)/2 + sqrt(3)*I/2)] + assert solve(sinh(x) + tanh(x)) == [0, I*pi] + + +@XFAIL +def test_rewrite_trigh(): + # if this import passes then the test below should also pass + from sympy import sech + assert solve(sinh(x) + sech(x)) == [ + 2*atanh(-S.Half + sqrt(5)/2 - sqrt(-2*sqrt(5) + 2)/2), + 2*atanh(-S.Half + sqrt(5)/2 + sqrt(-2*sqrt(5) + 2)/2), + 2*atanh(-sqrt(5)/2 - S.Half + sqrt(2 + 2*sqrt(5))/2), + 2*atanh(-sqrt(2 + 2*sqrt(5))/2 - sqrt(5)/2 - S.Half)] + + +def test_uselogcombine(): + eq = z - log(x) + log(y/(x*(-1 + y**2/x**2))) + assert solve(eq, x, force=True) == [-sqrt(y*(y - exp(z))), sqrt(y*(y - exp(z)))] + assert solve(log(x + 3) + log(1 + 3/x) - 3) == [ + -3 + sqrt(-12 + exp(3))*exp(S(3)/2)/2 + exp(3)/2, + -sqrt(-12 + exp(3))*exp(S(3)/2)/2 - 3 + exp(3)/2] + + +def test_atan2(): + assert solve(atan2(x, 2) - pi/3, x) == [2*sqrt(3)] + + +def test_misc(): + # shouldn't generate a GeneratorsNeeded error in _tsolve when the NaN is generated + # for eq_down. Actual answers, as determined numerically are approx. +/- 0.83 + assert solve(sinh(x)*sinh(sinh(x)) + cosh(x)*cosh(sinh(x)) - 3) is not None + + # watch out for recursive loop in tsolve + raises(NotImplementedError, lambda: solve((x+2)**y*x-3,x)) diff -Nru python3-sympy-0.7.2/sympy/statistics/distributions.py python3-sympy-0.7.3/sympy/statistics/distributions.py --- python3-sympy-0.7.2/sympy/statistics/distributions.py 2012-10-17 03:02:22.000000000 +0000 +++ python3-sympy-0.7.3/sympy/statistics/distributions.py 2013-07-13 17:53:32.000000000 +0000 @@ -33,12 +33,12 @@ def __new__(cls, sample): s = tuple.__new__(cls, sorted(sample)) s.mean = mean = sum(s) / Integer(len(s)) - s.variance = sum([(x-mean)**2 for x in s]) / Integer(len(s)) + s.variance = sum([(x - mean)**2 for x in s]) / Integer(len(s)) s.stddev = sqrt(s.variance) if len(s) % 2: s.median = s[len(s)//2] else: - s.median = sum(s[len(s)//2-1:len(s)//2+1]) / Integer(2) + s.median = sum(s[len(s)//2 - 1:len(s)//2 + 1]) / Integer(2) return s def __repr__(self): @@ -151,7 +151,7 @@ """ x = sympify(x) - return 1/(s.sigma*sqrt(2*pi)) * exp(-(x-s.mu)**2 / (2*s.sigma**2)) + return 1/(s.sigma*sqrt(2*pi)) * exp(-(x - s.mu)**2 / (2*s.sigma**2)) def cdf(s, x): """ @@ -169,7 +169,7 @@ """ x = sympify(x) - return (1+erf((x-s.mu)/(s.sigma*sqrt(2))))/2 + return (1 + erf((x - s.mu)/(s.sigma*sqrt(2))))/2 def _random(s): return random.gauss(float(s.mu), float(s.sigma)) @@ -213,7 +213,7 @@ y = erfinv(mpf(p)) t = Float(str(mpf(float(s.sigma)) * mpf(2)**0.5 * y)) mu = s.mu.evalf() - return (mu-t, mu+t) + return (mu - t, mu + t) @staticmethod def fit(sample): @@ -247,10 +247,10 @@ self.a = sympify(a) self.b = sympify(b) - mean = property(lambda s: (s.a+s.b)/2) - median = property(lambda s: (s.a+s.b)/2) - mode = property(lambda s: (s.a+s.b)/2) # arbitrary - variance = property(lambda s: (s.b-s.a)**2 / 12) + mean = property(lambda s: (s.a + s.b)/2) + median = property(lambda s: (s.a + s.b)/2) + mode = property(lambda s: (s.a + s.b)/2) # arbitrary + variance = property(lambda s: (s.b - s.a)**2 / 12) stddev = property(lambda s: sqrt(s.variance)) def pdf(s, x): @@ -269,11 +269,11 @@ """ x = sympify(x) if not x.is_Number: - raise NotImplementedError("SymPy does not yet support" + raise NotImplementedError("SymPy does not yet support " "piecewise functions") if x < s.a or x > s.b: return Rational(0) - return 1/(s.b-s.a) + return 1/(s.b - s.a) def cdf(s, x): """ @@ -291,13 +291,13 @@ """ x = sympify(x) if not x.is_Number: - raise NotImplementedError("SymPy does not yet support" + raise NotImplementedError("SymPy does not yet support " "piecewise functions") if x <= s.a: return Rational(0) if x >= s.b: return Rational(1) - return (x-s.a)/(s.b-s.a) + return (x - s.a)/(s.b - s.a) def _random(s): return Float(random.uniform(float(s.a), float(s.b))) @@ -317,7 +317,7 @@ p = sympify(p) assert p <= 1 - d = (s.b-s.a)*p / 2 + d = (s.b - s.a)*p / 2 return (s.mean - d, s.mean + d) @staticmethod @@ -340,7 +340,8 @@ sample = Sample(sample) m = sample.mean d = sqrt(12*sample.variance)/2 - return Uniform(m-d, m+d) + return Uniform(m - d, m + d) + class PDF(ContinuousProbability): """ @@ -383,7 +384,6 @@ self._variance = None self._stddev = None - def normalize(self): """ Normalize the probability distribution function so that @@ -417,7 +417,6 @@ else: return self - def cdf(self, x): """ Return the cumulative density function as an expression in x @@ -441,7 +440,8 @@ from sympy import integrate w = Dummy('w', real=True) self._cdf = integrate(self.pdf(w), w) - self._cdf = Lambda(w, self._cdf - self._cdf.subs(w, self.domain[0])) + self._cdf = Lambda( + w, self._cdf - self._cdf.subs(w, self.domain[0])) return self._cdf(x) def _get_mean(self): @@ -450,7 +450,8 @@ else: from sympy import integrate w = Dummy('w', real=True) - self._mean = integrate(self.pdf(w)*w,(w,self.domain[0],self.domain[1])) + self._mean = integrate( + self.pdf(w)*w, (w, self.domain[0], self.domain[1])) return self._mean def _get_variance(self): @@ -459,7 +460,8 @@ else: from sympy import integrate, simplify w = Dummy('w', real=True) - self._variance = integrate(self.pdf(w)*w**2,(w,self.domain[0],self.domain[1])) - self.mean**2 + self._variance = integrate(self.pdf( + w)*w**2, (w, self.domain[0], self.domain[1])) - self.mean**2 self._variance = simplify(self._variance) return self._variance @@ -474,11 +476,10 @@ variance = property(_get_variance) stddev = property(_get_stddev) - def _random(s): raise NotImplementedError - def transform(self,func,var): + def transform(self, func, var): """ Return a probability distribution of random variable func(x) currently only some simple injective functions are supported @@ -506,6 +507,6 @@ # this assignment holds only for x in domain # in general it would require implementing # piecewise defined functions in sympy - newPdf += (self.pdf(var)/abs(funcdiff)).subs(var,x) + newPdf += (self.pdf(var)/abs(funcdiff)).subs(var, x) return PDF(newPdf, (w, func.subs(var, self.domain[0]), func.subs(var, self.domain[1]))) diff -Nru python3-sympy-0.7.2/sympy/statistics/tests/test_statistics.py python3-sympy-0.7.3/sympy/statistics/tests/test_statistics.py --- python3-sympy-0.7.2/sympy/statistics/tests/test_statistics.py 2012-10-17 03:02:22.000000000 +0000 +++ python3-sympy-0.7.3/sympy/statistics/tests/test_statistics.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,10 +1,12 @@ -from sympy import sqrt, Rational, oo, Symbol, exp, pi +from sympy import sqrt, Rational, oo, Symbol, exp, pi, symbols from sympy.functions import erf from operator import abs from sympy.mpmath import mp +from sympy.utilities.tests.test_pickling import check + # Disable sympy.statistics deprecation warning for the tests # The warning is in __init__.py, so we only need to disable it for imports @@ -12,11 +14,13 @@ from sympy.utilities.exceptions import SymPyDeprecationWarning warnings.filterwarnings("ignore", category=SymPyDeprecationWarning) -from sympy.statistics.distributions import Normal, Uniform -from sympy.statistics.distributions import PDF +from sympy.statistics.distributions import (Normal, Uniform, Sample, PDF, + ContinuousProbability) warnings.filterwarnings("default") +x, y, z = symbols('x y z') + def test_normal(): dps, mp.dps = mp.dps, 20 @@ -31,15 +35,16 @@ assert N.variance == 16 assert N.confidence(1) == (-oo, oo) assert N.probability(1, 3) == erf(1/sqrt(32)) - assert N.pdf(1).evalf() == (exp(Rational(-1,32)) / (4*sqrt(2*pi))).evalf() + assert N.pdf(1).evalf() == (exp(Rational(-1, 32)) / (4*sqrt(2*pi))).evalf() for p in [0.1, 0.3, 0.7, 0.9, 0.995]: a, b = N.confidence(p) assert abs(float(N.probability(a, b).evalf()) - p) < 1e-10 N = Normal(0, 2/sqrt(2*pi)) - assert N.pdf(0) == Rational(1,2) + assert N.pdf(0) == Rational(1, 2) mp.dps = dps + def test_uniform(): U = Uniform(-3, -1) assert str(U) == "Uniform(-3, -1)" @@ -48,14 +53,15 @@ assert x < -1 and x > -3 assert U.mean == -2 assert U.confidence(1) == (-3, -1) - assert U.confidence(Rational(1,2)) == (Rational(-5,2), Rational(-3,2)) + assert U.confidence(Rational(1, 2)) == (Rational(-5, 2), Rational(-3, 2)) assert U.pdf(-4) == 0 - assert U.pdf(-Rational(3,2)) == Rational(1,2) + assert U.pdf(-Rational(3, 2)) == Rational(1, 2) assert U.pdf(0) == 0 assert U.cdf(-4) == 0 - assert U.cdf(-Rational(3,2)) == Rational(3,4) + assert U.cdf(-Rational(3, 2)) == Rational(3, 4) assert U.cdf(0) == 1 + def test_fit(): import random random.seed(1234) @@ -64,30 +70,32 @@ #print n.stddev assert abs(n.mean - 2) < 0.3 assert abs(n.stddev - 1.5) < 0.3 - n = Normal.fit([1,2,3,4,5]) + n = Normal.fit([1, 2, 3, 4, 5]) assert n.mean == 3 assert n.stddev == sqrt(2) - n = Uniform.fit([1,2,3,4,5]) + n = Uniform.fit([1, 2, 3, 4, 5]) assert n.mean == 3 assert n.stddev == sqrt(2) + def test_sample(): from sympy.statistics.distributions import Sample - s = Sample([0,1]) + s = Sample([0, 1]) assert str(s) == "Sample([0, 1])" assert repr(s) == "Sample([0, 1])" - assert s.mean == Rational(1,2) - assert s.median == Rational(1,2) - s = Sample([4,2,3]) + assert s.mean == Rational(1, 2) + assert s.median == Rational(1, 2) + s = Sample([4, 2, 3]) assert s == Sample([2, 3, 4]) assert s.median == 3 - s = Sample([4,2,3,1]) - assert s.median == Rational(5,2) + s = Sample([4, 2, 3, 1]) + assert s.median == Rational(5, 2) + def test_PDF(): a = Symbol('a', positive=True) x = Symbol('x', real=True) - exponential = PDF(exp(-x/a), (x,0,oo)) + exponential = PDF(exp(-x/a), (x, 0, oo)) exponential = exponential.normalize() assert exponential.pdf(x) == 1/a*exp(-x/a) assert exponential.cdf(x) == 1 - exp(-x/a) @@ -98,7 +106,7 @@ assert exponential.pdf(x) == exp(-x/a) assert exponential.cdf(x) == -a*exp(-x/a) + oo assert exponential.mean == -oo - exponential = PDF(1, (x,1,2)) + exponential = PDF(1, (x, 1, 2)) assert exponential.normalize() == exponential assert exponential._get_stddev() == sqrt(3)/6 assert exponential._get_stddev() == sqrt(3)/6 @@ -106,3 +114,26 @@ exponential = exponential.transform(x, x) assert exponential.pdf(x) == 1 assert exponential.cdf(x) == x - 1 + +# These last two tests are here instead of test_str.py and test_pickling.py +# because this module is deprecated. + +def test_printing(): + assert str(Normal(x + y, z)) == "Normal(x + y, z)" + assert str(Sample([x, y, 1])) in [ + "Sample([x, y, 1])", + "Sample([y, 1, x])", + "Sample([1, x, y])", + "Sample([y, x, 1])", + "Sample([x, 1, y])", + "Sample([1, y, x])", + ] + assert str(Uniform(x, y)) == "Uniform(x, y)" + assert str(Uniform(x + y, y)) == "Uniform(x + y, y)" + +def test_pickling(): + x = Symbol("x") + y = Symbol("y") + for c in (ContinuousProbability, ContinuousProbability(), Normal, + Normal(x, y), Sample, Sample([1, 3, 4]), Uniform, Uniform(x, y)): + check(c) diff -Nru python3-sympy-0.7.2/sympy/stats/__init__.py python3-sympy-0.7.3/sympy/stats/__init__.py --- python3-sympy-0.7.2/sympy/stats/__init__.py 2012-10-17 03:02:22.000000000 +0000 +++ python3-sympy-0.7.3/sympy/stats/__init__.py 2013-07-13 17:53:32.000000000 +0000 @@ -8,16 +8,16 @@ Queries on random expressions can be made using the functions -===================== ============================= - Expression Meaning ---------------------- ----------------------------- - P(condition) Probability - E(expression) Expectation value - variance(expression) Variance - density(expression) Probability Density Function - sample(expression) Produce a realization - where(condition) Where the condition is true -===================== ============================= +========================= ============================= + Expression Meaning +------------------------- ----------------------------- + ``P(condition)`` Probability + ``E(expression)`` Expected value + ``variance(expression)`` Variance + ``density(expression)`` Probability Density Function + ``sample(expression)`` Produce a realization + ``where(condition)`` Where the condition is true +========================= ============================= Examples ======== @@ -39,13 +39,31 @@ __all__ = [] from . import rv_interface -from .rv_interface import * +from .rv_interface import ( + cdf, covariance, density, dependent, E, given, independent, P, pspace, + random_symbols, sample, sample_iter, skewness, std, variance, where, + correlation, moment, cmoment, smoment, +) __all__.extend(rv_interface.__all__) from . import frv_types -from .frv_types import * +from .frv_types import ( + Bernoulli, Binomial, Coin, Die, DiscreteUniform, FiniteRV, Hypergeometric, +) __all__.extend(frv_types.__all__) from . import crv_types -from .crv_types import * +from .crv_types import ( + ContinuousRV, + Arcsin, Benini, Beta, BetaPrime, Cauchy, Chi, ChiNoncentral, ChiSquared, + Dagum, Erlang, Exponential, FDistribution, FisherZ, Frechet, Gamma, + GammaInverse, Kumaraswamy, Laplace, Logistic, LogNormal, Maxwell, + Nakagami, Normal, Pareto, QuadraticU, RaisedCosine, Rayleigh, + StudentT, Triangular, Uniform, UniformSum, VonMises, Weibull, + WignerSemicircle +) __all__.extend(crv_types.__all__) + +from . import drv_types +from .drv_types import (Geometric, Poisson) +__all__.extend(drv_types.__all__) diff -Nru python3-sympy-0.7.2/sympy/stats/crv.py python3-sympy-0.7.3/sympy/stats/crv.py --- python3-sympy-0.7.2/sympy/stats/crv.py 2012-10-17 03:02:22.000000000 +0000 +++ python3-sympy-0.7.3/sympy/stats/crv.py 2013-07-13 17:53:32.000000000 +0000 @@ -9,14 +9,17 @@ """ from sympy.stats.rv import (RandomDomain, SingleDomain, ConditionalDomain, - ProductDomain, PSpace, SinglePSpace, random_symbols, ProductPSpace) + ProductDomain, PSpace, SinglePSpace, random_symbols, ProductPSpace, + NamedArgsMixin) from sympy.functions.special.delta_functions import DiracDelta from sympy import (S, Interval, symbols, sympify, Dummy, FiniteSet, Mul, Tuple, - Integral, And, Or, Piecewise, solve, cacheit, integrate, oo, Lambda) -from sympy.solvers.inequalities import reduce_poly_inequalities + Integral, And, Or, Piecewise, solve, cacheit, integrate, oo, Lambda, + Basic) +from sympy.solvers.inequalities import reduce_rational_inequalities from sympy.polys.polyerrors import PolynomialError import random + class ContinuousDomain(RandomDomain): """ A domain with continuous support @@ -28,17 +31,13 @@ def as_boolean(self): raise NotImplementedError("Not Implemented for generic Domains") + class SingleContinuousDomain(ContinuousDomain, SingleDomain): """ A univariate domain with continuous support Represented using a single symbol and interval. """ - def __new__(cls, symbol, set): - assert symbol.is_Symbol - symbols = FiniteSet(symbol) - return RandomDomain.__new__(cls, symbols, set) - def integrate(self, expr, variables=None, **kwargs): if variables is None: variables = self.symbols @@ -73,6 +72,7 @@ def as_boolean(self): return And(*[domain.as_boolean() for domain in self.domains]) + class ConditionalContinuousDomain(ContinuousDomain, ConditionalDomain): """ A domain with continuous support that has been further restricted by a @@ -100,19 +100,20 @@ elif cond.is_Relational: if cond.is_Equality: # Add the appropriate Delta to the integrand - integrand *= DiracDelta(cond.lhs-cond.rhs) + integrand *= DiracDelta(cond.lhs - cond.rhs) else: symbols = cond.free_symbols & set(self.symbols) - if len(symbols)!=1: # Can't handle x > y + if len(symbols) != 1: # Can't handle x > y raise NotImplementedError( "Multivariate Inequalities not yet implemented") # Can handle x > 0 symbol = symbols.pop() # Find the limit with x, such as (x, -oo, oo) for i, limit in enumerate(limits): - if limit[0]==symbol: + if limit[0] == symbol: # Make condition into an Interval like [0, oo] - cintvl = reduce_poly_inequalities_wrap(cond, symbol) + cintvl = reduce_rational_inequalities_wrap( + cond, symbol) # Make limit into an Interval like [-oo, oo] lintvl = Interval(limit[1], limit[2]) # Intersect them to get [0, oo] @@ -121,7 +122,7 @@ limits[i] = (symbol, intvl.left, intvl.right) else: raise TypeError( - "Condition %s is not a relational or Boolean"%cond) + "Condition %s is not a relational or Boolean" % cond) evaluate = kwargs.pop('evaluate', True) if evaluate: @@ -134,43 +135,142 @@ @property def set(self): if len(self.symbols) == 1: - return (self.fulldomain.set & reduce_poly_inequalities_wrap( + return (self.fulldomain.set & reduce_rational_inequalities_wrap( self.condition, tuple(self.symbols)[0])) else: raise NotImplementedError( - "Set of Conditional Domain not Implemented") + "Set of Conditional Domain not Implemented") -class ContinuousPSpace(PSpace): + +class ContinuousDistribution(Basic): + def __call__(self, *args): + return self.pdf(*args) + + +class SingleContinuousDistribution(ContinuousDistribution, NamedArgsMixin): + """ Continuous distribution of a single variable + + Serves as superclass for Normal/Exponential/UniformDistribution etc.... + + Represented by parameters for each of the specific classes. E.g + NormalDistribution is represented by a mean and standard deviation. + + Provides methods for pdf, cdf, and sampling + + See Also: + sympy.stats.crv_types.* """ - A Continuous Probability Space + + set = Interval(-oo, oo) + + def __new__(cls, *args): + args = list(map(sympify, args)) + return Basic.__new__(cls, *args) + + @staticmethod + def check(*args): + pass + + def sample(self): + """ A random realization from the distribution """ + icdf = self._inverse_cdf_expression() + return icdf(random.uniform(0, 1)) + + @cacheit + def _inverse_cdf_expression(self): + """ Inverse of the CDF + + Used by sample + """ + x, z = symbols('x, z', real=True, positive=True, cls=Dummy) + # Invert CDF + try: + inverse_cdf = solve(self.cdf(x) - z, x) + except NotImplementedError: + inverse_cdf = None + if not inverse_cdf or len(inverse_cdf) != 1: + raise NotImplementedError("Could not invert CDF") + + return Lambda(z, inverse_cdf[0]) + + @cacheit + def compute_cdf(self, **kwargs): + """ Compute the CDF from the PDF + + Returns a Lambda + """ + x, z = symbols('x, z', real=True, bounded=True, cls=Dummy) + left_bound = self.set.start + + # CDF is integral of PDF from left bound to z + pdf = self.pdf(x) + cdf = integrate(pdf, (x, left_bound, z), **kwargs) + # CDF Ensure that CDF left of left_bound is zero + cdf = Piecewise((cdf, z >= left_bound), (0, True)) + return Lambda(z, cdf) + + def cdf(self, x, **kwargs): + """ Cumulative density function """ + return self.compute_cdf(**kwargs)(x) + + def expectation(self, expr, var, **kwargs): + """ Expectation of expression over distribution """ + return integrate(expr * self.pdf(var), (var, self.set), **kwargs) + +class ContinuousDistributionHandmade(SingleContinuousDistribution): + _argnames = ('pdf',) + + @property + def set(self): + return self.args[1] + + def __new__(cls, pdf, set=Interval(-oo, oo)): + return Basic.__new__(cls, pdf, set) + + +class ContinuousPSpace(PSpace): + """ Continuous Probability Space Represents the likelihood of an event space defined over a continuum. - Represented with a set of symbols and a probability density function. + Represented with a ContinuousDomain and a PDF (Lambda-Like) """ is_Continuous = True + @property + def domain(self): + return self.args[0] + + @property + def density(self): + return self.args[1] + + @property + def pdf(self): + return self.density(*self.domain.symbols) + def integrate(self, expr, rvs=None, **kwargs): if rvs is None: rvs = self.values else: rvs = frozenset(rvs) - expr = expr.subs(dict((rv, rv.symbol) for rv in rvs)) + expr = expr.xreplace(dict((rv, rv.symbol) for rv in rvs)) domain_symbols = frozenset(rv.symbol for rv in rvs) - return self.domain.integrate(self.density * expr, + return self.domain.integrate(self.pdf * expr, domain_symbols, **kwargs) def compute_density(self, expr, **kwargs): # Common case Density(X) where X in self.values if expr in self.values: # Marginalize all other random symbols out of the density - density = self.domain.integrate(self.density, set(rs.symbol - for rs in self.values - frozenset((expr,))), **kwargs) - return Lambda(expr.symbol, density) + randomsymbols = tuple(set(self.values) - frozenset([expr])) + symbols = tuple(rs.symbol for rs in randomsymbols) + pdf = self.domain.integrate(self.pdf, symbols, **kwargs) + return Lambda(expr.symbol, pdf) z = Dummy('z', real=True, bounded=True) return Lambda(z, self.integrate(DiracDelta(expr - z), **kwargs)) @@ -178,7 +278,8 @@ @cacheit def compute_cdf(self, expr, **kwargs): if not self.domain.set.is_Interval: - raise ValueError("CDF not well defined on multivariate expressions") + raise ValueError( + "CDF not well defined on multivariate expressions") d = self.compute_density(expr, **kwargs) x, z = symbols('x, z', real=True, bounded=True, cls=Dummy) @@ -208,68 +309,54 @@ # Other cases can be turned into univariate case # by computing a density handled by density computation except NotImplementedError: + from sympy.stats.rv import density expr = condition.lhs - condition.rhs - density = self.compute_density(expr, **kwargs) + dens = density(expr, **kwargs) + if not isinstance(dens, ContinuousDistribution): + dens = ContinuousDistributionHandmade(dens) # Turn problem into univariate case - space = SingleContinuousPSpace(z, density(z)) + space = SingleContinuousPSpace(z, dens) return space.probability(condition.__class__(space.value, 0)) - def where(self, condition): rvs = frozenset(random_symbols(condition)) - if not (len(rvs)==1 and rvs.issubset(self.values)): + if not (len(rvs) == 1 and rvs.issubset(self.values)): raise NotImplementedError( - "Multiple continuous random variables not supported") + "Multiple continuous random variables not supported") rv = tuple(rvs)[0] - interval = reduce_poly_inequalities_wrap(condition, rv) + interval = reduce_rational_inequalities_wrap(condition, rv) interval = interval.intersect(self.domain.set) return SingleContinuousDomain(rv.symbol, interval) def conditional_space(self, condition, normalize=True, **kwargs): - condition = condition.subs(dict((rv,rv.symbol) for rv in self.values)) + condition = condition.xreplace(dict((rv, rv.symbol) for rv in self.values)) domain = ConditionalContinuousDomain(self.domain, condition) - density = self.density if normalize: - density = density / domain.integrate(density, **kwargs) + pdf = self.pdf / domain.integrate(self.pdf, **kwargs) + density = Lambda(domain.symbols, pdf) return ContinuousPSpace(domain, density) + class SingleContinuousPSpace(ContinuousPSpace, SinglePSpace): """ - A continuous probability space over a single univariate domain + A continuous probability space over a single univariate variable - This class is commonly implemented by the various ContinuousRV types - such as Normal, Exponential, Uniform, etc.... - """ - def __new__(cls, symbol, density, set=Interval(-oo, oo)): - domain = SingleContinuousDomain(sympify(symbol), set) - obj = ContinuousPSpace.__new__(cls, domain, density) - obj._cdf = None - return obj + These consist of a Symbol and a SingleContinuousDistribution - @cacheit - def _inverse_cdf_expression(self): - """ - Inverse of the CDF + This class is normally accessed through the various random variable + functions, Normal, Exponential, Uniform, etc.... + """ - See Also - ======== - compute_cdf - sample - """ - d = self.compute_cdf(self.value) - x, z = symbols('x, z', real=True, positive=True, cls=Dummy) - # Invert CDF - try: - inverse_cdf = solve(d(x)-z, x) - except NotImplementedError: - inverse_cdf = None - if not inverse_cdf or len(inverse_cdf) != 1: - raise NotImplementedError("Could not invert CDF") + @property + def set(self): + return self.distribution.set - return Lambda(z, inverse_cdf[0]) + @property + def domain(self): + return SingleContinuousDomain(sympify(self.symbol), self.set) def sample(self): """ @@ -277,24 +364,48 @@ Returns dictionary mapping RandomSymbol to realization value. """ - icdf = self._inverse_cdf_expression() - return {self.value: icdf(random.uniform(0,1))} + return {self.value: self.distribution.sample()} + + def integrate(self, expr, rvs=None, **kwargs): + rvs = rvs or (self.value,) + if self.value not in rvs: + return expr + + expr = expr.xreplace(dict((rv, rv.symbol) for rv in rvs)) + + x = self.value.symbol + try: + return self.distribution.expectation(expr, x, **kwargs) + except: + evaluate = kwargs.pop('evaluate', True) + if evaluate: + return integrate(expr * self.pdf, (x, self.set), **kwargs) + else: + return Integral(expr * self.pdf, (x, self.set), **kwargs) + + def compute_cdf(self, expr, **kwargs): + if expr == self.value: + return self.distribution.compute_cdf(**kwargs) + else: + return ContinuousPSpace.compute_cdf(self, expr, **kwargs) class ProductContinuousPSpace(ProductPSpace, ContinuousPSpace): """ A collection of independent continuous probability spaces """ @property - def density(self): - return Mul(*[space.density for space in self.spaces]) + def pdf(self): + p = Mul(*[space.pdf for space in self.spaces]) + return p.subs(dict((rv, rv.symbol) for rv in self.values)) def _reduce_inequalities(conditions, var, **kwargs): try: - return reduce_poly_inequalities(conditions, var, **kwargs) + return reduce_rational_inequalities(conditions, var, **kwargs) except PolynomialError: - raise ValueError("Reduction of condition failed %s\n"%conditions[0]) + raise ValueError("Reduction of condition failed %s\n" % conditions[0]) + -def reduce_poly_inequalities_wrap(condition, var): +def reduce_rational_inequalities_wrap(condition, var): if condition.is_Relational: return _reduce_inequalities([[condition]], var, relational=False) if condition.__class__ is Or: diff -Nru python3-sympy-0.7.2/sympy/stats/crv_types.py python3-sympy-0.7.3/sympy/stats/crv_types.py --- python3-sympy-0.7.2/sympy/stats/crv_types.py 2012-10-17 03:02:22.000000000 +0000 +++ python3-sympy-0.7.3/sympy/stats/crv_types.py 2013-07-13 17:53:32.000000000 +0000 @@ -9,9 +9,17 @@ BetaPrime Cauchy Chi +ChiNoncentral +ChiSquared Dagum +Erlang Exponential +FDistribution +FisherZ +Frechet Gamma +GammaInverse +Kumaraswamy Laplace Logistic LogNormal @@ -19,20 +27,26 @@ Nakagami Normal Pareto +QuadraticU +RaisedCosine Rayleigh StudentT Triangular Uniform UniformSum +VonMises Weibull WignerSemicircle """ from sympy import (exp, log, sqrt, pi, S, Dummy, Interval, S, sympify, gamma, Piecewise, And, Eq, binomial, factorial, Sum, floor, Abs, - Symbol, log) + Symbol, log, besseli, Lambda, Basic) from sympy import beta as beta_fn -from .crv import SingleContinuousPSpace +from sympy import cos, exp, besseli +from sympy.stats.crv import (SingleContinuousPSpace, SingleContinuousDistribution, + ContinuousDistributionHandmade) +from sympy.stats.rv import _value_check from sympy.core.decorators import _sympifyit import random @@ -45,9 +59,17 @@ 'BetaPrime', 'Cauchy', 'Chi', +'ChiNoncentral', +'ChiSquared', 'Dagum', +'Erlang', 'Exponential', +'FDistribution', +'FisherZ', +'Frechet', 'Gamma', +'GammaInverse', +'Kumaraswamy', 'Laplace', 'Logistic', 'LogNormal', @@ -55,26 +77,21 @@ 'Nakagami', 'Normal', 'Pareto', +'QuadraticU', +'RaisedCosine', 'Rayleigh', 'StudentT', 'Triangular', 'Uniform', 'UniformSum', +'VonMises', 'Weibull', 'WignerSemicircle' ] -def _value_check(condition, message): - """ - Check a condition on input value. - - Raises ValueError with message if condition is not True - """ - if condition is not True: - raise ValueError(message) -def ContinuousRV(symbol, density, set=Interval(-oo,oo)): +def ContinuousRV(symbol, density, set=Interval(-oo, oo)): """ Create a Continuous Random Variable given the following: @@ -103,7 +120,15 @@ >>> P(X>0) 1/2 """ - return SingleContinuousPSpace(symbol, density, set).value + pdf = Lambda(symbol, density) + dist = ContinuousDistributionHandmade(pdf, set) + return SingleContinuousPSpace(symbol, dist).value + +def rv(symbol, cls, args): + args = list(map(sympify, args)) + dist = cls(*args) + dist.check(*args) + return SingleContinuousPSpace(symbol, dist).value ######################################## # Continuous Probability Distributions # @@ -112,13 +137,12 @@ #------------------------------------------------------------------------------- # Arcsin distribution ---------------------------------------------------------- -class ArcsinPSpace(SingleContinuousPSpace): - def __new__(cls, name, a, b): - a, b = sympify(a), sympify(b) - x = Symbol(name) - pdf = 1/(pi*sqrt((x-a)*(b-x))) - obj = SingleContinuousPSpace.__new__(cls, x, pdf, set=Interval(a, b)) - return obj + +class ArcsinDistribution(SingleContinuousDistribution): + _argnames = ('a', 'b') + + def pdf(self, x): + return 1/(pi*sqrt((x - self.a)*(self.b - x))) def Arcsin(name, a=0, b=1): r""" @@ -150,32 +174,37 @@ >>> a = Symbol("a", real=True) >>> b = Symbol("b", real=True) + >>> z = Symbol("z") >>> X = Arcsin("x", a, b) - >>> density(X) - Lambda(_x, 1/(pi*sqrt((-_x + b)*(_x - a)))) + >>> density(X)(z) + 1/(pi*sqrt((-a + z)*(b - z))) References ========== - [1] http://en.wikipedia.org/wiki/Arcsine_distribution + .. [1] http://en.wikipedia.org/wiki/Arcsine_distribution """ - return ArcsinPSpace(name, a, b).value + return rv(name, ArcsinDistribution, (a, b)) #------------------------------------------------------------------------------- # Benini distribution ---------------------------------------------------------- -class BeniniPSpace(SingleContinuousPSpace): - def __new__(cls, name, alpha, beta, sigma): - alpha, beta, sigma = sympify(alpha), sympify(beta), sympify(sigma) - x = Symbol(name) - pdf = (exp(-alpha*log(x/sigma)-beta*log(x/sigma)**2) - *(alpha/x+2*beta*log(x/sigma)/x)) - obj = SingleContinuousPSpace.__new__(cls, x, pdf, - set = Interval(sigma, oo)) - return obj + +class BeniniDistribution(SingleContinuousDistribution): + _argnames = ('alpha', 'beta', 'sigma') + + @property + def set(self): + return Interval(self.sigma, oo) + + def pdf(self, x): + alpha, beta, sigma = self.alpha, self.beta, self.sigma + return (exp(-alpha*log(x/sigma) - beta*log(x/sigma)**2) + *(alpha/x + 2*beta*log(x/sigma)/x)) + def Benini(name, alpha, beta, sigma): r""" @@ -185,15 +214,18 @@ .. math:: f(x) := e^{-\alpha\log{\frac{x}{\sigma}} - -\beta\log\left[{\frac{x}{\sigma}}\right]^2} + -\beta\log^2\left[{\frac{x}{\sigma}}\right]} \left(\frac{\alpha}{x}+\frac{2\beta\log{\frac{x}{\sigma}}}{x}\right) + This is a heavy-tailed distrubtion and is also known as the log-Rayleigh + distribution. + Parameters ========== - alpha : Real number, `alpha` > 0 a shape - beta : Real number, `beta` > 0 a shape - sigma : Real number, `sigma` > 0 a scale + alpha : Real number, `\alpha > 0`, a shape + beta : Real number, `\beta > 0`, a shape + sigma : Real number, `\sigma > 0`, a scale Returns ======= @@ -209,46 +241,48 @@ >>> alpha = Symbol("alpha", positive=True) >>> beta = Symbol("beta", positive=True) >>> sigma = Symbol("sigma", positive=True) + >>> z = Symbol("z") >>> X = Benini("x", alpha, beta, sigma) - >>> D = density(X) + >>> D = density(X)(z) >>> pprint(D, use_unicode=False) - / 2 \ - | / / x \\ / x \ / x \| - | | 2*beta*log|-----|| - alpha*log|-----| - beta*log |-----|| - | |alpha \sigma/| \sigma/ \sigma/| - Lambda|x, |----- + -----------------|*e | - \ \ x x / / + / / z \\ / z \ 2/ z \ + | 2*beta*log|-----|| - alpha*log|-----| - beta*log |-----| + |alpha \sigma/| \sigma/ \sigma/ + |----- + -----------------|*e + \ z z / References ========== - [1] http://en.wikipedia.org/wiki/Benini_distribution + .. [1] http://en.wikipedia.org/wiki/Benini_distribution + .. [2] http://reference.wolfram.com/legacy/v8/ref/BeniniDistribution.html """ - return BeniniPSpace(name, alpha, beta, sigma).value + return rv(name, BeniniDistribution, (alpha, beta, sigma)) #------------------------------------------------------------------------------- # Beta distribution ------------------------------------------------------------ -class BetaPSpace(SingleContinuousPSpace): - def __new__(cls, name, alpha, beta): - alpha, beta = sympify(alpha), sympify(beta) +class BetaDistribution(SingleContinuousDistribution): + _argnames = ('alpha', 'beta') + + set = Interval(0, 1) + + @staticmethod + def check(alpha, beta): _value_check(alpha > 0, "Alpha must be positive") _value_check(beta > 0, "Beta must be positive") - x = Symbol(name) - pdf = x**(alpha-1) * (1-x)**(beta-1) / beta_fn(alpha, beta) - - obj = SingleContinuousPSpace.__new__(cls, x, pdf, set=Interval(0, 1)) - obj.alpha = alpha - obj.beta = beta - return obj + def pdf(self, x): + alpha, beta = self.alpha, self.beta + return x**(alpha - 1) * (1 - x)**(beta - 1) / beta_fn(alpha, beta) def sample(self): - return {self.value: random.betavariate(self.alpha, self.beta)} + return random.betavariate(self.alpha, self.beta) + def Beta(name, alpha, beta): r""" @@ -264,8 +298,8 @@ Parameters ========== - alpha : Real number, `alpha` > 0 a shape - beta : Real number, `beta` > 0 a shape + alpha : Real number, `\alpha > 0`, a shape + beta : Real number, `\beta > 0`, a shape Returns ======= @@ -280,41 +314,45 @@ >>> alpha = Symbol("alpha", positive=True) >>> beta = Symbol("beta", positive=True) + >>> z = Symbol("z") >>> X = Beta("x", alpha, beta) - >>> D = density(X) + >>> D = density(X)(z) >>> pprint(D, use_unicode=False) - / alpha - 1 beta - 1 \ - | x *(-x + 1) *gamma(alpha + beta)| - Lambda|x, -----------------------------------------------| - \ gamma(alpha)*gamma(beta) / + alpha - 1 beta - 1 + z *(-z + 1) *gamma(alpha + beta) + ----------------------------------------------- + gamma(alpha)*gamma(beta) >>> simplify(E(X, meijerg=True)) alpha/(alpha + beta) - >>> simplify(variance(X, meijerg=True)) + >>> simplify(variance(X, meijerg=True)) #doctest: +SKIP alpha*beta/((alpha + beta)**2*(alpha + beta + 1)) References ========== - [1] http://en.wikipedia.org/wiki/Beta_distribution - [2] http://mathworld.wolfram.com/BetaDistribution.html + .. [1] http://en.wikipedia.org/wiki/Beta_distribution + .. [2] http://mathworld.wolfram.com/BetaDistribution.html """ - return BetaPSpace(name, alpha, beta).value + return rv(name, BetaDistribution, (alpha, beta)) #------------------------------------------------------------------------------- # Beta prime distribution ------------------------------------------------------ -class BetaPrimePSpace(SingleContinuousPSpace): - def __new__(cls, name, alpha, beta): - alpha, beta = sympify(alpha), sympify(beta) - x = Symbol(name) - pdf = x**(alpha-1)*(1+x)**(-alpha-beta)/beta_fn(alpha, beta) - obj = SingleContinuousPSpace.__new__(cls, x, pdf, set = Interval(0, oo)) - return obj + +class BetaPrimeDistribution(SingleContinuousDistribution): + _argnames = ('alpha', 'beta') + + set = Interval(0, oo) + + def pdf(self, x): + alpha, beta = self.alpha, self.beta + return x**(alpha - 1)*(1 + x)**(-alpha - beta)/beta_fn(alpha, beta) + def BetaPrime(name, alpha, beta): r""" @@ -330,8 +368,8 @@ Parameters ========== - alpha : Real number, `alpha` > 0 a shape - beta : Real number, `beta` > 0 a shape + alpha : Real number, `\alpha > 0`, a shape + beta : Real number, `\beta > 0`, a shape Returns ======= @@ -346,35 +384,36 @@ >>> alpha = Symbol("alpha", positive=True) >>> beta = Symbol("beta", positive=True) + >>> z = Symbol("z") >>> X = BetaPrime("x", alpha, beta) - >>> D = density(X) + >>> D = density(X)(z) >>> pprint(D, use_unicode=False) - / alpha - 1 -alpha - beta \ - | x *(x + 1) *gamma(alpha + beta)| - Lambda|x, ---------------------------------------------------| - \ gamma(alpha)*gamma(beta) / + alpha - 1 -alpha - beta + z *(z + 1) *gamma(alpha + beta) + --------------------------------------------------- + gamma(alpha)*gamma(beta) References ========== - [1] http://en.wikipedia.org/wiki/Beta_prime_distribution - [2] http://mathworld.wolfram.com/BetaPrimeDistribution.html + .. [1] http://en.wikipedia.org/wiki/Beta_prime_distribution + .. [2] http://mathworld.wolfram.com/BetaPrimeDistribution.html """ - return BetaPrimePSpace(name, alpha, beta).value + return rv(name, BetaPrimeDistribution, (alpha, beta)) #------------------------------------------------------------------------------- # Cauchy distribution ---------------------------------------------------------- -class CauchyPSpace(SingleContinuousPSpace): - def __new__(cls, name, x0, gamma): - x0, gamma = sympify(x0), sympify(gamma) - x = Symbol(name) - pdf = 1/(pi*gamma*(1+((x-x0)/gamma)**2)) - obj = SingleContinuousPSpace.__new__(cls, x, pdf) - return obj + +class CauchyDistribution(SingleContinuousDistribution): + _argnames = ('x0', 'gamma') + + def pdf(self, x): + return 1/(pi*self.gamma*(1 + ((x - self.x0)/self.gamma)**2)) + def Cauchy(name, x0, gamma): r""" @@ -390,7 +429,7 @@ ========== x0 : Real number, the location - gamma : Real number, `gamma` > 0 the scale + gamma : Real number, `\gamma > 0`, the scale Returns ======= @@ -405,31 +444,34 @@ >>> x0 = Symbol("x0") >>> gamma = Symbol("gamma", positive=True) + >>> z = Symbol("z") >>> X = Cauchy("x", x0, gamma) - >>> density(X) - Lambda(_x, 1/(pi*gamma*(1 + (_x - x0)**2/gamma**2))) + >>> density(X)(z) + 1/(pi*gamma*(1 + (-x0 + z)**2/gamma**2)) References ========== - [1] http://en.wikipedia.org/wiki/Cauchy_distribution - [2] http://mathworld.wolfram.com/CauchyDistribution.html + .. [1] http://en.wikipedia.org/wiki/Cauchy_distribution + .. [2] http://mathworld.wolfram.com/CauchyDistribution.html """ - return CauchyPSpace(name, x0, gamma).value + return rv(name, CauchyDistribution, (x0, gamma)) #------------------------------------------------------------------------------- # Chi distribution ------------------------------------------------------------- -class ChiPSpace(SingleContinuousPSpace): - def __new__(cls, name, k): - k = sympify(k) - x = Symbol(name) - pdf = 2**(1-k/2)*x**(k-1)*exp(-x**2/2)/gamma(k/2) - obj = SingleContinuousPSpace.__new__(cls, x, pdf, set = Interval(0, oo)) - return obj + +class ChiDistribution(SingleContinuousDistribution): + _argnames = ('k',) + + set = Interval(0, oo) + + def pdf(self, x): + return 2**(1 - self.k/2)*x**(self.k - 1)*exp(-x**2/2)/gamma(self.k/2) + def Chi(name, k): r""" @@ -445,7 +487,7 @@ Parameters ========== - k : Integer, `k` > 0 the number of degrees of freedom + k : A positive Integer, `k > 0`, the number of degrees of freedom Returns ======= @@ -459,31 +501,159 @@ >>> from sympy import Symbol, simplify >>> k = Symbol("k", integer=True) + >>> z = Symbol("z") >>> X = Chi("x", k) - >>> density(X) - Lambda(_x, 2**(-k/2 + 1)*_x**(k - 1)*exp(-_x**2/2)/gamma(k/2)) + >>> density(X)(z) + 2**(-k/2 + 1)*z**(k - 1)*exp(-z**2/2)/gamma(k/2) + + References + ========== + + .. [1] http://en.wikipedia.org/wiki/Chi_distribution + .. [2] http://mathworld.wolfram.com/ChiDistribution.html + """ + + return rv(name, ChiDistribution, (k,)) + +#------------------------------------------------------------------------------- +# Non-central Chi distribution ------------------------------------------------- + + +class ChiNoncentralDistribution(SingleContinuousDistribution): + _argnames = ('k', 'l') + + set = Interval(0, oo) + + def pdf(self, x): + k, l = self.k, self.l + return exp(-(x**2+l**2)/2)*x**k*l / (l*x)**(k/2) * besseli(k/2-1, l*x) + + +def ChiNoncentral(name, k, l): + r""" + Create a continuous random variable with a non-central Chi distribution. + + The density of the non-central Chi distribution is given by + + .. math:: + f(x) := \frac{e^{-(x^2+\lambda^2)/2} x^k\lambda} + {(\lambda x)^{k/2}} I_{k/2-1}(\lambda x) + + with `x \geq 0`. Here, `I_\nu (x)` is the + :ref:`modified Bessel function of the first kind `. + + Parameters + ========== + + k : A positive Integer, `k > 0`, the number of degrees of freedom + l : Shift parameter + + Returns + ======= + + A RandomSymbol. + + Examples + ======== + + >>> from sympy.stats import ChiNoncentral, density, E, std + >>> from sympy import Symbol, simplify + + >>> k = Symbol("k", integer=True) + >>> l = Symbol("l") + >>> z = Symbol("z") + + >>> X = ChiNoncentral("x", k, l) + + >>> density(X)(z) + l*z**k*(l*z)**(-k/2)*exp(-l**2/2 - z**2/2)*besseli(k/2 - 1, l*z) + + References + ========== + + .. [1] http://en.wikipedia.org/wiki/Noncentral_chi_distribution + """ + + return rv(name, ChiNoncentralDistribution, (k, l)) + +#------------------------------------------------------------------------------- +# Chi squared distribution ----------------------------------------------------- + + +class ChiSquaredDistribution(SingleContinuousDistribution): + _argnames = ('k',) + + set = Interval(0, oo) + + def pdf(self, x): + k = self.k + return 1/(2**(k/2)*gamma(k/2))*x**(k/2 - 1)*exp(-x/2) + + +def ChiSquared(name, k): + r""" + Create a continuous random variable with a Chi-squared distribution. + + The density of the Chi-squared distribution is given by + + .. math:: + f(x) := \frac{1}{2^{\frac{k}{2}}\Gamma\left(\frac{k}{2}\right)} + x^{\frac{k}{2}-1} e^{-\frac{x}{2}} + + with :math:`x \geq 0`. + + Parameters + ========== + + k : A positive Integer, `k > 0`, the number of degrees of freedom + + Returns + ======= + + A RandomSymbol. + + Examples + ======== + + >>> from sympy.stats import ChiSquared, density, E, variance + >>> from sympy import Symbol, simplify, combsimp, expand_func + + >>> k = Symbol("k", integer=True, positive=True) + >>> z = Symbol("z") + + >>> X = ChiSquared("x", k) + + >>> density(X)(z) + 2**(-k/2)*z**(k/2 - 1)*exp(-z/2)/gamma(k/2) + + >>> combsimp(E(X)) + k + + >>> simplify(expand_func(variance(X))) + 2*k References ========== - [1] http://en.wikipedia.org/wiki/Chi_distribution - [2] http://mathworld.wolfram.com/ChiDistribution.html + .. [1] http://en.wikipedia.org/wiki/Chi_squared_distribution + .. [2] http://mathworld.wolfram.com/Chi-SquaredDistribution.html """ - return ChiPSpace(name, k).value + return rv(name, ChiSquaredDistribution, (k, )) #------------------------------------------------------------------------------- # Dagum distribution ----------------------------------------------------------- -class DagumPSpace(SingleContinuousPSpace): - def __new__(cls, name, p, a, b): - p, a, b = sympify(p), sympify(a), sympify(b) - x = Symbol(name) - pdf = a*p/x*((x/b)**(a*p)/(((x/b)**a+1)**(p+1))) - obj = SingleContinuousPSpace.__new__(cls, x, pdf) - return obj + +class DagumDistribution(SingleContinuousDistribution): + _argnames = ('p', 'a', 'b') + + def pdf(self, x): + p, a, b = self.p, self.a, self.b + return a*p/x*((x/b)**(a*p)/(((x/b)**a + 1)**(p + 1))) + def Dagum(name, p, a, b): r""" @@ -492,17 +662,17 @@ The density of the Dagum distribution is given by .. math:: - f(x) := \frac{a p}{x} \left( \frac{(\tfrac{x}{b})^{a p}} - {\left((\tfrac{x}{b})^a + 1 \right)^{p+1}} \right) + f(x) := \frac{a p}{x} \left( \frac{\left(\tfrac{x}{b}\right)^{a p}} + {\left(\left(\tfrac{x}{b}\right)^a + 1 \right)^{p+1}} \right) with :math:`x > 0`. Parameters ========== - p : Real number, `p` > 0 a shape - a : Real number, `a` > 0 a shape - b : Real number, `b` > 0 a scale + p : Real number, `p > 0`, a shape + a : Real number, `a > 0`, a shape + b : Real number, `b > 0`, a scale Returns ======= @@ -518,38 +688,107 @@ >>> p = Symbol("p", positive=True) >>> b = Symbol("b", positive=True) >>> a = Symbol("a", positive=True) + >>> z = Symbol("z") >>> X = Dagum("x", p, a, b) - >>> density(X) - Lambda(_x, a*p*(_x/b)**(a*p)*((_x/b)**a + 1)**(-p - 1)/_x) + >>> density(X)(z) + a*p*(z/b)**(a*p)*((z/b)**a + 1)**(-p - 1)/z References ========== - [1] http://en.wikipedia.org/wiki/Dagum_distribution + .. [1] http://en.wikipedia.org/wiki/Dagum_distribution """ - return DagumPSpace(name, p, a, b).value + return rv(name, DagumDistribution, (p, a, b)) + +#------------------------------------------------------------------------------- +# Erlang distribution ---------------------------------------------------------- + +def Erlang(name, k, l): + r""" + Create a continuous random variable with an Erlang distribution. + + The density of the Erlang distribution is given by + + .. math:: + f(x) := \frac{\lambda^k x^{k-1} e^{-\lambda x}}{(k-1)!} + + with :math:`x \in [0,\infty]`. + + Parameters + ========== + + k : Integer + l : Real number, `\lambda > 0`, the rate + + Returns + ======= + + A RandomSymbol. + + Examples + ======== + + >>> from sympy.stats import Erlang, density, cdf, E, variance + >>> from sympy import Symbol, simplify, pprint + + >>> k = Symbol("k", integer=True, positive=True) + >>> l = Symbol("l", positive=True) + >>> z = Symbol("z") + + >>> X = Erlang("x", k, l) + + >>> D = density(X)(z) + >>> pprint(D, use_unicode=False) + k k - 1 -l*z + l *z *e + --------------- + gamma(k) + + >>> C = cdf(X, meijerg=True)(z) + >>> pprint(C, use_unicode=False) + / k*lowergamma(k, 0) k*lowergamma(k, l*z) + |- ------------------ + -------------------- for z >= 0 + < gamma(k + 1) gamma(k + 1) + | + \ 0 otherwise + + >>> simplify(E(X)) + k/l + + >>> simplify(variance(X)) + k/l**2 + + References + ========== + + .. [1] http://en.wikipedia.org/wiki/Erlang_distribution + .. [2] http://mathworld.wolfram.com/ErlangDistribution.html + """ + + return rv(name, GammaDistribution, (k, 1/l)) #------------------------------------------------------------------------------- # Exponential distribution ----------------------------------------------------- -class ExponentialPSpace(SingleContinuousPSpace): - def __new__(cls, name, rate): - rate = sympify(rate) - _value_check(rate > 0, "Rate must be positive.") +class ExponentialDistribution(SingleContinuousDistribution): + _argnames = ('rate',) + + set = Interval(0, oo) - x = Symbol(name) - pdf = rate * exp(-rate*x) + @staticmethod + def check(rate): + _value_check(rate > 0, "Rate must be positive.") - obj = SingleContinuousPSpace.__new__(cls, x, pdf, set=Interval(0, oo)) - obj.rate = rate - return obj + def pdf(self, x): + return self.rate * exp(-self.rate*x) def sample(self): - return {self.value: random.expovariate(self.rate)} + return random.expovariate(self.rate) + def Exponential(name, rate): r""" @@ -560,12 +799,12 @@ .. math:: f(x) := \lambda \exp(-\lambda x) - with :math:`x > 0`. + with `x > 0`. Note that the expected value is `1/\lambda`. Parameters ========== - rate : Real number, `rate` > 0 the rate or inverse scale + rate : A positive Real number, `\lambda > 0`, the rate (or inverse scale/inverse mean) Returns ======= @@ -580,14 +819,15 @@ >>> from sympy import Symbol >>> l = Symbol("lambda", positive=True) + >>> z = Symbol("z") >>> X = Exponential("x", l) - >>> density(X) - Lambda(_x, lambda*exp(-_x*lambda)) + >>> density(X)(z) + lambda*exp(-lambda*z) - >>> cdf(X) - Lambda(_z, Piecewise((1 - exp(-_z*lambda), _z >= 0), (0, True))) + >>> cdf(X)(z) + Piecewise((1 - exp(-lambda*z), z >= 0), (0, True)) >>> E(X) 1/lambda @@ -600,8 +840,8 @@ >>> X = Exponential('x', 10) - >>> density(X) - Lambda(_x, 10*exp(-10*_x)) + >>> density(X)(z) + 10*exp(-10*z) >>> E(X) 1/10 @@ -612,32 +852,238 @@ References ========== - [1] http://en.wikipedia.org/wiki/Exponential_distribution - [2] http://mathworld.wolfram.com/ExponentialDistribution.html + .. [1] http://en.wikipedia.org/wiki/Exponential_distribution + .. [2] http://mathworld.wolfram.com/ExponentialDistribution.html + """ + + return rv(name, ExponentialDistribution, (rate, )) + +#------------------------------------------------------------------------------- +# F distribution --------------------------------------------------------------- + +class FDistributionDistribution(SingleContinuousDistribution): + _argnames = ('d1', 'd2') + + set = Interval(0, oo) + + def pdf(self, x): + d1, d2 = self.d1, self.d2 + return (sqrt((d1*x)**d1*d2**d2 / (d1*x+d2)**(d1+d2)) + / (x * beta_fn(d1/2, d2/2))) + +def FDistribution(name, d1, d2): + r""" + Create a continuous random variable with a F distribution. + + The density of the F distribution is given by + + .. math:: + f(x) := \frac{\sqrt{\frac{(d_1 x)^{d_1} d_2^{d_2}} + {(d_1 x + d_2)^{d_1 + d_2}}}} + {x \mathrm{B} \left(\frac{d_1}{2}, \frac{d_2}{2}\right)} + + with :math:`x > 0`. + + .. TODO - What do these parameters mean? + + Parameters + ========== + + d1 : `d_1 > 0` a parameter + d2 : `d_2 > 0` a parameter + + Returns + ======= + + A RandomSymbol. + + Examples + ======== + + >>> from sympy.stats import FDistribution, density + >>> from sympy import Symbol, simplify, pprint + + >>> d1 = Symbol("d1", positive=True) + >>> d2 = Symbol("d2", positive=True) + >>> z = Symbol("z") + + >>> X = FDistribution("x", d1, d2) + + >>> D = density(X)(z) + >>> pprint(D, use_unicode=False) + d2 + -- ______________________________ + 2 / d1 -d1 - d2 /d1 d2\ + d2 *\/ (d1*z) *(d1*z + d2) *gamma|-- + --| + \2 2 / + ----------------------------------------------------- + /d1\ /d2\ + z*gamma|--|*gamma|--| + \2 / \2 / + + References + ========== + + .. [1] http://en.wikipedia.org/wiki/F-distribution + .. [2] http://mathworld.wolfram.com/F-Distribution.html """ - return ExponentialPSpace(name, rate).value + return rv(name, FDistributionDistribution, (d1, d2)) + +#------------------------------------------------------------------------------- +# Fisher Z distribution -------------------------------------------------------- + +class FisherZDistribution(SingleContinuousDistribution): + _argnames = ('d1', 'd2') + + def pdf(self, x): + d1, d2 = self.d1, self.d2 + return (2*d1**(d1/2)*d2**(d2/2) / beta_fn(d1/2, d2/2) * + exp(d1*x) / (d1*exp(2*x)+d2)**((d1+d2)/2)) + +def FisherZ(name, d1, d2): + r""" + Create a Continuous Random Variable with an Fisher's Z distribution. + + The density of the Fisher's Z distribution is given by + + .. math:: + f(x) := \frac{2d_1^{d_1/2} d_2^{d_2/2}} {\mathrm{B}(d_1/2, d_2/2)} + \frac{e^{d_1z}}{\left(d_1e^{2z}+d_2\right)^{\left(d_1+d_2\right)/2}} + + + .. TODO - What is the difference between these degrees of freedom? + + Parameters + ========== + + d1 : `d_1 > 0`, degree of freedom + d2 : `d_2 > 0`, degree of freedom + + Returns + ======= + + A RandomSymbol. + + Examples + ======== + + >>> from sympy.stats import FisherZ, density + >>> from sympy import Symbol, simplify, pprint + + >>> d1 = Symbol("d1", positive=True) + >>> d2 = Symbol("d2", positive=True) + >>> z = Symbol("z") + + >>> X = FisherZ("x", d1, d2) + + >>> D = density(X)(z) + >>> pprint(D, use_unicode=False) + d1 d2 + d1 d2 - -- - -- + -- -- 2 2 + 2 2 / 2*z \ d1*z /d1 d2\ + 2*d1 *d2 *\d1*e + d2/ *e *gamma|-- + --| + \2 2 / + -------------------------------------------------------- + /d1\ /d2\ + gamma|--|*gamma|--| + \2 / \2 / + + References + ========== + + .. [1] http://en.wikipedia.org/wiki/Fisher%27s_z-distribution + .. [2] http://mathworld.wolfram.com/Fishersz-Distribution.html + """ + + return rv(name, FisherZDistribution, (d1, d2)) + +#------------------------------------------------------------------------------- +# Frechet distribution --------------------------------------------------------- + +class FrechetDistribution(SingleContinuousDistribution): + _argnames = ('a', 's', 'm') + + set = Interval(0, oo) + + def __new__(cls, a, s=1, m=0): + a, s, m = list(map(sympify, (a, s, m))) + return Basic.__new__(cls, a, s, m) + + def pdf(self, x): + a, s, m = self.a, self.s, self.m + return a/s * ((x-m)/s)**(-1-a) * exp(-((x-m)/s)**(-a)) + +def Frechet(name, a, s=1, m=0): + r""" + Create a continuous random variable with a Frechet distribution. + + The density of the Frechet distribution is given by + + .. math:: + f(x) := \frac{\alpha}{s} \left(\frac{x-m}{s}\right)^{-1-\alpha} + e^{-(\frac{x-m}{s})^{-\alpha}} + + with :math:`x \geq m`. + + Parameters + ========== + + a : Real number, :math:`a \in \left(0, \infty\right)` the shape + s : Real number, :math:`s \in \left(0, \infty\right)` the scale + m : Real number, :math:`m \in \left(-\infty, \infty\right)` the minimum + + Returns + ======= + + A RandomSymbol. + + Examples + ======== + + >>> from sympy.stats import Frechet, density, E, std + >>> from sympy import Symbol, simplify + + >>> a = Symbol("a", positive=True) + >>> s = Symbol("s", positive=True) + >>> m = Symbol("m", real=True) + >>> z = Symbol("z") + + >>> X = Frechet("x", a, s, m) + + >>> density(X)(z) + a*((-m + z)/s)**(-a - 1)*exp(-((-m + z)/s)**(-a))/s + + References + ========== + + .. [1] http://en.wikipedia.org/wiki/Fr%C3%A9chet_distribution + """ + + return rv(name, FrechetDistribution, (a, s, m)) #------------------------------------------------------------------------------- # Gamma distribution ----------------------------------------------------------- -class GammaPSpace(SingleContinuousPSpace): - def __new__(cls, name, k, theta): - k, theta = sympify(k), sympify(theta) +class GammaDistribution(SingleContinuousDistribution): + _argnames = ('k', 'theta') + + set = Interval(0, oo) + + @staticmethod + def check(k, theta): _value_check(k > 0, "k must be positive") _value_check(theta > 0, "Theta must be positive") - x = Symbol(name) - pdf = x**(k-1) * exp(-x/theta) / (gamma(k)*theta**k) - - obj = SingleContinuousPSpace.__new__(cls, x, pdf, set=Interval(0, oo)) - obj.k = k - obj.theta = theta - return obj + def pdf(self, x): + k, theta = self.k, self.theta + return x**(k - 1) * exp(-x/theta) / (gamma(k)*theta**k) def sample(self): - return {self.value: random.gammavariate(self.k, self.theta)} + return random.gammavariate(self.k, self.theta) + def Gamma(name, k, theta): r""" @@ -653,8 +1099,8 @@ Parameters ========== - k : Real number, `k` > 0 a shape - theta : Real number, `theta` > 0 a scale + k : Real number, `k > 0`, a shape + theta : Real number, `\theta > 0`, a scale Returns ======= @@ -665,62 +1111,198 @@ ======== >>> from sympy.stats import Gamma, density, cdf, E, variance - >>> from sympy import Symbol, pprint + >>> from sympy import Symbol, pprint, simplify >>> k = Symbol("k", positive=True) >>> theta = Symbol("theta", positive=True) + >>> z = Symbol("z") >>> X = Gamma("x", k, theta) - >>> D = density(X) + >>> D = density(X)(z) >>> pprint(D, use_unicode=False) - / -x \ - | -----| - | k - 1 -k theta| - | x *theta *e | - Lambda|x, ---------------------| - \ gamma(k) / + -z + ----- + -k k - 1 theta + theta *z *e + --------------------- + gamma(k) - >>> C = cdf(X, meijerg=True) + >>> C = cdf(X, meijerg=True)(z) >>> pprint(C, use_unicode=False) - / / / z \ \ - | | k*lowergamma|k, -----| | - | | k*lowergamma(k, 0) \ theta/ | - Lambda|z, <- ------------------ + ---------------------- for z >= 0| - | | gamma(k + 1) gamma(k + 1) | - | | | - \ \ 0 otherwise / + / / z \ + | k*lowergamma|k, -----| + | k*lowergamma(k, 0) \ theta/ + <- ------------------ + ---------------------- for z >= 0 + | gamma(k + 1) gamma(k + 1) + | + \ 0 otherwise >>> E(X) theta*gamma(k + 1)/gamma(k) - >>> V = variance(X) + >>> V = simplify(variance(X)) >>> pprint(V, use_unicode=False) - 2 2 -k k + 1 - theta *gamma (k + 1) theta*theta *theta *gamma(k + 2) - - -------------------- + ------------------------------------- - 2 gamma(k) - gamma (k) + 2 + k*theta + + + References + ========== + + .. [1] http://en.wikipedia.org/wiki/Gamma_distribution + .. [2] http://mathworld.wolfram.com/GammaDistribution.html + """ + + return rv(name, GammaDistribution, (k, theta)) + +#------------------------------------------------------------------------------- +# Inverse Gamma distribution --------------------------------------------------- + +class GammaInverseDistribution(SingleContinuousDistribution): + _argnames = ('a', 'b') + + set = Interval(0, oo) + + @staticmethod + def check(a, b): + _value_check(a > 0, "alpha must be positive") + _value_check(b > 0, "beta must be positive") + + def pdf(self, x): + a, b = self.a, self.b + return b**a/gamma(a) * x**(-a-1) * exp(-b/x) + +def GammaInverse(name, a, b): + r""" + Create a continuous random variable with an inverse Gamma distribution. + + The density of the inverse Gamma distribution is given by + + .. math:: + f(x) := \frac{\beta^\alpha}{\Gamma(\alpha)} x^{-\alpha - 1} + \exp\left(\frac{-\beta}{x}\right) + + with :math:`x > 0`. + + Parameters + ========== + + a : Real number, `a > 0` a shape + b : Real number, `b > 0` a scale + + Returns + ======= + + A RandomSymbol. + + Examples + ======== + + >>> from sympy.stats import GammaInverse, density, cdf, E, variance + >>> from sympy import Symbol, pprint + + >>> a = Symbol("a", positive=True) + >>> b = Symbol("b", positive=True) + >>> z = Symbol("z") + + >>> X = GammaInverse("x", a, b) + + >>> D = density(X)(z) + >>> pprint(D, use_unicode=False) + -b + --- + a -a - 1 z + b *z *e + --------------- + gamma(a) + + References + ========== + + .. [1] http://en.wikipedia.org/wiki/Inverse-gamma_distribution + """ + + return rv(name, GammaInverseDistribution, (a, b)) + +#------------------------------------------------------------------------------- +# Kumaraswamy distribution ----------------------------------------------------- + +class KumaraswamyDistribution(SingleContinuousDistribution): + _argnames = ('a', 'b') + + set = Interval(0, oo) + + @staticmethod + def check(a, b): + _value_check(a > 0, "a must be positive") + _value_check(b > 0, "b must be positive") + + def pdf(self, x): + a, b = self.a, self.b + return a * b * x**(a-1) * (1-x**a)**(b-1) + + +def Kumaraswamy(name, a, b): + r""" + Create a Continuous Random Variable with a Kumaraswamy distribution. + + The density of the Kumaraswamy distribution is given by + + .. math:: + f(x) := a b x^{a-1} (1-x^a)^{b-1} + + with :math:`x \in [0,1]`. + + Parameters + ========== + + a : Real number, `a > 0` a shape + b : Real number, `b > 0` a shape + + Returns + ======= + + A RandomSymbol. + + Examples + ======== + + >>> from sympy.stats import Kumaraswamy, density, E, variance + >>> from sympy import Symbol, simplify, pprint + + >>> a = Symbol("a", positive=True) + >>> b = Symbol("b", positive=True) + >>> z = Symbol("z") + + >>> X = Kumaraswamy("x", a, b) + + >>> D = density(X)(z) + >>> pprint(D, use_unicode=False) + b - 1 + a - 1 / a \ + a*b*z *\- z + 1/ + References ========== - [1] http://en.wikipedia.org/wiki/Gamma_distribution - [2] http://mathworld.wolfram.com/GammaDistribution.html + .. [1] http://en.wikipedia.org/wiki/Kumaraswamy_distribution """ - return GammaPSpace(name, k, theta).value + return rv(name, KumaraswamyDistribution, (a, b)) #------------------------------------------------------------------------------- # Laplace distribution --------------------------------------------------------- -class LaplacePSpace(SingleContinuousPSpace): - def __new__(cls, name, mu, b): - mu, b = sympify(mu), sympify(b) - x = Symbol(name) - pdf = 1/(2*b)*exp(-Abs(x-mu)/b) - obj = SingleContinuousPSpace.__new__(cls, x, pdf) - return obj + +class LaplaceDistribution(SingleContinuousDistribution): + _argnames = ('mu', 'b') + + def pdf(self, x): + mu, b = self.mu, self.b + return 1/(2*b)*exp(-Abs(x - mu)/b) + def Laplace(name, mu, b): r""" @@ -734,8 +1316,8 @@ Parameters ========== - mu : Real number, the location - b : Real number, `b` > 0 a scale + mu : Real number, the location (mean) + b : Real number, `b > 0`, a scale Returns ======= @@ -750,33 +1332,33 @@ >>> mu = Symbol("mu") >>> b = Symbol("b", positive=True) + >>> z = Symbol("z") >>> X = Laplace("x", mu, b) - >>> density(X) - Lambda(_x, exp(-Abs(_x - mu)/b)/(2*b)) + >>> density(X)(z) + exp(-Abs(-mu + z)/b)/(2*b) References ========== - [1] http://en.wikipedia.org/wiki/Laplace_distribution - [2] http://mathworld.wolfram.com/LaplaceDistribution.html + .. [1] http://en.wikipedia.org/wiki/Laplace_distribution + .. [2] http://mathworld.wolfram.com/LaplaceDistribution.html """ - return LaplacePSpace(name, mu, b).value + return rv(name, LaplaceDistribution, (mu, b)) #------------------------------------------------------------------------------- # Logistic distribution -------------------------------------------------------- -class LogisticPSpace(SingleContinuousPSpace): - def __new__(cls, name, mu, s): - mu, s = sympify(mu), sympify(s) - x = Symbol(name) - pdf = exp(-(x-mu)/s)/(s*(1+exp(-(x-mu)/s))**2) +class LogisticDistribution(SingleContinuousDistribution): + _argnames = ('mu', 's') + + def pdf(self, x): + mu, s = self.mu, self.s + return exp(-(x - mu)/s)/(s*(1 + exp(-(x - mu)/s))**2) - obj = SingleContinuousPSpace.__new__(cls, x, pdf) - return obj def Logistic(name, mu, s): r""" @@ -790,8 +1372,8 @@ Parameters ========== - mu : Real number, the location - s : Real number, `s` > 0 a scale + mu : Real number, the location (mean) + s : Real number, `s > 0` a scale Returns ======= @@ -806,38 +1388,38 @@ >>> mu = Symbol("mu", real=True) >>> s = Symbol("s", positive=True) + >>> z = Symbol("z") >>> X = Logistic("x", mu, s) - >>> density(X) - Lambda(_x, exp((-_x + mu)/s)/(s*(exp((-_x + mu)/s) + 1)**2)) + >>> density(X)(z) + exp((mu - z)/s)/(s*(exp((mu - z)/s) + 1)**2) References ========== - [1] http://en.wikipedia.org/wiki/Logistic_distribution - [2] http://mathworld.wolfram.com/LogisticDistribution.html + .. [1] http://en.wikipedia.org/wiki/Logistic_distribution + .. [2] http://mathworld.wolfram.com/LogisticDistribution.html """ - return LogisticPSpace(name, mu, s).value + return rv(name, LogisticDistribution, (mu, s)) #------------------------------------------------------------------------------- # Log Normal distribution ------------------------------------------------------ -class LogNormalPSpace(SingleContinuousPSpace): - def __new__(cls, name, mean, std): - mean, std = sympify(mean), sympify(std) - - x = Symbol(name) - pdf = exp(-(log(x)-mean)**2 / (2*std**2)) / (x*sqrt(2*pi)*std) - - obj = SingleContinuousPSpace.__new__(cls, x, pdf, set=Interval(0, oo)) - obj.mean = mean - obj.std = std - return obj + +class LogNormalDistribution(SingleContinuousDistribution): + _argnames = ('mean', 'std') + + set = Interval(0, oo) + + def pdf(self, x): + mean, std = self.mean, self.std + return exp(-(log(x) - mean)**2 / (2*std**2)) / (x*sqrt(2*pi)*std) def sample(self): - return {self.value: random.lognormvariate(self.mean, self.std)} + return random.lognormvariate(self.mean, self.std) + def LogNormal(name, mean, std): r""" @@ -870,47 +1452,50 @@ >>> mu = Symbol("mu", real=True) >>> sigma = Symbol("sigma", positive=True) + >>> z = Symbol("z") >>> X = LogNormal("x", mu, sigma) - >>> D = density(X) + >>> D = density(X)(z) >>> pprint(D, use_unicode=False) - / 2\ - | -(-mu + log(x)) | - | ----------------| - | 2 | - | ___ 2*sigma | - | \/ 2 *e | - Lambda|x, -----------------------| - | ____ | - \ 2*x*\/ pi *sigma / + 2 + -(-mu + log(z)) + ----------------- + 2 + ___ 2*sigma + \/ 2 *e + ------------------------ + ____ + 2*\/ pi *sigma*z + >>> X = LogNormal('x', 0, 1) # Mean 0, standard deviation 1 - >>> density(X) - Lambda(_x, sqrt(2)*exp(-log(_x)**2/2)/(2*_x*sqrt(pi))) + >>> density(X)(z) + sqrt(2)*exp(-log(z)**2/2)/(2*sqrt(pi)*z) References ========== - [1] http://en.wikipedia.org/wiki/Lognormal - [2] http://mathworld.wolfram.com/LogNormalDistribution.html + .. [1] http://en.wikipedia.org/wiki/Lognormal + .. [2] http://mathworld.wolfram.com/LogNormalDistribution.html """ - return LogNormalPSpace(name, mean, std).value + return rv(name, LogNormalDistribution, (mean, std)) #------------------------------------------------------------------------------- # Maxwell distribution --------------------------------------------------------- -class MaxwellPSpace(SingleContinuousPSpace): - def __new__(cls, name, a): - a = sympify(a) - - x = Symbol(name) - - pdf = sqrt(2/pi)*x**2*exp(-x**2/(2*a**2))/a**3 - obj = SingleContinuousPSpace.__new__(cls, x, pdf, set = Interval(0, oo)) - return obj + +class MaxwellDistribution(SingleContinuousDistribution): + _argnames = ('a',) + + set = Interval(0, oo) + + def pdf(self, x): + a = self.a + return sqrt(2/pi)*x**2*exp(-x**2/(2*a**2))/a**3 + def Maxwell(name, a): r""" @@ -923,10 +1508,12 @@ with :math:`x \geq 0`. + .. TODO - what does the parameter mean? + Parameters ========== - a : Real number, `a` > 0 + a : Real number, `a > 0` Returns ======= @@ -940,11 +1527,12 @@ >>> from sympy import Symbol, simplify >>> a = Symbol("a", positive=True) + >>> z = Symbol("z") >>> X = Maxwell("x", a) - >>> density(X) - Lambda(_x, sqrt(2)*_x**2*exp(-_x**2/(2*a**2))/(sqrt(pi)*a**3)) + >>> density(X)(z) + sqrt(2)*z**2*exp(-z**2/(2*a**2))/(sqrt(pi)*a**3) >>> E(X) 2*sqrt(2)*a/sqrt(pi) @@ -955,22 +1543,25 @@ References ========== - [1] http://en.wikipedia.org/wiki/Maxwell_distribution - [2] http://mathworld.wolfram.com/MaxwellDistribution.html + .. [1] http://en.wikipedia.org/wiki/Maxwell_distribution + .. [2] http://mathworld.wolfram.com/MaxwellDistribution.html """ - return MaxwellPSpace(name, a).value + return rv(name, MaxwellDistribution, (a, )) #------------------------------------------------------------------------------- # Nakagami distribution -------------------------------------------------------- -class NakagamiPSpace(SingleContinuousPSpace): - def __new__(cls, name, mu, omega): - mu, omega = sympify(mu), sympify(omega) - x = Symbol(name) - pdf = 2*mu**mu/(gamma(mu)*omega**mu)*x**(2*mu-1)*exp(-mu/omega*x**2) - obj = SingleContinuousPSpace.__new__(cls, x, pdf, set = Interval(0, oo)) - return obj + +class NakagamiDistribution(SingleContinuousDistribution): + _argnames = ('mu', 'omega') + + set = Interval(0, oo) + + def pdf(self, x): + mu, omega = self.mu, self.omega + return 2*mu**mu/(gamma(mu)*omega**mu)*x**(2*mu - 1)*exp(-mu/omega*x**2) + def Nakagami(name, mu, omega): r""" @@ -987,8 +1578,8 @@ Parameters ========== - mu : Real number, :math:`mu \geq \frac{1}{2}` a shape - omega : Real number, `omega` > 0 the spread + mu : Real number, `\mu \geq \frac{1}{2}` a shape + omega : Real number, `\omega > 0`, the spread Returns ======= @@ -1003,57 +1594,55 @@ >>> mu = Symbol("mu", positive=True) >>> omega = Symbol("omega", positive=True) + >>> z = Symbol("z") >>> X = Nakagami("x", mu, omega) - >>> D = density(X) + >>> D = density(X)(z) >>> pprint(D, use_unicode=False) - / 2 \ - | -x *mu| - | ------| - | 2*mu - 1 mu -mu omega | - | 2*x *mu *omega *e | - Lambda|x, ---------------------------------| - \ gamma(mu) / + 2 + -mu*z + ------- + mu -mu 2*mu - 1 omega + 2*mu *omega *z *e + ---------------------------------- + gamma(mu) >>> simplify(E(X, meijerg=True)) sqrt(mu)*sqrt(omega)*gamma(mu + 1/2)/gamma(mu + 1) >>> V = simplify(variance(X, meijerg=True)) >>> pprint(V, use_unicode=False) - / 2 \ - omega*\gamma(mu)*gamma(mu + 1) - gamma (mu + 1/2)/ - -------------------------------------------------- - gamma(mu)*gamma(mu + 1) + 2 + omega*gamma (mu + 1/2) + omega - ----------------------- + gamma(mu)*gamma(mu + 1) References ========== - [1] http://en.wikipedia.org/wiki/Nakagami_distribution + .. [1] http://en.wikipedia.org/wiki/Nakagami_distribution """ - return NakagamiPSpace(name, mu, omega).value + return rv(name, NakagamiDistribution, (mu, omega)) #------------------------------------------------------------------------------- # Normal distribution ---------------------------------------------------------- -class NormalPSpace(SingleContinuousPSpace): - def __new__(cls, name, mean, std): - mean, std = sympify(mean), sympify(std) - _value_check(std > 0, "Standard deviation must be positive") +class NormalDistribution(SingleContinuousDistribution): + _argnames = ('mean', 'std') - x = Symbol(name) - pdf = exp(-(x-mean)**2 / (2*std**2)) / (sqrt(2*pi)*std) + @staticmethod + def check(mean, std): + _value_check(std > 0, "Standard deviation must be positive") - obj = SingleContinuousPSpace.__new__(cls, x, pdf) - obj.mean = mean - obj.std = std - obj.variance = std**2 - return obj + def pdf(self, x): + return exp(-(x - self.mean)**2 / (2*self.std**2)) / (sqrt(2*pi)*self.std) def sample(self): - return {self.value: random.normalvariate(self.mean, self.std)} + return random.normalvariate(self.mean, self.std) + def Normal(name, mean, std): r""" @@ -1079,31 +1668,32 @@ ======== >>> from sympy.stats import Normal, density, E, std, cdf, skewness - >>> from sympy import Symbol, simplify, pprint + >>> from sympy import Symbol, simplify, pprint, factor, together, factor_terms >>> mu = Symbol("mu") >>> sigma = Symbol("sigma", positive=True) + >>> z = Symbol("z") >>> X = Normal("x", mu, sigma) - >>> density(X) - Lambda(_x, sqrt(2)*exp(-(_x - mu)**2/(2*sigma**2))/(2*sqrt(pi)*sigma)) + >>> density(X)(z) + sqrt(2)*exp(-(-mu + z)**2/(2*sigma**2))/(2*sqrt(pi)*sigma) - >>> C = simplify(cdf(X)) + >>> C = simplify(cdf(X))(z) # it needs a little more help... >>> pprint(C, use_unicode=False) - / / ___ \ \ - | |\/ 2 *(z - mu)| | - | erf|--------------| | - | \ 2*sigma / 1| - Lambda|z, ------------------- + -| - \ 2 2/ + / ___ \ + |\/ 2 *(-mu + z)| + erf|---------------| + \ 2*sigma / 1 + -------------------- + - + 2 2 >>> simplify(skewness(X)) 0 >>> X = Normal("x", 0, 1) # Mean 0, standard deviation 1 - >>> density(X) - Lambda(_x, sqrt(2)*exp(-_x**2/2)/(2*sqrt(pi))) + >>> density(X)(z) + sqrt(2)*exp(-z**2/2)/(2*sqrt(pi)) >>> E(2*X + 1) 1 @@ -1114,32 +1704,35 @@ References ========== - [1] http://en.wikipedia.org/wiki/Normal_distribution - [2] http://mathworld.wolfram.com/NormalDistributionFunction.html + .. [1] http://en.wikipedia.org/wiki/Normal_distribution + .. [2] http://mathworld.wolfram.com/NormalDistributionFunction.html """ - return NormalPSpace(name, mean, std).value + return rv(name, NormalDistribution, (mean, std)) #------------------------------------------------------------------------------- # Pareto distribution ---------------------------------------------------------- -class ParetoPSpace(SingleContinuousPSpace): - def __new__(cls, name, xm, alpha): - xm, alpha = sympify(xm), sympify(alpha) +class ParetoDistribution(SingleContinuousDistribution): + _argnames = ('xm', 'alpha') + + @property + def set(self): + return Interval(self.xm, oo) + + @staticmethod + def check(xm, alpha): _value_check(xm > 0, "Xm must be positive") _value_check(alpha > 0, "Alpha must be positive") - x = Symbol(name) - pdf = alpha * xm**alpha / x**(alpha+1) - - obj = SingleContinuousPSpace.__new__(cls, x, pdf, set=Interval(xm, oo)) - obj.xm = xm - obj.alpha = alpha - return obj + def pdf(self, x): + xm, alpha = self.xm, self.alpha + return alpha * xm**alpha / x**(alpha + 1) def sample(self): - return {self.value: random.paretovariate(self.alpha)} + return random.paretovariate(self.alpha) + def Pareto(name, xm, alpha): r""" @@ -1148,15 +1741,15 @@ The density of the Pareto distribution is given by .. math:: - f(x) := \frac{\alpha\,x_\mathrm{m}^\alpha}{x^{\alpha+1}} + f(x) := \frac{\alpha\,x_m^\alpha}{x^{\alpha+1}} with :math:`x \in [x_m,\infty]`. Parameters ========== - xm : Real number, `xm` > 0 a scale - alpha : Real number, `alpha` > 0 a shape + xm : Real number, `x_m > 0`, a scale + alpha : Real number, `\alpha > 0`, a shape Returns ======= @@ -1171,31 +1764,179 @@ >>> xm = Symbol("xm", positive=True) >>> beta = Symbol("beta", positive=True) + >>> z = Symbol("z") >>> X = Pareto("x", xm, beta) - >>> density(X) - Lambda(_x, _x**(-beta - 1)*beta*xm**beta) + >>> density(X)(z) + beta*xm**beta*z**(-beta - 1) References ========== - [1] http://en.wikipedia.org/wiki/Pareto_distribution - [2] http://mathworld.wolfram.com/ParetoDistribution.html + .. [1] http://en.wikipedia.org/wiki/Pareto_distribution + .. [2] http://mathworld.wolfram.com/ParetoDistribution.html """ - return ParetoPSpace(name, xm, alpha).value + return rv(name, ParetoDistribution, (xm, alpha)) + +#------------------------------------------------------------------------------- +# QuadraticU distribution ------------------------------------------------------ + +class QuadraticUDistribution(SingleContinuousDistribution): + _argnames = ('a', 'b') + + @property + def set(self): + return Interval(self.a, self.b) + + def pdf(self, x): + a, b = self.a, self.b + alpha = 12 / (b-a)**3 + beta = (a+b) / 2 + return Piecewise( + (alpha * (x-beta)**2, And(a<=x, x<=b)), + (S.Zero, True)) + +def QuadraticU(name, a, b): + r""" + Create a Continuous Random Variable with a U-quadratic distribution. + + The density of the U-quadratic distribution is given by + + .. math:: + f(x) := \alpha (x-\beta)^2 + + with :math:`x \in [a,b]`. + + Parameters + ========== + + a : Real number + b : Real number, :math:`a < b` + + Returns + ======= + + A RandomSymbol. + + Examples + ======== + + >>> from sympy.stats import QuadraticU, density, E, variance + >>> from sympy import Symbol, simplify, factor, pprint + + >>> a = Symbol("a", real=True) + >>> b = Symbol("b", real=True) + >>> z = Symbol("z") + + >>> X = QuadraticU("x", a, b) + + >>> D = density(X)(z) + >>> pprint(D, use_unicode=False) + / 2 + | / a b \ + |12*|- - - - + z| + | \ 2 2 / + <----------------- for And(a <= z, z <= b) + | 3 + | (-a + b) + | + \ 0 otherwise + + References + ========== + + .. [1] http://en.wikipedia.org/wiki/U-quadratic_distribution + """ + + return rv(name, QuadraticUDistribution, (a, b)) + +#------------------------------------------------------------------------------- +# RaisedCosine distribution ---------------------------------------------------- + +class RaisedCosineDistribution(SingleContinuousDistribution): + _argnames = ('mu', 's') + + @property + def set(self): + return Interval(self.mu - self.s, self.mu + self.s) + + @staticmethod + def check(mu, s): + _value_check(s > 0, "s must be positive") + + def pdf(self, x): + mu, s = self.mu, self.s + return Piecewise( + ((1+cos(pi*(x-mu)/s)) / (2*s), And(mu-s<=x, x<=mu+s)), + (S.Zero, True)) + +def RaisedCosine(name, mu, s): + r""" + Create a Continuous Random Variable with a raised cosine distribution. + + The density of the raised cosine distribution is given by + + .. math:: + f(x) := \frac{1}{2s}\left(1+\cos\left(\frac{x-\mu}{s}\pi\right)\right) + + with :math:`x \in [\mu-s,\mu+s]`. + + Parameters + ========== + + mu : Real number + s : Real number, `s > 0` + + Returns + ======= + + A RandomSymbol. + + Examples + ======== + + >>> from sympy.stats import RaisedCosine, density, E, variance + >>> from sympy import Symbol, simplify, pprint + + >>> mu = Symbol("mu", real=True) + >>> s = Symbol("s", positive=True) + >>> z = Symbol("z") + + >>> X = RaisedCosine("x", mu, s) + + >>> D = density(X)(z) + >>> pprint(D, use_unicode=False) + / /pi*(-mu + z)\ + |cos|------------| + 1 + | \ s / + <--------------------- for And(z <= mu + s, mu - s <= z) + | 2*s + | + \ 0 otherwise + + References + ========== + + .. [1] http://en.wikipedia.org/wiki/Raised_cosine_distribution + """ + + return rv(name, RaisedCosineDistribution, (mu, s)) #------------------------------------------------------------------------------- # Rayleigh distribution -------------------------------------------------------- -class RayleighPSpace(SingleContinuousPSpace): - def __new__(cls, name, sigma): - sigma = sympify(sigma) - x = Symbol(name) - pdf = x/sigma**2*exp(-x**2/(2*sigma**2)) - obj = SingleContinuousPSpace.__new__(cls, x, pdf, set = Interval(0, oo)) - return obj + +class RayleighDistribution(SingleContinuousDistribution): + _argnames = ('sigma',) + + set = Interval(0, oo) + + def pdf(self, x): + sigma = self.sigma + return x/sigma**2*exp(-x**2/(2*sigma**2)) + def Rayleigh(name, sigma): r""" @@ -1211,7 +1952,7 @@ Parameters ========== - sigma : Real number, `sigma` > 0 + sigma : Real number, `\sigma > 0` Returns ======= @@ -1225,11 +1966,12 @@ >>> from sympy import Symbol, simplify >>> sigma = Symbol("sigma", positive=True) + >>> z = Symbol("z") >>> X = Rayleigh("x", sigma) - >>> density(X) - Lambda(_x, _x*exp(-_x**2/(2*sigma**2))/sigma**2) + >>> density(X)(z) + z*exp(-z**2/(2*sigma**2))/sigma**2 >>> E(X) sqrt(2)*sqrt(pi)*sigma/2 @@ -1240,22 +1982,23 @@ References ========== - [1] http://en.wikipedia.org/wiki/Rayleigh_distribution - [2] http://mathworld.wolfram.com/RayleighDistribution.html + .. [1] http://en.wikipedia.org/wiki/Rayleigh_distribution + .. [2] http://mathworld.wolfram.com/RayleighDistribution.html """ - return RayleighPSpace(name, sigma).value + return rv(name, RayleighDistribution, (sigma, )) #------------------------------------------------------------------------------- # StudentT distribution -------------------------------------------------------- -class StudentTPSpace(SingleContinuousPSpace): - def __new__(cls, name, nu): - nu = sympify(nu) - x = Symbol(name) - pdf = 1/(sqrt(nu)*beta_fn(S(1)/2,nu/2))*(1+x**2/nu)**(-(nu+1)/2) - obj = SingleContinuousPSpace.__new__(cls, x, pdf) - return obj + +class StudentTDistribution(SingleContinuousDistribution): + _argnames = ('nu',) + + def pdf(self, x): + nu = self.nu + return 1/(sqrt(nu)*beta_fn(S(1)/2, nu/2))*(1 + x**2/nu)**(-(nu + 1)/2) + def StudentT(name, nu): r""" @@ -1271,7 +2014,7 @@ Parameters ========== - nu : Real number, `nu` > 0, the degrees of freedom + nu : Real number, `\nu > 0`, the degrees of freedom Returns ======= @@ -1285,48 +2028,48 @@ >>> from sympy import Symbol, simplify, pprint >>> nu = Symbol("nu", positive=True) + >>> z = Symbol("z") >>> X = StudentT("x", nu) - >>> D = density(X) + >>> D = density(X)(z) >>> pprint(D, use_unicode=False) - / nu 1 \ - | - -- - - | - | 2 2 | - | / 2 \ | - | |x | /nu 1\| - | |-- + 1| *gamma|-- + -|| - | \nu / \2 2/| - Lambda|x, ------------------------------| - | ____ ____ /nu\ | - | \/ pi *\/ nu *gamma|--| | - \ \2 / / + nu 1 + - -- - - + 2 2 + / 2\ + | z | /nu 1\ + |1 + --| *gamma|-- + -| + \ nu/ \2 2/ + ------------------------------ + ____ ____ /nu\ + \/ pi *\/ nu *gamma|--| + \2 / References ========== - [1] http://en.wikipedia.org/wiki/Student_t-distribution - [2] http://mathworld.wolfram.com/Studentst-Distribution.html + .. [1] http://en.wikipedia.org/wiki/Student_t-distribution + .. [2] http://mathworld.wolfram.com/Studentst-Distribution.html """ - return StudentTPSpace(name, nu).value + return rv(name, StudentTDistribution, (nu, )) #------------------------------------------------------------------------------- # Triangular distribution ------------------------------------------------------ -class TriangularPSpace(SingleContinuousPSpace): - def __new__(cls, name, a, b, c): - a, b, c = sympify(a), sympify(b), sympify(c) - - x = Symbol(name) - pdf = Piecewise( - (2*(x-a)/((b-a)*(c-a)), And(a<=x, x>> from sympy.stats import Triangular, density, E - >>> from sympy import Symbol + >>> from sympy import Symbol, pprint >>> a = Symbol("a") >>> b = Symbol("b") >>> c = Symbol("c") + >>> z = Symbol("z") >>> X = Triangular("x", a,b,c) - >>> density(X) - Lambda(_x, Piecewise(((2*_x - 2*a)/((-a + b)*(-a + c)), - And(_x < c, a <= _x)), - (2/(-a + b), _x == c), - ((-2*_x + 2*b)/((-a + b)*(b - c)), - And(_x <= b, c < _x)), - (0, True))) + >>> pprint(density(X)(z), use_unicode=False) + / -2*a + 2*z + |----------------- for And(a <= z, z < c) + |(-a + b)*(-a + c) + | + | 2 + | ------ for z = c + < -a + b + | + | 2*b - 2*z + |---------------- for And(z <= b, c < z) + |(-a + b)*(b - c) + | + \ 0 otherwise References ========== - [1] http://en.wikipedia.org/wiki/Triangular_distribution - [2] http://mathworld.wolfram.com/TriangularDistribution.html + .. [1] http://en.wikipedia.org/wiki/Triangular_distribution + .. [2] http://mathworld.wolfram.com/TriangularDistribution.html """ - return TriangularPSpace(name, a, b, c).value + return rv(name, TriangularDistribution, (a, b, c)) #------------------------------------------------------------------------------- # Uniform distribution --------------------------------------------------------- -class UniformPSpace(SingleContinuousPSpace): - def __new__(cls, name, left, right): - left, right = sympify(left), sympify(right) - - x = Symbol(name) - pdf = Piecewise( - (S.One/(right-left), And(left <= x, x <= right)), - (S.Zero, True)) - obj = SingleContinuousPSpace.__new__(cls, x, pdf) - obj.left = left - obj.right = right - return obj +class UniformDistribution(SingleContinuousDistribution): + _argnames = ('left', 'right') + + def pdf(self, x): + left, right = self.left, self.right + return Piecewise( + (S.One/(right - left), And(left <= x, x <= right)), + (S.Zero, True)) - def compute_cdf(self, expr, **kwargs): + def compute_cdf(self, **kwargs): from sympy import Lambda, Min z = Dummy('z', real=True, bounded=True) - result = SingleContinuousPSpace.compute_cdf(self, expr, **kwargs) + result = SingleContinuousDistribution.compute_cdf(self, **kwargs) result = result(z).subs({Min(z, self.right): z, Min(z, self.left, self.right): self.left}) return Lambda(z, result) - def integrate(self, expr, rvs=None, **kwargs): + def expectation(self, expr, var, **kwargs): from sympy import Max, Min - result = SingleContinuousPSpace.integrate(self, expr, rvs, **kwargs) + result = SingleContinuousDistribution.expectation(self, expr, var, **kwargs) result = result.subs({Max(self.left, self.right): self.right, Min(self.left, self.right): self.left}) return result def sample(self): - return {self.value: random.uniform(self.left, self.right)} + return random.uniform(self.left, self.right) + def Uniform(name, left, right): r""" @@ -1450,16 +2198,17 @@ >>> from sympy.stats import Uniform, density, cdf, E, variance, skewness >>> from sympy import Symbol, simplify - >>> a = Symbol("a") - >>> b = Symbol("b") + >>> a = Symbol("a", negative=True) + >>> b = Symbol("b", positive=True) + >>> z = Symbol("z") >>> X = Uniform("x", a, b) - >>> density(X) - Lambda(_x, Piecewise((1/(-a + b), And(_x <= b, a <= _x)), (0, True))) + >>> density(X)(z) + Piecewise((1/(-a + b), And(a <= z, z <= b)), (0, True)) - >>> cdf(X) - Lambda(_z, _z/(-a + b) - a/(-a + b)) + >>> cdf(X)(z) + -a/(-a + b) + z/(-a + b) >>> simplify(E(X)) a/2 + b/2 @@ -1473,25 +2222,30 @@ References ========== - [1] http://en.wikipedia.org/wiki/Uniform_distribution_%28continuous%29 - [2] http://mathworld.wolfram.com/UniformDistribution.html + .. [1] http://en.wikipedia.org/wiki/Uniform_distribution_%28continuous%29 + .. [2] http://mathworld.wolfram.com/UniformDistribution.html """ - return UniformPSpace(name, left, right).value + return rv(name, UniformDistribution, (left, right)) #------------------------------------------------------------------------------- # UniformSum distribution ------------------------------------------------------ -class UniformSumPSpace(SingleContinuousPSpace): - def __new__(cls, name, n): - n = sympify(n) - x = Symbol(name) +class UniformSumDistribution(SingleContinuousDistribution): + _argnames = ('n',) + + @property + def set(self): + return Interval(0, self.n) + + def pdf(self, x): + n = self.n k = Dummy("k") - pdf =1/factorial(n-1)*Sum((-1)**k*binomial(n,k)*(x-k)**(n-1), (k,0,floor(x))) + return 1/factorial( + n - 1)*Sum((-1)**k*binomial(n, k)*(x - k)**(n - 1), (k, 0, floor(x))) + - obj = SingleContinuousPSpace.__new__(cls, x, pdf, set=Interval(0,n)) - return obj def UniformSum(name, n): r""" @@ -1509,7 +2263,7 @@ Parameters ========== - n : Integral number, `n` > 0 + n : A positive Integer, `n > 0` Returns ======= @@ -1523,51 +2277,121 @@ >>> from sympy import Symbol, pprint >>> n = Symbol("n", integer=True) + >>> z = Symbol("z") >>> X = UniformSum("x", n) - >>> D = density(X) + >>> D = density(X)(z) >>> pprint(D, use_unicode=False) - / floor(x) \ - | ___ | - | \ ` | - | \ k n - 1 /n\| - | ) (-1) *(-k + x) *| || - | / \k/| - | /__, | - | k = 0 | - Lambda|x, --------------------------------| - \ (n - 1)! / + floor(z) + ___ + \ ` + \ k n - 1 /n\ + ) (-1) *(-k + z) *| | + / \k/ + /__, + k = 0 + -------------------------------- + (n - 1)! References ========== - [1] http://en.wikipedia.org/wiki/Uniform_sum_distribution - [2] http://mathworld.wolfram.com/UniformSumDistribution.html + .. [1] http://en.wikipedia.org/wiki/Uniform_sum_distribution + .. [2] http://mathworld.wolfram.com/UniformSumDistribution.html """ - return UniformSumPSpace(name, n).value + return rv(name, UniformSumDistribution, (n, )) + +#------------------------------------------------------------------------------- +# VonMises distribution -------------------------------------------------------- + +class VonMisesDistribution(SingleContinuousDistribution): + _argnames = ('mu', 'k') + + set = Interval(0, 2*pi) + + @staticmethod + def check(mu, k): + _value_check(k > 0, "k must be positive") + + def pdf(self, x): + mu, k = self.mu, self.k + return exp(k*cos(x-mu)) / (2*pi*besseli(0, k)) + + +def VonMises(name, mu, k): + r""" + Create a Continuous Random Variable with a von Mises distribution. + + The density of the von Mises distribution is given by + + .. math:: + f(x) := \frac{e^{\kappa\cos(x-\mu)}}{2\pi I_0(\kappa)} + + with :math:`x \in [0,2\pi]`. + + Parameters + ========== + + mu : Real number, measure of location + k : Real number, measure of concentration + + Returns + ======= + + A RandomSymbol. + + Examples + ======== + + >>> from sympy.stats import VonMises, density, E, variance + >>> from sympy import Symbol, simplify, pprint + + >>> mu = Symbol("mu") + >>> k = Symbol("k", positive=True) + >>> z = Symbol("z") + + >>> X = VonMises("x", mu, k) + + >>> D = density(X)(z) + >>> pprint(D, use_unicode=False) + k*cos(mu - z) + e + ------------------ + 2*pi*besseli(0, k) + + + References + ========== + + .. [1] http://en.wikipedia.org/wiki/Von_Mises_distribution + .. [2] http://mathworld.wolfram.com/vonMisesDistribution.html + """ + + return rv(name, VonMisesDistribution, (mu, k)) #------------------------------------------------------------------------------- # Weibull distribution --------------------------------------------------------- -class WeibullPSpace(SingleContinuousPSpace): - def __new__(cls, name, alpha, beta): - alpha, beta = sympify(alpha), sympify(beta) +class WeibullDistribution(SingleContinuousDistribution): + _argnames = ('alpha', 'beta') + + set = Interval(0, oo) + + @staticmethod + def check(alpha, beta): _value_check(alpha > 0, "Alpha must be positive") _value_check(beta > 0, "Beta must be positive") - x = Symbol(name) - pdf = beta * (x/alpha)**(beta-1) * exp(-(x/alpha)**beta) / alpha - - obj = SingleContinuousPSpace.__new__(cls, x, pdf, set=Interval(0, oo)) - obj.alpha = alpha - obj.beta = beta - return obj + def pdf(self, x): + alpha, beta = self.alpha, self.beta + return beta * (x/alpha)**(beta - 1) * exp(-(x/alpha)**beta) / alpha def sample(self): - return {self.value: random.weibullvariate(self.alpha, self.beta)} + return random.weibullvariate(self.alpha, self.beta) + def Weibull(name, alpha, beta): r""" @@ -1586,7 +2410,7 @@ ========== lambda : Real number, :math:`\lambda > 0` a scale - k : Real number, `k` > 0 a shape + k : Real number, `k > 0` a shape Returns ======= @@ -1601,11 +2425,12 @@ >>> l = Symbol("lambda", positive=True) >>> k = Symbol("k", positive=True) + >>> z = Symbol("z") >>> X = Weibull("x", l, k) - >>> density(X) - Lambda(_x, k*(_x/lambda)**(k - 1)*exp(-(_x/lambda)**k)/lambda) + >>> density(X)(z) + k*(z/lambda)**(k - 1)*exp(-(z/lambda)**k)/lambda >>> simplify(E(X)) lambda*gamma(1 + 1/k) @@ -1616,25 +2441,28 @@ References ========== - [1] http://en.wikipedia.org/wiki/Weibull_distribution - [2] http://mathworld.wolfram.com/WeibullDistribution.html + .. [1] http://en.wikipedia.org/wiki/Weibull_distribution + .. [2] http://mathworld.wolfram.com/WeibullDistribution.html """ - return WeibullPSpace(name, alpha, beta).value + return rv(name, WeibullDistribution, (alpha, beta)) #------------------------------------------------------------------------------- # Wigner semicircle distribution ----------------------------------------------- -class WignerSemicirclePSpace(SingleContinuousPSpace): - def __new__(cls, name, R): - R = sympify(R) - x = Symbol(name) - pdf = 2/(pi*R**2)*sqrt(R**2-x**2) +class WignerSemicircleDistribution(SingleContinuousDistribution): + _argnames = ('R',) + + @property + def set(self): + return Interval(-self.R, self.R) + + def pdf(self, x): + R = self.R + return 2/(pi*R**2)*sqrt(R**2 - x**2) - obj = SingleContinuousPSpace.__new__(cls, x, pdf, set = Interval(-R, R)) - return obj def WignerSemicircle(name, R): r""" @@ -1650,7 +2478,7 @@ Parameters ========== - R : Real number, `R` > 0 the radius + R : Real number, `R > 0`, the radius Returns ======= @@ -1664,11 +2492,12 @@ >>> from sympy import Symbol, simplify >>> R = Symbol("R", positive=True) + >>> z = Symbol("z") >>> X = WignerSemicircle("x", R) - >>> density(X) - Lambda(_x, 2*sqrt(-_x**2 + R**2)/(pi*R**2)) + >>> density(X)(z) + 2*sqrt(R**2 - z**2)/(pi*R**2) >>> E(X) 0 @@ -1676,8 +2505,8 @@ References ========== - [1] http://en.wikipedia.org/wiki/Wigner_semicircle_distribution - [2] http://mathworld.wolfram.com/WignersSemicircleLaw.html + .. [1] http://en.wikipedia.org/wiki/Wigner_semicircle_distribution + .. [2] http://mathworld.wolfram.com/WignersSemicircleLaw.html """ - return WignerSemicirclePSpace(name, R).value + return rv(name, WignerSemicircleDistribution, (R,)) diff -Nru python3-sympy-0.7.2/sympy/stats/drv.py python3-sympy-0.7.3/sympy/stats/drv.py --- python3-sympy-0.7.2/sympy/stats/drv.py 1970-01-01 00:00:00.000000000 +0000 +++ python3-sympy-0.7.3/sympy/stats/drv.py 2013-07-13 17:53:32.000000000 +0000 @@ -0,0 +1,131 @@ +from sympy import (Basic, sympify, symbols, Dummy, Lambda, summation, + Piecewise, S, cacheit, solve, Sum) +from sympy.stats.rv import NamedArgsMixin, SinglePSpace +import random + +class SingleDiscreteDistribution(Basic, NamedArgsMixin): + """ Discrete distribution of a single variable + + Serves as superclass for PoissonDistribution etc.... + + Provides methods for pdf, cdf, and sampling + + See Also: + sympy.stats.crv_types.* + """ + + set = S.Integers + + def __new__(cls, *args): + args = list(map(sympify, args)) + return Basic.__new__(cls, *args) + + @staticmethod + def check(*args): + pass + + def sample(self): + """ A random realization from the distribution """ + icdf = self._inverse_cdf_expression() + return floor(icdf(random.uniform(0, 1))) + + @cacheit + def _inverse_cdf_expression(self): + """ Inverse of the CDF + + Used by sample + """ + x, z = symbols('x, z', real=True, positive=True, cls=Dummy) + # Invert CDF + try: + inverse_cdf = solve(self.cdf(x) - z, x) + except NotImplementedError: + inverse_cdf = None + if not inverse_cdf or len(inverse_cdf) != 1: + raise NotImplementedError("Could not invert CDF") + + return Lambda(z, inverse_cdf[0]) + + @cacheit + def compute_cdf(self, **kwargs): + """ Compute the CDF from the PDF + + Returns a Lambda + """ + x, z = symbols('x, z', integer=True, bounded=True, cls=Dummy) + left_bound = self.set.inf + + # CDF is integral of PDF from left bound to z + pdf = self.pdf(x) + cdf = summation(pdf, (x, left_bound, z), **kwargs) + # CDF Ensure that CDF left of left_bound is zero + cdf = Piecewise((cdf, z >= left_bound), (0, True)) + return Lambda(z, cdf) + + def cdf(self, x, **kwargs): + """ Cumulative density function """ + return self.compute_cdf(**kwargs)(x) + + def expectation(self, expr, var, **kwargs): + """ Expectation of expression over distribution """ + # return summation(expr * self.pdf(var), (var, self.set), **kwargs) + # TODO: support discrete sets with non integer stepsizes + evaluate = kwargs.pop('evaluate', True) + if evaluate: + return summation(expr * self.pdf(var), + (var, self.set.inf, self.set.sup), **kwargs) + else: + return Sum(expr * self.pdf(var), + (var, self.set.inf, self.set.sup), **kwargs) + + def __call__(self, *args): + return self.pdf(*args) + +class SingleDiscretePSpace(SinglePSpace): + """ Discrete probability space over a single univariate variable """ + + @property + def set(self): + return self.distribution.set + + @property + def domain(self): + raise NotImplementedError() + + def sample(self): + """ + Internal sample method + + Returns dictionary mapping RandomSymbol to realization value. + """ + return {self.value: self.distribution.sample()} + + def integrate(self, expr, rvs=None, **kwargs): + rvs = rvs or (self.value,) + if self.value not in rvs: + return expr + + expr = expr.xreplace(dict((rv, rv.symbol) for rv in rvs)) + + x = self.value.symbol + try: + return self.distribution.expectation(expr, x, **kwargs) + except: + evaluate = kwargs.pop('evaluate', True) + if evaluate: + return summation(expr * self.pdf, (x, self.set.inf, self.set.sup), + **kwargs) + else: + return Sum(expr * self.pdf, (x, self.set.inf, self.set.sup), + **kwargs) + + def compute_cdf(self, expr, **kwargs): + if expr == self.value: + return self.distribution.compute_cdf(**kwargs) + else: + raise NotImplementedError() + + def compute_density(self, expr, **kwargs): + if expr == self.value: + return self.distribution + raise NotImplementedError() diff -Nru python3-sympy-0.7.2/sympy/stats/drv_types.py python3-sympy-0.7.3/sympy/stats/drv_types.py --- python3-sympy-0.7.2/sympy/stats/drv_types.py 1970-01-01 00:00:00.000000000 +0000 +++ python3-sympy-0.7.3/sympy/stats/drv_types.py 2013-07-13 17:53:32.000000000 +0000 @@ -0,0 +1,129 @@ +from sympy.stats.drv import SingleDiscreteDistribution, SingleDiscretePSpace +from sympy import factorial, exp, Basic, Range, S, oo, sympify +from sympy.stats.rv import _value_check + +__all__ = ['Geometric', 'Poisson'] + +def rv(symbol, cls, *args): + args = list(map(sympify, args)) + dist = cls(*args) + dist.check(*args) + return SingleDiscretePSpace(symbol, dist).value + +class PoissonDistribution(SingleDiscreteDistribution): + _argnames = ('lamda',) + + set = S.Naturals0 + + @staticmethod + def check(lamda): + _value_check(lamda > 0, "Lambda must be positive") + + def pdf(self, k): + return self.lamda**k / factorial(k) * exp(-self.lamda) + +def Poisson(name, lamda): + r""" + Create a discrete random variable with a Poisson distribution. + + The density of the Poisson distribution is given by + + .. math:: + f(k) := \frac{\lambda^{k} e^{- \lambda}}{k!} + + Parameters + ========== + + lamda: Positive number, a rate + + Returns + ======= + + A RandomSymbol. + + Examples + ======== + + >>> from sympy.stats import Poisson, density, E, variance + >>> from sympy import Symbol, simplify + + >>> rate = Symbol("lambda", positive=True) + >>> z = Symbol("z") + + >>> X = Poisson("x", rate) + + >>> density(X)(z) + lambda**z*exp(-lambda)/factorial(z) + + >>> E(X) + lambda + + >>> simplify(variance(X)) + lambda + + References + ========== + + [1] http://en.wikipedia.org/wiki/Poisson_distribution + [2] http://mathworld.wolfram.com/PoissonDistribution.html + """ + return rv(name, PoissonDistribution, lamda) + +class GeometricDistribution(SingleDiscreteDistribution): + _argnames = ('p',) + set = S.Naturals + + @staticmethod + def check(p): + # _value_check(0 < p <= 1, "p must be between 0 and 1") + pass + + def pdf(self, k): + return (1 - self.p)**(k - 1) * self.p + +def Geometric(name, p): + r""" + Create a discrete random variable with a Geometric distribution. + + The density of the Poisson distribution is given by + + .. math:: + f(k) := p (1 - p)^{k - 1} + + Parameters + ========== + + p: A probability between 0 and 1 + + Returns + ======= + + A RandomSymbol. + + Examples + ======== + + >>> from sympy.stats import Geometric, density, E, variance + >>> from sympy import Symbol, S + + >>> p = S.One / 5 + >>> z = Symbol("z") + + >>> X = Geometric("x", p) + + >>> density(X)(z) + (4/5)**(z - 1)/5 + + >>> E(X) + 5 + + >>> variance(X) + 20 + + References + ========== + + [1] http://en.wikipedia.org/wiki/Geometric_distribution + [2] http://mathworld.wolfram.com/GeometricDistribution.html + """ + return rv(name, GeometricDistribution, p) diff -Nru python3-sympy-0.7.2/sympy/stats/frv.py python3-sympy-0.7.3/sympy/stats/frv.py --- python3-sympy-0.7.2/sympy/stats/frv.py 2012-10-17 03:02:22.000000000 +0000 +++ python3-sympy-0.7.3/sympy/stats/frv.py 2013-07-13 17:53:32.000000000 +0000 @@ -12,11 +12,16 @@ And, Or, Tuple) from sympy.core.sets import FiniteSet from sympy.stats.rv import (RandomDomain, ProductDomain, ConditionalDomain, - PSpace, ProductPSpace, SinglePSpace, random_symbols, sumsets, rv_subs) + PSpace, ProductPSpace, SinglePSpace, random_symbols, sumsets, rv_subs, + NamedArgsMixin) from sympy.core.compatibility import product from sympy.core.containers import Dict import random +class FiniteDensity(dict): + def __call__(self, item): + return self[sympify(item)] + class FiniteDomain(RandomDomain): """ A domain with discrete finite support @@ -24,14 +29,14 @@ Represented using a FiniteSet. """ is_Finite = True - def __new__(cls, elements): - elements = FiniteSet(*elements) - symbols = FiniteSet(sym for sym, val in elements) - return RandomDomain.__new__(cls, symbols, elements) + + @property + def symbols(self): + return FiniteSet(sym for sym, val in self.elements) @property def elements(self): - return self.args[1] + return self.args[0] @property def dict(self): @@ -46,6 +51,7 @@ def as_boolean(self): return Or(*[And(*[Eq(sym, val) for sym, val in item]) for item in self]) + class SingleFiniteDomain(FiniteDomain): """ A FiniteDomain over a single symbol/set @@ -54,18 +60,27 @@ """ def __new__(cls, symbol, set): - return RandomDomain.__new__(cls, (symbol, ), FiniteSet(*set)) + if not isinstance(set, FiniteSet): + set = FiniteSet(*set) + return Basic.__new__(cls, symbol, set) @property def symbol(self): + return self.args[0] return tuple(self.symbols)[0] + @property - def elements(self): - return FiniteSet(frozenset(((self.symbol, elem), )) for elem in self.set) + def symbols(self): + return FiniteSet(self.symbol) + @property def set(self): return self.args[1] + @property + def elements(self): + return FiniteSet(frozenset(((self.symbol, elem), )) for elem in self.set) + def __iter__(self): return (frozenset(((self.symbol, elem),)) for elem in self.set) @@ -73,6 +88,7 @@ sym, val = tuple(other)[0] return sym == self.symbol and val in self.set + class ProductFiniteDomain(ProductDomain, FiniteDomain): """ A Finite domain consisting of several other FiniteDomains @@ -88,6 +104,7 @@ def elements(self): return FiniteSet(iter(self)) + class ConditionalFiniteDomain(ConditionalDomain, ProductFiniteDomain): """ A FiniteDomain that has been restricted by a condition @@ -97,24 +114,28 @@ """ def __new__(cls, domain, condition): + if condition is True: + return domain cond = rv_subs(condition) # Check that we aren't passed a condition like die1 == z # where 'z' is a symbol that we don't know about # We will never be able to test this equality through iteration if not cond.free_symbols.issubset(domain.free_symbols): - raise ValueError('Condition "%s" contains foreign symbols \n%s.\n'%( - condition, tuple(cond.free_symbols-domain.free_symbols))+ + raise ValueError('Condition "%s" contains foreign symbols \n%s.\n' % ( + condition, tuple(cond.free_symbols - domain.free_symbols)) + "Will be unable to iterate using this condition") - return ConditionalDomain.__new__(cls, domain, condition) + return Basic.__new__(cls, domain, cond) + + def _test(self, elem): - val = self.condition.subs(dict(elem)) + val = self.condition.xreplace(dict(elem)) if val in [True, False]: return val elif val.is_Equality: return val.lhs == val.rhs - raise ValueError("Undeciable if %s"%str(val)) + raise ValueError("Undeciable if %s" % str(val)) def __contains__(self, other): return other in self.fulldomain and self._test(other) @@ -129,24 +150,51 @@ if frozenset(((self.fulldomain.symbol, elem),)) in self) else: raise NotImplementedError( - "Not implemented on multi-dimensional conditional domain") + "Not implemented on multi-dimensional conditional domain") #return FiniteSet(elem for elem in self.fulldomain if elem in self) def as_boolean(self): return FiniteDomain.as_boolean(self) +class SingleFiniteDistribution(Basic, NamedArgsMixin): + def __new__(cls, *args): + args = list(map(sympify, args)) + return Basic.__new__(cls, *args) + + @property + @cacheit + def density(self): + return dict((k, self.pdf(k)) for k in self.set) + + def pdf(self, x): + return self.density.get(x, 0) + + @property + def set(self): + return list(self.density.keys()) + + #============================================= #========= Probability Space =============== #============================================= + class FinitePSpace(PSpace): """ A Finite Probability Space Represents the probabilities of a finite number of events. """ - is_Finite = True + + @property + def domain(self): + return self.args[0] + + @property + def density(self): + return self.args[0] + def __new__(cls, domain, density): density = dict((sympify(key), sympify(val)) for key, val in list(density.items())) @@ -157,17 +205,17 @@ return obj def prob_of(self, elem): - return self._density.get(elem,0) + return self._density.get(elem, 0) def where(self, condition): assert all(r.symbol in self.symbols for r in random_symbols(condition)) return ConditionalFiniteDomain(self.domain, condition) def compute_density(self, expr): - expr = expr.subs(dict(((rs, rs.symbol) for rs in self.values))) - d = {} + expr = expr.xreplace(dict(((rs, rs.symbol) for rs in self.values))) + d = FiniteDensity() for elem in self.domain: - val = expr.subs(dict(elem)) + val = expr.xreplace(dict(elem)) prob = self.prob_of(elem) d[val] = d.get(val, 0) + prob return d @@ -196,9 +244,9 @@ def integrate(self, expr, rvs=None): rvs = rvs or self.values - expr = expr.subs(dict((rs, rs.symbol) for rs in rvs)) - return sum(expr.subs(dict(elem)) * self.prob_of(elem) - for elem in self.domain) + expr = expr.xreplace(dict((rs, rs.symbol) for rs in rvs)) + return sum([expr.xreplace(dict(elem)) * self.prob_of(elem) + for elem in self.domain]) def probability(self, condition): cond_symbols = frozenset(rs.symbol for rs in random_symbols(condition)) @@ -221,7 +269,7 @@ expr = Tuple(*self.values) cdf = self.sorted_cdf(expr, python_float=True) - x = random.uniform(0,1) + x = random.uniform(0, 1) # Find first occurence with cumulative probability less than x # This should be replaced with binary search for value, cum_prob in cdf: @@ -231,7 +279,8 @@ assert False, "We should never have gotten to this point" -class SingleFinitePSpace(FinitePSpace, SinglePSpace): + +class SingleFinitePSpace(SinglePSpace, FinitePSpace): """ A single finite probability space @@ -241,15 +290,16 @@ This class is implemented by many of the standard FiniteRV types such as Die, Bernoulli, Coin, etc.... """ + @property + def domain(self): + return SingleFiniteDomain(self.symbol, self.distribution.set) + + @property + @cacheit + def _density(self): + return dict((frozenset(((self.symbol, val),)), prob) + for val, prob in list(self.distribution.density.items())) - @classmethod - def fromdict(cls, name, density): - symbol = Symbol(name); - domain = SingleFiniteDomain(symbol, frozenset(list(density.keys()))) - density = dict((frozenset(((symbol, val),)) , prob) - for val, prob in list(density.items())) - density = Dict(density) - return FinitePSpace.__new__(cls, domain, density) class ProductFinitePSpace(ProductPSpace, FinitePSpace): """ @@ -258,6 +308,7 @@ @property def domain(self): return ProductFiniteDomain(*[space.domain for space in self.spaces]) + @property @cacheit def _density(self): diff -Nru python3-sympy-0.7.2/sympy/stats/frv_types.py python3-sympy-0.7.3/sympy/stats/frv_types.py --- python3-sympy-0.7.2/sympy/stats/frv_types.py 2012-10-17 03:02:22.000000000 +0000 +++ python3-sympy-0.7.3/sympy/stats/frv_types.py 2013-07-13 17:53:32.000000000 +0000 @@ -12,12 +12,26 @@ Hypergeometric """ -from sympy.stats.frv import SingleFinitePSpace -from sympy import S, sympify, Rational, binomial +from sympy.stats.frv import (SingleFinitePSpace, SingleFiniteDistribution) +from sympy import (S, sympify, Rational, binomial, cacheit, Symbol, Integer, + Dict, Basic) __all__ = ['FiniteRV', 'DiscreteUniform', 'Die', 'Bernoulli', 'Coin', 'Binomial', 'Hypergeometric'] +def rv(name, cls, *args): + density = cls(*args) + return SingleFinitePSpace(name, density).value + +class FiniteDistributionHandmade(SingleFiniteDistribution): + @property + def density(self): + return self.args[0] + + def __new__(cls, density): + density = Dict(density) + return Basic.__new__(cls, density) + def FiniteRV(name, density): """ Create a Finite Random Variable given a dict representing the density. @@ -34,35 +48,32 @@ >>> P(X>=2) 0.700000000000000 """ - return SingleFinitePSpace.fromdict(name, density).value - -class DiscreteUniformPSpace(SingleFinitePSpace): - """ - Create a Finite Random Variable representing a discrete uniform - distribution. + return rv(name, FiniteDistributionHandmade, density) - This class is for internal use. - - Create DiscreteUniform Random Symbols using DiscreteUniform function - - Examples - ======== +class DiscreteUniformDistribution(SingleFiniteDistribution): + @property + def items(self): + return self.args + + @property + def p(self): + return Rational(1, len(self.items)) + + @property + @cacheit + def density(self): + return dict((k, self.p) for k in self.set) + + @property + def set(self): + return self.items + + def pdf(self, x): + if x in self.items: + return self.p + else: + return S.Zero - >>> from sympy.stats import DiscreteUniform, density - >>> from sympy import symbols - - >>> X = DiscreteUniform('X', symbols('a b c')) # equally likely over a, b, c - >>> density(X) - {a: 1/3, b: 1/3, c: 1/3} - - >>> Y = DiscreteUniform('Y', list(range(5))) # distribution over a range - >>> density(Y) - {0: 1/5, 1: 1/5, 2: 1/5, 3: 1/5, 4: 1/5} - """ - def __new__(cls, name, items): - density = dict((sympify(item), Rational(1, len(items))) - for item in items) - return cls.fromdict(name, density) def DiscreteUniform(name, items): """ @@ -86,28 +97,23 @@ {0: 1/5, 1: 1/5, 2: 1/5, 3: 1/5, 4: 1/5} """ - return DiscreteUniformPSpace(name, items).value + return rv(name, DiscreteUniformDistribution, *items) -class DiePSpace(DiscreteUniformPSpace): - """ - Create a Finite Random Variable representing a fair die. - This class is for internal use. +class DieDistribution(SingleFiniteDistribution): + _argnames = ('sides',) - Create Dice Random Symbols using Die function + @property + def set(self): + return list(map(Integer, list(range(1, self.sides+1)))) + + def pdf(self, x): + x = sympify(x) + if x.is_Integer and x >= 1 and x <= self.sides: + return Rational(1, self.sides) + else: + return 0 - >>> from sympy.stats import Die, density - - >>> D6 = Die('D6', 6) # Six sided Die - >>> density(D6) - {1: 1/6, 2: 1/6, 3: 1/6, 4: 1/6, 5: 1/6, 6: 1/6} - - >>> D4 = Die('D4', 4) # Four sided Die - >>> density(D4) - {1: 1/4, 2: 1/4, 3: 1/4, 4: 1/4} - """ - def __new__(cls, name, sides): - return DiscreteUniformPSpace.__new__(cls, name, list(range(1, sides+1))) def Die(name, sides=6): """ @@ -126,34 +132,17 @@ {1: 1/4, 2: 1/4, 3: 1/4, 4: 1/4} """ - return DiePSpace(name, sides).value - -class BernoulliPSpace(SingleFinitePSpace): - """ - Create a Finite Random Variable representing a Bernoulli process. - - Returns a RandomSymbol. + return rv(name, DieDistribution, sides) - This class is for internal use. - Create Bernoulli Random Symbols using Bernoulli function. +class BernoulliDistribution(SingleFiniteDistribution): + _argnames = ('p', 'succ', 'fail') - >>> from sympy.stats import Bernoulli, density - >>> from sympy import S + @property + @cacheit + def density(self): + return {self.succ: self.p, self.fail: 1 - self.p} - >>> X = Bernoulli('X', S(3)/4) # 1-0 Bernoulli variable, probability = 3/4 - >>> density(X) - {0: 1/4, 1: 3/4} - - >>> X = Bernoulli('X', S.Half, 'Heads', 'Tails') # A fair coin toss - >>> density(X) - {Heads: 1/2, Tails: 1/2} - """ - - def __new__(cls, name, p, succ, fail): - succ, fail, p = list(map(sympify, (succ, fail, p))) - density = {succ: p, fail: (1-p)} - return cls.fromdict(name, density) def Bernoulli(name, p, succ=1, fail=0): """ @@ -173,31 +162,8 @@ {Heads: 1/2, Tails: 1/2} """ - return BernoulliPSpace(name, p, succ, fail).value - -class CoinPSpace(BernoulliPSpace): - """ - A probability space representing a coin toss. - - Probability p is the chance of gettings "Heads." Half by default - - This class is for internal use. - - Create Coin's using Coin function - - >>> from sympy.stats import Coin, density - >>> from sympy import Rational - - >>> C = Coin('C') # A fair coin toss - >>> density(C) - {H: 1/2, T: 1/2} + return rv(name, BernoulliDistribution, p, succ, fail) - >>> C2 = Coin('C2', Rational(3, 5)) # An unfair coin - >>> density(C2) - {H: 3/5, T: 2/5} - """ - def __new__(cls, name, p): - return BernoulliPSpace.__new__(cls, name, p, 'H', 'T') def Coin(name, p=S.Half): """ @@ -218,32 +184,19 @@ >>> density(C2) {H: 3/5, T: 2/5} """ - return CoinPSpace(name, p).value - -class BinomialPSpace(SingleFinitePSpace): - """ - Create a Finite Random Variable representing a binomial distribution. - - This class is for internal use. + return rv(name, BernoulliDistribution, p, 'H', 'T') - Create Binomial Random Symbols using Binomial function. - Examples - ======== +class BinomialDistribution(SingleFiniteDistribution): + _argnames = ('n', 'p', 'succ', 'fail') - >>> from sympy.stats import Binomial, density - >>> from sympy import S + @property + @cacheit + def density(self): + n, p, succ, fail = self.n, self.p, self.succ, self.fail + return dict((k*succ + (n - k)*fail, + binomial(n, k) * p**k * (1 - p)**(n - k)) for k in range(0, n + 1)) - >>> X = Binomial('X', 4, S.Half) # Four "coin flips" - >>> density(X) - {0: 1/16, 1: 1/4, 2: 3/8, 3: 1/4, 4: 1/16} - """ - - def __new__(cls, name, n, p, succ, fail): - n, p, succ, fail = list(map(sympify, (n, p, succ, fail))) - density = dict((k*succ + (n-k)*fail, - binomial(n, k) * p**k * (1-p)**(n-k)) for k in range(0, n+1)) - return cls.fromdict(name, density) def Binomial(name, n, p, succ=1, fail=0): """ @@ -262,32 +215,28 @@ {0: 1/16, 1: 1/4, 2: 3/8, 3: 1/4, 4: 1/16} """ - return BinomialPSpace(name, n, p, succ, fail).value + return rv(name, BinomialDistribution, n, p, succ, fail) -class HypergeometricPSpace(SingleFinitePSpace): - """ - Create a Finite Random Variable representing a hypergeometric distribution. - This class is for internal use. +class HypergeometricDistribution(SingleFiniteDistribution): + _argnames = ('N', 'm', 'n') - Create Hypergeometric Random Symbols using Hypergeometric function. + @property + @cacheit + def density(self): + N, m, n = self.N, self.m, self.n + N, m, n = list(map(sympify, (N, m, n))) + density = dict((sympify(k), + Rational(binomial(m, k) * binomial(N - m, n - k), + binomial(N, n))) + for k in range(max(0, n + m - N), min(m, n) + 1)) + return density - Examples - ======== - >>> from sympy.stats import Hypergeometric, density - >>> from sympy import S - >>> X = Hypergeometric('X', 10, 5, 3) # 10 marbles, 5 white (success), 3 draws - >>> density(X) - {0: 1/12, 1: 5/12, 2: 5/12, 3: 1/12} - """ + return dict((k, binomial(m, k) * binomial(N - m, n - k) / binomial(N, n)) + for k in range(max(0, n + m - N), min(m, n) + 1)) - def __new__(cls, name, N, m, n): - N, m, n = list(map(sympify, (N, m, n))) - density = dict((k, binomial(m, k) * binomial(N-m, n-k) / binomial(N, n)) - for k in range(max(0, n+m-N), min(m, n) + 1)) - return cls.fromdict(name, density) def Hypergeometric(name, N, m, n): """ @@ -305,5 +254,4 @@ >>> density(X) {0: 1/12, 1: 5/12, 2: 5/12, 3: 1/12} """ - - return HypergeometricPSpace(name, N, m, n).value + return rv(name, HypergeometricDistribution, N, m, n) diff -Nru python3-sympy-0.7.2/sympy/stats/rv.py python3-sympy-0.7.3/sympy/stats/rv.py --- python3-sympy-0.7.2/sympy/stats/rv.py 2012-10-17 03:02:22.000000000 +0000 +++ python3-sympy-0.7.3/sympy/stats/rv.py 2013-07-13 17:53:32.000000000 +0000 @@ -12,10 +12,13 @@ sympy.stats.rv_interface """ -from sympy import Basic, S, Expr, Symbol, Tuple, And, Add, Eq, lambdify +from sympy import (Basic, S, Expr, Symbol, Tuple, And, Add, Eq, lambdify, + sympify, Equality, solve, Lambda, DiracDelta) from sympy.core.sets import FiniteSet, ProductSet +from sympy.abc import x from functools import reduce + class RandomDomain(Basic): """ Represents a set of variables and the values which they can take @@ -48,6 +51,7 @@ def integrate(self, expr): raise NotImplementedError() + class SingleDomain(RandomDomain): """ A single variable and its domain @@ -59,19 +63,23 @@ """ def __new__(cls, symbol, set): assert symbol.is_Symbol - symbols = FiniteSet(symbol) - return RandomDomain.__new__(cls, symbols, set) + return Basic.__new__(cls, symbol, set) @property def symbol(self): - return tuple(self.symbols)[0] + return self.args[0] + + @property + def symbols(self): + return FiniteSet(self.symbol) def __contains__(self, other): - if len(other)!=1: + if len(other) != 1: return False sym, val = tuple(other)[0] return self.symbol == sym and val in self.set + class ConditionalDomain(RandomDomain): """ A RandomDomain with an attached condition @@ -82,18 +90,21 @@ sympy.stats.frv.ConditionalFiniteDomain """ def __new__(cls, fulldomain, condition): - condition = condition.subs(dict((rs,rs.symbol) + condition = condition.xreplace(dict((rs, rs.symbol) for rs in random_symbols(condition))) - return RandomDomain.__new__( - cls, fulldomain.symbols, fulldomain, condition) + return Basic.__new__(cls, fulldomain, condition) + + @property + def symbols(self): + return self.fulldomain.symbols @property def fulldomain(self): - return self.args[1] + return self.args[0] @property def condition(self): - return self.args[2] + return self.args[1] @property def set(self): @@ -102,6 +113,7 @@ def as_boolean(self): return And(self.fulldomain.as_boolean(), self.condition) + class PSpace(Basic): """ A Probability Space @@ -150,17 +162,37 @@ def integrate(self, expr): raise NotImplementedError() + class SinglePSpace(PSpace): """ Represents the probabilities of a set of random events that can be attributed to a single variable/symbol. """ + def __new__(cls, s, distribution): + if isinstance(s, str): + s = Symbol(s) + if not isinstance(s, Symbol): + raise TypeError("s should have been string or Symbol") + return Basic.__new__(cls, s, distribution) @property def value(self): - return tuple(self.values)[0] + return RandomSymbol(self, self.symbol) + + @property + def symbol(self): + return self.args[0] + + @property + def distribution(self): + return self.args[1] -class RandomSymbol(Symbol): + @property + def pdf(self): + return self.distribution.pdf(self.symbol) + + +class RandomSymbol(Expr): """ Random Symbols represent ProbabilitySpaces in SymPy Expressions In principle they can take on any value that their symbol can take on @@ -186,18 +218,21 @@ convenience functions Normal, Exponential, Coin, Die, FiniteRV, etc.... """ - is_bounded=True - is_finite=True - - def __new__(cls, *args): - obj = Basic.__new__(cls) - obj.pspace = args[0] - obj.symbol = args[1] - return obj - - @property - def name(self): - return self.symbol.name + def __new__(cls, pspace, symbol): + assert isinstance(symbol, Symbol) + assert isinstance(pspace, PSpace) + return Basic.__new__(cls, pspace, symbol) + + is_bounded = True + is_finite = True + is_Symbol = True + is_Atom = True + + _diff_wrt = True + + pspace = property(lambda self: self.args[0]) + symbol = property(lambda self: self.args[1]) + name = property(lambda self: self.symbol.name) @property def is_commutative(self): @@ -206,6 +241,11 @@ def _hashable_content(self): return self.pspace, self.symbol + @property + def free_symbols(self): + return set([self]) + + class ProductPSpace(PSpace): """ A probability space resulting from the merger of two independent probability @@ -233,14 +273,25 @@ from sympy.stats.crv import ProductContinuousPSpace cls = ProductContinuousPSpace - obj = Basic.__new__(cls, symbols, FiniteSet(*spaces)) - obj.rs_space_dict = rs_space_dict + obj = Basic.__new__(cls, *FiniteSet(*spaces)) return obj @property + def rs_space_dict(self): + d = {} + for space in self.spaces: + for value in space.values: + d[value] = space + return d + + @property + def symbols(self): + return FiniteSet(val.symbol for val in list(self.rs_space_dict.keys())) + + @property def spaces(self): - return self.args[1] + return FiniteSet(*self.args) @property def values(self): @@ -262,8 +313,9 @@ raise NotImplementedError("Density not available for ProductSpaces") def sample(self): - return dict([(k,v) for space in self.spaces - for k,v in list(space.sample().items())]) + return dict([(k, v) for space in self.spaces + for k, v in list(space.sample().items())]) + class ProductDomain(RandomDomain): """ @@ -288,11 +340,6 @@ domains2.extend(domain.domains) domains2 = FiniteSet(domains2) - sym_domain_dict = {} - for domain in domains2: - for symbol in domain.symbols: - sym_domain_dict[symbol] = domain - if all(domain.is_Finite for domain in domains2): from sympy.stats.frv import ProductFiniteDomain cls = ProductFiniteDomain @@ -300,13 +347,21 @@ from sympy.stats.crv import ProductContinuousDomain cls = ProductContinuousDomain - obj = RandomDomain.__new__(cls, symbols, domains2) - obj.sym_domain_dict = sym_domain_dict - return obj + return Basic.__new__(cls, *domains2) + + @property + def sym_domain_dict(self): + return dict((symbol, domain) for domain in self.domains + for symbol in domain.symbols) + + @property + def symbols(self): + return FiniteSet(sym for domain in self.domains + for sym in domain.symbols) @property def domains(self): - return self.args[1] + return self.args @property def set(self): @@ -327,6 +382,7 @@ def as_boolean(self): return And(*[domain.as_boolean() for domain in self.domains]) + def random_symbols(expr): """ Returns all RandomSymbols within a SymPy Expression. @@ -336,6 +392,7 @@ except AttributeError: return [] + def pspace(expr): """ Returns the underlying Probability Space of a random expression. @@ -361,30 +418,33 @@ # Otherwise make a product space return ProductPSpace(*[rv.pspace for rv in rvs]) + def sumsets(sets): """ Union of sets """ return reduce(frozenset.union, sets, frozenset()) -def rs_swap(a,b): + +def rs_swap(a, b): """ Build a dictionary to swap RandomSymbols based on their underlying symbol. i.e. - if X = ('x', pspace1) - and Y = ('x', pspace2) - then X and Y match and the key, value pair - {X:Y} will appear in the result + if ``X = ('x', pspace1)`` + and ``Y = ('x', pspace2)`` + then ``X`` and ``Y`` match and the key, value pair + ``{X:Y}`` will appear in the result Inputs: collections a and b of random variables which share common symbols Output: dict mapping RVs in a to RVs in b """ d = {} for rsa in a: - d[rsa] = [rsb for rsb in b if rsa.symbol==rsb.symbol][0] + d[rsa] = [rsb for rsb in b if rsa.symbol == rsb.symbol][0] return d + def given(expr, condition=None, **kwargs): """ From a random expression and a condition on that expression creates a new @@ -404,6 +464,13 @@ if not random_symbols(condition) or pspace_independent(expr, condition): return expr + condsymbols = random_symbols(condition) + if (isinstance(condition, Equality) and len(condsymbols) == 1 and + not isinstance(pspace(expr).domain, ConditionalDomain)): + rv = tuple(condsymbols)[0] + results = solve(condition, rv) + return sum(expr.subs(rv, res) for res in results) + # Get full probability space of both the expression and the condition fullspace = pspace(Tuple(expr, condition)) # Build new space given the condition @@ -412,9 +479,10 @@ # That point to the new conditional space swapdict = rs_swap(fullspace.values, space.values) # Swap random variables in the expression - expr = expr.subs(swapdict) + expr = expr.xreplace(swapdict) return expr + def expectation(expr, condition=None, numsamples=None, **kwargs): """ Returns the expected value of a random expression @@ -446,24 +514,25 @@ 5 """ - if not random_symbols(expr): # expr isn't random? + if not random_symbols(expr): # expr isn't random? return expr - if numsamples: # Computing by monte carlo sampling? + if numsamples: # Computing by monte carlo sampling? return sampling_E(expr, condition, numsamples=numsamples, **kwargs) # Create new expr and recompute E - if condition is not None: # If there is a condition + if condition is not None: # If there is a condition return expectation(given(expr, condition, **kwargs), **kwargs) # A few known statements for efficiency - if expr.is_Add: # We know that E is Linear + if expr.is_Add: # We know that E is Linear return Add(*[expectation(arg, **kwargs) for arg in expr.args]) # Otherwise case is simple, pass work off to the ProbabilitySpace return pspace(expr).integrate(expr, **kwargs) -def probability(condition, given_condition=None, numsamples=None, **kwargs): + +def probability(condition, given_condition=None, numsamples=None, **kwargs): """ Probability that a condition is true, optionally given a second condition @@ -497,13 +566,34 @@ if numsamples: return sampling_P(condition, given_condition, numsamples=numsamples, **kwargs) - if given_condition is not None: # If there is a condition + if given_condition is not None: # If there is a condition # Recompute on new conditional expr - return probability(given(condition, given_condition, **kwargs),**kwargs) + return probability(given(condition, given_condition, **kwargs), **kwargs) # Otherwise pass work off to the ProbabilitySpace return pspace(condition).probability(condition, **kwargs) + +class Density(Basic): + expr = property(lambda self: self.args[0]) + + @property + def condition(self): + if len(self.args) > 1: + return self.args[1] + else: + return None + + def doit(self, **kwargs): + expr, condition = self.expr, self.condition + if condition is not None: + # Recompute on new conditional expr + expr = given(expr, condition, **kwargs) + if not random_symbols(expr): + return Lambda(x, DiracDelta(x-expr)) + return pspace(expr).compute_density(expr, **kwargs) + + def density(expr, condition=None, **kwargs): """ Probability density of a random expression @@ -529,14 +619,10 @@ >>> density(2*D) {2: 1/6, 4: 1/6, 6: 1/6, 8: 1/6, 10: 1/6, 12: 1/6} >>> density(X) - Lambda(_x, sqrt(2)*exp(-_x**2/2)/(2*sqrt(pi))) + Lambda(x, sqrt(2)*exp(-x**2/2)/(2*sqrt(pi))) """ - if condition is not None: # If there is a condition - # Recompute on new conditional expr - return density(given(expr, condition, **kwargs), **kwargs) + return Density(expr, condition).doit(**kwargs) - # Otherwise pass work off to the ProbabilitySpace - return pspace(expr).compute_density(expr, **kwargs) def cdf(expr, condition=None, **kwargs): """ @@ -568,13 +654,14 @@ >>> cdf(X) Lambda(_z, erf(sqrt(2)*_z/2)/2 + 1/2) """ - if condition is not None: # If there is a condition + if condition is not None: # If there is a condition # Recompute on new conditional expr return cdf(given(expr, condition, **kwargs), **kwargs) # Otherwise pass work off to the ProbabilitySpace return pspace(expr).compute_cdf(expr, **kwargs) + def where(condition, given_condition=None, **kwargs): """ Returns the domain where a condition is True. @@ -598,13 +685,14 @@ >>> where(And(D1<=D2 , D2<3)) Domain: Or(And(a == 1, b == 1), And(a == 1, b == 2), And(a == 2, b == 2)) """ - if given_condition is not None: # If there is a condition + if given_condition is not None: # If there is a condition # Recompute on new conditional expr return where(given(condition, given_condition, **kwargs), **kwargs) # Otherwise pass work off to the ProbabilitySpace return pspace(condition).where(condition, **kwargs) + def sample(expr, condition=None, **kwargs): """ A realization of the random expression @@ -619,6 +707,7 @@ """ return next(sample_iter(expr, condition, numsamples=1)) + def sample_iter(expr, condition=None, numsamples=S.Infinity, **kwargs): """ Returns an iterator of realizations from the expression given a condition @@ -651,6 +740,7 @@ except TypeError: return sample_iter_subs(expr, condition, numsamples, **kwargs) + def sample_iter_lambdify(expr, condition=None, numsamples=S.Infinity, **kwargs): """ See sample_iter @@ -670,7 +760,7 @@ # Check that lambdify can handle the expression # Some operations like Sum can prove difficult try: - d = ps.sample() # a dictionary that maps RVs to values + d = ps.sample() # a dictionary that maps RVs to values args = [d[rv] for rv in rvs] fn(*args) if condition: @@ -681,27 +771,29 @@ def return_generator(): count = 0 while count < numsamples: - d = ps.sample() # a dictionary that maps RVs to values + d = ps.sample() # a dictionary that maps RVs to values args = [d[rv] for rv in rvs] - if condition: # Check that these values satisfy the condition + if condition: # Check that these values satisfy the condition gd = given_fn(*args) if not isinstance(gd, bool): - raise ValueError("Conditions must not contain free symbols") - if gd == False: # If the values don't satisfy then try again + raise ValueError( + "Conditions must not contain free symbols") + if gd is False: # If the values don't satisfy then try again continue yield fn(*args) count += 1 return return_generator() + def sample_iter_subs(expr, condition=None, numsamples=S.Infinity, **kwargs): """ See sample_iter Uses subs for computation. This is slow but almost always works. """ - if condition: + if condition is not None: ps = pspace(Tuple(expr, condition)) else: ps = pspace(expr) @@ -709,19 +801,20 @@ count = 0 while count < numsamples: - d = ps.sample() # a dictionary that maps RVs to values - + d = ps.sample() # a dictionary that maps RVs to values - if condition: # Check that these values satisfy the condition - gd = condition.subs(d) + if condition is not None: # Check that these values satisfy the condition + gd = condition.xreplace(d) if not isinstance(gd, bool): raise ValueError("Conditions must not contain free symbols") - if gd == False: # If the values don't satisfy then try again + if gd is False: # If the values don't satisfy then try again continue - yield expr.subs(d) + yield expr.xreplace(d) count += 1 + + def sampling_P(condition, given_condition=None, numsamples=1, evalf=True, **kwargs): """ @@ -743,7 +836,7 @@ if not isinstance(x, bool): raise ValueError("Conditions must not contain free symbols") - if x==True: + if x is True: count_true += 1 else: count_false += 1 @@ -754,6 +847,7 @@ else: return result + def sampling_E(condition, given_condition=None, numsamples=1, evalf=True, **kwargs): """ @@ -774,6 +868,7 @@ else: return result + def dependent(a, b): """ Dependence of two random expressions @@ -800,7 +895,7 @@ ======== independent """ - if pspace_independent(a,b): + if pspace_independent(a, b): return False z = Symbol('z', real=True) @@ -809,6 +904,7 @@ return (density(a, Eq(b, z)) != density(a) or density(b, Eq(a, z)) != density(b)) + def independent(a, b): """ Independence of two random expressions @@ -837,7 +933,8 @@ """ return not dependent(a, b) -def pspace_independent(a,b): + +def pspace_independent(a, b): """ Tests for independence between a and b by checking if their PSpaces have overlapping symbols. This is a sufficient but not necessary condition for @@ -852,6 +949,7 @@ return True return None + def rv_subs(expr, symbols=None): """ Given a random expression replace all random variables with their symbols. @@ -860,5 +958,26 @@ """ if symbols is None: symbols = random_symbols(expr) + if not symbols: + return expr swapdict = dict([(rv, rv.symbol) for rv in symbols]) - return expr.subs(swapdict) + return expr.xreplace(swapdict) + +class NamedArgsMixin(object): + _argnames = () + + def __getattr__(self, attr): + try: + return self.args[list(self._argnames).index(attr)] + except ValueError: + raise AttributeError("'%s' object has not attribute '%s'" % ( + type(self).__name__, attr)) + +def _value_check(condition, message): + """ + Check a condition on input value. + + Raises ValueError with message if condition is not True + """ + if condition is not True: + raise ValueError(message) diff -Nru python3-sympy-0.7.2/sympy/stats/rv_interface.py python3-sympy-0.7.3/sympy/stats/rv_interface.py --- python3-sympy-0.7.2/sympy/stats/rv_interface.py 2012-10-17 03:02:22.000000000 +0000 +++ python3-sympy-0.7.3/sympy/stats/rv_interface.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,10 +1,33 @@ from .rv import (probability, expectation, density, where, given, pspace, cdf, sample, sample_iter, random_symbols, independent, dependent) -from sympy import sqrt +from sympy import sqrt, simplify __all__ = ['P', 'E', 'density', 'where', 'given', 'sample', 'cdf', 'pspace', - 'sample_iter', 'variance', 'std', 'skewness', 'covariance', 'dependent', - 'independent', 'random_symbols'] + 'sample_iter', 'variance', 'std', 'skewness', 'covariance', + 'dependent', 'independent', 'random_symbols', 'correlation', + 'moment', 'cmoment'] + + + +def moment(X, n, c=0, condition=None, **kwargs): + """ + Return the nth moment of a random expression about c i.e. E((X-c)**n) + Default value of c is 0. + + Examples + ======== + + >>> from sympy.stats import Die, moment, E + >>> X = Die('X', 6) + >>> moment(X, 1, 6) + -5/2 + >>> moment(X, 2) + 91/6 + >>> moment(X, 1) == E(X) + True + """ + return expectation((X - c)**n, condition, **kwargs) + def variance(X, condition=None, **kwargs): """ @@ -28,8 +51,8 @@ >>> simplify(variance(B)) p*(-p + 1) """ - return (expectation(X**2, condition, **kwargs) - - expectation(X, condition, **kwargs)**2) + return cmoment(X, 2, condition, **kwargs) + def standard_deviation(X, condition=None, **kwargs): """ @@ -41,17 +64,18 @@ ======== >>> from sympy.stats import Bernoulli, std - >>> from sympy import Symbol + >>> from sympy import Symbol, simplify >>> p = Symbol('p') >>> B = Bernoulli('B', p, 1, 0) - >>> std(B) - sqrt(-p**2 + p) + >>> simplify(std(B)) + sqrt(p*(-p + 1)) """ return sqrt(variance(X, condition, **kwargs)) std = standard_deviation + def covariance(X, Y, condition=None, **kwargs): """ Covariance of two random expressions @@ -77,17 +101,109 @@ >>> covariance(X, Y + rate*X) 1/lambda """ - return expectation( - (X - expectation(X, condition, **kwargs)) * - (Y - expectation(Y, condition, **kwargs)), - condition, **kwargs) + (X - expectation(X, condition, **kwargs)) * + (Y - expectation(Y, condition, **kwargs)), + condition, **kwargs) + + +def correlation(X, Y, condition=None, **kwargs): + """ + Correlation of two random expressions, also known as correlation + coefficient or Pearson's correlation + + The normalized expectation that the two variables will rise + and fall together + + Correlation(X,Y) = E( (X-E(X)) * (Y-E(Y)) / (sigma(X) * sigma(Y)) ) + + Examples + ======== + + >>> from sympy.stats import Exponential, correlation + >>> from sympy import Symbol + + >>> rate = Symbol('lambda', positive=True, real=True, bounded = True) + >>> X = Exponential('X', rate) + >>> Y = Exponential('Y', rate) + + >>> correlation(X, X) + 1 + >>> correlation(X, Y) + 0 + >>> correlation(X, Y + rate*X) + 1/sqrt(1 + lambda**(-2)) + """ + return covariance(X, Y, condition, **kwargs)/(std(X, condition, **kwargs) + * std(Y, condition, **kwargs)) -def skewness(X, condition=None, **kwargs): +def cmoment(X, n, condition=None, **kwargs): + """ + Return the nth central moment of a random expression about its mean + i.e. E((X - E(X))**n) + + Examples + ======== + + >>> from sympy.stats import Die, cmoment, variance + >>> X = Die('X', 6) + >>> cmoment(X, 3) + 0 + >>> cmoment(X, 2) + 35/12 + >>> cmoment(X, 2) == variance(X) + True + """ mu = expectation(X, condition, **kwargs) + return moment(X, n, mu, condition, **kwargs) + + +def smoment(X, n, condition=None, **kwargs): + """ + Return the nth Standardized moment of a random expression i.e. + E( ((X - mu)/sigma(X))**n ) + + Examples + ======== + >>> from sympy.stats import skewness, Exponential, smoment + >>> from sympy import Symbol + >>> rate = Symbol('lambda', positive=True, real=True, bounded = True) + >>> Y = Exponential('Y', rate) + >>> smoment(Y, 4) + 9 + >>> smoment(Y, 4) == smoment(3*Y, 4) + True + >>> smoment(Y, 3) == skewness(Y) + True + """ sigma = std(X, condition, **kwargs) - return expectation( ((X-mu)/sigma) ** 3 , condition, **kwargs) + return (1/sigma)**n*cmoment(X, n, condition, **kwargs) + +def skewness(X, condition=None, **kwargs): + """ + Measure of the asymmetry of the probability distribution + + Positive skew indicates that most of the values lie to the right of + the mean + + skewness(X) = E( ((X - E(X))/sigma)**3 ) + + Examples + ======== + + >>> from sympy.stats import skewness, Exponential, Normal + >>> from sympy import Symbol + >>> X = Normal('X', 0, 1) + >>> skewness(X) + 0 + >>> rate = Symbol('lambda', positive=True, real=True, bounded = True) + >>> Y = Exponential('Y', rate) + >>> skewness(Y) + 2 + """ + return smoment(X, 3, condition, **kwargs) + P = probability E = expectation diff -Nru python3-sympy-0.7.2/sympy/stats/tests/test_continuous_rv.py python3-sympy-0.7.3/sympy/stats/tests/test_continuous_rv.py --- python3-sympy-0.7.2/sympy/stats/tests/test_continuous_rv.py 2012-10-17 03:02:22.000000000 +0000 +++ python3-sympy-0.7.3/sympy/stats/tests/test_continuous_rv.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,24 +1,36 @@ from sympy.stats import (P, E, where, density, variance, covariance, skewness, - given, pspace, cdf, ContinuousRV, sample) -from sympy.stats import (Arcsin, Benini, Beta, BetaPrime, Cauchy, Chi, Dagum, - Exponential, Gamma, Laplace, Logistic, LogNormal, - Maxwell, Nakagami, Normal, Pareto, Rayleigh, StudentT, - Triangular, Uniform, UniformSum, Weibull, - WignerSemicircle) + given, pspace, cdf, ContinuousRV, sample, + Arcsin, Benini, Beta, BetaPrime, Cauchy, + Chi, ChiSquared, + ChiNoncentral, Dagum, Erlang, Exponential, + FDistribution, FisherZ, Frechet, Gamma, GammaInverse, + Kumaraswamy, Laplace, Logistic, + LogNormal, Maxwell, Nakagami, Normal, Pareto, + QuadraticU, RaisedCosine, Rayleigh, StudentT, + Triangular, Uniform, UniformSum, VonMises, Weibull, + WignerSemicircle, correlation, moment, cmoment, + smoment) + from sympy import (Symbol, Dummy, Abs, exp, S, N, pi, simplify, Interval, erf, Eq, log, lowergamma, Sum, symbols, sqrt, And, gamma, beta, - Piecewise, Integral, sin, Lambda, factorial, binomial, floor) -from sympy.utilities.pytest import raises, XFAIL + Eq, log, lowergamma, Sum, symbols, sqrt, And, gamma, beta, + Piecewise, Integral, sin, cos, besseli, factorial, binomial, + floor) + + +from sympy.stats.crv_types import NormalDistribution + +from sympy.utilities.pytest import raises, XFAIL, slow oo = S.Infinity -_x = Dummy("x") -_z = Dummy("z") +x, y, z = list(map(Symbol, 'xyz')) + def test_single_normal(): mu = Symbol('mu', real=True, bounded=True) sigma = Symbol('sigma', real=True, positive=True, bounded=True) - X = Normal('x', 0,1) + X = Normal('x', 0, 1) Y = X*sigma + mu assert simplify(E(Y)) == mu @@ -32,10 +44,11 @@ assert E(X, Eq(X, mu)) == mu + @XFAIL def test_conditional_1d(): - X = Normal('x', 0,1) - Y = given(X, X>=0) + X = Normal('x', 0, 1) + Y = given(X, X >= 0) assert density(Y) == 2 * density(X) @@ -44,29 +57,42 @@ assert E(X**2) == E(Y**2) + def test_ContinuousDomain(): - X = Normal('x', 0,1) - assert where(X**2<=1).set == Interval(-1,1) - assert where(X**2<=1).symbol == X.symbol - where(And(X**2<=1, X>=0)).set == Interval(0,1) - raises(ValueError, lambda: where(sin(X)>1)) + X = Normal('x', 0, 1) + assert where(X**2 <= 1).set == Interval(-1, 1) + assert where(X**2 <= 1).symbol == X.symbol + where(And(X**2 <= 1, X >= 0)).set == Interval(0, 1) + raises(ValueError, lambda: where(sin(X) > 1)) - Y = given(X, X>=0) + Y = given(X, X >= 0) assert Y.pspace.domain.set == Interval(0, oo) + def test_multiple_normal(): - X, Y = Normal('x', 0,1), Normal('y', 0,1) + X, Y = Normal('x', 0, 1), Normal('y', 0, 1) - assert E(X+Y) == 0 - assert variance(X+Y) == 2 - assert variance(X+X) == 4 + assert E(X + Y) == 0 + assert variance(X + Y) == 2 + assert variance(X + X) == 4 assert covariance(X, Y) == 0 assert covariance(2*X + Y, -X) == -2*variance(X) + assert skewness(X) == 0 + assert skewness(X + Y) == 0 + assert correlation(X, Y) == 0 + assert correlation(X, X + Y) == correlation(X, X - Y) + assert moment(X, 2) == 1 + assert cmoment(X, 3) == 0 + assert moment(X + Y, 4) == 12 + assert cmoment(X, 2) == variance(X) + assert smoment(X*X, 2) == 1 + assert smoment(X + Y, 3) == skewness(X + Y) + assert E(X, Eq(X + Y, 0)) == 0 + assert variance(X, Eq(X + Y, 0)) == S.Half - assert E(X, Eq(X+Y, 0)) == 0 - assert variance(X, Eq(X+Y, 0)) == S.Half +@slow def test_symbolic(): mu1, mu2 = symbols('mu1 mu2', real=True, bounded=True) s1, s2 = symbols('sigma1 sigma2', real=True, bounded=True, positive=True) @@ -77,23 +103,24 @@ a, b, c = symbols('a b c', real=True, bounded=True) assert E(X) == mu1 - assert E(X+Y) == mu1+mu2 - assert E(a*X+b) == a*E(X)+b + assert E(X + Y) == mu1 + mu2 + assert E(a*X + b) == a*E(X) + b assert variance(X) == s1**2 - assert simplify(variance(X+a*Y+b)) == variance(X) + a**2*variance(Y) + assert simplify(variance(X + a*Y + b)) == variance(X) + a**2*variance(Y) assert E(Z) == 1/rate - assert E(a*Z+b) == a*E(Z)+b - assert E(X+a*Z+b) == mu1 + a/rate + b + assert E(a*Z + b) == a*E(Z) + b + assert E(X + a*Z + b) == mu1 + a/rate + b + def test_cdf(): - X = Normal('x', 0,1) + X = Normal('x', 0, 1) d = cdf(X) - assert P(X<1) == d(1) + assert P(X < 1) == d(1) assert d(0) == S.Half - d = cdf(X, X>0) # given X>0 + d = cdf(X, X > 0) # given X>0 assert d(0) == 0 Y = Exponential('y', 10) @@ -101,29 +128,31 @@ assert d(-5) == 0 assert P(Y > 3) == 1 - d(3) - raises(ValueError, lambda: cdf(X+Y)) + raises(ValueError, lambda: cdf(X + Y)) Z = Exponential('z', 1) f = cdf(Z) z = Symbol('z') assert f(z) == Piecewise((1 - exp(-z), z >= 0), (0, True)) + def test_sample(): z = Symbol('z') - Z = ContinuousRV(z, exp(-z), set=Interval(0,oo)) + Z = ContinuousRV(z, exp(-z), set=Interval(0, oo)) assert sample(Z) in Z.pspace.domain.set sym, val = list(Z.pspace.sample().items())[0] assert sym == Z and val in Interval(0, oo) + def test_ContinuousRV(): x = Symbol('x') - pdf = sqrt(2)*exp(-x**2/2)/(2*sqrt(pi)) # Normal distribution + pdf = sqrt(2)*exp(-x**2/2)/(2*sqrt(pi)) # Normal distribution # X and Y should be equivalent X = ContinuousRV(x, pdf) Y = Normal('y', 0, 1) assert variance(X) == variance(Y) - assert P(X>0) == P(Y>0) + assert P(X > 0) == P(Y > 0) def test_arcsin(): @@ -131,7 +160,7 @@ b = Symbol("b", real=True) X = Arcsin('x', a, b) - assert density(X) == Lambda(_x, 1/(pi*sqrt((-_x + b)*(_x - a)))) + assert density(X)(x) == 1/(pi*sqrt((-x + b)*(x - a))) def test_benini(): @@ -140,8 +169,8 @@ sigma = Symbol("sigma", positive=True) X = Benini('x', alpha, b, sigma) - assert density(X) == (Lambda(_x, (alpha/_x + 2*b*log(_x/sigma)/_x) - *exp(-alpha*log(_x/sigma) - b*log(_x/sigma)**2))) + assert density(X)(x) == ((alpha/x + 2*b*log(x/sigma)/x) + *exp(-alpha*log(x/sigma) - b*log(x/sigma)**2)) def test_beta(): @@ -153,7 +182,7 @@ dens = density(B) x = Symbol('x') - assert dens(x) == x**(a-1)*(1-x)**(b-1) / beta(a,b) + assert dens(x) == x**(a - 1)*(1 - x)**(b - 1) / beta(a, b) # This is too slow # assert E(B) == a / (a + b) @@ -163,7 +192,7 @@ a, b = 1, 2 B = Beta('x', a, b) assert E(B) == a / S(a + b) - assert variance(B) == (a*b) / S((a+b)**2 * (a+b+1)) + assert variance(B) == (a*b) / S((a + b)**2 * (a + b + 1)) def test_betaprime(): @@ -171,8 +200,8 @@ beta = Symbol("beta", positive=True) X = BetaPrime('x', alpha, beta) - assert density(X) == (Lambda(_x, _x**(alpha - 1)*(_x + 1)**(-alpha - beta) - *gamma(alpha + beta)/(gamma(alpha)*gamma(beta)))) + assert density(X)(x) == (x**(alpha - 1)*(x + 1)**(-alpha - beta) + *gamma(alpha + beta)/(gamma(alpha)*gamma(beta))) def test_cauchy(): @@ -180,16 +209,28 @@ gamma = Symbol("gamma", positive=True) X = Cauchy('x', x0, gamma) - assert density(X) == Lambda(_x, 1/(pi*gamma*(1 + (_x - x0)**2/gamma**2))) + assert density(X)(x) == 1/(pi*gamma*(1 + (x - x0)**2/gamma**2)) def test_chi(): k = Symbol("k", integer=True) X = Chi('x', k) - assert density(X) == (Lambda(_x, 2**(-k/2 + 1)*_x**(k - 1) - *exp(-_x**2/2)/gamma(k/2))) + assert density(X)(x) == 2**(-k/2 + 1)*x**(k - 1)*exp(-x**2/2)/gamma(k/2) +def test_chi_noncentral(): + k = Symbol("k", integer=True) + l = Symbol("l") + + X = ChiNoncentral("x", k, l) + assert density(X)(x) == (x**k*l*(x*l)**(-k/2)* + exp(-x**2/2 - l**2/2)*besseli(k/2 - 1, x*l)) + +def test_chi_squared(): + k = Symbol("k", integer=True) + + X = ChiSquared('x', k) + assert density(X)(x) == 2**(-k/2)*x**(k/2 - 1)*exp(-x/2)/gamma(k/2) def test_dagum(): p = Symbol("p", positive=True) @@ -197,9 +238,14 @@ a = Symbol("a", positive=True) X = Dagum('x', p, a, b) - assert density(X) == Lambda(_x, - a*p*(_x/b)**(a*p)*((_x/b)**a + 1)**(-p - 1)/_x) + assert density(X)(x) == a*p*(x/b)**(a*p)*((x/b)**a + 1)**(-p - 1)/x + +def test_erlang(): + k = Symbol("k", integer=True, positive=True) + l = Symbol("l", positive=True) + X = Erlang("x", k, l) + assert density(X)(x) == x**(k - 1)*l**k*exp(-x*l)/gamma(k) def test_exponential(): rate = Symbol('lambda', positive=True, real=True, bounded=True) @@ -208,50 +254,88 @@ assert E(X) == 1/rate assert variance(X) == 1/rate**2 assert skewness(X) == 2 - assert P(X>0) == S(1) - assert P(X>1) == exp(-rate) - assert P(X>10) == exp(-10*rate) + assert skewness(X) == smoment(X, 3) + assert smoment(2*X, 4) == smoment(X, 4) + assert moment(X, 3) == 3*2*1/rate**3 + assert P(X > 0) == S(1) + assert P(X > 1) == exp(-rate) + assert P(X > 10) == exp(-10*rate) + + assert where(X <= 1).set == Interval(0, 1) + +def test_f_distribution(): + d1 = Symbol("d1", positive=True) + d2 = Symbol("d2", positive=True) + + X = FDistribution("x", d1, d2) + assert density(X)(x) == (d2**(d2/2)*sqrt((x*d1)**d1 * + (x*d1 + d2)**(-d1 - d2))*gamma(d1/2 + d2/2)/(x*gamma(d1/2)*gamma(d2/2))) + +def test_fisher_z(): + d1 = Symbol("d1", positive=True) + d2 = Symbol("d2", positive=True) + + X = FisherZ("x", d1, d2) + assert density(X)(x) == (2*d1**(d1/2)*d2**(d2/2)* + (d1*exp(2*x) + d2)**(-d1/2 - d2/2)* + exp(x*d1)*gamma(d1/2 + d2/2)/(gamma(d1/2)*gamma(d2/2))) - assert where(X<=1).set == Interval(0,1) +def test_frechet(): + a = Symbol("a", positive=True) + s = Symbol("s", positive=True) + m = Symbol("m", real=True) + X = Frechet("x", a, s=s, m=m) + assert density(X)(x) == a*((x - m)/s)**(-a - 1)*exp(-((x - m)/s)**(-a))/s def test_gamma(): k = Symbol("k", positive=True) theta = Symbol("theta", positive=True) X = Gamma('x', k, theta) - assert density(X) == Lambda(_x, - _x**(k - 1)*theta**(-k)*exp(-_x/theta)/gamma(k)) - assert cdf(X, meijerg=True) == Lambda(_z, Piecewise( - (-k*lowergamma(k, 0)/gamma(k + 1) + k*lowergamma(k, _z/theta)/gamma(k + 1), _z >= 0), (0, True))) - assert variance(X) == (-theta**2*gamma(k + 1)**2/gamma(k)**2 + - theta*theta**(-k)*theta**(k + 1)*gamma(k + 2)/gamma(k)) + assert density(X)(x) == x**(k - 1)*theta**(-k)*exp(-x/theta)/gamma(k) + assert cdf(X, meijerg=True)(z) == Piecewise( + (-k*lowergamma(k, 0)/gamma(k + 1) + + k*lowergamma(k, z/theta)/gamma(k + 1), z >= 0), + (0, True)) + # assert simplify(variance(X)) == k*theta**2 # handled numerically below + assert E(X) == moment(X, 1) k, theta = symbols('k theta', real=True, bounded=True, positive=True) X = Gamma('x', k, theta) assert simplify(E(X)) == k*theta # can't get things to simplify on this one so we use subs - assert variance(X).subs(k,5) == (k*theta**2).subs(k, 5) + assert variance(X).subs(k, 5) == (k*theta**2).subs(k, 5) # The following is too slow # assert simplify(skewness(X)).subs(k, 5) == (2/sqrt(k)).subs(k, 5) +def test_gamma_inverse(): + a = Symbol("a", positive=True) + b = Symbol("b", positive=True) + + X = GammaInverse("x", a, b) + assert density(X)(x) == x**(-a - 1)*b**a*exp(-b/x)/gamma(a) + +def test_kumaraswamy(): + a = Symbol("a", positive=True) + b = Symbol("b", positive=True) + + X = Kumaraswamy("x", a, b) + assert density(X)(x) == x**(a - 1)*a*b*(-x**a + 1)**(b - 1) def test_laplace(): mu = Symbol("mu") b = Symbol("b", positive=True) X = Laplace('x', mu, b) - assert density(X) == Lambda(_x, exp(-Abs(_x - mu)/b)/(2*b)) - + assert density(X)(x) == exp(-Abs(x - mu)/b)/(2*b) def test_logistic(): mu = Symbol("mu", real=True) s = Symbol("s", positive=True) X = Logistic('x', mu, s) - assert density(X) == Lambda(_x, - exp((-_x + mu)/s)/(s*(exp((-_x + mu)/s) + 1)**2)) - + assert density(X)(x) == exp((-x + mu)/s)/(s*(exp((-x + mu)/s) + 1)**2) def test_lognormal(): mean = Symbol('mu', real=True, bounded=True) @@ -273,35 +357,35 @@ sigma = Symbol("sigma", positive=True) X = LogNormal('x', mu, sigma) - assert density(X) == (Lambda(_x, sqrt(2)*exp(-(-mu + log(_x))**2 - /(2*sigma**2))/(2*_x*sqrt(pi)*sigma))) - - X = LogNormal('x', 0, 1) # Mean 0, standard deviation 1 - assert density(X) == Lambda(_x, sqrt(2)*exp(-log(_x)**2/2)/(2*_x*sqrt(pi))) + assert density(X)(x) == (sqrt(2)*exp(-(-mu + log(x))**2 + /(2*sigma**2))/(2*x*sqrt(pi)*sigma)) + X = LogNormal('x', 0, 1) # Mean 0, standard deviation 1 + assert density(X)(x) == sqrt(2)*exp(-log(x)**2/2)/(2*x*sqrt(pi)) def test_maxwell(): a = Symbol("a", positive=True) X = Maxwell('x', a) - assert density(X) == (Lambda(_x, sqrt(2)*_x**2*exp(-_x**2/(2*a**2))/ - (sqrt(pi)*a**3))) + assert density(X)(x) == (sqrt(2)*x**2*exp(-x**2/(2*a**2))/ + (sqrt(pi)*a**3)) assert E(X) == 2*sqrt(2)*a/sqrt(pi) assert simplify(variance(X)) == a**2*(-8 + 3*pi)/pi + def test_nakagami(): mu = Symbol("mu", positive=True) omega = Symbol("omega", positive=True) X = Nakagami('x', mu, omega) - assert density(X) == (Lambda(_x, 2*_x**(2*mu - 1)*mu**mu*omega**(-mu) - *exp(-_x**2*mu/omega)/gamma(mu))) + assert density(X)(x) == (2*x**(2*mu - 1)*mu**mu*omega**(-mu) + *exp(-x**2*mu/omega)/gamma(mu)) assert simplify(E(X, meijerg=True)) == (sqrt(mu)*sqrt(omega) *gamma(mu + S.Half)/gamma(mu + 1)) - assert (simplify(variance(X, meijerg=True)) == - (omega*(gamma(mu)*gamma(mu + 1) - - gamma(mu + S.Half)**2)/(gamma(mu)*gamma(mu + 1)))) + assert simplify(variance(X, meijerg=True)) == ( + omega - omega*gamma(mu + S(1)/2)**2/(gamma(mu)*gamma(mu + 1))) + def test_pareto(): xm, beta = symbols('xm beta', positive=True, bounded=True) @@ -310,35 +394,48 @@ dens = density(X) x = Symbol('x') - assert dens(x) == x**(-(alpha+1))*xm**(alpha)*(alpha) + assert dens(x) == x**(-(alpha + 1))*xm**(alpha)*(alpha) # These fail because SymPy can not deduce that 1/xm != 0 # assert simplify(E(X)) == alpha*xm/(alpha-1) # assert simplify(variance(X)) == xm**2*alpha / ((alpha-1)**2*(alpha-2)) + def test_pareto_numeric(): xm, beta = 3, 2 alpha = beta + 5 X = Pareto('x', xm, alpha) - assert E(X) == alpha*xm/S(alpha-1) - assert variance(X) == xm**2*alpha / S(((alpha-1)**2*(alpha-2))) + assert E(X) == alpha*xm/S(alpha - 1) + assert variance(X) == xm**2*alpha / S(((alpha - 1)**2*(alpha - 2))) # Skewness tests too slow. Try shortcutting function? + +def test_raised_cosine(): + mu = Symbol("mu", real=True) + s = Symbol("s", positive=True) + + X = RaisedCosine("x", mu, s) + assert density(X)(x) == (Piecewise(((cos(pi*(x - mu)/s) + 1)/(2*s), + And(x <= mu + s, mu - s <= x)), (0, True))) + + def test_rayleigh(): sigma = Symbol("sigma", positive=True) X = Rayleigh('x', sigma) - assert density(X) == Lambda(_x, _x*exp(-_x**2/(2*sigma**2))/sigma**2) + assert density(X)(x) == x*exp(-x**2/(2*sigma**2))/sigma**2 assert E(X) == sqrt(2)*sqrt(pi)*sigma/2 assert variance(X) == -pi*sigma**2/2 + 2*sigma**2 + def test_studentt(): nu = Symbol("nu", positive=True) X = StudentT('x', nu) - assert density(X) == (Lambda(_x, (_x**2/nu + 1)**(-nu/2 - S.Half) - *gamma(nu/2 + S.Half)/(sqrt(pi)*sqrt(nu)*gamma(nu/2)))) + assert density(X)(x) == ((x**2/nu + 1)**(-nu/2 - S.Half) + *gamma(nu/2 + S.Half)/(sqrt(pi)*sqrt(nu)*gamma(nu/2))) + @XFAIL def test_triangular(): @@ -346,27 +443,36 @@ b = Symbol("b") c = Symbol("c") - X = Triangular('x', a,b,c) - assert Density(X) == Lambda(_x, - Piecewise(((2*_x - 2*a)/((-a + b)*(-a + c)), And(a <= _x, _x < c)), - (2/(-a + b), _x == c), - ((-2*_x + 2*b)/((-a + b)*(b - c)), And(_x <= b, c < _x)), - (0, True))) + X = Triangular('x', a, b, c) + assert density(X)(x) == Piecewise( + ((2*x - 2*a)/((-a + b)*(-a + c)), And(a <= x, x < c)), + (2/(-a + b), x == c), + ((-2*x + 2*b)/((-a + b)*(b - c)), And(x <= b, c < x)), + (0, True)) + + +def test_quadratic_u(): + a = Symbol("a", real=True) + b = Symbol("b", real=True) + + X = QuadraticU("x", a, b) + assert density(X)(x) == (Piecewise((12*(x - a/2 - b/2)**2/(-a + b)**3, + And(x <= b, a <= x)), (0, True))) def test_uniform(): l = Symbol('l', real=True, bounded=True) w = Symbol('w', positive=True, bounded=True) - X = Uniform('x', l, l+w) + X = Uniform('x', l, l + w) assert simplify(E(X)) == l + w/2 assert simplify(variance(X)) == w**2/12 - assert P(Xl+w) == 0 + assert P(X < l) == 0 and P(X > l + w) == 0 # With numbers all is well X = Uniform('x', 3, 5) - assert P(X<3) == 0 and P(X>5) == 0 - assert P(X<4) == P(X>4) == S.Half + assert P(X < 3) == 0 and P(X > 5) == 0 + assert P(X < 4) == P(X > 4) == S.Half @XFAIL @@ -375,8 +481,17 @@ _k = Symbol("k") X = UniformSum('x', n) - assert density(X) == (Lambda(_x, Sum((-1)**_k*(-_k + _x)**(n - 1) - *binomial(n, _k), (_k, 0, floor(_x)))/factorial(n - 1))) + assert density(X)(x) == (Sum((-1)**_k*(-_k + x)**(n - 1) + *binomial(n, _k), (_k, 0, floor(x)))/factorial(n - 1)) + + +def test_von_mises(): + mu = Symbol("mu") + k = Symbol("k", positive=True) + + X = VonMises("x", mu, k) + assert density(X)(x) == exp(k*cos(x - mu))/(2*pi*besseli(0, k)) + def test_weibull(): a, b = symbols('a b', positive=True) @@ -386,6 +501,7 @@ assert simplify(variance(X)) == simplify(a**2 * gamma(1 + 2/b) - E(X)**2) # Skewness tests too slow. Try shortcutting function? + def test_weibull_numeric(): # Test for integers and rationals a = 1 @@ -394,16 +510,18 @@ X = Weibull('x', a, b) assert simplify(E(X)) == simplify(a * gamma(1 + 1/S(b))) assert simplify(variance(X)) == simplify( - a**2 * gamma(1 + 2/S(b)) - E(X)**2) + a**2 * gamma(1 + 2/S(b)) - E(X)**2) # Not testing Skew... it's slow with int/frac values > 3/2 + def test_wignersemicircle(): R = Symbol("R", positive=True) X = WignerSemicircle('x', R) - assert density(X) == Lambda(_x, 2*sqrt(-_x**2 + R**2)/(pi*R**2)) + assert density(X)(x) == 2*sqrt(-x**2 + R**2)/(pi*R**2) assert E(X) == 0 + def test_prefab_sampling(): N = Normal('X', 0, 1) L = LogNormal('L', 0, 1) @@ -414,43 +532,79 @@ B = Beta('B', 2, 5) G = Gamma('G', 1, 3) - variables = [N,L,E,P,W,U,B,G] + variables = [N, L, E, P, W, U, B, G] niter = 10 for var in variables: for i in range(niter): assert sample(var) in var.pspace.domain.set + def test_input_value_assertions(): a, b = symbols('a b') p, q = symbols('p q', positive=True) raises(ValueError, lambda: Normal('x', 3, 0)) raises(ValueError, lambda: Normal('x', a, b)) - Normal('X', a, p) # No error raised + Normal('X', a, p) # No error raised raises(ValueError, lambda: Exponential('x', a)) - Exponential('Ex', p) # No error raised + Exponential('Ex', p) # No error raised for fn in [Pareto, Weibull, Beta, Gamma]: raises(ValueError, lambda: fn('x', a, p)) raises(ValueError, lambda: fn('x', p, a)) - fn('x', p, q) # No error raised + fn('x', p, q) # No error raised + @XFAIL def test_unevaluated(): - X = Normal('x', 0,1) + X = Normal('x', 0, 1) assert E(X, evaluate=False) == ( - Integral(sqrt(2)*x*exp(-x**2/2)/(2*sqrt(pi)), (x, -oo, oo))) + Integral(sqrt(2)*x*exp(-x**2/2)/(2*sqrt(pi)), (x, -oo, oo))) - assert E(X+1, evaluate=False) == ( - Integral(sqrt(2)*x*exp(-x**2/2)/(2*sqrt(pi)), (x, -oo, oo)) + 1) + assert E(X + 1, evaluate=False) == ( + Integral(sqrt(2)*x*exp(-x**2/2)/(2*sqrt(pi)), (x, -oo, oo)) + 1) - assert P(X>0, evaluate=False) == ( - Integral(sqrt(2)*exp(-x**2/2)/(2*sqrt(pi)), (x, 0, oo))) + assert P(X > 0, evaluate=False) == ( + Integral(sqrt(2)*exp(-x**2/2)/(2*sqrt(pi)), (x, 0, oo))) - assert P(X>0, X**2<1, evaluate=False) == ( - Integral(sqrt(2)*exp(-x**2/2)/(2*sqrt(pi)* + assert P(X > 0, X**2 < 1, evaluate=False) == ( + Integral(sqrt(2)*exp(-x**2/2)/(2*sqrt(pi)* Integral(sqrt(2)*exp(-x**2/2)/(2*sqrt(pi)), (x, -1, 1))), (x, 0, 1))) + def test_probability_unevaluated(): - T = Normal('T', 30, 3) - assert type(P(T>33, evaluate=False)) == Integral + T = Normal('T', 30, 3) + assert type(P(T > 33, evaluate=False)) == Integral + +def test_density_unevaluated(): + X = Normal('X', 0, 1) + Y = Normal('Y', 0, 2) + assert isinstance(density(X+Y, evaluate=False)(z), Integral) + + +def test_NormalDistribution(): + nd = NormalDistribution(0, 1) + x = Symbol('x') + assert nd.cdf(x) == erf(sqrt(2)*x/2)/2 + S.One/2 + assert isinstance(nd.sample(), float) or nd.sample().is_Number + assert nd.expectation(1, x) == 1 + assert nd.expectation(x, x) == 0 + assert nd.expectation(x**2, x) == 1 + +def test_random_parameters(): + mu = Normal('mu', 2, 3) + meas = Normal('T', mu, 1) + assert density(meas, evaluate=False)(z) + #assert density(meas, evaluate=False)(z) == Integral(mu.pspace.pdf * + # meas.pspace.pdf, (mu.symbol, -oo, oo)).subs(meas.symbol, z) + +def test_random_parameters_given(): + mu = Normal('mu', 2, 3) + meas = Normal('T', mu, 1) + assert given(meas, Eq(mu, 5)) == Normal('T', 5, 1) + +def test_conjugate_priors(): + mu = Normal('mu', 2, 3) + x = Normal('x', mu, 1) + assert isinstance(simplify(density(mu, Eq(x, y), evaluate=False)(z)), + Integral) diff -Nru python3-sympy-0.7.2/sympy/stats/tests/test_discrete_rv.py python3-sympy-0.7.3/sympy/stats/tests/test_discrete_rv.py --- python3-sympy-0.7.2/sympy/stats/tests/test_discrete_rv.py 1970-01-01 00:00:00.000000000 +0000 +++ python3-sympy-0.7.3/sympy/stats/tests/test_discrete_rv.py 2013-07-13 17:53:32.000000000 +0000 @@ -0,0 +1,28 @@ +from sympy.stats.drv_types import (PoissonDistribution, GeometricDistribution, + Poisson) +from sympy.abc import x +from sympy import S, Sum +from sympy.stats import E, variance, density + +def test_PoissonDistribution(): + l = 3 + p = PoissonDistribution(l) + assert abs(p.cdf(10).evalf() - 1) < .001 + assert p.expectation(x, x) == l + assert p.expectation(x**2, x) - p.expectation(x, x)**2 == l + +def test_Poisson(): + l = 3 + x = Poisson('x', l) + assert E(x) == l + assert variance(x) == l + assert density(x) == PoissonDistribution(l) + assert isinstance(E(x, evaluate=False), Sum) + assert isinstance(E(2*x, evaluate=False), Sum) + +def test_GeometricDistribution(): + p = S.One / 5 + d = GeometricDistribution(p) + assert d.expectation(x, x) == 1/p + assert d.expectation(x**2, x) - d.expectation(x, x)**2 == (1-p)/p**2 + assert abs(d.cdf(20000).evalf() - 1) < .001 diff -Nru python3-sympy-0.7.2/sympy/stats/tests/test_finite_rv.py python3-sympy-0.7.3/sympy/stats/tests/test_finite_rv.py --- python3-sympy-0.7.2/sympy/stats/tests/test_finite_rv.py 2012-10-17 03:02:22.000000000 +0000 +++ python3-sympy-0.7.3/sympy/stats/tests/test_finite_rv.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,22 +1,29 @@ from sympy import (EmptySet, FiniteSet, S, Symbol, Interval, exp, erf, sqrt, - symbols, simplify, Eq, cos, And, Tuple, Or, Dict, sympify, binomial) + symbols, simplify, Eq, cos, And, Tuple, Or, Dict, sympify, binomial, + factor) from sympy.stats import (DiscreteUniform, Die, Bernoulli, Coin, Binomial, Hypergeometric, P, E, variance, covariance, skewness, sample, density, - given, independent, dependent, where, FiniteRV, pspace, cdf) -from sympy.utilities.pytest import raises + given, independent, dependent, where, FiniteRV, pspace, cdf, + correlation, moment, cmoment, smoment) +from sympy.utilities.pytest import raises, slow +from sympy.abc import p oo = S.Infinity -def BayesTest(A,B): + + +def BayesTest(A, B): assert P(A, B) == P(And(A, B)) / P(B) assert P(A, B) == P(B, A) * P(A) / P(B) + def test_discreteuniform(): # Symbolic a, b, c = symbols('a b c') - X = DiscreteUniform('X', [a,b,c]) + X = DiscreteUniform('X', [a, b, c]) - assert E(X) == (a+b+c)/3 - assert variance(X) == (a**2+b**2+c**2)/3 - (a/3+b/3+c/3)**2 + assert E(X) == (a + b + c)/3 + assert simplify(variance(X) + - ((a**2 + b**2 + c**2)/3 - (a/3 + b/3 + c/3)**2)) == 0 assert P(Eq(X, a)) == P(Eq(X, b)) == P(Eq(X, c)) == S('1/3') Y = DiscreteUniform('Y', list(range(-5, 5))) @@ -24,117 +31,131 @@ # Numeric assert E(Y) == S('-1/2') assert variance(Y) == S('33/4') - assert skewness(Y) == 0 + for x in range(-5, 5): assert P(Eq(Y, x)) == S('1/10') - assert P(Y <= x) == S(x+6)/10 - assert P(Y >= x) == S(5-x)/10 + assert P(Y <= x) == S(x + 6)/10 + assert P(Y >= x) == S(5 - x)/10 + + assert density(Die('D', 6)) == density(DiscreteUniform('U', list(range(1, 7)))) - assert density(Die('D', 6)) == density(DiscreteUniform('U', list(range(1,7)))) def test_dice(): # TODO: Make iid method! - X, Y, Z= Die('X', 6), Die('Y', 6), Die('Z', 6) - a,b = symbols('a b') + X, Y, Z = Die('X', 6), Die('Y', 6), Die('Z', 6) + a, b = symbols('a b') - assert E(X) == 3+S.Half + assert E(X) == 3 + S.Half assert variance(X) == S(35)/12 - assert E(X+Y) == 7 - assert E(X+X) == 7 - assert E(a*X+b) == a*E(X)+b - assert variance(X+Y) == variance(X) + variance(Y) - assert variance(X+X) == 4 * variance(X) - assert covariance(X,Y) == S.Zero - assert covariance(X, X+Y) == variance(X) - assert density(Eq(cos(X*S.Pi),1))[True] == S.Half - - assert P(X>3) == S.Half + assert E(X + Y) == 7 + assert E(X + X) == 7 + assert E(a*X + b) == a*E(X) + b + assert variance(X + Y) == variance(X) + variance(Y) == cmoment(X + Y, 2) + assert variance(X + X) == 4 * variance(X) == cmoment(X + X, 2) + assert cmoment(X, 0) == 1 + assert cmoment(4*X, 3) == 64*cmoment(X, 3) + assert covariance(X, Y) == S.Zero + assert covariance(X, X + Y) == variance(X) + assert density(Eq(cos(X*S.Pi), 1))[True] == S.Half + assert correlation(X, Y) == 0 + assert correlation(X, Y) == correlation(Y, X) + assert smoment(X + Y, 3) == skewness(X + Y) + assert smoment(X, 0) == 1 + assert P(X > 3) == S.Half assert P(2*X > 6) == S.Half - assert P(X>Y) == S(5)/12 - assert P(Eq(X,Y)) == P(Eq(X,1)) + assert P(X > Y) == S(5)/12 + assert P(Eq(X, Y)) == P(Eq(X, 1)) - assert E(X, X>3) == 5 - assert E(X, Y>3) == E(X) - assert E(X+Y, Eq(X,Y)) == E(2*X) - assert E(X+Y-Z, 2*X>Y+1) == S(49)/12 - - assert P(X>3, X>3) == S.One - assert P(X>Y, Eq(Y, 6)) == S.Zero - assert P(Eq(X+Y, 12)) == S.One/36 - assert P(Eq(X+Y, 12), Eq(X, 6)) == S.One/6 - - assert density(X+Y) == density(Y+Z) != density(X+X) - d = density(2*X+Y**Z) - assert d[S(22)] == S.One/108 and d[S(4100)]==S.One/216 and S(3130) not in d + assert E(X, X > 3) == 5 == moment(X, 1, 0, X > 3) + assert E(X, Y > 3) == E(X) == moment(X, 1, 0, Y > 3) + assert E(X + Y, Eq(X, Y)) == E(2*X) + assert moment(X, 0) == 1 + assert moment(5*X, 2) == 25*moment(X, 2) + + assert P(X > 3, X > 3) == S.One + assert P(X > Y, Eq(Y, 6)) == S.Zero + assert P(Eq(X + Y, 12)) == S.One/36 + assert P(Eq(X + Y, 12), Eq(X, 6)) == S.One/6 + + assert density(X + Y) == density(Y + Z) != density(X + X) + d = density(2*X + Y**Z) + assert d[S(22)] == S.One/108 and d[S(4100)] == S.One/216 and S(3130) not in d assert pspace(X).domain.as_boolean() == Or( - *[Eq(X.symbol, i) for i in [1,2,3,4,5,6]]) + *[Eq(X.symbol, i) for i in [1, 2, 3, 4, 5, 6]]) + + assert where(X > 3).set == FiniteSet(4, 5, 6) - assert where(X>3).set == FiniteSet(4,5,6) def test_given(): X = Die('X', 6) - density(X, X>5) == {S(6): S(1)} - where(X>2, X>5).as_boolean() == Eq(X.symbol, 6) - sample(X, X>5) == 6 + assert density(X, X > 5) == {S(6): S(1)} + assert where(X > 2, X > 5).as_boolean() == Eq(X.symbol, 6) + assert sample(X, X > 5) == 6 + def test_domains(): - X, Y= Die('x', 6), Die('y', 6) + X, Y = Die('x', 6), Die('y', 6) x, y = X.symbol, Y.symbol # Domains - d = where(X>Y) + d = where(X > Y) assert d.condition == (x > y) - d = where(And(X>Y, Y>3)) - assert d.as_boolean() == Or(And(Eq(x,5), Eq(y,4)), And(Eq(x,6), Eq(y,5)), - And(Eq(x,6), Eq(y,4))) + d = where(And(X > Y, Y > 3)) + assert d.as_boolean() == Or(And(Eq(x, 5), Eq(y, 4)), And(Eq(x, 6), + Eq(y, 5)), And(Eq(x, 6), Eq(y, 4))) assert len(d.elements) == 3 - assert len(pspace(X+Y).domain.elements) == 36 + assert len(pspace(X + Y).domain.elements) == 36 Z = Die('x', 4) - raises(ValueError, lambda: P(X>Z)) # Two domains with same internal symbol + raises(ValueError, lambda: P(X > Z)) # Two domains with same internal symbol - pspace(X+Y).domain.set == FiniteSet(1,2,3,4,5,6)**2 + pspace(X + Y).domain.set == FiniteSet(1, 2, 3, 4, 5, 6)**2 - assert where(X>3).set == FiniteSet(4,5,6) + assert where(X > 3).set == FiniteSet(4, 5, 6) assert X.pspace.domain.dict == FiniteSet( - Dict({X.symbol:i}) for i in range(1,7)) + Dict({X.symbol: i}) for i in range(1, 7)) + + assert where(X > Y).dict == FiniteSet(Dict({X.symbol: i, Y.symbol: j}) + for i in range(1, 7) for j in range(1, 7) if i > j) - assert where(X>Y).dict == FiniteSet(Dict({X.symbol:i, Y.symbol:j}) - for i in range(1,7) for j in range(1,7) if i>j) def test_dice_bayes(): - X, Y, Z= Die('X', 6), Die('Y', 6), Die('Z', 6) + X, Y, Z = Die('X', 6), Die('Y', 6), Die('Z', 6) + + BayesTest(X > 3, X + Y < 5) + BayesTest(Eq(X - Y, Z), Z > Y) + BayesTest(X > 3, X > 2) - BayesTest(X>3, X+Y<5) - BayesTest(Eq(X-Y, Z), Z>Y) - BayesTest(X>3, X>2) def test_bernoulli(): p, a, b = symbols('p a b') X = Bernoulli('B', p, a, b) - assert E(X) == a*p + b*(-p+1) + assert E(X) == a*p + b*(-p + 1) assert density(X)[a] == p - assert density(X)[b] == 1-p + assert density(X)[b] == 1 - p X = Bernoulli('B', p, 1, 0) assert E(X) == p - assert variance(X) == -p**2 + p - E(a*X+b) == a*E(X)+b - variance(a*X+b) == a**2 * variance(X) + assert simplify(variance(X)) == p*(1 - p) + E(a*X + b) == a*E(X) + b + variance(a*X + b) == a**2 * variance(X) + def test_cdf(): D = Die('D', 6) o = S.One - assert cdf(D) == sympify({1:o/6, 2:o/3, 3:o/2, 4:2*o/3, 5:5*o/6, 6:o}) + assert cdf( + D) == sympify({1: o/6, 2: o/3, 3: o/2, 4: 2*o/3, 5: 5*o/6, 6: o}) + def test_coins(): C, D = Coin('C'), Coin('D') - H, T = sorted(density(C).keys()) + H, T = symbols('H, T') assert P(Eq(C, D)) == S.Half assert density(Tuple(C, D)) == {(H, H): S.One/4, (H, T): S.One/4, (T, H): S.One/4, (T, T): S.One/4} @@ -147,7 +168,8 @@ assert d.as_boolean() == Or(Eq(C.symbol, H), Eq(C.symbol, T)) - raises(ValueError, lambda: P(C>D)) # Can't intelligently compare H to T + raises(ValueError, lambda: P(C > D)) # Can't intelligently compare H to T + def test_binomial_numeric(): nvals = list(range(5)) @@ -157,47 +179,54 @@ for p in pvals: X = Binomial('X', n, p) assert Eq(E(X), n*p) - assert Eq(variance(X), n*p*(1-p)) + assert Eq(variance(X), n*p*(1 - p)) if n > 0 and 0 < p < 1: - assert Eq(skewness(X), (1-2*p)/sqrt(n*p*(1-p))) - for k in range(n+1): - assert Eq(P(Eq(X, k)), binomial(n, k)*p**k*(1-p)**(n-k)) + assert Eq(skewness(X), (1 - 2*p)/sqrt(n*p*(1 - p))) + for k in range(n + 1): + assert Eq(P(Eq(X, k)), binomial(n, k)*p**k*(1 - p)**(n - k)) + +@slow def test_binomial_symbolic(): - n = 10 # Because we're using for loops, can't do symbolic n + n = 10 # Because we're using for loops, can't do symbolic n p = symbols('p', positive=True) X = Binomial('X', n, p) - assert Eq(simplify(E(X)), n*p) - assert Eq(simplify(variance(X)), n*p*(1-p)) -# Can't detect the equality -# assert Eq(simplify(skewness(X)), (1-2*p)/sqrt(n*p*(1-p))) + assert simplify(E(X)) == n*p == simplify(moment(X, 1)) + assert simplify(variance(X)) == n*p*(1 - p) == simplify(cmoment(X, 2)) + assert factor(simplify(skewness(X))) == factor((1-2*p)/sqrt(n*p*(1-p))) # Test ability to change success/failure winnings H, T = symbols('H T') Y = Binomial('Y', n, p, succ=H, fail=T) - assert Eq(simplify(E(Y)), simplify(n*(H*p+T*(1-p)))) + assert simplify(E(Y)) == simplify(n*(H*p + T*(1 - p))) + def test_hypergeometric_numeric(): for N in range(1, 5): - for m in range(0, N+1): - for n in range(1, N+1): + for m in range(0, N + 1): + for n in range(1, N + 1): X = Hypergeometric('X', N, m, n) N, m, n = list(map(sympify, (N, m, n))) assert sum(density(X).values()) == 1 assert E(X) == n * m / N if N > 1: - assert variance(X) == n*(m/N)*(N-m)/N*(N-n)/(N-1) + assert variance(X) == n*(m/N)*(N - m)/N*(N - n)/(N - 1) # Only test for skewness when defined if N > 2 and 0 < m < N and n < N: - assert Eq(skewness(X),simplify((N-2*m)*sqrt(N-1)*(N-2*n) - / (sqrt(n*m*(N-m)*(N-n))*(N-2)))) + assert Eq(skewness(X), simplify((N - 2*m)*sqrt(N - 1)*(N - 2*n) + / (sqrt(n*m*(N - m)*(N - n))*(N - 2)))) def test_FiniteRV(): - F = FiniteRV('F', {1:S.Half, 2:S.One/4, 3:S.One/4}) + F = FiniteRV('F', {1: S.Half, 2: S.One/4, 3: S.One/4}) - assert density(F) == {S(1):S.Half, S(2):S.One/4, S(3):S.One/4} - assert P(F>=2) == S.Half + assert density(F) == {S(1): S.Half, S(2): S.One/4, S(3): S.One/4} + assert P(F >= 2) == S.Half assert pspace(F).domain.as_boolean() == Or( - *[Eq(F.symbol, i) for i in [1,2,3]]) + *[Eq(F.symbol, i) for i in [1, 2, 3]]) + +def test_density_call(): + x = Bernoulli('x', p) + d = density(x) + assert d(0) == 1 - p diff -Nru python3-sympy-0.7.2/sympy/stats/tests/test_rv.py python3-sympy-0.7.3/sympy/stats/tests/test_rv.py --- python3-sympy-0.7.2/sympy/stats/tests/test_rv.py 2012-10-17 03:02:22.000000000 +0000 +++ python3-sympy-0.7.3/sympy/stats/tests/test_rv.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,47 +1,55 @@ + from sympy import (EmptySet, FiniteSet, S, Symbol, Interval, exp, erf, sqrt, - symbols, simplify, Eq, cos, And, Tuple, integrate, oo, sin, Sum) -from sympy.stats import (Die, Normal, Exponential , P, E, variance, covariance, + symbols, simplify, Eq, cos, And, Tuple, integrate, oo, sin, Sum, Basic, + DiracDelta) +from sympy.stats import (Die, Normal, Exponential, P, E, variance, covariance, skewness, density, given, independent, dependent, where, pspace, random_symbols, sample) -from sympy.stats.rv import ProductPSpace, rs_swap +from sympy.stats.rv import ProductPSpace, rs_swap, Density, NamedArgsMixin from sympy.utilities.pytest import raises, XFAIL + def test_where(): X, Y = Die('X'), Die('Y') Z = Normal('Z', 0, 1) - assert where(Z**2<=1).set == Interval(-1, 1) - assert where(Z**2<=1).as_boolean() == Interval(-1,1).as_relational(Z.symbol) - assert where(And(X>Y, Y>4)).as_boolean() == And( - Eq(X.symbol, 6), Eq(Y.symbol, 5)) + assert where(Z**2 <= 1).set == Interval(-1, 1) + assert where( + Z**2 <= 1).as_boolean() == Interval(-1, 1).as_relational(Z.symbol) + assert where(And(X > Y, Y > 4)).as_boolean() == And( + Eq(X.symbol, 6), Eq(Y.symbol, 5)) - assert len(where(X<3).set) == 2 - assert 1 in where(X<3).set + assert len(where(X < 3).set) == 2 + assert 1 in where(X < 3).set X, Y = Normal('X', 0, 1), Normal('Y', 0, 1) assert where(And(X**2 <= 1, X >= 0)).set == Interval(0, 1) XX = given(X, And(X**2 <= 1, X >= 0)) assert XX.pspace.domain.set == Interval(0, 1) - assert XX.pspace.domain.as_boolean() == And(0 <= X.symbol, X.symbol**2 <= 1) + assert XX.pspace.domain.as_boolean() == \ + And(0 <= X.symbol, X.symbol**2 <= 1) with raises(TypeError): - XX = given(X, X+3) + XX = given(X, X + 3) + def test_random_symbols(): X, Y = Normal('X', 0, 1), Normal('Y', 0, 1) - assert set(random_symbols(2*X+1)) == set((X,)) - assert set(random_symbols(2*X+Y)) == set((X,Y)) - assert set(random_symbols(2*X+Y.symbol)) == set((X,)) + assert set(random_symbols(2*X + 1)) == set((X,)) + assert set(random_symbols(2*X + Y)) == set((X, Y)) + assert set(random_symbols(2*X + Y.symbol)) == set((X,)) assert set(random_symbols(2)) == set() + def test_pspace(): X, Y = Normal('X', 0, 1), Normal('Y', 0, 1) - assert not pspace(5+3) + assert not pspace(5 + 3) assert pspace(X) == X.pspace - assert pspace(2*X+1) == X.pspace - assert pspace(2*X+Y) == ProductPSpace(Y.pspace, X.pspace) + assert pspace(2*X + 1) == X.pspace + assert pspace(2*X + Y) == ProductPSpace(Y.pspace, X.pspace) + def test_rs_swap(): X = Normal('x', 0, 1) @@ -50,63 +58,78 @@ XX = Normal('x', 0, 2) YY = Normal('y', 0, 3) - expr = 2*X+Y - assert expr.subs(rs_swap((X,Y), (YY,XX))) == 2*XX+YY + expr = 2*X + Y + assert expr.subs(rs_swap((X, Y), (YY, XX))) == 2*XX + YY + def test_RandomSymbol(): X = Normal('x', 0, 1) Y = Normal('x', 0, 2) assert X.symbol == Y.symbol - assert X!=Y + assert X != Y assert X.name == X.symbol.name + X = Normal('lambda', 0, 1) # make sure we can use protected terms + X = Normal('Lambda', 0, 1) # make sure we can use SymPy terms + + +def test_RandomSymbol_diff(): + X = Normal('x', 0, 1) + assert (2*X).diff(X) + + def test_overlap(): X = Normal('x', 0, 1) Y = Normal('x', 0, 2) - raises(ValueError, lambda: P(X>Y)) + raises(ValueError, lambda: P(X > Y)) + def test_ProductPSpace(): X = Normal('X', 0, 1) Y = Normal('Y', 0, 1) px = X.pspace py = Y.pspace - assert pspace(X+Y) == ProductPSpace(px, py) - assert pspace(X+Y) == ProductPSpace(py, px) + assert pspace(X + Y) == ProductPSpace(px, py) + assert pspace(X + Y) == ProductPSpace(py, px) + def test_E(): assert E(5) == 5 + def test_Sample(): X = Die('X', 6) - Y = Normal('Y', 0,1) + Y = Normal('Y', 0, 1) z = Symbol('z') - assert sample(X) in [1,2,3,4,5,6] - assert sample(X+Y).is_Float + assert sample(X) in [1, 2, 3, 4, 5, 6] + assert sample(X + Y).is_Float - P(X+Y>0, Y<0, numsamples=10).is_number - assert E(X+Y, numsamples=10).is_number - assert variance(X+Y, numsamples=10).is_number + P(X + Y > 0, Y < 0, numsamples=10).is_number + assert E(X + Y, numsamples=10).is_number + assert variance(X + Y, numsamples=10).is_number - raises(ValueError, lambda: P(Y>z, numsamples=5)) + raises(ValueError, lambda: P(Y > z, numsamples=5)) - assert P(sin(Y)<=1, numsamples=10) == 1 - assert P(sin(Y)<=1, cos(Y)<1, numsamples=10) == 1 + assert P(sin(Y) <= 1, numsamples=10) == 1 + assert P(sin(Y) <= 1, cos(Y) < 1, numsamples=10) == 1 # Make sure this doesn't raise an error - E(Sum(1/z**Y, (z,1,oo)), Y>2, numsamples=3) + E(Sum(1/z**Y, (z, 1, oo)), Y > 2, numsamples=3) + def test_given(): X = Normal('X', 0, 1) Y = Normal('Y', 0, 1) A = given(X, True) - B = given(X, Y>2) + B = given(X, Y > 2) assert X == A == B + def test_dependence(): X, Y = Die('X'), Die('Y') assert independent(X, 2*Y) @@ -117,22 +140,49 @@ assert dependent(X, 2*X) # Create a dependency - XX, YY = given(Tuple(X,Y), Eq(X+Y, 3)) + XX, YY = given(Tuple(X, Y), Eq(X + Y, 3)) assert dependent(XX, YY) + @XFAIL def test_dependent_finite(): X, Y = Die('X'), Die('Y') # Dependence testing requires symbolic conditions which currently break # finite random variables - assert dependent(X, Y+X) + assert dependent(X, Y + X) - XX, YY = given(Tuple(X, Y), X+Y>5) # Create a dependency + XX, YY = given(Tuple(X, Y), X + Y > 5) # Create a dependency assert dependent(XX, YY) + def test_normality(): - X, Y = Normal('X', 0,1), Normal('Y', 0,1) + X, Y = Normal('X', 0, 1), Normal('Y', 0, 1) x, z = symbols('x, z', real=True) - dens = density(X-Y, Eq(X+Y, z)) + dens = density(X - Y, Eq(X + Y, z)) assert integrate(dens(x), (x, -oo, oo)) == 1 + +def test_Density(): + X = Die('X', 6) + d = Density(X) + assert d.doit() == density(X) + +def test_NamedArgsMixin(): + class Foo(Basic, NamedArgsMixin): + _argnames = 'foo', 'bar' + + a = Foo(1, 2) + + assert a.foo == 1 + assert a.bar == 2 + + raises(AttributeError, lambda: a.baz) + + class Bar(Basic, NamedArgsMixin): + pass + + raises(AttributeError, lambda: Bar(1, 2).foo) + +def test_density_constant(): + assert density(3)(2) == 0 + assert density(3)(3) == DiracDelta(0) diff -Nru python3-sympy-0.7.2/sympy/strategies/__init__.py python3-sympy-0.7.3/sympy/strategies/__init__.py --- python3-sympy-0.7.2/sympy/strategies/__init__.py 1970-01-01 00:00:00.000000000 +0000 +++ python3-sympy-0.7.3/sympy/strategies/__init__.py 2013-07-13 17:53:32.000000000 +0000 @@ -0,0 +1,33 @@ +""" Rewrite Rules + +DISCLAIMER: This module is experimental. The interface is subject to change. + +A rule is a function that transforms one expression into another + + Rule :: Expr -> Expr + +A strategy is a function that says how a rule should be applied to a syntax +tree. In general strategies take rules and produce a new rule + + Strategy :: [Rules], Other-stuff -> Rule + +This allows developers to separate a mathematical transformation from the +algorithmic details of applying that transformation. The goal is to separate +the work of mathematical programming from algorithmic programming. + +Submodules + +strategies.rl - some fundamental rules +strategies.core - generic non-SymPy specific strategies +strategies.traverse - strategies that traverse a SymPy tree +strategies.tools - some conglomerate strategies that do depend on SymPy +""" + +from . import rl +from . import traverse +from .rl import rm_id, unpack, flatten, sort, glom, distribute, rebuild +from .util import new +from .core import (condition, debug, chain, null_safe, do_one, exhaust, + minimize, tryit) +from .tools import canon, typed +from . import branch diff -Nru python3-sympy-0.7.2/sympy/strategies/branch/__init__.py python3-sympy-0.7.3/sympy/strategies/branch/__init__.py --- python3-sympy-0.7.2/sympy/strategies/branch/__init__.py 1970-01-01 00:00:00.000000000 +0000 +++ python3-sympy-0.7.3/sympy/strategies/branch/__init__.py 2013-07-13 17:53:32.000000000 +0000 @@ -0,0 +1,4 @@ +from . import traverse +from .core import (condition, debug, multiplex, exhaust, notempty, + chain, onaction, sfilter, yieldify, do_one, identity) +from .tools import canon diff -Nru python3-sympy-0.7.2/sympy/strategies/branch/core.py python3-sympy-0.7.3/sympy/strategies/branch/core.py --- python3-sympy-0.7.2/sympy/strategies/branch/core.py 1970-01-01 00:00:00.000000000 +0000 +++ python3-sympy-0.7.3/sympy/strategies/branch/core.py 2013-07-13 17:53:32.000000000 +0000 @@ -0,0 +1,109 @@ +""" Generic SymPy-Independent Strategies """ +import itertools + +def identity(x): + yield x + +def exhaust(brule): + """ Apply a branching rule repeatedly until it has no effect """ + def exhaust_brl(expr): + seen = set([expr]) + for nexpr in brule(expr): + if nexpr not in seen: + seen.add(nexpr) + for nnexpr in exhaust_brl(nexpr): + yield nnexpr + if seen == set([expr]): + yield expr + return exhaust_brl + +def onaction(brule, fn): + def onaction_brl(expr): + for result in brule(expr): + if result != expr: + fn(brule, expr, result) + yield result + return onaction_brl + +def debug(brule, file=None): + """ Print the input and output expressions at each rule application """ + if not file: + from sys import stdout + file = stdout + + def write(brl, expr, result): + file.write("Rule: %s\n"%brl.__name__) + file.write("In: %s\nOut: %s\n\n"%(expr, result)) + + return onaction(brule, write) + +def multiplex(*brules): + """ Multiplex many branching rules into one """ + def multiplex_brl(expr): + seen = set([]) + for brl in brules: + for nexpr in brl(expr): + if nexpr not in seen: + seen.add(nexpr) + yield nexpr + return multiplex_brl + +def condition(cond, brule): + """ Only apply branching rule if condition is true """ + def conditioned_brl(expr): + if cond(expr): + for x in brule(expr): yield x + else: + pass + return conditioned_brl + +def sfilter(pred, brule): + """ Yield only those results which satisfy the predicate """ + def filtered_brl(expr): + for x in filter(pred, brule(expr)): + yield x + return filtered_brl + +def notempty(brule): + def notempty_brl(expr): + yielded = False + for nexpr in brule(expr): + yielded = True + yield nexpr + if not yielded: + yield expr + return notempty_brl + +def do_one(*brules): + """ Execute one of the branching rules """ + def do_one_brl(expr): + yielded = False + for brl in brules: + for nexpr in brl(expr): + yielded = True + yield nexpr + if yielded: + raise StopIteration() + return do_one_brl + +def chain(*brules): + """ + Compose a sequence of brules so that they apply to the expr sequentially + """ + def chain_brl(expr): + if not brules: + yield expr + raise StopIteration() + + head, tail = brules[0], brules[1:] + for nexpr in head(expr): + for nnexpr in chain(*tail)(nexpr): + yield nnexpr + + return chain_brl + +def yieldify(rl): + """ Turn a rule into a branching rule """ + def brl(expr): + yield rl(expr) + return brl diff -Nru python3-sympy-0.7.2/sympy/strategies/branch/tests/test_core.py python3-sympy-0.7.3/sympy/strategies/branch/tests/test_core.py --- python3-sympy-0.7.2/sympy/strategies/branch/tests/test_core.py 1970-01-01 00:00:00.000000000 +0000 +++ python3-sympy-0.7.3/sympy/strategies/branch/tests/test_core.py 2013-07-13 17:53:32.000000000 +0000 @@ -0,0 +1,104 @@ +from sympy.strategies.branch.core import (exhaust, debug, multiplex, + condition, notempty, chain, onaction, sfilter, yieldify, do_one, + identity) + +def posdec(x): + if x > 0: + yield x-1 + else: + yield x + +def branch5(x): + if 0 < x < 5: + yield x-1 + elif 5 < x < 10: + yield x+1 + elif x == 5: + yield x+1 + yield x-1 + else: + yield x + +even = lambda x: x%2 == 0 + +def inc(x): + yield x + 1 + +def one_to_n(n): + for i in range(n): + yield i + +def test_exhaust(): + brl = exhaust(branch5) + assert set(brl(3)) == set([0]) + assert set(brl(7)) == set([10]) + assert set(brl(5)) == set([0, 10]) + +def test_debug(): + import io + file = io.StringIO() + rl = debug(posdec, file) + list(rl(5)) + log = file.getvalue() + file.close() + + assert posdec.__name__ in log + assert '5' in log + assert '4' in log + +def test_multiplex(): + brl = multiplex(posdec, branch5) + assert set(brl(3)) == set([2]) + assert set(brl(7)) == set([6, 8]) + assert set(brl(5)) == set([4, 6]) + +def test_condition(): + brl = condition(even, branch5) + assert set(brl(4)) == set(branch5(4)) + assert set(brl(5)) == set([]) + +def test_sfilter(): + brl = sfilter(even, one_to_n) + assert set(brl(10)) == set([0, 2, 4, 6, 8]) + +def test_notempty(): + + def ident_if_even(x): + if even(x): + yield x + + brl = notempty(ident_if_even) + assert set(brl(4)) == set([4]) + assert set(brl(5)) == set([5]) + +def test_chain(): + assert list(chain()(2)) == [2] # identity + assert list(chain(inc, inc)(2)) == [4] + assert list(chain(branch5, inc)(4)) == [4] + assert set(chain(branch5, inc)(5)) == set([5, 7]) + assert list(chain(inc, branch5)(5)) == [7] + +def test_onaction(): + L = [] + def record(fn, input, output): + L.append((input, output)) + + list(onaction(inc, record)(2)) + assert L == [(2, 3)] + + list(onaction(identity, record)(2)) + assert L == [(2, 3)] + +def test_yieldify(): + inc = lambda x: x + 1 + yinc = yieldify(inc) + assert list(yinc(3)) == [4] + +def test_do_one(): + def bad(expr): + raise ValueError() + yield False + + assert list(do_one(inc)(3)) == [4] + assert list(do_one(inc, bad)(3)) == [4] + assert list(do_one(inc, posdec)(3)) == [4] diff -Nru python3-sympy-0.7.2/sympy/strategies/branch/tests/test_tools.py python3-sympy-0.7.3/sympy/strategies/branch/tests/test_tools.py --- python3-sympy-0.7.2/sympy/strategies/branch/tests/test_tools.py 1970-01-01 00:00:00.000000000 +0000 +++ python3-sympy-0.7.3/sympy/strategies/branch/tests/test_tools.py 2013-07-13 17:53:32.000000000 +0000 @@ -0,0 +1,36 @@ +from sympy.strategies.branch.tools import canon +from sympy import Basic + + +def posdec(x): + if isinstance(x, int) and x > 0: + yield x-1 + else: + yield x + +def branch5(x): + if isinstance(x, int): + if 0 < x < 5: + yield x-1 + elif 5 < x < 10: + yield x+1 + elif x == 5: + yield x+1 + yield x-1 + else: + yield x + +def test_zero_ints(): + expr = Basic(2, Basic(5, 3), 8) + expected = set([Basic(0, Basic(0, 0), 0)]) + + brl = canon(posdec) + assert set(brl(expr)) == expected + +def test_split5(): + expr = Basic(2, Basic(5, 3), 8) + expected = set([Basic(0, Basic(0, 0), 10), + Basic(0, Basic(10, 0), 10)]) + + brl = canon(branch5) + assert set(brl(expr)) == expected diff -Nru python3-sympy-0.7.2/sympy/strategies/branch/tests/test_traverse.py python3-sympy-0.7.3/sympy/strategies/branch/tests/test_traverse.py --- python3-sympy-0.7.2/sympy/strategies/branch/tests/test_traverse.py 1970-01-01 00:00:00.000000000 +0000 +++ python3-sympy-0.7.3/sympy/strategies/branch/tests/test_traverse.py 2013-07-13 17:53:32.000000000 +0000 @@ -0,0 +1,46 @@ +from sympy import Basic, symbols, Symbol, S +from sympy.strategies.branch.traverse import top_down, sall +from sympy.strategies.branch.core import do_one, identity + +def inc(x): + if isinstance(x, int): + yield x + 1 + +def test_top_down_easy(): + expr = Basic(1, 2) + expected = Basic(2, 3) + brl = top_down(inc) + + assert set(brl(expr)) == set([expected]) + +def test_top_down_big_tree(): + expr = Basic(1, Basic(2), Basic(3, Basic(4), 5)) + expected = Basic(2, Basic(3), Basic(4, Basic(5), 6)) + brl = top_down(inc) + + assert set(brl(expr)) == set([expected]) + +def test_top_down_harder_function(): + def split5(x): + if x == 5: + yield x - 1 + yield x + 1 + + expr = Basic(Basic(5, 6), 1) + expected = set([Basic(Basic(4, 6), 1), Basic(Basic(6, 6), 1)]) + brl = top_down(split5) + + assert set(brl(expr)) == expected + +def test_sall(): + expr = Basic(1, 2) + expected = Basic(2, 3) + brl = sall(inc) + + assert list(brl(expr)) == [expected] + + expr = Basic(1, 2, Basic(3, 4)) + expected = Basic(2, 3, Basic(3, 4)) + brl = sall(do_one(inc, identity)) + + assert list(brl(expr)) == [expected] diff -Nru python3-sympy-0.7.2/sympy/strategies/branch/tools.py python3-sympy-0.7.3/sympy/strategies/branch/tools.py --- python3-sympy-0.7.2/sympy/strategies/branch/tools.py 1970-01-01 00:00:00.000000000 +0000 +++ python3-sympy-0.7.3/sympy/strategies/branch/tools.py 2013-07-13 17:53:32.000000000 +0000 @@ -0,0 +1,12 @@ +from .core import (exhaust, multiplex, debug, notempty, condition, chain, + onaction, sfilter, yieldify, do_one, identity) +from .traverse import top_down + +def canon(*rules): + """ Strategy for canonicalization + + Apply each branching rule in a top-down fashion through the tree. + Multiplex through all branching rule traversals + Keep doing this until there is no change. + """ + return exhaust(multiplex(*list(map(top_down, rules)))) diff -Nru python3-sympy-0.7.2/sympy/strategies/branch/traverse.py python3-sympy-0.7.3/sympy/strategies/branch/traverse.py --- python3-sympy-0.7.2/sympy/strategies/branch/traverse.py 1970-01-01 00:00:00.000000000 +0000 +++ python3-sympy-0.7.3/sympy/strategies/branch/traverse.py 2013-07-13 17:53:32.000000000 +0000 @@ -0,0 +1,23 @@ +""" Branching Strategies to Traverse a Tree """ + +from sympy.strategies.util import basic_fns +from .core import chain, identity, do_one +from sympy.core.compatibility import product + +def top_down(brule, fns=basic_fns): + """ Apply a rule down a tree running it on the top nodes first """ + return chain(do_one(brule, identity), + lambda expr: sall(top_down(brule, fns), fns)(expr)) + +def sall(brule, fns=basic_fns): + """ Strategic all - apply rule to args """ + op, new, children, leaf = list(map(fns.get, ('op', 'new', 'children', 'leaf'))) + def all_rl(expr): + if leaf(expr): + yield expr + else: + myop = op(expr) + argss = product(*list(map(brule, children(expr)))) + for args in argss: + yield new(myop, *args) + return all_rl diff -Nru python3-sympy-0.7.2/sympy/strategies/core.py python3-sympy-0.7.3/sympy/strategies/core.py --- python3-sympy-0.7.2/sympy/strategies/core.py 1970-01-01 00:00:00.000000000 +0000 +++ python3-sympy-0.7.3/sympy/strategies/core.py 2013-07-13 17:53:32.000000000 +0000 @@ -0,0 +1,116 @@ +""" Generic SymPy-Independent Strategies """ +from functools import partial + +identity = lambda x: x + +def exhaust(rule): + """ Apply a rule repeatedly until it has no effect """ + def exhaustive_rl(expr): + new, old = rule(expr), expr + while(new != old): + new, old = rule(new), new + return new + return exhaustive_rl + +def memoize(rule): + """ Memoized version of a rule """ + cache = {} + def memoized_rl(expr): + if expr in cache: + return cache[expr] + else: + result = rule(expr) + cache[expr] = result + return result + return memoized_rl + +def condition(cond, rule): + """ Only apply rule if condition is true """ + def conditioned_rl(expr): + if cond(expr): + return rule(expr) + else: + return expr + return conditioned_rl + +def chain(*rules): + """ + Compose a sequence of rules so that they apply to the expr sequentially + """ + def chain_rl(expr): + for rule in rules: + expr = rule(expr) + return expr + return chain_rl + +def debug(rule, file=None): + """ Print out before and after expressions each time rule is used """ + if file is None: + from sys import stdout + file = stdout + def debug_rl(*args, **kwargs): + expr = args[0] + result = rule(*args, **kwargs) + if result != expr: + file.write("Rule: %s\n"%rule.__name__) + file.write("In: %s\nOut: %s\n\n"%(expr, result)) + return result + return debug_rl + +def null_safe(rule): + """ Return original expr if rule returns None """ + def null_safe_rl(expr): + result = rule(expr) + if result is None: + return expr + else: + return result + return null_safe_rl + +def tryit(rule): + """ Return original expr if rule raises exception """ + def try_rl(expr): + try: + return rule(expr) + except: + return expr + return try_rl + +def do_one(*rules): + """ Try each of the rules until one works. Then stop. """ + def do_one_rl(expr): + for rl in rules: + result = rl(expr) + if result != expr: + return result + return expr + return do_one_rl + +def switch(key, ruledict): + """ Select a rule based on the result of key called on the function """ + def switch_rl(expr): + rl = ruledict.get(key(expr), identity) + return rl(expr) + return switch_rl + +identity = lambda x: x + +def minimize(*rules, **kwargs): + """ Select result of rules that minimizes objective + + >>> from sympy.strategies import minimize + >>> inc = lambda x: x + 1 + >>> dec = lambda x: x - 1 + >>> rl = minimize(inc, dec) + >>> rl(4) + 3 + + >>> rl = minimize(inc, dec, objective=lambda x: -x) # maximize + >>> rl(4) + 5 + """ + + objective = kwargs.get('objective', identity) + def minrule(expr): + return min([rule(expr) for rule in rules], key=objective) + return minrule diff -Nru python3-sympy-0.7.2/sympy/strategies/rl.py python3-sympy-0.7.3/sympy/strategies/rl.py --- python3-sympy-0.7.2/sympy/strategies/rl.py 1970-01-01 00:00:00.000000000 +0000 +++ python3-sympy-0.7.3/sympy/strategies/rl.py 2013-07-13 17:53:32.000000000 +0000 @@ -0,0 +1,157 @@ +""" Generic Rules for SymPy + +This file assumes knowledge of Basic and little else. +""" +from sympy.utilities.iterables import sift +from .util import new + +# Functions that create rules + +def rm_id(isid, new=new): + """ Create a rule to remove identities + + isid - fn :: x -> Bool --- whether or not this element is an identity + + >>> from sympy.strategies import rm_id + >>> from sympy import Basic + >>> remove_zeros = rm_id(lambda x: x==0) + >>> remove_zeros(Basic(1, 0, 2)) + Basic(1, 2) + >>> remove_zeros(Basic(0, 0)) # If only identites then we keep one + Basic(0) + + See Also: + unpack + """ + def ident_remove(expr): + """ Remove identities """ + ids = list(map(isid, expr.args)) + if sum(ids) == 0: # No identities. Common case + return expr + elif sum(ids) != len(ids): # there is at least one non-identity + return new(expr.__class__, + *[arg for arg, x in zip(expr.args, ids) if not x]) + else: + return new(expr.__class__, expr.args[0]) + + return ident_remove + +def glom(key, count, combine): + """ Create a rule to conglomerate identical args + + >>> from sympy.strategies import glom + >>> from sympy import Add + >>> from sympy.abc import x + + >>> key = lambda x: x.as_coeff_Mul()[1] + >>> count = lambda x: x.as_coeff_Mul()[0] + >>> combine = lambda cnt, arg: cnt * arg + >>> rl = glom(key, count, combine) + + >>> rl(Add(x, -x, 3*x, 2, 3, evaluate=False)) + 3*x + 5 + + Wait, how are key, count and combine supposed to work? + >>> key(2*x) + x + >>> count(2*x) + 2 + >>> combine(2, x) + 2*x + """ + def conglomerate(expr): + """ Conglomerate together identical args x + x -> 2x """ + groups = sift(expr.args, key) + counts = dict((k, sum(map(count, args))) for k, args in list(groups.items())) + newargs = [combine(cnt, mat) for mat, cnt in list(counts.items())] + if set(newargs) != set(expr.args): + return new(type(expr), *newargs) + else: + return expr + + return conglomerate + +def sort(key, new=new): + """ Create a rule to sort by a key function + + >>> from sympy.strategies import sort + >>> from sympy import Basic + >>> sort_rl = sort(str) + >>> sort_rl(Basic(3, 1, 2)) + Basic(1, 2, 3) + """ + + def sort_rl(expr): + return new(expr.__class__, *sorted(expr.args, key=key)) + return sort_rl + +def distribute(A, B): + """ Turns an A containing Bs into a B of As + + where A, B are container types + + >>> from sympy.strategies import distribute + >>> from sympy import Add, Mul, symbols + >>> x, y = symbols('x,y') + >>> dist = distribute(Mul, Add) + >>> expr = Mul(2, x+y, evaluate=False) + >>> expr + 2*(x + y) + >>> dist(expr) + 2*x + 2*y + """ + + def distribute_rl(expr): + for i, arg in enumerate(expr.args): + if isinstance(arg, B): + first, b, tail = expr.args[:i], expr.args[i], expr.args[i+1:] + return B(*[A(*(first + (arg,) + tail)) for arg in b.args]) + return expr + return distribute_rl + +def subs(a, b): + """ Replace expressions exactly """ + def subs_rl(expr): + if expr == a: + return b + else: + return expr + return subs_rl + +# Functions that are rules + +def unpack(expr): + """ Rule to unpack singleton args + + >>> from sympy.strategies import unpack + >>> from sympy import Basic + >>> unpack(Basic(2)) + 2 + """ + if len(expr.args) == 1: + return expr.args[0] + else: + return expr + +def flatten(expr, new=new): + """ Flatten T(a, b, T(c, d), T2(e)) to T(a, b, c, d, T2(e)) """ + cls = expr.__class__ + args = [] + for arg in expr.args: + if arg.__class__ == cls: + args.extend(arg.args) + else: + args.append(arg) + return new(expr.__class__, *args) + +def rebuild(expr): + """ Rebuild a SymPy tree + + This function recursively calls constructors in the expression tree. + This forces canonicalization and removes ugliness introduced by the use of + Basic.__new__ + """ + try: + return type(expr)(*list(map(rebuild, expr.args))) + except: + return expr diff -Nru python3-sympy-0.7.2/sympy/strategies/tests/test_core.py python3-sympy-0.7.3/sympy/strategies/tests/test_core.py --- python3-sympy-0.7.2/sympy/strategies/tests/test_core.py 1970-01-01 00:00:00.000000000 +0000 +++ python3-sympy-0.7.3/sympy/strategies/tests/test_core.py 2013-07-13 17:53:32.000000000 +0000 @@ -0,0 +1,88 @@ +from sympy.strategies.core import (null_safe, exhaust, memoize, condition, + chain, tryit, do_one, debug, switch, minimize) +from functools import partial + +def test_null_safe(): + def rl(expr): + if expr == 1: + return 2 + safe_rl = null_safe(rl) + assert rl(1) == safe_rl(1) + + assert rl(3) == None + assert safe_rl(3) == 3 + +def posdec(x): + if x > 0: + return x-1 + else: + return x +def test_exhaust(): + sink = exhaust(posdec) + assert sink(5) == 0 + assert sink(10) == 0 + +def test_memoize(): + rl = memoize(posdec) + assert rl(5) == posdec(5) + assert rl(5) == posdec(5) + assert rl(-2) == posdec(-2) + +def test_condition(): + rl = condition(lambda x: x%2 == 0, posdec) + assert rl(5) == 5 + assert rl(4) == 3 + +def test_chain(): + rl = chain(posdec, posdec) + assert rl(5) == 3 + assert rl(1) == 0 + +def test_tryit(): + def rl(expr): + assert False + safe_rl = tryit(rl) + assert safe_rl(1) == 1 + +def test_do_one(): + rl = do_one(posdec, posdec) + assert rl(5) == 4 + +def test_debug(): + import io + file = io.StringIO() + rl = debug(posdec, file) + rl(5) + log = file.getvalue() + file.close() + + assert posdec.__name__ in log + assert '5' in log + assert '4' in log + +def test_switch(): + inc = lambda x: x + 1 + dec = lambda x: x - 1 + key = lambda x: x % 3 + rl = switch(key, {0: inc, 1: dec}) + + assert rl(3) == 4 + assert rl(4) == 3 + assert rl(5) == 5 + +def test_minimize(): + inc = lambda x: x + 1 + dec = lambda x: x - 1 + rl = minimize(inc, dec) + assert rl(4) == 3 + + rl = minimize(inc, dec, objective=lambda x: -x) + assert rl(4) == 5 + +def test_do_one(): + rl1 = lambda x: 2 if x == 1 else x + rl2 = lambda x: 3 if x == 2 else x + + rule = do_one(rl1, rl2) + assert rule(1) == 2 + assert rule(rule(1)) == 3 diff -Nru python3-sympy-0.7.2/sympy/strategies/tests/test_rl.py python3-sympy-0.7.3/sympy/strategies/tests/test_rl.py --- python3-sympy-0.7.2/sympy/strategies/tests/test_rl.py 1970-01-01 00:00:00.000000000 +0000 +++ python3-sympy-0.7.3/sympy/strategies/tests/test_rl.py 2013-07-13 17:53:32.000000000 +0000 @@ -0,0 +1,59 @@ +from sympy.strategies.rl import (rm_id, glom, flatten, unpack, sort, distribute, + subs, rebuild) +from sympy import Basic + +def test_rm_id(): + rmzeros = rm_id(lambda x: x == 0) + assert rmzeros(Basic(0, 1)) == Basic(1) + assert rmzeros(Basic(0, 0)) == Basic(0) + assert rmzeros(Basic(2, 1)) == Basic(2, 1) + +def test_glom(): + from sympy import Add + from sympy.abc import x + key = lambda x: x.as_coeff_Mul()[1] + count = lambda x: x.as_coeff_Mul()[0] + newargs = lambda cnt, arg: cnt * arg + rl = glom(key, count, newargs) + + result = rl(Add(x, -x, 3*x, 2, 3, evaluate=False)) + expected = Add(3*x, 5) + assert set(result.args) == set(expected.args) + +def test_flatten(): + assert flatten(Basic(1, 2, Basic(3, 4))) == Basic(1, 2, 3, 4) + +def test_unpack(): + assert unpack(Basic(2)) == 2 + assert unpack(Basic(2, 3)) == Basic(2, 3) + +def test_sort(): + assert sort(str)(Basic(3,1,2)) == Basic(1,2,3) + +def test_distribute(): + class T1(Basic): pass + class T2(Basic): pass + + distribute_t12 = distribute(T1, T2) + assert distribute_t12(T1(1, 2, T2(3, 4), 5)) == \ + T2(T1(1, 2, 3, 5), + T1(1, 2, 4, 5)) + assert distribute_t12(T1(1, 2, 3)) == T1(1, 2, 3) + +def test_distribute_add_mul(): + from sympy import Add, Mul, symbols + x, y = symbols('x, y') + expr = Mul(2, Add(x, y), evaluate=False) + expected = Add(Mul(2, x), Mul(2, y)) + distribute_mul = distribute(Mul, Add) + assert distribute_mul(expr) == expected + +def test_subs(): + rl = subs(1, 2) + assert rl(1) == 2 + assert rl(3) == 3 + +def test_rebuild(): + from sympy import Add + expr = Basic.__new__(Add, 1, 2) + assert rebuild(expr) == 3 diff -Nru python3-sympy-0.7.2/sympy/strategies/tests/test_tools.py python3-sympy-0.7.3/sympy/strategies/tests/test_tools.py --- python3-sympy-0.7.2/sympy/strategies/tests/test_tools.py 1970-01-01 00:00:00.000000000 +0000 +++ python3-sympy-0.7.3/sympy/strategies/tests/test_tools.py 2013-07-13 17:53:32.000000000 +0000 @@ -0,0 +1,26 @@ +from sympy.strategies.tools import subs, typed +from sympy.strategies.rl import rm_id +from sympy import Basic + +def test_subs(): + from sympy import symbols + a,b,c,d,e,f = symbols('a,b,c,d,e,f') + mapping = {a: d, d: a, Basic(e): Basic(f)} + expr = Basic(a, Basic(b, c), Basic(d, Basic(e))) + result = Basic(d, Basic(b, c), Basic(a, Basic(f))) + assert subs(mapping)(expr) == result + +def test_subs_empty(): + assert subs({})(Basic(1, 2)) == Basic(1, 2) + +def test_typed(): + class A(Basic): + pass + class B(Basic): + pass + rmzeros = rm_id(lambda x: x == 0) + rmones = rm_id(lambda x: x == 1) + remove_something = typed({A: rmzeros, B: rmones}) + + assert remove_something(A(0, 1)) == A(1) + assert remove_something(B(0, 1)) == B(0) diff -Nru python3-sympy-0.7.2/sympy/strategies/tests/test_traverse.py python3-sympy-0.7.3/sympy/strategies/tests/test_traverse.py --- python3-sympy-0.7.2/sympy/strategies/tests/test_traverse.py 1970-01-01 00:00:00.000000000 +0000 +++ python3-sympy-0.7.3/sympy/strategies/tests/test_traverse.py 2013-07-13 17:53:32.000000000 +0000 @@ -0,0 +1,64 @@ +from sympy.strategies.traverse import (top_down, bottom_up, sall, top_down_once, + bottom_up_once, expr_fns, basic_fns) +from sympy import Basic, symbols, Symbol, S + +zero_symbols = lambda x: S.Zero if isinstance(x, Symbol) else x +x,y,z = symbols('x,y,z') + +def test_sall(): + zero_onelevel = sall(zero_symbols) + + assert zero_onelevel(Basic(x, y, Basic(x, z))) == \ + Basic(0, 0, Basic(x, z)) + +def test_bottom_up(): + _test_global_traversal(bottom_up) + _test_stop_on_non_basics(bottom_up) + +def test_top_down(): + _test_global_traversal(top_down) + _test_stop_on_non_basics(top_down) + +def _test_global_traversal(trav): + x,y,z = symbols('x,y,z') + zero_all_symbols = trav(zero_symbols) + + assert zero_all_symbols(Basic(x, y, Basic(x, z))) == \ + Basic(0, 0, Basic(0, 0)) + +def _test_stop_on_non_basics(trav): + def add_one_if_can(expr): + try: return expr + 1 + except: return expr + + expr = Basic(1, 'a', Basic(2, 'b')) + expected = Basic(2, 'a', Basic(3, 'b')) + rl = trav(add_one_if_can) + + assert rl(expr) == expected + +class Basic2(Basic): + pass +rl = lambda x: Basic2(*x.args) if isinstance(x, Basic) else x + +def test_top_down_once(): + top_rl = top_down_once(rl) + + assert top_rl(Basic(1, 2, Basic(3, 4))) == \ + Basic2(1, 2, Basic(3, 4)) + +def test_bottom_up_once(): + bottom_rl = bottom_up_once(rl) + + assert bottom_rl(Basic(1, 2, Basic(3, 4))) == \ + Basic(1, 2, Basic2(3, 4)) + +def test_expr_fns(): + from sympy.strategies.rl import rebuild + x, y = list(map(Symbol, 'xy')) + expr = x + y**3 + e = bottom_up(lambda x: x + 1, expr_fns)(expr) + b = bottom_up(lambda x: x + 1, basic_fns)(expr) + + assert b == e + assert rebuild(b) == e diff -Nru python3-sympy-0.7.2/sympy/strategies/tests/test_tree.py python3-sympy-0.7.3/sympy/strategies/tests/test_tree.py --- python3-sympy-0.7.2/sympy/strategies/tests/test_tree.py 1970-01-01 00:00:00.000000000 +0000 +++ python3-sympy-0.7.3/sympy/strategies/tests/test_tree.py 2013-07-13 17:53:32.000000000 +0000 @@ -0,0 +1,79 @@ +from sympy.strategies.tree import (treeapply, treeapply, greedy, allresults, + brute) +from functools import partial +from functools import reduce + +def test_treeapply(): + tree = ([3, 3], [4, 1], 2) + assert treeapply(tree, {list: min, tuple: max}) == 3 + + add = lambda *args: sum(args) + mul = lambda *args: reduce(lambda a, b: a*b, args, 1) + assert treeapply(tree, {list: add, tuple: mul}) == 60 + +def test_treeapply_leaf(): + assert treeapply(3, {}, leaf=lambda x: x**2) == 9 + tree = ([3, 3], [4, 1], 2) + treep1 = ([4, 4], [5, 2], 3) + assert treeapply(tree, {list: min, tuple: max}, leaf=lambda x: x+1) == \ + treeapply(treep1, {list: min, tuple: max}) + +def test_treeapply_strategies(): + from sympy.strategies import chain, minimize + join = {list: chain, tuple: minimize} + inc = lambda x: x + 1 + dec = lambda x: x - 1 + double = lambda x: 2*x + + assert treeapply(inc, join) == inc + assert treeapply((inc, dec), join)(5) == minimize(inc, dec)(5) + assert treeapply([inc, dec], join)(5) == chain(inc, dec)(5) + tree = (inc, [dec, double]) # either inc or dec-then-double + assert treeapply(tree, join)(5) == 6 + assert treeapply(tree, join)(1) == 0 + + maximize = partial(minimize, objective=lambda x: -x) + join = {list: chain, tuple: maximize} + fn = treeapply(tree, join) + assert fn(4) == 6 # highest value comes from the dec then double + assert fn(1) == 2 # highest value comes from the inc + +def test_greedy(): + inc = lambda x: x + 1 + dec = lambda x: x - 1 + double = lambda x: 2*x + tree = [inc, (dec, double)] # either inc or dec-then-double + + fn = greedy(tree, objective=lambda x: -x) + assert fn(4) == 6 # highest value comes from the dec then double + assert fn(1) == 2 # highest value comes from the inc + + tree = [inc, dec, [inc, dec, [(inc, inc), (dec, dec)]]] + lowest = greedy(tree) + assert lowest(10) == 8 + + highest = greedy(tree, objective=lambda x: -x) + assert highest(10) == 12 + +def test_allresults(): + inc = lambda x: x+1 + dec = lambda x: x-1 + double = lambda x: x*2 + square = lambda x: x**2 + + assert set(allresults(inc)(3)) == set([inc(3)]) + assert set(allresults([inc, dec])(3)) == set([2, 4]) + assert set(allresults((inc, dec))(3)) == set([3]) + assert set(allresults([inc, (dec, double)])(4)) == set([5, 6]) + +def test_brute(): + inc = lambda x: x+1 + dec = lambda x: x-1 + square = lambda x: x**2 + tree = ([inc, dec], square) + fn = brute(tree, lambda x: -x) + + assert fn(2) == (2 + 1)**2 + assert fn(-2) == (-2 - 1)**2 + + assert brute(inc)(1) == 2 diff -Nru python3-sympy-0.7.2/sympy/strategies/tools.py python3-sympy-0.7.3/sympy/strategies/tools.py --- python3-sympy-0.7.2/sympy/strategies/tools.py 1970-01-01 00:00:00.000000000 +0000 +++ python3-sympy-0.7.3/sympy/strategies/tools.py 2013-07-13 17:53:32.000000000 +0000 @@ -0,0 +1,44 @@ +from . import rl +from .core import do_one, exhaust, switch +from .traverse import top_down + +def subs(d, **kwargs): + """ Full simultaneous exact substitution + + Example + ======= + + >>> from sympy.strategies.tools import subs + >>> from sympy import Basic + >>> mapping = {1: 4, 4: 1, Basic(5): Basic(6, 7)} + >>> expr = Basic(1, Basic(2, 3), Basic(4, Basic(5))) + >>> subs(mapping)(expr) + Basic(4, Basic(2, 3), Basic(1, Basic(6, 7))) + """ + if d: + return top_down(do_one(*list(map(rl.subs, *list(zip(*list(d.items())))))), **kwargs) + else: + return lambda x: x + +def canon(*rules, **kwargs): + """ Strategy for canonicalization + + Apply each rule in a bottom_up fashion through the tree. + Do each one in turn. + Keep doing this until there is no change. + """ + return exhaust(top_down(exhaust(do_one(*rules)), **kwargs)) + +def typed(ruletypes): + """ Apply rules based on the expression type + + inputs: + ruletypes -- a dict mapping {Type: rule} + + >>> from sympy.strategies import rm_id, typed + >>> from sympy import Add, Mul + >>> rm_zeros = rm_id(lambda x: x==0) + >>> rm_ones = rm_id(lambda x: x==1) + >>> remove_idents = typed({Add: rm_zeros, Mul: rm_ones}) + """ + return switch(type, ruletypes) diff -Nru python3-sympy-0.7.2/sympy/strategies/traverse.py python3-sympy-0.7.3/sympy/strategies/traverse.py --- python3-sympy-0.7.2/sympy/strategies/traverse.py 1970-01-01 00:00:00.000000000 +0000 +++ python3-sympy-0.7.3/sympy/strategies/traverse.py 2013-07-13 17:53:32.000000000 +0000 @@ -0,0 +1,30 @@ +""" Strategies to Traverse a Tree """ +from .util import basic_fns, expr_fns +from sympy.strategies.core import chain, do_one + +def top_down(rule, fns=basic_fns): + """ Apply a rule down a tree running it on the top nodes first """ + return chain(rule, lambda expr: sall(top_down(rule, fns), fns)(expr)) + +def bottom_up(rule, fns=basic_fns): + """ Apply a rule down a tree running it on the bottom nodes first """ + return chain(lambda expr: sall(bottom_up(rule, fns), fns)(expr), rule) + +def top_down_once(rule, fns=basic_fns): + """ Apply a rule down a tree - stop on success """ + return do_one(rule, lambda expr: sall(top_down(rule, fns), fns)(expr)) + +def bottom_up_once(rule, fns=basic_fns): + """ Apply a rule up a tree - stop on success """ + return do_one(lambda expr: sall(bottom_up(rule, fns), fns)(expr), rule) + +def sall(rule, fns=basic_fns): + """ Strategic all - apply rule to args """ + op, new, children, leaf = list(map(fns.get, ('op', 'new', 'children', 'leaf'))) + def all_rl(expr): + if leaf(expr): + return expr + else: + args = list(map(rule, children(expr))) + return new(op(expr), *args) + return all_rl diff -Nru python3-sympy-0.7.2/sympy/strategies/tree.py python3-sympy-0.7.3/sympy/strategies/tree.py --- python3-sympy-0.7.2/sympy/strategies/tree.py 1970-01-01 00:00:00.000000000 +0000 +++ python3-sympy-0.7.3/sympy/strategies/tree.py 2013-07-13 17:53:32.000000000 +0000 @@ -0,0 +1,133 @@ +from functools import partial +from sympy.strategies import chain, minimize +import sympy.strategies.branch as branch +from sympy.strategies.branch import yieldify + +identity = lambda x: x + +def treeapply(tree, join, leaf=identity): + """ Apply functions onto recursive containers (tree) + + join - a dictionary mapping container types to functions + e.g. ``{list: minimize, tuple: chain}`` + + Keys are containers/iterables. Values are functions [a] -> a. + + Examples + -------- + + >>> from sympy.strategies.tree import treeapply + >>> tree = [(3, 2), (4, 1)] + >>> treeapply(tree, {list: max, tuple: min}) + 2 + + >>> add = lambda *args: sum(args) + >>> def mul(*args): + ... total = 1 + ... for arg in args: + ... total *= arg + ... return total + >>> treeapply(tree, {list: mul, tuple: add}) + 25 + """ + for typ in join: + if isinstance(tree, typ): + return join[typ](*list(map(partial(treeapply, join=join, leaf=leaf), + tree))) + return leaf(tree) + +def greedy(tree, objective=identity, **kwargs): + """ Execute a strategic tree. Select alternatives greedily + + Trees + ----- + + Nodes in a tree can be either + + function - a leaf + list - a selection among operations + tuple - a sequence of chained operations + + Textual examples + ---------------- + + Text: Run f, then run g, e.g. ``lambda x: g(f(x))`` + Code: ``(f, g)`` + + Text: Run either f or g, whichever minimizes the objective + Code: ``[f, g]`` + + Textx: Run either f or g, whichever is better, then run h + Code: ``([f, g], h)`` + + Text: Either expand then simplify or try factor then foosimp. Finally print + Code: ``([(expand, simplify), (factor, foosimp)], print)`` + + Objective + --------- + + "Better" is determined by the objective keyword. This function makes + choices to minimize the objective. It defaults to the identity. + + Example + ------- + + >>> from sympy.strategies.tree import greedy + >>> inc = lambda x: x + 1 + >>> dec = lambda x: x - 1 + >>> double = lambda x: 2*x + + >>> tree = [inc, (dec, double)] # either inc or dec-then-double + >>> fn = greedy(tree) + >>> fn(4) # lowest value comes from the inc + 5 + >>> fn(1) # lowest value comes from dec then double + 0 + + This funcion selects between options in a tuple. The result is chosen that + minimizes the objective function. + + >>> fn = greedy(tree, objective=lambda x: -x) # maximize + >>> fn(4) # highest value comes from the dec then double + 6 + >>> fn(1) # highest value comes from the inc + 2 + + Greediness + ---------- + + This is a greedy algorithm. In the example: + + ([a, b], c) # do either a or b, then do c + + the choice between running ``a`` or ``b`` is made without foresight to c + """ + optimize = partial(minimize, objective=objective) + return treeapply(tree, {list: optimize, tuple: chain}, **kwargs) + +def allresults(tree, leaf=yieldify): + """ Execute a strategic tree. Return all possibilities. + + Returns a lazy iterator of all possible results + + Exhaustiveness + -------------- + + This is an exhaustive algorithm. In the example + + ([a, b], [c, d]) + + All of the results from + + (a, c), (b, c), (a, d), (b, d) + + are returned. This can lead to combinatorial blowup. + + See sympy.strategies.greedy for details on input + """ + return treeapply(tree, {list: branch.multiplex, tuple: branch.chain}, + leaf=leaf) + +def brute(tree, objective=identity, **kwargs): + return lambda expr: min(tuple(allresults(tree, **kwargs)(expr)), + key=objective) diff -Nru python3-sympy-0.7.2/sympy/strategies/util.py python3-sympy-0.7.3/sympy/strategies/util.py --- python3-sympy-0.7.2/sympy/strategies/util.py 1970-01-01 00:00:00.000000000 +0000 +++ python3-sympy-0.7.3/sympy/strategies/util.py 2013-07-13 17:53:32.000000000 +0000 @@ -0,0 +1,15 @@ +from sympy import Basic + +new = Basic.__new__ + +def assoc(d, k, v): + d = d.copy() + d[k] = v + return d + +basic_fns = {'op': type, + 'new': Basic.__new__, + 'leaf': lambda x: not isinstance(x, Basic) or x.is_Atom, + 'children': lambda x: x.args} + +expr_fns = assoc(basic_fns, 'new', lambda op, *args: op(*args)) diff -Nru python3-sympy-0.7.2/sympy/tensor/index_methods.py python3-sympy-0.7.3/sympy/tensor/index_methods.py --- python3-sympy-0.7.2/sympy/tensor/index_methods.py 2012-10-17 03:02:22.000000000 +0000 +++ python3-sympy-0.7.3/sympy/tensor/index_methods.py 2013-07-13 17:53:32.000000000 +0000 @@ -17,9 +17,11 @@ from sympy.core.compatibility import reduce from functools import reduce + class IndexConformanceException(Exception): pass + def _remove_repeated(inds): """Removes repeated objects from sequences @@ -41,6 +43,7 @@ inds = [x for x in inds if not sum_index[x]] return set(inds), tuple([ i for i in sum_index if sum_index[i] ]) + def _get_indices_Mul(expr, return_dummies=False): """Determine the outer indices of a Mul object. @@ -76,6 +79,7 @@ else: return inds, symmetry + def _get_indices_Pow(expr): """Determine outer indices of a power or an exponential. @@ -124,6 +128,7 @@ return inds, symmetries + def _get_indices_Add(expr): """Determine outer indices of an Add object. @@ -157,8 +162,8 @@ return set(), {} if not all([x == non_scalars[0] for x in non_scalars[1:]]): - raise IndexConformanceException("Indices are not consistent: %s"%expr) - if not reduce(lambda x, y: x!=y or y, syms): + raise IndexConformanceException("Indices are not consistent: %s" % expr) + if not reduce(lambda x, y: x != y or y, syms): symmetries = syms[0] else: # FIXME: search for symmetries @@ -166,6 +171,7 @@ return non_scalars[0], symmetries + def get_indices(expr): """Determine the outer indices of expression ``expr`` @@ -258,10 +264,11 @@ elif not expr.has(Indexed): return set(), {} raise NotImplementedError( - "FIXME: No specialized handling of type %s"%type(expr)) + "FIXME: No specialized handling of type %s" % type(expr)) + def get_contraction_structure(expr): - """Determine dummy indices of ``expr`` and describe it's structure + """Determine dummy indices of ``expr`` and describe its structure By *dummy* we mean indices that are summation indices. @@ -275,7 +282,7 @@ 2) For all nodes in the SymPy expression tree that are *not* of type Add, the following applies: - If a node discovers contractions in one of it's arguments, the node + If a node discovers contractions in one of its arguments, the node itself will be stored as a key in the dict. For that key, the corresponding value is a list of dicts, each of which is the result of a recursive call to get_contraction_structure(). The list contains only @@ -308,9 +315,15 @@ >>> d = get_contraction_structure(x[i, i]*y[j, j]) >>> sorted(list(d.keys()), key=default_sort_key) [None, x[i, i]*y[j, j]] - >>> d[None] # Note that the product has no contractions + + In this case, the product has no contractions: + + >>> d[None] set([x[i, i]*y[j, j]]) - >>> sorted(d[x[i, i]*y[j, j]], key=default_sort_key) # factors are contracted ''first'' + + Factors are contracted "first": + + >>> sorted(d[x[i, i]*y[j, j]], key=default_sort_key) [{(i,): set([x[i, i]])}, {(j,): set([y[j, j]])}] A parenthesized Add object is also returned as a nested dictionary. The @@ -425,4 +438,4 @@ elif not expr.has(Indexed): return {None: set([expr])} raise NotImplementedError( - "FIXME: No specialized handling of type %s"%type(expr)) + "FIXME: No specialized handling of type %s" % type(expr)) diff -Nru python3-sympy-0.7.2/sympy/tensor/indexed.py python3-sympy-0.7.3/sympy/tensor/indexed.py --- python3-sympy-0.7.2/sympy/tensor/indexed.py 2012-10-17 03:02:22.000000000 +0000 +++ python3-sympy-0.7.3/sympy/tensor/indexed.py 2013-07-13 17:53:32.000000000 +0000 @@ -34,7 +34,7 @@ >>> from sympy.tensor import IndexedBase, Idx >>> from sympy import symbols >>> M = IndexedBase('M') - >>> i, j = list(map(Idx, ['i', 'j'])) + >>> i, j = symbols('i j', cls=Idx) >>> M[i, j] M[i, j] @@ -58,7 +58,7 @@ (dim1, 2*dim1, dim2) If an IndexedBase object has no shape information, it is assumed that the - array is as large as the ranges of it's indices: + array is as large as the ranges of its indices: >>> n, m = symbols('n m', integer=True) >>> i = Idx('i', m) @@ -109,15 +109,17 @@ from sympy.core import Expr, Tuple, Symbol, sympify, S from sympy.core.compatibility import is_sequence + class IndexException(Exception): pass + class Indexed(Expr): """Represents a mathematical object with indices. >>> from sympy.tensor import Indexed, IndexedBase, Idx >>> from sympy import symbols - >>> i, j = list(map(Idx, ['i', 'j'])) + >>> i, j = symbols('i j', cls=Idx) >>> Indexed('A', i, j) A[i, j] @@ -140,6 +142,7 @@ elif not isinstance(base, IndexedBase): raise TypeError(filldedent(""" Indexed expects string, Symbol or IndexedBase as base.""")) + args = list(map(sympify, args)) return Expr.__new__(cls, base, *args, **kw_args) @property @@ -150,7 +153,8 @@ ======== >>> from sympy.tensor import Indexed, IndexedBase, Idx - >>> i, j = list(map(Idx, ['i', 'j'])) + >>> from sympy import symbols + >>> i, j = symbols('i j', cls=Idx) >>> Indexed('A', i, j).base A >>> B = IndexedBase('B') @@ -169,7 +173,8 @@ ======== >>> from sympy.tensor import Indexed, Idx - >>> i, j = list(map(Idx, ['i', 'j'])) + >>> from sympy import symbols + >>> i, j = symbols('i j', cls=Idx) >>> Indexed('A', i, j).indices (i, j) @@ -185,7 +190,8 @@ ======== >>> from sympy.tensor import Indexed, Idx - >>> i, j, k, l, m = list(map(Idx, ['i', 'j', 'k', 'l', 'm'])) + >>> from sympy import symbols + >>> i, j, k, l, m = symbols('i:m', cls=Idx) >>> Indexed('A', i, j).rank 2 >>> q = Indexed('A', i, j, k, l, m) @@ -195,7 +201,7 @@ True """ - return len(self.args)-1 + return len(self.args) - 1 @property def shape(self): @@ -292,7 +298,7 @@ >>> type(A) - When an IndexedBase object recieves indices, it returns an array with named + When an IndexedBase object receives indices, it returns an array with named axes, represented by an Indexed object: >>> i, j = symbols('i j', integer=True) @@ -326,7 +332,7 @@ if is_sequence(shape): obj._shape = Tuple(*shape) else: - obj._shape = shape + obj._shape = sympify(shape) return obj @property diff -Nru python3-sympy-0.7.2/sympy/tensor/tensor.py python3-sympy-0.7.3/sympy/tensor/tensor.py --- python3-sympy-0.7.2/sympy/tensor/tensor.py 1970-01-01 00:00:00.000000000 +0000 +++ python3-sympy-0.7.3/sympy/tensor/tensor.py 2013-07-13 17:53:32.000000000 +0000 @@ -0,0 +1,2185 @@ +""" +This module defines tensors with abstract index notation. + +The abstract index notation has been first formalized by Penrose. + +Tensor indices are formal objects, with a tensor type; there is no +notion of index range, it is only possible to assign the dimension, +used to trace the Kronecker delta; the dimension can be a Symbol. + +The Einstein summation convention is used. +The covariant indices are indicated with a minus sign in front of the index. + +For instance the tensor ``t = p(a)*A(b,c)*q(-c)`` has the index ``c`` +contracted. + +A tensor expression ``t`` can be called; called with its +indices in sorted order it is equal to itself: +in the above example ``t(a, b) == t``; +one can call ``t`` with different indices; ``t(c, d) == p(c)*A(d,a)*q(-a)``. + +The contracted indices are dummy indices, internally they have no name, +the indices being represented by a graph-like structure. + +Tensors are put in canonical form using ``canon_bp``, which uses +the Butler-Portugal algorithm for canonicalization using the monoterm +symmetries of the tensors. + +If there is a (anti)symmetric metric, the indices can be raised and +lowered when the tensor is put in canonical form. +""" + + +from collections import defaultdict +from sympy.core import Basic, sympify, Add, Mul, S +from sympy.core.symbol import Symbol, symbols +from sympy.combinatorics.tensor_can import get_symmetric_group_sgs, bsgs_direct_product, canonicalize, riemann_bsgs + +class _TensorManager(object): + """ + Class to manage tensor properties. + + Notes + ===== + + Tensors belong to tensor commutation groups; each group has a label + ``comm``; there are predefined labels: + + ``0`` tensors commuting with any other tensor + + ``1`` tensors anticommuting among themselves + + ``2`` tensors not commuting, apart with those with ``comm=0`` + + Other groups can be defined using ``set_comm``; tensors in those + groups commute with those with ``comm=0``; by default they + do not commute with any other group. + """ + def __init__(self): + self._comm_init() + + def _comm_init(self): + self._comm = [{} for i in range(3)] + for i in range(3): + self._comm[0][i] = 0 + self._comm[i][0] = 0 + self._comm[1][1] = 1 + self._comm[2][1] = None + self._comm[1][2] = None + self._comm_symbols2i = {0:0, 1:1, 2:2} + self._comm_i2symbol = {0:0, 1:1, 2:2} + + @property + def comm(self): + return self._comm + + def comm_symbols2i(self, i): + """ + get the commutation group number corresponding to ``i`` + + ``i`` can be a symbol or a number or a string + + If ``i`` is not already defined its commutation group number + is set. + """ + if i not in self._comm_symbols2i: + n = len(self._comm) + self._comm.append({}) + self._comm[n][0] = 0 + self._comm[0][n] = 0 + self._comm_symbols2i[i] = n + self._comm_i2symbol[n] = i + return n + return self._comm_symbols2i[i] + + def comm_i2symbol(self, i): + """ + Returns the symbol corresponding to the commutation group number. + """ + return self._comm_i2symbol[i] + + def set_comm(self, i, j, c): + """ + set the commutation parameter ``c`` for commutation groups ``i, j`` + + Parameters + ========== + + i, j : symbols representing commutation groups + + c : group commutation number + + Notes + ===== + + ``i, j`` can be symbols, strings or numbers, + apart from ``0, 1`` and ``2`` which are reserved respectively + for commuting, anticommuting tensors and tensors not commuting + with any other group apart with the commuting tensors. + For the remaining cases, use this method to set the commutation rules; + by default ``c=None``. + + The group commutation number ``c`` is assigned in corrispondence + to the group commutation symbols; it can be + + 0 commuting + + 1 anticommuting + + None no commutation property + + Examples + ======== + + ``G`` and ``GH`` do not commute with themselves and commute with + each other; A is commuting. + + >>> from sympy.tensor.tensor import TensorIndexType, tensor_indices, tensorhead, TensorManager + >>> Lorentz = TensorIndexType('Lorentz') + >>> i0,i1,i2,i3,i4 = tensor_indices('i0:5', Lorentz) + >>> A = tensorhead('A', [Lorentz], [[1]]) + >>> G = tensorhead('G', [Lorentz], [[1]], 'Gcomm') + >>> GH = tensorhead('GH', [Lorentz], [[1]], 'GHcomm') + >>> TensorManager.set_comm('Gcomm', 'GHcomm', 0) + >>> (GH(i1)*G(i0)).canon_bp() + G(i0)*GH(i1) + >>> (G(i1)*G(i0)).canon_bp() + G(i1)*G(i0) + >>> (G(i1)*A(i0)).canon_bp() + A(i0)*G(i1) + """ + if c not in (0, 1, None): + raise ValueError('`c` can assume only the values 0, 1 or None') + + if i not in self._comm_symbols2i: + n = len(self._comm) + self._comm.append({}) + self._comm[n][0] = 0 + self._comm[0][n] = 0 + self._comm_symbols2i[i] = n + self._comm_i2symbol[n] = i + if j not in self._comm_symbols2i: + n = len(self._comm) + self._comm.append({}) + self._comm[0][n] = 0 + self._comm[n][0] = 0 + self._comm_symbols2i[j] = n + self._comm_i2symbol[n] = j + ni = self._comm_symbols2i[i] + nj = self._comm_symbols2i[j] + self._comm[ni][nj] = c + self._comm[nj][ni] = c + + def set_comms(self, *args): + """ + set the commutation group numbers ``c`` for symbols ``i, j`` + + Parameters + ========== + + args : sequence of ``(i, j, c)`` + """ + for i, j, c in args: + self.set_comm(i, j, c) + + def get_comm(self, i, j): + """ + Return the commutation parameter for commutation group numbers ``i, j`` + + see ``_TensorManager.set_comm`` + """ + return self._comm[i].get(j, 0 if i == 0 or j == 0 else None) + + def clear(self): + """ + Clear the TensorManager. + """ + self._comm_init() + + +TensorManager = _TensorManager() + +class TensorIndexType(Basic): + """ + A TensorIndexType is characterized by its name and its metric. + + Parameters + ========== + + name : name of the tensor type + + metric : metric symmetry or metric object or ``None`` + + + dim : dimension, it can be a symbol or an integer or ``None`` + + eps_dim : dimension of the epsilon tensor + + dummy_fmt : name of the head of dummy indices + + Attributes + ========== + + ``name`` + ``metric_name`` : it is 'metric' or metric.name + ``metric_antisym`` + ``metric`` : the metric tensor + ``delta`` : ``Kronecker delta`` + ``epsilon`` : the ``Levi-Civita epsilon`` tensor + ``dim`` + ``dim_eps`` + ``dummy_fmt`` + + Notes + ===== + + The ``metric`` parameter can be: + ``metric = False`` symmetric metric (in Riemannian geometry) + + ``metric = True`` antisymmetric metric (for spinor calculus) + + ``metric = None`` there is no metric + + ``metric`` can be an object having ``name`` and ``antisym`` attributes. + + + If there is a metric the metric is used to raise and lower indices. + + In the case of antisymmetric metric, the following raising and + lowering conventions will be adopted: + + ``psi(a) = g(a, b)*psi(-b); chi(-a) = chi(b)*g(-b, -a)`` + + ``g(-a, b) = delta(-a, b); g(b, -a) = -delta(a, -b)`` + + where ``delta(-a, b) = delta(b, -a)`` is the ``Kronecker delta`` + (see ``TensorIndex`` for the conventions on indices). + + If there is no metric it is not possible to raise or lower indices; + e.g. the index of the defining representation of ``SU(N)`` + is 'covariant' and the conjugate representation is + 'contravariant'; for ``N > 2`` they are linearly independent. + + ``eps_dim`` is by default equal to ``dim``, if the latter is an integer; + else it can be assigned (for use in naive dimensional regularization); + if ``eps_dim`` is not an integer ``epsilon`` is ``None``. + + Examples + ======== + + >>> from sympy.tensor.tensor import TensorIndexType + >>> Lorentz = TensorIndexType('Lorentz', dummy_fmt='L') + >>> Lorentz.metric + metric(Lorentz,Lorentz) + """ + + def __new__(cls, name, metric=False, dim=None, eps_dim = None, + dummy_fmt=None): + obj = Basic.__new__(cls, name, metric) + obj._name = name + if not dummy_fmt: + obj._dummy_fmt = '%s_%%d' % obj.name + else: + obj._dummy_fmt = '%s_%%d' % dummy_fmt + if metric is None: + obj.metric_antisym = None + obj.metric = None + else: + if metric in (True, False, 0, 1): + metric_name = 'metric' + obj.metric_antisym = metric + else: + metric_name = metric.name + obj.metric_antisym = metric.antisym + sym2 = TensorSymmetry(get_symmetric_group_sgs(2, obj.metric_antisym)) + S2 = TensorType([obj]*2, sym2) + obj.metric = S2(metric_name) + + obj._dim = dim + obj._delta = obj.get_kronecker_delta() + obj._eps_dim = eps_dim if eps_dim else dim + obj._epsilon = obj.get_epsilon() + return obj + + @property + def name(self): + return self._name + + @property + def dim(self): + return self._dim + + @property + def delta(self): + return self._delta + + @property + def eps_dim(self): + return self._eps_dim + + @property + def epsilon(self): + return self._epsilon + + @property + def dummy_fmt(self): + return self._dummy_fmt + + def get_kronecker_delta(self): + sym2 = TensorSymmetry(get_symmetric_group_sgs(2)) + S2 = TensorType([self]*2, sym2) + delta = S2('KD') + return delta + + def get_epsilon(self): + if not isinstance(self._eps_dim, int): + return None + sym = TensorSymmetry(get_symmetric_group_sgs(self._eps_dim, 1)) + Sdim = TensorType([self]*self._eps_dim, sym) + epsilon = Sdim('Eps') + return epsilon + + def __lt__(self, other): + return self.name < other.name + + def __str__(self): + return self.name + + __repr__ = __str__ + +class TensorIndex(Basic): + """ + Represents an abstract tensor index. + + Parameters + ========== + + name : name of the index + tensortype : ``TensorIndexType`` of the index + is_up : flag for contravariant index + + Attributes + ========== + + ``name`` + ``tensortype`` + ``is_up`` + + Notes + ===== + + Tensor indices are contracted with the Einstein summation convention. + + An index can be in contravariant or in covariant form; in the latter + case it is represented prepending a ``-`` to the index name. + + Dummy indices have a name with head given by ``tensortype.dummy_fmt`` + + + Examples + ======== + + >>> from sympy.tensor.tensor import TensorIndexType, TensorIndex, TensorSymmetry, TensorType, get_symmetric_group_sgs + >>> Lorentz = TensorIndexType('Lorentz', dummy_fmt='L') + >>> i = TensorIndex('i', Lorentz); i + i + >>> sym1 = TensorSymmetry(get_symmetric_group_sgs(1)) + >>> S1 = TensorType([Lorentz], sym1) + >>> A, B = S1('A,B') + >>> A(i)*B(-i) + A(L_0)*B(-L_0) + """ + def __new__(cls, name, tensortype, is_up=True): + + obj = Basic.__new__(cls, name, tensortype, is_up) + obj._name = name + obj._tensortype = tensortype + obj._is_up = is_up + return obj + + @property + def name(self): + return self._name + + @property + def tensortype(self): + return self._tensortype + + @property + def is_up(self): + return self._is_up + + def _pretty(self): + s = self._name + if not self._is_up: + s = '-%s' % s + return s + + def __lt__(self, other): + return (self._tensortype, self._name) < (other._tensortype, other._name) + + def __neg__(self): + t1 = TensorIndex(self._name, self._tensortype, + (not self._is_up)) + return t1 + +def tensor_indices(s, typ): + """ + Returns list of tensor indices given their names and their types + + Parameters + ========== + + s : string of comma separated names of indices + + typ : list of ``TensorIndexType`` of the indices + + Examples + ======== + + >>> from sympy.tensor.tensor import TensorIndexType, tensor_indices + >>> Lorentz = TensorIndexType('Lorentz', dummy_fmt='L') + >>> a, b, c, d = tensor_indices('a,b,c,d', Lorentz) + """ + if isinstance(s, str): + a = [x.name for x in symbols(s, seq=True)] + else: + raise ValueError('expecting a string') + + return [TensorIndex(i, typ) for i in a] + + +class TensorSymmetry(Basic): + """ + Monoterm symmetry of a tensor + + Parameters + ========== + + bsgs : tuple ``(base, sgs)`` BSGS of the symmetry of the tensor + + Attributes + ========== + + ``base`` : base of the BSGS + ``generators`` : generators of the BSGS + ``rank`` : rank of the tensor + + Notes + ===== + + A tensor can have an arbitrary monoterm symmetry provided by its BSGS. + Multiterm symmetries, like the cyclic symmetry of the Riemann tensor, + are not covered. + + See Also + ======== + + sympy.combinatorics.tensor_can.get_symmetric_group_sgs + + Examples + ======== + + Define a symmetric tensor + + >>> from sympy.tensor.tensor import TensorIndexType, tensor_indices, TensorSymmetry, TensorType, get_symmetric_group_sgs + >>> Lorentz = TensorIndexType('Lorentz', dummy_fmt='L') + >>> sym2 = TensorSymmetry(get_symmetric_group_sgs(2)) + >>> S2 = TensorType([Lorentz]*2, sym2) + >>> V = S2('V') + """ + def __new__(cls, bsgs, **kw_args): + base, generators = bsgs + obj = Basic.__new__(cls, base, generators, **kw_args) + return obj + + @property + def base(self): + return self.args[0] + + @property + def generators(self): + return self.args[1] + + @property + def rank(self): + return self.args[1][0].size - 2 + + def _hashable_content(self): + r = (tuple(self.base), tuple(self.generators)) + return r + + +def tensorsymmetry(*args): + """ + Return a ``TensorSymmetry`` object. + + One can represent a tensor with any monoterm slot symmetry group + using a BSGS. + + ``args`` can be a BSGS + ``args[0]`` base + ``args[1]`` sgs + + Usually tensors are in (direct products of) representations + of the symmetric group; + ``args`` can be a list of lists representing the shapes of Young tableaux + + Notes + ===== + + For instance: + ``[[1]]`` vector + ``[[1]*n]`` symmetric tensor of rank ``n`` + ``[[n]]`` antisymmetric tensor of rank ``n`` + ``[[2, 2]]`` monoterm slot symmetry of the Riemann tensor + ``[[1],[1]]`` vector*vector + ``[[2],[1],[1]`` (antisymmetric tensor)*vector*vector + + Notice that with the shape ``[2, 2]`` we associate only the monoterm + symmetries of the Riemann tensor; this is an abuse of notation, + since the shape ``[2, 2]`` corresponds usually to the irreducible + representation characterized by the monoterm symmetries and by the + cyclic symmetry. + + Examples + ======== + + Symmetric tensor using a Young tableau + + >>> from sympy.tensor.tensor import TensorIndexType, TensorType, tensorsymmetry + >>> Lorentz = TensorIndexType('Lorentz', dummy_fmt='L') + >>> sym2 = tensorsymmetry([1, 1]) + >>> S2 = TensorType([Lorentz]*2, sym2) + >>> V = S2('V') + + Symmetric tensor using a BSGS + >>> from sympy.tensor.tensor import TensorSymmetry, get_symmetric_group_sgs + >>> sym2 = tensorsymmetry(*get_symmetric_group_sgs(2)) + >>> S2 = TensorType([Lorentz]*2, sym2) + >>> V = S2('V') + """ + from sympy.combinatorics import Permutation + def tableau2bsgs(a): + if len(a) == 1: + # antisymmetric vector + n = a[0] + bsgs = get_symmetric_group_sgs(n, 1) + else: + if all(x == 1 for x in a): + # symmetric vector + n = len(a) + bsgs = get_symmetric_group_sgs(n) + elif a == [2, 2]: + bsgs = riemann_bsgs + else: + raise NotImplementedError + return bsgs + + if not args: + return TensorSymmetry([[], [Permutation(1)]]) + if len(args) == 2 and isinstance(args[1][0], Permutation): + return TensorSymmetry(args) + base, sgs = tableau2bsgs(args[0]) + for a in args[1:]: + basex, sgsx = tableau2bsgs(a) + base, sgs = bsgs_direct_product(base, sgs, basex, sgsx) + return TensorSymmetry((base, sgs)) + + +class TensorType(Basic): + """ + Class of tensor types. + + Parameters + ========== + + index_types : list of ``TensorIndexType`` of the tensor indices + symmetry : ``TensorSymmetry`` of the tensor + + Attributes + ========== + + ``index_types`` + ``symmetry`` + ``types`` : list of ``TensorIndexType`` without repetitions + + Examples + ======== + + Define a symmetric tensor + + >>> from sympy.tensor.tensor import TensorIndexType, tensorsymmetry, TensorType + >>> Lorentz = TensorIndexType('Lorentz', dummy_fmt='L') + >>> sym2 = tensorsymmetry([1, 1]) + >>> S2 = TensorType([Lorentz]*2, sym2) + >>> V = S2('V') + """ + is_commutative = False + + def __new__(cls, index_types, symmetry, **kw_args): + assert symmetry.rank == len(index_types) + obj = Basic.__new__(cls, index_types, symmetry, **kw_args) + return obj + + @property + def index_types(self): + return self.args[0] + + @property + def symmetry(self): + return self.args[1] + + @property + def types(self): + return sorted(set(self.index_types), key=lambda x: x.name) + + def __str__(self): + return 'TensorType(%s)' %([str(x) for x in self.index_types]) + + def __call__(self, s, comm=0): + """ + Return a TensorHead object or a list of TensorHead objects. + + ``s`` name or string of names + + ``comm``: commutation group number + see ``_TensorManager.set_comm`` + + Examples + ======== + + Define symmetric tensors ``V``, ``W`` and ``G``, respectively + commuting, anticommuting and with no commutation symmetry + + >>> from sympy.tensor.tensor import TensorIndexType, tensor_indices, tensorsymmetry, TensorType, canon_bp + >>> Lorentz = TensorIndexType('Lorentz', dummy_fmt='L') + >>> a, b = tensor_indices('a,b', Lorentz) + >>> sym2 = tensorsymmetry([1]*2) + >>> S2 = TensorType([Lorentz]*2, sym2) + >>> V = S2('V') + >>> W = S2('W', 1) + >>> G = S2('G', 2) + >>> canon_bp(V(a, b)*V(-b, -a)) + V(L_0, L_1)*V(-L_0, -L_1) + >>> canon_bp(W(a, b)*W(-b, -a)) + 0 + """ + if isinstance(s, str): + names = [x.name for x in symbols(s, seq=True)] + else: + raise ValueError('expecting a string') + if len(names) == 1: + return TensorHead(names[0], self, comm) + else: + return [TensorHead(name, self, comm) for name in names] + +def tensorhead(name, typ, sym, comm=0): + """ + Function generating tensorhead(s). + + Parameters + ========== + + name : name or sequence of names (as in ``symbol``) + + typ : index types + + sym : same as ``*args`` in ``tensorsymmetry`` + + comm : commutation group number + see ``_TensorManager.set_comm`` + + + Examples + ======== + + >>> from sympy.tensor.tensor import TensorIndexType, tensor_indices, tensorhead + >>> Lorentz = TensorIndexType('Lorentz', dummy_fmt='L') + >>> a, b = tensor_indices('a,b', Lorentz) + >>> A = tensorhead('A', [Lorentz]*2, [[1]*2]) + >>> A(a, -b) + A(a, -b) + + """ + sym = tensorsymmetry(*sym) + S = TensorType(typ, sym) + return S(name, comm) + + +class TensorHead(Basic): + """ + Tensor head of the tensor + + Parameters + ========== + + name : name of the tensor + + typ : list of TensorIndexType + + comm : commutation group number + + Attributes + ========== + + ``name`` + ``index_types`` + ``rank`` + ``types`` : equal to ``typ.types`` + ``symmetry`` : equal to ``typ.symmetry`` + ``comm`` : commutation group + + Notes + ===== + + A ``TensorHead`` belongs to a commutation group, defined by a + symbol on number ``comm`` (see ``_TensorManager.set_comm``); + tensors in a commutation group have the same commutation properties; + by default ``comm`` is ``0``, the group of the commuting tensors. + + Examples + ======== + + >>> from sympy.tensor.tensor import TensorIndexType, tensorsymmetry, TensorType + >>> Lorentz = TensorIndexType('Lorentz', dummy_fmt='L') + >>> sym2 = tensorsymmetry([1]*2) + >>> S2 = TensorType([Lorentz]*2, sym2) + >>> A = S2('A') + """ + is_commutative = False + + def __new__(cls, name, typ, comm, **kw_args): + assert isinstance(name, str) + + obj = Basic.__new__(cls, name, typ, **kw_args) + obj._name = obj.args[0] + obj._rank = len(obj.index_types) + obj._types = typ.types + obj._symmetry = typ.symmetry + obj._comm = TensorManager.comm_symbols2i(comm) + return obj + + @property + def name(self): + return self._name + + @property + def rank(self): + return self._rank + + @property + def types(self): + return self._types[:] + + @property + def symmetry(self): + return self._symmetry + + @property + def typ(self): + return self.args[1] + + @property + def comm(self): + return self._comm + + @property + def index_types(self): + return self.args[1].index_types[:] + + def __lt__(self, other): + return (self.name, self.index_types) < (other.name, other.index_types) + + def _hashable_content(self): + r = (self._name, tuple(self._types), self._symmetry, self._comm) + return r + + def commutes_with(self, other): + """ + Returns 0 (1) if self and other (anti)commute. + + Returns None if self and other do not (anti)commute. + """ + r = TensorManager.get_comm(self._comm, other._comm) + return r + + + def _pretty(self): + return '%s(%s)' %(self.name, ','.join([str(x) for x in self.index_types])) + + def __call__(self, *indices): + """ + Returns a tensor with indices. + + Examples + ======== + + >>> from sympy.tensor.tensor import TensorIndexType, tensor_indices, tensorhead + >>> Lorentz = TensorIndexType('Lorentz', dummy_fmt='L') + >>> a, b = tensor_indices('a,b', Lorentz) + >>> A = tensorhead('A', [Lorentz]*2, [[1]*2]) + >>> t = A(a, -b) + """ + if not [indices[i]._tensortype for i in range(len(indices))] == self.index_types: + raise ValueError('wrong index type') + components = [self] + free, dum = TensMul.from_indices(*indices) + free.sort(key=lambda x: x[0].name) + dum.sort() + return TensMul(S.One, components, free, dum) + + +class TensExpr(Basic): + """ + Abstract base class for tensor expressions + + Notes + ===== + + A tensor expression is an expression formed by tensors; + currently the sums of tensors are distributed. + + A ``TensExpr`` can be a ``TensAdd`` or a ``TensMul``. + + ``TensAdd`` objects are put in canonical form using the Butler-Portugal + algorithm for canonicalization under monoterm symmetries. + + ``TensMul`` objects are formed by products of component tensors, + and include a coefficient, which is a SymPy expression. + + + In the internal representation contracted indices are represented + by ``(ipos1, ipos2, icomp1, icomp2)``, where ``icomp1`` is the position + of the component tensor with contravariant index, ``ipos1`` is the + slot which the index occupies in that component tensor. + + Contracted indices are therefore nameless in the internal representation. + """ + + _op_priority = 11.0 + is_commutative = False + + def __neg__(self): + return self*S.NegativeOne + + def __abs__(self): + raise NotImplementedError + + def __add__(self, other): + raise NotImplementedError + + def __radd__(self, other): + raise NotImplementedError + + def __sub__(self, other): + raise NotImplementedError + + def __rsub__(self, other): + raise NotImplementedError + + def __mul__(self, other): + raise NotImplementedError + + def __rmul__(self, other): + return self*other + + def __pow__(self, other): + raise NotImplementedError + + def __rpow__(self, other): + raise NotImplementedError + + def __div__(self, other): + raise NotImplementedError + + def __rdiv__(self, other): + raise NotImplementedError() + + __truediv__ = __div__ + __rtruediv__ = __rdiv__ + + +def _tensAdd_collect_terms(args): + """ + collect TensMul terms differing at most by their coefficient + """ + a = [] + pprev = None + prev = args[0] + prev_coeff = prev._coeff + changed = False + + for x in args[1:]: + # if x and prev have the same tensor, update the coeff of prev + if x._components == prev._components \ + and x._free == prev._free and x._dum == prev._dum: + prev_coeff = prev_coeff + x._coeff + changed = True + op = 0 + else: + # x and prev are different; if not changed, prev has not + # been updated; store it + if not changed: + a.append(prev) + else: + # get a tensor from prev with coeff=prev_coeff and store it + if prev_coeff: + t = TensMul(prev_coeff, prev._components, + prev._free, prev._dum) + a.append(t) + # move x to prev + op = 1 + pprev, prev = prev, x + pprev_coeff, prev_coeff = prev_coeff, x._coeff + changed = False + # if the case op=0 prev was not stored; store it now + # in the case op=1 x was not stored; store it now (as prev) + if op == 0 and prev_coeff: + prev = TensMul(prev_coeff, prev._components, prev._free, prev._dum) + a.append(prev) + elif op == 1: + a.append(prev) + return a + +def _tensAdd_flatten(args): + """ + flatten TensAdd, coerce terms which are not tensors to tensors + """ + if not all(isinstance(x, TensExpr) for x in args): + args1 = [] + for x in args: + if isinstance(x, TensExpr): + if isinstance(x, TensAdd): + args1.extend(list(x.args)) + else: + args1.append(x) + args1 = [x for x in args1 if isinstance(x, TensExpr) and x._coeff] + args2 = [x for x in args if not isinstance(x, TensExpr)] + t1 = TensMul(Add(*args2), [], [], []) + args = [t1] + args1 + a = [] + for x in args: + if isinstance(x, TensAdd): + a.extend(list(x.args)) + else: + a.append(x) + args = [x for x in a if x._coeff] + return args + +def _tensAdd_check(args): + """ + check that all addends have the same free indices + """ + indices0 = sorted([x[0] for x in args[0]._free], key=lambda x: x.name) + list_indices = [sorted([y[0] for y in x._free], key=lambda x: x.name) for x in args[1:]] + if not all(x == indices0 for x in list_indices): + raise ValueError('all tensors must have the same indices') + + +class TensAdd(TensExpr): + """ + Sum of tensors + + Parameters + ========== + + free_args : list of the free indices + + Attributes + ========== + + ``args`` : tuple of addends + ``rank`` : rank of the tensor + ``free_args`` : list of the free indices in sorted order + + Notes + ===== + + Sum of more than one tensor are put automatically in canonical form. + + Examples + ======== + + >>> from sympy.tensor.tensor import TensorIndexType, tensorhead, tensor_indices + >>> Lorentz = TensorIndexType('Lorentz', dummy_fmt='L') + >>> a, b = tensor_indices('a,b', Lorentz) + >>> p, q = tensorhead('p,q', [Lorentz], [[1]]) + >>> t = p(a) + q(a); t + p(a) + q(a) + >>> t(b) + p(b) + q(b) + """ + + def __new__(cls, *args, **kw_args): + args = [sympify(x) for x in args if x] + args = _tensAdd_flatten(args) + if not args: + return S.Zero + + _tensAdd_check(args) + obj = Basic.__new__(cls, **kw_args) + if len(args) == 1 and isinstance(args[0], TensMul): + obj._args = tuple(args) + return obj + args = [x.canon_bp() for x in args if x] + args = [x for x in args if x] + if not args: + return S.Zero + + # collect canonicalized terms + args.sort(key=lambda x: (x._components, x._free, x._dum)) + a = _tensAdd_collect_terms(args) + if not a: + return S.Zero + # it there is only a component tensor return it + if len(a) == 1: + return a[0] + obj._args = tuple(a) + return obj + + @property + def free_args(self): + return self.args[0].free_args + + @property + def rank(self): + return self.args[0].rank + + def __call__(self, *indices): + """Returns tensor with ordered free indices replaced by ``indices`` + + Parameters + ========== + + indices + + Examples + ======== + + >>> from sympy import Symbol + >>> from sympy.tensor.tensor import TensorIndexType, tensor_indices, tensorhead + >>> D = Symbol('D') + >>> Lorentz = TensorIndexType('Lorentz', dim=D, dummy_fmt='L') + >>> i0,i1,i2,i3,i4 = tensor_indices('i0:5', Lorentz) + >>> p, q = tensorhead('p,q', [Lorentz], [[1]]) + >>> g = Lorentz.metric + >>> t = p(i0)*p(i1) + g(i0,i1)*q(i2)*q(-i2) + >>> t(i0,i2) + metric(i0, i2)*q(L_0)*q(-L_0) + p(i0)*p(i2) + >>> t(i0,i1) - t(i1,i0) + 0 + """ + free_args = self.free_args + indices = list(indices) + if [x._tensortype for x in indices] != [x._tensortype for x in free_args]: + raise ValueError('incompatible types') + if indices == free_args: + return self + index_tuples = list(zip(free_args, indices)) + a = [x.fun_eval(*index_tuples) for x in self.args] + res = TensAdd(*a) + + return res + + def canon_bp(self): + """ + canonicalize using the Butler-Portugal algorithm for canonicalization + under monoterm symmetries. + """ + args = [x.canon_bp() for x in self.args] + res = TensAdd(*args) + return res + + def equals(self, other): + other = sympify(other) + if isinstance(other, TensMul) and other._coeff == 0: + return self == 0 + t = self - other + if not isinstance(t, TensExpr): + return t == 0 + else: + if isinstance(t, TensMul): + return t._coeff == 0 + else: + return all(x._coeff == 0 for x in t.args) + + def __add__(self, other): + return TensAdd(self, other) + + def __radd__(self, other): + return TensAdd(other, self) + + def __sub__(self, other): + return TensAdd(self, -other) + + def __rsub__(self, other): + return TensAdd(other, -self) + + def __mul__(self, other): + return TensAdd(*[x*other for x in self.args]) + + def __div__(self, other): + other = sympify(other) + if isinstance(other, TensExpr): + raise ValueError('cannot divide by a tensor') + return TensAdd(*[x/other for x in self.args]) + + def __rdiv__(self, other): + raise ValueError('cannot divide by a tensor') + + __truediv__ = __div__ + __truerdiv__ = __rdiv__ + + def _hashable_content(self): + return tuple(self.args) + + def __hash__(self): + return super(TensAdd, self).__hash__() + + def __ne__(self, other): + return not (self == other) + + def contract_delta(self, delta): + args = [x.contract_delta(delta) for x in self.args] + t = TensAdd(*args) + return canon_bp(t) + + def contract_metric(self, g, contract_all=False): + """ + Raise or lower indices with the metric ``g`` + + Parameters + ========== + + g : metric + + contract_all : if True, eliminate all ``g`` which are contracted + + Notes + ===== + + see the ``TensorIndexType`` docstring for the contraction conventions + """ + + args = [x.contract_metric(g, contract_all) for x in self.args] + t = TensAdd(*args) + return canon_bp(t) + + + def fun_eval(self, *index_tuples): + """ + Return a tensor with free indices substituted according to ``index_tuples`` + + Parameters + ========== + + index_types : list of tuples ``(old_index, new_index)`` + + Examples + ======== + + >>> from sympy.tensor.tensor import TensorIndexType, tensor_indices, tensorhead + >>> Lorentz = TensorIndexType('Lorentz', dummy_fmt='L') + >>> i, j, k, l = tensor_indices('i,j,k,l', Lorentz) + >>> A, B = tensorhead('A,B', [Lorentz]*2, [[1]*2]) + >>> t = A(i, k)*B(-k, -j) + A(i, -j) + >>> t.fun_eval((i, k),(-j, l)) + A(k, L_0)*B(l, -L_0) + A(k, l) + """ + args = self.args + args1 = [] + for x in args: + y = x.fun_eval(*index_tuples) + args1.append(y) + return TensAdd(*args1) + + def substitute_indices(self, *index_tuples): + """ + Return a tensor with free indices substituted according to ``index_tuples`` + + Parameters + ========== + + index_types : list of tuples ``(old_index, new_index)`` + + Examples + ======== + + >>> from sympy.tensor.tensor import TensorIndexType, tensor_indices, tensorhead + >>> Lorentz = TensorIndexType('Lorentz', dummy_fmt='L') + >>> i, j, k, l = tensor_indices('i,j,k,l', Lorentz) + >>> A, B = tensorhead('A,B', [Lorentz]*2, [[1]*2]) + >>> t = A(i, k)*B(-k, -j); t + A(i, L_0)*B(-L_0, -j) + >>> t.substitute_indices((i,j), (j, k)) + A(j, L_0)*B(-L_0, -k) + """ + args = self.args + args1 = [] + for x in args: + y = x.substitute_indices(*index_tuples) + args1.append(y) + return TensAdd(*args1) + + def _pretty(self): + a = [] + args = self.args + for x in args: + a.append(str(x)) + a.sort() + s = ' + '.join(a) + s = s.replace('+ -', '- ') + return s + +class TensMul(TensExpr): + """ + Product of tensors + + Parameters + ========== + + coeff : SymPy coefficient of the tensor + args + + Attributes + ========== + + ``_components`` : list of ``TensorHead`` of the component tensors + ``types`` : list of nonrepeated ``TensorIndexType`` + ``free`` : list of ``(ind, ipos, icomp)``, see Notes + ``dum`` : list of ``(ipos1, ipos2, icomp1, icomp2)``, see Notes + ``ext_rank`` : rank of the tensor counting the dummy indices + ``rank`` : rank of the tensor + ``coeff`` : SymPy coefficient of the tensor + ``free_args`` : list of the free indices in sorted order + ``is_canon_bp`` : ``True`` if the tensor in in canonical form + + Notes + ===== + + ``args[0]`` list of ``TensorHead`` of the component tensors. + + ``args[1]`` list of ``(ind, ipos, icomp)`` + where ``ind`` is a free index, ``ipos`` is the slot position + of ``ind`` in the ``icomp``-th component tensor. + + ``args[2]`` list of tuples representing dummy indices. + ``(ipos1, ipos2, icomp1, icomp2)`` indicates that the contravariant + dummy index is the ``ipos1``-th slot position in the ``icomp1``-th + component tensor; the corresponding covariant index is + in the ``ipos2`` slot position in the ``icomp2``-th component tensor. + + """ + + def __new__(cls, coeff, *args, **kw_args): + obj = Basic.__new__(cls) + obj._components = args[0] + obj._types = [] + for t in obj._components: + obj._types.extend(t._types) + obj._free = args[1] + obj._dum = args[2] + obj._ext_rank = len(obj._free) + 2*len(obj._dum) + obj._coeff = coeff + obj._is_canon_bp = kw_args.get('is_canon_bp', False) + + return obj + + @property + def free_args(self): + return sorted([x[0] for x in self._free]) + + @property + def components(self): + return self._components[:] + + @property + def free(self): + return self._free[:] + + @property + def coeff(self): + return self._coeff + + @property + def dum(self): + return self._dum[:] + + @property + def rank(self): + return len(self._free) + + @property + def types(self): + return self._types[:] + + def equals(self, other): + if other == 0: + return self._coeff == 0 + other = sympify(other) + if not isinstance(other, TensExpr): + assert not self._components + return self._coeff == other + res = self - other + return res == 0 + + def _hashable_content(self): + t = self.canon_bp() + r = (t._coeff, tuple(t._components), \ + tuple(sorted(t._free)), tuple(sorted(t._dum))) + return r + + def __hash__(self): + return super(TensMul, self).__hash__() + + def __ne__(self, other): + return not self == other + + @staticmethod + def from_indices(*indices): + """ + Convert ``indices`` into ``free``, ``dum`` for single component tensor + + ``free`` list of tuples ``(index, pos, 0)``, + where ``pos`` is the position of index in + the list of indices formed by the component tensors + + ``dum`` list of tuples ``(pos_contr, pos_cov, 0, 0)`` + + Examples + ======== + + >>> from sympy.tensor.tensor import TensorIndexType, tensor_indices, TensMul + >>> Lorentz = TensorIndexType('Lorentz', dummy_fmt='L') + >>> m0, m1, m2, m3 = tensor_indices('m0,m1,m2,m3', Lorentz) + >>> TensMul.from_indices(m0, m1, -m1, m3) + ([(m0, 0, 0), (m3, 3, 0)], [(1, 2, 0, 0)]) + """ + n = len(indices) + if n == 1: + return [(indices[0], 0, 0)], [] + + # find the positions of the free indices and of the dummy indices + free = [True]*len(indices) + index_dict = {} + dum = [] + for i, index in enumerate(indices): + name = index._name + typ = index._tensortype + contr = index._is_up + if (name, typ) in index_dict: + # found a pair of dummy indices + is_contr, pos = index_dict[(name, typ)] + # check consistency and update free + if is_contr: + if contr: + raise ValueError('two equal contravariant indices in slots %d and %d' %(pos, i)) + else: + free[pos] = False + free[i] = False + else: + if contr: + free[pos] = False + free[i] = False + else: + raise ValueError('two equal covariant indices in slots %d and %d' %(pos, i)) + if contr: + dum.append((i, pos, 0, 0)) + else: + dum.append((pos, i, 0, 0)) + else: + index_dict[(name, typ)] = index._is_up, i + + free = [(index, i, 0) for i, index in enumerate(indices) if free[i]] + free.sort() + return free, dum + + def get_indices(self): + """ + Returns the list of indices of the tensor + + The indices are listed in the order in which they appear in the + component tensors. + The dummy indices are given a name which does not collide with + the names of the free indices. + + Examples + ======== + + >>> from sympy.tensor.tensor import TensorIndexType, tensor_indices, tensorhead + >>> Lorentz = TensorIndexType('Lorentz', dummy_fmt='L') + >>> m0, m1, m2 = tensor_indices('m0,m1,m2', Lorentz) + >>> g = Lorentz.metric + >>> p, q = tensorhead('p,q', [Lorentz], [[1]]) + >>> t = p(m1)*g(m0,m2) + >>> t.get_indices() + [m1, m0, m2] + """ + indices = [None]*self._ext_rank + start = 0 + pos = 0 + vpos = [] + components = self._components + for t in components: + vpos.append(pos) + pos += t._rank + cdt = defaultdict(int) + # if the free indices have names with dummy_fmt, start with an + # index higher than those for the dummy indices + # to avoid name collisions + for indx, ipos, cpos in self._free: + if indx._name.split('_')[0] == indx._tensortype._dummy_fmt[:-3]: + cdt[indx._tensortype] = max(cdt[indx._tensortype], int(indx._name.split('_')[1]) + 1) + start = vpos[cpos] + indices[start + ipos] = indx + for ipos1, ipos2, cpos1, cpos2 in self._dum: + start1 = vpos[cpos1] + start2 = vpos[cpos2] + typ1 = components[cpos1].index_types[ipos1] + assert typ1 == components[cpos2].index_types[ipos2] + fmt = typ1.dummy_fmt + nd = cdt[typ1] + indices[start1 + ipos1] = TensorIndex(fmt % nd, typ1) + indices[start2 + ipos2] = TensorIndex(fmt % nd, typ1, False) + cdt[typ1] += 1 + return indices + + def split(self): + """ + Returns a list of tensors, whose product is ``self`` + + Dummy indices contracted among different tensor components + become free indices with the same name as the one used to + represent the dummy indices. + + Examples + ======== + + >>> from sympy.tensor.tensor import TensorIndexType, tensor_indices, tensorhead + >>> Lorentz = TensorIndexType('Lorentz', dummy_fmt='L') + >>> a, b, c, d = tensor_indices('a,b,c,d', Lorentz) + >>> A, B = tensorhead('A,B', [Lorentz]*2, [[1]*2]) + >>> t = A(a,b)*B(-b,c) + >>> t + A(a, L_0)*B(-L_0, c) + >>> t.split() + [A(a, L_0), B(-L_0, c)] + """ + indices = self.get_indices() + pos = 0 + components = self._components + if not components: + return [TensMul(self._coeff, [], [], [])] + res = [] + for t in components: + t1 = t(*indices[pos:pos + t._rank]) + pos += t._rank + res.append(t1) + res[0] = TensMul(self._coeff, res[0]._components, res[0]._free, res[0]._dum, is_canon_bp=res[0]._is_canon_bp) + return res + + def canon_args(self): + """ + Returns ``(g, dummies, msym, v)``, the entries of ``canonicalize`` + + see ``canonicalize`` in ``tensor_can.py`` + """ + # to be called after sorted_components + from sympy.combinatorics.permutations import _af_new + types = list(set(self._types)) + types.sort(key = lambda x: x._name) + n = self._ext_rank + g = [None]*n + [n, n+1] + pos = 0 + vpos = [] + components = self._components + for t in components: + vpos.append(pos) + pos += t._rank + # ordered indices: first the free indices, ordered by types + # then the dummy indices, ordered by types and contravariant before + # covariant + # g[position in tensor] = position in ordered indices + for i, (indx, ipos, cpos) in enumerate(self._free): + pos = vpos[cpos] + ipos + g[pos] = i + pos = len(self._free) + j = len(self._free) + dummies = [] + prev = None + a = [] + msym = [] + for ipos1, ipos2, cpos1, cpos2 in self._dum: + pos1 = vpos[cpos1] + ipos1 + pos2 = vpos[cpos2] + ipos2 + g[pos1] = j + g[pos2] = j + 1 + j += 2 + typ = components[cpos1].index_types[ipos1] + if typ != prev: + if a: + dummies.append(a) + a = [pos, pos + 1] + prev = typ + msym.append(typ.metric_antisym) + else: + a.extend([pos, pos + 1]) + pos += 2 + if a: + dummies.append(a) + numtyp = [] + prev = None + for t in components: + if t == prev: + numtyp[-1][1] += 1 + else: + prev = t + numtyp.append([prev, 1]) + v = [] + for h, n in numtyp: + if h._comm == 0 or h._comm == 1: + comm = h._comm + else: + comm = TensorManager.get_comm(h._comm, h._comm) + v.append((h._symmetry.base, h._symmetry.generators, n, comm)) + return _af_new(g), dummies, msym, v + + def __add__(self, other): + return TensAdd(self, other) + + def __radd__(self, other): + return TensAdd(other, self) + + def __sub__(self, other): + return TensAdd(self, -other) + + def __rsub__(self, other): + return TensAdd(other, -self) + + def __mul__(self, other): + """ + Multiply two tensors using Einstein summation convention. + + If the two tensors have an index in common, one contravariant + and the other covariant, in their product the indices are summed + + Examples + ======== + + >>> from sympy.tensor.tensor import TensorIndexType, tensor_indices, tensorhead + >>> Lorentz = TensorIndexType('Lorentz', dummy_fmt='L') + >>> m0, m1, m2 = tensor_indices('m0,m1,m2', Lorentz) + >>> g = Lorentz.metric + >>> p, q = tensorhead('p,q', [Lorentz], [[1]]) + >>> t1 = p(m0) + >>> t2 = q(-m0) + >>> t1*t2 + p(L_0)*q(-L_0) + """ + other = sympify(other) + if not isinstance(other, TensExpr): + coeff = self._coeff*other + return TensMul(coeff, self._components, self._free, self._dum, is_canon_bp=self._is_canon_bp) + if isinstance(other, TensAdd): + return TensAdd(*[self*x for x in other.args]) + + components = self._components + other._components + # find out which free indices of self and other are contracted + free_dict1 = dict([(i.name, (pos, cpos, i)) for i, pos, cpos in self._free]) + free_dict2 = dict([(i.name, (pos, cpos, i)) for i, pos, cpos in other._free]) + + free_names = set(free_dict1.keys()) & set(free_dict2.keys()) + # find the new `free` and `dum` + nc1 = len(self._components) + dum2 = [(i1, i2, c1 + nc1, c2 + nc1) for i1, i2, c1, c2 in other._dum] + free1 = [(ind, i, c) for ind, i, c in self._free if ind.name not in free_names] + free2 = [(ind, i, c + nc1) for ind, i, c in other._free if ind.name not in free_names] + free = free1 + free2 + dum = self._dum + dum2 + for name in free_names: + ipos1, cpos1, ind1 = free_dict1[name] + ipos2, cpos2, ind2 = free_dict2[name] + cpos2 += nc1 + if ind1._is_up == ind2._is_up: + raise ValueError('wrong index contruction %s' % ind1) + if ind1._is_up: + new_dummy = (ipos1, ipos2, cpos1, cpos2) + else: + new_dummy = (ipos2, ipos1, cpos2, cpos1) + dum.append(new_dummy) + coeff = self._coeff*other._coeff + return TensMul(coeff, components, free, dum) + + def __rmul__(self, other): + other = sympify(other) + coeff = other*self._coeff + return TensMul(coeff, self._components, self._free, self._dum) + + def __div__(self, other): + other = sympify(other) + if isinstance(other, TensExpr): + raise ValueError('cannot divide by a tensor') + coeff = self._coeff/other + return TensMul(coeff, self._components, self._free, self._dum, is_canon_bp=self._is_canon_bp) + + def __rdiv__(self, other): + raise ValueError('cannot divide by a tensor') + + __truediv__ = __div__ + __truerdiv__ = __rdiv__ + + def sorted_components(self): + """ + Returns a tensor with sorted components + + The sorting is done taking into account the commutation group + of the component tensors. + """ + from sympy.combinatorics.permutations import _af_invert + cv = list(zip(self._components, list(range(len(self._components))))) + sign = 1 + n = len(cv) - 1 + for i in range(n): + for j in range(n, i, -1): + c = cv[j-1][0].commutes_with(cv[j][0]) + if c not in [0, 1]: + continue + if (cv[j-1][0]._types, cv[j-1][0]._name) > \ + (cv[j][0]._types, cv[j][0]._name): + cv[j-1], cv[j] = cv[j], cv[j-1] + if c: + sign = -sign + + # perm_inv[new_pos] = old_pos + components = [x[0] for x in cv] + perm_inv = [x[1] for x in cv] + perm = _af_invert(perm_inv) + free = [(ind, i, perm[c]) for ind, i, c in self._free] + free.sort() + dum = [(i1, i2, perm[c1], perm[c2]) for i1, i2, c1, c2 in self._dum] + dum.sort(key = lambda x: components[x[2]].index_types[x[0]]) + coeff = -self._coeff if sign == -1 else self._coeff + t = TensMul(coeff, components, free, dum) + return t + + def perm2tensor(self, g, canon_bp=False): + """ + Returns the tensor corresponding to the permutation ``g`` + + ``g`` permutation corrisponding to the tensor in the representation + used in canonicalization + + ``canon_bp`` if True, then ``g`` is the permutation + corresponding to the canonical form of the tensor + """ + from bisect import bisect_right + vpos = [] + components = self._components + pos = 0 + for t in components: + vpos.append(pos) + pos += t._rank + sorted_free = [x[0] for x in self._free] + sorted_free.sort() + nfree = len(sorted_free) + rank = self._ext_rank + indices = [None]*rank + dum = [[None]*4 for i in range((rank - nfree)//2)] + free = [] + icomp = -1 + for i in range(rank): + if i in vpos: + icomp += vpos.count(i) + pos0 = i + ipos = i - pos0 + gi = g[i] + if gi < nfree: + ind = sorted_free[gi] + free.append((ind, ipos, icomp)) + else: + j = gi - nfree + idum, cov = divmod(j, 2) + if cov: + dum[idum][1] = ipos + dum[idum][3] = icomp + else: + dum[idum][0] = ipos + dum[idum][2] = icomp + dum = [tuple(x) for x in dum] + coeff = self._coeff + if g[-1] != len(g) - 1: + coeff = -coeff + res = TensMul(coeff, components, free, dum, is_canon_bp=canon_bp) + return res + + def canon_bp(self): + """ + canonicalize using the Butler-Portugal algorithm for canonicalization + under monoterm symmetries. + + Examples + ======== + + >>> from sympy.tensor.tensor import TensorIndexType, tensor_indices, tensorhead + >>> Lorentz = TensorIndexType('Lorentz', dummy_fmt='L') + >>> m0, m1, m2 = tensor_indices('m0,m1,m2', Lorentz) + >>> A = tensorhead('A', [Lorentz]*2, [[2]]) + >>> t = A(m0,-m1)*A(m1,-m0) + >>> t.canon_bp() + -A(L_0, L_1)*A(-L_0, -L_1) + >>> t = A(m0,-m1)*A(m1,-m2)*A(m2,-m0) + >>> t.canon_bp() + 0 + """ + from sympy.combinatorics.tensor_can import canonicalize + if self._is_canon_bp: + return self + if not self._components: + return self + t = self.sorted_components() + g, dummies, msym, v = t.canon_args() + can = canonicalize(g, dummies, msym, *v) + if can == 0: + return S.Zero + return t.perm2tensor(can, True) + + def _contract(self, g, antisym, contract_all=False): + """ + helper method for ``contract_metric`` and ``contract_delta`` + + ``g`` metric to be contracted + + ``antisym``: + False symmetric metric + True antisymmetric metric + None delta + """ + if not self._components: + return self + free_indices = [x[0] for x in self._free] + a = self.split() + typ = g.index_types[0] + for i, tg in enumerate(a): + if tg._components[0] == g: + tg_free = [x[0] for x in tg._free] + if len(tg_free) == 0: + t = _contract_g_with_itself(a, i, tg, tg_free, g, antisym) + if contract_all == True and g in t._components: + return t._contract(g, antisym, True) + return t + + if all(indx in free_indices for indx in tg_free): + continue + else: + break + else: + # all metric tensors have only free indices, there is no contraction + return self + + # tg has one or two indices contracted with other tensors + # i position of tg in a + coeff = S.One + tg_free = tg._free + if antisym: + # order by slot position + tg_free = sorted(tg_free, key=lambda x: x[1]) + + if tg_free[0][0] in free_indices or tg_free[1][0] in free_indices: + # tg has one free index + res = _contract_g_with_free_index(a, free_indices, i, tg, tg_free, g, antisym) + else: + # tg has two indices contracted with other tensors + res = _contract_g_without_free_index(a, free_indices, i, tg, tg_free, g, typ, antisym) + if contract_all == True and g in res._components: + return res._contract(g, antisym, True) + return res + + def contract_delta(self, delta): + typ = delta._types[0] + t = self._contract(delta, None, True) + return t + + def contract_metric(self, g, contract_all=False): + """ + Raise or lower indices with the metric ``g`` + + ``g`` metric + + ``contract_all`` if True, eliminate all ``g`` which are contracted + + Notes + ===== + + see the ``TensorIndexType`` docstring for the contraction conventions + + Examples + ======== + + >>> from sympy.tensor.tensor import TensorIndexType, tensor_indices, tensorhead + >>> Lorentz = TensorIndexType('Lorentz', dummy_fmt='L') + >>> m0, m1, m2 = tensor_indices('m0,m1,m2', Lorentz) + >>> g = Lorentz.metric + >>> p, q = tensorhead('p,q', [Lorentz], [[1]]) + >>> t = p(m0)*q(m1)*g(-m0, -m1) + >>> t.canon_bp() + metric(L_0, L_1)*p(-L_0)*q(-L_1) + >>> t.contract_metric(g).canon_bp() + p(L_0)*q(-L_0) + """ + return self._contract(g, g.index_types[0].metric_antisym, contract_all) + + + def substitute_indices(self, *index_tuples): + """ + Return a tensor with free indices substituted according to ``index_tuples`` + + ``index_types`` list of tuples ``(old_index, new_index)`` + + Examples + ======== + + >>> from sympy.tensor.tensor import TensorIndexType, tensor_indices, tensorhead + >>> Lorentz = TensorIndexType('Lorentz', dummy_fmt='L') + >>> i, j, k, l = tensor_indices('i,j,k,l', Lorentz) + >>> A, B = tensorhead('A,B', [Lorentz]*2, [[1]*2]) + >>> t = A(i, k)*B(-k, -j); t + A(i, L_0)*B(-L_0, -j) + >>> t.substitute_indices((i,j), (j, k)) + A(j, L_0)*B(-L_0, -k) + """ + free = self._free + free1 = [] + for j, ipos, cpos in free: + for i, v in index_tuples: + if i._name == j._name and i._tensortype == j._tensortype: + if i._is_up == j._is_up: + free1.append((v, ipos, cpos)) + else: + free1.append((-v, ipos, cpos)) + break + else: + free1.append((j, ipos, cpos)) + + return TensMul(self._coeff, self._components, free1, self._dum) + + def fun_eval(self, *index_tuples): + """ + Return a tensor with free indices substituted according to ``index_tuples`` + + ``index_types`` list of tuples ``(old_index, new_index)`` + + Examples + ======== + + >>> from sympy.tensor.tensor import TensorIndexType, tensor_indices, tensorhead + >>> Lorentz = TensorIndexType('Lorentz', dummy_fmt='L') + >>> i, j, k, l = tensor_indices('i,j,k,l', Lorentz) + >>> A, B = tensorhead('A,B', [Lorentz]*2, [[1]*2]) + >>> t = A(i, k)*B(-k, -j); t + A(i, L_0)*B(-L_0, -j) + >>> t.fun_eval((i, k),(-j, l)) + A(k, L_0)*B(-L_0, l) + """ + free = self._free + free1 = [] + for j, ipos, cpos in free: + # search j in index_tuples + for i, v in index_tuples: + if i == j: + free1.append((v, ipos, cpos)) + break + else: + free1.append((j, ipos, cpos)) + return TensMul(self._coeff, self._components, free1, self._dum) + + + def __call__(self, *indices): + """Returns tensor with ordered free indices replaced by ``indices`` + + Examples + ======== + + >>> from sympy import Symbol + >>> from sympy.tensor.tensor import TensorIndexType, tensor_indices, tensorhead + >>> D = Symbol('D') + >>> Lorentz = TensorIndexType('Lorentz', dim=D, dummy_fmt='L') + >>> i0,i1,i2,i3,i4 = tensor_indices('i0:5', Lorentz) + >>> g = Lorentz.metric + >>> p, q = tensorhead('p,q', [Lorentz], [[1]]) + >>> t = p(i0)*q(i1)*q(-i1) + >>> t(i1) + p(i1)*q(L_0)*q(-L_0) + """ + free_args = self.free_args + indices = list(indices) + if [x._tensortype for x in indices] != [x._tensortype for x in free_args]: + raise ValueError('incompatible types') + if indices == free_args: + return self + t = self.fun_eval(*list(zip(free_args, indices))) + return t + + + def _pretty(self): + if self._components == []: + return str(self._coeff) + indices = [str(ind) for ind in self.get_indices()] + pos = 0 + a = [] + for t in self._components: + if t._rank > 0: + a.append('%s(%s)' % (t.name, ', '.join(indices[pos:pos + t._rank]))) + else: + a.append('%s' % t.name) + pos += t._rank + res = '*'. join(a) + if self._coeff == S.One: + return res + elif self._coeff == -S.One: + return '-%s' % res + if self._coeff.is_Atom: + return '%s*%s' % (self._coeff, res) + else: + return '(%s)*%s' %(self._coeff, res) + + + +def canon_bp(p): + """ + Butler-Portugal canonicalization + """ + if isinstance(p, TensExpr): + return p.canon_bp() + return p + +def tensor_mul(*a): + """ + product of tensors + """ + if not a: + return TensMul(S.One, [], [], []) + t = a[0] + for tx in a[1:]: + t = t*tx + return t + + + +def riemann_cyclic_replace(t_r): + """ + replace Riemann tensor with an equivalent expression + + ``R(m,n,p,q) -> 2/3*R(m,n,p,q) - 1/3*R(m,q,n,p) + 1/3*R(m,p,n,q)`` + + """ + free = sorted(t_r._free, key=lambda x: x[1]) + m, n, p, q = [x[0] for x in free] + t0 = S(2)/3*t_r + t1 = - S(1)/3*t_r.substitute_indices((m,m),(n,q),(p,n),(q,p)) + t2 = S(1)/3*t_r.substitute_indices((m,m),(n,p),(p,n),(q,q)) + t3 = t0 + t1 + t2 + return t3 + +def riemann_cyclic(t2): + """ + replace each Riemann tensor with an equivalent expression + satisfying the cyclic identity. + + This trick is discussed in the reference guide to Cadabra. + + Examples + ======== + + >>> from sympy.tensor.tensor import TensorIndexType, tensor_indices, tensorhead, riemann_cyclic + >>> Lorentz = TensorIndexType('Lorentz', dummy_fmt='L') + >>> i, j, k, l = tensor_indices('i,j,k,l', Lorentz) + >>> R = tensorhead('R', [Lorentz]*4, [[2, 2]]) + >>> t = R(i,j,k,l)*(R(-i,-j,-k,-l) - 2*R(-i,-k,-j,-l)) + >>> riemann_cyclic(t) + 0 + """ + if isinstance(t2, TensMul): + args = [t2] + else: + args = t2.args + a1 = [x.split() for x in args] + a2 = [[riemann_cyclic_replace(tx) for tx in y] for y in a1] + a3 = [tensor_mul(*v) for v in a2] + t3 = TensAdd(*a3) + if not t3: + return t3 + else: + return canon_bp(t3) + + +def tensorlist_contract_metric(a, tg): + """ + contract `tg` with a tensor in the list `a = t.split()` + Only for symmetric metric. + """ + ind1, ind2 = [x[0] for x in tg._free] + mind1 = -ind1 + mind2 = -ind2 + for i in range(len(a)): + t1 = a[i] + for j in range(len(t1._free)): + indx, ipos, _ = t1._free[j] + if indx == mind1 or indx == mind2: + ind3 = ind2 if indx == mind1 else ind1 + free1 = t1._free[:] + free1[j] = (ind3, ipos, 0) + t2 = TensMul(t1._coeff, t1._components, free1, t1._dum) + a[i] = t2 + return a + a.append(tg) + return a + +def _contract_g_with_itself(a, i, tg, tg_free, g, antisym): + """ + helper function for _contract + """ + typ = g.index_types[0] + a1 = a[:i] + a[i + 1:] + t11 = tensor_mul(*a1) + if typ._dim is None: + raise ValueError('dimension not assigned') + coeff = typ._dim*a[i]._coeff + if antisym and tg._dum[0][0] == 0: + # g(i, -i) = -D + coeff = -coeff + t = tensor_mul(*a1)*coeff + return t + + +def _contract_g_with_free_index(a, free_indices, i, tg, tg_free, g, antisym): + """ + helper function for _contract + """ + if tg_free[0][0] in free_indices: + ind_free = tg_free[0][0] + ind, ipos1, _ = tg_free[1] + else: + ind_free = tg_free[1][0] + ind, ipos1, _ = tg_free[0] + + ind1 = -ind + # search ind1 in the other component tensors + for j, tx in enumerate(a): + if ind1 in [x[0] for x in tx._free]: + break + # replace ind1 with ind_free + free1 = [] + for indx, iposx, _ in tx._free: + if indx == ind1: + free1.append((ind_free, iposx, 0)) + else: + free1.append((indx, iposx, 0)) + coeff = tx._coeff + if antisym: + if ind._is_up and ind == tg_free[0][0] or \ + (not ind._is_up) and ind == tg_free[1][0]: + # g(i1, i0)*psi(-i1) = -psi(i0) + # g(-i0, -i1)*psi(i1) = -psi(-i0) + coeff = -coeff + t1 = TensMul(coeff, tx._components, free1, tx._dum) + a[j] = t1 + a = a[:i] + a[i + 1:] + coeff = tg._coeff + res = tensor_mul(*a) + return coeff*res + + +def _contract_g_without_free_index(a, free_indices, i, tg, tg_free, g, typ, antisym): + """ + helper function for _contract + """ + coeff = S.One + ind1 = tg_free[0][0] + ind2 = tg_free[1][0] + ind1m = -ind1 + ind2m = -ind2 + for k, ty in enumerate(a): + if ind2m in [x[0] for x in ty._free]: + break + # ty has the index ind2m + ty_free = ty._free[:] + if ty._components == [g]: + ty_indices = [x[0] for x in ty_free] + if all(x in [ind1m, ind2m] for x in ty_indices): + # the two `g` are completely contracted + # i < k always + a = a[:i] + a[i+1:k] + a[k+1:] + coeff = coeff*typ._dim*tg._coeff*ty._coeff + if antisym: + ty_free = sorted(ty_free, key=lambda x: x[1]) + if ind1._is_up == ind2._is_up: + # g(i,j)*g(-i,-j) = g(-i,-j)*g(i,j) = dim + # g(i,j)*g(-j,-i) = g(-i,-j)*g(j,i) = -dim + if ind1m == ty_free[1][0]: + coeff = -coeff + else: + # g(-i,j)*g(i,-j) = g(i,-j)^g(-i,j) = -dim + # g(-i,j)*g(-j,i) = g(i,-j)*g(j,i) = dim + if ind1m == ty_free[0][0]: + coeff = -coeff + + if a: + res = tensor_mul(*a) + res = coeff*res + else: + res = TensMul(coeff, [],[],[], is_canon_bp=True) + return res + + free2 = [] + ty_freeindices = [x[0] for x in ty_free] + if ind1m in ty_freeindices: + # tg has both indices contracted with ty + free2 = [(indx, iposx, cposx) for indx, iposx, cposx in ty._free if indx != ind1m and indx != ind2m] + dum2 = ty._dum[:] + for indx, iposx, _ in ty_free: + if indx == ind1m: + iposx1 = iposx + if indx == ind2m: + iposx2 = iposx + if antisym: + if ind1._is_up == ind2._is_up: + if iposx1 < iposx2: + coeff = -coeff + dum2.append((iposx1, iposx2, 0, 0)) + else: + dum2.append((iposx2, iposx1, 0, 0)) + else: + if iposx1 > iposx2: + coeff = -coeff + dum2.append((iposx2, iposx1, 0, 0)) + else: + dum2.append((iposx1, iposx2, 0, 0)) + else: + dum2.append((iposx1, iposx2, 0, 0)) + else: + # replace ind2m with ind1 in the free indices of ty + + free2 = [] + if not antisym: + for indx, iposx, _ in ty_free: + if indx == ind2m: + free2.append((ind1, iposx, 0)) + else: + free2.append((indx, iposx, 0)) + else: + for indx, iposx, _ in ty_free: + if indx == ind2m: + free2.append((ind1, iposx, 0)) + if indx._is_up: + coeff = -coeff + else: + free2.append((indx, iposx, 0)) + dum2 = ty._dum + + t2 = TensMul(ty._coeff, ty._components, free2, dum2) + a[k] = t2 + a = a[:i] + a[i + 1:] + coeff = coeff*tg._coeff + res = tensor_mul(*a) + return coeff*res diff -Nru python3-sympy-0.7.2/sympy/tensor/tests/test_index_methods.py python3-sympy-0.7.3/sympy/tensor/tests/test_index_methods.py --- python3-sympy-0.7.2/sympy/tensor/tests/test_index_methods.py 2012-10-17 03:02:22.000000000 +0000 +++ python3-sympy-0.7.3/sympy/tensor/tests/test_index_methods.py 2013-07-13 17:53:32.000000000 +0000 @@ -7,6 +7,7 @@ # import test from sympy import get_contraction_structure, get_indices + def test_trivial_indices(): x, y = symbols('x y') assert get_indices(x) == (set([]), {}) @@ -14,6 +15,7 @@ assert get_indices(x + y) == (set([]), {}) assert get_indices(x**y) == (set([]), {}) + def test_get_indices_Indexed(): x = IndexedBase('x') y = IndexedBase('y') @@ -21,6 +23,7 @@ assert get_indices(x[i, j]) == (set([i, j]), {}) assert get_indices(x[j, i]) == (set([j, i]), {}) + def test_get_indices_Idx(): f = Function('f') i, j = Idx('i'), Idx('j') @@ -28,6 +31,7 @@ assert get_indices(f(j, i)) == (set([j, i]), {}) assert get_indices(f(i)*i) == (set(), {}) + def test_get_indices_mul(): x = IndexedBase('x') y = IndexedBase('y') @@ -35,41 +39,47 @@ assert get_indices(x[j]*y[i]) == (set([i, j]), {}) assert get_indices(x[i]*y[j]) == (set([i, j]), {}) + def test_get_indices_exceptions(): x = IndexedBase('x') y = IndexedBase('y') i, j = Idx('i'), Idx('j') raises(IndexConformanceException, lambda: get_indices(x[i] + y[j])) + def test_scalar_broadcast(): x = IndexedBase('x') y = IndexedBase('y') i, j = Idx('i'), Idx('j') assert get_indices(x[i] + y[i, i]) == (set([i]), {}) + def test_get_indices_add(): x = IndexedBase('x') y = IndexedBase('y') A = IndexedBase('A') i, j, k = Idx('i'), Idx('j'), Idx('k') - assert get_indices(x[i] + 2*y[i]) == (set([i,]), {}) - assert get_indices(y[i] + 2*A[i, j]*x[j]) == (set([i,]), {}) - assert get_indices(y[i] + 2*(x[i] + A[i, j]*x[j])) == (set([i,]), {}) - assert get_indices(y[i] + x[i]*(A[j, j] + 1)) == (set([i,]), {}) - assert get_indices(y[i] + x[i]*x[j]*(y[j] + A[j, k]*x[k])) == (set([i,]), {}) + assert get_indices(x[i] + 2*y[i]) == (set([i, ]), {}) + assert get_indices(y[i] + 2*A[i, j]*x[j]) == (set([i, ]), {}) + assert get_indices(y[i] + 2*(x[i] + A[i, j]*x[j])) == (set([i, ]), {}) + assert get_indices(y[i] + x[i]*(A[j, j] + 1)) == (set([i, ]), {}) + assert get_indices( + y[i] + x[i]*x[j]*(y[j] + A[j, k]*x[k])) == (set([i, ]), {}) + def test_get_indices_Pow(): x = IndexedBase('x') y = IndexedBase('y') A = IndexedBase('A') i, j, k = Idx('i'), Idx('j'), Idx('k') - assert get_indices(Pow(x[i], y[j])) == (set([i,j]), {}) + assert get_indices(Pow(x[i], y[j])) == (set([i, j]), {}) assert get_indices(Pow(x[i, k], y[j, k])) == (set([i, j, k]), {}) assert get_indices(Pow(A[i, k], y[k] + A[k, j]*x[j])) == (set([i, k]), {}) assert get_indices(Pow(2, x[i])) == get_indices(exp(x[i])) # test of a design decision, this may change: - assert get_indices(Pow(x[i], 2)) == (set([i,]), {}) + assert get_indices(Pow(x[i], 2)) == (set([i, ]), {}) + def test_get_contraction_structure_basic(): x = IndexedBase('x') @@ -78,9 +88,11 @@ assert get_contraction_structure(x[i]*y[j]) == {None: set([x[i]*y[j]])} assert get_contraction_structure(x[i] + y[j]) == {None: set([x[i], y[j]])} assert get_contraction_structure(x[i]*y[i]) == {(i,): set([x[i]*y[i]])} - assert get_contraction_structure(1 + x[i]*y[i]) == {None: set([S.One]), (i,): set([x[i]*y[i]])} + assert get_contraction_structure( + 1 + x[i]*y[i]) == {None: set([S.One]), (i,): set([x[i]*y[i]])} assert get_contraction_structure(x[i]**y[i]) == {None: set([x[i]**y[i]])} + def test_get_contraction_structure_complex(): x = IndexedBase('x') y = IndexedBase('y') @@ -93,18 +105,20 @@ d2 = {None: set([x[k]]), (i,): set([expr1*A[k, i]]), expr1*A[k, i]: [d1]} assert get_contraction_structure(expr2) == d2 + def test_contraction_structure_simple_Pow(): x = IndexedBase('x') y = IndexedBase('y') i, j, k = Idx('i'), Idx('j'), Idx('k') ii_jj = x[i, i]**y[j, j] assert get_contraction_structure(ii_jj) == { - None: set([ii_jj]), - ii_jj: [ - {(i,): set([x[i, i]])}, - {(j,): set([y[j, j]])} - ] - } + None: set([ii_jj]), + ii_jj: [ + {(i,): set([x[i, i]])}, + {(j,): set([y[j, j]])} + ] + } + def test_contraction_structure_Mul_and_Pow(): x = IndexedBase('x') @@ -122,32 +136,34 @@ ij_exp_kki = x[i]*y[j]*exp(y[i]*y[k, k]) result = get_contraction_structure(ij_exp_kki) expected = { - (i,): set([ij_exp_kki]), - ij_exp_kki: [{ - None: set([exp(y[i]*y[k, k])]), + (i,): set([ij_exp_kki]), + ij_exp_kki: [{ + None: set([exp(y[i]*y[k, k])]), exp(y[i]*y[k, k]): [{ None: set([y[i]*y[k, k]]), y[i]*y[k, k]: [{(k,): set([y[k, k]])}] - }]} - ] - } + }]} + ] + } assert result == expected + def test_contraction_structure_Add_in_Pow(): x = IndexedBase('x') y = IndexedBase('y') i, j, k = Idx('i'), Idx('j'), Idx('k') s_ii_jj_s = (1 + x[i, i])**(1 + y[j, j]) expected = { - None: set([s_ii_jj_s]), - s_ii_jj_s: [ - {None: set([S.One]), (i,): set([x[i, i]])}, - {None: set([S.One]), (j,): set([y[j, j]])} - ] - } - result = get_contraction_structure(s_ii_jj_s) + None: set([s_ii_jj_s]), + s_ii_jj_s: [ + {None: set([S.One]), (i,): set([x[i, i]])}, + {None: set([S.One]), (j,): set([y[j, j]])} + ] + } + result = get_contraction_structure(s_ii_jj_s) assert result == expected + def test_contraction_structure_Pow_in_Pow(): x = IndexedBase('x') y = IndexedBase('y') @@ -155,20 +171,21 @@ i, j, k = Idx('i'), Idx('j'), Idx('k') ii_jj_kk = x[i, i]**y[j, j]**z[k, k] expected = { - None: set([ii_jj_kk]), - ii_jj_kk: [ - {(i,): set([x[i, i]])}, - { - None: set([y[j, j]**z[k, k]]), - y[j, j]**z[k, k]: [ - {(j,): set([y[j, j]])}, - {(k,): set([z[k, k]])} - ] - } + None: set([ii_jj_kk]), + ii_jj_kk: [ + {(i,): set([x[i, i]])}, + { + None: set([y[j, j]**z[k, k]]), + y[j, j]**z[k, k]: [ + {(j,): set([y[j, j]])}, + {(k,): set([z[k, k]])} ] } + ] + } assert get_contraction_structure(ii_jj_kk) == expected + def test_ufunc_support(): f = Function('f') g = Function('g') @@ -185,6 +202,9 @@ assert get_indices(g(f(x[i]))) == (set([i]), {}) assert get_contraction_structure(f(x[i])) == {None: set([f(x[i])])} - assert get_contraction_structure(f(y[i])*g(x[i])) == {(i,): set([f(y[i])*g(x[i])])} - assert get_contraction_structure(f(y[i])*g(f(x[i]))) == {(i,): set([f(y[i])*g(f(x[i]))])} - assert get_contraction_structure(f(x[j], y[i])*g(x[i])) == {(i,): set([f(x[j], y[i])*g(x[i])])} + assert get_contraction_structure( + f(y[i])*g(x[i])) == {(i,): set([f(y[i])*g(x[i])])} + assert get_contraction_structure( + f(y[i])*g(f(x[i]))) == {(i,): set([f(y[i])*g(f(x[i]))])} + assert get_contraction_structure( + f(x[j], y[i])*g(x[i])) == {(i,): set([f(x[j], y[i])*g(x[i])])} diff -Nru python3-sympy-0.7.2/sympy/tensor/tests/test_indexed.py python3-sympy-0.7.3/sympy/tensor/tests/test_indexed.py --- python3-sympy-0.7.2/sympy/tensor/tests/test_indexed.py 2012-10-17 03:02:22.000000000 +0000 +++ python3-sympy-0.7.3/sympy/tensor/tests/test_indexed.py 2013-07-13 17:53:32.000000000 +0000 @@ -5,6 +5,7 @@ # import test: from sympy import IndexedBase, Idx, Indexed + def test_Idx_construction(): i, a, b = symbols('i a b', integer=True) assert Idx(i) != Idx(i, 1) @@ -20,14 +21,16 @@ raises(TypeError, lambda: Idx(i, (2, x))) raises(TypeError, lambda: Idx(i, (2, 3.5))) + def test_Idx_properties(): i, a, b = symbols('i a b', integer=True) assert Idx(i).is_integer + def test_Idx_bounds(): i, a, b = symbols('i a b', integer=True) - assert Idx(i).lower == None - assert Idx(i).upper == None + assert Idx(i).lower is None + assert Idx(i).upper is None assert Idx(i, a).lower == 0 assert Idx(i, a).upper == a - 1 assert Idx(i, 5).lower == 0 @@ -41,10 +44,11 @@ assert Idx(i, (-oo, oo)).lower == -oo assert Idx(i, (-oo, oo)).upper == oo + def test_Idx_fixed_bounds(): i, a, b = symbols('i a b', integer=True) - assert Idx(2).lower == None - assert Idx(2).upper == None + assert Idx(2).lower is None + assert Idx(2).upper is None assert Idx(2, a).lower == 0 assert Idx(2, a).upper == a - 1 assert Idx(2, 5).lower == 0 @@ -58,6 +62,7 @@ assert Idx(2, (-oo, oo)).lower == -oo assert Idx(2, (-oo, oo)).upper == oo + def test_Idx_func_args(): i, a, b = symbols('i a b', integer=True) ii = Idx(i) @@ -67,15 +72,17 @@ ii = Idx(i, (a, b)) assert ii.func(*ii.args) == ii + def test_Idx_subs(): i, a, b = symbols('i a b', integer=True) assert Idx(i, a).subs(a, b) == Idx(i, b) assert Idx(i, a).subs(i, b) == Idx(b, a) - assert Idx(i).subs(i,2) == Idx(2) + assert Idx(i).subs(i, 2) == Idx(2) assert Idx(i, a).subs(a, 2) == Idx(i, 2) assert Idx(i, (a, b)).subs(i, 2) == Idx(2, (a, b)) + def test_IndexedBase_sugar(): i, j = symbols('i j', integer=True) a = symbols('a') @@ -85,6 +92,7 @@ assert A1 == A2[(i, j)] assert A1 == A2[[i, j]] assert A1 == A2[Tuple(i, j)] + assert all(a.is_Integer for a in A2[1, 0].args[1:]) def test_IndexedBase_subs(): i, j, k = symbols('i j k', integer=True) @@ -93,6 +101,7 @@ B = IndexedBase(b) assert A[i] == B[i].subs(b, a) + def test_IndexedBase_shape(): i, j, m, n = symbols('i j m n', integer=True) a = IndexedBase('a', shape=(m, m)) @@ -105,6 +114,7 @@ raises(IndexException, lambda: b[i]) raises(IndexException, lambda: b[i, i, j]) + def test_Indexed_constructor(): i, j = symbols('i j', integer=True) A = Indexed('A', i, j) @@ -113,12 +123,14 @@ raises(TypeError, lambda: Indexed(A, i, j)) raises(IndexException, lambda: Indexed("A")) + def test_Indexed_func_args(): i, j = symbols('i j', integer=True) a = symbols('a') A = Indexed(a, i, j) assert A == A.func(*A.args) + def test_Indexed_subs(): i, j, k = symbols('i j k', integer=True) a, b = symbols('a b') @@ -127,6 +139,7 @@ assert A[i, j] == B[i, j].subs(b, a) assert A[i, j] == A[i, k].subs(k, j) + def test_Indexed_properties(): i, j = symbols('i j', integer=True) A = Indexed('A', i, j) @@ -137,21 +150,26 @@ raises(IndexException, lambda: A.shape) n, m = symbols('n m', integer=True) - assert Indexed('A', Idx(i, m), Idx(j, n)).ranges == [Tuple(0, m - 1), Tuple(0, n - 1)] + assert Indexed('A', Idx( + i, m), Idx(j, n)).ranges == [Tuple(0, m - 1), Tuple(0, n - 1)] assert Indexed('A', Idx(i, m), Idx(j, n)).shape == Tuple(m, n) raises(IndexException, lambda: Indexed("A", Idx(i, m), Idx(j)).shape) + def test_Indexed_shape_precedence(): i, j = symbols('i j', integer=True) o, p = symbols('o p', integer=True) n, m = symbols('n m', integer=True) a = IndexedBase('a', shape=(o, p)) assert a.shape == Tuple(o, p) - assert Indexed(a, Idx(i, m), Idx(j, n)).ranges == [Tuple(0, m - 1), Tuple(0, n - 1)] + assert Indexed( + a, Idx(i, m), Idx(j, n)).ranges == [Tuple(0, m - 1), Tuple(0, n - 1)] assert Indexed(a, Idx(i, m), Idx(j, n)).shape == Tuple(o, p) - assert Indexed(a, Idx(i, m), Idx(j)).ranges == [Tuple(0, m - 1), Tuple(None, None)] + assert Indexed( + a, Idx(i, m), Idx(j)).ranges == [Tuple(0, m - 1), Tuple(None, None)] assert Indexed(a, Idx(i, m), Idx(j)).shape == Tuple(o, p) + def test_complex_indices(): i, j = symbols('i j', integer=True) A = Indexed('A', i, i + j) diff -Nru python3-sympy-0.7.2/sympy/tensor/tests/test_tensor.py python3-sympy-0.7.3/sympy/tensor/tests/test_tensor.py --- python3-sympy-0.7.2/sympy/tensor/tests/test_tensor.py 1970-01-01 00:00:00.000000000 +0000 +++ python3-sympy-0.7.3/sympy/tensor/tests/test_tensor.py 2013-07-13 17:53:32.000000000 +0000 @@ -0,0 +1,1080 @@ +from sympy.core import S, Rational, Symbol, Basic +from sympy.combinatorics import Permutation +from sympy.combinatorics.tensor_can import (bsgs_direct_product, riemann_bsgs) +from sympy.tensor.tensor import (TensorIndexType, tensor_indices, + TensorSymmetry, get_symmetric_group_sgs, TensorType, TensorIndex, + tensor_mul, canon_bp, TensAdd, riemann_cyclic_replace, riemann_cyclic, + tensorlist_contract_metric, TensMul, tensorsymmetry, tensorhead, + TensorManager, TensExpr) +from sympy.utilities.pytest import raises + +#################### Tests from tensor_can.py ####################### + +def test_canonicalize_no_slot_sym(): + # A_d0 * B^d0; T_c = A^d0*B_d0 + Lorentz = TensorIndexType('Lorentz', dummy_fmt='L') + a, b, d0, d1 = tensor_indices('a,b,d0,d1', Lorentz) + sym1 = tensorsymmetry([1]) + S1 = TensorType([Lorentz], sym1) + A, B = S1('A,B') + t = A(-d0)*B(d0) + tc = t.canon_bp() + assert str(tc) == 'A(L_0)*B(-L_0)' + + # A^a * B^b; T_c = T + t = A(a)*B(b) + tc = t.canon_bp() + assert tc == t + # B^b * A^a + t1 = B(b)*A(a) + tc = t1.canon_bp() + assert str(tc) == 'A(a)*B(b)' + + # A symmetric + # A^{b}_{d0}*A^{d0, a}; T_c = A^{a d0}*A{b}_{d0} + sym2 = tensorsymmetry([1]*2) + S2 = TensorType([Lorentz]*2, sym2) + A = S2('A') + t = A(b, -d0)*A(d0, a) + tc = t.canon_bp() + assert str(tc) == 'A(a, L_0)*A(b, -L_0)' + + # A^{d1}_{d0}*B^d0*C_d1 + # T_c = A^{d0 d1}*B_d0*C_d1 + B, C = S1('B,C') + t = A(d1, -d0)*B(d0)*C(-d1) + tc = t.canon_bp() + assert str(tc) == 'A(L_0, L_1)*B(-L_0)*C(-L_1)' + + # A without symmetry + # A^{d1}_{d0}*B^d0*C_d1 ord=[d0,-d0,d1,-d1]; g = [2,1,0,3,4,5] + # T_c = A^{d0 d1}*B_d1*C_d0; can = [0,2,3,1,4,5] + nsym2 = tensorsymmetry([1],[1]) + NS2 = TensorType([Lorentz]*2, nsym2) + A = NS2('A') + B, C = S1('B, C') + t = A(d1, -d0)*B(d0)*C(-d1) + tc = t.canon_bp() + assert str(tc) == 'A(L_0, L_1)*B(-L_1)*C(-L_0)' + + # A, B without symmetry + # A^{d1}_{d0}*B_{d1}^{d0} + # T_c = A^{d0 d1}*B_{d0 d1} + B = NS2('B') + t = A(d1, -d0)*B(-d1, d0) + tc = t.canon_bp() + assert str(tc) == 'A(L_0, L_1)*B(-L_0, -L_1)' + # A_{d0}^{d1}*B_{d1}^{d0} + # T_c = A^{d0 d1}*B_{d1 d0} + t = A(-d0, d1)*B(-d1, d0) + tc = t.canon_bp() + assert str(tc) == 'A(L_0, L_1)*B(-L_1, -L_0)' + + # A, B, C without symmetry + # A^{d1 d0}*B_{a d0}*C_{d1 b} + # T_c=A^{d0 d1}*B_{a d1}*C_{d0 b} + C = NS2('C') + t = A(d1, d0)*B(-a, -d0)*C(-d1, -b) + tc = t.canon_bp() + assert str(tc) == 'A(L_0, L_1)*B(-a, -L_1)*C(-L_0, -b)' + + # A symmetric, B and C without symmetry + # A^{d1 d0}*B_{a d0}*C_{d1 b} + # T_c = A^{d0 d1}*B_{a d0}*C_{d1 b} + A = S2('A') + t = A(d1, d0)*B(-a, -d0)*C(-d1, -b) + tc = t.canon_bp() + assert str(tc) == 'A(L_0, L_1)*B(-a, -L_0)*C(-L_1, -b)' + + # A and C symmetric, B without symmetry + # A^{d1 d0}*B_{a d0}*C_{d1 b} ord=[a,b,d0,-d0,d1,-d1] + # T_c = A^{d0 d1}*B_{a d0}*C_{b d1} + C = S2('C') + t = A(d1, d0)*B(-a, -d0)*C(-d1, -b) + tc = t.canon_bp() + assert str(tc) == 'A(L_0, L_1)*B(-a, -L_0)*C(-b, -L_1)' + +def test_canonicalize_no_dummies(): + Lorentz = TensorIndexType('Lorentz', dummy_fmt='L') + a, b, c, d = tensor_indices('a, b, c, d', Lorentz) + sym1 = tensorsymmetry([1]) + sym2 = tensorsymmetry([1]*2) + sym2a = tensorsymmetry([2]) + + # A commuting + # A^c A^b A^a + # T_c = A^a A^b A^c + S1 = TensorType([Lorentz], sym1) + A = S1('A') + t = A(c)*A(b)*A(a) + tc = t.canon_bp() + assert str(tc) == 'A(a)*A(b)*A(c)' + + # A anticommuting + # A^c A^b A^a + # T_c = -A^a A^b A^c + A = S1('A', 1) + t = A(c)*A(b)*A(a) + tc = t.canon_bp() + assert str(tc) == '-A(a)*A(b)*A(c)' + + # A commuting and symmetric + # A^{b,d}*A^{c,a} + # T_c = A^{a c}*A^{b d} + S2 = TensorType([Lorentz]*2, sym2) + A = S2('A') + t = A(b, d)*A(c, a) + tc = t.canon_bp() + assert str(tc) == 'A(a, c)*A(b, d)' + + # A anticommuting and symmetric + # A^{b,d}*A^{c,a} + # T_c = -A^{a c}*A^{b d} + A = S2('A', 1) + t = A(b, d)*A(c, a) + tc = t.canon_bp() + assert str(tc) == '-A(a, c)*A(b, d)' + + # A^{c,a}*A^{b,d} + # T_c = A^{a c}*A^{b d} + t = A(c, a)*A(b, d) + tc = t.canon_bp() + assert str(tc) == 'A(a, c)*A(b, d)' + +def test_no_metric_symmetry(): + # no metric symmetry; A no symmetry + # A^d1_d0 * A^d0_d1 + # T_c = A^d0_d1 * A^d1_d0 + Lorentz = TensorIndexType('Lorentz', metric=None, dummy_fmt='L') + d0, d1, d2, d3 = tensor_indices('d:4', Lorentz) + A = tensorhead('A', [Lorentz]*2, [[1], [1]]) + t = A(d1, -d0)*A(d0, -d1) + tc = t.canon_bp() + assert str(tc) == 'A(L_0, -L_1)*A(L_1, -L_0)' + + # A^d1_d2 * A^d0_d3 * A^d2_d1 * A^d3_d0 + # T_c = A^d0_d1 * A^d1_d0 * A^d2_d3 * A^d3_d2 + t = A(d1, -d2)*A(d0, -d3)*A(d2,-d1)*A(d3,-d0) + tc = t.canon_bp() + assert str(tc) == 'A(L_0, -L_1)*A(L_1, -L_0)*A(L_2, -L_3)*A(L_3, -L_2)' + + # A^d0_d2 * A^d1_d3 * A^d3_d0 * A^d2_d1 + # T_c = A^d0_d1 * A^d1_d2 * A^d2_d3 * A^d3_d0 + t = A(d0, -d1)*A(d1, -d2)*A(d2, -d3)*A(d3,-d0) + tc = t.canon_bp() + assert str(tc) == 'A(L_0, -L_1)*A(L_1, -L_2)*A(L_2, -L_3)*A(L_3, -L_0)' + +def test_canonicalize1(): + Lorentz = TensorIndexType('Lorentz', dummy_fmt='L') + a, a0, a1, a2, a3, b, d0, d1, d2, d3 = \ + tensor_indices('a,a0,a1,a2,a3,b,d0,d1,d2,d3', Lorentz) + sym1 = tensorsymmetry([1]) + base3, gens3 = get_symmetric_group_sgs(3) + sym2 = tensorsymmetry([1]*2) + sym2a = tensorsymmetry([2]) + sym3 = tensorsymmetry([1]*3) + sym3a = tensorsymmetry([3]) + + # A_d0*A^d0; ord = [d0,-d0] + # T_c = A^d0*A_d0 + S1 = TensorType([Lorentz], sym1) + A = S1('A') + t = A(-d0)*A(d0) + tc = t.canon_bp() + assert str(tc) == 'A(L_0)*A(-L_0)' + + # A commuting + # A_d0*A_d1*A_d2*A^d2*A^d1*A^d0 + # T_c = A^d0*A_d0*A^d1*A_d1*A^d2*A_d2 + t = A(-d0)*A(-d1)*A(-d2)*A(d2)*A(d1)*A(d0) + tc = t.canon_bp() + assert str(tc) == 'A(L_0)*A(-L_0)*A(L_1)*A(-L_1)*A(L_2)*A(-L_2)' + + # A anticommuting + # A_d0*A_d1*A_d2*A^d2*A^d1*A^d0 + # T_c 0 + A = S1('A', 1) + t = A(-d0)*A(-d1)*A(-d2)*A(d2)*A(d1)*A(d0) + tc = t.canon_bp() + assert tc == 0 + + # A commuting symmetric + # A^{d0 b}*A^a_d1*A^d1_d0 + # T_c = A^{a d0}*A^{b d1}*A_{d0 d1} + S2 = TensorType([Lorentz]*2, sym2) + A = S2('A') + t = A(d0, b)*A(a, -d1)*A(d1, -d0) + tc = t.canon_bp() + assert str(tc) == 'A(a, L_0)*A(b, L_1)*A(-L_0, -L_1)' + + # A, B commuting symmetric + # A^{d0 b}*A^d1_d0*B^a_d1 + # T_c = A^{b d0}*A_d0^d1*B^a_d1 + B = S2('B') + t = A(d0, b)*A(d1, -d0)*B(a, -d1) + tc = t.canon_bp() + assert str(tc) == 'A(b, L_0)*A(-L_0, L_1)*B(a, -L_1)' + + # A commuting symmetric + # A^{d1 d0 b}*A^{a}_{d1 d0}; ord=[a,b, d0,-d0,d1,-d1] + # T_c = A^{a d0 d1}*A^{b}_{d0 d1} + S3 = TensorType([Lorentz]*3, sym3) + A = S3('A') + t = A(d1, d0, b)*A(a, -d1, -d0) + tc = t.canon_bp() + assert str(tc) == 'A(a, L_0, L_1)*A(b, -L_0, -L_1)' + + # A^{d3 d0 d2}*A^a0_{d1 d2}*A^d1_d3^a1*A^{a2 a3}_d0 + # T_c = A^{a0 d0 d1}*A^a1_d0^d2*A^{a2 a3 d3}*A_{d1 d2 d3} + t = A(d3, d0, d2)*A(a0, -d1, -d2)*A(d1, -d3, a1)*A(a2, a3, -d0) + tc = t.canon_bp() + assert str(tc) == 'A(a0, L_0, L_1)*A(a1, -L_0, L_2)*A(a2, a3, L_3)*A(-L_1, -L_2, -L_3)' + + # A commuting symmetric, B antisymmetric + # A^{d0 d1 d2} * A_{d2 d3 d1} * B_d0^d3 + # in this esxample and in the next three, + # renaming dummy indices and using symmetry of A, + # T = A^{d0 d1 d2} * A_{d0 d1 d3} * B_d2^d3 + # can = 0 + S2a = TensorType([Lorentz]*2, sym2a) + A = S3('A') + B = S2a('B') + t = A(d0, d1, d2)*A(-d2, -d3, -d1)*B(-d0, d3) + tc = t.canon_bp() + assert tc == 0 + + # A anticommuting symmetric, B anticommuting + # A^{d0 d1 d2} * A_{d2 d3 d1} * B_d0^d3 + # T_c = A^{d0 d1 d2} * A_{d0 d1}^d3 * B_{d2 d3} + A = S3('A', 1) + B = S2a('B') + t = A(d0, d1, d2)*A(-d2, -d3, -d1)*B(-d0, d3) + tc = t.canon_bp() + assert str(tc) == 'A(L_0, L_1, L_2)*A(-L_0, -L_1, L_3)*B(-L_2, -L_3)' + + # A anticommuting symmetric, B antisymmetric commuting, antisymmetric metric + # A^{d0 d1 d2} * A_{d2 d3 d1} * B_d0^d3 + # T_c = -A^{d0 d1 d2} * A_{d0 d1}^d3 * B_{d2 d3} + Spinor = TensorIndexType('Spinor', metric=1, dummy_fmt='S') + a, a0, a1, a2, a3, b, d0, d1, d2, d3 = \ + tensor_indices('a,a0,a1,a2,a3,b,d0,d1,d2,d3', Spinor) + S3 = TensorType([Spinor]*3, sym3) + S2a = TensorType([Spinor]*2, sym2a) + A = S3('A', 1) + B = S2a('B') + t = A(d0, d1, d2)*A(-d2, -d3, -d1)*B(-d0, d3) + tc = t.canon_bp() + assert str(tc) == '-A(S_0, S_1, S_2)*A(-S_0, -S_1, S_3)*B(-S_2, -S_3)' + + # A anticommuting symmetric, B antisymmetric anticommuting, + # no metric symmetry + # A^{d0 d1 d2} * A_{d2 d3 d1} * B_d0^d3 + # T_c = A^{d0 d1 d2} * A_{d0 d1 d3} * B_d2^d3 + Mat = TensorIndexType('Mat', metric=None, dummy_fmt='M') + a, a0, a1, a2, a3, b, d0, d1, d2, d3 = \ + tensor_indices('a,a0,a1,a2,a3,b,d0,d1,d2,d3', Mat) + S3 = TensorType([Mat]*3, sym3) + S2a = TensorType([Mat]*2, sym2a) + A = S3('A', 1) + B = S2a('B') + t = A(d0, d1, d2)*A(-d2, -d3, -d1)*B(-d0, d3) + tc = t.canon_bp() + assert str(tc) == 'A(M_0, M_1, M_2)*A(-M_0, -M_1, -M_3)*B(-M_2, M_3)' + + # Gamma anticommuting + # Gamma_{mu nu} * gamma^rho * Gamma^{nu mu alpha} + # T_c = -Gamma^{mu nu} * gamma^rho * Gamma_{alpha mu nu} + S1 = TensorType([Lorentz], sym1) + S2a = TensorType([Lorentz]*2, sym2a) + S3a = TensorType([Lorentz]*3, sym3a) + alpha, beta, gamma, mu, nu, rho = \ + tensor_indices('alpha,beta,gamma,mu,nu,rho', Lorentz) + Gamma = S1('Gamma', 2) + Gamma2 = S2a('Gamma', 2) + Gamma3 = S3a('Gamma', 2) + t = Gamma2(-mu,-nu)*Gamma(rho)*Gamma3(nu, mu, alpha) + tc = t.canon_bp() + assert str(tc) == '-Gamma(L_0, L_1)*Gamma(rho)*Gamma(alpha, -L_0, -L_1)' + + # Gamma_{mu nu} * Gamma^{gamma beta} * gamma_rho * Gamma^{nu mu alpha} + # T_c = Gamma^{mu nu} * Gamma^{beta gamma} * gamma_rho * Gamma^alpha_{mu nu} + t = Gamma2(mu, nu)*Gamma2(beta, gamma)*Gamma(-rho)*Gamma3(alpha, -mu, -nu) + tc = t.canon_bp() + assert str(tc) == 'Gamma(L_0, L_1)*Gamma(beta, gamma)*Gamma(-rho)*Gamma(alpha, -L_0, -L_1)' + + # f^a_{b,c} antisymmetric in b,c; A_mu^a no symmetry + # f^c_{d a} * f_{c e b} * A_mu^d * A_nu^a * A^{nu e} * A^{mu b} + # g = [8,11,5, 9,13,7, 1,10, 3,4, 2,12, 0,6, 14,15] + # T_c = -f^{a b c} * f_a^{d e} * A^mu_b * A_{mu d} * A^nu_c * A_{nu e} + Flavor = TensorIndexType('Flavor', dummy_fmt='F') + a, b, c, d, e, ff = tensor_indices('a,b,c,d,e,f', Flavor) + mu, nu = tensor_indices('mu,nu', Lorentz) + sym_f = tensorsymmetry([1], [2]) + S_f = TensorType([Flavor]*3, sym_f) + sym_A = tensorsymmetry([1], [1]) + S_A = TensorType([Lorentz, Flavor], sym_A) + f = S_f('f') + A = S_A('A') + t = f(c, -d, -a)*f(-c, -e, -b)*A(-mu, d)*A(-nu, a)*A(nu, e)*A(mu, b) + tc = t.canon_bp() + assert str(tc) == '-f(F_0, F_1, F_2)*f(-F_0, F_3, F_4)*A(L_0, -F_1)*A(-L_0, -F_3)*A(L_1, -F_2)*A(-L_1, -F_4)' + + +def test_riemann_invariants(): + Lorentz = TensorIndexType('Lorentz', dummy_fmt='L') + d0, d1, d2, d3, d4, d5, d6, d7, d8, d9, d10, d11 = \ + tensor_indices('d0:12', Lorentz) + # R^{d0 d1}_{d1 d0}; ord = [d0,-d0,d1,-d1] + # T_c = -R^{d0 d1}_{d0 d1} + R = tensorhead('R', [Lorentz]*4, [[2, 2]]) + t = R(d0, d1, -d1, -d0) + tc = t.canon_bp() + assert str(tc) == '-R(L_0, L_1, -L_0, -L_1)' + + # R_d11^d1_d0^d5 * R^{d6 d4 d0}_d5 * R_{d7 d2 d8 d9} * + # R_{d10 d3 d6 d4} * R^{d2 d7 d11}_d1 * R^{d8 d9 d3 d10} + # can = [0,2,4,6, 1,3,8,10, 5,7,12,14, 9,11,16,18, 13,15,20,22, + # 17,19,21>> from sympy.unify.core import unify, Compound, Variable + >>> from sympy.core.compatibility import next + >>> expr = Compound("Add", ("x", "y")) + >>> pattern = Compound("Add", ("x", Variable("a"))) + >>> next(unify(expr, pattern, {})) + {Variable(a): 'y'} + """ + s = s or {} + + if x == y: + yield s + elif isinstance(x, (Variable, CondVariable)): + for match in unify_var(x, y, s, **fns): + yield match + elif isinstance(y, (Variable, CondVariable)): + for match in unify_var(y, x, s, **fns): + yield match + elif isinstance(x, Compound) and isinstance(y, Compound): + is_commutative = fns.get('is_commutative', lambda x: False) + is_associative = fns.get('is_associative', lambda x: False) + for sop in unify(x.op, y.op, s, **fns): + if is_associative(x) and is_associative(y): + a, b = (x, y) if len(x.args) < len(y.args) else (y, x) + if is_commutative(x) and is_commutative(y): + combs = allcombinations(a.args, b.args, 'commutative') + else: + combs = allcombinations(a.args, b.args, 'associative') + for aaargs, bbargs in combs: + aa = [unpack(Compound(a.op, arg)) for arg in aaargs] + bb = [unpack(Compound(b.op, arg)) for arg in bbargs] + for match in unify(aa, bb, sop, **fns): + yield match + elif len(x.args) == len(y.args): + for match in unify(x.args, y.args, sop, **fns): + yield match + + elif is_args(x) and is_args(y) and len(x) == len(y): + if len(x) == 0: + yield s + else: + for shead in unify(x[0], y[0], s, **fns): + for match in unify(x[1:], y[1:], shead, **fns): + yield match + +def unify_var(var, x, s, **fns): + if var in s: + for match in unify(s[var], x, s, **fns): + yield match + elif occur_check(var, x): + pass + elif isinstance(var, CondVariable) and var.valid(x): + yield assoc(s, var, x) + elif isinstance(var, Variable): + yield assoc(s, var, x) + +def occur_check(var, x): + """ var occurs in subtree owned by x? """ + if var == x: + return True + elif isinstance(x, Compound): + return occur_check(var, x.args) + elif is_args(x): + if any(occur_check(var, xi) for xi in x): return True + return False + +def assoc(d, key, val): + """ Return copy of d with key associated to val """ + d = d.copy() + d[key] = val + return d + +def is_args(x): + """ Is x a traditional iterable? """ + return type(x) in (tuple, list, set) + +def unpack(x): + if isinstance(x, Compound) and len(x.args) == 1: + return x.args[0] + else: + return x + +def allcombinations(A, B, ordered): + """ + Restructure A and B to have the same number of elements + + ordered must be either 'commutative' or 'associative' + + A and B can be rearranged so that the larger of the two lists is + reorganized into smaller sublists. + + >>> from sympy.unify.core import allcombinations + >>> for x in allcombinations((1, 2, 3), (5, 6), 'associative'): print(x) + (((1,), (2, 3)), ((5,), (6,))) + (((1, 2), (3,)), ((5,), (6,))) + + >>> for x in allcombinations((1, 2, 3), (5, 6), 'commutative'): print(x) + (((1,), (2, 3)), ((5,), (6,))) + (((1, 2), (3,)), ((5,), (6,))) + (((1,), (3, 2)), ((5,), (6,))) + (((1, 3), (2,)), ((5,), (6,))) + (((2,), (1, 3)), ((5,), (6,))) + (((2, 1), (3,)), ((5,), (6,))) + (((2,), (3, 1)), ((5,), (6,))) + (((2, 3), (1,)), ((5,), (6,))) + (((3,), (1, 2)), ((5,), (6,))) + (((3, 1), (2,)), ((5,), (6,))) + (((3,), (2, 1)), ((5,), (6,))) + (((3, 2), (1,)), ((5,), (6,))) + """ + + if ordered == "commutative": + ordered = 11 + if ordered == "associative": + ordered = None + sm, bg = (A, B) if len(A) < len(B) else (B, A) + for part in kbins(list(range(len(bg))), len(sm), ordered=ordered): + if bg == B: + yield tuple((a,) for a in A), partition(B, part) + else: + yield partition(A, part), tuple((b,) for b in B) + +def partition(it, part): + """ Partition a tuple/list into pieces defined by indices + + >>> from sympy.unify.core import partition + >>> partition((10, 20, 30, 40), [[0, 1, 2], [3]]) + ((10, 20, 30), (40,)) + """ + return type(it)([index(it, ind) for ind in part]) + +def index(it, ind): + """ Fancy indexing into an indexable iterable (tuple, list) + + >>> from sympy.unify.core import index + >>> index([10, 20, 30], (1, 2, 0)) + [20, 30, 10] + """ + return type(it)([it[i] for i in ind]) diff -Nru python3-sympy-0.7.2/sympy/unify/rewrite.py python3-sympy-0.7.3/sympy/unify/rewrite.py --- python3-sympy-0.7.2/sympy/unify/rewrite.py 1970-01-01 00:00:00.000000000 +0000 +++ python3-sympy-0.7.3/sympy/unify/rewrite.py 2013-07-13 17:53:32.000000000 +0000 @@ -0,0 +1,52 @@ +""" Functions to support rewriting of SymPy expressions """ + +from sympy.unify.usympy import unify +from sympy.unify.usympy import rebuild +from sympy.strategies.tools import subs +from sympy import Expr +from sympy.assumptions import Q, ask + +def rewriterule(source, target, variables=(), condition=None, assume=None): + """ Rewrite rule + + Transform expressions that match source into expressions that match target + treating all `variables` as wilds. + + >>> from sympy.abc import w, x, y, z + >>> from sympy.unify.rewrite import rewriterule + >>> rl = rewriterule(x + y, x**y, [x, y]) + >>> sorted(rl(z + 3)) + [3**z, z**3] + + Use ``condition`` to specify additional requirements. Inputs are taken in + the same order as is found in variables. + + >>> rl = rewriterule(x + y, x**y, [x, y], lambda x, y: x.is_integer) + >>> list(rl(z + 3)) + [3**z] + + Use ``assume`` to specify additional requirements using new assumptions. + + >>> from sympy.assumptions import Q + >>> rl = rewriterule(x + y, x**y, [x, y], assume=Q.integer(x)) + >>> list(rl(z + 3)) + [3**z] + + Assumptions for the local context are provided at rule runtime + + >>> list(rl(w + z, Q.integer(z))) + [z**w] + """ + + def rewrite_rl(expr, assumptions=True): + for match in unify(source, expr, {}, variables=variables): + if (condition and + not condition(*[match.get(var, var) for var in variables])): + continue + if (assume and not ask(assume.xreplace(match), assumptions)): + continue + expr2 = subs(match)(target) + if isinstance(expr2, Expr): + expr2 = rebuild(expr2) + yield expr2 + return rewrite_rl diff -Nru python3-sympy-0.7.2/sympy/unify/tests/test_rewrite.py python3-sympy-0.7.3/sympy/unify/tests/test_rewrite.py --- python3-sympy-0.7.2/sympy/unify/tests/test_rewrite.py 1970-01-01 00:00:00.000000000 +0000 +++ python3-sympy-0.7.3/sympy/unify/tests/test_rewrite.py 2013-07-13 17:53:32.000000000 +0000 @@ -0,0 +1,72 @@ +from sympy.unify.rewrite import rewriterule +from sympy import sin, cos, Basic, Symbol, S +from sympy.abc import x, y, z +from sympy.core.compatibility import next +from sympy.strategies.rl import rebuild +from sympy.assumptions import Q + +p, q = Symbol('p'), Symbol('q') + +def test_simple(): + rl = rewriterule(Basic(p, 1), Basic(p, 2), variables=(p,)) + assert list(rl(Basic(3, 1))) == [Basic(3, 2)] + + p1 = p**2 + p2 = p**3 + rl = rewriterule(p1, p2, variables=(p,)) + + expr = x**2 + assert list(rl(expr)) == [x**3] + +def test_simple_variables(): + rl = rewriterule(Basic(x, 1), Basic(x, 2), variables=(x,)) + assert list(rl(Basic(3, 1))) == [Basic(3, 2)] + + rl = rewriterule(x**2, x**3, variables=(x,)) + assert list(rl(y**2)) == [y**3] + +def test_moderate(): + p1 = p**2 + q**3 + p2 = (p*q)**4 + rl = rewriterule(p1, p2, (p, q)) + + expr = x**2 + y**3 + assert list(rl(expr)) == [(x*y)**4] + +def test_sincos(): + p1 = sin(p)**2 + sin(p)**2 + p2 = 1 + rl = rewriterule(p1, p2, (p, q)) + + assert list(rl(sin(x)**2 + sin(x)**2)) == [1] + assert list(rl(sin(y)**2 + sin(y)**2)) == [1] + +def test_Exprs_ok(): + rl = rewriterule(p+q, q+p, (p, q)) + next(rl(x+y)).is_commutative + str(next(rl(x+y))) + +def test_condition_simple(): + rl = rewriterule(x, x+1, [x], lambda x: x < 10) + assert not list(rl(S(15))) + assert rebuild(next(rl(S(5)))) == 6 + + +def test_condition_multiple(): + rl = rewriterule(x + y, x**y, [x,y], lambda x, y: x.is_integer) + + a = Symbol('a') + b = Symbol('b', integer=True) + expr = a + b + assert list(rl(expr)) == [b**a] + + c = Symbol('c', integer=True) + d = Symbol('d', integer=True) + assert set(rl(c + d)) == set([c**d, d**c]) + +def test_assumptions(): + rl = rewriterule(x + y, x**y, [x, y], assume=Q.integer(x)) + + a, b = list(map(Symbol, 'ab')) + expr = a + b + assert list(rl(expr, Q.integer(b))) == [b**a] diff -Nru python3-sympy-0.7.2/sympy/unify/tests/test_sympy.py python3-sympy-0.7.3/sympy/unify/tests/test_sympy.py --- python3-sympy-0.7.2/sympy/unify/tests/test_sympy.py 1970-01-01 00:00:00.000000000 +0000 +++ python3-sympy-0.7.3/sympy/unify/tests/test_sympy.py 2013-07-13 17:53:32.000000000 +0000 @@ -0,0 +1,156 @@ +from sympy import Add, Basic, symbols, Mul, And, Symbol +from sympy.unify.core import Compound, Variable +from sympy.unify.usympy import (deconstruct, construct, unify, is_associative, + is_commutative) +from sympy.abc import w, x, y, z, n, m, k +from sympy.utilities.pytest import XFAIL +from sympy.core.compatibility import next + +def test_deconstruct(): + expr = Basic(1, 2, 3) + expected = Compound(Basic, (1, 2, 3)) + assert deconstruct(expr) == expected + + assert deconstruct(1) == 1 + assert deconstruct(x) == x + assert deconstruct(x, variables=(x,)) == Variable(x) + assert deconstruct(Add(1, x, evaluate=False)) == Compound(Add, (1, x)) + assert deconstruct(Add(1, x, evaluate=False), variables=(x,)) == \ + Compound(Add, (1, Variable(x))) + +def test_construct(): + expr = Compound(Basic, (1, 2, 3)) + expected = Basic(1, 2, 3) + assert construct(expr) == expected + +def test_nested(): + expr = Basic(1, Basic(2), 3) + cmpd = Compound(Basic, (1, Compound(Basic, (2,)), 3)) + assert deconstruct(expr) == cmpd + assert construct(cmpd) == expr + +def test_unify(): + expr = Basic(1, 2, 3) + a, b, c = list(map(Symbol, 'abc')) + pattern = Basic(a, b, c) + assert list(unify(expr, pattern, {}, (a, b, c))) == [{a: 1, b: 2, c: 3}] + assert list(unify(expr, pattern, variables=(a, b, c))) == \ + [{a: 1, b: 2, c: 3}] + +def test_unify_variables(): + assert list(unify(Basic(1, 2), Basic(1, x), {}, variables=(x,))) == [{x: 2}] + +def test_s_input(): + expr = Basic(1, 2) + a, b = list(map(Symbol, 'ab')) + pattern = Basic(a, b) + assert list(unify(expr, pattern, {}, (a, b))) == [{a: 1, b: 2}] + assert list(unify(expr, pattern, {a: 5}, (a, b))) == [] + +def iterdicteq(a, b): + a = tuple(a) + b = tuple(b) + return len(a) == len(b) and all(x in b for x in a) + +def test_unify_commutative(): + expr = Add(1, 2, 3, evaluate=False) + a, b, c = list(map(Symbol, 'abc')) + pattern = Add(a, b, c, evaluate=False) + + result = tuple(unify(expr, pattern, {}, (a, b, c))) + expected = ({a: 1, b: 2, c: 3}, + {a: 1, b: 3, c: 2}, + {a: 2, b: 1, c: 3}, + {a: 2, b: 3, c: 1}, + {a: 3, b: 1, c: 2}, + {a: 3, b: 2, c: 1}) + + assert iterdicteq(result, expected) + +def test_unify_iter(): + expr = Add(1, 2, 3, evaluate=False) + a, b, c = list(map(Symbol, 'abc')) + pattern = Add(a, c, evaluate=False) + assert is_associative(deconstruct(pattern)) + assert is_commutative(deconstruct(pattern)) + + result = list(unify(expr, pattern, {}, (a, c))) + expected = [{a: 1, c: Add(2, 3, evaluate=False)}, + {a: 1, c: Add(3, 2, evaluate=False)}, + {a: 2, c: Add(1, 3, evaluate=False)}, + {a: 2, c: Add(3, 1, evaluate=False)}, + {a: 3, c: Add(1, 2, evaluate=False)}, + {a: 3, c: Add(2, 1, evaluate=False)}, + {a: Add(1, 2, evaluate=False), c: 3}, + {a: Add(2, 1, evaluate=False), c: 3}, + {a: Add(1, 3, evaluate=False), c: 2}, + {a: Add(3, 1, evaluate=False), c: 2}, + {a: Add(2, 3, evaluate=False), c: 1}, + {a: Add(3, 2, evaluate=False), c: 1}] + + assert iterdicteq(result, expected) + +def test_hard_match(): + from sympy import sin, cos + expr = sin(x) + cos(x)**2 + p, q = list(map(Symbol, 'pq')) + pattern = sin(p) + cos(p)**2 + assert list(unify(expr, pattern, {}, (p, q))) == [{p: x}] + +def test_matrix(): + from sympy import MatrixSymbol + X = MatrixSymbol('X', n, n) + Y = MatrixSymbol('Y', 2, 2) + Z = MatrixSymbol('Z', 2, 3) + assert list(unify(X, Y, {}, variables=[n, 'X'])) == [{'X': 'Y', n: 2}] + assert list(unify(X, Z, {}, variables=[n, 'X'])) == [] + +def test_non_frankenAdds(): + # the is_commutative property used to fail because of Basic.__new__ + # This caused is_commutative and str calls to fail + expr = x+y*2 + rebuilt = construct(deconstruct(expr)) + # Ensure that we can run these commands without causing an error + str(rebuilt) + rebuilt.is_commutative + +def test_FiniteSet_commutivity(): + from sympy import FiniteSet + a, b, c, x, y = symbols('a,b,c,x,y') + s = FiniteSet(a, b, c) + t = FiniteSet(x, y) + variables = (x, y) + assert {x: FiniteSet(a, c), y: b} in tuple(unify(s, t, variables=variables)) + +def test_FiniteSet_complex(): + from sympy import FiniteSet + a, b, c, x, y, z = symbols('a,b,c,x,y,z') + expr = FiniteSet(Basic(1, x), y, Basic(x, z)) + pattern = FiniteSet(a, Basic(x, b)) + variables = a, b + expected = tuple([{b: 1, a: FiniteSet(y, Basic(x, z))}, + {b: z, a: FiniteSet(y, Basic(1, x))}]) + assert iterdicteq(unify(expr, pattern, variables=variables), expected) + +@XFAIL +def test_and(): + variables = x, y + str(list(unify((x>0) & (z<3), pattern, variables=variables))) + +def test_Union(): + from sympy import Interval + assert list(unify(Interval(0, 1) + Interval(10, 11), + Interval(0, 1) + Interval(12, 13), + variables=(Interval(12, 13),))) + +def test_is_commutative(): + assert is_commutative(deconstruct(x+y)) + assert is_commutative(deconstruct(x*y)) + assert not is_commutative(deconstruct(x**y)) + +def test_commutative_in_commutative(): + from sympy.abc import a,b,c,d + from sympy import sin, cos + eq = sin(3)*sin(4)*sin(5) + 4*cos(3)*cos(4) + pat = a*cos(b)*cos(c) + d*sin(b)*sin(c) + assert next(unify(eq, pat, variables=(a,b,c,d))) diff -Nru python3-sympy-0.7.2/sympy/unify/tests/test_unify.py python3-sympy-0.7.3/sympy/unify/tests/test_unify.py --- python3-sympy-0.7.2/sympy/unify/tests/test_unify.py 1970-01-01 00:00:00.000000000 +0000 +++ python3-sympy-0.7.3/sympy/unify/tests/test_unify.py 2013-07-13 17:53:32.000000000 +0000 @@ -0,0 +1,90 @@ +from sympy.unify.core import Compound, Variable, CondVariable, allcombinations +from sympy.unify import core +from sympy.core.compatibility import next + +a,b,c = 'abc' +w,x,y,z = list(map(Variable, 'wxyz')) + +C = Compound + +def is_associative(x): + return isinstance(x, Compound) and (x.op in ('Add', 'Mul', 'CAdd', 'CMul')) +def is_commutative(x): + return isinstance(x, Compound) and (x.op in ('CAdd', 'CMul')) + + +def unify(a, b, s={}): + return core.unify(a, b, s=s, is_associative=is_associative, + is_commutative=is_commutative) + +def test_basic(): + assert list(unify(a, x, {})) == [{x: a}] + assert list(unify(a, x, {x: 10})) == [] + assert list(unify(1, x, {})) == [{x: 1}] + assert list(unify(a, a, {})) == [{}] + assert list(unify((w, x), (y, z), {})) == [{w: y, x: z}] + assert list(unify(x, (a, b), {})) == [{x: (a, b)}] + + assert list(unify((a, b), (x, x), {})) == [] + assert list(unify((y, z), (x, x), {}))!= [] + assert list(unify((a, (b, c)), (a, (x, y)), {})) == [{x: b, y: c}] + +def test_ops(): + assert list(unify(C('Add', (a,b,c)), C('Add', (a,x,y)), {})) == \ + [{x:b, y:c}] + assert list(unify(C('Add', (C('Mul', (1,2)), b,c)), C('Add', (x,y,c)), {})) == \ + [{x: C('Mul', (1,2)), y:b}] + +def test_associative(): + c1 = C('Add', (1,2,3)) + c2 = C('Add', (x,y)) + result = list(unify(c1, c2, {})) + assert tuple(unify(c1, c2, {})) == ({x: 1, y: C('Add', (2, 3))}, + {x: C('Add', (1, 2)), y: 3}) + +def test_commutative(): + c1 = C('CAdd', (1,2,3)) + c2 = C('CAdd', (x,y)) + result = list(unify(c1, c2, {})) + assert {x: 1, y: C('CAdd', (2, 3))} in result + assert ({x: 2, y: C('CAdd', (1, 3))} in result or + {x: 2, y: C('CAdd', (3, 1))} in result) + +def _test_combinations_assoc(): + assert set(allcombinations((1,2,3), (a,b), True)) == \ + set(((((1, 2), (3,)), (a, b)), (((1,), (2, 3)), (a, b)))) + +def _test_combinations_comm(): + assert set(allcombinations((1,2,3), (a,b), None)) == \ + set(((((1,), (2, 3)), ('a', 'b')), (((2,), (3, 1)), ('a', 'b')), + (((3,), (1, 2)), ('a', 'b')), (((1, 2), (3,)), ('a', 'b')), + (((2, 3), (1,)), ('a', 'b')), (((3, 1), (2,)), ('a', 'b')))) + +def test_allcombinations(): + assert set(allcombinations((1,2), (1,2), 'commutative')) ==\ + set(((((1,),(2,)), ((1,),(2,))), (((1,),(2,)), ((2,),(1,))))) + + +def test_commutativity(): + c1 = Compound('CAdd', (a, b)) + c2 = Compound('CAdd', (x, y)) + assert is_commutative(c1) and is_commutative(c2) + assert len(list(unify(c1, c2, {}))) == 2 + + +def test_CondVariable(): + expr = C('CAdd', (1, 2)) + x = Variable('x') + y = CondVariable('y', lambda a: a % 2 == 0) + z = CondVariable('z', lambda a: a > 3) + pattern = C('CAdd', (x, y)) + assert list(unify(expr, pattern, {})) == \ + [{x: 1, y: 2}] + + z = CondVariable('z', lambda a: a > 3) + pattern = C('CAdd', (z, y)) + + assert list(unify(expr, pattern, {})) == [] + +def test_defaultdict(): + assert next(unify(Variable('x'), 'foo')) == {Variable('x'): 'foo'} diff -Nru python3-sympy-0.7.2/sympy/unify/usympy.py python3-sympy-0.7.3/sympy/unify/usympy.py --- python3-sympy-0.7.2/sympy/unify/usympy.py 1970-01-01 00:00:00.000000000 +0000 +++ python3-sympy-0.7.3/sympy/unify/usympy.py 2013-07-13 17:53:32.000000000 +0000 @@ -0,0 +1,126 @@ +""" SymPy interface to Unification engine + +See sympy.unify for module level docstring +See sympy.unify.core for algorithmic docstring """ + + +from sympy.core import Basic, Expr, Tuple, Add, Mul, Pow, FiniteSet +from sympy.matrices import MatAdd, MatMul, MatrixExpr +from sympy.core.sets import Union, Intersection, FiniteSet +from sympy.core.operations import AssocOp, LatticeOp +from sympy.unify.core import Compound, Variable, CondVariable +from sympy.unify import core + +basic_new_legal = [MatrixExpr] +eval_false_legal = [AssocOp, Pow, FiniteSet] +illegal = [LatticeOp] + +def sympy_associative(op): + assoc_ops = (AssocOp, MatAdd, MatMul, Union, Intersection, FiniteSet) + return any(issubclass(op, aop) for aop in assoc_ops) + +def sympy_commutative(op): + comm_ops = (Add, MatAdd, Union, Intersection, FiniteSet) + return any(issubclass(op, cop) for cop in comm_ops) + +def is_associative(x): + return isinstance(x, Compound) and sympy_associative(x.op) + +def is_commutative(x): + if not isinstance(x, Compound): + return False + if sympy_commutative(x.op): + return True + if issubclass(x.op, Mul): + return all(construct(arg).is_commutative for arg in x.args) + +def mk_matchtype(typ): + def matchtype(x): + return (isinstance(x, typ) or + isinstance(x, Compound) and issubclass(x.op, typ)) + return matchtype + +def deconstruct(s, variables=()): + """ Turn a SymPy object into a Compound """ + if s in variables: + return Variable(s) + if isinstance(s, (Variable, CondVariable)): + return s + if not isinstance(s, Basic) or s.is_Atom: + return s + return Compound(s.__class__, + tuple(deconstruct(arg, variables) for arg in s.args)) + +def construct(t): + """ Turn a Compound into a SymPy object """ + if isinstance(t, (Variable, CondVariable)): + return t.arg + if not isinstance(t, Compound): + return t + if any(issubclass(t.op, cls) for cls in eval_false_legal): + return t.op(*list(map(construct, t.args)), **{'evaluate': False}) + elif any(issubclass(t.op, cls) for cls in basic_new_legal): + return Basic.__new__(t.op, *list(map(construct, t.args))) + else: + return t.op(*list(map(construct, t.args))) + +def rebuild(s): + """ Rebuild a SymPy expression + + This removes harm caused by Expr-Rules interactions + """ + return construct(deconstruct(s)) + +def unify(x, y, s=None, variables=(), **kwargs): + """ Structural unification of two expressions/patterns + + Examples + ======== + + >>> from sympy.unify.usympy import unify + >>> from sympy import Basic, cos + >>> from sympy.abc import x, y, z, p, q + >>> from sympy.core.compatibility import next + + >>> next(unify(Basic(1, 2), Basic(1, x), variables=[x])) + {x: 2} + + >>> expr = 2*x + y + z + >>> pattern = 2*p + q + >>> next(unify(expr, pattern, {}, variables=(p, q))) + {p: x, q: y + z} + + Unification supports commutative and associative matching + + >>> expr = x + y + z + >>> pattern = p + q + >>> len(list(unify(expr, pattern, {}, variables=(p, q)))) + 12 + + Symbols not indicated to be variables are treated as literal, + else they are wild-like and match anything in a sub-expression. + + >>> expr = x*y*z + 3 + >>> pattern = x*y + 3 + >>> next(unify(expr, pattern, {}, variables=[x, y])) + {x: y, y: x*z} + + The x and y of the pattern above were in a Mul and matched factors + in the Mul of expr. Here, a single symbol matches an entire term: + + >>> expr = x*y + 3 + >>> pattern = p + 3 + >>> next(unify(expr, pattern, {}, variables=[p])) + {p: x*y} + + """ + decons = lambda x: deconstruct(x, variables) + s = s or {} + s = dict((decons(k), decons(v)) for k, v in list(s.items())) + + ds = core.unify(decons(x), decons(y), s, + is_associative=is_associative, + is_commutative=is_commutative, + **kwargs) + for d in ds: + yield dict((construct(k), construct(v)) for k, v in list(d.items())) diff -Nru python3-sympy-0.7.2/sympy/utilities/__init__.py python3-sympy-0.7.3/sympy/utilities/__init__.py --- python3-sympy-0.7.2/sympy/utilities/__init__.py 2012-10-17 03:02:22.000000000 +0000 +++ python3-sympy-0.7.3/sympy/utilities/__init__.py 2013-07-13 17:53:32.000000000 +0000 @@ -5,7 +5,7 @@ variations, numbered_symbols, cartes, capture, dict_merge, postorder_traversal, interactive_traversal, prefixes, postfixes, sift, topological_sort, unflatten, - quick_sort, has_dups, has_variety, reshape) + has_dups, has_variety, reshape, default_sort_key, ordered) from .lambdify import lambdify from .source import source @@ -16,5 +16,3 @@ from .cythonutils import cythonized from .timeutils import timed - -from .misc import default_sort_key diff -Nru python3-sympy-0.7.2/sympy/utilities/autowrap.py python3-sympy-0.7.3/sympy/utilities/autowrap.py --- python3-sympy-0.7.2/sympy/utilities/autowrap.py 2012-10-17 03:02:22.000000000 +0000 +++ python3-sympy-0.7.3/sympy/utilities/autowrap.py 2013-07-13 17:53:32.000000000 +0000 @@ -12,8 +12,8 @@ >>> from sympy.abc import x,y >>> expr = ((x - y)**(25)).expand() - >>> binary_callable = autowrap(expr) # doctest: +SKIP - >>> binary_callable(1, 2) # doctest: +SKIP + >>> binary_callable = autowrap(expr) + >>> binary_callable(1, 2) -1.0 The callable returned from autowrap() is a binary python function, not a @@ -24,11 +24,11 @@ lambdify(). >>> from sympy.utilities.autowrap import binary_function - >>> f = binary_function('f', expr) # doctest: +SKIP - >>> 2*f(x, y) + y # doctest: +SKIP + >>> f = binary_function('f', expr) + >>> 2*f(x, y) + y y + 2*f(x, y) - >>> (2*f(x, y) + y).evalf(2, subs={x: 1, y:2}) # doctest: +SKIP - 0.0 + >>> (2*f(x, y) + y).evalf(2, subs={x: 1, y:2}) + 0.e-110 The idea is that a SymPy user will primarily be interested in working with mathematical expressions, and should not have to learn details about wrapping @@ -66,20 +66,27 @@ """ +_doctest_depends_on = { 'exe': ('f2py', 'gfortran'), 'modules': ('numpy',)} + import sys import os import shutil import tempfile -import subprocess +from subprocess import STDOUT, CalledProcessError +from sympy.core.compatibility import check_output from sympy.utilities.codegen import ( - get_code_generator, Routine, OutputArgument, InOutArgument, - CodeGenArgumentListError, Result - ) + get_code_generator, Routine, OutputArgument, InOutArgument, + CodeGenArgumentListError, Result +) from sympy.utilities.lambdify import implemented_function +from sympy.utilities.decorator import doctest_depends_on from sympy import C -class CodeWrapError(Exception): pass + +class CodeWrapError(Exception): + pass + class CodeWrapper: """Base Class for code wrappers""" @@ -114,8 +121,9 @@ def _generate_code(self, main_routine, routines): routines.append(main_routine) - self.generator.write(routines, self.filename, True, self.include_header, - self.include_empty) + self.generator.write( + routines, self.filename, True, self.include_header, + self.include_empty) def wrap_code(self, routine, helpers=[]): @@ -132,7 +140,7 @@ mod = __import__(self.module_name) finally: sys.path.remove(workdir) - CodeWrapper._module_counter +=1 + CodeWrapper._module_counter += 1 os.chdir(oldwork) if not self.filepath: shutil.rmtree(workdir) @@ -142,17 +150,15 @@ def _process_files(self, routine): command = self.command command.extend(self.flags) - null = open(os.devnull, 'w') try: - if self.quiet: - retcode = subprocess.call(command, stdout=null, stderr=subprocess.STDOUT) - else: - retcode = subprocess.call(command) - except OSError: - retcode = 1 - if retcode: + retoutput = check_output(command, stderr=STDOUT) + except CalledProcessError as e: raise CodeWrapError( - "Error while executing command: %s" % " ".join(command)) + "Error while executing command: %s. Command output is:\n%s" % ( + " ".join(command), e.output)) + if not self.quiet: + print(retoutput) + class DummyWrapper(CodeWrapper): """Class used for testing independent of backends """ @@ -163,14 +169,17 @@ %(name)s.args = "%(args)s" %(name)s.returns = "%(retvals)s" """ + def _prepare_files(self, routine): return def _generate_code(self, routine, helpers): with open('%s.py' % self.module_name, 'w') as f: - printed = ", ".join([str(res.expr) for res in routine.result_variables]) + printed = ", ".join( + [str(res.expr) for res in routine.result_variables]) # convert OutputArguments to return value like f2py - inargs = [x for x in routine.arguments if not isinstance(x, OutputArgument)] + inargs = [x for x in routine.arguments if not isinstance( + x, OutputArgument)] retvals = [] for val in routine.result_variables: if isinstance(val, Result): @@ -179,11 +188,11 @@ retvals.append(val.result_var) print(DummyWrapper.template % { - 'name': routine.name, - 'expr': printed, - 'args': ", ".join([str(arg.name) for arg in inargs]), - 'retvals': ", ".join([str(val) for val in retvals]) - }, file=f) + 'name': routine.name, + 'expr': printed, + 'args': ", ".join([str(arg.name) for arg in inargs]), + 'retvals': ", ".join([str(val) for val in retvals]) + }, file=f) def _process_files(self, routine): return @@ -192,6 +201,7 @@ def _get_wrapped_function(cls, mod): return mod.autofunc + class CythonCodeWrapper(CodeWrapper): """Wrapper that uses Cython""" @@ -223,7 +233,8 @@ # setup.py ext_args = [repr(self.module_name), repr([pyxfilename, codefilename])] with open('setup.py', 'w') as f: - print(CythonCodeWrapper.setup_template % {'args': ", ".join(ext_args)}, file=f) + print(CythonCodeWrapper.setup_template % { + 'args': ", ".join(ext_args)}, file=f) @classmethod def _get_wrapped_function(cls, mod): @@ -250,15 +261,12 @@ """ for routine in routines: prototype = self.generator.get_prototype(routine) - origname = routine.name - routine.name = "%s_c" % origname - prototype_c = self.generator.get_prototype(routine) - routine.name = origname # declare print('cdef extern from "%s.h":' % prefix, file=f) print(' %s' % prototype, file=f) - if empty: print(file=f) + if empty: + print(file=f) # wrap ret, args_py = self._split_retvals_inargs(routine.arguments) @@ -279,7 +287,8 @@ print(' %s(%s)' % (routine.name, args_c), file=f) print(' return %s' % rets, file=f) - if empty: print(file=f) + if empty: + print(file=f) dump_pyx.extension = "pyx" def _split_retvals_inargs(self, args): @@ -299,9 +308,10 @@ def _declare_arg(self, arg): t = arg.get_datatype('c') if arg.dimensions: - return "%s *%s"%(t, str(arg.name)) + return "%s *%s" % (t, str(arg.name)) else: - return "%s %s"%(t, str(arg.name)) + return "%s %s" % (t, str(arg.name)) + class F2PyCodeWrapper(CodeWrapper): """Wrapper that uses f2py""" @@ -309,7 +319,7 @@ @property def command(self): filename = self.filename + '.' + self.generator.code_extension - command = ["f2py", "-m", self.module_name, "-c" , filename] + command = ["f2py", "-m", self.module_name, "-c", filename] return command def _prepare_files(self, routine): @@ -319,11 +329,16 @@ def _get_wrapped_function(cls, mod): return mod.autofunc + def _get_code_wrapper_class(backend): - wrappers = { 'F2PY': F2PyCodeWrapper, 'CYTHON': CythonCodeWrapper, 'DUMMY': DummyWrapper} + wrappers = { 'F2PY': F2PyCodeWrapper, 'CYTHON': CythonCodeWrapper, + 'DUMMY': DummyWrapper} return wrappers[backend.upper()] -def autowrap(expr, language='F95', backend='f2py', tempdir=None, args=None, flags=[], + +@doctest_depends_on(exe=('f2py', 'gfortran'), modules=('numpy',)) +def autowrap( + expr, language='F95', backend='f2py', tempdir=None, args=None, flags=[], verbose=False, helpers=[]): """Generates python callable binaries based on the math expression. @@ -359,8 +374,8 @@ >>> from sympy.abc import x, y, z >>> from sympy.utilities.autowrap import autowrap >>> expr = ((x - y + z)**(13)).expand() - >>> binary_func = autowrap(expr) # doctest: +SKIP - >>> binary_func(1, 4, 2) # doctest: +SKIP + >>> binary_func = autowrap(expr) + >>> binary_func(1, 4, 2) -1.0 """ @@ -369,7 +384,7 @@ CodeWrapperClass = _get_code_wrapper_class(backend) code_wrapper = CodeWrapperClass(code_generator, tempdir, flags, verbose) try: - routine = Routine('autofunc', expr, args) + routine = Routine('autofunc', expr, args) except CodeGenArgumentListError as e: # if all missing arguments are for pure output, we simply attach them # at the end and try again, because the wrappers will silently convert @@ -379,7 +394,7 @@ if not isinstance(missing, OutputArgument): raise new_args.append(missing.name) - routine = Routine('autofunc', expr, args + new_args) + routine = Routine('autofunc', expr, args + new_args) helps = [] for name, expr, args in helpers: @@ -387,6 +402,8 @@ return code_wrapper.wrap_code(routine, helpers=helps) + +@doctest_depends_on (exe=('f2py', 'gfortran'), modules=('numpy',)) def binary_function(symfunc, expr, **kwargs): """Returns a sympy function with expr as binary implementation @@ -394,20 +411,21 @@ autowrap the SymPy expression and attaching it to a Function object with implemented_function(). - >>> from sympy.abc import x, y, z + >>> from sympy.abc import x, y >>> from sympy.utilities.autowrap import binary_function >>> expr = ((x - y)**(25)).expand() - >>> f = binary_function('f', expr) # doctest: +SKIP - >>> type(f) # doctest: +SKIP - - >>> 2*f(x, y) # doctest: +SKIP + >>> f = binary_function('f', expr) + >>> type(f) + + >>> 2*f(x, y) 2*f(x, y) - >>> f(x, y).evalf(2, subs={x: 1, y: 2}) # doctest: +SKIP + >>> f(x, y).evalf(2, subs={x: 1, y: 2}) -1.0 """ binary = autowrap(expr, **kwargs) return implemented_function(symfunc, binary) +@doctest_depends_on (exe=('f2py', 'gfortran'), modules=('numpy',)) def ufuncify(args, expr, **kwargs): """ Generates a binary ufunc-like lambda function for numpy arrays @@ -437,10 +455,16 @@ ======== >>> from sympy.utilities.autowrap import ufuncify - >>> from sympy.abc import x, y, z - >>> f = ufuncify([x, y], y + x**2) # doctest: +SKIP - >>> f([1, 2, 3], 2) # doctest: +SKIP - [2. 5. 10.] + >>> from sympy.abc import x, y + >>> import numpy as np + >>> f = ufuncify([x, y], y + x**2) + >>> f([1, 2, 3], 2) + [ 3. 6. 11.] + >>> a = f(np.arange(5), 3) + >>> isinstance(a, np.ndarray) + True + >>> print(a) + [ 3. 4. 7. 12. 19.] """ y = C.IndexedBase(C.Dummy('y')) diff -Nru python3-sympy-0.7.2/sympy/utilities/benchmarking.py python3-sympy-0.7.3/sympy/utilities/benchmarking.py --- python3-sympy-0.7.2/sympy/utilities/benchmarking.py 2012-10-17 03:02:22.000000000 +0000 +++ python3-sympy-0.7.3/sympy/utilities/benchmarking.py 2013-07-13 17:53:32.000000000 +0000 @@ -15,7 +15,7 @@ units = ["s", "ms", "us", "ns"] scaling = [1, 1e3, 1e6, 1e9] -unitn = dict((s,i) for i,s in enumerate(units)) +unitn = dict((s, i) for i, s in enumerate(units)) precision = 3 @@ -24,7 +24,7 @@ class Directory(py.test.collect.Directory): def filefilter(self, path): - b = path.purebasename + b = path.purebasename ext = path.ext return b.startswith('bench_') and ext == '.py' @@ -43,26 +43,24 @@ # copy of timeit.Timer.__init__ # similarity index 95% self.timer = timer - stmt = timeit.reindent(stmt, 8) + stmt = timeit.reindent(stmt, 8) setup = timeit.reindent(setup, 4) - src = timeit.template % {'stmt': stmt, 'setup': setup} - self.src = src # Save for traceback display + src = timeit.template % {'stmt': stmt, 'setup': setup} + self.src = src # Save for traceback display code = compile(src, timeit.dummy_src_name, "exec") ns = {} #exec code in globals(), ns -- original timeit code - exec(code, globals, ns) # -- we use caller-provided globals instead + exec(code, globals, ns) # -- we use caller-provided globals instead self.inner = ns["inner"] - class Function(py.__.test.item.Function): def __init__(self, *args, **kw): super(Function, self).__init__(*args, **kw) - self.benchtime = None + self.benchtime = None self.benchtitle = None - def execute(self, target, *args): # get func source without first 'def func(...):' line src = getsource(target) @@ -74,7 +72,6 @@ else: self.benchtitle = src.splitlines()[0].strip() - # XXX we ignore args timer = Timer(src, globals=target.__globals__) @@ -82,12 +79,12 @@ # from IPython.Magic.magic_timeit repeat = 3 number = 1 - for i in range(1,10): + for i in range(1, 10): t = timer.timeit(number) if t >= 0.2: number *= (0.2 / t) - number = int(_ceil(number)) + number = int(_ceil(number)) break if t <= 0.02: @@ -98,10 +95,9 @@ # since we are very close to be > 0.2s we'd better adjust number # so that timing time is not too high number *= (0.2 / t) - number = int(_ceil(number)) + number = int(_ceil(number)) break - self.benchtime = min(timer.repeat(repeat, number)) / number # 'bench_' @@ -122,7 +118,6 @@ self.out.write('\n') self.print_bench_results() - def print_bench_results(self): self.out.write('==============================\n') self.out.write(' *** BENCHMARKING RESULTS *** \n') @@ -148,7 +143,8 @@ else: order = 3 - tstr = "%.*g %s" % (precision, best * scaling[order], units[order]) + tstr = "%.*g %s" % ( + precision, best * scaling[order], units[order]) results.append( [item.name, tstr, item.benchtitle] ) @@ -159,38 +155,37 @@ for s in results: tstr = s[1] - n,u = tstr.split() + n, u = tstr.split() # unit n un = unitn[u] try: - m,e = n.split('.') + m, e = n.split('.') except ValueError: - m,e = n,'' + m, e = n, '' wm[un] = max(len(m), wm[un]) we[un] = max(len(e), we[un]) for s in results: tstr = s[1] - n,u = tstr.split() + n, u = tstr.split() un = unitn[u] try: - m,e = n.split('.') + m, e = n.split('.') except ValueError: - m,e = n,'' + m, e = n, '' m = m.rjust(wm[un]) e = e.ljust(we[un]) if e.strip(): - n = '.'.join((m,e)) + n = '.'.join((m, e)) else: - n = ' '.join((m,e)) - + n = ' '.join((m, e)) # let's put the number into the right place txt = '' @@ -198,11 +193,10 @@ if i == un: txt += n else: - txt += ' '*(wm[i]+we[i]+1) + txt += ' '*(wm[i] + we[i] + 1) s[1] = '%s %s' % (txt, u) - # align all columns besides the last one for i in range(2): w = max(len(s[i]) for s in results) @@ -219,9 +213,9 @@ # hook our Directory/Module/Function as defaults from py.__.test import defaultconftest - defaultconftest.Directory = Directory - defaultconftest.Module = Module - defaultconftest.Function = Function + defaultconftest.Directory = Directory + defaultconftest.Module = Module + defaultconftest.Function = Function # hook BenchSession as py.test session config = py.test.config diff -Nru python3-sympy-0.7.2/sympy/utilities/codegen.py python3-sympy-0.7.3/sympy/utilities/codegen.py --- python3-sympy-0.7.2/sympy/utilities/codegen.py 2012-10-17 03:02:22.000000000 +0000 +++ python3-sympy-0.7.3/sympy/utilities/codegen.py 2013-07-13 17:53:32.000000000 +0000 @@ -88,7 +88,6 @@ from sympy.tensor import Idx, Indexed, IndexedBase - __all__ = [ # description of routines "Routine", "DataType", "default_datatypes", "get_default_datatype", @@ -163,18 +162,21 @@ out_arg = expr.lhs expr = expr.rhs if isinstance(out_arg, Indexed): - dims = tuple([ (S.Zero, dim-1) for dim in out_arg.shape]) + dims = tuple([ (S.Zero, dim - 1) for dim in out_arg.shape]) symbol = out_arg.base.label elif isinstance(out_arg, Symbol): dims = [] symbol = out_arg else: - raise CodeGenError("Only Indexed or Symbol can define output arguments") + raise CodeGenError( + "Only Indexed or Symbol can define output arguments") if expr.has(symbol): - output_args.append(InOutArgument(symbol, out_arg, expr, dimensions=dims)) + output_args.append( + InOutArgument(symbol, out_arg, expr, dimensions=dims)) else: - output_args.append(OutputArgument(symbol, out_arg, expr, dimensions=dims)) + output_args.append(OutputArgument( + symbol, out_arg, expr, dimensions=dims)) # avoid duplicate arguments symbols.remove(symbol) @@ -198,7 +200,7 @@ arg_list.append(InputArgument(symbol, **metadata)) - output_args.sort(key=lambda x:str(x.name)) + output_args.sort(key=lambda x: str(x.name)) arg_list.extend(output_args) if argument_sequence is not None: @@ -251,10 +253,12 @@ If return values are present, they are at the end ot the list. """ - args = [arg for arg in self.arguments if isinstance(arg, (OutputArgument, InOutArgument))] + args = [arg for arg in self.arguments if isinstance( + arg, (OutputArgument, InOutArgument))] args.extend(self.results) return args + class DataType(object): """Holds strings for a certain datatype in different programming languages.""" def __init__(self, cname, fname, pyname): @@ -276,6 +280,7 @@ else: return default_datatypes["float"] + class Variable(object): """Represents a typed variable.""" @@ -297,14 +302,15 @@ elif not isinstance(datatype, DataType): raise TypeError("The (optional) `datatype' argument must be an instance of the DataType class.") if dimensions and not isinstance(dimensions, (tuple, list)): - raise TypeError("The dimension argument must be a sequence of tuples") + raise TypeError( + "The dimension argument must be a sequence of tuples") self._name = name self._datatype = { - 'C': datatype.cname, - 'FORTRAN': datatype.fname, - 'PYTHON': datatype.pyname - } + 'C': datatype.cname, + 'FORTRAN': datatype.fname, + 'PYTHON': datatype.pyname + } self.dimensions = dimensions self.precision = precision @@ -329,6 +335,7 @@ raise CodeGenError("Has datatypes for languages: %s" % ", ".join(self._datatype)) + class Argument(Variable): """An abstract Argument data structure: a name and a data type. @@ -341,9 +348,11 @@ Variable.__init__(self, name, datatype, dimensions, precision) + class InputArgument(Argument): pass + class ResultBase(object): """Base class for all ``outgoing'' information from a routine @@ -355,6 +364,7 @@ self.expr = expr self.result_var = result_var + class OutputArgument(Argument, ResultBase): """OutputArgument are always initialized in the routine """ @@ -364,6 +374,7 @@ Argument.__init__(self, name, datatype, dimensions, precision) ResultBase.__init__(self, expr, result_var) + class InOutArgument(Argument, ResultBase): """InOutArgument are never initialized in the routine """ @@ -374,6 +385,7 @@ Argument.__init__(self, name, datatype, dimensions, precision) ResultBase.__init__(self, expr, result_var) + class Result(ResultBase): """An expression for a scalar return value. @@ -391,7 +403,7 @@ if not isinstance(expr, Expr): raise TypeError("The first argument must be a sympy expression.") - temp_var = Variable(Symbol('result_%s'%hash(expr)), + temp_var = Variable(Symbol('result_%s' % hash(expr)), datatype=datatype, dimensions=None, precision=precision) ResultBase.__init__(self, expr, temp_var.name) self._temp_variable = temp_var @@ -481,13 +493,16 @@ code_lines = self._preprocessor_statements(prefix) for routine in routines: - if empty: code_lines.append("\n") + if empty: + code_lines.append("\n") code_lines.extend(self._get_routine_opening(routine)) code_lines.extend(self._declare_arguments(routine)) code_lines.extend(self._declare_locals(routine)) - if empty: code_lines.append("\n") + if empty: + code_lines.append("\n") code_lines.extend(self._call_printer(routine)) - if empty: code_lines.append("\n") + if empty: + code_lines.append("\n") code_lines.extend(self._get_routine_ending(routine)) code_lines = self._indent_code(''.join(code_lines)) @@ -498,9 +513,11 @@ if code_lines: f.write(code_lines) + class CodeGenError(Exception): pass + class CodeGenArgumentListError(Exception): @property def missing_args(self): @@ -530,7 +547,8 @@ """Writes a common header for the generated files.""" code_lines = [] code_lines.append("/" + "*"*78 + '\n') - tmp = header_comment % {"version": sympy_version, "project": self.project} + tmp = header_comment % {"version": sympy_version, + "project": self.project} for line in tmp.splitlines(): code_lines.append(" *%s*\n" % line.center(76)) code_lines.append(" " + "*"*78 + "/\n") @@ -590,11 +608,14 @@ assign_to = result.result_var try: - constants, not_c, c_expr = ccode(result.expr, assign_to=assign_to, human=False) + constants, not_c, c_expr = ccode( + result.expr, assign_to=assign_to, human=False) except AssignmentError: assign_to = result.result_var - code_lines.append("%s %s;\n" % (result.get_datatype('c'), str(assign_to))) - constants, not_c, c_expr = ccode(result.expr, assign_to=assign_to, human=False) + code_lines.append( + "%s %s;\n" % (result.get_datatype('c'), str(assign_to))) + constants, not_c, c_expr = ccode( + result.expr, assign_to=assign_to, human=False) for name, value in sorted(constants, key=str): code_lines.append("double const %s = %s;\n" % (name, value)) @@ -641,26 +662,32 @@ """ if header: print(''.join(self._get_header()), file=f) - guard_name = "%s__%s__H" % (self.project.replace(" ", "_").upper(), prefix.replace("/", "_").upper()) + guard_name = "%s__%s__H" % (self.project.replace( + " ", "_").upper(), prefix.replace("/", "_").upper()) # include guards - if empty: print(file=f) + if empty: + print(file=f) print("#ifndef %s" % guard_name, file=f) print("#define %s" % guard_name, file=f) - if empty: print(file=f) + if empty: + print(file=f) # declaration of the function prototypes for routine in routines: prototype = self.get_prototype(routine) print("%s;" % prototype, file=f) # end if include guards - if empty: print(file=f) + if empty: + print(file=f) print("#endif", file=f) - if empty: print(file=f) + if empty: + print(file=f) dump_h.extension = interface_extension # This list of dump functions is used by CodeGen.write to know which dump # functions it has to call. dump_fns = [dump_c, dump_h] + class FCodeGen(CodeGen): """ Generator for Fortran 95 code @@ -683,7 +710,8 @@ """Writes a common header for the generated files.""" code_lines = [] code_lines.append("!" + "*"*78 + '\n') - tmp = header_comment % {"version": sympy_version, "project": self.project} + tmp = header_comment % {"version": sympy_version, + "project": self.project} for line in tmp.splitlines(): code_lines.append("!*%s*\n" % line.center(76)) code_lines.append("!" + "*"*78 + '\n') @@ -698,7 +726,8 @@ """ code_list = [] if len(routine.results) > 1: - raise CodeGenError("Fortran only supports a single or no return value.") + raise CodeGenError( + "Fortran only supports a single or no return value.") elif len(routine.results) == 1: result = routine.results[0] code_list.append(result.get_datatype('fortran')) @@ -730,14 +759,14 @@ elif isinstance(arg, OutputArgument): typeinfo = "%s, intent(out)" % arg.get_datatype('fortran') else: - raise CodeGenError("Unkown Argument type: %s"%type(arg)) + raise CodeGenError("Unkown Argument type: %s" % type(arg)) fprint = self._get_symbol if arg.dimensions: # fortran arrays start at 1 - dimstr = ", ".join(["%s:%s"%( - fprint(dim[0]+1), fprint(dim[1]+1)) + dimstr = ", ".join(["%s:%s" % ( + fprint(dim[0] + 1), fprint(dim[1] + 1)) for dim in arg.dimensions]) typeinfo += ", dimension(%s)" % dimstr array_list.append("%s :: %s\n" % (typeinfo, fprint(arg.name))) @@ -799,7 +828,8 @@ for obj, v in sorted(constants, key=str): t = get_default_datatype(obj) - declarations.append("%s, parameter :: %s = %s\n" % (t.fname, obj, v)) + declarations.append( + "%s, parameter :: %s = %s\n" % (t.fname, obj, v)) for obj in sorted(not_fortran, key=str): t = get_default_datatype(obj) if isinstance(obj, Function): @@ -821,13 +851,12 @@ lowercase = set([str(x).lower() for x in r.variables]) orig_case = set([str(x) for x in r.variables]) if len(lowercase) < len(orig_case): - raise CodeGenError("Fortran ignores case. Got symbols: %s"% + raise CodeGenError("Fortran ignores case. Got symbols: %s" % (", ".join([str(var) for var in r.variables]))) self.dump_code(routines, f, prefix, header, empty) dump_f95.extension = code_extension dump_f95.__doc__ = CodeGen.dump_code.__doc__ - def dump_h(self, routines, f, prefix, header=True, empty=True): """Writes the interface to a header file. @@ -853,12 +882,14 @@ """ if header: print(''.join(self._get_header()), file=f) - if empty: print(file=f) + if empty: + print(file=f) # declaration of the function prototypes for routine in routines: - prototype = self.get_interface(routine) + prototype = self.get_interface(routine) f.write(prototype) - if empty: print(file=f) + if empty: + print(file=f) dump_h.extension = interface_extension # This list of dump functions is used by CodeGen.write to know which dump @@ -878,7 +909,8 @@ # -def codegen(name_expr, language, prefix, project="project", to_files=False, header=True, empty=True, +def codegen( + name_expr, language, prefix, project="project", to_files=False, header=True, empty=True, argument_sequence=None): """Write source code for the given expressions in the given language. @@ -918,7 +950,6 @@ If omitted, arguments will be ordered alphabetically, but with all input aguments first, and then output or in-out arguments. - >>> from sympy import symbols >>> from sympy.utilities.codegen import codegen >>> from sympy.abc import x, y, z >>> [(c_name, c_code), (h_name, c_header)] = codegen( diff -Nru python3-sympy-0.7.2/sympy/utilities/compilef.py python3-sympy-0.7.3/sympy/utilities/compilef.py --- python3-sympy-0.7.2/sympy/utilities/compilef.py 2012-10-17 03:02:22.000000000 +0000 +++ python3-sympy-0.7.3/sympy/utilities/compilef.py 2013-07-13 17:53:32.000000000 +0000 @@ -85,10 +85,8 @@ from sympy.utilities.lambdify import lambdastr as getlambdastr from sympy.external import import_module -numpy = import_module('numpy') - libtccpath = './libtcc.so' -dps = 17 # decimal places of float precision +dps = 17 # decimal places of float precision # load libtcc TODO: better Windows support try: libtcc = ctypes.cdll.LoadLibrary(libtccpath) @@ -97,6 +95,7 @@ if not libtcc: raise ImportError('Could not load libtcc') + def __getLeftRight(expr, index, oplength=1, stopchar='+-'): """ Gets the expressions to the left and right of an operator. @@ -112,14 +111,14 @@ left = '' openbraces = 0 for char in reversed(expr[:index]): - if char == ' ': # skip whitespaces but keep them + if char == ' ': # skip whitespaces but keep them left = char + left continue elif char == ')': openbraces += 1 left = char + left elif char == '(': - if not openbraces: # happens when operator is in braces + if not openbraces: # happens when operator is in braces break openbraces -= 1 left = char + left @@ -134,15 +133,15 @@ # get right expression right = '' openbraces = 0 - for char in expr[index+oplength:]: - if char == ' ': # skip whitespaces but keep them + for char in expr[index + oplength:]: + if char == ' ': # skip whitespaces but keep them right += char continue elif char == '(': openbraces += 1 right += char elif char == ')': - if not openbraces: # happens when operator is in braces + if not openbraces: # happens when operator is in braces break openbraces -= 1 right += char @@ -156,6 +155,7 @@ right += char return (left, right) + def cexpr(pyexpr): """ Python math expression string -> C expression string @@ -174,6 +174,7 @@ # TODO: avoid integer division return pyexpr + def _gentmpvars(): """ Generate symbols tmp1, tmp2, ... infinitely. @@ -183,6 +184,7 @@ i += 1 yield Symbol('tmp' + str(i)) + def genfcode(lambdastr, use_cse=False): """ Python lambda string -> C function code @@ -211,7 +213,8 @@ cfstr = '' for symbol, expr in subs: vardec += ' double %s;\n' % symbol.name - cfstr += ' %s = %s;\n' % (symbol.name, cexpr(str(expr.evalf(dps)))) + cfstr += ' %s = %s;\n' % ( + symbol.name, cexpr(str(expr.evalf(dps)))) cfstr = vardec + cfstr finalexpr = cexpr(str(finalexpr[0].evalf(dps))) # generate C code @@ -224,6 +227,7 @@ """ % (cvarstr, cfstr, finalexpr) return code + def __run(cmd): """ Checks the exit code of a ran command. @@ -231,6 +235,7 @@ if not cmd == 0: raise RuntimeError('could not run libtcc command') + def _compile(code, argcount=None, fname='f', fprototype=None): """ C code with function -> compiled function @@ -244,15 +249,15 @@ fprototype = ctypes.CFUNCTYPE(*fprototype) else: assert argcount, 'need argcount if no prototype is specified' - fprototype = ctypes.CFUNCTYPE(*[ctypes.c_double]*(argcount+1)) + fprototype = ctypes.CFUNCTYPE(*[ctypes.c_double]*(argcount + 1)) # see libtcc.h for API documentation tccstate = libtcc.tcc_new() - __run(libtcc.tcc_set_output_type(tccstate, 0)) # output to memory + __run(libtcc.tcc_set_output_type(tccstate, 0)) # output to memory ##print libtcc.tcc_add_library_path(tccstate, mathh) # could be dropped - __run(libtcc.tcc_add_library(tccstate, 'm')) # use math.h FIXME: Windows + __run(libtcc.tcc_add_library(tccstate, 'm')) # use math.h FIXME: Windows # compile string __run(libtcc.tcc_compile_string(tccstate, code)) - __run(libtcc.tcc_relocate(tccstate)) # fails if link error + __run(libtcc.tcc_relocate(tccstate)) # fails if link error # create C variable to get result symbol = ctypes.c_long() __run(libtcc.tcc_get_symbol(tccstate, ctypes.byref(symbol), fname)) @@ -260,13 +265,15 @@ return fprototype(symbol.value) # expr needs to work with lambdastr + + def clambdify(args, expr, **kwargs): """ SymPy expression -> compiled function Supports all standard C math functions, pi and e. - >>> from sympy import symbols, sqrt + >>> from sympy import sqrt >>> from sympy.abc import x, y >>> cf = clambdify((x,y), sqrt(x*y)) >>> cf(0.5, 4) @@ -287,6 +294,7 @@ # compile code return _compile(code, len(args)) + def frange(*args, **kwargs): """ frange(lambdastr, [start,] stop[, step]) -> ctypes double array @@ -325,20 +333,20 @@ if len(args) == 4: step = args[3] assert start + step != start, \ - 'step is too small and would cause an infinite loop' + 'step is too small and would cause an infinite loop' # determine length of resulting array # TODO: do this better length = stop - start if length % step == 0: - length = length/step - 1 # exclude last one + length = length/step - 1 # exclude last one else: length = length//step if step > 0: if start < stop: - length += 1 # include first one + length += 1 # include first one else: if start > stop: - length += 1 # include first one + length += 1 # include first one if length < 0: length = 0 assert length == int(length) @@ -373,6 +381,7 @@ # return ctypes array with results return a + def evalonarray(lambdastr, array, length=None, **kwargs): """ Evaluates a function on an array using machine code. @@ -383,15 +392,15 @@ array will be overwritten! Make a copy before to avoid this. """ # interpret arguments - if hasattr(array, 'ctypes'): # numpy array + if hasattr(array, 'ctypes'): # numpy array pointer = array.ctypes.get_as_parameter() length = len(array) - elif isinstance(array, ctypes.Array): # ctypes array + elif isinstance(array, ctypes.Array): # ctypes array pointer = ctypes.byref(array) length = len(array) - elif isinstance(array, ctypes.c_void_p): # ctypes pointer FIXME + elif isinstance(array, ctypes.c_void_p): # ctypes pointer FIXME pointer = array - assert isinstance(length, int) and not length < 0 + assert isinstance(length, int) and not length < 0 else: raise ValueError('array type not recognized') # generate code @@ -414,7 +423,7 @@ """ % genfcode(lambdastr, **kwargs) # compile an run on array - run = _compile(code, fname='evalonarray', + run = _compile(code, fname='evalonarray', fprototype=[None, ctypes.c_void_p, ctypes.c_int]) run(pointer, length) @@ -425,10 +434,12 @@ from sympy import sqrt, pi, lambdify from math import exp as _exp, cos as _cos, sin as _sin + def test_cexpr(): expr = '1/(g(x)*3.5)**(x - a**x)/(x**2 + a)' assert cexpr(expr).replace(' ', '') == \ - '1/pow((g(x)*3.5),(x-pow(a,x)))/(pow(x,2)+a)' + '1/pow((g(x)*3.5),(x-pow(a,x)))/(pow(x,2)+a)' + def test_clambdify(): x = Symbol('x') @@ -442,9 +453,10 @@ f2 = (x - y) / z * pi pf2 = lambdify((x, y, z), f2, 'math') cf2 = clambdify((x, y, z), f2) - assert round(pf2(1, 2, 3), 14) == round(cf2(1, 2, 3), 14) + assert round(pf2(1, 2, 3), 14) == round(cf2(1, 2, 3), 14) # FIXME: slight difference in precision + def test_frange(): fstr = 'lambda x: _exp(x)*_cos(x)**x' f = eval(fstr) @@ -485,6 +497,7 @@ except TypeError: pass + def test_evalonarray_ctypes(): a = frange('lambda x: x', 10) evalonarray('lambda x: _sin(x)', a) @@ -495,12 +508,15 @@ ## for i, j in enumerater(a): ## print j + def test_evalonarray_numpy(): + numpy = import_module('numpy') a = numpy.arange(10, dtype=float) - evalonarray('lambda x: x + 1', a) + evalonarray('lambda x: x + 1', a) for i, j in enumerate(a): assert float(i + 1) == j + def test_use_cse(): args = ('lambda x: sqrt(x + 1)**sqrt(x + 1)', 1, 10) a = frange(*args) @@ -511,6 +527,7 @@ for i in range(len(a)): assert a[i] == b[i] + def benchmark(): """ Run some benchmarks for clambdify and frange. @@ -527,7 +544,8 @@ global cf, pf, psyf start = time() cf = clambdify(var, f) - print('compile time (including sympy overhead): %f s' % (time() - start)) + print('compile time (including sympy overhead): %f s' % ( + time() - start)) pf = lambdify(var, f, 'math') psyf = None psyco = import_module('psyco') @@ -550,20 +568,20 @@ print('Psyco lambda: %.4f %.4f %.4f' % tuple(t3.repeat(3, 20))) print('big function:') - from sympy import diff, _exp, _sin, _cos, pi, lambdify + from sympy import _exp, _sin, _cos, pi, lambdify x = Symbol('x') ## f1 = diff(_exp(x)**2 - _sin(x)**pi, x) \ ## * x**12-2*x**3+2*_exp(x**2)-3*x**7+4*_exp(123+x-x**5+2*x**4) \ ## * ((x + pi)**5).expand() f1 = 2*_exp(x**2) + x**12*(-pi*_sin(x)**((-1) + pi)*_cos(x) + 2*_exp(2*x)) \ - + 4*(10*pi**3*x**2 + 10*pi**2*x**3 + 5*pi*x**4 + 5*x*pi**4 + pi**5 \ - + x**5)*_exp(123 + x + 2*x**4 - x**5) - 2*x**3 - 3*x**7 + + 4*(10*pi**3*x**2 + 10*pi**2*x**3 + 5*pi*x**4 + 5*x*pi**4 + pi**5 + + x**5)*_exp(123 + x + 2*x**4 - x**5) - 2*x**3 - 3*x**7 fbenchmark(f1) print() print('simple function:') y = Symbol('y') - f2 = sqrt(x*y)+x*5 - fbenchmark(f2, [x,y]) + f2 = sqrt(x*y) + x*5 + fbenchmark(f2, [x, y]) times = 100000 fstr = '_exp(_sin(_exp(-x**2)) + sqrt(pi)*_cos(x**5/(x**3-x**2+pi*x)))' print() @@ -586,6 +604,7 @@ if __name__ == '__main__': if __debug__: print('Running tests...', end=' ') + numpy = import_module('numpy') test_cexpr() test_clambdify() test_frange() diff -Nru python3-sympy-0.7.2/sympy/utilities/decorator.py python3-sympy-0.7.3/sympy/utilities/decorator.py --- python3-sympy-0.7.2/sympy/utilities/decorator.py 2012-10-17 03:02:22.000000000 +0000 +++ python3-sympy-0.7.3/sympy/utilities/decorator.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,10 +1,12 @@ +import inspect + from sympy.core.decorators import wraps from sympy.core.compatibility import iterable def threaded_factory(func, use_add): """A factory for ``threaded`` decorators. """ - from sympy.core import sympify, Add + from sympy.core import sympify from sympy.matrices import Matrix @wraps(func) @@ -12,7 +14,10 @@ if isinstance(expr, Matrix): return expr.applyfunc(lambda f: func(f, *args, **kwargs)) elif iterable(expr): - return expr.__class__([ func(f, *args, **kwargs) for f in expr ]) + try: + return expr.__class__([func(f, *args, **kwargs) for f in expr]) + except TypeError: + return expr else: expr = sympify(expr) @@ -26,46 +31,50 @@ return threaded_func + def threaded(func): """Apply ``func`` to sub--elements of an object, including :class:`Add`. - This decorator is intended to make it uniformly possible to apply a - function to all elements of composite objects, e.g. matrices, lists, - tuples and other iterable containers, or just expressions. - - This version of :func:`threaded` decorator allows threading over - elements of :class:`Add` class. If this behavior is not desirable - use :func:`xthreaded` decorator. + This decorator is intended to make it uniformly possible to apply a + function to all elements of composite objects, e.g. matrices, lists, tuples + and other iterable containers, or just expressions. + + This version of :func:`threaded` decorator allows threading over + elements of :class:`Add` class. If this behavior is not desirable + use :func:`xthreaded` decorator. - Functions using this decorator must have the following signature:: + Functions using this decorator must have the following signature:: - @threaded - def function(expr, *args, **kwargs): + @threaded + def function(expr, *args, **kwargs): """ return threaded_factory(func, True) + def xthreaded(func): """Apply ``func`` to sub--elements of an object, excluding :class:`Add`. - This decorator is intended to make it uniformly possible to apply a - function to all elements of composite objects, e.g. matrices, lists, - tuples and other iterable containers, or just expressions. - - This version of :func:`threaded` decorator disallows threading over - elements of :class:`Add` class. If this behavior is not desirable - use :func:`threaded` decorator. + This decorator is intended to make it uniformly possible to apply a + function to all elements of composite objects, e.g. matrices, lists, tuples + and other iterable containers, or just expressions. + + This version of :func:`threaded` decorator disallows threading over + elements of :class:`Add` class. If this behavior is not desirable + use :func:`threaded` decorator. - Functions using this decorator must have the following signature:: + Functions using this decorator must have the following signature:: - @xthreaded - def function(expr, *args, **kwargs): + @xthreaded + def function(expr, *args, **kwargs): """ return threaded_factory(func, False) + def conserve_mpmath_dps(func): - """After the function finishes, resets the value of mpmath.mp.dps to the value it had before the function was run.""" + """After the function finishes, resets the value of mpmath.mp.dps to + the value it had before the function was run.""" import functools from sympy import mpmath @@ -78,3 +87,54 @@ func_wrapper = functools.update_wrapper(func_wrapper, func) return func_wrapper + + +class no_attrs_in_subclass(object): + """Don't 'inherit' certain attributes from a base class + + >>> from sympy.utilities.decorator import no_attrs_in_subclass + + >>> class A(object): + ... x = 'test' + + >>> A.x = no_attrs_in_subclass(A, A.x) + + >>> class B(A): + ... pass + + >>> hasattr(A, 'x') + True + >>> hasattr(B, 'x') + False + + """ + def __init__(self, cls, f): + self.cls = cls + self.f = f + + def __get__(self, instance, owner=None): + if owner == self.cls: + if hasattr(self.f, '__get__'): + return self.f.__get__(instance, owner) + return self.f + raise AttributeError + + +def doctest_depends_on(exe=None, modules=None, disable_viewers=None): + """Adds metadata about the depenencies which need to be met for doctesting + the docstrings of the decorated objects.""" + pyglet = False + if modules is not None and 'pyglet' in modules: + pyglet = True + + def depends_on_deco(fn): + fn._doctest_depends_on = dict(exe=exe, modules=modules, + disable_viewers=disable_viewers, + pyglet=pyglet) + + # once we drop py2.5 support and use class decorators this evaluates + # to True + if inspect.isclass(fn): + fn._doctest_depdends_on = no_attrs_in_subclass(fn, fn._doctest_depends_on) + return fn + return depends_on_deco diff -Nru python3-sympy-0.7.2/sympy/utilities/exceptions.py python3-sympy-0.7.3/sympy/utilities/exceptions.py --- python3-sympy-0.7.2/sympy/utilities/exceptions.py 2012-10-17 03:02:22.000000000 +0000 +++ python3-sympy-0.7.3/sympy/utilities/exceptions.py 2013-07-13 17:53:32.000000000 +0000 @@ -5,6 +5,7 @@ from sympy.utilities.misc import filldedent from warnings import warn as warning + class SymPyDeprecationWarning(DeprecationWarning): r"""A warning for deprecated features of SymPy. @@ -13,8 +14,11 @@ >>> import warnings >>> from sympy.utilities.exceptions import SymPyDeprecationWarning - >>> warnings.simplefilter("always", SymPyDeprecationWarning) - >>> warnings.warn("Don't do this, it's deprecated", SymPyDeprecationWarning) #doctest:+SKIP + >>> warnings.simplefilter( + ... "always", SymPyDeprecationWarning) + >>> warnings.warn( + ... "Don't do this, it's deprecated", + ... SymPyDeprecationWarning) #doctest:+SKIP __main__:1: SymPyDeprecationWarning: "Don't do this, it's deprecated" The recommended way to use this class is, however, is by calling @@ -112,7 +116,7 @@ if feature: if deprecated_since_version: - self.fullMessage = "%s has been deprecated since SymPy %s. " %\ + self.fullMessage = "%s has been deprecated since SymPy %s. " % \ (feature, deprecated_since_version) else: self.fullMessage = "%s has been deprecated. " % feature @@ -127,7 +131,6 @@ "http://code.google.com/p/sympy/issues/detail?id=%d for more " "info. ") % issue - if value: if not isinstance(value, str): value = "(%s)" % repr(value) @@ -143,4 +146,4 @@ def warn(self): see_above = self # the next line is what the user will see after the error is printed - warning (see_above, SymPyDeprecationWarning) + warning(see_above, SymPyDeprecationWarning) diff -Nru python3-sympy-0.7.2/sympy/utilities/iterables.py python3-sympy-0.7.3/sympy/utilities/iterables.py --- python3-sympy-0.7.2/sympy/utilities/iterables.py 2012-10-17 03:02:22.000000000 +0000 +++ python3-sympy-0.7.3/sympy/utilities/iterables.py 2013-07-13 17:53:32.000000000 +0000 @@ -2,12 +2,16 @@ import random from operator import gt +from sympy.core.decorators import deprecated from sympy.core import Basic, C -from sympy.core.compatibility import is_sequence, iterable # logical location -from sympy.core.compatibility import as_int, quick_sort,\ - product as cartes, combinations, combinations_with_replacement -from sympy.utilities.misc import default_sort_key -from sympy.utilities.exceptions import SymPyDeprecationWarning + +# this is the logical location of these functions +from sympy.core.compatibility import ( + as_int, combinations, combinations_with_replacement, + default_sort_key, is_sequence, iterable, permutations, + product as cartes, ordered, next, bin +) + def flatten(iterable, levels=None, cls=None): """ @@ -51,7 +55,8 @@ elif levels > 0: levels -= 1 else: - raise ValueError("expected non-negative number of levels, got %s" % levels) + raise ValueError( + "expected non-negative number of levels, got %s" % levels) if cls is None: reducible = lambda x: is_sequence(x, set) @@ -70,6 +75,7 @@ return result + def unflatten(iter, n=2): """Group ``iter`` into tuples of length ``n``. Raise an error if the length of ``iter`` is not a multiple of ``n``. @@ -78,6 +84,7 @@ raise ValueError('iter length is not a multiple of %i' % n) return list(zip(*(iter[i::n] for i in range(n)))) + def reshape(seq, how): """Reshape the sequence according to the template in ``how``. @@ -110,6 +117,10 @@ >>> reshape(tuple(seq), ([1], 1, (2,))) (([1], 2, (3, 4)), ([5], 6, (7, 8))) + + >>> reshape(list(range(12)), [2, [3], set([2]), (1, (3,), 1)]) + [[0, 1, [2, 3, 4], set([5, 6]), (7, (8, 9, 10), 11)]] + """ m = sum(flatten(how)) n, rem = divmod(len(seq), m) @@ -127,31 +138,39 @@ i += hi else: n = sum(flatten(hi)) - fg = type(hi) - rv[k].append(fg(reshape(seq[i: i + n], hi))[0]) + hi_type = type(hi) + rv[k].append(hi_type(reshape(seq[i: i + n], hi)[0])) i += n rv[k] = container(rv[k]) return type(seq)(rv) -def group(container, multiple=True): + +def group(seq, multiple=True): """ - Splits a container into a list of lists of equal, adjacent elements. + Splits a sequence into a list of lists of equal, adjacent elements. + + Examples + ======== >>> from sympy.utilities.iterables import group >>> group([1, 1, 1, 2, 2, 3]) [[1, 1, 1], [2, 2], [3]] - >>> group([1, 1, 1, 2, 2, 3], multiple=False) [(1, 3), (2, 2), (3, 1)] + >>> group([1, 1, 3, 2, 2, 1], multiple=False) + [(1, 2), (3, 1), (2, 2), (1, 1)] + See Also + ======== + multiset """ - if not container: + if not seq: return [] - current, groups = [container[0]], [] + current, groups = [seq[0]], [] - for elem in container[1:]: + for elem in seq[1:]: if elem == current[-1]: current.append(elem) else: @@ -168,7 +187,29 @@ return groups -def postorder_traversal(node, key=None): + +def multiset(seq): + """Return the hashable sequence in multiset form with values being the + multiplicity of the item in the sequence. + + Examples + ======== + + >>> from sympy.utilities.iterables import multiset + >>> multiset('mississippi') + {'i': 4, 'm': 1, 'p': 2, 's': 4} + + See Also + ======== + group + """ + rv = defaultdict(int) + for s in seq: + rv[s] += 1 + return dict(rv) + + +def postorder_traversal(node, keys=None): """ Do a postorder traversal of a tree. @@ -178,47 +219,55 @@ Parameters ========== + node : sympy expression The expression to traverse. - key : (default None) sort key - The key used to sort args of Basic objects. When None, args of Basic - objects are processed in arbitrary order. + keys : (default None) sort key(s) + The key(s) used to sort args of Basic objects. When None, args of Basic + objects are processed in arbitrary order. If key is defined, it will + be passed along to ordered() as the only key(s) to use to sort the + arguments; if ``key`` is simply True then the default keys of + ``ordered`` will be used (node count and default_sort_key). - Returns - ======= + Yields + ====== subtree : sympy expression All of the subtrees in the tree. Examples ======== - >>> from sympy import symbols, default_sort_key + >>> from sympy.utilities.iterables import postorder_traversal >>> from sympy.abc import w, x, y, z The nodes are returned in the order that they are encountered unless key - is given. + is given; simply passing key=True will guarantee that the traversal is + unique. >>> list(postorder_traversal(w + (x + y)*z)) # doctest: +SKIP [z, y, x, x + y, z*(x + y), w, w + z*(x + y)] - >>> list(postorder_traversal(w + (x + y)*z, key=default_sort_key)) + >>> list(postorder_traversal(w + (x + y)*z, keys=True)) [w, z, x, y, x + y, z*(x + y), w + z*(x + y)] """ if isinstance(node, Basic): args = node.args - if key: - args = list(args) - args.sort(key=key) + if keys: + if keys != True: + args = ordered(args, keys, default=False) + else: + args = ordered(args) for arg in args: - for subtree in postorder_traversal(arg, key): + for subtree in postorder_traversal(arg, keys): yield subtree elif iterable(node): for item in node: - for subtree in postorder_traversal(item, key): + for subtree in postorder_traversal(item, keys): yield subtree yield node + def interactive_traversal(expr): """Traverse a tree asking a user which branch to choose. """ from sympy.printing import pprint @@ -268,7 +317,7 @@ if n_args == 1: choices = '0' else: - choices = '0-%d' % (n_args-1) + choices = '0-%d' % (n_args - 1) try: choice = input("Your choice [%s,f,l,r,d,?]: " % choices) @@ -277,7 +326,8 @@ print() else: if choice == '?': - cprint(RED, "%s - select subexpression with the given index" % choices) + cprint(RED, "%s - select subexpression with the given index" % + choices) cprint(RED, "f - select the first subexpression") cprint(RED, "l - select the last subexpression") cprint(RED, "r - select a random subexpression") @@ -287,28 +337,90 @@ elif choice in ['d', '']: result = expr elif choice == 'f': - result = _interactive_traversal(args[0], stage+1) + result = _interactive_traversal(args[0], stage + 1) elif choice == 'l': - result = _interactive_traversal(args[-1], stage+1) + result = _interactive_traversal(args[-1], stage + 1) elif choice == 'r': - result = _interactive_traversal(random.choice(args), stage+1) + result = _interactive_traversal(random.choice(args), stage + 1) else: try: choice = int(choice) except ValueError: - cprint(BRED, "Choice must be a number in %s range\n" % choices) + cprint(BRED, + "Choice must be a number in %s range\n" % choices) result = _interactive_traversal(expr, stage) else: if choice < 0 or choice >= n_args: cprint(BRED, "Choice must be in %s range\n" % choices) result = _interactive_traversal(expr, stage) else: - result = _interactive_traversal(args[choice], stage+1) + result = _interactive_traversal(args[choice], stage + 1) return result return _interactive_traversal(expr, 0) + +def ibin(n, bits=0, str=False): + """Return a list of length ``bits`` corresponding to the binary value + of ``n`` with small bits to the right (last). If bits is omitted, the + length will be the number required to represent ``n``. If the bits are + desired in reversed order, use the [::-1] slice of the returned list. + + If a sequence of all bits-length lists starting from [0, 0,..., 0] + through [1, 1, ..., 1] are desired, pass a non-integer for bits, e.g. + 'all'. + + If the bit *string* is desired pass ``str=True``. + + Examples + ======== + + >>> from sympy.utilities.iterables import ibin + >>> ibin(2) + [1, 0] + >>> ibin(2, 4) + [0, 0, 1, 0] + >>> ibin(2, 4)[::-1] + [0, 1, 0, 0] + + If all lists corresponding to 0 to 2**n - 1, pass a non-integer + for bits: + + >>> bits = 2 + >>> for i in ibin(2, 'all'): + ... print(i) + (0, 0) + (0, 1) + (1, 0) + (1, 1) + + If a bit string is desired of a given length, use str=True: + + >>> n = 123 + >>> bits = 10 + >>> ibin(n, bits, str=True) + '0001111011' + >>> ibin(n, bits, str=True)[::-1] # small bits left + '1101111000' + >>> list(ibin(3, 'all', str=True)) + ['000', '001', '010', '011', '100', '101', '110', '111'] + + """ + if not str: + try: + bits = as_int(bits) + return [1 if i == "1" else 0 for i in bin(n)[2:].rjust(bits, "0")] + except ValueError: + return variations(list(range(2)), n, repetition=True) + else: + try: + bits = as_int(bits) + return bin(n)[2:].rjust(bits, "0") + except ValueError: + return (bin(i)[2:].rjust(n, "0") for i in range(2**n)) + + def variations(seq, n, repetition=False): """Returns a generator of the n-sized variations of ``seq`` (size N). ``repetition`` controls whether items in ``seq`` can appear more than once; @@ -341,8 +453,9 @@ ======== sympy.core.compatibility.permutations + sympy.core.compatibility.product """ - from sympy.core.compatibility import permutations + from sympy.core.compatibility import product if not repetition: seq = tuple(seq) @@ -354,9 +467,9 @@ if n == 0: yield () else: - for i in range(len(seq)): - for cc in variations(seq, n - 1, True): - yield (seq[i],) + cc + for i in product(seq, repeat=n): + yield i + def subsets(seq, k=None, repetition=False): """Generates all k-subsets (combinations) from an n-element set, seq. @@ -368,6 +481,7 @@ Examples ======== + >>> from sympy.utilities.iterables import subsets subsets(seq, k) will return the n!/k!/(n - k)! k-subsets (combinations) @@ -409,36 +523,31 @@ for i in combinations_with_replacement(seq, k): yield i + def numbered_symbols(prefix='x', cls=None, start=0, *args, **assumptions): """ Generate an infinite stream of Symbols consisting of a prefix and increasing subscripts. Parameters - ---------- + ========== + prefix : str, optional The prefix to use. By default, this function will generate symbols of the form "x0", "x1", etc. cls : class, optional - The class to use. By default, it uses Symbol, but you can also use Wild. + The class to use. By default, it uses Symbol, but you can also use Wild or Dummy. start : int, optional The start number. By default, it is 0. Returns - ------- + ======= + sym : Symbol The subscripted symbols. """ - if 'dummy' in assumptions: - SymPyDeprecationWarning( - feature="'dummy=True' to create numbered Dummy symbols", - useinstead="cls=Dummy", - issue=3378, deprecated_since_version="0.7.0", - ).warn() - if assumptions.pop('dummy'): - cls = C.Dummy if cls is None: # We can't just make the default cls=C.Symbol because it isn't @@ -450,6 +559,7 @@ yield cls(name, *args, **assumptions) start += 1 + def capture(func): """Return the printed output of func(). @@ -479,19 +589,14 @@ sys.stdout = stdout return file.getvalue() -def sift(expr, keyfunc): - """ - Sift the arguments of expr into a dictionary according to keyfunc. - INPUT: expr may be an expression or iterable; if it is an expr then - it is converted to a list of expr's args or [expr] if there are no args. +def sift(seq, keyfunc): + """ + Sift the sequence, ``seq`` into a dictionary according to keyfunc. OUTPUT: each element in expr is stored in a list keyed to the value of keyfunc for the element. - Note that for a SymPy expression, the order of the elements in the lists - is dependent on the order in .args, which can be arbitrary. - Examples ======== @@ -499,42 +604,42 @@ >>> from sympy.abc import x, y >>> from sympy import sqrt, exp - >>> sift(list(range(5)), lambda x: x%2) + >>> sift(list(range(5)), lambda x: x % 2) {0: [0, 2, 4], 1: [1, 3]} sift() returns a defaultdict() object, so any key that has no matches will give []. - >>> sift(x, lambda x: x.is_commutative) + >>> sift([x], lambda x: x.is_commutative) {True: [x]} >>> _[False] [] Sometimes you won't know how many keys you will get: - >>> sift(sqrt(x) + exp(x) + (y**x)**2, - ... lambda x: x.as_base_exp()[0]) + >>> sift([sqrt(x), exp(x), (y**x)**2], + ... lambda x: x.as_base_exp()[0]) {E: [exp(x)], x: [sqrt(x)], y: [y**(2*x)]} If you need to sort the sifted items it might be better to use - the lazyDSU_sort which can economically apply multiple sort keys + ``ordered`` which can economically apply multiple sort keys to a squence while sorting. See Also ======== - lazyDSU_sort + ordered """ - d = defaultdict(list) - if hasattr(expr, 'args'): - expr = expr.args or [expr] - for e in expr: - d[keyfunc(e)].append(e) - return d + m = defaultdict(list) + for i in seq: + m[keyfunc(i)].append(i) + return m + def take(iter, n): """Return ``n`` items from ``iter`` iterator. """ return [ value for _, value in zip(range(n), iter) ] + def dict_merge(*dicts): """Merge dictionaries into a single dictionary. """ merged = {} @@ -544,6 +649,7 @@ return merged + def common_prefix(*seqs): """Return the subsequence that is a common start of sequences in ``seqs``. @@ -569,6 +675,7 @@ i += 1 return seqs[0][:i] + def common_suffix(*seqs): """Return the subsequence that is a common ending of sequences in ``seqs``. @@ -598,6 +705,7 @@ else: return seqs[0][i + 1:] + def prefixes(seq): """ Generate all prefixes of a sequence. @@ -614,7 +722,8 @@ n = len(seq) for i in range(n): - yield seq[:i+1] + yield seq[:i + 1] + def postfixes(seq): """ @@ -632,13 +741,15 @@ n = len(seq) for i in range(n): - yield seq[n-i-1:] + yield seq[n - i - 1:] + def topological_sort(graph, key=None): r""" Topological sort of graph's vertices. - **Parameters** + Parameters + ========== ``graph`` : ``tuple[list, list[tuple[T, T]]`` A tuple consisting of a list of vertices and a list of edges of @@ -743,6 +854,7 @@ else: return L + def rotate_left(x, y): """ Left rotates a list x by the number of steps specified @@ -757,10 +869,11 @@ [1, 2, 0] """ if len(x) == 0: - return x + return [] y = y % len(x) return x[y:] + x[:y] + def rotate_right(x, y): """ Left rotates a list x by the number of steps specified @@ -775,140 +888,409 @@ [2, 0, 1] """ if len(x) == 0: - return x + return [] y = len(x) - y % len(x) return x[y:] + x[:y] -def multiset_partitions(multiset, m): + +def multiset_combinations(m, n, g=None): + """ + Return the unique combinations of size ``n`` from multiset ``m``. + + Examples + ======== + + >>> from sympy.utilities.iterables import multiset_combinations + >>> from sympy.core.compatibility import combinations + >>> [''.join(i) for i in multiset_combinations('baby', 3)] + ['abb', 'aby', 'bby'] + + >>> def count(f, s): return len(list(f(s, 3))) + + The number of combinations depends on the number of letters; the + number of unique combinations depends on how the letters are + repeated. + + >>> s1 = 'abracadabra' + >>> s2 = 'banana tree' + >>> count(combinations, s1), count(multiset_combinations, s1) + (165, 23) + >>> count(combinations, s2), count(multiset_combinations, s2) + (165, 54) + + """ + if g is None: + if type(m) is dict: + if n > sum(m.values()): + return + g = [[k, m[k]] for k in ordered(m)] + else: + m = list(m) + if n > len(m): + return + try: + m = multiset(m) + g = [(k, m[k]) for k in ordered(m)] + except TypeError: + m = list(ordered(m)) + g = [list(i) for i in group(m, multiple=False)] + del m + if sum(v for k, v in g) < n or not n: + yield [] + else: + for i, (k, v) in enumerate(g): + if v >= n: + yield [k]*n + v = n - 1 + for v in range(min(n, v), 0, -1): + for j in multiset_combinations(None, n - v, g[i + 1:]): + rv = [k]*v + j + if len(rv) == n: + yield rv + + +def multiset_permutations(m, size=None, g=None): """ - This is the algorithm for generating multiset partitions - as described by Knuth in TAOCP Vol 4. + Return the unique permutations of multiset ``m``. + + Examples + ======== - Given a multiset, this algorithm visits all of its - m-partitions, that is, all partitions having exactly size m - using auxiliary arrays as described in the book. + >>> from sympy.utilities.iterables import multiset_permutations + >>> from sympy import factorial + >>> [''.join(i) for i in multiset_permutations('aab')] + ['aab', 'aba', 'baa'] + >>> factorial(len('banana')) + 720 + >>> len(list(multiset_permutations('banana'))) + 60 + """ + if g is None: + if type(m) is dict: + g = [[k, m[k]] for k in ordered(m)] + else: + m = list(ordered(m)) + g = [list(i) for i in group(m, multiple=False)] + del m + do = [gi for gi in g if gi[1] > 0] + SUM = sum([gi[1] for gi in do]) + if not do or size is not None and (size > SUM or size < 1): + if size < 1: + yield [] + return + elif size == 1: + for k, v in do: + yield [k] + elif len(do) == 1: + k, v = do[0] + v = v if size is None else (size if size <= v else 0) + yield [k for i in range(v)] + elif all(v == 1 for k, v in do): + for p in permutations([k for k, v in do], size): + yield list(p) + else: + size = size if size is not None else SUM + for i, (k, v) in enumerate(do): + do[i][1] -= 1 + for j in multiset_permutations(None, size - 1, do): + if j: + yield [k] + j + do[i][1] += 1 + + +def _partition(seq, vector, m=None): + """ + Return the partion of seq as specified by the partition vector. + + Examples + ======== + + >>> from sympy.utilities.iterables import _partition + >>> _partition('abcde', [1, 0, 1, 2, 0]) + [['b', 'e'], ['a', 'c'], ['d']] + + Specifying the number of bins in the partition is optional: + + >>> _partition('abcde', [1, 0, 1, 2, 0], 3) + [['b', 'e'], ['a', 'c'], ['d']] + + The output of _set_partitions can be passed as follows: + + >>> output = (3, [1, 0, 1, 2, 0]) + >>> _partition('abcde', *output) + [['b', 'e'], ['a', 'c'], ['d']] + + See Also + ======== + combinatorics.partitions.Partition.from_rgs() + + """ + if m is None: + m = max(vector) + 1 + elif type(vector) is int: # entered as m, vector + vector, m = m, vector + p = [[] for i in range(m)] + for i, v in enumerate(vector): + p[v].append(seq[i]) + return p + + +def _set_partitions(n): + """Cycle through all partions of n elements, yielding the + current number of partitions, ``m``, and a mutable list, ``q`` + such that element[i] is in part q[i] of the partition. + + NOTE: ``q`` is modified in place and generally should not be changed + between function calls. + + Examples + ======== + + >>> from sympy.utilities.iterables import _set_partitions, _partition + >>> for m, q in _set_partitions(3): + ... print(m, q, _partition('abc', q, m)) + 1 [0, 0, 0] [['a', 'b', 'c']] + 2 [0, 0, 1] [['a', 'b'], ['c']] + 2 [0, 1, 0] [['a', 'c'], ['b']] + 2 [0, 1, 1] [['a'], ['b', 'c']] + 3 [0, 1, 2] [['a'], ['b'], ['c']] + + Notes + ===== + + This algorithm is similar to, and solves the same problem as, + Algorithm 7.2.1.5H, from volume 4A of Knuth's The Art of Computer + Programming. Knuth uses the term "restricted growth string" where + this code refers to a "partition vector". In each case, the meaning is + the same: the value in the ith element of the vector specifies to + which part the ith set element is to be assigned. + + At the lowest level, this code implements an n-digit big-endian + counter (stored in the array q) which is incremented (with carries) to + get the next partition in the sequence. A special twist is that a + digit is constrained to be at most one greater than the maximum of all + the digits to the left of it. The array p maintains this maximum, so + that the code can efficiently decide when a digit can be incremented + in place or whether it needs to be reset to 0 and trigger a carry to + the next digit. The enumeration starts with all the digits 0 (which + corresponds to all the set elements being assigned to the same 0th + part), and ends with 0123...n, which corresponds to each set element + being assigned to a different, singleton, part. + + This routine was rewritten to use 0-based lists while trying to + preserve the beauty and efficiency of the original algorithm. + + Reference + ========= + + Nijenhuis, Albert and Wilf, Herbert. (1978) Combinatorial Algorithms, + 2nd Ed, p 91, algorithm "nexequ". Available online from + http://www.math.upenn.edu/~wilf/website/CombAlgDownld.html (viewed + November 17, 2012). + + """ + p = [0]*n + q = [0]*n + nc = 1 + yield nc, q + while nc != n: + m = n + while 1: + m -= 1 + i = q[m] + if p[i] != 1: + break + q[m] = 0 + i += 1 + q[m] = i + m += 1 + nc += m - n + p[0] += n - m + if i == nc: + p[nc] = 0 + nc += 1 + p[i - 1] -= 1 + p[i] += 1 + yield nc, q + + +def multiset_partitions(multiset, m=None): + """ + Return unique partitions of the given multiset (in list form). + If ``m`` is None, all multisets will be returned, otherwise only + partitions with ``m`` parts will be returned. + + If ``multiset`` is an integer, a range [0, 1, ..., multiset - 1] + will be supplied. Examples ======== >>> from sympy.utilities.iterables import multiset_partitions - >>> list(multiset_partitions([1,2,3,4], 2)) - [[[1, 2, 3], [4]], [[1, 3], [2, 4]], [[1], [2, 3, 4]], [[1, 2], \ - [3, 4]], [[1, 2, 4], [3]], [[1, 4], [2, 3]], [[1, 3, 4], [2]]] - >>> list(multiset_partitions([1,2,3,4], 1)) + >>> list(multiset_partitions([1, 2, 3, 4], 2)) + [[[1, 2, 3], [4]], [[1, 2, 4], [3]], [[1, 2], [3, 4]], + [[1, 3, 4], [2]], [[1, 3], [2, 4]], [[1, 4], [2, 3]], + [[1], [2, 3, 4]]] + >>> list(multiset_partitions([1, 2, 3, 4], 1)) [[[1, 2, 3, 4]]] - >>> list(multiset_partitions([1,2,3,4], 4)) - [[[1], [2], [3], [4]]] + + Only unique partitions are returned and these will be returned in a + canonical order regardless of the order of the input: + + >>> a = [1, 2, 2, 1] + >>> ans = list(multiset_partitions(a, 2)) + >>> a.sort() + >>> list(multiset_partitions(a, 2)) == ans + True + >>> a = list(range(3, 1, -1)) + >>> (list(multiset_partitions(a)) == + ... list(multiset_partitions(sorted(a)))) + True + + If m is omitted then all partitions will be returned: + + >>> list(multiset_partitions([1, 1, 2])) + [[[1, 1, 2]], [[1, 1], [2]], [[1, 2], [1]], [[1], [1], [2]]] + >>> list(multiset_partitions([1]*3)) + [[[1, 1, 1]], [[1], [1, 1]], [[1], [1], [1]]] + + Counting + ======== + + The number of partitions of a set is given by the bell number: + + >>> from sympy import bell + >>> len(list(multiset_partitions(5))) == bell(5) == 52 + True + + The number of partitions of length k from a set of size n is given by the + Stirling Number of the 2nd kind: + + >>> def S2(n, k): + ... from sympy import Dummy, binomial, factorial, Sum + ... if k > n: + ... return 0 + ... j = Dummy() + ... arg = (-1)**(k-j)*j**n*binomial(k,j) + ... return 1/factorial(k)*Sum(arg,(j,0,k)).doit() + ... + >>> S2(5, 2) == len(list(multiset_partitions(5, 2))) == 15 + True + + These comments on counting apply to *sets*, not multisets. + + Notes + ===== + + When all the elements are the same in the multiset, the order + of the returned partitions is determined by the ``partitions`` + routine. If one is counting partitions then it is better to use + the ``nT`` function. See Also ======== + partitions sympy.combinatorics.partitions.Partition sympy.combinatorics.partitions.IntegerPartition + sympy.functions.combinatorial.numbers.nT """ - cache = {} - def visit(n, a): - ps = [[] for i in range(m)] - for j in range(n): - ps[a[j + 1]].append(multiset[j]) - canonical = tuple(tuple(j) for j in ps) - if not canonical in cache: - cache[canonical] = 1 - return ps - - def f(m_arr, n_arr, sigma, n, a): - if m_arr <= 2: - v = visit(n, a) - if v is not None: - yield v - else: - for v in f(m_arr - 1, n_arr - 1, (m_arr + sigma) % 2, n, a): - yield v - if n_arr == m_arr + 1: - a[m_arr] = m_arr - 1 - v = visit(n, a) - if v is not None: - yield v - while a[n_arr] > 0: - a[n_arr] = a[n_arr] - 1 - v = visit(n, a) - if v is not None: - yield v - elif n_arr > m_arr + 1: - if (m_arr + sigma) % 2 == 1: - a[n_arr - 1] = m_arr - 1 - else: - a[m_arr] = m_arr - 1 - func = [f, b][(a[n_arr] + sigma) % 2] - for v in func(m_arr, n_arr - 1, 0, n, a): - if v is not None: - yield v - while a[n_arr] > 0: - a[n_arr] = a[n_arr] - 1 - func = [f, b][(a[n_arr] + sigma) % 2] - for v in func(m_arr, n_arr - 1, 0, n, a): - if v is not None: - yield v - - def b(m_arr, n_arr, sigma, n, a): - if n_arr == m_arr + 1: - v = visit(n, a) - if v is not None: - yield v - while a[n_arr] < m_arr - 1: - a[n_arr] = a[n_arr] + 1 - v = visit(n, a) - if v is not None: - yield v - a[m_arr] = 0 - v = visit(n, a) - if v is not None: - yield v - elif n_arr > m_arr + 1: - func = [f, b][(a[n_arr] + sigma) % 2] - for v in func(m_arr, n_arr - 1, 0, n, a): - if v is not None: - yield v - while a[n_arr] < m_arr - 1: - a[n_arr] = a[n_arr] + 1 - func = [f, b][(a[n_arr] + sigma) % 2] - for v in func(m_arr, n_arr - 1, 0, n, a): - if v is not None: - yield v - if (m_arr + sigma) % 2 == 1: - a[n_arr - 1] = 0 - else: - a[m_arr] = 0 - if m_arr <= 2: - v = visit(n, a) - if v is not None: - yield v + if type(multiset) is int: + n = multiset + if m and m > n: + return + multiset = list(range(multiset)) + if m == 1: + yield [multiset[:]] + return + for nc, q in _set_partitions(n): + if m is None or nc == m: + rv = [[] for i in range(nc)] + for i in range(n): + rv[q[i]].append(multiset[i]) + yield rv + return + + if len(multiset) == 1 and type(multiset) is str: + multiset = [multiset] + + if not has_variety(multiset): + n = len(multiset) + if m and m > n: + return + if m == 1: + yield [multiset[:]] + return + x = multiset[:1] + for size, p in partitions(n, m, size=True): + if m is None or size == m: + rv = [] + for k in sorted(p): + rv.extend([x*k]*p[k]) + yield rv + else: + multiset = list(ordered(multiset)) + n = len(multiset) + if m and m > n: + return + if m == 1: + yield [multiset[:]] + return + + # if there are repeated elements, sort them and define the + # canon dictionary that will be used to create the cache key + # in case elements of the multiset are not hashable + cache = set() + canon = {} # {physical position: position where it appeared first} + for i, mi in enumerate(multiset): + canon.setdefault(i, canon.get(i, multiset.index(mi))) + if len(set(canon.values())) != n: + canon = {} + for i, mi in enumerate(multiset): + canon.setdefault(i, canon.get(i, multiset.index(mi))) else: - for v in b(m_arr - 1, n_arr - 1, (m_arr + sigma) % 2, n, a): - if v is not None: - yield v - - n = len(multiset) - a = [0] * (n + 1) - for j in range(1, m + 1): - a[n - m + j] = j - 1 - return f(m, n, 0, n, a) + canon = None + + for nc, q in _set_partitions(n): + if m is None or nc == m: + rv = [[] for i in range(nc)] + for i in range(n): + rv[q[i]].append(i) + if canon: + canonical = tuple( + sorted([tuple([canon[i] for i in j]) for j in rv])) + if canonical in cache: + continue + cache.add(canonical) + + yield [[multiset[j] for j in i] for i in rv] -def partitions(n, m=None, k=None): + +def partitions(n, m=None, k=None, size=False): """Generate all partitions of integer n (>= 0). - 'm' limits the number of parts in the partition, e.g. if m=2 then - partitions will contain no more than 2 numbers, while - 'k' limits the numbers which may appear in the partition, e.g. k=2 will - return partitions with no element greater than 2. + Parameters + ========== + + ``m`` : integer (default gives partitions of all sizes) + limits number of parts in parition (mnemonic: m, maximum parts) + ``k`` : integer (default gives partitions number from 1 through n) + limits the numbers that are kept in the partition (mnemonic: k, keys) + ``size`` : bool (default False, only partition is returned) + when ``True`` then (M, P) is returned where M is the sum of the + multiplicities and P is the generated partition. Each partition is represented as a dictionary, mapping an integer to the number of copies of that integer in the partition. For example, - the first partition of 4 returned is {4: 1}: a single 4. + the first partition of 4 returned is {4: 1}, "4: one of them". + + Examples + ======== >>> from sympy.utilities.iterables import partitions - Maximum key (number in partition) limited with k (in this case, 2): + The numbers appearing in the partition (the key of the returned dict) + are limited with k: >>> for p in partitions(6, k=2): ... print(p) @@ -917,7 +1299,8 @@ {1: 4, 2: 1} {1: 6} - Maximum number of parts in partion limited with m (in this case, 2): + The maximum number of parts in the partion (the sum of the values in + the returned dict) are limited with m: >>> for p in partitions(6, m=2): ... print(p) @@ -929,7 +1312,7 @@ Note that the _same_ dictionary object is returned each time. This is for speed: generating each partition goes quickly, - taking constant time independent of n. + taking constant time, independent of n. >>> [p for p in partitions(6, k=2)] [{1: 6}, {1: 6}, {1: 6}, {1: 6}] @@ -939,6 +1322,8 @@ >>> [p.copy() for p in partitions(6, k=2)] [{2: 3}, {1: 2, 2: 2}, {1: 4, 2: 1}, {1: 6}] + >>> [(M, p.copy()) for M, p in partitions(6, k=2, size=True)] + [(3, {2: 3}), (4, {1: 2, 2: 2}), (5, {1: 4, 2: 1}), (6, {1: 6})] Reference: modified from Tim Peter's version to allow for k and m values: @@ -948,6 +1333,7 @@ ======== sympy.combinatorics.partitions.Partition sympy.combinatorics.partitions.IntegerPartition + """ if n < 0: raise ValueError("n must be >= 0") @@ -971,7 +1357,10 @@ ms[r] = 1 keys.append(r) room = m - q - bool(r) - yield ms + if size: + yield sum(ms.values()), ms + else: + yield ms while keys != [1]: # Reuse any 1's. @@ -992,7 +1381,6 @@ del keys[-1], ms[i] room += 1 - # Break the remainder into pieces of size i-1. i -= 1 q, r = divmod(reuse, i) @@ -1009,7 +1397,11 @@ keys.append(r) break room -= need - yield ms + if size: + yield sum(ms.values()), ms + else: + yield ms + def binary_partitions(n): """ @@ -1064,11 +1456,13 @@ x >>= 1 yield [1]*n + def has_dups(seq): """Return True if there are any duplicate elements in ``seq``. Examples ======== + >>> from sympy.utilities.iterables import has_dups >>> from sympy import Dict, Set @@ -1084,13 +1478,14 @@ uniq = set() return any(True for s in seq if s in uniq or uniq.add(s)) + def has_variety(seq): """Return True if there are any different elements in ``seq``. Examples ======== + >>> from sympy.utilities.iterables import has_variety - >>> from sympy import Dict, Set >>> has_variety((1, 2, 1)) True @@ -1105,72 +1500,116 @@ return True return False -def uniq(seq): - """ - Remove repeated elements from an iterable, preserving order of first - appearance. - Returns a sequence of the same type of the input, or a list if the input - was not a sequence. +def uniq(seq, result=None): + """ + Yield unique elements from ``seq`` as an iterator. The second + parameter ``result`` is used internally; it is not necessary to pass + anything for this. Examples ======== >>> from sympy.utilities.iterables import uniq - >>> uniq([1,4,1,5,4,2,1,2]) + >>> dat = [1, 4, 1, 5, 4, 2, 1, 2] + >>> type(uniq(dat)) in (list, tuple) + False + + >>> list(uniq(dat)) [1, 4, 5, 2] - >>> uniq((1,4,1,5,4,2,1,2)) - (1, 4, 5, 2) - >>> uniq(x for x in (1,4,1,5,4,2,1,2)) + >>> list(uniq(x for x in dat)) [1, 4, 5, 2] - + >>> list(uniq([[1], [2, 1], [1]])) + [[1], [2, 1]] """ - from sympy.core.function import Tuple - seen = set() - result = (s for s in seq if not (s in seen or seen.add(s))) - if not hasattr(seq, '__getitem__'): - return list(result) - if isinstance(seq, Tuple): - return Tuple(*tuple(result)) - return type(seq)(result) + try: + seen = set() + result = result or [] + for i, s in enumerate(seq): + if not (s in seen or seen.add(s)): + yield s + except TypeError: + if s not in result: + yield s + result.append(s) + if hasattr(seq, '__getitem__'): + for s in uniq(seq[i + 1:], result): + yield s + else: + for s in uniq(seq, result): + yield s + def generate_bell(n): """ - Generates the bell permutations. - - In a Bell permutation, each cycle is a decreasing - sequence of integers. - - Reference: - [1] Generating involutions, derangements, and relatives by ECO - Vincent Vajnovszki, DMTCS vol 1 issue 12, 2010 + Generates the bell permutations of length ``n``. Examples ======== >>> from sympy.utilities.iterables import generate_bell - >>> list(generate_bell(3)) - [(0, 1, 2), (0, 2, 1), (1, 0, 2), (2, 0, 1), (2, 1, 0)] - """ - P = [i for i in range(n)] - T = [0] - cache = set() - def gen(P, T, t): - if t == (n - 1): - cache.add(tuple(P)) + >>> from sympy import zeros, Matrix + >>> from sympy.core.compatibility import permutations + + This is the sort of permutation used in the ringing of physical bells, + and does not produce permutations in lexicographical order. Rather, the + permutations differ from each other by exactly one inversion, and the + position at which the swapping occurs varies periodically in a simple + fashion. Consider the first few permutations of 4 elements generated + by ``permutations`` and ``generate_bell``: + + >>> list(permutations(list(range(4))))[:5] + [(0, 1, 2, 3), (0, 1, 3, 2), (0, 2, 1, 3), (0, 2, 3, 1), (0, 3, 1, 2)] + >>> list(generate_bell(4))[:5] + [(0, 1, 2, 3), (1, 0, 2, 3), (1, 2, 0, 3), (1, 2, 3, 0), (2, 1, 3, 0)] + + Notice how the 2nd and 3rd lexicographical permutations have 3 elements + out of place whereas each bell permutations always has only two + elements out of place relative to the previous permutation. + + How the position of inversion varies across the elements can be seen + by tracing out where the 0 appears in the permutations: + + >>> m = zeros(4, 24) + >>> for i, p in enumerate(generate_bell(4)): + ... m[:, i] = Matrix(list(p)) + >>> m.print_nonzero('X') + [ XXXXXX XXXXXX XXXXXX ] + [X XXXX XX XXXX XX XXXX X] + [XX XX XXXX XX XXXX XX XX] + [XXX XXXXXX XXXXXX XXX] + + References + ========== + + * http://en.wikipedia.org/wiki/Method_ringing + * http://stackoverflow.com/questions/4856615/recursive-permutation/4857018 + * http://programminggeeks.com/bell-algorithm-for-permutation/ + * http://en.wikipedia.org/wiki/ + Steinhaus%E2%80%93Johnson%E2%80%93Trotter_algorithm + * Generating involutions, derangements, and relatives by ECO + Vincent Vajnovszki, DMTCS vol 1 issue 12, 2010 + + """ + from sympy.functions.combinatorial.factorials import factorial + pos = dir = 1 + do = factorial(n) + p = list(range(n)) + yield tuple(p) + do -= 1 + while do: + if pos >= n: + dir = -dir + p[0], p[1] = p[1], p[0] + elif pos < 1: + dir = -dir + p[-2], p[-1] = p[-1], p[-2] else: - for i in T: - P[i], P[t+1] = P[t+1], P[i] - if tuple(P) not in cache: - cache.add(tuple(P)) - gen(P, T, t + 1) - P[i], P[t+1] = P[t+1], P[i] - T.append(t + 1) - cache.add(tuple(P)) - gen(P, T, t + 1) - T.remove(t + 1) - gen(P, T, 0) - return sorted(cache) + p[pos - 1], p[pos] = p[pos], p[pos - 1] + pos += dir + yield tuple(p) + do -= 1 + def generate_involutions(n): """ @@ -1192,37 +1631,23 @@ ======== >>> from sympy.utilities.iterables import generate_involutions - >>> generate_involutions(3) + >>> list(generate_involutions(3)) [(0, 1, 2), (0, 2, 1), (1, 0, 2), (2, 1, 0)] - >>> len(generate_involutions(4)) + >>> len(list(generate_involutions(4))) 10 """ - P = list(range(n)) # the items of the permutation - F = [0] # the fixed points {is this right??} - cache = set() - def gen(P, F, t): - if t == n: - cache.add(tuple(P)) + idx = list(range(n)) + for p in permutations(idx): + for i in idx: + if p[p[i]] != i: + break else: - for j in range(len(F)): - P[j], P[t] = P[t], P[j] - if tuple(P) not in cache: - cache.add(tuple(P)) - Fj = F.pop(j) - gen(P, F, t + 1) - F.insert(j, Fj) - P[j], P[t] = P[t], P[j] - t += 1 - F.append(t) - cache.add(tuple(P)) - gen(P, F, t) - F.pop() - gen(P, F, 1) - return sorted(cache) + yield p + def generate_derangements(perm): """ - Routine to generate derangements. + Routine to generate unique derangements. TODO: This will be rewritten to use the ECO operator approach once the permutations @@ -1232,59 +1657,83 @@ ======== >>> from sympy.utilities.iterables import generate_derangements - >>> list(generate_derangements([0,1,2])) + >>> list(generate_derangements([0, 1, 2])) [[1, 2, 0], [2, 0, 1]] - >>> list(generate_derangements([0,1,2,3])) + >>> list(generate_derangements([0, 1, 2, 3])) [[1, 0, 3, 2], [1, 2, 3, 0], [1, 3, 0, 2], [2, 0, 3, 1], \ [2, 3, 0, 1], [2, 3, 1, 0], [3, 0, 1, 2], [3, 2, 0, 1], \ [3, 2, 1, 0]] - >>> list(generate_derangements([0,1,1])) + >>> list(generate_derangements([0, 1, 1])) [] + + See Also + ======== + sympy.functions.combinatorial.factorials.subfactorial """ + p = multiset_permutations(perm) indices = list(range(len(perm))) - p = variations(indices, len(indices)) - for rv in \ - uniq(tuple(perm[i] for i in idx) \ - for idx in p if all(perm[k] != \ - perm[idx[k]] for k in range(len(perm)))): - yield list(rv) + p0 = next(p) + for pi in p: + if all(pi[i] != p0[i] for i in indices): + yield pi + +@deprecated( + useinstead="bracelets", deprecated_since_version="0.7.3") def unrestricted_necklace(n, k): - """ - A routine to generate unrestriced necklaces. + """Wrapper to necklaces to return a free (unrestricted) necklace.""" + return necklaces(n, k, free=True) - Here n is the length of the necklace and k - 1 - is the maximum permissible element in the - generated necklaces. - Reference: - http://mathworld.wolfram.com/Necklace.html +def necklaces(n, k, free=False): + """ + A routine to generate necklaces that may (free=True) or may not + (free=False) be turned over to be viewed. The "necklaces" returned + are comprised of ``n`` integers (beads) with ``k`` different + values (colors). Only unique necklaces are returned. Examples ======== - >>> from sympy.utilities.iterables import unrestricted_necklace - >>> [i[:] for i in unrestricted_necklace(3, 2)] - [[0, 0, 0], [0, 1, 1]] - >>> [i[:] for i in unrestricted_necklace(4, 4)] - [[0, 0, 0, 0], [0, 0, 1, 0], [0, 0, 2, 0], [0, 0, 3, 0], \ - [0, 1, 1, 1], [0, 1, 2, 1], [0, 1, 3, 1], [0, 2, 2, 2], \ - [0, 2, 3, 2], [0, 3, 3, 3]] - """ - a = [0] * n - def gen(t, p): - if (t > n - 1): - if (n % p == 0): - yield a - else: - a[t] = a[t - p] - for necklace in gen(t + 1, p): - yield necklace - for j in range(a[t - p] + 1, k): - a[t] = j - for necklace in gen(t + 1, t): - yield necklace - return gen(1, 1) + >>> from sympy.utilities.iterables import necklaces, bracelets + >>> def show(s, i): + ... return ''.join(s[j] for j in i) + + The "unrestricted necklace" is sometimes also referred to as a + "bracelet" (an object that can be turned over, a sequence that can + be reversed) and the term "necklace" is used to imply a sequence + that cannot be reversed. So ACB == ABC for a bracelet (rotate and + reverse) while the two are different for a necklace since rotation + alone cannot make the two sequences the same. + + (mnemonic: Bracelets can be viewed Backwards, but Not Necklaces.) + + >>> B = [show('ABC', i) for i in bracelets(3, 3)] + >>> N = [show('ABC', i) for i in necklaces(3, 3)] + >>> set(N) - set(B) + set(['ACB']) + + >>> list(necklaces(4, 2)) + [(0, 0, 0, 0), (0, 0, 0, 1), (0, 0, 1, 1), + (0, 1, 0, 1), (0, 1, 1, 1), (1, 1, 1, 1)] + + >>> [show('.o', i) for i in bracelets(4, 2)] + ['....', '...o', '..oo', '.o.o', '.ooo', 'oooo'] + + References + ========== + + http://mathworld.wolfram.com/Necklace.html + + """ + return uniq(minlex(i, directed=not free) for i in + variations(list(range(k)), n, repetition=True)) + + +def bracelets(n, k): + """Wrapper to necklaces to return a free (unrestricted) necklace.""" + return necklaces(n, k, free=True) + def generate_oriented_forest(n): """ @@ -1327,90 +1776,22 @@ else: break -def lazyDSU_sort(seq, keys, warn=False): - """Return sorted seq, breaking ties by applying keys only when needed. - - If ``warn`` is True then an error will be raised if there were no - keys remaining to break ties. - - Examples - ======== - - >>> from sympy.utilities.iterables import lazyDSU_sort, default_sort_key - >>> from sympy.abc import x, y - - The count_ops is not sufficient to break ties in this list and the first - two items appear in their original order: Python sorting is stable. - - >>> lazyDSU_sort([y + 2, x + 2, x**2 + y + 3], - ... [lambda x: x.count_ops()], warn=False) - ... - [y + 2, x + 2, x**2 + y + 3] - - The use of default_sort_key allows the tie to be broken (and warn can - be safely left False). - - >>> lazyDSU_sort([y + 2, x + 2, x**2 + y + 3], - ... [lambda x: x.count_ops(), - ... default_sort_key]) - ... - [x + 2, y + 2, x**2 + y + 3] - - Here, sequences are sorted by length, then sum: - - >>> seq, keys = [[[1, 2, 1], [0, 3, 1], [1, 1, 3], [2], [1]], [ - ... lambda x: len(x), - ... lambda x: sum(x)]] - ... - >>> lazyDSU_sort(seq, keys, warn=False) - [[1], [2], [1, 2, 1], [0, 3, 1], [1, 1, 3]] - If ``warn`` is True, an error will be raised if there were not - enough keys to break ties: - - >>> lazyDSU_sort(seq, keys, warn=True) - Traceback (most recent call last): - ... - ValueError: not enough keys to break ties - - - Notes - ===== +def minlex(seq, directed=True, is_set=False, small=None): + """ + Return a tuple where the smallest element appears first; if + ``directed`` is True (default) then the order is preserved, otherwise + the sequence will be reversed if that gives a smaller ordering. - The decorated sort is one of the fastest ways to sort a sequence for - which special item comparison is desired: the sequence is decorated, - sorted on the basis of the decoration (e.g. making all letters lower - case) and then undecorated. If one wants to break ties for items that - have the same decorated value, a second key can be used. But if the - second key is expensive to compute then it is inefficient to decorate - all items with both keys: only those items having identical first key - values need to be decorated. This function applies keys successively - only when needed to break ties. - """ - d = defaultdict(list) - keys = list(keys) - f = keys.pop(0) - for a in seq: - d[f(a)].append(a) - seq = [] - for k in sorted(d.keys()): - if len(d[k]) > 1: - if keys: - d[k] = lazyDSU_sort(d[k], keys, warn) - elif warn: - raise ValueError('not enough keys to break ties') - seq.extend(d[k]) - else: - seq.append(d[k][0]) - return seq + If every element appears only once then is_set can be set to True + for more efficient processing. -def minlex(seq, directed=True): - """Return a tuple where the smallest element appears first; if - ``directed`` is True (default) then the order is preserved, otherwise the - sequence will be reversed if that gives a lexically smaller ordering. + If the smallest element is known at the time of calling, it can be + passed and the calculation of the smallest element will be omitted. Examples ======== + >>> from sympy.combinatorics.polyhedron import minlex >>> minlex((1, 2, 0)) (0, 1, 2) @@ -1418,20 +1799,58 @@ (0, 2, 1) >>> minlex((1, 0, 2), directed=False) (0, 1, 2) + + >>> minlex('11010011000', directed=True) + '00011010011' + >>> minlex('11010011000', directed=False) + '00011001011' + """ + is_str = isinstance(seq, str) seq = list(seq) - small = min(seq) - i = seq.index(small) - if not directed: - n = len(seq) - p = (i + 1) % n - m = (i - 1) % n - if seq[p] > seq[m]: - seq = list(reversed(seq)) - i = n - i - 1 - if i: - seq = rotate_left(seq, i) - return tuple(seq) + if small is None: + small = min(seq) + if is_set: + i = seq.index(small) + if not directed: + n = len(seq) + p = (i + 1) % n + m = (i - 1) % n + if seq[p] > seq[m]: + seq = list(reversed(seq)) + i = n - i - 1 + if i: + seq = rotate_left(seq, i) + best = seq + else: + count = seq.count(small) + if count == 1 and directed: + best = rotate_left(seq, seq.index(small)) + else: + # if not directed, and not a set, we can't just + # pass this off to minlex with is_set True since + # peeking at the neighbor may not be sufficient to + # make the decision so we continue... + best = seq + for i in range(count): + seq = rotate_left(seq, seq.index(small, count != 1)) + if seq < best: + best = seq + # it's cheaper to rotate now rather than search + # again for these in reversed order so we test + # the reverse now + if not directed: + seq = rotate_left(seq, 1) + seq = list(reversed(seq)) + if seq < best: + best = seq + seq = list(reversed(seq)) + seq = rotate_right(seq, 1) + # common return + if is_str: + return ''.join(best) + return tuple(best) + def runs(seq, op=gt): """Group the sequence into lists in which successive elements @@ -1468,3 +1887,130 @@ if run: cycles.append(run) return cycles + + +def kbins(l, k, ordered=None): + """ + Return sequence ``l`` partitioned into ``k`` bins. + + Examples + ======== + + >>> from sympy.utilities.iterables import kbins + + The default is to give the items in the same order, but grouped + into k partitions without any reordering: + + >>> for p in kbins(list(range(5)), 2): + ... print(p) + ... + [[0], [1, 2, 3, 4]] + [[0, 1], [2, 3, 4]] + [[0, 1, 2], [3, 4]] + [[0, 1, 2, 3], [4]] + + The ``ordered`` flag which is either None (to give the simple partition + of the the elements) or is a 2 digit integer indicating whether the order of + the bins and the order of the items in the bins matters. Given:: + + A = [[0], [1, 2]] + B = [[1, 2], [0]] + C = [[2, 1], [0]] + D = [[0], [2, 1]] + + the following values for ``ordered`` have the shown meanings:: + + 00 means A == B == C == D + 01 means A == B + 10 means A == D + 11 means A == A + + >>> for ordered in [None, 0, 1, 10, 11]: + ... print('ordered =', ordered) + ... for p in kbins(list(range(3)), 2, ordered=ordered): + ... print(' ', p) + ... + ordered = None + [[0], [1, 2]] + [[0, 1], [2]] + ordered = 0 + [[0, 1], [2]] + [[0, 2], [1]] + [[0], [1, 2]] + ordered = 1 + [[0], [1, 2]] + [[0], [2, 1]] + [[1], [0, 2]] + [[1], [2, 0]] + [[2], [0, 1]] + [[2], [1, 0]] + ordered = 10 + [[0, 1], [2]] + [[2], [0, 1]] + [[0, 2], [1]] + [[1], [0, 2]] + [[0], [1, 2]] + [[1, 2], [0]] + ordered = 11 + [[0], [1, 2]] + [[0, 1], [2]] + [[0], [2, 1]] + [[0, 2], [1]] + [[1], [0, 2]] + [[1, 0], [2]] + [[1], [2, 0]] + [[1, 2], [0]] + [[2], [0, 1]] + [[2, 0], [1]] + [[2], [1, 0]] + [[2, 1], [0]] + + See Also + ======== + partitions, multiset_partitions + + """ + def partition(lista, bins): + # EnricoGiampieri's partition generator from + # http://stackoverflow.com/questions/13131491/ + # partition-n-items-into-k-bins-in-python-lazily + if len(lista) == 1 or bins == 1: + yield [lista] + elif len(lista) > 1 and bins > 1: + for i in range(1, len(lista)): + for part in partition(lista[i:], bins - 1): + if len([lista[:i]] + part) == bins: + yield [lista[:i]] + part + + if ordered is None: + for p in partition(l, k): + yield p + elif ordered == 11: + for pl in multiset_permutations(l): + pl = list(pl) + for p in partition(pl, k): + yield p + elif ordered == 00: + for p in multiset_partitions(l, k): + yield p + elif ordered == 10: + for p in multiset_partitions(l, k): + for perm in permutations(p): + yield list(perm) + elif ordered == 0o1: + for kgot, p in partitions(len(l), k, size=True): + if kgot != k: + continue + for li in multiset_permutations(l): + rv = [] + i = j = 0 + li = list(li) + for size, multiplicity in sorted(p.items()): + for m in range(multiplicity): + j = i + size + rv.append(li[i: j]) + i = j + yield rv + else: + raise ValueError( + 'ordered must be one of 00, 01, 10 or 11, not %s' % ordered) diff -Nru python3-sympy-0.7.2/sympy/utilities/lambdify.py python3-sympy-0.7.3/sympy/utilities/lambdify.py --- python3-sympy-0.7.2/sympy/utilities/lambdify.py 2012-10-17 03:02:22.000000000 +0000 +++ python3-sympy-0.7.3/sympy/utilities/lambdify.py 2013-07-13 17:53:32.000000000 +0000 @@ -5,7 +5,7 @@ from sympy.external import import_module -from sympy.core.compatibility import is_sequence +from sympy.core.compatibility import is_sequence, iterable import inspect @@ -26,64 +26,74 @@ # Mappings between sympy and other modules function names. MATH_TRANSLATIONS = { - "Abs":"fabs", - "ceiling":"ceil", - "E":"e", - "ln":"log", + "Abs": "fabs", + "ceiling": "ceil", + "E": "e", + "ln": "log", } MPMATH_TRANSLATIONS = { - "ceiling":"ceil", - "chebyshevt":"chebyt", - "chebyshevu":"chebyu", - "E":"e", - "I":"j", - "ln":"log", + "elliptic_k": "ellipk", + "elliptic_f": "ellipf", + "elliptic_e": "ellipe", + "elliptic_pi": "ellippi", + "ceiling": "ceil", + "chebyshevt": "chebyt", + "chebyshevu": "chebyu", + "E": "e", + "I": "j", + "ln": "log", #"lowergamma":"lower_gamma", - "oo":"inf", + "oo": "inf", #"uppergamma":"upper_gamma", - "LambertW":"lambertw", - "Matrix":"matrix", - "conjugate":"conj", - "dirichlet_eta":"altzeta", - "Ei":"ei", - "Shi":"shi", - "Chi":"chi", - "Si":"si", - "Ci":"ci" + "LambertW": "lambertw", + "Matrix": "matrix", + "MutableDenseMatrix": "matrix", + "ImmutableMatrix": "matrix", + "conjugate": "conj", + "dirichlet_eta": "altzeta", + "Ei": "ei", + "Shi": "shi", + "Chi": "chi", + "Si": "si", + "Ci": "ci" } NUMPY_TRANSLATIONS = { - "Abs":"abs", - "acos":"arccos", - "acosh":"arccosh", - "arg":"angle", - "asin":"arcsin", - "asinh":"arcsinh", - "atan":"arctan", - "atan2":"arctan2", - "atanh":"arctanh", - "ceiling":"ceil", - "E":"e", - "im":"imag", - "ln":"log", - "Matrix":"matrix", - "Max":"amax", - "Min":"amin", - "oo":"inf", - "re":"real", + "Abs": "abs", + "acos": "arccos", + "acosh": "arccosh", + "arg": "angle", + "asin": "arcsin", + "asinh": "arcsinh", + "atan": "arctan", + "atan2": "arctan2", + "atanh": "arctanh", + "ceiling": "ceil", + "E": "e", + "im": "imag", + "ln": "log", + "Matrix": "matrix", + "MutableDenseMatrix": "matrix", + "ImmutableMatrix": "matrix", + "Max": "amax", + "Min": "amin", + "oo": "inf", + "re": "real", } # Available modules: MODULES = { - "math" : (MATH, MATH_DEFAULT, MATH_TRANSLATIONS, ("from math import *",)), - "mpmath" : (MPMATH, MPMATH_DEFAULT, MPMATH_TRANSLATIONS, ("from sympy.mpmath import *",)), - "numpy" : (NUMPY, NUMPY_DEFAULT, NUMPY_TRANSLATIONS, ("import_module('numpy')",)), - "sympy" : (SYMPY, SYMPY_DEFAULT, {}, ("from sympy.functions import *", - "from sympy.matrices import Matrix", - "from sympy import Integral, pi, oo, nan, zoo, E, I",)), + "math": (MATH, MATH_DEFAULT, MATH_TRANSLATIONS, ("from math import *",)), + "mpmath": (MPMATH, MPMATH_DEFAULT, MPMATH_TRANSLATIONS, ("from sympy.mpmath import *",)), + "numpy": (NUMPY, NUMPY_DEFAULT, NUMPY_TRANSLATIONS, ("import_module('numpy')",)), + "sympy": (SYMPY, SYMPY_DEFAULT, {}, ( + "from sympy.functions import *", + "from sympy.matrices import *", + "from sympy import Integral, pi, oo, nan, zoo, E, I",)), } + def _import(module, reload="False"): """ Creates a global translation dictionary for module. @@ -94,9 +104,11 @@ other modules. """ try: - namespace, namespace_default, translations, import_commands = MODULES[module] + namespace, namespace_default, translations, import_commands = MODULES[ + module] except KeyError: - raise NameError("'%s' module can't be used for lambdification" % module) + raise NameError( + "'%s' module can't be used for lambdification" % module) # Clear namespace or exit if namespace != namespace_default: @@ -121,48 +133,31 @@ except ImportError: pass - raise ImportError("can't import '%s' with '%s' command" % (module, import_command)) + raise ImportError( + "can't import '%s' with '%s' command" % (module, import_command)) # Add translated names to namespace for sympyname, translation in translations.items(): namespace[sympyname] = namespace[translation] + def lambdify(args, expr, modules=None, printer=None, use_imps=True): """ Returns a lambda function for fast calculation of numerical values. - Usage: - - >>> from sympy import sqrt, sin - >>> from sympy.utilities.lambdify import lambdify - >>> from sympy.abc import x, y, z - >>> f = lambdify(x, x**2) - >>> f(2) - 4 - >>> f = lambdify((x,y,z), [z,y,x]) - >>> f(1,2,3) - [3, 2, 1] - >>> f = lambdify(x, sqrt(x)) - >>> f(4) - 2.0 - >>> f = lambdify((x,y), sin(x*y)**2) - >>> f(0, 5) - 0.0 - If not specified differently by the user, SymPy functions are replaced as far as possible by either python-math, numpy (if available) or mpmath - functions - exactly in this order. - To change this behavior, the "modules" argument can be used. - It accepts: + functions - exactly in this order. To change this behavior, the "modules" + argument can be used. It accepts: - the strings "math", "mpmath", "numpy", "sympy" - any modules (e.g. math) - dictionaries that map names of sympy functions to arbitrary functions - - lists that contain a mix of the arguments above. (Entries that are first - in the list have higher priority) + - lists that contain a mix of the arguments above, with higher priority + given to entries appearing first. - Examples - ======== + Usage + ===== (1) Use one of the provided modules: @@ -201,27 +196,49 @@ >> lambda x: my_cool_function(x) + Examples + ======== + + >>> from sympy.utilities.lambdify import implemented_function, lambdify + >>> from sympy import sqrt, sin, Matrix + >>> from sympy import Function + >>> from sympy.abc import x, y, z + + >>> f = lambdify(x, x**2) + >>> f(2) + 4 + >>> f = lambdify((x, y, z), [z, y, x]) + >>> f(1,2,3) + [3, 2, 1] + >>> f = lambdify(x, sqrt(x)) + >>> f(4) + 2.0 + >>> f = lambdify((x, y), sin(x*y)**2) + >>> f(0, 5) + 0.0 + >>> f = lambdify((x, y), Matrix((x, x + y)).T, modules='sympy') + >>> f(1, 2) + Matrix([[1, 3]]) + Functions present in `expr` can also carry their own numerical implementations, in a callable attached to the ``_imp_`` attribute. Usually you attach this using the ``implemented_function`` factory: - >>> from sympy.abc import x, y, z - >>> from sympy.utilities.lambdify import lambdify, implemented_function - >>> from sympy import Function >>> f = implemented_function(Function('f'), lambda x: x+1) >>> func = lambdify(x, f(x)) >>> func(4) 5 - ``lambdify`` always prefers ``_imp_`` implementations to - implementations in other namespaces, unless the ``use_imps`` input - parameter is False. + ``lambdify`` always prefers ``_imp_`` implementations to implementations + in other namespaces, unless the ``use_imps`` input parameter is False. """ from sympy.core.symbol import Symbol # If the user hasn't specified any modules, use what is available. + module_provided = True if modules is None: + module_provided = False # Use either numpy (if available) or python.math where possible. # XXX: This leads to different behaviour on different systems and # might be the reason for irreproducible errors. @@ -234,6 +251,7 @@ else: modules.insert(1, "numpy") + # Get the needed namespaces. namespaces = [] # First find any function implementations @@ -257,11 +275,23 @@ for term in syms: namespace.update({str(term): term}) - # Create lambda function. - lstr = lambdastr(args, expr, printer=printer) + # check if being used for numerical translations + dummify = False + if not module_provided: + if ((modules[1] == "numpy") or (modules[1] == "math") or + (modules[1] == "mpmath")): + dummify = True + else: + if isinstance(module_provided, str): + if ((modules == "numpy") or (modules == "math") or + (modules == "mpmath")): + dummify = True + # Create lambda function. + lstr = lambdastr(args, expr, printer=printer, dummify=dummify) return eval(lstr, namespace) + def _get_namespace(m): """ This is used by _lambdify to parse its arguments. @@ -276,7 +306,8 @@ else: raise TypeError("Argument must be either a string, dict or module but it is: %s" % m) -def lambdastr(args, expr, printer=None): + +def lambdastr(args, expr, printer=None, dummify=False): """ Returns a string that can be evaluated to a lambda function. @@ -288,6 +319,10 @@ 'lambda x,y,z: ([z, y, x])' """ + # Transforming everything to strings. + from sympy.matrices import DeferredVector + from sympy import Dummy, sympify, Symbol, Function + if printer is not None: if inspect.isfunction(printer): lambdarepr = printer @@ -300,17 +335,61 @@ #XXX: This has to be done here because of circular imports from sympy.printing.lambdarepr import lambdarepr - # Transform everything to strings. - expr = lambdarepr(expr) - if isinstance(args, str): - pass - elif hasattr(args, "__iter__"): - args = ",".join(str(a) for a in args) + def sub_args(args, dummies_dict): + if isinstance(args, str): + return args + elif isinstance(args, DeferredVector): + return str(args) + elif iterable(args): + flatten = lambda *n: (e for a in n for e in + (flatten(*a) if iterable(a) else (a,))) + dummies = flatten([sub_args(a, dummies_dict) for a in args]) + return ",".join(str(a) for a in dummies) + else: + if isinstance(args, (Symbol, Function)): + dummies = Dummy() + dummies_dict.update({args : dummies}) + return str(dummies) + else: + return str(args) + + def sub_expr(expr, dummies_dict): + try: + expr = sympify(expr).xreplace(dummies_dict) + except: + if isinstance(expr, DeferredVector): + pass + elif isinstance(expr, dict): + k = [sub_expr(sympify(a), dummies_dict) for a in list(expr.keys())] + v = [sub_expr(sympify(a), dummies_dict) for a in list(expr.values())] + expr = dict(list(zip(k, v))) + elif isinstance(expr, tuple): + expr = tuple(sub_expr(sympify(a), dummies_dict) for a in expr) + elif isinstance(expr, list): + expr = [sub_expr(sympify(a), dummies_dict) for a in expr] + return expr + + # Transform args + dummies_dict = {} + if dummify: + args = sub_args(args, dummies_dict) else: - args = str(args) + if isinstance(args, str): + pass + elif iterable(args, exclude=DeferredVector): + args = ",".join(str(a) for a in args) + + # Transform expr + if dummify: + if isinstance(expr, str): + pass + else: + expr = sub_expr(expr, dummies_dict) + expr = lambdarepr(expr) return "lambda %s: (%s)" % (args, expr) + def _imp_namespace(expr, namespace=None): """ Return namespace dict with function implementations @@ -336,7 +415,7 @@ Examples -------- - >>> from sympy.abc import x, y, z + >>> from sympy.abc import x >>> from sympy.utilities.lambdify import implemented_function, _imp_namespace >>> from sympy import Function >>> f = implemented_function(Function('f'), lambda x: x+1) @@ -377,6 +456,7 @@ _imp_namespace(arg, namespace) return namespace + def implemented_function(symfunc, implementation): """ Add numerical ``implementation`` to function ``symfunc``. @@ -404,7 +484,7 @@ Examples -------- - >>> from sympy.abc import x, y, z + >>> from sympy.abc import x >>> from sympy.utilities.lambdify import lambdify, implemented_function >>> from sympy import Function >>> f = implemented_function(Function('f'), lambda x: x+1) diff -Nru python3-sympy-0.7.2/sympy/utilities/mathml/__init__.py python3-sympy-0.7.3/sympy/utilities/mathml/__init__.py --- python3-sympy-0.7.2/sympy/utilities/mathml/__init__.py 2012-10-17 03:02:22.000000000 +0000 +++ python3-sympy-0.7.3/sympy/utilities/mathml/__init__.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,13 +1,14 @@ """Module with some functions for MathML, like transforming MathML content in MathML presentation. -To use this module, you will need libxml2 and libxslt, with its -respective python bindings. +To use this module, you will need lxml. """ from sympy.utilities.pkgdata import get_resource +from sympy.utilities.decorator import doctest_depends_on import xml.dom.minidom + def add_mathml_headers(s): return """""" + s + "" +@doctest_depends_on(modules=('lxml',)) def apply_xsl(mml, xsl): """Apply a xsl to a MathML string @param mml: a string with MathML code @param xsl: a string representing a path to a xsl (xml stylesheet) file. This file name is relative to the PYTHONPATH - """ - - import libxml2 - import libxslt - - s = get_resource(xsl).read() - - styledoc = libxml2.parseDoc(s) - style = libxslt.parseStylesheetDoc(styledoc) - doc = libxml2.parseDoc(mml) - result = style.applyStylesheet(doc, None) - sourceDoc = result - s = style.saveResultToString(result) - - style.freeStylesheet() - sourceDoc.freeDoc() + >>> from sympy.utilities.mathml import apply_xsl + >>> xsl = 'mathml/data/simple_mmlctop.xsl' + >>> mml = ' a b ' + >>> res = apply_xsl(mml,xsl) + >>> ''.join(res.splitlines()) + ' a + b' + """ + from lxml import etree + s = etree.XML(get_resource(xsl).read()) + transform = etree.XSLT(s) + doc = etree.XML(mml) + result = transform(doc) + s = str(result) return s + +@doctest_depends_on(modules=('lxml',)) def c2p(mml, simple=False): """Transforms a document in MathML content (like the one that sympy produces) in one document in MathML presentation, more suitable for printing, and more widely accepted + + >>> from sympy.utilities.mathml import c2p + >>> mml = ' 2 ' + >>> c2p(mml,simple=True) != c2p(mml,simple=False) + True + """ if not mml.startswith('>> from sympy import Basic, S, I, default_sort_key - >>> from sympy.core.function import UndefinedFunction - >>> from sympy.abc import x - - The following are eqivalent ways of getting the key for an object: - - >>> x.sort_key() == default_sort_key(x) - True - - Here are some examples of the key that is produced: - - >>> default_sort_key(UndefinedFunction('f')) - ((0, 0, 'UndefinedFunction'), (1, ('f',)), ((1, 0, 'Number'), (0, ()), (), 1), 1) - >>> default_sort_key('1') - ((0, 0, 'str'), (1, ('1',)), ((1, 0, 'Number'), (0, ()), (), 1), 1) - >>> default_sort_key(S.One) - ((1, 0, 'Number'), (0, ()), (), 1) - >>> default_sort_key(2) - ((1, 0, 'Number'), (0, ()), (), 2) - - - While sort_key is a method only defined for SymPy objects, - default_sort_key will accept anything as an argument so it is - more robust as a sorting key. For the following, using key= - lambda i: i.sort_key() would fail because 2 doesn't have a sort_key - method; that's why default_sort_key is used. Note, that it also - handles sympification of non-string items likes ints: - - >>> a = [2, I, -I] - >>> sorted(a, key=default_sort_key) - [2, -I, I] - - The returned key can be used anywhere that a key can be specified for - a function, e.g. sort, min, max, etc...: - - >>> a.sort(key=default_sort_key); a[0] - 2 - >>> min(a, key=default_sort_key) - 2 - - Note - ---- - - The key returned is useful for getting items into a canonical order - that will be the same across platforms. It is not directly useful for - sorting lists of expressions: - - >>> a, b = x, 1/x - - Since ``a`` has only 1 term, its value of sort_key is unaffected by - ``order``: - - >>> a.sort_key() == a.sort_key('rev-lex') - True - - If ``a`` and ``b`` are combined then the key will differ because there - are terms that can be ordered: - - >>> eq = a + b - >>> eq.sort_key() == eq.sort_key('rev-lex') - False - >>> eq.as_ordered_terms() - [x, 1/x] - >>> eq.as_ordered_terms('rev-lex') - [1/x, x] - - But since the keys for each of these terms are independent of ``order``'s - value, they don't sort differently when they appear separately in a list: - - >>> sorted(eq.args, key=default_sort_key) - [1/x, x] - >>> sorted(eq.args, key=lambda i: default_sort_key(i, order='rev-lex')) - [1/x, x] - - The order of terms obtained when using these keys is the order that would - be obtained if those terms were *factors* in a product. - - See Also - ======== - - sympy.core.expr.as_ordered_factors, sympy.core.expr.as_ordered_terms - - """ - - from sympy.core import S, Basic - from sympy.core.sympify import sympify, SympifyError - from sympy.core.compatibility import iterable - - if isinstance(item, Basic): - return item.sort_key(order=order) - - if iterable(item, exclude=str): - if isinstance(item, dict): - args = list(item.items()) - unordered = True - elif isinstance(item, set): - args = item - unordered = True - else: - # e.g. tuple, list - sort = False - args = list(item) - unordered = False - - args = [default_sort_key(arg, order=order) for arg in args] - - if unordered: - # e.g. dict, set - args = sorted(args) - - cls_index, args = 10, (len(args), tuple(args)) - else: - if not isinstance(item, str): - try: - item = sympify(item) - except SympifyError: - # e.g. lambda x: x - pass - else: - if isinstance(item, Basic): - # e.g int -> Integer - return default_sort_key(item) - # e.g. UndefinedFunction - - # e.g. str - cls_index, args = 0, (1, (str(item),)) - - return (cls_index, 0, item.__class__.__name__ - ), args, S.One.sort_key(), S.One def rawlines(s): """Return a cut-and-pastable string that, when printed, is equivalent @@ -225,7 +76,7 @@ rv = ["("] # add on the newlines trailing = s.endswith('\n') - n = last = len(lines) - 1 + last = len(lines) - 1 for i, li in enumerate(lines): if i != last or trailing: rv.append(repr(li)[:-1] + '\\n\'') @@ -241,7 +92,7 @@ import sys size = getattr(sys, "maxint", None) -if size is None: #Python 3 doesn't have maxint +if size is None: # Python 3 doesn't have maxint size = sys.maxsize if size > 2**32: ARCH = "64-bit" @@ -263,3 +114,37 @@ for a in args: print(a, end=' ') print() + + +def find_executable(executable, path=None): + """Try to find 'executable' in the directories listed in 'path' (a + string listing directories separated by 'os.pathsep'; defaults to + os.environ['PATH']). Returns the complete filename or None if not + found + """ + if path is None: + path = os.environ['PATH'] + paths = path.split(os.pathsep) + extlist = [''] + if os.name == 'os2': + (base, ext) = os.path.splitext(executable) + # executable files on OS/2 can have an arbitrary extension, but + # .exe is automatically appended if no dot is present in the name + if not ext: + executable = executable + ".exe" + elif sys.platform == 'win32': + pathext = os.environ['PATHEXT'].lower().split(os.pathsep) + (base, ext) = os.path.splitext(executable) + if ext.lower() not in pathext: + extlist = pathext + for ext in extlist: + execname = executable + ext + if os.path.isfile(execname): + return execname + else: + for p in paths: + f = os.path.join(p, execname) + if os.path.isfile(f): + return f + else: + return None diff -Nru python3-sympy-0.7.2/sympy/utilities/pkgdata.py python3-sympy-0.7.3/sympy/utilities/pkgdata.py --- python3-sympy-0.7.2/sympy/utilities/pkgdata.py 2012-10-17 03:02:22.000000000 +0000 +++ python3-sympy-0.7.3/sympy/utilities/pkgdata.py 2013-07-13 17:53:32.000000000 +0000 @@ -21,6 +21,7 @@ import os from io import StringIO + def get_resource(identifier, pkgname=__name__): """ Acquire a readable object for a given package name and identifier. @@ -48,7 +49,7 @@ if loader is not None: try: data = loader.get_data(path) - except IOError: + except (IOError,AttributeError): pass else: return StringIO(data) diff -Nru python3-sympy-0.7.2/sympy/utilities/pytest.py python3-sympy-0.7.3/sympy/utilities/pytest.py --- python3-sympy-0.7.2/sympy/utilities/pytest.py 2012-10-17 03:02:22.000000000 +0000 +++ python3-sympy-0.7.3/sympy/utilities/pytest.py 2013-07-13 17:53:32.000000000 +0000 @@ -94,8 +94,10 @@ class RaisesContext(object): def __init__(self, expectedException): self.expectedException = expectedException + def __enter__(self): return None + def __exit__(self, exc_type, exc_value, traceback): if exc_type is None: raise AssertionError("DID NOT RAISE") @@ -131,7 +133,6 @@ def skip(str): raise Skipped(str) - def SKIP(reason): """Similar to :func:`skip`, but this is a decorator. """ def wrapper(func): @@ -145,6 +146,7 @@ def slow(func): func._slow = True + def func_wrapper(): func() diff -Nru python3-sympy-0.7.2/sympy/utilities/randtest.py python3-sympy-0.7.3/sympy/utilities/randtest.py --- python3-sympy-0.7.2/sympy/utilities/randtest.py 2012-10-17 03:02:22.000000000 +0000 +++ python3-sympy-0.7.3/sympy/utilities/randtest.py 2013-07-13 17:53:32.000000000 +0000 @@ -3,9 +3,10 @@ from random import uniform import random -from sympy import I, nsimplify, S, Tuple, Dummy +from sympy import I, nsimplify, Tuple, Symbol from sympy.core.compatibility import is_sequence, as_int + def random_complex_number(a=2, b=-1, c=3, d=1, rational=False): """ Return a random complex number. @@ -36,6 +37,7 @@ else: return diff <= tol + def test_numerically(f, g, z=None, tol=1.0e-6, a=2, b=-1, c=3, d=1): """ Test numerically that f and g agree when evaluated in the argument z. @@ -48,19 +50,20 @@ Examples ======== - >>> from sympy import sin, cos, S + >>> from sympy import sin, cos >>> from sympy.abc import x >>> from sympy.utilities.randtest import test_numerically as tn >>> tn(sin(x)**2 + cos(x)**2, 1, x) True """ f, g, z = Tuple(f, g, z) - z = [z] if z else (f.free_symbols | g.free_symbols) + z = [z] if isinstance(z, Symbol) else (f.free_symbols | g.free_symbols) reps = list(zip(z, [random_complex_number(a, b, c, d) for zi in z])) z1 = f.subs(reps).n() z2 = g.subs(reps).n() return comp(z1, z2, tol) + def test_derivative_numerically(f, z, tol=1.0e-6, a=2, b=-1, c=3, d=1): """ Test numerically that the symbolically computed derivative of f @@ -73,7 +76,7 @@ Examples ======== - >>> from sympy import sin, cos + >>> from sympy import sin >>> from sympy.abc import x >>> from sympy.utilities.randtest import test_derivative_numerically as td >>> td(sin(x), x) @@ -85,7 +88,6 @@ f2 = Derivative(f, z).doit_numerically(z0) return comp(f1.n(), f2.n(), tol) -import random def _randrange(seed=None): """Return a randrange generator. ``seed`` can be o None - return randomly seeded generator @@ -112,8 +114,9 @@ elif isinstance(seed, int): return random.Random(seed).randrange elif is_sequence(seed): - seed = list(seed) # make a copy + seed = list(seed) # make a copy seed.reverse() + def give(a, b=None, seq=seed): if b is None: a, b = 0, a @@ -135,6 +138,7 @@ else: raise ValueError('_randrange got an unexpected seed') + def _randint(seed=None): """Return a randint generator. ``seed`` can be o None - return randomly seeded generator @@ -161,8 +165,9 @@ elif isinstance(seed, int): return random.Random(seed).randint elif is_sequence(seed): - seed = list(seed) # make a copy + seed = list(seed) # make a copy seed.reverse() + def give(a, b, seq=seed): a, b = as_int(a), as_int(b) w = b - a diff -Nru python3-sympy-0.7.2/sympy/utilities/runtests.py python3-sympy-0.7.3/sympy/utilities/runtests.py --- python3-sympy-0.7.2/sympy/utilities/runtests.py 2012-10-17 03:02:22.000000000 +0000 +++ python3-sympy-0.7.3/sympy/utilities/runtests.py 2013-07-13 17:53:32.000000000 +0000 @@ -14,6 +14,7 @@ import os import sys +import platform import inspect import traceback import pdb @@ -21,14 +22,17 @@ import linecache from fnmatch import fnmatch from timeit import default_timer as clock -import doctest as pdoctest # avoid clashing with our doctest() function +import doctest as pdoctest # avoid clashing with our doctest() function from doctest import DocTestFinder, DocTestRunner -import re as pre import random import subprocess import signal +import stat from sympy.core.cache import clear_cache +from sympy.utilities.misc import find_executable +from sympy.external import import_module +from sympy.utilities.exceptions import SymPyDeprecationWarning # Use sys.stdout encoding for ouput. # This was only added to Python's doctest in Python 2.6, so we must duplicate @@ -42,6 +46,11 @@ class Skipped(Exception): pass +import __future__ +# add more flags ?? +future_flags = __future__.division.compiler_flag | \ + __future__.with_statement.compiler_flag + def _indent(s, indent=4): """ Add the given number of space characters to the beginning of @@ -59,6 +68,8 @@ pdoctest._indent = _indent # ovverride reporter to maintain windows and python3 + + def _report_failure(self, out, test, example, got): """ Report that the given example failed. @@ -71,11 +82,6 @@ DocTestRunner.report_failure = _report_failure -def sys_normcase(f): - if sys_case_insensitive: - return f.lower() - return f - def convert_to_native_paths(lst): """ Converts a list of '/' separated paths into a list of @@ -89,11 +95,12 @@ if sys.platform == "win32": pos = rv.find(':') if pos != -1: - if rv[pos+1] != '\\': - rv = rv[:pos+1] + '\\' + rv[pos+1:] + if rv[pos + 1] != '\\': + rv = rv[:pos + 1] + '\\' + rv[pos + 1:] newlst.append(sys_normcase(rv)) return newlst + def get_sympy_dir(): """ Returns the root sympy directory and set the global value @@ -109,9 +116,16 @@ os.path.isdir(sympy_dir.upper())) return sys_normcase(sympy_dir) + +def sys_normcase(f): + if sys_case_insensitive: # global defined after call to get_sympy_dir() + return f.lower() + return f + + def isgeneratorfunction(object): """ - Return true if the object is a user-defined generator function. + Return True if the object is a user-defined generator function. Generator function objects provides same attributes as functions. @@ -121,10 +135,11 @@ """ CO_GENERATOR = 0x20 if (inspect.isfunction(object) or inspect.ismethod(object)) and \ - object.__code__.co_flags & CO_GENERATOR: + object.__code__.co_flags & CO_GENERATOR: return True return False + def setup_pprint(): from sympy import pprint_use_unicode, init_printing @@ -134,9 +149,10 @@ # hook our nice, hash-stable strprinter init_printing(pretty_print=False) + def run_in_subprocess_with_hash_randomization(function, function_args=(), function_kwargs={}, command=sys.executable, - module='sympy.utilities.runtests', force=False): + module='sympy.utilities.runtests', force=False): """ Run a function in a Python subprocess with hash randomization enabled. @@ -177,7 +193,8 @@ ... run_in_subprocess_with_hash_randomization) >>> # run the core tests in verbose mode >>> run_in_subprocess_with_hash_randomization("_test", - ... function_args=("core",), function_kwargs={'verbose': True}) #doctest: +SKIP + ... function_args=("core",), + ... function_kwargs={'verbose': True}) # doctest: +SKIP # Will return 0 if sys.executable supports hash randomization and tests # pass, 1 if they fail, and False if it does not support hash # randomization. @@ -202,7 +219,8 @@ return False # Now run the command commandstring = ("import sys; from %s import %s;sys.exit(%s(*%s, **%s))" % - (module, function, function, repr(function_args), repr(function_kwargs))) + (module, function, function, repr(function_args), + repr(function_kwargs))) try: return subprocess.call([command, "-R", "-c", commandstring]) @@ -214,8 +232,9 @@ else: os.environ["PYTHONHASHSEED"] = hash_seed + def run_all_tests(test_args=(), test_kwargs={}, doctest_args=(), - doctest_kwargs={}, examples_args=(), examples_kwargs={'quiet':True}): + doctest_kwargs={}, examples_args=(), examples_kwargs={'quiet': True}): """ Run all tests. @@ -226,13 +245,14 @@ This is what ``setup.py test`` uses. You can pass arguments and keyword arguments to the test functions that - support them (for now, test, doctest, and the examples). See the docstrings of those - functions for a description of the available options. + support them (for now, test, doctest, and the examples). See the + docstrings of those functions for a description of the available options. For example, to run the solvers tests with colors turned off: >>> from sympy.utilities.runtests import run_all_tests - >>> run_all_tests(test_args=("solvers",), test_kwargs={"colors:False"}) # doctest: +SKIP + >>> run_all_tests(test_args=("solvers",), + ... test_kwargs={"colors:False"}) # doctest: +SKIP """ tests_successful = True @@ -252,7 +272,7 @@ # Examples print() sys.path.append("examples") - from all import run_examples # examples/all.py + from all import run_examples # examples/all.py if not run_examples(*examples_args, **examples_kwargs): tests_successful = False @@ -260,8 +280,10 @@ if not (sys.platform == "win32" or sys.version_info[0] == 3): # run Sage tests; Sage currently doesn't support Windows or Python 3 dev_null = open(os.devnull, 'w') - if subprocess.call("sage -v", shell=True, stdout=dev_null, stderr=dev_null) == 0: - if subprocess.call("sage -python bin/test sympy/external/tests/test_sage.py", shell=True) != 0: + if subprocess.call("sage -v", shell=True, stdout=dev_null, + stderr=dev_null) == 0: + if subprocess.call("sage -python bin/test " + "sympy/external/tests/test_sage.py", shell=True) != 0: tests_successful = False if tests_successful: @@ -274,6 +296,7 @@ print("DO *NOT* COMMIT!") sys.exit(1) + def test(*paths, **kwargs): """ Run tests in the specified test_*.py files. @@ -388,7 +411,7 @@ Python using >>> import os - >>> os.environ['PYTHONHASHSEED'] = 42 # doctest: +SKIP + >>> os.environ['PYTHONHASHSEED'] = '42' # doctest: +SKIP Or from the command line using @@ -408,6 +431,7 @@ return not bool(ret) return not bool(_test(*paths, **kwargs)) + def _test(*paths, **kwargs): """ Internal function that actually runs the tests. @@ -430,7 +454,8 @@ seed = random.randrange(100000000) timeout = kwargs.get("timeout", False) slow = kwargs.get("slow", False) - r = PyTestReporter(verbose=verbose, tb=tb, colors=colors, force_colors=force_colors) + r = PyTestReporter(verbose=verbose, tb=tb, colors=colors, + force_colors=force_colors) t = SymPyTests(r, kw, post_mortem, seed) # Disable warnings for external modules @@ -438,6 +463,10 @@ sympy.external.importtools.WARN_OLD_VERSION = False sympy.external.importtools.WARN_NOT_INSTALLED = False + # Show deprecation warnings + import warnings + warnings.simplefilter("error", SymPyDeprecationWarning) + test_files = t.get_test_files('sympy') if len(paths) == 0: @@ -455,6 +484,7 @@ return int(not t.test(sort=sort, timeout=timeout, slow=slow)) + def doctest(*paths, **kwargs): """ Runs doctests in all \*.py files in the sympy directory which match @@ -501,6 +531,7 @@ return not bool(ret) return not bool(_doctest(*paths, **kwargs)) + def _doctest(*paths, **kwargs): """ Internal function that actually runs the doctests. @@ -515,26 +546,65 @@ verbose = kwargs.get("verbose", False) blacklist = kwargs.get("blacklist", []) blacklist.extend([ - "doc/src/modules/mpmath", # needs to be fixed upstream - "sympy/mpmath", # needs to be fixed upstream - "doc/src/modules/plotting.rst", # generates live plots - # "sympy/plotting", # generates live plots - "sympy/plotting/pygletplot", # generates live plots - "sympy/statistics", # prints a deprecation - "doc/src/modules/statistics.rst", # warning (this module - # is deprecated) - "sympy/utilities/compilef.py", # needs tcc - "sympy/utilities/autowrap.py", # needs installed compiler - "sympy/galgebra/GA.py", # needs numpy - "sympy/galgebra/latex_ex.py", # needs numpy - "sympy/conftest.py", # needs py.test - "sympy/utilities/benchmarking.py", # needs py.test - "examples/advanced/autowrap_integrators.py", # needs numpy - "examples/advanced/autowrap_ufuncify.py", # needs numpy - "examples/intermediate/mplot2d.py", # needs numpy and matplotlib - "examples/intermediate/mplot3d.py", # needs numpy and matplotlib - "examples/intermediate/sample.py", # needs numpy - ]) + "doc/src/modules/mpmath", # needs to be fixed upstream + "sympy/mpmath", # needs to be fixed upstream + "doc/src/modules/plotting.rst", # generates live plots + "sympy/statistics", # prints a deprecation + "doc/src/modules/statistics.rst", # warning (the module is deprecated) + "sympy/utilities/compilef.py" # needs tcc + ]) + + if import_module('numpy') is None: + blacklist.extend([ + "sympy/galgebra/GA.py", + "sympy/galgebra/latex_ex.py", + "sympy/plotting/experimental_lambdify.py", + "sympy/plotting/plot_implicit.py", + "examples/advanced/autowrap_integrators.py", + "examples/advanced/autowrap_ufuncify.py", + "examples/intermediate/sample.py", + "examples/intermediate/mplot2d.py", + "examples/intermediate/mplot3d.py" + ]) + else: + if import_module('matplotlib') is None: + blacklist.extend([ + "examples/intermediate/mplot2d.py", + "examples/intermediate/mplot3d.py" + ]) + else: + # don't display matplotlib windows + from sympy.plotting.plot import unset_show + unset_show() + + # can be removed once a fix for Issue 3696 is merged + blacklist.extend(["sympy/galgebra/latex_ex.py"]) + + if import_module('pyglet') is None: + blacklist.extend(["sympy/plotting/pygletplot"]) + + # disabled because of doctest failures in asmeurer's bot + blacklist.extend([ + "sympy/galgebra/GA.py", + "sympy/utilities/autowrap.py", + "examples/advanced/autowrap_integrators.py", + "examples/advanced/autowrap_ufuncify.py" + ]) + + # pytest = import_module('pytest') + # py = import_module('py') + # if py is None or pytest is None: + # blacklist.extend([ + # "sympy/conftest.py", + # "sympy/utilities/benchmarking.py" + # ]) + + # blacklist these modules until issue 1741 is resolved + blacklist.extend([ + "sympy/conftest.py", + "sympy/utilities/benchmarking.py" + ]) + blacklist = convert_to_native_paths(blacklist) # Disable warnings for external modules @@ -542,6 +612,10 @@ sympy.external.importtools.WARN_OLD_VERSION = False sympy.external.importtools.WARN_NOT_INSTALLED = False + # Show deprecation warnings + import warnings + warnings.simplefilter("error", SymPyDeprecationWarning) + r = PyTestReporter(verbose) t = SymPyDocTests(r, normal) @@ -549,7 +623,7 @@ test_files.extend(t.get_test_files('examples', init_only=False)) not_blacklisted = [f for f in test_files - if not any(b in f for b in blacklist)] + if not any(b in f for b in blacklist)] if len(paths) == 0: t._testfiles.extend(not_blacklisted) else: @@ -583,7 +657,7 @@ test_files.sort() not_blacklisted = [f for f in test_files - if not any(b in f for b in blacklist)] + if not any(b in f for b in blacklist)] if len(paths) == 0: matched = not_blacklisted @@ -592,7 +666,7 @@ # Paths were already made native in *py tests so don't repeat here. # There's no chance of having a *py file slip through since we # only have *rst files in test_files. - matched = [] + matched = [] for f in not_blacklisted: basename = os.path.basename(f) for p in paths: @@ -607,11 +681,13 @@ continue old_displayhook = sys.displayhook try: - # out = pdoctest.testfile(rst_file, module_relative=False, encoding='utf-8', + # out = pdoctest.testfile( + # rst_file, module_relative=False, encoding='utf-8', # optionflags=pdoctest.ELLIPSIS | pdoctest.NORMALIZE_WHITESPACE) - out = sympytestfile(rst_file, module_relative=False, encoding='utf-8', - optionflags=pdoctest.ELLIPSIS | pdoctest.NORMALIZE_WHITESPACE \ - | pdoctest.IGNORE_EXCEPTION_DETAIL) + out = sympytestfile( + rst_file, module_relative=False, encoding='utf-8', + optionflags=pdoctest.ELLIPSIS | pdoctest.NORMALIZE_WHITESPACE | + pdoctest.IGNORE_EXCEPTION_DETAIL) finally: # make sure we return to the original displayhook in case some # doctest has changed that @@ -630,11 +706,13 @@ print() # use as the id, everything past the first 'sympy' file_id = rst_file[rst_file.find('sympy') + len('sympy') + 1:] - print(file_id, end=' ') # get at least the name out so it is know who is being tested - wid = r.terminal_width - len(file_id) - 1 #update width + print(file_id, end=' ') + # get at least the name out so it is know who is being tested + wid = r.terminal_width - len(file_id) - 1 # update width test_file = '[%s]' % (tested) report = '[%s]' % (rstfailed or 'OK') - print(''.join([test_file,' '*(wid-len(test_file)-len(report)), report])) + print(''.join( + [test_file, ' '*(wid - len(test_file) - len(report)), report])) # the doctests for *py will have printed this message already if there was # a failure, so now only print it if there was intervening reporting by @@ -647,12 +725,13 @@ # The Python 2.5 doctest runner uses a tuple, but in 2.6+, it uses a namedtuple # (which doesn't exist in 2.5-) -if sys.version_info[:2] > (2,5): +if sys.version_info[:2] > (2, 5): from collections import namedtuple SymPyTestResults = namedtuple('TestResults', 'failed attempted') else: SymPyTestResults = lambda a, b: (a, b) + def sympytestfile(filename, module_relative=True, name=None, package=None, globs=None, verbose=None, report=True, optionflags=0, extraglobs=None, raise_on_error=False, @@ -739,11 +818,13 @@ # Relativize the path if not IS_PYTHON_3: - text, filename = pdoctest._load_testfile(filename, package, module_relative) + text, filename = pdoctest._load_testfile( + filename, package, module_relative) if encoding is not None: text = text.decode(encoding) else: - text, filename = pdoctest._load_testfile(filename, package, module_relative, encoding) + text, filename = pdoctest._load_testfile( + filename, package, module_relative, encoding) # If no name was given, then use the file's name. if name is None: @@ -763,10 +844,11 @@ runner = pdoctest.DebugRunner(verbose=verbose, optionflags=optionflags) else: runner = SymPyDocTestRunner(verbose=verbose, optionflags=optionflags) + runner._checker = SymPyOutputChecker() # Read the file, convert it to a test, and run it. test = parser.get_doctest(text, globs, name, filename, 0) - runner.run(test) + runner.run(test, compileflags=future_flags) if report: runner.summarize() @@ -778,10 +860,11 @@ return SymPyTestResults(runner.failures, runner.tries) + class SymPyTests(object): def __init__(self, reporter, kw="", post_mortem=False, - seed=random.random()): + seed=None): self._post_mortem = post_mortem self._kw = kw self._count = 0 @@ -789,7 +872,7 @@ self._reporter = reporter self._reporter.root_dir(self._root_dir) self._testfiles = [] - self._seed = seed + self._seed = seed if seed is not None else random.random() def test(self, sort=False, timeout=False, slow=False): """ @@ -816,7 +899,7 @@ def test_file(self, filename, sort=True, timeout=False, slow=False): clear_cache() self._count += 1 - gl = {'__file__':filename} + gl = {'__file__': filename} random.seed(self._seed) try: if IS_PYTHON_3: @@ -835,8 +918,8 @@ if "XFAIL" in gl: pytestfile = inspect.getsourcefile(gl["XFAIL"]) pytestfile2 = "" - if "SLOW" in gl: - pytestfile2 = inspect.getsourcefile(gl["SLOW"]) + if "slow" in gl: + pytestfile2 = inspect.getsourcefile(gl["slow"]) disabled = gl.get("disabled", False) if disabled: funcs = [] @@ -845,11 +928,10 @@ # that are defined in the testing file or in the file where # is defined the XFAIL decorator funcs = [gl[f] for f in list(gl.keys()) if f.startswith("test_") and - (inspect.isfunction(gl[f]) - or inspect.ismethod(gl[f])) and - (inspect.getsourcefile(gl[f]) == filename or - inspect.getsourcefile(gl[f]) == pytestfile or - inspect.getsourcefile(gl[f]) == pytestfile2)] + (inspect.isfunction(gl[f]) or inspect.ismethod(gl[f])) and + (inspect.getsourcefile(gl[f]) == filename or + inspect.getsourcefile(gl[f]) == pytestfile or + inspect.getsourcefile(gl[f]) == pytestfile2)] if slow: funcs = [f for f in funcs if getattr(f, '_slow', False)] # Sorting of XFAILed functions isn't fixed yet :-( @@ -893,7 +975,7 @@ raise except Exception: if timeout: - signal.alarm(0) # Disable the alarm. It could not be handled before. + signal.alarm(0) # Disable the alarm. It could not be handled before. t, v, tr = sys.exc_info() if t is AssertionError: self._reporter.test_fail((t, v, tr)) @@ -914,13 +996,13 @@ self._reporter.leaving_filename() def _timeout(self, function, timeout): - def callback(x,y): + def callback(x, y): signal.alarm(0) raise Skipped("Timeout") signal.signal(signal.SIGALRM, callback) - signal.alarm(timeout) # Set an alarm with a given timeout + signal.alarm(timeout) # Set an alarm with a given timeout function() - signal.alarm(0) # Disable the alarm + signal.alarm(0) # Disable the alarm def matches(self, x): """ @@ -932,7 +1014,7 @@ return True return x.__name__.find(self._kw) != -1 - def get_test_files(self, dir, pat = 'test_*.py'): + def get_test_files(self, dir, pat='test_*.py'): """ Returns the list of test_*.py (default) files at or below directory ``dir`` relative to the sympy home directory. @@ -945,6 +1027,7 @@ return [sys_normcase(gi) for gi in g] + class SymPyDocTests(object): def __init__(self, reporter, normal): @@ -975,7 +1058,7 @@ from io import StringIO - rel_name = filename[len(self._root_dir)+1:] + rel_name = filename[len(self._root_dir) + 1:] dirname, file = os.path.split(filename) module = rel_name.replace(os.sep, '.')[:-3] @@ -983,7 +1066,7 @@ # Examples files do not have __init__.py files, # So we have to temporarily extend sys.path to import them sys.path.insert(0, dirname) - module = file[:-3] # remove ".py" + module = file[:-3] # remove ".py" setup_pprint() try: module = pdoctest._normalize_module(module) @@ -1010,8 +1093,17 @@ self._reporter.entering_filename(filename, len(tests)) for test in tests: assert len(test.examples) != 0 - runner = SymPyDocTestRunner(optionflags=pdoctest.ELLIPSIS | \ - pdoctest.NORMALIZE_WHITESPACE | pdoctest.IGNORE_EXCEPTION_DETAIL) + + # check if there are external dependencies which need to be met + if '_doctest_depends_on' in test.globs: + if not self._process_dependencies(test.globs['_doctest_depends_on']): + self._reporter.test_skip() + continue + + runner = SymPyDocTestRunner(optionflags=pdoctest.ELLIPSIS | + pdoctest.NORMALIZE_WHITESPACE | + pdoctest.IGNORE_EXCEPTION_DETAIL) + runner._checker = SymPyOutputChecker() old = sys.stdout new = StringIO() sys.stdout = new @@ -1027,7 +1119,8 @@ # comes by default with a "from sympy import *" #exec('from sympy import *') in test.globs try: - f, t = runner.run(test, out=new.write, clear_globs=False) + f, t = runner.run(test, compileflags=future_flags, + out=new.write, clear_globs=False) except KeyboardInterrupt: raise finally: @@ -1071,6 +1164,93 @@ return [sys_normcase(gi) for gi in g] + def _process_dependencies(self, deps): + """ + Returns ``False`` if some dependencies are not met and the test should be + skipped otherwise returns ``True``. + """ + executables = deps.get('exe', None) + moduledeps = deps.get('modules', None) + viewers = deps.get('disable_viewers', None) + pyglet = deps.get('pyglet', None) + + # print deps + + if executables is not None: + for ex in executables: + found = find_executable(ex) + # print "EXE %s found %s" %(ex, found) + if found is None: + return False + if moduledeps is not None: + for extmod in moduledeps: + if extmod == 'matplotlib': + matplotlib = import_module( + 'matplotlib', + __import__kwargs={'fromlist': + ['pyplot', 'cm', 'collections']}, + min_module_version='1.0.0', catch=(RuntimeError,)) + if matplotlib is not None: + pass + # print "EXTMODULE matplotlib version %s found" % \ + # matplotlib.__version__ + else: + # print "EXTMODULE matplotlib > 1.0.0 not found" + return False + else: + # TODO min version support + mod = import_module(extmod) + if mod is not None: + version = "unknown" + if hasattr(mod, '__version__'): + version = mod.__version__ + # print "EXTMODULE %s version %s found" %(extmod, version) + else: + # print "EXTMODULE %s not found" %(extmod) + return False + if viewers is not None: + import tempfile + tempdir = tempfile.mkdtemp() + os.environ['PATH'] = '%s:%s' % (tempdir, os.environ['PATH']) + + vw = '#!/usr/bin/env python3\n' \ + 'import sys\n' \ + 'if len(sys.argv) <= 1:\n' \ + ' exit("wrong number of args")\n' + + for viewer in viewers: + with open(os.path.join(tempdir, viewer), 'w') as fh: + fh.write(vw) + + # make the file executable + os.chmod(os.path.join(tempdir, viewer), + stat.S_IREAD | stat.S_IWRITE | stat.S_IXUSR) + if pyglet: + # monkey-patch pyglet s.t. it does not open a window during + # doctesting + import pyglet + class DummyWindow(object): + def __init__(self, *args, **kwargs): + self.has_exit=True + self.width = 600 + self.height = 400 + + def set_vsync(self, x): + pass + + def switch_to(self): + pass + + def push_handlers(self, x): + pass + + def close(self): + pass + + pyglet.window.Window = DummyWindow + + return True + class SymPyDocTestFinder(DocTestFinder): """ A class used to extract the DocTests that are relevant to a given @@ -1110,31 +1290,34 @@ if test is not None: tests.append(test) + if not self._recurse: + return + # Look for tests in a module's contained objects. - if inspect.ismodule(obj) and self._recurse: + if inspect.ismodule(obj): for rawname, val in list(obj.__dict__.items()): # Recurse to functions & classes. if inspect.isfunction(val) or inspect.isclass(val): - in_module = self._from_module(module, val) - if not in_module: - # double check in case this function is decorated - # and just appears to come from a different module. - pat = r'\s*(def|class)\s+%s\s*\(' % rawname - PAT = pre.compile(pat) - in_module = any(PAT.match(line) for line in source_lines) - if in_module: - try: - valname = '%s.%s' % (name, rawname) - self._find(tests, val, valname, module, source_lines, globs, seen) - except KeyboardInterrupt: - raise - except ValueError as msg: - raise - except Exception: - pass + # Make sure we don't run doctests functions or classes + # from different modules + if val.__module__ != module.__name__: + continue + + assert self._from_module(module, val), \ + "%s is not in module %s (rawname %s)" % (val, module, rawname) + + try: + valname = '%s.%s' % (name, rawname) + self._find(tests, val, valname, module, + source_lines, globs, seen) + except KeyboardInterrupt: + raise + except ValueError: + raise + except Exception: + pass - # Look for tests in a module's __test__ dictionary. - if inspect.ismodule(obj) and self._recurse: + # Look for tests in a module's __test__ dictionary. for valname, val in list(getattr(obj, '__test__', {}).items()): if not isinstance(valname, str): raise ValueError("SymPyDocTestFinder.find: __test__ keys " @@ -1152,7 +1335,7 @@ globs, seen) # Look for tests in a class's contained objects. - if inspect.isclass(obj) and self._recurse: + if inspect.isclass(obj): for valname, val in list(obj.__dict__.items()): # Special handling for staticmethod/classmethod. if isinstance(val, staticmethod): @@ -1162,28 +1345,77 @@ # Recurse to methods, properties, and nested classes. if (inspect.isfunction(val) or - inspect.isclass(val) or - isinstance(val, property)): - in_module = self._from_module(module, val) - if not in_module: - # "double check" again - pat = r'\s*(def|class)\s+%s\s*\(' % valname - PAT = pre.compile(pat) - in_module = any(PAT.match(line) for line in source_lines) - if in_module: - valname = '%s.%s' % (name, valname) - self._find(tests, val, valname, module, source_lines, - globs, seen) + inspect.isclass(val) or + isinstance(val, property)): + # Make sure we don't run doctests functions or classes + # from different modules + if isinstance(val, property): + if val.fget.__module__ != module.__name__: + continue + else: + if val.__module__ != module.__name__: + continue + + assert self._from_module(module, val), \ + "%s is not in module %s (valname %s)" % (val, module, valname) + + valname = '%s.%s' % (name, valname) + self._find(tests, val, valname, module, source_lines, + globs, seen) + + def _from_module(self, module, object): + """ + Return true if the given object is defined in the given + module. + + This is a 1 to 1 copy of _from_module function from the python 2.7.3 + doctest module. It is needed because the doctest module shipped with + py 2.5 is broken (see PR 1969). + + This function should be removed once we drop support for python 2.5. + + """ + if module is None: + return True + elif inspect.getmodule(object) is not None: + return module is inspect.getmodule(object) + elif inspect.isfunction(object): + return module.__dict__ is object.__globals__ + elif inspect.isclass(object): + return module.__name__ == object.__module__ + elif hasattr(object, '__module__'): + return module.__name__ == object.__module__ + elif isinstance(object, property): + return True # [XX] no way not be sure. + else: + raise ValueError("object must be a class or function") def _get_test(self, obj, name, module, globs, source_lines): """ Return a DocTest for the given object, if it defines a docstring; otherwise, return None. """ + + lineno = None + # Extract the object's docstring. If it doesn't have one, # then return None (no test for this object). if isinstance(obj, str): + # obj is a string in the case for objects in the polys package. + # Note that source_lines is a binary string (compiled polys + # modules), which can't be handled by _find_lineno so determine + # the line number here. + docstring = obj + + matches = re.findall("line \d+", name) + assert len(matches) == 1, \ + "string '%s' does not contain lineno " % name + + # NOTE: this is not the exact linenumber but its better than no + # lineno ;) + lineno = int(matches[0][5:]) + else: try: if obj.__doc__ is None: @@ -1195,25 +1427,25 @@ except (TypeError, AttributeError): docstring = '' - # Find the docstring's location in the file. - lineno = self._find_lineno(obj, source_lines) - - if lineno is None: - # if None, then _find_lineno couldn't find the docstring. - # But IT IS STILL THERE. Likely it was decorated or something - # (i.e., @property docstrings have lineno == None) - # TODO: Write our own _find_lineno that is smarter in this regard - # Until then, just give it a dummy lineno. This is just used for - # sorting the tests, so the only bad effect is that they will appear - # last instead of the order that they really are in the file. - # lineno is also used to report the offending line of a failing - # doctest, which is another reason to fix this. See issue 1947. - lineno = 0 - # Don't bother if the docstring is empty. if self._exclude_empty and not docstring: return None + # check that properties have a docstring because _find_lineno + # assumes it + if isinstance(obj, property): + if obj.fget.__doc__ is None: + return None + + # Find the docstring's location in the file. + if lineno is None: + # handling of properties is not implemented in _find_lineno so do + # it here + tobj = obj if not isinstance(obj, property) else obj.fget + lineno = self._find_lineno(tobj, source_lines) + + assert lineno is not None + # Return a DocTest for this object. if module is None: filename = None @@ -1221,9 +1453,16 @@ filename = getattr(module, '__file__', module.__name__) if filename[-4:] in (".pyc", ".pyo"): filename = filename[:-1] + + if hasattr(obj, '_doctest_depends_on'): + globs['_doctest_depends_on'] = obj._doctest_depends_on + else: + globs['_doctest_depends_on'] = {} + return self._parser.get_doctest(docstring, globs, name, filename, lineno) + class SymPyDocTestRunner(DocTestRunner): """ A class used to run DocTest test cases, and accumulate statistics. @@ -1298,18 +1537,119 @@ SymPyDocTestRunner._SymPyDocTestRunner__record_outcome = \ DocTestRunner._DocTestRunner__record_outcome + +class SymPyOutputChecker(pdoctest.OutputChecker): + """ + Compared to the OutputChecker from the stdlib our OutputChecker class + supports numerical comparison of floats occuring in the output of the + doctest examples + """ + + def __init__(self): + # NOTE OutputChecker is an old-style class with no __init__ method, + # so we can't call the base class version of __init__ here + + got_floats = r'(\d+\.\d*|\.\d+)' + + # floats in the 'want' string may contain ellipses + want_floats = got_floats + r'(\.{3})?' + + front_sep = r'\s|\+|\-|\*|,' + back_sep = front_sep + r'|j|e' + + fbeg = r'^%s(?=%s|$)' % (got_floats, back_sep) + fmidend = r'(?<=%s)%s(?=%s|$)' % (front_sep, got_floats, back_sep) + self.num_got_rgx = re.compile(r'(%s|%s)' %(fbeg, fmidend)) + + fbeg = r'^%s(?=%s|$)' % (want_floats, back_sep) + fmidend = r'(?<=%s)%s(?=%s|$)' % (front_sep, want_floats, back_sep) + self.num_want_rgx = re.compile(r'(%s|%s)' %(fbeg, fmidend)) + + def check_output(self, want, got, optionflags): + """ + Return True iff the actual output from an example (`got`) + matches the expected output (`want`). These strings are + always considered to match if they are identical; but + depending on what option flags the test runner is using, + several non-exact match types are also possible. See the + documentation for `TestRunner` for more information about + option flags. + """ + # Handle the common case first, for efficiency: + # if they're string-identical, always return true. + if got == want: + return True + + # TODO parse integers as well ? + # Parse floats and compare them. If some of the parsed floats contain + # ellipses, skip the comparison. + matches = self.num_got_rgx.finditer(got) + numbers_got = [match.group(1) for match in matches] # list of strs + matches = self.num_want_rgx.finditer(want) + numbers_want = [match.group(1) for match in matches] # list of strs + if len(numbers_got) != len(numbers_want): + return False + + if len(numbers_got) > 0: + nw_ = [] + for ng, nw in zip(numbers_got, numbers_want): + if '...' in nw: + nw_.append(ng) + continue + else: + nw_.append(nw) + + if abs(float(ng)-float(nw)) > 1e-5: + return False + + got = self.num_got_rgx.sub(r'%s', got) + got = got % tuple(nw_) + + # can be used as a special sequence to signify a + # blank line, unless the DONT_ACCEPT_BLANKLINE flag is used. + if not (optionflags & pdoctest.DONT_ACCEPT_BLANKLINE): + # Replace in want with a blank line. + want = re.sub('(?m)^%s\s*?$' % re.escape(pdoctest.BLANKLINE_MARKER), + '', want) + # If a line in got contains only spaces, then remove the + # spaces. + got = re.sub('(?m)^\s*?$', '', got) + if got == want: + return True + + # This flag causes doctest to ignore any differences in the + # contents of whitespace strings. Note that this can be used + # in conjunction with the ELLIPSIS flag. + if optionflags & pdoctest.NORMALIZE_WHITESPACE: + got = ' '.join(got.split()) + want = ' '.join(want.split()) + if got == want: + return True + + # The ELLIPSIS flag says to let the sequence "..." in `want` + # match any substring in `got`. + if optionflags & pdoctest.ELLIPSIS: + if pdoctest._ellipsis_match(want, got): + return True + + # We didn't find any match; return false. + return False + + class Reporter(object): """ Parent class for all reporters. """ pass + class PyTestReporter(Reporter): """ Py.test like reporter. Should produce output identical to py.test. """ - def __init__(self, verbose=False, tb="short", colors=True, force_colors=False): + def __init__(self, verbose=False, tb="short", colors=True, + force_colors=False): self._verbose = verbose self._tb_style = tb self._colors = colors @@ -1341,7 +1681,8 @@ if sys.platform == "win32": # Windows support is based on: # - # http://code.activestate.com/recipes/440694-determine-size-of-console-window-on-windows/ + # http://code.activestate.com/recipes/ + # 440694-determine-size-of-console-window-on-windows/ from ctypes import windll, create_string_buffer @@ -1351,16 +1692,19 @@ if res: import struct - (_, _, _, _, _, left, _, right, _, _, _) = struct.unpack("hhhhHhhhhhh", csbi.raw) + (_, _, _, _, _, left, _, right, _, _, _) = \ + struct.unpack("hhhhHhhhhhh", csbi.raw) return right - left else: return self._default_width if hasattr(sys.stdout, 'isatty') and not sys.stdout.isatty(): - return self._default_width # leave PIPEs alone + return self._default_width # leave PIPEs alone try: - process = subprocess.Popen(['stty', '-a'], stdout=subprocess.PIPE, stderr=subprocess.PIPE) + process = subprocess.Popen(['stty', '-a'], + stdout=subprocess.PIPE, + stderr=subprocess.PIPE) stdout = process.stdout.read() if sys.version_info[0] > 2: stdout = stdout.decode("utf-8") @@ -1373,8 +1717,8 @@ # 2) OS X -> 80 columns # 3) Solaris -> columns = 80 - re_linux = r"columns\s+(?P\d+);" - re_osx = r"(?P\d+)\s*columns;" + re_linux = r"columns\s+(?P\d+);" + re_osx = r"(?P\d+)\s*columns;" re_solaris = r"columns\s+=\s+(?P\d+);" for regex in (re_linux, re_osx, re_solaris): @@ -1395,7 +1739,8 @@ return width - def write(self, text, color="", align="left", width=None, force_colors=False): + def write(self, text, color="", align="left", width=None, + force_colors=False): """ Prints a text on the screen. @@ -1406,27 +1751,29 @@ color : choose from the colors below, "" means default color align : "left"/"right", "left" is a normal print, "right" is aligned on - the right-hand side of the screen, filled with spaces if necessary + the right-hand side of the screen, filled with spaces if + necessary width : the screen width """ color_templates = ( - ("Black" , "0;30"), - ("Red" , "0;31"), - ("Green" , "0;32"), - ("Brown" , "0;33"), - ("Blue" , "0;34"), - ("Purple" , "0;35"), - ("Cyan" , "0;36"), - ("LightGray" , "0;37"), - ("DarkGray" , "1;30"), - ("LightRed" , "1;31"), - ("LightGreen" , "1;32"), - ("Yellow" , "1;33"), - ("LightBlue" , "1;34"), - ("LightPurple" , "1;35"), - ("LightCyan" , "1;36"), - ("White" , "1;37"), ) + ("Black", "0;30"), + ("Red", "0;31"), + ("Green", "0;32"), + ("Brown", "0;33"), + ("Blue", "0;34"), + ("Purple", "0;35"), + ("Cyan", "0;36"), + ("LightGray", "0;37"), + ("DarkGray", "1;30"), + ("LightRed", "1;31"), + ("LightGreen", "1;32"), + ("Yellow", "1;33"), + ("LightBlue", "1;34"), + ("LightPurple", "1;35"), + ("LightCyan", "1;36"), + ("White", "1;37"), + ) colors = {} @@ -1439,12 +1786,13 @@ width = self.terminal_width if align == "right": - if self._write_pos+len(text) > width: + if self._write_pos + len(text) > width: # we don't fit on the current line, create a new line self.write("\n") - self.write(" "*(width-self._write_pos-len(text))) + self.write(" "*(width - self._write_pos - len(text))) - if not self._force_colors and hasattr(sys.stdout, 'isatty') and not sys.stdout.isatty(): + if not self._force_colors and hasattr(sys.stdout, 'isatty') and not \ + sys.stdout.isatty(): # the stdout is not a terminal, this for example happens if the # output is piped to less, e.g. "bin/test | less". In this case, # the terminal control sequences would be printed verbatim, so @@ -1464,18 +1812,20 @@ if IS_PYTHON_3 and IS_WINDOWS: text = text.encode('raw_unicode_escape').decode('utf8', 'ignore') elif IS_PYTHON_3 and not sys.stdout.encoding.lower().startswith('utf'): - text = text.encode(sys.stdout.encoding, 'backslashreplace').decode(sys.stdout.encoding) + text = text.encode(sys.stdout.encoding, 'backslashreplace' + ).decode(sys.stdout.encoding) if color == "": sys.stdout.write(text) else: - sys.stdout.write("%s%s%s" % (c_color % colors[color], text, c_normal)) + sys.stdout.write("%s%s%s" % + (c_color % colors[color], text, c_normal)) sys.stdout.flush() l = text.rfind("\n") if l == -1: self._write_pos += len(text) else: - self._write_pos = len(text)-l-1 + self._write_pos = len(text) - l - 1 self._line_wrap = self._write_pos >= width self._write_pos %= width @@ -1483,9 +1833,9 @@ width = self.terminal_width if text != "": text = " %s " % text - idx = (width-len(text)) // 2 - t = delim*idx + text + delim*(width-idx-len(text)) - self.write(t+"\n") + idx = (width - len(text)) // 2 + t = delim*idx + text + delim*(width - idx - len(text)) + self.write(t + "\n") def write_exception(self, e, val, tb): t = traceback.extract_tb(tb) @@ -1501,18 +1851,32 @@ executable = sys.executable v = tuple(sys.version_info) python_version = "%s.%s.%s-%s-%s" % v - self.write("executable: %s (%s)\n" % (executable, python_version)) + if v[:2] == (2, 5): # CPython2.5 doesn't have python_implementation + implementation = "CPython" + else: + implementation = platform.python_implementation() + if implementation == 'PyPy': + implementation += " %s.%s.%s-%s-%s" % sys.pypy_version_info + self.write("executable: %s (%s) [%s]\n" % + (executable, python_version, implementation)) from .misc import ARCH self.write("architecture: %s\n" % ARCH) from sympy.core.cache import USE_CACHE self.write("cache: %s\n" % USE_CACHE) - from sympy.polys.domains import GROUND_TYPES - self.write("ground types: %s\n" % GROUND_TYPES) + from sympy.core.compatibility import GROUND_TYPES, HAS_GMPY + version = '' + if GROUND_TYPES =='gmpy': + if HAS_GMPY == 1: + import gmpy + elif HAS_GMPY == 2: + import gmpy2 as gmpy + version = gmpy.version() + self.write("ground types: %s %s\n" % (GROUND_TYPES, version)) if seed is not None: self.write("random seed: %d\n" % seed) from .misc import HASH_RANDOMIZATION self.write("hash randomization: ") - hash_seed = os.getenv("PYTHONHASHSEED") + hash_seed = os.getenv("PYTHONHASHSEED") or '0' if HASH_RANDOMIZATION and (hash_seed == "random" or int(hash_seed)): self.write("on (PYTHONHASHSEED=%s)\n" % hash_seed) else: @@ -1526,6 +1890,7 @@ global text, linelen text = "tests finished: %d passed, " % self._passed linelen = len(text) + def add_text(mytext): global text, linelen """Break new text if too long.""" @@ -1549,7 +1914,6 @@ add_text("%d exceptions, " % len(self._exceptions)) add_text("in %.2f seconds" % (self._t_end - self._t_start)) - if len(self._xpassed) > 0: self.write_center("xpassed tests", "_") for e in self._xpassed: @@ -1589,13 +1953,13 @@ self.write_center(text) ok = len(self._failed) == 0 and len(self._exceptions) == 0 and \ - len(self._failed_doctest) == 0 + len(self._failed_doctest) == 0 if not ok: self.write("DO *NOT* COMMIT!\n") return ok def entering_filename(self, filename, n): - rel_name = filename[len(self._root_dir)+1:] + rel_name = filename[len(self._root_dir) + 1:] self._active_file = rel_name self._active_file_error = False self.write(rel_name) @@ -1614,7 +1978,7 @@ def entering_test(self, f): self._active_f = f if self._verbose: - self.write("\n"+f.__name__+" ") + self.write("\n" + f.__name__ + " ") def test_xfail(self): self._xfailed += 1 @@ -1647,20 +2011,25 @@ else: self.write(char, "Green") - def test_skip(self, v): - if sys.version_info[:2] < (2, 6): - message = getattr(v, 'message', '') - else: - message = str(v) - self._skipped += 1 + def test_skip(self, v=None): char = "s" - if message == "KeyboardInterrupt": char = "K" - elif message == "Timeout": char = "T" - elif message == "Slow": char = "w" + self._skipped += 1 + if v is not None: + if sys.version_info[:2] < (2, 6): + message = getattr(v, 'message', '') + else: + message = str(v) + if message == "KeyboardInterrupt": + char = "K" + elif message == "Timeout": + char = "T" + elif message == "Slow": + char = "w" self.write(char, "Blue") if self._verbose: self.write(" - ", "Blue") - self.write(message, "Blue") + if v is not None: + self.write(message, "Blue") def test_exception(self, exc_info): self._exceptions.append((self._active_file, self._active_f, exc_info)) @@ -1669,7 +2038,7 @@ def import_error(self, filename, exc_info): self._exceptions.append((filename, None, exc_info)) - rel_name = filename[len(self._root_dir)+1:] + rel_name = filename[len(self._root_dir) + 1:] self.write(rel_name) self.write("[?] Failed to import", "Red") self.write(" ") diff -Nru python3-sympy-0.7.2/sympy/utilities/source.py python3-sympy-0.7.3/sympy/utilities/source.py --- python3-sympy-0.7.2/sympy/utilities/source.py 2012-10-17 03:02:22.000000000 +0000 +++ python3-sympy-0.7.3/sympy/utilities/source.py 2013-07-13 17:53:32.000000000 +0000 @@ -6,6 +6,7 @@ from sympy.core.compatibility import callable import collections + def source(object): """ Prints the source code of a given object. @@ -13,6 +14,7 @@ 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. @@ -24,11 +26,14 @@ lookup_view = lookup_view mod_name, func_name = get_mod_func(lookup_view) if func_name != '': - lookup_view = getattr(__import__(mod_name, {}, {}, ['*']), func_name) + lookup_view = getattr( + __import__(mod_name, {}, {}, ['*']), func_name) if not isinstance(lookup_view, collections.Callable): - raise AttributeError("'%s.%s' is not a callable." % (mod_name, func_name)) + 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 @@ -42,4 +47,4 @@ dot = callback.rfind('.') if dot == -1: return callback, '' - return callback[:dot], callback[dot+1:] + return callback[:dot], callback[dot + 1:] diff -Nru python3-sympy-0.7.2/sympy/utilities/tests/test_autowrap.py python3-sympy-0.7.3/sympy/utilities/tests/test_autowrap.py --- python3-sympy-0.7.2/sympy/utilities/tests/test_autowrap.py 2012-10-17 03:02:22.000000000 +0000 +++ python3-sympy-0.7.3/sympy/utilities/tests/test_autowrap.py 2013-07-13 17:53:32.000000000 +0000 @@ -6,12 +6,13 @@ import shutil from io import StringIO -from sympy.utilities.autowrap import autowrap, binary_function, CythonCodeWrapper,\ - ufuncify +from sympy.utilities.autowrap import autowrap, binary_function, CythonCodeWrapper, \ + ufuncify from sympy.utilities.codegen import Routine, CCodeGen, CodeGenArgumentListError from sympy.utilities.pytest import raises from sympy.core import symbols, Eq + def get_string(dump_fn, routines, prefix="file", header=False, empty=False): """Wrapper for dump_fn. dump_fn writes its results to a stream object and this wrapper returns the contents of that stream as a string. This @@ -26,52 +27,56 @@ output.close() return source + def test_cython_wrapper_scalar_function(): - x,y,z = symbols('x,y,z') - expr = (x+y)*z + x, y, z = symbols('x,y,z') + expr = (x + y)*z routine = Routine("test", expr) code_gen = CythonCodeWrapper(CCodeGen()) source = get_string(code_gen.dump_pyx, [routine]) expected = ( - 'cdef extern from "file.h":\n' - ' double test(double x, double y, double z)\n' - 'def test_c(double x, double y, double z):\n' - ' return test(x, y, z)\n' + 'cdef extern from "file.h":\n' + ' double test(double x, double y, double z)\n' + 'def test_c(double x, double y, double z):\n' + ' return test(x, y, z)\n' ) assert source == expected + def test_cython_wrapper_outarg(): from sympy import Equality - x,y,z = symbols('x,y,z') + x, y, z = symbols('x,y,z') code_gen = CythonCodeWrapper(CCodeGen()) routine = Routine("test", Equality(z, x + y)) source = get_string(code_gen.dump_pyx, [routine]) expected = ( - 'cdef extern from "file.h":\n' - ' void test(double x, double y, double &z)\n' - 'def test_c(double x, double y):\n' - ' cdef double z\n' - ' test(x, y, z)\n' - ' return z\n' + 'cdef extern from "file.h":\n' + ' void test(double x, double y, double &z)\n' + 'def test_c(double x, double y):\n' + ' cdef double z\n' + ' test(x, y, z)\n' + ' return z\n' ) assert source == expected + def test_cython_wrapper_inoutarg(): from sympy import Equality - x,y,z = symbols('x,y,z') + x, y, z = symbols('x,y,z') code_gen = CythonCodeWrapper(CCodeGen()) routine = Routine("test", Equality(z, x + y + z)) source = get_string(code_gen.dump_pyx, [routine]) expected = ( - 'cdef extern from "file.h":\n' - ' void test(double x, double y, double &z)\n' - 'def test_c(double x, double y, double z):\n' - ' test(x, y, z)\n' - ' return z\n' + 'cdef extern from "file.h":\n' + ' void test(double x, double y, double &z)\n' + 'def test_c(double x, double y, double z):\n' + ' test(x, y, z)\n' + ' return z\n' ) assert source == expected + def test_autowrap_dummy(): x, y, z = symbols('x y z') @@ -90,21 +95,25 @@ assert f.args == "x, y, z" assert f.returns == "z" + def test_autowrap_args(): x, y, z = symbols('x y z') - raises(CodeGenArgumentListError, lambda: autowrap(Eq(z, x + y), backend='dummy', args=[x])) + raises(CodeGenArgumentListError, lambda: autowrap(Eq(z, x + y), + backend='dummy', args=[x])) f = autowrap(Eq(z, x + y), backend='dummy', args=[y, x]) assert f() == str(x + y) assert f.args == "y, x" assert f.returns == "z" - raises(CodeGenArgumentListError, lambda: autowrap(Eq(z, x + y + z), backend='dummy', args=[x, y])) + raises(CodeGenArgumentListError, lambda: autowrap(Eq(z, x + y + z), + backend='dummy', args=[x, y])) f = autowrap(Eq(z, x + y + z), backend='dummy', args=[y, x, z]) assert f() == str(x + y + z) assert f.args == "y, x, z" assert f.returns == "z" + def test_autowrap_store_files(): x, y = symbols('x y') tmp = tempfile.mkdtemp() @@ -115,11 +124,13 @@ finally: shutil.rmtree(tmp) + def test_binary_function(): x, y = symbols('x y') f = binary_function('f', x + y, backend='dummy') assert f._imp_() == str(x + y) + def test_ufuncify(): x, y = symbols('x y') f = ufuncify((x, y), x + y, backend='dummy') diff -Nru python3-sympy-0.7.2/sympy/utilities/tests/test_code_quality.py python3-sympy-0.7.3/sympy/utilities/tests/test_code_quality.py --- python3-sympy-0.7.2/sympy/utilities/tests/test_code_quality.py 2012-10-17 03:02:22.000000000 +0000 +++ python3-sympy-0.7.3/sympy/utilities/tests/test_code_quality.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,13 +1,11 @@ -from sympy.core.compatibility import reduce -from os import walk, sep, chdir, pardir -from os.path import split, join, abspath, exists +from os import walk, sep, pardir +from os.path import split, join, abspath, exists, isfile from glob import glob import re import random import sys -from functools import reduce # System path separator (usually slash or backslash) to be # used with excluded files, e.g. @@ -17,17 +15,12 @@ sepd = {"sep": sep} # path and sympy_path -PATH = reduce(join, [split(__file__)[0], pardir, pardir]) # go to sympy/ -SYMPY_PATH = abspath(PATH) +SYMPY_PATH = abspath(join(split(__file__)[0], pardir, pardir)) # go to sympy/ assert exists(SYMPY_PATH) -# Tests can be executed when examples are not installed -# (e.g. after "./setup.py install") so set the examples path -# to null so it will be skipped by the checker if it is not -# there. -EXAMPLES_PATH = abspath(reduce(join, [PATH, pardir, "examples"])) -if not exists(EXAMPLES_PATH): - EXAMPLES_PATH = "" +TOP_PATH = abspath(join(SYMPY_PATH, pardir)) +BIN_PATH = join(TOP_PATH, "bin") +EXAMPLES_PATH = join(TOP_PATH, "examples") IS_PYTHON_3 = (sys.version_info[0] == 3) @@ -41,24 +34,30 @@ message_old_raise = "File contains old-style raise statement: %s, line %s, \"%s\"" message_eof = "File does not end with a newline: %s, line %s" message_multi_eof = "File ends with more than 1 newline: %s, line %s" +message_test_suite_def = "Function should start with 'test_' or '_': %s, line %s" implicit_test_re = re.compile('^\s*(>>> )?(\.\.\. )?from .* import .*\*') -str_raise_re = re.compile(r'^\s*(>>> )?(\.\.\. )?raise(\s+(\'|\")|\s*(\(\s*)+(\'|\"))') -gen_raise_re = re.compile(r'^\s*(>>> )?(\.\.\. )?raise(\s+Exception|\s*(\(\s*)+Exception)') +str_raise_re = re.compile( + r'^\s*(>>> )?(\.\.\. )?raise(\s+(\'|\")|\s*(\(\s*)+(\'|\"))') +gen_raise_re = re.compile( + r'^\s*(>>> )?(\.\.\. )?raise(\s+Exception|\s*(\(\s*)+Exception)') old_raise_re = re.compile(r'^\s*(>>> )?(\.\.\. )?raise((\s*\(\s*)|\s+)\w+\s*,') +test_suite_def_re = re.compile('^def\s+(?!(_|test))[^(]*\(\s*\)\s*:$') + def tab_in_leading(s): """Returns True if there are tabs in the leading whitespace of a line, including the whitespace of docstring code samples.""" - n = len(s)-len(s.lstrip()) - if not s[n:n+3] in ['...', '>>>']: + n = len(s) - len(s.lstrip()) + if not s[n:n + 3] in ['...', '>>>']: check = s[:n] else: - smore = s[n+3:] - check = s[:n] + smore[:len(smore)-len(smore.lstrip())] + smore = s[n + 3:] + check = s[:n] + smore[:len(smore) - len(smore.lstrip())] return not (check.expandtabs() == check) -def check_directory_tree(base_path, file_check, exclusions=set()): + +def check_directory_tree(base_path, file_check, exclusions=set(), pattern="*.py"): """ Checks all files in the directory tree (with base_path as starting point) with the file_check function provided, skipping files that contain @@ -67,11 +66,25 @@ if not base_path: return for root, dirs, files in walk(base_path): - for fname in glob(join(root, "*.py")): - if [ex for ex in exclusions if ex in fname]: - continue + check_files(glob(join(root, pattern)), file_check, exclusions) + + +def check_files(files, file_check, exclusions=set(), pattern=None): + """ + Checks all files with the file_check function provided, skipping files + that contain any of the strings in the set provided by exclusions. + """ + if not files: + return + for fname in files: + if not exists(fname) or not isfile(fname): + continue + if [ex for ex in exclusions if ex in fname]: + continue + if pattern is None or re.match(pattern, fname): file_check(fname) + def test_files(): """ This test tests all files in sympy and checks that: @@ -81,6 +94,7 @@ o that the file ends with a single newline o there are no general or string exceptions o there are no old style raise statements + o name of arg-less test suite functions start with _ or test_ """ def test(fname): @@ -92,53 +106,78 @@ test_this_file(fname, test_file) def test_this_file(fname, test_file): - line = None # to flag the case where there were no lines in file + line = None # to flag the case where there were no lines in file for idx, line in enumerate(test_file): + if re.match(r'.*test_.*\.py$', fname) and test_suite_def_re.match(line): + assert False, message_test_suite_def % (fname, idx + 1) if line.endswith(" \n") or line.endswith("\t\n"): - assert False, message_space % (fname, idx+1) + assert False, message_space % (fname, idx + 1) if line.endswith("\r\n"): - assert False, message_carriage % (fname, idx+1) + assert False, message_carriage % (fname, idx + 1) if tab_in_leading(line): - assert False, message_tabs % (fname, idx+1) + assert False, message_tabs % (fname, idx + 1) if str_raise_re.search(line): - assert False, message_str_raise % (fname, idx+1) + assert False, message_str_raise % (fname, idx + 1) if gen_raise_re.search(line): - assert False, message_gen_raise % (fname, idx+1) + assert False, message_gen_raise % (fname, idx + 1) if (implicit_test_re.search(line) and - not [ex for ex in import_exclude if ex in fname]): - assert False, message_implicit % (fname, idx+1) + not [ex for ex in import_exclude if ex in fname]): + assert False, message_implicit % (fname, idx + 1) result = old_raise_re.search(line) if result is not None: - assert False, message_old_raise % (fname, idx+1, result.group(2)) + assert False, message_old_raise % ( + fname, idx + 1, result.group(2)) if line is not None: if line == '\n' and idx > 0: - assert False, message_multi_eof % (fname, idx+1) + assert False, message_multi_eof % (fname, idx + 1) elif not line.endswith('\n'): # eof newline check - assert False, message_eof % (fname, idx+1) + assert False, message_eof % (fname, idx + 1) + # Files to test at top level + top_level_files = [join(TOP_PATH, file) for file in [ + "build.py", + "setup.py", + "setupegg.py", + ]] + # Files to exclude from all tests exclude = set([ "%(sep)smpmath%(sep)s" % sepd, ]) + # Files to exclude from the implicit import test import_exclude = set([ - "%(sep)s__init__.py" % sepd, + # glob imports are allowed in top-level __init__.py: + "%(sep)ssympy%(sep)s__init__.py" % sepd, + # these __init__.py should be fixed: + "%(sep)smechanics%(sep)s__init__.py" % sepd, + "%(sep)squantum%(sep)s__init__.py" % sepd, + # interactive sympy executes ``from sympy import *``: "%(sep)sinteractive%(sep)ssession.py" % sepd, + # isympy executes ``from sympy import *``: + "%(sep)sbin%(sep)sisympy" % sepd, + # these two are import timing tests: + "%(sep)sbin%(sep)ssympy_time.py" % sepd, + "%(sep)sbin%(sep)ssympy_time_cache.py" % sepd, # Taken from Python stdlib: "%(sep)sparsing%(sep)ssympy_tokenize.py" % sepd, # these two should be fixed: - "%(sep)smpmath%(sep)s" % sepd, - "%(sep)splotting%(sep)s" % sepd, + "%(sep)splotting%(sep)spygletplot%(sep)s" % sepd, + "%(sep)splotting%(sep)stextplot.py" % sepd, ]) + check_files(top_level_files, test) + check_directory_tree(BIN_PATH, test, set(["~", ".pyc", ".sh"]), "*") check_directory_tree(SYMPY_PATH, test, exclude) check_directory_tree(EXAMPLES_PATH, test, exclude) + def _with_space(c): # return c with a random amount of leading space return random.randint(0, 10)*' ' + c + def test_raise_statement_regular_expression(): candidates_ok = [ "some text # raise Exception, 'text'", @@ -219,7 +258,7 @@ "... import sympy.something.something", "... from sympy import something", "... from sympy.somewhere import something", - ">> from sympy import *", # To allow 'fake' docstrings + ">> from sympy import *", # To allow 'fake' docstrings "# from sympy import *", "some text # from sympy import *", ] @@ -229,9 +268,28 @@ "from sympy.somewhere import *", ">>> from sympy.somewhere import *", "... from sympy import *", - "... from sympy.somwhere import *", + "... from sympy.somewhere import *", ] for c in candidates_ok: assert implicit_test_re.search(_with_space(c)) is None, c for c in candidates_fail: assert implicit_test_re.search(_with_space(c)) is not None, c + + +def test_test_suite_defs(): + candidates_ok = [ + " def foo():\n", + "def foo(arg):\n", + "def _foo():\n", + "def test_foo():\n", + ] + candidates_fail = [ + "def foo():\n", + "def foo() :\n", + "def foo( ):\n", + "def foo():\n", + ] + for c in candidates_ok: + assert test_suite_def_re.search(c) is None, c + for c in candidates_fail: + assert test_suite_def_re.search(c) is not None, c diff -Nru python3-sympy-0.7.2/sympy/utilities/tests/test_codegen.py python3-sympy-0.7.3/sympy/utilities/tests/test_codegen.py --- python3-sympy-0.7.2/sympy/utilities/tests/test_codegen.py 2012-10-17 03:02:22.000000000 +0000 +++ python3-sympy-0.7.3/sympy/utilities/tests/test_codegen.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,9 +1,10 @@ from io import StringIO from sympy.core import symbols, Eq, pi, Catalan, Lambda, Dummy -from sympy.utilities.codegen import CCodeGen, Routine, InputArgument, Result, \ - CodeGenError, FCodeGen, codegen, CodeGenArgumentListError, OutputArgument, \ - InOutArgument +from sympy import erf +from sympy.utilities.codegen import (CCodeGen, Routine, InputArgument, + CodeGenError, FCodeGen, codegen, CodeGenArgumentListError, OutputArgument, + InOutArgument) from sympy.utilities.pytest import raises from sympy.utilities.lambdify import implemented_function @@ -11,6 +12,7 @@ #FIXME: Fails due to circular import in with core # from sympy import codegen + def get_string(dump_fn, routines, prefix="file", header=False, empty=False): """Wrapper for dump_fn. dump_fn writes its results to a stream object and this wrapper returns the contents of that stream as a string. This @@ -25,18 +27,21 @@ output.close() return source + def test_Routine_argument_order(): a, x, y, z = symbols('a x y z') - expr = (x+y)*z - raises(CodeGenArgumentListError, lambda: Routine("test", expr, argument_sequence=[z, x])) - raises(CodeGenArgumentListError, lambda: Routine("test", Eq(a, expr), argument_sequence=[z, x, y])) + expr = (x + y)*z + raises(CodeGenArgumentListError, lambda: Routine("test", expr, + argument_sequence=[z, x])) + raises(CodeGenArgumentListError, lambda: Routine("test", Eq(a, + expr), argument_sequence=[z, x, y])) r = Routine('test', Eq(a, expr), argument_sequence=[z, x, a, y]) assert [ arg.name for arg in r.arguments ] == [z, x, a, y] assert [ type(arg) for arg in r.arguments ] == [ - InputArgument, InputArgument, OutputArgument, InputArgument ] + InputArgument, InputArgument, OutputArgument, InputArgument ] r = Routine('test', Eq(z, expr), argument_sequence=[z, x, y]) assert [ type(arg) for arg in r.arguments ] == [ - InOutArgument, InputArgument, InputArgument ] + InOutArgument, InputArgument, InputArgument ] from sympy.tensor import IndexedBase, Idx A, B = list(map(IndexedBase, ['A', 'B'])) @@ -51,13 +56,14 @@ source = get_string(code_gen.dump_c, []) assert source == "#include \"file.h\"\n#include \n" + def test_empty_c_code_with_comment(): code_gen = CCodeGen() source = get_string(code_gen.dump_c, [], header=True) assert source[:82] == ( - "/******************************************************************************\n *" - ) - # " Code generated with sympy 0.7.2 " + "/******************************************************************************\n *" + ) + # " Code generated with sympy 0.7.2-git " assert source[158:] == ( "*\n" " * *\n" " * See http://www.sympy.org/ for more information. *\n" @@ -68,14 +74,16 @@ "#include \n" ) + def test_empty_c_header(): code_gen = CCodeGen() source = get_string(code_gen.dump_h, []) assert source == "#ifndef PROJECT__FILE__H\n#define PROJECT__FILE__H\n#endif\n" + def test_simple_c_code(): - x,y,z = symbols('x,y,z') - expr = (x+y)*z + x, y, z = symbols('x,y,z') + expr = (x + y)*z routine = Routine("test", expr) code_gen = CCodeGen() source = get_string(code_gen.dump_c, [routine]) @@ -88,6 +96,7 @@ ) assert source == expected + def test_numbersymbol_c_code(): routine = Routine("test", pi**Catalan) code_gen = CCodeGen() @@ -102,8 +111,9 @@ ) assert source == expected + def test_c_code_argument_order(): - x,y,z = symbols('x,y,z') + x, y, z = symbols('x,y,z') expr = x + y routine = Routine("test", expr, argument_sequence=[z, x, y]) code_gen = CCodeGen() @@ -117,9 +127,10 @@ ) assert source == expected + def test_simple_c_header(): - x,y,z = symbols('x,y,z') - expr = (x+y)*z + x, y, z = symbols('x,y,z') + expr = (x + y)*z routine = Routine("test", expr) code_gen = CCodeGen() source = get_string(code_gen.dump_h, [routine]) @@ -131,18 +142,19 @@ ) assert source == expected + def test_simple_c_codegen(): - x,y,z = symbols('x,y,z') - expr = (x+y)*z - result = codegen(("test", (x+y)*z), "C", "file", header=False, empty=False) + x, y, z = symbols('x,y,z') + expr = (x + y)*z + result = codegen(("test", expr), "C", "file", header=False, empty=False) expected = [ - ("file.c", + ("file.c", "#include \"file.h\"\n" "#include \n" "double test(double x, double y, double z) {\n" " return z*(x + y);\n" "}\n"), - ("file.h", + ("file.h", "#ifndef PROJECT__FILE__H\n" "#define PROJECT__FILE__H\n" "double test(double x, double y, double z);\n" @@ -150,24 +162,27 @@ ] assert result == expected + def test_multiple_results_c(): - x,y,z = symbols('x,y,z') - expr1 = (x+y)*z - expr2 = (x-y)*z + x, y, z = symbols('x,y,z') + expr1 = (x + y)*z + expr2 = (x - y)*z routine = Routine( "test", - [expr1,expr2] + [expr1, expr2] ) code_gen = CCodeGen() raises(CodeGenError, lambda: get_string(code_gen.dump_h, [routine])) + def test_no_results_c(): raises(ValueError, lambda: Routine("test", [])) + def test_ansi_math1_codegen(): # not included: log10 from sympy import (acos, asin, atan, ceiling, cos, cosh, floor, log, ln, - sin, sinh, sqrt, tan, tanh, N, Abs) + sin, sinh, sqrt, tan, tanh, Abs) x = symbols('x') name_expr = [ ("test_fabs", Abs(x)), @@ -219,12 +234,13 @@ 'double test_tanh(double x);\n#endif\n' ) + def test_ansi_math2_codegen(): # not included: frexp, ldexp, modf, fmod - from sympy import atan2, N + from sympy import atan2 x, y = symbols('x,y') name_expr = [ - ("test_atan2", atan2(x,y)), + ("test_atan2", atan2(x, y)), ("test_pow", x**y), ] result = codegen(name_expr, "C", "file", header=False, empty=False) @@ -242,12 +258,13 @@ '#endif\n' ) + def test_complicated_codegen(): - from sympy import sin, cos, tan, N - x,y,z = symbols('x,y,z') + from sympy import sin, cos, tan + x, y, z = symbols('x,y,z') name_expr = [ - ("test1", ((sin(x)+cos(y)+tan(z))**7).expand()), - ("test2", cos(cos(cos(cos(cos(cos(cos(cos(x+y+z))))))))), + ("test1", ((sin(x) + cos(y) + tan(z))**7).expand()), + ("test2", cos(cos(cos(cos(cos(cos(cos(cos(x + y + z))))))))), ] result = codegen(name_expr, "C", "file", header=False, empty=False) assert result[0][0] == "file.c" @@ -305,10 +322,11 @@ '#endif\n' ) + def test_loops_c(): from sympy.tensor import IndexedBase, Idx from sympy import symbols - n,m = symbols('n m', integer=True) + n, m = symbols('n m', integer=True) A = IndexedBase('A') x = IndexedBase('x') y = IndexedBase('y') @@ -316,35 +334,36 @@ j = Idx('j', n) (f1, code), (f2, interface) = codegen( - ('matrix_vector', Eq(y[i], A[i, j]*x[j])), "C", "file", header=False, empty=False) + ('matrix_vector', Eq(y[i], A[i, j]*x[j])), "C", "file", header=False, empty=False) assert f1 == 'file.c' expected = ( - '#include "file.h"\n' - '#include \n' - 'void matrix_vector(double *A, int m, int n, double *x, double *y) {\n' - ' for (int i=0; i\n' + 'void matrix_vector(double *A, int m, int n, double *x, double *y) {\n' + ' for (int i=0; i\n' - 'void test_dummies(int m_%(mno)i, double *x, double *y) {\n' - ' for (int i_%(ino)i=0; i_%(ino)i\n' + 'void test_dummies(int m_%(mno)i, double *x, double *y) {\n' + ' for (int i_%(ino)i=0; i_%(ino)i\n' - 'void matrix_vector(double *A, int m, int n, int o, int p, double *x, double *y) {\n' - ' for (int i=o; i<%(upperi)s; i++){\n' - ' y[i] = 0;\n' - ' }\n' - ' for (int i=o; i<%(upperi)s; i++){\n' - ' for (int j=0; j\n' + 'void matrix_vector(double *A, int m, int n, int o, int p, double *x, double *y) {\n' + ' for (int i=o; i<%(upperi)s; i++){\n' + ' y[i] = 0;\n' + ' }\n' + ' for (int i=o; i<%(upperi)s; i++){\n' + ' for (int j=0; j 2: @@ -155,14 +169,15 @@ from sympy.functions import (Piecewise, lowergamma, acosh, chebyshevu, chebyshevt, ln, chebyshevt_root, binomial, legendre, Heaviside, factorial, bernoulli, coth, tanh, assoc_legendre, sign, - arg, asin, DiracDelta, re, rf, Abs, uppergamma, binomial, sinh, Ylm, + arg, asin, DiracDelta, re, rf, Abs, uppergamma, binomial, sinh, Ynm, cos, cot, acos, acot, gamma, bell, hermite, harmonic, - LambertW, zeta, log, factorial, asinh, acoth, Zlm, + LambertW, zeta, log, factorial, asinh, acoth, Znm, cosh, dirichlet_eta, Eijk, loggamma, erf, ceiling, im, fibonacci, conjugate, tan, chebyshevu_root, floor, atanh, sqrt, RisingFactorial, sin, atan, ff, FallingFactorial, lucas, atan2, polygamma, exp) + def test_functions(): one_var = (acosh, ln, Heaviside, factorial, bernoulli, coth, tanh, sign, arg, asin, DiracDelta, re, Abs, sinh, cos, cot, acos, acot, @@ -173,7 +188,7 @@ atan2, polygamma, hermite, legendre, uppergamma) x, y, z = symbols("x,y,z") others = (chebyshevt_root, chebyshevu_root, Eijk(x, y, z), - Piecewise( (0, x<-1), (x**2, x<=1), (x**3, True)), + Piecewise( (0, x < -1), (x**2, x <= 1), (x**3, True)), assoc_legendre) for cls in one_var: check(cls) @@ -193,21 +208,24 @@ from sympy.geometry.line import Line, LinearEntity, Ray, Segment from sympy.geometry.polygon import Polygon, RegularPolygon, Triangle + def test_geometry(): - p1 = Point(1,2) - p2 = Point(2,3) - p3 = Point(0,0) - p4 = Point(0,1) - for c in (GeometryEntity, GeometryEntity(), Point, p1, Circle, Circle(p1,2), - Ellipse, Ellipse(p1,3,4), Line, Line(p1,p2), LinearEntity, - LinearEntity(p1,p2), Ray, Ray(p1,p2), Segment, Segment(p1,p2), - Polygon, Polygon(p1,p2,p3,p4), RegularPolygon, RegularPolygon(p1,4,5), - Triangle, Triangle(p1,p2,p3)): - check(c, check_attr = False) + p1 = Point(1, 2) + p2 = Point(2, 3) + p3 = Point(0, 0) + p4 = Point(0, 1) + for c in ( + GeometryEntity, GeometryEntity(), Point, p1, Circle, Circle(p1, 2), + Ellipse, Ellipse(p1, 3, 4), Line, Line(p1, p2), LinearEntity, + LinearEntity(p1, p2), Ray, Ray(p1, p2), Segment, Segment(p1, p2), + Polygon, Polygon(p1, p2, p3, p4), RegularPolygon, + RegularPolygon(p1, 4, 5), Triangle, Triangle(p1, p2, p3)): + check(c, check_attr=False) #================== integrals ==================== from sympy.integrals.integrals import Integral + def test_integrals(): x = Symbol("x") for c in (Integral, Integral(x)): @@ -216,20 +234,23 @@ #==================== logic ===================== from sympy.core.logic import Logic + def test_logic(): for c in (Logic, Logic(1)): check(c) #================== matrices ==================== -from sympy.matrices.matrices import Matrix, SparseMatrix +from sympy.matrices import Matrix, SparseMatrix + def test_matrices(): - for c in (Matrix, Matrix([1,2,3]), SparseMatrix, SparseMatrix([[1,2],[3,4]])): + for c in (Matrix, Matrix([1, 2, 3]), SparseMatrix, SparseMatrix([[1, 2], [3, 4]])): check(c) #================== ntheory ===================== from sympy.ntheory.generate import Sieve + def test_ntheory(): for c in (Sieve, Sieve()): check(c) @@ -238,6 +259,7 @@ from sympy.physics.paulialgebra import Pauli from sympy.physics.units import Unit + def test_physics(): for c in (Unit, Unit("meter", "m"), Pauli, Pauli(1)): check(c) @@ -245,6 +267,7 @@ #================== plotting ==================== # XXX: These tests are not complete, so XFAIL them + @XFAIL def test_plotting(): from sympy.plotting.color_scheme import ColorGradient, ColorScheme @@ -256,20 +279,22 @@ from sympy.plotting.plot_curve import PlotCurve from sympy.plotting.plot_interval import PlotInterval from sympy.plotting.plot_mode import PlotMode - from sympy.plotting.plot_modes import Cartesian2D, Cartesian3D, Cylindrical,\ + from sympy.plotting.plot_modes import Cartesian2D, Cartesian3D, Cylindrical, \ ParametricCurve2D, ParametricCurve3D, ParametricSurface, Polar, Spherical from sympy.plotting.plot_object import PlotObject from sympy.plotting.plot_surface import PlotSurface from sympy.plotting.plot_window import PlotWindow - for c in (ColorGradient, ColorGradient(0.2,0.4), ColorScheme, ManagedWindow, - ManagedWindow, Plot, ScreenShot, PlotAxes, PlotAxesBase, - PlotAxesFrame, PlotAxesOrdinate, PlotCamera, PlotController, - PlotCurve, PlotInterval, PlotMode, Cartesian2D, Cartesian3D, - Cylindrical, ParametricCurve2D, ParametricCurve3D, - ParametricSurface, Polar, Spherical, PlotObject, PlotSurface, - PlotWindow): + for c in ( + ColorGradient, ColorGradient(0.2, 0.4), ColorScheme, ManagedWindow, + ManagedWindow, Plot, ScreenShot, PlotAxes, PlotAxesBase, + PlotAxesFrame, PlotAxesOrdinate, PlotCamera, PlotController, + PlotCurve, PlotInterval, PlotMode, Cartesian2D, Cartesian3D, + Cylindrical, ParametricCurve2D, ParametricCurve3D, + ParametricSurface, Polar, Spherical, PlotObject, PlotSurface, + PlotWindow): check(c) + @XFAIL def test_plotting2(): from sympy.plotting.color_scheme import ColorGradient, ColorScheme @@ -281,13 +306,13 @@ from sympy.plotting.plot_curve import PlotCurve from sympy.plotting.plot_interval import PlotInterval from sympy.plotting.plot_mode import PlotMode - from sympy.plotting.plot_modes import Cartesian2D, Cartesian3D, Cylindrical,\ + from sympy.plotting.plot_modes import Cartesian2D, Cartesian3D, Cylindrical, \ ParametricCurve2D, ParametricCurve3D, ParametricSurface, Polar, Spherical from sympy.plotting.plot_object import PlotObject from sympy.plotting.plot_surface import PlotSurface from sympy.plotting.plot_window import PlotWindow check(ColorScheme("rainbow")) - check(Plot(1,visible=False)) + check(Plot(1, visible=False)) check(PlotAxes()) #================== polys ======================= @@ -297,34 +322,32 @@ from sympy.polys.domains import ( PythonIntegerRing, - SymPyIntegerRing, - SymPyRationalField, + PythonRationalField, PolynomialRing, FractionField, ExpressionDomain, ) + def test_polys(): x = Symbol("X") ZZ = PythonIntegerRing() - QQ = SymPyRationalField() + QQ = PythonRationalField() for c in (Poly, Poly(x, x)): check(c) - for c in (DMP, DMP([[ZZ(1)],[ZZ(2)],[ZZ(3)]], ZZ)): + for c in (DMP, DMP([[ZZ(1)], [ZZ(2)], [ZZ(3)]], ZZ)): check(c) - for c in (DMF, DMF(([ZZ(1),ZZ(2)], [ZZ(1),ZZ(3)]), ZZ)): + for c in (DMF, DMF(([ZZ(1), ZZ(2)], [ZZ(1), ZZ(3)]), ZZ)): check(c) - for c in (ANP, ANP([QQ(1),QQ(2)], [QQ(1),QQ(2),QQ(3)], QQ)): + for c in (ANP, ANP([QQ(1), QQ(2)], [QQ(1), QQ(2), QQ(3)], QQ)): check(c) for c in (PythonIntegerRing, PythonIntegerRing()): check(c) - for c in (SymPyIntegerRing, SymPyIntegerRing()): - check(c) - for c in (SymPyRationalField, SymPyRationalField()): + for c in (PythonRationalField, PythonRationalField()): check(c) for c in (PolynomialRing, PolynomialRing(ZZ, 'x', 'y')): @@ -335,12 +358,7 @@ for c in (ExpressionDomain, ExpressionDomain()): check(c) - from sympy.polys.domains import PythonRationalField - - for c in (PythonRationalField, PythonRationalField()): - check(c) - - from sympy.polys.domains import HAS_GMPY + from sympy.core.compatibility import HAS_GMPY if HAS_GMPY: from sympy.polys.domains import GMPYIntegerRing, GMPYRationalField @@ -364,16 +382,19 @@ from sympy.printing.printer import Printer from sympy.printing.python import PythonPrinter + def test_printing(): for c in (LatexPrinter, LatexPrinter(), MathMLPrinter, PrettyPrinter, prettyForm, stringPict, stringPict("a"), Printer, Printer(), PythonPrinter, PythonPrinter()): check(c) + @XFAIL def test_printing1(): check(MathMLPrinter()) + @XFAIL def test_printing2(): check(PrettyPrinter()) @@ -382,26 +403,18 @@ from sympy.series.limits import Limit from sympy.series.order import Order + def test_series(): e = Symbol("e") x = Symbol("x") for c in (Limit, Limit(e, x, 1), Order, Order(e)): check(c) -#================== statistics ================== -from sympy.statistics.distributions import ContinuousProbability, Normal, Sample, Uniform - -def test_statistics(): - x = Symbol("x") - y = Symbol("y") - for c in (ContinuousProbability, ContinuousProbability(), Normal, - Normal(x,y), Sample, Sample([1,3,4]), Uniform, Uniform(x,y)): - check(c) - #================== concrete ================== from sympy.concrete.products import Product from sympy.concrete.summations import Sum + def test_concrete(): x = Symbol("x") for c in (Product, Product(x, (x, 2, 4)), Sum, Sum(x, (x, 2, 4))): diff -Nru python3-sympy-0.7.2/sympy/utilities/tests/test_pytest.py python3-sympy-0.7.3/sympy/utilities/tests/test_pytest.py --- python3-sympy-0.7.2/sympy/utilities/tests/test_pytest.py 2012-10-17 03:02:22.000000000 +0000 +++ python3-sympy-0.7.3/sympy/utilities/tests/test_pytest.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,20 +1,24 @@ + from sympy.utilities.pytest import raises # Test callables -def test_expected_exception_is_silent(): + +def test_expected_exception_is_silent_callable(): def f(): raise ValueError() raises(ValueError, f) -def test_lack_of_exception_triggers_AssertionError(): + +def test_lack_of_exception_triggers_AssertionError_callable(): try: - raises(Exception, lambda: 1+1) + raises(Exception, lambda: 1 + 1) assert False except AssertionError as e: assert str(e) == "DID NOT RAISE" -def test_unexpected_exception_is_passed_through(): + +def test_unexpected_exception_is_passed_through_callable(): def f(): raise ValueError("some error message") try: @@ -23,40 +27,23 @@ except ValueError as e: assert str(e) == "some error message" -# Test compilable strings - -def test_expected_exception_is_silent(): - raises(ValueError, "raise ValueError()") - -def test_lack_of_exception_triggers_AssertionError(): - try: - raises(Exception, "1+1") - assert False - except AssertionError as e: - assert str(e) == "DID NOT RAISE" - -def test_unexpected_exception_is_passed_through(): - try: - raises(TypeError, 'raise ValueError("some error message")') - assert False - except ValueError as e: - assert str(e) == "some error message" - # Test with statement -def test_expected_exception_is_silent(): +def test_expected_exception_is_silent_with(): with raises(ValueError): raise ValueError() -def test_lack_of_exception_triggers_AssertionError(): + +def test_lack_of_exception_triggers_AssertionError_with(): try: with raises(Exception): - 1+1 + 1 + 1 assert False except AssertionError as e: assert str(e) == "DID NOT RAISE" -def test_unexpected_exception_is_passed_through(): + +def test_unexpected_exception_is_passed_through_with(): try: with raises(TypeError): raise ValueError("some error message") @@ -67,5 +54,6 @@ # Now we can use raises() instead of try/catch # to test that a specific exception class is raised + def test_second_argument_should_be_callable_or_string(): raises(TypeError, lambda: raises("irrelevant", 42)) diff -Nru python3-sympy-0.7.2/sympy/utilities/tests/test_source.py python3-sympy-0.7.3/sympy/utilities/tests/test_source.py --- python3-sympy-0.7.2/sympy/utilities/tests/test_source.py 2012-10-17 03:02:22.000000000 +0000 +++ python3-sympy-0.7.3/sympy/utilities/tests/test_source.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,7 +1,10 @@ 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') + assert get_mod_func( + 'sympy.core.basic.Basic') == ('sympy.core.basic', 'Basic') + def test_get_class(): _basic = get_class('sympy.core.basic.Basic') diff -Nru python3-sympy-0.7.2/sympy/utilities/tests/test_timeutils.py python3-sympy-0.7.3/sympy/utilities/tests/test_timeutils.py --- python3-sympy-0.7.2/sympy/utilities/tests/test_timeutils.py 1970-01-01 00:00:00.000000000 +0000 +++ python3-sympy-0.7.3/sympy/utilities/tests/test_timeutils.py 2013-07-13 17:53:32.000000000 +0000 @@ -0,0 +1,15 @@ +"""Tests for simple tools for timing functions' execution. """ + +import sys + +if sys.version_info[:2] <= (2, 5): + disabled = True + +from sympy.utilities.timeutils import timed + +def test_timed(): + result = timed(lambda: 1 + 1, limit=100000) + assert result[0] == 100000 and result[3] == "ns" + + result = timed("1 + 1", limit=100000) + assert result[0] == 100000 and result[3] == "ns" diff -Nru python3-sympy-0.7.2/sympy/utilities/timeutils.py python3-sympy-0.7.3/sympy/utilities/timeutils.py --- python3-sympy-0.7.2/sympy/utilities/timeutils.py 2012-10-17 03:02:22.000000000 +0000 +++ python3-sympy-0.7.3/sympy/utilities/timeutils.py 2013-07-13 17:53:32.000000000 +0000 @@ -1,20 +1,22 @@ -"""Simple tools for timing functions execution, when IPython is not - available. """ +"""Simple tools for timing functions' execution, when IPython is not available. """ -import timeit, math +import timeit +import math _scales = [1e0, 1e3, 1e6, 1e9] -_units = ['s', 'ms', '\u03bcs', 'ns'] +_units = ['s', 'ms', '\u03bcs', 'ns'] -def timed(func): - """Adaptively measure execution time of a function. """ - timer = timeit.Timer(func) +def timed(func, setup="pass", limit=None): + """Adaptively measure execution time of a function. """ + timer = timeit.Timer(func, setup=setup) repeat, number = 3, 1 for i in range(1, 10): if timer.timeit(number) >= 0.2: break + elif limit is not None and number >= limit: + break else: number *= 10 @@ -32,7 +34,6 @@ def __do_timings(): import os - from sympy.utilities.iterables import iterable res = os.getenv('SYMPY_TIMINGS', '') res = [x.strip() for x in res.split(',')] return set(res) @@ -40,16 +41,19 @@ _do_timings = __do_timings() _timestack = None + def _print_timestack(stack, level=1): print('-'*level, '%.2f %s%s' % (stack[2], stack[0], stack[3])) for s in stack[1]: - _print_timestack(s, level+1) + _print_timestack(s, level + 1) + def timethis(name): def decorator(func): global _do_timings if not name in _do_timings: return func + def wrapper(*args, **kwargs): from time import time global _timestack